mirror of
https://github.com/HDInnovations/UNIT3D-Community-Edition.git
synced 2026-05-04 09:20:21 -05:00
Merge pull request #2401 from HDInnovations/Refund-System
(Add) Refund System
This commit is contained in:
@@ -0,0 +1,73 @@
|
||||
<?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 HDVinnie <hdinnovations@protonmail.com>
|
||||
* @license https://www.gnu.org/licenses/agpl-3.0.en.html/ GNU Affero General Public License v3.0
|
||||
*/
|
||||
|
||||
namespace App\Console\Commands;
|
||||
|
||||
use App\Models\History;
|
||||
use Illuminate\Console\Command;
|
||||
use Illuminate\Support\Carbon;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
|
||||
class AutoRefundDownload extends Command
|
||||
{
|
||||
/**
|
||||
* The name and signature of the console command.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $signature = 'auto:refund_download';
|
||||
|
||||
/**
|
||||
* The console command description.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $description = 'Refunds Download To Users Based On Seed Time.';
|
||||
|
||||
/**
|
||||
* Execute the console command.
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
public function handle()
|
||||
{
|
||||
$now = Carbon::now();
|
||||
$MIN_SEEDTIME = config('hitrun.seedtime');
|
||||
$FULL_REFUND_SEEDTIME = 12 * 30 * 24 * 60 * 60 + $MIN_SEEDTIME;
|
||||
$COMMAND_RUN_PERIOD = 24 * 60 * 60; // This command is run every 24 hours
|
||||
|
||||
History::query()
|
||||
->selectRaw('LEAST(1, history.seedtime / ?) * torrents.size - history.refunded_download as refunded_download_delta', [$FULL_REFUND_SEEDTIME])
|
||||
->join('torrents', 'torrents.id', '=', 'history.torrent_id')
|
||||
->join('users', 'users.id', '=', 'history.user_id')
|
||||
->join('groups', 'groups.id', '=', 'users.group_id')
|
||||
->where('history.active', '=', 1)
|
||||
->where('history.seeder', '=', 1)
|
||||
->where('history.seedtime', '>=', $MIN_SEEDTIME)
|
||||
->where('history.seedtime', '<=', $FULL_REFUND_SEEDTIME + $MIN_SEEDTIME + $COMMAND_RUN_PERIOD)
|
||||
->where('history.created_at', '>=', $now->copy()->subSeconds($MIN_SEEDTIME))
|
||||
->whereColumn('torrents.user_id', '!=', 'history.user_id')
|
||||
->when(! config('other.refundable'), fn ($query) => $query->where(
|
||||
fn ($query) => $query
|
||||
->where('groups.is_refundable', '=', 1)
|
||||
->orWhere('torrents.refundable', '=', 1)
|
||||
))
|
||||
->update([
|
||||
'history.refunded_download' => DB::raw('history.refunded_download + (@delta := LEAST(1, history.seedtime / '.(int) $FULL_REFUND_SEEDTIME.') * torrents.size - history.refunded_download)'),
|
||||
'users.downloaded' => DB::raw('users.downloaded - @delta'),
|
||||
'history.updated_at' => DB::raw('history.updated_at'),
|
||||
]);
|
||||
|
||||
$this->comment('Automated Download Refund Command Complete');
|
||||
}
|
||||
}
|
||||
@@ -46,6 +46,7 @@ class Kernel extends ConsoleKernel
|
||||
$schedule->command('auto:reset_user_flushes')->daily();
|
||||
$schedule->command('auto:stats_clients')->daily();
|
||||
$schedule->command('auto:remove_torrent_buffs')->hourly();
|
||||
$schedule->command('auto:refund_download')->daily();
|
||||
$schedule->command('auto:torrent_balance')->hourly();
|
||||
//$schedule->command('auto:ban_disposable_users')->weekends();
|
||||
//$schedule->command('backup:clean')->daily();
|
||||
|
||||
@@ -262,4 +262,35 @@ class TorrentBuffController extends Controller
|
||||
return to_route('torrent', ['id' => $torrent->id])
|
||||
->withErrors('You Dont Have Enough Freeleech Tokens Or Already Have One Activated On This Torrent.');
|
||||
}
|
||||
|
||||
/**
|
||||
* Set Torrents Refudable Status.
|
||||
*/
|
||||
public function setRefundable(Request $request, $id)
|
||||
{
|
||||
$user = $request->user();
|
||||
abort_unless($user->group->is_modo || $user->group->is_internal, 403);
|
||||
|
||||
$torrent = Torrent::withAnyStatus()->findOrFail($id);
|
||||
$torrent_url = href_torrent($torrent);
|
||||
|
||||
if ($torrent->refundable == 0) {
|
||||
$torrent->refundable = 1;
|
||||
|
||||
$this->chatRepository->systemMessage(
|
||||
sprintf('Ladies and Gents, [url=%s]%s[/url] is now refundable! Grab It While You Can! :fire:', $torrent_url, $torrent->name)
|
||||
);
|
||||
} else {
|
||||
$torrent->refundable = 0;
|
||||
|
||||
$this->chatRepository->systemMessage(
|
||||
sprintf('Ladies and Gents, [url=%s]%s[/url] is no longer refundable! :poop:', $torrent_url, $torrent->name)
|
||||
);
|
||||
}
|
||||
|
||||
$torrent->save();
|
||||
|
||||
return to_route('torrent', ['id' => $torrent->id])
|
||||
->withSuccess('Torrent\'s Refundable Status Has Been Adjusted!');
|
||||
}
|
||||
}
|
||||
|
||||
@@ -515,6 +515,7 @@ class TorrentController extends Controller
|
||||
$torrent->moderated_at = Carbon::now();
|
||||
$torrent->moderated_by = 1; //System ID
|
||||
$torrent->free = $user->group->is_modo || $user->group->is_internal ? $request->input('free') : 0;
|
||||
$torrent->refundable = $user->group->is_modo || $user->group->is_internal ? $request->input('refundable') : 0;
|
||||
|
||||
$resolutionRule = 'nullable|exists:resolutions,id';
|
||||
if ($category->movie_meta || $category->tv_meta) {
|
||||
@@ -557,6 +558,7 @@ class TorrentController extends Controller
|
||||
'stream' => 'required',
|
||||
'sd' => 'required',
|
||||
'free' => 'sometimes|between:0,100',
|
||||
'refundable' => 'sometimes|bool',
|
||||
]);
|
||||
|
||||
if ($v->fails()) {
|
||||
|
||||
@@ -76,6 +76,7 @@ class UserController extends Controller
|
||||
->selectRaw('SUM(uploaded) as credited_upload_sum')
|
||||
->selectRaw('SUM(actual_downloaded) as download_sum')
|
||||
->selectRaw('SUM(downloaded) as credited_download_sum')
|
||||
->selectRaw('SUM(refunded_download) as refunded_download_sum')
|
||||
->selectRaw('SUM(seedtime) as seedtime_sum')
|
||||
->selectRaw('SUM(actual_downloaded > 0) as download_count')
|
||||
->selectRaw('COUNT(*) as count')
|
||||
|
||||
@@ -89,6 +89,16 @@ return [
|
||||
*/
|
||||
'doubleup' => false,
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Refund Torrent Download
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| Global Refund Download
|
||||
|
|
||||
*/
|
||||
'refundable' => false,
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Min Ratio
|
||||
|
||||
@@ -29,6 +29,7 @@ class GroupFactory extends Factory
|
||||
'is_immune' => $this->faker->boolean(),
|
||||
'is_freeleech' => $this->faker->boolean(),
|
||||
'is_double_upload' => $this->faker->boolean(),
|
||||
'is_refundable' => $this->faker->boolean(),
|
||||
'can_upload' => $this->faker->boolean(),
|
||||
'is_incognito' => $this->faker->boolean(),
|
||||
'autogroup' => $this->faker->boolean(),
|
||||
|
||||
@@ -0,0 +1,21 @@
|
||||
<?php
|
||||
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
|
||||
return new class () extends Migration {
|
||||
/**
|
||||
* Run the migrations.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function up(): void
|
||||
{
|
||||
Schema::table('history', function (Blueprint $table): void {
|
||||
$table->unsignedBigInteger('refunded_download')
|
||||
->after('downloaded')
|
||||
->default(0);
|
||||
});
|
||||
}
|
||||
};
|
||||
@@ -0,0 +1,20 @@
|
||||
<?php
|
||||
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
|
||||
return new class () extends Migration {
|
||||
/**
|
||||
* Run the migrations.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function up(): void
|
||||
{
|
||||
Schema::table('torrents', function (Blueprint $table): void {
|
||||
$table->boolean('refundable')->after('doubleup')
|
||||
->default(0);
|
||||
});
|
||||
}
|
||||
};
|
||||
@@ -0,0 +1,19 @@
|
||||
<?php
|
||||
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
|
||||
return new class () extends Migration {
|
||||
/**
|
||||
* Run the migrations.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function up(): void
|
||||
{
|
||||
Schema::table('groups', function (Blueprint $table): void {
|
||||
$table->boolean('is_refundable')->after('is_double_upload')->default(0);
|
||||
});
|
||||
}
|
||||
};
|
||||
@@ -155,6 +155,7 @@ return [
|
||||
'ready' => 'This file is ready for download',
|
||||
'recent-bumped' => 'Recently Bumped',
|
||||
'recommendations' => 'Recommendations',
|
||||
'refundable' => 'Refundable',
|
||||
'rejected' => 'Rejected',
|
||||
'region' => 'Region',
|
||||
'released' => 'Released',
|
||||
|
||||
@@ -206,6 +206,19 @@
|
||||
Double Upload
|
||||
</label>
|
||||
</p>
|
||||
<p class="form__group">
|
||||
<input name="is_refundable" type="hidden" value="0">
|
||||
<input
|
||||
id="is_refundable"
|
||||
class="form__checkbox"
|
||||
name="is_refundable"
|
||||
type="checkbox"
|
||||
value="1"
|
||||
>
|
||||
<label class="form__label" for="is_refundable">
|
||||
Refundable Download
|
||||
</label>
|
||||
</p>
|
||||
<p class="form__group">
|
||||
<input name="is_incognito" type="hidden" value="0">
|
||||
<input
|
||||
|
||||
@@ -223,6 +223,20 @@
|
||||
Double Upload
|
||||
</label>
|
||||
</p>
|
||||
<p class="form__group">
|
||||
<input name="is_refundable" type="hidden" value="0">
|
||||
<input
|
||||
id="is_refundable"
|
||||
class="form__checkbox"
|
||||
name="is_refundable"
|
||||
type="checkbox"
|
||||
value="1"
|
||||
@checked($group->is_refundable)
|
||||
>
|
||||
<label class="form__label" for="is_refundable">
|
||||
Refundable Download
|
||||
</label>
|
||||
</p>
|
||||
<p class="form__group">
|
||||
<input name="is_incognito" type="hidden" value="0">
|
||||
<input
|
||||
|
||||
@@ -46,6 +46,7 @@
|
||||
<th>Immune</th>
|
||||
<th>Freeleech</th>
|
||||
<th>Double Upload</th>
|
||||
<th>Refundable</th>
|
||||
<th>Incognito</th>
|
||||
<th>Upload</th>
|
||||
<th>Autogroup</th>
|
||||
@@ -134,6 +135,13 @@
|
||||
<i class="{{ config('other.font-awesome') }} fa-times text-red"></i>
|
||||
@endif
|
||||
</td>
|
||||
<td>
|
||||
@if ($group->is_refundable)
|
||||
<i class="{{ config('other.font-awesome') }} fa-check text-green"></i>
|
||||
@else
|
||||
<i class="{{ config('other.font-awesome') }} fa-times text-red"></i>
|
||||
@endif
|
||||
</td>
|
||||
<td>
|
||||
@if ($group->is_incognito)
|
||||
<i class="{{ config('other.font-awesome') }} fa-check text-green"></i>
|
||||
|
||||
@@ -49,6 +49,11 @@
|
||||
title="@if(config('other.doubleup')){{ __('torrent.global-double-upload') }}
@endif​@if(auth()->user()->group->is_double_upload){{ __('torrent.special-double_upload') }}
@endif​@if($torrent->doubleup > 0)100% {{ __('torrent.double-upload') }}@if($torrent->du_until !== null) (expires {{ $torrent->du_until->diffForHumans() }})@endif​@endif"
|
||||
></i>
|
||||
@endif
|
||||
@if ($torrent->refundable || auth()->user()->group->is_refundable)
|
||||
<i class="{{ config('other.font-awesome') }} fa-percentage"
|
||||
title='{{ __('torrent.refundable') }}'>
|
||||
</i>
|
||||
@endif
|
||||
@if ($torrent->sticky)
|
||||
<i
|
||||
class="{{ config('other.font-awesome') }} fa-thumbtack torrent-icons__sticky"
|
||||
|
||||
@@ -46,6 +46,7 @@
|
||||
<th>{{ __('torrent.completed') }}</th>
|
||||
<th>{{ __('common.upload') }}</th>
|
||||
<th>{{ __('common.download') }}</th>
|
||||
<th>{{ __('common.refunded-download') }}</th>
|
||||
<th>{{ __('common.added') }}</th>
|
||||
<th>{{ __('torrent.last-update') }}</th>
|
||||
<th>{{ __('torrent.completed_at') }}</th>
|
||||
@@ -89,6 +90,11 @@
|
||||
</span>
|
||||
</span>
|
||||
</td>
|
||||
<td>
|
||||
<span class="text-orange" title="{{ __('torrent.credited') }} {{ strtolower(__('common.download')) }}">
|
||||
({{ App\Helpers\StringHelper::formatBytes($history->refunded_download, 2) }})
|
||||
</span>
|
||||
</td>
|
||||
<td>
|
||||
<time datetime="{{ $history->created_at }}" title="{{ $history->created_at }}">
|
||||
{{ $history->created_at ? $history->created_at->diffForHumans() : 'N/A' }}
|
||||
|
||||
@@ -73,4 +73,4 @@
|
||||
<li>
|
||||
@include('components.partials._torrent-icons', ['personalFreeleech' => $personal_freeleech])
|
||||
</li>
|
||||
</ul>
|
||||
</ul>
|
||||
@@ -156,6 +156,27 @@
|
||||
</div>
|
||||
</dialog>
|
||||
</li>
|
||||
<li>
|
||||
@if ($torrent->refundable == 0)
|
||||
<form action="{{ route('refundable', ['id' => $torrent->id]) }}"
|
||||
method="POST"
|
||||
style="display: inline;">
|
||||
@csrf
|
||||
<button type="submit" class="form__button form__button--outlined">
|
||||
<i class="{{ config('other.font-awesome') }} fa-repeat"></i> {{ __('torrent.refundable') }}
|
||||
</button>
|
||||
</form>
|
||||
@else
|
||||
<form action="{{ route('refundable', ['id' => $torrent->id]) }}"
|
||||
method="POST"
|
||||
style="display: inline;">
|
||||
@csrf
|
||||
<button type="submit" class="form__button form__button--outlined">
|
||||
<i class="{{ config('other.font-awesome') }} fa-repeat"></i> {{ __('torrent.revoke') }} {{ __('torrent.refundable') }}
|
||||
</button>
|
||||
</form>
|
||||
@endif
|
||||
</li>
|
||||
<li>
|
||||
@if ($torrent->sticky == 0)
|
||||
<form
|
||||
|
||||
@@ -493,6 +493,8 @@
|
||||
<dd>{{ App\Helpers\StringHelper::formatBytes($history->download_sum ?? 0, 2) }}</dd>
|
||||
<dt>{{ __('torrent.torrent') }} {{ __('common.download') }} ({{ __('torrent.credited') }})</dt>
|
||||
<dd>{{ App\Helpers\StringHelper::formatBytes($history->credited_download_sum ?? 0, 2) }}</dd>
|
||||
<dt>{{ __('torrent.torrent') }} {{ __('common.download') }} ({{ __('torrent.refunded') }})</dt>
|
||||
<dd>{{ App\Helpers\StringHelper::formatBytes($history->refunded_download_sum ?? 0, 2) }}</dd>
|
||||
<dt>{{ __('bon.bon') }} {{ __('common.upload') }}</dt>
|
||||
<dd>{{ App\Helpers\StringHelper::formatBytes($boughtUpload, 2) }}</dd>
|
||||
</dl>
|
||||
|
||||
@@ -209,6 +209,7 @@ Route::group(['middleware' => 'language'], function (): void {
|
||||
Route::post('/{id}/torrent_feature', [App\Http\Controllers\TorrentBuffController::class, 'grantFeatured'])->name('torrent_feature');
|
||||
Route::post('/{id}/torrent_revokefeature', [App\Http\Controllers\TorrentBuffController::class, 'revokeFeatured'])->name('torrent_revokefeature');
|
||||
Route::post('/{id}/freeleech_token', [App\Http\Controllers\TorrentBuffController::class, 'freeleechToken'])->name('freeleech_token');
|
||||
Route::post('/{id}/refundable', [App\Http\Controllers\TorrentBuffController::class, 'setRefundable'])->name('refundable');
|
||||
});
|
||||
|
||||
// Poll System
|
||||
|
||||
@@ -102,6 +102,7 @@ class GroupControllerTest extends TestCase
|
||||
'is_immune' => $group->is_immune,
|
||||
'is_freeleech' => $group->is_freeleech,
|
||||
'is_double_upload' => $group->is_double_upload,
|
||||
'is_refundable' => $group->is_refundable,
|
||||
'can_upload' => $group->can_upload,
|
||||
'is_incognito' => $group->is_incognito,
|
||||
'autogroup' => $group->autogroup,
|
||||
@@ -136,6 +137,7 @@ class GroupControllerTest extends TestCase
|
||||
'is_immune' => $group->is_immune,
|
||||
'is_freeleech' => $group->is_freeleech,
|
||||
'is_double_upload' => $group->is_double_upload,
|
||||
'is_refundable' => $group->is_refundable,
|
||||
'can_upload' => $group->can_upload,
|
||||
'is_incognito' => $group->is_incognito,
|
||||
'autogroup' => $group->autogroup,
|
||||
|
||||
Reference in New Issue
Block a user