File

src/lib/service/system/system.service.ts

Description

Collection of System Services

Index

Properties
Methods

Constructor

constructor(backend: BackendService, logger: Logger, eventService: EventService, appCache: AppCacheService, translate: TranslateService)
Parameters :
Name Type Optional
backend BackendService no
logger Logger no
eventService EventService no
appCache AppCacheService no
translate TranslateService no

Methods

fetchSystemDefinition
fetchSystemDefinition(user: EoUser)

Fetches the system definition from the server. Provided params are used for storing the recent version in cache.

Parameters :
Name Type Optional Description
user EoUser no

The user to fetch the system definition for

Returns : Observable<boolean>

boolean

Public getCodesystem
getCodesystem(id: string)

Gets a codesystem

Parameters :
Name Type Optional Description
id string no

The codesystems id

Returns : ICodeSystem

The codesystem object matching the given id

Public getDefaultValue
getDefaultValue(valueType: string)

Creates a value depending on a given Type

Parameters :
Name Type Optional
valueType string no
Returns : any

any

getFormElementsFromFormModel
getFormElementsFromFormModel(objectTypeName: string, situation: string, isContextType?: boolean)

Get form elements from form model. This is useful if you have to fetch them for a special situation like SEARCH

Parameters :
Name Type Optional Description
objectTypeName string no

ObjectType to fetch elements for

situation string no

Form model situation to be fetched

isContextType boolean yes

Flag indicating that the form model should be fetched for a context mode

Returns : Observable<any[]>
Public getObjectType
getObjectType(objectTypeName: string)

Gets an ObjectType by name.

Parameters :
Name Type Optional Description
objectTypeName string no

The name of the object type

Returns : ObjectType

the ObjectType matching the given name

Public getObjectTypeForm
getObjectTypeForm(objectTypeName: string, situation: string, mode?: string)

Get the form model of an object type.

Parameters :
Name Type Optional Description
objectTypeName string no

The object type name

situation string no

The form situation to be fetched

mode string yes

Form mode to fetch (e.g. CONTEXT)

Returns : Observable<any>

The object type form model

Public getObjectTypes
getObjectTypes()

Gets all ObjectTypes

Returns : ObjectType[]

An array containing all object types

getOrganizationObject
getOrganizationObject(name: string)

Fetches the organization object for a given name.

Parameters :
Name Type Optional Description
name string no

The name to fetch object for

Returns : Observable<any>
getOrganizationObjectById
getOrganizationObjectById(id: string)

Retrieve an organization object by its ID

Parameters :
Name Type Optional Description
id string no

ID of org object

Returns : Observable<any>
getOrganizationObjects
getOrganizationObjects(names: string[])

Fetches a collection of organization objects

Parameters :
Name Type Optional Description
names string[] no

Array of names to fetch objects for

Returns : Observable<IOrganizationObjects[]>

A Array of Organization Objects

getRoles
getRoles()

Fetches a collection of organization roles

A Array of Organization Roles

Public getSystemDefinition
getSystemDefinition(user: EoUser)

Fetches the backends system definition and updates system$ Observable. Subscribe to the system$ observable instead of calling this function, otherwise you'll trigger fetching the system definition every time.

Parameters :
Name Type Optional Description
user EoUser no

The user to load the system definition for

Returns : Observable<boolean>

true when successfull

Public implementsType
implementsType(type: ObjectType, superTypeName: string)

Checks whether or not the given type implements a given supertype

Parameters :
Name Type Optional Description
type ObjectType no

Type to be checked

superTypeName string no

Name of the supertype

Returns : boolean

Properties

Public system$
system$: Observable<any>
Type : Observable<any>
Default value : this.systemSource.asObservable()

Accessors

system
getsystem()
setsystem(s: )
Parameters :
Name Optional
s no
Returns : void
import {forkJoin as observableForkJoin, of, Observable, ReplaySubject} from 'rxjs';

