From 81a3d98f8bf647ded6923eb77d3df791888e0a2a Mon Sep 17 00:00:00 2001 From: Bryan Newbold Date: Thu, 30 Jul 2020 17:26:49 -0700 Subject: generic helpers for TOML editing routes --- python/fatcat_web/editing_routes.py | 183 ++++++++++++++++++++++++++++++++++-- 1 file changed, 174 insertions(+), 9 deletions(-) (limited to 'python/fatcat_web/editing_routes.py') diff --git a/python/fatcat_web/editing_routes.py b/python/fatcat_web/editing_routes.py index ffce35f3..9598a754 100644 --- a/python/fatcat_web/editing_routes.py +++ b/python/fatcat_web/editing_routes.py @@ -2,7 +2,7 @@ from flask import render_template, abort, redirect, session, flash from flask_login import login_required -from fatcat_openapi_client import Editgroup +from fatcat_openapi_client import * from fatcat_openapi_client.rest import ApiException from fatcat_tools.transforms import * from fatcat_web import app, api, auth_api @@ -13,6 +13,82 @@ from fatcat_web.entity_helpers import * ### Helper Methods ########################################################## +def generic_entity_create_from_toml(user_api, entity_type: str, editgroup_id: str, toml_str: str) -> EntityEdit: + if entity_type == 'container': + entity = entity_from_toml(toml_str, ContainerEntity) + edit = user_api.create_container(editgroup_id, entity) + elif entity_type == 'creator': + entity = entity_from_toml(toml_str, CreatorEntity) + edit = user_api.create_creator(editgroup_id, entity) + elif entity_type == 'file': + entity = entity_from_toml(toml_str, FileEntity) + edit = user_api.create_file(editgroup_id, entity) + elif entity_type == 'fileset': + entity = entity_from_toml(toml_str, FilesetEntity) + edit = user_api.create_fileset(editgroup_id, entity) + elif entity_type == 'webcapture': + entity = entity_from_toml(toml_str, WebcaptureEntity) + edit = user_api.create_webcapture(editgroup_id, entity) + elif entity_type == 'release': + entity = entity_from_toml(toml_str, ReleaseEntity) + edit = user_api.create_release(editgroup_id, entity) + elif entity_type == 'work': + entity = entity_from_toml(toml_str, WorkEntity) + edit = user_api.create_work(editgroup_id, entity) + else: + raise NotImplementedError + return edit + +def generic_entity_delete_edit(user_api, entity_type: str, editgroup_id: str, edit_id: str) -> None: + try: + if entity_type == 'container': + user_api.delete_container_edit(editgroup_id, edit_id) + elif entity_type == 'creator': + user_api.delete_creator_edit(editgroup_id, edit_id) + elif entity_type == 'file': + user_api.delete_file_edit(editgroup_id, edit_id) + elif entity_type == 'fileset': + user_api.delete_fileset_edit(editgroup_id, edit_id) + elif entity_type == 'webcapture': + user_api.delete_webcapture_edit(editgroup_id, edit_id) + elif entity_type == 'release': + user_api.delete_release_edit(editgroup_id, edit_id) + elif entity_type == 'work': + user_api.delete_work_edit(editgroup_id, edit_id) + else: + raise NotImplementedError + except ApiException as ae: + if ae.status == 404: + pass + else: + raise ae + +def generic_entity_update_from_toml(user_api, entity_type: str, editgroup_id: str, existing_ident, toml_str: str) -> EntityEdit: + if entity_type == 'container': + entity = entity_from_toml(toml_str, ContainerEntity) + edit = user_api.update_container(editgroup_id, existing_ident, entity) + elif entity_type == 'creator': + entity = entity_from_toml(toml_str, CreatorEntity) + edit = user_api.update_creator(editgroup_id, existing_ident, entity) + elif entity_type == 'file': + entity = entity_from_toml(toml_str, FileEntity) + edit = user_api.update_file(editgroup_id, existing_ident, entity) + elif entity_type == 'fileset': + entity = entity_from_toml(toml_str, FilesetEntity) + edit = user_api.update_fileset(editgroup_id, existing_ident, entity) + elif entity_type == 'webcapture': + entity = entity_from_toml(toml_str, WebcaptureEntity) + edit = user_api.update_webcapture(editgroup_id, existing_ident, entity) + elif entity_type == 'release': + entity = entity_from_toml(toml_str, ReleaseEntity) + edit = user_api.update_release(editgroup_id, existing_ident, entity) + elif entity_type == 'work': + entity = entity_from_toml(toml_str, WorkEntity) + edit = user_api.update_work(editgroup_id, existing_ident, entity) + else: + raise NotImplementedError + return edit + def form_editgroup_get_or_create(api, edit_form): """ This function expects a submitted, validated edit form @@ -138,14 +214,7 @@ def generic_entity_edit(editgroup_id, entity_type, existing_ident, edit_template # a "update pointer" edit existing.revision = None try: - if entity_type == 'container': - user_api.delete_container_edit(editgroup.editgroup_id, existing_edit.edit_id) - elif entity_type == 'file': - user_api.delete_file_edit(editgroup.editgroup_id, existing_edit.edit_id) - elif entity_type == 'release': - user_api.delete_release_edit(editgroup.editgroup_id, existing_edit.edit_id) - else: - raise NotImplementedError + generic_entity_delete_edit(user_api, entity_type, editgroup.editgroup_id, existing_edit.edit_id) except ApiException as ae: if ae.status == 404: pass @@ -194,6 +263,102 @@ def generic_entity_edit(editgroup_id, entity_type, existing_ident, edit_template existing_ident=existing_ident, editgroup=editgroup, potential_editgroups=potential_editgroups), status +def generic_entity_toml_edit(editgroup_id, entity_type, existing_ident, edit_template): + """ + Similar to generic_entity_edit(), but for TOML editing mode. + + 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 = EntityTomlForm() + + 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 + try: + edit = generic_entity_create_from_toml(user_api, entity_type, editgroup.editgroup_id, form.toml.data) + except ValueError as ve: + form.toml.errors = [ve] + status = 400 + 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: # it's an update + # 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_update_from_toml(user_api, entity_type, editgroup.editgroup_id, existing.ident, form.toml.data) + except ValueError as ve: + form.toml.errors = [ve] + status = 400 + 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(edit_template, form=form, entity_type=entity_type, + existing_ident=existing_ident, editgroup=editgroup, + potential_editgroups=potential_editgroups), status + def generic_edit_delete(editgroup_id, entity_type, edit_id): # fetch editgroup (if set) or 404 editgroup = None -- cgit v1.2.3 From 18933a623450d42e5834cf31cee1f4cfa7f5bb7a Mon Sep 17 00:00:00 2001 From: Bryan Newbold Date: Thu, 30 Jul 2020 17:27:11 -0700 Subject: editing: more 'raise' status instead of 'abort()' --- python/fatcat_web/editing_routes.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'python/fatcat_web/editing_routes.py') diff --git a/python/fatcat_web/editing_routes.py b/python/fatcat_web/editing_routes.py index 9598a754..f3c6fdd0 100644 --- a/python/fatcat_web/editing_routes.py +++ b/python/fatcat_web/editing_routes.py @@ -151,7 +151,7 @@ def generic_entity_edit(editgroup_id, entity_type, existing_ident, edit_template try: editgroup = api.get_editgroup(editgroup_id) except ApiException as ae: - abort(ae.status) + raise ae # check that editgroup is edit-able if editgroup.changelog_index != None: -- cgit v1.2.3 From b14040ecb359d1575280b24eaab9bd0e4964e3f7 Mon Sep 17 00:00:00 2001 From: Bryan Newbold Date: Thu, 30 Jul 2020 17:31:17 -0700 Subject: wire up new TOML views --- python/fatcat_web/editing_routes.py | 193 +++++++++++++++++----- python/fatcat_web/templates/container_create.html | 4 +- python/fatcat_web/templates/container_edit.html | 5 + python/fatcat_web/templates/edit_macros.html | 2 +- python/fatcat_web/templates/editgroup_view.html | 2 +- python/fatcat_web/templates/entity_edit.html | 8 - python/fatcat_web/templates/entity_edit_toml.html | 12 ++ python/fatcat_web/templates/file_create.html | 4 +- python/fatcat_web/templates/file_edit.html | 5 + python/fatcat_web/templates/home.html | 12 +- python/fatcat_web/templates/release_create.html | 4 +- python/fatcat_web/templates/release_edit.html | 6 + python/tests/web_editing.py | 66 ++++++-- python/tests/web_entity_views.py | 16 +- 14 files changed, 256 insertions(+), 83 deletions(-) delete mode 100644 python/fatcat_web/templates/entity_edit.html (limited to 'python/fatcat_web/editing_routes.py') diff --git a/python/fatcat_web/editing_routes.py b/python/fatcat_web/editing_routes.py index f3c6fdd0..e84b14f7 100644 --- a/python/fatcat_web/editing_routes.py +++ b/python/fatcat_web/editing_routes.py @@ -366,27 +366,18 @@ def generic_edit_delete(editgroup_id, entity_type, edit_id): try: editgroup = api.get_editgroup(editgroup_id) except ApiException as ae: - raise ae + abort(ae.status) # check that editgroup is edit-able if editgroup.changelog_index != None: - abort(400, "Editgroup already merged") + 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: - raise ae + generic_entity_delete_edit(user_api, entity_type, editgroup.editgroup_id, edit_id) return redirect("/editgroup/{}".format(editgroup_id)) @@ -452,69 +443,187 @@ def release_editgroup_edit(editgroup_id, ident): def release_edit_delete(editgroup_id, edit_id): return generic_edit_delete(editgroup_id, 'release', edit_id) +@app.route('/editgroup//creator/edit//delete', methods=['POST']) +def creator_edit_delete(editgroup_id, edit_id): + return generic_edit_delete(editgroup_id, 'creator', edit_id) + +@app.route('/editgroup//fileset/edit//delete', methods=['POST']) +def fileset_edit_delete(editgroup_id, edit_id): + return generic_edit_delete(editgroup_id, 'fileset', edit_id) -### Not-Implemented Views ################################################### +@app.route('/editgroup//webcapture/edit//delete', methods=['POST']) +def webcapture_edit_delete(editgroup_id, edit_id): + return generic_edit_delete(editgroup_id, 'webcapture', edit_id) + +@app.route('/editgroup//work/edit//delete', methods=['POST']) +def work_edit_delete(editgroup_id, edit_id): + return generic_edit_delete(editgroup_id, 'work', edit_id) + +### TOML Views ############################################################## + +@app.route('/container/create/toml', methods=['GET', 'POST']) +@login_required +def container_create_toml_view(): + return generic_entity_toml_edit(None, 'container', None, 'entity_create_toml.html') + +@app.route('/container//edit/toml', methods=['GET', 'POST']) +@login_required +def container_edit_toml(ident): + return generic_entity_toml_edit(None, 'container', ident, 'entity_edit_toml.html') + +@app.route('/editgroup//container//edit/toml', methods=['GET', 'POST']) +@login_required +def container_editgroup_edit_toml(editgroup_id, ident): + return generic_entity_toml_edit(editgroup_id, 'container', ident, 'entity_edit_toml.html') + +@app.route('/creator/create/toml', methods=['GET', 'POST']) +@login_required +def creator_create_toml_view(): + return generic_entity_toml_edit(None, 'creator', None, 'entity_create_toml.html') + +@app.route('/creator//edit/toml', methods=['GET', 'POST']) +@login_required +def creator_edit_toml(ident): + return generic_entity_toml_edit(None, 'creator', ident, 'entity_edit_toml.html') + +@app.route('/editgroup//creator//edit/toml', methods=['GET', 'POST']) +@login_required +def creator_editgroup_edit_toml(editgroup_id, ident): + return generic_entity_toml_edit(editgroup_id, 'creator', ident, 'entity_edit_toml.html') + +@app.route('/file/create/toml', methods=['GET', 'POST']) +@login_required +def file_create_toml_view(): + return generic_entity_toml_edit(None, 'file', None, 'entity_create_toml.html') + +@app.route('/file//edit/toml', methods=['GET', 'POST']) +@login_required +def file_edit_toml(ident): + return generic_entity_toml_edit(None, 'file', ident, 'entity_edit_toml.html') + +@app.route('/editgroup//file//edit/toml', methods=['GET', 'POST']) +@login_required +def file_editgroup_edit_toml(editgroup_id, ident): + return generic_entity_toml_edit(editgroup_id, 'file', ident, 'entity_edit_toml.html') + +@app.route('/fileset/create/toml', methods=['GET', 'POST']) +@login_required +def fileset_create_toml_view(): + return generic_entity_toml_edit(None, 'fileset', None, 'entity_create_toml.html') + +@app.route('/fileset//edit/toml', methods=['GET', 'POST']) +@login_required +def fileset_edit_toml(ident): + return generic_entity_toml_edit(None, 'fileset', ident, 'entity_edit_toml.html') + +@app.route('/editgroup//fileset//edit/toml', methods=['GET', 'POST']) +@login_required +def fileset_editgroup_edit_toml(editgroup_id, ident): + return generic_entity_toml_edit(editgroup_id, 'fileset', ident, 'entity_edit_toml.html') + +@app.route('/webcapture/create/toml', methods=['GET', 'POST']) +@login_required +def webcapture_create_toml_view(): + return generic_entity_toml_edit(None, 'webcapture', None, 'entity_create_toml.html') + +@app.route('/webcapture//edit/toml', methods=['GET', 'POST']) +@login_required +def webcapture_edit_toml(ident): + return generic_entity_toml_edit(None, 'webcapture', ident, 'entity_edit_toml.html') + +@app.route('/editgroup//webcapture//edit/toml', methods=['GET', 'POST']) +@login_required +def webcapture_editgroup_edit_toml(editgroup_id, ident): + return generic_entity_toml_edit(editgroup_id, 'webcapture', ident, 'entity_edit_toml.html') + +@app.route('/release/create/toml', methods=['GET', 'POST']) +@login_required +def release_create_toml_view(): + return generic_entity_toml_edit(None, 'release', None, 'entity_create_toml.html') + +@app.route('/release//edit/toml', methods=['GET', 'POST']) +@login_required +def release_edit_toml(ident): + return generic_entity_toml_edit(None, 'release', ident, 'entity_edit_toml.html') + +@app.route('/editgroup//release//edit/toml', methods=['GET', 'POST']) +@login_required +def release_editgroup_edit_toml(editgroup_id, ident): + return generic_entity_toml_edit(editgroup_id, 'release', ident, 'entity_edit_toml.html') + +@app.route('/work/create/toml', methods=['GET', 'POST']) +@login_required +def work_create_toml_view(): + return generic_entity_toml_edit(None, 'work', None, 'entity_create_toml.html') + +@app.route('/work//edit/toml', methods=['GET', 'POST']) +@login_required +def work_edit_toml(ident): + return generic_entity_toml_edit(None, 'work', ident, 'entity_edit_toml.html') + +@app.route('/editgroup//work//edit/toml', methods=['GET', 'POST']) +@login_required +def work_editgroup_edit_toml(editgroup_id, ident): + return generic_entity_toml_edit(editgroup_id, 'work', ident, 'entity_edit_toml.html') + +### TOML-Only Editing Redirects ################################################ @app.route('/creator/create', methods=['GET']) +@login_required def creator_create_view(): - return abort(404) + return redirect('/creator/create/toml') @app.route('/creator//edit', methods=['GET']) +@login_required def creator_edit(ident): - return render_template('entity_edit.html'), 404 + return redirect(f'/creator/{ident}/edit/toml') @app.route('/editgroup//creator//edit', methods=['GET', 'POST']) +@login_required def creator_editgroup_edit(editgroup_id, ident): - return abort(404) - -@app.route('/editgroup//creator/edit//delete', methods=['POST']) -def creator_edit_delete(editgroup_id, edit_id): - return abort(404) + return redirect(f'/editgroup/{editgroup_id}/creator/{ident}/edit/toml') @app.route('/fileset/create', methods=['GET']) +@login_required def fileset_create_view(): - return abort(404) + return redirect('/fileset/create/toml') @app.route('/fileset//edit', methods=['GET']) +@login_required def fileset_edit(ident): - return render_template('entity_edit.html'), 404 + return redirect(f'/fileset/{ident}/edit/toml') @app.route('/editgroup//fileset//edit', methods=['GET', 'POST']) +@login_required def fileset_editgroup_edit(editgroup_id, ident): - return abort(404) - -@app.route('/editgroup//fileset/edit//delete', methods=['POST']) -def fileset_edit_delete(editgroup_id, edit_id): - return abort(404) + return redirect(f'/editgroup/{editgroup_id}/fileset/{ident}/edit/toml') @app.route('/webcapture/create', methods=['GET']) +@login_required def webcapture_create_view(): - return abort(404) + return redirect('/webcapture/create/toml') @app.route('/webcapture//edit', methods=['GET']) +@login_required def webcapture_edit(ident): - return render_template('entity_edit.html'), 404 + return redirect(f'/webcapture/{ident}/edit/toml') @app.route('/editgroup//webcapture//edit', methods=['GET', 'POST']) +@login_required def webcapture_editgroup_edit(editgroup_id, ident): - return abort(404) - -@app.route('/editgroup//webcapture/edit//delete', methods=['POST']) -def webcapture_edit_delete(editgroup_id, edit_id): - return abort(404) + return redirect(f'/editgroup/{editgroup_id}/webcapture/{ident}/edit/toml') @app.route('/work/create', methods=['GET']) +@login_required def work_create_view(): - return abort(404) + return redirect('/work/create/toml') @app.route('/work//edit', methods=['GET']) +@login_required def work_edit(ident): - return render_template('entity_edit.html'), 404 + return redirect(f'/work/{ident}/edit/toml') @app.route('/editgroup//work//edit', methods=['GET', 'POST']) +@login_required def work_editgroup_edit(editgroup_id, ident): - return abort(404) - -@app.route('/editgroup//work/edit//delete', methods=['POST']) -def work_edit_delete(editgroup_id, edit_id): - return abort(404) + return redirect(f'/editgroup/{editgroup_id}/work/{ident}/edit/toml') diff --git a/python/fatcat_web/templates/container_create.html b/python/fatcat_web/templates/container_create.html index 5786d05d..be8c5671 100644 --- a/python/fatcat_web/templates/container_create.html +++ b/python/fatcat_web/templates/container_create.html @@ -9,13 +9,15 @@ a journal (eg, "New England Journal of Medicine"), conference proceedings, a book series, or a blog. Not all publications are in a container.
+

