mirror of
https://github.com/jazzband/django-avatar.git
synced 2026-05-19 04:51:08 +00:00
Use django-appconf for nicer settings handling.
This commit is contained in:
parent
266240250a
commit
65d5f66b9b
10 changed files with 143 additions and 121 deletions
29
avatar/conf.py
Normal file
29
avatar/conf.py
Normal file
|
|
@ -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,))
|
||||
|
|
@ -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('<img src="%s" alt="%s" width="%s" height="%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)
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
@ -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 """<img src="%s" alt="%s" width="%s" height="%s" />""" % (
|
||||
|
|
|
|||
|
|
@ -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:
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
6
setup.py
6
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,
|
||||
)
|
||||
|
|
|
|||
|
|
@ -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")
|
||||
|
|
|
|||
Loading…
Reference in a new issue