From b8f156cfa1d145eb813814bc0260a9ac33237ee6 Mon Sep 17 00:00:00 2001 From: Rob van der Linde <robvdl@gmail.com> Date: Tue, 12 Mar 2024 09:41:38 +1300 Subject: [PATCH] config: setup RootFactory and traversal First of all get rid of the "home" view, which gets replaced by the top node in the RootFactory. As a side effect, that means we need to refer to "/" directly in the login and logout views, we can't use request.route_url("home") anymore as I have not figured out a way to name the top node of the RootFactory, and I don't think you can. For now add a single view handler for all Resource rather than a specific one for UserResource etc. Perhaps that come later, but added UserResource to the code as an example. This view handler always produces json. The scope= argument of Model.query hasn't landed in Samba yet, but I'll see it gets added, as it's clearly needed to override the default. Closes #4 --- src/sambal/resources/__init__.py | 5 +++++ src/sambal/resources/base.py | 15 +++++++++++++++ src/sambal/resources/root.py | 17 +++++++++++++++++ src/sambal/resources/user.py | 7 +++++++ src/sambal/routes.py | 5 ++++- src/sambal/views/auth.py | 4 ++-- src/sambal/views/domain.py | 14 ++++++++++++++ 7 files changed, 64 insertions(+), 3 deletions(-) create mode 100644 src/sambal/resources/__init__.py create mode 100644 src/sambal/resources/base.py create mode 100644 src/sambal/resources/root.py create mode 100644 src/sambal/resources/user.py create mode 100644 src/sambal/views/domain.py diff --git a/src/sambal/resources/__init__.py b/src/sambal/resources/__init__.py new file mode 100644 index 0000000..fc00049 --- /dev/null +++ b/src/sambal/resources/__init__.py @@ -0,0 +1,5 @@ +from .base import Resource +from .root import RootFactory +from .user import UserResource + +__all__ = ("Resource", "RootFactory", "UserResource") diff --git a/src/sambal/resources/base.py b/src/sambal/resources/base.py new file mode 100644 index 0000000..649564c --- /dev/null +++ b/src/sambal/resources/base.py @@ -0,0 +1,15 @@ +from ldb import SCOPE_ONELEVEL +from samba.netcmd.domain.models import Model + + +class Resource(dict): + model = Model + + def __init__(self, request, obj): + if request.samdb: + qs = self.model.query(request.samdb, base_dn=obj.dn, scope=SCOPE_ONELEVEL) + data = {model.name: model.as_dict() for model in qs if model} + else: + data = {} + + super().__init__(**data) diff --git a/src/sambal/resources/root.py b/src/sambal/resources/root.py new file mode 100644 index 0000000..2a05412 --- /dev/null +++ b/src/sambal/resources/root.py @@ -0,0 +1,17 @@ +from ldb import SCOPE_ONELEVEL +from samba.netcmd.domain.models import Model + +from .base import Resource + + +class RootFactory(dict): + model = Model + + def __init__(self, request): + if request.samdb: + qs = self.model.query(request.samdb, scope=SCOPE_ONELEVEL) + data = {obj.name: Resource(request, obj) for obj in qs if obj} + else: + data = {} + + super().__init__(**data) diff --git a/src/sambal/resources/user.py b/src/sambal/resources/user.py new file mode 100644 index 0000000..c961b77 --- /dev/null +++ b/src/sambal/resources/user.py @@ -0,0 +1,7 @@ +from samba.netcmd.domain.models import User + +from .base import Resource + + +class UserResource(Resource): + model = User diff --git a/src/sambal/routes.py b/src/sambal/routes.py index 75676d6..1de36f1 100644 --- a/src/sambal/routes.py +++ b/src/sambal/routes.py @@ -1,5 +1,8 @@ +from sambal.resources import RootFactory + + def includeme(config): config.add_static_view("static", "static", cache_max_age=3600) - config.add_route("home", "/") + config.set_root_factory(RootFactory) config.add_route("login", "/login/") config.add_route("logout", "/logout/") diff --git a/src/sambal/views/auth.py b/src/sambal/views/auth.py index 8c2c4bb..d7ccb66 100644 --- a/src/sambal/views/auth.py +++ b/src/sambal/views/auth.py @@ -31,7 +31,7 @@ def login(request): # Avoid looping the login page if accessed directly. # Also, as the app uses traversal request.matched_route can be None. if request.matched_route and request.matched_route.name == "login": - return_url = request.route_path("home") + return_url = "/" else: return_url = request.path @@ -47,5 +47,5 @@ def login(request): def logout(request): """Logout user.""" headers = request.logout() - redirect_url = request.route_url("home") + redirect_url = "/" return HTTPFound(location=redirect_url, headers=headers) diff --git a/src/sambal/views/domain.py b/src/sambal/views/domain.py new file mode 100644 index 0000000..d11ee6e --- /dev/null +++ b/src/sambal/views/domain.py @@ -0,0 +1,14 @@ +from pyramid.view import view_config + +from sambal.resources import Resource, RootFactory + + +@view_config(context=Resource, permission="read", renderer="json") +@view_config(context=RootFactory, permission="read", renderer="json") +def resource_view(context, request): + """Temporary view to produce JSON for every node. + + For this to work a custom JSON encoder is used to deal with the + various objects that aren't JSON encode-able out of the box. + """ + return context