Experienced users can also use the TOML + creation form to access all metadata fields in a raw format. {% endblock %} {% block edit_form_suffix %}

- New entity will be part of the current editgroup, which needs to be + New container entity will be part of the current editgroup, which needs to be submited and approved before the entity will formally be included in the catalog. diff --git a/python/fatcat_web/templates/container_edit.html b/python/fatcat_web/templates/container_edit.html index 5188ce0d..fd07b3da 100644 --- a/python/fatcat_web/templates/container_edit.html +++ b/python/fatcat_web/templates/container_edit.html @@ -7,6 +7,11 @@

Edit Container Entity

+ +

Experienced users can also use the TOML editing form to access all metadata + fields in a raw format. {% endblock %}

See the catalog diff --git a/python/fatcat_web/templates/edit_macros.html b/python/fatcat_web/templates/edit_macros.html index 60c17aa9..d4839373 100644 --- a/python/fatcat_web/templates/edit_macros.html +++ b/python/fatcat_web/templates/edit_macros.html @@ -55,7 +55,7 @@ {% macro editgroup_dropdown(form, editgroup=None, potential_editgroups=None) -%} {% if editgroup %}

You are updating an existing un-merged editgroup: {{ editgroup.editgroup_id }}. -

Description: {{ editgroup.description }} +

