<commit_before># -*- coding: utf8 -*-
# This file is part of PyBossa.
#
# Copyright (C) 2013 SF Isle of Man Limited
#
# PyBossa 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.
#
# PyBossa 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 PyBossa.  If not, see <http://www.gnu.org/licenses/>.

from flask import Blueprint
from flask import render_template
from flask import request
from flask import abort
from flask import flash
from flask import redirect
from flask import url_for
from flask import current_app
from flask import Response
from flask.ext.login import login_required, current_user
from flask_wtf import Form
from wtforms import TextField, IntegerField, validators
from wtforms.widgets import HiddenInput
from flask.ext.babel import lazy_gettext, gettext
from werkzeug.exceptions import HTTPException

import pybossa.model as model
from pybossa.core import db
from pybossa.util import admin_required, UnicodeWriter
from pybossa.cache import apps as cached_apps
from pybossa.cache import categories as cached_cat
from pybossa.auth import require
import pybossa.validator as pb_validator
from sqlalchemy import or_, func
import json
from StringIO import StringIO


blueprint = Blueprint('admin', __name__)


def format_error(msg, status_code):
    error = dict(error=msg,
                 status_code=status_code)
    return Response(json.dumps(error), status=status_code,
                    mimetype='application/json')


@blueprint.route('/')
@login_required
@admin_required
def index():
    """List admin actions"""
    return render_template('/admin/index.html')


@blueprint.route('/featured')
@blueprint.route('/featured/<int:app_id>', methods=['POST', 'DELETE'])
@login_required
@admin_required
def featured(app_id=None):
    """List featured apps of PyBossa"""
    try:
        categories = cached_cat.get_all()

        if request.method == 'GET':
            apps = {}
            for c in categories:
                n_apps = cached_apps.n_count(category=c.short_name)
                apps[c.short_name], n_apps = cached_apps.get(category=c.short_name,
                                                             page=1,
                                                             per_page=n_apps)
            return render_template('/admin/applications.html', apps=apps,
                                   categories=categories)
        else:
            app = db.session.query(model.app.App).get(app_id)
            if app:
                if request.method == 'POST':
                    cached_apps.reset()
                    f = model.featured.Featured()
                    f.app_id = app_id
                    require.app.update(app)
                    # Check if the app is already in this table
                    tmp = db.session.query(model.featured.Featured)\
                            .filter(model.featured.Featured.app_id == app_id)\
                            .first()
                    if (tmp is None):
                        db.session.add(f)
                        db.session.commit()
                        return json.dumps(f.dictize())
                    else:
                        msg = "App.id %s alreay in Featured table" % app_id
                        return format_error(msg, 415)
                if request.method == 'DELETE':
                    cached_apps.reset()
                    f = db.session.query(model.featured.Featured)\
                          .filter(model.featured.Featured.app_id == app_id)\
                          .first()
                    if (f):
                        db.session.delete(f)
                        db.session.commit()
                        return "", 204
                    else:
                        msg = 'App.id %s is not in Featured table' % app_id
                        return format_error(msg, 404)
            else:
                msg = 'App.id %s not found' % app_id
                return format_error(msg, 404)
    except Exception as e: # pragma: no cover
        current_app.logger.error(e)
        return abort(500)


class SearchForm(Form):
    user = TextField(lazy_gettext('User'))


@blueprint.route('/users', methods=['GET', 'POST'])
@login_required
@admin_required
def users(user_id=None):
    """Manage users of PyBossa"""
    try:
        form = SearchForm(request.form)
        users = db.session.query(model.user.User)\
                  .filter(model.user.User.admin == True)\
                  .filter(model.user.User.id != current_user.id)\
                  .all()

        if request.method == 'POST' and form.user.data:
            query = '%' + form.user.data.lower() + '%'
            found = db.session.query(model.user.User)\
                      .filter(or_(func.lower(model.user.User.name).like(query),
                                  func.lower(model.user.User.fullname).like(query)))\
                      .filter(model.user.User.id != current_user.id)\
                      .all()
            require.user.update(found)
            if not found:
                flash("<strong>Ooops!</strong> We didn't find a user "
                      "matching your query: <strong>%s</strong>" % form.user.data)
            return render_template('/admin/users.html', found=found, users=users,
                                   title=gettext("Manage Admin Users"),
                                   form=form)

        return render_template('/admin/users.html', found=[], users=users,
                               title=gettext("Manage Admin Users"), form=form)
    except Exception as e:  # pragma: no cover
        current_app.logger.error(e)
        return abort(500)


