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_DENY=all_agent_denies
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\TorrentDeleted;
use App\Events\TorrentUpdated;
use App\Events\UserCreated;
use App\Events\UserDestroyed;
use App\Events\UserDisabled;
use App\Events\UserEnabled;
@@ -31,15 +32,18 @@ class FireEvent extends Command
*
* @var string
*/
protected $description = 'Fire a event, options: --name, --idKey --idKeyOld';
protected $description = 'Fire an event, options: --name, --idKey --idKeyOld';
protected array $eventMaps = [
"torrent_created" => ['event' => TorrentCreated::class, 'model' => Torrent::class],
"torrent_updated" => ['event' => TorrentUpdated::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_disabled" => ['event' => UserDisabled::class, 'model' => User::class],
"user_enabled" => ['event' => UserEnabled::class, 'model' => User::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);
$log .= ", success call dispatch, result: " . var_export($result, true);
publish_model_event($name, $model->id);
} else {
$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 Filament\Notifications\Notification;
use GeoIp2\Database\Reader;
use GuzzleHttp\Client;
use Illuminate\Console\Command;
use Illuminate\Encryption\Encrypter;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Hash;
use Illuminate\Support\Facades\Http;
use Illuminate\Support\Facades\Redis;
use Illuminate\Support\Facades\Storage;
use Illuminate\Support\Str;
@@ -59,6 +61,7 @@ use NexusPlugin\Permission\Models\Role;
use NexusPlugin\PostLike\PostLikeRepository;
use NexusPlugin\StickyPromotion\Models\StickyPromotion;
use NexusPlugin\StickyPromotion\Models\StickyPromotionParticipator;
use NexusPlugin\Tracker\TrackerRepository;
use NexusPlugin\Work\Models\RoleWork;
use NexusPlugin\Work\WorkRepository;
use PhpIP\IP;
@@ -98,7 +101,8 @@ class Test extends Command
*/
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\CheckQueueFailedJobs;
use App\Jobs\MaintainPluginState;
use App\Jobs\ManagePlugin;
use App\Utils\ThirdPartyJob;
use Carbon\Carbon;
use Illuminate\Console\Scheduling\Event;
use Illuminate\Console\Scheduling\Schedule;
@@ -41,6 +44,8 @@ class Kernel extends ConsoleKernel
$schedule->command('meilisearch:import')->weeklyOn(1, "03:00")->withoutOverlapping();
$schedule->command('torrent:load_pieces_hash')->dailyAt("01:00")->withoutOverlapping();
$schedule->job(new CheckQueueFailedJobs())->everySixHours()->withoutOverlapping();
$schedule->job(new ThirdPartyJob())->everyMinute()->withoutOverlapping();
$schedule->job(new MaintainPluginState())->everyMinute()->withoutOverlapping();
$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
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
{
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 () {
do_log("cache_del: global_promotion_state");
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(),
])
@@ -117,9 +117,4 @@ class ViewExamUser extends ViewRecord
Actions\DeleteAction::make(),
];
}
private function getProgress()
{
}
}
+1 -1
View File
@@ -12,7 +12,7 @@ class TrustProxies extends Middleware
*
* @var array<int, string>|string|null
*/
protected $proxies;
protected $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\Foundation\Bus\Dispatchable;
use Illuminate\Queue\InteractsWithQueue;
use Illuminate\Queue\Middleware\WithoutOverlapping;
use Illuminate\Queue\SerializesModels;
use Nexus\Database\NexusDB;
use Nexus\Nexus;
@@ -55,6 +56,16 @@ class CalculateUserSeedBonus implements ShouldQueue
public $timeout = 3600;
/**
* 获取任务时,应该通过的中间件。
*
* @return array
*/
public function middleware()
{
return [new WithoutOverlapping($this->idRedisKey)];
}
/**
* Execute the job.
*
@@ -63,7 +74,11 @@ class CalculateUserSeedBonus implements ShouldQueue
public function handle()
{
$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');
$officialAdditionFactor = Setting::get('bonus.official_addition');
$donortimes_bonus = Setting::get('bonus.donortimes');
@@ -84,6 +99,8 @@ class CalculateUserSeedBonus implements ShouldQueue
$logFile = getLogFile("seed-bonus-points");
do_log("$logPrefix, [GET_UID_REAL], count: " . count($results) . ", logFile: $logFile");
$fd = fopen($logFile, 'a');
$seedPointsUpdates = $seedPointsPerHourUpdates = $seedBonusUpdates = [];
$logStr = "";
foreach ($results as $userInfo)
{
$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);
$all_bonus = $seedBonusResult['seed_bonus'];
$bonusLog .= ", all_bonus: $all_bonus";
if ($isDonor) {
if ($isDonor && $donortimes_bonus != 0) {
$all_bonus = $all_bonus * $donortimes_bonus;
$bonusLog .= ", isDonor, donortimes_bonus: $donortimes_bonus, all_bonus: $all_bonus";
}
@@ -112,13 +129,17 @@ class CalculateUserSeedBonus implements ShouldQueue
$all_bonus += $medalAddition;
$bonusLog .= ", medalAdditionFactor: {$seedBonusResult['medal_additional_factor']}, medalBonus: {$seedBonusResult['medal_bonus']}, medalAddition: $medalAddition, all_bonus: $all_bonus";
}
do_log($bonusLog);
$dividend = 3600 / $autoclean_interval_one;
$all_bonus = $all_bonus / $dividend;
$seed_points = $seedBonusResult['seed_points'] / $dividend;
$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";
do_log("$bonusLog, query: $sql");
NexusDB::statement($sql);
// $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";
// do_log("$bonusLog, query: $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) {
$log = sprintf(
'%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['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 {
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) {
NexusDB::cache_del($this->idRedisKey);
}
fwrite($fd, $logStr);
$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;
public $tries = 1;
public $timeout = 1800;
/**
* 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\Foundation\Bus\Dispatchable;
use Illuminate\Queue\InteractsWithQueue;
use Illuminate\Queue\Middleware\WithoutOverlapping;
use Illuminate\Queue\SerializesModels;
use Nexus\Database\NexusDB;
@@ -55,6 +56,16 @@ class UpdateTorrentSeedersEtc implements ShouldQueue
public $timeout = 1800;
/**
* 获取任务时,应该通过的中间件。
*
* @return array
*/
public function middleware()
{
return [new WithoutOverlapping($this->idRedisKey)];
}
/**
* Execute the job.
*
@@ -63,7 +74,11 @@ class UpdateTorrentSeedersEtc implements ShouldQueue
public function handle()
{
$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;
$delIdRedisKey = false;
@@ -76,44 +91,51 @@ class UpdateTorrentSeedersEtc implements ShouldQueue
return;
}
$torrentIdArr = explode(",", $idStr);
foreach ($torrentIdArr as $torrentId) {
if ($torrentId <= 0) {
continue;
}
$peerResult = NexusDB::table('peers')
->where('torrent', $torrentId)
->selectRaw("count(*) as count, seeder")
->groupBy('seeder')
->get()
;
$commentResult = NexusDB::table('comments')
->where('torrent',$torrentId)
->selectRaw("count(*) as count")
->first()
;
$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));
//批量取,简单化
$torrents = array();
// $res = sql_query("SELECT torrent, seeder, COUNT(*) AS c FROM peers GROUP BY torrent, seeder where torrent in ($idStr)");
$res = NexusDB::table("peers")
->selectRaw("torrent, seeder, COUNT(*) AS c")
->whereRaw("torrent in ($idStr)")
->groupBy(['torrent', 'seeder'])
->get();
foreach ($res as $row) {
if ($row->seeder == "yes")
$key = "seeders";
else
$key = "leechers";
$torrents[$row->torrent][$key] = $row->c;
}
// $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) {
NexusDB::cache_del($this->idRedisKey);
}
$costTime = time() - $beginTimestamp;
do_log(sprintf(
"$logPrefix, [DONE], update torrent count: %s, cost time: %s seconds",
count($torrentIdArr), $costTime
"$logPrefix, [DONE], update torrent count: %s, result: %s, cost time: %s seconds",
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\Foundation\Bus\Dispatchable;
use Illuminate\Queue\InteractsWithQueue;
use Illuminate\Queue\Middleware\WithoutOverlapping;
use Illuminate\Queue\SerializesModels;
use Nexus\Database\NexusDB;
@@ -55,6 +56,16 @@ class UpdateUserSeedingLeechingTime implements ShouldQueue
public $timeout = 3600;
/**
* 获取任务时,应该通过的中间件。
*
* @return array
*/
public function middleware()
{
return [new WithoutOverlapping($this->idRedisKey)];
}
/**
* Execute the job.
*
@@ -63,9 +74,12 @@ class UpdateUserSeedingLeechingTime implements ShouldQueue
public function handle()
{
$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;
$delIdRedisKey = false;
if (empty($idStr) && !empty($this->idRedisKey)) {
@@ -76,33 +90,35 @@ class UpdateUserSeedingLeechingTime implements ShouldQueue
do_log("$logPrefix, no idStr or idRedisKey", "error");
return;
}
$uidArr = explode(",", $idStr);
foreach ($uidArr as $uid) {
if ($uid <= 0) {
continue;
}
$sumInfo = NexusDB::table('snatched')
->selectRaw('sum(seedtime) as seedtime_sum, sum(leechtime) as leechtime_sum')
->where('userid', $uid)
->first();
if ($sumInfo && $sumInfo->seedtime_sum !== null) {
$update = [
'seedtime' => $sumInfo->seedtime_sum ?? 0,
'leechtime' => $sumInfo->leechtime_sum ?? 0,
'seed_time_updated_at' => Carbon::now()->toDateTimeString(),
];
NexusDB::table('users')
->where('id', $uid)
->update($update);
do_log("[CLEANUP_CLI_UPDATE_SEEDING_LEECHING_TIME_HANDLE_USER], [SUCCESS]: $uid => " . json_encode($update));
$count++;
}
//批量取,简单化
// $res = sql_query("select userid, sum(seedtime) as seedtime_sum, sum(leechtime) as leechtime_sum from snatched group by userid where userid in ($idStr)");
$res = NexusDB::table("snatched")
->selectRaw("userid, sum(seedtime) as seedtime_sum, sum(leechtime) as leechtime_sum")
->whereRaw("userid in ($idStr)")
->groupBy("userid")
->get();
$seedtimeUpdates = $leechTimeUpdates = [];
$nowStr = now()->toDateTimeString();
$count = 0;
foreach ($res as $row) {
$count++;
$seedtimeUpdates = sprintf("when %d then %d", $row->userid, $row->seedtime_sum ?? 0);
$leechTimeUpdates = sprintf("when %d then %d", $row->userid, $row->leechtime_sum ?? 0);
}
$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) {
NexusDB::cache_del($this->idRedisKey);
}
$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 = [
'username', 'email', 'passhash', 'secret', 'stylesheet', 'editsecret', 'added', 'modcomment', 'enabled', 'status',
'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 Illuminate\Support\Facades\App;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\URL;
use Illuminate\Support\Facades\View;
use Illuminate\Support\ServiceProvider;
use Illuminate\Http\Resources\Json\JsonResource;
@@ -37,8 +38,11 @@ class AppServiceProvider extends ServiceProvider
{
global $plugin;
$plugin->start();
// JsonResource::withoutWrapping();
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::registerNavigationGroups([
+4 -1
View File
@@ -169,7 +169,10 @@ for k, v in pairs(batchList) do
local isBatchKeyNew = false
if batchKey == false then
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
end
local hashKey
+11 -2
View File
@@ -9,6 +9,7 @@ use App\Models\User;
use Carbon\Carbon;
use Filament\Facades\Filament;
use Illuminate\Support\Facades\DB;
use Nexus\Database\NexusDB;
class DashboardRepository extends BaseRepository
{
@@ -51,18 +52,26 @@ class DashboardRepository extends BaseRepository
'text' => nexus_trans("dashboard.system_info.$name"),
'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] = [
'name' => $name,
'text' => nexus_trans("dashboard.system_info.$name"),
'value' => PHP_OS,
'value' => NexusDB::redis()->info()['redis_version'],
];
$name = 'server_software';
$result[$name] = [
'name' => $name,
'text' => nexus_trans("dashboard.system_info.$name"),
'value' => $_SERVER['SERVER_SOFTWARE'] ?? '',
];
$name = 'load_average';
$result[$name] = [
'name' => $name,
-28
View File
@@ -1327,32 +1327,4 @@ class ExamRepository extends BaseRepository
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);
$seedBoxRecord = SeedBoxRecord::query()->create($params);
$this->clearCache();
publish_model_event("seed_box_record_created", $seedBoxRecord->id);
return $seedBoxRecord;
}
@@ -85,6 +86,7 @@ class SeedBoxRepository extends BaseRepository
$params = $this->formatParams($params);
$model->update($params);
$this->clearCache();
publish_model_event("seed_box_record_updated", $id);
return $model;
}
+22
View File
@@ -1,6 +1,7 @@
<?php
namespace App\Repositories;
use App\Http\Middleware\Locale;
use App\Models\Invite;
use App\Models\Message;
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\Imdb\Imdb;
use Rhilip\Bencode\Bencode;
use Firebase\JWT\JWT;
use Firebase\JWT\Key;
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 BUY_STATUS_SUCCESS = 0;
const BUY_STATUS_NOT_YET = -1;
const BUY_STATUS_UNKNOWN = -2;
/**
* fetch torrent list
*
@@ -334,13 +344,23 @@ class TorrentRepository extends BaseRepository
public function encryptDownHash($id, $user): string
{
$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)
{
$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)
@@ -752,15 +772,94 @@ HTML;
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);
}
private function getBoughtUserCacheKey($torrentId): string
public function hasBuySuccessCache($uid, $torrentId): bool
{
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
+3 -2
View File
@@ -132,7 +132,8 @@ class UserRepository extends BaseRepository
'stylesheet' => $setting['defstylesheet'],
'added' => now()->toDateTimeString(),
'status' => User::STATUS_CONFIRMED,
'class' => $class
'class' => $class,
'passkey' => md5($username.date("Y-m-d H:i:s").$passhash)
];
$user = new User($data);
if (!empty($params['id'])) {
@@ -143,7 +144,7 @@ class UserRepository extends BaseRepository
$user->id = $params['id'];
}
$user->save();
fire_event("user_created", $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",
"imdbphp/imdbphp": "^7.0",
"irazasyed/telegram-bot-sdk": "^3.11",
"laravel/framework": "9.52.4",
"laravel/framework": "v9.52.17",
"laravel/octane": "^1.2",
"laravel/passport": "^11.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",
"This file is @generated automatically"
],
"content-hash": "2b89de67bf5d41d008100e25d21303b0",
"content-hash": "546ab4accfd6fa5ec14eeadfbc14e573",
"packages": [
{
"name": "akaunting/laravel-money",
@@ -3189,16 +3189,16 @@
},
{
"name": "laravel/framework",
"version": "v9.52.4",
"version": "v9.52.17",
"source": {
"type": "git",
"url": "https://github.com/laravel/framework.git",
"reference": "9239128cfb4d22afefb64060dfecf53e82987267"
"reference": "a069cf17e4943fb88d2a91c92690004fb3236dab"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/laravel/framework/zipball/9239128cfb4d22afefb64060dfecf53e82987267",
"reference": "9239128cfb4d22afefb64060dfecf53e82987267",
"url": "https://api.github.com/repos/laravel/framework/zipball/a069cf17e4943fb88d2a91c92690004fb3236dab",
"reference": "a069cf17e4943fb88d2a91c92690004fb3236dab",
"shasum": ""
},
"require": {
@@ -3295,7 +3295,7 @@
"league/flysystem-read-only": "^3.3",
"league/flysystem-sftp-v3": "^3.0",
"mockery/mockery": "^1.5.1",
"orchestra/testbench-core": "^7.16",
"orchestra/testbench-core": "^7.24",
"pda/pheanstalk": "^4.0",
"phpstan/phpdoc-parser": "^1.15",
"phpstan/phpstan": "^1.4.7",
@@ -3383,7 +3383,7 @@
"issues": "https://github.com/laravel/framework/issues",
"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",
@@ -13996,6 +13996,6 @@
"ext-xml": "*",
"ext-zend-opcache": "*"
},
"platform-dev": [],
"platform-dev": {},
"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
defined('VERSION_NUMBER') || define('VERSION_NUMBER', '1.8.13');
defined('RELEASE_DATE') || define('RELEASE_DATE', '2024-08-28');
defined('VERSION_NUMBER') || define('VERSION_NUMBER', '1.8.14');
defined('RELEASE_DATE') || define('RELEASE_DATE', '2024-11-08');
defined('IN_TRACKER') || define('IN_TRACKER', false);
defined('PROJECTNAME') || define("PROJECTNAME","NexusPHP");
defined('NEXUSPHPURL') || define("NEXUSPHPURL","https://nexusphp.org");
+12 -6
View File
@@ -818,7 +818,7 @@ function closeall() {
tagRemove = popstack(bbtags)
if ( (tagRemove != 'color') ) {
doInsert("[/"+tagRemove+"]", "", false);
eval("document.<?php echo $form?>." + tagRemove + ".value = ' " + tagRemove + " '");
eval("document.<?php echo $form?>." + tagRemove + ".value = ' " + tagRemove.toUpperCase() + " '");
eval(tagRemove + "_open = 0");
} else {
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'];
msgalert("messages.php",$text, "red");
}
\App\Utils\MsgAlert::getInstance()->render();
/*
$pending_invitee = $Cache->get_value('user_'.$CURUSER["id"].'_pending_invitee_count');
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.
print("<tr>\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");
$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>" : "");
@@ -5319,7 +5321,7 @@ function torrentTags($tags = 0, $type = 'checkbox')
return $html;
}
function saveSetting($prefix, $nameAndValue, $autoload = 'yes')
function saveSetting(string $prefix, array $nameAndValue, string $autoload = 'yes'): void
{
$prefix = strtolower($prefix);
$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")
{
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 />");
}
@@ -6078,7 +6084,7 @@ function calculate_seed_bonus($uid, $torrentIdArr = null): array
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",
$torrent['id'], $torrent['peerID'], $weeks_alive, $gb_size_raw, $gb_size, $temp, $officialAIncrease
));
), "debug");
}
if ($count > $maxseeding_bonus)
$count = $maxseeding_bonus;
@@ -6315,7 +6321,7 @@ function build_bonus_table(array $user, array $bonusResult = [], array $options
$isDonor = is_donor($user);
$donortimes_bonus = get_setting('bonus.donortimes');
$baseBonusFactor = 1;
if ($isDonor) {
if ($isDonor && $donortimes_bonus != 0) {
$baseBonusFactor = $donortimes_bonus;
}
$baseBonus = $bonusResult['seed_bonus'] * $baseBonusFactor;
+33 -3
View File
@@ -788,6 +788,15 @@ function get_user_id()
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()
{
if (IN_NEXUS) {
@@ -928,13 +937,13 @@ function getDataTraffic(array $torrent, array $queries, array $user, $peer, $sna
}
$uploaderRatio = get_setting('torrent.uploaderdouble');
$log .= ", uploaderRatio: $uploaderRatio";
if ($torrent['owner'] == $user['id']) {
if ($torrent['owner'] == $user['id'] && $uploaderRatio != 1) {
//uploader, use the bigger one
$upRatio = max($uploaderRatio, \App\Models\Torrent::$promotionTypes[$spStateReal]['up_multiplier']);
$log .= ", [IS_UPLOADER], upRatio: $upRatio";
$log .= ", [IS_UPLOADER] && uploaderRatio != 1, upRatio: $upRatio";
} else {
$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
@@ -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)));
}
/**
* 完整的 Laravel 事件, 在 php 端有监听者的需要触发. 同样会执行 publish_model_event()
*/
function fire_event(string $name, \Illuminate\Database\Eloquent\Model $model, \Illuminate\Database\Eloquent\Model $oldModel = null): void
{
$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);
}
/**
* 仅仅是往 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' => "主創: ",
'submit_search_at_shooter' => "搜索射手網",
'submit_search_at_opensubtitles' => "搜索Opensubtitles",
'title_show_or_hide' => "顯示&nbsp;或&nbsp;隱藏",
'title_bookmark' => "收藏",
'text_album_information' => "專輯資訊:",
'text_about_album' => "關于該專輯:",
+2 -2
View File
@@ -12,8 +12,8 @@ class DBMysqli implements DBInterface
if (mysqli_connect_errno()) {
throw new DatabaseException(mysqli_connect_error());
}
$mysqli->query("SET NAMES UTF8");
$mysqli->query("SET collation_connection = 'utf8_general_ci'");
$mysqli->set_charset("utf8mb4");
$mysqli->query("SET collation_connection = 'utf8mb4_unicode_ci'");
$mysqli->query("SET sql_mode=''");
$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]
);
}
/**
* @since 1.8.13
*/
$settingName = "__has_fix_exam_index_UPLOAD_TORRENT_COUNT";
$hasFixExamIndexUploadTorrentCount = get_setting($settingName, false);
if (!$hasFixExamIndexUploadTorrentCount) {
}
}
public function runExtraMigrate()
+15 -2
View File
@@ -2,9 +2,7 @@
namespace Nexus\Plugin;
use App\Repositories\BaseRepository;
use Illuminate\Support\Arr;
use Illuminate\Support\Facades\Artisan;
use Nexus\Database\NexusDB;
abstract class BasePlugin extends BaseRepository
{
@@ -44,4 +42,19 @@ abstract class BasePlugin extends BaseRepository
$pluginRoot = dirname($reflection->getFileName(), 2);
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']);
}
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
{
return self::$plugins[$id] ?? null;
+40 -64
View File
@@ -164,6 +164,13 @@ if (!$az) {
$redis->set("$passkeyInvalidKey:$passkey", TIMENOW, ['ex' => 24*3600]);
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);
unset($GLOBALS['CURUSER']);
$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] >= 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)
{
$ratio = (($az["downloaded"] > 0) ? ($az["uploaded"] / $az["downloaded"]) : 1);
@@ -451,42 +451,30 @@ if (!isset($self))
&& $torrent['owner'] != $userid
&& get_setting("torrent.paid_torrent_enabled") == "yes"
) {
$hasBuyCacheKey = \App\Repositories\TorrentRepository::BOUGHT_USER_CACHE_KEY_PREFIX . $torrentid;
$hasBuy = $redis->hGet($hasBuyCacheKey, $userid);
if ($hasBuy === false) {
//no cache
$lockName = "load_torrent_bought_user:$torrentid";
$loadBoughtLock = new \Nexus\Database\NexusLock($lockName, 300);
if ($loadBoughtLock->get()) {
//get lock, do load
executeCommand("torrent:load_bought_user $torrentid", "string", true, false);
} else {
do_log("can not get loadBoughtLock: $lockName", 'debug');
$torrentRep = new \App\Repositories\TorrentRepository();
$buyStatus = $torrentRep->getBuyStatus($userid, $torrentid);
if ($buyStatus > 0) {
do_log(sprintf("user: %v buy torrent %v fail count: %v", $userid, $torrentid, $buyStatus), "error");
if ($buyStatus > 3) {
//warn
\App\Utils\MsgAlert::getInstance()->add(
"announce_paid_torrent_too_many_times",
time() + 86400,
"announce to paid torrent and fail too many times, please make sure you have enough bonus!",
"",
"black"
);
}
//simple cache the hasBuy result
$hasBuy = \Nexus\Database\NexusDB::remember(sprintf("user_has_buy_torrent:%s:%s", $userid, $torrentid), 86400*10, function () use($userid, $torrentid) {
$exists = \App\Models\TorrentBuyLog::query()->where('uid', $userid)->where('torrent_id', $torrentid)->exists();
return intval($exists);
});
if ($buyStatus > 10) {
//disable download
(new \App\Repositories\UserRepository())->updateDownloadPrivileges(null, $userid, 'no', 'announce_paid_torrent_too_many_times');
}
warn("purchase fail, please try again later, please make sure you have enough bonus", 300);
}
if (!$hasBuy) {
$lock = new \Nexus\Database\NexusLock("buying_torrent:$userid", 5);
if (!$lock->get()) {
$msg = "buying torrent, wait!";
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);
}
if ($buyStatus == \App\Repositories\TorrentRepository::BUY_STATUS_UNKNOWN) {
//just enqueue job
\App\Utils\ThirdPartyJob::addBuyTorrent($userid, $torrentid);
warn("purchase in progress, please wait", 300);
}
}
}
@@ -535,7 +523,7 @@ if (isset($self) && $event == "stopped")
sql_query("DELETE FROM peers WHERE id = {$self['id']}") or err("D Err");
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;
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 ($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;
}
if (!empty($snatchInfo)) {
@@ -570,19 +558,7 @@ else
if ($event != 'stopped') {
$isPeerExistResultSet = sql_query("select id from peers where $selfwhere limit 1");
if (mysql_num_rows($isPeerExistResultSet) == 0) {
$cacheKey = 'peers:connectable:'.$ip.'-'.$port.'-'.$agent;
$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';
});
$connectable = "yes";
$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");
@@ -590,7 +566,7 @@ else
sql_query($insertPeerSql) or err("PL Err 2");
if (mysql_affected_rows())
{
// $updateset[] = ($seeder == "yes" ? "seeders = seeders + 1" : "leechers = leechers + 1");
$updateset[] = ($seeder == "yes" ? "seeders = seeders + 1" : "leechers = leechers + 1");
$hasChangeSeederLeecher = true;
// $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"));
@@ -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);
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);
$hrExists = \Nexus\Database\NexusDB::remember($hrCacheKey, 24*3600, function () use ($torrentid, $userid) {
return \App\Models\HitAndRun::query()->where("uid", $userid)->where("torrent_id", $torrentid)->exists();
$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() ? 1 : 0;
});
$hrLog .= ", hrExists: $hrExists";
if (!$hrExists) {
@@ -650,11 +626,11 @@ if (($left > 0 || $event == "completed") && $az['class'] < \App\Models\HitAndRun
do_log("$hrLog, not match", "debug");
}
}
if (isset($event) && !empty($event)) {
$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");
}
// revert to only increment/decrement
//if (isset($event) && !empty($event)) {
// $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");
//}
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)
{
$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'){
$hasthumb = true;
imagejpeg($thumb, $file_location.".".$ext.".thumb.jpg", $thumbquality_attachment);
+1 -1
View File
@@ -48,7 +48,7 @@ if ($_SERVER["REQUEST_METHOD"] == "POST")
if(!$orig)
stderr($lang_bitbucketupload['std_image_processing_failed'],$lang_bitbucketupload['std_sorry_the_uploaded']."$imgtypes[$it]".$lang_bitbucketupload['std_failed_processing']);
$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) {
case 1:
$ret = imagegif($thumb, $tgtfile);
-2
View File
@@ -7,8 +7,6 @@ loggedinorreturn();
stdhead($lang_contactstaff['head_contact_staff'], false);
begin_main_frame();
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");
end_compose();
print("</form>");
+2 -2
View File
@@ -6,7 +6,7 @@ require_once(get_langfile_path());
loggedinorreturn();
$id = intval($_GET["id"] ?? 0);
$customField = new \Nexus\Field\Field();
int_check($id);
int_check($id, true);
if (!isset($id) || !$id)
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);
$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);
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);
/*
+1 -1
View File
@@ -765,7 +765,7 @@ if ($action == "viewtopic")
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)
// 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)){
+1 -1
View File
@@ -259,7 +259,7 @@ function maketable($res, $mode = 'seeding')
return [$ret, $total_size];
}
$count = 0;
$torrentlist = "";
$torrentlist = $pagertop = $pagerbottom = "";
switch ($type)
{
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> ]";
}
}
$body = format_comment($message['msg'], false);
$body = format_comment($message['msg'], true);
//$body = htmlspecialchars_decode($body);
$added = $message['added'];
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);
$action = htmlspecialchars($_GET['action'] ?? '');
$do = htmlspecialchars($_GET['do'] ?? null);
$do = htmlspecialchars($_GET['do'] ?? '');
unset($msg);
if (isset($do)) {
if ($do == "upload")
@@ -398,7 +398,7 @@ for ($i=0; $i < count($allBonus); $i++)
elseif ($bonusarray['art'] == 'noad'){
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>");
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>");
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>");
@@ -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>");
if ($funboxvote_bonus > 0)
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)
print("<li>".$lang_mybonus['text_say_thanks'].$saythanks_bonus.$lang_mybonus['text_point'].add_s($saythanks_bonus)."</li>");
if ($receivethanks_bonus > 0)
@@ -611,6 +609,10 @@ if ($action == "exchange") {
else {
$upload = $CURUSER['uploaded'];
$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;
// 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]);
@@ -620,6 +622,10 @@ if ($action == "exchange") {
if($art == "traffic_downloaded") {
$downloaded = $CURUSER['downloaded'];
$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]);
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'];
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'];
print("<tr><td class=\"shoutrow\"><span class='date'>[".$time."]</span> ".
$del ." ". $username." " . format_comment($arr["text"],true,false,true,true,600,false,false)."
+3
View File
@@ -71,3 +71,6 @@ img.hitandrun {
.codemain>pre {
margin: 0;
}
.word-break-all {
word-break: break-all;
}
+3 -1
View File
@@ -151,6 +151,7 @@ $secret = mksecret();
$wantpasshash = md5($secret . $wantpassword . $secret);
$editsecret = ($verification == 'admin' ? '' : $secret);
$invite_count = (int) $invite_count;
$passkey = md5($wantusername.date("Y-m-d H:i:s").$wantpasshash);
$wantusername = sqlesc($wantusername);
$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)
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();
fire_event("user_created", \App\Models\User::query()->first($id, \App\Models\User::$commonFields));
$tmpInviteCount = get_setting('main.tmp_invite_count');
if ($tmpInviteCount > 0) {
$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
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);
$where .= ($where ? " AND " : "") . implode(" AND ", $wherea);
}
+3 -1
View File
@@ -702,7 +702,6 @@ $search_area = 0;
if (isset($searchstr))
{
if (!isset($_GET['notnewword']) || !$_GET['notnewword']){
insert_suggest($searchstr, $CURUSER['id']);
$notnewword="";
}
else{
@@ -956,6 +955,9 @@ do_log("[TORRENT_COUNT_SQL] $sql", 'debug');
if ($count)
{
if (isset($searchstr) && (!isset($_GET['notnewword']) || !$_GET['notnewword'])){
insert_suggest($searchstr, $CURUSER['id']);
}
if ($addparam != "")
{
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);
}
$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)
{
$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";
return $s;
}
$downloaders = array();
$seeders = array();
$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();
while ($subrow = mysql_fetch_array($subres)) {
if ($subrow["seeder"] == "yes")
$seeders[] = $subrow;
else
$downloaders[] = $subrow;
}
$downloaders = array();
$seeders = array();
$torrent = \App\Models\Torrent::query()->findOrFail($id, ['id', 'seeders', 'leechers']);
$seedersAndLeechers = apply_filter("torrent_seeder_leecher_list", [], $id);
if (isset($seedersAndLeechers['seeders'], $seedersAndLeechers['leechers'])) {
// dd($seedersAndLeechers);
$seeders = $seedersAndLeechers['seeders'];
$downloaders = $seedersAndLeechers['leechers'];
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);
$leechersCount = count($downloaders);
if ($torrent->seeders != $seedersCount || $torrent->leechers != $leechersCount) {
+1 -1
View File
@@ -53,7 +53,7 @@ if ($count){
}
else $username = get_username($arr['userid']);
$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($pagerbottom);
+1
View File
@@ -47,6 +47,7 @@ return [
'server_software' => 'Web software',
'load_average' => 'Server load average',
'filament_version' => 'Filament version',
'redis_version' => 'Redis version',
],
'latest_user' => [
'page_title' => 'User latest',
+4
View File
@@ -19,6 +19,10 @@ return [
'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.' ,
],
'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' => [
'subject' => 'Download permission restored',
'body' => 'Your download privileges restored, you can now download torrents. By: :operator',
+1
View File
@@ -47,6 +47,7 @@ return [
'server_software' => 'Web 软件',
'load_average' => '服务器平均负载',
'filament_version' => 'Filament 版本',
'redis_version' => 'Redis 版本',
],
'latest_user' => [
'page_title' => '最新用户',
+4
View File
@@ -19,6 +19,10 @@ return [
'subject' => '下载权限取消',
'body' => '你因上传速度过快下载权限被取消,若是盒子用户请备案。',
],
'download_disable_announce_paid_torrent_too_many_times' => [
'subject' => '下载权限取消',
'body' => '你因向付费种子汇报失败次数过多下载权限被取消,请确保你有足够的魔力。',
],
'download_enable' => [
'subject' => '下载权限恢复',
'body' => '你的下载权限恢复,你现在可以下载种子。By: :operator',
+1
View File
@@ -47,6 +47,7 @@ return [
'server_software' => 'Web 軟件',
'load_average' => '服務器平均負載',
'filament_version' => 'Filament 版本',
'redis_version' => 'Redis 版本',
],
'latest_user' => [
'page_title' => '最新用戶',
+4
View File
@@ -18,6 +18,10 @@ return [
'subject' => '下載權限取消',
'body' => '你因上傳速度過快下載權限被取消,若是盒子用戶請備案。',
],
'download_disable_announce_paid_torrent_too_many_times' => [
'subject' => '下载权限取消',
'body' => '你因向付費種子匯報失敗次數過多下載權限被取消,請確保你有足夠的魔力。',
],
'download_enable' => [
'subject' => '下載權限恢復',
'body' => '你的下載權限恢復,你現在可以下載種子。By: :operator',
@@ -20,7 +20,7 @@
colspan="3"
@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>
@endforeach
</tr>
+1 -1
View File
@@ -18,4 +18,4 @@ if ($uri !== '/' && file_exists(__DIR__.'/public'.$uri)) {
return false;
}
require_once __DIR__.'/public/index.php';
require_once __DIR__.'/public/nexus.php';