The "Authored on" field on the comment edit form doesn't actually show the date the comment was created, only the date it was modified.

Usually these are one and the same, but if you edit the date, save the comment, and then re-edit the comment, your date change won't be there, because the field displays the modification date instead. The field writes to $comment->created just fine but the form doesn't display that field for editing. To reproduce:

  1. Create a comment.
  2. Edit the date of the comment to be one month ago, or whatever. Save. See that the change does show when you view the comment.
  3. Edit the comment. See how the Authored on field shows the modification date (today) rather than the month-ago date.
Support from Acquia helps fund testing for Drupal Acquia logo

Comments

markabur’s picture

FileSize
1018 bytes

Here's the test that shows the problem.

markabur’s picture

Status: Active » Needs review
FileSize
1.96 KB

Here's the patch that fixes the problem. It doesn't include the test patch above, so they both need to be applied.

The fix has two parts, because the test fails for two reasons.

First part. Testing for $comment->date is not correct here, as that's the name of the form field, not the database field.

-    $date = (!empty($comment->date) ? $comment->date : format_date($comment->changed, 'custom', 'Y-m-d H:i O'));
+    $date = (!empty($comment->created) ? format_date($comment->created, 'custom', 'Y-m-d H:i O') : format_date($comment->changed, 'custom', 'Y-m-d H:i O'));

Second part. Saving the comment is timezone-sensitive, making the test fail if you're in any timezone other than +0300. These changes force the system to be UTC for this test, so that the field doesn't change unexpectedly:

+    variable_set('date_default_timezone', 'UTC');
-    $edit['date'] = '2008-03-02 17:23 +0300';
-    $expected_date = format_date(strtotime($edit['date']));
+    $edit['date'] = '2008-03-02 17:23 +0000';
+    $expected_date = format_date(strtotime($edit['date']), 'medium', '', 'UTC');
markabur’s picture

Cool, testbot actually ran the test in #1. Here's a patch that combines #1 and #2, should still be green...

markabur’s picture

Here's where the bug came from; it's not present in d6: #537062: Remove unneeded comment_edit() page callback

markabur’s picture

Title: Comment edit form is mixed up about editing dates » Editing a comment destroys its creation date

Thought about this and realized that this bug causes a type of data loss. If we add one more "save" step to the test then the bad date would be written to the database.

markabur’s picture

Priority: Normal » Major

Setting this to major as it's a regression from d6, and it does cause data corruption (wrong date written to database) 100% of the time a comment is edited.

bfroehle’s picture

