예제 #1
0
    def test_warn_project_excludes_completed_projects(self, clean_mock):
        """Test JOB email excludes completed projects."""
        from pybossa.core import mail
        with mail.record_messages() as outbox:
            date = '2010-10-22T11:02:00.000000'

            owner = UserFactory.create(consent=True, subscribed=True)
            project = ProjectFactory.create(updated=date, contacted=False,
                                            owner=owner)
            TaskFactory.create(created=date, project=project, state='completed')
            project_id = project.id
            project = project_repo.get(project_id)
            project.updated = date
            project_repo.update(project)

            project = ProjectFactory.create(updated=date, contacted=False,
                                            owner=owner)
            TaskFactory.create(created=date, project=project, state='ongoing')
            project_id = project.id
            project = project_repo.get(project_id)
            project.updated = date
            project_repo.update(project)

            warn_old_project_owners()
            assert len(outbox) == 1, outbox
            subject = 'Your PYBOSSA project: %s has been inactive' % project.name
            assert outbox[0].subject == subject
            err_msg = "project.contacted field should be True"
            assert project.contacted, err_msg
            err_msg = "project.published field should be False"
            assert project.published is False, err_msg
            err_msg = "cache of project should be cleaned"
            clean_mock.assert_called_with(project_id), err_msg
            err_msg = "The update date should be different"
            assert project.updated != date, err_msg
예제 #2
0
파일: jobs.py 프로젝트: alisheikh/pybossa
def warn_old_project_owners():
    """E-mail the project owners not updated in the last 3 months."""
    from pybossa.core import mail, project_repo
    from flask import current_app
    from flask.ext.mail import Message

    apps = get_non_updated_apps()

    with mail.connect() as conn:
        for a in apps:
            message = ("Dear %s,\
                       \
                       Your project %s has been inactive for the last 3 months.\
                       And we would like to inform you that if you need help \
                       with it, just contact us answering to this email.\
                       \
                       Otherwise, we will archive the project, removing it \
                       from the server. You have one month to upload any new \
                       tasks, add a new blog post, or engage new volunteers.\
                       \
                       If at the end the project is deleted, we will send you \
                       a ZIP file where you can download your project.\
                       \
                       All the best,\
                       \
                       The team.") % (a.owner.fullname, a.name)
            subject = ('Your %s project: %s has been inactive'
                       % (current_app.config.get('BRAND'), a.name))
            msg = Message(recipients=[a.owner.email_addr],
                          body=message,
                          subject=subject)
            conn.send(msg)
            a.contacted = True
            project_repo.update(a)
    return True
예제 #3
0
def create_quiz(short_name):
    (project, owner, n_tasks, n_task_runs, overall_progress, last_activity,
     n_results) = project_by_shortname(short_name)
    project_id = project.id
    project_button = add_custom_contrib_button_to(project, get_user_id_or_ip())
    feature_handler = ProFeatureHandler(current_app.config.get('PRO_FEATURES'))
    autoimporter_enabled = feature_handler.autoimporter_enabled_for(
        current_user)
    project_sanitized, owner_sanitized = sanitize_project_owner(
        project_button, owner, current_user)
    form = Add_quiz()
    if request.method == "POST" and form.validate():
        quiz_name = form.name.data
        q = quiz(name=quiz_name, project_id=project_id)
        db.session.add(q)
        db.session.commit()
        project.info.update({"is_quiz_provided": True})
        project_repo.update(project)
        session['quiz_name'] = quiz_name
        session['quiz_id'] = models.quiz.query.filter_by(
            name=quiz_name, project_id=project_id).first().quiz_id
        flash("Sucessfully created quiz", "success")
        return redirect(url_for('quiz.quiz_form', short_name=short_name))
    return render_template("add_quiz.html",
                           title="create quiz",
                           form=form,
                           project=project_sanitized,
                           pro_features=pro_features())
