mirror of
https://github.com/lkddi/nexusphp.git
synced 2026-07-20 01:17:29 +08:00
Compare commits
44 Commits
695d5f071f
..
php8
| Author | SHA1 | Date | |
|---|---|---|---|
| 78f00fb474 | |||
| ee30a70cb9 | |||
| dd2716427e | |||
| c50867a71a | |||
| fab32bf63d | |||
| e4cdb26c2f | |||
| f823dc191a | |||
| 1372776ba1 | |||
| 7d18a7f76a | |||
| dc77ab7b40 | |||
| 94a35b81dc | |||
| dfe9436f1d | |||
| 4afcb1bb08 | |||
| e3376c3f1b | |||
| 00fdc2d08f | |||
| 4d54e08918 | |||
| 4d4af87dc9 | |||
| f271e28b15 | |||
| 9995767bf7 | |||
| d115a3879a | |||
| 431fbfff56 | |||
| 9e632811ef | |||
| db4982f8f7 | |||
| af66ec806d | |||
| 09b785902f | |||
| d79031f24d | |||
| 527a2d2162 | |||
| 3dae3aec8d | |||
| 5c9caa7a46 | |||
| a712a3f1e4 | |||
| f07e0a5013 | |||
| 8dec50fc6d | |||
| 1e997e411c | |||
| fb440c6d2b | |||
| 8207f1ed6f | |||
| c162fc81be | |||
| fd0a2014ba | |||
| eb3c03c97f | |||
| fc19ee5e7c | |||
| 4e9e4ae143 | |||
| e12cd0fab9 | |||
| f3a6d366d8 | |||
| 50259367d6 | |||
| ea176b1615 |
@@ -4,7 +4,7 @@ FROM openresty/openresty:alpine
|
||||
RUN apk add --no-cache gettext bash curl openssl socat
|
||||
|
||||
# 拷贝 entrypoint
|
||||
COPY ./entrypoint.sh /usr/local/bin/entrypoint.sh
|
||||
COPY .docker/openresty/entrypoint.sh /usr/local/bin/entrypoint.sh
|
||||
RUN chmod +x /usr/local/bin/entrypoint.sh
|
||||
|
||||
CMD ["/bin/sh", "/usr/local/bin/entrypoint.sh"]
|
||||
|
||||
@@ -81,7 +81,7 @@ RUN curl -sS https://getcomposer.org/installer | php -- --install-dir=/usr/local
|
||||
ENV LOG_CHANNEL=stderr
|
||||
ENV RUNNING_IN_DOCKER=1
|
||||
|
||||
COPY entrypoint.sh /usr/local/bin/entrypoint.sh
|
||||
COPY .docker/php/entrypoint.sh /usr/local/bin/entrypoint.sh
|
||||
RUN chmod +x /usr/local/bin/entrypoint.sh
|
||||
|
||||
ENTRYPOINT ["entrypoint.sh"]
|
||||
|
||||
@@ -67,7 +67,10 @@ if [ "$SERVICE_NAME" = "php" ]; then
|
||||
cp -r "$SOURCE_DIR" "$TARGET_DIR"
|
||||
sed -i 's|LOG_FILE.*|LOG_FILE=php://stdout|g' "$ROOT_PATH/.env.example"
|
||||
if [ -f "$ENV_FILE" ]; then
|
||||
echo_info "update LOG_FILE + DB_HOST + REDIS_HOST ..."
|
||||
sed -i 's|LOG_FILE.*|LOG_FILE=php://stdout|g' "$ENV_FILE"
|
||||
sed -i 's|DB_HOST.*|DB_HOST=mysql|g' "$ENV_FILE"
|
||||
sed -i 's|REDIS_HOST.*|REDIS_HOST=redis|g' "$ENV_FILE"
|
||||
fi
|
||||
else
|
||||
echo_success ".env file: $ENV_FILE and vendor autoload file: $VENDOR_AUTOLOAD_FILE already exists, skip copy install file ..."
|
||||
|
||||
+3
-2
@@ -11,8 +11,9 @@ DB_CONNECTION=mysql
|
||||
DB_HOST=127.0.0.1
|
||||
DB_PORT=3306
|
||||
DB_DATABASE=nexusphp
|
||||
DB_USERNAME=root
|
||||
DB_PASSWORD=
|
||||
DB_USERNAME=nexusphp
|
||||
DB_PASSWORD=nexusphp
|
||||
DB_SCHEMA=public
|
||||
|
||||
BROADCAST_DRIVER=log
|
||||
CACHE_DRIVER=redis
|
||||
|
||||
+3
-3
@@ -1,6 +1,6 @@
|
||||
English | [中文](/)
|
||||
|
||||
Complete PT website building solution. Based on NexusPHP + Laravel + Filament.
|
||||
Complete PT website building solution. Based on NexusPHP + Laravel + FilamentPHP.
|
||||
|
||||
Welcome to participate in internationalization work, click [here](https://github.com/xiaomlove/nexusphp/discussions/193) for more information
|
||||
|
||||
@@ -40,8 +40,8 @@ Welcome to participate in internationalization work, click [here](https://github
|
||||
- Section H&R
|
||||
- TGBot
|
||||
## System Requirements
|
||||
- PHP: 8.2|8.3|8.4|8.5, must have extensions: bcmath, ctype, curl, fileinfo, json, mbstring, openssl, pdo_mysql, tokenizer, xml, mysqli, gd, redis, pcntl, sockets, posix, gmp, zend opcache, zip, intl, pdo_sqlite, sqlite3
|
||||
- Mysql: 5.7 latest version or above
|
||||
- PHP: 8.2|8.3|8.4|8.5, must have extensions: bcmath, ctype, curl, fileinfo, json, mbstring, openssl, pdo_mysql, tokenizer, xml, mysqli, gd, redis, pcntl, sockets, posix, gmp, zend opcache, zip, intl, pdo_sqlite, sqlite3, pdo_pgsql
|
||||
- Database: MySQL 5.7 latest version or above/PostgreSQL 16 or above
|
||||
- Redis:4.0.0 or above
|
||||
- Others: supervisor, rsync
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
中文 | [English](/README-EN.md)
|
||||
|
||||
完整的 PT 建站解决方案。基于 NexusPHP + Laravel + Filament。
|
||||
完整的 PT 建站解决方案。基于 NexusPHP + Laravel + FilamentPHP。
|
||||
|
||||
欢迎参与国际化工作,点击 [这里](https://github.com/xiaomlove/nexusphp/discussions/193) 了解详情
|
||||
|
||||
@@ -40,8 +40,8 @@
|
||||
- TGBot
|
||||
|
||||
## 系统要求
|
||||
- PHP: 8.2|8.3|8.4|8.5,必须扩展:bcmath, ctype, curl, fileinfo, json, mbstring, openssl, pdo_mysql, tokenizer, xml, mysqli, gd, redis, pcntl, sockets, posix, gmp, zend opcache, zip, intl, pdo_sqlite, sqlite3
|
||||
- Mysql: 5.7 最新版或以上版本
|
||||
- PHP: 8.2|8.3|8.4|8.5,必须扩展:bcmath, ctype, curl, fileinfo, json, mbstring, openssl, pdo_mysql, tokenizer, xml, mysqli, gd, redis, pcntl, sockets, posix, gmp, zend opcache, zip, intl, pdo_sqlite, sqlite3, pdo_pgsql
|
||||
- Database: MySQL 5.7 最新版或以上版本/PostgreSQL 16 或以上版本
|
||||
- Redis:4.0.0 或以上版本
|
||||
- 其他:supervisor, rsync
|
||||
|
||||
|
||||
@@ -170,9 +170,9 @@ class CrowdinSync extends Command
|
||||
$this->uploadFile($filePath, $specificFile);
|
||||
$this->info("File {$specificFile} uploaded successfully.");
|
||||
} else {
|
||||
throw new \RuntimeException("please specify a file to upload");
|
||||
// throw new \RuntimeException("please specify a file to upload");
|
||||
// Upload all files in the source directory
|
||||
$files = File::allFiles($this->sourceDir);
|
||||
$files = File::allFiles($this->sourceDir . '/en');
|
||||
|
||||
$bar = $this->output->createProgressBar(count($files));
|
||||
$bar->start();
|
||||
|
||||
@@ -108,7 +108,7 @@ class NexusUpdate extends Command
|
||||
// $settings = $settingTableRows['settings'];
|
||||
$symbolicLinks = $settingTableRows['symbolic_links'];
|
||||
$fails = $settingTableRows['fails'];
|
||||
$mysqlInfo = $this->update->getMysqlVersionInfo();
|
||||
$mysqlInfo = $this->update->getDatabaseVersionInfo();
|
||||
$redisInfo = $this->update->getRedisVersionInfo();
|
||||
|
||||
if (!empty($fails)) {
|
||||
|
||||
@@ -29,7 +29,7 @@ class MigrateTorrentsTableTextColumn extends Command
|
||||
public function handle()
|
||||
{
|
||||
if (Schema::hasTable("torrent_extras") && Schema::hasColumn("torrents", "descr")) {
|
||||
NexusDB::statement("insert into torrent_extras (torrent_id, descr, media_info, nfo, pt_gen, created_at) select id, descr, technical_info, nfo, pt_gen, now() from torrents on duplicate key update torrent_id = values(torrent_id)");
|
||||
NexusDB::statement("insert into torrent_extras (torrent_id, descr, media_info, nfo, pt_gen, created_at) select id, descr, technical_info, nfo, pt_gen, now() from torrents " . NexusDB::upsertField(['torrent_id'], ['torrent_id']));
|
||||
}
|
||||
$columns = ["ori_descr", "descr", "nfo", "technical_info", "pt_gen"];
|
||||
$sql = "alter table torrents ";
|
||||
|
||||
@@ -6,6 +6,9 @@ use App\Jobs\CheckCleanup;
|
||||
use App\Jobs\CheckQueueFailedJobs;
|
||||
use App\Jobs\MaintainPluginState;
|
||||
use App\Jobs\ManagePlugin;
|
||||
use App\Jobs\RemoveUserDonorStatus;
|
||||
use App\Jobs\RemoveUserVipStatus;
|
||||
use App\Jobs\RemoveUserWarning;
|
||||
use App\Jobs\SaveIpLogCacheToDB;
|
||||
use App\Jobs\UpdateIsSeedBoxFromUserRecordsCache;
|
||||
use App\Utils\ThirdPartyJob;
|
||||
@@ -53,6 +56,9 @@ class Kernel extends ConsoleKernel
|
||||
$schedule->job(new UpdateIsSeedBoxFromUserRecordsCache())->everySixHours();
|
||||
$schedule->job(new CheckCleanup())->everyFifteenMinutes();
|
||||
$schedule->job(new SaveIpLogCacheToDB())->hourly();
|
||||
$schedule->job(new RemoveUserWarning())->everyTwentySeconds();
|
||||
$schedule->job(new RemoveUserVipStatus())->everyMinute();
|
||||
$schedule->job(new RemoveUserDonorStatus())->everyMinute();
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -14,6 +14,7 @@ use App\Events\HitAndRunUpdated;
|
||||
use App\Events\MessageCreated;
|
||||
use App\Events\NewsCreated;
|
||||
use App\Events\SnatchedUpdated;
|
||||
use App\Events\StaffMessageCreated;
|
||||
use App\Events\TorrentCreated;
|
||||
use App\Events\TorrentDeleted;
|
||||
use App\Events\TorrentUpdated;
|
||||
@@ -28,6 +29,7 @@ use App\Models\HitAndRun;
|
||||
use App\Models\Message;
|
||||
use App\Models\News;
|
||||
use App\Models\Snatch;
|
||||
use App\Models\StaffMessage;
|
||||
use App\Models\Torrent;
|
||||
use App\Models\User;
|
||||
|
||||
@@ -59,6 +61,8 @@ final class ModelEventEnum {
|
||||
const SNATCHED_UPDATED = 'snatched_updated';
|
||||
const MESSAGE_CREATED = 'message_created';
|
||||
|
||||
const STAFF_MESSAGE_CREATED = 'staff_message_created';
|
||||
|
||||
public static array $eventMaps = [
|
||||
self::TORRENT_CREATED => ['event' => TorrentCreated::class, 'model' => Torrent::class],
|
||||
self::TORRENT_UPDATED => ['event' => TorrentUpdated::class, 'model' => Torrent::class],
|
||||
@@ -87,5 +91,7 @@ final class ModelEventEnum {
|
||||
self::AGENT_DENY_CREATED => ['event' => AgentDenyCreated::class, 'model' => AgentDeny::class],
|
||||
self::AGENT_DENY_UPDATED => ['event' => AgentDenyUpdated::class, 'model' => AgentDeny::class],
|
||||
self::AGENT_DENY_DELETED => ['event' => AgentDenyDeleted::class, 'model' => AgentDeny::class],
|
||||
|
||||
self::STAFF_MESSAGE_CREATED => ['event' => StaffMessageCreated::class, 'model' => StaffMessage::class],
|
||||
];
|
||||
}
|
||||
|
||||
@@ -16,5 +16,6 @@ enum PermissionEnum: string {
|
||||
case MANAGE_USER_BASIC_INFO = "prfmanage";
|
||||
case MANAGE_USER_CONFIDENTIAL_INFO = "cruprfmanage";
|
||||
case VIEW_USER_CONFIDENTIAL_INFO = "userprofile";
|
||||
case VIEW_USER_HISTORY = "viewhistory";
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,39 @@
|
||||
<?php
|
||||
|
||||
namespace App\Events;
|
||||
|
||||
use Illuminate\Broadcasting\Channel;
|
||||
use Illuminate\Broadcasting\InteractsWithSockets;
|
||||
use Illuminate\Broadcasting\PresenceChannel;
|
||||
use Illuminate\Broadcasting\PrivateChannel;
|
||||
use Illuminate\Contracts\Broadcasting\ShouldBroadcast;
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
use Illuminate\Foundation\Events\Dispatchable;
|
||||
use Illuminate\Queue\SerializesModels;
|
||||
|
||||
class StaffMessageCreated
|
||||
{
|
||||
use Dispatchable, InteractsWithSockets, SerializesModels;
|
||||
|
||||
public ?Model $model = null;
|
||||
|
||||
/**
|
||||
* Create a new event instance.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function __construct(Model $model)
|
||||
{
|
||||
$this->model = $model;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the channels the event should broadcast on.
|
||||
*
|
||||
* @return \Illuminate\Broadcasting\Channel|array
|
||||
*/
|
||||
public function broadcastOn()
|
||||
{
|
||||
return new PrivateChannel('channel-name');
|
||||
}
|
||||
}
|
||||
@@ -2,6 +2,7 @@
|
||||
|
||||
namespace App\Filament\Resources\System\SettingResource\Pages;
|
||||
|
||||
use Filament\Actions\Action;
|
||||
use Filament\Forms\Contracts\HasForms;
|
||||
use Filament\Forms\Concerns\InteractsWithForms;
|
||||
use Filament\Schemas\Schema;
|
||||
@@ -41,8 +42,6 @@ class EditSetting extends Page implements HasForms
|
||||
|
||||
protected static string $resource = SettingResource::class;
|
||||
|
||||
protected string $view = 'filament.resources.system.setting-resource.pages.edit-hit-and-run';
|
||||
|
||||
public ?array $data = [];
|
||||
|
||||
public function getTitle(): string
|
||||
@@ -56,7 +55,7 @@ class EditSetting extends Page implements HasForms
|
||||
$this->fillForm();
|
||||
}
|
||||
|
||||
public function form(Schema $schema): Schema
|
||||
public function content(Schema $schema): Schema
|
||||
{
|
||||
return $schema
|
||||
->components($this->getFormSchema())
|
||||
@@ -76,7 +75,7 @@ class EditSetting extends Page implements HasForms
|
||||
}
|
||||
Arr::set($settings, 'captcha.attendance.enabled', $normalized);
|
||||
|
||||
$this->form->fill($settings);
|
||||
$this->content->fill($settings);
|
||||
}
|
||||
|
||||
|
||||
@@ -85,7 +84,10 @@ class EditSetting extends Page implements HasForms
|
||||
{
|
||||
return [
|
||||
Tabs::make('Heading')
|
||||
->tabs($this->getTabs())
|
||||
->tabs($this->getTabs()),
|
||||
Action::make('submit')
|
||||
->label(__('label.save'))
|
||||
->action(fn() => $this->submit()),
|
||||
];
|
||||
}
|
||||
|
||||
@@ -93,7 +95,7 @@ class EditSetting extends Page implements HasForms
|
||||
{
|
||||
static::authorizeResourceAccess();
|
||||
|
||||
$formData = $this->form->getState();
|
||||
$formData = $this->content->getState();
|
||||
$notAutoloadNames = ['donation_custom'];
|
||||
$data = [];
|
||||
foreach ($formData as $prefix => $parts) {
|
||||
|
||||
@@ -2,11 +2,12 @@
|
||||
|
||||
namespace App\Filament\Resources\TorrentCustomFields\Pages;
|
||||
|
||||
use App\Filament\PageList;
|
||||
use App\Filament\Resources\TorrentCustomFields\TorrentCustomFieldResource;
|
||||
use Filament\Actions\CreateAction;
|
||||
use Filament\Resources\Pages\ListRecords;
|
||||
|
||||
class ListTorrentCustomFields extends ListRecords
|
||||
class ListTorrentCustomFields extends PageList
|
||||
{
|
||||
protected static string $resource = TorrentCustomFieldResource::class;
|
||||
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
|
||||
namespace App\Filament\Resources\User;
|
||||
|
||||
use App\Repositories\BonusRepository;
|
||||
use Filament\Schemas\Schema;
|
||||
use Filament\Tables\Columns\TextColumn;
|
||||
use Filament\Tables\Filters\Filter;
|
||||
@@ -9,7 +10,6 @@ use Filament\Forms\Components\TextInput;
|
||||
use Filament\Tables\Filters\SelectFilter;
|
||||
use App\Filament\Resources\User\BonusLogResource\Pages\ManageBonusLogs;
|
||||
use App\Filament\Resources\User\BonusLogResource\Pages;
|
||||
use App\Filament\Resources\User\BonusLogResource\RelationManagers;
|
||||
use App\Models\BonusLogs;
|
||||
use Filament\Forms;
|
||||
use Filament\Resources\Resource;
|
||||
@@ -17,6 +17,7 @@ use Filament\Tables\Table;
|
||||
use Filament\Tables;
|
||||
use Illuminate\Database\Eloquent\Builder;
|
||||
use Illuminate\Database\Eloquent\SoftDeletingScope;
|
||||
use Illuminate\Pagination\LengthAwarePaginator;
|
||||
use Illuminate\Support\Arr;
|
||||
use function Filament\Support\get_model_label;
|
||||
|
||||
@@ -35,10 +36,10 @@ class BonusLogResource extends Resource
|
||||
return __('admin.sidebar.bonus_log');
|
||||
}
|
||||
|
||||
public static function getModelLabel(): string
|
||||
{
|
||||
return sprintf('%s(%s)', get_model_label(static::getModel()), __('bonus-log.exclude_seeding_bonus'));
|
||||
}
|
||||
// public static function getModelLabel(): string
|
||||
// {
|
||||
// return sprintf('%s(%s)', get_model_label(static::getModel()), __('bonus-log.exclude_seeding_bonus'));
|
||||
// }
|
||||
|
||||
public static function form(Schema $schema): Schema
|
||||
{
|
||||
@@ -51,8 +52,10 @@ class BonusLogResource extends Resource
|
||||
public static function table(Table $table): Table
|
||||
{
|
||||
return $table
|
||||
->records(function (int $page, int $recordsPerPage, array $filters) {
|
||||
return self::listRecords($page, $recordsPerPage, $filters);
|
||||
})
|
||||
->columns([
|
||||
TextColumn::make('id')->sortable(),
|
||||
TextColumn::make('uid')
|
||||
->formatStateUsing(fn ($state) => username_for_admin($state))
|
||||
->label(__('label.username'))
|
||||
@@ -79,8 +82,18 @@ class BonusLogResource extends Resource
|
||||
->label(__('label.created_at'))
|
||||
,
|
||||
])
|
||||
->defaultSort('id', 'desc')
|
||||
->filters([
|
||||
SelectFilter::make('category')
|
||||
->options(BonusLogs::listCategoryOptions(true))
|
||||
->default(BonusLogs::CATEGORY_COMMON)
|
||||
->selectablePlaceholder(false)
|
||||
->label(__('bonus-log.category'))
|
||||
,
|
||||
SelectFilter::make('business_type')
|
||||
->options(BonusLogs::listBusinessTypeOptions())
|
||||
->label(__('bonus-log.fields.business_type'))
|
||||
->searchable(true)
|
||||
,
|
||||
Filter::make('uid')
|
||||
->schema([
|
||||
TextInput::make('uid')
|
||||
@@ -91,21 +104,6 @@ class BonusLogResource extends Resource
|
||||
return $query->when($data['uid'], fn (Builder $query, $value) => $query->where("uid", $value));
|
||||
})
|
||||
,
|
||||
SelectFilter::make('business_type')
|
||||
->options(BonusLogs::listStaticProps(Arr::except(BonusLogs::$businessTypes, BonusLogs::$businessTypeBonus), 'bonus-log.business_types', true))
|
||||
->label(__('bonus-log.fields.business_type'))
|
||||
->searchable(true)
|
||||
,
|
||||
// Tables\Filters\Filter::make('exclude_seeding_bonus')
|
||||
// ->toggle()
|
||||
// ->label(__('bonus-log.exclude_seeding_bonus'))
|
||||
// ->query(function (Builder $query, array $data) {
|
||||
// if ($data['isActive']) {
|
||||
// $query->whereNotIn("business_type", BonusLogs::$businessTypeBonus);
|
||||
// }
|
||||
// })
|
||||
// ->default()
|
||||
// ,
|
||||
])
|
||||
->recordActions([
|
||||
// Tables\Actions\EditAction::make(),
|
||||
@@ -122,4 +120,15 @@ class BonusLogResource extends Resource
|
||||
'index' => ManageBonusLogs::route('/'),
|
||||
];
|
||||
}
|
||||
|
||||
private static function listRecords(int $page, int $perPage, array $filters = []): LengthAwarePaginator
|
||||
{
|
||||
$rep = new BonusRepository();
|
||||
$category = $filters['category']['value'] ?: BonusLogs::CATEGORY_COMMON;
|
||||
$userId = intval($filters['userId']['value'] ?? 0);
|
||||
$businessType = intval($filters['businessType']['value'] ?? 0);
|
||||
$list = $rep->getList($category, $userId, $businessType, $page, $perPage);
|
||||
$count = $rep->getCount($category, $userId, $businessType);
|
||||
return new LengthAwarePaginator($list, $count, $perPage, $page);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,6 +2,8 @@
|
||||
|
||||
namespace App\Filament\Resources\User;
|
||||
|
||||
use Filament\Infolists\Components\RepeatableEntry;
|
||||
use Filament\Infolists\Components\RepeatableEntry\TableColumn;
|
||||
use Filament\Schemas\Schema;
|
||||
use Filament\Tables\Columns\TextColumn;
|
||||
use Filament\Tables\Columns\BooleanColumn;
|
||||
@@ -193,10 +195,21 @@ class ExamUserResource extends Resource
|
||||
->columns(2)
|
||||
,
|
||||
Group::make([
|
||||
ViewEntry::make('progressFormatted')
|
||||
->label('进度')
|
||||
->view('filament.resources.user.exam-user-resource.pages.detail-v3')
|
||||
])->columnSpan(1),
|
||||
RepeatableEntry::make('progressFormatted')
|
||||
->hiddenLabel()
|
||||
->table([
|
||||
TableColumn::make(__('label.exam.index_required_label')),
|
||||
TableColumn::make(__('label.exam.index_required_value')),
|
||||
TableColumn::make(__('label.exam.index_current_value')),
|
||||
TableColumn::make(__('label.exam.index_result')),
|
||||
])
|
||||
->schema([
|
||||
TextEntry::make('index_formatted'),
|
||||
TextEntry::make('require_value_formatted'),
|
||||
TextEntry::make('current_value_formatted'),
|
||||
TextEntry::make('index_result')->html(),
|
||||
])
|
||||
])->columnSpan(1),
|
||||
]),
|
||||
]);
|
||||
|
||||
|
||||
@@ -51,7 +51,7 @@ class UserPasskeyResource extends Resource
|
||||
->formatStateUsing(fn($state) => username_for_admin($state))
|
||||
->label(__('label.username'))
|
||||
,
|
||||
Tables\Columns\TextColumn::make('AAGUID')
|
||||
Tables\Columns\TextColumn::make('aaguid')
|
||||
->label("AAGUID")
|
||||
,
|
||||
Tables\Columns\TextColumn::make('credential_id')
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
|
||||
namespace App\Http;
|
||||
|
||||
use App\Http\Middleware\CheckSiteStatus;
|
||||
use App\Http\Middleware\Filament;
|
||||
use App\Http\Middleware\Locale;
|
||||
use App\Http\Middleware\LogUserIp;
|
||||
@@ -25,6 +26,7 @@ class Kernel extends HttpKernel
|
||||
\App\Http\Middleware\TrimStrings::class,
|
||||
// \Illuminate\Foundation\Http\Middleware\ConvertEmptyStringsToNull::class,
|
||||
\App\Http\Middleware\BootNexus::class,
|
||||
Locale::class,
|
||||
LogUserIp::class,
|
||||
];
|
||||
|
||||
@@ -47,6 +49,7 @@ class Kernel extends HttpKernel
|
||||
'api' => [
|
||||
'throttle:api',
|
||||
\Illuminate\Routing\Middleware\SubstituteBindings::class,
|
||||
CheckSiteStatus::class,
|
||||
],
|
||||
'filament' => [
|
||||
\Illuminate\Session\Middleware\StartSession::class,
|
||||
|
||||
@@ -0,0 +1,27 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Middleware;
|
||||
|
||||
use App\Exceptions\NexusException;
|
||||
use App\Models\Setting;
|
||||
use App\Models\User;
|
||||
use Closure;
|
||||
use Illuminate\Http\Request;
|
||||
use Symfony\Component\HttpFoundation\Response;
|
||||
|
||||
class CheckSiteStatus
|
||||
{
|
||||
/**
|
||||
* Handle an incoming request.
|
||||
*
|
||||
* @param \Closure(\Illuminate\Http\Request): (\Symfony\Component\HttpFoundation\Response) $next
|
||||
*/
|
||||
public function handle(Request $request, Closure $next): Response
|
||||
{
|
||||
$user = $request->user();
|
||||
if ($user && $user->class < User::CLASS_ADMINISTRATOR && !Setting::getIsSiteOnline()) {
|
||||
throw new NexusException(nexus_trans('misc.site_down_for_maintenance'));
|
||||
}
|
||||
return $next($request);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,62 @@
|
||||
<?php
|
||||
|
||||
namespace App\Jobs;
|
||||
|
||||
use App\Enums\ModelEventEnum;
|
||||
use App\Models\Message;
|
||||
use App\Models\User;
|
||||
use App\Models\UserModifyLog;
|
||||
use Illuminate\Contracts\Queue\ShouldQueue;
|
||||
use Illuminate\Foundation\Queue\Queueable;
|
||||
|
||||
class RemoveUserDonorStatus
|
||||
{
|
||||
/**
|
||||
* Create a new job instance.
|
||||
*/
|
||||
public function __construct()
|
||||
{
|
||||
//
|
||||
}
|
||||
|
||||
/**
|
||||
* Execute the job.
|
||||
*/
|
||||
public function handle(): void
|
||||
{
|
||||
$users = User::query()
|
||||
->with('language')
|
||||
->where('donor', 'yes')
|
||||
->whereNotNull('donoruntil')
|
||||
->where('donoruntil', '<', now())
|
||||
->get();
|
||||
$userModifyLogs = [];
|
||||
foreach ($users as $user) {
|
||||
$locale = $user->locale;
|
||||
$userModifyLogs[] = [
|
||||
'user_id' => $user->id,
|
||||
'content' => "donor status removed by - AutoSystem",
|
||||
'created_at' => now(),
|
||||
'updated_at' => now(),
|
||||
];
|
||||
$user->donor = 'no';
|
||||
do_log(sprintf("update user %s => %s", $user->id, json_encode($user->getDirty())));
|
||||
$user->save();
|
||||
clear_user_cache($user->id);
|
||||
publish_model_event(ModelEventEnum::USER_UPDATED, $user->id);
|
||||
$subject = nexus_trans("cleanup.msg_donor_status_removed", [], $locale);
|
||||
$msg = nexus_trans("cleanup.msg_donor_status_removed_body", [], $locale);
|
||||
Message::add([
|
||||
'sender' => 0,
|
||||
'receiver' => $user->id,
|
||||
'added' => now(),
|
||||
'subject' => $subject,
|
||||
'msg' => $msg,
|
||||
]);
|
||||
}
|
||||
if (!empty($userModifyLogs)) {
|
||||
UserModifyLog::query()->insert($userModifyLogs);
|
||||
}
|
||||
do_log("remove donor status if time's up, success handle user count: " . $users->count());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,69 @@
|
||||
<?php
|
||||
|
||||
namespace App\Jobs;
|
||||
|
||||
use App\Enums\ModelEventEnum;
|
||||
use App\Models\Message;
|
||||
use App\Models\User;
|
||||
use App\Models\UserModifyLog;
|
||||
use Illuminate\Contracts\Queue\ShouldQueue;
|
||||
use Illuminate\Foundation\Queue\Queueable;
|
||||
|
||||
class RemoveUserVipStatus
|
||||
{
|
||||
/**
|
||||
* Create a new job instance.
|
||||
*/
|
||||
public function __construct()
|
||||
{
|
||||
//
|
||||
}
|
||||
|
||||
/**
|
||||
* Execute the job.
|
||||
*/
|
||||
public function handle(): void
|
||||
{
|
||||
$users = User::query()
|
||||
->with('language')
|
||||
->where('vip_added', 'yes')
|
||||
->where('vip_until', '<', now())
|
||||
->get();
|
||||
$userModifyLogs = [];
|
||||
foreach ($users as $user) {
|
||||
$locale = $user->locale;
|
||||
$userModifyLogs[] = [
|
||||
'user_id' => $user->id,
|
||||
'content' => "VIP status removed by - AutoSystem",
|
||||
'created_at' => now(),
|
||||
'updated_at' => now(),
|
||||
];
|
||||
$message = [];
|
||||
$user->vip_added = 'no';
|
||||
$user->vip_until = null;
|
||||
if ($user->class <= User::CLASS_VIP) {
|
||||
$user->class = User::CLASS_USER;
|
||||
$subject = nexus_trans("cleanup.msg_vip_status_removed", [], $locale);
|
||||
$msg = nexus_trans("cleanup.msg_vip_status_removed_body", [], $locale);
|
||||
$message = [
|
||||
'sender' => 0,
|
||||
'receiver' => $user->id,
|
||||
'added' => now(),
|
||||
'subject' => $subject,
|
||||
'msg' => $msg,
|
||||
];
|
||||
}
|
||||
do_log(sprintf("update user %s => %s", $user->id, json_encode($user->getDirty())));
|
||||
$user->save();
|
||||
clear_user_cache($user->id);
|
||||
publish_model_event(ModelEventEnum::USER_UPDATED, $user->id);
|
||||
if (!empty($message)) {
|
||||
Message::add($message);
|
||||
}
|
||||
}
|
||||
if (!empty($userModifyLogs)) {
|
||||
UserModifyLog::query()->insert($userModifyLogs);
|
||||
}
|
||||
do_log("remove VIP status if time's up, success handle user count: " . $users->count());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,63 @@
|
||||
<?php
|
||||
|
||||
namespace App\Jobs;
|
||||
|
||||
use App\Enums\ModelEventEnum;
|
||||
use App\Models\Message;
|
||||
use App\Models\User;
|
||||
use App\Models\UserModifyLog;
|
||||
use Illuminate\Contracts\Queue\ShouldQueue;
|
||||
use Illuminate\Foundation\Queue\Queueable;
|
||||
|
||||
class RemoveUserWarning
|
||||
{
|
||||
/**
|
||||
* Create a new job instance.
|
||||
*/
|
||||
public function __construct()
|
||||
{
|
||||
//
|
||||
}
|
||||
|
||||
/**
|
||||
* Execute the job.
|
||||
*/
|
||||
public function handle(): void
|
||||
{
|
||||
$users = User::query()
|
||||
->with('language')
|
||||
->where('enabled', 'yes')
|
||||
->where('warned', 'yes')
|
||||
->where('warneduntil', '<', now())
|
||||
->get();
|
||||
$userModifyLogs = [];
|
||||
foreach ($users as $user) {
|
||||
$locale = $user->locale;
|
||||
$userModifyLogs[] = [
|
||||
'user_id' => $user->id,
|
||||
'content' => "Warning removed by System.",
|
||||
'created_at' => now(),
|
||||
'updated_at' => now(),
|
||||
];
|
||||
$user->warned = 'no';
|
||||
$user->warneduntil = null;
|
||||
do_log(sprintf("update user %s => %s", $user->id, json_encode($user->getDirty())));
|
||||
$user->save();
|
||||
clear_user_cache($user->id);
|
||||
publish_model_event(ModelEventEnum::USER_UPDATED, $user->id);
|
||||
$subject = nexus_trans("cleanup.msg_warning_removed", [], $locale);
|
||||
$msg = nexus_trans("cleanup.msg_your_warning_removed", [], $locale);
|
||||
Message::add([
|
||||
'sender' => 0,
|
||||
'receiver' => $user->id,
|
||||
'added' => now(),
|
||||
'subject' => $subject,
|
||||
'msg' => $msg,
|
||||
]);
|
||||
}
|
||||
if (!empty($userModifyLogs)) {
|
||||
UserModifyLog::query()->insert($userModifyLogs);
|
||||
}
|
||||
do_log("remove warning of users, success handle user count: " . $users->count());
|
||||
}
|
||||
}
|
||||
@@ -4,20 +4,24 @@ namespace App\Models;
|
||||
|
||||
|
||||
use Carbon\Carbon;
|
||||
use Illuminate\Support\Arr;
|
||||
|
||||
class BonusLogs extends NexusModel
|
||||
{
|
||||
protected $table = 'bonus_logs';
|
||||
|
||||
protected $fillable = ['uid', 'business_type', 'old_total_value', 'value', 'new_total_value', 'comment'];
|
||||
protected $fillable = ['uid', 'business_type', 'old_total_value', 'value', 'new_total_value', 'comment', 'created_at', 'updated_at'];
|
||||
|
||||
public $timestamps = true;
|
||||
const CATEGORY_COMMON = 'common';
|
||||
const CATEGORY_SEEDING = 'seeding';
|
||||
|
||||
const DEFAULT_BONUS_CANCEL_ONE_HIT_AND_RUN = 10000;
|
||||
const DEFAULT_BONUS_BUY_ATTENDANCE_CARD = 1000;
|
||||
const DEFAULT_BONUS_BUY_TEMPORARY_INVITE = 500;
|
||||
const DEFAULT_BONUS_BUY_RAINBOW_ID = 5000;
|
||||
const DEFAULT_BONUS_BUY_CHANGE_USERNAME_CARD = 100000;
|
||||
const DEFAULT_BONUS_SELF_ENABLE = 100000;
|
||||
|
||||
//扣除类,1开始
|
||||
const BUSINESS_TYPE_CANCEL_HIT_AND_RUN = 1;
|
||||
@@ -43,6 +47,7 @@ class BonusLogs extends NexusModel
|
||||
const BUSINESS_TYPE_TASK_PASS_REWARD = 21;
|
||||
const BUSINESS_TYPE_REWARD_TORRENT = 22;
|
||||
const BUSINESS_TYPE_CLAIMED_UNREACHED = 23;
|
||||
const BUSINESS_TYPE_SELF_ENABLE = 24;
|
||||
|
||||
//获得类,普通获得,1000 起步
|
||||
const BUSINESS_TYPE_ROLE_WORK_SALARY = 1000;
|
||||
@@ -84,6 +89,7 @@ class BonusLogs extends NexusModel
|
||||
self::BUSINESS_TYPE_TASK_PASS_REWARD => ['text' => 'Task success reward'],
|
||||
self::BUSINESS_TYPE_REWARD_TORRENT => ['text' => 'Reward torrent'],
|
||||
self::BUSINESS_TYPE_CLAIMED_UNREACHED => ['text' => 'Claimed torrent unreached'],
|
||||
self::BUSINESS_TYPE_SELF_ENABLE => ['text' => 'Self enable'],
|
||||
|
||||
self::BUSINESS_TYPE_ROLE_WORK_SALARY => ['text' => 'Role work salary'],
|
||||
self::BUSINESS_TYPE_TORRENT_BE_DOWNLOADED => ['text' => 'Torrent be downloaded'],
|
||||
@@ -100,7 +106,7 @@ class BonusLogs extends NexusModel
|
||||
self::BUSINESS_TYPE_SEEDING_MEDAL_ADDITION => ['text' => 'Seeding medal addition'],
|
||||
];
|
||||
|
||||
public static array $businessTypeBonus = [
|
||||
public static array $businessTypeSeeding = [
|
||||
self::BUSINESS_TYPE_SEEDING_BASIC,
|
||||
self::BUSINESS_TYPE_SEEDING_DONOR_ADDITION,
|
||||
self::BUSINESS_TYPE_SEEDING_OFFICIAL_ADDITION,
|
||||
@@ -108,6 +114,28 @@ class BonusLogs extends NexusModel
|
||||
self::BUSINESS_TYPE_SEEDING_MEDAL_ADDITION
|
||||
];
|
||||
|
||||
public static function listBusinessTypeOptions($category = ''): array
|
||||
{
|
||||
$source = BonusLogs::$businessTypes;
|
||||
if ($category == self::CATEGORY_COMMON) {
|
||||
$source = Arr::except(BonusLogs::$businessTypes, BonusLogs::$businessTypeSeeding);
|
||||
} else if ($category == self::CATEGORY_SEEDING) {
|
||||
$source = Arr::only(BonusLogs::$businessTypes, BonusLogs::$businessTypeSeeding);
|
||||
}
|
||||
return self::listStaticProps($source, 'bonus-log.business_types', true);
|
||||
}
|
||||
|
||||
public static function listCategoryOptions(bool $includeSeeding): array
|
||||
{
|
||||
$result = [
|
||||
self::CATEGORY_COMMON => nexus_trans('bonus-log.category_common')
|
||||
];
|
||||
if ($includeSeeding) {
|
||||
$result[self::CATEGORY_SEEDING] = nexus_trans('bonus-log.category_seeding');
|
||||
}
|
||||
return $result;
|
||||
}
|
||||
|
||||
public function getBusinessTypeTextAttribute()
|
||||
{
|
||||
return nexus_trans('bonus-log.business_types.' . $this->business_type);
|
||||
|
||||
@@ -235,6 +235,7 @@ class Exam extends NexusModel
|
||||
|
||||
public function getRecurringBegin(Carbon $time): Carbon
|
||||
{
|
||||
$time = $time->copy();
|
||||
$recurring = $this->recurring;
|
||||
if ($recurring == self::RECURRING_WEEKLY) {
|
||||
return $time->startOfWeek();
|
||||
@@ -248,6 +249,7 @@ class Exam extends NexusModel
|
||||
|
||||
public function getRecurringEnd(Carbon $time): Carbon
|
||||
{
|
||||
$time = $time->copy();
|
||||
$recurring = $this->recurring;
|
||||
if ($recurring == self::RECURRING_WEEKLY) {
|
||||
return $time->endOfWeek();
|
||||
|
||||
@@ -0,0 +1,9 @@
|
||||
<?php
|
||||
|
||||
namespace App\Models;
|
||||
|
||||
|
||||
class Faq extends NexusModel
|
||||
{
|
||||
protected $table = 'faq';
|
||||
}
|
||||
@@ -21,7 +21,7 @@ class IpLog extends NexusModel
|
||||
private function getIpLocation(string $ip)
|
||||
{
|
||||
$result = get_ip_location_from_geoip($ip);
|
||||
$out = $result['name'];
|
||||
$out = $result['name'] ?? '';
|
||||
$suffix = [];
|
||||
if (!empty($result['city_en'])) {
|
||||
$suffix[] = $result['city_en'];
|
||||
|
||||
@@ -15,7 +15,10 @@ class NexusModel extends Model
|
||||
|
||||
protected $perPage = 50;
|
||||
|
||||
protected $connection = NexusDB::ELOQUENT_CONNECTION_NAME;
|
||||
public function getConnectionName()
|
||||
{
|
||||
return NexusDB::getConnectionName();
|
||||
}
|
||||
|
||||
protected function usernameForAdmin(): Attribute
|
||||
{
|
||||
|
||||
@@ -9,7 +9,7 @@ class Passkey extends NexusModel
|
||||
public $timestamps = true;
|
||||
|
||||
protected $fillable = [
|
||||
'id', 'user_id', 'AAGUID', 'credential_id', 'public_key', 'counter',
|
||||
'id', 'user_id', 'aaguid', 'credential_id', 'public_key', 'counter',
|
||||
];
|
||||
|
||||
public function user()
|
||||
@@ -17,8 +17,9 @@ class Passkey extends NexusModel
|
||||
return $this->belongsTo(User::class, 'user_id');
|
||||
}
|
||||
|
||||
public function AAGUID() {
|
||||
$guid = $this->AAGUID;
|
||||
public function getAaguidFormatted(): string
|
||||
{
|
||||
$guid = $this->aaguid;
|
||||
return sprintf(
|
||||
'%s-%s-%s-%s-%s',
|
||||
substr($guid, 0, 8),
|
||||
|
||||
@@ -0,0 +1,13 @@
|
||||
<?php
|
||||
|
||||
namespace App\Models;
|
||||
|
||||
|
||||
use App\Models\Traits\NexusActivityLogTrait;
|
||||
|
||||
class RegImage extends NexusModel
|
||||
{
|
||||
protected $table = 'regimages';
|
||||
|
||||
protected $fillable = ['imagehash', 'imagestring', 'dateline'];
|
||||
}
|
||||
@@ -334,4 +334,14 @@ class Setting extends NexusModel
|
||||
{
|
||||
return self::get('main.showimdbinfo') == 'yes';
|
||||
}
|
||||
|
||||
public static function getSelfEnableBonus(): int
|
||||
{
|
||||
return (int)self::get("bonus.self_enable", BonusLogs::DEFAULT_BONUS_SELF_ENABLE);
|
||||
}
|
||||
|
||||
public static function getIsSiteOnline(): bool
|
||||
{
|
||||
return self::get('main.site_online') == 'yes';
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,8 +2,7 @@
|
||||
|
||||
namespace App\Models;
|
||||
|
||||
use App\Repositories\ToolRepository;
|
||||
use Google\Service\Testing\ToolResultsExecution;
|
||||
use App\Enums\ModelEventEnum;
|
||||
|
||||
class StaffMessage extends NexusModel
|
||||
{
|
||||
@@ -27,4 +26,16 @@ class StaffMessage extends NexusModel
|
||||
return $this->belongsTo(User::class, 'answeredby');
|
||||
}
|
||||
|
||||
public static function add(int $sender, string $subject, string $msg)
|
||||
{
|
||||
$record = self::query()->create([
|
||||
'sender' => $sender,
|
||||
'subject' => $subject,
|
||||
'msg' => $msg,
|
||||
'added' => now(),
|
||||
]);
|
||||
fire_event(ModelEventEnum::STAFF_MESSAGE_CREATED, $record);
|
||||
return $record;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+41
-1
@@ -5,6 +5,7 @@ namespace App\Models;
|
||||
use App\Repositories\TagRepository;
|
||||
use Carbon\Carbon;
|
||||
use Illuminate\Database\Eloquent\Casts\Attribute;
|
||||
use Nexus\Database\NexusDB;
|
||||
|
||||
class Torrent extends NexusModel
|
||||
{
|
||||
@@ -186,6 +187,37 @@ class Torrent extends NexusModel
|
||||
self::NFO_VIEW_STYLE_WINDOWS => ['text' => 'Windows-vy'],
|
||||
];
|
||||
|
||||
public function scopeWhereInfoHash($query, string $binaryHash)
|
||||
{
|
||||
if (NexusDB::isPgsql()) {
|
||||
return $query->whereRaw(
|
||||
"info_hash = decode(?, 'hex')",
|
||||
[bin2hex($binaryHash)]
|
||||
);
|
||||
} elseif (NexusDB::isMysql()) {
|
||||
return $query->where('info_hash', $binaryHash);
|
||||
}
|
||||
throw new \RuntimeException("Not supported database");
|
||||
}
|
||||
|
||||
/**
|
||||
* 重写获取 info_hash 的方法,确保从数据库读出时是正确的格式
|
||||
* 注意:不要使用 getInfoHashAttribute(),不带缓存,第1次有值,第2次指针到头,数据是空!!!
|
||||
*/
|
||||
public function infoHash(): Attribute
|
||||
{
|
||||
return Attribute::make(
|
||||
get: function ($value) {
|
||||
// PostgreSQL 返回 bytea 时可能是十六进制流或资源
|
||||
if (is_resource($value)) {
|
||||
rewind($value);
|
||||
return stream_get_contents($value);
|
||||
}
|
||||
return $value;
|
||||
}
|
||||
)->shouldCache();
|
||||
}
|
||||
|
||||
public function getPickInfoAttribute()
|
||||
{
|
||||
$info = self::$pickTypes[$this->picktype] ?? null;
|
||||
@@ -521,8 +553,16 @@ class Torrent extends NexusModel
|
||||
|
||||
public function tags(): \Illuminate\Database\Eloquent\Relations\BelongsToMany
|
||||
{
|
||||
$idsString = TagRepository::getOrderByFieldIdString();
|
||||
if (NexusDB::isPgsql()) {
|
||||
$orderByRaw = "array_position(ARRAY[$idsString]::int[], tags.id)";
|
||||
} else if (NexusDB::isMysql()) {
|
||||
$orderByRaw = "FIELD(tags.id, $idsString)";
|
||||
} else {
|
||||
throw new \RuntimeException("Unsupported database");
|
||||
}
|
||||
return $this->belongsToMany(Tag::class, 'torrent_tags', 'torrent_id', 'tag_id')
|
||||
->orderByRaw(sprintf("field(`tags`.`id`,%s)", TagRepository::getOrderByFieldIdString()));
|
||||
->orderByRaw($orderByRaw);
|
||||
}
|
||||
|
||||
public function reward_logs(): \Illuminate\Database\Eloquent\Relations\HasMany
|
||||
|
||||
+5
-3
@@ -31,8 +31,6 @@ class User extends Authenticatable implements FilamentUser, HasName
|
||||
|
||||
protected $perPage = 50;
|
||||
|
||||
protected $connection = NexusDB::ELOQUENT_CONNECTION_NAME;
|
||||
|
||||
const STATUS_CONFIRMED = 'confirmed';
|
||||
const STATUS_PENDING = 'pending';
|
||||
|
||||
@@ -109,6 +107,11 @@ class User extends Authenticatable implements FilamentUser, HasName
|
||||
|
||||
private const USER_ENABLE_LATELY = "user_enable_lately:%s";
|
||||
|
||||
public function getConnectionName()
|
||||
{
|
||||
return NexusDB::getConnectionName();
|
||||
}
|
||||
|
||||
public static function getUserEnableLatelyCacheKey(int $userId): string
|
||||
{
|
||||
return sprintf(self::USER_ENABLE_LATELY, $userId);
|
||||
@@ -369,7 +372,6 @@ class User extends Authenticatable implements FilamentUser, HasName
|
||||
{
|
||||
return $query->where('donor', 'yes')->where(function (Builder $query) {
|
||||
return $query->whereNull('donoruntil')
|
||||
->orWhere('donoruntil', '0000-00-00 00:00:00')
|
||||
->orWhere('donoruntil', '>=', now());
|
||||
});
|
||||
}
|
||||
|
||||
@@ -8,6 +8,8 @@ class UserBanLog extends NexusModel
|
||||
|
||||
protected $fillable = ['uid', 'username', 'operator', 'reason'];
|
||||
|
||||
public $timestamps = true;
|
||||
|
||||
public static function clearUserBanLogDuplicate()
|
||||
{
|
||||
$lists = UserBanLog::query()
|
||||
|
||||
@@ -244,8 +244,8 @@ class AttendanceRepository extends BaseRepository
|
||||
return 0;
|
||||
}
|
||||
$sql = sprintf(
|
||||
"insert into `%s` (`uid`, `points`, `date`) values %s on duplicate key update `uid` = values(`uid`)",
|
||||
$table, implode(',', $insert)
|
||||
'insert into %s (uid, points, "date") values %s %s',
|
||||
$table, implode(',', $insert), NexusDB::upsertField(['uid'], ['uid'])
|
||||
);
|
||||
NexusDB::statement($sql);
|
||||
$insertCount = count($insert);
|
||||
|
||||
@@ -31,7 +31,7 @@ class BaseRepository
|
||||
return $perPage;
|
||||
}
|
||||
|
||||
protected function handleAnonymous($username, $user, User $authenticator, Torrent $torrent = null)
|
||||
protected function handleAnonymous($username, $user, User $authenticator, ?Torrent $torrent = null)
|
||||
{
|
||||
if (!$user) {
|
||||
return "";
|
||||
|
||||
@@ -15,6 +15,7 @@ use App\Models\UserMedal;
|
||||
use App\Models\UserMeta;
|
||||
use Carbon\Carbon;
|
||||
use Illuminate\Database\Eloquent\Builder;
|
||||
use Nexus\Database\ClickHouse;
|
||||
use Nexus\Database\NexusDB;
|
||||
|
||||
class BonusRepository extends BaseRepository
|
||||
@@ -362,5 +363,71 @@ class BonusRepository extends BaseRepository
|
||||
});
|
||||
}
|
||||
|
||||
public function getCount(string $category = '', int $userId = 0, int $businessType = 0): int
|
||||
{
|
||||
if ($category == BonusLogs::CATEGORY_COMMON) {
|
||||
$query = $this->buildQuery($userId, $businessType);
|
||||
return $query->count();
|
||||
} else if ($category == BonusLogs::CATEGORY_SEEDING) {
|
||||
list($whereStr, $binds) = $this->buildWhereStrAndBinds($userId, $businessType);
|
||||
return ClickHouse::count("bonus_logs", $whereStr, $binds);
|
||||
}
|
||||
throw new \InvalidArgumentException("Invalid category: $category");
|
||||
}
|
||||
|
||||
public function getList(string $category = '', int $userId = 0, int $businessType = 0, int $page = 1, int $perPage = 50)
|
||||
{
|
||||
if ($category == BonusLogs::CATEGORY_COMMON) {
|
||||
$query = $this->buildQuery($userId, $businessType);
|
||||
return $query->orderBy("id", "desc")->forPage($page, $perPage)->get();
|
||||
} else if ($category == BonusLogs::CATEGORY_SEEDING) {
|
||||
list($whereStr, $binds) = $this->buildWhereStrAndBinds($userId, $businessType);
|
||||
$offset = ($page - 1) * $perPage;
|
||||
$rows = ClickHouse::list("select * from bonus_logs $whereStr order by created_at desc limit $offset, $perPage", $binds);
|
||||
$result = [];
|
||||
$id = 1;//fake id
|
||||
foreach ($rows as $row) {
|
||||
$record = new BonusLogs($row);
|
||||
$record->id = $id;
|
||||
$result[] = $record;
|
||||
$id++;
|
||||
}
|
||||
return $result;
|
||||
}
|
||||
throw new \InvalidArgumentException("Invalid category: $category");
|
||||
}
|
||||
|
||||
private function buildWhereStrAndBinds(int $userId = 0, int $businessType = 0)
|
||||
{
|
||||
$whereArr = [];
|
||||
$binds = [];
|
||||
if ($userId > 0) {
|
||||
$whereArr[] = "uid = :uid";
|
||||
$binds['uid'] = $userId;
|
||||
}
|
||||
if ($businessType > 0) {
|
||||
$whereArr[] = "business_type = :business_type";
|
||||
$binds["business_type"] = $businessType;
|
||||
}
|
||||
if (empty($whereArr)) {
|
||||
$whereStr = "";
|
||||
} else {
|
||||
$whereStr = sprintf("where %s", implode(' AND ', $whereArr));
|
||||
}
|
||||
return [$whereStr, $binds];
|
||||
}
|
||||
|
||||
private function buildQuery(int $userId = 0, int $businessType = 0): Builder
|
||||
{
|
||||
$query = BonusLogs::query();
|
||||
if ($userId > 0) {
|
||||
$query->where('uid', $userId);
|
||||
}
|
||||
if ($businessType > 0) {
|
||||
$query->where('business_type', $businessType);
|
||||
}
|
||||
return $query;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
@@ -47,10 +47,11 @@ class DashboardRepository extends BaseRepository
|
||||
'value' => PHP_VERSION,
|
||||
];
|
||||
$name = 'mysql_version';
|
||||
$databaseInfo = NexusDB::getDatabaseVersionInfo();
|
||||
$result[$name] = [
|
||||
'name' => $name,
|
||||
'text' => nexus_trans("dashboard.system_info.$name"),
|
||||
'value' => NexusDB::select('select version() as info')[0]['info'],
|
||||
'value' => sprintf("%s: %s", $databaseInfo['dbType'], $databaseInfo['version']),
|
||||
];
|
||||
// $name = 'os';
|
||||
// $result[$name] = [
|
||||
|
||||
@@ -31,8 +31,8 @@ class ExamRepository extends BaseRepository
|
||||
|
||||
public function store(array $params)
|
||||
{
|
||||
$this->checkIndexes($params);
|
||||
$this->checkBeginEnd($params);
|
||||
$diffInHours = $this->checkBeginEnd($params);
|
||||
$this->checkIndexes($params, $diffInHours);
|
||||
$this->checkFilters($params);
|
||||
/**
|
||||
* does not limit this
|
||||
@@ -48,8 +48,8 @@ class ExamRepository extends BaseRepository
|
||||
|
||||
public function update(array $params, $id)
|
||||
{
|
||||
$this->checkIndexes($params);
|
||||
$this->checkBeginEnd($params);
|
||||
$diffInHours = $this->checkBeginEnd($params);
|
||||
$this->checkIndexes($params, $diffInHours);
|
||||
$this->checkFilters($params);
|
||||
/**
|
||||
* does not limit this
|
||||
@@ -76,7 +76,7 @@ class ExamRepository extends BaseRepository
|
||||
return $params;
|
||||
}
|
||||
|
||||
private function checkIndexes(array $params): bool
|
||||
private function checkIndexes(array $params, float $examDuration): bool
|
||||
{
|
||||
if (empty($params['indexes'])) {
|
||||
throw new \InvalidArgumentException("Require index.");
|
||||
@@ -94,6 +94,14 @@ class ExamRepository extends BaseRepository
|
||||
'Invalid require value for index: %s.', $index['index']
|
||||
));
|
||||
}
|
||||
if ($index['index'] == Exam::INDEX_SEED_TIME_AVERAGE) {
|
||||
if ($index['require_value'] > $examDuration) {
|
||||
throw new \InvalidArgumentException(nexus_trans(
|
||||
'admin.resources.exam.index_seed_time_average_require_value_invalid',
|
||||
['index_seed_time_average_require_value' => $index['require_value'], 'duration' => $examDuration]
|
||||
));
|
||||
}
|
||||
}
|
||||
$validIndex[$index['index']] = $index;
|
||||
}
|
||||
if (empty($validIndex)) {
|
||||
@@ -102,28 +110,40 @@ class ExamRepository extends BaseRepository
|
||||
return true;
|
||||
}
|
||||
|
||||
private function checkBeginEnd(array $params): bool
|
||||
/**
|
||||
* check if begin/end valid, if yes, return diff in hours, else throw InvalidArgumentException
|
||||
* @param array $params
|
||||
* @return float
|
||||
*/
|
||||
private function checkBeginEnd(array $params): float
|
||||
{
|
||||
if (
|
||||
!empty($params['begin']) && !empty($params['end'])
|
||||
&& empty($params['duration'])
|
||||
&& empty($params['recurring'])
|
||||
) {
|
||||
return true;
|
||||
$begin = Carbon::parse($params['begin']);
|
||||
$end = Carbon::parse($params['end']);
|
||||
return round($begin->diffInHours($end, true));
|
||||
}
|
||||
if (
|
||||
empty($params['begin']) && empty($params['end'])
|
||||
&& isset($params['duration']) && ctype_digit((string)$params['duration']) && $params['duration'] > 0
|
||||
&& empty($params['recurring'])
|
||||
) {
|
||||
return true;
|
||||
//unit: day
|
||||
return round(floatval($params['duration']) * 24);
|
||||
}
|
||||
if (
|
||||
empty($params['begin']) && empty($params['end'])
|
||||
&& empty($params['duration'])
|
||||
&& !empty($params['recurring'])
|
||||
) {
|
||||
return true;
|
||||
$exam = new Exam(['recurring' => $params['recurring']]);
|
||||
$now = Carbon::now();
|
||||
$begin = $exam->getRecurringBegin($now);
|
||||
$end = $exam->getRecurringEnd($now);
|
||||
return round($begin->diffInHours($end, true));
|
||||
}
|
||||
|
||||
throw new \InvalidArgumentException(nexus_trans("exam.time_condition_invalid"));
|
||||
@@ -249,8 +269,24 @@ class ExamRepository extends BaseRepository
|
||||
$now = Carbon::now();
|
||||
$query = Exam::query()
|
||||
->where('status', Exam::STATUS_ENABLED)
|
||||
->whereRaw("if(begin is not null and end is not null, begin <= '$now' and end >= '$now', duration > 0 or recurring is not null)")
|
||||
;
|
||||
->where(function ($q) use ($now) {
|
||||
$q->where(function ($sub) use ($now) {
|
||||
// 如果 begin 和 end 都不为空,则判断时间
|
||||
$sub->whereNotNull('begin')
|
||||
->whereNotNull('end')
|
||||
->where('begin', '<=', $now)
|
||||
->where('end', '>=', $now);
|
||||
})->orWhere(function ($sub) {
|
||||
// 如果不满足上面的条件(即 begin 或 end 任意一个为空)
|
||||
$sub->where(function ($inner) {
|
||||
$inner->whereNull('begin')
|
||||
->orWhereNull('end');
|
||||
})->where(function ($inner) {
|
||||
$inner->where('duration', '>', 0)
|
||||
->orWhereNotNull('recurring');
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
if (!is_null($excludeId)) {
|
||||
$query->whereNotIn('id', Arr::wrap($excludeId));
|
||||
@@ -261,6 +297,7 @@ class ExamRepository extends BaseRepository
|
||||
if (!is_null($type)) {
|
||||
$query->where("type", $type);
|
||||
}
|
||||
|
||||
return $query->orderBy('priority', 'desc')->orderBy('id', 'asc')->get();
|
||||
}
|
||||
|
||||
@@ -672,8 +709,8 @@ class ExamRepository extends BaseRepository
|
||||
if ($index['index'] == Exam::INDEX_SEED_TIME_AVERAGE) {
|
||||
$torrentCountsRes = Snatch::query()
|
||||
->where('userid', $user->id)
|
||||
->where('completedat', '>=', $begin)
|
||||
->where('completedat', '<=', $end)
|
||||
->where('last_action', '>=', $begin)
|
||||
->where('last_action', '<=', $end)
|
||||
->selectRaw("count(distinct(torrentid)) as counts")
|
||||
->first();
|
||||
do_log("special index: {$index['index']}, get torrent count by: " . last_query());
|
||||
@@ -1025,13 +1062,13 @@ class ExamRepository extends BaseRepository
|
||||
if ($donateStatus == User::DONATE_YES) {
|
||||
$baseQuery->where(function (Builder $query) {
|
||||
$query->where('donor', 'yes')->where(function (Builder $query) {
|
||||
$query->where('donoruntil', '0000-00-00 00:00:00')->orWhereNull('donoruntil')->orWhere('donoruntil', '>=', Carbon::now());
|
||||
$query->whereNull('donoruntil')->orWhere('donoruntil', '>=', Carbon::now());
|
||||
});
|
||||
});
|
||||
} elseif ($donateStatus == User::DONATE_NO) {
|
||||
$baseQuery->where(function (Builder $query) {
|
||||
$query->where('donor', 'no')->orWhere(function (Builder $query) {
|
||||
$query->where('donoruntil', '!=','0000-00-00 00:00:00')->whereNotNull('donoruntil')->where('donoruntil', '<', Carbon::now());
|
||||
$query->whereNotNull('donoruntil')->where('donoruntil', '<', Carbon::now());
|
||||
});
|
||||
});
|
||||
} else {
|
||||
@@ -1107,22 +1144,44 @@ class ExamRepository extends BaseRepository
|
||||
|
||||
public function cronjobCheckout($ignoreTimeRange = false): int
|
||||
{
|
||||
$now = Carbon::now()->toDateTimeString();
|
||||
$now = Carbon::now(); // 保持 Carbon 对象即可,Laravel 会自动序列化
|
||||
$examUserTable = (new ExamUser())->getTable();
|
||||
$examTable = (new Exam())->getTable();
|
||||
$userTable = (new User())->getTable();
|
||||
|
||||
$baseQuery = ExamUser::query()
|
||||
->join($examTable, "$examUserTable.exam_id", "=", "$examTable.id")
|
||||
->where("$examUserTable.status", ExamUser::STATUS_NORMAL)
|
||||
->selectRaw("$examUserTable.*")
|
||||
->select("$examUserTable.*") // 替换 selectRaw
|
||||
->with(['exam', 'user', 'user.language'])
|
||||
->orderBy("$examUserTable.id", "asc");
|
||||
|
||||
if (!$ignoreTimeRange) {
|
||||
$whenThens = [];
|
||||
$whenThens[] = "when $examUserTable.`end` is not null then $examUserTable.`end` < '$now'";
|
||||
$whenThens[] = "when $examTable.`end` is not null then $examTable.`end` < '$now'";
|
||||
$whenThens[] = "when $examTable.duration > 0 then date_add($examUserTable.created_at, interval $examTable.duration day) < '$now'";
|
||||
$baseQuery->whereRaw(sprintf("case %s else false end", implode(" ", $whenThens)));
|
||||
$baseQuery->where(function ($query) use ($examUserTable, $examTable, $now) {
|
||||
$query->where(function ($q) use ($examUserTable, $now) {
|
||||
// 条件 1: exam_user.end 不为空且小于当前时间
|
||||
$q->whereNotNull("$examUserTable.end")
|
||||
->where("$examUserTable.end", '<', $now);
|
||||
})
|
||||
->orWhere(function ($q) use ($examTable, $now) {
|
||||
// 条件 2: exam.end 不为空且小于当前时间
|
||||
$q->whereNotNull("$examTable.end")
|
||||
->where("$examTable.end", '<', $now);
|
||||
})
|
||||
->orWhere(function ($q) use ($examUserTable, $examTable, $now) {
|
||||
// 条件 3: exam.duration > 0 且过期
|
||||
// 因为涉及到列与列的计算,这里需要用 whereRaw,但我们可以针对多数据库做自适应
|
||||
$q->where("$examTable.duration", '>', 0);
|
||||
|
||||
if (NexusDB::isPgsql()) {
|
||||
// PG 写法:使用 || 拼接字符串再转为 INTERVAL
|
||||
$q->whereRaw("$examUserTable.created_at + ($examTable.duration || ' day')::INTERVAL < ?", [$now]);
|
||||
} else {
|
||||
// MySQL 写法
|
||||
$q->whereRaw("DATE_ADD($examUserTable.created_at, INTERVAL $examTable.duration DAY) < ?", [$now]);
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
$size = 1000;
|
||||
|
||||
@@ -400,7 +400,7 @@ class HitAndRunRepository extends BaseRepository
|
||||
->selectRaw("count(*) as counts, uid")
|
||||
->where('status', HitAndRun::STATUS_UNREACHED)
|
||||
->groupBy('uid')
|
||||
->having("counts", '>=', $disableCounts)
|
||||
->havingRaw("count(*) >= $disableCounts")
|
||||
;
|
||||
if ($setting['diff_in_section']) {
|
||||
$query->whereHas('torrent.basic_category', function (Builder $query) use ($setting) {
|
||||
|
||||
@@ -199,7 +199,7 @@ class SeedBoxRepository extends BaseRepository
|
||||
$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');
|
||||
$selectRaw = sprintf("uid, %s as str", NexusDB::groupConcatField($field == IpAsnEnum::ASN ? 'asn' : 'ip'));
|
||||
while (true) {
|
||||
$list = SeedBoxRecord::getValidQuery(TypeEnum::USER, $isAllowed, $field)
|
||||
->selectRaw($selectRaw)
|
||||
|
||||
@@ -45,8 +45,8 @@ class SettingRepository extends BaseRepository
|
||||
return true;
|
||||
}
|
||||
$sql = sprintf(
|
||||
"insert into `%s` (`name`, `value`) values %s on duplicate key update `value` = values(`value`)",
|
||||
$settingModel->getTable(), implode(', ', $values)
|
||||
'insert into %s (name, "value") values %s %s',
|
||||
$settingModel->getTable(), implode(', ', $values), NexusDB::upsertField(['name'], ['value'])
|
||||
);
|
||||
$result = DB::insert($sql);
|
||||
do_log("sql: $sql, result: $result");
|
||||
|
||||
@@ -133,7 +133,7 @@ class TagRepository extends BaseRepository
|
||||
}
|
||||
$page++;
|
||||
}
|
||||
$sql .= sprintf("%s on duplicate key update updated_at = values(updated_at)", implode(', ', $values));
|
||||
$sql .= sprintf("%s %s", implode(', ', $values), NexusDB::upsertField(['torrent_id', 'tag_id'], ['updated_at']));
|
||||
do_log("migrate sql: $sql");
|
||||
NexusDB::statement($sql);
|
||||
do_log("[MIGRATE_TORRENT_TAG] done!");
|
||||
|
||||
@@ -511,8 +511,9 @@ class ToolRepository extends BaseRepository
|
||||
$stickyPromotionExists = NexusDB::hasTable($stickyPromotionParticipatorsTable);
|
||||
$claimTableExists = NexusDB::hasTable($claimTable);
|
||||
$hitAndRunTableExists = NexusDB::hasTable($hitAndRunTable);
|
||||
$idsField = NexusDB::groupConcatField('id');
|
||||
while (true) {
|
||||
$snatchRes = NexusDB::select("select userid, torrentid, group_concat(id) as ids from snatched group by userid, torrentid having(count(*)) > 1 limit $size");
|
||||
$snatchRes = NexusDB::select("select userid, torrentid, $idsField as ids from snatched group by userid, torrentid having(count(*)) > 1 limit $size");
|
||||
if (empty($snatchRes)) {
|
||||
break;
|
||||
}
|
||||
@@ -542,8 +543,9 @@ class ToolRepository extends BaseRepository
|
||||
public function removeDuplicatePeer()
|
||||
{
|
||||
$size = 2000;
|
||||
$idsField = NexusDB::groupConcatField('id');
|
||||
while (true) {
|
||||
$results = NexusDB::select("select torrent, userid, group_concat(id) as ids from peers group by torrent, peer_id, userid having(count(*)) > 1 limit $size");
|
||||
$results = NexusDB::select("select torrent, userid, $idsField as ids from peers group by torrent, peer_id, userid having(count(*)) > 1 limit $size");
|
||||
if (empty($results)) {
|
||||
do_log("[DELETE_DUPLICATED_PEERS], no data: ". last_query());
|
||||
break;
|
||||
|
||||
@@ -749,7 +749,7 @@ class TorrentRepository extends BaseRepository
|
||||
$values[] = sprintf("(%s, %s, '%s', '%s')", $torrentId, $tagId, $time, $time);
|
||||
}
|
||||
}
|
||||
$sql .= implode(', ', $values) . " on duplicate key update updated_at = values(updated_at)";
|
||||
$sql .= implode(', ', $values) . " " . NexusDB::upsertField(['torrent_id', 'tag_id'], ['updated_at']);
|
||||
if ($remove) {
|
||||
TorrentTag::query()->whereIn('torrent_id', $idArr)->delete();
|
||||
}
|
||||
|
||||
@@ -15,7 +15,25 @@ class UserPasskeyRepository extends BaseRepository
|
||||
public static function createWebAuthn()
|
||||
{
|
||||
$formats = ['android-key', 'android-safetynet', 'apple', 'fido-u2f', 'packed', 'tpm', 'none'];
|
||||
return new WebAuthn(get_setting('basic.SITENAME'), nexus()->getRequestHost(), $formats);
|
||||
$rpId = explode(':', nexus()->getRequestHost())[0];
|
||||
return new WebAuthn(get_setting('basic.SITENAME'), $rpId, $formats);
|
||||
}
|
||||
|
||||
private static function putChallenge($challenge): string
|
||||
{
|
||||
$challengeId = bin2hex(random_bytes(32));
|
||||
NexusDB::cache_put("passkey_challenge_{$challengeId}", $challenge, 120);
|
||||
return $challengeId;
|
||||
}
|
||||
|
||||
private static function getChallenge($challengeId)
|
||||
{
|
||||
$challenge = NexusDB::cache_get("passkey_challenge_{$challengeId}") ?? null;
|
||||
if ($challenge == null) {
|
||||
throw new RuntimeException(nexus_trans('passkey.passkey_timeout'));
|
||||
}
|
||||
NexusDB::cache_del("passkey_challenge_{$challengeId}");
|
||||
return $challenge;
|
||||
}
|
||||
|
||||
public static function getCreateArgs($userId, $userName)
|
||||
@@ -28,20 +46,22 @@ class UserPasskeyRepository extends BaseRepository
|
||||
return hex2bin($item['credential_id']);
|
||||
}, $passkey->toArray());
|
||||
|
||||
$createArgs = $WebAuthn->getCreateArgs(bin2hex($userId), $userName, $userName, 60 * 4, true, 'preferred', null, $credentialIds);
|
||||
$createArgs = $WebAuthn->getCreateArgs(bin2hex($userId), $userName, $userName, 120, true, 'preferred', null, $credentialIds);
|
||||
$challengeId = self::putChallenge($WebAuthn->getChallenge());
|
||||
|
||||
NexusDB::cache_put("{$userId}_passkey_challenge", $WebAuthn->getChallenge(), 60 * 4);
|
||||
|
||||
return $createArgs;
|
||||
return [
|
||||
'challengeId' => $challengeId,
|
||||
'options' => $createArgs,
|
||||
];
|
||||
}
|
||||
|
||||
public static function processCreate($userId, $clientDataJSON, $attestationObject)
|
||||
public static function processCreate($userId, $challengeId, $clientDataJSON, $attestationObject)
|
||||
{
|
||||
$WebAuthn = self::createWebAuthn();
|
||||
|
||||
$challenge = self::getChallenge($challengeId);
|
||||
$clientDataJSON = !empty($clientDataJSON) ? base64_decode($clientDataJSON) : null;
|
||||
$attestationObject = !empty($attestationObject) ? base64_decode($attestationObject) : null;
|
||||
$challenge = NexusDB::cache_get("{$userId}_passkey_challenge") ?? null;
|
||||
|
||||
$WebAuthn = self::createWebAuthn();
|
||||
|
||||
$data = $WebAuthn->processCreate($clientDataJSON, $attestationObject, $challenge, false, true, false);
|
||||
|
||||
@@ -60,9 +80,13 @@ class UserPasskeyRepository extends BaseRepository
|
||||
{
|
||||
$WebAuthn = self::createWebAuthn();
|
||||
|
||||
$getArgs = $WebAuthn->getGetArgs(null, 60 * 4, true, true, true, true, true, 'preferred');
|
||||
$getArgs = $WebAuthn->getGetArgs(null, 120, true, true, true, true, true, 'preferred');
|
||||
$challengeId = self::putChallenge($WebAuthn->getChallenge());
|
||||
|
||||
return $getArgs;
|
||||
return [
|
||||
'challengeId' => $challengeId,
|
||||
'options' => $getArgs,
|
||||
];
|
||||
}
|
||||
|
||||
public static function insertUserPasskey($userId, $AAGUID, $credentialId, $publicKey, $counter)
|
||||
@@ -77,21 +101,19 @@ class UserPasskeyRepository extends BaseRepository
|
||||
Passkey::query()->create($params);
|
||||
}
|
||||
|
||||
public static function processGet($challenge, $id, $clientDataJSON, $authenticatorData, $signature, $userHandle)
|
||||
public static function processGet($challengeId, $id, $clientDataJSON, $authenticatorData, $signature, $userHandle)
|
||||
{
|
||||
$WebAuthn = self::createWebAuthn();
|
||||
|
||||
$challenge = self::getChallenge($challengeId);
|
||||
$clientDataJSON = !empty($clientDataJSON) ? base64_decode($clientDataJSON) : null;
|
||||
$id = !empty($id) ? base64_decode($id) : null;
|
||||
$authenticatorData = !empty($authenticatorData) ? base64_decode($authenticatorData) : null;
|
||||
$signature = !empty($signature) ? base64_decode($signature) : null;
|
||||
$userHandle = !empty($userHandle) ? base64_decode($userHandle) : null;
|
||||
$challenge = !empty($challenge) ? base64_decode($challenge) : null;
|
||||
|
||||
$WebAuthn = self::createWebAuthn();
|
||||
|
||||
$passkey = Passkey::query()->where('credential_id', '=', bin2hex($id))->first();
|
||||
$credentialPublicKey = $passkey->public_key;
|
||||
|
||||
if ($credentialPublicKey === null) {
|
||||
if ($passkey === null) {
|
||||
throw new RuntimeException(nexus_trans('passkey.passkey_unknown'));
|
||||
}
|
||||
|
||||
@@ -100,7 +122,7 @@ class UserPasskeyRepository extends BaseRepository
|
||||
}
|
||||
|
||||
try {
|
||||
$WebAuthn->processGet($clientDataJSON, $authenticatorData, $signature, $credentialPublicKey, $challenge, null, 'preferred');
|
||||
$WebAuthn->processGet($clientDataJSON, $authenticatorData, $signature, $passkey->public_key, $challenge, null, false, true);
|
||||
} catch (Exception $e) {
|
||||
throw new RuntimeException(nexus_trans('passkey.passkey_error') . "\n" . $e->getMessage());
|
||||
}
|
||||
@@ -197,7 +219,7 @@ class UserPasskeyRepository extends BaseRepository
|
||||
<td>
|
||||
<div style="display:flex;align-items:center;padding:4px">
|
||||
<?php
|
||||
$meta = $AAGUIDS[$passkey->AAGUID()];
|
||||
$meta = $AAGUIDS[$passkey->getAaguidFormatted()];
|
||||
if (isset($meta)) {
|
||||
printf('<img style="width: 32px" src="%s" alt="%s" /><div style="margin-right:4px"><b>%s</b> (%s)', $meta['icon_dark'], $meta['name'], $meta['name'], $passkey->credential_id);
|
||||
} else {
|
||||
|
||||
@@ -2,7 +2,6 @@
|
||||
namespace App\Repositories;
|
||||
|
||||
use App\Enums\ModelEventEnum;
|
||||
use App\Enums\RedisKeysEnum;
|
||||
use App\Exceptions\InsufficientPermissionException;
|
||||
use App\Exceptions\NexusException;
|
||||
use App\Http\Resources\ExamUserResource;
|
||||
@@ -29,7 +28,6 @@ use Illuminate\Database\Eloquent\Builder;
|
||||
use Illuminate\Support\Arr;
|
||||
use Illuminate\Support\Collection;
|
||||
use Illuminate\Support\Facades\Auth;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
use Illuminate\Support\Facades\Gate;
|
||||
use Illuminate\Support\Str;
|
||||
use Nexus\Database\NexusDB;
|
||||
@@ -228,9 +226,9 @@ class UserRepository extends BaseRepository
|
||||
'operator' => $operator->id,
|
||||
];
|
||||
$modCommentText = sprintf("%s - Disable by %s, reason: %s.", now()->format('Y-m-d'), $operator->username, $reason);
|
||||
DB::transaction(function () use ($targetUser, $banLog, $modCommentText) {
|
||||
NexusDB::transaction(function () use ($targetUser, $banLog, $modCommentText) {
|
||||
$targetUser->updateWithModComment(['enabled' => User::ENABLED_NO], $modCommentText);
|
||||
UserBanLog::query()->insert($banLog);
|
||||
UserBanLog::query()->create($banLog);
|
||||
});
|
||||
do_log("user: $uid, $modCommentText");
|
||||
$this->clearCache($targetUser);
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
|
||||
namespace App\Services\Captcha\Drivers;
|
||||
|
||||
use App\Models\RegImage;
|
||||
use App\Services\Captcha\CaptchaDriverInterface;
|
||||
use App\Services\Captcha\Exceptions\CaptchaValidationException;
|
||||
|
||||
@@ -67,16 +68,11 @@ class ImageCaptchaDriver implements CaptchaDriverInterface
|
||||
$random = random_str();
|
||||
$imagehash = md5($random);
|
||||
$dateline = time();
|
||||
|
||||
$sql = sprintf(
|
||||
"INSERT INTO `regimages` (`imagehash`, `imagestring`, `dateline`) VALUES ('%s', '%s', '%s')",
|
||||
mysql_real_escape_string($imagehash),
|
||||
mysql_real_escape_string($random),
|
||||
mysql_real_escape_string((string) $dateline)
|
||||
);
|
||||
|
||||
sql_query($sql);
|
||||
|
||||
RegImage::query()->insert([
|
||||
'imagehash' => $imagehash,
|
||||
'dateline' => $dateline,
|
||||
'imagestring' => $random,
|
||||
]);
|
||||
return $imagehash;
|
||||
}
|
||||
|
||||
|
||||
+4
-2
@@ -35,6 +35,7 @@
|
||||
"ext-xml": "*",
|
||||
"ext-zend-opcache": "*",
|
||||
"ext-zip": "*",
|
||||
"ext-pdo": "*",
|
||||
"calebporzio/sushi": "^2.5",
|
||||
"cybercog/laravel-clickhouse": "dev-master",
|
||||
"elasticsearch/elasticsearch": "^7.16",
|
||||
@@ -42,7 +43,7 @@
|
||||
"flowframe/laravel-trend": "^0.4",
|
||||
"geoip2/geoip2": "~2.0",
|
||||
"google/auth": "1.44.0",
|
||||
"imdbphp/imdbphp": "^8.0",
|
||||
"imdbphp/imdbphp": "8.3.1",
|
||||
"irazasyed/telegram-bot-sdk": "^3.11",
|
||||
"laravel/framework": "^12.0",
|
||||
"laravel/horizon": "^5.31",
|
||||
@@ -87,7 +88,8 @@
|
||||
"@php artisan key:generate --ansi"
|
||||
],
|
||||
"post-update-cmd": [
|
||||
"@php artisan filament:upgrade"
|
||||
"@php artisan filament:upgrade",
|
||||
"@php artisan livewire:publish --assets"
|
||||
]
|
||||
},
|
||||
"extra": {
|
||||
|
||||
Generated
+387
-358
File diff suppressed because it is too large
Load Diff
@@ -24,12 +24,12 @@ return [
|
||||
*/
|
||||
|
||||
'connection' => [
|
||||
'host' => env('CLICKHOUSE_HOST', 'localhost'),
|
||||
'port' => env('CLICKHOUSE_HTTP_PORT', 8123),
|
||||
'username' => env('CLICKHOUSE_USER', 'default'),
|
||||
'password' => env('CLICKHOUSE_PASSWORD', ''),
|
||||
'host' => nexus_env('CLICKHOUSE_HOST', 'localhost'),
|
||||
'port' => nexus_env('CLICKHOUSE_HTTP_PORT', 8123),
|
||||
'username' => nexus_env('CLICKHOUSE_USER', 'default'),
|
||||
'password' => nexus_env('CLICKHOUSE_PASSWORD', ''),
|
||||
'options' => [
|
||||
'database' => env('CLICKHOUSE_DATABASE', 'default'),
|
||||
'database' => nexus_env('CLICKHOUSE_DATABASE', 'default'),
|
||||
'timeout' => 1,
|
||||
'connectTimeOut' => 2,
|
||||
],
|
||||
@@ -42,7 +42,7 @@ return [
|
||||
*/
|
||||
|
||||
'migrations' => [
|
||||
'table' => env('CLICKHOUSE_MIGRATION_TABLE', 'migrations'),
|
||||
'path' => database_path('clickhouse-migrations'),
|
||||
'table' => nexus_env('CLICKHOUSE_MIGRATION_TABLE', 'migrations'),
|
||||
'path' => __DIR__ . '/../database/clickhouse-migrations',
|
||||
],
|
||||
];
|
||||
|
||||
+1
-1
@@ -74,7 +74,7 @@ return [
|
||||
'charset' => 'utf8',
|
||||
'prefix' => '',
|
||||
'prefix_indexes' => true,
|
||||
'schema' => 'public',
|
||||
'schema' => env('DB_SCHEMA', 'public'),
|
||||
'sslmode' => 'prefer',
|
||||
],
|
||||
|
||||
|
||||
@@ -8,6 +8,45 @@ return [
|
||||
|
||||
'log_split' => nexus_env('LOG_SPLIT', 'daily'),
|
||||
|
||||
'database' => [
|
||||
'default' => nexus_env('DB_CONNECTION', 'mysql'),
|
||||
'connections' => [
|
||||
'mysql' => [
|
||||
'driver' => 'mysql',
|
||||
'url' => nexus_env('DATABASE_URL'),
|
||||
'host' => nexus_env('DB_HOST', '127.0.0.1'),
|
||||
'port' => (int)nexus_env('DB_PORT', 3306),
|
||||
'username' => nexus_env('DB_USERNAME', 'root'),
|
||||
'password' => nexus_env('DB_PASSWORD', ''),
|
||||
'database' => nexus_env('DB_DATABASE', 'nexusphp'),
|
||||
'unix_socket' => nexus_env('DB_SOCKET', ''),
|
||||
'charset' => 'utf8mb4',
|
||||
'collation' => 'utf8mb4_unicode_ci',
|
||||
'prefix' => '',
|
||||
'prefix_indexes' => true,
|
||||
'strict' => false,
|
||||
'engine' => null,
|
||||
'options' => extension_loaded('pdo_mysql') ? array_filter([
|
||||
PDO::MYSQL_ATTR_SSL_CA => nexus_env('MYSQL_ATTR_SSL_CA'),
|
||||
]) : [],
|
||||
],
|
||||
'pgsql' => [
|
||||
'driver' => 'pgsql',
|
||||
'url' => nexus_env('DATABASE_URL'),
|
||||
'host' => nexus_env('DB_HOST', '127.0.0.1'),
|
||||
'port' => nexus_env('DB_PORT', '5432'),
|
||||
'database' => nexus_env('DB_DATABASE', 'nexusphp'),
|
||||
'username' => nexus_env('DB_USERNAME', 'nexusphp'),
|
||||
'password' => nexus_env('DB_PASSWORD', ''),
|
||||
'charset' => 'utf8',
|
||||
'prefix' => '',
|
||||
'prefix_indexes' => true,
|
||||
'schema' => nexus_env('DB_SCHEMA', 'public'),
|
||||
'sslmode' => 'prefer',
|
||||
],
|
||||
],
|
||||
],
|
||||
|
||||
'mysql' => [
|
||||
'driver' => 'mysql',
|
||||
'url' => nexus_env('DATABASE_URL'),
|
||||
|
||||
@@ -16,7 +16,7 @@ return new class extends Migration
|
||||
$table->unsignedBigInteger('user_id')->index();
|
||||
$table->unsignedBigInteger('client_id');
|
||||
$table->text('scopes')->nullable();
|
||||
$table->boolean('revoked');
|
||||
$table->smallInteger('revoked');
|
||||
$table->dateTime('expires_at')->nullable();
|
||||
});
|
||||
}
|
||||
|
||||
@@ -17,7 +17,7 @@ return new class extends Migration
|
||||
$table->unsignedBigInteger('client_id');
|
||||
$table->string('name')->nullable();
|
||||
$table->text('scopes')->nullable();
|
||||
$table->boolean('revoked');
|
||||
$table->smallInteger('revoked');
|
||||
$table->timestamps();
|
||||
$table->dateTime('expires_at')->nullable();
|
||||
});
|
||||
|
||||
@@ -14,7 +14,7 @@ return new class extends Migration
|
||||
Schema::create('oauth_refresh_tokens', function (Blueprint $table) {
|
||||
$table->string('id', 100)->primary();
|
||||
$table->string('access_token_id', 100)->index();
|
||||
$table->boolean('revoked');
|
||||
$table->smallInteger('revoked');
|
||||
$table->dateTime('expires_at')->nullable();
|
||||
});
|
||||
}
|
||||
|
||||
@@ -18,9 +18,9 @@ return new class extends Migration
|
||||
$table->string('secret', 100)->nullable();
|
||||
$table->string('provider')->nullable();
|
||||
$table->text('redirect');
|
||||
$table->boolean('personal_access_client');
|
||||
$table->boolean('password_client');
|
||||
$table->boolean('revoked');
|
||||
$table->smallInteger('personal_access_client');
|
||||
$table->smallInteger('password_client');
|
||||
$table->smallInteger('revoked');
|
||||
$table->timestamps();
|
||||
});
|
||||
}
|
||||
|
||||
@@ -18,7 +18,7 @@ class CreateAdvertisementsTable extends Migration
|
||||
}
|
||||
Schema::create('advertisements', function (Blueprint $table) {
|
||||
$table->mediumIncrements('id');
|
||||
$table->boolean('enabled')->default(0);
|
||||
$table->smallInteger('enabled')->default(0);
|
||||
$table->enum('type', ['bbcodes', 'xhtml', 'text', 'image', 'flash']);
|
||||
$table->enum('position', ['header', 'footer', 'belownav', 'belowsearchbox', 'torrentdetail', 'comment', 'interoverforums', 'forumpost', 'popup']);
|
||||
$table->tinyInteger('displayorder')->default(0);
|
||||
|
||||
@@ -17,7 +17,7 @@ class CreateAgentAllowedExceptionTable extends Migration
|
||||
return;
|
||||
}
|
||||
Schema::create('agent_allowed_exception', function (Blueprint $table) {
|
||||
$table->unsignedTinyInteger('family_id')->default(0)->index('family_id');
|
||||
$table->unsignedTinyInteger('family_id')->default(0)->index();
|
||||
$table->string('name', 100)->default('');
|
||||
$table->string('peer_id', 20)->default('');
|
||||
$table->string('agent', 100)->default('');
|
||||
|
||||
@@ -22,15 +22,15 @@ class CreateAttachmentsTable extends Migration
|
||||
$table->unsignedSmallInteger('width')->default(0);
|
||||
$table->dateTime('added')->nullable();
|
||||
$table->string('filename')->default('');
|
||||
$table->char('dlkey', 32)->index('idx_delkey');
|
||||
$table->char('dlkey', 32)->index();
|
||||
$table->string('filetype', 50)->default('');
|
||||
$table->unsignedBigInteger('filesize')->default(0);
|
||||
$table->string('location')->default('');
|
||||
$table->mediumInteger('downloads')->default(0);
|
||||
$table->boolean('isimage')->unsigned()->default(0);
|
||||
$table->boolean('thumb')->unsigned()->default(0);
|
||||
$table->smallInteger('isimage')->unsigned()->default(0);
|
||||
$table->smallInteger('thumb')->unsigned()->default(0);
|
||||
$table->index(['userid', 'id'], 'pid');
|
||||
$table->index(['added', 'isimage', 'downloads'], 'dateline');
|
||||
$table->index(['added', 'isimage', 'downloads'], );
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@@ -18,7 +18,7 @@ class CreateAttendanceTable extends Migration
|
||||
}
|
||||
Schema::create('attendance', function (Blueprint $table) {
|
||||
$table->bigIncrements('id');
|
||||
$table->unsignedInteger('uid')->default(0)->index('idx_uid');
|
||||
$table->unsignedInteger('uid')->default(0)->index();
|
||||
$table->dateTime('added')->index();
|
||||
$table->unsignedInteger('points')->default(0);
|
||||
$table->unsignedInteger('days')->default(1);
|
||||
|
||||
@@ -23,7 +23,7 @@ class CreateBansTable extends Migration
|
||||
$table->string('comment')->default('');
|
||||
$table->bigInteger('first')->default(0);
|
||||
$table->bigInteger('last')->default(0);
|
||||
$table->index(['first', 'last'], 'first_last');
|
||||
$table->index(['first', 'last'], );
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@@ -20,7 +20,7 @@ class CreateBlocksTable extends Migration
|
||||
$table->increments('id');
|
||||
$table->unsignedMediumInteger('userid')->default(0);
|
||||
$table->unsignedMediumInteger('blockid')->default(0);
|
||||
$table->unique(['userid', 'blockid'], 'userfriend');
|
||||
$table->unique(['userid', 'blockid'],);
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@@ -20,7 +20,7 @@ class CreateBookmarksTable extends Migration
|
||||
$table->increments('id');
|
||||
$table->unsignedMediumInteger('torrentid')->default(0);
|
||||
$table->unsignedMediumInteger('userid')->default(0);
|
||||
$table->index(['userid', 'torrentid'], 'userid_torrentid');
|
||||
$table->index(['userid', 'torrentid'], );
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@@ -24,7 +24,7 @@ class CreateCategoriesTable extends Migration
|
||||
$table->string('image')->default('');
|
||||
$table->unsignedSmallInteger('sort_index')->default(0);
|
||||
$table->integer('icon_id')->default(0);
|
||||
$table->index(['mode', 'sort_index'], 'mode_sort');
|
||||
$table->index(['mode', 'sort_index'], );
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@@ -28,7 +28,7 @@ class CreateCheatersTable extends Migration
|
||||
$table->unsignedMediumInteger('leechers')->default(0);
|
||||
$table->unsignedTinyInteger('hit')->default(0);
|
||||
$table->unsignedMediumInteger('dealtby')->default(0);
|
||||
$table->boolean('dealtwith')->default(0);
|
||||
$table->smallInteger('dealtwith')->default(0);
|
||||
$table->string('comment')->default('');
|
||||
});
|
||||
}
|
||||
|
||||
@@ -19,7 +19,7 @@ class CreateChronicleTable extends Migration
|
||||
Schema::create('chronicle', function (Blueprint $table) {
|
||||
$table->mediumIncrements('id');
|
||||
$table->unsignedMediumInteger('userid')->default(0);
|
||||
$table->dateTime('added')->nullable()->index('added');
|
||||
$table->dateTime('added')->nullable()->index();
|
||||
$table->text('txt')->nullable();
|
||||
});
|
||||
}
|
||||
|
||||
@@ -18,7 +18,7 @@ class CreateCommentsTable extends Migration
|
||||
}
|
||||
Schema::create('comments', function (Blueprint $table) {
|
||||
$table->increments('id');
|
||||
$table->unsignedMediumInteger('user')->default(0)->index('user');
|
||||
$table->unsignedMediumInteger('user')->default(0)->index();
|
||||
$table->unsignedMediumInteger('torrent')->default(0);
|
||||
$table->dateTime('added')->nullable();
|
||||
$table->text('text')->nullable();
|
||||
@@ -28,8 +28,8 @@ class CreateCommentsTable extends Migration
|
||||
$table->unsignedMediumInteger('offer')->default(0);
|
||||
$table->integer('request')->default(0);
|
||||
$table->enum('anonymous', ['yes', 'no'])->default('no');
|
||||
$table->index(['torrent', 'id'], 'torrent_id');
|
||||
$table->index(['offer', 'id'], 'offer_id');
|
||||
$table->index(['torrent', 'id'], );
|
||||
$table->index(['offer', 'id'], );
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@@ -18,7 +18,7 @@ class CreateFilesTable extends Migration
|
||||
}
|
||||
Schema::create('files', function (Blueprint $table) {
|
||||
$table->increments('id');
|
||||
$table->unsignedMediumInteger('torrent')->default(0)->index('torrent');
|
||||
$table->unsignedMediumInteger('torrent')->default(0)->index();
|
||||
$table->string('filename')->default('');
|
||||
$table->unsignedBigInteger('size')->default(0);
|
||||
});
|
||||
|
||||
@@ -18,7 +18,7 @@ class CreateForummodsTable extends Migration
|
||||
}
|
||||
Schema::create('forummods', function (Blueprint $table) {
|
||||
$table->smallIncrements('id');
|
||||
$table->unsignedSmallInteger('forumid')->default(0)->index('forumid');
|
||||
$table->unsignedSmallInteger('forumid')->default(0)->index();
|
||||
$table->unsignedMediumInteger('userid')->default(0);
|
||||
});
|
||||
}
|
||||
|
||||
@@ -20,7 +20,7 @@ class CreateFriendsTable extends Migration
|
||||
$table->increments('id');
|
||||
$table->unsignedMediumInteger('userid')->default(0);
|
||||
$table->unsignedMediumInteger('friendid')->default(0);
|
||||
$table->unique(['userid', 'friendid'], 'userfriend');
|
||||
$table->unique(['userid', 'friendid']);
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@@ -20,7 +20,7 @@ class CreateInvitesTable extends Migration
|
||||
$table->increments('id');
|
||||
$table->unsignedMediumInteger('inviter')->default(0);
|
||||
$table->string('invitee', 80)->default('');
|
||||
$table->char('hash', 32)->index('hash');
|
||||
$table->char('hash', 32)->index();
|
||||
$table->dateTime('time_invited')->nullable();
|
||||
$table->tinyInteger('valid')->default(1);
|
||||
$table->integer('invitee_register_uid')->nullable();
|
||||
|
||||
@@ -19,7 +19,7 @@ class CreateIplogTable extends Migration
|
||||
Schema::create('iplog', function (Blueprint $table) {
|
||||
$table->bigIncrements('id');
|
||||
$table->string('ip', 64)->default('');
|
||||
$table->unsignedMediumInteger('userid')->default(0)->index('userid');
|
||||
$table->unsignedMediumInteger('userid')->default(0)->index();
|
||||
$table->dateTime('access')->nullable();
|
||||
});
|
||||
}
|
||||
|
||||
@@ -18,8 +18,8 @@ class CreateMagicTable extends Migration
|
||||
}
|
||||
Schema::create('magic', function (Blueprint $table) {
|
||||
$table->bigIncrements('id');
|
||||
$table->integer('torrentid')->default(0)->index('idx_torrentid');
|
||||
$table->integer('userid')->default(0)->index('idx_userid');
|
||||
$table->integer('torrentid')->default(0)->index();
|
||||
$table->integer('userid')->default(0)->index();
|
||||
$table->integer('value')->default(0);
|
||||
$table->timestamp('created_at')->useCurrent();
|
||||
$table->timestamp('updated_at')->useCurrent();
|
||||
|
||||
@@ -18,8 +18,8 @@ class CreateMessagesTable extends Migration
|
||||
}
|
||||
Schema::create('messages', function (Blueprint $table) {
|
||||
$table->increments('id');
|
||||
$table->unsignedMediumInteger('sender')->default(0)->index('sender');
|
||||
$table->unsignedMediumInteger('receiver')->default(0)->index('receiver');
|
||||
$table->unsignedMediumInteger('sender')->default(0)->index();
|
||||
$table->unsignedMediumInteger('receiver')->default(0)->index();
|
||||
$table->dateTime('added')->nullable();
|
||||
$table->string('subject', 128)->default('');
|
||||
$table->text('msg')->nullable();
|
||||
|
||||
@@ -19,7 +19,7 @@ class CreateNewsTable extends Migration
|
||||
Schema::create('news', function (Blueprint $table) {
|
||||
$table->mediumIncrements('id');
|
||||
$table->unsignedMediumInteger('userid')->default(0);
|
||||
$table->dateTime('added')->nullable()->index('added');
|
||||
$table->dateTime('added')->nullable()->index();
|
||||
$table->text('body')->nullable();
|
||||
$table->string('title')->default('');
|
||||
$table->enum('notify', ['yes', 'no'])->default('no');
|
||||
|
||||
@@ -18,7 +18,7 @@ class CreateOffersTable extends Migration
|
||||
}
|
||||
Schema::create('offers', function (Blueprint $table) {
|
||||
$table->mediumIncrements('id');
|
||||
$table->unsignedMediumInteger('userid')->default(0)->index('userid');
|
||||
$table->unsignedMediumInteger('userid')->default(0)->index();
|
||||
$table->string('name', 225)->default('');
|
||||
$table->text('descr')->nullable();
|
||||
$table->dateTime('added')->nullable();
|
||||
|
||||
@@ -19,7 +19,7 @@ class CreateOffervotesTable extends Migration
|
||||
Schema::create('offervotes', function (Blueprint $table) {
|
||||
$table->increments('id');
|
||||
$table->unsignedMediumInteger('offerid')->default(0);
|
||||
$table->unsignedMediumInteger('userid')->default(0)->index('userid');
|
||||
$table->unsignedMediumInteger('userid')->default(0)->index();
|
||||
$table->enum('vote', ['yeah', 'against'])->default('yeah');
|
||||
});
|
||||
}
|
||||
|
||||
@@ -19,7 +19,7 @@ class CreatePeersTable extends Migration
|
||||
Schema::create('peers', function (Blueprint $table) {
|
||||
$table->bigIncrements('id');
|
||||
$table->unsignedMediumInteger('torrent')->default(0);
|
||||
$table->char('peer_id', 20)->charset('binary')->index();
|
||||
$table->binary('peer_id', 20)->index();
|
||||
$table->string('ip', 64)->default('');
|
||||
$table->unsignedSmallInteger('port')->default(0);
|
||||
$table->unsignedBigInteger('uploaded')->default(0);
|
||||
@@ -36,7 +36,7 @@ class CreatePeersTable extends Migration
|
||||
$table->unsignedBigInteger('downloadoffset')->default(0);
|
||||
$table->unsignedBigInteger('uploadoffset')->default(0);
|
||||
$table->char('passkey', 32)->default('');
|
||||
$table->unique(['torrent', 'peer_id']);
|
||||
$table->unique(['torrent', 'peer_id', 'userid']);
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@@ -18,9 +18,9 @@ class CreatePollanswersTable extends Migration
|
||||
}
|
||||
Schema::create('pollanswers', function (Blueprint $table) {
|
||||
$table->increments('id');
|
||||
$table->unsignedMediumInteger('pollid')->default(0)->index('pollid');
|
||||
$table->unsignedMediumInteger('userid')->default(0)->index('userid');
|
||||
$table->unsignedTinyInteger('selection')->default(0)->index('selection');
|
||||
$table->unsignedMediumInteger('pollid')->default(0)->index();
|
||||
$table->unsignedMediumInteger('userid')->default(0)->index();
|
||||
$table->unsignedTinyInteger('selection')->default(0)->index();
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@@ -19,15 +19,14 @@ class CreatePostsTable extends Migration
|
||||
Schema::create('posts', function (Blueprint $table) {
|
||||
$table->increments('id');
|
||||
$table->unsignedMediumInteger('topicid')->default(0);
|
||||
$table->unsignedMediumInteger('userid')->default(0)->index('userid');
|
||||
$table->dateTime('added')->nullable()->index('added');
|
||||
$table->unsignedMediumInteger('userid')->default(0)->index();
|
||||
$table->dateTime('added')->nullable()->index();
|
||||
$table->text('body')->nullable();
|
||||
$table->text('ori_body')->nullable();
|
||||
$table->unsignedMediumInteger('editedby')->default(0);
|
||||
$table->dateTime('editdate')->nullable();
|
||||
$table->index(['topicid', 'id'], 'topicid_id');
|
||||
$table->index(['topicid', 'id']);
|
||||
});
|
||||
\Illuminate\Support\Facades\DB::statement('alter table posts add fulltext body(body)');
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -18,8 +18,8 @@ class CreateReadpostsTable extends Migration
|
||||
}
|
||||
Schema::create('readposts', function (Blueprint $table) {
|
||||
$table->increments('id');
|
||||
$table->unsignedMediumInteger('userid')->default(0)->index('userid');
|
||||
$table->unsignedMediumInteger('topicid')->default(0)->index('topicid');
|
||||
$table->unsignedMediumInteger('userid')->default(0)->index();
|
||||
$table->unsignedMediumInteger('topicid')->default(0)->index();
|
||||
$table->unsignedInteger('lastpostread')->default(0);
|
||||
});
|
||||
}
|
||||
|
||||
@@ -24,7 +24,7 @@ class CreateReportsTable extends Migration
|
||||
$table->enum('type', ['torrent', 'user', 'offer', 'request', 'post', 'comment', 'subtitle'])->default('torrent');
|
||||
$table->string('reason')->default('');
|
||||
$table->unsignedMediumInteger('dealtby')->default(0);
|
||||
$table->boolean('dealtwith')->default(0);
|
||||
$table->smallInteger('dealtwith')->default(0);
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@@ -18,7 +18,7 @@ class CreateRequestsTable extends Migration
|
||||
}
|
||||
Schema::create('requests', function (Blueprint $table) {
|
||||
$table->increments('id');
|
||||
$table->unsignedInteger('userid')->default(0)->index('userid');
|
||||
$table->unsignedInteger('userid')->default(0)->index();
|
||||
$table->string('request', 225)->default('');
|
||||
$table->text('descr');
|
||||
$table->unsignedInteger('comments')->default(0);
|
||||
@@ -31,7 +31,7 @@ class CreateRequestsTable extends Migration
|
||||
$table->string('ori_descr')->default('');
|
||||
$table->integer('ori_amount')->default(0);
|
||||
$table->dateTime('added')->nullable();
|
||||
$table->index(['finish', 'userid'], 'finish, userid');
|
||||
$table->index(['finish', 'userid']);
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@@ -18,7 +18,7 @@ class CreateResreqTable extends Migration
|
||||
}
|
||||
Schema::create('resreq', function (Blueprint $table) {
|
||||
$table->integer('id', true);
|
||||
$table->integer('reqid')->default(0)->index('reqid');
|
||||
$table->integer('reqid')->default(0)->index();
|
||||
$table->integer('torrentid')->default(0);
|
||||
$table->enum('chosen', ['yes', 'no'])->default('no');
|
||||
});
|
||||
|
||||
@@ -23,7 +23,7 @@ class CreateSearchboxFieldsTable extends Migration
|
||||
$table->integer('field_id')->default(0);
|
||||
$table->timestamp('created_at')->useCurrent();
|
||||
$table->timestamp('update_at')->useCurrent();
|
||||
$table->unique(['searchbox_id', 'field_type', 'field_id'], 'uniq_searchbox_type_id');
|
||||
$table->unique(['searchbox_id', 'field_type', 'field_id']);
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@@ -19,14 +19,14 @@ class CreateSearchboxTable extends Migration
|
||||
Schema::create('searchbox', function (Blueprint $table) {
|
||||
$table->smallIncrements('id');
|
||||
$table->string('name', 30)->nullable();
|
||||
$table->boolean('showsubcat')->default(0);
|
||||
$table->boolean('showsource')->default(0);
|
||||
$table->boolean('showmedium')->default(0);
|
||||
$table->boolean('showcodec')->default(0);
|
||||
$table->boolean('showstandard')->default(0);
|
||||
$table->boolean('showprocessing')->default(0);
|
||||
$table->boolean('showteam')->default(0);
|
||||
$table->boolean('showaudiocodec')->default(0);
|
||||
$table->smallInteger('showsubcat')->default(0);
|
||||
$table->smallInteger('showsource')->default(0);
|
||||
$table->smallInteger('showmedium')->default(0);
|
||||
$table->smallInteger('showcodec')->default(0);
|
||||
$table->smallInteger('showstandard')->default(0);
|
||||
$table->smallInteger('showprocessing')->default(0);
|
||||
$table->smallInteger('showteam')->default(0);
|
||||
$table->smallInteger('showaudiocodec')->default(0);
|
||||
$table->unsignedSmallInteger('catsperrow')->default(7);
|
||||
$table->unsignedSmallInteger('catpadding')->default(25);
|
||||
$table->text('custom_fields')->nullable();
|
||||
|
||||
@@ -18,7 +18,7 @@ class CreateSettingsTable extends Migration
|
||||
}
|
||||
Schema::create('settings', function (Blueprint $table) {
|
||||
$table->integer('id', true);
|
||||
$table->string('name')->default('')->unique('uniqe_name');
|
||||
$table->string('name')->default('')->unique();
|
||||
$table->mediumText('value')->nullable();
|
||||
$table->timestamp('created_at')->useCurrent();
|
||||
$table->timestamp('updated_at')->useCurrent();
|
||||
|
||||
@@ -18,7 +18,7 @@ class CreateSitelogTable extends Migration
|
||||
}
|
||||
Schema::create('sitelog', function (Blueprint $table) {
|
||||
$table->increments('id');
|
||||
$table->dateTime('added')->nullable()->index('added');
|
||||
$table->dateTime('added')->nullable()->index();
|
||||
$table->text('txt');
|
||||
$table->enum('security_level', ['normal', 'mod'])->default('normal');
|
||||
});
|
||||
|
||||
@@ -19,7 +19,7 @@ class CreateSnatchedTable extends Migration
|
||||
Schema::create('snatched', function (Blueprint $table) {
|
||||
$table->bigIncrements('id', true);
|
||||
$table->unsignedMediumInteger('torrentid')->default(0);
|
||||
$table->unsignedMediumInteger('userid')->default(0)->index('userid');
|
||||
$table->unsignedMediumInteger('userid')->default(0)->index();
|
||||
$table->string('ip', 64)->default('');
|
||||
$table->unsignedSmallInteger('port')->default(0);
|
||||
$table->unsignedBigInteger('uploaded')->default(0);
|
||||
@@ -31,7 +31,7 @@ class CreateSnatchedTable extends Migration
|
||||
$table->dateTime('startdat')->nullable();
|
||||
$table->dateTime('completedat')->nullable();
|
||||
$table->enum('finished', ['yes', 'no'])->default('no');
|
||||
$table->unique(['torrentid', 'userid'], 'torrentid_userid');
|
||||
$table->unique(['torrentid', 'userid']);
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@@ -23,7 +23,7 @@ class CreateStaffmessagesTable extends Migration
|
||||
$table->text('msg')->nullable();
|
||||
$table->string('subject', 128)->default('');
|
||||
$table->unsignedMediumInteger('answeredby')->default(0);
|
||||
$table->boolean('answered')->default(0);
|
||||
$table->smallInteger('answered')->default(0);
|
||||
$table->text('answer')->nullable();
|
||||
});
|
||||
}
|
||||
|
||||
@@ -28,7 +28,7 @@ class CreateSubsTable extends Migration
|
||||
$table->enum('anonymous', ['yes', 'no'])->default('no');
|
||||
$table->unsignedMediumInteger('hits')->default(0);
|
||||
$table->string('ext', 10)->default('');
|
||||
$table->index(['torrent_id', 'lang_id'], 'torrentid_langid');
|
||||
$table->index(['torrent_id', 'lang_id'],);
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@@ -18,9 +18,9 @@ class CreateSuggestTable extends Migration
|
||||
}
|
||||
Schema::create('suggest', function (Blueprint $table) {
|
||||
$table->increments('id');
|
||||
$table->string('keywords')->default('')->index('keywords');
|
||||
$table->string('keywords')->default('')->index();
|
||||
$table->unsignedMediumInteger('userid')->default(0);
|
||||
$table->dateTime('adddate')->nullable()->index('adddate');
|
||||
$table->dateTime('adddate')->nullable()->index();
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@@ -18,8 +18,8 @@ class CreateTopicsTable extends Migration
|
||||
}
|
||||
Schema::create('topics', function (Blueprint $table) {
|
||||
$table->mediumIncrements('id');
|
||||
$table->unsignedMediumInteger('userid')->default(0)->index('userid');
|
||||
$table->string('subject', 128)->default('')->index('subject');
|
||||
$table->unsignedMediumInteger('userid')->default(0)->index();
|
||||
$table->string('subject', 128)->default('')->index();
|
||||
$table->enum('locked', ['yes', 'no'])->default('no');
|
||||
$table->unsignedSmallInteger('forumid')->default(0);
|
||||
$table->unsignedInteger('firstpost')->default(0);
|
||||
@@ -27,8 +27,8 @@ class CreateTopicsTable extends Migration
|
||||
$table->enum('sticky', ['no', 'yes'])->default('no');
|
||||
$table->unsignedTinyInteger('hlcolor')->default(0);
|
||||
$table->unsignedInteger('views')->default(0);
|
||||
$table->index(['forumid', 'lastpost'], 'forumid_lastpost');
|
||||
$table->index(['forumid', 'sticky', 'lastpost'], 'forumid_sticky_lastpost');
|
||||
$table->index(['forumid', 'lastpost'], );
|
||||
$table->index(['forumid', 'sticky', 'lastpost'], );
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@@ -18,8 +18,8 @@ class CreateTorrentSecretsTable extends Migration
|
||||
}
|
||||
Schema::create('torrent_secrets', function (Blueprint $table) {
|
||||
$table->integer('id', true);
|
||||
$table->integer('uid')->index('idx_uid');
|
||||
$table->integer('torrent_id')->default(0)->index('idx_torrent_id');
|
||||
$table->integer('uid')->index();
|
||||
$table->integer('torrent_id')->default(0)->index();
|
||||
$table->string('secret');
|
||||
$table->timestamp('created_at')->useCurrent();
|
||||
$table->timestamp('updated_at')->useCurrent();
|
||||
|
||||
@@ -18,13 +18,16 @@ class CreateTorrentsCustomFieldValuesTable extends Migration
|
||||
}
|
||||
Schema::create('torrents_custom_field_values', function (Blueprint $table) {
|
||||
$table->integer('id', true);
|
||||
$table->integer('torrent_id')->default(0)->index('idx_torrent_id');
|
||||
$table->integer('custom_field_id')->default(0)->index('idx_field_id');
|
||||
$table->integer('torrent_id')->default(0)->index();
|
||||
$table->integer('custom_field_id')->default(0)->index();
|
||||
$table->mediumText('custom_field_value')->nullable();
|
||||
$table->dateTime('created_at');
|
||||
$table->dateTime('updated_at');
|
||||
});
|
||||
\Illuminate\Support\Facades\DB::statement('alter table torrents_custom_field_values add index(custom_field_value(191))');
|
||||
if (\Nexus\Database\NexusDB::isMysql()) {
|
||||
\Illuminate\Support\Facades\DB::statement('alter table torrents_custom_field_values add index(custom_field_value(191))');
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -18,7 +18,8 @@ class CreateTorrentsTable extends Migration
|
||||
}
|
||||
Schema::create('torrents', function (Blueprint $table) {
|
||||
$table->mediumIncrements('id');
|
||||
$table->string('name')->default('')->index('name');
|
||||
$table->binary('info_hash', 20)->nullable()->unique();
|
||||
$table->string('name')->default('')->index();
|
||||
$table->string('filename')->default('');
|
||||
$table->string('save_as')->default('');
|
||||
$table->text('descr')->nullable();
|
||||
@@ -45,27 +46,26 @@ class CreateTorrentsTable extends Migration
|
||||
$table->dateTime('last_action')->nullable();
|
||||
$table->enum('visible', ['yes', 'no'])->default('yes');
|
||||
$table->enum('banned', ['yes', 'no'])->default('no');
|
||||
$table->unsignedMediumInteger('owner')->default(0)->index('owner');
|
||||
$table->unsignedMediumInteger('owner')->default(0)->index();
|
||||
$table->binary('nfo')->nullable();
|
||||
$table->unsignedTinyInteger('sp_state')->default(1);
|
||||
$table->unsignedTinyInteger('promotion_time_type')->default(0);
|
||||
$table->dateTime('promotion_until')->nullable();
|
||||
$table->enum('anonymous', ['yes', 'no'])->default('no');
|
||||
$table->unsignedInteger('url')->nullable()->index('url');
|
||||
$table->unsignedInteger('url')->nullable()->index();
|
||||
$table->string('pos_state', 32)->default('normal');
|
||||
$table->unsignedTinyInteger('cache_stamp')->default(0);
|
||||
$table->enum('picktype', ['hot', 'classic', 'recommended', 'normal'])->default('normal');
|
||||
$table->dateTime('picktime')->nullable();
|
||||
$table->dateTime('last_reseed')->nullable();
|
||||
$table->mediumText('pt_gen')->nullable();
|
||||
// $table->integer('tags')->default(0);
|
||||
$table->text('technical_info')->nullable();
|
||||
$table->index(['visible', 'pos_state', 'id'], 'visible_pos_id');
|
||||
$table->index(['category', 'visible', 'banned'], 'category_visible_banned');
|
||||
$table->index(['visible', 'banned', 'pos_state', 'id'], 'visible_banned_pos_id');
|
||||
$table->index(['visible', 'pos_state', 'id'] );
|
||||
$table->index(['category', 'visible', 'banned']);
|
||||
$table->index(['visible', 'banned', 'pos_state', 'id']);
|
||||
});
|
||||
$sql = 'alter table torrents add column `info_hash` binary(20) NOT NULL after id, add unique info_hash(`info_hash`)';
|
||||
\Illuminate\Support\Facades\DB::statement($sql);
|
||||
// $sql = 'alter table torrents add column `info_hash` binary(20) NOT NULL after id, add unique info_hash(`info_hash`)';
|
||||
// \Illuminate\Support\Facades\DB::statement($sql);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -18,8 +18,8 @@ class CreateUserBanLogsTable extends Migration
|
||||
}
|
||||
Schema::create('user_ban_logs', function (Blueprint $table) {
|
||||
$table->bigInteger('id', true);
|
||||
$table->integer('uid')->default(0)->index('idx_uid');
|
||||
$table->string('username')->default('')->index('idx_username');
|
||||
$table->integer('uid')->default(0)->index();
|
||||
$table->string('username')->default('')->index();
|
||||
$table->integer('operator')->default(0);
|
||||
$table->string('reason')->nullable();
|
||||
$table->timestamp('created_at')->nullable()->useCurrent();
|
||||
|
||||
@@ -22,14 +22,14 @@ class CreateUsersTable extends Migration
|
||||
}
|
||||
Schema::create('users', function (Blueprint $table) use ($uidStarts) {
|
||||
$table->id('id')->startingValue($uidStarts);
|
||||
$table->string('username', 40)->default('')->unique('username');
|
||||
$table->string('username', 40)->default('')->unique();
|
||||
$table->string('passhash', 32)->default('');
|
||||
$table->binary('secret');
|
||||
$table->string('email', 80)->default('');
|
||||
$table->enum('status', ['pending', 'confirmed'])->default('pending');
|
||||
$table->dateTime('added')->nullable();
|
||||
$table->dateTime('last_login')->nullable();
|
||||
$table->dateTime('last_access')->nullable()->index('last_access');
|
||||
$table->dateTime('last_access')->nullable()->index();
|
||||
$table->dateTime('last_home')->nullable();
|
||||
$table->dateTime('last_offer')->nullable();
|
||||
$table->dateTime('forum_access')->nullable();
|
||||
@@ -48,25 +48,25 @@ class CreateUsersTable extends Migration
|
||||
$table->text('info')->nullable();
|
||||
$table->enum('acceptpms', ['yes', 'friends', 'no'])->default('yes');
|
||||
$table->enum('commentpm', ['yes', 'no'])->default('yes');
|
||||
$table->string('ip', 64)->default('')->index('ip');
|
||||
$table->unsignedTinyInteger('class')->default(1)->index('class');
|
||||
$table->string('ip', 64)->default('')->index();
|
||||
$table->unsignedTinyInteger('class')->default(1)->index();
|
||||
$table->tinyInteger('max_class_once')->default(1);
|
||||
$table->string('avatar')->default('');
|
||||
$table->unsignedBigInteger('uploaded')->default(0)->index('uploaded');
|
||||
$table->unsignedBigInteger('downloaded')->default(0)->index('downloaded');
|
||||
$table->unsignedBigInteger('uploaded')->default(0)->index();
|
||||
$table->unsignedBigInteger('downloaded')->default(0)->index();
|
||||
$table->unsignedBigInteger('seedtime')->default(0);
|
||||
$table->unsignedBigInteger('leechtime')->default(0);
|
||||
$table->string('title', 30)->default('');
|
||||
$table->unsignedSmallInteger('country')->default(107)->index('country');
|
||||
$table->unsignedSmallInteger('country')->default(107)->index();
|
||||
$table->string('notifs', 500)->nullable();
|
||||
$table->text('modcomment')->nullable();
|
||||
$table->enum('enabled', ['yes', 'no'])->default('yes')->index('enabled');
|
||||
$table->enum('enabled', ['yes', 'no'])->default('yes')->index();
|
||||
$table->enum('avatars', ['yes', 'no'])->default('yes');
|
||||
$table->enum('donor', ['yes', 'no'])->default('no');
|
||||
$table->decimal('donated')->default(0.00);
|
||||
$table->decimal('donated_cny')->default(0.00);
|
||||
$table->dateTime('donoruntil')->nullable();
|
||||
$table->enum('warned', ['yes', 'no'])->default('no')->index('warned');
|
||||
$table->enum('warned', ['yes', 'no'])->default('no')->index();
|
||||
$table->dateTime('warneduntil')->nullable();
|
||||
$table->enum('noad', ['yes', 'no'])->default('no');
|
||||
$table->dateTime('noaduntil')->nullable();
|
||||
@@ -84,7 +84,7 @@ class CreateUsersTable extends Migration
|
||||
$table->string('supportfor')->default('');
|
||||
$table->string('pickfor')->default('');
|
||||
$table->string('supportlang', 50)->default('');
|
||||
$table->string('passkey', 32)->default('')->index('passkey');
|
||||
$table->string('passkey', 32)->default('')->index();
|
||||
$table->string('promotion_link', 32)->nullable();
|
||||
$table->enum('uploadpos', ['yes', 'no'])->default('yes');
|
||||
$table->enum('forumpost', ['yes', 'no'])->default('yes');
|
||||
@@ -93,7 +93,7 @@ class CreateUsersTable extends Migration
|
||||
$table->enum('signatures', ['yes', 'no'])->default('yes');
|
||||
$table->string('signature', 800)->default('');
|
||||
$table->unsignedSmallInteger('lang')->default(6);
|
||||
$table->smallInteger('cheat')->default(0)->index('cheat');
|
||||
$table->smallInteger('cheat')->default(0)->index();
|
||||
$table->unsignedInteger('download')->default(0);
|
||||
$table->unsignedInteger('upload')->default(0);
|
||||
$table->unsignedTinyInteger('isp')->default(0);
|
||||
@@ -118,7 +118,7 @@ class CreateUsersTable extends Migration
|
||||
$table->enum('showdescription', ['yes', 'no'])->nullable()->default('yes');
|
||||
$table->enum('showcomment', ['yes', 'no'])->nullable()->default('yes');
|
||||
$table->enum('showclienterror', ['yes', 'no'])->default('no');
|
||||
$table->boolean('showdlnotice')->default(1);
|
||||
$table->smallInteger('showdlnotice')->default(1);
|
||||
$table->enum('tooltip', ['minorimdb', 'medianimdb', 'off'])->default('off');
|
||||
$table->enum('shownfo', ['yes', 'no'])->nullable()->default('yes');
|
||||
$table->enum('timetype', ['timeadded', 'timealive'])->nullable()->default('timealive');
|
||||
@@ -136,7 +136,7 @@ class CreateUsersTable extends Migration
|
||||
$table->unsignedSmallInteger('school')->default(35);
|
||||
$table->enum('showfb', ['yes', 'no'])->default('yes');
|
||||
$table->string('page')->nullable()->default('');
|
||||
$table->index(['status', 'added'], 'status_added');
|
||||
$table->index(['status', 'added']);
|
||||
|
||||
});
|
||||
}
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user