diff --git a/db/schema.sql b/db/schema.sql index c64eb3f355..2511423525 100644 --- a/db/schema.sql +++ b/db/schema.sql @@ -545,11 +545,12 @@ create table post ( primary key (id) ) engine=InnoDB; --- subscription to a thread +-- subscription to a thread or forum -- create table subscriptions ( userid integer not null, threadid integer not null, + -- or negative of forum ID (kludge) notified_time integer not null default 0 -- deprecated ) engine=InnoDB; @@ -723,8 +724,9 @@ create table notify ( -- destination of notification create_time integer not null, type integer not null, + -- see html/inc/forum_db.inc opaque integer not null - -- some other ID, e.g. that of the thread, user or PM record + -- the ID of the thread, user or PM record ); create table badge ( diff --git a/html/inc/forum.inc b/html/inc/forum.inc index f3f866149f..b2f84797a0 100644 --- a/html/inc/forum.inc +++ b/html/inc/forum.inc @@ -145,7 +145,15 @@ function show_forum_header($user) { -
+ '; + echo sprintf( + '
', + 'btn btn-sm', + button_style(), + tra("Search for words in forum messages"), + tra("Search forums") + ); + echo ' '.tra("Advanced search").' '; @@ -863,25 +871,53 @@ function post_warning($forum=null) { return $x; } -function notify_subscriber($thread, $user) { +function notify_thread_subscriber($thread, $user) { BoincForumPrefs::lookup($user); if ($user->prefs->pm_notification == 1) { - send_reply_notification_email($thread, $user); + send_thread_notification_email($thread, $user); } $now = time(); - $type = NOTIFY_SUBSCRIBED_POST; - BoincNotify::replace("userid=$user->id, create_time=$now, type=$type, opaque=$thread->id"); + $type = NOTIFY_SUBSCRIBED_THREAD; + BoincNotify::replace( + "userid=$user->id, create_time=$now, type=$type, opaque=$thread->id" + ); } // notify subscribed users, except for the given user // -function notify_subscribers($thread, $user) { +function notify_thread_subscribers($thread, $user) { $subs = BoincSubscription::enum("threadid=$thread->id"); foreach ($subs as $sub) { if ($user && ($user->id == $sub->userid)) continue; $user2 = BoincUser::lookup_id($sub->userid); if ($user2) { - notify_subscriber($thread, $user2); + notify_thread_subscriber($thread, $user2); + } + } +} + +function notify_forum_subscriber($forum, $user) { + BoincForumPrefs::lookup($user); + if ($user->prefs->pm_notification == 1) { + send_forum_notification_email($forum, $user); + } + $now = time(); + $type = NOTIFY_SUBSCRIBED_FORUM; + BoincNotify::replace( + "userid=$user->id, create_time=$now, type=$type, opaque=$forum->id" + ); +} + +// notify subscribed users, except for the given user +// +function notify_forum_subscribers($forum, $user) { + $id = -$forum->id; + $subs = BoincSubscription::enum("threadid=$id"); + foreach ($subs as $sub) { + if ($user && ($user->id == $sub->userid)) continue; + $user2 = BoincUser::lookup_id($sub->userid); + if ($user2) { + notify_forum_subscriber($forum, $user2); } } } @@ -909,7 +945,7 @@ function create_post($content, $parent_id, $user, $forum, $thread, $signature) { return null; } - notify_subscribers($thread, $user); + notify_thread_subscribers($thread, $user); $user->prefs->update("posts=posts+1"); $thread->update("replies=replies+1, timestamp=$now"); @@ -961,6 +997,8 @@ function create_thread($title, $content, $user, $forum, $signature, $export) { $thread = BoincThread::lookup_id($id); create_post($content, 0, $user, $forum, $thread, $signature); $forum->update("threads=threads+1"); + notify_forum_subscribers($forum, $user); + exit; return $thread; } @@ -1043,7 +1081,7 @@ function move_post($post, $old_thread, $old_forum, $new_thread, $new_forum) { update_thread_timestamp($new_thread); update_forum_timestamp($old_forum); update_forum_timestamp($new_forum); - notify_subscribers($new_thread, $g_logged_in_user); + notify_thread_subscribers($new_thread, $g_logged_in_user); return true; } @@ -1350,11 +1388,11 @@ function show_thread_and_context($thread, $user) { '; } -// see if thread is in subscription list +// see if ID is in subscription list // -function is_subscribed($thread, $subs) { +function is_subscribed($id, $subs) { foreach ($subs as $sub) { - if ($sub->threadid == $thread->id) return true; + if ($sub->threadid == $id) return true; } return false; } @@ -1369,21 +1407,40 @@ function is_forum_visible_to_user($forum, $user) { return true; } -function subscribed_post_email_line($notify) { +function subscribed_thread_email_line($notify) { $thread = BoincThread::lookup_id($notify->opaque); return "There are new posts in the thread '$thread->title'"; } -function subscribed_post_web_line($notify) { +function subscribed_thread_web_line($notify) { $thread = BoincThread::lookup_id($notify->opaque); return tra("New posts in the thread %1","id>$thread->title"); } -function subscribe_rss($notify, &$title, &$msg, &$url) { +function subscribed_thread_rss($notify) { $thread = BoincThread::lookup_id($notify->opaque); $title = tra("New posts in subscribed thread"); $msg = tra("There are new posts in the thread '%1'",$thread->title); $url = secure_url_base()."forum_thread.php?id=$thread->id"; + return [$title, $msg, $url]; +} + +function subscribed_forum_email_line($notify) { + $forum = BoincForum::lookup_id($notify->opaque); + return "There are new threads in the forum '$forum->title'"; +} + +function subscribed_forum_web_line($notify) { + $forum = BoincForum::lookup_id($notify->opaque); + return tra("New threads in the forum %1","id>$forum->title"); +} + +function subscribed_forum_rss($notify) { + $forum = BoincForum::lookup_id($notify->opaque); + $title = tra("New posts in subscribed forum"); + $msg = tra("There are new threads in the forum '%1'",$forum->title); + $url = secure_url_base()."forum_forum.php?id=$forum->id"; + return [$title, $msg, $url]; } function show_mark_as_read_button($user) { @@ -1399,14 +1456,14 @@ function show_mark_as_read_button($user) { } function remove_subscriptions_forum($userid, $forumid) { - $subs = BoincSubscription::enum("userid=$userid"); + $subs = BoincSubscription::enum("userid=$userid and threadid>0"); foreach ($subs as $sub) { $thread = BoincThread::lookup_id($sub->threadid); if ($thread && $thread->forum == $forumid) { BoincSubscription::delete($userid, $thread->id); } } - $notices = BoincNotify::enum("userid=$userid and type=".NOTIFY_SUBSCRIBED_POST); + $notices = BoincNotify::enum("userid=$userid and type=".NOTIFY_SUBSCRIBED_THREAD); foreach ($notices as $n) { $thread = BoincThread::lookup_id($n->opaque); if ($thread && $thread->forum == $forumid) { @@ -1417,7 +1474,7 @@ function remove_subscriptions_forum($userid, $forumid) { function remove_subscriptions_thread($userid, $threadid) { BoincSubscription::delete($userid, $threadid); - BoincNotify::delete_aux("userid=$userid and type=".NOTIFY_SUBSCRIBED_POST." and opaque=$threadid"); + BoincNotify::delete_aux("userid=$userid and type=".NOTIFY_SUBSCRIBED_THREAD." and opaque=$threadid"); } function parse_forum_cookie() { diff --git a/html/inc/forum_db.inc b/html/inc/forum_db.inc index bae78387c3..b6000bab47 100644 --- a/html/inc/forum_db.inc +++ b/html/inc/forum_db.inc @@ -329,6 +329,7 @@ class BoincNotify { define ('NOTIFY_FRIEND_REQ', 1); define ('NOTIFY_FRIEND_ACCEPT', 2); define ('NOTIFY_PM', 3); -define ('NOTIFY_SUBSCRIBED_POST', 4); +define ('NOTIFY_SUBSCRIBED_THREAD', 4); +define ('NOTIFY_SUBSCRIBED_FORUM', 5); ?> diff --git a/html/inc/forum_email.inc b/html/inc/forum_email.inc index 22a469ca89..e85726c64c 100644 --- a/html/inc/forum_email.inc +++ b/html/inc/forum_email.inc @@ -123,13 +123,13 @@ For assistance with ".PROJECT." go to ".$master_url; return $success; } -// If a user is subscribed to a thread that is replied to, -// send them an email notifying them of the reply. +// There's a new post in the thread, which the user is subscribed to. +// send them an email notifying them. // -function send_reply_notification_email($thread, $user){ - $title = PROJECT . ": A user has posted to '". $thread->title ."'"; +function send_thread_notification_email($thread, $user){ + $title = PROJECT . ": there is a new post in '". $thread->title ."'"; $link = secure_url_base() . "forum_thread.php?id=" . $thread->id; - $body = "Another " . PROJECT . " user has posted to the thread + $body = "A " . PROJECT . " user has posted to the thread \"" . $thread->title . "\".\n" ."To view the updated thread, visit:\n$link @@ -141,6 +141,24 @@ Do not reply to this message. return send_email($user, $title, $body); } +// There's a new thread in the forum, which the user is subscribed to. +// send them an email notifying them. +// +function send_forum_notification_email($forum, $user){ + $title = PROJECT . ": there is a new thread in '". $forum->title ."'"; + $link = secure_url_base() . "forum_forum.php?id=" . $forum->id; + $body = "A " . PROJECT . " user has added a thread to the forum +\"" . $thread->title . "\".\n" + ."To view the updated forum, visit:\n$link + +-------------------------- +To change email preferences, visit: +".secure_url_base()."edit_forum_preferences_form.php +Do not reply to this message. +"; + return send_email($user, $title, $body); +} + //////////////////// a user clicks the red "x" to report a post /////////// // function send_report_post_email($user, $forum, $thread, $post, $message) { diff --git a/html/inc/notify.inc b/html/inc/notify.inc index 8c1d1790f5..ae3b5fa289 100644 --- a/html/inc/notify.inc +++ b/html/inc/notify.inc @@ -1,7 +1,7 @@ . +// notifications as an RSS feed + require_once("../project/project.inc"); function notify_rss_auth($user) { @@ -37,8 +39,8 @@ function show_notify_rss_item($notify) { case NOTIFY_PM: pm_rss($notify, $title, $msg, $url); break; - case NOTIFY_SUBSCRIBED_POST: - subscribe_rss($notify, $title, $msg, $url); + case NOTIFY_SUBSCRIBED_THREAD: + [$title, $msg, $url] = subscribe_rss($notify); break; } if (!$msg) { diff --git a/html/inc/user.inc b/html/inc/user.inc index cf1ab44677..e3f5a41224 100644 --- a/html/inc/user.inc +++ b/html/inc/user.inc @@ -207,8 +207,10 @@ function notify_description($notify) { return friend_notify_accept_web_line($notify); case NOTIFY_PM: return pm_web_line($notify); - case NOTIFY_SUBSCRIBED_POST: - return subscribed_post_web_line($notify); + case NOTIFY_SUBSCRIBED_THREAD: + return subscribed_thread_web_line($notify); + case NOTIFY_SUBSCRIBED_FORUM: + return subscribed_forum_web_line($notify); } return null; } diff --git a/html/inc/util.inc b/html/inc/util.inc index 0b3d5c92b0..31c3460e9a 100644 --- a/html/inc/util.inc +++ b/html/inc/util.inc @@ -958,7 +958,7 @@ function show_button($url, $text, $desc=null, $class=null, $extra=null) { // for places with a bunch of buttons, like forum posts // function show_button_small($url, $text, $desc=null) { - echo button_text($url, $text, $desc, "btn-primary btn-xs"); + echo button_text($url, $text, $desc, "btn btn-xs", button_style()); } // used for showing icons diff --git a/html/ops/notify.php b/html/ops/notify.php index 62ae443d00..e4cc346bfe 100755 --- a/html/ops/notify.php +++ b/html/ops/notify.php @@ -87,8 +87,8 @@ function send_notify_emails() { case NOTIFY_PM: $x = pm_email_line($notify); break; - case NOTIFY_SUBSCRIBED_POST: - $x = subscribed_post_email_line($notify); + case NOTIFY_SUBSCRIBED_THREAD: + $x = subscribed_thread_email_line($notify); break; } if ($x) { diff --git a/html/user/forum_forum.php b/html/user/forum_forum.php index 844e5662b3..52b249479c 100644 --- a/html/user/forum_forum.php +++ b/html/user/forum_forum.php @@ -16,123 +16,143 @@ // You should have received a copy of the GNU Lesser General Public License // along with BOINC. If not, see . -// display the threads in a forum. +// forum page: display 'New thread' button and list of threads require_once('../inc/util.inc'); require_once('../inc/time.inc'); require_once('../inc/forum.inc'); require_once('../inc/pm.inc'); -check_get_args(array("id", "sort", "start")); - -$id = get_int("id"); -$sort_style = get_int("sort", true); -$start = get_int("start", true); -if (!$start) $start = 0; - -$forum = BoincForum::lookup_id($id); -if (!$forum) error_page("forum ID not found"); -$user = get_logged_in_user(false); -BoincForumPrefs::lookup($user); - -if (DISABLE_FORUMS && !is_admin($user)) { - error_page("Forums are disabled"); -} - -if (!is_forum_visible_to_user($forum, $user)) { +function forum_page($forum, $user, $msg=null) { + global $forum_sort_styles; + $sort_style = get_int("sort", true); + $start = get_int("start", true); + if (!$start) $start = 0; + $subs = null; if ($user) { - remove_subscriptions_forum($user->id, $id); + if (DISABLE_FORUMS && !is_admin($user)) { + error_page("Forums are disabled"); + } + BoincForumPrefs::lookup($user); + $subs = BoincSubscription::enum("userid=$user->id"); } - error_page(tra("Not visible to you")); -} -if (!$sort_style) { - // get the sort style either from the logged in user or a cookie - if ($user){ - $sort_style = $user->prefs->forum_sorting; - } else { - list($sort_style, $thread_style) = parse_forum_cookie(); + if (!is_forum_visible_to_user($forum, $user)) { + if ($user) { + remove_subscriptions_forum($user->id, $forum->id); + } + error_page(tra("Not visible to you")); } -} else { - // set the sort style - if ($user){ - $user->prefs->forum_sorting = $sort_style; - $user->prefs->update("forum_sorting=$sort_style"); + + if (!$sort_style) { + // get the sort style either from the logged in user or a cookie + if ($user){ + $sort_style = $user->prefs->forum_sorting; + } else { + list($sort_style, $thread_style) = parse_forum_cookie(); + } } else { - list($old_style, $thread_style) = parse_forum_cookie(); - send_cookie( - 'sorting', implode("|", array($sort_style, $thread_style)), true + // set the sort style + if ($user){ + $user->prefs->forum_sorting = $sort_style; + $user->prefs->update("forum_sorting=$sort_style"); + } else { + list($old_style, $thread_style) = parse_forum_cookie(); + send_cookie( + 'sorting', implode("|", array($sort_style, $thread_style)), true + ); + } + } + + switch ($forum->parent_type) { + case 0: + $category = BoincCategory::lookup_id($forum->category); + if ($category->is_helpdesk) { + page_head(tra("Questions and Answers").' : '.$forum->title); + } else { + page_head(tra("Message boards").' : '.$forum->title); + } + if ($msg) echo "

$msg

\n"; + show_forum_header($user); + show_forum_title($category, $forum, NULL); + break; + case 1: + $team = BoincTeam::lookup_id($forum->category); + page_head(tra("Team message board for %1", $team->name)); + if ($msg) echo "

$msg

\n"; + show_forum_header($user); + show_team_forum_title($forum); + break; + } + + echo ' +

+

+ + + + - - -
+ '; + + if (user_can_create_thread($user, $forum)) { + show_button( + "forum_post.php?id=$forum->id", + tra("New thread"), + tra("Add a new thread to this forum") ); } -} - -switch ($forum->parent_type) { -case 0: - $category = BoincCategory::lookup_id($forum->category); - if ($category->is_helpdesk) { - page_head(tra("Questions and Answers").' : '.$forum->title); + if (is_subscribed(-$forum->id, $subs)) { + BoincNotify::delete_aux(sprintf( + 'userid=%d and type=%d and opaque=%d', + $logged_in_user->id, + NOTIFY_SUBSCRIBED_FORUM, + $forum->id + )); + show_button_small( + "forum_forum.php?id=$forum->id&action=unsubscribe", + 'Unsubscribe', + 'Unsubscribe from this forum' + ); } else { - page_head(tra("Message boards").' : '.$forum->title); + show_button_small( + "forum_forum.php?id=$forum->id&action=subscribe", + 'Subscribe', + 'Click to get notified when there are new threads in this forum' + ); } - show_forum_header($user); - show_forum_title($category, $forum, NULL); - break; -case 1: - $team = BoincTeam::lookup_id($forum->category); - page_head(tra("Team message board for %1", $team->name)); - show_forum_header($user); - show_team_forum_title($forum); - break; -} -echo ' -

- - - - - + + +
-'; - -if (user_can_create_thread($user, $forum)) { - show_button( - "forum_post.php?id=$id", - tra("New thread"), - tra("Add a new thread to this forum") + echo ' +
+ '; + echo select_from_array("sort", $forum_sort_styles, $sort_style); + echo sprintf(' + +
+
+ +

', + button_style() ); + + show_forum_threads($forum, $start, $sort_style, $user, $subs); + + echo " +

". + tra("This message board is available as an %1 RSS feed %2", "id&setup=1>", ""); + + page_tail(); } -echo '

-
-'; -echo select_from_array("sort", $forum_sort_styles, $sort_style); -echo sprintf(' - -
-
- -

', - button_style() -); - -show_forum($forum, $start, $sort_style, $user); - -echo " -

". - tra("This message board is available as an %1 RSS feed %2", "id&setup=1>", ""); - -page_tail(); - -// This function shows the threads for the given forum -// Starting from $start, +// Show the threads for the given forum +// starting from $start, // using the given $sort_style (as defined in forum.php) // and using the features for the logged in user in $user. // -function show_forum($forum, $start, $sort_style, $user) { +function show_forum_threads($forum, $start, $sort_style, $user, $subs) { $page_nav = page_links( "forum_forum.php?id=$forum->id&sort=$sort_style", $forum->threads, @@ -164,10 +184,6 @@ function show_forum($forum, $start, $sort_style, $user) { $sort_style, $show_hidden, $sticky_first ); - if ($user) { - $subs = BoincSubscription::enum("userid=$user->id"); - } - // Run through the list of threads, displaying each of them // foreach ($threads as $thread) { @@ -177,7 +193,7 @@ function show_forum($forum, $start, $sort_style, $user) { //if ($thread->status==1){ // This is an answered helpdesk thread - if ($user && is_subscribed($thread, $subs)) { + if ($user && is_subscribed($thread->id, $subs)) { echo ''; } else { // Just a standard thread. @@ -238,4 +254,20 @@ function show_forum($forum, $start, $sort_style, $user) { echo "
$page_nav"; // show page links } +$id = get_int("id"); +$forum = BoincForum::lookup_id($id); +if (!$forum) error_page("forum ID not found"); +$user = get_logged_in_user(false); +$action = get_str('action', true); + +if ($action == 'subscribe') { + BoincSubscription::replace($user->id, -$id); + forum_page($forum, $user, 'You are now subscribed to this forum.'); +} else if ($action == 'unsubscribe') { + BoincSubscription::delete($user->id, -$id); + forum_page($forum, $user, 'You are now unsubscribed from this forum.'); +} else { + forum_page($forum, $user); +} + ?> diff --git a/html/user/forum_thread.php b/html/user/forum_thread.php index 4e7d482c47..2848417c84 100644 --- a/html/user/forum_thread.php +++ b/html/user/forum_thread.php @@ -167,10 +167,12 @@ if (!$logged_in_user) { } if ($is_subscribed) { - $type = NOTIFY_SUBSCRIBED_POST; - BoincNotify::delete_aux( - "userid=$logged_in_user->id and type=$type and opaque=$thread->id" - ); + BoincNotify::delete_aux(sprintf( + 'userid=%d and type=%d and opaque=%d', + $logged_in_user->id, + NOTIFY_SUBSCRIBED_THREAD, + $thread->id + )); $url = "forum_subscribe.php?action=unsubscribe&thread=".$thread->id."$tokens"; show_button_small( $url, @@ -182,7 +184,7 @@ if (!$logged_in_user) { show_button_small( $url, tra("Subscribe"), - tra("Click to get email when there are new posts in this thread") + tra("Click to get notified when there are new posts in this thread") ); }