From ef7fafdcb664f9c419069b41d743f69382571f98 Mon Sep 17 00:00:00 2001 From: Bryan Newbold Date: Wed, 12 Jun 2019 19:36:10 -0700 Subject: continue large refactors of entity views - container views generic - editgroup edit deletion and re-editing - /editgroup/entity/ident views --- python/fatcat_web/editing_routes.py | 212 +++++++++++++++++------- python/fatcat_web/routes.py | 26 ++- python/fatcat_web/templates/container_edit.html | 4 +- python/fatcat_web/templates/container_view.html | 2 +- python/fatcat_web/templates/edit_macros.html | 8 +- python/fatcat_web/templates/editgroup_view.html | 24 ++- python/fatcat_web/templates/entity_macros.html | 17 +- 7 files changed, 213 insertions(+), 80 deletions(-) diff --git a/python/fatcat_web/editing_routes.py b/python/fatcat_web/editing_routes.py index 6895a4cd..88fb4557 100644 --- a/python/fatcat_web/editing_routes.py +++ b/python/fatcat_web/editing_routes.py @@ -13,6 +13,7 @@ from fatcat_web.auth import handle_token_login, handle_logout, load_user, handle from fatcat_web.cors import crossdomain from fatcat_web.search import * from fatcat_web.forms import * +from fatcat_web.entity_helpers import * ### Helper Methods ########################################################## @@ -49,80 +50,177 @@ def form_editgroup_get_or_create(api, edit_form): ### Views ################################################################### -@app.route('/container/create', methods=['GET', 'POST']) -@login_required -def container_create(): - form = ContainerEntityForm() +def generic_entity_edit(entity_type, edit_template, existing_ident, editgroup_id): + """ + + 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//edit + - /editgroup//container//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: + abort(ae.status) + + # 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() + else: + raise NotImplementedError + if form.is_submitted(): if form.validate_on_submit(): # API on behalf of user user_api = auth_api(session['api_token']) - eg = form_editgroup_get_or_create(user_api, form) - if eg: - # no merge or anything hard to do; just create the entity - entity = form.to_entity() - try: - edit = user_api.create_container(eg.editgroup_id, entity) - except ApiException as ae: - app.log.warning(ae) - abort(ae.status) - # redirect to new entity - return redirect('/container/{}'.format(edit.ident)) + if not editgroup: + editgroup = form_editgroup_get_or_create(user_api, form) + + if editgroup: + # check that editgroup is edit-able + if editgroup.changelog_index != None: + flash("Editgroup already merged") + abort(400) + + 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) + else: + raise NotImplementedError + except ApiException as ae: + app.log.warning(ae) + abort(ae.status) + 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: + if entity_type == 'container': + user_api.delete_container_edit(editgroup.editgroup_id, existing_edit.edit_id) + else: + raise NotImplementedError + except ApiException as ae: + if ae.status == 404: + pass + else: + abort(ae.status) + try: + if entity_type == 'container': + edit = user_api.update_container(editgroup.editgroup_id, existing.ident, existing) + else: + raise NotImplementedError + except ApiException as ae: + app.log.warning(ae) + abort(ae.status) + 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: - editgroup_id = session.get('active_editgroup_id', None) - form.editgroup_id.data = editgroup_id - return render_template('container_create.html', form=form), status + + else: # form is not submitted + if existing: + if entity_type == 'container': + form = ContainerEntityForm.from_entity(existing) + else: + raise NotImplementedError + + if not editgroup_id: + form.editgroup_id.data = session.get('active_editgroup_id', None) + + return render_template(edit_template, form=form, + existing_ident=existing_ident, editgroup=editgroup), status + +def generic_edit_delete(entity_type, editgroup_id, 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) + + # 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) + else: + raise NotImplementedError + except ApiException as ae: + if ae.status == 404: + pass + else: + abort(ae.status) + return redirect("/editgroup/{}".format(editgroup_id)) + + +@app.route('/container/create', methods=['GET', 'POST']) +@login_required +def container_create(): + return generic_entity_edit('container', 'container_create.html', None, None) @app.route('/container//edit', methods=['GET', 'POST']) @login_required def container_edit(ident): - # TODO: prev_rev interlock - try: - entity = api.get_container(ident) - except ApiException as ae: - abort(ae.status) - status = 200 - form = ContainerEntityForm() - if form.is_submitted(): - if form.validate_on_submit(): - # API on behalf of user - user_api = auth_api(session['api_token']) - eg = form_editgroup_get_or_create(user_api, form) - if eg: - # all the tricky logic is in the update method - form.update_entity(entity) - try: - edit = user_api.update_container(eg.editgroup_id, entity.ident, entity) - except ApiException as ae: - app.log.warning(ae) - abort(ae.status) - # redirect to entity revision - # TODO: container_rev_view - return redirect('/container/{}'.format(edit.ident)) - else: - status = 400 - elif form.errors: - status = 400 - app.log.info("form errors (did not validate): {}".format(form.errors)) - else: - form = ContainerEntityForm.from_entity(entity) - if not form.is_submitted(): - editgroup_id = session.get('active_editgroup_id', None) - form.editgroup_id.data = editgroup_id - return render_template('container_edit.html', form=form, entity=entity), status + return generic_entity_edit('container', 'container_edit.html', ident, None) + +@app.route('/editgroup//container//edit', methods=['GET', 'POST']) +@login_required +def container_editgroup_edit(editgroup_id, ident): + return generic_entity_edit('container', 'container_edit.html', ident, editgroup_id) + +@app.route('/editgroup//container/edit//delete', methods=['POST', 'DELETE']) +@login_required +def container_edit_delete(editgroup_id, edit_id): + return generic_edit_delete('container', editgroup_id, edit_id) @app.route('/creator//edit', methods=['GET']) def creator_edit(ident): - try: - entity = api.get_creator(ident) - except ApiException as ae: - abort(ae.status) return render_template('entity_edit.html'), 404 @app.route('/creator/create', methods=['GET']) diff --git a/python/fatcat_web/routes.py b/python/fatcat_web/routes.py index 3dcf05ae..20036608 100644 --- a/python/fatcat_web/routes.py +++ b/python/fatcat_web/routes.py @@ -14,6 +14,7 @@ from fatcat_web.auth import handle_token_login, handle_logout, load_user, handle from fatcat_web.cors import crossdomain from fatcat_web.search import * from fatcat_web.hacks import strip_extlink_xml, wayback_suffix +from fatcat_web.entity_helpers import * ### Generic Entity Views #################################################### @@ -192,10 +193,7 @@ def work_lookup(): @app.route('/container/', methods=['GET']) def container_view(ident): - try: - entity = api.get_container(ident) - except ApiException as ae: - abort(ae.status) + entity = generic_get_entity('container', ident) if entity.issnl: try: @@ -213,7 +211,23 @@ def container_view(ident): if entity.state == "active": entity.es = container_to_elasticsearch(entity, force_bool=False) return render_template('container_view.html', - container=entity, container_stats=stats) + container=entity, editgroup_id=None, container_stats=stats) + +@app.route('/container/rev/', methods=['GET']) +def container_revision_view(ident): + entity = generic_get_entity_revision('container', revision_id) + return render_template('container_view.html', container=entity, editgroup=None) + +@app.route('/editgroup//container/', methods=['GET']) +def container_editgroup_view(editgroup_id, ident): + try: + editgroup = api.get_editgroup(editgroup_id) + except ApiException as ae: + abort(ae.status) + entity, edit = generic_get_editgroup_entity(editgroup, 'container', ident) + if entity.state == "deleted": + return render_template('deleted_entity.html', entity=entity, entity_type="container", editgroup=editgroup) + return render_template('container_view.html', container=entity, editgroup=editgroup) @app.route('/creator/', methods=['GET']) def creator_view(ident): @@ -333,6 +347,7 @@ def editgroup_view(ident): auth_to = dict( submit=False, accept=False, + edit=False, annotate=False, ) if session.get('editor'): @@ -340,6 +355,7 @@ def editgroup_view(ident): auth_to['annotate'] = True if user.is_admin or user.editor_id == eg.editor_id: auth_to['submit'] = True + auth_to['edit'] = True if user.is_admin: auth_to['accept'] = True return render_template('editgroup_view.html', editgroup=eg, diff --git a/python/fatcat_web/templates/container_edit.html b/python/fatcat_web/templates/container_edit.html index 553bedb6..6a08b1ae 100644 --- a/python/fatcat_web/templates/container_edit.html +++ b/python/fatcat_web/templates/container_edit.html @@ -6,12 +6,12 @@

