← Back to team overview

launchpad-reviewers team mailing list archive

[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