import {catchError, tap, map, switchMap} from 'rxjs/operators';
import {Injectable} from '@angular/core';
import {IOrganizationObjects} from '../../interface/organization-objects.interface';
import {BackendService} from '../backend/backend.service';
import {AppCacheService} from '../cache/app-cache.service';
import {Logger} from '../logger/logger';
import {ObjectType} from '../../model/object-type.model';
import {EoUser} from '../../model/eo-user.model';
import {cloneDeep} from 'lodash-es';
import {OrgRole} from '../../model/org.model';
import {Utils} from '../../util/utils';
import {ICodeSystem} from './systemdefinition.interface';
import {EventService} from '../events/event.service';
import {EnaioEvent} from '../events/events';
import moment from 'moment';
import {TranslateService} from "@ngx-translate/core";

/**
 * Collection of System Services
 */
@Injectable({
  providedIn: 'root'
})
export class SystemService {

  private _system;
  private systemSource = new ReplaySubject<any>();
  public system$: Observable<any> = this.systemSource.asObservable();

  // session cache for object type forms
  private objectTypeForms: any[] = [];
  private user: EoUser;
  private cachedRoles: OrgRole[] = [];

  constructor(private backend: BackendService,
              private logger: Logger,
              private eventService: EventService,
              private appCache: AppCacheService,
              private translate: TranslateService) {
    this.eventService.on(EnaioEvent.SYSTEM_STATUS_SCHEMA_CHANGED).subscribe(() => {
      this.fetchSystemDefinition(this.user);
    })

    // subscribe to language changes to recall the system types
    this.translate.onLangChange.subscribe(() => {
      this.resendSystemTypes();
    });
  }

  set system(s){
    this._system = s;
  }

  get system(){
    return JSON.parse(JSON.stringify(this._system));
  }

  /**
   * Gets all ObjectTypes
   *
   * @returns An array containing all object types
   */
  public getObjectTypes(): ObjectType[] {
    return this.system.types;
  }

  /**
   * Gets an ObjectType by name.
   *
   * @param objectTypeName The name of the object type
   * @returns the ObjectType matching the given name
   */
  public getObjectType(objectTypeName: string): ObjectType {
    return this.system.types.find(t => t.name === objectTypeName);
  }

  /**
   * Get form elements from form model. This is useful if you have to fetch them
   * for a special situation like SEARCH
   * @param objectTypeName ObjectType to fetch elements for
   * @param situation Form model situation to be fetched
   * @param isContextType Flag indicating that the form model should be fetched for a context mode
   */
  getFormElementsFromFormModel(objectTypeName: string, situation: string, isContextType?: boolean): Observable<any[]> {
    return this.getObjectTypeForm(objectTypeName, situation, isContextType ? 'CONTEXT' : null).pipe(
      switchMap(model => {
        const elements = [];
        this.processFormModelElements(model, elements);
        return of(elements);
    }))
  }

  private processFormModelElements(model: any, elements: any[]) {
    model.elements.forEach(e => {
      if(e.type !== "o2mGroup" && e.type !== "o2mGroupStack") {
        elements.push(e);
      } else if(e.elements && e.elements.length) {
        this.processFormModelElements(e, elements);
      }
    })
  }

  /**
   * Checks whether or not the given type implements a given supertype
   * @param type Type to be checked
   * @param superTypeName Name of the supertype
   */
  public implementsType(type: ObjectType, superTypeName: string): boolean {
    return type.name === superTypeName || (type.implements && type.implements.indexOf(superTypeName) !== -1);
  }

  /**
   * Gets a codesystem
   *
   * @param id The codesystems id
   * @returns The codesystem object matching the given id
   */
  public getCodesystem(id: string): ICodeSystem {
    return this.system.codesystems.find(t => t.id === id || t.name === id);
  }