+++ modules/comment/comment.testundefined
@@ -522,6 +522,7 @@ class CommentPreviewTest extends CommentHelperCase {
+    variable_set('date_default_timezone', 'UTC');
@@ -534,8 +535,8 @@ class CommentPreviewTest extends CommentHelperCase {
-    $edit['date'] = '2008-03-02 17:23 +0300';
-    $expected_date = format_date(strtotime($edit['date']));
+    $edit['date'] = '2008-03-02 17:23 +0000';

Are these changes necessary? Why have they been made?

+++ modules/comment/comment.moduleundefined
@@ -1910,7 +1910,7 @@ function comment_form($form, &$form_state, $comment) {
-    $date = (!empty($comment->date) ? $comment->date : format_date($comment->changed, 'custom', 'Y-m-d H:i O'));
+    $date = (!empty($comment->created) ? format_date($comment->created, 'custom', 'Y-m-d H:i O') : format_date($comment->changed, 'custom', 'Y-m-d H:i O'));

I agree that $date needs to be set differently. However, is there really a situation where $comment->created wouldn't exist (but $comment->changed would)? Something feels wrong about this.

bfroehle’s picture

    $date = (!empty($comment->date) ? $comment->date : format_date($comment->created, 'custom', 'Y-m-d H:i O'));

seems more appropriate to me...

bfroehle’s picture

Two new patches (tests only & tests+fix) which include revised tests (to eliminate my objections in #7) and the fix I think is proper (from #8).

The bug really originated in #122098: Split comment.timestamp into 'created' and 'updated' columns (the split of the previous timestamp into created and changed).

From comment_submit(), we see that the form element 'date' corresponds to the created timestamp:

  if (empty($comment->date)) {
    $comment->date = 'now';
  }
  $comment->created = strtotime($comment->date);
  $comment->changed = REQUEST_TIME;

And therefore we should use $comment->created, not $comment->changed, to generate the form element 'date.'

Status: Needs review » Needs work

The last submitted patch, 1005004-9-test-and-fix.patch, failed testing.

bfroehle’s picture

Status: Needs work » Needs review

#9: 1005004-9-test-and-fix.patch queued for re-testing.

markabur’s picture

Thanks for looking at this. I agree that it makes sense to do:

  $expected_form_date = format_date(strtotime($edit['date']), 'custom', 'Y-m-d H:i O');

instead of messing with the timezone. On my machine that results in the field looking like "2008-03-02 06:23 -0800" rather than the "2008-03-02 17:23 +0300" that was input, but they are equivalent. With my way, the input value of "2008-03-02 06:23 -0000" is exactly what you see if you look at the loaded form, i.e. there's no timezone conversion. But, the system needs to take care of timezones anyway, and this change is simpler.

    $date = (!empty($comment->date) ? $comment->date : format_date($comment->created, 'custom', 'Y-m-d H:i O'));

That makes more sense too. I don't know if $comment->date is ever really non-empty here, but yeah there's no point in pre-filling the field with $comment->changed in any case.

I've beefed up the tests to check the saved/loaded comment data against what it was originally created with. But I'm confused because the subject test should pass but it fails, and the date test should fail but it passes. Is this because comment_load($comment->id) isn't really loading the comment from the database?

The attached "fix" patch is good (same as above) but that subject test will still fail as we're not trying to fix that..

+    // Check that the comment data is correct after submitting the comment edit form with a small change.
+    $edit['subject'] = $edit['subject'] . ' edited';
+    $this->drupalPost('comment/' . $comment->id . '/edit', $edit, t('Save'));
+    $comment_loaded = comment_load($comment->id);
+    $this->assertEqual($comment_loaded->subject, $edit['subject'] . ' edited', t('Subject loaded.'));
+    $this->assertEqual($comment_loaded->comment_body[$langcode][0]['value'], $edit['comment_body[' . $langcode . '][0][value]'], t('Comment body loaded.'));
+    $this->assertEqual($comment_loaded->name, $edit['name'], t('Name loaded.'));
+    $this->assertEqual($comment_loaded->created, $raw_date, t('Date loaded.'));

Status: Needs review » Needs work

The last submitted patch, 1005004-11-test-and-fix.patch, failed testing.

bfroehle’s picture

@markabur: In #9 the 'date test' is passing because when you preview the comment it's just returning what you originally typed in. This is exactly the behavior of
$date = (!empty($comment->date) ? $comment->date : format_date($comment->created, 'custom', 'Y-m-d H:i O'));

The subject test is failing because
$edit['subject'] = $edit['subject'] . ' edited';
and then you do the comparison to
$edit['subject'] . 'edited'.

You should really just assert that the new subject is equal to $edit['subject'].

Lastly, if we're adding routines for verification after we save, we should probably change the name of the test (to something like testCommentEditPreviewSave) and the generic comments for it.

markabur’s picture

Doh, I see the trouble with $edit['subject'] = $edit['subject'] . ' edited';. Silly mistake.

But I'm still trying to understand why the final date test is passing in the tests-only patch; when I go through the sequence manually the date does change, which means the test should fail, since we just saved the comment while it was displaying the wrong date in the edit form.

In other words if the first test below fails, then we save the comment, then the second test below should fail as well, but it doesn't.

+    $this->assertFieldByName('date', $expected_form_date, t('Date field displayed.'));
[...]
+    $this->drupalPost('comment/' . $comment->id . '/edit', $edit, t('Save'));
[...]
+    $this->assertEqual($comment_loaded->created, $raw_date, t('Date loaded.'));
bfroehle’s picture

@markabur in #15: The second test is passing because the form save mechanism is fine. Since you aren't changing the date in $edit, $comment->created will still be set correctly. What was broken is the form generation mechanism, and this test does fail.

markabur’s picture

@bfroehle thanks, I just realized that -- $edit['date'] wasn't getting picked up from the form like I assumed. I'd like the test to demonstrate that saving the form in the mis-generated state results in bad data in the database. Does that make sense?

Is there a command for reading the value of the form field that's actually displayed? E.g. I want to add a step like "$edit['date'] = DrupalGetFormField('date')" before saving the form.

markabur’s picture

Assigned: Unassigned » markabur

$this->xpath() is what I was looking for..

markabur’s picture

Here's the revised test. It includes a section that uses $this->xpath() to retrieve the form fields from the page and then saves the comment using those values. So, the test-only patch will fail twice: once for displaying the wrong date after loading the comment, and once for saving that date to the database.

The fix causes the form to display the correct date, which causes the the correct date to get into the database when the form is saved.

markabur’s picture

Status: Needs work » Needs review
FileSize
4.86 KB
4.16 KB

Same thing but with the comment updated to reflect the renamed function (testCommentEditPreviewSave()).

moshe weitzman’s picture

Priority: Major » Critical
Status: Needs review » Reviewed & tested by the community

IMO it is a critical. Editing a comment is quite routine. One line fix, plus tests.

webchick’s picture

Status: Reviewed & tested by the community » Fixed

Wow, what a horrible problem! Thanks a lot for the fix, and for the test.

Committed to HEAD.

Status: Fixed » Closed (fixed)

Automatically closed -- issue fixed for 2 weeks with no activity.

tmctighe’s picture

Version: 7.x-dev » 7.23
Assigned: markabur » tmctighe
Status: Closed (fixed) » Needs review
FileSize
645 bytes

So this fix never solved the problem for users given the ability to edit their own comments.

In short: a user with the permission "Can edit own comments" edit's their comment, the original creation date is destroyed.

I've attached the fix.

andypost’s picture

Issue summary: View changes
Status: Needs review » Closed (fixed)

The follow-up with test should be ported in #1374090: Editing a comment still changes creation date

xanderol’s picture

Will this fix be making it into core?

7.24 still has the bug.

I applied the patch from #24 and it seems to take care of the problem.

andypost’s picture

Please do not use this issue to report.

Patch #24 nearly he same that was commited to 8.x in #1374090: Editing a comment still changes creation date so just backport the change with test