I needed to add time delays to Activity 2.x as people were updating content over and over within seconds of a previous updates and the stream was starting to look a bit messy and useless.

I think, if I remember from my brief use of it, that 1.x allowed for time limits but the feature wasn't there in 2.x. I decided to add it.

The patch creates adds 2 settings to the settings page for Delay after node/comment creation and Delay between updates, both defaulting to zero (no delay, store all activity). The first setting will probably be optional for most people but I have found that users create a node and then decide to immediately edit it after noticing spelling mistakes so I wanted to allow admins to set a limit before recording the first update for a node/comment. The second setting will ensure that, if an update occurs, Activity doesn't record another update for the same node by the same user for the selected amount of time (this should always be the node author in the current iteration of Activity 2.x).

The node_activity_type_check and comment_activity_type_check functions have been updated and check based on user as well as node so that Activity will record for different people updating content without checking the delay.

I have also created a small module to alter the way activity records the user id for an activity, it always stores the global user as the user performing the action unless it is an action on a profile node (created by Content Profile). This means that if you add user picture to your Activity views you can include the picture of the updater for node activities or the node author when it is a profile related activity - sweet!

A few examples of how this works with my hook module:

Example 1

Assuming there are publisher templates for node insert and node update, if we had settings at 1 hour delay for first update and 10 minutes for delay between updates:

  1. User A creates a new node at 15:00 - insert recorded
  2. User A updates node at 15:30 - no activity recorded
  3. User A updates node at 16:30 - update recorded
  4. User A updates node at 16:35 - no activity recorded
  5. User A updates node at 16:42 - update recorded

Example 2

Assuming there are publisher templates for node insert and node update, if we had settings at 1 hour delay for first update and 10 minutes for delay between updates:

  1. User A creates a new node at 15:00 - insert recorded
  2. User A updates node at 15:30 - no activity recorded
  3. User B updates node at 15:40 - no activity recorded
  4. User A updates node at 16:30 - update recorded
  5. User B updates node at 16:35 - update recorded
  6. User B updates node at 16:42 - no activity recorded

Note that the update that User B did before the 1 hour delay after User A created the node was not recorded but the update at 16:35 was recorded, even though there is a 10 minute delay. The delays are designed to stop duplicate activity records for the same user within the time limit. User B was a different user updating so logically we want to record this activity as well.

Conclusions

This patch should work fairly seemlessly with the current dev iteration even without my hooks module but, if people want it, I have also attached my Activity Mods module which can be activated from the Activity section on the modules page. It is only a few lines for one alter so no point in adding it to Drupal contrib.

Hope this helps others with the similar issues. Any feedback or suggestions will be welcomed.

Comments

Scott Reynolds’s picture

Status: Needs review » Needs work

First pass

  • Tables in db queries need {} around them
  • The db query to check the time can use the variable_get() as in the Where. so something like WHERE created < %d and %d will be the math. removes the need to db_fetch_array().
  • because it uses a variable_get, every activity type shares the same one. We need this per activity type

I have also created a small module to alter the way activity records the user id for an activity, it always stores the global user as the user performing the action unless it is an action on a profile node (created by Content Profile). This means that if you add user picture to your Activity views you can include the picture of the updater for node activities or the node author when it is a profile related activity - sweet!

Im working on a patch to finally put this to rest. The idea is to introduce a variable to hook_Content_type_alter($types, $bulk = FALSE). If $bulk is FALSE, then we use $GLOBALS['user']->uid. #724546: Introduce a $bulk variable to activity_record, but I think this shows a problem right? You didn't want the $GLOBAL['user'] when a profile node was updated.

Chris Graham’s picture

I did actually think about that second point you made when I was writing that, I'll have a look at getting it fixed and sort the table issue with the queries.

In terms of the sharing with the variable_get... I take it I was going down the right path with that and I'd just need to add in different variables to each .activity.inc file and update the admin with the extra settings, probably need to add another for user updates while I am at it.

For the last part I think that the global user thing is a good idea in general so I'd be happy enough to keep using hooks for profiles for now.

What I really need are 2 different templates for recording activity (or a conditional one) when updating nodes based on global user and the node author, so lets say User X is the global user then I would to be able to say:

"User X updated their profile"
..
and
..
"User X updated User Y's profile"

and then I could always use the global user and completely forget about the node author.

I don't think conditional templates are possible at the moment (unless I missed something) so I'm stuck with having to hook_alter that uid to force it to use node author for profile nodes and just say:

"User Y's profile was updated"

where User Y is node author regardless of the user performing the activity.

Chris Graham’s picture

Just had a bit of a play with the query to make it do the math... changed the query to:

/**
 * Implementation of hook_activity_type_check().
 */
