Ralfp 12 лет назад
Родитель
Сommit
1a5d7cc919

+ 2 - 2
.gitignore

@@ -182,9 +182,9 @@ south/**
 static/avatars/protoss
 static/avatars/protoss
 static/avatars/terran
 static/avatars/terran
 static/avatars/zerg
 static/avatars/zerg
+static/avatars/_thumbs
+static/avatars/custom
 static/avatars/custom.gif
 static/avatars/custom.gif
-static/strawman/**
-templates/strawman/**
 unidecode/**
 unidecode/**
 yaml/**
 yaml/**
 dev-manage.py
 dev-manage.py

+ 1 - 0
README.md

@@ -42,6 +42,7 @@ After you set low-level configuration of Misago, fire following commands on mana
 * __syncdb__ - this will create database structure for Misago
 * __syncdb__ - this will create database structure for Misago
 * __loadfixtures__ - this will populate Misago database with default data
 * __loadfixtures__ - this will populate Misago database with default data
 * __adduser Admin admin@example.com password --admin__ - this will create first admin user
 * __adduser Admin admin@example.com password --admin__ - this will create first admin user
+* __genavatars__ - this will rebuild avatars gallery thumbnails
 
 
 Misago stands on shoulders of Django and Django documentation covers deployment of apps extensively:
 Misago stands on shoulders of Django and Django documentation covers deployment of apps extensively:
 https://docs.djangoproject.com/en/dev/howto/deployment/
 https://docs.djangoproject.com/en/dev/howto/deployment/

+ 5 - 0
misago/settings_base.py

@@ -10,6 +10,11 @@ ADMIN_PATH = ''
 # Default format of Misago generated HTML
 # Default format of Misago generated HTML
 OUTPUT_FORMAT = 'html5'
 OUTPUT_FORMAT = 'html5'
 
 
+# Default avatar sizes
+# Those are avatar sizes Misago generates images for
+# Remember to run "genavatars" command when you change this setting!
+AVATAR_SIZES = (125, 100, 80, 60, 40, 24)
+
 # If you set this to False, Django will make some optimizations so as not
 # If you set this to False, Django will make some optimizations so as not
 # to load the internationalization machinery.
 # to load the internationalization machinery.
 USE_I18N = True
 USE_I18N = True

+ 7 - 2
misago/usercp/avatar/views.py

@@ -163,8 +163,8 @@ def crop(request, upload=False):
                 crop_y = int(aspect * float(request.POST['crop_y']))
                 crop_y = int(aspect * float(request.POST['crop_y']))
                 crop_w = int(aspect * float(request.POST['crop_w']))
                 crop_w = int(aspect * float(request.POST['crop_w']))
                 avatar = source.crop((crop_x, crop_y, crop_x + crop_w, crop_y + crop_w))
                 avatar = source.crop((crop_x, crop_y, crop_x + crop_w, crop_y + crop_w))
-                avatar.thumbnail((125, 125), Image.ANTIALIAS)
-                
+                avatar.thumbnail((settings.AVATAR_SIZES[0], settings.AVATAR_SIZES[0]), Image.ANTIALIAS)
+                            
                 if upload:
                 if upload:
                     image_name, image_extension = path(request.user.avatar_temp).splitext()
                     image_name, image_extension = path(request.user.avatar_temp).splitext()
                 else:
                 else:
@@ -172,6 +172,10 @@ def crop(request, upload=False):
                 image_name = '%s_%s%s' % (request.user.pk, get_random_string(8), image_extension)
                 image_name = '%s_%s%s' % (request.user.pk, get_random_string(8), image_extension)
                 avatar.save(image_path + image_name)
                 avatar.save(image_path + image_name)
                 
                 
+                for size in settings.AVATAR_SIZES[1:]:
+                    avatar.thumbnail((size, size), Image.ANTIALIAS)
+                    avatar.save(image_path + str(size) + '_' + image_name)
+                
                 request.user.delete_avatar_image()
                 request.user.delete_avatar_image()
                 if upload:
                 if upload:
                     request.user.delete_avatar_original()
                     request.user.delete_avatar_original()
@@ -194,6 +198,7 @@ def crop(request, upload=False):
                                             context_instance=RequestContext(request, {
                                             context_instance=RequestContext(request, {
                                               'message': message,
                                               'message': message,
                                               'after_upload': upload,
                                               'after_upload': upload,
+                                              'avatar_size': settings.AVATAR_SIZES[0],
                                               'source': 'avatars/%s' % (request.user.avatar_temp if upload else request.user.avatar_original),
                                               'source': 'avatars/%s' % (request.user.avatar_temp if upload else request.user.avatar_original),
                                               'tab': 'avatar',
                                               'tab': 'avatar',
                                             }));
                                             }));

+ 68 - 0
misago/users/management/commands/genavatars.py

@@ -0,0 +1,68 @@
+from django.core.management.base import BaseCommand, CommandError
+from django.conf import settings
+from path import path
+try:
+    from PIL import Image
+    has_pil = True
+except ImportError:
+    has_pil = False
+from misago.users.models import User
+    
+class Command(BaseCommand):
+    help = 'Regenerates avatar images for new dimensions'
+    def handle(self, *args, **options):
+        if not has_pil:
+            raise CommandError('genavatars requires Python Imaging Library to be installed in order to run')
+        self.scale_user_avatars()
+        self.scale_gallery_avatars()
+        self.stdout.write('\n\nAvatar images have been regenerated.\n')
+        
+    def scale_image(self, image_src, image_dir=None):
+        avatar = Image.open(image_src).convert("RGBA")
+        image_name = path.basename(path(image_src))
+        if not image_dir:
+            image_dir = path.dirname(path(image_src)) + '/%s_'
+        for size in settings.AVATAR_SIZES[1:]:
+            avatar.thumbnail((size, size), Image.ANTIALIAS)
+            avatar.save(image_dir % size + image_name)
+    
+    def scale_user_avatars(self):
+        for user in User.objects.filter(avatar_type='upload').iterator():
+            for image in path(settings.MEDIA_ROOT).joinpath('avatars').files('*_%s' % user.avatar_image):
+                if not image.isdir():
+                    image.remove()
+            self.scale_image(settings.MEDIA_ROOT + 'avatars/' + user.avatar_image)
+    
+    def scale_gallery_avatars(self):
+        try:
+            thumb_dir = path(settings.STATICFILES_DIRS[0]).joinpath('avatars').joinpath('_thumbs')
+            items = [thumb_dir]
+            for item in thumb_dir.walk():
+                items.append(item)
+            for item in reversed(items):
+                if item.isdir():
+                    item.rmdir()
+                else:
+                    item.remove()
+        except Exception:
+            pass
+        avatars_dir = path(settings.STATICFILES_DIRS[0]).joinpath('avatars')
+        avatars_len = len(avatars_dir)
+        avatars_list = []
+        for directory in avatars_dir.dirs():
+            avatars_list += directory.files('*.gif')
+            avatars_list += directory.files('*.jpg')
+            avatars_list += directory.files('*.jpeg')
+            avatars_list += directory.files('*.png')
+        thumb_dir = path(settings.STATICFILES_DIRS[0]).joinpath('avatars').joinpath('_thumbs')
+        thumb_dir.mkdir(777)
+        for size in settings.AVATAR_SIZES[1:]:
+            thumb_dir.joinpath(str(size)).mkdir(777)
+        for directory in avatars_dir.dirs():
+            dirname = path(directory[avatars_len:]).basename()
+            if dirname != '_thumbs':
+                for size in settings.AVATAR_SIZES[1:]:
+                    thumb_dir.joinpath(str(size)).joinpath(dirname).mkdir(777)
+        for avatar in avatars_list:
+            self.scale_image(avatar,
+                             thumb_dir + '/%s' + avatar.dirname()[avatars_len:] + '/')

+ 19 - 13
misago/users/models.py

@@ -18,6 +18,7 @@ from misago.roles.models import Role
 from misago.settings.settings import Settings as DBSettings
 from misago.settings.settings import Settings as DBSettings
 from misago.users.validators import validate_username, validate_password, validate_email
 from misago.users.validators import validate_username, validate_password, validate_email
 from misago.utils import get_random_string, slugify
 from misago.utils import get_random_string, slugify
+from misago.utils.avatars import avatar_size
 
 
 class UserManager(models.Manager):
 class UserManager(models.Manager):
     """
     """
@@ -234,7 +235,7 @@ class User(models.Model):
                 if not avatars_list:
                 if not avatars_list:
                     avatars_list = []
                     avatars_list = []
                     for directory in path(settings.STATICFILES_DIRS[0]).joinpath('avatars').dirs():
                     for directory in path(settings.STATICFILES_DIRS[0]).joinpath('avatars').dirs():
-                        if not directory[-7:] == '_locked':
+                        if not directory[-7:] == '_locked' and not directory[-7:] == '_thumbs':
                             avatars_list += directory.files('*.gif')
                             avatars_list += directory.files('*.gif')
                             avatars_list += directory.files('*.jpg')
                             avatars_list += directory.files('*.jpg')
                             avatars_list += directory.files('*.jpeg')
                             avatars_list += directory.files('*.jpeg')
@@ -275,6 +276,13 @@ class User(models.Model):
 
 
     def delete_avatar_image(self):
     def delete_avatar_image(self):
         if self.avatar_image:
         if self.avatar_image:
+            for size in settings.AVATAR_SIZES[1:]:
+                try:
+                    av_file = path(settings.MEDIA_ROOT + 'avatars/' + str(size) + '_' + self.avatar_image)
+                    if not av_file.isdir():
+                        av_file.remove()
+                except Exception as e:
+                    print e
             try:
             try:
                 av_file = path(settings.MEDIA_ROOT + 'avatars/' + self.avatar_image)
                 av_file = path(settings.MEDIA_ROOT + 'avatars/' + self.avatar_image)
                 if not av_file.isdir():
                 if not av_file.isdir():
@@ -402,25 +410,23 @@ class User(models.Model):
             cache.set(self.acl_key, acl, 2592000)
             cache.set(self.acl_key, acl, 2592000)
         return acl
         return acl
             
             
-    def get_avatar(self, size='normal'):
+    def get_avatar(self, size=None):
+        image_size = avatar_size(size) if size else None
+                
         # Get uploaded avatar
         # Get uploaded avatar
         if self.avatar_type == 'upload':
         if self.avatar_type == 'upload':
-            return settings.MEDIA_URL + 'avatars/' + self.avatar_image
+            image_prefix = '%s_' % image_size if image_size else ''
+            return settings.MEDIA_URL + 'avatars/' + image_prefix + self.avatar_image
         
         
         # Get gallery avatar
         # Get gallery avatar
         if self.avatar_type == 'gallery':
         if self.avatar_type == 'gallery':
-            return settings.STATIC_URL + 'avatars/' + self.avatar_image
+            image_prefix = '_thumbs/%s/' % image_size if image_size else ''
+            return settings.STATIC_URL + 'avatars/' + image_prefix + self.avatar_image
         
         
         # No avatar found, get gravatar
         # No avatar found, get gravatar
-        if size == 'big':
-            size = 150;
-        elif size == 'small':
-            size = 64;
-        elif size == 'tiny':
-            size = 46;
-        else:
-            size = 100
-        return 'http://www.gravatar.com/avatar/%s?s=%s' % (hashlib.md5(self.email).hexdigest(), size)
+        if not image_size:
+            image_size = settings.AVATAR_SIZES[0]
+        return 'http://www.gravatar.com/avatar/%s?s=%s' % (hashlib.md5(self.email).hexdigest(), image_size)
     
     
     def get_title(self):
     def get_title(self):
         if self.title:
         if self.title:

+ 19 - 0
misago/utils/avatars.py

@@ -0,0 +1,19 @@
+from django.conf import settings
+try:
+    import PIL
+    has_pil = True
+except ImportError:
+    has_pil = False
+avatar_sizes = {}
+
+def avatar_size(size):
+    if not has_pil:
+        return None
+    try:
+        return avatar_sizes[size]
+    except KeyError:
+        avatar_sizes[size] = None
+        for i in settings.AVATAR_SIZES[1:]:
+            if size <= i:
+                avatar_sizes[size] = i
+    return avatar_sizes[size]

BIN
static/avatars/100_avatar_guest.jpg


BIN
static/avatars/24_avatar_guest.jpg


BIN
static/avatars/40_avatar_guest.jpg


BIN
static/avatars/60_avatar_guest.jpg


BIN
static/avatars/80_avatar_guest.jpg


+ 1 - 0
static/sora/css/sora.css

@@ -969,6 +969,7 @@ td.lead-cell{color:#555555;font-weight:bold;}
 .threads-list .jump:hover i{background-image:url("../img/glyphicons-halflings-white.png");}
 .threads-list .jump:hover i{background-image:url("../img/glyphicons-halflings-white.png");}
 .threads-list .thread-stat{text-align:right;}
 .threads-list .thread-stat{text-align:right;}
 .threads-list .thread-author,.threads-list .thread-poster{font-weight:bold;}.threads-list .thread-author a,.threads-list .thread-poster a{color:#333333;}
 .threads-list .thread-author,.threads-list .thread-poster{font-weight:bold;}.threads-list .thread-author a,.threads-list .thread-poster a{color:#333333;}
+.threads-list .thread-author .avatar-tiny,.threads-list .thread-poster .avatar-tiny{margin-right:4px;}
 .threads-list .thread-closed{background-color:#9d261d;}
 .threads-list .thread-closed{background-color:#9d261d;}
 .threads-list .thread-new{background-color:#0088cc;}
 .threads-list .thread-new{background-color:#0088cc;}
 .threads-list .thread-flags{float:right;margin:0px;padding:0px;}.threads-list .thread-flags li{float:right;margin:0px;margin-left:6px;padding:0px;}
 .threads-list .thread-flags{float:right;margin:0px;padding:0px;}.threads-list .thread-flags li{float:right;margin:0px;margin-left:6px;padding:0px;}

+ 4 - 0
static/sora/css/sora/threads.less

@@ -52,6 +52,10 @@
     a {
     a {
       color: @textColor;
       color: @textColor;
     }
     }
+    
+    .avatar-tiny {
+      margin-right: 4px;
+    }
   }
   }
   
   
   .thread-closed {
   .thread-closed {

+ 1 - 1
templates/admin/home.html

@@ -40,7 +40,7 @@ One Administrator Online
         {% for session in admins %}    	
         {% for session in admins %}    	
         <tr>
         <tr>
           <td>
           <td>
-              <a href="{% url 'user' username=session.user.username_slug, user=session.user.pk %}"><img src="{{ session.user.get_avatar('medium') }}" class="avatar" alt="{% trans %}Admin's Avatar{% endtrans %}" title="{% trans %}Admin's Avatar{% endtrans %}"> <strong>{{ session.user.username }}</strong></a>
+              <a href="{% url 'user' username=session.user.username_slug, user=session.user.pk %}"><img src="{{ session.user.get_avatar(22) }}" class="avatar" alt="{% trans %}Admin's Avatar{% endtrans %}" title="{% trans %}Admin's Avatar{% endtrans %}"> <strong>{{ session.user.username }}</strong></a>
               <div class="muted" style="float: right;">{% trans start=session.start|timesince, ip=session.ip %}started {{ start }} ago from {{ ip }}{% endtrans %} <span class="info-popover tooltip-top" title="{% trans last=session.last|timesince %}Last click was {{ last }} ago{% endtrans %}"><i class="icon-time"></i></span></div>
               <div class="muted" style="float: right;">{% trans start=session.start|timesince, ip=session.ip %}started {{ start }} ago from {{ ip }}{% endtrans %} <span class="info-popover tooltip-top" title="{% trans last=session.last|timesince %}Last click was {{ last }} ago{% endtrans %}"><i class="icon-time"></i></span></div>
           </td>
           </td>
         </tr>{% endfor %}
         </tr>{% endfor %}

+ 1 - 1
templates/admin/layout.html

@@ -16,7 +16,7 @@
       	<li><a href="{% url 'index' %}"><i class="icon-home"></i> {% trans %}Forums Index{% endtrans %}</a></li>
       	<li><a href="{% url 'index' %}"><i class="icon-home"></i> {% trans %}Forums Index{% endtrans %}</a></li>
       </ul>
       </ul>
       <div class="user-profile pull-right">
       <div class="user-profile pull-right">
-        <img src="{{ user.get_avatar() }}" class="avatar-small" alt="{{ user.username }}" title="{{ user.username }}"> {{ user.username }}
+        <img src="{{ user.get_avatar(28) }}" class="avatar-small" alt="{{ user.username }}" title="{{ user.username }}"> {{ user.username }}
       </div>
       </div>
     </div>
     </div>
   </div>
   </div>

+ 1 - 1
templates/admin/team/list.html

@@ -14,7 +14,7 @@
     <tr>
     <tr>
       {% for user in items %} 
       {% for user in items %} 
       <td class="colspan6">
       <td class="colspan6">
-          <a href="{% url 'user' username=user.username_slug, user=user.pk %}"><img src="{{ user.get_avatar() }}" class="avatar" alt="{% trans %}User's Avatar{% endtrans %}" title="{% trans %}Admin's Avatar{% endtrans %}"> <strong>{{ user.username }}</strong></a>
+          <a href="{% url 'user' username=user.username_slug, user=user.pk %}"><img src="{{ user.get_avatar(42) }}" class="avatar" alt="{% trans %}User's Avatar{% endtrans %}" title="{% trans %}Admin's Avatar{% endtrans %}"> <strong>{{ user.username }}</strong></a>
       </td>{% if loop.last and loop.index is odd %}
       </td>{% if loop.last and loop.index is odd %}
       <td class="span6">
       <td class="span6">
       	&nbsp;
       	&nbsp;

+ 1 - 1
templates/admin/users/list.html

@@ -24,7 +24,7 @@
 {% endblock %}
 {% endblock %}
 
 
 {% block table_row scoped %}
 {% block table_row scoped %}
-  <td class="avatar-small"><img src="{{ item.get_avatar('small') }}" class="avatar-small" alt="{% trans %}User Avatar{% endtrans %}"></td>
+  <td class="avatar-small"><img src="{{ item.get_avatar(28) }}" class="avatar-small" alt="{% trans %}User Avatar{% endtrans %}"></td>
   <td colspan="2" class="lead-cell">
   <td colspan="2" class="lead-cell">
   	<strong>{{ item.username }}</strong> <span class="muted">{{ item.email }}</span>{% if item.activation > 0 %} <span class="label tooltip-top" title="{% if item.activation == 1 -%}
   	<strong>{{ item.username }}</strong> <span class="muted">{{ item.email }}</span>{% if item.activation > 0 %} <span class="label tooltip-top" title="{% if item.activation == 1 -%}
   	{% trans %}This user has not yet validated his e-mail address.{% endtrans %}
   	{% trans %}This user has not yet validated his e-mail address.{% endtrans %}

+ 1 - 1
templates/sora/index.html

@@ -25,7 +25,7 @@
     <h3>{% trans %}Team Online{% endtrans %}</h3>
     <h3>{% trans %}Team Online{% endtrans %}</h3>
     {% for user in team_online %}
     {% for user in team_online %}
     <div class="board-team">
     <div class="board-team">
-      <img src="{{ user.get_avatar() }}" alt="" class="avatar-small"> <a href="{% url 'user' username=user.username_slug, user=user.pk %}">{{ user.username }}</a>{% if user.get_title() %} <span class="muted">{{ _(user.get_title()) }}</span>{% endif %}
+      <img src="{{ user.get_avatar(28) }}" alt="" class="avatar-small"> <a href="{% url 'user' username=user.username_slug, user=user.pk %}">{{ user.username }}</a>{% if user.get_title() %} <span class="muted">{{ _(user.get_title()) }}</span>{% endif %}
     </div>
     </div>
     <hr>
     <hr>
     {% endfor %}
     {% endfor %}

+ 2 - 2
templates/sora/macros.html

@@ -5,8 +5,8 @@
 {%- endmacro %}
 {%- endmacro %}
 
 
 {# Guest avatar #}
 {# Guest avatar #}
-{% macro avatar_guest() -%}
-{{ STATIC_URL }}avatars/avatar_guest.jpg
+{% macro avatar_guest(size=None) -%}
+{{ STATIC_URL }}avatars/{% if size %}{{ size }}_{% endif %}avatar_guest.jpg
 {%- endmacro %}
 {%- endmacro %}
 
 
 {# Messages list macro #}
 {# Messages list macro #}

+ 1 - 1
templates/sora/profiles/list.html

@@ -45,7 +45,7 @@
   <tbody>
   <tbody>
     <tr>{% for user in users %}
     <tr>{% for user in users %}
       <td class="span6{% if user.get_style() %} {{ user.get_style() }}{% endif %}">
       <td class="span6{% if user.get_style() %} {{ user.get_style() }}{% endif %}">
-        <a href="{% url 'user' username=user.username_slug, user=user.pk %}"><img src="{{ user.get_avatar('medium') }}" class="avatar" alt="{% trans %}Member's Avatar{% endtrans %}" title="{% trans %}Member's Avatar{% endtrans %}"> <strong>{{ user.username }}</strong>{% if user.title or (in_search and user.get_title()) %} <span class="muted">{% if in_search%}{{ _(user.get_title()) }}{% else %}{{ _(user.title) }}{% endif %}</span>{% endif %}</a>
+        <a href="{% url 'user' username=user.username_slug, user=user.pk %}"><img src="{{ user.get_avatar(42) }}" class="avatar" alt="{% trans %}Member's Avatar{% endtrans %}" title="{% trans %}Member's Avatar{% endtrans %}"> <strong>{{ user.username }}</strong>{% if user.title or (in_search and user.get_title()) %} <span class="muted">{% if in_search%}{{ _(user.get_title()) }}{% else %}{{ _(user.title) }}{% endif %}</span>{% endif %}</a>
       </td>{% if loop.last and loop.index is odd %}
       </td>{% if loop.last and loop.index is odd %}
       <td class="span6">
       <td class="span6">
       	&nbsp;
       	&nbsp;

+ 3 - 2
templates/sora/threads/list.html

@@ -28,6 +28,7 @@
   </div>
   </div>
 </div>
 </div>
 {% endif %}
 {% endif %}
+      
 {% if message %}{{ macros.draw_message(message) }}{% endif %}
 {% if message %}{{ macros.draw_message(message) }}{% endif %}
 <div class="list-nav">
 <div class="list-nav">
   {{ pager() }}
   {{ pager() }}
@@ -71,9 +72,9 @@
           {% if thread.deleted %}<li><span class="tooltip-top" title="{% trans %}This thread has been deleted.{% endtrans %}"><i class="icon-remove"></i></span></li>{% endif %}
           {% if thread.deleted %}<li><span class="tooltip-top" title="{% trans %}This thread has been deleted.{% endtrans %}"><i class="icon-remove"></i></span></li>{% endif %}
         </ul>
         </ul>
       </td>
       </td>
-      <td class="span2 thread-author"><span class="tooltip-top" title="{{ thread.start|reltimesince }}">{% if thread.start_poster_id %}{% if settings.avatars_on_threads_list %}<img src="{{ thread.start_poster.get_avatar() }}" alt="" class="avatar-tiny"> {% endif %}<a href="{% url 'user' user=thread.start_poster_id, username=thread.start_poster_slug %}">{{ thread.start_poster_name }}</a>{% else %}{% if settings.avatars_on_threads_list %}<img src="{{ macros.avatar_guest() }}" alt="" class="avatar-tiny"> {% endif %}<em class="muted">{{ thread.start_poster_name }}</em>{% endif %}</span></td>
+      <td class="span2 thread-author"><span class="tooltip-top" title="{{ thread.start|reltimesince }}">{% if thread.start_poster_id %}{% if settings.avatars_on_threads_list %}<img src="{{ thread.start_poster.get_avatar(24) }}" alt="" class="avatar-tiny"> {% endif %}<a href="{% url 'user' user=thread.start_poster_id, username=thread.start_poster_slug %}">{{ thread.start_poster_name }}</a>{% else %}{% if settings.avatars_on_threads_list %}<img src="{{ macros.avatar_guest(24) }}" alt="" class="avatar-tiny"> {% endif %}<em class="muted">{{ thread.start_poster_name }}</em>{% endif %}</span></td>
       <td class="span1 thread-stat">{{ thread.replies|intcomma }}</td>
       <td class="span1 thread-stat">{{ thread.replies|intcomma }}</td>
-      <td class="span2 thread-poster"><span class="tooltip-top"title="{{ thread.last|reltimesince }}">{% if thread.last_poster_id %}{% if settings.avatars_on_threads_list %}<img src="{{ thread.last_poster.get_avatar() }}" alt="" class="avatar-tiny"> {% endif %}<a href="{% url 'user' user=thread.last_poster_id, username=thread.last_poster_slug %}">{{ thread.last_poster_name }}</a>{% else %}{% if settings.avatars_on_threads_list %}<img src="{{ macros.avatar_guest() }}" alt="" class="avatar-tiny"> {% endif %}<em class="muted">{{ thread.last_poster_name }}</em>{% endif %}</span></td>
+      <td class="span2 thread-poster"><span class="tooltip-top" title="{{ thread.last|reltimesince }}">{% if thread.last_poster_id %}{% if settings.avatars_on_threads_list %}<img src="{{ thread.last_poster.get_avatar(24) }}" alt="" class="avatar-tiny"> {% endif %}<a href="{% url 'user' user=thread.last_poster_id, username=thread.last_poster_slug %}">{{ thread.last_poster_name }}</a>{% else %}{% if settings.avatars_on_threads_list %}<img src="{{ macros.avatar_guest(24) }}" alt="" class="avatar-tiny"> {% endif %}<em class="muted">{{ thread.last_poster_name }}</em>{% endif %}</span></td>
       {% if user.is_authenticated() and list_form %}
       {% if user.is_authenticated() and list_form %}
       <td class="check-cell">{% if thread.forum_id == forum.pk %}<label class="checkbox"><input form="threads_form" name="{{ list_form['list_items']['html_name'] }}" type="checkbox" class="checkbox-member" value="{{ thread.pk }}"{% if list_form['list_items']['has_value'] and ('' ~ thread.pk) in list_form['list_items']['value'] %} checked="checked"{% endif %}></label>{% else %}&nbsp;{% endif %}</td>
       <td class="check-cell">{% if thread.forum_id == forum.pk %}<label class="checkbox"><input form="threads_form" name="{{ list_form['list_items']['html_name'] }}" type="checkbox" class="checkbox-member" value="{{ thread.pk }}"{% if list_form['list_items']['has_value'] and ('' ~ thread.pk) in list_form['list_items']['value'] %} checked="checked"{% endif %}></label>{% else %}&nbsp;{% endif %}</td>
       {% endif %}
       {% endif %}

+ 2 - 2
templates/sora/threads/thread.html

@@ -46,7 +46,7 @@
   {% if post.message %}{{ macros.draw_message(post.message) }}{% endif %}
   {% if post.message %}{{ macros.draw_message(post.message) }}{% endif %}
   <div id="post-{{ post.pk }}" class="well well-post{% if post.user and post.user.rank and post.user.rank.style %} {{ post.user.rank.style }}{% endif %}">
   <div id="post-{{ post.pk }}" class="well well-post{% if post.user and post.user.rank and post.user.rank.style %} {{ post.user.rank.style }}{% endif %}">
     <div class="post-author">
     <div class="post-author">
-      <img src="{{ post.user.get_avatar() }}" alt="" class="avatar-normal">
+      <img src="{{ post.user.get_avatar(80) }}" alt="" class="avatar-normal">
       <div class="post-bit">
       <div class="post-bit">
         <a href="{% url 'user' user=post.user.pk, username=post.user.username_slug %}" class="lead">{{ post.user.username }}</a>{% if post.user.get_title() %}
         <a href="{% url 'user' user=post.user.pk, username=post.user.username_slug %}" class="lead">{{ post.user.username }}</a>{% if post.user.get_title() %}
         <p class="user-title">{{ _(post.user.get_title()) }}</p>{% endif %}
         <p class="user-title">{{ _(post.user.get_title()) }}</p>{% endif %}
@@ -145,7 +145,7 @@
   <form action="{% url 'thread_reply' thread=thread.pk, slug=thread.slug %}" method="post">
   <form action="{% url 'thread_reply' thread=thread.pk, slug=thread.slug %}" method="post">
     <input type="hidden" name="{{ csrf_id }}" value="{{ csrf_token }}">
     <input type="hidden" name="{{ csrf_id }}" value="{{ csrf_token }}">
     <input type="hidden" name="quick_reply" value="1">
     <input type="hidden" name="quick_reply" value="1">
-    <img src="{{ user.get_avatar(big) }}" alt="{% trans %}Your Avatar{% endtrans %}" class="avatar-big">
+    <img src="{{ user.get_avatar() }}" alt="{% trans %}Your Avatar{% endtrans %}" class="avatar-big">
     <div class="arrow"></div>
     <div class="arrow"></div>
     {{ editor.editor(quick_reply.post, _('Post Reply')) }}
     {{ editor.editor(quick_reply.post, _('Post Reply')) }}
   </form>
   </form>

+ 1 - 1
templates/sora/userbar.html

@@ -11,7 +11,7 @@
         <li><a href="#" title="{% trans %}New Posts{% endtrans %}" class="tooltip-bottom"><i class="icon-star-empty "></i></a></li>
         <li><a href="#" title="{% trans %}New Posts{% endtrans %}" class="tooltip-bottom"><i class="icon-star-empty "></i></a></li>
       </ul>
       </ul>
       <ul class="nav pull-right">{% if user.is_authenticated() %}
       <ul class="nav pull-right">{% if user.is_authenticated() %}
-        <li class="user-profile"><a href="{% url 'user' user=user.id, username=user.username_slug %}" title="{% trans %}Go to your profile{% endtrans %}" class="tooltip-bottom"><div><img src="{{ user.get_avatar() }}" class="avatar-small" alt="{{ user.username }}" title="{{ user.username }}"> {{ user.username }}</div></a></li>
+        <li class="user-profile"><a href="{% url 'user' user=user.id, username=user.username_slug %}" title="{% trans %}Go to your profile{% endtrans %}" class="tooltip-bottom"><div><img src="{{ user.get_avatar(28) }}" class="avatar-small" alt="{{ user.username }}" title="{{ user.username }}"> {{ user.username }}</div></a></li>
         <li><a href="#" title="{% trans %}Go to Moderator Control Panel{% endtrans %}" class="tooltip-bottom"><i class="icon-tasks"></i> {% trans %}Mod CP{% endtrans %}</a></li>
         <li><a href="#" title="{% trans %}Go to Moderator Control Panel{% endtrans %}" class="tooltip-bottom"><i class="icon-tasks"></i> {% trans %}Mod CP{% endtrans %}</a></li>
         <li><a href="{% url 'usercp' %}" title="{% trans %}Edit your profile options{% endtrans %}" class="tooltip-bottom"><i class="icon-cog"></i> {% trans %}Options{% endtrans %}</a></li>
         <li><a href="{% url 'usercp' %}" title="{% trans %}Edit your profile options{% endtrans %}" class="tooltip-bottom"><i class="icon-cog"></i> {% trans %}Options{% endtrans %}</a></li>
         <li><form action="{% url 'sign_out' %}" method="post"><input type="hidden" name="{{ csrf_id }}" value="{{ csrf_token }}"><button type="submit" title="{% trans %}Sign Out and browse as guest{% endtrans %}" class="btn btn-link tooltip-bottom"><i class="icon-off"></i> {% trans %}Sign Out{% endtrans %}</button></form></li>
         <li><form action="{% url 'sign_out' %}" method="post"><input type="hidden" name="{{ csrf_id }}" value="{{ csrf_token }}"><button type="submit" title="{% trans %}Sign Out and browse as guest{% endtrans %}" class="btn btn-link tooltip-bottom"><i class="icon-off"></i> {% trans %}Sign Out{% endtrans %}</button></form></li>

+ 2 - 2
templates/sora/usercp/avatar_crop.html

@@ -64,8 +64,8 @@
         {
         {
           if (parseInt(c.w) > 0)
           if (parseInt(c.w) > 0)
           {
           {
-            var rx = 125 / c.w;
-            var ry = 125 / c.h;
+            var rx = {{ avatar_size }} / c.w;
+            var ry = {{ avatar_size }} / c.h;
             
             
             $(crop_w).val(c.w);
             $(crop_w).val(c.w);
             $(crop_x).val(c.x);
             $(crop_x).val(c.x);