Merge lp:~sinzui/launchpad/unassign-bugs-0 into lp:launchpad

Proposed by Curtis Hovey
Status: Merged
Approved by: Brad Crittenden
Approved revision: no longer in the source branch.
Merged at revision: 14653
Proposed branch: lp:~sinzui/launchpad/unassign-bugs-0
Merge into: lp:launchpad
Diff against target: 204 lines (+7/-109)
4 files modified
lib/lp/bugs/interfaces/bugtask.py (+1/-6)
lib/lp/bugs/model/bugtask.py (+2/-9)
lib/lp/bugs/model/tests/test_bugtask.py (+4/-62)
lib/lp/bugs/stories/bugtask-management/xx-change-assignee.txt (+0/-32)
To merge this branch: bzr merge lp:~sinzui/launchpad/unassign-bugs-0
Reviewer Review Type Date Requested Status
Brad Crittenden (community) code Approve
Review via email: mp+87785@code.launchpad.net

Description of the change

Permit logged in users to unassign bugs.

    Launchpad bug: https://bugs.launchpad.net/bugs/910876
       Also fixes: https://bugs.launchpad.net/bugs/910879
       Also fixes: https://bugs.launchpad.net/bugs/783271
    Pre-implementation: flacoste

Summary of bug 910876:
Lp has some complex logic to determine when to show the "Remove assignee"
action in the picker. The rules are easily subverted by users by assigning
themselves, then they have permission to remove themselves. The rules
for unassignment mirror the rules for assignment, but there are no cases
where users abused unassignment. Lp forces contributors to take awkward
steps in the UI or they use API do complete their task.

--------------------------------------------------------------------

RULES

    * Revert userCanUnassign to the 2009 rules, any logged in user
      can unassign form a bug.
      * This fix closes one or more other bugs

QA

    * As a user not in a project role, eg
      Visit https://bugs.qastaging.launchpad.net/pyflakes/+bug/848467
    * verify the picker shows the "Remove assignee" action.

LINT

    lib/lp/bugs/interfaces/bugtask.py
    lib/lp/bugs/model/bugtask.py
    lib/lp/bugs/model/tests/test_bugtask.py
    lib/lp/bugs/stories/bugtask-management/xx-change-assignee.txt

TEST

    ./bin/test -vvc -t test_userCanUnassign lp.bugs.model.tests.test_bugtask
    ./bin/test -vvc -t xx-change-assignee lp.bugs.tests.test_doc

IMPLEMENTATION

Updated userCanUnassign to only check for a logged in user.
    lib/lp/bugs/interfaces/bugtask.py
    lib/lp/bugs/model/bugtask.py

Removed redundant tests...the tests only need to check an anonymous
case and a logged in user case. Project roles are unimportant.
    lib/lp/bugs/model/tests/test_bugtask.py
    lib/lp/bugs/stories/bugtask-management/xx-change-assignee.txt

To post a comment you must log in.
Revision history for this message
Brad Crittenden (bac) wrote :

Branch looks good Curtis. Lots of nice red.