Description: {{ editgroup.description or "" }} {% else %} {% if not potential_editgroups %}

You have no un-submitted editgroups in progress; a new one will be diff --git a/python/fatcat_web/templates/editgroup_view.html b/python/fatcat_web/templates/editgroup_view.html index e8146d19..a36dc3e5 100644 --- a/python/fatcat_web/templates/editgroup_view.html +++ b/python/fatcat_web/templates/editgroup_view.html @@ -25,7 +25,7 @@ updated {% endif %} [view edit] - {% if auth_to.edit and not editgroup.changelog_index and not editgroup.submitted and entity_type in ('release', 'file', 'container') %} + {% if auth_to.edit and not editgroup.changelog_index and not editgroup.submitted %} [re-edit] diff --git a/python/fatcat_web/templates/entity_edit.html b/python/fatcat_web/templates/entity_edit.html deleted file mode 100644 index 97f7bf46..00000000 --- a/python/fatcat_web/templates/entity_edit.html +++ /dev/null @@ -1,8 +0,0 @@ -{% extends "base.html" %} -{% block body %} - -

Not Implemented

- -

Entity editing via the web interface isn't implemented yet. Sorry! - -{% endblock %} diff --git a/python/fatcat_web/templates/entity_edit_toml.html b/python/fatcat_web/templates/entity_edit_toml.html index 4b6e7b6d..807e4d2b 100644 --- a/python/fatcat_web/templates/entity_edit_toml.html +++ b/python/fatcat_web/templates/entity_edit_toml.html @@ -37,3 +37,15 @@ {% endblock %} {% endblock %} +{% block postscript %} + + +{% endblock %} diff --git a/python/fatcat_web/templates/file_create.html b/python/fatcat_web/templates/file_create.html index a7c99b96..affcfb6e 100644 --- a/python/fatcat_web/templates/file_create.html +++ b/python/fatcat_web/templates/file_create.html @@ -5,13 +5,15 @@

