aboutsummaryrefslogtreecommitdiff
path: root/src/fields/util.ts
diff options
context:
space:
mode:
authorbobzel <zzzman@gmail.com>2023-07-07 13:36:21 -0400
committerbobzel <zzzman@gmail.com>2023-07-07 13:36:21 -0400
commitfa38dbe06d6ddb5f4499b759459a24d2b3c111e8 (patch)
tree64020a79fcc4eedf77d2bddfd2c1cb048ed077d9 /src/fields/util.ts
parent53fe9a1e2503d8112ddb2f2101f46d5a2e23c791 (diff)
a bunch of fixes to simplify collaboration and make it work better.
Diffstat (limited to 'src/fields/util.ts')
-rw-r--r--src/fields/util.ts77
1 files changed, 17 insertions, 60 deletions
diff --git a/src/fields/util.ts b/src/fields/util.ts
index fc0057827..9230d9df0 100644
--- a/src/fields/util.ts
+++ b/src/fields/util.ts
@@ -14,6 +14,7 @@ import { List } from './List';
import { ObjectField } from './ObjectField';
import { PrefetchProxy, ProxyField } from './Proxy';
import { RefField } from './RefField';
+import { RichTextField } from './RichTextField';
import { SchemaHeaderField } from './SchemaHeaderField';
import { ComputedField } from './ScriptField';
import { ScriptCast, StrCast } from './Types';
@@ -62,8 +63,9 @@ const _setterImpl = action(function (target: any, prop: string | symbol | number
const writeMode = DocServer.getFieldWriteMode(prop as string);
const fromServer = target[UpdatingFromServer];
const sameAuthor = fromServer || receiver.author === Doc.CurrentUserEmail;
- const writeToDoc = sameAuthor || effectiveAcl === AclEdit || effectiveAcl === AclAugment || effectiveAcl === AclAdmin || writeMode !== DocServer.WriteMode.LiveReadonly;
- const writeToServer = (sameAuthor || effectiveAcl === AclEdit || effectiveAcl === AclAugment || effectiveAcl === AclAdmin) && !DocServer.Control.isReadOnly();
+ const writeToDoc =
+ sameAuthor || effectiveAcl === AclEdit || effectiveAcl === AclAdmin || writeMode === DocServer.WriteMode.Playground || writeMode === DocServer.WriteMode.LivePlayground || (effectiveAcl === AclAugment && value instanceof RichTextField);
+ const writeToServer = (sameAuthor || effectiveAcl === AclEdit || effectiveAcl === AclAdmin || (effectiveAcl === AclAugment && value instanceof RichTextField)) && !DocServer.Control.isReadOnly();
if (writeToDoc) {
if (value === undefined) {
@@ -104,7 +106,7 @@ const _setterImpl = action(function (target: any, prop: string | symbol | number
);
return true;
}
- return false;
+ return true;
});
let _setter: (target: any, prop: string | symbol | number, value: any, receiver: any) => boolean = _setterImpl;
@@ -128,6 +130,7 @@ export function denormalizeEmail(email: string) {
* Copies parent's acl fields to the child
*/
export function inheritParentAcls(parent: Doc, child: Doc) {
+ if (GetEffectiveAcl(parent) !== AclAdmin) return;
for (const key of Object.keys(parent)) {
// if the default acl mode is private, then don't inherit the acl-Public permission, but set it to private.
// const permission: string = key === 'acl-Public' && Doc.defaultAclPrivate ? AclPrivate : parent[key];
@@ -168,30 +171,16 @@ const getEffectiveAclCache = computedFn(function (target: any, user?: string) {
return getEffectiveAcl(target, user);
}, true);
-// return layout acl from cache or chache the acl and return.
-const getEffectiveLayoutAclCache = computedFn(function (target: any, user?: string) {
- return getEffectiveLayoutAcl(target, user);
-}, true);
-
/**
* Calculates the effective access right to a document for the current user.
*/
export function GetEffectiveAcl(target: any, user?: string): symbol {
if (!target) return AclPrivate;
if (target[UpdatingFromServer]) return AclAdmin;
- return getEffectiveAclCache(Doc.GetProto(target), user); // all changes received from the server must be processed as Admin. return this directly so that the acls aren't cached (UpdatingFromServer is not observable)
-}
-
-/**
- * Calculates the effective access layout right to a document for the current user. By getting the container's effective acl if the layout acl isn't set.
- */
-export function GetEffectiveLayoutAcl(target: any, user?: string): symbol {
- if (!target) return AclPrivate;
- if (target[UpdatingFromServer]) return AclAdmin;
- return getEffectiveLayoutAclCache(target, user);
+ return getEffectiveAclCache(target, user); // all changes received from the server must be processed as Admin. return this directly so that the acls aren't cached (UpdatingFromServer is not observable)
}
-function getPropAcl(target: any, prop: string | symbol | number) {
+export function GetPropAcl(target: any, prop: string | symbol | number) {
if (typeof prop === 'symbol' || target[UpdatingFromServer]) return AclAdmin; // requesting the UpdatingFromServer prop or AclSym must always go through to keep the local DB consistent
if (prop && DocServer.IsPlaygroundField(prop.toString())) return AclEdit; // playground props are always editable
return GetEffectiveAcl(target);
@@ -234,37 +223,6 @@ function getEffectiveAcl(target: any, user?: string): symbol {
}
/**
- * Returns the layout acl that is effective on the document passed through as the target. If no layout acls
- * have been set, it returns the regular acls for the document target is contained in.
- */
-function getEffectiveLayoutAcl(target: any, user?: string): symbol {
- const targetAcls = target[DocAcl];
-
- 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
- if (targetAcls && Object.keys(targetAcls).length) {
- var effectiveAcl;
- for (const [key, value] of Object.entries(targetAcls)) {
- const entity = denormalizeEmail(key.substring(4)); // an individual or a group
- if ((GetCachedGroupByName(entity) || userChecked === entity || entity === 'Me') && entity != 'Public') {
- if (effectiveAcl && HierarchyMapping.get(value as symbol)!.level > HierarchyMapping.get(effectiveAcl)!.level) {
- effectiveAcl = value as symbol;
- } else {
- effectiveAcl = value as symbol;
- }
- }
- }
-
- if (effectiveAcl) {
- return DocServer?.Control?.isReadOnly?.() && HierarchyMapping.get(effectiveAcl)!.level < aclLevel.editable ? AclEdit : effectiveAcl;
- }
- }
- // authored documents are private until an ACL is set.
- const targetAuthor = target.__fieldTuples?.author || target.author; // target may be a Doc or Proxy, so check __fieldTuples.author and .author
- if (targetAuthor && targetAuthor !== userChecked) return AclPrivate;
- return AclAdmin;
-}
-
-/**
* Recursively distributes the access right for a user across the children of a document and its annotations.
* @param key the key storing the access right (e.g. acl-groupname)
* @param acl the access right being stored (e.g. "Can Edit")
@@ -272,11 +230,13 @@ function getEffectiveLayoutAcl(target: any, user?: string): symbol {
* @param inheritingFromCollection whether the target is being assigned rights after being dragged into a collection (and so is inheriting the acls from the collection)
* inheritingFromCollection is not currently being used but could be used if acl assignment defaults change
*/
-export function distributeAcls(key: string, acl: SharingPermissions, target: Doc, inheritingFromCollection?: boolean, visited?: Doc[], isDashboard?: boolean) {
+export function distributeAcls(key: string, acl: SharingPermissions, target: Doc, inheritingFromCollection?: boolean, visited?: Doc[]) {
if (!visited) visited = [] as Doc[];
if (!target || visited.includes(target)) return;
if ((target._type_collection === CollectionViewType.Docking && visited.length > 1) || Doc.GetProto(visited[0]) !== Doc.GetProto(target)) {
- target[key] = acl;
+ if (target.author !== Doc.CurrentUserEmail || key !== `acl-${Doc.CurrentUserEmailNormalized}`) {
+ target[key] = acl;
+ }
if (target !== Doc.GetProto(target)) {
//apparently we can't call updateCachedAcls twice (once for the main dashboard, and again for the nested dashboard...???)
updateCachedAcls(target);
@@ -288,19 +248,16 @@ export function distributeAcls(key: string, acl: SharingPermissions, target: Doc
let layoutDocChanged = false; // determines whether fetchProto should be called or not (i.e. is there a change that should be reflected in target[AclSym])
// 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 (GetEffectiveAcl(target) === AclAdmin && (!inheritingFromCollection || !target[key] || ReverseHierarchyMap.get(StrCast(target[key]))!.level > ReverseHierarchyMap.get(acl)!.level)) {
- target[key] = acl;
- layoutDocChanged = true;
- if (isDashboard) {
- DocListCastAsync(target[Doc.LayoutFieldKey(target)]).then(docs => {
- docs?.forEach(d => distributeAcls(key, acl, d, inheritingFromCollection, visited));
- });
+ if (target.author !== Doc.CurrentUserEmail || key !== `acl-${Doc.CurrentUserEmailNormalized}`) {
+ target[key] = acl;
+ layoutDocChanged = true;
}
}
let dataDocChanged = false;
const dataDoc = target[DocData];
if (dataDoc && (!inheritingFromCollection || !dataDoc[key] || ReverseHierarchyMap.get(StrCast(dataDoc[key]))! > ReverseHierarchyMap.get(acl)!)) {
- if (GetEffectiveAcl(dataDoc) === AclAdmin) {
+ if (GetEffectiveAcl(dataDoc) === AclAdmin && (target.author !== Doc.CurrentUserEmail || key !== `acl-${Doc.CurrentUserEmailNormalized}`)) {
dataDoc[key] = acl;
dataDocChanged = true;
}
@@ -327,7 +284,7 @@ export function distributeAcls(key: string, acl: SharingPermissions, target: Doc
export function setter(target: any, in_prop: string | symbol | number, value: any, receiver: any): boolean {
let prop = in_prop;
- const effectiveAcl = in_prop === 'constructor' || typeof in_prop === 'symbol' ? AclAdmin : getPropAcl(target, prop);
+ const effectiveAcl = in_prop === 'constructor' || typeof in_prop === 'symbol' ? AclAdmin : GetPropAcl(target, prop);
if (effectiveAcl !== AclEdit && effectiveAcl !== AclAugment && effectiveAcl !== AclAdmin) return true;
// if you're trying to change an acl but don't have Admin access / you're trying to change it to something that isn't an acceptable acl, you can't
if (typeof prop === 'string' && prop.startsWith('acl') && (effectiveAcl !== AclAdmin || ![...Object.values(SharingPermissions), undefined].includes(value))) return true;