backend bonus log exclude seeding default

This commit is contained in:
xiaomlove
2025-09-17 04:05:36 +07:00
parent 74d722b301
commit 4009337133
16 changed files with 136 additions and 31 deletions

View File

@@ -15,6 +15,7 @@ use App\Models\User;
use App\Repositories\SearchBoxRepository; use App\Repositories\SearchBoxRepository;
use App\Repositories\TagRepository; use App\Repositories\TagRepository;
use App\Repositories\TorrentRepository; use App\Repositories\TorrentRepository;
use Elasticsearch\Endpoints\Search;
use Filament\Facades\Filament; use Filament\Facades\Filament;
use Filament\Forms; use Filament\Forms;
use Filament\Pages\Actions\Action; use Filament\Pages\Actions\Action;
@@ -302,7 +303,7 @@ class TorrentResource extends Resource
}) })
->deselectRecordsAfterCompletion(); ->deselectRecordsAfterCompletion();
} }
$actions[] = self::getBulkActionChangeCategory(); // $actions[] = self::getBulkActionChangeCategory();
if (user_can('torrent-delete')) { if (user_can('torrent-delete')) {
$actions[] = Tables\Actions\DeleteBulkAction::make('bulk-delete')->using(function (Collection $records) { $actions[] = Tables\Actions\DeleteBulkAction::make('bulk-delete')->using(function (Collection $records) {
@@ -357,7 +358,7 @@ class TorrentResource extends Resource
->helperText(new HtmlString(__('admin.resources.torrent.bulk_action_change_category_section_help'))) ->helperText(new HtmlString(__('admin.resources.torrent.bulk_action_change_category_section_help')))
->options(function() { ->options(function() {
$rep = new SearchBoxRepository(); $rep = new SearchBoxRepository();
$list = $rep->listSections(false); $list = $rep->listSections(SearchBox::listAllSectionId(), false);
$result = []; $result = [];
foreach ($list as $section) { foreach ($list as $section) {
$result[$section->id] = $section->displaySectionName; $result[$section->id] = $section->displaySectionName;
@@ -367,12 +368,12 @@ class TorrentResource extends Resource
->reactive() ->reactive()
->required() ->required()
, ,
$searchBoxRep->buildSearchBoxFormSchema(SearchBox::getBrowseSearchBox()) $searchBoxRep->buildSearchBoxFormSchema(SearchBox::getBrowseSearchBox(), 'section_info')
->hidden(function (Forms\Get $get) { ->hidden(function (Forms\Get $get) {
return $get('section_id') != SearchBox::getBrowseMode(); return $get('section_id') != SearchBox::getBrowseMode();
}) })
, ,
$searchBoxRep->buildSearchBoxFormSchema(SearchBox::getSpecialSearchBox()) $searchBoxRep->buildSearchBoxFormSchema(SearchBox::getSpecialSearchBox(), 'section_info')
->hidden(function (Forms\Get $get) { ->hidden(function (Forms\Get $get) {
return $get('section_id') != SearchBox::getSpecialMode(); return $get('section_id') != SearchBox::getSpecialMode();
}) })
@@ -381,8 +382,9 @@ class TorrentResource extends Resource
]) ])
->action(function (Collection $records, array $data) { ->action(function (Collection $records, array $data) {
$torrentRep = new TorrentRepository(); $torrentRep = new TorrentRepository();
$newSectionId = $data['section_id'];
try { try {
$torrentRep->changeCategory($records, $data['section_id'], $data['category_id']); $torrentRep->changeCategory($records, $newSectionId, $data['section_info']['section'][$newSectionId]);
} catch (\Exception $exception) { } catch (\Exception $exception) {
do_log($exception->getMessage(), 'error'); do_log($exception->getMessage(), 'error');
} }

View File

@@ -88,6 +88,16 @@ class BonusLogResource extends Resource
->options(BonusLogs::listStaticProps(BonusLogs::$businessTypes, 'bonus-log.business_types', true)) ->options(BonusLogs::listStaticProps(BonusLogs::$businessTypes, 'bonus-log.business_types', true))
->label(__('bonus-log.fields.business_type')) ->label(__('bonus-log.fields.business_type'))
, ,
Tables\Filters\Filter::make('exclude_seeding_bonus')
->toggle()
->label(__('bonus-log.exclude_seeding_bonus'))
->query(function (Builder $query, array $data) {
if ($data['isActive']) {
$query->whereNotIn("business_type", BonusLogs::$businessTypeBonus);
}
})
->default()
,
]) ])
->actions([ ->actions([
// Tables\Actions\EditAction::make(), // Tables\Actions\EditAction::make(),

View File

@@ -2,8 +2,10 @@
namespace App\Http\Controllers; namespace App\Http\Controllers;
use App\Auth\Permission;
use App\Http\Resources\SearchBoxResource; use App\Http\Resources\SearchBoxResource;
use App\Http\Resources\TorrentResource; use App\Http\Resources\TorrentResource;
use App\Models\SearchBox;
use App\Repositories\SearchBoxRepository; use App\Repositories\SearchBoxRepository;
use App\Repositories\UploadRepository; use App\Repositories\UploadRepository;
use Illuminate\Http\Request; use Illuminate\Http\Request;
@@ -22,7 +24,7 @@ class UploadController extends Controller
public function sections(Request $request) public function sections(Request $request)
{ {
$sections = $this->searchBoxRepository->listSections(); $sections = $this->searchBoxRepository->listSections(SearchBox::listAuthorizedSectionId());
$resource = SearchBoxResource::collection($sections); $resource = SearchBoxResource::collection($sections);
return $this->success($resource); return $this->success($resource);
} }

View File

@@ -0,0 +1,23 @@
<?php
namespace App\Http\Resources;
use Illuminate\Http\Resources\Json\JsonResource;
class BookmarkResource extends JsonResource
{
/**
* Transform the resource into an array.
*
* @param \Illuminate\Http\Request $request
* @return array
*/
public function toArray($request)
{
return [
'id' => $this->id,
'torrent_id' => $this->torrentid,
'user_id' => $this->userid,
];
}
}

View File

@@ -96,6 +96,14 @@ class BonusLogs extends NexusModel
self::BUSINESS_TYPE_SEEDING_MEDAL_ADDITION => ['text' => 'Seeding medal addition'], self::BUSINESS_TYPE_SEEDING_MEDAL_ADDITION => ['text' => 'Seeding medal addition'],
]; ];
public static array $businessTypeBonus = [
self::BUSINESS_TYPE_SEEDING_BASIC,
self::BUSINESS_TYPE_SEEDING_DONOR_ADDITION,
self::BUSINESS_TYPE_SEEDING_OFFICIAL_ADDITION,
self::BUSINESS_TYPE_SEEDING_HAREM_ADDITION,
self::BUSINESS_TYPE_SEEDING_MEDAL_ADDITION
];
public function getBusinessTypeTextAttribute() public function getBusinessTypeTextAttribute()
{ {
return nexus_trans('bonus-log.business_types.' . $this->business_type); return nexus_trans('bonus-log.business_types.' . $this->business_type);

View File

@@ -113,6 +113,10 @@ class HitAndRun extends NexusModel
do_log(sprintf('[INVALID_CATEGORY], Torrent: %s', $this->torrent_id), 'error'); do_log(sprintf('[INVALID_CATEGORY], Torrent: %s', $this->torrent_id), 'error');
return '---'; return '---';
} }
if (!$this->snatch) {
do_log("hit and run: {$this->id} no snatch", 'warning');
return '---';
}
$seedTimeMinimum = HitAndRun::getConfig('seed_time_minimum', $searchBoxId); $seedTimeMinimum = HitAndRun::getConfig('seed_time_minimum', $searchBoxId);
$diffInSeconds = 3600 * $seedTimeMinimum - $this->snatch->seedtime; $diffInSeconds = 3600 * $seedTimeMinimum - $this->snatch->seedtime;
return mkprettytime($diffInSeconds); return mkprettytime($diffInSeconds);

View File

@@ -158,8 +158,8 @@ class SearchBox extends NexusModel
} }
$table = self::$taxonomies[$torrentField]['table']; $table = self::$taxonomies[$torrentField]['table'];
return NexusDB::table($table)->where(function (Builder $query) use ($searchBox) { return NexusDB::table($table)->where(function (Builder $query) use ($searchBox) {
return $query->where('mode', $searchBox->id)->orWhere('mode', 0); return $query->whereIn('mode', [$searchBox->id, 0]);
})->orderBy('sort_index')->orderBy('id')->get(); })->orderBy('sort_index', 'desc')->orderBy('id', 'desc')->get();
} }
public static function listModeOptions(): array public static function listModeOptions(): array
@@ -301,8 +301,8 @@ class SearchBox extends NexusModel
$this->setRelation( $this->setRelation(
$relationName, $relationName,
$modelName::query()->whereIn('mode', [$this->getKey(), 0]) $modelName::query()->whereIn('mode', [$this->getKey(), 0])
->orderBy('sort_index') ->orderBy('sort_index', 'desc')
->orderBy('id') ->orderBy('id', 'desc')
->get() ->get()
); );
} }
@@ -367,4 +367,22 @@ class SearchBox extends NexusModel
return $results; return $results;
} }
public static function listAuthorizedSectionId(): array
{
$modeIds = [self::getBrowseMode()];
if (self::isSpecialEnabled() && Permission::canViewSpecialSection()) {
$modeIds[] = self::getSpecialMode();
}
return $modeIds;
}
public static function listAllSectionId(): array
{
$modeIds = [self::getBrowseMode()];
if (self::isSpecialEnabled()) {
$modeIds[] = self::getSpecialMode();
}
return $modeIds;
}
} }

