Merge remote-tracking branch 'origin/php8' into php8

This commit is contained in:
xiaomlove
2024-11-18 22:21:27 +08:00
62 changed files with 864 additions and 242 deletions
+2
View File
@@ -91,3 +91,5 @@ MEILISEARCH_MASTER_KEY=
CACHE_KEY_AGENT_ALLOW=all_agent_allows CACHE_KEY_AGENT_ALLOW=all_agent_allows
CACHE_KEY_AGENT_DENY=all_agent_denies CACHE_KEY_AGENT_DENY=all_agent_denies
CHANNEL_NAME_SETTING=channel_setting CHANNEL_NAME_SETTING=channel_setting
CHANNEL_NAME_MODEL_EVENT=channel_model_event
FORCE_SCHEME=
+6 -1
View File
@@ -6,6 +6,7 @@ use App\Events\NewsCreated;
use App\Events\TorrentCreated; use App\Events\TorrentCreated;
use App\Events\TorrentDeleted; use App\Events\TorrentDeleted;
use App\Events\TorrentUpdated; use App\Events\TorrentUpdated;
use App\Events\UserCreated;
use App\Events\UserDestroyed; use App\Events\UserDestroyed;
use App\Events\UserDisabled; use App\Events\UserDisabled;
use App\Events\UserEnabled; use App\Events\UserEnabled;
@@ -31,15 +32,18 @@ class FireEvent extends Command
* *
* @var string * @var string
*/ */
protected $description = 'Fire a event, options: --name, --idKey --idKeyOld'; protected $description = 'Fire an event, options: --name, --idKey --idKeyOld';
protected array $eventMaps = [ protected array $eventMaps = [
"torrent_created" => ['event' => TorrentCreated::class, 'model' => Torrent::class], "torrent_created" => ['event' => TorrentCreated::class, 'model' => Torrent::class],
"torrent_updated" => ['event' => TorrentUpdated::class, 'model' => Torrent::class], "torrent_updated" => ['event' => TorrentUpdated::class, 'model' => Torrent::class],
"torrent_deleted" => ['event' => TorrentDeleted::class, 'model' => Torrent::class], "torrent_deleted" => ['event' => TorrentDeleted::class, 'model' => Torrent::class],
"user_created" => ['event' => UserCreated::class, 'model' => User::class],
"user_destroyed" => ['event' => UserDestroyed::class, 'model' => User::class], "user_destroyed" => ['event' => UserDestroyed::class, 'model' => User::class],
"user_disabled" => ['event' => UserDisabled::class, 'model' => User::class], "user_disabled" => ['event' => UserDisabled::class, 'model' => User::class],
"user_enabled" => ['event' => UserEnabled::class, 'model' => User::class], "user_enabled" => ['event' => UserEnabled::class, 'model' => User::class],
"news_created" => ['event' => NewsCreated::class, 'model' => News::class], "news_created" => ['event' => NewsCreated::class, 'model' => News::class],
]; ];
@@ -69,6 +73,7 @@ class FireEvent extends Command
} }
$result = call_user_func_array([$eventName, "dispatch"], $params); $result = call_user_func_array([$eventName, "dispatch"], $params);
$log .= ", success call dispatch, result: " . var_export($result, true); $log .= ", success call dispatch, result: " . var_export($result, true);
publish_model_event($name, $model->id);
} else { } else {
$log .= ", invalid argument to call, it should be instance of: " . Model::class; $log .= ", invalid argument to call, it should be instance of: " . Model::class;
} }
+5 -1
View File
@@ -40,10 +40,12 @@ use App\Repositories\UserRepository;
use Carbon\Carbon; use Carbon\Carbon;
use Filament\Notifications\Notification; use Filament\Notifications\Notification;
use GeoIp2\Database\Reader; use GeoIp2\Database\Reader;
use GuzzleHttp\Client;
use Illuminate\Console\Command; use Illuminate\Console\Command;
use Illuminate\Encryption\Encrypter; use Illuminate\Encryption\Encrypter;
use Illuminate\Support\Facades\DB; use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Hash; use Illuminate\Support\Facades\Hash;
use Illuminate\Support\Facades\Http;
use Illuminate\Support\Facades\Redis; use Illuminate\Support\Facades\Redis;
use Illuminate\Support\Facades\Storage; use Illuminate\Support\Facades\Storage;
use Illuminate\Support\Str; use Illuminate\Support\Str;
@@ -59,6 +61,7 @@ use NexusPlugin\Permission\Models\Role;
use NexusPlugin\PostLike\PostLikeRepository; use NexusPlugin\PostLike\PostLikeRepository;
use NexusPlugin\StickyPromotion\Models\StickyPromotion; use NexusPlugin\StickyPromotion\Models\StickyPromotion;
use NexusPlugin\StickyPromotion\Models\StickyPromotionParticipator; use NexusPlugin\StickyPromotion\Models\StickyPromotionParticipator;
use NexusPlugin\Tracker\TrackerRepository;
use NexusPlugin\Work\Models\RoleWork; use NexusPlugin\Work\Models\RoleWork;
use NexusPlugin\Work\WorkRepository; use NexusPlugin\Work\WorkRepository;
use PhpIP\IP; use PhpIP\IP;
@@ -98,7 +101,8 @@ class Test extends Command
*/ */
public function handle() public function handle()
{ {
CleanupRepository::checkQueueFailedJobs(); $result = \Nexus\Plugin\Plugin::listEnabled();
dd($result);
} }
} }
+5
View File
@@ -4,6 +4,9 @@ namespace App\Console;
use App\Jobs\CheckCleanup; use App\Jobs\CheckCleanup;
use App\Jobs\CheckQueueFailedJobs; use App\Jobs\CheckQueueFailedJobs;
use App\Jobs\MaintainPluginState;
use App\Jobs\ManagePlugin;
use App\Utils\ThirdPartyJob;
use Carbon\Carbon; use Carbon\Carbon;
use Illuminate\Console\Scheduling\Event; use Illuminate\Console\Scheduling\Event;
use Illuminate\Console\Scheduling\Schedule; use Illuminate\Console\Scheduling\Schedule;
@@ -41,6 +44,8 @@ class Kernel extends ConsoleKernel
$schedule->command('meilisearch:import')->weeklyOn(1, "03:00")->withoutOverlapping(); $schedule->command('meilisearch:import')->weeklyOn(1, "03:00")->withoutOverlapping();
$schedule->command('torrent:load_pieces_hash')->dailyAt("01:00")->withoutOverlapping(); $schedule->command('torrent:load_pieces_hash')->dailyAt("01:00")->withoutOverlapping();
$schedule->job(new CheckQueueFailedJobs())->everySixHours()->withoutOverlapping(); $schedule->job(new CheckQueueFailedJobs())->everySixHours()->withoutOverlapping();
$schedule->job(new ThirdPartyJob())->everyMinute()->withoutOverlapping();
$schedule->job(new MaintainPluginState())->everyMinute()->withoutOverlapping();
$this->registerScheduleCleanup($schedule); $this->registerScheduleCleanup($schedule);
} }
+39
View File
@@ -0,0 +1,39 @@
<?php
namespace App\Events;
use Illuminate\Broadcasting\Channel;
use Illuminate\Broadcasting\InteractsWithSockets;
use Illuminate\Broadcasting\PresenceChannel;
use Illuminate\Broadcasting\PrivateChannel;
use Illuminate\Contracts\Broadcasting\ShouldBroadcast;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Foundation\Events\Dispatchable;
use Illuminate\Queue\SerializesModels;
class UserCreated
{
use Dispatchable, InteractsWithSockets, SerializesModels;
public ?Model $model = null;
/**
* Create a new event instance.
*
* @return void
*/
public function __construct(Model $model)
{
$this->model = $model;
}
/**
* Get the channels the event should broadcast on.
*
* @return \Illuminate\Broadcasting\Channel|array
*/
public function broadcastOn()
{
return new PrivateChannel('channel-name');
}
}
+25
View File
@@ -1,7 +1,32 @@
<?php <?php
namespace App\Filament\Pages; namespace App\Filament\Pages;
use App\Filament\Widgets\AccountInfo;
use App\Filament\Widgets\LatestTorrents;
use App\Filament\Widgets\LatestUsers;
use App\Filament\Widgets\SystemInfo;
use App\Filament\Widgets\TorrentStat;
use App\Filament\Widgets\TorrentTrend;
use App\Filament\Widgets\UserClassStat;
use App\Filament\Widgets\UserStat;
use App\Filament\Widgets\UserTrend;
class Dashboard extends \Filament\Pages\Dashboard class Dashboard extends \Filament\Pages\Dashboard
{ {
protected ?string $maxContentWidth = 'full'; protected ?string $maxContentWidth = 'full';
protected function getWidgets(): array
{
return [
AccountInfo::class,
LatestUsers::class,
LatestTorrents::class,
UserTrend::class,
TorrentTrend::class,
UserStat::class,
UserClassStat::class,
TorrentStat::class,
SystemInfo::class,
];
}
} }
@@ -66,6 +66,8 @@ class TorrentStateResource extends Resource
Tables\Actions\EditAction::make()->after(function () { Tables\Actions\EditAction::make()->after(function () {
do_log("cache_del: global_promotion_state"); do_log("cache_del: global_promotion_state");
NexusDB::cache_del(Setting::TORRENT_GLOBAL_STATE_CACHE_KEY); NexusDB::cache_del(Setting::TORRENT_GLOBAL_STATE_CACHE_KEY);
do_log("publish_model_event: global_promotion_state_updated");
publish_model_event("global_promotion_state_updated", 0);
}), }),
// Tables\Actions\DeleteAction::make(), // Tables\Actions\DeleteAction::make(),
]) ])
@@ -117,9 +117,4 @@ class ViewExamUser extends ViewRecord
Actions\DeleteAction::make(), Actions\DeleteAction::make(),
]; ];
} }
private function getProgress()
{
}
} }
+1 -1
View File
@@ -12,7 +12,7 @@ class TrustProxies extends Middleware
* *
* @var array<int, string>|string|null * @var array<int, string>|string|null
*/ */
protected $proxies; protected $proxies = ['*'];
/** /**
* The headers that should be used to detect proxies. * The headers that should be used to detect proxies.
+68
View File
@@ -0,0 +1,68 @@
<?php
namespace App\Jobs;
use App\Models\TorrentBuyLog;
use App\Repositories\BonusRepository;
use App\Repositories\TorrentRepository;
use Illuminate\Bus\Queueable;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Foundation\Bus\Dispatchable;
use Illuminate\Queue\InteractsWithQueue;
use Illuminate\Queue\SerializesModels;
class BuyTorrent implements ShouldQueue
{
use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;
public int $userId;
public int $torrentId;
/**
* Create a new job instance.
*
* @return void
*/
public function __construct(int $userId, int $torrentId)
{
$this->userId = $userId;
$this->torrentId = $torrentId;
}
/**
* Execute the job.
*
* @return void
*/
public function handle()
{
$logPrefix = sprintf("user: %s, torrent: %s", $this->userId, $this->torrentId);
$torrentRep = new TorrentRepository();
$userId = $this->userId;
$torrentId = $this->torrentId;
$hasBuy = TorrentBuyLog::query()
->where("uid", $userId)
->where("torrent_id", $torrentId)
->exists()
;
if ($hasBuy) {
//标记购买成功
do_log("$logPrefix, already bought");
$torrentRep->addBuySuccessCache($userId, $torrentId);
return;
}
try {
$bonusRep = new BonusRepository();
$bonusRep->consumeToBuyTorrent($this->userId, $this->torrentId);
//标记购买成功
do_log("$logPrefix, buy torrent success");
$torrentRep->addBuySuccessCache($userId, $torrentId);
} catch (\Throwable $throwable) {
//标记购买失败,缓存 3600 秒,这个时间内不能再次购买
do_log("$logPrefix, buy torrent fail: " . $throwable->getMessage(), "error");
$torrentRep->addBuyFailCache($userId, $torrentId);
}
}
}
+41 -8
View File
@@ -9,6 +9,7 @@ use Illuminate\Contracts\Queue\ShouldBeUnique;
use Illuminate\Contracts\Queue\ShouldQueue; use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Foundation\Bus\Dispatchable; use Illuminate\Foundation\Bus\Dispatchable;
use Illuminate\Queue\InteractsWithQueue; use Illuminate\Queue\InteractsWithQueue;
use Illuminate\Queue\Middleware\WithoutOverlapping;
use Illuminate\Queue\SerializesModels; use Illuminate\Queue\SerializesModels;
use Nexus\Database\NexusDB; use Nexus\Database\NexusDB;
use Nexus\Nexus; use Nexus\Nexus;
@@ -55,6 +56,16 @@ class CalculateUserSeedBonus implements ShouldQueue
public $timeout = 3600; public $timeout = 3600;
/**
* 获取任务时,应该通过的中间件。
*
* @return array
*/
public function middleware()
{
return [new WithoutOverlapping($this->idRedisKey)];
}
/** /**
* Execute the job. * Execute the job.
* *
@@ -63,7 +74,11 @@ class CalculateUserSeedBonus implements ShouldQueue
public function handle() public function handle()
{ {
$beginTimestamp = time(); $beginTimestamp = time();
$logPrefix = sprintf("[CLEANUP_CLI_CALCULATE_SEED_BONUS_HANDLE_JOB], commonRequestId: %s, beginUid: %s, endUid: %s", $this->requestId, $this->beginUid, $this->endUid); $logPrefix = sprintf(
"[CLEANUP_CLI_CALCULATE_SEED_BONUS_HANDLE_JOB], commonRequestId: %s, beginUid: %s, endUid: %s, idStr: %s, idRedisKey: %s",
$this->requestId, $this->beginUid, $this->endUid, $this->idStr, $this->idRedisKey
);
do_log("$logPrefix, job start ...");
$haremAdditionFactor = Setting::get('bonus.harem_addition'); $haremAdditionFactor = Setting::get('bonus.harem_addition');
$officialAdditionFactor = Setting::get('bonus.official_addition'); $officialAdditionFactor = Setting::get('bonus.official_addition');
$donortimes_bonus = Setting::get('bonus.donortimes'); $donortimes_bonus = Setting::get('bonus.donortimes');
@@ -84,6 +99,8 @@ class CalculateUserSeedBonus implements ShouldQueue
$logFile = getLogFile("seed-bonus-points"); $logFile = getLogFile("seed-bonus-points");
do_log("$logPrefix, [GET_UID_REAL], count: " . count($results) . ", logFile: $logFile"); do_log("$logPrefix, [GET_UID_REAL], count: " . count($results) . ", logFile: $logFile");
$fd = fopen($logFile, 'a'); $fd = fopen($logFile, 'a');
$seedPointsUpdates = $seedPointsPerHourUpdates = $seedBonusUpdates = [];
$logStr = "";
foreach ($results as $userInfo) foreach ($results as $userInfo)
{ {
$uid = $userInfo['id']; $uid = $userInfo['id'];
@@ -92,7 +109,7 @@ class CalculateUserSeedBonus implements ShouldQueue
$bonusLog = "[CLEANUP_CLI_CALCULATE_SEED_BONUS_HANDLE_USER], user: $uid, seedBonusResult: " . nexus_json_encode($seedBonusResult); $bonusLog = "[CLEANUP_CLI_CALCULATE_SEED_BONUS_HANDLE_USER], user: $uid, seedBonusResult: " . nexus_json_encode($seedBonusResult);
$all_bonus = $seedBonusResult['seed_bonus']; $all_bonus = $seedBonusResult['seed_bonus'];
$bonusLog .= ", all_bonus: $all_bonus"; $bonusLog .= ", all_bonus: $all_bonus";
if ($isDonor) { if ($isDonor && $donortimes_bonus != 0) {
$all_bonus = $all_bonus * $donortimes_bonus; $all_bonus = $all_bonus * $donortimes_bonus;
$bonusLog .= ", isDonor, donortimes_bonus: $donortimes_bonus, all_bonus: $all_bonus"; $bonusLog .= ", isDonor, donortimes_bonus: $donortimes_bonus, all_bonus: $all_bonus";
} }
@@ -112,13 +129,17 @@ class CalculateUserSeedBonus implements ShouldQueue
$all_bonus += $medalAddition; $all_bonus += $medalAddition;
$bonusLog .= ", medalAdditionFactor: {$seedBonusResult['medal_additional_factor']}, medalBonus: {$seedBonusResult['medal_bonus']}, medalAddition: $medalAddition, all_bonus: $all_bonus"; $bonusLog .= ", medalAdditionFactor: {$seedBonusResult['medal_additional_factor']}, medalBonus: {$seedBonusResult['medal_bonus']}, medalAddition: $medalAddition, all_bonus: $all_bonus";
} }
do_log($bonusLog);
$dividend = 3600 / $autoclean_interval_one; $dividend = 3600 / $autoclean_interval_one;
$all_bonus = $all_bonus / $dividend; $all_bonus = $all_bonus / $dividend;
$seed_points = $seedBonusResult['seed_points'] / $dividend; $seed_points = $seedBonusResult['seed_points'] / $dividend;
$updatedAt = now()->toDateTimeString(); // $updatedAt = now()->toDateTimeString();
$sql = "update users set seed_points = ifnull(seed_points, 0) + $seed_points, seed_points_per_hour = {$seedBonusResult['seed_points']}, seedbonus = seedbonus + $all_bonus, seed_points_updated_at = '$updatedAt' where id = $uid limit 1"; // $sql = "update users set seed_points = ifnull(seed_points, 0) + $seed_points, seed_points_per_hour = {$seedBonusResult['seed_points']}, seedbonus = seedbonus + $all_bonus, seed_points_updated_at = '$updatedAt' where id = $uid limit 1";
do_log("$bonusLog, query: $sql"); // do_log("$bonusLog, query: $sql");
NexusDB::statement($sql); // NexusDB::statement($sql);
$seedPointsUpdates[] = sprintf("when %d then ifnull(seed_points, 0) + %f", $uid, $seed_points);
$seedPointsPerHourUpdates[] = sprintf("when %d then %f", $uid, $seedBonusResult['seed_points']);
$seedBonusUpdates[] = sprintf("when %d then seedbonus + %f", $uid, $all_bonus);
if ($fd) { if ($fd) {
$log = sprintf( $log = sprintf(
'%s|%s|%s|%s|%s|%s|%s|%s', '%s|%s|%s|%s|%s|%s|%s|%s',
@@ -126,16 +147,28 @@ class CalculateUserSeedBonus implements ShouldQueue
$userInfo['seed_points'], number_format($seed_points, 1, '.', ''), number_format($userInfo['seed_points'] + $seed_points, 1, '.', ''), $userInfo['seed_points'], number_format($seed_points, 1, '.', ''), number_format($userInfo['seed_points'] + $seed_points, 1, '.', ''),
$userInfo['seedbonus'], number_format($all_bonus, 1, '.', ''), number_format($userInfo['seedbonus'] + $all_bonus, 1, '.', '') $userInfo['seedbonus'], number_format($all_bonus, 1, '.', ''), number_format($userInfo['seedbonus'] + $all_bonus, 1, '.', '')
); );
fwrite($fd, $log . PHP_EOL); // fwrite($fd, $log . PHP_EOL);
$logStr .= $log . PHP_EOL;
} else { } else {
do_log("logFile: $logFile is not writeable!", 'error'); do_log("logFile: $logFile is not writeable!", 'error');
} }
} }
$nowStr = now()->toDateTimeString();
$sql = sprintf(
"update users set seed_points = case id %s end, seed_points_per_hour = case id %s end, seedbonus = case id %s end, seed_points_updated_at = '%s' where id in (%s)",
implode(" ", $seedPointsUpdates), implode(" ", $seedPointsPerHourUpdates), implode(" ", $seedBonusUpdates), $nowStr, $idStr
);
$result = NexusDB::statement($sql);
if ($delIdRedisKey) { if ($delIdRedisKey) {
NexusDB::cache_del($this->idRedisKey); NexusDB::cache_del($this->idRedisKey);
} }
fwrite($fd, $logStr);
$costTime = time() - $beginTimestamp; $costTime = time() - $beginTimestamp;
do_log("$logPrefix, [DONE], cost time: $costTime seconds"); do_log(sprintf(
"$logPrefix, [DONE], update user count: %s, result: %s, cost time: %s seconds",
count($seedPointsUpdates), var_export($result, true), $costTime
));
do_log("$logPrefix, sql: $sql", "debug");
} }
/** /**
+4
View File
@@ -16,6 +16,10 @@ class LoadTorrentBoughtUsers implements ShouldQueue
private int $torrentId; private int $torrentId;
public $tries = 1;
public $timeout = 1800;
/** /**
* Create a new job instance. * Create a new job instance.
* *
+44
View File
@@ -0,0 +1,44 @@
<?php
namespace App\Jobs;
use Illuminate\Bus\Queueable;
use Illuminate\Contracts\Queue\ShouldBeUnique;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Foundation\Bus\Dispatchable;
use Illuminate\Queue\InteractsWithQueue;
use Illuminate\Queue\SerializesModels;
use Nexus\Database\NexusDB;
use Nexus\Plugin\Plugin;
class MaintainPluginState implements ShouldQueue
{
use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;
/**
* Create a new job instance.
*
* @return void
*/
public function __construct()
{
//
}
/**
* Execute the job.
*
* @return void
*/
public function handle()
{
$enabled = Plugin::listEnabled();
$key = "nexus_plugin_enabled";
NexusDB::redis()->del($key);
$nowStr = now()->toDateTimeString();
foreach ($enabled as $name => $value) {
NexusDB::redis()->hSet($key, $name, $nowStr);
}
do_log("$key: " . nexus_json_encode($enabled));
}
}
+54 -32
View File
@@ -10,6 +10,7 @@ use Illuminate\Contracts\Queue\ShouldBeUnique;
use Illuminate\Contracts\Queue\ShouldQueue; use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Foundation\Bus\Dispatchable; use Illuminate\Foundation\Bus\Dispatchable;
use Illuminate\Queue\InteractsWithQueue; use Illuminate\Queue\InteractsWithQueue;
use Illuminate\Queue\Middleware\WithoutOverlapping;
use Illuminate\Queue\SerializesModels; use Illuminate\Queue\SerializesModels;
use Nexus\Database\NexusDB; use Nexus\Database\NexusDB;
@@ -55,6 +56,16 @@ class UpdateTorrentSeedersEtc implements ShouldQueue
public $timeout = 1800; public $timeout = 1800;
/**
* 获取任务时,应该通过的中间件。
*
* @return array
*/
public function middleware()
{
return [new WithoutOverlapping($this->idRedisKey)];
}
/** /**
* Execute the job. * Execute the job.
* *
@@ -63,7 +74,11 @@ class UpdateTorrentSeedersEtc implements ShouldQueue
public function handle() public function handle()
{ {
$beginTimestamp = time(); $beginTimestamp = time();
$logPrefix = sprintf("[CLEANUP_CLI_UPDATE_TORRENT_SEEDERS_ETC_HANDLE_JOB], commonRequestId: %s, beginTorrentId: %s, endTorrentId: %s", $this->requestId, $this->beginTorrentId, $this->endTorrentId); $logPrefix = sprintf(
"[CLEANUP_CLI_UPDATE_TORRENT_SEEDERS_ETC_HANDLE_JOB], commonRequestId: %s, beginTorrentId: %s, endTorrentId: %s, idStr: %s, idRedisKey: %s",
$this->requestId, $this->beginTorrentId, $this->endTorrentId, $this->idStr, $this->idRedisKey
);
do_log("$logPrefix, job start ...");
$idStr = $this->idStr; $idStr = $this->idStr;
$delIdRedisKey = false; $delIdRedisKey = false;
@@ -76,44 +91,51 @@ class UpdateTorrentSeedersEtc implements ShouldQueue
return; return;
} }
$torrentIdArr = explode(",", $idStr); $torrentIdArr = explode(",", $idStr);
foreach ($torrentIdArr as $torrentId) { //批量取,简单化
if ($torrentId <= 0) { $torrents = array();
continue; // $res = sql_query("SELECT torrent, seeder, COUNT(*) AS c FROM peers GROUP BY torrent, seeder where torrent in ($idStr)");
} $res = NexusDB::table("peers")
$peerResult = NexusDB::table('peers') ->selectRaw("torrent, seeder, COUNT(*) AS c")
->where('torrent', $torrentId) ->whereRaw("torrent in ($idStr)")
->selectRaw("count(*) as count, seeder") ->groupBy(['torrent', 'seeder'])
->groupBy('seeder') ->get();
->get() foreach ($res as $row) {
; if ($row->seeder == "yes")
$commentResult = NexusDB::table('comments') $key = "seeders";
->where('torrent',$torrentId) else
->selectRaw("count(*) as count") $key = "leechers";
->first() $torrents[$row->torrent][$key] = $row->c;
;
$update = [
'comments' => $commentResult && $commentResult->count !== null ? $commentResult->count : 0,
'seeders' => 0,
'leechers' => 0,
];
foreach ($peerResult as $item) {
if ($item->seeder == 'yes') {
$update['seeders'] = $item->count;
} elseif ($item->seeder == 'no') {
$update['leechers'] = $item->count;
}
}
NexusDB::table('torrents')->where('id', $torrentId)->update($update);
do_log("[CLEANUP_CLI_UPDATE_TORRENT_SEEDERS_ETC_HANDLE_TORRENT], [SUCCESS]: $torrentId => " . json_encode($update));
} }
// $res = sql_query("SELECT torrent, COUNT(*) AS c FROM comments GROUP BY torrent where torrent in ($idStr)");
$res = NexusDB::table("comments")
->selectRaw("torrent, COUNT(*) AS c")
->whereRaw("torrent in ($idStr)")
->groupBy(['torrent'])
->get();
foreach ($res as $row) {
$torrents[$row->torrent]["comments"] = $row->c;
}
$seedersUpdates = $leechersUpdates = $commentsUpdates = [];
foreach ($torrentIdArr as $id) {
$seedersUpdates[] = sprintf("when %d then %d", $id, $torrents[$id]["seeders"] ?? 0);
$leechersUpdates[] = sprintf("when %d then %d", $id, $torrents[$id]["leechers"] ?? 0);
$commentsUpdates[] = sprintf("when %d then %d", $id, $torrents[$id]["comments"] ?? 0);
}
$sql = sprintf(
"update torrents set seeders = case id %s end, leechers = case id %s end, comments = case id %s end where id in (%s)",
implode(" ", $seedersUpdates), implode(" ", $leechersUpdates), implode(" ", $commentsUpdates), $idStr
);
$result = NexusDB::statement($sql);
if ($delIdRedisKey) { if ($delIdRedisKey) {
NexusDB::cache_del($this->idRedisKey); NexusDB::cache_del($this->idRedisKey);
} }
$costTime = time() - $beginTimestamp; $costTime = time() - $beginTimestamp;
do_log(sprintf( do_log(sprintf(
"$logPrefix, [DONE], update torrent count: %s, cost time: %s seconds", "$logPrefix, [DONE], update torrent count: %s, result: %s, cost time: %s seconds",
count($torrentIdArr), $costTime count($torrentIdArr), var_export($result, true), $costTime
)); ));
do_log("$logPrefix, sql: $sql", "debug");
} }
/** /**
+40 -24
View File
@@ -10,6 +10,7 @@ use Illuminate\Contracts\Queue\ShouldBeUnique;
use Illuminate\Contracts\Queue\ShouldQueue; use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Foundation\Bus\Dispatchable; use Illuminate\Foundation\Bus\Dispatchable;
use Illuminate\Queue\InteractsWithQueue; use Illuminate\Queue\InteractsWithQueue;
use Illuminate\Queue\Middleware\WithoutOverlapping;
use Illuminate\Queue\SerializesModels; use Illuminate\Queue\SerializesModels;
use Nexus\Database\NexusDB; use Nexus\Database\NexusDB;
@@ -55,6 +56,16 @@ class UpdateUserSeedingLeechingTime implements ShouldQueue
public $timeout = 3600; public $timeout = 3600;
/**
* 获取任务时,应该通过的中间件。
*
* @return array
*/
public function middleware()
{
return [new WithoutOverlapping($this->idRedisKey)];
}
/** /**
* Execute the job. * Execute the job.
* *
@@ -63,9 +74,12 @@ class UpdateUserSeedingLeechingTime implements ShouldQueue
public function handle() public function handle()
{ {
$beginTimestamp = time(); $beginTimestamp = time();
$logPrefix = sprintf("[CLEANUP_CLI_UPDATE_SEEDING_LEECHING_TIME_HANDLE_JOB], commonRequestId: %s, beginUid: %s, endUid: %s", $this->requestId, $this->beginUid, $this->endUid); $logPrefix = sprintf(
"[CLEANUP_CLI_UPDATE_SEEDING_LEECHING_TIME_HANDLE_JOB], commonRequestId: %s, beginUid: %s, endUid: %s, idStr: %s, idRedisKey: %s",
$this->requestId, $this->beginUid, $this->endUid, $this->idStr, $this->idRedisKey,
);
do_log("$logPrefix, job start ...");
$count = 0;
$idStr = $this->idStr; $idStr = $this->idStr;
$delIdRedisKey = false; $delIdRedisKey = false;
if (empty($idStr) && !empty($this->idRedisKey)) { if (empty($idStr) && !empty($this->idRedisKey)) {
@@ -76,33 +90,35 @@ class UpdateUserSeedingLeechingTime implements ShouldQueue
do_log("$logPrefix, no idStr or idRedisKey", "error"); do_log("$logPrefix, no idStr or idRedisKey", "error");
return; return;
} }
$uidArr = explode(",", $idStr); //批量取,简单化
foreach ($uidArr as $uid) { // $res = sql_query("select userid, sum(seedtime) as seedtime_sum, sum(leechtime) as leechtime_sum from snatched group by userid where userid in ($idStr)");
if ($uid <= 0) { $res = NexusDB::table("snatched")
continue; ->selectRaw("userid, sum(seedtime) as seedtime_sum, sum(leechtime) as leechtime_sum")
} ->whereRaw("userid in ($idStr)")
$sumInfo = NexusDB::table('snatched') ->groupBy("userid")
->selectRaw('sum(seedtime) as seedtime_sum, sum(leechtime) as leechtime_sum') ->get();
->where('userid', $uid) $seedtimeUpdates = $leechTimeUpdates = [];
->first(); $nowStr = now()->toDateTimeString();
if ($sumInfo && $sumInfo->seedtime_sum !== null) { $count = 0;
$update = [ foreach ($res as $row) {
'seedtime' => $sumInfo->seedtime_sum ?? 0, $count++;
'leechtime' => $sumInfo->leechtime_sum ?? 0, $seedtimeUpdates = sprintf("when %d then %d", $row->userid, $row->seedtime_sum ?? 0);
'seed_time_updated_at' => Carbon::now()->toDateTimeString(), $leechTimeUpdates = sprintf("when %d then %d", $row->userid, $row->leechtime_sum ?? 0);
];
NexusDB::table('users')
->where('id', $uid)
->update($update);
do_log("[CLEANUP_CLI_UPDATE_SEEDING_LEECHING_TIME_HANDLE_USER], [SUCCESS]: $uid => " . json_encode($update));
$count++;
}
} }
$sql = sprintf(
"update users set seedtime = case id %s end, leechtime = case id %s end, seed_time_updated_at = '%s' where id in (%s)",
implode(" ", $seedtimeUpdates), implode(" ", $leechTimeUpdates), $nowStr, $idStr
);
$result = NexusDB::statement($sql);
if ($delIdRedisKey) { if ($delIdRedisKey) {
NexusDB::cache_del($this->idRedisKey); NexusDB::cache_del($this->idRedisKey);
} }
$costTime = time() - $beginTimestamp; $costTime = time() - $beginTimestamp;
do_log("$logPrefix, [DONE], user total count: " . count($uidArr) . ", success update count: $count, cost time: $costTime seconds"); do_log(sprintf(
"$logPrefix, [DONE], update user count: %s, result: %s, cost time: %s seconds",
$count, var_export($result, true), $costTime
));
do_log("$logPrefix, sql: $sql", "debug");
} }
/** /**
+2 -1
View File
@@ -184,7 +184,8 @@ class User extends Authenticatable implements FilamentUser, HasName
protected $fillable = [ protected $fillable = [
'username', 'email', 'passhash', 'secret', 'stylesheet', 'editsecret', 'added', 'modcomment', 'enabled', 'status', 'username', 'email', 'passhash', 'secret', 'stylesheet', 'editsecret', 'added', 'modcomment', 'enabled', 'status',
'leechwarn', 'leechwarnuntil', 'page', 'class', 'uploaded', 'downloaded', 'clientselect', 'showclienterror', 'last_home', 'leechwarn', 'leechwarnuntil', 'page', 'class', 'uploaded', 'downloaded', 'clientselect', 'showclienterror', 'last_home',
'seedbonus', 'bonuscomment', 'downloadpos', 'vip_added', 'vip_until', 'title', 'invites', 'attendance_card', 'seed_points_per_hour' 'seedbonus', 'bonuscomment', 'downloadpos', 'vip_added', 'vip_until', 'title', 'invites', 'attendance_card',
'seed_points_per_hour', 'passkey',
]; ];
/** /**
+5 -1
View File
@@ -6,6 +6,7 @@ use App\Http\Middleware\Locale;
use Carbon\Carbon; use Carbon\Carbon;
use Illuminate\Support\Facades\App; use Illuminate\Support\Facades\App;
use Illuminate\Support\Facades\DB; use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\URL;
use Illuminate\Support\Facades\View; use Illuminate\Support\Facades\View;
use Illuminate\Support\ServiceProvider; use Illuminate\Support\ServiceProvider;
use Illuminate\Http\Resources\Json\JsonResource; use Illuminate\Http\Resources\Json\JsonResource;
@@ -37,8 +38,11 @@ class AppServiceProvider extends ServiceProvider
{ {
global $plugin; global $plugin;
$plugin->start(); $plugin->start();
// JsonResource::withoutWrapping();
DB::connection(config('database.default'))->enableQueryLog(); DB::connection(config('database.default'))->enableQueryLog();
$forceScheme = strtolower(env('FORCE_SCHEME'));
if (env('APP_ENV') == "production" && in_array($forceScheme, ['https', 'http'])) {
URL::forceScheme($forceScheme);
}
Filament::serving(function () { Filament::serving(function () {
Filament::registerNavigationGroups([ Filament::registerNavigationGroups([
+4 -1
View File
@@ -169,7 +169,10 @@ for k, v in pairs(batchList) do
local isBatchKeyNew = false local isBatchKeyNew = false
if batchKey == false then if batchKey == false then
batchKey = v .. ":" .. ARGV[4] batchKey = v .. ":" .. ARGV[4]
redis.call("SET", v, batchKey, "EX", ARGV[5]) redis.call("SET", v, batchKey)
if (k > 1) then
redis.call("EXPIRE", v, ARGV[5])
end
isBatchKeyNew = true isBatchKeyNew = true
end end
local hashKey local hashKey
+11 -2
View File
@@ -9,6 +9,7 @@ use App\Models\User;
use Carbon\Carbon; use Carbon\Carbon;
use Filament\Facades\Filament; use Filament\Facades\Filament;
use Illuminate\Support\Facades\DB; use Illuminate\Support\Facades\DB;
use Nexus\Database\NexusDB;
class DashboardRepository extends BaseRepository class DashboardRepository extends BaseRepository
{ {
@@ -51,18 +52,26 @@ class DashboardRepository extends BaseRepository
'text' => nexus_trans("dashboard.system_info.$name"), 'text' => nexus_trans("dashboard.system_info.$name"),
'value' => DB::select(DB::raw('select version() as info'))[0]->info, 'value' => DB::select(DB::raw('select version() as info'))[0]->info,
]; ];
$name = 'os'; // $name = 'os';
// $result[$name] = [
// 'name' => $name,
// 'text' => nexus_trans("dashboard.system_info.$name"),
// 'value' => PHP_OS,
// ];
$name = 'redis_version';
$result[$name] = [ $result[$name] = [
'name' => $name, 'name' => $name,
'text' => nexus_trans("dashboard.system_info.$name"), 'text' => nexus_trans("dashboard.system_info.$name"),
'value' => PHP_OS, 'value' => NexusDB::redis()->info()['redis_version'],
]; ];
$name = 'server_software'; $name = 'server_software';
$result[$name] = [ $result[$name] = [
'name' => $name, 'name' => $name,
'text' => nexus_trans("dashboard.system_info.$name"), 'text' => nexus_trans("dashboard.system_info.$name"),
'value' => $_SERVER['SERVER_SOFTWARE'] ?? '', 'value' => $_SERVER['SERVER_SOFTWARE'] ?? '',
]; ];
$name = 'load_average'; $name = 'load_average';
$result[$name] = [ $result[$name] = [
'name' => $name, 'name' => $name,
-28
View File
@@ -1327,32 +1327,4 @@ class ExamRepository extends BaseRepository
return $result; return $result;
} }
public function fixIndexUploadTorrentCount()
{
$page = 1;
$size = 2000;
$examUserTable = (new ExamUser())->getTable();
$examProgressTable = (new ExamProgress())->getTable();
while (true) {
$offset = ($page - 1)*$size;
$list = NexusDB::table($examProgressTable)
->select("$examProgressTable.*, $examUserTable.created_at as exam_created_at")
->join($examUserTable, "$examProgressTable.exam_user_id", "=", "$examUserTable.id", "left")
->where("$examUserTable.status", ExamUser::STATUS_NORMAL)
->where("$examProgressTable.index", Exam::INDEX_UPLOAD_TORRENT_COUNT)
->limit($size)
->offset($offset)
->get()
;
if ($list->count() == 0) {
do_log("page: $page, offset: $offset, no more data...");
return;
}
foreach ($list as $item) {
}
}
}
} }
+2
View File
@@ -34,6 +34,7 @@ class SeedBoxRepository extends BaseRepository
$params = $this->formatParams($params); $params = $this->formatParams($params);
$seedBoxRecord = SeedBoxRecord::query()->create($params); $seedBoxRecord = SeedBoxRecord::query()->create($params);
$this->clearCache(); $this->clearCache();
publish_model_event("seed_box_record_created", $seedBoxRecord->id);
return $seedBoxRecord; return $seedBoxRecord;
} }
@@ -85,6 +86,7 @@ class SeedBoxRepository extends BaseRepository
$params = $this->formatParams($params); $params = $this->formatParams($params);
$model->update($params); $model->update($params);
$this->clearCache(); $this->clearCache();
publish_model_event("seed_box_record_updated", $id);
return $model; return $model;
} }
+22
View File
@@ -1,6 +1,7 @@
<?php <?php
namespace App\Repositories; namespace App\Repositories;
use App\Http\Middleware\Locale;
use App\Models\Invite; use App\Models\Invite;
use App\Models\Message; use App\Models\Message;
use App\Models\News; use App\Models\News;
@@ -503,4 +504,25 @@ class ToolRepository extends BaseRepository
} }
} }
} }
public function sendAlarmEmail(string $subjectTransKey, array $subjectTransContext, string $msgTransKey, array $msgTransContext): void
{
$receiverUid = get_setting("system.alarm_email_receiver");
if (empty($receiverUid)) {
$locale = Locale::getDefault();
$subject = nexus_trans($subjectTransKey, $subjectTransContext, $locale);
$msg = nexus_trans($msgTransKey, $msgTransContext, $locale);
do_log(sprintf("%s - %s", $subject, $msg), "error");
} else {
$receiverUidArr = preg_split("/[\r\n\s,]+/", $receiverUid);
$users = User::query()->whereIn("id", $receiverUidArr)->get(User::$commonFields);
foreach ($users as $user) {
$locale = $user->locale;
$subject = nexus_trans($subjectTransKey, $subjectTransContext, $locale);
$msg = nexus_trans($msgTransKey, $msgTransContext, $locale);
$result = $this->sendMail($user->email, $subject, $msg);
do_log(sprintf("send msg: %s result: %s", $msg, var_export($result, true)), $result ? "info" : "error");
}
}
}
} }
+106 -7
View File
@@ -36,13 +36,23 @@ use Illuminate\Support\Str;
use Nexus\Database\NexusDB; use Nexus\Database\NexusDB;
use Nexus\Imdb\Imdb; use Nexus\Imdb\Imdb;
use Rhilip\Bencode\Bencode; use Rhilip\Bencode\Bencode;
use Firebase\JWT\JWT;
use Firebase\JWT\Key;
class TorrentRepository extends BaseRepository class TorrentRepository extends BaseRepository
{ {
const BOUGHT_USER_CACHE_KEY_PREFIX = "torrent_purchasers:"; const BOUGHT_USER_CACHE_KEY_PREFIX = "torrent_purchasers";
const BUY_FAIL_CACHE_KEY_PREFIX = "torrent_purchase_fails";
const PIECES_HASH_CACHE_KEY = "torrent_pieces_hash"; const PIECES_HASH_CACHE_KEY = "torrent_pieces_hash";
const BUY_STATUS_SUCCESS = 0;
const BUY_STATUS_NOT_YET = -1;
const BUY_STATUS_UNKNOWN = -2;
/** /**
* fetch torrent list * fetch torrent list
* *
@@ -334,13 +344,23 @@ class TorrentRepository extends BaseRepository
public function encryptDownHash($id, $user): string public function encryptDownHash($id, $user): string
{ {
$key = $this->getEncryptDownHashKey($user); $key = $this->getEncryptDownHashKey($user);
return (new Hashids($key))->encode($id); $payload = [
'id' => $id,
'exp' => time() + 3600
];
return JWT::encode($payload, $key, 'HS256');
} }
public function decryptDownHash($downHash, $user) public function decryptDownHash($downHash, $user)
{ {
$key = $this->getEncryptDownHashKey($user); $key = $this->getEncryptDownHashKey($user);
return (new Hashids($key))->decode($downHash); try {
$decoded = JWT::decode($downHash, new Key($key, 'HS256'));
return [$decoded->id];
} catch (\Exception $e) {
do_log("Invalid down hash: $downHash, " . $e->getMessage(), "error");
return '';
}
} }
private function getEncryptDownHashKey($user) private function getEncryptDownHashKey($user)
@@ -752,15 +772,94 @@ HTML;
return $total; return $total;
} }
public function addBoughtUserToCache($torrentId, $uid) /**
* 购买成功缓存,保存为 hash,一个种子一个 hash,永久有效
* @param $uid
* @param $torrentId
* @return void
* @throws \RedisException
*/
public function addBuySuccessCache($uid, $torrentId): void
{ {
NexusDB::redis()->hSet($this->getBoughtUserCacheKey($torrentId), $uid, 1); NexusDB::redis()->hSet($this->getBoughtUserCacheKey($torrentId), $uid, 1);
} }
public function hasBuySuccessCache($uid, $torrentId): bool
private function getBoughtUserCacheKey($torrentId): string
{ {
return self::BOUGHT_USER_CACHE_KEY_PREFIX . $torrentId; return NexusDB::redis()->hGet($this->getBoughtUserCacheKey($torrentId), $uid) == 1;
}
/**
* 获取购买种子的缓存状态
*
* @param $uid
* @param $torrentId
* @return int
*/
public function getBuyStatus($uid, $torrentId): int
{
//查询是否已经购买
if ($this->hasBuySuccessCache($uid, $torrentId)) {
return self::BUY_STATUS_SUCCESS;
}
//是否购买失败过
$buyFailCount = $this->getBuyFailCache($uid, $torrentId);
if ($buyFailCount > 0) {
//根据失败次数,禁用下载权限并做提示等
return $buyFailCount;
}
//不是成功或失败,直接返回未知
return self::BUY_STATUS_UNKNOWN;
}
/**
* 添加购买失败缓存, 结果累加
* @param $uid
* @param $torrentId
* @return void
* @throws \RedisException
*/
public function addBuyFailCache($uid, $torrentId): void
{
$key = $this->getBuyFailCacheKey($uid, $torrentId);
$result = NexusDB::redis()->incr($key);
if ($result == 1) {
NexusDB::redis()->expire($key, 3600);
}
}
/**
* 获取失败缓存 ,结果是失败的次数
*
* @param $uid
* @param $torrentId
* @return int
* @throws \RedisException
*/
public function getBuyFailCache($uid, $torrentId): int
{
return intval(NexusDB::redis()->get($this->getBuyFailCacheKey($uid, $torrentId)));
}
/**
* 购买成功缓存 key
* @param $torrentId
* @return string
*/
public function getBoughtUserCacheKey($torrentId): string
{
return sprintf("%s:%s", self::BOUGHT_USER_CACHE_KEY_PREFIX, $torrentId);
}
/**
* 购买失败缓存 key
* @param int $userId
* @param int $torrentId
* @return string
*/
public function getBuyFailCacheKey(int $userId, int $torrentId): string
{
return sprintf("%s:%s:%s", self::BUY_FAIL_CACHE_KEY_PREFIX, $userId, $torrentId);
} }
public function addPiecesHashCache(int $torrentId, string $piecesHash): bool|int|\Redis public function addPiecesHashCache(int $torrentId, string $piecesHash): bool|int|\Redis
+3 -2
View File
@@ -132,7 +132,8 @@ class UserRepository extends BaseRepository
'stylesheet' => $setting['defstylesheet'], 'stylesheet' => $setting['defstylesheet'],
'added' => now()->toDateTimeString(), 'added' => now()->toDateTimeString(),
'status' => User::STATUS_CONFIRMED, 'status' => User::STATUS_CONFIRMED,
'class' => $class 'class' => $class,
'passkey' => md5($username.date("Y-m-d H:i:s").$passhash)
]; ];
$user = new User($data); $user = new User($data);
if (!empty($params['id'])) { if (!empty($params['id'])) {
@@ -143,7 +144,7 @@ class UserRepository extends BaseRepository
$user->id = $params['id']; $user->id = $params['id'];
} }
$user->save(); $user->save();
fire_event("user_created", $user);
return $user; return $user;
} }
+85
View File
@@ -0,0 +1,85 @@
<?php
namespace App\Utils;
use Nexus\Database\NexusDB;
final class MsgAlert {
private static ?self $instance = null;
private static array $alerts = [];
private string $redisKeyPrefix = "nexus_alerts";
private function __construct()
{
$redis = NexusDB::redis();
$result = $redis->lRange($this->getListKey(), 0, 10);
if (!empty($result)) {
$nowTimestamp = time();
$valid = [];
foreach ($result as $item) {
$arr = json_decode($item, true);
if (is_array($arr) && $arr['deadline'] > $nowTimestamp) {
$valid[$arr['name']] = $arr;
} else {
$redis->lRem($this->getListKey(), $item, 0);
}
}
self::$alerts = $valid;
}
}
private function __clone()
{
}
public static function getInstance(): MsgAlert
{
if (isset(self::$instance)) {
return self::$instance;
}
return self::$instance = new self;
}
public function add(string $name, int $deadline, string $text, string $url = "", string $color = "red"): void
{
if (!isset(self::$alerts[$name])) {
$params = compact('name', 'deadline', 'text', 'url', 'color');
self::$alerts[$name] = $params;
NexusDB::redis()->rPush($this->getListKey(), json_encode($params));
}
}
private function getListKey(): string
{
return sprintf("%s:%s", $this->redisKeyPrefix, get_user_id());
}
public static function render(): void
{
$nowTimestamp = time();
foreach (self::$alerts as $item) {
if ($item['deadline'] > $nowTimestamp) {
msgalert($item['url'] ?: '', $item['text'], $item['color'] ?: 'red');
}
}
}
public function remove($name): void
{
foreach (self::$alerts as $item) {
if ($item['name'] = $name) {
unset(self::$alerts[$name]);
NexusDB::redis()->lRem($this->getListKey(), json_encode($item));
}
}
}
}
+70
View File
@@ -0,0 +1,70 @@
<?php
namespace App\Utils;
use App\Jobs\BuyTorrent;
use http\Exception\InvalidArgumentException;
use Illuminate\Support\Facades\Queue;
use Nexus\Database\NexusDB;
use Nexus\Database\NexusLock;
final class ThirdPartyJob {
private static string $queueKey = "nexus_third_party_job";
private static int $size = 20;
const JOB_BUY_TORRENT = "buyTorrent";
public function __invoke(): void
{
$lockName = convertNamespaceToSnake(__METHOD__);
$lock = new NexusLock($lockName, 600);
if (!$lock->get()) {
do_log("can not get lock: $lockName, return ...");
return;
}
$list = NexusDB::redis()->lRange(self::$queueKey, 0, self::$size);
$successCount = 0;
foreach ($list as $item) {
$data = json_decode($item, true);
if (!empty($data['name'])) {
$successCount++;
match ($data['name']) {
self::JOB_BUY_TORRENT => self::enqueueJobBuyTorrent($data),
default => throw new InvalidArgumentException("invalid name: {$data['name']}")
};
} else {
do_log(sprintf("%s no name, skip", $item), "error");
}
NexusDB::redis()->lRem(self::$queueKey, $item);
}
do_log(sprintf("success dispatch %s jobs", $successCount));
$lock->release();
}
public static function addBuyTorrent(int $userId, int $torrentId): void
{
$key = sprintf("%s:%s_%s", self::$queueKey, $userId, $torrentId);
if (NexusDB::redis()->set($key, now()->toDateTimeString(), ['nx', 'ex' => 3600])) {
$value = [
'name' => self::JOB_BUY_TORRENT,
'userId' => $userId,
'torrentId' => $torrentId,
];
NexusDB::redis()->rPush(self::$queueKey, json_encode($value));
do_log("success addBuyTorrent: $key", "debug");
} else {
do_log("no need to addBuyTorrent: $key", "debug");
}
}
private static function enqueueJobBuyTorrent(array $params): void
{
if (!empty($params['userId']) && !empty($params['torrentId'])) {
$job = new BuyTorrent($params['userId'], $params['torrentId']);
Queue::push($job);
} else {
do_log("no userId or torrentId: " . json_encode($params), "error");
}
}
}
+1 -1
View File
@@ -42,7 +42,7 @@
"hashids/hashids": "^4.1", "hashids/hashids": "^4.1",
"imdbphp/imdbphp": "^7.0", "imdbphp/imdbphp": "^7.0",
"irazasyed/telegram-bot-sdk": "^3.11", "irazasyed/telegram-bot-sdk": "^3.11",
"laravel/framework": "9.52.4", "laravel/framework": "v9.52.17",
"laravel/octane": "^1.2", "laravel/octane": "^1.2",
"laravel/passport": "^11.10", "laravel/passport": "^11.10",
"laravel/sanctum": "^2.10", "laravel/sanctum": "^2.10",
Generated
+8 -8
View File
@@ -4,7 +4,7 @@
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
"This file is @generated automatically" "This file is @generated automatically"
], ],
"content-hash": "2b89de67bf5d41d008100e25d21303b0", "content-hash": "546ab4accfd6fa5ec14eeadfbc14e573",
"packages": [ "packages": [
{ {
"name": "akaunting/laravel-money", "name": "akaunting/laravel-money",
@@ -3189,16 +3189,16 @@
}, },
{ {
"name": "laravel/framework", "name": "laravel/framework",
"version": "v9.52.4", "version": "v9.52.17",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/laravel/framework.git", "url": "https://github.com/laravel/framework.git",
"reference": "9239128cfb4d22afefb64060dfecf53e82987267" "reference": "a069cf17e4943fb88d2a91c92690004fb3236dab"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/laravel/framework/zipball/9239128cfb4d22afefb64060dfecf53e82987267", "url": "https://api.github.com/repos/laravel/framework/zipball/a069cf17e4943fb88d2a91c92690004fb3236dab",
"reference": "9239128cfb4d22afefb64060dfecf53e82987267", "reference": "a069cf17e4943fb88d2a91c92690004fb3236dab",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
@@ -3295,7 +3295,7 @@
"league/flysystem-read-only": "^3.3", "league/flysystem-read-only": "^3.3",
"league/flysystem-sftp-v3": "^3.0", "league/flysystem-sftp-v3": "^3.0",
"mockery/mockery": "^1.5.1", "mockery/mockery": "^1.5.1",
"orchestra/testbench-core": "^7.16", "orchestra/testbench-core": "^7.24",
"pda/pheanstalk": "^4.0", "pda/pheanstalk": "^4.0",
"phpstan/phpdoc-parser": "^1.15", "phpstan/phpdoc-parser": "^1.15",
"phpstan/phpstan": "^1.4.7", "phpstan/phpstan": "^1.4.7",
@@ -3383,7 +3383,7 @@
"issues": "https://github.com/laravel/framework/issues", "issues": "https://github.com/laravel/framework/issues",
"source": "https://github.com/laravel/framework" "source": "https://github.com/laravel/framework"
}, },
"time": "2023-02-22T14:38:06+00:00" "time": "2024-11-12T15:39:14+00:00"
}, },
{ {
"name": "laravel/octane", "name": "laravel/octane",
@@ -13996,6 +13996,6 @@
"ext-xml": "*", "ext-xml": "*",
"ext-zend-opcache": "*" "ext-zend-opcache": "*"
}, },
"platform-dev": [], "platform-dev": {},
"plugin-api-version": "2.6.0" "plugin-api-version": "2.6.0"
} }
@@ -0,0 +1,29 @@
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
return new class extends Migration
{
/**
* Run the migrations.
*
* @return void
*/
public function up()
{
$sql = 'ALTER table torrents MODIFY column `info_hash` binary(20) DEFAULT NULL';
\Illuminate\Support\Facades\DB::statement($sql);
}
/**
* Reverse the migrations.
*
* @return void
*/
public function down()
{
//
}
};
+2 -2
View File
@@ -1,6 +1,6 @@
<?php <?php
defined('VERSION_NUMBER') || define('VERSION_NUMBER', '1.8.13'); defined('VERSION_NUMBER') || define('VERSION_NUMBER', '1.8.14');
defined('RELEASE_DATE') || define('RELEASE_DATE', '2024-08-28'); defined('RELEASE_DATE') || define('RELEASE_DATE', '2024-11-08');
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");
+12 -6
View File
@@ -818,7 +818,7 @@ function closeall() {
tagRemove = popstack(bbtags) tagRemove = popstack(bbtags)
if ( (tagRemove != 'color') ) { if ( (tagRemove != 'color') ) {
doInsert("[/"+tagRemove+"]", "", false); doInsert("[/"+tagRemove+"]", "", false);
eval("document.<?php echo $form?>." + tagRemove + ".value = ' " + tagRemove + " '"); eval("document.<?php echo $form?>." + tagRemove + ".value = ' " + tagRemove.toUpperCase() + " '");
eval(tagRemove + "_open = 0"); eval(tagRemove + "_open = 0");
} else { } else {
doInsert("[/"+tagRemove+"]", "", false); doInsert("[/"+tagRemove+"]", "", false);
@@ -2798,6 +2798,8 @@ if ($msgalert)
$text = $lang_functions['text_you_have'].$unread.$lang_functions['text_new_message'] . add_s($unread) . $lang_functions['text_click_here_to_read']; $text = $lang_functions['text_you_have'].$unread.$lang_functions['text_new_message'] . add_s($unread) . $lang_functions['text_click_here_to_read'];
msgalert("messages.php",$text, "red"); msgalert("messages.php",$text, "red");
} }
\App\Utils\MsgAlert::getInstance()->render();
/* /*
$pending_invitee = $Cache->get_value('user_'.$CURUSER["id"].'_pending_invitee_count'); $pending_invitee = $Cache->get_value('user_'.$CURUSER["id"].'_pending_invitee_count');
if ($pending_invitee == ""){ if ($pending_invitee == ""){
@@ -3280,7 +3282,7 @@ function commenttable($rows, $type, $parent_id, $review = false)
$dt = sqlesc(date("Y-m-d H:i:s",(TIMENOW - $secs))); // calculate date. $dt = sqlesc(date("Y-m-d H:i:s",(TIMENOW - $secs))); // calculate date.
print("<tr>\n"); print("<tr>\n");
print("<td class=\"rowfollow\" width=\"150\" valign=\"top\" style=\"padding: 0px;\">".return_avatar_image($avatar)."</td>\n"); print("<td class=\"rowfollow\" width=\"150\" valign=\"top\" style=\"padding: 0px;\">".return_avatar_image($avatar)."</td>\n");
print("<td class=\"rowfollow\" valign=\"top\"><br />".$text.$text_editby."</td>\n"); print("<td class=\"rowfollow word-break-all\" valign=\"top\"><br />".$text.$text_editby."</td>\n");
print("</tr>\n"); print("</tr>\n");
$actionbar = "<a href=\"comment.php?action=add&amp;sub=quote&amp;cid=".$row['id']."&amp;pid=".$parent_id."&amp;type=".$type."\"><img class=\"f_quote\" src=\"pic/trans.gif\" alt=\"Quote\" title=\"".$lang_functions['title_reply_with_quote']."\" /></a>". $actionbar = "<a href=\"comment.php?action=add&amp;sub=quote&amp;cid=".$row['id']."&amp;pid=".$parent_id."&amp;type=".$type."\"><img class=\"f_quote\" src=\"pic/trans.gif\" alt=\"Quote\" title=\"".$lang_functions['title_reply_with_quote']."\" /></a>".
"<a href=\"comment.php?action=add&amp;pid=".$parent_id."&amp;type=".$type."\"><img class=\"f_reply\" src=\"pic/trans.gif\" alt=\"Add Reply\" title=\"".$lang_functions['title_add_reply']."\" /></a>".(user_can('commanage') ? "<a href=\"comment.php?action=delete&amp;cid=".$row['id']."&amp;type=".$type."\"><img class=\"f_delete\" src=\"pic/trans.gif\" alt=\"Delete\" title=\"".$lang_functions['title_delete']."\" /></a>" : "").($row["user"] == $CURUSER["id"] || get_user_class() >= $commanage_class ? "<a href=\"comment.php?action=edit&amp;cid=".$row['id']."&amp;type=".$type."\"><img class=\"f_edit\" src=\"pic/trans.gif\" alt=\"Edit\" title=\"".$lang_functions['title_edit']."\" />"."</a>" : ""); "<a href=\"comment.php?action=add&amp;pid=".$parent_id."&amp;type=".$type."\"><img class=\"f_reply\" src=\"pic/trans.gif\" alt=\"Add Reply\" title=\"".$lang_functions['title_add_reply']."\" /></a>".(user_can('commanage') ? "<a href=\"comment.php?action=delete&amp;cid=".$row['id']."&amp;type=".$type."\"><img class=\"f_delete\" src=\"pic/trans.gif\" alt=\"Delete\" title=\"".$lang_functions['title_delete']."\" /></a>" : "").($row["user"] == $CURUSER["id"] || get_user_class() >= $commanage_class ? "<a href=\"comment.php?action=edit&amp;cid=".$row['id']."&amp;type=".$type."\"><img class=\"f_edit\" src=\"pic/trans.gif\" alt=\"Edit\" title=\"".$lang_functions['title_edit']."\" />"."</a>" : "");
@@ -5319,7 +5321,7 @@ function torrentTags($tags = 0, $type = 'checkbox')
return $html; return $html;
} }
function saveSetting($prefix, $nameAndValue, $autoload = 'yes') function saveSetting(string $prefix, array $nameAndValue, string $autoload = 'yes'): void
{ {
$prefix = strtolower($prefix); $prefix = strtolower($prefix);
$datetimeNow = date('Y-m-d H:i:s'); $datetimeNow = date('Y-m-d H:i:s');
@@ -5907,7 +5909,11 @@ function get_ip_location_from_geoip($ip): bool|array
function msgalert($url, $text, $bgcolor = "red") function msgalert($url, $text, $bgcolor = "red")
{ {
print("<table border=\"0\" cellspacing=\"0\" cellpadding=\"10\"><tr><td style='border: none; padding: 10px; background: ".$bgcolor."'>\n"); print("<table border=\"0\" cellspacing=\"0\" cellpadding=\"10\"><tr><td style='border: none; padding: 10px; background: ".$bgcolor."'>\n");
print("<b><a href=\"".$url."\" target='_blank'><font color=\"white\">".$text."</font></a></b>"); if (!empty($url)) {
print("<b><a href=\"".$url."\" target='_blank'><font color=\"white\">".$text."</font></a></b>");
} else {
print("<b><font color=\"white\">".$text."</font></b>");
}
print("</td></tr></table><br />"); print("</td></tr></table><br />");
} }
@@ -6078,7 +6084,7 @@ function calculate_seed_bonus($uid, $torrentIdArr = null): array
do_log(sprintf( do_log(sprintf(
"$logPrefix, torrent: %s, peer ID: %s, weeks: %s, size_raw: %s GB, size: %s GB, increase A: %s, increase official A: %s", "$logPrefix, torrent: %s, peer ID: %s, weeks: %s, size_raw: %s GB, size: %s GB, increase A: %s, increase official A: %s",
$torrent['id'], $torrent['peerID'], $weeks_alive, $gb_size_raw, $gb_size, $temp, $officialAIncrease $torrent['id'], $torrent['peerID'], $weeks_alive, $gb_size_raw, $gb_size, $temp, $officialAIncrease
)); ), "debug");
} }
if ($count > $maxseeding_bonus) if ($count > $maxseeding_bonus)
$count = $maxseeding_bonus; $count = $maxseeding_bonus;
@@ -6315,7 +6321,7 @@ function build_bonus_table(array $user, array $bonusResult = [], array $options
$isDonor = is_donor($user); $isDonor = is_donor($user);
$donortimes_bonus = get_setting('bonus.donortimes'); $donortimes_bonus = get_setting('bonus.donortimes');
$baseBonusFactor = 1; $baseBonusFactor = 1;
if ($isDonor) { if ($isDonor && $donortimes_bonus != 0) {
$baseBonusFactor = $donortimes_bonus; $baseBonusFactor = $donortimes_bonus;
} }
$baseBonus = $bonusResult['seed_bonus'] * $baseBonusFactor; $baseBonus = $bonusResult['seed_bonus'] * $baseBonusFactor;
+33 -3
View File
@@ -788,6 +788,15 @@ function get_user_id()
return auth()->user()->id ?? 0; return auth()->user()->id ?? 0;
} }
function get_user_passkey()
{
if (IN_NEXUS) {
global $CURUSER;
return $CURUSER["passkey"] ?? "";
}
return auth()->user()->passkey ?? "";
}
function get_pure_username() function get_pure_username()
{ {
if (IN_NEXUS) { if (IN_NEXUS) {
@@ -928,13 +937,13 @@ function getDataTraffic(array $torrent, array $queries, array $user, $peer, $sna
} }
$uploaderRatio = get_setting('torrent.uploaderdouble'); $uploaderRatio = get_setting('torrent.uploaderdouble');
$log .= ", uploaderRatio: $uploaderRatio"; $log .= ", uploaderRatio: $uploaderRatio";
if ($torrent['owner'] == $user['id']) { if ($torrent['owner'] == $user['id'] && $uploaderRatio != 1) {
//uploader, use the bigger one //uploader, use the bigger one
$upRatio = max($uploaderRatio, \App\Models\Torrent::$promotionTypes[$spStateReal]['up_multiplier']); $upRatio = max($uploaderRatio, \App\Models\Torrent::$promotionTypes[$spStateReal]['up_multiplier']);
$log .= ", [IS_UPLOADER], upRatio: $upRatio"; $log .= ", [IS_UPLOADER] && uploaderRatio != 1, upRatio: $upRatio";
} else { } else {
$upRatio = \App\Models\Torrent::$promotionTypes[$spStateReal]['up_multiplier']; $upRatio = \App\Models\Torrent::$promotionTypes[$spStateReal]['up_multiplier'];
$log .= ", [IS_NOT_UPLOADER], upRatio: $upRatio"; $log .= ", [IS_NOT_UPLOADER] || uploaderRatio == 1, upRatio: $upRatio";
} }
/** /**
* VIP do not calculate downloaded * VIP do not calculate downloaded
@@ -1238,6 +1247,9 @@ function get_snatch_info($torrentId, $userId)
return mysql_fetch_assoc(sql_query(sprintf('select * from snatched where torrentid = %s and userid = %s order by id desc limit 1', $torrentId, $userId))); return mysql_fetch_assoc(sql_query(sprintf('select * from snatched where torrentid = %s and userid = %s order by id desc limit 1', $torrentId, $userId)));
} }
/**
* 完整的 Laravel 事件, 在 php 端有监听者的需要触发. 同样会执行 publish_model_event()
*/
function fire_event(string $name, \Illuminate\Database\Eloquent\Model $model, \Illuminate\Database\Eloquent\Model $oldModel = null): void function fire_event(string $name, \Illuminate\Database\Eloquent\Model $model, \Illuminate\Database\Eloquent\Model $oldModel = null): void
{ {
$prefix = "fire_event:"; $prefix = "fire_event:";
@@ -1250,3 +1262,21 @@ function fire_event(string $name, \Illuminate\Database\Eloquent\Model $model, \I
} }
executeCommand("event:fire --name=$name --idKey=$idKey --idKeyOld=$idKeyOld", "string", true, false); executeCommand("event:fire --name=$name --idKey=$idKey --idKeyOld=$idKeyOld", "string", true, false);
} }
/**
* 仅仅是往 redis 发布事件, php 端无监听者仅在其他平台有需要的触发这个即可, 较轻量
*/
function publish_model_event(string $event, int $id): void
{
$channel = nexus_env("CHANNEL_NAME_MODEL_EVENT");
if (!empty($channel)) {
\Nexus\Database\NexusDB::redis()->publish($channel, json_encode(["event" => $event, "id" => $id]));
} else {
do_log("event: $event, id: $id, channel: $channel, channel is empty!", "error");
}
}
function convertNamespaceToSnake(string $str): string
{
return str_replace(["\\", "::"], ["_", "."], $str);
}
+1
View File
@@ -208,6 +208,7 @@ $lang_details = array
'text_creator' => "主創: ", 'text_creator' => "主創: ",
'submit_search_at_shooter' => "搜索射手網", 'submit_search_at_shooter' => "搜索射手網",
'submit_search_at_opensubtitles' => "搜索Opensubtitles", 'submit_search_at_opensubtitles' => "搜索Opensubtitles",
'title_show_or_hide' => "顯示&nbsp;或&nbsp;隱藏",
'title_bookmark' => "收藏", 'title_bookmark' => "收藏",
'text_album_information' => "專輯資訊:", 'text_album_information' => "專輯資訊:",
'text_about_album' => "關于該專輯:", 'text_about_album' => "關于該專輯:",
+2 -2
View File
@@ -12,8 +12,8 @@ class DBMysqli implements DBInterface
if (mysqli_connect_errno()) { if (mysqli_connect_errno()) {
throw new DatabaseException(mysqli_connect_error()); throw new DatabaseException(mysqli_connect_error());
} }
$mysqli->query("SET NAMES UTF8"); $mysqli->set_charset("utf8mb4");
$mysqli->query("SET collation_connection = 'utf8_general_ci'"); $mysqli->query("SET collation_connection = 'utf8mb4_unicode_ci'");
$mysqli->query("SET sql_mode=''"); $mysqli->query("SET sql_mode=''");
$mysqli->query("SET time_zone='".date('P')."'"); $mysqli->query("SET time_zone='".date('P')."'");
-9
View File
@@ -332,15 +332,6 @@ class Update extends Install
["value" => User::query()->where("class", User::CLASS_STAFF_LEADER)->first(["id"])->id] ["value" => User::query()->where("class", User::CLASS_STAFF_LEADER)->first(["id"])->id]
); );
} }
/**
* @since 1.8.13
*/
$settingName = "__has_fix_exam_index_UPLOAD_TORRENT_COUNT";
$hasFixExamIndexUploadTorrentCount = get_setting($settingName, false);
if (!$hasFixExamIndexUploadTorrentCount) {
}
} }
public function runExtraMigrate() public function runExtraMigrate()
+15 -2
View File
@@ -2,9 +2,7 @@
namespace Nexus\Plugin; namespace Nexus\Plugin;
use App\Repositories\BaseRepository; use App\Repositories\BaseRepository;
use Illuminate\Support\Arr;
use Illuminate\Support\Facades\Artisan; use Illuminate\Support\Facades\Artisan;
use Nexus\Database\NexusDB;
abstract class BasePlugin extends BaseRepository abstract class BasePlugin extends BaseRepository
{ {
@@ -44,4 +42,19 @@ abstract class BasePlugin extends BaseRepository
$pluginRoot = dirname($reflection->getFileName(), 2); $pluginRoot = dirname($reflection->getFileName(), 2);
return $pluginRoot . "/resources/views/" . trim($name, "/"); return $pluginRoot . "/resources/views/" . trim($name, "/");
} }
public function trans($name): string
{
return nexus_trans($this->getTransKey($name));
}
public function getTransKey($name): string
{
return sprintf("%s::%s", static::ID, $name);
}
public static function getInstance(): static
{
return Plugin::getById(static::ID);
}
} }
+10
View File
@@ -23,6 +23,16 @@ class Plugin
return !empty(self::$providers[$name]['providers']); return !empty(self::$providers[$name]['providers']);
} }
public static function listEnabled(): array
{
$result = [];
//plugins are more exactly
foreach (self::$plugins as $id => $plugin) {
$result[$id] = 1;
}
return $result;
}
public static function getById($id) :BasePlugin|null public static function getById($id) :BasePlugin|null
{ {
return self::$plugins[$id] ?? null; return self::$plugins[$id] ?? null;
+40 -64
View File
@@ -164,6 +164,13 @@ if (!$az) {
$redis->set("$passkeyInvalidKey:$passkey", TIMENOW, ['ex' => 24*3600]); $redis->set("$passkeyInvalidKey:$passkey", TIMENOW, ['ex' => 24*3600]);
warn("Invalid passkey! Re-download the .torrent from $BASEURL"); warn("Invalid passkey! Re-download the .torrent from $BASEURL");
} }
if ($az["enabled"] == "no")
warn("Your account is disabled!", 300);
elseif ($az["parked"] == "yes")
warn("Your account is parked! (Read the FAQ)", 300);
elseif ($az["downloadpos"] == "no")
warn("Your downloading privileges have been disabled! (Read the rules)", 300);
$userid = intval($az['id'] ?? 0); $userid = intval($az['id'] ?? 0);
unset($GLOBALS['CURUSER']); unset($GLOBALS['CURUSER']);
$CURUSER = $GLOBALS["CURUSER"] = $az; $CURUSER = $GLOBALS["CURUSER"] = $az;
@@ -401,13 +408,6 @@ if (!isset($self))
if ($valid[0] >= 1 && $seeder == 'no') err("You already are downloading the same torrent. You may only leech from one location at a time.", 300); if ($valid[0] >= 1 && $seeder == 'no') err("You already are downloading the same torrent. You may only leech from one location at a time.", 300);
if ($valid[0] >= 3 && $seeder == 'yes') err("You cannot seed the same torrent from more than 3 locations.", 300); if ($valid[0] >= 3 && $seeder == 'yes') err("You cannot seed the same torrent from more than 3 locations.", 300);
if ($az["enabled"] == "no")
warn("Your account is disabled!", 300);
elseif ($az["parked"] == "yes")
warn("Your account is parked! (Read the FAQ)", 300);
elseif ($az["downloadpos"] == "no")
warn("Your downloading privileges have been disabled! (Read the rules)", 300);
if ($az["class"] < UC_VIP) if ($az["class"] < UC_VIP)
{ {
$ratio = (($az["downloaded"] > 0) ? ($az["uploaded"] / $az["downloaded"]) : 1); $ratio = (($az["downloaded"] > 0) ? ($az["uploaded"] / $az["downloaded"]) : 1);
@@ -451,42 +451,30 @@ if (!isset($self))
&& $torrent['owner'] != $userid && $torrent['owner'] != $userid
&& get_setting("torrent.paid_torrent_enabled") == "yes" && get_setting("torrent.paid_torrent_enabled") == "yes"
) { ) {
$hasBuyCacheKey = \App\Repositories\TorrentRepository::BOUGHT_USER_CACHE_KEY_PREFIX . $torrentid; $torrentRep = new \App\Repositories\TorrentRepository();
$hasBuy = $redis->hGet($hasBuyCacheKey, $userid); $buyStatus = $torrentRep->getBuyStatus($userid, $torrentid);
if ($hasBuy === false) { if ($buyStatus > 0) {
//no cache do_log(sprintf("user: %v buy torrent %v fail count: %v", $userid, $torrentid, $buyStatus), "error");
$lockName = "load_torrent_bought_user:$torrentid"; if ($buyStatus > 3) {
$loadBoughtLock = new \Nexus\Database\NexusLock($lockName, 300); //warn
if ($loadBoughtLock->get()) { \App\Utils\MsgAlert::getInstance()->add(
//get lock, do load "announce_paid_torrent_too_many_times",
executeCommand("torrent:load_bought_user $torrentid", "string", true, false); time() + 86400,
} else { "announce to paid torrent and fail too many times, please make sure you have enough bonus!",
do_log("can not get loadBoughtLock: $lockName", 'debug'); "",
"black"
);
} }
//simple cache the hasBuy result if ($buyStatus > 10) {
$hasBuy = \Nexus\Database\NexusDB::remember(sprintf("user_has_buy_torrent:%s:%s", $userid, $torrentid), 86400*10, function () use($userid, $torrentid) { //disable download
$exists = \App\Models\TorrentBuyLog::query()->where('uid', $userid)->where('torrent_id', $torrentid)->exists(); (new \App\Repositories\UserRepository())->updateDownloadPrivileges(null, $userid, 'no', 'announce_paid_torrent_too_many_times');
return intval($exists); }
}); warn("purchase fail, please try again later, please make sure you have enough bonus", 300);
} }
if (!$hasBuy) { if ($buyStatus == \App\Repositories\TorrentRepository::BUY_STATUS_UNKNOWN) {
$lock = new \Nexus\Database\NexusLock("buying_torrent:$userid", 5); //just enqueue job
if (!$lock->get()) { \App\Utils\ThirdPartyJob::addBuyTorrent($userid, $torrentid);
$msg = "buying torrent, wait!"; warn("purchase in progress, please wait", 300);
do_log("[ANNOUNCE] user: $userid, torrent: $torrentid, $msg", 'error');
err($msg);
}
$bonusRep = new \App\Repositories\BonusRepository();
try {
$bonusRep->consumeToBuyTorrent($az['id'], $torrent['id'], 'Web');
$redis->hSet($hasBuyCacheKey, $userid, 1);
$lock->release();
} catch (\Exception $exception) {
$msg = $exception->getMessage();
do_log("[ANNOUNCE] user: $userid, torrent: $torrentid, $msg " . $exception->getTraceAsString(), 'error');
$lock->release();
err($msg);
}
} }
} }
} }
@@ -535,7 +523,7 @@ if (isset($self) && $event == "stopped")
sql_query("DELETE FROM peers WHERE id = {$self['id']}") or err("D Err"); sql_query("DELETE FROM peers WHERE id = {$self['id']}") or err("D Err");
if (mysql_affected_rows() && !empty($snatchInfo)) if (mysql_affected_rows() && !empty($snatchInfo))
{ {
// $updateset[] = ($self["seeder"] == "yes" ? "seeders = seeders - 1" : "leechers = leechers - 1"); $updateset[] = ($self["seeder"] == "yes" ? "seeders = seeders - 1" : "leechers = leechers - 1");
$hasChangeSeederLeecher = true; $hasChangeSeederLeecher = true;
sql_query("UPDATE snatched SET uploaded = uploaded + $trueupthis, downloaded = downloaded + $truedownthis, to_go = $left, $announcetime, last_action = ".$dt." WHERE id = {$snatchInfo['id']}") or err("SL Err 1"); sql_query("UPDATE snatched SET uploaded = uploaded + $trueupthis, downloaded = downloaded + $truedownthis, to_go = $left, $announcetime, last_action = ".$dt." WHERE id = {$snatchInfo['id']}") or err("SL Err 1");
} }
@@ -556,7 +544,7 @@ elseif(isset($self))
if (mysql_affected_rows()) if (mysql_affected_rows())
{ {
if ($seeder <> $self["seeder"]) { if ($seeder <> $self["seeder"]) {
// $updateset[] = ($seeder == "yes" ? "seeders = seeders + 1, leechers = leechers - 1" : "seeders = seeders - 1, leechers = leechers + 1"); $updateset[] = ($seeder == "yes" ? "seeders = seeders + 1, leechers = leechers - 1" : "seeders = seeders - 1, leechers = leechers + 1");
$hasChangeSeederLeecher = true; $hasChangeSeederLeecher = true;
} }
if (!empty($snatchInfo)) { if (!empty($snatchInfo)) {
@@ -570,19 +558,7 @@ else
if ($event != 'stopped') { if ($event != 'stopped') {
$isPeerExistResultSet = sql_query("select id from peers where $selfwhere limit 1"); $isPeerExistResultSet = sql_query("select id from peers where $selfwhere limit 1");
if (mysql_num_rows($isPeerExistResultSet) == 0) { if (mysql_num_rows($isPeerExistResultSet) == 0) {
$cacheKey = 'peers:connectable:'.$ip.'-'.$port.'-'.$agent; $connectable = "yes";
$connectable = \Nexus\Database\NexusDB::remember($cacheKey, 3600, function () use ($ip, $port) {
if (isIPV6($ip)) {
$sockres = @fsockopen("tcp://[".$ip."]",$port,$errno,$errstr,1);
} else {
$sockres = @fsockopen($ip, $port, $errno, $errstr, 1);
}
if (is_resource($sockres)) {
fclose($sockres);
return 'yes';
}
return 'no';
});
$insertPeerSql = "INSERT INTO peers (torrent, userid, peer_id, ip, port, connectable, uploaded, downloaded, to_go, started, last_action, seeder, agent, downloadoffset, uploadoffset, passkey, ipv4, ipv6, is_seed_box) VALUES ($torrentid, $userid, ".sqlesc($peer_id).", ".sqlesc($ip).", $port, '$connectable', $uploaded, $downloaded, $left, $dt, $dt, '$seeder', ".sqlesc($agent).", $downloaded, $uploaded, ".sqlesc($passkey).", ".sqlesc($ipv4).", ".sqlesc($ipv6).", ".intval($isIPSeedBox).")"; $insertPeerSql = "INSERT INTO peers (torrent, userid, peer_id, ip, port, connectable, uploaded, downloaded, to_go, started, last_action, seeder, agent, downloadoffset, uploadoffset, passkey, ipv4, ipv6, is_seed_box) VALUES ($torrentid, $userid, ".sqlesc($peer_id).", ".sqlesc($ip).", $port, '$connectable', $uploaded, $downloaded, $left, $dt, $dt, '$seeder', ".sqlesc($agent).", $downloaded, $uploaded, ".sqlesc($passkey).", ".sqlesc($ipv4).", ".sqlesc($ipv6).", ".intval($isIPSeedBox).")";
do_log("[INSERT PEER] peer not exists for $selfwhere, do insert with $insertPeerSql"); do_log("[INSERT PEER] peer not exists for $selfwhere, do insert with $insertPeerSql");
@@ -590,7 +566,7 @@ else
sql_query($insertPeerSql) or err("PL Err 2"); sql_query($insertPeerSql) or err("PL Err 2");
if (mysql_affected_rows()) if (mysql_affected_rows())
{ {
// $updateset[] = ($seeder == "yes" ? "seeders = seeders + 1" : "leechers = leechers + 1"); $updateset[] = ($seeder == "yes" ? "seeders = seeders + 1" : "leechers = leechers + 1");
$hasChangeSeederLeecher = true; $hasChangeSeederLeecher = true;
// $check = @mysql_fetch_row(@sql_query("SELECT COUNT(*) FROM snatched WHERE torrentid = $torrentid AND userid = $userid")); // $check = @mysql_fetch_row(@sql_query("SELECT COUNT(*) FROM snatched WHERE torrentid = $torrentid AND userid = $userid"));
$checkSnatchedRes = mysql_fetch_assoc(sql_query("SELECT id FROM snatched WHERE torrentid = $torrentid AND userid = $userid limit 1")); $checkSnatchedRes = mysql_fetch_assoc(sql_query("SELECT id FROM snatched WHERE torrentid = $torrentid AND userid = $userid limit 1"));
@@ -617,8 +593,8 @@ if (($left > 0 || $event == "completed") && $az['class'] < \App\Models\HitAndRun
$hrLog = sprintf("[HR_LOG] user: %d, torrent: %d, hrMode: %s", $userid, $torrentid, $hrMode); $hrLog = sprintf("[HR_LOG] user: %d, torrent: %d, hrMode: %s", $userid, $torrentid, $hrMode);
if ($hrMode == \App\Models\HitAndRun::MODE_GLOBAL || ($hrMode == \App\Models\HitAndRun::MODE_MANUAL && $torrent['hr'] == \App\Models\Torrent::HR_YES)) { if ($hrMode == \App\Models\HitAndRun::MODE_GLOBAL || ($hrMode == \App\Models\HitAndRun::MODE_MANUAL && $torrent['hr'] == \App\Models\Torrent::HR_YES)) {
$hrCacheKey = sprintf("hit_and_run:%d:%d", $userid, $torrentid); $hrCacheKey = sprintf("hit_and_run:%d:%d", $userid, $torrentid);
$hrExists = \Nexus\Database\NexusDB::remember($hrCacheKey, 24*3600, function () use ($torrentid, $userid) { $hrExists = \Nexus\Database\NexusDB::remember($hrCacheKey, mt_rand(86400*365*5, 86400*365*10), function () use ($torrentid, $userid) {
return \App\Models\HitAndRun::query()->where("uid", $userid)->where("torrent_id", $torrentid)->exists(); return \App\Models\HitAndRun::query()->where("uid", $userid)->where("torrent_id", $torrentid)->exists() ? 1 : 0;
}); });
$hrLog .= ", hrExists: $hrExists"; $hrLog .= ", hrExists: $hrExists";
if (!$hrExists) { if (!$hrExists) {
@@ -650,11 +626,11 @@ if (($left > 0 || $event == "completed") && $az['class'] < \App\Models\HitAndRun
do_log("$hrLog, not match", "debug"); do_log("$hrLog, not match", "debug");
} }
} }
// revert to only increment/decrement
if (isset($event) && !empty($event)) { //if (isset($event) && !empty($event)) {
$updateset[] = 'seeders = ' . get_row_count("peers", "where torrent = $torrentid and to_go = 0"); // $updateset[] = 'seeders = ' . get_row_count("peers", "where torrent = $torrentid and to_go = 0");
$updateset[] = 'leechers = ' . get_row_count("peers", "where torrent = $torrentid and to_go > 0"); // $updateset[] = 'leechers = ' . get_row_count("peers", "where torrent = $torrentid and to_go > 0");
} //}
if (count($updateset) || $hasChangeSeederLeecher) // Update only when there is change in peer counts if (count($updateset) || $hasChangeSeederLeecher) // Update only when there is change in peer counts
{ {
+1 -1
View File
@@ -109,7 +109,7 @@ if ($Attach->enable_attachment())
if ($orig && !$stop) if ($orig && !$stop)
{ {
$thumb = imagecreatetruecolor($newwidth, $newheight); $thumb = imagecreatetruecolor($newwidth, $newheight);
imagecopyresized($thumb, $orig, 0, 0, 0, 0, $newwidth, $newheight, $width, $height); imagecopyresampled($thumb, $orig, 0, 0, 0, 0, $newwidth, $newheight, $width, $height);
if ($thumbnailtype_attachment == 'createthumb'){ if ($thumbnailtype_attachment == 'createthumb'){
$hasthumb = true; $hasthumb = true;
imagejpeg($thumb, $file_location.".".$ext.".thumb.jpg", $thumbquality_attachment); imagejpeg($thumb, $file_location.".".$ext.".thumb.jpg", $thumbquality_attachment);
+1 -1
View File
@@ -48,7 +48,7 @@ if ($_SERVER["REQUEST_METHOD"] == "POST")
if(!$orig) if(!$orig)
stderr($lang_bitbucketupload['std_image_processing_failed'],$lang_bitbucketupload['std_sorry_the_uploaded']."$imgtypes[$it]".$lang_bitbucketupload['std_failed_processing']); stderr($lang_bitbucketupload['std_image_processing_failed'],$lang_bitbucketupload['std_sorry_the_uploaded']."$imgtypes[$it]".$lang_bitbucketupload['std_failed_processing']);
$thumb = imagecreatetruecolor($newwidth, $newheight); $thumb = imagecreatetruecolor($newwidth, $newheight);
imagecopyresized($thumb, $orig, 0, 0, 0, 0, $newwidth, $newheight, $width, $height); imagecopyresampled($thumb, $orig, 0, 0, 0, 0, $newwidth, $newheight, $width, $height);
switch ($it) { switch ($it) {
case 1: case 1:
$ret = imagegif($thumb, $tgtfile); $ret = imagegif($thumb, $tgtfile);
-2
View File
@@ -7,8 +7,6 @@ loggedinorreturn();
stdhead($lang_contactstaff['head_contact_staff'], false); stdhead($lang_contactstaff['head_contact_staff'], false);
begin_main_frame(); begin_main_frame();
print("<form id=compose method=post name=\"compose\" action=takecontact.php>"); print("<form id=compose method=post name=\"compose\" action=takecontact.php>");
if (isset($_GET["returnto"]) && $_GET["returnto"] || $_SERVER["HTTP_REFERER"])
print("<input type=hidden name=returnto value=\"".(htmlspecialchars($_GET["returnto"] ?? '') ? htmlspecialchars($_GET["returnto"] ?? '') : htmlspecialchars($_SERVER["HTTP_REFERER"] ?? ''))."\">");
begin_compose($lang_contactstaff['text_message_to_staff'], "new"); begin_compose($lang_contactstaff['text_message_to_staff'], "new");
end_compose(); end_compose();
print("</form>"); print("</form>");
+2 -2
View File
@@ -6,7 +6,7 @@ require_once(get_langfile_path());
loggedinorreturn(); loggedinorreturn();
$id = intval($_GET["id"] ?? 0); $id = intval($_GET["id"] ?? 0);
$customField = new \Nexus\Field\Field(); $customField = new \Nexus\Field\Field();
int_check($id); int_check($id, true);
if (!isset($id) || !$id) if (!isset($id) || !$id)
die(); die();
@@ -483,7 +483,7 @@ WHERE " . $where_area . " ORDER BY torrents.id DESC") or sqlerr(__FILE__, __LINE
tr($lang_details['row_hot_meter'], "<table><tr><td class=\"no_border_wide\"><b>" . $lang_details['text_views']."</b>". $row["views"] . "</td><td class=\"no_border_wide\"><b>" . $lang_details['text_hits']. "</b>" . $row["hits"] . "</td><td class=\"no_border_wide\"><b>" .$lang_details['text_snatched'] . "</b><a href=\"viewsnatches.php?id=".$id."\"><b>" . $row["times_completed"]. $lang_details['text_view_snatches'] . "</td><td class=\"no_border_wide\"><b>" . $lang_details['row_last_seeder']. "</b>" . gettime($row["last_action"]) . "</td></tr></table>",1); tr($lang_details['row_hot_meter'], "<table><tr><td class=\"no_border_wide\"><b>" . $lang_details['text_views']."</b>". $row["views"] . "</td><td class=\"no_border_wide\"><b>" . $lang_details['text_hits']. "</b>" . $row["hits"] . "</td><td class=\"no_border_wide\"><b>" .$lang_details['text_snatched'] . "</b><a href=\"viewsnatches.php?id=".$id."\"><b>" . $row["times_completed"]. $lang_details['text_view_snatches'] . "</td><td class=\"no_border_wide\"><b>" . $lang_details['row_last_seeder']. "</b>" . gettime($row["last_action"]) . "</td></tr></table>",1);
$bwres = sql_query("SELECT uploadspeed.name AS upname, downloadspeed.name AS downname, isp.name AS ispname FROM users LEFT JOIN uploadspeed ON users.upload = uploadspeed.id LEFT JOIN downloadspeed ON users.download = downloadspeed.id LEFT JOIN isp ON users.isp = isp.id WHERE users.id=".$row['owner']); $bwres = sql_query("SELECT uploadspeed.name AS upname, downloadspeed.name AS downname, isp.name AS ispname FROM users LEFT JOIN uploadspeed ON users.upload = uploadspeed.id LEFT JOIN downloadspeed ON users.download = downloadspeed.id LEFT JOIN isp ON users.isp = isp.id WHERE users.id=".$row['owner']);
$bwrow = mysql_fetch_array($bwres); $bwrow = mysql_fetch_array($bwres);
if ($bwrow['upname'] && $bwrow['downname']) if (isset($bwrow['upname']) && isset($bwrow['downname']) && $bwrow['upname'] && $bwrow['downname'])
tr($lang_details['row_uploader_bandwidth'], "<img class=\"speed_down\" src=\"pic/trans.gif\" alt=\"Downstream Rate\" /> ".$bwrow['downname']."&nbsp;&nbsp;&nbsp;&nbsp;<img class=\"speed_up\" src=\"pic/trans.gif\" alt=\"Upstream Rate\" /> ".$bwrow['upname']."&nbsp;&nbsp;&nbsp;&nbsp;".$bwrow['ispname'],1); tr($lang_details['row_uploader_bandwidth'], "<img class=\"speed_down\" src=\"pic/trans.gif\" alt=\"Downstream Rate\" /> ".$bwrow['downname']."&nbsp;&nbsp;&nbsp;&nbsp;<img class=\"speed_up\" src=\"pic/trans.gif\" alt=\"Upstream Rate\" /> ".$bwrow['upname']."&nbsp;&nbsp;&nbsp;&nbsp;".$bwrow['ispname'],1);
/* /*
+1 -1
View File
@@ -765,7 +765,7 @@ if ($action == "viewtopic")
print("<table class=\"main\" width=\"100%\" border=\"1\" cellspacing=\"0\" cellpadding=\"5\">\n"); print("<table class=\"main\" width=\"100%\" border=\"1\" cellspacing=\"0\" cellpadding=\"5\">\n");
$body = "<div id=\"pid".$postid."body\">"; $body = "<div id=\"pid".$postid."body\" style=\"word-break: break-all;\">";
//hidden content applied to second or higher floor post (for whose user class below Ad , not poster , not mods ,not reply's author) //hidden content applied to second or higher floor post (for whose user class below Ad , not poster , not mods ,not reply's author)
// if ($protected_enabled && $pn+$offset>1 && get_user_class()<UC_ADMINISTRATOR && $userid != $base_posterid && $posterid!=$userid && !$is_forummod){ // if ($protected_enabled && $pn+$offset>1 && get_user_class()<UC_ADMINISTRATOR && $userid != $base_posterid && $posterid!=$userid && !$is_forummod){
if ($pn+$offset>1 && !can_view_post($userid, $arr)){ if ($pn+$offset>1 && !can_view_post($userid, $arr)){
+1 -1
View File
@@ -259,7 +259,7 @@ function maketable($res, $mode = 'seeding')
return [$ret, $total_size]; return [$ret, $total_size];
} }
$count = 0; $count = 0;
$torrentlist = ""; $torrentlist = $pagertop = $pagerbottom = "";
switch ($type) switch ($type)
{ {
case 'uploaded': case 'uploaded':
+1 -1
View File
@@ -228,7 +228,7 @@ $sender = get_username($message['sender']);
$reply = " [ <a href=\"sendmessage.php?receiver=" . $message['sender'] . "&replyto=" . $pm_id . "\">".$lang_messages['text_reply']."</a> ]"; $reply = " [ <a href=\"sendmessage.php?receiver=" . $message['sender'] . "&replyto=" . $pm_id . "\">".$lang_messages['text_reply']."</a> ]";
} }
} }
$body = format_comment($message['msg'], false); $body = format_comment($message['msg'], true);
//$body = htmlspecialchars_decode($body); //$body = htmlspecialchars_decode($body);
$added = $message['added']; $added = $message['added'];
if ($message['sender'] == $CURUSER['id']) if ($message['sender'] == $CURUSER['id'])
+10 -4
View File
@@ -301,7 +301,7 @@ if ($bonus_tweak == "disable" || $bonus_tweak == "disablesave")
stderr($lang_mybonus['std_sorry'],$lang_mybonus['std_karma_system_disabled'].($bonus_tweak == "disablesave" ? "<b>".$lang_mybonus['std_points_active']."</b>" : ""),false); stderr($lang_mybonus['std_sorry'],$lang_mybonus['std_karma_system_disabled'].($bonus_tweak == "disablesave" ? "<b>".$lang_mybonus['std_points_active']."</b>" : ""),false);
$action = htmlspecialchars($_GET['action'] ?? ''); $action = htmlspecialchars($_GET['action'] ?? '');
$do = htmlspecialchars($_GET['do'] ?? null); $do = htmlspecialchars($_GET['do'] ?? '');
unset($msg); unset($msg);
if (isset($do)) { if (isset($do)) {
if ($do == "upload") if ($do == "upload")
@@ -398,7 +398,7 @@ for ($i=0; $i < count($allBonus); $i++)
elseif ($bonusarray['art'] == 'noad'){ elseif ($bonusarray['art'] == 'noad'){
if ($enablenoad_advertisement == 'yes' && get_user_class() >= $noad_advertisement) if ($enablenoad_advertisement == 'yes' && get_user_class() >= $noad_advertisement)
print("<td class=\"rowfollow\" align=\"center\"><input type=\"submit\" name=\"submit\" value=\"".$lang_mybonus['submit_class_above_no_ad']."\" disabled=\"disabled\" /></td>"); print("<td class=\"rowfollow\" align=\"center\"><input type=\"submit\" name=\"submit\" value=\"".$lang_mybonus['submit_class_above_no_ad']."\" disabled=\"disabled\" /></td>");
elseif (strtotime($CURUSER['noaduntil']) >= TIMENOW) elseif (!empty($CURUSER['noaduntil']) && strtotime($CURUSER['noaduntil']) >= TIMENOW)
print("<td class=\"rowfollow\" align=\"center\"><input type=\"submit\" name=\"submit\" value=\"".$lang_mybonus['submit_already_disabled']."\" disabled=\"disabled\" /></td>"); print("<td class=\"rowfollow\" align=\"center\"><input type=\"submit\" name=\"submit\" value=\"".$lang_mybonus['submit_already_disabled']."\" disabled=\"disabled\" /></td>");
elseif (get_user_class() < $bonusnoad_advertisement) elseif (get_user_class() < $bonusnoad_advertisement)
print("<td class=\"rowfollow\" align=\"center\"><input type=\"submit\" name=\"submit\" value=\"".get_user_class_name($bonusnoad_advertisement,false,false,true).$lang_mybonus['text_plus_only']."\" disabled=\"disabled\" /></td>"); print("<td class=\"rowfollow\" align=\"center\"><input type=\"submit\" name=\"submit\" value=\"".get_user_class_name($bonusnoad_advertisement,false,false,true).$lang_mybonus['text_plus_only']."\" disabled=\"disabled\" /></td>");
@@ -550,8 +550,6 @@ if ($offervote_bonus > 0)
print("<li>".$lang_mybonus['text_offer_vote'].$offervote_bonus.$lang_mybonus['text_point'].add_s($offervote_bonus)."</li>"); print("<li>".$lang_mybonus['text_offer_vote'].$offervote_bonus.$lang_mybonus['text_point'].add_s($offervote_bonus)."</li>");
if ($funboxvote_bonus > 0) if ($funboxvote_bonus > 0)
print("<li>".$lang_mybonus['text_funbox_vote'].$funboxvote_bonus.$lang_mybonus['text_point'].add_s($funboxvote_bonus)."</li>"); print("<li>".$lang_mybonus['text_funbox_vote'].$funboxvote_bonus.$lang_mybonus['text_point'].add_s($funboxvote_bonus)."</li>");
if ($ratetorrent_bonus > 0)
print("<li>".$lang_mybonus['text_rate_torrent'].$ratetorrent_bonus.$lang_mybonus['text_point'].add_s($ratetorrent_bonus)."</li>");
if ($saythanks_bonus > 0) if ($saythanks_bonus > 0)
print("<li>".$lang_mybonus['text_say_thanks'].$saythanks_bonus.$lang_mybonus['text_point'].add_s($saythanks_bonus)."</li>"); print("<li>".$lang_mybonus['text_say_thanks'].$saythanks_bonus.$lang_mybonus['text_point'].add_s($saythanks_bonus)."</li>");
if ($receivethanks_bonus > 0) if ($receivethanks_bonus > 0)
@@ -611,6 +609,10 @@ if ($action == "exchange") {
else { else {
$upload = $CURUSER['uploaded']; $upload = $CURUSER['uploaded'];
$up = $upload + $bonusarray['menge']; $up = $upload + $bonusarray['menge'];
do_log(sprintf(
"user: %s going to use %s bonus to exchange uploaded from %s to %s",
$CURUSER['id'], $points, $CURUSER['uploaded'], $up
));
// $bonuscomment = date("Y-m-d") . " - " .$points. " Points for upload bonus.\n " .$bonuscomment; // $bonuscomment = date("Y-m-d") . " - " .$points. " Points for upload bonus.\n " .$bonuscomment;
// sql_query("UPDATE users SET uploaded = ".sqlesc($up).", seedbonus = seedbonus - $points, bonuscomment = ".sqlesc($bonuscomment)." WHERE id = ".sqlesc($userid)) or sqlerr(__FILE__, __LINE__); // sql_query("UPDATE users SET uploaded = ".sqlesc($up).", seedbonus = seedbonus - $points, bonuscomment = ".sqlesc($bonuscomment)." WHERE id = ".sqlesc($userid)) or sqlerr(__FILE__, __LINE__);
$bonusRep->consumeUserBonus($CURUSER['id'], $points, \App\Models\BonusLogs::BUSINESS_TYPE_EXCHANGE_UPLOAD, $points. " Points for uploaded.", ['uploaded' => $up]); $bonusRep->consumeUserBonus($CURUSER['id'], $points, \App\Models\BonusLogs::BUSINESS_TYPE_EXCHANGE_UPLOAD, $points. " Points for uploaded.", ['uploaded' => $up]);
@@ -620,6 +622,10 @@ if ($action == "exchange") {
if($art == "traffic_downloaded") { if($art == "traffic_downloaded") {
$downloaded = $CURUSER['downloaded']; $downloaded = $CURUSER['downloaded'];
$down = $downloaded + $bonusarray['menge']; $down = $downloaded + $bonusarray['menge'];
do_log(sprintf(
"user: %s going to use %s bonus to exchange downloaded from %s to %s",
$CURUSER['id'], $points, $CURUSER['downloaded'], $down
));
$bonusRep->consumeUserBonus($CURUSER['id'], $points, \App\Models\BonusLogs::BUSINESS_TYPE_EXCHANGE_DOWNLOAD, $points. " Points for downloaded.", ['downloaded' => $down]); $bonusRep->consumeUserBonus($CURUSER['id'], $points, \App\Models\BonusLogs::BUSINESS_TYPE_EXCHANGE_DOWNLOAD, $points. " Points for downloaded.", ['downloaded' => $down]);
nexus_redirect("" . get_protocol_prefix() . "$BASEURL/mybonus.php?do=download"); nexus_redirect("" . get_protocol_prefix() . "$BASEURL/mybonus.php?do=download");
} }
+1 -1
View File
@@ -127,7 +127,7 @@ else
} }
else $username = $lang_shoutbox['text_guest']; else $username = $lang_shoutbox['text_guest'];
if (isset($CURUSER) && $CURUSER['timetype'] != 'timealive') if (isset($CURUSER) && $CURUSER['timetype'] != 'timealive')
$time = strftime("%m.%d %H:%M",$arr["date"]); $time = (new DateTime())->setTimestamp($arr["date"])->format('m.d H:i');
else $time = get_elapsed_time($arr["date"]).$lang_shoutbox['text_ago']; else $time = get_elapsed_time($arr["date"]).$lang_shoutbox['text_ago'];
print("<tr><td class=\"shoutrow\"><span class='date'>[".$time."]</span> ". print("<tr><td class=\"shoutrow\"><span class='date'>[".$time."]</span> ".
$del ." ". $username." " . format_comment($arr["text"],true,false,true,true,600,false,false)." $del ." ". $username." " . format_comment($arr["text"],true,false,true,true,600,false,false)."
+3
View File
@@ -71,3 +71,6 @@ img.hitandrun {
.codemain>pre { .codemain>pre {
margin: 0; margin: 0;
} }
.word-break-all {
word-break: break-all;
}
+3 -1
View File
@@ -151,6 +151,7 @@ $secret = mksecret();
$wantpasshash = md5($secret . $wantpassword . $secret); $wantpasshash = md5($secret . $wantpassword . $secret);
$editsecret = ($verification == 'admin' ? '' : $secret); $editsecret = ($verification == 'admin' ? '' : $secret);
$invite_count = (int) $invite_count; $invite_count = (int) $invite_count;
$passkey = md5($wantusername.date("Y-m-d H:i:s").$wantpasshash);
$wantusername = sqlesc($wantusername); $wantusername = sqlesc($wantusername);
$wantpasshash = sqlesc($wantpasshash); $wantpasshash = sqlesc($wantpasshash);
@@ -167,8 +168,9 @@ $res_check_user = sql_query("SELECT * FROM users WHERE username = " . $wantusern
if(mysql_num_rows($res_check_user) == 1) if(mysql_num_rows($res_check_user) == 1)
bark($lang_takesignup['std_username_exists']); bark($lang_takesignup['std_username_exists']);
$ret = sql_query("INSERT INTO users (username, passhash, secret, editsecret, email, country, gender, status, class, invites, ".($type == 'invite' ? "invited_by," : "")." added, last_access, lang, stylesheet".($showschool == 'yes' ? ", school" : "").", uploaded) VALUES (" . $wantusername . "," . $wantpasshash . "," . $secret . "," . $editsecret . "," . $email . "," . $country . "," . $gender . ", 'pending', ".$defaultclass_class.",". $invite_count .", ".($type == 'invite' ? "'$inviter'," : "") ." '". date("Y-m-d H:i:s") ."' , " . " '". date("Y-m-d H:i:s") ."' , ".$sitelangid . ",".$defcss.($showschool == 'yes' ? ",".$school : "").",".($iniupload_main > 0 ? $iniupload_main : 0).")") or sqlerr(__FILE__, __LINE__); $ret = sql_query("INSERT INTO users (username, passhash, passkey, secret, editsecret, email, country, gender, status, class, invites, ".($type == 'invite' ? "invited_by," : "")." added, last_access, lang, stylesheet".($showschool == 'yes' ? ", school" : "").", uploaded) VALUES (" . $wantusername . "," . $wantpasshash . "," . sqlesc($passkey) . "," . $secret . "," . $editsecret . "," . $email . "," . $country . "," . $gender . ", 'pending', ".$defaultclass_class.",". $invite_count .", ".($type == 'invite' ? "'$inviter'," : "") ." '". date("Y-m-d H:i:s") ."' , " . " '". date("Y-m-d H:i:s") ."' , ".$sitelangid . ",".$defcss.($showschool == 'yes' ? ",".$school : "").",".($iniupload_main > 0 ? $iniupload_main : 0).")") or sqlerr(__FILE__, __LINE__);
$id = mysql_insert_id(); $id = mysql_insert_id();
fire_event("user_created", \App\Models\User::query()->first($id, \App\Models\User::$commonFields));
$tmpInviteCount = get_setting('main.tmp_invite_count'); $tmpInviteCount = get_setting('main.tmp_invite_count');
if ($tmpInviteCount > 0) { if ($tmpInviteCount > 0) {
$userRep = new \App\Repositories\UserRepository(); $userRep = new \App\Repositories\UserRepository();
+1 -1
View File
@@ -71,7 +71,7 @@ if (isset($searchstr)){
$ANDOR = ($search_mode == 0 ? " AND " : " OR "); // only affects mode 0 and mode 1 $ANDOR = ($search_mode == 0 ? " AND " : " OR "); // only affects mode 0 and mode 1
foreach ($like_expression_array as &$like_expression_array_element) foreach ($like_expression_array as &$like_expression_array_element)
$like_expression_array_element = "(torrents.name" . $like_expression_array_element.($_GET['ismalldescr'] ? " OR torrents.small_descr". $like_expression_array_element : "").")"; $like_expression_array_element = "(torrents.name" . $like_expression_array_element . (isset($_GET['ismalldescr']) && $_GET['ismalldescr'] ? " OR torrents.small_descr" . $like_expression_array_element : "") . ")";
$wherea[] = implode($ANDOR, $like_expression_array); $wherea[] = implode($ANDOR, $like_expression_array);
$where .= ($where ? " AND " : "") . implode(" AND ", $wherea); $where .= ($where ? " AND " : "") . implode(" AND ", $wherea);
} }
+3 -1
View File
@@ -702,7 +702,6 @@ $search_area = 0;
if (isset($searchstr)) if (isset($searchstr))
{ {
if (!isset($_GET['notnewword']) || !$_GET['notnewword']){ if (!isset($_GET['notnewword']) || !$_GET['notnewword']){
insert_suggest($searchstr, $CURUSER['id']);
$notnewword=""; $notnewword="";
} }
else{ else{
@@ -956,6 +955,9 @@ do_log("[TORRENT_COUNT_SQL] $sql", 'debug');
if ($count) if ($count)
{ {
if (isset($searchstr) && (!isset($_GET['notnewword']) || !$_GET['notnewword'])){
insert_suggest($searchstr, $CURUSER['id']);
}
if ($addparam != "") if ($addparam != "")
{ {
if ($pagerlink != "") if ($pagerlink != "")
+1 -1
View File
@@ -238,7 +238,7 @@ if (user_can('userprofile') || $user["id"] == $CURUSER["id"])
tr_small($lang_userdetails['row_ip_address'], $user['ip'].$locationinfo.$seedBoxIcon, 1); tr_small($lang_userdetails['row_ip_address'], $user['ip'].$locationinfo.$seedBoxIcon, 1);
} }
$clientselect = ''; $clientselect = '';
$res = sql_query("SELECT peer_id, agent, ipv4, ipv6, port FROM peers WHERE userid = {$user['id']} GROUP BY agent") or sqlerr(); $res = sql_query("SELECT peer_id, agent, ipv4, ipv6, port FROM peers WHERE userid = {$user['id']} GROUP BY agent, ipv4, ipv6, port") or sqlerr();
if (mysql_num_rows($res) > 0) if (mysql_num_rows($res) > 0)
{ {
$clientselect .= "<table border='1' cellspacing='0' cellpadding='5'><tr><td class='colhead'>Agent</td><td class='colhead'>IPV4</td><td class='colhead'>IPV6</td><td class='colhead'>Port</td></tr>"; $clientselect .= "<table border='1' cellspacing='0' cellpadding='5'><tr><td class='colhead'>Agent</td><td class='colhead'>IPV4</td><td class='colhead'>IPV6</td><td class='colhead'>Port</td></tr>";
+18 -10
View File
@@ -168,16 +168,24 @@ function dltable($name, $arr, $torrent, &$isSeedBoxCaseWhens)
$s .= "</table>\n"; $s .= "</table>\n";
return $s; return $s;
} }
$downloaders = array(); $downloaders = array();
$seeders = array(); $seeders = array();
$torrent = \App\Models\Torrent::query()->findOrFail($id, ['id', 'seeders', 'leechers']); $torrent = \App\Models\Torrent::query()->findOrFail($id, ['id', 'seeders', 'leechers']);
$subres = sql_query("SELECT id, seeder, finishedat, downloadoffset, uploadoffset, ip, ipv4, ipv6, port, uploaded, downloaded, to_go, UNIX_TIMESTAMP(started) AS st, connectable, agent, peer_id, UNIX_TIMESTAMP(last_action) AS la, userid FROM peers WHERE torrent = $id") or sqlerr(); $seedersAndLeechers = apply_filter("torrent_seeder_leecher_list", [], $id);
while ($subrow = mysql_fetch_array($subres)) { if (isset($seedersAndLeechers['seeders'], $seedersAndLeechers['leechers'])) {
if ($subrow["seeder"] == "yes") // dd($seedersAndLeechers);
$seeders[] = $subrow; $seeders = $seedersAndLeechers['seeders'];
else $downloaders = $seedersAndLeechers['leechers'];
$downloaders[] = $subrow; do_log("SEEDER_LEECHER_FROM_FILTER: torrent_seeder_leecher_list");
} } else {
$subres = sql_query("SELECT id, seeder, finishedat, downloadoffset, uploadoffset, ip, ipv4, ipv6, port, uploaded, downloaded, to_go, UNIX_TIMESTAMP(started) AS st, connectable, agent, peer_id, UNIX_TIMESTAMP(last_action) AS la, userid FROM peers WHERE torrent = $id") or sqlerr();
while ($subrow = mysql_fetch_array($subres)) {
if ($subrow["seeder"] == "yes")
$seeders[] = $subrow;
else
$downloaders[] = $subrow;
}
}
$seedersCount = count($seeders); $seedersCount = count($seeders);
$leechersCount = count($downloaders); $leechersCount = count($downloaders);
if ($torrent->seeders != $seedersCount || $torrent->leechers != $leechersCount) { if ($torrent->seeders != $seedersCount || $torrent->leechers != $leechersCount) {
+1 -1
View File
@@ -53,7 +53,7 @@ if ($count){
} }
else $username = get_username($arr['userid']); else $username = get_username($arr['userid']);
$reportImage = "<img class=\"f_report\" src=\"pic/trans.gif\" alt=\"Report\" title=\"".$lang_viewsnatches['title_report']."\" />"; $reportImage = "<img class=\"f_report\" src=\"pic/trans.gif\" alt=\"Report\" title=\"".$lang_viewsnatches['title_report']."\" />";
print("<tr$highlight><td class=rowfollow align=center>" . $username ."</td>".(user_can('userprofile') || $arr['userid'] == $CURUSER['id'] ? "<td class=rowfollow align=center><span class='nowrap'>".$arr['ip'].$seedBoxRep->renderIcon($arr['ip'], $arr['userid'])."</span></td>" : "")."<td class=rowfollow align=center>".$uploaded."@".$uprate.$lang_viewsnatches['text_per_second']."<br />".$downloaded."@".$downrate.$lang_viewsnatches['text_per_second']."</td><td class=rowfollow align=center>$ratio</td><td class=rowfollow align=center>$seedtime</td><td class=rowfollow align=center>$leechtime</td><td class=rowfollow align=center>".gettime($arr['completedat'],true,false)."</td><td class=rowfollow align=center>".gettime($arr['last_action'],true,false)."</td><td class=rowfollow align=center style='padding: 0px'>".($userrow['privacy'] != 'strong' || user_can('viewanonymous') ? "<a href=report.php?user={$arr['userid']}>$reportImage</a>" : $reportImage)."</td></tr>\n"); print("<tr$highlight><td class=rowfollow align=center>" . $username ."</td>".(user_can('userprofile') ? "<td class=rowfollow align=center><span class='nowrap'>".$arr['ip'].$seedBoxRep->renderIcon($arr['ip'], $arr['userid'])."</span></td>" : "")."<td class=rowfollow align=center>".$uploaded."@".$uprate.$lang_viewsnatches['text_per_second']."<br />".$downloaded."@".$downrate.$lang_viewsnatches['text_per_second']."</td><td class=rowfollow align=center>$ratio</td><td class=rowfollow align=center>$seedtime</td><td class=rowfollow align=center>$leechtime</td><td class=rowfollow align=center>".gettime($arr['completedat'],true,false)."</td><td class=rowfollow align=center>".gettime($arr['last_action'],true,false)."</td><td class=rowfollow align=center style='padding: 0px'>".($userrow['privacy'] != 'strong' || user_can('viewanonymous') ? "<a href=report.php?user={$arr['userid']}>$reportImage</a>" : $reportImage)."</td></tr>\n");
} }
print("</table>\n"); print("</table>\n");
print($pagerbottom); print($pagerbottom);
+1
View File
@@ -47,6 +47,7 @@ return [
'server_software' => 'Web software', 'server_software' => 'Web software',
'load_average' => 'Server load average', 'load_average' => 'Server load average',
'filament_version' => 'Filament version', 'filament_version' => 'Filament version',
'redis_version' => 'Redis version',
], ],
'latest_user' => [ 'latest_user' => [
'page_title' => 'User latest', 'page_title' => 'User latest',
+4
View File
@@ -19,6 +19,10 @@ return [
'subject' => 'Download permission canceled', 'subject' => 'Download permission canceled',
'body' => 'Your download permission has been cancelled due to excessive upload speed, please file if you are a seed box user.' , 'body' => 'Your download permission has been cancelled due to excessive upload speed, please file if you are a seed box user.' ,
], ],
'download_disable_announce_paid_torrent_too_many_times' => [
'subject' => 'Download permission canceled',
'body' => 'Your download permission has been cancelled due to announce to paid torrent too many times, please make sure you have enough bonus.' ,
],
'download_enable' => [ 'download_enable' => [
'subject' => 'Download permission restored', 'subject' => 'Download permission restored',
'body' => 'Your download privileges restored, you can now download torrents. By: :operator', 'body' => 'Your download privileges restored, you can now download torrents. By: :operator',
+1
View File
@@ -47,6 +47,7 @@ return [
'server_software' => 'Web 软件', 'server_software' => 'Web 软件',
'load_average' => '服务器平均负载', 'load_average' => '服务器平均负载',
'filament_version' => 'Filament 版本', 'filament_version' => 'Filament 版本',
'redis_version' => 'Redis 版本',
], ],
'latest_user' => [ 'latest_user' => [
'page_title' => '最新用户', 'page_title' => '最新用户',
+4
View File
@@ -19,6 +19,10 @@ return [
'subject' => '下载权限取消', 'subject' => '下载权限取消',
'body' => '你因上传速度过快下载权限被取消,若是盒子用户请备案。', 'body' => '你因上传速度过快下载权限被取消,若是盒子用户请备案。',
], ],
'download_disable_announce_paid_torrent_too_many_times' => [
'subject' => '下载权限取消',
'body' => '你因向付费种子汇报失败次数过多下载权限被取消,请确保你有足够的魔力。',
],
'download_enable' => [ 'download_enable' => [
'subject' => '下载权限恢复', 'subject' => '下载权限恢复',
'body' => '你的下载权限恢复,你现在可以下载种子。By: :operator', 'body' => '你的下载权限恢复,你现在可以下载种子。By: :operator',
+1
View File
@@ -47,6 +47,7 @@ return [
'server_software' => 'Web 軟件', 'server_software' => 'Web 軟件',
'load_average' => '服務器平均負載', 'load_average' => '服務器平均負載',
'filament_version' => 'Filament 版本', 'filament_version' => 'Filament 版本',
'redis_version' => 'Redis 版本',
], ],
'latest_user' => [ 'latest_user' => [
'page_title' => '最新用戶', 'page_title' => '最新用戶',
+4
View File
@@ -18,6 +18,10 @@ return [
'subject' => '下載權限取消', 'subject' => '下載權限取消',
'body' => '你因上傳速度過快下載權限被取消,若是盒子用戶請備案。', 'body' => '你因上傳速度過快下載權限被取消,若是盒子用戶請備案。',
], ],
'download_disable_announce_paid_torrent_too_many_times' => [
'subject' => '下载权限取消',
'body' => '你因向付費種子匯報失敗次數過多下載權限被取消,請確保你有足夠的魔力。',
],
'download_enable' => [ 'download_enable' => [
'subject' => '下載權限恢復', 'subject' => '下載權限恢復',
'body' => '你的下載權限恢復,你現在可以下載種子。By: :operator', 'body' => '你的下載權限恢復,你現在可以下載種子。By: :operator',
@@ -20,7 +20,7 @@
colspan="3" colspan="3"
@endif @endif
> >
<div class="px-4 py-3 filament-tables-text-column">{{$item['value']}}</div> <div class="px-4 py-3 filament-tables-text-column {{$item['class'] ?? ''}}"><span class="">{{$item['value']}}</span></div>
</td> </td>
@endforeach @endforeach
</tr> </tr>
+1 -1
View File
@@ -18,4 +18,4 @@ if ($uri !== '/' && file_exists(__DIR__.'/public'.$uri)) {
return false; return false;
} }
require_once __DIR__.'/public/index.php'; require_once __DIR__.'/public/nexus.php';