implement primary keys

This commit is contained in:
evilchili 2025-10-08 00:46:09 -07:00
parent b395940d2d
commit bb3070aa1a
2 changed files with 38 additions and 27 deletions

View File

@ -2,11 +2,18 @@ from __future__ import annotations
from datetime import datetime from datetime import datetime
from typing import List from typing import List
from enum import StrEnum
from grung.types import BackReference, Collection, DateTime, Dict, Field, Password, Pointer, Record, Timestamp from grung.types import BackReference, Collection, DateTime, Dict, Field, Password, Pointer, Record, Timestamp
from tinydb import where from tinydb import where
class Permissions(StrEnum):
READ = "r"
WRITE = "w"
DELETE = "d"
class Page(Record): class Page(Record):
""" """
A page in the wiki. Just about everything in the databse is either a Page or a subclass of a Page. 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): def fields(cls):
# fmt: off # fmt: off
return [ 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("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("name"), # The portion of the URI after the last /
Field("title"), # The page title Field("title"), # The page title
@ -74,7 +81,7 @@ class Page(Record):
def get_child(self, obj: Record): def get_child(self, obj: Record):
for page in self.members: for page in self.members:
if page.uid == obj.uid: if page[page._metadata.primary_key] == obj[obj._metadata.primary_key]:
return page return page
return None return None
@ -104,8 +111,9 @@ class Page(Record):
group_grants = {} group_grants = {}
for ref, grant in obj.acl.items(): for ref, grant in obj.acl.items():
if ref.startswith("Group::"): (table_name, pkey, pval) = ref.split("::")
group = app.db.Group.get(where("uid") == ref.split("::")[1], recurse=False) if table_name == "Group":
group = app.db.Group.get(where(pkey) == pval, recurse=False)
if entity.reference in group.members: if entity.reference in group.members:
group_grants[ref] = grant group_grants[ref] = grant
if group_grants: if group_grants:
@ -119,6 +127,18 @@ class Page(Record):
class Entity(Page): 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: def has_permission(self, record: Record, requested: str) -> bool | None:
for entity, grants in record.get_acl_for_entity(self).items(): for entity, grants in record.get_acl_for_entity(self).items():
if requested in grants: if requested in grants:
@ -140,39 +160,29 @@ class User(Entity):
A website user, editable as a wiki page. 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 @classmethod
def fields(cls): def fields(cls):
return [ return super().fields() + [
field
for field in [
*super().fields(),
Field("email", unique=True), Field("email", unique=True),
Password("password"), Password("password"),
] ]
if field.name != "members"
] 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): class Group(Entity):
""" """
A set of users, editable as a wiki page. A set of users, editable as a wiki page.
""" """
@classmethod
def fields(cls):
return super().fields() + [
Collection("members", Entity)
]
class NPC(Page): class NPC(Page):
""" """
An NPC, editable as a wiki 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")]

View File

@ -48,8 +48,8 @@ def get_page(path: str = "", table: str = "Page", create_okay: bool = False):
if hasattr(page, "members"): if hasattr(page, "members"):
subpages = [] subpages = []
for pointer in page.members: for pointer in page.members:
table, uid = pointer.split("::") table, pkey, pval = pointer.split("::")
subpages += app.db.table(table).search(where("uid") == uid, recurse=False) subpages += app.db.table(table).search(where(pkey) == pval, recurse=False)
page.members = subpages page.members = subpages
return page return page
@ -105,6 +105,7 @@ def logout():
if "user_id" in session: if "user_id" in session:
del session["user_id"] del session["user_id"]
del g.user del g.user
return redirect(url_for("index"))
@app.web.route(f"{app.config.VIEW_URI}/<path:table>/<path:path>", methods=["GET"]) @app.web.route(f"{app.config.VIEW_URI}/<path:table>/<path:path>", methods=["GET"])