WIP: Road to 1.0.0 #1
|
@ -30,13 +30,13 @@ class Ban extends Model
|
||||||
'userID',
|
'userID',
|
||||||
'reason',
|
'reason',
|
||||||
'bannedUntil',
|
'bannedUntil',
|
||||||
'userAgent',
|
'isPermanent',
|
||||||
'authorUserID',
|
'authorUserID',
|
||||||
|
|
||||||
];
|
];
|
||||||
|
|
||||||
public $dates = [
|
public $dates = [
|
||||||
'bannedUntil',
|
'suspendedUntil',
|
||||||
];
|
];
|
||||||
|
|
||||||
public function user()
|
public function user()
|
||||||
|
|
|
@ -21,7 +21,7 @@
|
||||||
|
|
||||||
namespace App\Console;
|
namespace App\Console;
|
||||||
|
|
||||||
use App\Jobs\CleanBans;
|
use App\Jobs\ProcessDueSuspensions;
|
||||||
use Illuminate\Console\Scheduling\Schedule;
|
use Illuminate\Console\Scheduling\Schedule;
|
||||||
use Illuminate\Foundation\Console\Kernel as ConsoleKernel;
|
use Illuminate\Foundation\Console\Kernel as ConsoleKernel;
|
||||||
|
|
||||||
|
@ -50,7 +50,7 @@ class Kernel extends ConsoleKernel
|
||||||
->daily();
|
->daily();
|
||||||
// Production value: Every day
|
// Production value: Every day
|
||||||
|
|
||||||
$schedule->job(new CleanBans)
|
$schedule->job(new ProcessDueSuspensions)
|
||||||
->daily();
|
->daily();
|
||||||
// Production value: Every day
|
// Production value: Every day
|
||||||
}
|
}
|
||||||
|
|
|
@ -34,48 +34,26 @@ class BanController extends Controller
|
||||||
{
|
{
|
||||||
$this->authorize('create', [Ban::class, $user]);
|
$this->authorize('create', [Ban::class, $user]);
|
||||||
|
|
||||||
// FIXME: Needs refactoring to a simpler format, e.g. parse the user's given date directly.
|
|
||||||
|
|
||||||
if (is_null($user->bans)) {
|
if (is_null($user->bans)) {
|
||||||
|
|
||||||
|
$duration = $request->duration;
|
||||||
$reason = $request->reason;
|
$reason = $request->reason;
|
||||||
$duration = strtolower($request->durationOperator);
|
$type = $request->suspensionType; // ON: Temporary | OFF: Permanent
|
||||||
$durationOperand = $request->durationOperand;
|
|
||||||
|
|
||||||
$expiryDate = now();
|
if ($type == "on") {
|
||||||
|
$expiryDate = now()->addDays($duration);
|
||||||
if (! empty($duration)) {
|
|
||||||
switch ($duration) {
|
|
||||||
case 'days':
|
|
||||||
$expiryDate->addDays($durationOperand);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case 'weeks':
|
|
||||||
$expiryDate->addWeeks($durationOperand);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case 'months':
|
|
||||||
$expiryDate->addMonths($durationOperand);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case 'years':
|
|
||||||
$expiryDate->addYears($durationOperand);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
// Essentially permanent
|
|
||||||
$expiryDate->addYears(40);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
$ban = Ban::create([
|
$ban = Ban::create([
|
||||||
'userID' => $user->id,
|
'userID' => $user->id,
|
||||||
'reason' => $reason,
|
'reason' => $reason,
|
||||||
'bannedUntil' => $expiryDate->format('Y-m-d H:i:s'),
|
'bannedUntil' => ($type == "on") ? $expiryDate->format('Y-m-d H:i:s') : null,
|
||||||
'userAgent' => 'Unknown',
|
|
||||||
'authorUserID' => Auth::user()->id,
|
'authorUserID' => Auth::user()->id,
|
||||||
|
'isPermanent' => ($type == "off") ? true : false
|
||||||
]);
|
]);
|
||||||
|
|
||||||
event(new UserBannedEvent($user, $ban));
|
$request->session()->flash('success', __('Account suspended.'));
|
||||||
$request->session()->flash('success', __('Account suspended. Suspension ID #:susId', ['susId', $ban->id]));
|
|
||||||
} else {
|
} else {
|
||||||
$request->session()->flash('error', __('Account already suspended!'));
|
$request->session()->flash('error', __('Account already suspended!'));
|
||||||
}
|
}
|
||||||
|
|
|
@ -71,6 +71,17 @@ class ProfileController extends Controller
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$suspensionInfo = null;
|
||||||
|
if ($user->isBanned())
|
||||||
|
{
|
||||||
|
$suspensionInfo = [
|
||||||
|
|
||||||
|
'isPermanent' => $user->bans->isPermanent,
|
||||||
|
'reason' => $user->bans->reason,
|
||||||
|
'bannedUntil' => $user->bans->bannedUntil
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
if (Auth::user()->is($user) || Auth::user()->can('profiles.view.others')) {
|
if (Auth::user()->is($user) || Auth::user()->can('profiles.view.others')) {
|
||||||
return view('dashboard.user.profile.displayprofile')
|
return view('dashboard.user.profile.displayprofile')
|
||||||
->with([
|
->with([
|
||||||
|
@ -82,6 +93,7 @@ class ProfileController extends Controller
|
||||||
'since' => $createdDate->englishMonth.' '.$createdDate->year,
|
'since' => $createdDate->englishMonth.' '.$createdDate->year,
|
||||||
'ipInfo' => IP::lookup($user->originalIP),
|
'ipInfo' => IP::lookup($user->originalIP),
|
||||||
'roles' => $roleList,
|
'roles' => $roleList,
|
||||||
|
'suspensionInfo' => $suspensionInfo
|
||||||
]);
|
]);
|
||||||
} else {
|
} else {
|
||||||
abort(403, __('You cannot view someone else\'s profile.'));
|
abort(403, __('You cannot view someone else\'s profile.'));
|
||||||
|
|
|
@ -45,8 +45,15 @@ class BanUserRequest extends FormRequest
|
||||||
{
|
{
|
||||||
return [
|
return [
|
||||||
'reason' => 'required|string',
|
'reason' => 'required|string',
|
||||||
'durationOperand' => 'nullable|string',
|
'suspensionType' => 'required|string',
|
||||||
'durationOperator' => 'nullable|string',
|
'duration' => 'required_if:suspensionType,on|nullable|integer',
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
public function messages()
|
||||||
|
{
|
||||||
|
return [
|
||||||
|
'duration.required_if' => __('You must provide a duration if the suspension is temporary.')
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -30,7 +30,7 @@ use Illuminate\Queue\InteractsWithQueue;
|
||||||
use Illuminate\Queue\SerializesModels;
|
use Illuminate\Queue\SerializesModels;
|
||||||
use Illuminate\Support\Facades\Log;
|
use Illuminate\Support\Facades\Log;
|
||||||
|
|
||||||
class CleanBans implements ShouldQueue
|
class ProcessDueSuspensions implements ShouldQueue
|
||||||
{
|
{
|
||||||
use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;
|
use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;
|
||||||
|
|
||||||
|
@ -52,15 +52,15 @@ class CleanBans implements ShouldQueue
|
||||||
*/
|
*/
|
||||||
public function handle()
|
public function handle()
|
||||||
{
|
{
|
||||||
Log::debug('Running automatic ban cleaner...');
|
Log::debug('Running automatic suspension cleaner...');
|
||||||
$bans = Ban::all();
|
$bans = Ban::all();
|
||||||
|
|
||||||
if (! is_null($bans)) {
|
if (! is_null($bans)) {
|
||||||
foreach ($this->bans as $ban) {
|
foreach ($this->bans as $ban) {
|
||||||
$bannedUntil = Carbon::parse($ban->bannedUntil);
|
$bannedUntil = Carbon::parse($ban->bannedUntil);
|
||||||
|
|
||||||
if ($bannedUntil->equalTo(now())) {
|
if ($bannedUntil->isToday()) {
|
||||||
Log::debug('Deleted ban '.$ban->id.' belonging to '.$ban->user->name);
|
Log::debug('Lifted expired suspension ID '.$ban->id.' for '.$ban->user->name);
|
||||||
$ban->delete();
|
$ban->delete();
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -611,5 +611,21 @@ return [
|
||||||
],
|
],
|
||||||
|
|
||||||
],
|
],
|
||||||
|
[
|
||||||
|
'name' => 'BootstrapSwitch',
|
||||||
|
'active' => true,
|
||||||
|
'files' => [
|
||||||
|
[
|
||||||
|
'type' => 'js',
|
||||||
|
'asset' => false,
|
||||||
|
'location' => 'https://cdn.jsdelivr.net/gh/gitbrent/bootstrap4-toggle@3.6.1/js/bootstrap4-toggle.min.js'
|
||||||
|
],
|
||||||
|
[
|
||||||
|
'type' => 'css',
|
||||||
|
'asset' => false,
|
||||||
|
'location' => 'https://cdn.jsdelivr.net/gh/gitbrent/bootstrap4-toggle@3.6.1/css/bootstrap4-toggle.min.css'
|
||||||
|
]
|
||||||
|
]
|
||||||
|
]
|
||||||
],
|
],
|
||||||
];
|
];
|
||||||
|
|
|
@ -0,0 +1,36 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
use Illuminate\Database\Migrations\Migration;
|
||||||
|
use Illuminate\Database\Schema\Blueprint;
|
||||||
|
use Illuminate\Support\Facades\Schema;
|
||||||
|
|
||||||
|
class ChangeBansTable extends Migration
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Run the migrations.
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function up()
|
||||||
|
{
|
||||||
|
Schema::table('bans', function (Blueprint $table) {
|
||||||
|
|
||||||
|
$table->dropColumn('userAgent');
|
||||||
|
$table->boolean('isPermanent')->default(false);
|
||||||
|
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reverse the migrations.
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function down()
|
||||||
|
{
|
||||||
|
Schema::table('bans', function (Blueprint $table) {
|
||||||
|
$table->dropColumn('isPermanent');
|
||||||
|
$table->string('userAgent')->after('bannedUntil');
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
|
@ -411,14 +411,13 @@ return [
|
||||||
'title' => ':name\'s profile',
|
'title' => ':name\'s profile',
|
||||||
'profile' => 'Profile',
|
'profile' => 'Profile',
|
||||||
'users' => 'Users',
|
'users' => 'Users',
|
||||||
'account_banned' => 'Account banned',
|
'account_banned' => 'Account suspended',
|
||||||
'account_banned_exp' => 'This user has been banned by the moderators.',
|
'account_banned_exp' => 'This user has been suspended by the admins.',
|
||||||
'ban_confirm' => 'Please confirm that you want to ban this user account. You\'ll need to add a reason and expiration date to confirm this. Bans don\'t transfer to connected Minecraft networks (yet).',
|
'ban_confirm' => 'Please confirm that you want to suspend this account. You\'ll need to add a reason and expiration date to confirm this.',
|
||||||
'leave_empty' => 'Leave empty for a permanent ban',
|
|
||||||
'duration' => 'Duration',
|
'duration' => 'Duration',
|
||||||
'p_duration' => 'Punishment duration',
|
'p_duration' => 'Suspension duration',
|
||||||
'p_duration_exp' => 'e.g. Spamming',
|
'p_duration_exp' => 'e.g. Spamming',
|
||||||
'ban' => 'Ban',
|
'ban' => 'Suspend',
|
||||||
|
|
||||||
'terminate_notice' => 'You are about to terminate a staff member',
|
'terminate_notice' => 'You are about to terminate a staff member',
|
||||||
'terminate_notice_warning' => 'Terminating a staff member will remove their privileges on the team management site and Network.
|
'terminate_notice_warning' => 'Terminating a staff member will remove their privileges on the team management site and Network.
|
||||||
|
|
|
@ -18,16 +18,16 @@
|
||||||
|
|
||||||
@section('content')
|
@section('content')
|
||||||
|
|
||||||
@if ($profile->user->isBanned())
|
@if (is_array($suspensionInfo))
|
||||||
|
|
||||||
<div class="alert alert-danger">
|
<div class="alert alert-danger">
|
||||||
|
|
||||||
<span><i class="fa fa-ban"></i> <b>{{__('messages.profile.account_banned')}}</b></span>
|
<span><i class="fa fa-ban"></i> <b>{{__('messages.profile.account_banned')}} {{ ($suspensionInfo['isPermanent']) ? __('permanently.') : __('until :date.', ['date' => $suspensionInfo['bannedUntil']]) }}</b></span>
|
||||||
|
|
||||||
<p>{{__('messages.profile.account_banned_exp')}}</p>
|
<p>{{__('messages.profile.account_banned_exp')}}</p>
|
||||||
|
|
||||||
<p>
|
<p>
|
||||||
<i class="fas fa-chevron-right"></i> <b>{{$profile->user->bans->reason}}</>
|
<i class="fas fa-chevron-right"></i> <b>{{$suspensionInfo['reason']}}</b>
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
@ -43,32 +43,33 @@
|
||||||
<form id="banAccountForm" name="banAccount" method="POST" action="{{route('banUser', ['user' => $profile->user->id])}}">
|
<form id="banAccountForm" name="banAccount" method="POST" action="{{route('banUser', ['user' => $profile->user->id])}}">
|
||||||
@csrf
|
@csrf
|
||||||
|
|
||||||
<label for="reason">{{__('messages.reusable.reason')}}</label>
|
<div class="row">
|
||||||
<input type="text" name="reason" id="reason" class="form-control" placeholder="{{__('messages.profile.p_duration_exp')}}">
|
|
||||||
|
|
||||||
<div class="input-group">
|
<div class="col">
|
||||||
<input type="text" class="form-control" name="durationOperator" aria-label="{{__('messages.profile.p_duration')}}">
|
<label for="reason">{{__('Public note')}}</label>
|
||||||
<div class="input-group-append">
|
<input type="text" name="reason" id="reason" class="form-control" placeholder="{{__('messages.profile.p_duration_exp')}}">
|
||||||
<button id="durationDropdown" class="btn btn-outline-secondary dropdown-toggle duration-btn" type="button" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">{{__('messages.profile.duration')}}</button>
|
</div>
|
||||||
<div class="dropdown-menu">
|
|
||||||
<a class="dropdown-item" href="#">Days</a>
|
<div class="col">
|
||||||
<a class="dropdown-item" href="#">Weeks</a>
|
<label for="duration">{{ __('Duration') }}</label>
|
||||||
<a class="dropdown-item" href="#">Months</a>
|
<input type="text" name="duration" id="duration" class="form-control" placeholder="{{ __('in days') }}">
|
||||||
<div role="separator" class="dropdown-divider"></div>
|
|
||||||
<a class="dropdown-item" href="#">Years</a>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
|
||||||
<p class="text-muted text-sm">{{__('messages.profile.leave_empty')}}</p>
|
|
||||||
|
|
||||||
<input id="operator" type="hidden" value="" name="durationOperand" class="duration-operator-fld">
|
|
||||||
|
<div class="mt-2">
|
||||||
|
<input type="hidden" name="suspensionType" value="off">
|
||||||
|
|
||||||
|
<label for="suspensionType">Suspension type</label><br>
|
||||||
|
<input type="checkbox" id="suspensionType" name="suspensionType" checked data-toggle="toggle" data-on="Temporary" data-off="Permanent" data-onstyle="success" data-offstyle="danger" data-width="130" data-height="40">
|
||||||
|
<p class="text-muted text-sm"><i class="fas fa-info-circle"></i> {{ __('Temporary suspensions will be automatically lifted. The suspension note is visible to all users. Suspended users will not be able to login or register.') }}</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
|
||||||
</form>
|
</form>
|
||||||
|
|
||||||
<x-slot name="modalFooter">
|
<x-slot name="modalFooter">
|
||||||
|
<button id="banAccountButton" type="button" class="btn btn-danger"><i class="fa fa-gavel"></i> {{__('Confirm')}}</button>
|
||||||
<button id="banAccountButton" type="button" class="btn btn-danger"><i class="fa fa-ban"></i> {{__('messages.profile.ban')}}</button>
|
|
||||||
|
|
||||||
</x-slot>
|
</x-slot>
|
||||||
|
|
||||||
</x-modal>
|
</x-modal>
|
||||||
|
@ -334,13 +335,13 @@
|
||||||
<div class="management-btn text-center">
|
<div class="management-btn text-center">
|
||||||
|
|
||||||
@if (!$profile->user->isBanned())
|
@if (!$profile->user->isBanned())
|
||||||
<button class="btn btn-danger mb-2" id="banAccountTrigger"><i class="fa fa-ban"></i> {{__('messages.profile.ban_acc')}}</button><br>
|
<button class="btn btn-danger mb-2" id="banAccountTrigger"><i class="fa fa-ban"></i> {{__('Suspend')}}</button><br>
|
||||||
@else
|
@else
|
||||||
<form method="post" action="{{route('unbanUser', ['user' => $profile->user->id])}}">
|
<form method="post" action="{{route('unbanUser', ['user' => $profile->user->id])}}">
|
||||||
|
|
||||||
@method('DELETE')
|
@method('DELETE')
|
||||||
@csrf
|
@csrf
|
||||||
<button type="submit" class="btn btn-warning mb-2"><i class="fa fa-check"></i> {{__('messages.profile.unban_acc')}}</button>
|
<button type="submit" class="btn btn-warning mb-2"><i class="fa fa-check"></i> {{__('Lift Suspension')}}</button>
|
||||||
|
|
||||||
</form>
|
</form>
|
||||||
@endif
|
@endif
|
||||||
|
|
Loading…
Reference in New Issue