aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/client/util/CurrentUserUtils.ts14
-rw-r--r--src/client/util/GroupManager.tsx5
-rw-r--r--src/client/util/SharingManager.tsx28
-rw-r--r--src/client/util/SnappingManager.ts8
-rw-r--r--src/client/views/collections/CollectionStackingView.tsx1
-rw-r--r--src/fields/List.ts5
-rw-r--r--src/fields/util.ts46
-rw-r--r--src/server/websocket.ts6
8 files changed, 61 insertions, 52 deletions
diff --git a/src/client/util/CurrentUserUtils.ts b/src/client/util/CurrentUserUtils.ts
index 580c6040e..694982fea 100644
--- a/src/client/util/CurrentUserUtils.ts
+++ b/src/client/util/CurrentUserUtils.ts
@@ -8,9 +8,9 @@ import { RichTextField } from "../../fields/RichTextField";
import { listSpec } from "../../fields/Schema";
import { SchemaHeaderField } from "../../fields/SchemaHeaderField";
import { ComputedField, ScriptField } from "../../fields/ScriptField";
-import { BoolCast, Cast, NumCast, PromiseValue, StrCast } from "../../fields/Types";
+import { BoolCast, Cast, NumCast, PromiseValue, StrCast, DateCast } from "../../fields/Types";
import { nullAudio } from "../../fields/URLField";
-import { SharingPermissions, UserGroups } from "../../fields/util";
+import { SharingPermissions } from "../../fields/util";
import { Utils } from "../../Utils";
import { DocServer } from "../DocServer";
import { Docs, DocumentOptions, DocUtils } from "../documents/Documents";
@@ -32,6 +32,7 @@ import { Scripting } from "./Scripting";
import { SearchUtil } from "./SearchUtil";
import { SelectionManager } from "./SelectionManager";
import { UndoManager } from "./UndoManager";
+import { SnappingManager } from "./SnappingManager";
export let resolvedPorts: { server: number, socket: number };
@@ -957,8 +958,13 @@ export class CurrentUserUtils {
static async updateUserDocument(doc: Doc, sharingDocumentId: string) {
if (!doc.globalGroupDatabase) doc.globalGroupDatabase = Docs.Prototypes.MainGroupDocument();
- await DocListCastAsync((doc.globalGroupDatabase as Doc).data);
- UserGroups.Current;
+ const groups = await DocListCastAsync((doc.globalGroupDatabase as Doc).data);
+ reaction(() => DateCast((doc.globalGroupDatabase as Doc).lastModified),
+ async () => {
+ const groups = await DocListCastAsync((doc.globalGroupDatabase as Doc).data);
+ const mygroups = groups?.filter(group => JSON.parse(StrCast(group.members)).includes(Doc.CurrentUserEmail)) || [];
+ SnappingManager.SetCachedGroups(["Public", ...mygroups?.map(g => StrCast(g.title))]);
+ }, { fireImmediately: true });
doc.system = true;
doc.noviceMode = doc.noviceMode === undefined ? "true" : doc.noviceMode;
doc.title = Doc.CurrentUserEmail;
diff --git a/src/client/util/GroupManager.tsx b/src/client/util/GroupManager.tsx
index 63e2a8024..cc1d45a58 100644
--- a/src/client/util/GroupManager.tsx
+++ b/src/client/util/GroupManager.tsx
@@ -13,6 +13,7 @@ import "./GroupManager.scss";
import { GroupMemberView } from "./GroupMemberView";
import { SharingManager, User } from "./SharingManager";
import { listSpec } from "../../fields/Schema";
+import { DateField } from "../../fields/DateField";
/**
* Interface for options for the react-select component
@@ -144,6 +145,7 @@ export class GroupManager extends React.Component<{}> {
*/
addGroup(groupDoc: Doc): boolean {
if (this.GroupManagerDoc) {
+ this.GroupManagerDoc.lastModified = new DateField;
Doc.AddDocToList(this.GroupManagerDoc, "data", groupDoc);
return true;
}
@@ -158,6 +160,7 @@ export class GroupManager extends React.Component<{}> {
deleteGroup(group: Doc): boolean {
if (group) {
if (this.GroupManagerDoc && this.hasEditAccess(group)) {
+ this.GroupManagerDoc.lastModified = new DateField;
Doc.RemoveDocFromList(this.GroupManagerDoc, "data", group);
SharingManager.Instance.removeGroup(group);
const members = JSON.parse(StrCast(group.members));
@@ -184,6 +187,7 @@ export class GroupManager extends React.Component<{}> {
const memberList = JSON.parse(StrCast(groupDoc.members));
!memberList.includes(email) && memberList.push(email);
groupDoc.members = JSON.stringify(memberList);
+ this.GroupManagerDoc && (this.GroupManagerDoc.lastModified = new DateField);
SharingManager.Instance.shareWithAddedMember(groupDoc, email);
}
}
@@ -200,6 +204,7 @@ export class GroupManager extends React.Component<{}> {
if (index !== -1) {
const user = memberList.splice(index, 1)[0];
groupDoc.members = JSON.stringify(memberList);
+ this.GroupManagerDoc && (this.GroupManagerDoc.lastModified = new DateField);
SharingManager.Instance.removeMember(groupDoc, email);
}
}
diff --git a/src/client/util/SharingManager.tsx b/src/client/util/SharingManager.tsx
index ee397ab4f..16bcd46c8 100644
--- a/src/client/util/SharingManager.tsx
+++ b/src/client/util/SharingManager.tsx
@@ -22,6 +22,7 @@ import "./SharingManager.scss";
import { SelectionManager } from "./SelectionManager";
import { intersection } from "lodash";
import { SearchBox } from "../views/search/SearchBox";
+import { listSpec } from "../../fields/Schema";
export interface User {
email: string;
@@ -172,8 +173,8 @@ export class SharingManager extends React.Component<{}> {
group.docsShared ? Doc.IndexOf(doc, DocListCast(group.docsShared)) === -1 && (group.docsShared as List<Doc>).push(doc) : group.docsShared = new List<Doc>([doc]);
users.forEach(({ user, sharingDoc }) => {
- if (permission !== SharingPermissions.None) Doc.IndexOf(doc, DocListCast(sharingDoc[storage])) === -1 && Doc.AddDocToList(sharingDoc, storage, doc); // add the doc to the sharingDoc if it hasn't already been added
- else GetEffectiveAcl(doc, undefined, user.email) === AclPrivate && Doc.IndexOf((doc.aliasOf as Doc || doc), DocListCast(sharingDoc[storage])) !== -1 && Doc.RemoveDocFromList(sharingDoc, storage, (doc.aliasOf as Doc || doc)); // remove the doc from the list if it already exists
+ if (permission !== SharingPermissions.None) Doc.AddDocToList(sharingDoc, storage, doc); // add the doc to the sharingDoc if it hasn't already been added
+ else GetEffectiveAcl(doc, undefined, user.email) === AclPrivate && Doc.RemoveDocFromList(sharingDoc, storage, (doc.aliasOf as Doc || doc)); // remove the doc from the list if it already exists
});
}
});
@@ -189,9 +190,13 @@ export class SharingManager extends React.Component<{}> {
const self = this;
if (group.docsShared) {
if (!user) retry && this.populateUsers().then(() => self.shareWithAddedMember(group, emailId, false));
- else DocListCastAsync(group.docsShared).then(dl => dl?.forEach(doc => {
- Doc.AddDocToList(user.sharingDoc, storage, doc);
- }));
+ else {
+ DocListCastAsync(user.sharingDoc[storage]).then(userdocs =>
+ DocListCastAsync(group.docsShared).then(dl => {
+ const filtered = dl?.filter(doc => !userdocs?.includes(doc));
+ filtered && userdocs?.push(...filtered);
+ }));
+ }
}
}
@@ -222,9 +227,12 @@ export class SharingManager extends React.Component<{}> {
const user: ValidatedUser = this.users.find(({ user: { email } }) => email === emailId)!;
if (group.docsShared) {
- DocListCastAsync(group.docsShared).then(dl => dl?.forEach(doc => {
- Doc.RemoveDocFromList(user.sharingDoc, storage, doc);
- }));
+ DocListCastAsync(user.sharingDoc[storage]).then(userdocs =>
+ DocListCastAsync(group.docsShared).then(dl => {
+ const remaining = userdocs?.filter(doc => !dl?.includes(doc)) || [];
+ userdocs?.splice(0, userdocs.length, ...remaining);
+ })
+ );
}
}
@@ -261,8 +269,8 @@ export class SharingManager extends React.Component<{}> {
doc.author === Doc.CurrentUserEmail && !doc[myAcl] && distributeAcls(myAcl, SharingPermissions.Admin, doc);
distributeAcls(acl, permission as SharingPermissions, doc);
- if (permission !== SharingPermissions.None) Doc.IndexOf(doc, DocListCast(sharingDoc[storage])) === -1 && Doc.AddDocToList(sharingDoc, storage, doc);
- else GetEffectiveAcl(doc, undefined, user.email) === AclPrivate && Doc.IndexOf((doc.aliasOf as Doc || doc), DocListCast(sharingDoc[storage])) !== -1 && Doc.RemoveDocFromList(sharingDoc, storage, (doc.aliasOf as Doc || doc));
+ if (permission !== SharingPermissions.None) Doc.AddDocToList(sharingDoc, storage, doc);
+ else GetEffectiveAcl(doc, undefined, user.email) === AclPrivate && Doc.RemoveDocFromList(sharingDoc, storage, (doc.aliasOf as Doc || doc));
});
}
diff --git a/src/client/util/SnappingManager.ts b/src/client/util/SnappingManager.ts
index fc07e8ab4..d067dff6c 100644
--- a/src/client/util/SnappingManager.ts
+++ b/src/client/util/SnappingManager.ts
@@ -14,6 +14,9 @@ export namespace SnappingManager {
this.horizSnapLines = horizLines;
this.vertSnapLines = vertLines;
}
+
+ @observable cachedGroups: string[] = [];
+ @action setCachedGroups(groups: string[]) { this.cachedGroups = groups; }
}
const manager = new Manager();
@@ -25,5 +28,10 @@ export namespace SnappingManager {
export function SetIsDragging(dragging: boolean) { runInAction(() => manager.IsDragging = dragging); }
export function GetIsDragging() { return manager.IsDragging; }
+
+ /// bcz; argh!! TODO; These do not belong here, but there were include order problems with leaving them in util.ts
+ // need to investigate further what caused the mobx update problems and move to a better location.
+ export function SetCachedGroups(groups: string[]) { manager.setCachedGroups(groups); }
+ export function GetCachedGroups() { return manager.cachedGroups; }
}
diff --git a/src/client/views/collections/CollectionStackingView.tsx b/src/client/views/collections/CollectionStackingView.tsx
index daaee67dc..72ce041e1 100644
--- a/src/client/views/collections/CollectionStackingView.tsx
+++ b/src/client/views/collections/CollectionStackingView.tsx
@@ -294,7 +294,6 @@ export class CollectionStackingView extends CollectionSubView<StackingDocument,
const docs = this.childDocList;
if (docs) {
newDocs.map((doc, i) => {
- console.log(doc.title);
if (i === 0) {
if (targInd === -1) targInd = docs.length;
else targInd = docs.indexOf(this.filteredChildren[targInd]);
diff --git a/src/fields/List.ts b/src/fields/List.ts
index ceb538b2d..a0cbebaf5 100644
--- a/src/fields/List.ts
+++ b/src/fields/List.ts
@@ -43,7 +43,7 @@ const listHandlers: any = {
}
}
const res = list.__fields.push(...items);
- this[Update]({ op: "$addToSet", items });
+ this[Update]({ op: "$addToSet", items, length: length + items.length });
return res;
}),
reverse() {
@@ -77,7 +77,8 @@ const listHandlers: any = {
}
}
const res = list.__fields.splice(start, deleteCount, ...items);
- this[Update](items.length === 0 && deleteCount ? { op: "$remFromSet", items: removed } : undefined);
+ this[Update](items.length === 0 && deleteCount ? { op: "$remFromSet", items: removed, length: list.__fields.length } :
+ items.length && !deleteCount ? { op: "$addToSet", items, length: list.__fields.length } : undefined);
return res.map(toRealField);
}),
unshift(...items: any[]) {
diff --git a/src/fields/util.ts b/src/fields/util.ts
index 791b98b83..fd409a54e 100644
--- a/src/fields/util.ts
+++ b/src/fields/util.ts
@@ -1,5 +1,5 @@
import { UndoManager } from "../client/util/UndoManager";
-import { Doc, FieldResult, UpdatingFromServer, LayoutSym, AclPrivate, AclEdit, AclReadonly, AclAddonly, AclSym, CachedUpdates, DataSym, DocListCast, AclAdmin, FieldsSym, HeightSym, WidthSym, fetchProto, AclUnset } from "./Doc";
+import { Doc, FieldResult, UpdatingFromServer, LayoutSym, AclPrivate, AclEdit, AclReadonly, AclAddonly, AclSym, CachedUpdates, DataSym, DocListCast, AclAdmin, FieldsSym, HeightSym, WidthSym, fetchProto, AclUnset, DocListCastAsync } from "./Doc";
import { SerializationHelper } from "../client/util/SerializationHelper";
import { ProxyField, PrefetchProxy } from "./Proxy";
import { RefField } from "./RefField";
@@ -8,10 +8,13 @@ import { action, trace, observable, reaction, computed } from "mobx";
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";
+import { ScriptCast, StrCast, DateCast, Cast, NumCast } from "./Types";
import { returnZero } from "../Utils";
import CursorField from "./CursorField";
import { List } from "./List";
+import { listSpec } from "./Schema";
+import { DateField } from "./DateField";
+import { SnappingManager } from "../client/util/SnappingManager";
function _readOnlySetter(): never {
throw new Error("Documents can't be modified in read-only mode");
@@ -22,32 +25,6 @@ export function TraceMobx() {
tracing && trace();
}
-// the list of groups that the current user is a member of
-export class UserGroups {
- static computing = false;
- static cachedGroups: string[] = [];
- static globalGroupDoc: Doc | undefined;
- static get Current() {
- if (!Doc.UserDoc() || UserGroups.computing) return UserGroups.cachedGroups;
- UserGroups.computing = true;
- if (!UserGroups.globalGroupDoc) UserGroups.globalGroupDoc = Doc.UserDoc().globalGroupDatabase as Doc;
- if (UserGroups.globalGroupDoc) {
- const dbgroups = DocListCast(UserGroups.globalGroupDoc.data);
- if (dbgroups.length !== UserGroups.cachedGroups.length - 1) {
- UserGroups.cachedGroups = [
- "Public",
- ...dbgroups?.
- filter(group => group instanceof Doc).
- map(group => group as Doc).
- filter(group => JSON.parse(StrCast(group.members))?.includes(Doc.CurrentUserEmail)).
- map(group => StrCast(group.title))
- ];
- }
- }
- UserGroups.computing = false;
- return UserGroups.cachedGroups;
- }
-}
export interface GetterResult {
value: FieldResult;
@@ -190,7 +167,7 @@ export function GetEffectiveAcl(target: any, in_prop?: string | symbol | number,
// if the current user is the author of the document / the current user is a member of the admin group
const userChecked = user || Doc.CurrentUserEmail;
if (userChecked === (target.__fields?.author || target.author)) return AclAdmin;
- if (UserGroups.Current?.includes("Admin")) return AclAdmin;
+ if (SnappingManager.GetCachedGroups().includes("Admin")) return AclAdmin;
if (target[AclSym] && Object.keys(target[AclSym]).length) {
@@ -211,7 +188,7 @@ export function GetEffectiveAcl(target: any, in_prop?: string | symbol | number,
// 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.
const entity = denormalizeEmail(key.substring(4)); // an individual or a group
- if (UserGroups.Current?.includes(entity) || userChecked === entity) {
+ if (SnappingManager.GetCachedGroups().includes(entity) || userChecked === entity) {
if (HierarchyMapping.get(value as symbol)! > HierarchyMapping.get(effectiveAcl)!) {
effectiveAcl = value as symbol;
if (effectiveAcl === AclAdmin) return effectiveAcl;
@@ -388,9 +365,12 @@ export function deleteProperty(target: any, prop: string | number | symbol) {
export function updateFunction(target: any, prop: any, value: any, receiver: any) {
let current = ObjectField.MakeCopy(value);
return (diff?: any) => {
- const op = diff?.op === "$addToSet" ? { '$addToSet': { ["fields." + prop]: SerializationHelper.Serialize(new List<Doc>(diff.items)) } } :
- diff?.op === "$remFromSet" ? { '$remFromSet': { ["fields." + prop]: SerializationHelper.Serialize(new List<Doc>(diff.items)) } }
- : { '$set': { ["fields." + prop]: SerializationHelper.Serialize(value) } };
+ const op =
+ diff?.op === "$addToSet" ? { '$addToSet': { ["fields." + prop]: SerializationHelper.Serialize(new List<Doc>(diff.items)) } } :
+ diff?.op === "$remFromSet" ? { '$remFromSet': { ["fields." + prop]: SerializationHelper.Serialize(new List<Doc>(diff.items)) } }
+ : { '$set': { ["fields." + prop]: SerializationHelper.Serialize(value) } };
+ !op['$set'] && ((op as any).length = diff.length);
+
const oldValue = current;
const newValue = ObjectField.MakeCopy(value);
current = newValue;
diff --git a/src/server/websocket.ts b/src/server/websocket.ts
index c9b5d1cbf..03795d254 100644
--- a/src/server/websocket.ts
+++ b/src/server/websocket.ts
@@ -277,7 +277,8 @@ export namespace WebSocket {
const newListItems = diff.diff.$set[updatefield].fields;
const curList = (curListItems as any)?.fields?.[updatefield.replace("fields.", "")]?.fields || [];
diff.diff.$set[updatefield].fields = [...curList, ...newListItems.filter((newItem: any) => !curList.some((curItem: any) => curItem.fieldId ? curItem.fieldId === newItem.fieldId : curItem.heading ? curItem.heading === newItem.heading : false))];
- const sendBack = true;//curList.length !== prelen;
+ const sendBack = diff.diff.length !== diff.diff.$set[updatefield].fields.length;
+ delete diff.diff.length;
Database.Instance.update(diff.id, diff.diff,
() => {
if (sendBack) {
@@ -295,7 +296,8 @@ export namespace WebSocket {
const remListItems = diff.diff.$set[updatefield].fields;
const curList = (curListItems as any)?.fields?.[updatefield.replace("fields.", "")]?.fields || [];
diff.diff.$set[updatefield].fields = curList?.filter((curItem: any) => !remListItems.some((remItem: any) => remItem.fieldId ? remItem.fieldId === curItem.fieldId : remItem.heading ? remItem.heading === curItem.heading : false));
- const sendBack = true;//curList.length + remListItems.length !== prelen;
+ const sendBack = diff.diff.length !== diff.diff.$set[updatefield].fields.length;
+ delete diff.diff.length;
Database.Instance.update(diff.id, diff.diff,
() => {
if (sendBack) {