aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/client/util/CurrentUserUtils.ts26
-rw-r--r--src/client/util/GroupManager.tsx8
-rw-r--r--src/client/util/LinkManager.ts12
-rw-r--r--src/client/util/SharingManager.tsx9
-rw-r--r--src/client/views/nodes/formattedText/FormattedTextBox.tsx12
-rw-r--r--src/fields/Doc.ts1
-rw-r--r--src/server/ApiManagers/UserManager.ts12
-rw-r--r--src/server/GarbageCollector.ts2
-rw-r--r--src/server/authentication/AuthenticationManager.ts1
-rw-r--r--src/server/authentication/DashUserModel.ts4
10 files changed, 57 insertions, 30 deletions
diff --git a/src/client/util/CurrentUserUtils.ts b/src/client/util/CurrentUserUtils.ts
index 694982fea..7535d7c24 100644
--- a/src/client/util/CurrentUserUtils.ts
+++ b/src/client/util/CurrentUserUtils.ts
@@ -1,6 +1,6 @@
import { computed, observable, reaction } from "mobx";
import * as rp from 'request-promise';
-import { DataSym, Doc, DocListCast, DocListCastAsync } from "../../fields/Doc";
+import { DataSym, Doc, DocListCast, DocListCastAsync, AclReadonly } from "../../fields/Doc";
import { Id } from "../../fields/FieldSymbols";
import { List } from "../../fields/List";
import { PrefetchProxy } from "../../fields/Proxy";
@@ -541,9 +541,9 @@ export class CurrentUserUtils {
})) as any as Doc;
}
}
- static async setupMenuPanel(doc: Doc, sharingDocumentId: string) {
+ static async setupMenuPanel(doc: Doc, sharingDocumentId: string, linkDatabaseId: string) {
if (doc.menuStack === undefined) {
- await this.setupSharingSidebar(doc, sharingDocumentId); // sets up the right sidebar collection for mobile upload documents and sharing
+ await this.setupSharingSidebar(doc, sharingDocumentId, linkDatabaseId); // sets up the right sidebar collection for mobile upload documents and sharing
const menuBtns = (await CurrentUserUtils.menuBtnDescriptions(doc)).map(({ title, target, icon, click, watchedDocuments }) =>
Docs.Create.FontIconDocument({
icon,
@@ -876,7 +876,16 @@ export class CurrentUserUtils {
}
// Sharing sidebar is where shared documents are contained
- static async setupSharingSidebar(doc: Doc, sharingDocumentId: string) {
+ static async setupSharingSidebar(doc: Doc, sharingDocumentId: string, linkDatabaseId: string) {
+ if (doc.myLinkDatabase === undefined) {
+ let linkDocs = await DocServer.GetRefField(linkDatabaseId);
+ if (!linkDocs) {
+ linkDocs = new Doc(linkDatabaseId, true);
+ (linkDocs as Doc).data = new List<Doc>([]);
+ (linkDocs as Doc)["acl-Public"] = SharingPermissions.Add;
+ }
+ doc.myLinkDatabase = new PrefetchProxy(linkDocs);
+ }
if (doc.mySharedDocs === undefined) {
let sharedDocs = await DocServer.GetRefField(sharingDocumentId + "outer");
if (!sharedDocs) {
@@ -956,7 +965,7 @@ export class CurrentUserUtils {
return doc.clickFuncs as Doc;
}
- static async updateUserDocument(doc: Doc, sharingDocumentId: string) {
+ static async updateUserDocument(doc: Doc, sharingDocumentId: string, linkDatabaseId: string) {
if (!doc.globalGroupDatabase) doc.globalGroupDatabase = Docs.Prototypes.MainGroupDocument();
const groups = await DocListCastAsync((doc.globalGroupDatabase as Doc).data);
reaction(() => DateCast((doc.globalGroupDatabase as Doc).lastModified),
@@ -996,9 +1005,8 @@ export class CurrentUserUtils {
this.setupOverlays(doc); // documents in overlay layer
this.setupDockedButtons(doc); // the bottom bar of font icons
await this.setupSidebarButtons(doc); // the pop-out left sidebar of tools/panels
- await this.setupMenuPanel(doc, sharingDocumentId);
+ await this.setupMenuPanel(doc, sharingDocumentId, linkDatabaseId);
if (!doc.globalScriptDatabase) doc.globalScriptDatabase = Docs.Prototypes.MainScriptDocument();
- if (!doc.myLinkDatabase) doc.myLinkDatabase = new List([]);
setTimeout(() => this.setupDefaultPresentation(doc), 0); // presentation that's initially triggered
@@ -1036,10 +1044,10 @@ export class CurrentUserUtils {
public static async loadUserDocument(id: string) {
this.curr_id = id;
await rp.get(Utils.prepend("/getUserDocumentIds")).then(ids => {
- const { userDocumentId, sharingDocumentId } = JSON.parse(ids);
+ const { userDocumentId, sharingDocumentId, linkDatabaseId } = JSON.parse(ids);
if (userDocumentId !== "guest") {
return DocServer.GetRefField(userDocumentId).then(async field =>
- this.updateUserDocument(Doc.SetUserDoc(field instanceof Doc ? field : new Doc(userDocumentId, true)), sharingDocumentId));
+ this.updateUserDocument(Doc.SetUserDoc(field instanceof Doc ? field : new Doc(userDocumentId, true)), sharingDocumentId, linkDatabaseId));
} else {
throw new Error("There should be a user id! Why does Dash think there isn't one?");
}
diff --git a/src/client/util/GroupManager.tsx b/src/client/util/GroupManager.tsx
index cc1d45a58..6458de0ed 100644
--- a/src/client/util/GroupManager.tsx
+++ b/src/client/util/GroupManager.tsx
@@ -145,8 +145,8 @@ export class GroupManager extends React.Component<{}> {
*/
addGroup(groupDoc: Doc): boolean {
if (this.GroupManagerDoc) {
- this.GroupManagerDoc.lastModified = new DateField;
Doc.AddDocToList(this.GroupManagerDoc, "data", groupDoc);
+ this.GroupManagerDoc.lastModified = new DateField;
return true;
}
return false;
@@ -160,7 +160,6 @@ 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));
@@ -168,6 +167,7 @@ export class GroupManager extends React.Component<{}> {
const index = DocListCast(this.GroupManagerDoc.data).findIndex(grp => grp === group);
index !== -1 && Cast(this.GroupManagerDoc.data, listSpec(Doc), [])?.splice(index, 1);
}
+ this.GroupManagerDoc.lastModified = new DateField;
if (group === this.currentGroup) {
this.currentGroup = undefined;
}
@@ -187,8 +187,8 @@ 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);
+ this.GroupManagerDoc && (this.GroupManagerDoc.lastModified = new DateField);
}
}
@@ -204,8 +204,8 @@ 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);
+ this.GroupManagerDoc && (this.GroupManagerDoc.lastModified = new DateField);
}
}
}
diff --git a/src/client/util/LinkManager.ts b/src/client/util/LinkManager.ts
index 56b6cb8a9..0456b4029 100644
--- a/src/client/util/LinkManager.ts
+++ b/src/client/util/LinkManager.ts
@@ -36,17 +36,21 @@ export class LinkManager {
public getAllLinks(): Doc[] {
- const lset = new Set<Doc>(DocListCast(Doc.UserDoc().myLinkDatabase));
- SharingManager.Instance.users.forEach(user => DocListCast(user.sharingDoc.myLinkDatabase).map(lset.add));
+ const lset = new Set<Doc>(DocListCast(Doc.LinkDBDoc().data));
+ SharingManager.Instance.users.forEach(user => {
+ DocListCast((user.linkDatabase as Doc)?.data).map(doc => {
+ lset.add(doc);
+ });
+ });
return Array.from(lset);
}
public addLink(linkDoc: Doc): boolean {
- return Doc.AddDocToList(Doc.UserDoc(), "myLinkDatabase", linkDoc);
+ return Doc.AddDocToList(Doc.LinkDBDoc(), "data", linkDoc);
}
public deleteLink(linkDoc: Doc): boolean {
- return Doc.RemoveDocFromList(Doc.UserDoc(), "myLinkDatabase", linkDoc);
+ return Doc.RemoveDocFromList(Doc.LinkDBDoc(), "data", linkDoc);
}
// finds all links that contain the given anchor
diff --git a/src/client/util/SharingManager.tsx b/src/client/util/SharingManager.tsx
index 16bcd46c8..271face98 100644
--- a/src/client/util/SharingManager.tsx
+++ b/src/client/util/SharingManager.tsx
@@ -22,11 +22,11 @@ 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;
sharingDocumentId: string;
+ linkDatabaseId: string;
}
/**
@@ -53,6 +53,7 @@ const storage = "data";
interface ValidatedUser {
user: User; // database minimal info to identify / communicate with a user (email, sharing doc id)
sharingDoc: Doc; // document to share/message another user
+ linkDatabase: Doc;
userColor: string; // stored on the sharinDoc, extracted for convenience?
}
@@ -130,8 +131,10 @@ export class SharingManager extends React.Component<{}> {
const isCandidate = user.email !== Doc.CurrentUserEmail;
if (isCandidate) {
const sharingDoc = await DocServer.GetRefField(user.sharingDocumentId);
- if (sharingDoc instanceof Doc) {
- sharingDocs.push({ user, sharingDoc, userColor: StrCast(sharingDoc.color) });
+ const linkDatabase = await DocServer.GetRefField(user.linkDatabaseId);
+ if (sharingDoc instanceof Doc && linkDatabase instanceof Doc) {
+ await DocListCastAsync(linkDatabase.data);
+ sharingDocs.push({ user, sharingDoc, linkDatabase, userColor: StrCast(sharingDoc.color) });
}
}
});
diff --git a/src/client/views/nodes/formattedText/FormattedTextBox.tsx b/src/client/views/nodes/formattedText/FormattedTextBox.tsx
index 598657a58..99a009d13 100644
--- a/src/client/views/nodes/formattedText/FormattedTextBox.tsx
+++ b/src/client/views/nodes/formattedText/FormattedTextBox.tsx
@@ -289,10 +289,12 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<(FieldViewProp
}
}
} else {
-
- const json = JSON.parse(Cast(this.dataDoc[this.fieldKey], RichTextField)?.Data!);
- json.selection = state.toJSON().selection;
- this._editorView.updateState(EditorState.fromJSON(this.config, json));
+ const jsonstring = Cast(this.dataDoc[this.fieldKey], RichTextField)?.Data!;
+ if (jsonstring) {
+ const json = JSON.parse(jsonstring);
+ json.selection = state.toJSON().selection;
+ this._editorView.updateState(EditorState.fromJSON(this.config, json));
+ }
}
}
}
@@ -1554,7 +1556,7 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<(FieldViewProp
}
@computed get sidebarHandle() {
- const annotated = DocListCast(this.dataDoc[this.annotationKey]).filter(d => d?.title).length;
+ const annotated = DocListCast(this.dataDoc[this.annotationKey]).filter(d => d?.author).length;
return !this.props.isSelected() && !(annotated && !this.sidebarWidth()) ? (null) :
<div className="formattedTextBox-sidebar-handle"
style={{ left: `max(0px, calc(100% - ${this.sidebarWidthPercent} ${this.sidebarWidth() ? "- 5px" : "- 10px"}))`, background: annotated ? "lightBlue" : undefined }}
diff --git a/src/fields/Doc.ts b/src/fields/Doc.ts
index d85f0785e..0e0a49876 100644
--- a/src/fields/Doc.ts
+++ b/src/fields/Doc.ts
@@ -885,6 +885,7 @@ export namespace Doc {
export function SetSearchQuery(query: string) { runInAction(() => manager._searchQuery = query); }
export function UserDoc(): Doc { return manager._user_doc; }
export function SharingDoc(): Doc { return Cast(Doc.UserDoc().mySharedDocs, Doc, null); }
+ export function LinkDBDoc(): Doc { return Cast(Doc.UserDoc().myLinkDatabase, Doc, null); }
export function SetSelectedTool(tool: InkTool) { Doc.UserDoc().activeInkTool = tool; }
export function GetSelectedTool(): InkTool { return StrCast(Doc.UserDoc().activeInkTool, InkTool.None) as InkTool; }
diff --git a/src/server/ApiManagers/UserManager.ts b/src/server/ApiManagers/UserManager.ts
index e5c0f3827..f36506b14 100644
--- a/src/server/ApiManagers/UserManager.ts
+++ b/src/server/ApiManagers/UserManager.ts
@@ -19,9 +19,9 @@ export default class UserManager extends ApiManager {
method: Method.GET,
subscription: "/getUsers",
secureHandler: async ({ res }) => {
- const cursor = await Database.Instance.query({}, { email: 1, sharingDocumentId: 1 }, "users");
+ const cursor = await Database.Instance.query({}, { email: 1, linkDatabaseId: 1, sharingDocumentId: 1 }, "users");
const results = await cursor.toArray();
- res.send(results.map(user => ({ email: user.email, sharingDocumentId: user.sharingDocumentId })));
+ res.send(results.map(user => ({ email: user.email, linkDatabaseId: user.linkDatabaseId, sharingDocumentId: user.sharingDocumentId })));
}
});
@@ -47,7 +47,7 @@ export default class UserManager extends ApiManager {
register({
method: Method.GET,
subscription: "/getUserDocumentIds",
- secureHandler: ({ res, user }) => res.send({ userDocumentId: user.userDocumentId, sharingDocumentId: user.sharingDocumentId })
+ secureHandler: ({ res, user }) => res.send({ userDocumentId: user.userDocumentId, linkDatabaseId: user.linkDatabaseId, sharingDocumentId: user.sharingDocumentId })
});
register({
@@ -58,6 +58,12 @@ export default class UserManager extends ApiManager {
register({
method: Method.GET,
+ subscription: "/getLinkDatabaseId",
+ secureHandler: ({ res, user }) => res.send(user.linkDatabaseId)
+ });
+
+ register({
+ method: Method.GET,
subscription: "/getCurrentUser",
secureHandler: ({ res, user: { _id, email, cacheDocumentIds } }) => res.send(JSON.stringify({ id: _id, email, cacheDocumentIds })),
publicHandler: ({ res }) => res.send(JSON.stringify({ id: "__guest__", email: "" }))
diff --git a/src/server/GarbageCollector.ts b/src/server/GarbageCollector.ts
index 6bd0e5163..7c441e3c0 100644
--- a/src/server/GarbageCollector.ts
+++ b/src/server/GarbageCollector.ts
@@ -65,7 +65,7 @@ async function GarbageCollect(full: boolean = true) {
// await new Promise(res => setTimeout(res, 3000));
const cursor = await Database.Instance.query({}, { userDocumentId: 1 }, 'users');
const users = await cursor.toArray();
- const ids: string[] = [...users.map(user => user.userDocumentId), ...users.map(user => user.sharingDocumentId)]];
+ const ids: string[] = [...users.map(user => user.userDocumentId), ...users.map(user => user.sharingDocumentId), ...users.map(user => user.linkDatabaseId)];
const visited = new Set<string>();
const files: { [name: string]: string[] } = {};
diff --git a/src/server/authentication/AuthenticationManager.ts b/src/server/authentication/AuthenticationManager.ts
index 84abd41a2..9eb4a328f 100644
--- a/src/server/authentication/AuthenticationManager.ts
+++ b/src/server/authentication/AuthenticationManager.ts
@@ -49,6 +49,7 @@ export let postSignup = (req: Request, res: Response, next: NextFunction) => {
password,
userDocumentId: Utils.GenerateGuid(),
sharingDocumentId: Utils.GenerateGuid(),
+ linkDatabaseId: Utils.GenerateGuid(),
cacheDocumentIds: ""
} as Partial<DashUserModel>;
diff --git a/src/server/authentication/DashUserModel.ts b/src/server/authentication/DashUserModel.ts
index 4f2856a78..bee28b96d 100644
--- a/src/server/authentication/DashUserModel.ts
+++ b/src/server/authentication/DashUserModel.ts
@@ -11,6 +11,7 @@ export type DashUserModel = mongoose.Document & {
userDocumentId: string;
sharingDocumentId: string;
+ linkDatabaseId: string;
cacheDocumentIds: string;
profile: {
@@ -39,7 +40,8 @@ const userSchema = new mongoose.Schema({
userDocumentId: String, // id that identifies a document which hosts all of a user's account data
sharingDocumentId: String, // id that identifies a document that stores documents shared to a user, their user color, and any additional info needed to communicate between users
- cacheDocumentIds: String,
+ linkDatabaseId: String,
+ cacheDocumentIds: String, // set of document ids to retreive on startup
facebook: String,
twitter: String,