diff --git a/avatar/conf.py b/avatar/conf.py new file mode 100644 index 0000000..e25ee91 --- /dev/null +++ b/avatar/conf.py @@ -0,0 +1,29 @@ +from django.conf import settings +from PIL import Image + +from appconf import AppConf + + +class AvatarConf(AppConf): + DEFAULT_SIZE = 80 + RESIZE_METHOD = Image.ANTIALIAS + STORAGE_DIR = 'avatars' + GRAVATAR_BASE_URL = 'http://www.gravatar.com/avatar/' + GRAVATAR_BACKUP = True + GRAVATAR_DEFAULT = None + DEFAULT_URL = 'avatar/img/default.jpg' + MAX_AVATARS_PER_USER = 42 + MAX_SIZE = 1024 * 1024 + THUMB_FORMAT = 'JPEG' + THUMB_QUALITY = 85 + HASH_FILENAMES = False + HASH_USERDIRNAMES = False + ALLOWED_FILE_EXTS = None + CACHE_TIMEOUT = 60 * 60 + STORAGE = settings.DEFAULT_FILE_STORAGE + CLEANUP_DELETED = False + AUTO_GENERATE_SIZES = (DEFAULT_SIZE,) + + def configure_auto_generate_avatar_sizes(self, value): + return value or getattr(settings, 'AUTO_GENERATE_AVATAR_SIZES', + (self.DEFAULT_SIZE,)) diff --git a/avatar/forms.py b/avatar/forms.py index d4bc4db..c52b42a 100644 --- a/avatar/forms.py +++ b/avatar/forms.py @@ -7,16 +7,16 @@ from django.utils.safestring import mark_safe from django.utils.translation import ugettext_lazy as _ from django.template.defaultfilters import filesizeformat +from avatar.conf import settings from avatar.models import Avatar -from avatar.settings import (AVATAR_MAX_AVATARS_PER_USER, AVATAR_MAX_SIZE, - AVATAR_ALLOWED_FILE_EXTS, AVATAR_DEFAULT_SIZE) def avatar_img(avatar, size): if not avatar.thumbnail_exists(size): avatar.create_thumbnail(size) return mark_safe('%s' % - (avatar.avatar_url(size), six.text_type(avatar), size, size)) + (avatar.avatar_url(size), six.text_type(avatar), + size, size)) class UploadAvatarForm(forms.Form): @@ -29,29 +29,33 @@ class UploadAvatarForm(forms.Form): def clean_avatar(self): data = self.cleaned_data['avatar'] - if AVATAR_ALLOWED_FILE_EXTS: - (root, ext) = os.path.splitext(data.name.lower()) - if ext not in AVATAR_ALLOWED_FILE_EXTS: - raise forms.ValidationError( - _("%(ext)s is an invalid file extension. " - "Authorized extensions are : %(valid_exts_list)s") % - {'ext': ext, 'valid_exts_list': ", ".join(AVATAR_ALLOWED_FILE_EXTS)}) - if data.size > AVATAR_MAX_SIZE: + + if settings.AVATAR_ALLOWED_FILE_EXTS: + root, ext = os.path.splitext(data.name.lower()) + if ext not in settings.AVATAR_ALLOWED_FILE_EXTS: + valid_exts = ", ".join(settings.AVATAR_ALLOWED_FILE_EXTS) + error = _("%(ext)s is an invalid file extension. " + "Authorized extensions are : %(valid_exts_list)s") + raise forms.ValidationError(error % + {'ext': ext, + 'valid_exts_list': valid_exts}) + + if data.size > settings.AVATAR_MAX_SIZE: error = _("Your file is too big (%(size)s), " "the maximum allowed size is %(max_valid_size)s") raise forms.ValidationError(error % { 'size': filesizeformat(data.size), - 'max_valid_size': filesizeformat(AVATAR_MAX_SIZE) + 'max_valid_size': filesizeformat(settings.AVATAR_MAX_SIZE) }) count = Avatar.objects.filter(user=self.user).count() - if (AVATAR_MAX_AVATARS_PER_USER > 1 and - count >= AVATAR_MAX_AVATARS_PER_USER): + if (settings.AVATAR_MAX_AVATARS_PER_USER > 1 and + count >= settings.AVATAR_MAX_AVATARS_PER_USER): error = _("You already have %(nb_avatars)d avatars, " "and the maximum allowed is %(nb_max_avatars)d.") raise forms.ValidationError(error % { 'nb_avatars': count, - 'nb_max_avatars': AVATAR_MAX_AVATARS_PER_USER, + 'nb_max_avatars': settings.AVATAR_MAX_AVATARS_PER_USER, }) return @@ -60,21 +64,23 @@ class PrimaryAvatarForm(forms.Form): def __init__(self, *args, **kwargs): kwargs.pop('user') - size = kwargs.pop('size', AVATAR_DEFAULT_SIZE) + size = kwargs.pop('size', settings.AVATAR_DEFAULT_SIZE) avatars = kwargs.pop('avatars') super(PrimaryAvatarForm, self).__init__(*args, **kwargs) + choices = [(avatar.id, avatar_img(avatar, size)) for avatar in avatars] self.fields['choice'] = forms.ChoiceField(label=_("Choices"), - choices=[(c.id, avatar_img(c, size)) for c in avatars], - widget=widgets.RadioSelect) + choices=choices, + widget=widgets.RadioSelect) class DeleteAvatarForm(forms.Form): def __init__(self, *args, **kwargs): kwargs.pop('user') - size = kwargs.pop('size', AVATAR_DEFAULT_SIZE) + size = kwargs.pop('size', settings.AVATAR_DEFAULT_SIZE) avatars = kwargs.pop('avatars') super(DeleteAvatarForm, self).__init__(*args, **kwargs) + choices = [(avatar.id, avatar_img(avatar, size)) for avatar in avatars] self.fields['choices'] = forms.MultipleChoiceField(label=_("Choices"), - choices=[(c.id, avatar_img(c, size)) for c in avatars], - widget=widgets.CheckboxSelectMultiple) + choices=choices, + widget=widgets.CheckboxSelectMultiple) diff --git a/avatar/management/commands/rebuild_avatars.py b/avatar/management/commands/rebuild_avatars.py index 0b00835..0c1180e 100644 --- a/avatar/management/commands/rebuild_avatars.py +++ b/avatar/management/commands/rebuild_avatars.py @@ -1,15 +1,15 @@ from django.core.management.base import NoArgsCommand +from django.conf import settings from avatar.models import Avatar -from avatar.settings import AUTO_GENERATE_AVATAR_SIZES class Command(NoArgsCommand): help = ("Regenerates avatar thumbnails for the sizes specified in " - "settings.AUTO_GENERATE_AVATAR_SIZES.") + "settings.AVATAR_AUTO_GENERATE_SIZES.") def handle_noargs(self, **options): for avatar in Avatar.objects.all(): - for size in AUTO_GENERATE_AVATAR_SIZES: + for size in settings.AVATAR_AUTO_GENERATE_SIZES: print("Rebuilding Avatar id=%s at size %s." % (avatar.id, size)) avatar.create_thumbnail(size) diff --git a/avatar/models.py b/avatar/models.py index fd20b0d..5bc3a52 100644 --- a/avatar/models.py +++ b/avatar/models.py @@ -3,7 +3,6 @@ import os import hashlib from PIL import Image -from django.conf import settings from django.db import models from django.core.files import File from django.core.files.base import ContentFile @@ -12,27 +11,21 @@ from django.utils.translation import ugettext as _ from django.utils import six from django.db.models import signals -from avatar.util import get_username, force_bytes +from avatar.conf import settings +from avatar.util import get_username, force_bytes, invalidate_cache try: from django.utils.timezone import now except ImportError: now = datetime.datetime.now -from avatar.util import invalidate_cache -from avatar.settings import (AVATAR_STORAGE_DIR, AVATAR_RESIZE_METHOD, - AVATAR_MAX_AVATARS_PER_USER, AVATAR_THUMB_FORMAT, - AVATAR_HASH_USERDIRNAMES, AVATAR_HASH_FILENAMES, - AVATAR_THUMB_QUALITY, AUTO_GENERATE_AVATAR_SIZES, - AVATAR_DEFAULT_SIZE, AVATAR_STORAGE, - AVATAR_CLEANUP_DELETED) -avatar_storage = get_storage_class(AVATAR_STORAGE)() +avatar_storage = get_storage_class(settings.AVATAR_STORAGE)() def avatar_file_path(instance=None, filename=None, size=None, ext=None): - tmppath = [AVATAR_STORAGE_DIR] - if AVATAR_HASH_USERDIRNAMES: + tmppath = [settings.AVATAR_STORAGE_DIR] + if settings.AVATAR_HASH_USERDIRNAMES: tmp = hashlib.md5(get_username(instance.user)).hexdigest() tmppath.extend([tmp[0], tmp[1], get_username(instance.user)]) else: @@ -40,7 +33,7 @@ def avatar_file_path(instance=None, filename=None, size=None, ext=None): if not filename: # Filename already stored in database filename = instance.avatar.name - if ext and AVATAR_HASH_FILENAMES: + if ext and settings.AVATAR_HASH_FILENAMES: # An extension was provided, probably because the thumbnail # is in a different format than the file. Use it. Because it's # only enabled if AVATAR_HASH_FILENAMES is true, we can trust @@ -49,7 +42,7 @@ def avatar_file_path(instance=None, filename=None, size=None, ext=None): filename = root + "." + ext else: # File doesn't exist yet - if AVATAR_HASH_FILENAMES: + if settings.AVATAR_HASH_FILENAMES: (root, ext) = os.path.splitext(filename) filename = hashlib.md5(force_bytes(filename)).hexdigest() filename = filename + ext @@ -84,7 +77,7 @@ class Avatar(models.Model): avatars = Avatar.objects.filter(user=self.user) if self.pk: avatars = avatars.exclude(pk=self.pk) - if AVATAR_MAX_AVATARS_PER_USER > 1: + if settings.AVATAR_MAX_AVATARS_PER_USER > 1: if self.primary: avatars = avatars.filter(primary=True) avatars.update(primary=False) @@ -101,7 +94,7 @@ class Avatar(models.Model): try: orig = self.avatar.storage.open(self.avatar.name, 'rb') image = Image.open(orig) - quality = quality or AVATAR_THUMB_QUALITY + quality = quality or settings.AVATAR_THUMB_QUALITY w, h = image.size if w != size or h != size: if w > h: @@ -112,9 +105,9 @@ class Avatar(models.Model): image = image.crop((0, diff, w, h - diff)) if image.mode != "RGB": image = image.convert("RGB") - image = image.resize((size, size), AVATAR_RESIZE_METHOD) + image = image.resize((size, size), settings.AVATAR_RESIZE_METHOD) thumb = six.BytesIO() - image.save(thumb, AVATAR_THUMB_FORMAT, quality=quality) + image.save(thumb, settings.AVATAR_THUMB_FORMAT, quality=quality) thumb_file = ContentFile(thumb.getvalue()) else: thumb_file = File(orig) @@ -126,10 +119,10 @@ class Avatar(models.Model): return self.avatar.storage.url(self.avatar_name(size)) def get_absolute_url(self): - return self.avatar_url(AVATAR_DEFAULT_SIZE) + return self.avatar_url(settings.AVATAR_DEFAULT_SIZE) def avatar_name(self, size): - ext = find_extension(AVATAR_THUMB_FORMAT) + ext = find_extension(settings.AVATAR_THUMB_FORMAT) return avatar_file_path( instance=self, size=size, @@ -144,12 +137,12 @@ def invalidate_avatar_cache(sender, instance, **kwargs): def create_default_thumbnails(sender, instance, created=False, **kwargs): invalidate_avatar_cache(sender, instance) if created: - for size in AUTO_GENERATE_AVATAR_SIZES: + for size in settings.AVATAR_AUTO_GENERATE_SIZES: instance.create_thumbnail(size) def remove_avatar_images(instance=None, **kwargs): - for size in AUTO_GENERATE_AVATAR_SIZES: + for size in settings.AVATAR_AUTO_GENERATE_SIZES: if instance.thumbnail_exists(size): instance.avatar.storage.delete(instance.avatar_name(size)) instance.avatar.storage.delete(instance.avatar.name) @@ -158,5 +151,5 @@ def remove_avatar_images(instance=None, **kwargs): signals.post_save.connect(create_default_thumbnails, sender=Avatar) signals.post_delete.connect(invalidate_avatar_cache, sender=Avatar) -if AVATAR_CLEANUP_DELETED: +if settings.AVATAR_CLEANUP_DELETED: signals.post_delete.connect(remove_avatar_images, sender=Avatar) diff --git a/avatar/settings.py b/avatar/settings.py deleted file mode 100644 index 71a3609..0000000 --- a/avatar/settings.py +++ /dev/null @@ -1,21 +0,0 @@ -from django.conf import settings -from PIL import Image - -AVATAR_DEFAULT_SIZE = getattr(settings, 'AVATAR_DEFAULT_SIZE', 80) -AUTO_GENERATE_AVATAR_SIZES = getattr(settings, 'AUTO_GENERATE_AVATAR_SIZES', (AVATAR_DEFAULT_SIZE,)) -AVATAR_RESIZE_METHOD = getattr(settings, 'AVATAR_RESIZE_METHOD', Image.ANTIALIAS) -AVATAR_STORAGE_DIR = getattr(settings, 'AVATAR_STORAGE_DIR', 'avatars') -AVATAR_GRAVATAR_BASE_URL = getattr(settings, 'AVATAR_GRAVATAR_BASE_URL', 'http://www.gravatar.com/avatar/') -AVATAR_GRAVATAR_BACKUP = getattr(settings, 'AVATAR_GRAVATAR_BACKUP', True) -AVATAR_GRAVATAR_DEFAULT = getattr(settings, 'AVATAR_GRAVATAR_DEFAULT', None) -AVATAR_DEFAULT_URL = getattr(settings, 'AVATAR_DEFAULT_URL', 'avatar/img/default.jpg') -AVATAR_MAX_AVATARS_PER_USER = getattr(settings, 'AVATAR_MAX_AVATARS_PER_USER', 42) -AVATAR_MAX_SIZE = getattr(settings, 'AVATAR_MAX_SIZE', 1024 * 1024) -AVATAR_THUMB_FORMAT = getattr(settings, 'AVATAR_THUMB_FORMAT', "JPEG") -AVATAR_THUMB_QUALITY = getattr(settings, 'AVATAR_THUMB_QUALITY', 85) -AVATAR_HASH_FILENAMES = getattr(settings, 'AVATAR_HASH_FILENAMES', False) -AVATAR_HASH_USERDIRNAMES = getattr(settings, 'AVATAR_HASH_USERDIRNAMES', False) -AVATAR_ALLOWED_FILE_EXTS = getattr(settings, 'AVATAR_ALLOWED_FILE_EXTS', None) -AVATAR_CACHE_TIMEOUT = getattr(settings, 'AVATAR_CACHE_TIMEOUT', 60 * 60) -AVATAR_STORAGE = getattr(settings, 'AVATAR_STORAGE', settings.DEFAULT_FILE_STORAGE) -AVATAR_CLEANUP_DELETED = getattr(settings, 'AVATAR_CLEANUP_DELETED', False) diff --git a/avatar/templatetags/avatar_tags.py b/avatar/templatetags/avatar_tags.py index d1b32ff..75a1a4f 100644 --- a/avatar/templatetags/avatar_tags.py +++ b/avatar/templatetags/avatar_tags.py @@ -12,8 +12,7 @@ from django.template.loader import render_to_string from django.utils import six from django.utils.translation import ugettext as _ -from avatar.settings import (AVATAR_GRAVATAR_BACKUP, AVATAR_GRAVATAR_DEFAULT, - AVATAR_DEFAULT_SIZE, AVATAR_GRAVATAR_BASE_URL) +from avatar.conf import settings from avatar.util import (get_primary_avatar, get_default_avatar_url, cache_result, get_user_model, get_user, force_bytes) from avatar.models import Avatar @@ -23,25 +22,25 @@ register = template.Library() @cache_result() @register.simple_tag -def avatar_url(user, size=AVATAR_DEFAULT_SIZE): +def avatar_url(user, size=settings.AVATAR_DEFAULT_SIZE): avatar = get_primary_avatar(user, size=size) if avatar: return avatar.avatar_url(size) - if AVATAR_GRAVATAR_BACKUP: + if settings.AVATAR_GRAVATAR_BACKUP: params = {'s': str(size)} - if AVATAR_GRAVATAR_DEFAULT: - params['d'] = AVATAR_GRAVATAR_DEFAULT + if settings.AVATAR_GRAVATAR_DEFAULT: + params['d'] = settings.AVATAR_GRAVATAR_DEFAULT path = "%s/?%s" % (hashlib.md5(force_bytes(user.email)).hexdigest(), urlencode(params)) - return urljoin(AVATAR_GRAVATAR_BASE_URL, path) + return urljoin(settings.AVATAR_GRAVATAR_BASE_URL, path) return get_default_avatar_url() @cache_result() @register.simple_tag -def avatar(user, size=AVATAR_DEFAULT_SIZE, **kwargs): +def avatar(user, size=settings.AVATAR_DEFAULT_SIZE, **kwargs): if not isinstance(user, get_user_model()): try: user = get_user(user) @@ -71,7 +70,7 @@ def has_avatar(user): @cache_result() @register.simple_tag -def primary_avatar(user, size=AVATAR_DEFAULT_SIZE): +def primary_avatar(user, size=settings.AVATAR_DEFAULT_SIZE): """ This tag tries to get the default avatar for a user without doing any db requests. It achieve this by linking to a special view that will do all the @@ -86,7 +85,7 @@ def primary_avatar(user, size=AVATAR_DEFAULT_SIZE): @cache_result() @register.simple_tag -def render_avatar(avatar, size=AVATAR_DEFAULT_SIZE): +def render_avatar(avatar, size=settings.AVATAR_DEFAULT_SIZE): if not avatar.thumbnail_exists(size): avatar.create_thumbnail(size) return """%s""" % ( diff --git a/avatar/util.py b/avatar/util.py index 6f4571c..195bee6 100644 --- a/avatar/util.py +++ b/avatar/util.py @@ -1,6 +1,5 @@ import hashlib -from django.conf import settings from django.core.cache import cache from django.utils import six from django.template.defaultfilters import slugify @@ -22,8 +21,8 @@ except ImportError: else: custom_user_model = True -from avatar.settings import (AVATAR_DEFAULT_URL, AVATAR_CACHE_TIMEOUT, - AUTO_GENERATE_AVATAR_SIZES, AVATAR_DEFAULT_SIZE) +from avatar.conf import settings + cached_funcs = set() @@ -56,11 +55,11 @@ def get_cache_key(user_or_username, size, prefix): def cache_set(key, value): - cache.set(key, value, AVATAR_CACHE_TIMEOUT) + cache.set(key, value, settings.AVATAR_CACHE_TIMEOUT) return value -def cache_result(default_size=AVATAR_DEFAULT_SIZE): +def cache_result(default_size=settings.AVATAR_DEFAULT_SIZE): """ Decorator to cache the result of functions that take a ``user`` and a ``size`` value. @@ -70,7 +69,6 @@ def cache_result(default_size=AVATAR_DEFAULT_SIZE): prefix = func.__name__ cached_funcs.add(prefix) key = get_cache_key(user, size or default_size, prefix=prefix) - print key result = cache.get(key) if result is None: result = func(user, size or default_size) @@ -84,7 +82,7 @@ def invalidate_cache(user, size=None): """ Function to be called when saving or changing an user's avatars. """ - sizes = set(AUTO_GENERATE_AVATAR_SIZES) + sizes = set(settings.AVATAR_AUTO_GENERATE_SIZES) if size is not None: sizes.add(size) for prefix in cached_funcs: @@ -96,20 +94,23 @@ def get_default_avatar_url(): base_url = getattr(settings, 'STATIC_URL', None) if not base_url: base_url = getattr(settings, 'MEDIA_URL', '') - # Don't use base_url if the default avatar url starts with http:// of https:// - if AVATAR_DEFAULT_URL.startswith('http://') or AVATAR_DEFAULT_URL.startswith('https://'): - return AVATAR_DEFAULT_URL + + # Don't use base_url if the default url starts with http:// of https:// + if settings.AVATAR_DEFAULT_URL.startswith(('http://', 'https://')): + return settings.AVATAR_DEFAULT_URL # We'll be nice and make sure there are no duplicated forward slashes ends = base_url.endswith('/') - begins = AVATAR_DEFAULT_URL.startswith('/') + + begins = settings.AVATAR_DEFAULT_URL.startswith('/') if ends and begins: base_url = base_url[:-1] elif not ends and not begins: - return '%s/%s' % (base_url, AVATAR_DEFAULT_URL) - return '%s%s' % (base_url, AVATAR_DEFAULT_URL) + return '%s/%s' % (base_url, settings.AVATAR_DEFAULT_URL) + + return '%s%s' % (base_url, settings.AVATAR_DEFAULT_URL) -def get_primary_avatar(user, size=AVATAR_DEFAULT_SIZE): +def get_primary_avatar(user, size=settings.AVATAR_DEFAULT_SIZE): User = get_user_model() if not isinstance(user, User): try: diff --git a/avatar/views.py b/avatar/views.py index 5a2d0b0..6e6d077 100644 --- a/avatar/views.py +++ b/avatar/views.py @@ -6,9 +6,9 @@ from django.utils.translation import ugettext as _ from django.contrib import messages from django.contrib.auth.decorators import login_required +from django.conf import settings from avatar.forms import PrimaryAvatarForm, DeleteAvatarForm, UploadAvatarForm from avatar.models import Avatar -from avatar.settings import AVATAR_MAX_AVATARS_PER_USER, AVATAR_DEFAULT_SIZE from avatar.signals import avatar_updated from avatar.util import (get_primary_avatar, get_default_avatar_url, get_user_model, get_user) @@ -16,20 +16,21 @@ from avatar.util import (get_primary_avatar, get_default_avatar_url, def _get_next(request): """ - The part that's the least straightforward about views in this module is how they - determine their redirects after they have finished computation. + The part that's the least straightforward about views in this module is + how they determine their redirects after they have finished computation. - In short, they will try and determine the next place to go in the following order: + In short, they will try and determine the next place to go in the + following order: - 1. If there is a variable named ``next`` in the *POST* parameters, the view will - redirect to that variable's value. - 2. If there is a variable named ``next`` in the *GET* parameters, the view will - redirect to that variable's value. - 3. If Django can determine the previous page from the HTTP headers, the view will - redirect to that previous page. + 1. If there is a variable named ``next`` in the *POST* parameters, the + view will redirect to that variable's value. + 2. If there is a variable named ``next`` in the *GET* parameters, + the view will redirect to that variable's value. + 3. If Django can determine the previous page from the HTTP headers, + the view will redirect to that previous page. """ next = request.POST.get('next', request.GET.get('next', - request.META.get('HTTP_REFERER', None))) + request.META.get('HTTP_REFERER', None))) if not next: next = request.path return next @@ -46,11 +47,12 @@ def _get_avatars(user): else: avatar = None - if AVATAR_MAX_AVATARS_PER_USER == 1: + if settings.AVATAR_MAX_AVATARS_PER_USER == 1: avatars = primary_avatar else: - # Slice the default set now that we used the queryset for the primary avatar - avatars = avatars[:AVATAR_MAX_AVATARS_PER_USER] + # Slice the default set now that we used + # the queryset for the primary avatar + avatars = avatars[:settings.AVATAR_MAX_AVATARS_PER_USER] return (avatar, avatars) @@ -61,7 +63,8 @@ def add(request, extra_context=None, next_override=None, extra_context = {} avatar, avatars = _get_avatars(request.user) upload_avatar_form = upload_form(request.POST or None, - request.FILES or None, user=request.user) + request.FILES or None, + user=request.user) if request.method == "POST" and 'avatar' in request.FILES: if upload_avatar_form.is_valid(): avatar = Avatar(user=request.user, primary=True) @@ -94,7 +97,8 @@ def change(request, extra_context=None, next_override=None, kwargs = {} upload_avatar_form = upload_form(user=request.user, **kwargs) primary_avatar_form = primary_form(request.POST or None, - user=request.user, avatars=avatars, **kwargs) + user=request.user, + avatars=avatars, **kwargs) if request.method == "POST": updated = False if 'choice' in request.POST and primary_avatar_form.is_valid(): @@ -125,7 +129,8 @@ def delete(request, extra_context=None, next_override=None, *args, **kwargs): extra_context = {} avatar, avatars = _get_avatars(request.user) delete_avatar_form = DeleteAvatarForm(request.POST or None, - user=request.user, avatars=avatars) + user=request.user, + avatars=avatars) if request.method == 'POST': if delete_avatar_form.is_valid(): ids = delete_avatar_form.cleaned_data['choices'] @@ -135,11 +140,14 @@ def delete(request, extra_context=None, next_override=None, *args, **kwargs): if six.text_type(a.id) not in ids: a.primary = True a.save() - avatar_updated.send(sender=Avatar, user=request.user, avatar=avatar) + avatar_updated.send(sender=Avatar, user=request.user, + avatar=avatar) break Avatar.objects.filter(id__in=ids).delete() - messages.success(request, _("Successfully deleted the requested avatars.")) + messages.success(request, + _("Successfully deleted the requested avatars.")) return redirect(next_override or _get_next(request)) + context = { 'avatar': avatar, 'avatars': avatars, @@ -156,10 +164,13 @@ def avatar_gallery(request, username, template_name="avatar/gallery.html"): user = get_user(username) except get_user_model().DoesNotExist: raise Http404 - return render(request, template_name, { + + context = { "other_user": user, "avatars": user.avatar_set.all(), - }) + } + + return render(request, template_name, context) def avatar(request, username, id, template_name="avatar/avatar.html"): @@ -207,7 +218,7 @@ def avatar(request, username, id, template_name="avatar/avatar.html"): }) -def render_primary(request, extra_context={}, user=None, size=AVATAR_DEFAULT_SIZE, *args, **kwargs): +def render_primary(request, user=None, size=settings.AVATAR_DEFAULT_SIZE): size = int(size) avatar = get_primary_avatar(user, size=size) if avatar: @@ -216,6 +227,8 @@ def render_primary(request, extra_context={}, user=None, size=AVATAR_DEFAULT_SIZ # be useful in certain situations, particulary if there is a CDN and # we want to minimize the storage usage on our static server, letting # the CDN store those files instead - return redirect(avatar.avatar_url(size)) + url = avatar.avatar_url(size) else: - return redirect(get_default_avatar_url()) + url = get_default_avatar_url() + + return redirect(url) diff --git a/setup.py b/setup.py index f5b624c..40bc22f 100644 --- a/setup.py +++ b/setup.py @@ -52,7 +52,9 @@ setup( 'media/avatar/img/default.jpg', ], }, - install_requires=['Pillow>=2.0'], - include_package_data=True, + install_requires=[ + 'Pillow>=2.0', + 'django-appconf>=0.6', + ], zip_safe=False, ) diff --git a/tests/tests.py b/tests/tests.py index 985d2ba..1df24c1 100644 --- a/tests/tests.py +++ b/tests/tests.py @@ -4,7 +4,7 @@ from django.test import TestCase from django.core.urlresolvers import reverse from django.conf import settings -from avatar.settings import AVATAR_DEFAULT_URL, AVATAR_MAX_AVATARS_PER_USER +from avatar.conf import settings from avatar.util import get_primary_avatar, get_user_model from avatar.models import Avatar from PIL import Image @@ -72,7 +72,7 @@ class AvatarUploadTests(TestCase): if not base_url: base_url = settings.MEDIA_URL self.assertTrue(base_url in loc) - self.assertTrue(loc.endswith(AVATAR_DEFAULT_URL)) + self.assertTrue(loc.endswith(settings.AVATAR_DEFAULT_URL)) def testNonExistingUser(self): a = get_primary_avatar("nonexistinguser") @@ -110,7 +110,7 @@ class AvatarUploadTests(TestCase): self.assertEqual(avatars[0].id, primaries[0].id) def testTooManyAvatars(self): - for i in range(0, AVATAR_MAX_AVATARS_PER_USER): + for i in range(0, settings.AVATAR_MAX_AVATARS_PER_USER): self.testNormalImageUpload() count_before = Avatar.objects.filter(user=self.user).count() response = upload_helper(self, "test.png")