- web: add general-purpose notification mechanism.

Users can choose whether to get 1 email per notification,
    a daily "digest" email, or no email.
    (All notifications are shown on the Account page).
    Currently used for:
    - Friend requests and confirmations
    - Posts to subscribed threads
    - Private messages

    NOTE: To implement the "daily digest" feature, projects must add
    a periodic task for html/ops/notify.php to config.xml
- web: have project_footer() generate links for
    Account Page and Message Boards as well as Home
    NOTE: projects that want this change
    will have to modify their own project.inc.

svn path=/trunk/boinc/; revision=14447
This commit is contained in:
David Anderson 2007-12-30 22:02:16 +00:00
parent 40f594b07c
commit f183b6f47f
21 changed files with 484 additions and 119 deletions

View File

@ -22,3 +22,8 @@ David Dec 19 2007
user/
bolt_course.php
bolt_sched.php
David Dec 27 2007
- preliminary implementation of exercise_set
inc/bolt.inc

View File

@ -12561,3 +12561,46 @@ David 27 Dec 2007
hosts_user.php
tools/
upgrade
David 30 Dec 2007
- web: add general-purpose notification mechanism.
Users can choose whether to get 1 email per notification,
a daily "digest" email, or no email.
(All notifications are shown on the Account page).
Currently used for:
- Friend requests and confirmations
- Posts to subscribed threads
- Private messages
NOTE: To implement the "daily digest" feature, projects must add
a periodic task for html/ops/notify.php to config.xml
- web: have project_footer() generate links for
Account Page and Message Boards as well as Home
NOTE: projects that want this change
will have to modify their own project.inc.
db/
constraints.sql
schema.sql
html/
inc/
boinc_db.inc
friend.inc (new)
forum.inc
forum_db.inc
forum_email.inc
pm.inc
user.inc
ops/
db_update.php
notify.php
project.sample/
project.inc
user/
edit_forum_preferences_action.php
edit_forum_preferences_form.php
forum_subscribe.php
forum_thread.php
pm.php
tools/
make_project

View File

@ -122,4 +122,4 @@ alter table friend
add unique friend_u (user_src, user_dest);
alter table notify
add index notify_u (userid);
add unique notify_un (userid, type, opaque);

View File

