diff --git a/includes/admin.settings.inc b/includes/admin.settings.inc index c65c20c..90a6d73 100644 --- a/includes/admin.settings.inc +++ b/includes/admin.settings.inc @@ -26,6 +26,21 @@ function project_issue_settings_form(&$form_state) { '#description' => t('If selected, user signatures will be appended to the display of issue followups.'), ); + if (module_exists('flag')) { + $flags = flag_get_flags(); + $flag_options[0] = t('- None -'); + foreach ($flags as $flag) { + $flag_options[$flag->name] = $flag->title; + } + $form['project_issue_subscription_flag'] = array( + '#title' => t('Issue subscription flag'), + '#type' => 'select', + '#options' => $flag_options, + '#default_value' => variable_get('project_issue_subscription_flag', NULL), + '#description' => t('Allows users to receive e-mail notifications about issues that have been flagged with the selected flag. When none is selected, users can only subscribe by commenting on an issue.'), + ); + } + $form['project_issue_reply_to'] = array( '#type' => 'textfield', '#title' => t('Reply-to address on e-mail notifications'), diff --git a/includes/mail.inc b/includes/mail.inc index 0e510fc..7efe394 100644 --- a/includes/mail.inc +++ b/includes/mail.inc @@ -249,15 +249,101 @@ function project_issue_mail_notify($nid) { } } - if (count($uids)) { + // Retrieve list of users being globally subscribed to all issues. + $accounts_all_issues = array(); + $result = db_query("SELECT pisu.uid, u.name, u.mail FROM {project_issue_subscriptions_user} pisu INNER JOIN {users} u ON pisu.uid = u.uid WHERE u.status = 1 AND pisu.level = " . PROJECT_ISSUE_SUBSCRIPTIONS_ALL); + while ($account = db_fetch_object($result)) { + $accounts_all_issues[$account->uid] = $account; + } + + // Check whether Flag module integration is enabled for e-mail notifications. + $flag_integration = (module_exists('flag') && variable_get('project_issue_subscription_flag', 0)); + + // Retrieve list of users being globally subscribed to "own" issues (without + // Flag integration). + $accounts_flagged_issues = array(); + if (!$flag_integration) { + $result = db_query("SELECT pisu.uid, u.name, u.mail FROM {project_issue_subscriptions_user} pisu INNER JOIN {users} u ON pisu.uid = u.uid WHERE u.status = 1 AND pisu.level = " . PROJECT_ISSUE_SUBSCRIPTIONS_FLAGGED); + while ($account = db_fetch_object($result)) { + $accounts_flagged_issues[$account->uid] = $account; + } + } + + // Check per-project subscriptions of involved users. + if (!empty($uids)) { $placeholders = implode(',', array_fill(0, count($uids), '%d')); - array_unshift($uids, $node->project_issue['pid']); - $result = db_query("SELECT p.*, u.uid, u.name, u.mail FROM {project_subscriptions} p INNER JOIN {users} u ON p.uid = u.uid WHERE u.status = 1 AND p.nid = %d AND (p.level = 2 OR (p.level = 1 AND u.uid IN ($placeholders)))", $uids); + $args = $uids; + array_unshift($args, $node->project_issue['pid']); + + // Check which involved users are subscribed to all issues of the project. + $result = db_query("SELECT pisp.uid, u.name, u.mail + FROM {project_issue_subscriptions_project} pisp + INNER JOIN {users} u ON pisp.uid = u.uid + WHERE u.status = 1 AND pisp.nid = %d AND pisp.uid IN ($placeholders) AND pisp.level = " . PROJECT_ISSUE_SUBSCRIPTIONS_ALL, $args); + while ($account = db_fetch_object($result)) { + $accounts_all_issues[$account->uid] = $account; + } + + // Check which involved users are subscribed to "own" issues of the project + // (without Flag integration). + if (!$flag_integration) { + $result = db_query("SELECT pisp.uid, u.name, u.mail + FROM {project_issue_subscriptions_project} pisp + INNER JOIN {users} u ON pisp.uid = u.uid + WHERE u.status = 1 AND pisp.nid = %d AND pisp.uid IN ($placeholders) AND pisp.level = " . PROJECT_ISSUE_SUBSCRIPTIONS_FLAGGED, $args); + while ($account = db_fetch_object($result)) { + $accounts_flagged_issues[$account->uid] = $account; + } + } } - else { - $result = db_query('SELECT p.*, u.uid, u.name, u.mail FROM {project_subscriptions} p INNER JOIN {users} u ON p.uid = u.uid WHERE u.status = 1 AND p.nid = %d AND p.level = 2', $node->project_issue['pid']); + + // Check which users subscribed to the issue via Flag. + if ($flag_integration) { + // Retrieve all users who flagged the issue. + $flag_contents = flag_get_content_flags('node', $node->nid, variable_get('project_issue_subscription_flag', 0)); + + // Now use the list of users that flagged the issue to retrieve the list of + // users who are subscribed to flagged issues of the project. For example, a + // user who globally subscribed to no issues should not get an e-mail + // notification after flagging the issue. That should only happen when the + // user subscribed to flagged issues for the project. + if (!empty($flag_contents)) { + $flags_uids = array_keys($flag_contents); + $placeholders = implode(',', array_fill(0, count($flags_uids), '%d')); + $args = $flags_uids; + + // Check which users flagged the issue and globally subscribed to flagged + // issues (across projects). + $result = db_query("SELECT pisu.uid, u.name, u.mail + FROM {project_issue_subscriptions_user} pisu + INNER JOIN {users} u ON pisu.uid = u.uid + WHERE u.status = 1 AND pisu.uid IN ($placeholders) AND pisu.level = " . PROJECT_ISSUE_SUBSCRIPTIONS_FLAGGED, $args); + while ($account = db_fetch_object($result)) { + $accounts_flagged_issues[$account->uid] = $account; + } + + // Check which users flagged the issue and subscribed to flagged issues of + // the project. + array_unshift($args, $node->project_issue['pid']); + $result = db_query("SELECT pisp.uid, u.name, u.mail + FROM {project_issue_subscriptions_project} pisp + INNER JOIN {users} u ON pisp.uid = u.uid + WHERE u.status = 1 AND pisp.nid = %d AND pisp.uid IN ($placeholders) AND pisp.level = " . PROJECT_ISSUE_SUBSCRIPTIONS_FLAGGED, $args); + while ($account = db_fetch_object($result)) { + $accounts_flagged_issues[$account->uid] = $account; + } + } } + // Lastly, join the lists of users being + // - globally subscribed to all issues + // - globally subscribed to own issues (without Flag integration) + // - globally subscribed to flagged issues + // - subscribed to all issues of the project + // - subscribed to own issues of the project (without Flag integration) + // - subscribed to flagged issues of the project + $recipients = $accounts_all_issues + $accounts_flagged_issues; + // To save workload, check here if either the anonymous role or the // authenticated role has the 'view uploaded files' permission, since // we only need to process each user's file access permission if this @@ -289,7 +375,7 @@ function project_issue_mail_notify($nid) { // some punctuation) are used. See example in Appendix A.1.2. $from = '"' . mime_header_encode($sender->name) . "\" <$sender->mail>"; - while ($recipient = db_fetch_object($result)) { + foreach ($recipients as $recipient) { // To save work, only go through a user_load if we need it. if ($check_file_perms || $check_node_access) { $account = user_load(array('uid' => $recipient->uid)); diff --git a/includes/project_node.inc b/includes/project_node.inc index ce6c661..f62e18a 100644 --- a/includes/project_node.inc +++ b/includes/project_node.inc @@ -65,6 +65,6 @@ function project_issue_project_delete($node) { node_delete($issue->nid); } db_query('DELETE FROM {project_issue_projects} WHERE nid = %d', $node->nid); - db_query('DELETE FROM {project_subscriptions} WHERE nid = %d', $node->nid); + db_query('DELETE FROM {project_issue_subscriptions_project} WHERE nid = %d', $node->nid); } diff --git a/includes/subscribe.inc b/includes/subscribe.inc index 703114b..a4324a9 100644 --- a/includes/subscribe.inc +++ b/includes/subscribe.inc @@ -1,172 +1,182 @@ t('None'), + PROJECT_ISSUE_SUBSCRIPTIONS_FLAGGED => t('Subscribed issues'), + PROJECT_ISSUE_SUBSCRIPTIONS_ALL => t('All issues'), + ); +} - if (!valid_email_address($user->mail)) { - drupal_set_message(t('You need to provide a valid e-mail address to subscribe to issue e-mails. Please edit your user information.'), 'error'); - drupal_goto('user/'. $user->uid .'/edit'); - } +/** + * Form constructor for global user project issue subscriptions. + */ +function project_issue_subscriptions_user_form(&$form_state, $account) { + // Global subscription level. + project_issue_subscriptions_user_settings_load($account); - $levels = array(0 => t('None'), 1 => t('Own issues'), 2 => t('All issues')); + $form['account'] = array( + '#type' => 'value', + '#value' => $account, + ); + $form['#tree'] = TRUE; - if ($project_nid) { - if (!is_numeric($project_nid)) { - $project_nid = db_result(db_query(db_rewrite_sql("SELECT p.nid FROM {project_projects} p WHERE p.uri = '%s'", 'p'), $project_nid)); - } - if (!$project_nid) { - return drupal_not_found(); - } + $form['project_issue_subscriptions'] = array( + '#type' => 'fieldset', + '#title' => t('Issue subscriptions'), + '#collapsible' => TRUE, + ); - $project = node_load($project_nid); - project_project_set_breadcrumb($project, TRUE); + $form['project_issue_subscriptions']['level'] = array( + '#type' => 'radios', + '#title' => t('Global project issue subscription level'), + '#options' => _project_issue_subscription_levels(), + '#default_value' => $account->project_issue_subscriptions['level'], + ); - $level = db_result(db_query('SELECT level FROM {project_subscriptions} WHERE nid = %d AND uid = %d', $project->nid, $user->uid)); - $form['single'] = array( - '#type' => 'value', - '#value' => $project->nid, - ); - $form['#project'] = array( - '#type' => 'value', - '#value' => $project, - ); - $form['subscribe'] = array( - '#type' => 'markup', - '#value' => '

'. t('Subscribe to receive e-mail notification when an issue for this project is updated.') .'

', + // Per-project subscription level (only enabled). + // We only allow to change (and remove) per-project subscriptions on this + // form. Users are able to subscribe to further projects by visiting the + // individual project pages. In terms of UX, that's preferred anyway, since + // a user normally wants to know and be sure what exactly she subscribes to. + $form['project_issue_subscriptions']['projects'] = array( + '#theme' => 'project_issue_subscriptions_projects_table', + '#header' => array(t('Project'), t('Subscription level')), + '#description' => t('All project subscription levels with the same or lower level as your global default level will be removed.'), + ); + $result = db_query(db_rewrite_sql("SELECT pisp.nid, n.title, pisp.level + FROM {project_issue_subscriptions_project} pisp + INNER JOIN {node} n ON n.nid = pisp.nid + WHERE n.type = 'project_project' AND n.status = 1 AND pisp.uid = %d ORDER BY n.title + ", 'n'), $account->uid); + while ($project = db_fetch_object($result)) { + $form['project_issue_subscriptions']['projects'][$project->nid]['title'] = array( + '#value' => l($project->title, "node/$project->nid"), ); - $form['options']['#tree'] = TRUE; - $form['options'][$project->nid] = array( - '#type' => 'radios', - '#title' => t('Subscribe to @project issues', array('@project' => $project->title)), - '#default_value' => isset($level) ? $level : 0, - '#options' => $levels, + $form['project_issue_subscriptions']['projects'][$project->nid]['level'] = array( + '#type' => 'select', + '#options' => $form['project_issue_subscriptions']['level']['#options'], ); - } - else { - $form['buttons']['all'] = array( - '#type' => 'markup', - '#value' => t('All projects'), - ); - foreach ($levels as $key => $level) { - $form['buttons'][$level] = array( - '#type' => 'submit', - '#name' => 'all', - '#value' => $level, - ); - } - $nids = array(); - - $result = db_query(db_rewrite_sql("SELECT s.nid, n.title, s.level, p.uri FROM {project_subscriptions} s INNER JOIN {node} n ON n.nid = s.nid INNER JOIN {project_projects} p ON n.nid = p.nid WHERE n.type = 'project_project' AND n.status = 1 AND s.uid = %d ORDER BY n.title", 's'), $user->uid); - while ($project = db_fetch_object($result)) { - $form['project'][$project->nid]['title'] = array( - '#value' => l($project->title, "node/$project->nid"), - ); - foreach ($levels as $key => $level) { - if ($project->level == $key) { - $status[$project->nid] = $key; - } - } - $nids[] = $project->nid; - } - - if (empty($nids)) { - $placeholders = ''; - } - else { - $placeholders = " AND n.nid NOT IN (". implode(',', array_fill(0, count($nids), '%d')) .")"; - } - - $result = db_query(db_rewrite_sql("SELECT n.nid, n.title, p.uri FROM {node} n INNER JOIN {project_projects} p ON n.nid = p.nid WHERE n.type = 'project_project' AND n.status = 1". ($nids ? $placeholders : "") ." ORDER BY n.title"), $nids); - while ($project = db_fetch_object($result)) { - $form['project'][$project->nid]['title'] = array( - '#value' => l($project->title, "node/$project->nid"), - ); - $nids[] = $project->nid; - } - - foreach ($nids as $nid) { - $form['options']['#tree'] = TRUE; - $form['options'][$nid] = array( - '#type' => 'radios', - '#default_value' => isset($status[$nid]) ? $status[$nid] : 0, - '#options' => $levels, - ); - } - } - $form['submit'] = array( + $form['actions']['submit'] = array( '#type' => 'submit', - '#value' => t('Subscribe'), + '#value' => t('Save'), + '#weight' => 100, ); return $form; } -function theme_project_issue_subscribe($form) { - global $user; - - $output = ''; - - if (empty($form['#project'])) { - $output .= project_issue_query_result_links(); - } - else { - $project = $form['#project']['#value']; - $output .= project_issue_query_result_links($project->project['uri']); +/** + * Form submission handler for project_issue_user_subscribe_form(). + */ +function project_issue_subscriptions_user_form_submit($form, &$form_state) { + // Update the global issue subscription settings. + $account = $form_state['values']['account']; + $account->project_issue_subscriptions = $form_state['values']['project_issue_subscriptions']; + project_issue_subscriptions_user_settings_save($account); + + // Delete the existing per-project settings. + db_query("DELETE FROM {project_issue_subscriptions_project} WHERE uid = %d", array($account->uid)); + + // Insert the new per-project settings. + foreach ($form_state['values']['project_issue_subscriptions']['projects'] as $nid => $level) { + // Skip all per-project settings having the same or a lower level than the + // global default. + if ($level > $form_state['values']['project_issue_subscriptions']['level']) { + db_query("INSERT INTO {project_issue_subscriptions_project} (uid, nid, level) VALUES (%d, %d, %d)", array($account->uid, $nid, $level)); + } } - if (!isset($form['single'])) { - $levels = array(0 => t('None'), 1 => t('Own issues'), 2 => t('All issues')); - $headers = array_merge(array(t('Project')), $levels); + drupal_set_message(t('Your subscription settings have been updated.')); +} +/** + * Returns HTML for per-project subscription levels table in project_issue_user_subscribe_form(). + */ +function theme_project_issue_subscriptions_projects_table($element) { + $output = ''; + $rows = array(); + foreach (element_children($element) as $nid) { $row = array(); - foreach (element_children($form['buttons']) as $key) { - $row[] = drupal_render($form['buttons'][$key]); - } - $rows = array($row); - - foreach (element_children($form['project']) as $key) { - $row = array(drupal_render($form['project'][$key]['title'])); - foreach ($levels as $level => $name) { - $row[] = drupal_render($form['options'][$key][$level]); - } - $rows[] = $row; - } - $output .= theme('table', $headers, $rows); + $row[] = drupal_render($element[$nid]['title']); + $row[] = drupal_render($element[$nid]['level']); + $rows[] = array(); + } + if (!empty($rows)) { + $output .= theme('table', $element['#header'], $rows); + $output .= check_plain($element['#description']); } - $output .= drupal_render($form); + $output .= drupal_render($element); return $output; } -function project_issue_subscribe_submit($form, &$form_state) { - +/** + * Form constructor for per-project issue subscription. + */ +function project_issue_subscriptions_project_form($form_state, $project_nid) { global $user; - $all = $form_state['clicked_button']['#value']; - $levels = array(0 => t('None'), 1 => t('Own issues'), 2 => t('All issues')); + // @todo Isn't this globally enforced elsewhere...? + if (!valid_email_address($user->mail)) { + drupal_set_message(t('You need to provide a valid e-mail address to subscribe to issue e-mails. Please edit your user information.'), 'error'); + drupal_goto('user/'. $user->uid .'/edit'); + } - // Remove previous subscriptions for user. - if (isset($form_state['values']['single'])) { - db_query('DELETE FROM {project_subscriptions} WHERE nid = %d AND uid = %d', $form_state['values']['single'], $user->uid); - } - else { - db_query('DELETE FROM {project_subscriptions} WHERE uid = %d', $user->uid); - } + if (!is_numeric($project_nid)) { + $project_nid = project_get_nid_from_uri($project_nid); + } + if (!$project_nid || !($project = node_load($project_nid))) { + return drupal_not_found(); + } - $_level = array_search($all, $levels); + project_project_set_breadcrumb($project, TRUE); + drupal_set_title(t('Subscribe to @project issues', array('@project' => $project->title))); - foreach ($form_state['values']['options'] as $nid => $level) { - if ($_level !== 0 && $level !== 0) { - db_query('INSERT INTO {project_subscriptions} (nid, uid, level) VALUES (%d, %d, %d)', $nid, $user->uid, $_level ? $_level : $level); - } - } - drupal_set_message(t('Subscription settings saved.')); + $form['nid'] = array( + '#type' => 'value', + '#value' => $project->nid, + ); + $form['uid'] = array( + '#type' => 'value', + '#value' => $user->uid, + ); - if (isset($form['single'])) { - $form_state['redirect'] = 'project/issues/subscribe-mail/'. $form['#project']['#value']->project['uri']; - } - else { - $form_state['redirect'] = 'project/issues/subscribe-mail'; - } + $level = db_result(db_query('SELECT level FROM {project_issue_subscriptions_project} WHERE nid = %d AND uid = %d', $project->nid, $user->uid)); + // Default to None. + if (!$level) { + $level = PROJECT_ISSUE_SUBSCRIPTIONS_NONE; + } + $form['level'] = array( + '#type' => 'radios', + '#title' => t('Subscription level'), + '#options' => _project_issue_subscription_levels(), + '#default_value' => $level, + '#description' => t('Receive an e-mail notification when an issue for this project is updated.'), + ); + + $form['actions']['submit'] = array( + '#type' => 'submit', + '#value' => t('Subscribe'), + ); + return $form; +} + +/** + * Form submission handler for project_issue_user_subscribe_form(). + */ +function project_issue_subscriptions_project_form_submit($form, &$form_state) { + // Delete the existing per-project setting. + db_query("DELETE FROM {project_issue_subscriptions_project} WHERE nid = %d AND uid = %d", array($form_state['values']['nid'], $form_state['values']['uid'])); + + // Insert the new per-project setting. + if ($form_state['values']['level'] > PROJECT_ISSUE_SUBSCRIPTIONS_NONE) { + db_query("INSERT INTO {project_issue_subscriptions_project} (nid, uid, level) VALUES (%d, %d, %d)", array($form_state['values']['nid'], $form_state['values']['uid'], $form_state['values']['level'])); + } + + drupal_set_message(t('Your subscription setting has been updated.')); } diff --git a/project_issue.info b/project_issue.info index 2225d1a..a70606e 100644 --- a/project_issue.info +++ b/project_issue.info @@ -1,9 +1,10 @@ name = Project issue tracking description = Provides issue tracking for the project.module. +package = Project +core = 6.x dependencies[] = project dependencies[] = views dependencies[] = comment dependencies[] = comment_upload dependencies[] = upload -package = Project -core = 6.x +recommends[] = flag diff --git a/project_issue.install b/project_issue.install index 1c24aff..1a3ff48 100644 --- a/project_issue.install +++ b/project_issue.install @@ -282,7 +282,29 @@ function project_issue_schema() { 'primary key' => array('priority'), ); - $schema['project_subscriptions'] = array( + $schema['project_issue_subscriptions_user'] = array( + 'description' => 'Stores global issue subscriptions per user.', + 'fields' => array( + 'uid' => array( + 'description' => 'The {users}.uid for this subscriber.', + 'type' => 'int', + 'unsigned' => TRUE, + 'not null' => TRUE, + 'default' => 0, + ), + 'level' => array( + 'description' => 'The global subscription setting level. 0 = None, 1 = Flagged, 2 = All.', + 'type' => 'int', + 'size' => 'tiny', + 'unsigned' => TRUE, + 'not null' => TRUE, + 'default' => 0, + ), + ), + 'primary key' => array('uid', 'level'), + ); + + $schema['project_issue_subscriptions_project'] = array( 'description' => 'Table keeping track of per-user project_issue subscriptions.', 'fields' => array( 'nid' => array( @@ -626,3 +648,44 @@ function project_issue_update_6006() { return $ret; } + +/** + * Revamp project issue subscriptions for Flag integration. + */ +function project_issue_update_6007() { + $ret = array(); + + // Delete obsolete 'project_issue_global_subscribe_page' variable. + variable_del('project_issue_global_subscribe_page'); + + // Rename {project_subscriptions} to {project_issue_subscriptions_project}. + db_rename_table($ret, 'project_subscriptions', 'project_issue_subscriptions_project'); + + // Ensure that existing project subscriptions are clean. + $ret[] = update_sql("DELETE FROM {project_issue_subscriptions_project} WHERE level = 0"); + + // Create new global issue subscription setting table. + db_create_table($ret, 'project_issue_subscriptions_user', array( + 'description' => 'Stores global issue subscriptions per user.', + 'fields' => array( + 'uid' => array( + 'description' => 'The {users}.uid for this subscriber.', + 'type' => 'int', + 'unsigned' => TRUE, + 'not null' => TRUE, + 'default' => 0, + ), + 'level' => array( + 'description' => 'The global subscription setting level. 0 = None, 1 = Flagged, 2 = All.', + 'type' => 'int', + 'size' => 'tiny', + 'unsigned' => TRUE, + 'not null' => TRUE, + 'default' => 0, + ), + ), + 'primary key' => array('uid', 'level'), + )); + + return $ret; +} diff --git a/project_issue.module b/project_issue.module index 4345d1d..1d4f250 100644 --- a/project_issue.module +++ b/project_issue.module @@ -11,6 +11,21 @@ define('PROJECT_ISSUE_STATE_FIXED', 2); define('PROJECT_ISSUE_STATE_CLOSED', 7); /** + * Project issue subscriptions level: Not subscribed. + */ +define('PROJECT_ISSUE_SUBSCRIPTIONS_NONE', 0); + +/** + * Project issue subscriptions level: Own/flagged issues. + */ +define('PROJECT_ISSUE_SUBSCRIPTIONS_FLAGGED', 1); + +/** + * Project issue subscriptions level: All issues. + */ +define('PROJECT_ISSUE_SUBSCRIPTIONS_ALL', 2); + +/** * Implementation of hook_init(). */ function project_issue_init() { @@ -61,20 +76,27 @@ function project_issue_menu() { 'type' => MENU_NORMAL_ITEM, 'file' => 'includes/statistics.inc', ); - $path = 'project/issues/subscribe-mail'; - if (!variable_get('project_issue_global_subscribe_page', TRUE)) { - // If we don't want the global subscribe page, require an argument. - $path .= '/%'; - } - $items[$path] = array( + + // Project issue subscriptions. + $items['project/issues/subscribe-mail/%'] = array( 'title' => 'Subscribe', 'page callback' => 'drupal_get_form', - 'page arguments' => array('project_issue_subscribe', 3), + 'page arguments' => array('project_issue_subscriptions_project_form', 3), 'access callback' => 'project_issue_menu_access', 'access arguments' => array('auth'), 'type' => MENU_NORMAL_ITEM, 'file' => 'includes/subscribe.inc', ); + $items['user/%user/subscriptions'] = array( + 'title' => 'Subscriptions', + 'page callback' => 'drupal_get_form', + 'page arguments' => array('project_issue_subscriptions_user_form', 1), + 'access callback' => 'project_issue_menu_access', + 'access arguments' => array('auth'), + 'file' => 'includes/subscribe.inc', + ); + + // Search. if (module_exists('search')) { $items['search/issues'] = array( 'title' => 'Issues', @@ -297,10 +319,10 @@ function project_issue_theme() { 'change' => NULL, ), ), - 'project_issue_subscribe' => array( - 'file' => 'issue.inc', + 'project_issue_subscriptions_projects_table' => array( + 'file' => 'includes/subscribe.inc', 'arguments' => array( - 'form' => NULL, + 'element' => NULL, ), ), 'project_issue_summary' => array( @@ -866,6 +888,73 @@ function _project_issue_followup_get_user() { } /** + * Loads user account settings for project issue subscriptions. + * + * @param $account + * A user account object to attach project issue subscription settings to. + * Required properties: + * - uid: The ID of the user account. + * Attached properties: + * - project_issue_subscriptions: An associative array containing: + * - level: An integer denoting the user's global issue subscription level: + * - PROJECT_ISSUE_SUBSCRIPTIONS_NONE + * - PROJECT_ISSUE_SUBSCRIPTIONS_FLAGGED + * - PROJECT_ISSUE_SUBSCRIPTIONS_ALL + */ +function project_issue_subscriptions_user_settings_load($account) { + // Setup defaults. + $defaults = array( + 'level' => PROJECT_ISSUE_SUBSCRIPTIONS_NONE, + ); + + // For existing accounts, load account settings. + if (!empty($account->uid)) { + $settings = db_fetch_array(db_query("SELECT * FROM {project_issue_subscriptions_user} WHERE uid = %d", array($account->uid))); + $settings = ($settings ? $settings : array()); + $account->project_issue_subscriptions = array_merge($defaults, $settings); + } + // Otherwise, attach default settings. + else { + $account->project_issue_subscriptions = $defaults; + } +} + +/** + * Saves user account settings for project issue subscriptions. + * + * @param $account + * A user account object containing at least the properties: + * - uid: The ID of the user account. + * - project_issue_subscriptions: An associative array containing: + * - level: An integer denoting the user's global issue subscription level. + * + * @see project_issue_subscriptions_user_settings_load() + */ +function project_issue_subscriptions_user_settings_save($account) { + db_query("UPDATE {project_issue_subscriptions_user} SET level = %d WHERE uid = %d", array( + $account->project_issue_subscriptions['level'], + $account->uid, + )); + if (!db_affected_rows()) { + db_query("INSERT INTO {project_issue_subscriptions_user} (uid, level) VALUES (%d, %d)", array( + $account->uid, + $account->project_issue_subscriptions['level'], + )); + } +} + +/** + * Implements hook_user(). + */ +function project_issue_user($op, $edit, $account) { + if ($op == 'delete') { + db_query("DELETE FROM {project_issue_subscriptions_user} WHERE uid = %d", $account->uid); + db_query("DELETE FROM {project_issue_subscriptions_project} WHERE uid = %d", $account->uid); + db_query("DELETE FROM {project_issue_project_maintainer} WHERE uid = %d", $account->uid); + } +} + +/** * hook_nodeapi() implementation. This just decides what type of node * is being passed, and calls the appropriate type-specific hook. * @@ -1834,13 +1923,6 @@ function project_issue_query_result_links($project_arg = NULL) { 'attributes' => array('title' => t('See statistics about issues.')), ); } - if (!empty($user->uid) && variable_get('project_issue_global_subscribe_page', TRUE)) { - $links['subscribe'] = array( - 'title' => t('Subscribe'), - 'href' => "project/issues/subscribe-mail", - 'attributes' => array('title' => t('Receive e-mail updates about issues.')), - ); - } } else { // We know the project, make project-specific links.