We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
Add time to export filename


--- END ISSUE ---

Below are some code segments, each from a relevant file. One or more of these files may contain bugs.
--- BEGIN FILES ---
Path: `CTFd/admin/__init__.py`
Content:
```
1 import csv
2 import datetime
3 import os
4 from io import BytesIO, StringIO
5 
6 from flask import Blueprint, abort
7 from flask import current_app as app
8 from flask import (
9     redirect,
10     render_template,
11     render_template_string,
12     request,
13     send_file,
14     url_for,
15 )
16 
17 admin = Blueprint("admin", __name__)
18 
19 # isort:imports-firstparty
20 from CTFd.admin import challenges  # noqa: F401
21 from CTFd.admin import notifications  # noqa: F401
22 from CTFd.admin import pages  # noqa: F401
23 from CTFd.admin import scoreboard  # noqa: F401
24 from CTFd.admin import statistics  # noqa: F401
25 from CTFd.admin import submissions  # noqa: F401
26 from CTFd.admin import teams  # noqa: F401
27 from CTFd.admin import users  # noqa: F401
28 from CTFd.cache import cache, clear_config, clear_pages, clear_standings
29 from CTFd.models import (
30     Awards,
31     Challenges,
32     Configs,
33     Notifications,
34     Pages,
35     Solves,
36     Submissions,
37     Teams,
38     Tracking,
39     Unlocks,
40     Users,
41     db,
42     get_class_by_tablename,
43 )
44 from CTFd.utils import config as ctf_config
45 from CTFd.utils import get_config, set_config
46 from CTFd.utils.csv import load_challenges_csv, load_teams_csv, load_users_csv
47 from CTFd.utils.decorators import admins_only
48 from CTFd.utils.exports import export_ctf as export_ctf_util
49 from CTFd.utils.exports import import_ctf as import_ctf_util
50 from CTFd.utils.helpers import get_errors
51 from CTFd.utils.security.auth import logout_user
52 from CTFd.utils.uploads import delete_file
53 from CTFd.utils.user import is_admin
54 
55 
56 @admin.route("/admin", methods=["GET"])
57 def view():
58     if is_admin():
59         return redirect(url_for("admin.statistics"))
60     return redirect(url_for("auth.login"))
61 
62 
63 @admin.route("/admin/plugins/<plugin>", methods=["GET", "POST"])
64 @admins_only
65 def plugin(plugin):
66     if request.method == "GET":
67         plugins_path = os.path.join(app.root_path, "plugins")
68 
69         config_html_plugins = [
70             name
71             for name in os.listdir(plugins_path)
72             if os.path.isfile(os.path.join(plugins_path, name, "config.html"))
73         ]
74 
75         if plugin in config_html_plugins:
76             config_html = open(
77                 os.path.join(app.root_path, "plugins", plugin, "config.html")
78             ).read()
79             return render_template_string(config_html)
80         abort(404)
81     elif request.method == "POST":
82         for k, v in request.form.items():
83             if k == "nonce":
84                 continue
85             set_config(k, v)
86         with app.app_context():
87             clear_config()
88         return "1"
89 
90 
91 @admin.route("/admin/import", methods=["POST"])
92 @admins_only
93 def import_ctf():
94     backup = request.files["backup"]
95     errors = get_errors()
96     try:
97         import_ctf_util(backup)
98     except Exception as e:
99         print(e)
100         errors.append(repr(e))
101 
102     if errors:
103         return errors[0], 500
104     else:
105         return redirect(url_for("admin.config"))
106 
107 
108 @admin.route("/admin/export", methods=["GET", "POST"])
109 @admins_only
110 def export_ctf():
111     backup = export_ctf_util()
112     ctf_name = ctf_config.ctf_name()
113     day = datetime.datetime.now().strftime("%Y-%m-%d")
114     full_name = u"{}.{}.zip".format(ctf_name, day)
115     return send_file(
116         backup, cache_timeout=-1, as_attachment=True, attachment_filename=full_name
117     )
118 
119 
120 @admin.route("/admin/import/csv", methods=["POST"])
121 @admins_only
122 def import_csv():
123     csv_type = request.form["csv_type"]
124     # Try really hard to load data in properly no matter what nonsense Excel gave you
125     raw = request.files["csv_file"].stream.read()
126     try:
127         csvdata = raw.decode("utf-8-sig")
128     except UnicodeDecodeError:
129         try:
130             csvdata = raw.decode("cp1252")
131         except UnicodeDecodeError:
132             csvdata = raw.decode("latin-1")
133     csvfile = StringIO(csvdata)
134 
135     loaders = {
136         "challenges": load_challenges_csv,
137         "users": load_users_csv,
138         "teams": load_teams_csv,
139     }
140 
141     loader = loaders[csv_type]
142     reader = csv.DictReader(csvfile)
143     loader(reader)
144     return redirect(url_for("admin.config"))
145 
146 
147 @admin.route("/admin/export/csv")
148 @admins_only
149 def export_csv():
150     table = request.args.get("table")
151 
152     # TODO: It might make sense to limit dumpable tables. Config could potentially leak sensitive information.
153     model = get_class_by_tablename(table)
154     if model is None:
155         abort(404)
156 
157     temp = StringIO()
158     writer = csv.writer(temp)
159 
160     header = [column.name for column in model.__mapper__.columns]
161     writer.writerow(header)
162 
163     responses = model.query.all()
164 
165     for curr in responses:
166         writer.writerow(
167             [getattr(curr, column.name) for column in model.__mapper__.columns]
168         )
169 
170     temp.seek(0)
171 
172     # In Python 3 send_file requires bytes
173     output = BytesIO()
174     output.write(temp.getvalue().encode("utf-8"))
175     output.seek(0)
176     temp.close()
177 
178     return send_file(
179         output,
180         as_attachment=True,
181         cache_timeout=-1,
182         attachment_filename="{name}-{table}.csv".format(
183             name=ctf_config.ctf_name(), table=table
184         ),
185     )
186 
187 
188 @admin.route("/admin/config", methods=["GET", "POST"])
189 @admins_only
190 def config():
191     # Clear the config cache so that we don't get stale values
192     clear_config()
193 
194     configs = Configs.query.all()
195     configs = {c.key: get_config(c.key) for c in configs}
196 
197     themes = ctf_config.get_themes()
198     themes.remove(get_config("ctf_theme"))
199 
200     return render_template("admin/config.html", themes=themes, **configs)
201 
202 
203 @admin.route("/admin/reset", methods=["GET", "POST"])
204 @admins_only
205 def reset():
206     if request.method == "POST":
207         require_setup = False
208         logout = False
209         next_url = url_for("admin.statistics")
210 
211         data = request.form
212 
213         if data.get("pages"):
214             _pages = Pages.query.all()
215             for p in _pages:
216                 for f in p.files:
217                     delete_file(file_id=f.id)
218 
219             Pages.query.delete()
220 
221         if data.get("notifications"):
222             Notifications.query.delete()
223 
224         if data.get("challenges"):
225             _challenges = Challenges.query.all()
226             for c in _challenges:
227                 for f in c.files:
228                     delete_file(file_id=f.id)
229             Challenges.query.delete()
230 
231         if data.get("accounts"):
232             Users.query.delete()
233             Teams.query.delete()
234             require_setup = True
235             logout = True
236 
237         if data.get("submissions"):
238             Solves.query.delete()
239             Submissions.query.delete()
240             Awards.query.delete()
241             Unlocks.query.delete()
242             Tracking.query.delete()
243 
244         if require_setup:
245             set_config("setup", False)
246             cache.clear()
247             logout_user()
248             next_url = url_for("views.setup")
249 
250         db.session.commit()
251 
252         clear_pages()
253         clear_standings()
254         clear_config()
255 
256         if logout is True:
257             cache.clear()
258             logout_user()
259 
260         db.session.close()
261         return redirect(next_url)
262 
263     return render_template("admin/reset.html")
264
```

