X-Git-Url: https://git.openstreetmap.org./osqa.git/blobdiff_plain/f3b3b737aefbb812828fdec07e188ff8093ccf81..cdf6f5f965021228d2a411d23726eda56db0b5a7:/forum/views/admin.py diff --git a/forum/views/admin.py b/forum/views/admin.py index 7f83f9a..a834b71 100644 --- a/forum/views/admin.py +++ b/forum/views/admin.py @@ -1,22 +1,26 @@ from datetime import datetime, timedelta -import os, time, csv, random +import json +import time +from django.views.decorators.csrf import csrf_exempt from django.shortcuts import render_to_response, get_object_or_404 from django.core.urlresolvers import reverse 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 import models + +from django.contrib import messages + +from forum.http_responses import HttpResponseUnauthorized from forum.settings.base import Setting -from forum.forms import MaintenanceModeForm, PageForm, NodeManFilterForm, CreateUserForm +from forum.forms import MaintenanceModeForm, PageForm, CreateUserForm from forum.settings.forms import SettingsSetForm from forum.utils import pagination, html - -from forum.models import Question, Answer, User, Node, Action, Page, NodeState +from forum.utils.mail import send_template_email +from forum.models import Question, Answer, User, Node, Action, Page, NodeState, Tag from forum.models.node import NodeMetaClass -from forum.actions import NewPageAction, EditPageAction, PublishAction, DeleteAction, UserJoinsAction +from forum.actions import NewPageAction, EditPageAction, PublishAction, DeleteAction, UserJoinsAction, CloseAction from forum import settings TOOLS = {} @@ -30,28 +34,51 @@ def super_user_required(fn): return wrapper -def admin_page(fn): - @super_user_required +def staff_user_required(fn): def wrapper(request, *args, **kwargs): - res = fn(request, *args, **kwargs) - if isinstance(res, HttpResponse): - return res + if request.user.is_authenticated() and (request.user.is_staff or request.user.is_superuser): + return fn(request, *args, **kwargs) + else: + return HttpResponseUnauthorized(request) + + return wrapper + +def admin_page_wrapper(fn, request, *args, **kwargs): + res = fn(request, *args, **kwargs) + 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) + 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 + context['tools'] = [(name, fn.label) for name, fn in TOOLS.items()] - unsaved = request.session.get('previewing_settings', {}) - context['unsaved'] = set([getattr(settings, s).set.name for s in unsaved.keys() if hasattr(settings, s)]) + # Show the navigation only to moderators and super users + if not context.has_key("hide_navigation"): + context['hide_navigation'] = not request.user.is_superuser - return render_to_response(template, context, context_instance=RequestContext(request)) + 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)) + +def admin_page(fn): + @super_user_required + def wrapper(request, *args, **kwargs): + return admin_page_wrapper(fn, request, *args, **kwargs) + + return wrapper + +def moderation_page(fn): + @staff_user_required + def wrapper(request, *args, **kwargs): + return admin_page_wrapper(fn, request, *args, **kwargs) return wrapper @@ -94,7 +121,7 @@ def statistics(request): '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([ + qgraph_data = json.dumps([ (time.mktime(d.timetuple()) * 1000, i + last_month_n_questions) for i, d in enumerate(last_month_questions) ]) @@ -104,7 +131,7 @@ def statistics(request): last_month_n_users = User.objects.filter(date_joined__lt=last_month).count() - ugraph_data = simplejson.dumps([ + ugraph_data = json.dumps([ (time.mktime(d.timetuple()) * 1000, i + last_month_n_users) for i, d in enumerate(last_month_users) ]) @@ -156,7 +183,7 @@ def settings_set(request, set_name): if not 'reset' in request.POST: form.save() - request.user.message_set.create(message=_("'%s' settings saved succesfully") % set_name) + messages.info(request, _("'%s' settings saved succesfully") % set_name) if set_name in ('minrep', 'badges', 'repgain'): settings.SETTINGS_PACK.set_value("custom") @@ -263,7 +290,7 @@ def go_bootstrap(request): settings.SETTINGS_PACK.set_value("bootstrap") - request.user.message_set.create(message=_('Bootstrap mode enabled')) + messages.info(request, _('Bootstrap mode enabled')) return HttpResponseRedirect(reverse('admin_index')) @super_user_required @@ -277,7 +304,7 @@ def go_defaults(request): settings.SETTINGS_PACK.set_value("default") - request.user.message_set.create(message=_('All values reverted to defaults')) + messages.info(request, ('All values reverted to defaults')) return HttpResponseRedirect(reverse('admin_index')) @@ -293,7 +320,7 @@ def recalculate_denormalized(request): u.reputation = u.reputes.aggregate(reputation=models.Sum('value'))['reputation'] u.save() - request.user.message_set.create(message=_('All values recalculated')) + messages.info(request, _('All values recalculated')) return HttpResponseRedirect(reverse('admin_index')) @admin_page @@ -312,12 +339,12 @@ def maintenance(request): else: message = _('Settings adjusted') - request.user.message_set.create(message=message) + messages.info(request, message) return HttpResponseRedirect(reverse('admin_maintenance')) elif 'open' in request.POST: settings.MAINTAINANCE_MODE.set_value(None) - request.user.message_set.create(message=_("Your site is now running normally")) + messages.info(request, _("Your site is now running normally")) return HttpResponseRedirect(reverse('admin_maintenance')) else: form = MaintenanceModeForm(initial={'ips': request.META['REMOTE_ADDR'], @@ -327,7 +354,7 @@ def maintenance(request): }) -@admin_page +@moderation_page def flagged_posts(request): return ('osqaadmin/flagged_posts.html', { 'flagged_posts': get_flagged_posts(), @@ -381,6 +408,12 @@ def edit_page(request, id=None): 'published': published }) +@admin_page +def delete_page(request, id=None): + page = get_object_or_404(Page, id=id) + page.delete() + return HttpResponseRedirect(reverse('admin_static_pages')) + @admin_tools_page(_('createuser'), _("Create new user")) def create_user(request): if request.POST: @@ -396,7 +429,7 @@ def create_user(request): user_.save() UserJoinsAction(user=user_).save() - request.user.message_set.create(message=_("New user created sucessfully. %s.") % html.hyperlink( + messages.info(request, _("New user created sucessfully. %s.") % html.hyperlink( user_.get_profile_url(), _("See %s profile") % user_.username, target="_blank")) return HttpResponseRedirect(reverse("admin_tools", kwargs={'name': 'createuser'})) @@ -410,83 +443,153 @@ def create_user(request): class NodeManagementPaginatorContext(pagination.PaginatorContext): def __init__(self, id='QUESTIONS_LIST', prefix='', default_pagesize=100): super (NodeManagementPaginatorContext, self).__init__(id, sort_methods=( - (_('title'), pagination.SimpleSort(_('title'), '-title', "")), (_('added_at'), pagination.SimpleSort(_('added_at'), '-added_at', "")), + (_('added_at_asc'), pagination.SimpleSort(_('added_at_asc'), 'added_at', "")), + (_('author'), pagination.SimpleSort(_('author'), '-author__username', "")), + (_('author_asc'), pagination.SimpleSort(_('author_asc'), 'author__username', "")), (_('score'), pagination.SimpleSort(_('score'), '-score', "")), + (_('score_asc'), pagination.SimpleSort(_('score_asc'), 'score', "")), (_('act_at'), pagination.SimpleSort(_('act_at'), '-last_activity_at', "")), - ), pagesizes=(default_pagesize,), default_pagesize=default_pagesize, prefix=prefix) + (_('act_at_asc'), pagination.SimpleSort(_('act_at_asc'), 'last_activity_at', "")), + (_('act_by'), pagination.SimpleSort(_('act_by'), '-last_activity_by__username', "")), + (_('act_by_asc'), pagination.SimpleSort(_('act_by_asc'), 'last_activity_by__username', "")), + ), pagesizes=(default_pagesize,), force_sort='added_at', default_pagesize=default_pagesize, prefix=prefix) -@admin_tools_page(_("nodeman"), _("Node management")) +@admin_tools_page(_("nodeman"), _("Bulk management")) def node_management(request): if request.POST: - selected_nodes = request.POST.getlist('_selected_node') + params = pagination.generate_uri(request.GET, ('page',)) + + if "save_filter" in request.POST: + filter_name = request.POST.get('filter_name', _('filter')) + params = pagination.generate_uri(request.GET, ('page',)) + current_filters = settings.NODE_MAN_FILTERS.value + current_filters.append((filter_name, params)) + settings.NODE_MAN_FILTERS.set_value(current_filters) - if selected_nodes and request.POST.get('action', None): - action = request.POST['action'] - selected_nodes = Node.objects.filter(id__in=selected_nodes) + elif r"execute" in request.POST: + selected_nodes = request.POST.getlist('_selected_node') - message = _("No action performed") + if selected_nodes and request.POST.get('action', None): + action = str(request.POST['action']) + selected_nodes = Node.objects.filter(id__in=selected_nodes) - if action == 'delete_selected': - for node in selected_nodes: - if node.node_type in ('question', 'answer', 'comment') and (not node.nis.deleted): - DeleteAction(user=request.user, node=node, ip=request.META['REMOTE_ADDR']).save() - - message = _("All selected nodes marked as deleted") + message = _("No action performed") - request.user.message_set.create(message=message) - return HttpResponseRedirect(reverse("admin_tools", kwargs={'name': 'nodeman'})) + if action == 'delete_selected': + for node in selected_nodes: + if node.node_type in ('question', 'answer', 'comment') and (not node.nis.deleted): + DeleteAction(user=request.user, node=node, ip=request.META['REMOTE_ADDR']).save() + + message = _("All selected nodes marked as deleted") + + if action == 'undelete_selected': + for node in selected_nodes: + if node.node_type in ('question', 'answer', 'comment') and (node.nis.deleted): + node.nstate.deleted.cancel(ip=request.META['REMOTE_ADDR']) + + message = _("All selected nodes undeleted") + + if action == "close_selected": + for node in selected_nodes: + if node.node_type == "question" and (not node.nis.closed): + CloseAction(node=node.leaf, user=request.user, extra=_("bulk close"), ip=request.META['REMOTE_ADDR']).save() + + message = _("Selected questions were closed") + + if action == "hard_delete_selected": + ids = [n.id for n in selected_nodes] + + for id in ids: + try: + node = Node.objects.get(id=id) + node.delete() + except: + pass + + message = _("All selected nodes deleted") + + messages.info(request, message) + + params = pagination.generate_uri(request.GET, ('page',)) + + return HttpResponseRedirect(reverse("admin_tools", kwargs={'name': 'nodeman'}) + "?" + params) nodes = Node.objects.all() - if (request.GET): - filter_form = NodeManFilterForm(request.GET) - else: - filter_form = NodeManFilterForm({'node_type': 'all', 'state_type': 'any'}) + text = request.GET.get('text', '') + text_in = request.GET.get('text_in', 'body') - if filter_form.is_valid(): - data = filter_form.cleaned_data + authors = request.GET.getlist('authors') + tags = request.GET.getlist('tags') - if data['node_type'] != 'all': - nodes = nodes.filter(node_type=data['node_type']) + type_filter = request.GET.getlist('node_type') + state_filter = request.GET.getlist('state_type') + state_filter_type = request.GET.get('state_filter_type', 'any') - if (data['state_type'] != 'any'): - nodes = nodes.filter_state(**{str(data['state_type']): True}) + if type_filter: + nodes = nodes.filter(node_type__in=type_filter) - if data['text']: - filter = None + state_types = NodeState.objects.filter(node__in=nodes).values_list('state_type', flat=True).distinct('state_type') + state_filter = [s for s in state_filter if s in state_types] - if data['text_in'] == 'title' or data['text_in'] == 'both': - filter = models.Q(title__icontains=data['text']) + if state_filter: + if state_filter_type == 'all': + nodes = nodes.all_states(*state_filter) + else: + nodes = nodes.any_state(*state_filter) - 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 (authors): + nodes = nodes.filter(author__id__in=authors) + authors = User.objects.filter(id__in=authors) + + if (tags): + nodes = nodes.filter(tags__id__in=tags) + tags = Tag.objects.filter(id__in=tags) + + if text: + text_in = request.GET.get('text_in', 'body') + filter = None + if text_in == 'title' or text_in == 'both': + filter = models.Q(title__icontains=text) + + if text_in == 'body' or text_in == 'both': + sec_filter = models.Q(body__icontains=text) if filter: - nodes = nodes.filter(filter) - else: - print filter_form.errors + 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') + node_types = [(k, n.friendly_name) for k, n in NodeMetaClass.types.items()] return ('osqaadmin/nodeman.html', pagination.paginated(request, ("nodes", NodeManagementPaginatorContext()), { 'nodes': nodes, + 'text': text, + 'text_in': text_in, + 'type_filter': type_filter, + 'state_filter': state_filter, + 'state_filter_type': state_filter_type, 'node_types': node_types, 'state_types': state_types, - 'filter_form': filter_form, - 'hide_menu': True + 'authors': authors, + 'tags': tags, + 'hide_navigation': True })) +@csrf_exempt +@super_user_required +def test_email_settings(request): + user = request.user + send_template_email([user,], 'osqaadmin/mail_test.html', { 'user' : user }) - - - - + return render_to_response( + 'osqaadmin/test_email_settings.html', + { 'user': user, }, + RequestContext(request) + )