launchpad-reviewers team mailing list archive
-
launchpad-reviewers team
-
Mailing list archive
-
Message #21015
[Merge] lp:~wgrant/launchpad/unify-person-questions into lp:launchpad
William Grant has proposed merging lp:~wgrant/launchpad/unify-person-questions into lp:launchpad.
Commit message:
Move Person questions views from lp.registry to lp.answers.
Requested reviews:
Launchpad code reviewers (launchpad-reviewers)
For more details, see:
https://code.launchpad.net/~wgrant/launchpad/unify-person-questions/+merge/306685
Move Person questions views from lp.registry to lp.answers.
--
Your team Launchpad code reviewers is requested to review the proposed merge of lp:~wgrant/launchpad/unify-person-questions into lp:launchpad.
=== modified file 'lib/lp/answers/browser/configure.zcml'
--- lib/lp/answers/browser/configure.zcml 2014-04-24 02:53:05 +0000
+++ lib/lp/answers/browser/configure.zcml 2016-09-24 06:34:14 +0000
@@ -385,14 +385,14 @@
/>
<browser:page
for="lp.registry.interfaces.person.IPerson"
- class="lp.registry.browser.person.PersonLatestQuestionsView"
+ class="lp.answers.browser.person.PersonLatestQuestionsView"
name="+portlet-latestquestions"
permission="zope.Public"
template="../templates/questiontarget-portlet-latestquestions.pt"
/>
<browser:page
for="lp.registry.interfaces.person.IPerson"
- class="lp.registry.browser.person.PersonSearchQuestionsView"
+ class="lp.answers.browser.person.PersonSearchQuestionsView"
name="+questions"
permission="zope.Public"
/>
@@ -404,7 +404,7 @@
/>
<browser:page
for="lp.registry.interfaces.person.IPerson"
- class="lp.registry.browser.person.SearchAnsweredQuestionsView"
+ class="lp.answers.browser.person.SearchAnsweredQuestionsView"
name="+answeredquestions"
permission="zope.Public"
/>
@@ -416,7 +416,7 @@
/>
<browser:page
for="lp.registry.interfaces.person.IPerson"
- class="lp.registry.browser.person.SearchAssignedQuestionsView"
+ class="lp.answers.browser.person.SearchAssignedQuestionsView"
name="+assignedquestions"
permission="zope.Public"
/>
@@ -428,7 +428,7 @@
/>
<browser:page
for="lp.registry.interfaces.person.IPerson"
- class="lp.registry.browser.person.SearchCommentedQuestionsView"
+ class="lp.answers.browser.person.SearchCommentedQuestionsView"
name="+commentedquestions"
permission="zope.Public"
/>
@@ -440,7 +440,7 @@
/>
<browser:page
for="lp.registry.interfaces.person.IPerson"
- class="lp.registry.browser.person.SearchCreatedQuestionsView"
+ class="lp.answers.browser.person.SearchCreatedQuestionsView"
name="+createdquestions"
permission="zope.Public"
/>
@@ -452,7 +452,7 @@
/>
<browser:page
for="lp.registry.interfaces.person.IPerson"
- class="lp.registry.browser.person.SearchNeedAttentionQuestionsView"
+ class="lp.answers.browser.person.SearchNeedAttentionQuestionsView"
name="+needattentionquestions"
permission="zope.Public"
/>
@@ -464,7 +464,7 @@
/>
<browser:page
for="lp.registry.interfaces.person.IPerson"
- class="lp.registry.browser.person.SearchSubscribedQuestionsView"
+ class="lp.answers.browser.person.SearchSubscribedQuestionsView"
name="+subscribedquestions"
permission="zope.Public"
/>
@@ -476,13 +476,13 @@
/>
<browser:page
for="lp.registry.interfaces.person.IPerson"
- class="lp.registry.browser.person.PersonAnswerContactForView"
+ class="lp.answers.browser.person.PersonAnswerContactForView"
name="+answer-contact-for"
permission="zope.Public"
template="../templates/person-answer-contact-for.pt"
/>
<browser:menus
- module="lp.registry.browser.person"
+ module="lp.answers.browser.person"
classes="PersonAnswersMenu"
/>
<browser:page
=== added file 'lib/lp/answers/browser/person.py'
--- lib/lp/answers/browser/person.py 1970-01-01 00:00:00 +0000
+++ lib/lp/answers/browser/person.py 2016-09-24 06:34:14 +0000
@@ -0,0 +1,278 @@
+# Copyright 2009-2014 Canonical Ltd. This software is licensed under the
+# GNU Affero General Public License version 3 (see the file LICENSE).
+
+"""Person-related answer listing classes."""
+
+__metaclass__ = type
+__all__ = [
+ 'PersonAnswerContactForView',
+ 'PersonAnswersMenu',
+ 'PersonLatestQuestionsView',
+ 'PersonSearchQuestionsView',
+ 'SearchAnsweredQuestionsView',
+ 'SearchAssignedQuestionsView',
+ 'SearchCommentedQuestionsView',
+ 'SearchCreatedQuestionsView',
+ 'SearchNeedAttentionQuestionsView',
+ 'SearchSubscribedQuestionsView',
+ ]
+
+
+from operator import attrgetter
+
+from lp import _
+from lp.answers.browser.questiontarget import SearchQuestionsView
+from lp.answers.enums import QuestionParticipation
+from lp.answers.interfaces.questionsperson import IQuestionsPerson
+from lp.app.browser.launchpadform import LaunchpadFormView
+from lp.registry.interfaces.person import IPerson
+from lp.services.propertycache import cachedproperty
+from lp.services.webapp import (
+ Link,
+ NavigationMenu,
+ )
+from lp.services.webapp.publisher import LaunchpadView
+
+
+class PersonLatestQuestionsView(LaunchpadFormView):
+ """View used by the porlet displaying the latest questions made by
+ a person.
+ """
+
+ @cachedproperty
+ def getLatestQuestions(self, quantity=5):
+ """Return <quantity> latest questions created for this target. """
+ return IQuestionsPerson(self.context).searchQuestions(
+ participation=QuestionParticipation.OWNER)[:quantity]
+
+
+class PersonSearchQuestionsView(SearchQuestionsView):
+ """View to search and display questions that involve an `IPerson`."""
+
+ display_target_column = True
+
+ @property
+ def template(self):
+ # Persons always show the default template.
+ return self.default_template
+
+ @property
+ def pageheading(self):
+ """See `SearchQuestionsView`."""
+ return _('Questions involving $name',
+ mapping=dict(name=self.context.displayname))
+
+ @property
+ def empty_listing_message(self):
+ """See `SearchQuestionsView`."""
+ return _('No questions involving $name found with the '
+ 'requested statuses.',
+ mapping=dict(name=self.context.displayname))
+
+
+class SearchAnsweredQuestionsView(PersonSearchQuestionsView):
+ """View used to search and display questions answered by an IPerson."""
+
+ def getDefaultFilter(self):
+ """See `SearchQuestionsView`."""
+ return dict(participation=QuestionParticipation.ANSWERER)
+
+ @property
+ def pageheading(self):
+ """See `SearchQuestionsView`."""
+ return _('Questions answered by $name',
+ mapping=dict(name=self.context.displayname))
+
+ @property
+ def empty_listing_message(self):
+ """See `SearchQuestionsView`."""
+ return _('No questions answered by $name found with the '
+ 'requested statuses.',
+ mapping=dict(name=self.context.displayname))
+
+
+class SearchAssignedQuestionsView(PersonSearchQuestionsView):
+ """View used to search and display questions assigned to an IPerson."""
+
+ def getDefaultFilter(self):
+ """See `SearchQuestionsView`."""
+ return dict(participation=QuestionParticipation.ASSIGNEE)
+
+ @property
+ def pageheading(self):
+ """See `SearchQuestionsView`."""
+ return _('Questions assigned to $name',
+ mapping=dict(name=self.context.displayname))
+
+ @property
+ def empty_listing_message(self):
+ """See `SearchQuestionsView`."""
+ return _('No questions assigned to $name found with the '
+ 'requested statuses.',
+ mapping=dict(name=self.context.displayname))
+
+
+class SearchCommentedQuestionsView(PersonSearchQuestionsView):
+ """View used to search and show questions commented on by an IPerson."""
+
+ def getDefaultFilter(self):
+ """See `SearchQuestionsView`."""
+ return dict(participation=QuestionParticipation.COMMENTER)
+
+ @property
+ def pageheading(self):
+ """See `SearchQuestionsView`."""
+ return _('Questions commented on by $name ',
+ mapping=dict(name=self.context.displayname))
+
+ @property
+ def empty_listing_message(self):
+ """See `SearchQuestionsView`."""
+ return _('No questions commented on by $name found with the '
+ 'requested statuses.',
+ mapping=dict(name=self.context.displayname))
+
+
+class SearchCreatedQuestionsView(PersonSearchQuestionsView):
+ """View used to search and display questions created by an IPerson."""
+
+ def getDefaultFilter(self):
+ """See `SearchQuestionsView`."""
+ return dict(participation=QuestionParticipation.OWNER)
+
+ @property
+ def pageheading(self):
+ """See `SearchQuestionsView`."""
+ return _('Questions asked by $name',
+ mapping=dict(name=self.context.displayname))
+
+ @property
+ def empty_listing_message(self):
+ """See `SearchQuestionsView`."""
+ return _('No questions asked by $name found with the '
+ 'requested statuses.',
+ mapping=dict(name=self.context.displayname))
+
+
+class SearchNeedAttentionQuestionsView(PersonSearchQuestionsView):
+ """View used to search and show questions needing an IPerson attention."""
+
+ def getDefaultFilter(self):
+ """See `SearchQuestionsView`."""
+ return dict(needs_attention=True)
+
+ @property
+ def pageheading(self):
+ """See `SearchQuestionsView`."""
+ return _("Questions needing $name's attention",
+ mapping=dict(name=self.context.displayname))
+
+ @property
+ def empty_listing_message(self):
+ """See `SearchQuestionsView`."""
+ return _("No questions need $name's attention.",
+ mapping=dict(name=self.context.displayname))
+
+
+class SearchSubscribedQuestionsView(PersonSearchQuestionsView):
+ """View used to search and show questions subscribed to by an IPerson."""
+
+ def getDefaultFilter(self):
+ """See `SearchQuestionsView`."""
+ return dict(participation=QuestionParticipation.SUBSCRIBER)
+
+ @property
+ def pageheading(self):
+ """See `SearchQuestionsView`."""
+ return _('Questions $name is subscribed to',
+ mapping=dict(name=self.context.displayname))
+
+ @property
+ def empty_listing_message(self):
+ """See `SearchQuestionsView`."""
+ return _('No questions subscribed to by $name found with the '
+ 'requested statuses.',
+ mapping=dict(name=self.context.displayname))
+
+
+class PersonAnswerContactForView(LaunchpadView):
+ """View used to show all the IQuestionTargets that an IPerson is an answer
+ contact for.
+ """
+
+ @property
+ def label(self):
+ return 'Projects for which %s is an answer contact' % (
+ self.context.displayname)
+
+ page_title = label
+
+ @cachedproperty
+ def direct_question_targets(self):
+ """List of targets that the IPerson is a direct answer contact.
+
+ Return a list of IQuestionTargets sorted alphabetically by title.
+ """
+ return sorted(
+ IQuestionsPerson(self.context).getDirectAnswerQuestionTargets(),
+ key=attrgetter('title'))
+
+ @cachedproperty
+ def team_question_targets(self):
+ """List of IQuestionTargets for the context's team membership.
+
+ Sorted alphabetically by title.
+ """
+ return sorted(
+ IQuestionsPerson(self.context).getTeamAnswerQuestionTargets(),
+ key=attrgetter('title'))
+
+ def showRemoveYourselfLink(self):
+ """The link is shown when the page is in the user's own profile."""
+ return self.user == self.context
+
+
+class PersonAnswersMenu(NavigationMenu):
+
+ usedfor = IPerson
+ facet = 'answers'
+ links = ['answered', 'assigned', 'created', 'commented', 'need_attention',
+ 'subscribed', 'answer_contact_for']
+
+ def answer_contact_for(self):
+ summary = "Projects for which %s is an answer contact" % (
+ self.context.displayname)
+ return Link(
+ '+answer-contact-for', 'Answer contact for', summary, icon='edit')
+
+ def answered(self):
+ summary = 'Questions answered by %s' % self.context.displayname
+ return Link(
+ '+answeredquestions', 'Answered', summary, icon='question')
+
+ def assigned(self):
+ summary = 'Questions assigned to %s' % self.context.displayname
+ return Link(
+ '+assignedquestions', 'Assigned', summary, icon='question')
+
+ def created(self):
+ summary = 'Questions asked by %s' % self.context.displayname
+ return Link('+createdquestions', 'Asked', summary, icon='question')
+
+ def commented(self):
+ summary = 'Questions commented on by %s' % (
+ self.context.displayname)
+ return Link(
+ '+commentedquestions', 'Commented', summary, icon='question')
+
+ def need_attention(self):
+ summary = 'Questions needing %s attention' % (
+ self.context.displayname)
+ return Link('+needattentionquestions', 'Need attention', summary,
+ icon='question')
+
+ def subscribed(self):
+ text = 'Subscribed'
+ summary = 'Questions subscribed to by %s' % (
+ self.context.displayname)
+ return Link('+subscribedquestions', text, summary, icon='question')
=== modified file 'lib/lp/registry/browser/person.py'
--- lib/lp/registry/browser/person.py 2016-07-28 00:26:13 +0000
+++ lib/lp/registry/browser/person.py 2016-09-24 06:34:14 +0000
@@ -11,8 +11,6 @@
'PeopleSearchView',
'PersonAccountAdministerView',
'PersonAdministerView',
- 'PersonAnswerContactForView',
- 'PersonAnswersMenu',
'PersonBrandingView',
'PersonBreadcrumb',
'PersonCodeOfConductEditView',
@@ -29,7 +27,6 @@
'PersonIndexView',
'PersonKarmaView',
'PersonLanguagesView',
- 'PersonLatestQuestionsView',
'PersonNavigation',
'PersonOAuthTokensView',
'PersonOverviewMenu',
@@ -38,7 +35,6 @@
'PersonRdfView',
'PersonRelatedSoftwareView',
'PersonRenameFormMixin',
- 'PersonSearchQuestionsView',
'PersonSetActionNavigationMenu',
'PersonSetContextMenu',
'PersonSetNavigation',
@@ -47,12 +43,6 @@
'PPANavigationMenuMixIn',
'RedirectToEditLanguagesView',
'RestrictedMembershipsPersonView',
- 'SearchAnsweredQuestionsView',
- 'SearchAssignedQuestionsView',
- 'SearchCommentedQuestionsView',
- 'SearchCreatedQuestionsView',
- 'SearchNeedAttentionQuestionsView',
- 'SearchSubscribedQuestionsView',
'archive_to_person',
]
@@ -109,9 +99,6 @@
from zope.security.proxy import removeSecurityProxy
from lp import _
-from lp.answers.browser.questiontarget import SearchQuestionsView
-from lp.answers.enums import QuestionParticipation
-from lp.answers.interfaces.questionsperson import IQuestionsPerson
from lp.app.browser.launchpadform import (
action,
custom_widget,
@@ -3320,250 +3307,6 @@
self.next_url = self.action_url
-class PersonLatestQuestionsView(LaunchpadFormView):
- """View used by the porlet displaying the latest questions made by
- a person.
- """
-
- @cachedproperty
- def getLatestQuestions(self, quantity=5):
- """Return <quantity> latest questions created for this target. """
- return IQuestionsPerson(self.context).searchQuestions(
- participation=QuestionParticipation.OWNER)[:quantity]
-
-
-class PersonSearchQuestionsView(SearchQuestionsView):
- """View to search and display questions that involve an `IPerson`."""
-
- display_target_column = True
-
- @property
- def template(self):
- # Persons always show the default template.
- return self.default_template
-
- @property
- def pageheading(self):
- """See `SearchQuestionsView`."""
- return _('Questions involving $name',
- mapping=dict(name=self.context.displayname))
-
- @property
- def empty_listing_message(self):
- """See `SearchQuestionsView`."""
- return _('No questions involving $name found with the '
- 'requested statuses.',
- mapping=dict(name=self.context.displayname))
-
-
-class SearchAnsweredQuestionsView(PersonSearchQuestionsView):
- """View used to search and display questions answered by an IPerson."""
-
- def getDefaultFilter(self):
- """See `SearchQuestionsView`."""
- return dict(participation=QuestionParticipation.ANSWERER)
-
- @property
- def pageheading(self):
- """See `SearchQuestionsView`."""
- return _('Questions answered by $name',
- mapping=dict(name=self.context.displayname))
-
- @property
- def empty_listing_message(self):
- """See `SearchQuestionsView`."""
- return _('No questions answered by $name found with the '
- 'requested statuses.',
- mapping=dict(name=self.context.displayname))
-
-
-class SearchAssignedQuestionsView(PersonSearchQuestionsView):
- """View used to search and display questions assigned to an IPerson."""
-
- def getDefaultFilter(self):
- """See `SearchQuestionsView`."""
- return dict(participation=QuestionParticipation.ASSIGNEE)
-
- @property
- def pageheading(self):
- """See `SearchQuestionsView`."""
- return _('Questions assigned to $name',
- mapping=dict(name=self.context.displayname))
-
- @property
- def empty_listing_message(self):
- """See `SearchQuestionsView`."""
- return _('No questions assigned to $name found with the '
- 'requested statuses.',
- mapping=dict(name=self.context.displayname))
-
-
-class SearchCommentedQuestionsView(PersonSearchQuestionsView):
- """View used to search and show questions commented on by an IPerson."""
-
- def getDefaultFilter(self):
- """See `SearchQuestionsView`."""
- return dict(participation=QuestionParticipation.COMMENTER)
-
- @property
- def pageheading(self):
- """See `SearchQuestionsView`."""
- return _('Questions commented on by $name ',
- mapping=dict(name=self.context.displayname))
-
- @property
- def empty_listing_message(self):
- """See `SearchQuestionsView`."""
- return _('No questions commented on by $name found with the '
- 'requested statuses.',
- mapping=dict(name=self.context.displayname))
-
-
-class SearchCreatedQuestionsView(PersonSearchQuestionsView):
- """View used to search and display questions created by an IPerson."""
-
- def getDefaultFilter(self):
- """See `SearchQuestionsView`."""
- return dict(participation=QuestionParticipation.OWNER)
-
- @property
- def pageheading(self):
- """See `SearchQuestionsView`."""
- return _('Questions asked by $name',
- mapping=dict(name=self.context.displayname))
-
- @property
- def empty_listing_message(self):
- """See `SearchQuestionsView`."""
- return _('No questions asked by $name found with the '
- 'requested statuses.',
- mapping=dict(name=self.context.displayname))
-
-
-class SearchNeedAttentionQuestionsView(PersonSearchQuestionsView):
- """View used to search and show questions needing an IPerson attention."""
-
- def getDefaultFilter(self):
- """See `SearchQuestionsView`."""
- return dict(needs_attention=True)
-
- @property
- def pageheading(self):
- """See `SearchQuestionsView`."""
- return _("Questions needing $name's attention",
- mapping=dict(name=self.context.displayname))
-
- @property
- def empty_listing_message(self):
- """See `SearchQuestionsView`."""
- return _("No questions need $name's attention.",
- mapping=dict(name=self.context.displayname))
-
-
-class SearchSubscribedQuestionsView(PersonSearchQuestionsView):
- """View used to search and show questions subscribed to by an IPerson."""
-
- def getDefaultFilter(self):
- """See `SearchQuestionsView`."""
- return dict(participation=QuestionParticipation.SUBSCRIBER)
-
- @property
- def pageheading(self):
- """See `SearchQuestionsView`."""
- return _('Questions $name is subscribed to',
- mapping=dict(name=self.context.displayname))
-
- @property
- def empty_listing_message(self):
- """See `SearchQuestionsView`."""
- return _('No questions subscribed to by $name found with the '
- 'requested statuses.',
- mapping=dict(name=self.context.displayname))
-
-
-class PersonAnswerContactForView(LaunchpadView):
- """View used to show all the IQuestionTargets that an IPerson is an answer
- contact for.
- """
-
- @property
- def label(self):
- return 'Projects for which %s is an answer contact' % (
- self.context.displayname)
-
- page_title = label
-
- @cachedproperty
- def direct_question_targets(self):
- """List of targets that the IPerson is a direct answer contact.
-
- Return a list of IQuestionTargets sorted alphabetically by title.
- """
- return sorted(
- IQuestionsPerson(self.context).getDirectAnswerQuestionTargets(),
- key=attrgetter('title'))
-
- @cachedproperty
- def team_question_targets(self):
- """List of IQuestionTargets for the context's team membership.
-
- Sorted alphabetically by title.
- """
- return sorted(
- IQuestionsPerson(self.context).getTeamAnswerQuestionTargets(),
- key=attrgetter('title'))
-
- def showRemoveYourselfLink(self):
- """The link is shown when the page is in the user's own profile."""
- return self.user == self.context
-
-
-class PersonAnswersMenu(NavigationMenu):
-
- usedfor = IPerson
- facet = 'answers'
- links = ['answered', 'assigned', 'created', 'commented', 'need_attention',
- 'subscribed', 'answer_contact_for']
-
- def answer_contact_for(self):
- summary = "Projects for which %s is an answer contact" % (
- self.context.displayname)
- return Link(
- '+answer-contact-for', 'Answer contact for', summary, icon='edit')
-
- def answered(self):
- summary = 'Questions answered by %s' % self.context.displayname
- return Link(
- '+answeredquestions', 'Answered', summary, icon='question')
-
- def assigned(self):
- summary = 'Questions assigned to %s' % self.context.displayname
- return Link(
- '+assignedquestions', 'Assigned', summary, icon='question')
-
- def created(self):
- summary = 'Questions asked by %s' % self.context.displayname
- return Link('+createdquestions', 'Asked', summary, icon='question')
-
- def commented(self):
- summary = 'Questions commented on by %s' % (
- self.context.displayname)
- return Link(
- '+commentedquestions', 'Commented', summary, icon='question')
-
- def need_attention(self):
- summary = 'Questions needing %s attention' % (
- self.context.displayname)
- return Link('+needattentionquestions', 'Need attention', summary,
- icon='question')
-
- def subscribed(self):
- text = 'Subscribed'
- summary = 'Questions subscribed to by %s' % (
- self.context.displayname)
- return Link('+subscribedquestions', text, summary, icon='question')
-
-
class BaseWithStats:
"""An ISourcePackageRelease or a ISourcePackagePublishingHistory,
with extra stats added.
Follow ups