aboutsummaryrefslogtreecommitdiffstats
path: root/python
diff options
context:
space:
mode:
Diffstat (limited to 'python')
-rw-r--r--python/fatcat_web/editing_routes.py212
-rw-r--r--python/fatcat_web/routes.py26
-rw-r--r--python/fatcat_web/templates/container_edit.html4
-rw-r--r--python/fatcat_web/templates/container_view.html2
-rw-r--r--python/fatcat_web/templates/edit_macros.html8
-rw-r--r--python/fatcat_web/templates/editgroup_view.html24
-rw-r--r--python/fatcat_web/templates/entity_macros.html17
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/<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:
+ 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/<ident>/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/<editgroup_id>/container/<ident>/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/<editgroup_id>/container/edit/<edit_id>/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/<ident>/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/<ident>', 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/<revision_id>', 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/<editgroup_id>/container/<ident>', 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/<ident>', 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 @@
<div class="ui segment">
<h1 class="ui header">Edit Container Entity</h1>
-<form class="ui form" id="edit_container_form" method="POST" action="/container/{{ entity.ident }}/edit">
+<form class="ui form" id="edit_container_form" method="POST" action="{% if editgroup %}/editgroup/{{ editgroup.editgroup_id }}{% endif %}/container/{{ existing_ident }}/edit">
{% endblock %}
{{ form.hidden_tag() }}
<br>
- {{ edit_macros.editgroup_dropdown(form) }}
+ {{ edit_macros.editgroup_dropdown(form, editgroup) }}
<h3 class="ui dividing header">The Basics</h3>
<br>
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 %}
</div>
-{{ entity_macros.fatcat_bits(entity, "container", "") }}
+{{ entity_macros.fatcat_bits(entity, "container", "", editgroup) }}
</div>
</div>
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 @@
</div>
{%- endmacro %}
-{% macro editgroup_dropdown(form) -%}
+{% macro editgroup_dropdown(form, editgroup=None) -%}
<div class="ui accordion">
- <div class="{% if not editgroup_id %}active{% endif %} title">
+ <div class="{% if not editgroup %}active{% endif %} title">
<h3><i class="dropdown icon"></i>Editgroup Meta</h3>
</div>
- <div class="{% if not editgroup_id %}active{% endif %} content">
- {% if editgroup_id %}
+ <div class="{% if not editgroup %}active{% endif %} content">
+ {% if editgroup %}
<p>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) -%}
<div class="{% if edits %}active{% endif %} title">
<h3><i class="dropdown icon"></i>{{ entity_name }} Edits ({{ edits|count }})</h3>
</div><div class="{% if edits %}active{% endif %} content" style="padding-bottom: 0.5em;">
@@ -22,6 +22,14 @@
{% else %}
updated
{% endif %}
+ <a href="/editgroup/{{ editgroup.editgroup_id }}/{{ entity_type }}/{{ edit.ident }}">[view edit]</a>
+ {% if auth_to.edit and not editgroup.changelog_index and not editgroup.submitted %}
+ <a href="/editgroup/{{ editgroup.editgroup_id }}/{{ entity_type }}/{{ edit.ident }}/edit" style="color: green;">[re-edit]</a>
+ <form id="submit_edit_delete" method="POST" action="/editgroup/{{ editgroup.editgroup_id }}/{{ entity_type }}/edit/{{ edit.edit_id }}/delete" style="display:inline;">
+ <input type="hidden" name="csrf_token" value="{{ csrf_token() }}"/>
+ <input type="submit" value="[delete-edit]" style="background:none; color: red; border: none; padding:9;font-weight:bold;cursor:pointer;"></input>
+ </form>
+ {% endif %}
</div>
{% if edit.revision %}
Revision: <small><code>{{ edit.revision }}</code></small>
@@ -99,13 +107,13 @@ reviewable bundle.
<br><br clear="all">
<div class="ui styled fluid accordion">
- {{ 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") }}
</div>
<br>
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 %}
+<div class="ui segment pink inverted attached">
+ <b>Edit In Progress</b>
+ <p>You are viewing this entity as of a specific editgroup (which may or may not have been merged yet):
+ <b><a href="/editgroup/{{ editgroup.editgroup_id }}">{{ editgroup.editgroup_id }}</a></b>
+</div>
+{% elif entity.state == None and entity.ident == None %}
+<div class="ui segment pink inverted attached">
+ <b>Revision</b>
+ <p>You are viewing a specific revision of an entity.
+</div>
+{% elif entity.state == "wip" %}
<div class="ui segment pink inverted attached">
<b>Work In Progress</b>
<p>This entity has not been "accepted" into the official database yet.
@@ -19,7 +30,7 @@
</div>
<div class="two ui buttons bottom attached">
- <a href="/{{ entity_type }}/{{ entity.ident }}/edit" class="ui blue button">Edit Metadata</a>
+ <a href="{% if editgroup %}/editgroup/{{ editgroup.editgroup_id }}{% endif %}/{{ entity_type }}/{{ entity.ident }}/edit" class="ui blue button">Edit Metadata</a>
<a href="/{{ entity_type }}/{{ entity.ident }}/history" class="ui button">View History</a>
</div>
{%- endmacro %}