Merge pull request #2255 from Roardom/add-user-uploads

(Refactor) split user torrents into history and uploads
This commit is contained in:
HDVinnie
2022-06-03 20:21:00 -04:00
committed by GitHub
11 changed files with 485 additions and 66 deletions

View File

@@ -1239,6 +1239,29 @@ class UserController extends Controller
]);
}
/**
* Get A Users Uploads Table.
*/
public function uploads(Request $request, string $username): \Illuminate\Contracts\View\Factory|\Illuminate\View\View
{
$user = User::where('username', '=', $username)->firstOrFail();
\abort_unless($request->user()->group->is_modo || $request->user()->id == $user->id, 403);
$hisUpl = History::where('user_id', '=', $user->id)->sum('actual_uploaded');
$hisUplCre = History::where('user_id', '=', $user->id)->sum('uploaded');
$hisDownl = History::where('user_id', '=', $user->id)->sum('actual_downloaded');
$hisDownlCre = History::where('user_id', '=', $user->id)->sum('downloaded');
return \view('user.private.uploads', [
'route' => 'uploads',
'user' => $user,
'his_upl' => $hisUpl,
'his_upl_cre' => $hisUplCre,
'his_downl' => $hisDownl,
'his_downl_cre' => $hisDownlCre,
]);
}
/**
* Get A Users Graveyard Resurrections.
*/

View File

@@ -44,16 +44,12 @@ class UserTorrents extends Component
public string $downloaded = 'any';
public string $hasHistory = 'any';
public array $status = [];
public string $sortField = 'created_at';
public string $sortDirection = 'desc';
public $unapprovedOnTop = true;
public $showMorePrecision = false;
protected $queryString = [
@@ -69,9 +65,7 @@ class UserTorrents extends Component
'immune' => ['except' => 'any'],
'uploaded' => ['except' => 'any'],
'downloaded' => ['except' => 'any'],
'hasHistory' => ['except' => 'any'],
'status' => ['except' => []],
'unapprovedOnTop' => ['except' => true],
'showMorePrecision' => ['except' => false],
];
@@ -97,8 +91,14 @@ class UserTorrents extends Component
final public function getHistoryProperty(): \Illuminate\Contracts\Pagination\LengthAwarePaginator
{
return History::rightJoin('torrents', 'history.torrent_id', '=', 'torrents.id')
return History::query()
->join('torrents', fn ($join) => $join
->on('history.torrent_id', '=', 'torrents.id')
->where('history.created_at', '>=', $this->user->created_at) // Unneeded, but increases performance
->where('history.user_id', '=', $this->user->id)
)
->select(
'history.torrent_id',
'history.agent',
'history.uploaded',
'history.downloaded',
@@ -112,7 +112,6 @@ class UserTorrents extends Component
'history.immune',
'history.hitrun',
'history.prewarn',
'torrents.id',
'torrents.name',
'torrents.seeders',
'torrents.leechers',
@@ -121,24 +120,12 @@ class UserTorrents extends Component
'torrents.user_id',
'torrents.status',
)
->when(
$this->uploaded === 'include',
fn ($query) => $query->selectRaw('COALESCE(history.created_at, NOW()) as created_at'),
fn ($query) => $query->selectRaw('COALESCE(history.created_at, torrents.created_at) as created_at')
)
->selectRaw('IF(torrents.user_id = ?, 1, 0) AS uploader', [$this->user->id])
->selectRaw('history.active AND history.seeder AS seeding')
->selectRaw('history.active AND NOT history.seeder AS leeching')
->selectRaw('TIMESTAMPDIFF(SECOND, history.created_at, history.completed_at) AS leechtime')
->selectRaw('CAST(history.uploaded AS float) / CAST((history.downloaded + 1) AS float) AS ratio')
->selectRaw('CAST(history.actual_uploaded AS float) / CAST((history.actual_downloaded + 1) AS float) AS actual_ratio')
->where(fn ($query) => $query
->where('history.user_id', '=', $this->user->id)
->orWhere(fn ($query) => $query
->where('torrents.user_id', '=', $this->user->id)
->whereNull('history.user_id')
)
)
->when($this->name, fn ($query) => $query
->where('name', 'like', '%'.str_replace(' ', '%', $this->name).'%')
)
@@ -166,14 +153,11 @@ class UserTorrents extends Component
->when($this->hitrun === 'exclude', fn ($query) => $query->where(fn ($query) => $query->where('hitrun', '=', 0)->orWhereNull('hitrun')))
->when($this->immune === 'include', fn ($query) => $query->where('immune', '=', 1))
->when($this->immune === 'exclude', fn ($query) => $query->where(fn ($query) => $query->where('immune', '=', 0)->orWhereNull('immune')))
->when($this->hasHistory === 'include', fn ($query) => $query->whereNotNull('history.updated_at'))
->when($this->hasHistory === 'exclude', fn ($query) => $query->whereNull('history.updated_at'))
->when($this->uploaded === 'include', fn ($query) => $query->where('torrents.user_id', '=', $this->user->id))
->when($this->uploaded === 'exclude', fn ($query) => $query->where('torrents.user_id', '<>', $this->user->id))
->when($this->downloaded === 'include', fn ($query) => $query->where('history.actual_downloaded', '>', 0))
->when($this->downloaded === 'exclude', fn ($query) => $query->where('history.actual_downloaded', '=', 0))
->when(! empty($this->status), fn ($query) => $query->whereIntegerInRaw('status', $this->status))
->when($this->unapprovedOnTop, fn ($query) => $query->orderByRaw('IF(status = 1, 1, 0)'))
->orderBy($this->sortField, $this->sortDirection)
->paginate($this->perPage);
}

