Commit ee69bd3a7f847b2f882d36b88d2a467e4a97116e
Exists in
master
and in
39 other branches
Merge branch 'master' of github.com:TracyWebTech/colab
Showing
17 changed files
with
695 additions
and
104 deletions
Show diff stats
TODO.rst
@@ -47,6 +47,7 @@ Interface | @@ -47,6 +47,7 @@ Interface | ||
47 | * Paginar discussoes | 47 | * Paginar discussoes |
48 | * Paginar dashboard de discussoes | 48 | * Paginar dashboard de discussoes |
49 | * Highlight mostrar resultados normalizados (com e sem acentos) | 49 | * Highlight mostrar resultados normalizados (com e sem acentos) |
50 | +* Adicionar opção para escolha de idioma | ||
50 | 51 | ||
51 | 52 | ||
52 | Outros | 53 | Outros |
requirements.txt
src/accounts/migrations/0006_auto__add_field_user_modified.py
0 → 100644
@@ -0,0 +1,69 @@ | @@ -0,0 +1,69 @@ | ||
1 | +# -*- coding: utf-8 -*- | ||
2 | +from south.db import db | ||
3 | +from south.v2 import SchemaMigration | ||
4 | +from django.db import models | ||
5 | +from django.utils import timezone | ||
6 | + | ||
7 | + | ||
8 | +class Migration(SchemaMigration): | ||
9 | + | ||
10 | + def forwards(self, orm): | ||
11 | + # Adding field 'User.modified' | ||
12 | + db.add_column(u'accounts_user', 'modified', | ||
13 | + self.gf('django.db.models.fields.DateTimeField')(auto_now=True, default=timezone.now, blank=True), | ||
14 | + keep_default=False) | ||
15 | + | ||
16 | + | ||
17 | + def backwards(self, orm): | ||
18 | + # Deleting field 'User.modified' | ||
19 | + db.delete_column(u'accounts_user', 'modified') | ||
20 | + | ||
21 | + | ||
22 | + models = { | ||
23 | + u'accounts.user': { | ||
24 | + 'Meta': {'object_name': 'User'}, | ||
25 | + 'date_joined': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}), | ||
26 | + 'email': ('django.db.models.fields.EmailField', [], {'unique': 'True', 'max_length': '75', 'blank': 'True'}), | ||
27 | + 'facebook': ('django.db.models.fields.CharField', [], {'max_length': '128', 'null': 'True', 'blank': 'True'}), | ||
28 | + 'first_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}), | ||
29 | + 'google_talk': ('django.db.models.fields.EmailField', [], {'max_length': '75', 'null': 'True', 'blank': 'True'}), | ||
30 | + 'groups': ('django.db.models.fields.related.ManyToManyField', [], {'symmetrical': 'False', 'related_name': "u'user_set'", 'blank': 'True', 'to': u"orm['auth.Group']"}), | ||
31 | + u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), | ||
32 | + 'institution': ('django.db.models.fields.CharField', [], {'max_length': '128', 'null': 'True', 'blank': 'True'}), | ||
33 | + 'is_active': ('django.db.models.fields.BooleanField', [], {'default': 'True'}), | ||
34 | + 'is_staff': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), | ||
35 | + 'is_superuser': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), | ||
36 | + 'last_login': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}), | ||
37 | + 'last_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}), | ||
38 | + 'modified': ('django.db.models.fields.DateTimeField', [], {'auto_now': 'True', 'blank': 'True'}), | ||
39 | + 'password': ('django.db.models.fields.CharField', [], {'max_length': '128'}), | ||
40 | + 'role': ('django.db.models.fields.CharField', [], {'max_length': '128', 'null': 'True', 'blank': 'True'}), | ||
41 | + 'twitter': ('django.db.models.fields.CharField', [], {'max_length': '128', 'null': 'True', 'blank': 'True'}), | ||
42 | + 'user_permissions': ('django.db.models.fields.related.ManyToManyField', [], {'symmetrical': 'False', 'related_name': "u'user_set'", 'blank': 'True', 'to': u"orm['auth.Permission']"}), | ||
43 | + 'username': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '30'}), | ||
44 | + 'verification_hash': ('django.db.models.fields.CharField', [], {'max_length': '32', 'null': 'True', 'blank': 'True'}), | ||
45 | + 'webpage': ('django.db.models.fields.CharField', [], {'max_length': '256', 'null': 'True', 'blank': 'True'}) | ||
46 | + }, | ||
47 | + u'auth.group': { | ||
48 | + 'Meta': {'object_name': 'Group'}, | ||
49 | + u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), | ||
50 | + 'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '80'}), | ||
51 | + 'permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': u"orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'}) | ||
52 | + }, | ||
53 | + u'auth.permission': { | ||
54 | + 'Meta': {'ordering': "(u'content_type__app_label', u'content_type__model', u'codename')", 'unique_together': "((u'content_type', u'codename'),)", 'object_name': 'Permission'}, | ||
55 | + 'codename': ('django.db.models.fields.CharField', [], {'max_length': '100'}), | ||
56 | + 'content_type': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['contenttypes.ContentType']"}), | ||
57 | + u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), | ||
58 | + 'name': ('django.db.models.fields.CharField', [], {'max_length': '50'}) | ||
59 | + }, | ||
60 | + u'contenttypes.contenttype': { | ||
61 | + 'Meta': {'ordering': "('name',)", 'unique_together': "(('app_label', 'model'),)", 'object_name': 'ContentType', 'db_table': "'django_content_type'"}, | ||
62 | + 'app_label': ('django.db.models.fields.CharField', [], {'max_length': '100'}), | ||
63 | + u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), | ||
64 | + 'model': ('django.db.models.fields.CharField', [], {'max_length': '100'}), | ||
65 | + 'name': ('django.db.models.fields.CharField', [], {'max_length': '100'}) | ||
66 | + } | ||
67 | + } | ||
68 | + | ||
69 | + complete_apps = ['accounts'] |
src/accounts/models.py
@@ -16,6 +16,7 @@ class User(AbstractUser): | @@ -16,6 +16,7 @@ class User(AbstractUser): | ||
16 | google_talk = models.EmailField(null=True, blank=True) | 16 | google_talk = models.EmailField(null=True, blank=True) |
17 | webpage = models.CharField(max_length=256, null=True, blank=True) | 17 | webpage = models.CharField(max_length=256, null=True, blank=True) |
18 | verification_hash = models.CharField(max_length=32, null=True, blank=True) | 18 | verification_hash = models.CharField(max_length=32, null=True, blank=True) |
19 | + modified = models.DateTimeField(auto_now=True) | ||
19 | 20 | ||
20 | def get_absolute_url(self): | 21 | def get_absolute_url(self): |
21 | return reverse('user_profile', kwargs={'username': self.username}) | 22 | return reverse('user_profile', kwargs={'username': self.username}) |
src/accounts/search_indexes.py
1 | # -*- coding: utf-8 -*- | 1 | # -*- coding: utf-8 -*- |
2 | 2 | ||
3 | from haystack import indexes | 3 | from haystack import indexes |
4 | +from django.db.models import Count | ||
4 | 5 | ||
6 | +from proxy.models import Revision, Ticket, Wiki | ||
7 | +from badger.utils import get_users_counters | ||
5 | from .models import User | 8 | from .models import User |
6 | 9 | ||
7 | 10 | ||
8 | class UserIndex(indexes.SearchIndex, indexes.Indexable): | 11 | class UserIndex(indexes.SearchIndex, indexes.Indexable): |
9 | # common fields | 12 | # common fields |
10 | - text = indexes.CharField(document=True, use_template=True) | ||
11 | - url = indexes.CharField(model_attr='get_absolute_url') | 13 | + text = indexes.CharField(document=True, use_template=True, stored=False) |
14 | + url = indexes.CharField(model_attr='get_absolute_url', indexed=False) | ||
12 | title = indexes.CharField(model_attr='get_full_name') | 15 | title = indexes.CharField(model_attr='get_full_name') |
13 | description = indexes.CharField(null=True) | 16 | description = indexes.CharField(null=True) |
14 | type = indexes.CharField() | 17 | type = indexes.CharField() |
15 | icon_name = indexes.CharField() | 18 | icon_name = indexes.CharField() |
16 | 19 | ||
17 | # extra fields | 20 | # extra fields |
18 | - username = indexes.CharField(model_attr='username') | 21 | + username = indexes.CharField(model_attr='username', stored=False) |
19 | name = indexes.CharField(model_attr='get_full_name') | 22 | name = indexes.CharField(model_attr='get_full_name') |
20 | - email = indexes.CharField(model_attr='email') | 23 | + email = indexes.CharField(model_attr='email', stored=False) |
21 | institution = indexes.CharField(model_attr='institution', null=True) | 24 | institution = indexes.CharField(model_attr='institution', null=True) |
22 | role = indexes.CharField(model_attr='role', null=True) | 25 | role = indexes.CharField(model_attr='role', null=True) |
23 | - google_talk = indexes.CharField(model_attr='google_talk', null=True) | ||
24 | - webpage = indexes.CharField(model_attr='webpage', null=True) | 26 | + google_talk = indexes.CharField(model_attr='google_talk', null=True, |
27 | + stored=False) | ||
28 | + webpage = indexes.CharField(model_attr='webpage', null=True, stored=False) | ||
29 | + message_count = indexes.IntegerField(stored=False) | ||
30 | + changeset_count = indexes.IntegerField(stored=False) | ||
31 | + ticket_count = indexes.IntegerField(stored=False) | ||
32 | + wiki_count = indexes.IntegerField(stored=False) | ||
33 | + contribution_count = indexes.IntegerField(stored=False) | ||
25 | 34 | ||
26 | def get_model(self): | 35 | def get_model(self): |
27 | return User | 36 | return User |
28 | 37 | ||
38 | + @property | ||
39 | + def badge_counters(self): | ||
40 | + if not hasattr(self, '_badge_counters'): | ||
41 | + self._badge_counters = get_users_counters() | ||
42 | + return self._badge_counters | ||
43 | + | ||
29 | def get_updated_field(self): | 44 | def get_updated_field(self): |
30 | - return 'date_joined' | 45 | + return 'modified' |
46 | + | ||
47 | + def prepare(self, obj): | ||
48 | + prepared_data = super(UserIndex, self).prepare(obj) | ||
49 | + | ||
50 | + prepared_data['contribution_count'] = sum(( | ||
51 | + self.prepared_data['message_count'], | ||
52 | + self.prepared_data['changeset_count'], | ||
53 | + self.prepared_data['ticket_count'], | ||
54 | + self.prepared_data['wiki_count'] | ||
55 | + )) | ||
56 | + | ||
57 | + return prepared_data | ||
31 | 58 | ||
32 | def prepare_description(self, obj): | 59 | def prepare_description(self, obj): |
33 | return u'{}\n{}\n{}\n{}'.format( | 60 | return u'{}\n{}\n{}\n{}'.format( |
@@ -40,5 +67,17 @@ class UserIndex(indexes.SearchIndex, indexes.Indexable): | @@ -40,5 +67,17 @@ class UserIndex(indexes.SearchIndex, indexes.Indexable): | ||
40 | def prepare_type(self, obj): | 67 | def prepare_type(self, obj): |
41 | return u'user' | 68 | return u'user' |
42 | 69 | ||
70 | + def prepare_message_count(self, obj): | ||
71 | + return self.badge_counters[obj.username]['messages'] | ||
72 | + | ||
73 | + def prepare_changeset_count(self, obj): | ||
74 | + return self.badge_counters[obj.username]['revisions'] | ||
75 | + | ||
76 | + def prepare_ticket_count(self, obj): | ||
77 | + return self.badge_counters[obj.username]['tickets'] | ||
78 | + | ||
79 | + def prepare_wiki_count(self, obj): | ||
80 | + return self.badge_counters[obj.username]['wikis'] | ||
81 | + | ||
43 | def index_queryset(self, using=None): | 82 | def index_queryset(self, using=None): |
44 | return self.get_model().objects.filter(is_active=True) | 83 | return self.get_model().objects.filter(is_active=True) |
src/accounts/templates/accounts/user_detail.html
1 | {% extends "base.html" %} | 1 | {% extends "base.html" %} |
2 | -{% load i18n gravatar %} | 2 | + |
3 | +{% load i18n gravatar i18n_model %} | ||
4 | + | ||
3 | 5 | ||
4 | {% block head_js %} | 6 | {% block head_js %} |
5 | {% include "pizza-chart.html" with chart_data=type_count chart_div="collabs" chart_height=300 %} | 7 | {% include "pizza-chart.html" with chart_data=type_count chart_div="collabs" chart_height=300 %} |
@@ -36,40 +38,41 @@ | @@ -36,40 +38,41 @@ | ||
36 | 38 | ||
37 | <ul class="unstyled-list"> | 39 | <ul class="unstyled-list"> |
38 | {% if user_.institution or user_.role %} | 40 | {% if user_.institution or user_.role %} |
39 | - <li> | ||
40 | - <span class="icon-briefcase icon-fixed-width"></span> | ||
41 | - {{ user_.role }} | ||
42 | - {% if user_.institution and user_.role %}-{% endif %} | ||
43 | - {{ user_.institution }} | ||
44 | - </li> | ||
45 | - {% endif %} | ||
46 | - {% if request.user.is_active %} | ||
47 | - <li> | ||
48 | - {% if user_.twitter %} | ||
49 | - <span class="icon-twitter icon-fixed-width"></span> <a target="_blank" href="{{ user_.twitter_link }}" title="{% trans 'Twitter account' %}">{{ user_.twitter }}</a> | ||
50 | - {% endif %} | ||
51 | - {% if user_.facebook %} | ||
52 | - <span class="icon-facebook icon-fixed-width"></span> <a target="_blank" href="{{ user_.facebook_link }}" title="{% trans 'Facebook account' %}">{{ user_.facebook }}</a> | ||
53 | - {% endif %} | ||
54 | - </li> | ||
55 | - | ||
56 | - {% if user_.google_talk %} | ||
57 | - <li><span class="icon-google-plus icon-fixed-width"></span> {{ user_.google_talk }}</li> | 41 | + <li> |
42 | + <span class="icon-briefcase icon-fixed-width"></span> | ||
43 | + {{ user_.role }} | ||
44 | + {% if user_.institution and user_.role %}-{% endif %} | ||
45 | + {{ user_.institution }} | ||
46 | + </li> | ||
58 | {% endif %} | 47 | {% endif %} |
59 | - {% if user_.webpage %} | ||
60 | - <li><span class="icon-link icon-fixed-width"></span> <a target="_blank" href="{{ user_.webpage }}" title="{% trans 'Personal webpage' %}">{{ user_.webpage }}</a></li> | 48 | + {% if request.user.is_active %} |
49 | + <li> | ||
50 | + {% if user_.twitter %} | ||
51 | + <span class="icon-twitter icon-fixed-width"></span> <a target="_blank" href="{{ user_.twitter_link }}" title="{% trans 'Twitter account' %}">{{ user_.twitter }}</a> | ||
52 | + {% endif %} | ||
53 | + {% if user_.facebook %} | ||
54 | + <span class="icon-facebook icon-fixed-width"></span> <a target="_blank" href="{{ user_.facebook_link }}" title="{% trans 'Facebook account' %}">{{ user_.facebook }}</a> | ||
55 | + {% endif %} | ||
56 | + </li> | ||
57 | + | ||
58 | + {% if user_.google_talk %} | ||
59 | + <li><span class="icon-google-plus icon-fixed-width"></span> {{ user_.google_talk }}</li> | ||
60 | + {% endif %} | ||
61 | + {% if user_.webpage %} | ||
62 | + <li><span class="icon-link icon-fixed-width"></span> <a target="_blank" href="{{ user_.webpage }}" title="{% trans 'Personal webpage' %}">{{ user_.webpage }}</a></li> | ||
63 | + {% endif %} | ||
61 | {% endif %} | 64 | {% endif %} |
62 | - {% endif %} | ||
63 | </ul> | 65 | </ul> |
64 | 66 | ||
65 | {% if user_.mailinglists %} | 67 | {% if user_.mailinglists %} |
66 | - <b>{% trans 'Subscribes: ' %}</b> | 68 | + <b>{% trans 'Subscribes: ' %}</b> |
67 | {% for list in user_.mailinglists %} | 69 | {% for list in user_.mailinglists %} |
68 | <span class="label label-primary">{{ list }}</span> | 70 | <span class="label label-primary">{{ list }}</span> |
69 | {% endfor %} | 71 | {% endfor %} |
70 | {% endif %} | 72 | {% endif %} |
71 | 73 | ||
72 | <div class="divider"></div> | 74 | <div class="divider"></div> |
75 | + | ||
73 | </div> | 76 | </div> |
74 | 77 | ||
75 | <div class="col-lg-4 col-md-4 col-sm-7"> | 78 | <div class="col-lg-4 col-md-4 col-sm-7"> |
@@ -95,29 +98,50 @@ | @@ -95,29 +98,50 @@ | ||
95 | </div> | 98 | </div> |
96 | </div> | 99 | </div> |
97 | 100 | ||
98 | - </div> | ||
99 | - <div class="row"> | ||
100 | - <div class="col-lg-6 col-md-6 col-sm-12"> | ||
101 | - <h3>{% trans "Latest posted" %} </h3> | ||
102 | - <ul class="message-list"> | ||
103 | - {% for doc in emails %} | ||
104 | - {% include "message-preview.html" with result=doc %} | ||
105 | - {% empty %} | ||
106 | - <li>{% trans "There are no posts by this user so far." %}</li> | ||
107 | - {% endfor %} | ||
108 | - </ul> | ||
109 | - </div> | ||
110 | 101 | ||
111 | - <div class="col-lg-6 col-md-6 col-sm-12"> | ||
112 | - <h3>{% trans "Community inside participations" %}</h3> | ||
113 | - <ul class="message-list"> | ||
114 | - {% for result in results %} | ||
115 | - {% include "message-preview.html" %} | ||
116 | - {% empty %} | ||
117 | - <li>{% trans "No contributions of this user so far." %}</li> | ||
118 | - {% endfor %} | ||
119 | - </ul> | 102 | + {% if user_.badge_set.exists %} |
103 | + <div class="col-lg-8 col-md-12 col-sm-7"> | ||
104 | + <div class="panel panel-default"> | ||
105 | + <div class="panel-heading"> | ||
106 | + <h3 class="panel-title">{% trans "Badges" %}</h3> | ||
107 | + </div> | ||
108 | + <div class="panel-body"> | ||
109 | + <div> | ||
110 | + {% for badge in user_.badge_set.all %} | ||
111 | + {% translate badge as badge_trans %} | ||
112 | + <img src="{{ badge.get_badge_url }}" title="({{ badge_trans.title }}) {{ badge_trans.description }}" /> | ||
113 | + {% endfor %} | ||
114 | + </div> | ||
115 | + </div> | ||
116 | + </div> | ||
120 | </div> | 117 | </div> |
118 | + {% endif %} | ||
119 | + | ||
120 | + </div> <!-- End of user-profile row --> | ||
121 | + | ||
122 | + <div class="row"> | ||
123 | + | ||
124 | + <div class="col-lg-6 col-md-6 col-sm-12"> | ||
125 | + <h3>{% trans "Latest posted" %} </h3> | ||
126 | + <ul class="message-list"> | ||
127 | + {% for doc in emails %} | ||
128 | + {% include "message-preview.html" with result=doc %} | ||
129 | + {% empty %} | ||
130 | + <li>{% trans "There are no posts by this user so far." %}</li> | ||
131 | + {% endfor %} | ||
132 | + </ul> | ||
133 | + </div> | ||
134 | + | ||
135 | + <div class="col-lg-6 col-md-6 col-sm-12"> | ||
136 | + <h3>{% trans "Community inside participations" %}</h3> | ||
137 | + <ul class="message-list"> | ||
138 | + {% for result in results %} | ||
139 | + {% include "message-preview.html" %} | ||
140 | + {% empty %} | ||
141 | + <li>{% trans "No contributions of this user so far." %}</li> | ||
142 | + {% endfor %} | ||
143 | + </ul> | ||
144 | + </div> | ||
121 | 145 | ||
122 | </div> | 146 | </div> |
123 | 147 |
src/badger/admin.py
1 | +# -*- coding: utf-8 -*- | ||
2 | + | ||
1 | from django.contrib import admin | 3 | from django.contrib import admin |
4 | +from django.utils.translation import ugettext_lazy as _ | ||
5 | + | ||
6 | +from .models import Badge, BadgeI18N | ||
7 | + | ||
2 | 8 | ||
3 | -from .models import Badge | 9 | +class BadgeI18NInline(admin.TabularInline): |
10 | + model = BadgeI18N | ||
4 | 11 | ||
5 | 12 | ||
6 | class BadgeAdmin(admin.ModelAdmin): | 13 | class BadgeAdmin(admin.ModelAdmin): |
7 | - pass | 14 | + inlines = [BadgeI18NInline, ] |
15 | + list_display = ['title', 'description', 'order'] | ||
16 | + list_editable = ['order', ] | ||
8 | 17 | ||
9 | 18 | ||
10 | admin.site.register(Badge, BadgeAdmin) | 19 | admin.site.register(Badge, BadgeAdmin) |
@@ -0,0 +1,44 @@ | @@ -0,0 +1,44 @@ | ||
1 | +# -*- coding: utf-8 -*- | ||
2 | + | ||
3 | +from django.core.management.base import BaseCommand, CommandError | ||
4 | +from haystack.query import SearchQuerySet | ||
5 | + | ||
6 | +from accounts.models import User | ||
7 | +from badger.models import Badge | ||
8 | + | ||
9 | + | ||
10 | +class Command(BaseCommand): | ||
11 | + help = "Rebuild the user's badges." | ||
12 | + | ||
13 | + def handle(self, *args, **kwargs): | ||
14 | + for badge in Badge.objects.filter(type='auto'): | ||
15 | + if not badge.comparison: | ||
16 | + continue | ||
17 | + elif badge.comparison == 'biggest': | ||
18 | + order = u'-{}'.format(Badge.USER_ATTR_OPTS[badge.user_attr]) | ||
19 | + sqs = SearchQuerySet().filter(type='user') | ||
20 | + user = sqs.order_by(order)[0] | ||
21 | + badge.awardees.remove(*list(badge.awardees.all())) | ||
22 | + badge.awardees.add(User.objects.get(pk=user.pk)) | ||
23 | + continue | ||
24 | + | ||
25 | + comparison = u'__{}'.format(badge.comparison) if badge.comparison \ | ||
26 | + is not 'equal' else u'' | ||
27 | + | ||
28 | + key = u'{}{}'.format( | ||
29 | + Badge.USER_ATTR_OPTS[badge.user_attr], | ||
30 | + comparison | ||
31 | + ) | ||
32 | + opts = {key: badge.value} | ||
33 | + | ||
34 | + sqs = SearchQuerySet().filter( | ||
35 | + type='user', | ||
36 | + **opts | ||
37 | + ) | ||
38 | + | ||
39 | + # Remove all awardees to make sure that all of then | ||
40 | + # still accomplish the necessary to keep the badge | ||
41 | + badge.awardees.remove(*list(badge.awardees.all())) | ||
42 | + | ||
43 | + for user in sqs: | ||
44 | + badge.awardees.add(User.objects.get(pk=user.pk)) |
src/badger/management/commands/update_badges.py
1 | # -*- coding: utf-8 -*- | 1 | # -*- coding: utf-8 -*- |
2 | 2 | ||
3 | from django.core.management.base import BaseCommand, CommandError | 3 | from django.core.management.base import BaseCommand, CommandError |
4 | +from haystack.query import SearchQuerySet | ||
4 | 5 | ||
5 | from accounts.models import User | 6 | from accounts.models import User |
6 | -from badger.utils import get_counters_to_badge | ||
7 | from badger.models import Badge | 7 | from badger.models import Badge |
8 | 8 | ||
9 | 9 | ||
@@ -14,17 +14,26 @@ class Command(BaseCommand): | @@ -14,17 +14,26 @@ class Command(BaseCommand): | ||
14 | for badge in Badge.objects.filter(type='auto'): | 14 | for badge in Badge.objects.filter(type='auto'): |
15 | if not badge.comparison: | 15 | if not badge.comparison: |
16 | continue | 16 | continue |
17 | - for user in User.objects.all(): | ||
18 | - user_counters = get_counters_to_badge(user) | ||
19 | - | ||
20 | - # TODO remove user if it doesn't sastify the conditions of the | ||
21 | - # badge anymore | ||
22 | - if badge.comparison == 'gte': | ||
23 | - if user_counters[badge.user_attr] >= badge.value: | ||
24 | - badge.awardees.add(user) | ||
25 | - elif badge.comparison == 'lte': | ||
26 | - if user_counters[badge.user_attr] <= badge.value: | ||
27 | - badge.awardees.add(user) | ||
28 | - elif badge.comparison == 'equal': | ||
29 | - if user_counters[badge.user_attr] == badge.value: | ||
30 | - badge.awardees.add(user) | 17 | + elif badge.comparison == 'biggest': |
18 | + order = u'-{}'.format(Badge.USER_ATTR_OPTS[badge.user_attr]) | ||
19 | + sqs = SearchQuerySet().filter(type='user') | ||
20 | + user = sqs.order_by(order)[0] | ||
21 | + badge.awardees.add(User.objects.get(pk=user.pk)) | ||
22 | + continue | ||
23 | + | ||
24 | + comparison = u'__{}'.format(badge.comparison) if badge.comparison \ | ||
25 | + is not 'equal' else u'' | ||
26 | + | ||
27 | + key = u'{}{}'.format( | ||
28 | + Badge.USER_ATTR_OPTS[badge.user_attr], | ||
29 | + comparison | ||
30 | + ) | ||
31 | + opts = {key: badge.value} | ||
32 | + | ||
33 | + sqs = SearchQuerySet().filter( | ||
34 | + type='user', | ||
35 | + **opts | ||
36 | + ) | ||
37 | + | ||
38 | + for user in sqs: | ||
39 | + badge.awardees.add(User.objects.get(pk=user.pk)) |
src/badger/migrations/0002_auto__add_field_badge_title_en__add_field_badge_title_es__add_field_ba.py
0 → 100644
@@ -0,0 +1,120 @@ | @@ -0,0 +1,120 @@ | ||
1 | +# -*- coding: utf-8 -*- | ||
2 | +import datetime | ||
3 | +from south.db import db | ||
4 | +from south.v2 import SchemaMigration | ||
5 | +from django.db import models | ||
6 | + | ||
7 | + | ||
8 | +class Migration(SchemaMigration): | ||
9 | + | ||
10 | + def forwards(self, orm): | ||
11 | + # Adding field 'Badge.title_en' | ||
12 | + db.add_column(u'badger_badge', 'title_en', | ||
13 | + self.gf('django.db.models.fields.CharField')(max_length=200, null=True, blank=True), | ||
14 | + keep_default=False) | ||
15 | + | ||
16 | + # Adding field 'Badge.title_es' | ||
17 | + db.add_column(u'badger_badge', 'title_es', | ||
18 | + self.gf('django.db.models.fields.CharField')(max_length=200, null=True, blank=True), | ||
19 | + keep_default=False) | ||
20 | + | ||
21 | + # Adding field 'Badge.description_en' | ||
22 | + db.add_column(u'badger_badge', 'description_en', | ||
23 | + self.gf('django.db.models.fields.CharField')(max_length=200, null=True, blank=True), | ||
24 | + keep_default=False) | ||
25 | + | ||
26 | + # Adding field 'Badge.description_es' | ||
27 | + db.add_column(u'badger_badge', 'description_es', | ||
28 | + self.gf('django.db.models.fields.CharField')(max_length=200, null=True, blank=True), | ||
29 | + keep_default=False) | ||
30 | + | ||
31 | + | ||
32 | + # Changing field 'Badge.description' | ||
33 | + db.alter_column(u'badger_badge', 'description', self.gf('django.db.models.fields.CharField')(max_length=200, null=True)) | ||
34 | + | ||
35 | + # Changing field 'Badge.title' | ||
36 | + db.alter_column(u'badger_badge', 'title', self.gf('django.db.models.fields.CharField')(max_length=200, null=True)) | ||
37 | + | ||
38 | + def backwards(self, orm): | ||
39 | + # Deleting field 'Badge.title_en' | ||
40 | + db.delete_column(u'badger_badge', 'title_en') | ||
41 | + | ||
42 | + # Deleting field 'Badge.title_es' | ||
43 | + db.delete_column(u'badger_badge', 'title_es') | ||
44 | + | ||
45 | + # Deleting field 'Badge.description_en' | ||
46 | + db.delete_column(u'badger_badge', 'description_en') | ||
47 | + | ||
48 | + # Deleting field 'Badge.description_es' | ||
49 | + db.delete_column(u'badger_badge', 'description_es') | ||
50 | + | ||
51 | + | ||
52 | + # Changing field 'Badge.description' | ||
53 | + db.alter_column(u'badger_badge', 'description', self.gf('django.db.models.fields.CharField')(default='', max_length=200)) | ||
54 | + | ||
55 | + # Changing field 'Badge.title' | ||
56 | + db.alter_column(u'badger_badge', 'title', self.gf('django.db.models.fields.CharField')(default='', max_length=200)) | ||
57 | + | ||
58 | + models = { | ||
59 | + u'accounts.user': { | ||
60 | + 'Meta': {'object_name': 'User'}, | ||
61 | + 'date_joined': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}), | ||
62 | + 'email': ('django.db.models.fields.EmailField', [], {'unique': 'True', 'max_length': '75', 'blank': 'True'}), | ||
63 | + 'facebook': ('django.db.models.fields.CharField', [], {'max_length': '128', 'null': 'True', 'blank': 'True'}), | ||
64 | + 'first_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}), | ||
65 | + 'google_talk': ('django.db.models.fields.EmailField', [], {'max_length': '75', 'null': 'True', 'blank': 'True'}), | ||
66 | + 'groups': ('django.db.models.fields.related.ManyToManyField', [], {'symmetrical': 'False', 'related_name': "u'user_set'", 'blank': 'True', 'to': u"orm['auth.Group']"}), | ||
67 | + u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), | ||
68 | + 'institution': ('django.db.models.fields.CharField', [], {'max_length': '128', 'null': 'True', 'blank': 'True'}), | ||
69 | + 'is_active': ('django.db.models.fields.BooleanField', [], {'default': 'True'}), | ||
70 | + 'is_staff': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), | ||
71 | + 'is_superuser': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), | ||
72 | + 'last_login': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}), | ||
73 | + 'last_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}), | ||
74 | + 'password': ('django.db.models.fields.CharField', [], {'max_length': '128'}), | ||
75 | + 'role': ('django.db.models.fields.CharField', [], {'max_length': '128', 'null': 'True', 'blank': 'True'}), | ||
76 | + 'twitter': ('django.db.models.fields.CharField', [], {'max_length': '128', 'null': 'True', 'blank': 'True'}), | ||
77 | + 'user_permissions': ('django.db.models.fields.related.ManyToManyField', [], {'symmetrical': 'False', 'related_name': "u'user_set'", 'blank': 'True', 'to': u"orm['auth.Permission']"}), | ||
78 | + 'username': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '30'}), | ||
79 | + 'verification_hash': ('django.db.models.fields.CharField', [], {'max_length': '32', 'null': 'True', 'blank': 'True'}), | ||
80 | + 'webpage': ('django.db.models.fields.CharField', [], {'max_length': '256', 'null': 'True', 'blank': 'True'}) | ||
81 | + }, | ||
82 | + u'auth.group': { | ||
83 | + 'Meta': {'object_name': 'Group'}, | ||
84 | + u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), | ||
85 | + 'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '80'}), | ||
86 | + 'permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': u"orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'}) | ||
87 | + }, | ||
88 | + u'auth.permission': { | ||
89 | + 'Meta': {'ordering': "(u'content_type__app_label', u'content_type__model', u'codename')", 'unique_together': "((u'content_type', u'codename'),)", 'object_name': 'Permission'}, | ||
90 | + 'codename': ('django.db.models.fields.CharField', [], {'max_length': '100'}), | ||
91 | + 'content_type': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['contenttypes.ContentType']"}), | ||
92 | + u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), | ||
93 | + 'name': ('django.db.models.fields.CharField', [], {'max_length': '50'}) | ||
94 | + }, | ||
95 | + u'badger.badge': { | ||
96 | + 'Meta': {'object_name': 'Badge'}, | ||
97 | + 'awardees': ('django.db.models.fields.related.ManyToManyField', [], {'symmetrical': 'False', 'to': u"orm['accounts.User']", 'null': 'True', 'blank': 'True'}), | ||
98 | + 'comparison': ('django.db.models.fields.CharField', [], {'max_length': '10', 'null': 'True', 'blank': 'True'}), | ||
99 | + 'description': ('django.db.models.fields.CharField', [], {'max_length': '200', 'null': 'True', 'blank': 'True'}), | ||
100 | + 'description_en': ('django.db.models.fields.CharField', [], {'max_length': '200', 'null': 'True', 'blank': 'True'}), | ||
101 | + 'description_es': ('django.db.models.fields.CharField', [], {'max_length': '200', 'null': 'True', 'blank': 'True'}), | ||
102 | + u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), | ||
103 | + 'image': ('django.db.models.fields.files.ImageField', [], {'max_length': '100'}), | ||
104 | + 'title': ('django.db.models.fields.CharField', [], {'max_length': '200', 'null': 'True', 'blank': 'True'}), | ||
105 | + 'title_en': ('django.db.models.fields.CharField', [], {'max_length': '200', 'null': 'True', 'blank': 'True'}), | ||
106 | + 'title_es': ('django.db.models.fields.CharField', [], {'max_length': '200', 'null': 'True', 'blank': 'True'}), | ||
107 | + 'type': ('django.db.models.fields.CharField', [], {'max_length': '200'}), | ||
108 | + 'user_attr': ('django.db.models.fields.CharField', [], {'max_length': '100', 'null': 'True', 'blank': 'True'}), | ||
109 | + 'value': ('django.db.models.fields.PositiveSmallIntegerField', [], {'null': 'True', 'blank': 'True'}) | ||
110 | + }, | ||
111 | + u'contenttypes.contenttype': { | ||
112 | + 'Meta': {'ordering': "('name',)", 'unique_together': "(('app_label', 'model'),)", 'object_name': 'ContentType', 'db_table': "'django_content_type'"}, | ||
113 | + 'app_label': ('django.db.models.fields.CharField', [], {'max_length': '100'}), | ||
114 | + u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), | ||
115 | + 'model': ('django.db.models.fields.CharField', [], {'max_length': '100'}), | ||
116 | + 'name': ('django.db.models.fields.CharField', [], {'max_length': '100'}) | ||
117 | + } | ||
118 | + } | ||
119 | + | ||
120 | + complete_apps = ['badger'] | ||
0 | \ No newline at end of file | 121 | \ No newline at end of file |
src/badger/migrations/0003_auto__add_badgei18n__add_unique_badgei18n_i18n_source_i18n_language__d.py
0 → 100644
@@ -0,0 +1,131 @@ | @@ -0,0 +1,131 @@ | ||
1 | +# -*- coding: utf-8 -*- | ||
2 | +import datetime | ||
3 | +from south.db import db | ||
4 | +from south.v2 import SchemaMigration | ||
5 | +from django.db import models | ||
6 | + | ||
7 | + | ||
8 | +class Migration(SchemaMigration): | ||
9 | + | ||
10 | + def forwards(self, orm): | ||
11 | + # Adding model 'BadgeI18N' | ||
12 | + db.create_table(u'badger_badgei18n', ( | ||
13 | + (u'id', self.gf('django.db.models.fields.AutoField')(primary_key=True)), | ||
14 | + ('i18n_language', self.gf('django.db.models.fields.CharField')(max_length=10)), | ||
15 | + ('title', self.gf('django.db.models.fields.CharField')(max_length=200, null=True, blank=True)), | ||
16 | + ('description', self.gf('django.db.models.fields.CharField')(max_length=200, null=True, blank=True)), | ||
17 | + ('i18n_source', self.gf('django.db.models.fields.related.ForeignKey')(related_name='translations', to=orm['badger.Badge'])), | ||
18 | + )) | ||
19 | + db.send_create_signal(u'badger', ['BadgeI18N']) | ||
20 | + | ||
21 | + # Adding unique constraint on 'BadgeI18N', fields ['i18n_source', 'i18n_language'] | ||
22 | + db.create_unique(u'badger_badgei18n', ['i18n_source_id', 'i18n_language']) | ||
23 | + | ||
24 | + # Deleting field 'Badge.title_en' | ||
25 | + db.delete_column(u'badger_badge', 'title_en') | ||
26 | + | ||
27 | + # Deleting field 'Badge.description_en' | ||
28 | + db.delete_column(u'badger_badge', 'description_en') | ||
29 | + | ||
30 | + # Deleting field 'Badge.title_es' | ||
31 | + db.delete_column(u'badger_badge', 'title_es') | ||
32 | + | ||
33 | + # Deleting field 'Badge.description_es' | ||
34 | + db.delete_column(u'badger_badge', 'description_es') | ||
35 | + | ||
36 | + | ||
37 | + def backwards(self, orm): | ||
38 | + # Removing unique constraint on 'BadgeI18N', fields ['i18n_source', 'i18n_language'] | ||
39 | + db.delete_unique(u'badger_badgei18n', ['i18n_source_id', 'i18n_language']) | ||
40 | + | ||
41 | + # Deleting model 'BadgeI18N' | ||
42 | + db.delete_table(u'badger_badgei18n') | ||
43 | + | ||
44 | + # Adding field 'Badge.title_en' | ||
45 | + db.add_column(u'badger_badge', 'title_en', | ||
46 | + self.gf('django.db.models.fields.CharField')(max_length=200, null=True, blank=True), | ||
47 | + keep_default=False) | ||
48 | + | ||
49 | + # Adding field 'Badge.description_en' | ||
50 | + db.add_column(u'badger_badge', 'description_en', | ||
51 | + self.gf('django.db.models.fields.CharField')(max_length=200, null=True, blank=True), | ||
52 | + keep_default=False) | ||
53 | + | ||
54 | + # Adding field 'Badge.title_es' | ||
55 | + db.add_column(u'badger_badge', 'title_es', | ||
56 | + self.gf('django.db.models.fields.CharField')(max_length=200, null=True, blank=True), | ||
57 | + keep_default=False) | ||
58 | + | ||
59 | + # Adding field 'Badge.description_es' | ||
60 | + db.add_column(u'badger_badge', 'description_es', | ||
61 | + self.gf('django.db.models.fields.CharField')(max_length=200, null=True, blank=True), | ||
62 | + keep_default=False) | ||
63 | + | ||
64 | + | ||
65 | + models = { | ||
66 | + u'accounts.user': { | ||
67 | + 'Meta': {'object_name': 'User'}, | ||
68 | + 'date_joined': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}), | ||
69 | + 'email': ('django.db.models.fields.EmailField', [], {'unique': 'True', 'max_length': '75', 'blank': 'True'}), | ||
70 | + 'facebook': ('django.db.models.fields.CharField', [], {'max_length': '128', 'null': 'True', 'blank': 'True'}), | ||
71 | + 'first_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}), | ||
72 | + 'google_talk': ('django.db.models.fields.EmailField', [], {'max_length': '75', 'null': 'True', 'blank': 'True'}), | ||
73 | + 'groups': ('django.db.models.fields.related.ManyToManyField', [], {'symmetrical': 'False', 'related_name': "u'user_set'", 'blank': 'True', 'to': u"orm['auth.Group']"}), | ||
74 | + u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), | ||
75 | + 'institution': ('django.db.models.fields.CharField', [], {'max_length': '128', 'null': 'True', 'blank': 'True'}), | ||
76 | + 'is_active': ('django.db.models.fields.BooleanField', [], {'default': 'True'}), | ||
77 | + 'is_staff': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), | ||
78 | + 'is_superuser': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), | ||
79 | + 'last_login': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}), | ||
80 | + 'last_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}), | ||
81 | + 'password': ('django.db.models.fields.CharField', [], {'max_length': '128'}), | ||
82 | + 'role': ('django.db.models.fields.CharField', [], {'max_length': '128', 'null': 'True', 'blank': 'True'}), | ||
83 | + 'twitter': ('django.db.models.fields.CharField', [], {'max_length': '128', 'null': 'True', 'blank': 'True'}), | ||
84 | + 'user_permissions': ('django.db.models.fields.related.ManyToManyField', [], {'symmetrical': 'False', 'related_name': "u'user_set'", 'blank': 'True', 'to': u"orm['auth.Permission']"}), | ||
85 | + 'username': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '30'}), | ||
86 | + 'verification_hash': ('django.db.models.fields.CharField', [], {'max_length': '32', 'null': 'True', 'blank': 'True'}), | ||
87 | + 'webpage': ('django.db.models.fields.CharField', [], {'max_length': '256', 'null': 'True', 'blank': 'True'}) | ||
88 | + }, | ||
89 | + u'auth.group': { | ||
90 | + 'Meta': {'object_name': 'Group'}, | ||
91 | + u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), | ||
92 | + 'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '80'}), | ||
93 | + 'permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': u"orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'}) | ||
94 | + }, | ||
95 | + u'auth.permission': { | ||
96 | + 'Meta': {'ordering': "(u'content_type__app_label', u'content_type__model', u'codename')", 'unique_together': "((u'content_type', u'codename'),)", 'object_name': 'Permission'}, | ||
97 | + 'codename': ('django.db.models.fields.CharField', [], {'max_length': '100'}), | ||
98 | + 'content_type': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['contenttypes.ContentType']"}), | ||
99 | + u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), | ||
100 | + 'name': ('django.db.models.fields.CharField', [], {'max_length': '50'}) | ||
101 | + }, | ||
102 | + u'badger.badge': { | ||
103 | + 'Meta': {'object_name': 'Badge'}, | ||
104 | + 'awardees': ('django.db.models.fields.related.ManyToManyField', [], {'symmetrical': 'False', 'to': u"orm['accounts.User']", 'null': 'True', 'blank': 'True'}), | ||
105 | + 'comparison': ('django.db.models.fields.CharField', [], {'max_length': '10', 'null': 'True', 'blank': 'True'}), | ||
106 | + 'description': ('django.db.models.fields.CharField', [], {'max_length': '200', 'null': 'True', 'blank': 'True'}), | ||
107 | + u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), | ||
108 | + 'image': ('django.db.models.fields.files.ImageField', [], {'max_length': '100'}), | ||
109 | + 'title': ('django.db.models.fields.CharField', [], {'max_length': '200', 'null': 'True', 'blank': 'True'}), | ||
110 | + 'type': ('django.db.models.fields.CharField', [], {'max_length': '200'}), | ||
111 | + 'user_attr': ('django.db.models.fields.CharField', [], {'max_length': '100', 'null': 'True', 'blank': 'True'}), | ||
112 | + 'value': ('django.db.models.fields.PositiveSmallIntegerField', [], {'null': 'True', 'blank': 'True'}) | ||
113 | + }, | ||
114 | + u'badger.badgei18n': { | ||
115 | + 'Meta': {'unique_together': "(('i18n_source', 'i18n_language'),)", 'object_name': 'BadgeI18N'}, | ||
116 | + 'description': ('django.db.models.fields.CharField', [], {'max_length': '200', 'null': 'True', 'blank': 'True'}), | ||
117 | + 'i18n_language': ('django.db.models.fields.CharField', [], {'max_length': '10'}), | ||
118 | + 'i18n_source': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'translations'", 'to': u"orm['badger.Badge']"}), | ||
119 | + u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), | ||
120 | + 'title': ('django.db.models.fields.CharField', [], {'max_length': '200', 'null': 'True', 'blank': 'True'}) | ||
121 | + }, | ||
122 | + u'contenttypes.contenttype': { | ||
123 | + 'Meta': {'ordering': "('name',)", 'unique_together': "(('app_label', 'model'),)", 'object_name': 'ContentType', 'db_table': "'django_content_type'"}, | ||
124 | + 'app_label': ('django.db.models.fields.CharField', [], {'max_length': '100'}), | ||
125 | + u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), | ||
126 | + 'model': ('django.db.models.fields.CharField', [], {'max_length': '100'}), | ||
127 | + 'name': ('django.db.models.fields.CharField', [], {'max_length': '100'}) | ||
128 | + } | ||
129 | + } | ||
130 | + | ||
131 | + complete_apps = ['badger'] | ||
0 | \ No newline at end of file | 132 | \ No newline at end of file |
src/badger/migrations/0004_auto__add_field_badge_order.py
0 → 100644
@@ -0,0 +1,89 @@ | @@ -0,0 +1,89 @@ | ||
1 | +# -*- coding: utf-8 -*- | ||
2 | +import datetime | ||
3 | +from south.db import db | ||
4 | +from south.v2 import SchemaMigration | ||
5 | +from django.db import models | ||
6 | + | ||
7 | + | ||
8 | +class Migration(SchemaMigration): | ||
9 | + | ||
10 | + def forwards(self, orm): | ||
11 | + # Adding field 'Badge.order' | ||
12 | + db.add_column(u'badger_badge', 'order', | ||
13 | + self.gf('django.db.models.fields.PositiveSmallIntegerField')(default=100), | ||
14 | + keep_default=False) | ||
15 | + | ||
16 | + | ||
17 | + def backwards(self, orm): | ||
18 | + # Deleting field 'Badge.order' | ||
19 | + db.delete_column(u'badger_badge', 'order') | ||
20 | + | ||
21 | + | ||
22 | + models = { | ||
23 | + u'accounts.user': { | ||
24 | + 'Meta': {'object_name': 'User'}, | ||
25 | + 'date_joined': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}), | ||
26 | + 'email': ('django.db.models.fields.EmailField', [], {'unique': 'True', 'max_length': '75', 'blank': 'True'}), | ||
27 | + 'facebook': ('django.db.models.fields.CharField', [], {'max_length': '128', 'null': 'True', 'blank': 'True'}), | ||
28 | + 'first_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}), | ||
29 | + 'google_talk': ('django.db.models.fields.EmailField', [], {'max_length': '75', 'null': 'True', 'blank': 'True'}), | ||
30 | + 'groups': ('django.db.models.fields.related.ManyToManyField', [], {'symmetrical': 'False', 'related_name': "u'user_set'", 'blank': 'True', 'to': u"orm['auth.Group']"}), | ||
31 | + u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), | ||
32 | + 'institution': ('django.db.models.fields.CharField', [], {'max_length': '128', 'null': 'True', 'blank': 'True'}), | ||
33 | + 'is_active': ('django.db.models.fields.BooleanField', [], {'default': 'True'}), | ||
34 | + 'is_staff': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), | ||
35 | + 'is_superuser': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), | ||
36 | + 'last_login': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}), | ||
37 | + 'last_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}), | ||
38 | + 'password': ('django.db.models.fields.CharField', [], {'max_length': '128'}), | ||
39 | + 'role': ('django.db.models.fields.CharField', [], {'max_length': '128', 'null': 'True', 'blank': 'True'}), | ||
40 | + 'twitter': ('django.db.models.fields.CharField', [], {'max_length': '128', 'null': 'True', 'blank': 'True'}), | ||
41 | + 'user_permissions': ('django.db.models.fields.related.ManyToManyField', [], {'symmetrical': 'False', 'related_name': "u'user_set'", 'blank': 'True', 'to': u"orm['auth.Permission']"}), | ||
42 | + 'username': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '30'}), | ||
43 | + 'verification_hash': ('django.db.models.fields.CharField', [], {'max_length': '32', 'null': 'True', 'blank': 'True'}), | ||
44 | + 'webpage': ('django.db.models.fields.CharField', [], {'max_length': '256', 'null': 'True', 'blank': 'True'}) | ||
45 | + }, | ||
46 | + u'auth.group': { | ||
47 | + 'Meta': {'object_name': 'Group'}, | ||
48 | + u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), | ||
49 | + 'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '80'}), | ||
50 | + 'permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': u"orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'}) | ||
51 | + }, | ||
52 | + u'auth.permission': { | ||
53 | + 'Meta': {'ordering': "(u'content_type__app_label', u'content_type__model', u'codename')", 'unique_together': "((u'content_type', u'codename'),)", 'object_name': 'Permission'}, | ||
54 | + 'codename': ('django.db.models.fields.CharField', [], {'max_length': '100'}), | ||
55 | + 'content_type': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['contenttypes.ContentType']"}), | ||
56 | + u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), | ||
57 | + 'name': ('django.db.models.fields.CharField', [], {'max_length': '50'}) | ||
58 | + }, | ||
59 | + u'badger.badge': { | ||
60 | + 'Meta': {'ordering': "['order']", 'object_name': 'Badge'}, | ||
61 | + 'awardees': ('django.db.models.fields.related.ManyToManyField', [], {'symmetrical': 'False', 'to': u"orm['accounts.User']", 'null': 'True', 'blank': 'True'}), | ||
62 | + 'comparison': ('django.db.models.fields.CharField', [], {'max_length': '10', 'null': 'True', 'blank': 'True'}), | ||
63 | + 'description': ('django.db.models.fields.CharField', [], {'max_length': '200', 'null': 'True', 'blank': 'True'}), | ||
64 | + u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), | ||
65 | + 'image': ('django.db.models.fields.files.ImageField', [], {'max_length': '100'}), | ||
66 | + 'order': ('django.db.models.fields.PositiveSmallIntegerField', [], {'default': '100'}), | ||
67 | + 'title': ('django.db.models.fields.CharField', [], {'max_length': '200', 'null': 'True', 'blank': 'True'}), | ||
68 | + 'type': ('django.db.models.fields.CharField', [], {'max_length': '200'}), | ||
69 | + 'user_attr': ('django.db.models.fields.CharField', [], {'max_length': '100', 'null': 'True', 'blank': 'True'}), | ||
70 | + 'value': ('django.db.models.fields.PositiveSmallIntegerField', [], {'null': 'True', 'blank': 'True'}) | ||
71 | + }, | ||
72 | + u'badger.badgei18n': { | ||
73 | + 'Meta': {'unique_together': "(('i18n_source', 'i18n_language'),)", 'object_name': 'BadgeI18N'}, | ||
74 | + 'description': ('django.db.models.fields.CharField', [], {'max_length': '200', 'null': 'True', 'blank': 'True'}), | ||
75 | + 'i18n_language': ('django.db.models.fields.CharField', [], {'max_length': '10'}), | ||
76 | + 'i18n_source': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'translations'", 'to': u"orm['badger.Badge']"}), | ||
77 | + u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), | ||
78 | + 'title': ('django.db.models.fields.CharField', [], {'max_length': '200', 'null': 'True', 'blank': 'True'}) | ||
79 | + }, | ||
80 | + u'contenttypes.contenttype': { | ||
81 | + 'Meta': {'ordering': "('name',)", 'unique_together': "(('app_label', 'model'),)", 'object_name': 'ContentType', 'db_table': "'django_content_type'"}, | ||
82 | + 'app_label': ('django.db.models.fields.CharField', [], {'max_length': '100'}), | ||
83 | + u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), | ||
84 | + 'model': ('django.db.models.fields.CharField', [], {'max_length': '100'}), | ||
85 | + 'name': ('django.db.models.fields.CharField', [], {'max_length': '100'}) | ||
86 | + } | ||
87 | + } | ||
88 | + | ||
89 | + complete_apps = ['badger'] | ||
0 | \ No newline at end of file | 90 | \ No newline at end of file |
src/badger/models.py
1 | # -*- coding: utf-8 -*- | 1 | # -*- coding: utf-8 -*- |
2 | 2 | ||
3 | +from django.conf import settings | ||
3 | from django.contrib.auth import get_user_model | 4 | from django.contrib.auth import get_user_model |
4 | from django.db import models | 5 | from django.db import models |
5 | -from django.utils.translation import ugettext as _ | 6 | +from django.utils.translation import ugettext_lazy as _ |
7 | +from PIL import Image | ||
8 | +from i18n_model.models import I18nModel | ||
6 | 9 | ||
7 | 10 | ||
8 | class Badge(models.Model): | 11 | class Badge(models.Model): |
@@ -10,6 +13,7 @@ class Badge(models.Model): | @@ -10,6 +13,7 @@ class Badge(models.Model): | ||
10 | (u'gte', _(u'Greater than or equal')), | 13 | (u'gte', _(u'Greater than or equal')), |
11 | (u'lte', _(u'less than or equal')), | 14 | (u'lte', _(u'less than or equal')), |
12 | (u'equal', _(u'Equal')), | 15 | (u'equal', _(u'Equal')), |
16 | + (u'biggest', _(u'Biggest')), | ||
13 | ) | 17 | ) |
14 | TYPE_CHOICES = ( | 18 | TYPE_CHOICES = ( |
15 | (u'auto', _(u'Automatically')), | 19 | (u'auto', _(u'Automatically')), |
@@ -22,8 +26,18 @@ class Badge(models.Model): | @@ -22,8 +26,18 @@ class Badge(models.Model): | ||
22 | (u'revisions', _(u'Revisions')), | 26 | (u'revisions', _(u'Revisions')), |
23 | (u'tickets', _(u'Ticket')), | 27 | (u'tickets', _(u'Ticket')), |
24 | ) | 28 | ) |
25 | - title = models.CharField(_(u'Title'), max_length=200) | ||
26 | - description = models.CharField(_(u'Description'), max_length=200) | 29 | + USER_ATTR_OPTS = { |
30 | + u'messages': u'message_count', | ||
31 | + u'revisions': u'changeset_count', | ||
32 | + u'tickets': u'ticket_count', | ||
33 | + u'wikis': u'wiki_count', | ||
34 | + u'contributions': u'contribution_count', | ||
35 | + } | ||
36 | + | ||
37 | + title = models.CharField(_(u'Title'), max_length=200, blank=True, | ||
38 | + null=True) | ||
39 | + description = models.CharField(_(u'Description'), max_length=200, | ||
40 | + blank=True, null=True) | ||
27 | image = models.ImageField(upload_to='badges') | 41 | image = models.ImageField(upload_to='badges') |
28 | type = models.CharField(_(u'Type'), max_length=200, choices=TYPE_CHOICES) | 42 | type = models.CharField(_(u'Type'), max_length=200, choices=TYPE_CHOICES) |
29 | user_attr = models.CharField( | 43 | user_attr = models.CharField( |
@@ -50,10 +64,22 @@ class Badge(models.Model): | @@ -50,10 +64,22 @@ class Badge(models.Model): | ||
50 | blank=True, | 64 | blank=True, |
51 | null=True | 65 | null=True |
52 | ) | 66 | ) |
67 | + order = models.PositiveSmallIntegerField(_(u'Order'), default=100) | ||
53 | 68 | ||
54 | class Meta: | 69 | class Meta: |
55 | verbose_name = _(u'Badge') | 70 | verbose_name = _(u'Badge') |
56 | verbose_name_plural = _(u'Badges') | 71 | verbose_name_plural = _(u'Badges') |
72 | + ordering = ['order', ] | ||
73 | + | ||
74 | + def get_badge_url(self): | ||
75 | + return u'{}{}'.format(settings.MEDIA_URL, self.image) | ||
76 | + | ||
77 | + def save(self, *args, **kwargs): | ||
78 | + img = Image.open(self.image) | ||
79 | + (width, height) = img.size | ||
80 | + img = img.resize((50, 50), Image.ANTIALIAS) | ||
81 | + super(Badge, self).save(*args, **kwargs) | ||
82 | + img.save(self.image.path) | ||
57 | 83 | ||
58 | def __unicode__(self): | 84 | def __unicode__(self): |
59 | return u'{} ({}, {})'.format( | 85 | return u'{} ({}, {})'.format( |
@@ -61,3 +87,9 @@ class Badge(models.Model): | @@ -61,3 +87,9 @@ class Badge(models.Model): | ||
61 | self.get_user_attr_display(), | 87 | self.get_user_attr_display(), |
62 | self.get_type_display(), | 88 | self.get_type_display(), |
63 | ) | 89 | ) |
90 | + | ||
91 | + | ||
92 | +class BadgeI18N(I18nModel): | ||
93 | + class Meta: | ||
94 | + source_model = Badge | ||
95 | + translation_fields = ('title', 'description') |
src/badger/utils.py
@@ -2,32 +2,45 @@ | @@ -2,32 +2,45 @@ | ||
2 | 2 | ||
3 | from django.db.models import Count | 3 | from django.db.models import Count |
4 | 4 | ||
5 | -from haystack.query import SearchQuerySet | ||
6 | - | ||
7 | from proxy.models import Revision, Ticket, Wiki | 5 | from proxy.models import Revision, Ticket, Wiki |
8 | -from super_archives.models import Message | ||
9 | - | ||
10 | - | ||
11 | -def get_counters_to_badge(user): | ||
12 | - # count_revisions = Revision.objects.filter(author=user.username).count() | ||
13 | - # count_tickets = Ticket.objects.filter(author=user.username).count() | ||
14 | - # count_wikis = Wiki.objects.filter(author=user.username).count() | ||
15 | - count_revisions = SearchQuerySet().filter( | ||
16 | - type='changeset', | ||
17 | - author=user.username | ||
18 | - ).count() | ||
19 | - count_tickets = SearchQuerySet().filter( | ||
20 | - type='ticket', | ||
21 | - author=user.username | ||
22 | - ).count() | ||
23 | - count_wikis = SearchQuerySet().filter( | ||
24 | - type='wiki', | ||
25 | - author=user.username | ||
26 | - ).count() | ||
27 | - return dict( | ||
28 | - messages=user.emails.aggregate(Count('message'))['message__count'], | ||
29 | - revisions=count_revisions, | ||
30 | - tickets=count_tickets, | ||
31 | - wikis=count_wikis, | ||
32 | - contributions=count_revisions + count_tickets + count_wikis, | ||
33 | - ) | 6 | +from accounts.models import User |
7 | + | ||
8 | + | ||
9 | +def get_wiki_counters(): | ||
10 | + return { | ||
11 | + author: count for author, count in Wiki.objects.values_list( | ||
12 | + 'author' | ||
13 | + ).annotate(count=Count('author')) | ||
14 | + } | ||
15 | + | ||
16 | + | ||
17 | +def get_revision_counters(): | ||
18 | + return { | ||
19 | + author: count for author, count in Revision.objects.values_list( | ||
20 | + 'author' | ||
21 | + ).annotate(count=Count('author')) | ||
22 | + } | ||
23 | + | ||
24 | + | ||
25 | +def get_ticket_counters(): | ||
26 | + return { | ||
27 | + author: count for author, count in Ticket.objects.values_list( | ||
28 | + 'author' | ||
29 | + ).annotate(count=Count('author')) | ||
30 | + } | ||
31 | + | ||
32 | + | ||
33 | +def get_users_counters(): | ||
34 | + wiki_counters = get_wiki_counters() | ||
35 | + revision_counters = get_revision_counters() | ||
36 | + ticket_counters = get_ticket_counters() | ||
37 | + | ||
38 | + users_counters = {} | ||
39 | + for user in User.objects.annotate(message_count=Count('emails__message')): | ||
40 | + users_counters[user.username] = { | ||
41 | + 'messages': user.message_count, | ||
42 | + 'wikis': wiki_counters.get(user.username, 0), | ||
43 | + 'revisions': revision_counters.get(user.username, 0), | ||
44 | + 'tickets': ticket_counters.get(user.username, 0), | ||
45 | + } | ||
46 | + return users_counters |
src/colab/custom_settings.py
@@ -9,8 +9,8 @@ TIME_ZONE = 'America/Sao_Paulo' | @@ -9,8 +9,8 @@ TIME_ZONE = 'America/Sao_Paulo' | ||
9 | gettext = lambda s: s | 9 | gettext = lambda s: s |
10 | LANGUAGES = ( | 10 | LANGUAGES = ( |
11 | ('en', gettext('English')), | 11 | ('en', gettext('English')), |
12 | - ('es', gettext('Spanish')), | ||
13 | ('pt-br', gettext('Portuguese')), | 12 | ('pt-br', gettext('Portuguese')), |
13 | + ('es', gettext('Spanish')), | ||
14 | ) | 14 | ) |
15 | 15 | ||
16 | DJANGO_DATE_FORMAT_TO_JS = { | 16 | DJANGO_DATE_FORMAT_TO_JS = { |
@@ -18,7 +18,7 @@ DJANGO_DATE_FORMAT_TO_JS = { | @@ -18,7 +18,7 @@ DJANGO_DATE_FORMAT_TO_JS = { | ||
18 | 'es': ('es', 'dd/MM/yyyy'), | 18 | 'es': ('es', 'dd/MM/yyyy'), |
19 | } | 19 | } |
20 | 20 | ||
21 | -LANGUAGE_CODE = 'pt-br' | 21 | +LANGUAGE_CODE = 'en' |
22 | 22 | ||
23 | # The absolute path to the folder containing the attachments | 23 | # The absolute path to the folder containing the attachments |
24 | ATTACHMENTS_FOLDER_PATH = '/home/colab/trac/attachments/' | 24 | ATTACHMENTS_FOLDER_PATH = '/home/colab/trac/attachments/' |
@@ -108,7 +108,7 @@ INSTALLED_APPS = INSTALLED_APPS + ( | @@ -108,7 +108,7 @@ INSTALLED_APPS = INSTALLED_APPS + ( | ||
108 | 'conversejs', | 108 | 'conversejs', |
109 | 'haystack', | 109 | 'haystack', |
110 | 'hitcounter', | 110 | 'hitcounter', |
111 | - 'badger', | 111 | + 'i18n_model', |
112 | 112 | ||
113 | # Own apps | 113 | # Own apps |
114 | 'super_archives', | 114 | 'super_archives', |
@@ -118,6 +118,7 @@ INSTALLED_APPS = INSTALLED_APPS + ( | @@ -118,6 +118,7 @@ INSTALLED_APPS = INSTALLED_APPS + ( | ||
118 | 'accounts', | 118 | 'accounts', |
119 | 'proxy', | 119 | 'proxy', |
120 | 'search', | 120 | 'search', |
121 | + 'badger', | ||
121 | 122 | ||
122 | # Feedzilla and deps | 123 | # Feedzilla and deps |
123 | 'feedzilla', | 124 | 'feedzilla', |
@@ -231,6 +232,7 @@ STATICFILES_DIRS = ( | @@ -231,6 +232,7 @@ STATICFILES_DIRS = ( | ||
231 | ) | 232 | ) |
232 | 233 | ||
233 | STATIC_ROOT = os.path.join(BASE_DIR, '..', 'www', 'static') | 234 | STATIC_ROOT = os.path.join(BASE_DIR, '..', 'www', 'static') |
235 | +MEDIA_ROOT = os.path.join(BASE_DIR, '..', 'www', 'static', 'media') | ||
234 | 236 | ||
235 | TEMPLATE_DIRS = ( | 237 | TEMPLATE_DIRS = ( |
236 | os.path.join(BASE_DIR, 'templates'), | 238 | os.path.join(BASE_DIR, 'templates'), |
src/colab/settings.py
@@ -80,5 +80,6 @@ USE_TZ = True | @@ -80,5 +80,6 @@ USE_TZ = True | ||
80 | # https://docs.djangoproject.com/en/dev/howto/static-files/ | 80 | # https://docs.djangoproject.com/en/dev/howto/static-files/ |
81 | 81 | ||
82 | STATIC_URL = '/static/' | 82 | STATIC_URL = '/static/' |
83 | +MEDIA_URL = '/media/' | ||
83 | 84 | ||
84 | from custom_settings import * | 85 | from custom_settings import * |
src/colab/urls.py
1 | -from django.conf.urls import patterns, include, url | 1 | +from django.conf.urls import patterns, include, url, static |
2 | from django.conf import settings | 2 | from django.conf import settings |
3 | from django.views.generic import TemplateView | 3 | from django.views.generic import TemplateView |
4 | from django.contrib import admin | 4 | from django.contrib import admin |
@@ -31,3 +31,9 @@ urlpatterns = patterns('', | @@ -31,3 +31,9 @@ urlpatterns = patterns('', | ||
31 | 31 | ||
32 | url(r'^', include('proxy.urls')), | 32 | url(r'^', include('proxy.urls')), |
33 | ) | 33 | ) |
34 | + | ||
35 | +if settings.DEBUG: | ||
36 | + urlpatterns += static.static( | ||
37 | + settings.MEDIA_URL, | ||
38 | + document_root=settings.MEDIA_ROOT | ||
39 | + ) |