Edit Container Entity

-
+ {% endblock %} {{ form.hidden_tag() }}
- {{ edit_macros.editgroup_dropdown(form) }} + {{ edit_macros.editgroup_dropdown(form, editgroup) }}

The Basics


diff --git a/python/fatcat_web/templates/container_view.html b/python/fatcat_web/templates/container_view.html index 619bd647..ef4335fb 100644 --- a/python/fatcat_web/templates/container_view.html +++ b/python/fatcat_web/templates/container_view.html @@ -124,7 +124,7 @@ {% endif %}
-{{ entity_macros.fatcat_bits(entity, "container", "") }} +{{ entity_macros.fatcat_bits(entity, "container", "", editgroup) }} diff --git a/python/fatcat_web/templates/edit_macros.html b/python/fatcat_web/templates/edit_macros.html index 9bd14596..66da04e7 100644 --- a/python/fatcat_web/templates/edit_macros.html +++ b/python/fatcat_web/templates/edit_macros.html @@ -35,13 +35,13 @@ {%- endmacro %} -{% macro editgroup_dropdown(form) -%} +{% macro editgroup_dropdown(form, editgroup=None) -%}
-
+

Editgroup Meta

-
- {% if editgroup_id %} +
+ {% if editgroup %}

You have an editgroup in progress, and this edit will be included by default. You can override this below. {% else %} diff --git a/python/fatcat_web/templates/editgroup_view.html b/python/fatcat_web/templates/editgroup_view.html index 8b454bb2..52b55d43 100644 --- a/python/fatcat_web/templates/editgroup_view.html +++ b/python/fatcat_web/templates/editgroup_view.html @@ -3,7 +3,7 @@ {% block body %} -{% macro edit_list(edits, entity_type, entity_name) -%} +{% macro edit_list(auth_to, editgroup, edits, entity_type, entity_name) -%}