review: Approve (code)

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'lib/lp/bugs/interfaces/bugtask.py'
2--- lib/lp/bugs/interfaces/bugtask.py 2012-01-03 15:56:55 +0000
3+++ lib/lp/bugs/interfaces/bugtask.py 2012-01-06 17:27:12 +0000
4@@ -841,12 +841,7 @@
5 """
6
7 def userCanUnassign(user):
8- """Check if the current user can set assignee to None.
9-
10- Project owner, project drivers, series drivers, bug supervisors
11- and Launchpad admins can do this always; other users can do this
12- only if they or their reams are the assignee.
13- """
14+ """Check if the current user can set assignee to None."""
15
16 @mutator_for(assignee)
17 @operation_parameters(
18
19=== modified file 'lib/lp/bugs/model/bugtask.py'
20--- lib/lp/bugs/model/bugtask.py 2012-01-02 17:10:14 +0000
21+++ lib/lp/bugs/model/bugtask.py 2012-01-06 17:27:12 +0000
22@@ -1093,15 +1093,8 @@
23 return self.userHasBugSupervisorPrivileges(user)
24
25 def userCanUnassign(self, user):
26- """True if user can set the assignee to None.
27-
28- This option not shown for regular users unless they or their teams
29- are the assignees. Project owners, drivers, bug supervisors and
30- Launchpad admins can always unassign.
31- """
32- return user is not None and (
33- user.inTeam(self.assignee) or
34- self.userHasBugSupervisorPrivileges(user))
35+ """See `IBugTask`."""
36+ return user is not None
37
38 def canTransitionToAssignee(self, assignee):
39 """See `IBugTask`."""
40
41=== modified file 'lib/lp/bugs/model/tests/test_bugtask.py'
42--- lib/lp/bugs/model/tests/test_bugtask.py 2011-12-30 06:14:56 +0000
43+++ lib/lp/bugs/model/tests/test_bugtask.py 2012-01-06 17:27:12 +0000
44@@ -769,24 +769,16 @@
45 self.assertTrue(
46 self.series_bugtask.userCanSetAnyAssignee(self.regular_user))
47
48- def test_userCanUnassign_regular_user(self):
49- # Ordinary users can unassign themselves...
50- login_person(self.regular_user)
51- self.assertEqual(self.target_bugtask.assignee, self.regular_user)
52- self.assertEqual(self.series_bugtask.assignee, self.regular_user)
53- self.assertTrue(
54- self.target_bugtask.userCanUnassign(self.regular_user))
55- self.assertTrue(
56- self.series_bugtask.userCanUnassign(self.regular_user))
57- # ...but not other assignees.
58+ def test_userCanUnassign_logged_in_user(self):
59+ # Ordinary users can unassign any user or team.
60 login_person(self.target_owner_member)
61 other_user = self.factory.makePerson()
62 self.series_bugtask.transitionToAssignee(other_user)
63 self.target_bugtask.transitionToAssignee(other_user)
64 login_person(self.regular_user)
65- self.assertFalse(
66+ self.assertTrue(
67 self.target_bugtask.userCanUnassign(self.regular_user))
68- self.assertFalse(
69+ self.assertTrue(
70 self.series_bugtask.userCanUnassign(self.regular_user))
71
72 def test_userCanSetAnyAssignee_target_owner(self):
73@@ -797,14 +789,6 @@
74 self.assertTrue(
75 self.series_bugtask.userCanSetAnyAssignee(self.target.owner))
76
77- def test_userCanUnassign_target_owner(self):
78- # The target owner can unassign anybody.
79- login_person(self.target_owner_member)
80- self.assertTrue(
81- self.target_bugtask.userCanUnassign(self.target_owner_member))
82- self.assertTrue(
83- self.series_bugtask.userCanUnassign(self.target_owner_member))
84-
85 def test_userCanSetAnyAssignee_bug_supervisor(self):
86 # A bug supervisor can assign anybody.
87 if self.supervisor_member is not None:
88@@ -816,15 +800,6 @@
89 self.series_bugtask.userCanSetAnyAssignee(
90 self.supervisor_member))
91
92- def test_userCanUnassign_bug_supervisor(self):
93- # A bug supervisor can unassign anybody.
94- if self.supervisor_member is not None:
95- login_person(self.supervisor_member)
96- self.assertTrue(
97- self.target_bugtask.userCanUnassign(self.supervisor_member))
98- self.assertTrue(
99- self.series_bugtask.userCanUnassign(self.supervisor_member))
100-
101 def test_userCanSetAnyAssignee_driver(self):
102 # A project driver can assign anybody.
103 login_person(self.driver_member)
104@@ -833,14 +808,6 @@
105 self.assertTrue(
106 self.series_bugtask.userCanSetAnyAssignee(self.driver_member))
107
108- def test_userCanUnassign_driver(self):
109- # A project driver can unassign anybody.
110- login_person(self.driver_member)
111- self.assertTrue(
112- self.target_bugtask.userCanUnassign(self.driver_member))
113- self.assertTrue(
114- self.series_bugtask.userCanUnassign(self.driver_member))
115-
116 def test_userCanSetAnyAssignee_series_driver(self):
117 # A series driver can assign anybody to series bug tasks.
118 login_person(self.driver_member)
119@@ -858,15 +825,6 @@
120 self.target_bugtask.userCanSetAnyAssignee(
121 self.series_driver_member))
122
123- def test_userCanUnassign_series_driver(self):
124- # The target owner can unassign anybody from series bug tasks...
125- login_person(self.series_driver_member)
126- self.assertTrue(
127- self.series_bugtask.userCanUnassign(self.series_driver_member))
128- # ...but not from tasks of the main product/distribution.
129- self.assertFalse(
130- self.target_bugtask.userCanUnassign(self.series_driver_member))
131-
132 def test_userCanSetAnyAssignee_launchpad_admins(self):
133 # Launchpad admins can assign anybody.
134 login_person(self.target_owner_member)
135@@ -875,14 +833,6 @@
136 self.assertTrue(self.target_bugtask.userCanSetAnyAssignee(foo_bar))
137 self.assertTrue(self.series_bugtask.userCanSetAnyAssignee(foo_bar))
138
139- def test_userCanUnassign_launchpad_admins(self):
140- # Launchpad admins can unassign anybody.
141- login_person(self.target_owner_member)
142- foo_bar = getUtility(IPersonSet).getByEmail('foo.bar@canonical.com')
143- login_person(foo_bar)
144- self.assertTrue(self.target_bugtask.userCanUnassign(foo_bar))
145- self.assertTrue(self.series_bugtask.userCanUnassign(foo_bar))
146-
147 def test_userCanSetAnyAssignee_bug_importer(self):
148 # The bug importer celebrity can assign anybody.
149 login_person(self.target_owner_member)
150@@ -893,14 +843,6 @@
151 self.assertTrue(
152 self.series_bugtask.userCanSetAnyAssignee(bug_importer))
153
154- def test_userCanUnassign_launchpad_bug_importer(self):
155- # The bug importer celebrity can unassign anybody.
156- login_person(self.target_owner_member)
157- bug_importer = getUtility(ILaunchpadCelebrities).bug_importer
158- login_person(bug_importer)
159- self.assertTrue(self.target_bugtask.userCanUnassign(bug_importer))
160- self.assertTrue(self.series_bugtask.userCanUnassign(bug_importer))
161-
162
163 class TestProductBugTaskPermissionsToSetAssignee(
164 TestBugTaskPermissionsToSetAssigneeMixin, TestCaseWithFactory):
165
166=== modified file 'lib/lp/bugs/stories/bugtask-management/xx-change-assignee.txt'
167--- lib/lp/bugs/stories/bugtask-management/xx-change-assignee.txt 2011-12-24 15:18:32 +0000
168+++ lib/lp/bugs/stories/bugtask-management/xx-change-assignee.txt 2012-01-06 17:27:12 +0000
169@@ -157,35 +157,3 @@
170 There is 1 error in the data you entered. Please fix it and try again.
171 (Find…)
172 Constraint not satisfied
173-
174-The unassign option is only shown if the current assignee is the user
175-or one of his teams...
176-
177- >>> user_browser.open("http://bugs.launchpad.dev/jokosher/+bug/11")
178- >>> assignee_control = user_browser.getControl(
179- ... name="jokosher.assignee.option", index=0)
180- >>> assignee_control.value = ["jokosher.assignee.assign_to_nobody"]
181- >>> user_browser.getControl("Save Changes", index=0).click()
182-
183-...or if there is no assignee.
184-
185- >>> assignee_control = user_browser.getControl(
186- ... name="jokosher.assignee.option", index=0)
187- >>> assignee_control.value = ["jokosher.assignee.assign_to_nobody"]
188-
189-If the bugtask is assigned to anybody else, the unassign option is not
190-shown.
191-
192- >>> admin_browser.open("http://bugs.launchpad.dev/jokosher/+bug/11")
193- >>> assignee_control = admin_browser.getControl(
194- ... name="jokosher.assignee.option", index=0)
195- >>> assignee_control.value = ["jokosher.assignee.assign_to_me"]
196- >>> admin_browser.getControl("Save Changes", index=0).click()
197- >>> user_browser.open("http://bugs.launchpad.dev/jokosher/+bug/11")
198- >>> assignee_control = user_browser.getControl(
199- ... name="jokosher.assignee.option", index=0)
200- >>> assignee_control.value = ["jokosher.assignee.assign_to_nobody"]
201- Traceback (most recent call last):
202- ...
203- ItemNotFoundError: insufficient items with name
204- 'jokosher.assignee.assign_to_nobody'