Skip to content

Commit 3436a84

Browse files
authored
Upgrading manage.py to work with Flask 2.0 (CTFd#2361)
* Fix manage.py to work with Flask CLI * Support both the legacy `manage.py` CLI as well as the new `flask` CLI * Closes CTFd#2354 * Closes CTFd#2352
1 parent a3051a0 commit 3436a84

File tree

4 files changed

+103
-87
lines changed

4 files changed

+103
-87
lines changed

CTFd/__init__.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
from CTFd.plugins import init_plugins
2020
from CTFd.utils.crypto import sha256
2121
from CTFd.utils.initialization import (
22+
init_cli,
2223
init_events,
2324
init_logs,
2425
init_request_processors,
@@ -312,5 +313,6 @@ def set_sqlite_pragma(dbapi_connection, connection_record):
312313
init_logs(app)
313314
init_events(app)
314315
init_plugins(app)
316+
init_cli(app)
315317

316318
return app

CTFd/cli/__init__.py

Lines changed: 92 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,92 @@
1+
import datetime
2+
import shutil
3+
from pathlib import Path
4+
5+
import click
6+
from flask import Blueprint, current_app
7+
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+
from CTFd.utils.exports import set_import_end_time, set_import_error
14+
15+
_cli = Blueprint("cli", __name__)
16+
17+
18+
def jsenums():
19+
import json
20+
import os
21+
22+
from CTFd.constants import JS_ENUMS
23+
24+
path = os.path.join(current_app.root_path, "themes/core/assets/js/constants.js")
25+
26+
with open(path, "w+") as f:
27+
for k, v in JS_ENUMS.items():
28+
f.write("const {} = Object.freeze({});".format(k, json.dumps(v)))
29+
30+
31+
BUILD_COMMANDS = {"jsenums": jsenums}
32+
33+
34+
@_cli.cli.command("get_config")
35+
@click.argument("key")
36+
def get_config(key):
37+
print(get_config_util(key))
38+
39+
40+
@_cli.cli.command("set_config")
41+
@click.argument("key")
42+
@click.argument("value")
43+
def set_config(key, value):
44+
print(set_config_util(key, value).value)
45+
46+
47+
@_cli.cli.command("build")
48+
@click.argument("cmd")
49+
def build(cmd):
50+
cmd = BUILD_COMMANDS.get(cmd)
51+
cmd()
52+
53+
54+
@_cli.cli.command("export_ctf")
55+
@click.argument("path", default="")
56+
def export_ctf(path):
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_%T")
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+
@_cli.cli.command("import_ctf")
74+
@click.argument("path", type=click.Path(exists=True))
75+
@click.option(
76+
"--delete_import_on_finish",
77+
default=False,
78+
is_flag=True,
79+
help="Delete import file when import is finished",
80+
)
81+
def import_ctf(path, delete_import_on_finish=False):
82+
try:
83+
import_ctf_util(path)
84+
except Exception as e:
85+
from CTFd.utils.dates import unix_time
86+
87+
set_import_error("Import Failure: " + str(e))
88+
set_import_end_time(value=unix_time(datetime.datetime.utcnow()))
89+
90+
if delete_import_on_finish:
91+
print(f"Deleting {path}")
92+
Path(path).unlink()

CTFd/utils/initialization/__init__.py

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,12 @@
4343
)
4444

4545

46+
def init_cli(app):
47+
from CTFd.cli import _cli
48+
49+
app.register_blueprint(_cli, cli_group=None)
50+
51+
4652
def init_template_filters(app):
4753
app.jinja_env.filters["markdown"] = markdown
4854
app.jinja_env.filters["unix_time"] = unix_time

manage.py

Lines changed: 3 additions & 87 deletions
Original file line numberDiff line numberDiff line change
@@ -1,95 +1,11 @@
1-
import datetime
2-
import shutil
3-
from pathlib import Path
4-
5-
from flask_migrate import MigrateCommand
6-
from flask_script import Manager
1+
from flask.cli import FlaskGroup
72

83
from CTFd import create_app
9-
from CTFd.utils import get_config as get_config_util
10-
from CTFd.utils import set_config as set_config_util
11-
from CTFd.utils.config import ctf_name
12-
from CTFd.utils.exports import export_ctf as export_ctf_util
13-
from CTFd.utils.exports import import_ctf as import_ctf_util
14-
from CTFd.utils.exports import (
15-
set_import_end_time,
16-
set_import_error,
17-
)
184

195
app = create_app()
206

21-
manager = Manager(app)
22-
manager.add_command("db", MigrateCommand)
23-
24-
25-
def jsenums():
26-
from CTFd.constants import JS_ENUMS
27-
import json
28-
import os
29-
30-
path = os.path.join(app.root_path, "themes/core/assets/js/constants.js")
31-
32-
with open(path, "w+") as f:
33-
for k, v in JS_ENUMS.items():
34-
f.write("const {} = Object.freeze({});".format(k, json.dumps(v)))
35-
36-
37-
BUILD_COMMANDS = {"jsenums": jsenums}
38-
39-
40-
@manager.command
41-
def get_config(key):
42-
with app.app_context():
43-
print(get_config_util(key))
44-
45-
46-
@manager.command
47-
def set_config(key, value):
48-
with app.app_context():
49-
print(set_config_util(key, value).value)
50-
51-
52-
@manager.command
53-
def build(cmd):
54-
with app.app_context():
55-
cmd = BUILD_COMMANDS.get(cmd)
56-
cmd()
57-
58-
59-
@manager.command
60-
def export_ctf(path=None):
61-
with app.app_context():
62-
backup = export_ctf_util()
63-
64-
if path:
65-
with open(path, "wb") as target:
66-
shutil.copyfileobj(backup, target)
67-
else:
68-
name = ctf_name()
69-
day = datetime.datetime.now().strftime("%Y-%m-%d_%T")
70-
full_name = f"{name}.{day}.zip"
71-
72-
with open(full_name, "wb") as target:
73-
shutil.copyfileobj(backup, target)
74-
75-
print(f"Exported {full_name}")
76-
77-
78-
@manager.command
79-
def import_ctf(path, delete_import_on_finish=False):
80-
with app.app_context():
81-
try:
82-
import_ctf_util(path)
83-
except Exception as e:
84-
from CTFd.utils.dates import unix_time
85-
86-
set_import_error(f"Import Failure: " + str(e))
87-
set_import_end_time(value=unix_time(datetime.datetime.utcnow()))
88-
89-
if delete_import_on_finish:
90-
print(f"Deleting {path}")
91-
Path(path).unlink()
7+
cli = FlaskGroup(app)
928

939

9410
if __name__ == "__main__":
95-
manager.run()
11+
cli()

0 commit comments

Comments
 (0)