{{ entity_name }} Edits ({{ edits|count }})

@@ -22,6 +22,14 @@ {% else %} updated {% endif %} + [view edit] + {% if auth_to.edit and not editgroup.changelog_index and not editgroup.submitted %} + [re-edit] + + + + + {% endif %}
{% if edit.revision %} Revision: {{ edit.revision }} @@ -99,13 +107,13 @@ reviewable bundle.

- {{ edit_list(editgroup.edits.releases, "release", "Release") }} - {{ edit_list(editgroup.edits.works, "work", "Work") }} - {{ edit_list(editgroup.edits.containers, "container", "Container") }} - {{ edit_list(editgroup.edits.creators, "creator", "Creator") }} - {{ edit_list(editgroup.edits.files, "file", "File") }} - {{ edit_list(editgroup.edits.filesets, "fileset", "File Set") }} - {{ edit_list(editgroup.edits.webcaptures, "webcapture", "Web Capture") }} + {{ edit_list(auth_to, editgroup, editgroup.edits.releases, "release", "Release") }} + {{ edit_list(auth_to, editgroup, editgroup.edits.works, "work", "Work") }} + {{ edit_list(auth_to, editgroup, editgroup.edits.containers, "container", "Container") }} + {{ edit_list(auth_to, editgroup, editgroup.edits.creators, "creator", "Creator") }} + {{ edit_list(auth_to, editgroup, editgroup.edits.files, "file", "File") }} + {{ edit_list(auth_to, editgroup, editgroup.edits.filesets, "fileset", "File Set") }} + {{ edit_list(auth_to, editgroup, editgroup.edits.webcaptures, "webcapture", "Web Capture") }}

diff --git a/python/fatcat_web/templates/entity_macros.html b/python/fatcat_web/templates/entity_macros.html index a2b2f996..77d4ff81 100644 --- a/python/fatcat_web/templates/entity_macros.html +++ b/python/fatcat_web/templates/entity_macros.html @@ -1,7 +1,18 @@ -{% macro fatcat_bits(entity, entity_type, expand="") -%} +{% macro fatcat_bits(entity, entity_type, expand="", editgroup=None) -%} -{% if entity.state == "wip" %} +{% if entity.state == None and editgroup.editgroup_id %} +
+ Edit In Progress +

You are viewing this entity as of a specific editgroup (which may or may not have been merged yet): + {{ editgroup.editgroup_id }} +

+{% elif entity.state == None and entity.ident == None %} +
+ Revision +

You are viewing a specific revision of an entity. +

+{% elif entity.state == "wip" %}
Work In Progress

This entity has not been "accepted" into the official database yet. @@ -19,7 +30,7 @@

{%- endmacro %} -- cgit v1.2.3