  /**
   * Get the form model of an object type.
   *
   * @param objectTypeName The object type name
   * @param situation The form situation to be fetched
   * @param mode Form mode to fetch (e.g. CONTEXT)
   * @returns The object type form model
   */
  public getObjectTypeForm(objectTypeName: string, situation: string, mode?: string): Observable<any> {

    /** check if we have a cached form first */
    let cachedForm;

    let i = 0;
    while (!cachedForm && i < this.objectTypeForms.length) {
      if (this.objectTypeForms[i].name === objectTypeName &&
        this.objectTypeForms[i].mode === mode &&
        this.objectTypeForms[i].situation === situation) {
        cachedForm = this.objectTypeForms[i];
      }
      i++;
    }

    if (cachedForm) {
      /** return a clone of the cached model as otherwise model changes will be added to the chached model */
      return of(cloneDeep(cachedForm));
    } else {

      let uri = `/ui/form/${objectTypeName}?situation=${situation}`;
      uri += !!mode ? `&formmode=${mode}` : '';

      /** fetch and cache the requested form, if no cached version was found */
      return this.backend.getViaTempCache(uri, () => this.backend
        .getJson(uri)
        .pipe(
          map(res => {
            if (objectTypeName === 'sysdmscontenttemplate') {
              res.elements[0].elements.forEach(el => {
                el.label = this.translate.instant('eo.global.templateParam.' + el.name);
              });
            }
            return res;
          }),
          tap((model) => this.objectTypeForms.push(cloneDeep(model)))
        ));
    }
  }

  /**
   * Fetches the backends system definition and updates system$ Observable.
   * Subscribe to the system$ observable instead of calling this function, otherwise you'll trigger fetching the
   * system definition every time.
   *
   * @param user The user to load the system definition for
   * @returns true when successfull
   */
  public getSystemDefinition(user: EoUser): Observable<boolean> {

    this.user = user;
    // todo: temporary: OrgChanges could not be recognized but affect object definition
    return this.fetchSystemDefinition(user);

    // todo: enable again when OrgChanges are recognizable (DO NOT DELETE!)
    // // is there a cached version
    // return this.appCache
    //   .getItem(this.appCache.SYSTEM_DEFINITION)
    //   .catch((error) => {
    //     this.logger.error('Error fetching cached version of system definition.', error);
    //     return this.fetchSystemDefinition(user);
    //   })
    //   .flatMap((cachedSystemDefinition: any) => {
    //
    //     // yes? then check if it's up to date
    //     if (cachedSystemDefinition) {
    //
    //       if (
    //         user.schema.version !== cachedSystemDefinition.info.version ||
    //         user.id !== cachedSystemDefinition.info.user ||
    //         user.getSchemaLocale() !== cachedSystemDefinition.info.locale
    //       ) {
    //         return this.fetchSystemDefinition(user);
    //       } else {
    //         // cache is up to date. return the cached one
    //         this.logger.debug('System definition is up to date, using cached version.', cachedSystemDefinition);
    //         this.system = cachedSystemDefinition;
    //         this.systemSource.next(this.system);
    //         return of(true);
    //       }
    //     } else {
    //       // no cached systemDefinition found
    //       return this.fetchSystemDefinition(user);
    //     }
    //   });
  }

  /**
   * Creates a value depending on a given Type
   *
   * @param string valueType
   * @returns any
   */
  public getDefaultValue(valueType: string): any {
    let defaultValue;
    switch (valueType) {
      case 'CURRENT_USER': {
        defaultValue = this.user.name;
        break;
      }
      case 'CURRENT_USER_NAME': {
        defaultValue = this.user.title;
        break;
      }
      case 'CURRENT_DATETIME': {
        defaultValue = new Date();
        break;
      }
      case 'CURRENT_DATE': {
        defaultValue = moment().startOf('day').format('yyyy-MM-DD');
        break;
      }
      case 'YEAR': {
        defaultValue = moment().year();
        break;
      }
      case 'MONTH': {
        defaultValue = moment().month() + 1;
        break;
      }
      case 'DAY': {
        defaultValue = moment().date();
        break;
      }
      case 'HOUR': {
        defaultValue = moment().hour();
        break;
      }
      case 'MINUTE': {
        defaultValue = moment().minute();
        break;
      }
      case 'SECOND': {
        defaultValue = moment().second();
        break;
      }
      case 'WEEK_OF_YEAR': {
        defaultValue = moment().isoWeek();
        break;
      }
      case 'FIRST_DAY_OF_WEEK': {
        defaultValue = moment().startOf('isoWeek').toDate();
        break;
      }
      case 'FIRST_DAY_OF_MONTH': {
        defaultValue = moment().startOf('month').toDate();
        break;
      }
      case 'FIRST_DAY_OF_YEAR': {
        defaultValue = moment().startOf('year').toDate();
        break;
      }
    }

    return defaultValue;
  }