@blueprint.route('/users/export')
@login_required
@admin_required
def export_users():
    """Export Users list in the given format, only for admins"""

    exportable_attributes = ('id', 'name', 'fullname', 'email_addr',
                             'created', 'locale', 'admin')

    def respond_json():
        return Response(gen_json(), mimetype='application/json')

    def gen_json():
        users = db.session.query(model.user.User).all()
        json_users = []
        for user in users:
            json_users.append(dictize_with_exportable_attributes(user))
        return json.dumps(json_users)

    def dictize_with_exportable_attributes(user):
        dict_user = {}
        for attr in exportable_attributes:
            dict_user[attr] = getattr(user, attr)
        return dict_user

    def respond_csv():
        out = StringIO()
        writer = UnicodeWriter(out)
        return Response(gen_csv(out, writer, write_user), mimetype='text/csv')

    def gen_csv(out, writer, write_user):
        add_headers(writer)
        for user in db.session.query(model.user.User).yield_per(1):
            write_user(writer, user)
        yield out.getvalue()

    def write_user(writer, user):
        values = [getattr(user, attr) for attr in sorted(exportable_attributes)]
        writer.writerow(values)

    def add_headers(writer):
        writer.writerow(sorted(exportable_attributes))

    export_formats = ["json", "csv"]

    fmt = request.args.get('format')
    if not fmt:
        return redirect(url_for('.index'))
    if fmt not in export_formats:
        abort(415)
    return {"json": respond_json, "csv": respond_csv}[fmt]()<commit_msg>Download it as a file.<commit_after># -* -coding: utf8 -*-
# This file is part of PyBossa.
#
# Copyright (C) 2013 SF Isle of Man Limited
#
# PyBossa 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.
#
# PyBossa 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 PyBossa.  If not, see <http://www.gnu.org/licenses/>.

from flask import Blueprint
from flask import render_template
from flask import request
from flask import abort
from flask import flash
from flask import redirect
from flask import url_for
from flask import current_app
from flask import Response
from flask.ext.login import login_required, current_user
from flask_wtf import Form
from wtforms import TextField, IntegerField, validators
from wtforms.widgets import HiddenInput
from flask.ext.babel import lazy_gettext, gettext
from werkzeug.exceptions import HTTPException

import pybossa.model as model
from pybossa.core import db
from pybossa.util import admin_required, UnicodeWriter
from pybossa.cache import apps as cached_apps
from pybossa.cache import categories as cached_cat
from pybossa.auth import require
import pybossa.validator as pb_validator
from sqlalchemy import or_, func
import json
from StringIO import StringIO


blueprint = Blueprint('admin', __name__)


def format_error(msg, status_code):
    error = dict(error=msg,
                 status_code=status_code)
    return Response(json.dumps(error), status=status_code,
                    mimetype='application/json')


@blueprint.route('/')
@login_required
@admin_required
def index():
    """List admin actions"""
    return render_template('/admin/index.html')


@blueprint.route('/featured')
@blueprint.route('/featured/<int:app_id>', methods=['POST', 'DELETE'])
@login_required
@admin_required
def featured(app_id=None):
    """List featured apps of PyBossa"""
    try:
        categories = cached_cat.get_all()

        if request.method == 'GET':
            apps = {}
            for c in categories:
                n_apps = cached_apps.n_count(category=c.short_name)
                apps[c.short_name], n_apps = cached_apps.get(category=c.short_name,
                                                             page=1,
                                                             per_page=n_apps)
            return render_template('/admin/applications.html', apps=apps,
                                   categories=categories)
        else:
            app = db.session.query(model.app.App).get(app_id)
            if app:
                if request.method == 'POST':
                    cached_apps.reset()
                    f = model.featured.Featured()
                    f.app_id = app_id
                    require.app.update(app)
                    # Check if the app is already in this table
                    tmp = db.session.query(model.featured.Featured)\
                            .filter(model.featured.Featured.app_id == app_id)\
                            .first()
                    if (tmp is None):
                        db.session.add(f)
                        db.session.commit()
                        return json.dumps(f.dictize())
                    else:
                        msg = "App.id %s alreay in Featured table" % app_id
                        return format_error(msg, 415)
                if request.method == 'DELETE':
                    cached_apps.reset()
                    f = db.session.query(model.featured.Featured)\
                          .filter(model.featured.Featured.app_id == app_id)\
                          .first()
                    if (f):
                        db.session.delete(f)
                        db.session.commit()
                        return "", 204
                    else:
                        msg = 'App.id %s is not in Featured table' % app_id
                        return format_error(msg, 404)
            else:
                msg = 'App.id %s not found' % app_id
                return format_error(msg, 404)
    except Exception as e: # pragma: no cover
        current_app.logger.error(e)
        return abort(500)


