refactor isSeedBox judgement

This commit is contained in:
xiaomlove
2025-05-11 02:33:22 +07:00
parent 6ff9d70ebc
commit 4b39d708d2
32 changed files with 1030 additions and 233 deletions
+3 -3
View File
@@ -9,6 +9,7 @@ use App\Models\PersonalAccessToken;
use App\Models\Torrent; use App\Models\Torrent;
use App\Models\User; use App\Models\User;
use App\Repositories\ExamRepository; use App\Repositories\ExamRepository;
use App\Repositories\SeedBoxRepository;
use App\Repositories\UploadRepository; use App\Repositories\UploadRepository;
use Illuminate\Console\Command; use Illuminate\Console\Command;
use NexusPlugin\Menu\Filament\MenuItemResource\Pages\ManageMenuItems; use NexusPlugin\Menu\Filament\MenuItemResource\Pages\ManageMenuItems;
@@ -55,9 +56,8 @@ class Test extends Command
*/ */
public function handle() public function handle()
{ {
$rep = new MenuRepository(); $rep = new SeedBoxRepository();
$result = \Nexus\Plugin\Plugin::listEnabled(); $rep->updateCacheCronjob();
dd($result);
} }
} }
+2
View File
@@ -6,6 +6,7 @@ use App\Jobs\CheckCleanup;
use App\Jobs\CheckQueueFailedJobs; use App\Jobs\CheckQueueFailedJobs;
use App\Jobs\MaintainPluginState; use App\Jobs\MaintainPluginState;
use App\Jobs\ManagePlugin; use App\Jobs\ManagePlugin;
use App\Jobs\UpdateIsSeedBoxFromUserRecordsCache;
use App\Utils\ThirdPartyJob; use App\Utils\ThirdPartyJob;
use Carbon\Carbon; use Carbon\Carbon;
use Illuminate\Console\Scheduling\Event; use Illuminate\Console\Scheduling\Event;
@@ -48,6 +49,7 @@ class Kernel extends ConsoleKernel
$schedule->job(new CheckQueueFailedJobs())->everySixHours()->withoutOverlapping(); $schedule->job(new CheckQueueFailedJobs())->everySixHours()->withoutOverlapping();
$schedule->job(new ThirdPartyJob())->everyMinute()->withoutOverlapping(); $schedule->job(new ThirdPartyJob())->everyMinute()->withoutOverlapping();
$schedule->job(new MaintainPluginState())->everyMinute()->withoutOverlapping(); $schedule->job(new MaintainPluginState())->everyMinute()->withoutOverlapping();
$schedule->job(new UpdateIsSeedBoxFromUserRecordsCache())->everySixHours()->withoutOverlapping();
$this->registerScheduleCleanup($schedule); $this->registerScheduleCleanup($schedule);
} }
+10
View File
@@ -0,0 +1,10 @@
<?php
namespace App\Enums\SeedBoxRecord;
enum IpAsnEnum: string {
case IP = "IP";
case ASN = "ASN";
}
@@ -0,0 +1,9 @@
<?php
namespace App\Enums\SeedBoxRecord;
enum IsAllowedEnum: int {
case YES = 1;
case NO = 0;
}
+10
View File
@@ -0,0 +1,10 @@
<?php
namespace App\Enums\SeedBoxRecord;
enum TypeEnum: int {
case USER = 1;
case ADMIN = 2;
}
@@ -48,8 +48,8 @@ class SeedBoxRecordResource extends Resource
Forms\Components\TextInput::make('operator')->label(__('label.seed_box_record.operator')), Forms\Components\TextInput::make('operator')->label(__('label.seed_box_record.operator')),
Forms\Components\TextInput::make('bandwidth')->label(__('label.seed_box_record.bandwidth'))->integer(), Forms\Components\TextInput::make('bandwidth')->label(__('label.seed_box_record.bandwidth'))->integer(),
Forms\Components\TextInput::make('asn')->label(__('label.seed_box_record.asn'))->integer(), Forms\Components\TextInput::make('asn')->label(__('label.seed_box_record.asn'))->integer(),
Forms\Components\TextInput::make('ip_begin')->label(__('label.seed_box_record.ip_begin')), // Forms\Components\TextInput::make('ip_begin')->label(__('label.seed_box_record.ip_begin')),
Forms\Components\TextInput::make('ip_end')->label(__('label.seed_box_record.ip_end')), // Forms\Components\TextInput::make('ip_end')->label(__('label.seed_box_record.ip_end')),
Forms\Components\TextInput::make('ip')->label(__('label.seed_box_record.ip'))->helperText(__('label.seed_box_record.ip_help')), Forms\Components\TextInput::make('ip')->label(__('label.seed_box_record.ip'))->helperText(__('label.seed_box_record.ip_help')),
Forms\Components\Toggle::make('is_allowed') Forms\Components\Toggle::make('is_allowed')
->label(__('label.seed_box_record.is_allowed')) ->label(__('label.seed_box_record.is_allowed'))
@@ -2,16 +2,19 @@
namespace App\Filament\Resources\System\SeedBoxRecordResource\Pages; namespace App\Filament\Resources\System\SeedBoxRecordResource\Pages;
use App\Exceptions\SeedBoxYesException;
use App\Filament\PageList; use App\Filament\PageList;
use App\Filament\Resources\System\SeedBoxRecordResource; use App\Filament\Resources\System\SeedBoxRecordResource;
use Filament\Pages\Actions; use App\Repositories\SeedBoxRepository;
use Filament\Actions;
use Filament\Forms; use Filament\Forms;
use Illuminate\Support\HtmlString;
class ListSeedBoxRecords extends PageList class ListSeedBoxRecords extends PageList
{ {
protected static string $resource = SeedBoxRecordResource::class; protected static string $resource = SeedBoxRecordResource::class;
protected static ?array $checkResult = null;
protected function getHeaderActions(): array protected function getHeaderActions(): array
{ {
return [ return [
@@ -23,17 +26,40 @@ class ListSeedBoxRecords extends PageList
Forms\Components\TextInput::make('uid')->required()->label('UID'), Forms\Components\TextInput::make('uid')->required()->label('UID'),
]) ])
->modalHeading(__('admin.resources.seed_box_record.check_modal_header')) ->modalHeading(__('admin.resources.seed_box_record.check_modal_header'))
->action(function ($data) { ->action(function (array $data) {
try { $result = SeedBoxRepository::isSeedBoxFromUserRecords($data['uid'], $data['ip']);
isIPSeedBox($data['ip'], $data['uid'], true, true); self::$checkResult = $result;
send_admin_success_notification(nexus_trans("seed-box.is_seed_box_no")); // return $result;
} catch (SeedBoxYesException $exception) { // $this->replaceMountedAction("checkResult", ['result' => $result]);
send_admin_fail_notification(nexus_trans("seed-box.is_seed_box_yes", ['id' => $exception->getId()])); // if ($checkResult['result']) {
} catch (\Throwable $throwable) { // send_admin_success_notification(nexus_trans("seed-box.is_seed_box_yes", ['desc' => $checkResult['desc']]));
do_log($throwable->getMessage() . $throwable->getTraceAsString(), "error"); // } else {
send_admin_fail_notification($throwable->getMessage()); // send_admin_fail_notification(nexus_trans("seed-box.is_seed_box_no", ['desc' => $checkResult['desc']]));
} // }
}) })
->registerModalActions([
Actions\Action::make('checkResult')
->modalHeading(function () {
if (self::$checkResult !== null) {
if (self::$checkResult['result']) {
return nexus_trans("seed-box.is_seed_box_yes");
} else {
return nexus_trans("seed-box.is_seed_box_no");
}
}
return 'Unknown';
})
->action(null)
->modalSubmitAction(false)
->modalCancelAction(false)
->modalDescription(fn () => new HtmlString(self::$checkResult['desc'] ?? ''))
// ->modalContent(fn () => new HtmlString(self::$checkResult['desc'] ?? ''))
])
->after(function() {
$this->mountAction("checkResult");
})
,
]; ];
} }
} }
@@ -0,0 +1,39 @@
<?php
namespace App\Jobs;
use App\Enums\SeedBoxRecord\IpAsnEnum;
use App\Enums\SeedBoxRecord\IsAllowedEnum;
use App\Repositories\SeedBoxRepository;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Foundation\Queue\Queueable;
class UpdateIsSeedBoxFromUserRecordsCache implements ShouldQueue
{
use Queueable;
/**
* Create a new job instance.
*/
public function __construct()
{
//
}
/**
* Execute the job.
*/
public function handle(): void
{
$rep = new SeedBoxRepository();
foreach (IpAsnEnum::cases() as $field) {
foreach (IsAllowedEnum::cases() as $isAllowed) {
$rep->updateUserCacheCronjob($isAllowed, $field);
do_log("SeedBoxRepository::updateUserCacheCronjob isAllowed: $isAllowed->name, field: $field->name success");
$rep->updateAdminCacheCronjob($isAllowed, $field);
do_log("SeedBoxRepository::updateAdminCacheCronjob isAllowed: $isAllowed->name, field: $field->name success");
}
}
do_log("UpdateIsSeedBoxFromUserRecordsCache done!");
}
}
+42
View File
@@ -2,7 +2,12 @@
namespace App\Models; namespace App\Models;
use App\Enums\SeedBoxRecord\IpAsnEnum;
use App\Enums\SeedBoxRecord\IsAllowedEnum;
use App\Enums\SeedBoxRecord\TypeEnum;
use App\Repositories\SeedBoxRepository;
use Illuminate\Database\Eloquent\Casts\Attribute; use Illuminate\Database\Eloquent\Casts\Attribute;
use Nexus\Database\NexusDB;
class SeedBoxRecord extends NexusModel class SeedBoxRecord extends NexusModel
{ {
@@ -30,6 +35,43 @@ class SeedBoxRecord extends NexusModel
self::STATUS_DENIED => ['text' => 'Denied'], self::STATUS_DENIED => ['text' => 'Denied'],
]; ];
protected static function booted(): void
{
static::saved(function (SeedBoxRecord $model) {
self::updateCache($model);
});
static::deleted(function (SeedBoxRecord $model) {
self::updateCache($model);
});
}
private static function updateCache(SeedBoxRecord $model): void
{
SeedBoxRepository::updateCache(
$model->type == TypeEnum::ADMIN->value ? 0 : $model->uid,
TypeEnum::from($model->type),
IsAllowedEnum::from($model->is_allowed),
!empty($model->ip) ? IpAsnEnum::IP : IpAsnEnum::ASN,
);
}
public static function getValidQuery(TypeEnum $type, IsAllowedEnum $isAllowed, IpAsnEnum $field)
{
$query = self::query()
->where('status', self::STATUS_ALLOWED)
->where('type', $type->value)
->where('is_allowed', $isAllowed->value)
;
if ($field == IpAsnEnum::IP) {
$query->whereNotNull("ip");
} elseif ($field == IpAsnEnum::ASN) {
$query->where("asn", ">", 0);
} else {
throw new \InvalidArgumentException("Invalid ipOrAsn");
}
return $query;
}
protected function typeText(): Attribute protected function typeText(): Attribute
{ {
return new Attribute( return new Attribute(
+1 -1
View File
@@ -80,7 +80,7 @@ class AppPanelProvider extends PanelProvider
]) ])
->navigationItems([ ->navigationItems([
NavigationItem::make('Horizon') NavigationItem::make('Horizon')
->label(nexus_trans('admin.sidebar.queue_monitor', [], Auth::user() ? get_langfolder_cookie(true) : 'en')) ->label(fn () => nexus_trans('admin.sidebar.queue_monitor', [], Auth::user() ? get_langfolder_cookie(true) : 'en'))
->icon('heroicon-o-presentation-chart-line') ->icon('heroicon-o-presentation-chart-line')
->group('System') ->group('System')
->sort(99) ->sort(99)
+201 -11
View File
@@ -1,22 +1,30 @@
<?php <?php
namespace App\Repositories; namespace App\Repositories;
use App\Events\SeedBoxRecordUpdated; use App\Enums\SeedBoxRecord\IpAsnEnum;
use App\Enums\SeedBoxRecord\IsAllowedEnum;
use App\Enums\SeedBoxRecord\TypeEnum;
use App\Exceptions\InsufficientPermissionException; use App\Exceptions\InsufficientPermissionException;
use App\Models\Message; use App\Models\Message;
use App\Models\Poll; use App\Models\Poll;
use App\Models\SeedBoxRecord; use App\Models\SeedBoxRecord;
use App\Models\Torrent;
use App\Models\User; use App\Models\User;
use GeoIp2\Database\Reader;
use Illuminate\Support\Arr; use Illuminate\Support\Arr;
use Illuminate\Support\Facades\Auth; use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Facades\DB; use MaxMind\Db\Reader\InvalidDatabaseException;
use Nexus\Database\NexusDB; use Nexus\Database\NexusDB;
use PhpIP\IP; use PhpIP\IP;
use PhpIP\IPBlock; use PhpIP\IPBlock;
class SeedBoxRepository extends BaseRepository class SeedBoxRepository extends BaseRepository
{ {
const IS_SEED_BOX_FROM_USER_RECORD_CACHE_PREFIX = "IS_SEED_BOX_FROM_USER_RECORD";
const APPROVAL_COUNT_CACHE_KEY = "SEED_BOX_RECORD_APPROVAL_NONE";
private static ?Reader $asnReader = null;
public function getList(array $params) public function getList(array $params)
{ {
$query = Poll::query(); $query = Poll::query();
@@ -33,7 +41,7 @@ class SeedBoxRepository extends BaseRepository
{ {
$params = $this->formatParams($params); $params = $this->formatParams($params);
$seedBoxRecord = SeedBoxRecord::query()->create($params); $seedBoxRecord = SeedBoxRecord::query()->create($params);
$this->clearCache(); $this->clearApprovalCountCache();
publish_model_event("seed_box_record_created", $seedBoxRecord->id); publish_model_event("seed_box_record_created", $seedBoxRecord->id);
return $seedBoxRecord; return $seedBoxRecord;
} }
@@ -102,7 +110,7 @@ class SeedBoxRepository extends BaseRepository
$model = SeedBoxRecord::query()->findOrFail($id); $model = SeedBoxRecord::query()->findOrFail($id);
$params = $this->formatParams($params); $params = $this->formatParams($params);
$model->update($params); $model->update($params);
$this->clearCache(); $this->clearApprovalCountCache();
publish_model_event("seed_box_record_updated", $id); publish_model_event("seed_box_record_updated", $id);
return $model; return $model;
} }
@@ -115,7 +123,7 @@ class SeedBoxRepository extends BaseRepository
public function delete($id, $uid) public function delete($id, $uid)
{ {
$this->clearCache(); $this->clearApprovalCountCache();
publish_model_event("seed_box_record_deleted", $id); publish_model_event("seed_box_record_deleted", $id);
return SeedBoxRecord::query()->whereIn('id', Arr::wrap($id))->where('uid', $uid)->delete(); return SeedBoxRecord::query()->whereIn('id', Arr::wrap($id))->where('uid', $uid)->delete();
} }
@@ -146,7 +154,7 @@ class SeedBoxRepository extends BaseRepository
return NexusDB::transaction(function () use ($seedBoxRecord, $status, $message) { return NexusDB::transaction(function () use ($seedBoxRecord, $status, $message) {
$seedBoxRecord->status = $status; $seedBoxRecord->status = $status;
$seedBoxRecord->save(); $seedBoxRecord->save();
$this->clearCache(); $this->clearApprovalCountCache();
return Message::add($message); return Message::add($message);
}); });
} }
@@ -173,12 +181,194 @@ class SeedBoxRepository extends BaseRepository
return '<img src="pic/misc/seed-box.png" style="vertical-align: bottom; height: 16px; margin-left: 4px" title="SeedBox" />'; return '<img src="pic/misc/seed-box.png" style="vertical-align: bottom; height: 16px; margin-left: 4px" title="SeedBox" />';
} }
private function clearCache() private function clearApprovalCountCache(): void
{ {
NexusDB::cache_del('SEED_BOX_RECORD_APPROVAL_NONE'); NexusDB::cache_del(self::APPROVAL_COUNT_CACHE_KEY);
// SeedBoxRecordUpdated::dispatch(); }
public function updateUserCacheCronjob(IsAllowedEnum $isAllowed, IpAsnEnum $field): void
{
$size = 1000;
$page = 1;
$logPrefix = "isAllowed: $isAllowed->name, field: $field->name, page: $page, size: $size";
$selectRaw = sprintf("uid, group_concat(%s) as str", $field == IpAsnEnum::ASN ? 'asn' : 'ip');
while (true) {
$list = SeedBoxRecord::getValidQuery(TypeEnum::USER, $isAllowed, $field)
->selectRaw($selectRaw)
->groupBy('uid')
->forPage($page, $size)
->get();
if ($list->isEmpty()) {
do_log("$logPrefix, no more data ...");
break;
}
foreach ($list as $record) {
$uid = $record->uid;
$str = $record->str;
do_log("$logPrefix, handling user: $uid with $field->name: $str");
self::updateCache($record->uid, TypeEnum::USER, $isAllowed, $field, $str);
do_log("$logPrefix, handling user: $uid with $field->name: $str done!");
}
$page++;
}
do_log("$logPrefix, all done!");
}
public function updateAdminCacheCronjob(IsAllowedEnum $isAllowed, IpAsnEnum $field): void
{
$size = 1000;
$page = 1;
$logPrefix = "isAllowed: $isAllowed->name, field: $field->name, page: $page, size: $size";
$fieldName = $field == IpAsnEnum::ASN ? 'asn' : 'ip';
while (true) {
$list = SeedBoxRecord::getValidQuery(TypeEnum::ADMIN, $isAllowed, $field)
->selectRaw($fieldName)
->forPage($page, $size)
->get();
if ($list->isEmpty()) {
do_log("$logPrefix, no more data ...");
break;
}
self::updateCache(0, TypeEnum::ADMIN, $isAllowed, $field, $list->pluck($fieldName)->join(","));
$page++;
}
do_log("$logPrefix, all done!");
}
public static function updateCache(int $userId, TypeEnum $type, IsAllowedEnum $isAllowed, IpAsnEnum $field, string $ipOrAsnStr = null): void
{
if (!is_null($ipOrAsnStr)) {
$list = explode(',', $ipOrAsnStr);
} else {
$query = SeedBoxRecord::getValidQuery($type, $isAllowed, $field);
if ($userId > 0) {
$query->where('uid', $userId);
}
if ($field == IpAsnEnum::IP) {
$list = $query->pluck('ip')->toArray();
} else {
$list = $query->pluck('asn')->toArray();
}
}
$list = array_filter($list);
$key = self::getCacheKey($userId, $isAllowed, $field);
do_log("userId: $userId, type: $type->name, isAllowed: $isAllowed->name, ipOrAsn: $field->name, key: $key, list: " . json_encode($list));
NexusDB::cache_del($key);
if (!empty($list)) {
NexusDB::redis()->sadd($key, ...$list);
NexusDB::redis()->expireAt($key, time() + 86400 * 30);
}
}
public static function isSeedBoxFromUserRecords(int $userId, string $ip): array
{
$logPrefix = "userId: $userId, ip: $ip";
$redis = NexusDB::redis();
//first check from asn field
$asn = self::getAsnFromIp($ip);
$uidArr = [0, $userId];
if ($asn > 0) {
//check if allowed by asn
$logPrefix .= ", asn: $asn";
foreach($uidArr as $uid) {
$key = self::getCacheKey($uid, IsAllowedEnum::YES, IpAsnEnum::ASN);
if ($redis->sismember($key, $asn)) {
$desc = "$logPrefix, asn $asn in allowed $key, result: false";
return self::buildCheckResult(false, $desc);
}
}
foreach($uidArr as $uid) {
$key = self::getCacheKey($uid, IsAllowedEnum::NO, IpAsnEnum::ASN);
if ($redis->sismember($key, $asn)) {
$desc = ("$logPrefix, asn $asn in $key, result: true");
return self::buildCheckResult(true, $desc);
}
}
}
//then check from ip field
foreach($uidArr as $uid) {
$key = self::getCacheKey($uid, IsAllowedEnum::YES, IpAsnEnum::IP);
if ($redis->sismember($key, $ip)) {
$desc = ("$logPrefix, ip $ip in allowed $key, result: false");
return self::buildCheckResult(false, $desc);
}
}
foreach($uidArr as $uid) {
$key = self::getCacheKey($uid, IsAllowedEnum::NO, IpAsnEnum::IP);
if ($redis->sismember($key, $ip)) {
$desc = ("$logPrefix, ip $ip in $key, result: true");
return self::buildCheckResult(true, $desc);
}
}
return self::buildCheckResult(false, "not match any record, result: false");
}
private static function buildCheckResult(bool $isSeedBox, string $desc): array
{
$result = [
'result' => $isSeedBox,
'desc' => $desc,
];
do_log(json_encode($result));
return $result;
}
public static function getAsnFromIp(string $ip): int
{
//虽然 ip 对应的 asn 相对固定,但不宜设置较大的缓存时间,IP 地址较多,容易引起内存膨胀
return NexusDB::remember("IP_TO_ASN:$ip", 3600, function () use ($ip) {
$reader = self::getAsnReader();
if (is_null($reader)) {
return 0;
}
$asnObj = $reader->asn($ip);
return $asnObj->autonomousSystemNumber ?? 0;
});
}
/**
* IS_SEED_BOX_FROM_USER_RECORD:IP:INCLUDES:USER:10001
* IS_SEED_BOX_FROM_USER_RECORD:IP:EXCLUDES:USER:10001
* IS_SEED_BOX_FROM_USER_RECORD:ASN:INCLUDES:USER:10001
* IS_SEED_BOX_FROM_USER_RECORD:ASN:EXCLUDES:USER:10001
* IS_SEED_BOX_FROM_USER_RECORD:ASN:EXCLUDES:ADMIN
*
* @param int $userId
* @param int $isAllowed
* @param string $field
* @return string
*/
private static function getCacheKey(int $userId, IsAllowedEnum $isAllowed, IpAsnEnum $field): string
{
$key = sprintf(
"%s:%s:%s",
self::IS_SEED_BOX_FROM_USER_RECORD_CACHE_PREFIX,
$field->name,
$isAllowed == IsAllowedEnum::YES ? "EXCLUDES" : "INCLUDES", //允许,要排队它不是 seedBox
);
if ($userId > 0) {
$key .= ":USER:$userId";
} else {
$key .= ":ADMIN";
}
return $key;
}
/**
* @throws InvalidDatabaseException
*/
private static function getAsnReader(): ?Reader
{
if (is_null(self::$asnReader)) {
$database = nexus_env('GEOIP2_ASN_DATABASE');
if (!file_exists($database) || !is_readable($database)) {
do_log("GEOIP2_ASN_DATABASE: $database not exists or not readable", "debug");
return null;
}
self::$asnReader = new Reader($database);
}
return self::$asnReader;
} }
} }
+3
View File
@@ -681,6 +681,9 @@ class UserRepository extends BaseRepository
'login_logs' => 'uid', 'login_logs' => 'uid',
'oauth_access_tokens' => 'user_id', 'oauth_access_tokens' => 'user_id',
'oauth_auth_codes' => 'user_id', 'oauth_auth_codes' => 'user_id',
'seed_box_records' => 'uid',
'user_modify_logs' => 'user_id',
'messages' => 'receiver',
]; ];
foreach ($tables as $table => $key) { foreach ($tables as $table => $key) {
NexusDB::statement(sprintf("delete from `%s` where `%s` in (%s)", $table, $key, $uidStr)); NexusDB::statement(sprintf("delete from `%s` where `%s` in (%s)", $table, $key, $uidStr));
+3 -3
View File
@@ -100,9 +100,9 @@ return [
*/ */
'trim' => [ 'trim' => [
'recent' => 60, 'recent' => 60 * 72,
'pending' => 60, 'pending' => 60 * 72,
'completed' => 60, 'completed' => 60 * 72,
'recent_failed' => 10080, 'recent_failed' => 10080,
'failed' => 10080, 'failed' => 10080,
'monitored' => 10080, 'monitored' => 10080,
@@ -0,0 +1,28 @@
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
return new class extends Migration
{
/**
* Run the migrations.
*/
public function up(): void
{
Schema::table('seed_box_records', function (Blueprint $table) {
$table->index('uid');
});
}
/**
* Reverse the migrations.
*/
public function down(): void
{
Schema::table('seed_box_records', function (Blueprint $table) {
//
});
}
};
+2 -3
View File
@@ -78,9 +78,8 @@ function peasant_to_user($down_floor_gb, $down_roof_gb, $minratio){
while ($arr = mysql_fetch_assoc($res)) while ($arr = mysql_fetch_assoc($res))
{ {
$locale = get_user_locale($arr['id']); $locale = get_user_locale($arr['id']);
$subject = nexus_trans("cleanup.msg_low_ratio_warning_removed", [], $locale); $subject = sqlesc(nexus_trans("cleanup.msg_low_ratio_warning_removed", [], $locale));
$msg = nexus_trans("cleanup.msg_your_ratio_warning_removed", [], $locale); $msg = sqlesc(nexus_trans("cleanup.msg_your_ratio_warning_removed", [], $locale));
writecomment($arr['id'],"Leech Warning removed by System."); writecomment($arr['id'],"Leech Warning removed by System.");
sql_query("UPDATE users SET class = 1, leechwarn = 'no', leechwarnuntil = null WHERE id = {$arr['id']}") or sqlerr(__FILE__, __LINE__); sql_query("UPDATE users SET class = 1, leechwarn = 'no', leechwarnuntil = null WHERE id = {$arr['id']}") or sqlerr(__FILE__, __LINE__);
sql_query("INSERT INTO messages (sender, receiver, added, subject, msg) VALUES(0, {$arr['id']}, $dt, $subject, $msg)") or sqlerr(__FILE__, __LINE__); sql_query("INSERT INTO messages (sender, receiver, added, subject, msg) VALUES(0, {$arr['id']}, $dt, $subject, $msg)") or sqlerr(__FILE__, __LINE__);
+1 -1
View File
@@ -1,6 +1,6 @@
<?php <?php
defined('VERSION_NUMBER') || define('VERSION_NUMBER', '1.9.0'); defined('VERSION_NUMBER') || define('VERSION_NUMBER', '1.9.0');
defined('RELEASE_DATE') || define('RELEASE_DATE', '2025-05-08'); defined('RELEASE_DATE') || define('RELEASE_DATE', '2025-05-11');
defined('IN_TRACKER') || define('IN_TRACKER', false); defined('IN_TRACKER') || define('IN_TRACKER', false);
defined('PROJECTNAME') || define("PROJECTNAME","NexusPHP"); defined('PROJECTNAME') || define("PROJECTNAME","NexusPHP");
defined('NEXUSPHPURL') || define("NEXUSPHPURL","https://nexusphp.org"); defined('NEXUSPHPURL') || define("NEXUSPHPURL","https://nexusphp.org");
+1 -1
View File
@@ -2812,7 +2812,7 @@ if ($msgalert)
//seed box approval //seed box approval
if (get_user_class() >= \App\Models\User::CLASS_ADMINISTRATOR && get_setting('seed_box.enabled') == 'yes') { if (get_user_class() >= \App\Models\User::CLASS_ADMINISTRATOR && get_setting('seed_box.enabled') == 'yes') {
$cacheKey = 'SEED_BOX_RECORD_APPROVAL_NONE'; $cacheKey = \App\Repositories\SeedBoxRepository::APPROVAL_COUNT_CACHE_KEY;
$toApprovalCounts = $Cache->get_value($cacheKey); $toApprovalCounts = $Cache->get_value($cacheKey);
if ($toApprovalCounts === false) { if ($toApprovalCounts === false) {
$toApprovalCounts = get_row_count('seed_box_records', 'where status = 0'); $toApprovalCounts = get_row_count('seed_box_records', 'where status = 0');
+9
View File
@@ -915,6 +915,15 @@ function isIPSeedBoxFromASN($ip, $exceptionWhenYes = false): bool
return $result; return $result;
} }
/**
* @deprecated
* @param $ip
* @param $uid
* @param $withoutCache
* @param $exceptionWhenYes
* @return bool
* @throws \App\Exceptions\SeedBoxYesException
*/
function isIPSeedBox($ip, $uid, $withoutCache = false, $exceptionWhenYes = false): bool function isIPSeedBox($ip, $uid, $withoutCache = false, $exceptionWhenYes = false): bool
{ {
$key = "nexus_is_ip_seed_box:ip:$ip:uid:$uid"; $key = "nexus_is_ip_seed_box:ip:$ip:uid:$uid";
+2 -2
View File
@@ -337,10 +337,10 @@ $isSeedBoxRuleEnabled = get_setting('seed_box.enabled') == 'yes';
$isIPSeedBox = false; $isIPSeedBox = false;
if ($isSeedBoxRuleEnabled) { if ($isSeedBoxRuleEnabled) {
if (!empty($ipv4)) { if (!empty($ipv4)) {
$isIPSeedBox = isIPSeedBox($ipv4, $userid); $isIPSeedBox = \App\Repositories\SeedBoxRepository::isSeedBoxFromUserRecords($userid, $ipv4)['result'];
} }
if (!$isIPSeedBox && !empty($ipv6)) { if (!$isIPSeedBox && !empty($ipv6)) {
$isIPSeedBox = isIPSeedBox($ipv6, $userid); $isIPSeedBox = \App\Repositories\SeedBoxRepository::isSeedBoxFromUserRecords($userid, $ipv6)['result'];
} }
} }
$log .= ", [SEED_BOX], isSeedBoxRuleEnabled: $isSeedBoxRuleEnabled, isIPSeedBox: $isIPSeedBox"; $log .= ", [SEED_BOX], isSeedBoxRuleEnabled: $isSeedBoxRuleEnabled, isIPSeedBox: $isIPSeedBox";
+6 -12
View File
@@ -1007,8 +1007,8 @@ if (get_setting('seed_box.enabled') == 'yes') {
$seedBox = ''; $seedBox = '';
$columnOperator = nexus_trans('label.seed_box_record.operator'); $columnOperator = nexus_trans('label.seed_box_record.operator');
$columnBandwidth = nexus_trans('label.seed_box_record.bandwidth'); $columnBandwidth = nexus_trans('label.seed_box_record.bandwidth');
$columnIPBegin = nexus_trans('label.seed_box_record.ip_begin'); // $columnIPBegin = nexus_trans('label.seed_box_record.ip_begin');
$columnIPEnd = nexus_trans('label.seed_box_record.ip_end'); // $columnIPEnd = nexus_trans('label.seed_box_record.ip_end');
$columnIP = nexus_trans('label.seed_box_record.ip'); $columnIP = nexus_trans('label.seed_box_record.ip');
$columnIPHelp = nexus_trans('label.seed_box_record.ip_help'); $columnIPHelp = nexus_trans('label.seed_box_record.ip_help');
$columnComment = nexus_trans('label.comment'); $columnComment = nexus_trans('label.comment');
@@ -1068,14 +1068,6 @@ CSS;
<div class="label">{$columnBandwidth}</div> <div class="label">{$columnBandwidth}</div>
<div class="field"><input type="number" name="params[bandwidth]"></div> <div class="field"><input type="number" name="params[bandwidth]"></div>
</div> </div>
<div class="form-control-row">
<div class="label">{$columnIPBegin}</div>
<div class="field"><input type="text" name="params[ip_begin]"></div>
</div>
<div class="form-control-row">
<div class="label">{$columnIPEnd}</div>
<div class="field"><input type="text" name="params[ip_end]"></div>
</div>
<div class="form-control-row"> <div class="form-control-row">
<div class="label">{$columnIP}</div> <div class="label">{$columnIP}</div>
<div class="field"><input type="text" name="params[ip]"><div><small>{$columnIPHelp}</small></div></div> <div class="field"><input type="text" name="params[ip]"><div><small>{$columnIPHelp}</small></div></div>
@@ -1097,8 +1089,9 @@ jQuery('#add-seed-box-btn').on('click', function () {
btnAlign: 'c', btnAlign: 'c',
yes: function () { yes: function () {
let params = jQuery('#seed-box-form').serialize() let params = jQuery('#seed-box-form').serialize()
jQuery('body').loading({stoppable: false});
jQuery.post('ajax.php', params + "&action=addSeedBoxRecord", function (response) { jQuery.post('ajax.php', params + "&action=addSeedBoxRecord", function (response) {
console.log(response) jQuery('body').loading('stop');
if (response.ret != 0) { if (response.ret != 0) {
layer.alert(response.msg) layer.alert(response.msg)
return return
@@ -1111,8 +1104,9 @@ jQuery('#add-seed-box-btn').on('click', function () {
jQuery('#seed-box-table').on('click', '.remove-seed-box-btn', function () { jQuery('#seed-box-table').on('click', '.remove-seed-box-btn', function () {
let params = {action: "removeSeedBoxRecord", params: {id: jQuery(this).attr("data-id")}} let params = {action: "removeSeedBoxRecord", params: {id: jQuery(this).attr("data-id")}}
layer.confirm("{$lang_functions['std_confirm_remove']}", window.nexusLayerOptions.confirm, function (index) { layer.confirm("{$lang_functions['std_confirm_remove']}", window.nexusLayerOptions.confirm, function (index) {
jQuery('body').loading({stoppable: false});
jQuery.post('ajax.php', params, function (response) { jQuery.post('ajax.php', params, function (response) {
console.log(response) jQuery('body').loading('stop');
if (response.ret != 0) { if (response.ret != 0) {
layer.alert(response.msg, window.nexusLayerOptions.alert) layer.alert(response.msg, window.nexusLayerOptions.alert)
return return
+333 -113
View File
File diff suppressed because it is too large Load Diff
File diff suppressed because one or more lines are too long
+264 -48
View File
@@ -370,9 +370,7 @@
if (key === "") if (key === "")
return object; return object;
return key.split(".").reduce((carry, i) => { return key.split(".").reduce((carry, i) => {
if (carry === void 0) return carry?.[i];
return void 0;
return carry[i];
}, object); }, object);
} }
function dataSet(object, key, value) { function dataSet(object, key, value) {
@@ -499,6 +497,9 @@
if (value === null || value === "") { if (value === null || value === "") {
el.value = ""; el.value = "";
} }
if (el.multiple && Array.isArray(value) && value.length === 0) {
el.value = "";
}
}); });
let clearFileInputValue = () => { let clearFileInputValue = () => {
el.value = null; el.value = null;
@@ -901,7 +902,7 @@
deferredMutations = deferredMutations.concat(mutations); deferredMutations = deferredMutations.concat(mutations);
return; return;
} }
let addedNodes = /* @__PURE__ */ new Set(); let addedNodes = [];
let removedNodes = /* @__PURE__ */ new Set(); let removedNodes = /* @__PURE__ */ new Set();
let addedAttributes = /* @__PURE__ */ new Map(); let addedAttributes = /* @__PURE__ */ new Map();
let removedAttributes = /* @__PURE__ */ new Map(); let removedAttributes = /* @__PURE__ */ new Map();
@@ -909,8 +910,24 @@
if (mutations[i].target._x_ignoreMutationObserver) if (mutations[i].target._x_ignoreMutationObserver)
continue; continue;
if (mutations[i].type === "childList") { if (mutations[i].type === "childList") {
mutations[i].addedNodes.forEach((node) => node.nodeType === 1 && addedNodes.add(node)); mutations[i].removedNodes.forEach((node) => {
mutations[i].removedNodes.forEach((node) => node.nodeType === 1 && removedNodes.add(node)); if (node.nodeType !== 1)
return;
if (!node._x_marker)
return;
removedNodes.add(node);
});
mutations[i].addedNodes.forEach((node) => {
if (node.nodeType !== 1)
return;
if (removedNodes.has(node)) {
removedNodes.delete(node);
return;
}
if (node._x_marker)
return;
addedNodes.push(node);
});
} }
if (mutations[i].type === "attributes") { if (mutations[i].type === "attributes") {
let el = mutations[i].target; let el = mutations[i].target;
@@ -943,29 +960,15 @@
onAttributeAddeds.forEach((i) => i(el, attrs)); onAttributeAddeds.forEach((i) => i(el, attrs));
}); });
for (let node of removedNodes) { for (let node of removedNodes) {
if (addedNodes.has(node)) if (addedNodes.some((i) => i.contains(node)))
continue; continue;
onElRemoveds.forEach((i) => i(node)); onElRemoveds.forEach((i) => i(node));
} }
addedNodes.forEach((node) => {
node._x_ignoreSelf = true;
node._x_ignore = true;
});
for (let node of addedNodes) { for (let node of addedNodes) {
if (removedNodes.has(node))
continue;
if (!node.isConnected) if (!node.isConnected)
continue; continue;
delete node._x_ignoreSelf;
delete node._x_ignore;
onElAddeds.forEach((i) => i(node)); onElAddeds.forEach((i) => i(node));
node._x_ignore = true;
node._x_ignoreSelf = true;
} }
addedNodes.forEach((node) => {
delete node._x_ignoreSelf;
delete node._x_ignore;
});
addedNodes = null; addedNodes = null;
removedNodes = null; removedNodes = null;
addedAttributes = null; addedAttributes = null;
@@ -1468,13 +1471,20 @@ ${expression ? 'Expression: "' + expression + '"\n\n' : ""}`, el);
function interceptInit(callback) { function interceptInit(callback) {
initInterceptors2.push(callback); initInterceptors2.push(callback);
} }
var markerDispenser = 1;
function initTree(el, walker = walk, intercept = () => { function initTree(el, walker = walk, intercept = () => {
}) { }) {
if (findClosest(el, (i) => i._x_ignore))
return;
deferHandlingDirectives(() => { deferHandlingDirectives(() => {
walker(el, (el2, skip) => { walker(el, (el2, skip) => {
if (el2._x_marker)
return;
intercept(el2, skip); intercept(el2, skip);
initInterceptors2.forEach((i) => i(el2, skip)); initInterceptors2.forEach((i) => i(el2, skip));
directives(el2, el2.attributes).forEach((handle) => handle()); directives(el2, el2.attributes).forEach((handle) => handle());
if (!el2._x_ignore)
el2._x_marker = markerDispenser++;
el2._x_ignore && skip(); el2._x_ignore && skip();
}); });
}); });
@@ -1483,6 +1493,7 @@ ${expression ? 'Expression: "' + expression + '"\n\n' : ""}`, el);
walker(root, (el) => { walker(root, (el) => {
cleanupElement(el); cleanupElement(el);
cleanupAttributes(el); cleanupAttributes(el);
delete el._x_marker;
}); });
} }
function warnAboutMissingPlugins() { function warnAboutMissingPlugins() {
@@ -2284,7 +2295,7 @@ ${expression ? 'Expression: "' + expression + '"\n\n' : ""}`, el);
get raw() { get raw() {
return raw; return raw;
}, },
version: "3.14.3", version: "3.14.9",
flushAndStopDeferringMutations, flushAndStopDeferringMutations,
dontAutoEvaluateFunctions, dontAutoEvaluateFunctions,
disableEffectScheduling, disableEffectScheduling,
@@ -3131,7 +3142,6 @@ ${expression ? 'Expression: "' + expression + '"\n\n' : ""}`, el);
placeInDom(clone2, target, modifiers); placeInDom(clone2, target, modifiers);
skipDuringClone(() => { skipDuringClone(() => {
initTree(clone2); initTree(clone2);
clone2._x_ignore = true;
})(); })();
}); });
el._x_teleportPutBack = () => { el._x_teleportPutBack = () => {
@@ -4353,9 +4363,11 @@ ${expression ? 'Expression: "' + expression + '"\n\n' : ""}`, el);
"on": "$on", "on": "$on",
"el": "$el", "el": "$el",
"id": "$id", "id": "$id",
"js": "$js",
"get": "$get", "get": "$get",
"set": "$set", "set": "$set",
"call": "$call", "call": "$call",
"hook": "$hook",
"commit": "$commit", "commit": "$commit",
"watch": "$watch", "watch": "$watch",
"entangle": "$entangle", "entangle": "$entangle",
@@ -4423,6 +4435,14 @@ ${expression ? 'Expression: "' + expression + '"\n\n' : ""}`, el);
wireProperty("$id", (component) => { wireProperty("$id", (component) => {
return component.id; return component.id;
}); });
wireProperty("$js", (component) => {
let fn = component.addJsAction.bind(component);
let jsActions = component.getJsActions();
Object.keys(jsActions).forEach((name) => {
fn[name] = component.getJsAction(name);
});
return fn;
});
wireProperty("$set", (component) => async (property, value, live = true) => { wireProperty("$set", (component) => async (property, value, live = true) => {
dataSet(component.reactive, property, value); dataSet(component.reactive, property, value);
if (live) { if (live) {
@@ -4450,6 +4470,16 @@ ${expression ? 'Expression: "' + expression + '"\n\n' : ""}`, el);
wireProperty("$refresh", (component) => component.$wire.$commit); wireProperty("$refresh", (component) => component.$wire.$commit);
wireProperty("$commit", (component) => async () => await requestCommit(component)); wireProperty("$commit", (component) => async () => await requestCommit(component));
wireProperty("$on", (component) => (...params) => listen2(component, ...params)); wireProperty("$on", (component) => (...params) => listen2(component, ...params));
wireProperty("$hook", (component) => (name, callback) => {
let unhook = on2(name, ({ component: hookComponent, ...params }) => {
if (hookComponent === void 0)
return callback(params);
if (hookComponent.id === component.id)
return callback({ component: hookComponent, ...params });
});
component.addCleanup(unhook);
return unhook;
});
wireProperty("$dispatch", (component) => (...params) => dispatch3(component, ...params)); wireProperty("$dispatch", (component) => (...params) => dispatch3(component, ...params));
wireProperty("$dispatchSelf", (component) => (...params) => dispatchSelf(component, ...params)); wireProperty("$dispatchSelf", (component) => (...params) => dispatchSelf(component, ...params));
wireProperty("$dispatchTo", () => (...params) => dispatchTo(...params)); wireProperty("$dispatchTo", () => (...params) => dispatchTo(...params));
@@ -4508,6 +4538,7 @@ ${expression ? 'Expression: "' + expression + '"\n\n' : ""}`, el);
this.ephemeral = extractData(deepClone(this.snapshot.data)); this.ephemeral = extractData(deepClone(this.snapshot.data));
this.reactive = Alpine.reactive(this.ephemeral); this.reactive = Alpine.reactive(this.ephemeral);
this.queuedUpdates = {}; this.queuedUpdates = {};
this.jsActions = {};
this.$wire = generateWireObject(this, this.reactive); this.$wire = generateWireObject(this, this.reactive);
this.cleanups = []; this.cleanups = [];
this.processEffects(this.effects); this.processEffects(this.effects);
@@ -4583,6 +4614,18 @@ ${expression ? 'Expression: "' + expression + '"\n\n' : ""}`, el);
} }
el.setAttribute("wire:effects", JSON.stringify(effects)); el.setAttribute("wire:effects", JSON.stringify(effects));
} }
addJsAction(name, action) {
this.jsActions[name] = action;
}
hasJsAction(name) {
return this.jsActions[name] !== void 0;
}
getJsAction(name) {
return this.jsActions[name].bind(this.$wire);
}
getJsActions() {
return this.jsActions;
}
addCleanup(cleanup2) { addCleanup(cleanup2) {
this.cleanups.push(cleanup2); this.cleanups.push(cleanup2);
} }
@@ -4709,6 +4752,16 @@ ${expression ? 'Expression: "' + expression + '"\n\n' : ""}`, el);
} }
}); });
} }
function globalDirective(name, callback) {
if (customDirectiveNames.has(name))
return;
customDirectiveNames.add(name);
on2("directive.global.init", ({ el, directive: directive3, cleanup: cleanup2 }) => {
if (directive3.value === name) {
callback({ el, directive: directive3, cleanup: cleanup2 });
}
});
}
function getDirectives(el) { function getDirectives(el) {
return new DirectiveManager(el); return new DirectiveManager(el);
} }
@@ -4771,7 +4824,7 @@ ${expression ? 'Expression: "' + expression + '"\n\n' : ""}`, el);
} }
}; };
// ../../../../usr/local/lib/node_modules/@alpinejs/collapse/dist/module.esm.js // ../alpine/packages/collapse/dist/module.esm.js
function src_default2(Alpine3) { function src_default2(Alpine3) {
Alpine3.directive("collapse", collapse); Alpine3.directive("collapse", collapse);
collapse.inline = (el, { modifiers }) => { collapse.inline = (el, { modifiers }) => {
@@ -4821,7 +4874,7 @@ ${expression ? 'Expression: "' + expression + '"\n\n' : ""}`, el);
start: { height: current + "px" }, start: { height: current + "px" },
end: { height: full + "px" } end: { height: full + "px" }
}, () => el._x_isShown = true, () => { }, () => el._x_isShown = true, () => {
if (el.getBoundingClientRect().height == full) { if (Math.abs(el.getBoundingClientRect().height - full) < 1) {
el.style.overflow = null; el.style.overflow = null;
} }
}); });
@@ -4865,7 +4918,7 @@ ${expression ? 'Expression: "' + expression + '"\n\n' : ""}`, el);
} }
var module_default2 = src_default2; var module_default2 = src_default2;
// ../../../../usr/local/lib/node_modules/@alpinejs/focus/dist/module.esm.js // ../alpine/packages/focus/dist/module.esm.js
var candidateSelectors = ["input", "select", "textarea", "a[href]", "button", "[tabindex]:not(slot)", "audio[controls]", "video[controls]", '[contenteditable]:not([contenteditable="false"])', "details>summary:first-of-type", "details"]; var candidateSelectors = ["input", "select", "textarea", "a[href]", "button", "[tabindex]:not(slot)", "audio[controls]", "video[controls]", '[contenteditable]:not([contenteditable="false"])', "details>summary:first-of-type", "details"];
var candidateSelector = /* @__PURE__ */ candidateSelectors.join(","); var candidateSelector = /* @__PURE__ */ candidateSelectors.join(",");
var NoElement = typeof Element === "undefined"; var NoElement = typeof Element === "undefined";
@@ -5814,7 +5867,7 @@ ${expression ? 'Expression: "' + expression + '"\n\n' : ""}`, el);
} }
var module_default3 = src_default3; var module_default3 = src_default3;
// ../../../../usr/local/lib/node_modules/@alpinejs/persist/dist/module.esm.js // ../alpine/packages/persist/dist/module.esm.js
function src_default4(Alpine3) { function src_default4(Alpine3) {
let persist = () => { let persist = () => {
let alias; let alias;
@@ -5876,7 +5929,7 @@ ${expression ? 'Expression: "' + expression + '"\n\n' : ""}`, el);
} }
var module_default4 = src_default4; var module_default4 = src_default4;
// ../../../../usr/local/lib/node_modules/@alpinejs/intersect/dist/module.esm.js // ../alpine/packages/intersect/dist/module.esm.js
function src_default5(Alpine3) { function src_default5(Alpine3) {
Alpine3.directive("intersect", Alpine3.skipDuringClone((el, { value, expression, modifiers }, { evaluateLater: evaluateLater2, cleanup: cleanup2 }) => { Alpine3.directive("intersect", Alpine3.skipDuringClone((el, { value, expression, modifiers }, { evaluateLater: evaluateLater2, cleanup: cleanup2 }) => {
let evaluate3 = evaluateLater2(expression); let evaluate3 = evaluateLater2(expression);
@@ -7633,6 +7686,8 @@ ${expression ? 'Expression: "' + expression + '"\n\n' : ""}`, el);
// js/plugins/navigate/popover.js // js/plugins/navigate/popover.js
function packUpPersistedPopovers(persistedEl) { function packUpPersistedPopovers(persistedEl) {
if (!isPopoverSupported())
return;
persistedEl.querySelectorAll(":popover-open").forEach((el) => { persistedEl.querySelectorAll(":popover-open").forEach((el) => {
el.setAttribute("data-navigate-popover-open", ""); el.setAttribute("data-navigate-popover-open", "");
let animations = el.getAnimations(); let animations = el.getAnimations();
@@ -7651,6 +7706,8 @@ ${expression ? 'Expression: "' + expression + '"\n\n' : ""}`, el);
}); });
} }
function unPackPersistedPopovers(persistedEl) { function unPackPersistedPopovers(persistedEl) {
if (!isPopoverSupported())
return;
persistedEl.querySelectorAll("[data-navigate-popover-open]").forEach((el) => { persistedEl.querySelectorAll("[data-navigate-popover-open]").forEach((el) => {
el.removeAttribute("data-navigate-popover-open"); el.removeAttribute("data-navigate-popover-open");
queueMicrotask(() => { queueMicrotask(() => {
@@ -7668,6 +7725,9 @@ ${expression ? 'Expression: "' + expression + '"\n\n' : ""}`, el);
}); });
}); });
} }
function isPopoverSupported() {
return typeof document.createElement("div").showPopover === "function";
}
// js/plugins/navigate/page.js // js/plugins/navigate/page.js
var oldBodyScriptTagHashes = []; var oldBodyScriptTagHashes = [];
@@ -7677,6 +7737,7 @@ ${expression ? 'Expression: "' + expression + '"\n\n' : ""}`, el);
]; ];
function swapCurrentPageWithNewHtml(html, andThen) { function swapCurrentPageWithNewHtml(html, andThen) {
let newDocument = new DOMParser().parseFromString(html, "text/html"); let newDocument = new DOMParser().parseFromString(html, "text/html");
let newHtml = newDocument.documentElement;
let newBody = document.adoptNode(newDocument.body); let newBody = document.adoptNode(newDocument.body);
let newHead = document.adoptNode(newDocument.head); let newHead = document.adoptNode(newDocument.head);
oldBodyScriptTagHashes = oldBodyScriptTagHashes.concat(Array.from(document.body.querySelectorAll("script")).map((i) => { oldBodyScriptTagHashes = oldBodyScriptTagHashes.concat(Array.from(document.body.querySelectorAll("script")).map((i) => {
@@ -7684,6 +7745,7 @@ ${expression ? 'Expression: "' + expression + '"\n\n' : ""}`, el);
})); }));
let afterRemoteScriptsHaveLoaded = () => { let afterRemoteScriptsHaveLoaded = () => {
}; };
replaceHtmlAttributes(newHtml);
mergeNewHead(newHead).finally(() => { mergeNewHead(newHead).finally(() => {
afterRemoteScriptsHaveLoaded(); afterRemoteScriptsHaveLoaded();
}); });
@@ -7703,6 +7765,21 @@ ${expression ? 'Expression: "' + expression + '"\n\n' : ""}`, el);
i.replaceWith(cloneScriptTag(i)); i.replaceWith(cloneScriptTag(i));
}); });
} }
function replaceHtmlAttributes(newHtmlElement) {
let currentHtmlElement = document.documentElement;
Array.from(newHtmlElement.attributes).forEach((attr) => {
const name = attr.name;
const value = attr.value;
if (currentHtmlElement.getAttribute(name) !== value) {
currentHtmlElement.setAttribute(name, value);
}
});
Array.from(currentHtmlElement.attributes).forEach((attr) => {
if (!newHtmlElement.hasAttribute(attr.name)) {
currentHtmlElement.removeAttribute(attr.name);
}
});
}
function mergeNewHead(newHead) { function mergeNewHead(newHead) {
let children = Array.from(document.head.children); let children = Array.from(document.head.children);
let headChildrenHtmlLookup = children.map((i) => i.outerHTML); let headChildrenHtmlLookup = children.map((i) => i.outerHTML);
@@ -7736,6 +7813,8 @@ ${expression ? 'Expression: "' + expression + '"\n\n' : ""}`, el);
child.remove(); child.remove();
} }
for (let child of Array.from(newHead.children)) { for (let child of Array.from(newHead.children)) {
if (child.tagName.toLowerCase() === "noscript")
continue;
document.head.appendChild(child); document.head.appendChild(child);
} }
return Promise.all(remoteScriptsPromises); return Promise.all(remoteScriptsPromises);
@@ -8083,14 +8162,22 @@ ${expression ? 'Expression: "' + expression + '"\n\n' : ""}`, el);
if (!state.alpine) if (!state.alpine)
state.alpine = {}; state.alpine = {};
state.alpine[key] = unwrap(object); state.alpine[key] = unwrap(object);
window.history.replaceState(state, "", url.toString()); try {
window.history.replaceState(state, "", url.toString());
} catch (e) {
console.error(e);
}
} }
function push(url, key, object) { function push(url, key, object) {
let state = window.history.state || {}; let state = window.history.state || {};
if (!state.alpine) if (!state.alpine)
state.alpine = {}; state.alpine = {};
state = { alpine: { ...state.alpine, ...{ [key]: unwrap(object) } } }; state = { alpine: { ...state.alpine, ...{ [key]: unwrap(object) } } };
window.history.pushState(state, "", url.toString()); try {
window.history.pushState(state, "", url.toString());
} catch (e) {
console.error(e);
}
} }
function unwrap(object) { function unwrap(object) {
if (object === void 0) if (object === void 0)
@@ -8103,24 +8190,24 @@ ${expression ? 'Expression: "' + expression + '"\n\n' : ""}`, el);
let search = url.search; let search = url.search;
if (!search) if (!search)
return false; return false;
let data2 = fromQueryString(search); let data2 = fromQueryString(search, key);
return Object.keys(data2).includes(key); return Object.keys(data2).includes(key);
}, },
get(url, key) { get(url, key) {
let search = url.search; let search = url.search;
if (!search) if (!search)
return false; return false;
let data2 = fromQueryString(search); let data2 = fromQueryString(search, key);
return data2[key]; return data2[key];
}, },
set(url, key, value) { set(url, key, value) {
let data2 = fromQueryString(url.search); let data2 = fromQueryString(url.search, key);
data2[key] = stripNulls(unwrap(value)); data2[key] = stripNulls(unwrap(value));
url.search = toQueryString(data2); url.search = toQueryString(data2);
return url; return url;
}, },
remove(url, key) { remove(url, key) {
let data2 = fromQueryString(url.search); let data2 = fromQueryString(url.search, key);
delete data2[key]; delete data2[key];
url.search = toQueryString(data2); url.search = toQueryString(data2);
return url; return url;
@@ -8156,7 +8243,7 @@ ${expression ? 'Expression: "' + expression + '"\n\n' : ""}`, el);
let entries = buildQueryStringEntries(data2); let entries = buildQueryStringEntries(data2);
return Object.entries(entries).map(([key, value]) => `${key}=${value}`).join("&"); return Object.entries(entries).map(([key, value]) => `${key}=${value}`).join("&");
} }
function fromQueryString(search) { function fromQueryString(search, queryKey) {
search = search.replace("?", ""); search = search.replace("?", "");
if (search === "") if (search === "")
return {}; return {};
@@ -8175,10 +8262,12 @@ ${expression ? 'Expression: "' + expression + '"\n\n' : ""}`, el);
if (typeof value == "undefined") if (typeof value == "undefined")
return; return;
value = decodeURIComponent(value.replaceAll("+", "%20")); value = decodeURIComponent(value.replaceAll("+", "%20"));
if (!key.includes("[")) { let decodedKey = decodeURIComponent(key);
let shouldBeHandledAsArray = decodedKey.includes("[") && decodedKey.startsWith(queryKey);
if (!shouldBeHandledAsArray) {
data2[key] = value; data2[key] = value;
} else { } else {
let dotNotatedKey = key.replaceAll("[", ".").replaceAll("]", ""); let dotNotatedKey = decodedKey.replaceAll("[", ".").replaceAll("]", "");
insertDotNotatedValueIntoData(dotNotatedKey, value, data2); insertDotNotatedValueIntoData(dotNotatedKey, value, data2);
} }
}); });
@@ -8209,7 +8298,8 @@ ${expression ? 'Expression: "' + expression + '"\n\n' : ""}`, el);
return swapElements(from2, to); return swapElements(from2, to);
} }
let updateChildrenOnly = false; let updateChildrenOnly = false;
if (shouldSkip(updating, from2, to, () => updateChildrenOnly = true)) let skipChildren = false;
if (shouldSkipChildren(updating, () => skipChildren = true, from2, to, () => updateChildrenOnly = true))
return; return;
if (from2.nodeType === 1 && window.Alpine) { if (from2.nodeType === 1 && window.Alpine) {
window.Alpine.cloneNode(from2, to); window.Alpine.cloneNode(from2, to);
@@ -8226,7 +8316,9 @@ ${expression ? 'Expression: "' + expression + '"\n\n' : ""}`, el);
patchAttributes(from2, to); patchAttributes(from2, to);
} }
updated(from2, to); updated(from2, to);
patchChildren(from2, to); if (!skipChildren) {
patchChildren(from2, to);
}
} }
function differentElementNamesTypesOrKeys(from2, to) { function differentElementNamesTypesOrKeys(from2, to) {
return from2.nodeType != to.nodeType || from2.nodeName != to.nodeName || getKey(from2) != getKey(to); return from2.nodeType != to.nodeType || from2.nodeName != to.nodeName || getKey(from2) != getKey(to);
@@ -8286,6 +8378,7 @@ ${expression ? 'Expression: "' + expression + '"\n\n' : ""}`, el);
let holdover = fromKeyHoldovers[toKey]; let holdover = fromKeyHoldovers[toKey];
from2.appendChild(holdover); from2.appendChild(holdover);
currentFrom = holdover; currentFrom = holdover;
fromKey = getKey(currentFrom);
} else { } else {
if (!shouldSkip(adding, currentTo)) { if (!shouldSkip(adding, currentTo)) {
let clone2 = currentTo.cloneNode(true); let clone2 = currentTo.cloneNode(true);
@@ -8359,6 +8452,7 @@ ${expression ? 'Expression: "' + expression + '"\n\n' : ""}`, el);
if (fromKeys[toKey]) { if (fromKeys[toKey]) {
currentFrom.replaceWith(fromKeys[toKey]); currentFrom.replaceWith(fromKeys[toKey]);
currentFrom = fromKeys[toKey]; currentFrom = fromKeys[toKey];
fromKey = getKey(currentFrom);
} }
} }
if (toKey && fromKey) { if (toKey && fromKey) {
@@ -8367,6 +8461,7 @@ ${expression ? 'Expression: "' + expression + '"\n\n' : ""}`, el);
fromKeyHoldovers[fromKey] = currentFrom; fromKeyHoldovers[fromKey] = currentFrom;
currentFrom.replaceWith(fromKeyNode); currentFrom.replaceWith(fromKeyNode);
currentFrom = fromKeyNode; currentFrom = fromKeyNode;
fromKey = getKey(currentFrom);
} else { } else {
fromKeyHoldovers[fromKey] = currentFrom; fromKeyHoldovers[fromKey] = currentFrom;
currentFrom = addNodeBefore(from2, currentTo, currentFrom); currentFrom = addNodeBefore(from2, currentTo, currentFrom);
@@ -8437,6 +8532,11 @@ ${expression ? 'Expression: "' + expression + '"\n\n' : ""}`, el);
hook(...args, () => skip = true); hook(...args, () => skip = true);
return skip; return skip;
} }
function shouldSkipChildren(hook, skipChildren, ...args) {
let skip = false;
hook(...args, () => skip = true, skipChildren);
return skip;
}
var patched = false; var patched = false;
function createElement(html) { function createElement(html) {
const template = document.createElement("template"); const template = document.createElement("template");
@@ -8512,6 +8612,8 @@ ${expression ? 'Expression: "' + expression + '"\n\n' : ""}`, el);
let fromId = from && from._x_bindings && from._x_bindings.id; let fromId = from && from._x_bindings && from._x_bindings.id;
if (!fromId) if (!fromId)
return; return;
if (!to.setAttribute)
return;
to.setAttribute("id", fromId); to.setAttribute("id", fromId);
to.id = fromId; to.id = fromId;
} }
@@ -8520,7 +8622,7 @@ ${expression ? 'Expression: "' + expression + '"\n\n' : ""}`, el);
} }
var module_default8 = src_default8; var module_default8 = src_default8;
// ../../../../usr/local/lib/node_modules/@alpinejs/mask/dist/module.esm.js // ../alpine/packages/mask/dist/module.esm.js
function src_default9(Alpine3) { function src_default9(Alpine3) {
Alpine3.directive("mask", (el, { value, expression }, { effect: effect3, evaluateLater: evaluateLater2, cleanup: cleanup2 }) => { Alpine3.directive("mask", (el, { value, expression }, { effect: effect3, evaluateLater: evaluateLater2, cleanup: cleanup2 }) => {
let templateFn = () => expression; let templateFn = () => expression;
@@ -8546,8 +8648,13 @@ ${expression ? 'Expression: "' + expression + '"\n\n' : ""}`, el);
} else { } else {
processInputValue(el, false); processInputValue(el, false);
} }
if (el._x_model) if (el._x_model) {
if (el._x_model.get() === el.value)
return;
if (el._x_model.get() === null && el.value === "")
return;
el._x_model.set(el.value); el._x_model.set(el.value);
}
}); });
const controller = new AbortController(); const controller = new AbortController();
cleanup2(() => { cleanup2(() => {
@@ -8725,10 +8832,15 @@ ${expression ? 'Expression: "' + expression + '"\n\n' : ""}`, el);
destroyComponent(component2.id); destroyComponent(component2.id);
}); });
} }
let directives2 = Array.from(el.getAttributeNames()).filter((name) => matchesForLivewireDirective(name)).map((name) => extractDirective(el, name));
directives2.forEach((directive3) => {
trigger2("directive.global.init", { el, directive: directive3, cleanup: (callback) => {
module_default.onAttributeRemoved(el, directive3.raw, callback);
} });
});
let component = closestComponent(el, false); let component = closestComponent(el, false);
if (component) { if (component) {
trigger2("element.init", { el, component }); trigger2("element.init", { el, component });
let directives2 = Array.from(el.getAttributeNames()).filter((name) => matchesForLivewireDirective(name)).map((name) => extractDirective(el, name));
directives2.forEach((directive3) => { directives2.forEach((directive3) => {
trigger2("directive.init", { el, component, directive: directive3, cleanup: (callback) => { trigger2("directive.init", { el, component, directive: directive3, cleanup: (callback) => {
module_default.onAttributeRemoved(el, directive3.raw, callback); module_default.onAttributeRemoved(el, directive3.raw, callback);
@@ -8804,7 +8916,7 @@ ${expression ? 'Expression: "' + expression + '"\n\n' : ""}`, el);
onlyIfScriptHasntBeenRunAlreadyForThisComponent(component, key, () => { onlyIfScriptHasntBeenRunAlreadyForThisComponent(component, key, () => {
let scriptContent = extractScriptTagContent(content); let scriptContent = extractScriptTagContent(content);
module_default.dontAutoEvaluateFunctions(() => { module_default.dontAutoEvaluateFunctions(() => {
module_default.evaluate(component.el, scriptContent, { "$wire": component.$wire }); module_default.evaluate(component.el, scriptContent, { "$wire": component.$wire, "$js": component.$wire.$js });
}); });
}); });
}); });
@@ -8876,6 +8988,10 @@ ${expression ? 'Expression: "' + expression + '"\n\n' : ""}`, el);
} }
// js/features/supportJsEvaluation.js // js/features/supportJsEvaluation.js
module_default.magic("js", (el) => {
let component = closestComponent(el);
return component.$wire.js;
});
on2("effect", ({ component, effects }) => { on2("effect", ({ component, effects }) => {
let js = effects.js; let js = effects.js;
let xjs = effects.xjs; let xjs = effects.xjs;
@@ -8887,8 +9003,9 @@ ${expression ? 'Expression: "' + expression + '"\n\n' : ""}`, el);
}); });
} }
if (xjs) { if (xjs) {
xjs.forEach((expression) => { xjs.forEach(({ expression, params }) => {
module_default.evaluate(component.el, expression); params = Object.values(params);
module_default.evaluate(component.el, expression, { scope: component.jsActions, params });
}); });
} }
}); });
@@ -8908,10 +9025,10 @@ ${expression ? 'Expression: "' + expression + '"\n\n' : ""}`, el);
to.__livewire = component; to.__livewire = component;
trigger2("morph", { el, toEl: to, component }); trigger2("morph", { el, toEl: to, component });
module_default.morph(el, to, { module_default.morph(el, to, {
updating: (el2, toEl, childrenOnly, skip) => { updating: (el2, toEl, childrenOnly, skip, skipChildren) => {
if (isntElement(el2)) if (isntElement(el2))
return; return;
trigger2("morph.updating", { el: el2, toEl, component, skip, childrenOnly }); trigger2("morph.updating", { el: el2, toEl, component, skip, childrenOnly, skipChildren });
if (el2.__livewire_replace === true) if (el2.__livewire_replace === true)
el2.innerHTML = toEl.innerHTML; el2.innerHTML = toEl.innerHTML;
if (el2.__livewire_replace_self === true) { if (el2.__livewire_replace_self === true) {
@@ -8922,6 +9039,8 @@ ${expression ? 'Expression: "' + expression + '"\n\n' : ""}`, el);
return skip(); return skip();
if (el2.__livewire_ignore_self === true) if (el2.__livewire_ignore_self === true)
childrenOnly(); childrenOnly();
if (el2.__livewire_ignore_children === true)
return skipChildren();
if (isComponentRootEl(el2) && el2.getAttribute("wire:id") !== component.id) if (isComponentRootEl(el2) && el2.getAttribute("wire:id") !== component.id)
return skip(); return skip();
if (isComponentRootEl(el2)) if (isComponentRootEl(el2))
@@ -9354,6 +9473,14 @@ ${expression ? 'Expression: "' + expression + '"\n\n' : ""}`, el);
el.__addedByMorph = true; el.__addedByMorph = true;
}); });
directive2("transition", ({ el, directive: directive3, component, cleanup: cleanup2 }) => { directive2("transition", ({ el, directive: directive3, component, cleanup: cleanup2 }) => {
for (let i = 0; i < el.attributes.length; i++) {
if (el.attributes[i].name.startsWith("wire:show")) {
module_default.bind(el, {
[directive3.rawName.replace("wire:transition", "x-transition")]: directive3.expression
});
return;
}
}
let visibility = module_default.reactive({ state: el.__addedByMorph ? false : true }); let visibility = module_default.reactive({ state: el.__addedByMorph ? false : true });
module_default.bind(el, { module_default.bind(el, {
[directive3.rawName.replace("wire:", "x-")]: "", [directive3.rawName.replace("wire:", "x-")]: "",
@@ -9466,6 +9593,55 @@ ${expression ? 'Expression: "' + expression + '"\n\n' : ""}`, el);
}; };
}); });
// js/directives/wire-current.js
module_default.addInitSelector(() => `[wire\\:current]`);
var onPageChanges = /* @__PURE__ */ new Map();
document.addEventListener("livewire:navigated", () => {
onPageChanges.forEach((i) => i(new URL(window.location.href)));
});
globalDirective("current", ({ el, directive: directive3, cleanup: cleanup2 }) => {
let expression = directive3.expression;
let options = {
exact: directive3.modifiers.includes("exact"),
strict: directive3.modifiers.includes("strict")
};
if (expression.startsWith("#"))
return;
if (!el.hasAttribute("href"))
return;
let href = el.getAttribute("href");
let hrefUrl = new URL(href, window.location.href);
let classes = expression.split(" ").filter(String);
let refreshCurrent = (url) => {
if (pathMatches(hrefUrl, url, options)) {
el.classList.add(...classes);
el.setAttribute("data-current", "");
} else {
el.classList.remove(...classes);
el.removeAttribute("data-current");
}
};
refreshCurrent(new URL(window.location.href));
onPageChanges.set(el, refreshCurrent);
cleanup2(() => onPageChanges.delete(el));
});
function pathMatches(hrefUrl, actualUrl, options) {
if (hrefUrl.hostname !== actualUrl.hostname)
return false;
let hrefPath = options.strict ? hrefUrl.pathname : hrefUrl.pathname.replace(/\/+$/, "");
let actualPath = options.strict ? actualUrl.pathname : actualUrl.pathname.replace(/\/+$/, "");
if (options.exact) {
return hrefPath === actualPath;
}
let hrefPathSegments = hrefPath.split("/");
let actualPathSegments = actualPath.split("/");
for (let i = 0; i < hrefPathSegments.length; i++) {
if (hrefPathSegments[i] !== actualPathSegments[i])
return false;
}
return true;
}
// js/directives/shared.js // js/directives/shared.js
function toggleBooleanStateDirective(el, directive3, isTruthy, cachedDisplay = null) { function toggleBooleanStateDirective(el, directive3, isTruthy, cachedDisplay = null) {
isTruthy = directive3.modifiers.includes("remove") ? !isTruthy : isTruthy; isTruthy = directive3.modifiers.includes("remove") ? !isTruthy : isTruthy;
@@ -9730,11 +9906,20 @@ ${expression ? 'Expression: "' + expression + '"\n\n' : ""}`, el);
directive2("ignore", ({ el, directive: directive3 }) => { directive2("ignore", ({ el, directive: directive3 }) => {
if (directive3.modifiers.includes("self")) { if (directive3.modifiers.includes("self")) {
el.__livewire_ignore_self = true; el.__livewire_ignore_self = true;
} else if (directive3.modifiers.includes("children")) {
el.__livewire_ignore_children = true;
} else { } else {
el.__livewire_ignore = true; el.__livewire_ignore = true;
} }
}); });
// js/directives/wire-cloak.js
module_default.interceptInit((el) => {
if (el.hasAttribute("wire:cloak")) {
module_default.mutateDom(() => el.removeAttribute("wire:cloak"));
}
});
// js/directives/wire-dirty.js // js/directives/wire-dirty.js
var refreshDirtyStatesByComponent = new WeakBag(); var refreshDirtyStatesByComponent = new WeakBag();
on2("commit", ({ component, respond }) => { on2("commit", ({ component, respond }) => {
@@ -9746,7 +9931,6 @@ ${expression ? 'Expression: "' + expression + '"\n\n' : ""}`, el);
}); });
directive2("dirty", ({ el, directive: directive3, component }) => { directive2("dirty", ({ el, directive: directive3, component }) => {
let targets = dirtyTargets(el); let targets = dirtyTargets(el);
let dirty = Alpine.reactive({ state: false });
let oldIsDirty = false; let oldIsDirty = false;
let initialDisplay = el.style.display; let initialDisplay = el.style.display;
let refreshDirtyState = (isDirty) => { let refreshDirtyState = (isDirty) => {
@@ -9965,6 +10149,38 @@ ${expression ? 'Expression: "' + expression + '"\n\n' : ""}`, el);
return durationInMilliSeconds || defaultDuration; return durationInMilliSeconds || defaultDuration;
} }
// js/directives/wire-show.js
module_default.interceptInit((el) => {
for (let i = 0; i < el.attributes.length; i++) {
if (el.attributes[i].name.startsWith("wire:show")) {
let { name, value } = el.attributes[i];
let modifierString = name.split("wire:show")[1];
let expression = value.startsWith("!") ? "!$wire." + value.slice(1).trim() : "$wire." + value.trim();
module_default.bind(el, {
["x-show" + modifierString]() {
return module_default.evaluate(el, expression);
}
});
}
}
});
// js/directives/wire-text.js
module_default.interceptInit((el) => {
for (let i = 0; i < el.attributes.length; i++) {
if (el.attributes[i].name.startsWith("wire:text")) {
let { name, value } = el.attributes[i];
let modifierString = name.split("wire:text")[1];
let expression = value.startsWith("!") ? "!$wire." + value.slice(1).trim() : "$wire." + value.trim();
module_default.bind(el, {
["x-text" + modifierString]() {
return module_default.evaluate(el, expression);
}
});
}
}
});
// js/index.js // js/index.js
var Livewire2 = { var Livewire2 = {
directive: directive2, directive: directive2,
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
+1 -1
View File
@@ -1,2 +1,2 @@
{"/livewire.js":"38dc8241"} {"/livewire.js":"df3a17f2"}
+1 -1
View File
@@ -278,7 +278,7 @@ return [
'ip' => 'IP(Block)', 'ip' => 'IP(Block)',
'ip_begin' => 'Begin IP', 'ip_begin' => 'Begin IP',
'ip_end' => 'End IP', 'ip_end' => 'End IP',
'ip_help' => 'Fill in the ASN/begin IP + end IP/IP (Block), only one of the three', 'ip_help' => 'Fill in the IP address or ASN, not both!',
'status' => 'Status', 'status' => 'Status',
'is_allowed' => 'Is whitelisted', 'is_allowed' => 'Is whitelisted',
'is_allowed_help' => 'IPs in the whitelist are not affected by the SeedBox rule', 'is_allowed_help' => 'IPs in the whitelist are not affected by the SeedBox rule',
+1 -1
View File
@@ -14,6 +14,6 @@ return [
'subject' => 'SeedBox record status changed', 'subject' => 'SeedBox record status changed',
'body' => 'The status of your SeedBox record with ID :id was changed by :operator from :old_status to :new_status. Reason: :reason', 'body' => 'The status of your SeedBox record with ID :id was changed by :operator from :old_status to :new_status. Reason: :reason',
], ],
'is_seed_box_yes' => 'This IP is SeedBox, identified by the record with ID :id', 'is_seed_box_yes' => 'This IP is SeedBox',
'is_seed_box_no' => 'This IP is not SeedBox', 'is_seed_box_no' => 'This IP is not SeedBox',
]; ];
+2 -2
View File
@@ -281,10 +281,10 @@ return [
'type' => '添加类型', 'type' => '添加类型',
'operator' => '运营商', 'operator' => '运营商',
'bandwidth' => '带宽(Mbps)', 'bandwidth' => '带宽(Mbps)',
'ip' => 'IP(段)', 'ip' => 'IP',
'ip_begin' => '起始 IP', 'ip_begin' => '起始 IP',
'ip_end' => '结束 IP', 'ip_end' => '结束 IP',
'ip_help' => '填写 ASN/起始 IP + 结束 IP/IP(段),不要同时填写', 'ip_help' => '填写IP地址或ASN,不要同时填写',
'status' => '状态', 'status' => '状态',
'is_allowed' => '是否白名单', 'is_allowed' => '是否白名单',
'is_allowed_help' => '位于白名单中的 IP 不受 SeedBox 规则影响', 'is_allowed_help' => '位于白名单中的 IP 不受 SeedBox 规则影响',
+2 -2
View File
@@ -14,6 +14,6 @@ return [
'subject' => 'SeedBox 记录状态变更', 'subject' => 'SeedBox 记录状态变更',
'body' => '你的 ID 为 :id 的 SeedBox 记录状态被 :operator 由 :old_status 变更为 :new_status。原因::reason', 'body' => '你的 ID 为 :id 的 SeedBox 记录状态被 :operator 由 :old_status 变更为 :new_status。原因::reason',
], ],
'is_seed_box_yes' => '此 IP 是 SeedBox, 由 ID 为 :id 的记录确定', 'is_seed_box_yes' => "此 IP 是 SeedBox",
'is_seed_box_no' => '此 IP 不是 SeedBox', 'is_seed_box_no' => "此 IP 不是 SeedBox",
]; ];
+1 -1
View File
@@ -278,7 +278,7 @@ return [
'ip' => 'IP(段)', 'ip' => 'IP(段)',
'ip_begin' => '起始 IP', 'ip_begin' => '起始 IP',
'ip_end' => '結束 IP', 'ip_end' => '結束 IP',
'ip_help' => '填寫ASN/起始 IP + 結束 IP/IP(段),不要同時填寫', 'ip_help' => '填寫IP地址或ASN,不要同時填寫',
'status' => '狀態', 'status' => '狀態',
'is_allowed' => '是否白名單', 'is_allowed' => '是否白名單',
'is_allowed_help' => '位於白名單中的 IP 不受 SeedBox 規則影響', 'is_allowed_help' => '位於白名單中的 IP 不受 SeedBox 規則影響',
+1 -1
View File
@@ -14,6 +14,6 @@ return [
'subject' => 'SeedBox 記錄狀態變更', 'subject' => 'SeedBox 記錄狀態變更',
'body' => '你的 ID 為 :id 的 SeedBox 記錄狀態被 :operator 由 :old_status 變更為 :new_status。原因::reason', 'body' => '你的 ID 為 :id 的 SeedBox 記錄狀態被 :operator 由 :old_status 變更為 :new_status。原因::reason',
], ],
'is_seed_box_yes' => '此 IP 是 SeedBox, 由 ID 為 :id 的記錄確定', 'is_seed_box_yes' => '此 IP 是 SeedBox',
'is_seed_box_no' => '此 IP 不是 SeedBox', 'is_seed_box_no' => '此 IP 不是 SeedBox',
]; ];