Path: `manage.py`
Content:
```
1 import datetime
2 import shutil
3 
4 from flask_migrate import MigrateCommand
5 from flask_script import Manager
6 
7 from CTFd import create_app
8 from CTFd.utils import get_config as get_config_util
9 from CTFd.utils import set_config as set_config_util
10 from CTFd.utils.config import ctf_name
11 from CTFd.utils.exports import export_ctf as export_ctf_util
12 from CTFd.utils.exports import import_ctf as import_ctf_util
13 
14 app = create_app()
15 
16 manager = Manager(app)
17 manager.add_command("db", MigrateCommand)
18 
19 
20 def jsenums():
21     from CTFd.constants import JS_ENUMS
22     import json
23     import os
24 
25     path = os.path.join(app.root_path, "themes/core/assets/js/constants.js")
26 
27     with open(path, "w+") as f:
28         for k, v in JS_ENUMS.items():
29             f.write("const {} = Object.freeze({});".format(k, json.dumps(v)))
30 
31 
32 BUILD_COMMANDS = {"jsenums": jsenums}
33 
34 
35 @manager.command
36 def get_config(key):
37     with app.app_context():
38         print(get_config_util(key))
39 
40 
41 @manager.command
42 def set_config(key, value):
43     with app.app_context():
44         print(set_config_util(key, value).value)
45 
46 
47 @manager.command
48 def build(cmd):
49     with app.app_context():
50         cmd = BUILD_COMMANDS.get(cmd)
51         cmd()
52 
53 
54 @manager.command
55 def export_ctf(path=None):
56     with app.app_context():
57         backup = export_ctf_util()
58 
59         if path:
60             with open(path, "wb") as target:
61                 shutil.copyfileobj(backup, target)
62         else:
63             name = ctf_name()
64             day = datetime.datetime.now().strftime("%Y-%m-%d")
65             full_name = f"{name}.{day}.zip"
66 
67             with open(full_name, "wb") as target:
68                 shutil.copyfileobj(backup, target)
69 
70             print(f"Exported {full_name}")
71 
72 
73 @manager.command
74 def import_ctf(path):
75     with app.app_context():
76         import_ctf_util(path)
77 
78 
79 if __name__ == "__main__":
80     manager.run()
81
```
--- 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/CTFd/admin/__init__.py b/CTFd/admin/__init__.py
--- a/CTFd/admin/__init__.py
+++ b/CTFd/admin/__init__.py
@@ -110,7 +110,7 @@
 def export_ctf():
     backup = export_ctf_util()
     ctf_name = ctf_config.ctf_name()
