diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/client/documents/Documents.ts | 12 | ||||
-rw-r--r-- | src/client/util/CurrentUserUtils.ts | 9 | ||||
-rw-r--r-- | src/client/util/GroupManager.tsx | 2 | ||||
-rw-r--r-- | src/client/util/SharingManager.tsx | 31 | ||||
-rw-r--r-- | src/client/views/DocComponent.tsx | 4 | ||||
-rw-r--r-- | src/client/views/PropertiesView.tsx | 11 | ||||
-rw-r--r-- | src/client/views/collections/CollectionMenu.tsx | 4 | ||||
-rw-r--r-- | src/client/views/collections/CollectionView.tsx | 4 | ||||
-rw-r--r-- | src/client/views/nodes/formattedText/RichTextRules.ts | 8 |
9 files changed, 40 insertions, 45 deletions
diff --git a/src/client/documents/Documents.ts b/src/client/documents/Documents.ts index 47fa7067d..7ee8267f8 100644 --- a/src/client/documents/Documents.ts +++ b/src/client/documents/Documents.ts @@ -574,7 +574,7 @@ export namespace Docs { * only when creating a DockDocument from the current user's already existing * main document. */ - export function InstanceFromProto(proto: Doc, data: Field | undefined, options: DocumentOptions, delegId?: string, fieldKey: string = "data") { + export function InstanceFromProto(proto: Doc, data: Field | undefined, options: DocumentOptions, delegId?: string, fieldKey: string = "data", protoId?: string) { const { omit: protoProps, extract: delegateProps } = OmitKeys(options, delegateKeys, "^_"); protoProps.system = delegateProps.system; @@ -590,7 +590,7 @@ export namespace Docs { protoProps.isPrototype = true; - const dataDoc = MakeDataDelegate(proto, protoProps, data, fieldKey); + const dataDoc = MakeDataDelegate(proto, protoProps, data, fieldKey, protoId); const viewDoc = Doc.MakeDelegate(dataDoc, delegId); // so that the list of annotations is already initialised, prevents issues in addonly. @@ -620,8 +620,8 @@ export namespace Docs { * @param options initial values to apply to this new delegate * @param value the data to store in this new delegate */ - function MakeDataDelegate<D extends Field>(proto: Doc, options: DocumentOptions, value?: D, fieldKey: string = "data") { - const deleg = Doc.MakeDelegate(proto); + function MakeDataDelegate<D extends Field>(proto: Doc, options: DocumentOptions, value?: D, fieldKey: string = "data", id: string | undefined = undefined) { + const deleg = Doc.MakeDelegate(proto, id); if (value !== undefined) { deleg[fieldKey] = value; } @@ -807,8 +807,8 @@ export namespace Docs { return InstanceFromProto(Prototypes.get(DocumentType.COL), new List(documents), { _chromeStatus: "collapsed", dontRegisterChildViews: true, ...options, _viewType: CollectionViewType.Tree }, id); } - export function StackingDocument(documents: Array<Doc>, options: DocumentOptions, id?: string) { - return InstanceFromProto(Prototypes.get(DocumentType.COL), new List(documents), { _chromeStatus: "collapsed", ...options, _viewType: CollectionViewType.Stacking }, id); + export function StackingDocument(documents: Array<Doc>, options: DocumentOptions, id?: string, protoId?: string) { + return InstanceFromProto(Prototypes.get(DocumentType.COL), new List(documents), { _chromeStatus: "collapsed", ...options, _viewType: CollectionViewType.Stacking }, id, undefined, protoId); } export function MulticolumnDocument(documents: Array<Doc>, options: DocumentOptions) { diff --git a/src/client/util/CurrentUserUtils.ts b/src/client/util/CurrentUserUtils.ts index cff07d48e..ec550c15a 100644 --- a/src/client/util/CurrentUserUtils.ts +++ b/src/client/util/CurrentUserUtils.ts @@ -30,6 +30,7 @@ import { Scripting } from "./Scripting"; import { SearchUtil } from "./SearchUtil"; import { SelectionManager } from "./SelectionManager"; import { UndoManager } from "./UndoManager"; +import { SharingPermissions } from "../../fields/util"; const headerViewVersion = "0.1"; @@ -874,11 +875,13 @@ export class CurrentUserUtils { // Sharing sidebar is where shared documents are contained static async setupSharingSidebar(doc: Doc, sharingDocumentId: string) { if (doc.mySharedDocs === undefined) { - let sharedDocs = await DocServer.GetRefField(sharingDocumentId); + let sharedDocs = await DocServer.GetRefField(sharingDocumentId + "outer"); 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); + title: "My SharedDocs", childDropAction: "alias", system: true, contentPointerEvents: "none", childLimitHeight: 0, _yMargin: 50, _gridGap: 15, + _showTitle: "title", ignoreClick: true, lockedPosition: true, + }, sharingDocumentId + "outer", sharingDocumentId); + (sharedDocs as Doc)["acl-Public"] = Doc.GetProto(sharedDocs as Doc)["acl-Public"] = SharingPermissions.Add; } if (sharedDocs instanceof Doc) { sharedDocs.userColor = sharedDocs.userColor || "#12121233"; diff --git a/src/client/util/GroupManager.tsx b/src/client/util/GroupManager.tsx index 70ea48ab8..e81c95d83 100644 --- a/src/client/util/GroupManager.tsx +++ b/src/client/util/GroupManager.tsx @@ -66,7 +66,7 @@ export class GroupManager extends React.Component<{}> { const evaluating = raw.map(async user => { const userSharingDocument = await DocServer.GetRefField(user.sharingDocumentId); if (userSharingDocument instanceof Doc) { - const notificationDoc = await Cast(userSharingDocument.mySharedDocs, Doc, null); + const notificationDoc = await Cast(userSharingDocument.data, Doc, null); runInAction(() => notificationDoc && this.users.push(user.email)); } }); diff --git a/src/client/util/SharingManager.tsx b/src/client/util/SharingManager.tsx index 0cf6cc87c..c67ec2db5 100644 --- a/src/client/util/SharingManager.tsx +++ b/src/client/util/SharingManager.tsx @@ -47,7 +47,7 @@ const groupType = "!groupType/"; const storage = "data"; /** - * A user who also has a notificationDoc. + * A user who also has a sharing doc. */ interface ValidatedUser { user: User; // database minimal info to identify / communicate with a user (email, sharing doc id) @@ -59,7 +59,7 @@ interface ValidatedUser { export class SharingManager extends React.Component<{}> { public static Instance: SharingManager; @observable private isOpen = false; // whether the SharingManager modal is open or not - @observable public users: ValidatedUser[] = []; // the list of users with notificationDocs + @observable public users: ValidatedUser[] = []; // the list of users with sharing docs @observable private targetDoc: Doc | undefined; // the document being shared @observable private targetDocView: DocumentView | undefined; // the DocumentView of the document being shared // @observable private copied = false; @@ -163,9 +163,9 @@ 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, 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 + 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 }); } }); @@ -228,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(({ sharingDoc: notificationDoc }) => Doc.RemoveDocFromList(notificationDoc, storage, doc)); + users.forEach(({ sharingDoc }) => Doc.RemoveDocFromList(sharingDoc, storage, doc)); }); } } @@ -237,19 +237,18 @@ export class SharingManager extends React.Component<{}> { * Shares the document with a user. */ setInternalSharing = (recipient: ValidatedUser, permission: string, targetDoc?: Doc) => { - const { user, sharingDoc: notificationDoc } = recipient; + const { user, sharingDoc } = recipient; const target = targetDoc || this.targetDoc!; - const key = normalizeEmail(user.email); - const acl = `acl-${key}`; + const acl = `acl-${normalizeEmail(user.email)}`; + const myAcl = `acl-${Doc.CurrentUserEmailNormalized}`; const docs = SelectionManager.SelectedDocuments().length < 2 ? [target] : SelectionManager.SelectedDocuments().map(docView => docView.props.Document); - docs.forEach(doc => { - doc.author === Doc.CurrentUserEmail && !doc[`acl-${Doc.CurrentUserEmailNormalized}`] && distributeAcls(`acl-${Doc.CurrentUserEmailNormalized}`, SharingPermissions.Admin, doc); + 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(notificationDoc[storage])) === -1 && Doc.AddDocToList(notificationDoc, storage, doc); - 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)); + 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)); }); } @@ -449,7 +448,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, sharingDoc: 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, 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-"; @@ -465,7 +464,7 @@ export class SharingManager extends React.Component<{}> { <select className={"permissions-dropdown"} value={permissions} - onChange={e => this.setInternalSharing({ user, sharingDoc: notificationDoc, userColor }, e.currentTarget.value)} + onChange={e => this.setInternalSharing({ user, sharingDoc: sharingDoc, userColor }, e.currentTarget.value)} > {this.sharingOptions(uniform)} </select> @@ -516,7 +515,7 @@ export class SharingManager extends React.Component<{}> { // the list of groups shared with - const groupListMap: (Doc | { groupName: string })[] = groups.filter(({ groupName }) => docs.length > 1 ? commonKeys.includes(`acl-${StrCast(groupName).replace('.', '_')}`) : true); + const groupListMap: (Doc | { groupName: string })[] = groups.filter(({ groupName }) => docs.length > 1 ? commonKeys.includes(`acl-${normalizeEmail(StrCast(groupName))}`) : true); groupListMap.unshift({ groupName: "Public" }, { groupName: "Override" }); const groupListContents = groupListMap.map(group => { const groupKey = `acl-${StrCast(group.groupName)}`; diff --git a/src/client/views/DocComponent.tsx b/src/client/views/DocComponent.tsx index 893b74d75..b3fbe418b 100644 --- a/src/client/views/DocComponent.tsx +++ b/src/client/views/DocComponent.tsx @@ -7,7 +7,7 @@ import { InteractionUtils } from '../util/InteractionUtils'; import { List } from '../../fields/List'; import { DateField } from '../../fields/DateField'; import { ScriptField } from '../../fields/ScriptField'; -import { GetEffectiveAcl, SharingPermissions, distributeAcls } from '../../fields/util'; +import { GetEffectiveAcl, SharingPermissions, distributeAcls, denormalizeEmail } from '../../fields/util'; /// DocComponent returns a generic React base class used by views that don't have 'fieldKey' props (e.g.,CollectionFreeFormDocumentView, DocumentView) @@ -166,7 +166,7 @@ export function ViewBoxAnnotatableComponent<P extends ViewBoxAnnotatableProps, T if (this.props.Document[AclSym]) { added.forEach(d => { for (const [key, value] of Object.entries(this.props.Document[AclSym])) { - if (d.author === key.substring(4).replace("_", ".") && !d.aliasOf) distributeAcls(key, SharingPermissions.Admin, d, true); + if (d.author === denormalizeEmail(key.substring(4)) && !d.aliasOf) distributeAcls(key, SharingPermissions.Admin, d, true); //else if (this.props.Document[key] === SharingPermissions.Admin) distributeAcls(key, SharingPermissions.Add, d, true); // else distributeAcls(key, this.AclMap.get(value) as SharingPermissions, d, true); } diff --git a/src/client/views/PropertiesView.tsx b/src/client/views/PropertiesView.tsx index b30691ff5..f3241e8d9 100644 --- a/src/client/views/PropertiesView.tsx +++ b/src/client/views/PropertiesView.tsx @@ -10,7 +10,7 @@ import { Id } from "../../fields/FieldSymbols"; import { InkField } from "../../fields/InkField"; import { ComputedField } from "../../fields/ScriptField"; import { Cast, NumCast, StrCast } from "../../fields/Types"; -import { GetEffectiveAcl, SharingPermissions } from "../../fields/util"; +import { GetEffectiveAcl, SharingPermissions, denormalizeEmail } from "../../fields/util"; import { emptyFunction, emptyPath, returnEmptyDoclist, returnEmptyFilter, returnFalse, returnOne } from "../../Utils"; import { DocumentType } from "../documents/DocumentTypes"; import { DocumentManager } from "../util/DocumentManager"; @@ -409,7 +409,7 @@ export class PropertiesView extends React.Component<PropertiesViewProps> { // DocCastAsync(Doc.UserDoc().sidebarUsersDisplayed).then(sidebarUsersDisplayed => { if (commonKeys.length) { for (const key of commonKeys) { - const name = key.substring(4).replace("_", "."); + const name = denormalizeEmail(key.substring(4)); const uniform = docs.every(doc => this.layoutDocAcls ? doc?.[AclSym]?.[key] === docs[0]?.[AclSym]?.[key] : doc?.[DataSym]?.[AclSym]?.[key] === docs[0]?.[DataSym]?.[AclSym]?.[key]); if (name !== Doc.CurrentUserEmail && name !== target.author && name !== "Public" && name !== "Override"/* && sidebarUsersDisplayed![name] !== false*/) { tableEntries.push(this.sharingItem(name, showAdmin, uniform ? AclMap.get(this.layoutDocAcls ? target[AclSym][key] : target[DataSym][AclSym][key])! : "-multiple-")); @@ -417,13 +417,6 @@ export class PropertiesView extends React.Component<PropertiesViewProps> { } } - // if (Doc.UserDoc().sidebarUsersDisplayed) { - // for (const [name, value] of Object.entries(sidebarUsersDisplayed!)) { - // if (value === true && !this.selectedDoc![`acl-${name.substring(8).replace(".", "_")}`]) tableEntries.push(this.sharingItem(name.substring(8), effectiveAcl, SharingPermissions.None)); - // } - // } - // }) - const ownerSame = Doc.CurrentUserEmail !== target.author && docs.filter(doc => doc).every(doc => doc.author === docs[0].author); // shifts the current user, owner, public to the top of the doc. tableEntries.unshift(this.sharingItem("Override", showAdmin, docs.filter(doc => doc).every(doc => doc["acl-Override"] === docs[0]["acl-Override"]) ? (AclMap.get(target[AclSym]?.["acl-Override"]) || "None") : "-multiple-")); diff --git a/src/client/views/collections/CollectionMenu.tsx b/src/client/views/collections/CollectionMenu.tsx index e9cb57fed..09ff3bb0c 100644 --- a/src/client/views/collections/CollectionMenu.tsx +++ b/src/client/views/collections/CollectionMenu.tsx @@ -894,14 +894,14 @@ export class CollectionStackingViewChrome extends React.Component<CollectionMenu if (docs instanceof Doc) { const keys = Object.keys(docs).filter(key => key.indexOf("title") >= 0 || key.indexOf("author") >= 0 || key.indexOf("creationDate") >= 0 || key.indexOf("lastModified") >= 0 || - (key[0].toUpperCase() === key[0] && key.substring(0, 3) !== "acl" && key[0] !== "_")); + (key[0].toUpperCase() === key[0] && key[0] !== "_")); return keys.filter(key => key.toLowerCase().indexOf(val) > -1); } else { const keys = new Set<string>(); docs.forEach(doc => Doc.allKeys(doc).forEach(key => keys.add(key))); const noviceKeys = Array.from(keys).filter(key => key.indexOf("title") >= 0 || key.indexOf("author") >= 0 || key.indexOf("creationDate") >= 0 || key.indexOf("lastModified") >= 0 || - (key[0]?.toUpperCase() === key[0] && key.substring(0, 3) !== "acl" && key[0] !== "_")); + (key[0]?.toUpperCase() === key[0] && key[0] !== "_")); return noviceKeys.filter(key => key.toLowerCase().indexOf(val) > -1); } } diff --git a/src/client/views/collections/CollectionView.tsx b/src/client/views/collections/CollectionView.tsx index 522f46280..2bdc8e2f3 100644 --- a/src/client/views/collections/CollectionView.tsx +++ b/src/client/views/collections/CollectionView.tsx @@ -10,7 +10,7 @@ import { List } from '../../../fields/List'; import { ObjectField } from '../../../fields/ObjectField'; import { BoolCast, Cast, ScriptCast, StrCast } from '../../../fields/Types'; import { ImageField } from '../../../fields/URLField'; -import { distributeAcls, GetEffectiveAcl, SharingPermissions, TraceMobx } from '../../../fields/util'; +import { distributeAcls, GetEffectiveAcl, SharingPermissions, TraceMobx, normalizeEmail, denormalizeEmail } from '../../../fields/util'; import { returnFalse, Utils } from '../../../Utils'; import { Docs, DocUtils } from '../../documents/Documents'; import { DocumentType } from '../../documents/DocumentTypes'; @@ -143,7 +143,7 @@ export class CollectionView extends Touchable<FieldViewProps & CollectionViewCus if (this.props.Document[AclSym]) { added.forEach(d => { for (const [key, value] of Object.entries(this.props.Document[AclSym])) { - if (d.author === key.substring(4).replace("_", ".") && !d.aliasOf) distributeAcls(key, SharingPermissions.Admin, d, true); + if (d.author === denormalizeEmail(key.substring(4)) && !d.aliasOf) distributeAcls(key, SharingPermissions.Admin, d, true); //else if (this.props.Document[key] === SharingPermissions.Admin) distributeAcls(key, SharingPermissions.Add, d, true); //else distributeAcls(key, this.AclMap.get(value) as SharingPermissions, d, true); } diff --git a/src/client/views/nodes/formattedText/RichTextRules.ts b/src/client/views/nodes/formattedText/RichTextRules.ts index 921c0e128..72b91c955 100644 --- a/src/client/views/nodes/formattedText/RichTextRules.ts +++ b/src/client/views/nodes/formattedText/RichTextRules.ts @@ -3,7 +3,8 @@ import { NodeSelection, TextSelection } from "prosemirror-state"; import { DataSym, Doc } from "../../../../fields/Doc"; import { Id } from "../../../../fields/FieldSymbols"; import { ComputedField } from "../../../../fields/ScriptField"; -import { Cast, NumCast, StrCast } from "../../../../fields/Types"; +import { NumCast, StrCast } from "../../../../fields/Types"; +import { normalizeEmail } from "../../../../fields/util"; import { returnFalse, Utils } from "../../../../Utils"; import { DocServer } from "../../../DocServer"; import { Docs, DocUtils } from "../../../documents/Documents"; @@ -11,7 +12,6 @@ import { FormattedTextBox } from "./FormattedTextBox"; import { wrappingInputRule } from "./prosemirrorPatches"; import { RichTextMenu } from "./RichTextMenu"; import { schema } from "./schema_rts"; -import { List } from "../../../../fields/List"; export class RichTextRules { public Document: Doc; @@ -271,7 +271,7 @@ export class RichTextRules { (state, match, start, end) => { const fieldKey = match[1]; const rawdocid = match[3]?.substring(1); - const docid = rawdocid ? (!rawdocid.includes("@") ? Doc.CurrentUserEmail + "@" + rawdocid : rawdocid).replace(".", "_") : undefined; + const docid = rawdocid ? (!rawdocid.includes("@") ? normalizeEmail(Doc.CurrentUserEmail) + "@" + rawdocid : rawdocid) : undefined; const value = match[2]?.substring(1); if (!fieldKey) { const linkId = Utils.GenerateGuid(); @@ -304,7 +304,7 @@ export class RichTextRules { const fieldKey = match[1] || ""; const fieldParam = match[2]?.replace("…", "...") || ""; const rawdocid = match[3]?.substring(1); - const docid = rawdocid ? (!rawdocid.includes("@") ? Doc.CurrentUserEmail + "@" + rawdocid : rawdocid).replace(".", "_") : undefined; + const docid = rawdocid ? (!rawdocid.includes("@") ? normalizeEmail(Doc.CurrentUserEmail) + "@" + rawdocid : rawdocid) : undefined; if (!fieldKey && !docid) return state.tr; docid && DocServer.GetRefField(docid).then(docx => { if (!(docx instanceof Doc && docx)) { |