12156.1.3
by Brad Crittenden
Updated copyright |
1 |
# Copyright 2009-2011 Canonical Ltd. This software is licensed under the
|
8687.15.17
by Karl Fogel
Add the copyright header block to the rest of the files under lib/lp/. |
2 |
# GNU Affero General Public License version 3 (see the file LICENSE).
|
4962.5.8
by Guilherme Salgado
Lots of refactorings |
3 |
|
4 |
"""People Merge related wiew classes."""
|
|
5 |
||
6 |
__metaclass__ = type |
|
7 |
||
8 |
__all__ = [ |
|
9 |
'AdminPeopleMergeView', |
|
10 |
'AdminTeamMergeView', |
|
10085.5.8
by Curtis Hovey
Revised comments and documentation. |
11 |
'DeleteTeamView', |
4962.5.8
by Guilherme Salgado
Lots of refactorings |
12 |
'FinishedPeopleMergeRequestView', |
13 |
'RequestPeopleMergeMultipleEmailsView', |
|
10123.4.5
by Brad Crittenden
Removed breadcrumbs as they showed up on other /people pages. Simplified page template. |
14 |
'RequestPeopleMergeView', |
15 |
]
|
|
4962.5.8
by Guilherme Salgado
Lots of refactorings |
16 |
|
5653.2.1
by Maris Fogels
Changed occurrances of addError() so that the conform to the new API. Fixed a number of broken msgids. |
17 |
|
4962.5.8
by Guilherme Salgado
Lots of refactorings |
18 |
from zope.component import getUtility |
12043.3.2
by Curtis Hovey
Use a single import for removeSecurityProxy. |
19 |
from zope.security.proxy import removeSecurityProxy |
4962.5.8
by Guilherme Salgado
Lots of refactorings |
20 |
|
14600.1.12
by Curtis Hovey
Move i18n to lp. |
21 |
from lp import _ |
11929.9.1
by Tim Penhey
Move launchpadform into lp.app.browser. |
22 |
from lp.app.browser.launchpadform import ( |
23 |
action, |
|
24 |
LaunchpadFormView, |
|
25 |
)
|
|
13130.1.12
by Curtis Hovey
Sorted imports. |
26 |
from lp.app.interfaces.launchpad import ILaunchpadCelebrities |
11818.6.17
by Curtis Hovey
Restored the check for the purged state to AdminTeamMergeView (but placed it |
27 |
from lp.registry.interfaces.mailinglist import ( |
28 |
MailingListStatus, |
|
29 |
PURGE_STATES, |
|
30 |
)
|
|
7675.110.3
by Curtis Hovey
Ran the migration script to move registry code to lp.registry. |
31 |
from lp.registry.interfaces.person import ( |
11403.1.4
by Henning Eggers
Reformatted imports using format-imports script r32. |
32 |
IAdminPeopleMergeSchema, |
33 |
IAdminTeamMergeSchema, |
|
34 |
IPersonSet, |
|
35 |
IRequestPeopleMerge, |
|
36 |
)
|
|
14612.2.1
by William Grant
format-imports on lib/. So many imports. |
37 |
from lp.services.database.lpstorm import IMasterObject |
14550.1.1
by Steve Kowalik
Run format-imports over lib/lp and lib/canonical/launchpad |
38 |
from lp.services.identity.interfaces.emailaddress import ( |
39 |
EmailAddressStatus, |
|
40 |
IEmailAddressSet, |
|
41 |
)
|
|
11818.6.3
by Curtis Hovey
Moved the merge super team rule into the base view to ensure the right behaviour is honoured if the user uses merge instead of delete. |
42 |
from lp.services.propertycache import cachedproperty |
14612.2.1
by William Grant
format-imports on lib/. So many imports. |
43 |
from lp.services.verification.interfaces.authtoken import LoginTokenType |
44 |
from lp.services.verification.interfaces.logintoken import ILoginTokenSet |
|
45 |
from lp.services.webapp import ( |
|
46 |
canonical_url, |
|
47 |
LaunchpadView, |
|
48 |
)
|
|
49 |
from lp.services.webapp.interfaces import ILaunchBag |
|
12156.1.1
by Brad Crittenden
Removed has_existing_ppa and has_ppa_with_published_packages from IPerson. Modified IArchiveSet.getPPAOwnedByPerson to replace those two ill-placed methods. |
50 |
from lp.soyuz.enums import ArchiveStatus |
51 |
from lp.soyuz.interfaces.archive import IArchiveSet |
|
4962.5.8
by Guilherme Salgado
Lots of refactorings |
52 |
|
53 |
||
12167.1.5
by j.c.sackett
Updated validator. |
54 |
class ValidatingMergeView(LaunchpadFormView): |
12167.1.6
by j.c.sackett
Lint fixes. |
55 |
|
12167.1.5
by j.c.sackett
Updated validator. |
56 |
def validate(self, data): |
57 |
"""Check that user is not attempting to merge a person into itself."""
|
|
58 |
dupe_person = data.get('dupe_person') |
|
12760.1.4
by Curtis Hovey
Added a test to verify an IPerson cannot merge into himself; fixed validator. |
59 |
target_person = data.get('target_person') or self.user |
12760.1.11
by Curtis Hovey
Explain that the duplicate person/team must be active. |
60 |
if dupe_person is None: |
61 |
self.setFieldError( |
|
62 |
'dupe_person', 'The duplicate is not a valid person or team.') |
|
63 |
else: |
|
64 |
if dupe_person == target_person: |
|
65 |
self.addError(_("You can't merge ${name} into itself.", |
|
66 |
mapping=dict(name=dupe_person.name))) |
|
12167.1.5
by j.c.sackett
Updated validator. |
67 |
dupe_person_ppas = getUtility(IArchiveSet).getPPAOwnedByPerson( |
68 |
dupe_person, statuses=[ArchiveStatus.ACTIVE, |
|
69 |
ArchiveStatus.DELETING]) |
|
70 |
if dupe_person_ppas is not None: |
|
71 |
self.addError(_( |
|
72 |
"${name} has a PPA that must be deleted before it " |
|
73 |
"can be merged. It may take ten minutes to remove the "
|
|
74 |
"deleted PPA's files.", |
|
75 |
mapping=dict(name=dupe_person.name))) |
|
12760.1.4
by Curtis Hovey
Added a test to verify an IPerson cannot merge into himself; fixed validator. |
76 |
if dupe_person.is_merge_pending: |
77 |
self.addError(_("${name} is already queued for merging.", |
|
78 |
mapping=dict(name=dupe_person.name))) |
|
79 |
if target_person is not None and target_person.is_merge_pending: |
|
80 |
self.addError(_("${name} is already queued for merging.", |
|
81 |
mapping=dict(name=target_person.name))) |
|
82 |
||
12167.1.5
by j.c.sackett
Updated validator. |
83 |
|
84 |
class AdminMergeBaseView(ValidatingMergeView): |
|
4962.5.8
by Guilherme Salgado
Lots of refactorings |
85 |
"""Base view for the pages where admins can merge people/teams."""
|
86 |
||
11118.3.7
by Curtis Hovey
Added missing page titles to malone index and admin merge. Removed obsolete test. |
87 |
page_title = 'Merge Launchpad accounts' |
4962.5.8
by Guilherme Salgado
Lots of refactorings |
88 |
# Both subclasses share the same template so we need to define these
|
89 |
# variables (which are used in the template) here rather than on
|
|
90 |
# subclasses.
|
|
91 |
should_confirm_email_reassignment = False |
|
92 |
should_confirm_member_deactivation = False |
|
12760.1.9
by Curtis Hovey
Updated the merge views to queue a merge job. |
93 |
merge_message = _( |
94 |
'A merge is queued and is expected to complete in a few minutes.') |
|
4962.5.8
by Guilherme Salgado
Lots of refactorings |
95 |
|
96 |
dupe_person_emails = () |
|
97 |
dupe_person = None |
|
98 |
target_person = None |
|
13555.6.1
by Robert Collins
Refactor team deletes to let the model code know that a delete is requested. |
99 |
delete = False |
4962.5.8
by Guilherme Salgado
Lots of refactorings |
100 |
|
9271.3.3
by Guilherme Salgado
convert merge pages |
101 |
@property
|
102 |
def cancel_url(self): |
|
103 |
return canonical_url(getUtility(IPersonSet)) |
|
104 |
||
10085.5.4
by Curtis Hovey
Refactored merging to accommodate the team delete scenario. |
105 |
@property
|
10085.5.7
by Curtis Hovey
Restored the next_url behaviour to the base merge form. |
106 |
def success_url(self): |
10085.5.4
by Curtis Hovey
Refactored merging to accommodate the team delete scenario. |
107 |
return canonical_url(self.target_person) |
108 |
||
4962.5.8
by Guilherme Salgado
Lots of refactorings |
109 |
def render(self): |
110 |
# Subclasses may define other actions that they will render manually
|
|
111 |
# only in certain circunstances, so don't include them in the list of
|
|
112 |
# actions to be rendered.
|
|
113 |
self.actions = [self.merge_action] |
|
114 |
return super(AdminMergeBaseView, self).render() |
|
115 |
||
4962.5.10
by Guilherme Salgado
Add/improve a couple docstrings and rename a method. |
116 |
def setUpPeople(self, data): |
117 |
"""Store the people to be merged in instance variables.
|
|
118 |
||
119 |
Also store all emails associated with the dupe account in an
|
|
120 |
instance variable.
|
|
121 |
"""
|
|
4962.5.8
by Guilherme Salgado
Lots of refactorings |
122 |
emailset = getUtility(IEmailAddressSet) |
123 |
self.dupe_person = data['dupe_person'] |
|
13555.6.1
by Robert Collins
Refactor team deletes to let the model code know that a delete is requested. |
124 |
self.target_person = data.get('target_person', None) |
4962.5.8
by Guilherme Salgado
Lots of refactorings |
125 |
self.dupe_person_emails = emailset.getByPerson(self.dupe_person) |
126 |
||
127 |
def doMerge(self, data): |
|
12394.1.1
by Gavin Panella
Improve the docs around some uses of PersonSet.merge(). |
128 |
"""Merge the two person/team entries specified in the form.
|
129 |
||
130 |
Before merging this moves each email address of the duplicate person
|
|
131 |
to the target person, and resets them to `NEW`.
|
|
132 |
"""
|
|
12651.1.10
by Curtis Hovey
Removed team purge rules from merge views. |
133 |
if not self.dupe_person.is_team: |
134 |
# Transfer user email addresses. Team addresses will be deleted.
|
|
135 |
for email in self.dupe_person_emails: |
|
136 |
email = IMasterObject(email) |
|
137 |
# EmailAddress.person and EmailAddress.account are readonly
|
|
138 |
# fields, so we need to remove the security proxy here.
|
|
139 |
naked_email = removeSecurityProxy(email) |
|
140 |
naked_email.personID = self.target_person.id |
|
141 |
naked_email.accountID = self.target_person.accountID |
|
142 |
naked_email.status = EmailAddressStatus.NEW |
|
13303.11.22
by Aaron Bentley
Fix lint. |
143 |
getUtility(IPersonSet).mergeAsync( |
13555.6.1
by Robert Collins
Refactor team deletes to let the model code know that a delete is requested. |
144 |
self.dupe_person, self.target_person, reviewer=self.user, |
145 |
delete=self.delete) |
|
10085.5.4
by Curtis Hovey
Refactored merging to accommodate the team delete scenario. |
146 |
self.request.response.addInfoNotification(self.merge_message) |
10085.5.7
by Curtis Hovey
Restored the next_url behaviour to the base merge form. |
147 |
self.next_url = self.success_url |
4962.5.8
by Guilherme Salgado
Lots of refactorings |
148 |
|
149 |
||
150 |
class AdminPeopleMergeView(AdminMergeBaseView): |
|
4962.5.10
by Guilherme Salgado
Add/improve a couple docstrings and rename a method. |
151 |
"""A view for merging two Persons.
|
152 |
||
153 |
If the duplicate person has any email addresses associated with we'll
|
|
154 |
ask the user to confirm that it's okay to reassign these emails to the
|
|
155 |
other account. We do it because the fact that the dupe person still has
|
|
156 |
email addresses is a possible indication that the admin may be merging
|
|
157 |
the wrong person.
|
|
158 |
"""
|
|
4962.5.8
by Guilherme Salgado
Lots of refactorings |
159 |
|
160 |
label = "Merge Launchpad people" |
|
161 |
schema = IAdminPeopleMergeSchema |
|
162 |
||
163 |
@action('Merge', name='merge') |
|
164 |
def merge_action(self, action, data): |
|
165 |
"""Merge the two person entries specified in the form.
|
|
166 |
||
167 |
If we're merging a person which has email addresses associated with
|
|
168 |
we'll ask for confirmation before actually performing the merge.
|
|
169 |
"""
|
|
4962.5.10
by Guilherme Salgado
Add/improve a couple docstrings and rename a method. |
170 |
self.setUpPeople(data) |
4962.5.8
by Guilherme Salgado
Lots of refactorings |
171 |
if self.dupe_person_emails.count() > 0: |
172 |
# We're merging a person which has one or more email addresses,
|
|
173 |
# so we better warn the admin doing the operation and have him
|
|
174 |
# check the emails that will be reassigned to ensure he's not
|
|
175 |
# doing anything stupid.
|
|
176 |
self.should_confirm_email_reassignment = True |
|
177 |
return
|
|
178 |
self.doMerge(data) |
|
179 |
||
180 |
@action('Reassign E-mails and Merge', name='reassign_emails_and_merge') |
|
181 |
def reassign_emails_and_merge_action(self, action, data): |
|
182 |
"""Reassign emails of the person to be merged and merge them."""
|
|
4962.5.10
by Guilherme Salgado
Add/improve a couple docstrings and rename a method. |
183 |
self.setUpPeople(data) |
4962.5.8
by Guilherme Salgado
Lots of refactorings |
184 |
self.doMerge(data) |
185 |
||
186 |
||
187 |
class AdminTeamMergeView(AdminMergeBaseView): |
|
188 |
"""A view for merging two Teams.
|
|
189 |
||
4962.5.10
by Guilherme Salgado
Add/improve a couple docstrings and rename a method. |
190 |
The duplicate team cannot be associated with a mailing list and if it
|
191 |
has any active members we'll ask for confirmation from the user as we'll
|
|
192 |
need to deactivate all members before we can do the merge.
|
|
4962.5.8
by Guilherme Salgado
Lots of refactorings |
193 |
"""
|
194 |
||
195 |
label = "Merge Launchpad teams" |
|
196 |
schema = IAdminTeamMergeSchema |
|
197 |
||
10085.5.2
by Curtis Hovey
Added support for team owners and moderators to delete teams. |
198 |
def hasMailingList(self, team): |
11818.6.17
by Curtis Hovey
Restored the check for the purged state to AdminTeamMergeView (but placed it |
199 |
unused_states = [state for state in PURGE_STATES] |
200 |
unused_states.append(MailingListStatus.PURGED) |
|
10085.5.2
by Curtis Hovey
Added support for team owners and moderators to delete teams. |
201 |
return ( |
202 |
team.mailing_list is not None |
|
11818.6.17
by Curtis Hovey
Restored the check for the purged state to AdminTeamMergeView (but placed it |
203 |
and team.mailing_list.status not in unused_states) |
11818.6.1
by Curtis Hovey
Allow team owner to purge their lists. Automatically purge a purgable list when deleting a team. Use bold text to inform the owner that he needs to purge the list first. |
204 |
|
11818.6.3
by Curtis Hovey
Moved the merge super team rule into the base view to ensure the right behaviour is honoured if the user uses merge instead of delete. |
205 |
@cachedproperty
|
206 |
def registry_experts(self): |
|
207 |
return getUtility(ILaunchpadCelebrities).registry_experts |
|
208 |
||
4962.5.8
by Guilherme Salgado
Lots of refactorings |
209 |
def validate(self, data): |
210 |
"""Check there are no mailing lists associated with the dupe team."""
|
|
8752.1.1
by Brad Crittenden
Properly handle invalid teams when merging. |
211 |
# If errors have already been discovered there is no need to continue,
|
212 |
# especially since some of our expected data may be missing in the
|
|
213 |
# case of user-entered invalid data.
|
|
214 |
if len(self.errors) > 0: |
|
215 |
return
|
|
216 |
||
4962.5.8
by Guilherme Salgado
Lots of refactorings |
217 |
super(AdminTeamMergeView, self).validate(data) |
7675.286.1
by Guilherme Salgado
Fix the bug by preventing teams with superteams from being merged |
218 |
dupe_team = data['dupe_person'] |
6821.5.19
by Barry Warsaw
Finish up team merges. |
219 |
# We cannot merge the teams if there is a mailing list on the
|
220 |
# duplicate person, unless that mailing list is purged.
|
|
10085.5.2
by Curtis Hovey
Added support for team owners and moderators to delete teams. |
221 |
if self.hasMailingList(dupe_team): |
4962.5.8
by Guilherme Salgado
Lots of refactorings |
222 |
self.addError(_( |
5653.2.1
by Maris Fogels
Changed occurrances of addError() so that the conform to the new API. Fixed a number of broken msgids. |
223 |
"${name} is associated with a Launchpad mailing list; we " |
7675.286.1
by Guilherme Salgado
Fix the bug by preventing teams with superteams from being merged |
224 |
"can't merge it.", mapping=dict(name=dupe_team.name))) |
4962.5.8
by Guilherme Salgado
Lots of refactorings |
225 |
|
226 |
@action('Merge', name='merge') |
|
227 |
def merge_action(self, action, data): |
|
228 |
"""Merge the two team entries specified in the form.
|
|
229 |
||
230 |
A confirmation will be asked if the team we're merging from still
|
|
231 |
has active members, as in that case we'll have to deactivate all
|
|
232 |
members first.
|
|
233 |
"""
|
|
4962.5.10
by Guilherme Salgado
Add/improve a couple docstrings and rename a method. |
234 |
self.setUpPeople(data) |
4962.5.8
by Guilherme Salgado
Lots of refactorings |
235 |
if self.dupe_person.activemembers.count() > 0: |
236 |
# Merging teams with active members is not possible, so we'll
|
|
237 |
# ask the admin if he wants to deactivate all members and then
|
|
238 |
# merge.
|
|
239 |
self.should_confirm_member_deactivation = True |
|
240 |
return
|
|
12651.1.10
by Curtis Hovey
Removed team purge rules from merge views. |
241 |
super(AdminTeamMergeView, self).doMerge(data) |
4962.5.8
by Guilherme Salgado
Lots of refactorings |
242 |
|
243 |
@action('Deactivate Members and Merge', |
|
244 |
name='deactivate_members_and_merge') |
|
245 |
def deactivate_members_and_merge_action(self, action, data): |
|
246 |
"""Deactivate all members of the team to be merged and merge them."""
|
|
4962.5.10
by Guilherme Salgado
Add/improve a couple docstrings and rename a method. |
247 |
self.setUpPeople(data) |
12651.1.10
by Curtis Hovey
Removed team purge rules from merge views. |
248 |
super(AdminTeamMergeView, self).doMerge(data) |
4962.5.8
by Guilherme Salgado
Lots of refactorings |
249 |
|
250 |
||
10085.5.2
by Curtis Hovey
Added support for team owners and moderators to delete teams. |
251 |
class DeleteTeamView(AdminTeamMergeView): |
252 |
"""A view that deletes a team by merging it with Registry experts."""
|
|
253 |
||
254 |
page_title = 'Delete' |
|
13555.6.1
by Robert Collins
Refactor team deletes to let the model code know that a delete is requested. |
255 |
field_names = ['dupe_person'] |
12760.1.9
by Curtis Hovey
Updated the merge views to queue a merge job. |
256 |
merge_message = _('The team is queued to be deleted.') |
10085.5.2
by Curtis Hovey
Added support for team owners and moderators to delete teams. |
257 |
|
258 |
@property
|
|
259 |
def label(self): |
|
260 |
return 'Delete %s' % self.context.displayname |
|
261 |
||
262 |
def __init__(self, context, request): |
|
263 |
super(DeleteTeamView, self).__init__(context, request) |
|
13555.6.1
by Robert Collins
Refactor team deletes to let the model code know that a delete is requested. |
264 |
if ('field.dupe_person' in self.request.form): |
10085.5.8
by Curtis Hovey
Revised comments and documentation. |
265 |
# These fields have fixed values and are managed by this method.
|
266 |
# The user has crafted a request to gain ownership of the dupe
|
|
267 |
# team's assets.
|
|
268 |
self.addError('Unable to process submitted data.') |
|
10085.5.5
by Curtis Hovey
Added tests to verify teams with lists cannot be deleted. |
269 |
elif 'field.actions.delete' in self.request.form: |
10085.5.2
by Curtis Hovey
Added support for team owners and moderators to delete teams. |
270 |
# In the case of deleting a team, the form values are always
|
271 |
# the context team, and the registry experts team. These values
|
|
272 |
# are injected during __init__ because the base classes assume the
|
|
10085.5.8
by Curtis Hovey
Revised comments and documentation. |
273 |
# values are submitted. The validations performed by the base
|
10085.5.2
by Curtis Hovey
Added support for team owners and moderators to delete teams. |
274 |
# classes are still required to ensure the team can be deleted.
|
10085.5.4
by Curtis Hovey
Refactored merging to accommodate the team delete scenario. |
275 |
self.request.form.update(self.default_values) |
10085.5.5
by Curtis Hovey
Added tests to verify teams with lists cannot be deleted. |
276 |
else: |
277 |
# Show the page explaining the action.
|
|
278 |
pass
|
|
10085.5.4
by Curtis Hovey
Refactored merging to accommodate the team delete scenario. |
279 |
|
280 |
@property
|
|
281 |
def default_values(self): |
|
282 |
return { |
|
283 |
'field.dupe_person': self.context.name, |
|
13555.6.1
by Robert Collins
Refactor team deletes to let the model code know that a delete is requested. |
284 |
'field.delete': True, |
10085.5.4
by Curtis Hovey
Refactored merging to accommodate the team delete scenario. |
285 |
}
|
10085.5.2
by Curtis Hovey
Added support for team owners and moderators to delete teams. |
286 |
|
287 |
@property
|
|
288 |
def cancel_url(self): |
|
289 |
return canonical_url(self.context) |
|
290 |
||
291 |
@property
|
|
10085.5.7
by Curtis Hovey
Restored the next_url behaviour to the base merge form. |
292 |
def success_url(self): |
10085.5.4
by Curtis Hovey
Refactored merging to accommodate the team delete scenario. |
293 |
return canonical_url(getUtility(IPersonSet)) |
294 |
||
295 |
@property
|
|
10085.5.2
by Curtis Hovey
Added support for team owners and moderators to delete teams. |
296 |
def has_mailing_list(self): |
297 |
return self.hasMailingList(self.context) |
|
298 |
||
299 |
def canDelete(self, data): |
|
300 |
return not self.has_mailing_list |
|
301 |
||
302 |
@action('Delete', name='delete', condition=canDelete) |
|
303 |
def merge_action(self, action, data): |
|
304 |
base = super(DeleteTeamView, self) |
|
13555.6.1
by Robert Collins
Refactor team deletes to let the model code know that a delete is requested. |
305 |
self.delete = True |
10085.5.2
by Curtis Hovey
Added support for team owners and moderators to delete teams. |
306 |
base.deactivate_members_and_merge_action.success(data) |
307 |
||
308 |
||
4962.5.8
by Guilherme Salgado
Lots of refactorings |
309 |
class FinishedPeopleMergeRequestView(LaunchpadView): |
310 |
"""A simple view for a page where we only tell the user that we sent the
|
|
311 |
email with further instructions to complete the merge.
|
|
312 |
||
313 |
This view is used only when the dupe account has a single email address.
|
|
314 |
"""
|
|
10085.5.2
by Curtis Hovey
Added support for team owners and moderators to delete teams. |
315 |
|
13980.3.16
by Curtis Hovey
Moved person-mergerequest-sent page_title into view. |
316 |
page_title = 'Merge request sent' |
317 |
||
4962.5.8
by Guilherme Salgado
Lots of refactorings |
318 |
def initialize(self): |
319 |
user = getUtility(ILaunchBag).user |
|
320 |
try: |
|
321 |
dupe_id = int(self.request.get('dupe')) |
|
322 |
except (ValueError, TypeError): |
|
323 |
self.request.response.redirect(canonical_url(user)) |
|
324 |
return
|
|
325 |
||
326 |
dupe_account = getUtility(IPersonSet).get(dupe_id) |
|
327 |
results = getUtility(IEmailAddressSet).getByPerson(dupe_account) |
|
328 |
||
329 |
result_count = results.count() |
|
330 |
if not result_count: |
|
331 |
# The user came back to visit this page with nothing to
|
|
332 |
# merge, so we redirect him away to somewhere useful.
|
|
333 |
self.request.response.redirect(canonical_url(user)) |
|
334 |
return
|
|
335 |
assert result_count == 1 |
|
6879.1.1
by Guilherme Salgado
Fix the bug |
336 |
# Need to remove the security proxy because the dupe account may have
|
337 |
# hidden email addresses.
|
|
338 |
self.dupe_email = removeSecurityProxy(results[0]).email |
|
4962.5.8
by Guilherme Salgado
Lots of refactorings |
339 |
|
340 |
def render(self): |
|
341 |
if self.dupe_email: |
|
342 |
return LaunchpadView.render(self) |
|
343 |
else: |
|
344 |
return '' |
|
345 |
||
346 |
||
13303.11.10
by Aaron Bentley
Fix pages broken by assuming LaunchpadView. |
347 |
class RequestPeopleMergeMultipleEmailsView(LaunchpadView): |
10123.4.1
by Brad Crittenden
Don't show hidden emails when merging accounts. |
348 |
"""Merge request view when dupe account has multiple email addresses."""
|
4962.5.8
by Guilherme Salgado
Lots of refactorings |
349 |
|
10123.4.5
by Brad Crittenden
Removed breadcrumbs as they showed up on other /people pages. Simplified page template. |
350 |
label = 'Merge Launchpad accounts' |
351 |
page_title = label |
|
352 |
||
4962.5.8
by Guilherme Salgado
Lots of refactorings |
353 |
def __init__(self, context, request): |
13303.11.10
by Aaron Bentley
Fix pages broken by assuming LaunchpadView. |
354 |
super(RequestPeopleMergeMultipleEmailsView, self).__init__( |
355 |
context, request) |
|
4962.5.8
by Guilherme Salgado
Lots of refactorings |
356 |
self.form_processed = False |
357 |
self.dupe = None |
|
358 |
self.notified_addresses = [] |
|
359 |
||
360 |
def processForm(self): |
|
361 |
dupe = self.request.form.get('dupe') |
|
362 |
if dupe is None: |
|
363 |
# We just got redirected to this page and we don't have the dupe
|
|
364 |
# hidden field in request.form.
|
|
365 |
dupe = self.request.get('dupe') |
|
366 |
if dupe is None: |
|
367 |
return
|
|
368 |
||
369 |
self.dupe = getUtility(IPersonSet).get(int(dupe)) |
|
370 |
emailaddrset = getUtility(IEmailAddressSet) |
|
371 |
self.dupeemails = emailaddrset.getByPerson(self.dupe) |
|
372 |
||
373 |
if self.request.method != "POST": |
|
374 |
return
|
|
375 |
||
376 |
login = getUtility(ILaunchBag).login |
|
377 |
logintokenset = getUtility(ILoginTokenSet) |
|
378 |
||
10123.4.1
by Brad Crittenden
Don't show hidden emails when merging accounts. |
379 |
email_addresses = [] |
380 |
if self.email_hidden: |
|
381 |
# If the email addresses are hidden we must send a merge request
|
|
382 |
# to each of them. But first we've got to remove the security
|
|
383 |
# proxy so we can get to them.
|
|
384 |
email_addresses = [removeSecurityProxy(email).email |
|
385 |
for email in self.dupeemails] |
|
386 |
else: |
|
387 |
# Otherwise we send a merge request only to the ones the user
|
|
388 |
# selected.
|
|
389 |
emails = self.request.form.get("selected") |
|
390 |
if emails is not None: |
|
10123.4.3
by Brad Crittenden
Changes from review. Typos fixed. Tests made more clear. |
391 |
# We can have multiple email addresses selected, and in this
|
10123.4.1
by Brad Crittenden
Don't show hidden emails when merging accounts. |
392 |
# case emails will be a list. Otherwise it will be a string
|
393 |
# and we need to make a list with that value to use in the for
|
|
394 |
# loop.
|
|
395 |
if not isinstance(emails, list): |
|
396 |
emails = [emails] |
|
397 |
||
398 |
for emailaddress in emails: |
|
399 |
email = emailaddrset.getByEmail(emailaddress) |
|
11594.1.2
by Curtis Hovey
Ask the user to reselect the email addresses when requesting a merge if the dupe account changes. |
400 |
if email is None or email not in self.dupeemails: |
11594.1.1
by Curtis Hovey
Save hack from another branch that may fix an oops. |
401 |
# The dupe person has changes his email addresses.
|
402 |
# See bug 239838.
|
|
11594.1.2
by Curtis Hovey
Ask the user to reselect the email addresses when requesting a merge if the dupe account changes. |
403 |
self.request.response.addNotification( |
404 |
"An address was removed from the duplicate "
|
|
11594.1.1
by Curtis Hovey
Save hack from another branch that may fix an oops. |
405 |
"account while you were making this merge "
|
406 |
"request. Select again.") |
|
407 |
return
|
|
10123.4.1
by Brad Crittenden
Don't show hidden emails when merging accounts. |
408 |
email_addresses.append(emailaddress) |
409 |
||
410 |
for emailaddress in email_addresses: |
|
411 |
token = logintokenset.new( |
|
10123.4.5
by Brad Crittenden
Removed breadcrumbs as they showed up on other /people pages. Simplified page template. |
412 |
self.user, login, emailaddress, LoginTokenType.ACCOUNTMERGE) |
10123.4.1
by Brad Crittenden
Don't show hidden emails when merging accounts. |
413 |
token.sendMergeRequestEmail() |
414 |
self.notified_addresses.append(emailaddress) |
|
11594.1.3
by Curtis Hovey
Move form_processes after the test that acutally made changes. Added a test for |
415 |
self.form_processed = True |
10123.4.1
by Brad Crittenden
Don't show hidden emails when merging accounts. |
416 |
|
6596.1.1
by Guilherme Salgado
Fix https://launchpad.net/bugs/241332 |
417 |
@property
|
10123.4.5
by Brad Crittenden
Removed breadcrumbs as they showed up on other /people pages. Simplified page template. |
418 |
def cancel_url(self): |
419 |
"""Cancel URL."""
|
|
420 |
return canonical_url(self.user) |
|
421 |
||
422 |
@property
|
|
10123.4.1
by Brad Crittenden
Don't show hidden emails when merging accounts. |
423 |
def email_hidden(self): |
424 |
"""Does the duplicate account hide email addresses?"""
|
|
425 |
return self.dupe.hide_email_addresses |
|
12167.1.6
by j.c.sackett
Lint fixes. |
426 |
|
12167.1.3
by j.c.sackett
Added ppa validation step to RequestPeopleMergeView |
427 |
|
12167.1.5
by j.c.sackett
Updated validator. |
428 |
class RequestPeopleMergeView(ValidatingMergeView): |
12167.1.2
by j.c.sackett
Grouped RequestPeopleMergeView with the other RequestPeopleMerge views. |
429 |
"""The view for the page where the user asks a merge of two accounts.
|
430 |
||
431 |
If the dupe account have only one email address we send a message to that
|
|
432 |
address and then redirect the user to other page saying that everything
|
|
433 |
went fine. Otherwise we redirect the user to another page where we list
|
|
434 |
all email addresses owned by the dupe account and the user selects which
|
|
435 |
of those (s)he wants to claim.
|
|
436 |
"""
|
|
437 |
||
438 |
label = 'Merge Launchpad accounts' |
|
439 |
page_title = label |
|
440 |
schema = IRequestPeopleMerge |
|
441 |
||
442 |
@property
|
|
443 |
def cancel_url(self): |
|
444 |
return canonical_url(getUtility(IPersonSet)) |
|
445 |
||
446 |
@action('Continue', name='continue') |
|
447 |
def continue_action(self, action, data): |
|
448 |
dupeaccount = data['dupe_person'] |
|
449 |
if dupeaccount == self.user: |
|
450 |
# Please, don't try to merge you into yourself.
|
|
451 |
return
|
|
452 |
||
453 |
emails = getUtility(IEmailAddressSet).getByPerson(dupeaccount) |
|
454 |
emails_count = emails.count() |
|
455 |
if emails_count > 1: |
|
456 |
# The dupe account have more than one email address. Must redirect
|
|
457 |
# the user to another page to ask which of those emails (s)he
|
|
458 |
# wants to claim.
|
|
459 |
self.next_url = '+requestmerge-multiple?dupe=%d' % dupeaccount.id |
|
460 |
return
|
|
461 |
||
462 |
assert emails_count == 1 |
|
463 |
email = emails[0] |
|
464 |
login = getUtility(ILaunchBag).login |
|
465 |
logintokenset = getUtility(ILoginTokenSet) |
|
466 |
# Need to remove the security proxy because the dupe account may have
|
|
467 |
# hidden email addresses.
|
|
468 |
token = logintokenset.new( |
|
469 |
self.user, login, removeSecurityProxy(email).email, |
|
470 |
LoginTokenType.ACCOUNTMERGE) |
|
471 |
token.sendMergeRequestEmail() |
|
472 |
self.next_url = './+mergerequest-sent?dupe=%d' % dupeaccount.id |