diff --git a/app/Models/User.php b/app/Models/User.php index aaf4ee4f..a50b0d47 100644 --- a/app/Models/User.php +++ b/app/Models/User.php @@ -102,6 +102,7 @@ class User extends Authenticatable implements FilamentUser, HasName 'invites' => '邀请', ]; + public static array $notificationOptions = ['topic_reply', 'hr_reached']; public function getClassTextAttribute(): string { @@ -555,6 +556,14 @@ class User extends Authenticatable implements FilamentUser, HasName return false; } + public function acceptNotification($name): bool + { + if (!isset($this->original['notifs'])) { + throw new \RuntimeException("Not fetch field: notifs"); + } + return str_contains($this->notifs, "[{$name}]"); + } + diff --git a/app/Repositories/HitAndRunRepository.php b/app/Repositories/HitAndRunRepository.php index 2a325b52..66c5633b 100644 --- a/app/Repositories/HitAndRunRepository.php +++ b/app/Repositories/HitAndRunRepository.php @@ -135,7 +135,7 @@ class HitAndRunRepository extends BaseRepository ->with([ 'torrent' => function ($query) {$query->select(['id', 'size', 'name', 'category']);}, 'snatch', - 'user' => function ($query) {$query->select(['id', 'username', 'lang', 'class', 'donoruntil', 'enabled']);}, + 'user' => function ($query) {$query->select(['id', 'username', 'lang', 'class', 'donoruntil', 'enabled', 'notifs']);}, 'user.language', ]); if (!is_null($uid)) { @@ -297,8 +297,12 @@ class HitAndRunRepository extends BaseRepository do_log($hitAndRun->toJson() . ", [$logPrefix], affectedRows != 1, skip!", 'notice'); return false; } - $message = $this->geReachedMessage($hitAndRun); - Message::query()->insert($message); + if ($hitAndRun->user->acceptNotification('hr_reached')) { + $message = $this->geReachedMessage($hitAndRun); + Message::query()->insert($message); + } else { + do_log($hitAndRun->toJson() . ", [$logPrefix], user do not accept hr_reached notification", 'notice'); + } return true; } diff --git a/include/constants.php b/include/constants.php index 7fab68f4..ab6aeb1a 100644 --- a/include/constants.php +++ b/include/constants.php @@ -1,6 +1,6 @@ 'Passkey 登录链接', 'row_seed_box' => 'SeedBox', 'add_seed_box_btn' => '登记', + 'checkbox_pm_on_topic_reply' => '论坛帖子有新回复时通知我', + 'checkbox_pm_on_hr_reached' => 'H&R 达标时通知我', ); ?> diff --git a/lang/cht/lang_usercp.php b/lang/cht/lang_usercp.php index 13d65f06..d6674cc8 100644 --- a/lang/cht/lang_usercp.php +++ b/lang/cht/lang_usercp.php @@ -252,6 +252,8 @@ $lang_usercp = array 'row_passkey_login_url' => 'Passkey 登錄鏈接', 'row_seed_box' => 'SeedBox', 'add_seed_box_btn' => '登記', + 'checkbox_pm_on_topic_reply' => '論壇帖子有新回復時通知我', + 'checkbox_pm_on_hr_reached' => 'H&R 達標時通知我', ); ?> diff --git a/lang/en/lang_usercp.php b/lang/en/lang_usercp.php index bd355ea5..c2ee0916 100644 --- a/lang/en/lang_usercp.php +++ b/lang/en/lang_usercp.php @@ -254,6 +254,8 @@ $lang_usercp = array 'row_passkey_login_url' => 'Passkey login URL', 'row_seed_box' => 'SeedBox', 'add_seed_box_btn' => 'Register', + 'checkbox_pm_on_topic_reply' => 'Notify me when there are new replies to forum posts', + 'checkbox_pm_on_hr_reached' => 'Notify me when H&R reaches target', ); ?> diff --git a/nexus/Install/Update.php b/nexus/Install/Update.php index fdc60ad7..36a2542c 100644 --- a/nexus/Install/Update.php +++ b/nexus/Install/Update.php @@ -282,6 +282,14 @@ class Update extends Install } $this->removeMenu(['catmanage.php']); + if (!NexusDB::hasColumn('users', 'seed_points_updated_at')) { + $this->runMigrate('database/migrations/2022_11_23_042152_add_seed_points_seed_times_update_time_to_users_table.php'); + foreach (User::$notificationOptions as $option) { + $sql = "update users set notifs = concat(nofifs, '[$option]') where instr(nofifs, '[$option]') = 0"; + NexusDB::statement($sql); + } + } + } public function runExtraMigrate() diff --git a/public/forums.php b/public/forums.php index 131a01c2..d780d82b 100644 --- a/public/forums.php +++ b/public/forums.php @@ -458,18 +458,21 @@ if ($action == "post") $topicInfo = \App\Models\Topic::query()->findOrFail($topicid); $postUrl = sprintf('[url=forums.php?action=viewtopic&topicid=%s&page=p%s#pid%s]%s[/url]', $topicid, $postid, $postid, $topicInfo->subject); if ($type == 'reply' && $topicInfo->userid != $CURUSER['id']) { + /** @var \App\Models\User $receiver */ $receiver = $topicInfo->user; - $locale = $receiver->locale; - $notify = [ - 'sender' => 0, - 'receiver' => $receiver->id, - 'subject' => nexus_trans('forum.topic.replied_notify_subject', [], $locale), - 'msg' => nexus_trans('forum.topic.replied_notify_body', ['topic_subject' => $postUrl], $locale), - 'added' => now(), - ]; - \App\Models\Message::query()->insert($notify); - \Nexus\Database\NexusDB::cache_del("user_{$topicInfo->userid}_unread_message_count"); - \Nexus\Database\NexusDB::cache_del("user_{$topicInfo->userid}_inbox_count"); + if ($receiver->acceptNotification('topic_reply')) { + $locale = $receiver->locale; + $notify = [ + 'sender' => 0, + 'receiver' => $receiver->id, + 'subject' => nexus_trans('forum.topic.replied_notify_subject', [], $locale), + 'msg' => nexus_trans('forum.topic.replied_notify_body', ['topic_subject' => $postUrl], $locale), + 'added' => now(), + ]; + \App\Models\Message::query()->insert($notify); + \Nexus\Database\NexusDB::cache_del("user_{$topicInfo->userid}_unread_message_count"); + \Nexus\Database\NexusDB::cache_del("user_{$topicInfo->userid}_inbox_count"); + } } $Cache->delete_value('forum_'.$forumid.'_post_'.$today_date.'_count'); diff --git a/public/usercp.php b/public/usercp.php index daa7456b..872140c8 100644 --- a/public/usercp.php +++ b/public/usercp.php @@ -126,6 +126,19 @@ if ($action){ $updateset[] = "info = " . sqlesc($info); + //notifs + if (!empty($_POST['notifs'])) { + preg_match_all('/\[(.*)\]/Ui', $CURUSER['notifs'], $notifsArr); + $notifsArr = array_fill_keys($notifsArr[1], 1); + foreach (\App\Models\User::$notificationOptions as $option) { + if (isset($_POST['notifs'][$option])) { + $notifsArr[$option] = 1; + } else { + unset($notifsArr[$option]); + } + } + $updateset[] = "notifs = " . sqlesc('[' . implode('][', array_keys($notifsArr)) . ']'); + } $query = "UPDATE users SET " . implode(",", $updateset) . " WHERE id = ".sqlesc($CURUSER["id"]); $result = sql_query($query); if (!$result) @@ -169,7 +182,15 @@ if ($action){ tr_small($lang_usercp['row_account_parked'], "".$lang_usercp['checkbox_pack_my_account']."
".$lang_usercp['text_account_pack_note']."" ,1); - tr_small($lang_usercp['row_pms'],$lang_usercp['text_accept_pms']."".$lang_usercp['radio_all_except_blocks']."".$lang_usercp['radio_friends_only']."".$lang_usercp['radio_staff_only']."
".$lang_usercp['checkbox_delete_pms']."
".$lang_usercp['checkbox_save_pms']."
".$lang_usercp['checkbox_pm_on_comments'],1); + $pmY = $lang_usercp['text_accept_pms']."".$lang_usercp['radio_all_except_blocks']."".$lang_usercp['radio_friends_only']."".$lang_usercp['radio_staff_only'] + ."
".$lang_usercp['checkbox_delete_pms'] + ."
".$lang_usercp['checkbox_save_pms'] + ."
".$lang_usercp['checkbox_pm_on_comments'] + ; + foreach (\App\Models\User::$notificationOptions as $option) { + $pmY .= sprintf('
%s', $option, str_contains($CURUSER['notifs'], "[{$option}]") == "yes" ? " checked" : "", $lang_usercp["checkbox_pm_on_{$option}"]); + } + tr_small($lang_usercp['row_pms'], $pmY,1); tr_small($lang_usercp['row_gender'], "".$lang_usercp['radio_not_available']." @@ -212,47 +233,62 @@ tr($lang_usercp['row_school'], "", 1); $updateset = array(); $pmnotif = $_POST["pmnotif"] ?? ''; $emailnotif = $_POST["emailnotif"] ?? ''; - $notifs = ($pmnotif == 'yes' ? "[pm]" : ""); - $notifs .= ($emailnotif == 'yes' ? "[email]" : ""); - function browsecheck($dbtable = "categories", $cbname = "cat"){ + preg_match_all('/\[(.*)\]/Ui', $CURUSER['notifs'], $notifs); + $notifs = array_fill_keys($notifs[1], 1); + foreach ($notifs as $key => $value) { + foreach (['incldead', 'spstate', 'inclbookmarked'] as $item) { + if (str_starts_with($key, $item)) { + unset($notifs[$key]); + } + } + } + + if ($pmnotif == 'yes') { + $notifs['pm'] = 1; + } else { + unset($notifs['pm']); + } + if ($emailnotif == 'yes') { + $notifs['email'] = 1; + } else { + unset($notifs['email']); + } + + function browsecheck($dbtable = "categories", $cbname = "cat", array &$result){ global $_POST; - $return = ""; $r = sql_query("SELECT id FROM ".$dbtable) or sqlerr(); $rows = mysql_num_rows($r); for ($i = 0; $i < $rows; ++$i) { $a = mysql_fetch_assoc($r); - if (isset($_POST[$cbname.$a['id']]) && $_POST[$cbname.$a['id']] == 'yes') - $return .= "[".$cbname.$a['id']."]"; + if (isset($_POST[$cbname.$a['id']]) && $_POST[$cbname.$a['id']] == 'yes') { + $result[$cbname.$a['id']] = 1; + } else { + unset($result[$cbname.$a['id']]); + } } - return $return; } - /*$r = sql_query("SELECT id FROM categories") or sqlerr(); - $rows = mysql_num_rows($r); - for ($i = 0; $i < $rows; ++$i) - { - $a = mysql_fetch_assoc($r); - if ($_POST["cat$a['id']"] == 'yes') - $notifs .= "[cat$a['id']]"; - }*/ - $notifs .= browsecheck("categories", "cat"); - $notifs .= browsecheck("sources", "sou"); - $notifs .= browsecheck("media", "med"); - $notifs .= browsecheck("codecs", "cod"); - $notifs .= browsecheck("standards", "sta"); - $notifs .= browsecheck("processings", "pro"); - $notifs .= browsecheck("teams", "tea"); - $notifs .= browsecheck("audiocodecs", "aud"); + browsecheck("categories", "cat", $notifs); + browsecheck("sources", "sou", $notifs); + browsecheck("media", "med", $notifs); + browsecheck("codecs", "cod", $notifs); + browsecheck("standards", "sta", $notifs); + browsecheck("processings", "pro", $notifs); + browsecheck("teams", "tea", $notifs); + browsecheck("audiocodecs", "aud", $notifs); $incldead = $_POST["incldead"]; - if (isset($incldead) && $incldead != 1) - $notifs .= "[incldead=".$incldead."]"; + if (isset($incldead) && $incldead != 1) { + $notifs["incldead=$incldead"] = 1; + } $spstate = $_POST["spstate"]; - if ($spstate) - $notifs .= "[spstate=".$spstate."]"; + if ($spstate) { + $notifs["spstate=$spstate"] = 1; + } $inclbookmarked = $_POST["inclbookmarked"]; - if ($inclbookmarked) - $notifs .= "[inclbookmarked=".$inclbookmarked."]"; + if ($inclbookmarked) { + $notifs["inclbookmarked=$inclbookmarked"] = 1; + } $stylesheet = $_POST["stylesheet"]; // $caticon = $_POST["caticon"]; $sitelanguage = $_POST["sitelanguage"]; @@ -262,7 +298,7 @@ tr($lang_usercp['row_school'], "", 1); elseif ($fontsize == 'small') $updateset[] = "fontsize = 'small'"; else $updateset[] = "fontsize = 'medium'"; - $updateset[] = "notifs = " . sqlesc($notifs); + $updateset[] = "notifs = " . sqlesc('[' . implode('][', array_keys($notifs)) . ']'); if (is_valid_id($stylesheet)) $updateset[] = "stylesheet = " . sqlesc($stylesheet); @@ -367,6 +403,23 @@ $spsectiontype = $specialcatmode; if ($enablespecial == 'yes' && get_user_class() >= get_setting('authority.view_special_torrent')) $allowspecial = true; else $allowspecial = false; +if (strpos($CURUSER['notifs'], "[spstate=0]") !== false) + $special_state = 0; +elseif (strpos($CURUSER['notifs'], "[spstate=1]") !== false) + $special_state = 1; +elseif (strpos($CURUSER['notifs'], "[spstate=2]") !== false) + $special_state = 2; +elseif (strpos($CURUSER['notifs'], "[spstate=3]") !== false) + $special_state = 3; +elseif (strpos($CURUSER['notifs'], "[spstate=4]") !== false) + $special_state = 4; +elseif (strpos($CURUSER['notifs'], "[spstate=5]") !== false) + $special_state = 5; +elseif (strpos($CURUSER['notifs'], "[spstate=6]") !== false) + $special_state = 6; +elseif (strpos($CURUSER['notifs'], "[spstate=7]") !== false) + $special_state = 7; +else $special_state = 0; /* $showsubcat = (get_searchbox_value($brsectiontype, 'showsubcat') || ($allowspecial && get_searchbox_value($spsectiontype, 'showsubcat'))); $showsource = (get_searchbox_value($brsectiontype, 'showsource') || ($allowspecial && get_searchbox_value($spsectiontype, 'showsource'))); //whether show sources or not @@ -521,25 +574,11 @@ if ($showaudiocodec) $audiocodecs = searchbox_item_list("audiocodecs"); $categories .= ""; $categories .= ""; - if (strpos($CURUSER['notifs'], "[spstate=0]") !== false) - $special_state = 0; - elseif (strpos($CURUSER['notifs'], "[spstate=1]") !== false) - $special_state = 1; - elseif (strpos($CURUSER['notifs'], "[spstate=2]") !== false) - $special_state = 2; - elseif (strpos($CURUSER['notifs'], "[spstate=3]") !== false) - $special_state = 3; - elseif (strpos($CURUSER['notifs'], "[spstate=4]") !== false) - $special_state = 4; - elseif (strpos($CURUSER['notifs'], "[spstate=5]") !== false) - $special_state = 5; - elseif (strpos($CURUSER['notifs'], "[spstate=6]") !== false) - $special_state = 6; - else $special_state = 0; $categories .= ""; $categories .= "
".$lang_usercp['text_additional_selection']."
".$lang_usercp['text_show_dead_active']."
".$lang_usercp['text_show_special_torrents']."
".$lang_usercp['text_show_bookmarked']."
"; */ + $categories = build_search_box_category_table($browsecatmode, 'yes','torrents.php?allsec=1', false, 3, $CURUSER['notifs'], ['section_name' => true]); $delimiter = '
'; if (get_setting('main.spsct') == 'yes') {