Create New File Entity

+

Experienced users can also use the TOML + creation form to access all metadata fields in a raw format. {% endblock %} {% block edit_form_suffix %}

- New entity will be part of the current editgroup, which needs to be + New file entity will be part of the current editgroup, which needs to be submited and approved before the entity will formally be included in the catalog. diff --git a/python/fatcat_web/templates/file_edit.html b/python/fatcat_web/templates/file_edit.html index e8a421b3..b7876fc5 100644 --- a/python/fatcat_web/templates/file_edit.html +++ b/python/fatcat_web/templates/file_edit.html @@ -7,6 +7,11 @@

Edit File Entity

+ +

Experienced users can also use the TOML editing form to access all metadata + fields in a raw format. {% endblock %}

See the catalog diff --git a/python/fatcat_web/templates/home.html b/python/fatcat_web/templates/home.html index 4557e212..de32d6a4 100644 --- a/python/fatcat_web/templates/home.html +++ b/python/fatcat_web/templates/home.html @@ -171,11 +171,10 @@ Creator
authors, editors, translators +
Create {% if config.FATCAT_DOMAIN == 'fatcat.wiki' %} - Author {% else %} - Author (prod)
Dummy
Realistic @@ -206,11 +205,10 @@

File Set
datasets, suplementary materials + Create {% if config.FATCAT_DOMAIN == 'fatcat.wiki' %} - Dataset {% else %} - Dataset (prod)
Dummy
Realistic @@ -218,12 +216,11 @@ Web Capture
HTML and interactive articles, blog posts + Create {% if config.FATCAT_DOMAIN == 'fatcat.wiki' %} - D-Lib
Blog Post {% else %} - D-Lib (prod)
Dummy
Realistic @@ -231,11 +228,10 @@ Work
for grouping Releases + Create {% if config.FATCAT_DOMAIN == 'fatcat.wiki' %} - Paper {% else %} - Paper (prod)
Dummy
Realistic diff --git a/python/fatcat_web/templates/release_create.html b/python/fatcat_web/templates/release_create.html index 5ec2efe5..4f5dabd7 100644 --- a/python/fatcat_web/templates/release_create.html +++ b/python/fatcat_web/templates/release_create.html @@ -5,13 +5,15 @@

