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 .= "
| ".$lang_usercp['text_additional_selection']." | ||
| ".$lang_usercp['text_show_dead_active']." | ".$lang_usercp['text_show_special_torrents']." | ".$lang_usercp['text_show_bookmarked']." |