<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/>.

import time
from StringIO import StringIO
from flask import Blueprint, request, url_for, flash, redirect, abort, Response, current_app
from flask import render_template, make_response
from flask_wtf import Form
from wtforms import IntegerField, DecimalField, TextField, BooleanField, \
    SelectField, validators, TextAreaField, FileField
from wtforms.widgets import HiddenInput
from flask.ext.login import login_required, current_user
from flask.ext.babel import lazy_gettext, gettext
from werkzeug.exceptions import HTTPException
from sqlalchemy.sql import text

import pybossa.model as model
import pybossa.stats as stats
import pybossa.validator as pb_validator

from pybossa.core import db, uploader
from pybossa.cache import ONE_DAY, ONE_HOUR
from pybossa.model.app import App
from pybossa.model.task import Task
from pybossa.model.user import User
from pybossa.util import Pagination, UnicodeWriter, admin_required
from pybossa.auth import require
from pybossa.cache import apps as cached_apps
from pybossa.cache import categories as cached_cat
from pybossa.ckan import Ckan

import json
import importer
import presenter as presenter_module
import operator
import math
import requests

blueprint = Blueprint('app', __name__)

class AvatarUploadForm(Form):
    avatar = FileField(lazy_gettext('Avatar'), )
    x1 = IntegerField(label=None, widget=HiddenInput(), default=0)
    y1 = IntegerField(label=None, widget=HiddenInput(), default=0)
    x2 = IntegerField(label=None, widget=HiddenInput(), default=0)
    y2 = IntegerField(label=None, widget=HiddenInput(), default=0)


class AppForm(Form):
    id = IntegerField(label=None, widget=HiddenInput())
    name = TextField(lazy_gettext('Name'),
                     [validators.Required(),
                      pb_validator.Unique(db.session, model.app.App, model.app.App.name,
                                          message="Name is already taken.")])
    short_name = TextField(lazy_gettext('Short Name'),
                           [validators.Required(),
                            pb_validator.NotAllowedChars(),
                            pb_validator.Unique(
                                db.session, model.app.App, model.app.App.short_name,
                                message=lazy_gettext(
                                    "Short Name is already taken."))])
    description = TextField(lazy_gettext('Description'),
                            [validators.Required(
                                message=lazy_gettext(
                                    "You must provide a description."))])
    thumbnail = TextField(lazy_gettext('Icon Link'))
    allow_anonymous_contributors = SelectField(
        lazy_gettext('Allow Anonymous Contributors'),
        choices=[('True', lazy_gettext('Yes')),
                 ('False', lazy_gettext('No'))])
    category_id = SelectField(lazy_gettext('Category'), coerce=int)
    long_description = TextAreaField(lazy_gettext('Long Description'))
    hidden = BooleanField(lazy_gettext('Hide?'))
    avatar = FileField(lazy_gettext('Avatar'))
    x1 = IntegerField(label=None, widget=HiddenInput(), default=0)
    y1 = IntegerField(label=None, widget=HiddenInput(), default=0)
    x2 = IntegerField(label=None, widget=HiddenInput(), default=0)
    y2 = IntegerField(label=None, widget=HiddenInput(), default=0)


class TaskPresenterForm(Form):
    id = IntegerField(label=None, widget=HiddenInput())
    editor = TextAreaField('')


class TaskRedundancyForm(Form):
    n_answers = IntegerField(lazy_gettext('Redundancy'),
                             [validators.Required(),
                              validators.NumberRange(
                                  min=1, max=1000,
                                  message=lazy_gettext('Number of answers should be a \
                                                       value between 1 and 1,000'))])


class TaskPriorityForm(Form):
    task_ids = TextField(lazy_gettext('Task IDs'),
                         [validators.Required(),
                          pb_validator.CommaSeparatedIntegers()])

    priority_0 = DecimalField(lazy_gettext('Priority'),
                              [validators.NumberRange(
                                  min=0, max=1,
                                  message=lazy_gettext('Priority should be a \
                                                       value between 0.0 and 1.0'))])


class TaskSchedulerForm(Form):
    sched = SelectField(lazy_gettext('Task Scheduler'),
                        choices=[('default', lazy_gettext('Default')),
                                 ('breadth_first', lazy_gettext('Breadth First')),
                                 ('depth_first', lazy_gettext('Depth First')),
                                 ('random', lazy_gettext('Random'))])


