diff options
Diffstat (limited to 'src/fields/util.ts')
-rw-r--r-- | src/fields/util.ts | 47 |
1 files changed, 25 insertions, 22 deletions
diff --git a/src/fields/util.ts b/src/fields/util.ts index 4c71572db..d8523dfa2 100644 --- a/src/fields/util.ts +++ b/src/fields/util.ts @@ -5,7 +5,7 @@ import { ProxyField, PrefetchProxy } from "./Proxy"; import { RefField } from "./RefField"; import { ObjectField } from "./ObjectField"; import { action, trace } from "mobx"; -import { Parent, OnUpdate, Update, Id, SelfProxy, Self, HandleUpdate } from "./FieldSymbols"; +import { Parent, OnUpdate, Update, Id, SelfProxy, Self, HandleUpdate, ToString, ToScriptString } from "./FieldSymbols"; import { DocServer } from "../client/DocServer"; import { ComputedField } from "./ScriptField"; import { ScriptCast, StrCast } from "./Types"; @@ -154,15 +154,16 @@ export enum SharingPermissions { /** * Calculates the effective access right to a document for the current user. */ -export function GetEffectiveAcl(target: any, in_prop?: string | symbol | number): symbol { +export function GetEffectiveAcl(target: any, in_prop?: string | symbol | number, user?: string): symbol { if (!target) return AclPrivate; if (in_prop === UpdatingFromServer || target[UpdatingFromServer]) return AclAdmin; if (target[AclSym] && Object.keys(target[AclSym]).length) { + const userChecked = user || Doc.CurrentUserEmail; + // if the current user is the author of the document / the current user is a member of the admin group - // but not if the doc in question is an alias - the current user will be the author of their alias rather than the original author - if ((Doc.CurrentUserEmail === (target.__fields?.author || target.author) && !(target.aliasOf || target.__fields?.aliasOf)) || currentUserGroups.includes("admin")) return AclAdmin; + if (userChecked === (target.__fields?.author || target.author) || currentUserGroups.includes("admin")) return AclAdmin; // if the ACL is being overriden or the property being modified is one of the playground fields (which can be freely modified) if (_overrideAcl || (in_prop && DocServer.PlaygroundFields?.includes(in_prop.toString()))) return AclEdit; @@ -179,7 +180,7 @@ export function GetEffectiveAcl(target: any, in_prop?: string | symbol | number) for (const [key, value] of Object.entries(target[AclSym])) { // there are issues with storing fields with . in the name, so they are replaced with _ during creation // as a result we need to restore them again during this comparison. - if (currentUserGroups.includes(key.substring(4)) || Doc.CurrentUserEmail === key.substring(4).replace("_", ".")) { + if (currentUserGroups.includes(key.substring(4).replace("_", ".")) || userChecked === key.substring(4).replace("_", ".")) { if (HierarchyMapping.get(value as symbol)! > HierarchyMapping.get(effectiveAcl)!) { effectiveAcl = value as symbol; if (effectiveAcl === AclAdmin) break; @@ -209,51 +210,53 @@ export function distributeAcls(key: string, acl: SharingPermissions, target: Doc ["Admin", 4] ]); - let changed = false; // determines whether fetchProto should be called or not (i.e. is there a change that should be reflected in target[AclSym]) + let layoutDocChanged = false; // determines whether fetchProto should be called or not (i.e. is there a change that should be reflected in target[AclSym]) + let dataDocChanged = false; const dataDoc = target[DataSym]; // if it is inheriting from a collection, it only inherits if A) the key doesn't already exist or B) the right being inherited is more restrictive if (!inheritingFromCollection || !target[key] || HierarchyMapping.get(StrCast(target[key]))! > HierarchyMapping.get(acl)!) { target[key] = acl; - changed = true; - - // maps over the aliases of the document - if (target.aliases) { - DocListCast(target.aliases).map(alias => { - distributeAcls(key, acl, alias, inheritingFromCollection); - }); - } - + layoutDocChanged = true; } if (dataDoc && (!inheritingFromCollection || !dataDoc[key] || HierarchyMapping.get(StrCast(dataDoc[key]))! > HierarchyMapping.get(acl)!)) { dataDoc[key] = acl; - changed = true; + dataDocChanged = true; + + // maps over the aliases of the document + const aliases = DocListCast(dataDoc.aliases); + if (aliases.length) { + aliases.map(alias => { + alias !== target && distributeAcls(key, acl, alias, inheritingFromCollection); + }); + } // maps over the children of the document DocListCast(dataDoc[Doc.LayoutFieldKey(dataDoc)]).map(d => { - if (d.author === Doc.CurrentUserEmail && (!inheritingFromCollection || !d[key] || HierarchyMapping.get(StrCast(d[key]))! > HierarchyMapping.get(acl)!)) { + if (GetEffectiveAcl(d) === AclAdmin && (!inheritingFromCollection || !d[key] || HierarchyMapping.get(StrCast(d[key]))! > HierarchyMapping.get(acl)!)) { distributeAcls(key, acl, d, inheritingFromCollection); } const data = d[DataSym]; - if (data && data.author === Doc.CurrentUserEmail && (!inheritingFromCollection || !data[key] || HierarchyMapping.get(StrCast(data[key]))! > HierarchyMapping.get(acl)!)) { + if (data && GetEffectiveAcl(data) === AclAdmin && (!inheritingFromCollection || !data[key] || HierarchyMapping.get(StrCast(data[key]))! > HierarchyMapping.get(acl)!)) { distributeAcls(key, acl, data, inheritingFromCollection); } }); // maps over the annotations of the document DocListCast(dataDoc[Doc.LayoutFieldKey(dataDoc) + "-annotations"]).map(d => { - if (d.author === Doc.CurrentUserEmail && (!inheritingFromCollection || !d[key] || HierarchyMapping.get(StrCast(d[key]))! > HierarchyMapping.get(acl)!)) { + if (GetEffectiveAcl(d) === AclAdmin && (!inheritingFromCollection || !d[key] || HierarchyMapping.get(StrCast(d[key]))! > HierarchyMapping.get(acl)!)) { distributeAcls(key, acl, d, inheritingFromCollection); } const data = d[DataSym]; - if (data && data.author === Doc.CurrentUserEmail && (!inheritingFromCollection || !data[key] || HierarchyMapping.get(StrCast(data[key]))! > HierarchyMapping.get(acl)!)) { + if (data && GetEffectiveAcl(data) === AclAdmin && (!inheritingFromCollection || !data[key] || HierarchyMapping.get(StrCast(data[key]))! > HierarchyMapping.get(acl)!)) { distributeAcls(key, acl, data, inheritingFromCollection); } }); } - changed && fetchProto(target); // updates target[AclSym] when changes to acls have been made + layoutDocChanged && fetchProto(target); // updates target[AclSym] when changes to acls have been made + dataDocChanged && fetchProto(dataDoc); } const layoutProps = ["panX", "panY", "width", "height", "nativeWidth", "nativeHeight", "fitWidth", "fitToBox", @@ -286,7 +289,7 @@ export function setter(target: any, in_prop: string | symbol | number, value: an export function getter(target: any, in_prop: string | symbol | number, receiver: any): any { let prop = in_prop; - if (in_prop === FieldsSym || in_prop === Id || in_prop === HandleUpdate || in_prop === CachedUpdates) return target.__fields[prop] || target[prop]; + if (in_prop === ToString || in_prop === ToScriptString || in_prop === FieldsSym || in_prop === Id || in_prop === HandleUpdate || in_prop === CachedUpdates) return target.__fields[prop] || target[prop]; if (in_prop === AclSym) return _overrideAcl ? undefined : target[AclSym]; if (GetEffectiveAcl(target) === AclPrivate && !_overrideAcl) return prop === HeightSym || prop === WidthSym ? returnZero : undefined; if (prop === LayoutSym) { |