← Back to team overview

launchpad-reviewers team mailing list archive

[Merge] ~cjwatson/launchpad:message-revisions-time-rendering into launchpad:master

 

Colin Watson has proposed merging ~cjwatson/launchpad:message-revisions-time-rendering into launchpad:master.

Commit message:
Render message revision timestamps in webapp

Requested reviews:
  Launchpad code reviewers (launchpad-reviewers)
Related bugs:
  Bug #1933079 in Launchpad itself: "answers.launchpad.net timestamp of changes of comment shown in wrong time zone"
  https://bugs.launchpad.net/launchpad/+bug/1933079

For more details, see:
https://code.launchpad.net/~cjwatson/launchpad/+git/launchpad/+merge/404485

This causes them to be displayed according to the user's configured time zone.
-- 
Your team Launchpad code reviewers is requested to review the proposed merge of ~cjwatson/launchpad:message-revisions-time-rendering into launchpad:master.
diff --git a/lib/lp/answers/templates/questionmessage-display.pt b/lib/lp/answers/templates/questionmessage-display.pt
index c1ed29a..49973ab 100644
--- a/lib/lp/answers/templates/questionmessage-display.pt
+++ b/lib/lp/answers/templates/questionmessage-display.pt
@@ -24,7 +24,7 @@
           <div class='message-revision-item'>
             <div class='message-revision-title'>
                 <a class="js-action">
-                    Revision #{revision}, created at  {date_created}
+                    Revision #{revision}, created at {date_created_display}
                 </a>
             </div>
             <div class='message-revision-body'>{content}</div>
diff --git a/lib/lp/bugs/templates/bugcomment-box.pt b/lib/lp/bugs/templates/bugcomment-box.pt
index 34e5789..1e1882a 100644
--- a/lib/lp/bugs/templates/bugcomment-box.pt
+++ b/lib/lp/bugs/templates/bugcomment-box.pt
@@ -24,7 +24,7 @@
         <div class='message-revision-item'>
           <div class='message-revision-title'>
               <a class="js-action">
-                  Revision #{revision}, created at  {date_created}
+                  Revision #{revision}, created at {date_created_display}
               </a>
           </div>
           <div class='message-revision-body'>{content}</div>
diff --git a/lib/lp/code/templates/codereviewcomment-header.pt b/lib/lp/code/templates/codereviewcomment-header.pt
index 3d2b976..3511b9f 100644
--- a/lib/lp/code/templates/codereviewcomment-header.pt
+++ b/lib/lp/code/templates/codereviewcomment-header.pt
@@ -13,7 +13,7 @@
     <div class='message-revision-item'>
       <div class='message-revision-title'>
           <a class="js-action">
-              Revision #{revision}, created at  {date_created}
+              Revision #{revision}, created at {date_created_display}
           </a>
       </div>
       <div class='message-revision-body'>{content}</div>
diff --git a/lib/lp/services/messages/interfaces/messagerevision.py b/lib/lp/services/messages/interfaces/messagerevision.py
index aa0ff0a..43f0c9a 100644
--- a/lib/lp/services/messages/interfaces/messagerevision.py
+++ b/lib/lp/services/messages/interfaces/messagerevision.py
@@ -25,6 +25,7 @@ from zope.schema import (
     Datetime,
     Int,
     Text,
+    TextLine,
     )
 
 from lp import _
@@ -55,6 +56,12 @@ class IMessageRevisionView(Interface):
         title=_("The time when this message revision was created."),
         required=True, readonly=True))
 
+    date_created_display = exported(TextLine(
+        title=_(
+            "The time when this message revision was created, rendered in the "
+            "user's timezone for the web UI."),
+        required=True, readonly=True))
+
     date_deleted = exported(Datetime(
         title=_("The time when this message revision was created."),
         required=False, readonly=True))