@ -398,8 +398,11 @@ create table subscriptions (
userid integer not null,
threadid integer not null,
notified_time integer not null default 0
-- deprecated
) engine=InnoDB;
-- actually: prefs for all community features
--
create table forum_preferences (
userid integer not null default 0,
signature varchar(254) not null default '',
@ -425,6 +428,10 @@ create table forum_preferences (
ignore_sticky_posts tinyint not null default 0,
banished_until integer not null default 0,
pm_notification tinyint not null default 0,
-- actually controls all notifications.
-- 0 = no email
-- 1 = email per event
-- 2 = digest email
primary key (userid)
) engine=MyISAM;

View File

@ -265,7 +265,9 @@ class BoincPrivateMessage {
}
static function insert($clause) {
$db = BoincDb::get();
return $db->insert('private_messages', $clause);
$ret = $db->insert('private_messages', $clause);
if (!$ret) return $ret;
return $db->insert_id();
}
static function count($clause) {
$db = BoincDb::get();

View File

@ -710,6 +710,16 @@ function post_warning() {
";
}
function notify_subscriber($thread, $user) {
BoincForumPrefs::lookup($user);
if ($user->prefs->pm_notification == 1) {
send_reply_notification_email($thread, $user);
}
$now = time();
$type = NOTIFY_SUBSCRIBED_POST;
BoincNotify::replace("userid=$user->id, create_time=$now, type=$type, opaque=$thread->id");
}
// Various functions for adding/hiding/unhiding stuff.
// These take care of counts and timestamps.
// Don't do these things directly - use these functions
@ -722,16 +732,13 @@ function create_post($content, $parent_id, $user, $forum, $thread, $signature) {
$id = BoincPost::insert("(thread, user, timestamp, content, parent_post, signature) values ($thread->id, $user->id, $now, '$content', $parent_id, $sig)");
if (!$id) return null;
// send emails to subscribed users
// notify subscribed users
//
$subs = BoincSubscription::enum("threadid=$thread->id");
foreach ($subs as $sub) {
if ($user->id == $sub->userid) continue;
$user2 = BoincUser::lookup_id($sub->userid);
$visit_time = thread_last_visit($user2, $thread);
if ($visit_time > $sub->notified_time) {
send_reply_notification_email($thread, $user2);
}
notify_subscriber($thread, $user2);
}
$user->update("posts=posts+1");
$thread->update("replies=replies+1, timestamp=$now");
@ -1060,5 +1067,15 @@ function is_forum_visible_to_user($forum, $user) {
return true;
}
function subscribed_post_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) {
$thread = BoincThread::lookup_id($notify->opaque);
return "New posts in the thread <a href=forum_thread.php?id=$thread->id>$thread->title</a>";
}
?>

View File

@ -241,6 +241,15 @@ class BoincFriend {
$db = BoincDb::get();
return $db->enum('friend', 'BoincFriend', $clause);
}
static function delete($id1, $id2) {
$db = BoincDb::get();
$db->delete_aux('friend', "user_src=$id1 and user_dest=$id2");
$db->delete_aux('friend', "user_src=$id2 and user_dest=$id1");
}
static function replace($clause) {
$db = BoincDb::get();
return $db->replace('friend', $clause);
}
}
class BoincNotify {
@ -250,6 +259,10 @@ class BoincNotify {
if (!$ret) return null;
return $db->insert_id();
}
static function replace($clause) {
$db = BoincDb::get();
return $db->replace('notify', $clause);
}
static function enum($clause) {
$db = BoincDb::get();
return $db->enum('notify', 'BoincNotify', $clause);
@ -262,9 +275,19 @@ class BoincNotify {
$db = BoincDb::get();
return $db->delete($this, 'notify');
}
function delete_aux($clause) {
$db = BoincDb::get();
$db->delete_aux('notify', $clause);
}
static function enum_general($query) {
$db = BoincDb::get();
return $db->enum_general('BoincNotify', $query);
}
}
define ('NOTIFY_FRIEND_REQ', 1);
define ('NOTIFY_FRIEND_ACCEPT', 2);
define ('NOTIFY_PM', 3);
define ('NOTIFY_SUBSCRIBED_POST', 4);
?>

View File

@ -110,8 +110,15 @@ For further information and assistance with ".PROJECT." go to ".MASTER_URL;
function send_reply_notification_email($thread, $user){
$title = PROJECT . ": A user has posted to '". stripslashes($thread->title) ."'";
$link = URL_BASE . "forum_thread.php?id=" . $thread->id;
$body = "Another " . PROJECT . " user has posted to the thread \"" . stripslashes($thread->title) . "\".\n"
."To view the updated thread, visit the following URL:\n\n$link";
$body = "Another " . PROJECT . " user has posted to the thread
\"" . stripslashes($thread->title) . "\".\n"
."To view the updated thread, visit:\n$link
--------------------------
To change email preferences, visit:
".URL_BASE."edit_forum_preferences_form.php
Do not reply to this message.
";
return send_email($user, $title, $body);
}

78
html/inc/friend.inc Normal file
View File

@ -0,0 +1,78 @@
<?php
// The following two are what gets put into notification email digests
//
function friend_notify_req_email_line($notify) {
$src_user = BoincUser::lookup($notify->opaque);
if (!$src_user) return "";
return "$src_user->name has added you as a friend; please confirm";
}
function friend_notify_accept_email_line($notify) {
$src_user = BoincUser::lookup($notify->opaque);
if (!$src_user) return "";
return "$src_user->name has confirmed you as a friend";
}
// The following two are what gets put in the Notification
// area of user's Account page
//
function friend_notify_req_web_line($notify) {
$user = BoincUser::lookup_id($notify->opaque);
return "
<a href=friend.php?action=query&userid=$notify->opaque>Friendship request</a> from $user->name
";
}
function friend_notify_accept_web_line($notify) {
$user = BoincUser::lookup_id($notify->opaque);
return "
<a href=friend.php?action=accepted&userid=$notify->opaque>Friendship confirmation</a> from $user->name
";
}
function send_friend_request_email($src_user, $dest_user, $msg) {
$message = "
$src_user->name has added you as a friend at ".PROJECT.".
";
if (strlen($msg)) {
$message .= "
$src_user->name says: $msg
";
}
$message .= "
Please accept or decline by visiting
".URL_BASE."home.php
--------------------------
To change email preferences, visit:
".URL_BASE."edit_forum_preferences_form.php
Do not reply to this message.
" ;
send_email($dest_user, "[".PROJECT."] friend request", $message);
}
function send_friend_accept_email($dest_user, $src_user, $msg) {
$message = "
$dest_user->name has confirmed you as a friend at ".PROJECT.".
";
if (strlen($msg)) {
$message .= "
$dest_user->name says: $msg
";
}
$message .= "
Visit your Account page at
".URL_BASE."home.php
--------------------------
To change email preferences, visit:
".URL_BASE."edit_forum_preferences_form.php
Do not reply to this message.
" ;
send_email($src_user, "[".PROJECT."] friend confirmed", $message);
}
?>

View File

@ -77,19 +77,10 @@ function pm_create_new($error = null) {
exit();
}
function pm_send($to, $subject, $content) {
global $logged_in_user;
$userid = $to->id;
$senderid = $logged_in_user->id;
$sql_subject = mysql_real_escape_string($subject);
$sql_content = mysql_real_escape_string($content);
$to_user = BoincUser::lookup_id($userid);
BoincForumPrefs::lookup($to_user);
$send_email = false;
if ($to_user->prefs->pm_notification) $send_email = true;
BoincPrivateMessage::insert("(userid, senderid, date, subject, content) VALUES ($userid, $senderid, UNIX_TIMESTAMP(), '$sql_subject', '$sql_content')");
if ($send_email) {
$message = "
function send_pm_notification_email(
$logged_in_user, $to_user, $subject, $content
) {
$message = "
You have received a new private message at ".PROJECT.".
From: $logged_in_user->name (ID $logged_in_user->id)
@ -101,12 +92,50 @@ $content
To delete or respond to this message, visit:
".URL_BASE."pm.php
To disable email delivery of private messages, visit:
To change email preferences, visit:
".URL_BASE."edit_forum_preferences_form.php
Do not reply to this message.
" ;
send_email($to, "[".PROJECT."] private message", $message);
send_email($to_user, "[".PROJECT."] private message", $message);
}
function pm_email_line($notify) {
$pm = BoincPrivateMessage::lookup_id($notify->opaque);
$from_user = BoincUser::lookup_id($pm->senderid);
return "$from_user->name sent you a private message; subject: '$pm->subject'";
}
function pm_web_line($notify) {
$pm = BoincPrivateMessage::lookup_id($notify->opaque);
$from_user = BoincUser::lookup_id($pm->senderid);
return "<a href=pm.php>Private message</a> from $from_user->name, subject: $pm->subject";
}
function pm_send($to_user, $subject, $content) {
global $logged_in_user;
$sql_subject = mysql_real_escape_string($subject);
$sql_content = mysql_real_escape_string($content);
$mid = BoincPrivateMessage::insert("(userid, senderid, date, subject, content) VALUES ($to_user->id, $logged_in_user->id, UNIX_TIMESTAMP(), '$sql_subject', '$sql_content')");
if (!$mid) {
error_page("Couldn't create message");
}
// send email notification if needed
//
BoincForumPrefs::lookup($to_user);
switch ($to_user->prefs->pm_notification) {
case 0:
case 2:
break;
case 1:
send_pm_notification_email(
$logged_in_user, $to_user, $subject, $content
);
break;
}
// create notification in any case
//
BoincNotify::insert("(userid, create_time, type, opaque) values ($to_user->id, ".time().", ".NOTIFY_PM.", $mid)");
}
function pm_count($userid, $duration) {

View File

@ -4,6 +4,7 @@ require_once("../inc/credit.inc");
require_once("../inc/email.inc");
require_once("../inc/util.inc");
require_once("../inc/team.inc");
require_once("../inc/friend.inc");
require_once("../inc/forum_db.inc");
function parse_project($f) {
@ -150,20 +151,15 @@ function show_user_stats_private($user) {
function notify_description($notify) {
switch ($notify->type) {
case NOTIFY_FRIEND_REQ:
$user = BoincUser::lookup_id($notify->opaque);
return "
<a href=friend.php?action=query&userid=$notify->opaque>Friend request from $user->name</a>
<br>
";
break;
return friend_notify_req_web_line($notify);
case NOTIFY_FRIEND_ACCEPT:
$user = BoincUser::lookup_id($notify->opaque);
return "
<a href=friend.php?action=accepted&userid=$notify->opaque>$user->name confirmed as friend</a>
<br>
";
break;
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);
}
return "Unknown notification type: $notify->type";
}
// show static user info (private)
@ -222,17 +218,18 @@ function show_user_info_private($user) {
if (count($notifies)) {
$x = "";
foreach ($notifies as $notify) {
$x .= notify_description($notify);
$x .= notify_description($notify)."<br>";
}
row2("Notifications", $x);
}
$friends = BoincFriend::enum("user_src=$user->id and reciprocated=1");
if (count($friends)) {
$x = "";
$x = null;
foreach($friends as $friend) {
if ($x) $x .= " | ";
$fuser = BoincUser::lookup_id($friend->user_dest);
$x .= " ". user_links($fuser);
$x .= user_links($fuser, true);
}
row2("Friends", $x);
}
@ -305,10 +302,11 @@ function show_user_summary_public($user) {
$friends = BoincFriend::enum("user_src=$user->id and reciprocated=1");
if (count($friends)) {
$x = "";
$x = null;
foreach($friends as $friend) {
if ($x) $x .= " | ";
$fuser = BoincUser::lookup_id($friend->user_dest);
$x .= " ".user_links($fuser, true);
$x .= user_links($fuser, true);
}
row2("Friends", $x);
}
@ -316,8 +314,12 @@ function show_user_summary_public($user) {
if ($g_logged_in_user && $g_logged_in_user->id != $user->id) {
row2("Contact", "<a href=\"pm.php?action=new&userid=".$user->id."\">Send private message</a>");
$friend = BoincFriend::lookup($g_logged_in_user->id, $user->id);
if (!$friend) {
row2("Community", "<a href=friend.php?action=add&userid=".$user->id.">Add as friend</a>");
if ($friend && $friend->reciprocated) {
row2("This person is a friend",
"<a href=friend.php?action=cancel_confirm&userid=$user->id>Cancel friendship</a>"
);
} else {
row2("Community", "<a href=friend.php?action=add&userid=$user->id>Add as friend</a>");
}
}
}

View File

@ -534,6 +534,13 @@ function update_12_18_2007() {
");
}
function update_12_28_2007() {
do_query("alter table notify drop index notify_u");
do_query("alter table notify
add unique notify_un (userid, type, opaque)
");
}
// modify the following to call the function you want.
// Make sure you do all needed functions, in order.
// (Look at your DB structure using "explain" queries to see

91
html/ops/notify.php Executable file
View File

@ -0,0 +1,91 @@
#!/usr/bin/env php
<?php
// Script to delete old notifications and send notification emails.
// Run once a day.
//
// We send emails for notifications generated in the last day.
// This is a slight kludge - since the timing of period tasks
// is not precise, notifications may be delivered twice or not at all.
// We use a 1-hour slop factor to err on the side of twice.
//
require_once("../inc/boinc_db.inc");
require_once("../inc/util.inc");
require_once("../project/project.inc");
// delete notifications older than 90 days
//
function delete_old_notifies() {
$t = time()-90*86400;
BoincNotify::delete_aux("create_time < $t");
}
function send_notify_email($userid, $message) {
$user = BoincUser::lookup_id($userid);
$subject = "Daily notification summary from ".PROJECT;
$body = "The following events occurred in the past day at ".PROJECT.".
For details, visit your Account page at
".URL_BASE."home.php
$message
---------------
To change your email preferences for ".PROJECT.", visit:
".URL_BASE."edit_forum_preferences_form.php
Do not reply to this email.
";
send_email($user, $subject, $body);
echo "sending to $user->email_addr\n";
}
function send_notify_emails() {
$t = time() - (86400 + 3600); // 1-hour slop factor
$query = "select notify.* from DBNAME.notify, DBNAME.forum_preferences where forum_preferences.pm_notification=2 and notify.userid = forum_preferences.userid and notify.create_time > $t";
$notifies = BoincNotify::enum_general($query);
$userid = 0;
$message = "";
$i = 1;
foreach ($notifies as $notify) {
if ($userid && $notify->userid != $userid) {
send_notify_email($userid, $message);
$message = "";
$i = 1;
}
$userid = $notify->userid;
$message .= "$i) ";
switch ($notify->type) {
case NOTIFY_FRIEND_REQ:
$message .= friend_notify_req_email_line($notify);
break;
case NOTIFY_FRIEND_ACCEPT:
$message .= friend_notify_accept_email_line($notify);
break;
case NOTIFY_PM:
$message .= pm_email_line($notify);
break;
case NOTIFY_SUBSCRIBED_POST:
$message .= subscribed_post_email_line($notify);
break;
}
$message .= "\n";
$i++;
}
if ($userid) {
send_notify_email($userid, $message);
}
}
$t = time_str(time());
echo "Starting at $t\n";
delete_old_notifies();
send_notify_emails();
$t = time_str(time());
echo "Ending at $t\n\n";
?>

View File

@ -7,7 +7,7 @@
require_once("../inc/util.inc");
$master_url = parse_config(get_config(), "<master_url>");
define("PROJECT", "Test Project");
define("PROJECT", "REPLACE WITH PROJECT NAME");
define("URL_BASE", $master_url);
define("IMAGE_PATH", "../user_profile/images/");
define("IMAGE_URL", "user_profile/images/");
@ -15,9 +15,10 @@ define("PROFILE_PATH", "../user_profile/");
define("PROFILE_URL", "user_profile/");
define("LANGUAGE_FILE", "languages.txt");
define("STYLESHEET", "white.css");
define("COPYRIGHT_HOLDER", "Test Group");
define("COPYRIGHT_HOLDER", "REPLACE WITH COPYRIGHT HOLDER");
define("SYS_ADMIN_EMAIL", "admin@$master_url");
define("UOTD_ADMIN_EMAIL", "admin@$master_url"); # who gets user of the day pool running low e-mails?
define("UOTD_ADMIN_EMAIL", "admin@$master_url");
// who gets user of the day pool running low e-mails?
// Email addresses separated by pipe ( | ) that will receive user reported
// offensive forum posts.
@ -37,7 +38,7 @@ function project_banner($title) {
function project_footer($show_return, $show_date) {
echo "<br><hr noshade size=1><center>";
if ($show_return) {
echo "<a href=\"".URL_BASE."\">Return to ".PROJECT." main page</a><br>\n";
echo "<a href=index.php>Home</a> | <a href=home.php>My Account</a> | <a href=forum_index.php>Message Boards</a><br>\n";
}
echo "<br><br>Copyright &copy; ".date("Y ").COPYRIGHT_HOLDER."</center>\n";
if ($show_date) {

View File

@ -83,7 +83,6 @@ if ($avatar_type==0){
}
}
// Update some simple prefs that are either on or off
$images_as_links = ($_POST["forum_images_as_links"]!="")?1:0;
$link_popup = ($_POST["forum_link_popup"]!="")?1:0;
$hide_avatars = ($_POST["forum_hide_avatars"]!="")?1:0;
@ -91,7 +90,7 @@ $hide_signatures = ($_POST["forum_hide_signatures"]!="")?1:0;
$jump_to_unread = ($_POST["forum_jump_to_unread"]!="")?1:0;
$ignore_sticky_posts = ($_POST["forum_ignore_sticky_posts"]!="")?1:0;
$no_signature_by_default = ($_POST["signature_by_default"]!="")?0:1;
$pm_notification = ($_POST["pm_notification"]!="")?1:0;
$pm_notification = post_int("pm_notification");
//$low_rating_threshold = post_int("forum_low_rating_threshold");
//$high_rating_threshold = post_int("forum_high_rating_threshold");
$signature = stripslashes($_POST["signature"]);

View File

@ -27,15 +27,31 @@ echo "<script type=\"text/javascript\">
start_table();
echo "<form method=\"post\" action=\"edit_forum_preferences_action.php\" enctype=\"multipart/form-data\">";
// ------------ Notification -----------
row1("Notifications");
$ch0 = $user->prefs->pm_notification==0?"checked":"";
$ch1 = $user->prefs->pm_notification==1?"checked":"";
$ch2 = $user->prefs->pm_notification==2?"checked":"";
row2(
"How should we notify you of new private messages, friend requests, posts in subscribed threads, and other events?",
"<input type=radio name=pm_notification value=0 $ch0> On my Account page (no email)
<br><input type=radio name=pm_notification value=1 $ch1> Immediately, by email
<br><input type=radio name=pm_notification value=2 $ch2> In a single daily email
"
);
// ------------ Forum identity -----------
$zero_select = $two_select = "";
if (strlen($user->prefs->avatar)){
$two_select="checked=\"true\"";
} else {
$zero_select="checked=\"true\"";
}
row1("Identity");
row1("Message-board identity");
row2("Avatar
<br><span class=note>An image representing you.
<br><span class=note>An image representing you on the message boards.
<br>Format: JPG or /PNG. Size: at most 4 KB, 100x100 pixels</span>",
"<input type=\"radio\" name=\"avatar_select\" value=\"0\" ".$zero_select.">Don't use an avatar <br><input type=\"radio\" name=\"avatar_select\" value=\"2\" ".$two_select.">Use this uploaded avatar: <input type=\"file\" name=\"picture\">"
);
@ -52,7 +68,7 @@ if (!$user->prefs->no_signature_by_default){
$signature=stripslashes($user->prefs->signature);
$maxlen=250;
row2(
"Signature<br>
"Signature for message board posts<br>
<span class=note>Max length is $maxlen chars.</span>".
html_info(),
"<textarea name=\"signature\" rows=4 cols=50 id=\"signature\" onkeydown=\"textCounter(this.form.signature, this.form.remLen,$maxlen);\"
@ -67,16 +83,7 @@ if ($user->prefs->signature!=""){
);
}
row1("Private message notification");
if ($user->prefs->pm_notification){
$pm_notification="checked=\"checked\"";
} else {
$pm_notification="";
}
row2(
"Send email notification of new private messages",
"<input type=\"checkbox\" id=\"pm_notification\" name=\"pm_notification\" ".$pm_notification.">"
);
// ------------ Message display -----------
if ($user->prefs->hide_avatars){
$forum_hide_avatars = "checked=\"checked\"";
@ -132,6 +139,8 @@ row2("How to sort",
"
);
// ------------ Message filtering -----------
row1("Message filtering");
$filtered_userlist = get_ignored_list($user);

View File

@ -29,7 +29,7 @@ function subscribe($forum, $thread, $user) {
show_forum_header($user);
show_title($forum, $thread);
echo "<p>You are now subscribed to <b>", cleanup_title($thread->title), "</b>.
You will receive an email whenever someone posts to the thread.";
You will be notified whenever there is a new post.";
} else {
page_head("Subscription failed");
echo "<p>We are currently unable to subscribe you to this thread (<b>", cleanup_title($thread->title), "</b>).

View File

@ -115,6 +115,8 @@ if (can_reply($thread, $forum, $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");
$url = "forum_subscribe.php?action=unsubscribe&thread=".$thread->id."$tokens";
show_button($url, tra("Unsubscribe"), "You are subscribed to this thread. Click here to unsubscribe.");
} else {

View File

@ -5,36 +5,28 @@
require_once("../inc/forum_db.inc");
require_once("../inc/profile.inc");
// tell src:
// You are about to add X as a friend.
// We will notify X, who wil have to confirm that you are friends
// (add message here)
// add/cancel
// see if there's already a request,
// and whether the notification record is there
//
// send PM or email to dest saying
// subject: X added you as a friend on Project
// X added you as a friend on Project.
// X says: Y
// To confirm this friend request, please visit:
// Z
//
// Thanks -- Project
//
// To control the emails you receive from Project, please visit W
//
// link goes to page:
// You have a friend request.
// (show picture)
// Name (conutry)
// You and X have friends in common:
// buttons: Confirm, Ignore
// small links: Send a message, report this person
// no rate-limiting mechanism
function send_request() {
function check_pending($user, $destuser) {
$friend = BoincFriend::lookup($user->id, $destuser->id);
if ($friend) {
if ($friend->reciprocated) {
error_page("Already friends");
}
$notify = BoincNotify::lookup($destuser->id, NOTIFY_FRIEND_REQ, $user->id);
if ($notify) {
page_head("Request pending");
$t = date_str($friend->create_time);
echo "You requested friendship with $destuser->name on $t.
<p>
This request is still pending confirmation.
";
page_tail();
exit();
}
BoincFriend::delete($user->id, $destuser->id);
}
}
// user has clicked "add to friends". Ask them if they really mean it.
@ -46,10 +38,9 @@ function handle_add($user) {
}
$destuser = BoincUser::lookup_id($destid);
if (!$destuser) error_page("No such user");
$friend = BoincFriend::lookup($user->id, $destid);
if ($friend) {
error_page("Friend request already exists");
}
check_pending($user, $destuser);
page_head("Add friend");
echo "
<form method=post action=friend.php>
@ -64,7 +55,7 @@ function handle_add($user) {
<textarea name=message cols=64 rows=4></textarea>
<p>
<input type=submit value=OK>
<input type=submit value=Cancel>
</form>
";
page_tail();
}
@ -76,20 +67,28 @@ function handle_add_confirm($user) {
$destuser = BoincUser::lookup_id($destid);
if (!$destuser) error_page("No such user");
check_pending($user, $destuser);
$msg = post_str('message', true);
if ($msg) $msg = strip_tags(process_user_text($msg));
$now = time();
$ret = BoincFriend::insert("(user_src, user_dest, message, create_time, reciprocated) values ($user->id, $destid, '$msg', $now, 0)");
$ret = BoincFriend::replace("user_src=$user->id, user_dest=$destid, message='$msg', create_time=$now, reciprocated=0");
if (!$ret) {
error_page("database error");
}
$ret = BoincNotify::insert("(userid, create_time, type, opaque) values ($destid, $now, ".NOTIFY_FRIEND_REQ.", $user->id)");
if (!$ret) {
error_page("Database error");
$now = time();
$type = NOTIFY_FRIEND_REQ;
BoincNotify::replace("userid=$destid, create_time=$now, type=$type, opaque=$user->id");
BoincForumPrefs::lookup($destuser);
if ($destuser->prefs->pm_notification == 1) {
send_friend_request_email($user, $destuser, $msg);
}
page_head("Friend request sent");
echo "We have notified <b>$destuser->name</b> of your request.";
echo "
We have notified <b>$destuser->name</b> of your request.
";
page_tail();
}
@ -105,19 +104,18 @@ function handle_query($user) {
$x = user_links($srcuser, true);
echo "
$x has added you as a friend.
If $srcuser->name is in fact your friend, please click Accept.
";
$img_url = profile_user_thumb_url($srcuser);
if ($img_url) {
echo "<p><img src=$img_url><p>\n";
}
if (strlen($friend->message)) {
echo "<p>$srcuser->name says: $friend->message<p>";
}
echo "
<p>
<a href=friend.php?action=accept&userid=$srcid>Accept</a> |
<a href=friend.php?action=ignore&userid=$srcid>Ignore</a>
<a href=friend.php?action=accept&userid=$srcid>Accept</a>
(click if $srcuser->name is in fact a friend)
<p>
<a href=friend.php?action=ignore&userid=$srcid>Decline</a>
(click if $srcuser->name is not a friend)
<p>
";
page_tail();
}
@ -139,24 +137,26 @@ function handle_accept($user) {
$msg = post_str('message', true);
if ($msg) $msg = strip_tags(process_user_text($msg));
$now = time();
$ret = BoincFriend::insert("(user_src, user_dest, message, create_time, reciprocated) values ($user->id, $srcid, '$msg', $now, 1)");
$ret = BoincFriend::replace("user_src=$user->id, user_dest=$srcid, message='$msg', create_time=$now, reciprocated=1");
if (!$ret) {
error_page("database error");
}
$ret = BoincNotify::insert("(userid, create_time, type, opaque) values ($srcid, $now, ".NOTIFY_FRIEND_ACCEPT.", $user->id)");
if (!$ret) {
error_page("Database error");
$type = NOTIFY_FRIEND_ACCEPT;
BoincNotify::replace("userid=$srcid, create_time=$now, type=$type, opaque=$user->id");
BoincForumPrefs::lookup($srcuser);
if ($srcuser->prefs->pm_notification == 1) {
send_friend_accept_email($user, $srcuser, $msg);
}
$notify = BoincNotify::lookup($user->id, NOTIFY_FRIEND_REQ, $srcid);
if ($notify) {
$notify->delete();
} else {
echo "?? notification not found";
}
page_head("Friendship confirmed");
echo "Your friendship with <b>$srcuser->name</b> has been confirmed.";
echo "
Your friendship with <b>$srcuser->name</b> has been confirmed.
";
page_tail();
}
@ -173,11 +173,11 @@ function handle_ignore($user) {
$notify = BoincNotify::lookup($user->id, NOTIFY_FRIEND_REQ, $srcid);
if ($notify) {
$notify->delete();
} else {
echo "?? notification not found";
}
page_head("Friendship declined");
echo "You have declined friendship with <b>$srcuser->name</b>.";
echo "
You have declined friendship with <b>$srcuser->name</b>
";
page_tail();
}
@ -201,6 +201,33 @@ function handle_accepted($user) {
page_tail();
}
function handle_cancel_confirm($user) {
$destid = get_int('userid');
$destuser = BoincUser::lookup_id($destid);
if (!$destuser) error_page("No such user");
page_head("Cancel friendship?");
echo "
Are you sure you want to cancel your friendship with $destuser->name?
<p>
";
show_button("friend.php?action=cancel&userid=$destid", "Yes", "Cancel friendship");
echo "<p>";
show_button("home.php", "No", "Don't cancel friendship");
page_tail();
}
function handle_cancel($user) {
$destid = get_int('userid');
$destuser = BoincUser::lookup_id($destid);
if (!$destuser) error_page("No such user");
BoincFriend::delete($user->id, $destid);
page_head("Friendship cancelled");
echo "
Your friendship with $destuser->name has been cancelled.
";
page_tail();
}
// "home page" has Requests area
// (icon) N friend request(s)
@ -228,6 +255,12 @@ case 'accepted':
case 'ignore':
handle_ignore($user);
break;
case 'cancel_confirm':
handle_cancel_confirm($user);
break;
case 'cancel':
handle_cancel($user);
break;
default:
error_page("unknown action");
}

View File

@ -45,6 +45,9 @@ function make_script() {
";
}
// show all private messages,
// and delete notifications of new messages
//
function do_inbox($logged_in_user) {
page_head(tra("Private messages").": ".tra("Inbox"));
@ -54,6 +57,8 @@ function do_inbox($logged_in_user) {
}
$options = get_output_options($logged_in_user);
BoincNotify::delete_aux("userid=$logged_in_user->id and type=".NOTIFY_PM);
$msgs = BoincPrivateMessage::enum(
"userid=$logged_in_user->id ORDER BY date DESC"
);

View File

@ -258,6 +258,11 @@ t.period = '24 hours'
t.output = 'team_import.out'
t.cmd = 'run_in_ops team_import.php'
t = project.config.tasks.make_node_and_append("task")
t.period = '24 hours'
t.output = 'notify.out'
t.cmd = 'run_in_ops notify.php'
project.config.write()
svn_version_file = proot+'/local.revision'