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.
_______________________________________________ Mailing list: https://launchpad.net/~launchpad-reviewers Post to : launchpad-reviewers@lists.launchpad.net Unsubscribe : https://launchpad.net/~launchpad-reviewers More help : https://help.launchpad.net/ListHelp