From e7ad9a390584ac9df0f7c03dc687e38ca4e073e3 Mon Sep 17 00:00:00 2001 From: Bryan Newbold Date: Wed, 17 Nov 2021 20:23:30 -0800 Subject: initial implementation of editgroup 'diff' for review --- python/fatcat_web/entity_helpers.py | 71 ++++++++++++++++++++++- python/fatcat_web/routes.py | 30 ++++++++++ python/fatcat_web/templates/editgroup_diff.html | 77 +++++++++++++++++++++++++ python/fatcat_web/templates/editgroup_view.html | 11 ++-- 4 files changed, 183 insertions(+), 6 deletions(-) create mode 100644 python/fatcat_web/templates/editgroup_diff.html diff --git a/python/fatcat_web/entity_helpers.py b/python/fatcat_web/entity_helpers.py index 86543ee3..bf81dfce 100644 --- a/python/fatcat_web/entity_helpers.py +++ b/python/fatcat_web/entity_helpers.py @@ -1,4 +1,5 @@ -from typing import Any, Tuple +import difflib +from typing import Any, Dict, Tuple from fatcat_openapi_client import ( ContainerEntity, @@ -17,6 +18,7 @@ from flask import abort from fatcat_tools.transforms import ( container_to_elasticsearch, + entity_to_toml, file_to_elasticsearch, release_to_elasticsearch, ) @@ -188,7 +190,7 @@ def generic_get_entity_revision(entity_type: str, revision_id: str) -> Any: elif entity_type == "work": return enrich_work_entity(api.get_work_revision(revision_id)) else: - raise NotImplementedError + raise NotImplementedError(f"entity_type: {entity_type}") except ApiException as ae: abort(ae.status) except ApiValueError: @@ -258,3 +260,68 @@ def generic_get_editgroup_entity( entity.ident = ident return entity, edit + + +def _entity_edit_diff(entity_type: str, entity_edit: EntityEdit) -> Dict[str, Any]: + """ + entity_edit + ident + revision + prev_revision + redirect_ident + """ + pop_fields = ["revision", "state"] + new_rev = generic_get_entity_revision(entity_type, entity_edit.revision) + new_toml = entity_to_toml(new_rev, pop_fields=pop_fields) + if entity_edit.prev_revision: + old_rev = generic_get_entity_revision(entity_type, entity_edit.prev_revision) + old_toml = entity_to_toml(old_rev, pop_fields=pop_fields) + fromdesc = f"/{entity_type}/rev/{entity_edit.prev_revision}.toml" + else: + old_toml = "" + fromdesc = "(created)" + + # differ = difflib.HtmlDiff(tabsize=4) + # html_table = differ.make_table( + # old_toml.split('\n'), + # new_toml.split('\n'), + # fromdesc=fromdesc, + # todesc=entity_edit.revision, + # context=True, + # numlines=3, + # ) + # return dict(html_table=html_table) + diff_lines = list( + difflib.unified_diff( + old_toml.split("\n"), + new_toml.split("\n"), + fromfile=fromdesc, + tofile=f"/{entity_type}/rev/{entity_edit.revision}.toml", + ) + ) + return dict(diff_lines=diff_lines) + + +def editgroup_get_diffs(editgroup: Editgroup) -> Dict[str, Any]: + diffs: Dict[str, Any] = {} + + for entity_type in [ + "container", + "creator", + "release", + "work", + "file", + "fileset", + "webcapture", + ]: + edits = getattr(editgroup.edits, entity_type + "s") or [] + diffs[entity_type] = {} + for ed in edits: + # only for creation and update + if ed.revision and not ed.redirect_ident: + diffs[entity_type][ed.ident] = _entity_edit_diff(entity_type, ed) + else: + diffs[entity_type][ed.ident] = None + # XXX: + print(diffs.keys()) + return diffs diff --git a/python/fatcat_web/routes.py b/python/fatcat_web/routes.py index 3d2c68cd..f180e339 100644 --- a/python/fatcat_web/routes.py +++ b/python/fatcat_web/routes.py @@ -41,6 +41,7 @@ from fatcat_web.auth import ( ) from fatcat_web.cors import crossdomain from fatcat_web.entity_helpers import ( + editgroup_get_diffs, generic_get_editgroup_entity, generic_get_entity, generic_get_entity_revision, @@ -689,6 +690,35 @@ def editgroup_view(ident: str) -> AnyResponse: return render_template("editgroup_view.html", editgroup=eg, auth_to=auth_to) +@app.route("/editgroup//diff", methods=["GET"]) +def editgroup_diff_view(ident: str) -> AnyResponse: + try: + eg = api.get_editgroup(str(ident)) + eg.editor = api.get_editor(eg.editor_id) + eg.annotations = api.get_editgroup_annotations(eg.editgroup_id, expand="editors") + except ApiException as ae: + abort(ae.status) + # TODO: idomatic check for login? + auth_to = dict( + submit=False, + accept=False, + edit=False, + annotate=False, + ) + if session.get("editor"): + user = load_user(session["editor"]["editor_id"]) + 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 + diffs = editgroup_get_diffs(eg) + return render_template( + "editgroup_diff.html", editgroup=eg, auth_to=auth_to, editgroup_diffs=diffs + ) + + @app.route("/editgroup//annotation", methods=["POST"]) @login_required def editgroup_create_annotation(ident: str) -> AnyResponse: diff --git a/python/fatcat_web/templates/editgroup_diff.html b/python/fatcat_web/templates/editgroup_diff.html new file mode 100644 index 00000000..de6a800d --- /dev/null +++ b/python/fatcat_web/templates/editgroup_diff.html @@ -0,0 +1,77 @@ +{% extends "editgroup_view.html" %} + +{% macro edit_diff_list(auth_to, editgroup, edits, diffs, entity_type, entity_name) -%} +{% if edits %} +

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

+
+
+ {% for edit in edits %} +
+
+
+ [view] + {% if auth_to.edit and not editgroup.changelog_index and not editgroup.submitted %} +
[re-edit] +
+
+ + +
+ {% endif %} +
+
+ {{ entity_type }}_{{ edit.ident }} + {% if edit.redirect_ident %} + => redirect to {{ entity_type }}/{{ edit.redirect_ident }} + {% elif not edit.revision %} + deleted + {% elif not edit.prev_revision %} + created + {% else %} + updated + {% endif %} +
+ {% if edit.revision %} + Revision: {{ edit.revision }} + {% endif %} + {% if edit.extra %} + {{ entity_macros.extra_metadata(edit.extra) }} + {% endif %} + {% if edit.revision and not edit.redirect_ident and edit.ident in diffs %} +
+ {% for line in diffs[edit.ident]['diff_lines'] %} + {% set line_space = false %} + {% if line.startswith('@@') or line.startswith('---') or line.startswith('+++') %} + {% set line_color = "lightblue" %} + {% elif line.startswith('+') %} + {% set line_color = "lightgreen" %} + {% elif line.startswith('-') %} + {% set line_color = "#ffa3a3" %} + {% else %} + {% set line_color = "#ddd" %} + {% set line_space = true %} + {% endif %} +
{% if line_space %} {% endif %}{{ line.strip() }}
+ {% endfor %} +
+ {% endif %} +
+
+ {% endfor %} +
+{% endif %} +{%- endmacro %} + +{% block title %}Editgroup diff{% endblock %} + +{% block editgroupedits %} +

All Entity Change Diffs

+{{ edit_diff_list(auth_to, editgroup, editgroup.edits.releases, editgroup_diffs.release, "release", "Release") }} +{{ edit_diff_list(auth_to, editgroup, editgroup.edits.works, editgroup_diffs.work, "work", "Work") }} +{{ edit_diff_list(auth_to, editgroup, editgroup.edits.containers, editgroup_diffs.container, "container", "Container") }} +{{ edit_diff_list(auth_to, editgroup, editgroup.edits.creators, editgroup_diffs.creator, "creator", "Creator") }} +{{ edit_diff_list(auth_to, editgroup, editgroup.edits.files, editgroup_diffs.file, "file", "File") }} +{{ edit_diff_list(auth_to, editgroup, editgroup.edits.filesets, editgroup_diffs.fileset, "fileset", "File Set") }} +{{ edit_diff_list(auth_to, editgroup, editgroup.edits.webcaptures, editgroup_diffs.webcapture, "webcapture", "Web Capture") }} +{% endblock %} + diff --git a/python/fatcat_web/templates/editgroup_view.html b/python/fatcat_web/templates/editgroup_view.html index e1af719d..de904c2a 100644 --- a/python/fatcat_web/templates/editgroup_view.html +++ b/python/fatcat_web/templates/editgroup_view.html @@ -1,10 +1,6 @@ {% extends "base.html" %} {% import "entity_macros.html" as entity_macros %} -{% block title %}Editgroup{% endblock %} - -{% block body %} - {% macro edit_list(auth_to, editgroup, edits, entity_type, entity_name) -%}

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

@@ -49,6 +45,9 @@
{%- endmacro %} +{% block title %}Editgroup{% endblock %} + +{% block body %} {# extended by changelog_entry #} {% block editgroupheader %} @@ -170,6 +169,7 @@ {{ entity_macros.extra_metadata(editgroup.extra) }} {% endif %} +{% block editgroupedits %}

All Entity Changes

{{ edit_list(auth_to, editgroup, editgroup.edits.releases, "release", "Release") }} @@ -183,8 +183,10 @@
As JSON via API
+{% endblock %}
+{% block editgroupannotations %}

Comments and Annotations

{% for annotation in editgroup.annotations|reverse %}
@@ -241,6 +243,7 @@
{% endif %} +{% endblock %} {% endblock %} -- cgit v1.2.3