Catalog changes and punishments.
- Updated pagination to 35 assets per page in order to fit with newer card scaling. - Implemented the ability to go to traverse pages in the shop. - Allowed the CPU/Memory usage updater job to run when the site is under maintenance. - User punishments. - Revamped punishment notice page. - Created middleware to redirect to punishment notice page when a punishment is active. - Completed moderation status label on user admin/search pages. - Added routes for punishments. - Fixed user homepage button on user admin page. - Added punishments section on user admin page. - Removed legacy bans. - Prevent banned user thumbnails from being rendered.
This commit is contained in:
parent
241f2deb16
commit
0083a01d85
|
|
@ -17,7 +17,7 @@ class Kernel extends ConsoleKernel
|
||||||
*/
|
*/
|
||||||
protected function schedule(Schedule $schedule)
|
protected function schedule(Schedule $schedule)
|
||||||
{
|
{
|
||||||
$schedule->job(new UpdateUsageCounters)->everyMinute();
|
$schedule->job(new UpdateUsageCounters)->everyMinute()->evenInMaintenanceMode();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
||||||
|
|
@ -46,7 +46,6 @@ class CommentsController extends Controller
|
||||||
];
|
];
|
||||||
|
|
||||||
foreach($comments as $comment) {
|
foreach($comments as $comment) {
|
||||||
// TODO: XlXi: user profile link
|
|
||||||
$poster = [
|
$poster = [
|
||||||
'name' => $comment->user->username,
|
'name' => $comment->user->username,
|
||||||
'thumbnail' => 'https://www.virtubrick.local/images/testing/headshot.png',
|
'thumbnail' => 'https://www.virtubrick.local/images/testing/headshot.png',
|
||||||
|
|
|
||||||
|
|
@ -65,7 +65,7 @@ class ShopController extends Controller
|
||||||
|
|
||||||
$assets = self::getAssets($valid['assetTypeId'], (isset($valid['gearGenreId']) ? $valid['gearGenreId'] : null));
|
$assets = self::getAssets($valid['assetTypeId'], (isset($valid['gearGenreId']) ? $valid['gearGenreId'] : null));
|
||||||
$assets = $assets->orderByDesc('created_at')
|
$assets = $assets->orderByDesc('created_at')
|
||||||
->paginate(30);
|
->paginate(35);
|
||||||
|
|
||||||
$data = [];
|
$data = [];
|
||||||
foreach($assets as $asset) {
|
foreach($assets as $asset) {
|
||||||
|
|
|
||||||
|
|
@ -31,11 +31,10 @@ class ThumbnailController extends Controller
|
||||||
|
|
||||||
private function userValidationRules()
|
private function userValidationRules()
|
||||||
{
|
{
|
||||||
// TODO: Fail validation if user is moderated.
|
|
||||||
return [
|
return [
|
||||||
'id' => [
|
'id' => [
|
||||||
'required',
|
'required',
|
||||||
Rule::exists('App\Models\User', 'id')
|
Rule::exists('App\Models\User', 'id'),
|
||||||
],
|
],
|
||||||
'position' => ['sometimes', 'regex:/(Full|Bust)/i'],
|
'position' => ['sometimes', 'regex:/(Full|Bust)/i'],
|
||||||
'type' => 'regex:/(3D|2D)/i'
|
'type' => 'regex:/(3D|2D)/i'
|
||||||
|
|
@ -55,7 +54,13 @@ class ThumbnailController extends Controller
|
||||||
$valid['type'] = strtolower($valid['type']);
|
$valid['type'] = strtolower($valid['type']);
|
||||||
|
|
||||||
if($renderType == 'User') {
|
if($renderType == 'User') {
|
||||||
if($valid['position'] == null)
|
if($model->hasActivePunishment() && $model->getPunishment()->isDeletion())
|
||||||
|
{
|
||||||
|
$validator->errors()->add('id', 'User is moderated');
|
||||||
|
return ValidationHelper::generateValidatorError($validator);
|
||||||
|
}
|
||||||
|
|
||||||
|
if(!array_key_exists('position', $valid))
|
||||||
$valid['position'] = 'Full';
|
$valid['position'] = 'Full';
|
||||||
|
|
||||||
$valid['position'] = strtolower($valid['position']);
|
$valid['position'] = strtolower($valid['position']);
|
||||||
|
|
@ -109,9 +114,9 @@ class ThumbnailController extends Controller
|
||||||
return $this->handleRender($request, 'Asset');
|
return $this->handleRender($request, 'Asset');
|
||||||
}
|
}
|
||||||
|
|
||||||
public function renderUser()
|
public function renderUser(Request $request)
|
||||||
{
|
{
|
||||||
return handleRender($request, 'User');
|
return $this->handleRender($request, 'User');
|
||||||
}
|
}
|
||||||
|
|
||||||
public function tryAsset()
|
public function tryAsset()
|
||||||
|
|
|
||||||
|
|
@ -1,14 +0,0 @@
|
||||||
<?php
|
|
||||||
|
|
||||||
namespace App\Http\Controllers\Web\Auth;
|
|
||||||
|
|
||||||
use Illuminate\Http\Request;
|
|
||||||
use App\Http\Controllers\Controller;
|
|
||||||
|
|
||||||
class UserModerationController extends Controller
|
|
||||||
{
|
|
||||||
public function create()
|
|
||||||
{
|
|
||||||
return view('web.auth.moderated');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -0,0 +1,28 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Http\Controllers\Web;
|
||||||
|
|
||||||
|
use Illuminate\Support\Facades\Auth;
|
||||||
|
use Illuminate\Http\Request;
|
||||||
|
|
||||||
|
use App\Http\Controllers\Controller;
|
||||||
|
|
||||||
|
class ModerationController extends Controller
|
||||||
|
{
|
||||||
|
public function notice(Request $request)
|
||||||
|
{
|
||||||
|
return view('web.auth.moderated')->with('punishment', Auth::user()->getPunishment());
|
||||||
|
}
|
||||||
|
|
||||||
|
public function reactivate(Request $request)
|
||||||
|
{
|
||||||
|
$punishment = Auth::user()->getPunishment();
|
||||||
|
if(!$punishment || !$punishment->expired())
|
||||||
|
return redirect()->back();
|
||||||
|
|
||||||
|
$punishment->active = false;
|
||||||
|
$punishment->save();
|
||||||
|
|
||||||
|
return redirect()->back();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -11,6 +11,9 @@ class ProfileController extends Controller
|
||||||
{
|
{
|
||||||
protected function index(Request $request, User $user)
|
protected function index(Request $request, User $user)
|
||||||
{
|
{
|
||||||
|
if($user->hasActivePunishment() && $user->getPunishment()->isDeletion())
|
||||||
|
abort(404);
|
||||||
|
|
||||||
return view('web.user.profile')->with([
|
return view('web.user.profile')->with([
|
||||||
'title' => sprintf('Profile of %s', $user->username),
|
'title' => sprintf('Profile of %s', $user->username),
|
||||||
'user' => $user
|
'user' => $user
|
||||||
|
|
|
||||||
|
|
@ -25,7 +25,7 @@ class Kernel extends HttpKernel
|
||||||
\Illuminate\View\Middleware\ShareErrorsFromSession::class,
|
\Illuminate\View\Middleware\ShareErrorsFromSession::class,
|
||||||
\Illuminate\Foundation\Http\Middleware\ValidatePostSize::class,
|
\Illuminate\Foundation\Http\Middleware\ValidatePostSize::class,
|
||||||
\App\Http\Middleware\TrimStrings::class,
|
\App\Http\Middleware\TrimStrings::class,
|
||||||
\Illuminate\Foundation\Http\Middleware\ConvertEmptyStringsToNull::class,
|
\Illuminate\Foundation\Http\Middleware\ConvertEmptyStringsToNull::class
|
||||||
];
|
];
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -43,14 +43,15 @@ class Kernel extends HttpKernel
|
||||||
// XlXi: Yeah no, the double session protector was stupid.
|
// XlXi: Yeah no, the double session protector was stupid.
|
||||||
//\App\Http\Middleware\DoubleSessionProtector::class, // Prevents DDoS attacks.
|
//\App\Http\Middleware\DoubleSessionProtector::class, // Prevents DDoS attacks.
|
||||||
\App\Http\Middleware\DailyReward::class,
|
\App\Http\Middleware\DailyReward::class,
|
||||||
\App\Http\Middleware\LastSeenMiddleware::class
|
\App\Http\Middleware\LastSeenMiddleware::class,
|
||||||
|
\App\Http\Middleware\UserPunishmentMiddleware::class
|
||||||
],
|
],
|
||||||
|
|
||||||
'api' => [
|
'api' => [
|
||||||
\App\Http\Middleware\PreventRequestsDuringMaintenance::class,
|
|
||||||
|
|
||||||
// \Laravel\Sanctum\Http\Middleware\EnsureFrontendRequestsAreStateful::class,
|
// \Laravel\Sanctum\Http\Middleware\EnsureFrontendRequestsAreStateful::class,
|
||||||
\Illuminate\Routing\Middleware\SubstituteBindings::class,
|
\Illuminate\Routing\Middleware\SubstituteBindings::class,
|
||||||
|
|
||||||
|
\App\Http\Middleware\UserPunishmentMiddleware::class
|
||||||
],
|
],
|
||||||
];
|
];
|
||||||
|
|
||||||
|
|
@ -74,7 +75,6 @@ class Kernel extends HttpKernel
|
||||||
'verified' => \Illuminate\Auth\Middleware\EnsureEmailIsVerified::class,
|
'verified' => \Illuminate\Auth\Middleware\EnsureEmailIsVerified::class,
|
||||||
|
|
||||||
'roleset' => \App\Http\Middleware\Roleset::class,
|
'roleset' => \App\Http\Middleware\Roleset::class,
|
||||||
'banned' => \App\Http\Middleware\CheckBan::class,
|
|
||||||
'lastseen' => \App\Http\Middleware\LastSeenMiddleware::class,
|
'lastseen' => \App\Http\Middleware\LastSeenMiddleware::class,
|
||||||
'csrf' => \App\Http\Middleware\VerifyCsrfToken::class,
|
'csrf' => \App\Http\Middleware\VerifyCsrfToken::class,
|
||||||
];
|
];
|
||||||
|
|
|
||||||
|
|
@ -1,31 +0,0 @@
|
||||||
<?php
|
|
||||||
|
|
||||||
namespace App\Http\Middleware;
|
|
||||||
|
|
||||||
use Closure;
|
|
||||||
use Illuminate\Http\Request;
|
|
||||||
use Illuminate\Support\Facades\Auth;
|
|
||||||
|
|
||||||
class CheckBan
|
|
||||||
{
|
|
||||||
/**
|
|
||||||
* Handle an incoming request.
|
|
||||||
*
|
|
||||||
* @param \Illuminate\Http\Request $request
|
|
||||||
* @param \Closure(\Illuminate\Http\Request): (\Illuminate\Http\Response|\Illuminate\Http\RedirectResponse) $next
|
|
||||||
* @return \Illuminate\Http\Response|\Illuminate\Http\RedirectResponse
|
|
||||||
*/
|
|
||||||
public function handle(Request $request, Closure $next)
|
|
||||||
{
|
|
||||||
if(Auth::check() && Auth::user()->banId != null) {
|
|
||||||
if($request->route()->getName() != 'moderation.notice' && $request->route()->getName() != 'logout') {
|
|
||||||
return redirect()
|
|
||||||
->to(route('moderation.notice', [], 302));
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
return redirect('/', 302);
|
|
||||||
}
|
|
||||||
|
|
||||||
return $next($request);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -0,0 +1,52 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Http\Middleware;
|
||||||
|
|
||||||
|
use Closure;
|
||||||
|
use Illuminate\Support\Facades\Auth;
|
||||||
|
use Illuminate\Http\Request;
|
||||||
|
|
||||||
|
class UserPunishmentMiddleware
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Handle an incoming request.
|
||||||
|
*
|
||||||
|
* @param \Illuminate\Http\Request $request
|
||||||
|
* @param \Closure(\Illuminate\Http\Request): (\Illuminate\Http\Response|\Illuminate\Http\RedirectResponse) $next
|
||||||
|
* @return \Illuminate\Http\Response|\Illuminate\Http\RedirectResponse
|
||||||
|
*/
|
||||||
|
public function handle(Request $request, Closure $next)
|
||||||
|
{
|
||||||
|
$isPunishmentRoute = str_starts_with($request->route()->getName(), 'punishment.');
|
||||||
|
if(Auth::user() && Auth::user()->hasActivePunishment())
|
||||||
|
{
|
||||||
|
if($isPunishmentRoute || $request->route()->getName() == 'auth.logout')
|
||||||
|
return $next($request);
|
||||||
|
|
||||||
|
if(in_array('api', $request->route()->middleware()))
|
||||||
|
{
|
||||||
|
if($request->route()->getName() == 'content') // cdn.virtubrick.net
|
||||||
|
return $next($request);
|
||||||
|
|
||||||
|
return response(['errors' => [['code' => 0, 'message' => 'User is moderated']]], 403)
|
||||||
|
->header('Cache-Control', 'private')
|
||||||
|
->header('Content-Type', 'application/json; charset=utf-8');
|
||||||
|
}
|
||||||
|
|
||||||
|
// Not an API route.
|
||||||
|
if(!$isPunishmentRoute)
|
||||||
|
return redirect()->route('punishment.notice', ['ReturnUrl' => url()->full()]);
|
||||||
|
}
|
||||||
|
elseif($isPunishmentRoute)
|
||||||
|
{
|
||||||
|
$returnUrl = $request->input('ReturnUrl');
|
||||||
|
|
||||||
|
if(!$returnUrl)
|
||||||
|
$returnUrl = '/';
|
||||||
|
|
||||||
|
return redirect($returnUrl);
|
||||||
|
}
|
||||||
|
|
||||||
|
return $next($request);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,84 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Models;
|
||||||
|
|
||||||
|
use Carbon\Carbon;
|
||||||
|
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||||
|
use Illuminate\Database\Eloquent\Model;
|
||||||
|
|
||||||
|
class Punishment extends Model
|
||||||
|
{
|
||||||
|
use HasFactory;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The attributes that should be cast.
|
||||||
|
*
|
||||||
|
* @var array<string, string>
|
||||||
|
*/
|
||||||
|
protected $casts = [
|
||||||
|
'expiration' => 'datetime',
|
||||||
|
'created_at' => 'datetime',
|
||||||
|
'updated_at' => 'datetime'
|
||||||
|
];
|
||||||
|
|
||||||
|
public function punishment_type()
|
||||||
|
{
|
||||||
|
return $this->belongsTo(PunishmentType::class, 'punishment_type_id');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function user()
|
||||||
|
{
|
||||||
|
return $this->belongsTo(User::class, 'user_id');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function moderator()
|
||||||
|
{
|
||||||
|
return $this->belongsTo(User::class, 'moderator_id');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function pardoner()
|
||||||
|
{
|
||||||
|
return $this->belongsTo(User::class, 'pardoner_id');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function context()
|
||||||
|
{
|
||||||
|
return $this->hasMany(PunishmentContext::class, 'punishment_id');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function expired()
|
||||||
|
{
|
||||||
|
if($this->user->hasRoleset('Owner'))
|
||||||
|
return true;
|
||||||
|
|
||||||
|
if(!$this->expiration)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
return !$this->isDeletion() && Carbon::now()->greaterThan($this->expiration);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function isDeletion()
|
||||||
|
{
|
||||||
|
return $this->punishment_type->time === null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function reviewed()
|
||||||
|
{
|
||||||
|
return $this->created_at->isoFormat('lll');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function expirationStr()
|
||||||
|
{
|
||||||
|
if(!$this->expiration)
|
||||||
|
return 'Never';
|
||||||
|
|
||||||
|
return $this->created_at->isoFormat('lll');
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function activeFor($userId)
|
||||||
|
{
|
||||||
|
return self::where('user_id', $userId)
|
||||||
|
->where('active', true)
|
||||||
|
->orderByDesc('id');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,11 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Models;
|
||||||
|
|
||||||
|
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||||
|
use Illuminate\Database\Eloquent\Model;
|
||||||
|
|
||||||
|
class PunishmentContext extends Model
|
||||||
|
{
|
||||||
|
use HasFactory;
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,21 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Models;
|
||||||
|
|
||||||
|
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||||
|
use Illuminate\Database\Eloquent\Model;
|
||||||
|
|
||||||
|
class PunishmentType extends Model
|
||||||
|
{
|
||||||
|
use HasFactory;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The attributes that are mass assignable.
|
||||||
|
*
|
||||||
|
* @var array
|
||||||
|
*/
|
||||||
|
protected $fillable = [
|
||||||
|
'label',
|
||||||
|
'time'
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
@ -132,6 +132,21 @@ class User extends Authenticatable implements MustVerifyEmail
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function hasActivePunishment()
|
||||||
|
{
|
||||||
|
return Punishment::activeFor($this->id)->exists();
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getPunishment()
|
||||||
|
{
|
||||||
|
return Punishment::activeFor($this->id)->first();
|
||||||
|
}
|
||||||
|
|
||||||
|
public function punishments()
|
||||||
|
{
|
||||||
|
return $this->hasMany(Punishment::class, 'user_id');
|
||||||
|
}
|
||||||
|
|
||||||
public function _hasRolesetInternal($roleName)
|
public function _hasRolesetInternal($roleName)
|
||||||
{
|
{
|
||||||
$roleset = Roleset::where('Name', $roleName)->first();
|
$roleset = Roleset::where('Name', $roleName)->first();
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,28 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\View\Components\Admin;
|
||||||
|
|
||||||
|
use Illuminate\View\Component;
|
||||||
|
|
||||||
|
class ModerationStatus extends Component
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Create a new component instance.
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function __construct()
|
||||||
|
{
|
||||||
|
//
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the view / contents that represent the component.
|
||||||
|
*
|
||||||
|
* @return \Illuminate\Contracts\View\View|\Closure|string
|
||||||
|
*/
|
||||||
|
public function render()
|
||||||
|
{
|
||||||
|
return view('components.admin.moderation-status');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -20,7 +20,6 @@ return new class extends Migration
|
||||||
$table->dateTime('email_verified_at')->nullable();
|
$table->dateTime('email_verified_at')->nullable();
|
||||||
$table->string('password');
|
$table->string('password');
|
||||||
$table->rememberToken();
|
$table->rememberToken();
|
||||||
$table->unsignedBigInteger('banId')->nullable();
|
|
||||||
|
|
||||||
$table->string('biography')->nullable();
|
$table->string('biography')->nullable();
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,40 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
use Illuminate\Database\Migrations\Migration;
|
||||||
|
use Illuminate\Database\Schema\Blueprint;
|
||||||
|
use Illuminate\Support\Facades\Schema;
|
||||||
|
|
||||||
|
return new class extends Migration
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Run the migrations.
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function up()
|
||||||
|
{
|
||||||
|
Schema::create('punishments', function (Blueprint $table) {
|
||||||
|
$table->id();
|
||||||
|
|
||||||
|
$table->unsignedTinyInteger('punishment_type_id');
|
||||||
|
$table->boolean('active');
|
||||||
|
$table->string('user_note');
|
||||||
|
$table->unsignedBigInteger('user_id');
|
||||||
|
$table->unsignedBigInteger('moderator_id');
|
||||||
|
$table->unsignedBigInteger('pardoner_id')->nullable();
|
||||||
|
$table->timestamp('expiration')->nullable();
|
||||||
|
|
||||||
|
$table->timestamps();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reverse the migrations.
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function down()
|
||||||
|
{
|
||||||
|
Schema::dropIfExists('punishments');
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
@ -0,0 +1,35 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
use Illuminate\Database\Migrations\Migration;
|
||||||
|
use Illuminate\Database\Schema\Blueprint;
|
||||||
|
use Illuminate\Support\Facades\Schema;
|
||||||
|
|
||||||
|
return new class extends Migration
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Run the migrations.
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function up()
|
||||||
|
{
|
||||||
|
Schema::create('punishment_types', function (Blueprint $table) {
|
||||||
|
$table->id();
|
||||||
|
|
||||||
|
$table->string('label');
|
||||||
|
$table->integer('time')->nullable();
|
||||||
|
|
||||||
|
$table->timestamps();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reverse the migrations.
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function down()
|
||||||
|
{
|
||||||
|
Schema::dropIfExists('punishment_types');
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
@ -0,0 +1,37 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
use Illuminate\Database\Migrations\Migration;
|
||||||
|
use Illuminate\Database\Schema\Blueprint;
|
||||||
|
use Illuminate\Support\Facades\Schema;
|
||||||
|
|
||||||
|
return new class extends Migration
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Run the migrations.
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function up()
|
||||||
|
{
|
||||||
|
Schema::create('punishment_contexts', function (Blueprint $table) {
|
||||||
|
$table->id();
|
||||||
|
|
||||||
|
$table->unsignedBigInteger('punishment_id');
|
||||||
|
$table->string('user_note');
|
||||||
|
$table->longText('description')->nullable();
|
||||||
|
$table->string('content_hash')->nullable()->comment('Will display an image from the CDN.');
|
||||||
|
|
||||||
|
$table->timestamps();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reverse the migrations.
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function down()
|
||||||
|
{
|
||||||
|
Schema::dropIfExists('punishment_contexts');
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
@ -18,7 +18,8 @@ class DatabaseSeeder extends Seeder
|
||||||
WebConfigurationSeeder::class,
|
WebConfigurationSeeder::class,
|
||||||
AssetTypeSeeder::class,
|
AssetTypeSeeder::class,
|
||||||
UsageCounterSeeder::class,
|
UsageCounterSeeder::class,
|
||||||
RolesetSeeder::class
|
RolesetSeeder::class,
|
||||||
|
PunishmentTypeSeeder::class
|
||||||
//FFlagSeeder::class
|
//FFlagSeeder::class
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,27 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Database\Seeders;
|
||||||
|
|
||||||
|
use Illuminate\Database\Console\Seeds\WithoutModelEvents;
|
||||||
|
use Illuminate\Database\Seeder;
|
||||||
|
|
||||||
|
use App\Models\PunishmentType;
|
||||||
|
|
||||||
|
class PunishmentTypeSeeder extends Seeder
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Run the database seeds.
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function run()
|
||||||
|
{
|
||||||
|
PunishmentType::create(['label' => 'Reminder', 'time' => 0]);
|
||||||
|
PunishmentType::create(['label' => 'Warning', 'time' => 0]);
|
||||||
|
PunishmentType::create(['label' => 'Banned for 1 Day', 'time' => 1]);
|
||||||
|
PunishmentType::create(['label' => 'Banned for 3 Days', 'time' => 3]);
|
||||||
|
PunishmentType::create(['label' => 'Banned for 7 Days', 'time' => 7]);
|
||||||
|
PunishmentType::create(['label' => 'Banned for 14 Days', 'time' => 14]);
|
||||||
|
PunishmentType::create(['label' => 'Account Deleted']);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -150,7 +150,9 @@ class ShopCategoryButton extends Component {
|
||||||
}
|
}
|
||||||
|
|
||||||
handleClick() {
|
handleClick() {
|
||||||
this.props.navigateCategory(this.props.id, this.data);
|
this.props.setPage(1, true, () => {
|
||||||
|
this.props.navigateCategory(this.props.id, this.data);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
|
|
@ -177,7 +179,7 @@ class ShopCategories extends Component {
|
||||||
return (
|
return (
|
||||||
<div className="virtubrick-shop-categories">
|
<div className="virtubrick-shop-categories">
|
||||||
<h5>Category</h5>
|
<h5>Category</h5>
|
||||||
<ShopCategoryButton id="all" label="All Items" getCategoryAssetTypeByLabel={this.props.getCategoryAssetTypeByLabel} getCategoryAssetTypeIds={this.props.getCategoryAssetTypeIds} navigateCategory={this.props.navigateCategory} shopState={this.props.shopState} />
|
<ShopCategoryButton id="all" label="All Items" getCategoryAssetTypeByLabel={this.props.getCategoryAssetTypeByLabel} getCategoryAssetTypeIds={this.props.getCategoryAssetTypeIds} navigateCategory={this.props.navigateCategory} shopState={this.props.shopState} setPage={this.props.setPage} />
|
||||||
<ul className="list-unstyled ps-0">
|
<ul className="list-unstyled ps-0">
|
||||||
{
|
{
|
||||||
Object.keys(shopCategories).map((categoryName, index) =>
|
Object.keys(shopCategories).map((categoryName, index) =>
|
||||||
|
|
@ -185,10 +187,10 @@ class ShopCategories extends Component {
|
||||||
<a className="text-decoration-none fw-normal align-items-center virtubrick-list-dropdown" data-bs-toggle="collapse" data-bs-target={`#${makeCategoryId(categoryName, 'collapse')}`} aria-expanded={(index === 0 ? 'true' : 'false')} href="#">{ categoryName }</a>
|
<a className="text-decoration-none fw-normal align-items-center virtubrick-list-dropdown" data-bs-toggle="collapse" data-bs-target={`#${makeCategoryId(categoryName, 'collapse')}`} aria-expanded={(index === 0 ? 'true' : 'false')} href="#">{ categoryName }</a>
|
||||||
<div className={classNames({'collapse': true, 'show': (index === 0)})} id={makeCategoryId(categoryName, 'collapse')}>
|
<div className={classNames({'collapse': true, 'show': (index === 0)})} id={makeCategoryId(categoryName, 'collapse')}>
|
||||||
<ul className="btn-toggle-nav list-unstyled fw-normal small">
|
<ul className="btn-toggle-nav list-unstyled fw-normal small">
|
||||||
<li><ShopCategoryButton id={makeCategoryId(`all-${categoryName}`, 'type')} label={`All ${categoryName}`} categoryName={categoryName} getCategoryAssetTypeByLabel={this.props.getCategoryAssetTypeByLabel} getCategoryAssetTypeIds={this.props.getCategoryAssetTypeIds} navigateCategory={this.props.navigateCategory} shopState={this.props.shopState} /></li>
|
<li><ShopCategoryButton id={makeCategoryId(`all-${categoryName}`, 'type')} label={`All ${categoryName}`} categoryName={categoryName} getCategoryAssetTypeByLabel={this.props.getCategoryAssetTypeByLabel} getCategoryAssetTypeIds={this.props.getCategoryAssetTypeIds} navigateCategory={this.props.navigateCategory} shopState={this.props.shopState} setPage={this.props.setPage} /></li>
|
||||||
{
|
{
|
||||||
shopCategories[categoryName].map(({label, assetTypeId, gearGenreId}, index) =>
|
shopCategories[categoryName].map(({label, assetTypeId, gearGenreId}, index) =>
|
||||||
<li><ShopCategoryButton id={makeCategoryId(`${label}-${categoryName}`, 'type')} label={label} categoryName={categoryName} getCategoryAssetTypeByLabel={this.props.getCategoryAssetTypeByLabel} getCategoryAssetTypeIds={this.props.getCategoryAssetTypeIds} navigateCategory={this.props.navigateCategory} shopState={this.props.shopState} /></li>
|
<li><ShopCategoryButton id={makeCategoryId(`${label}-${categoryName}`, 'type')} label={label} categoryName={categoryName} getCategoryAssetTypeByLabel={this.props.getCategoryAssetTypeByLabel} getCategoryAssetTypeIds={this.props.getCategoryAssetTypeIds} navigateCategory={this.props.navigateCategory} shopState={this.props.shopState} setPage={this.props.setPage} /></li>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
</ul>
|
</ul>
|
||||||
|
|
@ -271,10 +273,13 @@ class Shop extends Component {
|
||||||
pageLoaded: true,
|
pageLoaded: true,
|
||||||
pageNumber: null,
|
pageNumber: null,
|
||||||
pageCount: null,
|
pageCount: null,
|
||||||
error: false
|
error: false,
|
||||||
|
dataMem: false
|
||||||
};
|
};
|
||||||
|
|
||||||
this.navigateCategory = this.navigateCategory.bind(this);
|
this.navigateCategory = this.navigateCategory.bind(this);
|
||||||
|
this.incrementPage = this.incrementPage.bind(this);
|
||||||
|
this.setPage = this.setPage.bind(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
getCategoryAssetTypeIds(categoryName) {
|
getCategoryAssetTypeIds(categoryName) {
|
||||||
|
|
@ -304,14 +309,23 @@ class Shop extends Component {
|
||||||
return assetType;
|
return assetType;
|
||||||
}
|
}
|
||||||
|
|
||||||
navigateCategory(categoryId, data) {
|
navigateCategory(categoryId, dataraw) {
|
||||||
this.setState({selectedCategoryId: categoryId, pageLoaded: false});
|
if(this.state.pageLoaded == false) return;
|
||||||
|
|
||||||
|
this.setState({selectedCategoryId: categoryId, dataMem: dataraw, pageLoaded: false});
|
||||||
|
|
||||||
let url = buildGenericApiUrl('api', 'shop/v1/list-json');
|
let url = buildGenericApiUrl('api', 'shop/v1/list-json');
|
||||||
|
|
||||||
|
if (this.state.pageNumber == null || this.state.pageNumber == 1)
|
||||||
|
this.setState({pageNumber: 1});
|
||||||
|
|
||||||
let paramIterator = 0;
|
let paramIterator = 0;
|
||||||
|
let data = {...dataraw, page: this.state.pageNumber};
|
||||||
Object.keys(data).filter(key => {
|
Object.keys(data).filter(key => {
|
||||||
if (key == 'label')
|
if (key == 'label')
|
||||||
return false;
|
return false;
|
||||||
|
else if (key == 'page' && (data[key] == null || data[key] == 1))
|
||||||
|
return false;
|
||||||
return true;
|
return true;
|
||||||
}).map(key => {
|
}).map(key => {
|
||||||
url += ((paramIterator++ == 0 ? '?' : '&') + `${key}=${data[key]}`);
|
url += ((paramIterator++ == 0 ? '?' : '&') + `${key}=${data[key]}`);
|
||||||
|
|
@ -321,7 +335,7 @@ class Shop extends Component {
|
||||||
.then(res => {
|
.then(res => {
|
||||||
const items = res.data;
|
const items = res.data;
|
||||||
|
|
||||||
this.setState({ pageItems: items.data, pageCount: items.pages, pageNumber: 1, pageLoaded: true, error: false });
|
this.setState({ pageItems: items.data, pageCount: items.pages, pageLoaded: true, error: false });
|
||||||
}).catch(err => {
|
}).catch(err => {
|
||||||
const data = err.response.data;
|
const data = err.response.data;
|
||||||
|
|
||||||
|
|
@ -334,6 +348,22 @@ class Shop extends Component {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
incrementPage(amount) {
|
||||||
|
this.setPage(this.state.pageNumber + amount);
|
||||||
|
}
|
||||||
|
|
||||||
|
setPage(page, bypass = false, callback) {
|
||||||
|
if(!bypass && this.state.pageLoaded == false) return;
|
||||||
|
|
||||||
|
this.setState({pageNumber: page}, () => {
|
||||||
|
if(callback)
|
||||||
|
callback();
|
||||||
|
|
||||||
|
if(!bypass)
|
||||||
|
this.navigateCategory(this.state.selectedCategoryId, this.state.dataMem);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
return (
|
return (
|
||||||
<div className="container-lg my-2">
|
<div className="container-lg my-2">
|
||||||
|
|
@ -351,7 +381,7 @@ class Shop extends Component {
|
||||||
</div>
|
</div>
|
||||||
<div className="row">
|
<div className="row">
|
||||||
<div className="col-md-2">
|
<div className="col-md-2">
|
||||||
<ShopCategories getCategoryAssetTypeByLabel={this.getCategoryAssetTypeByLabel} getCategoryAssetTypeIds={this.getCategoryAssetTypeIds} navigateCategory={this.navigateCategory} shopState={this.state} />
|
<ShopCategories getCategoryAssetTypeByLabel={this.getCategoryAssetTypeByLabel} getCategoryAssetTypeIds={this.getCategoryAssetTypeIds} navigateCategory={this.navigateCategory} shopState={this.state} setPage={this.setPage} />
|
||||||
</div>
|
</div>
|
||||||
<div className="col-md-10 d-flex flex-column">
|
<div className="col-md-10 d-flex flex-column">
|
||||||
<div className="card p-3">
|
<div className="card p-3">
|
||||||
|
|
@ -386,7 +416,7 @@ class Shop extends Component {
|
||||||
this.state.pageCount > 1 ?
|
this.state.pageCount > 1 ?
|
||||||
<ul className="list-inline mx-auto mt-3">
|
<ul className="list-inline mx-auto mt-3">
|
||||||
<li className="list-inline-item">
|
<li className="list-inline-item">
|
||||||
<button className="btn btn-secondary" disabled={(this.state.pageNumber <= 1) ? true : null}><i className="fa-solid fa-angle-left"></i></button>
|
<button className="btn btn-secondary" disabled={(this.state.pageNumber <= 1) ? true : null} onClick={ () => this.incrementPage(-1) }><i className="fa-solid fa-angle-left"></i></button>
|
||||||
</li>
|
</li>
|
||||||
<li className="list-inline-item virtubrick-paginator">
|
<li className="list-inline-item virtubrick-paginator">
|
||||||
<span>Page </span>
|
<span>Page </span>
|
||||||
|
|
@ -394,7 +424,7 @@ class Shop extends Component {
|
||||||
<span> of { this.state.pageCount || '???' }</span>
|
<span> of { this.state.pageCount || '???' }</span>
|
||||||
</li>
|
</li>
|
||||||
<li className="list-inline-item">
|
<li className="list-inline-item">
|
||||||
<button className="btn btn-secondary" disabled={(this.state.pageNumber >= this.state.pageCount) ? true : null}><i className="fa-solid fa-angle-right"></i></button>
|
<button className="btn btn-secondary" disabled={(this.state.pageNumber >= this.state.pageCount) ? true : null} onClick={ () => this.incrementPage(1) }><i className="fa-solid fa-angle-right"></i></button>
|
||||||
</li>
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
:
|
:
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,19 @@
|
||||||
|
@props([
|
||||||
|
'user'
|
||||||
|
])
|
||||||
|
|
||||||
|
@php
|
||||||
|
$color = 'text-';
|
||||||
|
$label = 'Unknown';
|
||||||
|
if($user->hasActivePunishment())
|
||||||
|
{
|
||||||
|
$color .= 'danger';
|
||||||
|
$label = $user->getPunishment()->punishment_type->label;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
$color .= 'success';
|
||||||
|
$label = 'OK';
|
||||||
|
}
|
||||||
|
@endphp
|
||||||
|
<p class="{{ $color }}">{{ $label }}</p>
|
||||||
|
|
@ -61,7 +61,7 @@
|
||||||
@endif
|
@endif
|
||||||
<x-admin.user-admin-label label="Username">{{ $user->username }}</x-admin.user-admin-label>
|
<x-admin.user-admin-label label="Username">{{ $user->username }}</x-admin.user-admin-label>
|
||||||
<x-admin.user-admin-label label="Previous User Names"><b>TODO</b></x-admin.user-admin-label>
|
<x-admin.user-admin-label label="Previous User Names"><b>TODO</b></x-admin.user-admin-label>
|
||||||
<x-admin.user-admin-label label="Moderation Status"><span class="text-success">OK (TODO)</span></x-admin.user-admin-label>
|
<x-admin.user-admin-label label="Moderation Status"><x-admin.moderation-status :user="$user" /></x-admin.user-admin-label>
|
||||||
<x-admin.user-admin-label label="User Id">
|
<x-admin.user-admin-label label="User Id">
|
||||||
<x-admin.user-search-input id="userid" definition="User ID" :value="$user->id" :nolabel=true />
|
<x-admin.user-search-input id="userid" definition="User ID" :value="$user->id" :nolabel=true />
|
||||||
</x-admin.user-admin-label>
|
</x-admin.user-admin-label>
|
||||||
|
|
@ -74,7 +74,7 @@
|
||||||
<img src="{{ asset('/images/testing/avatar.png') }}" width="200" height="200" class="img-fluid vb-charimg" />
|
<img src="{{ asset('/images/testing/avatar.png') }}" width="200" height="200" class="img-fluid vb-charimg" />
|
||||||
</div>
|
</div>
|
||||||
<div class="col-6">
|
<div class="col-6">
|
||||||
<a href="#" class="text-decoration-none">User Homepage</a><br/>
|
<a href="{{ $user->getProfileUrl() }}" class="text-decoration-none">User Homepage</a><br/>
|
||||||
<a href="#" class="text-decoration-none">Moderate User</a>
|
<a href="#" class="text-decoration-none">Moderate User</a>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
@ -90,16 +90,24 @@
|
||||||
<th scope="col">Moderator</th>
|
<th scope="col">Moderator</th>
|
||||||
<th scope="col">Created</th>
|
<th scope="col">Created</th>
|
||||||
<th scope="col">Expiration</th>
|
<th scope="col">Expiration</th>
|
||||||
|
<th scope="col">Acknowledged</th>
|
||||||
</tr>
|
</tr>
|
||||||
</thead>
|
</thead>
|
||||||
<tbody>
|
<tbody>
|
||||||
<tr>
|
@foreach($user->punishments as $punishment)
|
||||||
<th scope="col">1</th>
|
<tr>
|
||||||
<th scope="col">1 day, perm, etc...</th>
|
<th scope="col">{{ $punishment->id }}</th>
|
||||||
<th scope="col">Joe</th>
|
<th scope="col">{{ $punishment->punishment_type->label }}</th>
|
||||||
<th scope="col">1/2/3 4:5 6</th>
|
<th scope="col">
|
||||||
<th scope="col">1/2/3 4:5 6</th>
|
<a href="{{ route('admin.useradmin', ['ID' => $punishment->moderator->id]) }}" class="text-decoration-none">
|
||||||
</tr>
|
<x-user-circle :user="$punishment->moderator" :size=24 />
|
||||||
|
</a>
|
||||||
|
</th>
|
||||||
|
<th scope="col">{{ $punishment->reviewed() }}</th>
|
||||||
|
<th scope="col">{{ $punishment->expirationStr() }}</th>
|
||||||
|
<th scope="col">{{ $punishment->active ? 'No' : 'Yes' }}</th>
|
||||||
|
</tr>
|
||||||
|
@endforeach
|
||||||
</tbody>
|
</tbody>
|
||||||
</table>
|
</table>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
||||||
|
|
@ -56,7 +56,7 @@
|
||||||
</th>
|
</th>
|
||||||
<th scope="col">{{ $user->id }}</th>
|
<th scope="col">{{ $user->id }}</th>
|
||||||
<th scope="col">{{ Auth::user()->hasRoleset('Owner') ? $user->email : $user->getCensoredEmail() }}</th>
|
<th scope="col">{{ Auth::user()->hasRoleset('Owner') ? $user->email : $user->getCensoredEmail() }}</th>
|
||||||
<th scope="col"><p class="text-success">OK (TODO)</p></th>
|
<th scope="col"><x-admin.moderation-status :user="$user" /></th>
|
||||||
<th scope="col">
|
<th scope="col">
|
||||||
@if($rolesetCount > 0)
|
@if($rolesetCount > 0)
|
||||||
@php
|
@php
|
||||||
|
|
|
||||||
|
|
@ -1,42 +1,62 @@
|
||||||
@php
|
|
||||||
$noFooter = true;
|
|
||||||
$noNav = true;
|
|
||||||
@endphp
|
|
||||||
|
|
||||||
@extends('layouts.app')
|
@extends('layouts.app')
|
||||||
|
@section('theme', 'light')
|
||||||
@section('title', 'Moderation Notice')
|
@nonav
|
||||||
|
@nofooter
|
||||||
|
|
||||||
@section('content')
|
@section('content')
|
||||||
<div class="container m-auto">
|
<div class="container m-auto">
|
||||||
<x-card class="virtubrick-moderation-card">
|
<div class="card p-3 virtubrick-moderation-card">
|
||||||
<x-slot name="title">
|
<h3>{{ $punishment->punishment_type->label }}</h3>
|
||||||
MODERATION NOTICE
|
<p>
|
||||||
</x-slot>
|
Your account has been {{ $punishment->isDeletion() ? 'closed ' : 'temporarily restricted' }} for violating our Terms of Service.
|
||||||
<x-slot name="body">
|
@if(!$punishment->isDeletion())
|
||||||
<div class="p-2 mb-2 d-flex flex-column justify-content-center">
|
Your account will be terminated if you do not abide by the rules.
|
||||||
<p>Your account has been suspended for violating our Terms of Service.</p>
|
@endif
|
||||||
<div class="my-3">
|
</p>
|
||||||
<p><b>Suspention Date:</b> 5/6/2022 9:35 PM</p>
|
|
||||||
<p><b>Note:</b> testing</p>
|
<div class="my-3">
|
||||||
</div>
|
<p><b>Reviewed:</b> {{ $punishment->reviewed() }}</p>
|
||||||
</div>
|
<p><b>Moderator Note:</b> {{ $punishment->user_note }}</p>
|
||||||
</x-slot>
|
</div>
|
||||||
<x-slot name="footer">
|
|
||||||
<p>By checking the "I Agree" checkbox below, you agree to abide by {{ config('app.name') }}'s Terms of Service. Your account will be permantently suspended if you continue breaking the Terms of Service.</p>
|
@foreach($punishment->context as $context)
|
||||||
<form>
|
<div class="card bg-secondary p-2 mb-2 border-1">
|
||||||
<div class="my-2">
|
<p><b>Reason:</b> {{ $context->user_note }}</p>
|
||||||
<input class="form-check-input" type="checkbox" value="" id="agree" name="agree">
|
@if($context->description)
|
||||||
<label class="form-check-label" for="agree">
|
<p><b>Offensive Item:</b> {{ $context->description }}</p>
|
||||||
I Agree
|
@endif
|
||||||
</label>
|
@if($context->content_hash)
|
||||||
</div>
|
<img src="{{ route('content', $context->content_hash) }}" class="img-fluid" width="210" height="210"/>
|
||||||
<button class="btn btn-primary">REACTIVATE</button>
|
@endif
|
||||||
</form>
|
</div>
|
||||||
|
@endforeach
|
||||||
|
|
||||||
|
<div class="text-center">
|
||||||
|
@if($punishment->expired())
|
||||||
|
<p>By checking the "I Agree" checkbox below, you agree to abide by {{ config('app.name') }}'s Terms of Service.</p>
|
||||||
|
<form method="POST" action="{{ route('punishment.reactivate') }}" class="mt-2">
|
||||||
|
@csrf
|
||||||
|
<div class="mb-2">
|
||||||
|
<input class="form-check-input" type="checkbox" value="" id="vb-reactivation-checkbox">
|
||||||
|
<label class="form-check-label" for="vb-reactivation-checkbox">
|
||||||
|
I Agree
|
||||||
|
</label>
|
||||||
|
</div>
|
||||||
|
<button class="btn btn-success" id="vb-reactivation-button" disabled>Re-activate My Account</button>
|
||||||
|
</form>
|
||||||
|
<script>
|
||||||
|
document.getElementById('vb-reactivation-checkbox').addEventListener('change', (event) => {
|
||||||
|
document.getElementById('vb-reactivation-button').disabled = !event.currentTarget.checked;
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
@elseif(!$punishment->isDeletion())
|
||||||
|
<p>You will be able to reactivate your account in <b>{{ $punishment->expiration->diffForHumans(['syntax' => Carbon\CarbonInterface::DIFF_ABSOLUTE]) }}</b>.</p>
|
||||||
|
@endif
|
||||||
|
|
||||||
|
<a class="btn btn-primary my-2" href="{{ route('auth.logout') }}">Logout</a>
|
||||||
|
|
||||||
<p>You will be able to reactivate your account in <b>0 Seconds</b>.</p>
|
|
||||||
<p class="text-muted">If you believe you have been unfairly moderated, please contact us at contact us at <a href="mailto:support@virtubrick.net" class="fw-bold text-decoration-none">support@virtubrick.net</a> and we'll be happy to help.</p>
|
<p class="text-muted">If you believe you have been unfairly moderated, please contact us at contact us at <a href="mailto:support@virtubrick.net" class="fw-bold text-decoration-none">support@virtubrick.net</a> and we'll be happy to help.</p>
|
||||||
</x-slot>
|
</div>
|
||||||
</x-card>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@endsection
|
@endsection
|
||||||
|
|
|
||||||
|
|
@ -74,12 +74,10 @@ Route::group(['as' => 'admin.', 'prefix' => 'admin'], function() {
|
||||||
});
|
});
|
||||||
|
|
||||||
Route::group(['as' => 'auth.', 'namespace' => 'Auth'], function() {
|
Route::group(['as' => 'auth.', 'namespace' => 'Auth'], function() {
|
||||||
Route::group(['as' => 'protection.', 'prefix' => 'request-blocked'], function() {
|
//Route::group(['as' => 'protection.', 'prefix' => 'request-blocked'], function() {
|
||||||
Route::get('/', 'DoubleSessionBlockController@index')->name('index');
|
// Route::get('/', 'DoubleSessionBlockController@index')->name('index');
|
||||||
Route::post('/', 'DoubleSessionBlockController@store')->name('bypass');
|
// Route::post('/', 'DoubleSessionBlockController@store')->name('bypass');
|
||||||
});
|
//});
|
||||||
|
|
||||||
Route::get('/moderation-notice', 'UserModerationController@index')->middleware(['auth', 'banned'])->name('moderation.notice');
|
|
||||||
|
|
||||||
Route::middleware('guest')->group(function () {
|
Route::middleware('guest')->group(function () {
|
||||||
Route::group(['as' => 'register.', 'prefix' => 'register'], function() {
|
Route::group(['as' => 'register.', 'prefix' => 'register'], function() {
|
||||||
|
|
@ -120,6 +118,12 @@ Route::group(['as' => 'auth.', 'namespace' => 'Auth'], function() {
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
Route::group(['as' => 'punishment.', 'prefix' => 'membership'], function() {
|
||||||
|
Route::middleware('auth')->group(function () {
|
||||||
|
Route::get('/not-approved', 'ModerationController@notice')->name('notice');
|
||||||
|
Route::post('/not-approved', 'ModerationController@reactivate')->name('reactivate');
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
Route::withoutMiddleware(['csrf'])->group(function () {
|
Route::withoutMiddleware(['csrf'])->group(function () {
|
||||||
Route::group(['as' => 'client.'], function() {
|
Route::group(['as' => 'client.'], function() {
|
||||||
|
|
@ -130,3 +134,7 @@ Route::withoutMiddleware(['csrf'])->group(function () {
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
Route::fallback(function() {
|
||||||
|
return view('errors.404');
|
||||||
|
});
|
||||||
Loading…
Reference in New Issue