Merge branch 'laravel-12'
This commit is contained in:
11
app/Enums/UserRole.php
Normal file
11
app/Enums/UserRole.php
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Enums;
|
||||||
|
|
||||||
|
enum UserRole: string
|
||||||
|
{
|
||||||
|
case ADMINISTRATOR = 'admin';
|
||||||
|
case MODERATOR = 'moderator';
|
||||||
|
case SUPPORTER = 'supporter';
|
||||||
|
case BANNED = 'banned';
|
||||||
|
}
|
||||||
@@ -2,6 +2,7 @@
|
|||||||
|
|
||||||
namespace App\Http\Controllers\Admin;
|
namespace App\Http\Controllers\Admin;
|
||||||
|
|
||||||
|
use App\Enums\UserRole;
|
||||||
use App\Models\User;
|
use App\Models\User;
|
||||||
use App\Http\Controllers\Controller;
|
use App\Http\Controllers\Controller;
|
||||||
use Illuminate\Http\Request;
|
use Illuminate\Http\Request;
|
||||||
@@ -31,11 +32,11 @@ class UserController extends Controller
|
|||||||
|
|
||||||
switch ($validated['action']) {
|
switch ($validated['action']) {
|
||||||
case 'ban':
|
case 'ban':
|
||||||
$user->update(['is_banned' => 1]);
|
$user->addRole(UserRole::BANNED);
|
||||||
alert()->success('Banned', 'User has been banned.');
|
alert()->success('Banned', 'User has been banned.');
|
||||||
break;
|
break;
|
||||||
case 'unban':
|
case 'unban':
|
||||||
$user->update(['is_banned' => 0]);
|
$user->removeRole(UserRole::BANNED);
|
||||||
alert()->success('Unbanned', 'User has been unbanned.');
|
alert()->success('Unbanned', 'User has been unbanned.');
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
|
|||||||
@@ -8,6 +8,8 @@ use App\Models\Episode;
|
|||||||
use Illuminate\Http\Request;
|
use Illuminate\Http\Request;
|
||||||
use App\Http\Controllers\Controller;
|
use App\Http\Controllers\Controller;
|
||||||
|
|
||||||
|
use GrantHolle\Altcha\Rules\ValidAltcha;
|
||||||
|
|
||||||
class DownloadApiController extends Controller
|
class DownloadApiController extends Controller
|
||||||
{
|
{
|
||||||
/**
|
/**
|
||||||
@@ -16,11 +18,12 @@ class DownloadApiController extends Controller
|
|||||||
public function getDownload(Request $request)
|
public function getDownload(Request $request)
|
||||||
{
|
{
|
||||||
$validated = $request->validate([
|
$validated = $request->validate([
|
||||||
'episode_id' => 'required',
|
'episode_id' => ['required'],
|
||||||
'captcha' => 'required|captcha'
|
'captcha' => ['required', new ValidAltcha],
|
||||||
]);
|
]);
|
||||||
|
|
||||||
$episode = Episode::where('id', $request->input('episode_id'))->firstOrFail();
|
$episode = Episode::where('id', $request->input('episode_id'))
|
||||||
|
->firstOrFail();
|
||||||
|
|
||||||
// Increase download count, as we assume the user
|
// Increase download count, as we assume the user
|
||||||
// downloads after submitting the captcha
|
// downloads after submitting the captcha
|
||||||
|
|||||||
@@ -2,6 +2,7 @@
|
|||||||
|
|
||||||
namespace App\Http\Controllers\Auth;
|
namespace App\Http\Controllers\Auth;
|
||||||
|
|
||||||
|
use App\Enums\UserRole;
|
||||||
use App\Models\User;
|
use App\Models\User;
|
||||||
|
|
||||||
use App\Http\Controllers\Controller;
|
use App\Http\Controllers\Controller;
|
||||||
@@ -88,10 +89,7 @@ class DiscordAuthController extends Controller
|
|||||||
|
|
||||||
// User is not in the guild
|
// User is not in the guild
|
||||||
if ($response->status() === 404) {
|
if ($response->status() === 404) {
|
||||||
$user->update([
|
$user->removeRole(UserRole::SUPPORTER);
|
||||||
'is_patreon' => false,
|
|
||||||
]);
|
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -110,22 +108,15 @@ class DiscordAuthController extends Controller
|
|||||||
$discordRoles = $response->json('roles', []);
|
$discordRoles = $response->json('roles', []);
|
||||||
$patreonRoles = config('discord.patreon_roles', []);
|
$patreonRoles = config('discord.patreon_roles', []);
|
||||||
|
|
||||||
$isPatreon = false;
|
// If intersect of array is empty, then the user doesn't have the role
|
||||||
foreach($patreonRoles as $patreonRole)
|
$hasSupporterRole = !empty(array_intersect($discordRoles, $patreonRoles));
|
||||||
{
|
|
||||||
if (in_array($patreonRole, $discordRoles, true)) {
|
if (!$hasSupporterRole) {
|
||||||
$isPatreon = true;
|
// Remove role if not found
|
||||||
break;
|
$user->removeRole(UserRole::SUPPORTER);
|
||||||
}
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Only update if something actually changed
|
$user->addRole(UserRole::SUPPORTER);
|
||||||
$isPatreonOld = (bool) $user->is_patreon;
|
|
||||||
if ($isPatreonOld !== $isPatreon) {
|
|
||||||
$user->update([
|
|
||||||
'is_patreon' => $isPatreon,
|
|
||||||
]);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -11,6 +11,8 @@ use Illuminate\Support\Facades\Auth;
|
|||||||
use Illuminate\Support\Facades\Hash;
|
use Illuminate\Support\Facades\Hash;
|
||||||
use Illuminate\Validation\Rules;
|
use Illuminate\Validation\Rules;
|
||||||
|
|
||||||
|
use GrantHolle\Altcha\Rules\ValidAltcha;
|
||||||
|
|
||||||
class RegisteredUserController extends Controller
|
class RegisteredUserController extends Controller
|
||||||
{
|
{
|
||||||
/**
|
/**
|
||||||
@@ -24,6 +26,7 @@ class RegisteredUserController extends Controller
|
|||||||
'name' => ['required', 'string', 'max:255'],
|
'name' => ['required', 'string', 'max:255'],
|
||||||
'email' => ['required', 'string', 'lowercase', 'email', 'max:255', 'unique:'.User::class],
|
'email' => ['required', 'string', 'lowercase', 'email', 'max:255', 'unique:'.User::class],
|
||||||
'password' => ['required', 'confirmed', Rules\Password::defaults()],
|
'password' => ['required', 'confirmed', Rules\Password::defaults()],
|
||||||
|
'altcha' => ['required', new ValidAltcha],
|
||||||
]);
|
]);
|
||||||
|
|
||||||
$user = User::create([
|
$user = User::create([
|
||||||
|
|||||||
@@ -5,6 +5,8 @@ namespace App\Http\Controllers;
|
|||||||
use App\Models\Contact;
|
use App\Models\Contact;
|
||||||
use Illuminate\Http\Request;
|
use Illuminate\Http\Request;
|
||||||
|
|
||||||
|
use GrantHolle\Altcha\Rules\ValidAltcha;
|
||||||
|
|
||||||
class ContactController extends Controller
|
class ContactController extends Controller
|
||||||
{
|
{
|
||||||
/**
|
/**
|
||||||
@@ -25,7 +27,7 @@ class ContactController extends Controller
|
|||||||
'email' => 'required|max:50',
|
'email' => 'required|max:50',
|
||||||
'message' => 'required|max:1000',
|
'message' => 'required|max:1000',
|
||||||
'subject' => 'required|max:50',
|
'subject' => 'required|max:50',
|
||||||
'captcha' => 'required|captcha',
|
'altcha' => ['required', new ValidAltcha],
|
||||||
]);
|
]);
|
||||||
|
|
||||||
$contact = new Contact();
|
$contact = new Contact();
|
||||||
@@ -37,9 +39,4 @@ class ContactController extends Controller
|
|||||||
|
|
||||||
return back()->with('status', 'contact-submitted');
|
return back()->with('status', 'contact-submitted');
|
||||||
}
|
}
|
||||||
|
|
||||||
public function reloadCaptcha(): \Illuminate\Http\JsonResponse
|
|
||||||
{
|
|
||||||
return response()->json(['captcha'=> captcha_img()]);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -111,11 +111,13 @@ class HomeController extends Controller
|
|||||||
*/
|
*/
|
||||||
public function updateLanguage(Request $request): \Illuminate\Http\RedirectResponse
|
public function updateLanguage(Request $request): \Illuminate\Http\RedirectResponse
|
||||||
{
|
{
|
||||||
if(! in_array($request->language, config('lang-detector.languages'))) {
|
abort_unless(in_array($request->language, config('app.supported_locales'), true), 404);
|
||||||
return redirect()->back();
|
|
||||||
}
|
|
||||||
|
|
||||||
Cookie::queue(Cookie::forever('locale', $request->language));
|
session(['locale' => $request->language]);
|
||||||
|
|
||||||
|
if (Auth::check()) {
|
||||||
|
Auth::user()->update(['locale' => $request->language]);
|
||||||
|
}
|
||||||
|
|
||||||
return redirect()->back();
|
return redirect()->back();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -37,6 +37,7 @@ class Kernel extends HttpKernel
|
|||||||
\App\Http\Middleware\VerifyCsrfToken::class,
|
\App\Http\Middleware\VerifyCsrfToken::class,
|
||||||
\Illuminate\Routing\Middleware\SubstituteBindings::class,
|
\Illuminate\Routing\Middleware\SubstituteBindings::class,
|
||||||
\App\Http\Middleware\IsBanned::class,
|
\App\Http\Middleware\IsBanned::class,
|
||||||
|
\App\Http\Middleware\SetLocale::class,
|
||||||
],
|
],
|
||||||
|
|
||||||
'api' => [
|
'api' => [
|
||||||
@@ -58,6 +59,7 @@ class Kernel extends HttpKernel
|
|||||||
'auth.basic' => \Illuminate\Auth\Middleware\AuthenticateWithBasicAuth::class,
|
'auth.basic' => \Illuminate\Auth\Middleware\AuthenticateWithBasicAuth::class,
|
||||||
'auth.session' => \Illuminate\Session\Middleware\AuthenticateSession::class,
|
'auth.session' => \Illuminate\Session\Middleware\AuthenticateSession::class,
|
||||||
'auth.admin' => \App\Http\Middleware\IsAdmin::class,
|
'auth.admin' => \App\Http\Middleware\IsAdmin::class,
|
||||||
|
'auth.moderator' => \App\Http\Middleware\IsModerator::class,
|
||||||
'cache.headers' => \Illuminate\Http\Middleware\SetCacheHeaders::class,
|
'cache.headers' => \Illuminate\Http\Middleware\SetCacheHeaders::class,
|
||||||
'can' => \Illuminate\Auth\Middleware\Authorize::class,
|
'can' => \Illuminate\Auth\Middleware\Authorize::class,
|
||||||
'guest' => \App\Http\Middleware\RedirectIfAuthenticated::class,
|
'guest' => \App\Http\Middleware\RedirectIfAuthenticated::class,
|
||||||
|
|||||||
@@ -1,28 +1,14 @@
|
|||||||
<?php namespace app\Http\Middleware;
|
<?php namespace app\Http\Middleware;
|
||||||
|
|
||||||
|
use App\Enums\UserRole;
|
||||||
|
|
||||||
use Closure;
|
use Closure;
|
||||||
use Illuminate\Contracts\Auth\Guard;
|
use Illuminate\Http\Request;
|
||||||
|
use Illuminate\Support\Facades\Auth;
|
||||||
|
use Symfony\Component\HttpFoundation\Response;
|
||||||
|
|
||||||
class IsAdmin {
|
class IsAdmin {
|
||||||
|
|
||||||
/**
|
|
||||||
* The Guard implementation.
|
|
||||||
*
|
|
||||||
* @var Guard
|
|
||||||
*/
|
|
||||||
protected $auth;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Create a new filter instance.
|
|
||||||
*
|
|
||||||
* @param Guard $auth
|
|
||||||
* @return void
|
|
||||||
*/
|
|
||||||
public function __construct(Guard $auth)
|
|
||||||
{
|
|
||||||
$this->auth = $auth;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Handle an incoming request.
|
* Handle an incoming request.
|
||||||
*
|
*
|
||||||
@@ -30,15 +16,14 @@ class IsAdmin {
|
|||||||
* @param \Closure $next
|
* @param \Closure $next
|
||||||
* @return mixed
|
* @return mixed
|
||||||
*/
|
*/
|
||||||
public function handle($request, Closure $next)
|
public function handle(Request $request, Closure $next): Response
|
||||||
{
|
{
|
||||||
if( ! $this->auth->user()->is_admin)
|
if(Auth::check() && Auth::user()->hasRole(UserRole::ADMINISTRATOR))
|
||||||
{
|
{
|
||||||
session()->flash('error_msg','This resource is restricted to Administrators!');
|
return $next($request);
|
||||||
return redirect()->route('home.index');
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return $next($request);
|
session()->flash('error_msg','This resource is restricted to Administrators!');
|
||||||
|
return redirect()->route('home.index');
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,8 +1,11 @@
|
|||||||
<?php namespace app\Http\Middleware;
|
<?php namespace app\Http\Middleware;
|
||||||
|
|
||||||
|
use App\Enums\UserRole;
|
||||||
|
|
||||||
use Closure;
|
use Closure;
|
||||||
|
use Illuminate\Http\Request;
|
||||||
use Illuminate\Support\Facades\Auth;
|
use Illuminate\Support\Facades\Auth;
|
||||||
use Illuminate\Contracts\Auth\Guard;
|
use Symfony\Component\HttpFoundation\Response;
|
||||||
|
|
||||||
class IsBanned {
|
class IsBanned {
|
||||||
|
|
||||||
@@ -13,9 +16,9 @@ class IsBanned {
|
|||||||
* @param \Closure $next
|
* @param \Closure $next
|
||||||
* @return mixed
|
* @return mixed
|
||||||
*/
|
*/
|
||||||
public function handle($request, Closure $next)
|
public function handle(Request $request, Closure $next): Response
|
||||||
{
|
{
|
||||||
if(auth()->check() && auth()->user()->is_banned == 1)
|
if(Auth::check() && Auth::user()->hasRole(UserRole::BANNED))
|
||||||
{
|
{
|
||||||
Auth::logout();
|
Auth::logout();
|
||||||
$request->session()->invalidate();
|
$request->session()->invalidate();
|
||||||
|
|||||||
29
app/Http/Middleware/IsModerator.php
Normal file
29
app/Http/Middleware/IsModerator.php
Normal file
@@ -0,0 +1,29 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Http\Middleware;
|
||||||
|
|
||||||
|
use App\Enums\UserRole;
|
||||||
|
|
||||||
|
use Closure;
|
||||||
|
use Illuminate\Http\Request;
|
||||||
|
use Illuminate\Support\Facades\Auth;
|
||||||
|
use Symfony\Component\HttpFoundation\Response;
|
||||||
|
|
||||||
|
class IsModerator
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Handle an incoming request.
|
||||||
|
*
|
||||||
|
* @param \Closure(\Illuminate\Http\Request): (\Symfony\Component\HttpFoundation\Response) $next
|
||||||
|
*/
|
||||||
|
public function handle(Request $request, Closure $next): Response
|
||||||
|
{
|
||||||
|
if (Auth::check() && Auth::user()->hasRole(UserRole::MODERATOR))
|
||||||
|
{
|
||||||
|
return $next($request);
|
||||||
|
}
|
||||||
|
|
||||||
|
session()->flash('error_msg','This resource is restricted to Administrators!');
|
||||||
|
return redirect()->route('home.index');
|
||||||
|
}
|
||||||
|
}
|
||||||
41
app/Http/Middleware/SetLocale.php
Normal file
41
app/Http/Middleware/SetLocale.php
Normal file
@@ -0,0 +1,41 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Http\Middleware;
|
||||||
|
|
||||||
|
use Closure;
|
||||||
|
use Illuminate\Http\Request;
|
||||||
|
use Illuminate\Support\Facades\App;
|
||||||
|
use Illuminate\Support\Facades\Auth;
|
||||||
|
use Symfony\Component\HttpFoundation\Response;
|
||||||
|
|
||||||
|
class SetLocale
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Handle an incoming request.
|
||||||
|
*
|
||||||
|
* @param \Closure(\Illuminate\Http\Request): (\Symfony\Component\HttpFoundation\Response) $next
|
||||||
|
*/
|
||||||
|
public function handle(Request $request, Closure $next): Response
|
||||||
|
{
|
||||||
|
// 1. Logged-in user preference
|
||||||
|
if (Auth::check() && Auth::user()->locale) {
|
||||||
|
App::setLocale(Auth::user()->locale);
|
||||||
|
return $next($request);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 2. Session (guest or user override)
|
||||||
|
if (session()->has('locale') && in_array($request->language, config('app.supported_locales'), true)) {
|
||||||
|
App::setLocale(session('locale'));
|
||||||
|
return $next($request);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 3. Browser language
|
||||||
|
$locale = $request->getPreferredLanguage(config('app.supported_locales'));
|
||||||
|
|
||||||
|
if ($locale) {
|
||||||
|
App::setLocale($locale);
|
||||||
|
}
|
||||||
|
|
||||||
|
return $next($request);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -9,6 +9,8 @@ use Illuminate\Support\Facades\RateLimiter;
|
|||||||
use Illuminate\Support\Str;
|
use Illuminate\Support\Str;
|
||||||
use Illuminate\Validation\ValidationException;
|
use Illuminate\Validation\ValidationException;
|
||||||
|
|
||||||
|
use GrantHolle\Altcha\Rules\ValidAltcha;
|
||||||
|
|
||||||
class LoginRequest extends FormRequest
|
class LoginRequest extends FormRequest
|
||||||
{
|
{
|
||||||
/**
|
/**
|
||||||
@@ -29,6 +31,7 @@ class LoginRequest extends FormRequest
|
|||||||
return [
|
return [
|
||||||
'email' => ['required', 'string', 'email'],
|
'email' => ['required', 'string', 'email'],
|
||||||
'password' => ['required', 'string'],
|
'password' => ['required', 'string'],
|
||||||
|
'altcha' => ['required', new ValidAltcha],
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -2,6 +2,7 @@
|
|||||||
|
|
||||||
namespace App\Livewire;
|
namespace App\Livewire;
|
||||||
|
|
||||||
|
use App\Enums\UserRole;
|
||||||
use App\Models\Comment;
|
use App\Models\Comment;
|
||||||
use App\Models\User;
|
use App\Models\User;
|
||||||
|
|
||||||
@@ -17,7 +18,7 @@ class AdminUserSearch extends Component
|
|||||||
public $search = '';
|
public $search = '';
|
||||||
|
|
||||||
#[Url(history: true)]
|
#[Url(history: true)]
|
||||||
public $filtered = ['true'];
|
public $discordId = '';
|
||||||
|
|
||||||
#[Url(history: true)]
|
#[Url(history: true)]
|
||||||
public $patreon = [];
|
public $patreon = [];
|
||||||
@@ -38,10 +39,10 @@ class AdminUserSearch extends Component
|
|||||||
|
|
||||||
public function render()
|
public function render()
|
||||||
{
|
{
|
||||||
$users = User::when($this->filtered !== [], fn ($query) => $query->where('id', '>=', 10000))
|
$users = User::when($this->patreon !== [], fn ($query) => $query->whereJsonContains('roles', UserRole::SUPPORTER->value))
|
||||||
->when($this->patreon !== [], fn ($query) => $query->where('is_patreon', 1))
|
->when($this->banned !== [], fn ($query) => $query->whereJsonContains('roles', UserRole::BANNED->value))
|
||||||
->when($this->banned !== [], fn ($query) => $query->where('is_banned', 1))
|
|
||||||
->when($this->search !== '', fn ($query) => $query->where('name', 'like', '%'.$this->search.'%'))
|
->when($this->search !== '', fn ($query) => $query->where('name', 'like', '%'.$this->search.'%'))
|
||||||
|
->when($this->discordId !== '', fn ($query) => $query->where('discord_id', '=', $this->discordId))
|
||||||
->paginate(20);
|
->paginate(20);
|
||||||
|
|
||||||
return view('livewire.admin-user-search', [
|
return view('livewire.admin-user-search', [
|
||||||
|
|||||||
@@ -73,9 +73,9 @@ class DownloadsSearch extends Component
|
|||||||
$types[] = 'FHD';
|
$types[] = 'FHD';
|
||||||
} elseif ($label === 'FHD 48fps') {
|
} elseif ($label === 'FHD 48fps') {
|
||||||
$types[] = 'FHDi';
|
$types[] = 'FHDi';
|
||||||
} elseif ($label === 'UHD' && auth()->user()->is_patreon) {
|
} elseif ($label === 'UHD' && auth()->user()->hasRole(\App\Enums\UserRole::SUPPORTER)) {
|
||||||
$types[] = 'UHD';
|
$types[] = 'UHD';
|
||||||
} elseif ($label === 'UHD 48fps' && auth()->user()->is_patreon) {
|
} elseif ($label === 'UHD 48fps' && auth()->user()->hasRole(\App\Enums\UserRole::SUPPORTER)) {
|
||||||
$types[] = 'UHDi';
|
$types[] = 'UHDi';
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -98,7 +98,7 @@ class DownloadsSearch extends Component
|
|||||||
|
|
||||||
public function mount()
|
public function mount()
|
||||||
{
|
{
|
||||||
if (!auth()->user()->is_patreon) {
|
if (!auth()->user()->hasRole(\App\Enums\UserRole::SUPPORTER)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -3,6 +3,8 @@
|
|||||||
namespace App\Models;
|
namespace App\Models;
|
||||||
|
|
||||||
//use Illuminate\Contracts\Auth\MustVerifyEmail;
|
//use Illuminate\Contracts\Auth\MustVerifyEmail;
|
||||||
|
|
||||||
|
use App\Enums\UserRole;
|
||||||
use Illuminate\Database\Eloquent\Relations\HasMany;
|
use Illuminate\Database\Eloquent\Relations\HasMany;
|
||||||
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||||
use Illuminate\Foundation\Auth\User as Authenticatable;
|
use Illuminate\Foundation\Auth\User as Authenticatable;
|
||||||
@@ -25,8 +27,6 @@ class User extends Authenticatable
|
|||||||
'email',
|
'email',
|
||||||
'password',
|
'password',
|
||||||
'locale',
|
'locale',
|
||||||
'is_patreon',
|
|
||||||
'is_banned',
|
|
||||||
// Discord
|
// Discord
|
||||||
'discord_id',
|
'discord_id',
|
||||||
'discord_avatar',
|
'discord_avatar',
|
||||||
@@ -55,7 +55,7 @@ class User extends Authenticatable
|
|||||||
'name' => 'string',
|
'name' => 'string',
|
||||||
'email' => 'string',
|
'email' => 'string',
|
||||||
'locale' => 'string',
|
'locale' => 'string',
|
||||||
'roles' => 'json',
|
'roles' => 'array',
|
||||||
'tag_blacklist' => 'array',
|
'tag_blacklist' => 'array',
|
||||||
// Discord
|
// Discord
|
||||||
'discord_id' => 'integer',
|
'discord_id' => 'integer',
|
||||||
@@ -120,4 +120,44 @@ class User extends Authenticatable
|
|||||||
|
|
||||||
return asset('images/default-avatar.webp');
|
return asset('images/default-avatar.webp');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check if user has a specific role
|
||||||
|
*/
|
||||||
|
public function hasRole(UserRole $role): bool
|
||||||
|
{
|
||||||
|
return in_array($role->value, $this->roles ?? [], true);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Add Role to User
|
||||||
|
*/
|
||||||
|
public function addRole(UserRole $role): void
|
||||||
|
{
|
||||||
|
if ($this->hasRole($role)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get all current roles
|
||||||
|
$roles = $this->roles ?? [];
|
||||||
|
|
||||||
|
// Add new role
|
||||||
|
$roles[] = $role->value;
|
||||||
|
|
||||||
|
$this->roles = $roles;
|
||||||
|
$this->save();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Remove Role from User
|
||||||
|
*/
|
||||||
|
public function removeRole(UserRole $role): void
|
||||||
|
{
|
||||||
|
if (!$this->hasRole($role)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->roles = array_diff($this->roles, [$role->value]);
|
||||||
|
$this->save();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -34,8 +34,8 @@ class EpisodeService
|
|||||||
Request $request,
|
Request $request,
|
||||||
Hentai $hentai,
|
Hentai $hentai,
|
||||||
int $episodeNumber,
|
int $episodeNumber,
|
||||||
Studios $studio = null,
|
?Studios $studio = null,
|
||||||
Episode $referenceEpisode = null
|
?Episode $referenceEpisode = null
|
||||||
): Episode
|
): Episode
|
||||||
{
|
{
|
||||||
$episode = new Episode();
|
$episode = new Episode();
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
{
|
{
|
||||||
"name": "laravel/laravel",
|
"name": "w33b/hstream",
|
||||||
"type": "project",
|
"type": "project",
|
||||||
"description": "The skeleton application for the Laravel framework.",
|
"description": "The website of hstream.moe",
|
||||||
"keywords": [
|
"keywords": [
|
||||||
"laravel",
|
"laravel",
|
||||||
"framework"
|
"framework"
|
||||||
@@ -9,45 +9,38 @@
|
|||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"require": {
|
"require": {
|
||||||
"php": "^8.2",
|
"php": "^8.2",
|
||||||
|
"grantholle/laravel-altcha": "^2.1",
|
||||||
"guzzlehttp/guzzle": "^7.8.1",
|
"guzzlehttp/guzzle": "^7.8.1",
|
||||||
"hisorange/browser-detect": "^5.0",
|
"hisorange/browser-detect": "^5.0",
|
||||||
"http-interop/http-factory-guzzle": "^1.2",
|
"http-interop/http-factory-guzzle": "^1.2",
|
||||||
"intervention/image": "^3.9",
|
"intervention/image": "^3.11",
|
||||||
"intervention/image-laravel": "^1.3",
|
"intervention/image-laravel": "^1.5",
|
||||||
"laravel/framework": "^11.0",
|
"laravel/framework": "^12.0",
|
||||||
"laravel/sanctum": "^4.0",
|
"laravel/sanctum": "^4.2",
|
||||||
"laravel/scout": "^10.20",
|
"laravel/scout": "^10.20",
|
||||||
"laravel/socialite": "^5.24",
|
"laravel/socialite": "^5.24",
|
||||||
"laravel/tinker": "^2.10",
|
"laravel/tinker": "^2.10",
|
||||||
"livewire/livewire": "^3.6.4",
|
"livewire/livewire": "^3.7.0",
|
||||||
"maize-tech/laravel-markable": "^2.3.0",
|
"maize-tech/laravel-markable": "^2.3.0",
|
||||||
"meilisearch/meilisearch-php": "^1.16",
|
"meilisearch/meilisearch-php": "^1.16",
|
||||||
"mews/captcha": "3.4.4",
|
|
||||||
"predis/predis": "^2.2",
|
"predis/predis": "^2.2",
|
||||||
"realrashid/sweet-alert": "^7.2",
|
"realrashid/sweet-alert": "^7.2",
|
||||||
"rtconner/laravel-tagging": "^4.1",
|
"rtconner/laravel-tagging": "^5.0",
|
||||||
"socialiteproviders/discord": "^4.2",
|
"socialiteproviders/discord": "^4.2",
|
||||||
"spatie/laravel-discord-alerts": "^1.5",
|
"spatie/laravel-discord-alerts": "^1.8",
|
||||||
"spatie/laravel-sitemap": "^7.3",
|
"spatie/laravel-sitemap": "^7.3"
|
||||||
"vluzrmos/language-detector": "^2.3"
|
|
||||||
},
|
},
|
||||||
"require-dev": {
|
"require-dev": {
|
||||||
"barryvdh/laravel-debugbar": "^3.14.7",
|
"barryvdh/laravel-debugbar": "^3.16",
|
||||||
"fakerphp/faker": "^1.24.0",
|
"fakerphp/faker": "^1.24.0",
|
||||||
"laravel/breeze": "^2.3",
|
"laravel/breeze": "^2.3",
|
||||||
"laravel/pint": "^1.18",
|
"laravel/pint": "^1.18",
|
||||||
"laravel/sail": "^1.38",
|
|
||||||
"mockery/mockery": "^1.4.4",
|
"mockery/mockery": "^1.4.4",
|
||||||
"nunomaduro/collision": "^8.1",
|
"nunomaduro/collision": "^8.1",
|
||||||
"phpunit/phpunit": "^11.4",
|
"phpunit/phpunit": "^11.4",
|
||||||
"spatie/laravel-ignition": "^2.0"
|
"spatie/laravel-ignition": "^2.0"
|
||||||
},
|
},
|
||||||
"repositories": [
|
"repositories": [],
|
||||||
{
|
|
||||||
"type": "vcs",
|
|
||||||
"url": "https://github.com/renatokira/comments.git"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"autoload": {
|
"autoload": {
|
||||||
"exclude-from-classmap": [],
|
"exclude-from-classmap": [],
|
||||||
"psr-4": {
|
"psr-4": {
|
||||||
|
|||||||
2033
composer.lock
generated
2033
composer.lock
generated
File diff suppressed because it is too large
Load Diff
@@ -111,6 +111,18 @@ return [
|
|||||||
|
|
||||||
'faker_locale' => 'en_US',
|
'faker_locale' => 'en_US',
|
||||||
|
|
||||||
|
/*
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
| Supported Locales
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
|
|
||||||
|
| This is used to display the supported locales by this app, it also is
|
||||||
|
| used to verify session data and requests in the SetLocale Middleware
|
||||||
|
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
'supported_locales' => ['en', 'de', 'fr'],
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|--------------------------------------------------------------------------
|
|--------------------------------------------------------------------------
|
||||||
| Encryption Key
|
| Encryption Key
|
||||||
|
|||||||
@@ -1,50 +0,0 @@
|
|||||||
<?php
|
|
||||||
|
|
||||||
return [
|
|
||||||
'characters' => ['2', '3', '4', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'J', 'M', 'N', 'P', 'Q', 'R', 'T', 'U', 'X', 'Y', 'Z'],
|
|
||||||
'default' => [
|
|
||||||
'length' => 5,
|
|
||||||
'width' => 120,
|
|
||||||
'height' => 36,
|
|
||||||
'quality' => 90,
|
|
||||||
'math' => false,
|
|
||||||
'expire' => 60,
|
|
||||||
'encrypt' => false,
|
|
||||||
],
|
|
||||||
'math' => [
|
|
||||||
'length' => 9,
|
|
||||||
'width' => 120,
|
|
||||||
'height' => 36,
|
|
||||||
'quality' => 90,
|
|
||||||
'math' => true,
|
|
||||||
],
|
|
||||||
|
|
||||||
'flat' => [
|
|
||||||
'length' => 6,
|
|
||||||
'width' => 160,
|
|
||||||
'height' => 46,
|
|
||||||
'quality' => 90,
|
|
||||||
'lines' => 6,
|
|
||||||
'bgImage' => false,
|
|
||||||
'bgColor' => '#ecf2f4',
|
|
||||||
'fontColors' => ['#2c3e50', '#c0392b', '#16a085', '#c0392b', '#8e44ad', '#303f9f', '#f57c00', '#795548'],
|
|
||||||
'contrast' => -5,
|
|
||||||
],
|
|
||||||
'mini' => [
|
|
||||||
'length' => 3,
|
|
||||||
'width' => 60,
|
|
||||||
'height' => 32,
|
|
||||||
],
|
|
||||||
'inverse' => [
|
|
||||||
'length' => 5,
|
|
||||||
'width' => 120,
|
|
||||||
'height' => 36,
|
|
||||||
'quality' => 90,
|
|
||||||
'sensitive' => true,
|
|
||||||
'angle' => 12,
|
|
||||||
'sharpen' => 10,
|
|
||||||
'blur' => 2,
|
|
||||||
'invert' => true,
|
|
||||||
'contrast' => -5,
|
|
||||||
]
|
|
||||||
];
|
|
||||||
@@ -1,46 +0,0 @@
|
|||||||
<?php
|
|
||||||
|
|
||||||
return [
|
|
||||||
/*
|
|
||||||
* Indicates whenever should autodetect and apply the language of the request.
|
|
||||||
*/
|
|
||||||
'autodetect' => env('LANG_DETECTOR_AUTODETECT', true),
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Default driver to use to detect the request language.
|
|
||||||
*
|
|
||||||
* Available: browser, subdomain, uri.
|
|
||||||
*/
|
|
||||||
'driver' => env('LANG_DETECTOR_DRIVER', 'browser'),
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Used on subdomain and uri drivers. That indicates which segment should be used
|
|
||||||
* to verify the language.
|
|
||||||
*/
|
|
||||||
'segment' => env('LANG_DETECTOR_SEGMENT', 0),
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Languages available on the application.
|
|
||||||
*
|
|
||||||
* You could use parse_langs_to_array to use the string syntax
|
|
||||||
* or just use the array of languages with its aliases.
|
|
||||||
*/
|
|
||||||
'languages' => parse_langs_to_array(
|
|
||||||
env('LANG_DETECTOR_LANGUAGES', ['en', 'de', 'fr'])
|
|
||||||
),
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Indicates if should store detected locale on cookies
|
|
||||||
*/
|
|
||||||
'cookie' => (bool) env('LANG_DETECTOR_COOKIE', true),
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Indicates if should encrypt cookie
|
|
||||||
*/
|
|
||||||
'cookie_encrypt' => (bool) env('LANG_DETECTOR_COOKIE_ENCRYPT', false),
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Cookie name
|
|
||||||
*/
|
|
||||||
'cookie_name' => env('LANG_DETECTOR_COOKIE', 'locale'),
|
|
||||||
];
|
|
||||||
@@ -0,0 +1,30 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
use Illuminate\Database\Migrations\Migration;
|
||||||
|
use Illuminate\Database\Schema\Blueprint;
|
||||||
|
use Illuminate\Support\Facades\Schema;
|
||||||
|
|
||||||
|
return new class extends Migration
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Run the migrations.
|
||||||
|
*/
|
||||||
|
public function up(): void
|
||||||
|
{
|
||||||
|
Schema::table('users', function (Blueprint $table) {
|
||||||
|
$table->string('locale', 10)
|
||||||
|
->nullable()
|
||||||
|
->after('discord_avatar');
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reverse the migrations.
|
||||||
|
*/
|
||||||
|
public function down(): void
|
||||||
|
{
|
||||||
|
Schema::table('users', function (Blueprint $table) {
|
||||||
|
$table->dropColumn('locale');
|
||||||
|
});
|
||||||
|
}
|
||||||
|
};
|
||||||
@@ -0,0 +1,50 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
use Illuminate\Database\Migrations\Migration;
|
||||||
|
use Illuminate\Database\Schema\Blueprint;
|
||||||
|
use Illuminate\Support\Facades\DB;
|
||||||
|
use Illuminate\Support\Facades\Schema;
|
||||||
|
|
||||||
|
return new class extends Migration
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Run the migrations.
|
||||||
|
*/
|
||||||
|
public function up(): void
|
||||||
|
{
|
||||||
|
// Migrate supporters
|
||||||
|
DB::table('users')->where('is_patreon', 1)->update([
|
||||||
|
'roles' => DB::raw("JSON_ARRAY('supporter')")
|
||||||
|
]);
|
||||||
|
|
||||||
|
// Migrate banned
|
||||||
|
DB::table('users')->where('is_banned', 1)->update([
|
||||||
|
'roles' => DB::raw("JSON_ARRAY('banned')")
|
||||||
|
]);
|
||||||
|
|
||||||
|
// Migrate admins
|
||||||
|
DB::table('users')->where('is_admin', 1)->update([
|
||||||
|
'roles' => DB::raw("JSON_ARRAY('admin')")
|
||||||
|
]);
|
||||||
|
|
||||||
|
// Drop columns
|
||||||
|
Schema::table('users', function (Blueprint $table) {
|
||||||
|
$table->dropColumn('is_admin');
|
||||||
|
$table->dropColumn('is_patreon');
|
||||||
|
$table->dropColumn('is_banned');
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reverse the migrations.
|
||||||
|
*/
|
||||||
|
public function down(): void
|
||||||
|
{
|
||||||
|
DB::table('users')->update(['roles' => null]);
|
||||||
|
Schema::table('users', function (Blueprint $table) {
|
||||||
|
$table->boolean('is_admin')->default(0);
|
||||||
|
$table->boolean('is_patreon')->default(0);
|
||||||
|
$table->boolean('is_banned')->default(0);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
};
|
||||||
@@ -1,74 +0,0 @@
|
|||||||
services:
|
|
||||||
laravel.test:
|
|
||||||
build:
|
|
||||||
context: './vendor/laravel/sail/runtimes/8.3'
|
|
||||||
dockerfile: Dockerfile
|
|
||||||
args:
|
|
||||||
WWWGROUP: '${WWWGROUP}'
|
|
||||||
MYSQL_CLIENT: mariadb-client
|
|
||||||
image: 'sail-8.3/app'
|
|
||||||
extra_hosts:
|
|
||||||
- 'host.docker.internal:host-gateway'
|
|
||||||
ports:
|
|
||||||
- '${APP_PORT:-80}:80'
|
|
||||||
- '${VITE_PORT:-5173}:${VITE_PORT:-5173}'
|
|
||||||
environment:
|
|
||||||
WWWUSER: '${WWWUSER}'
|
|
||||||
LARAVEL_SAIL: 1
|
|
||||||
XDEBUG_MODE: '${SAIL_XDEBUG_MODE:-off}'
|
|
||||||
XDEBUG_CONFIG: '${SAIL_XDEBUG_CONFIG:-client_host=host.docker.internal}'
|
|
||||||
IGNITION_LOCAL_SITES_PATH: '${PWD}'
|
|
||||||
volumes:
|
|
||||||
- '.:/var/www/html'
|
|
||||||
networks:
|
|
||||||
- sail
|
|
||||||
depends_on:
|
|
||||||
- mariadb
|
|
||||||
- redis
|
|
||||||
mariadb:
|
|
||||||
image: 'mariadb:11'
|
|
||||||
ports:
|
|
||||||
- '${FORWARD_DB_PORT:-3306}:3306'
|
|
||||||
environment:
|
|
||||||
MYSQL_ROOT_PASSWORD: '${DB_PASSWORD}'
|
|
||||||
MYSQL_ROOT_HOST: '%'
|
|
||||||
MYSQL_DATABASE: '${DB_DATABASE}'
|
|
||||||
MYSQL_USER: '${DB_USERNAME}'
|
|
||||||
MYSQL_PASSWORD: '${DB_PASSWORD}'
|
|
||||||
MYSQL_ALLOW_EMPTY_PASSWORD: 'yes'
|
|
||||||
volumes:
|
|
||||||
- 'sail-mariadb:/var/lib/mysql'
|
|
||||||
- './vendor/laravel/sail/database/mariadb/create-testing-database.sh:/docker-entrypoint-initdb.d/10-create-testing-database.sh'
|
|
||||||
networks:
|
|
||||||
- sail
|
|
||||||
healthcheck:
|
|
||||||
test:
|
|
||||||
- CMD
|
|
||||||
- healthcheck.sh
|
|
||||||
- '--connect'
|
|
||||||
- '--innodb_initialized'
|
|
||||||
retries: 3
|
|
||||||
timeout: 5s
|
|
||||||
redis:
|
|
||||||
image: 'redis:alpine'
|
|
||||||
ports:
|
|
||||||
- '${FORWARD_REDIS_PORT:-6379}:6379'
|
|
||||||
volumes:
|
|
||||||
- 'sail-redis:/data'
|
|
||||||
networks:
|
|
||||||
- sail
|
|
||||||
healthcheck:
|
|
||||||
test:
|
|
||||||
- CMD
|
|
||||||
- redis-cli
|
|
||||||
- ping
|
|
||||||
retries: 3
|
|
||||||
timeout: 5s
|
|
||||||
networks:
|
|
||||||
sail:
|
|
||||||
driver: bridge
|
|
||||||
volumes:
|
|
||||||
sail-mariadb:
|
|
||||||
driver: local
|
|
||||||
sail-redis:
|
|
||||||
driver: local
|
|
||||||
1313
package-lock.json
generated
1313
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
@@ -20,6 +20,7 @@
|
|||||||
"@fortawesome/fontawesome-free": "^6.5.1",
|
"@fortawesome/fontawesome-free": "^6.5.1",
|
||||||
"@jellyfin/libass-wasm": "^4.1.1",
|
"@jellyfin/libass-wasm": "^4.1.1",
|
||||||
"@yaireo/tagify": "^4.21.2",
|
"@yaireo/tagify": "^4.21.2",
|
||||||
|
"altcha": "^2.3.0",
|
||||||
"chart.js": "^4.5.0",
|
"chart.js": "^4.5.0",
|
||||||
"dashjs": "^5.0.0",
|
"dashjs": "^5.0.0",
|
||||||
"hammerjs": "^2.0.8",
|
"hammerjs": "^2.0.8",
|
||||||
|
|||||||
@@ -123,3 +123,32 @@ input:checked~.dot {
|
|||||||
src: url(https://fonts.bunny.net/figtree/files/figtree-latin-ext-600-normal.woff2) format('woff2'), url(https://fonts.bunny.net/figtree/files/figtree-latin-ext-600-normal.woff) format('woff');
|
src: url(https://fonts.bunny.net/figtree/files/figtree-latin-ext-600-normal.woff2) format('woff2'), url(https://fonts.bunny.net/figtree/files/figtree-latin-ext-600-normal.woff) format('woff');
|
||||||
unicode-range: U+0100-02AF, U+0304, U+0308, U+0329, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
|
unicode-range: U+0100-02AF, U+0304, U+0308, U+0329, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Captcha */
|
||||||
|
:root {
|
||||||
|
--altcha-border-width: 1px;
|
||||||
|
--altcha-border-radius: 0.375rem;
|
||||||
|
--altcha-color-base: #333;
|
||||||
|
--altcha-color-border: #a0a0a0;
|
||||||
|
--altcha-color-text: #fff;
|
||||||
|
--altcha-color-border-focus: currentColor;
|
||||||
|
--altcha-color-error-text: #f23939;
|
||||||
|
--altcha-color-footer-bg: #141414;
|
||||||
|
--altcha-max-width: 260px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.altcha-footer {
|
||||||
|
border-bottom-left-radius: 0.375rem;
|
||||||
|
border-bottom-right-radius: 0.375rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
input[type="checkbox"] {
|
||||||
|
background-color: #ffffff;
|
||||||
|
border-color: #a0a0a0;
|
||||||
|
color: rgb(225,29,72);
|
||||||
|
}
|
||||||
|
|
||||||
|
input[type="checkbox"]:checked {
|
||||||
|
background-color: rgb(225,29,72);
|
||||||
|
box-shadow: 0 0 0 0px #fff, 0 0 0 calc(2px + 0px) rgba(246, 59, 118, 0.5), 0 0 #0000;
|
||||||
|
}
|
||||||
@@ -12,6 +12,9 @@ import {
|
|||||||
initTE,
|
initTE,
|
||||||
} from "tw-elements";
|
} from "tw-elements";
|
||||||
|
|
||||||
|
// Captcha
|
||||||
|
import 'altcha';
|
||||||
|
|
||||||
// import Alpine from 'alpinejs';
|
// import Alpine from 'alpinejs';
|
||||||
|
|
||||||
// window.Alpine = Alpine;
|
// window.Alpine = Alpine;
|
||||||
|
|||||||
@@ -6,7 +6,7 @@
|
|||||||
<div class="mb-4 rounded-lg bg-success-400 px-6 py-5 text-base text-success-800 mt-5" role="alert">
|
<div class="mb-4 rounded-lg bg-success-400 px-6 py-5 text-base text-success-800 mt-5" role="alert">
|
||||||
{{ $alert->text }}
|
{{ $alert->text }}
|
||||||
@auth
|
@auth
|
||||||
@if(Auth::user()->is_admin)
|
@if(Auth::user()->hasRole(\App\Enums\UserRole::ADMINISTRATOR))
|
||||||
<form method="POST" action="{{ route('admin.alert.delete', $alert->id) }}" class="float-right hover:text-success-900">
|
<form method="POST" action="{{ route('admin.alert.delete', $alert->id) }}" class="float-right hover:text-success-900">
|
||||||
@csrf
|
@csrf
|
||||||
@method('delete')
|
@method('delete')
|
||||||
@@ -21,7 +21,7 @@
|
|||||||
<div class="mb-4 rounded-lg bg-danger-400 px-6 py-5 text-base text-danger-800 mt-5" role="alert">
|
<div class="mb-4 rounded-lg bg-danger-400 px-6 py-5 text-base text-danger-800 mt-5" role="alert">
|
||||||
{{ $alert->text }}
|
{{ $alert->text }}
|
||||||
@auth
|
@auth
|
||||||
@if(Auth::user()->is_admin)
|
@if(Auth::user()->hasRole(\App\Enums\UserRole::ADMINISTRATOR))
|
||||||
<form method="POST" action="{{ route('admin.alert.delete', $alert->id) }}" class="float-right hover:text-danger-900">
|
<form method="POST" action="{{ route('admin.alert.delete', $alert->id) }}" class="float-right hover:text-danger-900">
|
||||||
@csrf
|
@csrf
|
||||||
@method('delete')
|
@method('delete')
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
@auth
|
@auth
|
||||||
@if(Auth::user()->is_admin)
|
@if(Auth::user()->hasRole(\App\Enums\UserRole::ADMINISTRATOR))
|
||||||
<div class="relative p-5 bg-white dark:bg-neutral-700/40 rounded-lg overflow-hidden z-10">
|
<div class="relative p-5 bg-white dark:bg-neutral-700/40 rounded-lg overflow-hidden z-10">
|
||||||
<div class="float-left">
|
<div class="float-left">
|
||||||
<a data-te-toggle="modal" data-te-target="#modalUploadEpisode" class="text-xl text-gray-800 dark:text-gray-200 leading-tight cursor-pointer whitespace-nowrap">
|
<a data-te-toggle="modal" data-te-target="#modalUploadEpisode" class="text-xl text-gray-800 dark:text-gray-200 leading-tight cursor-pointer whitespace-nowrap">
|
||||||
|
|||||||
@@ -69,6 +69,11 @@
|
|||||||
</label>
|
</label>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<div class="block">
|
||||||
|
<altcha-widget id="captcha" floating challengeurl="/altcha-challenge"></altcha-widget>
|
||||||
|
<x-input-error :messages="$errors->get('altcha')" class="mt-2" />
|
||||||
|
</div>
|
||||||
|
|
||||||
<div class="flex items-center justify-end mt-4">
|
<div class="flex items-center justify-end mt-4">
|
||||||
@if (Route::has('password.request'))
|
@if (Route::has('password.request'))
|
||||||
<a class="underline text-sm text-neutral-600 dark:text-neutral-400 hover:text-neutral-900 dark:hover:text-neutral-100 rounded-md focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-rose-500 dark:focus:ring-offset-neutral-800" href="{{ route('password.request') }}">
|
<a class="underline text-sm text-neutral-600 dark:text-neutral-400 hover:text-neutral-900 dark:hover:text-neutral-100 rounded-md focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-rose-500 dark:focus:ring-offset-neutral-800" href="{{ route('password.request') }}">
|
||||||
@@ -127,6 +132,11 @@
|
|||||||
<x-input-error :messages="$errors->get('password_confirmation')" class="mt-2" />
|
<x-input-error :messages="$errors->get('password_confirmation')" class="mt-2" />
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<div class="block">
|
||||||
|
<altcha-widget id="captcha" floating challengeurl="/altcha-challenge"></altcha-widget>
|
||||||
|
<x-input-error :messages="$errors->get('altcha')" class="mt-2" />
|
||||||
|
</div>
|
||||||
|
|
||||||
<div class="flex items-center justify-end mt-4">
|
<div class="flex items-center justify-end mt-4">
|
||||||
<x-primary-button class="ms-4">
|
<x-primary-button class="ms-4">
|
||||||
{{ __('Register') }}
|
{{ __('Register') }}
|
||||||
|
|||||||
@@ -33,19 +33,7 @@
|
|||||||
<x-input-error class="mt-2" :messages="$errors->get('message')" />
|
<x-input-error class="mt-2" :messages="$errors->get('message')" />
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div>
|
<altcha-widget id="captcha" floating challengeurl="/altcha-challenge"></altcha-widget>
|
||||||
<x-input-label for="message" :value="__('Captcha')" />
|
|
||||||
<div class="flex pt-2">
|
|
||||||
<div id="captchaImg">
|
|
||||||
{!! captcha_img() !!}
|
|
||||||
</div>
|
|
||||||
<button type="button" class="inline-flex items-center ml-2 px-2 py-2 bg-white dark:bg-gray-800 border border-gray-300 dark:border-gray-500 rounded-md font-semibold text-xs text-gray-700 dark:text-gray-300 uppercase tracking-widest shadow-sm hover:bg-gray-50 dark:hover:bg-gray-700 focus:outline-none focus:ring-2 focus:ring-indigo-500 focus:ring-offset-2 dark:focus:ring-offset-gray-800 disabled:opacity-25 transition ease-in-out duration-150" id="reloadcaptcha">
|
|
||||||
<i class="fa-solid fa-rotate-right"></i>
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
<br>
|
|
||||||
<x-text-input id="captcha" class="block " type="text" name="captcha" required />
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="flex items-center gap-4">
|
<div class="flex items-center gap-4">
|
||||||
<x-primary-button>{{ __('Submit') }}</x-primary-button>
|
<x-primary-button>{{ __('Submit') }}</x-primary-button>
|
||||||
@@ -65,18 +53,4 @@
|
|||||||
@endif
|
@endif
|
||||||
</div>
|
</div>
|
||||||
</form>
|
</form>
|
||||||
|
|
||||||
<script>
|
|
||||||
function reloadCaptcha() {
|
|
||||||
window.axios.get('/reload-captcha').then(function(response) {
|
|
||||||
if (response.status == 200) {
|
|
||||||
document.querySelector("#captchaImg").innerHTML = response.data.captcha;
|
|
||||||
}
|
|
||||||
}).catch(function(error) {
|
|
||||||
console.log(error);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
document.querySelector("#reloadcaptcha").addEventListener("click", reloadCaptcha);
|
|
||||||
</script>
|
|
||||||
</section>
|
</section>
|
||||||
@@ -163,7 +163,7 @@
|
|||||||
<i class="fa-solid fa-gear"></i> {{ __('nav.settings') }}
|
<i class="fa-solid fa-gear"></i> {{ __('nav.settings') }}
|
||||||
</x-dropdown-link>
|
</x-dropdown-link>
|
||||||
|
|
||||||
@if (Auth::user()->is_admin)
|
@if (Auth::user()->hasRole(\App\Enums\UserRole::ADMINISTRATOR))
|
||||||
<x-dropdown-link href="{{ route('admin.upload.index') }}">
|
<x-dropdown-link href="{{ route('admin.upload.index') }}">
|
||||||
<i class="fa-solid fa-user-tie"></i> Admin
|
<i class="fa-solid fa-user-tie"></i> Admin
|
||||||
</x-dropdown-link>
|
</x-dropdown-link>
|
||||||
|
|||||||
@@ -6,12 +6,16 @@
|
|||||||
<thead class="text-xs text-gray-700 uppercase bg-gray-50 dark:bg-pink-700 dark:text-neutral-200 ">
|
<thead class="text-xs text-gray-700 uppercase bg-gray-50 dark:bg-pink-700 dark:text-neutral-200 ">
|
||||||
<tr>
|
<tr>
|
||||||
<th scope="col" class="px-6 py-3">
|
<th scope="col" class="px-6 py-3">
|
||||||
Discord-ID
|
ID
|
||||||
|
</th>
|
||||||
|
<th scope="col" class="px-6 py-3">
|
||||||
|
Discord ID
|
||||||
<input
|
<input
|
||||||
class="w-4 h-4 ml-2 text-rose-600 bg-gray-100 border-gray-300 rounded focus:ring-rose-500 dark:focus:ring-rose-600 dark:ring-offset-gray-800 focus:ring-2 dark:bg-gray-700 dark:border-gray-600"
|
wire:model.live.debounce.600ms="discordId"
|
||||||
type="checkbox"
|
type="search"
|
||||||
wire:model.live="filtered"
|
id="discord-search"
|
||||||
value="true"
|
class="ml-2 w-32 h-7 text-sm text-gray-900 border border-gray-300 rounded-lg bg-gray-50 focus:ring-rose-800 focus:border-rose-900 dark:bg-neutral-900 dark:border-neutral-600 dark:placeholder-gray-400 dark:text-white dark:focus:ring-rose-800 dark:focus:border-rose-900"
|
||||||
|
placeholder="Search..."
|
||||||
>
|
>
|
||||||
</th>
|
</th>
|
||||||
<th scope="col" class="px-6 py-3">
|
<th scope="col" class="px-6 py-3">
|
||||||
@@ -59,14 +63,17 @@
|
|||||||
<th scope="row" class="px-6 py-4 font-medium text-gray-900 whitespace-nowrap dark:text-white">
|
<th scope="row" class="px-6 py-4 font-medium text-gray-900 whitespace-nowrap dark:text-white">
|
||||||
{{ $user->id }}
|
{{ $user->id }}
|
||||||
</th>
|
</th>
|
||||||
|
<td class="px-6 py-4">
|
||||||
|
{{ $user->discord_id ?? 'n/a' }}
|
||||||
|
</td>
|
||||||
<td class="px-6 py-4">
|
<td class="px-6 py-4">
|
||||||
{{ $user->name }}
|
{{ $user->name }}
|
||||||
</td>
|
</td>
|
||||||
<td class="px-6 py-4">
|
<td class="px-6 py-4">
|
||||||
{{ $user->is_patreon ? 'Yes' : 'No' }}
|
{{ $user->hasRole(\App\Enums\UserRole::SUPPORTER) ? 'Yes' : 'No' }}
|
||||||
</td>
|
</td>
|
||||||
<td class="px-6 py-4">
|
<td class="px-6 py-4">
|
||||||
{{ $user->is_banned ? 'Yes' : 'No' }}
|
{{ $user->hasRole(\App\Enums\UserRole::BANNED) ? 'Yes' : 'No' }}
|
||||||
</td>
|
</td>
|
||||||
<td class="px-6 py-4">
|
<td class="px-6 py-4">
|
||||||
{{ $user->created_at->format('Y-m-d') }}
|
{{ $user->created_at->format('Y-m-d') }}
|
||||||
@@ -78,9 +85,9 @@
|
|||||||
<form method="POST" action="{{ route('admin.user.update') }}">
|
<form method="POST" action="{{ route('admin.user.update') }}">
|
||||||
@csrf
|
@csrf
|
||||||
<input type="hidden" value="{{ $user->id }}" name="id">
|
<input type="hidden" value="{{ $user->id }}" name="id">
|
||||||
<input type="hidden" value="{{ $user->is_banned ? 'unban' : 'ban' }}" name="action">
|
<input type="hidden" value="{{ $user->hasRole(\App\Enums\UserRole::BANNED) ? 'unban' : 'ban' }}" name="action">
|
||||||
<button type="submit" class="inline-block w-full rounded bg-rose-600 pl-[4px] pr-[4px] p-[1px] text-xs font-medium uppercase leading-normal text-white transition duration-150 ease-in-out hover:bg-rose-700 focus:bg-rose-600">
|
<button type="submit" class="inline-block w-full rounded bg-rose-600 pl-[4px] pr-[4px] p-[1px] text-xs font-medium uppercase leading-normal text-white transition duration-150 ease-in-out hover:bg-rose-700 focus:bg-rose-600">
|
||||||
{{ $user->is_banned ? 'Unban' : 'Ban' }}
|
{{ $user->hasRole(\App\Enums\UserRole::BANNED) ? 'Unban' : 'Ban' }}
|
||||||
</button>
|
</button>
|
||||||
</form>
|
</form>
|
||||||
<button wire:click="deleteUserComments('{{ $user->id }}')" class="inline-block w-full rounded bg-red-600 pl-[4px] pr-[4px] p-[1px] text-xs font-medium uppercase leading-normal text-white transition duration-150 ease-in-out hover:bg-rose-700 focus:bg-rose-600">
|
<button wire:click="deleteUserComments('{{ $user->id }}')" class="inline-block w-full rounded bg-red-600 pl-[4px] pr-[4px] p-[1px] text-xs font-medium uppercase leading-normal text-white transition duration-150 ease-in-out hover:bg-rose-700 focus:bg-rose-600">
|
||||||
|
|||||||
@@ -6,10 +6,10 @@
|
|||||||
<div class="flex-grow">
|
<div class="flex-grow">
|
||||||
<div class="flex gap-2">
|
<div class="flex gap-2">
|
||||||
<p class="font-medium text-gray-900 dark:text-gray-100">{{ $comment->user->name }}</p>
|
<p class="font-medium text-gray-900 dark:text-gray-100">{{ $comment->user->name }}</p>
|
||||||
@if($comment->user->is_admin)
|
@if($comment->user->hasRole(\App\Enums\UserRole::ADMINISTRATOR))
|
||||||
<a data-te-toggle="tooltip" title="Admin"><i class="fa-solid fa-crown text-yellow-600"></i></a>
|
<a data-te-toggle="tooltip" title="Admin"><i class="fa-solid fa-crown text-yellow-600"></i></a>
|
||||||
@endif
|
@endif
|
||||||
@if($comment->user->is_patreon)
|
@if($comment->user->hasRole(\App\Enums\UserRole::SUPPORTER))
|
||||||
<a data-te-toggle="tooltip" title="Badge of appreciation for the horny people supporting us! :3"><i class="fa-solid fa-hand-holding-heart text-rose-600"></i></a>
|
<a data-te-toggle="tooltip" title="Badge of appreciation for the horny people supporting us! :3"><i class="fa-solid fa-hand-holding-heart text-rose-600"></i></a>
|
||||||
@endif
|
@endif
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -52,7 +52,7 @@
|
|||||||
<br>
|
<br>
|
||||||
@php $download = $episode->getDownloadByType('UHD'); @endphp
|
@php $download = $episode->getDownloadByType('UHD'); @endphp
|
||||||
@isset($download)
|
@isset($download)
|
||||||
@if (!Auth::user()->is_patreon)
|
@if (!Auth::user()->hasRole(\App\Enums\UserRole::SUPPORTER))
|
||||||
@if (config('hstream.free_downloads'))
|
@if (config('hstream.free_downloads'))
|
||||||
<p class="font-bold text-gray-800 dark:text-gray-200">
|
<p class="font-bold text-gray-800 dark:text-gray-200">
|
||||||
<i class="fa-solid fa-lock-open pr-[4px] text-yellow-600"></i> 4k
|
<i class="fa-solid fa-lock-open pr-[4px] text-yellow-600"></i> 4k
|
||||||
@@ -91,7 +91,7 @@
|
|||||||
|
|
||||||
<br>
|
<br>
|
||||||
@if ($episode->interpolated_uhd)
|
@if ($episode->interpolated_uhd)
|
||||||
@if (!Auth::user()->is_patreon)
|
@if (!Auth::user()->hasRole(\App\Enums\UserRole::SUPPORTER))
|
||||||
@if (config('hstream.free_downloads'))
|
@if (config('hstream.free_downloads'))
|
||||||
<p class="font-bold text-gray-800 dark:text-gray-200">
|
<p class="font-bold text-gray-800 dark:text-gray-200">
|
||||||
<i class="fa-solid fa-lock-open pr-[4px] text-yellow-600"></i> 4k 48fps
|
<i class="fa-solid fa-lock-open pr-[4px] text-yellow-600"></i> 4k 48fps
|
||||||
|
|||||||
@@ -8,18 +8,7 @@
|
|||||||
<p id="message" class="text-red-600">
|
<p id="message" class="text-red-600">
|
||||||
</p>
|
</p>
|
||||||
<div class="flex pt-2">
|
<div class="flex pt-2">
|
||||||
<div id="captchaImg">
|
<altcha-widget id="altcha" challengeurl="/altcha-challenge"></altcha-widget>
|
||||||
{!! captcha_img() !!}
|
|
||||||
</div>
|
|
||||||
<button type="button" class="inline-flex items-center ml-2 px-2 py-2 bg-white dark:bg-gray-800 border border-gray-300 dark:border-gray-500 rounded-md font-semibold text-xs text-gray-700 dark:text-gray-300 uppercase tracking-widest shadow-sm hover:bg-gray-50 dark:hover:bg-gray-700 focus:outline-none focus:ring-2 focus:ring-indigo-500 focus:ring-offset-2 dark:focus:ring-offset-gray-800 disabled:opacity-25 transition ease-in-out duration-150" id="reloadcaptcha" >
|
|
||||||
<i class="fa-solid fa-rotate-right"></i>
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
<div class="flex pt-2 mt-1">
|
|
||||||
<x-text-input id="captcha_text" class="block " type="text" name="captcha_text"/>
|
|
||||||
<button type="button" class="inline-flex items-center ml-2 px-2 -pt-1 bg-rose-600 border border-transparent rounded-md font-semibold text-xs text-white uppercase tracking-widest hover:bg-rose-700 active:bg-rose-900 focus:outline-none focus:ring-2 focus:ring-rose-500 focus:ring-offset-2 dark:focus:ring-offset-gray-800 transition ease-in-out duration-150" id="submitcaptcha" >
|
|
||||||
Submit
|
|
||||||
</button>
|
|
||||||
</div>
|
</div>
|
||||||
<br>
|
<br>
|
||||||
<p class="text-gray-800 dark:text-gray-200 text-sm">
|
<p class="text-gray-800 dark:text-gray-200 text-sm">
|
||||||
@@ -51,21 +40,12 @@
|
|||||||
|
|
||||||
<script>
|
<script>
|
||||||
var downloadCounter = 0;
|
var downloadCounter = 0;
|
||||||
function reloadCaptcha() {
|
|
||||||
window.axios.get('/reload-captcha').then(function (response) {
|
|
||||||
if (response.status == 200) {
|
|
||||||
document.querySelector("#captchaImg").innerHTML = response.data.captcha;
|
|
||||||
}
|
|
||||||
}).catch(function (error) {
|
|
||||||
console.log(error);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
function submitCaptcha() {
|
function submitCaptcha(captchaToken) {
|
||||||
document.querySelector("#message").innerHTML = '';
|
document.querySelector("#message").innerHTML = '';
|
||||||
window.axios.post('/get-download', {
|
window.axios.post('/get-download', {
|
||||||
captcha: document.getElementById('captcha_text').value,
|
episode_id: document.getElementById('e_id').value,
|
||||||
episode_id: document.getElementById('e_id').value
|
captcha: captchaToken,
|
||||||
}).then(function (response) {
|
}).then(function (response) {
|
||||||
document.querySelector("#captcharequired").style.display = "none";
|
document.querySelector("#captcharequired").style.display = "none";
|
||||||
document.querySelector("#captchsolved").style.display = "block";
|
document.querySelector("#captchsolved").style.display = "block";
|
||||||
@@ -89,6 +69,16 @@
|
|||||||
|
|
||||||
document.querySelector("#downloadEpisode").addEventListener("click", increaseDownloadCounter);
|
document.querySelector("#downloadEpisode").addEventListener("click", increaseDownloadCounter);
|
||||||
|
|
||||||
document.querySelector("#reloadcaptcha").addEventListener("click", reloadCaptcha);
|
document.addEventListener("DOMContentLoaded", () => {
|
||||||
document.querySelector("#submitcaptcha").addEventListener("click", submitCaptcha);
|
const altcha = document.querySelector("#altcha");
|
||||||
|
|
||||||
|
altcha.addEventListener("statechange", (ev) => {
|
||||||
|
if (ev.detail.state === "verified") {
|
||||||
|
submitCaptcha(ev.detail.payload);
|
||||||
|
|
||||||
|
// Remove captcha from DOM
|
||||||
|
altcha.remove();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
</script>
|
</script>
|
||||||
|
|||||||
@@ -6,10 +6,10 @@
|
|||||||
<div class="flex-grow">
|
<div class="flex-grow">
|
||||||
<div class="flex gap-2">
|
<div class="flex gap-2">
|
||||||
<p class="font-medium text-gray-900 dark:text-gray-100">{{ $comment->user->name }}</p>
|
<p class="font-medium text-gray-900 dark:text-gray-100">{{ $comment->user->name }}</p>
|
||||||
@if($comment->user->is_admin)
|
@if($comment->user->hasRole(\App\Enums\UserRole::ADMINISTRATOR))
|
||||||
<a data-te-toggle="tooltip" title="Admin"><i class="fa-solid fa-crown text-yellow-600"></i></a>
|
<a data-te-toggle="tooltip" title="Admin"><i class="fa-solid fa-crown text-yellow-600"></i></a>
|
||||||
@endif
|
@endif
|
||||||
@if($comment->user->is_patreon)
|
@if($comment->user->hasRole(\App\Enums\UserRole::SUPPORTER))
|
||||||
<a data-te-toggle="tooltip" title="Badge of appreciation for the horny people supporting us! :3"><i class="fa-solid fa-hand-holding-heart text-rose-600"></i></a>
|
<a data-te-toggle="tooltip" title="Badge of appreciation for the horny people supporting us! :3"><i class="fa-solid fa-hand-holding-heart text-rose-600"></i></a>
|
||||||
@endif
|
@endif
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -46,7 +46,7 @@
|
|||||||
@include('modals.share')
|
@include('modals.share')
|
||||||
|
|
||||||
@auth
|
@auth
|
||||||
@if(Auth::user()->is_admin)
|
@if(Auth::user()->hasRole(\App\Enums\UserRole::ADMINISTRATOR))
|
||||||
@include('admin.modals.upload-episode')
|
@include('admin.modals.upload-episode')
|
||||||
@include('admin.modals.add-subtitles')
|
@include('admin.modals.add-subtitles')
|
||||||
@include('admin.modals.edit-episode')
|
@include('admin.modals.edit-episode')
|
||||||
|
|||||||
@@ -4,7 +4,7 @@
|
|||||||
<div class="flex flex-col py-5 pl-24">
|
<div class="flex flex-col py-5 pl-24">
|
||||||
<strong class="text-slate-900 text-xl font-bold dark:text-slate-200">
|
<strong class="text-slate-900 text-xl font-bold dark:text-slate-200">
|
||||||
{{ $user->name }}
|
{{ $user->name }}
|
||||||
@if ($user->is_patreon)
|
@if ($user->hasRole(\App\Enums\UserRole::SUPPORTER))
|
||||||
<a data-te-toggle="tooltip" title="Badge of appreciation for the horny people supporting us! :3"><i
|
<a data-te-toggle="tooltip" title="Badge of appreciation for the horny people supporting us! :3"><i
|
||||||
class="fa-solid fa-hand-holding-heart text-rose-600 animate-pulse"></i></a>
|
class="fa-solid fa-hand-holding-heart text-rose-600 animate-pulse"></i></a>
|
||||||
@endif
|
@endif
|
||||||
|
|||||||
62
routes/admin.php
Normal file
62
routes/admin.php
Normal file
@@ -0,0 +1,62 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
use App\Http\Controllers\Admin\AlertController;
|
||||||
|
use App\Http\Controllers\Admin\ContactController;
|
||||||
|
use App\Http\Controllers\Admin\CommentsController;
|
||||||
|
use App\Http\Controllers\Admin\EpisodeController;
|
||||||
|
use App\Http\Controllers\Admin\ReleaseController;
|
||||||
|
use App\Http\Controllers\Admin\UserController;
|
||||||
|
use App\Http\Controllers\Admin\SubtitleController;
|
||||||
|
use App\Http\Controllers\Admin\SiteBackgroundController;
|
||||||
|
use App\Http\Controllers\Api\AdminApiController;
|
||||||
|
use Illuminate\Support\Facades\Route;
|
||||||
|
|
||||||
|
/*
|
||||||
|
|---------------------------------------------------------------------------------
|
||||||
|
| Admin Routes
|
||||||
|
|---------------------------------------------------------------------------------
|
||||||
|
*/
|
||||||
|
Route::group(['middleware' => ['auth', 'auth.admin']], function () {
|
||||||
|
// Site alerts
|
||||||
|
Route::get('/admin/alert', [AlertController::class, 'index'])->name('admin.alert.index');
|
||||||
|
Route::post('/admin/alert', [AlertController::class, 'store'])->name('admin.alert.create');
|
||||||
|
Route::delete('/admin/alert/{alert_id}', [AlertController::class, 'delete'])->name('admin.alert.delete');
|
||||||
|
|
||||||
|
// Users
|
||||||
|
Route::get('/admin/users', [UserController::class, 'index'])->name('admin.user.index');
|
||||||
|
Route::post('/admin/users', [UserController::class, 'update'])->name('admin.user.update');
|
||||||
|
|
||||||
|
// Comments
|
||||||
|
Route::get('/admin/comments', [CommentsController::class, 'index'])->name('admin.comments.index');
|
||||||
|
|
||||||
|
// Contact page overview
|
||||||
|
Route::get('/admin/contact', [ContactController::class, 'index'])->name('admin.contact.index');
|
||||||
|
Route::delete('/admin/contact/{contact_id}', [ContactController::class, 'delete'])->name('admin.contact.delete');
|
||||||
|
|
||||||
|
// Site background settings
|
||||||
|
Route::get('/admin/background', [SiteBackgroundController::class, 'index'])->name('admin.background.index');
|
||||||
|
Route::post('/admin/background', [SiteBackgroundController::class, 'create'])->name('admin.background.create');
|
||||||
|
Route::put('/admin/background', [SiteBackgroundController::class, 'update'])->name('admin.background.update');
|
||||||
|
Route::delete('/admin/background', [SiteBackgroundController::class, 'delete'])->name('admin.background.delete');
|
||||||
|
|
||||||
|
// Release
|
||||||
|
Route::get('/admin/release', [ReleaseController::class, 'index'])->name('admin.upload.index');
|
||||||
|
Route::post('/admin/release/upload', [ReleaseController::class, 'store'])->name('admin.upload');
|
||||||
|
|
||||||
|
// Episode
|
||||||
|
Route::post('/admin/episode/upload', [EpisodeController::class, 'store'])->name('admin.upload.episode');
|
||||||
|
Route::post('/admin/episode/edit', [EpisodeController::class, 'update'])->name('admin.edit');
|
||||||
|
|
||||||
|
// Get Tags used for Upload Form
|
||||||
|
Route::get('/admin/tags', [AdminApiController::class, 'getTags'])->name('admin.tags');
|
||||||
|
Route::get('/admin/studios', [AdminApiController::class, 'getStudios'])->name('admin.studios');
|
||||||
|
|
||||||
|
// Get Tags for editing Episode
|
||||||
|
Route::get('/admin/tags/{episode_id}', [AdminApiController::class, 'getEpisodeTags'])->name('admin.tags.episode');
|
||||||
|
Route::get('/admin/studio/{episode_id}', [AdminApiController::class, 'getEpisodeStudio'])->name('admin.studio.episode');
|
||||||
|
|
||||||
|
// Subtitles
|
||||||
|
Route::get('/admin/subtitles/{episode_id}', [AdminApiController::class, 'getSubtitles'])->name('admin.subtitles');
|
||||||
|
Route::post('/admin/add-new-subtitle', [SubtitleController::class, 'store'])->name('admin.add.new.subtitle');
|
||||||
|
Route::post('/admin/update-subtitles', [SubtitleController::class, 'update'])->name('admin.update.subtitles');
|
||||||
|
});
|
||||||
45
routes/user.php
Normal file
45
routes/user.php
Normal file
@@ -0,0 +1,45 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
use App\Http\Controllers\HomeController;
|
||||||
|
use App\Http\Controllers\ProfileController;
|
||||||
|
use App\Http\Controllers\PlaylistController;
|
||||||
|
use App\Http\Controllers\Api\UserApiController;
|
||||||
|
use Illuminate\Support\Facades\Route;
|
||||||
|
|
||||||
|
/*
|
||||||
|
|---------------------------------------------------------------------------------
|
||||||
|
| User Routes
|
||||||
|
|---------------------------------------------------------------------------------
|
||||||
|
*/
|
||||||
|
Route::middleware('auth')->group(function () {
|
||||||
|
Route::get('/user/profile', [ProfileController::class, 'index'])->name('profile.show');
|
||||||
|
Route::get('/user/comments', [ProfileController::class, 'comments'])->name('profile.comments');
|
||||||
|
Route::get('/user/likes', [ProfileController::class, 'likes'])->name('profile.likes');
|
||||||
|
Route::get('/user/watched', [ProfileController::class, 'watched'])->name('user.watched');
|
||||||
|
|
||||||
|
// Notifications
|
||||||
|
Route::get('/user/notifications', [App\Http\Controllers\NotificationController::class, 'index'])->name('profile.notifications');
|
||||||
|
Route::delete('/user/notifications', [App\Http\Controllers\NotificationController::class, 'delete'])->name('profile.notifications.delete');
|
||||||
|
|
||||||
|
// User Profile Actions
|
||||||
|
Route::get('/user/settings', [ProfileController::class, 'settings'])->name('profile.settings');
|
||||||
|
Route::patch('/user/settings', [ProfileController::class, 'update'])->name('profile.update');
|
||||||
|
Route::delete('/user/delete', [ProfileController::class, 'destroy'])->name('profile.delete');
|
||||||
|
Route::post('/user/settings', [ProfileController::class, 'saveSettings'])->name('profile.settings.save');
|
||||||
|
Route::get('/user/blacklist', [UserApiController::class, 'getBlacklist'])->name('profile.blacklist');
|
||||||
|
Route::post('/user/blacklist', [ProfileController::class, 'saveBlacklist'])->name('profile.blacklist.save');
|
||||||
|
|
||||||
|
// Playlist Routes for User Page
|
||||||
|
Route::get('/user/playlists', [PlaylistController::class, 'playlists'])->name('profile.playlists');
|
||||||
|
Route::get('/user/playlist/{playlist_id}', [PlaylistController::class, 'showPlaylist'])->name('profile.playlist.show');
|
||||||
|
Route::post('/create-playlist', [PlaylistController::class, 'createPlaylist'])->name('profile.playlists.create');
|
||||||
|
Route::delete('/user/playlist/{playlist_id}', [PlaylistController::class, 'deletePlaylist'])->name('profile.playlist.delete');
|
||||||
|
Route::post('/user/playlist-episode', [PlaylistController::class, 'deleteEpisodeFromPlaylist'])->name('playlist.delete.episode');
|
||||||
|
|
||||||
|
// Playlist Routes for Modals on Stream Page
|
||||||
|
Route::post('/hentai/add-to-playlist', [PlaylistController::class, 'addPlaylistApi'])->name('hentai.playlists.add');
|
||||||
|
Route::post('/hentai/create-playlist', [PlaylistController::class, 'createPlaylistApi'])->name('hentai.playlists.create');
|
||||||
|
|
||||||
|
// Download Page
|
||||||
|
Route::get('/download-search', [HomeController::class, 'downloadSearch'])->name('download.search');
|
||||||
|
});
|
||||||
@@ -3,14 +3,12 @@
|
|||||||
use App\Http\Controllers\ContactController;
|
use App\Http\Controllers\ContactController;
|
||||||
use App\Http\Controllers\HomeController;
|
use App\Http\Controllers\HomeController;
|
||||||
use App\Http\Controllers\PlaylistController;
|
use App\Http\Controllers\PlaylistController;
|
||||||
use App\Http\Controllers\ProfileController;
|
|
||||||
use App\Http\Controllers\StreamController;
|
use App\Http\Controllers\StreamController;
|
||||||
use App\Http\Controllers\UserController;
|
|
||||||
use App\Http\Controllers\Api\AdminApiController;
|
|
||||||
use App\Http\Controllers\Api\DownloadApiController;
|
use App\Http\Controllers\Api\DownloadApiController;
|
||||||
use App\Http\Controllers\Api\HentaiApiController;
|
use App\Http\Controllers\Api\HentaiApiController;
|
||||||
use App\Http\Controllers\Api\StreamApiController;
|
use App\Http\Controllers\Api\StreamApiController;
|
||||||
use App\Http\Controllers\Api\UserApiController;
|
|
||||||
use Illuminate\Support\Facades\Route;
|
use Illuminate\Support\Facades\Route;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -40,100 +38,15 @@ Route::post('/search', [HomeController::class, 'searchRedirect'])->name('hentai.
|
|||||||
Route::get('/contact', [ContactController::class, 'index'])->name('contact.index');
|
Route::get('/contact', [ContactController::class, 'index'])->name('contact.index');
|
||||||
Route::post('/contact', [ContactController::class, 'store'])->name('contact.store');
|
Route::post('/contact', [ContactController::class, 'store'])->name('contact.store');
|
||||||
|
|
||||||
// Public Playlistts
|
// Public Playlists
|
||||||
Route::get('/playlists', [PlaylistController::class, 'index'])->name('playlist.index');
|
Route::get('/playlists', [PlaylistController::class, 'index'])->name('playlist.index');
|
||||||
Route::get('/playlist/{playlist_id}', [PlaylistController::class, 'show'])->name('playlist.show');
|
Route::get('/playlist/{playlist_id}', [PlaylistController::class, 'show'])->name('playlist.show');
|
||||||
|
|
||||||
// Captcha Reload
|
|
||||||
Route::get('/reload-captcha', [ContactController::class, 'reloadCaptcha']);
|
|
||||||
|
|
||||||
// Download
|
// Download
|
||||||
Route::post('/get-download', [DownloadApiController::class, 'getDownload']);
|
Route::post('/get-download', [DownloadApiController::class, 'getDownload']);
|
||||||
|
|
||||||
Route::post('/update-language', [HomeController::class, 'updateLanguage'])->name('update.language');
|
Route::post('/update-language', [HomeController::class, 'updateLanguage'])->name('update.language');
|
||||||
|
|
||||||
// User Routes
|
require __DIR__.'/user.php';
|
||||||
Route::middleware('auth')->group(function () {
|
require __DIR__.'/admin.php';
|
||||||
Route::get('/user/profile', [ProfileController::class, 'index'])->name('profile.show');
|
|
||||||
Route::get('/user/comments', [ProfileController::class, 'comments'])->name('profile.comments');
|
|
||||||
Route::get('/user/likes', [ProfileController::class, 'likes'])->name('profile.likes');
|
|
||||||
Route::get('/user/watched', [ProfileController::class, 'watched'])->name('user.watched');
|
|
||||||
|
|
||||||
// Notifications
|
|
||||||
Route::get('/user/notifications', [App\Http\Controllers\NotificationController::class, 'index'])->name('profile.notifications');
|
|
||||||
Route::delete('/user/notifications', [App\Http\Controllers\NotificationController::class, 'delete'])->name('profile.notifications.delete');
|
|
||||||
|
|
||||||
// User Profile Actions
|
|
||||||
Route::get('/user/settings', [ProfileController::class, 'settings'])->name('profile.settings');
|
|
||||||
Route::patch('/user/settings', [ProfileController::class, 'update'])->name('profile.update');
|
|
||||||
Route::delete('/user/delete', [ProfileController::class, 'destroy'])->name('profile.delete');
|
|
||||||
Route::post('/user/settings', [ProfileController::class, 'saveSettings'])->name('profile.settings.save');
|
|
||||||
Route::get('/user/blacklist', [UserApiController::class, 'getBlacklist'])->name('profile.blacklist');
|
|
||||||
Route::post('/user/blacklist', [ProfileController::class, 'saveBlacklist'])->name('profile.blacklist.save');
|
|
||||||
|
|
||||||
// Playlist Routes for User Page
|
|
||||||
Route::get('/user/playlists', [PlaylistController::class, 'playlists'])->name('profile.playlists');
|
|
||||||
Route::get('/user/playlist/{playlist_id}', [PlaylistController::class, 'showPlaylist'])->name('profile.playlist.show');
|
|
||||||
Route::post('/create-playlist', [PlaylistController::class, 'createPlaylist'])->name('profile.playlists.create');
|
|
||||||
Route::delete('/user/playlist/{playlist_id}', [PlaylistController::class, 'deletePlaylist'])->name('profile.playlist.delete');
|
|
||||||
Route::post('/user/playlist-episode', [PlaylistController::class, 'deleteEpisodeFromPlaylist'])->name('playlist.delete.episode');
|
|
||||||
|
|
||||||
// Playlist Routes for Modals on Stream Page
|
|
||||||
Route::post('/hentai/add-to-playlist', [PlaylistController::class, 'addPlaylistApi'])->name('hentai.playlists.add');
|
|
||||||
Route::post('/hentai/create-playlist', [PlaylistController::class, 'createPlaylistApi'])->name('hentai.playlists.create');
|
|
||||||
|
|
||||||
// Download Page
|
|
||||||
Route::get('/download-search', [HomeController::class, 'downloadSearch'])->name('download.search');
|
|
||||||
});
|
|
||||||
|
|
||||||
/*
|
|
||||||
|---------------------------------------------------------------------------------
|
|
||||||
| Admin Pages
|
|
||||||
|---------------------------------------------------------------------------------
|
|
||||||
*/
|
|
||||||
Route::group(['middleware' => ['auth', 'auth.admin']], function () {
|
|
||||||
// Site alerts
|
|
||||||
Route::get('/admin/alert', [App\Http\Controllers\Admin\AlertController::class, 'index'])->name('admin.alert.index');
|
|
||||||
Route::post('/admin/alert', [App\Http\Controllers\Admin\AlertController::class, 'store'])->name('admin.alert.create');
|
|
||||||
Route::delete('/admin/alert/{alert_id}', [App\Http\Controllers\Admin\AlertController::class, 'delete'])->name('admin.alert.delete');
|
|
||||||
|
|
||||||
// Users
|
|
||||||
Route::get('/admin/users', [App\Http\Controllers\Admin\UserController::class, 'index'])->name('admin.user.index');
|
|
||||||
Route::post('/admin/users', [App\Http\Controllers\Admin\UserController::class, 'update'])->name('admin.user.update');
|
|
||||||
|
|
||||||
// Comments
|
|
||||||
Route::get('/admin/comments', [App\Http\Controllers\Admin\CommentsController::class, 'index'])->name('admin.comments.index');
|
|
||||||
|
|
||||||
// Contact page overview
|
|
||||||
Route::get('/admin/contact', [App\Http\Controllers\Admin\ContactController::class, 'index'])->name('admin.contact.index');
|
|
||||||
Route::delete('/admin/contact/{contact_id}', [App\Http\Controllers\Admin\ContactController::class, 'delete'])->name('admin.contact.delete');
|
|
||||||
|
|
||||||
// Site background settings
|
|
||||||
Route::get('/admin/background', [App\Http\Controllers\Admin\SiteBackgroundController::class, 'index'])->name('admin.background.index');
|
|
||||||
Route::post('/admin/background', [App\Http\Controllers\Admin\SiteBackgroundController::class, 'create'])->name('admin.background.create');
|
|
||||||
Route::put('/admin/background', [App\Http\Controllers\Admin\SiteBackgroundController::class, 'update'])->name('admin.background.update');
|
|
||||||
Route::delete('/admin/background', [App\Http\Controllers\Admin\SiteBackgroundController::class, 'delete'])->name('admin.background.delete');
|
|
||||||
|
|
||||||
// Release
|
|
||||||
Route::get('/admin/release', [App\Http\Controllers\Admin\ReleaseController::class, 'index'])->name('admin.upload.index');
|
|
||||||
Route::post('/admin/release/upload', [App\Http\Controllers\Admin\ReleaseController::class, 'store'])->name('admin.upload');
|
|
||||||
|
|
||||||
// Episode
|
|
||||||
Route::post('/admin/episode/upload', [App\Http\Controllers\Admin\EpisodeController::class, 'store'])->name('admin.upload.episode');
|
|
||||||
Route::post('/admin/episode/edit', [App\Http\Controllers\Admin\EpisodeController::class, 'update'])->name('admin.edit');
|
|
||||||
|
|
||||||
// Get Tags used for Upload Form
|
|
||||||
Route::get('/admin/tags', [AdminApiController::class, 'getTags'])->name('admin.tags');
|
|
||||||
Route::get('/admin/studios', [AdminApiController::class, 'getStudios'])->name('admin.studios');
|
|
||||||
|
|
||||||
// Get Tags for editing Episode
|
|
||||||
Route::get('/admin/tags/{episode_id}', [AdminApiController::class, 'getEpisodeTags'])->name('admin.tags.episode');
|
|
||||||
Route::get('/admin/studio/{episode_id}', [AdminApiController::class, 'getEpisodeStudio'])->name('admin.studio.episode');
|
|
||||||
|
|
||||||
// Subtitles
|
|
||||||
Route::get('/admin/subtitles/{episode_id}', [AdminApiController::class, 'getSubtitles'])->name('admin.subtitles');
|
|
||||||
Route::post('/admin/add-new-subtitle', [App\Http\Controllers\Admin\SubtitleController::class, 'store'])->name('admin.add.new.subtitle');
|
|
||||||
Route::post('/admin/update-subtitles', [App\Http\Controllers\Admin\SubtitleController::class, 'update'])->name('admin.update.subtitles');
|
|
||||||
});
|
|
||||||
|
|
||||||
require __DIR__.'/auth.php';
|
require __DIR__.'/auth.php';
|
||||||
|
|||||||
Reference in New Issue
Block a user