예제 #4
0
def edit_question(short_name):
    (project, owner, n_tasks, n_task_runs, overall_progress, last_activity,
     n_results) = project_by_shortname(short_name)
    pro = pro_features()
    project_button = add_custom_contrib_button_to(project, get_user_id_or_ip())
    feature_handler = ProFeatureHandler(current_app.config.get('PRO_FEATURES'))
    autoimporter_enabled = feature_handler.autoimporter_enabled_for(
        current_user)
    project_sanitized, owner_sanitized = sanitize_project_owner(
        project_button, owner, current_user)
    print project_button["contrib_button"]
    if (project_button["contrib_button"] == "draft"):
        if ("questionSet" not in project.info.keys()):
            project.info.update({
                "questionSet": {
                    "images": [],
                    "videos": [],
                    "audios": [],
                    "documents": []
                }
            })
            project_repo.update(project)

        session["edit_question"] = {
            "images": [],
            "documents": [],
            "videos": [],
            "audios": []
        }
        return redirect_content_type(
            url_for('.images_edit', short_name=short_name))

    else:
        return ("Sorry, You Edit the questions for draft project only.",
                "alert")
예제 #5
0
파일: jobs.py 프로젝트: fiorda/pybossa
def warn_old_project_owners():
    """E-mail the project owners not updated in the last 3 months."""
    from pybossa.core import mail, project_repo
    from pybossa.cache.projects import clean
    from flask.ext.mail import Message

    projects = get_non_updated_projects()

    with mail.connect() as conn:
        for project in projects:
            subject = ('Your %s project: %s has been inactive'
                       % (current_app.config.get('BRAND'), project.name))
            body = render_template('/account/email/inactive_project.md',
                                   project=project)
            html = render_template('/account/email/inactive_project.html',
                                   project=project)
            msg = Message(recipients=[project.owner.email_addr],
                          subject=subject,
                          body=body,
                          html=html)
            conn.send(msg)
            project.contacted = True
            project.published = False
            clean(project.id)
            project_repo.update(project)
    return True
예제 #6
0
파일: jobs.py 프로젝트: Genius38/pybossa-1
def warn_old_project_owners():
    """E-mail the project owners not updated in the last 3 months."""
    from pybossa.core import mail, project_repo
    from pybossa.cache.projects import clean
    from flask.ext.mail import Message

    projects = get_non_updated_projects()

    with mail.connect() as conn:
        for project in projects:
            subject = ('Your %s project: %s has been inactive' %
                       (current_app.config.get('BRAND'), project.name))
            body = render_template('/account/email/inactive_project.md',
                                   project=project)
            html = render_template('/account/email/inactive_project.html',
                                   project=project)
            msg = Message(recipients=[project.owner.email_addr],
                          subject=subject,
                          body=body,
                          html=html)
            conn.send(msg)
            project.contacted = True
            project.published = False
            clean(project.id)
            project_repo.update(project)
    return True
예제 #7
0
파일: jobs.py 프로젝트: idahoan/pybossa
def warn_old_project_owners():
    """E-mail the project owners not updated in the last 3 months."""
    from pybossa.core import mail, project_repo
    from flask import current_app
    from flask.ext.mail import Message

    apps = get_non_updated_apps()

    with mail.connect() as conn:
        for a in apps:
            message = ("Dear %s,\
                       \
                       Your project %s has been inactive for the last 3 months.\
                       And we would like to inform you that if you need help \
                       with it, just contact us answering to this email.\
                       \
                       Otherwise, we will archive the project, removing it \
                       from the server. You have one month to upload any new \
                       tasks, add a new blog post, or engage new volunteers.\
                       \
                       If at the end the project is deleted, we will send you \
                       a ZIP file where you can download your project.\
                       \
                       All the best,\
                       \
                       The team.") % (a.owner.fullname, a.name)
            subject = ('Your %s project: %s has been inactive'
                       % (current_app.config.get('BRAND'), a.name))
            msg = Message(recipients=[a.owner.email_addr],
                          body=message,
                          subject=subject)
            conn.send(msg)
            a.contacted = True
            project_repo.update(a)
    return True
