def create_auth_token(): if not app.testing: app.csrf.protect() duration_seconds = request.form.get('duration_seconds', None) if duration_seconds: try: duration_seconds = int(duration_seconds) assert duration_seconds >= 1 except (ValueError, AssertionError): abort(400, "duration_seconds must be a positive non-zero integer") # check user's auth. api_token and editor_id are signed together in session # cookie, so if api_token is valid editor_id is assumed to match. If that # wasn't true, users could manipulate session cookies and create tokens for # any user user_api = auth_api(session['api_token']) resp = user_api.auth_check() assert (resp.success) # generate token using *superuser* privs editor_id = session['editor']['editor_id'] try: resp = priv_api.create_auth_token(editor_id, duration_seconds=duration_seconds) except ApiException as ae: app.log.info(ae) raise ae return render_template('auth_token.html', auth_token=resp.token)
def generic_edit_delete(editgroup_id, entity_type, edit_id): # fetch editgroup (if set) or 404 editgroup = None if editgroup_id: try: editgroup = api.get_editgroup(editgroup_id) except ApiException as ae: abort(ae.status) # check that editgroup is edit-able if editgroup.changelog_index != None: flash("Editgroup already merged") abort(400) # API on behalf of user user_api = auth_api(session['api_token']) # do the deletion try: if entity_type == 'container': user_api.delete_container_edit(editgroup.editgroup_id, edit_id) elif entity_type == 'file': user_api.delete_file_edit(editgroup.editgroup_id, edit_id) elif entity_type == 'release': user_api.delete_release_edit(editgroup.editgroup_id, edit_id) else: raise NotImplementedError except ApiException as ae: abort(ae.status) return redirect("/editgroup/{}".format(editgroup_id))
def auth_account(): # auth check on account page user_api = auth_api(session['api_token']) resp = user_api.auth_check() assert (resp.success) editor = user_api.get_editor(session['editor']['editor_id']) session['editor'] = editor.to_dict() load_user(editor.editor_id) return render_template('auth_account.html')
def editgroup_submit(ident): if not app.testing: app.csrf.protect() # on behalf of user... user_api = auth_api(session['api_token']) try: eg = user_api.get_editgroup(str(ident)) if eg.changelog_index: abort(400, "Editgroup already accepted") user_api.update_editgroup(eg.editgroup_id, eg, submit=True) except ApiException as ae: app.log.info(ae) abort(ae.status) return redirect('/editgroup/{}'.format(ident))
def change_username(): # show the user a list of login options if not 'username' in request.form: abort(400) # on behalf of user... user_api = auth_api(session['api_token']) editor = user_api.get_editor(session['editor']['editor_id']) editor.username = request.form['username'] editor = user_api.update_editor(editor.editor_id, editor) # update our session session['editor'] = editor.to_dict() load_user(editor.editor_id) flash("Username updated successfully") return redirect('/auth/account')
def change_username(): if not app.testing: app.csrf.protect() # show the user a list of login options if not 'username' in request.form: abort(400) # on behalf of user... user_api = auth_api(session['api_token']) try: editor = user_api.get_editor(session['editor']['editor_id']) editor.username = request.form['username'] editor = user_api.update_editor(editor.editor_id, editor) except ApiException as ae: app.log.info(ae) raise ae # update our session session['editor'] = editor.to_dict() load_user(editor.editor_id) return redirect('/auth/account')
def generic_edit_delete(editgroup_id, entity_type, edit_id): # fetch editgroup (if set) or 404 editgroup = None if editgroup_id: try: editgroup = api.get_editgroup(editgroup_id) except ApiException as ae: abort(ae.status) # check that editgroup is edit-able if editgroup.changelog_index != None: flash("Editgroup already merged") abort(400) # API on behalf of user user_api = auth_api(session['api_token']) # do the deletion generic_entity_delete_edit(user_api, entity_type, editgroup.editgroup_id, edit_id) return redirect("/editgroup/{}".format(editgroup_id))
def editgroup_create_annotation(ident): if not app.testing: app.csrf.protect() comment_markdown = request.form.get('comment_markdown') if not comment_markdown: app.log.info("empty comment field") abort(400) # on behalf of user... user_api = auth_api(session['api_token']) try: eg = user_api.get_editgroup(str(ident)) if eg.changelog_index: abort(400, "Editgroup already accepted") ega = EditgroupAnnotation( comment_markdown=comment_markdown, extra=None, ) user_api.create_editgroup_annotation(eg.editgroup_id, ega) except ApiException as ae: app.log.info(ae) raise ae return redirect('/editgroup/{}'.format(ident))
def generic_entity_delete(editgroup_id: Optional[str], entity_type: str, existing_ident: str): """ Similar to generic_entity_edit(), but for deleting entities. This is a bit simpler! Handles both creation and update/edit paths. """ # fetch editgroup (if set) or 404 editgroup = None if editgroup_id: try: editgroup = api.get_editgroup(editgroup_id) except ApiException as ae: raise ae # check that editgroup is edit-able if editgroup.changelog_index != None: flash("Editgroup already merged") abort(400) # fetch entity (if set) or 404 existing = None existing_edit = None if editgroup and existing_ident: existing, existing_edit = generic_get_editgroup_entity(editgroup, entity_type, existing_ident) elif existing_ident: existing = generic_get_entity(entity_type, existing_ident) # parse form (if submitted) status = 200 form = EntityEditForm() if form.is_submitted(): if form.validate_on_submit(): # API on behalf of user user_api = auth_api(session['api_token']) if not editgroup: editgroup = form_editgroup_get_or_create(user_api, form) if editgroup: # TODO: some danger of wiping database state here is # "updated edit" causes, eg, a 4xx error. Better to allow # this in the API itself. For now, form validation *should* # catch most errors, and if not editor can hit back and try # again. This means, need to allow failure of deletion. if existing_edit: # need to clear revision on object or this becomes just # a "update pointer" edit existing.revision = None generic_entity_delete_edit(user_api, entity_type, editgroup.editgroup_id, existing_edit.edit_id) try: edit = generic_entity_delete_entity(user_api, entity_type, editgroup.editgroup_id, existing.ident) except ApiException as ae: app.log.warning(ae) raise ae if status == 200: return redirect('/editgroup/{}/{}/{}'.format(editgroup.editgroup_id, entity_type, edit.ident)) else: status = 400 elif form.errors: status = 400 app.log.info("form errors (did not validate): {}".format(form.errors)) else: # form is not submitted if existing: form = EntityTomlForm.from_entity(existing) editor_editgroups = api.get_editor_editgroups(session['editor']['editor_id'], limit=20) potential_editgroups = [e for e in editor_editgroups if e.changelog_index == None and e.submitted == None] if not form.is_submitted(): # default to most recent not submitted, fallback to "create new" form.editgroup_id.data = "" if potential_editgroups: form.editgroup_id.data = potential_editgroups[0].editgroup_id return render_template("entity_delete.html", form=form, entity_type=entity_type, existing_ident=existing_ident, editgroup=editgroup, potential_editgroups=potential_editgroups), status
def generic_entity_edit(editgroup_id, entity_type, existing_ident, edit_template): """ existing (entity) Create: existing blank, ident blank, editgroup optional Update: ident set Need to handle: - editgroup not set (need to create one) - creating entity from form - updating an existing ident - updating an existing editgroup/ident Views: - /container/create - /container/<ident>/edit - /editgroup/<editgroup_id>/container/<ident>/edit Helpers: - get_editgroup_revision(editgroup, entity_type, ident) -> None or entity TODO: prev_rev interlock """ # fetch editgroup (if set) or 404 editgroup = None if editgroup_id: try: editgroup = api.get_editgroup(editgroup_id) except ApiException as ae: raise ae # check that editgroup is edit-able if editgroup.changelog_index != None: abort(400, "Editgroup already merged") # fetch entity (if set) or 404 existing = None existing_edit = None if editgroup and existing_ident: existing, existing_edit = generic_get_editgroup_entity(editgroup, entity_type, existing_ident) elif existing_ident: existing = generic_get_entity(entity_type, existing_ident) # parse form (if submitted) status = 200 if entity_type == 'container': form = ContainerEntityForm() elif entity_type == 'file': form = FileEntityForm() elif entity_type == 'release': form = ReleaseEntityForm() else: raise NotImplementedError if form.is_submitted(): if form.validate_on_submit(): # API on behalf of user user_api = auth_api(session['api_token']) if not editgroup: editgroup = form_editgroup_get_or_create(user_api, form) if editgroup: if not existing_ident: # it's a create entity = form.to_entity() try: if entity_type == 'container': edit = user_api.create_container(editgroup.editgroup_id, entity) elif entity_type == 'file': edit = user_api.create_file(editgroup.editgroup_id, entity) elif entity_type == 'release': edit = user_api.create_release(editgroup.editgroup_id, entity) else: raise NotImplementedError except ApiException as ae: app.log.warning(ae) raise ae return redirect('/editgroup/{}/{}/{}'.format(editgroup.editgroup_id, entity_type, edit.ident)) else: # it's an update # all the tricky logic is in the update method form.update_entity(existing) # do we need to try to delete the current in-progress edit first? # TODO: some danger of wiping database state here is # "updated edit" causes, eg, a 4xx error. Better to allow # this in the API itself. For now, form validation *should* # catch most errors, and if not editor can hit back and try # again. This means, need to allow failure of deletion. if existing_edit: # need to clear revision on object or this becomes just # a "update pointer" edit existing.revision = None try: generic_entity_delete_edit(user_api, entity_type, editgroup.editgroup_id, existing_edit.edit_id) except ApiException as ae: if ae.status == 404: pass else: raise ae try: if entity_type == 'container': edit = user_api.update_container(editgroup.editgroup_id, existing.ident, existing) elif entity_type == 'file': edit = user_api.update_file(editgroup.editgroup_id, existing.ident, existing) elif entity_type == 'release': edit = user_api.update_release(editgroup.editgroup_id, existing.ident, existing) else: raise NotImplementedError except ApiException as ae: app.log.warning(ae) raise ae return redirect('/editgroup/{}/{}/{}'.format(editgroup.editgroup_id, entity_type, edit.ident)) else: status = 400 elif form.errors: status = 400 app.log.info("form errors (did not validate): {}".format(form.errors)) else: # form is not submitted if existing: if entity_type == 'container': form = ContainerEntityForm.from_entity(existing) elif entity_type == 'file': form = FileEntityForm.from_entity(existing) elif entity_type == 'release': form = ReleaseEntityForm.from_entity(existing) else: raise NotImplementedError editor_editgroups = api.get_editor_editgroups(session['editor']['editor_id'], limit=20) potential_editgroups = [e for e in editor_editgroups if e.changelog_index == None and e.submitted == None] if not form.is_submitted(): # default to most recent not submitted, fallback to "create new" form.editgroup_id.data = "" if potential_editgroups: form.editgroup_id.data = potential_editgroups[0].editgroup_id return render_template(edit_template, form=form, existing_ident=existing_ident, editgroup=editgroup, potential_editgroups=potential_editgroups), status