class BlogpostForm(Form):
    id = IntegerField(label=None, widget=HiddenInput())
    title = TextField(lazy_gettext('Title'),
                     [validators.Required(message=lazy_gettext(
                                    "You must enter a title for the post."))])
    body = TextAreaField(lazy_gettext('Body'),
                           [validators.Required(message=lazy_gettext(
                                    "You must enter some text for the post."))])


def app_title(app, page_name):
    if not app:  # pragma: no cover
        return "Application not found"
    if page_name is None:
        return "Application: %s" % (app.name)
    return "Application: %s &middot; %s" % (app.name, page_name)


def app_by_shortname(short_name):
    app = cached_apps.get_app(short_name)
    if app.id:
        # Populate CACHE with the data of the app
        return (app,
                cached_apps.n_tasks(app.id),
                cached_apps.n_task_runs(app.id),
                cached_apps.overall_progress(app.id),
                cached_apps.last_activity(app.id))

    else:
        cached_apps.delete_app(short_name)
        return abort(404)


@blueprint.route('/', defaults={'page': 1})
@blueprint.route('/page/<int:page>/', defaults={'page': 1})
def redirect_old_featured(page):
    """DEPRECATED only to redirect old links"""
    return redirect(url_for('.index', page=page), 301)


@blueprint.route('/published/', defaults={'page': 1})
@blueprint.route('/published/<int:page>/', defaults={'page': 1})
def redirect_old_published(page):  # pragma: no cover
    """DEPRECATED only to redirect old links"""
    category = db.session.query(model.category.Category).first()
    return redirect(url_for('.app_cat_index', category=category.short_name, page=page), 301)


@blueprint.route('/draft/', defaults={'page': 1})
@blueprint.route('/draft/<int:page>/', defaults={'page': 1})
def redirect_old_draft(page):
    """DEPRECATED only to redirect old links"""
    return redirect(url_for('.draft', page=page), 301)


@blueprint.route('/category/featured/', defaults={'page': 1})
@blueprint.route('/category/featured/page/<int:page>/')
def index(page):
    """List apps in the system"""
    if cached_apps.n_featured() > 0:
        return app_index(page, cached_apps.get_featured, 'featured',
                         True, False)
    else:
        categories = cached_cat.get_all()
        cat_short_name = categories[0].short_name
        return redirect(url_for('.app_cat_index', category=cat_short_name))


def app_index(page, lookup, category, fallback, use_count):
    """Show apps of app_type"""

    per_page = current_app.config['APPS_PER_PAGE']

    apps, count = lookup(category, page, per_page)

    data = []
    for app in apps:
        data.append(dict(app=app, n_tasks=cached_apps.n_tasks(app['id']),
                         overall_progress=cached_apps.overall_progress(app['id']),
                         last_activity=app['last_activity'],
                         last_activity_raw=app['last_activity_raw'],
                         n_completed_tasks=cached_apps.n_completed_tasks(app['id']),
                         n_volunteers=cached_apps.n_volunteers(app['id'])))


    if fallback and not apps:  # pragma: no cover
        return redirect(url_for('.index'))

    pagination = Pagination(page, per_page, count)
    categories = cached_cat.get_all()
    # Check for pre-defined categories featured and draft
    featured_cat = model.category.Category(name='Featured',
                                  short_name='featured',
                                  description='Featured applications')
    if category == 'featured':
        active_cat = featured_cat
    elif category == 'draft':
        active_cat = model.category.Category(name='Draft',
                                    short_name='draft',
                                    description='Draft applications')
    else:
        active_cat = db.session.query(model.category.Category)\
                       .filter_by(short_name=category).first()

    # Check if we have to add the section Featured to local nav
    if cached_apps.n_featured() > 0:
        categories.insert(0, featured_cat)
    template_args = {
        "apps": data,
        "title": gettext("Applications"),
        "pagination": pagination,
        "active_cat": active_cat,
        "categories": categories}

    if use_count:
        template_args.update({"count": count})
    return render_template('/applications/index.html', **template_args)


@blueprint.route('/category/draft/', defaults={'page': 1})
@blueprint.route('/category/draft/page/<int:page>/')
@login_required
@admin_required
def draft(page):
    """Show the Draft apps"""
    return app_index(page, cached_apps.get_draft, 'draft',
                     False, True)


@blueprint.route('/category/<string:category>/', defaults={'page': 1})
@blueprint.route('/category/<string:category>/page/<int:page>/')
def app_cat_index(category, page):
    """Show Apps that belong to a given category"""
    return app_index(page, cached_apps.get, category, False, True)