예제 #8
0
    def test_warn_project_excludes_completed_projects(self, clean_mock):
        """Test JOB email excludes completed projects."""
        from pybossa.core import mail
        with mail.record_messages() as outbox:
            date = '2010-10-22T11:02:00.000000'

            project = ProjectFactory.create(updated=date, contacted=False)
            TaskFactory.create(created=date,
                               project=project,
                               state='completed')
            project_id = project.id
            project = project_repo.get(project_id)
            project.updated = date
            project_repo.update(project)

            project = ProjectFactory.create(updated=date, contacted=False)
            TaskFactory.create(created=date, project=project, state='ongoing')
            project_id = project.id
            project = project_repo.get(project_id)
            project.updated = date
            project_repo.update(project)

            warn_old_project_owners()
            assert len(outbox) == 1, outbox
            subject = 'Your PyBossa project: %s has been inactive' % project.name
            assert outbox[0].subject == subject
            err_msg = "project.contacted field should be True"
            assert project.contacted, err_msg
            err_msg = "project.published field should be False"
            assert project.published is False, err_msg
            err_msg = "cache of project should be cleaned"
            clean_mock.assert_called_with(project_id), err_msg
            err_msg = "The update date should be different"
            assert project.updated != date, err_msg
예제 #9
0
def store_questions(project):

    if(session.get("question") is not None):
        for i in ["images","videos","documents","audios"]:
            if len(session["question"][i])!=0:
                project.info["questionSet"][i]=session["question"][i]
            print session["question"]
    project_repo.update(project)
예제 #10
0
    def test_anonymous_user_cannot_read_auditlog(self):
        """Test anonymous users cannot read auditlogs"""

        app = AppFactory.create()
        app.hidden = 1
        project_repo.update(app)

        logs = auditlog_repo.filter_by(app_short_name=app.short_name)

        for log in logs:
            assert_raises(Unauthorized, getattr(require, 'auditlog').read, log)
예제 #11
0
    def test_admin_user_can_read_auditlog(self):
        """Test admin users can read auditlogs"""

        owner = UserFactory.create_batch(2)[1]
        app = AppFactory.create(owner=owner)
        app.hidden = 1
        project_repo.update(app)

        logs = auditlog_repo.filter_by(app_short_name=app.short_name)

        for log in logs:
            assert_not_raises(Exception, getattr(require, 'auditlog').read, log)
예제 #12
0
def audios_edit(short_name):
    (project, owner, n_tasks, n_task_runs,
     overall_progress, last_activity,
     n_results) = project_by_shortname(short_name)
    pro=pro_features()
    project_button = add_custom_contrib_button_to(project, get_user_id_or_ip())
    feature_handler = ProFeatureHandler(current_app.config.get('PRO_FEATURES'))
    autoimporter_enabled = feature_handler.autoimporter_enabled_for(current_user)
    project_sanitized, owner_sanitized = sanitize_project_owner(project_button, owner, current_user)
    if request.method == 'POST':
        session_count=len(session["edit_question"]["audios"]);
        session["edit_question"]["audios"]=[]
        for j in range(1,session_count+1):
            ans=[]
            type_q="normal"
            print str(j)+'_question'
            if(request.form.get(str(j)+'_question','')!=""):
                que=request.form.get(str(j)+'_question')
                if(request.form.get(str(j)+'_divcheckbox','')!=""):
                    type_q="mcqs"
                    if(request.form.get(str(j)+'_answer','')!=""):
                        ans=request.form.getlist(str(j)+'_answer')

                dictobj={"questionString":request.form.get(str(j)+'_question'),"answers":ans,"type":type_q}
                session["edit_question"]["audios"].append(dictobj)

        if(request.form.get('submit','')=="submit"):
            p=edit_draft_question(project)
            project.info["questionSet"]["audios"]=session["edit_question"]["audios"]
            project_repo.update(project)
            if(p!="-1"):
                return redirect_content_type(url_for('.'+p.lower()+"_edit",short_name=short_name))
            else:
                return redirect_content_type(url_for('.edit_success',short_name=short_name))
        else:
            type_q="normal"
            answer=[]
            if(request.form.get('question','')==""):
                flash("Question field is Empty","warning")
                return  render_template('audios_edit.html',project=project_sanitized,
                pro_features=pro)
            if(request.form.get('checkbox','')!=""):
                if(request.form.getlist('answer')[0]=="" or request.form.getlist('answer')[1]==""):
                    flash("Atleast 2 answers are required","warning")
                    return  render_template('audios_edit.html',project=project_sanitized,
                    pro_features=pro)
                else:
                    type_q="mcqs"
                    answer=request.form.getlist('answer')
            dictobj={"questionString":request.form.get('question'),"answers":answer,"type":type_q}
            session["edit_question"]["audios"].append(dictobj)

    return  render_template('audios_edit.html',project=project_sanitized,pro_features=pro) #we are going to tags.html
