From 10cf5fd785393ac8786bf76f9a6a4825496e6bf6 Mon Sep 17 00:00:00 2001 From: Kishore Chitrapu <44282098+kvchitrapu@users.noreply.github.com> Date: Wed, 22 Feb 2023 00:13:36 -0500 Subject: [PATCH] [proofing] Add partial work for search+replace ## Tests 1. built container with make docker-start 2. checked Texts, Dictionaries, and Proofing pages. 3. tested `proofing > project > edit > search` page 4. tested `proofing > project > edit > search and replace` page ## To do 1. Test actual `search and replace`. I could not find a pre-existing text in db to test this feature. 2. add support in translation files --- ambuda/templates/proofing/projects/edit.html | 2 + .../templates/proofing/projects/replace.html | 47 ++++++++++++++ ambuda/views/proofing/project.py | 65 +++++++++++++++++++ 3 files changed, 114 insertions(+) create mode 100644 ambuda/templates/proofing/projects/replace.html diff --git a/ambuda/templates/proofing/projects/edit.html b/ambuda/templates/proofing/projects/edit.html index 71fbe0b8..988a18b7 100644 --- a/ambuda/templates/proofing/projects/edit.html +++ b/ambuda/templates/proofing/projects/edit.html @@ -15,12 +15,14 @@ {{ m.project_nav(project=project, active='edit') }} {% set search_url = url_for("proofing.project.search", slug=project.slug) %} +{% set replace_url = url_for("proofing.project.replace", slug=project.slug) %} {% set ocr_url = url_for("proofing.project.batch_ocr", slug=project.slug) %}
diff --git a/ambuda/templates/proofing/projects/replace.html b/ambuda/templates/proofing/projects/replace.html new file mode 100644 index 00000000..3bbb8f98 --- /dev/null +++ b/ambuda/templates/proofing/projects/replace.html @@ -0,0 +1,47 @@ +{% extends 'proofing/base.html' %} +{% from "macros/forms.html" import field %} +{% import "macros/proofing.html" as m %} + +{% block title %}Search and Replace {{ project.title }} | Ambuda{% endblock %} + +{% block content %} + +{{ m.project_header_nested('Search and Replace', project) }} +{{ m.project_nav(project=project, active='edit') }} + +
+

Use this simple search and replace form to make edits across this project.

+
+ +
+ {{ field(form.query) }} + {{ field(form.replace) }} + +
+ +{% if query %} +
+ +{% macro sp(s, p, n) %}{% if n == 1 %}{{ s }}{% else %}{{ p }}{% endif %}{% endmacro %} + +{% set nr = results|length %} +

Found {{ nr }} {{ sp("page", "pages", nr) }} that {{ sp("contains", "contain", nr) }} {{ query }}.

+ + + +
+{% endif %} +{% endblock %} \ No newline at end of file diff --git a/ambuda/views/proofing/project.py b/ambuda/views/proofing/project.py index 6e7f554b..9a375790 100644 --- a/ambuda/views/proofing/project.py +++ b/ambuda/views/proofing/project.py @@ -96,6 +96,13 @@ class DeleteProjectForm(FlaskForm): slug = StringField("Slug", validators=[DataRequired()]) +class ReplaceForm(SearchForm): + class Meta: + csrf = False + + replace = StringField(_l("Replace"), validators=[DataRequired()]) + + @bp.route("//") def summary(slug): """Show basic information about the project.""" @@ -279,6 +286,64 @@ def search(slug): ) +@bp.route("//replace") +@login_required +def replace(slug): + """Search and replace a string across all of the project's pages. + + This is useful to replace a string across the project in one shot. + """ + project_ = q.project(slug) + if project_ is None: + abort(404) + + form = ReplaceForm(request.args) + if not form.validate(): + return render_template( + "proofing/projects/replace.html", project=project_, form=form + ) + + # search for "query" string and replace with "update" string + query = form.query.data + update = form.replace.data + + results = [] + for page_ in project_.pages: + if not page_.revisions: + continue + + matches = [] + + latest = page_.revisions[-1] + for line in latest.content.splitlines(): + if query in line: + matches.append( + { + "query": escape(line).replace( + query, Markup(f"{escape(query)}") + ), + "update": escape(line).replace( + query, Markup(f"{escape(update)}") + ), + } + ) + if matches: + results.append( + { + "slug": page_.slug, + "matches": matches, + } + ) + return render_template( + "proofing/projects/replace.html", + project=project_, + form=form, + query=query, + update=update, + results=results, + ) + + @bp.route("//batch-ocr", methods=["GET", "POST"]) @p2_required def batch_ocr(slug):