diff --git a/lib/lp/services/messages/javascript/messages.edit.js b/lib/lp/services/messages/javascript/messages.edit.js
index c6e79b6..56762e8 100644
--- a/lib/lp/services/messages/javascript/messages.edit.js
+++ b/lib/lp/services/messages/javascript/messages.edit.js
@@ -201,8 +201,6 @@ YUI.add('lp.services.messages.edit', function(Y) {
         var content = "";
         revisions.forEach(function(rev) {
             var attrs = rev.getAttrs();
-            var date_created = new Date(attrs.date_created);
-            attrs.date_created = date_created.toLocaleString();
             attrs.content = module.htmlify_msg(attrs.content);
             content += Y.Lang.sub(template, attrs);
         });
diff --git a/lib/lp/services/messages/javascript/tests/test_messages.edit.html b/lib/lp/services/messages/javascript/tests/test_messages.edit.html
index e6a27c2..9d394c2 100644
--- a/lib/lp/services/messages/javascript/tests/test_messages.edit.html
+++ b/lib/lp/services/messages/javascript/tests/test_messages.edit.html
@@ -74,7 +74,7 @@ GNU Affero General Public License version 3 (see the file LICENSE).
                   <!-- The description of the revision, that will expand the
                    revision content once clicked. -->
                   <div class='message-revision-title'>
-                      <a class="js-action">Revision #{revision}, created at  {date_created}</a>
+                      <a class="js-action">Revision #{revision}, created at {date_created_display}</a>
                   </div>
                   <!-- The revision content itself -->
                   <div class='message-revision-body'>{content}</div>
@@ -119,7 +119,7 @@ GNU Affero General Public License version 3 (see the file LICENSE).
               <script type="text/template">
                 <div class='message-revision-item'>
                   <div class='message-revision-title'>
-                      <a class="js-action">Revision #{revision}, created at {date_created}</a>
+                      <a class="js-action">Revision #{revision}, created at {date_created_display}</a>
                   </div>
                   <div class='message-revision-body'>{content}</div>
                 </div>
diff --git a/lib/lp/services/messages/javascript/tests/test_messages.edit.js b/lib/lp/services/messages/javascript/tests/test_messages.edit.js
index f5cbd39..d9644f0 100644
--- a/lib/lp/services/messages/javascript/tests/test_messages.edit.js
+++ b/lib/lp/services/messages/javascript/tests/test_messages.edit.js
@@ -190,11 +190,11 @@ YUI.add('lp.services.messages.edit.test', function(Y) {
                 "entries": [{
                     "revision": 1,
                     "content": "content 1",
-                    "date_created": "2021-05-10T19:41:36.102749+00:00"
+                    "date_created_display": "2021-05-10 19:41:36 UTC"
                 }, {
                     "revision": 2,
                     "content": "content 2",
-                    "date_created": "2021-05-11T22:17:11.000123+00:00"
+                    "date_created_display": "2021-05-11 22:17:11 UTC"
                 }]
             };
             module.lp_client.io_provider.success({
@@ -216,13 +216,11 @@ YUI.add('lp.services.messages.edit.test', function(Y) {
             revisions.each(function(rev, i) {
                 // Entries are shown in reverse order.
                 var entry = response.entries[response.entries.length - i -1];
-                var date_created = new Date(entry.date_created);
-                entry['formatted_date'] = date_created.toLocaleString();
                 var title = rev.one('.message-revision-title');
                 var body = rev.one('.message-revision-body');
                 var expected_title = Y.Lang.sub(
                     '<a class="js-action">' +
-                    'Revision #{revision}, created at {formatted_date}' +
+                    'Revision #{revision}, created at {date_created_display}' +
                     '</a>',
                     entry);
                 Y.Assert.areSame(
diff --git a/lib/lp/services/messages/model/messagerevision.py b/lib/lp/services/messages/model/messagerevision.py
index 535ff66..5dc20e3 100644
--- a/lib/lp/services/messages/model/messagerevision.py
+++ b/lib/lp/services/messages/model/messagerevision.py
@@ -20,6 +20,7 @@ from storm.locals import (
     )
 from zope.interface import implementer
 
+from lp.app.browser.tales import DateTimeFormatterAPI
 from lp.services.database.constants import UTC_NOW
 from lp.services.database.interfaces import IStore
 from lp.services.database.stormbase import StormBase
@@ -87,6 +88,10 @@ class MessageRevision(StormBase):
     def content(self):
         return '\n\n'.join(i.content for i in self.chunks)
 
+    @property
+    def date_created_display(self):
+        return DateTimeFormatterAPI(self.date_created).datetime()
+
     def deleteContent(self):
         store = IStore(self)
         store.find(MessageRevisionChunk, message_revision=self).remove()
diff --git a/lib/lp/services/messages/tests/test_messagerevision.py b/lib/lp/services/messages/tests/test_messagerevision.py
index 80d1a14..19cc931 100644
--- a/lib/lp/services/messages/tests/test_messagerevision.py
+++ b/lib/lp/services/messages/tests/test_messagerevision.py
@@ -14,6 +14,7 @@ from testtools.matchers import (
 from zope.security.interfaces import Unauthorized
 from zope.security.proxy import ProxyFactory
 
+from lp.app.browser.tales import DateTimeFormatterAPI
 from lp.bugs.interfaces.bugmessage import IBugMessage
 from lp.services.database.interfaces import IStore
 from lp.services.database.sqlbase import get_transaction_timestamp
@@ -85,6 +86,7 @@ class TestMessageRevisionAPI(MessageTypeScenariosMixin, TestCaseWithFactory):
         msg = self.makeMessage(content="initial content")
         msg.editContent("new content 1")
         msg.editContent("final content")
+        dates_created = [revision.date_created for revision in msg.revisions]
         ws = self.getWebservice(self.person)
         url = self.getMessageAPIURL(msg)
         ws_message = ws.get(url).jsonBody()
@@ -95,37 +97,45 @@ class TestMessageRevisionAPI(MessageTypeScenariosMixin, TestCaseWithFactory):
             "total_size": Equals(2)}))
         self.assertThat(revisions["entries"], MatchesListwise([
             ContainsDict({
-                "date_created": Not(Is(None)),
-                "date_deleted": Is(None),
                 "content": Equals("initial content"),
+                "date_created": Equals(dates_created[0].isoformat()),
+                "date_created_display": Equals(
+                    DateTimeFormatterAPI(dates_created[0]).datetime()),
+                "date_deleted": Is(None),
                 "self_link": EndsWith("/revisions/1")
-            }),
+                }),
             ContainsDict({
-                "date_created": Not(Is(None)),
-                "date_deleted": Is(None),
                 "content": Equals("new content 1"),
+                "date_created": Equals(dates_created[1].isoformat()),
+                "date_created_display": Equals(
+                    DateTimeFormatterAPI(dates_created[1]).datetime()),
+                "date_deleted": Is(None),
                 "self_link": EndsWith("/revisions/2")
-            })]))
+                })]))
 
     def test_get_single_revision(self):
         msg = self.makeMessage(content="initial content")
         msg.editContent("new content 1")
+        date_created = msg.revisions[0].date_created
         ws = self.getWebservice(self.person)
 
         with person_logged_in(self.person):
             revision_url = api_url(msg.revisions[0])
         revision = ws.get(revision_url).jsonBody()
         self.assertThat(revision, ContainsDict({
-                "date_created": Not(Is(None)),
-                "date_deleted": Is(None),
-                "content": Equals("initial content"),
-                "self_link": EndsWith("/revisions/1")
+            "content": Equals("initial content"),
+            "date_created": Equals(date_created.isoformat()),
+            "date_created_display": Equals(
+                DateTimeFormatterAPI(date_created).datetime()),
+            "date_deleted": Is(None),
+            "self_link": EndsWith("/revisions/1")
             }))
 
     def test_delete_revision_content(self):
         msg = self.makeMessage(content="initial content")
         msg.editContent("new content 1")
         msg.editContent("final content")
+        dates_created = [revision.date_created for revision in msg.revisions]
 
         with person_logged_in(self.person):
             revision_url = api_url(msg.revisions[0])
@@ -136,16 +146,19 @@ class TestMessageRevisionAPI(MessageTypeScenariosMixin, TestCaseWithFactory):
 
         revision = ws.get(revision_url).jsonBody()
         self.assertThat(revision, ContainsDict({
-            "date_created": Not(Is(None)),
-            "date_deleted": Not(Is(None)),
             "content": Equals(""),
+            "date_created": Equals(dates_created[0].isoformat()),
+            "date_created_display": Equals(
+                DateTimeFormatterAPI(dates_created[0]).datetime()),
+            "date_deleted": Not(Is(None)),
             "self_link": EndsWith("/revisions/1")
-        }))
+            }))
 
     def test_delete_revision_content_denied_for_non_owners(self):
         msg = self.makeMessage(content="initial content")
         msg.editContent("new content 1")
         msg.editContent("final content")
+        dates_created = [revision.date_created for revision in msg.revisions]
         someone_else = self.factory.makePerson()
 
         with person_logged_in(self.person):
@@ -157,9 +170,10 @@ class TestMessageRevisionAPI(MessageTypeScenariosMixin, TestCaseWithFactory):
 
         revision = ws.get(revision_url).jsonBody()
         self.assertThat(revision, ContainsDict({
-            "date_created": Not(Is(None)),
-            "date_deleted": Is(None),
             "content": Equals("initial content"),
+            "date_created": Equals(dates_created[0].isoformat()),
+            "date_created_display": Equals(
+                DateTimeFormatterAPI(dates_created[0]).datetime()),
+            "date_deleted": Is(None),
             "self_link": EndsWith("/revisions/1")
-        }))
-
+            }))