From 2511933033650d565c0434eb4289f4b86b1e6109 Mon Sep 17 00:00:00 2001 From: xiaomlove Date: Wed, 7 Sep 2022 20:36:41 +0800 Subject: [PATCH 01/12] update topten+staff+log menu visibility --- include/constants.php | 2 +- include/functions.php | 14 ++++++++++---- public/staff.php | 5 +---- 3 files changed, 12 insertions(+), 9 deletions(-) diff --git a/include/constants.php b/include/constants.php index 07693973..230be357 100644 --- a/include/constants.php +++ b/include/constants.php @@ -1,6 +1,6 @@ ".$lang_functions['text_forums'].""); print ("".$lang_functions['text_torrents'].""); - if ($enablespecial == 'yes' && get_user_class() >= get_setting('authority.view_special_torrent')) + if ($enablespecial == 'yes' && user_can('view_special_torrent')) print ("".$lang_functions['text_special'].""); if ($enableoffer == 'yes') print ("".$lang_functions['text_offers'].""); @@ -2307,11 +2307,17 @@ function menu ($selected = "home") { print ("".$lang_functions['text_upload'].""); print ("".$lang_functions['text_subtitles'].""); // print ("".$lang_functions['text_user_cp'].""); - print ("".$lang_functions['text_top_ten'].""); - print ("".$lang_functions['text_log'].""); + if (user_can('topten')) { + print ("".$lang_functions['text_top_ten'].""); + } + if (user_can('log')) { + print ("".$lang_functions['text_log'].""); + } print ("".$lang_functions['text_rules'].""); print ("".$lang_functions['text_faq'].""); - print ("".$lang_functions['text_staff'].""); + if (user_can('staffmem')) { + print ("".$lang_functions['text_staff'].""); + } print ("".$lang_functions['text_contactstaff'].""); print (""); } diff --git a/public/staff.php b/public/staff.php index c34d3d6a..ee4dbef8 100644 --- a/public/staff.php +++ b/public/staff.php @@ -3,10 +3,7 @@ require "../include/bittorrent.php"; dbconn(); require_once(get_langfile_path()); loggedinorreturn(true); -if (get_user_class() < UC_VIP) -{ - stderr($lang_staff['std_sorry'],$lang_staff['std_permission_denied_only'].get_user_class_name(UC_VIP,false,true,true).$lang_staff['std_or_above_can_view'],false); -} +user_can('staffmem', true); stdhead($lang_staff['head_staff']); $Cache->new_page('staff_page', 900, true); From 21d93cbc0b8d4bb90093c4db878f575a686c9755 Mon Sep 17 00:00:00 2001 From: xiaomlove Date: Thu, 8 Sep 2022 01:42:59 +0800 Subject: [PATCH 02/12] fix grant props --- .../User/UserResource/Pages/UserProfile.php | 4 ++- include/constants.php | 2 +- public/getusertorrentlistajax.php | 29 ++++++++++++++----- resources/lang/en/claim.php | 2 ++ resources/lang/zh_CN/claim.php | 2 ++ resources/lang/zh_TW/claim.php | 2 ++ 6 files changed, 31 insertions(+), 10 deletions(-) diff --git a/app/Filament/Resources/User/UserResource/Pages/UserProfile.php b/app/Filament/Resources/User/UserResource/Pages/UserProfile.php index 7071dbc8..c447e847 100644 --- a/app/Filament/Resources/User/UserResource/Pages/UserProfile.php +++ b/app/Filament/Resources/User/UserResource/Pages/UserProfile.php @@ -287,8 +287,10 @@ class UserProfile extends Page try { if (!empty($data['duration'])) { $data['deadline'] = now()->addDays($data['duration']); + } else { + $data['deadline'] = null; } - $rep->addMeta($this->record, $data); + $rep->addMeta($this->record, $data, $data); $this->notify('success', 'Success!'); $this->emitSelf(self::EVENT_RECORD_UPDATED, $this->record->id); } catch (\Exception $exception) { diff --git a/include/constants.php b/include/constants.php index 230be357..f6b978e2 100644 --- a/include/constants.php +++ b/include/constants.php @@ -1,6 +1,6 @@ ".$arr['anonymous'].""; $claimButton = ''; - if ($showActionClaim && \App\Models\Claim::getConfigIsEnabled() && \Carbon\Carbon::parse($arr['added'])->addDays($claimTorrentTTL)->lte(\Carbon\Carbon::now())) { - $claim = $claimData->get($arr['torrent']); - $claimButton = $claimRep->buildActionButtons($arr['torrent'], $claim); + if ( + $showActionClaim + && \App\Models\Claim::getConfigIsEnabled() + && \Carbon\Carbon::parse($arr['added'])->addDays($claimTorrentTTL)->lte(\Carbon\Carbon::now()) + ) { + $claim = $claimData->get($arr['torrent']); + if ($CURUSER['id'] == $arr['userid']) { + $claimButton = $claimRep->buildActionButtons($arr['torrent'], $claim); + } else { + if ($claim) { + $claimText = nexus_trans('claim.already_claimed'); + } else { + $claimText = nexus_trans('claim.not_claim_yet'); + } + $claimButton = sprintf('', $claimText); + } } $ret .= sprintf('%s', $claimButton); $ret .="\n"; @@ -234,7 +247,7 @@ switch ($type) { // $res = sql_query("SELECT torrents.id AS torrent, torrents.name as torrentname, small_descr, seeders, leechers, anonymous, torrents.banned, torrents.approval_status, categories.name AS catname, categories.image, category, sp_state, size, torrents.hr, snatched.seedtime, snatched.uploaded FROM torrents LEFT JOIN snatched ON torrents.id = snatched.torrentid LEFT JOIN categories ON torrents.category = categories.id WHERE torrents.owner=$id AND snatched.userid=$id " . (($CURUSER["id"] != $id)?((get_user_class() < $viewanonymous_class) ? " AND anonymous = 'no'":""):"") ." ORDER BY torrents.added DESC") or sqlerr(__FILE__, __LINE__); // $res = sql_query("SELECT torrents.id AS torrent, torrents.name as torrentname, small_descr, seeders, leechers, anonymous, torrents.banned, torrents.approval_status, categories.name AS catname, categories.image, category, sp_state, size, torrents.hr, torrents.added FROM torrents LEFT JOIN categories ON torrents.category = categories.id WHERE torrents.owner=$id " . (($CURUSER["id"] != $id)?((!user_can('viewanonymous')) ? " AND anonymous = 'no'":""):"") ." ORDER BY torrents.id DESC") or sqlerr(__FILE__, __LINE__); - $fields = "torrents.id AS torrent, torrents.name as torrentname, small_descr, seeders, leechers, anonymous, torrents.banned, torrents.approval_status, categories.name AS catname, categories.image, category, sp_state, size, torrents.hr, torrents.added"; + $fields = "torrents.id AS torrent, torrents.name as torrentname, small_descr, seeders, leechers, anonymous, torrents.banned, torrents.approval_status, categories.name AS catname, categories.image, category, sp_state, size, torrents.hr, torrents.added,torrents.owner as userid"; $tableWhere = "torrents LEFT JOIN categories ON torrents.category = categories.id WHERE torrents.owner=$id"; if ($CURUSER['id'] != $id && !user_can('viewanonymous')) { $tableWhere .= " AND anonymous = 'no'"; @@ -247,7 +260,7 @@ switch ($type) case 'seeding': { // $res = sql_query("SELECT torrent,added,snatched.uploaded,snatched.downloaded,torrents.name as torrentname, torrents.small_descr, torrents.sp_state, torrents.banned, torrents.approval_status, categories.name as catname,size,torrents.hr,image,category,seeders,leechers FROM peers LEFT JOIN torrents ON peers.torrent = torrents.id LEFT JOIN categories ON torrents.category = categories.id LEFT JOIN snatched ON torrents.id = snatched.torrentid WHERE peers.userid=$id AND snatched.userid = $id AND peers.seeder='yes' ORDER BY torrents.id DESC") or sqlerr(); - $fields = "torrent,added,snatched.uploaded,snatched.downloaded,torrents.name as torrentname, torrents.small_descr, torrents.sp_state, torrents.banned, torrents.approval_status, categories.name as catname,size,torrents.hr,image,category,seeders,leechers,snatched.seedtime,snatched.uploaded"; + $fields = "torrent,added,snatched.uploaded,snatched.downloaded,torrents.name as torrentname, torrents.small_descr, torrents.sp_state, torrents.banned, torrents.approval_status, categories.name as catname,size,torrents.hr,image,category,seeders,leechers,snatched.seedtime,snatched.uploaded,snatched.userid"; $tableWhere = "peers LEFT JOIN torrents ON peers.torrent = torrents.id LEFT JOIN categories ON torrents.category = categories.id LEFT JOIN snatched ON torrents.id = snatched.torrentid WHERE peers.userid=$id AND snatched.userid = $id AND peers.seeder='yes'"; $order = "torrents.id DESC"; break; @@ -257,7 +270,7 @@ switch ($type) case 'leeching': { // $res = sql_query("SELECT torrent,snatched.uploaded,snatched.downloaded,torrents.name as torrentname, torrents.small_descr, torrents.sp_state, torrents.banned, torrents.approval_status, categories.name as catname,size,torrents.hr,image,category,seeders,leechers, torrents.added FROM peers LEFT JOIN torrents ON peers.torrent = torrents.id LEFT JOIN categories ON torrents.category = categories.id LEFT JOIN snatched ON torrents.id = snatched.torrentid WHERE peers.userid=$id AND snatched.userid = $id AND peers.seeder='no' ORDER BY torrents.id DESC") or sqlerr(); - $fields = "torrent,snatched.uploaded,snatched.downloaded,torrents.name as torrentname, torrents.small_descr, torrents.sp_state, torrents.banned, torrents.approval_status, categories.name as catname,size,torrents.hr,image,category,seeders,leechers, torrents.added,snatched.seedtime,snatched.uploaded"; + $fields = "torrent,snatched.uploaded,snatched.downloaded,torrents.name as torrentname, torrents.small_descr, torrents.sp_state, torrents.banned, torrents.approval_status, categories.name as catname,size,torrents.hr,image,category,seeders,leechers, torrents.added,snatched.seedtime,snatched.uploaded,snatched.userid"; $tableWhere = "peers LEFT JOIN torrents ON peers.torrent = torrents.id LEFT JOIN categories ON torrents.category = categories.id LEFT JOIN snatched ON torrents.id = snatched.torrentid WHERE peers.userid=$id AND snatched.userid = $id AND peers.seeder='no'"; $order = "torrents.id DESC"; break; @@ -267,7 +280,7 @@ switch ($type) case 'completed': { // $res = sql_query("SELECT torrents.id AS torrent, torrents.name AS torrentname, small_descr, categories.name AS catname, torrents.banned, torrents.approval_status, categories.image, category, sp_state, size, torrents.hr, torrents.added,snatched.uploaded, snatched.seedtime, snatched.leechtime, snatched.completedat FROM torrents LEFT JOIN snatched ON torrents.id = snatched.torrentid LEFT JOIN categories on torrents.category = categories.id WHERE snatched.finished='yes' AND torrents.owner != $id AND userid=$id ORDER BY snatched.id DESC") or sqlerr(); - $fields = "torrents.id AS torrent, torrents.name AS torrentname, small_descr, categories.name AS catname, torrents.banned, torrents.approval_status, categories.image, category, sp_state, size, torrents.hr, torrents.added,snatched.uploaded, snatched.seedtime,snatched.uploaded, snatched.leechtime, snatched.completedat"; + $fields = "torrents.id AS torrent, torrents.name AS torrentname, small_descr, categories.name AS catname, torrents.banned, torrents.approval_status, categories.image, category, sp_state, size, torrents.hr, torrents.added,snatched.uploaded, snatched.seedtime,snatched.uploaded, snatched.leechtime, snatched.completedat,snatched.userid"; $tableWhere = "torrents LEFT JOIN snatched ON torrents.id = snatched.torrentid LEFT JOIN categories on torrents.category = categories.id WHERE snatched.finished='yes' AND userid=$id AND torrents.owner != $id"; $order = "snatched.id DESC"; break; @@ -277,7 +290,7 @@ switch ($type) case 'incomplete': { // $res = sql_query("SELECT torrents.id AS torrent, torrents.name AS torrentname, small_descr, torrents.banned, torrents.approval_status, categories.name AS catname, categories.image, category, sp_state, size, torrents.hr, torrents.added,snatched.uploaded, snatched.downloaded, snatched.leechtime FROM torrents LEFT JOIN snatched ON torrents.id = snatched.torrentid LEFT JOIN categories on torrents.category = categories.id WHERE snatched.finished='no' AND userid=$id AND torrents.owner != $id ORDER BY snatched.id DESC") or sqlerr(); - $fields = "torrents.id AS torrent, torrents.name AS torrentname, small_descr, torrents.banned, torrents.approval_status, categories.name AS catname, categories.image, category, sp_state, size, torrents.hr, torrents.added,snatched.uploaded, snatched.downloaded, snatched.leechtime,snatched.seedtime,snatched.uploaded"; + $fields = "torrents.id AS torrent, torrents.name AS torrentname, small_descr, torrents.banned, torrents.approval_status, categories.name AS catname, categories.image, category, sp_state, size, torrents.hr, torrents.added,snatched.uploaded, snatched.downloaded, snatched.leechtime,snatched.seedtime,snatched.uploaded,snatched.userid"; $tableWhere = "torrents LEFT JOIN snatched ON torrents.id = snatched.torrentid LEFT JOIN categories on torrents.category = categories.id WHERE snatched.finished='no' AND userid=$id AND torrents.owner != $id"; $order = "snatched.id DESC"; break; diff --git a/resources/lang/en/claim.php b/resources/lang/en/claim.php index 9a465baa..a0f3d0e9 100644 --- a/resources/lang/en/claim.php +++ b/resources/lang/en/claim.php @@ -29,4 +29,6 @@ return [ 'add_claim_confirm' => 'Confirm to claim?', 'remove_claim' => 'Give up', 'remove_claim_confirm' => 'Confirm to give up the claim?', + 'already_claimed' => 'Claimed', + 'not_claim_yet' => 'Unclaimed', ]; diff --git a/resources/lang/zh_CN/claim.php b/resources/lang/zh_CN/claim.php index 925b306e..1f510b5a 100644 --- a/resources/lang/zh_CN/claim.php +++ b/resources/lang/zh_CN/claim.php @@ -29,4 +29,6 @@ return [ 'add_claim_confirm' => '确认要认领?', 'remove_claim' => '放弃', 'remove_claim_confirm' => '确认要放弃认领?', + 'already_claimed' => '已认领', + 'not_claim_yet' => '未认领', ]; diff --git a/resources/lang/zh_TW/claim.php b/resources/lang/zh_TW/claim.php index bfc9d19b..473e4650 100644 --- a/resources/lang/zh_TW/claim.php +++ b/resources/lang/zh_TW/claim.php @@ -28,4 +28,6 @@ return [ 'add_claim_confirm' => '確認要認領?', 'remove_claim' => '放棄', 'remove_claim_confirm' => '確認要放棄認領?', + 'already_claimed' => '已認領', + 'not_claim_yet' => '未認領', ]; From bbc4d72ea614e1fe2b96b4bd09b8c48ab944308c Mon Sep 17 00:00:00 2001 From: xiaomlove Date: Thu, 8 Sep 2022 01:52:28 +0800 Subject: [PATCH 03/12] userdetails page torrent show action column always --- public/getusertorrentlistajax.php | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/public/getusertorrentlistajax.php b/public/getusertorrentlistajax.php index 15b7b57e..d7a3440b 100644 --- a/public/getusertorrentlistajax.php +++ b/public/getusertorrentlistajax.php @@ -129,9 +129,7 @@ function maketable($res, $mode = 'seeding') $ret = "". ($showsize ? "" : "").($showsenum ? "" : "").($showlenum ? "" : "").($showuploaded ? "" : "") . ($showdownloaded ? "" : "").($showratio ? "" : "").($showsetime ? "" : "").($showletime ? "" : "").($showcotime ? "" : "").($showanonymous ? "" : ""); - if ($showActionClaim) { - $ret .= sprintf('', $lang_functions['std_action']); - } + $ret .= sprintf('', $lang_functions['std_action']); $ret .= ""; $total_size = 0; foreach ($results as $arr) From 7434fb5252ca3fa072d36958702fab23aa8d7b6d Mon Sep 17 00:00:00 2001 From: xiaomlove Date: Thu, 8 Sep 2022 19:14:01 +0800 Subject: [PATCH 04/12] use data-table instead lay-table --- app/Http/Controllers/Controller.php | 16 ++ app/Providers/AppServiceProvider.php | 7 +- include/globalfunctions.php | 7 +- .../datatables-1.12.1/datatables.min.css | 15 ++ .../datatables-1.12.1/datatables.min.js | 213 ++++++++++++++++++ resources/lang/en/pagination.php | 22 ++ resources/lang/zh_CN/pagination.php | 22 ++ resources/lang/zh_TW/pagination.php | 22 ++ resources/views/data-table.blade.php | 31 +++ 9 files changed, 348 insertions(+), 7 deletions(-) create mode 100644 public/vendor/datatables-1.12.1/datatables.min.css create mode 100644 public/vendor/datatables-1.12.1/datatables.min.js create mode 100644 resources/views/data-table.blade.php diff --git a/app/Http/Controllers/Controller.php b/app/Http/Controllers/Controller.php index 894c494a..2929a0be 100644 --- a/app/Http/Controllers/Controller.php +++ b/app/Http/Controllers/Controller.php @@ -57,4 +57,20 @@ class Controller extends BaseController return Str::slug("$title.$action", '.'); } + protected function getPaginationParameters(): array + { + $request = request(); + $format = $request->__format; + if ($format == 'data-table') { + $perPage = $request->length; + $page = intval($request->start / $perPage) + 1; + } else { + $perPage = $request->limit; + $page = $request->page; + } + return [$perPage, ['*'], 'page', $page]; + } + + + } diff --git a/app/Providers/AppServiceProvider.php b/app/Providers/AppServiceProvider.php index b97177b7..57106d78 100644 --- a/app/Providers/AppServiceProvider.php +++ b/app/Providers/AppServiceProvider.php @@ -6,11 +6,11 @@ use App\Http\Middleware\Locale; use Carbon\Carbon; use Illuminate\Support\Facades\App; use Illuminate\Support\Facades\DB; +use Illuminate\Support\Facades\View; use Illuminate\Support\ServiceProvider; use Illuminate\Http\Resources\Json\JsonResource; use Nexus\Nexus; use Filament\Facades\Filament; -use Illuminate\Contracts\View\View; use NexusPlugin\Menu\Filament\MenuItemResource; class AppServiceProvider extends ServiceProvider @@ -44,11 +44,6 @@ class AppServiceProvider extends ServiceProvider ]); }); -// Filament::registerRenderHook( -// 'content.end', -// fn (): View => view('filament.footer'), -// ); - Filament::registerStyles([ asset('styles/sprites.css'), asset('styles/admin.css'), diff --git a/include/globalfunctions.php b/include/globalfunctions.php index 3cb0af01..242256f7 100644 --- a/include/globalfunctions.php +++ b/include/globalfunctions.php @@ -522,7 +522,7 @@ function api(...$args) $resultKey = 'ret'; $msgKey = 'msg'; $format = $_REQUEST['__format'] ?? ''; - if ($format == 'layui-table') { + if (in_array($format, ['layui-table', 'data-table'])) { $resultKey = 'code'; $count = $data['meta']['total'] ?? 0; if (isset($data['data'])) { @@ -539,6 +539,11 @@ function api(...$args) if ($format == 'layui-table') { $results['count'] = $count; } + if ($format == 'data-table') { + $results['draw'] = intval($_REQUEST['draw'] ?? 1); + $results['recordsTotal'] = $count; + $results['recordsFiltered'] = $count; + } return $results; } diff --git a/public/vendor/datatables-1.12.1/datatables.min.css b/public/vendor/datatables-1.12.1/datatables.min.css new file mode 100644 index 00000000..b6d5f46d --- /dev/null +++ b/public/vendor/datatables-1.12.1/datatables.min.css @@ -0,0 +1,15 @@ +/* + * This combined file was created by the DataTables downloader builder: + * https://datatables.net/download + * + * To rebuild or modify this file with the latest versions of the included + * software please visit: + * https://datatables.net/download/#dt/jqc-1.12.4/dt-1.12.1 + * + * Included libraries: + * jQuery 1 1.12.4, DataTables 1.12.1 + */ + +table.dataTable td.dt-control{text-align:center;cursor:pointer}table.dataTable td.dt-control:before{height:1em;width:1em;margin-top:-9px;display:inline-block;color:white;border:.15em solid white;border-radius:1em;box-shadow:0 0 .2em #444;box-sizing:content-box;text-align:center;text-indent:0 !important;font-family:"Courier New",Courier,monospace;line-height:1em;content:"+";background-color:#31b131}table.dataTable tr.dt-hasChild td.dt-control:before{content:"-";background-color:#d33333}table.dataTable thead>tr>th.sorting,table.dataTable thead>tr>th.sorting_asc,table.dataTable thead>tr>th.sorting_desc,table.dataTable thead>tr>th.sorting_asc_disabled,table.dataTable thead>tr>th.sorting_desc_disabled,table.dataTable thead>tr>td.sorting,table.dataTable thead>tr>td.sorting_asc,table.dataTable thead>tr>td.sorting_desc,table.dataTable thead>tr>td.sorting_asc_disabled,table.dataTable thead>tr>td.sorting_desc_disabled{cursor:pointer;position:relative;padding-right:26px}table.dataTable thead>tr>th.sorting:before,table.dataTable thead>tr>th.sorting:after,table.dataTable thead>tr>th.sorting_asc:before,table.dataTable thead>tr>th.sorting_asc:after,table.dataTable thead>tr>th.sorting_desc:before,table.dataTable thead>tr>th.sorting_desc:after,table.dataTable thead>tr>th.sorting_asc_disabled:before,table.dataTable thead>tr>th.sorting_asc_disabled:after,table.dataTable thead>tr>th.sorting_desc_disabled:before,table.dataTable thead>tr>th.sorting_desc_disabled:after,table.dataTable thead>tr>td.sorting:before,table.dataTable thead>tr>td.sorting:after,table.dataTable thead>tr>td.sorting_asc:before,table.dataTable thead>tr>td.sorting_asc:after,table.dataTable thead>tr>td.sorting_desc:before,table.dataTable thead>tr>td.sorting_desc:after,table.dataTable thead>tr>td.sorting_asc_disabled:before,table.dataTable thead>tr>td.sorting_asc_disabled:after,table.dataTable thead>tr>td.sorting_desc_disabled:before,table.dataTable thead>tr>td.sorting_desc_disabled:after{position:absolute;display:block;opacity:.125;right:10px;line-height:9px;font-size:.9em}table.dataTable thead>tr>th.sorting:before,table.dataTable thead>tr>th.sorting_asc:before,table.dataTable thead>tr>th.sorting_desc:before,table.dataTable thead>tr>th.sorting_asc_disabled:before,table.dataTable thead>tr>th.sorting_desc_disabled:before,table.dataTable thead>tr>td.sorting:before,table.dataTable thead>tr>td.sorting_asc:before,table.dataTable thead>tr>td.sorting_desc:before,table.dataTable thead>tr>td.sorting_asc_disabled:before,table.dataTable thead>tr>td.sorting_desc_disabled:before{bottom:50%;content:"▴"}table.dataTable thead>tr>th.sorting:after,table.dataTable thead>tr>th.sorting_asc:after,table.dataTable thead>tr>th.sorting_desc:after,table.dataTable thead>tr>th.sorting_asc_disabled:after,table.dataTable thead>tr>th.sorting_desc_disabled:after,table.dataTable thead>tr>td.sorting:after,table.dataTable thead>tr>td.sorting_asc:after,table.dataTable thead>tr>td.sorting_desc:after,table.dataTable thead>tr>td.sorting_asc_disabled:after,table.dataTable thead>tr>td.sorting_desc_disabled:after{top:50%;content:"▾"}table.dataTable thead>tr>th.sorting_asc:before,table.dataTable thead>tr>th.sorting_desc:after,table.dataTable thead>tr>td.sorting_asc:before,table.dataTable thead>tr>td.sorting_desc:after{opacity:.6}table.dataTable thead>tr>th.sorting_desc_disabled:after,table.dataTable thead>tr>th.sorting_asc_disabled:before,table.dataTable thead>tr>td.sorting_desc_disabled:after,table.dataTable thead>tr>td.sorting_asc_disabled:before{display:none}table.dataTable thead>tr>th:active,table.dataTable thead>tr>td:active{outline:none}div.dataTables_scrollBody table.dataTable thead>tr>th:before,div.dataTables_scrollBody table.dataTable thead>tr>th:after,div.dataTables_scrollBody table.dataTable thead>tr>td:before,div.dataTables_scrollBody table.dataTable thead>tr>td:after{display:none}div.dataTables_processing{position:absolute;top:50%;left:50%;width:200px;margin-left:-100px;margin-top:-26px;text-align:center;padding:2px}div.dataTables_processing>div:last-child{position:relative;width:80px;height:15px;margin:1em auto}div.dataTables_processing>div:last-child>div{position:absolute;top:0;width:13px;height:13px;border-radius:50%;background:rgba(13, 110, 253, 0.9);animation-timing-function:cubic-bezier(0, 1, 1, 0)}div.dataTables_processing>div:last-child>div:nth-child(1){left:8px;animation:datatables-loader-1 .6s infinite}div.dataTables_processing>div:last-child>div:nth-child(2){left:8px;animation:datatables-loader-2 .6s infinite}div.dataTables_processing>div:last-child>div:nth-child(3){left:32px;animation:datatables-loader-2 .6s infinite}div.dataTables_processing>div:last-child>div:nth-child(4){left:56px;animation:datatables-loader-3 .6s infinite}@keyframes datatables-loader-1{0%{transform:scale(0)}100%{transform:scale(1)}}@keyframes datatables-loader-3{0%{transform:scale(1)}100%{transform:scale(0)}}@keyframes datatables-loader-2{0%{transform:translate(0, 0)}100%{transform:translate(24px, 0)}}table.dataTable.nowrap th,table.dataTable.nowrap td{white-space:nowrap}table.dataTable th.dt-left,table.dataTable td.dt-left{text-align:left}table.dataTable th.dt-center,table.dataTable td.dt-center,table.dataTable td.dataTables_empty{text-align:center}table.dataTable th.dt-right,table.dataTable td.dt-right{text-align:right}table.dataTable th.dt-justify,table.dataTable td.dt-justify{text-align:justify}table.dataTable th.dt-nowrap,table.dataTable td.dt-nowrap{white-space:nowrap}table.dataTable thead th,table.dataTable thead td,table.dataTable tfoot th,table.dataTable tfoot td{text-align:left}table.dataTable thead th.dt-head-left,table.dataTable thead td.dt-head-left,table.dataTable tfoot th.dt-head-left,table.dataTable tfoot td.dt-head-left{text-align:left}table.dataTable thead th.dt-head-center,table.dataTable thead td.dt-head-center,table.dataTable tfoot th.dt-head-center,table.dataTable tfoot td.dt-head-center{text-align:center}table.dataTable thead th.dt-head-right,table.dataTable thead td.dt-head-right,table.dataTable tfoot th.dt-head-right,table.dataTable tfoot td.dt-head-right{text-align:right}table.dataTable thead th.dt-head-justify,table.dataTable thead td.dt-head-justify,table.dataTable tfoot th.dt-head-justify,table.dataTable tfoot td.dt-head-justify{text-align:justify}table.dataTable thead th.dt-head-nowrap,table.dataTable thead td.dt-head-nowrap,table.dataTable tfoot th.dt-head-nowrap,table.dataTable tfoot td.dt-head-nowrap{white-space:nowrap}table.dataTable tbody th.dt-body-left,table.dataTable tbody td.dt-body-left{text-align:left}table.dataTable tbody th.dt-body-center,table.dataTable tbody td.dt-body-center{text-align:center}table.dataTable tbody th.dt-body-right,table.dataTable tbody td.dt-body-right{text-align:right}table.dataTable tbody th.dt-body-justify,table.dataTable tbody td.dt-body-justify{text-align:justify}table.dataTable tbody th.dt-body-nowrap,table.dataTable tbody td.dt-body-nowrap{white-space:nowrap}table.dataTable{width:100%;margin:0 auto;clear:both;border-collapse:separate;border-spacing:0}table.dataTable thead th,table.dataTable tfoot th{font-weight:bold}table.dataTable thead th,table.dataTable thead td{padding:10px;border-bottom:1px solid rgba(0, 0, 0, 0.3)}table.dataTable thead th:active,table.dataTable thead td:active{outline:none}table.dataTable tfoot th,table.dataTable tfoot td{padding:10px 10px 6px 10px;border-top:1px solid rgba(0, 0, 0, 0.3)}table.dataTable tbody tr{background-color:transparent}table.dataTable tbody tr.selected>*{box-shadow:inset 0 0 0 9999px rgba(13, 110, 253, 0.9);color:white}table.dataTable tbody th,table.dataTable tbody td{padding:8px 10px}table.dataTable.row-border tbody th,table.dataTable.row-border tbody td,table.dataTable.display tbody th,table.dataTable.display tbody td{border-top:1px solid rgba(0, 0, 0, 0.15)}table.dataTable.row-border tbody tr:first-child th,table.dataTable.row-border tbody tr:first-child td,table.dataTable.display tbody tr:first-child th,table.dataTable.display tbody tr:first-child td{border-top:none}table.dataTable.cell-border tbody th,table.dataTable.cell-border tbody td{border-top:1px solid rgba(0, 0, 0, 0.15);border-right:1px solid rgba(0, 0, 0, 0.15)}table.dataTable.cell-border tbody tr th:first-child,table.dataTable.cell-border tbody tr td:first-child{border-left:1px solid rgba(0, 0, 0, 0.15)}table.dataTable.cell-border tbody tr:first-child th,table.dataTable.cell-border tbody tr:first-child td{border-top:none}table.dataTable.stripe>tbody>tr.odd>*,table.dataTable.display>tbody>tr.odd>*{box-shadow:inset 0 0 0 9999px rgba(0, 0, 0, 0.023)}table.dataTable.stripe>tbody>tr.odd.selected>*,table.dataTable.display>tbody>tr.odd.selected>*{box-shadow:inset 0 0 0 9999px rgba(13, 110, 253, 0.923)}table.dataTable.hover>tbody>tr:hover>*,table.dataTable.display>tbody>tr:hover>*{box-shadow:inset 0 0 0 9999px rgba(0, 0, 0, 0.035)}table.dataTable.hover>tbody>tr.selected:hover>*,table.dataTable.display>tbody>tr.selected:hover>*{box-shadow:inset 0 0 0 9999px rgba(13, 110, 253, 0.935)}table.dataTable.order-column>tbody tr>.sorting_1,table.dataTable.order-column>tbody tr>.sorting_2,table.dataTable.order-column>tbody tr>.sorting_3,table.dataTable.display>tbody tr>.sorting_1,table.dataTable.display>tbody tr>.sorting_2,table.dataTable.display>tbody tr>.sorting_3{box-shadow:inset 0 0 0 9999px rgba(0, 0, 0, 0.019)}table.dataTable.order-column>tbody tr.selected>.sorting_1,table.dataTable.order-column>tbody tr.selected>.sorting_2,table.dataTable.order-column>tbody tr.selected>.sorting_3,table.dataTable.display>tbody tr.selected>.sorting_1,table.dataTable.display>tbody tr.selected>.sorting_2,table.dataTable.display>tbody tr.selected>.sorting_3{box-shadow:inset 0 0 0 9999px rgba(13, 110, 253, 0.919)}table.dataTable.display>tbody>tr.odd>.sorting_1,table.dataTable.order-column.stripe>tbody>tr.odd>.sorting_1{box-shadow:inset 0 0 0 9999px rgba(0, 0, 0, 0.054)}table.dataTable.display>tbody>tr.odd>.sorting_2,table.dataTable.order-column.stripe>tbody>tr.odd>.sorting_2{box-shadow:inset 0 0 0 9999px rgba(0, 0, 0, 0.047)}table.dataTable.display>tbody>tr.odd>.sorting_3,table.dataTable.order-column.stripe>tbody>tr.odd>.sorting_3{box-shadow:inset 0 0 0 9999px rgba(0, 0, 0, 0.039)}table.dataTable.display>tbody>tr.odd.selected>.sorting_1,table.dataTable.order-column.stripe>tbody>tr.odd.selected>.sorting_1{box-shadow:inset 0 0 0 9999px rgba(13, 110, 253, 0.954)}table.dataTable.display>tbody>tr.odd.selected>.sorting_2,table.dataTable.order-column.stripe>tbody>tr.odd.selected>.sorting_2{box-shadow:inset 0 0 0 9999px rgba(13, 110, 253, 0.947)}table.dataTable.display>tbody>tr.odd.selected>.sorting_3,table.dataTable.order-column.stripe>tbody>tr.odd.selected>.sorting_3{box-shadow:inset 0 0 0 9999px rgba(13, 110, 253, 0.939)}table.dataTable.display>tbody>tr.even>.sorting_1,table.dataTable.order-column.stripe>tbody>tr.even>.sorting_1{box-shadow:inset 0 0 0 9999px rgba(0, 0, 0, 0.019)}table.dataTable.display>tbody>tr.even>.sorting_2,table.dataTable.order-column.stripe>tbody>tr.even>.sorting_2{box-shadow:inset 0 0 0 9999px rgba(0, 0, 0, 0.011)}table.dataTable.display>tbody>tr.even>.sorting_3,table.dataTable.order-column.stripe>tbody>tr.even>.sorting_3{box-shadow:inset 0 0 0 9999px rgba(0, 0, 0, 0.003)}table.dataTable.display>tbody>tr.even.selected>.sorting_1,table.dataTable.order-column.stripe>tbody>tr.even.selected>.sorting_1{box-shadow:inset 0 0 0 9999px rgba(13, 110, 253, 0.919)}table.dataTable.display>tbody>tr.even.selected>.sorting_2,table.dataTable.order-column.stripe>tbody>tr.even.selected>.sorting_2{box-shadow:inset 0 0 0 9999px rgba(13, 110, 253, 0.911)}table.dataTable.display>tbody>tr.even.selected>.sorting_3,table.dataTable.order-column.stripe>tbody>tr.even.selected>.sorting_3{box-shadow:inset 0 0 0 9999px rgba(13, 110, 253, 0.903)}table.dataTable.display tbody tr:hover>.sorting_1,table.dataTable.order-column.hover tbody tr:hover>.sorting_1{box-shadow:inset 0 0 0 9999px rgba(0, 0, 0, 0.082)}table.dataTable.display tbody tr:hover>.sorting_2,table.dataTable.order-column.hover tbody tr:hover>.sorting_2{box-shadow:inset 0 0 0 9999px rgba(0, 0, 0, 0.074)}table.dataTable.display tbody tr:hover>.sorting_3,table.dataTable.order-column.hover tbody tr:hover>.sorting_3{box-shadow:inset 0 0 0 9999px rgba(0, 0, 0, 0.062)}table.dataTable.display tbody tr:hover.selected>.sorting_1,table.dataTable.order-column.hover tbody tr:hover.selected>.sorting_1{box-shadow:inset 0 0 0 9999px rgba(13, 110, 253, 0.982)}table.dataTable.display tbody tr:hover.selected>.sorting_2,table.dataTable.order-column.hover tbody tr:hover.selected>.sorting_2{box-shadow:inset 0 0 0 9999px rgba(13, 110, 253, 0.974)}table.dataTable.display tbody tr:hover.selected>.sorting_3,table.dataTable.order-column.hover tbody tr:hover.selected>.sorting_3{box-shadow:inset 0 0 0 9999px rgba(13, 110, 253, 0.962)}table.dataTable.no-footer{border-bottom:1px solid rgba(0, 0, 0, 0.3)}table.dataTable.compact thead th,table.dataTable.compact thead td{padding:4px 17px}table.dataTable.compact tfoot th,table.dataTable.compact tfoot td{padding:4px}table.dataTable.compact tbody th,table.dataTable.compact tbody td{padding:4px}table.dataTable th,table.dataTable td{box-sizing:content-box}.dataTables_wrapper{position:relative;clear:both}.dataTables_wrapper .dataTables_length{float:left}.dataTables_wrapper .dataTables_length select{border:1px solid #aaa;border-radius:3px;padding:5px;background-color:transparent;padding:4px}.dataTables_wrapper .dataTables_filter{float:right;text-align:right}.dataTables_wrapper .dataTables_filter input{border:1px solid #aaa;border-radius:3px;padding:5px;background-color:transparent;margin-left:3px}.dataTables_wrapper .dataTables_info{clear:both;float:left;padding-top:.755em}.dataTables_wrapper .dataTables_paginate{float:right;text-align:right;padding-top:.25em}.dataTables_wrapper .dataTables_paginate .paginate_button{box-sizing:border-box;display:inline-block;min-width:1.5em;padding:.5em 1em;margin-left:2px;text-align:center;text-decoration:none !important;cursor:pointer;color:#333 !important;border:1px solid transparent;border-radius:2px}.dataTables_wrapper .dataTables_paginate .paginate_button.current,.dataTables_wrapper .dataTables_paginate .paginate_button.current:hover{color:#333 !important;border:1px solid rgba(0, 0, 0, 0.3);background-color:rgba(230, 230, 230, 0.1);background:-webkit-gradient(linear, left top, left bottom, color-stop(0%, rgba(230, 230, 230, 0.1)), color-stop(100%, rgba(0, 0, 0, 0.1)));background:-webkit-linear-gradient(top, rgba(230, 230, 230, 0.1) 0%, rgba(0, 0, 0, 0.1) 100%);background:-moz-linear-gradient(top, rgba(230, 230, 230, 0.1) 0%, rgba(0, 0, 0, 0.1) 100%);background:-ms-linear-gradient(top, rgba(230, 230, 230, 0.1) 0%, rgba(0, 0, 0, 0.1) 100%);background:-o-linear-gradient(top, rgba(230, 230, 230, 0.1) 0%, rgba(0, 0, 0, 0.1) 100%);background:linear-gradient(to bottom, rgba(230, 230, 230, 0.1) 0%, rgba(0, 0, 0, 0.1) 100%)}.dataTables_wrapper .dataTables_paginate .paginate_button.disabled,.dataTables_wrapper .dataTables_paginate .paginate_button.disabled:hover,.dataTables_wrapper .dataTables_paginate .paginate_button.disabled:active{cursor:default;color:#666 !important;border:1px solid transparent;background:transparent;box-shadow:none}.dataTables_wrapper .dataTables_paginate .paginate_button:hover{color:white !important;border:1px solid #111;background-color:#585858;background:-webkit-gradient(linear, left top, left bottom, color-stop(0%, #585858), color-stop(100%, #111));background:-webkit-linear-gradient(top, #585858 0%, #111 100%);background:-moz-linear-gradient(top, #585858 0%, #111 100%);background:-ms-linear-gradient(top, #585858 0%, #111 100%);background:-o-linear-gradient(top, #585858 0%, #111 100%);background:linear-gradient(to bottom, #585858 0%, #111 100%)}.dataTables_wrapper .dataTables_paginate .paginate_button:active{outline:none;background-color:#2b2b2b;background:-webkit-gradient(linear, left top, left bottom, color-stop(0%, #2b2b2b), color-stop(100%, #0c0c0c));background:-webkit-linear-gradient(top, #2b2b2b 0%, #0c0c0c 100%);background:-moz-linear-gradient(top, #2b2b2b 0%, #0c0c0c 100%);background:-ms-linear-gradient(top, #2b2b2b 0%, #0c0c0c 100%);background:-o-linear-gradient(top, #2b2b2b 0%, #0c0c0c 100%);background:linear-gradient(to bottom, #2b2b2b 0%, #0c0c0c 100%);box-shadow:inset 0 0 3px #111}.dataTables_wrapper .dataTables_paginate .ellipsis{padding:0 1em}.dataTables_wrapper .dataTables_length,.dataTables_wrapper .dataTables_filter,.dataTables_wrapper .dataTables_info,.dataTables_wrapper .dataTables_processing,.dataTables_wrapper .dataTables_paginate{color:#333}.dataTables_wrapper .dataTables_scroll{clear:both}.dataTables_wrapper .dataTables_scroll div.dataTables_scrollBody{-webkit-overflow-scrolling:touch}.dataTables_wrapper .dataTables_scroll div.dataTables_scrollBody>table>thead>tr>th,.dataTables_wrapper .dataTables_scroll div.dataTables_scrollBody>table>thead>tr>td,.dataTables_wrapper .dataTables_scroll div.dataTables_scrollBody>table>tbody>tr>th,.dataTables_wrapper .dataTables_scroll div.dataTables_scrollBody>table>tbody>tr>td{vertical-align:middle}.dataTables_wrapper .dataTables_scroll div.dataTables_scrollBody>table>thead>tr>th>div.dataTables_sizing,.dataTables_wrapper .dataTables_scroll div.dataTables_scrollBody>table>thead>tr>td>div.dataTables_sizing,.dataTables_wrapper .dataTables_scroll div.dataTables_scrollBody>table>tbody>tr>th>div.dataTables_sizing,.dataTables_wrapper .dataTables_scroll div.dataTables_scrollBody>table>tbody>tr>td>div.dataTables_sizing{height:0;overflow:hidden;margin:0 !important;padding:0 !important}.dataTables_wrapper.no-footer .dataTables_scrollBody{border-bottom:1px solid rgba(0, 0, 0, 0.3)}.dataTables_wrapper.no-footer div.dataTables_scrollHead table.dataTable,.dataTables_wrapper.no-footer div.dataTables_scrollBody>table{border-bottom:none}.dataTables_wrapper:after{visibility:hidden;display:block;content:"";clear:both;height:0}@media screen and (max-width: 767px){.dataTables_wrapper .dataTables_info,.dataTables_wrapper .dataTables_paginate{float:none;text-align:center}.dataTables_wrapper .dataTables_paginate{margin-top:.5em}}@media screen and (max-width: 640px){.dataTables_wrapper .dataTables_length,.dataTables_wrapper .dataTables_filter{float:none;text-align:center}.dataTables_wrapper .dataTables_filter{margin-top:.5em}} + + diff --git a/public/vendor/datatables-1.12.1/datatables.min.js b/public/vendor/datatables-1.12.1/datatables.min.js new file mode 100644 index 00000000..53f5ccf7 --- /dev/null +++ b/public/vendor/datatables-1.12.1/datatables.min.js @@ -0,0 +1,213 @@ +/* + * This combined file was created by the DataTables downloader builder: + * https://datatables.net/download + * + * To rebuild or modify this file with the latest versions of the included + * software please visit: + * https://datatables.net/download/#dt/dt-1.12.1 + * + * Included libraries: + * DataTables 1.12.1 + */ + +/*! + SpryMedia Ltd. + + This source file is free software, available under the following license: + MIT license - http://datatables.net/license + + This source file is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + or FITNESS FOR A PARTICULAR PURPOSE. See the license files for details. + + For details please refer to: http://www.datatables.net + DataTables 1.12.1 + ©2008-2022 SpryMedia Ltd - datatables.net/license +*/ +var $jscomp=$jscomp||{};$jscomp.scope={};$jscomp.findInternal=function(l,y,A){l instanceof String&&(l=String(l));for(var q=l.length,E=0;E").css({position:"fixed",top:0,left:-1*l(y).scrollLeft(),height:1, +width:1,overflow:"hidden"}).append(l("
").css({position:"absolute",top:1,left:1,width:100,overflow:"scroll"}).append(l("
").css({width:"100%",height:10}))).appendTo("body"),d=c.children(),e=d.children();b.barWidth=d[0].offsetWidth-d[0].clientWidth;b.bScrollOversize=100===e[0].offsetWidth&&100!==d[0].clientWidth;b.bScrollbarLeft=1!==Math.round(e.offset().left);b.bBounding=c[0].getBoundingClientRect().width?!0:!1;c.remove()}l.extend(a.oBrowser,u.__browser);a.oScroll.iBarWidth=u.__browser.barWidth} +function Gb(a,b,c,d,e,h){var f=!1;if(c!==q){var g=c;f=!0}for(;d!==e;)a.hasOwnProperty(d)&&(g=f?b(g,a[d],d,a):a[d],f=!0,d+=h);return g}function cb(a,b){var c=u.defaults.column,d=a.aoColumns.length;c=l.extend({},u.models.oColumn,c,{nTh:b?b:A.createElement("th"),sTitle:c.sTitle?c.sTitle:b?b.innerHTML:"",aDataSort:c.aDataSort?c.aDataSort:[d],mData:c.mData?c.mData:d,idx:d});a.aoColumns.push(c);c=a.aoPreSearchCols;c[d]=l.extend({},u.models.oSearch,c[d]);Ia(a,d,l(b).data())}function Ia(a,b,c){b=a.aoColumns[b]; +var d=a.oClasses,e=l(b.nTh);if(!b.sWidthOrig){b.sWidthOrig=e.attr("width")||null;var h=(e.attr("style")||"").match(/width:\s*(\d+[pxem%]+)/);h&&(b.sWidthOrig=h[1])}c!==q&&null!==c&&(Eb(c),P(u.defaults.column,c,!0),c.mDataProp===q||c.mData||(c.mData=c.mDataProp),c.sType&&(b._sManualType=c.sType),c.className&&!c.sClass&&(c.sClass=c.className),c.sClass&&e.addClass(c.sClass),h=b.sClass,l.extend(b,c),Y(b,c,"sWidth","sWidthOrig"),h!==b.sClass&&(b.sClass=h+" "+b.sClass),c.iDataSort!==q&&(b.aDataSort=[c.iDataSort]), +Y(b,c,"aDataSort"));var f=b.mData,g=ma(f),k=b.mRender?ma(b.mRender):null;c=function(m){return"string"===typeof m&&-1!==m.indexOf("@")};b._bAttrSrc=l.isPlainObject(f)&&(c(f.sort)||c(f.type)||c(f.filter));b._setter=null;b.fnGetData=function(m,n,p){var t=g(m,n,q,p);return k&&n?k(t,n,m,p):t};b.fnSetData=function(m,n,p){return ha(f)(m,n,p)};"number"!==typeof f&&(a._rowReadObject=!0);a.oFeatures.bSort||(b.bSortable=!1,e.addClass(d.sSortableNone));a=-1!==l.inArray("asc",b.asSorting);c=-1!==l.inArray("desc", +b.asSorting);b.bSortable&&(a||c)?a&&!c?(b.sSortingClass=d.sSortableAsc,b.sSortingClassJUI=d.sSortJUIAscAllowed):!a&&c?(b.sSortingClass=d.sSortableDesc,b.sSortingClassJUI=d.sSortJUIDescAllowed):(b.sSortingClass=d.sSortable,b.sSortingClassJUI=d.sSortJUI):(b.sSortingClass=d.sSortableNone,b.sSortingClassJUI="")}function sa(a){if(!1!==a.oFeatures.bAutoWidth){var b=a.aoColumns;db(a);for(var c=0,d=b.length;cm[n])d(g.length+m[n],k);else if("string"===typeof m[n]){var p=0;for(f=g.length;pb&&a[e]--; -1!=d&&c===q&&a.splice(d,1)}function va(a,b,c,d){var e=a.aoData[b],h,f=function(k,m){for(;k.childNodes.length;)k.removeChild(k.firstChild);k.innerHTML=T(a,b,m,"display")};if("dom"!==c&&(c&&"auto"!==c||"dom"!==e.src)){var g=e.anCells;if(g)if(d!==q)f(g[d],d);else for(c=0,h=g.length;c").appendTo(d));var k=0;for(b=g.length;k=a.fnRecordsDisplay()?0:d,a.iInitDisplayStart=-1);c=F(a,"aoPreDrawCallback","preDraw",[a]);if(-1!==l.inArray(!1,c))V(a,!1);else{c=[];var e=0;d=a.asStripeClasses;var h=d.length,f=a.oLanguage,g="ssp"==Q(a),k=a.aiDisplay,m=a._iDisplayStart,n=a.fnDisplayEnd();a.bDrawing=!0;if(a.bDeferLoading)a.bDeferLoading=!1,a.iDraw++,V(a,!1);else if(!g)a.iDraw++;else if(!a.bDestroying&&!b){Kb(a);return}if(0!==k.length)for(b=g?a.aoData.length:n,f=g?0:m;f",{"class":h?d[0]:""}).append(l("
").insertAfter(H));r.nTBody=fa[0];H=t.children("tfoot");0===H.length&&0").appendTo(t));0===H.length||0===H.children().length?t.addClass(C.sNoFooter):0/g,Dc=/^\d{2,4}[\.\/\-]\d{1,2}[\.\/\-]\d{1,2}([T ]{1}\d{1,2}[:\.]\d{2}([\.:]\d{2})?)?$/,Ec=/(\/|\.|\*|\+|\?|\||\(|\)|\[|\]|\{|\}|\\|\$|\^|\-)/g,vb=/['\u00A0,$£€¥%\u2009\u202F\u20BD\u20a9\u20BArfkɃΞ]/gi,aa=function(a){return a&&!0!==a&&"-"!== +a?!1:!0},nc=function(a){var b=parseInt(a,10);return!isNaN(b)&&isFinite(a)?b:null},oc=function(a,b){xb[b]||(xb[b]=new RegExp(ob(b),"g"));return"string"===typeof a&&"."!==b?a.replace(/\./g,"").replace(xb[b],"."):a},yb=function(a,b,c){var d="string"===typeof a;if(aa(a))return!0;b&&d&&(a=oc(a,b));c&&d&&(a=a.replace(vb,""));return!isNaN(parseFloat(a))&&isFinite(a)},pc=function(a,b,c){return aa(a)?!0:aa(a)||"string"===typeof a?yb(a.replace(Ya,""),b,c)?!0:null:null},U=function(a,b,c){var d=[],e=0,h=a.length; +if(c!==q)for(;ea.length)){var b=a.slice().sort();for(var c=b[0], +d=1,e=b.length;d")[0],Bc=Sa.textContent!==q,Cc=/<.*?>/g,mb=u.util.throttle,tc=[],N=Array.prototype,Fc=function(a){var b,c=u.settings,d=l.map(c,function(h,f){return h.nTable});if(a){if(a.nTable&&a.oApi)return[a];if(a.nodeName&&"table"===a.nodeName.toLowerCase()){var e= +l.inArray(a,d);return-1!==e?[c[e]]:null}if(a&&"function"===typeof a.settings)return a.settings().toArray();"string"===typeof a?b=l(a):a instanceof l&&(b=a)}else return[];if(b)return b.map(function(h){e=l.inArray(this,d);return-1!==e?c[e]:null}).toArray()};var B=function(a,b){if(!(this instanceof B))return new B(a,b);var c=[],d=function(f){(f=Fc(f))&&c.push.apply(c,f)};if(Array.isArray(a))for(var e=0,h=a.length;ea?new B(b[a],this[a]):null},filter:function(a){var b=[];if(N.filter)b=N.filter.call(this,a,this);else for(var c=0,d=this.length;c").addClass(g),l("td",k).addClass(g).html(f)[0].colSpan=na(a),e.push(k[0]))};h(c,d);b._details&&b._details.detach();b._details=l(e);b._detailsShow&&b._details.insertAfter(b.nTr)},wc=u.util.throttle(function(a){Da(a[0])}, +500),Cb=function(a,b){var c=a.context;c.length&&(a=c[0].aoData[b!==q?b:a[0]])&&a._details&&(a._details.remove(),a._detailsShow=q,a._details=q,l(a.nTr).removeClass("dt-hasChild"),wc(c))},xc=function(a,b){var c=a.context;if(c.length&&a.length){var d=c[0].aoData[a[0]];d._details&&((d._detailsShow=b)?(d._details.insertAfter(d.nTr),l(d.nTr).addClass("dt-hasChild")):(d._details.detach(),l(d.nTr).removeClass("dt-hasChild")),F(c[0],null,"childRow",[b,a.row(a[0])]),Ic(c[0]),wc(c))}},Ic=function(a){var b=new B(a), +c=a.aoData;b.off("draw.dt.DT_details column-sizing.dt.DT_details destroy.dt.DT_details");0g){var n=l.map(d,function(p,t){return p.bVisible?t:null});return[n[n.length+g]]}return[ta(a,g)];case "name":return l.map(e,function(p,t){return p===m[1]?t:null});default:return[]}if(f.nodeName&&f._DT_CellIndex)return[f._DT_CellIndex.column];g=l(h).filter(f).map(function(){return l.inArray(this,h)}).toArray();if(g.length||!f.nodeName)return g; +g=l(f).closest("*[data-dt-column]");return g.length?[g.data("dt-column")]:[]},a,c)};z("columns()",function(a,b){a===q?a="":l.isPlainObject(a)&&(b=a,a="");b=Ab(b);var c=this.iterator("table",function(d){return Kc(d,a,b)},1);c.selector.cols=a;c.selector.opts=b;return c});J("columns().header()","column().header()",function(a,b){return this.iterator("column",function(c,d){return c.aoColumns[d].nTh},1)});J("columns().footer()","column().footer()",function(a,b){return this.iterator("column",function(c, +d){return c.aoColumns[d].nTf},1)});J("columns().data()","column().data()",function(){return this.iterator("column-rows",yc,1)});J("columns().dataSrc()","column().dataSrc()",function(){return this.iterator("column",function(a,b){return a.aoColumns[b].mData},1)});J("columns().cache()","column().cache()",function(a){return this.iterator("column-rows",function(b,c,d,e,h){return Fa(b.aoData,h,"search"===a?"_aFilterData":"_aSortData",c)},1)});J("columns().nodes()","column().nodes()",function(){return this.iterator("column-rows", +function(a,b,c,d,e){return Fa(a.aoData,e,"anCells",b)},1)});J("columns().visible()","column().visible()",function(a,b){var c=this,d=this.iterator("column",function(e,h){if(a===q)return e.aoColumns[h].bVisible;var f=e.aoColumns,g=f[h],k=e.aoData,m;if(a!==q&&g.bVisible!==a){if(a){var n=l.inArray(!0,U(f,"bVisible"),h+1);f=0;for(m=k.length;fd;return!0};u.isDataTable=u.fnIsDataTable=function(a){var b=l(a).get(0),c=!1;if(a instanceof u.Api)return!0;l.each(u.settings,function(d,e){d=e.nScrollHead?l("table",e.nScrollHead)[0]:null;var h=e.nScrollFoot? +l("table",e.nScrollFoot)[0]:null;if(e.nTable===b||d===b||h===b)c=!0});return c};u.tables=u.fnTables=function(a){var b=!1;l.isPlainObject(a)&&(b=a.api,a=a.visible);var c=l.map(u.settings,function(d){if(!a||a&&l(d.nTable).is(":visible"))return d.nTable});return b?new B(c):c};u.camelToHungarian=P;z("$()",function(a,b){b=this.rows(b).nodes();b=l(b);return l([].concat(b.filter(a).toArray(),b.find(a).toArray()))});l.each(["on","one","off"],function(a,b){z(b+"()",function(){var c=Array.prototype.slice.call(arguments); +c[0]=l.map(c[0].split(/\s/),function(e){return e.match(/\.dt\b/)?e:e+".dt"}).join(" ");var d=l(this.tables().nodes());d[b].apply(d,c);return this})});z("clear()",function(){return this.iterator("table",function(a){Ma(a)})});z("settings()",function(){return new B(this.context,this.context)});z("init()",function(){var a=this.context;return a.length?a[0].oInit:null});z("data()",function(){return this.iterator("table",function(a){return U(a.aoData,"_aData")}).flatten()});z("destroy()",function(a){a=a|| +!1;return this.iterator("table",function(b){var c=b.oClasses,d=b.nTable,e=b.nTBody,h=b.nTHead,f=b.nTFoot,g=l(d);e=l(e);var k=l(b.nTableWrapper),m=l.map(b.aoData,function(p){return p.nTr}),n;b.bDestroying=!0;F(b,"aoDestroyCallback","destroy",[b]);a||(new B(b)).columns().visible(!0);k.off(".DT").find(":not(tbody *)").off(".DT");l(y).off(".DT-"+b.sInstance);d!=h.parentNode&&(g.children("thead").detach(),g.append(h));f&&d!=f.parentNode&&(g.children("tfoot").detach(),g.append(f));b.aaSorting=[];b.aaSortingFixed= +[];Va(b);l(m).removeClass(b.asStripeClasses.join(" "));l("th, td",h).removeClass(c.sSortable+" "+c.sSortableAsc+" "+c.sSortableDesc+" "+c.sSortableNone);e.children().detach();e.append(m);h=b.nTableWrapper.parentNode;f=a?"remove":"detach";g[f]();k[f]();!a&&h&&(h.insertBefore(d,b.nTableReinsertBefore),g.css("width",b.sDestroyWidth).removeClass(c.sTable),(n=b.asDestroyStripes.length)&&e.children().each(function(p){l(this).addClass(b.asDestroyStripes[p%n])}));c=l.inArray(b,u.settings);-1!==c&&u.settings.splice(c, +1)})});l.each(["column","row","cell"],function(a,b){z(b+"s().every()",function(c){var d=this.selector.opts,e=this;return this.iterator(b,function(h,f,g,k,m){c.call(e[b](f,"cell"===b?g:d,"cell"===b?d:q),f,g,k,m)})})});z("i18n()",function(a,b,c){var d=this.context[0];a=ma(a)(d.oLanguage);a===q&&(a=b);c!==q&&l.isPlainObject(a)&&(a=a[c]!==q?a[c]:a._);return a.replace("%d",c)});u.version="1.12.1";u.settings=[];u.models={};u.models.oSearch={bCaseInsensitive:!0,sSearch:"",bRegex:!1,bSmart:!0,"return":!1}; +u.models.oRow={nTr:null,anCells:null,_aData:[],_aSortData:null,_aFilterData:null,_sFilterRow:null,_sRowStripe:"",src:null,idx:-1};u.models.oColumn={idx:null,aDataSort:null,asSorting:null,bSearchable:null,bSortable:null,bVisible:null,_sManualType:null,_bAttrSrc:!1,fnCreatedCell:null,fnGetData:null,fnSetData:null,mData:null,mRender:null,nTh:null,nTf:null,sClass:null,sContentPadding:null,sDefaultContent:null,sName:null,sSortDataType:"std",sSortingClass:null,sSortingClassJUI:null,sTitle:null,sType:null, +sWidth:null,sWidthOrig:null};u.defaults={aaData:null,aaSorting:[[0,"asc"]],aaSortingFixed:[],ajax:null,aLengthMenu:[10,25,50,100],aoColumns:null,aoColumnDefs:null,aoSearchCols:[],asStripeClasses:null,bAutoWidth:!0,bDeferRender:!1,bDestroy:!1,bFilter:!0,bInfo:!0,bLengthChange:!0,bPaginate:!0,bProcessing:!1,bRetrieve:!1,bScrollCollapse:!1,bServerSide:!1,bSort:!0,bSortMulti:!0,bSortCellsTop:!1,bSortClasses:!0,bStateSave:!1,fnCreatedRow:null,fnDrawCallback:null,fnFooterCallback:null,fnFormatNumber:function(a){return a.toString().replace(/\B(?=(\d{3})+(?!\d))/g, +this.oLanguage.sThousands)},fnHeaderCallback:null,fnInfoCallback:null,fnInitComplete:null,fnPreDrawCallback:null,fnRowCallback:null,fnServerData:null,fnServerParams:null,fnStateLoadCallback:function(a){try{return JSON.parse((-1===a.iStateDuration?sessionStorage:localStorage).getItem("DataTables_"+a.sInstance+"_"+location.pathname))}catch(b){return{}}},fnStateLoadParams:null,fnStateLoaded:null,fnStateSaveCallback:function(a,b){try{(-1===a.iStateDuration?sessionStorage:localStorage).setItem("DataTables_"+ +a.sInstance+"_"+location.pathname,JSON.stringify(b))}catch(c){}},fnStateSaveParams:null,iStateDuration:7200,iDeferLoading:null,iDisplayLength:10,iDisplayStart:0,iTabIndex:0,oClasses:{},oLanguage:{oAria:{sSortAscending:": activate to sort column ascending",sSortDescending:": activate to sort column descending"},oPaginate:{sFirst:"First",sLast:"Last",sNext:"Next",sPrevious:"Previous"},sEmptyTable:"No data available in table",sInfo:"Showing _START_ to _END_ of _TOTAL_ entries",sInfoEmpty:"Showing 0 to 0 of 0 entries", +sInfoFiltered:"(filtered from _MAX_ total entries)",sInfoPostFix:"",sDecimal:"",sThousands:",",sLengthMenu:"Show _MENU_ entries",sLoadingRecords:"Loading...",sProcessing:"",sSearch:"Search:",sSearchPlaceholder:"",sUrl:"",sZeroRecords:"No matching records found"},oSearch:l.extend({},u.models.oSearch),sAjaxDataProp:"data",sAjaxSource:null,sDom:"lfrtip",searchDelay:null,sPaginationType:"simple_numbers",sScrollX:"",sScrollXInner:"",sScrollY:"",sServerMethod:"GET",renderer:null,rowId:"DT_RowId"};E(u.defaults); +u.defaults.column={aDataSort:null,iDataSort:-1,asSorting:["asc","desc"],bSearchable:!0,bSortable:!0,bVisible:!0,fnCreatedCell:null,mData:null,mRender:null,sCellType:"td",sClass:"",sContentPadding:"",sDefaultContent:null,sName:"",sSortDataType:"std",sTitle:null,sType:null,sWidth:null};E(u.defaults.column);u.models.oSettings={oFeatures:{bAutoWidth:null,bDeferRender:null,bFilter:null,bInfo:null,bLengthChange:null,bPaginate:null,bProcessing:null,bServerSide:null,bSort:null,bSortMulti:null,bSortClasses:null, +bStateSave:null},oScroll:{bCollapse:null,iBarWidth:0,sX:null,sXInner:null,sY:null},oLanguage:{fnInfoCallback:null},oBrowser:{bScrollOversize:!1,bScrollbarLeft:!1,bBounding:!1,barWidth:0},ajax:null,aanFeatures:[],aoData:[],aiDisplay:[],aiDisplayMaster:[],aIds:{},aoColumns:[],aoHeader:[],aoFooter:[],oPreviousSearch:{},aoPreSearchCols:[],aaSorting:null,aaSortingFixed:[],asStripeClasses:null,asDestroyStripes:[],sDestroyWidth:0,aoRowCallback:[],aoHeaderCallback:[],aoFooterCallback:[],aoDrawCallback:[], +aoRowCreatedCallback:[],aoPreDrawCallback:[],aoInitComplete:[],aoStateSaveParams:[],aoStateLoadParams:[],aoStateLoaded:[],sTableId:"",nTable:null,nTHead:null,nTFoot:null,nTBody:null,nTableWrapper:null,bDeferLoading:!1,bInitialised:!1,aoOpenRows:[],sDom:null,searchDelay:null,sPaginationType:"two_button",iStateDuration:0,aoStateSave:[],aoStateLoad:[],oSavedState:null,oLoadedState:null,sAjaxSource:null,sAjaxDataProp:null,jqXHR:null,json:q,oAjaxData:q,fnServerData:null,aoServerParams:[],sServerMethod:null, +fnFormatNumber:null,aLengthMenu:null,iDraw:0,bDrawing:!1,iDrawError:-1,_iDisplayLength:10,_iDisplayStart:0,_iRecordsTotal:0,_iRecordsDisplay:0,oClasses:{},bFiltered:!1,bSorted:!1,bSortCellsTop:null,oInit:null,aoDestroyCallback:[],fnRecordsTotal:function(){return"ssp"==Q(this)?1*this._iRecordsTotal:this.aiDisplayMaster.length},fnRecordsDisplay:function(){return"ssp"==Q(this)?1*this._iRecordsDisplay:this.aiDisplay.length},fnDisplayEnd:function(){var a=this._iDisplayLength,b=this._iDisplayStart,c=b+ +a,d=this.aiDisplay.length,e=this.oFeatures,h=e.bPaginate;return e.bServerSide?!1===h||-1===a?b+d:Math.min(b+a,this._iRecordsDisplay):!h||c>d||-1===a?d:c},oInstance:null,sInstance:null,iTabIndex:0,nScrollHead:null,nScrollFoot:null,aLastSort:[],oPlugins:{},rowIdFn:null,rowId:null};u.ext=M={buttons:{},classes:{},build:"dt/dt-1.12.1",errMode:"alert",feature:[],search:[],selector:{cell:[],column:[],row:[]},internal:{},legacy:{ajax:null},pager:{},renderer:{pageButton:{},header:{}},order:{},type:{detect:[], +search:{},order:{}},_unique:0,fnVersionCheck:u.fnVersionCheck,iApiIndex:0,oJUIClasses:{},sVersion:u.version};l.extend(M,{afnFiltering:M.search,aTypes:M.type.detect,ofnSearch:M.type.search,oSort:M.type.order,afnSortData:M.order,aoFeatures:M.feature,oApi:M.internal,oStdClasses:M.classes,oPagination:M.pager});l.extend(u.ext.classes,{sTable:"dataTable",sNoFooter:"no-footer",sPageButton:"paginate_button",sPageButtonActive:"current",sPageButtonDisabled:"disabled",sStripeOdd:"odd",sStripeEven:"even",sRowEmpty:"dataTables_empty", +sWrapper:"dataTables_wrapper",sFilter:"dataTables_filter",sInfo:"dataTables_info",sPaging:"dataTables_paginate paging_",sLength:"dataTables_length",sProcessing:"dataTables_processing",sSortAsc:"sorting_asc",sSortDesc:"sorting_desc",sSortable:"sorting",sSortableAsc:"sorting_desc_disabled",sSortableDesc:"sorting_asc_disabled",sSortableNone:"sorting_disabled",sSortColumn:"sorting_",sFilterInput:"",sLengthSelect:"",sScrollWrapper:"dataTables_scroll",sScrollHead:"dataTables_scrollHead",sScrollHeadInner:"dataTables_scrollHeadInner", +sScrollBody:"dataTables_scrollBody",sScrollFoot:"dataTables_scrollFoot",sScrollFootInner:"dataTables_scrollFootInner",sHeaderTH:"",sFooterTH:"",sSortJUIAsc:"",sSortJUIDesc:"",sSortJUI:"",sSortJUIAscAllowed:"",sSortJUIDescAllowed:"",sSortJUIWrapper:"",sSortIcon:"",sJUIHeader:"",sJUIFooter:""});var ic=u.ext.pager;l.extend(ic,{simple:function(a,b){return["previous","next"]},full:function(a,b){return["first","previous","next","last"]},numbers:function(a,b){return[Ea(a,b)]},simple_numbers:function(a,b){return["previous", +Ea(a,b),"next"]},full_numbers:function(a,b){return["first","previous",Ea(a,b),"next","last"]},first_last_numbers:function(a,b){return["first",Ea(a,b),"last"]},_numbers:Ea,numbers_length:7});l.extend(!0,u.ext.renderer,{pageButton:{_:function(a,b,c,d,e,h){var f=a.oClasses,g=a.oLanguage.oPaginate,k=a.oLanguage.oAria.paginate||{},m,n,p=0,t=function(x,w){var r,C=f.sPageButtonDisabled,G=function(I){Ta(a,I.data.action,!0)};var ba=0;for(r=w.length;ba").appendTo(x);t(O,L)}else{m=null;n=L;O=a.iTabIndex;switch(L){case "ellipsis":x.append('');break;case "first":m=g.sFirst;0===e&&(O=-1,n+=" "+C);break;case "previous":m=g.sPrevious;0===e&&(O=-1,n+=" "+C);break;case "next":m=g.sNext;if(0===h||e===h-1)O=-1,n+=" "+C;break;case "last":m=g.sLast;if(0===h||e===h-1)O=-1,n+=" "+C;break;default:m=a.fnFormatNumber(L+1),n=e===L?f.sPageButtonActive:""}null!==m&&(O=l("",{"class":f.sPageButton+" "+n,"aria-controls":a.sTableId, +"aria-label":k[L],"data-dt-idx":p,tabindex:O,id:0===c&&"string"===typeof L?a.sTableId+"_"+L:null}).html(m).appendTo(x),sb(O,{action:L},G),p++)}}};try{var v=l(b).find(A.activeElement).data("dt-idx")}catch(x){}t(l(b).empty(),d);v!==q&&l(b).find("[data-dt-idx="+v+"]").trigger("focus")}}});l.extend(u.ext.type.detect,[function(a,b){b=b.oLanguage.sDecimal;return yb(a,b)?"num"+b:null},function(a,b){if(a&&!(a instanceof Date)&&!Dc.test(a))return null;b=Date.parse(a);return null!==b&&!isNaN(b)||aa(a)?"date": +null},function(a,b){b=b.oLanguage.sDecimal;return yb(a,b,!0)?"num-fmt"+b:null},function(a,b){b=b.oLanguage.sDecimal;return pc(a,b)?"html-num"+b:null},function(a,b){b=b.oLanguage.sDecimal;return pc(a,b,!0)?"html-num-fmt"+b:null},function(a,b){return aa(a)||"string"===typeof a&&-1!==a.indexOf("<")?"html":null}]);l.extend(u.ext.type.search,{html:function(a){return aa(a)?a:"string"===typeof a?a.replace(mc," ").replace(Ya,""):""},string:function(a){return aa(a)?a:"string"===typeof a?a.replace(mc," "): +a}});var Xa=function(a,b,c,d){if(0!==a&&(!a||"-"===a))return-Infinity;b&&(a=oc(a,b));a.replace&&(c&&(a=a.replace(c,"")),d&&(a=a.replace(d,"")));return 1*a};l.extend(M.type.order,{"date-pre":function(a){a=Date.parse(a);return isNaN(a)?-Infinity:a},"html-pre":function(a){return aa(a)?"":a.replace?a.replace(/<.*?>/g,"").toLowerCase():a+""},"string-pre":function(a){return aa(a)?"":"string"===typeof a?a.toLowerCase():a.toString?a.toString():""},"string-asc":function(a,b){return ab?1:0},"string-desc":function(a, +b){return ab?-1:0}});bb("");l.extend(!0,u.ext.renderer,{header:{_:function(a,b,c,d){l(a.nTable).on("order.dt.DT",function(e,h,f,g){a===h&&(e=c.idx,b.removeClass(d.sSortAsc+" "+d.sSortDesc).addClass("asc"==g[e]?d.sSortAsc:"desc"==g[e]?d.sSortDesc:c.sSortingClass))})},jqueryui:function(a,b,c,d){l("
").addClass(d.sSortJUIWrapper).append(b.contents()).append(l("").addClass(d.sSortIcon+" "+c.sSortingClassJUI)).appendTo(b);l(a.nTable).on("order.dt.DT",function(e,h,f,g){a===h&&(e=c.idx, +b.removeClass(d.sSortAsc+" "+d.sSortDesc).addClass("asc"==g[e]?d.sSortAsc:"desc"==g[e]?d.sSortDesc:c.sSortingClass),b.find("span."+d.sSortIcon).removeClass(d.sSortJUIAsc+" "+d.sSortJUIDesc+" "+d.sSortJUI+" "+d.sSortJUIAscAllowed+" "+d.sSortJUIDescAllowed).addClass("asc"==g[e]?d.sSortJUIAsc:"desc"==g[e]?d.sSortJUIDesc:c.sSortingClassJUI))})}}});var $a=function(a){Array.isArray(a)&&(a=a.join(","));return"string"===typeof a?a.replace(/&/g,"&").replace(//g,">").replace(/"/g, +"""):a},kc=!1,zc=",",Ac=".";if(Intl)try{for(var Ha=(new Intl.NumberFormat).formatToParts(100000.1),ra=0;rah?"-":"",g=parseFloat(h);if(isNaN(g))return $a(h);g=g.toFixed(c);h=Math.abs(g);g=parseInt(h,10);h=c?b+(h-g).toFixed(c).substring(2):"";0===g&&0===parseFloat(h)&&(f="");return f+(d||"")+g.toString().replace(/\B(?=(\d{3})+(?!\d))/g,a)+h+(e||"")}}},text:function(){return{display:$a,filter:$a}}}; +l.extend(u.ext.internal,{_fnExternApiFunc:lc,_fnBuildAjax:Qa,_fnAjaxUpdate:Kb,_fnAjaxParameters:Tb,_fnAjaxUpdateDraw:Ub,_fnAjaxDataSrc:za,_fnAddColumn:cb,_fnColumnOptions:Ia,_fnAdjustColumnSizing:sa,_fnVisibleToColumnIndex:ta,_fnColumnIndexToVisible:ua,_fnVisbleColumns:na,_fnGetColumns:Ka,_fnColumnTypes:eb,_fnApplyColumnDefs:Hb,_fnHungarianMap:E,_fnCamelToHungarian:P,_fnLanguageCompat:la,_fnBrowserDetect:Fb,_fnAddData:ia,_fnAddTr:La,_fnNodeToDataIndex:function(a,b){return b._DT_RowIndex!==q?b._DT_RowIndex: +null},_fnNodeToColumnIndex:function(a,b,c){return l.inArray(c,a.aoData[b].anCells)},_fnGetCellData:T,_fnSetCellData:Ib,_fnSplitObjNotation:hb,_fnGetObjectDataFn:ma,_fnSetObjectDataFn:ha,_fnGetDataMaster:ib,_fnClearTable:Ma,_fnDeleteIndex:Na,_fnInvalidate:va,_fnGetRowElements:gb,_fnCreateTr:fb,_fnBuildHead:Jb,_fnDrawHead:xa,_fnDraw:ja,_fnReDraw:ka,_fnAddOptionsHtml:Mb,_fnDetectHeader:wa,_fnGetUniqueThs:Pa,_fnFeatureHtmlFilter:Ob,_fnFilterComplete:ya,_fnFilterCustom:Xb,_fnFilterColumn:Wb,_fnFilter:Vb, +_fnFilterCreateSearch:nb,_fnEscapeRegex:ob,_fnFilterData:Yb,_fnFeatureHtmlInfo:Rb,_fnUpdateInfo:ac,_fnInfoMacros:bc,_fnInitialise:Aa,_fnInitComplete:Ra,_fnLengthChange:pb,_fnFeatureHtmlLength:Nb,_fnFeatureHtmlPaginate:Sb,_fnPageChange:Ta,_fnFeatureHtmlProcessing:Pb,_fnProcessingDisplay:V,_fnFeatureHtmlTable:Qb,_fnScrollDraw:Ja,_fnApplyToChildren:da,_fnCalculateColumnWidths:db,_fnThrottle:mb,_fnConvertToWidth:cc,_fnGetWidestNode:dc,_fnGetMaxLenString:ec,_fnStringToCss:K,_fnSortFlatten:oa,_fnSort:Lb, +_fnSortAria:gc,_fnSortListener:rb,_fnSortAttachListener:kb,_fnSortingClasses:Va,_fnSortData:fc,_fnSaveState:Da,_fnLoadState:hc,_fnImplementState:tb,_fnSettingsFromNode:Wa,_fnLog:ea,_fnMap:Y,_fnBindAction:sb,_fnCallbackReg:R,_fnCallbackFire:F,_fnLengthOverflow:qb,_fnRenderer:lb,_fnDataSource:Q,_fnRowAttributes:jb,_fnExtend:ub,_fnCalculateEnd:function(){}});l.fn.dataTable=u;u.$=l;l.fn.dataTableSettings=u.settings;l.fn.dataTableExt=u.ext;l.fn.DataTable=function(a){return l(this).dataTable(a).api()}; +l.each(u,function(a,b){l.fn.DataTable[a]=b});return u}); + + +/*! + DataTables styling integration + ©2018 SpryMedia Ltd - datatables.net/license +*/ +(function(c){"function"===typeof define&&define.amd?define(["jquery","datatables.net"],function(a){return c(a,window,document)}):"object"===typeof exports?module.exports=function(a,b){a||(a=window);b&&b.fn.dataTable||(b=require("datatables.net")(a,b).$);return c(b,a,a.document)}:c(jQuery,window,document)})(function(c,a,b,d){return c.fn.dataTable}); + + diff --git a/resources/lang/en/pagination.php b/resources/lang/en/pagination.php index a4c4df70..5ec3e8fb 100644 --- a/resources/lang/en/pagination.php +++ b/resources/lang/en/pagination.php @@ -3,4 +3,26 @@ return [ 'next' => 'Next »', 'previous' => '« Previous', + "decimal" => "", + "emptyTable" => "No data available in table", + "info" => "Showing _START_ to _END_ of _TOTAL_ entries", + "infoEmpty" => "Showing 0 to 0 of 0 entries", + "infoFiltered" => "(filtered from _MAX_ total entries)", + "infoPostFix" => "", + "thousands" => ",", + "lengthMenu" => "Show _MENU_ entries", + "loadingRecords" => "Loading...", + "processing" => "", + "search" => "Search:", + "zeroRecords" => "No matching records found", + "paginate" => [ + "first" => "First", + "last" => "Last", + "next" => "Next", + "previous" => "Previous" + ], + "aria" => [ + "sortAscending" => ": activate to sort column ascending", + "sortDescending"=> ": activate to sort column descending" + ] ]; diff --git a/resources/lang/zh_CN/pagination.php b/resources/lang/zh_CN/pagination.php index e13e0403..5a0a85a5 100644 --- a/resources/lang/zh_CN/pagination.php +++ b/resources/lang/zh_CN/pagination.php @@ -3,4 +3,26 @@ return [ 'next' => '下一页 »', 'previous' => '« 上一页', + "decimal" => "", + "emptyTable" => "无数据", + "info" => "当前展示第 _START_ 至第 _END_ 条,共 _TOTAL_ 条记录", + "infoEmpty" => "当前展示第 0 条至第 0 条,共 0 条记录", + "infoFiltered" => "(筛选自 _MAX_ 条记录)", + "infoPostFix" => "", + "thousands" => ",", + "lengthMenu" => "每页展示 _MENU_ 条记录", + "loadingRecords" => "加载中...", + "processing" => "", + "search" => "搜索:", + "zeroRecords" => "没有发现任何匹配的记录", + "paginate" => [ + "first" => "首页", + "last" => "尾页", + "next" => "下一页", + "previous" => "上一页" + ], + "aria" => [ + "sortAscending" => ": 升序排序", + "sortDescending"=> ": 降序排序" + ] ]; diff --git a/resources/lang/zh_TW/pagination.php b/resources/lang/zh_TW/pagination.php index c55a1e03..68990b58 100644 --- a/resources/lang/zh_TW/pagination.php +++ b/resources/lang/zh_TW/pagination.php @@ -3,4 +3,26 @@ return [ 'next' => '下一頁 »', 'previous' => '« 上一頁', + "decimal" => "", + "emptyTable" => "無數據", + "info" => "當前展示第 _START_ 至第 _END_ 條,共 _TOTAL_ 條記錄", + "infoEmpty" => "當前展示第 0 條至第 0 條,共 0 條記錄", + "infoFiltered" => "(篩選自 _MAX_ 條記錄)", + "infoPostFix" => "", + "thousands" => ",", + "lengthMenu" => "每頁展示 _MENU_ 條記錄", + "loadingRecords" => "加載中...", + "processing" => "", + "search" => "搜索:", + "zeroRecords" => "沒有發現任何匹配的記錄", + "paginate" => [ + "first" => "首頁", + "last" => "尾頁", + "next" => "下一頁", + "previous" => "上一頁" + ], + "aria" => [ + "sortAscending" => ": 升序排序", + "sortDescending"=> ": 降序排序" + ] ]; diff --git a/resources/views/data-table.blade.php b/resources/views/data-table.blade.php new file mode 100644 index 00000000..272ce939 --- /dev/null +++ b/resources/views/data-table.blade.php @@ -0,0 +1,31 @@ + + + + + + + @stack('css') + + + + @stack('scripts') + + + +@yield('content') + + From f76e656f779b37a7dc2b3153e90a9fbc3031b8ab Mon Sep 17 00:00:00 2001 From: xiaomlove Date: Thu, 8 Sep 2022 19:50:37 +0800 Subject: [PATCH 05/12] rsync include public/vendor --- nexus/Install/Update.php | 1 + 1 file changed, 1 insertion(+) diff --git a/nexus/Install/Update.php b/nexus/Install/Update.php index 5dc5d344..54ff934a 100644 --- a/nexus/Install/Update.php +++ b/nexus/Install/Update.php @@ -386,6 +386,7 @@ class Update extends Install } // $command = sprintf('cp -raf %s/. %s', $path, ROOT_PATH); $command = "rsync -rvq $path/ " . ROOT_PATH; + $command .= " --include=public/vendor"; foreach ($excludes as $exclude) { $command .= " --exclude=$exclude"; } From d715012bc177e6254a472ccf008de3f96c17698c Mon Sep 17 00:00:00 2001 From: xiaomlove Date: Thu, 8 Sep 2022 21:48:15 +0800 Subject: [PATCH 06/12] torrent delete independent of torrent management --- lang/chs/lang_settings.php | 4 +++- lang/cht/lang_settings.php | 4 +++- lang/en/lang_settings.php | 4 +++- nexus/Install/settings.default.php | 1 + public/delete.php | 2 +- public/edit.php | 2 +- public/settings.php | 5 ++++- resources/lang/en/permission.php | 6 +++++- resources/lang/zh_CN/permission.php | 4 ++++ resources/lang/zh_TW/permission.php | 4 ++++ 10 files changed, 29 insertions(+), 7 deletions(-) diff --git a/lang/chs/lang_settings.php b/lang/chs/lang_settings.php index c3dcb295..9566cb22 100644 --- a/lang/chs/lang_settings.php +++ b/lang/chs/lang_settings.php @@ -91,7 +91,7 @@ $lang_settings = array 'row_view_userlist' => "查看用户列表", 'text_view_userlist_note' => "。查看、搜索用户列表。", 'row_torrent_management' => "管理种子", - 'text_torrent_management_note' => "。编辑、删除种子,但不能将种子设为置顶或促销。", + 'text_torrent_management_note' => "。编辑种子,但不能将种子设为置顶或促销或删除。", 'row_torrent_sticky' => "设定种子置顶", 'text_torrent_sticky_note' => "。将种子设为置顶", 'row_torrent_on_promotion' => "设定种子为促销", @@ -771,6 +771,8 @@ $lang_settings = array 'text_harem_addition_note' => '倍作为奖励(系数,如填入 0.01,后宫获得 100 魔力则奖励用户 100 * 0.01 = 1)', 'row_offer_skip_approved_count' => '直接发布候选通过数', 'text_offer_skip_approved_count_note' => '当通过的候选数大于等于此数值时,可直接发布不用提交候选。', + 'row_torrent_delete' => '删除种子', + 'text_torrent_delete_note' => '。删除种子', ); ?> diff --git a/lang/cht/lang_settings.php b/lang/cht/lang_settings.php index 9701895b..6ec1fc42 100644 --- a/lang/cht/lang_settings.php +++ b/lang/cht/lang_settings.php @@ -91,7 +91,7 @@ $lang_settings = array 'row_view_userlist' => "檢視用戶清單", 'text_view_userlist_note' => "。檢視、搜索用戶清單。", 'row_torrent_management' => "管理種子", - 'text_torrent_management_note' => "。編輯、移除種子,但無法將種子設為置頂或促銷。", + 'text_torrent_management_note' => "。編輯種子,但無法將種子設為置頂或促銷或移除。", 'row_torrent_sticky' => "設定種子置頂", 'text_torrent_sticky_note' => "。將種子設為置頂", 'row_torrent_on_promotion' => "設定種子為促銷", @@ -771,6 +771,8 @@ $lang_settings = array 'text_harem_addition_note' => '倍作為獎勵(系數,如填入 0.01,後宮獲得 100 魔力則獎勵用戶 100 * 0.01 = 1)', 'row_offer_skip_approved_count' => '直接發布候選通過數', 'text_offer_skip_approved_count_note' => '當通過的候選數大於等於此數值時,可直接發布不用提交候選。', + 'row_torrent_delete' => '移除種子', + 'text_torrent_delete_note' => '。移除種子', ); ?> diff --git a/lang/en/lang_settings.php b/lang/en/lang_settings.php index 9a049d52..9e0fc03b 100644 --- a/lang/en/lang_settings.php +++ b/lang/en/lang_settings.php @@ -91,7 +91,7 @@ $lang_settings = array 'row_view_userlist' => "View User List", 'text_view_userlist_note' => ". View, search user list", 'row_torrent_management' => "Torrent Management", - 'text_torrent_management_note' => ". Edit, delete torrents, excluding setting torrent sticky or on promotion", + 'text_torrent_management_note' => ". Edit torrents, excluding setting torrent sticky or on promotion or delete", 'row_torrent_sticky' => "Torrent Sticky", 'text_torrent_sticky_note' => ". Set torrents sticky", 'row_torrent_on_promotion' => "Torrent on Promotion", @@ -771,6 +771,8 @@ $lang_settings = array 'text_harem_addition_note' => 'times as reward (factor, e.g. fill in 0.01, if harem gets 100 bonus then reward user 100 * 0.01 = 1)', 'row_offer_skip_approved_count' => 'Direct upload offer allow count', 'text_offer_skip_approved_count_note' => 'When the number of approved offer is greater than or equal to this value, you can upload directly without submitting offers.', + 'row_torrent_delete' => 'Delete torrent', + 'text_torrent_delete_note' => '.Delete torrent', ); ?> diff --git a/nexus/Install/settings.default.php b/nexus/Install/settings.default.php index 10acad0f..66c584f3 100644 --- a/nexus/Install/settings.default.php +++ b/nexus/Install/settings.default.php @@ -176,6 +176,7 @@ return array ( 'view_special_torrent' => '4', 'torrent_hr' => User::CLASS_ADMINISTRATOR, 'torrent-approval' => User::CLASS_ADMINISTRATOR, + 'torrent-delete' => User::CLASS_ADMINISTRATOR, ), 'tweak' => array ( diff --git a/public/delete.php b/public/delete.php index 0db79d51..2c2cc32f 100644 --- a/public/delete.php +++ b/public/delete.php @@ -4,7 +4,7 @@ dbconn(); require_once(get_langfile_path()); require_once(get_langfile_path("",true)); loggedinorreturn(); -user_can('torrentmanage', true); +user_can('torrent-delete', true); function bark($msg) { global $lang_delete; stdhead(); diff --git a/public/edit.php b/public/edit.php index 2d99b928..ae6720c1 100644 --- a/public/edit.php +++ b/public/edit.php @@ -205,7 +205,7 @@ else { print("
\n"); print("
".$lang_getusertorrentlistajax['col_type']."".$lang_getusertorrentlistajax['col_name']."".$lang_getusertorrentlistajax['col_added']."\"size\"\"seeders\"\"leechers\"".$lang_getusertorrentlistajax['col_uploaded']."".$lang_getusertorrentlistajax['col_downloaded']."".$lang_getusertorrentlistajax['col_ratio']."".$lang_getusertorrentlistajax['col_se_time']."".$lang_getusertorrentlistajax['col_le_time']."".$lang_getusertorrentlistajax['col_time_completed']."".$lang_getusertorrentlistajax['col_anonymous']."%s%s
",{valign:"top",colSpan:na(a),"class":a.oClasses.sRowEmpty}).html(e))[0];F(a,"aoHeaderCallback","header",[l(a.nTHead).children("tr")[0], +ib(a),m,n,k]);F(a,"aoFooterCallback","footer",[l(a.nTFoot).children("tr")[0],ib(a),m,n,k]);d=l(a.nTBody);d.children().detach();d.append(l(c));F(a,"aoDrawCallback","draw",[a]);a.bSorted=!1;a.bFiltered=!1;a.bDrawing=!1}}function ka(a,b){var c=a.oFeatures,d=c.bFilter;c.bSort&&Lb(a);d?ya(a,a.oPreviousSearch):a.aiDisplay=a.aiDisplayMaster.slice();!0!==b&&(a._iDisplayStart=0);a._drawHold=b;ja(a);a._drawHold=!1}function Mb(a){var b=a.oClasses,c=l(a.nTable);c=l("
").insertBefore(c);var d=a.oFeatures, +e=l("
",{id:a.sTableId+"_wrapper","class":b.sWrapper+(a.nTFoot?"":" "+b.sNoFooter)});a.nHolding=c[0];a.nTableWrapper=e[0];a.nTableReinsertBefore=a.nTable.nextSibling;for(var h=a.sDom.split(""),f,g,k,m,n,p,t=0;t")[0];m=h[t+1];if("'"==m||'"'==m){n="";for(p=2;h[t+p]!=m;)n+=h[t+p],p++;"H"==n?n=b.sJUIHeader:"F"==n&&(n=b.sJUIFooter);-1!=n.indexOf(".")?(m=n.split("."),k.id=m[0].substr(1,m[0].length-1),k.className=m[1]):"#"==n.charAt(0)?k.id=n.substr(1, +n.length-1):k.className=n;t+=p}e.append(k);e=l(k)}else if(">"==g)e=e.parent();else if("l"==g&&d.bPaginate&&d.bLengthChange)f=Nb(a);else if("f"==g&&d.bFilter)f=Ob(a);else if("r"==g&&d.bProcessing)f=Pb(a);else if("t"==g)f=Qb(a);else if("i"==g&&d.bInfo)f=Rb(a);else if("p"==g&&d.bPaginate)f=Sb(a);else if(0!==u.ext.feature.length)for(k=u.ext.feature,p=0,m=k.length;p',g=d.sSearch;g=g.match(/_INPUT_/)?g.replace("_INPUT_",f):g+f;b=l("
",{id:h.f?null:c+"_filter","class":b.sFilter}).append(l("
").addClass(b.sLength);a.aanFeatures.l||(k[0].id=c+"_length");k.children().append(a.oLanguage.sLengthMenu.replace("_MENU_",e[0].outerHTML));l("select",k).val(a._iDisplayLength).on("change.DT",function(m){pb(a,l(this).val());ja(a)});l(a.nTable).on("length.dt.DT",function(m,n,p){a===n&&l("select",k).val(p)});return k[0]}function Sb(a){var b=a.sPaginationType,c=u.ext.pager[b],d="function"===typeof c,e=function(f){ja(f)};b=l("
").addClass(a.oClasses.sPaging+ +b)[0];var h=a.aanFeatures;d||c.fnInit(a,b,e);h.p||(b.id=a.sTableId+"_paginate",a.aoDrawCallback.push({fn:function(f){if(d){var g=f._iDisplayStart,k=f._iDisplayLength,m=f.fnRecordsDisplay(),n=-1===k;g=n?0:Math.ceil(g/k);k=n?1:Math.ceil(m/k);m=c(g,k);var p;n=0;for(p=h.p.length;nh&&(d=0)):"first"==b?d=0:"previous"==b?(d=0<=e?d-e:0,0>d&&(d=0)):"next"==b?d+e",{id:a.aanFeatures.r?null:a.sTableId+"_processing","class":a.oClasses.sProcessing}).html(a.oLanguage.sProcessing).append("
").insertBefore(a.nTable)[0]}function V(a, +b){a.oFeatures.bProcessing&&l(a.aanFeatures.r).css("display",b?"block":"none");F(a,null,"processing",[a,b])}function Qb(a){var b=l(a.nTable),c=a.oScroll;if(""===c.sX&&""===c.sY)return a.nTable;var d=c.sX,e=c.sY,h=a.oClasses,f=b.children("caption"),g=f.length?f[0]._captionSide:null,k=l(b[0].cloneNode(!1)),m=l(b[0].cloneNode(!1)),n=b.children("tfoot");n.length||(n=null);k=l("
",{"class":h.sScrollWrapper}).append(l("
",{"class":h.sScrollHead}).css({overflow:"hidden",position:"relative",border:0, +width:d?d?K(d):null:"100%"}).append(l("
",{"class":h.sScrollHeadInner}).css({"box-sizing":"content-box",width:c.sXInner||"100%"}).append(k.removeAttr("id").css("margin-left",0).append("top"===g?f:null).append(b.children("thead"))))).append(l("
",{"class":h.sScrollBody}).css({position:"relative",overflow:"auto",width:d?K(d):null}).append(b));n&&k.append(l("
",{"class":h.sScrollFoot}).css({overflow:"hidden",border:0,width:d?d?K(d):null:"100%"}).append(l("
",{"class":h.sScrollFootInner}).append(m.removeAttr("id").css("margin-left", +0).append("bottom"===g?f:null).append(b.children("tfoot")))));b=k.children();var p=b[0];h=b[1];var t=n?b[2]:null;if(d)l(h).on("scroll.DT",function(v){v=this.scrollLeft;p.scrollLeft=v;n&&(t.scrollLeft=v)});l(h).css("max-height",e);c.bCollapse||l(h).css("height",e);a.nScrollHead=p;a.nScrollBody=h;a.nScrollFoot=t;a.aoDrawCallback.push({fn:Ja,sName:"scrolling"});return k[0]}function Ja(a){var b=a.oScroll,c=b.sX,d=b.sXInner,e=b.sY;b=b.iBarWidth;var h=l(a.nScrollHead),f=h[0].style,g=h.children("div"),k= +g[0].style,m=g.children("table");g=a.nScrollBody;var n=l(g),p=g.style,t=l(a.nScrollFoot).children("div"),v=t.children("table"),x=l(a.nTHead),w=l(a.nTable),r=w[0],C=r.style,G=a.nTFoot?l(a.nTFoot):null,ba=a.oBrowser,L=ba.bScrollOversize;U(a.aoColumns,"nTh");var O=[],I=[],H=[],fa=[],Z,Ba=function(D){D=D.style;D.paddingTop="0";D.paddingBottom="0";D.borderTopWidth="0";D.borderBottomWidth="0";D.height=0};var X=g.scrollHeight>g.clientHeight;if(a.scrollBarVis!==X&&a.scrollBarVis!==q)a.scrollBarVis=X,sa(a); +else{a.scrollBarVis=X;w.children("thead, tfoot").remove();if(G){X=G.clone().prependTo(w);var ca=G.find("tr");var Ca=X.find("tr");X.find("[id]").removeAttr("id")}var Ua=x.clone().prependTo(w);x=x.find("tr");X=Ua.find("tr");Ua.find("th, td").removeAttr("tabindex");Ua.find("[id]").removeAttr("id");c||(p.width="100%",h[0].style.width="100%");l.each(Pa(a,Ua),function(D,W){Z=ta(a,D);W.style.width=a.aoColumns[Z].sWidth});G&&da(function(D){D.style.width=""},Ca);h=w.outerWidth();""===c?(C.width="100%",L&& +(w.find("tbody").height()>g.offsetHeight||"scroll"==n.css("overflow-y"))&&(C.width=K(w.outerWidth()-b)),h=w.outerWidth()):""!==d&&(C.width=K(d),h=w.outerWidth());da(Ba,X);da(function(D){var W=y.getComputedStyle?y.getComputedStyle(D).width:K(l(D).width());H.push(D.innerHTML);O.push(W)},X);da(function(D,W){D.style.width=O[W]},x);l(X).css("height",0);G&&(da(Ba,Ca),da(function(D){fa.push(D.innerHTML);I.push(K(l(D).css("width")))},Ca),da(function(D,W){D.style.width=I[W]},ca),l(Ca).height(0));da(function(D, +W){D.innerHTML='
'+H[W]+"
";D.childNodes[0].style.height="0";D.childNodes[0].style.overflow="hidden";D.style.width=O[W]},X);G&&da(function(D,W){D.innerHTML='
'+fa[W]+"
";D.childNodes[0].style.height="0";D.childNodes[0].style.overflow="hidden";D.style.width=I[W]},Ca);Math.round(w.outerWidth())g.offsetHeight||"scroll"==n.css("overflow-y")?h+b:h,L&&(g.scrollHeight>g.offsetHeight||"scroll"==n.css("overflow-y"))&& +(C.width=K(ca-b)),""!==c&&""===d||ea(a,1,"Possible column misalignment",6)):ca="100%";p.width=K(ca);f.width=K(ca);G&&(a.nScrollFoot.style.width=K(ca));!e&&L&&(p.height=K(r.offsetHeight+b));c=w.outerWidth();m[0].style.width=K(c);k.width=K(c);d=w.height()>g.clientHeight||"scroll"==n.css("overflow-y");e="padding"+(ba.bScrollbarLeft?"Left":"Right");k[e]=d?b+"px":"0px";G&&(v[0].style.width=K(c),t[0].style.width=K(c),t[0].style[e]=d?b+"px":"0px");w.children("colgroup").insertBefore(w.children("thead")); +n.trigger("scroll");!a.bSorted&&!a.bFiltered||a._drawHold||(g.scrollTop=0)}}function da(a,b,c){for(var d=0,e=0,h=b.length,f,g;e").appendTo(g.find("tbody"));g.find("thead, tfoot").remove();g.append(l(a.nTHead).clone()).append(l(a.nTFoot).clone());g.find("tfoot th, tfoot td").css("width","");m=Pa(a,g.find("thead")[0]); +for(v=0;v").css({width:w.sWidthOrig,margin:0,padding:0,border:0,height:1}));if(a.aoData.length)for(v=0;v").css(h||e?{position:"absolute",top:0,left:0,height:1,right:0,overflow:"hidden"}:{}).append(g).appendTo(p);h&&f?g.width(f):h? +(g.css("width","auto"),g.removeAttr("width"),g.width()").css("width",K(a)).appendTo(b||A.body);b=a[0].offsetWidth;a.remove();return b}function dc(a,b){var c=ec(a,b);if(0>c)return null;var d=a.aoData[c];return d.nTr?d.anCells[b]:l("
").html(T(a,c,b,"display"))[0]}function ec(a,b){for(var c,d=-1,e=-1,h=0,f=a.aoData.length;hd&&(d=c.length,e=h);return e}function K(a){return null===a?"0px":"number"==typeof a?0>a?"0px":a+"px":a.match(/\d$/)?a+"px":a}function oa(a){var b= +[],c=a.aoColumns;var d=a.aaSortingFixed;var e=l.isPlainObject(d);var h=[];var f=function(n){n.length&&!Array.isArray(n[0])?h.push(n):l.merge(h,n)};Array.isArray(d)&&f(d);e&&d.pre&&f(d.pre);f(a.aaSorting);e&&d.post&&f(d.post);for(a=0;aG?1:0;if(0!==C)return"asc"===r.dir?C:-C}C=c[n];G=c[p];return CG?1:0}):f.sort(function(n,p){var t,v=g.length, +x=e[n]._aSortData,w=e[p]._aSortData;for(t=0;tG?1:0})}a.bSorted=!0}function gc(a){var b=a.aoColumns,c=oa(a);a=a.oLanguage.oAria;for(var d=0,e=b.length;d/g,"");var k=h.nTh;k.removeAttribute("aria-sort");h.bSortable&&(0e?e+1:3))}e=0;for(h=d.length;ee?e+1:3))}a.aLastSort=d}function fc(a,b){var c=a.aoColumns[b],d=u.ext.order[c.sSortDataType],e;d&&(e=d.call(a.oInstance,a,b,ua(a,b)));for(var h,f=u.ext.type.order[c.sType+"-pre"],g=0,k=a.aoData.length;g=e.length?[0,m[1]]:m)}));b.search!==q&&l.extend(a.oPreviousSearch,$b(b.search));if(b.columns){f=0;for(d=b.columns.length;f=c&&(b=c-d);b-=b%d;if(-1===d||0>b)b=0;a._iDisplayStart=b}function lb(a,b){a=a.renderer;var c=u.ext.renderer[b]; +return l.isPlainObject(a)&&a[b]?c[a[b]]||c._:"string"===typeof a?c[a]||c._:c._}function Q(a){return a.oFeatures.bServerSide?"ssp":a.ajax||a.sAjaxSource?"ajax":"dom"}function Ea(a,b){var c=ic.numbers_length,d=Math.floor(c/2);b<=c?a=pa(0,b):a<=d?(a=pa(0,c-2),a.push("ellipsis"),a.push(b-1)):(a>=b-1-d?a=pa(b-(c-2),b):(a=pa(a-d+2,a+d-1),a.push("ellipsis"),a.push(b-1)),a.splice(0,0,"ellipsis"),a.splice(0,0,0));a.DT_el="span";return a}function bb(a){l.each({num:function(b){return Xa(b,a)},"num-fmt":function(b){return Xa(b, +a,vb)},"html-num":function(b){return Xa(b,a,Ya)},"html-num-fmt":function(b){return Xa(b,a,Ya,vb)}},function(b,c){M.type.order[b+a+"-pre"]=c;b.match(/^html\-/)&&(M.type.search[b+a]=M.type.search.html)})}function jc(a,b,c,d,e){return y.moment?a[b](e):y.luxon?a[c](e):d?a[d](e):a}function Za(a,b,c){if(y.moment){var d=y.moment.utc(a,b,c,!0);if(!d.isValid())return null}else if(y.luxon){d=b?y.luxon.DateTime.fromFormat(a,b):y.luxon.DateTime.fromISO(a);if(!d.isValid)return null;d.setLocale(c)}else b?(kc|| +alert("DataTables warning: Formatted date without Moment.js or Luxon - https://datatables.net/tn/17"),kc=!0):d=new Date(a);return d}function wb(a){return function(b,c,d,e){0===arguments.length?(d="en",b=c=null):1===arguments.length?(d="en",c=b,b=null):2===arguments.length&&(d=c,c=b,b=null);var h="datetime-"+c;u.ext.type.order[h]||(u.ext.type.detect.unshift(function(f){return f===h?h:!1}),u.ext.type.order[h+"-asc"]=function(f,g){f=f.valueOf();g=g.valueOf();return f===g?0:fg?-1:1});return function(f,g){if(null===f||f===q)"--now"===e?(f=new Date,f=new Date(Date.UTC(f.getFullYear(),f.getMonth(),f.getDate(),f.getHours(),f.getMinutes(),f.getSeconds()))):f="";if("type"===g)return h;if(""===f)return"sort"!==g?"":Za("0000-01-01 00:00:00",null,d);if(null!==c&&b===c&&"sort"!==g&&"type"!==g&&!(f instanceof Date))return f;var k=Za(f,b,d);if(null===k)return f;if("sort"===g)return k;f=null===c?jc(k,"toDate","toJSDate", +"")[a]():jc(k,"format","toFormat","toISOString",c);return"display"===g?$a(f):f}}}function lc(a){return function(){var b=[Wa(this[u.ext.iApiIndex])].concat(Array.prototype.slice.call(arguments));return u.ext.internal[a].apply(this,b)}}var u=function(a,b){if(this instanceof u)return l(a).DataTable(b);b=a;this.$=function(f,g){return this.api(!0).$(f,g)};this._=function(f,g){return this.api(!0).rows(f,g).data()};this.api=function(f){return f?new B(Wa(this[M.iApiIndex])):new B(this)};this.fnAddData=function(f, +g){var k=this.api(!0);f=Array.isArray(f)&&(Array.isArray(f[0])||l.isPlainObject(f[0]))?k.rows.add(f):k.row.add(f);(g===q||g)&&k.draw();return f.flatten().toArray()};this.fnAdjustColumnSizing=function(f){var g=this.api(!0).columns.adjust(),k=g.settings()[0],m=k.oScroll;f===q||f?g.draw(!1):(""!==m.sX||""!==m.sY)&&Ja(k)};this.fnClearTable=function(f){var g=this.api(!0).clear();(f===q||f)&&g.draw()};this.fnClose=function(f){this.api(!0).row(f).child.hide()};this.fnDeleteRow=function(f,g,k){var m=this.api(!0); +f=m.rows(f);var n=f.settings()[0],p=n.aoData[f[0][0]];f.remove();g&&g.call(this,n,p);(k===q||k)&&m.draw();return p};this.fnDestroy=function(f){this.api(!0).destroy(f)};this.fnDraw=function(f){this.api(!0).draw(f)};this.fnFilter=function(f,g,k,m,n,p){n=this.api(!0);null===g||g===q?n.search(f,k,m,p):n.column(g).search(f,k,m,p);n.draw()};this.fnGetData=function(f,g){var k=this.api(!0);if(f!==q){var m=f.nodeName?f.nodeName.toLowerCase():"";return g!==q||"td"==m||"th"==m?k.cell(f,g).data():k.row(f).data()|| +null}return k.data().toArray()};this.fnGetNodes=function(f){var g=this.api(!0);return f!==q?g.row(f).node():g.rows().nodes().flatten().toArray()};this.fnGetPosition=function(f){var g=this.api(!0),k=f.nodeName.toUpperCase();return"TR"==k?g.row(f).index():"TD"==k||"TH"==k?(f=g.cell(f).index(),[f.row,f.columnVisible,f.column]):null};this.fnIsOpen=function(f){return this.api(!0).row(f).child.isShown()};this.fnOpen=function(f,g,k){return this.api(!0).row(f).child(g,k).show().child()[0]};this.fnPageChange= +function(f,g){f=this.api(!0).page(f);(g===q||g)&&f.draw(!1)};this.fnSetColumnVis=function(f,g,k){f=this.api(!0).column(f).visible(g);(k===q||k)&&f.columns.adjust().draw()};this.fnSettings=function(){return Wa(this[M.iApiIndex])};this.fnSort=function(f){this.api(!0).order(f).draw()};this.fnSortListener=function(f,g,k){this.api(!0).order.listener(f,g,k)};this.fnUpdate=function(f,g,k,m,n){var p=this.api(!0);k===q||null===k?p.row(g).data(f):p.cell(g,k).data(f);(n===q||n)&&p.columns.adjust();(m===q||m)&& +p.draw();return 0};this.fnVersionCheck=M.fnVersionCheck;var c=this,d=b===q,e=this.length;d&&(b={});this.oApi=this.internal=M.internal;for(var h in u.ext.internal)h&&(this[h]=lc(h));this.each(function(){var f={},g=1").appendTo(t));r.nTHead=H[0];var fa=t.children("tbody");0===fa.length&&(fa=l("
\n"); print("\n"); - if (user_can('torrentmanage')) { + if (user_can('torrent-delete')) { print("

"); print("
\n"); print("\n"); diff --git a/public/settings.php b/public/settings.php index f212dd75..d186a52e 100644 --- a/public/settings.php +++ b/public/settings.php @@ -222,7 +222,7 @@ elseif ($action == 'savesettings_authority') // save user authority 'commanage','forummanage','viewuserlist','torrentmanage','torrentsticky', 'torrentonpromotion', 'torrent_hr', 'askreseed', 'viewnfo', 'torrentstructure','sendinvite','viewhistory','topten','log','confilog','userprofile', 'torrenthistory','prfmanage', 'cruprfmanage', 'uploadsub','delownsub','submanage','updateextinfo', 'viewanonymous','beanonymous','addoffer','offermanage', 'upload','uploadspecial', - 'view_special_torrent','movetorrent','chrmanage','viewinvite', 'buyinvite','seebanned','againstoffer','userbar', 'torrent-approval' + 'view_special_torrent','movetorrent','chrmanage','viewinvite', 'buyinvite','seebanned','againstoffer','userbar', 'torrent-approval', 'torrent-delete' ); GetVar($validConfig); $AUTHORITY = []; @@ -441,6 +441,9 @@ elseif ($action == 'authoritysettings') //Authority settings tr($lang_settings['row_forum_management'], $lang_settings['text_minimum_class'].classlist('forummanage',$maxclass,$AUTHORITY['forummanage'],0,true).$lang_settings['text_default'].get_user_class_name(UC_ADMINISTRATOR,false,true,true).$lang_settings['text_forum_management_note'],1); tr($lang_settings['row_view_userlist'], $lang_settings['text_minimum_class'].classlist('viewuserlist',$maxclass,$AUTHORITY['viewuserlist'],0,true).$lang_settings['text_default'].get_user_class_name(UC_POWER_USER,false,true,true).$lang_settings['text_view_userlist_note'],1); tr($lang_settings['row_torrent_management'], $lang_settings['text_minimum_class'].classlist('torrentmanage',$maxclass,$AUTHORITY['torrentmanage'],0,true).$lang_settings['text_default'].get_user_class_name(UC_MODERATOR,false,true,true).$lang_settings['text_torrent_management_note'], 1); + tr($lang_settings['row_torrent_delete'], $lang_settings['text_minimum_class'].classlist('torrent-delete',$maxclass,$AUTHORITY['torrent-delete'],0,true).$lang_settings['text_default'].get_user_class_name(UC_MODERATOR,false,true,true).$lang_settings['text_torrent_delete_note'], 1); + + tr($lang_settings['row_torrent_sticky'], $lang_settings['text_minimum_class'].classlist('torrentsticky',$maxclass,$AUTHORITY['torrentsticky'],0,true).$lang_settings['text_default'].get_user_class_name(UC_ADMINISTRATOR,false,true,true).$lang_settings['text_torrent_sticky_note'],1); tr($lang_settings['row_torrent_on_promotion'], $lang_settings['text_minimum_class'].classlist('torrentonpromotion',$maxclass,$AUTHORITY['torrentonpromotion'] ?? '',0,true).$lang_settings['text_default'].get_user_class_name(UC_ADMINISTRATOR,false,true,true).$lang_settings['text_torrent_promotion_note'],1); tr($lang_settings['row_torrent_hr'], $lang_settings['text_minimum_class'].classlist('torrent_hr',$maxclass,$AUTHORITY['torrent_hr'] ?? '',0,true).$lang_settings['text_default'].get_user_class_name(UC_ADMINISTRATOR,false,true,true).$lang_settings['text_torrent_hr_note'],1); diff --git a/resources/lang/en/permission.php b/resources/lang/en/permission.php index f345c7c8..45bed5b5 100644 --- a/resources/lang/en/permission.php +++ b/resources/lang/en/permission.php @@ -59,7 +59,11 @@ return [ ], 'torrentmanage' => [ 'text' => 'Torrent Management', - 'desc' => 'Edit, delete torrents, excluding setting torrent sticky or on promotion', + 'desc' => 'Edit torrents, excluding setting torrent sticky or on promotion or delete', + ], + 'torrent-delete' => [ + 'text' => 'Delete torrent', + 'desc' => 'Delete torrent', ], 'torrentsticky' => [ 'text' => 'Torrent Sticky', diff --git a/resources/lang/zh_CN/permission.php b/resources/lang/zh_CN/permission.php index c6e4645c..5987a378 100644 --- a/resources/lang/zh_CN/permission.php +++ b/resources/lang/zh_CN/permission.php @@ -61,6 +61,10 @@ return [ 'text' => '管理种子', 'desc' => '编辑、删除种子,但不能将种子设为置顶或促销', ], + 'torrent-delete' => [ + 'text' => '删除种子', + 'desc' => '删除种子', + ], 'torrentsticky' => [ 'text' => '设定种子置顶', 'desc' => '将种子设为置顶', diff --git a/resources/lang/zh_TW/permission.php b/resources/lang/zh_TW/permission.php index 7c7f5935..642c8097 100644 --- a/resources/lang/zh_TW/permission.php +++ b/resources/lang/zh_TW/permission.php @@ -61,6 +61,10 @@ return [ 'text' => '管理種子', 'desc' => '編輯、移除種子,但無法將種子設為置頂或促銷', ], + 'torrent-delete' => [ + 'text' => '移除种子', + 'desc' => '移除种子', + ], 'torrentsticky' => [ 'text' => '設定種子置頂', 'desc' => '將種子設為置頂', From 57a97f2b5c864d524609fceb2ef9d6ef7111731d Mon Sep 17 00:00:00 2001 From: xiaomlove Date: Thu, 8 Sep 2022 21:50:18 +0800 Subject: [PATCH 07/12] torrent delete default administrator --- public/settings.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/public/settings.php b/public/settings.php index d186a52e..d0e31dcf 100644 --- a/public/settings.php +++ b/public/settings.php @@ -441,7 +441,7 @@ elseif ($action == 'authoritysettings') //Authority settings tr($lang_settings['row_forum_management'], $lang_settings['text_minimum_class'].classlist('forummanage',$maxclass,$AUTHORITY['forummanage'],0,true).$lang_settings['text_default'].get_user_class_name(UC_ADMINISTRATOR,false,true,true).$lang_settings['text_forum_management_note'],1); tr($lang_settings['row_view_userlist'], $lang_settings['text_minimum_class'].classlist('viewuserlist',$maxclass,$AUTHORITY['viewuserlist'],0,true).$lang_settings['text_default'].get_user_class_name(UC_POWER_USER,false,true,true).$lang_settings['text_view_userlist_note'],1); tr($lang_settings['row_torrent_management'], $lang_settings['text_minimum_class'].classlist('torrentmanage',$maxclass,$AUTHORITY['torrentmanage'],0,true).$lang_settings['text_default'].get_user_class_name(UC_MODERATOR,false,true,true).$lang_settings['text_torrent_management_note'], 1); - tr($lang_settings['row_torrent_delete'], $lang_settings['text_minimum_class'].classlist('torrent-delete',$maxclass,$AUTHORITY['torrent-delete'],0,true).$lang_settings['text_default'].get_user_class_name(UC_MODERATOR,false,true,true).$lang_settings['text_torrent_delete_note'], 1); + tr($lang_settings['row_torrent_delete'], $lang_settings['text_minimum_class'].classlist('torrent-delete',$maxclass,$AUTHORITY['torrent-delete'],0,true).$lang_settings['text_default'].get_user_class_name(UC_ADMINISTRATOR,false,true,true).$lang_settings['text_torrent_delete_note'], 1); tr($lang_settings['row_torrent_sticky'], $lang_settings['text_minimum_class'].classlist('torrentsticky',$maxclass,$AUTHORITY['torrentsticky'],0,true).$lang_settings['text_default'].get_user_class_name(UC_ADMINISTRATOR,false,true,true).$lang_settings['text_torrent_sticky_note'],1); From 55589c8d8ed7bacfc6bde342bb025caccec38069 Mon Sep 17 00:00:00 2001 From: xiaomlove Date: Thu, 8 Sep 2022 22:01:30 +0800 Subject: [PATCH 08/12] clear_setting_cache() immediately --- include/functions.php | 1 + nexus/Install/Install.php | 1 + public/settings.php | 1 - 3 files changed, 2 insertions(+), 1 deletion(-) diff --git a/include/functions.php b/include/functions.php index 385b3559..6244ed4b 100644 --- a/include/functions.php +++ b/include/functions.php @@ -5169,6 +5169,7 @@ function saveSetting($prefix, $nameAndValue, $autoload = 'yes') } $sql .= implode(",", $data) . " on duplicate key update value = values(value)"; \Nexus\Database\NexusDB::statement($sql); + clear_setting_cache(); do_action("nexus_setting_update", $prefix, $nameAndValue); } diff --git a/nexus/Install/Install.php b/nexus/Install/Install.php index a610ad9a..61fdf0c0 100644 --- a/nexus/Install/Install.php +++ b/nexus/Install/Install.php @@ -568,6 +568,7 @@ class Install $this->doLog("[SAVE SETTING], prefix: $prefix, nameAndValues: " . json_encode($group)); saveSetting($prefix, $group); } + } public function createSymbolicLinks($symbolicLinks) diff --git a/public/settings.php b/public/settings.php index d0e31dcf..3e3c3c16 100644 --- a/public/settings.php +++ b/public/settings.php @@ -11,7 +11,6 @@ permissiondenied(); function go_back() { global $lang_settings; - clear_setting_cache(); stdmsg($lang_settings['std_message'], $lang_settings['std_click']."".$lang_settings['std_here']."".$lang_settings['std_to_go_back']); } From 771e7ad88fbb92ebd03e40e5c2caf596bcaa32fc Mon Sep 17 00:00:00 2001 From: xiaomlove Date: Sun, 11 Sep 2022 01:15:31 +0800 Subject: [PATCH 09/12] bonus redemption limit click frequency --- app/Console/Commands/Test.php | 3 ++- include/constants.php | 2 +- lang/chs/lang_mybonus.php | 1 + lang/cht/lang_mybonus.php | 1 + lang/en/lang_mybonus.php | 1 + nexus/Database/NexusLock.php | 50 +++++++++++++++++++++++++++++++++++ public/details.php | 11 ++++++-- public/mybonus.php | 18 ++++++++++--- 8 files changed, 79 insertions(+), 8 deletions(-) create mode 100644 nexus/Database/NexusLock.php diff --git a/app/Console/Commands/Test.php b/app/Console/Commands/Test.php index 7d629dd5..dee5383c 100644 --- a/app/Console/Commands/Test.php +++ b/app/Console/Commands/Test.php @@ -38,6 +38,7 @@ use Illuminate\Support\Facades\Hash; use Illuminate\Support\Facades\Redis; use Illuminate\Support\Facades\Storage; use Illuminate\Support\Str; +use Imdb\Cache; use League\Flysystem\StorageAttributes; use Nexus\Database\NexusDB; use Nexus\Imdb\Imdb; @@ -86,7 +87,7 @@ class Test extends Command */ public function handle() { - + $r = \Illuminate\Support\Facades\Cache::lock(); } diff --git a/include/constants.php b/include/constants.php index f6b978e2..d26c4885 100644 --- a/include/constants.php +++ b/include/constants.php @@ -1,6 +1,6 @@ '基本奖励', 'reward_type_harem_addition' => '后宫加成', 'bonus_base' => '基础魔力', + 'lock_text' => '系统限制 %s 秒内只能点击交换按钮一次!', ); ?> diff --git a/lang/cht/lang_mybonus.php b/lang/cht/lang_mybonus.php index c120eb79..d7376a0b 100644 --- a/lang/cht/lang_mybonus.php +++ b/lang/cht/lang_mybonus.php @@ -138,6 +138,7 @@ $lang_mybonus = array 'reward_type_basic' => '基本獎勵', 'reward_type_harem_addition' => '後宮加成', 'bonus_base' => '基礎魔力', + 'lock_text' => '系統限製 %s 秒內只能點擊交換按鈕一次!', ); ?> diff --git a/lang/en/lang_mybonus.php b/lang/en/lang_mybonus.php index ce663fce..8820f00f 100644 --- a/lang/en/lang_mybonus.php +++ b/lang/en/lang_mybonus.php @@ -138,6 +138,7 @@ where
  • A is an intermediate variable
  • Ti is the i< 'reward_type_basic' => 'Basic reward', 'reward_type_harem_addition' => 'Harem addition', 'bonus_base' => 'Base bonus', + 'lock_text' => 'The system limits you to one click on the exchange button within %s seconds!', ); ?> diff --git a/nexus/Database/NexusLock.php b/nexus/Database/NexusLock.php new file mode 100644 index 00000000..4f88b717 --- /dev/null +++ b/nexus/Database/NexusLock.php @@ -0,0 +1,50 @@ +seconds > 0) { + return $this->redis->set($this->name, $this->owner, ['nx', 'ex' => $this->seconds]) == true; + } else { + return $this->redis->setnx($this->name, $this->owner) == true; + } + } + + /** + * Release the lock. + * + * @return bool + */ + public function release() + { + return (bool) $this->redis->eval(LuaScripts::releaseLock(), [$this->name, $this->owner], 1); + } + +} diff --git a/public/details.php b/public/details.php index 064c0d85..74831a1d 100644 --- a/public/details.php +++ b/public/details.php @@ -429,8 +429,15 @@ JS; function hex_esc($matches) { return sprintf("%02x", ord($matches[0])); } - if ($enablenfo_main=='yes') - tr($lang_details['row_torrent_info'], "" . (!empty($files_info) ? "" : "") . "". (user_can('torrentstructure') ? "" : "") . "
    " . $files_info . "".$lang_details['row_info_hash'].": ".preg_replace_callback('/./s', "hex_esc", hash_pad($row["info_hash"]))."" . $lang_details['text_torrent_structure'] . "".$lang_details['text_torrent_info_note']."
    ",1); + $infoTds = []; + if (!empty($files_info)) { + $infoTds[] = "" . $files_info . ""; + } + $infoTds[] = "".$lang_details['row_info_hash'].": ".preg_replace_callback('/./s', "hex_esc", hash_pad($row["info_hash"])).""; + if (user_can('torrentstructure')) { + $infoTds[] = "" . $lang_details['text_torrent_structure'] . "".$lang_details['text_torrent_info_note'].""; + } + tr($lang_details['row_torrent_info'], "" . implode("", $infoTds) . "
    ",1); tr($lang_details['row_hot_meter'], "
    " . $lang_details['text_views']."". $row["views"] . "" . $lang_details['text_hits']. "" . $row["hits"] . "" .$lang_details['text_snatched'] . "" . $row["times_completed"]. $lang_details['text_view_snatches'] . "" . $lang_details['row_last_seeder']. "" . gettime($row["last_action"]) . "
    ",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); diff --git a/public/mybonus.php b/public/mybonus.php index 716310eb..5be81c7e 100644 --- a/public/mybonus.php +++ b/public/mybonus.php @@ -235,7 +235,8 @@ function bonusarray($option = 0){ } $allBonus = bonusarray(); - +$lockSeconds = 10; +$lockText = sprintf($lang_mybonus['lock_text'], $lockSeconds); if ($bonus_tweak == "disable" || $bonus_tweak == "disablesave") stderr($lang_mybonus['std_sorry'],$lang_mybonus['std_karma_system_disabled'].($bonus_tweak == "disablesave" ? "".$lang_mybonus['std_points_active']."" : ""),false); @@ -265,6 +266,8 @@ if (isset($do)) { $msg = $lang_mybonus['text_success_buy_medal']; elseif ($do == "attendance_card") $msg = $lang_mybonus['text_success_buy_attendance_card']; + elseif ($do == 'duplicated') + $msg = $lockText; else $msg = ''; } @@ -275,10 +278,10 @@ if (!$action) { print("\n"); print("\n"); if ($msg) - print(""); + print(""); ?> +

    ()". @@ -452,6 +455,7 @@ if ($factor > 0) { number_format($addition * $factor, 3) ); } + $summaryTable .= '
    ".$SITENAME.$lang_mybonus['text_karma_system']."
    ". $msg ."
    ". $msg ."
    -
    ".$lang_mybonus['col_option']."
    '; print '
    '.$summaryTable.'
    '; @@ -512,6 +516,12 @@ if ($action == "exchange") { if($CURUSER['seedbonus'] >= $points) { $bonusRep = new \App\Repositories\BonusRepository(); + $lockName = "user:$userid:exchange:bonus"; + $lock = new \Nexus\Database\NexusLock($lockName, $lockSeconds); + if (!$lock->get()) { + do_log("[LOCKED], $lockName, $lockText"); + nexus_redirect('mybonus.php?do=duplicated'); + } //=== trade for upload if($art == "traffic") { if ($CURUSER['uploaded'] > $dlamountlimit_bonus * 1073741824)//uploaded amount reach limit @@ -550,7 +560,7 @@ if ($action == "exchange") { // $bonuscomment = date("Y-m-d") . " - " .$points. " Points for invites.\n " .htmlspecialchars($bonuscomment); // sql_query("UPDATE users SET invites = ".sqlesc($inv).", 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_INVITE, $points. " Points for invites.", ['invites' => $inv, ]); - nexus_redirect("" . get_protocol_prefix() . "$BASEURL/mybonus.php?do=invite"); + nexus_redirect("" . get_protocol_prefix() . "$BASEURL/mybonus.php?do=invite"); } //=== trade for special title /**** the $words array are words that you DO NOT want the user to have... use to filter "bad words" & user class... From d5e81ac0096b8d24f54d477b0b3f8d2ca72d88f8 Mon Sep 17 00:00:00 2001 From: xiaomlove Date: Mon, 12 Sep 2022 20:00:07 +0800 Subject: [PATCH 10/12] add is_seed_box to peers --- app/Models/Peer.php | 2 +- app/Repositories/SeedBoxRepository.php | 10 +++- app/Repositories/TrackerRepository.php | 6 +++ ..._181952_add_is_seed_box_to_peers_table.php | 32 +++++++++++++ include/constants.php | 4 +- include/functions.php | 11 ++--- public/announce.php | 11 +++-- public/viewpeerlist.php | 48 ++++++++++++++----- 8 files changed, 99 insertions(+), 25 deletions(-) create mode 100644 database/migrations/2022_09_12_181952_add_is_seed_box_to_peers_table.php diff --git a/app/Models/Peer.php b/app/Models/Peer.php index aa585799..6243e55c 100644 --- a/app/Models/Peer.php +++ b/app/Models/Peer.php @@ -11,7 +11,7 @@ class Peer extends NexusModel protected $fillable = [ 'torrent', 'peer_id', 'ip', 'port', 'uploaded', 'downloaded', 'to_go', 'seeder', 'started', 'last_action', 'prev_action', 'connectable', 'userid', 'agent', 'finishedat', 'downloadoffset', 'uploadedoffset', 'passkey', - 'ipv4', 'ipv6', + 'ipv4', 'ipv6', 'is_seed_box' ]; const CONNECTABLE_YES = 'yes'; diff --git a/app/Repositories/SeedBoxRepository.php b/app/Repositories/SeedBoxRepository.php index a29a8d7f..13666832 100644 --- a/app/Repositories/SeedBoxRepository.php +++ b/app/Repositories/SeedBoxRepository.php @@ -138,12 +138,20 @@ class SeedBoxRepository extends BaseRepository } foreach (Arr::wrap($ipArr) as $ip) { if ((isIPV4($ip) || isIPV6($ip)) && $enableSeedBox && isIPSeedBox($ip, $uid)) { - return ''; + return $this->getSeedBoxIcon(); } } return ''; } + public function getSeedBoxIcon($isSeedBox = true): string + { + if (!$isSeedBox) { + return ''; + } + return ''; + } + private function clearCache() { return true; diff --git a/app/Repositories/TrackerRepository.php b/app/Repositories/TrackerRepository.php index 73edf972..251151be 100644 --- a/app/Repositories/TrackerRepository.php +++ b/app/Repositories/TrackerRepository.php @@ -841,11 +841,16 @@ class TrackerRepository extends BaseRepository 'agent' => $queries['user_agent'], 'connectable' => $this->getConnectable($queries['ip'], $queries['port'], $queries['user_agent']) ]; + $isSeedBox = false; if (!empty($queries['ipv4'])) { $update['ipv4'] = $queries['ipv4']; + $isSeedBox = isIPSeedBox($queries['ipv4'], $peer->userid); } if (!empty($queries['ipv6'])) { $update['ipv6'] = $queries['ipv6']; + if (!$isSeedBox) { + $isSeedBox = isIPSeedBox($queries['ipv6'], $peer->userid); + } } if ($peer->exists) { @@ -865,6 +870,7 @@ class TrackerRepository extends BaseRepository $update['last_action'] = $nowStr; $update['uploaded'] = $queries['uploaded']; $update['downloaded'] = $queries['downloaded']; + $update['is_seed_box'] = intval($isSeedBox); $logData = json_encode(Arr::except($update, ['peer_id'])); if ($peer->exists) { diff --git a/database/migrations/2022_09_12_181952_add_is_seed_box_to_peers_table.php b/database/migrations/2022_09_12_181952_add_is_seed_box_to_peers_table.php new file mode 100644 index 00000000..fa574c69 --- /dev/null +++ b/database/migrations/2022_09_12_181952_add_is_seed_box_to_peers_table.php @@ -0,0 +1,32 @@ +tinyInteger('is_seed_box')->default(0); + }); + } + + /** + * Reverse the migrations. + * + * @return void + */ + public function down() + { + Schema::table('peers', function (Blueprint $table) { + $table->dropColumn('is_seed_box'); + }); + } +}; diff --git a/include/constants.php b/include/constants.php index d26c4885..17b6d75f 100644 --- a/include/constants.php +++ b/include/constants.php @@ -1,6 +1,6 @@ whereIn('torrent', $torrentIdArr) - ->whereIn('userid', array_unique($ownerIdArr)) ->where('seeder', 'yes') - ->get(['torrent', 'ipv4', 'ipv6']) + ->where('is_seed_box', '1') + ->get(['torrent', 'is_seed_box']) ->keyBy('torrent'); } @@ -3559,9 +3559,8 @@ foreach ($rows as $row) $banned_torrent = ($row["banned"] == 'yes' ? " (".$lang_functions['text_banned'].")" : ""); $sp_torrent_sub = get_torrent_promotion_append_sub($row['sp_state'],"",true,$row['added'], $row['promotion_time_type'], $row['promotion_until'], $row['__ignore_global_sp_state'] ?? false); $approvalStatusIcon = $torrentRep->renderApprovalStatus($row['approval_status']); - if ($showSeedBoxIcon && $ownerPeerInfo->has($row['id'])) { - $ownerPeer = $ownerPeerInfo->get($row['id']); - $seedBoxIcon = $seedBoxRep->renderIcon([$ownerPeer->ipv4, $ownerPeer->ipv6], $row['owner']); + if ($showSeedBoxIcon && $seedBoxPeerInfo->has($row['id'])) { + $seedBoxIcon = $seedBoxRep->getSeedBoxIcon(); } else { $seedBoxIcon = ''; } diff --git a/public/announce.php b/public/announce.php index 6430c311..37182ad4 100644 --- a/public/announce.php +++ b/public/announce.php @@ -332,7 +332,12 @@ if(isset($self) && empty($_GET['event']) && $self['prevts'] > (TIMENOW - $announ $isSeedBoxRuleEnabled = get_setting('seed_box.enabled') == 'yes'; $isIPSeedBox = false; if ($isSeedBoxRuleEnabled && !($az['class'] >= \App\Models\User::CLASS_VIP || $isDonor)) { - $isIPSeedBox = isIPSeedBox($ip, $userid); + if (!empty($ipv4)) { + $isIPSeedBox = isIPSeedBox($ipv4, $userid); + } + if (!$isIPSeedBox && !empty($ipv6)) { + $isIPSeedBox = isIPSeedBox($ipv6, $userid); + } } $log .= ", [SEED_BOX], isSeedBoxRuleEnabled: $isSeedBoxRuleEnabled, isIPSeedBox: $isIPSeedBox"; @@ -537,7 +542,7 @@ elseif(isset($self)) $updateset[] = "times_completed = times_completed + 1"; } - sql_query("UPDATE peers SET ip = ".sqlesc($ip).", port = $port, uploaded = $uploaded, downloaded = $downloaded, to_go = $left, prev_action = last_action, last_action = $dt, seeder = '$seeder', agent = ".sqlesc($agent)." $finished $peerIPV46 WHERE $selfwhere") or err("PL Err 1"); + sql_query("UPDATE peers SET ip = ".sqlesc($ip).", port = $port, uploaded = $uploaded, downloaded = $downloaded, to_go = $left, prev_action = last_action, last_action = $dt, seeder = '$seeder', agent = ".sqlesc($agent).", is_seed_box = ". intval($isIPSeedBox) . " $finished $peerIPV46 WHERE $selfwhere") or err("PL Err 1"); if (mysql_affected_rows()) { @@ -578,7 +583,7 @@ else } 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) 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).")"; + $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"); try { diff --git a/public/viewpeerlist.php b/public/viewpeerlist.php index 585a438f..8337ec20 100644 --- a/public/viewpeerlist.php +++ b/public/viewpeerlist.php @@ -11,11 +11,11 @@ header("Content-Type: text/xml; charset=utf-8"); $id = intval($_GET['id'] ?? 0); $seedBoxRep = new \App\Repositories\SeedBoxRepository(); - -function get_location_column($e, $isStrongPrivacy, $canView): string +function get_location_column($e, $isStrongPrivacy, $canView): array { global $enablelocation_tweak, $seedBoxRep, $lang_functions, $lang_viewpeerlist; $address = $ips = []; + $isSeedBox = false; //First, build the location if ($enablelocation_tweak == 'yes') { if (!empty($e['ipv4'])) { @@ -39,10 +39,12 @@ function get_location_column($e, $isStrongPrivacy, $canView): string $location = '
    '.$addressStr.'
    '; } else { if (!empty($e['ipv4'])) { - $ips[] = $e['ipv4'] . $seedBoxRep->renderIcon($e['ipv4'], $e['userid']); + $seedBoxIcon = $seedBoxRep->renderIcon($e['ipv4'], $e['userid']); + $ips[] = $e['ipv4'] . $seedBoxIcon; } if (!empty($e['ipv6'])) { - $ips[] = $e['ipv6'] . $seedBoxRep->renderIcon($e['ipv6'], $e['userid']); + $seedBoxIcon = $seedBoxRep->renderIcon($e['ipv6'], $e['userid']); + $ips[] = $e['ipv6'] . $seedBoxIcon; } $location = '
    '.implode('
    ', $ips).'
    '; } @@ -55,8 +57,13 @@ function get_location_column($e, $isStrongPrivacy, $canView): string } else { $result = $location; } - - return "
    " . $result . "
    \n"; + if (isset($seedBoxIcon) && !empty($seedBoxIcon)) { + $isSeedBox = true; + } + return [ + "td" => "
    " . $result . "
    ", + "is_seed_box" => $isSeedBox, + ]; } function get_username_seed_box_icon($e): string @@ -74,7 +81,7 @@ function get_username_seed_box_icon($e): string if(isset($CURUSER)) { -function dltable($name, $arr, $torrent) +function dltable($name, $arr, $torrent, &$isSeedBoxCaseWhens) { global $lang_viewpeerlist,$viewanonymous_class,$userprofile_class,$enablelocation_tweak; global $CURUSER; @@ -101,7 +108,8 @@ function dltable($name, $arr, $torrent) $now = time(); $num = 0; $privacyData = \App\Models\User::query()->whereIn('id', array_column($arr, 'userid'))->get(['id', 'privacy'])->keyBy('id'); - foreach ($arr as $e) { + + foreach ($arr as $e) { $privacy = $privacyData->get($e['userid'])->privacy ?? ''; ++$num; @@ -112,10 +120,14 @@ function dltable($name, $arr, $torrent) $isStrongPrivacy = $privacy == "strong" || ($torrent['anonymous'] == 'yes' && $e['userid'] == $torrent['owner']); $canView = user_can('viewanonymous') || $e['userid'] == $CURUSER['id']; if ($showLocationColumn) { - $columnLocation = get_location_column($e, $isStrongPrivacy, $canView); + $columnLocationResult = get_location_column($e, $isStrongPrivacy, $canView); + $columnLocation = $columnLocationResult['td']; + $isSeedBox = $columnLocationResult['is_seed_box']; } else { $usernameSeedBoxIcon = get_username_seed_box_icon($e); + $isSeedBox = !empty($usernameSeedBoxIcon); } + $isSeedBoxCaseWhens[$e['id']] = sprintf("when %s then %s", $e['id'], intval($isSeedBox)); if ($isStrongPrivacy) { $columnUsername = "".$lang_viewpeerlist['text_anonymous']."".$usernameSeedBoxIcon; if ($canView) { @@ -159,7 +171,7 @@ function dltable($name, $arr, $torrent) $downloaders = array(); $seeders = array(); $torrent = \App\Models\Torrent::query()->findOrFail($id, ['id', 'seeders', 'leechers']); - $subres = sql_query("SELECT 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(); + $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; @@ -176,6 +188,7 @@ function dltable($name, $arr, $torrent) $torrent->update($update); do_log("[UPDATE_TORRENT_SEEDERS_LEECHERS], torrent: $id, original: " . $torrent->toJson() . ", update: " . json_encode($update)); } + function leech_sort($a,$b) { $x = $a["to_go"]; $y = $b["to_go"]; @@ -199,7 +212,18 @@ function dltable($name, $arr, $torrent) usort($seeders, "seed_sort"); usort($downloaders, "leech_sort"); - print(dltable($lang_viewpeerlist['text_seeders'], $seeders, $row)); - print(dltable($lang_viewpeerlist['text_leechers'], $downloaders, $row)); + $isSeedBoxCaseWhens = []; + $seederTable = dltable($lang_viewpeerlist['text_seeders'], $seeders, $row, $isSeedBoxCaseWhens); + $leecherTable = dltable($lang_viewpeerlist['text_leechers'], $downloaders, $row, $isSeedBoxCaseWhens); + //update peer is_seed_box + if (!empty($isSeedBoxCaseWhens)) { + $sql = sprintf( + "update peers set is_seed_box = case id %s end where id in (%s)", + implode(' ', array_values($isSeedBoxCaseWhens)), implode(',', array_keys($isSeedBoxCaseWhens)) + ); + do_log("[IS_SEED_BOX], $sql"); + sql_query($sql); + } + print $seederTable . $leecherTable; } ?> From e5cb98cf3583fc1c67999e2c5d39b9e86a98749f Mon Sep 17 00:00:00 2001 From: xiaomlove Date: Mon, 12 Sep 2022 22:02:57 +0800 Subject: [PATCH 11/12] attach torrent tags support delete olds --- .../Resources/Torrent/TorrentResource.php | 7 ++++- app/Repositories/TorrentRepository.php | 26 +++++++++---------- app/Repositories/UserRepository.php | 5 +++- public/recover.php | 7 ++--- public/viewpeerlist.php | 2 +- resources/lang/en/admin.php | 1 + resources/lang/zh_CN/admin.php | 1 + resources/lang/zh_TW/admin.php | 1 + 8 files changed, 29 insertions(+), 21 deletions(-) diff --git a/app/Filament/Resources/Torrent/TorrentResource.php b/app/Filament/Resources/Torrent/TorrentResource.php index 6163de01..bc046f67 100644 --- a/app/Filament/Resources/Torrent/TorrentResource.php +++ b/app/Filament/Resources/Torrent/TorrentResource.php @@ -163,6 +163,7 @@ class TorrentResource extends Resource $torrentRep = new TorrentRepository(); $torrentRep->setPosState($idArr, $data['pos_state']); } catch (\Exception $exception) { + do_log($exception->getMessage() . $exception->getTraceAsString(), 'error'); Filament::notify('danger', class_basename($exception)); } }) @@ -180,6 +181,7 @@ class TorrentResource extends Resource $torrentRep = new TorrentRepository(); $torrentRep->syncTags($idArr); } catch (\Exception $exception) { + do_log($exception->getMessage() . $exception->getTraceAsString(), 'error'); Filament::notify('danger', class_basename($exception)); } }) @@ -188,11 +190,13 @@ class TorrentResource extends Resource $actions[] = Tables\Actions\BulkAction::make('attach_tag') ->label(__('admin.resources.torrent.bulk_action_attach_tag')) ->form([ + Forms\Components\Checkbox::make('remove')->label(__('admin.resources.torrent.bulk_action_attach_tag_remove_old')), Forms\Components\CheckboxList::make('tags') ->label(__('label.tag.label')) ->columns(4) ->options(TagRepository::createBasicQuery()->pluck('name', 'id')->toArray()) ->required(), + ]) ->icon('heroicon-o-tag') ->action(function (Collection $records, array $data) { @@ -202,8 +206,9 @@ class TorrentResource extends Resource $idArr = $records->pluck('id')->toArray(); try { $torrentRep = new TorrentRepository(); - $torrentRep->syncTags($idArr, $data['tags']); + $torrentRep->syncTags($idArr, $data['tags'], $data['remove'] ?? false); } catch (\Exception $exception) { + do_log($exception->getMessage() . $exception->getTraceAsString(), 'error'); Filament::notify('danger', class_basename($exception)); } }) diff --git a/app/Repositories/TorrentRepository.php b/app/Repositories/TorrentRepository.php index aab17db3..0f10aa2b 100644 --- a/app/Repositories/TorrentRepository.php +++ b/app/Repositories/TorrentRepository.php @@ -30,6 +30,7 @@ use Hashids\Hashids; use Illuminate\Database\Eloquent\Builder; use Illuminate\Support\Arr; use Illuminate\Support\Facades\Auth; +use Illuminate\Support\Facades\DB; use Illuminate\Support\Str; use Nexus\Database\NexusDB; @@ -572,28 +573,27 @@ class TorrentRepository extends BaseRepository return false; } - public function syncTags($id, array $tagIdArr = []) + public function syncTags($id, array $tagIdArr = [], $remove = true) { user_can('torrentmanage', true); $idArr = Arr::wrap($id); - return NexusDB::transaction(function () use ($idArr, $tagIdArr) { - $insert = []; + return NexusDB::transaction(function () use ($idArr, $tagIdArr, $remove) { + $sql = "insert into torrent_tags (torrent_id, tag_id, created_at, updated_at) values "; $time = now()->toDateTimeString(); + $values = []; foreach ($idArr as $torrentId) { foreach ($tagIdArr as $tagId) { - $insert[] = [ - 'torrent_id' => $torrentId, - 'tag_id' => $tagId, - 'created_at' => $time, - 'updated_at' => $time, - ]; + $values[] = sprintf("(%s, %s, '%s', '%s')", $torrentId, $tagId, $time, $time); } } - TorrentTag::query()->whereIn('torrent_id', $idArr)->delete(); - if (!empty($insert)) { - TorrentTag::query()->insert($insert); + $sql .= implode(', ', $values) . " on duplicate key update updated_at = values(updated_at)"; + if ($remove) { + TorrentTag::query()->whereIn('torrent_id', $idArr)->delete(); } - return count($insert); + if (!empty($values)) { + DB::insert($sql); + } + return count($values); }); } diff --git a/app/Repositories/UserRepository.php b/app/Repositories/UserRepository.php index 6f5aba4f..f3f543a5 100644 --- a/app/Repositories/UserRepository.php +++ b/app/Repositories/UserRepository.php @@ -138,7 +138,10 @@ class UserRepository extends BaseRepository throw new \InvalidArgumentException("password confirmation != password"); } $user = User::query()->findOrFail($id, ['id', 'username', 'class']); - $this->checkPermission(Auth::user(), $user); + $operator = Auth::user(); + if ($operator) { + $this->checkPermission($operator, $user); + } $secret = mksecret(); $passhash = md5($secret . $password . $secret); $update = [ diff --git a/public/recover.php b/public/recover.php index 3ac4d5f0..5e9ed59a 100644 --- a/public/recover.php +++ b/public/recover.php @@ -50,7 +50,7 @@ if ($_SERVER["REQUEST_METHOD"] == "POST") $title = $SITENAME.$lang_recover['mail_title']; $body = << {$lang_recover['mail_this_link']}

    + {$lang_recover['mail_this_link']}
    $baseUrl/recover.php?id={$arr["id"]}&secret=$hash {$lang_recover['mail_four']} EOD; @@ -96,11 +96,8 @@ elseif($_SERVER["REQUEST_METHOD"] == "GET" && $take_recover && isset($_GET["id"] {$lang_recover['mail_two_one']}{$arr["username"]} {$lang_recover['mail_two_two']}$newpassword {$lang_recover['mail_two_three']} -{$lang_recover['mail_here']} -{$lang_recover['mail_three_1']} -{$lang_confirm_resend['mail_google_answer']} +{$lang_recover['mail_here']} {$lang_recover['mail_two_four']} - EOD; sent_mail($email,$SITENAME,$SITEEMAIL,$title,$body,"details",true,false,''); diff --git a/public/viewpeerlist.php b/public/viewpeerlist.php index 8337ec20..813902d2 100644 --- a/public/viewpeerlist.php +++ b/public/viewpeerlist.php @@ -216,7 +216,7 @@ function dltable($name, $arr, $torrent, &$isSeedBoxCaseWhens) $seederTable = dltable($lang_viewpeerlist['text_seeders'], $seeders, $row, $isSeedBoxCaseWhens); $leecherTable = dltable($lang_viewpeerlist['text_leechers'], $downloaders, $row, $isSeedBoxCaseWhens); //update peer is_seed_box - if (!empty($isSeedBoxCaseWhens)) { + if (!empty($isSeedBoxCaseWhens) && get_setting('seed_box.enabled') == 'yes') { $sql = sprintf( "update peers set is_seed_box = case id %s end where id in (%s)", implode(' ', array_values($isSeedBoxCaseWhens)), implode(',', array_keys($isSeedBoxCaseWhens)) diff --git a/resources/lang/en/admin.php b/resources/lang/en/admin.php index 4dc01823..f27f10d4 100644 --- a/resources/lang/en/admin.php +++ b/resources/lang/en/admin.php @@ -87,6 +87,7 @@ return [ 'bulk_action_remove_tag' => 'Remove tag', 'bulk_action_attach_tag' => 'Attach tag', 'action_approval' => 'Approval', + 'bulk_action_attach_tag_remove_old' => 'Also delete old tags', ], 'seed_box_record' => [ 'toggle_status' => 'Change status', diff --git a/resources/lang/zh_CN/admin.php b/resources/lang/zh_CN/admin.php index 8c3e900f..fc54330f 100644 --- a/resources/lang/zh_CN/admin.php +++ b/resources/lang/zh_CN/admin.php @@ -87,6 +87,7 @@ return [ 'bulk_action_remove_tag' => '清除标签', 'bulk_action_attach_tag' => '设置标签', 'action_approval' => '审核', + 'bulk_action_attach_tag_remove_old' => '同时删除旧标签', ], 'seed_box_record' => [ 'toggle_status' => '更改状态', diff --git a/resources/lang/zh_TW/admin.php b/resources/lang/zh_TW/admin.php index 5ad4a52c..16fdd38f 100644 --- a/resources/lang/zh_TW/admin.php +++ b/resources/lang/zh_TW/admin.php @@ -87,6 +87,7 @@ return [ 'bulk_action_remove_tag' => '清除標簽', 'bulk_action_attach_tag' => '設置標簽', 'action_approval' => '審核', + 'bulk_action_attach_tag_remove_old' => '同時刪除舊標簽', ], 'seed_box_record' => [ 'toggle_status' => '更改狀態', From 480ed17b038600853c637486c45d8cb7cf10dc9b Mon Sep 17 00:00:00 2001 From: xiaomlove Date: Mon, 12 Sep 2022 22:41:45 +0800 Subject: [PATCH 12/12] add bulk confirm --- app/Filament/Resources/User/UserResource.php | 24 +++++++++++++++++--- app/Repositories/UserRepository.php | 14 ++++++++++++ resources/lang/en/admin.php | 1 + resources/lang/zh_CN/admin.php | 1 + resources/lang/zh_TW/admin.php | 1 + 5 files changed, 38 insertions(+), 3 deletions(-) diff --git a/app/Filament/Resources/User/UserResource.php b/app/Filament/Resources/User/UserResource.php index fcb733b1..e2f86cde 100644 --- a/app/Filament/Resources/User/UserResource.php +++ b/app/Filament/Resources/User/UserResource.php @@ -6,6 +6,7 @@ use App\Filament\OptionsTrait; use App\Filament\Resources\User\UserResource\Pages; use App\Filament\Resources\User\UserResource\RelationManagers; use App\Models\User; +use App\Repositories\UserRepository; use Filament\Forms; use Filament\Forms\Components\Grid; use Filament\Resources\Form; @@ -15,6 +16,8 @@ use Filament\Tables; use Illuminate\Database\Eloquent\Builder; use Illuminate\Database\Eloquent\SoftDeletingScope; +use Illuminate\Support\Collection; +use Illuminate\Support\Facades\Auth; use Illuminate\Support\HtmlString; class UserResource extends Resource @@ -85,9 +88,7 @@ class UserResource extends Resource ->actions([ Tables\Actions\ViewAction::make(), ]) - ->bulkActions([ -// Tables\Actions\DeleteBulkAction::make(), - ]); + ->bulkActions(self::getBulkActions()); } public static function getRelations(): array @@ -108,4 +109,21 @@ class UserResource extends Resource ]; } + public static function getBulkActions(): array + { + $actions = []; + if (Auth::user()->class >= User::CLASS_SYSOP) { + $actions[] = Tables\Actions\BulkAction::make('confirm') + ->label(__('admin.resources.user.actions.confirm_bulk')) + ->requiresConfirmation() + ->deselectRecordsAfterCompletion() + ->action(function (Collection $records) { + $rep = new UserRepository(); + $rep->confirmUser($records->pluck('id')->toArray()); + }); + } + + return $actions; + } + } diff --git a/app/Repositories/UserRepository.php b/app/Repositories/UserRepository.php index f3f543a5..8e8a40d9 100644 --- a/app/Repositories/UserRepository.php +++ b/app/Repositories/UserRepository.php @@ -483,4 +483,18 @@ class UserRepository extends BaseRepository return $result; } + public function confirmUser($id): bool + { + $update = [ + 'status' => User::STATUS_CONFIRMED, + 'editsecret' => '', + ]; + User::query() + ->whereIn('id', Arr::wrap($id)) + ->where('status', User::STATUS_PENDING) + ->update($update); + + return true; + } + } diff --git a/resources/lang/en/admin.php b/resources/lang/en/admin.php index f27f10d4..82480c32 100644 --- a/resources/lang/en/admin.php +++ b/resources/lang/en/admin.php @@ -67,6 +67,7 @@ return [ 'grant_prop_form_prop' => 'Select prop', 'grant_prop_form_duration' => 'Duration', 'grant_prop_form_duration_help' => 'Unit: days. If left blank, the user has it permanently. Note: There is no time limit for Name Change Card, ignore this value.' , + 'confirm_bulk' => 'Bulk confirm', ] ], 'exam_user' => [ diff --git a/resources/lang/zh_CN/admin.php b/resources/lang/zh_CN/admin.php index fc54330f..ed68f5d7 100644 --- a/resources/lang/zh_CN/admin.php +++ b/resources/lang/zh_CN/admin.php @@ -67,6 +67,7 @@ return [ 'grant_prop_form_prop' => '选择道具', 'grant_prop_form_duration' => '有效时长', 'grant_prop_form_duration_help' => '单位:天。如果留空,用户永久拥有。注:改名卡没有时间限制,忽略该值。', + 'confirm_bulk' => '批量确认', ] ], 'exam_user' => [ diff --git a/resources/lang/zh_TW/admin.php b/resources/lang/zh_TW/admin.php index 16fdd38f..c46b91fd 100644 --- a/resources/lang/zh_TW/admin.php +++ b/resources/lang/zh_TW/admin.php @@ -67,6 +67,7 @@ return [ 'grant_prop_form_prop' => '選擇道具', 'grant_prop_form_duration' => '有效時長', 'grant_prop_form_duration_help' => '單位:天。如果留空,用戶永久擁有。註:改名卡沒有時間限製,忽略該值。', + 'confirm_bulk' => '批量確認', ] ], 'exam_user' => [