name == 'friend') { switch ($event) { case 'flag': // See the status of the friendship. $status = flag_friend_determine_friend_status($flag, $account->uid, $content_id); // If both are now flagged, we record the relationship and remove the flags. if ($status == 'both flagged') { // Remove any message entries for either user. flag_friend_message('unflag', $flag, $account->uid, $content_id); flag_friend_message('unflag', $flag, $content_id, $account->uid); // Since these users have flagged eachother, we create the relationship in the flag_friend table. db_query("INSERT INTO {flag_friend} VALUES(%d, %d, %d)", $account->uid, $content_id, $_SERVER['REQUEST_TIME']); // Then remove the flags. $flag->flag('unflag', $content_id, $account); $flag->flag('unflag', $account->uid, user_load(array('uid' => $content_id))); } break; case 'unflag': // Remove message. flag_friend_message($event, $flag, $content_id, $account->uid); break; } } } /** * Implementation of hook_preprocess_flag(). */ function flag_friend_preprocess_flag(&$vars) { // this hook preprocesses ALL flag links, so make sure we have ours if ($vars['flag']->name == 'friend') { global $user; // Determine what the status in the friend process is. $status = flag_friend_determine_friend_status($vars['flag'], $user->uid, $vars['content_id']); // Depending on the status, we need to manipulate the vars. if ($status == 'pending') { $vars['link_text'] = t('Pending - Cancel?'); $vars['flag_name_css'] = 'pending friend'; // TODO: some js to detect pending links and handle accordingly } if ($status == 'flagged') { // Make this link into a remove link with $vars['action'] = 'unflag'; $vars['link_href'] = str_replace('flag/confirm/', 'flag-friend/unfriend/', $vars['link_href']); $vars['link_text'] = $vars['flag']->unflag_short; } if ($status == 'approval') { $vars['link_text'] = t('Approve'); } } } /** * Implementation of hook_menu(). */ function flag_friend_menu($may_cache) { global $user; $items = array(); if (!$may_cache) { if ($user->uid) { if (arg(0) == 'user' && is_numeric(arg(1))) { // menu item to see message and respond $items[] = array( 'path' => 'user/'. arg(1) .'/flag-friend', 'callback' => 'flag_friend_page', 'callback arguments' => array(user_load(array('uid' => arg(1)))), 'access' => user_access('access content'), 'type' => MENU_CALLBACK, ); } } $items[] = array( 'path' => 'flag-friend', 'callback' => 'flag_friend_unfriend', 'access' => user_access('access content'), 'type' => MENU_CALLBACK, ); } return $items; } /** * Menu callback for displaying friends */ function flag_friend_page($account) { global $user; $output = ''; // make sure that only you can see your own pending friends if ($user->uid == $account->uid) { drupal_set_title(t('My friends')); $flag = flag_get_flag('friend'); // display a list of any pending friend requests $flags = flag_friend_get_flags($flag, $account->uid); if (!empty($flags)) { $output .= theme('flag_friend_pending_flags', $account, $flags); } } else { drupal_set_title(t("@name's friends", array('@name' => $account->name))); } // display a list of this user's friends $friends = flag_friend_get_friends($account->uid); $output .= theme('flag_friend_friend_list', $account, $friends); return $output; } /** * Callback function to retrieve pending friend flags for theming. */ function flag_friend_get_flags($flag, $content_id, $reset = NULL) { static $flagged_content; $uid = $content_id; $content_type = $flag->content_type; if (!isset($flagged_content[$uid][$content_type][$content_id]) || $reset) { $flags = flag_get_flags($flag->content_type); $flagged_content[$uid][$content_type][$content_id] = array(); // get any flags that do not have messages $result = db_query("SELECT * FROM {flag_content} WHERE content_type = '%s' AND content_id = %d", $content_type, $content_id); while ($new_flag = db_fetch_object($result)) { $fcid = flag_friend_get_fcid($flag, $content_id, $new_flag->uid); $flagged_content[$uid][$content_type][$content_id][$fcid] = $new_flag; $flagged_content[$uid][$content_type][$content_id][$fcid]->user = user_load(array('uid' => $new_flag->uid)); } // get flags with messages $result = db_query("SELECT fc.*, ffm.message FROM {flag_content} fc INNER JOIN {flag_friend_message} ffm ON ffm.fcid = fc.fcid WHERE content_type = '%s' AND content_id = %d", $content_type, $content_id); while ($new_flag = db_fetch_object($result)) { $fcid = flag_friend_get_fcid($flag, $content_id, $new_flag->uid); $flagged_content[$uid][$content_type][$content_id][$fcid] = $new_flag; $flagged_content[$uid][$content_type][$content_id][$fcid]->user = user_load(array('uid' => $new_flag->uid)); } } return $flagged_content[$uid][$content_type][$content_id]; } /** * Callback function to retrieve a list of friends for the given user. */ function flag_friend_get_friends($uid, $reset = NULL) { static $friends; if (!isset($friends[$uid]) || $reset) { $result = db_query("SELECT * FROM {flag_friend} WHERE uid = %d OR friend_uid = %d", $uid, $uid); while ($friend = db_fetch_object($result)) { // if the current user is in the uid column if ($friend->uid == $uid) { // load the friend_uid $friends[$uid][$friend->friend_uid] = user_load(array('uid' => $friend->friend_uid)); } else { // the current user is the friend_uid // load the uid column as the friend $friends[$uid][$friend->uid] = user_load(array('uid' => $friend->uid)); } } } return $friends[$uid]; } /** * Theme function for the list of pending flags. */ function theme_flag_friend_pending_flags($account, $flags) { // $account is the user of the page we're looking at // $flag->user is the user requesting the relationship $output = ''; $output .= t('

You have !friend_request.

', array('!friend_request' => format_plural(count($flags), 'a friend request', count($flags) .' friend requests'))); $output .= '
'; $count = count($flags); $output .= '
'. $count .' Pending Friend'. format_plural($count, '', 's') .'
'; $output .= '
'; return $output; } /** * Implementation of hook_user(). */ function flag_friend_user($op, &$edit, &$account, $category = NULL) { switch ($op) { case 'form': // The user account edit form is about to be displayed. The module should present the form elements it wishes to inject into the form. $form = array(); $form['friend_notification'] = array( '#type' => 'select', '#title' => t('I would like to be notified when someone wants to be friends with me'), '#multiple' => FALSE, '#options' => array(0 => 'Yes', -1 => 'No'), '#default_value' => isset($account->friend_notification) ? $account->friend_notification : 0, '#weight' => -10, ); return $form; break; } } /** * Implementation of hook_user_link(). */ function flag_friend_user_link($account) { global $user; // do not supply a link if the account and user are the same if ($user->uid != $account->uid) { $links = array(); $links['flag-friend'] = array( 'title' => flag_create_link('friend', $account->uid), 'html' => TRUE, ); return $links; } } /** * Create a denial link. */ function flag_friend_create_link($type, $uid) { if ($type == 'unfriend') { $flag = flag_get_flag('friend'); $link = str_replace('Approve', 'Deny', str_replace('/flag-form/', '/flag-friend/', $flag->theme('unflag', $uid))); return $link; } } /** * Theme function for the list of friends for the given user. */ function theme_flag_friend_friend_list($account, $friends) { $output = ''; if (!empty($friends)) { $output .= ''; } else { $output .= 'You have no friends, loser.'; } return $output; } /** * Menu callback to either unflag yourself, or remove the relationship record. */ function flag_friend_unfriend($event, $flag, $flag_name, $content_id, $token = NULL) { global $user; //die(print_r(func_get_args())); // this might be a denial, in which case we unflag if ($event == 'unflag') { // the content_id is actually the account param in this case $account = user_load(array('uid' => $content_id)); // and the $user->uid is actually the content(_id) we're unflagging $content_id = $user->uid; $flag = flag_get_flag($flag_name); $flag->flag($event, $content_id, $account); } else { // remove the friend relationship db_query('DELETE FROM {flag_friend} WHERE (uid = %d AND friend_uid = %d) OR (uid = %d AND friend_uid = %d)', $user->uid, $content_id, $content_id, $user->uid); } drupal_goto(); } /** * Determines the status of the friendship by testing various conditions. * * @param object $flag * The flag object. * * @param int $uid1 * The account id of one of the users. * * @param int $uid2 * The account id of the other user. * * @return * A string describing the status of the relationship. * * NOTE: this could possibly go into hook_flag_access? once available. */ function flag_friend_determine_friend_status($flag, $uid1, $uid2) { $you_are_flagged = $flag->is_flagged($uid1, $uid2); $they_are_flagged = $flag->is_flagged($uid2, $uid1); $friends = db_result(db_query("SELECT * FROM {flag_friend} WHERE (uid = %d AND friend_uid = %d) OR (uid = %d AND friend_uid = %d)", $uid1, $uid2, $uid2, $uid1)); // see if these users have flagged eachother if ($you_are_flagged && $they_are_flagged) { return 'both flagged'; } else if ($friends) { return 'flagged'; } else if (!$you_are_flagged && !$they_are_flagged) { return 'unflagged'; } else if ($you_are_flagged && !$they_are_flagged) { return 'approval'; } else if (!$you_are_flagged && $they_are_flagged) { return 'pending'; } } function flag_friend_form_alter($form_id, &$form) { if ($form_id == 'flag_confirm' && $form['flag_name']['#value'] == 'friend') { $action = $form['action']['#value']; $flag = flag_get_flag('friend'); $content_id = $form['content_id']['#value']; $token = $_REQUEST['token']; switch ($action) { case 'flag': $flag_form = flag_friend_message_form($action, $flag, $content_id, $token); $form = array_merge($flag_form, $form); unset($form['actions']['submit']); unset($form['actions']['cancel']); $form['#submit']['flag_friend_form_submit'] = array(); break; case 'unflag': $unflag_form = flag_friend_unfriend_form($action, $flag, $content_id, $token); $form = array_merge($form, $unflag_form); $form['#submit']['flag_friend_form_submit'] = array(); break; } } } /** * Form to send a message to a user before friend flagging. */ function flag_friend_message_form($action, $flag, $content_id, $token) { $form['current'] = array('#type' => 'value', '#value' => func_get_args()); $form['flag_friend_message'] = array( '#type' => 'textarea', '#title' => t('Friend message (optional)'), '#description' => t('Enter a message to send to this user.'), '#cols' => 60, '#rows' => 5, ); $form['flag_friend_submit'] = array( '#type' => 'submit', '#value' => t('Send'), '#suffix' => l('Cancel', $_GET['destination']), ); $form['#theme'] = 'flag_friend_message_form'; return $form; } /** * Form to confirm an unfriend flagging. */ function flag_friend_unfriend_form($action, $flag, $content_id, $token) { $form['current'] = array('#type' => 'value', '#value' => func_get_args()); $question = t('Are you sure you want to !action?', array('!action' => $action)); $path = $_REQUEST['destination']; $form = confirm_form($form, $question, $path); $form['#redirect'] = 'flag/'. $action .'/'. $flag->name .'/'. $content_id .'/'. $token .'?'. drupal_get_destination(); $form['#theme'] = 'flag_friend_unfriend_form'; return $form; } /** * Submit handler for message_form() and unfriend_form(). */ function flag_friend_form_submit($form_id, $form_values) { global $user; $action = $form_values['current'][0]; $flag = $form_values['current'][1]; $content_id = $form_values['current'][2]; $account = $user; $token = $form_values['current'][3]; if ($form_values['flag_friend_message']) { $flag->friend_message = $form_values['flag_friend_message']; } flag_friend_message($action, $flag, $content_id, $account->uid); $status = flag_friend_determine_friend_status($flag, $account->uid, $content_id); flag_friend_message_email($status, $flag, $content_id, $account); } /** * API callback function to update our new field. */ function flag_friend_message($action, $flag, $content_id, $account_uid) { // see if the flag has an fcid if (!isset($flag->fcid)) { $flag->fcid = flag_friend_get_fcid($flag, $content_id, $account_uid); } if ($action == 'flag' && $flag->friend_message) { db_query("INSERT INTO {flag_friend_message} VALUES(%d, '%s')", $flag->fcid, $flag->friend_message); } else if ($action == 'unflag') { db_query("DELETE FROM {flag_friend_message} WHERE fcid = %d", $flag->fcid); } } function flag_friend_message_email($status, $flag, $recipient_uid, $sender) { $recipient = user_load(array('uid' => $recipient_uid)); if (isset($recipient->friend_notification) && $recipient->friend_notification != -1) { $email = theme('flag_friend_message_email', $status, $flag, $recipient, $sender); if (function_exists('messaging_message_send_user')) { messaging_message_send_user($recipient, $email, NULL, 1); } else { drupal_mail($email['type'], $recipient->mail, $email['subject'], $email['body']); } } } /** * Theme the outgoing email message. * * @param string $status * Status of the friendship. * * @param object $flag * The flag object. * * @param object $recipient * The user object of the person receiving the email. * * @param object $sender * The user object of the person sending the email. * * @return * An array containing the email [type] (mailkey), [subject] and [body]. */ function theme_flag_friend_message_email($status, $flag, $recipient, $sender) { $email = array(); $email['type'] = 'flag-friend'; switch ($status) { case 'both flagged': // sender confirmed you as a friend $email['subject'] = t('!username confirmed you as a friend !site', array( '!username' => $sender->name, '!site' => 'on '. variable_get('site_name', ''), )); $email['body'] = t('!firstname confirmed you as a friend on !site.\n\n To view !firstname\'s profile, follow this link,\n !link\n\n !message\n\n Thanks,\n The !site Team', array( '!firstname' => $sender->firstname ? $sender->firstname : $sender->name, '!site' => variable_get('site_name', ''), '!message' => $flag->friend_message ? 'Message:\n'. $flag->friend_message : '', '!link' => url('user/'. $recipient->uid, NULL, NULL, TRUE), )); break; case 'pending': // sender added you as a friend $email['subject'] = t('!username added you as a friend !site', array('!username' => $sender->name, '!site' => 'on '. variable_get('site_name', ''))); $email['body'] = t('!firstname added you as a friend on !site. We need to confirm that you know !firstname in order for you to be friends on !site.\n\n To confirm this friend request, follow the link below:\n !link\n\n !message\n\n Thanks,\n The !site Team', array( '!firstname' => $sender->firstname ? $sender->firstname : $sender->name, '!site' => variable_get('site_name', ''), '!message' => $flag->friend_message ? 'Message:\n'. $flag->friend_message : '', '!link' => url('user/'. $recipient->uid .'/flag-friend', NULL, NULL, TRUE), )); break; } return $email; } /** * Retrieves the fcid of a flag. * * NOTE: hopefully fcid will be passed into the hook_flag() at some point * at which time will render this function unnecessary */ function flag_friend_get_fcid($flag, $content_id, $account_uid) { return db_result(db_query("SELECT fcid FROM {flag_content} WHERE fid = %d AND content_type = '%s' AND content_id = %d AND uid = %d", $flag->fid, $flag->content_type, $content_id, $account_uid)); } /** * Retrieve our flag's message. */ function flag_friend_get_message($fcid) { $flag_friend = FALSE; $result = db_result(db_query("SELECT message FROM {flag_friend_message} WHERE fcid = %d", $fcid)); if ($result) { $flag_friend = $result; } return $flag_friend; } /** * Theme function for the message form. */ function theme_flag_friend_message_form($form) { drupal_set_title('Send a friend request.'); return drupal_render($form); } /** * Theme function for the unfriending action. */ function theme_flag_friend_unfriend_form($form) { //drupal_set_title(); return drupal_render($form); } /** * Implementation of hook_flag_default_flags(). */ function flag_friend_flag_default_flags() { $flags = array(); $flags[] = array( 'content_type' => 'user', 'name' => 'friend', 'title' => 'Friend', 'roles' => array( 0 => '2', ), 'global' => FALSE, 'flag_short' => 'Add friend', 'flag_long' => 'Add this user to your list of friends.', 'flag_confirmation' => 'Are you sure you want to add this user to your list of friends?', 'unflag_short' => 'Remove friend', 'unflag_long' => 'Remove this user from your list of friends.', 'unflag_confirmation' => 'Are you sure you want to remove this user from your list of friends?', 'status' => FALSE, 'link_type' => 'confirm', 'locked' => array('name', 'global', 'link_type'), ); return $flags; }