-    day = datetime.datetime.now().strftime("%Y-%m-%d")
+    day = datetime.datetime.now().strftime("%Y-%m-%d_%T")
     full_name = u"{}.{}.zip".format(ctf_name, day)
     return send_file(
         backup, cache_timeout=-1, as_attachment=True, attachment_filename=full_name
diff --git a/manage.py b/manage.py
--- a/manage.py
+++ b/manage.py
@@ -61,7 +61,7 @@
                 shutil.copyfileobj(backup, target)
         else:
             name = ctf_name()
-            day = datetime.datetime.now().strftime("%Y-%m-%d")
+            day = datetime.datetime.now().strftime("%Y-%m-%d_%T")
             full_name = f"{name}.{day}.zip"
 
             with open(full_name, "wb") as target:

{"golden_diff": "diff --git a/CTFd/admin/__init__.py b/CTFd/admin/__init__.py\n--- a/CTFd/admin/__init__.py\n+++ b/CTFd/admin/__init__.py\n@@ -110,7 +110,7 @@\n def export_ctf():\n     backup = export_ctf_util()\n     ctf_name = ctf_config.ctf_name()\n-    day = datetime.datetime.now().strftime(\"%Y-%m-%d\")\n+    day = datetime.datetime.now().strftime(\"%Y-%m-%d_%T\")\n     full_name = u\"{}.{}.zip\".format(ctf_name, day)\n     return send_file(\n         backup, cache_timeout=-1, as_attachment=True, attachment_filename=full_name\ndiff --git a/manage.py b/manage.py\n--- a/manage.py\n+++ b/manage.py\n@@ -61,7 +61,7 @@\n                 shutil.copyfileobj(backup, target)\n         else:\n             name = ctf_name()\n-            day = datetime.datetime.now().strftime(\"%Y-%m-%d\")\n+            day = datetime.datetime.now().strftime(\"%Y-%m-%d_%T\")\n             full_name = f\"{name}.{day}.zip\"\n \n             with open(full_name, \"wb\") as target:\n", "issue": "Add time to export filename\n\n", "before_files": [{"content": "import csv\nimport datetime\nimport os\nfrom io import BytesIO, StringIO\n\nfrom flask import Blueprint, abort\nfrom flask import current_app as app\nfrom flask import (\n    redirect,\n    render_template,\n    render_template_string,\n    request,\n    send_file,\n    url_for,\n)\n\nadmin = Blueprint(\"admin\", __name__)\n\n# isort:imports-firstparty\nfrom CTFd.admin import challenges  # noqa: F401\nfrom CTFd.admin import notifications  # noqa: F401\nfrom CTFd.admin import pages  # noqa: F401\nfrom CTFd.admin import scoreboard  # noqa: F401\nfrom CTFd.admin import statistics  # noqa: F401\nfrom CTFd.admin import submissions  # noqa: F401\nfrom CTFd.admin import teams  # noqa: F401\nfrom CTFd.admin import users  # noqa: F401\nfrom CTFd.cache import cache, clear_config, clear_pages, clear_standings\nfrom CTFd.models import (\n    Awards,\n    Challenges,\n    Configs,\n    Notifications,\n    Pages,\n    Solves,\n    Submissions,\n    Teams,\n    Tracking,\n    Unlocks,\n    Users,\n    db,\n    get_class_by_tablename,\n)\nfrom CTFd.utils import config as ctf_config\nfrom CTFd.utils import get_config, set_config\nfrom CTFd.utils.csv import load_challenges_csv, load_teams_csv, load_users_csv\nfrom CTFd.utils.decorators import admins_only\nfrom CTFd.utils.exports import export_ctf as export_ctf_util\nfrom CTFd.utils.exports import import_ctf as import_ctf_util\nfrom CTFd.utils.helpers import get_errors\nfrom CTFd.utils.security.auth import logout_user\nfrom CTFd.utils.uploads import delete_file\nfrom CTFd.utils.user import is_admin\n\n\n@admin.route(\"/admin\", methods=[\"GET\"])\ndef view():\n    if is_admin():\n        return redirect(url_for(\"admin.statistics\"))\n    return redirect(url_for(\"auth.login\"))\n\n\n@admin.route(\"/admin/plugins/<plugin>\", methods=[\"GET\", \"POST\"])\n@admins_only\ndef plugin(plugin):\n    if request.method == \"GET\":\n        plugins_path = os.path.join(app.root_path, \"plugins\")\n\n        config_html_plugins = [\n            name\n            for name in os.listdir(plugins_path)\n            if os.path.isfile(os.path.join(plugins_path, name, \"config.html\"))\n        ]\n\n        if plugin in config_html_plugins:\n            config_html = open(\n                os.path.join(app.root_path, \"plugins\", plugin, \"config.html\")\n            ).read()\n            return render_template_string(config_html)\n        abort(404)\n    elif request.method == \"POST\":\n        for k, v in request.form.items():\n            if k == \"nonce\":\n                continue\n            set_config(k, v)\n        with app.app_context():\n            clear_config()\n        return \"1\"\n\n\n@admin.route(\"/admin/import\", methods=[\"POST\"])\n@admins_only\ndef import_ctf():\n    backup = request.files[\"backup\"]\n    errors = get_errors()\n    try:\n        import_ctf_util(backup)\n    except Exception as e:\n        print(e)\n        errors.append(repr(e))\n\n    if errors:\n        return errors[0], 500\n    else:\n        return redirect(url_for(\"admin.config\"))\n\n\n@admin.route(\"/admin/export\", methods=[\"GET\", \"POST\"])\n@admins_only\ndef export_ctf():\n    backup = export_ctf_util()\n    ctf_name = ctf_config.ctf_name()\n    day = datetime.datetime.now().strftime(\"%Y-%m-%d\")\n    full_name = u\"{}.{}.zip\".format(ctf_name, day)\n    return send_file(\n        backup, cache_timeout=-1, as_attachment=True, attachment_filename=full_name\n    )\n\n\n@admin.route(\"/admin/import/csv\", methods=[\"POST\"])\n@admins_only\ndef import_csv():\n    csv_type = request.form[\"csv_type\"]\n    # Try really hard to load data in properly no matter what nonsense Excel gave you\n    raw = request.files[\"csv_file\"].stream.read()\n    try:\n        csvdata = raw.decode(\"utf-8-sig\")\n    except UnicodeDecodeError:\n        try:\n            csvdata = raw.decode(\"cp1252\")\n        except UnicodeDecodeError:\n            csvdata = raw.decode(\"latin-1\")\n    csvfile = StringIO(csvdata)\n\n    loaders = {\n        \"challenges\": load_challenges_csv,\n        \"users\": load_users_csv,\n        \"teams\": load_teams_csv,\n    }\n\n    loader = loaders[csv_type]\n    reader = csv.DictReader(csvfile)\n    loader(reader)\n    return redirect(url_for(\"admin.config\"))\n\n\n@admin.route(\"/admin/export/csv\")\n@admins_only\ndef export_csv():\n    table = request.args.get(\"table\")\n\n    # TODO: It might make sense to limit dumpable tables. Config could potentially leak sensitive information.\n    model = get_class_by_tablename(table)\n    if model is None:\n        abort(404)\n\n    temp = StringIO()\n    writer = csv.writer(temp)\n\n    header = [column.name for column in model.__mapper__.columns]\n    writer.writerow(header)\n\n    responses = model.query.all()\n\n    for curr in responses:\n        writer.writerow(\n            [getattr(curr, column.name) for column in model.__mapper__.columns]\n        )\n\n    temp.seek(0)\n\n    # In Python 3 send_file requires bytes\n    output = BytesIO()\n    output.write(temp.getvalue().encode(\"utf-8\"))\n    output.seek(0)\n    temp.close()\n\n    return send_file(\n        output,\n        as_attachment=True,\n        cache_timeout=-1,\n        attachment_filename=\"{name}-{table}.csv\".format(\n            name=ctf_config.ctf_name(), table=table\n        ),\n    )\n\n\n@admin.route(\"/admin/config\", methods=[\"GET\", \"POST\"])\n@admins_only\ndef config():\n    # Clear the config cache so that we don't get stale values\n    clear_config()\n\n    configs = Configs.query.all()\n    configs = {c.key: get_config(c.key) for c in configs}\n\n    themes = ctf_config.get_themes()\n    themes.remove(get_config(\"ctf_theme\"))\n\n    return render_template(\"admin/config.html\", themes=themes, **configs)\n\n\n@admin.route(\"/admin/reset\", methods=[\"GET\", \"POST\"])\n@admins_only\ndef reset():\n    if request.method == \"POST\":\n        require_setup = False\n        logout = False\n        next_url = url_for(\"admin.statistics\")\n\n        data = request.form\n\n        if data.get(\"pages\"):\n            _pages = Pages.query.all()\n            for p in _pages:\n                for f in p.files:\n                    delete_file(file_id=f.id)\n\n            Pages.query.delete()\n\n        if data.get(\"notifications\"):\n            Notifications.query.delete()\n\n        if data.get(\"challenges\"):\n            _challenges = Challenges.query.all()\n            for c in _challenges:\n                for f in c.files:\n                    delete_file(file_id=f.id)\n            Challenges.query.delete()\n\n        if data.get(\"accounts\"):\n            Users.query.delete()\n            Teams.query.delete()\n            require_setup = True\n            logout = True\n\n        if data.get(\"submissions\"):\n            Solves.query.delete()\n            Submissions.query.delete()\n            Awards.query.delete()\n            Unlocks.query.delete()\n            Tracking.query.delete()\n\n        if require_setup:\n            set_config(\"setup\", False)\n            cache.clear()\n            logout_user()\n            next_url = url_for(\"views.setup\")\n\n        db.session.commit()\n\n        clear_pages()\n        clear_standings()\n        clear_config()\n\n        if logout is True:\n            cache.clear()\n            logout_user()\n\n        db.session.close()\n        return redirect(next_url)\n\n    return render_template(\"admin/reset.html\")\n", "path": "CTFd/admin/__init__.py"}, {"content": "import datetime\nimport shutil\n\nfrom flask_migrate import MigrateCommand\nfrom flask_script import Manager\n\nfrom CTFd import create_app\nfrom CTFd.utils import get_config as get_config_util\nfrom CTFd.utils import set_config as set_config_util\nfrom CTFd.utils.config import ctf_name\nfrom CTFd.utils.exports import export_ctf as export_ctf_util\nfrom CTFd.utils.exports import import_ctf as import_ctf_util\n\napp = create_app()\n\nmanager = Manager(app)\nmanager.add_command(\"db\", MigrateCommand)\n\n\ndef jsenums():\n    from CTFd.constants import JS_ENUMS\n    import json\n    import os\n\n    path = os.path.join(app.root_path, \"themes/core/assets/js/constants.js\")\n\n    with open(path, \"w+\") as f:\n        for k, v in JS_ENUMS.items():\n            f.write(\"const {} = Object.freeze({});\".format(k, json.dumps(v)))\n\n\nBUILD_COMMANDS = {\"jsenums\": jsenums}\n\n\n@manager.command\ndef get_config(key):\n    with app.app_context():\n        print(get_config_util(key))\n\n\n@manager.command\ndef set_config(key, value):\n    with app.app_context():\n        print(set_config_util(key, value).value)\n\n\n@manager.command\ndef build(cmd):\n    with app.app_context():\n        cmd = BUILD_COMMANDS.get(cmd)\n        cmd()\n\n\n@manager.command\ndef export_ctf(path=None):\n    with app.app_context():\n        backup = export_ctf_util()\n\n        if path:\n            with open(path, \"wb\") as target:\n                shutil.copyfileobj(backup, target)\n        else:\n            name = ctf_name()\n            day = datetime.datetime.now().strftime(\"%Y-%m-%d\")\n            full_name = f\"{name}.{day}.zip\"\n\n            with open(full_name, \"wb\") as target:\n                shutil.copyfileobj(backup, target)\n\n            print(f\"Exported {full_name}\")\n\n\n@manager.command\ndef import_ctf(path):\n    with app.app_context():\n        import_ctf_util(path)\n\n\nif __name__ == \"__main__\":\n    manager.run()\n", "path": "manage.py"}], "after_files": [{"content": "import csv\nimport datetime\nimport os\nfrom io import BytesIO, StringIO\n\nfrom flask import Blueprint, abort\nfrom flask import current_app as app\nfrom flask import (\n    redirect,\n    render_template,\n    render_template_string,\n    request,\n    send_file,\n    url_for,\n)\n\nadmin = Blueprint(\"admin\", __name__)\n\n# isort:imports-firstparty\nfrom CTFd.admin import challenges  # noqa: F401\nfrom CTFd.admin import notifications  # noqa: F401\nfrom CTFd.admin import pages  # noqa: F401\nfrom CTFd.admin import scoreboard  # noqa: F401\nfrom CTFd.admin import statistics  # noqa: F401\nfrom CTFd.admin import submissions  # noqa: F401\nfrom CTFd.admin import teams  # noqa: F401\nfrom CTFd.admin import users  # noqa: F401\nfrom CTFd.cache import cache, clear_config, clear_pages, clear_standings\nfrom CTFd.models import (\n    Awards,\n    Challenges,\n    Configs,\n    Notifications,\n    Pages,\n    Solves,\n    Submissions,\n    Teams,\n    Tracking,\n    Unlocks,\n    Users,\n    db,\n    get_class_by_tablename,\n)\nfrom CTFd.utils import config as ctf_config\nfrom CTFd.utils import get_config, set_config\nfrom CTFd.utils.csv import load_challenges_csv, load_teams_csv, load_users_csv\nfrom CTFd.utils.decorators import admins_only\nfrom CTFd.utils.exports import export_ctf as export_ctf_util\nfrom CTFd.utils.exports import import_ctf as import_ctf_util\nfrom CTFd.utils.helpers import get_errors\nfrom CTFd.utils.security.auth import logout_user\nfrom CTFd.utils.uploads import delete_file\nfrom CTFd.utils.user import is_admin\n\n\n@admin.route(\"/admin\", methods=[\"GET\"])\ndef view():\n    if is_admin():\n        return redirect(url_for(\"admin.statistics\"))\n    return redirect(url_for(\"auth.login\"))\n\n\n@admin.route(\"/admin/plugins/<plugin>\", methods=[\"GET\", \"POST\"])\n@admins_only\ndef plugin(plugin):\n    if request.method == \"GET\":\n        plugins_path = os.path.join(app.root_path, \"plugins\")\n\n        config_html_plugins = [\n            name\n            for name in os.listdir(plugins_path)\n            if os.path.isfile(os.path.join(plugins_path, name, \"config.html\"))\n        ]\n\n        if plugin in config_html_plugins:\n            config_html = open(\n                os.path.join(app.root_path, \"plugins\", plugin, \"config.html\")\n            ).read()\n            return render_template_string(config_html)\n        abort(404)\n    elif request.method == \"POST\":\n        for k, v in request.form.items():\n            if k == \"nonce\":\n                continue\n            set_config(k, v)\n        with app.app_context():\n            clear_config()\n        return \"1\"\n\n\n@admin.route(\"/admin/import\", methods=[\"POST\"])\n@admins_only\ndef import_ctf():\n    backup = request.files[\"backup\"]\n    errors = get_errors()\n    try:\n        import_ctf_util(backup)\n    except Exception as e:\n        print(e)\n        errors.append(repr(e))\n\n    if errors:\n        return errors[0], 500\n    else:\n        return redirect(url_for(\"admin.config\"))\n\n\n@admin.route(\"/admin/export\", methods=[\"GET\", \"POST\"])\n@admins_only\ndef export_ctf():\n    backup = export_ctf_util()\n    ctf_name = ctf_config.ctf_name()\n    day = datetime.datetime.now().strftime(\"%Y-%m-%d_%T\")\n    full_name = u\"{}.{}.zip\".format(ctf_name, day)\n    return send_file(\n        backup, cache_timeout=-1, as_attachment=True, attachment_filename=full_name\n    )\n\n\n@admin.route(\"/admin/import/csv\", methods=[\"POST\"])\n@admins_only\ndef import_csv():\n    csv_type = request.form[\"csv_type\"]\n    # Try really hard to load data in properly no matter what nonsense Excel gave you\n    raw = request.files[\"csv_file\"].stream.read()\n    try:\n        csvdata = raw.decode(\"utf-8-sig\")\n    except UnicodeDecodeError:\n        try:\n            csvdata = raw.decode(\"cp1252\")\n        except UnicodeDecodeError:\n            csvdata = raw.decode(\"latin-1\")\n    csvfile = StringIO(csvdata)\n\n    loaders = {\n        \"challenges\": load_challenges_csv,\n        \"users\": load_users_csv,\n        \"teams\": load_teams_csv,\n    }\n\n    loader = loaders[csv_type]\n    reader = csv.DictReader(csvfile)\n    loader(reader)\n    return redirect(url_for(\"admin.config\"))\n\n\n@admin.route(\"/admin/export/csv\")\n@admins_only\ndef export_csv():\n    table = request.args.get(\"table\")\n\n    # TODO: It might make sense to limit dumpable tables. Config could potentially leak sensitive information.\n    model = get_class_by_tablename(table)\n    if model is None:\n        abort(404)\n\n    temp = StringIO()\n    writer = csv.writer(temp)\n\n    header = [column.name for column in model.__mapper__.columns]\n    writer.writerow(header)\n\n    responses = model.query.all()\n\n    for curr in responses:\n        writer.writerow(\n            [getattr(curr, column.name) for column in model.__mapper__.columns]\n        )\n\n    temp.seek(0)\n\n    # In Python 3 send_file requires bytes\n    output = BytesIO()\n    output.write(temp.getvalue().encode(\"utf-8\"))\n    output.seek(0)\n    temp.close()\n\n    return send_file(\n        output,\n        as_attachment=True,\n        cache_timeout=-1,\n        attachment_filename=\"{name}-{table}.csv\".format(\n            name=ctf_config.ctf_name(), table=table\n        ),\n    )\n\n\n@admin.route(\"/admin/config\", methods=[\"GET\", \"POST\"])\n@admins_only\ndef config():\n    # Clear the config cache so that we don't get stale values\n    clear_config()\n\n    configs = Configs.query.all()\n    configs = {c.key: get_config(c.key) for c in configs}\n\n    themes = ctf_config.get_themes()\n    themes.remove(get_config(\"ctf_theme\"))\n\n    return render_template(\"admin/config.html\", themes=themes, **configs)\n\n\n@admin.route(\"/admin/reset\", methods=[\"GET\", \"POST\"])\n@admins_only\ndef reset():\n    if request.method == \"POST\":\n        require_setup = False\n        logout = False\n        next_url = url_for(\"admin.statistics\")\n\n        data = request.form\n\n        if data.get(\"pages\"):\n            _pages = Pages.query.all()\n            for p in _pages:\n                for f in p.files:\n                    delete_file(file_id=f.id)\n\n            Pages.query.delete()\n\n        if data.get(\"notifications\"):\n            Notifications.query.delete()\n\n        if data.get(\"challenges\"):\n            _challenges = Challenges.query.all()\n            for c in _challenges:\n                for f in c.files:\n                    delete_file(file_id=f.id)\n            Challenges.query.delete()\n\n        if data.get(\"accounts\"):\n            Users.query.delete()\n            Teams.query.delete()\n            require_setup = True\n            logout = True\n\n        if data.get(\"submissions\"):\n            Solves.query.delete()\n            Submissions.query.delete()\n            Awards.query.delete()\n            Unlocks.query.delete()\n            Tracking.query.delete()\n\n        if require_setup:\n            set_config(\"setup\", False)\n            cache.clear()\n            logout_user()\n            next_url = url_for(\"views.setup\")\n\n        db.session.commit()\n\n        clear_pages()\n        clear_standings()\n        clear_config()\n\n        if logout is True:\n            cache.clear()\n            logout_user()\n\n        db.session.close()\n        return redirect(next_url)\n\n    return render_template(\"admin/reset.html\")\n", "path": "CTFd/admin/__init__.py"}, {"content": "import datetime\nimport shutil\n\nfrom flask_migrate import MigrateCommand\nfrom flask_script import Manager\n\nfrom CTFd import create_app\nfrom CTFd.utils import get_config as get_config_util\nfrom CTFd.utils import set_config as set_config_util\nfrom CTFd.utils.config import ctf_name\nfrom CTFd.utils.exports import export_ctf as export_ctf_util\nfrom CTFd.utils.exports import import_ctf as import_ctf_util\n\napp = create_app()\n\nmanager = Manager(app)\nmanager.add_command(\"db\", MigrateCommand)\n\n\ndef jsenums():\n    from CTFd.constants import JS_ENUMS\n    import json\n    import os\n\n    path = os.path.join(app.root_path, \"themes/core/assets/js/constants.js\")\n\n    with open(path, \"w+\") as f:\n        for k, v in JS_ENUMS.items():\n            f.write(\"const {} = Object.freeze({});\".format(k, json.dumps(v)))\n\n\nBUILD_COMMANDS = {\"jsenums\": jsenums}\n\n\n@manager.command\ndef get_config(key):\n    with app.app_context():\n        print(get_config_util(key))\n\n\n@manager.command\ndef set_config(key, value):\n    with app.app_context():\n        print(set_config_util(key, value).value)\n\n\n@manager.command\ndef build(cmd):\n    with app.app_context():\n        cmd = BUILD_COMMANDS.get(cmd)\n        cmd()\n\n\n@manager.command\ndef export_ctf(path=None):\n    with app.app_context():\n        backup = export_ctf_util()\n\n        if path:\n            with open(path, \"wb\") as target:\n                shutil.copyfileobj(backup, target)\n        else:\n            name = ctf_name()\n            day = datetime.datetime.now().strftime(\"%Y-%m-%d_%T\")\n            full_name = f\"{name}.{day}.zip\"\n\n            with open(full_name, \"wb\") as target:\n                shutil.copyfileobj(backup, target)\n\n            print(f\"Exported {full_name}\")\n\n\n@manager.command\ndef import_ctf(path):\n    with app.app_context():\n        import_ctf_util(path)\n\n\nif __name__ == \"__main__\":\n    manager.run()\n", "path": "manage.py"}]}