aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--app/Http/Controllers/VerbController.php86
-rw-r--r--app/Http/Middleware/Login.php34
-rw-r--r--app/Http/routes.php30
-rw-r--r--app/User.php9
-rw-r--r--app/Verb.php42
-rw-r--r--app/VerbAction.php41
-rw-r--r--bootstrap/app.php1
-rw-r--r--database/migrations/2016_09_04_081754_create_verb_actions_table.php38
-rw-r--r--database/migrations/2016_09_04_081924_add_active_to_verbs.php31
-rw-r--r--public/css/hebrewparsetrainer.css17
-rw-r--r--public/js/moderators.js57
-rw-r--r--resources/views/contribute.blade.php35
-rw-r--r--resources/views/layouts/master.blade.php33
-rw-r--r--resources/views/stats.blade.php51
-rw-r--r--resources/views/suggest.blade.php76
-rw-r--r--resources/views/suggestions.blade.php32
16 files changed, 555 insertions, 58 deletions
diff --git a/app/Http/Controllers/VerbController.php b/app/Http/Controllers/VerbController.php
new file mode 100644
index 0000000..98b0579
--- /dev/null
+++ b/app/Http/Controllers/VerbController.php
@@ -0,0 +1,86 @@
+<?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 App\Http\Controllers;
+
+use HebrewParseTrainer\Verb;
+use HebrewParseTrainer\VerbAction;
+use HebrewParseTrainer\RandomLog;
+use Illuminate\Http\Request;
+use Illuminate\Support\Facades\Input;
+use Illuminate\Support\Facades\Auth;
+use Laravel\Lumen\Routing\Controller as BaseController;
+
+class VerbController extends BaseController {
+
+ public function random() {
+ $verbs = Verb::where('active', 1)->get();
+ foreach (Input::get() as $col => $val) {
+ $val = explode(',', $val);
+ $verbs = $verbs->filter(function(Verb $item) use ($col, $val) {
+ return in_array($item->getAttribute($col), $val);
+ });
+ }
+ $verb = $verbs->random();
+
+ $log = new RandomLog();
+ $log->request = json_encode(Input::get());
+ $log->response = $verb->id;
+ $log->ip = $_SERVER['REMOTE_ADDR'];
+ $log->save();
+
+ $obj = ['verb' => $verb, 'answers' => $verb->otherParsings()];
+ return response()->json($obj);
+ }
+
+ public function vote($choice, $verb_id) {
+ $verb = Verb::findOrFail($verb_id);
+ $user = Auth::user();
+
+ if ($verb->active)
+ return ['success' => false, 'message' => 'This verb has been accepted already.'];
+
+ foreach ($verb->actions()->where('kind', VerbAction::KIND_VOTE)->get() as $vote) {
+ if ($vote->user->id == $user->id) {
+ $vote->delete();
+ }
+ }
+
+ $vote = new VerbAction;
+ $vote->user_id = $user->id;
+ $vote->verb_id = $verb_id;
+ $vote->kind = VerbAction::KIND_VOTE;
+ $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();
+ }
+
+ return [
+ 'success' => true,
+ 'vote_weight' => $user->voteWeight(),
+ 'accepted' => (bool) $verb->active,
+ 'new_vote_count' => $verb->voteCount()
+ ];
+ }
+
+}
diff --git a/app/Http/Middleware/Login.php b/app/Http/Middleware/Login.php
new file mode 100644
index 0000000..8a71104
--- /dev/null
+++ b/app/Http/Middleware/Login.php
@@ -0,0 +1,34 @@
+<?php
+
+namespace App\Http\Middleware;
+
+use Closure;
+use Illuminate\Support\Facades\Auth;
+
+class Login {
+ /**
+ * Create a new middleware instance.
+ *
+ * @param \Illuminate\Contracts\Auth\Factory $auth
+ * @return void
+ */
+ public function __construct() {
+ }
+
+ /**
+ * Handle an incoming request.
+ *
+ * @param \Illuminate\Http\Request $request
+ * @param \Closure $next
+ * @param string|null $guard
+ * @return mixed
+ */
+ public function handle($request, Closure $next, $guard = null) {
+ if ($request->has('login') && !Auth::check()) {
+ return response('Unauthorized.', 401)
+ ->header('WWW-Authenticate', 'Basic realm="Please enter your email and password"');
+ }
+
+ return $next($request);
+ }
+}
diff --git a/app/Http/routes.php b/app/Http/routes.php
index 9cf12b4..8313029 100644
--- a/app/Http/routes.php
+++ b/app/Http/routes.php
@@ -29,7 +29,10 @@
*/
$app->group(
- ['prefix' => parse_url(env('APP_URL'), PHP_URL_PATH)],
+ [
+ 'prefix' => parse_url(env('APP_URL'), PHP_URL_PATH),
+ 'middleware' => 'login'
+ ],
function ($app) {
$app->get('/', function () use ($app) {
@@ -44,15 +47,24 @@ $app->group(
return \HebrewParseTrainer\Tense::all();
});
+ $app->get('/verb/random',
+ 'App\Http\Controllers\VerbController@random');
+
$app->get('/logout', function () use ($app) {
- return response('Unauthorized.', 401)
- ->header('WWW-Authenticate', 'Basic realm="Please click OK, then Cancel to logout."');
+ return response('You have been logged out.', 401)
+ ->header(
+ 'WWW-Authenticate',
+ 'Basic realm="Please click OK, then Cancel to logout."');
});
- $app->get('/verb/random', 'App\Http\Controllers\RandomVerbController@show');
+ $app->get('/contribute', function () use ($app) {
+ return view('contribute');
+ });
- $app->get('/user/create', 'App\Http\Controllers\UserController@createForm');
- $app->post('/user/create', 'App\Http\Controllers\UserController@createForm');
+ $app->get('/user/create',
+ 'App\Http\Controllers\UserController@createForm');
+ $app->post('/user/create',
+ 'App\Http\Controllers\UserController@createForm');
$app->group(
['middleware' => 'auth:basic-http'],
@@ -62,6 +74,12 @@ $app->group(
return view('stats');
});
+ $app->get('/verb/{id}/vote/{choice}',
+ 'App\Http\Controllers\VerbController@vote');
+
+ $app->post('/verb/suggest',
+ 'App\Http\Controllers\VerbController@suggest');
+
});
});
diff --git a/app/User.php b/app/User.php
index 3c1799d..dda14ca 100644
--- a/app/User.php
+++ b/app/User.php
@@ -28,6 +28,8 @@ class User extends Model implements Authenticatable {
public $timestamps = false;
protected $fillable = ['email', 'name'];
+ const VOTE_WEIGHT_BASE = 5;
+
public function changePoints($kind, $change, $verb = null) {
$change = new PointChange;
$change->user = $this->id;
@@ -40,6 +42,13 @@ class User extends Model implements Authenticatable {
$this->save();
}
+ public function voteWeight() {
+ if ($this->points <= 0)
+ return 0;
+
+ return floor(log($this->points, self::VOTE_WEIGHT_BASE));
+ }
+
public function setPasswordAttribute($pass) {
$this->attributes['password'] = Hash::make($pass);
}
diff --git a/app/Verb.php b/app/Verb.php
index 28e22ea..aa0db26 100644
--- a/app/Verb.php
+++ b/app/Verb.php
@@ -22,14 +22,38 @@ use Illuminate\Database\Eloquent\Model;
class Verb extends Model {
- protected $table = 'verbs';
- public $timestamps = false;
- protected $fillable = ['verb', 'root', 'stem', 'tense', 'person', 'gender', 'number'];
+ protected $table = 'verbs';
+ public $timestamps = false;
+ protected $fillable = ['verb', 'root', 'stem', 'tense', 'person', 'gender', 'number'];
- public function otherParsings()
- {
- return self::where('verb', $this->verb)->get()
- ->filter(function($v){return $v->verb === $this->verb;});
- }
+ const ACCEPTED_VOTE_COUNT = 1;
-} \ No newline at end of file
+ public function actions() {
+ return $this->hasMany('HebrewParseTrainer\VerbAction');
+ }
+
+ public function otherParsings() {
+ return self::where('verb', $this->verb)->get()
+ ->filter(function($v){return $v->verb === $this->verb;});
+ }
+
+ public function voteCount() {
+ $votes = $this->actions()->where('kind', VerbAction::KIND_VOTE)->get();
+ $total = 0;
+ foreach ($votes as $vote)
+ $total += $vote->vote_weight;
+ return $total;
+ }
+
+ public function userVote(User $user) {
+ $votes = $this->actions()
+ ->where('kind', VerbAction::KIND_VOTE)
+ ->where('user_id', $user->id)
+ ->get();
+ foreach ($votes as $vote) {
+ return $vote->vote_weight;
+ }
+ return 0;
+ }
+
+}
diff --git a/app/VerbAction.php b/app/VerbAction.php
new file mode 100644
index 0000000..79c8cd0
--- /dev/null
+++ b/app/VerbAction.php
@@ -0,0 +1,41 @@
+<?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 VerbAction extends Model {
+
+ protected $table = 'verb_actions';
+ public $timestamps = false;
+ protected $dates = ['date'];
+ protected $fillable = ['user_id', 'verb_id', 'kind', 'vote_weight', 'comment_text'];
+
+ const KIND_SUGGEST = 1;
+ const KIND_VOTE = 2;
+
+ public function verb() {
+ return $this->belongsTo('HebrewParseTrainer\Verb');
+ }
+
+ public function user() {
+ return $this->belongsTo('HebrewParseTrainer\User');
+ }
+
+}
diff --git a/bootstrap/app.php b/bootstrap/app.php
index 04f448e..c72ab23 100644
--- a/bootstrap/app.php
+++ b/bootstrap/app.php
@@ -68,6 +68,7 @@ $app->singleton(
$app->routeMiddleware([
'auth' => App\Http\Middleware\Authenticate::class,
+ 'login' => App\Http\Middleware\Login::class,
]);
/*
diff --git a/database/migrations/2016_09_04_081754_create_verb_actions_table.php b/database/migrations/2016_09_04_081754_create_verb_actions_table.php
new file mode 100644
index 0000000..d7b0f29
--- /dev/null
+++ b/database/migrations/2016_09_04_081754_create_verb_actions_table.php
@@ -0,0 +1,38 @@
+<?php
+
+use Illuminate\Database\Schema\Blueprint;
+use Illuminate\Database\Migrations\Migration;
+
+class CreateVerbActionsTable extends Migration
+{
+ /**
+ * Run the migrations.
+ *
+ * @return void
+ */
+ public function up()
+ {
+ Schema::create('verb_actions', function (Blueprint $table) {
+ $table->increments('id');
+ $table->integer('user_id')->unsigned();
+ $table->integer('verb_id')->unsigned();
+ $table->tinyInteger('kind');
+ $table->tinyInteger('vote_weight')->nullable();
+ $table->string('comment_text')->nullable();
+ $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('verb_actions');
+ }
+}
diff --git a/database/migrations/2016_09_04_081924_add_active_to_verbs.php b/database/migrations/2016_09_04_081924_add_active_to_verbs.php
new file mode 100644
index 0000000..79c5993
--- /dev/null
+++ b/database/migrations/2016_09_04_081924_add_active_to_verbs.php
@@ -0,0 +1,31 @@
+<?php
+
+use Illuminate\Database\Schema\Blueprint;
+use Illuminate\Database\Migrations\Migration;
+
+class AddActiveToVerbs extends Migration
+{
+ /**
+ * Run the migrations.
+ *
+ * @return void
+ */
+ public function up()
+ {
+ Schema::table('verbs', function (Blueprint $table) {
+ $table->boolean('active')->default(true);
+ });
+ }
+
+ /**
+ * Reverse the migrations.
+ *
+ * @return void
+ */
+ public function down()
+ {
+ Schema::table('verbs', function (Blueprint $table) {
+ $table->dropColumn('active');
+ });
+ }
+}
diff --git a/public/css/hebrewparsetrainer.css b/public/css/hebrewparsetrainer.css
index 54f0c2d..30ef258 100644
--- a/public/css/hebrewparsetrainer.css
+++ b/public/css/hebrewparsetrainer.css
@@ -20,6 +20,23 @@
src: url('fonts/EzraSIL.ttf');
}
+body {
+ padding-top: 20px;
+}
+
+.large {
+ font-size: 150%;
+}
+
+.header {
+ border-bottom: 1px solid #e5e5e5;
+ margin-bottom: 30px;
+}
+
+.suggestions td {
+ vertical-align: middle !important;
+}
+
#trainer-404 {
display: none;
padding: 15px;
diff --git a/public/js/moderators.js b/public/js/moderators.js
new file mode 100644
index 0000000..2b192f8
--- /dev/null
+++ b/public/js/moderators.js
@@ -0,0 +1,57 @@
+/**
+ * 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/>.
+ */
+$(document).ready(function(){
+ $('.vote').click(function(){
+ var vote = parseInt($(this).data('vote'));
+ var verbId = $(this).data('verb');
+
+ var container = $(this).parent();
+
+ $.ajax({
+ url: app_url + 'verb/' + verbId + '/vote/' + vote,
+ success: function(data) {
+ if (!data.success) {
+ fail(data.message);
+ return;
+ }
+
+ var btns = container.find('.vote');
+ if (vote) {
+ $(btns[0]).removeClass('btn-danger');
+ $(btns[0]).addClass('btn-default');
+ $(btns[1]).addClass('btn-success');
+ $(btns[1]).removeClass('btn-default');
+ } else {
+ $(btns[0]).addClass('btn-danger');
+ $(btns[0]).removeClass('btn-default');
+ $(btns[1]).removeClass('btn-success');
+ $(btns[1]).addClass('btn-default');
+ }
+
+ container.find('.vote-count').text(data.new_vote_count);
+
+ if (data.accepted) {
+ alert('This verb has now been accepted!');
+ container.parent().remove();
+ }
+ }
+ });
+
+ return true;
+ });
+});
diff --git a/resources/views/contribute.blade.php b/resources/views/contribute.blade.php
new file mode 100644
index 0000000..4c3b6de
--- /dev/null
+++ b/resources/views/contribute.blade.php
@@ -0,0 +1,35 @@
+@extends('layouts.master')
+
+@section('master-content')
+<p class="lead">
+ Thank you for wanting to help out! To expand our database, we are looking for volunteers to enter more verbs.
+</p>
+
+@if(!Auth::check())
+ <a class="btn btn-lg btn-primary" href="{{ env('APP_URL') }}contribute?login=yes">Login</a>
+ <a class="btn btn-lg btn-success" href="{{ env('APP_URL') }}user/create">Sign up</a>
+@endif
+
+<h3>Here's how it works:</h3>
+
+<ul>
+ <li>Any user can <em>suggest new verbs</em>.</li>
+ <li>These have to be <em>peer-reviewed</em> by other contributors.</li>
+ <li>It has to get <em>five</em> votes to be accepted.</li>
+ <li>Contributors <em>earn points</em> for all accepted verbs they suggested.</li>
+ <li>The <em>vote weight</em> is dependent on the number of points a user has.</li>
+</ul>
+
+@if(Auth::check())
+ <hr/>
+ <div class="row">
+ <div class="col-lg-6">
+ @include('suggestions')
+ </div>
+ <div class="col-lg-6">
+ @include('suggest')
+ </div>
+ </div>
+@endif
+
+@endsection
diff --git a/resources/views/layouts/master.blade.php b/resources/views/layouts/master.blade.php
index 3c111da..199db2d 100644
--- a/resources/views/layouts/master.blade.php
+++ b/resources/views/layouts/master.blade.php
@@ -16,17 +16,43 @@ 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/>.
-->
+<?php
+use Illuminate\Support\Facades\Auth;
+use Illuminate\Support\Facades\Request;
+
+$activePage = isset($activePage) ? $activePage : '';
+$menu = [
+ 'Train' => ['/', ''],
+ 'Contribute' => ['contribute', 'contribute'],
+];
+
+if (Auth::check()) {
+ $menu['Statistics'] = ['stats', 'stats'];
+ $menu['Logout'] = ['logout', 'logout'];
+}
+?>
<html lang="en">
<head>
<meta charset="utf-8">
<title>ParseTrainer</title>
<link rel="stylesheet" href="{{ env('APP_URL') }}vendor/twbs/bootstrap/dist/css/bootstrap.min.css">
<link rel="stylesheet" href="{{ env('APP_URL') }}public/css/hebrewparsetrainer.css">
+
+ <script type="text/javascript">
+ var app_url = '{{ env('APP_URL') }}';
+ </script>
</head>
<body role="application">
<div class="container" role="main">
- <div class="page-header">
- <h1>ParseTrainer</h1>
+ <div class="header clearfix">
+ <nav>
+ <ul class="nav nav-pills pull-right">
+ @foreach($menu as $name => $link)
+ <li role="presentation" class="{{ Request::is($link[0]) ? 'active' : '' }}"><a href="{{ env('APP_URL') }}{{ $link[1] }}">{{ $name }}</a></li>
+ @endforeach
+ </ul>
+ </nav>
+ <h2 class="text-muted">ParseTrainer</h2>
</div>
@yield('master-content')
@@ -35,5 +61,8 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
<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/hebrewparsetrainer.js"></script>
+ @if(Auth::check())
+ <script src="{{ env('APP_URL') }}public/js/moderators.js"></script>
+ @endif
</body>
</html>
diff --git a/resources/views/stats.blade.php b/resources/views/stats.blade.php
index f68c9ac..04fabfe 100644
--- a/resources/views/stats.blade.php
+++ b/resources/views/stats.blade.php
@@ -1,42 +1,3 @@
-<!DOCTYPE html>
-<!--
-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/>.
- -->
-<html lang="en">
-<head>
- <meta charset="utf-8">
- <title>ParseTrainer statistics</title>
- <link rel="stylesheet" href="{{ url("/vendor/twbs/bootstrap/dist/css/bootstrap.min.css") }}">
- <link rel="stylesheet" href="{{ url("/vendor/twbs/bootstrap/dist/css/bootstrap-theme.min.css") }}">
- <link rel="stylesheet" href="{{ url("/public/css/hebrewparsetrainer.css") }}">
-</head>
-<body role="application">
-<div class="container" role="main">
- <div class="page-header">
- <h1>ParseTrainer statistics</h1>
- </div>
-
- <div class="row">
- <div class="col-md-12">
- <div id="statistics" style="height:400px;"></div>
- </div>
- </div>
-</div>
-
<?php
use \HebrewParseTrainer\RandomLog;
@@ -53,6 +14,15 @@ foreach ($db_stats as $stat) {
$stats = "[" . implode(",", $stats) . "]";
?>
+@extends('layouts.master')
+
+@section('master-content')
+<div class="row">
+ <div class="col-md-12">
+ <div id="statistics" style="height:400px;"></div>
+ </div>
+</div>
+
<script src="{{ url("/vendor/components/jquery/jquery.min.js") }}"></script>
<script src="{{ url("/vendor/twbs/bootstrap/dist/js/bootstrap.min.js") }}"></script>
<script src="//code.highcharts.com/stock/highstock.js"></script>
@@ -105,5 +75,4 @@ $stats = "[" . implode(",", $stats) . "]";
]
});
</script>
-</body>
-</html>
+@endsection
diff --git a/resources/views/suggest.blade.php b/resources/views/suggest.blade.php
new file mode 100644
index 0000000..6a1ebe8
--- /dev/null
+++ b/resources/views/suggest.blade.php
@@ -0,0 +1,76 @@
+<?php
+use HebrewParseTrainer\Root;
+use HebrewParseTrainer\Tense;
+use HebrewParseTrainer\Verb;
+?>
+<div class="panel panel-default">
+ <div class="panel-heading">
+ <h3 class="panel-title">Suggest a new verb</h3>
+ </div>
+ <div class="panel-body">
+ <form class="form-horizontal">
+ <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="קָטַל"/>
+ </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">
+ @foreach(Root::all() as $root)
+ <option value="{{ $root->id }}">{{{ $root->root }}}</option>
+ @endforeach
+ </select>
+ </div>
+ </div>
+ <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">
+ @foreach(Tense::all() as $tense)
+ <option value="{{ $tense->id }}">{{{ $tense->abbreviation }}}: {{{ $tense->name }}}</option>
+ @endforeach
+ </select>
+ </div>
+ </div>
+ <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">
+ <option value="">(none)</option>
+ <option value="1">1</option>
+ <option value="2">2</option>
+ <option value="3">3</option>
+ </select>
+ </div>
+ </div>
+ <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">
+ <option value="">(none)</option>
+ <option value="m">masculine</option>
+ <option value="f">feminine</option>
+ </select>
+ </div>
+ </div>
+ <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">
+ <option value="">(none)</option>
+ <option value="s">singular</option>
+ <option value="p">plural</option>
+ </select>
+ </div>
+ </div>
+ <div class="form-group">
+ <div class="col-sm-offset-2 col-sm-10">
+ <button type="submit" class="btn btn-primary">Suggest</button>
+ </div>
+ </div>
+ </form>
+ </div>
+</div>
diff --git a/resources/views/suggestions.blade.php b/resources/views/suggestions.blade.php
new file mode 100644
index 0000000..dcec56a
--- /dev/null
+++ b/resources/views/suggestions.blade.php
@@ -0,0 +1,32 @@
+<?php
+use HebrewParseTrainer\Verb;
+?>
+<div class="panel panel-default">
+ <div class="panel-heading">
+ <h3 class="panel-title">Current suggestions</h3>
+ </div>
+ <div class="panel-body">
+ <table class="table table-hover table-condensed suggestions">
+ <tr>
+ <th>Verb</th>
+ <th>Root</th>
+ <th>Parsing</th>
+ <th>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>
+ </tr>
+ @empty
+ <tr><td colspan="4">There are no active suggestions. Why not add a verb yourself?</td></tr>
+ @endforelse
+ </table>
+ </div>
+</div>