예제 #13
0
    def test_pro_user_can_read_auditlog(self):
        """Test pro users can read auditlogs"""

        owner = UserFactory.create_batch(2, pro=True)[1]
        app = AppFactory.create(owner=owner)
        app.hidden = 1
        project_repo.update(app)

        logs = auditlog_repo.filter_by(app_short_name=app.short_name)

        assert self.mock_authenticated.id == app.owner_id

        for log in logs:
            assert_not_raises(Exception, getattr(require, 'auditlog').read, log)
예제 #14
0
def upload_task(short_name):
        (project, owner, n_tasks, n_task_runs,
         overall_progress, last_activity,
         n_results) = project_by_shortname(short_name)
        pro=pro_features()
        project_button = add_custom_contrib_button_to(project, get_user_id_or_ip())

        feature_handler = ProFeatureHandler(current_app.config.get('PRO_FEATURES'))
        autoimporter_enabled = feature_handler.autoimporter_enabled_for(current_user)
        project_sanitized, owner_sanitized = sanitize_project_owner(project_button, owner, current_user)
        if request.method=='POST':
            upload_form=TaskUpload()
            if upload_form.validate_on_submit():
                _file=request.files['avatar']
                #extract_files_local(parent_path+"/uploads"+CONTAINER,_file.filename)
                if _file and allowed_file(_file.filename):
                    _file.save(os.path.join((parent_path+'/uploads/'+CONTAINER) , _file.filename))
                    if(check_file_size(parent_path+'/uploads/'+CONTAINER+"/"+_file.filename)):
                        global zipobj
                        zipobj=extract_files_local((parent_path+"/uploads/"+CONTAINER),_file.filename,project.id)
                        session["zzz"]=zipobj["zzz"]
                        zipobj.pop("zzz",None)
                        if "directory_names" not in project.info.keys():
                            project.info.update({"directory_names":[]})
                        project.info["directory_names"].append(session["zzz"])
                        project_repo.update(project)
                        #add_task(project.id,zipobj["zzz"])
                        return redirect_content_type(url_for('.select_type',
                                                             short_name=short_name))
                    else:
                        if os.path.exists(parent_path+'/uploads/'+CONTAINER+"/"+_file.filename):
                            os.remove(parent_path+'/uploads/'+CONTAINER+"/"+_file.filename)
                        flash('File Size should be less than 5 MB');
            else:
                flash(gettext('Please upload the file'),'warning')

        upload_form =TaskUpload()
        response =dict(template='/upload_form.html',
                       upload_form=upload_form,
                       project=project_sanitized,
                       pro_features=pro
                       )

        return handle_content_type(response)
예제 #15
0
파일: admin.py 프로젝트: tompollard/pybossa
def featured(project_id=None):
    """List featured projects of PYBOSSA."""
    try:
        if request.method == 'GET':
            categories = cached_cat.get_all()
            projects = {}
            for c in categories:
                n_projects = cached_projects.n_count(category=c.short_name)
                projects[c.short_name] = cached_projects.get(
                    category=c.short_name,
                    page=1,
                    per_page=n_projects)
            response = dict(template = '/admin/projects.html',
                            projects=projects,
                            categories=categories,
                            form=dict(csrf=generate_csrf()))
            return handle_content_type(response)
        else:
            project = project_repo.get(project_id)
            if project:
                ensure_authorized_to('update', project)
                if request.method == 'POST':
                    if project.featured is True:
                        msg = "Project.id %s already featured" % project_id
                        return format_error(msg, 415)
                    cached_projects.reset()
                    project.featured = True
                    project_repo.update(project)
                    return json.dumps(project.dictize())

                if request.method == 'DELETE':
                    if project.featured is False:
                        msg = 'Project.id %s is not featured' % project_id
                        return format_error(msg, 415)
                    cached_projects.reset()
                    project.featured = False
                    project_repo.update(project)
                    return json.dumps(project.dictize())
            else:
                msg = 'Project.id %s not found' % project_id
                return format_error(msg, 404)
    except Exception as e:  # pragma: no cover
        current_app.logger.error(e)
        return abort(500)
