"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.ObjectTreesApplication = void 0;
const authentication_1 = require("@loopback/authentication");
const authentication_jwt_1 = require("@loopback/authentication-jwt");
const authorization_1 = require("@loopback/authorization");
const core_1 = require("@loopback/core");
const repository_1 = require("@loopback/repository");
const rest_1 = require("@loopback/rest");
const rest_explorer_1 = require("@loopback/rest-explorer");
const lodash_1 = require("lodash");
const application_component_1 = require("./application.component");
const boot_component_1 = require("./boot.component");
const constants_1 = require("./constants");
const object_node_controller_1 = require("./controllers/object-node.controller");
const object_tree_controller_1 = require("./controllers/object-tree.controller");
const object_type_controller_1 = require("./controllers/object-type.controller");
const ping_controller_1 = require("./controllers/ping.controller");
const user_controller_1 = require("./controllers/user.controller");
const db_datasource_1 = require("./datasources/db.datasource");
const extension_description_1 = require("./integration/extension-description");
const constants_2 = require("./interceptors/constants");
const content_text_model_1 = require("./models/content-text.model");
const object_node_model_1 = require("./models/object-node.model");
const object_sub_type_model_1 = require("./models/object-sub-type.model");
const content_file_repository_1 = require("./repositories/content-file.repository");
const content_text_repository_1 = require("./repositories/content-text.repository");
const object_node_repository_1 = require("./repositories/object-node.repository");
const object_sub_type_repository_1 = require("./repositories/object-sub-type.repository");
const object_type_repository_1 = require("./repositories/object-type.repository");
const sequence_1 = require("./sequence");
const access_rights_provider_1 = require("./services/access-rights/access-rights.provider");
const action_entity_provider_1 = require("./services/action-entity/action-entity.provider");
const app_authorization_service_1 = require("./services/app-authorization.service");
const application_service_1 = require("./services/application.service");
const content_entity_provider_1 = require("./services/content-entity/content-entity.provider");
const content_entity_service_1 = require("./services/content-entity/content-entity.service");
const entity_definition_provider_1 = require("./services/entity-definition/entity-definition.provider");
const transient_uri_reference_provider_1 = require("./services/inside-rest/transient-uri-reference.provider");
const object_node_content_service_1 = require("./services/object-node/object-node-content.service");
const object_node_service_1 = require("./services/object-node/object-node.service");
const object_tree_provider_1 = require("./services/object-tree/object-tree.provider");
const object_tree_service_1 = require("./services/object-tree/object-tree.service");
const object_type_service_1 = require("./services/object-type.service");
const root_config_provider_1 = require("./services/root-config/root-config.provider");
const transient_entity_provider_1 = require("./services/transient-entity/transient-entity.provider");
const uri_complete_provider_1 = require("./services/uri-complete/uri-complete.provider");
const user_authentication_service_1 = require("./services/user-authentication.service");
/*export abstract class ObjectTreesApplicationInterface extends RestApplication {
  public abstract async boot(): Promise<void>;
  public bootOptions: BootOptions;
  public abstract dataSource(dataSource: any, nameOrOptions?: any): any;
  public abstract model(modelClass: any): any;
  public abstract repository(repoClass: any, nameOrOptions?: any): any;
  public abstract service(cls: any, nameOrOptions?: any): any;
}*/
class ObjectTreesApplication extends rest_1.RestApplication {
    constructor(config, parent) {
        super(config, parent);
        this.interceptorDescriptions = {};
        this.controllersDescriptions = [];
        this.extensionProviders = [];
        this.staticDir = {};
        const app = this;
        console.log('Init application...');
        // Set up the custom sequence
        app.sequence(sequence_1.MySequence);
        // Customize @loopback/rest-explorer configuration here
        app.configure(rest_explorer_1.RestExplorerBindings.COMPONENT).to({
            path: '/explorer',
        });
        app.component(rest_explorer_1.RestExplorerComponent);
        //    app.configureFileUpload(options.fileStorageDirectory);
        app.bind(rest_1.RestBindings.REQUEST_BODY_PARSER_OPTIONS).to({ limit: '500mb' });
        // Customize @loopback/boot Boot Conventions here
        app.bootOptions = {
            controllers: {
                // Customize ControllerBoot Conventions here
                dirs: [],
                extensions: ['.controller.js'],
                nested: false,
            },
            repositories: {
                dirs: [],
                extensions: ['.repository.js'],
                nested: false,
            },
        };
        app
            .bind(core_1.ContextBindings.GLOBAL_INTERCEPTOR_ORDERED_GROUPS)
            .to(constants_2.INTERCEPTORS_ORDER);
        app.controller(object_node_controller_1.ObjectNodeController);
        app.controller(object_tree_controller_1.ObjectTreeController);
        app.controller(object_type_controller_1.ObjectTypeController);
        app.controller(ping_controller_1.PingController);
        app.controller(user_controller_1.UserController);
        // Bind datasource
        app.dataSource(db_datasource_1.DbDataSource, authentication_jwt_1.UserServiceBindings.DATASOURCE_NAME);
        app
            .dataSource(db_datasource_1.DbDataSource, constants_1.DATASTORE_DB.replace('datasources.', ''))
            .inScope(core_1.BindingScope.SINGLETON);
        app.model(content_text_model_1.ContentText);
        app.model(object_node_model_1.ObjectNode);
        app.model(object_sub_type_model_1.ObjectSubType);
        app.model(repository_1.ObjectType);
        app.repository(content_file_repository_1.ContentFileRepository);
        app.repository(content_text_repository_1.ContentTextRepository);
        app.repository(object_node_repository_1.ObjectNodeRepository);
        app.repository(object_sub_type_repository_1.ObjectSubTypeRepository);
        app.repository(object_type_repository_1.ObjectTypeRepository);
        // ------ ADD SNIPPET AT THE BOTTOM ---------
        // Mount authentication system
        app.component(authentication_1.AuthenticationComponent);
        // Mount jwt component
        app.component(authentication_jwt_1.JWTAuthenticationComponent);
        // Bind user and credentials repository
        app
            .bind(authentication_jwt_1.UserServiceBindings.USER_SERVICE)
            .toClass(user_authentication_service_1.UserAuthenticationService);
        // Bind datasource
        //  app.dataSource(DbDataSource, UserServiceBindings.DATASOURCE_NAME);
        // ------------- END OF SNIPPET -------------
        const authorizationOptions = {
            precedence: authorization_1.AuthorizationDecision.DENY,
            defaultDecision: authorization_1.AuthorizationDecision.DENY,
        };
        app.configure(authorization_1.AuthorizationBindings.COMPONENT).to(authorizationOptions);
        app.component(authorization_1.AuthorizationComponent);
        app
            .bind(constants_1.AUTHORIZATION_SERVICE)
            .toProvider(app_authorization_service_1.AppAuthorizationProvider)
            .tag(authorization_1.AuthorizationTags.AUTHORIZER);
        app.bind(rest_1.RestBindings.ERROR_WRITER_OPTIONS).to({
            safeFields: ['errorCode', 'errorArgs', 'name'],
        });
        app.component(application_component_1.ApplicationComponent);
        if (!config) {
            config = {};
        }
        if (!config.extensions) {
            config.extensions = [];
        }
        config.extensions.unshift(transient_entity_provider_1.TransientEntityProvider);
        config.extensions.unshift(entity_definition_provider_1.EntityDefinitionProvider);
        config.extensions.unshift(access_rights_provider_1.AccessRightsProvider);
        config.extensions.unshift(content_entity_provider_1.ContentEntityCoreProvider);
        config.extensions.unshift(object_tree_provider_1.ObjectTreeProvider);
        config.extensions.unshift(action_entity_provider_1.ActionEntityProvider);
        config.extensions.push(uri_complete_provider_1.UriCompleteProvider);
        config.extensions.push(root_config_provider_1.RootConfigProvider);
        config.extensions.push(transient_uri_reference_provider_1.TransientUriReferenceProvider);
        this.addProviders(app, config.extensions);
        this.config = config;
        console.log('Application initialized !');
    }
    addStaticDir(basePath, dirName) {
        this.staticDir[basePath] = dirName;
    }
    getStaticDirs() {
        return this.staticDir;
    }
    addProviders(app, extensions, addedProviders = []) {
        for (const objectTypeProvider of extensions) {
            const provider = new objectTypeProvider(app);
            if (!addedProviders.includes(provider.name)) {
                addedProviders.push(provider.name);
                this.addProviders(app, provider.requiredProviders, addedProviders);
                this.extensionProviders.push(provider);
            }
        }
    }
    addController(providerId, controller) {
        this.controller(controller.controllerCtor, controller.nameOrOptions);
        this.controllersDescriptions.push(lodash_1.merge({ providerId, controllerId: controller.controllerCtor.name }, controller.description));
    }
    addInterceptor(providerId, interceptorProvider) {
        this.interceptor(interceptorProvider.interceptor, lodash_1.merge({}, {
            name: interceptorProvider.id,
            global: true,
            group: interceptorProvider.id,
        }, interceptorProvider.nameOrOptions
            ? interceptorProvider.nameOrOptions
            : {}));
        this.interceptorDescriptions[interceptorProvider.id] = lodash_1.merge({ providerId }, interceptorProvider.description);
    }
    async bootObjectTrees() {
        const app = this;
        console.log('Boot application...');
        await app.boot();
        app.service(application_service_1.ApplicationService, { defaultScope: core_1.BindingScope.SINGLETON });
        (await app.getService(application_service_1.ApplicationService)).app = app;
        app.service(content_entity_service_1.ContentEntityService, { defaultScope: core_1.BindingScope.SINGLETON });
        await app.getService(content_entity_service_1.ContentEntityService);
        app.service(object_type_service_1.ObjectTypeService, { defaultScope: core_1.BindingScope.SINGLETON });
        await app.getService(object_type_service_1.ObjectTypeService);
        const appCtx = await app.getService(application_service_1.ApplicationService);
        const objectTypeService = await app.getService(object_type_service_1.ObjectTypeService);
        await objectTypeService.cleanWhenReboot();
        app.service(object_node_service_1.ObjectNodeService, { defaultScope: core_1.BindingScope.SINGLETON });
        await app.getService(object_node_service_1.ObjectNodeService);
        app.service(object_node_content_service_1.ObjectNodeContentService, {
            defaultScope: core_1.BindingScope.SINGLETON,
        });
        await app.getService(object_node_content_service_1.ObjectNodeContentService);
        app.service(object_tree_service_1.ObjectTreeService, { defaultScope: core_1.BindingScope.SINGLETON });
        await app.getService(object_tree_service_1.ObjectTreeService);
        for (const provider of this.extensionProviders) {
            await provider.setContext(appCtx);
        }
        for (const provider of this.extensionProviders) {
            await provider.beforeBoot();
        }
        for (const provider of this.extensionProviders) {
            await provider.migrateBeforeBoot();
        }
        for (const provider of this.extensionProviders) {
            await provider.boot();
        }
        app.component(boot_component_1.ObjectTreesBootComponent);
        console.log('Boot up !');
        appCtx.configSummary = await this.calculateBootSummary(app);
        for (const treatment of appCtx.configSummary.descriptionLines) {
            console.log(treatment);
        }
    }
    async calculateBootSummary(app) {
        var _a, _b, _c, _d;
        const configSummary = new extension_description_1.TreatmentDescription('CoreProvider', ObjectTreesApplication.name, 'Boot summary:');
        //    for (const interceptorId of Object.keys(this.interceptorDescriptions)
        const interceptors = app
            .getBinding(core_1.ContextBindings.GLOBAL_INTERCEPTOR_ORDERED_GROUPS)
            .getValue(app);
        const preTreatmentDescription = new extension_description_1.TreatmentDescription('CoreProvider', ObjectTreesApplication.name, 'Treatments on incoming request:');
        // eslint-disable-next-line @typescript-eslint/prefer-for-of
        for (let index = 0; index < interceptors.length; index++) {
            if (interceptors[index] in this.interceptorDescriptions &&
                this.interceptorDescriptions[interceptors[index]].preTreatment) {
                const treatment = new extension_description_1.TreatmentDescription(this.interceptorDescriptions[interceptors[index]].providerId, interceptors[index], (_a = this.interceptorDescriptions[interceptors[index]].preTreatment) === null || _a === void 0 ? void 0 : _a.description);
                for (const serviceName of (_b = this.interceptorDescriptions[interceptors[index]].preTreatment) === null || _b === void 0 ? void 0 : _b.services) {
                    treatment.runnerId += ' and ' + serviceName;
                    const service = await this.getService({ name: serviceName });
                    if (service.getPreTreatmentDescription) {
                        treatment.subTreatments.push(...service.getPreTreatmentDescription());
                    }
                }
                preTreatmentDescription.subTreatments.push(treatment);
            }
        }
        configSummary.subTreatments.push(preTreatmentDescription);
        for (const description of this.controllersDescriptions) {
            const treatment = new extension_description_1.TreatmentDescription(description.providerId, description.controllerId, description.description);
            for (const serviceName of description.services) {
                treatment.runnerId += ' and ' + serviceName;
                const service = await this.getService({ name: serviceName });
                if (service.getTreatmentDescription) {
                    treatment.subTreatments.push(...service.getTreatmentDescription());
                }
            }
            configSummary.subTreatments.push(treatment);
        }
        /*
        const treatmentDescription = new TreatmentDescription(
          'CoreProvider',
          ObjectTreesApplication.name,
          'Request extended actions',
        );
        for (const treatment of (
          await this.getService<ActionEntityService>(ActionEntityService)
        ).getTreatmentDescription()) {
          treatmentDescription.subTreatments.push(treatment);
        }
        configSummary.subTreatments.push(treatmentDescription);*/
        const postTreatmentDescriptions = new extension_description_1.TreatmentDescription('CoreProvider', ObjectTreesApplication.name, 'Treatments on returned Entity(ies):');
        // eslint-disable-next-line @typescript-eslint/prefer-for-of
        for (let index = interceptors.length - 1; index >= 0; index--) {
            if (interceptors[index] in this.interceptorDescriptions &&
                this.interceptorDescriptions[interceptors[index]].postTreatment) {
                const treatment = new extension_description_1.TreatmentDescription(this.interceptorDescriptions[interceptors[index]].providerId, interceptors[index], (_c = this.interceptorDescriptions[interceptors[index]].postTreatment) === null || _c === void 0 ? void 0 : _c.description);
                for (const serviceName of (_d = this.interceptorDescriptions[interceptors[index]].postTreatment) === null || _d === void 0 ? void 0 : _d.services) {
                    treatment.runnerId += ' and ' + serviceName;
                    const service = await this.getService({ name: serviceName });
                    if (service.getPostTreatmentDescription) {
                        treatment.subTreatments.push(...service.getPostTreatmentDescription());
                    }
                }
                postTreatmentDescriptions.subTreatments.push(treatment);
            }
        }
        configSummary.subTreatments.push(postTreatmentDescriptions);
        return configSummary;
    }
    async getService(t) {
        let name = t.name;
        if (name.endsWith('Provider')) {
            name = name.substr(0, name.length - 'Provider'.length);
        }
        return this.get('services.' + name);
    }
}
exports.ObjectTreesApplication = ObjectTreesApplication;
//# sourceMappingURL=application.js.map