Support for Drupal 7 is ending on 5 January 2025—it’s time to migrate to Drupal 10! Learn about the many benefits of Drupal 10 and find migration tools in our resource center.
I suggest limiting this to firing when the user profile form is submitted by a particular user, profile fields have changed as a result of the submit, and hasn't been submitted in the last 15 minutes, as opposed to on each user_save() since that can be triggered by a range of non-user facing events.
Comment | File | Size | Author |
---|---|---|---|
#23 | 1782898.commons_activity_stream.updated_profile_use_request_time.patch | 852 bytes | jpontani |
#20 | profile_updated_message-1782898-20.patch | 10.7 KB | mmilano |
#19 | profile_updated_message-1782898-19.patch | 10.06 KB | mmilano |
#19 | profile_updated_message-1782898-19.patch | 10.06 KB | mmilano |
#15 | profile_updated_message-1782898-15.patch | 10.07 KB | mmilano |
Comments
Comment #1
ezra-g CreditAttribution: ezra-g commentedMoving this to the main Drupal Commons issue queue per #1812492: Consider using central issue queue for Commons projects.
Comment #2
mmilano CreditAttribution: mmilano commentedThe 2 challenges here were to know when the profile was updated last, and detect if there were changes. I approached this by using the standard cache table, although a custom cache table might be more appropriate.
When a user submits their profile, the form values are serialized and stored in the cache table.
The next time the user submits the profile form, the new values are compared against the old values with a string comparison of a serialized array.
Keys we don't care about for change detection (login, access, pass, etc...) are filtered out and sorted before the values are compared and stored.
Using cache_get gives us the additional benefit of knowing when the last time the cache was set. This is how the 15 minute threshold was implemented.
The last check is that the user is submitting their own form. I didn't think that activity should display if an admin was in there changing someone else's profile.
The feature was re-created and copied back to the source.
Comment #3
jpontani CreditAttribution: jpontani commentedYou'll want to remove the DSM call. Also your message doesn't actually link to anything (no HREF set), looks like the export may have messed up the message details.
Returns HTML:
<a class="aloha-link-text">@{message:user:name}</a> has an updated profile.
Other than that, looks good to me.
Comment #4
mmilano CreditAttribution: mmilano commentedGood catch, this update fixes those 2 issues.
Comment #5
ezra-g CreditAttribution: ezra-g commentedThis message never generates on a fresh installation of Commons with #4 applied, probably because $change_detected is never set to TRUE if there's no cache entry for the user having edited her profile, so $change_detected won't be set to TRUE on the first profile edit:
Comment #6
mmilano CreditAttribution: mmilano commented@ezra, that does not look like the code from the patch in #4.
Comment #7
jpontani CreditAttribution: jpontani commented@mmilano, It would still not detect a change if the cache wasn't set initially.
That would see that no cache exists, and thus a "change" would necessarily exist because they have never updated their profile previously.
Taking a look at it again, would this not also trigger on a new user's initial registration? No cache would exist because you're checking for a cache bin of: commons_up_ (no UID), depending on if the user is created prior to this submit handler at least. I haven't tried it to see, so I'm just thinking "out loud", so to speak.
Comment #8
mmilano CreditAttribution: mmilano commentedjpontani, that would only set cache if it was never set before. cache_set() definitely needs to be outside the conditions.
I'm still concerned how Ezra's code got the way it is, but I'll ignore that for now.
A business logic question is: Should the updated message generate when a user registers? (I think not)
The confirmed bug is: The message will not generate until the second time the user submits their profile.
If we move the data comparison outside of the cache check, it will fix that bug.
But I need to know if the message is expected to be generated when a user registers.
Once I get that info, I'll recreate the patch.
Comment #9
ezra-g CreditAttribution: ezra-g commented@mmilano, You're correct - I accidentally quoted a modified version of the code rather than your patch - Sorry about the mistake.
This message does not need to appear when a user first registers (though a separate issue for a "User registered for site" message is a good idea).
Comment #10
jpontani CreditAttribution: jpontani commented@mmilano, Yea that's true, just was posting quickly. Your code in #8 should remedy the issue if the cache isn't set, as per #9 should accomodate only existing users and not a user that is just registering. One quick thought to do that would be to set that specific submit handler to be executed first, and then if the uid exists, continue, otherwise skip that handler.
Comment #11
mmilano CreditAttribution: mmilano commented@jpontani - This code is not triggered on registration, it is a submit handler attached to form id: edit_profile_user_profile_form
For registration, I think the cleanest solution would be to add a separate submit handler to the user register form. Then we wouldn't have to clutter up our user edit form handler with conditionals and the alternate message.
Comment #12
ezra-g CreditAttribution: ezra-g commentedAgreed - Seems like a great separate post 3.0 feature :).
Comment #13
mmilano CreditAttribution: mmilano commentedHere is a new patch as per #8.
Comment #14
ezra-g CreditAttribution: ezra-g commentedIn functional testing of #13, with all the caches cleared, submitting the user profile edit form for the first time with no changes results in an activity stream message being created. That's probably an acceptable behavior for the first submit after a cache clear, but seems unideal given that we've introduced some non-trivial code to avoid generating messages in this scenario.
As an alternative approach, we could follow the pattern that Commons Follow uses to avoid duplicative messages: Use a simple EFQ for a message of the same type about the same user within the last 15 minutes, and don't create a new message if one has been created within that timespan.
It would be possible for users to generate a new message every 15 minutes if they wanted to, but even with #13, a determined user could simply alter the body field by one character to bypass the check.
Comment #15
mmilano CreditAttribution: mmilano commentedI don't see how in #13, the user could bypass the 15 minute check by altering a character since it would not get past the test for $last_update > $time - 900 except after a cache clear. Maybe you weren't referring to the time check and just the character difference. In that case, if you could define the additional requirements that are required for the message to trigger, we could work on a solution for that.
I think the EFQ is a good solution to avoid breaking the 15 minute check shortly after cache is cleared.
Attached is a patch with that logic vs basing the time check on when the cache was last updated.
Comment #16
mmilano CreditAttribution: mmilano commentedComment #17
ezra-g CreditAttribution: ezra-g commentedSorry I was unclear there.
My point was that we've introduced some code complexity to avoid generating a message when the profile hasn't changed, and that currently this code isn't performing as expected because I can submit the user profile form with no changes and still generate an activity stream message.
From my perspective, that's why this still needs work. The patch in #15 also has this issue.
Secondarily, I was suggesting that perhaps we don't need to attempt to prevent messages from being generated when the user profile contents haven't actually changed since it's easy for users to bypass this check as long as they only do so once every 15 minutes. However, after further thought I realized I was focusing only on malicious users attempting to generate extra messages (which we basically can't prevent) when really it seems worth keeping this check in place to prevent extra messages from being generated by well-intentioned users who save the form without changes.
So, to reiterate, I think this just needs a re-roll to prevent an activity stream messages from being generated when the form is saved without any changes for the first time (presumably, when no cache entry has been created).
Comment #18
ezra-g CreditAttribution: ezra-g commentedPS, feel free to find me in #drupal-commons to discuss.
Comment #19
mmilano CreditAttribution: mmilano commentedOk, so this patch contains the change detection logic from the patch in #4, and the EFQ method of detecting if a message was created recently from the patch in #15.
These are now the use cases where the message should logically trigger, but will not because of going with the cache architecture route:
- User updates profile information for the first time with changes.
- User updates profile information with changes after a cache clear.
I have some alternate solution ideas:
1) We no longer use the cache timestamp, so the only benefit we're getting is easy storage.
While I know using $user->data is not encouraged, using cache tables isn't exactly a golden for this either.
This would remove the failure in the cache clear use case above. The first time with changes use case might still be a little tricky.
2) Preprocess the form to get the default values, store them in $form_state['storage'] and compare them on the submit.
This would resolve both cases above, although may come with more risk. I'll make a new post with this concept in a patch.
Comment #20
mmilano CreditAttribution: mmilano commentedOops, I attached the last patch twice. It is the same file.
This patch is a proof of concept for alternative solution idea number 2 in #19 above.
The idea is that we programmatically get and store the default $form_state['values'] array when the form loads. Then we compare it on submit.
I am not sure this is entirely sane, but was just having some fun tinkering with alternate solutions. My concerns are if it's an appropriate use of prepare and process form this way, as well as potential issues with array keys we need to remove in the $remove_keys array as users install or create other modules. I suppose they keys could be a problem with the other change detection logic as well.
Comment #21
ezra-g CreditAttribution: ezra-g commented#20 works as expected in my functional testing - A message isn't created until the user updates a profile field value. Nice!
I got an undefined index error with
so I changed to
, tweaked code comments and committed.
Thanks, mmilano!
Comment #22
jpontani CreditAttribution: jpontani commentedre #21, might look into switching to REQUEST_TIME constant, as per http://api.drupal.org/api/drupal/includes%21bootstrap.inc/constant/REQUE...
Just a thought for future functionality.
Comment #23
jpontani CreditAttribution: jpontani commentedAttached a patch to updated to REQUEST_TIME constant.
Comment #24
ezra-g CreditAttribution: ezra-g commentedLooks good to me.
Comment #25
ezra-g CreditAttribution: ezra-g commentedThis was committed on Feb 4: http://drupalcode.org/project/commons_activity_streams.git/commit/9d23b91.
Thanks, mmilano!
Comment #26
ezra-g CreditAttribution: ezra-g commentedOops, I missed that this issue was open for just the followup in 23.
Comment #27
ezra-g CreditAttribution: ezra-g commented#23 is committed. Thanks!
http://drupalcode.org/project/commons_activity_streams.git/commitdiff/d7...