Compare commits
52 Commits
5b4d3d435e
..
main
| Author | SHA1 | Date | |
|---|---|---|---|
| f8022b3f18 | |||
| 57d1ec34c3 | |||
| 81639aaabf | |||
| 5dc1bff60c | |||
| 2f3f0edc30 | |||
| a71b2976af | |||
| 2c016274ab | |||
| 5ba0a55316 | |||
| a6fe34a0d1 | |||
| bb53e06c69 | |||
| 5cae5dc658 | |||
| 356d07365f | |||
| 3574d20fae | |||
| 9fc9e8ed10 | |||
| f5c706b587 | |||
| cbea71d9ae | |||
| 64a621173c | |||
| 839779b82e | |||
| 112cf9433e | |||
| 26a6500fca | |||
| d8cf70e747 | |||
| 0d4545c2ab | |||
| 900103e1c2 | |||
| d4c90976f8 | |||
| 72263127df | |||
| 6d3de59929 | |||
| ddb1bc2d14 | |||
| 5f3874a233 | |||
| ba3650899e | |||
| 904604fcfb | |||
| b7b34b503c | |||
| 4928733383 | |||
| 6340302ac6 | |||
| c1829ba7bd | |||
| 0b155bbb80 | |||
| 9f959efa14 | |||
| 38e3346dc3 | |||
| 09c08f3fea | |||
| 75f631c3e6 | |||
| fdf26604f3 | |||
| 59cb39ca77 | |||
| 62647be75c | |||
| de6efb877c | |||
| 2151d69791 | |||
| 05d4ef1bdb | |||
| 8ae9eaaadb | |||
| 361b511c3e | |||
| 1bc505057f | |||
| a78b1c41ac | |||
| 2480c5b309 | |||
| 4fc11d7329 | |||
| f3e5100d5d |
@@ -3,11 +3,10 @@
|
||||
namespace App\Console\Commands;
|
||||
|
||||
use App\Models\PopularDaily;
|
||||
use App\Models\PopularWeekly;
|
||||
use App\Models\PopularMonthly;
|
||||
|
||||
use Illuminate\Support\Carbon;
|
||||
use App\Models\PopularWeekly;
|
||||
use Illuminate\Console\Command;
|
||||
use Illuminate\Support\Carbon;
|
||||
|
||||
class AutoStats extends Command
|
||||
{
|
||||
|
||||
@@ -4,7 +4,6 @@ namespace App\Console\Commands;
|
||||
|
||||
use App\Models\Episode;
|
||||
use App\Models\Hentai;
|
||||
|
||||
use Illuminate\Console\Command;
|
||||
use Illuminate\Support\Carbon;
|
||||
use Spatie\Sitemap\Sitemap;
|
||||
@@ -17,7 +16,7 @@ class GenerateSitemap extends Command
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $signature = 'sitemap:generate';
|
||||
protected $signature = 'app:generate-sitemap';
|
||||
|
||||
/**
|
||||
* The console command description.
|
||||
|
||||
@@ -2,9 +2,8 @@
|
||||
|
||||
namespace App\Console\Commands;
|
||||
|
||||
use App\Models\Downloads;
|
||||
use App\Jobs\GetFileSizeFromCDN;
|
||||
|
||||
use App\Models\Downloads;
|
||||
use Illuminate\Console\Command;
|
||||
|
||||
class GetFileSize extends Command
|
||||
|
||||
@@ -4,9 +4,8 @@ namespace App\Console\Commands;
|
||||
|
||||
use App\Models\User;
|
||||
use App\Models\UserDownload;
|
||||
|
||||
use Illuminate\Support\Carbon;
|
||||
use Illuminate\Console\Command;
|
||||
use Illuminate\Support\Carbon;
|
||||
|
||||
class ResetUserDownloads extends Command
|
||||
{
|
||||
|
||||
@@ -0,0 +1,109 @@
|
||||
<?php
|
||||
|
||||
namespace App\Console\Commands;
|
||||
|
||||
use App\Enums\UserRole;
|
||||
use App\Models\User;
|
||||
use Illuminate\Console\Command;
|
||||
use Illuminate\Support\Facades\Crypt;
|
||||
use Illuminate\Support\Facades\Http;
|
||||
use Illuminate\Contracts\Encryption\DecryptException;
|
||||
use Illuminate\Support\Facades\Log;
|
||||
|
||||
class SyncSubscriptionKeys extends Command
|
||||
{
|
||||
/**
|
||||
* The name and signature of the console command.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $signature = 'app:sync-subscription-keys';
|
||||
|
||||
/**
|
||||
* The console command description.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $description = 'Sync local users against active subscription keys';
|
||||
|
||||
/**
|
||||
* Execute the console command.
|
||||
*/
|
||||
public function handle()
|
||||
{
|
||||
$endpoint = config('services.subscription_service_host');
|
||||
if (!$endpoint) {
|
||||
$this->error('Missing endpoint.');
|
||||
return self::FAILURE;
|
||||
}
|
||||
|
||||
$response = Http::asJson()
|
||||
->acceptJson()
|
||||
->timeout(20)
|
||||
->retry(3, 1000)
|
||||
->post($endpoint.'/api/membership/keys', [
|
||||
'payload' => base64_encode(Crypt::encryptString('get-active-keys')),
|
||||
]);
|
||||
|
||||
if (! $response->successful()) {
|
||||
$this->error('Subscription API request failed: HTTP ' . $response->status());
|
||||
return self::FAILURE;
|
||||
}
|
||||
|
||||
try {
|
||||
$decrypted = Crypt::decryptString(base64_decode($response->json('payload')));
|
||||
$activeKeys = json_decode($decrypted, true, flags: JSON_THROW_ON_ERROR);
|
||||
} catch (DecryptException $e) {
|
||||
$this->error('Could not decrypt API response.');
|
||||
return self::FAILURE;
|
||||
} catch (\JsonException $e) {
|
||||
$this->error('API returned invalid JSON.');
|
||||
return self::FAILURE;
|
||||
}
|
||||
|
||||
if (! is_array($activeKeys)) {
|
||||
$this->error('API response payload was not an array.');
|
||||
return self::FAILURE;
|
||||
}
|
||||
|
||||
$activeKeys = collect($activeKeys)
|
||||
->filter(fn ($key) => is_string($key) && $key !== '')
|
||||
->values()
|
||||
->all();
|
||||
|
||||
$this->markInactiveUsers($activeKeys);
|
||||
$this->markActiveUsers($activeKeys);
|
||||
|
||||
return self::SUCCESS;
|
||||
}
|
||||
|
||||
private function markInactiveUsers(array $activeKeys)
|
||||
{
|
||||
User::query()
|
||||
->whereNotNull('subscription_key')
|
||||
->whereNotIn('subscription_key', $activeKeys)
|
||||
->chunk(100, function ($users) {
|
||||
foreach($users as $user) {
|
||||
if ($user->hasRole(UserRole::SUPPORTER)) {
|
||||
Log::info("Removed Supporter Role from {$user->name}");
|
||||
$user->removeRole(UserRole::SUPPORTER);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private function markActiveUsers(array $activeKeys)
|
||||
{
|
||||
User::query()
|
||||
->whereNotNull('subscription_key')
|
||||
->whereIn('subscription_key', $activeKeys)
|
||||
->chunk(100, function ($users) {
|
||||
foreach($users as $user) {
|
||||
if (!$user->hasRole(UserRole::SUPPORTER)) {
|
||||
Log::info("Added Supporter Role for {$user->name}");
|
||||
$user->addRole(UserRole::SUPPORTER);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
+18
-17
@@ -5,21 +5,20 @@ namespace App\Helpers;
|
||||
use App\Models\Comment;
|
||||
use App\Models\Episode;
|
||||
use App\Models\Hentai;
|
||||
use App\Models\PopularDaily;
|
||||
use App\Models\PopularMonthly;
|
||||
use App\Models\PopularWeekly;
|
||||
use App\Models\PopularDaily;
|
||||
|
||||
use Conner\Tagging\Model\Tag;
|
||||
|
||||
use Illuminate\Support\Facades\DB;
|
||||
use Illuminate\Support\Facades\Cache;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
|
||||
class CacheHelper
|
||||
{
|
||||
public static function getRecentlyReleased(bool $guest)
|
||||
{
|
||||
$guestString = $guest ? 'guest' : 'authed';
|
||||
return Cache::remember("recently_released_".$guestString, now()->addMinutes(60), function () use ($guest) {
|
||||
|
||||
return Cache::remember('recently_released_'.$guestString, now()->addMinutes(60), function () use ($guest) {
|
||||
return Episode::with('gallery')
|
||||
->when($guest, fn ($query) => $query->withoutTags(['loli', 'shota']))
|
||||
->orderBy('release_date', 'desc')
|
||||
@@ -31,7 +30,8 @@ class CacheHelper
|
||||
public static function getRecentlyUploaded(bool $guest)
|
||||
{
|
||||
$guestString = $guest ? 'guest' : 'authed';
|
||||
return Cache::remember("recently_uploaded".$guestString, now()->addMinutes(5), function () use ($guest) {
|
||||
|
||||
return Cache::remember('recently_uploaded'.$guestString, now()->addMinutes(5), function () use ($guest) {
|
||||
return Episode::with('gallery')
|
||||
->when($guest, fn ($query) => $query->withoutTags(['loli', 'shota']))
|
||||
->orderBy('created_at', 'desc')
|
||||
@@ -42,21 +42,21 @@ class CacheHelper
|
||||
|
||||
public static function getTotalViewCount()
|
||||
{
|
||||
return Cache::remember("total_view_count", now()->addMinutes(60), function () {
|
||||
return Cache::remember('total_view_count', now()->addMinutes(60), function () {
|
||||
return Episode::sum('view_count');
|
||||
});
|
||||
}
|
||||
|
||||
public static function getTotalEpisodeCount()
|
||||
{
|
||||
return Cache::remember("total_episode_count", now()->addMinutes(60), function () {
|
||||
return Cache::remember('total_episode_count', now()->addMinutes(60), function () {
|
||||
return Episode::count();
|
||||
});
|
||||
}
|
||||
|
||||
public static function getTotalHentaiCount()
|
||||
{
|
||||
return Cache::remember("total_hentai_count", now()->addMinutes(60), function () {
|
||||
return Cache::remember('total_hentai_count', now()->addMinutes(60), function () {
|
||||
return Hentai::count();
|
||||
});
|
||||
}
|
||||
@@ -64,7 +64,8 @@ class CacheHelper
|
||||
public static function getPopularAllTime(bool $guest)
|
||||
{
|
||||
$guestString = $guest ? 'guest' : 'authed';
|
||||
return Cache::remember("top_hentai_alltime".$guestString, now()->addMinutes(360), function () use ($guest) {
|
||||
|
||||
return Cache::remember('top_hentai_alltime'.$guestString, now()->addMinutes(360), function () use ($guest) {
|
||||
return Episode::with('gallery')
|
||||
->when($guest, fn ($query) => $query->withoutTags(['loli', 'shota']))
|
||||
->orderBy('view_count', 'desc')
|
||||
@@ -75,7 +76,7 @@ class CacheHelper
|
||||
|
||||
public static function getPopularMonthly()
|
||||
{
|
||||
return Cache::remember("top_hentai_monthly", now()->addMinutes(360), function () {
|
||||
return Cache::remember('top_hentai_monthly', now()->addMinutes(360), function () {
|
||||
return PopularMonthly::groupBy('episode_id')
|
||||
->select('episode_id', DB::raw('count(*) as total'))
|
||||
->with('episode.gallery')
|
||||
@@ -87,7 +88,7 @@ class CacheHelper
|
||||
|
||||
public static function getPopularWeekly()
|
||||
{
|
||||
return Cache::remember("top_hentai_weekly", now()->addMinutes(360), function () {
|
||||
return Cache::remember('top_hentai_weekly', now()->addMinutes(360), function () {
|
||||
return PopularWeekly::groupBy('episode_id')
|
||||
->select('episode_id', DB::raw('count(*) as total'))
|
||||
->with('episode.gallery')
|
||||
@@ -100,7 +101,7 @@ class CacheHelper
|
||||
|
||||
public static function getPopularDaily()
|
||||
{
|
||||
return Cache::remember("top_hentai_daily", now()->addMinutes(30), function () {
|
||||
return Cache::remember('top_hentai_daily', now()->addMinutes(30), function () {
|
||||
return PopularDaily::groupBy('episode_id')
|
||||
->select('episode_id', DB::raw('count(*) as total'))
|
||||
->with('episode.gallery')
|
||||
@@ -112,22 +113,22 @@ class CacheHelper
|
||||
|
||||
public static function getMostLikes()
|
||||
{
|
||||
return Cache::remember("top_likes", now()->addMinutes(30), function () {
|
||||
return Cache::remember('top_likes', now()->addMinutes(30), function () {
|
||||
return DB::table('markable_likes')->groupBy('markable_id')->select('markable_id', DB::raw('count(*) as total'))->orderBy('total', 'desc')->limit(16)->get();
|
||||
});
|
||||
}
|
||||
|
||||
public static function getAllTags()
|
||||
{
|
||||
return Cache::remember("all_tags", now()->addMinutes(10080), function () {
|
||||
return Cache::remember('all_tags', now()->addMinutes(10080), function () {
|
||||
return Tag::where('count', '>', 0)->orderBy('slug', 'ASC')->get();
|
||||
});
|
||||
}
|
||||
|
||||
public static function getLatestComments()
|
||||
{
|
||||
return Cache::remember("latest_comments", now()->addMinutes(60), function () {
|
||||
return Comment::latest()->take(10)->get();
|
||||
return Cache::remember('latest_comments', now()->addMinutes(60), function () {
|
||||
return Comment::with('user')->latest()->take(10)->get();
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,102 @@
|
||||
<?php
|
||||
|
||||
namespace App\Helpers;
|
||||
|
||||
use Illuminate\Support\Facades\Auth;
|
||||
use Illuminate\Support\Facades\Cache;
|
||||
use Conner\Tagging\Model\Tag;
|
||||
|
||||
class FilterCategories
|
||||
{
|
||||
public static function getFilterCategories()
|
||||
{
|
||||
$taglist = Cache::remember(
|
||||
'searchtags',
|
||||
300,
|
||||
fn () => Tag::where('count', '>', 0)
|
||||
->orderBy('slug')
|
||||
->get(),
|
||||
);
|
||||
|
||||
$appearances = [
|
||||
'Loli',
|
||||
'Shota',
|
||||
'Milf',
|
||||
'Futanari',
|
||||
'Big Boobs',
|
||||
'Small Boobs',
|
||||
'Dark Skin',
|
||||
'Cosplay',
|
||||
'Elf',
|
||||
'Maid',
|
||||
'Nekomimi',
|
||||
'Nurse',
|
||||
'School Girl',
|
||||
'Succubus',
|
||||
'Teacher',
|
||||
'Trap',
|
||||
'Pregnant',
|
||||
'Glasses',
|
||||
'Swim Suit',
|
||||
'Ugly Bastard',
|
||||
'Monster',
|
||||
];
|
||||
|
||||
$types = [
|
||||
'3D',
|
||||
'4K',
|
||||
'48Fps',
|
||||
'4K 48Fps',
|
||||
'Censored',
|
||||
'Uncensored',
|
||||
'Comedy',
|
||||
'Fantasy',
|
||||
'Horror',
|
||||
'Vanilla',
|
||||
'Ntr',
|
||||
'Pov',
|
||||
'Filmed',
|
||||
'X-Ray',
|
||||
];
|
||||
|
||||
$actions = [
|
||||
'Anal',
|
||||
'Bdsm',
|
||||
'Facial',
|
||||
'Blow Job',
|
||||
'Boob Job',
|
||||
'Foot Job',
|
||||
'Hand Job',
|
||||
'Rimjob',
|
||||
'Inflation',
|
||||
'Masturbation',
|
||||
'Public Sex',
|
||||
'Rape',
|
||||
'Reverse Rape',
|
||||
'Threesome',
|
||||
'Orgy',
|
||||
'Gangbang',
|
||||
];
|
||||
|
||||
$excluded = [...$appearances, ...$types, ...$actions];
|
||||
|
||||
$categories = [
|
||||
'Genres' => $taglist
|
||||
->reject(fn ($tag) => in_array($tag->name, $excluded))
|
||||
->pluck('name')
|
||||
->toArray(),
|
||||
|
||||
'Actions' => $actions,
|
||||
|
||||
'Appearance' => collect($appearances)
|
||||
->reject(function ($tag) {
|
||||
return Auth::guest() && in_array($tag, ['Loli', 'Shota']);
|
||||
})
|
||||
->toArray(),
|
||||
|
||||
'Types' => $types,
|
||||
];
|
||||
|
||||
return $categories;
|
||||
}
|
||||
}
|
||||
@@ -8,7 +8,7 @@ class GitHelper
|
||||
{
|
||||
public static function shortCommit()
|
||||
{
|
||||
return Cache::remember("git_commit", now()->addMinutes(60), function () {
|
||||
return Cache::remember('git_commit', now()->addMinutes(60), function () {
|
||||
try {
|
||||
return trim(exec('git rev-parse --short HEAD'));
|
||||
} catch (\Exception $e) {
|
||||
|
||||
@@ -4,14 +4,16 @@ namespace App\Http\Controllers\Admin;
|
||||
|
||||
use App\Http\Controllers\Controller;
|
||||
use App\Models\Alert;
|
||||
use Illuminate\Http\RedirectResponse;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\View\View;
|
||||
|
||||
class AlertController extends Controller
|
||||
{
|
||||
/**
|
||||
* Display alert index page
|
||||
*/
|
||||
public function index(): \Illuminate\View\View
|
||||
public function index(): View
|
||||
{
|
||||
return view('admin.alert.index');
|
||||
}
|
||||
@@ -19,7 +21,7 @@ class AlertController extends Controller
|
||||
/**
|
||||
* Create Alert.
|
||||
*/
|
||||
public function store(Request $request): \Illuminate\Http\RedirectResponse
|
||||
public function store(Request $request): RedirectResponse
|
||||
{
|
||||
$validated = $request->validate([
|
||||
'message' => 'required|string|max:255',
|
||||
@@ -39,7 +41,7 @@ class AlertController extends Controller
|
||||
/**
|
||||
* Delete Alert.
|
||||
*/
|
||||
public function delete(int $alert_id): \Illuminate\Http\RedirectResponse
|
||||
public function delete(int $alert_id): RedirectResponse
|
||||
{
|
||||
Alert::where('id', $alert_id)->delete();
|
||||
|
||||
|
||||
@@ -3,13 +3,14 @@
|
||||
namespace App\Http\Controllers\Admin;
|
||||
|
||||
use App\Http\Controllers\Controller;
|
||||
use Illuminate\View\View;
|
||||
|
||||
class CommentsController extends Controller
|
||||
{
|
||||
/**
|
||||
* Display Comments Page.
|
||||
*/
|
||||
public function index(): \Illuminate\View\View
|
||||
public function index(): View
|
||||
{
|
||||
return view('admin.comments.index');
|
||||
}
|
||||
|
||||
@@ -4,25 +4,27 @@ namespace App\Http\Controllers\Admin;
|
||||
|
||||
use App\Http\Controllers\Controller;
|
||||
use App\Models\Contact;
|
||||
use Illuminate\Http\RedirectResponse;
|
||||
use Illuminate\View\View;
|
||||
|
||||
class ContactController extends Controller
|
||||
{
|
||||
/**
|
||||
* Display Contact Page.
|
||||
*/
|
||||
public function index(): \Illuminate\View\View
|
||||
public function index(): View
|
||||
{
|
||||
$contacts = Contact::orderBy('created_at', 'DESC')->get();
|
||||
|
||||
return view('admin.contact.index', [
|
||||
'contacts' => $contacts
|
||||
'contacts' => $contacts,
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete Contact.
|
||||
*/
|
||||
public function delete(int $contact_id): \Illuminate\Http\RedirectResponse
|
||||
public function delete(int $contact_id): RedirectResponse
|
||||
{
|
||||
Contact::where('id', $contact_id)->delete();
|
||||
|
||||
|
||||
@@ -2,19 +2,22 @@
|
||||
|
||||
namespace App\Http\Controllers\Admin;
|
||||
|
||||
use App\Enums\UserRole;
|
||||
use App\Http\Controllers\Controller;
|
||||
use App\Models\Episode;
|
||||
|
||||
use App\Jobs\DiscordReleaseNotification;
|
||||
use App\Models\Episode;
|
||||
use App\Services\DownloadService;
|
||||
use App\Services\EpisodeService;
|
||||
use App\Services\GalleryService;
|
||||
use Illuminate\Http\RedirectResponse;
|
||||
use Illuminate\Http\Request;
|
||||
|
||||
class EpisodeController extends Controller
|
||||
{
|
||||
protected EpisodeService $episodeService;
|
||||
|
||||
protected GalleryService $galleryService;
|
||||
|
||||
protected DownloadService $downloadService;
|
||||
|
||||
public function __construct(
|
||||
@@ -30,7 +33,7 @@ class EpisodeController extends Controller
|
||||
/**
|
||||
* Add Episode to existing series
|
||||
*/
|
||||
public function store(Request $request): \Illuminate\Http\RedirectResponse
|
||||
public function store(Request $request): RedirectResponse
|
||||
{
|
||||
$referenceEpisode = Episode::with('hentai')->where('id', $request->input('episode_id'))->firstOrFail();
|
||||
$episodeNumber = $referenceEpisode->hentai->episodes()->count() + 1;
|
||||
@@ -43,7 +46,7 @@ class EpisodeController extends Controller
|
||||
|
||||
// Discord Alert
|
||||
if ($request->has('censored')) {
|
||||
DiscordReleaseNotification::dispatch($referenceEpisode->title." - ".$episodeNumber, 'release-censored');
|
||||
DiscordReleaseNotification::dispatch($referenceEpisode->title.' - '.$episodeNumber, 'release-censored');
|
||||
} else {
|
||||
DiscordReleaseNotification::dispatch($episode->slug, 'release');
|
||||
}
|
||||
@@ -51,16 +54,27 @@ class EpisodeController extends Controller
|
||||
cache()->flush();
|
||||
|
||||
return to_route('hentai.index', [
|
||||
'title' => $episode->slug
|
||||
'title' => $episode->slug,
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Edit Episode
|
||||
*/
|
||||
public function update(Request $request): \Illuminate\Http\RedirectResponse
|
||||
public function update(Request $request): RedirectResponse
|
||||
{
|
||||
$episode = Episode::with('hentai')->where('id', $request->input('episode_id'))->firstOrFail();
|
||||
|
||||
if ($request->user()->hasRole(UserRole::MODERATOR)) {
|
||||
$this->episodeService->updateEpisodeModerator($request, $episode->id);
|
||||
|
||||
cache()->flush();
|
||||
|
||||
return to_route('hentai.index', [
|
||||
'title' => $episode->slug,
|
||||
]);
|
||||
}
|
||||
|
||||
$studio = $this->episodeService->getOrCreateStudio(json_decode($request->input('studio'))[0]->value);
|
||||
|
||||
$oldinterpolated = $episode->interpolated;
|
||||
@@ -87,7 +101,7 @@ class EpisodeController extends Controller
|
||||
cache()->flush();
|
||||
|
||||
return to_route('hentai.index', [
|
||||
'title' => $episode->slug
|
||||
'title' => $episode->slug,
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,18 +3,21 @@
|
||||
namespace App\Http\Controllers\Admin;
|
||||
|
||||
use App\Http\Controllers\Controller;
|
||||
use App\Models\Hentai;
|
||||
|
||||
use App\Jobs\DiscordReleaseNotification;
|
||||
use App\Models\Hentai;
|
||||
use App\Services\DownloadService;
|
||||
use App\Services\EpisodeService;
|
||||
use App\Services\GalleryService;
|
||||
use Illuminate\Http\RedirectResponse;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\View\View;
|
||||
|
||||
class ReleaseController extends Controller
|
||||
{
|
||||
protected EpisodeService $episodeService;
|
||||
|
||||
protected GalleryService $galleryService;
|
||||
|
||||
protected DownloadService $downloadService;
|
||||
|
||||
public function __construct(
|
||||
@@ -30,7 +33,7 @@ class ReleaseController extends Controller
|
||||
/**
|
||||
* Display release page
|
||||
*/
|
||||
public function index(): \Illuminate\View\View
|
||||
public function index(): View
|
||||
{
|
||||
return view('admin.release.create');
|
||||
}
|
||||
@@ -38,7 +41,7 @@ class ReleaseController extends Controller
|
||||
/**
|
||||
* Upload New Hentai with One or Multipe Episodes
|
||||
*/
|
||||
public function store(Request $request): \Illuminate\Http\RedirectResponse
|
||||
public function store(Request $request): RedirectResponse
|
||||
{
|
||||
// Create new Hentai or find existing one
|
||||
$slug = $this->episodeService->generateSlug($request->input('title'));
|
||||
|
||||
@@ -3,22 +3,22 @@
|
||||
namespace App\Http\Controllers\Admin;
|
||||
|
||||
use App\Http\Controllers\Controller;
|
||||
|
||||
use App\Models\SiteBackground;
|
||||
|
||||
use Illuminate\Http\RedirectResponse;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
use Illuminate\Support\Facades\File;
|
||||
use Illuminate\Support\Facades\Log;
|
||||
use Intervention\Image\Laravel\Facades\Image;
|
||||
use Illuminate\View\View;
|
||||
use Intervention\Image\Encoders\WebpEncoder;
|
||||
use Intervention\Image\Laravel\Facades\Image;
|
||||
|
||||
class SiteBackgroundController extends Controller
|
||||
{
|
||||
/**
|
||||
* Display admin index page
|
||||
*/
|
||||
public function index(): \Illuminate\View\View
|
||||
public function index(): View
|
||||
{
|
||||
return view('admin.background.index', [
|
||||
'images' => SiteBackground::all(),
|
||||
@@ -28,7 +28,7 @@ class SiteBackgroundController extends Controller
|
||||
/**
|
||||
* Create new site backgrounds
|
||||
*/
|
||||
public function create(Request $request): \Illuminate\Http\RedirectResponse
|
||||
public function create(Request $request): RedirectResponse
|
||||
{
|
||||
$request->validate([
|
||||
'images' => 'required',
|
||||
@@ -44,7 +44,7 @@ class SiteBackgroundController extends Controller
|
||||
$bg = SiteBackground::create(array_merge(
|
||||
$request->only(['date_start', 'date_end']),
|
||||
[
|
||||
'default' => (bool) $request->input('default', false)
|
||||
'default' => (bool) $request->input('default', false),
|
||||
]
|
||||
));
|
||||
|
||||
@@ -55,13 +55,14 @@ class SiteBackgroundController extends Controller
|
||||
|
||||
Image::read($file->getRealPath())
|
||||
->scaleDown(height: $resolution)
|
||||
->encode(new WebpEncoder())
|
||||
->encode(new WebpEncoder)
|
||||
->save(public_path($targetPath));
|
||||
}
|
||||
|
||||
} catch (\Exception $e) {
|
||||
DB::rollBack();
|
||||
Log::error($e->getMessage());
|
||||
|
||||
return redirect()->back();
|
||||
}
|
||||
|
||||
@@ -74,7 +75,7 @@ class SiteBackgroundController extends Controller
|
||||
return redirect()->back();
|
||||
}
|
||||
|
||||
public function update(Request $request): \Illuminate\Http\RedirectResponse
|
||||
public function update(Request $request): RedirectResponse
|
||||
{
|
||||
$request->validate([
|
||||
'id' => 'required|exists:site_backgrounds,id',
|
||||
@@ -85,7 +86,7 @@ class SiteBackgroundController extends Controller
|
||||
SiteBackground::where('id', $request->input('id'))->update(array_merge(
|
||||
$request->only(['date_start', 'date_end']),
|
||||
[
|
||||
'default' => (bool) $request->input('default', false)
|
||||
'default' => (bool) $request->input('default', false),
|
||||
]
|
||||
));
|
||||
|
||||
@@ -97,7 +98,7 @@ class SiteBackgroundController extends Controller
|
||||
/**
|
||||
* Delete backround
|
||||
*/
|
||||
public function delete(Request $request): \Illuminate\Http\RedirectResponse
|
||||
public function delete(Request $request): RedirectResponse
|
||||
{
|
||||
$id = $request->input('id');
|
||||
|
||||
@@ -116,6 +117,7 @@ class SiteBackgroundController extends Controller
|
||||
} catch (\Exception $e) {
|
||||
DB::rollBack();
|
||||
Log::error($e->getMessage());
|
||||
|
||||
return redirect()->back();
|
||||
}
|
||||
|
||||
|
||||
@@ -2,10 +2,11 @@
|
||||
|
||||
namespace App\Http\Controllers\Admin;
|
||||
|
||||
use App\Http\Controllers\Controller;
|
||||
use App\Models\Episode;
|
||||
use App\Models\EpisodeSubtitle;
|
||||
use App\Models\Subtitle;
|
||||
use App\Http\Controllers\Controller;
|
||||
use Illuminate\Http\RedirectResponse;
|
||||
use Illuminate\Http\Request;
|
||||
|
||||
class SubtitleController extends Controller
|
||||
@@ -13,7 +14,7 @@ class SubtitleController extends Controller
|
||||
/**
|
||||
* Add new Subtitle.
|
||||
*/
|
||||
public function store(Request $request): \Illuminate\Http\RedirectResponse
|
||||
public function store(Request $request): RedirectResponse
|
||||
{
|
||||
$subtitle = Subtitle::create([
|
||||
'name' => $request->name,
|
||||
@@ -32,7 +33,7 @@ class SubtitleController extends Controller
|
||||
/**
|
||||
* Update Episode Subtitles.
|
||||
*/
|
||||
public function update(Request $request): \Illuminate\Http\RedirectResponse
|
||||
public function update(Request $request): RedirectResponse
|
||||
{
|
||||
$episode = Episode::where('id', $request->input('episode_id'))->firstOrFail();
|
||||
|
||||
|
||||
@@ -3,16 +3,17 @@
|
||||
namespace App\Http\Controllers\Admin;
|
||||
|
||||
use App\Enums\UserRole;
|
||||
use App\Models\User;
|
||||
use App\Http\Controllers\Controller;
|
||||
use App\Models\User;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\View\View;
|
||||
|
||||
class UserController extends Controller
|
||||
{
|
||||
/**
|
||||
* Display Users Page.
|
||||
*/
|
||||
public function index(): \Illuminate\View\View
|
||||
public function index(): View
|
||||
{
|
||||
return view('admin.users.index');
|
||||
}
|
||||
@@ -27,7 +28,6 @@ class UserController extends Controller
|
||||
'action' => 'required',
|
||||
]);
|
||||
|
||||
|
||||
$user = User::findOrFail($validated['id']);
|
||||
|
||||
switch ($validated['action']) {
|
||||
|
||||
@@ -3,10 +3,10 @@
|
||||
namespace App\Http\Controllers\Api;
|
||||
|
||||
use App\Helpers\CacheHelper;
|
||||
use App\Http\Controllers\Controller;
|
||||
use App\Models\Episode;
|
||||
use App\Models\Studios;
|
||||
use App\Models\Subtitle;
|
||||
use App\Http\Controllers\Controller;
|
||||
|
||||
class AdminApiController extends Controller
|
||||
{
|
||||
|
||||
@@ -2,13 +2,11 @@
|
||||
|
||||
namespace App\Http\Controllers\Api;
|
||||
|
||||
use App\Http\Controllers\Controller;
|
||||
use App\Models\Downloads;
|
||||
use App\Models\Episode;
|
||||
|
||||
use App\Rules\ValidCaptcha;
|
||||
use Illuminate\Http\Request;
|
||||
use App\Http\Controllers\Controller;
|
||||
|
||||
use GrantHolle\Altcha\Rules\ValidAltcha;
|
||||
|
||||
class DownloadApiController extends Controller
|
||||
{
|
||||
@@ -19,7 +17,7 @@ class DownloadApiController extends Controller
|
||||
{
|
||||
$validated = $request->validate([
|
||||
'episode_id' => ['required'],
|
||||
'captcha' => ['required', new ValidAltcha],
|
||||
'captcha' => ['required', new ValidCaptcha],
|
||||
]);
|
||||
|
||||
$episode = Episode::where('id', $request->input('episode_id'))
|
||||
|
||||
@@ -2,12 +2,11 @@
|
||||
|
||||
namespace App\Http\Controllers\Api;
|
||||
|
||||
use App\Http\Controllers\Controller;
|
||||
use App\Models\Hentai;
|
||||
use App\Models\PopularMonthly;
|
||||
use Carbon\Carbon;
|
||||
|
||||
use Illuminate\Support\Facades\Cache;
|
||||
use App\Http\Controllers\Controller;
|
||||
|
||||
class HentaiApiController extends Controller
|
||||
{
|
||||
|
||||
@@ -3,9 +3,7 @@
|
||||
namespace App\Http\Controllers\Api;
|
||||
|
||||
use App\Http\Controllers\Controller;
|
||||
|
||||
use App\Models\Episode;
|
||||
|
||||
use Illuminate\Http\Request;
|
||||
|
||||
class StreamApiController extends Controller
|
||||
@@ -33,7 +31,7 @@ class StreamApiController extends Controller
|
||||
'stream_url' => $episode->dmca_takedown ? 'stuff/dmca' : $episode->url,
|
||||
'stream_domains' => config('hstream.stream_domain'),
|
||||
'asia_stream_domains' => config('hstream.asia_stream_domain'),
|
||||
'extra_subtitles' => $subtitles
|
||||
'extra_subtitles' => $subtitles,
|
||||
], 200);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,9 +4,8 @@ namespace App\Http\Controllers\Api;
|
||||
|
||||
use App\Helpers\CacheHelper;
|
||||
use App\Http\Controllers\Controller;
|
||||
use Illuminate\Http\Request;
|
||||
|
||||
use Conner\Tagging\Model\Tag;
|
||||
use Illuminate\Http\Request;
|
||||
|
||||
class UserApiController extends Controller
|
||||
{
|
||||
@@ -33,11 +32,10 @@ class UserApiController extends Controller
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
return response()->json([
|
||||
'message' => 'success',
|
||||
'tags' => $tagWhiteList,
|
||||
'usertags' => $tagBlackList
|
||||
'usertags' => $tagBlackList,
|
||||
], 200);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,30 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Controllers\Auth;
|
||||
|
||||
use AltchaOrg\Altcha\Algorithm\Pbkdf2;
|
||||
use AltchaOrg\Altcha\Altcha;
|
||||
use AltchaOrg\Altcha\CreateChallengeOptions;
|
||||
use App\Http\Controllers\Controller;
|
||||
|
||||
class CaptchaController extends Controller
|
||||
{
|
||||
public function create(): array
|
||||
{
|
||||
$pbkdf2 = new Pbkdf2;
|
||||
|
||||
$altcha = new Altcha(
|
||||
hmacSignatureSecret: config('captcha.hmac_key'),
|
||||
);
|
||||
|
||||
// Create challenge
|
||||
$challenge = $altcha->createChallenge(new CreateChallengeOptions(
|
||||
algorithm: $pbkdf2,
|
||||
cost: 5000,
|
||||
counter: random_int(5000, 10000),
|
||||
expiresAt: time() + 600,
|
||||
));
|
||||
|
||||
return get_object_vars($challenge);
|
||||
}
|
||||
}
|
||||
@@ -3,11 +3,9 @@
|
||||
namespace App\Http\Controllers\Auth;
|
||||
|
||||
use App\Enums\UserRole;
|
||||
use App\Models\User;
|
||||
|
||||
use App\Http\Controllers\Controller;
|
||||
use App\Models\User;
|
||||
use Illuminate\Http\RedirectResponse;
|
||||
use Illuminate\Support\Str;
|
||||
use Illuminate\Support\Facades\Auth;
|
||||
use Illuminate\Support\Facades\Http;
|
||||
use Illuminate\Support\Facades\Log;
|
||||
@@ -90,6 +88,7 @@ class DiscordAuthController extends Controller
|
||||
// User is not in the guild
|
||||
if ($response->status() === 404) {
|
||||
$user->removeRole(UserRole::SUPPORTER);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -114,6 +113,7 @@ class DiscordAuthController extends Controller
|
||||
if (! $hasSupporterRole) {
|
||||
// Remove role if not found
|
||||
$user->removeRole(UserRole::SUPPORTER);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
@@ -11,6 +11,7 @@ use Illuminate\Support\Facades\Hash;
|
||||
use Illuminate\Support\Facades\Password;
|
||||
use Illuminate\Support\Str;
|
||||
use Illuminate\Validation\Rules;
|
||||
use Illuminate\Validation\ValidationException;
|
||||
use Illuminate\View\View;
|
||||
|
||||
class NewPasswordController extends Controller
|
||||
@@ -26,7 +27,7 @@ class NewPasswordController extends Controller
|
||||
/**
|
||||
* Handle an incoming new password request.
|
||||
*
|
||||
* @throws \Illuminate\Validation\ValidationException
|
||||
* @throws ValidationException
|
||||
*/
|
||||
public function store(Request $request): RedirectResponse
|
||||
{
|
||||
|
||||
@@ -16,8 +16,7 @@ class PasswordController extends Controller
|
||||
public function update(Request $request): RedirectResponse
|
||||
{
|
||||
// If user logged in with Discord and has not yet a password, allow to set password
|
||||
if ($request->user()->discord_id && is_null($request->user()->password))
|
||||
{
|
||||
if ($request->user()->discord_id && is_null($request->user()->password)) {
|
||||
$validated = $request->validateWithBag('updatePassword', [
|
||||
'password' => ['required', Password::defaults(), 'confirmed'],
|
||||
]);
|
||||
|
||||
@@ -6,6 +6,7 @@ use App\Http\Controllers\Controller;
|
||||
use Illuminate\Http\RedirectResponse;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Support\Facades\Password;
|
||||
use Illuminate\Validation\ValidationException;
|
||||
use Illuminate\View\View;
|
||||
|
||||
class PasswordResetLinkController extends Controller
|
||||
@@ -21,7 +22,7 @@ class PasswordResetLinkController extends Controller
|
||||
/**
|
||||
* Handle an incoming password reset link request.
|
||||
*
|
||||
* @throws \Illuminate\Validation\ValidationException
|
||||
* @throws ValidationException
|
||||
*/
|
||||
public function store(Request $request): RedirectResponse
|
||||
{
|
||||
|
||||
@@ -4,21 +4,21 @@ namespace App\Http\Controllers\Auth;
|
||||
|
||||
use App\Http\Controllers\Controller;
|
||||
use App\Models\User;
|
||||
use App\Rules\ValidCaptcha;
|
||||
use Illuminate\Auth\Events\Registered;
|
||||
use Illuminate\Http\RedirectResponse;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Support\Facades\Auth;
|
||||
use Illuminate\Support\Facades\Hash;
|
||||
use Illuminate\Validation\Rules;
|
||||
|
||||
use GrantHolle\Altcha\Rules\ValidAltcha;
|
||||
use Illuminate\Validation\ValidationException;
|
||||
|
||||
class RegisteredUserController extends Controller
|
||||
{
|
||||
/**
|
||||
* Handle an incoming registration request.
|
||||
*
|
||||
* @throws \Illuminate\Validation\ValidationException
|
||||
* @throws ValidationException
|
||||
*/
|
||||
public function store(Request $request): RedirectResponse
|
||||
{
|
||||
@@ -26,7 +26,7 @@ class RegisteredUserController extends Controller
|
||||
'name' => ['required', 'string', 'max:255'],
|
||||
'email' => ['required', 'string', 'lowercase', 'email', 'max:255', 'unique:'.User::class],
|
||||
'password' => ['required', 'confirmed', Rules\Password::defaults()],
|
||||
'altcha' => ['required', new ValidAltcha],
|
||||
'altcha' => ['required', new ValidCaptcha],
|
||||
]);
|
||||
|
||||
$user = User::create([
|
||||
|
||||
@@ -3,16 +3,17 @@
|
||||
namespace App\Http\Controllers;
|
||||
|
||||
use App\Models\Contact;
|
||||
use App\Rules\ValidCaptcha;
|
||||
use Illuminate\Http\RedirectResponse;
|
||||
use Illuminate\Http\Request;
|
||||
|
||||
use GrantHolle\Altcha\Rules\ValidAltcha;
|
||||
use Illuminate\View\View;
|
||||
|
||||
class ContactController extends Controller
|
||||
{
|
||||
/**
|
||||
* Display Contact Page.
|
||||
*/
|
||||
public function index(): \Illuminate\View\View
|
||||
public function index(): View
|
||||
{
|
||||
return view('contact.form');
|
||||
}
|
||||
@@ -20,17 +21,17 @@ class ContactController extends Controller
|
||||
/**
|
||||
* Store Contact Submission.
|
||||
*/
|
||||
public function store(Request $request): \Illuminate\Http\RedirectResponse
|
||||
public function store(Request $request): RedirectResponse
|
||||
{
|
||||
$validated = $request->validate([
|
||||
'name' => 'required|max:30',
|
||||
'email' => 'required|max:50',
|
||||
'message' => 'required|max:1000',
|
||||
'subject' => 'required|max:50',
|
||||
'altcha' => ['required', new ValidAltcha],
|
||||
'altcha' => ['required', new ValidCaptcha],
|
||||
]);
|
||||
|
||||
$contact = new Contact();
|
||||
$contact = new Contact;
|
||||
$contact->name = $request->input('name');
|
||||
$contact->email = $request->input('email');
|
||||
$contact->message = $request->input('message');
|
||||
|
||||
@@ -2,32 +2,32 @@
|
||||
|
||||
namespace App\Http\Controllers;
|
||||
|
||||
use App\Models\Episode;
|
||||
use App\Helpers\CacheHelper;
|
||||
use App\Models\Episode;
|
||||
use Illuminate\Http\RedirectResponse;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Support\Facades\Auth;
|
||||
use Illuminate\Support\Facades\Cookie;
|
||||
use Illuminate\View\View;
|
||||
|
||||
class HomeController extends Controller
|
||||
{
|
||||
/**
|
||||
* Display Home Page.
|
||||
*/
|
||||
public function index(): \Illuminate\View\View
|
||||
public function index(): View
|
||||
{
|
||||
$guest = Auth::guest();
|
||||
|
||||
$guestString = $guest ? 'guest' : 'authed';
|
||||
|
||||
$mostLikes = \cache()->remember('mostLikes'.$guestString, 300, fn () =>
|
||||
Episode::with('gallery')
|
||||
$mostLikes = \cache()->remember('mostLikes'.$guestString, 300, fn () => Episode::with('gallery')
|
||||
->when($guest, fn ($query) => $query->withoutTags(['loli', 'shota']))
|
||||
->whereIn('id', function ($query) {
|
||||
$mostLikesIds = CacheHelper::getMostLikes()->pluck('markable_id')->toArray();
|
||||
$query->selectRaw('id')
|
||||
->from('episodes')
|
||||
->whereIn('id', $mostLikesIds)
|
||||
->orderByRaw("FIELD(id, " . implode(',', $mostLikesIds) . ")");
|
||||
->orderByRaw('FIELD(id, '.implode(',', $mostLikesIds).')');
|
||||
})
|
||||
->get()
|
||||
);
|
||||
@@ -47,7 +47,7 @@ class HomeController extends Controller
|
||||
/**
|
||||
* Display Banned Page.
|
||||
*/
|
||||
public function banned(): \Illuminate\View\View
|
||||
public function banned(): View
|
||||
{
|
||||
return view('auth.banned');
|
||||
}
|
||||
@@ -56,7 +56,7 @@ class HomeController extends Controller
|
||||
* Redirects to a random Hentai episode
|
||||
* Done due to performance reasons
|
||||
*/
|
||||
public function random(): \Illuminate\Http\RedirectResponse
|
||||
public function random(): RedirectResponse
|
||||
{
|
||||
$random = Episode::inRandomOrder()
|
||||
->limit(1)
|
||||
@@ -71,7 +71,7 @@ class HomeController extends Controller
|
||||
/**
|
||||
* Display Search Page.
|
||||
*/
|
||||
public function search(): \Illuminate\View\View
|
||||
public function search(): View
|
||||
{
|
||||
return view('search.index');
|
||||
}
|
||||
@@ -79,7 +79,7 @@ class HomeController extends Controller
|
||||
/**
|
||||
* Display Download Search Page.
|
||||
*/
|
||||
public function downloadSearch(): \Illuminate\View\View
|
||||
public function downloadSearch(): View
|
||||
{
|
||||
return view('search.download');
|
||||
}
|
||||
@@ -87,7 +87,7 @@ class HomeController extends Controller
|
||||
/**
|
||||
* Redirect POST Data to GET with Query String.
|
||||
*/
|
||||
public function searchRedirect(Request $request): \Illuminate\Http\RedirectResponse
|
||||
public function searchRedirect(Request $request): RedirectResponse
|
||||
{
|
||||
return redirect()->route('hentai.search', [
|
||||
'search' => $request->input('live-search'),
|
||||
@@ -97,7 +97,7 @@ class HomeController extends Controller
|
||||
/**
|
||||
* Display Stats Page.
|
||||
*/
|
||||
public function stats(): \Illuminate\View\View
|
||||
public function stats(): View
|
||||
{
|
||||
return view('home.stats', [
|
||||
'viewCount' => CacheHelper::getTotalViewCount(),
|
||||
@@ -109,7 +109,7 @@ class HomeController extends Controller
|
||||
/**
|
||||
* Manually set website language
|
||||
*/
|
||||
public function updateLanguage(Request $request): \Illuminate\Http\RedirectResponse
|
||||
public function updateLanguage(Request $request): RedirectResponse
|
||||
{
|
||||
abort_unless(in_array($request->language, config('app.supported_locales'), true), 404);
|
||||
|
||||
|
||||
@@ -5,19 +5,20 @@ namespace App\Http\Controllers;
|
||||
use App\Http\Requests\MatrixRegisterRequest;
|
||||
use App\Services\MatrixRegistrationService;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\View\View;
|
||||
|
||||
class MatrixController extends Controller
|
||||
{
|
||||
/**
|
||||
* Display the user page.
|
||||
*/
|
||||
public function index(Request $request): \Illuminate\View\View
|
||||
public function index(Request $request): View
|
||||
{
|
||||
$rooms = [
|
||||
['name' => '🏠 General', 'description' => 'Our main chat.', 'alias' => 'https://matrix.to/#/#general:hstream.moe'],
|
||||
['name' => '📡 Releases', 'description' => 'Were we @everyone for new releases.', 'alias' => 'https://matrix.to/#/#releases:hstream.moe'],
|
||||
['name' => '👗 NSFW 2D', 'description' => 'Channel for R18 2D Media.', 'alias' => 'https://matrix.to/#/#nsfw:hstream.moe'],
|
||||
['name' => '👗 NSFW IRL', 'description' => 'Channel for R18 IRL Media.', 'alias' => 'https://matrix.to/#/#nsfw-irl:hstream.moe']
|
||||
['name' => '👗 NSFW IRL', 'description' => 'Channel for R18 IRL Media.', 'alias' => 'https://matrix.to/#/#nsfw-irl:hstream.moe'],
|
||||
];
|
||||
|
||||
return view('matrix.index', [
|
||||
@@ -49,7 +50,7 @@ class MatrixController extends Controller
|
||||
} catch (\Exception $e) {
|
||||
return back()
|
||||
->withErrors([
|
||||
'username' => $e->getMessage()
|
||||
'username' => $e->getMessage(),
|
||||
])
|
||||
->withInput();
|
||||
}
|
||||
|
||||
@@ -2,15 +2,16 @@
|
||||
|
||||
namespace App\Http\Controllers;
|
||||
|
||||
use Illuminate\Http\RedirectResponse;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
use Illuminate\View\View;
|
||||
|
||||
class NotificationController extends Controller
|
||||
{
|
||||
/**
|
||||
* Display the user's notification page.
|
||||
*/
|
||||
public function index(Request $request): \Illuminate\View\View
|
||||
public function index(Request $request): View
|
||||
{
|
||||
return view('profile.notifications', [
|
||||
'user' => $request->user(),
|
||||
@@ -21,7 +22,7 @@ class NotificationController extends Controller
|
||||
/**
|
||||
* Delete Notifcation
|
||||
*/
|
||||
public function delete(Request $request): \Illuminate\Http\RedirectResponse
|
||||
public function delete(Request $request): RedirectResponse
|
||||
{
|
||||
$request->validate([
|
||||
'id' => 'required|exists:notifications,id',
|
||||
|
||||
@@ -6,8 +6,10 @@ use App\Models\Episode;
|
||||
use App\Models\Playlist;
|
||||
use App\Models\PlaylistEpisode;
|
||||
use App\Services\PlaylistService;
|
||||
use Illuminate\Http\JsonResponse;
|
||||
use Illuminate\Http\RedirectResponse;
|
||||
use Illuminate\Http\Request;
|
||||
use RealRashid\SweetAlert\Facades\Alert;
|
||||
use Illuminate\View\View;
|
||||
|
||||
class PlaylistController extends Controller
|
||||
{
|
||||
@@ -21,7 +23,7 @@ class PlaylistController extends Controller
|
||||
/**
|
||||
* Display the public playlists page.
|
||||
*/
|
||||
public function index(): \Illuminate\View\View
|
||||
public function index(): View
|
||||
{
|
||||
return view('playlist.index');
|
||||
}
|
||||
@@ -29,7 +31,7 @@ class PlaylistController extends Controller
|
||||
/**
|
||||
* Display public playlist.
|
||||
*/
|
||||
public function show($playlist_id): \Illuminate\View\View
|
||||
public function show($playlist_id): View
|
||||
{
|
||||
if (! is_numeric($playlist_id)) {
|
||||
abort(404);
|
||||
@@ -42,14 +44,13 @@ class PlaylistController extends Controller
|
||||
]);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Display the user's playlists page.
|
||||
*/
|
||||
public function playlists(Request $request): \Illuminate\View\View
|
||||
public function playlists(Request $request): View
|
||||
{
|
||||
$title = 'Delete Playlist!';
|
||||
$text = "Are you sure you want to delete?";
|
||||
$text = 'Are you sure you want to delete?';
|
||||
confirmDelete($title, $text);
|
||||
|
||||
return view('profile.playlists', [
|
||||
@@ -61,7 +62,7 @@ class PlaylistController extends Controller
|
||||
/**
|
||||
* Display user's playlist.
|
||||
*/
|
||||
public function showPlaylist(Request $request, $playlist_id): \Illuminate\View\View
|
||||
public function showPlaylist(Request $request, $playlist_id): View
|
||||
{
|
||||
if (! is_numeric($playlist_id)) {
|
||||
abort(404);
|
||||
@@ -79,13 +80,13 @@ class PlaylistController extends Controller
|
||||
/**
|
||||
* Create user playlist (Form).
|
||||
*/
|
||||
public function createPlaylist(Request $request): \Illuminate\Http\RedirectResponse
|
||||
public function createPlaylist(Request $request): RedirectResponse
|
||||
{
|
||||
$validated = $request->validate([
|
||||
'name' => 'required|max:30',
|
||||
]);
|
||||
|
||||
$playlist = new Playlist();
|
||||
$playlist = new Playlist;
|
||||
$playlist->user_id = $request->user()->id;
|
||||
$playlist->name = $request->input('name');
|
||||
$playlist->is_private = $request->input('visiblity') === 'private';
|
||||
@@ -97,7 +98,7 @@ class PlaylistController extends Controller
|
||||
/**
|
||||
* Delete user playlist.
|
||||
*/
|
||||
public function deletePlaylist(Request $request, $playlist_id): \Illuminate\Http\RedirectResponse
|
||||
public function deletePlaylist(Request $request, $playlist_id): RedirectResponse
|
||||
{
|
||||
if (! is_numeric($playlist_id)) {
|
||||
abort(404);
|
||||
@@ -117,7 +118,7 @@ class PlaylistController extends Controller
|
||||
/**
|
||||
* Delete episode from playlist.
|
||||
*/
|
||||
public function deleteEpisodeFromPlaylist(Request $request): \Illuminate\Http\JsonResponse
|
||||
public function deleteEpisodeFromPlaylist(Request $request): JsonResponse
|
||||
{
|
||||
if (! is_numeric($request->input('playlist')) || ! is_numeric($request->input('episode'))) {
|
||||
return response()->json([
|
||||
@@ -145,13 +146,13 @@ class PlaylistController extends Controller
|
||||
/**
|
||||
* Add to user playlist (API).
|
||||
*/
|
||||
public function addPlaylistApi(Request $request): \Illuminate\Http\JsonResponse
|
||||
public function addPlaylistApi(Request $request): JsonResponse
|
||||
{
|
||||
$user = $request->user();
|
||||
|
||||
$validated = $request->validate([
|
||||
'playlist' => 'required|max:30',
|
||||
'episode_id' => 'required'
|
||||
'episode_id' => 'required',
|
||||
]);
|
||||
|
||||
$playlist = Playlist::where('user_id', $user->id)->where('id', $request->input('playlist'))->firstOrFail();
|
||||
@@ -161,7 +162,7 @@ class PlaylistController extends Controller
|
||||
$exists = PlaylistEpisode::where('playlist_id', $playlist->id)->where('episode_id', $episode->id)->exists();
|
||||
if ($exists) {
|
||||
return response()->json([
|
||||
'message' => 'already-added'
|
||||
'message' => 'already-added',
|
||||
], 200);
|
||||
}
|
||||
|
||||
@@ -175,20 +176,20 @@ class PlaylistController extends Controller
|
||||
]);
|
||||
|
||||
return response()->json([
|
||||
'message' => 'success'
|
||||
'message' => 'success',
|
||||
], 200);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create user playlist (API).
|
||||
*/
|
||||
public function createPlaylistApi(Request $request): \Illuminate\Http\JsonResponse
|
||||
public function createPlaylistApi(Request $request): JsonResponse
|
||||
{
|
||||
$validated = $request->validate([
|
||||
'name' => 'required|max:30',
|
||||
]);
|
||||
|
||||
$playlist = new Playlist();
|
||||
$playlist = new Playlist;
|
||||
$playlist->user_id = $request->user()->id;
|
||||
$playlist->name = $request->input('name');
|
||||
$playlist->is_private = $request->input('visiblity') === 'private';
|
||||
@@ -196,7 +197,7 @@ class PlaylistController extends Controller
|
||||
|
||||
return response()->json([
|
||||
'message' => 'success',
|
||||
'playlist_id' => $playlist->id
|
||||
'playlist_id' => $playlist->id,
|
||||
], 200);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,22 +2,21 @@
|
||||
|
||||
namespace App\Http\Controllers;
|
||||
|
||||
use App\Http\Requests\ProfileUpdateRequest;
|
||||
use App\Models\Episode;
|
||||
use App\Models\User;
|
||||
use App\Http\Requests\ProfileUpdateRequest;
|
||||
use Conner\Tagging\Model\Tag;
|
||||
use Illuminate\Http\RedirectResponse;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Support\Str;
|
||||
use Illuminate\Http\UploadedFile;
|
||||
use Illuminate\Support\Facades\Auth;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
use Illuminate\Support\Facades\Redirect;
|
||||
use Illuminate\Support\Facades\Storage;
|
||||
use Illuminate\Support\Str;
|
||||
use Illuminate\View\View;
|
||||
|
||||
use Intervention\Image\Laravel\Facades\Image;
|
||||
|
||||
use Conner\Tagging\Model\Tag;
|
||||
|
||||
class ProfileController extends Controller
|
||||
{
|
||||
/**
|
||||
@@ -96,6 +95,16 @@ class ProfileController extends Controller
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Display the user's subscription page.
|
||||
*/
|
||||
public function subscription(Request $request): View
|
||||
{
|
||||
return view('profile.subscription', [
|
||||
'user' => $request->user(),
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Update user settings.
|
||||
*/
|
||||
@@ -121,6 +130,7 @@ class ProfileController extends Controller
|
||||
if (! $tags) {
|
||||
$user->tag_blacklist = null;
|
||||
$user->save();
|
||||
|
||||
return Redirect::route('profile.settings')->with('status', 'blacklist-updated');
|
||||
}
|
||||
|
||||
@@ -139,7 +149,7 @@ class ProfileController extends Controller
|
||||
/**
|
||||
* Delete the user's account.
|
||||
*/
|
||||
public function destroy(Request $request): \Illuminate\Http\RedirectResponse
|
||||
public function destroy(Request $request): RedirectResponse
|
||||
{
|
||||
$user = $request->user();
|
||||
|
||||
@@ -174,11 +184,11 @@ class ProfileController extends Controller
|
||||
/**
|
||||
* Store custom user avatar.
|
||||
*/
|
||||
protected function storeAvatar(\Illuminate\Http\UploadedFile $file, User $user): void
|
||||
protected function storeAvatar(UploadedFile $file, User $user): void
|
||||
{
|
||||
// Create Folder for Image Upload
|
||||
if (! Storage::disk('public')->exists("/images/avatars")) {
|
||||
Storage::disk('public')->makeDirectory("/images/avatars");
|
||||
if (! Storage::disk('public')->exists('/images/avatars')) {
|
||||
Storage::disk('public')->makeDirectory('/images/avatars');
|
||||
}
|
||||
|
||||
// Delete old avatar if it exists
|
||||
@@ -196,5 +206,4 @@ class ProfileController extends Controller
|
||||
|
||||
$user->avatar = $filename;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -2,26 +2,25 @@
|
||||
|
||||
namespace App\Http\Controllers;
|
||||
|
||||
use App\Helpers\CacheHelper;
|
||||
use App\Models\Episode;
|
||||
use App\Models\Gallery;
|
||||
use App\Models\Hentai;
|
||||
use App\Models\Playlist;
|
||||
use App\Models\PlaylistEpisode;
|
||||
use App\Models\Watched;
|
||||
use App\Helpers\CacheHelper;
|
||||
|
||||
use hisorange\BrowserDetect\Facade as Browser;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Support\Carbon;
|
||||
use Illuminate\Support\Facades\Auth;
|
||||
|
||||
use hisorange\BrowserDetect\Facade as Browser;
|
||||
use Illuminate\View\View;
|
||||
|
||||
class StreamController extends Controller
|
||||
{
|
||||
/**
|
||||
* Display Stream Page.
|
||||
*/
|
||||
public function index(Request $request, string $title): \Illuminate\View\View
|
||||
public function index(Request $request, string $title): View
|
||||
{
|
||||
$titleParts = explode('-', $title);
|
||||
if (! is_numeric($titleParts[array_key_last($titleParts)])) {
|
||||
@@ -37,7 +36,6 @@ class StreamController extends Controller
|
||||
]);
|
||||
}
|
||||
|
||||
|
||||
$episode = Episode::where('slug', $title)->firstOrFail();
|
||||
$gallery = Gallery::where('episode_id', $episode->id)->get();
|
||||
$moreEpisodes = Episode::with(['gallery', 'studio'])->where('hentai_id', $episode->hentai_id)->whereNot('id', $episode->id)->get();
|
||||
|
||||
+56
-29
@@ -2,7 +2,34 @@
|
||||
|
||||
namespace App\Http;
|
||||
|
||||
use App\Http\Middleware\Authenticate;
|
||||
use App\Http\Middleware\EncryptCookies;
|
||||
use App\Http\Middleware\IsAdmin;
|
||||
use App\Http\Middleware\IsBanned;
|
||||
use App\Http\Middleware\IsModerator;
|
||||
use App\Http\Middleware\PreventRequestsDuringMaintenance;
|
||||
use App\Http\Middleware\RedirectIfAuthenticated;
|
||||
use App\Http\Middleware\SetLocale;
|
||||
use App\Http\Middleware\TrimStrings;
|
||||
use App\Http\Middleware\TrustProxies;
|
||||
use App\Http\Middleware\ValidateSignature;
|
||||
use App\Http\Middleware\VerifyCsrfToken;
|
||||
use Illuminate\Auth\Middleware\AuthenticateWithBasicAuth;
|
||||
use Illuminate\Auth\Middleware\Authorize;
|
||||
use Illuminate\Auth\Middleware\EnsureEmailIsVerified;
|
||||
use Illuminate\Auth\Middleware\RequirePassword;
|
||||
use Illuminate\Cookie\Middleware\AddQueuedCookiesToResponse;
|
||||
use Illuminate\Foundation\Http\Kernel as HttpKernel;
|
||||
use Illuminate\Foundation\Http\Middleware\ConvertEmptyStringsToNull;
|
||||
use Illuminate\Foundation\Http\Middleware\HandlePrecognitiveRequests;
|
||||
use Illuminate\Foundation\Http\Middleware\ValidatePostSize;
|
||||
use Illuminate\Http\Middleware\HandleCors;
|
||||
use Illuminate\Http\Middleware\SetCacheHeaders;
|
||||
use Illuminate\Routing\Middleware\SubstituteBindings;
|
||||
use Illuminate\Routing\Middleware\ThrottleRequests;
|
||||
use Illuminate\Session\Middleware\AuthenticateSession;
|
||||
use Illuminate\Session\Middleware\StartSession;
|
||||
use Illuminate\View\Middleware\ShareErrorsFromSession;
|
||||
|
||||
class Kernel extends HttpKernel
|
||||
{
|
||||
@@ -15,12 +42,12 @@ class Kernel extends HttpKernel
|
||||
*/
|
||||
protected $middleware = [
|
||||
// \App\Http\Middleware\TrustHosts::class,
|
||||
\App\Http\Middleware\TrustProxies::class,
|
||||
\Illuminate\Http\Middleware\HandleCors::class,
|
||||
\App\Http\Middleware\PreventRequestsDuringMaintenance::class,
|
||||
\Illuminate\Foundation\Http\Middleware\ValidatePostSize::class,
|
||||
\App\Http\Middleware\TrimStrings::class,
|
||||
\Illuminate\Foundation\Http\Middleware\ConvertEmptyStringsToNull::class,
|
||||
TrustProxies::class,
|
||||
HandleCors::class,
|
||||
PreventRequestsDuringMaintenance::class,
|
||||
ValidatePostSize::class,
|
||||
TrimStrings::class,
|
||||
ConvertEmptyStringsToNull::class,
|
||||
];
|
||||
|
||||
/**
|
||||
@@ -30,20 +57,20 @@ class Kernel extends HttpKernel
|
||||
*/
|
||||
protected $middlewareGroups = [
|
||||
'web' => [
|
||||
\App\Http\Middleware\EncryptCookies::class,
|
||||
\Illuminate\Cookie\Middleware\AddQueuedCookiesToResponse::class,
|
||||
\Illuminate\Session\Middleware\StartSession::class,
|
||||
\Illuminate\View\Middleware\ShareErrorsFromSession::class,
|
||||
\App\Http\Middleware\VerifyCsrfToken::class,
|
||||
\Illuminate\Routing\Middleware\SubstituteBindings::class,
|
||||
\App\Http\Middleware\IsBanned::class,
|
||||
\App\Http\Middleware\SetLocale::class,
|
||||
EncryptCookies::class,
|
||||
AddQueuedCookiesToResponse::class,
|
||||
StartSession::class,
|
||||
ShareErrorsFromSession::class,
|
||||
VerifyCsrfToken::class,
|
||||
SubstituteBindings::class,
|
||||
IsBanned::class,
|
||||
SetLocale::class,
|
||||
],
|
||||
|
||||
'api' => [
|
||||
// \Laravel\Sanctum\Http\Middleware\EnsureFrontendRequestsAreStateful::class,
|
||||
\Illuminate\Routing\Middleware\ThrottleRequests::class.':api',
|
||||
\Illuminate\Routing\Middleware\SubstituteBindings::class,
|
||||
ThrottleRequests::class.':api',
|
||||
SubstituteBindings::class,
|
||||
],
|
||||
];
|
||||
|
||||
@@ -55,18 +82,18 @@ class Kernel extends HttpKernel
|
||||
* @var array<string, class-string|string>
|
||||
*/
|
||||
protected $middlewareAliases = [
|
||||
'auth' => \App\Http\Middleware\Authenticate::class,
|
||||
'auth.basic' => \Illuminate\Auth\Middleware\AuthenticateWithBasicAuth::class,
|
||||
'auth.session' => \Illuminate\Session\Middleware\AuthenticateSession::class,
|
||||
'auth.admin' => \App\Http\Middleware\IsAdmin::class,
|
||||
'auth.moderator' => \App\Http\Middleware\IsModerator::class,
|
||||
'cache.headers' => \Illuminate\Http\Middleware\SetCacheHeaders::class,
|
||||
'can' => \Illuminate\Auth\Middleware\Authorize::class,
|
||||
'guest' => \App\Http\Middleware\RedirectIfAuthenticated::class,
|
||||
'password.confirm' => \Illuminate\Auth\Middleware\RequirePassword::class,
|
||||
'precognitive' => \Illuminate\Foundation\Http\Middleware\HandlePrecognitiveRequests::class,
|
||||
'signed' => \App\Http\Middleware\ValidateSignature::class,
|
||||
'throttle' => \Illuminate\Routing\Middleware\ThrottleRequests::class,
|
||||
'verified' => \Illuminate\Auth\Middleware\EnsureEmailIsVerified::class,
|
||||
'auth' => Authenticate::class,
|
||||
'auth.basic' => AuthenticateWithBasicAuth::class,
|
||||
'auth.session' => AuthenticateSession::class,
|
||||
'auth.admin' => IsAdmin::class,
|
||||
'auth.moderator' => IsModerator::class,
|
||||
'cache.headers' => SetCacheHeaders::class,
|
||||
'can' => Authorize::class,
|
||||
'guest' => RedirectIfAuthenticated::class,
|
||||
'password.confirm' => RequirePassword::class,
|
||||
'precognitive' => HandlePrecognitiveRequests::class,
|
||||
'signed' => ValidateSignature::class,
|
||||
'throttle' => ThrottleRequests::class,
|
||||
'verified' => EnsureEmailIsVerified::class,
|
||||
];
|
||||
}
|
||||
|
||||
@@ -1,29 +1,28 @@
|
||||
<?php namespace app\Http\Middleware;
|
||||
<?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 IsAdmin {
|
||||
|
||||
class IsAdmin
|
||||
{
|
||||
/**
|
||||
* Handle an incoming request.
|
||||
*
|
||||
* @param \Illuminate\Http\Request $request
|
||||
* @param \Closure $next
|
||||
* @return mixed
|
||||
*/
|
||||
public function handle(Request $request, Closure $next): Response
|
||||
{
|
||||
if(Auth::check() && Auth::user()->hasRole(UserRole::ADMINISTRATOR))
|
||||
{
|
||||
if (Auth::check() && Auth::user()->hasRole(UserRole::ADMINISTRATOR)) {
|
||||
return $next($request);
|
||||
}
|
||||
|
||||
session()->flash('error_msg', 'This resource is restricted to Administrators!');
|
||||
|
||||
return redirect()->route('home.index');
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,32 +1,30 @@
|
||||
<?php namespace app\Http\Middleware;
|
||||
<?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 IsBanned {
|
||||
|
||||
class IsBanned
|
||||
{
|
||||
/**
|
||||
* Handle an incoming request.
|
||||
*
|
||||
* @param \Illuminate\Http\Request $request
|
||||
* @param \Closure $next
|
||||
* @return mixed
|
||||
*/
|
||||
public function handle(Request $request, Closure $next): Response
|
||||
{
|
||||
if(Auth::check() && Auth::user()->hasRole(UserRole::BANNED))
|
||||
{
|
||||
if (Auth::check() && Auth::user()->hasRole(UserRole::BANNED)) {
|
||||
Auth::logout();
|
||||
$request->session()->invalidate();
|
||||
$request->session()->regenerateToken();
|
||||
|
||||
return redirect()->route('home.banned');
|
||||
}
|
||||
|
||||
return $next($request);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -3,7 +3,6 @@
|
||||
namespace App\Http\Middleware;
|
||||
|
||||
use App\Enums\UserRole;
|
||||
|
||||
use Closure;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Support\Facades\Auth;
|
||||
@@ -14,16 +13,18 @@ class IsModerator
|
||||
/**
|
||||
* Handle an incoming request.
|
||||
*
|
||||
* @param \Closure(\Illuminate\Http\Request): (\Symfony\Component\HttpFoundation\Response) $next
|
||||
* @param Closure(Request): (Response) $next
|
||||
*/
|
||||
public function handle(Request $request, Closure $next): Response
|
||||
{
|
||||
if (Auth::check() && Auth::user()->hasRole(UserRole::MODERATOR))
|
||||
{
|
||||
if (Auth::check() && (
|
||||
Auth::user()->hasRole(UserRole::MODERATOR) ||
|
||||
Auth::user()->hasRole(UserRole::ADMINISTRATOR))) {
|
||||
return $next($request);
|
||||
}
|
||||
|
||||
session()->flash('error_msg','This resource is restricted to Administrators!');
|
||||
session()->flash('error_msg', 'This resource is restricted to Moderators!');
|
||||
|
||||
return redirect()->route('home.index');
|
||||
}
|
||||
}
|
||||
|
||||
@@ -13,7 +13,7 @@ class RedirectIfAuthenticated
|
||||
/**
|
||||
* Handle an incoming request.
|
||||
*
|
||||
* @param \Closure(\Illuminate\Http\Request): (\Symfony\Component\HttpFoundation\Response) $next
|
||||
* @param Closure(Request): (Response) $next
|
||||
*/
|
||||
public function handle(Request $request, Closure $next, string ...$guards): Response
|
||||
{
|
||||
|
||||
@@ -13,19 +13,23 @@ class SetLocale
|
||||
/**
|
||||
* Handle an incoming request.
|
||||
*
|
||||
* @param \Closure(\Illuminate\Http\Request): (\Symfony\Component\HttpFoundation\Response) $next
|
||||
* @param Closure(Request): (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)) {
|
||||
if ($request->session()->has('locale') &&
|
||||
in_array(session('locale'), config('app.supported_locales'), true)) {
|
||||
|
||||
App::setLocale(session('locale'));
|
||||
|
||||
return $next($request);
|
||||
}
|
||||
|
||||
|
||||
@@ -2,15 +2,15 @@
|
||||
|
||||
namespace App\Http\Requests\Auth;
|
||||
|
||||
use App\Rules\ValidCaptcha;
|
||||
use Illuminate\Auth\Events\Lockout;
|
||||
use Illuminate\Contracts\Validation\ValidationRule;
|
||||
use Illuminate\Foundation\Http\FormRequest;
|
||||
use Illuminate\Support\Facades\Auth;
|
||||
use Illuminate\Support\Facades\RateLimiter;
|
||||
use Illuminate\Support\Str;
|
||||
use Illuminate\Validation\ValidationException;
|
||||
|
||||
use GrantHolle\Altcha\Rules\ValidAltcha;
|
||||
|
||||
class LoginRequest extends FormRequest
|
||||
{
|
||||
/**
|
||||
@@ -24,21 +24,21 @@ class LoginRequest extends FormRequest
|
||||
/**
|
||||
* Get the validation rules that apply to the request.
|
||||
*
|
||||
* @return array<string, \Illuminate\Contracts\Validation\ValidationRule|array<mixed>|string>
|
||||
* @return array<string, ValidationRule|array<mixed>|string>
|
||||
*/
|
||||
public function rules(): array
|
||||
{
|
||||
return [
|
||||
'email' => ['required', 'string', 'email'],
|
||||
'password' => ['required', 'string'],
|
||||
'altcha' => ['required', new ValidAltcha],
|
||||
'altcha' => ['required', new ValidCaptcha],
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Attempt to authenticate the request's credentials.
|
||||
*
|
||||
* @throws \Illuminate\Validation\ValidationException
|
||||
* @throws ValidationException
|
||||
*/
|
||||
public function authenticate(): void
|
||||
{
|
||||
@@ -58,7 +58,7 @@ class LoginRequest extends FormRequest
|
||||
/**
|
||||
* Ensure the login request is not rate limited.
|
||||
*
|
||||
* @throws \Illuminate\Validation\ValidationException
|
||||
* @throws ValidationException
|
||||
*/
|
||||
public function ensureIsNotRateLimited(): void
|
||||
{
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
|
||||
namespace App\Http\Requests;
|
||||
|
||||
use Illuminate\Contracts\Validation\ValidationRule;
|
||||
use Illuminate\Foundation\Http\FormRequest;
|
||||
|
||||
class MatrixRegisterRequest extends FormRequest
|
||||
@@ -13,13 +14,14 @@ class MatrixRegisterRequest extends FormRequest
|
||||
{
|
||||
$isOldEnough = $this->user()->created_at->lt(now()->subMonth());
|
||||
$noAccount = ! $this->user()->matrix_id;
|
||||
|
||||
return $isOldEnough && $noAccount;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the validation rules that apply to the request.
|
||||
*
|
||||
* @return array<string, \Illuminate\Contracts\Validation\ValidationRule|array<mixed>|string>
|
||||
* @return array<string, ValidationRule|array<mixed>|string>
|
||||
*/
|
||||
public function rules(): array
|
||||
{
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
namespace App\Http\Requests;
|
||||
|
||||
use App\Models\User;
|
||||
use Illuminate\Contracts\Validation\ValidationRule;
|
||||
use Illuminate\Foundation\Http\FormRequest;
|
||||
use Illuminate\Validation\Rule;
|
||||
|
||||
@@ -11,7 +12,7 @@ class ProfileUpdateRequest extends FormRequest
|
||||
/**
|
||||
* Get the validation rules that apply to the request.
|
||||
*
|
||||
* @return array<string, \Illuminate\Contracts\Validation\ValidationRule|array<mixed>|string>
|
||||
* @return array<string, ValidationRule|array<mixed>|string>
|
||||
*/
|
||||
public function rules(): array
|
||||
{
|
||||
@@ -21,7 +22,7 @@ class ProfileUpdateRequest extends FormRequest
|
||||
'nullable',
|
||||
'image',
|
||||
'mimes:jpg,png,jpeg,webp,gif',
|
||||
'max:8192'
|
||||
'max:8192',
|
||||
],
|
||||
'email' => [
|
||||
'required',
|
||||
|
||||
@@ -7,7 +7,6 @@ use Illuminate\Contracts\Queue\ShouldQueue;
|
||||
use Illuminate\Foundation\Bus\Dispatchable;
|
||||
use Illuminate\Queue\InteractsWithQueue;
|
||||
use Illuminate\Queue\SerializesModels;
|
||||
|
||||
use Spatie\DiscordAlerts\Facades\DiscordAlert;
|
||||
|
||||
class DiscordReleaseNotification implements ShouldQueue
|
||||
@@ -32,26 +31,25 @@ class DiscordReleaseNotification implements ShouldQueue
|
||||
*/
|
||||
public function handle(): void
|
||||
{
|
||||
switch($this->messageType)
|
||||
{
|
||||
switch ($this->messageType) {
|
||||
case 'release':
|
||||
DiscordAlert::message("<@&868457842250764289> (´• ω •`)ノ New **4k** Release! Check it out here: https://hstream.moe/hentai/".$this->slug);
|
||||
DiscordAlert::message('<@&868457842250764289> (´• ω •`)ノ New **4k** Release! Check it out here: https://hstream.moe/hentai/'.$this->slug);
|
||||
break;
|
||||
case 'release-censored':
|
||||
# Because Discord TOS
|
||||
DiscordAlert::message("<@&868457842250764289> (´• ω •`)ノ New **4k** Release: ".$this->slug." - *No link here because of* :pLoli:");
|
||||
// Because Discord TOS
|
||||
DiscordAlert::message('<@&868457842250764289> (´• ω •`)ノ New **4k** Release: '.$this->slug.' - *No link here because of* :pLoli:');
|
||||
break;
|
||||
case 'update':
|
||||
# 1080p 48fps added
|
||||
DiscordAlert::to('update')->message("<@&1283518462584426598> (´• ω •`)ノ Added **48fps** to Release! Check it out here: https://hstream.moe/hentai/".$this->slug);
|
||||
// 1080p 48fps added
|
||||
DiscordAlert::to('update')->message('<@&1283518462584426598> (´• ω •`)ノ Added **48fps** to Release! Check it out here: https://hstream.moe/hentai/'.$this->slug);
|
||||
break;
|
||||
case 'updateUHD':
|
||||
# 4k 48fps added
|
||||
DiscordAlert::to('update')->message("<@&1326860920902778963> (´• ω •`)ノ Added **48fps 4k** to Release! Check it out here: https://hstream.moe/hentai/".$this->slug);
|
||||
// 4k 48fps added
|
||||
DiscordAlert::to('update')->message('<@&1326860920902778963> (´• ω •`)ノ Added **48fps 4k** to Release! Check it out here: https://hstream.moe/hentai/'.$this->slug);
|
||||
break;
|
||||
case 'v2':
|
||||
# v2 re-release
|
||||
DiscordAlert::to('rerelease')->message("<@&1425505303075754035> (´• ω •`)ノ **v2 Re-**Release! Check it out here: https://hstream.moe/hentai/".$this->slug);
|
||||
// v2 re-release
|
||||
DiscordAlert::to('rerelease')->message('<@&1425505303075754035> (´• ω •`)ノ **v2 Re-**Release! Check it out here: https://hstream.moe/hentai/'.$this->slug);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
|
||||
@@ -7,12 +7,12 @@ use Illuminate\Bus\Queueable;
|
||||
use Illuminate\Contracts\Queue\ShouldQueue;
|
||||
use Illuminate\Foundation\Bus\Dispatchable;
|
||||
use Illuminate\Http\Client\RequestException;
|
||||
use Illuminate\Queue\InteractsWithQueue;
|
||||
use Illuminate\Queue\SerializesModels;
|
||||
use Illuminate\Support\Carbon;
|
||||
use Illuminate\Support\Facades\Crypt;
|
||||
use Illuminate\Support\Facades\Http;
|
||||
use Illuminate\Support\Facades\Log;
|
||||
use Illuminate\Queue\InteractsWithQueue;
|
||||
use Illuminate\Queue\SerializesModels;
|
||||
|
||||
class GetFileSizeFromCDN implements ShouldQueue
|
||||
{
|
||||
@@ -37,6 +37,7 @@ class GetFileSizeFromCDN implements ShouldQueue
|
||||
$download = Downloads::find($this->downloadId);
|
||||
if (! $download) {
|
||||
Log::error("Download not found for ID: {$this->downloadId}");
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
@@ -5,7 +5,6 @@ namespace App\Livewire;
|
||||
use App\Models\Comment;
|
||||
use Livewire\Component;
|
||||
use Livewire\WithPagination;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
|
||||
class AdminCommentSearch extends Component
|
||||
{
|
||||
@@ -41,7 +40,7 @@ class AdminCommentSearch extends Component
|
||||
->paginate(12);
|
||||
|
||||
return view('livewire.admin-comment-search', [
|
||||
'comments' => $comments
|
||||
'comments' => $comments,
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,10 +5,9 @@ namespace App\Livewire;
|
||||
use App\Enums\UserRole;
|
||||
use App\Models\Comment;
|
||||
use App\Models\User;
|
||||
|
||||
use Livewire\Attributes\Url;
|
||||
use Livewire\Component;
|
||||
use Livewire\WithPagination;
|
||||
use Livewire\Attributes\Url;
|
||||
|
||||
class AdminUserSearch extends Component
|
||||
{
|
||||
@@ -46,7 +45,7 @@ class AdminUserSearch extends Component
|
||||
->paginate(20);
|
||||
|
||||
return view('livewire.admin-user-search', [
|
||||
'users' => $users
|
||||
'users' => $users,
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,12 +2,11 @@
|
||||
|
||||
namespace App\Livewire;
|
||||
|
||||
use Livewire\Component;
|
||||
use Livewire\WithPagination;
|
||||
use Livewire\Attributes\Url;
|
||||
|
||||
use App\Models\SiteBackground;
|
||||
use Illuminate\Support\Carbon;
|
||||
use Livewire\Attributes\Url;
|
||||
use Livewire\Component;
|
||||
use Livewire\WithPagination;
|
||||
|
||||
class BackgroundImages extends Component
|
||||
{
|
||||
@@ -20,16 +19,14 @@ class BackgroundImages extends Component
|
||||
{
|
||||
$now = Carbon::now();
|
||||
|
||||
$images = SiteBackground::when($this->filter === 'active', fn ($query) =>
|
||||
$query->whereDate('date_start', '<=', $now)->whereDate('date_end', '>=', $now)
|
||||
$images = SiteBackground::when($this->filter === 'active', fn ($query) => $query->whereDate('date_start', '<=', $now)->whereDate('date_end', '>=', $now)
|
||||
)
|
||||
->when($this->filter === 'inactive', fn ($query) =>
|
||||
$query->whereDate('date_start', '>', $now)->orWhereDate('date_end', '<', $now)
|
||||
->when($this->filter === 'inactive', fn ($query) => $query->whereDate('date_start', '>', $now)->orWhereDate('date_end', '<', $now)
|
||||
)
|
||||
->paginate(10);
|
||||
|
||||
return view('livewire.background-images', [
|
||||
'images' => $images
|
||||
'images' => $images,
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
||||
+52
-17
@@ -1,20 +1,18 @@
|
||||
<?php
|
||||
|
||||
|
||||
namespace App\Livewire;
|
||||
|
||||
use App\Models\User;
|
||||
use App\Enums\UserRole;
|
||||
use App\Models\Episode;
|
||||
use App\Models\ModLog;
|
||||
use App\Models\User;
|
||||
use App\Notifications\CommentNotification;
|
||||
|
||||
use Livewire\Component;
|
||||
|
||||
use Illuminate\Support\Str;
|
||||
use Illuminate\Foundation\Auth\Access\AuthorizesRequests;
|
||||
use Illuminate\Support\Facades\Auth;
|
||||
use Illuminate\Support\Facades\Cache;
|
||||
use Illuminate\Support\Facades\RateLimiter;
|
||||
use Illuminate\Foundation\Auth\Access\AuthorizesRequests;
|
||||
|
||||
use Illuminate\Support\Str;
|
||||
use Livewire\Component;
|
||||
use Maize\Markable\Models\Like;
|
||||
|
||||
class Comment extends Component
|
||||
@@ -30,31 +28,31 @@ class Comment extends Component
|
||||
public $liked = false;
|
||||
|
||||
public $replyState = [
|
||||
'body' => ''
|
||||
'body' => '',
|
||||
];
|
||||
|
||||
public $isEditing = false;
|
||||
|
||||
public $editState = [
|
||||
'body' => ''
|
||||
'body' => '',
|
||||
];
|
||||
|
||||
protected $listeners = [
|
||||
'refresh' => '$refresh'
|
||||
'refresh' => '$refresh',
|
||||
];
|
||||
|
||||
protected $validationAttributes = [
|
||||
'replyState.body' => 'reply'
|
||||
'replyState.body' => 'reply',
|
||||
];
|
||||
|
||||
public function updatedIsEditing($isEditing)
|
||||
public function updatedIsEditing(bool $isEditing)
|
||||
{
|
||||
if (! $isEditing) {
|
||||
return;
|
||||
}
|
||||
|
||||
$this->editState = [
|
||||
'body' => $this->comment->body
|
||||
'body' => $this->comment->body,
|
||||
];
|
||||
}
|
||||
|
||||
@@ -71,15 +69,50 @@ class Comment extends Component
|
||||
{
|
||||
$this->authorize('destroy', $this->comment);
|
||||
|
||||
$user = Auth::user();
|
||||
|
||||
if ($user->hasRole(UserRole::ADMINISTRATOR) || $user->hasRole(UserRole::MODERATOR)) {
|
||||
// Log to ModLog
|
||||
ModLog::create([
|
||||
'moderator' => $user->name,
|
||||
'data' => "Deleted comment {$this->comment->id} written by {$this->comment->user->id} with contents: {$this->comment->body}",
|
||||
]);
|
||||
|
||||
$this->comment->deleted_by_moderator_id = $user->id;
|
||||
$this->comment->save();
|
||||
$this->dispatch('refresh');
|
||||
return;
|
||||
}
|
||||
|
||||
$this->comment->delete();
|
||||
|
||||
$this->dispatch('refresh');
|
||||
}
|
||||
|
||||
public function restoreComment()
|
||||
{
|
||||
$this->authorize('restore', $this->comment);
|
||||
|
||||
$user = Auth::user();
|
||||
|
||||
if ($user->hasRole(UserRole::ADMINISTRATOR) || $user->hasRole(UserRole::MODERATOR)) {
|
||||
// Log to ModLog
|
||||
ModLog::create([
|
||||
'moderator' => $user->name,
|
||||
'data' => "Restored comment {$this->comment->id} written by {$this->comment->user->id} with contents: {$this->comment->body}",
|
||||
]);
|
||||
|
||||
$this->comment->deleted_by_moderator_id = null;
|
||||
$this->comment->save();
|
||||
$this->dispatch('refresh');
|
||||
}
|
||||
}
|
||||
|
||||
public function postReply()
|
||||
{
|
||||
if (! ($this->comment->depth() < 2)) {
|
||||
$this->addError('replyState.body', "Too many sub comments.");
|
||||
$this->addError('replyState.body', 'Too many sub comments.');
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -91,13 +124,14 @@ class Comment extends Component
|
||||
$seconds = RateLimiter::availableIn($rateLimitKey);
|
||||
|
||||
$this->addError('replyState.body', "Too many comments. Try again in {$seconds} seconds.");
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
RateLimiter::hit($rateLimitKey, $rateLimitMinutes);
|
||||
|
||||
$this->validate([
|
||||
'replyState.body' => 'required'
|
||||
'replyState.body' => 'required',
|
||||
]);
|
||||
|
||||
$reply = $this->comment->children()->make($this->replyState);
|
||||
@@ -123,7 +157,7 @@ class Comment extends Component
|
||||
}
|
||||
|
||||
$this->replyState = [
|
||||
'body' => ''
|
||||
'body' => '',
|
||||
];
|
||||
|
||||
$this->isReplying = false;
|
||||
@@ -144,6 +178,7 @@ class Comment extends Component
|
||||
if ($this->liked) {
|
||||
$this->liked = false;
|
||||
$this->likeCount--;
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
@@ -2,11 +2,10 @@
|
||||
|
||||
namespace App\Livewire;
|
||||
|
||||
use Illuminate\Support\Facades\RateLimiter;
|
||||
use Livewire\Component;
|
||||
use Livewire\WithPagination;
|
||||
|
||||
use Illuminate\Support\Facades\RateLimiter;
|
||||
|
||||
class Comments extends Component
|
||||
{
|
||||
use WithPagination;
|
||||
@@ -14,21 +13,21 @@ class Comments extends Component
|
||||
public $model;
|
||||
|
||||
public $newCommentState = [
|
||||
'body' => ''
|
||||
'body' => '',
|
||||
];
|
||||
|
||||
protected $validationAttributes = [
|
||||
'newCommentState.body' => 'comment'
|
||||
'newCommentState.body' => 'comment',
|
||||
];
|
||||
|
||||
protected $listeners = [
|
||||
'refresh' => '$refresh'
|
||||
'refresh' => '$refresh',
|
||||
];
|
||||
|
||||
public function postComment()
|
||||
{
|
||||
$this->validate([
|
||||
'newCommentState.body' => 'required'
|
||||
'newCommentState.body' => 'required',
|
||||
]);
|
||||
|
||||
$user = auth()->user();
|
||||
@@ -39,6 +38,7 @@ class Comments extends Component
|
||||
$seconds = RateLimiter::availableIn($rateLimitKey);
|
||||
|
||||
$this->addError('newCommentState.body', "Too many comments. Try again in {$seconds} seconds.");
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -49,7 +49,7 @@ class Comments extends Component
|
||||
$comment->save();
|
||||
|
||||
$this->newCommentState = [
|
||||
'body' => ''
|
||||
'body' => '',
|
||||
];
|
||||
|
||||
$this->resetPage();
|
||||
@@ -65,7 +65,7 @@ class Comments extends Component
|
||||
->paginate(50);
|
||||
|
||||
return view('livewire.comments', [
|
||||
'comments' => $comments
|
||||
'comments' => $comments,
|
||||
]);
|
||||
}
|
||||
}
|
||||
@@ -23,11 +23,21 @@ class DownloadButton extends Component
|
||||
|
||||
public $fileExtension = 'HEVC';
|
||||
|
||||
public $version = '';
|
||||
|
||||
public function mount()
|
||||
{
|
||||
if (str_contains($this->downloadUrl, 'AV1')) {
|
||||
$this->fileExtension = 'AV1';
|
||||
}
|
||||
|
||||
if (str_contains($this->downloadUrl, 'v2')) {
|
||||
$this->version = 'v2';
|
||||
}
|
||||
|
||||
if (str_contains($this->downloadUrl, 'v3')) {
|
||||
$this->version = 'v3';
|
||||
}
|
||||
}
|
||||
|
||||
public function clicked($downloadId)
|
||||
|
||||
@@ -5,11 +5,9 @@ namespace App\Livewire;
|
||||
use App\Models\Episode;
|
||||
use App\Models\User;
|
||||
use App\Models\UserDownload;
|
||||
|
||||
use Livewire\Component;
|
||||
|
||||
use Illuminate\Support\Carbon;
|
||||
use Illuminate\Support\Facades\Auth;
|
||||
use Livewire\Component;
|
||||
|
||||
class DownloadsFree extends Component
|
||||
{
|
||||
@@ -51,6 +49,7 @@ class DownloadsFree extends Component
|
||||
if (Carbon::parse($alreadyDownloaded->created_at)->addHours(6) <= Carbon::now()) {
|
||||
// Already expired
|
||||
$alreadyDownloaded->delete();
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -65,6 +64,7 @@ class DownloadsFree extends Component
|
||||
if ($user->downloads_left <= 0) {
|
||||
// Daily limit reached
|
||||
$this->granted = 3;
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
@@ -2,10 +2,11 @@
|
||||
|
||||
namespace App\Livewire;
|
||||
|
||||
use App\Enums\UserRole;
|
||||
use App\Models\Downloads;
|
||||
use Livewire\Attributes\Url;
|
||||
use Livewire\Component;
|
||||
use Livewire\WithPagination;
|
||||
use Livewire\Attributes\Url;
|
||||
|
||||
class DownloadsSearch extends Component
|
||||
{
|
||||
@@ -25,6 +26,7 @@ class DownloadsSearch extends Component
|
||||
|
||||
#[Url(history: true)]
|
||||
public $studios = [];
|
||||
|
||||
public $studiosCopy = [];
|
||||
|
||||
// To toggle individual option selection
|
||||
@@ -73,9 +75,9 @@ class DownloadsSearch extends Component
|
||||
$types[] = 'FHD';
|
||||
} elseif ($label === 'FHD 48fps') {
|
||||
$types[] = 'FHDi';
|
||||
} elseif ($label === 'UHD' && auth()->user()->hasRole(\App\Enums\UserRole::SUPPORTER)) {
|
||||
} elseif ($label === 'UHD' && auth()->user()->hasRole(UserRole::SUPPORTER)) {
|
||||
$types[] = 'UHD';
|
||||
} elseif ($label === 'UHD 48fps' && auth()->user()->hasRole(\App\Enums\UserRole::SUPPORTER)) {
|
||||
} elseif ($label === 'UHD 48fps' && auth()->user()->hasRole(UserRole::SUPPORTER)) {
|
||||
$types[] = 'UHDi';
|
||||
}
|
||||
}
|
||||
@@ -98,7 +100,7 @@ class DownloadsSearch extends Component
|
||||
|
||||
public function mount()
|
||||
{
|
||||
if (!auth()->user()->hasRole(\App\Enums\UserRole::SUPPORTER)) {
|
||||
if (! auth()->user()->hasRole(UserRole::SUPPORTER)) {
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -144,7 +146,9 @@ class DownloadsSearch extends Component
|
||||
|
||||
$downloads = Downloads::when($this->fileSearch != '', fn ($query) => $query->where('url', 'like', '%'.$this->fileSearch.'%'))
|
||||
->whereIn('type', $this->getSelectedTypes())
|
||||
->when($this->studios !== [], fn ($q) => $q->whereHas('episode', fn ($query) => $query->whereHas('studio', function ($query) { $query->whereIn('slug', $this->studios); })))
|
||||
->when($this->studios !== [], fn ($q) => $q->whereHas('episode', fn ($query) => $query->whereHas('studio', function ($query) {
|
||||
$query->whereIn('slug', $this->studios);
|
||||
})))
|
||||
->whereNotNull('size')
|
||||
->orderBy($orderby, $orderdirection)
|
||||
->paginate(20);
|
||||
|
||||
@@ -4,10 +4,9 @@ namespace App\Livewire;
|
||||
|
||||
use App\Models\Episode;
|
||||
use App\Models\User;
|
||||
use Livewire\Component;
|
||||
use Illuminate\Support\Facades\Auth;
|
||||
use Illuminate\Support\Facades\Cache;
|
||||
|
||||
use Livewire\Component;
|
||||
use Maize\Markable\Models\Like;
|
||||
|
||||
class LikeButton extends Component
|
||||
@@ -52,6 +51,7 @@ class LikeButton extends Component
|
||||
if ($this->liked) {
|
||||
$this->liked = false;
|
||||
$this->likeCount--;
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
@@ -3,10 +3,10 @@
|
||||
namespace App\Livewire;
|
||||
|
||||
use App\Models\Episode;
|
||||
use Illuminate\Support\Facades\Auth;
|
||||
use Livewire\Attributes\Url;
|
||||
use Livewire\Component;
|
||||
use Livewire\WithPagination;
|
||||
use Livewire\Attributes\Url;
|
||||
use Illuminate\Support\Facades\Auth;
|
||||
|
||||
class LiveSearch extends Component
|
||||
{
|
||||
@@ -20,14 +20,17 @@ class LiveSearch extends Component
|
||||
|
||||
#[Url(history: true)]
|
||||
public $tags = [];
|
||||
|
||||
public $tagsCopy = [];
|
||||
|
||||
#[Url(history: true)]
|
||||
public $studios = [];
|
||||
|
||||
public $studiosCopy = [];
|
||||
|
||||
#[Url(history: true)]
|
||||
public $blacklist = [];
|
||||
|
||||
public $blacklistCopy = [];
|
||||
|
||||
#[Url(history: true)]
|
||||
@@ -118,10 +121,14 @@ class LiveSearch extends Component
|
||||
}
|
||||
|
||||
$user_id = Auth::check() ? auth()->user()->id : 0;
|
||||
$episodes = Episode::with('gallery')->when($this->search != '', fn ($query) => $query->where(function($query) { $query->where('title', 'like', '%'.$this->search.'%')->orWhere('title_search', 'like', '%'.$this->search.'%')->orWhere('title_jpn', 'like', '%'.$this->search.'%'); }))
|
||||
$episodes = Episode::with('gallery')->when($this->search != '', fn ($query) => $query->where(function ($query) {
|
||||
$query->where('title', 'like', '%'.$this->search.'%')->orWhere('title_search', 'like', '%'.$this->search.'%')->orWhere('title_jpn', 'like', '%'.$this->search.'%');
|
||||
}))
|
||||
->when($this->tags !== [], fn ($query) => $query->withAllTags($this->tags))
|
||||
->when($this->blacklist !== [], fn ($query) => $query->withoutTags($this->blacklist))
|
||||
->when($this->studios !== [], fn ($query) => $query->whereHas('studio', function ($query) { $query->whereIn('slug', $this->studios); }))
|
||||
->when($this->studios !== [], fn ($query) => $query->whereHas('studio', function ($query) {
|
||||
$query->whereIn('slug', $this->studios);
|
||||
}))
|
||||
->when($this->hideWatched !== [] && Auth::check(), fn ($query) => $query->whereDoesntHave('watched', function ($query) use ($user_id) {
|
||||
$query->where('user_id', $user_id);
|
||||
}))
|
||||
|
||||
@@ -3,8 +3,8 @@
|
||||
namespace App\Livewire;
|
||||
|
||||
use App\Models\Episode;
|
||||
use Livewire\Component;
|
||||
use Illuminate\Support\Facades\Auth;
|
||||
use Livewire\Component;
|
||||
|
||||
class NavLiveSearch extends Component
|
||||
{
|
||||
|
||||
@@ -5,13 +5,11 @@ namespace App\Livewire;
|
||||
use App\Models\Playlist;
|
||||
use App\Models\PlaylistEpisode;
|
||||
use App\Services\PlaylistService;
|
||||
|
||||
use Illuminate\Database\Eloquent\Collection;
|
||||
use Illuminate\Support\Facades\Auth;
|
||||
use Livewire\Attributes\Url;
|
||||
use Livewire\Component;
|
||||
use Livewire\WithPagination;
|
||||
use Livewire\Attributes\Url;
|
||||
|
||||
use Illuminate\Support\Facades\Auth;
|
||||
use Illuminate\Database\Eloquent\Collection;
|
||||
|
||||
class PlaylistOverview extends Component
|
||||
{
|
||||
|
||||
@@ -3,10 +3,9 @@
|
||||
namespace App\Livewire;
|
||||
|
||||
use App\Models\Playlist;
|
||||
|
||||
use Livewire\Attributes\Url;
|
||||
use Livewire\Component;
|
||||
use Livewire\WithPagination;
|
||||
use Livewire\Attributes\Url;
|
||||
|
||||
class Playlists extends Component
|
||||
{
|
||||
@@ -59,7 +58,7 @@ class Playlists extends Component
|
||||
->paginate($this->pagination);
|
||||
|
||||
return view('livewire.playlists', [
|
||||
'playlists' => $playlists
|
||||
'playlists' => $playlists,
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,7 +3,6 @@
|
||||
namespace App\Livewire;
|
||||
|
||||
use App\Models\Comment;
|
||||
|
||||
use Livewire\Component;
|
||||
use Livewire\WithPagination;
|
||||
|
||||
@@ -36,14 +35,13 @@ class UserComments extends Component
|
||||
$orderdirection = 'desc';
|
||||
}
|
||||
|
||||
|
||||
$comments = Comment::where('user_id', $this->model->id)
|
||||
->when($this->commentSearch != '', fn ($query) => $query->where('body', 'like', '%'.$this->commentSearch.'%'))
|
||||
->orderBy($orderby, $orderdirection)
|
||||
->paginate(10);
|
||||
->paginate(6);
|
||||
|
||||
return view('livewire.user-comments', [
|
||||
'comments' => $comments
|
||||
'comments' => $comments,
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,10 +3,10 @@
|
||||
namespace App\Livewire;
|
||||
|
||||
use App\Models\Episode;
|
||||
use Illuminate\Support\Facades\Auth;
|
||||
use Livewire\Attributes\Url;
|
||||
use Livewire\Component;
|
||||
use Livewire\WithPagination;
|
||||
use Livewire\Attributes\Url;
|
||||
use Illuminate\Support\Facades\Auth;
|
||||
|
||||
class UserLikes extends Component
|
||||
{
|
||||
@@ -20,14 +20,17 @@ class UserLikes extends Component
|
||||
|
||||
#[Url(history: true)]
|
||||
public $tags = [];
|
||||
|
||||
public $tagsCopy = [];
|
||||
|
||||
#[Url(history: true)]
|
||||
public $studios = [];
|
||||
|
||||
public $studiosCopy = [];
|
||||
|
||||
#[Url(history: true)]
|
||||
public $blacklist = [];
|
||||
|
||||
public $blacklistCopy = [];
|
||||
|
||||
#[Url(history: true)]
|
||||
@@ -119,10 +122,14 @@ class UserLikes extends Component
|
||||
|
||||
$user_id = Auth::check() ? auth()->user()->id : 0;
|
||||
$episodes = Episode::whereHasLike(auth()->user())
|
||||
->when($this->search !== '', fn ($query) => $query->where(function($query) { $query->where('title', 'like', '%'.$this->search.'%')->orWhere('title_search', 'like', '%'.$this->search.'%')->orWhere('title_jpn', 'like', '%'.$this->search.'%'); }))
|
||||
->when($this->search !== '', fn ($query) => $query->where(function ($query) {
|
||||
$query->where('title', 'like', '%'.$this->search.'%')->orWhere('title_search', 'like', '%'.$this->search.'%')->orWhere('title_jpn', 'like', '%'.$this->search.'%');
|
||||
}))
|
||||
->when($this->tags !== [], fn ($query) => $query->withAllTags($this->tags))
|
||||
->when($this->blacklist !== [], fn ($query) => $query->withoutTags($this->blacklist))
|
||||
->when($this->studios !== [], fn ($query) => $query->whereHas('studio', function ($query) { $query->whereIn('slug', $this->studios); }))
|
||||
->when($this->studios !== [], fn ($query) => $query->whereHas('studio', function ($query) {
|
||||
$query->whereIn('slug', $this->studios);
|
||||
}))
|
||||
->when($this->hideWatched !== [] && Auth::check(), fn ($query) => $query->whereDoesntHave('watched', function ($query) use ($user_id) {
|
||||
$query->where('user_id', $user_id);
|
||||
}))
|
||||
|
||||
@@ -0,0 +1,75 @@
|
||||
<?php
|
||||
|
||||
namespace App\Livewire;
|
||||
|
||||
use App\Enums\UserRole;
|
||||
use App\Models\User;
|
||||
use App\Services\SubscriptionService;
|
||||
use Livewire\Component;
|
||||
use Livewire\Attributes\Computed;
|
||||
use Illuminate\Support\Facades\RateLimiter;
|
||||
|
||||
class UserSubscription extends Component
|
||||
{
|
||||
public $userId = 0;
|
||||
|
||||
public $subscriptionKey = '';
|
||||
|
||||
public $isActive = false;
|
||||
|
||||
protected $rules = [
|
||||
'subscriptionKey' => 'required|string|size:48',
|
||||
];
|
||||
|
||||
public function mount(User $user)
|
||||
{
|
||||
$this->userId = $user ? $user->id : auth()->user()->id;
|
||||
$this->subscriptionKey = $user->subscription_key ?? '';
|
||||
$this->isActive = $user->hasRole(UserRole::SUPPORTER) ?? false;
|
||||
}
|
||||
|
||||
public function applyKey(SubscriptionService $subscriptionService)
|
||||
{
|
||||
$this->validate();
|
||||
|
||||
$rateLimitKey = "apply-subscription:{$this->userId}";
|
||||
$rateLimitMinutes = 60 * 5; // 5 minutes
|
||||
|
||||
// Rate Limit to prevent users trying random keys
|
||||
if (RateLimiter::tooManyAttempts($rateLimitKey, 1)) {
|
||||
$seconds = RateLimiter::availableIn($rateLimitKey);
|
||||
$this->addError('subscriptionKey', "Too many attempts. Try again in {$seconds} seconds.");
|
||||
return;
|
||||
}
|
||||
|
||||
RateLimiter::hit($rateLimitKey, $rateLimitMinutes);
|
||||
|
||||
// Check if token is already being used
|
||||
$alreadyUsed = User::where('subscription_key', $this->subscriptionKey)
|
||||
->whereNot('id', $this->userId)
|
||||
->exists();
|
||||
|
||||
if ($alreadyUsed) {
|
||||
$this->addError('subscriptionKey', 'Key already used!');
|
||||
return;
|
||||
}
|
||||
|
||||
$user = User::where('id', $this->userId)->firstOrFail();
|
||||
|
||||
// Verify token
|
||||
$success = $subscriptionService->checkSubscriptionStatus($user, $this->subscriptionKey);
|
||||
if (!$success) {
|
||||
$this->addError('subscriptionKey', 'Invalid Key! If you believe this is a bug, please report this to the admin!');
|
||||
return;
|
||||
}
|
||||
|
||||
$user->subscription_key = $this->subscriptionKey;
|
||||
$user->save();
|
||||
$this->isActive = true;
|
||||
}
|
||||
|
||||
public function render()
|
||||
{
|
||||
return view('livewire.user-subscription');
|
||||
}
|
||||
}
|
||||
@@ -1,29 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace App\Livewire;
|
||||
|
||||
use App\Models\Episode;
|
||||
use Livewire\Component;
|
||||
|
||||
class ViewCount extends Component
|
||||
{
|
||||
public $episodeId = 0;
|
||||
|
||||
public $viewCount = 0;
|
||||
|
||||
public function mount(Episode $episode)
|
||||
{
|
||||
$this->episodeId = $episode->id;
|
||||
$this->viewCount = $episode->view_count;
|
||||
}
|
||||
|
||||
public function update()
|
||||
{
|
||||
$this->viewCount = Episode::where('id', $this->episodeId)->firstOrFail()->view_count;
|
||||
}
|
||||
|
||||
public function render()
|
||||
{
|
||||
return view('livewire.view-count');
|
||||
}
|
||||
}
|
||||
@@ -3,7 +3,6 @@
|
||||
namespace App\Livewire;
|
||||
|
||||
use App\Models\Watched as UserWatched;
|
||||
use App\Models\User;
|
||||
use Illuminate\Support\Carbon;
|
||||
use Livewire\Component;
|
||||
use Livewire\WithPagination;
|
||||
|
||||
+13
-6
@@ -4,19 +4,18 @@ namespace App\Models;
|
||||
|
||||
use App\Models\Presenters\CommentPresenter;
|
||||
use Illuminate\Database\Eloquent\Builder;
|
||||
use Illuminate\Database\Eloquent\SoftDeletes;
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
use Illuminate\Database\Eloquent\SoftDeletes;
|
||||
use Maize\Markable\Markable;
|
||||
use Maize\Markable\Models\Like;
|
||||
|
||||
class Comment extends Model
|
||||
{
|
||||
use HasFactory, SoftDeletes, Markable;
|
||||
use HasFactory, Markable, SoftDeletes;
|
||||
|
||||
protected static $marks = [
|
||||
Like::class
|
||||
Like::class,
|
||||
];
|
||||
|
||||
/**
|
||||
@@ -25,7 +24,7 @@ class Comment extends Model
|
||||
* @var string[]
|
||||
*/
|
||||
protected $fillable = [
|
||||
'body'
|
||||
'body',
|
||||
];
|
||||
|
||||
public function presenter()
|
||||
@@ -73,4 +72,12 @@ class Comment extends Model
|
||||
{
|
||||
return cache()->remember('commentLikes'.$this->id, 300, fn () => $this->likes->count());
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns wether or not comment has been removed by moderation
|
||||
*/
|
||||
public function isDeletedByModerator(): bool
|
||||
{
|
||||
return $this->deleted_by_moderator_id !== null;
|
||||
}
|
||||
}
|
||||
|
||||
+13
-18
@@ -2,35 +2,28 @@
|
||||
|
||||
namespace App\Models;
|
||||
|
||||
use App\Models\Downloads;
|
||||
use App\Models\PopularMonthly;
|
||||
use App\Models\PopularWeekly;
|
||||
use App\Models\PopularDaily;
|
||||
|
||||
use Conner\Tagging\Taggable;
|
||||
use Laravel\Scout\Searchable;
|
||||
use Maize\Markable\Markable;
|
||||
use Maize\Markable\Models\Like;
|
||||
|
||||
use Spatie\Sitemap\Contracts\Sitemapable;
|
||||
use Spatie\Sitemap\Tags\Url;
|
||||
|
||||
use Illuminate\Support\Carbon;
|
||||
use Illuminate\Support\Facades\Cache;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
use Illuminate\Database\Eloquent\Relations\BelongsTo;
|
||||
use Illuminate\Database\Eloquent\Relations\HasMany;
|
||||
use Illuminate\Support\Carbon;
|
||||
use Illuminate\Support\Facades\Cache;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
use Laravel\Scout\Searchable;
|
||||
use Maize\Markable\Markable;
|
||||
use Maize\Markable\Models\Like;
|
||||
use Spatie\Sitemap\Contracts\Sitemapable;
|
||||
use Spatie\Sitemap\Tags\Url;
|
||||
|
||||
class Episode extends Model implements Sitemapable
|
||||
{
|
||||
use Markable, Taggable;
|
||||
use HasFactory;
|
||||
use Markable, Taggable;
|
||||
use Searchable;
|
||||
|
||||
protected static $marks = [
|
||||
Like::class
|
||||
Like::class,
|
||||
];
|
||||
|
||||
/**
|
||||
@@ -180,6 +173,7 @@ class Episode extends Model implements Sitemapable
|
||||
|
||||
$problematicResults .= $pTag;
|
||||
}
|
||||
|
||||
return $problematicResults;
|
||||
}
|
||||
|
||||
@@ -234,9 +228,10 @@ class Episode extends Model implements Sitemapable
|
||||
return $this->hasMany(Watched::class);
|
||||
}
|
||||
|
||||
public function getDownloadByType(string $type): Downloads | null
|
||||
public function getDownloadByType(string $type): ?Downloads
|
||||
{
|
||||
$cacheKey = "episode_{$this->id}_download_{$type}";
|
||||
|
||||
return Cache::remember($cacheKey, now()->addMinutes(10), function () use ($type) {
|
||||
return $this->downloads()->where('type', $type)->first();
|
||||
});
|
||||
|
||||
@@ -2,19 +2,18 @@
|
||||
|
||||
namespace App\Models;
|
||||
|
||||
use Conner\Tagging\Taggable;
|
||||
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
use Illuminate\Support\Carbon;
|
||||
use Illuminate\Support\Facades\Cache;
|
||||
use Spatie\Sitemap\Contracts\Sitemapable;
|
||||
use Spatie\Sitemap\Tags\Url;
|
||||
|
||||
use Illuminate\Support\Facades\Cache;
|
||||
use Illuminate\Support\Carbon;
|
||||
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
use Conner\Tagging\Taggable;
|
||||
|
||||
class Hentai extends Model implements Sitemapable
|
||||
{
|
||||
use Taggable;
|
||||
use HasFactory;
|
||||
use Taggable;
|
||||
|
||||
/**
|
||||
* The attributes that are mass assignable.
|
||||
@@ -31,7 +30,7 @@ class Hentai extends Model implements Sitemapable
|
||||
return $this->hasMany(Episode::class, 'hentai_id');
|
||||
}
|
||||
|
||||
public function title(): String
|
||||
public function title(): string
|
||||
{
|
||||
return $this->episodes->first()->title;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,18 @@
|
||||
<?php
|
||||
|
||||
namespace App\Models;
|
||||
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
|
||||
class ModLog extends Model
|
||||
{
|
||||
/**
|
||||
* The attributes that are mass assignable.
|
||||
*
|
||||
* @var string[]
|
||||
*/
|
||||
protected $fillable = [
|
||||
'moderator',
|
||||
'data',
|
||||
];
|
||||
}
|
||||
@@ -2,8 +2,8 @@
|
||||
|
||||
namespace App\Models;
|
||||
|
||||
use Illuminate\Database\Eloquent\Relations\HasMany;
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
use Illuminate\Database\Eloquent\Relations\HasMany;
|
||||
|
||||
class Playlist extends Model
|
||||
{
|
||||
|
||||
@@ -2,8 +2,8 @@
|
||||
|
||||
namespace App\Models;
|
||||
|
||||
use Illuminate\Database\Eloquent\Relations\BelongsTo;
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
use Illuminate\Database\Eloquent\Relations\BelongsTo;
|
||||
|
||||
class PlaylistEpisode extends Model
|
||||
{
|
||||
|
||||
@@ -16,13 +16,13 @@ class SiteBackground extends Model
|
||||
protected $fillable = [
|
||||
'date_start',
|
||||
'date_end',
|
||||
'default'
|
||||
'default',
|
||||
];
|
||||
|
||||
/**
|
||||
* Returns the current IDs of active wallpaper
|
||||
*/
|
||||
public function getImages(): ? \Illuminate\Support\Collection
|
||||
public function getImages(): ?Collection
|
||||
{
|
||||
$now = Carbon::now();
|
||||
|
||||
|
||||
@@ -3,8 +3,8 @@
|
||||
namespace App\Models;
|
||||
|
||||
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||
use Illuminate\Database\Eloquent\Relations\HasMany;
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
use Illuminate\Database\Eloquent\Relations\HasMany;
|
||||
|
||||
class Studios extends Model
|
||||
{
|
||||
|
||||
+15
-11
@@ -5,17 +5,18 @@ namespace App\Models;
|
||||
// use Illuminate\Contracts\Auth\MustVerifyEmail;
|
||||
|
||||
use App\Enums\UserRole;
|
||||
use Illuminate\Database\Eloquent\Relations\HasMany;
|
||||
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||
use Illuminate\Database\Eloquent\Relations\HasMany;
|
||||
use Illuminate\Foundation\Auth\User as Authenticatable;
|
||||
use Illuminate\Notifications\Notifiable;
|
||||
use Illuminate\Support\Facades\Storage;
|
||||
|
||||
use Illuminate\Support\Facades\DB;
|
||||
use Illuminate\Support\Facades\Storage;
|
||||
use Spatie\LaravelPasskeys\Models\Concerns\HasPasskeys;
|
||||
use Spatie\LaravelPasskeys\Models\Concerns\InteractsWithPasskeys;
|
||||
|
||||
class User extends Authenticatable
|
||||
class User extends Authenticatable implements HasPasskeys
|
||||
{
|
||||
use HasFactory, Notifiable;
|
||||
use HasFactory, InteractsWithPasskeys, Notifiable;
|
||||
|
||||
/**
|
||||
* The attributes that are mass assignable.
|
||||
@@ -30,6 +31,7 @@ class User extends Authenticatable
|
||||
// Discord
|
||||
'discord_id',
|
||||
'discord_avatar',
|
||||
'subscription_key',
|
||||
];
|
||||
|
||||
/**
|
||||
@@ -40,6 +42,7 @@ class User extends Authenticatable
|
||||
protected $hidden = [
|
||||
'password',
|
||||
'remember_token',
|
||||
'subscription_key',
|
||||
];
|
||||
|
||||
/**
|
||||
@@ -62,7 +65,6 @@ class User extends Authenticatable
|
||||
'discord_avatar' => 'string',
|
||||
];
|
||||
|
||||
|
||||
/**
|
||||
* Has Many Playlists.
|
||||
*/
|
||||
@@ -108,13 +110,11 @@ class User extends Authenticatable
|
||||
*/
|
||||
public function getAvatar(): string
|
||||
{
|
||||
if ($this->discord_id && $this->discord_avatar && !$this->avatar)
|
||||
{
|
||||
if ($this->discord_id && $this->discord_avatar && ! $this->avatar) {
|
||||
return "https://external-content.duckduckgo.com/iu/?u={$this->discord_avatar}";
|
||||
}
|
||||
|
||||
if ($this->avatar)
|
||||
{
|
||||
if ($this->avatar) {
|
||||
return Storage::url($this->avatar);
|
||||
}
|
||||
|
||||
@@ -157,7 +157,11 @@ class User extends Authenticatable
|
||||
return;
|
||||
}
|
||||
|
||||
$this->roles = array_diff($this->roles, [$role->value]);
|
||||
$this->roles = collect($this->roles)
|
||||
->reject(fn ($value) => $value === $role->value)
|
||||
->values()
|
||||
->all();
|
||||
|
||||
$this->save();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,8 +2,8 @@
|
||||
|
||||
namespace App\Models;
|
||||
|
||||
use Illuminate\Database\Eloquent\Relations\BelongsTo;
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
use Illuminate\Database\Eloquent\Relations\BelongsTo;
|
||||
|
||||
class UserDownload extends Model
|
||||
{
|
||||
|
||||
@@ -2,8 +2,8 @@
|
||||
|
||||
namespace App\Models;
|
||||
|
||||
use Illuminate\Database\Eloquent\Relations\BelongsTo;
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
use Illuminate\Database\Eloquent\Relations\BelongsTo;
|
||||
|
||||
class Watched extends Model
|
||||
{
|
||||
|
||||
@@ -3,8 +3,6 @@
|
||||
namespace App\Notifications;
|
||||
|
||||
use Illuminate\Bus\Queueable;
|
||||
use Illuminate\Contracts\Queue\ShouldQueue;
|
||||
use Illuminate\Notifications\Messages\MailMessage;
|
||||
use Illuminate\Notifications\Notification;
|
||||
|
||||
class CommentNotification extends Notification
|
||||
@@ -12,7 +10,9 @@ class CommentNotification extends Notification
|
||||
use Queueable;
|
||||
|
||||
protected $type;
|
||||
|
||||
protected $message;
|
||||
|
||||
protected $url;
|
||||
|
||||
/**
|
||||
|
||||
@@ -2,8 +2,9 @@
|
||||
|
||||
namespace App\Policies;
|
||||
|
||||
use App\Models\User;
|
||||
use App\Enums\UserRole;
|
||||
use App\Models\Comment;
|
||||
use App\Models\User;
|
||||
use Illuminate\Auth\Access\HandlesAuthorization;
|
||||
|
||||
class CommentPolicy
|
||||
@@ -17,6 +18,26 @@ class CommentPolicy
|
||||
|
||||
public function destroy(User $user, Comment $comment): bool
|
||||
{
|
||||
if ($user->hasRole(UserRole::ADMINISTRATOR) ||
|
||||
$user->hasRole(UserRole::MODERATOR)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return $user->id === $comment->user_id;
|
||||
}
|
||||
|
||||
public function restore(User $user, Comment $comment): bool
|
||||
{
|
||||
// Comment not deleted
|
||||
if ($comment->deleted_by_moderator_id === null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if ($user->hasRole(UserRole::ADMINISTRATOR) ||
|
||||
$user->hasRole(UserRole::MODERATOR)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -4,6 +4,8 @@ namespace App\Providers;
|
||||
|
||||
use Illuminate\Support\Facades\Event;
|
||||
use Illuminate\Support\ServiceProvider;
|
||||
use SocialiteProviders\Discord\Provider;
|
||||
use SocialiteProviders\Manager\SocialiteWasCalled;
|
||||
|
||||
class AppServiceProvider extends ServiceProvider
|
||||
{
|
||||
@@ -20,8 +22,8 @@ class AppServiceProvider extends ServiceProvider
|
||||
*/
|
||||
public function boot(): void
|
||||
{
|
||||
Event::listen(function (\SocialiteProviders\Manager\SocialiteWasCalled $event) {
|
||||
$event->extendSocialite('discord', \SocialiteProviders\Discord\Provider::class);
|
||||
Event::listen(function (SocialiteWasCalled $event) {
|
||||
$event->extendSocialite('discord', Provider::class);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,130 @@
|
||||
<?php
|
||||
|
||||
namespace App\Rules;
|
||||
|
||||
use AltchaOrg\Altcha\Algorithm\Pbkdf2;
|
||||
use AltchaOrg\Altcha\Altcha;
|
||||
use AltchaOrg\Altcha\Challenge;
|
||||
use AltchaOrg\Altcha\ChallengeParameters;
|
||||
use AltchaOrg\Altcha\Payload;
|
||||
use AltchaOrg\Altcha\Solution;
|
||||
use AltchaOrg\Altcha\VerifySolutionOptions;
|
||||
use Closure;
|
||||
use Illuminate\Contracts\Validation\ValidationRule;
|
||||
use Illuminate\Translation\PotentiallyTranslatedString;
|
||||
|
||||
/**
|
||||
* Validation rule to verify captcha solution.
|
||||
*/
|
||||
class ValidCaptcha implements ValidationRule
|
||||
{
|
||||
/**
|
||||
* Altcha instance.
|
||||
*/
|
||||
protected Altcha $altcha;
|
||||
|
||||
/**
|
||||
* Pbkdf2 algorithm instance.
|
||||
*/
|
||||
protected Pbkdf2 $pbkdf2;
|
||||
|
||||
/**
|
||||
* Class constructor.
|
||||
*/
|
||||
public function __construct()
|
||||
{
|
||||
$this->pbkdf2 = new Pbkdf2;
|
||||
$this->altcha = new Altcha(
|
||||
hmacSignatureSecret: config('captcha.hmac_key'),
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse payload and return the decoded data as an array.
|
||||
*/
|
||||
private function parsePayload(string $value): ?array
|
||||
{
|
||||
$decoded = base64_decode($value, true);
|
||||
if ($decoded === false) {
|
||||
return null;
|
||||
}
|
||||
|
||||
$payload = json_decode($decoded, true);
|
||||
if (! is_array($payload)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return $payload;
|
||||
}
|
||||
|
||||
/**
|
||||
* Verify if payload has required fields.
|
||||
*/
|
||||
private function verifyFields(array $payload): bool
|
||||
{
|
||||
if (! isset($payload['challenge'], $payload['solution'])) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (! is_array($payload['challenge']) || ! is_array($payload['solution'])) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a Challenge object from challenge data.
|
||||
*/
|
||||
private function createChallenge(array $challengeData): Challenge
|
||||
{
|
||||
return new Challenge(
|
||||
ChallengeParameters::fromArray($challengeData['parameters'] ?? []),
|
||||
$challengeData['signature'] ?? null,
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a Solution object from solution data.
|
||||
*/
|
||||
private function createSolution(array $solutionData): Solution
|
||||
{
|
||||
return new Solution(
|
||||
counter: (int) ($solutionData['counter'] ?? 0),
|
||||
derivedKey: (string) ($solutionData['derivedKey'] ?? ''),
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Run the validation rule.
|
||||
*
|
||||
* @param Closure(string, ?string=): PotentiallyTranslatedString $fail
|
||||
*/
|
||||
public function validate(string $attribute, mixed $value, Closure $fail): void
|
||||
{
|
||||
$payload = $this->parsePayload($value);
|
||||
if (! $payload) {
|
||||
$fail('Invalid captcha.');
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if (! $this->verifyFields($payload)) {
|
||||
$fail('Invalid captcha.');
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
$challenge = $this->createChallenge($payload['challenge']);
|
||||
$solution = $this->createSolution($payload['solution']);
|
||||
|
||||
$result = $this->altcha->verifySolution(new VerifySolutionOptions(
|
||||
algorithm: $this->pbkdf2,
|
||||
payload: new Payload($challenge, $solution),
|
||||
));
|
||||
|
||||
if (! $result->verified) {
|
||||
$fail('Invalid captcha.');
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -2,11 +2,9 @@
|
||||
|
||||
namespace App\Services;
|
||||
|
||||
use App\Jobs\GetFileSizeFromCDN;
|
||||
use App\Models\Downloads;
|
||||
use App\Models\Episode;
|
||||
|
||||
use App\Jobs\GetFileSizeFromCDN;
|
||||
|
||||
use Illuminate\Http\Request;
|
||||
|
||||
class DownloadService
|
||||
|
||||
@@ -5,14 +5,13 @@ namespace App\Services;
|
||||
use App\Models\Episode;
|
||||
use App\Models\Hentai;
|
||||
use App\Models\Studios;
|
||||
|
||||
use App\Models\ModLog;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Support\Carbon;
|
||||
use Illuminate\Support\Str;
|
||||
use Illuminate\Support\Facades\Storage;
|
||||
|
||||
use Intervention\Image\Laravel\Facades\Image;
|
||||
use Illuminate\Support\Str;
|
||||
use Intervention\Image\Encoders\WebpEncoder;
|
||||
use Intervention\Image\Laravel\Facades\Image;
|
||||
|
||||
class EpisodeService
|
||||
{
|
||||
@@ -24,6 +23,7 @@ class EpisodeService
|
||||
|
||||
if (is_numeric($lastPart) && $lastPart < 1000) {
|
||||
$slugParts[array_key_last($slugParts)] = 's'.$lastPart;
|
||||
|
||||
return implode('-', $slugParts);
|
||||
}
|
||||
|
||||
@@ -36,11 +36,10 @@ class EpisodeService
|
||||
int $episodeNumber,
|
||||
?Studios $studio = null,
|
||||
?Episode $referenceEpisode = null
|
||||
): Episode
|
||||
{
|
||||
$episode = new Episode();
|
||||
): Episode {
|
||||
$episode = new Episode;
|
||||
$episode->title = $referenceEpisode->title ?? $request->input('title');
|
||||
$episode->title_search = preg_replace("/[^A-Za-z0-9 ]/", '', $episode->title);
|
||||
$episode->title_search = preg_replace('/[^A-Za-z0-9 ]/', '', $episode->title);
|
||||
$episode->title_jpn = $referenceEpisode->title_jpn ?? $request->input('title_jpn');
|
||||
$episode->slug = "{$hentai->slug}-{$episodeNumber}";
|
||||
$episode->hentai_id = $hentai->id;
|
||||
@@ -64,6 +63,68 @@ class EpisodeService
|
||||
return $episode;
|
||||
}
|
||||
|
||||
private function applyTags(Request $request, Episode $episode): void
|
||||
{
|
||||
$tags = json_decode($request->input('tags'));
|
||||
$newtags = [];
|
||||
foreach ($tags as $t) {
|
||||
$newtags[] = $t->value;
|
||||
}
|
||||
|
||||
$newTagsTemp = $newtags;
|
||||
$oldTagsTemp = $episode->tagNames();
|
||||
|
||||
sort($newTagsTemp);
|
||||
sort($oldTagsTemp);
|
||||
|
||||
if ($newTagsTemp !== $oldTagsTemp) {
|
||||
ModLog::create([
|
||||
'moderator' => $request->user()->name,
|
||||
'data' => sprintf(
|
||||
'Updated Episode tags from %s to %s',
|
||||
implode(', ', $oldTagsTemp),
|
||||
implode(', ', $newTagsTemp),
|
||||
),
|
||||
]);
|
||||
}
|
||||
|
||||
$episode->retag($newtags);
|
||||
}
|
||||
|
||||
private function updateTitle(Request $request, Episode $episode): void
|
||||
{
|
||||
$updates = [];
|
||||
|
||||
if ($episode->title !== $request->input('title')) {
|
||||
$updates['title'] = $request->input('title');
|
||||
$updates['title_search'] = preg_replace(
|
||||
'/[^A-Za-z0-9 ]/',
|
||||
'',
|
||||
$request->input('title')
|
||||
);
|
||||
|
||||
// Log to ModLog
|
||||
ModLog::create([
|
||||
'moderator' => $request->user()->name,
|
||||
'data' => "Updating Hentai Title from {$episode->title} to {$request->input('title')}",
|
||||
]);
|
||||
}
|
||||
|
||||
if ($episode->title_jpn !== $request->input('title_jpn')) {
|
||||
$updates['title_jpn'] = $request->input('title_jpn');
|
||||
|
||||
// Log to ModLog
|
||||
ModLog::create([
|
||||
'moderator' => $request->user()->name,
|
||||
'data' => "Updating Hentai Title from {$episode->title_jpn} to {$request->input('title_jpn')}",
|
||||
]);
|
||||
}
|
||||
|
||||
if (! empty($updates)) {
|
||||
$episode->hentai->episodes()->update($updates);
|
||||
}
|
||||
}
|
||||
|
||||
public function updateEpisode(Request $request, Studios $studio, int $episodeId): Episode
|
||||
{
|
||||
$episode = Episode::where('id', $episodeId)->firstOrFail();
|
||||
@@ -77,17 +138,31 @@ class EpisodeService
|
||||
$episode->dmca_takedown = $request->input('dmca_takedown') == 'true';
|
||||
$episode->save();
|
||||
|
||||
// Tagging
|
||||
$tags = json_decode($request->input('tags'));
|
||||
$newtags = [];
|
||||
foreach ($tags as $t) {
|
||||
$newtags[] = $t->value;
|
||||
}
|
||||
$episode->retag($newtags);
|
||||
$this->applyTags($request, $episode);
|
||||
$this->updateTitle($request, $episode);
|
||||
|
||||
return $episode;
|
||||
}
|
||||
|
||||
public function updateEpisodeModerator(Request $request, int $episodeId): void
|
||||
{
|
||||
$episode = Episode::where('id', $episodeId)->firstOrFail();
|
||||
$oldDescription = $episode->description;
|
||||
$episode->description = $request->input('description');
|
||||
$episode->save();
|
||||
|
||||
if ($episode->description !== $oldDescription) {
|
||||
// Log to ModLog
|
||||
ModLog::create([
|
||||
'moderator' => $request->user()->name,
|
||||
'data' => "Updated Episode description from {$oldDescription} to {$episode->description}",
|
||||
]);
|
||||
}
|
||||
|
||||
$this->applyTags($request, $episode);
|
||||
$this->updateTitle($request, $episode);
|
||||
}
|
||||
|
||||
public function getOrCreateStudio(string $studioName): Studios
|
||||
{
|
||||
return Studios::firstOrCreate(
|
||||
@@ -96,7 +171,6 @@ class EpisodeService
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
public function createOrUpdateCover(Request $request, Episode $episode, string $slug, int $episodeNumber): void
|
||||
{
|
||||
if (! $request->hasFile("episodecover{$episodeNumber}")) {
|
||||
@@ -111,7 +185,7 @@ class EpisodeService
|
||||
// Encode and save cover image
|
||||
Image::read($request->file("episodecover{$episodeNumber}")->getRealPath())
|
||||
->cover(268, 394)
|
||||
->encode(new WebpEncoder())
|
||||
->encode(new WebpEncoder)
|
||||
->save(Storage::disk('public')->path($episode->cover_url));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,17 +5,13 @@ namespace App\Services;
|
||||
use App\Models\Episode;
|
||||
use App\Models\Gallery;
|
||||
use App\Models\Hentai;
|
||||
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Support\Facades\File;
|
||||
use Illuminate\Support\Facades\Storage;
|
||||
|
||||
use Intervention\Image\Laravel\Facades\Image;
|
||||
use Intervention\Image\Encoders\WebpEncoder;
|
||||
use Intervention\Image\Laravel\Facades\Image;
|
||||
|
||||
class GalleryService
|
||||
{
|
||||
|
||||
public function createOrUpdateGallery(Request $request, Hentai $hentai, Episode $episode, int $episodeNumber, bool $override = false): void
|
||||
{
|
||||
$galleryInputNumber = $override ? 1 : $episodeNumber;
|
||||
@@ -45,7 +41,7 @@ class GalleryService
|
||||
|
||||
private function createGallery(Hentai $hentai, Episode $episode, int $episodeNumber, int $counter): Gallery
|
||||
{
|
||||
$gallery = new Gallery();
|
||||
$gallery = new Gallery;
|
||||
$gallery->hentai_id = $hentai->id;
|
||||
$gallery->episode_id = $episode->id;
|
||||
$gallery->image_url = "/images/hentai/{$hentai->slug}/gallery-ep-{$episodeNumber}-{$counter}.webp";
|
||||
@@ -59,12 +55,12 @@ class GalleryService
|
||||
{
|
||||
Image::read($sourceImage->getRealPath())
|
||||
->cover(1920, 1080)
|
||||
->encode(new WebpEncoder())
|
||||
->encode(new WebpEncoder)
|
||||
->save(Storage::disk('public')->path($gallery->image_url));
|
||||
|
||||
Image::read($sourceImage->getRealPath())
|
||||
->cover(960, 540)
|
||||
->encode(new WebpEncoder())
|
||||
->encode(new WebpEncoder)
|
||||
->save(Storage::disk('public')->path($gallery->thumbnail_url));
|
||||
}
|
||||
|
||||
|
||||
@@ -15,7 +15,7 @@ class MatrixRegistrationService
|
||||
$nonceResponse = Http::get("$server/_synapse/admin/v1/register");
|
||||
|
||||
if (! $nonceResponse->ok()) {
|
||||
throw new \Exception("Could not fetch nonce from Matrix.");
|
||||
throw new \Exception('Could not fetch nonce from Matrix.');
|
||||
}
|
||||
|
||||
$nonce = $nonceResponse->json()['nonce'];
|
||||
@@ -26,7 +26,7 @@ class MatrixRegistrationService
|
||||
$nonce."\0".
|
||||
$username."\0".
|
||||
$password."\0".
|
||||
"notadmin",
|
||||
'notadmin',
|
||||
$secret
|
||||
);
|
||||
|
||||
|
||||
@@ -0,0 +1,79 @@
|
||||
<?php
|
||||
|
||||
namespace App\Services;
|
||||
|
||||
use App\Enums\UserRole;
|
||||
use App\Models\User;
|
||||
use Exception;
|
||||
use Illuminate\Contracts\Encryption\DecryptException;
|
||||
use Illuminate\Support\Facades\Crypt;
|
||||
use Illuminate\Support\Facades\Http;
|
||||
use Illuminate\Support\Str;
|
||||
|
||||
class SubscriptionService
|
||||
{
|
||||
private function generateEncryptedPayload(string $subscriptionKey): string
|
||||
{
|
||||
return base64_encode(Crypt::encryptString(json_encode([
|
||||
'subscription_access_key' => $subscriptionKey,
|
||||
'timestamp' => now()->timestamp,
|
||||
'nonce' => Str::uuid()->toString(),
|
||||
], JSON_THROW_ON_ERROR)));
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the subscription status from the subscription service.
|
||||
*/
|
||||
private function getSubscriptionStatus(string $subscriptionKey): array | null
|
||||
{
|
||||
try {
|
||||
$payload = $this->generateEncryptedPayload($subscriptionKey);
|
||||
|
||||
$response = Http::post(config('services.subscription_service_host').'/api/membership/verify', [
|
||||
'payload' => $payload,
|
||||
]);
|
||||
|
||||
if (! $response->successful()) {
|
||||
logger()->error('Subscription Service API error', [
|
||||
'status' => $response->status(),
|
||||
'body' => $response->body(),
|
||||
]);
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
$encryptedResponse = $response->json('payload');
|
||||
|
||||
$json = json_decode(
|
||||
Crypt::decryptString($encryptedResponse),
|
||||
true,
|
||||
flags: JSON_THROW_ON_ERROR
|
||||
);
|
||||
|
||||
return $json;
|
||||
} catch (Exception $e) {
|
||||
logger()->error('getSubscriptionStatus Exception', [
|
||||
'details' => $e,
|
||||
]);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public function checkSubscriptionStatus(User $user, string $subscriptionKey): bool
|
||||
{
|
||||
$subscriptionStatus = $this->getSubscriptionStatus($subscriptionKey);
|
||||
if (!$subscriptionStatus) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if ($subscriptionStatus['valid'] === true &&
|
||||
$subscriptionStatus['active'] === true) {
|
||||
$user->addRole(UserRole::SUPPORTER);
|
||||
return true;
|
||||
}
|
||||
|
||||
$user->removeRole(UserRole::SUPPORTER);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
+9
-4
@@ -1,5 +1,10 @@
|
||||
<?php
|
||||
|
||||
use App\Exceptions\Handler;
|
||||
use App\Http\Kernel;
|
||||
use Illuminate\Contracts\Debug\ExceptionHandler;
|
||||
use Illuminate\Foundation\Application;
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Create The Application
|
||||
@@ -11,7 +16,7 @@
|
||||
|
|
||||
*/
|
||||
|
||||
$app = new Illuminate\Foundation\Application(
|
||||
$app = new Application(
|
||||
$_ENV['APP_BASE_PATH'] ?? dirname(__DIR__)
|
||||
);
|
||||
|
||||
@@ -28,7 +33,7 @@ $app = new Illuminate\Foundation\Application(
|
||||
|
||||
$app->singleton(
|
||||
Illuminate\Contracts\Http\Kernel::class,
|
||||
App\Http\Kernel::class
|
||||
Kernel::class
|
||||
);
|
||||
|
||||
$app->singleton(
|
||||
@@ -37,8 +42,8 @@ $app->singleton(
|
||||
);
|
||||
|
||||
$app->singleton(
|
||||
Illuminate\Contracts\Debug\ExceptionHandler::class,
|
||||
App\Exceptions\Handler::class
|
||||
ExceptionHandler::class,
|
||||
Handler::class
|
||||
);
|
||||
|
||||
/*
|
||||
|
||||
+2
-1
@@ -9,7 +9,7 @@
|
||||
"license": "MIT",
|
||||
"require": {
|
||||
"php": "^8.2",
|
||||
"grantholle/laravel-altcha": "^2.1",
|
||||
"altcha-org/altcha": "^2.0",
|
||||
"guzzlehttp/guzzle": "^7.8.1",
|
||||
"hisorange/browser-detect": "^5.0",
|
||||
"http-interop/http-factory-guzzle": "^1.2",
|
||||
@@ -28,6 +28,7 @@
|
||||
"rtconner/laravel-tagging": "^5.0",
|
||||
"socialiteproviders/discord": "^4.2",
|
||||
"spatie/laravel-discord-alerts": "^1.8",
|
||||
"spatie/laravel-passkeys": "^1.7",
|
||||
"spatie/laravel-sitemap": "^7.3"
|
||||
},
|
||||
"require-dev": {
|
||||
|
||||
Generated
+1807
-753
File diff suppressed because it is too large
Load Diff
+10
-5
@@ -1,7 +1,12 @@
|
||||
<?php
|
||||
|
||||
use App\Providers\AppServiceProvider;
|
||||
use App\Providers\AuthServiceProvider;
|
||||
use App\Providers\EventServiceProvider;
|
||||
use App\Providers\RouteServiceProvider;
|
||||
use Illuminate\Support\Facades\Facade;
|
||||
use Illuminate\Support\ServiceProvider;
|
||||
use Mews\Captcha\Facades\Captcha;
|
||||
|
||||
return [
|
||||
|
||||
@@ -175,11 +180,11 @@ return [
|
||||
/*
|
||||
* Application Service Providers...
|
||||
*/
|
||||
App\Providers\AppServiceProvider::class,
|
||||
App\Providers\AuthServiceProvider::class,
|
||||
AppServiceProvider::class,
|
||||
AuthServiceProvider::class,
|
||||
// App\Providers\BroadcastServiceProvider::class,
|
||||
App\Providers\EventServiceProvider::class,
|
||||
App\Providers\RouteServiceProvider::class,
|
||||
EventServiceProvider::class,
|
||||
RouteServiceProvider::class,
|
||||
])->toArray(),
|
||||
|
||||
/*
|
||||
@@ -195,7 +200,7 @@ return [
|
||||
|
||||
'aliases' => Facade::defaultAliases()->merge([
|
||||
// 'Example' => App\Facades\Example::class,
|
||||
'Captcha' => Mews\Captcha\Facades\Captcha::class,
|
||||
'Captcha' => Captcha::class,
|
||||
])->toArray(),
|
||||
|
||||
];
|
||||
|
||||
+3
-1
@@ -1,5 +1,7 @@
|
||||
<?php
|
||||
|
||||
use App\Models\User;
|
||||
|
||||
return [
|
||||
|
||||
/*
|
||||
@@ -62,7 +64,7 @@ return [
|
||||
'providers' => [
|
||||
'users' => [
|
||||
'driver' => 'eloquent',
|
||||
'model' => App\Models\User::class,
|
||||
'model' => User::class,
|
||||
],
|
||||
|
||||
// 'users' => [
|
||||
|
||||
@@ -0,0 +1,9 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* Altcha Captcha System
|
||||
*/
|
||||
|
||||
return [
|
||||
'hmac_key' => env('ALTCHA_HMAC_KEY'),
|
||||
];
|
||||
@@ -1,5 +1,7 @@
|
||||
<?php
|
||||
|
||||
use Spatie\DiscordAlerts\Jobs\SendToDiscordChannelJob;
|
||||
|
||||
return [
|
||||
/*
|
||||
* The webhook URLs that we'll use to send a message to Discord.
|
||||
@@ -14,5 +16,5 @@ return [
|
||||
* This job will send the message to Discord. You can extend this
|
||||
* job to set timeouts, retries, etc...
|
||||
*/
|
||||
'job' => Spatie\DiscordAlerts\Jobs\SendToDiscordChannelJob::class,
|
||||
'job' => SendToDiscordChannelJob::class,
|
||||
];
|
||||
|
||||
+1
-1
@@ -12,7 +12,7 @@ return [
|
||||
'803325441942356059', // Tier-3
|
||||
'803322725576736858', // Tier-2
|
||||
'802270568912519198', // Tier-1
|
||||
'802234830384267315' // admin
|
||||
'802234830384267315', // admin
|
||||
],
|
||||
|
||||
'discord_bot_token' => env('DISCORD_BOT_TOKEN'),
|
||||
|
||||
+2
-2
@@ -30,11 +30,11 @@ return [
|
||||
|
||||
// Asia Fallback (HTTP)
|
||||
'asia_download_domain' => [
|
||||
'https://komako-b-ddl.musume-h.xyz'
|
||||
'https://komako-b-ddl.musume-h.xyz',
|
||||
],
|
||||
|
||||
'asia_stream_domain' => [
|
||||
'https://komako-b-str.musume-h.xyz'
|
||||
'https://komako-b-str.musume-h.xyz',
|
||||
],
|
||||
|
||||
// Free 4k Downloads
|
||||
|
||||
+4
-2
@@ -1,5 +1,7 @@
|
||||
<?php
|
||||
|
||||
use Intervention\Image\Drivers\Gd\Driver;
|
||||
|
||||
return [
|
||||
|
||||
/*
|
||||
@@ -16,7 +18,7 @@ return [
|
||||
|
|
||||
*/
|
||||
|
||||
'driver' => \Intervention\Image\Drivers\Gd\Driver::class,
|
||||
'driver' => Driver::class,
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
@@ -38,5 +40,5 @@ return [
|
||||
'autoOrientation' => true,
|
||||
'decodeAnimation' => true,
|
||||
'blendingColor' => 'ffffff',
|
||||
]
|
||||
],
|
||||
];
|
||||
|
||||
@@ -0,0 +1,49 @@
|
||||
<?php
|
||||
|
||||
use App\Models\User;
|
||||
use Spatie\LaravelPasskeys\Actions\ConfigureCeremonyStepManagerFactoryAction;
|
||||
use Spatie\LaravelPasskeys\Actions\FindPasskeyToAuthenticateAction;
|
||||
use Spatie\LaravelPasskeys\Actions\GeneratePasskeyAuthenticationOptionsAction;
|
||||
use Spatie\LaravelPasskeys\Actions\GeneratePasskeyRegisterOptionsAction;
|
||||
use Spatie\LaravelPasskeys\Actions\StorePasskeyAction;
|
||||
use Spatie\LaravelPasskeys\Models\Passkey;
|
||||
|
||||
return [
|
||||
/*
|
||||
* After a successful authentication attempt using a passkey
|
||||
* we'll redirect to this URL.
|
||||
*/
|
||||
'redirect_to_after_login' => '/',
|
||||
|
||||
/*
|
||||
* These class are responsible for performing core tasks regarding passkeys.
|
||||
* You can customize them by creating a class that extends the default, and
|
||||
* by specifying your custom class name here.
|
||||
*/
|
||||
'actions' => [
|
||||
'generate_passkey_register_options' => GeneratePasskeyRegisterOptionsAction::class,
|
||||
'store_passkey' => StorePasskeyAction::class,
|
||||
'generate_passkey_authentication_options' => GeneratePasskeyAuthenticationOptionsAction::class,
|
||||
'find_passkey' => FindPasskeyToAuthenticateAction::class,
|
||||
'configure_ceremony_step_manager_factory' => ConfigureCeremonyStepManagerFactoryAction::class,
|
||||
],
|
||||
|
||||
/*
|
||||
* These properties will be used to generate the passkey.
|
||||
*/
|
||||
'relying_party' => [
|
||||
'name' => config('app.name'),
|
||||
'id' => parse_url(config('app.url'), PHP_URL_HOST),
|
||||
'icon' => null,
|
||||
],
|
||||
|
||||
/*
|
||||
* The models used by the package.
|
||||
*
|
||||
* You can override this by specifying your own models
|
||||
*/
|
||||
'models' => [
|
||||
'passkey' => Passkey::class,
|
||||
'authenticatable' => env('AUTH_MODEL', User::class),
|
||||
],
|
||||
];
|
||||
+6
-3
@@ -1,5 +1,8 @@
|
||||
<?php
|
||||
|
||||
use Illuminate\Cookie\Middleware\EncryptCookies;
|
||||
use Illuminate\Foundation\Http\Middleware\ValidateCsrfToken;
|
||||
use Laravel\Sanctum\Http\Middleware\AuthenticateSession;
|
||||
use Laravel\Sanctum\Sanctum;
|
||||
|
||||
return [
|
||||
@@ -60,9 +63,9 @@ return [
|
||||
*/
|
||||
|
||||
'middleware' => [
|
||||
'authenticate_session' => Laravel\Sanctum\Http\Middleware\AuthenticateSession::class,
|
||||
'encrypt_cookies' => Illuminate\Cookie\Middleware\EncryptCookies::class,
|
||||
'validate_csrf_token' => Illuminate\Foundation\Http\Middleware\ValidateCsrfToken::class,
|
||||
'authenticate_session' => AuthenticateSession::class,
|
||||
'encrypt_cookies' => EncryptCookies::class,
|
||||
'validate_csrf_token' => ValidateCsrfToken::class,
|
||||
],
|
||||
|
||||
];
|
||||
|
||||
+2
-2
@@ -149,12 +149,12 @@ return [
|
||||
'title_jpn',
|
||||
'slug',
|
||||
'description',
|
||||
'tags'
|
||||
'tags',
|
||||
],
|
||||
'sortableAttributes' => [
|
||||
'created_at',
|
||||
'release_date',
|
||||
'title'
|
||||
'title',
|
||||
],
|
||||
],
|
||||
],
|
||||
|
||||
@@ -54,4 +54,9 @@ return [
|
||||
'server' => env('MATRIX_SERVER'),
|
||||
'shared_secret' => env('MATRIX_SHARED_SECRET'),
|
||||
],
|
||||
|
||||
/**
|
||||
* Subscription Service
|
||||
*/
|
||||
'subscription_service_host' => env('SUBSCRIPTION_SERVICE_HOST'),
|
||||
];
|
||||
|
||||
@@ -263,5 +263,4 @@ return [
|
||||
'confirm_delete_icon' => env('SWEET_ALERT_CONFIRM_DELETE_ICON', 'warning'),
|
||||
'confirm_delete_show_loader_on_confirm' => env('SWEET_ALERT_CONFIRM_DELETE_SHOW_LOADER_ON_CONFIRM', true),
|
||||
|
||||
|
||||
];
|
||||
|
||||
@@ -2,11 +2,11 @@
|
||||
|
||||
namespace Database\Factories;
|
||||
|
||||
use App\Models\Studios;
|
||||
use App\Models\Episode;
|
||||
use Illuminate\Database\Eloquent\Factories\Factory;
|
||||
|
||||
/**
|
||||
* @extends \Illuminate\Database\Eloquent\Factories\Factory<\App\Models\Episode>
|
||||
* @extends Factory<Episode>
|
||||
*/
|
||||
class EpisodeFactory extends Factory
|
||||
{
|
||||
|
||||
@@ -2,10 +2,11 @@
|
||||
|
||||
namespace Database\Factories;
|
||||
|
||||
use App\Models\Hentai;
|
||||
use Illuminate\Database\Eloquent\Factories\Factory;
|
||||
|
||||
/**
|
||||
* @extends \Illuminate\Database\Eloquent\Factories\Factory<\App\Models\Hentai>
|
||||
* @extends Factory<Hentai>
|
||||
*/
|
||||
class HentaiFactory extends Factory
|
||||
{
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user