  /**
   * Fetches the system definition from the server. Provided params are used for storing the
   * recent version in cache.
   *
   * @param user The user to fetch the system definition for
   * @return boolean
   */
  fetchSystemDefinition(user: EoUser): Observable<boolean> {

    const fetches = [
      this.backend.getJson('/system/type/list?elements=true&basetypes=true'),
      this.backend.getJson('/system/cs/list?elements=true')
    ];

    return observableForkJoin(fetches)
      .pipe(
        catchError(Utils.catch((error) => {
          this.logger.error('Error fetching recent version of system definition from server.', error);
          this.systemSource.error('Error fetching recent version of system definition from server.');
        })),
        map((data) => {

          this.objectTypeForms = [];
          const system = {
            /**
             * info about the current system definition
             */
            info: {
              user: user.id,
              locale: user.getSchemaLocale(),
              version: user.schema.version
            },
            /**
             * supported backend locales
             */
            locales: user.schema.supportedLocales,
            /**
             * object type definitions
             */
            types: [],
            /**
             * codesystems cache
             */
            codesystems: []
          };

          const types = data[0];
          system.types = types.map(t => new ObjectType(t));
          system.codesystems = data[1];
          const commonEntries = system.codesystems.find(c => c.id === 'B0E3563DC67140D6984A368095DE0F0B')?.entries?.find(e => e.data === 'group_common');
          if (commonEntries) {
            const translatedText = this.translate.instant('eo.quicksearch.result.group.global');
            commonEntries.defaultrepresentation = translatedText;
            commonEntries.label = translatedText;
            commonEntries.subentries.forEach(sub => {
              sub.defaultrepresentation = translatedText + ' / ' + sub.label;
              sub.label = sub.defaultrepresentation;
            });
          }

          this.system = system;
          this.systemSource.next(system);
          this.logger.debug('Fetched new version of system definition (user: ' + user.id + ', version: ' + user.schema.version + ').');
          this.appCache
            .setItem(this.appCache.SYSTEM_DEFINITION, system)
            .subscribe(() => {
              this.logger.debug('Cached recent version');
            }, Utils.logError(null, 'Error caching recent version of system definition.'));

          return true;
        }));
  }

  /**
   * Retrieve an organization object by its ID
   * @param id ID of org object
   */
  getOrganizationObjectById(id: string): Observable<any> {
    return this.backend.getJson(`/organization/id/${id}`)
  }

  /**
   * Fetches the organization object for a given name.
   *
   * @param name The name to fetch object for
   * @returns
   */
  getOrganizationObject(name: string): Observable<any> {
    return this.getOrganizationObjects([name]).pipe(map(res => res[0]));
  }

  /**
   * Fetches a collection of organization objects
   *
   * @param names Array of names to fetch objects for
   * @returns A Array of Organization Objects
   */
  getOrganizationObjects(names: string[]): Observable<IOrganizationObjects[]> {
    const toFetch: Observable<IOrganizationObjects>[] = names.map(name => this.backend.getJson(`/organization/name/${name}`).pipe(catchError(error => of({id: name, active: false}))));
    return observableForkJoin(toFetch);
  }

  /**
   * Fetches a collection of organization roles
   *
   * @return A Array of Organization Roles
   */
  getRoles(): Observable<OrgRole[]> {
    if (this.cachedRoles.length) {
      return of(this.cachedRoles);
    } else {
      return this.backend
        .get('/organization/role')
        .pipe(
          map(o => o as OrgRole[]),
          tap(roles => (this.cachedRoles = roles as OrgRole[]))
        );
    }
  }

  /**
   * Re-emits the current system types to trigger system events.
   * Updating the translations of system types for 'sysdmscontenttemplate'.
   *
   * @remarks
   * This method is intended to be used internally within the service to ensure that system  type translations are kept up to date.
   *
   */
  private resendSystemTypes(): void {
    if (this._system) {
      this.systemSource.next(this._system);
    }
  }
}

results matching ""

    No results matching ""