Index: og.install =================================================================== RCS file: /cvs/drupal-contrib/contributions/modules/og/og.install,v retrieving revision 1.16 diff -u -F^f -r1.16 og.install --- og.install 1 Aug 2006 23:40:03 -0000 1.16 +++ og.install 22 Aug 2006 15:26:32 -0000 @@ -26,19 +26,23 @@ function og_install() { is_admin int(1) NOT NULL DEFAULT 0, uid int(11) NOT NULL, mail_type int(11) NULL, - created int(11) NULL DEFAULT 0, - changed int(11) NULL DEFAULT 0, + created int(11) NULL DEFAULT 0, + changed int(11) NULL DEFAULT 0, PRIMARY KEY (nid, uid) ) /*!40100 DEFAULT CHARACTER SET utf8 */;"); - - $sql = "ALTER TABLE {node_access} DROP PRIMARY KEY, ADD INDEX `nid_gid_realm` ( `nid` , `gid` , `realm`)"; - db_query($sql); - $sql = "ALTER TABLE {node_access} CHANGE grant_view grant_view int(11) unsigned NOT NULL default '0'"; - db_query($sql); + db_query("CREATE TABLE {og_ancestry} ( + nid int(11) NOT NULL, + group_nid int(11) NOT NULL, + is_public int(1) NOT NULL, + PRIMARY KEY (nid), + KEY (group_nid) + ) /*!40100 DEFAULT CHARACTER SET utf8 */;"); - $sql = "UPDATE {system} SET status = 1 WHERE name = 'og_basic'"; - db_query($sql); + // TODO: use enable_module() when that hits core + // $sql = "UPDATE {system} SET status = 1 WHERE name = 'og_basic'"; + // db_query($sql); + break; case 'pgsql': db_query("CREATE TABLE {og} ( @@ -66,22 +70,19 @@ function og_install() { changed numeric(11) NULL DEFAULT 0, PRIMARY KEY (nid, uid) );"); - - $sql = "ALTER TABLE {node_access} ". - "DROP CONSTRAINT {node_access}_pkey;"; - db_query($sql); - - $sql = "CREATE INDEX nid_gid_realm ON {node_access} (nid, gid, realm);"; - db_query($sql); - - $sql = "ALTER TABLE {node_access} ". - "ALTER COLUMN grant_view TYPE numeric(11), ". - "ALTER COLUMN grant_view SET NOT NULL, ". - "ALTER COLUMN grant_view SET DEFAULT '0';"; - db_query($sql); - - $sql = "UPDATE {system} SET status = 1 WHERE name = 'og_basic'"; - db_query($sql); + + db_query("CREATE TABLE {og_ancestry} ( + nid numeric(11) NOT NULL, + group_nid numeric(11) NOT NULL, + is_public numeric(1) NOT NULL, + PRIMARY KEY (nid), + ); + CREATE INDEX group_nid_idx ON group_nid (numeric); + "); + + // TODO. use enable_module() once that hits core + // $sql = "UPDATE {system} SET status = 1 WHERE name = 'og_basic'"; + // db_query($sql); break; } @@ -291,3 +292,48 @@ function og_update_11() { } return $ret ? $ret : array(); } + +// use the new na_arbitrator way of writing to node_access table +function og_update_12() { + switch ($GLOBALS['db_type']) { + case 'mysql': + case 'mysqli': + $ret[] = update_sql("CREATE TABLE {og_ancestry} ( + nid int(11) NOT NULL, + group_nid int(11) NOT NULL, + is_public int(1) NULL, + PRIMARY KEY (nid), + KEY (group_nid) + ) /*!40100 DEFAULT CHARACTER SET utf8 */;"); + og_migrate_12(); + break; + case 'pgsql': + db_query("CREATE TABLE {og_ancestry} ( + nid numeric(11) NOT NULL, + group_nid numeric(11) NOT NULL, + is_public numeric(1) NOT NULL, + PRIMARY KEY (nid) + ); + CREATE INDEX group_nid_idx ON group_nid (numeric); + "); + break; + } + return $ret ? $ret : array(); +} + +// TODO: more testing +function og_migrate_12() { + $ret = array(); + $result = db_query_range("SELECT * FROM node_access WHERE realm IN ('og_all', 'og_subscriber') AND nid < %d", 0, 20); + while ($row = db_fetch_object($result)) { + if ($row->realm == 'og_all') { + $grants[] = array('realm' => 'og_public', 'gid' => 0, 'view' => 1, 'update' => 0, 'delete' => 0); + } + else { + $grants[] = array('realm' => 'og_subscriber', 'gid' => $row->gid, 'view' => 1, 'update' => 1, 'delete' => 0); + } + + node_access_write_grants($row, $grants); + unset($grants); + } +} \ No newline at end of file Index: og.module =================================================================== RCS file: /cvs/drupal-contrib/contributions/modules/og/og.module,v retrieving revision 1.227 diff -u -F^f -r1.227 og.module --- og.module 7 Aug 2006 19:24:02 -0000 1.227 +++ og.module 22 Aug 2006 15:26:34 -0000 @@ -35,18 +35,17 @@ function og_help($section) { switch ($section) { case 'admin/help#og': break; - case 'admin/modules#description': + case 'admin/settings/modules#description': return t("Organic groups"); - case strstr($section, 'admin/block/configure/og'): + case strstr($section, 'admin/build/block/configure/og'): return t('Group specific blocks are only visible on group pages and not on systemwide pages like the home page or admin pages.'); case 'admin/settings/og': - return t('In order to let group admins determine their own group theme, you must enable multiple themes using %page.', array('%page' => l(t('theme configuration page'), 'admin/themes'))); + return t('In order to let group admins determine their own group theme, you must enable multiple themes using !page.', array('!page' => l(t('theme configuration page'), 'admin/themes'))); } } function og_menu($may_cache) { global $user; - $items = array(); if ($may_cache) { @@ -61,8 +60,10 @@ function og_menu($may_cache) { $items[] = array('path' => 'og/deny', 'type' => MENU_CALLBACK, 'callback' => 'og_deny', 'access' => $access, 'title' => t('deny subscription request')); $items[] = array('path' => 'og/create_admin', 'type' => MENU_CALLBACK, 'callback' => 'og_create_admin', 'access' => $access, 'title' => t('create group administrator')); $items[] = array('path' => 'og/delete_admin', 'type' => MENU_CALLBACK, 'callback' => 'og_delete_admin', 'access' => $access, 'title' => t('delete group administrator')); - $items[] = array('path' => 'og/remove_node', 'type' => MENU_CALLBACK, 'callback' => 'og_remove_node', 'access' => $access, 'title' => t('remove post from group')); + $items[] = array('path' => 'og/remove_node', 'type' => MENU_CALLBACK, 'callback' => 'drupal_get_form', 'callback arguments' => array('og_remove_node'), 'access' => $access, 'title' => t('remove post from group')); $items[] = array('path' => 'og/feed', 'callback' => 'og_feed', 'title' => t('group feed'), 'type' => MENU_CALLBACK, 'access' => user_access('access content')); + + $items[] = array('path' => 'admin/settings/og', 'callback' => 'drupal_get_form', 'callback arguments' => array('og_admin_settings'), 'title' => t('organic groups configuration')); } else { // we get a NOTICE if doing this from within og_theme() so I do it here for now. @@ -75,7 +76,7 @@ function og_menu($may_cache) { $items[] = array('path' => "og/manage/$key", 'callback' => 'og_manage', 'title' => t('manage subscription'), 'callback arguments' => array($key), 'type' => MENU_CALLBACK, 'access' => user_access('access content')); $items[] = array('path' => "og/invite/$key", 'callback' => 'og_invite', 'title' => t('send invitation'), 'callback arguments' => array($key), 'type' => MENU_CALLBACK, 'access' => user_access('access content')); // group admin only - $items[] = array('path' => "og/users/$key/add", 'callback' => 'og_add_users_page', 'title' => t('add subscribers'), 'callback arguments' => array($key), 'type' => MENU_LOCAL_TASK, 'access' => node_access('update', array('nid' => $key, 'status' => 1)), 'weight' => 5); + $items[] = array('path' => "og/users/$key/add", 'callback' => 'drupal_get_form', 'title' => t('add subscribers'), 'callback arguments' => array(og_add_users, $key), 'type' => MENU_LOCAL_TASK, 'access' => node_access('update', array('nid' => $key, 'status' => 1)), 'weight' => 5); // silly page that just redirects to the group page $items[] = array('path' => "og/view/$key", 'callback' => 'og_nodeview', 'title' => $sub['title'], 'callback arguments' => array($key), 'access' => TRUE, 'type' => MENU_CALLBACK); @@ -85,7 +86,7 @@ function og_menu($may_cache) { if (arg(0) == 'node' && is_numeric(arg(1))) { $node = node_load(arg(1)); if (og_is_group_type($node->type)) { - $items[] = array('path' => 'node/'. arg(1). '/email', 'title' => t('email'), 'callback' => 'og_email', 'callback arguments' => array(arg(1)), 'access' => node_access('update', $node), 'type' => MENU_LOCAL_TASK, 'weight' => 7); + $items[] = array('path' => 'node/'. arg(1). '/email', 'title' => t('email'), 'callback' => 'drupal_get_form', 'callback arguments' => array('og_email_form', arg(1)), 'access' => node_access('update', $node), 'type' => MENU_LOCAL_TASK, 'weight' => 7); } } } @@ -105,7 +106,7 @@ function og_init() { og_theme(); og_set_locale(); - if (module_exist('views')) { + if (module_exists('views')) { include drupal_get_path('module', 'og'). '/og_views.inc'; } } @@ -185,7 +186,7 @@ function og_theme() { elseif (arg(0) == 'comment' && is_numeric(arg(2))) { $group_node = og_set_theme(arg(2)); } - + og_set_group_context($group_node); } @@ -253,23 +254,22 @@ function og_nodeview($gid) { drupal_goto("node/$gid"); } + /** * Admins may broadcast email to all their subscribers * * @param $gid * the nid of a group. */ -function og_email($gid) { + function og_email_form($gid) { $node = node_load($gid); drupal_set_title(t('Send email to %group', array('%group' => $node->title))); - $form = og_email_form($gid); - return drupal_get_form('og_email_form', $form); -} - -function og_email_form($gid) { + $result = db_query(og_list_users_sql(1), $gid); - $txt = format_plural(db_num_rows($result), '1 subscriber', 'all %count subscribers'); - drupal_set_message(t('Your email will be sent to %count in this group. Please use this feature sparingly.', array('%count' => l($txt, "og/users/$gid")))); + $txt = format_plural(db_num_rows($result), '1 subscriber', 'all @count subscribers'); + if (!$_POST) { + drupal_set_message(t('Your email will be sent to !count in this group. Please use this feature sparingly.', array('!count' => l($txt, "og/users/$gid")))); + } $form['subject'] = array('#type' => 'textfield', '#title' => t('Subject'), '#size' => 70, '#maxlength' => 250, '#description' => t("Enter a subject for your email."), '#required' => true); $form['body'] = array('#type' => 'textarea', '#title' => t('Body'), '#rows' => 5, '#cols' => 90, '#description' => t('Enter a body for your email.'), '#required' => true); @@ -283,16 +283,15 @@ function og_email_form_submit($form_id, $msg = $form_values['body']. t("\n\n--------------------------------\nThis message was sent by an administrator in the '%group' group at %site. To visit this group, browse to %url1. To unsubscribe from this group, visit %url2", array('%group' => $node->title, '%site' => variable_get('site_name', drupal), '%url1' => url("node/$node->nid", NULL, NULL, TRUE), '%url2' => url("og/unsubscribe/$node->nid", NULL, NULL, TRUE))); global $user; $from = $user->mail; - $headers = "From: $from\nReply-to: $from\nX-Mailer: Drupal\nReturn-path: $from"; $sql = og_list_users_sql(1); $result = db_query($sql, $form_values['gid']); while ($row = db_fetch_object($result)) { $emails[] = $row->mail; } foreach ($emails as $mail) { - user_mail(trim($mail), $form_values['subject'], $msg, $headers); + drupal_mail('og_mail', trim($mail), $form_values['subject'], $msg, $from); } - drupal_set_message(t('%count emails sent.', array('%count' => count($emails)))); + drupal_set_message(format_plural(count($emails), '1 email sent.', '@count emails sent')); drupal_goto("node/{$form_values[gid]}"); } @@ -306,7 +305,15 @@ function og_manage($gid) { } $group = node_load($gid); + $bc = array(l(t('home'), ''), l(t('groups'), 'og'), l($group->title, "node/$gid")); + drupal_set_breadcrumb($bc); + + return drupal_get_form('og_manage_form', $group); +} +function og_manage_form($group) { + global $user; + // avoid double messages on POST if (!$_POST) { // group manager can't unsubscribe @@ -317,18 +324,19 @@ function og_manage($gid) { drupal_set_message(t('You may not unsubscribe from this group because you are its owner. A site administrator can assign ownership to another user and then you can unsubscribe.')); } else { - $links[] = l(t('Unsubscribe from this group'), "og/unsubscribe/$gid", NULL, 'destination=og'); - $form['unsubscribe'] = array('#type' => 'markup', '#title' => t('Goodbye'), '#value' => theme('item_list', $links, t('Actions'))); + $links[] = array('unsubscribe' => array( + 'title' => t('Unsubscribe from this group'), + 'href' => "og/unsubscribe/$group->nid", + 'query' => 'destination=og' + )); + $form['unsubscribe'] = array('#type' => 'item', '#title' => t('Goodbye'), '#value' => theme('item_list', $links, t('Actions'))); } } - $form['mail_type'] = array('#type' => 'radios', '#title' => t('Email notification'), '#default_value' => $user->og_groups[$gid]['mail_type'], '#options' => array(1 => t('enabled'), 0 => t('disabled')), '#description' => t('Do you want to receive an email each time a message is posted to this group?')); + $form['mail_type'] = array('#type' => 'radios', '#title' => t('Email notification'), '#default_value' => $user->og_groups[$group->nid]['mail_type'], '#options' => array(1 => t('enabled'), 0 => t('disabled')), '#description' => t('Do you want to receive an email each time a message is posted to this group?')); $form['op'] = array('#type' => 'submit', '#value' => t('Submit')); - $form['gid'] = array('#type' => 'value', '#value' => $gid); - $output = drupal_get_form('og_manage_form', $form); - $bc = array(l(t('home'), ''), l(t('groups'), 'og'), l($group->title, "node/$gid")); - drupal_set_breadcrumb($bc); - return $output; + $form['gid'] = array('#type' => 'value', '#value' => $group->nid); + return $form; } function og_manage_form_submit($form_id, $form_values) { @@ -389,9 +397,8 @@ function og_approve($gid, $uid) { $subj = t("Subscription request approved for '%title'", array('%title' => $node->title)); $body = t('You may now post messages in this group located at %url', array('%url' => url("node/$node->nid", NULL, NULL, TRUE))); $from = variable_get('site_mail', ini_get('sendmail_from')); - $headers = "From: $from\nReply-to: $from\nX-Mailer: Drupal\nReturn-path: $from\nErrors-to: $from"; $account = user_load(array('uid' => $uid)); - user_mail($account->mail, $subj, $body, $headers); + drupal_mail('og_approve', $account->mail, $subj, $body, $from); drupal_goto("node/$gid"); } else { @@ -409,7 +416,7 @@ function og_deny($gid, $uid) { $from = variable_get('site_mail', ini_get('sendmail_from')); $headers = "From: $from\nReply-to: $from\nX-Mailer: Drupal\nReturn-path: $from\nErrors-to: $from"; $account = user_load(array('uid' => $uid)); - user_mail($account->mail, $subj, $body, $headers); + drupal_mail('og_deny', $account->mail, $subj, $body, $from); drupal_goto("node/$gid"); } else { @@ -421,7 +428,7 @@ function og_create_admin($gid, $uid) { $node = node_load($gid); if (node_access('update',$node)) { og_save_subscription($gid, $uid, array('is_admin' => 1)); - drupal_set_message(t('User was promoted to %ga', array('%ga' => theme('placeholder', t('group administrator'))))); + drupal_set_message(t('User was promoted to %ga', array('%ga' => t('group administrator')))); drupal_goto("node/$gid"); } else { @@ -433,7 +440,7 @@ function og_delete_admin($gid, $uid) { $node = node_load($gid); if (node_access('update', $node)) { og_save_subscription($gid, $uid, array('is_admin' => 0)); - drupal_set_message(t('User is no longer a %ga', array('%ga' => theme('placeholder', t('group administrator'))))); + drupal_set_message(t('User is no longer a %ga', array('%ga' => t('group administrator')))); drupal_goto("node/$gid"); } else { @@ -444,12 +451,12 @@ function og_delete_admin($gid, $uid) { function og_remove_node($gid, $nid) { if (node_access('update', node_load($gid))) { $node = node_load($nid); - $form['confirm'] = array('#type' => 'markup', '#title' => t('Confirmation'), '#value' => t('Remove %title from this group.', array('%title' => theme('placeholder', $node->title)))); + $form['confirm'] = array('#type' => 'markup', '#title' => t('Confirmation'), '#value' => t('Remove %title from this group.', array('%title' => $node->title))); $form['og_confirm'] = array('#type' => 'value', '#value' => 1); $form['op'] = array('#type' => 'submit', '#value' => t('Remove')); $form['nid'] = array('#type' => 'value', '#value' => $nid); $form['gid'] = array('#type' => 'value', '#value' => $gid); - return drupal_get_form('og_remove_node', $form); + return $form; } else { drupal_access_denied(); @@ -461,7 +468,7 @@ function og_remove_node_submit($form_id, if ($form_values['og_confirm']) { $sql = "DELETE FROM {node_access} WHERE nid=%d AND gid=%d AND realm IN ('og_subscriber', 'og_public')"; db_query($sql, $form_values['nid'], $form_values['gid']); - drupal_set_message(t('%title removed from group.', array('%title' => theme('placeholder', $node->title)))); + drupal_set_message(t('%title removed from group.', array('%title' => $node->title))); drupal_goto("node/{$form_values['gid']}"); } } @@ -469,9 +476,7 @@ function og_remove_node_submit($form_id, function og_invite($gid) { $node = node_load($gid); if ($node->og_selective < OG_INVITE_ONLY || node_access('update', $node)) { - $max = variable_get('og_email_max', 10); - $form = og_invite_form($gid); - return drupal_get_form('og_invite_form', $form); + return drupal_get_form('og_invite_form', $gid); } else { drupal_access_denied(); @@ -542,11 +547,10 @@ function og_invite_form_submit($form_id, $body .= $form_values['pmessage'] ? "\n\n ----------------------------\n". $form_values['pmessage']. "\n--------------------------------" : ''; global $user; $from = $user->mail; - $headers = "From: $from\nReply-to: $from\nX-Mailer: Drupal\nReturn-path: $from"; foreach ($emails as $mail) { - user_mail($mail, $subj, $body, $headers); + drupal_mail('og_invite_form', $mail, $subj, $body, $from); } - drupal_set_message(format_plural(count($emails), '%count invitations sent.', '%count invitations sent.')); + drupal_set_message(format_plural(count($emails), '1 invitation sent.', '@count invitations sent.')); } function og_subscribe($gid, $uid = NULL) { @@ -601,22 +605,21 @@ function og_subscribe_user($gid, $accoun $body = t('To instantly approve this request, visit %url. ', array('%url' => url("og/approve/$node->nid/$account->uid", NULL, NULL, TRUE))); $body .= t('You may deny this request or manage subscribers at %url', array('%url' => url("og/users/$node->nid", NULL, NULL, TRUE))); $from = variable_get('site_mail', ini_get('sendmail_from')); - $headers = "From: $from\nX-Mailer: Drupal\nReturn-path: $from\nErrors-to: $from"; - user_mail(implode(', ', $admins), $subj, $body, $headers); + drupal_mail(implode(', ', $admins), $subj, $body, $from); } $return_value = array('type' => 'approval', - 'message' => t('Subscription request to the %group group awaits approval by an administrator.', array('%group' => theme('placeholder', $node->title)))); + 'message' => t('Subscription 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('Subscribed to the %group group', array('%group' => theme('placeholder', $node->title)))); + 'message' => t('Subscribed to the %group @group', array('@group' => $node->title))); break; case OG_CLOSED: case OG_INVITE_ONLY: $return_value = array('type' => 'rejected', - 'message' => t('Subscription request to the %group group was rejected, only group administrators can add users to this group.', array('%group' => theme('placeholder', $node->title)))); + 'message' => t('Subscription request to the @group group was rejected, only group administrators can add users to this group.', array('@group' => $node->title))); } return $return_value; } @@ -665,7 +668,7 @@ function og_list_users_sql($min_is_activ return "SELECT u.uid, u.name, u.mail, u.picture, ou.* FROM {og_uid} ou INNER JOIN {users} u ON ou.uid = u.uid WHERE ou.nid = %d AND u.status > 0 AND is_active >= $min_is_active AND is_admin >= $min_is_admin ORDER BY u.name ASC"; } -function og_add_users_page($gid) { +function og_add_users($gid) { $form['og_names'] = array('#type' => 'textarea', '#title' => t('List of users'), '#rows' => 5, @@ -674,8 +677,7 @@ function og_add_users_page($gid) { ); $form['op'] = array('#type' => 'submit', '#value' => t('Submit')); $form['gid'] = array('#type' => 'value', '#value' => $gid); - $output = drupal_get_form('og_add_users', $form); - return $output; + return $form; } function og_add_users_validate($form_id, $form_values) { @@ -708,7 +710,7 @@ function og_add_users_submit($form_id, $ foreach ($accounts as $account) { og_save_subscription($form_values['gid'], $account->uid, array('is_active' => 1)); } - drupal_set_message(t('%count added to the group', array('%count' => format_plural(count($accounts), '1 user', '%count users')))); + drupal_set_message(format_plural(count($accounts), '1 user added to the group', '@count users added to the group')); } function og_list_users_page($gid) { @@ -797,7 +799,7 @@ function og_list_groups_page_html($resul $rows[] = array(array('data' => t('No groups'), 'colspan' => 4)); } elseif (!empty($user->og_groups)) { - drupal_set_message(t('You may also view an OPML file listing RSS feeds from your subscribed groups.', array('%opml' => url('og/user/opml'))), 'help'); + drupal_set_message(t('You may also view an !opml listing RSS feeds from your subscribed groups.', array('!opml' => l(t('OPML file'), 'og/user/opml'))), 'help'); } return theme('table', $header, $rows). theme('pager', NULL, 50); } @@ -863,13 +865,8 @@ function og_get_home_nodes_sql($str_type */ function og_db_rewrite_sql($sql, $primary_table, $primary_field, $args) { if (isset($args['og_nid']) && is_numeric($args['og_nid'])) { - // we add this JOIN for node admins and when node access is disabled because node_rewrite_sql() adds it for everyone else - if (user_access('administer nodes') || node_access_view_all_nodes()) { - $query['join'] = 'INNER JOIN {node_access} na ON n.nid = na.nid'; - } - $where[] = '(na.gid = '. $args['og_nid']. " AND na.realm = 'og_subscriber')"; // private nodes - $where[] = '(na.grant_view = '. $args['og_nid']. " AND na.realm = 'og_public')"; // public nodes - $query['where'] = implode(' OR ', $where); + $query['join'] = 'INNER JOIN {og_ancestry} oga ON n.nid = oga.nid'; + $query['where'] = 'oga.group_nid = '. $args['og_nid']; return $query; } } @@ -883,7 +880,11 @@ function og_view_group(&$node, $teaser = // if you just want to change the presentation of a group home page section, redefine theme_og_list_generic() function theme_og_view($node, $teaser = FALSE, $page = FALSE) { if ($teaser || !$page) { - $node->teaser = $node->og_description; + $node->content['og_description'] = array( + '#type' => 'item', + '#title' => t('Description'), + '#value' => $node->og_description + ); } else { $bc[] = array('path' => "og", 'title' => t('groups')); @@ -894,7 +895,12 @@ function theme_og_view($node, $teaser = 'type' => 'application/rss+xml', 'title' => $node->title. t(' RSS feed'), 'href' => url("og/feed/$node->nid"))); - $output = ''; + // save the mission in an array element for use by themes if desired + // $node->content['og_mission'] = array( +// '#type' => 'item', +// '#title' => t('Mission'), +// '#value' => theme('og_mission', $node) +// ); // 2 views. 'segregate each content type' or 'a river of news' if (variable_get('og_home_page_presentation', 'gbct') == 'ron') { @@ -902,9 +908,10 @@ function theme_og_view($node, $teaser = $num = variable_get('og_max_posts', 10); $result = pager_query(db_rewrite_sql($sql, 'n', 'nid', array('og_nid' => $node->nid)), $num); while ($onenode = db_fetch_object($result)) { - $output .= node_view(node_load($onenode->nid), TRUE, FALSE); + $nodes .= node_view(node_load($onenode->nid), TRUE, FALSE); } - $output .= theme('pager', NULL, $num); + $node->content['nodes'] = array('#value' => $nodes); + $node->content['pager'] = array('#value' => theme('pager', NULL, $num)); } else { $mode = 'all'; @@ -917,18 +924,18 @@ function theme_og_view($node, $teaser = $types[$ntype] = $ntype; } $exempt = array_merge(variable_get('og_node_types', array('og')), variable_get('og_omitted', array())); - foreach ($types as $type => $val) { - if (!in_array($type, $exempt)) { - if ($table = og_list_og($node->nid, $type, $mode)) { + foreach ($types as $type) { + if (!in_array($type->type, $exempt)) { + if ($table = og_list_og($node->nid, $type->type, $mode)) { $output .= $table; } } } } $url = url("og/feed/$node->nid"); - $node->og_xml_icon = theme('xml_icon', $url); + $node->content['og_xml_icon'] = array('#value' => theme('xml_icon', $url)); - if (!$output) { + if (!$nodes) { global $user; if (in_array($node->nid, array_keys($user->og_groups))) { drupal_set_message(t('No posts in this group.')); @@ -938,14 +945,7 @@ function theme_og_view($node, $teaser = } } } - // save the homepage nodes in an array element for use by themes if desired - $node->homepage_nodes = $output; - if ($node->body) { - // save the mission in an array element for use by themes if desired - $node->og_mission = theme('og_mission', $node); - } - $node->body = $node->og_mission. $output. $node->og_xml_icon; return $node; } @@ -954,15 +954,19 @@ function theme_og_mission($node) { } /** - * Adds standard fields for any node named as a group node + * Adds standard fields for any node configured to be a group node * * @param object $node */ -function og_node_form($node) { +function og_group_form($node) { global $user; $edit = $_POST['edit']; + // all group home pages are publically accessible as far as og is concerned. their posts may or may not be. + // change this via hook_form_alter() if you want subscriber only group home pages. this may become part of og.module one day + $form['og_public'] = array('#type' => 'value', '#value' => TRUE); + $form['og_description'] = array('#type' => 'textfield', '#title' => t('Description'), '#default_value' => $node->og_description, '#size' => 70, '#maxlength' => 150, '#required' => true, '#description' => t('A brief description for the group details block and the group directory.'), '#weight' => -4); $form['og_website'] = array('#type' => 'textfield', '#title' => t('Group website'), '#default_value' => $node->og_website, '#description' => t('If your group has its own website, enter the address here.')); @@ -1017,7 +1021,7 @@ function og_node_form($node) { $default = TRUE; // fall through case OG_DIRECTORY_CHOOSE_FALSE: - $form['og_directory'] = array('#type' => 'checkbox', '#title' => t('list in groups directory'), '#default_value' => $node->nid ? $node->og_directory : $default, '#description' => t('Should this group appear on the %page?', array('%page' => l(t('list of groups page'),'og')))); + $form['og_directory'] = array('#type' => 'checkbox', '#title' => t('list in groups directory'), '#default_value' => $node->nid ? $node->og_directory : $default, '#description' => t('Should this group appear on the !page?', array('!page' => l(t('list of groups page'),'og')))); break; } @@ -1049,7 +1053,7 @@ function og_node_form($node) { } // language - if (module_exist('locale') && $languages = locale_supported_languages()) { + if (module_exists('locale') && $languages = locale_supported_languages()) { if (count($languages['name']) > 1) { $languages['name'] = array_map('check_plain', $languages['name']); $form['locale']['og_language'] = array('#type' => 'radios', @@ -1065,21 +1069,13 @@ function og_node_form($node) { return $form; } -// get og_public property for given node -function og_node_load_public($node) { - $sql = "SELECT grant_view FROM {node_access} WHERE nid = %d AND gid=0 AND realm='og_all'"; - $gv = db_result(db_query($sql, $node->nid)); - $node->og_public = $gv ? 1 : 0; - return $node; -} - // returns all the group affiliations for a given node. function og_get_node_groups($node) { if (!og_is_group_type($node->type)) { - $sql = "SELECT na.gid, n.title FROM {node_access} na INNER JOIN {node} n ON na.gid = n.nid WHERE na.nid = %d AND na.realm='og_subscriber' AND na.gid != 0"; + $sql = "SELECT oga.group_nid, n.title FROM {og_ancestry} oga INNER JOIN {node} n ON oga.nid = n.nid WHERE oga.nid = %d"; $result = db_query($sql, $node->nid); while ($row = db_fetch_object($result)) { - $groups[$row->gid] = $row->title; + $groups[$row->group_nid] = $row->title; } return $groups ? $groups : array(); } @@ -1095,14 +1091,6 @@ function og_validate_group(&$node) { } function og_submit_group(&$node) { - // if a post isn't in any groups. it must be public. this assumption is the heart of the problem with - // running multiple node permission modules at same time. ideally, all node permission modules could - // communicate and only make the node public if no permission module objected (i.e. 'deny') - // this problem needs solving in core drupal - if (empty($node->og_groups)) { - $node->og_public = 1; - } - // comments are not allowed on group nodes, since we don't have any nice way to present them if (og_is_group_type($node->type)) { $node->comment = COMMENT_NODE_DISABLED; @@ -1124,7 +1112,7 @@ function og_load_group(&$node) { $sql = 'SELECT selective AS og_selective, description AS og_description, theme AS og_theme, website AS og_website, register AS og_register, directory AS og_directory, notification AS og_notification, language AS og_language FROM {og} WHERE nid = %d'; $result = db_query($sql, $node->nid); $node = (object) array_merge((array)$node, (array)db_fetch_array($result)); - $node->comment = COMMENT_NODE_DISABLED; // we don't use comments on og nodes + $node->comment = COMMENT_NODE_DISABLED; // we don't use comments on og nodes. technically not needed since we set this on node submit } function og_insert_group($node) { @@ -1157,7 +1145,7 @@ function og_nodeapi(&$node, $op, $teaser break; case 'load': if (!og_is_group_type($node->type)) { - $node = og_node_load_public($node); + $node->og_public = db_result(db_query_range("SELECT is_public FROM {og_ancestry} WHERE nid = %d", $node->nid, 0, 1)); } else { og_load_group($node); @@ -1182,8 +1170,7 @@ function og_nodeapi(&$node, $op, $teaser } break; case 'delete': - og_delete_grants($node); - $sql = "DELETE FROM {og} WHERE nid = %d"; + $sql = "DELETE FROM {og_ancestry} WHERE nid = %d"; db_query($sql, $node->nid); $sql = "DELETE FROM {og_uid} WHERE nid = %d"; db_query($sql, $node->nid); @@ -1191,23 +1178,29 @@ function og_nodeapi(&$node, $op, $teaser case 'insert': if (og_is_group_type($node->type)) { og_insert_group($node); + // make sure the node owner is a full powered subscriber + og_save_subscription($node->nid, $node->uid, array('is_active' => 1, 'is_admin' => 1)); } - if (variable_get('og_enabled', 0)) { - og_save_permissions($node); + elseif (!og_is_omitted_type($node->type)) { + og_save_ancestry($node); } - if (!module_exist('og2list')) { + + // TODO: move this to cron to help give tiome to fix typos, and help scaling + if (!module_exists('og2list')) { if ($node->status) { $node->msgid = "$node->nid-0". og_msgid_server(); - og_mail(node_get_name($node), $node); + og_mail(node_get_types('name', $node), $node); } } break; case 'update': if (og_is_group_type($node->type)) { og_update_group($node); + // make sure the node owner is a full powered subscriber + og_save_subscription($node->nid, $node->uid, array('is_active' => 1, 'is_admin' => 1)); } - if (variable_get('og_enabled', 0)) { - og_save_permissions($node); + elseif (!og_is_omitted_type($node->type)) { + og_save_ancestry($node); } break; case 'search result': @@ -1228,16 +1221,19 @@ function og_msgid_server() { } function og_form_alter($form_id, &$form) { - $node = $form['#node']; - - if (!strpos($form_id, 'node_form') || in_array($node->type, variable_get('og_omitted', array()))) { - return; + if (strpos($form_id, 'node_form')) { + $node = $form['#node']; + if (og_is_group_type($node->type)) { + $form = array_merge($form, og_group_form($node)); + } + elseif (!in_array($node->type, variable_get('og_omitted', array()))) { + og_form_add_og_audience($form_id, $form); + } } - og_form_add_og_audience($form_id, $form); } /** - * Helper method to add OG audience fields to a given form. This is + * Helper method to add OG audience fields to a given node form. This is * lives in a separate method from og_form_alter() so it can be shared * by other OG contrib modules. */ @@ -1246,72 +1242,65 @@ function og_form_add_og_audience($form_i $edit = $_REQUEST['edit']; $node = $form['#node']; - if (og_is_group_type($node->type)) { - $form = array_merge($form, og_node_form($node)); + $required = variable_get('og_audience_required', 0); + $subs = og_get_subscriptions($node->uid); + foreach ($subs as $key => $val) { + $options[$key] = $val['title']; + } + + // TODO: this behavior is not ideal in some curcumstances. We might disable those checkboxes where admin is not a subscriber + if ($node->nid && $node->uid != $user->uid && !og_is_group_type($node->type)) { } - else { - $required = variable_get('og_audience_required', 0); - $subs = og_get_subscriptions($node->uid); - foreach ($subs as $key => $val) { - $options[$key] = $val['title']; - } - - // TODO: this behavior is not ideal in some curcumstances. We might disable those checkboxes where admin is not a subscriber - if ($node->nid && $node->uid != $user->uid && !og_is_group_type($node->type)) { - // i think this is displaying during unwanted times - // drupal_set_message(t('Admins: If you want to assign this post to a group whose checkbox does not appear below, you must first change the %author. The author\'s subscriptions are shown in the audience field.', array('%author' => theme('placeholder', t('Author'))))); - } - // get the visibility for normal users - $vis = variable_get('og_visibility', 0); - - // override visibility for og admins and when author only has 1 group - if (user_access('administer organic groups') && $vis < 2) { - $vis = $vis == OG_VISIBLE_GROUPONLY ? OG_VISIBLE_CHOOSE_PRIVATE : OG_VISIBLE_CHOOSE_PUBLIC; - } - elseif (!count($subs)) { - // don't show checkbox if no subscriptions. must be public. - $vis = OG_VISIBLE_BOTH; - } - - switch ($vis) { - case OG_VISIBLE_BOTH: - $form['og_nodeapi']['og_public'] = array('#type' => 'value', '#value' => 1); - break; - case OG_VISIBLE_GROUPONLY: - $form['og_nodeapi']['og_public'] = array('#type' => 'value', '#value' => 0); - break; + // get the visibility for normal users + $vis = variable_get('og_visibility', 0); + + // override visibility for og admins and when author only has 1 group + if (user_access('administer organic groups') && $vis < 2) { + $vis = $vis == OG_VISIBLE_GROUPONLY ? OG_VISIBLE_CHOOSE_PRIVATE : OG_VISIBLE_CHOOSE_PUBLIC; + } + elseif (!count($subs)) { + // don't show checkbox if no subscriptions. must be public. + $vis = OG_VISIBLE_BOTH; + } + + switch ($vis) { + case OG_VISIBLE_BOTH: + $form['og_nodeapi']['og_public'] = array('#type' => 'value', '#value' => 1); + break; + case OG_VISIBLE_GROUPONLY: + $form['og_nodeapi']['og_public'] = array('#type' => 'value', '#value' => 0); + break; - //user decides how public the post is. - case OG_VISIBLE_CHOOSE_PUBLIC: - $form['og_nodeapi']['visible']['og_public'] = array('#type' => 'checkbox', '#title' => t('Public'), '#default_value' => $node->nid ? $node->og_public : 1, '#description' => t('Show this post to everyone, or only to subscribers of the groups checked below. Only uncheck this box if truly needed.')); - break; - case OG_VISIBLE_CHOOSE_PRIVATE: - $form['og_nodeapi']['visible']['og_public'] = array('#type' => 'checkbox', '#title' => t('Public'), '#default_value' => $node->nid ? $node->og_public : 0, '#description' => t('Show this post to everyone, or only to subscribers of the groups checked below. Only check this box if truly needed.')); - break; - } + //user decides how public the post is. + case OG_VISIBLE_CHOOSE_PUBLIC: + $form['og_nodeapi']['visible']['og_public'] = array('#type' => 'checkbox', '#title' => t('Public'), '#default_value' => $node->nid ? $node->og_public : 1, '#description' => t('Show this post to everyone, or only to subscribers of the groups checked below. Only uncheck this box if truly needed.')); + break; + case OG_VISIBLE_CHOOSE_PRIVATE: + $form['og_nodeapi']['visible']['og_public'] = array('#type' => 'checkbox', '#title' => t('Public'), '#default_value' => $node->nid ? $node->og_public : 0, '#description' => t('Show this post to everyone, or only to subscribers of the groups checked below. Only check this box if truly needed.')); + break; + } - if (isset($edit['og_groups'])) { - // populate field from the querystring if sent - $groups = $edit['og_groups']; - } - elseif ($node->nid) { - $groups = $node->og_groups; - } - else { - $groups = array(); - } + if (isset($edit['og_groups'])) { + // populate field from the querystring if sent + $groups = $edit['og_groups']; + } + elseif ($node->nid) { + $groups = $node->og_groups; + } + else { + $groups = array(); + } - if (count($subs)) { - $form['og_nodeapi']['visible']['og_groups'] = array('#type' => 'checkboxes', '#title' => t('Audience'), '#options' => $options, '#required' => $required, '#description' => t('Show this post in these groups.'), '#default_value' => $groups); - } + if (count($subs)) { + $form['og_nodeapi']['visible']['og_groups'] = array('#type' => 'checkboxes', '#title' => t('Audience'), '#options' => $options, '#required' => $required, '#description' => t('Show this post in these groups.'), '#default_value' => $groups); + } - if (count($form['og_nodeapi']['visible']) > 1) { - $form['og_nodeapi']['#type'] = 'fieldset'; - $form['og_nodeapi']['#title'] = t('Groups'); - $form['og_nodeapi']['#collapsible'] = TRUE; - $form['og_nodeapi']['#collapsed'] = isset($edit['og_groups']) ? TRUE : FALSE; - } + if (count($form['og_nodeapi']['visible']) > 1) { + $form['og_nodeapi']['#type'] = 'fieldset'; + $form['og_nodeapi']['#title'] = t('Groups'); + $form['og_nodeapi']['#collapsible'] = TRUE; + $form['og_nodeapi']['#collapsed'] = isset($edit['og_groups']) ? TRUE : FALSE; } } @@ -1332,7 +1321,7 @@ function og_get_visibility_default() { function og_comment($comment, $op) { switch ($op) { case 'insert': - if ($comment['status'] == COMMENT_PUBLISHED && !module_exist('og2list')) { + if ($comment['status'] == COMMENT_PUBLISHED && !module_exists('og2list')) { $node = node_load($comment['nid']); $comment['og_groups'] = $node->og_groups; $comment['msgid'] = $comment['nid']. '-'. $comment['cid']. og_msgid_server(); @@ -1405,7 +1394,7 @@ function og_mail($type, $obj) { $group_home = url("node/$row->gid", NULL, NULL, TRUE); $group_name = mime_header_encode($row->group_name); $groupheaders = $headers. "\nList-Id: $group_name <$group_home>\nList-Unsubscribe: <$unsubscribe>\nList-Owner: $owner <$ownerurl>\nList-Archive: <$group_home>"; - user_mail($row->mail, $subj, $txt, $groupheaders); + drupal_mail('og_mail', $row->mail, $subj, $txt, NULL, $groupheaders); } } } @@ -1462,10 +1451,10 @@ function og_user($op, $edit, &$account, $values = array(); $result = db_query(db_rewrite_sql('SELECT n.nid, n.title, o.* FROM {node} n INNER JOIN {og} o ON n.nid = o.nid WHERE n.type IN ('. str_pad('', count(variable_get('og_node_types', array('og'))) * 5 - 1, "'%s',") .') AND o.register = 1 ORDER BY n.title'), variable_get('og_node_types', array('og'))); while ($group = db_fetch_object($result)) { - $options[$group->nid] = t('Subscribe to %name.', array('%name' => theme('placeholder', $group->title))); + $options[$group->nid] = t('Subscribe to @name.', array('@name' => $group->title)); $values[$group->nid] = in_array($group->nid, (array) $edit['og_register']) ? $group->nid : 0; if ($group->selective) { - $options[$group->nid] .= ' '. theme('placeholder', t('(approval needed)')); + $options[$group->nid] .= ' '. t('(approval needed)'); } } if (count($options)) { @@ -1501,17 +1490,9 @@ function og_user($op, $edit, &$account, } } -/** - * In the 'og_subscriber' realm, the gid is usually the nid of a group. This is used - * to store which nodes should show up in which groups. When applied to an og node, grant_view is - * always 1 but you can set it to 0 in order to have a completely private group homepage. - * In the og_public realm, the gid is always 0 but the grant_view column holds the parent group. This is needed so - * that public nodes appear on the group home page for non subscribers. The og_all realm is used to denote a public node. -**/ function og_node_grants($account, $op) { if ($op == 'view') { $grants['og_public'][] = 0; // everyone can see a public node - $grants['og_all'][] = 0; } // get subscriptions @@ -1528,114 +1509,48 @@ function og_node_grants($account, $op) { return $grants ? $grants : array(); } -function og_save_permissions(&$node) { - $sql = "DELETE FROM {node_access} WHERE realm LIKE '%s' AND nid = %d"; - db_query($sql, 'og_%', $node->nid); - - if (!og_is_group_type($node->type)) { - // put the post into each selected group. we need a separate row for public and private nodes. - // for public nodes, the grant_view column indicaOGtes which group the node belongs to. The gid=0 always. Needed to get - // public nodes to display on the home page for non subscribers - // we INSERT a broad grant here but og_node_grants() only issues it selectively for a given operation +function og_save_ancestry($node) { + if (!og_is_omitted_type($node->type)) { + $sql = "DELETE FROM {og_ancestry} WHERE nid = %d"; + db_query($sql, $node->nid); if (is_array($node->og_groups)) { foreach ($node->og_groups as $gid) { - $sql = "INSERT INTO {node_access} (nid, gid, realm, grant_view, grant_update, grant_delete) VALUES (%d, %d, 'og_subscriber', 1, 1, 1)"; - db_query($sql, $node->nid, $gid); - - if ($node->og_public) { - $sql = "INSERT INTO {node_access} (nid, gid, realm, grant_view) VALUES (%d, 0, 'og_public', %d)"; - db_query($sql, $node->nid, $gid); - } + $sql = "INSERT INTO {og_ancestry} (nid, group_nid, is_public) VALUES (%d, %d, %d)"; + db_query($sql, $node->nid, $gid, $node->og_public); } } + } +} - // if the public checkbox was selected, give a universal grant for this node - if ($node->og_public) { - $sql = "INSERT INTO {node_access} (nid, gid, realm, grant_view) VALUES (%d, 0, 'og_all', 1)"; - db_query($sql, $node->nid); +function og_node_access_records($node) { + if (og_is_omitted_type($node->type)) { + return; + } + + if (is_array($node->og_groups)) { + foreach ($node->og_groups as $gid) { + // we write a broad grant here but og_node_grants() only issues it selectively. + $grants[] = array('realm' => 'og_subscriber', 'gid' => $gid, 'grant_view' => 1, 'grant_update' => 1, 'grant_delete' => 1); } } - else { - // all groups are publically accessible, although their posts may not be - // if you really want an inaccessible group homepage, you should go to node_access table and delete the record which is inserted here. - $sql = "INSERT INTO {node_access} (nid, gid, realm, grant_view) VALUES (%d, 0, 'og_all', 1)"; - db_query($sql, $node->nid); - - // we INSERT a broad grant here but only og_node_grants() only issues it selectively. Enabes all group admins to edit the og node - $sql = "INSERT INTO {node_access} (nid, gid, realm, grant_view, grant_update, grant_delete) VALUES (%d, %d, 'og_subscriber', 1, 1, 0)"; - db_query($sql, $node->nid, $node->nid); - - // make sure the node owner is a full powered subscriber - og_save_subscription($node->nid, $node->uid, array('is_active' => 1, 'is_admin' => 1)); + + if ($node->og_public) { + $grants[] = array('realm' => 'og_public', 'gid' => 0, 'grant_view' => 1, 'grant_update' => 0, 'grant_delete' => 0); + } + + // propose a deny for non public nodes whose type matters to og and aren't in a group + if (!count($grants)) { + $grants[] = array('priority' => 10, 'realm' => 'og_public', 'gid' => 0, 'grant_view' => 0, 'grant_update' => 0, 'grant_delete' => 0); } -} - -// delete all existing grants for this module -function og_delete_grants(&$node) { - $sql = "DELETE FROM {node_access} WHERE realm LIKE '%s' AND nid = %d"; - db_query($sql, 'og_%', $node->nid); + return $grants; } -/** - * Update the node_access table when a user enables/disables the module in the - * settings page. Because Drupal does not, at this - * time, provide hooks that run automatically upon the enabling/disabling of a - * module in the admin/modules page, we must force the site-admin to explicitly - * enable/disable a module on the settings page, in - * addition to enabling/disabling the module in the admin/modules page. - * - * Here, if the user is enabling the module, we make sure the default entry in - * the node_access table is deleted and walk through all the nodes in the node table - * and grant all view access as is the default case when this module is not - * enabled. We only do this for nodes whose permissions haven't been set before by - * this module. It is possible that a site-admin may have previously enabled the - * module before disabling it. Upon re-enabling, we want to account for the old - * permissions set by the module by not re-inserting entries for them. - * - * Disabling the module simply requires re-inserting the default entry back into - * the node access table to give 'view' perms to everyone for everything: - * (0, 0, 'all', 1, 0, 0) - */ -function _og_update_db($enable) { - if (!$enable) { - // We use the delete statement to avoid inserting a duplicate entry - // into the database. Without the DELETE query, this can happen - // when a site admin has already enabled the modules from the - // settings page and goes back to it and resaves the enabled setting. - switch ($GLOBALS['db_type']) { - case 'mysql': - case 'mysqli': - db_query('REPLACE INTO {node_access} VALUES (0, 0, \'all\', 1, 0, 0)'); - break; - case 'pgsql': - $result = db_query("UPDATE {node_access} SET nid=0, gid=0, realm='all', grant_view=1, grant_update=0, grant_delete=0 WHERE nid=0 AND gid=0 and realm='all'"); - if (!db_num_rows($result)) { - db_query('INSERT INTO {node_access} VALUES (0, 0, \'all\', 1, 0, 0)'); - } - break; - } - drupal_set_message(t('Organic groups access control has been disabled. You may now disable the module on the %modules page', array('%modules' => l(t('admin/modules'), 'admin/modules')))); - } - else { - // The module was just enabled or re-enabled; provide default view - // access to everyone for nodes that were created between the previous - // disabling of the module and the current enabling of the module; - // nodes that were created during a previous enabled period are - // left-alone. Permissions for those nodes will be the same as when - // the module was previously enabled. - db_query('DELETE from {node_access} WHERE nid=0 AND gid=0 AND realm=\'all\' AND grant_view=1 AND grant_update=0 AND grant_delete=0'); - - // Assign universal grant to all non-group nodes which don't already have any grants from this module - $result = db_query("SELECT n.nid, na.gid FROM {node} n LEFT JOIN {node_access} na ON n.nid = na.nid AND realm LIKE '%og%' WHERE n.type NOT IN (". str_pad('', count(variable_get('og_node_types', array('og'))) * 5 - 1, "'%s',") .') AND na.gid IS NULL', variable_get('og_node_types', array('og'))); - while ($row = db_fetch_object($result)) { - $sql = "INSERT INTO {node_access} (nid, gid, realm, grant_view) VALUES (%d, 0, 'og_all', 1)"; - db_query($sql, $row->nid); - } - drupal_set_message(t('Organic groups access control enabled.')); - } +function og_is_omitted_type($type) { + return in_array($type, variable_get('og_omitted', array())); } + /** * Menu callback */ @@ -1712,10 +1627,11 @@ function og_block($op = 'list', $delta = function og_block_notifications() { if ($groupnode = og_get_group_context()) { - $content = t('This group offers a %groupfeed and an %email.', array('%groupfeed' => l(t('RSS feed'), 'og/feed/'. $groupnode->nid), '%email' => l(t('email subscription'), 'og/manage/'. $groupnode->nid))); - if (module_exist('views')) { + $content = t('This group offers a !groupfeed and an !email.', array('!groupfeed' => l(t('RSS feed'), 'og/feed/'. $groupnode->nid), '!email' => l(t('email subscription'), 'og/manage/'. $groupnode->nid))); + if (module_exists('views')) { $content .= t(' Or subscribe to these personalized, sitewide feeds:'); - $links[] = t('my unread: '). theme('links', array(l('feed', 'group/myunread/feed'), l('page', 'group/og_unread'))); + $links[] = t('my unread: '). theme('links', array(array('feed' => array('title' => 'feed', 'href' => 'group/myunread/feed'), 'page' => array('title' => 'page', 'href' => 'group/og_unread')))); + // TODO: new link format $links[] = t('my groups: '). theme('links', array(l('feed', 'group/mytracker/feed'), l('page', 'group/og_tracker'))); $links[] = t('all posts: '). theme('links', array(l('feed', 'group/tracker/feed'), l('page', 'groups/tracker'))); $content .= theme('item_list', $links); @@ -1833,13 +1749,12 @@ function og_block_details() { } } } - // $output = "