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 |