diff --git a/ctfcli/__main__.py b/ctfcli/__main__.py index b5bd3a9..71641cf 100644 --- a/ctfcli/__main__.py +++ b/ctfcli/__main__.py @@ -12,6 +12,7 @@ from ctfcli.cli.config import Config from ctfcli.cli.plugins import Plugins from ctfcli.cli.templates import Templates +from ctfcli.cli.pages import Pages from ctfcli.utils.plugins import get_plugin_dir @@ -47,6 +48,9 @@ def config(self): def challenge(self): return COMMANDS.get("challenge") + def pages(self): + return COMMANDS.get("pages") + def plugins(self): return COMMANDS.get("plugins") @@ -57,6 +61,7 @@ def templates(self): COMMANDS = { "challenge": Challenge(), "config": Config(), + "pages": Pages(), "plugins": Plugins(), "templates": Templates(), "cli": CTFCLI(), diff --git a/ctfcli/cli/pages.py b/ctfcli/cli/pages.py new file mode 100644 index 0000000..8d94005 --- /dev/null +++ b/ctfcli/cli/pages.py @@ -0,0 +1,44 @@ +import sys +from pathlib import Path +import frontmatter + +import click + +from ctfcli.utils.config import load_config +from ctfcli.utils.pages import ( + get_current_pages, + get_existing_page, + sync_page, + install_page, +) + + +class Pages(object): + def install(self): + try: + _config = load_config() + except: + click.secho("No ctfcli configuration found", fg="red") + sys.exit(1) + + pages = Path("./pages") + if pages.is_dir() is False: + click.secho( + f'"pages" folder not found. All pages must exist in the "pages" folder.', + fg="red", + ) + sys.exit(1) + else: + current_pages = get_current_pages() + + pagefiles = list(pages.glob("**/*.md")) + list(pages.glob("**/*.html")) + for path_obj in pagefiles: + page = frontmatter.load(path_obj) + existing_page = get_existing_page( + route=page["route"], pageset=current_pages + ) + + if existing_page: + sync_page(page, path_obj, existing_page["id"]) + else: + install_page(page, path_obj) diff --git a/ctfcli/utils/pages.py b/ctfcli/utils/pages.py new file mode 100644 index 0000000..6ddd568 --- /dev/null +++ b/ctfcli/utils/pages.py @@ -0,0 +1,71 @@ +from .config import generate_session + +FORMATS = { + ".md": "markdown", + ".html": "html", + ".htm": "html", +} + + +def get_current_pages(): + s = generate_session() + return s.get(f"/api/v1/pages", json=True).json()["data"] + + +def get_existing_page(route, pageset=None): + if pageset is None: + pageset = get_current_pages() + for page in pageset: + if route == page["route"]: + return page + return None + + +def get_format(ext): + return FORMATS[ext] + + +def sync_page(matter, path_obj, page_id): + route = matter["route"] + title = matter["title"] + content = matter.content + draft = bool(matter.get("draft")) + hidden = bool(matter.get("hidden")) + auth_required = bool(matter.get("auth_required")) + format = get_format(path_obj.suffix) + + s = generate_session() + data = { + "route": route, + "title": title, + "content": content, + "draft": draft, + "hidden": hidden, + "auth_required": auth_required, + "format": format, + } + r = s.patch(f"/api/v1/pages/{page_id}", json=data) + r.raise_for_status() + + +def install_page(matter, path_obj): + route = matter["route"] + title = matter["title"] + content = matter.content + draft = bool(matter.get("draft")) + hidden = bool(matter.get("hidden")) + auth_required = bool(matter.get("auth_required")) + format = get_format(path_obj.suffix) + + s = generate_session() + data = { + "route": route, + "title": title, + "content": content, + "draft": draft, + "hidden": hidden, + "auth_required": auth_required, + "format": format, + } + r = s.post(f"/api/v1/pages", json=data) + r.raise_for_status() diff --git a/requirements.txt b/requirements.txt index 0664eed..bb4ca36 100644 --- a/requirements.txt +++ b/requirements.txt @@ -6,3 +6,4 @@ Pygments==2.7.4 requests==2.22.0 colorama==0.4.3 appdirs==1.4.3 +python-frontmatter==1.0.0 diff --git a/setup.py b/setup.py index 297120e..fd8c522 100644 --- a/setup.py +++ b/setup.py @@ -41,6 +41,7 @@ def read(fname): "requests==2.22.0", "colorama==0.4.3", "appdirs==1.4.3", + "python-frontmatter==1.0.0", ], packages=find_packages(), include_package_data=True,