diff --git a/src/ttfrog/schema.py b/src/ttfrog/schema.py index 2fa7598..2bbc113 100644 --- a/src/ttfrog/schema.py +++ b/src/ttfrog/schema.py @@ -2,11 +2,18 @@ from __future__ import annotations from datetime import datetime from typing import List +from enum import StrEnum from grung.types import BackReference, Collection, DateTime, Dict, Field, Password, Pointer, Record, Timestamp from tinydb import where +class Permissions(StrEnum): + READ = "r" + WRITE = "w" + DELETE = "d" + + class Page(Record): """ A page in the wiki. Just about everything in the databse is either a Page or a subclass of a Page. @@ -16,7 +23,7 @@ class Page(Record): def fields(cls): # fmt: off return [ - *super().fields(), # Pick up the UID and whatever other non-optional fields exist + *super().fields(), Field("uri", unique=True), # The URI for the page, relative to the app's VIEW_URI Field("name"), # The portion of the URI after the last / Field("title"), # The page title @@ -74,7 +81,7 @@ class Page(Record): def get_child(self, obj: Record): for page in self.members: - if page.uid == obj.uid: + if page[page._metadata.primary_key] == obj[obj._metadata.primary_key]: return page return None @@ -104,8 +111,9 @@ class Page(Record): group_grants = {} for ref, grant in obj.acl.items(): - if ref.startswith("Group::"): - group = app.db.Group.get(where("uid") == ref.split("::")[1], recurse=False) + (table_name, pkey, pval) = ref.split("::") + if table_name == "Group": + group = app.db.Group.get(where(pkey) == pval, recurse=False) if entity.reference in group.members: group_grants[ref] = grant if group_grants: @@ -119,6 +127,18 @@ class Page(Record): class Entity(Page): + + @classmethod + def fields(cls): + inherited = [ + field + for field in super().fields() + if field.name not in ("members", "uid") + ] + return inherited + [ + Field("name", primary_key=True), + ] + def has_permission(self, record: Record, requested: str) -> bool | None: for entity, grants in record.get_acl_for_entity(self).items(): if requested in grants: @@ -140,39 +160,29 @@ class User(Entity): A website user, editable as a wiki page. """ - def check_credentials(self, username: str, password: str) -> bool: - return username == self.name and self._metadata.fields["password"].compare(password, self.password) - @classmethod def fields(cls): - return [ - field - for field in [ - *super().fields(), - Field("email", unique=True), - Password("password"), - ] - if field.name != "members" + return super().fields() + [ + Field("email", unique=True), + Password("password"), ] + def check_credentials(self, username: str, password: str) -> bool: + return username == self.name and self._metadata.fields["password"].compare(password, self.password) + class Group(Entity): """ A set of users, editable as a wiki page. """ + @classmethod + def fields(cls): + return super().fields() + [ + Collection("members", Entity) + ] class NPC(Page): """ An NPC, editable as a wiki page. """ - - -class Permissions(Record): - READ = "r" - WRITE = "w" - DELETE = "d" - - @classmethod - def fields(cls): - return [*super().fields(), Pointer("entity", Entity), Field("grants")] diff --git a/src/ttfrog/web.py b/src/ttfrog/web.py index 0f94679..c8e9b43 100644 --- a/src/ttfrog/web.py +++ b/src/ttfrog/web.py @@ -48,8 +48,8 @@ def get_page(path: str = "", table: str = "Page", create_okay: bool = False): if hasattr(page, "members"): subpages = [] for pointer in page.members: - table, uid = pointer.split("::") - subpages += app.db.table(table).search(where("uid") == uid, recurse=False) + table, pkey, pval = pointer.split("::") + subpages += app.db.table(table).search(where(pkey) == pval, recurse=False) page.members = subpages return page @@ -105,6 +105,7 @@ def logout(): if "user_id" in session: del session["user_id"] del g.user + return redirect(url_for("index")) @app.web.route(f"{app.config.VIEW_URI}//", methods=["GET"])