<commit_before># This file is part of PyBOSSA.
#
# 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 StringIO import StringIO
import requests
from flask import Blueprint, request, url_for, flash, redirect, abort, Response, current_app
from flask import render_template, make_response
from flaskext.wtf import Form, IntegerField, TextField, BooleanField, \
    SelectField, validators, HiddenInput, TextAreaField
from flaskext.login import login_required, current_user
from flaskext.babel import lazy_gettext
from werkzeug.exceptions import HTTPException

import pybossa.model as model
import pybossa.stats as stats

from pybossa.core import db
from pybossa.model import App, Task
from pybossa.util import Unique, Pagination, unicode_csv_reader, UnicodeWriter
from pybossa.auth import require
from pybossa.cache import apps as cached_apps

import json
import sys

blueprint = Blueprint('app', __name__)


class BulkImportException(Exception):
    pass


class AppForm(Form):
    id = IntegerField(label=None, widget=HiddenInput())
    name = TextField(lazy_gettext('Name'),
                     [validators.Required(),
                      Unique(db.session, model.App, model.App.name,
                             message="Name is already taken.")])
    short_name = TextField(lazy_gettext('Short Name'),
                           [validators.Required(),
                            Unique(db.session, model.App, model.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'))])
    long_description = TextAreaField(lazy_gettext('Long Description'))
    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'))],)
    hidden = BooleanField(lazy_gettext('Hide?'))


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


class BulkTaskCSVImportForm(Form):
    msg_required = lazy_gettext("You must provide a URL")
    msg_url = lazy_gettext("Oops! That's not a valid URL. You must provide a valid URL")
    csv_url = TextField(lazy_gettext('URL'),
                        [validators.Required(message=msg_required),
                         validators.URL(message=msg_url)])


class BulkTaskGDImportForm(Form):
    msg_required = lazy_gettext("You must provide a URL")
    msg_url = lazy_gettext("Oops! That's not a valid URL. You must provide a valid URL")
    googledocs_url = TextField(lazy_gettext('URL'),
                               [validators.Required(message=msg_required),
                                   validators.URL(message=msg_url)])


class BulkTaskEpiCollectPlusImportForm(Form):
    msg_required = lazy_gettext("You must provide an EpiCollect Plus project name")
    msg_form_required = lazy_gettext("You must provide a Form name for the project")
    epicollect_project = TextField(lazy_gettext('Project Name'),
                               [validators.Required(message=msg_required)])
    epicollect_form = TextField(lazy_gettext('Form name'),
                               [validators.Required(message=msg_required)])


@blueprint.route('/', defaults={'page': 1})
@blueprint.route('/page/<int:page>')
def index(page):
    """By default show the Featured apps"""
    if require.app.read():
        per_page = 5

        apps, count = cached_apps.get_featured(page, per_page)

        if apps:
            pagination = Pagination(page, per_page, count)
            return render_template('/applications/index.html',
                                   title=lazy_gettext("Applications"),
                                   apps=apps,
                                   pagination=pagination,
                                   app_type='app-featured')
        else:
            return redirect(url_for('.published'))
    else:
        abort(403)


@blueprint.route('/published', defaults={'page': 1})
@blueprint.route('/published/page/<int:page>')
def published(page):
    """Show the Published apps"""
    if require.app.read():
        per_page = 5

        apps, count = cached_apps.get_published(page, per_page)

        pagination = Pagination(page, per_page, count)
        return render_template('/applications/index.html',
                               title=lazy_gettext("Applications"),
                               apps=apps,
                               count=count,
                               pagination=pagination,
                               app_type='app-published')
    else:
        abort(403)


@blueprint.route('/draft', defaults={'page': 1})
@blueprint.route('/draft/page/<int:page>')
def draft(page):
    if require.app.read():
        per_page = 5

        apps, count = cached_apps.get_draft(page, per_page)

        pagination = Pagination(page, per_page, count)
        return render_template('/applications/index.html',
                               title=lazy_gettext("Applications"),
                               apps=apps,
                               count=count,
                               pagination=pagination,
                               app_type='app-draft')
    else:
        abort(403)


@blueprint.route('/new', methods=['GET', 'POST'])
@login_required
def new():
    errors = False
    if require.app.create():
        form = AppForm(request.form)
        if request.method == 'POST' and form.validate():
            info = {}
            # Add the info items
            if form.thumbnail.data:
                info['thumbnail'] = form.thumbnail.data
            if form.sched.data:
                info['sched'] = form.sched.data

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

            cached_apps.reset()
            db.session.add(app)
            db.session.commit()
            # Clean cache
            msg_1 = lazy_gettext('Application created!')
            flash('<i class="icon-ok"></i> ' + msg_1, 'success')
            flash('<i class="icon-bullhorn"></i> ' + lazy_gettext('You can check the ') +
                  '<strong><a href="https://docs.pybossa.com">' + lazy_gettext('Guide and '
                  ' Documentation') + '</a></strong> ' + lazy_gettext('for adding tasks, '
                  ' a thumbnail, using PyBossa.JS, etc.'), 'info')
            return redirect(url_for('.settings', short_name=app.short_name))
        if request.method == 'POST' and not form.validate():
            flash(lazy_gettext('Please correct the errors'), 'error')
            errors = True
        return render_template('applications/new.html',
                               title=lazy_gettext("Create an Application"),
                               form=form, errors=errors)
    else:
        abort(403)


@blueprint.route('/<short_name>/taskpresentereditor', methods=['GET', 'POST'])
@login_required
def task_presenter_editor(short_name):
    errors = False
    app = App.query.filter_by(short_name=short_name).first()

    if not app:
        abort(404)

    title = "Application: %s &middot; Task Presenter Editor" % app.name
    if not require.app.update(app):
        abort(403)

    form = TaskPresenterForm(request.form)
    if request.method == 'POST' and form.validate():
        app.info['task_presenter'] = form.editor.data
        db.session.add(app)
        db.session.commit()
        msg_1 = lazy_gettext('Task presenter added!')
        flash('<i class="icon-ok"></i> ' + msg_1, 'success')
        return redirect(url_for('.settings', short_name=app.short_name))

    if request.method == 'POST' and not form.validate():
        flash(lazy_gettext('Please correct the errors'), 'error')
        errors = True

    if request.method != 'GET':
        return

    if app.info.get('task_presenter'):
        form.editor.data = app.info['task_presenter']
    else:
        if request.args.get('template'):
            tmpl_uri = "applications/snippets/%s.html" \
                % request.args.get('template')
            tmpl = render_template(tmpl_uri, app=app)
            form.editor.data = tmpl
            msg = 'Your code will be <em>automagically</em> rendered in \
                      the <strong>preview section</strong>. Click in the \
                      preview button!'
            flash(lazy_gettext(msg), 'info')
        else:
            msg = '<strong>Note</strong> You will need to upload ' \
                'the tasks using the <a href="%s">' \
                'CSV importer</a> or download the app ' \
                'bundle and run the <strong>createTasks.py ' \
                '</strong> script in your ' \
                'computer' % url_for('app.import_task',
                                     short_name=app.short_name)
            flash(lazy_gettext(msg), 'info')
            return render_template(
                'applications/task_presenter_options.html',
                title=title,
                app=app)
    return render_template('applications/task_presenter_editor.html',
                           title=title,
                           form=form,
                           app=app,
                           errors=errors)


@blueprint.route('/<short_name>/delete', methods=['GET', 'POST'])
@login_required
def delete(short_name):
    app = App.query.filter_by(short_name=short_name).first()
    if app:
        title = "Application: %s &middot; Delete" % app.name
        if require.app.delete(app):
            if request.method == 'GET':
                return render_template('/applications/delete.html',
                                       title=title,
                                       app=app)
            else:
                # Clean cache
                cached_apps.clean(app.id)
                db.session.delete(app)
                db.session.commit()
                flash(lazy_gettext('Application deleted!'), 'success')
                return redirect(url_for('account.profile'))
        else:
            abort(403)
    else:
        abort(404)


@blueprint.route('/<short_name>/update', methods=['GET', 'POST'])
@login_required
def update(short_name):
    app = App.query.filter_by(short_name=short_name).first_or_404()
    if require.app.update(app):
        title = "Application: %s &middot; Update" % app.name
        if request.method == 'GET':
            form = AppForm(obj=app)
            form.populate_obj(app)
            if app.info.get('thumbnail'):
                form.thumbnail.data = app.info['thumbnail']
            if app.info.get('sched'):
                for s in form.sched.choices:
                    if app.info['sched'] == s[0]:
                        form.sched.data = s[0]
                        break

            return render_template('/applications/update.html',
                                   title=title,
                                   form=form,
                                   app=app)

        if request.method == 'POST':
            form = AppForm(request.form)
            if form.validate():
                if form.hidden.data:
                    hidden = 1<commit_msg>shortcut else branch<commit_after># This file is part of PyBOSSA.
#
# 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 StringIO import StringIO
import requests
from flask import Blueprint, request, url_for, flash, redirect, abort, Response, current_app
from flask import render_template, make_response
from flaskext.wtf import Form, IntegerField, TextField, BooleanField, \
    SelectField, validators, HiddenInput, TextAreaField
from flaskext.login import login_required, current_user
from flaskext.babel import lazy_gettext
from werkzeug.exceptions import HTTPException

import pybossa.model as model
import pybossa.stats as stats

from pybossa.core import db
from pybossa.model import App, Task
from pybossa.util import Unique, Pagination, unicode_csv_reader, UnicodeWriter
from pybossa.auth import require
from pybossa.cache import apps as cached_apps

import json
import sys

blueprint = Blueprint('app', __name__)


class BulkImportException(Exception):
    pass


class AppForm(Form):
    id = IntegerField(label=None, widget=HiddenInput())
    name = TextField(lazy_gettext('Name'),
                     [validators.Required(),
                      Unique(db.session, model.App, model.App.name,
                             message="Name is already taken.")])
    short_name = TextField(lazy_gettext('Short Name'),
                           [validators.Required(),
                            Unique(db.session, model.App, model.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'))])
    long_description = TextAreaField(lazy_gettext('Long Description'))
    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'))],)
    hidden = BooleanField(lazy_gettext('Hide?'))


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


class BulkTaskCSVImportForm(Form):
    msg_required = lazy_gettext("You must provide a URL")
    msg_url = lazy_gettext("Oops! That's not a valid URL. You must provide a valid URL")
    csv_url = TextField(lazy_gettext('URL'),
                        [validators.Required(message=msg_required),
                         validators.URL(message=msg_url)])


class BulkTaskGDImportForm(Form):
    msg_required = lazy_gettext("You must provide a URL")
    msg_url = lazy_gettext("Oops! That's not a valid URL. You must provide a valid URL")
    googledocs_url = TextField(lazy_gettext('URL'),
                               [validators.Required(message=msg_required),
                                   validators.URL(message=msg_url)])


class BulkTaskEpiCollectPlusImportForm(Form):
    msg_required = lazy_gettext("You must provide an EpiCollect Plus project name")
    msg_form_required = lazy_gettext("You must provide a Form name for the project")
    epicollect_project = TextField(lazy_gettext('Project Name'),
                               [validators.Required(message=msg_required)])
    epicollect_form = TextField(lazy_gettext('Form name'),
                               [validators.Required(message=msg_required)])


@blueprint.route('/', defaults={'page': 1})
@blueprint.route('/page/<int:page>')
def index(page):
    """By default show the Featured apps"""
    if require.app.read():
        per_page = 5

        apps, count = cached_apps.get_featured(page, per_page)

        if apps:
            pagination = Pagination(page, per_page, count)
            return render_template('/applications/index.html',
                                   title=lazy_gettext("Applications"),
                                   apps=apps,
                                   pagination=pagination,
                                   app_type='app-featured')
        else:
            return redirect(url_for('.published'))
    else:
        abort(403)


@blueprint.route('/published', defaults={'page': 1})
@blueprint.route('/published/page/<int:page>')
def published(page):
    """Show the Published apps"""
    if require.app.read():
        per_page = 5

        apps, count = cached_apps.get_published(page, per_page)

        pagination = Pagination(page, per_page, count)
        return render_template('/applications/index.html',
                               title=lazy_gettext("Applications"),
                               apps=apps,
                               count=count,
                               pagination=pagination,
                               app_type='app-published')
    else:
        abort(403)


@blueprint.route('/draft', defaults={'page': 1})
@blueprint.route('/draft/page/<int:page>')
def draft(page):
    if require.app.read():
        per_page = 5

        apps, count = cached_apps.get_draft(page, per_page)

        pagination = Pagination(page, per_page, count)
        return render_template('/applications/index.html',
                               title=lazy_gettext("Applications"),
                               apps=apps,
                               count=count,
                               pagination=pagination,
                               app_type='app-draft')
    else:
        abort(403)


@blueprint.route('/new', methods=['GET', 'POST'])
@login_required
def new():
    errors = False
    if require.app.create():
        form = AppForm(request.form)
        if request.method == 'POST' and form.validate():
            info = {}
            # Add the info items
            if form.thumbnail.data:
                info['thumbnail'] = form.thumbnail.data
            if form.sched.data:
                info['sched'] = form.sched.data

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

            cached_apps.reset()
            db.session.add(app)
            db.session.commit()
            # Clean cache
            msg_1 = lazy_gettext('Application created!')
            flash('<i class="icon-ok"></i> ' + msg_1, 'success')
            flash('<i class="icon-bullhorn"></i> ' + lazy_gettext('You can check the ') +
                  '<strong><a href="https://docs.pybossa.com">' + lazy_gettext('Guide and '
                  ' Documentation') + '</a></strong> ' + lazy_gettext('for adding tasks, '
                  ' a thumbnail, using PyBossa.JS, etc.'), 'info')
            return redirect(url_for('.settings', short_name=app.short_name))
        if request.method == 'POST' and not form.validate():
            flash(lazy_gettext('Please correct the errors'), 'error')
            errors = True
        return render_template('applications/new.html',
                               title=lazy_gettext("Create an Application"),
                               form=form, errors=errors)
    else:
        abort(403)


@blueprint.route('/<short_name>/taskpresentereditor', methods=['GET', 'POST'])
@login_required
def task_presenter_editor(short_name):
    errors = False
    app = App.query.filter_by(short_name=short_name).first()

    if not app:
        abort(404)

    title = "Application: %s &middot; Task Presenter Editor" % app.name
    if not require.app.update(app):
        abort(403)

    form = TaskPresenterForm(request.form)
    if request.method == 'POST' and form.validate():
        app.info['task_presenter'] = form.editor.data
        db.session.add(app)
        db.session.commit()
        msg_1 = lazy_gettext('Task presenter added!')
        flash('<i class="icon-ok"></i> ' + msg_1, 'success')
        return redirect(url_for('.settings', short_name=app.short_name))

    if request.method == 'POST' and not form.validate():
        flash(lazy_gettext('Please correct the errors'), 'error')
        errors = True

    if request.method != 'GET':
        return

    if app.info.get('task_presenter'):
        form.editor.data = app.info['task_presenter']
    else:
        if request.args.get('template'):
            tmpl_uri = "applications/snippets/%s.html" \
                % request.args.get('template')
            tmpl = render_template(tmpl_uri, app=app)
            form.editor.data = tmpl
            msg = 'Your code will be <em>automagically</em> rendered in \
                      the <strong>preview section</strong>. Click in the \
                      preview button!'
            flash(lazy_gettext(msg), 'info')
        else:
            msg = '<strong>Note</strong> You will need to upload ' \
                'the tasks using the <a href="%s">' \
                'CSV importer</a> or download the app ' \
                'bundle and run the <strong>createTasks.py ' \
                '</strong> script in your ' \
                'computer' % url_for('app.import_task',
                                     short_name=app.short_name)
            flash(lazy_gettext(msg), 'info')
            return render_template(
                'applications/task_presenter_options.html',
                title=title,
                app=app)
    return render_template('applications/task_presenter_editor.html',
                           title=title,
                           form=form,
                           app=app,
                           errors=errors)


@blueprint.route('/<short_name>/delete', methods=['GET', 'POST'])
@login_required
def delete(short_name):
    app = App.query.filter_by(short_name=short_name).first()
    if not app:
        abort(404)

    title = "Application: %s &middot; Delete" % app.name
    if require.app.delete(app):
        if request.method == 'GET':
            return render_template('/applications/delete.html',
                                   title=title,
                                   app=app)
        else:
            # Clean cache
            cached_apps.clean(app.id)
            db.session.delete(app)
            db.session.commit()
            flash(lazy_gettext('Application deleted!'), 'success')
            return redirect(url_for('account.profile'))
    else:
        abort(403)

@blueprint.route('/<short_name>/update', methods=['GET', 'POST'])
@login_required
def update(short_name):
    app = App.query.filter_by(short_name=short_name).first_or_404()
    if require.app.update(app):
        title = "Application: %s &middot; Update" % app.name
        if request.method == 'GET':
            form = AppForm(obj=app)
            form.populate_obj(app)
            if app.info.get('thumbnail'):
                form.thumbnail.data = app.info['thumbnail']
            if app.info.get('sched'):
                for s in form.sched.choices:
                    if app.info['sched'] == s[0]:
                        form.sched.data = s[0]
                        break

            return render_template('/applications/update.html',
                                   title=title,
                                   form=form,
                                   app=app)

        if request.method == 'POST':
            form = AppForm(request.form)
            if form.validate():
                if form.hidden.data:
                    hidden = 1
{'fraction_non_alphanumeric': 0.1101022462595239, 'fraction_numerical': 0.003237140262918953, 'mean_word_length': 1.9596915527514898, 'pattern_counts': {'":': 0, '<': 57, '<?xml version=': 0, '>': 57, 'https://': 2, 'lorem ipsum': 0, 'www.': 2, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 40, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '4305135', 'n_tokens_mistral': 6960, 'n_tokens_neox': 6716, 'n_words': 1549}