aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--app/Http/Controllers/VerbController.php92
-rw-r--r--app/PointChange.php35
-rw-r--r--app/Verb.php14
-rw-r--r--database/migrations/2016_09_04_081811_create_point_changes_table.php37
-rw-r--r--public/css/hebrewparsetrainer.css4
-rw-r--r--public/js/alerts.js11
-rw-r--r--public/js/moderators.js39
-rw-r--r--resources/views/layouts/master.blade.php1
-rw-r--r--resources/views/suggest.blade.php30
-rw-r--r--resources/views/suggestions.blade.php10
10 files changed, 248 insertions, 25 deletions
diff --git a/app/Http/Controllers/VerbController.php b/app/Http/Controllers/VerbController.php
index 98b0579..18cdd2f 100644
--- a/app/Http/Controllers/VerbController.php
+++ b/app/Http/Controllers/VerbController.php
@@ -18,12 +18,17 @@
*/
namespace App\Http\Controllers;
+use HebrewParseTrainer\PointChange;
+use HebrewParseTrainer\Stem;
+use HebrewParseTrainer\Tense;
use HebrewParseTrainer\Verb;
use HebrewParseTrainer\VerbAction;
use HebrewParseTrainer\RandomLog;
+
use Illuminate\Http\Request;
-use Illuminate\Support\Facades\Input;
use Illuminate\Support\Facades\Auth;
+use Illuminate\Support\Facades\Input;
+use Illuminate\Support\Facades\Validator;
use Laravel\Lumen\Routing\Controller as BaseController;
class VerbController extends BaseController {
@@ -48,6 +53,82 @@ class VerbController extends BaseController {
return response()->json($obj);
}
+ public function suggest(Request $request) {
+ $_tenses = Tense::all();
+ $tenses = [];
+ foreach ($_tenses as $tense)
+ $tenses[] = $tense->name;
+
+ $_stems = Stem::all();
+ $stems = [];
+ foreach ($_stems as $stem)
+ $stems[] = $stem->name;
+
+ $validator = Validator::make($request->input(), [
+ 'verb' => 'required',
+ 'root' => 'required',
+ 'stem' => 'in:' . implode(',', $stems),
+ 'tense' => 'in:' . implode(',', $tenses),
+ 'person' => 'in:,1,2,3',
+ 'gender' => 'in:,m,f',
+ 'number' => 'in:,s,p',
+ ]);
+
+ if ($validator->fails()) {
+ return [
+ 'success' => false,
+ 'message' => $validator->errors()->first()
+ ];
+ }
+
+ $verb = new Verb;
+ $verb->verb = $request->input('verb');
+ $verb->root = $request->input('root');
+ $verb->stem = $request->input('stem');
+ $verb->tense = $request->input('tense');
+ $verb->person = $request->input('person') ? $request->input('person') : null;
+ $verb->gender = $request->input('gender') ? $request->input('gender') : null;
+ $verb->number = $request->input('number') ? $request->input('number') : null;
+ $verb->active = 0;
+ $verb->save();
+
+ $action = new VerbAction;
+ $action->kind = VerbAction::KIND_SUGGEST;
+ $action->user_id = Auth::user()->id;
+ $action->verb_id = $verb->id;
+ $action->save();
+
+ $this->vote(1, $verb->id);
+
+ return [
+ 'success' => true,
+ 'id' => $verb->id,
+ 'accepted' => $verb->active != 0
+ ];
+ }
+
+ protected function checkAccept($verb) {
+ if ($verb->voteCount() < Verb::ACCEPTED_VOTE_COUNT)
+ return false;
+
+ $verb->active = 1;
+ $verb->save();
+
+ if (!is_null($user = $verb->suggestedBy())) {
+ $ptchange = new PointChange;
+ $ptchange->kind = PointChange::KIND_SUGGESTION_ACCEPTED;
+ $ptchange->change = PointChange::POINTS_SUGGESTION_ACCEPTED;
+ $ptchange->user_id = $user->id;
+ $ptchange->verb_id = $verb->id;
+ $ptchange->save();
+
+ $user->points += PointChange::POINTS_SUGGESTION_ACCEPTED;
+ $user->save();
+ }
+
+ return true;
+ }
+
public function vote($choice, $verb_id) {
$verb = Verb::findOrFail($verb_id);
$user = Auth::user();
@@ -68,17 +149,12 @@ class VerbController extends BaseController {
$vote->vote_weight = ($choice == 1 ? 1 : -1) * $user->voteWeight();
$vote->save();
- $message = 'You have voted.';
-
- if ($verb->voteCount() >= Verb::ACCEPTED_VOTE_COUNT) {
- $verb->active = 1;
- $verb->save();
- }
+ $accepted = $this->checkAccept($verb);
return [
'success' => true,
'vote_weight' => $user->voteWeight(),
- 'accepted' => (bool) $verb->active,
+ 'accepted' => $accepted,
'new_vote_count' => $verb->voteCount()
];
}
diff --git a/app/PointChange.php b/app/PointChange.php
new file mode 100644
index 0000000..c157b36
--- /dev/null
+++ b/app/PointChange.php
@@ -0,0 +1,35 @@
+<?php
+/**
+ * HebrewParseTrainer - practice Hebrew verbs
+ * Copyright (C) 2015 Camil Staps <info@camilstaps.nl>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+namespace HebrewParseTrainer;
+
+use Illuminate\Database\Eloquent\Model;
+
+class PointChange extends Model {
+
+ protected $table = 'point_changes';
+ public $timestamps = false;
+ protected $dates = ['date'];
+ protected $fillable = ['kind', 'change'];
+
+ const KIND_SUGGESTION_ACCEPTED = 1;
+ const KIND_MANUAL = 3;
+
+ const POINTS_SUGGESTION_ACCEPTED = 2;
+
+}
diff --git a/app/Verb.php b/app/Verb.php
index aa0db26..3ff79fc 100644
--- a/app/Verb.php
+++ b/app/Verb.php
@@ -26,7 +26,7 @@ class Verb extends Model {
public $timestamps = false;
protected $fillable = ['verb', 'root', 'stem', 'tense', 'person', 'gender', 'number'];
- const ACCEPTED_VOTE_COUNT = 1;
+ const ACCEPTED_VOTE_COUNT = 5;
public function actions() {
return $this->hasMany('HebrewParseTrainer\VerbAction');
@@ -56,4 +56,16 @@ class Verb extends Model {
return 0;
}
+ public function suggestedBy() {
+ $suggs = $this->actions()
+ ->where('kind', VerbAction::KIND_SUGGEST)
+ ->get();
+
+ foreach ($suggs as $sugg) {
+ return $sugg->user;
+ }
+
+ return null;
+ }
+
}
diff --git a/database/migrations/2016_09_04_081811_create_point_changes_table.php b/database/migrations/2016_09_04_081811_create_point_changes_table.php
new file mode 100644
index 0000000..4ade816
--- /dev/null
+++ b/database/migrations/2016_09_04_081811_create_point_changes_table.php
@@ -0,0 +1,37 @@
+<?php
+
+use Illuminate\Database\Schema\Blueprint;
+use Illuminate\Database\Migrations\Migration;
+
+class CreatePointChangesTable extends Migration
+{
+ /**
+ * Run the migrations.
+ *
+ * @return void
+ */
+ public function up()
+ {
+ Schema::create('point_changes', function (Blueprint $table) {
+ $table->increments('id');
+ $table->integer('user_id')->unsigned();
+ $table->integer('verb_id')->unsigned()->nullable();
+ $table->tinyInteger('kind')->unsigned();
+ $table->integer('change');
+ $table->timestamp('date')->default(DB::raw('CURRENT_TIMESTAMP'));
+
+ $table->foreign('user_id')->references('id')->on('users');
+ $table->foreign('verb_id')->references('id')->on('verbs');
+ });
+ }
+
+ /**
+ * Reverse the migrations.
+ *
+ * @return void
+ */
+ public function down()
+ {
+ Schema::drop('point_changes');
+ }
+}
diff --git a/public/css/hebrewparsetrainer.css b/public/css/hebrewparsetrainer.css
index 30ef258..6e35fe8 100644
--- a/public/css/hebrewparsetrainer.css
+++ b/public/css/hebrewparsetrainer.css
@@ -37,6 +37,10 @@ body {
vertical-align: middle !important;
}
+.suggestions td.vote-cell {
+ width: 30px;
+}
+
#trainer-404 {
display: none;
padding: 15px;
diff --git a/public/js/alerts.js b/public/js/alerts.js
new file mode 100644
index 0000000..c1763ed
--- /dev/null
+++ b/public/js/alerts.js
@@ -0,0 +1,11 @@
+$.fn.addAlert = function (kind, message) {
+ var box = '<div class="alert alert-' + kind + ' alert-dismissible" role="alert">' +
+ '<button type="button" class="close" data-dismiss="alert" aria-label="Close"><span aria-hidden="true">&times;</span></button>' +
+ message + '</div>';
+
+ $(this).find('.alerts').append($(box));
+}
+
+$.fn.clearAlerts = function () {
+ $(this).find('.alerts').html('');
+}
diff --git a/public/js/moderators.js b/public/js/moderators.js
index 2b192f8..1a61075 100644
--- a/public/js/moderators.js
+++ b/public/js/moderators.js
@@ -20,10 +20,17 @@ $(document).ready(function(){
var vote = parseInt($(this).data('vote'));
var verbId = $(this).data('verb');
- var container = $(this).parent();
+ var container = $(this).closest('tr');
+
+ var fail = function(msg) {
+ alert('Voting failed with the message: "' + msg + '". Please try again.');
+ }
$.ajax({
url: app_url + 'verb/' + verbId + '/vote/' + vote,
+ error: function(jqxhr, stat, error) {
+ fail(stat);
+ },
success: function(data) {
if (!data.success) {
fail(data.message);
@@ -54,4 +61,34 @@ $(document).ready(function(){
return true;
});
+
+ $('form#suggest').submit(function(){
+ var data = $(this).serialize();
+ var form = $(this);
+
+ form.clearAlerts();
+
+ $.ajax({
+ url: app_url + 'verb/suggest',
+ method: 'post',
+ data: data,
+ error: function(jqxhr, stat, error) {
+ form.addAlert('danger', stat);
+ },
+ success: function(data) {
+ if (!data.success) {
+ form.addAlert('danger', data.message);
+ return;
+ }
+
+ if (data.accepted) {
+ form.addAlert('success', 'The new verb has been <b>accepted immediately</b>.');
+ } else {
+ form.addAlert('success', 'The new verb has been proposed for peer review.');
+ }
+ }
+ });
+
+ return false;
+ });
});
diff --git a/resources/views/layouts/master.blade.php b/resources/views/layouts/master.blade.php
index 199db2d..ad8056d 100644
--- a/resources/views/layouts/master.blade.php
+++ b/resources/views/layouts/master.blade.php
@@ -60,6 +60,7 @@ if (Auth::check()) {
<script src="{{ env('APP_URL') }}vendor/components/jquery/jquery.min.js"></script>
<script src="{{ env('APP_URL') }}vendor/twbs/bootstrap/dist/js/bootstrap.min.js"></script>
+ <script src="{{ env('APP_URL') }}public/js/alerts.js"></script>
<script src="{{ env('APP_URL') }}public/js/hebrewparsetrainer.js"></script>
@if(Auth::check())
<script src="{{ env('APP_URL') }}public/js/moderators.js"></script>
diff --git a/resources/views/suggest.blade.php b/resources/views/suggest.blade.php
index 6a1ebe8..1bc50f7 100644
--- a/resources/views/suggest.blade.php
+++ b/resources/views/suggest.blade.php
@@ -1,5 +1,6 @@
<?php
use HebrewParseTrainer\Root;
+use HebrewParseTrainer\Stem;
use HebrewParseTrainer\Tense;
use HebrewParseTrainer\Verb;
?>
@@ -8,19 +9,30 @@ use HebrewParseTrainer\Verb;
<h3 class="panel-title">Suggest a new verb</h3>
</div>
<div class="panel-body">
- <form class="form-horizontal">
+ <form class="form-horizontal" id="suggest">
+ <div class="alerts"></div>
<div class="form-group">
<label for="suggest-verb" class="col-sm-2 control-label">Verb</label>
<div class="col-sm-10">
- <input type="text" class="form-control" id="suggest-verb" placeholder="קָטַל"/>
+ <input type="text" class="form-control" id="suggest-verb" name="verb" placeholder="קָטַל"/>
</div>
</div>
<div class="form-group">
<label for="suggest-root" class="col-sm-2 control-label">Root</label>
<div class="col-sm-10">
- <select id="suggest-root" class="form-control">
+ <select id="suggest-root" class="form-control" name="root">
@foreach(Root::all() as $root)
- <option value="{{ $root->id }}">{{{ $root->root }}}</option>
+ <option value="{{ $root->root }}">{{{ $root->root }}}</option>
+ @endforeach
+ </select>
+ </div>
+ </div>
+ <div class="form-group">
+ <label for="suggest-stem" class="col-sm-2 control-label">Stem</label>
+ <div class="col-sm-10">
+ <select id="suggest-stem" class="form-control" name="stem">
+ @foreach(Stem::all() as $stem)
+ <option value="{{ $stem->name }}">{{{ $stem->name }}}</option>
@endforeach
</select>
</div>
@@ -28,9 +40,9 @@ use HebrewParseTrainer\Verb;
<div class="form-group">
<label for="suggest-tense" class="col-sm-2 control-label">Tense</label>
<div class="col-sm-10">
- <select id="suggest-tense" class="form-control">
+ <select id="suggest-tense" class="form-control" name="tense">
@foreach(Tense::all() as $tense)
- <option value="{{ $tense->id }}">{{{ $tense->abbreviation }}}: {{{ $tense->name }}}</option>
+ <option value="{{ $tense->name }}">{{{ $tense->abbreviation }}}: {{{ $tense->name }}}</option>
@endforeach
</select>
</div>
@@ -38,7 +50,7 @@ use HebrewParseTrainer\Verb;
<div class="form-group">
<label for="suggest-person" class="col-sm-2 control-label">Person</label>
<div class="col-sm-10">
- <select id="suggest-person" class="form-control">
+ <select id="suggest-person" class="form-control" name="person">
<option value="">(none)</option>
<option value="1">1</option>
<option value="2">2</option>
@@ -49,7 +61,7 @@ use HebrewParseTrainer\Verb;
<div class="form-group">
<label for="suggest-gender" class="col-sm-2 control-label">Gender</label>
<div class="col-sm-10">
- <select id="suggest-gender" class="form-control">
+ <select id="suggest-gender" class="form-control" name="gender">
<option value="">(none)</option>
<option value="m">masculine</option>
<option value="f">feminine</option>
@@ -59,7 +71,7 @@ use HebrewParseTrainer\Verb;
<div class="form-group">
<label for="suggest-number" class="col-sm-2 control-label">Number</label>
<div class="col-sm-10">
- <select id="suggest-number" class="form-control">
+ <select id="suggest-number" class="form-control" name="number">
<option value="">(none)</option>
<option value="s">singular</option>
<option value="p">plural</option>
diff --git a/resources/views/suggestions.blade.php b/resources/views/suggestions.blade.php
index dcec56a..e9b8efb 100644
--- a/resources/views/suggestions.blade.php
+++ b/resources/views/suggestions.blade.php
@@ -11,18 +11,16 @@ use HebrewParseTrainer\Verb;
<th>Verb</th>
<th>Root</th>
<th>Parsing</th>
- <th>Votes</th>
+ <th colspan="3">Votes</th>
</tr>
@forelse(Verb::where('active', 0)->orderBy('verb')->get() as $verb)
<tr>
<td class="large">{{ $verb->verb }}</td>
<td class="large">{{ $verb->root }}</td>
<td>{{ $verb->stem }} {{ $verb->tense }} {{ $verb->person }}{{ $verb->gender }}{{ $verb->number }}</td>
- <td>
- <button data-vote="0" data-verb="{{ $verb->id }}" class="vote btn btn-{{ $verb->userVote(Auth::user()) < 0 ? 'danger' : 'default' }}">-</button>
- <span class="vote-count btn">{{ $verb->voteCount() }}</span>
- <button data-vote="1" data-verb="{{ $verb->id }}" class="vote btn btn-{{ $verb->userVote(Auth::user()) > 0 ? 'success' : 'default' }}">+</button>
- </td>
+ <td class="vote-cell"><button data-vote="0" data-verb="{{ $verb->id }}" class="vote btn btn-{{ $verb->userVote(Auth::user()) < 0 ? 'danger' : 'default' }}">-</button></td>
+ <td class="vote-cell"><span class="vote-count btn">{{ $verb->voteCount() }}</span></td>
+ <td class="vote-cell"><button data-vote="1" data-verb="{{ $verb->id }}" class="vote btn btn-{{ $verb->userVote(Auth::user()) > 0 ? 'success' : 'default' }}">+</button></td>
</tr>
@empty
<tr><td colspan="4">There are no active suggestions. Why not add a verb yourself?</td></tr>