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 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")]

View File

@ -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}/<path:table>/<path:path>", methods=["GET"])