def categories(): """List Categories""" try: if request.method == 'GET': require.category.read() form = CategoryForm() if request.method == 'POST': require.category.create() form = CategoryForm(request.form) if form.validate(): slug = form.name.data.lower().replace(" ", "") category = model.Category(name=form.name.data, short_name=slug, description=form.description.data) db.session.add(category) db.session.commit() cached_cat.reset() msg = gettext("Category added") flash(msg, 'success') else: flash(gettext('Please correct the errors'), 'error') categories = cached_cat.get_all() n_apps_per_category = dict() for c in categories: n_apps_per_category[c.short_name] = cached_apps.n_count( c.short_name) return render_template('admin/categories.html', title=gettext('Categories'), categories=categories, n_apps_per_category=n_apps_per_category, form=form) except Exception as e: # pragma: no cover current_app.logger.error(e) return abort(500)
def del_category(id): """Delete a category.""" try: category = project_repo.get_category(id) if category: if len(cached_cat.get_all()) > 1: ensure_authorized_to('delete', category) if request.method == 'GET': response = dict(template='admin/del_category.html', title=gettext('Delete Category'), category=category, form=dict(csrf=generate_csrf())) return handle_content_type(response) if request.method == 'POST': project_repo.delete_category(category) msg = gettext("Category deleted") flash(msg, 'success') cached_cat.reset() return redirect_content_type(url_for(".categories")) else: msg = gettext('Sorry, it is not possible to delete the only' ' available category. You can modify it, ' ' click the edit button') flash(msg, 'warning') return redirect_content_type(url_for('.categories')) else: abort(404) except HTTPException: raise except Exception as e: # pragma: no cover current_app.logger.error(e) return abort(500)
def app_index(page, lookup, category, fallback, use_count): """Show apps of app_type""" per_page = 5 # @FC to come back to project homepage from the application detail if 'cat_byapp_' in category: category = get_app_category(category.replace("cat_byapp_", "")) # @FC apps, count = lookup(category, page, per_page) data = [] #for app in apps: # if 'tutorial' in app['short_name']: # data.append(dict(app=app, n_tasks=cached_apps.n_tasks(app['id']), # overall_progress=cached_apps.overall_progress(app['id']), # last_activity=cached_apps.last_activity(app['id']))) for app in apps: if 'tutorial' not in app['short_name']: data.append(dict(app=app, n_tasks=cached_apps.n_tasks(app['id']), overall_progress=cached_apps.overall_progress(app['id']), last_activity=cached_apps.last_activity(app['id']))) if fallback and not apps: return redirect(url_for('.published')) pagination = Pagination(page, per_page, count) categories = cached_cat.get_all() # Check for pre-defined categories featured and draft featured_cat = model.Category(name='Featured', short_name='featured', description='Featured applications') if category == 'featured': active_cat = featured_cat elif category == 'draft': active_cat = model.Category(name='Draft', short_name='draft', description='Draft applications') else: active_cat = db.session.query(model.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, "n_apps_per_category": None, "categories": categories} n_apps_per_category = dict() for c in categories: n_apps_per_category[c.short_name] = cached_apps.n_count(c.short_name) template_args['n_apps_per_category'] = n_apps_per_category if use_count: template_args.update({"count": count}) return render_template('/applications/index.html', **template_args)
def del_category(id): """Deletes a category""" try: category = db.session.query(model.Category).get(id) if category: if len(cached_cat.get_all()) > 1: require.category.delete(category) if request.method == 'GET': return render_template('admin/del_category.html', title=lazy_gettext('Delete Category'), category=category) if request.method == 'POST': db.session.delete(category) db.session.commit() msg = lazy_gettext("Category deleted") flash(msg, 'success') cached_cat.reset() return redirect(url_for(".categories")) else: msg = lazy_gettext('Sorry, it is not possible to delete the only \ available category. You can modify it, click the \ edit button') flash(msg, 'warning') return redirect(url_for('.categories')) else: return abort(404) except HTTPException: return abort(403) except Exception as e: current_app.logger.error(e) return abort(500)
def del_category(id): """Deletes a category""" try: category = db.session.query(model.Category).get(id) if category: if len(cached_cat.get_all()) > 1: require.category.delete(category) if request.method == 'GET': return render_template('admin/del_category.html', title=gettext('Delete Category'), category=category) if request.method == 'POST': db.session.delete(category) db.session.commit() msg = gettext("Category deleted") flash(msg, 'success') cached_cat.reset() return redirect(url_for(".categories")) else: msg = gettext('Sorry, it is not possible to delete the only \ available category. You can modify it, click the \ edit button') flash(msg, 'warning') return redirect(url_for('.categories')) else: return abort(404) except HTTPException: return abort(403) except Exception as e: current_app.logger.error(e) return abort(500)
def categories(): """List Categories""" try: if request.method == 'GET': require.category.read() form = CategoryForm() if request.method == 'POST': require.category.create() form = CategoryForm(request.form) if form.validate(): slug = form.name.data.lower().replace(" ", "") category = model.category.Category(name=form.name.data, short_name=slug, description=form.description.data) db.session.add(category) db.session.commit() cached_cat.reset() msg = gettext("Category added") flash(msg, 'success') else: flash(gettext('Please correct the errors'), 'error') categories = cached_cat.get_all() n_apps_per_category = dict() for c in categories: n_apps_per_category[c.short_name] = cached_apps.n_count(c.short_name) return render_template('admin/categories.html', title=gettext('Categories'), categories=categories, n_apps_per_category=n_apps_per_category, form=form) except Exception as e: # pragma: no cover current_app.logger.error(e) return abort(500)
def categories(): """List Categories.""" try: if request.method == 'GET': ensure_authorized_to('read', Category) form = CategoryForm() if request.method == 'POST': ensure_authorized_to('create', Category) form = CategoryForm(request.form) del form.id if form.validate(): slug = form.name.data.lower().replace(" ", "") category = Category(name=form.name.data, short_name=slug, description=form.description.data) project_repo.save_category(category) cached_cat.reset() msg = gettext("Category added") flash(msg, 'success') else: flash(gettext('Please correct the errors'), 'error') categories = cached_cat.get_all() n_projects_per_category = dict() for c in categories: n_projects_per_category[c.short_name] = \ cached_projects.n_count(c.short_name) return render_template('admin/categories.html', title=gettext('Categories'), categories=categories, n_projects_per_category=n_projects_per_category, form=form) except Exception as e: # pragma: no cover current_app.logger.error(e) return abort(500)
def del_category(id): """Delete a category.""" try: category = project_repo.get_category(id) if category: if len(cached_cat.get_all()) > 1: ensure_authorized_to('delete', category) if request.method == 'GET': return render_template('admin/del_category.html', title=gettext('Delete Category'), category=category) if request.method == 'POST': project_repo.delete_category(category) msg = gettext("Category deleted") flash(msg, 'success') cached_cat.reset() return redirect(url_for(".categories")) else: msg = gettext('Sorry, it is not possible to delete the only' ' available category. You can modify it, ' ' click the edit button') flash(msg, 'warning') return redirect(url_for('.categories')) else: abort(404) except HTTPException: raise except Exception as e: # pragma: no cover current_app.logger.error(e) return abort(500)
def home(): """ Render home page with the cached apps and users""" d = {'featured': cached_apps.get_featured_front_page(), 'top_apps': cached_apps.get_top(), 'top_users': None, 'categories': None, 'apps': None, 'n_apps_per_category': None} if app.config['ENFORCE_PRIVACY'] and current_user.is_authenticated(): if current_user.admin: d['top_users'] = cached_users.get_top() if not app.config['ENFORCE_PRIVACY']: d['top_users'] = cached_users.get_top() # @FC categories = cached_cat.get_all() n_apps_per_category = dict() apps = dict() for c in categories: n_apps_per_category[c.short_name] = cached_apps.n_count(c.short_name) apps[c.short_name],count = cached_apps.get(c.short_name,1,1) d['categories'] = categories d['n_apps_per_category'] = n_apps_per_category d['apps'] = apps # Current user Survey System if current_user.is_authenticated(): sql = text('''SELECT COUNT(task_run.id) AS task_run FROM task_run WHERE :cur_user_id=task_run.user_id''') results = db.engine.execute(sql,cur_user_id=current_user.id) for row in results: num_run_task=row.task_run if current_user.is_authenticated() and current_user.survey_check!= "None" and current_user.survey_check == "2": if num_run_task>=30: d['survey_three'] = True new_profile = model.User(id=current_user.id, survey_check="3") db.session.query(model.User).filter(model.User.id == current_user.id).first() db.session.merge(new_profile) db.session.commit() cached_users.delete_user_summary(current_user.name) elif current_user.is_authenticated() and current_user.survey_check!= "None" and current_user.survey_check == "1": if num_run_task>=1: d['survey_two'] = True new_profile = model.User(id=current_user.id, survey_check="2") db.session.query(model.User).filter(model.User.id == current_user.id).first() db.session.merge(new_profile) db.session.commit() cached_users.delete_user_summary(current_user.name) elif current_user.is_authenticated() and current_user.survey_check!= "None" and current_user.survey_check == "0": d['survey_one'] = True new_profile = model.User(id=current_user.id, survey_check="1") db.session.query(model.User).filter(model.User.id == current_user.id).first() db.session.merge(new_profile) db.session.commit() cached_users.delete_user_summary(current_user.name) else: d['survey_one'] = False # @FC return render_template('/home/index.html', **d)
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 index(): """List admin actions.""" 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) return render_template('/admin/index.html', projects=projects, categories=categories)
def featured(app_id=None): """List featured apps of PyBossa""" try: categories = cached_cat.get_all() if request.method == 'GET': apps = {} for c in categories: n_apps = cached_apps.n_count(category=c.short_name) apps[c.short_name], n_apps = cached_apps.get(category=c.short_name, page=1, per_page=n_apps) return render_template('/admin/applications.html', apps=apps, categories=categories) elif app_id: if request.method == 'POST': cached_apps.reset() f = model.Featured() f.app_id = app_id app = db.session.query(model.App).get(app_id) require.app.update(app) # Check if the app is already in this table tmp = db.session.query(model.Featured)\ .filter(model.Featured.app_id == app_id)\ .first() if (tmp is None): db.session.add(f) db.session.commit() return json.dumps(f.dictize()) else: msg = "App.id %s alreay in Featured table" % app_id return format_error(msg, 415) if request.method == 'DELETE': cached_apps.reset() f = db.session.query(model.Featured)\ .filter(model.Featured.app_id == app_id)\ .first() if (f): db.session.delete(f) db.session.commit() return "", 204 else: msg = 'App.id %s is not in Featured table' % app_id return format_error(msg, 404) else: msg = ('App.id is missing for %s action in featured method' % request.method) return format_error(msg, 415) except HTTPException: return abort(403) except Exception as e: current_app.logger.error(e) return abort(500)
def app_index(page, lookup, category, fallback, use_count): """Show apps of app_type""" per_page = 5 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'])) 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(name='Featured', short_name='featured', description='Featured applications') if category == 'featured': active_cat = featured_cat elif category == 'draft': active_cat = model.Category(name='Draft', short_name='draft', description='Draft applications') else: active_cat = db.session.query(model.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)
def index(): """Return the Data page.""" 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) for p in projects[c.short_name]: p['n_task_runs'] = cached_projects.n_task_runs(p['id']) p['n_results'] = cached_projects.n_results(p['id']) return render_template('/index.html', projects=projects, categories=categories, title="Data")
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() if len(categories) > 0: cat_short_name = categories[0].short_name else: cat = db.session.query(model.Category).first() if cat: cat_short_name = cat.short_name else: cat_short_name = "algo" 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 = 5 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'])) 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(name='Featured', short_name='featured', description='Featured applications') if category == 'featured': active_cat = featured_cat elif category == 'draft': active_cat = model.Category(name='Draft', short_name='draft', description='Draft applications') else: active_cat = db.session.query(model.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)
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 = db.session.query(model.app.App).get(app_id) if app: require.app.update(app) if request.method == 'POST': cached_apps.reset() if not app.featured: app.featured = True db.session.add(app) db.session.commit() return json.dumps(app.dictize()) else: msg = "App.id %s already featured" % app_id return format_error(msg, 415) if request.method == 'DELETE': cached_apps.reset() if app.featured: app.featured = False db.session.add(app) db.session.commit() return json.dumps(app.dictize()) else: msg = 'App.id %s is not featured' % app_id return format_error(msg, 415) 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 home(): """ Render home page with the cached apps and users""" d = {'featured': cached_apps.get_featured_front_page(), 'top_apps': cached_apps.get_top(), 'top_users': None, 'categories': None, 'apps': None, 'n_apps_per_category': None} if app.config['ENFORCE_PRIVACY'] and current_user.is_authenticated(): if current_user.admin: d['top_users'] = cached_users.get_top() if not app.config['ENFORCE_PRIVACY']: d['top_users'] = cached_users.get_top() # @FC categories = cached_cat.get_all() n_apps_per_category = dict() apps = dict() for c in categories: n_apps_per_category[c.short_name] = cached_apps.n_count(c.short_name) apps[c.short_name],count = cached_apps.get(c.short_name,1,1) d['categories'] = categories d['n_apps_per_category'] = n_apps_per_category d['apps'] = apps # Current user Survey System print current_user if current_user.is_authenticated(): # Check if survey_check is None # That is the case of a first time registration if current_user.survey_check == "None" : return redirect(url_for('survey_check')) if current_user.survey_check == "YES" : sql = text('''SELECT COUNT(task_run.id) AS task_run FROM task_run WHERE :cur_user_id=task_run.user_id''') results = db.engine.execute(sql,cur_user_id=current_user.id) num_run_task = 0 for row in results: num_run_task = row.task_run print "Number of tasks run : ",num_run_task if num_run_task > 30: return render_template('/survey_check/survey_check_complete.html', **d) # @FC return render_template('/home/index.html', **d)
def app_index(page, lookup, category, fallback, use_count): """Show apps of app_type""" if not require.app.read(): abort(403) per_page = 5 apps, count = lookup(category, page, per_page) if fallback and not apps: return redirect(url_for('.published')) pagination = Pagination(page, per_page, count) categories = cached_cat.get_all() # Check for pre-defined categories featured and draft featured_cat = model.Category(name='Featured', short_name='featured', description='Featured applications') if category == 'featured': active_cat = featured_cat elif category == 'draft': active_cat = model.Category(name='Draft', short_name='draft', description='Draft applications') else: active_cat = db.session.query(model.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": apps, "title": lazy_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)
def _populate_form(form, repo_contents, project_json): """Populate the import form using data from a GitHub repo.""" def add_choices(field, exts, default): field.choices = [('', 'None')] valid = {k: v for k, v in repo_contents.items() if any(k.endswith(ext) for ext in exts)} for k, v in valid.items(): field.choices.append((v['download_url'], k)) if v['name'] == default: field.default = v['download_url'] categories = cached_cat.get_all() form.category_id.choices = [(c.id, c.name) for c in categories] form.category_id.default = project_json.get('category_id', categories[0].id) add_choices(form.tutorial, ['.html'], 'tutorial.html') add_choices(form.task_presenter, ['.html'], 'template.html') add_choices(form.results, ['.html'], 'results.html') add_choices(form.long_description, ['.md'], 'long_description.md') add_choices(form.thumbnail, ['.png', '.jpg', 'jpeg'], 'thumbnail.png')
def app_index(page, lookup, category, fallback, use_count): """Show apps of app_type""" if not require.app.read(): abort(403) per_page = 5 apps, count = lookup(category, page, per_page) if fallback and not apps: return redirect(url_for('.published')) pagination = Pagination(page, per_page, count) categories = cached_cat.get_all() # Check for pre-defined categories featured and draft featured_cat = model.Category(name='Featured', short_name='featured', description='Featured applications') if category == 'featured': active_cat = featured_cat elif category == 'draft': active_cat = model.Category(name='Draft', short_name='draft', description='Draft applications') else: active_cat = db.session.query(model.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": apps, "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)
def update(short_name): app = app_by_shortname(short_name) def handle_valid_form(form): hidden = int(form.hidden.data) new_info = {} # Add the info items app = app_by_shortname(short_name) if form.thumbnail.data: new_info['thumbnail'] = form.thumbnail.data #if form.sched.data: # new_info['sched'] = form.sched.data # Merge info object info = dict(app.info.items() + new_info.items()) new_application = model.App( id=form.id.data, name=form.name.data, short_name=form.short_name.data, description=form.description.data, long_description=form.long_description.data, hidden=hidden, info=info, owner_id=app.owner_id, allow_anonymous_contributors=form.allow_anonymous_contributors.data, category_id=form.category_id.data) app = app_by_shortname(short_name) db.session.merge(new_application) db.session.commit() cached_apps.reset() cached_cat.reset() flash(gettext('Application updated!'), 'success') return redirect(url_for('.details', short_name=new_application.short_name)) try: require.app.read(app) require.app.update(app) title = app_title(app, "Update") if request.method == 'GET': form = AppForm(obj=app) categories = db.session.query(model.Category).all() form.category_id.choices = [(c.id, c.name) for c in categories] if app.category_id is None: app.category_id = categories[0].id 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 if request.method == 'POST': form = AppForm(request.form) categories = cached_cat.get_all() form.category_id.choices = [(c.id, c.name) for c in categories] if form.validate(): return handle_valid_form(form) flash(gettext('Please correct the errors'), 'error') return render_template('/applications/update.html', form=form, title=title, app=app) except HTTPException: if app.hidden: raise abort(403) else: raise
def test_get_all_returns_all_categories(self): categories = [CategoryFactory.create()] assert cached_categories.get_all() == categories
def update(short_name): app, n_tasks, n_task_runs, overall_progress, last_activity = app_by_shortname(short_name) def handle_valid_form(form): hidden = int(form.hidden.data) new_info = {} # Add the info items app, n_tasks, n_task_runs, overall_progress, last_activity = app_by_shortname(short_name) if form.thumbnail.data: new_info['thumbnail'] = form.thumbnail.data #if form.sched.data: # new_info['sched'] = form.sched.data # Merge info object info = dict(app.info.items() + new_info.items()) new_application = model.App( id=form.id.data, name=form.name.data, short_name=form.short_name.data, description=form.description.data, long_description=form.long_description.data, hidden=hidden, info=info, owner_id=app.owner_id, allow_anonymous_contributors=form.allow_anonymous_contributors.data, category_id=form.category_id.data) app, n_tasks, n_task_runs, overall_progress, last_activity = app_by_shortname(short_name) db.session.merge(new_application) db.session.commit() cached_apps.reset() cached_cat.reset() flash(gettext('Application updated!'), 'success') return redirect(url_for('.details', short_name=new_application.short_name)) try: require.app.read(app) require.app.update(app) title = app_title(app, "Update") if request.method == 'GET': form = AppForm(obj=app) categories = db.session.query(model.Category).all() form.category_id.choices = [(c.id, c.name) for c in categories] if app.category_id is None: app.category_id = categories[0].id 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 if request.method == 'POST': form = AppForm(request.form) categories = cached_cat.get_all() form.category_id.choices = [(c.id, c.name) for c in categories] if form.validate(): return handle_valid_form(form) flash(gettext('Please correct the errors'), 'error') return render_template('/applications/update.html', form=form, title=title, app=app) except HTTPException: if app.hidden: raise abort(403) else: raise