]> git.openstreetmap.org Git - osqa.git/blob - forum/views/admin.py
ddb4852b060c16dbaa53037fc327fafafce2110a
[osqa.git] / forum / views / admin.py
1 from datetime import datetime, timedelta
2 import time
3
4 from django.shortcuts import render_to_response, get_object_or_404
5 from django.core.urlresolvers import reverse
6 from django.http import HttpResponseRedirect, HttpResponse, HttpResponseForbidden, Http404
7 from django.template import RequestContext
8 from django.utils.translation import ugettext as _
9 from django.utils import simplejson
10 from django.db.models import Sum
11 from forum.settings.base import Setting
12 from forum.forms import MaintenanceModeForm, PageForm
13 from forum.settings.forms import SettingsSetForm
14
15 from forum.models import Question, Answer, User, Node, Action, Page
16 from forum.actions import NewPageAction, EditPageAction, PublishAction
17 from forum import settings
18
19 def super_user_required(fn):
20     def wrapper(request, *args, **kwargs):
21         if request.user.is_authenticated() and request.user.is_superuser:
22             return fn(request, *args, **kwargs)
23         else:
24             return HttpResponseForbidden()
25
26     return wrapper
27
28 def admin_page(fn):
29     @super_user_required
30     def wrapper(request, *args, **kwargs):
31         res = fn(request, *args, **kwargs)
32         if isinstance(res, tuple):
33             template, context = res
34             context['basetemplate'] = settings.DJSTYLE_ADMIN_INTERFACE and "osqaadmin/djstyle_base.html" or "osqaadmin/base.html"
35             context['allsets'] = Setting.sets
36             context['othersets'] = sorted(
37                     [s for s in Setting.sets.values() if not s.name in
38                     ('basic', 'users', 'email', 'paths', 'extkeys', 'repgain', 'minrep', 'voting', 'badges', 'about', 'faq', 'sidebar',
39                     'form', 'moderation', 'css', 'headandfoot')]
40                     , lambda s1, s2: s1.weight - s2.weight)
41
42             unsaved = request.session.get('previewing_settings', {})
43             context['unsaved'] = set([getattr(settings, s).set.name for s in unsaved.keys() if hasattr(settings, s)])
44
45
46             return render_to_response(template, context, context_instance=RequestContext(request))
47         else:
48             return res
49
50     return wrapper
51
52 @admin_page
53 def dashboard(request):
54     return ('osqaadmin/dashboard.html', {
55         'settings_pack': unicode(settings.SETTINGS_PACK),
56         'statistics': get_statistics(),
57         'recent_activity': get_recent_activity(),
58         'flagged_posts': get_flagged_posts(),
59     })
60
61 @super_user_required
62 def interface_switch(request):
63     if request.GET and request.GET.get('to', None) and request.GET['to'] in ('default', 'djstyle'):
64         settings.DJSTYLE_ADMIN_INTERFACE.set_value(request.GET['to'] == 'djstyle')
65
66     return HttpResponseRedirect(reverse('admin_index'))
67
68 @admin_page
69 def statistics(request):
70     today = datetime.now()
71     last_month = today - timedelta(days=30)
72
73     last_month_questions = Question.objects.filter_state(deleted=False).filter(added_at__gt=last_month
74                                                   ).order_by('added_at').values_list('added_at', flat=True)
75
76     last_month_n_questions = Question.objects.filter_state(deleted=False).filter(added_at__lt=last_month).count()
77     qgraph_data = simplejson.dumps([
78             (time.mktime(d.timetuple()) * 1000, i + last_month_n_questions)
79             for i, d in enumerate(last_month_questions)
80     ])
81
82     last_month_users = User.objects.filter(date_joined__gt=last_month
83                                                   ).order_by('date_joined').values_list('date_joined', flat=True)
84
85     last_month_n_users = User.objects.filter(date_joined__lt=last_month).count()
86
87     ugraph_data = simplejson.dumps([
88             (time.mktime(d.timetuple()) * 1000, i + last_month_n_users)
89             for i, d in enumerate(last_month_users)
90     ])
91
92     return 'osqaadmin/statistics.html', {
93         'graphs': [
94             {
95                 'id': 'questions_graph',
96                 'caption': _("Questions Graph"),
97                 'data': qgraph_data
98             },{
99                 'id': 'userss_graph',
100                 'caption': _("Users Graph"),
101                 'data': ugraph_data
102             }
103         ]
104     }
105
106
107 @admin_page
108 def settings_set(request, set_name):
109     set = Setting.sets.get(set_name, {})
110     current_preview = request.session.get('previewing_settings', {})
111
112     if set is None:
113         raise Http404
114
115     if request.POST:
116         form = SettingsSetForm(set, data=request.POST, files=request.FILES)
117
118         if form.is_valid():
119             if 'preview' in request.POST:
120                 current_preview.update(form.cleaned_data)
121                 request.session['previewing_settings'] = current_preview
122
123                 return HttpResponseRedirect(reverse('index'))
124             else:
125                 for s in set:
126                     current_preview.pop(s.name, None)
127
128                 request.session['previewing_settings'] = current_preview
129
130                 if not 'reset' in request.POST:
131                     form.save()
132                     request.user.message_set.create(message=_("'%s' settings saved succesfully") % set_name)
133
134                     if set_name in ('minrep', 'badges', 'repgain'):
135                         settings.SETTINGS_PACK.set_value("custom")
136
137                 return HttpResponseRedirect(reverse('admin_set', args=[set_name]))
138     else:
139         form = SettingsSetForm(set, unsaved=current_preview)
140
141     return 'osqaadmin/set.html', {
142         'form': form,
143         'markdown': set.markdown,
144     }
145
146 @super_user_required
147 def get_default(request, set_name, var_name):
148     set = Setting.sets.get(set_name, None)
149     if set is None: raise Http404
150
151     setting = dict([(s.name, s) for s in set]).get(var_name, None)
152     if setting is None: raise Http404
153
154     setting.to_default()
155
156     if request.is_ajax():
157         return HttpResponse(setting.default)
158     else:
159         return HttpResponseRedirect(reverse('admin_set', kwargs={'set_name': set_name}))
160
161
162 def get_recent_activity():
163     return Action.objects.order_by('-action_date')[0:30]
164
165 def get_flagged_posts():
166     return Action.objects.filter(canceled=False, action_type="flag").order_by('-action_date')[0:30]
167
168 def get_statistics():
169     return {
170         'total_users': User.objects.all().count(),
171         'users_last_24': User.objects.filter(date_joined__gt=(datetime.now() - timedelta(days=1))).count(),
172         'total_questions': Question.objects.filter_state(deleted=False).count(),
173         'questions_last_24': Question.objects.filter_state(deleted=False).filter(added_at__gt=(datetime.now() - timedelta(days=1))).count(),
174         'total_answers': Answer.objects.filter_state(deleted=False).count(),
175         'answers_last_24': Answer.objects.filter_state(deleted=False).filter(added_at__gt=(datetime.now() - timedelta(days=1))).count(),
176     }
177
178 @super_user_required
179 def go_bootstrap(request):
180     #todo: this is the quick and dirty way of implementing a bootstrap mode
181     try:
182         from forum_modules.default_badges import settings as dbsets
183         dbsets.POPULAR_QUESTION_VIEWS.set_value(100)
184         dbsets.NOTABLE_QUESTION_VIEWS.set_value(200)
185         dbsets.FAMOUS_QUESTION_VIEWS.set_value(300)
186         dbsets.NICE_ANSWER_VOTES_UP.set_value(2)
187         dbsets.NICE_QUESTION_VOTES_UP.set_value(2)
188         dbsets.GOOD_ANSWER_VOTES_UP.set_value(4)
189         dbsets.GOOD_QUESTION_VOTES_UP.set_value(4)
190         dbsets.GREAT_ANSWER_VOTES_UP.set_value(8)
191         dbsets.GREAT_QUESTION_VOTES_UP.set_value(8)
192         dbsets.FAVORITE_QUESTION_FAVS.set_value(1)
193         dbsets.STELLAR_QUESTION_FAVS.set_value(3)
194         dbsets.DISCIPLINED_MIN_SCORE.set_value(3)
195         dbsets.PEER_PRESSURE_MAX_SCORE.set_value(-3)
196         dbsets.CIVIC_DUTY_VOTES.set_value(15)
197         dbsets.PUNDIT_COMMENT_COUNT.set_value(10)
198         dbsets.SELF_LEARNER_UP_VOTES.set_value(2)
199         dbsets.STRUNK_AND_WHITE_EDITS.set_value(10)
200         dbsets.ENLIGHTENED_UP_VOTES.set_value(2)
201         dbsets.GURU_UP_VOTES.set_value(4)
202         dbsets.NECROMANCER_UP_VOTES.set_value(2)
203         dbsets.NECROMANCER_DIF_DAYS.set_value(30)
204         dbsets.TAXONOMIST_USE_COUNT.set_value(5)
205     except:
206         pass
207
208     settings.REP_TO_VOTE_UP.set_value(0)
209     settings.REP_TO_VOTE_DOWN.set_value(15)
210     settings.REP_TO_FLAG.set_value(15)
211     settings.REP_TO_COMMENT.set_value(0)
212     settings.REP_TO_LIKE_COMMENT.set_value(0)
213     settings.REP_TO_UPLOAD.set_value(0)
214     settings.REP_TO_CREATE_TAGS.set_value(0)
215     settings.REP_TO_CLOSE_OWN.set_value(60)
216     settings.REP_TO_REOPEN_OWN.set_value(120)
217     settings.REP_TO_RETAG.set_value(150)
218     settings.REP_TO_EDIT_WIKI.set_value(200)
219     settings.REP_TO_EDIT_OTHERS.set_value(400)
220     settings.REP_TO_CLOSE_OTHERS.set_value(600)
221     settings.REP_TO_DELETE_COMMENTS.set_value(400)
222     settings.REP_TO_VIEW_FLAGS.set_value(30)
223
224     settings.INITIAL_REP.set_value(1)
225     settings.MAX_REP_BY_UPVOTE_DAY.set_value(300)
226     settings.REP_GAIN_BY_UPVOTED.set_value(15)
227     settings.REP_LOST_BY_DOWNVOTED.set_value(1)
228     settings.REP_LOST_BY_DOWNVOTING.set_value(0)
229     settings.REP_GAIN_BY_ACCEPTED.set_value(25)
230     settings.REP_GAIN_BY_ACCEPTING.set_value(5)
231     settings.REP_LOST_BY_FLAGGED.set_value(2)
232     settings.REP_LOST_BY_FLAGGED_3_TIMES.set_value(30)
233     settings.REP_LOST_BY_FLAGGED_5_TIMES.set_value(100)
234
235     settings.SETTINGS_PACK.set_value("bootstrap")
236
237     request.user.message_set.create(message=_('Bootstrap mode enabled'))
238     return HttpResponseRedirect(reverse('admin_index'))
239
240 @super_user_required
241 def go_defaults(request):
242     for setting in Setting.sets['badges']:
243         setting.to_default()
244     for setting in Setting.sets['minrep']:
245         setting.to_default()
246     for setting in Setting.sets['repgain']:
247         setting.to_default()
248
249     settings.SETTINGS_PACK.set_value("default")
250
251     request.user.message_set.create(message=_('All values reverted to defaults'))
252     return HttpResponseRedirect(reverse('admin_index'))
253
254
255 @super_user_required
256 def recalculate_denormalized(request):
257     for n in Node.objects.all():
258         n = n.leaf
259         n.score = n.votes.aggregate(score=Sum('value'))['score']
260         if not n.score: n.score = 0
261         n.save()
262
263     for u in User.objects.all():
264         u.reputation = u.reputes.aggregate(reputation=Sum('value'))['reputation']
265         u.save()
266
267     request.user.message_set.create(message=_('All values recalculated'))
268     return HttpResponseRedirect(reverse('admin_index'))
269
270 @admin_page
271 def maintenance(request):
272     if request.POST:
273         if 'close' in request.POST or 'adjust' in request.POST:
274             form = MaintenanceModeForm(request.POST)
275
276             if form.is_valid():
277                 settings.MAINTAINANCE_MODE.set_value({
278                     'allow_ips': form.cleaned_data['ips'],
279                     'message': form.cleaned_data['message']})
280
281                 if 'close' in request.POST:
282                     message = _('Maintenance mode enabled')
283                 else:
284                     message = _('Settings adjusted')
285
286                 request.user.message_set.create(message=message)
287
288                 return HttpResponseRedirect(reverse('admin_maintenance'))
289         elif 'open' in request.POST:
290             settings.MAINTAINANCE_MODE.set_value(None)
291             request.user.message_set.create(message=_("Your site is now running normally"))
292             return HttpResponseRedirect(reverse('admin_maintenance'))
293     else:
294         form = MaintenanceModeForm(initial={'ips': request.META['REMOTE_ADDR'],
295                                             'message': _('Currently down for maintenance. We\'ll be back soon')})
296
297     return ('osqaadmin/maintenance.html', {'form': form, 'in_maintenance': settings.MAINTAINANCE_MODE.value is not None})
298
299
300 @admin_page
301 def flagged_posts(request):
302     return ('osqaadmin/flagged_posts.html', {
303         'flagged_posts': get_flagged_posts(),
304     })
305
306 @admin_page
307 def static_pages(request):
308     pages = Page.objects.all()
309
310     return ('osqaadmin/static_pages.html', {
311         'pages': pages,
312     })
313
314 @admin_page
315 def edit_page(request, id=None):
316     if id:
317         page = get_object_or_404(Page, id=id)
318     else:
319         page = None
320
321     if request.POST:
322         form = PageForm(page, request.POST)
323
324         if form.is_valid():
325             if form.has_changed():
326                 if not page:
327                     page = NewPageAction(user=request.user, ip=request.META['REMOTE_ADDR']).save(data=form.cleaned_data).node
328                 else:
329                     EditPageAction(user=request.user, node=page, ip=request.META['REMOTE_ADDR']).save(data=form.cleaned_data)
330
331             if ('publish' in request.POST) and (not page.published):
332                 PublishAction(user=request.user, node=page, ip=request.META['REMOTE_ADDR']).save()
333             elif ('unpublish' in request.POST) and page.published:
334                 page.nstate.published.cancel(ip=request.META['REMOTE_ADDR'])
335
336             return HttpResponseRedirect(reverse('admin_edit_page', kwargs={'id': page.id}))
337
338     else:
339         form = PageForm(page)
340
341     if page:
342         published = page.published
343     else:
344         published = False
345
346     return ('osqaadmin/edit_page.html', {
347         'page': page,
348         'form': form,
349         'published': published
350     })
351
352
353