Skip to content

Commit

Permalink
Merge pull request #719 from liberapay/team-rename
Browse files Browse the repository at this point in the history
Implement team rename
  • Loading branch information
Changaco authored Oct 1, 2017
2 parents d9e517a + 1890b45 commit 78d65c1
Show file tree
Hide file tree
Showing 4 changed files with 60 additions and 19 deletions.
4 changes: 4 additions & 0 deletions emails/team_rename.spt
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
{{ _("A team you're a member of has been renamed") }}

[---] text/html
<p>{{ _("The team “{0}” has been renamed to “{1}” by {2}.", old_name, new_name, renamed_by) }}</p>
47 changes: 32 additions & 15 deletions liberapay/models/participant.py
Original file line number Diff line number Diff line change
Expand Up @@ -123,7 +123,7 @@ def make_active(cls, kind, username=None, password=None, cursor=None):
RETURNING participants.*::participants
""".format(cols, placeholders), vals)
if username:
p.change_username(username, c)
p.change_username(username, cursor=c)
return p

def make_team(self, name, email=None, email_lang=None, throttle_takes=True):
Expand All @@ -143,7 +143,7 @@ def make_team(self, name, email=None, email_lang=None, throttle_takes=True):
VALUES ('group', 'active', now(), %s)
RETURNING participants.*::participants
""", (throttle_takes,))
t.change_username(name, c)
t.change_username(name, cursor=c)
t.add_member(self, c)
if email:
t.set_email_lang(email_lang, cursor=c)
Expand Down Expand Up @@ -1280,7 +1280,7 @@ def pay_invoice(self, invoice):
# More Random Stuff
# =================

def change_username(self, suggested, cursor=None):
def change_username(self, suggested, cursor=None, recorder=None):
suggested = suggested and suggested.strip()

if not suggested:
Expand Down Expand Up @@ -1316,11 +1316,11 @@ def change_username(self, suggested, cursor=None):
if actual is None:
return suggested
assert (suggested, lowercased) == actual # sanity check
c.hit_rate_limit('change_username', self.id, TooManyUsernameChanges)

# Deal with redirections
last_rename = self.get_last_event_of_type('set_username')
if last_rename:
c.hit_rate_limit('change_username', self.id, TooManyUsernameChanges)
old_username = last_rename.payload
prefixes = {
'old': '/%s/' % old_username.lower(),
Expand All @@ -1334,21 +1334,38 @@ def change_username(self, suggested, cursor=None):
, mtime = now()
WHERE to_prefix = %(old)s;
""", prefixes)
# Add a redirection if the old name was in use long enough (1 hour)
active_period = utcnow() - last_rename.ts
if active_period.total_seconds() > 3600:
c.run("""
INSERT INTO redirections
(from_prefix, to_prefix)
VALUES (%(old)s || '%%', %(new)s)
ON CONFLICT (from_prefix) DO UPDATE
SET to_prefix = excluded.to_prefix
, mtime = now()
""", prefixes)
if prefixes['old'] != prefixes['new']:
# Add a redirection if the old name was in use long enough (1 hour)
active_period = utcnow() - last_rename.ts
if active_period.total_seconds() > 3600:
c.run("""
INSERT INTO redirections
(from_prefix, to_prefix)
VALUES (%(old)s || '%%', %(new)s)
ON CONFLICT (from_prefix) DO UPDATE
SET to_prefix = excluded.to_prefix
, mtime = now()
""", prefixes)

self.add_event(c, 'set_username', suggested)
self.set_attributes(username=suggested)

if last_rename and self.kind == 'group':
assert isinstance(recorder, Participant)
members = self.db.all("""
SELECT p
FROM current_takes t
JOIN participants p ON p.id = t.member
WHERE t.team = %s
""", (self.id,))
for m in members:
if m != recorder:
m.notify(
'team_rename', email=False, web=True,
old_name=old_username, new_name=suggested,
renamed_by=recorder.username,
)

return suggested

def update_avatar(self, src=None, cursor=None):
Expand Down
18 changes: 18 additions & 0 deletions tests/py/test_settings.py
Original file line number Diff line number Diff line change
Expand Up @@ -97,3 +97,21 @@ def test_too_long(self):
r = self.change_username(username)
assert r.code == 400
assert "The username &#39;%s&#39; is too long." % username in r.text, r.text

def test_change_team_name(self):
team = self.make_participant(None, kind='group')
team.change_username('team')
alice = self.make_participant('alice')
team.add_member(alice)
bob = self.make_participant('bob')
team.add_member(bob)
r = self.client.POST('/team/settings/edit', {'username': 'Team'},
auth_as=alice, raise_immediately=False)
assert r.code == 302
assert r.headers[b'Location'] == b'/Team/edit'
team = team.refetch()
assert team.username == 'Team'
alice = alice.refetch()
assert alice.pending_notifs == 0
bob = bob.refetch()
assert bob.pending_notifs == 1
10 changes: 6 additions & 4 deletions www/%username/settings/edit.spt
Original file line number Diff line number Diff line change
Expand Up @@ -9,11 +9,11 @@ request.allow('POST')
body = request.body
out = {}

p = get_participant(state, restrict=True)
if user != p:
raise response.error(403)
p = get_participant(state, restrict=True, allow_member=True)

if 'new-password' in body:
if not p.is_person:
raise response.error(403)
if p.session_token and p.session_token.endswith('.em'):
pass # user logged in via email, allow resetting password
elif not p.password:
Expand All @@ -28,6 +28,8 @@ if 'new-password' in body:
out['msg'] = _("Your password has been changed.")

elif 'privacy' in body:
if not p.is_person:
raise response.error(403)
fields = body['privacy'].split()
for field in fields:
if field not in PRIVACY_FIELDS:
Expand All @@ -44,7 +46,7 @@ elif 'privacy' in body:
out['msg'] = _("Your privacy settings have been changed.")

elif 'username' in body:
p.change_username(body['username'])
p.change_username(body['username'], recorder=user)
response.redirect(p.path('edit'))

if request.headers.get(b'X-Requested-With') != b'XMLHttpRequest':
Expand Down

0 comments on commit 78d65c1

Please sign in to comment.