Repository: getsentry/sentry

Issue:
500 error when rename team slug
Error raised if same slug already exists

Traceback:

```
File "/home/www/pyenv/versions/sentry/lib/python2.7/site-packages/django/core/handlers/base.py", line 112, in get_response
     response = wrapped_callback(request, *callback_args, **callback_kwargs)
   File "/home/www/pyenv/versions/sentry/lib/python2.7/site-packages/django/views/generic/base.py", line 69, in view
     return self.dispatch(request, *args, **kwargs)
   File "/home/www/pyenv/versions/sentry/lib/python2.7/site-packages/django/utils/decorators.py", line 29, in _wrapper
     return bound_func(*args, **kwargs)
   File "/home/www/pyenv/versions/sentry/lib/python2.7/site-packages/django/utils/decorators.py", line 99, in _wrapped_view
     response = view_func(request, *args, **kwargs)
   File "/home/www/pyenv/versions/sentry/lib/python2.7/site-packages/django/utils/decorators.py", line 25, in bound_func
     return func(self, *args2, **kwargs2)
   File "/home/www/pyenv/versions/sentry/lib/python2.7/site-packages/sentry/web/frontend/base.py", line 144, in dispatch
     return self.handle(request, *args, **kwargs)
   File "/home/www/pyenv/versions/sentry/lib/python2.7/site-packages/sentry/web/frontend/team_settings.py", line 37, in handle
     team = form.save()
   File "/home/www/pyenv/versions/sentry/lib/python2.7/site-packages/django/forms/models.py", line 446, in save
     construct=False)
   File "/home/www/pyenv/versions/sentry/lib/python2.7/site-packages/django/forms/models.py", line 99, in save_instance
     instance.save()
   File "/home/www/pyenv/versions/sentry/lib/python2.7/site-packages/sentry/models/team.py", line 141, in save
     super(Team, self).save(*args, **kwargs)
   File "/home/www/pyenv/versions/sentry/lib/python2.7/site-packages/django/db/models/base.py", line 545, in save
     force_update=force_update, update_fields=update_fields)
   File "/home/www/pyenv/versions/sentry/lib/python2.7/site-packages/django/db/models/base.py", line 573, in save_base
     updated = self._save_table(raw, cls, force_insert, force_update, using, update_fields)
   File "/home/www/pyenv/versions/sentry/lib/python2.7/site-packages/django/db/models/base.py", line 635, in _save_table
     forced_update)
   File "/home/www/pyenv/versions/sentry/lib/python2.7/site-packages/django/db/models/base.py", line 679, in _do_update
     return filtered._update(values) > 0
   File "/home/www/pyenv/versions/sentry/lib/python2.7/site-packages/django/db/models/query.py", line 510, in _update
     return query.get_compiler(self.db).execute_sql(None)
   File "/home/www/pyenv/versions/sentry/lib/python2.7/site-packages/django/db/models/sql/compiler.py", line 980, in execute_sql
     cursor = super(SQLUpdateCompiler, self).execute_sql(result_type)
   File "/home/www/pyenv/versions/sentry/lib/python2.7/site-packages/django/db/models/sql/compiler.py", line 786, in execute_sql
     cursor.execute(sql, params)
   File "/home/www/pyenv/versions/sentry/lib/python2.7/site-packages/django/db/backends/util.py", line 53, in execute
     return self.cursor.execute(sql, params)
   File "/home/www/pyenv/versions/sentry/lib/python2.7/site-packages/django/db/utils.py", line 99, in __exit__
     six.reraise(dj_exc_type, dj_exc_value, traceback)
   File "/home/www/pyenv/versions/sentry/lib/python2.7/site-packages/django/db/backends/util.py", line 53, in execute
     return self.cursor.execute(sql, params)
 IntegrityError: duplicate key value violates unique constraint "sentry_team_organization_id_1e0ece47434a2ed_uniq"
 DETAIL:  Key (organization_id, slug)=(1, adwile) already exists.
```



Discussion:

Resolving patch:
diff --git a/src/sentry/web/frontend/team_settings.py b/src/sentry/web/frontend/team_settings.py
--- a/src/sentry/web/frontend/team_settings.py
+++ b/src/sentry/web/frontend/team_settings.py
@@ -3,6 +3,7 @@
 from django import forms
 from django.contrib import messages
 from django.core.urlresolvers import reverse
+from django.db import IntegrityError
 from django.http import HttpResponseRedirect
 from django.utils.translation import ugettext_lazy as _
 
@@ -23,21 +24,27 @@ def get_form(self, request, team):
         return EditTeamForm(request.POST or None, instance=team)
 
     def handle(self, request, organization, team):
+        old_slug = team.slug
         form = self.get_form(request, team)
         if form.is_valid():
-            team = form.save()
-
-            AuditLogEntry.objects.create(
-                organization=organization,
-                actor=request.user,
-                ip_address=request.META['REMOTE_ADDR'],
-                target_object=team.id,
-                event=AuditLogEntryEvent.TEAM_EDIT,
-                data=team.get_audit_log_data(),
-            )
-
-            messages.add_message(request, messages.SUCCESS,
-                _('Changes to your team were saved.'))
+            try:
+                team = form.save()
+            except IntegrityError:
+                team.slug = old_slug
+                messages.add_message(request, messages.ERROR,
+                    _('Changes to your team failed. Slug already exists.'))
+            else:
+                AuditLogEntry.objects.create(
+                    organization=organization,
+                    actor=request.user,
+                    ip_address=request.META['REMOTE_ADDR'],
+                    target_object=team.id,
+                    event=AuditLogEntryEvent.TEAM_EDIT,
+                    data=team.get_audit_log_data(),
+                )
+
+                messages.add_message(request, messages.SUCCESS,
+                    _('Changes to your team were saved.'))
 
             return HttpResponseRedirect(reverse('sentry-manage-team', args=[organization.slug, team.slug]))
 


Test patch:
diff --git a/tests/sentry/web/frontend/test_team_settings.py b/tests/sentry/web/frontend/test_team_settings.py
--- a/tests/sentry/web/frontend/test_team_settings.py
+++ b/tests/sentry/web/frontend/test_team_settings.py
@@ -44,3 +44,15 @@ def test_valid_params(self):
         self.assertEquals(resp['Location'], 'http://testserver' + self.path)
         team = Team.objects.get(pk=self.team.pk)
         self.assertEquals(team.name, 'bar')
+
+    def test_slug_already_exists(self):
+        self.login_as(self.user)
+        self.create_team(name='bar', organization=self.organization)
+        resp = self.client.post(self.path, {
+            'name': 'bar',
+            'slug': self.team.slug,
+        })
+        assert resp.status_code == 302
+        self.assertEquals(resp['Location'], 'http://testserver' + self.path)
+        team = Team.objects.get(pk=self.team.pk)
+        self.assertEquals(team.name, self.team.name)