]> git.openstreetmap.org Git - osqa.git/blob - osqa/forum_modules/default_badges/badges.py
95e886d2c60756408ede4e7a9db4b45481861917
[osqa.git] / osqa / forum_modules / default_badges / badges.py
1 from datetime import timedelta
2
3 from django.db.models.signals import post_save
4 from django.utils.translation import ugettext as _
5
6 from forum.badges.base import PostCountableAbstractBadge, ActivityAbstractBadge, FirstActivityAbstractBadge, \
7         ActivityCountAbstractBadge, CountableAbstractBadge, AbstractBadge
8 from forum.models import Question, Answer, Activity, Tag
9 from forum.models.user import activity_record
10 from forum import const
11
12 import settings
13
14 class PopularQuestionBadge(PostCountableAbstractBadge):
15     type = const.BRONZE_BADGE
16     description = _('Asked a question with %s views') % str(settings.POPULAR_QUESTION_VIEWS)
17
18     def __init__(self):
19         super(PopularQuestionBadge, self).__init__(Question, 'view_count', settings.POPULAR_QUESTION_VIEWS)
20
21 class NotableQuestionBadge(PostCountableAbstractBadge):
22     type = const.SILVER_BADGE
23     description = _('Asked a question with %s views') % str(settings.NOTABLE_QUESTION_VIEWS)
24
25     def __init__(self):
26         super(NotableQuestionBadge, self).__init__(Question, 'view_count', settings.NOTABLE_QUESTION_VIEWS)
27
28 class FamousQuestionBadge(PostCountableAbstractBadge):
29     type = const.GOLD_BADGE
30     description = _('Asked a question with %s views') % str(settings.FAMOUS_QUESTION_VIEWS)
31
32     def __init__(self):
33         super(FamousQuestionBadge, self).__init__(Question, 'view_count', settings.FAMOUS_QUESTION_VIEWS)
34
35
36 class NiceAnswerBadge(PostCountableAbstractBadge):
37     type = const.BRONZE_BADGE
38     description = _('Answer voted up %s times') % str(settings.NICE_ANSWER_VOTES_UP)
39
40     def __init__(self):
41         super(NiceAnswerBadge, self).__init__(Answer, 'vote_up_count', settings.NICE_ANSWER_VOTES_UP)
42
43 class NiceQuestionBadge(PostCountableAbstractBadge):
44     type = const.BRONZE_BADGE
45     description = _('Question voted up %s times') % str(settings.NICE_QUESTION_VOTES_UP)
46
47     def __init__(self):
48         super(NiceQuestionBadge, self).__init__(Question, 'vote_up_count', settings.NICE_QUESTION_VOTES_UP)
49
50 class GoodAnswerBadge(PostCountableAbstractBadge):
51     type = const.SILVER_BADGE
52     description = _('Answer voted up %s times') % str(settings.GOOD_ANSWER_VOTES_UP)
53
54     def __init__(self):
55         super(GoodAnswerBadge, self).__init__(Answer, 'vote_up_count', settings.GOOD_ANSWER_VOTES_UP)
56
57 class GoodQuestionBadge(PostCountableAbstractBadge):
58     type = const.SILVER_BADGE
59     description = _('Question voted up %s times') % str(settings.GOOD_QUESTION_VOTES_UP)
60
61     def __init__(self):
62         super(GoodQuestionBadge, self).__init__(Question, 'vote_up_count', settings.GOOD_QUESTION_VOTES_UP)
63
64 class GreatAnswerBadge(PostCountableAbstractBadge):
65     type = const.GOLD_BADGE
66     description = _('Answer voted up %s times') % str(settings.GREAT_ANSWER_VOTES_UP)
67
68     def __init__(self):
69         super(GreatAnswerBadge, self).__init__(Answer, 'vote_up_count', settings.GREAT_ANSWER_VOTES_UP)
70
71 class GreatQuestionBadge(PostCountableAbstractBadge):
72     type = const.GOLD_BADGE
73     description = _('Question voted up %s times') % str(settings.GREAT_QUESTION_VOTES_UP)
74
75     def __init__(self):
76         super(GreatQuestionBadge, self).__init__(Question, 'vote_up_count', settings.GREAT_QUESTION_VOTES_UP)
77
78
79 class FavoriteQuestionBadge(PostCountableAbstractBadge):
80     type = const.SILVER_BADGE
81     description = _('Question favorited by %s users') % str(settings.FAVORITE_QUESTION_FAVS)
82
83     def __init__(self):
84         super(FavoriteQuestionBadge, self).__init__(Question, 'favourite_count', settings.FAVORITE_QUESTION_FAVS)
85
86 class StellarQuestionBadge(PostCountableAbstractBadge):
87     type = const.GOLD_BADGE
88     description = _('Question favorited by %s users') % str(settings.STELLAR_QUESTION_FAVS)
89
90     def __init__(self):
91         super(StellarQuestionBadge, self).__init__(Question, 'favourite_count', settings.STELLAR_QUESTION_FAVS)
92
93
94 class DisciplinedBadge(ActivityAbstractBadge):
95     type = const.BRONZE_BADGE
96     description = _('Deleted own post with score of %s or higher') % str(settings.DISCIPLINED_MIN_SCORE)
97
98     def __init__(self):
99         def handler(instance):
100             if instance.user.id == instance.content_object.author.id and instance.content_object.score >= settings.DISCIPLINED_MIN_SCORE:
101                 self.award_badge(instance.user, instance)
102
103         super(DisciplinedBadge, self).__init__(const.TYPE_ACTIVITY_DELETE_QUESTION, handler)
104
105 class PeerPressureBadge(ActivityAbstractBadge):
106     type = const.BRONZE_BADGE
107     description = _('Deleted own post with score of %s or lower') % str(settings.PEER_PRESSURE_MAX_SCORE)
108
109     def __init__(self):
110         def handler(instance):
111             if instance.user.id == instance.content_object.author.id and instance.content_object.score <= settings.PEER_PRESSURE_MAX_SCORE:
112                 self.award_badge(instance.user, instance)
113
114         super(PeerPressureBadge, self).__init__(const.TYPE_ACTIVITY_DELETE_QUESTION, handler)
115
116
117 class CitizenPatrolBadge(FirstActivityAbstractBadge):
118     type = const.BRONZE_BADGE
119     description = _('First flagged post')
120
121     def __init__(self):
122         super(CitizenPatrolBadge, self).__init__(const.TYPE_ACTIVITY_MARK_OFFENSIVE)
123
124 class CriticBadge(FirstActivityAbstractBadge):
125     type = const.BRONZE_BADGE
126     description = _('First down vote')
127
128     def __init__(self):
129         super(CriticBadge, self).__init__(const.TYPE_ACTIVITY_VOTE_DOWN)
130
131 class OrganizerBadge(FirstActivityAbstractBadge):
132     type = const.BRONZE_BADGE
133     description = _('First retag')
134
135     def __init__(self):
136         super(OrganizerBadge, self).__init__(const.TYPE_ACTIVITY_UPDATE_TAGS)
137
138 class SupporterBadge(FirstActivityAbstractBadge):
139     type = const.BRONZE_BADGE
140     description = _('First up vote')
141
142     def __init__(self):
143         super(SupporterBadge, self).__init__(const.TYPE_ACTIVITY_VOTE_UP)
144
145 class EditorBadge(FirstActivityAbstractBadge):
146     type = const.BRONZE_BADGE
147     description = _('First edit')
148
149     def __init__(self):
150         super(EditorBadge, self).__init__((const.TYPE_ACTIVITY_UPDATE_ANSWER, const.TYPE_ACTIVITY_UPDATE_QUESTION))
151
152 class ScholarBadge(FirstActivityAbstractBadge):
153     type = const.BRONZE_BADGE
154     description = _('First accepted answer on your own question')
155
156     def __init__(self):
157         super(ScholarBadge, self).__init__(const.TYPE_ACTIVITY_MARK_ANSWER)
158
159 class AutobiographerBadge(FirstActivityAbstractBadge):
160     type = const.BRONZE_BADGE
161     description = _('Completed all user profile fields')
162
163     def __init__(self):
164         super(AutobiographerBadge, self).__init__(const.TYPE_ACTIVITY_USER_FULL_UPDATED)
165
166 class CleanupBadge(FirstActivityAbstractBadge):
167     type = const.BRONZE_BADGE
168     description = _('First rollback')
169
170     def __init__(self):
171         super(CleanupBadge, self).__init__((const.TYPE_ACTIVITY_CANCEL_VOTE_UP, const.TYPE_ACTIVITY_CANCEL_VOTE_DOWN))
172
173
174 class CivicDutyBadge(ActivityCountAbstractBadge):
175     type = const.SILVER_BADGE
176     description = _('Voted %s times') % str(settings.CIVIC_DUTY_VOTES)
177
178     def __init__(self):
179         super(CivicDutyBadge, self).__init__((const.TYPE_ACTIVITY_VOTE_DOWN, const.TYPE_ACTIVITY_VOTE_UP), settings.CIVIC_DUTY_VOTES)
180
181 class PunditBadge(ActivityCountAbstractBadge):
182     type = const.BRONZE_BADGE
183     description = _('Left %s comments') % str(settings.PUNDIT_COMMENT_COUNT)
184
185     def __init__(self):
186         super(PunditBadge, self).__init__((const.TYPE_ACTIVITY_COMMENT_ANSWER, const.TYPE_ACTIVITY_COMMENT_QUESTION), settings.PUNDIT_COMMENT_COUNT)
187
188
189 class SelfLearnerBadge(CountableAbstractBadge):
190     type = const.BRONZE_BADGE
191     description = _('Answered your own question with at least %s up votes') % str(settings.SELF_LEARNER_UP_VOTES)
192
193     def __init__(self):
194
195         def handler(instance):
196             if instance.author_id == instance.question.author_id:
197                 self.award_badge(instance.author, instance)
198
199         super(SelfLearnerBadge, self).__init__(Answer, 'vote_up_count', settings.SELF_LEARNER_UP_VOTES, handler)
200
201
202 class StrunkAndWhiteBadge(ActivityCountAbstractBadge):
203     type = const.SILVER_BADGE
204     name = _('Strunk & White')
205     description = _('Edited %s entries') % str(settings.STRUNK_AND_WHITE_EDITS)
206
207     def __init__(self):
208         super(StrunkAndWhiteBadge, self).__init__((const.TYPE_ACTIVITY_UPDATE_ANSWER, const.TYPE_ACTIVITY_UPDATE_QUESTION), settings.STRUNK_AND_WHITE_EDITS)
209
210
211 def is_user_first(post):
212     return post.__class__.objects.filter(author=post.author).order_by('added_at')[0].id == post.id
213
214 class StudentBadge(CountableAbstractBadge):
215     type = const.BRONZE_BADGE
216     description = _('Asked first question with at least one up vote')
217
218     def __init__(self):
219         def handler(instance):
220             if is_user_first(instance):
221                 self.award_badge(instance.author, instance)
222
223         super(StudentBadge, self).__init__(Question, 'vote_up_count', 1, handler)
224
225 class TeacherBadge(CountableAbstractBadge):
226     type = const.BRONZE_BADGE
227     description = _('Answered first question with at least one up vote')
228
229     def __init__(self):
230         def handler(instance):
231             if is_user_first(instance):
232                 self.award_badge(instance.author, instance)
233
234         super(TeacherBadge, self).__init__(Answer, 'vote_up_count', 1, handler)
235
236
237 class AcceptedAndVotedAnswerAbstractBadge(AbstractBadge):
238     def __init__(self, up_votes, handler):
239         def wrapper(sender, instance, **kwargs):
240             if sender is Answer:
241                 answer = instance
242                 if not "vote_up_count" in answer.get_dirty_fields():
243                     return
244             else:
245                 answer = instance.content_object
246
247             accepted = answer.accepted
248             vote_count = answer.vote_up_count
249
250             if accepted and vote_count == up_votes:
251                 handler(answer)
252
253         activity_record.connect(wrapper, sender=const.TYPE_ACTIVITY_MARK_ANSWER, weak=False)
254         post_save.connect(wrapper, sender=Answer, weak=False)
255
256
257 class EnlightenedBadge(AcceptedAndVotedAnswerAbstractBadge):
258     type = const.SILVER_BADGE
259     description = _('First answer was accepted with at least %s up votes') % str(settings.ENLIGHTENED_UP_VOTES)
260
261     def __init__(self):
262         def handler(answer):
263             self.award_badge(answer.author, answer, True)
264
265         super(EnlightenedBadge, self).__init__(settings.ENLIGHTENED_UP_VOTES, handler)
266
267
268 class GuruBadge(AcceptedAndVotedAnswerAbstractBadge):
269     type = const.SILVER_BADGE
270     description = _('Accepted answer and voted up %s times') % str(settings.GURU_UP_VOTES)
271
272     def __init__(self):
273         def handler(answer):
274             self.award_badge(answer.author, answer)
275
276         super(GuruBadge, self).__init__(settings.GURU_UP_VOTES, handler)
277
278
279 class NecromancerBadge(CountableAbstractBadge):
280     type = const.SILVER_BADGE
281     description = _('Answered a question more than %(dif_days)s days later with at least %(up_votes)s votes') % \
282             {'dif_days': str(settings.NECROMANCER_DIF_DAYS), 'up_votes': str(settings.NECROMANCER_UP_VOTES)}
283
284     def __init__(self):
285         def handler(instance):
286             if instance.added_at >= (instance.question.added_at + timedelta(days=int(settings.NECROMANCER_DIF_DAYS))):
287                 self.award_badge(instance.author, instance)
288
289         super(NecromancerBadge, self).__init__(Answer, "vote_up_count", settings.NECROMANCER_UP_VOTES, handler)
290
291
292 class TaxonomistBadge(AbstractBadge):
293     type = const.SILVER_BADGE
294     description = _('Created a tag used by %s questions') % str(settings.TAXONOMIST_USE_COUNT)
295
296     def __init__(self):
297         def handler(instance, **kwargs):
298             if instance.used_count == settings.TAXONOMIST_USE_COUNT:
299                 self.award_badge(instance.created_by, instance)           
300
301         post_save.connect(handler, sender=Tag, weak=False)
302
303
304 #class GeneralistTag(AbstractBadge):
305 #    pass
306
307 #class ExpertTag(AbstractBadge):
308 #    pass
309
310 #class YearlingTag(AbstractBadge):
311 #    pass
312
313
314