View File

@@ -242,13 +242,9 @@ class SearchBoxRepository extends BaseRepository
return Category::query()->whereIn('id', $idArr)->delete(); return Category::query()->whereIn('id', $idArr)->delete();
} }
public function listSections($withCategoryAndTags = true) public function listSections($id, $withCategoryAndTags = true)
{ {
$modeIds = [SearchBox::getBrowseMode()]; $searchBoxList = SearchBox::query()->with($withCategoryAndTags ? ['categories'] : [])->find($id);
if (SearchBox::isSpecialEnabled() && Permission::canUploadToSpecialSection()) {
$modeIds[] = SearchBox::getSpecialMode();
}
$searchBoxList = SearchBox::query()->with($withCategoryAndTags ? ['categories'] : [])->find($modeIds);
if ($withCategoryAndTags) { if ($withCategoryAndTags) {
foreach ($searchBoxList as $searchBox) { foreach ($searchBoxList as $searchBox) {
if ($searchBox->showsubcat) { if ($searchBox->showsubcat) {
@@ -260,7 +256,7 @@ class SearchBoxRepository extends BaseRepository
return $searchBoxList; return $searchBoxList;
} }
public function buildSearchBoxFormSchema(SearchBox $searchBox, string $namePrefix = ""): Forms\Components\Section public function buildSearchBoxFormSchema(SearchBox $searchBox, string $namePrefix): Forms\Components\Section
{ {
$lang = get_langfolder_cookie(); $lang = get_langfolder_cookie();
$heading = $searchBox->section_name[$lang] ?? nexus_trans('searchbox.sections.browse'); $heading = $searchBox->section_name[$lang] ?? nexus_trans('searchbox.sections.browse');

View File

@@ -1113,16 +1113,55 @@ HTML;
} }
} }
public function changeCategory(Collection $torrents, int $sectionId, int $categoryId): void public function changeCategory(Collection $torrents, int $sectionId, array $specificSubCategoryAndTags): void
{ {
assert_has_permission(Permission::canManageTorrent()); assert_has_permission(Permission::canManageTorrent());
$searchBox = SearchBox::query()->findOrFail($sectionId);
$category = $searchBox->categories()->findOrFail($categoryId);
$torrentIdArr = $torrents->pluck('id')->toArray(); $torrentIdArr = $torrents->pluck('id')->toArray();
if (empty($torrentIdArr)) { if (empty($torrentIdArr)) {
do_log("torrents is empty", 'warn'); do_log("torrents is empty", 'warn');
return; return;
} }
$torrentIdStr = implode(',', $torrentIdArr);
do_log("torrentIdStr: $torrentIdStr, sectionId: $sectionId");
$searchBoxRep = new SearchBoxRepository();
$sections = $searchBoxRep->listSections(SearchBox::listAllSectionId(), true)->keyBy('id');
if (!$sections->has($sectionId)) {
throw new NexusException(nexus_trans('upload.invalid_section'));
}
/**
* @var $section SearchBox
*/
$section = $sections->get($sectionId);
$validCategoryIdArr = $section->categories->pluck('id')->toArray();
if (!empty($specificSubCategoryAndTags['category']) && !in_array($specificSubCategoryAndTags['category'], $validCategoryIdArr)) {
throw new NexusException(nexus_trans('upload.invalid_category'));
}
$baseUpdateQuery = Torrent::query()->whereIn('id', $torrentIdArr);
$updateCategoryQuery = $baseUpdateQuery->clone();
if (!empty($validCategoryId)) {
$updateCategoryQuery->whereNotIn('category', $validCategoryIdArr);
}
$updateCategoryResult = $updateCategoryQuery->update(['category' => 0]);
do_log(sprintf("update category = 0 when category not in: %s, result: %s", implode(', ', $validCategoryIdArr), $updateCategoryResult));
foreach (SearchBox::$taxonomies as $name => $info) {
$relationName = "taxonomy_{$name}";
$relation = $section->{$relationName};
if (empty($specificSubCategoryAndTags[$name])) {
continue;
}
//有指定,看是否有效
if (!$relation) {
do_log("searchBox: {$section->id} no relation of $name");
throw new NexusException(nexus_trans('upload.not_supported_sub_category_field', ['field' => $name]));
}
$validIdArr = $relation->pluck('id')->toArray();
if (!in_array($specificSubCategoryAndTags[$name], $validIdArr)) {
do_log("taxonomy {$name}, specific: {$specificSubCategoryAndTags[$name]} not in validIdArr: " . implode(', ', $validIdArr));
throw new NexusException(nexus_trans('upload.not_supported_sub_category_field', ['field' => $name]));
}
}
$operatorId = get_user_id(); $operatorId = get_user_id();
$siteLogArr = []; $siteLogArr = [];
foreach ($torrents as $torrent) { foreach ($torrents as $torrent) {
@@ -1139,7 +1178,7 @@ HTML;
foreach ($torrents as $torrent) { foreach ($torrents as $torrent) {
fire_event(ModelEventEnum::TORRENT_UPDATED, $torrent); fire_event(ModelEventEnum::TORRENT_UPDATED, $torrent);
} }
do_log("success change torrent category to $categoryId, torrent count:" . $torrents->count()); do_log("success change to section $sectionId, torrent count:" . $torrents->count());
} }
} }

View File

@@ -440,7 +440,7 @@ class UploadRepository extends BaseRepository
private function getSubCategoriesAndTags(Request $request, Category $category): array private function getSubCategoriesAndTags(Request $request, Category $category): array
{ {
$searchBoxRep = new SearchBoxRepository(); $searchBoxRep = new SearchBoxRepository();
$sections = $searchBoxRep->listSections()->keyBy('id'); $sections = $searchBoxRep->listSections(SearchBox::listAllSectionId())->keyBy('id');
if (!$sections->has($category->mode)) { if (!$sections->has($category->mode)) {
throw new NexusException(nexus_trans('upload.invalid_section')); throw new NexusException(nexus_trans('upload.invalid_section'));
} }

View File

@@ -1,6 +1,6 @@
<?php <?php
defined('VERSION_NUMBER') || define('VERSION_NUMBER', '1.9.7'); defined('VERSION_NUMBER') || define('VERSION_NUMBER', '1.9.7');
defined('RELEASE_DATE') || define('RELEASE_DATE', '2025-09-15'); defined('RELEASE_DATE') || define('RELEASE_DATE', '2025-09-17');
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");

View File

@@ -6300,25 +6300,24 @@ function build_bonus_table(array $user, array $bonusResult = [], array $options
$baseBonusFactor = $donortimes_bonus; $baseBonusFactor = $donortimes_bonus;
} }
$baseBonus = $bonusResult['seed_bonus'] * $baseBonusFactor; $baseBonus = $bonusResult['seed_bonus'] * $baseBonusFactor;
$totalBonus = $baseBonus $totalBonus = $baseBonus;
+ $haremAddition * $haremFactor
+ $bonusResult['official_bonus'] * $officialAdditionalFactor
+ $bonusResult['medal_bonus'] * $bonusResult['medal_additional_factor']
;
$rowSpan = 1; $rowSpan = 1;
$hasHaremAddition = $hasOfficialAddition = $hasMedalAddition = false; $hasHaremAddition = $hasOfficialAddition = $hasMedalAddition = false;
if ($haremFactor > 0) { if ($haremFactor > 0) {
$rowSpan++; $rowSpan++;
$hasHaremAddition = true; $hasHaremAddition = true;
$totalBonus += $haremAddition * $haremFactor;
} }
if ($officialAdditionalFactor > 0 && $officialTag) { if ($officialAdditionalFactor > 0 && $officialTag) {
$rowSpan++; $rowSpan++;
$hasOfficialAddition = true; $hasOfficialAddition = true;
$totalBonus += $bonusResult['official_bonus'] * $officialAdditionalFactor;
} }
if ($bonusResult['medal_additional_factor'] > 0) { if ($bonusResult['medal_additional_factor'] > 0) {
$rowSpan++; $rowSpan++;
$hasMedalAddition = true; $hasMedalAddition = true;
$totalBonus += $bonusResult['medal_bonus'] * $bonusResult['medal_additional_factor'];
} }
$table = sprintf('<table cellpadding="5" style="%s">', $options['table_style'] ?? ''); $table = sprintf('<table cellpadding="5" style="%s">', $options['table_style'] ?? '');

View File

@@ -501,16 +501,17 @@ if (user_can('prfmanage') && $user["class"] < get_user_class())
->orderBy("id", "desc") ->orderBy("id", "desc")
->limit(20) ->limit(20)
->get() ->get()
->map(fn ($item) => sprintf("%s - %s", $item->created_at->format("Y-m-d"), $item->content)) ->map(fn ($item) => sprintf("[%s] %s", $item->created_at->format("Y-m-d"), $item->content))
->implode("content", "\n") ->implode("\n")
; ;
tr($lang_userdetails['row_comment'], "<textarea cols=\"60\" rows=\"6\" name=\"modcomment\">".$modcomment."</textarea>", 1); tr($lang_userdetails['row_comment'], "<textarea cols=\"60\" rows=\"6\" name=\"modcomment\">".$modcomment."</textarea>", 1);
$bonuscomment = \App\Models\BonusLogs::query() $bonuscomment = \App\Models\BonusLogs::query()
->where("uid", $user["id"]) ->where("uid", $user["id"])
->whereNotIn("business_type", \App\Models\BonusLogs::$businessTypeBonus)
->orderBy("id", "desc") ->orderBy("id", "desc")
->limit(20) ->limit(20)
->get() ->get()
->map(fn ($item) => sprintf("%s - %s", $item->created_at->format("Y-m-d"), $item->comment)) ->map(fn ($item) => sprintf("[%s] %s", $item->created_at->format("Y-m-d"), $item->comment))
->implode("\n") ->implode("\n")
; ;
tr($lang_userdetails['row_seeding_karma'], "<textarea cols=\"60\" rows=\"6\" name=\"bonuscomment\" readonly=\"readonly\">".$bonuscomment."</textarea>", 1); tr($lang_userdetails['row_seeding_karma'], "<textarea cols=\"60\" rows=\"6\" name=\"bonuscomment\" readonly=\"readonly\">".$bonuscomment."</textarea>", 1);

View File

@@ -42,4 +42,5 @@ return [
'value' => 'Trade value', 'value' => 'Trade value',
'new_total_value' => 'Post-trade value', 'new_total_value' => 'Post-trade value',
], ],
'exclude_seeding_bonus' => 'Exclude seeding bonus',
]; ];

View File

@@ -44,4 +44,5 @@ return [
'value' => '交易值', 'value' => '交易值',
'new_total_value' => '交易后值', 'new_total_value' => '交易后值',
], ],
'exclude_seeding_bonus' => '不包含做种魔力',
]; ];

View File

@@ -42,4 +42,5 @@ return [
'value' => '交易值', 'value' => '交易值',
'new_total_value' => '交易後值', 'new_total_value' => '交易後值',
], ],
'exclude_seeding_bonus' => '不包含做種魔力',
]; ];