class SearchForm(Form):
    user = TextField(lazy_gettext('User'))


@blueprint.route('/users', methods=['GET', 'POST'])
@login_required
@admin_required
def users(user_id=None):
    """Manage users of PyBossa"""
    try:
        form = SearchForm(request.form)
        users = db.session.query(model.user.User)\
                  .filter(model.user.User.admin == True)\
                  .filter(model.user.User.id != current_user.id)\
                  .all()

        if request.method == 'POST' and form.user.data:
            query = '%' + form.user.data.lower() + '%'
            found = db.session.query(model.user.User)\
                      .filter(or_(func.lower(model.user.User.name).like(query),
                                  func.lower(model.user.User.fullname).like(query)))\
                      .filter(model.user.User.id != current_user.id)\
                      .all()
            require.user.update(found)
            if not found:
                flash("<strong>Ooops!</strong> We didn't find a user "
                      "matching your query: <strong>%s</strong>" % form.user.data)
            return render_template('/admin/users.html', found=found, users=users,
                                   title=gettext("Manage Admin Users"),
                                   form=form)

        return render_template('/admin/users.html', found=[], users=users,
                               title=gettext("Manage Admin Users"), form=form)
    except Exception as e:  # pragma: no cover
        current_app.logger.error(e)
        return abort(500)


@blueprint.route('/users/export')
@login_required
@admin_required
def export_users():
    """Export Users list in the given format, only for admins"""

    exportable_attributes = ('id', 'name', 'fullname', 'email_addr',
                             'created', 'locale', 'admin')

    def respond_json():
        tmp = 'attachment; filename=all_users.json'
        res = Response(gen_json(), mimetype='application/json')
        res.headers['Content-Disposition'] = tmp
        return res

    def gen_json():
        users = db.session.query(model.user.User).all()
        json_users = []
        for user in users:
            json_users.append(dictize_with_exportable_attributes(user))
        return json.dumps(json_users)

    def dictize_with_exportable_attributes(user):
        dict_user = {}
        for attr in exportable_attributes:
            dict_user[attr] = getattr(user, attr)
        return dict_user

    def respond_csv():
        out = StringIO()
        writer = UnicodeWriter(out)
        tmp = 'attachment; filename=all_users.csv'
        res = Response(gen_csv(out, writer, write_user), mimetype='text/csv')
        res.headers['Content-Disposition'] = tmp
        return res

    def gen_csv(out, writer, write_user):
        add_headers(writer)
        for user in db.session.query(model.user.User).yield_per(1):
            write_user(writer, user)
        yield out.getvalue()

    def write_user(writer, user):
        values = [getattr(user, attr) for attr in sorted(exportable_attributes)]
        writer.writerow(values)

    def add_headers(writer):
        writer.writerow(sorted(exportable_attributes))

    export_formats = ["json", "csv"]

    fmt = request.args.get('format')
    if not fmt:
        return redirect(url_for('.index'))
    if fmt not in export_formats:
        abort(415)
    return {"json": respond_json, "csv": respond_csv}[fmt]()
{'fraction_non_alphanumeric': 0.10048180550272601, 'fraction_numerical': 0.003676936731330037, 'mean_word_length': 2.0220306513409962, 'pattern_counts': {'":': 4, '<': 15, '<?xml version=': 0, '>': 15, 'https://': 0, 'lorem ipsum': 0, 'www.': 2, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 17, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '1032882', 'n_tokens_mistral': 4428, 'n_tokens_neox': 4191, 'n_words': 1155}