@blueprint.route('/new', methods=['GET', 'POST'])
@login_required
def new():
    require.app.create()
    form = AppForm(request.form)
    categories = db.session.query(model.category.Category).all()
    form.category_id.choices = [(c.id, c.name) for c in categories]

    def respond(errors):
        return render_template('applications/new.html',
                               title=gettext("Create an Application"),
                               form=form, errors=errors)

    if request.method != 'POST':
        return respond(False)

    del form.id
    if not form.validate():
        flash(gettext('Please correct the errors'), 'error')
        return respond(True)

    info = {}

    app = model.app.App(name=form.name.data,
                    short_name=form.short_name.data,
                    description=form.description.data,
                    long_description=form.long_description.data,
                    category_id=form.category_id.data,
                    allow_anonymous_contributors=form.allow_anonymous_contributors.data,
                    hidden=int(form.hidden.data),
                    owner_id=current_user.id,
                    info=info)

    #cached_apps.reset()
    db.session.add(app)
    db.session.commit()
    # Upload the app
    if form.avatar.data:
        file = request.files['avatar']
        coordinates = (form.x1.data, form.y1.data,
                       form.x2.data, form.y2.data)
        prefix = time.time()
        file.filename = "app_%s_thumbnail_%i.png" % (app.id, prefix)
        container = "user_%s" % current_user.id
        uploader.upload_file(file,
                             container=container,
                             coordinates=coordinates)

        # Update thumbnail for app
        app.info['thumbnail'] = file.filename
        app.info['container'] = container
        db.session.commit()

    # Clean cache
    msg_1 = gettext('Application created!')
    flash('<i class="icon-ok"></i> ' + msg_1, 'success')
    flash('<i class="icon-bullhorn"></i> ' +
          gettext('You can check the ') +
          '<strong><a href="https://docs.pybossa.com">' +
          gettext('Guide and Documentation') +
          '</a></strong> ' +
          gettext('for adding tasks, a thumbnail, using PyBossa.JS, etc.'),
          'info')<commit_msg>Remove comments<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/>.

import time
from StringIO import StringIO
from flask import Blueprint, request, url_for, flash, redirect, abort, Response, current_app
from flask import render_template, make_response
from flask_wtf import Form
from wtforms import IntegerField, DecimalField, TextField, BooleanField, \
    SelectField, validators, TextAreaField, FileField
from wtforms.widgets import HiddenInput
from flask.ext.login import login_required, current_user
from flask.ext.babel import lazy_gettext, gettext
from werkzeug.exceptions import HTTPException
from sqlalchemy.sql import text

import pybossa.model as model
import pybossa.stats as stats
import pybossa.validator as pb_validator

from pybossa.core import db, uploader
from pybossa.cache import ONE_DAY, ONE_HOUR
from pybossa.model.app import App
from pybossa.model.task import Task
from pybossa.model.user import User
from pybossa.util import Pagination, UnicodeWriter, admin_required
from pybossa.auth import require
from pybossa.cache import apps as cached_apps
from pybossa.cache import categories as cached_cat
from pybossa.ckan import Ckan

import json
import importer
import presenter as presenter_module
import operator
import math
import requests

blueprint = Blueprint('app', __name__)

class AvatarUploadForm(Form):
    avatar = FileField(lazy_gettext('Avatar'), )
    x1 = IntegerField(label=None, widget=HiddenInput(), default=0)
    y1 = IntegerField(label=None, widget=HiddenInput(), default=0)
    x2 = IntegerField(label=None, widget=HiddenInput(), default=0)
    y2 = IntegerField(label=None, widget=HiddenInput(), default=0)


class AppForm(Form):
    id = IntegerField(label=None, widget=HiddenInput())
    name = TextField(lazy_gettext('Name'),
                     [validators.Required(),
                      pb_validator.Unique(db.session, model.app.App, model.app.App.name,
                                          message="Name is already taken.")])
    short_name = TextField(lazy_gettext('Short Name'),
                           [validators.Required(),
                            pb_validator.NotAllowedChars(),
                            pb_validator.Unique(
                                db.session, model.app.App, model.app.App.short_name,
                                message=lazy_gettext(
                                    "Short Name is already taken."))])
    description = TextField(lazy_gettext('Description'),
                            [validators.Required(
                                message=lazy_gettext(
                                    "You must provide a description."))])
    thumbnail = TextField(lazy_gettext('Icon Link'))
    allow_anonymous_contributors = SelectField(
        lazy_gettext('Allow Anonymous Contributors'),
        choices=[('True', lazy_gettext('Yes')),
                 ('False', lazy_gettext('No'))])
    category_id = SelectField(lazy_gettext('Category'), coerce=int)
    long_description = TextAreaField(lazy_gettext('Long Description'))
    hidden = BooleanField(lazy_gettext('Hide?'))
    avatar = FileField(lazy_gettext('Avatar'))
    x1 = IntegerField(label=None, widget=HiddenInput(), default=0)
    y1 = IntegerField(label=None, widget=HiddenInput(), default=0)
    x2 = IntegerField(label=None, widget=HiddenInput(), default=0)
    y2 = IntegerField(label=None, widget=HiddenInput(), default=0)


