aboutsummaryrefslogtreecommitdiff
path: root/src/fields
diff options
context:
space:
mode:
Diffstat (limited to 'src/fields')
-rw-r--r--src/fields/Doc.ts67
-rw-r--r--src/fields/util.ts60
2 files changed, 98 insertions, 29 deletions
diff --git a/src/fields/Doc.ts b/src/fields/Doc.ts
index bbc9d388a..c965dc282 100644
--- a/src/fields/Doc.ts
+++ b/src/fields/Doc.ts
@@ -17,8 +17,9 @@ import { RichTextField } from "./RichTextField";
import { listSpec } from "./Schema";
import { ComputedField } from "./ScriptField";
import { Cast, FieldValue, NumCast, StrCast, ToConstructor } from "./Types";
-import { deleteProperty, getField, getter, makeEditable, makeReadOnly, setter, updateFunction } from "./util";
+import { deleteProperty, getField, getter, makeEditable, makeReadOnly, setter, updateFunction, getEffectiveAcl } from "./util";
import { LinkManager } from "../client/util/LinkManager";
+import { SharingPermissions } from "../client/util/SharingManager";
export namespace Field {
export function toKeyValueString(doc: Doc, key: string): string {
@@ -100,23 +101,39 @@ export const AclEdit = Symbol("AclEdit");
export const UpdatingFromServer = Symbol("UpdatingFromServer");
const CachedUpdates = Symbol("Cached updates");
+const AclMap = new Map<string, symbol>([
+ [SharingPermissions.None, AclPrivate],
+ [SharingPermissions.View, AclReadonly],
+ [SharingPermissions.Add, AclAddonly],
+ [SharingPermissions.Edit, AclEdit]
+]);
export function fetchProto(doc: Doc) {
+ console.log("in fetchproto");
if (doc.author !== Doc.CurrentUserEmail) { // storing acls for groups needs to be extended here - AclSym should store a datastructure that stores information about permissions
- const acl = Doc.Get(doc, "ACL", true);
- switch (acl) {
- case "ownerOnly":
- doc[AclSym] = AclPrivate;
- return undefined;
- case "readOnly":
- doc[AclSym] = AclReadonly;
- break;
- case "addOnly":
- doc[AclSym] = AclAddonly;
- break;
- case "edit":
- doc[AclSym] = AclEdit;
- }
+
+ const permissions: { [key: string]: symbol } = {};
+
+ Object.keys(doc).forEach(key => {
+ if (key.startsWith("ACL")) permissions[key] = AclMap.get(StrCast(doc[key]))!;
+ });
+
+ doc[AclSym] = permissions;
+
+ // const acl = Doc.Get(doc, "ACL", true);
+ // switch (acl) {
+ // case "ownerOnly":
+ // doc[AclSym] = AclPrivate;
+ // return undefined;
+ // case "readOnly":
+ // doc[AclSym] = AclReadonly;
+ // break;
+ // case "addOnly":
+ // doc[AclSym] = AclAddonly;
+ // break;
+ // // case "edit":
+ // // doc[AclSym] = AclEdit;
+ // }
}
if (doc.proto instanceof Promise) {
@@ -134,10 +151,10 @@ export class Doc extends RefField {
set: setter,
get: getter,
// getPrototypeOf: (target) => Cast(target[SelfProxy].proto, Doc) || null, // TODO this might be able to replace the proto logic in getter
- has: (target, key) => target[AclSym] !== AclPrivate && key in target.__fields,
+ has: (target, key) => getEffectiveAcl(target) !== AclPrivate && key in target.__fields,
ownKeys: target => {
const obj = {} as any;
- if (target[AclSym] !== AclPrivate) Object.assign(obj, target.___fields);
+ if (getEffectiveAcl(target) !== AclPrivate) Object.assign(obj, target.___fields);
runInAction(() => obj.__LAYOUT__ = target.__LAYOUT__);
return Object.keys(obj);
},
@@ -191,11 +208,11 @@ export class Doc extends RefField {
private [Self] = this;
private [SelfProxy]: any;
- public [AclSym]: any = undefined;
+ public [AclSym]: any;
public [WidthSym] = () => NumCast(this[SelfProxy]._width);
public [HeightSym] = () => NumCast(this[SelfProxy]._height);
public [ToScriptString]() { return `DOC-"${this[Self][Id]}"-`; }
- public [ToString]() { return `Doc(${this[AclSym] === AclPrivate ? "-inaccessible-" : this.title})`; }
+ public [ToString]() { return `Doc(${getEffectiveAcl(this) === AclPrivate ? "-inaccessible-" : this.title})`; }
public get [LayoutSym]() { return this[SelfProxy].__LAYOUT__; }
public get [DataSym]() {
const self = this[SelfProxy];
@@ -823,7 +840,8 @@ export namespace Doc {
}
// don't bother memoizing (caching) the result if called from a non-reactive context. (plus this avoids a warning message)
export function IsBrushedDegreeUnmemoized(doc: Doc) {
- if (!doc || doc[AclSym] === AclPrivate || Doc.GetProto(doc)[AclSym] === AclPrivate) return 0;
+ console.log("here");
+ if (!doc || getEffectiveAcl(doc) === AclPrivate || getEffectiveAcl(Doc.GetProto(doc)) === AclPrivate) return 0;
return brushManager.BrushedDoc.has(doc) ? 2 : brushManager.BrushedDoc.has(Doc.GetProto(doc)) ? 1 : 0;
}
export function IsBrushedDegree(doc: Doc) {
@@ -832,15 +850,15 @@ export namespace Doc {
})(doc);
}
export function BrushDoc(doc: Doc) {
-
- if (!doc || doc[AclSym] === AclPrivate || Doc.GetProto(doc)[AclSym] === AclPrivate) return doc;
+ console.log("here");
+ if (!doc || getEffectiveAcl(doc) === AclPrivate || getEffectiveAcl(Doc.GetProto(doc)) === AclPrivate) return doc;
brushManager.BrushedDoc.set(doc, true);
brushManager.BrushedDoc.set(Doc.GetProto(doc), true);
return doc;
}
export function UnBrushDoc(doc: Doc) {
- if (!doc || doc[AclSym] === AclPrivate || Doc.GetProto(doc)[AclSym] === AclPrivate) return doc;
+ if (!doc || getEffectiveAcl(doc) === AclPrivate || getEffectiveAcl(Doc.GetProto(doc)) === AclPrivate) return doc;
brushManager.BrushedDoc.delete(doc);
brushManager.BrushedDoc.delete(Doc.GetProto(doc));
return doc;
@@ -870,7 +888,8 @@ export namespace Doc {
}
const highlightManager = new HighlightBrush();
export function IsHighlighted(doc: Doc) {
- if (!doc || doc[AclSym] === AclPrivate || Doc.GetProto(doc)[AclSym] === AclPrivate) return false;
+ console.log("here");
+ if (!doc || getEffectiveAcl(doc) === AclPrivate || getEffectiveAcl(Doc.GetProto(doc)) === AclPrivate) return false;
return highlightManager.HighlightedDoc.get(doc) || highlightManager.HighlightedDoc.get(Doc.GetProto(doc));
}
export function HighlightDoc(doc: Doc, dataAndDisplayDocs = true) {
diff --git a/src/fields/util.ts b/src/fields/util.ts
index 7bb090a93..a3e7a36f8 100644
--- a/src/fields/util.ts
+++ b/src/fields/util.ts
@@ -1,5 +1,5 @@
import { UndoManager } from "../client/util/UndoManager";
-import { Doc, Field, FieldResult, UpdatingFromServer, LayoutSym, AclSym, AclPrivate } from "./Doc";
+import { Doc, Field, FieldResult, UpdatingFromServer, LayoutSym, AclSym, AclPrivate, AclEdit, AclReadonly, AclAddonly } from "./Doc";
import { SerializationHelper } from "../client/util/SerializationHelper";
import { ProxyField, PrefetchProxy } from "./Proxy";
import { RefField } from "./RefField";
@@ -9,6 +9,7 @@ import { Parent, OnUpdate, Update, Id, SelfProxy, Self } from "./FieldSymbols";
import { DocServer } from "../client/DocServer";
import { ComputedField } from "./ScriptField";
import { ScriptCast } from "./Types";
+import GroupManager from "../client/util/GroupManager";
function _readOnlySetter(): never {
@@ -107,11 +108,57 @@ export function OVERRIDE_ACL(val: boolean) {
_overrideAcl = val;
}
+const HierarchyMapping = new Map<symbol, number>([
+ [AclPrivate, 0],
+ [AclReadonly, 1],
+ [AclAddonly, 2],
+ [AclEdit, 3]
+]);
+
+export function getEffectiveAcl(target: any): symbol {
+
+ console.log("in getEffectiveAcl");
+
+ if (target[AclSym].ACL) return target[AclSym].ACL;
+
+ let effectiveAcl = AclEdit;
+
+ for (const [key, value] of Object.entries(target[AclSym])) {
+ if (key.startsWith("ACL-")) {
+ if (GroupManager.Instance.currentUserGroups.includes(key.substring(4)) || Doc.CurrentUserEmail === key.substring(4).replace("_", ".")) {
+ if (HierarchyMapping.get(value as symbol)! > HierarchyMapping.get(effectiveAcl)!) {
+ effectiveAcl = value as symbol;
+ if (effectiveAcl === AclEdit) break;
+ }
+ }
+ }
+ }
+
+ return effectiveAcl;
+}
+
+function testPermission(target: any, in_prop: string | symbol | number): boolean {
+
+ console.log("here");
+ // if (target[AclSym].ACL !== AclEdit && !_overrideAcl && !DocServer.PlaygroundFields.includes(in_prop.toString())) return false;
+ if (target[AclSym].ACL === AclEdit) return true;
+ for (const [key, value] of Object.entries(target[AclSym])) {
+ if (key.startsWith("ACL-")) {
+ if (GroupManager.Instance.currentUserGroups.includes(key.substring(4))) {
+ if (value === AclEdit) return true;
+ }
+ }
+ }
+ return _overrideAcl || DocServer.PlaygroundFields.includes(in_prop.toString());
+}
+
const layoutProps = ["panX", "panY", "width", "height", "nativeWidth", "nativeHeight", "fitWidth", "fitToBox",
"chromeStatus", "viewType", "gridGap", "xMargin", "yMargin", "autoHeight"];
export function setter(target: any, in_prop: string | symbol | number, value: any, receiver: any): boolean {
+ console.log("in setter")
let prop = in_prop;
- if (target[AclSym] && !_overrideAcl && !DocServer.PlaygroundFields.includes(in_prop.toString())) return true; // generalise to a testpermission function
+ // if (target[AclSym] && !_overrideAcl && !DocServer.PlaygroundFields.includes(in_prop.toString())) return true; // generalise to a testpermission function
+ if (!testPermission(target, in_prop)) return true;
if (typeof prop === "string" && prop !== "__id" && prop !== "__fields" && (prop.startsWith("_") || layoutProps.includes(prop))) {
if (!prop.startsWith("_")) {
console.log(prop + " is deprecated - switch to _" + prop);
@@ -129,9 +176,11 @@ 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 {
+ console.log("in getter")
let prop = in_prop;
- if (in_prop === AclSym) return _overrideAcl ? undefined : target[AclSym];
- if (target[AclSym] === AclPrivate && !_overrideAcl) return undefined;
+ const effectiveAcl = getEffectiveAcl(target);
+ if (in_prop === AclSym) return _overrideAcl ? undefined : effectiveAcl;
+ if (effectiveAcl === AclPrivate && !_overrideAcl) return undefined;
if (prop === LayoutSym) {
return target.__LAYOUT__;
}
@@ -168,7 +217,8 @@ function getFieldImpl(target: any, prop: string | number, receiver: any, ignoreP
}
if (field === undefined && !ignoreProto && prop !== "proto") {
const proto = getFieldImpl(target, "proto", receiver, true);//TODO tfs: instead of receiver we could use target[SelfProxy]... I don't which semantics we want or if it really matters
- if (proto instanceof Doc && proto[AclSym] !== AclPrivate) {
+ console.log("here");
+ if (proto instanceof Doc && getEffectiveAcl(proto) !== AclPrivate) {
return getFieldImpl(proto[Self], prop, receiver, ignoreProto);
}
return undefined;