diff options
-rw-r--r-- | app/Http/Controllers/VerbController.php | 92 | ||||
-rw-r--r-- | app/PointChange.php | 35 | ||||
-rw-r--r-- | app/Verb.php | 14 | ||||
-rw-r--r-- | database/migrations/2016_09_04_081811_create_point_changes_table.php | 37 | ||||
-rw-r--r-- | public/css/hebrewparsetrainer.css | 4 | ||||
-rw-r--r-- | public/js/alerts.js | 11 | ||||
-rw-r--r-- | public/js/moderators.js | 39 | ||||
-rw-r--r-- | resources/views/layouts/master.blade.php | 1 | ||||
-rw-r--r-- | resources/views/suggest.blade.php | 30 | ||||
-rw-r--r-- | resources/views/suggestions.blade.php | 10 |
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">×</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> |