# GNU MediaGoblin -- federated, autonomous media hosting
# Copyright (C) 2011, 2012 MediaGoblin contributors.  See AUTHORS.
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU Affero General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU Affero General Public License for more details.
#
# You should have received a copy of the GNU Affero General Public License
# along with this program.  If not, see <http://www.gnu.org/licenses/>.


from mediagoblin.db.models import (MediaEntry, User, Report, Privilege,
                                   UserBan, LocalUser)
from mediagoblin.decorators import (require_admin_or_moderator_login,
                                    active_user_from_url, user_has_privilege,
                                    allow_reporting)
from mediagoblin.tools.response import render_to_response, redirect
from mediagoblin.moderation import forms as moderation_forms
from mediagoblin.moderation.tools import (take_punitive_actions, \
    take_away_privileges, give_privileges, ban_user, unban_user, \
    parse_report_panel_settings)
from math import ceil

@require_admin_or_moderator_login
def moderation_media_processing_panel(request):
    '''
    Show the global media processing panel for this instance
    '''
    processing_entries = MediaEntry.query.filter_by(state = u'processing').\
        order_by(MediaEntry.created.desc())

    # Get media entries which have failed to process
    failed_entries = MediaEntry.query.filter_by(state = u'failed').\
        order_by(MediaEntry.created.desc())

    processed_entries = MediaEntry.query.filter_by(state = u'processed').\
        order_by(MediaEntry.created.desc()).limit(10)

    # Render to response
    return render_to_response(
        request,
        'mediagoblin/moderation/media_panel.html',
        {'processing_entries': processing_entries,
         'failed_entries': failed_entries,
         'processed_entries': processed_entries})

@require_admin_or_moderator_login
def moderation_users_panel(request):
    '''
    Show the global panel for monitoring users in this instance
    '''
    current_page = 1
    if len(request.args) > 0:
        form = moderation_forms.UserPanelSortingForm(request.args)
        if form.validate():
            current_page = form.p.data or 1

    all_user_list = User.query
    user_list = all_user_list.order_by(
        User.created.desc()).offset(
            (current_page-1)*10).limit(10)
    last_page = int(ceil(all_user_list.count()/10.))

    return render_to_response(
        request,
        'mediagoblin/moderation/user_panel.html',
        {'user_list': user_list,
         'current_page':current_page,
         'last_page':last_page})

@require_admin_or_moderator_login
def moderation_users_detail(request):
    '''
    Shows details about a particular user.
    '''
    user = LocalUser.query.filter(
        LocalUser.username==request.matchdict['user']
    ).first()
    active_reports = user.reports_filed_on.filter(
        Report.resolved==None).limit(5)
    closed_reports = user.reports_filed_on.filter(
        Report.resolved!=None).all()
    privileges = Privilege.query
    user_banned = UserBan.query.get(user.id)
    ban_form = moderation_forms.BanForm()

    return render_to_response(
        request,
        'mediagoblin/moderation/user.html',
        {'user':user,
         'privileges': privileges,
         'reports':active_reports,
         'user_banned':user_banned,
         'ban_form':ban_form})

@require_admin_or_moderator_login
@allow_reporting
def moderation_reports_panel(request):
    '''
    Show the global panel for monitoring reports filed against comments or
        media entries for this instance.
    '''
    filters = []
    active_settings, closed_settings = {'current_page':1}, {'current_page':1}

    if len(request.args) > 0:
        form = moderation_forms.ReportPanelSortingForm(request.args)
        if form.validate():
            filters = parse_report_panel_settings(form)
            active_settings['current_page'] = form.active_p.data or 1
            closed_settings['current_page'] = form.closed_p.data or 1
            filters = [
               getattr(Report,key)==val
               for key,val in filters.items()]

    all_active = Report.query.filter(
        Report.resolved==None).filter(
        *filters)
    all_closed = Report.query.filter(
        Report.resolved!=None).filter(
        *filters)

    # report_list and closed_report_list are the two lists of up to 10
    # items which are actually passed to the user in this request
    report_list = all_active.order_by(
        Report.created.desc()).offset(
            (active_settings['current_page']-1)*10).limit(10)
    closed_report_list = all_closed.order_by(
        Report.created.desc()).offset(
            (closed_settings['current_page']-1)*10).limit(10)

    active_settings['last_page'] = int(ceil(all_active.count()/10.))
    closed_settings['last_page'] = int(ceil(all_closed.count()/10.))
    # Render to response
    return render_to_response(
        request,
        'mediagoblin/moderation/report_panel.html',
        {'report_list':report_list,
         'closed_report_list':closed_report_list,
         'active_settings':active_settings,
         'closed_settings':closed_settings})

@require_admin_or_moderator_login
@allow_reporting
def moderation_reports_detail(request):
    """
    This is the page an admin or moderator goes to see the details of a report.
    The report can be resolved or unresolved. This is also the page that a mod-
    erator would go to to take an action to resolve a report.
    """
    form = moderation_forms.ReportResolutionForm(request.form)
    report = Report.query.get(request.matchdict['report_id'])

    form.take_away_privileges.choices = [
        (s.privilege_name,s.privilege_name.title()) \
            for s in report.reported_user.all_privileges
    ]

    if request.method == "POST" and form.validate() and not (
        not request.user.has_privilege(u'admin') and
        report.reported_user.has_privilege(u'admin')):

        user = User.query.get(form.targeted_user.data)
        return take_punitive_actions(request, form, report, user)


    form.targeted_user.data = report.reported_user_id

    return render_to_response(
        request,
        'mediagoblin/moderation/report.html',
        {'report':report,
         'form':form})

@user_has_privilege(u'admin')
@active_user_from_url
def give_or_take_away_privilege(request, url_user):
    '''
    A form action to give or take away a particular privilege from a user.
    Can only be used by an admin.
    '''
    form = moderation_forms.PrivilegeAddRemoveForm(request.form)
    if request.method == "POST" and form.validate():
        privilege = Privilege.query.filter(
            Privilege.privilege_name==form.privilege_name.data).one()
        if not take_away_privileges(
            url_user.username, form.privilege_name.data):

            give_privileges(url_user.username, form.privilege_name.data)
        url_user.save()

    return redirect(
        request,
        'mediagoblin.moderation.users_detail',
        user=url_user.username)

@user_has_privilege(u'admin')
@active_user_from_url
def ban_or_unban(request, url_user):
    """
    A page to ban or unban a user. Only can be used by an admin.
    """
    form = moderation_forms.BanForm(request.form)
    if request.method == "POST" and form.validate():
        already_banned = unban_user(url_user.id)
        same_as_requesting_user = (request.user.id == url_user.id)
        if not already_banned and not same_as_requesting_user:
            user_ban = ban_user(url_user.id,
                expiration_date = form.user_banned_until.data,
                reason = form.why_user_was_banned.data)
            user_ban.save()
    return redirect(
        request,
        'mediagoblin.moderation.users_detail',
        user=url_user.username)
