? .svn ? images/.svn ? includes/.svn ? modules/.svn ? modules/og_access/.svn ? modules/og_access/translations/.svn ? modules/og_actions/.svn ? modules/og_actions/translations/.svn ? modules/og_notifications/.svn ? modules/og_notifications/translations/.svn ? modules/og_views/.svn ? modules/og_views/includes/.svn ? modules/og_views/translations/.svn ? modules/og_views/views/.svn ? tests/.svn ? theme/.svn ? translations/.svn Index: og.install =================================================================== RCS file: /cvs/drupal-contrib/contributions/modules/og/Attic/og.install,v retrieving revision 1.71.4.5 diff -u -p -w -r1.71.4.5 og.install --- og.install 15 May 2009 17:28:02 -0000 1.71.4.5 +++ og.install 12 Aug 2009 20:21:18 -0000 @@ -68,6 +68,13 @@ function og_schema() { 'not null' => TRUE, 'default' => 0, ), + 'og_private_preview'=> array( + 'description' => 'Give invited users preview access to an otherwise private group?', + 'type' => 'int', + 'size' => 'tiny', + 'not null' => TRUE, + 'default' => 0, + ), ), 'primary key' => array('nid'), ); @@ -143,6 +150,24 @@ function og_schema() { ), 'primary key' => array('nid', 'group_nid'), ); + $schema['og_invite'] = array( + 'description' => 'Pending OG Invitations', + 'fields' => array( + 'mail' => array( + 'type' => 'varchar', + 'length' => 64, + 'not null' => TRUE, + 'description' => "Invited email address.", + ), + 'group_nid' => array( + 'description' => "The group's {node}.nid.", + 'type' => 'int', + 'size' => 'normal', + 'not null' => TRUE, + ), + ), + 'primary key' => array('mail', 'group_nid'), + ); return $schema; } @@ -432,6 +457,48 @@ function og_update_6203() { return $ret; } +// Add og_invite table to store emails for inviting non-users to groups. +function og_update_6204() { + $ret = array(); + $schema['og_invite'] = array( + 'description' => 'Pending OG Invitations', + 'fields' => array( + 'mail' => array( + 'type' => 'varchar', + 'length' => 64, + 'not null' => TRUE, + 'description' => "Invited email address.", + ), + 'group_nid' => array( + 'description' => "The group's {node}.nid.", + 'type' => 'int', + 'size' => 'normal', + 'not null' => TRUE, + ), + ), + 'primary key' => array('mail', 'group_nid'), + ); + db_create_table($ret, 'og_invite', $schema['og_invite']); + return $ret; +} + +// Add private_preview field to allow invited users to preview a private group before joining +function og_update_6205() { + $ret = array(); + + $schema = array( + 'description' => 'Give invited users preview access to an otherwise private group?', + 'type' => 'int', + 'size' => 'tiny', + 'not null' => TRUE, + 'default' => 0, + ); + + + db_add_field($ret, 'og', 'og_private_preview', $schema); + return $ret; +} + // end updates // function og_uninstall() { Index: og.module =================================================================== RCS file: /cvs/drupal-contrib/contributions/modules/og/Attic/og.module,v retrieving revision 1.628.4.22 diff -u -p -w -r1.628.4.22 og.module --- og.module 10 Aug 2009 20:39:11 -0000 1.628.4.22 +++ og.module 12 Aug 2009 20:21:18 -0000 @@ -45,8 +45,8 @@ function og_menu() { 'file' => 'og.pages.inc', 'page callback' => 'og_subscribe', 'page arguments' => array(2), - 'access callback' => 'node_access', - 'access arguments' => array('view', 2), + 'access callback' => 'og_menu_access_subscribe', + 'access arguments' => array(2), 'title' => 'Join group' ); @@ -258,6 +258,29 @@ function og_menu_access_invite($node) { return og_is_group_member($node) && ($node->og_selective < OG_INVITE_ONLY || og_is_group_admin($node)); } +function og_menu_access_subscribe($group_node) { + if($group_node->og_private) { + if(og_is_invited($group_node)) return TRUE; + else return FALSE; + } + else return node_access('view', $group_node); +} + +function og_is_invited($group_node) { + global $user; + + if (!isset($user->og_groups)) { + $user = user_load(array('uid' => $user->uid)); + } + + $sql = "SELECT COUNT(*) FROM {og_invite} WHERE group_nid = %d and mail = '%s'"; + $query = db_query($sql, $group_node->nid, $user->uid); + $cnt = db_result($query); + + if($cnt == 0) return FALSE; + else return TRUE; +} + /** * Check a user's membership in a group. * @@ -727,8 +750,12 @@ function og_subscribe_user($gid, $accoun else { // Moderated groups must approve all members (selective=1). $node = node_load($gid); + // this switch statement may take some careful reading switch ($node->og_selective) { case OG_MODERATED: + $sql = "SELECT COUNT(*) FROM {og_invite} WHERE mail = '%d' AND group_nid = %d"; + $cnt = db_result(db_query($sql, $account->uid, $node->nid)); + if (!$cnt) { $admins = array(); og_save_subscription($gid, $account->uid, array('is_active' => 0)); $sql = og_list_users_sql(1, 1, NULL); @@ -757,15 +784,16 @@ function og_subscribe_user($gid, $accoun } $return_value = array('type' => 'approval', 'message' => t('Membership request to the %group group awaits approval by an administrator.', array('%group' => $node->title))); - - break; - case OG_OPEN: - og_save_subscription($gid, $account->uid, array('is_active' => 1)); - $return_value = array('type' => 'subscribed', - 'message' => t('You are now a member of %group.', array('%group' => $node->title))); break; - case OG_CLOSED: + } case OG_INVITE_ONLY: + if (!$cnt) { + $sql = "SELECT COUNT(*) FROM {og_invite} WHERE mail = '%d' AND group_nid = %d"; + $cnt = db_result(db_query($sql, $account->uid, $node->nid)); + } + case OG_CLOSED: + if (!$cnt) { + // no invitations // admins can add members to these groups, but others can't. if (og_is_group_admin($node)) { og_save_subscription($gid, $account->uid, array('is_active' => 1)); @@ -774,6 +802,17 @@ function og_subscribe_user($gid, $accoun $return_value = array('type' => 'rejected', 'message' => t('Membership request to the %group group was rejected, only group administrators can add users to this group.', array('%group' => $node->title))); } + break; + } + $sql = "DELETE FROM {og_invite} WHERE mail = '%d'"; + $result = db_query($sql, $account->uid); + // fall through if we are already invited + case OG_OPEN: + og_save_subscription($gid, $account->uid, array('is_active' => 1)); + $return_value = array('type' => 'subscribed', + 'message' => t('You are now a member of the %group.', array('%group' => $node->title))); + break; + } } @@ -1787,6 +1826,14 @@ function _og_mail_text($messageid, $vari return t("Invitation to join the group '@group' at @site", $variables, $langcode); case 'og_invite_user_body': return t("Hi. I'm a member of '@group' and I welcome you to join this group as well. Please see the link and message below.\n\n@group\n@description\nJoin: !group_url\n@body", $variables, $langcode); + case 'og_invite_nonuser_subject': + return t("Invitation to join the group '@group' at @site", $variables, $langcode); + case 'og_invite_nonuser_body': + return t("Hi. I'm a member of '@group' and I welcome you to join this group as well. Please see the link and message below.\n\n@group\n@description\nJoin: !group_url\n@body", $variables, $langcode); + case 'og_invite_user_privatepreview_subject': + return t("Invitation to join the group '@group' at @site", $variables, $langcode); + case 'og_invite_user_privatepreview_body': + return t("Hi. I'm a member of '@group' and I welcome you to join this group as well. Please see the link and message below.\n\n@group\n@description\nJoin: !group_url\n@body", $variables, $langcode); case 'og_request_user_subject': return t("Membership request for '@group' from '@username'", $variables, $langcode); case 'og_request_user_body': @@ -1850,6 +1897,7 @@ function og_user($op, $edit, &$account, ); return $form; } + break; case 'insert': if (isset($edit['og_register'])) { foreach (array_keys(array_filter($edit['og_register'])) as $gid) { @@ -1859,6 +1907,16 @@ function og_user($op, $edit, &$account, } } } + $sql = "SELECT group_nid FROM {og_invite} WHERE mail = '%s'"; + $result = db_query($sql, $account->mail); + while ($group = db_fetch_array($result)) { + $gid = $group['group_nid']; + $groupnode = node_load($gid); + og_save_subscription($gid, $account->uid, array('is_active' => 1)); + drupal_set_message(t('You are now a member of the %group.', array('%group' => $groupnode->title))); + } + $sql = "DELETE FROM {og_invite} WHERE mail = '%s'"; + $result = db_query($sql, $account->mail); break; case 'delete': $sql = 'DELETE FROM {og_uid} WHERE uid=%d'; @@ -2104,7 +2162,7 @@ function og_block_details() { if ($subscription == 'active' || user_access('administer nodes')) { $links = module_invoke_all('og_create_links', $node); // We want to open this up for OG_INVITE_ONLY but we need to handle invitation workflow much better. See http://drupal.org/node/170332 - if ($node->og_selective < OG_INVITE_ONLY) { + if ($node->og_selective < OG_INVITE_ONLY || og_is_group_admin($node)) { $links['invite'] = l(t('Invite friend'), "og/invite/$node->nid"); } $links['subscribers'] = $txt; @@ -2180,11 +2238,14 @@ function og_block_details() { } function og_subscribe_link($node) { - if ($node->og_selective == OG_MODERATED) { - $txt = t('Request membership'); - } - elseif ($node->og_selective == OG_OPEN) { + global $user; + $sql = "SELECT COUNT(*) FROM {og_invite} WHERE mail = '%d' AND group_nid = %d"; + $cnt = db_result(db_query($sql, $user->uid, $node->nid)); + if ($cnt || $node->og_selective == OG_OPEN) { + // already invited or open group $txt = t('Join'); + } elseif ($node->og_selective == OG_MODERATED) { + $txt = t('Request membership'); } if(isset($txt)) return l($txt, "og/subscribe/$node->nid", array('attributes' => array('rel' => 'nofollow'), 'query' => drupal_get_destination())); Index: og.pages.inc =================================================================== RCS file: /cvs/drupal-contrib/contributions/modules/og/Attic/og.pages.inc,v retrieving revision 1.1.2.3 diff -u -p -w -r1.1.2.3 og.pages.inc --- og.pages.inc 8 Aug 2009 17:37:37 -0000 1.1.2.3 +++ og.pages.inc 12 Aug 2009 20:21:19 -0000 @@ -214,6 +214,9 @@ function og_invite_form_validate($form, elseif (in_array($user->mail, $emails)) { form_set_error('mails', t('You may not invite yourself - @self.', array('@self' => $user->mail))); } + elseif (in_array($user->name, $emails)) { + form_set_error('mails', t('You may not invite yourself - @self.', array('@self' => $user->name))); + } else { $valid_emails = array(); $bad = array(); @@ -253,16 +256,79 @@ function og_invite_form_submit($form, &$ '@group' => $node->title, '@description' => $node->og_description, '@site' => variable_get('site_name', 'drupal'), - '!group_url' => url("og/subscribe/$node->nid", array('absolute' => TRUE)), '@body' => $form_state['values']['pmessage'], ); global $user; $from = $user->mail; + $sent = 0; foreach ($emails as $mail) { + $variables['!group_url'] = url("og/subscribe/$node->nid", array('absolute' => TRUE)); + if($node->og_private and $node->og_private_preview) + $variables['!preview_url'] = url("node/$node->nid", array('absolute' => TRUE)); + + $account = user_load(array('mail' => $mail)); + $wasinactive = FALSE; + if ($account) { + $sql = "SELECT is_active,uid FROM {og_uid} WHERE uid = %d AND nid = %d"; + $oguid = db_fetch_array(db_query($sql, $account->uid, $node->nid)); + if ($oguid['uid']) { + // user already active/pending + if($oguid['is_active']) { + drupal_set_message(t("@username is already a member of the group", array('@username' => $account->name))); + continue; + } else { + $wasinactive = TRUE; + drupal_set_message(t('@username already requested group membership', array('@username' => $account->name))); + } + } + } + + if (og_is_group_admin($node)) { + if ($account) { + if ($wasinactive) { + // user wanted to be a member, we want them to be a member--oh happy day + db_query("UPDATE {og_uid} SET is_active = 1 WHERE uid = %d and nid = %d", $account->uid, $node->nid); + drupal_set_message(t('@username has now been approved as a member', array('@username' => $account->name))); + } else { + $sql = "SELECT COUNT(*) FROM {og_invite} WHERE mail = '%d' AND group_nid = %d"; + $cnt = db_result(db_query($sql, $account->uid, $node->nid)); + if ($cnt) { + drupal_set_message(t('@username was already on the invitation list for this group, but will be re-invited.', array('@username' => $account->name))); + } + else { + $record = array('mail' => $account->uid, 'group_nid' => $node->nid); + $result = drupal_write_record('og_invite', $record); + } + } + } else { + $sql = "SELECT COUNT(*) FROM {og_invite} WHERE mail = '%s' AND group_nid = %d"; + $cnt = db_result(db_query($sql, $mail, $node->nid)); + if ($cnt) { + drupal_set_message(t('@email was already on the invitation list for this group, but will be re-invited.', array('@email' => $mail))); + } + else { + $record = array('mail' => $mail, 'group_nid' => $node->nid); + $result = drupal_write_record('og_invite', $record); + } + $variables['!group_url'] = url('user/register', array('absolute' => TRUE)); + } + } + // could still be here if user in there but is_active = 0: don't send another invitation if they don't need one + if ($wasinactive) { + continue; + } + $sent ++; + + // Send different emails based on whether the invitee has an account yet or not and whether the group is private w/preview enabled + if($account) { + if($node->og_private and $node->og_private_preview) drupal_mail('og', 'invite_user', $mail, $GLOBALS['language'], $variables, $from); + else drupal_mail('og', 'invite_user_privatepreview', $mail, $GLOBALS['language'], $variables, $from); + } + else drupal_mail('og', 'invite_nonuser', $mail, $GLOBALS['language'], $variables, $from); } - drupal_set_message(format_plural(count($emails), '1 invitation sent.', '@count invitations sent.')); + drupal_set_message(format_plural($sent, '1 invitation sent.', '@count invitations sent.')); } function og_subscribe($node, $uid = NULL) { @@ -286,7 +352,9 @@ function og_subscribe($node, $uid = NULL $account = user_load(array('uid' => $uid)); } - if ($node->og_selective >= OG_INVITE_ONLY || $node->status == 0 || !og_is_group_type($node->type)) { + $sql = "SELECT COUNT(*) FROM {og_invite} WHERE mail = '%d' AND group_nid = %d"; + $cnt = db_result(db_query($sql, $account->uid, $node->nid)); + if (($node->og_selective >= OG_INVITE_ONLY && !$cnt) || $node->og_selective >= OG_CLOSED || $node->status == 0 || !og_is_group_type($node->type)) { drupal_access_denied(); exit(); } @@ -312,7 +380,9 @@ function og_subscribe($node, $uid = NULL function og_confirm_subscribe($form_state, $gid, $node, $account) { $form['gid'] = array('#type' => 'value', '#value' => $gid); $form['account'] = array('#type' => 'value', '#value' => $account); - if ($node->og_selective == OG_MODERATED) { + $sql = "SELECT COUNT(*) FROM {og_invite} WHERE mail = '%d' AND group_nid = %d"; + $cnt = db_result(db_query($sql, $account->uid, $node->nid)); + if ($node->og_selective == OG_MODERATED && !$cnt) { $form['request'] = array( '#type' => 'textarea', '#title' => t('Additional details'), @@ -384,6 +454,7 @@ function og_add_users($form_state, $grou '#description' => t('Add one or more usernames in order to associate users with this group. Multiple usernames should be separated by a comma.'), '#element_validate' => array('og_add_users_og_names_validate'), ); + $form['og_names']['#description'] .= '
' . t('If you wish to use emails in addition to usernames, invite will accept a mix of both.', array( '@url' => url('og/invite/'. $group_node->nid))); $form['op'] = array('#type' => 'submit', '#value' => t('Add users')); $form['gid'] = array('#type' => 'value', '#value' => $group_node->nid); return $form; Index: includes/og.admin.inc =================================================================== RCS file: /cvs/drupal-contrib/contributions/modules/og/includes/Attic/og.admin.inc,v retrieving revision 1.15.4.2 diff -u -p -w -r1.15.4.2 og.admin.inc --- includes/og.admin.inc 22 Jun 2009 15:59:27 -0000 1.15.4.2 +++ includes/og.admin.inc 12 Aug 2009 20:21:19 -0000 @@ -156,9 +156,35 @@ function og_admin_settings() { '#type' => 'textarea', '#title' => t('Invite user notification body'), '#rows' => 10, - '#description' => t('The body of the message sent to users invited to join a group. Available variables: @group, @site, @description, !group_url, @body'), + '#description' => t('The body of the message sent to users invited to join a group. Available variables: @group, @site, @description, !group_url, !preview_url, @body'), '#default_value' => _og_mail_text('og_invite_user_body') ); + $form['og_settings']['notifications']['og_invite_nonuser_subject'] = array( + '#type' => 'textfield', + '#title' => t('Invite non-user notification subject'), + '#description' => t('The subject of the message sent to people without accounts invited to join a group. Available variables: @group, @site, @description, !group_url, @body'), + '#default_value' => _og_mail_text('og_invite_nonuser_subject') + ); + $form['og_settings']['notifications']['og_invite_nonuser_body'] = array( + '#type' => 'textarea', + '#title' => t('Invite non-user notification body'), + '#rows' => 10, + '#description' => t('The body of the message sent to people without accounts invited to join a group. Available variables: @group, @site, @description, !group_url, !preview_url, @body'), + '#default_value' => _og_mail_text('og_invite_nonuser_body') + ); + $form['og_settings']['notifications']['og_invite_user_privatepreview_subject'] = array( + '#type' => 'textfield', + '#title' => t('Invite user notification subject (for private groups with private preview enabled)'), + '#description' => t('The subject of the message sent to users invited to join a private group with private preview enabled. Available variables: @group, @site, @description, !group_url, @body'), + '#default_value' => _og_mail_text('og_invite_nonuser_subject') + ); + $form['og_settings']['notifications']['og_invite_user_privatepreview_body'] = array( + '#type' => 'textarea', + '#title' => t('Invite user notification body (for private groups with private preview enabled)'), + '#rows' => 10, + '#description' => t('The body of the message sent to people without accounts invited to join a group. Available variables: @group, @site, @description, !group_url, !preview_url, @body'), + '#default_value' => _og_mail_text('og_invite_nonuser_body') + ); $form['og_settings']['notifications']['og_request_user_subject'] = array( '#type' => 'textfield', '#title' => t('Request user notification subject'), Index: modules/og_access/og_access.module =================================================================== RCS file: /cvs/drupal-contrib/contributions/modules/og/modules/og_access/Attic/og_access.module,v retrieving revision 1.32.4.2 diff -u -p -w -r1.32.4.2 og_access.module --- modules/og_access/og_access.module 8 Aug 2009 18:58:30 -0000 1.32.4.2 +++ modules/og_access/og_access.module 12 Aug 2009 20:21:19 -0000 @@ -106,6 +106,11 @@ function og_access_content_extra_fields( 'description' => t('Checkbox for visibility of group home page to non-members.'), 'weight' => 0, ); + $extra['og_private_preview'] = array( + 'label' => t('Private group preview'), + 'description' => t('If this box is checked, users invited to private groups will be able to view the group in order to decide whether or not they want to join.'), + 'weight' => 0, + ); } return $extra; } @@ -133,6 +138,14 @@ function og_access_alter_group_form(&$fo '#type' => 'value', '#value' => 1 ); + + $form['og_private_preview'] = array( + '#type' => 'checkbox', + '#title' => t('Private group preview'), + '#default_value' => isset($node->nid) ? $node->og_private_preview : 0, + '#weight' => module_exists('content') ? content_extra_field_weight($node->type, 'og_private_preview') : 0, + '#description' => t('If this box is checked, users invited to private groups will be able to view the group in order to decide whether or not they want to join.'), + ); break; case OG_PRIVATE_GROUPS_CHOOSE_TRUE : @@ -147,6 +160,14 @@ function og_access_alter_group_form(&$fo '#weight' => module_exists('content') ? content_extra_field_weight($node->type, 'og_private') : 0, '#description' => t('Should this group be visible only to its members? Disabled if the group is set to List in Directory or Membership requests: open.') ); + + $form['og_private_preview'] = array( + '#type' => 'checkbox', + '#title' => t('Private group preview'), + '#default_value' => isset($node->nid) ? $node->og_private_preview : 0, + '#weight' => module_exists('content') ? content_extra_field_weight($node->type, 'og_private_preview') : 0, + '#description' => t('If this box is checked, users invited to private groups will be able to view the group in order to decide whether or not they want to join.'), + ); break; } } @@ -254,6 +275,11 @@ function og_access_form_alter(&$form, &$ function og_access_node_grants($account, $op) { if ($op == 'view') { $grants['og_public'][] = 0; // everyone can see a public node + + $sql = "SELECT group_nid FROM og_invite WHERE mail='%s'"; + $result = db_query($sql, $account->uid); + while($gid = db_result($result)) + $grants['og_private_preview'][] = $gid; } // Subscribers get an admin or non-admin grant for each subscription @@ -298,7 +324,7 @@ function og_access_node_access_records($ ); } else { - // If the group private, let subscribers view the group homepage. + // If the group is private, let subscribers view the group homepage. $grants[] = array ( 'realm' => 'og_subscriber', 'gid' => $node->nid, @@ -308,6 +334,18 @@ function og_access_node_access_records($ 'priority' => 0, ); + if($node->og_private_preview) { + // If the private group allows previews for invited users, let those users view the group homepage as well. + $grants[] = array ( + 'realm' => 'og_private_preview', + 'gid' => $node->nid, + 'grant_view' => 1, + 'grant_update' => 0, + 'grant_delete' => 0, + 'priority' => 0, + ); + } + } } elseif (!empty($node->og_groups)) { Index: modules/og_actions/og_actions.module =================================================================== RCS file: /cvs/drupal-contrib/contributions/modules/og/modules/og_actions/Attic/og_actions.module,v retrieving revision 1.9.4.2 diff -u -p -w -r1.9.4.2 og_actions.module --- modules/og_actions/og_actions.module 9 Jun 2009 01:04:44 -0000 1.9.4.2 +++ modules/og_actions/og_actions.module 12 Aug 2009 20:21:19 -0000 @@ -33,6 +33,12 @@ function og_actions_action_info() { 'nodeapi' => array('insert', 'update'), ), ), + 'og_invite_user_action' => array( + 'type' => 'user', + 'description' => t('Invite user to the specified groups'), + 'configurable' => TRUE, + 'hooks' => array(), + ), 'og_subscribe_user_action' => array( 'type' => 'user', 'description' => t('Subscribe user to the specified groups'), @@ -274,6 +280,63 @@ function og_subscribe_user_action_submit } /** + * A configurable action to subscribe a user to specific groups. + */ +function og_invite_user_action($account, $context) { + if (isset($context['groups'])) { + require_once drupal_get_path('module', 'og') ."/og.pages.inc"; + foreach ($context['groups'] as $gid) { + $form_state = array('values' => array('mails' => $account->name, 'gid' => $gid, 'pmessage' => $context['pmessage'])); + drupal_execute('og_invite_form', $form_state, node_load($gid)); + } + watchdog('action', 'Invited user %name to groups %groups.', array('%name' => $account->name, '%groups' => implode(',', $context['groups']))); + } +} + +/** + * Configuration form for Invite User action. + */ +function og_invite_user_action_form($context) { + $form = array(); + + if (!isset($context['groups'])) { + $context['groups'] = array(); + } + + $groups = og_all_groups_options(); + if (count($groups)) { + $form['groups'] = array( + '#type' => 'select', + '#title' => t('Groups'), + '#options' => $groups, + '#description' => t('Select the groups to which this user should be invited.'), + '#default_value' => $context['groups'], + '#required' => TRUE, + '#multiple' => TRUE, + ); + $form['pmessage'] = array( + '#type' => 'textarea', + '#title' => t('Personal message'), + '#description' => t('Optional. Enter a message which will become part of the invitation email.') + ); + } + else { + drupal_set_message(t('Please create a group first.', array('!url' => url('admin/content')))); + } + return $form; +} + +/** + * Submission handler for Invite User action configuration form. + */ +function og_invite_user_action_submit($form, &$form_state) { + return array( + 'groups' => $form_state['values']['groups'], + 'pmessage' => $form_state['values']['pmessage'], + ); +} + +/** * A configurable action to unsubscribe a user from specific groups. */ function og_unsubscribe_user_action($account, $context) {