mirror of
https://github.com/bigcapitalhq/bigcapital.git
synced 2026-02-16 21:00:31 +00:00
refactoring: retrieve resources fields.
fix: issue in create a new custom view.
This commit is contained in:
@@ -1,4 +1,5 @@
|
||||
import { Inject, Service } from 'typedi';
|
||||
import { omit } from 'lodash';
|
||||
import TenancyService from 'services/Tenancy/TenancyService';
|
||||
import { IAccountsTypesService, IAccountType } from 'interfaces';
|
||||
|
||||
@@ -12,8 +13,17 @@ export default class AccountsTypesService implements IAccountsTypesService{
|
||||
* @param {number} tenantId -
|
||||
* @return {Promise<IAccountType>}
|
||||
*/
|
||||
getAccountsTypes(tenantId: number): Promise<IAccountType> {
|
||||
async getAccountsTypes(tenantId: number): Promise<IAccountType> {
|
||||
const { accountTypeRepository } = this.tenancy.repositories(tenantId);
|
||||
return accountTypeRepository.all();
|
||||
const { AccountType } = this.tenancy.models(tenantId);
|
||||
const { __ } = this.tenancy.i18n(tenantId);
|
||||
|
||||
const allAccountsTypes = await accountTypeRepository.all();
|
||||
|
||||
return allAccountsTypes.map((_accountType: IAccountType) => ({
|
||||
id: _accountType.id,
|
||||
label: __(AccountType.labels[_accountType.key]),
|
||||
...omit(_accountType, ['id']),
|
||||
}));
|
||||
}
|
||||
}
|
||||
@@ -1,78 +1,71 @@
|
||||
import { Service, Inject } from 'typedi';
|
||||
import { camelCase, upperFirst } from 'lodash'
|
||||
import { camelCase, upperFirst } from 'lodash';
|
||||
import pluralize from 'pluralize';
|
||||
import { IModel } from 'interfaces';
|
||||
import resourceFieldsKeys from 'data/ResourceFieldsKeys';
|
||||
import {
|
||||
getModelFields,
|
||||
} from 'lib/ViewRolesBuilder'
|
||||
import TenancyService from 'services/Tenancy/TenancyService';
|
||||
import { ServiceError } from 'exceptions';
|
||||
|
||||
const ERRORS = {
|
||||
RESOURCE_MODEL_NOT_FOUND: 'RESOURCE_MODEL_NOT_FOUND',
|
||||
};
|
||||
|
||||
@Service()
|
||||
export default class ResourceService {
|
||||
@Inject()
|
||||
tenancy: TenancyService;
|
||||
|
||||
/**
|
||||
*
|
||||
* @param {string} resourceName
|
||||
*/
|
||||
getResourceFieldsRelations(modelName: string) {
|
||||
const fieldsRelations = resourceFieldsKeys[modelName];
|
||||
|
||||
if (!fieldsRelations) {
|
||||
throw new Error('Fields relation not found in thte given resource model.');
|
||||
}
|
||||
return fieldsRelations;
|
||||
}
|
||||
|
||||
/**
|
||||
* Transform resource to model name.
|
||||
* @param {string} resourceName
|
||||
*/
|
||||
private resourceToModelName(resourceName: string): string {
|
||||
return upperFirst(camelCase(resourceName));
|
||||
return upperFirst(camelCase(pluralize.singular(resourceName)));
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve model from resource name in specific tenant.
|
||||
* Retrieve model fields.
|
||||
* @param {number} tenantId
|
||||
* @param {string} resourceName
|
||||
* @param {IModel} Model
|
||||
*/
|
||||
public getModel(tenantId: number, resourceName: string) {
|
||||
const models = this.tenancy.models(tenantId);
|
||||
const modelName = this.resourceToModelName(resourceName);
|
||||
private getModelFields(tenantId: number, Model: IModel) {
|
||||
const { __ } = this.tenancy.i18n(tenantId);
|
||||
const fields = getModelFields(Model);
|
||||
|
||||
return models[modelName];
|
||||
}
|
||||
|
||||
getModelFields(Model: IModel) {
|
||||
const fields = Object.keys(Model.fields);
|
||||
|
||||
return fields.sort((a, b) => {
|
||||
if (a < b) { return -1; }
|
||||
if (a > b) { return 1; }
|
||||
return 0;
|
||||
});
|
||||
return fields.map((field) => ({
|
||||
label: __(field.label, field.label),
|
||||
key: field.key,
|
||||
dataType: field.columnType,
|
||||
}));
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* Retrieve resource fields from resource model name.
|
||||
* @param {string} resourceName
|
||||
*/
|
||||
getResourceFields(Model: IModel) {
|
||||
console.log(Model);
|
||||
public getResourceFields(tenantId: number, modelName: string) {
|
||||
const resourceModel = this.getResourceModel(tenantId, modelName);
|
||||
|
||||
if (Model.resourceable) {
|
||||
return this.getModelFields(Model);
|
||||
}
|
||||
return [];
|
||||
return this.getModelFields(tenantId, resourceModel);
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param {string} resourceName
|
||||
* Retrieve resource model object.
|
||||
* @param {number} tenantId -
|
||||
* @param {string} inputModelName -
|
||||
*/
|
||||
getResourceColumns(Model: IModel) {
|
||||
if (Model.resourceable) {
|
||||
return this.getModelFields(Model);
|
||||
public getResourceModel(tenantId: number, inputModelName: string) {
|
||||
const modelName = this.resourceToModelName(inputModelName);
|
||||
const Models = this.tenancy.models(tenantId);
|
||||
|
||||
if (!Models[modelName]) {
|
||||
throw new ServiceError(ERRORS.RESOURCE_MODEL_NOT_FOUND);
|
||||
}
|
||||
return [];
|
||||
if (!Models[modelName].resourceable) {
|
||||
throw new ServiceError(ERRORS.RESOURCE_MODEL_NOT_FOUND);
|
||||
}
|
||||
return Models[modelName];
|
||||
}
|
||||
}
|
||||
@@ -6,7 +6,11 @@ import {
|
||||
IViewDTO,
|
||||
IView,
|
||||
IViewEditDTO,
|
||||
IModel,
|
||||
IViewColumnDTO,
|
||||
IViewRoleDTO,
|
||||
} from 'interfaces';
|
||||
import { getModelFieldsKeys } from 'lib/ViewRolesBuilder';
|
||||
import TenancyService from 'services/Tenancy/TenancyService';
|
||||
import ResourceService from "services/Resource/ResourceService";
|
||||
import { validateRolesLogicExpression } from 'lib/ViewRolesBuilder';
|
||||
@@ -37,14 +41,14 @@ export default class ViewsService implements IViewsService {
|
||||
* @param {number} tenantId -
|
||||
* @param {string} resourceModel -
|
||||
*/
|
||||
public async listResourceViews(tenantId: number, resourceModel: string): Promise<IView[]> {
|
||||
this.logger.info('[views] trying to retrieve resource views.', { tenantId, resourceModel });
|
||||
public async listResourceViews(tenantId: number, resourceModelName: string): Promise<IView[]> {
|
||||
this.logger.info('[views] trying to retrieve resource views.', { tenantId, resourceModelName });
|
||||
|
||||
// Validate the resource model name is valid.
|
||||
this.getResourceModelOrThrowError(tenantId, resourceModel);
|
||||
const resourceModel = this.getResourceModelOrThrowError(tenantId, resourceModelName);
|
||||
|
||||
const { viewRepository } = this.tenancy.repositories(tenantId);
|
||||
return viewRepository.allByResource(resourceModel);
|
||||
return viewRepository.allByResource(resourceModel.name);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -53,7 +57,7 @@ export default class ViewsService implements IViewsService {
|
||||
* @param {IViewRoleDTO[]} viewRoles
|
||||
*/
|
||||
private validateResourceRolesFieldsExistance(ResourceModel: IModel, viewRoles: IViewRoleDTO[]) {
|
||||
const resourceFieldsKeys = this.resourceService.getResourceFields(ResourceModel);
|
||||
const resourceFieldsKeys = getModelFieldsKeys(ResourceModel);
|
||||
|
||||
const fieldsKeys = viewRoles.map(viewRole => viewRole.fieldKey);
|
||||
const notFoundFieldsKeys = difference(fieldsKeys, resourceFieldsKeys);
|
||||
@@ -70,7 +74,7 @@ export default class ViewsService implements IViewsService {
|
||||
* @param {IViewColumnDTO[]} viewColumns
|
||||
*/
|
||||
private validateResourceColumnsExistance(ResourceModel: IModel, viewColumns: IViewColumnDTO[]) {
|
||||
const resourceFieldsKeys = this.resourceService.getResourceColumns(ResourceModel);
|
||||
const resourceFieldsKeys = getModelFieldsKeys(ResourceModel);
|
||||
|
||||
const fieldsKeys = viewColumns.map((viewColumn: IViewColumnDTO) => viewColumn.fieldKey);
|
||||
const notFoundFieldsKeys = difference(fieldsKeys, resourceFieldsKeys);
|
||||
@@ -115,12 +119,7 @@ export default class ViewsService implements IViewsService {
|
||||
* @param {number} resourceModel
|
||||
*/
|
||||
private getResourceModelOrThrowError(tenantId: number, resourceModel: string): IModel {
|
||||
const ResourceModel = this.resourceService.getModel(tenantId, resourceModel);
|
||||
|
||||
if (!ResourceModel || !ResourceModel.resourceable) {
|
||||
throw new ServiceError(ERRORS.RESOURCE_MODEL_NOT_FOUND);
|
||||
}
|
||||
return ResourceModel;
|
||||
return this.resourceService.getResourceModel(tenantId, resourceModel);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -137,6 +136,8 @@ export default class ViewsService implements IViewsService {
|
||||
notViewId?: number
|
||||
): void {
|
||||
const { View } = this.tenancy.models(tenantId);
|
||||
|
||||
this.logger.info('[views] trying to validate view name uniqiness.', { tenantId, resourceModel, viewName });
|
||||
const foundViews = await View.query()
|
||||
.where('resource_model', resourceModel)
|
||||
.where('name', viewName)
|
||||
@@ -165,6 +166,8 @@ export default class ViewsService implements IViewsService {
|
||||
* ---------
|
||||
* @param {number} tenantId - Tenant id.
|
||||
* @param {IViewDTO} viewDTO - View DTO.
|
||||
*
|
||||
* @return {Promise<IView>}
|
||||
*/
|
||||
public async newView(tenantId: number, viewDTO: IViewDTO): Promise<IView> {
|
||||
const { viewRepository } = this.tenancy.repositories(tenantId);
|
||||
@@ -187,6 +190,7 @@ export default class ViewsService implements IViewsService {
|
||||
throw new ServiceError(ERRORS.LOGIC_EXPRESSION_INVALID);
|
||||
}
|
||||
// Save view details.
|
||||
this.logger.info('[views] trying to insert to storage.', { tenantId, viewDTO })
|
||||
const view = await viewRepository.insert({
|
||||
predefined: false,
|
||||
name: viewDTO.name,
|
||||
@@ -216,7 +220,7 @@ export default class ViewsService implements IViewsService {
|
||||
* @param {IViewEditDTO}
|
||||
*/
|
||||
public async editView(tenantId: number, viewId: number, viewEditDTO: IViewEditDTO): Promise<void> {
|
||||
const { View } = this.tenancy.models(tenantId);
|
||||
const { viewRepository } = this.tenancy.repositories(tenantId);
|
||||
this.logger.info('[view] trying to edit custom view.', { tenantId, viewId });
|
||||
|
||||
// Retrieve view details or throw not found error.
|
||||
@@ -229,22 +233,23 @@ export default class ViewsService implements IViewsService {
|
||||
await this.validateViewNameUniquiness(tenantId, view.resourceModel, viewEditDTO.name, viewId);
|
||||
|
||||
// Validate the given fields keys exist on the storage.
|
||||
this.validateResourceRolesFieldsExistance(ResourceModel, view.roles);
|
||||
this.validateResourceRolesFieldsExistance(ResourceModel, viewEditDTO.roles);
|
||||
|
||||
// Validate the given columnable fields keys exists on the storage.
|
||||
this.validateResourceColumnsExistance(ResourceModel, view.columns);
|
||||
this.validateResourceColumnsExistance(ResourceModel, viewEditDTO.columns);
|
||||
|
||||
// Validates the view conditional logic expression.
|
||||
if (!validateRolesLogicExpression(viewEditDTO.logicExpression, viewEditDTO.roles)) {
|
||||
throw new ServiceError(ERRORS.LOGIC_EXPRESSION_INVALID);
|
||||
}
|
||||
// Save view details.
|
||||
await View.query()
|
||||
.where('id', view.id)
|
||||
.patch({
|
||||
name: viewEditDTO.name,
|
||||
roles_logic_expression: viewEditDTO.logicExpression,
|
||||
});
|
||||
// Update view details.
|
||||
await viewRepository.update(tenantId, viewId, {
|
||||
predefined: false,
|
||||
name: viewEditDTO.name,
|
||||
rolesLogicExpression: viewEditDTO.logicExpression,
|
||||
roles: viewEditDTO.roles,
|
||||
columns: viewEditDTO.columns,
|
||||
})
|
||||
this.logger.info('[view] edited successfully.', { tenantId, viewId });
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user