summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJochen Stals2010-05-18 20:00:48 (GMT)
committer Jochen Stals2010-05-18 20:00:48 (GMT)
commit17fcf6fc26d46508adbec2547d1fac37254aef21 (patch)
tree3a17ff3722f6fc38d62afb745f34b276b5374a9a
parent958ddf68354a38895e8c6de1876f6ec8a1732a62 (diff)
Improved sanitization of input content on heartbeat comments and shouts6.x-4.9
added features support improved documentation on the heartbeat log actions Refactored heartbeat activity object improved css for heartbeat display suite fixed issues on drupal.org
-rw-r--r--changelog.txt33
-rw-r--r--heartbeat.admin.inc50
-rw-r--r--heartbeat.features.inc117
-rw-r--r--heartbeat.install21
-rw-r--r--heartbeat.js7
-rw-r--r--heartbeat.module49
-rw-r--r--heartbeat.pages.inc9
-rw-r--r--includes/heartbeatactivity.inc2
-rw-r--r--modules/hds/hds_regions.css22
-rw-r--r--modules/heartbeat_comments/heartbeat_comments.admin.inc4
-rw-r--r--modules/heartbeat_comments/heartbeat_comments.js39
-rw-r--r--modules/heartbeat_comments/heartbeat_comments.module30
-rw-r--r--modules/heartbeat_comments/heartbeat_comments.rules.inc1
-rw-r--r--modules/heartbeat_rules/hrules.rules.inc8
-rw-r--r--modules/shouts/shouts.js2
-rw-r--r--modules/shouts/shouts.module25
16 files changed, 346 insertions, 73 deletions
diff --git a/changelog.txt b/changelog.txt
index e975c50..a35495d 100644
--- a/changelog.txt
+++ b/changelog.txt
@@ -6,6 +6,39 @@
#############################################################################
---------------------------------------------------------------
+# @date 10/05/2010 For release DRUPAL-6--4-9
+---------------------------------------------------------------
+- Security Update!
+ When shouts are displayed, the content is now sanitized with filter_xss
+ to filter the user input.
+ Actions:
+ - Upgraded heartbeat.install so the default allowed tags are more secure.
+ There is a left-over img attack but the code where this filtering is done,
+ is managed by a higher level permission. Before heartbeat messages,
+ heartbeat comments (and shouts) were sanitized with this tags match. It is
+ only needed and handy for the per UI manipulatable heartbeat messages. This
+ means that heartbeat comments and shouts will follow the normal filter_xss
+ approach within standard drupal.
+ - Added the filter_xss for shouts module when fetching the shouts from database
+ - Tipped by David Rothstein, I moved the filter_xss for heartbeat_messages to a
+ earlier point so it's not theme-overriable (thus possibly leading to XSS attack)
+- Change to hds_regions.css following the DS releases.
+- Added basic features integration.
+- Fixed a couple of issues from the d.o queue.
+- Refactored the comment rules integration so it can take the original author as well.
+- Added update hook for this install.
+
+---------------------------------------------------------------
+# @date 19/04/2010 For release DRUPAL-6--4-8
+---------------------------------------------------------------
+- bugfixes and feature request from issuequeue.
+
+---------------------------------------------------------------
+# @date 17/05/2010 For release DRUPAL-6--4-7
+---------------------------------------------------------------
+- bugfixes and feature request from issuequeue.
+
+---------------------------------------------------------------
# @date 14/04/2010 For release DRUPAL-6--4-6
---------------------------------------------------------------
- moved connectedheartbeat to friendlist_activity module where it
diff --git a/heartbeat.admin.inc b/heartbeat.admin.inc
index 3a505b9..a297ba7 100644
--- a/heartbeat.admin.inc
+++ b/heartbeat.admin.inc
@@ -15,7 +15,7 @@
function heartbeat_activity_admin() {
$edit = $_POST;
- if (isset($edit['operation']) && ($edit['operation'] == 'delete') && isset($edit['heartbeat-messages']) && $edit['heartbeat-messages']) {
+ if (isset($edit['operation']) && ($edit['operation'] == 'delete') && isset($edit['heartbeat-activity']) && $edit['heartbeat-activity']) {
return drupal_get_form('heartbeat_messages_multiple_delete_confirm');
}
else {
@@ -45,13 +45,13 @@ function heartbeat_messages_admin_overview() {
// load the comments that we want to display
$form['header'] = array('#type' => 'value', '#value' => array(
theme('table_select_header_cell'),
- array('data' => t('Subject'), 'field' => 'subject'),
+ array('data' => t('Activity message'), 'field' => 'message'),
array('data' => t('Author'), 'field' => 'name'),
array('data' => t('Language'), 'field' => 'language'),
array('data' => t('Time'), 'field' => 'timestamp', 'sort' => 'desc'),
array('data' => t('Operations'))
));
- $result = pager_query('SELECT DISTINCT ha.message AS \'subject\', ha.uaid, ha.timestamp, ha.language, u.name AS registered_name, u.uid FROM {heartbeat_activity} ha LEFT JOIN {users} u ON u.uid = ha.uid '. tablesort_sql($form['header']['#value']), 50, 0, NULL);
+ $result = pager_query('SELECT DISTINCT ha.message AS \'message\', ha.uaid, ha.timestamp, ha.language, u.name AS registered_name, u.uid FROM {heartbeat_activity} ha LEFT JOIN {users} u ON u.uid = ha.uid '. tablesort_sql($form['header']['#value']), 50, 0, NULL);
// build a table listing the appropriate comments
$destination = drupal_get_destination();
@@ -59,14 +59,15 @@ function heartbeat_messages_admin_overview() {
while ($message = db_fetch_object($result)) {
$rows[$message->uaid] = '';
$message->name = $message->uid ? $message->registered_name : $anon;
- $title = strip_tags($message->subject);
- $form['subject'][$message->uaid] = array('#value' => l($title, 'heartbeat/message/'. $message->uaid, array('attributes' => array('title' => truncate_utf8($title, 128)), 'fragment' => 'heartbeat-message-'. $message->uaid)));
+ $title = strip_tags($message->message);
+ $form['message'][$message->uaid] = array('#value' => l($title, 'heartbeat/message/'. $message->uaid, array('attributes' => array('title' => truncate_utf8($title, 128)), 'fragment' => 'heartbeat-message-'. $message->uaid)));
$form['username'][$message->uaid] = array('#value' => theme('username', $message));
$form['timestamp'][$message->uaid] = array('#value' => format_date($message->timestamp, 'small'));
$form['language'][$message->uaid] = array('#value' => $message->language);
$form['operations'][$message->uaid] = array('#value' => l(t('view'), 'heartbeat/message/'. $message->uaid. '', array('query' => $destination)));
+ $form['operations'][$message->uaid]['#value'] .= ' - ' . l(t('delete'), 'heartbeat/delete/'. $message->uaid. '', array('query' => $destination));
}
- $form['heartbeat-messages'] = array('#type' => 'checkboxes', '#options' => isset($rows) ? $rows: array());
+ $form['heartbeat-activity'] = array('#type' => 'checkboxes', '#options' => isset($rows) ? $rows: array());
$form['pager'] = array('#value' => theme('pager', NULL, 50, 0));
return $form;
}
@@ -77,8 +78,8 @@ function heartbeat_messages_admin_overview() {
* We can't execute any 'Update options' if no messages were selected.
*/
function heartbeat_messages_admin_overview_validate($form, &$form_state) {
- $form_state['values']['heartbeat-messages'] = array_diff($form_state['values']['heartbeat-messages'], array(0));
- if (count($form_state['values']['heartbeat-messages']) == 0) {
+ $form_state['values']['heartbeat-activity'] = array_diff($form_state['values']['heartbeat-activity'], array(0));
+ if (count($form_state['values']['heartbeat-activity']) == 0) {
form_set_error('', t('Please select one or more messages to perform the update on.'));
drupal_goto('admin/content/heartbeat');
}
@@ -95,7 +96,7 @@ function heartbeat_messages_admin_overview_submit($form, &$form_state) {
if ($form_state['values']['operation'] == 'delete') {
// extract the appropriate database query operation
$query = "DELETE FROM {heartbeat_activity} WHERE uaid = %d";
- foreach ($form_state['values']['heartbeat-messages'] as $uaid => $value) {
+ foreach ($form_state['values']['heartbeat-activity'] as $uaid => $value) {
if ($value) {
$activity = heartbeat_load_message_instance($uaid);
@@ -105,7 +106,7 @@ function heartbeat_messages_admin_overview_submit($form, &$form_state) {
// Allow modules to respond to the updating of a comment.
module_invoke_all('heartbeat_activity_delete', $activity);
// Add an entry to the watchdog log.
- watchdog('content', 'Heartbeat: updated %subject.', array('%subject' => $activity->message), WATCHDOG_NOTICE, l(t('view'), 'heartbeat/message/'. $activity->uaid, array('fragment' => 'heartbeat-message-'. $activity->uaid)));
+ watchdog('content', 'Heartbeat: updated %message.', array('%message' => $activity->message), WATCHDOG_NOTICE, l(t('view'), 'heartbeat/message/'. $activity->uaid, array('fragment' => 'heartbeat-message-'. $activity->uaid)));
}
}
@@ -123,11 +124,11 @@ function heartbeat_messages_admin_overview_submit($form, &$form_state) {
*/
function theme_heartbeat_messages_admin_overview($form) {
$output = drupal_render($form['options']);
- if (isset($form['subject']) && is_array($form['subject'])) {
- foreach (element_children($form['subject']) as $key) {
+ if (isset($form['message']) && is_array($form['message'])) {
+ foreach (element_children($form['message']) as $key) {
$row = array();
- $row[] = drupal_render($form['heartbeat-messages'][$key]);
- $row[] = drupal_render($form['subject'][$key]);
+ $row[] = drupal_render($form['heartbeat-activity'][$key]);
+ $row[] = drupal_render($form['message'][$key]);
$row[] = drupal_render($form['username'][$key]);
$row[] = drupal_render($form['language'][$key]);
$row[] = drupal_render($form['timestamp'][$key]);
@@ -163,12 +164,12 @@ function theme_heartbeat_messages_admin_overview($form) {
function heartbeat_messages_multiple_delete_confirm(&$form_state) {
$edit = $form_state['post'];
- $form['heartbeat-messages'] = array('#prefix' => '<ul>', '#suffix' => '</ul>', '#tree' => TRUE);
+ $form['heartbeat-activity'] = array('#prefix' => '<ul>', '#suffix' => '</ul>', '#tree' => TRUE);
// array_filter() returns only elements with actual values
$counter = 0;
- foreach (array_filter($edit['heartbeat-messages']) as $uaid => $value) {
+ foreach (array_filter($edit['heartbeat-activity']) as $uaid => $value) {
$activity = heartbeat_load_message_instance($uaid);
- $form['heartbeat-messages'][$uaid] = array('#type' => 'hidden', '#value' => $uaid, '#prefix' => '<li>', '#suffix' => check_plain(strip_tags($activity->message)) .'</li>');
+ $form['heartbeat-activity'][$uaid] = array('#type' => 'hidden', '#value' => $uaid, '#prefix' => '<li>', '#suffix' => check_plain(strip_tags($activity->message)) .'</li>');
$counter++;
}
$form['operation'] = array('#type' => 'hidden', '#value' => 'delete');
@@ -193,8 +194,13 @@ function heartbeat_messages_multiple_delete_confirm(&$form_state) {
function heartbeat_messages_multiple_delete_confirm_submit($form, &$form_state) {
if ($form_state['values']['confirm']) {
- foreach ($form_state['values']['heartbeat-messages'] as $uaid => $value) {
+
+ foreach ($form_state['values']['heartbeat-activity'] as $uaid => $value) {
+
db_query("DELETE FROM {heartbeat_activity} WHERE uaid = %d", $uaid);
+
+ // Delete their attachments as well.
+ module_invoke_all('heartbeat_delete', $uaid);
}
drupal_set_message(t('The messages have been deleted.'));
@@ -247,7 +253,7 @@ function heartbeat_admin_settings() {
'#collapsible' => TRUE,
'#collapsed' => FALSE,
);
- $allowed_tags = array('h1', 'h2', 'h3', 'h4', 'h5', 'h6', 'a', 'span', 'em', 'strong', 'ul', 'li', 'p', 'div', 'img', 'object', 'param', 'embed', 'blockquote', 'script', 'style');
+ $allowed_tags = array('h1', 'h2', 'h3', 'h4', 'h5', 'h6', 'a', 'span', 'em', 'strong', 'ul', 'li', 'p', 'div', 'img', 'blockquote');
$form['hb_fields'] ['heartbeat_allowed_tags'] = array(
'#title' => t('Filter the messages with for these tags only'),
'#type' => 'textfield',
@@ -543,8 +549,9 @@ function heartbeat_activity_stream_configure(& $form_state, $access_type) {
20 => t('Every 20 seconds'),
30 => t('Every 30 seconds'),
45 => t('Every 45 seconds'),
- 60 => t('Every minute')
- // Jabber push will be an option here
+ 60 => t('Every minute'),
+ // XMPP/Jabber push instead of pulling the messages
+ //100 => t('Use XMPP to push messages')
),
'#title' => t('Poll every x seconds for newer messages to prepend the stream.'),
'#default_value' => isset($access_type['poll_messages']) ? $access_type['poll_messages'] : 0,
@@ -1329,6 +1336,7 @@ function heartbeat_activity_ahah($element) {
'settings' => call_user_func_array('array_merge_recursive', $javascript['setting']),
));
}
+ exit;
}
/**
diff --git a/heartbeat.features.inc b/heartbeat.features.inc
new file mode 100644
index 0000000..d035356
--- /dev/null
+++ b/heartbeat.features.inc
@@ -0,0 +1,117 @@
+<?php
+// $Id$
+
+/**
+ * @file
+ * Features support.
+ */
+
+/**
+ * Return API information for features.
+ */
+function _heartbeat_features_api() {
+ return array(
+ 'heartbeat' => array(
+ 'name' => t('Heartbeat'),
+ 'default_hook' => 'heartbeat_message_info',
+ 'default_file' => FEATURES_DEFAULTS_INCLUDED,
+ 'features_source' => TRUE,
+ 'file' => drupal_get_path('module', 'heartbeat') .'/heartbeat.features.inc',
+ ),
+ );
+}
+
+/**
+ * Implementation of hook_features_export_options().
+ */
+function heartbeat_features_export_options() {
+ return _heartbeat_features_get_types();
+}
+
+/**
+ * Get types for features.
+ */
+function _heartbeat_features_get_types() {
+ $types = array();
+ $templates = heartbeat_messages('all', TRUE);
+ foreach ($templates as $template) {
+ $types[$template->message_id] = empty($template->description) ? $template->message_id : $template->description;
+ }
+ return $types;
+}
+
+/**
+ * Implementation of hook_features_export().
+ */
+function heartbeat_features_export($data, &$export, $module_name = '') {
+ $pipe = array();
+ $export['dependencies']['heartbeat'] = 'heartbeat';
+ foreach ($data as $module) {
+ $export['features']['heartbeat'][$module] = $module;
+ }
+
+ return $pipe;
+}
+
+/**
+ * Implementation of hook_features_export_render().
+ */
+function heartbeat_features_export_render($module = 'foo', $data) {
+ $code = array();
+ $info = array();
+
+ // Begin code
+ $code[] = ' $messages = array();' . "\n";
+
+ // Gather all messages
+ $messages = heartbeat_messages('all', TRUE, FALSE);
+
+ foreach ($messages as $message) {
+ $message = (object) $message;
+ if (!array_search($message->message_id, $data)) {
+ continue; // Leave if not selected
+ }
+
+ // Label the current message
+ $code[] = ' // Exported heartbeat message: ' . $message->message_id;
+
+ // Build message object
+ $concat_args = heartbeat_decode_message_variables($message->concat_args);
+ $variables = heartbeat_decode_message_variables($message->variables);
+ $message = array(
+ 'message' => $message->message,
+ 'message_concat' => $message->message_concat,
+ 'message_id' => $message->message_id,
+ 'concat_args' => $concat_args,
+ 'description' => $message->description,
+ 'perms' => $message->perms,
+ 'custom' => HEARTBEAT_MESSAGE_DEFAULT,
+ 'variables' => $variables
+ );
+
+ // Add to code
+ $code[] = ' $messages[] = ' . var_export($message, 1) . ";\n";
+ }
+
+ // End code
+ $code[] = "\n" . ' return $messages;';
+
+ // Put code into a string
+ $code = implode($code, "\n");
+
+ return array('heartbeat_message_info' => $code);
+}
+
+/**
+ * Implementation of hook_features_revert().
+ */
+function heartbeat_features_revert($module = NULL) {
+ // Get default heartbeats from feature
+ if (module_hook($module, 'heartbeat_message_info')) {
+ $heartbeats = module_invoke($module, 'heartbeat_message_info');
+
+ foreach ($heartbeats as $heartbeat) {
+ heartbeat_messages_revert($heartbeat);
+ }
+ }
+}
diff --git a/heartbeat.install b/heartbeat.install
index f6acc99..57b7edd 100644
--- a/heartbeat.install
+++ b/heartbeat.install
@@ -25,7 +25,7 @@ function heartbeat_install() {
variable_set('heartbeat_activity_grouping_seconds', 7200);
variable_set('heartbeat_activity_grouping_how_many', 5);
- $allowed_tags = array('h1', 'h2', 'h3', 'h4', 'h5', 'h6', 'a', 'span', 'em', 'strong', 'ul', 'li', 'p', 'div', 'img', 'object', 'param', 'embed', 'blockquote', 'script', 'style');
+ $allowed_tags = array('h1', 'h2', 'h3', 'h4', 'h5', 'h6', 'a', 'span', 'em', 'strong', 'ul', 'li', 'p', 'div', 'img', 'blockquote');
variable_set('heartbeat_allowed_tags', implode(',', $allowed_tags));
variable_set('heartbeat_activity_log_cron_delete', 2678400);
variable_set('heartbeat_access_types', array());
@@ -443,3 +443,22 @@ function heartbeat_update_402() {
return $ret;
}
+/**
+ * Update to version 4.6.9
+ *
+ * @return sql statements array
+ */
+function heartbeat_update_403() {
+
+ $tags = array();
+ $old_tags = explode(',', variable_get('heartbeat_allowed_tags', ''));
+ foreach ($old_tags as $tag) {
+ if (!in_array($tag, array('script', 'style', 'embed', 'object', 'param'))) {
+ $tags[] = $tag;
+ }
+ }
+
+ variable_set('heartbeat_allowed_tags', implode(',', $tags));
+
+ return array();
+}
diff --git a/heartbeat.js b/heartbeat.js
index dd08628..92dcdbc 100644
--- a/heartbeat.js
+++ b/heartbeat.js
@@ -9,11 +9,11 @@ Drupal.heartbeat.moreLink = null;
* wait().
* Function that shows throbber while waiting a response.
*/
-Drupal.heartbeat.wait = function(element) {
+Drupal.heartbeat.wait = function(element, parentSelector) {
// We wait for a server response and show a throbber
// by adding the class heartbeat-messages-waiting.
- Drupal.heartbeat.moreLink = $(element).parents('.heartbeat-more-messages-wrapper');
+ Drupal.heartbeat.moreLink = $(element).parents(parentSelector);
// Disable double-clicking.
if (Drupal.heartbeat.moreLink.is('.heartbeat-messages-waiting')) {
return false;
@@ -36,9 +36,8 @@ Drupal.heartbeat.doneWaiting = function() {
* Fetch older messages with ajax.
*/
Drupal.heartbeat.getOlderMessages = function(element, page) {
- Drupal.heartbeat.wait(element);
+ Drupal.heartbeat.wait(element, '.heartbeat-more-messages-wrapper');
$.post(element.href, {block: page ? 0 : 1, ajax: 1}, Drupal.heartbeat.appendMessages);
-
}
/**
diff --git a/heartbeat.module b/heartbeat.module
index 5e14017..20e9931 100644
--- a/heartbeat.module
+++ b/heartbeat.module
@@ -187,6 +187,22 @@ function heartbeat_menu() {
}
}
+ // Build content administration
+ $items['admin/content/heartbeat'] = array(
+ 'title' => 'administer heartbeat activity',
+ 'description' => 'Administer heartbeat activity',
+ 'weight' => -5,
+ 'page callback' => 'heartbeat_activity_admin',
+ 'access arguments' => array('delete heartbeat activity logs'),
+ 'file' => 'heartbeat.admin.inc',
+ );
+ $items['admin/content/heartbeat/activity'] = array(
+ 'title' => 'List activity messages',
+ 'description' => 'Overview activity messages',
+ 'type' => MENU_DEFAULT_LOCAL_TASK,
+ 'weight' => -5,
+ );
+
// Build menu
$items['admin/build/heartbeat'] = array(
'title' => 'Heartbeat',
@@ -363,6 +379,9 @@ function heartbeat_theme() {
'heartbeat_stream_overview' => array(
'arguments' => array('form' => NULL),
),
+ 'heartbeat_messages_admin_overview' => array(
+ 'arguments' => array('form' => NULL),
+ ),
);
}
@@ -373,11 +392,10 @@ function heartbeat_user($type, $edit, &$account, $category = NULL) {
switch ($type) {
case 'load':
- global $user;
$account->heartbeat_relations = heartbeat_get_related_uids($account->uid);
- //if ($account->uid == $user->uid) {
- //$user->heartbeat_relations = $account->heartbeat_relations;
- //}
+ break;
+ case 'delete':
+ db_query("DELETE FROM {heartbeat_activity} WHERE uid = %d OR uid_target = %d ", $account->uid, $account->uid);
break;
case 'view':
break;
@@ -508,6 +526,14 @@ function heartbeat_form_alter($form, $form_state, $form_id) {
}
/**
+ * Implementation of hook_features_api().
+ */
+function heartbeat_features_api() {
+ require_once('heartbeat.features.inc');
+ return _heartbeat_features_api();
+}
+
+/**
* Function to load title for pages.
*/
function heartbeat_messages_title($access_type = NULL) {
@@ -1160,12 +1186,17 @@ function heartbeat_log($data, $args = array()) {
// Relational message of heartbeat messages
$row = heartbeat_message_load($data['message_id'], 'message_id');
+
$template = new HeartbeatMessageTemplate($row->hid, $row->message_id, $row->message, $row->message_concat, $row->concat_args);
$data = $data + (array)$row;
$heartbeatactivity = new HeartbeatActivity($data, $template);
- return $heartbeatactivity->save($args);
+ $saved = $heartbeatactivity->save($args);
+
+ module_invoke_all('heartbeat_activity_log', $heartbeatactivity, $args);
+
+ return $saved;
}
/**
@@ -1514,6 +1545,9 @@ function heartbeat_stream_view($access_type, $page = FALSE, $offset = 0, $ajax =
$heartbeatAccess = new $accesstype($stream, $page, $account);
// Set the js variable to poll for newer messages
+ if ($heartbeatAccess->stream->poll_messages == 100) {
+ // Use XMPP to serve the activity
+ }
drupal_add_js(array('heartbeatPollNewerMessages' => $heartbeatAccess->stream->poll_messages), 'setting');
$heartbeatAccess->setOffsetSql($offset);
@@ -1590,6 +1624,11 @@ function heartbeat_stream_more_link($heartbeatAccess, $offset_time, $page = TRUE
$path .= '/' . $offset_time;
+ // Add a fourth paramter to indicate that where on a profile page.
+ if (arg(0) == 'user' && is_numeric(arg(1)) && variable_get('heartbeat_show_user_profile_messages_' . $heartbeatAccess->getStream()->name, 0)) {
+ $path .= '/' . arg(1);
+ }
+
if ($ajax_pager) {
$attributes['attributes']['onclick'] = 'javascript:Drupal.heartbeat.getOlderMessages(this, ' . (int)$page . '); return false;';
}
diff --git a/heartbeat.pages.inc b/heartbeat.pages.inc
index 738c1b7..d7eb747 100644
--- a/heartbeat.pages.inc
+++ b/heartbeat.pages.inc
@@ -30,12 +30,17 @@ function heartbeat_messages_page($access_type, $offset_time = 0, $account = NULL
$output .= heartbeat_stream_prev_link($access_type);
}
+ // For block updates by ajax displayed on the user
+ // profile page, we want to show the account requested.
+ if (!$page && is_numeric($account) && $account > 0 && variable_get('heartbeat_show_user_profile_messages_'. $access_type, 0)) {
+ $account = heartbeat_user_load($account);
+ }
+
// Message streams for each access type
$context = heartbeat_stream_view($access_type, $page, $offset_time, $ajax, $account);
if (!isset($context)) {
- $data = t('No messages found.');
- return $ajax ? drupal_json(array('status' => TRUE, 'data' => $data)) : $data;
+ return $ajax ? drupal_json(array('status' => TRUE, 'data' => t('No messages found.'))) : t('No messages found.');
}
// Get the messages
diff --git a/includes/heartbeatactivity.inc b/includes/heartbeatactivity.inc
index 7dd8537..6298d07 100644
--- a/includes/heartbeatactivity.inc
+++ b/includes/heartbeatactivity.inc
@@ -168,7 +168,7 @@ class HeartbeatActivity {
// Limit the number of displayed (grouped) messages by message
// or left as default global configuration
- if (isset($this->template->concat_args['group_num_max'])) {
+ if (!empty($this->template->concat_args['group_num_max'])) {
$max_items_to_group = $this->template->concat_args['group_num_max'];
}
diff --git a/modules/hds/hds_regions.css b/modules/hds/hds_regions.css
index 7d16144..4b34f37 100644
--- a/modules/hds/hds_regions.css
+++ b/modules/hds/hds_regions.css
@@ -5,15 +5,19 @@
}
.hds-region-left {
- clear: left;
+ display: inline;
float: left;
}
-.hds-region-middle {
- clear: none;
+.hds-region-middle-wrapper {
+ display: inline;
+ float: left;
+ width: 100%;
+ margin-right: -100%;
}
.hds-region-right {
+ display: inline;
float: right;
}
@@ -33,20 +37,18 @@
/* middle region */
-.hds-no-sidebars {
+.hds-no-sidebars .hds-region-middle {
}
-.hds-sidebar-left {
+.hds-sidebar-left .hds-region-middle {
margin-left: 25%;
- overflow: hidden;
}
-.hds-sidebar-right {
+.hds-sidebar-right .hds-region-middle {
margin-right: 25%;
- overflow: hidden;
}
-.hds-two-sidebars {
+.hds-two-sidebars .hds-region-middle {
margin-left: 25%;
margin-right: 25%;
-}
+} \ No newline at end of file
diff --git a/modules/heartbeat_comments/heartbeat_comments.admin.inc b/modules/heartbeat_comments/heartbeat_comments.admin.inc
index 3bf3d1f..01f7bfe 100644
--- a/modules/heartbeat_comments/heartbeat_comments.admin.inc
+++ b/modules/heartbeat_comments/heartbeat_comments.admin.inc
@@ -40,9 +40,9 @@ function heartbeat_comments_admin_overview() {
// load the comments that we want to display
$form['header'] = array('#type' => 'value', '#value' => array(
theme('table_select_header_cell'),
- array('data' => t('Message'), 'field' => 'subject'),
+ array('data' => t('Comment'), 'field' => 'subject'),
array('data' => t('Author'), 'field' => 'name'),
- array('data' => t('Posted in'), 'field' => 'heartbeat_title'),
+ array('data' => t('Reacted on'), 'field' => 'heartbeat_title'),
array('data' => t('Time'), 'field' => 'timestamp', 'sort' => 'desc')
));
$result = pager_query('SELECT c.hcid, c.uid, c.uaid, c.message AS \'subject\', c.cleared, c.time, ha.message AS \'heartbeat_title\', u.name AS registered_name, u.uid FROM {heartbeat_comments} c LEFT JOIN {heartbeat_activity} ha ON ha.uaid = c.uaid LEFT JOIN {users} u ON u.uid = c.uid '. tablesort_sql($form['header']['#value']), 50, 0, NULL);
diff --git a/modules/heartbeat_comments/heartbeat_comments.js b/modules/heartbeat_comments/heartbeat_comments.js
index 0ef6d73..a3a552b 100644
--- a/modules/heartbeat_comments/heartbeat_comments.js
+++ b/modules/heartbeat_comments/heartbeat_comments.js
@@ -5,6 +5,8 @@ Drupal.heartbeat = Drupal.heartbeat || {};
Drupal.heartbeat.comments = Drupal.heartbeat.comments || {};
+Drupal.heartbeat.comments.button = null;
+
/**
* Attach behaviours to the message streams
*/
@@ -15,6 +17,11 @@ Drupal.behaviors.heartbeat_comments = function (context) {
}
Drupal.heartbeat.comments.submit = function(element) {
+
+ // Throw in the throbber
+ Drupal.heartbeat.comments.button = $(element);
+ Drupal.heartbeat.wait(Drupal.heartbeat.comments.button, '.heartbeat-comments-wrapper');
+ Drupal.heartbeat.comments.button.attr("disabled", "disabled");
var formElement = $(element).parents('form');
@@ -23,7 +30,8 @@ Drupal.heartbeat.comments.submit = function(element) {
message: formElement.find('.heartbeat-message-comment').val(),
uaid: formElement.find('.heartbeat-message-uaid').val(),
nid: formElement.find('.heartbeat-message-nid').val(),
- node_comment: formElement.find('.heartbeat-message-node-comment').val()
+ node_comment: formElement.find('.heartbeat-message-node-comment').val(),
+ first_comment: !$('#heartbeat-comments-list-' + formElement.find('.heartbeat-message-uaid').val()).length
};
$.post(url, args, Drupal.heartbeat.comments.submitted,'json');
@@ -31,27 +39,30 @@ Drupal.heartbeat.comments.submit = function(element) {
}
Drupal.heartbeat.comments.submitted = function(data) {
+
if (data.id != undefined) {
if (!$('#heartbeat-comments-list-' + data.id).length) {
- var html = '<ul class="summary" id="heartbeat-comments-list-' + data.id + '"></ul>';
if (Drupal.settings.heartbeat_comments_position == 'up') {
- $('#heartbeat-comments-wrapper-' + data.id).append(html);
+ $('#heartbeat-comments-wrapper-' + data.id).append(data.data);
}
else {
- $('#heartbeat-comments-wrapper-' + data.id).prepend(html);
+ $('#heartbeat-comments-wrapper-' + data.id).prepend(data.data);
}
}
-
- if (Drupal.settings.heartbeat_comments_order == 'oldest_on_top') {
- $('#heartbeat-comments-list-' + data.id).append(data.data);
- }
- else {
- $('#heartbeat-comments-list-' + data.id).prepend(data.data);
- }
-
- $('#heartbeat-comments-list-' + data.id).parents('.heartbeat-comments').find('.heartbeat-message-comment').val('');
-
+ else {
+ if (Drupal.settings.heartbeat_comments_order == 'oldest_on_top') {
+ $('#heartbeat-comments-list-' + data.id).append(data.data);
+ }
+ else {
+ $('#heartbeat-comments-list-' + data.id).prepend(data.data);
+ }
+
+ $('#heartbeat-comments-list-' + data.id).parents('.heartbeat-comments').find('.heartbeat-message-comment').val('');
+ }
//Drupal.attachBehaviors($('.heartbeat-stream'));
+
+ Drupal.heartbeat.doneWaiting();
+ Drupal.heartbeat.comments.button.removeAttr("disabled");
}
} \ No newline at end of file
diff --git a/modules/heartbeat_comments/heartbeat_comments.module b/modules/heartbeat_comments/heartbeat_comments.module
index 6aca8f5..3fb2220 100644
--- a/modules/heartbeat_comments/heartbeat_comments.module
+++ b/modules/heartbeat_comments/heartbeat_comments.module
@@ -108,6 +108,16 @@ function heartbeat_comments_heartbeat_load(&$messages, HeartbeatAccess $stream)
}
/**
+ * Implementation of hook_heartbeat_delete().
+ * Delete the attached comments to a heartbeat activity object.
+ * @param $message
+ * HeartbeatActivity ID
+ */
+function heartbeat_comments_heartbeat_delete($uaid) {
+ db_query("DELETE FROM {heartbeat_comments} WHERE uaid = %d", $uaid);
+}
+
+/**
* Implementation of hook_heartbeat_attachments().
* @param $message
* HeartbeatActivity object
@@ -238,6 +248,8 @@ function heartbeat_comments_form($form_state = array(), $uaid = 0, $node_comment
$form['submit'] = array(
'#type' => 'submit',
'#value' => t('Submit'),
+ '#prefix' => '<span class="heartbeat-comments-wrapper">',
+ '#suffix' => '<span class="heartbeat-messages-throbber">&nbsp;</span></span>',
'#attributes' => array(
'class' => 'heartbeat-comment-submit'
),
@@ -296,9 +308,11 @@ function heartbeat_comments_form_submit($form = array(), &$form_state = array())
$uaid = ($ahah ? $_POST['uaid'] : (isset($form_state['values']['uaid']) ? $form_state['values']['uaid'] : $form_state['clicked_button']['#post']['uaid']));
$nid = ($ahah ? $_POST['nid'] : (isset($form_state['values']['nid']) ? $form_state['values']['nid']: 0));
$node_comment = $nid > 0 && ($ahah ? $_POST['node_comment'] : $form_state['values']['node_comment']);
+ $first_comment = ($ahah ? $_POST['first_comment'] : $form_state['values']['first_comment']);
if (!user_access('add heartbeat comment') || empty($message)) {
drupal_json(array('status' => FALSE, 'data' => t('No message recorded')));
+ exit;
}
$saved = NULL;
@@ -327,18 +341,23 @@ function heartbeat_comments_form_submit($form = array(), &$form_state = array())
}
}
+ $authorid = db_result(db_query("SELECT uid FROM {heartbeat_activity} WHERE uaid = %d", $uaid));
+ $author = user_load($authorid);
+
// Let rules know there has been a shout event
if (module_exists('rules')) {
- rules_invoke_event('heartbeat_comment_post', $user, $saved);
+ rules_invoke_event('heartbeat_comment_post', $user, $saved, $author);
}
if ($ahah) {
if (isset($saved)) {
- drupal_json(array('status' => TRUE, 'data' => theme('heartbeat_comment', $saved, $node_comment), 'id' => $uaid));
+ $content = $first_comment ? theme('heartbeat_comments', array($saved), $uaid, $node_comment) : theme('heartbeat_comment', $saved, $node_comment);
+ drupal_json(array('status' => TRUE, 'data' => $content, 'id' => $uaid));
}
else {
drupal_json(array('status' => TRUE, 'data' => 'error'));
}
+ exit;
}
else {
if ($saved) {
@@ -411,7 +430,6 @@ function theme_heartbeat_comment($comment, $node_comment = FALSE, $last = FALSE)
$output .= '<div class="heartbeat-teaser">';
$output .= l($account->name, 'user/' . $comment->uid) . ' ';
- $comment->comment = filter_xss($comment->comment);
$output .= $comment->comment;
$output .= '</div>';
@@ -443,6 +461,8 @@ function heartbeat_get_message_reactions($uaid) {
FROM {heartbeat_comments} s INNER JOIN {users} u ON s.uid = u.uid
WHERE uaid = %d ORDER BY time DESC", $tuaid, 0, HEARTBEAT_REACTIONS_PER_PAGE + 1);
while ($comment = db_fetch_object($result)) {
+ // Sanitize the comment messages.
+ $comment->comment = filter_xss($comment->comment);
$reactions[] = $comment;
}
@@ -477,6 +497,8 @@ function heartbeat_get_node_comments($node, $cid = 0) {
if ($comment = db_fetch_object($result)) {
$comment->name = $comment->uid ? $comment->registered_name : $comment->name;
+ // Sanitize the comment messages.
+ $comment->comment = check_markup($comment->comment, $comment->format, FALSE);
$comments[] = $comment;
}
}
@@ -506,6 +528,8 @@ function heartbeat_get_node_comments($node, $cid = 0) {
//drupal_add_css(drupal_get_path('module', 'comment') .'/comment.css');
while ($comment = db_fetch_object($result)) {
$comment = drupal_unpack($comment);
+ // Sanitize the comment messages.
+ $comment->comment = check_markup($comment->comment, $comment->format, FALSE);
$comment->name = $comment->uid ? $comment->registered_name : $comment->name;
$comment->depth = count(explode('.', $comment->thread)) - 1;
$comments[] = $comment;
diff --git a/modules/heartbeat_comments/heartbeat_comments.rules.inc b/modules/heartbeat_comments/heartbeat_comments.rules.inc
index fb57ad3..46839ed 100644
--- a/modules/heartbeat_comments/heartbeat_comments.rules.inc
+++ b/modules/heartbeat_comments/heartbeat_comments.rules.inc
@@ -18,6 +18,7 @@ function heartbeat_comments_rules_event_info() {
'arguments' => array(
'user' => array('type' => 'user', 'label' => t('User who reacts on the acivity.')),
'heartbeat_comment' => array('type' => 'heartbeat_comment', 'label' => t('Comment that has been posted.')),
+ 'author' => array('type' => 'user', 'label' => t('User who is the original author of the activity.')),
),
'redirect' => TRUE,
),
diff --git a/modules/heartbeat_rules/hrules.rules.inc b/modules/heartbeat_rules/hrules.rules.inc
index df1a547..3c52ce3 100644
--- a/modules/heartbeat_rules/hrules.rules.inc
+++ b/modules/heartbeat_rules/hrules.rules.inc
@@ -84,7 +84,7 @@ function hrules_rules_action_info() {
// Base action to execute as default user activity logs
'heartbeat_rules_default_action' => array(
- 'label' => t('Logs user activity for single users'),
+ 'label' => t('Logs default activity'),
'eval input' => array(
'uid_param',
'uid_target_param',
@@ -93,20 +93,20 @@ function hrules_rules_action_info() {
'message_id_param',
'variables_param'
),
- 'help' => 'Create a relation between a user and others when handling content(node or comment).',
+ 'help' => 'Create a relation between a user and something else(node, user, comment, etc ...).',
'module' => 'heartbeat',
),
// Simplified action to execute user-to-user activity logs
'heartbeat_rules_users_action' => array(
- 'label' => t('Logs default user activity between users'),
+ 'label' => t('Logs activity to indicate a relation between users'),
'eval input' => array(
'uid_param',
'uid_target_param',
'message_id_param',
'variables_param'
),
- 'help' => 'Create a relation between a user and another user.',
+ 'help' => 'Create a relation between a user and another user. This is only helpfull for relationships like friends, collegues, ... but not when a user only addresses his content to another user.',
'module' => 'heartbeat',
),
);
diff --git a/modules/shouts/shouts.js b/modules/shouts/shouts.js
index ca4144a..1eeea86 100644
--- a/modules/shouts/shouts.js
+++ b/modules/shouts/shouts.js
@@ -19,7 +19,7 @@ Drupal.heartbeat.Shouts.shout = function(element, callback_url) {
Drupal.heartbeat.Shouts.button = $(element);
// Throw in the throbber
- Drupal.heartbeat.wait($('.heartbeat-messages-throbber'));
+ Drupal.heartbeat.wait($('.heartbeat-messages-throbber'), '.shouts-form-wrapper');
Drupal.heartbeat.Shouts.button.attr("disabled", "disabled");
var field = $(element).parents('form').find('.shout-message:first');
diff --git a/modules/shouts/shouts.module b/modules/shouts/shouts.module
index f25da8a..d8306f0 100644
--- a/modules/shouts/shouts.module
+++ b/modules/shouts/shouts.module
@@ -53,6 +53,9 @@ function shouts_block($op = 'list', $delta = 0, $edit = array()) {
);
return $form;
}
+ elseif ($op == 'save') {
+ variable_set('show_latest_shout', $edit['show_latest_shout']);
+ }
}
/**
@@ -82,8 +85,15 @@ function shouts_user($op, &$edit, &$account, $category = NULL) {
case 'view':
$latest_shout = get_latest_shout($account->uid);
if (!empty($latest_shout->message)) {
- $account->content['latest_shout'] = array(
- '#value' => theme('shoutform_message', $latest_shout->message, false, false, $latest_shout->time)
+ $account->content['shouts'] = array(
+ '#type' => 'user_profile_category',
+ '#title' => t('Lastest shout'),
+ '#attributes' => array('class' => 'shouts-profile'),
+ '#weight' => 1,
+ 'latest_shout' => array(
+ '#type' => 'user_profile_item',
+ '#value' => theme('shoutform_message', $latest_shout->message, false, false, $latest_shout->time)
+ )
);
}
break;
@@ -183,12 +193,13 @@ function theme_shoutform_message($latest_shout, $update, $time = '') {
$shout_time = '<span class="shout_ago">'. $date .' '. $ago. '</span>';
}
- $latest_shout = '<div class="latest_shout">'. $latest_shout. '</div>';
+ $latest_shout = '<div class="latest_shout">'. $latest_shout .'</div>';
$output = '<div class="inner">'. $latest_shout . $shout_time . '</div>';
if (!$update) {
$output = '<div id="shout-wrapper">'. $output .'</div>';
}
+
return $output;
}
@@ -224,7 +235,7 @@ function shouts_shout_form($form_state = array(), $show_latest_shout = TRUE) {
}
$form['submit'] = array(
- '#prefix' => '<span class="heartbeat-more-messages-wrapper">',
+ '#prefix' => '<span class="shouts-form-wrapper">',
'#suffix' => '<span class="heartbeat-messages-throbber">&nbsp;</span></span>',
'#type' => 'submit',
'#value' => t('Shout'),
@@ -253,6 +264,7 @@ function shouts_shout_form_submit($form = array(), &$form_state = array()) {
if (!user_access('make shout') || empty($message)) {
drupal_json(array('status' => FALSE, 'data' => t('No message recorded')));
+ exit;
}
$success = db_query("INSERT INTO {shouts} (uid, message, time) VALUES (%d, '%s', '%s')", $uid, $message, date('Y-m-d H:i:s'));
@@ -268,6 +280,7 @@ function shouts_shout_form_submit($form = array(), &$form_state = array()) {
if ($ahah) {
drupal_json(array('status' => TRUE, 'data' => theme('shoutform_message', $message, true, true, date('Y-m-d H:i:s'))));
+ exit;
}
else {
drupal_set_message(t('Shout has been posted.'));
@@ -277,6 +290,7 @@ function shouts_shout_form_submit($form = array(), &$form_state = array()) {
if ($ahah) {
drupal_json(array('status' => TRUE, 'data' => 'error'));
+ exit;
}
else {
drupal_set_message(t('Error while posting shout.'));
@@ -300,6 +314,7 @@ function shout_load($shout_id) {
*/
function get_latest_shout($uid) {
$shout = db_fetch_object(db_query_range('SELECT message, cleared, time FROM {shouts} WHERE uid = %d ORDER BY time DESC', $uid, 0, 1));
+ $shout->message = filter_xss($shout->message);
return $shout;
}
@@ -321,5 +336,5 @@ function clear_shout() {
} else {
drupal_json(array('status' => FALSE, 'data' => theme_shoutform_message(t('Error while clearing shout.'), false, true)));
}
-
+ exit;
}