Create New Release Entity

+

Experienced users can also use the TOML + creation form to access all metadata fields in a raw format. {% endblock %} {% block edit_form_suffix %}

- New entity will be part of the current editgroup, which needs to be + New release entity will be part of the current editgroup, which needs to be submited and approved before the entity will formally be included in the catalog. diff --git a/python/fatcat_web/templates/release_edit.html b/python/fatcat_web/templates/release_edit.html index a4a7e56f..21c8cf68 100644 --- a/python/fatcat_web/templates/release_edit.html +++ b/python/fatcat_web/templates/release_edit.html @@ -7,6 +7,11 @@

Edit Release Entity

+ +

Experienced users can also use the TOML editing form to access all metadata + fields in a raw format. {% endblock %}

See the catalog @@ -14,6 +19,7 @@ href="https://guide.fatcat.wiki/editing_quickstart.html">the editing tutorial if this is your first time making an edit. + {{ form.hidden_tag() }}

Editgroup Metadata

diff --git a/python/tests/web_editing.py b/python/tests/web_editing.py index 17f4f5ae..ea244388 100644 --- a/python/tests/web_editing.py +++ b/python/tests/web_editing.py @@ -2,7 +2,7 @@ from fixtures import * -def test_web_release_create_merge(app_admin, api): +def test_web_release_create_accept(app_admin, api): eg = quick_eg(api) @@ -129,18 +129,60 @@ def test_web_file_create(app_admin, api): follow_redirects=True) assert rv.status_code == 200 +DUMMY_DEMO_ENTITIES = { + 'container': 'aaaaaaaaaaaaaeiraaaaaaaaam', + 'creator': 'aaaaaaaaaaaaaircaaaaaaaaaq', + 'file': 'aaaaaaaaaaaaamztaaaaaaaaam', + 'fileset': 'aaaaaaaaaaaaaztgaaaaaaaaai', + 'webcapture': 'aaaaaaaaaaaaa53xaaaaaaaaai', + 'release': 'aaaaaaaaaaaaarceaaaaaaaaai', + 'work': 'aaaaaaaaaaaaavkvaaaaaaaaai', +} def test_web_edit_get(app_admin): # these are all existing entities - rv = app_admin.get('/release/aaaaaaaaaaaaarceaaaaaaaaai/edit') - assert rv.status_code == 200 - assert b'A bigger example' in rv.data - - rv = app_admin.get('/file/aaaaaaaaaaaaamztaaaaaaaaam/edit') - assert rv.status_code == 200 - assert b'ffc1005680cb620eec4c913437dfabbf311b535cfe16cbaeb2faec1f92afc362' in rv.data - - rv = app_admin.get('/container/aaaaaaaaaaaaaeiraaaaaaaaam/edit') - assert rv.status_code == 200 - assert b'1549-1277' in rv.data + for entity_type in ['release', 'file', 'container']: + rv = app_admin.get(f'/{entity_type}/{DUMMY_DEMO_ENTITIES[entity_type]}/edit') + assert rv.status_code == 200 + if entity_type == 'release': + assert b'A bigger example' in rv.data + elif entity_type == 'file': + assert b'ffc1005680cb620eec4c913437dfabbf311b535cfe16cbaeb2faec1f92afc362' in rv.data + elif entity_type == 'container': + assert b'1549-1277' in rv.data + + rv = app_admin.get(f'/{entity_type}/{DUMMY_DEMO_ENTITIES[entity_type]}/edit/toml') + assert rv.status_code == 200 + if entity_type == 'release': + assert b'A bigger example' in rv.data + elif entity_type == 'file': + assert b'ffc1005680cb620eec4c913437dfabbf311b535cfe16cbaeb2faec1f92afc362' in rv.data + elif entity_type == 'container': + assert b'1549-1277' in rv.data + + # TOML-only endpoints + for entity_type in ['creator', 'fileset', 'webcapture', 'work']: + rv = app_admin.get(f'/{entity_type}/{DUMMY_DEMO_ENTITIES[entity_type]}/edit') + assert rv.status_code == 302 + + rv = app_admin.get(f'/{entity_type}/{DUMMY_DEMO_ENTITIES[entity_type]}/edit/toml') + assert rv.status_code == 200 + + +def test_web_create_get(app_admin): + + for entity_type in ['release', 'file', 'container']: + rv = app_admin.get(f'/{entity_type}/create') + assert rv.status_code == 200 + + rv = app_admin.get(f'/{entity_type}/create/toml') + assert rv.status_code == 200 + + # these are TOML only + for entity_type in ['creator', 'fileset', 'webcapture', 'work']: + rv = app_admin.get(f'/{entity_type}/create') + assert rv.status_code == 302 + + rv = app_admin.get(f'/{entity_type}/create/toml') + assert rv.status_code == 200 diff --git a/python/tests/web_entity_views.py b/python/tests/web_entity_views.py index b01bd815..7b973ef2 100644 --- a/python/tests/web_entity_views.py +++ b/python/tests/web_entity_views.py @@ -210,9 +210,9 @@ def test_web_creator(app): rv = app.get('/creator/aaaaaaaaaaaaaircaaaaaaaaai') assert rv.status_code == 200 rv = app.get('/creator/aaaaaaaaaaaaaircaaaaaaaaai/edit') - assert rv.status_code == 404 + assert rv.status_code == 302 rv = app.get('/creator/create') - assert rv.status_code == 404 + assert rv.status_code == 302 def test_web_file(app): @@ -266,9 +266,9 @@ def test_web_fileset(app): rv = app.get('/fileset/aaaaaaaaaaaaaztgaaaaaaaaai') assert rv.status_code == 200 rv = app.get('/fileset/aaaaaaaaaaaaaztgaaaaaaaaai/edit') - assert rv.status_code == 404 + assert rv.status_code == 302 rv = app.get('/fileset/create') - assert rv.status_code == 404 + assert rv.status_code == 302 def test_web_webcatpure(app): @@ -277,9 +277,9 @@ def test_web_webcatpure(app): rv = app.get('/webcapture/aaaaaaaaaaaaa53xaaaaaaaaai') assert rv.status_code == 200 rv = app.get('/webcapture/aaaaaaaaaaaaa53xaaaaaaaaai/edit') - assert rv.status_code == 404 + assert rv.status_code == 302 rv = app.get('/webcapture/create') - assert rv.status_code == 404 + assert rv.status_code == 302 def test_web_release(app): @@ -376,6 +376,6 @@ def test_web_work(app): rv = app.get('/work/aaaaaaaaaaaaavkvaaaaaaaaai') assert rv.status_code == 200 rv = app.get('/work/aaaaaaaaaaaaavkvaaaaaaaaai/edit') - assert rv.status_code == 404 + assert rv.status_code == 302 rv = app.get('/work/create') - assert rv.status_code == 404 + assert rv.status_code == 302 -- cgit v1.2.3 From b7aed96075187af72b510c55e762d1e13c0a5306 Mon Sep 17 00:00:00 2001 From: Bryan Newbold Date: Thu, 30 Jul 2020 20:35:32 -0700 Subject: implement webface entity deletion --- python/fatcat_web/editing_routes.py | 229 ++++++++++++++++++++++--- python/fatcat_web/templates/entity_delete.html | 49 ++++++ python/tests/web_editing.py | 57 ++++++ 3 files changed, 308 insertions(+), 27 deletions(-) create mode 100644 python/fatcat_web/templates/entity_delete.html (limited to 'python/fatcat_web/editing_routes.py') diff --git a/python/fatcat_web/editing_routes.py b/python/fatcat_web/editing_routes.py index e84b14f7..8e3b03b0 100644 --- a/python/fatcat_web/editing_routes.py +++ b/python/fatcat_web/editing_routes.py @@ -1,4 +1,6 @@ +from typing import Optional + from flask import render_template, abort, redirect, session, flash from flask_login import login_required @@ -63,6 +65,28 @@ def generic_entity_delete_edit(user_api, entity_type: str, editgroup_id: str, ed else: raise ae +def generic_entity_delete_entity(user_api, entity_type: str, editgroup_id: str, entity_ident: str) -> None: + try: + if entity_type == 'container': + edit = user_api.delete_container(editgroup_id, entity_ident) + elif entity_type == 'creator': + edit = user_api.delete_creator(editgroup_id, entity_ident) + elif entity_type == 'file': + edit = user_api.delete_file(editgroup_id, entity_ident) + elif entity_type == 'fileset': + edit = user_api.delete_fileset(editgroup_id, entity_ident) + elif entity_type == 'webcapture': + edit = user_api.delete_webcapture(editgroup_id, entity_ident) + elif entity_type == 'release': + edit = user_api.delete_release(editgroup_id, entity_ident) + elif entity_type == 'work': + edit = user_api.delete_work(editgroup_id, entity_ident) + else: + raise NotImplementedError + except ApiException as ae: + raise ae + return edit + def generic_entity_update_from_toml(user_api, entity_type: str, editgroup_id: str, existing_ident, toml_str: str) -> EntityEdit: if entity_type == 'container': entity = entity_from_toml(toml_str, ContainerEntity) @@ -359,6 +383,87 @@ def generic_entity_toml_edit(editgroup_id, entity_type, existing_ident, edit_tem existing_ident=existing_ident, editgroup=editgroup, potential_editgroups=potential_editgroups), status +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_edit_delete(editgroup_id, entity_type, edit_id): # fetch editgroup (if set) or 404 editgroup = None @@ -390,19 +495,43 @@ def container_create_view(): @app.route('/container//edit', methods=['GET', 'POST']) @login_required -def container_edit(ident): +def container_edit_view(ident): return generic_entity_edit(None, 'container', ident, 'container_edit.html') +@app.route('/container//delete', methods=['GET', 'POST']) +@login_required +def container_delete_view(ident): + return generic_entity_delete(None, 'container', ident) + @app.route('/editgroup//container//edit', methods=['GET', 'POST']) @login_required -def container_editgroup_edit(editgroup_id, ident): +def container_editgroup_edit_view(editgroup_id, ident): return generic_entity_edit(editgroup_id, 'container', ident, 'container_edit.html') +@app.route('/editgroup//container//delete', methods=['GET', 'POST']) +@login_required +def container_editgroup_delete_view(editgroup_id, ident): + return generic_entity_delete(editgroup_id, 'container', ident) + @app.route('/editgroup//container/edit//delete', methods=['POST']) @login_required def container_edit_delete(editgroup_id, edit_id): return generic_edit_delete(editgroup_id, 'container', edit_id) +@app.route('/creator//delete', methods=['GET', 'POST']) +@login_required +def creator_delete_view(ident): + return generic_entity_delete(None, 'creator', ident) + +@app.route('/editgroup//creator/edit//delete', methods=['POST']) +def creator_edit_delete(editgroup_id, edit_id): + return generic_edit_delete(editgroup_id, 'creator', edit_id) + +@app.route('/editgroup//creator//delete', methods=['GET', 'POST']) +@login_required +def creator_editgroup_delete(editgroup_id, ident): + return generic_entity_delete(editgroup_id, 'creator', ident) + @app.route('/file/create', methods=['GET', 'POST']) @login_required def file_create_view(): @@ -410,19 +539,57 @@ def file_create_view(): @app.route('/file//edit', methods=['GET', 'POST']) @login_required -def file_edit(ident): +def file_edit_view(ident): return generic_entity_edit(None, 'file', ident, 'file_edit.html') +@app.route('/file//delete', methods=['GET', 'POST']) +@login_required +def file_delete_view(ident): + return generic_entity_delete(None, 'file', ident) + @app.route('/editgroup//file//edit', methods=['GET', 'POST']) @login_required -def file_editgroup_edit(editgroup_id, ident): +def file_editgroup_edit_view(editgroup_id, ident): return generic_entity_edit(editgroup_id, 'file', ident, 'file_edit.html') +@app.route('/editgroup//file//delete', methods=['GET', 'POST']) +@login_required +def file_editgroup_delete_view(editgroup_id, ident): + return generic_entity_delete(editgroup_id, 'file', ident) + @app.route('/editgroup//file/edit//delete', methods=['POST']) @login_required def file_edit_delete(editgroup_id, edit_id): return generic_edit_delete(editgroup_id, 'file', edit_id) +@app.route('/fileset//delete', methods=['GET', 'POST']) +@login_required +def fileset_delete_view(ident): + return generic_entity_delete(None, 'fileset', ident) + +@app.route('/editgroup//fileset/edit//delete', methods=['POST']) +def fileset_edit_delete(editgroup_id, edit_id): + return generic_edit_delete(editgroup_id, 'fileset', edit_id) + +@app.route('/editgroup//fileset//delete', methods=['GET', 'POST']) +@login_required +def fileset_editgroup_delete(editgroup_id, ident): + return generic_entity_delete(editgroup_id, 'fileset', ident) + +@app.route('/webcapture//delete', methods=['GET', 'POST']) +@login_required +def webcapture_delete_view(ident): + return generic_entity_delete(None, 'webcapture', ident) + +@app.route('/editgroup//webcapture/edit//delete', methods=['POST']) +def webcapture_edit_delete(editgroup_id, edit_id): + return generic_edit_delete(editgroup_id, 'webcapture', edit_id) + +@app.route('/editgroup//webcapture//delete', methods=['GET', 'POST']) +@login_required +def webcapture_editgroup_delete(editgroup_id, ident): + return generic_entity_delete(editgroup_id, 'webcapture', ident) + @app.route('/release/create', methods=['GET', 'POST']) @login_required def release_create_view(): @@ -430,35 +597,43 @@ def release_create_view(): @app.route('/release//edit', methods=['GET', 'POST']) @login_required -def release_edit(ident): +def release_edit_view(ident): return generic_entity_edit(None, 'release', ident, 'release_edit.html') +@app.route('/release//delete', methods=['GET', 'POST']) +@login_required +def release_delete_view(ident): + return generic_entity_delete(None, 'release', ident) + @app.route('/editgroup//release//edit', methods=['GET', 'POST']) @login_required def release_editgroup_edit(editgroup_id, ident): return generic_entity_edit(editgroup_id, 'release', ident, 'release_edit.html') +@app.route('/editgroup//release//delete', methods=['GET', 'POST']) +@login_required +def release_editgroup_delete(editgroup_id, ident): + return generic_entity_delete(editgroup_id, 'release', ident) + @app.route('/editgroup//release/edit//delete', methods=['POST']) @login_required def release_edit_delete(editgroup_id, edit_id): return generic_edit_delete(editgroup_id, 'release', edit_id) -@app.route('/editgroup//creator/edit//delete', methods=['POST']) -def creator_edit_delete(editgroup_id, edit_id): - return generic_edit_delete(editgroup_id, 'creator', edit_id) - -@app.route('/editgroup//fileset/edit//delete', methods=['POST']) -def fileset_edit_delete(editgroup_id, edit_id): - return generic_edit_delete(editgroup_id, 'fileset', edit_id) - -@app.route('/editgroup//webcapture/edit//delete', methods=['POST']) -def webcapture_edit_delete(editgroup_id, edit_id): - return generic_edit_delete(editgroup_id, 'webcapture', edit_id) +@app.route('/work//delete', methods=['GET', 'POST']) +@login_required +def work_delete_view(ident): + return generic_entity_delete(None, 'work', ident) @app.route('/editgroup//work/edit//delete', methods=['POST']) def work_edit_delete(editgroup_id, edit_id): return generic_edit_delete(editgroup_id, 'work', edit_id) +@app.route('/editgroup//work//delete', methods=['GET', 'POST']) +@login_required +def work_editgroup_delete(editgroup_id, ident): + return generic_entity_delete(editgroup_id, 'work', ident) + ### TOML Views ############################################################## @app.route('/container/create/toml', methods=['GET', 'POST']) @@ -468,7 +643,7 @@ def container_create_toml_view(): @app.route('/container//edit/toml', methods=['GET', 'POST']) @login_required -def container_edit_toml(ident): +def container_edit_toml_view(ident): return generic_entity_toml_edit(None, 'container', ident, 'entity_edit_toml.html') @app.route('/editgroup//container//edit/toml', methods=['GET', 'POST']) @@ -483,7 +658,7 @@ def creator_create_toml_view(): @app.route('/creator//edit/toml', methods=['GET', 'POST']) @login_required -def creator_edit_toml(ident): +def creator_edit_toml_view(ident): return generic_entity_toml_edit(None, 'creator', ident, 'entity_edit_toml.html') @app.route('/editgroup//creator//edit/toml', methods=['GET', 'POST']) @@ -498,7 +673,7 @@ def file_create_toml_view(): @app.route('/file//edit/toml', methods=['GET', 'POST']) @login_required -def file_edit_toml(ident): +def file_edit_toml_view(ident): return generic_entity_toml_edit(None, 'file', ident, 'entity_edit_toml.html') @app.route('/editgroup//file//edit/toml', methods=['GET', 'POST']) @@ -513,7 +688,7 @@ def fileset_create_toml_view(): @app.route('/fileset//edit/toml', methods=['GET', 'POST']) @login_required -def fileset_edit_toml(ident): +def fileset_edit_toml_view(ident): return generic_entity_toml_edit(None, 'fileset', ident, 'entity_edit_toml.html') @app.route('/editgroup//fileset//edit/toml', methods=['GET', 'POST']) @@ -528,7 +703,7 @@ def webcapture_create_toml_view(): @app.route('/webcapture//edit/toml', methods=['GET', 'POST']) @login_required -def webcapture_edit_toml(ident): +def webcapture_edit_toml_view(ident): return generic_entity_toml_edit(None, 'webcapture', ident, 'entity_edit_toml.html') @app.route('/editgroup//webcapture//edit/toml', methods=['GET', 'POST']) @@ -543,7 +718,7 @@ def release_create_toml_view(): @app.route('/release//edit/toml', methods=['GET', 'POST']) @login_required -def release_edit_toml(ident): +def release_edit_toml_view(ident): return generic_entity_toml_edit(None, 'release', ident, 'entity_edit_toml.html') @app.route('/editgroup//release//edit/toml', methods=['GET', 'POST']) @@ -558,7 +733,7 @@ def work_create_toml_view(): @app.route('/work//edit/toml', methods=['GET', 'POST']) @login_required -def work_edit_toml(ident): +def work_edit_toml_view(ident): return generic_entity_toml_edit(None, 'work', ident, 'entity_edit_toml.html') @app.route('/editgroup//work//edit/toml', methods=['GET', 'POST']) @@ -575,7 +750,7 @@ def creator_create_view(): @app.route('/creator//edit', methods=['GET']) @login_required -def creator_edit(ident): +def creator_edit_view(ident): return redirect(f'/creator/{ident}/edit/toml') @app.route('/editgroup//creator//edit', methods=['GET', 'POST']) @@ -590,7 +765,7 @@ def fileset_create_view(): @app.route('/fileset//edit', methods=['GET']) @login_required -def fileset_edit(ident): +def fileset_edit_view(ident): return redirect(f'/fileset/{ident}/edit/toml') @app.route('/editgroup//fileset//edit', methods=['GET', 'POST']) @@ -605,7 +780,7 @@ def webcapture_create_view(): @app.route('/webcapture//edit', methods=['GET']) @login_required -def webcapture_edit(ident): +def webcapture_edit_view(ident): return redirect(f'/webcapture/{ident}/edit/toml') @app.route('/editgroup//webcapture//edit', methods=['GET', 'POST']) @@ -620,7 +795,7 @@ def work_create_view(): @app.route('/work//edit', methods=['GET']) @login_required -def work_edit(ident): +def work_edit_view(ident): return redirect(f'/work/{ident}/edit/toml') @app.route('/editgroup//work//edit', methods=['GET', 'POST']) diff --git a/python/fatcat_web/templates/entity_delete.html b/python/fatcat_web/templates/entity_delete.html new file mode 100644 index 00000000..b2e13af4 --- /dev/null +++ b/python/fatcat_web/templates/entity_delete.html @@ -0,0 +1,49 @@ +{% import "edit_macros.html" as edit_macros %} +{% extends "base.html" %} + +{% block body %} +{% block edit_form_prefix %} +
+

