Compare commits

...

15 Commits

Author SHA1 Message Date
xiaomlove 1372776ba1 pg support: group_concat 2026-04-25 13:44:23 +07:00
xiaomlove 7d18a7f76a pg support of duplicate key update 2026-04-25 03:22:38 +07:00
xiaomlove dc77ab7b40 pg support 2026-04-23 01:04:30 +07:00
xiaomlove 94a35b81dc migrations remove index name 2026-04-20 22:41:09 +07:00
xiaomlove dfe9436f1d remove debug 2026-04-18 12:18:46 +07:00
xiaomlove 4afcb1bb08 announce support pg 2026-04-18 12:15:14 +07:00
xiaomlove e3376c3f1b support pg problem fix 2026-04-16 04:03:52 +07:00
xiaomlove 00fdc2d08f support pg 2026-04-15 03:27:30 +07:00
xiaomlove 4d54e08918 migrations boolean() -> smallInteger() 2026-04-14 13:12:56 +07:00
xiaomlove 4d4af87dc9 update migrations to support pg 2026-04-13 14:17:19 +07:00
xiaomlove f271e28b15 DBPdo instead of DBMysqli 2026-04-13 03:12:04 +07:00
xiaomlove 9995767bf7 release v1.10.2 2026-04-11 12:07:31 +07:00
xiaomlove d115a3879a takelogin bark when self-enable feature is disable 2026-04-09 13:37:05 +07:00
xiaomlove 431fbfff56 fix self enable switch 2026-04-09 11:48:21 +07:00
xiaomlove 9e632811ef self enable add switch 2026-04-09 10:52:58 +07:00
121 changed files with 821 additions and 310 deletions
+1
View File
@@ -13,6 +13,7 @@ DB_PORT=3306
DB_DATABASE=nexusphp DB_DATABASE=nexusphp
DB_USERNAME=nexusphp DB_USERNAME=nexusphp
DB_PASSWORD=nexusphp DB_PASSWORD=nexusphp
DB_SCHEMA=public
BROADCAST_DRIVER=log BROADCAST_DRIVER=log
CACHE_DRIVER=redis CACHE_DRIVER=redis
+1 -1
View File
@@ -108,7 +108,7 @@ class NexusUpdate extends Command
// $settings = $settingTableRows['settings']; // $settings = $settingTableRows['settings'];
$symbolicLinks = $settingTableRows['symbolic_links']; $symbolicLinks = $settingTableRows['symbolic_links'];
$fails = $settingTableRows['fails']; $fails = $settingTableRows['fails'];
$mysqlInfo = $this->update->getMysqlVersionInfo(); $mysqlInfo = $this->update->getDatabaseVersionInfo();
$redisInfo = $this->update->getRedisVersionInfo(); $redisInfo = $this->update->getRedisVersionInfo();
if (!empty($fails)) { if (!empty($fails)) {
@@ -29,7 +29,7 @@ class MigrateTorrentsTableTextColumn extends Command
public function handle() public function handle()
{ {
if (Schema::hasTable("torrent_extras") && Schema::hasColumn("torrents", "descr")) { 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"]; $columns = ["ori_descr", "descr", "nfo", "technical_info", "pt_gen"];
$sql = "alter table torrents "; $sql = "alter table torrents ";
@@ -51,7 +51,7 @@ class UserPasskeyResource extends Resource
->formatStateUsing(fn($state) => username_for_admin($state)) ->formatStateUsing(fn($state) => username_for_admin($state))
->label(__('label.username')) ->label(__('label.username'))
, ,
Tables\Columns\TextColumn::make('AAGUID') Tables\Columns\TextColumn::make('aaguid')
->label("AAGUID") ->label("AAGUID")
, ,
Tables\Columns\TextColumn::make('credential_id') Tables\Columns\TextColumn::make('credential_id')
-1
View File
@@ -28,7 +28,6 @@ class RemoveUserDonorStatus
->with('language') ->with('language')
->where('donor', 'yes') ->where('donor', 'yes')
->whereNotNull('donoruntil') ->whereNotNull('donoruntil')
->where('donoruntil', '!=', '0000-00-00 00:00:00')
->where('donoruntil', '<', now()) ->where('donoruntil', '<', now())
->get(); ->get();
$userModifyLogs = []; $userModifyLogs = [];
+9
View File
@@ -0,0 +1,9 @@
<?php
namespace App\Models;
class Faq extends NexusModel
{
protected $table = 'faq';
}
+4 -1
View File
@@ -15,7 +15,10 @@ class NexusModel extends Model
protected $perPage = 50; protected $perPage = 50;
protected $connection = NexusDB::ELOQUENT_CONNECTION_NAME; public function getConnectionName()
{
return NexusDB::getConnectionName();
}
protected function usernameForAdmin(): Attribute protected function usernameForAdmin(): Attribute
{ {
+4 -3
View File
@@ -9,7 +9,7 @@ class Passkey extends NexusModel
public $timestamps = true; public $timestamps = true;
protected $fillable = [ protected $fillable = [
'id', 'user_id', 'AAGUID', 'credential_id', 'public_key', 'counter', 'id', 'user_id', 'aaguid', 'credential_id', 'public_key', 'counter',
]; ];
public function user() public function user()
@@ -17,8 +17,9 @@ class Passkey extends NexusModel
return $this->belongsTo(User::class, 'user_id'); return $this->belongsTo(User::class, 'user_id');
} }
public function AAGUID() { public function getAaguidFormatted(): string
$guid = $this->AAGUID; {
$guid = $this->aaguid;
return sprintf( return sprintf(
'%s-%s-%s-%s-%s', '%s-%s-%s-%s-%s',
substr($guid, 0, 8), substr($guid, 0, 8),
+13
View File
@@ -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'];
}
+41 -1
View File
@@ -5,6 +5,7 @@ namespace App\Models;
use App\Repositories\TagRepository; use App\Repositories\TagRepository;
use Carbon\Carbon; use Carbon\Carbon;
use Illuminate\Database\Eloquent\Casts\Attribute; use Illuminate\Database\Eloquent\Casts\Attribute;
use Nexus\Database\NexusDB;
class Torrent extends NexusModel class Torrent extends NexusModel
{ {
@@ -186,6 +187,37 @@ class Torrent extends NexusModel
self::NFO_VIEW_STYLE_WINDOWS => ['text' => 'Windows-vy'], 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() public function getPickInfoAttribute()
{ {
$info = self::$pickTypes[$this->picktype] ?? null; $info = self::$pickTypes[$this->picktype] ?? null;
@@ -521,8 +553,16 @@ class Torrent extends NexusModel
public function tags(): \Illuminate\Database\Eloquent\Relations\BelongsToMany 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') 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 public function reward_logs(): \Illuminate\Database\Eloquent\Relations\HasMany
+5 -3
View File
@@ -31,8 +31,6 @@ class User extends Authenticatable implements FilamentUser, HasName
protected $perPage = 50; protected $perPage = 50;
protected $connection = NexusDB::ELOQUENT_CONNECTION_NAME;
const STATUS_CONFIRMED = 'confirmed'; const STATUS_CONFIRMED = 'confirmed';
const STATUS_PENDING = 'pending'; const STATUS_PENDING = 'pending';
@@ -109,6 +107,11 @@ class User extends Authenticatable implements FilamentUser, HasName
private const USER_ENABLE_LATELY = "user_enable_lately:%s"; private const USER_ENABLE_LATELY = "user_enable_lately:%s";
public function getConnectionName()
{
return NexusDB::getConnectionName();
}
public static function getUserEnableLatelyCacheKey(int $userId): string public static function getUserEnableLatelyCacheKey(int $userId): string
{ {
return sprintf(self::USER_ENABLE_LATELY, $userId); 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->where('donor', 'yes')->where(function (Builder $query) {
return $query->whereNull('donoruntil') return $query->whereNull('donoruntil')
->orWhere('donoruntil', '0000-00-00 00:00:00')
->orWhere('donoruntil', '>=', now()); ->orWhere('donoruntil', '>=', now());
}); });
} }
+2 -2
View File
@@ -244,8 +244,8 @@ class AttendanceRepository extends BaseRepository
return 0; return 0;
} }
$sql = sprintf( $sql = sprintf(
"insert into `%s` (`uid`, `points`, `date`) values %s on duplicate key update `uid` = values(`uid`)", 'insert into %s (uid, points, "date") values %s %s',
$table, implode(',', $insert) $table, implode(',', $insert), NexusDB::upsertField(['uid'], ['uid'])
); );
NexusDB::statement($sql); NexusDB::statement($sql);
$insertCount = count($insert); $insertCount = count($insert);
+2 -1
View File
@@ -47,10 +47,11 @@ class DashboardRepository extends BaseRepository
'value' => PHP_VERSION, 'value' => PHP_VERSION,
]; ];
$name = 'mysql_version'; $name = 'mysql_version';
$databaseInfo = NexusDB::getDatabaseVersionInfo();
$result[$name] = [ $result[$name] = [
'name' => $name, 'name' => $name,
'text' => nexus_trans("dashboard.system_info.$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'; // $name = 'os';
// $result[$name] = [ // $result[$name] = [
+24 -8
View File
@@ -269,8 +269,12 @@ class ExamRepository extends BaseRepository
$now = Carbon::now(); $now = Carbon::now();
$query = Exam::query() $query = Exam::query()
->where('status', Exam::STATUS_ENABLED) ->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)") ->whereRaw('
; CASE
WHEN begin IS NOT NULL AND "end" IS NOT NULL
THEN begin <= ? AND "end" >= ?
ELSE duration > 0 OR recurring IS NOT NULL
END', [$now, $now]);
if (!is_null($excludeId)) { if (!is_null($excludeId)) {
$query->whereNotIn('id', Arr::wrap($excludeId)); $query->whereNotIn('id', Arr::wrap($excludeId));
@@ -1045,13 +1049,13 @@ class ExamRepository extends BaseRepository
if ($donateStatus == User::DONATE_YES) { if ($donateStatus == User::DONATE_YES) {
$baseQuery->where(function (Builder $query) { $baseQuery->where(function (Builder $query) {
$query->where('donor', 'yes')->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) { } elseif ($donateStatus == User::DONATE_NO) {
$baseQuery->where(function (Builder $query) { $baseQuery->where(function (Builder $query) {
$query->where('donor', 'no')->orWhere(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 { } else {
@@ -1139,10 +1143,22 @@ class ExamRepository extends BaseRepository
->orderBy("$examUserTable.id", "asc"); ->orderBy("$examUserTable.id", "asc");
if (!$ignoreTimeRange) { if (!$ignoreTimeRange) {
$whenThens = []; $whenThens = [];
$whenThens[] = "when $examUserTable.`end` is not null then $examUserTable.`end` < '$now'"; $params = [];
$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'"; $whenThens[] = "WHEN $examUserTable.\"end\" IS NOT NULL THEN $examUserTable.\"end\" < ?";
$baseQuery->whereRaw(sprintf("case %s else false end", implode(" ", $whenThens))); $params[] = $now;
$whenThens[] = "WHEN $examTable.\"end\" IS NOT NULL THEN $examTable.\"end\" < ?";
$params[] = $now;
if (NexusDB::isMysql()) {
$whenThens[] = "when $examTable.duration > 0 then date_add($examUserTable.created_at, interval $examTable.duration day) < ?";
} elseif (NexusDB::isPgsql()) {
$whenThens[] = "WHEN $examTable.duration > 0 THEN ($examUserTable.created_at + ($examTable.duration || ' day')::INTERVAL) < ?";
}
$params[] = $now;
$baseQuery->whereRaw(sprintf("CASE %s ELSE false END", implode(" ", $whenThens)), $params);
} }
$size = 1000; $size = 1000;
+1 -1
View File
@@ -400,7 +400,7 @@ class HitAndRunRepository extends BaseRepository
->selectRaw("count(*) as counts, uid") ->selectRaw("count(*) as counts, uid")
->where('status', HitAndRun::STATUS_UNREACHED) ->where('status', HitAndRun::STATUS_UNREACHED)
->groupBy('uid') ->groupBy('uid')
->having("counts", '>=', $disableCounts) ->havingRaw("count(*) >= $disableCounts")
; ;
if ($setting['diff_in_section']) { if ($setting['diff_in_section']) {
$query->whereHas('torrent.basic_category', function (Builder $query) use ($setting) { $query->whereHas('torrent.basic_category', function (Builder $query) use ($setting) {
+1 -1
View File
@@ -199,7 +199,7 @@ class SeedBoxRepository extends BaseRepository
$size = 1000; $size = 1000;
$page = 1; $page = 1;
$logPrefix = "isAllowed: $isAllowed->name, field: $field->name, page: $page, size: $size"; $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) { while (true) {
$list = SeedBoxRecord::getValidQuery(TypeEnum::USER, $isAllowed, $field) $list = SeedBoxRecord::getValidQuery(TypeEnum::USER, $isAllowed, $field)
->selectRaw($selectRaw) ->selectRaw($selectRaw)
+2 -2
View File
@@ -45,8 +45,8 @@ class SettingRepository extends BaseRepository
return true; return true;
} }
$sql = sprintf( $sql = sprintf(
"insert into `%s` (`name`, `value`) values %s on duplicate key update `value` = values(`value`)", 'insert into %s (name, "value") values %s %s',
$settingModel->getTable(), implode(', ', $values) $settingModel->getTable(), implode(', ', $values), NexusDB::upsertField(['name'], ['value'])
); );
$result = DB::insert($sql); $result = DB::insert($sql);
do_log("sql: $sql, result: $result"); do_log("sql: $sql, result: $result");
+1 -1
View File
@@ -133,7 +133,7 @@ class TagRepository extends BaseRepository
} }
$page++; $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"); do_log("migrate sql: $sql");
NexusDB::statement($sql); NexusDB::statement($sql);
do_log("[MIGRATE_TORRENT_TAG] done!"); do_log("[MIGRATE_TORRENT_TAG] done!");
+4 -2
View File
@@ -511,8 +511,9 @@ class ToolRepository extends BaseRepository
$stickyPromotionExists = NexusDB::hasTable($stickyPromotionParticipatorsTable); $stickyPromotionExists = NexusDB::hasTable($stickyPromotionParticipatorsTable);
$claimTableExists = NexusDB::hasTable($claimTable); $claimTableExists = NexusDB::hasTable($claimTable);
$hitAndRunTableExists = NexusDB::hasTable($hitAndRunTable); $hitAndRunTableExists = NexusDB::hasTable($hitAndRunTable);
$idsField = NexusDB::groupConcatField('id');
while (true) { 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)) { if (empty($snatchRes)) {
break; break;
} }
@@ -542,8 +543,9 @@ class ToolRepository extends BaseRepository
public function removeDuplicatePeer() public function removeDuplicatePeer()
{ {
$size = 2000; $size = 2000;
$idsField = NexusDB::groupConcatField('id');
while (true) { 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)) { if (empty($results)) {
do_log("[DELETE_DUPLICATED_PEERS], no data: ". last_query()); do_log("[DELETE_DUPLICATED_PEERS], no data: ". last_query());
break; break;
+1 -1
View File
@@ -749,7 +749,7 @@ class TorrentRepository extends BaseRepository
$values[] = sprintf("(%s, %s, '%s', '%s')", $torrentId, $tagId, $time, $time); $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) { if ($remove) {
TorrentTag::query()->whereIn('torrent_id', $idArr)->delete(); TorrentTag::query()->whereIn('torrent_id', $idArr)->delete();
} }
+1 -1
View File
@@ -219,7 +219,7 @@ class UserPasskeyRepository extends BaseRepository
<td> <td>
<div style="display:flex;align-items:center;padding:4px"> <div style="display:flex;align-items:center;padding:4px">
<?php <?php
$meta = $AAGUIDS[$passkey->AAGUID()]; $meta = $AAGUIDS[$passkey->getAaguidFormatted()];
if (isset($meta)) { 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); 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 { } else {
@@ -2,6 +2,7 @@
namespace App\Services\Captcha\Drivers; namespace App\Services\Captcha\Drivers;
use App\Models\RegImage;
use App\Services\Captcha\CaptchaDriverInterface; use App\Services\Captcha\CaptchaDriverInterface;
use App\Services\Captcha\Exceptions\CaptchaValidationException; use App\Services\Captcha\Exceptions\CaptchaValidationException;
@@ -67,16 +68,11 @@ class ImageCaptchaDriver implements CaptchaDriverInterface
$random = random_str(); $random = random_str();
$imagehash = md5($random); $imagehash = md5($random);
$dateline = time(); $dateline = time();
RegImage::query()->insert([
$sql = sprintf( 'imagehash' => $imagehash,
"INSERT INTO `regimages` (`imagehash`, `imagestring`, `dateline`) VALUES ('%s', '%s', '%s')", 'dateline' => $dateline,
mysql_real_escape_string($imagehash), 'imagestring' => $random,
mysql_real_escape_string($random), ]);
mysql_real_escape_string((string) $dateline)
);
sql_query($sql);
return $imagehash; return $imagehash;
} }
+3 -1
View File
@@ -35,6 +35,7 @@
"ext-xml": "*", "ext-xml": "*",
"ext-zend-opcache": "*", "ext-zend-opcache": "*",
"ext-zip": "*", "ext-zip": "*",
"ext-pdo": "*",
"calebporzio/sushi": "^2.5", "calebporzio/sushi": "^2.5",
"cybercog/laravel-clickhouse": "dev-master", "cybercog/laravel-clickhouse": "dev-master",
"elasticsearch/elasticsearch": "^7.16", "elasticsearch/elasticsearch": "^7.16",
@@ -87,7 +88,8 @@
"@php artisan key:generate --ansi" "@php artisan key:generate --ansi"
], ],
"post-update-cmd": [ "post-update-cmd": [
"@php artisan filament:upgrade" "@php artisan filament:upgrade",
"@php artisan livewire:publish --assets"
] ]
}, },
"extra": { "extra": {
+1 -1
View File
@@ -74,7 +74,7 @@ return [
'charset' => 'utf8', 'charset' => 'utf8',
'prefix' => '', 'prefix' => '',
'prefix_indexes' => true, 'prefix_indexes' => true,
'schema' => 'public', 'schema' => env('DB_SCHEMA', 'public'),
'sslmode' => 'prefer', 'sslmode' => 'prefer',
], ],
+39
View File
@@ -8,6 +8,45 @@ return [
'log_split' => nexus_env('LOG_SPLIT', 'daily'), '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' => [ 'mysql' => [
'driver' => 'mysql', 'driver' => 'mysql',
'url' => nexus_env('DATABASE_URL'), 'url' => nexus_env('DATABASE_URL'),
@@ -16,7 +16,7 @@ return new class extends Migration
$table->unsignedBigInteger('user_id')->index(); $table->unsignedBigInteger('user_id')->index();
$table->unsignedBigInteger('client_id'); $table->unsignedBigInteger('client_id');
$table->text('scopes')->nullable(); $table->text('scopes')->nullable();
$table->boolean('revoked'); $table->smallInteger('revoked');
$table->dateTime('expires_at')->nullable(); $table->dateTime('expires_at')->nullable();
}); });
} }
@@ -17,7 +17,7 @@ return new class extends Migration
$table->unsignedBigInteger('client_id'); $table->unsignedBigInteger('client_id');
$table->string('name')->nullable(); $table->string('name')->nullable();
$table->text('scopes')->nullable(); $table->text('scopes')->nullable();
$table->boolean('revoked'); $table->smallInteger('revoked');
$table->timestamps(); $table->timestamps();
$table->dateTime('expires_at')->nullable(); $table->dateTime('expires_at')->nullable();
}); });
@@ -14,7 +14,7 @@ return new class extends Migration
Schema::create('oauth_refresh_tokens', function (Blueprint $table) { Schema::create('oauth_refresh_tokens', function (Blueprint $table) {
$table->string('id', 100)->primary(); $table->string('id', 100)->primary();
$table->string('access_token_id', 100)->index(); $table->string('access_token_id', 100)->index();
$table->boolean('revoked'); $table->smallInteger('revoked');
$table->dateTime('expires_at')->nullable(); $table->dateTime('expires_at')->nullable();
}); });
} }
@@ -18,9 +18,9 @@ return new class extends Migration
$table->string('secret', 100)->nullable(); $table->string('secret', 100)->nullable();
$table->string('provider')->nullable(); $table->string('provider')->nullable();
$table->text('redirect'); $table->text('redirect');
$table->boolean('personal_access_client'); $table->smallInteger('personal_access_client');
$table->boolean('password_client'); $table->smallInteger('password_client');
$table->boolean('revoked'); $table->smallInteger('revoked');
$table->timestamps(); $table->timestamps();
}); });
} }
@@ -18,7 +18,7 @@ class CreateAdvertisementsTable extends Migration
} }
Schema::create('advertisements', function (Blueprint $table) { Schema::create('advertisements', function (Blueprint $table) {
$table->mediumIncrements('id'); $table->mediumIncrements('id');
$table->boolean('enabled')->default(0); $table->smallInteger('enabled')->default(0);
$table->enum('type', ['bbcodes', 'xhtml', 'text', 'image', 'flash']); $table->enum('type', ['bbcodes', 'xhtml', 'text', 'image', 'flash']);
$table->enum('position', ['header', 'footer', 'belownav', 'belowsearchbox', 'torrentdetail', 'comment', 'interoverforums', 'forumpost', 'popup']); $table->enum('position', ['header', 'footer', 'belownav', 'belowsearchbox', 'torrentdetail', 'comment', 'interoverforums', 'forumpost', 'popup']);
$table->tinyInteger('displayorder')->default(0); $table->tinyInteger('displayorder')->default(0);
@@ -17,7 +17,7 @@ class CreateAgentAllowedExceptionTable extends Migration
return; return;
} }
Schema::create('agent_allowed_exception', function (Blueprint $table) { 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('name', 100)->default('');
$table->string('peer_id', 20)->default(''); $table->string('peer_id', 20)->default('');
$table->string('agent', 100)->default(''); $table->string('agent', 100)->default('');
@@ -22,15 +22,15 @@ class CreateAttachmentsTable extends Migration
$table->unsignedSmallInteger('width')->default(0); $table->unsignedSmallInteger('width')->default(0);
$table->dateTime('added')->nullable(); $table->dateTime('added')->nullable();
$table->string('filename')->default(''); $table->string('filename')->default('');
$table->char('dlkey', 32)->index('idx_delkey'); $table->char('dlkey', 32)->index();
$table->string('filetype', 50)->default(''); $table->string('filetype', 50)->default('');
$table->unsignedBigInteger('filesize')->default(0); $table->unsignedBigInteger('filesize')->default(0);
$table->string('location')->default(''); $table->string('location')->default('');
$table->mediumInteger('downloads')->default(0); $table->mediumInteger('downloads')->default(0);
$table->boolean('isimage')->unsigned()->default(0); $table->smallInteger('isimage')->unsigned()->default(0);
$table->boolean('thumb')->unsigned()->default(0); $table->smallInteger('thumb')->unsigned()->default(0);
$table->index(['userid', 'id'], 'pid'); $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) { Schema::create('attendance', function (Blueprint $table) {
$table->bigIncrements('id'); $table->bigIncrements('id');
$table->unsignedInteger('uid')->default(0)->index('idx_uid'); $table->unsignedInteger('uid')->default(0)->index();
$table->dateTime('added')->index(); $table->dateTime('added')->index();
$table->unsignedInteger('points')->default(0); $table->unsignedInteger('points')->default(0);
$table->unsignedInteger('days')->default(1); $table->unsignedInteger('days')->default(1);
@@ -23,7 +23,7 @@ class CreateBansTable extends Migration
$table->string('comment')->default(''); $table->string('comment')->default('');
$table->bigInteger('first')->default(0); $table->bigInteger('first')->default(0);
$table->bigInteger('last')->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->increments('id');
$table->unsignedMediumInteger('userid')->default(0); $table->unsignedMediumInteger('userid')->default(0);
$table->unsignedMediumInteger('blockid')->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->increments('id');
$table->unsignedMediumInteger('torrentid')->default(0); $table->unsignedMediumInteger('torrentid')->default(0);
$table->unsignedMediumInteger('userid')->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->string('image')->default('');
$table->unsignedSmallInteger('sort_index')->default(0); $table->unsignedSmallInteger('sort_index')->default(0);
$table->integer('icon_id')->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->unsignedMediumInteger('leechers')->default(0);
$table->unsignedTinyInteger('hit')->default(0); $table->unsignedTinyInteger('hit')->default(0);
$table->unsignedMediumInteger('dealtby')->default(0); $table->unsignedMediumInteger('dealtby')->default(0);
$table->boolean('dealtwith')->default(0); $table->smallInteger('dealtwith')->default(0);
$table->string('comment')->default(''); $table->string('comment')->default('');
}); });
} }
@@ -19,7 +19,7 @@ class CreateChronicleTable extends Migration
Schema::create('chronicle', function (Blueprint $table) { Schema::create('chronicle', function (Blueprint $table) {
$table->mediumIncrements('id'); $table->mediumIncrements('id');
$table->unsignedMediumInteger('userid')->default(0); $table->unsignedMediumInteger('userid')->default(0);
$table->dateTime('added')->nullable()->index('added'); $table->dateTime('added')->nullable()->index();
$table->text('txt')->nullable(); $table->text('txt')->nullable();
}); });
} }
@@ -18,7 +18,7 @@ class CreateCommentsTable extends Migration
} }
Schema::create('comments', function (Blueprint $table) { Schema::create('comments', function (Blueprint $table) {
$table->increments('id'); $table->increments('id');
$table->unsignedMediumInteger('user')->default(0)->index('user'); $table->unsignedMediumInteger('user')->default(0)->index();
$table->unsignedMediumInteger('torrent')->default(0); $table->unsignedMediumInteger('torrent')->default(0);
$table->dateTime('added')->nullable(); $table->dateTime('added')->nullable();
$table->text('text')->nullable(); $table->text('text')->nullable();
@@ -28,8 +28,8 @@ class CreateCommentsTable extends Migration
$table->unsignedMediumInteger('offer')->default(0); $table->unsignedMediumInteger('offer')->default(0);
$table->integer('request')->default(0); $table->integer('request')->default(0);
$table->enum('anonymous', ['yes', 'no'])->default('no'); $table->enum('anonymous', ['yes', 'no'])->default('no');
$table->index(['torrent', 'id'], 'torrent_id'); $table->index(['torrent', 'id'], );
$table->index(['offer', 'id'], 'offer_id'); $table->index(['offer', 'id'], );
}); });
} }
@@ -18,7 +18,7 @@ class CreateFilesTable extends Migration
} }
Schema::create('files', function (Blueprint $table) { Schema::create('files', function (Blueprint $table) {
$table->increments('id'); $table->increments('id');
$table->unsignedMediumInteger('torrent')->default(0)->index('torrent'); $table->unsignedMediumInteger('torrent')->default(0)->index();
$table->string('filename')->default(''); $table->string('filename')->default('');
$table->unsignedBigInteger('size')->default(0); $table->unsignedBigInteger('size')->default(0);
}); });
@@ -18,7 +18,7 @@ class CreateForummodsTable extends Migration
} }
Schema::create('forummods', function (Blueprint $table) { Schema::create('forummods', function (Blueprint $table) {
$table->smallIncrements('id'); $table->smallIncrements('id');
$table->unsignedSmallInteger('forumid')->default(0)->index('forumid'); $table->unsignedSmallInteger('forumid')->default(0)->index();
$table->unsignedMediumInteger('userid')->default(0); $table->unsignedMediumInteger('userid')->default(0);
}); });
} }
@@ -20,7 +20,7 @@ class CreateFriendsTable extends Migration
$table->increments('id'); $table->increments('id');
$table->unsignedMediumInteger('userid')->default(0); $table->unsignedMediumInteger('userid')->default(0);
$table->unsignedMediumInteger('friendid')->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->increments('id');
$table->unsignedMediumInteger('inviter')->default(0); $table->unsignedMediumInteger('inviter')->default(0);
$table->string('invitee', 80)->default(''); $table->string('invitee', 80)->default('');
$table->char('hash', 32)->index('hash'); $table->char('hash', 32)->index();
$table->dateTime('time_invited')->nullable(); $table->dateTime('time_invited')->nullable();
$table->tinyInteger('valid')->default(1); $table->tinyInteger('valid')->default(1);
$table->integer('invitee_register_uid')->nullable(); $table->integer('invitee_register_uid')->nullable();
@@ -19,7 +19,7 @@ class CreateIplogTable extends Migration
Schema::create('iplog', function (Blueprint $table) { Schema::create('iplog', function (Blueprint $table) {
$table->bigIncrements('id'); $table->bigIncrements('id');
$table->string('ip', 64)->default(''); $table->string('ip', 64)->default('');
$table->unsignedMediumInteger('userid')->default(0)->index('userid'); $table->unsignedMediumInteger('userid')->default(0)->index();
$table->dateTime('access')->nullable(); $table->dateTime('access')->nullable();
}); });
} }
@@ -18,8 +18,8 @@ class CreateMagicTable extends Migration
} }
Schema::create('magic', function (Blueprint $table) { Schema::create('magic', function (Blueprint $table) {
$table->bigIncrements('id'); $table->bigIncrements('id');
$table->integer('torrentid')->default(0)->index('idx_torrentid'); $table->integer('torrentid')->default(0)->index();
$table->integer('userid')->default(0)->index('idx_userid'); $table->integer('userid')->default(0)->index();
$table->integer('value')->default(0); $table->integer('value')->default(0);
$table->timestamp('created_at')->useCurrent(); $table->timestamp('created_at')->useCurrent();
$table->timestamp('updated_at')->useCurrent(); $table->timestamp('updated_at')->useCurrent();
@@ -18,8 +18,8 @@ class CreateMessagesTable extends Migration
} }
Schema::create('messages', function (Blueprint $table) { Schema::create('messages', function (Blueprint $table) {
$table->increments('id'); $table->increments('id');
$table->unsignedMediumInteger('sender')->default(0)->index('sender'); $table->unsignedMediumInteger('sender')->default(0)->index();
$table->unsignedMediumInteger('receiver')->default(0)->index('receiver'); $table->unsignedMediumInteger('receiver')->default(0)->index();
$table->dateTime('added')->nullable(); $table->dateTime('added')->nullable();
$table->string('subject', 128)->default(''); $table->string('subject', 128)->default('');
$table->text('msg')->nullable(); $table->text('msg')->nullable();
@@ -19,7 +19,7 @@ class CreateNewsTable extends Migration
Schema::create('news', function (Blueprint $table) { Schema::create('news', function (Blueprint $table) {
$table->mediumIncrements('id'); $table->mediumIncrements('id');
$table->unsignedMediumInteger('userid')->default(0); $table->unsignedMediumInteger('userid')->default(0);
$table->dateTime('added')->nullable()->index('added'); $table->dateTime('added')->nullable()->index();
$table->text('body')->nullable(); $table->text('body')->nullable();
$table->string('title')->default(''); $table->string('title')->default('');
$table->enum('notify', ['yes', 'no'])->default('no'); $table->enum('notify', ['yes', 'no'])->default('no');
@@ -18,7 +18,7 @@ class CreateOffersTable extends Migration
} }
Schema::create('offers', function (Blueprint $table) { Schema::create('offers', function (Blueprint $table) {
$table->mediumIncrements('id'); $table->mediumIncrements('id');
$table->unsignedMediumInteger('userid')->default(0)->index('userid'); $table->unsignedMediumInteger('userid')->default(0)->index();
$table->string('name', 225)->default(''); $table->string('name', 225)->default('');
$table->text('descr')->nullable(); $table->text('descr')->nullable();
$table->dateTime('added')->nullable(); $table->dateTime('added')->nullable();
@@ -19,7 +19,7 @@ class CreateOffervotesTable extends Migration
Schema::create('offervotes', function (Blueprint $table) { Schema::create('offervotes', function (Blueprint $table) {
$table->increments('id'); $table->increments('id');
$table->unsignedMediumInteger('offerid')->default(0); $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'); $table->enum('vote', ['yeah', 'against'])->default('yeah');
}); });
} }
@@ -19,7 +19,7 @@ class CreatePeersTable extends Migration
Schema::create('peers', function (Blueprint $table) { Schema::create('peers', function (Blueprint $table) {
$table->bigIncrements('id'); $table->bigIncrements('id');
$table->unsignedMediumInteger('torrent')->default(0); $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->string('ip', 64)->default('');
$table->unsignedSmallInteger('port')->default(0); $table->unsignedSmallInteger('port')->default(0);
$table->unsignedBigInteger('uploaded')->default(0); $table->unsignedBigInteger('uploaded')->default(0);
@@ -36,7 +36,7 @@ class CreatePeersTable extends Migration
$table->unsignedBigInteger('downloadoffset')->default(0); $table->unsignedBigInteger('downloadoffset')->default(0);
$table->unsignedBigInteger('uploadoffset')->default(0); $table->unsignedBigInteger('uploadoffset')->default(0);
$table->char('passkey', 32)->default(''); $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) { Schema::create('pollanswers', function (Blueprint $table) {
$table->increments('id'); $table->increments('id');
$table->unsignedMediumInteger('pollid')->default(0)->index('pollid'); $table->unsignedMediumInteger('pollid')->default(0)->index();
$table->unsignedMediumInteger('userid')->default(0)->index('userid'); $table->unsignedMediumInteger('userid')->default(0)->index();
$table->unsignedTinyInteger('selection')->default(0)->index('selection'); $table->unsignedTinyInteger('selection')->default(0)->index();
}); });
} }
@@ -19,15 +19,14 @@ class CreatePostsTable extends Migration
Schema::create('posts', function (Blueprint $table) { Schema::create('posts', function (Blueprint $table) {
$table->increments('id'); $table->increments('id');
$table->unsignedMediumInteger('topicid')->default(0); $table->unsignedMediumInteger('topicid')->default(0);
$table->unsignedMediumInteger('userid')->default(0)->index('userid'); $table->unsignedMediumInteger('userid')->default(0)->index();
$table->dateTime('added')->nullable()->index('added'); $table->dateTime('added')->nullable()->index();
$table->text('body')->nullable(); $table->text('body')->nullable();
$table->text('ori_body')->nullable(); $table->text('ori_body')->nullable();
$table->unsignedMediumInteger('editedby')->default(0); $table->unsignedMediumInteger('editedby')->default(0);
$table->dateTime('editdate')->nullable(); $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) { Schema::create('readposts', function (Blueprint $table) {
$table->increments('id'); $table->increments('id');
$table->unsignedMediumInteger('userid')->default(0)->index('userid'); $table->unsignedMediumInteger('userid')->default(0)->index();
$table->unsignedMediumInteger('topicid')->default(0)->index('topicid'); $table->unsignedMediumInteger('topicid')->default(0)->index();
$table->unsignedInteger('lastpostread')->default(0); $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->enum('type', ['torrent', 'user', 'offer', 'request', 'post', 'comment', 'subtitle'])->default('torrent');
$table->string('reason')->default(''); $table->string('reason')->default('');
$table->unsignedMediumInteger('dealtby')->default(0); $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) { Schema::create('requests', function (Blueprint $table) {
$table->increments('id'); $table->increments('id');
$table->unsignedInteger('userid')->default(0)->index('userid'); $table->unsignedInteger('userid')->default(0)->index();
$table->string('request', 225)->default(''); $table->string('request', 225)->default('');
$table->text('descr'); $table->text('descr');
$table->unsignedInteger('comments')->default(0); $table->unsignedInteger('comments')->default(0);
@@ -31,7 +31,7 @@ class CreateRequestsTable extends Migration
$table->string('ori_descr')->default(''); $table->string('ori_descr')->default('');
$table->integer('ori_amount')->default(0); $table->integer('ori_amount')->default(0);
$table->dateTime('added')->nullable(); $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) { Schema::create('resreq', function (Blueprint $table) {
$table->integer('id', true); $table->integer('id', true);
$table->integer('reqid')->default(0)->index('reqid'); $table->integer('reqid')->default(0)->index();
$table->integer('torrentid')->default(0); $table->integer('torrentid')->default(0);
$table->enum('chosen', ['yes', 'no'])->default('no'); $table->enum('chosen', ['yes', 'no'])->default('no');
}); });
@@ -23,7 +23,7 @@ class CreateSearchboxFieldsTable extends Migration
$table->integer('field_id')->default(0); $table->integer('field_id')->default(0);
$table->timestamp('created_at')->useCurrent(); $table->timestamp('created_at')->useCurrent();
$table->timestamp('update_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) { Schema::create('searchbox', function (Blueprint $table) {
$table->smallIncrements('id'); $table->smallIncrements('id');
$table->string('name', 30)->nullable(); $table->string('name', 30)->nullable();
$table->boolean('showsubcat')->default(0); $table->smallInteger('showsubcat')->default(0);
$table->boolean('showsource')->default(0); $table->smallInteger('showsource')->default(0);
$table->boolean('showmedium')->default(0); $table->smallInteger('showmedium')->default(0);
$table->boolean('showcodec')->default(0); $table->smallInteger('showcodec')->default(0);
$table->boolean('showstandard')->default(0); $table->smallInteger('showstandard')->default(0);
$table->boolean('showprocessing')->default(0); $table->smallInteger('showprocessing')->default(0);
$table->boolean('showteam')->default(0); $table->smallInteger('showteam')->default(0);
$table->boolean('showaudiocodec')->default(0); $table->smallInteger('showaudiocodec')->default(0);
$table->unsignedSmallInteger('catsperrow')->default(7); $table->unsignedSmallInteger('catsperrow')->default(7);
$table->unsignedSmallInteger('catpadding')->default(25); $table->unsignedSmallInteger('catpadding')->default(25);
$table->text('custom_fields')->nullable(); $table->text('custom_fields')->nullable();
@@ -18,7 +18,7 @@ class CreateSettingsTable extends Migration
} }
Schema::create('settings', function (Blueprint $table) { Schema::create('settings', function (Blueprint $table) {
$table->integer('id', true); $table->integer('id', true);
$table->string('name')->default('')->unique('uniqe_name'); $table->string('name')->default('')->unique();
$table->mediumText('value')->nullable(); $table->mediumText('value')->nullable();
$table->timestamp('created_at')->useCurrent(); $table->timestamp('created_at')->useCurrent();
$table->timestamp('updated_at')->useCurrent(); $table->timestamp('updated_at')->useCurrent();
@@ -18,7 +18,7 @@ class CreateSitelogTable extends Migration
} }
Schema::create('sitelog', function (Blueprint $table) { Schema::create('sitelog', function (Blueprint $table) {
$table->increments('id'); $table->increments('id');
$table->dateTime('added')->nullable()->index('added'); $table->dateTime('added')->nullable()->index();
$table->text('txt'); $table->text('txt');
$table->enum('security_level', ['normal', 'mod'])->default('normal'); $table->enum('security_level', ['normal', 'mod'])->default('normal');
}); });
@@ -19,7 +19,7 @@ class CreateSnatchedTable extends Migration
Schema::create('snatched', function (Blueprint $table) { Schema::create('snatched', function (Blueprint $table) {
$table->bigIncrements('id', true); $table->bigIncrements('id', true);
$table->unsignedMediumInteger('torrentid')->default(0); $table->unsignedMediumInteger('torrentid')->default(0);
$table->unsignedMediumInteger('userid')->default(0)->index('userid'); $table->unsignedMediumInteger('userid')->default(0)->index();
$table->string('ip', 64)->default(''); $table->string('ip', 64)->default('');
$table->unsignedSmallInteger('port')->default(0); $table->unsignedSmallInteger('port')->default(0);
$table->unsignedBigInteger('uploaded')->default(0); $table->unsignedBigInteger('uploaded')->default(0);
@@ -31,7 +31,7 @@ class CreateSnatchedTable extends Migration
$table->dateTime('startdat')->nullable(); $table->dateTime('startdat')->nullable();
$table->dateTime('completedat')->nullable(); $table->dateTime('completedat')->nullable();
$table->enum('finished', ['yes', 'no'])->default('no'); $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->text('msg')->nullable();
$table->string('subject', 128)->default(''); $table->string('subject', 128)->default('');
$table->unsignedMediumInteger('answeredby')->default(0); $table->unsignedMediumInteger('answeredby')->default(0);
$table->boolean('answered')->default(0); $table->smallInteger('answered')->default(0);
$table->text('answer')->nullable(); $table->text('answer')->nullable();
}); });
} }
@@ -28,7 +28,7 @@ class CreateSubsTable extends Migration
$table->enum('anonymous', ['yes', 'no'])->default('no'); $table->enum('anonymous', ['yes', 'no'])->default('no');
$table->unsignedMediumInteger('hits')->default(0); $table->unsignedMediumInteger('hits')->default(0);
$table->string('ext', 10)->default(''); $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) { Schema::create('suggest', function (Blueprint $table) {
$table->increments('id'); $table->increments('id');
$table->string('keywords')->default('')->index('keywords'); $table->string('keywords')->default('')->index();
$table->unsignedMediumInteger('userid')->default(0); $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) { Schema::create('topics', function (Blueprint $table) {
$table->mediumIncrements('id'); $table->mediumIncrements('id');
$table->unsignedMediumInteger('userid')->default(0)->index('userid'); $table->unsignedMediumInteger('userid')->default(0)->index();
$table->string('subject', 128)->default('')->index('subject'); $table->string('subject', 128)->default('')->index();
$table->enum('locked', ['yes', 'no'])->default('no'); $table->enum('locked', ['yes', 'no'])->default('no');
$table->unsignedSmallInteger('forumid')->default(0); $table->unsignedSmallInteger('forumid')->default(0);
$table->unsignedInteger('firstpost')->default(0); $table->unsignedInteger('firstpost')->default(0);
@@ -27,8 +27,8 @@ class CreateTopicsTable extends Migration
$table->enum('sticky', ['no', 'yes'])->default('no'); $table->enum('sticky', ['no', 'yes'])->default('no');
$table->unsignedTinyInteger('hlcolor')->default(0); $table->unsignedTinyInteger('hlcolor')->default(0);
$table->unsignedInteger('views')->default(0); $table->unsignedInteger('views')->default(0);
$table->index(['forumid', 'lastpost'], 'forumid_lastpost'); $table->index(['forumid', 'lastpost'], );
$table->index(['forumid', 'sticky', 'lastpost'], 'forumid_sticky_lastpost'); $table->index(['forumid', 'sticky', 'lastpost'], );
}); });
} }
@@ -18,8 +18,8 @@ class CreateTorrentSecretsTable extends Migration
} }
Schema::create('torrent_secrets', function (Blueprint $table) { Schema::create('torrent_secrets', function (Blueprint $table) {
$table->integer('id', true); $table->integer('id', true);
$table->integer('uid')->index('idx_uid'); $table->integer('uid')->index();
$table->integer('torrent_id')->default(0)->index('idx_torrent_id'); $table->integer('torrent_id')->default(0)->index();
$table->string('secret'); $table->string('secret');
$table->timestamp('created_at')->useCurrent(); $table->timestamp('created_at')->useCurrent();
$table->timestamp('updated_at')->useCurrent(); $table->timestamp('updated_at')->useCurrent();
@@ -18,13 +18,16 @@ class CreateTorrentsCustomFieldValuesTable extends Migration
} }
Schema::create('torrents_custom_field_values', function (Blueprint $table) { Schema::create('torrents_custom_field_values', function (Blueprint $table) {
$table->integer('id', true); $table->integer('id', true);
$table->integer('torrent_id')->default(0)->index('idx_torrent_id'); $table->integer('torrent_id')->default(0)->index();
$table->integer('custom_field_id')->default(0)->index('idx_field_id'); $table->integer('custom_field_id')->default(0)->index();
$table->mediumText('custom_field_value')->nullable(); $table->mediumText('custom_field_value')->nullable();
$table->dateTime('created_at'); $table->dateTime('created_at');
$table->dateTime('updated_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) { Schema::create('torrents', function (Blueprint $table) {
$table->mediumIncrements('id'); $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('filename')->default('');
$table->string('save_as')->default(''); $table->string('save_as')->default('');
$table->text('descr')->nullable(); $table->text('descr')->nullable();
@@ -45,27 +46,26 @@ class CreateTorrentsTable extends Migration
$table->dateTime('last_action')->nullable(); $table->dateTime('last_action')->nullable();
$table->enum('visible', ['yes', 'no'])->default('yes'); $table->enum('visible', ['yes', 'no'])->default('yes');
$table->enum('banned', ['yes', 'no'])->default('no'); $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->binary('nfo')->nullable();
$table->unsignedTinyInteger('sp_state')->default(1); $table->unsignedTinyInteger('sp_state')->default(1);
$table->unsignedTinyInteger('promotion_time_type')->default(0); $table->unsignedTinyInteger('promotion_time_type')->default(0);
$table->dateTime('promotion_until')->nullable(); $table->dateTime('promotion_until')->nullable();
$table->enum('anonymous', ['yes', 'no'])->default('no'); $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->string('pos_state', 32)->default('normal');
$table->unsignedTinyInteger('cache_stamp')->default(0); $table->unsignedTinyInteger('cache_stamp')->default(0);
$table->enum('picktype', ['hot', 'classic', 'recommended', 'normal'])->default('normal'); $table->enum('picktype', ['hot', 'classic', 'recommended', 'normal'])->default('normal');
$table->dateTime('picktime')->nullable(); $table->dateTime('picktime')->nullable();
$table->dateTime('last_reseed')->nullable(); $table->dateTime('last_reseed')->nullable();
$table->mediumText('pt_gen')->nullable(); $table->mediumText('pt_gen')->nullable();
// $table->integer('tags')->default(0);
$table->text('technical_info')->nullable(); $table->text('technical_info')->nullable();
$table->index(['visible', 'pos_state', 'id'], 'visible_pos_id'); $table->index(['visible', 'pos_state', 'id'] );
$table->index(['category', 'visible', 'banned'], 'category_visible_banned'); $table->index(['category', 'visible', 'banned']);
$table->index(['visible', 'banned', 'pos_state', 'id'], 'visible_banned_pos_id'); $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`)'; // $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); // \Illuminate\Support\Facades\DB::statement($sql);
} }
/** /**
@@ -18,8 +18,8 @@ class CreateUserBanLogsTable extends Migration
} }
Schema::create('user_ban_logs', function (Blueprint $table) { Schema::create('user_ban_logs', function (Blueprint $table) {
$table->bigInteger('id', true); $table->bigInteger('id', true);
$table->integer('uid')->default(0)->index('idx_uid'); $table->integer('uid')->default(0)->index();
$table->string('username')->default('')->index('idx_username'); $table->string('username')->default('')->index();
$table->integer('operator')->default(0); $table->integer('operator')->default(0);
$table->string('reason')->nullable(); $table->string('reason')->nullable();
$table->timestamp('created_at')->nullable()->useCurrent(); $table->timestamp('created_at')->nullable()->useCurrent();
@@ -22,14 +22,14 @@ class CreateUsersTable extends Migration
} }
Schema::create('users', function (Blueprint $table) use ($uidStarts) { Schema::create('users', function (Blueprint $table) use ($uidStarts) {
$table->id('id')->startingValue($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->string('passhash', 32)->default('');
$table->binary('secret'); $table->binary('secret');
$table->string('email', 80)->default(''); $table->string('email', 80)->default('');
$table->enum('status', ['pending', 'confirmed'])->default('pending'); $table->enum('status', ['pending', 'confirmed'])->default('pending');
$table->dateTime('added')->nullable(); $table->dateTime('added')->nullable();
$table->dateTime('last_login')->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_home')->nullable();
$table->dateTime('last_offer')->nullable(); $table->dateTime('last_offer')->nullable();
$table->dateTime('forum_access')->nullable(); $table->dateTime('forum_access')->nullable();
@@ -48,25 +48,25 @@ class CreateUsersTable extends Migration
$table->text('info')->nullable(); $table->text('info')->nullable();
$table->enum('acceptpms', ['yes', 'friends', 'no'])->default('yes'); $table->enum('acceptpms', ['yes', 'friends', 'no'])->default('yes');
$table->enum('commentpm', ['yes', 'no'])->default('yes'); $table->enum('commentpm', ['yes', 'no'])->default('yes');
$table->string('ip', 64)->default('')->index('ip'); $table->string('ip', 64)->default('')->index();
$table->unsignedTinyInteger('class')->default(1)->index('class'); $table->unsignedTinyInteger('class')->default(1)->index();
$table->tinyInteger('max_class_once')->default(1); $table->tinyInteger('max_class_once')->default(1);
$table->string('avatar')->default(''); $table->string('avatar')->default('');
$table->unsignedBigInteger('uploaded')->default(0)->index('uploaded'); $table->unsignedBigInteger('uploaded')->default(0)->index();
$table->unsignedBigInteger('downloaded')->default(0)->index('downloaded'); $table->unsignedBigInteger('downloaded')->default(0)->index();
$table->unsignedBigInteger('seedtime')->default(0); $table->unsignedBigInteger('seedtime')->default(0);
$table->unsignedBigInteger('leechtime')->default(0); $table->unsignedBigInteger('leechtime')->default(0);
$table->string('title', 30)->default(''); $table->string('title', 30)->default('');
$table->unsignedSmallInteger('country')->default(107)->index('country'); $table->unsignedSmallInteger('country')->default(107)->index();
$table->string('notifs', 500)->nullable(); $table->string('notifs', 500)->nullable();
$table->text('modcomment')->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('avatars', ['yes', 'no'])->default('yes');
$table->enum('donor', ['yes', 'no'])->default('no'); $table->enum('donor', ['yes', 'no'])->default('no');
$table->decimal('donated')->default(0.00); $table->decimal('donated')->default(0.00);
$table->decimal('donated_cny')->default(0.00); $table->decimal('donated_cny')->default(0.00);
$table->dateTime('donoruntil')->nullable(); $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->dateTime('warneduntil')->nullable();
$table->enum('noad', ['yes', 'no'])->default('no'); $table->enum('noad', ['yes', 'no'])->default('no');
$table->dateTime('noaduntil')->nullable(); $table->dateTime('noaduntil')->nullable();
@@ -84,7 +84,7 @@ class CreateUsersTable extends Migration
$table->string('supportfor')->default(''); $table->string('supportfor')->default('');
$table->string('pickfor')->default(''); $table->string('pickfor')->default('');
$table->string('supportlang', 50)->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->string('promotion_link', 32)->nullable();
$table->enum('uploadpos', ['yes', 'no'])->default('yes'); $table->enum('uploadpos', ['yes', 'no'])->default('yes');
$table->enum('forumpost', ['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->enum('signatures', ['yes', 'no'])->default('yes');
$table->string('signature', 800)->default(''); $table->string('signature', 800)->default('');
$table->unsignedSmallInteger('lang')->default(6); $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('download')->default(0);
$table->unsignedInteger('upload')->default(0); $table->unsignedInteger('upload')->default(0);
$table->unsignedTinyInteger('isp')->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('showdescription', ['yes', 'no'])->nullable()->default('yes');
$table->enum('showcomment', ['yes', 'no'])->nullable()->default('yes'); $table->enum('showcomment', ['yes', 'no'])->nullable()->default('yes');
$table->enum('showclienterror', ['yes', 'no'])->default('no'); $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('tooltip', ['minorimdb', 'medianimdb', 'off'])->default('off');
$table->enum('shownfo', ['yes', 'no'])->nullable()->default('yes'); $table->enum('shownfo', ['yes', 'no'])->nullable()->default('yes');
$table->enum('timetype', ['timeadded', 'timealive'])->nullable()->default('timealive'); $table->enum('timetype', ['timeadded', 'timealive'])->nullable()->default('timealive');
@@ -136,7 +136,7 @@ class CreateUsersTable extends Migration
$table->unsignedSmallInteger('school')->default(35); $table->unsignedSmallInteger('school')->default(35);
$table->enum('showfb', ['yes', 'no'])->default('yes'); $table->enum('showfb', ['yes', 'no'])->default('yes');
$table->string('page')->nullable()->default(''); $table->string('page')->nullable()->default('');
$table->index(['status', 'added'], 'status_added'); $table->index(['status', 'added']);
}); });
} }
@@ -13,6 +13,10 @@ return new class extends Migration
*/ */
public function up() public function up()
{ {
if (\Nexus\Database\NexusDB::isPgsql()) {
//fresh install no need
return;
}
$tableFields = \App\Repositories\UpgradeRepository::DATETIME_INVALID_VALUE_FIELDS; $tableFields = \App\Repositories\UpgradeRepository::DATETIME_INVALID_VALUE_FIELDS;
foreach ($tableFields as $table => $fields) { foreach ($tableFields as $table => $fields) {
@@ -14,24 +14,27 @@ return new class extends Migration
*/ */
public function up() public function up()
{ {
if (\Nexus\Database\NexusDB::isPgsql()) {
return;
}
$tableName = 'peers'; $tableName = 'peers';
$result = DB::select('show index from ' . $tableName); $columnNames = ['torrent', 'peer_id'];
$indexToDrop = []; // 1. 获取该表所有的索引信息
foreach ($result as $item) { $indexesToDelete = \Nexus\Database\NexusDB::listColumnIndexNames($tableName, $columnNames);
if (in_array($item->Column_name, ['torrent', 'peer_id'])) {
$indexToDrop[$item->Key_name] = "drop index " . $item->Key_name; // 3. 执行删除操作
Schema::table($tableName, function (Blueprint $table) use ($indexesToDelete) {
foreach ($indexesToDelete as $indexName) {
// 如果是主键,需要单独处理
if ($indexName === 'primary') {
$table->dropPrimary();
} else {
$table->dropIndex($indexName);
}
} }
} $table->index(['torrent', 'peer_id']);
if (!empty($indexToDrop)) { $table->index('peer_id');
$sql = sprintf("alter table %s %s", $tableName, implode(', ', $indexToDrop)); });
DB::statement($sql);
}
$sql = "alter table $tableName add index idx_torrent_peer(`torrent`, `peer_id`(20))";
DB::statement($sql);
$sql = "alter table $tableName add index idx_peer(`peer_id`(20))";
DB::statement($sql);
} }
@@ -14,7 +14,7 @@ return new class extends Migration
public function up() public function up()
{ {
Schema::table('searchbox', function (Blueprint $table) { Schema::table('searchbox', function (Blueprint $table) {
$table->text('extra')->nullable(); $table->json('extra')->nullable();
}); });
} }
@@ -14,7 +14,9 @@ return new class extends Migration
public function up() public function up()
{ {
Schema::table('searchbox', function (Blueprint $table) { Schema::table('searchbox', function (Blueprint $table) {
$table->json('extra')->nullable()->change(); if (\Nexus\Database\NexusDB::isMysql()) {
$table->json('extra')->nullable()->change();
}
$table->string('custom_fields_display_name')->nullable(true)->default('')->change(); $table->string('custom_fields_display_name')->nullable(true)->default('')->change();
}); });
@@ -16,7 +16,7 @@ return new class extends Migration
Schema::table('invites', function (Blueprint $table) { Schema::table('invites', function (Blueprint $table) {
$table->dateTime('expired_at')->nullable(true)->index(); $table->dateTime('expired_at')->nullable(true)->index();
$table->dateTime('created_at')->useCurrent(); $table->dateTime('created_at')->useCurrent();
$table->index(['inviter'], 'idx_inviter'); $table->index(['inviter'], );
}); });
} }
@@ -4,6 +4,7 @@ use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint; use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema; use Illuminate\Support\Facades\Schema;
use Illuminate\Support\Facades\DB; use Illuminate\Support\Facades\DB;
use Nexus\Database\NexusDB;
return new class extends Migration return new class extends Migration
{ {
@@ -14,27 +15,28 @@ return new class extends Migration
*/ */
public function up() public function up()
{ {
if (NexusDB::isPgsql()) {
return;
}
$tableName = 'snatched'; $tableName = 'snatched';
$result = DB::select('show index from ' . $tableName); $columnNames = ['torrentid', 'userid'];
$indexToDrop = []; // 1. 获取该表所有的索引信息
foreach ($result as $item) { $indexesToDelete = NexusDB::listColumnIndexNames($tableName, $columnNames);
if (in_array($item->Column_name, ['torrentid', 'userid'])) {
if ($item->Non_unique == 0) { // 3. 执行删除操作
return; Schema::table($tableName, function (Blueprint $table) use ($indexesToDelete) {
foreach ($indexesToDelete as $indexName) {
// 如果是主键,需要单独处理
if ($indexName === 'primary') {
$table->dropPrimary();
} else {
$table->dropIndex($indexName);
} }
$indexToDrop[$item->Key_name] = "drop index " . $item->Key_name;
} }
} $table->unique(['torrentid', 'userid']);
if (!empty($indexToDrop)) { $table->index('userid');
$sql = sprintf("alter table %s %s", $tableName, implode(', ', $indexToDrop)); });
DB::statement($sql);
}
$sql = "alter table $tableName add unique unique_torrent_user(`torrentid`, `userid`)";
DB::statement($sql);
$sql = "alter table $tableName add index idx_user(`userid`)";
DB::statement($sql);
} }
/** /**
@@ -3,7 +3,7 @@
use Illuminate\Database\Migrations\Migration; use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint; use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema; use Illuminate\Support\Facades\Schema;
use Illuminate\Support\Facades\DB; use Nexus\Database\NexusDB;
return new class extends Migration return new class extends Migration
{ {
@@ -14,16 +14,28 @@ return new class extends Migration
*/ */
public function up() public function up()
{ {
$tableName = 'peers'; if (NexusDB::isPgsql()) {
$result = DB::select('show index from ' . $tableName); return;
$toDropIndex = 'idx_torrent_peer';
foreach ($result as $item) {
if ($item->Key_name == $toDropIndex) {
DB::statement("alter table $tableName drop index $toDropIndex");
break;
}
} }
DB::statement("alter table $tableName add unique unique_torrent_peer_user(`torrent`, `peer_id`, `userid`)"); $tableName = 'peers';
$columnNames = ['torrent', 'peer_id', 'userid'];
// 1. 获取该表所有的索引信息
$indexesToDelete = NexusDB::listColumnIndexNames($tableName, $columnNames);
// 3. 执行删除操作
Schema::table($tableName, function (Blueprint $table) use ($indexesToDelete) {
foreach ($indexesToDelete as $indexName) {
// 如果是主键,需要单独处理
if ($indexName === 'primary') {
$table->dropPrimary();
} else {
$table->dropIndex($indexName);
}
}
$table->unique(['torrent', 'peer_id', 'userid']);
$table->index('peer_id');
$table->index('userid');
});
} }
@@ -14,7 +14,7 @@ return new class extends Migration
public function up() public function up()
{ {
Schema::table('users', function (Blueprint $table) { Schema::table('users', function (Blueprint $table) {
$table->decimal("seedbonus", 20, 1)->change(); $table->decimal("seedbonus", 20, 1)->default(0)->change();
}); });
Schema::table('bonus_logs', function (Blueprint $table) { Schema::table('bonus_logs', function (Blueprint $table) {
$table->decimal("old_total_value", 20, 1)->change(); $table->decimal("old_total_value", 20, 1)->change();
@@ -14,7 +14,7 @@ return new class extends Migration
public function up() public function up()
{ {
Schema::table('claims', function (Blueprint $table) { Schema::table('claims', function (Blueprint $table) {
$table->index("created_at", "idx_created_at"); $table->index("created_at", );
}); });
} }
@@ -13,10 +13,10 @@ return new class extends Migration
*/ */
public function up() public function up()
{ {
$columnInfo = \Nexus\Database\NexusDB::getMysqlColumnInfo("torrents", "cache_stamp"); // $columnInfo = \Nexus\Database\NexusDB::getMysqlColumnInfo("torrents", "cache_stamp");
if ($columnInfo["DATA_TYPE"] == "int") { // if ($columnInfo["DATA_TYPE"] == "int") {
return; // return;
} // }
Schema::table('torrents', function (Blueprint $table) { Schema::table('torrents', function (Blueprint $table) {
$table->integer("cache_stamp")->default(0)->change(); $table->integer("cache_stamp")->default(0)->change();
}); });
@@ -14,7 +14,7 @@ return new class extends Migration
public function up() public function up()
{ {
Schema::table('oauth_clients', function (Blueprint $table) { Schema::table('oauth_clients', function (Blueprint $table) {
$table->boolean("skips_authorization")->default(false); $table->smallInteger("skips_authorization")->default(false);
}); });
} }
@@ -13,8 +13,9 @@ return new class extends Migration
*/ */
public function up() public function up()
{ {
$sql = 'ALTER table torrents MODIFY column `info_hash` binary(20) DEFAULT NULL'; Schema::table('torrents', function (Blueprint $table) {
\Illuminate\Support\Facades\DB::statement($sql); $table->binary('info_hash', 20)->nullable()->change();
});
} }
/** /**
@@ -25,7 +25,7 @@ return new class extends Migration
$table->string('email_claim')->nullable(); $table->string('email_claim')->nullable();
$table->string('level_claim')->nullable(); $table->string('level_claim')->nullable();
$table->string('level_limit')->nullable(); $table->string('level_limit')->nullable();
$table->boolean('enabled'); $table->smallInteger('enabled');
$table->integer('priority'); $table->integer('priority');
$table->timestamps(); $table->timestamps();
}); });
@@ -11,6 +11,9 @@ return new class extends Migration
*/ */
public function up(): void public function up(): void
{ {
if (\Nexus\Database\NexusDB::isPgsql()) {
return;
}
$tableFields = \App\Repositories\UpgradeRepository::DATETIME_INVALID_VALUE_FIELDS; $tableFields = \App\Repositories\UpgradeRepository::DATETIME_INVALID_VALUE_FIELDS;
foreach ($tableFields as $table => $fields) { foreach ($tableFields as $table => $fields) {
@@ -0,0 +1,27 @@
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
return new class extends Migration
{
/**
* Run the migrations.
*/
public function up(): void
{
// 1. 字段名改为小写
Schema::table('user_passkeys', function (Blueprint $table) {
$table->renameColumn('AAGUID', 'aaguid');
});
}
/**
* Reverse the migrations.
*/
public function down(): void
{
//
}
};
+11 -6
View File
@@ -139,7 +139,8 @@ function promotion($class, $down_floor_gb, $minratio, $time_week, $addinvite = 0
function demotion($class,$deratio){ function demotion($class,$deratio){
$newclass = $class - 1; $newclass = $class - 1;
$sql = "SELECT id FROM users WHERE class = $class AND uploaded / downloaded < $deratio"; // $sql = "SELECT id FROM users WHERE class = $class AND uploaded / downloaded < $deratio";
$sql = "SELECT id FROM users WHERE class = $class AND uploaded < downloaded * $deratio";
$res = sql_query($sql) or sqlerr(__FILE__, __LINE__); $res = sql_query($sql) or sqlerr(__FILE__, __LINE__);
$matchUserCount = mysql_num_rows($res); $matchUserCount = mysql_num_rows($res);
do_log("sql: $sql, match user count: $matchUserCount"); do_log("sql: $sql, match user count: $matchUserCount");
@@ -585,7 +586,8 @@ function docleanup($forceAll = 0, $printProgress = false) {
//3.delete unconfirmed accounts //3.delete unconfirmed accounts
$deadtime = time() - $signup_timeout; $deadtime = time() - $signup_timeout;
sql_query("DELETE FROM users WHERE status = 'pending' AND added < FROM_UNIXTIME($deadtime) AND last_login < FROM_UNIXTIME($deadtime) AND last_access < FROM_UNIXTIME($deadtime)") or sqlerr(__FILE__, __LINE__); $deadlineField = \Nexus\Database\NexusDB::fromUnixTimestampField($deadtime);
sql_query("DELETE FROM users WHERE status = 'pending' AND added < $deadlineField AND last_login < $deadlineField AND last_access < $deadlineField") or sqlerr(__FILE__, __LINE__);
// $query = \App\Models\User::query() // $query = \App\Models\User::query()
// ->where('status', 'pending') // ->where('status', 'pending')
// ->whereRaw("added < FROM_UNIXTIME($deadtime)") // ->whereRaw("added < FROM_UNIXTIME($deadtime)")
@@ -619,7 +621,7 @@ function docleanup($forceAll = 0, $printProgress = false) {
} }
//7.delete regimage codes //7.delete regimage codes
sql_query("TRUNCATE TABLE `regimages`") or sqlerr(__FILE__, __LINE__); sql_query("TRUNCATE TABLE regimages") or sqlerr(__FILE__, __LINE__);
$log = "delete regimage codes"; $log = "delete regimage codes";
do_log($log); do_log($log);
if ($printProgress) { if ($printProgress) {
@@ -1069,7 +1071,7 @@ function docleanup($forceAll = 0, $printProgress = false) {
//delete old shoutbox //delete old shoutbox
$until = TIMENOW - $length; $until = TIMENOW - $length;
sql_query("DELETE FROM shoutbox WHERE `date` < ".sqlesc($until)) or sqlerr(__FILE__, __LINE__); sql_query("DELETE FROM shoutbox WHERE date < $until") or sqlerr(__FILE__, __LINE__);
$log = "delete old shoutbox"; $log = "delete old shoutbox";
do_log($log); do_log($log);
if ($printProgress) { if ($printProgress) {
@@ -1078,7 +1080,7 @@ function docleanup($forceAll = 0, $printProgress = false) {
//delete old general log //delete old general log
$until = date("Y-m-d H:i:s",(TIMENOW - $length)); $until = date("Y-m-d H:i:s",(TIMENOW - $length));
sql_query("DELETE FROM sitelog WHERE added < ".sqlesc($until)) or sqlerr(__FILE__, __LINE__); sql_query("DELETE FROM sitelog WHERE added < " . sqlesc($until)) or sqlerr(__FILE__, __LINE__);
$log = "delete old general log"; $log = "delete old general log";
do_log($log); do_log($log);
if ($printProgress) { if ($printProgress) {
@@ -1157,7 +1159,10 @@ function docleanup($forceAll = 0, $printProgress = false) {
//8.lock topics where last post was made more than x days ago //8.lock topics where last post was made more than x days ago
$secs = 365*24*60*60; $secs = 365*24*60*60;
sql_query("UPDATE topics, posts SET topics.locked='yes' WHERE topics.lastpost = posts.id AND topics.sticky = 'no' AND UNIX_TIMESTAMP(posts.added) < ".TIMENOW." - $secs") or sqlerr(__FILE__, __LINE__); $postAddedField = \Nexus\Database\NexusDB::unixTimestampField('posts.added');
$diff = TIMENOW - $secs;
// sql_query("UPDATE topics, posts SET topics.locked='yes' WHERE topics.lastpost = posts.id AND topics.sticky = 'no' AND $postAddedField < ".TIMENOW." - $secs") or sqlerr(__FILE__, __LINE__);
sql_query("UPDATE topics SET locked='yes' WHERE sticky = 'no' AND lastpost in (select id from posts where $postAddedField < $diff)");
$log = "lock topics where last post was made more than x days ago"; $log = "lock topics where last post was made more than x days ago";
do_log($log); do_log($log);
+2 -2
View File
@@ -1,6 +1,6 @@
<?php <?php
defined('VERSION_NUMBER') || define('VERSION_NUMBER', '1.10.1'); defined('VERSION_NUMBER') || define('VERSION_NUMBER', '1.10.2');
defined('RELEASE_DATE') || define('RELEASE_DATE', '2026-02-17'); defined('RELEASE_DATE') || define('RELEASE_DATE', '2026-04-11');
defined('IN_TRACKER') || define('IN_TRACKER', false); defined('IN_TRACKER') || define('IN_TRACKER', false);
defined('PROJECTNAME') || define("PROJECTNAME","NexusPHP"); defined('PROJECTNAME') || define("PROJECTNAME","NexusPHP");
defined('NEXUSPHPURL') || define("NEXUSPHPURL","https://nexusphp.org"); defined('NEXUSPHPURL') || define("NEXUSPHPURL","https://nexusphp.org");
+3 -3
View File
@@ -1,7 +1,7 @@
<?php <?php
$config = require ROOT_PATH . 'config/nexus.php'; $dbConfig = nexus_config('nexus.database');
$connectionMysql = $config['mysql']; $config = $dbConfig['connections'][$dbConfig['default']];
\Nexus\Database\NexusDB::bootEloquent($connectionMysql); \Nexus\Database\NexusDB::bootEloquent($config);
+15 -11
View File
@@ -1277,9 +1277,9 @@ function parse_imdb_id($url)
$url = str_pad($url, 7, '0', STR_PAD_LEFT); $url = str_pad($url, 7, '0', STR_PAD_LEFT);
} }
if ($url != "" && preg_match("/[0-9]+/i", $url, $matches)) { if ($url != "" && preg_match("/[0-9]+/i", $url, $matches)) {
return $matches[0]; return intval($matches[0]);
} }
return ''; return null;
} }
function build_imdb_url($imdb_id) function build_imdb_url($imdb_id)
@@ -2092,9 +2092,6 @@ function userlogin() {
// error_reporting(E_ALL & ~E_NOTICE); // error_reporting(E_ALL & ~E_NOTICE);
// error_reporting(-1); // error_reporting(-1);
// } // }
if ($row['enabled'] !== 'yes') {
}
return $loginResult = true; return $loginResult = true;
} }
@@ -3306,7 +3303,7 @@ function pager($rpp, $count, $href, $opts = array(), $pagename = "page") {
$start = $page * $rpp; $start = $page * $rpp;
$add_key_shortcut = key_shortcut($page,$pages-1); $add_key_shortcut = key_shortcut($page,$pages-1);
return array($pagertop, $pagerbottom, "LIMIT $start,$rpp", $start, $rpp, $page); return array($pagertop, $pagerbottom, "limit $rpp offset $start", $start, $rpp, $page);
} }
function commenttable($rows, $type, $parent_id, $review = false) function commenttable($rows, $type, $parent_id, $review = false)
@@ -5413,7 +5410,7 @@ function saveSetting(string $prefix, array $nameAndValue, string $autoload = 'ye
{ {
$prefix = strtolower($prefix); $prefix = strtolower($prefix);
$datetimeNow = date('Y-m-d H:i:s'); $datetimeNow = date('Y-m-d H:i:s');
$sql = "insert into `settings` (name, value, created_at, updated_at, autoload) values "; $sql = "insert into settings (name, value, created_at, updated_at, autoload) values ";
$data = []; $data = [];
foreach ($nameAndValue as $name => $value) { foreach ($nameAndValue as $name => $value) {
if (is_array($value)) { if (is_array($value)) {
@@ -5421,7 +5418,7 @@ function saveSetting(string $prefix, array $nameAndValue, string $autoload = 'ye
} }
$data[] = sprintf("(%s, %s, %s, %s, '%s')", sqlesc("$prefix.$name"), sqlesc($value), sqlesc($datetimeNow), sqlesc($datetimeNow), $autoload); $data[] = sprintf("(%s, %s, %s, %s, '%s')", sqlesc("$prefix.$name"), sqlesc($value), sqlesc($datetimeNow), sqlesc($datetimeNow), $autoload);
} }
$sql .= implode(",", $data) . " on duplicate key update value = values(value)"; $sql .= implode(",", $data) . " " . \Nexus\Database\NexusDB::upsertField(['name'], ['value']);
\Nexus\Database\NexusDB::statement($sql); \Nexus\Database\NexusDB::statement($sql);
clear_setting_cache(); clear_setting_cache();
do_action("nexus_setting_update"); do_action("nexus_setting_update");
@@ -6062,7 +6059,7 @@ function insert_torrent_tags($torrentId, $tagIdArr, $sync = false)
if (empty($tagIdArr)) { if (empty($tagIdArr)) {
return; return;
} }
$insertTagsSql = 'insert into torrent_tags (`torrent_id`, `tag_id`, `created_at`, `updated_at`) values '; $insertTagsSql = 'insert into torrent_tags (torrent_id, tag_id, created_at, updated_at) values ';
$values = []; $values = [];
foreach ($tagIdArr as $tagId) { foreach ($tagIdArr as $tagId) {
if (in_array($tagId, $specialTags) && !$canSetSpecialTag) { if (in_array($tagId, $specialTags) && !$canSetSpecialTag) {
@@ -6142,7 +6139,7 @@ function calculate_seed_bonus($uid, $torrentIdArr = null): array
$idStr = implode(',', \Illuminate\Support\Arr::wrap($torrentIdArr)); $idStr = implode(',', \Illuminate\Support\Arr::wrap($torrentIdArr));
$sql = "select torrents.id, torrents.added, torrents.size, torrents.seeders, 'NO_PEER_ID' as peerID, '' as last_action, '' as ip from torrents WHERE id in ($idStr) and size >= $minSize"; $sql = "select torrents.id, torrents.added, torrents.size, torrents.seeders, 'NO_PEER_ID' as peerID, '' as last_action, '' as ip from torrents WHERE id in ($idStr) and size >= $minSize";
} else { } else {
$sql = "select torrents.id, torrents.added, torrents.size, torrents.seeders, peers.id as peerID, peers.last_action, peers.ip from torrents LEFT JOIN peers ON peers.torrent = torrents.id WHERE peers.userid = $uid AND peers.seeder ='yes' and torrents.size > $minSize group by peers.torrent, peers.peer_id"; $sql = "select torrents.id, torrents.added, torrents.size, torrents.seeders, peers.id as peerID, peers.last_action, peers.ip from torrents LEFT JOIN peers ON peers.torrent = torrents.id WHERE peers.userid = $uid AND peers.seeder ='yes' and torrents.size > $minSize group by torrents.id, peers.id";
} }
$tagGrouped = []; $tagGrouped = [];
$torrentResult = \Nexus\Database\NexusDB::select($sql); $torrentResult = \Nexus\Database\NexusDB::select($sql);
@@ -6157,7 +6154,14 @@ function calculate_seed_bonus($uid, $torrentIdArr = null): array
$officialAdditionalFactor = \App\Models\Setting::get('bonus.official_addition'); $officialAdditionalFactor = \App\Models\Setting::get('bonus.official_addition');
$zeroBonusTag = \App\Models\Setting::get('bonus.zero_bonus_tag'); $zeroBonusTag = \App\Models\Setting::get('bonus.zero_bonus_tag');
$zeroBonusFactor = \App\Models\Setting::get('bonus.zero_bonus_factor'); $zeroBonusFactor = \App\Models\Setting::get('bonus.zero_bonus_factor');
$userMedalResult = \Nexus\Database\NexusDB::select("select round(sum(bonus_addition_factor), 5) as factor from medals where id in (select medal_id from user_medals where uid = $uid and (expire_at is null or expire_at > '$nowStr') and (bonus_addition_expire_at is null or bonus_addition_expire_at > '$nowStr'))"); if (\Nexus\Database\NexusDB::isMysql()) {
$factorField = "round(sum(bonus_addition_factor), 5)";
} elseif (\Nexus\Database\NexusDB::isPgsql()) {
$factorField = "round(sum(bonus_addition_factor)::numeric, 5)";
} else {
throw new \RuntimeException("Not supported database");
}
$userMedalResult = \Nexus\Database\NexusDB::select("select $factorField as factor from medals where id in (select medal_id from user_medals where uid = $uid and (expire_at is null or expire_at > '$nowStr') and (bonus_addition_expire_at is null or bonus_addition_expire_at > '$nowStr'))");
$medalAdditionalFactor = floatval($userMedalResult[0]['factor'] ?? 0); $medalAdditionalFactor = floatval($userMedalResult[0]['factor'] ?? 0);
do_log("$logPrefix, sql: $sql, count: " . count($torrentResult) . ", officialTag: $officialTag, officialAdditionalFactor: $officialAdditionalFactor, zeroBonusTag: $zeroBonusTag, zeroBonusFactor: $zeroBonusFactor, medalAdditionalFactor: $medalAdditionalFactor"); do_log("$logPrefix, sql: $sql, count: " . count($torrentResult) . ", officialTag: $officialTag, officialAdditionalFactor: $officialAdditionalFactor, zeroBonusTag: $zeroBonusTag, zeroBonusFactor: $zeroBonusFactor, medalAdditionalFactor: $medalAdditionalFactor");
$last_action = ""; $last_action = "";
+18 -5
View File
@@ -89,6 +89,10 @@ function sqlesc($value) {
} }
function hash_pad($hash) { function hash_pad($hash) {
if (is_resource($hash)) {
rewind($hash);
$hash = stream_get_contents($hash);
}
return str_pad($hash, 20); return str_pad($hash, 20);
} }
@@ -96,7 +100,14 @@ function hash_where($name, $hash) {
// $shhash = preg_replace('/ *$/s', "", $hash); // $shhash = preg_replace('/ *$/s', "", $hash);
// return "($name = " . sqlesc($hash) . " OR $name = " . sqlesc($shhash) . ")"; // return "($name = " . sqlesc($hash) . " OR $name = " . sqlesc($shhash) . ")";
// return sprintf("$name in (%s, %s)", sqlesc($hash), sqlesc($shhash)); // return sprintf("$name in (%s, %s)", sqlesc($hash), sqlesc($shhash));
return "$name = " . sqlesc($hash); if (\Nexus\Database\NexusDB::isMysql()) {
return "$name = " . sqlesc($hash);
} elseif (Nexus\Database\NexusDB::isPgsql()) {
return "$name = decode(bin2hex('$hash'), 'hex')";
} else {
throw new \RuntimeException("Not supported database");
}
} }
//no need any more... //no need any more...
@@ -622,10 +633,11 @@ function last_query($all = false, $format = 'json')
{ {
static $connection; static $connection;
if (is_null($connection)) { if (is_null($connection)) {
$connectionName = \Nexus\Database\NexusDB::getConnectionName();
if (IN_NEXUS) { if (IN_NEXUS) {
$connection = \Illuminate\Database\Capsule\Manager::connection(\Nexus\Database\NexusDB::ELOQUENT_CONNECTION_NAME); $connection = \Illuminate\Database\Capsule\Manager::connection($connectionName);
} else { } else {
$connection = \Illuminate\Support\Facades\DB::connection(config('database.default')); $connection = \Illuminate\Support\Facades\DB::connection($connectionName);
} }
} }
if ($all === 'COUNT') { if ($all === 'COUNT') {
@@ -1506,8 +1518,9 @@ function get_user_from_cookie(array $cookie, $isArray = true): array|\App\Models
$signature = $result['signature']; $signature = $result['signature'];
$log .= ", uid = $id"; $log .= ", uid = $id";
$isAjax = nexus()->isAjax(); $isAjax = nexus()->isAjax();
//only in nexus web can self-enable $selfEnableBonus = \App\Models\Setting::getSelfEnableBonus();
$shouldIgnoreEnabled = IN_NEXUS && !$isAjax; //only in nexus web can self-enable, and require bonus > 0
$shouldIgnoreEnabled = IN_NEXUS && !$isAjax && $selfEnableBonus > 0;
if ($isArray) { if ($isArray) {
$whereStr = sprintf("id = %d and status = 'confirmed'", $id); $whereStr = sprintf("id = %d and status = 'confirmed'", $id);
if (!$shouldIgnoreEnabled) { if (!$shouldIgnoreEnabled) {
+1 -1
View File
@@ -827,7 +827,7 @@ $lang_settings = array
'row_reward_times_limit' => '魔力奖励次数限制', 'row_reward_times_limit' => '魔力奖励次数限制',
'text_reward_times_limit_note' => '种子详情页的魔力奖励每人每天次数限制,设置为 0 不限制。默认:0', 'text_reward_times_limit_note' => '种子详情页的魔力奖励每人每天次数限制,设置为 0 不限制。默认:0',
'row_self_enable' => '自助解封', 'row_self_enable' => '自助解封',
'text_self_enable_note' => '个魔力值,如果他选择在被封禁 1 天内解封。封禁时长为 N 天,失去的魔力值将会是此值的 N 倍。', 'text_self_enable_note' => '个魔力值,如果他选择在被封禁 1 天内解封。封禁时长为 N 天,失去的魔力值将会是此值的 N 倍。设置为 0 禁用此功能。',
); );
?> ?>
+1 -1
View File
@@ -827,7 +827,7 @@ $lang_settings = array
'row_reward_times_limit' => '魔力獎勵次數限制', 'row_reward_times_limit' => '魔力獎勵次數限制',
'text_reward_times_limit_note' => '種子詳情頁的魔力獎勵每人每天次數限制,設置爲 0 不限制。默認:0', 'text_reward_times_limit_note' => '種子詳情頁的魔力獎勵每人每天次數限制,設置爲 0 不限制。默認:0',
'row_self_enable' => '自助解封', 'row_self_enable' => '自助解封',
'text_self_enable_note' => '個魔力值,如果他選擇在被封禁 1 天內解封。封禁時長為 N 天,失去的魔力值將會是此值的 N 倍。', 'text_self_enable_note' => '個魔力值,如果他選擇在被封禁 1 天內解封。封禁時長為 N 天,失去的魔力值將會是此值的 N 倍。設置為 0 禁用此功能。',
); );
?> ?>
+1 -1
View File
@@ -827,7 +827,7 @@ $lang_settings = array
'row_reward_times_limit' => 'Reward Frequency Limit', 'row_reward_times_limit' => 'Reward Frequency Limit',
'text_reward_times_limit_note' => 'Daily limit per user for bonus rewards on seed detail pages. Set to 0 for no limit. Default: 0', 'text_reward_times_limit_note' => 'Daily limit per user for bonus rewards on seed detail pages. Set to 0 for no limit. Default: 0',
'row_self_enable' => 'Self-service unblocking', 'row_self_enable' => 'Self-service unblocking',
'text_self_enable_note' => 'points. If he chooses to unblock within 1 day of being banned. If the ban duration is N days, the lost mana points will be N times this value.', 'text_self_enable_note' => 'points. If he chooses to unblock within 1 day of being banned. If the ban duration is N days, the lost mana points will be N times this value. Setting it to 0 disables this feature.',
); );
?> ?>
+6 -2
View File
@@ -1,9 +1,11 @@
<?php <?php
namespace Nexus\Database; namespace Nexus\Database;
use PDOStatement;
interface DBInterface interface DBInterface
{ {
public function connect($host, $username, $password, $database, $port); public function connect($host, $username, $password, $database, $port, $driver = 'mysql');
public function query(string $sql); public function query(string $sql);
@@ -29,4 +31,6 @@ interface DBInterface
public function freeResult($result); public function freeResult($result);
} public function prepare(string $sql): PDOStatement;
}
+11 -1
View File
@@ -1,11 +1,16 @@
<?php <?php
namespace Nexus\Database; namespace Nexus\Database;
/**
* @deprecated
*
* use DBPdo instead
*/
class DBMysqli implements DBInterface class DBMysqli implements DBInterface
{ {
private $mysqli; private $mysqli;
public function connect($host, $username, $password, $database, $port) public function connect($host, $username, $password, $database, $port, $driver = 'mysql')
{ {
$mysqli = new \mysqli($host, $username, $password, $database, $port); $mysqli = new \mysqli($host, $username, $password, $database, $port);
/* check connection */ /* check connection */
@@ -87,4 +92,9 @@ class DBMysqli implements DBInterface
return $mysqliResult->free_result(); return $mysqliResult->free_result();
} }
public function prepare(string $sql): \PDOStatement
{
throw new \RuntimeException("mysqli not supported");
}
} }
+133
View File
@@ -0,0 +1,133 @@
<?php
namespace Nexus\Database;
use PDO;
class DBPdo implements DBInterface
{
private PDO $pdo;
private $driver;
private $lastStmt;
public function connect($host, $username, $password, $database, $port, $driver = 'mysql')
{
$this->driver = $driver;
if ($driver === 'mysql') {
$dsn = "mysql:host={$host};port={$port};dbname={$database};charset=utf8mb4";
} elseif ($driver === 'pgsql') {
$dsn = "pgsql:host={$host};port={$port};dbname={$database}";
} else {
throw new DatabaseException("Unsupported driver");
}
$pdo = new PDO($dsn, $username, $password, [
PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION, // 替代 mysqli 报错机制
PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC,
]);
// ===== MySQL 专属 =====
if ($driver === 'mysql') {
$pdo->exec("SET NAMES utf8mb4");
$pdo->exec("SET collation_connection = 'utf8mb4_unicode_ci'");
$pdo->exec("SET sql_mode=''");
$pdo->exec("SET time_zone='".date('P')."'");
}
// ===== PostgreSQL 专属 =====
if ($driver === 'pgsql') {
$pdo->exec("SET TIME ZONE '".date('P')."'");
}
return $this->pdo = $pdo;
}
public function query(string $sql)
{
$this->lastStmt = $this->pdo->query($sql);
return $this->lastStmt;
}
public function error(): string
{
$error = $this->pdo->errorInfo();
return $error[2] ?? '';
}
public function errno(): int
{
$error = $this->pdo->errorInfo();
return (int)($error[1] ?? 0);
}
public function numRows($stmt): int
{
// ⚠️ PDO 对 SELECT 不可靠,这里兼容处理
return $stmt->rowCount();
}
public function selectDb($database)
{
if ($this->driver === 'mysql') {
return $this->pdo->exec("USE `{$database}`");
}
if ($this->driver === 'pgsql') {
// PostgreSQL 不能切数据库,只能重连
throw new DatabaseException("PostgreSQL does not support selectDb()");
}
return false;
}
public function fetchAssoc($stmt)
{
return $stmt->fetch(PDO::FETCH_ASSOC);
}
public function fetchRow($stmt)
{
return $stmt->fetch(PDO::FETCH_NUM);
}
public function fetchArray($stmt, $type = null)
{
if ($type === null) {
return $stmt->fetch(PDO::FETCH_BOTH);
}
// 兼容 mysqli 常量
switch ($type) {
case MYSQLI_ASSOC:
return $stmt->fetch(PDO::FETCH_ASSOC);
case MYSQLI_NUM:
return $stmt->fetch(PDO::FETCH_NUM);
default:
return $stmt->fetch(PDO::FETCH_BOTH);
}
}
public function affectedRows(): int
{
return $this->lastStmt ? $this->lastStmt->rowCount() : 0;
}
public function escapeString(string $string): string
{
return substr($this->pdo->quote($string), 1, -1);
}
public function lastInsertId(): int
{
return (int)$this->pdo->lastInsertId();
}
public function freeResult($stmt)
{
return $stmt->closeCursor();
}
public function prepare(string $sql): \PDOStatement
{
return $this->lastStmt = $this->pdo->prepare($sql);
}
}
+123 -11
View File
@@ -57,14 +57,15 @@ class NexusDB
return self::$instance; return self::$instance;
} }
$instance = new self; $instance = new self;
$driver = new DBMysqli(); // $driver = new DBMysqli();
$driver = new DBPdo();
$instance->setDriver($driver); $instance->setDriver($driver);
return self::$instance = $instance; return self::$instance = $instance;
} }
public function connect($host, $username, $password, $database, $port) public function connect($host, $username, $password, $database, $port, $driver = 'mysql')
{ {
$result = $this->driver->connect($host, $username, $password, $database, $port); $result = $this->driver->connect($host, $username, $password, $database, $port, $driver);
if (!$result) { if (!$result) {
throw new DatabaseException(sprintf('[%s]: %s', $this->errno(), $this->error())); throw new DatabaseException(sprintf('[%s]: %s', $this->errno(), $this->error()));
} }
@@ -77,8 +78,9 @@ class NexusDB
if ($this->isConnected()) { if ($this->isConnected()) {
return null; return null;
} }
$config = nexus_config('nexus.mysql'); $dbType = self::getConnectionName();
return $this->connect($config['host'], $config['username'], $config['password'], $config['database'], $config['port']); $config = nexus_config('nexus.database.connections.' . $dbType);
return $this->connect($config['host'], $config['username'], $config['password'], $config['database'], $config['port'], $dbType);
} }
public function query(string $sql) public function query(string $sql)
@@ -149,6 +151,11 @@ class NexusDB
return $this->driver->freeResult($result); return $this->driver->freeResult($result);
} }
public function prepare(string $sql)
{
return $this->driver->prepare($sql);
}
public function isConnected() public function isConnected()
{ {
return $this->isConnected; return $this->isConnected;
@@ -162,9 +169,9 @@ class NexusDB
if (!IN_NEXUS) { if (!IN_NEXUS) {
return DB::table($table)->insertGetId($data); return DB::table($table)->insertGetId($data);
} }
$fields = array_map(function ($value) {return "`$value`";}, array_keys($data)); $fields = array_map(function ($value) {return "$value";}, array_keys($data));
$values = array_map(function ($value) {return sqlesc($value);}, array_values($data)); $values = array_map(function ($value) {return sqlesc($value);}, array_values($data));
$sql = sprintf("insert into `%s` (%s) values (%s)", $table, implode(', ', $fields), implode(', ', $values)); $sql = sprintf("insert into %s (%s) values (%s)", $table, implode(', ', $fields), implode(', ', $values));
sql_query($sql); sql_query($sql);
return mysql_insert_id(); return mysql_insert_id();
} }
@@ -259,7 +266,7 @@ class NexusDB
public static function bootEloquent(array $config) public static function bootEloquent(array $config)
{ {
$capsule = new Capsule(Container::getInstance()); $capsule = new Capsule(Container::getInstance());
$connectionName = self::ELOQUENT_CONNECTION_NAME; $connectionName = self::getConnectionName();
$capsule->addConnection($config, $connectionName); $capsule->addConnection($config, $connectionName);
$capsule->setAsGlobal(); $capsule->setAsGlobal();
$capsule->bootEloquent(); $capsule->bootEloquent();
@@ -271,7 +278,7 @@ class NexusDB
private static function schema(): \Illuminate\Database\Schema\Builder private static function schema(): \Illuminate\Database\Schema\Builder
{ {
if (IN_NEXUS) { if (IN_NEXUS) {
return Capsule::schema(self::ELOQUENT_CONNECTION_NAME); return Capsule::schema(self::getConnectionName());
} }
throw new \RuntimeException('can not call this when not in nexus.'); throw new \RuntimeException('can not call this when not in nexus.');
} }
@@ -295,7 +302,7 @@ class NexusDB
public static function table($table): \Illuminate\Database\Query\Builder public static function table($table): \Illuminate\Database\Query\Builder
{ {
if (IN_NEXUS) { if (IN_NEXUS) {
return Capsule::table($table, null, self::ELOQUENT_CONNECTION_NAME); return Capsule::table($table, null, self::getConnectionName());
} }
return DB::table($table); return DB::table($table);
} }
@@ -319,7 +326,7 @@ class NexusDB
public static function transaction(\Closure $callback, $attempts = 1) public static function transaction(\Closure $callback, $attempts = 1)
{ {
if (IN_NEXUS) { if (IN_NEXUS) {
return Capsule::connection(self::ELOQUENT_CONNECTION_NAME)->transaction($callback, $attempts); return Capsule::connection(self::getConnectionName())->transaction($callback, $attempts);
} }
return DB::transaction($callback, $attempts); return DB::transaction($callback, $attempts);
} }
@@ -455,5 +462,110 @@ class NexusDB
} }
} }
public static function getConnectionName()
{
return nexus_config('nexus.database.default');
}
public static function isMysql(): bool
{
return self::getConnectionName() === 'mysql';
}
public static function isPgsql(): bool
{
return self::getConnectionName() === 'pgsql';
}
public static function listColumnIndexNames(string $table, array $columns): array
{
$indexes = Schema::getIndexes($table);
$indexesNames = [];
foreach ($indexes as $index) {
foreach ($columns as $columnName) {
if (in_array($columnName, $index['columns'])) {
$indexesNames[] = $index['name'];
}
}
}
return $indexesNames;
}
public static function getDatabaseVersionInfo(): array
{
if (self::isMysql()) {
$sql = 'select version() as v';
$result = NexusDB::select($sql);
$version = $result[0]['v'];
$minVersion = '5.7.8';
} else if (self::isPgsql()) {
$sql = 'SHOW server_version;';
$result = NexusDB::select($sql);
$version = $result[0]['server_version'];
$minVersion = '16.0';
} else {
throw new \RuntimeException('Not supported database.');
}
$dbType = self::getConnectionName();
$match = version_compare($version, $minVersion, '>=');
return compact('version', 'match', 'minVersion', 'dbType');
}
public static function unixTimestampField(string $field): string
{
if (self::isMysql()) {
return sprintf("UNIX_TIMESTAMP(%s)", $field);
} elseif (self::isPgsql()) {
return sprintf("EXTRACT(EPOCH FROM %s)", $field);
} else {
throw new \RuntimeException('Not supported database.');
}
}
public static function fromUnixTimestampField(int $timestamp): string
{
if (self::isMysql()) {
return sprintf("FROM_UNIXTIME(%d)", $timestamp);
} elseif (self::isPgsql()) {
return sprintf("to_timestamp(%d)", $timestamp);
} else {
throw new \RuntimeException('Not supported database.');
}
}
public static function upsertField(array $uniqueFields, array $updateFields = []): string
{
if (self::isMysql()) {
$updates = [];
foreach ($updateFields ?: ['id'] as $field) {
$updates[] = "`$field` = VALUES(`$field`)";
}
return sprintf("ON DUPLICATE KEY UPDATE %s", implode(', ', $updates));
} elseif (self::isPgsql()) {
if (empty($updateFields)) {
$updateStr = "NOTHING";
} else {
$updates = [];
foreach ($updateFields as $field) {
$updates[] = "$field = EXCLUDED.$field";
}
$updateStr = "UPDATE SET " . implode(', ', $updates);
}
return sprintf("ON CONFLICT (%s) DO %s", implode(', ', $uniqueFields), $updateStr);
} else {
throw new \RuntimeException('Not supported database.');
}
}
public static function groupConcatField(string $field): string
{
if (self::isMysql()) {
return sprintf("group_concat(%s)", $field);
} elseif (self::isPgsql()) {
return sprintf("string_agg(%s::text, ',')", $field);
} else {
throw new \RuntimeException('Not supported database.');
}
}
} }
+7 -2
View File
@@ -1,9 +1,9 @@
<?php <?php
use Nexus\Database\NexusDB; use Nexus\Database\NexusDB;
function mysql_connect($host, $username, $password, $database, $port) function mysql_connect($host, $username, $password, $database, $port, $driver = 'mysql')
{ {
return NexusDB::getInstance()->connect($host, $username, $password, $database, $port); return NexusDB::getInstance()->connect($host, $username, $password, $database, $port, $driver);
} }
function mysql_errno() function mysql_errno()
@@ -65,3 +65,8 @@ function mysql_free_result($result)
{ {
return NexusDB::getInstance()->freeResult($result); return NexusDB::getInstance()->freeResult($result);
} }
function mysql_prepare(string $sql): \PDOStatement
{
return NexusDB::getInstance()->prepare($sql);
}
+8 -1
View File
@@ -384,7 +384,14 @@ JS;
$torrentIdArr = [$torrentId]; $torrentIdArr = [$torrentId];
} }
$torrentIdStr = implode(',', $torrentIdArr); $torrentIdStr = implode(',', $torrentIdArr);
$res = sql_query("select f.*, v.custom_field_value, v.torrent_id from torrents_custom_field_values v inner join torrents_custom_fields f on v.custom_field_id = f.id inner join searchbox box on box.id = $searchBoxId and find_in_set(f.id, box.custom_fields) where torrent_id in ($torrentIdStr) order by f.priority desc"); if (NexusDB::isMysql()) {
$customFieldStr = "find_in_set(f.id, box.custom_fields)";
} elseif (NexusDB::isPgsql()) {
$customFieldStr = "f.id = ANY(string_to_array(box.custom_fields, ',')::int[])";
} else {
throw new \RuntimeException("Not supported database");
}
$res = sql_query("select f.*, v.custom_field_value, v.torrent_id from torrents_custom_field_values v inner join torrents_custom_fields f on v.custom_field_id = f.id inner join searchbox box on box.id = $searchBoxId and $customFieldStr where torrent_id in ($torrentIdStr) order by f.priority desc");
$values = []; $values = [];
$result = []; $result = [];
while ($row = mysql_fetch_assoc($res)) { while ($row = mysql_fetch_assoc($res)) {

Some files were not shown because too many files have changed in this diff Show More