{% if user.is_staff and user.has_perm('groups.change_groupprofile') %}
@@ -14,7 +19,7 @@
{% endif %}
{{ profile.group.name }}
- {% if user.has_perm('groups.change_groupprofile') or user in leaders %}
+ {% if user_can_edit %}
{{ _('Edit group profile') }}
{% endif %}
diff --git a/apps/groups/tests/test_views.py b/apps/groups/tests/test_views.py
index cefae4d93e1..2ef55e856c3 100644
--- a/apps/groups/tests/test_views.py
+++ b/apps/groups/tests/test_views.py
@@ -1,3 +1,7 @@
+import os
+
+from django.core.files import File
+
from nose.tools import eq_
from groups.models import GroupProfile
@@ -45,3 +49,50 @@ def test_edit_without_perm(self):
args=[slug]),
{'information': '=new info='})
eq_(r.status_code, 403)
+
+
+class EditAvatarTests(TestCase):
+ def setUp(self):
+ super(EditAvatarTests, self).setUp()
+ self.user = user(save=True)
+ add_permission(self.user, GroupProfile, 'change_groupprofile')
+ self.group_profile = group_profile(group=group(save=True), save=True)
+ self.client.login(username=self.user.username, password='testpass')
+
+ def tearDown(self):
+ if self.group_profile.avatar:
+ self.group_profile.avatar.delete()
+ super(EditAvatarTests, self).tearDown()
+
+ def test_upload_avatar(self):
+ """Upload a group avatar."""
+ with open('apps/upload/tests/media/test.jpg') as f:
+ self.group_profile.avatar.save('test_old.jpg', File(f), save=True)
+ assert self.group_profile.avatar.name.endswith('92b516.jpg')
+ old_path = self.group_profile.avatar.path
+ assert os.path.exists(old_path), 'Old avatar is not in place.'
+
+ url = reverse('groups.edit_avatar', locale='en-US',
+ args=[self.group_profile.slug])
+ with open('apps/upload/tests/media/test.jpg') as f:
+ r = self.client.post(url, {'avatar': f})
+
+ eq_(302, r.status_code)
+ url = reverse('groups.profile', args=[self.group_profile.slug])
+ eq_('http://testserver/en-US' + url, r['location'])
+ assert not os.path.exists(old_path), 'Old avatar was not removed.'
+
+ def test_delete_avatar(self):
+ """Delete a group avatar."""
+ self.test_upload_avatar()
+
+ url = reverse('groups.delete_avatar', locale='en-US',
+ args=[self.group_profile.slug])
+ r = self.client.get(url)
+ eq_(200, r.status_code)
+ r = self.client.post(url)
+ eq_(302, r.status_code)
+ url = reverse('groups.profile', args=[self.group_profile.slug])
+ eq_('http://testserver/en-US' + url, r['location'])
+ gp = GroupProfile.uncached.get(slug=self.group_profile.slug)
+ eq_('', gp.avatar.name)
diff --git a/apps/groups/urls.py b/apps/groups/urls.py
index 5c81d242f36..a67202e625a 100644
--- a/apps/groups/urls.py
+++ b/apps/groups/urls.py
@@ -4,4 +4,8 @@
url(r'^$', 'list', name='groups.list'),
url(r'^/(?P[^/]+)$', 'profile', name='groups.profile'),
url(r'^/(?P[^/]+)/edit$', 'edit', name='groups.edit'),
+ url(r'^/(?P[^/]+)/avatar$', 'edit_avatar',
+ name='groups.edit_avatar'),
+ url(r'^/(?P[^/]+)/avatar/delete$', 'delete_avatar',
+ name='groups.delete_avatar'),
)
diff --git a/apps/groups/views.py b/apps/groups/views.py
index f78fce3c53b..b82b87bbf14 100644
--- a/apps/groups/views.py
+++ b/apps/groups/views.py
@@ -1,3 +1,6 @@
+import os
+
+from django.conf import settings
from django.contrib import messages
from django.core.exceptions import PermissionDenied
from django.http import HttpResponseRedirect
@@ -8,8 +11,9 @@
from tower import ugettext as _
from access.decorators import login_required
-from groups.forms import GroupProfileForm
+from groups.forms import GroupProfileForm, GroupAvatarForm
from groups.models import GroupProfile
+from upload.tasks import _create_image_thumbnail
def list(request):
@@ -21,9 +25,10 @@ def profile(request, group_slug):
prof = get_object_or_404(GroupProfile, slug=group_slug)
leaders = prof.leaders.all()
members = prof.group.user_set.all()
+ user_can_edit = _user_can_edit(request.user, prof)
return jingo.render(request, 'groups/profile.html',
{'profile': prof, 'leaders': leaders,
- 'members': members})
+ 'members': members, 'user_can_edit': user_can_edit})
@login_required
@@ -31,8 +36,7 @@ def profile(request, group_slug):
def edit(request, group_slug):
prof = get_object_or_404(GroupProfile, slug=group_slug)
- if not (request.user.has_perm('groups.change_groupprofile') or
- request.user in prof.leaders.all()):
+ if not _user_can_edit(request.user, prof):
raise PermissionDenied
form = GroupProfileForm(request.POST or None, instance=prof)
@@ -44,3 +48,64 @@ def edit(request, group_slug):
return jingo.render(request, 'groups/edit.html',
{'form': form, 'profile': prof})
+
+
+@login_required
+@require_http_methods(['GET', 'POST'])
+def edit_avatar(request, group_slug):
+ """Edit group avatar."""
+ prof = get_object_or_404(GroupProfile, slug=group_slug)
+
+ if not _user_can_edit(request.user, prof):
+ raise PermissionDenied
+
+ form = GroupAvatarForm(request.POST or None, request.FILES or None,
+ instance=prof)
+
+ old_avatar_path = None
+ if prof.avatar and os.path.isfile(prof.avatar.path):
+ # Need to store the path, or else django's
+ # form.is_valid() messes with it.
+ old_avatar_path = prof.avatar.path
+ if request.method == 'POST' and form.is_valid():
+ # Upload new avatar and replace old one.
+ if old_avatar_path:
+ os.unlink(old_avatar_path)
+
+ prof = form.save()
+ content = _create_image_thumbnail(prof.avatar.path,
+ settings.AVATAR_SIZE, pad=True)
+ # We want everything as .png
+ name = prof.avatar.name + ".png"
+ # Delete uploaded avatar and replace with thumbnail.
+ prof.avatar.delete()
+ prof.avatar.save(name, content, save=True)
+ return HttpResponseRedirect(prof.get_absolute_url())
+
+ return jingo.render(request, 'groups/edit_avatar.html',
+ {'form': form, 'profile': prof})
+
+
+@login_required
+@require_http_methods(['GET', 'POST'])
+def delete_avatar(request, group_slug):
+ """Delete group avatar."""
+ prof = get_object_or_404(GroupProfile, slug=group_slug)
+
+ if not _user_can_edit(request.user, prof):
+ raise PermissionDenied
+
+ if request.method == 'POST':
+ # Delete avatar here
+ if prof.avatar:
+ prof.avatar.delete()
+ return HttpResponseRedirect(prof.get_absolute_url())
+
+ return jingo.render(request, 'groups/confirm_avatar_delete.html',
+ {'profile': prof})
+
+
+def _user_can_edit(user, group_profile):
+ """Can the given user edit the given group profile?"""
+ return (user.has_perm('groups.change_groupprofile') or
+ user in group_profile.leaders.all())
diff --git a/apps/sumo/views.py b/apps/sumo/views.py
index 7cbc44f94e6..f732d68110f 100644
--- a/apps/sumo/views.py
+++ b/apps/sumo/views.py
@@ -136,6 +136,7 @@ def monitor(request):
(settings.GALLERY_IMAGE_THUMBNAIL_PATH, os.R_OK | os.W_OK, msg),
(settings.GALLERY_VIDEO_PATH, os.R_OK | os.W_OK, msg),
(settings.GALLERY_VIDEO_THUMBNAIL_PATH, os.R_OK | os.W_OK, msg),
+ (settings.GROUP_AVATAR_PATH, os.R_OK | os.W_OK, msg),
)
filepath_results = []
diff --git a/media/css/groups.css b/media/css/groups.css
index 038d0241b74..ab7f52554d1 100644
--- a/media/css/groups.css
+++ b/media/css/groups.css
@@ -41,6 +41,11 @@ article.main h2 {
width: 48px;
}
+#avatar-area p {
+ font-size: 12px;
+ margin: 2px 0;
+}
+
#group-profile a.edit {
background: transparent url(../img/icons.actions.png) no-repeat left -25px;
float: right;
@@ -84,3 +89,40 @@ div.editor {
#id_information {
height: 350px;
}
+
+/* avatar delete */
+#avatar-delete p {
+ margin: 10px 0;
+}
+
+/* change avatar */
+#change-avatar form {
+ margin: 25px 0;
+}
+
+#change-avatar ul {
+ list-style: none;
+}
+
+#change-avatar div.val-wrap {
+ display: inline-block;
+ line-height:35px;
+ margin-right: 10px;
+ width: auto;
+}
+
+#change-avatar label {
+ display: inline-block;
+ padding: 0 5px 0 0;
+ text-align: right;
+ vertical-align: top;
+ width: 180px;
+}
+
+#change-avatar div.val-wrap input {
+ display: block;
+}
+
+#change-avatar div.submit {
+ padding: 10px 0 0 188px;
+}