View File

@@ -0,0 +1,104 @@
<?php
/**
* 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\Torrent;
use App\Models\User;
use Livewire\Component;
use Livewire\WithPagination;
class UserUploads extends Component
{
use WithPagination;
public ?\Illuminate\Contracts\Auth\Authenticatable $user = null;
public int $perPage = 25;
public string $name = '';
public string $personalRelease = 'any';
public array $status = [];
public string $sortField = 'created_at';
public string $sortDirection = 'desc';
public $showMorePrecision = false;
protected $queryString = [
'perPage' => ['except' => ''],
'name' => ['except' => ''],
'personalRelease' => ['except' => 'any'],
'sortField' => ['except' => 'created_at'],
'sortDirection' => ['except' => 'desc'],
'status' => ['except' => []],
];
final public function mount($userId): void
{
$this->user = User::find($userId);
}
final public function paginationView(): string
{
return 'vendor.pagination.livewire-pagination';
}
final public function updatedPage(): void
{
$this->emit('paginationChanged');
}
final public function updatingSearch(): void
{
$this->resetPage();
}
final public function getUploadsProperty(): \Illuminate\Contracts\Pagination\LengthAwarePaginator
{
return Torrent::query()
->withCount('thanks')
->withSum('tips', 'cost')
->where('created_at', '>=', $this->user->created_at) // Unneeded, but increases performances
->where('user_id', '=', $this->user->id)
->when($this->name, fn ($query) => $query
->where('name', 'like', '%'.str_replace(' ', '%', $this->name).'%')
)
->when(! empty($this->status), fn ($query) => $query->whereIntegerInRaw('status', $this->status))
->when($this->personalRelease === 'include', fn ($query) => $query->where('personal_release', '=', 1))
->when($this->personalRelease === 'exclude', fn ($query) => $query->where('personal_release', '=', 0))
->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-uploads', [
'uploads' => $this->uploads,
]);
}
final public function sortBy($field): void
{
if ($this->sortField === $field) {
$this->sortDirection = $this->sortDirection === 'asc' ? 'desc' : 'asc';
} else {
$this->sortDirection = 'asc';
}
$this->sortField = $field;
}
}

View File

@@ -19,6 +19,7 @@
@import 'components/quick_search';
@import 'components/user-active';
@import 'components/user-torrents';
@import 'components/user-uploads';
@import 'layout/header';
@import 'layout/secondary-nav';
@import 'layout/top_nav';

View File

@@ -0,0 +1,61 @@
.user-uploads__name-header,
.user-uploads__size-header,
.user-uploads__seeders-header,
.user-uploads__leechers-header,
.user-uploads__times-header,
.user-uploads__tips-header,
.user-uploads__thanks-header,
.user-uploads__created-at-header,
.user-uploads__personal-release-header,
.user-uploads__status-header {
cursor: pointer;
white-space: nowrap;
font-size: 11px;
}
.user-uploads__name,
.user-uploads__size,
.user-uploads__seeders,
.user-uploads__leechers,
.user-uploads__times,
.user-uploads__tips,
.user-uploads__thanks,
.user-uploads__created-at {
font-size: 14px;
}
.user-uploads__personal-release,
.user-uploads__status {
font-size: 11px;
}
.user-uploads__size-header,
.user-uploads__seeders-header,
.user-uploads__leechers-header,
.user-uploads__times-header,
.user-uploads__size,
.user-uploads__seeders,
.user-uploads__leechers,
.user-uploads__times {
text-align: right;
}
.user-uploads__personal-release-header,
.user-uploads__status-header,
.user-uploads__persona-release,
.user-uploads__status {
text-align: center;
}
.user-uploads__name {
font-weight: bolder;
color: var(--text-color);
}
.user-uploads__checkbox {
all: revert !important;
}
.user-uploads__checkbox:indeterminate {
all: revert !important;
}

View File

@@ -108,18 +108,6 @@
{{ __('torrent.downloaded') }}
</label>
</span>
<span class="badge-user">
<label style="user-select: none" class="inline" x-data="{ state: @entangle('hasHistory'), ...ternaryCheckbox() }">
<input
type="checkbox"
class="user-torrents__checkbox"
x-init="updateTernaryCheckboxProperties($el, state)"
x-on:click="state = getNextTernaryCheckboxState(state); updateTernaryCheckboxProperties($el, state)"
x-bind:checked="state === 'include'"
>
Has history
</label>
</span>
</div>
</div>
<div class="mx-0 mt-5 form-group fatten-me">
@@ -162,12 +150,6 @@
Show more precision
</label>
</span>
<span class="badge-user">
<label class="inline">
<input type="checkbox" class="user-torrents__checkbox" wire:model="unapprovedOnTop">
Unapproved on top
</label>
</span>
</div>
</div>
</div>
@@ -259,26 +241,26 @@
@foreach ($histories as $history)
<tr>
<td>
<a class="user-torrents__name" href="{{ route('torrent', ['id' => $history->id]) }}">
<a class="user-torrents__name" href="{{ route('torrent', ['id' => $history->torrent_id]) }}">
{{ $history->name }}
</a>
</td>
<td class="user-torrents__seeders">
<a href="{{ route('peers', ['id' => $history->id]) }}">
<a href="{{ route('peers', ['id' => $history->torrent_id]) }}">
<span class='text-green'>
{{ $history->seeders }}
</span>
</a>
</td>
<td class="user-torrents__leechers">
<a href="{{ route('peers', ['id' => $history->id]) }}">
<a href="{{ route('peers', ['id' => $history->torrent_id]) }}">
<span class='text-red'>
{{ $history->leechers }}
</span>
</a>
</td>
<td class="user-torrents__times">
<a href="{{ route('history', ['id' => $history->id]) }}">
<a href="{{ route('history', ['id' => $history->torrent_id]) }}">
<span class='text-orange'>
{{ $history->times_completed }}
</span>
@@ -343,26 +325,36 @@
</td>
@if ($showMorePrecision)
<td class="user-torrents__leechtime">
@if ($history->actual_uploaded === null)
@if ($history->leechtime === null)
N/A
@else
{{ App\Helpers\StringHelper::timeElapsed($history->leechtime) }}
@endif
</td>
<td class="user-torrents__seedtime">
<span class="{{ $history->seedtime < config('hitrun.seedtime') ? 'text-red' : 'text-green' }}">
{{ App\Helpers\StringHelper::timeElapsed($history->seedtime) }}
<span class="{{ ($history->seedtime ?? 0) < config('hitrun.seedtime') ? 'text-red' : 'text-green' }}">
@if ($history->seedtime === null)
N/A
@else
{{ App\Helpers\StringHelper::timeElapsed($history->seedtime) }}
@endif
</span>
</td>
<td class="user-torrents__created-at">
@if ($history->updated_at === null)
<em title="Uploaded date">{{ $history->created_at ?? 'N/A' }}</em>
@else
<time datetime="{{ $history->created_at ?? 0}}">
{{ $history->created_at ?? 'N/A' }}
@endif
</time>
</td>
<td class="user-torrents__updated-at">
<time datetime="{{ $history->updated_at ?? 0}}">
{{ $history->updated_at ?? 'N/A' }}
</time>
</td>
<td class="user-torrents__completed-at">
<time datetime="{{ $history->completed_at ?? 0}}">
{{ $history->completed_at ?? 'N/A' }}
</time>
</td>
<td class="user-torrents__updated-at">{{ $history->updated_at ?? 'N/A' }}</td>
<td class="user-torrents__complated-at">{{ $history->completed_at ?? 'N/A' }}</td>
@else
<td class="user-torrents__leechtime">
@if ($history->leechtime === null)
@@ -381,13 +373,7 @@
@endif
</td>
<td class="user-torrents__created-at">
@if ($history->updated_at === null)
<em title="Uploaded date">
{{ $history->created_at === null ? 'N/A' : \explode(" ", $history->created_at)[0] }}
</em>
@else
{{ $history->created_at === null ? 'N/A' : \explode(" ", $history->created_at)[0] }}
@endif
{{ $history->created_at === null ? 'N/A' : \explode(" ", $history->created_at)[0] }}
</td>
<td class="user-torrents__updated-at">
{{ $history->updated_at === null ? 'N/A' : \explode(" ", $history->updated_at)[0] }}

View File

@@ -0,0 +1,214 @@
<div>
<div class="container well search mt-5">
<div class="form-horizontal form-condensed form-torrent-search form-bordered">
<div class="mx-0 mt-5 form-group fatten-me">
<label for="name" class="mt-5 col-sm-1 label label-default fatten-me">{{ __('torrent.name') }}</label>
<div class="col-sm-9 fatten-me">
<input type="text" class="form-control" id="name" wire:model="name" placeholder="{{ __('torrent.name') }}">
</div>
</div>
<div class="mx-0 mt-5 form-group fatten-me">
<div class="mt-5 col-sm-1 label label-default fatten-me">
{{ __('torrent.filters') }}
</div>
<div class="col-sm-10">
<span class="badge-user">
<label style="user-select: none" class="inline" x-data="{ state: @entangle('personalRelease'), ...ternaryCheckbox() }">
<input
type="checkbox"
class="user-uploads__checkbox"
x-init="updateTernaryCheckboxProperties($el, state)"
x-on:click="state = getNextTernaryCheckboxState(state); updateTernaryCheckboxProperties($el, state)"
x-bind:checked="state === 'include'"
>
{{ __('torrent.personal-release') }}
</label>
</span>
</div>
</div>
<div class="mx-0 mt-5 form-group fatten-me">
<div class="mt-5 col-sm-1 label label-default fatten-me">
{{ __('torrent.moderation') }}
</div>
<div class="col-sm-10">
<span class="badge-user">
<label class="inline">
<input type="checkbox" class="user-uploads__checkbox" wire:model="status" value="0">
{{ __('torrent.pending') }}
</label>
</span>
<span class="badge-user">
<label class="inline">
<input type="checkbox" class="user-uploads__checkbox" wire:model="status" value="1">
{{ __('torrent.approved') }}
</label>
</span>
<span class="badge-user">
<label class="inline">
<input type="checkbox" class="user-uploads__checkbox" wire:model="status" value="2">
{{ __('torrent.rejected') }}
</label>
</span>
<span class="badge-user">
<label class="inline">
<input type="checkbox" class="user-uploads__checkbox" wire:model="status" value="3">
Postponed
</label>
</span>
</div>
</div>
<div class="mx-0 mt-5 form-group fatten-me">
<div class="mt-5 col-sm-1 label label-default fatten-me">Options</div>
<div class="col-sm-10">
<span class="badge-user">
<label class="inline">
<input type="checkbox" class="user-uploads__checkbox" wire:model="showMorePrecision">
Show more precision
</label>
</span>
</div>
</div>
</div>
</div>
<div>
<div class="table-responsive">
<table class="table table-condensed table-striped table-bordered">
<thead>
<th class="user-uploads__name-header" wire:click="sortBy('name')" role="columnheader button">
{{ __('torrent.name') }}
@include('livewire.includes._sort-icon', ['field' => 'name'])
</th>
<th class="user-uploads__size-header" wire:click="sortBy('size')" role="columnheader button">
{{ __('torrent.size') }}
@include('livewire.includes._sort-icon', ['field' => 'size'])
</th>
<th class="user-uploads__seeders-header" wire:click="sortBy('seeders')" role="columnheader button" title="{{ __('torrent.seeders') }}">
<i class="fas fa-arrow-alt-circle-up"></i>
@include('livewire.includes._sort-icon', ['field' => 'seeders'])
</th>
<th class="user-uploads__leechers-header" wire:click="sortBy('leechers')" role="columnheader button" title="{{ __('torrent.leechers') }}">
<i class="fas fa-arrow-alt-circle-down"></i>
@include('livewire.includes._sort-icon', ['field' => 'leechers'])
</th>
<th class="user-uploads__times-header" wire:click="sortBy('times_completed')" role="columnheader button" title="{{ __('torrent.completed') }}">
<i class="fas fa-check-circle"></i>
@include('livewire.includes._sort-icon', ['field' => 'times_completed'])
</th>
<th class="user-uploads__tips-header" wire:click="sortBy('tips_sum_cost')" role="columnheader button" title="{{ __('bon.tips') }}">
<i class="fas fa-coins"></i>
@include('livewire.includes._sort-icon', ['field' => 'tips_sum_cost'])
</th>
<th class="user-uploads__thanks-header" wire:click="sortBy('thanks_count')" role="columnheader button" title="{{ __('torrent.thanks') }}">
<i class="fas fa-heart"></i>
@include('livewire.includes._sort-icon', ['field' => 'thanks_count'])
</th>
<th class="user-uploads__created-at-header" wire:click="sortBy('created_at')" role="columnheader button">
{{ __('torrent.uploaded') }}
@include('livewire.includes._sort-icon', ['field' => 'created_at'])
</th>
<th class="user-uploads__personal-release-header" wire:click="sortBy('personal_release')" role="columnheader button" title="{{ __('torrent.personal-release') }}">
<i class="fas fa-user-plus"></i>
@include('livewire.includes._sort-icon', ['field' => 'status'])
</th>
<th class="user-uploads__status-header" wire:click="sortBy('status')" role="columnheader button" title="{{ __('torrent.approved') }}">
<i class="fas fa-tasks"></i>
@include('livewire.includes._sort-icon', ['field' => 'status'])
</th>
</thead>
<tbody>
@foreach ($uploads as $torrent)
<tr>
<td>
@if ($torrent->internal)
<i class="{{ config('other.font-awesome') }} fa-magic" style="color: #baaf92;"></i>
@endif
<a class="user-uploads__name" href="{{ route('torrent', ['id' => $torrent->id]) }}">
{{ $torrent->name }}
</a>
</td>
<td class="user-uploads__size">
{{ App\Helpers\StringHelper::formatBytes($torrent->size) }}
</td>
<td class="user-uploads__seeders">
<a href="{{ route('peers', ['id' => $torrent->id]) }}">
<span class='text-green'>
{{ $torrent->seeders }}
</span>
</a>
</td>
<td class="user-uploads__leechers">
<a href="{{ route('peers', ['id' => $torrent->id]) }}">
<span class='text-red'>
{{ $torrent->leechers }}
</span>
</a>
</td>
<td class="user-uploads__times">
<a href="{{ route('history', ['id' => $torrent->id]) }}">
<span class='text-orange'>
{{ $torrent->times_completed }}
</span>
</a>
</td>
<td class="user-uploads__tips">
{{ $torrent->tips_sum_cost ?? 0 }}
</td>
<td class="user-uploads__thanks">
{{ $torrent->thanks_count ?? 0 }}
</td>
<td class="user-uploads__created-at">
<time datetime="{{ $torrent->created_at }}">
@if ($showMorePrecision)
{{ $torrent->created_at ?? 'N/A' }}
@else
{{ $torrent->created_at === null ? 'N/A' : \explode(" ", $torrent->created_at)[0] }}
@endif
</time>
</td>
<td class="user-uploads__personal-release">
@if ($torrent->personal_release === 1)
<i class="{{ config('other.font-awesome') }} fa-check text-green" title="Immune"></i>
@else
<i class="{{ config('other.font-awesome') }} fa-times text-red" title="Not immune"></i>
@endif
</td>
<td class="user-uploads__status">
@switch($torrent->status)
@case(0)
<span title="{{ __('torrent.pending') }}" class="{{ config('other.font-awesome') }} fa-tasks text-orange"></span>
@break
@case(1)
<span title="{{ __('torrent.approved') }}" class="{{ config('other.font-awesome') }} fa-check text-green"></span>
@break
@case(2)
<span title="{{ __('torrent.rejected') }}" class ="{{ config('other.font-awesome') }} fa-times text-red"></span>
@break
@case(3)
<span title="Postponed" class ="{{ config('other.font-awesome') }} fa-hourglass text-red"></span>
@break
@endswitch
</td>
</tr>
@endforeach
</tbody>
</table>
<div class="text-center">
{{ $uploads->links() }}
</div>
</div>
</div>
<script nonce="{{ HDVinnie\SecureHeaders\SecureHeaders::nonce('script') }}">
function ternaryCheckbox() {
return {
updateTernaryCheckboxProperties(el, state) {
el.indeterminate = (state === 'exclude');
el.checked = (state === 'include');
},
getNextTernaryCheckboxState(state) {
return (state === 'include') ? 'exclude' : (state === 'exclude' ? 'any' : 'include');
}
}
}
</script>
</div>

View File

@@ -231,13 +231,13 @@
</ul>
<ul class="top-nav__ratio-bar" x-bind:class="expanded && 'mobile'">
<li class="ratio-bar__uploaded" title="{{ __('common.upload') }}">
<a href="{{ route('user_torrents', ['username' => auth()->user()->username, 'uploaded' => 'include']) }}">
<a href="{{ route('user_uploads', ['username' => auth()->user()->username]) }}">
<i class="{{ config('other.font-awesome') }} fa-arrow-up"></i>
{{ auth()->user()->getUploaded() }}
</a>
</li>
<li class="ratio-bar__downloaded" title="{{ __('common.download') }}">
<a href="{{ route('user_torrents', ['username' => auth()->user()->username, 'uploaded' => 'exclude']) }}">
<a href="{{ route('user_torrents', ['username' => auth()->user()->username, 'downloaded' => 'include']) }}">
<i class="{{ config('other.font-awesome') }} fa-arrow-down"></i>
{{ auth()->user()->getDownloaded() }}
</a>
@@ -391,7 +391,7 @@
</a>
</li>
<li>
<a href="{{ route('user_torrents', ['username' => auth()->user()->username, 'uploaded' => 'include']) }}">
<a href="{{ route('user_uploads', ['username' => auth()->user()->username]) }}">
<i class="{{ config('other.font-awesome') }} fa-upload"></i>
{{ __('user.my-uploads') }}
</a>

View File

@@ -179,7 +179,7 @@
<li class="nav-tab-menu">
@if ($isProfileOwner || $isModo)
<a
class="{{ Route::is('user_torrents', 'user_active', 'user_resurrections', 'user_requested') ? 'nav-tab--active__link' : 'nav-tab__link' }}"
class="{{ Route::is('user_torrents', 'user_uploads', 'user_active', 'user_resurrections', 'user_requested') ? 'nav-tab--active__link' : 'nav-tab__link' }}"
href="{{ route('user_torrents', ['username' => $user->username]) }}"
>
{{ __('torrent.torrents') }}
@@ -200,7 +200,7 @@
</a>
</li>
<li class="nav-tabV2">
<a class="nav-tab__link" href="{{ route('user_torrents', ['username' => $user->username, 'uploaded' => 'include']) }}">
<a class="nav-tab__link" href="{{ route('user_uploads', ['username' => $user->username]) }}">
{{ __('user.uploads') }}
</a>
</li>

View File

@@ -0,0 +1,45 @@
@extends('layout.default')
@section('title')
<title>{{ $user->username }} {{ __('user.uploads') }} - {{ config('other.title') }}</title>
@endsection
@section('breadcrumbs')
<li class="breadcrumbV2">
<a href="{{ route('users.show', ['username' => $user->username]) }}" class="breadcrumb__link">
{{ $user->username }}
</a>
</li>
<li class="breadcrumb--active">
{{ __('user.uploads') }}
</li>
@endsection
@section('nav-tabs')
@include('user.buttons.user')
@endsection
@section('content')
<div class="container-fluid">
<div class="block">
<div class="button-holder some-padding">
<div class="button-left">
</div>
<div class="button-right">
<span class="badge-user"><strong>{{ __('user.total-download') }}:</strong>
<span class="badge-extra text-red">{{ App\Helpers\StringHelper::formatBytes($his_downl, 2) }}</span>
<span class="badge-extra text-orange" data-toggle="tooltip"
data-original-title="{{ __('user.credited-download') }}">{{ App\Helpers\StringHelper::formatBytes($his_downl_cre, 2) }}</span>
</span>
<span class="badge-user"><strong>{{ __('user.total-upload') }}:</strong>
<span class="badge-extra text-green">{{ App\Helpers\StringHelper::formatBytes($his_upl, 2) }}</span>
<span class="badge-extra text-blue" data-toggle="tooltip"
data-original-title="{{ __('user.credited-upload') }}">{{ App\Helpers\StringHelper::formatBytes($his_upl_cre, 2) }}</span>
</span>
</div>
</div>
<hr class="some-padding">
@livewire('user-uploads', ['userId' => $user->id])
</div>
@endsection

View File

@@ -306,6 +306,7 @@ Route::group(['middleware' => 'language'], function () {
Route::get('/{username}/active', [App\Http\Controllers\UserController::class, 'active'])->name('user_active');
Route::get('/{username}/activeByClient/{ip}/{port}', [App\Http\Controllers\UserController::class, 'activeByClient'])->name('user_active_by_client');
Route::get('/{username}/torrents', [App\Http\Controllers\UserController::class, 'torrents'])->name('user_torrents');
Route::get('/{username}/uploads', [App\Http\Controllers\UserController::class, 'uploads'])->name('user_uploads');
Route::get('/{username}/topics', [App\Http\Controllers\UserController::class, 'topics'])->name('user_topics');
Route::get('/{username}/posts', [App\Http\Controllers\UserController::class, 'posts'])->name('user_posts');
Route::get('/{username}/followers', [App\Http\Controllers\UserController::class, 'followers'])->name('user_followers');