class TaskPresenterForm(Form):
    id = IntegerField(label=None, widget=HiddenInput())
    editor = TextAreaField('')


class TaskRedundancyForm(Form):
    n_answers = IntegerField(lazy_gettext('Redundancy'),
                             [validators.Required(),
                              validators.NumberRange(
                                  min=1, max=1000,
                                  message=lazy_gettext('Number of answers should be a \
                                                       value between 1 and 1,000'))])


class TaskPriorityForm(Form):
    task_ids = TextField(lazy_gettext('Task IDs'),
                         [validators.Required(),
                          pb_validator.CommaSeparatedIntegers()])

    priority_0 = DecimalField(lazy_gettext('Priority'),
                              [validators.NumberRange(
                                  min=0, max=1,
                                  message=lazy_gettext('Priority should be a \
                                                       value between 0.0 and 1.0'))])


class TaskSchedulerForm(Form):
    sched = SelectField(lazy_gettext('Task Scheduler'),
                        choices=[('default', lazy_gettext('Default')),
                                 ('breadth_first', lazy_gettext('Breadth First')),
                                 ('depth_first', lazy_gettext('Depth First')),
                                 ('random', lazy_gettext('Random'))])


class BlogpostForm(Form):
    id = IntegerField(label=None, widget=HiddenInput())
    title = TextField(lazy_gettext('Title'),
                     [validators.Required(message=lazy_gettext(
                                    "You must enter a title for the post."))])
    body = TextAreaField(lazy_gettext('Body'),
                           [validators.Required(message=lazy_gettext(
                                    "You must enter some text for the post."))])


def app_title(app, page_name):
    if not app:  # pragma: no cover
        return "Application not found"
    if page_name is None:
        return "Application: %s" % (app.name)
    return "Application: %s &middot; %s" % (app.name, page_name)


def app_by_shortname(short_name):
    app = cached_apps.get_app(short_name)
    if app.id:
        # Populate CACHE with the data of the app
        return (app,
                cached_apps.n_tasks(app.id),
                cached_apps.n_task_runs(app.id),
                cached_apps.overall_progress(app.id),
                cached_apps.last_activity(app.id))

    else:
        cached_apps.delete_app(short_name)
        return abort(404)


@blueprint.route('/', defaults={'page': 1})
@blueprint.route('/page/<int:page>/', defaults={'page': 1})
def redirect_old_featured(page):
    """DEPRECATED only to redirect old links"""
    return redirect(url_for('.index', page=page), 301)


@blueprint.route('/published/', defaults={'page': 1})
@blueprint.route('/published/<int:page>/', defaults={'page': 1})
def redirect_old_published(page):  # pragma: no cover
    """DEPRECATED only to redirect old links"""
    category = db.session.query(model.category.Category).first()
    return redirect(url_for('.app_cat_index', category=category.short_name, page=page), 301)


@blueprint.route('/draft/', defaults={'page': 1})
@blueprint.route('/draft/<int:page>/', defaults={'page': 1})
def redirect_old_draft(page):
    """DEPRECATED only to redirect old links"""
    return redirect(url_for('.draft', page=page), 301)


@blueprint.route('/category/featured/', defaults={'page': 1})
@blueprint.route('/category/featured/page/<int:page>/')
def index(page):
    """List apps in the system"""
    if cached_apps.n_featured() > 0:
        return app_index(page, cached_apps.get_featured, 'featured',
                         True, False)
    else:
        categories = cached_cat.get_all()
        cat_short_name = categories[0].short_name
        return redirect(url_for('.app_cat_index', category=cat_short_name))


