Add request line bans functionality
Diff
app/Http/Controllers/Admin/RequestLineBanController.php | 69 +++++-
app/Http/Controllers/DJ/RequestController.php | 6 +-
app/Http/Controllers/Event/Senior/EventsTimetableController.php | 100 +++++++-
app/Http/Controllers/Management/EventsTimetableController.php | 100 +-------
app/Http/routes.php | 24 +-
app/Models/Group.php | 1 +-
app/Models/RequestBan.php | 6 +-
database/migrations/2016_06_11_112217_create_request_bans_table.php | 1 +-
resources/assets/sass/_misc.sass | 5 +-
resources/assets/sass/_navigation.sass | 3 +-
resources/views/admin/request-bans-form.blade.php | 34 ++-
resources/views/admin/request-bans.blade.php | 48 +++-
resources/views/events/senior/events-timetable.blade.php | 50 ++++-
resources/views/layouts/nav.blade.php | 16 +-
resources/views/management/events-timetable.blade.php | 50 +----
15 files changed, 350 insertions(+), 163 deletions(-)
@@ -0,0 +1,69 @@
<?php
namespace App\Http\Controllers\Admin;
use App\Http\Controllers\Controller;
use App\Models\RequestBan;
use Illuminate\Http\Request;
class RequestLineBanController extends Controller {
/**
* Show the administrator a list of all bans.
*
* @return mixed
*/
public function index()
{
return view('admin.request-bans', [
'bans' => RequestBan::orderBy('id', 'desc')->paginate(15)
]);
}
/**
* Show the administrator a form to ban an IP address.
*
* @return mixed
*/
public function banForm()
{
return view('admin.request-bans-form');
}
/**
* Ban an IP from the request line
*
* @param Request $request
* @return mixed
*/
public function ban(Request $request)
{
$this->validate($request, [
'ip' => 'required|ip|unique:request_bans,ip_address,NULL,id,deleted_at,NULL'
]);
$ban = new RequestBan;
$ban->ip_address = $request->get('ip');
$ban->added_by = auth()->user()->userid;
$ban->save();
return redirect()->route('dashboard::admin::request-ban')->with('msg', [
'type' => 'success',
'msg' => 'Successfully banned IP address from the request line.'
]);
}
/**
* Unban an IP from the request line.
*
* @param int $id id of the ip to unban
* @return mixed
*/
public function unban(int $id)
{
RequestBan::findOrFail($id)->delete();
return redirect()->back()->with('msg', [
'type' => 'success',
'msg' => _('Successfully unbanned IP from the request line.')
]);
}
}
@@ -3,6 +3,7 @@ namespace App\Http\Controllers\DJ;
use App\Http\Controllers\Controller;
use App\Models\Request;
use App\Models\RequestBan;
use Illuminate\Http\Request as HttpRequest;
use Vinkla\Pusher\Facades\Pusher;
@@ -49,6 +50,11 @@ class RequestController extends Controller
'request' => 'required|string|max:500'
]);
if (RequestBan::where('ip', $request->ip())->count()) {
// This IP is banned from the request line.
abort(403);
}
$r = new Request;
$r->name = $request->get('name');
$r->request = $request->get('request');
@@ -0,0 +1,100 @@
<?php
namespace App\Http\Controllers\Event\Senior;
use App\Http\Controllers\Controller;
use App\Models\Event;
use Carbon\Carbon;
/**
* Allow a senior event staff member to accept or deny events.
*
* @author Jordan Doyle <jordan@doyle.wf>
*/
class EventsTimetableController extends Controller
{
public function index()
{
$unapproved = Event::where('week', Carbon::now()->weekOfYear)
->where('year', Carbon::now()->year)
->where('approved', false)
->orderBy('id', 'desc')
->get();
return view('events.senior.events-timetable', ['unapproved' => $unapproved]);
}
/**
* Approve an event and delete every other event for that hour.
*
* @param $id
* @return mixed
*/
public function approve($id)
{
$event = Event::findOrFail($id);
if ($event->approved) {
return redirect()->back()->with('msg', [
'type' => 'success',
'msg' => _('This event has already been approved.')
]);
}
$others = Event::where('week', Carbon::now()->weekOfYear)
->where('year', Carbon::now()->year)
->where('day', $event->day)
->where('hour', $event->hour)
->where('approved', true)
->count();
if ($others) {
// there is already an approved event in this slot.
return redirect()->back()->with('msg', [
'msg' => _('There is already an approved event in this slot.'),
'type' => 'danger'
]);
}
// approve this event
$event->approved = true;
$event->save();
// delete all the other unapproved events that wanted this slot.
Event::where('week', Carbon::now()->weekOfYear)
->where('year', Carbon::now()->year)
->where('day', $event->day)
->where('hour', $event->hour)
->where('approved', false)
->delete();
return redirect()->back()->with('msg', [
'msg' => _('Successfully approved event and deleted other events which wanted this slot.'),
'type' => 'success'
]);
}
/**
* Deny an event.
*
* @param $id
* @return mixed
*/
public function deny($id)
{
$event = Event::findOrFail($id);
if ($event->approved) {
return redirect()->back()->with('msg', [
'type' => 'success',
'msg' => _('This event has already been approved.')
]);
}
$event->delete();
return redirect()->back()->with('msg', [
'msg' => _('Successfully declined event.'),
'type' => 'success'
]);
}
}
@@ -1,100 +0,0 @@
<?php
namespace App\Http\Controllers\Management;
use App\Http\Controllers\Controller;
use App\Models\Event;
use Carbon\Carbon;
/**
* Allow a manager to accept or deny events.
*
* @author Jordan Doyle <jordan@doyle.wf>
*/
class EventsTimetableController extends Controller
{
public function index()
{
$unapproved = Event::where('week', Carbon::now()->weekOfYear)
->where('year', Carbon::now()->year)
->where('approved', false)
->orderBy('id', 'desc')
->get();
return view('management.events-timetable', ['unapproved' => $unapproved]);
}
/**
* Approve an event and delete every other event for that hour.
*
* @param $id
* @return mixed
*/
public function approve($id)
{
$event = Event::findOrFail($id);
if ($event->approved) {
return redirect()->back()->with('msg', [
'type' => 'success',
'msg' => _('This event has already been approved.')
]);
}
$others = Event::where('week', Carbon::now()->weekOfYear)
->where('year', Carbon::now()->year)
->where('day', $event->day)
->where('hour', $event->hour)
->where('approved', true)
->count();
if ($others) {
// there is already an approved event in this slot.
return redirect()->back()->with('msg', [
'msg' => _('There is already an approved event in this slot.'),
'type' => 'danger'
]);
}
// approve this event
$event->approved = true;
$event->save();
// delete all the other unapproved events that wanted this slot.
Event::where('week', Carbon::now()->weekOfYear)
->where('year', Carbon::now()->year)
->where('day', $event->day)
->where('hour', $event->hour)
->where('approved', false)
->delete();
return redirect()->back()->with('msg', [
'msg' => _('Successfully approved event and deleted other events which wanted this slot.'),
'type' => 'success'
]);
}
/**
* Deny an event.
*
* @param $id
* @return mixed
*/
public function deny($id)
{
$event = Event::findOrFail($id);
if ($event->approved) {
return redirect()->back()->with('msg', [
'type' => 'success',
'msg' => _('This event has already been approved.')
]);
}
$event->delete();
return redirect()->back()->with('msg', [
'msg' => _('Successfully declined event.'),
'type' => 'success'
]);
}
}
@@ -75,17 +75,24 @@ Route::group(['middleware' => 'auth', 'as' => 'dashboard::'], function () {
});
Route::group([
'as' => 'senior-events::',
'prefix' => 'senior-events',
'namespace' => 'Event\Senior',
'middleware' => sprintf('is:%s', Group::SENIOR_EVENTS)
], function () {
// Timetable routes
Route::get('awaiting-review', ['as' => 'awaiting-review', 'uses' => 'EventsTimetableController@index']);
Route::put('approve/{id}', ['as' => 'approve', 'uses' => 'EventsTimetableController@approve']);
Route::delete('deny/{id}', ['as' => 'deny', 'uses' => 'EventsTimetableController@deny']);
});
Route::group([
'as' => 'management::',
'prefix' => 'management',
'namespace' => 'Management',
'middleware' => 'is:management'
], function () {
// Events routes
Route::group(['prefix' => 'events', 'as' => 'events::'], function () {
Route::get('timetable', ['as' => 'timetable', 'uses' => 'EventsTimetableController@index']);
Route::put('approve/{id}', ['as' => 'approve', 'uses' => 'EventsTimetableController@approve']);
Route::delete('deny/{id}', ['as' => 'deny', 'uses' => 'EventsTimetableController@deny']);
});
});
Route::group([
@@ -96,6 +103,11 @@ Route::group(['middleware' => 'auth', 'as' => 'dashboard::'], function () {
], function () {
Route::get('connection-info', ['as' => 'connection-info', 'uses' => 'ConnectionInfoController@getForm']);
Route::post('connection-info', ['as' => 'connection-info.post', 'uses' => 'ConnectionInfoController@postForm']);
Route::get('request-ban', ['as' => 'request-ban', 'uses' => 'RequestLineBanController@index']);
Route::get('request-ban/add', ['as' => 'request-ban.form', 'uses' => 'RequestLineBanController@banForm']);
Route::put('request-ban', ['as' => 'request-ban.ban', 'uses' => 'RequestLineBanController@ban']);
Route::delete('request-ban/{id}', ['as' => 'request-ban.unban', 'uses' => 'RequestLineBanController@unban']);
});
});
@@ -21,6 +21,7 @@ class Group extends Model
const GUEST_DJ = 'Guest DJ';
const RADIO_DJ = 'Radio DJ';
const EVENT = 'Events';
const SENIOR_EVENTS = 'Senior Events';
const MANAGEMENT = 'Management';
const ADMINISTRATOR = 'Administrator';
const OWNERSHIP = 'Ownership';
@@ -2,19 +2,21 @@
namespace App\Models;
use Carbon\Carbon;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\SoftDeletes;
/**
* Table containing IPs of everyone that is banned from the request line.
*
* @property integer $id
* @property string $ip
* @property string $ip_address
* @property integer $added_by
* @property Carbon $created_at
* @property Carbon $updated_at
* @property Carbon $deleted_at
* @author Jordan Doyle <jordan@doyle.wf>
*/
class RequestBan
class RequestBan extends Model
{
use SoftDeletes;
}
@@ -17,6 +17,7 @@ class CreateRequestBansTable extends Migration
$table->ipAddress('ip_address');
$table->integer('added_by');
$table->timestamps();
$table->softDeletes();
});
}
@@ -70,3 +70,8 @@ $alerts: map_merge($alerts, ("danger": (#f2dede, darken(adjust-hue(#fcf8e3, -10)
ul
columns: 4
list-style: none
#add
position: fixed
bottom: 2rem
right: 2rem
@@ -1,3 +1,6 @@
.mdl-layout__header-row
position: relative
.pagination
float: right
@@ -0,0 +1,34 @@
@extends(Request::ajax() ? 'layouts.ajax-main' : 'layouts.main')
@section('title'){{ _('Add Request Line Ban') }} @endsection
@section('content')
<div class="mdl-card mdl-cell mdl-cell--12-col mdl-shadow--2dp">
<div class="mdl-card__supporting-text">
<h4>{{ _('Add IP Ban') }}</h4>
<p>{{ _('Here you can ban IP addresses from submitting requests through the request line. Please enter a well-formed IP address below (ie. 94.213.39.123) and submit.') }}</p>
<form role="form" method="POST" action="{{ route('dashboard::admin::request-ban.ban') }}">
{{ csrf_field() }}
{{ method_field('put') }}
<fieldset class="mdl-textfield mdl-js-textfield mdl-textfield--floating-label {{ $errors->has('ip') ? 'is-invalid' : '' }}">
<input type="text" class="mdl-textfield__input" id="ip" name="ip"
value="{{ old('ip') }}">
<label class="mdl-textfield__label" for="ip">IP Address</label>
@if ($errors->has('ip'))
<span class="mdl-textfield__error">{{ $errors->first('ip') }}</span>
@endif
</fieldset>
<fieldset class="form-group">
<button type="submit"
class="mdl-button mdl-button--raised mdl-button--colored mdl-js-button mdl-js-ripple-effect">
<i class="fa fa-btn fa-plus"></i> {{ _('Save') }}
</button>
</fieldset>
</form>
</div>
</div>
@endsection
@@ -0,0 +1,48 @@
@extends(Request::ajax() ? 'layouts.ajax-main' : 'layouts.main')
@section('title'){{ _('Request Line Bans') }} @endsection
@section('content')
<div class="table-responsive">
{!! $bans->links() !!}
<table class="mdl-data-table mdl-js-data-table mdl-cell mdl-cell--12-col mdl-shadow--2dp">
<thead>
<tr>
<th class="mdl-data-table__cell--non-numeric">#</th>
<th class="mdl-data-table__cell--non-numeric">IP Address</th>
<th class="mdl-data-table__cell--non-numeric">Banned By</th>
<th class="mdl-data-table__cell--non-numeric">Added</th>
<th></th>
</tr>
</thead>
<tbody>
@foreach($bans as $ban)
<tr>
<td class="mdl-data-table__cell--non-numeric">{{ $ban->id }}</td>
<td class="mdl-data-table__cell--non-numeric">{{ $ban->ip_address }}</td>
<td class="mdl-data-table__cell--non-numeric">{{ App\Models\User::find($ban->added_by)->getDisplayName() }}</td>
<td class="mdl-data-table__cell--non-numeric">{{ $ban->created_at->diffForHumans() }}</td>
<td>
<form action="{{ route('dashboard::admin::request-ban.unban', $ban->id) }}" method="post">
{{ csrf_field() }}
{{ method_field('delete') }}
<button class="mdl-button mdl-js-button mdl-button--icon mdl-button--colored">
<i class="material-icons delete">delete forever</i>
</button>
</form>
</td>
</tr>
@endforeach
</tbody>
</table>
{!! $bans->links() !!}
</div>
<a class="mdl-button mdl-js-button mdl-button--fab mdl-button--colored" id="add" href="{{ route('dashboard::admin::request-ban.form') }}">
<i class="material-icons">add</i>
</a>
@endsection
@@ -0,0 +1,50 @@
@extends(Request::ajax() ? 'layouts.ajax-main' : 'layouts.main')
@section('title'){{ _('Approve Events') }} @endsection
@section('content')
@if($unapproved->count())
@foreach($unapproved as $event)
<div class="mdl-card mdl-cell mdl-cell--12-col mdl-shadow--2dp">
<div class="mdl-card__supporting-text">
<h4>{{ $event->user()->first()->getDisplayName() }}</h4>
<p>
{{ $event->user()->first()->getDisplayName() }} would like to book event <strong>{{ $event->type->name }}</strong> on <strong>{{ ['Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday', 'Sunday'][$event->day] }}</strong> at <strong>{{ sprintf('%02d:00', $event->hour) }}</strong> in room <a href="https://www.habbo.com/room/{{ $event->room_id }}" class="no-decoration">{{ $event->room_id }}</a>.
</p>
<p>
There are {{ App\Models\Event::where('week', $event->week)->where('year', $event->year)->where('day', $event->day)->where('hour', $event->hour)->where('id', '<>', $event->id)->count() }} other people who would like this slot.
</p>
</div>
<div class="mdl-card__actions mdl-card--border">
<form action="{{ route('dashboard::senior-events::approve', $event->id) }}" method="post">
{{ csrf_field() }}
{{ method_field('put') }}
<button class="mdl-button mdl-button--colored mdl-js-button mdl-js-ripple-effect" type="submit">
<i class="material-icons">check</i> {{ _('Approve') }}
</button>
</form>
<form action="{{ route('dashboard::senior-events::deny', $event->id) }}" method="post">
{{ csrf_field() }}
{{ method_field('delete') }}
<button class="mdl-button mdl-button--colored mdl-js-button mdl-js-ripple-effect" type="submit">
<i class="material-icons">close</i> {{ _('Deny') }}
</button>
</form>
<div class="mdl-layout-spacer"></div>
<strong>{{ $event->created_at->diffForHumans() }}</strong>
</div>
</div>
@endforeach
@else
<div class="mdl-card mdl-cell mdl-cell--12-col mdl-shadow--2dp">
<div class="mdl-card__supporting-text">
<h4>{{ _('All Done!') }}</h4>
<p>{{ _('There are no events awaiting your viewing.') }}</p>
</div>
</div>
@endif
@endsection
@@ -64,17 +64,23 @@
</a>
@endif
@if(auth()->user()->isManagement())
@if(auth()->user()->is(App\Models\Group::SENIOR_EVENTS))
<div class="zpan-drawer-separator"></div>
<span class="mdl-navigation__link" href>Management</span>
<span class="mdl-navigation__link" href>Senior Events</span>
<a class="mdl-navigation__link {{ is_route('dashboard::management::events::timetable') ? 'is-active' : '' }}"
href="{{ route('dashboard::management::events::timetable') }}">
<i class="material-icons">event_available</i> Events Timetable
<a class="mdl-navigation__link {{ is_route('dashboard::senior-events::awaiting-review') ? 'is-active' : '' }}"
href="{{ route('dashboard::senior-events::awaiting-review') }}">
<i class="material-icons">event_available</i> Awaiting Review ({{ App\Models\Event::where('week', Carbon\Carbon::now()->weekOfYear)->where('year', Carbon\Carbon::now()->year)->where('approved', false)->count() }})
</a>
@endif
@if(auth()->user()->isManagement())
<div class="zpan-drawer-separator"></div>
<span class="mdl-navigation__link" href>Management</span>
@endif
@if(auth()->user()->isAdmin())
<div class="zpan-drawer-separator"></div>
@@ -1,50 +0,0 @@
@extends(Request::ajax() ? 'layouts.ajax-main' : 'layouts.main')
@section('title'){{ _('Approve Events') }} @endsection
@section('content')
@if($unapproved->count())
@foreach($unapproved as $event)
<div class="mdl-card mdl-cell mdl-cell--12-col mdl-shadow--2dp">
<div class="mdl-card__supporting-text">
<h4>{{ $event->user()->first()->getDisplayName() }}</h4>
<p>
{{ $event->user()->first()->getDisplayName() }} would like to book event <strong>{{ $event->type->name }}</strong> on <strong>{{ ['Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday', 'Sunday'][$event->day] }}</strong> at <strong>{{ sprintf('%02d:00', $event->hour) }}</strong> in room <a href="https://www.habbo.com/room/{{ $event->room_id }}" class="no-decoration">{{ $event->room_id }}</a>.
</p>
<p>
There are {{ App\Models\Event::where('week', $event->week)->where('year', $event->year)->where('day', $event->day)->where('hour', $event->hour)->where('id', '<>', $event->id)->count() }} other people who would like this slot.
</p>
</div>
<div class="mdl-card__actions mdl-card--border">
<form action="{{ route('dashboard::management::events::approve', $event->id) }}" method="post">
{{ csrf_field() }}
{{ method_field('put') }}
<button class="mdl-button mdl-button--colored mdl-js-button mdl-js-ripple-effect" type="submit">
<i class="material-icons">check</i> {{ _('Approve') }}
</button>
</form>
<form action="{{ route('dashboard::management::events::deny', $event->id) }}" method="post">
{{ csrf_field() }}
{{ method_field('delete') }}
<button class="mdl-button mdl-button--colored mdl-js-button mdl-js-ripple-effect" type="submit">
<i class="material-icons">close</i> {{ _('Deny') }}
</button>
</form>
<div class="mdl-layout-spacer"></div>
<strong>{{ $event->created_at->diffForHumans() }}</strong>
</div>
</div>
@endforeach
@else
<div class="mdl-card mdl-cell mdl-cell--12-col mdl-shadow--2dp">
<div class="mdl-card__supporting-text">
<h4>{{ _('All Done!') }}</h4>
<p>{{ _('There are no events awaiting your viewing.') }}</p>
</div>
</div>
@endif
@endsection