X-Git-Url: https://git.openstreetmap.org./osqa.git/blobdiff_plain/9e40b5e5d7e26f4b8d3250cfbde23540a6205fd6..66503d2ac0ba6b217a3ba4af553e2440c9f2421c:/forum/views/admin.py?ds=inline diff --git a/forum/views/admin.py b/forum/views/admin.py index 9fd08f2..948f6c5 100644 --- a/forum/views/admin.py +++ b/forum/views/admin.py @@ -1,27 +1,32 @@ from datetime import datetime, timedelta -import time +import os, time, csv, random from django.shortcuts import render_to_response, get_object_or_404 from django.core.urlresolvers import reverse -from django.http import HttpResponseRedirect, HttpResponse, HttpResponseForbidden, Http404 +from django.http import HttpResponseRedirect, HttpResponse, Http404 +from forum.http_responses import HttpResponseUnauthorized from django.template import RequestContext from django.utils.translation import ugettext as _ from django.utils import simplejson -from django.db.models import Sum +from django.db import models from forum.settings.base import Setting -from forum.forms import MaintenanceModeForm, PageForm +from forum.forms import MaintenanceModeForm, PageForm, NodeManFilterForm from forum.settings.forms import SettingsSetForm +from forum.utils import pagination -from forum.models import Question, Answer, User, Node, Action, Page +from forum.models import Question, Answer, User, Node, Action, Page, NodeState +from forum.models.node import NodeMetaClass from forum.actions import NewPageAction, EditPageAction, PublishAction from forum import settings +TOOLS = {} + def super_user_required(fn): def wrapper(request, *args, **kwargs): if request.user.is_authenticated() and request.user.is_superuser: return fn(request, *args, **kwargs) else: - return HttpResponseForbidden() + return HttpResponseUnauthorized(request) return wrapper @@ -29,29 +34,48 @@ def admin_page(fn): @super_user_required def wrapper(request, *args, **kwargs): res = fn(request, *args, **kwargs) - if isinstance(res, tuple): - template, context = res - context['basetemplate'] = settings.DJSTYLE_ADMIN_INTERFACE and "osqaadmin/djstyle_base.html" or "osqaadmin/base.html" - context['allsets'] = Setting.sets - context['othersets'] = sorted( - [s for s in Setting.sets.values() if not s.name in - ('basic', 'users', 'email', 'paths', 'extkeys', 'repgain', 'minrep', 'voting', 'badges', 'about', 'faq', 'sidebar', - 'form', 'moderation', 'css')] - , lambda s1, s2: s1.weight - s2.weight) - return render_to_response(template, context, context_instance=RequestContext(request)) - else: + if isinstance(res, HttpResponse): return res + template, context = res + context['basetemplate'] = settings.DJSTYLE_ADMIN_INTERFACE and "osqaadmin/djstyle_base.html" or "osqaadmin/base.html" + context['allsets'] = Setting.sets + context['othersets'] = sorted( + [s for s in Setting.sets.values() if not s.name in + ('basic', 'users', 'email', 'paths', 'extkeys', 'repgain', 'minrep', 'voting', 'accept', 'badges', 'about', 'faq', 'sidebar', + 'form', 'moderation', 'css', 'headandfoot', 'head', 'view', 'urls')] + , lambda s1, s2: s1.weight - s2.weight) + + context['tools'] = TOOLS + + unsaved = request.session.get('previewing_settings', {}) + context['unsaved'] = set([getattr(settings, s).set.name for s in unsaved.keys() if hasattr(settings, s)]) + + return render_to_response(template, context, context_instance=RequestContext(request)) + return wrapper +def admin_tools_page(name, label): + def decorator(fn): + fn = admin_page(fn) + fn.label = label + TOOLS[name] = fn + + return fn + return decorator + +class ActivityPaginatorContext(pagination.PaginatorContext): + def __init__(self): + super (ActivityPaginatorContext, self).__init__('ADMIN_RECENT_ACTIVITY', pagesizes=(20, 40, 80), default_pagesize=40) + @admin_page def dashboard(request): - return ('osqaadmin/dashboard.html', { - 'settings_pack': unicode(settings.SETTINGS_PACK), - 'statistics': get_statistics(), - 'recent_activity': get_recent_activity(), - 'flagged_posts': get_flagged_posts(), - }) + return ('osqaadmin/dashboard.html', pagination.paginated(request, ("recent_activity", ActivityPaginatorContext()), { + 'settings_pack': unicode(settings.SETTINGS_PACK), + 'statistics': get_statistics(), + 'recent_activity': get_recent_activity(), + 'flagged_posts': get_flagged_posts(), + })) @super_user_required def interface_switch(request): @@ -66,42 +90,51 @@ def statistics(request): last_month = today - timedelta(days=30) last_month_questions = Question.objects.filter_state(deleted=False).filter(added_at__gt=last_month - ).order_by('added_at').values_list('added_at', flat=True) + ).order_by('added_at').values_list( + 'added_at', flat=True) last_month_n_questions = Question.objects.filter_state(deleted=False).filter(added_at__lt=last_month).count() qgraph_data = simplejson.dumps([ - (time.mktime(d.timetuple()) * 1000, i + last_month_n_questions) - for i, d in enumerate(last_month_questions) + (time.mktime(d.timetuple()) * 1000, i + last_month_n_questions) + for i, d in enumerate(last_month_questions) ]) last_month_users = User.objects.filter(date_joined__gt=last_month - ).order_by('date_joined').values_list('date_joined', flat=True) + ).order_by('date_joined').values_list('date_joined', flat=True) last_month_n_users = User.objects.filter(date_joined__lt=last_month).count() ugraph_data = simplejson.dumps([ - (time.mktime(d.timetuple()) * 1000, i + last_month_n_users) - for i, d in enumerate(last_month_users) + (time.mktime(d.timetuple()) * 1000, i + last_month_n_users) + for i, d in enumerate(last_month_users) ]) return 'osqaadmin/statistics.html', { - 'graphs': [ + 'graphs': [ { - 'id': 'questions_graph', - 'caption': _("Questions Graph"), - 'data': qgraph_data - },{ - 'id': 'userss_graph', - 'caption': _("Users Graph"), - 'data': ugraph_data + 'id': 'questions_graph', + 'caption': _("Questions Graph"), + 'data': qgraph_data + }, { + 'id': 'userss_graph', + 'caption': _("Users Graph"), + 'data': ugraph_data } - ] + ] } +@admin_page +def tools_page(request, name): + if not name in TOOLS: + raise Http404 + + return TOOLS[name](request) + @admin_page def settings_set(request, set_name): - set = Setting.sets.get(set_name, None) + set = Setting.sets.get(set_name, {}) + current_preview = request.session.get('previewing_settings', {}) if set is None: raise Http404 @@ -110,19 +143,31 @@ def settings_set(request, set_name): form = SettingsSetForm(set, data=request.POST, files=request.FILES) if form.is_valid(): - form.save() - request.user.message_set.create(message=_("'%s' settings saved succesfully") % set_name) + if 'preview' in request.POST: + current_preview.update(form.cleaned_data) + request.session['previewing_settings'] = current_preview - if set_name in ('minrep', 'badges', 'repgain'): - settings.SETTINGS_PACK.set_value("custom") + return HttpResponseRedirect(reverse('index')) + else: + for s in set: + current_preview.pop(s.name, None) - return HttpResponseRedirect(reverse('admin_set', args=[set_name])) + request.session['previewing_settings'] = current_preview + + if not 'reset' in request.POST: + form.save() + request.user.message_set.create(message=_("'%s' settings saved succesfully") % set_name) + + if set_name in ('minrep', 'badges', 'repgain'): + settings.SETTINGS_PACK.set_value("custom") + + return HttpResponseRedirect(reverse('admin_set', args=[set_name])) else: - form = SettingsSetForm(set) + form = SettingsSetForm(set, unsaved=current_preview) return 'osqaadmin/set.html', { - 'form': form, - 'markdown': set.markdown, + 'form': form, + 'markdown': set.markdown, } @super_user_required @@ -142,24 +187,26 @@ def get_default(request, set_name, var_name): def get_recent_activity(): - return Action.objects.order_by('-action_date')[0:30] + return Action.objects.order_by('-action_date') def get_flagged_posts(): return Action.objects.filter(canceled=False, action_type="flag").order_by('-action_date')[0:30] def get_statistics(): return { - 'total_users': User.objects.all().count(), - 'users_last_24': User.objects.filter(date_joined__gt=(datetime.now() - timedelta(days=1))).count(), - 'total_questions': Question.objects.filter_state(deleted=False).count(), - 'questions_last_24': Question.objects.filter_state(deleted=False).filter(added_at__gt=(datetime.now() - timedelta(days=1))).count(), - 'total_answers': Answer.objects.filter_state(deleted=False).count(), - 'answers_last_24': Answer.objects.filter_state(deleted=False).filter(added_at__gt=(datetime.now() - timedelta(days=1))).count(), + 'total_users': User.objects.all().count(), + 'users_last_24': User.objects.filter(date_joined__gt=(datetime.now() - timedelta(days=1))).count(), + 'total_questions': Question.objects.filter_state(deleted=False).count(), + 'questions_last_24': Question.objects.filter_state(deleted=False).filter( + added_at__gt=(datetime.now() - timedelta(days=1))).count(), + 'total_answers': Answer.objects.filter_state(deleted=False).count(), + 'answers_last_24': Answer.objects.filter_state(deleted=False).filter( + added_at__gt=(datetime.now() - timedelta(days=1))).count(), } @super_user_required def go_bootstrap(request): - #todo: this is the quick and dirty way of implementing a bootstrap mode +#todo: this is the quick and dirty way of implementing a bootstrap mode try: from forum_modules.default_badges import settings as dbsets dbsets.POPULAR_QUESTION_VIEWS.set_value(100) @@ -238,12 +285,12 @@ def go_defaults(request): def recalculate_denormalized(request): for n in Node.objects.all(): n = n.leaf - n.score = n.votes.aggregate(score=Sum('value'))['score'] + n.score = n.votes.aggregate(score=models.Sum('value'))['score'] if not n.score: n.score = 0 n.save() for u in User.objects.all(): - u.reputation = u.reputes.aggregate(reputation=Sum('value'))['reputation'] + u.reputation = u.reputes.aggregate(reputation=models.Sum('value'))['reputation'] u.save() request.user.message_set.create(message=_('All values recalculated')) @@ -257,8 +304,8 @@ def maintenance(request): if form.is_valid(): settings.MAINTAINANCE_MODE.set_value({ - 'allow_ips': form.cleaned_data['ips'], - 'message': form.cleaned_data['message']}) + 'allow_ips': form.cleaned_data['ips'], + 'message': form.cleaned_data['message']}) if 'close' in request.POST: message = _('Maintenance mode enabled') @@ -276,13 +323,14 @@ def maintenance(request): form = MaintenanceModeForm(initial={'ips': request.META['REMOTE_ADDR'], 'message': _('Currently down for maintenance. We\'ll be back soon')}) - return ('osqaadmin/maintenance.html', {'form': form, 'in_maintenance': settings.MAINTAINANCE_MODE.value is not None}) + return ('osqaadmin/maintenance.html', {'form': form, 'in_maintenance': settings.MAINTAINANCE_MODE.value is not None + }) @admin_page def flagged_posts(request): return ('osqaadmin/flagged_posts.html', { - 'flagged_posts': get_flagged_posts(), + 'flagged_posts': get_flagged_posts(), }) @admin_page @@ -290,7 +338,7 @@ def static_pages(request): pages = Page.objects.all() return ('osqaadmin/static_pages.html', { - 'pages': pages, + 'pages': pages, }) @admin_page @@ -306,9 +354,11 @@ def edit_page(request, id=None): if form.is_valid(): if form.has_changed(): if not page: - page = NewPageAction(user=request.user, ip=request.META['REMOTE_ADDR']).save(data=form.cleaned_data).node + page = NewPageAction(user=request.user, ip=request.META['REMOTE_ADDR']).save(data=form.cleaned_data + ).node else: - EditPageAction(user=request.user, node=page, ip=request.META['REMOTE_ADDR']).save(data=form.cleaned_data) + EditPageAction(user=request.user, node=page, ip=request.META['REMOTE_ADDR']).save( + data=form.cleaned_data) if ('publish' in request.POST) and (not page.published): PublishAction(user=request.user, node=page, ip=request.META['REMOTE_ADDR']).save() @@ -326,10 +376,62 @@ def edit_page(request, id=None): published = False return ('osqaadmin/edit_page.html', { - 'page': page, - 'form': form, - 'published': published + 'page': page, + 'form': form, + 'published': published }) +@admin_tools_page(_("nodeman"), _("Node management")) +def node_management(request): + nodes = Node.objects.all() + + if (request.GET): + filter_form = NodeManFilterForm(request.GET) + else: + filter_form = NodeManFilterForm({'node_type': 'all', 'state_type': 'any'}) + + if filter_form.is_valid(): + data = filter_form.cleaned_data + + if data['node_type'] != 'all': + nodes = nodes.filter(node_type=data['node_type']) + + if (data['state_type'] != 'any'): + nodes = nodes.filter_state(**{str(data['state_type']): True}) + + if data['text']: + filter = None + + if data['text_in'] == 'title' or data['text_in'] == 'both': + filter = models.Q(title__icontains=data['text']) + + if data['text_in'] == 'body' or data['text_in'] == 'both': + sec_filter = models.Q(body__icontains=data['text']) + if filter: + filter = filter | sec_filter + else: + filter = sec_filter + + if filter: + nodes = nodes.filter(filter) + + + node_types = [('all', _("all"))] + [(k, n.friendly_name) for k, n in NodeMetaClass.types.items()] + state_types = NodeState.objects.filter(node__in=nodes).values_list('state_type', flat=True).distinct('state_type') + + return ('osqaadmin/nodeman.html', pagination.paginated(request, ("nodes", ActivityPaginatorContext()), { + 'nodes': nodes, + 'node_types': node_types, + 'state_types': state_types, + 'filter_form': filter_form, + 'hide_menu': True + })) + + + + + + +