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
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
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())
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")
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
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
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)
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)
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)
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
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)
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)
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)
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)
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
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"
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)