예제 #16
0
파일: admin.py 프로젝트: fiorda/pybossa
def featured(project_id=None):
    """List featured projects of PYBOSSA."""
    try:
        if request.method == 'GET':
            categories = cached_cat.get_all()
            projects = {}
            for c in categories:
                n_projects = cached_projects.n_count(category=c.short_name)
                projects[c.short_name] = cached_projects.get(
                    category=c.short_name,
                    page=1,
                    per_page=n_projects)
            response = dict(template = '/admin/projects.html',
                            projects=projects,
                            categories=categories,
                            form=dict(csrf=generate_csrf()))
            return handle_content_type(response)
        else:
            project = project_repo.get(project_id)
            if project:
                ensure_authorized_to('update', project)
                if request.method == 'POST':
                    if project.featured is True:
                        msg = "Project.id %s already featured" % project_id
                        return format_error(msg, 415)
                    cached_projects.reset()
                    project.featured = True
                    project_repo.update(project)
                    return json.dumps(project.dictize())

                if request.method == 'DELETE':
                    if project.featured is False:
                        msg = 'Project.id %s is not featured' % project_id
                        return format_error(msg, 415)
                    cached_projects.reset()
                    project.featured = False
                    project_repo.update(project)
                    return json.dumps(project.dictize())
            else:
                msg = 'Project.id %s not found' % project_id
                return format_error(msg, 404)
    except Exception as e:  # pragma: no cover
        current_app.logger.error(e)
        return abort(500)
예제 #17
0
파일: admin.py 프로젝트: idahoan/pybossa
def featured(app_id=None):
    """List featured apps of PyBossa"""
    try:
        if request.method == 'GET':
            categories = cached_cat.get_all()
            apps = {}
            for c in categories:
                n_apps = cached_apps.n_count(category=c.short_name)
                apps[c.short_name] = 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 = project_repo.get(app_id)
            if app:
                require.app.update(app)
                if request.method == 'POST':
                    if app.featured is True:
                        msg = "App.id %s already featured" % app_id
                        return format_error(msg, 415)
                    cached_apps.reset()
                    app.featured = True
                    project_repo.update(app)
                    return json.dumps(app.dictize())

                if request.method == 'DELETE':
                    if app.featured is False:
                        msg = 'App.id %s is not featured' % app_id
                        return format_error(msg, 415)
                    cached_apps.reset()
                    app.featured = False
                    project_repo.update(app)
                    return json.dumps(app.dictize())
            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)
예제 #18
0
파일: jobs.py 프로젝트: 97amarnathk/pybossa
def create_onesignal_app(project_id):
    """Create onesignal app."""
    from flask import url_for
    from pybossa.core import project_repo
    auth_key = current_app.config.get('ONESIGNAL_AUTH_KEY')
    if auth_key:
        project = project_repo.get(project_id)
        chrome_web_origin = url_for('project.details',
                                    short_name=project.short_name,
                                    _external=True)
        chrome_web_default_notification_icon = project.info.get('thumbnail_url')
        client = PybossaOneSignal(auth_key=auth_key)
        res = client.create_app(project.short_name,
                                chrome_web_origin,
                                chrome_web_default_notification_icon)
        
        if res[0] == 200:
            project.info['onesignal'] = res[2]
            project.info['onesignal_app_id'] = res[2]['id']
            project_repo.update(project)
        return res
예제 #19
0
파일: admin.py 프로젝트: alisheikh/pybossa
def featured(app_id=None):
    """List featured apps of PyBossa"""
    try:
        if request.method == 'GET':
            categories = cached_cat.get_all()
            apps = {}
            for c in categories:
                n_apps = cached_apps.n_count(category=c.short_name)
                apps[c.short_name] = 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 = project_repo.get(app_id)
            if app:
                require.app.update(app)
                if request.method == 'POST':
                    if app.featured is True:
                        msg = "App.id %s already featured" % app_id
                        return format_error(msg, 415)
                    cached_apps.reset()
                    app.featured = True
                    project_repo.update(app)
                    return json.dumps(app.dictize())

                if request.method == 'DELETE':
                    if app.featured is False:
                        msg = 'App.id %s is not featured' % app_id
                        return format_error(msg, 415)
                    cached_apps.reset()
                    app.featured = False
                    project_repo.update(app)
                    return json.dumps(app.dictize())
            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)
