diff options
-rw-r--r-- | python/fatcat_web/entity_helpers.py | 53 | ||||
-rw-r--r-- | python/fatcat_web/templates/editgroup_diff.html | 52 | ||||
-rw-r--r-- | python/fatcat_web/templates/editgroup_view.html | 62 | ||||
-rw-r--r-- | python/tests/web_editgroup.py | 8 |
4 files changed, 83 insertions, 92 deletions
diff --git a/python/fatcat_web/entity_helpers.py b/python/fatcat_web/entity_helpers.py index bf81dfce..24f380c8 100644 --- a/python/fatcat_web/entity_helpers.py +++ b/python/fatcat_web/entity_helpers.py @@ -1,5 +1,5 @@ import difflib -from typing import Any, Dict, Tuple +from typing import Any, Dict, List, Tuple from fatcat_openapi_client import ( ContainerEntity, @@ -262,47 +262,52 @@ def generic_get_editgroup_entity( return entity, edit -def _entity_edit_diff(entity_type: str, entity_edit: EntityEdit) -> Dict[str, Any]: +def _entity_edit_diff(entity_type: str, entity_edit: EntityEdit) -> List[str]: """ - entity_edit - ident - revision - prev_revision - redirect_ident + Helper to generate diff lines for a single entity edit. + + Schema of entity_edit (as a reminder): + + 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) + new_toml = entity_to_toml(new_rev, pop_fields=pop_fields).split("\n") + if len(new_toml) == 1 and not new_toml[0].strip(): + new_toml = [] 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) + old_toml = entity_to_toml(old_rev, pop_fields=pop_fields).split("\n") fromdesc = f"/{entity_type}/rev/{entity_edit.prev_revision}.toml" else: - old_toml = "" + 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"), + old_toml, + new_toml, fromfile=fromdesc, tofile=f"/{entity_type}/rev/{entity_edit.revision}.toml", ) ) - return dict(diff_lines=diff_lines) + return diff_lines def editgroup_get_diffs(editgroup: Editgroup) -> Dict[str, Any]: + """ + Fetches before/after entity revisions, and computes "diffs" of TOML representations. + + Returns a dict with entity type (pluralized, like "files"), then within + that a dict with entity ident (without prefix) containing a list of + strings, one per line of the "unified diff" format. If there is no diff for + an edited entity (eg, it was or redirected), instead `None` is returned for + that entity. + """ diffs: Dict[str, Any] = {} for entity_type in [ @@ -322,6 +327,4 @@ def editgroup_get_diffs(editgroup: Editgroup) -> Dict[str, Any]: 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/templates/editgroup_diff.html b/python/fatcat_web/templates/editgroup_diff.html index de6a800d..4b32fbf5 100644 --- a/python/fatcat_web/templates/editgroup_diff.html +++ b/python/fatcat_web/templates/editgroup_diff.html @@ -2,56 +2,31 @@ {% macro edit_diff_list(auth_to, editgroup, edits, diffs, entity_type, entity_name) -%} {% if edits %} - <h3>{{ entity_name }} Edits ({{ edits|count }})</h3> + <h3>{{ entity_name }} Edit Diffs ({{ edits|count }})</h3> <hr> <div class="ui divided list"> {% for edit in edits %} - <div class="item"> + <div class="item" id="{{ entity_type }}_{{ edit.ident }}"> <div class="content" style="padding-bottom: 0.5em;"> - <div style="float: right; font-weight: bold;"> - <a href="/editgroup/{{ editgroup.editgroup_id }}/{{ entity_type }}/{{ edit.ident }}">[view]</a> - {% if auth_to.edit and not editgroup.changelog_index and not editgroup.submitted %} - <br><a href="/editgroup/{{ editgroup.editgroup_id }}/{{ entity_type }}/{{ edit.ident }}/edit" style="color: green;">[re-edit]</a> - <br> - <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]" style="background:none; color: red; border: none; font-weight:bold; cursor:pointer; padding: 0;"></input> - </form> - {% endif %} - </div> - <div class="header"> - <a href="/{{ entity_type }}/{{ edit.ident }}">{{ entity_type }}_{{ edit.ident }}</a> - {% if edit.redirect_ident %} - => redirect to <a href="/{{ entity_type }}/{{ edit.redirect_ident }}">{{ entity_type }}/{{ edit.redirect_ident }}</a> - {% elif not edit.revision %} - deleted - {% elif not edit.prev_revision %} - created - {% else %} - updated - {% endif %} - </div> - {% if edit.revision %} - Revision: <small><code><a href="/{{ entity_type }}/rev/{{ edit.revision }}">{{ edit.revision }}</a></code></small> - {% endif %} + {{ entity_edit_header(auth_to, editgroup, edit, entity_type, entity_name) }} {% if edit.extra %} {{ entity_macros.extra_metadata(edit.extra) }} {% endif %} - {% if edit.revision and not edit.redirect_ident and edit.ident in diffs %} - <div style="border: 2px solid black; overflow-x:scroll; margin: 0.5em;"> - {% for line in diffs[edit.ident]['diff_lines'] %} + {% if edit.revision and not edit.redirect_ident and edit.ident in diffs and diffs[edit.ident] != None %} + <div style="border: 1px solid black; font-size: smaller; font-color: #222; word-break: break-all; margin-top: 0.5em; margin-bottom: 0.5em;"> + {% for line in diffs[edit.ident] %} {% set line_space = false %} {% if line.startswith('@@') or line.startswith('---') or line.startswith('+++') %} - {% set line_color = "lightblue" %} + {% set line_color = "lightblue" %}{# a light blue #} {% elif line.startswith('+') %} - {% set line_color = "lightgreen" %} + {% set line_color = "#a4efa4" %}{# a light green #} {% elif line.startswith('-') %} - {% set line_color = "#ffa3a3" %} + {% set line_color = "#ffa3a3" %}{# a light red #} {% else %} - {% set line_color = "#ddd" %} + {% set line_color = "#eee" %}{# almost white #} {% set line_space = true %} {% endif %} - <pre style="background-color: {{ line_color }}; margin: 0px;">{% if line_space %} {% endif %}{{ line.strip() }}</pre> + <pre style="background-color: {{ line_color }}; white-space: pre-wrap; margin: 0px;">{% if line_space %} {% endif %}{{ line.strip() }}</pre> {% endfor %} </div> {% endif %} @@ -62,10 +37,11 @@ {% endif %} {%- endmacro %} -{% block title %}Editgroup diff{% endblock %} +{% block title %}Editgroup Diff{% endblock %} + +{% block pagetitle %}Editgroup Diff{% endblock %} {% block editgroupedits %} -<h3 class="ui header">All Entity Change Diffs</h3> {{ 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") }} diff --git a/python/fatcat_web/templates/editgroup_view.html b/python/fatcat_web/templates/editgroup_view.html index de904c2a..0142a46b 100644 --- a/python/fatcat_web/templates/editgroup_view.html +++ b/python/fatcat_web/templates/editgroup_view.html @@ -1,40 +1,45 @@ {% extends "base.html" %} {% import "entity_macros.html" as entity_macros %} +{% macro entity_edit_header(auth_to, editgroup, edit, entity_type, entity_name) -%} + <div style="float: right; font-weight: bold;"> + <a href="/editgroup/{{ editgroup.editgroup_id }}/{{ entity_type }}/{{ edit.ident }}">[view]</a> + <a href="/editgroup/{{ editgroup.editgroup_id }}/diff#{{ entity_type }}_{{ edit.ident }}">[diff]</a> + {% if auth_to.edit and not editgroup.changelog_index and not editgroup.submitted %} + <br><a href="/editgroup/{{ editgroup.editgroup_id }}/{{ entity_type }}/{{ edit.ident }}/edit" style="color: green;">[re-edit]</a> + <br> + <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]" style="background:none; color: red; border: none; font-weight:bold; cursor:pointer; padding: 0;"></input> + </form> + {% endif %} + </div> + <div class="header"> + <a href="/{{ entity_type }}/{{ edit.ident }}">{{ entity_type }}_{{ edit.ident }}</a> + {% if edit.redirect_ident %} + => redirect to <a href="/{{ entity_type }}/{{ edit.redirect_ident }}">{{ entity_type }}/{{ edit.redirect_ident }}</a> + {% elif not edit.revision %} + deleted + {% elif not edit.prev_revision %} + created + {% else %} + updated + {% endif %} + </div> + {% if edit.revision %} + Revision: <small><code><a href="/{{ entity_type }}/rev/{{ edit.revision }}">{{ edit.revision }}</a></code></small> + {% endif %} +{%- endmacro %} + {% 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;"> <div class="ui divided list"> {% for edit in edits %} - <div class="item"> + <div class="item" id="{{ entity_type }}_{{ edit.ident }}"> <div class="content" style="padding-bottom: 0.5em;"> - <div style="float: right; font-weight: bold;"> - <a href="/editgroup/{{ editgroup.editgroup_id }}/{{ entity_type }}/{{ edit.ident }}">[view]</a> - {% if auth_to.edit and not editgroup.changelog_index and not editgroup.submitted %} - <br><a href="/editgroup/{{ editgroup.editgroup_id }}/{{ entity_type }}/{{ edit.ident }}/edit" style="color: green;">[re-edit]</a> - <br> - <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]" style="background:none; color: red; border: none; font-weight:bold; cursor:pointer; padding: 0;"></input> - </form> - {% endif %} - </div> - <div class="header"> - <a href="/{{ entity_type }}/{{ edit.ident }}">{{ entity_type }}_{{ edit.ident }}</a> - {% if edit.redirect_ident %} - => redirect to <a href="/{{ entity_type }}/{{ edit.redirect_ident }}">{{ entity_type }}/{{ edit.redirect_ident }}</a> - {% elif not edit.revision %} - deleted - {% elif not edit.prev_revision %} - created - {% else %} - updated - {% endif %} - </div> - {% if edit.revision %} - Revision: <small><code><a href="/{{ entity_type }}/rev/{{ edit.revision }}">{{ edit.revision }}</a></code></small> - {% endif %} + {{ entity_edit_header(auth_to, editgroup, edit, entity_type, entity_name) }} {% if edit.extra %} {{ entity_macros.extra_metadata(edit.extra) }} {% endif %} @@ -51,11 +56,10 @@ {# extended by changelog_entry #} {% block editgroupheader %} -<h1 class="ui header">Editgroup +<h1 class="ui header">{% block pagetitle %}Editgroup{% endblock %} <span class="sub header"><code>editgroup_{{ editgroup.editgroup_id }}</code></span></h1> {% if not auth_to.submit %} -<br clear="all"> <div class="ui info small message"> <div class="header"> What is an editgroup? diff --git a/python/tests/web_editgroup.py b/python/tests/web_editgroup.py index 62a5df2e..906c18e6 100644 --- a/python/tests/web_editgroup.py +++ b/python/tests/web_editgroup.py @@ -5,8 +5,16 @@ def test_editgroup_basics(app): rv = app.get("/editgroup/aaaaaaaaaaaabo53aaaaaaaaae") assert rv.status_code == 200 + rv = app.get("/editgroup/aaaaaaaaaaaabo53aaaaaaaaae/diff") + assert rv.status_code == 200 + rv = app.get("/editgroup/aaaaaaaaaaaabo53aaaaaaaaa4/diff") + assert rv.status_code == 200 + rv = app.get("/editgroup/aaaaaaaaaaaabo53aaaaaaaaaq/diff") + assert rv.status_code == 200 rv = app.get("/editgroup/ccccccccccccccccccccccccca") assert rv.status_code == 404 + rv = app.get("/editgroup/ccccccccccccccccccccccccca/diff") + assert rv.status_code == 404 rv = app.get("/editor/aaaaaaaaaaaabkvkaaaaaaaaae") assert rv.status_code == 200 |