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