From 5b4b916b2700da746c12754ba3238eb1f3bbf5f7 Mon Sep 17 00:00:00 2001 From: usodhi <61431818+usodhi@users.noreply.github.com> Date: Sat, 15 Aug 2020 01:42:57 +0530 Subject: many changes to acls, aliases, sharing sidebar etc --- src/fields/util.ts | 37 ++++++++++++++++++++----------------- 1 file changed, 20 insertions(+), 17 deletions(-) (limited to 'src/fields') diff --git a/src/fields/util.ts b/src/fields/util.ts index 3d832636f..561d505e3 100644 --- a/src/fields/util.ts +++ b/src/fields/util.ts @@ -154,14 +154,16 @@ export enum SharingPermissions { /** * Calculates the effective access right to a document for the current user. */ -export function GetEffectiveAcl(target: any, in_prop?: string | symbol | number): symbol { +export function GetEffectiveAcl(target: any, in_prop?: string | symbol | number, user?: string): symbol { if (!target) return AclPrivate; if (in_prop === UpdatingFromServer || target[UpdatingFromServer]) return AclAdmin; if (target[AclSym] && Object.keys(target[AclSym]).length) { + const userChecked = user || Doc.CurrentUserEmail; + // if the current user is the author of the document / the current user is a member of the admin group - if (Doc.CurrentUserEmail === (target.__fields?.author || target.author) || currentUserGroups.includes("admin")) return AclAdmin; + if (userChecked === (target.__fields?.author || target.author) || currentUserGroups.includes("admin")) return AclAdmin; // if the ACL is being overriden or the property being modified is one of the playground fields (which can be freely modified) if (_overrideAcl || (in_prop && DocServer.PlaygroundFields?.includes(in_prop.toString()))) return AclEdit; @@ -178,7 +180,7 @@ export function GetEffectiveAcl(target: any, in_prop?: string | symbol | number) for (const [key, value] of Object.entries(target[AclSym])) { // 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. - if (currentUserGroups.includes(key.substring(4)) || Doc.CurrentUserEmail === key.substring(4).replace("_", ".")) { + if (currentUserGroups.includes(key.substring(4).replace("_", ".")) || userChecked === key.substring(4).replace("_", ".")) { if (HierarchyMapping.get(value as symbol)! > HierarchyMapping.get(effectiveAcl)!) { effectiveAcl = value as symbol; if (effectiveAcl === AclAdmin) break; @@ -208,52 +210,53 @@ export function distributeAcls(key: string, acl: SharingPermissions, target: Doc ["Admin", 4] ]); - let changed = false; // determines whether fetchProto should be called or not (i.e. is there a change that should be reflected in target[AclSym]) + let layoutDocChanged = false; // determines whether fetchProto should be called or not (i.e. is there a change that should be reflected in target[AclSym]) + let dataDocChanged = false; const dataDoc = target[DataSym]; // if it is inheriting from a collection, it only inherits if A) the key doesn't already exist or B) the right being inherited is more restrictive if (!inheritingFromCollection || !target[key] || HierarchyMapping.get(StrCast(target[key]))! > HierarchyMapping.get(acl)!) { target[key] = acl; - changed = true; + layoutDocChanged = true; + } + + if (dataDoc && (!inheritingFromCollection || !dataDoc[key] || HierarchyMapping.get(StrCast(dataDoc[key]))! > HierarchyMapping.get(acl)!)) { + dataDoc[key] = acl; + dataDocChanged = true; // maps over the aliases of the document - const aliases = DocListCast(target.aliases); + const aliases = DocListCast(dataDoc.aliases); if (aliases.length) { aliases.map(alias => { alias !== target && distributeAcls(key, acl, alias, inheritingFromCollection); }); } - } - - if (dataDoc && (!inheritingFromCollection || !dataDoc[key] || HierarchyMapping.get(StrCast(dataDoc[key]))! > HierarchyMapping.get(acl)!)) { - dataDoc[key] = acl; - changed = true; - // maps over the children of the document DocListCast(dataDoc[Doc.LayoutFieldKey(dataDoc)]).map(d => { - if (d.author === Doc.CurrentUserEmail && (!inheritingFromCollection || !d[key] || HierarchyMapping.get(StrCast(d[key]))! > HierarchyMapping.get(acl)!)) { + if (GetEffectiveAcl(d) === AclAdmin && (!inheritingFromCollection || !d[key] || HierarchyMapping.get(StrCast(d[key]))! > HierarchyMapping.get(acl)!)) { distributeAcls(key, acl, d, inheritingFromCollection); } const data = d[DataSym]; - if (data && data.author === Doc.CurrentUserEmail && (!inheritingFromCollection || !data[key] || HierarchyMapping.get(StrCast(data[key]))! > HierarchyMapping.get(acl)!)) { + if (data && GetEffectiveAcl(data) === AclAdmin && (!inheritingFromCollection || !data[key] || HierarchyMapping.get(StrCast(data[key]))! > HierarchyMapping.get(acl)!)) { distributeAcls(key, acl, data, inheritingFromCollection); } }); // maps over the annotations of the document DocListCast(dataDoc[Doc.LayoutFieldKey(dataDoc) + "-annotations"]).map(d => { - if (d.author === Doc.CurrentUserEmail && (!inheritingFromCollection || !d[key] || HierarchyMapping.get(StrCast(d[key]))! > HierarchyMapping.get(acl)!)) { + if (GetEffectiveAcl(d) === AclAdmin && (!inheritingFromCollection || !d[key] || HierarchyMapping.get(StrCast(d[key]))! > HierarchyMapping.get(acl)!)) { distributeAcls(key, acl, d, inheritingFromCollection); } const data = d[DataSym]; - if (data && data.author === Doc.CurrentUserEmail && (!inheritingFromCollection || !data[key] || HierarchyMapping.get(StrCast(data[key]))! > HierarchyMapping.get(acl)!)) { + if (data && GetEffectiveAcl(data) === AclAdmin && (!inheritingFromCollection || !data[key] || HierarchyMapping.get(StrCast(data[key]))! > HierarchyMapping.get(acl)!)) { distributeAcls(key, acl, data, inheritingFromCollection); } }); } - changed && fetchProto(target); // updates target[AclSym] when changes to acls have been made + layoutDocChanged && fetchProto(target); // updates target[AclSym] when changes to acls have been made + dataDocChanged && fetchProto(dataDoc); } const layoutProps = ["panX", "panY", "width", "height", "nativeWidth", "nativeHeight", "fitWidth", "fitToBox", -- cgit v1.2.3-70-g09d2 From 077a38dc22f6082974e639f8a020ceb179116958 Mon Sep 17 00:00:00 2001 From: bobzel Date: Fri, 14 Aug 2020 18:08:47 -0400 Subject: fixed some edge cses with richTextMenu synchronization. added author field to delegates --- src/client/views/collections/CollectionMenu.tsx | 4 +++- src/client/views/nodes/formattedText/RichTextMenu.tsx | 2 +- src/fields/Doc.ts | 1 + 3 files changed, 5 insertions(+), 2 deletions(-) (limited to 'src/fields') diff --git a/src/client/views/collections/CollectionMenu.tsx b/src/client/views/collections/CollectionMenu.tsx index 0b3be8739..97d38d27e 100644 --- a/src/client/views/collections/CollectionMenu.tsx +++ b/src/client/views/collections/CollectionMenu.tsx @@ -429,7 +429,9 @@ export class CollectionFreeFormViewChrome extends React.Component { @action public updateMenu(view: EditorView, lastState: EditorState | undefined, props: any) { - if (!view || !(view as any).TextView?.props.isSelected(true)) { + if (!view || !(view as any).TextView?.props.isSelected(true) || !view.hasFocus()) { return; } this.view = view; diff --git a/src/fields/Doc.ts b/src/fields/Doc.ts index ea53bc9a2..b530b1cf7 100644 --- a/src/fields/Doc.ts +++ b/src/fields/Doc.ts @@ -781,6 +781,7 @@ export namespace Doc { if (doc) { const delegate = new Doc(id, true); delegate.proto = doc; + delegate.author = Doc.CurrentUserEmail; title && (delegate.title = title); return delegate; } -- cgit v1.2.3-70-g09d2 From cd7b13c2c1086739d866e4a6ad9c239a46d89244 Mon Sep 17 00:00:00 2001 From: bobzel Date: Fri, 14 Aug 2020 18:19:20 -0400 Subject: fix to give an author to template doc protos. --- src/fields/Doc.ts | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'src/fields') diff --git a/src/fields/Doc.ts b/src/fields/Doc.ts index b530b1cf7..5f5fe98bc 100644 --- a/src/fields/Doc.ts +++ b/src/fields/Doc.ts @@ -791,7 +791,9 @@ export namespace Doc { let _applyCount: number = 0; export function ApplyTemplate(templateDoc: Doc) { if (templateDoc) { - const target = Doc.MakeDelegate(new Doc()); + const proto = new Doc(); + proto.author = Doc.CurrentUserEmail; + const target = Doc.MakeDelegate(proto); const targetKey = StrCast(templateDoc.layoutKey, "layout"); const applied = ApplyTemplateTo(templateDoc, target, targetKey, templateDoc.title + "(..." + _applyCount++ + ")"); target.layoutKey = targetKey; -- cgit v1.2.3-70-g09d2 From 4e3ed774c9ac3d1365c67125ddc97df9de245f41 Mon Sep 17 00:00:00 2001 From: bobzel Date: Fri, 14 Aug 2020 21:39:18 -0400 Subject: fixed default documents that were missing the 'system' tag. fixed catalog to have default worksapce documents in it. --- src/client/util/CurrentUserUtils.ts | 3 --- src/client/views/DocumentDecorations.tsx | 9 ++++----- src/client/views/MainView.tsx | 8 ++++++-- src/client/views/search/SearchBox.tsx | 7 +++---- src/fields/ScriptField.ts | 1 + 5 files changed, 14 insertions(+), 14 deletions(-) (limited to 'src/fields') diff --git a/src/client/util/CurrentUserUtils.ts b/src/client/util/CurrentUserUtils.ts index aff80da75..8931495dc 100644 --- a/src/client/util/CurrentUserUtils.ts +++ b/src/client/util/CurrentUserUtils.ts @@ -861,9 +861,6 @@ export class CurrentUserUtils { title: "pres element template", backgroundColor: "transparent", _xMargin: 5, _height: 46, isTemplateDoc: true, isTemplateForField: "data", system: true })); } - if (doc.activePresentation === undefined) { - doc.activePresentation = Doc.MakeCopy(doc.emptyPresentation as Doc, true); - } } // Sharing sidebar is where shared documents are contained diff --git a/src/client/views/DocumentDecorations.tsx b/src/client/views/DocumentDecorations.tsx index 3f16dd7e7..e546ca858 100644 --- a/src/client/views/DocumentDecorations.tsx +++ b/src/client/views/DocumentDecorations.tsx @@ -659,7 +659,6 @@ export class DocumentDecorations extends React.Component<{}, { value: string }> if (bounds.y > bounds.b) { bounds.y = bounds.b - (this._resizeBorderWidth + this._linkBoxHeight + this._titleHeight); } - let offset = 0; const useRotation = seldoc.rootDoc.type === DocumentType.INK; return (
@@ -674,10 +673,10 @@ export class DocumentDecorations extends React.Component<{}, { value: string }>
{bounds.r - bounds.x < 15 && bounds.b - bounds.y < 15 ? (null) : <>
{maximizeIcon} {titleArea} diff --git a/src/client/views/MainView.tsx b/src/client/views/MainView.tsx index 5a2488bb6..f7ff895a5 100644 --- a/src/client/views/MainView.tsx +++ b/src/client/views/MainView.tsx @@ -254,6 +254,8 @@ export class MainView extends React.Component { @action createNewWorkspace = async (id?: string) => { + const myCatalog = Doc.UserDoc().myCatalog as Doc; + const presentation = Doc.MakeCopy(Doc.UserDoc().emptyPresentation as Doc, true); const workspaces = Cast(this.userDoc.myWorkspaces, Doc) as Doc; const workspaceCount = DocListCast(workspaces.data).length + 1; const freeformOptions: DocumentOptions = { @@ -264,8 +266,10 @@ export class MainView extends React.Component { title: "Untitled Collection", }; const freeformDoc = CurrentUserUtils.GuestTarget || Docs.Create.FreeformDocument([], freeformOptions); - const workspaceDoc = Docs.Create.StandardCollectionDockingDocument([{ doc: freeformDoc, initialWidth: 600, path: [Doc.UserDoc().myCatalog as Doc] }], { title: `Workspace ${workspaceCount}` }, id, "row"); - + const workspaceDoc = Docs.Create.StandardCollectionDockingDocument([{ doc: freeformDoc, initialWidth: 600, path: [myCatalog] }], { title: `Workspace ${workspaceCount}` }, id, "row"); + Doc.AddDocToList(myCatalog, "data", freeformDoc); + Doc.AddDocToList(myCatalog, "data", presentation); + Doc.UserDoc().activePresentation = presentation; const toggleTheme = ScriptField.MakeScript(`self.darkScheme = !self.darkScheme`); const toggleComic = ScriptField.MakeScript(`toggleComicMode()`); const copyWorkspace = ScriptField.MakeScript(`copyWorkspace()`); diff --git a/src/client/views/search/SearchBox.tsx b/src/client/views/search/SearchBox.tsx index 770a03cb1..084449d04 100644 --- a/src/client/views/search/SearchBox.tsx +++ b/src/client/views/search/SearchBox.tsx @@ -604,13 +604,12 @@ export class SearchBox extends ViewBoxBaseComponent `NOT ({!join from=id to=proto_i}type_t:${type}) AND NOT type_t:${type}`).join(" AND ")}`; // fq: type_t:collection OR {!join from=id to=proto_i}type_t:collection q:text_t:hello - const query = [baseExpr, includeDeleted, includeIcons, typeExpr].join(" AND ").replace(/AND $/, ""); + const query = [baseExpr, includeDeleted, typeExpr].join(" AND ").replace(/AND $/, ""); return query; } diff --git a/src/fields/ScriptField.ts b/src/fields/ScriptField.ts index 9391f56ac..1fb71fefb 100644 --- a/src/fields/ScriptField.ts +++ b/src/fields/ScriptField.ts @@ -98,6 +98,7 @@ export class ScriptField extends ObjectField { if (script?.options.capturedVariables) { const doc = Doc.assign(new Doc, script.options.capturedVariables); + doc.system = true; this.captures = new ProxyField(doc); } this.setterscript = setterscript; -- cgit v1.2.3-70-g09d2 From ab89ef62d3f11c11f3f6e7162ca0e112bac1517e Mon Sep 17 00:00:00 2001 From: bobzel Date: Mon, 17 Aug 2020 15:55:17 -0400 Subject: added sort to solr search options. removed delete field assignment when removing Documents. Allowed ToScriptScript and ToString to go through regardless of ACLs --- solr-8.3.1/server/solr/dash/conf/schema.xml | 2 +- src/client/util/SearchUtil.ts | 3 ++- src/client/views/DocComponent.tsx | 1 - src/client/views/collections/CollectionSchemaCells.tsx | 2 +- src/client/views/collections/CollectionView.tsx | 1 - src/client/views/search/SearchBox.tsx | 17 +++++++++++++++-- src/fields/Doc.ts | 16 +++++----------- src/fields/util.ts | 4 ++-- 8 files changed, 26 insertions(+), 20 deletions(-) (limited to 'src/fields') diff --git a/solr-8.3.1/server/solr/dash/conf/schema.xml b/solr-8.3.1/server/solr/dash/conf/schema.xml index 4f6ae57b2..74c4b494c 100644 --- a/solr-8.3.1/server/solr/dash/conf/schema.xml +++ b/solr-8.3.1/server/solr/dash/conf/schema.xml @@ -51,7 +51,7 @@ - + diff --git a/src/client/util/SearchUtil.ts b/src/client/util/SearchUtil.ts index 6dafbd58e..ce96ab67b 100644 --- a/src/client/util/SearchUtil.ts +++ b/src/client/util/SearchUtil.ts @@ -28,6 +28,7 @@ export namespace SearchUtil { start?: number; rows?: number; fq?: string; + sort?: string; allowAliases?: boolean; onlyAliases?: boolean; "facet"?: string; @@ -42,7 +43,7 @@ export namespace SearchUtil { if (options.onlyAliases) { replacedQuery = `{!join from=id to=proto_i}DEFAULT:${replacedQuery}`; } - const gotten = await rp.get(rpquery, { qs: { ...options, sort: "lastModified_d desc", q: replacedQuery } }); + const gotten = await rp.get(rpquery, { qs: { ...options, q: replacedQuery } }); const result: IdSearchResult = gotten.startsWith("<") ? { ids: [], docs: [], numFound: 0, lines: [] } : JSON.parse(gotten); if (!returnDocs) { return result; diff --git a/src/client/views/DocComponent.tsx b/src/client/views/DocComponent.tsx index 8c8bb6fde..23ce71c4f 100644 --- a/src/client/views/DocComponent.tsx +++ b/src/client/views/DocComponent.tsx @@ -135,7 +135,6 @@ export function ViewBoxAnnotatableComponent

{ Doc.RemoveDocFromList(targetDataDoc, this.props.fieldKey + "-annotations", doc); recent && Doc.AddDocToList(recent, "data", doc, undefined, true, true); - doc.deleted = true; }); return true; } diff --git a/src/client/views/collections/CollectionSchemaCells.tsx b/src/client/views/collections/CollectionSchemaCells.tsx index d46aa3574..fa4d8c51b 100644 --- a/src/client/views/collections/CollectionSchemaCells.tsx +++ b/src/client/views/collections/CollectionSchemaCells.tsx @@ -297,7 +297,7 @@ export class CollectionSchemaCell extends React.Component { let cfield = props.Document[props.fieldKey]; this.type = props.fieldKey; if (StrCast(this.props.Document._searchString).toLowerCase() !== "") { - let term = Field.toString(cfield as Field); + let term = (cfield instanceof Promise) ? "...promise pending..." : Field.toString(cfield as Field); term = term.toLowerCase(); const search = StrCast(this.props.Document._searchString).toLowerCase(); let start = term.indexOf(search); diff --git a/src/client/views/collections/CollectionView.tsx b/src/client/views/collections/CollectionView.tsx index 9d305145e..2064b0be4 100644 --- a/src/client/views/collections/CollectionView.tsx +++ b/src/client/views/collections/CollectionView.tsx @@ -208,7 +208,6 @@ export class CollectionView extends Touchable { Doc.RemoveDocFromList(targetDataDoc, this.props.fieldKey, doc); recent && Doc.AddDocToList(recent, "data", doc, undefined, true, true); - doc.deleted = true; }); return true; } diff --git a/src/client/views/search/SearchBox.tsx b/src/client/views/search/SearchBox.tsx index 07f1485c3..847bda137 100644 --- a/src/client/views/search/SearchBox.tsx +++ b/src/client/views/search/SearchBox.tsx @@ -4,7 +4,7 @@ import { action, computed, observable, runInAction, reaction, IReactionDisposer import { observer } from 'mobx-react'; import * as React from 'react'; import * as rp from 'request-promise'; -import { Doc, DocListCast } from '../../../fields/Doc'; +import { Doc, DocListCast, Opt } from '../../../fields/Doc'; import { documentSchema } from "../../../fields/documentSchemas"; import { Id } from '../../../fields/FieldSymbols'; import { List } from '../../../fields/List'; @@ -24,6 +24,7 @@ import { ViewBoxBaseComponent } from "../DocComponent"; import { DocumentView } from '../nodes/DocumentView'; import { FieldView, FieldViewProps } from '../nodes/FieldView'; import "./SearchBox.scss"; +import { ColumnType } from "../collections/CollectionSchemaView"; export const searchSchema = createSchema({ id: "string", @@ -616,6 +617,18 @@ export class SearchBox extends ViewBoxBaseComponent { + switch (type) { + case ColumnType.Date: return "_d"; + case ColumnType.String: return "_t"; + case ColumnType.Boolean: return "_b"; + case ColumnType.Number: return "_n"; + } + } + const headers = Cast(this.props.Document._schemaHeaders, listSpec(SchemaHeaderField), []); + return headers.reduce((p: Opt, header: SchemaHeaderField) => p || (header.desc !== undefined && suffixMap(header.type) ? (header.heading + suffixMap(header.type) + (header.desc ? " desc" : " asc")) : undefined), undefined); + } private NumResults = 50; private lockPromise?: Promise; getResults = async (query: string) => { @@ -624,7 +637,7 @@ export class SearchBox extends ViewBoxBaseComponent { while (this._results.length <= this._endIndex && (this._numTotalResults === -1 || this._maxSearchIndex < this._numTotalResults)) { - this._curRequest = SearchUtil.Search(query, true, { onlyAliases: true, allowAliases: true, fq: this.filterQuery, start: this._maxSearchIndex, rows: this.NumResults, hl: true, "hl.fl": "*", }).then(action(async (res: SearchUtil.DocSearchResult) => { + this._curRequest = SearchUtil.Search(query, true, { onlyAliases: true, allowAliases: true, sort: this.primarySort, fq: this.filterQuery, start: 0, rows: this.NumResults, hl: true, "hl.fl": "*", }).then(action(async (res: SearchUtil.DocSearchResult) => { // happens at the beginning this.realTotalResults = res.numFound <= 0 ? 0 : res.numFound; if (res.numFound !== this._numTotalResults && this._numTotalResults === -1) { diff --git a/src/fields/Doc.ts b/src/fields/Doc.ts index 5f5fe98bc..0dcb8ab42 100644 --- a/src/fields/Doc.ts +++ b/src/fields/Doc.ts @@ -195,6 +195,8 @@ export class Doc extends RefField { @observable private ___fieldKeys: any = {}; + @observable + public [AclSym]: { [key: string]: symbol }; private [UpdatingFromServer]: boolean = false; @@ -204,17 +206,9 @@ export class Doc extends RefField { private [Self] = this; private [SelfProxy]: any; - public [FieldsSym] = (clear?: boolean) => { - if (clear) { - this.___fields = {}; - this.___fieldKeys = {}; - } - return this.___fields; - } - @observable - public [AclSym]: { [key: string]: symbol }; - public [WidthSym] = () => NumCast(this[SelfProxy]._width); - public [HeightSym] = () => NumCast(this[SelfProxy]._height); + public [FieldsSym](clear?: boolean) { return clear ? this.___fields = this.___fieldKeys = {} : this.___fields; } + public [WidthSym]() { return NumCast(this[SelfProxy]._width); } + public [HeightSym]() { return NumCast(this[SelfProxy]._height); } public [ToScriptString]() { return `DOC-"${this[Self][Id]}"-`; } public [ToString]() { return `Doc(${GetEffectiveAcl(this) === AclPrivate ? "-inaccessible-" : this.title})`; } public get [LayoutSym]() { return this[SelfProxy].__LAYOUT__; } diff --git a/src/fields/util.ts b/src/fields/util.ts index 3d832636f..e3d9ed2ef 100644 --- a/src/fields/util.ts +++ b/src/fields/util.ts @@ -5,7 +5,7 @@ import { ProxyField, PrefetchProxy } from "./Proxy"; import { RefField } from "./RefField"; import { ObjectField } from "./ObjectField"; import { action, trace } from "mobx"; -import { Parent, OnUpdate, Update, Id, SelfProxy, Self, HandleUpdate } from "./FieldSymbols"; +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"; @@ -286,7 +286,7 @@ 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 { let prop = in_prop; - if (in_prop === FieldsSym || in_prop === Id || in_prop === HandleUpdate || in_prop === CachedUpdates) return target.__fields[prop] || target[prop]; + if (in_prop === ToString || in_prop === ToScriptString || in_prop === FieldsSym || in_prop === Id || in_prop === HandleUpdate || in_prop === CachedUpdates) return target.__fields[prop] || target[prop]; if (in_prop === AclSym) return _overrideAcl ? undefined : target[AclSym]; if (GetEffectiveAcl(target) === AclPrivate && !_overrideAcl) return prop === HeightSym || prop === WidthSym ? returnZero : undefined; if (prop === LayoutSym) { -- cgit v1.2.3-70-g09d2