def app_index(page, lookup, category, fallback, use_count):
    """Show apps of app_type"""

    per_page = current_app.config['APPS_PER_PAGE']

    apps, count = lookup(category, page, per_page)

    data = []
    for app in apps:
        data.append(dict(app=app, n_tasks=cached_apps.n_tasks(app['id']),
                         overall_progress=cached_apps.overall_progress(app['id']),
                         last_activity=app['last_activity'],
                         last_activity_raw=app['last_activity_raw'],
                         n_completed_tasks=cached_apps.n_completed_tasks(app['id']),
                         n_volunteers=cached_apps.n_volunteers(app['id'])))


    if fallback and not apps:  # pragma: no cover
        return redirect(url_for('.index'))

    pagination = Pagination(page, per_page, count)
    categories = cached_cat.get_all()
    # Check for pre-defined categories featured and draft
    featured_cat = model.category.Category(name='Featured',
                                  short_name='featured',
                                  description='Featured applications')
    if category == 'featured':
        active_cat = featured_cat
    elif category == 'draft':
        active_cat = model.category.Category(name='Draft',
                                    short_name='draft',
                                    description='Draft applications')
    else:
        active_cat = db.session.query(model.category.Category)\
                       .filter_by(short_name=category).first()

    # Check if we have to add the section Featured to local nav
    if cached_apps.n_featured() > 0:
        categories.insert(0, featured_cat)
    template_args = {
        "apps": data,
        "title": gettext("Applications"),
        "pagination": pagination,
        "active_cat": active_cat,
        "categories": categories}

    if use_count:
        template_args.update({"count": count})
    return render_template('/applications/index.html', **template_args)


@blueprint.route('/category/draft/', defaults={'page': 1})
@blueprint.route('/category/draft/page/<int:page>/')
@login_required
@admin_required
def draft(page):
    """Show the Draft apps"""
    return app_index(page, cached_apps.get_draft, 'draft',
                     False, True)


@blueprint.route('/category/<string:category>/', defaults={'page': 1})
@blueprint.route('/category/<string:category>/page/<int:page>/')
def app_cat_index(category, page):
    """Show Apps that belong to a given category"""
    return app_index(page, cached_apps.get, category, False, True)


@blueprint.route('/new', methods=['GET', 'POST'])
@login_required
def new():
    require.app.create()
    form = AppForm(request.form)
    categories = db.session.query(model.category.Category).all()
    form.category_id.choices = [(c.id, c.name) for c in categories]

    def respond(errors):
        return render_template('applications/new.html',
                               title=gettext("Create an Application"),
                               form=form, errors=errors)

    if request.method != 'POST':
        return respond(False)

    del form.id
    if not form.validate():
        flash(gettext('Please correct the errors'), 'error')
        return respond(True)

    info = {}

    app = model.app.App(name=form.name.data,
                    short_name=form.short_name.data,
                    description=form.description.data,
                    long_description=form.long_description.data,
                    category_id=form.category_id.data,
                    allow_anonymous_contributors=form.allow_anonymous_contributors.data,
                    hidden=int(form.hidden.data),
                    owner_id=current_user.id,
                    info=info)

    db.session.add(app)
    db.session.commit()
    # Upload the app
    if form.avatar.data:
        file = request.files['avatar']
        coordinates = (form.x1.data, form.y1.data,
                       form.x2.data, form.y2.data)
        prefix = time.time()
        file.filename = "app_%s_thumbnail_%i.png" % (app.id, prefix)
        container = "user_%s" % current_user.id
        uploader.upload_file(file,
                             container=container,
                             coordinates=coordinates)

        # Update thumbnail for app
        app.info['thumbnail'] = file.filename
        app.info['container'] = container
        db.session.commit()

    # Clean cache
    msg_1 = gettext('Application created!')
    flash('<i class="icon-ok"></i> ' + msg_1, 'success')
    flash('<i class="icon-bullhorn"></i> ' +
          gettext('You can check the ') +
          '<strong><a href="https://docs.pybossa.com">' +
          gettext('Guide and Documentation') +
          '</a></strong> ' +
          gettext('for adding tasks, a thumbnail, using PyBossa.JS, etc.'),
          'info')
{'fraction_non_alphanumeric': 0.11448408871745419, 'fraction_numerical': 0.005400192864030858, 'mean_word_length': 2.5149132321041217, 'pattern_counts': {'":': 12, '<': 37, '<?xml version=': 0, '>': 41, 'https://': 2, 'lorem ipsum': 0, 'www.': 2, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 48, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '333427', 'n_tokens_mistral': 7455, 'n_tokens_neox': 7178, 'n_words': 1693}