mirror of
https://github.com/lkddi/nexusphp.git
synced 2026-04-23 19:37:23 +08:00
Merge branch 'php8' into section
This commit is contained in:
@@ -22,14 +22,14 @@ class BaseRepository
|
||||
|
||||
protected function handleAnonymous($username, User $user, User $authenticator, Torrent $torrent = null)
|
||||
{
|
||||
$canViewAnonymousClass = Setting::get('authority.viewanonymous');
|
||||
if($user->privacy == "strong" || ($torrent && $torrent->anonymous == 'yes' && $user->id == $torrent->owner)) {
|
||||
//用户强私密,或者种子作者匿名而当前项作者刚好为种子作者
|
||||
if($authenticator->class >= $canViewAnonymousClass || $user->id == $authenticator->id) {
|
||||
$anonymousText = nexus_trans('label.anonymous');
|
||||
if(user_can('viewanonymous', false, $authenticator->id) || $user->id == $authenticator->id) {
|
||||
//但当前用户权限可以查看匿名者,或当前用户查看自己的数据,显示个匿名,后边加真实用户名
|
||||
return sprintf('匿名(%s)', $username);
|
||||
return sprintf('%s(%s)', $anonymousText, $username);
|
||||
} else {
|
||||
return '匿名';
|
||||
return $anonymousText;
|
||||
}
|
||||
} else {
|
||||
return $username;
|
||||
@@ -55,4 +55,20 @@ class BaseRepository
|
||||
return User::query()->findOrFail(intval($user), $fields);
|
||||
}
|
||||
|
||||
protected function executeCommand($command, $format = 'string'): string|array
|
||||
{
|
||||
$append = " 2>&1";
|
||||
if (!str_ends_with($command, $append)) {
|
||||
$command .= $append;
|
||||
}
|
||||
do_log("command: $command");
|
||||
$result = exec($command, $output, $result_code);
|
||||
$outputString = implode("\n", $output);
|
||||
do_log(sprintf('result_code: %s, result: %s, output: %s', $result_code, $result, $outputString));
|
||||
if ($result_code != 0) {
|
||||
throw new \RuntimeException($outputString);
|
||||
}
|
||||
return $format == 'string' ? $outputString : $output;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -3,13 +3,16 @@ namespace App\Repositories;
|
||||
|
||||
use App\Models\HitAndRun;
|
||||
use App\Models\Message;
|
||||
use App\Models\SearchBox;
|
||||
use App\Models\Setting;
|
||||
use App\Models\User;
|
||||
use App\Models\UserBanLog;
|
||||
use Carbon\Carbon;
|
||||
use Elasticsearch\Endpoints\Search;
|
||||
use Illuminate\Database\Eloquent\Builder;
|
||||
use Illuminate\Support\Arr;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
use Nexus\Database\NexusDB;
|
||||
|
||||
class HitAndRunRepository extends BaseRepository
|
||||
{
|
||||
@@ -87,12 +90,31 @@ class HitAndRunRepository extends BaseRepository
|
||||
return $query;
|
||||
}
|
||||
|
||||
public function cronjobUpdateStatus($uid = null, $torrentId = null, $ignoreTime = false): bool|int
|
||||
public function cronjobUpdateStatus($uid = null, $torrentId = null, $ignoreTime = false)
|
||||
{
|
||||
$diffInSection = HitAndRun::diffInSection();
|
||||
$browseMode = Setting::get('main.browsecat');
|
||||
$setting = HitAndRun::getConfig('*', $browseMode);
|
||||
$setting['diff_in_section'] = $diffInSection;
|
||||
$setting['search_box_id'] = $browseMode;
|
||||
$this->doCronjobUpdateStatus($setting, $uid, $torrentId, $ignoreTime);
|
||||
$this->checkAndDisableUser($setting);
|
||||
|
||||
$specialMode = Setting::get('main.specialcat');
|
||||
if ($diffInSection && $browseMode != $specialMode) {
|
||||
$setting = HitAndRun::getConfig('*', $specialMode);
|
||||
$setting['diff_in_section'] = $diffInSection;
|
||||
$setting['search_box_id'] = $specialMode;
|
||||
$this->doCronjobUpdateStatus($setting, $uid, $torrentId, $ignoreTime);
|
||||
$this->checkAndDisableUser($setting);
|
||||
}
|
||||
}
|
||||
|
||||
private function doCronjobUpdateStatus(array $setting, $uid = null, $torrentId = null, $ignoreTime = false)
|
||||
{
|
||||
do_log("uid: $uid, torrentId: $torrentId, ignoreTime: " . var_export($ignoreTime, true));
|
||||
$size = 1000;
|
||||
$page = 1;
|
||||
$setting = Setting::get('hr');
|
||||
if (empty($setting['mode'])) {
|
||||
do_log("H&R not set.");
|
||||
return false;
|
||||
@@ -108,7 +130,7 @@ class HitAndRunRepository extends BaseRepository
|
||||
$query = HitAndRun::query()
|
||||
->where('status', HitAndRun::STATUS_INSPECTING)
|
||||
->with([
|
||||
'torrent' => function ($query) {$query->select(['id', 'size', 'name']);},
|
||||
'torrent' => function ($query) {$query->select(['id', 'size', 'name', 'category']);},
|
||||
'snatch',
|
||||
'user' => function ($query) {$query->select(['id', 'username', 'lang', 'class', 'donoruntil', 'enabled']);},
|
||||
'user.language',
|
||||
@@ -122,6 +144,12 @@ class HitAndRunRepository extends BaseRepository
|
||||
if (!$ignoreTime) {
|
||||
$query->where('created_at', '<', Carbon::now()->subHours($setting['inspect_time']));
|
||||
}
|
||||
if ($setting['diff_in_section']) {
|
||||
$query->whereHas('torrent.basic_category', function (Builder $query) use ($setting) {
|
||||
return $query->where('mode', $setting['search_box_id']);
|
||||
});
|
||||
}
|
||||
|
||||
$successCounts = 0;
|
||||
$disabledUsers = [];
|
||||
while (true) {
|
||||
@@ -164,7 +192,7 @@ class HitAndRunRepository extends BaseRepository
|
||||
$requireSeedTime = bcmul($setting['seed_time_minimum'], 3600);
|
||||
do_log("$currentLog, targetSeedTime: $targetSeedTime, requireSeedTime: $requireSeedTime");
|
||||
if ($targetSeedTime >= $requireSeedTime) {
|
||||
$result = $this->reachedBySeedTime($row);
|
||||
$result = $this->reachedBySeedTime($row, $setting);
|
||||
if ($result) {
|
||||
$successCounts++;
|
||||
}
|
||||
@@ -176,7 +204,7 @@ class HitAndRunRepository extends BaseRepository
|
||||
$requireShareRatio = $setting['ignore_when_ratio_reach'];
|
||||
do_log("$currentLog, targetShareRatio: $targetShareRatio, requireShareRatio: $requireShareRatio");
|
||||
if ($targetShareRatio >= $requireShareRatio) {
|
||||
$result = $this->reachedByShareRatio($row);
|
||||
$result = $this->reachedByShareRatio($row, $setting);
|
||||
if ($result) {
|
||||
$successCounts++;
|
||||
}
|
||||
@@ -185,7 +213,7 @@ class HitAndRunRepository extends BaseRepository
|
||||
|
||||
//unreached
|
||||
if ($row->created_at->addHours($setting['inspect_time'])->lte(Carbon::now())) {
|
||||
$result = $this->unreached($row, !isset($disabledUsers[$row->uid]));
|
||||
$result = $this->unreached($row, $setting, !isset($disabledUsers[$row->uid]));
|
||||
if ($result) {
|
||||
$successCounts++;
|
||||
$disabledUsers[$row->uid] = true;
|
||||
@@ -212,15 +240,15 @@ class HitAndRunRepository extends BaseRepository
|
||||
];
|
||||
}
|
||||
|
||||
private function reachedByShareRatio(HitAndRun $hitAndRun): bool
|
||||
private function reachedByShareRatio(HitAndRun $hitAndRun, array $setting): bool
|
||||
{
|
||||
do_log(__METHOD__);
|
||||
$comment = nexus_trans('hr.reached_by_share_ratio_comment', [
|
||||
'now' => Carbon::now()->toDateTimeString(),
|
||||
'seed_time_minimum' => Setting::get('hr.seed_time_minimum'),
|
||||
'seed_time_minimum' => $setting['seed_time_minimum'],
|
||||
'seed_time' => bcdiv($hitAndRun->snatch->seedtime, 3600, 1),
|
||||
'share_ratio' => get_hr_ratio($hitAndRun->snatch->uploaded, $hitAndRun->snatch->downloaded),
|
||||
'ignore_when_ratio_reach' => Setting::get('hr.ignore_when_ratio_reach'),
|
||||
'ignore_when_ratio_reach' => $setting['ignore_when_ratio_reach'],
|
||||
], $hitAndRun->user->locale);
|
||||
$update = [
|
||||
'comment' => $comment
|
||||
@@ -228,13 +256,13 @@ class HitAndRunRepository extends BaseRepository
|
||||
return $this->inspectingToReached($hitAndRun, $update, __FUNCTION__);
|
||||
}
|
||||
|
||||
private function reachedBySeedTime(HitAndRun $hitAndRun): bool
|
||||
private function reachedBySeedTime(HitAndRun $hitAndRun, array $setting): bool
|
||||
{
|
||||
do_log(__METHOD__);
|
||||
$comment = nexus_trans('hr.reached_by_seed_time_comment', [
|
||||
'now' => Carbon::now()->toDateTimeString(),
|
||||
'seed_time' => bcdiv($hitAndRun->snatch->seedtime, 3600, 1),
|
||||
'seed_time_minimum' => Setting::get('hr.seed_time_minimum')
|
||||
'seed_time_minimum' => $setting['seed_time_minimum'],
|
||||
], $hitAndRun->user->locale);
|
||||
$update = [
|
||||
'comment' => $comment
|
||||
@@ -271,16 +299,16 @@ class HitAndRunRepository extends BaseRepository
|
||||
return true;
|
||||
}
|
||||
|
||||
private function unreached(HitAndRun $hitAndRun, $disableUser = true): bool
|
||||
private function unreached(HitAndRun $hitAndRun, array $setting, $disableUser = true): bool
|
||||
{
|
||||
do_log(sprintf('hitAndRun: %s, disableUser: %s', $hitAndRun->toJson(), var_export($disableUser, true)));
|
||||
$comment = nexus_trans('hr.unreached_comment', [
|
||||
'now' => Carbon::now()->toDateTimeString(),
|
||||
'seed_time' => bcdiv($hitAndRun->snatch->seedtime, 3600, 1),
|
||||
'seed_time_minimum' => Setting::get('hr.seed_time_minimum'),
|
||||
'seed_time_minimum' => $setting['seed_time_minimum'],
|
||||
'share_ratio' => get_hr_ratio($hitAndRun->snatch->uploaded, $hitAndRun->snatch->downloaded),
|
||||
'torrent_size' => mksize($hitAndRun->torrent->size),
|
||||
'ignore_when_ratio_reach' => Setting::get('hr.ignore_when_ratio_reach')
|
||||
'ignore_when_ratio_reach' => $setting['ignore_when_ratio_reach']
|
||||
], $hitAndRun->user->locale);
|
||||
$update = [
|
||||
'status' => HitAndRun::STATUS_UNREACHED,
|
||||
@@ -307,31 +335,43 @@ class HitAndRunRepository extends BaseRepository
|
||||
];
|
||||
Message::query()->insert($message);
|
||||
|
||||
if (!$disableUser) {
|
||||
do_log("[DO_NOT_DISABLE_USER], return");
|
||||
return true;
|
||||
return true;
|
||||
}
|
||||
|
||||
private function checkAndDisableUser(array $setting): void
|
||||
{
|
||||
$disableCounts = HitAndRun::getConfig('ban_user_when_counts_reach', $setting['search_box_id']);
|
||||
$query = HitAndRun::query()
|
||||
->selectRaw("count(*) as counts, uid")
|
||||
->where('status', HitAndRun::STATUS_UNREACHED)
|
||||
->groupBy('uid')
|
||||
->having("counts", '>=', $disableCounts)
|
||||
;
|
||||
if ($setting['diff_in_section']) {
|
||||
$query->whereHas('torrent.basic_category', function (Builder $query) use ($setting) {
|
||||
return $query->where('mode', $setting['search_box_id']);
|
||||
});
|
||||
}
|
||||
if ($hitAndRun->user->enabled == 'no') {
|
||||
do_log("[USER_ALREADY_DISABLED], return");
|
||||
return true;
|
||||
$result = $query->get();
|
||||
if ($result->isEmpty()) {
|
||||
do_log("No user to disable");
|
||||
return;
|
||||
}
|
||||
//disable user
|
||||
/** @var User $user */
|
||||
$user = $hitAndRun->user;
|
||||
$counts = $user->hitAndRuns()->where('status', HitAndRun::STATUS_UNREACHED)->count();
|
||||
$disableCounts = Setting::get('hr.ban_user_when_counts_reach');
|
||||
do_log("user: {$user->id}, H&R counts: $counts, disableCounts: $disableCounts", 'notice');
|
||||
if ($counts >= $disableCounts) {
|
||||
do_log("[DISABLE_USER_DUE_TO_H&R_UNREACHED]", 'notice');
|
||||
$comment = nexus_trans('hr.unreached_disable_comment', [], $user->locale);
|
||||
$user->updateWithModComment(['enabled' => User::ENABLED_NO], $comment);
|
||||
$users = User::query()
|
||||
->with('language')
|
||||
->where('enabled', User::ENABLED_YES)
|
||||
->find($result->pluck('id')->toArray(), ['id', 'username', 'lang']);
|
||||
foreach ($users as $user) {
|
||||
$locale = $user->locale;
|
||||
$comment = nexus_trans('hr.unreached_disable_comment', [], $locale);
|
||||
$user->updateWithModComment(['enabled' => User::ENABLED_NO], sprintf('%s - %s', date('Y-m-d'), $comment));
|
||||
$message = [
|
||||
'receiver' => $hitAndRun->uid,
|
||||
'receiver' => $user->id,
|
||||
'added' => Carbon::now()->toDateTimeString(),
|
||||
'subject' => $comment,
|
||||
'msg' => nexus_trans('hr.unreached_disable_message_content', [
|
||||
'ban_user_when_counts_reach' => Setting::get('hr.ban_user_when_counts_reach'),
|
||||
], $hitAndRun->user->locale),
|
||||
], $locale),
|
||||
];
|
||||
Message::query()->insert($message);
|
||||
$userBanLog = [
|
||||
@@ -340,30 +380,59 @@ class HitAndRunRepository extends BaseRepository
|
||||
'reason' => $comment
|
||||
];
|
||||
UserBanLog::query()->insert($userBanLog);
|
||||
do_log("Disable user: " . nexus_json_encode($userBanLog));
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public function getStatusStats($uid, $formatted = true)
|
||||
{
|
||||
$results = HitAndRun::query()->where('uid', $uid)
|
||||
->selectRaw('status, count(*) as counts')
|
||||
->groupBy('status')
|
||||
->get()
|
||||
->pluck('counts', 'status');
|
||||
if ($formatted) {
|
||||
return sprintf(
|
||||
'%s/%s/%s',
|
||||
$results->get(HitAndRun::STATUS_INSPECTING, 0),
|
||||
$results->get(HitAndRun::STATUS_UNREACHED, 0),
|
||||
Setting::get('hr.ban_user_when_counts_reach')
|
||||
);
|
||||
$diffInSection = HitAndRun::diffInSection();
|
||||
if ($diffInSection) {
|
||||
$sql = "select hit_and_runs.status, categories.mode, count(*) as counts from hit_and_runs left join torrents on torrents.id = hit_and_runs.torrent_id left join categories on categories.id = torrents.category where hit_and_runs.uid = $uid group by hit_and_runs.status, categories.mode";
|
||||
} else {
|
||||
$sql = "select hit_and_runs.status, count(*) as counts from hit_and_runs where uid = $uid group by status";
|
||||
}
|
||||
$results = NexusDB::select($sql);
|
||||
do_log("user: $uid, sql: $sql, results: " . json_encode($results));
|
||||
if (!$formatted) {
|
||||
return $results;
|
||||
}
|
||||
if ($diffInSection) {
|
||||
$grouped = [];
|
||||
foreach ($results as $item) {
|
||||
$grouped[$item['mode']][$item['status']] = $item['counts'];
|
||||
}
|
||||
$out = [];
|
||||
foreach (SearchBox::listSections() as $key => $info) {
|
||||
$out[] = sprintf(
|
||||
'%s: %s/%s/%s',
|
||||
$info['text'],
|
||||
$grouped[$info['mode']][HitAndRun::STATUS_INSPECTING] ?? 0,
|
||||
$grouped[$info['mode']][HitAndRun::STATUS_UNREACHED] ?? 0,
|
||||
HitAndRun::getConfig('ban_user_when_counts_reach', $info['mode'])
|
||||
);
|
||||
}
|
||||
return implode(" ", $out);
|
||||
} else {
|
||||
$grouped = [];
|
||||
foreach ($results as $item) {
|
||||
$grouped[$item['status']] = $item['counts'];
|
||||
}
|
||||
foreach (SearchBox::listSections() as $key => $info) {
|
||||
if ($key == SearchBox::SECTION_BROWSE) {
|
||||
return sprintf(
|
||||
'%s/%s/%s',
|
||||
$grouped[HitAndRun::STATUS_INSPECTING] ?? 0,
|
||||
$grouped[HitAndRun::STATUS_UNREACHED] ?? 0,
|
||||
HitAndRun::getConfig('ban_user_when_counts_reach', $info['mode'])
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
return $results;
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
public function listStatus(): array
|
||||
{
|
||||
$results = [];
|
||||
@@ -407,6 +476,16 @@ class HitAndRunRepository extends BaseRepository
|
||||
|
||||
private function getCanPardonStatus(): array
|
||||
{
|
||||
return [HitAndRun::STATUS_INSPECTING, HitAndRun::STATUS_UNREACHED];
|
||||
return HitAndRun::CAN_PARDON_STATUS;
|
||||
}
|
||||
|
||||
public function renderOnUploadPage($value, $searchBoxId): string
|
||||
{
|
||||
if (HitAndRun::getConfig('mode', $searchBoxId) == \App\Models\HitAndRun::MODE_MANUAL && user_can('torrent_hr')) {
|
||||
$hrRadio = sprintf('<label><input type="radio" name="hr[%s]" value="0"%s />NO</label>', $searchBoxId, $value == 0 ? ' checked' : '');
|
||||
$hrRadio .= sprintf('<label><input type="radio" name="hr[%s]" value="1"%s />YES</label>', $searchBoxId, $value == 1 ? ' checked' : '');
|
||||
return tr('H&R', $hrRadio, 1, "mode_$searchBoxId", true);
|
||||
}
|
||||
return '';
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,187 @@
|
||||
<?php
|
||||
namespace App\Repositories;
|
||||
|
||||
use App\Models\Plugin;
|
||||
|
||||
class PluginRepository extends BaseRepository
|
||||
{
|
||||
public function cronjob($action = null, $id = null, $force = false)
|
||||
{
|
||||
if ($action == 'install' || $action === null) {
|
||||
$this->doCronjob('install', $id, $force, Plugin::STATUS_PRE_INSTALL, Plugin::STATUS_INSTALLING);
|
||||
}
|
||||
if ($action == 'delete' || $action === null) {
|
||||
$this->doCronjob('delete', $id, $force, Plugin::STATUS_PRE_DELETE, Plugin::STATUS_DELETING);
|
||||
}
|
||||
if ($action == 'update' || $action === null) {
|
||||
$this->doCronjob('update', $id, $force, Plugin::STATUS_PRE_UPDATE, Plugin::STATUS_UPDATING);
|
||||
}
|
||||
}
|
||||
|
||||
private function doCronjob($action, $id, $force, $preStatus, $doingStatus)
|
||||
{
|
||||
$query = Plugin::query();
|
||||
if (!$force) {
|
||||
$query->where('status', $preStatus);
|
||||
}
|
||||
if ($id !== null) {
|
||||
$query->where("id", $id);
|
||||
}
|
||||
$list = $query->get();
|
||||
if ($list->isEmpty()) {
|
||||
do_log("No plugin need to be $action...");
|
||||
return;
|
||||
}
|
||||
$idArr = $list->pluck('id')->toArray();
|
||||
Plugin::query()->whereIn('id', $idArr)->update(['status' => $doingStatus]);
|
||||
foreach ($list as $item) {
|
||||
match ($action) {
|
||||
'install' => $this->doInstall($item),
|
||||
'update' => $this->doUpdate($item),
|
||||
'delete' => $this->doDelete($item),
|
||||
default => throw new \InvalidArgumentException("Invalid action: $action")
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
public function doInstall(Plugin $plugin)
|
||||
{
|
||||
$packageName = $plugin->package_name;
|
||||
try {
|
||||
$this->execComposerConfig($plugin);
|
||||
$this->execComposerRequire($plugin);
|
||||
$output = $this->execPluginInstall($plugin);
|
||||
$version = $this->getInstalledVersion($packageName);
|
||||
do_log("success install plugin: $packageName version: $version");
|
||||
$update = [
|
||||
'status' => Plugin::STATUS_NORMAL,
|
||||
'status_result' => $output,
|
||||
'installed_version' => $version
|
||||
];
|
||||
} catch (\Throwable $throwable) {
|
||||
$update = [
|
||||
'status' => Plugin::STATUS_INSTALL_FAILED,
|
||||
'status_result' => $throwable->getMessage()
|
||||
];
|
||||
do_log("fail install plugin: " . $packageName);
|
||||
} finally {
|
||||
$this->updateResult($plugin, $update);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public function doDelete(Plugin $plugin)
|
||||
{
|
||||
$packageName = $plugin->package_name;
|
||||
$removeSuccess = true;
|
||||
try {
|
||||
$output = $this->execComposerRemove($plugin);
|
||||
do_log("success remove plugin: $packageName");
|
||||
$update = [
|
||||
'status' => Plugin::STATUS_NOT_INSTALLED,
|
||||
'status_result' => $output,
|
||||
'installed_version' => null,
|
||||
];
|
||||
} catch (\Throwable $throwable) {
|
||||
$update = [
|
||||
'status' => Plugin::STATUS_DELETE_FAILED,
|
||||
'status_result' => $throwable->getMessage()
|
||||
];
|
||||
$removeSuccess = false;
|
||||
do_log("fail remove plugin: " . $packageName);
|
||||
} finally {
|
||||
if ($removeSuccess) {
|
||||
$plugin->delete();
|
||||
} else {
|
||||
$this->updateResult($plugin, $update);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public function doUpdate(Plugin $plugin)
|
||||
{
|
||||
$packageName = $plugin->package_name;
|
||||
try {
|
||||
$output = $this->execComposerUpdate($plugin);
|
||||
$this->execPluginInstall($plugin);
|
||||
$version = $this->getInstalledVersion($packageName);
|
||||
do_log("success update plugin: $packageName to version: $version");
|
||||
$update = [
|
||||
'status' => Plugin::STATUS_NORMAL,
|
||||
'status_result' => $output,
|
||||
'installed_version' => $version,
|
||||
];
|
||||
} catch (\Throwable $throwable) {
|
||||
$update = [
|
||||
'status' => Plugin::STATUS_UPDATE_FAILED,
|
||||
'status_result' => $throwable->getMessage()
|
||||
];
|
||||
do_log("fail update plugin: " . $packageName);
|
||||
} finally {
|
||||
$this->updateResult($plugin, $update);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private function getRepositoryKey(Plugin $plugin)
|
||||
{
|
||||
return str_replace("xiaomlove/nexusphp-", "", $plugin->package_name);
|
||||
}
|
||||
|
||||
private function execComposerConfig(Plugin $plugin)
|
||||
{
|
||||
$command = sprintf("composer config repositories.%s git %s", $this->getRepositoryKey($plugin), $plugin->remote_url);
|
||||
do_log("[COMPOSER_CONFIG]: $command");
|
||||
return $this->executeCommand($command);
|
||||
}
|
||||
|
||||
private function execComposerRequire(Plugin $plugin)
|
||||
{
|
||||
$command = sprintf("composer require %s", $plugin->package_name);
|
||||
do_log("[COMPOSER_REQUIRE]: $command");
|
||||
return $this->executeCommand($command);
|
||||
}
|
||||
|
||||
private function execComposerRemove(Plugin $plugin)
|
||||
{
|
||||
$command = sprintf("composer remove %s", $plugin->package_name);
|
||||
do_log("[COMPOSER_REMOVE]: $command");
|
||||
return $this->executeCommand($command);
|
||||
}
|
||||
|
||||
private function execComposerUpdate(Plugin $plugin)
|
||||
{
|
||||
$command = sprintf("composer update %s", $plugin->package_name);
|
||||
do_log("[COMPOSER_UPDATE]: $command");
|
||||
return $this->executeCommand($command);
|
||||
}
|
||||
|
||||
private function execPluginInstall(Plugin $plugin)
|
||||
{
|
||||
$command = sprintf("php artisan plugin install %s", $plugin->package_name);
|
||||
do_log("[PLUGIN_INSTALL]: $command");
|
||||
return $this->executeCommand($command);
|
||||
}
|
||||
|
||||
private function updateResult(Plugin $plugin, array $update)
|
||||
{
|
||||
$update['status_result'] = $update['status_result'] . "\n\nREQUEST_ID: " . nexus()->getRequestId();
|
||||
do_log("[UPDATE]: " . json_encode($update));
|
||||
$plugin->update($update);
|
||||
}
|
||||
|
||||
public function getInstalledVersion($packageName)
|
||||
{
|
||||
$command = sprintf('composer info |grep -E %s', $packageName);
|
||||
$result = $this->executeCommand($command);
|
||||
$parts = preg_split("/[\s]+/", trim($result));
|
||||
$version = $parts[1];
|
||||
if (str_contains($version, 'dev')) {
|
||||
$version .= " $parts[2]";
|
||||
}
|
||||
return $version;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -154,7 +154,7 @@ class SeedBoxRepository extends BaseRepository
|
||||
|
||||
private function clearCache()
|
||||
{
|
||||
return true;
|
||||
NexusDB::cache_del('SEED_BOX_RECORD_APPROVAL_NONE');
|
||||
// SeedBoxRecordUpdated::dispatch();
|
||||
}
|
||||
|
||||
|
||||
@@ -11,6 +11,8 @@ class TagRepository extends BaseRepository
|
||||
{
|
||||
private static $orderByFieldIdString;
|
||||
|
||||
private static $allTags;
|
||||
|
||||
public function getList(array $params)
|
||||
{
|
||||
$query = $this->createBasicQuery();
|
||||
@@ -48,10 +50,14 @@ class TagRepository extends BaseRepository
|
||||
return Tag::query()->orderBy('priority', 'desc')->orderBy('id', 'desc');
|
||||
}
|
||||
|
||||
public function renderCheckbox(array $checked = []): string
|
||||
public function renderCheckbox(array $checked = [], $ignorePermission = false): string
|
||||
{
|
||||
$html = '';
|
||||
$results = $this->createBasicQuery()->get();
|
||||
$results = $this->listAll();
|
||||
if (!$ignorePermission && !user_can('torrent-set-special-tag')) {
|
||||
$specialTags = Tag::listSpecial();
|
||||
$results = $results->filter(fn ($item) => !in_array($item->id, $specialTags));
|
||||
}
|
||||
foreach ($results as $value) {
|
||||
$html .= sprintf(
|
||||
'<label><input type="checkbox" name="tags[]" value="%s"%s />%s</label>',
|
||||
@@ -61,20 +67,22 @@ class TagRepository extends BaseRepository
|
||||
return $html;
|
||||
}
|
||||
|
||||
public function renderSpan(Collection $tagKeyById, array $renderIdArr = [], $withFilterLink = false): string
|
||||
public function renderSpan(array $renderIdArr = [], $withFilterLink = false): string
|
||||
{
|
||||
$html = '';
|
||||
foreach ($renderIdArr as $tagId) {
|
||||
$value = $tagKeyById->get($tagId);
|
||||
if ($value) {
|
||||
$item = sprintf(
|
||||
"<span style=\"background-color:%s;color:%s;border-radius:%s;font-size:%s;margin:%s;padding:%s\">%s</span>",
|
||||
$value->color, $value->font_color, $value->border_radius, $value->font_size, $value->margin, $value->padding, $value->name
|
||||
);
|
||||
if ($withFilterLink) {
|
||||
$html .= sprintf('<a href="?tag_id=%s">%s</a>', $tagId, $item);
|
||||
} else {
|
||||
$html .= $item;
|
||||
foreach ($this->listAll() as $value) {
|
||||
if (in_array($value->id, $renderIdArr) || (isset($renderIdArr[0]) && $renderIdArr[0] == '*')) {
|
||||
$tagId = $value->id;
|
||||
if ($value) {
|
||||
$item = sprintf(
|
||||
"<span style=\"background-color:%s;color:%s;border-radius:%s;font-size:%s;margin:%s;padding:%s\">%s</span>",
|
||||
$value->color, $value->font_color, $value->border_radius, $value->font_size, $value->margin, $value->padding, $value->name
|
||||
);
|
||||
if ($withFilterLink) {
|
||||
$html .= sprintf('<a href="?tag_id=%s">%s</a>', $tagId, $item);
|
||||
} else {
|
||||
$html .= $item;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -141,5 +149,28 @@ class TagRepository extends BaseRepository
|
||||
return self::$orderByFieldIdString;
|
||||
}
|
||||
|
||||
public function listAll()
|
||||
{
|
||||
if (empty(self::$allTags)) {
|
||||
self::$allTags = self::createBasicQuery()->get();
|
||||
}
|
||||
return self::$allTags;
|
||||
}
|
||||
|
||||
public function buildSelect($name, $value): string
|
||||
{
|
||||
$list = $this->listAll();
|
||||
$select = sprintf('<select name="%s"><option value="">%s</option>', $name, nexus_trans('nexus.select_one_please'));
|
||||
foreach ($list as $item) {
|
||||
$selected = '';
|
||||
if ($item->id == $value) {
|
||||
$selected = ' selected';
|
||||
}
|
||||
$select .= sprintf('<option value="%s"%s>%s</option>', $item->id, $selected, $item->name);
|
||||
}
|
||||
$select .= '</select>';
|
||||
return $select;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
@@ -24,7 +24,7 @@ class ToolRepository extends BaseRepository
|
||||
{
|
||||
const BACKUP_EXCLUDES = ['vendor', 'node_modules', '.git', '.idea', '.settings', '.DS_Store', '.github'];
|
||||
|
||||
public function backupWeb($method = null): array
|
||||
public function backupWeb($method = null, $transfer = false): array
|
||||
{
|
||||
$webRoot = base_path();
|
||||
$dirName = basename($webRoot);
|
||||
@@ -76,10 +76,13 @@ class ToolRepository extends BaseRepository
|
||||
$result_code = 0;
|
||||
do_log("No tar command, use zip.");
|
||||
}
|
||||
return compact('result_code', 'filename');
|
||||
if (!$transfer) {
|
||||
return compact('result_code', 'filename');
|
||||
}
|
||||
return $this->transfer($filename, $result_code);
|
||||
}
|
||||
|
||||
public function backupDatabase(): array
|
||||
public function backupDatabase($transfer = false): array
|
||||
{
|
||||
$connectionName = config('database.default');
|
||||
$config = config("database.connections.$connectionName");
|
||||
@@ -93,10 +96,13 @@ class ToolRepository extends BaseRepository
|
||||
"command: %s, output: %s, result_code: %s, result: %s, filename: %s",
|
||||
$command, json_encode($output), $result_code, $result, $filename
|
||||
));
|
||||
return compact('result_code', 'filename');
|
||||
if (!$transfer) {
|
||||
return compact('result_code', 'filename');
|
||||
}
|
||||
return $this->transfer($filename, $result_code);
|
||||
}
|
||||
|
||||
public function backupAll($method = null): array
|
||||
public function backupAll($method = null, $transfer = false): array
|
||||
{
|
||||
$backupWeb = $this->backupWeb($method);
|
||||
if ($backupWeb['result_code'] != 0) {
|
||||
@@ -134,8 +140,10 @@ class ToolRepository extends BaseRepository
|
||||
$result_code = 0;
|
||||
do_log("No tar command, use zip.");
|
||||
}
|
||||
return compact('result_code', 'filename');
|
||||
|
||||
if (!$transfer) {
|
||||
return compact('result_code', 'filename');
|
||||
}
|
||||
return $this->transfer($filename, $result_code);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -178,27 +186,33 @@ class ToolRepository extends BaseRepository
|
||||
}
|
||||
$backupResult = $this->backupAll();
|
||||
do_log("Backup all result: " . json_encode($backupResult));
|
||||
if ($backupResult['result_code'] != 0) {
|
||||
throw new \RuntimeException("Backup all fail.");
|
||||
}
|
||||
$filename = $backupResult['filename'];
|
||||
$transferResult = $this->transfer($backupResult['filename'], $backupResult['result_code'], $setting);
|
||||
$backupResult['transfer_result'] = $transferResult;
|
||||
do_log("[BACKUP_ALL_DONE]: " . json_encode($backupResult));
|
||||
return $backupResult;
|
||||
}
|
||||
|
||||
public function transfer($filename, $result_code, $setting = null): array
|
||||
{
|
||||
if ($result_code != 0) {
|
||||
throw new \RuntimeException("file: $filename backup fail!");
|
||||
}
|
||||
$result = compact('filename', 'result_code');
|
||||
if (empty($setting)) {
|
||||
$setting = Setting::get('backup');
|
||||
}
|
||||
$saveResult = $this->saveToGoogleDrive($setting, $filename);
|
||||
do_log("[BACKUP_GOOGLE_DRIVE]: $saveResult");
|
||||
$backupResult['google_drive'] = $saveResult;
|
||||
$result['google_drive'] = $saveResult;
|
||||
|
||||
$saveResult = $this->saveToFtp($setting, $filename);
|
||||
do_log("[BACKUP_FTP]: $saveResult");
|
||||
$backupResult['ftp'] = $saveResult;
|
||||
$result['ftp'] = $saveResult;
|
||||
|
||||
$saveResult = $this->saveToSftp($setting, $filename);
|
||||
do_log("[BACKUP_SFTP]: $saveResult");
|
||||
$backupResult['sftp'] = $saveResult;
|
||||
|
||||
do_log("[BACKUP_ALL_DONE]: " . json_encode($backupResult));
|
||||
|
||||
return $backupResult;
|
||||
|
||||
$result['sftp'] = $saveResult;
|
||||
return $result;
|
||||
}
|
||||
|
||||
private function saveToGoogleDrive(array $setting, $filename): bool|string
|
||||
|
||||
@@ -598,11 +598,72 @@ class TorrentRepository extends BaseRepository
|
||||
|
||||
}
|
||||
|
||||
public function setPosState($id, $posState): int
|
||||
public function setPosState($id, $posState, $posStateUntil = null): int
|
||||
{
|
||||
user_can('torrentsticky', true);
|
||||
if ($posState == Torrent::POS_STATE_STICKY_NONE) {
|
||||
$posStateUntil = null;
|
||||
}
|
||||
if ($posStateUntil && Carbon::parse($posStateUntil)->lte(now())) {
|
||||
$posState = Torrent::POS_STATE_STICKY_NONE;
|
||||
$posStateUntil = null;
|
||||
}
|
||||
$update = [
|
||||
'pos_state' => $posState,
|
||||
'pos_state_until' => $posStateUntil,
|
||||
];
|
||||
$idArr = Arr::wrap($id);
|
||||
return Torrent::query()->whereIn('id', $idArr)->update(['pos_state' => $posState]);
|
||||
return Torrent::query()->whereIn('id', $idArr)->update($update);
|
||||
}
|
||||
|
||||
public function setPickType($id, $pickType): int
|
||||
{
|
||||
user_can('torrentmanage', true);
|
||||
if (!isset(Torrent::$pickTypes[$pickType])) {
|
||||
throw new \InvalidArgumentException("Invalid pickType: $pickType");
|
||||
}
|
||||
$update = [
|
||||
'picktype' => $pickType,
|
||||
'picktime' => now(),
|
||||
];
|
||||
$idArr = Arr::wrap($id);
|
||||
return Torrent::query()->whereIn('id', $idArr)->update($update);
|
||||
}
|
||||
|
||||
public function setHr($id, $hrStatus): int
|
||||
{
|
||||
user_can('torrentmanage', true);
|
||||
if (!isset(Torrent::$hrStatus[$hrStatus])) {
|
||||
throw new \InvalidArgumentException("Invalid hrStatus: $hrStatus");
|
||||
}
|
||||
$update = [
|
||||
'hr' => $hrStatus,
|
||||
];
|
||||
$idArr = Arr::wrap($id);
|
||||
return Torrent::query()->whereIn('id', $idArr)->update($update);
|
||||
}
|
||||
|
||||
public function setSpState($id, $spState, $promotionTimeType, $promotionUntil = null): int
|
||||
{
|
||||
user_can('torrentonpromotion', true);
|
||||
if (!isset(Torrent::$promotionTypes[$spState])) {
|
||||
throw new \InvalidArgumentException("Invalid spState: $spState");
|
||||
}
|
||||
if (!isset(Torrent::$promotionTimeTypes[$promotionTimeType])) {
|
||||
throw new \InvalidArgumentException("Invalid promotionTimeType: $promotionTimeType");
|
||||
}
|
||||
if (in_array($promotionTimeType, [Torrent::PROMOTION_TIME_TYPE_GLOBAL, Torrent::PROMOTION_TIME_TYPE_PERMANENT])) {
|
||||
$promotionUntil = null;
|
||||
} elseif (!$promotionUntil || Carbon::parse($promotionUntil)->lte(now())) {
|
||||
throw new \InvalidArgumentException("Invalid promotionUntil: $promotionUntil");
|
||||
}
|
||||
$update = [
|
||||
'sp_state' => $spState,
|
||||
'promotion_time_type' => $promotionTimeType,
|
||||
'promotion_until' => $promotionUntil,
|
||||
];
|
||||
$idArr = Arr::wrap($id);
|
||||
return Torrent::query()->whereIn('id', $idArr)->update($update);
|
||||
}
|
||||
|
||||
public function buildUploadFieldInput($name, $value, $noteText, $btnText): string
|
||||
|
||||
@@ -593,7 +593,7 @@ class TrackerRepository extends BaseRepository
|
||||
$notSeedBoxMaxSpeedMbps = Setting::get('seed_box.not_seed_box_max_speed');
|
||||
do_log("upSpeedMbps: $upSpeedMbps, notSeedBoxMaxSpeedMbps: $notSeedBoxMaxSpeedMbps");
|
||||
if ($upSpeedMbps > $notSeedBoxMaxSpeedMbps) {
|
||||
(new \App\Repositories\UserRepository())->updateDownloadPrivileges(null, $user, 'no');
|
||||
(new \App\Repositories\UserRepository())->updateDownloadPrivileges(null, $user, 'no', 'upload_over_speed');
|
||||
do_log("user: {$user->id} downloading privileges have been disabled! (over speed)", 'error');
|
||||
throw new TrackerException("Your downloading privileges have been disabled! (over speed)");
|
||||
}
|
||||
@@ -1092,7 +1092,8 @@ class TrackerRepository extends BaseRepository
|
||||
if ($user->isDonating()) {
|
||||
return;
|
||||
}
|
||||
$hrMode = Setting::get('hr.mode');
|
||||
// $hrMode = Setting::get('hr.mode');
|
||||
$hrMode = HitAndRun::getConfig('mode', $torrent->basic_category->mode);
|
||||
if ($hrMode == HitAndRun::MODE_DISABLED) {
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -162,12 +162,15 @@ class UserRepository extends BaseRepository
|
||||
return User::listClass();
|
||||
}
|
||||
|
||||
public function disableUser(User $operator, $uid, $reason)
|
||||
public function disableUser(User $operator, $uid, $reason = '')
|
||||
{
|
||||
$targetUser = User::query()->findOrFail($uid, ['id', 'enabled', 'username', 'class']);
|
||||
if ($targetUser->enabled == User::ENABLED_NO) {
|
||||
throw new NexusException('Already disabled !');
|
||||
}
|
||||
if (empty($reason)) {
|
||||
$reason = nexus_trans("user.disable_by_admin");
|
||||
}
|
||||
$this->checkPermission($operator, $targetUser);
|
||||
$banLog = [
|
||||
'uid' => $uid,
|
||||
@@ -326,7 +329,7 @@ class UserRepository extends BaseRepository
|
||||
}
|
||||
|
||||
|
||||
public function updateDownloadPrivileges($operator, $user, $status)
|
||||
public function updateDownloadPrivileges($operator, $user, $status, $disableReasonKey = null)
|
||||
{
|
||||
if (!in_array($status, ['yes', 'no'])) {
|
||||
throw new \InvalidArgumentException("Invalid status: $status");
|
||||
@@ -345,8 +348,12 @@ class UserRepository extends BaseRepository
|
||||
if ($status == 'no') {
|
||||
$update = ['downloadpos' => 'no'];
|
||||
$modComment = date('Y-m-d') . " - Download disable by " . $operatorUsername;
|
||||
$message['subject'] = nexus_trans('message.download_disable.subject', [], $targetUser->locale);
|
||||
$message['msg'] = nexus_trans('message.download_disable.body', ['operator' => $operatorUsername], $targetUser->locale);
|
||||
$msgTransPrefix = "message.download_disable";
|
||||
if ($disableReasonKey !== null) {
|
||||
$msgTransPrefix .= "_$disableReasonKey";
|
||||
}
|
||||
$message['subject'] = nexus_trans("$msgTransPrefix.subject", [], $targetUser->locale);
|
||||
$message['msg'] = nexus_trans("$msgTransPrefix.body", ['operator' => $operatorUsername], $targetUser->locale);
|
||||
} else {
|
||||
$update = ['downloadpos' => 'yes'];
|
||||
$modComment = date('Y-m-d') . " - Download enable by " . $operatorUsername;
|
||||
@@ -463,23 +470,41 @@ class UserRepository extends BaseRepository
|
||||
$user = $this->getUser($user);
|
||||
$metaKey = $metaData['meta_key'];
|
||||
$allowMultiple = UserMeta::$metaKeys[$metaKey]['multiple'];
|
||||
$log = "user: {$user->id}, metaKey: $metaKey, allowMultiple: $allowMultiple";
|
||||
if ($allowMultiple) {
|
||||
//Allow multiple, just insert
|
||||
$result = $user->metas()->create($metaData);
|
||||
$log .= ", allowMultiple, just insert";
|
||||
} else {
|
||||
$metaExists = $user->metas()->where('meta_key', $metaKey)->first();
|
||||
$log .= ", metaExists: " . ($metaExists->id ?? '');
|
||||
if (!$metaExists) {
|
||||
$result = $user->metas()->create($metaData);
|
||||
$log .= ", meta not exists, just create";
|
||||
} else {
|
||||
if (empty($keyExistsUpdates)) {
|
||||
$keyExistsUpdates = ['updated_at' => now()];
|
||||
$log .= ", meta exists";
|
||||
$keyExistsUpdates['updated_at'] = now();
|
||||
if (!empty($keyExistsUpdates['duration'])) {
|
||||
$log .= ", has duration: {$keyExistsUpdates['duration']}";
|
||||
if ($metaExists->deadline && $metaExists->deadline->gte(now())) {
|
||||
$log .= ", not expire";
|
||||
$keyExistsUpdates['deadline'] = $metaExists->deadline->addDays($keyExistsUpdates['duration']);
|
||||
} else {
|
||||
$log .= ", expired or not set";
|
||||
$keyExistsUpdates['deadline'] = now()->addDays($keyExistsUpdates['duration']);
|
||||
}
|
||||
unset($keyExistsUpdates['duration']);
|
||||
} else {
|
||||
$keyExistsUpdates['deadline'] = null;
|
||||
}
|
||||
$log .= ", update: " . json_encode($keyExistsUpdates);
|
||||
$result = $metaExists->update($keyExistsUpdates);
|
||||
}
|
||||
}
|
||||
if ($result) {
|
||||
clear_user_cache($user->id, $user->passkey);
|
||||
}
|
||||
do_log($log);
|
||||
return $result;
|
||||
}
|
||||
|
||||
@@ -497,9 +522,13 @@ class UserRepository extends BaseRepository
|
||||
return true;
|
||||
}
|
||||
|
||||
public function destroy($id)
|
||||
public function destroy($id, $reasonKey = 'user.destroy_by_admin')
|
||||
{
|
||||
user_can('user-delete', true);
|
||||
if (!isRunningInConsole()) {
|
||||
user_can('user-delete', true);
|
||||
}
|
||||
$uidArr = Arr::wrap($id);
|
||||
$users = User::query()->with('language')->whereIn('id', $uidArr)->get(['id', 'username', 'lang']);
|
||||
$tables = [
|
||||
'users' => 'id',
|
||||
'hit_and_runs' => 'uid',
|
||||
@@ -508,9 +537,18 @@ class UserRepository extends BaseRepository
|
||||
'exam_progress' => 'uid',
|
||||
];
|
||||
foreach ($tables as $table => $key) {
|
||||
\Nexus\Database\NexusDB::table($table)->where($key, $id)->delete();
|
||||
\Nexus\Database\NexusDB::table($table)->whereIn($key, $uidArr)->delete();
|
||||
}
|
||||
do_log("[DESTROY_USER]: $id", 'error');
|
||||
do_log("[DESTROY_USER]: " . json_encode($uidArr), 'error');
|
||||
$userBanLogs = [];
|
||||
foreach ($users as $user) {
|
||||
$userBanLogs[] = [
|
||||
'uid' => $user->id,
|
||||
'username' => $user->username,
|
||||
'reason' => nexus_trans($reasonKey, [], $user->locale)
|
||||
];
|
||||
}
|
||||
UserBanLog::query()->insert($userBanLogs);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user