Merge lp:~andrea.corbellini/launchpad/blueprint-comments-part3 into lp:launchpad

Proposed by Andrea Corbellini
Status: Work in progress
Proposed branch: lp:~andrea.corbellini/launchpad/blueprint-comments-part3
Merge into: lp:launchpad
Diff against target: 351 lines (+237/-8)
5 files modified
lib/lp/blueprints/configure.zcml (+88/-1)
lib/lp/blueprints/doc/specification.txt (+49/-0)
lib/lp/blueprints/interfaces/specification.py (+17/-5)
lib/lp/blueprints/interfaces/specificationmessage.py (+27/-2)
lib/lp/blueprints/model/specification.py (+56/-0)
To merge this branch: bzr merge lp:~andrea.corbellini/launchpad/blueprint-comments-part3
Reviewer Review Type Date Requested Status
Brad Crittenden (community) code Needs Resubmitting
Eleanor Berger (community) Approve
Review via email: mp+16291@code.launchpad.net
To post a comment you must log in.
Revision history for this message
Andrea Corbellini (andrea.corbellini) wrote :

This branch contains the model work needed for blueprint comments.

* I created two new interfaces: ISpecificationComment and ISpecificationMessageAddForm. Currently they are not used but will be needed for displaying in the web UI.
* I also added some new attributes to ISpecification: messages, newMessage, linkMessage, getMessageChunks.
* Finally I added tests at the end of lib/lp/blueprints/doc/specification.txt.

To test the changes: bin/test -t specification.txt

Revision history for this message
Eleanor Berger (intellectronica) wrote :

Andrea, thanks again for taking on this work. And well done, the branch looks in great shape. We can't land it just yet, since the tree is closed, but I'm marking it approved and you can continue with the UI branch building on top of this one.

review: Approve
10065. By Andrea Corbellini

Merge with devel.

10066. By Andrea Corbellini

Allow missing attributes.

10067. By Andrea Corbellini

Merge with devel.

Revision history for this message
Martin Pool (mbp) wrote :

Can we land this now?

Revision history for this message
Andrea Corbellini (andrea.corbellini) wrote :

Unfortunately no, sorry. The PQM said some tests failed. I'm almost sure the problem is caused by the fact that some attributes are missing from the <allow> directives in the configure.zcml file.

I'd fix the errors, but unfortunately in this period I don't have the time to run the full test suite.

Revision history for this message
Brad Crittenden (bac) wrote :

I am changing the status of this branch to Work in progress as it will now need significant work before landing and will need a re-review. Andrea I hope you can pick this work up again when you have time.

review: Needs Resubmitting (code)
Revision history for this message
Robert Collins (lifeless) wrote :

It may not need significant work.

Running it through ec2 once will return a subunit file listing all of
the failing tests, allowing it to be worked on much more simply than
by running the full test suite.

Unmerged revisions

10067. By Andrea Corbellini

Merge with devel.

10066. By Andrea Corbellini

Allow missing attributes.

10065. By Andrea Corbellini

Merge with devel.

10064. By Andrea Corbellini

Lint code.

10063. By Andrea Corbellini

Adjust permissions.

10062. By Andrea Corbellini

Add tests.

10061. By Andrea Corbellini

Add the missing imports.

10060. By Andrea Corbellini

Add the code for the new attributes and methods.

10059. By Andrea Corbellini

Set permissions for the new methods.

10058. By Andrea Corbellini

