feat: add global user namespace for shared access
Create a special _global namespace that every new user automatically gets can_create_rel access to (inclusive of can_read). This provides a shared space where all users can see and interact with published nodes. - ensureGlobalNamespace creates _global on first use with self-ownership - ensureUser grants can_create_rel to each new user on the global namespace - User visibility still relies on existing post-BFS global readability Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
This commit is contained in:
@@ -810,6 +810,37 @@ func (s *nodeServiceImpl) resolveUserRef(st store.GraphStore, ref string) (strin
|
|||||||
return s.ensureUser(st, ref)
|
return s.ensureUser(st, ref)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const globalNamespace = "_global"
|
||||||
|
|
||||||
|
func (s *nodeServiceImpl) ensureGlobalNamespace(st store.GraphStore) (string, error) {
|
||||||
|
nsID, err := s.resolveIDByNameAndType(st, globalNamespace, "namespace")
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
if nsID != "" {
|
||||||
|
return nsID, nil
|
||||||
|
}
|
||||||
|
id, err := st.GenerateID()
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
now := time.Now().UTC().Format(time.RFC3339)
|
||||||
|
if err := st.AddNode(id, globalNamespace, "", nil, now, now); err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
if err := st.AddRel(id, "_type::namespace", ""); err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
if err := st.AddRel(id, string(models.RelInNamespace), id); err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
// Self-owned so no single user controls it.
|
||||||
|
if err := st.AddRel(id, string(models.RelHasOwnership), id); err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
return id, nil
|
||||||
|
}
|
||||||
|
|
||||||
func (s *nodeServiceImpl) ensureUser(st store.GraphStore, username string) (string, error) {
|
func (s *nodeServiceImpl) ensureUser(st store.GraphStore, username string) (string, error) {
|
||||||
userID, err := s.resolveIDByNameAndType(st, username, "user")
|
userID, err := s.resolveIDByNameAndType(st, username, "user")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -833,6 +864,17 @@ func (s *nodeServiceImpl) ensureUser(st store.GraphStore, username string) (stri
|
|||||||
if err := st.AddRel(id, string(models.RelHasOwnership), id); err != nil {
|
if err := st.AddRel(id, string(models.RelHasOwnership), id); err != nil {
|
||||||
return "", err
|
return "", err
|
||||||
}
|
}
|
||||||
|
// Every user gets can_create_rel access to the global namespace (inclusive
|
||||||
|
// of can_read), providing a shared space where all users can see and interact with
|
||||||
|
// nodes that are published there. User nodes themselves are already
|
||||||
|
// globally readable via the post-BFS identity override in getPermContext.
|
||||||
|
globalNsID, err := s.ensureGlobalNamespace(st)
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
if err := st.AddRel(id, string(models.RelCanCreateRel), globalNsID); err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
return id, nil
|
return id, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user