UNPKG

@universis/docutracks

Version:

Implementation of document numbering services hosted by docutracks

353 lines (339 loc) 15.6 kB
'use strict'; Object.defineProperty(exports, '__esModule', { value: true }); var common = require('@themost/common'); var docnumbers = require('@universis/docnumbers'); var fetch = require('node-fetch'); var data = require('@themost/data'); var util = require('util'); function _interopDefaultLegacy (e) { return e && typeof e === 'object' && 'default' in e ? e : { 'default': e }; } var fetch__default = /*#__PURE__*/_interopDefaultLegacy(fetch); const DocumentReferenceKind = { Default: { Id: 1 }, }; const DocumentReferenceType = { Incoming: { Id: 1 }, Outgoing: { Id: 2 }, }; /*! ***************************************************************************** Copyright (c) Microsoft Corporation. Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted. THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. ***************************************************************************** */ function __decorate(decorators, target, key, desc) { var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d; if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc); else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r; return c > 3 && r && Object.defineProperty(target, key, r), r; } function __awaiter(thisArg, _arguments, P, generator) { function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } return new (P || (P = Promise))(function (resolve, reject) { function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } step((generator = generator.apply(thisArg, _arguments || [])).next()); }); } let DepartmentDocumentNumberSeries = class DepartmentDocumentNumberSeries { static getGroups(context) { return __awaiter(this, void 0, void 0, function* () { // validate permissions const validator = new data.DataPermissionEventListener(); // noinspection JSUnresolvedFunction const validateAsync = util.promisify(validator.validate); // get first user department const user = yield context.model('User').where('name').equal(context.user.name).getTypedItem(); const userDepartments = user && user.property('departments'); let firstUserDepartment = null; if (userDepartments) { firstUserDepartment = yield userDepartments.select('id').getItem(); } // validate create permissions yield validateAsync({ model: context.model('DepartmentDocumentNumberSeries'), mask: data.PermissionMask.Create, target: { department: firstUserDepartment }, }); const service = context.getApplication().getService(docnumbers.DocumentNumberService); if (typeof service.getGroups === 'function') { return yield service.getGroups(); } }); } }; __decorate([ data.EdmMapping.func('Groups', data.EdmType.CollectionOf('Object')) ], DepartmentDocumentNumberSeries, "getGroups", null); DepartmentDocumentNumberSeries = __decorate([ data.EdmMapping.entityType('DocumentNumberSeries') ], DepartmentDocumentNumberSeries); class DepartmentDocumentNumberSeriesReplacer extends common.ApplicationService { constructor(app) { super(app); } apply() { // get schema loader const schemaLoader = this.getApplication().getConfiguration().getStrategy(data.SchemaLoaderStrategy); // get model definition const model = schemaLoader.getModelDefinition('DepartmentDocumentNumberSeries'); // get model class const loader = this.getApplication().getConfiguration().getStrategy(data.ModelClassLoaderStrategy); const DepartmentDocumentNumberSeriesBase = loader.resolve(model); // extend class DepartmentDocumentNumberSeriesBase.getGroups = DepartmentDocumentNumberSeries.getGroups; const builder = this.getApplication().getStrategy(data.ODataModelBuilder); if (builder != null) { builder.addEntity('OrganizationGroupItem') .addProperty('id', data.EdmType.EdmInt32, false) .addProperty('name', data.EdmType.EdmString, false) .addProperty('alternateName', data.EdmType.EdmString, false) .addProperty('path', data.EdmType.EdmString, false); builder.getEntity('DepartmentDocumentNumberSeries').collection .addFunction('Groups').returnsCollection('OrganizationGroupItem'); } } } class LoginError extends Error { constructor() { super('Failed to authenticate process against current document number service'); } } class InvalidIdentifierError extends Error { constructor() { super('The specified document series has an invalid identifier'); } } function assignHeaders(source, addHeaders) { if (addHeaders) { addHeaders.forEach((value, name) => { source.append(name, value); }); } return source; } class DocutracksNumberService extends docnumbers.DefaultDocumentNumberService { constructor(app) { super(app); this.options = app.getConfiguration().getSourceAt('settings/universis/docutracks'); // apply changes to document series model new DepartmentDocumentNumberSeriesReplacer(app).apply(); } /** * Validates the content type of the given response * @param {Response} response */ validateContentType(response) { // get content type const contentType = response.headers.get('Content-Type'); if (/^application\/json;/g.test(contentType) === false) { throw new common.HttpNotAcceptableError(`Document service response is invalid. Expected a valid json but got ${contentType}`); } } login() { return __awaiter(this, void 0, void 0, function* () { const loginResponse = yield fetch__default["default"](new URL('/services/authentication/login', this.options.server).toString(), { method: 'POST', body: JSON.stringify({ UserName: this.options.user, Password: this.options.password }), headers: new fetch.Headers({ 'Content-Type': 'application/json' }) }); if (loginResponse.ok) { // validate response this.validateContentType(loginResponse); // get body const body = yield loginResponse.json(); if (body == null) { throw new Error('The response returned by document service is invalid.'); } if (body && body.Success === false) { throw new LoginError(); } // return cookie const setCookie = loginResponse.headers.get('Set-Cookie'); return setCookie.split(',').map((v) => v.trim()).find((v) => { return /^\.ASPXAUTH=/.test(v); }); } else { throw new LoginError(); } }); } getGroupFrom(alternateName) { const matches = /^\/Groups\/(\d+)$/ig.exec(alternateName); if (matches == null) { throw new InvalidIdentifierError(); } return parseInt(matches[1], 10); } next(context, documentSeries, extraAttributes) { return __awaiter(this, void 0, void 0, function* () { common.Args.check(documentSeries != null, 'Document series cannot be empty at this context.'); // get document series alternate name const alternateName = yield context.model('DocumentNumberSeries').where('id').equal(documentSeries.id) .select('alternateName').silent().value(); if (alternateName == null) { throw new common.DataError('E_ATTRIBUTE', 'The specified document series does not have an alternate name or it\'s not accessible.', null, 'DocumentNumberSeries', 'alternateName'); } // try to login const authenticationCookie = yield this.login(); // the alternate name should have a format like /Groups/104 // get group identifier from the given alternate name const value = this.getGroupFrom(alternateName); // set group reference const group = { Id: value }; const title = extraAttributes && extraAttributes.description; // create request payload const documentRequest = { Document: { Title: title, Attachments: [], Kind: DocumentReferenceKind.Default, Type: DocumentReferenceType.Outgoing, CreatedByGroup: group, CreatedForGroup: group, DocumentCopies: [ { CreatedByGroup: group, OwnedByGroup: group } ] } }; const userContext = context; if (userContext.user && userContext.user.name) { // try to get user const findUser = yield this.getUser(userContext.user.name); if (findUser.User != null) { documentRequest.Document.CreatedBy = findUser.User; } } const headers1 = assignHeaders(new fetch.Headers({ 'Content-Type': 'application/json', 'Cookie': authenticationCookie }), this.headers); // register document const response1 = yield fetch__default["default"](new URL('/services/document/register', this.options.server).toString(), { method: 'POST', body: JSON.stringify(documentRequest), headers: headers1 }); // if response is ok if (response1.ok) { this.validateContentType(response1); // get response const documentResponse = yield response1.json(); // if the operation has been failed if (documentResponse.Success === false) { common.TraceUtils.error('DocutracksNumberService', documentRequest, documentResponse); // throw error throw new common.DataError('E_DOC_NUMBER_ERROR', documentResponse.ErrorInfo.ExceptionMessage || documentResponse.ErrorInfo.ErrorMessage, null); } // otherwise return document number return documentResponse.DocumentInfo.ProtocolText; } }); } getUser(name) { return __awaiter(this, void 0, void 0, function* () { // try to login const authenticationCookie = yield this.login(); const headers = assignHeaders(new fetch.Headers({ 'Content-Type': 'application/json', 'Cookie': authenticationCookie }), this.headers); const response = yield fetch__default["default"](new URL('/services/user/get/byusername', this.options.server).toString(), { method: 'POST', body: JSON.stringify({ Username: name }), // tslint:disable-next-line: object-literal-shorthand headers: headers }); if (response.ok) { this.validateContentType(response); const res = yield response.json(); return res; } throw new common.HttpError(response.status, 'An error occurred while getting user', response.statusText); }); } getGroups() { return __awaiter(this, void 0, void 0, function* () { // try to login const authenticationCookie = yield this.login(); // register document const headers = assignHeaders(new fetch.Headers({ 'Content-Type': 'application/json', 'Cookie': authenticationCookie }), this.headers); const response = yield fetch__default["default"](new URL('/services/organization/fullUsersTree', this.options.server).toString(), { method: 'GET', // tslint:disable-next-line: object-literal-shorthand headers: headers }); if (response.ok) { this.validateContentType(response); const body = yield response.json(); const results = []; if (Array.isArray(body)) { function extractGroups(group, parentPath) { const res = []; const addGroup = { id: group.Id, name: group.DisplayName, alternateName: `/Groups/${group.Id}`, path: `${parentPath}/${group.DisplayName}` }; res.push(addGroup); if (group.SubGroups) { group.SubGroups.forEach((item) => { const addGroups = extractGroups(item, addGroup.path); res.push.apply(res, addGroups); }); } return res; } body.forEach((item) => { results.push.apply(results, extractGroups(item, '')); }); } return results; } throw new Error('An error occurred while getting organization groups'); }); } add(context, file, item) { return super.add(context, file, item); } replace(context, file, item) { return super.replace(context, file, item); } } exports.DocumentReferenceKind = DocumentReferenceKind; exports.DocumentReferenceType = DocumentReferenceType; exports.DocutracksNumberService = DocutracksNumberService; exports.InvalidIdentifierError = InvalidIdentifierError; exports.LoginError = LoginError; //# sourceMappingURL=index.js.map