Delete Entity

+ + +{% endblock %} + +

See the catalog + style guide for schema notes, and the editing + tutorial if this is your first time making an edit. + + {{ form.hidden_tag() }} + +

Editgroup Metadata

+ {{ edit_macros.editgroup_dropdown(form, editgroup, potential_editgroups) }} + +

Submit

+ {{ edit_macros.form_field_basic(form.edit_description) }} + This description will be attached to the individual edit, not to the + editgroup as a whole. + +{% block edit_form_suffix %} +

+ +

+ Deletion will be part of the current editgroup, which needs to be submited and + approved before the change is included in the catalog. +

+
+{% endblock %} +{% endblock %} + +{% block postscript %} + + +{% endblock %} diff --git a/python/tests/web_editing.py b/python/tests/web_editing.py index ea244388..8386badb 100644 --- a/python/tests/web_editing.py +++ b/python/tests/web_editing.py @@ -129,6 +129,57 @@ def test_web_file_create(app_admin, api): follow_redirects=True) assert rv.status_code == 200 +def test_web_file_toml_create(app_admin, api): + + eg = quick_eg(api) + + # bogus/bad submit + rv = app_admin.post('/file/create/toml', + data={ + 'editgroup_id': eg.editgroup_id, + }, + follow_redirects=True) + assert rv.status_code == 400 + + # ok/valid submit + rv = app_admin.post('/file/create/toml', + data={ + 'editgroup_id': eg.editgroup_id, + 'toml': """ +size = 12345 +sha1 = "45be56a396c4d03faaa41e055170c23534dec736" + """, + }, + follow_redirects=True) + assert rv.status_code == 200 + + # upper-case SHA-1 + rv = app_admin.post('/file/create/toml', + data={ + 'editgroup_id': eg.editgroup_id, + 'toml': """ +size = 12345 +sha1 = "45BE56A396C4D03FAAA41E055170C23534DEC736" + """, + }, + follow_redirects=True) + assert rv.status_code == 400 + +def test_web_file_delete(app_admin, api): + + eg = quick_eg(api) + + rv = app_admin.get('/file/aaaaaaaaaaaaamztaaaaaaaaam/delete') + assert rv.status_code == 200 + + rv = app_admin.post('/file/aaaaaaaaaaaaamztaaaaaaaaam/delete', + data={ + 'editgroup_id': eg.editgroup_id, + }, + follow_redirects=True) + assert rv.status_code == 200 + # NOTE: did not *accept* the deletion edit + DUMMY_DEMO_ENTITIES = { 'container': 'aaaaaaaaaaaaaeiraaaaaaaaam', 'creator': 'aaaaaaaaaaaaaircaaaaaaaaaq', @@ -186,3 +237,9 @@ def test_web_create_get(app_admin): rv = app_admin.get(f'/{entity_type}/create/toml') assert rv.status_code == 200 + +def test_web_edit_delete(app_admin): + + for entity_type in DUMMY_DEMO_ENTITIES.keys(): + rv = app_admin.get(f'/{entity_type}/{DUMMY_DEMO_ENTITIES[entity_type]}/delete') + assert rv.status_code == 200 -- cgit v1.2.3