UNPKG

scrivito

Version:

Scrivito is a professional, yet easy to use SaaS Enterprise Content Management Service, built for digital agencies and medium to large businesses. It is completely maintenance-free, cost-effective, and has unprecedented performance and security.

272 lines (233 loc) 7.58 kB
import { ArgumentError, isBlob, isFile } from 'scrivito_sdk/common'; import { FieldBoost, FullTextSearchOperator, ObjScope, SearchField, SearchOperator, createObjFromFileIn, createObjIn, excludeDeletedObjs, excludeGlobal, getObjBy, getObjFrom, getRootObjFrom, restrictToObjClass, } from 'scrivito_sdk/models'; import { AttributeDefinitions, Obj, ObjClass } from 'scrivito_sdk/realm'; import { initialAttributesFor } from 'scrivito_sdk/realm/initial_attributes_for'; import { ObjAttributes } from 'scrivito_sdk/realm/obj'; import { ObjSearch, SearchValue } from 'scrivito_sdk/realm/obj_search'; import { Schema } from 'scrivito_sdk/realm/schema'; import { unwrapAppAttributes, wrapInAppClass, } from 'scrivito_sdk/realm/wrap_in_app_class'; import { objClassNameFor } from './registry'; export interface SiteContext< AttrDefs extends AttributeDefinitions = AttributeDefinitions > { create(params?: ObjAttributes<AttrDefs>): Obj<AttrDefs>; createFromFile( file: File, attributes?: ObjAttributes<AttrDefs> ): Promise<Obj<AttrDefs>>; get(objId: string): Obj<AttrDefs> | null; getIncludingDeleted(objId: string): Obj<AttrDefs> | null; getByPath(path: string): Obj<AttrDefs> | null; getByPermalink(permalink: string): Obj<AttrDefs> | null; root(): Obj | null; all(): ObjSearch<AttrDefs>; where( fields: SearchField, operator: SearchOperator, value: SearchValue, boost?: FieldBoost ): ObjSearch<AttrDefs>; whereFullTextOf( fields: SearchField, operator: FullTextSearchOperator, value: SearchValue, boost?: FieldBoost ): ObjSearch<AttrDefs>; } export class BasicSiteContext<AttrDefs extends AttributeDefinitions> implements SiteContext<AttrDefs> { constructor( private readonly objClass: ObjClass, private readonly scopeIncludingDeletedObjs: ObjScope ) {} get(id: string): Obj<AttrDefs> | null { return this.getObj(id, this.scope()); } getIncludingDeleted(id: string): Obj<AttrDefs> | null { return this.getObj(id, this.scopeIncludingDeletedObjs); } getByPath(path: string): Obj<AttrDefs> | null { const obj = getObjBy(this.scope().and(excludeGlobal), '_path', path); return wrapInAppClass<AttrDefs>(obj); } getByPermalink(permalink: string): Obj<AttrDefs> | null { const obj = getObjBy(this.scope(), '_permalink', permalink); return wrapInAppClass<AttrDefs>(obj); } root(): Obj | null { return wrapInAppClass(getRootObjFrom(this.scope())); } all(): ObjSearch<AttrDefs> { return this.getSearch(1000); } where( attribute: SearchField, operator: SearchOperator, value: SearchValue, boost?: FieldBoost ): ObjSearch<AttrDefs> { return this.getSearch().and(attribute, operator, value, boost); } whereFullTextOf( attribute: SearchField, operator: FullTextSearchOperator, value: SearchValue, boost?: FieldBoost ): ObjSearch<AttrDefs> { return this.getSearch().andFullTextOf(attribute, operator, value, boost); } create(attributes: ObjAttributes<AttrDefs> = {}): Obj<AttrDefs> { const objClassName = this.objClassNameForCreate(); assertValidCreateAttributes(attributes); const attributesForCreate = prepareAttributesForCreate( attributes, objClassName, // Bang: objClassNameForCreate above ensures that it's a subclass of Obj Schema.forClass(this.objClass)! ); const basicObj = createObjIn( this.scope().and(restrictToObjClass(objClassName)), attributesForCreate ); return wrapInAppClass<AttrDefs>(basicObj); } async createFromFile( file: File, attributes: ObjAttributes<AttrDefs> = {} ): Promise<Obj<AttrDefs>> { const objClassName = this.objClassNameForCreate(); assertValidFile(file); assertValidCreateAttributes(attributes); if (Object.prototype.hasOwnProperty.call(attributes, 'blob')) { throw new ArgumentError( 'Setting attribute "blob" is not allowed when creating CMS objects from file, ' + 'because the file will be assigned to that attribute' ); } // Bang: objClassNameForCreate above ensures that it's a subclass of Obj const schema = Schema.forClass(this.objClass)!; if (!schema.isBinary()) { throw new ArgumentError( 'Creating CMS objects from file is only available for classes with a binary attribute "blob"' ); } const attributesForCreate = prepareAttributesForCreate( attributes, objClassName, schema ); const basicObj = await createObjFromFileIn( this.scope().and(restrictToObjClass(objClassName)), file, attributesForCreate ); return wrapInAppClass<AttrDefs>(basicObj); } toSiteContext(): SiteContext<AttrDefs> { return { get: this.get.bind(this), getIncludingDeleted: this.getIncludingDeleted.bind(this), getByPath: this.getByPath.bind(this), getByPermalink: this.getByPermalink.bind(this), root: this.root.bind(this), all: this.all.bind(this), where: this.where.bind(this), whereFullTextOf: this.where.bind(this), create: this.create.bind(this), createFromFile: this.createFromFile.bind(this), }; } private getObj(id: string, scope: ObjScope) { return wrapInAppClass<AttrDefs>( getObjFrom(this.getScopeRestrictedToSameClass(scope), id) ); } private getSearch(batchSize?: 1000) { const search = this.getScopeRestrictedToSameClass(this.scope()).search(); if (batchSize !== undefined) search.batchSize(batchSize); return new ObjSearch<AttrDefs>(search); } private getScopeRestrictedToSameClass(scope: ObjScope) { const objClassName = this.objClassName(); return objClassName ? scope.and(restrictToObjClass(objClassName)) : scope; } private objClassName() { return objClassNameFor(this.objClass); } private objClassNameForCreate() { const objClassName = this.objClassName(); if (!objClassName) { throw new ArgumentError( 'Use a specific class (like Page or Image) in order to create an Obj.' ); } return objClassName; } private scope() { return this.scopeIncludingDeletedObjs.and(excludeDeletedObjs); } } function prepareAttributesForCreate( appAttributes: { [key: string]: unknown }, appClassName: string, schema: Schema ) { const initialAttributes = initialAttributesFor( appAttributes, schema, appClassName ); const createAttributes = { ...appAttributes, ...initialAttributes, }; return unwrapAppAttributes(createAttributes, schema, appClassName); } function assertValidCreateAttributes(attributes: { [key: string]: unknown }) { if (attributes.constructor !== Object) { throw new ArgumentError( 'The provided attributes are invalid. They have ' + 'to be an Object with valid Scrivito attribute values.' ); } if (attributes._objClass) { throw new ArgumentError( 'Invalid attribute "_objClass". ' + `"${String( attributes._objClass )}.create" will automatically set the CMS object class ` + 'correctly.' ); } } function assertValidFile(file: unknown) { if (!isFile(file)) { if (isBlob(file)) { throw new ArgumentError( 'Creating CMS objects from file is only available with instances of "File", ' + 'but an instance of "Blob" is given' ); } throw new ArgumentError( 'Creating CMS objects from file is only available with instances of "File"' ); } }