Add `linkMessage()` to ISpecification.

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
=== modified file 'lib/lp/blueprints/configure.zcml'
--- lib/lp/blueprints/configure.zcml 2009-09-23 03:36:55 +0000
+++ lib/lp/blueprints/configure.zcml 2010-02-16 12:43:20 +0000
@@ -157,7 +157,84 @@
157 <class157 <class
158 class="lp.blueprints.model.specification.Specification">158 class="lp.blueprints.model.specification.Specification">
159 <allow159 <allow
160 interface="lp.blueprints.interfaces.specification.ISpecification"/>160 attributes="
161 linkBranch
162 unlinkBranch
163 unqueue
164 getBranchLink
165 messages
166 all_blocked
167 goal_proposer
168 getSubscriptionByName
169 owner
170 linked_branches
171 productseries
172 getFeedbackRequests
173 id
174 createDependency
175 sprints
176 queue
177 man_days
178 removeDependency
179 goal
180 linkMessage
181 date_goal_proposed
182 priority
183 date_goal_decided
184 declineBy
185 date_started
186 has_accepted_goal
187 goalstatus
188 is_started
189 getSprintSpecification
190 product
191 getDelta
192 subscriptions
193 sprint_links
194 feedbackrequests
195 retarget
196 unlinkSprint
197 dependencies
198 unsubscribe
199 subscribers
200 milestone
201 linkSprint
202 updateLifecycleStatus
203 is_blocked
204 completer
205 is_incomplete
206 starter
207 subscription
208 notificationRecipientAddresses
209 is_complete
210 date_completed
211 direction_approved
212 subscribe
213 isSubscribed
214 superseded_by
215 distroseries
216 whiteboard
217 proposeGoal
218 datecreated
219 blocked_specs
220 all_deps
221 distribution
222 getMessageChunks
223 informational
224 goal_decider
225 implementation_status
226 acceptBy
227 name
228 title
229 approver
230 definition_status
231 summary
232 assignee
233 specurl
234 drafter
235 target
236 specification_branch
237 mentoring_offers"/>
161238
162 <!-- We allow any authenticated person to update the whiteboard -->239 <!-- We allow any authenticated person to update the whiteboard -->
163240
@@ -185,6 +262,14 @@
185 attributes="262 attributes="
186 linkBug263 linkBug
187 unlinkBug"/>264 unlinkBug"/>
265 <require
266 permission="launchpad.Edit"
267 attributes="
268 newMessage"/>
269 <require
270 permission="launchpad.Admin"
271 attributes="
272 setCommentVisibility"/>
188 </class>273 </class>
189 <class274 <class
190 class="lp.blueprints.model.specificationbug.SpecificationBug">275 class="lp.blueprints.model.specificationbug.SpecificationBug">
@@ -232,6 +317,8 @@
232 class="lp.blueprints.model.specificationmessage.SpecificationMessage">317 class="lp.blueprints.model.specificationmessage.SpecificationMessage">
233 <allow318 <allow
234 interface="lp.blueprints.interfaces.specificationmessage.ISpecificationMessage"/>319 interface="lp.blueprints.interfaces.specificationmessage.ISpecificationMessage"/>
320 <require permission="launchpad.Admin"
321 set_attributes="visible"/>
235 </class>322 </class>
236323
237 <!-- SpecificationMessageSet -->324 <!-- SpecificationMessageSet -->
238325
=== modified file 'lib/lp/blueprints/doc/specification.txt'
--- lib/lp/blueprints/doc/specification.txt 2009-08-13 19:03:36 +0000
+++ lib/lp/blueprints/doc/specification.txt 2010-02-16 12:43:20 +0000
@@ -531,3 +531,52 @@
531 False531 False
532 >>> canvas.date_completed is not None532 >>> canvas.date_completed is not None
533 False533 False
534
535
536== Specification comments ==
537
538A comment can be added to a specification using the `newMessage()` method:
539
540 >>> spec = specset.new(
541 ... 'spec-for-comments', 'Spec for comments',
542 ... 'http://www.example.com/SpecForComments',
543 ... 'Specification used to test comments',
544 ... SpecificationDefinitionStatus.APPROVED, mark,
545 ... distribution=ubuntu)
546 >>> message = spec.newMessage(mark, 'Subject', 'First comment.')
547
548All messages are stored in `messages`.
549
550 >>> message in spec.messages
551 True
552
553The message chunks associated to a blueprint can be obtained with the method
554`getMessageChunks()`.
555
556 >>> chunks = spec.getMessageChunks()
557 >>> len(chunks)
558 1
559 >>> chunk = chunks[0]
560 >>> chunk.message.subject
561 u'Subject'
562 >>> chunk.content
563 u'First comment.'
564
565All comments are visible by default, but they can be hidden by an
566administrator using `setCommentVisibility()`.
567
568 >>> from zope.component import getUtility
569 >>> from lp.blueprints.interfaces.specificationmessage import (
570 ... ISpecificationMessageSet)
571 >>> message_set = getUtility(ISpecificationMessageSet)
572 >>> comment = message_set.getBySpecificationAndMessage(
573 ... spec, spec.messages[0])
574
575 >>> comment.visible
576 True
577 >>> spec.setCommentVisibility(mark, 0, False)
578 >>> comment.visible
579 False
580
581 >>> check_permission('launchpad.Admin', spec.setCommentVisibility)
582 True
534583
=== modified file 'lib/lp/blueprints/interfaces/specification.py'
--- lib/lp/blueprints/interfaces/specification.py 2009-07-17 00:26:05 +0000
+++ lib/lp/blueprints/interfaces/specification.py 2010-02-16 12:43:20 +0000
@@ -26,10 +26,7 @@
26 ]26 ]
2727
2828
29from lazr.restful.declarations import (29from lazr.restful.declarations import export_as_webservice_entry
30 REQUEST_USER, call_with, export_as_webservice_entry,
31 export_write_operation, operation_parameters, operation_returns_entry)
32from lazr.restful.fields import Reference
33from zope.interface import Interface, Attribute30from zope.interface import Interface, Attribute
34from zope.component import getUtility31from zope.component import getUtility
3532
@@ -40,7 +37,6 @@
40 ContentNameField, PublicPersonChoice, Summary, Title)37 ContentNameField, PublicPersonChoice, Summary, Title)
41from canonical.launchpad.validators import LaunchpadValidationError38from canonical.launchpad.validators import LaunchpadValidationError
42from lp.registry.interfaces.role import IHasOwner39from lp.registry.interfaces.role import IHasOwner
43from lp.code.interfaces.branch import IBranch
44from lp.code.interfaces.branchlink import IHasLinkedBranches40from lp.code.interfaces.branchlink import IHasLinkedBranches
45from lp.registry.interfaces.mentoringoffer import ICanBeMentored41from lp.registry.interfaces.mentoringoffer import ICanBeMentored
46from canonical.launchpad.interfaces.validation import valid_webref42from canonical.launchpad.interfaces.validation import valid_webref
@@ -879,6 +875,22 @@
879 def getBranchLink(branch):875 def getBranchLink(branch):
880 """Return the SpecificationBranch link for the branch, or None."""876 """Return the SpecificationBranch link for the branch, or None."""
881877
878 # comments
879 messages = Attribute("The specification messages related to this object.")
880
881 def newMessage(owner, subject, content):
882 """Create a new message and link it to this specification."""
883
884 def linkMessage(message, user):
885 """Link a message to this specification."""
886
887 def getMessageChunks():
888 """Return MessageChunks linked to comments made on this specification
889 """
890
891 def setCommentVisibility(user, comment_number, visible):
892 """Set the `visible` attribute on a specification comment."""
893
882894
883# Interfaces for containers895# Interfaces for containers
884class ISpecificationSet(IHasSpecifications):896class ISpecificationSet(IHasSpecifications):
885897
=== modified file 'lib/lp/blueprints/interfaces/specificationmessage.py'
--- lib/lp/blueprints/interfaces/specificationmessage.py 2009-08-10 12:34:20 +0000
+++ lib/lp/blueprints/interfaces/specificationmessage.py 2010-02-16 12:43:20 +0000
@@ -12,8 +12,9 @@
12 ]12 ]
1313
14from lazr.restful.fields import Reference14from lazr.restful.fields import Reference
15from zope.interface import Interface15from zope.interface import Attribute, Interface
16from zope.schema import Bool, Int16from zope.schema import Bool, Int, Text
17from canonical.launchpad.fields import Title
1718
18from lp.blueprints.interfaces.specification import ISpecification19from lp.blueprints.interfaces.specification import ISpecification
19from canonical.launchpad.interfaces.message import IMessage20from canonical.launchpad.interfaces.message import IMessage
@@ -54,3 +55,27 @@
5455
55 Return None if no such ISpecificationMesssage exists.56 Return None if no such ISpecificationMesssage exists.
56 """57 """
58
59
60class ISpecificationComment(IMessage):
61 """A specification comment for displaying in the web UI."""
62
63 specification = Attribute(u"The specification the comments belongs to.")
64 show_for_admin = Bool(
65 title=u"A hidden comment still displayed for admins.",
66 readonly=True)
67 index = Int(title=u"The comment number.", required=True, readonly=True)
68 was_truncated = Bool(
69 title=u"Whether the displayed text was truncated for display.",
70 readonly=True)
71 text_for_display = Text(
72 title=u"The comment text to be displayed in the UI.", readonly=True)
73 display_title = Attribute(u"Whether or not to show the title.")
74
75
76class ISpecificationMessageAddForm(Interface):
77 """Schema used to build the add form for specification comment.
78 """
79
80 subject = Title(title=u"Subject", required=True)
81 comment = Text(title=u"Comment", required=False)
5782
=== modified file 'lib/lp/blueprints/model/specification.py'
--- lib/lp/blueprints/model/specification.py 2009-09-21 14:56:07 +0000
+++ lib/lp/blueprints/model/specification.py 2010-02-16 12:43:20 +0000
@@ -10,8 +10,11 @@
10 'SpecificationSet',10 'SpecificationSet',
11 ]11 ]
1212
13from email.Utils import make_msgid
14
13from storm.store import Store15from storm.store import Store
1416
17from zope.component import getUtility
15from zope.interface import implements18from zope.interface import implements
16from zope.event import notify19from zope.event import notify
1720
@@ -33,6 +36,7 @@
33from canonical.database.constants import DEFAULT, UTC_NOW36from canonical.database.constants import DEFAULT, UTC_NOW
34from canonical.database.datetimecol import UtcDateTimeCol37from canonical.database.datetimecol import UtcDateTimeCol
35from canonical.database.enumcol import EnumCol38from canonical.database.enumcol import EnumCol
39from canonical.launchpad.database.message import Message, MessageChunk
3640
37from canonical.launchpad.helpers import (41from canonical.launchpad.helpers import (
38 get_contact_email_addresses, shortlist)42 get_contact_email_addresses, shortlist)
@@ -55,6 +59,10 @@
55 SprintSpecification)59 SprintSpecification)
56from lp.blueprints.model.sprint import Sprint60from lp.blueprints.model.sprint import Sprint
5761
62from lp.blueprints.model.specificationmessage import SpecificationMessage
63from lp.blueprints.interfaces.specificationmessage import (
64 ISpecificationMessageSet)
65
58from lazr.lifecycle.objectdelta import ObjectDelta66from lazr.lifecycle.objectdelta import ObjectDelta
59from lp.blueprints.adapters import SpecificationDelta67from lp.blueprints.adapters import SpecificationDelta
6068
@@ -652,6 +660,54 @@
652 spec_branch = self.getBranchLink(branch)660 spec_branch = self.getBranchLink(branch)
653 spec_branch.destroySelf()661 spec_branch.destroySelf()
654662
663 # comments
664 messages = SQLRelatedJoin(
665 'Message', joinColumn='specification', otherColumn='message',
666 intermediateTable='SpecificationMessage', prejoins=['owner'],
667 orderBy=['datecreated', 'id'])
668
669 def newMessage(self, owner, subject=None, content=None):
670 """See `ISpecification`."""
671 if subject is None:
672 subject = self.followup_subject()
673 msg = Message(
674 owner=owner, subject=subject,
675 rfc822msgid=make_msgid('blueprints'))
676 MessageChunk(message=msg, content=content, sequence=1)
677 specmsg = self.linkMessage(msg)
678 if not specmsg:
679 return
680 notify(ObjectCreatedEvent(specmsg, user=owner))
681 return specmsg.message
682
683 def linkMessage(self, message, user=None):
684 """See `ISpecification`."""
685 if message not in self.messages:
686 if user is None:
687 user = message.owner
688 return SpecificationMessage(specification=self, message=message)
689
690 def getMessageChunks(self):
691 """See `ISpecification`."""
692 query = """
693 SpecificationMessage.specification = %s AND
694 Message.id = MessageChunk.message AND
695 SpecificationMessage.message = Message.id
696 """ % sqlvalues(self)
697 chunks = MessageChunk.select(
698 query, clauseTables=['SpecificationMessage', 'Message'],
699 prejoinClauseTables=['Message'],
700 orderBy=['Message.datecreated', 'Message.id',
701 'MessageChunk.sequence'])
702 return list(chunks)
703
704 def setCommentVisibility(self, user, comment_number, visible):
705 """See `ISpecification`."""
706 message_set = getUtility(ISpecificationMessageSet)
707 message = message_set.getBySpecificationAndMessage(
708 self, self.messages[comment_number])
709 message.visible = visible
710
655711
656class HasSpecificationsMixin:712class HasSpecificationsMixin:
657 """A mixin class that implements many of the common shortcut properties713 """A mixin class that implements many of the common shortcut properties