function node_activity_type_check($token_objects, $types) {
  // Don't want to log an activity too soon after the node was first created
  $updating_old = ($token_objects['node']->changed - $token_objects['node']->created > variable_get('activity_first_update_delay', 0));
  
  $update_delay = db_query("SELECT aid FROM {activity} WHERE nid = %d AND op = 'update' AND uid = %d AND created > %d ORDER BY created DESC LIMIT 1", $token_objects['node']->nid, $token_objects['user']->uid, $token_objects['node']->changed - variable_get('activity_delay_between_updates', 0));
  
  return (in_array($token_objects['node']->type, $types) && ($token_objects['node']->is_new || ($updating_old && db_affected_rows($update_delay) == 0));
}

but the the thing is.... I still have to do a db_affected_rows() on this to then check that there are zero affected rows. I know that this is better than a db_fetch_array() but I'm just worried about that db_affected_rows()... from what I've found everyone says to stay away from using affected_rows() with a resource from a SELECT and that it should only be used with INSERT,UPDATE or DELETE. There used to be a db_num_rows() in D5 but it was stripped for D6 given that it wasn't compatible with Postgre.... any thoughts? Am I barking up the wrong tree with that method?

Scott Reynolds’s picture

/**
* Implementation of hook_activity_type_check().
*/
function node_activity_type_check($token_objects, $types) {
  // Don't want to log an activity too soon after the node was first created
  $updating_old = ($token_objects['node']->changed - $token_objects['node']->created > variable_get('activity_first_update_delay', 0));
  
  $update_delay = db_result(db_query("SELECT COUNT(aid) FROM {activity} WHERE nid = %d AND op = 'update' AND uid = %d AND created > %d ORDER BY created DESC LIMIT 1", $token_objects['node']->nid, $token_objects['user']->uid, $token_objects['node']->changed - variable_get('activity_delay_between_updates', 0)));
  
  return (in_array($token_objects['node']->type, $types) && ($token_objects['node']->is_new || $updating_old == 0);
}
Chris Graham’s picture

Thanks for that. It is working now with nodes and comments having separate settings in the admin, but I'm having an issue with user related activity.

I placed a drupal_set_message() in user_activity_type_check() and it wasn't firing so I modified activity.module and changed the code in activity_record_check() from this:

if (!empty($types)) {
  return module_invoke(activity_module_name($context['hook']), 'activity_type_check', $token_objects, $types);
}

to this:

if (!empty($types)) {
  drupal_set_message('Calling ' . $context['hook'] . ' activity type check');
  return module_invoke(activity_module_name($context['hook']), 'activity_type_check', $token_objects, $types);
}
else {
  drupal_set_message('Never called ' . $context['hook'] . ' activity type check');
}

and it is catching in the else so user_activity_type_check() is never being called.... ever! Is this a bug?

I thought that $types contained activity types, so things like insert, update, delete, view... am I wrong?

Scott Reynolds’s picture

Yep a bug, simple fix, just change empty($types) to empty($token_objects)

#770120: Typo in activity_record_check, $types = $token_objects

Scott Reynolds’s picture

Nope I was wrong, just remove the empty($types). What this was doing was saying "Did the user select only specific 'types' for this template, if so then call the type check function". Essentially, it assumed that type check should be called only if the User select specific 'types' (i.e. node type).

I hope to spend some time on this here soon as well.

Chris Graham’s picture

Damn.... just realised something. This global user thing is going to have an impact on the user related activity. It will store the uid as the logged in user's id and then the activity row in the DB won't include any id related to the user the activity was performed on.

In order to get the time delays working with user account updates user_activity_type_check() needs to check the uid on the activity to see when the last update was and it won't see the account's uid to allow for the delay.

For now I'm going to do another alter in my mods module to keep the author for user related activity as well as content profile nodes.

This might be a huge pain but it might be better if Activity could record 2 ids, one for the author/user and one for the actor. This would help with other things like views, but it might be a lot of work...

Scott Reynolds’s picture

This might be a huge pain but it might be better if Activity could record 2 ids, one for the author/user and one for the actor. This would help with other things like views, but it might be a lot of work...

That creates quiet a bit of headaches in different places.

Have you looked at modifying the activity_record_check function for this instead?

Chris Graham’s picture

Status: Needs work » Needs review
StatusFileSize
new8.1 KB

Finally got around to getting the new version of the patch updated. Done a bit of testing and it seems to be working, just need a few more people to review to make sure.

The admin settings now have independent time delays for user/comment/node activities.

Scott Reynolds’s picture

Interesting, any reason you didn't do this in activity_record_check instead of each module's activity_type_check ?

That would prevent breaking other modules and not introducing an api change. and activity_type_check now loses its semantic meaning as its just not checking types but record times.

Scott Reynolds’s picture

Status: Needs review » Needs work

Also want the settings for the delay Per template not globally in Activity settings. Thats not where it belongs. Some templates I might want to post it all the time some others I want to add repetition protection.

Chris Graham’s picture

That sounds like a much better plan. I'll try and get a look at this again when I get time.

rjbrown99’s picture

#13: Have you had an opportunity to update the patch? Thank you.

_shy’s picture

Status: Needs work » Closed (outdated)

D6 reached its EOL back in February 2016, and there is no active release for D6 for this module anymore.
Development or support is not planned for D6. All D6-related issues are marked as outdated in a bunch.

If the issue remains relevant for D10+ versions, merge requests with proposed solutions for a new module version (D10+) are welcome in a new follow-up issue.

Thanks!

Now that this issue is closed, review the contribution record.

As a contributor, attribute any organization that helped you, or if you volunteered your own time.

Maintainers, credit people who helped resolve this issue.