We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
1.8.0 translation feedback: Focal upgrade warning
## Description

AO [suggested](https://weblate.securedrop.org/translate/securedrop/securedrop/en/?checksum=c775f74150ac3872) changing `A manual update is urgently required to remain safe.` to `A manual upgrade is urgently required to remain safe.` in:

```
<strong>Critical Security:</strong>&nbsp;&nbsp;The operating system used by your SecureDrop servers 
will reach its end-of-life on April 30, 2021. A manual update is urgently required to remain safe. 
Please contact your adminstrator. <a href="//securedrop.org/xenial-eol" rel="noreferrer">Learn More</a>
```

as well as [here](https://weblate.securedrop.org/translate/securedrop/securedrop/en/?checksum=60e0284e103e2c51):
```
<strong>Critical Security:</strong>&nbsp;&nbsp;The operating system used by your SecureDrop servers 
has reached its end-of-life. A manual update is required to re-enable the Source Interface and remain safe. 
Please contact your administrator. <a href="//securedrop.org/xenial-eol" rel="noreferrer">Learn More</a>
```

There's also a typo in the first string: "adminstrator" needs another "i".



--- END ISSUE ---

Below are some code segments, each from a relevant file. One or more of these files may contain bugs.
--- BEGIN FILES ---
Path: `securedrop/journalist_app/col.py`
Content:
```
1 # -*- coding: utf-8 -*-
2 
3 from pathlib import Path
4 
5 from flask import (
6     Blueprint,
7     abort,
8     current_app,
9     flash,
10     g,
11     redirect,
12     render_template,
13     request,
14     send_file,
15     url_for,
16     Markup,
17     escape,
18 )
19 import werkzeug
20 from flask_babel import gettext
21 from sqlalchemy.orm.exc import NoResultFound
22 
23 from db import db
24 from models import Reply, Submission
25 from journalist_app.forms import ReplyForm
26 from journalist_app.utils import (make_star_true, make_star_false, get_source,
27                                   delete_collection, col_download_unread,
28                                   col_download_all, col_star, col_un_star,
29                                   col_delete, col_delete_data, mark_seen)
30 from sdconfig import SDConfig
31 
32 
33 def make_blueprint(config: SDConfig) -> Blueprint:
34     view = Blueprint('col', __name__)
35 
36     @view.route('/add_star/<filesystem_id>', methods=('POST',))
37     def add_star(filesystem_id: str) -> werkzeug.Response:
38         make_star_true(filesystem_id)
39         db.session.commit()
40         return redirect(url_for('main.index'))
41 
42     @view.route("/remove_star/<filesystem_id>", methods=('POST',))
43     def remove_star(filesystem_id: str) -> werkzeug.Response:
44         make_star_false(filesystem_id)
45         db.session.commit()
46         return redirect(url_for('main.index'))
47 
48     @view.route('/<filesystem_id>')
49     def col(filesystem_id: str) -> str:
50         form = ReplyForm()
51         source = get_source(filesystem_id)
52         source.has_key = current_app.crypto_util.get_fingerprint(filesystem_id)
53         return render_template("col.html", filesystem_id=filesystem_id,
54                                source=source, form=form)
55 
56     @view.route('/delete/<filesystem_id>', methods=('POST',))
57     def delete_single(filesystem_id: str) -> werkzeug.Response:
58         """deleting a single collection from its /col page"""
59         source = get_source(filesystem_id)
60         try:
61             delete_collection(filesystem_id)
62         except ValueError as e:
63             current_app.logger.error("error deleting collection: %s", e)
64             abort(500)
65 
66         flash(
67             Markup(
68                 "<b>{}</b> {}".format(
69                     # Translators: Here, "Success!" appears before a message
70                     # confirming the success of an operation.
71                     escape(gettext("Success!")),
72                     escape(gettext(
73                         "The account and data for the source {} has been deleted.").format(
74                             source.journalist_designation))
75                 )
76             ), 'success')
77 
78         return redirect(url_for('main.index'))
79 
80     @view.route('/process', methods=('POST',))
81     def process() -> werkzeug.Response:
82         actions = {'download-unread': col_download_unread,
83                    'download-all': col_download_all, 'star': col_star,
84                    'un-star': col_un_star, 'delete': col_delete,
85                    'delete-data': col_delete_data}
86         if 'cols_selected' not in request.form:
87             flash(
88                 Markup("<b>{}</b> {}".format(
89                     # Translators: Here, "Nothing Selected" appears before a message
90                     # asking the user to select one or more items.
91                     escape(gettext('Nothing Selected')),
92                     escape(gettext('You must select one or more items.'))
93                     )
94                 ), 'error')
95             return redirect(url_for('main.index'))
96 
97         # getlist is cgi.FieldStorage.getlist
98         cols_selected = request.form.getlist('cols_selected')
99         action = request.form['action']
100 
101         if action not in actions:
102             return abort(500)
103 
104         method = actions[action]
105         return method(cols_selected)
106 
107     @view.route('/<filesystem_id>/<fn>')
108     def download_single_file(filesystem_id: str, fn: str) -> werkzeug.Response:
109         """
110         Marks the file being download (the file being downloaded is either a submission message,
111         submission file attachement, or journalist reply) as seen by the current logged-in user and
112         send the file to a client to be saved or opened.
113         """
114         if '..' in fn or fn.startswith('/'):
115             abort(404)
116 
117         file = current_app.storage.path(filesystem_id, fn)
118         if not Path(file).is_file():
119             flash(
120                 gettext(
121                     "Your download failed because a file could not be found. An admin can find "
122                     + "more information in the system and monitoring logs."
123                 ),
124                 "error"
125             )
126             current_app.logger.error("File {} not found".format(file))
127             return redirect(url_for("col.col", filesystem_id=filesystem_id))
128 
129         # mark as seen by the current user
130         try:
131             journalist = g.get("user")
132             if fn.endswith("reply.gpg"):
133                 reply = Reply.query.filter(Reply.filename == fn).one()
134                 mark_seen([reply], journalist)
135             elif fn.endswith("-doc.gz.gpg") or fn.endswith("doc.zip.gpg"):
136                 file = Submission.query.filter(Submission.filename == fn).one()
137                 mark_seen([file], journalist)
138             else:
139                 message = Submission.query.filter(Submission.filename == fn).one()
140                 mark_seen([message], journalist)
141         except NoResultFound as e:
142             current_app.logger.error("Could not mark {} as seen: {}".format(fn, e))
143 
144         return send_file(current_app.storage.path(filesystem_id, fn),
145                          mimetype="application/pgp-encrypted")
146 
147     return view
148
```
--- END FILES ---

Please first localize the bug based on the issue statement, and then generate a patch according to the `git diff` format fenced by three backticks.

Here is an example:

```diff
diff --git a/examples/server_async.py b/examples/server_async.py
--- a/examples/server_async.py
+++ b/examples/server_async.py
@@ -313,4 +313,4 @@
 
 
 if __name__ == "__main__":
-    asyncio.run(run_async_server("."), debug=True)
+    asyncio.run(run_async_server(), debug=True)
diff --git a/examples/server_sync.py b/examples/server_sync.py
--- a/examples/server_sync.py
+++ b/examples/server_sync.py
@@ -313,5 +313,5 @@
 
 
 if __name__ == "__main__":
-    server = run_sync_server(".")
+    server = run_sync_server()
     server.shutdown()

```

diff --git a/securedrop/journalist_app/col.py b/securedrop/journalist_app/col.py
--- a/securedrop/journalist_app/col.py
+++ b/securedrop/journalist_app/col.py
@@ -70,7 +70,7 @@
                     # confirming the success of an operation.
                     escape(gettext("Success!")),
                     escape(gettext(
-                        "The account and data for the source {} has been deleted.").format(
+                        "The account and data for the source {} have been deleted.").format(
                             source.journalist_designation))
                 )
             ), 'success')