예제 #20
0
def draft_project(project):
    if(session.get("question") is not None):
        print "in draft"
        print session["question"]
    else:
        print "session is None"

    if "questionSet" not in project.info.keys():
        project.info.update({"questionSet":{"images":[],"videos":[],"documents":[],"audios":[]}})
        project_repo.update(project)
    if "importer_type" not in project.info.keys():
        project.info.update({"importer_type":"frg"})
        project_repo.update(project)
    if session.get('question') is None:
        session["question"]={"images":[],"videos":[],"audios":[],"documents":[]}
    for i in list_container:
        if len(project.info["questionSet"][i.lower()])==0 :
            b=list_container.index(i)
            del list_container[b]
            return i.lower()
        else:
            global previous_data
            previous_data.append(i)
    return "-1"
예제 #21
0
def import_repo(short_name):
    """Import a project from a GitHub repo."""
    project = project_repo.get_by_shortname(short_name)
    if not project:  # pragma: no cover
        abort(404)
    ensure_authorized_to('update', project)

    github_url = request.args.get('github_url')
    try:
        gh_repo = GitHubRepo(github_url)
    except GitHubURLError as e:
        flash(str(e), 'error')
        return redirect(url_for('.sync', short_name=project.short_name))

    gh_repo.load_contents()
    try:
        gh_repo.validate()
    except InvalidPybossaProjectError as e:
        flash(str(e), 'error')
        return redirect(url_for('.sync', short_name=project.short_name))

    form = GitHubProjectForm(request.form)
    project_json = gh_repo.get_project_json()
    _populate_form(form, gh_repo.contents, project_json)
    categories = project_repo.get_all_categories()

    if request.method == 'POST' and form.validate():
        info = json.loads(form.additional_properties.data)
        original_short_name = project_json['short_name']
        if form.tutorial.data:
            resp = github.get(form.tutorial.data)
            info['tutorial'] = resp.content.replace(original_short_name,
                                                    project.short_name)
        if form.task_presenter.data:
            resp = github.get(form.task_presenter.data)
            info['task_presenter'] = resp.content.replace(original_short_name,
                                                          project.short_name)
        if form.results.data:
            resp = github.get(form.results.data)
            info['results'] = resp.content.replace(original_short_name,
                                                   project.short_name)
        long_description = None
        if form.long_description.data:
            resp = github.get(form.long_description.data)
            long_description = resp.content

        old_project = Project(**project.dictize())
        project.description = form.description.data
        project.long_description = long_description
        project.category_id = form.category_id.data
        project.webhook = form.webhook.data
        project.info = info

        if form.thumbnail.data:
            data = github.get(form.thumbnail.data).content
            prefix = time.time()
            filename = "project_%s_thumbnail_%i.png" % (project.id, prefix)
            container = "user_%s" % current_user.id
            _download(filename, container, data)
            if project.info.get("thumbnail"):
                uploader.delete_file(project.info["thumbnail"], container)
            project.info['container'] = container
            project.info['thumbnail'] = filename
        try:
            project_repo.update(project)
        except sqlalchemy.exc.DataError as e:  # pragma: no cover
            flash('''DataError: {0} <br><br>Please check the files being
                  imported from GitHub'''.format(e.orig), 'danger')
            return redirect(url_for('.sync', short_name=project.short_name))

        auditlogger.add_log_entry(old_project, project, current_user)
        cached_cat.reset()
        cached_projects.get_project(project.short_name)
        flash(gettext('Project updated!'), 'success')
        return redirect(url_for('project.tasks',
                                short_name=project.short_name))

    elif request.method == 'POST':  # pragma: no cover
        flash(gettext('Please correct the errors'), 'error')

    else:
        form.process()
        form.description.data = project_json.get('description', '')
        form.webhook.data = project_json.get('webhook', '')

        reserved_keys = ['name', 'short_name', 'description', 'webhook',
                         'category_id']
        for k in reserved_keys:
            project_json.pop(k, None)
        form.additional_properties.data = json.dumps(project_json)

    return render_template('projects/github/import.html', form=form,
                           github_url=github_url, project=project)