mirror of
https://github.com/BillyOutlast/UNIT3D.git
synced 2026-02-04 03:01:20 +01:00
Merge pull request #4929 from HDInnovations/development
(Release) UNIT3D v9.1.6
This commit is contained in:
@@ -10,6 +10,7 @@ limewire
|
||||
mal
|
||||
mediainfo
|
||||
phpstorm
|
||||
rottentomatoes
|
||||
shareaza
|
||||
tmdb
|
||||
tvdb
|
||||
|
||||
@@ -71,9 +71,13 @@ class AutoRemoveTimedTorrentBuffs extends Command
|
||||
Unit3dAnnounce::addTorrent($torrent);
|
||||
}
|
||||
|
||||
Torrent::query()->whereNotNull('bumped_at')->where('bumped_at', '<', now()->subWeek())->update([
|
||||
'bumped_at' => DB::raw('created_at'),
|
||||
]);
|
||||
Torrent::query()
|
||||
->whereNotNull('bumped_at')
|
||||
->where('bumped_at', '<', now()->subWeek())
|
||||
->whereColumn('bumped_at', '!=', 'created_at')
|
||||
->update([
|
||||
'bumped_at' => DB::raw('created_at'),
|
||||
]);
|
||||
|
||||
$this->comment('Automated Removal Of Expired Torrent Buffs Command Complete');
|
||||
}
|
||||
|
||||
@@ -448,7 +448,10 @@ readonly class TorrentSearchFiltersDTO
|
||||
$filters[] = 'user.username = '.json_encode($this->uploader);
|
||||
|
||||
if (!$group->is_modo) {
|
||||
$filters[] = 'anon = false';
|
||||
$filters[] = [
|
||||
'anon = false',
|
||||
'user.username = '.json_encode($this->user->username),
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -183,8 +183,8 @@ class Bbcode
|
||||
'code' => [
|
||||
'openBbcode' => '/^\[code\]/i',
|
||||
'closeBbcode' => '[/code]',
|
||||
'openHtml' => '<pre>',
|
||||
'closeHtml' => '</pre>',
|
||||
'openHtml' => '<div class="bbcode-rendered__clipboard" x-data="clipboardButton"><pre><code>',
|
||||
'closeHtml' => '</code></pre><div class="bbcode-rendered__clipboard-container"><button class="bbcode-rendered__clipboard-button" x-bind="button"><i class="fa fa-clone"></i></button></div></div>',
|
||||
'block' => true,
|
||||
],
|
||||
'pre' => [
|
||||
|
||||
@@ -56,6 +56,16 @@ if (!\function_exists('href_request')) {
|
||||
}
|
||||
}
|
||||
|
||||
if (!\function_exists('href_rottentomatoes')) {
|
||||
function href_rottentomatoes(string|null $title, string|null $date): string
|
||||
{
|
||||
$year = substr($date ?? '', 0, 4);
|
||||
$query = "{$title} ({$year}) site:rottentomatoes.com";
|
||||
|
||||
return "https://html.duckduckgo.com/html/?q=\\".rawurlencode($query);
|
||||
}
|
||||
}
|
||||
|
||||
if (!\function_exists('href_poll')) {
|
||||
function href_poll(App\Models\Poll $poll): string
|
||||
{
|
||||
|
||||
@@ -48,6 +48,7 @@ class TorrentTools
|
||||
|
||||
$result['info']['source'] = config('torrent.source');
|
||||
$result['info']['private'] = 1;
|
||||
$result['info']['entropy'] = bin2hex(random_bytes(64));
|
||||
|
||||
if (config('torrent.created_by_append') && \array_key_exists('created by', $result)) {
|
||||
$result['created by'] = trim((string) $result['created by'], '. ').'. '.config('torrent.created_by', '');
|
||||
|
||||
@@ -420,7 +420,7 @@ class ChatController extends Controller
|
||||
}
|
||||
|
||||
/* USERS */
|
||||
public function updateUserChatStatus(Request $request): \Illuminate\Http\JsonResponse
|
||||
public function updateUserChatStatus(Request $request): \Illuminate\Contracts\Routing\ResponseFactory|\Illuminate\Http\Response
|
||||
{
|
||||
$user = $request->user();
|
||||
$user->load(['chatStatus', 'chatroom', 'group', 'echoes']);
|
||||
@@ -432,7 +432,7 @@ class ChatController extends Controller
|
||||
$user->chatStatus()->associate($status);
|
||||
$user->save();
|
||||
|
||||
return response()->json($user);
|
||||
return response('success');
|
||||
}
|
||||
|
||||
public function updateUserRoom(Request $request): \Illuminate\Http\JsonResponse
|
||||
|
||||
@@ -27,7 +27,7 @@ class QuickSearchController extends Controller
|
||||
{
|
||||
public function index(Request $request): \Illuminate\Http\JsonResponse
|
||||
{
|
||||
$query = $request->input('query');
|
||||
$query = $request->input('query', '');
|
||||
|
||||
$filters = [
|
||||
'deleted_at IS NULL',
|
||||
|
||||
@@ -671,7 +671,6 @@ class TorrentController extends BaseController
|
||||
'media_info' => $hit['mediainfo'],
|
||||
'bd_info' => $hit['bdinfo'],
|
||||
'description' => $hit['description'],
|
||||
'info_hash' => $hit['info_hash'],
|
||||
'size' => $hit['size'],
|
||||
'num_file' => $hit['num_file'],
|
||||
'files' => $hit['files'],
|
||||
|
||||
70
app/Http/Controllers/API/TorrentRequestController.php
Normal file
70
app/Http/Controllers/API/TorrentRequestController.php
Normal file
@@ -0,0 +1,70 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
/**
|
||||
* NOTICE OF LICENSE.
|
||||
*
|
||||
* UNIT3D Community Edition is open-sourced software licensed under the GNU Affero General Public License v3.0
|
||||
* The details is bundled with this project in the file LICENSE.txt.
|
||||
*
|
||||
* @project UNIT3D Community Edition
|
||||
*
|
||||
* @author HDVinnie <hdinnovations@protonmail.com>
|
||||
* @license https://www.gnu.org/licenses/agpl-3.0.en.html/ GNU Affero General Public License v3.0
|
||||
*/
|
||||
|
||||
namespace App\Http\Controllers\API;
|
||||
|
||||
use App\Http\Controllers\Controller;
|
||||
use App\Http\Resources\TorrentRequestResource;
|
||||
use App\Models\TorrentRequest;
|
||||
use Illuminate\Http\Request;
|
||||
|
||||
class RequestController extends Controller
|
||||
{
|
||||
/**
|
||||
* Request search filter.
|
||||
*/
|
||||
public function filter(Request $request): \Illuminate\Http\JsonResponse
|
||||
{
|
||||
$query = TorrentRequest::query()
|
||||
->with(['user', 'claim.user', 'filler'])
|
||||
->withSum('bounties', 'seedbonus')
|
||||
->when($request->filled('name'), fn ($query) => $query->where('name', 'LIKE', '%'.str_replace(' ', '%', $request->input('name')).'%'))
|
||||
->when($request->filled('category_id'), fn ($query) => $query->whereIntegerInRaw('category_id', (array) $request->input('category_id')))
|
||||
->when($request->filled('type_id'), fn ($query) => $query->whereIntegerInRaw('type_id', (array) $request->input('type_id')))
|
||||
->when($request->filled('resolution_id'), fn ($query) => $query->whereIntegerInRaw('resolution_id', (array) $request->input('resolution_id')))
|
||||
->when($request->filled('tmdb'), fn ($query) => $query->whereAny(['tmdb_movie_id', 'tmdb_tv_id'], '=', $request->integer('tmdb')))
|
||||
->when($request->filled('imdb'), fn ($query) => $query->where('imdb', '=', $request->integer('imdb')))
|
||||
->when($request->filled('tvdb'), fn ($query) => $query->where('tvdb', '=', $request->integer('tvdb')))
|
||||
->when($request->filled('mal'), fn ($query) => $query->where('mal', '=', $request->integer('mal')))
|
||||
->when($request->filled('filled'), fn ($query) => $request->boolean('filled')
|
||||
? $query->whereNotNull('filled_by')
|
||||
: $query->whereNull('filled_by'))
|
||||
->when($request->filled('claimed'), fn ($query) => $request->boolean('claimed')
|
||||
? $query->whereNotNull('claim')
|
||||
: $query->whereNull('claim'));
|
||||
|
||||
$perPage = min($request->integer('perPage', 25), 100);
|
||||
$page = max($request->integer('page', 1), 1);
|
||||
$requests = $query->paginate(
|
||||
perPage: $perPage,
|
||||
page: $page
|
||||
);
|
||||
|
||||
return TorrentRequestResource::collection($requests)->response();
|
||||
}
|
||||
|
||||
/**
|
||||
* View a single request.
|
||||
*/
|
||||
public function show(int $id): \Illuminate\Http\JsonResponse
|
||||
{
|
||||
$request = TorrentRequest::with(['user', 'claim.user', 'filler'])
|
||||
->withSum('bounties', 'seedbonus')
|
||||
->findOrFail($id);
|
||||
|
||||
return new TorrentRequestResource($request)->response();
|
||||
}
|
||||
}
|
||||
@@ -58,7 +58,7 @@ class RequestController extends Controller
|
||||
public function show(Request $request, TorrentRequest $torrentRequest): \Illuminate\Contracts\View\Factory|\Illuminate\View\View
|
||||
{
|
||||
return view('requests.show', [
|
||||
'torrentRequest' => $torrentRequest->load(['category', 'claim' => ['user'], 'bounties', 'torrent']),
|
||||
'torrentRequest' => $torrentRequest->load(['category', 'claim.user.group', 'bounties.user.group', 'torrent']),
|
||||
'user' => $request->user(),
|
||||
'canEdit' => $request->user()->group->is_modo || TorrentRequest::query()
|
||||
->whereDoesntHave('bounties', fn ($query) => $query->where('user_id', '!=', $request->user()->id))
|
||||
|
||||
@@ -20,7 +20,6 @@ use App\Enums\ModerationStatus;
|
||||
use App\Helpers\StringHelper;
|
||||
use App\Models\Conversation;
|
||||
use App\Services\Unit3dAnnounce;
|
||||
use Carbon\Carbon;
|
||||
use App\Models\Donation;
|
||||
use Illuminate\Http\Request;
|
||||
use App\Models\PrivateMessage;
|
||||
@@ -68,7 +67,7 @@ class DonationController extends Controller
|
||||
{
|
||||
abort_unless($request->user()->group->is_owner, 403);
|
||||
|
||||
$now = Carbon::now();
|
||||
$now = now();
|
||||
|
||||
$donation = Donation::with(['user', 'package'])->findOrFail($id);
|
||||
$donation->status = ModerationStatus::APPROVED;
|
||||
|
||||
@@ -47,7 +47,7 @@ class DonationGatewayController extends Controller
|
||||
/**
|
||||
* Store A Donation Gateway.
|
||||
*/
|
||||
public function store(StoreDonationGatewayRequest $request)
|
||||
public function store(StoreDonationGatewayRequest $request): \Illuminate\Http\RedirectResponse
|
||||
{
|
||||
abort_unless($request->user()->group->is_owner, 403);
|
||||
|
||||
@@ -83,7 +83,7 @@ class DonationGatewayController extends Controller
|
||||
/**
|
||||
* Destroy A Donation Gateway.
|
||||
*/
|
||||
public function destroy(Request $request, DonationGateway $gateway)
|
||||
public function destroy(Request $request, DonationGateway $gateway): \Illuminate\Http\RedirectResponse
|
||||
{
|
||||
abort_unless($request->user()->group->is_owner, 403);
|
||||
|
||||
|
||||
@@ -18,32 +18,67 @@ namespace App\Http\Controllers;
|
||||
|
||||
use App\Models\History;
|
||||
use App\Models\Torrent;
|
||||
use App\Models\TorrentReseed;
|
||||
use App\Models\User;
|
||||
use App\Notifications\NewReseedRequest;
|
||||
use App\Repositories\ChatRepository;
|
||||
use Illuminate\Http\Request;
|
||||
|
||||
class ReseedController extends Controller
|
||||
class TorrentReseedController extends Controller
|
||||
{
|
||||
/**
|
||||
* ReseedController Constructor.
|
||||
* TorrentReseedController Constructor.
|
||||
*/
|
||||
public function __construct(private readonly ChatRepository $chatRepository)
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* Display a listing of torrent reseed requests.
|
||||
*/
|
||||
public function index(): \Illuminate\Contracts\View\Factory|\Illuminate\Contracts\View\View|\Illuminate\Contracts\Foundation\Application
|
||||
{
|
||||
return view('torrent-reseed.index');
|
||||
}
|
||||
|
||||
/**
|
||||
* Reseed Request A Torrent.
|
||||
*/
|
||||
public function store(Request $request, int $id): \Illuminate\Http\RedirectResponse
|
||||
{
|
||||
// TODO: Store reseed requests so can be viewed in a table view.
|
||||
|
||||
$torrent = Torrent::findOrFail($id);
|
||||
$potentialReseeds = History::where('torrent_id', '=', $torrent->id)->where('active', '=', 0)->get();
|
||||
$userId = $request->user()->id;
|
||||
|
||||
// Check if this user has already made a reseed request for this torrent
|
||||
$existingUserReseed = TorrentReseed::where('torrent_id', '=', $torrent->id)
|
||||
->where('user_id', '=', $userId)
|
||||
->first();
|
||||
|
||||
if ($existingUserReseed) {
|
||||
return to_route('torrents.show', ['id' => $torrent->id])
|
||||
->withErrors('You have already made a reseed request for this torrent.');
|
||||
}
|
||||
|
||||
// Check seeders condition and if a request already exists for this torrent
|
||||
$existingReseed = TorrentReseed::where('torrent_id', '=', $torrent->id)->first();
|
||||
|
||||
if ($torrent->seeders <= 2) {
|
||||
// Send Notification
|
||||
if ($existingReseed) {
|
||||
$existingReseed->increment('requests_count');
|
||||
$existingReseed->save();
|
||||
|
||||
return to_route('torrents.show', ['id' => $torrent->id])
|
||||
->with('success', 'A reseed request already exists. Your request has been counted.');
|
||||
}
|
||||
TorrentReseed::create([
|
||||
'torrent_id' => $torrent->id,
|
||||
'user_id' => $userId,
|
||||
'requests_count' => 1,
|
||||
]);
|
||||
|
||||
// Send notifications
|
||||
$potentialReseeds = History::where('torrent_id', '=', $torrent->id)->where('active', '=', 0)->get();
|
||||
|
||||
foreach ($potentialReseeds as $potentialReseed) {
|
||||
User::find($potentialReseed->user_id)->notify(new NewReseedRequest($torrent));
|
||||
}
|
||||
@@ -77,7 +77,6 @@ class FollowController extends Controller
|
||||
|
||||
$user->notify(new NewUnfollow('user', $request->user()));
|
||||
|
||||
return to_route('users.show', ['user' => $user])
|
||||
->with('success', \sprintf(trans('user.follow-revoked'), $user->username));
|
||||
return back()->with('success', \sprintf(trans('user.follow-revoked'), $user->username));
|
||||
}
|
||||
}
|
||||
|
||||
36
app/Http/Controllers/User/UnregisteredInfoHashController.php
Normal file
36
app/Http/Controllers/User/UnregisteredInfoHashController.php
Normal file
@@ -0,0 +1,36 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
/**
|
||||
* NOTICE OF LICENSE.
|
||||
*
|
||||
* UNIT3D Community Edition is open-sourced software licensed under the GNU Affero General Public License v3.0
|
||||
* The details is bundled with this project in the file LICENSE.txt.
|
||||
*
|
||||
* @project UNIT3D Community Edition
|
||||
*
|
||||
* @author Roardom <roardom@protonmail.com>
|
||||
* @license https://www.gnu.org/licenses/agpl-3.0.en.html/ GNU Affero General Public License v3.0
|
||||
*/
|
||||
|
||||
namespace App\Http\Controllers\User;
|
||||
|
||||
use App\Http\Controllers\Controller;
|
||||
use App\Models\User;
|
||||
use Illuminate\Http\Request;
|
||||
|
||||
class UnregisteredInfoHashController extends Controller
|
||||
{
|
||||
/**
|
||||
* Show user unregistered info hashes.
|
||||
*/
|
||||
public function index(Request $request, User $user): \Illuminate\Contracts\View\Factory|\Illuminate\View\View
|
||||
{
|
||||
abort_unless($request->user()->group->is_modo || $request->user()->is($user), 403);
|
||||
|
||||
return view('user.unregistered-info-hash.index', [
|
||||
'user' => $user,
|
||||
]);
|
||||
}
|
||||
}
|
||||
@@ -231,7 +231,7 @@ class UserController extends Controller
|
||||
// Define data
|
||||
$request->validate([
|
||||
'title' => 'nullable|max:255',
|
||||
'about' => 'nullable|max:1000',
|
||||
'about' => 'nullable|max:20000',
|
||||
'signature' => 'nullable|max:1000'
|
||||
]);
|
||||
$user->title = $request->input('title');
|
||||
|
||||
@@ -18,14 +18,10 @@ namespace App\Http\Livewire;
|
||||
|
||||
use App\Models\Announce;
|
||||
use App\Traits\LivewireSort;
|
||||
use Livewire\Attributes\Computed;
|
||||
use Livewire\Attributes\Url;
|
||||
use Livewire\Component;
|
||||
use Livewire\WithPagination;
|
||||
|
||||
/**
|
||||
* @property \Illuminate\Pagination\LengthAwarePaginator<int, Announce> $announces
|
||||
*/
|
||||
class AnnounceSearch extends Component
|
||||
{
|
||||
use LivewireSort;
|
||||
@@ -59,12 +55,10 @@ class AnnounceSearch extends Component
|
||||
}
|
||||
|
||||
/**
|
||||
* @return \Illuminate\Pagination\Paginator<int, Announce>
|
||||
* @var \Illuminate\Pagination\Paginator<int, Announce>
|
||||
*/
|
||||
#[Computed]
|
||||
final public function announces(): \Illuminate\Pagination\Paginator
|
||||
{
|
||||
return Announce::query()
|
||||
protected \Illuminate\Pagination\Paginator $announces {
|
||||
get => Announce::query()
|
||||
->when($this->torrentId !== '', fn ($query) => $query->where('torrent_id', '=', $this->torrentId))
|
||||
->when($this->userId !== '', fn ($query) => $query->where('user_id', '=', $this->userId))
|
||||
->when($this->sortField !== '', fn ($query) => $query->orderBy($this->sortField, $this->sortDirection))
|
||||
|
||||
@@ -19,14 +19,10 @@ namespace App\Http\Livewire;
|
||||
use App\Models\Apikey;
|
||||
use App\Models\User;
|
||||
use App\Traits\LivewireSort;
|
||||
use Livewire\Attributes\Computed;
|
||||
use Livewire\Attributes\Url;
|
||||
use Livewire\Component;
|
||||
use Livewire\WithPagination;
|
||||
|
||||
/**
|
||||
* @property \Illuminate\Pagination\LengthAwarePaginator<int, Apikey> $apikeys
|
||||
*/
|
||||
class ApikeySearch extends Component
|
||||
{
|
||||
use LivewireSort;
|
||||
@@ -50,14 +46,13 @@ class ApikeySearch extends Component
|
||||
public int $perPage = 25;
|
||||
|
||||
/**
|
||||
* @return \Illuminate\Pagination\LengthAwarePaginator<int, Apikey>
|
||||
* @var \Illuminate\Pagination\LengthAwarePaginator<int, Apikey>
|
||||
*/
|
||||
#[Computed]
|
||||
final public function apikeys(): \Illuminate\Pagination\LengthAwarePaginator
|
||||
{
|
||||
return Apikey::with([
|
||||
'user' => fn ($query) => $query->withTrashed()->with('group'),
|
||||
])
|
||||
final protected \Illuminate\Pagination\LengthAwarePaginator $apikeys {
|
||||
get => Apikey::query()
|
||||
->with([
|
||||
'user' => fn ($query) => $query->withTrashed()->with('group'),
|
||||
])
|
||||
->when($this->username, fn ($query) => $query->whereIn('user_id', User::withTrashed()->select('id')->where('username', 'LIKE', '%'.$this->username.'%')))
|
||||
->when($this->apikey, fn ($query) => $query->where('content', 'LIKE', '%'.$this->apikey.'%'))
|
||||
->orderBy($this->sortField, $this->sortDirection)
|
||||
|
||||
@@ -19,7 +19,6 @@ namespace App\Http\Livewire;
|
||||
use App\Enums\ModerationStatus;
|
||||
use App\Models\Application;
|
||||
use App\Traits\LivewireSort;
|
||||
use Livewire\Attributes\Computed;
|
||||
use Livewire\Attributes\Url;
|
||||
use Livewire\Component;
|
||||
use Livewire\WithPagination;
|
||||
@@ -47,17 +46,17 @@ class ApplicationSearch extends Component
|
||||
public int $perPage = 25;
|
||||
|
||||
/**
|
||||
* @return \Illuminate\Pagination\LengthAwarePaginator<int, Application>
|
||||
* @var \Illuminate\Pagination\LengthAwarePaginator<int, Application>
|
||||
*/
|
||||
#[Computed]
|
||||
final public function applications(): \Illuminate\Pagination\LengthAwarePaginator
|
||||
{
|
||||
return Application::withoutGlobalScopes()->with([
|
||||
'user.group',
|
||||
'moderated.group',
|
||||
'imageProofs',
|
||||
'urlProofs'
|
||||
])
|
||||
protected \Illuminate\Pagination\LengthAwarePaginator $applications {
|
||||
get => Application::query()
|
||||
->withoutGlobalScopes()
|
||||
->with([
|
||||
'user.group',
|
||||
'moderated.group',
|
||||
'imageProofs',
|
||||
'urlProofs'
|
||||
])
|
||||
->when($this->email, fn ($query) => $query->where('email', 'LIKE', '%'.$this->email.'%'))
|
||||
->when($this->status === '1', fn ($query) => $query->where('status', '=', ModerationStatus::APPROVED))
|
||||
->when($this->status === '0', fn ($query) => $query->where('status', '=', ModerationStatus::PENDING))
|
||||
|
||||
@@ -19,7 +19,6 @@ namespace App\Http\Livewire;
|
||||
use App\Models\Ticket;
|
||||
use App\Models\TicketAttachment;
|
||||
use App\Models\User;
|
||||
use Livewire\Attributes\Computed;
|
||||
use Livewire\Attributes\Validate;
|
||||
use Livewire\Component;
|
||||
use Livewire\WithFileUploads;
|
||||
@@ -67,16 +66,16 @@ class AttachmentUpload extends Component
|
||||
}
|
||||
|
||||
/**
|
||||
* @return \Illuminate\Database\Eloquent\Collection<int, TicketAttachment>
|
||||
* @var \Illuminate\Database\Eloquent\Collection<int, TicketAttachment>
|
||||
*/
|
||||
#[Computed]
|
||||
final public function attachments(): \Illuminate\Database\Eloquent\Collection
|
||||
{
|
||||
$ticket = Ticket::find($this->ticket);
|
||||
protected \Illuminate\Database\Eloquent\Collection $attachments {
|
||||
get {
|
||||
$ticket = Ticket::find($this->ticket);
|
||||
|
||||
abort_unless($ticket->user_id === $this->user->id || $this->user->group->is_modo, 403);
|
||||
abort_unless($ticket->user_id === $this->user->id || $this->user->group->is_modo, 403);
|
||||
|
||||
return $ticket->attachments;
|
||||
return $ticket->attachments;
|
||||
}
|
||||
}
|
||||
|
||||
final public function render(): \Illuminate\Contracts\View\Factory|\Illuminate\Contracts\View\View|\Illuminate\Contracts\Foundation\Application
|
||||
|
||||
@@ -18,7 +18,6 @@ namespace App\Http\Livewire;
|
||||
|
||||
use App\Models\Audit;
|
||||
use App\Traits\Auditable;
|
||||
use Livewire\Attributes\Computed;
|
||||
use Livewire\Attributes\Url;
|
||||
use Livewire\Component;
|
||||
use Livewire\WithPagination;
|
||||
@@ -56,12 +55,10 @@ class AuditLogSearch extends Component
|
||||
public string $sortDirection = 'desc';
|
||||
|
||||
/**
|
||||
* @return string[]
|
||||
* @var string[]
|
||||
*/
|
||||
#[Computed]
|
||||
final public function modelNames(): array
|
||||
{
|
||||
return collect(scandir(app_path('Models')) ?: [])
|
||||
final protected array $modelNames {
|
||||
get => collect(scandir(app_path('Models')) ?: [])
|
||||
->filter(fn ($path) => str_ends_with($path, '.php'))
|
||||
->map(fn ($path) => 'App\\Models\\'.basename($path, '.php'))
|
||||
->filter(fn ($class) => class_exists($class))
|
||||
@@ -73,25 +70,23 @@ class AuditLogSearch extends Component
|
||||
|
||||
/**
|
||||
* @throws JsonException
|
||||
* @return \Illuminate\Pagination\LengthAwarePaginator<int, Audit>
|
||||
* @var \Illuminate\Pagination\LengthAwarePaginator<int, Audit>
|
||||
*/
|
||||
#[Computed]
|
||||
final public function audits(): \Illuminate\Pagination\LengthAwarePaginator
|
||||
{
|
||||
$audits = Audit::with('user')
|
||||
final protected \Illuminate\Pagination\LengthAwarePaginator $audits {
|
||||
get => Audit::query()
|
||||
->with('user')
|
||||
->when($this->username, fn ($query) => $query->whereRelation('user', 'username', '=', $this->username))
|
||||
->when($this->modelName, fn ($query) => $query->where('model_name', '=', $this->modelName))
|
||||
->when($this->modelId, fn ($query) => $query->where('model_entry_id', '=', $this->modelId))
|
||||
->when($this->action, fn ($query) => $query->where('action', '=', $this->action))
|
||||
->when($this->record, fn ($query) => $query->where('record', 'LIKE', '%'.$this->record.'%'))
|
||||
->latest()
|
||||
->paginate($this->perPage);
|
||||
->paginate($this->perPage)
|
||||
->through(function ($audit) {
|
||||
$audit->values = json_decode((string) $audit->record, true, 512, JSON_THROW_ON_ERROR);
|
||||
|
||||
foreach ($audits as $audit) {
|
||||
$audit->values = json_decode((string) $audit->record, true, 512, JSON_THROW_ON_ERROR);
|
||||
}
|
||||
|
||||
return $audits;
|
||||
return $audit;
|
||||
});
|
||||
}
|
||||
|
||||
final public function render(): \Illuminate\Contracts\View\Factory|\Illuminate\Contracts\View\View|\Illuminate\Contracts\Foundation\Application
|
||||
|
||||
@@ -22,10 +22,10 @@ use App\Rules\PathToZip;
|
||||
use Illuminate\Http\Response;
|
||||
use Illuminate\Support\Facades\Validator;
|
||||
use Illuminate\Validation\ValidationException;
|
||||
use Livewire\Attributes\Computed;
|
||||
use Livewire\Component;
|
||||
use Spatie\Backup\BackupDestination\Backup;
|
||||
use Spatie\Backup\BackupDestination\BackupDestination;
|
||||
use Spatie\Backup\Config\MonitoredBackupsConfig;
|
||||
use Spatie\Backup\Helpers\Format;
|
||||
use Spatie\Backup\Tasks\Monitor\BackupDestinationStatus;
|
||||
use Spatie\Backup\Tasks\Monitor\BackupDestinationStatusFactory;
|
||||
@@ -40,14 +40,10 @@ class BackupPanel extends Component
|
||||
protected $listeners = ['refreshBackups' => '$refresh'];
|
||||
|
||||
/**
|
||||
* @return array<mixed>
|
||||
* @var array<mixed>
|
||||
*/
|
||||
#[Computed]
|
||||
final public function backupStatuses(): array
|
||||
{
|
||||
$monitorConfig = \Spatie\Backup\Config\MonitoredBackupsConfig::fromArray(config('backup.monitor_backups'));
|
||||
|
||||
return BackupDestinationStatusFactory::createForMonitorConfig($monitorConfig)
|
||||
final protected array $backupStatuses {
|
||||
get => BackupDestinationStatusFactory::createForMonitorConfig(MonitoredBackupsConfig::fromArray(config('backup.monitor_backups')))
|
||||
->map(fn (BackupDestinationStatus $backupDestinationStatus) => [
|
||||
'name' => $backupDestinationStatus->backupDestination()->backupName(),
|
||||
'disk' => $backupDestinationStatus->backupDestination()->diskName(),
|
||||
@@ -63,46 +59,37 @@ class BackupPanel extends Component
|
||||
->toArray();
|
||||
}
|
||||
|
||||
#[Computed]
|
||||
final public function activeDisk(): ?string
|
||||
{
|
||||
if (\count($this->backupStatuses)) {
|
||||
return $this->backupStatuses[0]['disk'];
|
||||
}
|
||||
|
||||
return null;
|
||||
final protected ?string $activeDisk {
|
||||
get => $this->backupStatuses[0]['disk'] ?? null;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array<mixed>
|
||||
* @var array<mixed>
|
||||
*/
|
||||
#[Computed]
|
||||
final public function disks(): array
|
||||
{
|
||||
return collect($this->backupStatuses)
|
||||
final protected array $disks {
|
||||
get => collect($this->backupStatuses)
|
||||
->map(fn ($backupStatus): mixed => $backupStatus['disk'])
|
||||
->values()
|
||||
->all();
|
||||
}
|
||||
|
||||
/**
|
||||
* @var array<mixed>
|
||||
* @throws ValidationException
|
||||
*/
|
||||
#[Computed]
|
||||
final public function backups(): array
|
||||
{
|
||||
$this->validateActiveDisk();
|
||||
final protected array $backups {
|
||||
get {
|
||||
$this->validateActiveDisk();
|
||||
|
||||
$backupDestination = BackupDestination::create($this->activeDisk, config('backup.backup.name'));
|
||||
|
||||
return $backupDestination
|
||||
->backups()
|
||||
->map(fn (Backup $backup) => [
|
||||
'path' => $backup->path(),
|
||||
'date' => $backup->date()->format('Y-m-d H:i:s'),
|
||||
'size' => Format::humanReadableSize($backup->sizeInBytes()),
|
||||
])
|
||||
->toArray();
|
||||
return BackupDestination::create($this->activeDisk, config('backup.backup.name'))
|
||||
->backups()
|
||||
->map(fn (Backup $backup) => [
|
||||
'path' => $backup->path(),
|
||||
'date' => $backup->date()->format('Y-m-d H:i:s'),
|
||||
'size' => Format::humanReadableSize($backup->sizeInBytes()),
|
||||
])
|
||||
->toArray();
|
||||
}
|
||||
}
|
||||
|
||||
final public function deleteBackup(int $fileIndex): void
|
||||
|
||||
@@ -17,7 +17,6 @@ declare(strict_types=1);
|
||||
namespace App\Http\Livewire;
|
||||
|
||||
use App\Models\BlockedIp;
|
||||
use Livewire\Attributes\Computed;
|
||||
use Livewire\Attributes\Url;
|
||||
use Livewire\Attributes\Validate;
|
||||
use Livewire\Component;
|
||||
@@ -75,12 +74,10 @@ class BlockIpAddress extends Component
|
||||
}
|
||||
|
||||
/**
|
||||
* @return \Illuminate\Pagination\LengthAwarePaginator<int, BlockedIp>
|
||||
* @var \Illuminate\Pagination\LengthAwarePaginator<int, BlockedIp>
|
||||
*/
|
||||
#[Computed]
|
||||
final public function ipAddresses(): \Illuminate\Pagination\LengthAwarePaginator
|
||||
{
|
||||
return BlockedIp::query()
|
||||
final protected \Illuminate\Pagination\LengthAwarePaginator $ipAddresses {
|
||||
get => BlockedIp::query()
|
||||
->when($this->ipSearch, fn ($query) => $query->where('ip_address', 'LIKE', '%'.$this->ipSearch.'%'))
|
||||
->when($this->reasonSearch, fn ($query) => $query->where('reason', 'LIKE', '%'.$this->reasonSearch.'%'))
|
||||
->latest()
|
||||
|
||||
@@ -41,7 +41,6 @@ use App\Notifications\NewCommentTag;
|
||||
use App\Repositories\ChatRepository;
|
||||
use App\Traits\CastLivewireProperties;
|
||||
use Illuminate\Support\Facades\Notification;
|
||||
use Livewire\Attributes\Computed;
|
||||
use Livewire\Attributes\Validate;
|
||||
use Livewire\Component;
|
||||
use Livewire\WithPagination;
|
||||
@@ -199,12 +198,10 @@ class Comments extends Component
|
||||
}
|
||||
|
||||
/**
|
||||
* @return \Illuminate\Contracts\Pagination\LengthAwarePaginator<int, \App\Models\Comment>
|
||||
* @var \Illuminate\Contracts\Pagination\LengthAwarePaginator<int, \App\Models\Comment>
|
||||
*/
|
||||
#[Computed]
|
||||
final public function comments(): \Illuminate\Contracts\Pagination\LengthAwarePaginator
|
||||
{
|
||||
return $this->model
|
||||
final protected \Illuminate\Contracts\Pagination\LengthAwarePaginator $comments {
|
||||
get => $this->model
|
||||
->comments()
|
||||
->with(['user:id,username,group_id,image,title', 'user.group', 'children.user:id,username,group_id,image,title', 'children.user.group'])
|
||||
->parent()
|
||||
|
||||
@@ -18,7 +18,6 @@ namespace App\Http\Livewire;
|
||||
|
||||
use App\Models\Conversation;
|
||||
use App\Traits\LivewireSort;
|
||||
use Livewire\Attributes\Computed;
|
||||
use Livewire\Attributes\Rule;
|
||||
use Livewire\Attributes\Url;
|
||||
use Livewire\Component;
|
||||
@@ -49,12 +48,10 @@ class ConversationSearch extends Component
|
||||
public string $sortDirection = 'desc';
|
||||
|
||||
/**
|
||||
* @return \Illuminate\Pagination\LengthAwarePaginator<int, Conversation>
|
||||
* @var \Illuminate\Pagination\LengthAwarePaginator<int, Conversation>
|
||||
*/
|
||||
#[Computed]
|
||||
final public function conversations(): \Illuminate\Pagination\LengthAwarePaginator
|
||||
{
|
||||
return Conversation::query()
|
||||
final protected \Illuminate\Pagination\LengthAwarePaginator $conversations {
|
||||
get => Conversation::query()
|
||||
->with([
|
||||
'users' => fn ($query) => $query->with('group')->where('users.id', '!=', auth()->id()),
|
||||
'participants' => fn ($query) => $query->where('user_id', auth()->id()),
|
||||
|
||||
@@ -18,7 +18,6 @@ namespace App\Http\Livewire;
|
||||
|
||||
use App\Models\EmailUpdate;
|
||||
use App\Models\User;
|
||||
use Livewire\Attributes\Computed;
|
||||
use Livewire\Attributes\Url;
|
||||
use Livewire\Component;
|
||||
use Livewire\WithPagination;
|
||||
@@ -44,14 +43,13 @@ class EmailUpdateSearch extends Component
|
||||
public int $perPage = 25;
|
||||
|
||||
/**
|
||||
* @return \Illuminate\Pagination\LengthAwarePaginator<int, EmailUpdate>
|
||||
* @var \Illuminate\Pagination\LengthAwarePaginator<int, EmailUpdate>
|
||||
*/
|
||||
#[Computed]
|
||||
final public function emailUpdates(): \Illuminate\Pagination\LengthAwarePaginator
|
||||
{
|
||||
return EmailUpdate::with([
|
||||
'user' => fn ($query) => $query->withTrashed()->with('group'),
|
||||
])
|
||||
final protected \Illuminate\Pagination\LengthAwarePaginator $emailUpdates {
|
||||
get => EmailUpdate::query()
|
||||
->with([
|
||||
'user' => fn ($query) => $query->withTrashed()->with('group'),
|
||||
])
|
||||
->when($this->username, fn ($query) => $query->whereIn('user_id', User::withTrashed()->select('id')->where('username', 'LIKE', '%'.$this->username.'%')))
|
||||
->orderBy($this->sortField, $this->sortDirection)
|
||||
->paginate($this->perPage);
|
||||
|
||||
@@ -20,7 +20,6 @@ use App\Models\FailedLoginAttempt;
|
||||
use App\Traits\LivewireSort;
|
||||
use Carbon\Carbon;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
use Livewire\Attributes\Computed;
|
||||
use Livewire\Attributes\Url;
|
||||
use Livewire\Component;
|
||||
use Livewire\WithPagination;
|
||||
@@ -51,12 +50,10 @@ class FailedLoginSearch extends Component
|
||||
public string $sortDirection = 'desc';
|
||||
|
||||
/**
|
||||
* @return \Illuminate\Database\Eloquent\Collection<int, FailedLoginAttempt>
|
||||
* @var \Illuminate\Database\Eloquent\Collection<int, FailedLoginAttempt>
|
||||
*/
|
||||
#[Computed]
|
||||
final public function failedLoginsTop10Ip(): \Illuminate\Database\Eloquent\Collection
|
||||
{
|
||||
return FailedLoginAttempt::query()
|
||||
final protected \Illuminate\Database\Eloquent\Collection $failedLoginsTop10Ip {
|
||||
get => FailedLoginAttempt::query()
|
||||
->select(['ip_address', DB::raw('COUNT(*) as login_attempts'), DB::raw('MAX(created_at) as latest_created_at')])
|
||||
->groupBy('ip_address')
|
||||
->having('login_attempts', '>', 3)
|
||||
@@ -67,12 +64,10 @@ class FailedLoginSearch extends Component
|
||||
}
|
||||
|
||||
/**
|
||||
* @return \Illuminate\Pagination\LengthAwarePaginator<int, FailedLoginAttempt>
|
||||
* @var \Illuminate\Pagination\LengthAwarePaginator<int, FailedLoginAttempt>
|
||||
*/
|
||||
#[Computed]
|
||||
final public function failedLogins(): \Illuminate\Pagination\LengthAwarePaginator
|
||||
{
|
||||
return FailedLoginAttempt::query()
|
||||
final protected \Illuminate\Pagination\LengthAwarePaginator $failedLogins {
|
||||
get => FailedLoginAttempt::query()
|
||||
->with('user.group')
|
||||
->when($this->username, fn ($query) => $query->where('username', 'LIKE', $this->username.'%'))
|
||||
->when($this->userId, fn ($query) => $query->where('user_id', '=', $this->userId))
|
||||
|
||||
@@ -18,7 +18,6 @@ namespace App\Http\Livewire;
|
||||
|
||||
use App\Models\ForumCategory;
|
||||
use App\Models\Topic;
|
||||
use Livewire\Attributes\Computed;
|
||||
use Livewire\Attributes\Url;
|
||||
use Livewire\Component;
|
||||
use Livewire\WithPagination;
|
||||
@@ -63,12 +62,10 @@ class ForumCategoryTopicSearch extends Component
|
||||
}
|
||||
|
||||
/**
|
||||
* @return \Illuminate\Pagination\LengthAwarePaginator<int, Topic>
|
||||
* @var \Illuminate\Pagination\LengthAwarePaginator<int, Topic>
|
||||
*/
|
||||
#[Computed]
|
||||
final public function topics(): \Illuminate\Pagination\LengthAwarePaginator
|
||||
{
|
||||
return Topic::query()
|
||||
final protected \Illuminate\Pagination\LengthAwarePaginator $topics {
|
||||
get => Topic::query()
|
||||
->select('topics.*')
|
||||
->with([
|
||||
'user.group',
|
||||
|
||||
@@ -19,7 +19,6 @@ namespace App\Http\Livewire;
|
||||
use App\Models\Forum;
|
||||
use App\Models\Subscription;
|
||||
use App\Models\Topic;
|
||||
use Livewire\Attributes\Computed;
|
||||
use Livewire\Attributes\Url;
|
||||
use Livewire\Component;
|
||||
use Livewire\WithPagination;
|
||||
@@ -68,12 +67,10 @@ class ForumTopicSearch extends Component
|
||||
}
|
||||
|
||||
/**
|
||||
* @return \Illuminate\Pagination\LengthAwarePaginator<int, Topic>
|
||||
* @var \Illuminate\Pagination\LengthAwarePaginator<int, Topic>
|
||||
*/
|
||||
#[Computed]
|
||||
final public function topics(): \Illuminate\Pagination\LengthAwarePaginator
|
||||
{
|
||||
return Topic::query()
|
||||
final protected \Illuminate\Pagination\LengthAwarePaginator $topics {
|
||||
get => Topic::query()
|
||||
->select('topics.*')
|
||||
->with([
|
||||
'user.group',
|
||||
|
||||
@@ -18,14 +18,10 @@ namespace App\Http\Livewire;
|
||||
|
||||
use App\Models\Gift;
|
||||
use App\Traits\LivewireSort;
|
||||
use Livewire\Attributes\Computed;
|
||||
use Livewire\Attributes\Url;
|
||||
use Livewire\Component;
|
||||
use Livewire\WithPagination;
|
||||
|
||||
/**
|
||||
* @property \Illuminate\Pagination\LengthAwarePaginator<int, Gift> $gifts
|
||||
*/
|
||||
class GiftLogSearch extends Component
|
||||
{
|
||||
use LivewireSort;
|
||||
@@ -52,15 +48,14 @@ class GiftLogSearch extends Component
|
||||
public int $perPage = 25;
|
||||
|
||||
/**
|
||||
* @return \Illuminate\Pagination\LengthAwarePaginator<int, Gift>
|
||||
* @var \Illuminate\Pagination\LengthAwarePaginator<int, Gift>
|
||||
*/
|
||||
#[Computed]
|
||||
final public function gifts(): \Illuminate\Pagination\LengthAwarePaginator
|
||||
{
|
||||
return Gift::with([
|
||||
'sender' => fn ($query) => $query->withTrashed()->with('group'),
|
||||
'recipient' => fn ($query) => $query->withTrashed()->with('group'),
|
||||
])
|
||||
final protected \Illuminate\Pagination\LengthAwarePaginator $gifts {
|
||||
get => Gift::query()
|
||||
->with([
|
||||
'sender' => fn ($query) => $query->withTrashed()->with('group'),
|
||||
'recipient' => fn ($query) => $query->withTrashed()->with('group'),
|
||||
])
|
||||
->when($this->sender, fn ($query) => $query->whereRelation('sender', 'username', '=', $this->sender))
|
||||
->when($this->receiver, fn ($query) => $query->whereRelation('recipient', 'username', '=', $this->receiver))
|
||||
->when($this->comment, fn ($query) => $query->where('comment', 'LIKE', '%'.$this->comment.'%'))
|
||||
|
||||
@@ -19,14 +19,10 @@ namespace App\Http\Livewire;
|
||||
use App\Models\History;
|
||||
use App\Traits\LivewireSort;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
use Livewire\Attributes\Computed;
|
||||
use Livewire\Attributes\Url;
|
||||
use Livewire\Component;
|
||||
use Livewire\WithPagination;
|
||||
|
||||
/**
|
||||
* @property \Illuminate\Pagination\LengthAwarePaginator<int, History> $histories
|
||||
*/
|
||||
class HistorySearch extends Component
|
||||
{
|
||||
use LivewireSort;
|
||||
@@ -92,12 +88,10 @@ class HistorySearch extends Component
|
||||
}
|
||||
|
||||
/**
|
||||
* @return \Illuminate\Pagination\LengthAwarePaginator<int, History>
|
||||
* @var \Illuminate\Pagination\LengthAwarePaginator<int, History>
|
||||
*/
|
||||
#[Computed]
|
||||
final public function histories(): \Illuminate\Pagination\LengthAwarePaginator
|
||||
{
|
||||
return History::query()
|
||||
final protected \Illuminate\Pagination\LengthAwarePaginator $histories {
|
||||
get => History::query()
|
||||
->with('user', 'torrent:id,name')
|
||||
->when(
|
||||
$this->groupBy === 'user_id',
|
||||
|
||||
@@ -19,7 +19,6 @@ namespace App\Http\Livewire;
|
||||
use App\Models\Invite;
|
||||
use App\Traits\LivewireSort;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
use Livewire\Attributes\Computed;
|
||||
use Livewire\Attributes\Url;
|
||||
use Livewire\Component;
|
||||
use Livewire\WithPagination;
|
||||
@@ -87,12 +86,10 @@ class InviteLogSearch extends Component
|
||||
}
|
||||
|
||||
/**
|
||||
* @return \Illuminate\Pagination\LengthAwarePaginator<int, Invite>
|
||||
* @var \Illuminate\Pagination\LengthAwarePaginator<int, Invite>
|
||||
*/
|
||||
#[Computed]
|
||||
final public function invites(): \Illuminate\Pagination\LengthAwarePaginator
|
||||
{
|
||||
return Invite::withTrashed()
|
||||
final protected \Illuminate\Pagination\LengthAwarePaginator $invites {
|
||||
get => Invite::withTrashed()
|
||||
->with([
|
||||
'sender' => fn ($query) => $query->withTrashed()->with('group'),
|
||||
'receiver' => fn ($query) => $query->withTrashed()->with('group'),
|
||||
|
||||
@@ -19,16 +19,11 @@ namespace App\Http\Livewire;
|
||||
use App\Traits\CastLivewireProperties;
|
||||
use Illuminate\Pagination\LengthAwarePaginator;
|
||||
use Illuminate\Support\Facades\File;
|
||||
use Livewire\Attributes\Computed;
|
||||
use Livewire\Attributes\Url;
|
||||
use Livewire\Component;
|
||||
use Livewire\WithPagination;
|
||||
use SplFileInfo;
|
||||
|
||||
/**
|
||||
* @property \Illuminate\Support\Collection $logFiles
|
||||
* @property LengthAwarePaginator $entries
|
||||
*/
|
||||
class LaravelLogViewer extends Component
|
||||
{
|
||||
use CastLivewireProperties;
|
||||
@@ -54,64 +49,64 @@ class LaravelLogViewer extends Component
|
||||
$this->perPage += 5;
|
||||
}
|
||||
|
||||
#[Computed]
|
||||
final public function logFiles()
|
||||
{
|
||||
$directory = storage_path('logs');
|
||||
|
||||
return collect(File::allFiles($directory))
|
||||
->sortByDesc(fn (SplFileInfo $file) => $file->getMTime())->values();
|
||||
/**
|
||||
* @var \Illuminate\Support\Collection<int, \Symfony\Component\Finder\SplFileInfo>
|
||||
*/
|
||||
final protected \Illuminate\Support\Collection $logFiles {
|
||||
get => collect(File::allFiles(storage_path('logs')))
|
||||
->sortByDesc(fn (SplFileInfo $file) => $file->getMTime())
|
||||
->values();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return LengthAwarePaginator<\Illuminate\Support\Collection<string|int, mixed>>
|
||||
* @var LengthAwarePaginator<string, \Illuminate\Support\Collection<int, mixed>>
|
||||
*/
|
||||
#[Computed]
|
||||
final public function entries(): LengthAwarePaginator
|
||||
{
|
||||
$files = $this->logFiles;
|
||||
$logString = '';
|
||||
final protected LengthAwarePaginator $entries {
|
||||
get {
|
||||
$files = $this->logFiles;
|
||||
$logString = '';
|
||||
|
||||
foreach ($this->logs as $log) {
|
||||
if ($files[$log] ?? []) {
|
||||
$logString .= file_get_contents($files[$log]->getPathname());
|
||||
foreach ($this->logs as $log) {
|
||||
if ($files[$log] ?? []) {
|
||||
$logString .= file_get_contents($files[$log]->getPathname());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$entryPattern = '/^\[(?<date>.*)\]\s(?<env>\w+)\.(?<level>\w+)\:\s/m';
|
||||
$contextPattern = '/^(?<message>[^\{]*)?(?:\{"exception"\:"\[object\]\s\((?<exception>[^\s\(]+))?.*\s(?:in|at)\s(?<in>.*)\:(?<line>\d+)\)?/ms';
|
||||
$entryPattern = '/^\[(?<date>.*)\]\s(?<env>\w+)\.(?<level>\w+)\:\s/m';
|
||||
$contextPattern = '/^(?<message>[^\{]*)?(?:\{"exception"\:"\[object\]\s\((?<exception>[^\s\(]+))?.*\s(?:in|at)\s(?<in>.*)\:(?<line>\d+)\)?/ms';
|
||||
|
||||
$entries = collect();
|
||||
$entries = collect();
|
||||
|
||||
if (preg_match_all($entryPattern, $logString, $entryMatches, PREG_SET_ORDER) !== false) {
|
||||
$stacktraces = preg_split($entryPattern, $logString);
|
||||
// Delete the empty first entry
|
||||
array_shift($stacktraces);
|
||||
$numEntries = \count($entryMatches);
|
||||
if (preg_match_all($entryPattern, $logString, $entryMatches, PREG_SET_ORDER) !== false) {
|
||||
$stacktraces = preg_split($entryPattern, $logString);
|
||||
// Delete the empty first entry
|
||||
array_shift($stacktraces);
|
||||
$numEntries = \count($entryMatches);
|
||||
|
||||
for ($i = 0; $i < $numEntries; $i++) {
|
||||
// The context is the portion before the first stack trace
|
||||
$context = preg_split('/^\[stacktrace\]|Stack trace\:/ms', (string) $stacktraces[$i])[0];
|
||||
// The `context` consists of a message, an exception, a filename, and a line count
|
||||
preg_match($contextPattern, $context, $contextMatches);
|
||||
for ($i = 0; $i < $numEntries; $i++) {
|
||||
// The context is the portion before the first stack trace
|
||||
$context = preg_split('/^\[stacktrace\]|Stack trace\:/ms', (string) $stacktraces[$i])[0];
|
||||
// The `context` consists of a message, an exception, a filename, and a line count
|
||||
preg_match($contextPattern, $context, $contextMatches);
|
||||
|
||||
$entries->push([
|
||||
'date' => $entryMatches[$i]['date'],
|
||||
'env' => $entryMatches[$i]['env'],
|
||||
'level' => $entryMatches[$i]['level'],
|
||||
'message' => $contextMatches['message'] ?? '',
|
||||
'exception' => $contextMatches['exception'] ?? '',
|
||||
'in' => $contextMatches['in'] ?? '',
|
||||
'line' => $contextMatches['line'] ?? '',
|
||||
'stacktrace' => $stacktraces[$i],
|
||||
]);
|
||||
$entries->push([
|
||||
'date' => $entryMatches[$i]['date'],
|
||||
'env' => $entryMatches[$i]['env'],
|
||||
'level' => $entryMatches[$i]['level'],
|
||||
'message' => $contextMatches['message'] ?? '',
|
||||
'exception' => $contextMatches['exception'] ?? '',
|
||||
'in' => $contextMatches['in'] ?? '',
|
||||
'line' => $contextMatches['line'] ?? '',
|
||||
'stacktrace' => $stacktraces[$i],
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
||||
$groupedEntries = $entries->groupBy(fn ($entry) => $entry['message'].'-'.$entry['exception'].'-'.$entry['in'].'-'.$entry['line']);
|
||||
$currentEntries = $groupedEntries->forPage($this->page, $this->perPage);
|
||||
|
||||
return new LengthAwarePaginator($currentEntries, $groupedEntries->count(), $this->perPage, $this->page);
|
||||
}
|
||||
|
||||
$groupedEntries = $entries->groupBy(fn ($entry) => $entry['message'].'-'.$entry['exception'].'-'.$entry['in'].'-'.$entry['line']);
|
||||
$currentEntries = $groupedEntries->forPage($this->page, $this->perPage);
|
||||
|
||||
return new LengthAwarePaginator($currentEntries, $groupedEntries->count(), $this->perPage, $this->page);
|
||||
}
|
||||
|
||||
final public function clearLatestLog(): void
|
||||
|
||||
@@ -20,7 +20,6 @@ use App\Models\History;
|
||||
use App\Traits\CastLivewireProperties;
|
||||
use App\Traits\LivewireSort;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
use Livewire\Attributes\Computed;
|
||||
use Livewire\Attributes\Url;
|
||||
use Livewire\Component;
|
||||
use Livewire\WithPagination;
|
||||
@@ -52,12 +51,10 @@ class LeakerSearch extends Component
|
||||
public string $sortDirection = 'desc';
|
||||
|
||||
/**
|
||||
* @return \Illuminate\Pagination\LengthAwarePaginator<int, History>
|
||||
* @var \Illuminate\Pagination\LengthAwarePaginator<int, History>
|
||||
*/
|
||||
#[Computed]
|
||||
final public function leakers(): \Illuminate\Pagination\LengthAwarePaginator
|
||||
{
|
||||
return History::query()
|
||||
final protected \Illuminate\Pagination\LengthAwarePaginator $leakers {
|
||||
get => History::query()
|
||||
->select([
|
||||
'history.user_id',
|
||||
DB::raw('count(*) as leak_count'),
|
||||
@@ -81,10 +78,8 @@ class LeakerSearch extends Component
|
||||
->paginate($this->perPage);
|
||||
}
|
||||
|
||||
#[Computed]
|
||||
final public function torrentIdCount(): int
|
||||
{
|
||||
return \count(array_filter(array_map('trim', explode(',', $this->torrentIds))));
|
||||
final protected int $torrentIdCount {
|
||||
get => \count(array_filter(array_map('trim', explode(',', $this->torrentIds))));
|
||||
}
|
||||
|
||||
final public function render(): \Illuminate\Contracts\View\Factory|\Illuminate\Contracts\View\View|\Illuminate\Contracts\Foundation\Application
|
||||
|
||||
@@ -19,7 +19,6 @@ namespace App\Http\Livewire;
|
||||
use App\Models\TmdbMovie;
|
||||
use App\Models\Type;
|
||||
use App\Traits\LivewireSort;
|
||||
use Livewire\Attributes\Computed;
|
||||
use Livewire\Attributes\Url;
|
||||
use Livewire\Component;
|
||||
use Livewire\WithPagination;
|
||||
@@ -50,12 +49,11 @@ class MissingMediaSearch extends Component
|
||||
public int $perPage = 50;
|
||||
|
||||
/**
|
||||
* @return \Illuminate\Pagination\LengthAwarePaginator<int, TmdbMovie>
|
||||
* @var \Illuminate\Pagination\LengthAwarePaginator<int, TmdbMovie>
|
||||
*/
|
||||
#[Computed]
|
||||
final public function medias(): \Illuminate\Pagination\LengthAwarePaginator
|
||||
{
|
||||
return TmdbMovie::with(['torrents:tmdb_movie_id,tmdb_tv_id,resolution_id,type_id' => ['resolution:id,position,name']])
|
||||
final protected \Illuminate\Pagination\LengthAwarePaginator $medias {
|
||||
get => TmdbMovie::query()
|
||||
->with(['torrents:tmdb_movie_id,tmdb_tv_id,resolution_id,type_id' => ['resolution:id,position,name']])
|
||||
->when($this->name, fn ($query) => $query->where('title', 'LIKE', '%'.$this->name.'%'))
|
||||
->when($this->year, fn ($query) => $query->where('release_date', 'LIKE', '%'.$this->year.'%'))
|
||||
->withCount(['requests' => fn ($query) => $query->whereNull('torrent_id')->whereDoesntHave('claim')])
|
||||
@@ -65,12 +63,13 @@ class MissingMediaSearch extends Component
|
||||
}
|
||||
|
||||
/**
|
||||
* @return \Illuminate\Database\Eloquent\Collection<int, Type>
|
||||
* @var \Illuminate\Database\Eloquent\Collection<int, Type>
|
||||
*/
|
||||
#[Computed]
|
||||
final public function types(): \Illuminate\Database\Eloquent\Collection
|
||||
{
|
||||
return Type::select(['id', 'position', 'name'])->orderBy('position')->get();
|
||||
final protected \Illuminate\Database\Eloquent\Collection $types {
|
||||
get => Type::query()
|
||||
->select(['id', 'position', 'name'])
|
||||
->orderBy('position')
|
||||
->get();
|
||||
}
|
||||
|
||||
final public function render(): \Illuminate\Contracts\View\Factory|\Illuminate\Contracts\View\View|\Illuminate\Contracts\Foundation\Application
|
||||
|
||||
@@ -17,7 +17,6 @@ declare(strict_types=1);
|
||||
namespace App\Http\Livewire;
|
||||
|
||||
use App\Models\Note;
|
||||
use Livewire\Attributes\Computed;
|
||||
use Livewire\Attributes\Url;
|
||||
use Livewire\Component;
|
||||
use Livewire\WithPagination;
|
||||
@@ -40,12 +39,10 @@ class NoteSearch extends Component
|
||||
}
|
||||
|
||||
/**
|
||||
* @return \Illuminate\Pagination\LengthAwarePaginator<int, Note>
|
||||
* @var \Illuminate\Pagination\LengthAwarePaginator<int, Note>
|
||||
*/
|
||||
#[Computed]
|
||||
final public function notes(): \Illuminate\Pagination\LengthAwarePaginator
|
||||
{
|
||||
return Note::query()
|
||||
final protected \Illuminate\Pagination\LengthAwarePaginator $notes {
|
||||
get => Note::query()
|
||||
->with([
|
||||
'noteduser' => fn ($query) => $query->withTrashed()->with(['group']),
|
||||
'staffuser' => fn ($query) => $query->withTrashed()->with(['group']),
|
||||
|
||||
@@ -18,7 +18,6 @@ namespace App\Http\Livewire;
|
||||
|
||||
use App\Models\User;
|
||||
use App\Traits\LivewireSort;
|
||||
use Livewire\Attributes\Computed;
|
||||
use Livewire\Attributes\Url;
|
||||
use Livewire\Component;
|
||||
use Livewire\WithPagination;
|
||||
@@ -103,12 +102,10 @@ class NotificationSearch extends Component
|
||||
public string $sortDirection = 'desc';
|
||||
|
||||
/**
|
||||
* @return \Illuminate\Pagination\LengthAwarePaginator<int, \Illuminate\Notifications\DatabaseNotification>
|
||||
* @var \Illuminate\Pagination\LengthAwarePaginator<int, \Illuminate\Notifications\DatabaseNotification>
|
||||
*/
|
||||
#[Computed]
|
||||
final public function notifications(): \Illuminate\Pagination\LengthAwarePaginator
|
||||
{
|
||||
return auth()->user()->notifications()
|
||||
final protected \Illuminate\Pagination\LengthAwarePaginator $notifications {
|
||||
get => auth()->user()->notifications()
|
||||
->select('*')
|
||||
->selectRaw("CASE WHEN read_at IS NULL THEN 'FALSE' ELSE 'TRUE' END as is_read")
|
||||
->where(function ($query): void {
|
||||
|
||||
@@ -19,14 +19,10 @@ namespace App\Http\Livewire;
|
||||
use App\Models\Passkey;
|
||||
use App\Models\User;
|
||||
use App\Traits\LivewireSort;
|
||||
use Livewire\Attributes\Computed;
|
||||
use Livewire\Attributes\Url;
|
||||
use Livewire\Component;
|
||||
use Livewire\WithPagination;
|
||||
|
||||
/**
|
||||
* @property \Illuminate\Pagination\LengthAwarePaginator<int, Passkey> $passkeys
|
||||
*/
|
||||
class PasskeySearch extends Component
|
||||
{
|
||||
use LivewireSort;
|
||||
@@ -50,14 +46,13 @@ class PasskeySearch extends Component
|
||||
public int $perPage = 25;
|
||||
|
||||
/**
|
||||
* @return \Illuminate\Pagination\LengthAwarePaginator<int, Passkey>
|
||||
* @var \Illuminate\Pagination\LengthAwarePaginator<int, Passkey>
|
||||
*/
|
||||
#[Computed]
|
||||
final public function passkeys(): \Illuminate\Pagination\LengthAwarePaginator
|
||||
{
|
||||
return Passkey::with([
|
||||
'user' => fn ($query) => $query->withTrashed()->with('group'),
|
||||
])
|
||||
final protected \Illuminate\Pagination\LengthAwarePaginator $passkeys {
|
||||
get => Passkey::query()
|
||||
->with([
|
||||
'user' => fn ($query) => $query->withTrashed()->with('group'),
|
||||
])
|
||||
->when($this->username, fn ($query) => $query->whereIn('user_id', User::withTrashed()->select('id')->where('username', '=', $this->username)))
|
||||
->when($this->passkey, fn ($query) => $query->where('content', 'LIKE', '%'.$this->passkey.'%'))
|
||||
->orderBy($this->sortField, $this->sortDirection)
|
||||
|
||||
@@ -19,14 +19,10 @@ namespace App\Http\Livewire;
|
||||
use App\Models\PasswordResetHistory;
|
||||
use App\Models\User;
|
||||
use App\Traits\LivewireSort;
|
||||
use Livewire\Attributes\Computed;
|
||||
use Livewire\Attributes\Url;
|
||||
use Livewire\Component;
|
||||
use Livewire\WithPagination;
|
||||
|
||||
/**
|
||||
* @property \Illuminate\Contracts\Pagination\LengthAwarePaginator<int, PasswordResetHistory> $passwordResetHistories
|
||||
*/
|
||||
class PasswordResetHistorySearch extends Component
|
||||
{
|
||||
use LivewireSort;
|
||||
@@ -47,14 +43,13 @@ class PasswordResetHistorySearch extends Component
|
||||
public int $perPage = 25;
|
||||
|
||||
/**
|
||||
* @return \Illuminate\Pagination\LengthAwarePaginator<int, PasswordResetHistory>
|
||||
* @var \Illuminate\Pagination\LengthAwarePaginator<int, PasswordResetHistory>
|
||||
*/
|
||||
#[Computed]
|
||||
final public function passwordResetHistories(): \Illuminate\Pagination\LengthAwarePaginator
|
||||
{
|
||||
return PasswordResetHistory::with([
|
||||
'user' => fn ($query) => $query->withTrashed()->with('group'),
|
||||
])
|
||||
final protected \Illuminate\Pagination\LengthAwarePaginator $passwordResetHistories {
|
||||
get => PasswordResetHistory::query()
|
||||
->with([
|
||||
'user' => fn ($query) => $query->withTrashed()->with('group'),
|
||||
])
|
||||
->when($this->username, fn ($query) => $query->whereIn('user_id', User::withTrashed()->select('id')->where('username', 'LIKE', '%'.$this->username.'%')))
|
||||
->orderBy($this->sortField, $this->sortDirection)
|
||||
->paginate($this->perPage);
|
||||
|
||||
@@ -19,7 +19,6 @@ namespace App\Http\Livewire;
|
||||
use App\Models\Peer;
|
||||
use App\Traits\LivewireSort;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
use Livewire\Attributes\Computed;
|
||||
use Livewire\Attributes\Url;
|
||||
use Livewire\Component;
|
||||
use Livewire\WithPagination;
|
||||
@@ -98,12 +97,10 @@ class PeerSearch extends Component
|
||||
}
|
||||
|
||||
/**
|
||||
* @return \Illuminate\Contracts\Pagination\LengthAwarePaginator<int, Peer>
|
||||
* @var \Illuminate\Contracts\Pagination\LengthAwarePaginator<int, Peer>
|
||||
*/
|
||||
#[Computed]
|
||||
final public function peers(): \Illuminate\Contracts\Pagination\LengthAwarePaginator
|
||||
{
|
||||
return Peer::query()
|
||||
final protected \Illuminate\Contracts\Pagination\LengthAwarePaginator $peers {
|
||||
get => Peer::query()
|
||||
->when(
|
||||
$this->groupBy === 'none',
|
||||
fn ($query) => $query
|
||||
|
||||
@@ -19,7 +19,6 @@ namespace App\Http\Livewire;
|
||||
use App\Models\Playlist;
|
||||
use App\Models\PlaylistCategory;
|
||||
use App\Traits\LivewireSort;
|
||||
use Livewire\Attributes\Computed;
|
||||
use Livewire\Attributes\Url;
|
||||
use Livewire\Component;
|
||||
use Livewire\WithPagination;
|
||||
@@ -55,14 +54,13 @@ class PlaylistSearch extends Component
|
||||
}
|
||||
|
||||
/**
|
||||
* @return \Illuminate\Pagination\LengthAwarePaginator<int, Playlist>
|
||||
* @var \Illuminate\Pagination\LengthAwarePaginator<int, Playlist>
|
||||
*/
|
||||
#[Computed]
|
||||
final public function playlists()
|
||||
{
|
||||
return Playlist::with([
|
||||
'user:id,username,group_id,image' => ['group'],
|
||||
])
|
||||
final protected $playlists {
|
||||
get => Playlist::query()
|
||||
->with([
|
||||
'user:id,username,group_id,image' => ['group'],
|
||||
])
|
||||
->withCount('torrents')
|
||||
->when(
|
||||
! auth()->user()->group->is_modo,
|
||||
@@ -81,12 +79,14 @@ class PlaylistSearch extends Component
|
||||
}
|
||||
|
||||
/**
|
||||
* @return \Illuminate\Database\Eloquent\Collection<int, PlaylistCategory>
|
||||
* @var \Illuminate\Database\Eloquent\Collection<int, PlaylistCategory>
|
||||
*/
|
||||
#[Computed(seconds: 3600, cache: true)]
|
||||
final public function playlistCategories(): \Illuminate\Database\Eloquent\Collection
|
||||
{
|
||||
return PlaylistCategory::query()->orderBy('position')->get();
|
||||
final protected \Illuminate\Database\Eloquent\Collection $playlistCategories {
|
||||
get => cache()->remember(
|
||||
'playlist-categories',
|
||||
3600,
|
||||
fn () => PlaylistCategory::query()->orderBy('position')->get()
|
||||
);
|
||||
}
|
||||
|
||||
final public function render(): \Illuminate\Contracts\View\Factory|\Illuminate\Contracts\View\View|\Illuminate\Contracts\Foundation\Application
|
||||
|
||||
@@ -17,7 +17,6 @@ declare(strict_types=1);
|
||||
namespace App\Http\Livewire;
|
||||
|
||||
use App\Models\Post;
|
||||
use Livewire\Attributes\Computed;
|
||||
use Livewire\Attributes\Url;
|
||||
use Livewire\Component;
|
||||
use Livewire\WithPagination;
|
||||
@@ -37,12 +36,10 @@ class PostSearch extends Component
|
||||
}
|
||||
|
||||
/**
|
||||
* @return \Illuminate\Pagination\LengthAwarePaginator<int, Post>
|
||||
* @var \Illuminate\Pagination\LengthAwarePaginator<int, Post>
|
||||
*/
|
||||
#[Computed]
|
||||
final public function posts(): \Illuminate\Pagination\LengthAwarePaginator
|
||||
{
|
||||
return Post::query()
|
||||
final protected \Illuminate\Pagination\LengthAwarePaginator $posts {
|
||||
get => Post::query()
|
||||
->with('user', 'user.group', 'topic:id,name,state')
|
||||
->withCount('likes', 'dislikes', 'authorPosts', 'authorTopics')
|
||||
->withSum('tips', 'bon')
|
||||
|
||||
@@ -19,67 +19,49 @@ namespace App\Http\Livewire;
|
||||
use App\Models\TmdbTv;
|
||||
use App\Models\TmdbMovie;
|
||||
use Illuminate\Support\Facades\Redis;
|
||||
use Livewire\Attributes\Computed;
|
||||
use Livewire\Component;
|
||||
|
||||
class RandomMedia extends Component
|
||||
{
|
||||
/**
|
||||
* @return \Illuminate\Support\Collection<int, TmdbMovie>
|
||||
* @var \Illuminate\Support\Collection<int, TmdbMovie>
|
||||
*/
|
||||
#[Computed]
|
||||
final public function movies(): \Illuminate\Support\Collection
|
||||
{
|
||||
$cacheKey = config('cache.prefix').':random-media-movie-ids';
|
||||
final protected \Illuminate\Support\Collection $movies {
|
||||
get {
|
||||
$cacheKey = config('cache.prefix').':random-media-movie-ids';
|
||||
|
||||
$movieIds = Redis::connection('cache')->command('SRANDMEMBER', [$cacheKey, 3]);
|
||||
$movieIds = Redis::connection('cache')->command('SRANDMEMBER', [$cacheKey, 3]);
|
||||
|
||||
return TmdbMovie::query()
|
||||
->select(['id', 'backdrop', 'title', 'release_date'])
|
||||
->withMin('torrents', 'category_id')
|
||||
->whereIn('id', $movieIds)
|
||||
->get();
|
||||
return TmdbMovie::query()
|
||||
->select(['id', 'backdrop', 'title', 'release_date'])
|
||||
->withMin('torrents', 'category_id')
|
||||
->whereIn('id', $movieIds)
|
||||
->get();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @return \Illuminate\Support\Collection<int, TmdbMovie>
|
||||
* @var \Illuminate\Support\Collection<int, TmdbTv>
|
||||
*/
|
||||
#[Computed]
|
||||
final public function movies2(): \Illuminate\Support\Collection
|
||||
{
|
||||
$cacheKey = config('cache.prefix').':random-media-movie-ids';
|
||||
final protected \Illuminate\Support\Collection $tvs {
|
||||
get {
|
||||
$cacheKey = config('cache.prefix').':random-media-tv-ids';
|
||||
|
||||
$movieIds = Redis::connection('cache')->command('SRANDMEMBER', [$cacheKey, 3]);
|
||||
$tvIds = Redis::connection('cache')->command('SRANDMEMBER', [$cacheKey, 3]);
|
||||
|
||||
return TmdbMovie::query()
|
||||
->select(['id', 'backdrop', 'title', 'release_date'])
|
||||
->withMin('torrents', 'category_id')
|
||||
->whereIn('id', $movieIds)
|
||||
->get();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return \Illuminate\Support\Collection<int, TmdbTv>
|
||||
*/
|
||||
#[Computed]
|
||||
final public function tvs(): \Illuminate\Support\Collection
|
||||
{
|
||||
$cacheKey = config('cache.prefix').':random-media-tv-ids';
|
||||
|
||||
$tvIds = Redis::connection('cache')->command('SRANDMEMBER', [$cacheKey, 3]);
|
||||
|
||||
return TmdbTv::query()
|
||||
->select(['id', 'backdrop', 'name', 'first_air_date'])
|
||||
->withMin('torrents', 'category_id')
|
||||
->whereIn('id', $tvIds)
|
||||
->get();
|
||||
return TmdbTv::query()
|
||||
->select(['id', 'backdrop', 'name', 'first_air_date'])
|
||||
->withMin('torrents', 'category_id')
|
||||
->whereIn('id', $tvIds)
|
||||
->get();
|
||||
}
|
||||
}
|
||||
|
||||
final public function render(): \Illuminate\Contracts\View\Factory | \Illuminate\Contracts\View\View | \Illuminate\Contracts\Foundation\Application
|
||||
{
|
||||
return view('livewire.random-media', [
|
||||
'movies' => $this->movies,
|
||||
'movies2' => $this->movies2,
|
||||
'movies2' => $this->movies,
|
||||
'tvs' => $this->tvs
|
||||
]);
|
||||
}
|
||||
|
||||
@@ -19,14 +19,10 @@ namespace App\Http\Livewire;
|
||||
use App\Models\Report;
|
||||
use App\Models\User;
|
||||
use App\Traits\LivewireSort;
|
||||
use Livewire\Attributes\Computed;
|
||||
use Livewire\Attributes\Url;
|
||||
use Livewire\Component;
|
||||
use Livewire\WithPagination;
|
||||
|
||||
/**
|
||||
* @property \Illuminate\Pagination\LengthAwarePaginator<int, Report> $reports
|
||||
*/
|
||||
class ReportSearch extends Component
|
||||
{
|
||||
use LivewireSort;
|
||||
@@ -68,12 +64,10 @@ class ReportSearch extends Component
|
||||
public int $perPage = 25;
|
||||
|
||||
/**
|
||||
* @return \Illuminate\Pagination\LengthAwarePaginator<int, Report>
|
||||
* @var \Illuminate\Pagination\LengthAwarePaginator<int, Report>
|
||||
*/
|
||||
#[Computed]
|
||||
final public function reports(): \Illuminate\Pagination\LengthAwarePaginator
|
||||
{
|
||||
return Report::orderBy('solved')
|
||||
final protected \Illuminate\Pagination\LengthAwarePaginator $reports {
|
||||
get => Report::query()
|
||||
->with('reported.group', 'reporter.group', 'staff.group')
|
||||
->when($this->type !== null, fn ($query) => $query->where('type', '=', $this->type))
|
||||
->when($this->reporter !== null, fn ($query) => $query->whereIn('reporter_id', User::withTrashed()->select('id')->where('username', 'LIKE', '%'.$this->reporter.'%')))
|
||||
@@ -86,6 +80,7 @@ class ReportSearch extends Component
|
||||
->when($this->status === 'snoozed', fn ($query) => $query->where('solved', '=', false)->where('snoozed_until', '>', now()))
|
||||
->when($this->status === 'closed', fn ($query) => $query->where('solved', '=', true))
|
||||
->when($this->status === 'all_open', fn ($query) => $query->where('solved', '=', false))
|
||||
->orderBy('solved')
|
||||
->orderBy($this->sortField, $this->sortDirection)
|
||||
->paginate($this->perPage);
|
||||
}
|
||||
|
||||
@@ -19,14 +19,10 @@ namespace App\Http\Livewire;
|
||||
use App\Models\Rsskey;
|
||||
use App\Models\User;
|
||||
use App\Traits\LivewireSort;
|
||||
use Livewire\Attributes\Computed;
|
||||
use Livewire\Attributes\Url;
|
||||
use Livewire\Component;
|
||||
use Livewire\WithPagination;
|
||||
|
||||
/**
|
||||
* @property \Illuminate\Pagination\LengthAwarePaginator<int, Rsskey> $rsskeys
|
||||
*/
|
||||
class RsskeySearch extends Component
|
||||
{
|
||||
use LivewireSort;
|
||||
@@ -50,14 +46,13 @@ class RsskeySearch extends Component
|
||||
public int $perPage = 25;
|
||||
|
||||
/**
|
||||
* @return \Illuminate\Pagination\LengthAwarePaginator<int, Rsskey>
|
||||
* @var \Illuminate\Pagination\LengthAwarePaginator<int, Rsskey>
|
||||
*/
|
||||
#[Computed]
|
||||
final public function rsskeys(): \Illuminate\Pagination\LengthAwarePaginator
|
||||
{
|
||||
return Rsskey::with([
|
||||
'user' => fn ($query) => $query->withTrashed()->with('group'),
|
||||
])
|
||||
final protected \Illuminate\Pagination\LengthAwarePaginator $rsskeys {
|
||||
get => Rsskey::query()
|
||||
->with([
|
||||
'user' => fn ($query) => $query->withTrashed()->with('group'),
|
||||
])
|
||||
->when($this->username, fn ($query) => $query->whereIn('user_id', User::withTrashed()->select('id')->where('username', 'LIKE', '%'.$this->username.'%')))
|
||||
->when($this->rsskey, fn ($query) => $query->where('content', 'LIKE', '%'.$this->rsskey.'%'))
|
||||
->orderBy($this->sortField, $this->sortDirection)
|
||||
|
||||
@@ -35,7 +35,6 @@ use App\Services\Unit3dAnnounce;
|
||||
use App\Traits\CastLivewireProperties;
|
||||
use App\Traits\LivewireSort;
|
||||
use Illuminate\Support\Facades\Notification;
|
||||
use Livewire\Attributes\Computed;
|
||||
use Livewire\Attributes\Url;
|
||||
use Livewire\Component;
|
||||
|
||||
@@ -228,138 +227,138 @@ class SimilarTorrent extends Component
|
||||
/**
|
||||
* @phpstan-ignore missingType.generics (The return type is too complex for phpstan, something to do with lack of support of Collection array shapes)
|
||||
*/
|
||||
#[Computed]
|
||||
final public function torrents(): \Illuminate\Support\Collection
|
||||
{
|
||||
$user = auth()->user();
|
||||
final protected \Illuminate\Support\Collection $torrents {
|
||||
get {
|
||||
$user = auth()->user();
|
||||
|
||||
return Torrent::query()
|
||||
->with('type:id,name,position', 'resolution:id,name,position')
|
||||
->withCount([
|
||||
'comments',
|
||||
])
|
||||
->when(
|
||||
!config('announce.external_tracker.is_enabled'),
|
||||
fn ($query) => $query->withCount([
|
||||
'seeds' => fn ($query) => $query->where('active', '=', true)->where('visible', '=', true),
|
||||
'leeches' => fn ($query) => $query->where('active', '=', true)->where('visible', '=', true),
|
||||
]),
|
||||
)
|
||||
->when(
|
||||
config('other.thanks-system.is-enabled'),
|
||||
fn ($query) => $query->withCount('thanks')
|
||||
)
|
||||
->withExists([
|
||||
'featured as featured',
|
||||
'freeleechTokens' => fn ($query) => $query->where('user_id', '=', auth()->id()),
|
||||
'bookmarks' => fn ($query) => $query->where('user_id', '=', $user->id),
|
||||
'history as seeding' => fn ($query) => $query->where('user_id', '=', $user->id)
|
||||
->where('active', '=', 1)
|
||||
->where('seeder', '=', 1),
|
||||
'history as leeching' => fn ($query) => $query->where('user_id', '=', $user->id)
|
||||
->where('active', '=', 1)
|
||||
->where('seeder', '=', 0),
|
||||
'history as not_completed' => fn ($query) => $query->where('user_id', '=', $user->id)
|
||||
->where('active', '=', 0)
|
||||
->where('seeder', '=', 0)
|
||||
->whereNull('completed_at'),
|
||||
'history as not_seeding' => fn ($query) => $query->where('user_id', '=', $user->id)
|
||||
->where('active', '=', 0)
|
||||
->where(
|
||||
fn ($query) => $query
|
||||
->where('seeder', '=', 1)
|
||||
->orWhereNotNull('completed_at')
|
||||
),
|
||||
'trump',
|
||||
])
|
||||
->when(
|
||||
$this->category->movie_meta,
|
||||
fn ($query) => $query->whereRelation('category', 'movie_meta', '=', true),
|
||||
)
|
||||
->when(
|
||||
$this->category->tv_meta,
|
||||
fn ($query) => $query->whereRelation('category', 'tv_meta', '=', true),
|
||||
)
|
||||
->when($this->category->tv_meta, fn ($query) => $query->where('tmdb_tv_id', '=', $this->tmdbId))
|
||||
->when($this->category->movie_meta, fn ($query) => $query->where('tmdb_movie_id', '=', $this->tmdbId))
|
||||
->when($this->category->game_meta, fn ($query) => $query->where('igdb', '=', $this->igdbId))
|
||||
->where((new TorrentSearchFiltersDTO(
|
||||
name: $this->name,
|
||||
description: $this->description,
|
||||
mediainfo: $this->mediainfo,
|
||||
keywords: $this->keywords ? array_map('trim', explode(',', $this->keywords)) : [],
|
||||
uploader: $this->uploader,
|
||||
episodeNumber: $this->episodeNumber,
|
||||
seasonNumber: $this->seasonNumber,
|
||||
minSize: $this->minSize === null ? null : $this->minSize * $this->minSizeMultiplier,
|
||||
maxSize: $this->maxSize === null ? null : $this->maxSize * $this->maxSizeMultiplier,
|
||||
playlistId: $this->playlistId,
|
||||
typeIds: $this->typeIds,
|
||||
resolutionIds: $this->resolutionIds,
|
||||
free: $this->free,
|
||||
doubleup: $this->doubleup,
|
||||
featured: $this->featured,
|
||||
refundable: $this->refundable,
|
||||
internal: $this->internal,
|
||||
personalRelease: $this->personalRelease,
|
||||
trumpable: $this->trumpable,
|
||||
highspeed: $this->highspeed,
|
||||
userBookmarked: $this->bookmarked,
|
||||
userWished: $this->wished,
|
||||
alive: $this->alive,
|
||||
dying: $this->dying,
|
||||
dead: $this->dead,
|
||||
graveyard: $this->graveyard,
|
||||
userDownloaded: match (true) {
|
||||
$this->downloaded => true,
|
||||
$this->notDownloaded => false,
|
||||
default => null,
|
||||
},
|
||||
userSeeder: match (true) {
|
||||
$this->seeding => true,
|
||||
$this->leeching => false,
|
||||
default => null,
|
||||
},
|
||||
userActive: match (true) {
|
||||
$this->seeding => true,
|
||||
$this->leeching => true,
|
||||
default => null,
|
||||
},
|
||||
))->toSqlQueryBuilder())
|
||||
->orderBy($this->sortField, $this->sortDirection)
|
||||
->get()
|
||||
->when(
|
||||
$this->category->movie_meta,
|
||||
fn ($torrents) => $this->groupByTypeAndSort($torrents),
|
||||
fn ($torrents) => $torrents
|
||||
->when($this->category->tv_meta, function ($torrents) {
|
||||
return $torrents
|
||||
->groupBy(fn ($torrent) => $torrent->season_number === 0 ? ($torrent->episode_number === 0 ? 'Complete Pack' : 'Specials') : 'Seasons')
|
||||
->map(fn ($packOrSpecialOrSeasons, $key) => match ($key) {
|
||||
'Complete Pack' => $this->groupByTypeAndSort($packOrSpecialOrSeasons),
|
||||
'Specials' => $packOrSpecialOrSeasons
|
||||
->groupBy(fn ($torrent) => 'Special '.$torrent->episode_number)
|
||||
->sortKeysDesc(SORT_NATURAL)
|
||||
->map(fn ($episode) => $this->groupByTypeAndSort($episode)),
|
||||
'Seasons' => $packOrSpecialOrSeasons
|
||||
->groupBy(fn ($torrent) => 'Season '.$torrent->season_number)
|
||||
->sortKeysDesc(SORT_NATURAL)
|
||||
->map(
|
||||
fn ($season) => $season
|
||||
->groupBy(fn ($torrent) => $torrent->episode_number === 0 ? 'Season Pack' : 'Episodes')
|
||||
->map(fn ($packOrEpisodes, $key) => match ($key) {
|
||||
'Season Pack' => $this->groupByTypeAndSort($packOrEpisodes),
|
||||
'Episodes' => $packOrEpisodes
|
||||
->groupBy(fn ($torrent) => 'Episode '.$torrent->episode_number)
|
||||
->sortKeysDesc(SORT_NATURAL)
|
||||
->map(fn ($episode) => $this->groupByTypeAndSort($episode)),
|
||||
default => abort(500, 'Group found that isn\'t one of: Season Pack, Episodes.'),
|
||||
})
|
||||
),
|
||||
default => abort(500, 'Group found that isn\'t one of: Complete Pack, Specials, Seasons'),
|
||||
});
|
||||
})
|
||||
);
|
||||
return Torrent::query()
|
||||
->with('type:id,name,position', 'resolution:id,name,position')
|
||||
->withCount([
|
||||
'comments',
|
||||
])
|
||||
->when(
|
||||
!config('announce.external_tracker.is_enabled'),
|
||||
fn ($query) => $query->withCount([
|
||||
'seeds' => fn ($query) => $query->where('active', '=', true)->where('visible', '=', true),
|
||||
'leeches' => fn ($query) => $query->where('active', '=', true)->where('visible', '=', true),
|
||||
]),
|
||||
)
|
||||
->when(
|
||||
config('other.thanks-system.is-enabled'),
|
||||
fn ($query) => $query->withCount('thanks')
|
||||
)
|
||||
->withExists([
|
||||
'featured as featured',
|
||||
'freeleechTokens' => fn ($query) => $query->where('user_id', '=', auth()->id()),
|
||||
'bookmarks' => fn ($query) => $query->where('user_id', '=', $user->id),
|
||||
'history as seeding' => fn ($query) => $query->where('user_id', '=', $user->id)
|
||||
->where('active', '=', 1)
|
||||
->where('seeder', '=', 1),
|
||||
'history as leeching' => fn ($query) => $query->where('user_id', '=', $user->id)
|
||||
->where('active', '=', 1)
|
||||
->where('seeder', '=', 0),
|
||||
'history as not_completed' => fn ($query) => $query->where('user_id', '=', $user->id)
|
||||
->where('active', '=', 0)
|
||||
->where('seeder', '=', 0)
|
||||
->whereNull('completed_at'),
|
||||
'history as not_seeding' => fn ($query) => $query->where('user_id', '=', $user->id)
|
||||
->where('active', '=', 0)
|
||||
->where(
|
||||
fn ($query) => $query
|
||||
->where('seeder', '=', 1)
|
||||
->orWhereNotNull('completed_at')
|
||||
),
|
||||
'trump',
|
||||
])
|
||||
->when(
|
||||
$this->category->movie_meta,
|
||||
fn ($query) => $query->whereRelation('category', 'movie_meta', '=', true),
|
||||
)
|
||||
->when(
|
||||
$this->category->tv_meta,
|
||||
fn ($query) => $query->whereRelation('category', 'tv_meta', '=', true),
|
||||
)
|
||||
->when($this->category->tv_meta, fn ($query) => $query->where('tmdb_tv_id', '=', $this->tmdbId))
|
||||
->when($this->category->movie_meta, fn ($query) => $query->where('tmdb_movie_id', '=', $this->tmdbId))
|
||||
->when($this->category->game_meta, fn ($query) => $query->where('igdb', '=', $this->igdbId))
|
||||
->where((new TorrentSearchFiltersDTO(
|
||||
name: $this->name,
|
||||
description: $this->description,
|
||||
mediainfo: $this->mediainfo,
|
||||
keywords: $this->keywords ? array_map('trim', explode(',', $this->keywords)) : [],
|
||||
uploader: $this->uploader,
|
||||
episodeNumber: $this->episodeNumber,
|
||||
seasonNumber: $this->seasonNumber,
|
||||
minSize: $this->minSize === null ? null : $this->minSize * $this->minSizeMultiplier,
|
||||
maxSize: $this->maxSize === null ? null : $this->maxSize * $this->maxSizeMultiplier,
|
||||
playlistId: $this->playlistId,
|
||||
typeIds: $this->typeIds,
|
||||
resolutionIds: $this->resolutionIds,
|
||||
free: $this->free,
|
||||
doubleup: $this->doubleup,
|
||||
featured: $this->featured,
|
||||
refundable: $this->refundable,
|
||||
internal: $this->internal,
|
||||
personalRelease: $this->personalRelease,
|
||||
trumpable: $this->trumpable,
|
||||
highspeed: $this->highspeed,
|
||||
userBookmarked: $this->bookmarked,
|
||||
userWished: $this->wished,
|
||||
alive: $this->alive,
|
||||
dying: $this->dying,
|
||||
dead: $this->dead,
|
||||
graveyard: $this->graveyard,
|
||||
userDownloaded: match (true) {
|
||||
$this->downloaded => true,
|
||||
$this->notDownloaded => false,
|
||||
default => null,
|
||||
},
|
||||
userSeeder: match (true) {
|
||||
$this->seeding => true,
|
||||
$this->leeching => false,
|
||||
default => null,
|
||||
},
|
||||
userActive: match (true) {
|
||||
$this->seeding => true,
|
||||
$this->leeching => true,
|
||||
default => null,
|
||||
},
|
||||
))->toSqlQueryBuilder())
|
||||
->orderBy($this->sortField, $this->sortDirection)
|
||||
->get()
|
||||
->when(
|
||||
$this->category->movie_meta,
|
||||
fn ($torrents) => $this->groupByTypeAndSort($torrents),
|
||||
fn ($torrents) => $torrents
|
||||
->when($this->category->tv_meta, function ($torrents) {
|
||||
return $torrents
|
||||
->groupBy(fn ($torrent) => $torrent->season_number === 0 ? ($torrent->episode_number === 0 ? 'Complete Pack' : 'Specials') : 'Seasons')
|
||||
->map(fn ($packOrSpecialOrSeasons, $key) => match ($key) {
|
||||
'Complete Pack' => $this->groupByTypeAndSort($packOrSpecialOrSeasons),
|
||||
'Specials' => $packOrSpecialOrSeasons
|
||||
->groupBy(fn ($torrent) => 'Special '.$torrent->episode_number)
|
||||
->sortKeysDesc(SORT_NATURAL)
|
||||
->map(fn ($episode) => $this->groupByTypeAndSort($episode)),
|
||||
'Seasons' => $packOrSpecialOrSeasons
|
||||
->groupBy(fn ($torrent) => 'Season '.$torrent->season_number)
|
||||
->sortKeysDesc(SORT_NATURAL)
|
||||
->map(
|
||||
fn ($season) => $season
|
||||
->groupBy(fn ($torrent) => $torrent->episode_number === 0 ? 'Season Pack' : 'Episodes')
|
||||
->map(fn ($packOrEpisodes, $key) => match ($key) {
|
||||
'Season Pack' => $this->groupByTypeAndSort($packOrEpisodes),
|
||||
'Episodes' => $packOrEpisodes
|
||||
->groupBy(fn ($torrent) => 'Episode '.$torrent->episode_number)
|
||||
->sortKeysDesc(SORT_NATURAL)
|
||||
->map(fn ($episode) => $this->groupByTypeAndSort($episode)),
|
||||
default => abort(500, 'Group found that isn\'t one of: Season Pack, Episodes.'),
|
||||
})
|
||||
),
|
||||
default => abort(500, 'Group found that isn\'t one of: Complete Pack, Specials, Seasons'),
|
||||
});
|
||||
})
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -383,12 +382,10 @@ class SimilarTorrent extends Component
|
||||
}
|
||||
|
||||
/**
|
||||
* @return \Illuminate\Database\Eloquent\Collection<int, TorrentRequest>
|
||||
* @var \Illuminate\Database\Eloquent\Collection<int, TorrentRequest>
|
||||
*/
|
||||
#[Computed]
|
||||
final public function torrentRequests(): \Illuminate\Database\Eloquent\Collection
|
||||
{
|
||||
return TorrentRequest::with(['user:id,username,group_id', 'user.group', 'category', 'type', 'resolution'])
|
||||
final protected \Illuminate\Database\Eloquent\Collection $torrentRequests {
|
||||
get => TorrentRequest::with(['user:id,username,group_id', 'user.group', 'category', 'type', 'resolution'])
|
||||
->withCount(['comments'])
|
||||
->withExists('claim')
|
||||
->when($this->category->movie_meta, fn ($query) => $query->where('tmdb_movie_id', '=', $this->tmdbId))
|
||||
@@ -404,12 +401,10 @@ class SimilarTorrent extends Component
|
||||
}
|
||||
|
||||
/**
|
||||
* @return \Illuminate\Database\Eloquent\Collection<int, PlaylistCategory>
|
||||
* @var \Illuminate\Database\Eloquent\Collection<int, PlaylistCategory>
|
||||
*/
|
||||
#[Computed]
|
||||
final public function playlistCategories(): \Illuminate\Database\Eloquent\Collection
|
||||
{
|
||||
return PlaylistCategory::query()
|
||||
final protected \Illuminate\Database\Eloquent\Collection $playlistCategories {
|
||||
get => PlaylistCategory::query()
|
||||
->with([
|
||||
'playlists' => fn ($query) => $query
|
||||
->withCount('torrents')
|
||||
@@ -433,16 +428,10 @@ class SimilarTorrent extends Component
|
||||
}
|
||||
|
||||
/**
|
||||
* @return ?\Illuminate\Database\Eloquent\Collection<int, TmdbMovie>
|
||||
* @var ?\Illuminate\Database\Eloquent\Collection<int, TmdbMovie>
|
||||
*/
|
||||
#[Computed]
|
||||
final public function collectionMovies(): ?\Illuminate\Database\Eloquent\Collection
|
||||
{
|
||||
if (!$this->work instanceof TmdbMovie) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return $this->work->collections()->first()?->movies()->get();
|
||||
final protected ?\Illuminate\Database\Eloquent\Collection $collectionMovies {
|
||||
get => $this->work instanceof TmdbMovie ? $this->work->collections()->first()?->movies()->get() : null;
|
||||
}
|
||||
|
||||
final public function alertConfirm(): void
|
||||
@@ -475,9 +464,9 @@ class SimilarTorrent extends Component
|
||||
$torrents = Torrent::whereKey($this->checked)->get();
|
||||
$users = [];
|
||||
$title = match (true) {
|
||||
$this->category->movie_meta => ($movie = TmdbMovie::find($this->tmdbId))->title.' ('.$movie->release_date->format('Y').')',
|
||||
$this->category->tv_meta => ($tv = TmdbTv::find($this->tmdbId))->name.' ('.$tv->first_air_date->format('Y').')',
|
||||
$this->category->game_meta => ($game = IgdbGame::find($this->igdbId))->name.' ('.$game->first_release_date->format('Y').')',
|
||||
$this->category->movie_meta => ($movie = TmdbMovie::find($this->tmdbId))->title.($movie->release_date === null ? '' : ' ('.$movie->release_date->format('Y').')'),
|
||||
$this->category->tv_meta => ($tv = TmdbTv::find($this->tmdbId))->name.($tv->first_air_date === null ? '' : ' ('.$tv->first_air_date->format('Y').')'),
|
||||
$this->category->game_meta => ($game = IgdbGame::find($this->igdbId))->name.($game->first_release_date === null ? '' : ' ('.$game->first_release_date->format('Y').')'),
|
||||
default => $torrents->pluck('name')->join(', '),
|
||||
};
|
||||
|
||||
@@ -537,46 +526,52 @@ class SimilarTorrent extends Component
|
||||
);
|
||||
}
|
||||
|
||||
#[Computed]
|
||||
final public function personalFreeleech(): bool
|
||||
{
|
||||
return cache()->get('personal_freeleech:'.auth()->id()) ?? false;
|
||||
final protected bool $personalFreeleech {
|
||||
get => cache()->get('personal_freeleech:'.auth()->id()) ?? false;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return \Illuminate\Database\Eloquent\Collection<int, Type>
|
||||
* @var \Illuminate\Database\Eloquent\Collection<int, Type>
|
||||
*/
|
||||
#[Computed(seconds: 3600, cache: true)]
|
||||
final public function types(): \Illuminate\Database\Eloquent\Collection
|
||||
{
|
||||
return Type::query()->orderBy('position')->get();
|
||||
final protected \Illuminate\Database\Eloquent\Collection $types {
|
||||
get => cache()->remember(
|
||||
'types',
|
||||
3600,
|
||||
fn () => Type::query()->orderBy('position')->get(),
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return \Illuminate\Database\Eloquent\Collection<int, Resolution>
|
||||
* @var \Illuminate\Database\Eloquent\Collection<int, Resolution>
|
||||
*/
|
||||
#[Computed(seconds: 3600, cache: true)]
|
||||
final public function resolutions(): \Illuminate\Database\Eloquent\Collection
|
||||
{
|
||||
return Resolution::query()->orderBy('position')->get();
|
||||
final protected \Illuminate\Database\Eloquent\Collection $resolutions {
|
||||
get => cache()->remember(
|
||||
'resolutions',
|
||||
3600,
|
||||
fn () => Resolution::query()->orderBy('position')->get(),
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return \Illuminate\Database\Eloquent\Collection<int, Region>
|
||||
* @var \Illuminate\Database\Eloquent\Collection<int, Region>
|
||||
*/
|
||||
#[Computed(seconds: 3600, cache: true)]
|
||||
final public function regions(): \Illuminate\Database\Eloquent\Collection
|
||||
{
|
||||
return Region::query()->orderBy('position')->get();
|
||||
final protected \Illuminate\Database\Eloquent\Collection $regions {
|
||||
get => cache()->remember(
|
||||
'regions',
|
||||
3600,
|
||||
fn () => Region::query()->orderBy('position')->get(),
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return \Illuminate\Database\Eloquent\Collection<int, Distributor>
|
||||
* @var \Illuminate\Database\Eloquent\Collection<int, Distributor>
|
||||
*/
|
||||
#[Computed(seconds: 3600, cache: true)]
|
||||
final public function distributors(): \Illuminate\Database\Eloquent\Collection
|
||||
{
|
||||
return Distributor::query()->orderBy('name')->get();
|
||||
final protected \Illuminate\Database\Eloquent\Collection $distributors {
|
||||
get => cache()->remember(
|
||||
'distributors',
|
||||
3600,
|
||||
fn () => Distributor::query()->orderBy('name')->get(),
|
||||
);
|
||||
}
|
||||
|
||||
final public function render(): \Illuminate\Contracts\View\Factory|\Illuminate\Contracts\View\View|\Illuminate\Contracts\Foundation\Application
|
||||
|
||||
@@ -18,34 +18,39 @@ namespace App\Http\Livewire\Stats;
|
||||
|
||||
use App\Models\History;
|
||||
use App\Models\Peer;
|
||||
use Livewire\Attributes\Computed;
|
||||
use Livewire\Attributes\Lazy;
|
||||
use Livewire\Component;
|
||||
|
||||
#[Lazy(isolate: true)]
|
||||
class PeerStats extends Component
|
||||
{
|
||||
#[Computed(cache: true, seconds: 10 * 60)]
|
||||
final public function leecherCount(): int
|
||||
{
|
||||
// Generally sites have more seeders than leechers, so it ends up being faster (by approximately 50%) to compute leechers and total instead of seeders and leechers.
|
||||
return Peer::query()->where('seeder', '=', false)->where('active', '=', true)->count();
|
||||
final protected int $leecherCount {
|
||||
get => (int) cache()->remember(
|
||||
'peer-stats:leecher-count',
|
||||
10 * 60,
|
||||
// Generally sites have more seeders than leechers, so it ends up being faster (by approximately 50%) to compute leechers and total instead of seeders and leechers.
|
||||
fn () => Peer::query()->where('seeder', '=', false)->where('active', '=', true)->count()
|
||||
);
|
||||
}
|
||||
|
||||
#[Computed(cache: true, seconds: 10 * 60)]
|
||||
final public function peerCount(): int
|
||||
{
|
||||
return Peer::query()->where('active', '=', true)->count();
|
||||
final protected int $peerCount {
|
||||
get => (int) cache()->remember(
|
||||
'peer-stats:peer-count',
|
||||
10 * 60,
|
||||
fn () => Peer::query()->where('active', '=', true)->count(),
|
||||
);
|
||||
}
|
||||
|
||||
#[Computed(cache: true, seconds: 10 * 60)]
|
||||
final public function totalSeeded(): int
|
||||
{
|
||||
return (int) History::query()
|
||||
->join('torrents', 'history.torrent_id', '=', 'torrents.id')
|
||||
->where('history.active', '=', true)
|
||||
->where('history.seeder', '=', true)
|
||||
->sum('size');
|
||||
final protected int $totalSeeded {
|
||||
get => (int) cache()->remember(
|
||||
'peer-stats:total-seeded',
|
||||
10 * 60,
|
||||
fn () => History::query()
|
||||
->join('torrents', 'history.torrent_id', '=', 'torrents.id')
|
||||
->where('history.active', '=', true)
|
||||
->where('history.seeder', '=', true)
|
||||
->sum('size'),
|
||||
);
|
||||
}
|
||||
|
||||
final public function placeholder(): string
|
||||
|
||||
@@ -19,41 +19,48 @@ namespace App\Http\Livewire\Stats;
|
||||
use App\Models\Category;
|
||||
use App\Models\Resolution;
|
||||
use App\Models\Torrent;
|
||||
use Livewire\Attributes\Computed;
|
||||
use Livewire\Attributes\Lazy;
|
||||
use Livewire\Component;
|
||||
|
||||
#[Lazy(isolate: true)]
|
||||
class TorrentStats extends Component
|
||||
{
|
||||
#[Computed(cache: true, seconds: 10 * 60)]
|
||||
final public function totalCount(): int
|
||||
{
|
||||
return Torrent::query()->count();
|
||||
final protected int $totalCount {
|
||||
get => (int) cache()->remember(
|
||||
'torrent-stats:total-count',
|
||||
10 * 60,
|
||||
fn () => Torrent::query()->count(),
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return \Illuminate\Database\Eloquent\Collection<int, Resolution>
|
||||
* @var \Illuminate\Database\Eloquent\Collection<int, Resolution>
|
||||
*/
|
||||
#[Computed(cache: true, seconds: 10 * 60)]
|
||||
final public function resolutions(): \Illuminate\Database\Eloquent\Collection
|
||||
{
|
||||
return Resolution::query()->withCount('torrents')->orderBy('position')->get();
|
||||
final protected \Illuminate\Database\Eloquent\Collection $resolutions {
|
||||
get => cache()->remember(
|
||||
'torrent-stats:resolutions',
|
||||
10 * 60,
|
||||
fn () => Resolution::query()->withCount('torrents')->orderBy('position')->get(),
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return \Illuminate\Database\Eloquent\Collection<int, Category>
|
||||
* @var \Illuminate\Database\Eloquent\Collection<int, Category>
|
||||
*/
|
||||
#[Computed(cache: true, seconds: 10 * 60)]
|
||||
final public function categories(): \Illuminate\Database\Eloquent\Collection
|
||||
{
|
||||
return Category::query()->withCount('torrents')->orderBy('position')->get();
|
||||
final protected \Illuminate\Database\Eloquent\Collection $categories {
|
||||
get => cache()->remember(
|
||||
'torrent-stats:categories',
|
||||
10 * 60,
|
||||
fn () => Category::query()->withCount('torrents')->orderBy('position')->get(),
|
||||
);
|
||||
}
|
||||
|
||||
#[Computed(cache: true, seconds: 10 * 60)]
|
||||
final public function sizeSum(): int
|
||||
{
|
||||
return (int) Torrent::query()->sum('size');
|
||||
final protected int $sizeSum {
|
||||
get => (int) cache()->remember(
|
||||
'torrent-stats:size-sum',
|
||||
10 * 60,
|
||||
fn () => Torrent::query()->sum('size'),
|
||||
);
|
||||
}
|
||||
|
||||
final public function placeholder(): string
|
||||
|
||||
@@ -17,35 +17,42 @@ declare(strict_types=1);
|
||||
namespace App\Http\Livewire\Stats;
|
||||
|
||||
use App\Models\History;
|
||||
use Livewire\Attributes\Computed;
|
||||
use Livewire\Attributes\Lazy;
|
||||
use Livewire\Component;
|
||||
|
||||
#[Lazy(isolate: true)]
|
||||
class TrafficStats extends Component
|
||||
{
|
||||
#[Computed(cache: true, seconds: 10 * 60)]
|
||||
final public function actualUpload(): int
|
||||
{
|
||||
return (int) History::query()->sum('actual_uploaded');
|
||||
final protected int $actualUpload {
|
||||
get => (int) cache()->remember(
|
||||
'traffic-stats:actual-upload',
|
||||
10 * 60,
|
||||
fn () => History::query()->sum('actual_uploaded'),
|
||||
);
|
||||
}
|
||||
|
||||
#[Computed(cache: true, seconds: 10 * 60)]
|
||||
final public function creditedUpload(): int
|
||||
{
|
||||
return (int) History::query()->sum('uploaded');
|
||||
final protected int $creditedUpload {
|
||||
get => (int) cache()->remember(
|
||||
'traffic-stats:credited-upload',
|
||||
10 * 60,
|
||||
fn () => History::query()->sum('uploaded'),
|
||||
);
|
||||
}
|
||||
|
||||
#[Computed(cache: true, seconds: 10 * 60)]
|
||||
final public function actualDownload(): int
|
||||
{
|
||||
return (int) History::query()->sum('actual_downloaded');
|
||||
final protected int $actualDownload {
|
||||
get => (int) cache()->remember(
|
||||
'traffic-stats:actual-download',
|
||||
10 * 60,
|
||||
fn () => History::query()->sum('actual_downloaded'),
|
||||
);
|
||||
}
|
||||
|
||||
#[Computed(cache: true, seconds: 10 * 60)]
|
||||
final public function creditedDownload(): int
|
||||
{
|
||||
return (int) History::query()->sum('downloaded');
|
||||
final protected int $creditedDownload {
|
||||
get => (int) cache()->remember(
|
||||
'traffic-stats:credited-download',
|
||||
10 * 60,
|
||||
fn () => History::query()->sum('downloaded'),
|
||||
);
|
||||
}
|
||||
|
||||
final public function placeholder(): string
|
||||
|
||||
@@ -17,59 +17,74 @@ declare(strict_types=1);
|
||||
namespace App\Http\Livewire\Stats;
|
||||
|
||||
use App\Models\User;
|
||||
use Livewire\Attributes\Computed;
|
||||
use Livewire\Attributes\Lazy;
|
||||
use Livewire\Component;
|
||||
|
||||
#[Lazy(isolate: true)]
|
||||
class UserStats extends Component
|
||||
{
|
||||
#[Computed(cache: true, seconds: 10 * 60)]
|
||||
final public function allUsers(): int
|
||||
{
|
||||
return User::query()->withTrashed()->count();
|
||||
final protected int $allUsers {
|
||||
get => (int) cache()->remember(
|
||||
'user-stats:all-users',
|
||||
10 * 60,
|
||||
fn () => User::query()->withTrashed()->count(),
|
||||
);
|
||||
}
|
||||
|
||||
#[Computed(cache: true, seconds: 10 * 60)]
|
||||
final public function activeUsers(): int
|
||||
{
|
||||
return User::query()->whereHas('group', fn ($query) => $query->whereNotIn('slug', ['banned', 'validating', 'disabled', 'pruned']))->count();
|
||||
final protected int $activeUsers {
|
||||
get => (int) cache()->remember(
|
||||
'user-stats:active-users',
|
||||
10 * 60,
|
||||
fn () => User::query()->whereHas('group', fn ($query) => $query->whereNotIn('slug', ['banned', 'validating', 'disabled', 'pruned']))->count(),
|
||||
);
|
||||
}
|
||||
|
||||
#[Computed(cache: true, seconds: 10 * 60)]
|
||||
final public function disableUsers(): int
|
||||
{
|
||||
return User::query()->whereRelation('group', 'slug', '=', 'disabled')->count();
|
||||
final protected int $disableUsers {
|
||||
get => (int) cache()->remember(
|
||||
'user-stats:disable-users',
|
||||
10 * 60,
|
||||
fn () => User::query()->whereRelation('group', 'slug', '=', 'disabled')->count(),
|
||||
);
|
||||
}
|
||||
|
||||
#[Computed(cache: true, seconds: 10 * 60)]
|
||||
final public function prunedUsers(): int
|
||||
{
|
||||
return User::query()->onlyTrashed()->whereRelation('group', 'slug', '=', 'pruned')->count();
|
||||
final protected int $prunedUsers {
|
||||
get => (int) cache()->remember(
|
||||
'user-stats:pruned-users',
|
||||
10 * 60,
|
||||
fn () => User::query()->onlyTrashed()->whereRelation('group', 'slug', '=', 'pruned')->count(),
|
||||
);
|
||||
}
|
||||
|
||||
#[Computed(cache: true, seconds: 10 * 60)]
|
||||
final public function bannedUsers(): int
|
||||
{
|
||||
return User::query()->whereRelation('group', 'slug', '=', 'banned')->count();
|
||||
final protected int $bannedUsers {
|
||||
get => (int) cache()->remember(
|
||||
'user-stats:banned-users',
|
||||
10 * 60,
|
||||
fn () => User::query()->whereRelation('group', 'slug', '=', 'banned')->count(),
|
||||
);
|
||||
}
|
||||
|
||||
#[Computed(cache: true, seconds: 10 * 60)]
|
||||
final public function usersActiveToday(): int
|
||||
{
|
||||
return User::query()->where('last_action', '>', now()->subDay())->count();
|
||||
final protected int $usersActiveToday {
|
||||
get => (int) cache()->remember(
|
||||
'user-stats:users-active-today',
|
||||
10 * 60,
|
||||
fn () => User::query()->where('last_action', '>', now()->subDay())->count(),
|
||||
);
|
||||
}
|
||||
|
||||
#[Computed(cache: true, seconds: 10 * 60)]
|
||||
final public function usersActiveThisWeek(): int
|
||||
{
|
||||
return User::query()->where('last_action', '>', now()->subWeek())->count();
|
||||
final protected int $usersActiveThisWeek {
|
||||
get => (int) cache()->remember(
|
||||
'user-stats:users-active-this-week',
|
||||
10 * 60,
|
||||
fn () => User::query()->where('last_action', '>', now()->subWeek())->count(),
|
||||
);
|
||||
}
|
||||
|
||||
#[Computed(cache: true, seconds: 10 * 60)]
|
||||
final public function usersActiveThisMonth(): int
|
||||
{
|
||||
return User::query()->where('last_action', '>', now()->subMonth())->count();
|
||||
final protected int $usersActiveThisMonth {
|
||||
get => (int) cache()->remember(
|
||||
'user-stats:users-active-this-month',
|
||||
10 * 60,
|
||||
fn () => User::query()->where('last_action', '>', now()->subMonth())->count(),
|
||||
);
|
||||
}
|
||||
|
||||
final public function placeholder(): string
|
||||
|
||||
@@ -17,7 +17,6 @@ declare(strict_types=1);
|
||||
namespace App\Http\Livewire;
|
||||
|
||||
use App\Models\Forum;
|
||||
use Livewire\Attributes\Computed;
|
||||
use Livewire\Component;
|
||||
use Livewire\WithPagination;
|
||||
|
||||
@@ -26,12 +25,10 @@ class SubscribedForum extends Component
|
||||
use WithPagination;
|
||||
|
||||
/**
|
||||
* @return \Illuminate\Pagination\LengthAwarePaginator<int, Forum>
|
||||
* @var \Illuminate\Pagination\LengthAwarePaginator<int, Forum>
|
||||
*/
|
||||
#[Computed]
|
||||
final public function forums()
|
||||
{
|
||||
return Forum::query()
|
||||
final protected $forums {
|
||||
get => Forum::query()
|
||||
->with('latestPoster', 'lastRepliedTopic')
|
||||
->whereRelation('subscribedUsers', 'users.id', '=', auth()->id())
|
||||
->authorized(canReadTopic: true)
|
||||
|
||||
@@ -17,7 +17,6 @@ declare(strict_types=1);
|
||||
namespace App\Http\Livewire;
|
||||
|
||||
use App\Models\Topic;
|
||||
use Livewire\Attributes\Computed;
|
||||
use Livewire\Component;
|
||||
use Livewire\WithPagination;
|
||||
|
||||
@@ -26,12 +25,10 @@ class SubscribedTopic extends Component
|
||||
use WithPagination;
|
||||
|
||||
/**
|
||||
* @return \Illuminate\Pagination\LengthAwarePaginator<int, Topic>
|
||||
* @var \Illuminate\Pagination\LengthAwarePaginator<int, Topic>
|
||||
*/
|
||||
#[Computed]
|
||||
final public function topics(): \Illuminate\Pagination\LengthAwarePaginator
|
||||
{
|
||||
return Topic::query()
|
||||
final protected \Illuminate\Pagination\LengthAwarePaginator $topics {
|
||||
get => Topic::query()
|
||||
->select('topics.*')
|
||||
->with([
|
||||
'user.group',
|
||||
|
||||
@@ -18,7 +18,6 @@ namespace App\Http\Livewire;
|
||||
|
||||
use App\Models\Subtitle;
|
||||
use App\Traits\LivewireSort;
|
||||
use Livewire\Attributes\Computed;
|
||||
use Livewire\Attributes\Url;
|
||||
use Livewire\Component;
|
||||
use Livewire\WithPagination;
|
||||
@@ -60,12 +59,11 @@ class SubtitleSearch extends Component
|
||||
}
|
||||
|
||||
/**
|
||||
* @return \Illuminate\Pagination\LengthAwarePaginator<int, Subtitle>
|
||||
* @var \Illuminate\Pagination\LengthAwarePaginator<int, Subtitle>
|
||||
*/
|
||||
#[Computed]
|
||||
final public function subtitles(): \Illuminate\Pagination\LengthAwarePaginator
|
||||
{
|
||||
return Subtitle::with(['user.group', 'torrent.category', 'language'])
|
||||
final protected \Illuminate\Pagination\LengthAwarePaginator $subtitles {
|
||||
get => Subtitle::query()
|
||||
->with(['user.group', 'torrent.category', 'language'])
|
||||
->whereHas('torrent')
|
||||
->when($this->search, fn ($query) => $query->where('title', 'like', '%'.$this->search.'%'))
|
||||
->when($this->categories, fn ($query) => $query->whereHas('torrent', fn ($query) => $query->whereIn('category_id', $this->categories)))
|
||||
|
||||
@@ -19,14 +19,10 @@ namespace App\Http\Livewire;
|
||||
use App\Models\Ticket;
|
||||
use App\Models\User;
|
||||
use App\Traits\LivewireSort;
|
||||
use Livewire\Attributes\Computed;
|
||||
use Livewire\Attributes\Url;
|
||||
use Livewire\Component;
|
||||
use Livewire\WithPagination;
|
||||
|
||||
/**
|
||||
* @property \Illuminate\Pagination\LengthAwarePaginator<int, Ticket> $tickets
|
||||
*/
|
||||
class TicketSearch extends Component
|
||||
{
|
||||
use LivewireSort;
|
||||
@@ -71,12 +67,10 @@ class TicketSearch extends Component
|
||||
}
|
||||
|
||||
/**
|
||||
* @return \Illuminate\Pagination\LengthAwarePaginator<int, Ticket>
|
||||
* @var \Illuminate\Pagination\LengthAwarePaginator<int, Ticket>
|
||||
*/
|
||||
#[Computed]
|
||||
final public function tickets(): \Illuminate\Pagination\LengthAwarePaginator
|
||||
{
|
||||
return Ticket::query()
|
||||
final protected \Illuminate\Pagination\LengthAwarePaginator $tickets {
|
||||
get => Ticket::query()
|
||||
->with(['user.group', 'staff.group', 'category', 'priority'])
|
||||
->when(!$this->user->group->is_modo, fn ($query) => $query->where('user_id', '=', $this->user->id))
|
||||
->when(
|
||||
|
||||
@@ -17,7 +17,6 @@ declare(strict_types=1);
|
||||
namespace App\Http\Livewire;
|
||||
|
||||
use App\Models\TmdbCollection;
|
||||
use Livewire\Attributes\Computed;
|
||||
use Livewire\Attributes\Url;
|
||||
use Livewire\Component;
|
||||
use Livewire\WithPagination;
|
||||
@@ -37,12 +36,10 @@ class TmdbCollectionSearch extends Component
|
||||
}
|
||||
|
||||
/**
|
||||
* @return \Illuminate\Pagination\LengthAwarePaginator<int, TmdbCollection>
|
||||
* @var \Illuminate\Pagination\LengthAwarePaginator<int, TmdbCollection>
|
||||
*/
|
||||
#[Computed]
|
||||
final public function collections(): \Illuminate\Pagination\LengthAwarePaginator
|
||||
{
|
||||
return TmdbCollection::withCount('movies')
|
||||
final protected \Illuminate\Pagination\LengthAwarePaginator $collections {
|
||||
get => TmdbCollection::withCount('movies')
|
||||
->with('movies')
|
||||
->when($this->search !== '', fn ($query) => $query->where('name', 'LIKE', '%'.$this->search.'%'))
|
||||
->oldest('name')
|
||||
|
||||
@@ -17,7 +17,6 @@ declare(strict_types=1);
|
||||
namespace App\Http\Livewire;
|
||||
|
||||
use App\Models\TmdbCompany;
|
||||
use Livewire\Attributes\Computed;
|
||||
use Livewire\Attributes\Url;
|
||||
use Livewire\Component;
|
||||
use Livewire\WithPagination;
|
||||
@@ -37,12 +36,10 @@ class TmdbCompanySearch extends Component
|
||||
}
|
||||
|
||||
/**
|
||||
* @return \Illuminate\Pagination\LengthAwarePaginator<int, TmdbCompany>
|
||||
* @var \Illuminate\Pagination\LengthAwarePaginator<int, TmdbCompany>
|
||||
*/
|
||||
#[Computed]
|
||||
final public function companies(): \Illuminate\Pagination\LengthAwarePaginator
|
||||
{
|
||||
return TmdbCompany::query()
|
||||
final protected \Illuminate\Pagination\LengthAwarePaginator $companies {
|
||||
get => TmdbCompany::query()
|
||||
->withCount([
|
||||
'movie' => fn ($query) => $query->has('torrents'),
|
||||
'tv' => fn ($query) => $query->has('torrents'),
|
||||
|
||||
@@ -17,7 +17,6 @@ declare(strict_types=1);
|
||||
namespace App\Http\Livewire;
|
||||
|
||||
use App\Models\TmdbNetwork;
|
||||
use Livewire\Attributes\Computed;
|
||||
use Livewire\Attributes\Url;
|
||||
use Livewire\Component;
|
||||
use Livewire\WithPagination;
|
||||
@@ -37,12 +36,10 @@ class TmdbNetworkSearch extends Component
|
||||
}
|
||||
|
||||
/**
|
||||
* @return \Illuminate\Pagination\LengthAwarePaginator<int, TmdbNetwork>
|
||||
* @var \Illuminate\Pagination\LengthAwarePaginator<int, TmdbNetwork>
|
||||
*/
|
||||
#[Computed]
|
||||
final public function networks(): \Illuminate\Pagination\LengthAwarePaginator
|
||||
{
|
||||
return TmdbNetwork::query()
|
||||
final protected \Illuminate\Pagination\LengthAwarePaginator $networks {
|
||||
get => TmdbNetwork::query()
|
||||
->withCount([
|
||||
'tv' => fn ($query) => $query->has('torrents'),
|
||||
])
|
||||
|
||||
@@ -20,7 +20,6 @@ use App\Enums\Occupation;
|
||||
use App\Models\TmdbPerson;
|
||||
use App\Models\Torrent;
|
||||
use App\Models\User;
|
||||
use Livewire\Attributes\Computed;
|
||||
use Livewire\Attributes\Url;
|
||||
use Livewire\Component;
|
||||
|
||||
@@ -50,10 +49,8 @@ class TmdbPersonCredit extends Component
|
||||
};
|
||||
}
|
||||
|
||||
#[Computed]
|
||||
final public function personalFreeleech(): bool
|
||||
{
|
||||
return cache()->get('personal_freeleech:'.auth()->user()->id) ?? false;
|
||||
final protected bool $personalFreeleech {
|
||||
get => cache()->get('personal_freeleech:'.auth()->user()->id) ?? false;
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -64,291 +61,271 @@ class TmdbPersonCredit extends Component
|
||||
$value = Occupation::from($value);
|
||||
}
|
||||
|
||||
#[Computed]
|
||||
public function directedCount(): int
|
||||
{
|
||||
return $this->person->directedMovies()->count() + $this->person->directedTv()->count();
|
||||
final protected int $directedCount {
|
||||
get => $this->person->directedMovies()->count() + $this->person->directedTv()->count();
|
||||
}
|
||||
|
||||
#[Computed]
|
||||
public function createdCount(): int
|
||||
{
|
||||
return $this->person->createdTv()->count();
|
||||
final protected int $createdCount {
|
||||
get => $this->person->createdTv()->count();
|
||||
}
|
||||
|
||||
#[Computed]
|
||||
public function writtenCount(): int
|
||||
{
|
||||
return $this->person->writtenMovies()->count() + $this->person->writtenTv()->count();
|
||||
final protected int $writtenCount {
|
||||
get => $this->person->writtenMovies()->count() + $this->person->writtenTv()->count();
|
||||
}
|
||||
|
||||
#[Computed]
|
||||
public function producedCount(): int
|
||||
{
|
||||
return $this->person->producedMovies()->count() + $this->person->producedTv()->count();
|
||||
final protected int $producedCount {
|
||||
get => $this->person->producedMovies()->count() + $this->person->producedTv()->count();
|
||||
}
|
||||
|
||||
#[Computed]
|
||||
public function composedCount(): int
|
||||
{
|
||||
return $this->person->composedMovies()->count() + $this->person->composedTv()->count();
|
||||
final protected int $composedCount {
|
||||
get => $this->person->composedMovies()->count() + $this->person->composedTv()->count();
|
||||
}
|
||||
|
||||
#[Computed]
|
||||
public function cinematographedCount(): int
|
||||
{
|
||||
return $this->person->cinematographedMovies()->count() + $this->person->cinematographedTv()->count();
|
||||
final protected int $cinematographedCount {
|
||||
get => $this->person->cinematographedMovies()->count() + $this->person->cinematographedTv()->count();
|
||||
}
|
||||
|
||||
#[Computed]
|
||||
public function editedCount(): int
|
||||
{
|
||||
return $this->person->editedMovies()->count() + $this->person->editedTv()->count();
|
||||
final protected int $editedCount {
|
||||
get => $this->person->editedMovies()->count() + $this->person->editedTv()->count();
|
||||
}
|
||||
|
||||
#[Computed]
|
||||
public function productionDesignedCount(): int
|
||||
{
|
||||
return $this->person->productionDesignedMovies()->count() + $this->person->productionDesignedTv()->count();
|
||||
final protected int $productionDesignedCount {
|
||||
get => $this->person->productionDesignedMovies()->count() + $this->person->productionDesignedTv()->count();
|
||||
}
|
||||
|
||||
#[Computed]
|
||||
public function artDirectedCount(): int
|
||||
{
|
||||
return $this->person->artDirectedMovies()->count() + $this->person->artDirectedTv()->count();
|
||||
final protected int $artDirectedCount {
|
||||
get => $this->person->artDirectedMovies()->count() + $this->person->artDirectedTv()->count();
|
||||
}
|
||||
|
||||
#[Computed]
|
||||
public function actedCount(): int
|
||||
{
|
||||
return $this->person->actedMovies()->count() + $this->person->actedTv()->count();
|
||||
final protected int $actedCount {
|
||||
get => $this->person->actedMovies()->count() + $this->person->actedTv()->count();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return \Illuminate\Support\Collection<int, Torrent>
|
||||
*/
|
||||
#[Computed]
|
||||
final public function medias(): \Illuminate\Support\Collection
|
||||
{
|
||||
if ($this->occupationId === null) {
|
||||
return collect();
|
||||
}
|
||||
final protected \Illuminate\Support\Collection $medias {
|
||||
get {
|
||||
if ($this->occupationId === null) {
|
||||
return collect();
|
||||
}
|
||||
|
||||
$movies = $this->person
|
||||
->movie()
|
||||
->with('genres', 'directors')
|
||||
->wherePivot('occupation_id', '=', $this->occupationId)
|
||||
->orderBy('release_date')
|
||||
->get()
|
||||
// Since the credits table unique index has nullable columns, we get duplicate credits, which means duplicate movies
|
||||
->unique();
|
||||
$tv = $this->person
|
||||
->tv()
|
||||
->with('genres', 'creators')
|
||||
->wherePivot('occupation_id', '=', $this->occupationId)
|
||||
->orderBy('first_air_date')
|
||||
->get()
|
||||
// Since the credits table unique index has nullable columns, we get duplicate credits, which means duplicate tv
|
||||
->unique();
|
||||
$movies = $this->person
|
||||
->movie()
|
||||
->with('genres', 'directors')
|
||||
->wherePivot('occupation_id', '=', $this->occupationId)
|
||||
->orderBy('release_date')
|
||||
->get()
|
||||
// Since the credits table unique index has nullable columns, we get duplicate credits, which means duplicate movies
|
||||
->unique();
|
||||
$tv = $this->person
|
||||
->tv()
|
||||
->with('genres', 'creators')
|
||||
->wherePivot('occupation_id', '=', $this->occupationId)
|
||||
->orderBy('first_air_date')
|
||||
->get()
|
||||
// Since the credits table unique index has nullable columns, we get duplicate credits, which means duplicate tv
|
||||
->unique();
|
||||
|
||||
$movieIds = $movies->pluck('id');
|
||||
$tvIds = $tv->pluck('id');
|
||||
$movieIds = $movies->pluck('id');
|
||||
$tvIds = $tv->pluck('id');
|
||||
|
||||
$torrents = Torrent::query()
|
||||
->with('type:id,name,position', 'resolution:id,name,position')
|
||||
->select([
|
||||
'id',
|
||||
'name',
|
||||
'info_hash',
|
||||
'size',
|
||||
'leechers',
|
||||
'seeders',
|
||||
'times_completed',
|
||||
'category_id',
|
||||
'user_id',
|
||||
'season_number',
|
||||
'episode_number',
|
||||
'tmdb_movie_id',
|
||||
'tmdb_tv_id',
|
||||
'free',
|
||||
'doubleup',
|
||||
'highspeed',
|
||||
'sticky',
|
||||
'internal',
|
||||
'created_at',
|
||||
'bumped_at',
|
||||
'type_id',
|
||||
'resolution_id',
|
||||
'personal_release',
|
||||
])
|
||||
->selectRaw(<<<'SQL'
|
||||
$torrents = Torrent::query()
|
||||
->with('type:id,name,position', 'resolution:id,name,position')
|
||||
->select([
|
||||
'id',
|
||||
'name',
|
||||
'info_hash',
|
||||
'size',
|
||||
'leechers',
|
||||
'seeders',
|
||||
'times_completed',
|
||||
'category_id',
|
||||
'user_id',
|
||||
'season_number',
|
||||
'episode_number',
|
||||
'tmdb_movie_id',
|
||||
'tmdb_tv_id',
|
||||
'free',
|
||||
'doubleup',
|
||||
'highspeed',
|
||||
'sticky',
|
||||
'internal',
|
||||
'created_at',
|
||||
'bumped_at',
|
||||
'type_id',
|
||||
'resolution_id',
|
||||
'personal_release',
|
||||
])
|
||||
->selectRaw(<<<'SQL'
|
||||
CASE
|
||||
WHEN category_id IN (SELECT `id` from `categories` where `movie_meta` = 1) THEN 'movie'
|
||||
WHEN category_id IN (SELECT `id` from `categories` where `tv_meta` = 1) THEN 'tv'
|
||||
END as meta
|
||||
SQL)
|
||||
->withCount([
|
||||
'comments',
|
||||
])
|
||||
->when(
|
||||
!config('announce.external_tracker.is_enabled'),
|
||||
fn ($query) => $query->withCount([
|
||||
'seeds' => fn ($query) => $query->where('active', '=', true)->where('visible', '=', true),
|
||||
'leeches' => fn ($query) => $query->where('active', '=', true)->where('visible', '=', true),
|
||||
]),
|
||||
)
|
||||
->when(
|
||||
config('other.thanks-system.is-enabled'),
|
||||
fn ($query) => $query->withCount('thanks')
|
||||
)
|
||||
->withExists([
|
||||
'featured as featured',
|
||||
'freeleechTokens' => fn ($query) => $query->where('user_id', '=', auth()->id()),
|
||||
'bookmarks' => fn ($query) => $query->where('user_id', '=', auth()->id()),
|
||||
'history as seeding' => fn ($query) => $query->where('user_id', '=', auth()->id())
|
||||
->where('active', '=', 1)
|
||||
->where('seeder', '=', 1),
|
||||
'history as leeching' => fn ($query) => $query->where('user_id', '=', auth()->id())
|
||||
->where('active', '=', 1)
|
||||
->where('seeder', '=', 0),
|
||||
'history as not_completed' => fn ($query) => $query->where('user_id', '=', auth()->id())
|
||||
->where('active', '=', 0)
|
||||
->where('seeder', '=', 0)
|
||||
->whereNull('completed_at'),
|
||||
'history as not_seeding' => fn ($query) => $query->where('user_id', '=', auth()->id())
|
||||
->where('active', '=', 0)
|
||||
->where(
|
||||
fn ($query) => $query
|
||||
->where('seeder', '=', 1)
|
||||
->orWhereNotNull('completed_at')
|
||||
),
|
||||
'trump',
|
||||
])
|
||||
->where(
|
||||
fn ($query) => $query
|
||||
->where(
|
||||
fn ($query) => $query
|
||||
->whereRelation('category', 'movie_meta', '=', true)
|
||||
->whereIntegerInRaw('tmdb_movie_id', $movieIds)
|
||||
)
|
||||
->orWhere(
|
||||
fn ($query) => $query
|
||||
->whereRelation('category', 'tv_meta', '=', true)
|
||||
->whereIntegerInRaw('tmdb_tv_id', $tvIds)
|
||||
)
|
||||
)
|
||||
->get();
|
||||
->withCount([
|
||||
'comments',
|
||||
])
|
||||
->when(
|
||||
!config('announce.external_tracker.is_enabled'),
|
||||
fn ($query) => $query->withCount([
|
||||
'seeds' => fn ($query) => $query->where('active', '=', true)->where('visible', '=', true),
|
||||
'leeches' => fn ($query) => $query->where('active', '=', true)->where('visible', '=', true),
|
||||
]),
|
||||
)
|
||||
->when(
|
||||
config('other.thanks-system.is-enabled'),
|
||||
fn ($query) => $query->withCount('thanks')
|
||||
)
|
||||
->withExists([
|
||||
'featured as featured',
|
||||
'freeleechTokens' => fn ($query) => $query->where('user_id', '=', auth()->id()),
|
||||
'bookmarks' => fn ($query) => $query->where('user_id', '=', auth()->id()),
|
||||
'history as seeding' => fn ($query) => $query->where('user_id', '=', auth()->id())
|
||||
->where('active', '=', 1)
|
||||
->where('seeder', '=', 1),
|
||||
'history as leeching' => fn ($query) => $query->where('user_id', '=', auth()->id())
|
||||
->where('active', '=', 1)
|
||||
->where('seeder', '=', 0),
|
||||
'history as not_completed' => fn ($query) => $query->where('user_id', '=', auth()->id())
|
||||
->where('active', '=', 0)
|
||||
->where('seeder', '=', 0)
|
||||
->whereNull('completed_at'),
|
||||
'history as not_seeding' => fn ($query) => $query->where('user_id', '=', auth()->id())
|
||||
->where('active', '=', 0)
|
||||
->where(
|
||||
fn ($query) => $query
|
||||
->where('seeder', '=', 1)
|
||||
->orWhereNotNull('completed_at')
|
||||
),
|
||||
'trump',
|
||||
])
|
||||
->where(
|
||||
fn ($query) => $query
|
||||
->where(
|
||||
fn ($query) => $query
|
||||
->whereRelation('category', 'movie_meta', '=', true)
|
||||
->whereIntegerInRaw('tmdb_movie_id', $movieIds)
|
||||
)
|
||||
->orWhere(
|
||||
fn ($query) => $query
|
||||
->whereRelation('category', 'tv_meta', '=', true)
|
||||
->whereIntegerInRaw('tmdb_tv_id', $tvIds)
|
||||
)
|
||||
)
|
||||
->get();
|
||||
|
||||
$groupedTorrents = [];
|
||||
$groupedTorrents = [];
|
||||
|
||||
foreach ($torrents as &$torrent) {
|
||||
// Memoizing and avoiding casts reduces runtime duration from 70ms to 40ms.
|
||||
// If accessing laravel's attributes array directly, it's reduced to 11ms,
|
||||
// but the attributes array is marked as protected so we can't access it.
|
||||
$tmdb = $torrent->getAttributeValue('tmdb_movie_id') ?: $torrent->getAttributeValue('tmdb_tv_id');
|
||||
$type = $torrent->getRelationValue('type')->getAttributeValue('name');
|
||||
foreach ($torrents as &$torrent) {
|
||||
// Memoizing and avoiding casts reduces runtime duration from 70ms to 40ms.
|
||||
// If accessing laravel's attributes array directly, it's reduced to 11ms,
|
||||
// but the attributes array is marked as protected so we can't access it.
|
||||
$tmdb = $torrent->getAttributeValue('tmdb_movie_id') ?: $torrent->getAttributeValue('tmdb_tv_id');
|
||||
$type = $torrent->getRelationValue('type')->getAttributeValue('name');
|
||||
|
||||
switch ($torrent->getAttributeValue('meta')) {
|
||||
case 'movie':
|
||||
$groupedTorrents['movie'][$tmdb]['Movie'][$type][] = $torrent;
|
||||
$groupedTorrents['movie'][$tmdb]['category_id'] = $torrent->getAttributeValue('category_id');
|
||||
switch ($torrent->getAttributeValue('meta')) {
|
||||
case 'movie':
|
||||
$groupedTorrents['movie'][$tmdb]['Movie'][$type][] = $torrent;
|
||||
$groupedTorrents['movie'][$tmdb]['category_id'] = $torrent->getAttributeValue('category_id');
|
||||
|
||||
break;
|
||||
case 'tv':
|
||||
$episode = $torrent->getAttributeValue('episode_number');
|
||||
$season = $torrent->getAttributeValue('season_number');
|
||||
break;
|
||||
case 'tv':
|
||||
$episode = $torrent->getAttributeValue('episode_number');
|
||||
$season = $torrent->getAttributeValue('season_number');
|
||||
|
||||
if ($season == 0) {
|
||||
if ($episode == 0) {
|
||||
$groupedTorrents['tv'][$tmdb]['Complete Pack'][$type][] = $torrent;
|
||||
if ($season == 0) {
|
||||
if ($episode == 0) {
|
||||
$groupedTorrents['tv'][$tmdb]['Complete Pack'][$type][] = $torrent;
|
||||
} else {
|
||||
$groupedTorrents['tv'][$tmdb]['Specials']["Special {$episode}"][$type][] = $torrent;
|
||||
}
|
||||
} else {
|
||||
$groupedTorrents['tv'][$tmdb]['Specials']["Special {$episode}"][$type][] = $torrent;
|
||||
}
|
||||
} else {
|
||||
if ($episode == 0) {
|
||||
$groupedTorrents['tv'][$tmdb]['Seasons']["Season {$season}"]['Season Pack'][$type][] = $torrent;
|
||||
} else {
|
||||
$groupedTorrents['tv'][$tmdb]['Seasons']["Season {$season}"]['Episodes']["Episode {$episode}"][$type][] = $torrent;
|
||||
}
|
||||
}
|
||||
$groupedTorrents['tv'][$tmdb]['category_id'] = $torrent->getAttributeValue('category_id');
|
||||
}
|
||||
}
|
||||
|
||||
foreach ($groupedTorrents as $mediaType => &$workTorrents) {
|
||||
switch ($mediaType) {
|
||||
case 'movie':
|
||||
foreach ($workTorrents as &$movieTorrents) {
|
||||
$this->sortTorrentTypes($movieTorrents['Movie']);
|
||||
}
|
||||
|
||||
break;
|
||||
case 'tv':
|
||||
foreach ($workTorrents as &$tvTorrents) {
|
||||
foreach ($tvTorrents as $packOrSpecialOrSeasonsType => &$packOrSpecialOrSeasons) {
|
||||
switch ($packOrSpecialOrSeasonsType) {
|
||||
case 'Complete Pack':
|
||||
$this->sortTorrentTypes($packOrSpecialOrSeasons);
|
||||
|
||||
break;
|
||||
case 'Specials':
|
||||
krsort($packOrSpecialOrSeasons, SORT_NATURAL);
|
||||
|
||||
foreach ($packOrSpecialOrSeasons as &$specialTorrents) {
|
||||
$this->sortTorrentTypes($specialTorrents);
|
||||
}
|
||||
|
||||
break;
|
||||
case 'Seasons':
|
||||
krsort($packOrSpecialOrSeasons, SORT_NATURAL);
|
||||
|
||||
foreach ($packOrSpecialOrSeasons as &$season) {
|
||||
foreach ($season as $packOrEpisodesType => &$packOrEpisodes) {
|
||||
switch ($packOrEpisodesType) {
|
||||
case 'Season Pack':
|
||||
$this->sortTorrentTypes($packOrEpisodes);
|
||||
|
||||
break;
|
||||
case 'Episodes':
|
||||
krsort($packOrEpisodes, SORT_NATURAL);
|
||||
|
||||
foreach ($packOrEpisodes as &$episodeTorrents) {
|
||||
$this->sortTorrentTypes($episodeTorrents);
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if ($episode == 0) {
|
||||
$groupedTorrents['tv'][$tmdb]['Seasons']["Season {$season}"]['Season Pack'][$type][] = $torrent;
|
||||
} else {
|
||||
$groupedTorrents['tv'][$tmdb]['Seasons']["Season {$season}"]['Episodes']["Episode {$episode}"][$type][] = $torrent;
|
||||
}
|
||||
}
|
||||
}
|
||||
$groupedTorrents['tv'][$tmdb]['category_id'] = $torrent->getAttributeValue('category_id');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$medias = collect();
|
||||
foreach ($groupedTorrents as $mediaType => &$workTorrents) {
|
||||
switch ($mediaType) {
|
||||
case 'movie':
|
||||
foreach ($workTorrents as &$movieTorrents) {
|
||||
$this->sortTorrentTypes($movieTorrents['Movie']);
|
||||
}
|
||||
|
||||
foreach ($movies as $movie) {
|
||||
if (\array_key_exists('movie', $groupedTorrents) && \array_key_exists($movie->id, $groupedTorrents['movie'])) {
|
||||
$media = $movie;
|
||||
$media->setAttribute('meta', 'movie');
|
||||
$media->setRelation('torrents', $groupedTorrents['movie'][$movie->id]);
|
||||
$media->setAttribute('category_id', $media->torrents['category_id']);
|
||||
$medias->add($media);
|
||||
break;
|
||||
case 'tv':
|
||||
foreach ($workTorrents as &$tvTorrents) {
|
||||
foreach ($tvTorrents as $packOrSpecialOrSeasonsType => &$packOrSpecialOrSeasons) {
|
||||
switch ($packOrSpecialOrSeasonsType) {
|
||||
case 'Complete Pack':
|
||||
$this->sortTorrentTypes($packOrSpecialOrSeasons);
|
||||
|
||||
break;
|
||||
case 'Specials':
|
||||
krsort($packOrSpecialOrSeasons, SORT_NATURAL);
|
||||
|
||||
foreach ($packOrSpecialOrSeasons as &$specialTorrents) {
|
||||
$this->sortTorrentTypes($specialTorrents);
|
||||
}
|
||||
|
||||
break;
|
||||
case 'Seasons':
|
||||
krsort($packOrSpecialOrSeasons, SORT_NATURAL);
|
||||
|
||||
foreach ($packOrSpecialOrSeasons as &$season) {
|
||||
foreach ($season as $packOrEpisodesType => &$packOrEpisodes) {
|
||||
switch ($packOrEpisodesType) {
|
||||
case 'Season Pack':
|
||||
$this->sortTorrentTypes($packOrEpisodes);
|
||||
|
||||
break;
|
||||
case 'Episodes':
|
||||
krsort($packOrEpisodes, SORT_NATURAL);
|
||||
|
||||
foreach ($packOrEpisodes as &$episodeTorrents) {
|
||||
$this->sortTorrentTypes($episodeTorrents);
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
foreach ($tv as $show) {
|
||||
if (\array_key_exists('tv', $groupedTorrents) && \array_key_exists($show->id, $groupedTorrents['tv'])) {
|
||||
$media = $show;
|
||||
$media->setAttribute('meta', 'tv');
|
||||
$media->setRelation('torrents', $groupedTorrents['tv'][$show->id]);
|
||||
$media->setAttribute('category_id', $media->torrents['category_id']);
|
||||
$medias->add($media);
|
||||
$medias = collect();
|
||||
|
||||
foreach ($movies as $movie) {
|
||||
if (\array_key_exists('movie', $groupedTorrents) && \array_key_exists($movie->id, $groupedTorrents['movie'])) {
|
||||
$media = $movie;
|
||||
$media->setAttribute('meta', 'movie');
|
||||
$media->setRelation('torrents', $groupedTorrents['movie'][$movie->id]);
|
||||
$media->setAttribute('category_id', $media->torrents['category_id']);
|
||||
$medias->add($media);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $medias;
|
||||
foreach ($tv as $show) {
|
||||
if (\array_key_exists('tv', $groupedTorrents) && \array_key_exists($show->id, $groupedTorrents['tv'])) {
|
||||
$media = $show;
|
||||
$media->setAttribute('meta', 'tv');
|
||||
$media->setRelation('torrents', $groupedTorrents['tv'][$show->id]);
|
||||
$media->setAttribute('category_id', $media->torrents['category_id']);
|
||||
$medias->add($media);
|
||||
}
|
||||
}
|
||||
|
||||
return $medias;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -17,7 +17,6 @@ declare(strict_types=1);
|
||||
namespace App\Http\Livewire;
|
||||
|
||||
use App\Models\TmdbPerson;
|
||||
use Livewire\Attributes\Computed;
|
||||
use Livewire\Attributes\Url;
|
||||
use Livewire\Component;
|
||||
use Livewire\WithPagination;
|
||||
@@ -46,12 +45,11 @@ class TmdbPersonSearch extends Component
|
||||
}
|
||||
|
||||
/**
|
||||
* @return \Illuminate\Pagination\LengthAwarePaginator<int, TmdbPerson>
|
||||
* @var \Illuminate\Pagination\LengthAwarePaginator<int, TmdbPerson>
|
||||
*/
|
||||
#[Computed]
|
||||
final public function persons(): \Illuminate\Pagination\LengthAwarePaginator
|
||||
{
|
||||
return TmdbPerson::select(['id', 'still', 'name'])
|
||||
final protected \Illuminate\Pagination\LengthAwarePaginator $persons {
|
||||
get => TmdbPerson::query()
|
||||
->select(['id', 'still', 'name'])
|
||||
->when($this->search !== '', fn ($query) => $query->where('name', 'LIKE', '%'.$this->search.'%'))
|
||||
->when($this->occupationIds !== [], fn ($query) => $query->whereHas('credits', fn ($query) => $query->whereIn('occupation_id', $this->occupationIds)))
|
||||
->when($this->firstCharacter !== '', fn ($query) => $query->where('name', 'LIKE', $this->firstCharacter.'%'))
|
||||
@@ -60,12 +58,11 @@ class TmdbPersonSearch extends Component
|
||||
}
|
||||
|
||||
/**
|
||||
* @return \Illuminate\Database\Eloquent\Collection<int, TmdbPerson>
|
||||
* @var \Illuminate\Database\Eloquent\Collection<int, TmdbPerson>
|
||||
*/
|
||||
#[Computed]
|
||||
final public function firstCharacters(): \Illuminate\Database\Eloquent\Collection
|
||||
{
|
||||
return TmdbPerson::selectRaw('substr(name, 1, 1) as alpha, count(*) as count')
|
||||
final protected \Illuminate\Database\Eloquent\Collection $firstCharacters {
|
||||
get => TmdbPerson::query()
|
||||
->selectRaw('substr(name, 1, 1) as alpha, count(*) as count')
|
||||
->when($this->search !== '', fn ($query) => $query->where('name', 'LIKE', '%'.$this->search.'%'))
|
||||
->when($this->occupationIds !== [], fn ($query) => $query->whereHas('credits', fn ($query) => $query->whereIn('occupation_id', $this->occupationIds)))
|
||||
->groupBy('alpha')
|
||||
|
||||
@@ -19,7 +19,6 @@ namespace App\Http\Livewire;
|
||||
use App\Models\Torrent;
|
||||
use App\Models\User;
|
||||
use App\Traits\TorrentMeta;
|
||||
use Livewire\Attributes\Computed;
|
||||
use Livewire\Component;
|
||||
|
||||
class TopTorrents extends Component
|
||||
@@ -36,74 +35,72 @@ class TopTorrents extends Component
|
||||
}
|
||||
|
||||
/**
|
||||
* @return \Illuminate\Support\Collection<int, Torrent>
|
||||
* @var \Illuminate\Support\Collection<int, Torrent>
|
||||
*/
|
||||
#[Computed]
|
||||
final public function torrents(): \Illuminate\Support\Collection
|
||||
{
|
||||
$torrents = Torrent::query()
|
||||
->with(['user.group', 'category', 'type', 'resolution'])
|
||||
->withExists([
|
||||
'featured as featured',
|
||||
'bookmarks' => fn ($query) => $query->where('user_id', '=', $this->user->id),
|
||||
'freeleechTokens' => fn ($query) => $query->where('user_id', '=', $this->user->id),
|
||||
'history as seeding' => fn ($query) => $query->where('user_id', '=', $this->user->id)
|
||||
->where('active', '=', 1)
|
||||
->where('seeder', '=', 1),
|
||||
'history as leeching' => fn ($query) => $query->where('user_id', '=', $this->user->id)
|
||||
->where('active', '=', 1)
|
||||
->where('seeder', '=', 0),
|
||||
'history as not_completed' => fn ($query) => $query->where('user_id', '=', $this->user->id)
|
||||
->where('active', '=', 0)
|
||||
->where('seeder', '=', 0)
|
||||
->whereNull('completed_at'),
|
||||
'history as not_seeding' => fn ($query) => $query->where('user_id', '=', $this->user->id)
|
||||
->where('active', '=', 0)
|
||||
->where(
|
||||
fn ($query) => $query
|
||||
->where('seeder', '=', 1)
|
||||
->orWhereNotNull('completed_at')
|
||||
),
|
||||
])
|
||||
->selectRaw(<<<SQL
|
||||
CASE
|
||||
WHEN category_id IN (SELECT id FROM categories WHERE movie_meta = 1) THEN 'movie'
|
||||
WHEN category_id IN (SELECT id FROM categories WHERE tv_meta = 1) THEN 'tv'
|
||||
WHEN category_id IN (SELECT id FROM categories WHERE game_meta = 1) THEN 'game'
|
||||
WHEN category_id IN (SELECT id FROM categories WHERE music_meta = 1) THEN 'music'
|
||||
WHEN category_id IN (SELECT id FROM categories WHERE no_meta = 1) THEN 'no'
|
||||
END AS meta
|
||||
SQL)
|
||||
->withCount(['thanks', 'comments'])
|
||||
->when($this->tab === 'newest', fn ($query) => $query->orderByDesc('id'))
|
||||
->when($this->tab === 'seeded', fn ($query) => $query->orderByDesc('seeders'))
|
||||
->when(
|
||||
$this->tab === 'dying',
|
||||
fn ($query) => $query
|
||||
->where('seeders', '=', 1)
|
||||
->where('times_completed', '>=', 1)
|
||||
->orderByDesc('leechers')
|
||||
)
|
||||
->when($this->tab === 'leeched', fn ($query) => $query->orderByDesc('leechers'))
|
||||
->when(
|
||||
$this->tab === 'dead',
|
||||
fn ($query) => $query
|
||||
->where('seeders', '=', 0)
|
||||
->orderByDesc('leechers')
|
||||
)
|
||||
->take(5)
|
||||
->get();
|
||||
final protected \Illuminate\Support\Collection $torrents {
|
||||
get {
|
||||
$torrents = Torrent::query()
|
||||
->with(['user.group', 'category', 'type', 'resolution'])
|
||||
->withExists([
|
||||
'featured as featured',
|
||||
'bookmarks' => fn ($query) => $query->where('user_id', '=', $this->user->id),
|
||||
'freeleechTokens' => fn ($query) => $query->where('user_id', '=', $this->user->id),
|
||||
'history as seeding' => fn ($query) => $query->where('user_id', '=', $this->user->id)
|
||||
->where('active', '=', 1)
|
||||
->where('seeder', '=', 1),
|
||||
'history as leeching' => fn ($query) => $query->where('user_id', '=', $this->user->id)
|
||||
->where('active', '=', 1)
|
||||
->where('seeder', '=', 0),
|
||||
'history as not_completed' => fn ($query) => $query->where('user_id', '=', $this->user->id)
|
||||
->where('active', '=', 0)
|
||||
->where('seeder', '=', 0)
|
||||
->whereNull('completed_at'),
|
||||
'history as not_seeding' => fn ($query) => $query->where('user_id', '=', $this->user->id)
|
||||
->where('active', '=', 0)
|
||||
->where(
|
||||
fn ($query) => $query
|
||||
->where('seeder', '=', 1)
|
||||
->orWhereNotNull('completed_at')
|
||||
),
|
||||
])
|
||||
->selectRaw(<<<SQL
|
||||
CASE
|
||||
WHEN category_id IN (SELECT id FROM categories WHERE movie_meta = 1) THEN 'movie'
|
||||
WHEN category_id IN (SELECT id FROM categories WHERE tv_meta = 1) THEN 'tv'
|
||||
WHEN category_id IN (SELECT id FROM categories WHERE game_meta = 1) THEN 'game'
|
||||
WHEN category_id IN (SELECT id FROM categories WHERE music_meta = 1) THEN 'music'
|
||||
WHEN category_id IN (SELECT id FROM categories WHERE no_meta = 1) THEN 'no'
|
||||
END AS meta
|
||||
SQL)
|
||||
->withCount(['thanks', 'comments'])
|
||||
->when($this->tab === 'newest', fn ($query) => $query->orderByDesc('id'))
|
||||
->when($this->tab === 'seeded', fn ($query) => $query->orderByDesc('seeders'))
|
||||
->when(
|
||||
$this->tab === 'dying',
|
||||
fn ($query) => $query
|
||||
->where('seeders', '=', 1)
|
||||
->where('times_completed', '>=', 1)
|
||||
->orderByDesc('leechers')
|
||||
)
|
||||
->when($this->tab === 'leeched', fn ($query) => $query->orderByDesc('leechers'))
|
||||
->when(
|
||||
$this->tab === 'dead',
|
||||
fn ($query) => $query
|
||||
->where('seeders', '=', 0)
|
||||
->orderByDesc('leechers')
|
||||
)
|
||||
->take(5)
|
||||
->get();
|
||||
|
||||
// See app/Traits/TorrentMeta.php
|
||||
$this->scopeMeta($torrents);
|
||||
// See app/Traits/TorrentMeta.php
|
||||
$this->scopeMeta($torrents);
|
||||
|
||||
return $torrents;
|
||||
return $torrents;
|
||||
}
|
||||
}
|
||||
|
||||
#[Computed]
|
||||
final public function personalFreeleech(): bool
|
||||
{
|
||||
return cache()->get('personal_freeleech:'.$this->user->id) ?? false;
|
||||
final protected bool $personalFreeleech {
|
||||
get => cache()->get('personal_freeleech:'.$this->user->id) ?? false;
|
||||
}
|
||||
|
||||
final public function render(): \Illuminate\Contracts\View\Factory | \Illuminate\Contracts\View\View | \Illuminate\Contracts\Foundation\Application
|
||||
|
||||
@@ -12,7 +12,6 @@ use App\Models\Thank;
|
||||
use App\Models\Torrent;
|
||||
use App\Models\User;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
use Livewire\Attributes\Computed;
|
||||
use Livewire\Component;
|
||||
|
||||
class TopUsers extends Component
|
||||
@@ -20,175 +19,208 @@ class TopUsers extends Component
|
||||
public string $tab = 'uploaders';
|
||||
|
||||
/**
|
||||
* @return \Illuminate\Support\Collection<int, Torrent>
|
||||
* @var \Illuminate\Support\Collection<int, Torrent>
|
||||
*/
|
||||
#[Computed(cache: true)]
|
||||
final public function uploaders(): \Illuminate\Support\Collection
|
||||
{
|
||||
return Torrent::with(['user.group'])
|
||||
->select(DB::raw('user_id, COUNT(user_id) as value'))
|
||||
->where('user_id', '!=', User::SYSTEM_USER_ID)
|
||||
->where('anon', '=', false)
|
||||
->groupBy('user_id')
|
||||
->orderByDesc('value')
|
||||
->take(8)
|
||||
->get();
|
||||
final protected \Illuminate\Support\Collection $uploaders {
|
||||
get => cache()->remember(
|
||||
'top-users:uploaders',
|
||||
3600,
|
||||
fn () => Torrent::query()
|
||||
->with(['user.group'])
|
||||
->select(DB::raw('user_id, COUNT(user_id) as value'))
|
||||
->where('user_id', '!=', User::SYSTEM_USER_ID)
|
||||
->where('anon', '=', false)
|
||||
->groupBy('user_id')
|
||||
->orderByDesc('value')
|
||||
->take(8)
|
||||
->get(),
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return \Illuminate\Support\Collection<int, History>
|
||||
* @var \Illuminate\Support\Collection<int, History>
|
||||
*/
|
||||
#[Computed(cache: true)]
|
||||
final public function downloaders(): \Illuminate\Support\Collection
|
||||
{
|
||||
return History::with(['user.group'])
|
||||
->select(DB::raw('user_id, count(distinct torrent_id) as value'))
|
||||
->whereNotNull('completed_at')
|
||||
->where('user_id', '!=', User::SYSTEM_USER_ID)
|
||||
->groupBy('user_id')
|
||||
->orderByDesc('value')
|
||||
->take(8)
|
||||
->get();
|
||||
final protected \Illuminate\Support\Collection $downloaders {
|
||||
get => cache()->remember(
|
||||
'top-users:downloaders',
|
||||
3600,
|
||||
fn () => History::query()
|
||||
->with(['user.group'])
|
||||
->select(DB::raw('user_id, count(distinct torrent_id) as value'))
|
||||
->whereNotNull('completed_at')
|
||||
->where('user_id', '!=', User::SYSTEM_USER_ID)
|
||||
->groupBy('user_id')
|
||||
->orderByDesc('value')
|
||||
->take(8)
|
||||
->get(),
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return \Illuminate\Support\Collection<int, User>
|
||||
* @var \Illuminate\Support\Collection<int, User>
|
||||
*/
|
||||
#[Computed(cache: true)]
|
||||
final public function uploaded(): \Illuminate\Support\Collection
|
||||
{
|
||||
return User::select(['id', 'group_id', 'username', 'uploaded', 'image'])
|
||||
->with('group')
|
||||
->where('id', '!=', User::SYSTEM_USER_ID)
|
||||
->whereDoesntHave('group', fn ($query) => $query->whereIn('slug', ['banned', 'validating', 'disabled', 'pruned']))
|
||||
->orderByDesc('uploaded')
|
||||
->take(8)
|
||||
->get();
|
||||
final protected \Illuminate\Support\Collection $uploaded {
|
||||
get => cache()->remember(
|
||||
'top-users:uploaded',
|
||||
3600,
|
||||
fn () => User::query()
|
||||
->select(['id', 'group_id', 'username', 'uploaded', 'image'])
|
||||
->with('group')
|
||||
->where('id', '!=', User::SYSTEM_USER_ID)
|
||||
->whereDoesntHave('group', fn ($query) => $query->whereIn('slug', ['banned', 'validating', 'disabled', 'pruned']))
|
||||
->orderByDesc('uploaded')
|
||||
->take(8)
|
||||
->get(),
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return \Illuminate\Support\Collection<int, User>
|
||||
* @var \Illuminate\Support\Collection<int, User>
|
||||
*/
|
||||
#[Computed(cache: true)]
|
||||
final public function downloaded(): \Illuminate\Support\Collection
|
||||
{
|
||||
return User::select(['id', 'group_id', 'username', 'downloaded', 'image'])
|
||||
->with('group')
|
||||
->where('id', '!=', User::SYSTEM_USER_ID)
|
||||
->whereDoesntHave('group', fn ($query) => $query->whereIn('slug', ['banned', 'validating', 'disabled', 'pruned']))
|
||||
->orderByDesc('downloaded')
|
||||
->take(8)
|
||||
->get();
|
||||
final protected \Illuminate\Support\Collection $downloaded {
|
||||
get => cache()->remember(
|
||||
'top-users:downloaded',
|
||||
3600,
|
||||
fn () => User::query()
|
||||
->select(['id', 'group_id', 'username', 'downloaded', 'image'])
|
||||
->with('group')
|
||||
->where('id', '!=', User::SYSTEM_USER_ID)
|
||||
->whereDoesntHave('group', fn ($query) => $query->whereIn('slug', ['banned', 'validating', 'disabled', 'pruned']))
|
||||
->orderByDesc('downloaded')
|
||||
->take(8)
|
||||
->get(),
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return \Illuminate\Support\Collection<int, Peer>
|
||||
* @var \Illuminate\Support\Collection<int, Peer>
|
||||
*/
|
||||
#[Computed(cache: true)]
|
||||
final public function seeders(): \Illuminate\Support\Collection
|
||||
{
|
||||
return Peer::with(['user.group'])
|
||||
->select(DB::raw('user_id, count(distinct torrent_id) as value'))
|
||||
->where('user_id', '!=', User::SYSTEM_USER_ID)
|
||||
->where('seeder', '=', 1)
|
||||
->where('active', '=', 1)
|
||||
->groupBy('user_id')
|
||||
->orderByDesc('value')
|
||||
->take(8)
|
||||
->get();
|
||||
final protected \Illuminate\Support\Collection $seeders {
|
||||
get => cache()->remember(
|
||||
'top-users:seeders',
|
||||
3600,
|
||||
fn () => Peer::query()
|
||||
->with(['user.group'])
|
||||
->select(DB::raw('user_id, count(distinct torrent_id) as value'))
|
||||
->where('user_id', '!=', User::SYSTEM_USER_ID)
|
||||
->where('seeder', '=', 1)
|
||||
->where('active', '=', 1)
|
||||
->groupBy('user_id')
|
||||
->orderByDesc('value')
|
||||
->take(8)
|
||||
->get(),
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return \Illuminate\Support\Collection<int, User>
|
||||
* @var \Illuminate\Support\Collection<int, User>
|
||||
*/
|
||||
#[Computed(cache: true)]
|
||||
final public function seedtimes(): \Illuminate\Support\Collection
|
||||
{
|
||||
return User::withSum('history as seedtime', 'seedtime')
|
||||
->with('group')
|
||||
->where('id', '!=', User::SYSTEM_USER_ID)
|
||||
->whereDoesntHave('group', fn ($query) => $query->whereIn('slug', ['banned', 'validating', 'disabled', 'pruned']))
|
||||
->orderByDesc('seedtime')
|
||||
->take(8)
|
||||
->get();
|
||||
final protected \Illuminate\Support\Collection $seedtimes {
|
||||
get => cache()->remember(
|
||||
'top-users:seedtimes',
|
||||
3600,
|
||||
fn () => User::query()
|
||||
->withSum('history as seedtime', 'seedtime')
|
||||
->with('group')
|
||||
->where('id', '!=', User::SYSTEM_USER_ID)
|
||||
->whereDoesntHave('group', fn ($query) => $query->whereIn('slug', ['banned', 'validating', 'disabled', 'pruned']))
|
||||
->orderByDesc('seedtime')
|
||||
->take(8)
|
||||
->get(),
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return \Illuminate\Support\Collection<int, User>
|
||||
* @var \Illuminate\Support\Collection<int, User>
|
||||
*/
|
||||
#[Computed(cache: true)]
|
||||
final public function served(): \Illuminate\Support\Collection
|
||||
{
|
||||
return User::withCount('uploadSnatches')
|
||||
->with('group')
|
||||
->where('id', '!=', User::SYSTEM_USER_ID)
|
||||
->whereDoesntHave('group', fn ($query) => $query->whereIn('slug', ['banned', 'validating', 'disabled', 'pruned']))
|
||||
->orderByDesc('upload_snatches_count')
|
||||
->take(8)
|
||||
->get();
|
||||
final protected \Illuminate\Support\Collection $served {
|
||||
get => cache()->remember(
|
||||
'top-users:served',
|
||||
3600,
|
||||
fn () => User::query()
|
||||
->withCount('uploadSnatches')
|
||||
->with('group')
|
||||
->where('id', '!=', User::SYSTEM_USER_ID)
|
||||
->whereDoesntHave('group', fn ($query) => $query->whereIn('slug', ['banned', 'validating', 'disabled', 'pruned']))
|
||||
->orderByDesc('upload_snatches_count')
|
||||
->take(8)
|
||||
->get(),
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return \Illuminate\Support\Collection<int, Comment>
|
||||
* @var \Illuminate\Support\Collection<int, Comment>
|
||||
*/
|
||||
#[Computed(cache: true)]
|
||||
final public function commenters(): \Illuminate\Support\Collection
|
||||
{
|
||||
return Comment::with(['user.group'])
|
||||
->select(DB::raw('user_id, COUNT(user_id) as value'))
|
||||
->where('user_id', '!=', User::SYSTEM_USER_ID)
|
||||
->where('anon', '=', false)
|
||||
->groupBy('user_id')
|
||||
->orderByDesc('value')
|
||||
->take(8)
|
||||
->get();
|
||||
final protected \Illuminate\Support\Collection $commenters {
|
||||
get => cache()->remember(
|
||||
'top-users:commenters',
|
||||
3600,
|
||||
fn () => Comment::query()
|
||||
->with(['user.group'])
|
||||
->select(DB::raw('user_id, COUNT(user_id) as value'))
|
||||
->where('user_id', '!=', User::SYSTEM_USER_ID)
|
||||
->where('anon', '=', false)
|
||||
->groupBy('user_id')
|
||||
->orderByDesc('value')
|
||||
->take(8)
|
||||
->get(),
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return \Illuminate\Support\Collection<int, Post>
|
||||
* @var \Illuminate\Support\Collection<int, Post>
|
||||
*/
|
||||
#[Computed(cache: true)]
|
||||
final public function posters(): \Illuminate\Support\Collection
|
||||
{
|
||||
return Post::with(['user.group'])
|
||||
->select(DB::raw('user_id, COUNT(user_id) as value'))
|
||||
->where('user_id', '!=', User::SYSTEM_USER_ID)
|
||||
->groupBy('user_id')
|
||||
->orderByDesc('value')
|
||||
->take(8)
|
||||
->get();
|
||||
final protected \Illuminate\Support\Collection $posters {
|
||||
get => cache()->remember(
|
||||
'top-users:posters',
|
||||
3600,
|
||||
fn () => Post::query()
|
||||
->with(['user.group'])
|
||||
->select(DB::raw('user_id, COUNT(user_id) as value'))
|
||||
->where('user_id', '!=', User::SYSTEM_USER_ID)
|
||||
->groupBy('user_id')
|
||||
->orderByDesc('value')
|
||||
->take(8)
|
||||
->get(),
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return \Illuminate\Support\Collection<int, Thank>
|
||||
* @var \Illuminate\Support\Collection<int, Thank>
|
||||
*/
|
||||
#[Computed(cache: true)]
|
||||
final public function thankers(): \Illuminate\Support\Collection
|
||||
{
|
||||
return Thank::with(['user.group'])
|
||||
->select(DB::raw('user_id, COUNT(user_id) as value'))
|
||||
->where('user_id', '!=', User::SYSTEM_USER_ID)
|
||||
->groupBy('user_id')
|
||||
->orderByDesc('value')
|
||||
->take(8)
|
||||
->get();
|
||||
final protected \Illuminate\Support\Collection $thankers {
|
||||
get => cache()->remember(
|
||||
'top-users:thankers',
|
||||
3600,
|
||||
fn () => Thank::query()
|
||||
->with(['user.group'])
|
||||
->select(DB::raw('user_id, COUNT(user_id) as value'))
|
||||
->where('user_id', '!=', User::SYSTEM_USER_ID)
|
||||
->groupBy('user_id')
|
||||
->orderByDesc('value')
|
||||
->take(8)
|
||||
->get(),
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return \Illuminate\Support\Collection<int, Torrent>
|
||||
* @var \Illuminate\Support\Collection<int, Torrent>
|
||||
*/
|
||||
#[Computed(cache: true)]
|
||||
final public function personals(): \Illuminate\Support\Collection
|
||||
{
|
||||
return Torrent::with(['user.group'])
|
||||
->select(DB::raw('user_id, COUNT(user_id) as value'))
|
||||
->where('user_id', '!=', User::SYSTEM_USER_ID)
|
||||
->where('anon', '=', false)
|
||||
->where('personal_release', '=', true)
|
||||
->groupBy('user_id')
|
||||
->orderByDesc('value')
|
||||
->take(8)
|
||||
->get();
|
||||
final protected \Illuminate\Support\Collection $personals {
|
||||
get => cache()->remember(
|
||||
'top-users:personals',
|
||||
3600,
|
||||
fn () => Torrent::query()
|
||||
->with(['user.group'])
|
||||
->select(DB::raw('user_id, COUNT(user_id) as value'))
|
||||
->where('user_id', '!=', User::SYSTEM_USER_ID)
|
||||
->where('anon', '=', false)
|
||||
->where('personal_release', '=', true)
|
||||
->groupBy('user_id')
|
||||
->orderByDesc('value')
|
||||
->take(8)
|
||||
->get(),
|
||||
);
|
||||
}
|
||||
|
||||
public function render(): \Illuminate\Contracts\View\Factory|\Illuminate\Contracts\View\View|\Illuminate\Contracts\Foundation\Application
|
||||
|
||||
@@ -20,7 +20,6 @@ use App\Models\Post;
|
||||
use App\Models\Topic;
|
||||
use App\Models\TopicRead;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
use Livewire\Attributes\Computed;
|
||||
use Livewire\Attributes\Url;
|
||||
use Livewire\Component;
|
||||
use Livewire\WithPagination;
|
||||
@@ -47,35 +46,35 @@ class TopicPostSearch extends Component
|
||||
}
|
||||
|
||||
/**
|
||||
* @return \Illuminate\Pagination\LengthAwarePaginator<int, Post>
|
||||
* @var \Illuminate\Pagination\LengthAwarePaginator<int, Post>
|
||||
*/
|
||||
#[Computed]
|
||||
final public function posts(): \Illuminate\Pagination\LengthAwarePaginator
|
||||
{
|
||||
$posts = Post::query()
|
||||
->with('user', 'user.group')
|
||||
->withCount('likes', 'dislikes', 'authorPosts', 'authorTopics')
|
||||
->withSum('tips', 'bon')
|
||||
->where('topic_id', '=', $this->topic->id)
|
||||
->authorized(canReadTopic: true)
|
||||
->when($this->search !== '', fn ($query) => $query->where('content', 'LIKE', '%'.$this->search.'%'))
|
||||
->orderBy('created_at')
|
||||
->paginate(25);
|
||||
final protected \Illuminate\Pagination\LengthAwarePaginator $posts {
|
||||
get {
|
||||
$posts = Post::query()
|
||||
->with('user', 'user.group')
|
||||
->withCount('likes', 'dislikes', 'authorPosts', 'authorTopics')
|
||||
->withSum('tips', 'bon')
|
||||
->where('topic_id', '=', $this->topic->id)
|
||||
->authorized(canReadTopic: true)
|
||||
->when($this->search !== '', fn ($query) => $query->where('content', 'LIKE', '%'.$this->search.'%'))
|
||||
->orderBy('created_at')
|
||||
->paginate(25);
|
||||
|
||||
if ($lastPost = $posts->getCollection()->last()) {
|
||||
TopicRead::upsert([[
|
||||
'topic_id' => $this->topic->id,
|
||||
'user_id' => auth()->id(),
|
||||
'last_read_post_id' => $lastPost->id,
|
||||
]], [
|
||||
'topic_id',
|
||||
'user_id'
|
||||
], [
|
||||
'last_read_post_id' => DB::raw('GREATEST(last_read_post_id, VALUES(last_read_post_id))')
|
||||
]);
|
||||
if ($lastPost = $posts->getCollection()->last()) {
|
||||
TopicRead::upsert([[
|
||||
'topic_id' => $this->topic->id,
|
||||
'user_id' => auth()->id(),
|
||||
'last_read_post_id' => $lastPost->id,
|
||||
]], [
|
||||
'topic_id',
|
||||
'user_id'
|
||||
], [
|
||||
'last_read_post_id' => DB::raw('GREATEST(last_read_post_id, VALUES(last_read_post_id))')
|
||||
]);
|
||||
}
|
||||
|
||||
return $posts;
|
||||
}
|
||||
|
||||
return $posts;
|
||||
}
|
||||
|
||||
final public function render(): \Illuminate\Contracts\View\Factory|\Illuminate\Contracts\View\View|\Illuminate\Contracts\Foundation\Application
|
||||
|
||||
@@ -18,7 +18,6 @@ namespace App\Http\Livewire;
|
||||
|
||||
use App\Models\ForumCategory;
|
||||
use App\Models\Topic;
|
||||
use Livewire\Attributes\Computed;
|
||||
use Livewire\Attributes\Url;
|
||||
use Livewire\Component;
|
||||
use Livewire\WithPagination;
|
||||
@@ -59,12 +58,10 @@ class TopicSearch extends Component
|
||||
}
|
||||
|
||||
/**
|
||||
* @return \Illuminate\Database\Eloquent\Collection<int, ForumCategory>
|
||||
* @var \Illuminate\Database\Eloquent\Collection<int, ForumCategory>
|
||||
*/
|
||||
#[Computed]
|
||||
final public function forumCategories(): \Illuminate\Database\Eloquent\Collection
|
||||
{
|
||||
return ForumCategory::query()
|
||||
final protected \Illuminate\Database\Eloquent\Collection $forumCategories {
|
||||
get => ForumCategory::query()
|
||||
->with([
|
||||
'forums' => fn ($query) => $query->authorized(canReadTopic: true)
|
||||
])
|
||||
@@ -74,12 +71,10 @@ class TopicSearch extends Component
|
||||
}
|
||||
|
||||
/**
|
||||
* @return \Illuminate\Pagination\LengthAwarePaginator<int, Topic>
|
||||
* @var \Illuminate\Pagination\LengthAwarePaginator<int, Topic>
|
||||
*/
|
||||
#[Computed]
|
||||
final public function topics(): \Illuminate\Pagination\LengthAwarePaginator
|
||||
{
|
||||
return Topic::query()
|
||||
final protected \Illuminate\Pagination\LengthAwarePaginator $topics {
|
||||
get => Topic::query()
|
||||
->select('topics.*')
|
||||
->with([
|
||||
'user.group',
|
||||
|
||||
@@ -16,19 +16,14 @@ declare(strict_types=1);
|
||||
|
||||
namespace App\Http\Livewire;
|
||||
|
||||
use App\Models\Announce;
|
||||
use App\Models\TorrentDownload;
|
||||
use App\Traits\LivewireSort;
|
||||
use Illuminate\Support\Carbon;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
use Livewire\Attributes\Computed;
|
||||
use Livewire\Attributes\Url;
|
||||
use Livewire\Component;
|
||||
use Livewire\WithPagination;
|
||||
|
||||
/**
|
||||
* @property \Illuminate\Pagination\LengthAwarePaginator<int, Announce> $announces
|
||||
*/
|
||||
class TorrentDownloadSearch extends Component
|
||||
{
|
||||
use LivewireSort;
|
||||
@@ -92,12 +87,10 @@ class TorrentDownloadSearch extends Component
|
||||
}
|
||||
|
||||
/**
|
||||
* @return \Illuminate\Pagination\LengthAwarePaginator<int, TorrentDownload>
|
||||
* @var \Illuminate\Pagination\LengthAwarePaginator<int, TorrentDownload>
|
||||
*/
|
||||
#[Computed]
|
||||
final public function torrentDownloads(): \Illuminate\Pagination\LengthAwarePaginator
|
||||
{
|
||||
return TorrentDownload::query()
|
||||
final protected \Illuminate\Pagination\LengthAwarePaginator $torrentDownloads {
|
||||
get => TorrentDownload::query()
|
||||
->with([
|
||||
'user' => fn ($query) => $query->with('group')->withTrashed(),
|
||||
'torrent:id,name'
|
||||
|
||||
@@ -25,7 +25,6 @@ use App\Models\Type;
|
||||
use App\Traits\CastLivewireProperties;
|
||||
use App\Traits\LivewireSort;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
use Livewire\Attributes\Computed;
|
||||
use Livewire\Attributes\Url;
|
||||
use Livewire\Component;
|
||||
use Livewire\WithPagination;
|
||||
@@ -125,68 +124,74 @@ class TorrentRequestSearch extends Component
|
||||
}
|
||||
|
||||
/**
|
||||
* @return \Illuminate\Database\Eloquent\Collection<int, Category>
|
||||
* @var \Illuminate\Database\Eloquent\Collection<int, Category>
|
||||
*/
|
||||
#[Computed(seconds: 3600, cache: true)]
|
||||
final public function categories(): \Illuminate\Database\Eloquent\Collection
|
||||
{
|
||||
return Category::query()->orderBy('position')->get();
|
||||
final protected \Illuminate\Database\Eloquent\Collection $categories {
|
||||
get => cache()->remember(
|
||||
'categories',
|
||||
3600,
|
||||
fn () => Category::query()->orderBy('position')->get(),
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return \Illuminate\Database\Eloquent\Collection<int, Type>
|
||||
* @var \Illuminate\Database\Eloquent\Collection<int, Type>
|
||||
*/
|
||||
#[Computed(seconds: 3600, cache: true)]
|
||||
final public function types(): \Illuminate\Database\Eloquent\Collection
|
||||
{
|
||||
return Type::query()->orderBy('position')->get();
|
||||
final protected \Illuminate\Database\Eloquent\Collection $types {
|
||||
get => cache()->remember(
|
||||
'types',
|
||||
3600,
|
||||
fn () => Type::query()->orderBy('position')->get(),
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return \Illuminate\Database\Eloquent\Collection<int, Resolution>
|
||||
* @var \Illuminate\Database\Eloquent\Collection<int, Resolution>
|
||||
*/
|
||||
#[Computed(seconds: 3600, cache: true)]
|
||||
final public function resolutions(): \Illuminate\Database\Eloquent\Collection
|
||||
{
|
||||
return Resolution::query()->orderBy('position')->get();
|
||||
final protected \Illuminate\Database\Eloquent\Collection $resolutions {
|
||||
get => cache()->remember(
|
||||
'resolutions',
|
||||
3600,
|
||||
fn () => Resolution::query()->orderBy('position')->get(),
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return \Illuminate\Database\Eloquent\Collection<int, TmdbGenre>
|
||||
* @var \Illuminate\Database\Eloquent\Collection<int, TmdbGenre>
|
||||
*/
|
||||
#[Computed(seconds: 3600, cache: true)]
|
||||
final public function genres(): \Illuminate\Database\Eloquent\Collection
|
||||
{
|
||||
return TmdbGenre::query()->orderBy('name')->get();
|
||||
final protected \Illuminate\Database\Eloquent\Collection $genres {
|
||||
get => cache()->remember(
|
||||
'genres',
|
||||
3600,
|
||||
fn () => TmdbGenre::query()->orderBy('name')->get(),
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return \Illuminate\Support\Collection<int, TmdbMovie>
|
||||
* @var \Illuminate\Support\Collection<int, TmdbMovie>
|
||||
*/
|
||||
#[Computed(seconds: 3600, cache: true)]
|
||||
final public function primaryLanguages(): \Illuminate\Support\Collection
|
||||
{
|
||||
return TmdbMovie::query()
|
||||
->select('original_language')
|
||||
->distinct()
|
||||
->orderBy('original_language')
|
||||
->pluck('original_language');
|
||||
final protected \Illuminate\Support\Collection $primaryLanguages {
|
||||
get => cache()->remember(
|
||||
'original-languages',
|
||||
3600,
|
||||
fn () => TmdbMovie::query()
|
||||
->select('original_language')
|
||||
->distinct()
|
||||
->orderBy('original_language')
|
||||
->pluck('original_language'),
|
||||
);
|
||||
}
|
||||
|
||||
#[Computed]
|
||||
final public function torrentRequestStat(): ?object
|
||||
{
|
||||
return DB::table('requests')
|
||||
final protected ?object $torrentRequestStat {
|
||||
get => DB::table('requests')
|
||||
->selectRaw('count(*) as total')
|
||||
->selectRaw('count(case when filled_by is not null then 1 end) as filled')
|
||||
->selectRaw('count(case when filled_by is null then 1 end) as unfilled')
|
||||
->first();
|
||||
}
|
||||
|
||||
#[Computed]
|
||||
final public function torrentRequestBountyStat(): ?object
|
||||
{
|
||||
return DB::table('requests')
|
||||
final protected ?object $torrentRequestBountyStat {
|
||||
get => DB::table('requests')
|
||||
->selectRaw('coalesce(sum(bounty), 0) as total')
|
||||
->selectRaw('coalesce(sum(case when filled_by is not null then bounty end), 0) as claimed')
|
||||
->selectRaw('coalesce(sum(case when filled_by is null then bounty end), 0) as unclaimed')
|
||||
@@ -194,129 +199,129 @@ class TorrentRequestSearch extends Component
|
||||
}
|
||||
|
||||
/**
|
||||
* @return \Illuminate\Pagination\LengthAwarePaginator<int, TorrentRequest>
|
||||
* @var \Illuminate\Pagination\LengthAwarePaginator<int, TorrentRequest>
|
||||
*/
|
||||
#[Computed]
|
||||
final public function torrentRequests(): \Illuminate\Pagination\LengthAwarePaginator
|
||||
{
|
||||
$user = auth()->user();
|
||||
$isRegexAllowed = $user->group->is_modo;
|
||||
$isRegex = fn ($field) => $isRegexAllowed
|
||||
&& \strlen((string) $field) > 2
|
||||
&& $field[0] === '/'
|
||||
&& $field[-1] === '/'
|
||||
&& @preg_match($field, 'Validate regex') !== false;
|
||||
final protected \Illuminate\Pagination\LengthAwarePaginator $torrentRequests {
|
||||
get {
|
||||
$user = auth()->user();
|
||||
$isRegexAllowed = $user->group->is_modo;
|
||||
$isRegex = fn ($field) => $isRegexAllowed
|
||||
&& \strlen((string) $field) > 2
|
||||
&& $field[0] === '/'
|
||||
&& $field[-1] === '/'
|
||||
&& @preg_match($field, 'Validate regex') !== false;
|
||||
|
||||
return TorrentRequest::with(['user:id,username,group_id', 'user.group', 'category', 'type', 'resolution'])
|
||||
->withCount(['comments', 'bounties'])
|
||||
->withExists('claim')
|
||||
->when(
|
||||
$this->name !== '',
|
||||
fn ($query) => $query
|
||||
->when(
|
||||
$isRegex($this->name),
|
||||
fn ($query) => $query->where('name', 'REGEXP', substr($this->name, 1, -1)),
|
||||
fn ($query) => $query->where('name', 'LIKE', '%'.str_replace(' ', '%', $this->name).'%')
|
||||
)
|
||||
)
|
||||
->when(
|
||||
$this->requestor !== '',
|
||||
fn ($query) => $query
|
||||
->whereRelation('user', 'username', '=', $this->requestor)
|
||||
->when(
|
||||
$user === null,
|
||||
fn ($query) => $query->where('anon', '=', false),
|
||||
fn ($query) => $query
|
||||
->when(
|
||||
!$user->group->is_modo,
|
||||
fn ($query) => $query
|
||||
->where(
|
||||
fn ($query) => $query
|
||||
->where('anon', '=', false)
|
||||
->orWhere('user_id', '=', $user->id)
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
->when($this->categoryIds !== [], fn ($query) => $query->whereIntegerInRaw('category_id', $this->categoryIds))
|
||||
->when($this->typeIds !== [], fn ($query) => $query->whereIntegerInRaw('type_id', $this->typeIds))
|
||||
->when($this->resolutionIds !== [], fn ($query) => $query->whereIntegerInRaw('resolution_id', $this->resolutionIds))
|
||||
->when($this->tmdbId !== null, fn ($query) => $query->where(fn ($query) => $query->where('tmdb_movie_id', '=', $this->tmdbId)->orWhere('tmdb_tv_id', '=', $this->tmdbId)))
|
||||
->when($this->imdbId !== '', fn ($query) => $query->where('imdb', '=', (preg_match('/tt0*(\d{7,})/', $this->imdbId, $matches) ? $matches[1] : $this->imdbId)))
|
||||
->when($this->tvdbId !== null, fn ($query) => $query->where('tvdb', '=', $this->tvdbId))
|
||||
->when($this->malId !== null, fn ($query) => $query->where('mal', '=', $this->malId))
|
||||
->when(
|
||||
$this->genreIds !== [],
|
||||
fn ($query) => $query
|
||||
->where(
|
||||
fn ($query) => $query
|
||||
->where(
|
||||
fn ($query) => $query
|
||||
->whereRelation('category', 'movie_meta', '=', true)
|
||||
->whereIn('tmdb_movie_id', DB::table('tmdb_genre_tmdb_movie')->select('tmdb_movie_id')->whereIn('tmdb_genre_id', $this->genreIds))
|
||||
)
|
||||
->orWhere(
|
||||
fn ($query) => $query
|
||||
->whereRelation('category', 'tv_meta', '=', true)
|
||||
->whereIn('tmdb_tv_id', DB::table('tmdb_genre_tmdb_tv')->select('tmdb_tv_id')->whereIn('tmdb_genre_id', $this->genreIds))
|
||||
)
|
||||
)
|
||||
)
|
||||
->when(
|
||||
$this->primaryLanguageNames !== [],
|
||||
fn ($query) => $query
|
||||
->where(
|
||||
fn ($query) => $query
|
||||
->where(
|
||||
fn ($query) => $query
|
||||
->whereRelation('category', 'movie_meta', '=', true)
|
||||
->whereHas('movie', fn ($query) => $query->whereIn('original_language', $this->primaryLanguageNames))
|
||||
)
|
||||
->orWhere(
|
||||
fn ($query) => $query
|
||||
->whereRelation('category', 'tv_meta', '=', true)
|
||||
->whereHas('tv', fn ($query) => $query->whereIn('original_language', $this->primaryLanguageNames))
|
||||
)
|
||||
)
|
||||
)
|
||||
->when($this->unfilled || $this->claimed || $this->pending || $this->filled, function ($query): void {
|
||||
$query->where(function ($query): void {
|
||||
return TorrentRequest::with(['user:id,username,group_id', 'user.group', 'category', 'type', 'resolution'])
|
||||
->withCount(['comments', 'bounties'])
|
||||
->withExists('claim')
|
||||
->when(
|
||||
$this->name !== '',
|
||||
fn ($query) => $query
|
||||
->when(
|
||||
$isRegex($this->name),
|
||||
fn ($query) => $query->where('name', 'REGEXP', substr($this->name, 1, -1)),
|
||||
fn ($query) => $query->where('name', 'LIKE', '%'.str_replace(' ', '%', $this->name).'%')
|
||||
)
|
||||
)
|
||||
->when(
|
||||
$this->requestor !== '',
|
||||
fn ($query) => $query
|
||||
->whereRelation('user', 'username', '=', $this->requestor)
|
||||
->when(
|
||||
$user === null,
|
||||
fn ($query) => $query->where('anon', '=', false),
|
||||
fn ($query) => $query
|
||||
->when(
|
||||
!$user->group->is_modo,
|
||||
fn ($query) => $query
|
||||
->where(
|
||||
fn ($query) => $query
|
||||
->where('anon', '=', false)
|
||||
->orWhere('user_id', '=', $user->id)
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
->when($this->categoryIds !== [], fn ($query) => $query->whereIntegerInRaw('category_id', $this->categoryIds))
|
||||
->when($this->typeIds !== [], fn ($query) => $query->whereIntegerInRaw('type_id', $this->typeIds))
|
||||
->when($this->resolutionIds !== [], fn ($query) => $query->whereIntegerInRaw('resolution_id', $this->resolutionIds))
|
||||
->when($this->tmdbId !== null, fn ($query) => $query->where(fn ($query) => $query->where('tmdb_movie_id', '=', $this->tmdbId)->orWhere('tmdb_tv_id', '=', $this->tmdbId)))
|
||||
->when($this->imdbId !== '', fn ($query) => $query->where('imdb', '=', (preg_match('/tt0*(\d{7,})/', $this->imdbId, $matches) ? $matches[1] : $this->imdbId)))
|
||||
->when($this->tvdbId !== null, fn ($query) => $query->where('tvdb', '=', $this->tvdbId))
|
||||
->when($this->malId !== null, fn ($query) => $query->where('mal', '=', $this->malId))
|
||||
->when(
|
||||
$this->genreIds !== [],
|
||||
fn ($query) => $query
|
||||
->where(
|
||||
fn ($query) => $query
|
||||
->where(
|
||||
fn ($query) => $query
|
||||
->whereRelation('category', 'movie_meta', '=', true)
|
||||
->whereIn('tmdb_movie_id', DB::table('tmdb_genre_tmdb_movie')->select('tmdb_movie_id')->whereIn('tmdb_genre_id', $this->genreIds))
|
||||
)
|
||||
->orWhere(
|
||||
fn ($query) => $query
|
||||
->whereRelation('category', 'tv_meta', '=', true)
|
||||
->whereIn('tmdb_tv_id', DB::table('tmdb_genre_tmdb_tv')->select('tmdb_tv_id')->whereIn('tmdb_genre_id', $this->genreIds))
|
||||
)
|
||||
)
|
||||
)
|
||||
->when(
|
||||
$this->primaryLanguageNames !== [],
|
||||
fn ($query) => $query
|
||||
->where(
|
||||
fn ($query) => $query
|
||||
->where(
|
||||
fn ($query) => $query
|
||||
->whereRelation('category', 'movie_meta', '=', true)
|
||||
->whereHas('movie', fn ($query) => $query->whereIn('original_language', $this->primaryLanguageNames))
|
||||
)
|
||||
->orWhere(
|
||||
fn ($query) => $query
|
||||
->whereRelation('category', 'tv_meta', '=', true)
|
||||
->whereHas('tv', fn ($query) => $query->whereIn('original_language', $this->primaryLanguageNames))
|
||||
)
|
||||
)
|
||||
)
|
||||
->when($this->unfilled || $this->claimed || $this->pending || $this->filled, function ($query): void {
|
||||
$query->where(function ($query): void {
|
||||
if ($this->unfilled) {
|
||||
$query->whereNull('torrent_id')->whereDoesntHave('claim');
|
||||
}
|
||||
})
|
||||
->orWhere(function ($query): void {
|
||||
if ($this->claimed) {
|
||||
$query->whereHas('claim')->whereNull('torrent_id')->whereNull('approved_when');
|
||||
$query->where(function ($query): void {
|
||||
if ($this->unfilled) {
|
||||
$query->whereNull('torrent_id')->whereDoesntHave('claim');
|
||||
}
|
||||
})
|
||||
->orWhere(function ($query): void {
|
||||
if ($this->pending) {
|
||||
$query->whereNotNull('torrent_id')->whereNull('approved_when');
|
||||
}
|
||||
})
|
||||
->orWhere(function ($query): void {
|
||||
if ($this->filled) {
|
||||
$query->whereNotNull('torrent_id')->whereNotNull('approved_when');
|
||||
}
|
||||
});
|
||||
});
|
||||
})
|
||||
->when($this->myRequests, function ($query) use ($user): void {
|
||||
$query->where('user_id', '=', $user->id);
|
||||
})
|
||||
->when($this->myClaims, function ($query) use ($user): void {
|
||||
$query->whereRelation('claim', 'user_id', '=', $user->id)->whereNull('torrent_id')->whereNull('approved_by');
|
||||
})
|
||||
->when($this->myVoted, function ($query) use ($user): void {
|
||||
$query->whereRelation('bounties', 'user_id', '=', $user->id);
|
||||
})
|
||||
->when($this->myFilled, function ($query) use ($user): void {
|
||||
$query->where('filled_by', '=', $user->id);
|
||||
})
|
||||
->orderBy($this->sortField, $this->sortDirection)
|
||||
->paginate($this->perPage);
|
||||
->orWhere(function ($query): void {
|
||||
if ($this->claimed) {
|
||||
$query->whereHas('claim')->whereNull('torrent_id')->whereNull('approved_when');
|
||||
}
|
||||
})
|
||||
->orWhere(function ($query): void {
|
||||
if ($this->pending) {
|
||||
$query->whereNotNull('torrent_id')->whereNull('approved_when');
|
||||
}
|
||||
})
|
||||
->orWhere(function ($query): void {
|
||||
if ($this->filled) {
|
||||
$query->whereNotNull('torrent_id')->whereNotNull('approved_when');
|
||||
}
|
||||
});
|
||||
});
|
||||
})
|
||||
->when($this->myRequests, function ($query) use ($user): void {
|
||||
$query->where('user_id', '=', $user->id);
|
||||
})
|
||||
->when($this->myClaims, function ($query) use ($user): void {
|
||||
$query->whereRelation('claim', 'user_id', '=', $user->id)->whereNull('torrent_id')->whereNull('approved_by');
|
||||
})
|
||||
->when($this->myVoted, function ($query) use ($user): void {
|
||||
$query->whereRelation('bounties', 'user_id', '=', $user->id);
|
||||
})
|
||||
->when($this->myFilled, function ($query) use ($user): void {
|
||||
$query->where('filled_by', '=', $user->id);
|
||||
})
|
||||
->orderBy($this->sortField, $this->sortDirection)
|
||||
->paginate($this->perPage);
|
||||
}
|
||||
}
|
||||
|
||||
final public function render(): \Illuminate\Contracts\View\Factory|\Illuminate\Contracts\View\View|\Illuminate\Contracts\Foundation\Application
|
||||
|
||||
80
app/Http/Livewire/TorrentReseedSearch.php
Normal file
80
app/Http/Livewire/TorrentReseedSearch.php
Normal file
@@ -0,0 +1,80 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
/**
|
||||
* NOTICE OF LICENSE.
|
||||
*
|
||||
* UNIT3D Community Edition is open-sourced software licensed under the GNU Affero General Public License v3.0
|
||||
* The details is bundled with this project in the file LICENSE.txt.
|
||||
*
|
||||
* @project UNIT3D Community Edition
|
||||
*
|
||||
* @author HDVinnie <hdinnovations@protonmail.com>
|
||||
* @license https://www.gnu.org/licenses/agpl-3.0.en.html/ GNU Affero General Public License v3.0
|
||||
*/
|
||||
|
||||
namespace App\Http\Livewire;
|
||||
|
||||
use App\Models\TorrentReseed;
|
||||
use App\Traits\CastLivewireProperties;
|
||||
use App\Traits\LivewireSort;
|
||||
use Livewire\Attributes\Url;
|
||||
use Livewire\Component;
|
||||
use Livewire\WithPagination;
|
||||
|
||||
class TorrentReseedSearch extends Component
|
||||
{
|
||||
use CastLivewireProperties;
|
||||
use LivewireSort;
|
||||
use WithPagination;
|
||||
|
||||
#TODO: Update URL attributes once Livewire 3 fixes upstream bug. See: https://github.com/livewire/livewire/discussions/7746
|
||||
|
||||
#[Url(history: true)]
|
||||
public int $perPage = 25;
|
||||
|
||||
#[Url(history: true)]
|
||||
public string $torrentName = '';
|
||||
|
||||
#[Url(history: true)]
|
||||
public bool $myRequests = false;
|
||||
|
||||
#[Url(history: true)]
|
||||
public string $sortField = 'created_at';
|
||||
|
||||
#[Url(history: true)]
|
||||
public string $sortDirection = 'desc';
|
||||
|
||||
final public function updatingTorrentName(): void
|
||||
{
|
||||
$this->resetPage();
|
||||
}
|
||||
|
||||
final public function updatingMyRequests(): void
|
||||
{
|
||||
$this->resetPage();
|
||||
}
|
||||
|
||||
/**
|
||||
* @var \Illuminate\Pagination\LengthAwarePaginator<int, TorrentReseed>
|
||||
*/
|
||||
final protected \Illuminate\Pagination\LengthAwarePaginator $torrentReseeds {
|
||||
get => TorrentReseed::query()
|
||||
->with([
|
||||
'user:id,username,group_id,deleted_at',
|
||||
'torrent:id,name,seeders,leechers,deleted_at',
|
||||
])
|
||||
->when($this->torrentName !== '', fn ($query) => $query->whereRelation('torrent', 'name', 'LIKE', '%'.$this->torrentName.'%'))
|
||||
->when($this->myRequests, fn ($query) => $query->where('user_id', '=', auth()->id()))
|
||||
->orderBy($this->sortField, $this->sortDirection)
|
||||
->paginate($this->perPage);
|
||||
}
|
||||
|
||||
final public function render(): \Illuminate\Contracts\View\Factory|\Illuminate\Contracts\View\View|\Illuminate\Contracts\Foundation\Application
|
||||
{
|
||||
return view('livewire.torrent-reseed-search', [
|
||||
'torrentReseeds' => $this->torrentReseeds,
|
||||
]);
|
||||
}
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -18,7 +18,6 @@ namespace App\Http\Livewire;
|
||||
|
||||
use App\Models\TorrentTrump;
|
||||
use App\Traits\LivewireSort;
|
||||
use Livewire\Attributes\Computed;
|
||||
use Livewire\Attributes\Url;
|
||||
use Livewire\Component;
|
||||
use Livewire\WithPagination;
|
||||
@@ -46,12 +45,10 @@ class TorrentTrumpSearch extends Component
|
||||
public int $perPage = 25;
|
||||
|
||||
/**
|
||||
* @return \Illuminate\Pagination\LengthAwarePaginator<int, TorrentTrump>
|
||||
* @var \Illuminate\Pagination\LengthAwarePaginator<int, TorrentTrump>
|
||||
*/
|
||||
#[Computed]
|
||||
final public function torrentTrumps(): \Illuminate\Pagination\LengthAwarePaginator
|
||||
{
|
||||
return TorrentTrump::query()
|
||||
final protected \Illuminate\Pagination\LengthAwarePaginator $torrentTrumps {
|
||||
get => TorrentTrump::query()
|
||||
->with([
|
||||
'user:id,username,group_id,deleted_at',
|
||||
'torrent:id,name,deleted_at',
|
||||
|
||||
@@ -25,16 +25,11 @@ use Illuminate\Database\Eloquent\Collection;
|
||||
use Illuminate\Database\Query\JoinClause;
|
||||
use Illuminate\Support\Carbon;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
use Livewire\Attributes\Computed;
|
||||
use Livewire\Attributes\Url;
|
||||
use Livewire\Attributes\Validate;
|
||||
use Livewire\Component;
|
||||
use Throwable;
|
||||
|
||||
/**
|
||||
* @property Collection<int, Torrent> $works
|
||||
* @property array<string, string> $metaTypes
|
||||
*/
|
||||
class Trending extends Component
|
||||
{
|
||||
#TODO: Update URL attributes once Livewire 3 fixes upstream bug. See: https://github.com/livewire/livewire/discussions/7746
|
||||
@@ -74,214 +69,214 @@ class Trending extends Component
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Collection<int, Torrent>
|
||||
* @var Collection<int, Torrent>
|
||||
*/
|
||||
#[Computed]
|
||||
final public function works(): Collection
|
||||
{
|
||||
$this->validate();
|
||||
final protected Collection $works {
|
||||
get {
|
||||
$this->validate();
|
||||
|
||||
$metaIdColumn = match ($this->metaType) {
|
||||
'tv_meta' => 'tmdb_tv_id',
|
||||
default => 'tmdb_movie_id',
|
||||
};
|
||||
$metaIdColumn = match ($this->metaType) {
|
||||
'tv_meta' => 'tmdb_tv_id',
|
||||
default => 'tmdb_movie_id',
|
||||
};
|
||||
|
||||
return cache()->remember(
|
||||
'trending-'.$this->interval.'-'.($this->from ?? '').'-'.($this->until ?? '').'-'.$this->metaType,
|
||||
0, //3600,
|
||||
fn () => Torrent::query()
|
||||
->with('movie', 'tv')
|
||||
->addSelect([
|
||||
$metaIdColumn,
|
||||
DB::raw('MIN(category_id) as category_id'),
|
||||
DB::raw('COUNT(*) as download_count'),
|
||||
])
|
||||
->join('history', 'history.torrent_id', '=', 'torrents.id')
|
||||
->where($metaIdColumn, '!=', 0)
|
||||
->when($this->interval === 'day', fn ($query) => $query->whereBetween('history.completed_at', [now()->subDay(), now()]))
|
||||
->when($this->interval === 'week', fn ($query) => $query->whereBetween('history.completed_at', [now()->subWeek(), now()]))
|
||||
->when($this->interval === 'month', fn ($query) => $query->whereBetween('history.completed_at', [now()->subMonth(), now()]))
|
||||
->when($this->interval === 'year', fn ($query) => $query->whereBetween('history.completed_at', [now()->subYear(), now()]))
|
||||
->when($this->interval === 'all', fn ($query) => $query->whereNotNull('history.completed_at'))
|
||||
->when($this->interval === 'custom', fn ($query) => $query->whereBetween('history.completed_at', [$this->from ?: now(), $this->until ?: now()]))
|
||||
->whereRelation('category', $this->metaType, '=', true)
|
||||
// Small torrents screw the stats since users download them only to farm bon.
|
||||
->where('torrents.size', '>', 1024 * 1024 * 1024)
|
||||
->groupBy($metaIdColumn)
|
||||
->orderByRaw('COUNT(*) DESC')
|
||||
->limit(250)
|
||||
->get($metaIdColumn)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Collection<int|string, Collection<int, Torrent>>
|
||||
* @phpstan-ignore generics.notSubtype (I can't figure out the correct return type to silence this error)
|
||||
*/
|
||||
#[Computed]
|
||||
final public function weekly(): Collection
|
||||
{
|
||||
$this->validate();
|
||||
|
||||
$metaIdColumn = match ($this->metaType) {
|
||||
'tv_meta' => 'tmdb_tv_id',
|
||||
default => 'tmdb_movie_id',
|
||||
};
|
||||
|
||||
return cache()->remember(
|
||||
'weekly-charts:'.$this->metaType,
|
||||
24 * 3600,
|
||||
fn () => Torrent::query()
|
||||
->withoutGlobalScopes()
|
||||
->with('movie', 'tv')
|
||||
->fromSub(
|
||||
History::query()
|
||||
->withoutGlobalScopes()
|
||||
->join('torrents', 'torrents.id', '=', 'history.torrent_id')
|
||||
->join('categories', fn (JoinClause $join) => $join->on('torrents.category_id', '=', 'categories.id')->where($this->metaType, '=', true))
|
||||
->select([
|
||||
DB::raw('FROM_DAYS(TO_DAYS(history.created_at) - MOD(TO_DAYS(history.created_at) - 1, 7)) AS week_start'),
|
||||
$metaIdColumn,
|
||||
DB::raw('MIN(categories.id) as category_id'),
|
||||
DB::raw('COUNT(*) AS download_count'),
|
||||
DB::raw('ROW_NUMBER() OVER (PARTITION BY FROM_DAYS(TO_DAYS(history.created_at) - MOD(TO_DAYS(history.created_at) - 1, 7)) ORDER BY COUNT(*) DESC) AS place'),
|
||||
])
|
||||
->where($metaIdColumn, '!=', 0)
|
||||
// Small torrents screw the stats since users download them only to farm bon.
|
||||
->where('torrents.size', '>', 1024 * 1024 * 1024)
|
||||
->groupBy('week_start', $metaIdColumn),
|
||||
'ranked_groups',
|
||||
)
|
||||
->where('place', '<=', 10)
|
||||
->orderByDesc('week_start')
|
||||
->orderBy('place')
|
||||
->withCasts([
|
||||
'week_start' => 'datetime',
|
||||
])
|
||||
->get()
|
||||
->groupBy('week_start')
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Collection<int|string, Collection<int, Torrent>>
|
||||
* @phpstan-ignore generics.notSubtype (I can't figure out the correct return type to silence this error)
|
||||
*/
|
||||
#[Computed]
|
||||
final public function monthly(): Collection
|
||||
{
|
||||
$this->validate();
|
||||
|
||||
$metaIdColumn = match ($this->metaType) {
|
||||
'tv_meta' => 'tmdb_tv_id',
|
||||
default => 'tmdb_movie_id',
|
||||
};
|
||||
|
||||
return cache()->remember(
|
||||
'monthly-charts:'.$this->metaType,
|
||||
24 * 3600,
|
||||
fn () => Torrent::query()
|
||||
->withoutGlobalScopes()
|
||||
->with($this->metaType === 'movie_meta' ? 'movie' : 'tv')
|
||||
->fromSub(
|
||||
History::query()
|
||||
->withoutGlobalScopes()
|
||||
->join('torrents', 'torrents.id', '=', 'history.torrent_id')
|
||||
->join('categories', fn (JoinClause $join) => $join->on('torrents.category_id', '=', 'categories.id')->where($this->metaType, '=', true))
|
||||
->select([
|
||||
DB::raw('EXTRACT(YEAR_MONTH FROM history.created_at) AS the_year_month'),
|
||||
$metaIdColumn,
|
||||
DB::raw('MIN(categories.id) as category_id'),
|
||||
DB::raw('COUNT(*) AS download_count'),
|
||||
DB::raw('ROW_NUMBER() OVER (PARTITION BY EXTRACT(YEAR_MONTH FROM history.created_at) ORDER BY COUNT(*) DESC) AS place'),
|
||||
])
|
||||
->where($metaIdColumn, '!=', 0)
|
||||
// Small torrents screw the stats since users download them only to farm bon.
|
||||
->where('torrents.size', '>', 1024 * 1024 * 1024)
|
||||
->groupBy('the_year_month', $metaIdColumn),
|
||||
'ranked_groups',
|
||||
)
|
||||
->where('place', '<=', 10)
|
||||
->orderByDesc('the_year_month')
|
||||
->orderBy('place')
|
||||
->get()
|
||||
->groupBy('the_year_month')
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Collection<int|string, Collection<int, Torrent>>
|
||||
* @phpstan-ignore generics.notSubtype (I can't figure out the correct return type to silence this error)
|
||||
*/
|
||||
#[Computed]
|
||||
final public function releaseYear(): Collection
|
||||
{
|
||||
$this->validate();
|
||||
|
||||
$metaIdColumn = match ($this->metaType) {
|
||||
'tv_meta' => 'tmdb_tv_id',
|
||||
default => 'tmdb_movie_id',
|
||||
};
|
||||
|
||||
return cache()->remember(
|
||||
'trending-by-release-year:'.$this->metaType,
|
||||
24 * 3600,
|
||||
fn () => Torrent::query()
|
||||
->withoutGlobalScopes()
|
||||
->with($this->metaType === 'movie_meta' ? 'movie' : 'tv')
|
||||
->fromSub(
|
||||
Torrent::query()
|
||||
->withoutGlobalScopes()
|
||||
->whereRelation('category', $this->metaType, '=', true)
|
||||
->leftJoin('tmdb_movies', 'torrents.tmdb_movie_id', '=', 'tmdb_movies.id')
|
||||
->leftJoin('tmdb_tv', 'torrents.tmdb_tv_id', '=', 'tmdb_tv.id')
|
||||
->select([
|
||||
$metaIdColumn,
|
||||
DB::raw('MIN(category_id) as category_id'),
|
||||
DB::raw('SUM(times_completed) AS download_count'),
|
||||
'the_year' => $this->metaType === 'movie_meta'
|
||||
? TmdbMovie::query()
|
||||
->selectRaw('EXTRACT(YEAR FROM tmdb_movies.release_date)')
|
||||
->whereColumn('tmdb_movies.id', '=', 'torrents.tmdb_movie_id')
|
||||
: TmdbTv::query()
|
||||
->selectRaw('EXTRACT(YEAR FROM tmdb_tv.first_air_date)')
|
||||
->whereColumn('tmdb_tv.id', '=', 'torrents.tmdb_tv_id'),
|
||||
DB::raw('ROW_NUMBER() OVER (PARTITION BY COALESCE(EXTRACT(YEAR FROM MAX(tmdb_movies.release_date)), EXTRACT(YEAR FROM MAX(tmdb_tv.first_air_date))) ORDER BY SUM(times_completed) DESC) AS place'),
|
||||
])
|
||||
->where($metaIdColumn, '!=', 0)
|
||||
// Small torrents screw the stats since users download them only to farm bon.
|
||||
->where('torrents.size', '>', 2 * 1024 * 1024 * 1024)
|
||||
->when($this->metaType === 'tv_meta', fn ($query) => $query->where('episode_number', '=', 0))
|
||||
->havingNotNull('the_year')
|
||||
->where(fn ($query) => $query->whereNotNull('tmdb_movies.id')->orWhereNotNull('tmdb_tv.id'))
|
||||
->groupBy('the_year', $metaIdColumn),
|
||||
'ranked_groups',
|
||||
)
|
||||
->where('place', '<=', 10)
|
||||
->orderByDesc('the_year')
|
||||
->orderBy('place')
|
||||
->get()
|
||||
->groupBy('the_year')
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array<string, string>
|
||||
*/
|
||||
#[Computed]
|
||||
final public function metaTypes(): array
|
||||
{
|
||||
$metaTypes = [];
|
||||
|
||||
if (Category::where('movie_meta', '=', true)->exists()) {
|
||||
$metaTypes[(string) __('mediahub.movie')] = 'movie_meta';
|
||||
return cache()->remember(
|
||||
'trending-'.$this->interval.'-'.($this->from ?? '').'-'.($this->until ?? '').'-'.$this->metaType,
|
||||
0, //3600,
|
||||
fn () => Torrent::query()
|
||||
->with('movie', 'tv')
|
||||
->addSelect([
|
||||
$metaIdColumn,
|
||||
DB::raw('MIN(category_id) as category_id'),
|
||||
DB::raw('COUNT(*) as download_count'),
|
||||
])
|
||||
->join('history', 'history.torrent_id', '=', 'torrents.id')
|
||||
->where($metaIdColumn, '!=', 0)
|
||||
->when($this->interval === 'day', fn ($query) => $query->whereBetween('history.completed_at', [now()->subDay(), now()]))
|
||||
->when($this->interval === 'week', fn ($query) => $query->whereBetween('history.completed_at', [now()->subWeek(), now()]))
|
||||
->when($this->interval === 'month', fn ($query) => $query->whereBetween('history.completed_at', [now()->subMonth(), now()]))
|
||||
->when($this->interval === 'year', fn ($query) => $query->whereBetween('history.completed_at', [now()->subYear(), now()]))
|
||||
->when($this->interval === 'all', fn ($query) => $query->whereNotNull('history.completed_at'))
|
||||
->when($this->interval === 'custom', fn ($query) => $query->whereBetween('history.completed_at', [$this->from ?: now(), $this->until ?: now()]))
|
||||
->whereRelation('category', $this->metaType, '=', true)
|
||||
// Small torrents screw the stats since users download them only to farm bon.
|
||||
->where('torrents.size', '>', 1024 * 1024 * 1024)
|
||||
->groupBy($metaIdColumn)
|
||||
->orderByRaw('COUNT(*) DESC')
|
||||
->limit(250)
|
||||
->get($metaIdColumn)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
if (Category::where('tv_meta', '=', true)->exists()) {
|
||||
$metaTypes[(string) __('mediahub.show')] = 'tv_meta';
|
||||
/**
|
||||
* @var Collection<int|string, Collection<int, Torrent>>
|
||||
* @phpstan-ignore generics.notSubtype (I can't figure out the correct return type to silence this error)
|
||||
*/
|
||||
final protected Collection $weekly {
|
||||
get {
|
||||
$this->validate();
|
||||
|
||||
$metaIdColumn = match ($this->metaType) {
|
||||
'tv_meta' => 'tmdb_tv_id',
|
||||
default => 'tmdb_movie_id',
|
||||
};
|
||||
|
||||
return cache()->remember(
|
||||
'weekly-charts:'.$this->metaType,
|
||||
24 * 3600,
|
||||
fn () => Torrent::query()
|
||||
->withoutGlobalScopes()
|
||||
->with('movie', 'tv')
|
||||
->fromSub(
|
||||
History::query()
|
||||
->withoutGlobalScopes()
|
||||
->join('torrents', 'torrents.id', '=', 'history.torrent_id')
|
||||
->join('categories', fn (JoinClause $join) => $join->on('torrents.category_id', '=', 'categories.id')->where($this->metaType, '=', true))
|
||||
->select([
|
||||
DB::raw('FROM_DAYS(TO_DAYS(history.created_at) - MOD(TO_DAYS(history.created_at) - 1, 7)) AS week_start'),
|
||||
$metaIdColumn,
|
||||
DB::raw('MIN(categories.id) as category_id'),
|
||||
DB::raw('COUNT(*) AS download_count'),
|
||||
DB::raw('ROW_NUMBER() OVER (PARTITION BY FROM_DAYS(TO_DAYS(history.created_at) - MOD(TO_DAYS(history.created_at) - 1, 7)) ORDER BY COUNT(*) DESC) AS place'),
|
||||
])
|
||||
->where($metaIdColumn, '!=', 0)
|
||||
// Small torrents screw the stats since users download them only to farm bon.
|
||||
->where('torrents.size', '>', 1024 * 1024 * 1024)
|
||||
->groupBy('week_start', $metaIdColumn),
|
||||
'ranked_groups',
|
||||
)
|
||||
->where('place', '<=', 10)
|
||||
->orderByDesc('week_start')
|
||||
->orderBy('place')
|
||||
->withCasts([
|
||||
'week_start' => 'datetime',
|
||||
])
|
||||
->get()
|
||||
->groupBy('week_start')
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
return $metaTypes;
|
||||
/**
|
||||
* @var Collection<int|string, Collection<int, Torrent>>
|
||||
* @phpstan-ignore generics.notSubtype (I can't figure out the correct return type to silence this error)
|
||||
*/
|
||||
final protected Collection $monthly {
|
||||
get {
|
||||
$this->validate();
|
||||
|
||||
$metaIdColumn = match ($this->metaType) {
|
||||
'tv_meta' => 'tmdb_tv_id',
|
||||
default => 'tmdb_movie_id',
|
||||
};
|
||||
|
||||
return cache()->remember(
|
||||
'monthly-charts:'.$this->metaType,
|
||||
24 * 3600,
|
||||
fn () => Torrent::query()
|
||||
->withoutGlobalScopes()
|
||||
->with($this->metaType === 'movie_meta' ? 'movie' : 'tv')
|
||||
->fromSub(
|
||||
History::query()
|
||||
->withoutGlobalScopes()
|
||||
->join('torrents', 'torrents.id', '=', 'history.torrent_id')
|
||||
->join('categories', fn (JoinClause $join) => $join->on('torrents.category_id', '=', 'categories.id')->where($this->metaType, '=', true))
|
||||
->select([
|
||||
DB::raw('EXTRACT(YEAR_MONTH FROM history.created_at) AS the_year_month'),
|
||||
$metaIdColumn,
|
||||
DB::raw('MIN(categories.id) as category_id'),
|
||||
DB::raw('COUNT(*) AS download_count'),
|
||||
DB::raw('ROW_NUMBER() OVER (PARTITION BY EXTRACT(YEAR_MONTH FROM history.created_at) ORDER BY COUNT(*) DESC) AS place'),
|
||||
])
|
||||
->where($metaIdColumn, '!=', 0)
|
||||
// Small torrents screw the stats since users download them only to farm bon.
|
||||
->where('torrents.size', '>', 1024 * 1024 * 1024)
|
||||
->groupBy('the_year_month', $metaIdColumn),
|
||||
'ranked_groups',
|
||||
)
|
||||
->where('place', '<=', 10)
|
||||
->orderByDesc('the_year_month')
|
||||
->orderBy('place')
|
||||
->get()
|
||||
->groupBy('the_year_month')
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @var Collection<int|string, Collection<int, Torrent>>
|
||||
* @phpstan-ignore generics.notSubtype (I can't figure out the correct return type to silence this error)
|
||||
*/
|
||||
final protected Collection $releaseYear {
|
||||
get {
|
||||
$this->validate();
|
||||
|
||||
$metaIdColumn = match ($this->metaType) {
|
||||
'tv_meta' => 'tmdb_tv_id',
|
||||
default => 'tmdb_movie_id',
|
||||
};
|
||||
|
||||
return cache()->remember(
|
||||
'trending-by-release-year:'.$this->metaType,
|
||||
24 * 3600,
|
||||
fn () => Torrent::query()
|
||||
->withoutGlobalScopes()
|
||||
->with($this->metaType === 'movie_meta' ? 'movie' : 'tv')
|
||||
->fromSub(
|
||||
Torrent::query()
|
||||
->withoutGlobalScopes()
|
||||
->whereRelation('category', $this->metaType, '=', true)
|
||||
->leftJoin('tmdb_movies', 'torrents.tmdb_movie_id', '=', 'tmdb_movies.id')
|
||||
->leftJoin('tmdb_tv', 'torrents.tmdb_tv_id', '=', 'tmdb_tv.id')
|
||||
->select([
|
||||
$metaIdColumn,
|
||||
DB::raw('MIN(category_id) as category_id'),
|
||||
DB::raw('SUM(times_completed) AS download_count'),
|
||||
'the_year' => $this->metaType === 'movie_meta'
|
||||
? TmdbMovie::query()
|
||||
->selectRaw('EXTRACT(YEAR FROM tmdb_movies.release_date)')
|
||||
->whereColumn('tmdb_movies.id', '=', 'torrents.tmdb_movie_id')
|
||||
: TmdbTv::query()
|
||||
->selectRaw('EXTRACT(YEAR FROM tmdb_tv.first_air_date)')
|
||||
->whereColumn('tmdb_tv.id', '=', 'torrents.tmdb_tv_id'),
|
||||
DB::raw('ROW_NUMBER() OVER (PARTITION BY COALESCE(EXTRACT(YEAR FROM MAX(tmdb_movies.release_date)), EXTRACT(YEAR FROM MAX(tmdb_tv.first_air_date))) ORDER BY SUM(times_completed) DESC) AS place'),
|
||||
])
|
||||
->where($metaIdColumn, '!=', 0)
|
||||
// Small torrents screw the stats since users download them only to farm bon.
|
||||
->where('torrents.size', '>', 2 * 1024 * 1024 * 1024)
|
||||
->when($this->metaType === 'tv_meta', fn ($query) => $query->where('episode_number', '=', 0))
|
||||
->havingNotNull('the_year')
|
||||
->where(fn ($query) => $query->whereNotNull('tmdb_movies.id')->orWhereNotNull('tmdb_tv.id'))
|
||||
->groupBy('the_year', $metaIdColumn),
|
||||
'ranked_groups',
|
||||
)
|
||||
->where('place', '<=', 10)
|
||||
->orderByDesc('the_year')
|
||||
->orderBy('place')
|
||||
->get()
|
||||
->groupBy('the_year')
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @var array<string, string>
|
||||
*/
|
||||
final protected array $metaTypes {
|
||||
get {
|
||||
$metaTypes = [];
|
||||
|
||||
if (Category::where('movie_meta', '=', true)->exists()) {
|
||||
$metaTypes[(string) __('mediahub.movie')] = 'movie_meta';
|
||||
}
|
||||
|
||||
if (Category::where('tv_meta', '=', true)->exists()) {
|
||||
$metaTypes[(string) __('mediahub.show')] = 'tv_meta';
|
||||
}
|
||||
|
||||
return $metaTypes;
|
||||
}
|
||||
}
|
||||
|
||||
final public function placeholder(): string
|
||||
|
||||
@@ -21,7 +21,6 @@ use Laravel\Fortify\Actions\DisableTwoFactorAuthentication;
|
||||
use Laravel\Fortify\Actions\EnableTwoFactorAuthentication;
|
||||
use Laravel\Fortify\Actions\GenerateNewRecoveryCodes;
|
||||
use Laravel\Fortify\Features;
|
||||
use Livewire\Attributes\Computed;
|
||||
use Livewire\Component;
|
||||
|
||||
class TwoFactorAuthForm extends Component
|
||||
@@ -126,19 +125,15 @@ class TwoFactorAuthForm extends Component
|
||||
/**
|
||||
* Get the current user of the application.
|
||||
*/
|
||||
#[Computed]
|
||||
final public function user(): ?\Illuminate\Contracts\Auth\Authenticatable
|
||||
{
|
||||
return auth()->user();
|
||||
final protected ?\Illuminate\Contracts\Auth\Authenticatable $user {
|
||||
get => auth()->user();
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine if two-factor authentication is enabled.
|
||||
*/
|
||||
#[Computed]
|
||||
final public function enabled(): bool
|
||||
{
|
||||
return !empty($this->user->two_factor_secret);
|
||||
final protected bool $enabled {
|
||||
get => !empty($this->user->two_factor_secret);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -21,7 +21,6 @@ use App\Models\UnregisteredInfoHash;
|
||||
use App\Traits\CastLivewireProperties;
|
||||
use App\Traits\LivewireSort;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
use Livewire\Attributes\Computed;
|
||||
use Livewire\Attributes\Url;
|
||||
use Livewire\Component;
|
||||
use Livewire\WithPagination;
|
||||
@@ -58,12 +57,10 @@ class UnregisteredInfoHashSearch extends Component
|
||||
}
|
||||
|
||||
/**
|
||||
* @return \Illuminate\Pagination\LengthAwarePaginator<int, UnregisteredInfoHash>
|
||||
* @var \Illuminate\Pagination\LengthAwarePaginator<int, UnregisteredInfoHash>
|
||||
*/
|
||||
#[Computed]
|
||||
final public function unregisteredInfoHashes(): \Illuminate\Pagination\LengthAwarePaginator
|
||||
{
|
||||
return UnregisteredInfoHash::query()
|
||||
final protected \Illuminate\Pagination\LengthAwarePaginator $unregisteredInfoHashes {
|
||||
get => UnregisteredInfoHash::query()
|
||||
->with('user')
|
||||
->when($this->username !== '', fn ($query) => $query->whereRelation('user', 'username', 'LIKE', '%'.$this->username.'%'))
|
||||
->when(
|
||||
|
||||
@@ -19,14 +19,10 @@ namespace App\Http\Livewire;
|
||||
use App\Models\Peer;
|
||||
use App\Models\User;
|
||||
use App\Traits\LivewireSort;
|
||||
use Livewire\Attributes\Computed;
|
||||
use Livewire\Attributes\Url;
|
||||
use Livewire\Component;
|
||||
use Livewire\WithPagination;
|
||||
|
||||
/**
|
||||
* @property \Illuminate\Pagination\LengthAwarePaginator<int, Peer> $actives
|
||||
*/
|
||||
class UserActive extends Component
|
||||
{
|
||||
use LivewireSort;
|
||||
@@ -80,12 +76,10 @@ class UserActive extends Component
|
||||
}
|
||||
|
||||
/**
|
||||
* @return \Illuminate\Pagination\LengthAwarePaginator<int, Peer>
|
||||
* @var \Illuminate\Pagination\LengthAwarePaginator<int, Peer>
|
||||
*/
|
||||
#[Computed]
|
||||
final public function actives(): \Illuminate\Pagination\LengthAwarePaginator
|
||||
{
|
||||
return Peer::query()
|
||||
final protected \Illuminate\Pagination\LengthAwarePaginator $actives {
|
||||
get => Peer::query()
|
||||
->join('torrents', 'peers.torrent_id', '=', 'torrents.id')
|
||||
->select(
|
||||
'peers.port',
|
||||
|
||||
@@ -19,7 +19,6 @@ namespace App\Http\Livewire;
|
||||
use App\Models\Bookmark;
|
||||
use App\Models\User;
|
||||
use App\Traits\LivewireSort;
|
||||
use Livewire\Attributes\Computed;
|
||||
use Livewire\Attributes\Url;
|
||||
use Livewire\Component;
|
||||
use Livewire\WithPagination;
|
||||
@@ -45,12 +44,10 @@ class UserBookmarks extends Component
|
||||
}
|
||||
|
||||
/**
|
||||
* @return \Illuminate\Contracts\Pagination\LengthAwarePaginator<int, Bookmark>
|
||||
* @var \Illuminate\Contracts\Pagination\LengthAwarePaginator<int, Bookmark>
|
||||
*/
|
||||
#[Computed]
|
||||
final public function bookmarks(): \Illuminate\Contracts\Pagination\LengthAwarePaginator
|
||||
{
|
||||
return Bookmark::query()
|
||||
final protected \Illuminate\Contracts\Pagination\LengthAwarePaginator $bookmarks {
|
||||
get => Bookmark::query()
|
||||
->select([
|
||||
'bookmarks.torrent_id',
|
||||
'bookmarks.created_at as bookmark_created_at',
|
||||
|
||||
@@ -21,14 +21,10 @@ use App\Models\User;
|
||||
use App\Models\Peer;
|
||||
use App\Traits\LivewireSort;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
use Livewire\Attributes\Computed;
|
||||
use Livewire\Attributes\Url;
|
||||
use Livewire\Component;
|
||||
use Livewire\WithPagination;
|
||||
|
||||
/**
|
||||
* @property \Illuminate\Pagination\LengthAwarePaginator<int, BonEarning> $bonEarnings
|
||||
*/
|
||||
class UserEarnings extends Component
|
||||
{
|
||||
use LivewireSort;
|
||||
@@ -64,75 +60,89 @@ class UserEarnings extends Component
|
||||
}
|
||||
|
||||
/**
|
||||
* @return \Illuminate\Database\Eloquent\Collection<int, BonEarning>
|
||||
* @var \Illuminate\Database\Eloquent\Collection<int, BonEarning>
|
||||
*/
|
||||
#[Computed]
|
||||
final public function bonEarnings(): \Illuminate\Support\Collection
|
||||
{
|
||||
$outerQuery = DB::query()->select(DB::raw(1));
|
||||
$innerQuery = Peer::query()
|
||||
->select(DB::raw(1))
|
||||
->join('history', fn ($join) => $join->on('history.torrent_id', '=', 'peers.torrent_id')->on('history.user_id', '=', 'peers.user_id'))
|
||||
->join('torrents', 'peers.torrent_id', '=', 'torrents.id')
|
||||
->where('peers.seeder', '=', true)
|
||||
->where('peers.active', '=', true)
|
||||
->where('peers.user_id', '=', $this->user->id)
|
||||
->where('peers.created_at', '<', now()->subMinutes(30))
|
||||
->where('torrents.name', 'LIKE', '%'.str_replace(' ', '%', $this->torrentName).'%')
|
||||
->groupBy('peers.torrent_id');
|
||||
final protected \Illuminate\Support\Collection $bonEarnings {
|
||||
get {
|
||||
$outerQuery = DB::query()->select(DB::raw(1));
|
||||
$innerQuery = Peer::query()
|
||||
->select(DB::raw(1))
|
||||
->join('history', fn ($join) => $join->on('history.torrent_id', '=', 'peers.torrent_id')->on('history.user_id', '=', 'peers.user_id'))
|
||||
->join('torrents', 'peers.torrent_id', '=', 'torrents.id')
|
||||
->where('peers.seeder', '=', true)
|
||||
->where('peers.active', '=', true)
|
||||
->where('peers.user_id', '=', $this->user->id)
|
||||
->where('peers.created_at', '<', now()->subMinutes(30))
|
||||
->where('torrents.name', 'LIKE', '%'.str_replace(' ', '%', $this->torrentName).'%')
|
||||
->groupBy('peers.torrent_id');
|
||||
|
||||
foreach (BonEarning::with('conditions')->orderBy('position')->get() as $bonEarning) {
|
||||
// Raw bindings are fine since all database values are either enums or numeric
|
||||
$conditionQuery = '1=1';
|
||||
foreach (BonEarning::with('conditions')->orderBy('position')->get() as $bonEarning) {
|
||||
// Raw bindings are fine since all database values are either enums or numeric
|
||||
$conditionQuery = '1=1';
|
||||
|
||||
foreach ($bonEarning->conditions as $condition) {
|
||||
$conditionQuery .= ' AND '.match ($condition->operand1) {
|
||||
'1' => '1',
|
||||
'age' => 'TIMESTAMPDIFF(SECOND, torrents.created_at, NOW())',
|
||||
'size' => 'torrents.size',
|
||||
'seeders' => 'torrents.seeders',
|
||||
'leechers' => 'torrents.leechers',
|
||||
'times_completed' => 'torrents.times_completed',
|
||||
'internal' => 'torrents.internal',
|
||||
'personal_release' => 'torrents.personal_release',
|
||||
'type_id' => 'torrents.type_id',
|
||||
'seedtime' => 'history.seedtime',
|
||||
'connectable' => 'peers.connectable',
|
||||
}.' '.$condition->operator.' '.$condition->operand2;
|
||||
foreach ($bonEarning->conditions as $condition) {
|
||||
$conditionQuery .= ' AND '.match ($condition->operand1) {
|
||||
'1' => '1',
|
||||
'age' => 'TIMESTAMPDIFF(SECOND, torrents.created_at, NOW())',
|
||||
'size' => 'torrents.size',
|
||||
'seeders' => 'torrents.seeders',
|
||||
'leechers' => 'torrents.leechers',
|
||||
'times_completed' => 'torrents.times_completed',
|
||||
'internal' => 'torrents.internal',
|
||||
'personal_release' => 'torrents.personal_release',
|
||||
'type_id' => 'torrents.type_id',
|
||||
'seedtime' => 'history.seedtime',
|
||||
'connectable' => 'peers.connectable',
|
||||
}.' '.$condition->operator.' '.$condition->operand2;
|
||||
}
|
||||
|
||||
$innerQuery->selectRaw("MAX({$conditionQuery}) AS bon_earning_{$bonEarning->id}");
|
||||
$outerQuery->selectRaw("SUM(bon_earning_{$bonEarning->id}) AS bon_earning_{$bonEarning->id}");
|
||||
}
|
||||
|
||||
$innerQuery->selectRaw("MAX({$conditionQuery}) AS bon_earning_{$bonEarning->id}");
|
||||
$outerQuery->selectRaw("SUM(bon_earning_{$bonEarning->id}) AS bon_earning_{$bonEarning->id}");
|
||||
$torrentCounts = $outerQuery->fromSub($innerQuery, 'peers_per_torrent')->first();
|
||||
|
||||
return BonEarning::query()
|
||||
->orderBy('position')
|
||||
->get()
|
||||
->map(function ($bonEarning) use ($torrentCounts) {
|
||||
$bonEarning->setAttribute('torrents_count', $torrentCounts->{"bon_earning_{$bonEarning->id}"});
|
||||
|
||||
return $bonEarning;
|
||||
});
|
||||
}
|
||||
|
||||
$torrentCounts = $outerQuery->fromSub($innerQuery, 'peers_per_torrent')->first();
|
||||
|
||||
return BonEarning::query()
|
||||
->orderBy('position')
|
||||
->get()
|
||||
->map(function ($bonEarning) use ($torrentCounts) {
|
||||
$bonEarning->setAttribute('torrents_count', $torrentCounts->{"bon_earning_{$bonEarning->id}"});
|
||||
|
||||
return $bonEarning;
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* @return \Illuminate\Database\Query\Builder
|
||||
* @var \Illuminate\Database\Query\Builder
|
||||
*/
|
||||
#[Computed]
|
||||
final public function query(): \Illuminate\Database\Query\Builder
|
||||
{
|
||||
$bonEarnings = BonEarning::with('conditions')->orderBy('position')->get();
|
||||
final protected \Illuminate\Database\Query\Builder $query {
|
||||
get {
|
||||
$bonEarnings = BonEarning::with('conditions')->orderBy('position')->get();
|
||||
|
||||
$earningsQuery = str_repeat('(', $bonEarnings->count()).'0';
|
||||
$earningsQuery = str_repeat('(', $bonEarnings->count()).'0';
|
||||
|
||||
foreach ($bonEarnings as $bonEarning) {
|
||||
// Raw bindings are fine since all database values are either enums or numeric
|
||||
$conditionQuery = '1=1';
|
||||
foreach ($bonEarnings as $bonEarning) {
|
||||
// Raw bindings are fine since all database values are either enums or numeric
|
||||
$conditionQuery = '1=1';
|
||||
|
||||
foreach ($bonEarning->conditions as $condition) {
|
||||
$conditionQuery .= ' AND '.match ($condition->operand1) {
|
||||
foreach ($bonEarning->conditions as $condition) {
|
||||
$conditionQuery .= ' AND '.match ($condition->operand1) {
|
||||
'1' => '1',
|
||||
'age' => 'TIMESTAMPDIFF(SECOND, torrents.created_at, NOW())',
|
||||
'size' => 'torrents.size',
|
||||
'seeders' => 'torrents.seeders',
|
||||
'leechers' => 'torrents.leechers',
|
||||
'times_completed' => 'torrents.times_completed',
|
||||
'internal' => 'torrents.internal',
|
||||
'personal_release' => 'torrents.personal_release',
|
||||
'type_id' => 'torrents.type_id',
|
||||
'seedtime' => 'history.seedtime',
|
||||
'connectable' => 'MAX(peers.connectable)',
|
||||
}.' '.$condition->operator.' '.$condition->operand2;
|
||||
}
|
||||
|
||||
$variable = match ($bonEarning->variable) {
|
||||
'1' => '1',
|
||||
'age' => 'TIMESTAMPDIFF(SECOND, torrents.created_at, NOW())',
|
||||
'size' => 'torrents.size',
|
||||
@@ -141,68 +151,52 @@ class UserEarnings extends Component
|
||||
'times_completed' => 'torrents.times_completed',
|
||||
'internal' => 'torrents.internal',
|
||||
'personal_release' => 'torrents.personal_release',
|
||||
'type_id' => 'torrents.type_id',
|
||||
'seedtime' => 'history.seedtime',
|
||||
'connectable' => 'MAX(peers.connectable)',
|
||||
}.' '.$condition->operator.' '.$condition->operand2;
|
||||
};
|
||||
|
||||
$earningsQuery .= match ($bonEarning->operation) {
|
||||
'append' => " + CASE WHEN ({$conditionQuery}) THEN {$variable} * {$bonEarning->multiplier} ELSE 0 END)",
|
||||
'multiply' => " * CASE WHEN ({$conditionQuery}) THEN {$variable} * {$bonEarning->multiplier} ELSE 1 END)",
|
||||
};
|
||||
}
|
||||
|
||||
$variable = match ($bonEarning->variable) {
|
||||
'1' => '1',
|
||||
'age' => 'TIMESTAMPDIFF(SECOND, torrents.created_at, NOW())',
|
||||
'size' => 'torrents.size',
|
||||
'seeders' => 'torrents.seeders',
|
||||
'leechers' => 'torrents.leechers',
|
||||
'times_completed' => 'torrents.times_completed',
|
||||
'internal' => 'torrents.internal',
|
||||
'personal_release' => 'torrents.personal_release',
|
||||
'seedtime' => 'history.seedtime',
|
||||
'connectable' => 'MAX(peers.connectable)',
|
||||
};
|
||||
$query = DB::table('peers')
|
||||
->select([
|
||||
DB::raw('1 as "1"'),
|
||||
'torrents.name',
|
||||
DB::raw('TIMESTAMPDIFF(SECOND, torrents.created_at, NOW()) as age'),
|
||||
'torrents.type_id',
|
||||
'torrents.size',
|
||||
'torrents.seeders',
|
||||
'torrents.leechers',
|
||||
'torrents.times_completed',
|
||||
'history.seedtime',
|
||||
'torrents.personal_release',
|
||||
'torrents.internal',
|
||||
DB::raw('MAX(peers.connectable) as connectable'),
|
||||
'peers.torrent_id',
|
||||
'peers.user_id',
|
||||
DB::raw("({$earningsQuery}) AS hourly_earnings"),
|
||||
])
|
||||
->join('history', fn ($join) => $join->on('history.torrent_id', '=', 'peers.torrent_id')->on('history.user_id', '=', 'peers.user_id'))
|
||||
->join('torrents', 'peers.torrent_id', '=', 'torrents.id')
|
||||
->where('peers.seeder', '=', true)
|
||||
->where('peers.active', '=', true)
|
||||
->where('peers.user_id', '=', $this->user->id)
|
||||
->where('peers.created_at', '<', now()->subMinutes(30))
|
||||
->where('torrents.name', 'LIKE', '%'.str_replace(' ', '%', $this->torrentName).'%')
|
||||
->groupBy(['peers.torrent_id', 'peers.user_id']);
|
||||
|
||||
$earningsQuery .= match ($bonEarning->operation) {
|
||||
'append' => " + CASE WHEN ({$conditionQuery}) THEN {$variable} * {$bonEarning->multiplier} ELSE 0 END)",
|
||||
'multiply' => " * CASE WHEN ({$conditionQuery}) THEN {$variable} * {$bonEarning->multiplier} ELSE 1 END)",
|
||||
};
|
||||
return $query;
|
||||
}
|
||||
|
||||
$query = DB::table('peers')
|
||||
->select([
|
||||
DB::raw('1 as "1"'),
|
||||
'torrents.name',
|
||||
DB::raw('TIMESTAMPDIFF(SECOND, torrents.created_at, NOW()) as age'),
|
||||
'torrents.type_id',
|
||||
'torrents.size',
|
||||
'torrents.seeders',
|
||||
'torrents.leechers',
|
||||
'torrents.times_completed',
|
||||
'history.seedtime',
|
||||
'torrents.personal_release',
|
||||
'torrents.internal',
|
||||
DB::raw('MAX(peers.connectable) as connectable'),
|
||||
'peers.torrent_id',
|
||||
'peers.user_id',
|
||||
DB::raw("({$earningsQuery}) AS hourly_earnings"),
|
||||
])
|
||||
->join('history', fn ($join) => $join->on('history.torrent_id', '=', 'peers.torrent_id')->on('history.user_id', '=', 'peers.user_id'))
|
||||
->join('torrents', 'peers.torrent_id', '=', 'torrents.id')
|
||||
->where('peers.seeder', '=', true)
|
||||
->where('peers.active', '=', true)
|
||||
->where('peers.user_id', '=', $this->user->id)
|
||||
->where('peers.created_at', '<', now()->subMinutes(30))
|
||||
->where('torrents.name', 'LIKE', '%'.str_replace(' ', '%', $this->torrentName).'%')
|
||||
->groupBy(['peers.torrent_id', 'peers.user_id']);
|
||||
|
||||
return $query;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return \Illuminate\Contracts\Pagination\LengthAwarePaginator<int, Peer>
|
||||
* @var \Illuminate\Contracts\Pagination\LengthAwarePaginator<int, Peer>
|
||||
*/
|
||||
#[Computed]
|
||||
final public function torrents(): \Illuminate\Contracts\Pagination\LengthAwarePaginator
|
||||
{
|
||||
return $this
|
||||
final protected \Illuminate\Contracts\Pagination\LengthAwarePaginator $torrents {
|
||||
get => $this
|
||||
->query
|
||||
->orderBy($this->sortField, $this->sortDirection)
|
||||
->paginate(25);
|
||||
@@ -211,10 +205,8 @@ class UserEarnings extends Component
|
||||
/**
|
||||
* @return float|numeric-string
|
||||
*/
|
||||
#[Computed]
|
||||
final public function total(): float|string
|
||||
{
|
||||
return DB::query()->fromSub($this->query, 'earnings_per_torrent')->sum('hourly_earnings');
|
||||
final protected float|string $total {
|
||||
get => DB::query()->fromSub($this->query, 'earnings_per_torrent')->sum('hourly_earnings');
|
||||
}
|
||||
|
||||
final public function render(): \Illuminate\Contracts\View\Factory|\Illuminate\Contracts\View\View|\Illuminate\Contracts\Foundation\Application
|
||||
|
||||
@@ -18,7 +18,6 @@ namespace App\Http\Livewire;
|
||||
|
||||
use App\Models\Note;
|
||||
use App\Models\User;
|
||||
use Livewire\Attributes\Computed;
|
||||
use Livewire\Attributes\Url;
|
||||
use Livewire\Component;
|
||||
use Livewire\WithPagination;
|
||||
@@ -70,12 +69,10 @@ class UserNotes extends Component
|
||||
}
|
||||
|
||||
/**
|
||||
* @return \Illuminate\Pagination\LengthAwarePaginator<int, Note>
|
||||
* @var \Illuminate\Pagination\LengthAwarePaginator<int, Note>
|
||||
*/
|
||||
#[Computed]
|
||||
final public function notes(): \Illuminate\Pagination\LengthAwarePaginator
|
||||
{
|
||||
return Note::query()
|
||||
final protected \Illuminate\Pagination\LengthAwarePaginator $notes {
|
||||
get => Note::query()
|
||||
->with('staffuser', 'staffuser.group')
|
||||
->where('user_id', '=', $this->user->id)
|
||||
->paginate($this->perPage);
|
||||
|
||||
@@ -19,7 +19,6 @@ namespace App\Http\Livewire;
|
||||
use App\Models\Resurrection;
|
||||
use App\Models\User;
|
||||
use App\Traits\LivewireSort;
|
||||
use Livewire\Attributes\Computed;
|
||||
use Livewire\Attributes\Url;
|
||||
use Livewire\Component;
|
||||
use Livewire\WithPagination;
|
||||
@@ -59,12 +58,10 @@ class UserResurrections extends Component
|
||||
}
|
||||
|
||||
/**
|
||||
* @return \Illuminate\Contracts\Pagination\LengthAwarePaginator<int, Resurrection>
|
||||
* @var \Illuminate\Contracts\Pagination\LengthAwarePaginator<int, Resurrection>
|
||||
*/
|
||||
#[Computed]
|
||||
final public function resurrections(): \Illuminate\Contracts\Pagination\LengthAwarePaginator
|
||||
{
|
||||
return Resurrection::query()
|
||||
final protected \Illuminate\Contracts\Pagination\LengthAwarePaginator $resurrections {
|
||||
get => Resurrection::query()
|
||||
->select([
|
||||
'resurrections.id',
|
||||
'resurrections.created_at',
|
||||
|
||||
@@ -20,7 +20,6 @@ use App\Models\Group;
|
||||
use App\Models\User;
|
||||
use App\Traits\CastLivewireProperties;
|
||||
use App\Traits\LivewireSort;
|
||||
use Livewire\Attributes\Computed;
|
||||
use Livewire\Attributes\Url;
|
||||
use Livewire\Component;
|
||||
use Livewire\WithPagination;
|
||||
@@ -75,12 +74,10 @@ class UserSearch extends Component
|
||||
}
|
||||
|
||||
/**
|
||||
* @return \Illuminate\Pagination\LengthAwarePaginator<int, User>
|
||||
* @var \Illuminate\Pagination\LengthAwarePaginator<int, User>
|
||||
*/
|
||||
#[Computed]
|
||||
final public function users(): \Illuminate\Pagination\LengthAwarePaginator
|
||||
{
|
||||
return User::query()
|
||||
final protected \Illuminate\Pagination\LengthAwarePaginator $users {
|
||||
get => User::query()
|
||||
->with('group')
|
||||
->when($this->username !== '', fn ($query) => $query->where('username', 'LIKE', '%'.$this->username.'%'))
|
||||
->when(
|
||||
@@ -106,12 +103,10 @@ class UserSearch extends Component
|
||||
}
|
||||
|
||||
/**
|
||||
* @return \Illuminate\Support\Collection<int, Group>
|
||||
* @var \Illuminate\Support\Collection<int, Group>
|
||||
*/
|
||||
#[Computed]
|
||||
final public function groups()
|
||||
{
|
||||
return Group::orderBy('position')->get();
|
||||
final protected $groups {
|
||||
get => Group::orderBy('position')->get();
|
||||
}
|
||||
|
||||
final public function render(): \Illuminate\Contracts\View\Factory|\Illuminate\Contracts\View\View|\Illuminate\Contracts\Foundation\Application
|
||||
|
||||
@@ -19,7 +19,6 @@ namespace App\Http\Livewire;
|
||||
use App\Models\History;
|
||||
use App\Models\User;
|
||||
use App\Traits\LivewireSort;
|
||||
use Livewire\Attributes\Computed;
|
||||
use Livewire\Attributes\Url;
|
||||
use Livewire\Component;
|
||||
use Livewire\WithPagination;
|
||||
@@ -89,12 +88,10 @@ class UserTorrents extends Component
|
||||
}
|
||||
|
||||
/**
|
||||
* @return \Illuminate\Contracts\Pagination\LengthAwarePaginator<int, History>
|
||||
* @var \Illuminate\Contracts\Pagination\LengthAwarePaginator<int, History>
|
||||
*/
|
||||
#[Computed]
|
||||
final public function history(): \Illuminate\Contracts\Pagination\LengthAwarePaginator
|
||||
{
|
||||
return History::query()
|
||||
final protected \Illuminate\Contracts\Pagination\LengthAwarePaginator $history {
|
||||
get => History::query()
|
||||
->join(
|
||||
'torrents',
|
||||
fn ($join) => $join
|
||||
|
||||
86
app/Http/Livewire/UserUnregisteredInfoHashSearch.php
Normal file
86
app/Http/Livewire/UserUnregisteredInfoHashSearch.php
Normal file
@@ -0,0 +1,86 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
/**
|
||||
* NOTICE OF LICENSE.
|
||||
*
|
||||
* UNIT3D Community Edition is open-sourced software licensed under the GNU Affero General Public License v3.0
|
||||
* The details is bundled with this project in the file LICENSE.txt.
|
||||
*
|
||||
* @project UNIT3D Community Edition
|
||||
*
|
||||
* @author Roardom <roardom@protonmail.com>
|
||||
* @license https://www.gnu.org/licenses/agpl-3.0.en.html/ GNU Affero General Public License v3.0
|
||||
*/
|
||||
|
||||
namespace App\Http\Livewire;
|
||||
|
||||
use App\Models\UnregisteredInfoHash;
|
||||
use App\Models\User;
|
||||
use App\Traits\CastLivewireProperties;
|
||||
use App\Traits\LivewireSort;
|
||||
use Livewire\Attributes\Url;
|
||||
use Livewire\Component;
|
||||
use Livewire\WithPagination;
|
||||
|
||||
class UserUnregisteredInfoHashSearch extends Component
|
||||
{
|
||||
use CastLivewireProperties;
|
||||
use LivewireSort;
|
||||
use WithPagination;
|
||||
|
||||
public ?User $user = null;
|
||||
|
||||
#TODO: Update URL attributes once Livewire 3 fixes upstream bug. See: https://github.com/livewire/livewire/discussions/7746
|
||||
|
||||
#[Url(history: true)]
|
||||
public int $perPage = 25;
|
||||
|
||||
#[Url(history: true)]
|
||||
public string $sortField = 'deleted_at';
|
||||
|
||||
#[Url(history: true)]
|
||||
public string $sortDirection = 'desc';
|
||||
|
||||
final public function mount(int $userId): void
|
||||
{
|
||||
$this->user = User::find($userId);
|
||||
}
|
||||
|
||||
final public function updatingSearch(): void
|
||||
{
|
||||
$this->resetPage();
|
||||
}
|
||||
|
||||
/**
|
||||
* @var \Illuminate\Pagination\LengthAwarePaginator<int, UnregisteredInfoHash>
|
||||
*/
|
||||
final protected \Illuminate\Pagination\LengthAwarePaginator $unregisteredInfoHashes {
|
||||
get => UnregisteredInfoHash::query()
|
||||
->select([
|
||||
'unregistered_info_hashes.info_hash',
|
||||
'unregistered_info_hashes.updated_at',
|
||||
'torrents.id',
|
||||
'torrents.name',
|
||||
'torrents.size',
|
||||
'torrents.deleted_at',
|
||||
])
|
||||
->withCasts([
|
||||
'deleted_at' => 'datetime',
|
||||
])
|
||||
->join('torrents', 'unregistered_info_hashes.info_hash', '=', 'torrents.info_hash')
|
||||
->whereBelongsTo($this->user)
|
||||
->whereNotNull('torrents.deleted_at')
|
||||
->where('unregistered_info_hashes.updated_at', '>', now()->subHours(2))
|
||||
->orderBy($this->sortField, $this->sortDirection)
|
||||
->paginate($this->perPage);
|
||||
}
|
||||
|
||||
final public function render(): \Illuminate\Contracts\View\Factory|\Illuminate\Contracts\View\View|\Illuminate\Contracts\Foundation\Application
|
||||
{
|
||||
return view('livewire.user-unregistered-info-hash-search', [
|
||||
'unregisteredInfoHashes' => $this->unregisteredInfoHashes,
|
||||
]);
|
||||
}
|
||||
}
|
||||
@@ -20,7 +20,6 @@ use App\Models\Scopes\ApprovedScope;
|
||||
use App\Models\Torrent;
|
||||
use App\Models\User;
|
||||
use App\Traits\LivewireSort;
|
||||
use Livewire\Attributes\Computed;
|
||||
use Livewire\Attributes\Url;
|
||||
use Livewire\Component;
|
||||
use Livewire\WithPagination;
|
||||
@@ -69,12 +68,10 @@ class UserUploads extends Component
|
||||
}
|
||||
|
||||
/**
|
||||
* @return \Illuminate\Pagination\LengthAwarePaginator<int, Torrent>
|
||||
* @var \Illuminate\Pagination\LengthAwarePaginator<int, Torrent>
|
||||
*/
|
||||
#[Computed]
|
||||
final public function uploads(): \Illuminate\Pagination\LengthAwarePaginator
|
||||
{
|
||||
return Torrent::query()
|
||||
final protected \Illuminate\Pagination\LengthAwarePaginator $uploads {
|
||||
get => Torrent::query()
|
||||
->withCount('thanks', 'comments')
|
||||
->withSum('tips', 'bon')
|
||||
->withoutGlobalScope(ApprovedScope::class)
|
||||
|
||||
@@ -25,18 +25,11 @@ use App\Notifications\WarningsDeleted;
|
||||
use App\Notifications\WarningTorrentDeleted;
|
||||
use App\Traits\LivewireSort;
|
||||
use Illuminate\Support\Carbon;
|
||||
use Livewire\Attributes\Computed;
|
||||
use Livewire\Attributes\Url;
|
||||
use Livewire\Attributes\Validate;
|
||||
use Livewire\Component;
|
||||
use Livewire\WithPagination;
|
||||
|
||||
/**
|
||||
* @property \Illuminate\Pagination\LengthAwarePaginator<int, Warning> $warnings
|
||||
* @property int $automatedWarningsCount
|
||||
* @property int $manualWarningsCount
|
||||
* @property int $deletedWarningsCount
|
||||
*/
|
||||
class UserWarnings extends Component
|
||||
{
|
||||
use LivewireSort;
|
||||
@@ -64,12 +57,10 @@ class UserWarnings extends Component
|
||||
public string $sortDirection = 'desc';
|
||||
|
||||
/**
|
||||
* @return \Illuminate\Pagination\LengthAwarePaginator<int, Warning>
|
||||
* @var \Illuminate\Pagination\LengthAwarePaginator<int, Warning>
|
||||
*/
|
||||
#[Computed]
|
||||
final public function warnings(): \Illuminate\Pagination\LengthAwarePaginator
|
||||
{
|
||||
return $this->user
|
||||
final protected \Illuminate\Pagination\LengthAwarePaginator $warnings {
|
||||
get => $this->user
|
||||
->userwarning()
|
||||
->when(
|
||||
auth()->user()->group->is_modo,
|
||||
@@ -87,22 +78,16 @@ class UserWarnings extends Component
|
||||
->paginate($this->perPage);
|
||||
}
|
||||
|
||||
#[Computed]
|
||||
final public function automatedWarningsCount(): int
|
||||
{
|
||||
return $this->user->userwarning()->whereNotNull('torrent')->count();
|
||||
final protected int $automatedWarningsCount {
|
||||
get => $this->user->userwarning()->whereNotNull('torrent')->count();
|
||||
}
|
||||
|
||||
#[Computed]
|
||||
final public function manualWarningsCount(): int
|
||||
{
|
||||
return $this->user->userwarning()->whereNull('torrent')->count();
|
||||
final protected int $manualWarningsCount {
|
||||
get => $this->user->userwarning()->whereNull('torrent')->count();
|
||||
}
|
||||
|
||||
#[Computed]
|
||||
final public function deletedWarningsCount(): int
|
||||
{
|
||||
return $this->user->userwarning()->onlyTrashed()->count();
|
||||
final protected int $deletedWarningsCount {
|
||||
get => $this->user->userwarning()->onlyTrashed()->count();
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -18,7 +18,6 @@ namespace App\Http\Livewire;
|
||||
|
||||
use App\Models\Warning;
|
||||
use App\Traits\LivewireSort;
|
||||
use Livewire\Attributes\Computed;
|
||||
use Livewire\Attributes\Url;
|
||||
use Livewire\Component;
|
||||
use Livewire\WithPagination;
|
||||
@@ -55,12 +54,10 @@ class WarningLogSearch extends Component
|
||||
public string $sortDirection = 'desc';
|
||||
|
||||
/**
|
||||
* @return \Illuminate\Pagination\LengthAwarePaginator<int, Warning>
|
||||
* @var \Illuminate\Pagination\LengthAwarePaginator<int, Warning>
|
||||
*/
|
||||
#[Computed]
|
||||
final public function warnings(): \Illuminate\Pagination\LengthAwarePaginator
|
||||
{
|
||||
return Warning::query()
|
||||
final protected \Illuminate\Pagination\LengthAwarePaginator $warnings {
|
||||
get => Warning::query()
|
||||
->with(['warneduser.group', 'staffuser.group', 'torrenttitle'])
|
||||
->when($this->sender, fn ($query) => $query->whereRelation('staffuser', 'username', '=', $this->sender))
|
||||
->when($this->receiver, fn ($query) => $query->whereRelation('warneduser', 'username', '=', $this->receiver))
|
||||
|
||||
@@ -18,7 +18,6 @@ namespace App\Http\Livewire;
|
||||
|
||||
use App\Models\Watchlist;
|
||||
use App\Traits\LivewireSort;
|
||||
use Livewire\Attributes\Computed;
|
||||
use Livewire\Attributes\Url;
|
||||
use Livewire\Component;
|
||||
use Livewire\WithPagination;
|
||||
@@ -55,12 +54,10 @@ class WatchlistSearch extends Component
|
||||
}
|
||||
|
||||
/**
|
||||
* @return \Illuminate\Pagination\LengthAwarePaginator<int, Watchlist>
|
||||
* @var \Illuminate\Pagination\LengthAwarePaginator<int, Watchlist>
|
||||
*/
|
||||
#[Computed]
|
||||
final public function users(): \Illuminate\Pagination\LengthAwarePaginator
|
||||
{
|
||||
return Watchlist::query()
|
||||
final protected \Illuminate\Pagination\LengthAwarePaginator $users {
|
||||
get => Watchlist::query()
|
||||
->with(['user.group', 'author.group'])
|
||||
->when($this->search, fn ($query) => $query->where('message', 'LIKE', '%'.$this->search.'%'))
|
||||
->orderBy($this->sortField, $this->sortDirection)
|
||||
|
||||
@@ -39,6 +39,28 @@ class CheckIfBanned
|
||||
'message' => __('auth.banned'),
|
||||
]);
|
||||
}
|
||||
|
||||
if ($request->is('rss/*')) {
|
||||
$message = __('auth.banned');
|
||||
$now = now()->toRssString();
|
||||
$url = config('app.url');
|
||||
|
||||
return response(
|
||||
<<<XML
|
||||
<?xml version="1.0" encoding="UTF-8" ?>
|
||||
<rss version="2.0">
|
||||
<channel>
|
||||
<title>{$message}</title>
|
||||
<link>{$url}</link>
|
||||
<description>{$message}</description>
|
||||
<pubDate>{$now}</pubDate>
|
||||
</channel>
|
||||
</rss>
|
||||
XML,
|
||||
403
|
||||
)->header('Content-Type', 'text/xml');
|
||||
}
|
||||
|
||||
auth()->logout();
|
||||
$request->session()->flush();
|
||||
|
||||
|
||||
@@ -88,6 +88,26 @@ class StoreTorrentRequestRequest extends FormRequest
|
||||
$mustBeNull,
|
||||
]),
|
||||
],
|
||||
'season_number' => [
|
||||
Rule::when($category->tv_meta, [
|
||||
'required',
|
||||
'integer',
|
||||
'min:0',
|
||||
]),
|
||||
Rule::when(!$category->tv_meta, [
|
||||
$mustBeNull,
|
||||
]),
|
||||
],
|
||||
'episode_number' => [
|
||||
Rule::when($category->tv_meta, [
|
||||
'required',
|
||||
'integer',
|
||||
'min:0',
|
||||
]),
|
||||
Rule::when(!$category->tv_meta, [
|
||||
$mustBeNull,
|
||||
]),
|
||||
],
|
||||
'tmdb_movie_id' => [
|
||||
Rule::when($category->movie_meta, [
|
||||
'required_with:movie_exists_on_tmdb',
|
||||
|
||||
@@ -88,6 +88,26 @@ class UpdateTorrentRequestRequest extends FormRequest
|
||||
$mustBeNull,
|
||||
]),
|
||||
],
|
||||
'season_number' => [
|
||||
Rule::when($category->tv_meta, [
|
||||
'required',
|
||||
'integer',
|
||||
'min:0',
|
||||
]),
|
||||
Rule::when(!$category->tv_meta, [
|
||||
$mustBeNull,
|
||||
]),
|
||||
],
|
||||
'episode_number' => [
|
||||
Rule::when($category->tv_meta, [
|
||||
'required',
|
||||
'integer',
|
||||
'min:0',
|
||||
]),
|
||||
Rule::when(!$category->tv_meta, [
|
||||
$mustBeNull,
|
||||
]),
|
||||
],
|
||||
'tmdb_movie_id' => [
|
||||
Rule::when($category->movie_meta, [
|
||||
'required_with:movie_exists_on_tmdb',
|
||||
|
||||
@@ -16,8 +16,8 @@ declare(strict_types=1);
|
||||
|
||||
namespace App\Http\Resources;
|
||||
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Http\Resources\Json\JsonResource;
|
||||
use JsonSerializable;
|
||||
|
||||
/**
|
||||
* @mixin \App\Models\Bot
|
||||
@@ -26,9 +26,41 @@ class BotResource extends JsonResource
|
||||
{
|
||||
/**
|
||||
* Transform the resource into an array.
|
||||
*
|
||||
* @return array{
|
||||
* id: int,
|
||||
* position: int,
|
||||
* name: string,
|
||||
* command: string,
|
||||
* color: string|null,
|
||||
* icon: string|null,
|
||||
* emoji: string|null,
|
||||
* help: string|null,
|
||||
* active: bool,
|
||||
* is_protected: bool,
|
||||
* is_nerdbot: bool,
|
||||
* is_systembot: bool,
|
||||
* created_at: \Illuminate\Support\Carbon|null,
|
||||
* updated_at: \Illuminate\Support\Carbon|null,
|
||||
* }
|
||||
*/
|
||||
public function toArray($request): array|\Illuminate\Contracts\Support\Arrayable|JsonSerializable
|
||||
public function toArray(Request $request): array
|
||||
{
|
||||
return parent::toArray($request);
|
||||
return [
|
||||
'id' => $this->id,
|
||||
'position' => $this->position,
|
||||
'name' => $this->name,
|
||||
'command' => $this->command,
|
||||
'color' => $this->color,
|
||||
'icon' => $this->icon,
|
||||
'emoji' => $this->emoji,
|
||||
'help' => $this->help,
|
||||
'active' => $this->active,
|
||||
'is_protected' => $this->is_protected,
|
||||
'is_nerdbot' => $this->is_nerdbot,
|
||||
'is_systembot' => $this->is_systembot,
|
||||
'created_at' => $this->created_at,
|
||||
'updated_at' => $this->updated_at,
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
@@ -18,6 +18,7 @@ namespace App\Http\Resources;
|
||||
|
||||
use App\Helpers\Bbcode;
|
||||
use hdvinnie\LaravelJoyPixels\LaravelJoyPixels;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Http\Resources\Json\JsonResource;
|
||||
|
||||
/**
|
||||
@@ -29,8 +30,19 @@ class ChatMessageResource extends JsonResource
|
||||
* Transform the resource into an array.
|
||||
*
|
||||
* @throws \Illuminate\Contracts\Container\BindingResolutionException
|
||||
*
|
||||
* @return array{
|
||||
* id: int,
|
||||
* bot: BotResource,
|
||||
* user: ChatUserResource,
|
||||
* receiver: ChatUserResource,
|
||||
* chatroom: ChatRoomResource,
|
||||
* message: string,
|
||||
* created_at: string,
|
||||
* updated_at: string,
|
||||
* }
|
||||
*/
|
||||
public function toArray($request): array
|
||||
public function toArray(Request $request): array
|
||||
{
|
||||
$emojiOne = new LaravelJoyPixels();
|
||||
|
||||
|
||||
@@ -16,6 +16,7 @@ declare(strict_types=1);
|
||||
|
||||
namespace App\Http\Resources;
|
||||
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Http\Resources\Json\JsonResource;
|
||||
|
||||
/**
|
||||
@@ -25,8 +26,17 @@ class ChatRoomResource extends JsonResource
|
||||
{
|
||||
/**
|
||||
* Transform the resource into an array.
|
||||
*
|
||||
* @return array{
|
||||
* id: int,
|
||||
* name: string,
|
||||
* users: \Illuminate\Http\Resources\Json\AnonymousResourceCollection,
|
||||
* messages: \Illuminate\Http\Resources\Json\AnonymousResourceCollection,
|
||||
* created_at: string,
|
||||
* updated_at: string,
|
||||
* }
|
||||
*/
|
||||
public function toArray($request): array
|
||||
public function toArray(Request $request): array
|
||||
{
|
||||
return [
|
||||
'id' => $this->id,
|
||||
|
||||
@@ -16,6 +16,7 @@ declare(strict_types=1);
|
||||
|
||||
namespace App\Http\Resources;
|
||||
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Http\Resources\Json\JsonResource;
|
||||
|
||||
/**
|
||||
@@ -25,8 +26,24 @@ class ChatUserResource extends JsonResource
|
||||
{
|
||||
/**
|
||||
* Transform the resource into an array.
|
||||
*
|
||||
* @return array{
|
||||
* id: int,
|
||||
* username: string,
|
||||
* chat_status: mixed,
|
||||
* chat_status_id: int,
|
||||
* chatroom_id: int,
|
||||
* group: mixed,
|
||||
* echoes: mixed,
|
||||
* group_id: int,
|
||||
* title: string,
|
||||
* image: string,
|
||||
* is_lifetime: bool,
|
||||
* is_donor: bool,
|
||||
* icon: string,
|
||||
* }
|
||||
*/
|
||||
public function toArray($request): array
|
||||
public function toArray(Request $request): array
|
||||
{
|
||||
return [
|
||||
'id' => $this->id,
|
||||
|
||||
59
app/Http/Resources/TorrentRequestResource.php
Normal file
59
app/Http/Resources/TorrentRequestResource.php
Normal file
@@ -0,0 +1,59 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
/**
|
||||
* NOTICE OF LICENSE.
|
||||
*
|
||||
* UNIT3D Community Edition is open-sourced software licensed under the GNU Affero General Public License v3.0
|
||||
* The details is bundled with this project in the file LICENSE.txt.
|
||||
*
|
||||
* @project UNIT3D Community Edition
|
||||
*
|
||||
* @author HDVinnie <hdinnovations@protonmail.com>
|
||||
* @license https://www.gnu.org/licenses/agpl-3.0.en.html/ GNU Affero General Public License v3.0
|
||||
*/
|
||||
|
||||
namespace App\Http\Resources;
|
||||
|
||||
use Illuminate\Http\Resources\Json\JsonResource;
|
||||
use Illuminate\Http\Request;
|
||||
|
||||
/**
|
||||
* @mixin \App\Models\TorrentRequest
|
||||
*/
|
||||
class TorrentRequestResource extends JsonResource
|
||||
{
|
||||
/**
|
||||
* Transform the resource into an array.
|
||||
*
|
||||
* @param Request $request
|
||||
* @return array<string, mixed>
|
||||
*/
|
||||
public function toArray(Request $request): array
|
||||
{
|
||||
return [
|
||||
'id' => $this->id,
|
||||
'name' => $this->name,
|
||||
'description' => $this->description,
|
||||
'category_id' => $this->category_id,
|
||||
'type_id' => $this->type_id,
|
||||
'resolution_id' => $this->whenNotNull($this->resolution_id),
|
||||
'user' => $this->anon ? 'anonymous' : $this->user->username,
|
||||
'tmdb' => $this->tmdb_movie_id ?: $this->tmdb_tv_id,
|
||||
'imdb' => $this->imdb,
|
||||
'tvdb' => $this->tvdb,
|
||||
'mal' => $this->mal,
|
||||
'igdb' => $this->igdb,
|
||||
'season_number' => $this->whenNotNull($this->season_number),
|
||||
'episode_number' => $this->whenNotNull($this->episode_number),
|
||||
'bounty' => $this->whenAggregated('bounties', 'seedbonus', 'sum'),
|
||||
'status' => $this->filled_by !== null ? ($this->approved_by !== null ? 'filled' : 'pending') : ($this->claim ? 'claimed' : 'unfilled'),
|
||||
'claimed' => $this->claim !== null,
|
||||
'claimed_by' => $this->when($this->claim !== null, $this->claim?->anon ? 'anonymous' : ($this->claim?->user?->username ?? null)),
|
||||
'filled_by' => $this->when($this->filled_by !== null, $this->filled_anon ? 'anonymous' : ($this->filler?->username ?? null)),
|
||||
'created' => $this->created_at->toIso8601String(),
|
||||
'updated_at' => $this->updated_at->toIso8601String(),
|
||||
];
|
||||
}
|
||||
}
|
||||
@@ -17,17 +17,76 @@ declare(strict_types=1);
|
||||
namespace App\Http\Resources;
|
||||
|
||||
use App\Enums\AuthGuard;
|
||||
use Illuminate\Http\JsonResponse;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Http\Resources\Json\JsonResource;
|
||||
|
||||
/**
|
||||
* @mixin \App\Models\Torrent
|
||||
* @property \App\Models\TmdbMovie|\App\Models\TmdbTv|\App\Models\IgdbGame $meta
|
||||
*/
|
||||
class TorrentResource extends JsonResource
|
||||
{
|
||||
/**
|
||||
* Transform the resource into an array.
|
||||
*
|
||||
* @return array{
|
||||
* type: 'torrent',
|
||||
* id: string,
|
||||
* attributes: array{
|
||||
* meta: array{
|
||||
* poster: string,
|
||||
* genres: string,
|
||||
* },
|
||||
* name: string,
|
||||
* release_year: string|null,
|
||||
* category: string,
|
||||
* type: string,
|
||||
* resolution: string,
|
||||
* distributor: string,
|
||||
* region: string,
|
||||
* media_info: string,
|
||||
* bd_info: string,
|
||||
* description: string,
|
||||
* size: float,
|
||||
* folder: string|null,
|
||||
* num_file: int,
|
||||
* files: \Illuminate\Support\Collection<
|
||||
* int,
|
||||
* array{
|
||||
* index: int,
|
||||
* name: string,
|
||||
* size: int,
|
||||
* },
|
||||
* >,
|
||||
* freeleech: string,
|
||||
* double_upload: bool,
|
||||
* refundable: bool,
|
||||
* internal: int,
|
||||
* featured: \Illuminate\Http\Resources\MissingValue|mixed,
|
||||
* personal_release: bool,
|
||||
* uploader: string,
|
||||
* seeders: int,
|
||||
* leechers: int,
|
||||
* times_completed: int,
|
||||
* tmdb_id: int|null,
|
||||
* imdb_id: int,
|
||||
* tvdb_id: int,
|
||||
* mal_id: int,
|
||||
* igdb_id: int,
|
||||
* category_id: int|null,
|
||||
* type_id: int,
|
||||
* resolution_id: \Illuminate\Http\Resources\MissingValue|mixed,
|
||||
* distributor_id: \Illuminate\Http\Resources\MissingValue|mixed,
|
||||
* region_id: \Illuminate\Http\Resources\MissingValue|mixed,
|
||||
* created_at: \Illuminate\Support\Carbon|null,
|
||||
* download_link: string,
|
||||
* magnet_link: \Illuminate\Http\Resources\MissingValue|mixed,
|
||||
* details_link: string,
|
||||
* }
|
||||
* }
|
||||
*/
|
||||
public function toArray($request): array
|
||||
public function toArray(Request $request): array
|
||||
{
|
||||
return [
|
||||
'type' => 'torrent',
|
||||
@@ -47,7 +106,6 @@ class TorrentResource extends JsonResource
|
||||
'media_info' => $this->mediainfo,
|
||||
'bd_info' => $this->bdinfo,
|
||||
'description' => $this->description,
|
||||
'info_hash' => bin2hex($this->info_hash),
|
||||
'size' => $this->size,
|
||||
'folder' => $this->folder,
|
||||
'num_file' => $this->num_file,
|
||||
@@ -87,7 +145,7 @@ class TorrentResource extends JsonResource
|
||||
/**
|
||||
* Customize the outgoing response for the resource.
|
||||
*/
|
||||
public function withResponse($request, $response): void
|
||||
public function withResponse(Request $request, JsonResponse $response): void
|
||||
{
|
||||
$response->setEncodingOptions(JSON_UNESCAPED_SLASHES | JSON_PRETTY_PRINT);
|
||||
}
|
||||
|
||||
@@ -16,14 +16,20 @@ declare(strict_types=1);
|
||||
|
||||
namespace App\Http\Resources;
|
||||
|
||||
use Illuminate\Http\JsonResponse;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Http\Resources\Json\ResourceCollection;
|
||||
|
||||
class TorrentsResource extends ResourceCollection
|
||||
{
|
||||
/**
|
||||
* Transform the resource collection into an array.
|
||||
*
|
||||
* @return array{
|
||||
* data: \Illuminate\Http\Resources\Json\AnonymousResourceCollection,
|
||||
* }
|
||||
*/
|
||||
public function toArray($request): array
|
||||
public function toArray(Request $request): array
|
||||
{
|
||||
return [
|
||||
'data' => TorrentResource::collection($this->collection),
|
||||
@@ -32,8 +38,14 @@ class TorrentsResource extends ResourceCollection
|
||||
|
||||
/**
|
||||
* Get additional data that should be returned with the resource array.
|
||||
*
|
||||
* @return array{
|
||||
* links: array{
|
||||
* self: string,
|
||||
* }
|
||||
* }
|
||||
*/
|
||||
public function with($request): array
|
||||
public function with(Request $request): array
|
||||
{
|
||||
return [
|
||||
'links' => [
|
||||
@@ -45,7 +57,7 @@ class TorrentsResource extends ResourceCollection
|
||||
/**
|
||||
* Customize the outgoing response for the resource.
|
||||
*/
|
||||
public function withResponse($request, $response): void
|
||||
public function withResponse(Request $request, JsonResponse $response): void
|
||||
{
|
||||
$response->setEncodingOptions(JSON_UNESCAPED_SLASHES | JSON_PRETTY_PRINT);
|
||||
}
|
||||
|
||||
@@ -16,6 +16,7 @@ declare(strict_types=1);
|
||||
|
||||
namespace App\Http\Resources;
|
||||
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Http\Resources\Json\JsonResource;
|
||||
|
||||
/**
|
||||
@@ -25,8 +26,18 @@ class UserAudibleResource extends JsonResource
|
||||
{
|
||||
/**
|
||||
* Transform the resource into an array.
|
||||
*
|
||||
* @return array{
|
||||
* id: int,
|
||||
* user_id: int,
|
||||
* user: ChatUserResource,
|
||||
* target: ChatUserResource,
|
||||
* room: \App\Models\Chatroom|null,
|
||||
* bot: \App\Models\Bot|null,
|
||||
* status: int,
|
||||
* }
|
||||
*/
|
||||
public function toArray($request): array
|
||||
public function toArray(Request $request): array
|
||||
{
|
||||
return [
|
||||
'id' => $this->id,
|
||||
|
||||
@@ -16,6 +16,7 @@ declare(strict_types=1);
|
||||
|
||||
namespace App\Http\Resources;
|
||||
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Http\Resources\Json\JsonResource;
|
||||
|
||||
/**
|
||||
@@ -25,8 +26,17 @@ class UserEchoResource extends JsonResource
|
||||
{
|
||||
/**
|
||||
* Transform the resource into an array.
|
||||
*
|
||||
* @return array{
|
||||
* id: int,
|
||||
* user_id: int,
|
||||
* user: ChatUserResource,
|
||||
* target: ChatUserResource,
|
||||
* room: \App\Models\Chatroom,
|
||||
* bot: \App\Models\Bot,
|
||||
* }
|
||||
*/
|
||||
public function toArray($request): array
|
||||
public function toArray(Request $request): array
|
||||
{
|
||||
return [
|
||||
'id' => $this->id,
|
||||
|
||||
@@ -16,6 +16,7 @@ declare(strict_types=1);
|
||||
|
||||
namespace App\Http\Resources;
|
||||
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Http\Resources\Json\JsonResource;
|
||||
|
||||
/**
|
||||
@@ -25,8 +26,21 @@ class UserResource extends JsonResource
|
||||
{
|
||||
/**
|
||||
* Transform the resource into an array.
|
||||
*
|
||||
* @return array{
|
||||
* username: string,
|
||||
* group: string,
|
||||
* uploaded: string,
|
||||
* downloaded: string,
|
||||
* ratio: string,
|
||||
* buffer: string,
|
||||
* seeding: int,
|
||||
* leeching: int,
|
||||
* seedbonus: string,
|
||||
* hit_and_runs: int,
|
||||
* }
|
||||
*/
|
||||
public function toArray($request): array
|
||||
public function toArray(Request $request): array
|
||||
{
|
||||
return [
|
||||
'username' => $this->username,
|
||||
|
||||
@@ -23,17 +23,17 @@ use Illuminate\Database\Eloquent\Model;
|
||||
/**
|
||||
* App\Models\Donation.
|
||||
*
|
||||
* @property int $id
|
||||
* @property int $user_id
|
||||
* @property int $gifted_user_id
|
||||
* @property ModerationStatus $status
|
||||
* @property int $package_id
|
||||
* @property string $transaction
|
||||
* @property bool $is_gifted
|
||||
* @property \Illuminate\Support\Carbon $starts_at
|
||||
* @property \Illuminate\Support\Carbon $ends_at
|
||||
* @property \Illuminate\Support\Carbon $created_at
|
||||
* @property \Illuminate\Support\Carbon $updated_at
|
||||
* @property int $id
|
||||
* @property int $user_id
|
||||
* @property int $gifted_user_id
|
||||
* @property ModerationStatus $status
|
||||
* @property int $package_id
|
||||
* @property string $transaction
|
||||
* @property bool $is_gifted
|
||||
* @property \Illuminate\Support\Carbon|null $starts_at
|
||||
* @property \Illuminate\Support\Carbon|null $ends_at
|
||||
* @property \Illuminate\Support\Carbon|null $created_at
|
||||
* @property \Illuminate\Support\Carbon|null $updated_at
|
||||
*/
|
||||
class Donation extends Model
|
||||
{
|
||||
|
||||
@@ -46,6 +46,8 @@ use Illuminate\Database\Eloquent\Model;
|
||||
* @property \Illuminate\Support\Carbon|null $approved_when
|
||||
* @property int|null $type_id
|
||||
* @property int|null $resolution_id
|
||||
* @property int|null $season_number
|
||||
* @property int|null $episode_number
|
||||
*/
|
||||
class TorrentRequest extends Model
|
||||
{
|
||||
|
||||
63
app/Models/TorrentReseed.php
Normal file
63
app/Models/TorrentReseed.php
Normal file
@@ -0,0 +1,63 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
/**
|
||||
* NOTICE OF LICENSE.
|
||||
*
|
||||
* UNIT3D Community Edition is open-sourced software licensed under the GNU Affero General Public License v3.0
|
||||
* The details is bundled with this project in the file LICENSE.txt.
|
||||
*
|
||||
* @project UNIT3D Community Edition
|
||||
*
|
||||
* @author HDVinnie <hdinnovations@protonmail.com>
|
||||
* @license https://www.gnu.org/licenses/agpl-3.0.en.html/ GNU Affero General Public License v3.0
|
||||
*/
|
||||
|
||||
namespace App\Models;
|
||||
|
||||
use App\Traits\Auditable;
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
|
||||
/**
|
||||
* App\Models\TorrentReseed.
|
||||
*
|
||||
* @property int $id
|
||||
* @property int $torrent_id
|
||||
* @property int $user_id
|
||||
* @property \Illuminate\Support\Carbon|null $created_at
|
||||
* @property \Illuminate\Support\Carbon|null $updated_at
|
||||
* @property-read Torrent $torrent
|
||||
* @property-read User $user
|
||||
*/
|
||||
class TorrentReseed extends Model
|
||||
{
|
||||
use Auditable;
|
||||
|
||||
/**
|
||||
* The attributes that aren't mass assignable.
|
||||
*
|
||||
* @var string[]
|
||||
*/
|
||||
protected $guarded = ['id', 'created_at', 'updated_at'];
|
||||
|
||||
/**
|
||||
* Belongs To A Torrent.
|
||||
*
|
||||
* @return \Illuminate\Database\Eloquent\Relations\BelongsTo<Torrent, $this>
|
||||
*/
|
||||
public function torrent(): \Illuminate\Database\Eloquent\Relations\BelongsTo
|
||||
{
|
||||
return $this->belongsTo(Torrent::class);
|
||||
}
|
||||
|
||||
/**
|
||||
* Belongs To A User.
|
||||
*
|
||||
* @return \Illuminate\Database\Eloquent\Relations\BelongsTo<User, $this>
|
||||
*/
|
||||
public function user(): \Illuminate\Database\Eloquent\Relations\BelongsTo
|
||||
{
|
||||
return $this->belongsTo(User::class);
|
||||
}
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user