{"golden_diff": "diff --git a/securedrop/journalist_app/col.py b/securedrop/journalist_app/col.py\n--- a/securedrop/journalist_app/col.py\n+++ b/securedrop/journalist_app/col.py\n@@ -70,7 +70,7 @@\n                     # confirming the success of an operation.\n                     escape(gettext(\"Success!\")),\n                     escape(gettext(\n-                        \"The account and data for the source {} has been deleted.\").format(\n+                        \"The account and data for the source {} have been deleted.\").format(\n                             source.journalist_designation))\n                 )\n             ), 'success')\n", "issue": "1.8.0 translation feedback: Focal upgrade warning\n## Description\r\n\r\nAO [suggested](https://weblate.securedrop.org/translate/securedrop/securedrop/en/?checksum=c775f74150ac3872) changing `A manual update is urgently required to remain safe.` to `A manual upgrade is urgently required to remain safe.` in:\r\n\r\n```\r\n<strong>Critical Security:</strong>&nbsp;&nbsp;The operating system used by your SecureDrop servers \r\nwill reach its end-of-life on April 30, 2021. A manual update is urgently required to remain safe. \r\nPlease contact your adminstrator. <a href=\"//securedrop.org/xenial-eol\" rel=\"noreferrer\">Learn More</a>\r\n```\r\n\r\nas well as [here](https://weblate.securedrop.org/translate/securedrop/securedrop/en/?checksum=60e0284e103e2c51):\r\n```\r\n<strong>Critical Security:</strong>&nbsp;&nbsp;The operating system used by your SecureDrop servers \r\nhas reached its end-of-life. A manual update is required to re-enable the Source Interface and remain safe. \r\nPlease contact your administrator. <a href=\"//securedrop.org/xenial-eol\" rel=\"noreferrer\">Learn More</a>\r\n```\r\n\r\nThere's also a typo in the first string: \"adminstrator\" needs another \"i\".\r\n\r\n\n", "before_files": [{"content": "# -*- coding: utf-8 -*-\n\nfrom pathlib import Path\n\nfrom flask import (\n    Blueprint,\n    abort,\n    current_app,\n    flash,\n    g,\n    redirect,\n    render_template,\n    request,\n    send_file,\n    url_for,\n    Markup,\n    escape,\n)\nimport werkzeug\nfrom flask_babel import gettext\nfrom sqlalchemy.orm.exc import NoResultFound\n\nfrom db import db\nfrom models import Reply, Submission\nfrom journalist_app.forms import ReplyForm\nfrom journalist_app.utils import (make_star_true, make_star_false, get_source,\n                                  delete_collection, col_download_unread,\n                                  col_download_all, col_star, col_un_star,\n                                  col_delete, col_delete_data, mark_seen)\nfrom sdconfig import SDConfig\n\n\ndef make_blueprint(config: SDConfig) -> Blueprint:\n    view = Blueprint('col', __name__)\n\n    @view.route('/add_star/<filesystem_id>', methods=('POST',))\n    def add_star(filesystem_id: str) -> werkzeug.Response:\n        make_star_true(filesystem_id)\n        db.session.commit()\n        return redirect(url_for('main.index'))\n\n    @view.route(\"/remove_star/<filesystem_id>\", methods=('POST',))\n    def remove_star(filesystem_id: str) -> werkzeug.Response:\n        make_star_false(filesystem_id)\n        db.session.commit()\n        return redirect(url_for('main.index'))\n\n    @view.route('/<filesystem_id>')\n    def col(filesystem_id: str) -> str:\n        form = ReplyForm()\n        source = get_source(filesystem_id)\n        source.has_key = current_app.crypto_util.get_fingerprint(filesystem_id)\n        return render_template(\"col.html\", filesystem_id=filesystem_id,\n                               source=source, form=form)\n\n    @view.route('/delete/<filesystem_id>', methods=('POST',))\n    def delete_single(filesystem_id: str) -> werkzeug.Response:\n        \"\"\"deleting a single collection from its /col page\"\"\"\n        source = get_source(filesystem_id)\n        try:\n            delete_collection(filesystem_id)\n        except ValueError as e:\n            current_app.logger.error(\"error deleting collection: %s\", e)\n            abort(500)\n\n        flash(\n            Markup(\n                \"<b>{}</b> {}\".format(\n                    # Translators: Here, \"Success!\" appears before a message\n                    # confirming the success of an operation.\n                    escape(gettext(\"Success!\")),\n                    escape(gettext(\n                        \"The account and data for the source {} has been deleted.\").format(\n                            source.journalist_designation))\n                )\n            ), 'success')\n\n        return redirect(url_for('main.index'))\n\n    @view.route('/process', methods=('POST',))\n    def process() -> werkzeug.Response:\n        actions = {'download-unread': col_download_unread,\n                   'download-all': col_download_all, 'star': col_star,\n                   'un-star': col_un_star, 'delete': col_delete,\n                   'delete-data': col_delete_data}\n        if 'cols_selected' not in request.form:\n            flash(\n                Markup(\"<b>{}</b> {}\".format(\n                    # Translators: Here, \"Nothing Selected\" appears before a message\n                    # asking the user to select one or more items.\n                    escape(gettext('Nothing Selected')),\n                    escape(gettext('You must select one or more items.'))\n                    )\n                ), 'error')\n            return redirect(url_for('main.index'))\n\n        # getlist is cgi.FieldStorage.getlist\n        cols_selected = request.form.getlist('cols_selected')\n        action = request.form['action']\n\n        if action not in actions:\n            return abort(500)\n\n        method = actions[action]\n        return method(cols_selected)\n\n    @view.route('/<filesystem_id>/<fn>')\n    def download_single_file(filesystem_id: str, fn: str) -> werkzeug.Response:\n        \"\"\"\n        Marks the file being download (the file being downloaded is either a submission message,\n        submission file attachement, or journalist reply) as seen by the current logged-in user and\n        send the file to a client to be saved or opened.\n        \"\"\"\n        if '..' in fn or fn.startswith('/'):\n            abort(404)\n\n        file = current_app.storage.path(filesystem_id, fn)\n        if not Path(file).is_file():\n            flash(\n                gettext(\n                    \"Your download failed because a file could not be found. An admin can find \"\n                    + \"more information in the system and monitoring logs.\"\n                ),\n                \"error\"\n            )\n            current_app.logger.error(\"File {} not found\".format(file))\n            return redirect(url_for(\"col.col\", filesystem_id=filesystem_id))\n\n        # mark as seen by the current user\n        try:\n            journalist = g.get(\"user\")\n            if fn.endswith(\"reply.gpg\"):\n                reply = Reply.query.filter(Reply.filename == fn).one()\n                mark_seen([reply], journalist)\n            elif fn.endswith(\"-doc.gz.gpg\") or fn.endswith(\"doc.zip.gpg\"):\n                file = Submission.query.filter(Submission.filename == fn).one()\n                mark_seen([file], journalist)\n            else:\n                message = Submission.query.filter(Submission.filename == fn).one()\n                mark_seen([message], journalist)\n        except NoResultFound as e:\n            current_app.logger.error(\"Could not mark {} as seen: {}\".format(fn, e))\n\n        return send_file(current_app.storage.path(filesystem_id, fn),\n                         mimetype=\"application/pgp-encrypted\")\n\n    return view\n", "path": "securedrop/journalist_app/col.py"}], "after_files": [{"content": "# -*- coding: utf-8 -*-\n\nfrom pathlib import Path\n\nfrom flask import (\n    Blueprint,\n    abort,\n    current_app,\n    flash,\n    g,\n    redirect,\n    render_template,\n    request,\n    send_file,\n    url_for,\n    Markup,\n    escape,\n)\nimport werkzeug\nfrom flask_babel import gettext\nfrom sqlalchemy.orm.exc import NoResultFound\n\nfrom db import db\nfrom models import Reply, Submission\nfrom journalist_app.forms import ReplyForm\nfrom journalist_app.utils import (make_star_true, make_star_false, get_source,\n                                  delete_collection, col_download_unread,\n                                  col_download_all, col_star, col_un_star,\n                                  col_delete, col_delete_data, mark_seen)\nfrom sdconfig import SDConfig\n\n\ndef make_blueprint(config: SDConfig) -> Blueprint:\n    view = Blueprint('col', __name__)\n\n    @view.route('/add_star/<filesystem_id>', methods=('POST',))\n    def add_star(filesystem_id: str) -> werkzeug.Response:\n        make_star_true(filesystem_id)\n        db.session.commit()\n        return redirect(url_for('main.index'))\n\n    @view.route(\"/remove_star/<filesystem_id>\", methods=('POST',))\n    def remove_star(filesystem_id: str) -> werkzeug.Response:\n        make_star_false(filesystem_id)\n        db.session.commit()\n        return redirect(url_for('main.index'))\n\n    @view.route('/<filesystem_id>')\n    def col(filesystem_id: str) -> str:\n        form = ReplyForm()\n        source = get_source(filesystem_id)\n        source.has_key = current_app.crypto_util.get_fingerprint(filesystem_id)\n        return render_template(\"col.html\", filesystem_id=filesystem_id,\n                               source=source, form=form)\n\n    @view.route('/delete/<filesystem_id>', methods=('POST',))\n    def delete_single(filesystem_id: str) -> werkzeug.Response:\n        \"\"\"deleting a single collection from its /col page\"\"\"\n        source = get_source(filesystem_id)\n        try:\n            delete_collection(filesystem_id)\n        except ValueError as e:\n            current_app.logger.error(\"error deleting collection: %s\", e)\n            abort(500)\n\n        flash(\n            Markup(\n                \"<b>{}</b> {}\".format(\n                    # Translators: Here, \"Success!\" appears before a message\n                    # confirming the success of an operation.\n                    escape(gettext(\"Success!\")),\n                    escape(gettext(\n                        \"The account and data for the source {} have been deleted.\").format(\n                            source.journalist_designation))\n                )\n            ), 'success')\n\n        return redirect(url_for('main.index'))\n\n    @view.route('/process', methods=('POST',))\n    def process() -> werkzeug.Response:\n        actions = {'download-unread': col_download_unread,\n                   'download-all': col_download_all, 'star': col_star,\n                   'un-star': col_un_star, 'delete': col_delete,\n                   'delete-data': col_delete_data}\n        if 'cols_selected' not in request.form:\n            flash(\n                Markup(\"<b>{}</b> {}\".format(\n                    # Translators: Here, \"Nothing Selected\" appears before a message\n                    # asking the user to select one or more items.\n                    escape(gettext('Nothing Selected')),\n                    escape(gettext('You must select one or more items.'))\n                    )\n                ), 'error')\n            return redirect(url_for('main.index'))\n\n        # getlist is cgi.FieldStorage.getlist\n        cols_selected = request.form.getlist('cols_selected')\n        action = request.form['action']\n\n        if action not in actions:\n            return abort(500)\n\n        method = actions[action]\n        return method(cols_selected)\n\n    @view.route('/<filesystem_id>/<fn>')\n    def download_single_file(filesystem_id: str, fn: str) -> werkzeug.Response:\n        \"\"\"\n        Marks the file being download (the file being downloaded is either a submission message,\n        submission file attachement, or journalist reply) as seen by the current logged-in user and\n        send the file to a client to be saved or opened.\n        \"\"\"\n        if '..' in fn or fn.startswith('/'):\n            abort(404)\n\n        file = current_app.storage.path(filesystem_id, fn)\n        if not Path(file).is_file():\n            flash(\n                gettext(\n                    \"Your download failed because a file could not be found. An admin can find \"\n                    + \"more information in the system and monitoring logs.\"\n                ),\n                \"error\"\n            )\n            current_app.logger.error(\"File {} not found\".format(file))\n            return redirect(url_for(\"col.col\", filesystem_id=filesystem_id))\n\n        # mark as seen by the current user\n        try:\n            journalist = g.get(\"user\")\n            if fn.endswith(\"reply.gpg\"):\n                reply = Reply.query.filter(Reply.filename == fn).one()\n                mark_seen([reply], journalist)\n            elif fn.endswith(\"-doc.gz.gpg\") or fn.endswith(\"doc.zip.gpg\"):\n                file = Submission.query.filter(Submission.filename == fn).one()\n                mark_seen([file], journalist)\n            else:\n                message = Submission.query.filter(Submission.filename == fn).one()\n                mark_seen([message], journalist)\n        except NoResultFound as e:\n            current_app.logger.error(\"Could not mark {} as seen: {}\".format(fn, e))\n\n        return send_file(current_app.storage.path(filesystem_id, fn),\n                         mimetype=\"application/pgp-encrypted\")\n\n    return view\n", "path": "securedrop/journalist_app/col.py"}]}