diff options
Diffstat (limited to 'pysite/views')
| -rw-r--r-- | pysite/views/staff/index.py | 21 | ||||
| -rw-r--r-- | pysite/views/staff/tables/__init__.py | 0 | ||||
| -rw-r--r-- | pysite/views/staff/tables/edit.py | 110 | ||||
| -rw-r--r-- | pysite/views/staff/tables/index.py | 13 | ||||
| -rw-r--r-- | pysite/views/staff/tables/table.py | 63 | ||||
| -rw-r--r-- | pysite/views/staff/tables/table_bare.py | 30 | ||||
| -rw-r--r-- | pysite/views/wiki/special/__init__.py | 1 | 
7 files changed, 234 insertions, 4 deletions
| diff --git a/pysite/views/staff/index.py b/pysite/views/staff/index.py index 11447f87..fc05f1a7 100644 --- a/pysite/views/staff/index.py +++ b/pysite/views/staff/index.py @@ -3,14 +3,29 @@ from pprint import pformat  from flask import current_app  from pysite.base_route import RouteView -from pysite.constants import ALL_STAFF_ROLES +from pysite.constants import ALL_STAFF_ROLES, DEBUG_MODE, TABLE_MANAGER_ROLES  from pysite.decorators import require_roles  class StaffView(RouteView):      path = "/" -    name = "index" +    name = "staff_index"      @require_roles(*ALL_STAFF_ROLES)      def get(self): -        return self.render("staff/staff.html", app_config=pformat(current_app.config, indent=4, width=120)) +        return self.render( +            "staff/staff.html", manager=self.is_table_editor(), +            app_config=pformat(current_app.config, indent=4, width=120) +        ) + +    def is_table_editor(self): +        if DEBUG_MODE: +            return True + +        data = self.user_data + +        for role in TABLE_MANAGER_ROLES: +            if role in data.get("roles", []): +                return True + +        return False diff --git a/pysite/views/staff/tables/__init__.py b/pysite/views/staff/tables/__init__.py new file mode 100644 index 00000000..e69de29b --- /dev/null +++ b/pysite/views/staff/tables/__init__.py diff --git a/pysite/views/staff/tables/edit.py b/pysite/views/staff/tables/edit.py new file mode 100644 index 00000000..b70bc20e --- /dev/null +++ b/pysite/views/staff/tables/edit.py @@ -0,0 +1,110 @@ +import json + +from flask import redirect, request, url_for +from werkzeug.exceptions import BadRequest, NotFound + +from pysite.base_route import RouteView +from pysite.constants import TABLE_MANAGER_ROLES +from pysite.decorators import csrf, require_roles +from pysite.mixins import DBMixin +from pysite.tables import TABLES + + +class TableEditView(RouteView, DBMixin): +    path = "/tables/<table>/edit" +    name = "tables.edit" + +    @require_roles(*TABLE_MANAGER_ROLES) +    def get(self, table): +        obj = TABLES.get(table) + +        if not obj: +            # Unknown table +            raise NotFound() + +        if obj.locked: +            return redirect(url_for("staff.tables.table", table=table, page=1), code=303) + +        key = request.args.get("key") + +        old_primary = None + +        if key: +            db_obj = self.db.get(table, key) +            old_primary = key  # Provide the current document's primary key, in case it's modified + +            document = json.dumps(  # Editor uses JSON +                db_obj, +                indent=4 +            ) +        else: +            document = json.dumps(  # Generate default document from key schema +                {k: "" for k in obj.keys}, +                indent=4 +            ) + +        return self.render( +            "staff/tables/edit.html", table=table, primary_key=obj.primary_key, +            document=document, old_primary=old_primary +        ) + +    @require_roles(*TABLE_MANAGER_ROLES) +    @csrf +    def post(self, table): +        obj = TABLES.get(TABLES) + +        if not obj: +            # Unknown table +            raise NotFound() + +        if obj.locked: +            raise BadRequest() + +        data = request.form.get("json") +        old_primary = request.form.get("old_primary") + +        if not data: +            # No data given (for some reason) +            document = json.dumps( +                {k: "" for k in obj.keys}, +                indent=4 +            ) + +            return self.render( +                "staff/tables/edit.html", table=table, primary_key=obj.primary_key, document=document, +                message="Please provide some data to save", old_primary=old_primary +            ) + +        try: +            data = json.loads(data) +        except json.JSONDecodeError as e: +            # Invalid JSON +            return self.render( +                "staff/tables/edit.html", table=table, primary_key=obj.primary_key, document=data, +                message=f"Invalid JSON, please try again: {e}", old_primary=old_primary +            ) + +        if not data[obj.primary_key]: +            # No primary key value provided +            return self.render( +                "staff/tables/edit.html", table=table, primary_key=obj.primary_key, document=data, +                message=f"Please provide a value for the primary key: {obj.primary_key}", old_primary=old_primary +            ) + +        if old_primary is None: +            self.db.insert(  # This is a new object, so just insert it +                table, data +            ) +        elif old_primary == data[obj.primary_key]: +            self.db.insert(  # This is an update without a primary key change, replace the whole document +                table, data, conflict="replace" +            ) +        else: +            self.db.delete(  # This is a primary key change, so we need to remove the old object +                table, old_primary +            ) +            self.db.insert( +                table, data, +            ) + +        return redirect(url_for("staff.tables.table", table=table, page=1), code=303) diff --git a/pysite/views/staff/tables/index.py b/pysite/views/staff/tables/index.py new file mode 100644 index 00000000..0d84aeb4 --- /dev/null +++ b/pysite/views/staff/tables/index.py @@ -0,0 +1,13 @@ +from pysite.base_route import RouteView +from pysite.constants import TABLE_MANAGER_ROLES +from pysite.decorators import require_roles +from pysite.tables import TABLES + + +class TablesView(RouteView): +    path = "/tables" +    name = "tables.index" + +    @require_roles(*TABLE_MANAGER_ROLES) +    def get(self): +        return self.render("staff/tables/index.html", tables=TABLES) diff --git a/pysite/views/staff/tables/table.py b/pysite/views/staff/tables/table.py new file mode 100644 index 00000000..f47d7793 --- /dev/null +++ b/pysite/views/staff/tables/table.py @@ -0,0 +1,63 @@ +from math import ceil + +from flask import request +from werkzeug.exceptions import BadRequest, NotFound + +from pysite.base_route import RouteView +from pysite.constants import TABLE_MANAGER_ROLES +from pysite.decorators import require_roles +from pysite.mixins import DBMixin +from pysite.tables import TABLES + + +class TableView(RouteView, DBMixin): +    path = "/tables/<table>/<page>" +    name = "tables.table" + +    @require_roles(*TABLE_MANAGER_ROLES) +    def get(self, table, page): +        search = request.args.get("search") +        search_key = request.args.get("search-key") + +        pages = page +        obj = TABLES.get(table) + +        if not obj: +            return NotFound() + +        if search: +            new_search = f"(?i){search}"  # Case-insensitive search +            search_key = search_key or obj.primary_key + +            query = self.db.query(table).filter(lambda d: d[search_key].match(new_search)) +        else: +            query = self.db.query(table) + +        if page != "all": +            try: +                page = int(page) +            except ValueError: +                # Not an integer +                return BadRequest() + +            count = self.db.run(query.count(), coerce=int) +            pages = max(ceil(count / 10), 1)  # Pages if we have 10 documents per page, always at least one + +            if page < 1 or page > pages: +                # If the page is too small or too big, well, that's an error +                return BadRequest() + +            documents = self.db.run(  # Get only the documents for this page +                query.skip((page - 1) * 10).limit(10), +                coerce=list +            ) +        else: +            documents = self.db.run(query, coerce=list) + +        documents = [dict(sorted(d.items())) for d in documents] + +        return self.render( +            "staff/tables/table.html", +            table=table, documents=documents, table_obj=obj, +            page=page, pages=pages, search=search, search_key=search_key +        ) diff --git a/pysite/views/staff/tables/table_bare.py b/pysite/views/staff/tables/table_bare.py new file mode 100644 index 00000000..abd6cb19 --- /dev/null +++ b/pysite/views/staff/tables/table_bare.py @@ -0,0 +1,30 @@ +from flask import redirect, request, url_for +from werkzeug.exceptions import NotFound + +from pysite.base_route import RouteView +from pysite.constants import TABLE_MANAGER_ROLES +from pysite.decorators import require_roles +from pysite.mixins import DBMixin +from pysite.tables import TABLES + + +class TableView(RouteView, DBMixin): +    path = "/tables/<table>" +    name = "tables.table_bare" + +    @require_roles(*TABLE_MANAGER_ROLES) +    def get(self, table): +        if table not in TABLES: +            raise NotFound() + +        search = request.args.get("search") + +        args = { +            "table": table, +            "page": 1 +        } + +        if search is not None: +            args["search"] = search + +        return redirect(url_for("staff.tables.table", **args)) diff --git a/pysite/views/wiki/special/__init__.py b/pysite/views/wiki/special/__init__.py index 9bad5790..e69de29b 100644 --- a/pysite/views/wiki/special/__init__.py +++ b/pysite/views/wiki/special/__init__.py @@ -1 +0,0 @@ -# coding=utf-8 | 
