Skip to content

Commit

Permalink
feat: Public-files repos and improved rootnodes (#1349)
Browse files Browse the repository at this point in the history
- `Skeleton.read()` now allows to create an entry when not existing
(Skeletonish replacement for db.GetOrInsert()`
- `Tree.rootnodeSkel()` with optional ensure-feature
- Deprecation of `Tree.ensureOwnModuleRootNode()`
- `File.FileNodeSkel` now contains a `public`-bone to identify public
root nodes
- `File.getUploadURL()` checks against public-setting of the uploaded
file and the repository given
  • Loading branch information
phorward authored Dec 11, 2024
1 parent 9e3845c commit 87ce810
Show file tree
Hide file tree
Showing 6 changed files with 67 additions and 8 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ This file documents any relevant changes done to ViUR-core since version 3.
- feat: Make SkeletonInstance json serializable (#1262)
- feat: Provide `ignore`-parameter for `Skeleton.fromClient` (#1330)
- feat: Provide `User.is_active()` function (#1309)
- feat: Public-files repos and improved rootnodes
- feat: Retrieve default `descr` from bone's name in its Skeleton (#1227)
- feat+refactor: Improved and extended `Skeleton.subskel()` (#1259)
- fix: `File.write()` didn't return `db.Key` (#1303)
Expand Down
14 changes: 14 additions & 0 deletions src/viur/core/modules/file.py
Original file line number Diff line number Diff line change
Expand Up @@ -428,8 +428,19 @@ class FileNodeSkel(TreeSkel):
rootNode = BooleanBone(
descr="Is RootNode",
defaultValue=False,
readOnly=True,
visible=False,
)

public = BooleanBone(
descr="Is public?",
defaultValue=False,
readOnly=True,
visible=False,
)

viurCurrentSeoKeys = None


class File(Tree):
PENDING_POSTFIX = " (pending)"
Expand Down Expand Up @@ -859,6 +870,9 @@ def getUploadURL(
if not self.canAdd("leaf", rootNode):
raise errors.Forbidden()

if rootNode and public != bool(rootNode.get("public")):
raise errors.Forbidden("Cannot upload a public file into private repository or vice versa")

maxSize = None # The user has some file/add permissions, don't restrict fileSize

if maxSize:
Expand Down
37 changes: 34 additions & 3 deletions src/viur/core/prototypes/tree.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import logging
import typing as t
from deprecated.sphinx import deprecated
from viur.core import utils, errors, db, current
from viur.core.decorators import *
from viur.core.bones import KeyBone, SortIndexBone
Expand Down Expand Up @@ -138,16 +139,46 @@ def cloneSkel(self, skelType: SkelType, *args, **kwargs) -> SkeletonInstance:
"""
return self.baseSkel(skelType, *args, **kwargs)

def rootnodeSkel(
self,
*,
identifier: str = "rep_module_repo",
ensure: bool | dict | t.Callable[[SkeletonInstance], None] = False,
) -> SkeletonInstance:
"""
Retrieve a new :class:`viur.core.skeleton.SkeletonInstance` that is used by the application
for rootnode entries.
The default is a SkeletonInstance returned by :func:`~baseSkel`, with a preset key created from identifier.
:param identifier: Unique identifier (name) for this rootnode.
:param ensure: If provided, ensures that the skeleton is available, and created with optionally provided values.
:return: Returns a SkeletonInstance for handling root nodes.
"""
skel = self.baseSkel("node")

skel["key"] = db.Key(skel.kindName, identifier)
skel["rootNode"] = True

if ensure not in (False, None):
return skel.read(create=ensure)

return skel

@deprecated(
version="3.7.0",
reason="Use rootnodeSkel(ensure=True) instead.",
action="always"
)
def ensureOwnModuleRootNode(self) -> db.Entity:
"""
Ensures, that general root-node for the current module exists.
If no root-node exists yet, it will be created.
:returns: The entity of the root-node.
"""
key = "rep_module_repo"
kindName = self.viewSkel("node").kindName
return db.GetOrInsert(db.Key(kindName, key), creationdate=utils.utcNow(), rootNode=1)
return self.rootnodeSkel(ensure=True).dbEntity

def getAvailableRootNodes(self, *args, **kwargs) -> list[dict[t.Literal["name", "key"], str]]:
"""
Expand Down
1 change: 1 addition & 0 deletions src/viur/core/render/json/default.py
Original file line number Diff line number Diff line change
Expand Up @@ -233,6 +233,7 @@ def deleteSuccess(self, skel: SkeletonInstance, params=None, *args, **kwargs):
return json.dumps("OKAY")

def listRootNodes(self, rootNodes, *args, **kwargs):
current.request.get().response.headers["Content-Type"] = "application/json"
return json.dumps(rootNodes, cls=CustomJsonEncoder)

def render(self, action: str, skel: t.Optional[SkeletonInstance] = None, **kwargs):
Expand Down
20 changes: 16 additions & 4 deletions src/viur/core/skeleton.py
Original file line number Diff line number Diff line change
Expand Up @@ -1112,6 +1112,7 @@ def read(
skel: SkeletonInstance,
key: t.Optional[KeyType] = None,
*,
create: bool | dict | t.Callable[[SkeletonInstance], None] = False,
_check_legacy: bool = True
) -> t.Optional[SkeletonInstance]:
"""
Expand All @@ -1126,6 +1127,8 @@ def read(
:param key: A :class:`viur.core.db.Key`, string, or int; from which the data shall be fetched.
If not provided, skel["key"] will be used.
:param create: Allows to specify a dict or initial callable that is executed in case the Skeleton with the
given key does not exist, it will be created.
:returns: None on error, or the given SkeletonInstance on success.
Expand All @@ -1143,11 +1146,20 @@ def read(
except (ValueError, NotImplementedError): # This key did not parse
return None

if not (db_res := db.Get(db_key)):
if db_res := db.Get(db_key):
skel.setEntity(db_res)
return skel
elif create in (False, None):
return None

skel.setEntity(db_res)
return skel
elif isinstance(create, dict):
if create and not skel.fromClient(create, amend=True):
raise ReadFromClientException(skel.errors)
elif callable(create):
create(skel)
elif create is not True:
raise ValueError("'create' must either be dict, a callable or True.")

return skel.write()

@classmethod
@deprecated(
Expand Down
2 changes: 1 addition & 1 deletion src/viur/core/version.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
# This will mark it as a pre-release as well on PyPI.
# See CONTRIBUTING.md for further information.

__version__ = "3.7.0.rc8"
__version__ = "3.7.0.rc9"

assert __version__.count(".") >= 2 and "".join(__version__.split(".", 3)[:3]).isdigit(), \
"Semantic __version__ expected!"

0 comments on commit 87ce810

Please sign in to comment.