aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorbobzel <zzzman@gmail.com>2020-10-01 20:31:39 -0400
committerbobzel <zzzman@gmail.com>2020-10-01 20:31:39 -0400
commit266590937d3fda5dd96729edaa7c9bfac42370d9 (patch)
tree39a0315ff280757c8e07fd4e29a49a9d5e251efd /src
parentca64e0257cc4dd43e386c17b3d8b7b30747a7d9f (diff)
major performance fix by adding a SharingDocument to the user's DB account so that inquiring the users' UserDoc (and everything it referecens) is no longer necessary.
Diffstat (limited to 'src')
-rw-r--r--src/client/DocServer.ts10
-rw-r--r--src/client/util/CurrentUserUtils.ts39
-rw-r--r--src/client/util/GroupManager.tsx12
-rw-r--r--src/client/util/SettingsManager.tsx4
-rw-r--r--src/client/util/SharingManager.tsx37
-rw-r--r--src/client/views/GlobalKeyHandler.ts3
-rw-r--r--src/client/views/nodes/DocumentView.tsx2
-rw-r--r--src/fields/Doc.ts2
-rw-r--r--src/mobile/AudioUpload.tsx2
-rw-r--r--src/mobile/ImageUpload.tsx4
-rw-r--r--src/mobile/MobileInterface.tsx8
-rw-r--r--src/server/ApiManagers/UserManager.ts14
-rw-r--r--src/server/GarbageCollector.ts2
-rw-r--r--src/server/authentication/AuthenticationManager.ts3
-rw-r--r--src/server/authentication/DashUserModel.ts4
15 files changed, 82 insertions, 64 deletions
diff --git a/src/client/DocServer.ts b/src/client/DocServer.ts
index d7dfa4498..9683eab45 100644
--- a/src/client/DocServer.ts
+++ b/src/client/DocServer.ts
@@ -9,6 +9,7 @@ import { GestureOverlay } from './views/GestureOverlay';
import MobileInkOverlay from '../mobile/MobileInkOverlay';
import { runInAction } from 'mobx';
import { ObjectField } from '../fields/ObjectField';
+import { StrCast } from '../fields/Types';
/**
* This class encapsulates the transfer and cross-client synchronization of
@@ -25,6 +26,15 @@ import { ObjectField } from '../fields/ObjectField';
*/
export namespace DocServer {
let _cache: { [id: string]: RefField | Promise<Opt<RefField>> } = {};
+
+ export function PRINT_CACHE() {
+ const strings: string[] = [];
+ Array.from(Object.keys(_cache)).forEach(key => {
+ const doc = _cache[key];
+ if (doc instanceof Doc) strings.push(StrCast(doc.author) + " " + StrCast(doc.title) + " " + StrCast(Doc.GetT(doc, "title", "string", true)));
+ });
+ strings.sort().forEach((str, i) => console.log(i.toString() + " " + str));
+ }
export let _socket: SocketIOClient.Socket;
// this client's distinct GUID created at initialization
let GUID: string;
diff --git a/src/client/util/CurrentUserUtils.ts b/src/client/util/CurrentUserUtils.ts
index d45a2c90a..c00ad2334 100644
--- a/src/client/util/CurrentUserUtils.ts
+++ b/src/client/util/CurrentUserUtils.ts
@@ -404,7 +404,7 @@ export class CurrentUserUtils {
const headerTemplate = Docs.Create.RTFDocument(new RichTextField(JSON.stringify(json), ""), { title: "header", version: headerViewVersion, target: doc, _height: 70, _headerHeight: 12, _headerFontSize: 9, _autoHeight: true, system: true, cloneFieldFilter: new List<string>(["system"]) }, "header"); // text needs to be a space to allow templateText to be created
headerTemplate[DataSym].layout =
"<div style={'height:100%'}>" +
- " <FormattedTextBox {...props} fieldKey={'header'} dontSelectOnLoad={'true'} ignoreAutoHeight={'true'} pointerEvents='{this._headerPointerEvents||`none`}' fontSize='{this._headerFontSize}px' height='{this._headerHeight}px' background='{this._headerColor||this.target.userColor}' />" +
+ " <FormattedTextBox {...props} fieldKey={'header'} dontSelectOnLoad={'true'} ignoreAutoHeight={'true'} pointerEvents='{this._headerPointerEvents||`none`}' fontSize='{this._headerFontSize}px' height='{this._headerHeight}px' background='{this._headerColor||this.target.mySharedDocs.userColor}' />" +
" <FormattedTextBox {...props} fieldKey={'text'} position='absolute' top='{(this._headerHeight)*scale}px' height='calc({100/scale}% - {this._headerHeight}px)'/>" +
"</div>";
(headerTemplate.proto as Doc).isTemplateDoc = makeTemplate(headerTemplate.proto as Doc, true, "headerView");
@@ -513,10 +513,7 @@ export class CurrentUserUtils {
return doc.myItemCreators as Doc;
}
- static menuBtnDescriptions(doc: Doc): {
- title: string, target: Doc, icon: string, click: string, watchedDocuments?: Doc
- }[] {
- this.setupSharingSidebar(doc); // sets up the right sidebar collection for mobile upload documents and sharing
+ static async menuBtnDescriptions(doc: Doc) {
return [
{ title: "Dashboards", target: Cast(doc.myDashboards, Doc, null), icon: "desktop", click: 'selectMainMenu(self)' },
{ title: "Recently Closed", target: Cast(doc.myRecentlyClosedDocs, Doc, null), icon: "archive", click: 'selectMainMenu(self)' },
@@ -540,9 +537,10 @@ export class CurrentUserUtils {
})) as any as Doc;
}
}
- static setupMenuPanel(doc: Doc) {
+ static async setupMenuPanel(doc: Doc, sharingDocumentId: string) {
if (doc.menuStack === undefined) {
- const menuBtns = CurrentUserUtils.menuBtnDescriptions(doc).map(({ title, target, icon, click, watchedDocuments }) =>
+ await this.setupSharingSidebar(doc, sharingDocumentId); // 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,
iconShape: "square",
@@ -874,9 +872,18 @@ export class CurrentUserUtils {
}
// Sharing sidebar is where shared documents are contained
- static setupSharingSidebar(doc: Doc) {
+ static async setupSharingSidebar(doc: Doc, sharingDocumentId: string) {
if (doc.mySharedDocs === undefined) {
- doc.mySharedDocs = new PrefetchProxy(Docs.Create.StackingDocument([], { title: "My SharedDocs", childDropAction: "alias", system: true, contentPointerEvents: "none", childLimitHeight: 0, _yMargin: 50, _gridGap: 15, _showTitle: "title", ignoreClick: true, lockedPosition: true }));
+ let sharedDocs = await DocServer.GetRefField(sharingDocumentId);
+ if (!sharedDocs) {
+ sharedDocs = Docs.Create.StackingDocument([], {
+ title: "My SharedDocs", childDropAction: "alias", system: true, contentPointerEvents: "none", childLimitHeight: 0, _yMargin: 50, _gridGap: 15, _showTitle: "title", ignoreClick: true, lockedPosition: true
+ }, sharingDocumentId);
+ }
+ if (sharedDocs instanceof Doc) {
+ sharedDocs.userColor = sharedDocs.userColor || "#12121233";
+ }
+ doc.mySharedDocs = new PrefetchProxy(sharedDocs);
}
}
@@ -943,11 +950,10 @@ export class CurrentUserUtils {
return doc.clickFuncs as Doc;
}
- static async updateUserDocument(doc: Doc) {
+ static async updateUserDocument(doc: Doc, sharingDocumentId: string) {
doc.system = true;
doc.noviceMode = doc.noviceMode === undefined ? "true" : doc.noviceMode;
doc.title = Doc.CurrentUserEmail;
- doc.userColor = doc.userColor || "#12121233";
doc._raiseWhenDragged = true;
doc.activeInkPen = doc;
doc.activeInkColor = StrCast(doc.activeInkColor, "rgb(0, 0, 0)");
@@ -976,7 +982,7 @@ 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
- this.setupMenuPanel(doc);
+ await this.setupMenuPanel(doc, sharingDocumentId);
doc.globalLinkDatabase = Docs.Prototypes.MainLinkDocument();
doc.globalScriptDatabase = Docs.Prototypes.MainScriptDocument();
doc.globalGroupDatabase = Docs.Prototypes.MainGroupDocument();
@@ -1013,10 +1019,11 @@ export class CurrentUserUtils {
public static async loadUserDocument({ id, email }: { id: string, email: string }) {
this.curr_id = id;
Doc.CurrentUserEmail = email;
- await rp.get(Utils.prepend("/getUserDocumentId")).then(id => {
- if (id && id !== "guest") {
- return DocServer.GetRefField(id).then(async field =>
- Doc.SetUserDoc(await this.updateUserDocument(field instanceof Doc ? field : new Doc(id, true))));
+ await rp.get(Utils.prepend("/getUserDocumentIds")).then(ids => {
+ const { userDocumentId, sharingDocumentId } = JSON.parse(ids) as any;
+ if (userDocumentId !== "guest") {
+ return DocServer.GetRefField(userDocumentId).then(async field =>
+ Doc.SetUserDoc(await this.updateUserDocument(field instanceof Doc ? field : new Doc(userDocumentId, true), sharingDocumentId)));
} 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 cb512bca8..70ea48ab8 100644
--- a/src/client/util/GroupManager.tsx
+++ b/src/client/util/GroupManager.tsx
@@ -64,14 +64,10 @@ export class GroupManager extends React.Component<{}> {
const userList = await RequestPromise.get(Utils.prepend("/getUsers"));
const raw = JSON.parse(userList) as User[];
const evaluating = raw.map(async user => {
- const userDocument = await DocServer.GetRefField(user.userDocumentId);
- if (userDocument instanceof Doc) {
- const notificationDoc = await Cast(userDocument.mySharedDocs, Doc);
- runInAction(() => {
- if (notificationDoc instanceof Doc) {
- this.users.push(user.email);
- }
- });
+ const userSharingDocument = await DocServer.GetRefField(user.sharingDocumentId);
+ if (userSharingDocument instanceof Doc) {
+ const notificationDoc = await Cast(userSharingDocument.mySharedDocs, Doc, null);
+ runInAction(() => notificationDoc && this.users.push(user.email));
}
});
return Promise.all(evaluating).then(() => this.populating = false);
diff --git a/src/client/util/SettingsManager.tsx b/src/client/util/SettingsManager.tsx
index cd01fea5a..9934f26d3 100644
--- a/src/client/util/SettingsManager.tsx
+++ b/src/client/util/SettingsManager.tsx
@@ -56,7 +56,7 @@ export class SettingsManager extends React.Component<{}> {
@undoBatch changeFontFamily = action((e: React.ChangeEvent) => Doc.UserDoc().fontFamily = (e.currentTarget as any).value);
@undoBatch changeFontSize = action((e: React.ChangeEvent) => Doc.UserDoc().fontSize = (e.currentTarget as any).value);
@undoBatch switchActiveBackgroundColor = action((color: ColorState) => Doc.UserDoc().activeCollectionBackground = String(color.hex));
- @undoBatch switchUserColor = action((color: ColorState) => Doc.UserDoc().userColor = String(color.hex));
+ @undoBatch switchUserColor = action((color: ColorState) => Doc.SharingDoc().userColor = String(color.hex));
@undoBatch
playgroundModeToggle = action(() => {
this.playgroundMode = !this.playgroundMode;
@@ -205,6 +205,6 @@ export class SettingsManager extends React.Component<{}> {
isDisplayed={this.isOpen}
interactive={true}
closeOnExternalClick={this.close}
- dialogueBoxStyle={{ width: "600px", background: Cast(Doc.UserDoc().userColor, "string", null) }} />;
+ dialogueBoxStyle={{ width: "600px", background: Cast(Doc.SharingDoc().userColor, "string", null) }} />;
}
} \ No newline at end of file
diff --git a/src/client/util/SharingManager.tsx b/src/client/util/SharingManager.tsx
index 984583ed5..0cf6cc87c 100644
--- a/src/client/util/SharingManager.tsx
+++ b/src/client/util/SharingManager.tsx
@@ -25,7 +25,7 @@ import { SearchBox } from "../views/search/SearchBox";
export interface User {
email: string;
- userDocumentId: string;
+ sharingDocumentId: string;
}
/**
@@ -50,12 +50,11 @@ const storage = "data";
* A user who also has a notificationDoc.
*/
interface ValidatedUser {
- user: User;
- notificationDoc: Doc;
- userColor: string;
+ user: User; // database minimal info to identify / communicate with a user (email, sharing doc id)
+ sharingDoc: Doc; // document to share/message another user
+ userColor: string; // stored on the sharinDoc, extracted for convenience?
}
-
@observer
export class SharingManager extends React.Component<{}> {
public static Instance: SharingManager;
@@ -119,7 +118,7 @@ export class SharingManager extends React.Component<{}> {
}
/**
- * Populates the list of validated users (this.users) by adding registered users which have a mySharedDocs.
+ * Populates the list of validated users (this.users) by adding registered users which have a sharingDocument.
*/
populateUsers = async () => {
if (!this.populating) {
@@ -130,15 +129,9 @@ export class SharingManager extends React.Component<{}> {
const evaluating = raw.map(async user => {
const isCandidate = user.email !== Doc.CurrentUserEmail;
if (isCandidate) {
- const userDocument = await DocServer.GetRefField(user.userDocumentId);
- if (userDocument instanceof Doc) {
- const notificationDoc = await Cast(userDocument.mySharedDocs, Doc);
- const userColor = StrCast(userDocument.userColor);
- runInAction(() => {
- if (notificationDoc instanceof Doc) {
- this.users.push({ user, notificationDoc, userColor });
- }
- });
+ const userSharingDoc = await DocServer.GetRefField(user.sharingDocumentId);
+ if (userSharingDoc instanceof Doc) {
+ runInAction(() => this.users.push({ user, sharingDoc: userSharingDoc, userColor: StrCast(userSharingDoc.userColor) }));
}
}
});
@@ -170,7 +163,7 @@ export class SharingManager extends React.Component<{}> {
// if documents have been shared, add the doc to that list if it doesn't already exist, otherwise create a new list with the doc
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, notificationDoc }) => {
+ users.forEach(({ user, sharingDoc: notificationDoc }) => {
if (permission !== SharingPermissions.None) Doc.IndexOf(doc, DocListCast(notificationDoc[storage])) === -1 && Doc.AddDocToList(notificationDoc, storage, doc); // add the doc to the notificationDoc if it hasn't already been added
else GetEffectiveAcl(doc, undefined, user.email) === AclPrivate && Doc.IndexOf((doc.aliasOf as Doc || doc), DocListCast(notificationDoc[storage])) !== -1 && Doc.RemoveDocFromList(notificationDoc, storage, (doc.aliasOf as Doc || doc)); // remove the doc from the list if it already exists
});
@@ -185,7 +178,7 @@ export class SharingManager extends React.Component<{}> {
*/
shareWithAddedMember = (group: Doc, emailId: string) => {
const user: ValidatedUser = this.users.find(({ user: { email } }) => email === emailId)!;
- if (group.docsShared) DocListCast(group.docsShared).forEach(doc => Doc.IndexOf(doc, DocListCast(user.notificationDoc[storage])) === -1 && Doc.AddDocToList(user.notificationDoc, storage, doc));
+ if (group.docsShared) DocListCast(group.docsShared).forEach(doc => Doc.IndexOf(doc, DocListCast(user.sharingDoc[storage])) === -1 && Doc.AddDocToList(user.sharingDoc, storage, doc));
}
/**
@@ -216,7 +209,7 @@ export class SharingManager extends React.Component<{}> {
if (group.docsShared) {
DocListCast(group.docsShared).forEach(doc => {
- Doc.IndexOf(doc, DocListCast(user.notificationDoc[storage])) !== -1 && Doc.RemoveDocFromList(user.notificationDoc, storage, doc); // remove the doc only if it is in the list
+ Doc.IndexOf(doc, DocListCast(user.sharingDoc[storage])) !== -1 && Doc.RemoveDocFromList(user.sharingDoc, storage, doc); // remove the doc only if it is in the list
});
}
}
@@ -235,7 +228,7 @@ export class SharingManager extends React.Component<{}> {
const members: string[] = JSON.parse(StrCast(group.members));
const users: ValidatedUser[] = this.users.filter(({ user: { email } }) => members.includes(email));
- users.forEach(({ notificationDoc }) => Doc.RemoveDocFromList(notificationDoc, storage, doc));
+ users.forEach(({ sharingDoc: notificationDoc }) => Doc.RemoveDocFromList(notificationDoc, storage, doc));
});
}
}
@@ -244,7 +237,7 @@ export class SharingManager extends React.Component<{}> {
* Shares the document with a user.
*/
setInternalSharing = (recipient: ValidatedUser, permission: string, targetDoc?: Doc) => {
- const { user, notificationDoc } = recipient;
+ const { user, sharingDoc: notificationDoc } = recipient;
const target = targetDoc || this.targetDoc!;
const key = normalizeEmail(user.email);
const acl = `acl-${key}`;
@@ -456,7 +449,7 @@ export class SharingManager extends React.Component<{}> {
const commonKeys = intersection(...docs.map(doc => this.layoutDocAcls ? doc?.[AclSym] && Object.keys(doc[AclSym]) : doc?.[DataSym]?.[AclSym] && Object.keys(doc[DataSym][AclSym])));
// the list of users shared with
- const userListContents: (JSX.Element | null)[] = users.filter(({ user }) => docs.length > 1 ? commonKeys.includes(`acl-${normalizeEmail(user.email)}`) : docs[0]?.author !== user.email).map(({ user, notificationDoc, userColor }) => {
+ const userListContents: (JSX.Element | null)[] = users.filter(({ user }) => docs.length > 1 ? commonKeys.includes(`acl-${normalizeEmail(user.email)}`) : docs[0]?.author !== user.email).map(({ user, sharingDoc: notificationDoc, userColor }) => {
const userKey = `acl-${normalizeEmail(user.email)}`;
const uniform = docs.every(doc => this.layoutDocAcls ? doc?.[AclSym]?.[userKey] === docs[0]?.[AclSym]?.[userKey] : doc?.[DataSym]?.[AclSym]?.[userKey] === docs[0]?.[DataSym]?.[AclSym]?.[userKey]);
const permissions = uniform ? StrCast(targetDoc?.[userKey]) : "-multiple-";
@@ -472,7 +465,7 @@ export class SharingManager extends React.Component<{}> {
<select
className={"permissions-dropdown"}
value={permissions}
- onChange={e => this.setInternalSharing({ user, notificationDoc, userColor }, e.currentTarget.value)}
+ onChange={e => this.setInternalSharing({ user, sharingDoc: notificationDoc, userColor }, e.currentTarget.value)}
>
{this.sharingOptions(uniform)}
</select>
diff --git a/src/client/views/GlobalKeyHandler.ts b/src/client/views/GlobalKeyHandler.ts
index 1b2395423..2ea1c464f 100644
--- a/src/client/views/GlobalKeyHandler.ts
+++ b/src/client/views/GlobalKeyHandler.ts
@@ -55,7 +55,8 @@ export class KeyManager {
});
public handle = action(async (e: KeyboardEvent) => {
- if (e.key.toLowerCase() === "shift") KeyManager.Instance.ShiftPressed = true;
+ if (e.key.toLowerCase() === "shift" && e.ctrlKey && e.altKey) KeyManager.Instance.ShiftPressed = true;
+ if (!Doc.UserDoc().noviceMode && e.key.toLocaleLowerCase() === "shift") DocServer.PRINT_CACHE();
const keyname = e.key && e.key.toLowerCase();
this.handleGreedy(keyname);
diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx
index 5f99f27b1..ddcf7f6f4 100644
--- a/src/client/views/nodes/DocumentView.tsx
+++ b/src/client/views/nodes/DocumentView.tsx
@@ -1049,7 +1049,7 @@ export class DocumentView extends DocComponent<DocumentViewProps, Document>(Docu
const titleView = (!this.ShowTitle ? (null) :
<div className={`documentView-titleWrapper${showTitleHover ? "-hover" : ""}`} key="title" style={{
position: this.showOverlappingTitle ? "absolute" : "relative",
- background: SharingManager.Instance.users.find(users => users.user.email === this.dataDoc.author)?.userColor || (this.rootDoc.type === DocumentType.RTF ? StrCast(Doc.UserDoc().userColor) : "rgba(0,0,0,0.4)"),
+ background: SharingManager.Instance.users.find(users => users.user.email === this.dataDoc.author)?.userColor || (this.rootDoc.type === DocumentType.RTF ? StrCast(Doc.SharingDoc().userColor) : "rgba(0,0,0,0.4)"),
pointerEvents: this.onClickHandler || this.Document.ignoreClick ? "none" : undefined,
}}>
<EditableView ref={this._titleRef}
diff --git a/src/fields/Doc.ts b/src/fields/Doc.ts
index 59be3a27c..d9c641973 100644
--- a/src/fields/Doc.ts
+++ b/src/fields/Doc.ts
@@ -867,6 +867,7 @@ export namespace Doc {
export class DocData {
@observable _user_doc: Doc = undefined!;
+ @observable _sharing_doc: Doc = undefined!;
@observable _searchQuery: string = "";
}
@@ -883,6 +884,7 @@ export namespace Doc {
export function SearchQuery(): string { return manager._searchQuery; }
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 SetSelectedTool(tool: InkTool) { Doc.UserDoc().activeInkTool = tool; }
export function GetSelectedTool(): InkTool { return StrCast(Doc.UserDoc().activeInkTool, InkTool.None) as InkTool; }
diff --git a/src/mobile/AudioUpload.tsx b/src/mobile/AudioUpload.tsx
index 36663c85f..ebc8bc8a7 100644
--- a/src/mobile/AudioUpload.tsx
+++ b/src/mobile/AudioUpload.tsx
@@ -53,7 +53,7 @@ export class AudioUpload extends React.Component {
* Pushing the audio doc onto Dash Web through the right side bar
*/
uploadAudio = () => {
- const audioRightSidebar = Cast(Doc.UserDoc().mySharedDocs, Doc) as Doc;
+ const audioRightSidebar = Cast(Doc.SharingDoc(), Doc, null);
const audioDoc = this._audioCol;
const data = Cast(audioRightSidebar.data, listSpec(Doc));
for (let i = 1; i < 8; i++) {
diff --git a/src/mobile/ImageUpload.tsx b/src/mobile/ImageUpload.tsx
index 1ee4c7815..65f9e40ff 100644
--- a/src/mobile/ImageUpload.tsx
+++ b/src/mobile/ImageUpload.tsx
@@ -63,11 +63,11 @@ export class Uploader extends React.Component<ImageUploadProps> {
doc = Docs.Create.ImageDocument(path, { _nativeWidth: defaultNativeImageDim, _width: 400, title: name });
}
this.setOpacity(4, "1"); // Slab 4
- const res = await rp.get(Utils.prepend("/getUserDocumentId"));
+ const res = await rp.get(Utils.prepend("/getUserDocumentIds"));
if (!res) {
throw new Error("No user id returned");
}
- const field = await DocServer.GetRefField(res);
+ const field = await DocServer.GetRefField(JSON.parse(res).userDocumentId);
let pending: Opt<Doc>;
if (field instanceof Doc) {
pending = col;
diff --git a/src/mobile/MobileInterface.tsx b/src/mobile/MobileInterface.tsx
index 72914e62b..a42d85b56 100644
--- a/src/mobile/MobileInterface.tsx
+++ b/src/mobile/MobileInterface.tsx
@@ -440,7 +440,7 @@ export class MobileInterface extends React.Component {
// DocButton that uses UndoManager and handles the opacity change if CanUndo is true
@computed get undo() {
if (this.mainContainer && this._activeDoc.type === "collection" && this._activeDoc !== this._homeDoc &&
- this._activeDoc !== Doc.UserDoc().mySharedDocs && this._activeDoc.title !== "WORKSPACES") {
+ this._activeDoc !== Doc.SharingDoc() && this._activeDoc.title !== "WORKSPACES") {
return (
<div className="docButton"
style={{ backgroundColor: "black", color: "white", fontSize: "60", opacity: UndoManager.CanUndo() ? "1" : "0.4", }}
@@ -458,7 +458,7 @@ export class MobileInterface extends React.Component {
// DocButton that uses UndoManager and handles the opacity change if CanRedo is true
@computed get redo() {
if (this.mainContainer && this._activeDoc.type === "collection" && this._activeDoc !== this._homeDoc &&
- this._activeDoc !== Doc.UserDoc().mySharedDocs && this._activeDoc.title !== "WORKSPACES") {
+ this._activeDoc !== Doc.SharingDoc() && this._activeDoc.title !== "WORKSPACES") {
return (
<div className="docButton"
style={{ backgroundColor: "black", color: "white", fontSize: "60", opacity: UndoManager.CanRedo() ? "1" : "0.4", }}
@@ -609,7 +609,7 @@ export class MobileInterface extends React.Component {
// Returns the image upload pop up
@computed get uploadImage() {
- const doc = !this._homeMenu ? this._activeDoc : Cast(Doc.UserDoc().mySharedDocs, Doc) as Doc;
+ const doc = !this._homeMenu ? this._activeDoc : Cast(Doc.SharingDoc(), Doc) as Doc;
return <Uploader Document={doc} />;
}
@@ -632,7 +632,7 @@ export class MobileInterface extends React.Component {
*/
@action
switchToMobileUploads = () => {
- const mobileUpload = Cast(Doc.UserDoc().mySharedDocs, Doc) as Doc;
+ const mobileUpload = Cast(Doc.SharingDoc(), Doc) as Doc;
this.switchCurrentView(mobileUpload);
this._homeMenu = false;
}
diff --git a/src/server/ApiManagers/UserManager.ts b/src/server/ApiManagers/UserManager.ts
index 0d1d8f218..c9ffaff4c 100644
--- a/src/server/ApiManagers/UserManager.ts
+++ b/src/server/ApiManagers/UserManager.ts
@@ -19,16 +19,22 @@ export default class UserManager extends ApiManager {
method: Method.GET,
subscription: "/getUsers",
secureHandler: async ({ res }) => {
- const cursor = await Database.Instance.query({}, { email: 1, userDocumentId: 1 }, "users");
+ const cursor = await Database.Instance.query({}, { email: 1, sharingDocumentId: 1 }, "users");
const results = await cursor.toArray();
- res.send(results.map(user => ({ email: user.email, userDocumentId: user.userDocumentId })));
+ res.send(results.map(user => ({ email: user.email, sharingDocumentId: user.sharingDocumentId })));
}
});
register({
method: Method.GET,
- subscription: "/getUserDocumentId",
- secureHandler: ({ res, user }) => res.send(user.userDocumentId)
+ subscription: "/getUserDocumentIds",
+ secureHandler: ({ res, user }) => res.send({ userDocumentId: user.userDocumentId, sharingDocumentId: user.sharingDocumentId })
+ });
+
+ register({
+ method: Method.GET,
+ subscription: "/getSharingDocumentId",
+ secureHandler: ({ res, user }) => res.send(user.sharingDocumentId)
});
register({
diff --git a/src/server/GarbageCollector.ts b/src/server/GarbageCollector.ts
index a9a3b0481..6bd0e5163 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);
+ const ids: string[] = [...users.map(user => user.userDocumentId), ...users.map(user => user.sharingDocumentId)]];
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 00f1fe44e..36363e3cf 100644
--- a/src/server/authentication/AuthenticationManager.ts
+++ b/src/server/authentication/AuthenticationManager.ts
@@ -47,7 +47,8 @@ export let postSignup = (req: Request, res: Response, next: NextFunction) => {
const model = {
email,
password,
- userDocumentId: Utils.GenerateGuid()
+ userDocumentId: Utils.GenerateGuid(),
+ sharingDocumentId: Utils.GenerateGuid()
} as Partial<DashUserModel>;
const user = new User(model);
diff --git a/src/server/authentication/DashUserModel.ts b/src/server/authentication/DashUserModel.ts
index 51d920a8f..0bdc25644 100644
--- a/src/server/authentication/DashUserModel.ts
+++ b/src/server/authentication/DashUserModel.ts
@@ -10,6 +10,7 @@ export type DashUserModel = mongoose.Document & {
passwordResetExpires?: Date,
userDocumentId: string;
+ sharingDocumentId: string;
profile: {
name: string,
@@ -35,7 +36,8 @@ const userSchema = new mongoose.Schema({
passwordResetToken: String,
passwordResetExpires: Date,
- userDocumentId: String,
+ 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
facebook: String,
twitter: String,