mirror of
https://github.com/bigcapitalhq/bigcapital.git
synced 2026-02-21 07:10:33 +00:00
refactoring: retrieve resources fields.
fix: issue in create a new custom view.
This commit is contained in:
34
client/src/components/ErrorBoundary/index.js
Normal file
34
client/src/components/ErrorBoundary/index.js
Normal file
@@ -0,0 +1,34 @@
|
|||||||
|
import React from 'react';
|
||||||
|
import PropTypes from 'prop-types';
|
||||||
|
|
||||||
|
function ErrorBoundary({
|
||||||
|
error,
|
||||||
|
errorInfo,
|
||||||
|
children
|
||||||
|
}) {
|
||||||
|
|
||||||
|
if (errorInfo) {
|
||||||
|
return (
|
||||||
|
<div>
|
||||||
|
<h2>Something went wrong.</h2>
|
||||||
|
|
||||||
|
<details style={{ whiteSpace: 'pre-wrap' }}>
|
||||||
|
{error && error.toString()}
|
||||||
|
<br />
|
||||||
|
{errorInfo.componentStack}
|
||||||
|
</details>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
return children;
|
||||||
|
}
|
||||||
|
|
||||||
|
ErrorBoundary.defaultProps = {
|
||||||
|
children: null,
|
||||||
|
};
|
||||||
|
|
||||||
|
ErrorBoundary.propTypes = {
|
||||||
|
children: PropTypes.node,
|
||||||
|
};
|
||||||
|
|
||||||
|
export default ErrorBoundary;
|
||||||
@@ -59,6 +59,7 @@
|
|||||||
"nodemon": "^1.19.1",
|
"nodemon": "^1.19.1",
|
||||||
"objection": "^2.0.10",
|
"objection": "^2.0.10",
|
||||||
"objection-soft-delete": "^1.0.7",
|
"objection-soft-delete": "^1.0.7",
|
||||||
|
"pluralize": "^8.0.0",
|
||||||
"reflect-metadata": "^0.1.13",
|
"reflect-metadata": "^0.1.13",
|
||||||
"ts-transformer-keys": "^0.4.2",
|
"ts-transformer-keys": "^0.4.2",
|
||||||
"tsyringe": "^4.3.0",
|
"tsyringe": "^4.3.0",
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
import { Service, Inject } from 'typedi';
|
||||||
import { Router, Request, Response, NextFunction } from 'express';
|
import { Router, Request, Response, NextFunction } from 'express';
|
||||||
import {
|
import {
|
||||||
param,
|
param,
|
||||||
@@ -5,20 +6,26 @@ import {
|
|||||||
} from 'express-validator';
|
} from 'express-validator';
|
||||||
import asyncMiddleware from 'api/middleware/asyncMiddleware';
|
import asyncMiddleware from 'api/middleware/asyncMiddleware';
|
||||||
import BaseController from './BaseController';
|
import BaseController from './BaseController';
|
||||||
import { Service } from 'typedi';
|
import { ServiceError } from 'exceptions';
|
||||||
import ResourceFieldsKeys from 'data/ResourceFieldsKeys';
|
import ResourceService from 'services/Resource/ResourceService';
|
||||||
|
|
||||||
@Service()
|
@Service()
|
||||||
export default class ResourceController extends BaseController{
|
export default class ResourceController extends BaseController{
|
||||||
|
@Inject()
|
||||||
|
resourcesService: ResourceService;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Router constructor.
|
* Router constructor.
|
||||||
*/
|
*/
|
||||||
router() {
|
router() {
|
||||||
const router = Router();
|
const router = Router();
|
||||||
|
|
||||||
router.get('/:resource_model/fields',
|
router.get(
|
||||||
this.resourceModelParamSchema,
|
'/:resource_model/fields', [
|
||||||
asyncMiddleware(this.resourceFields.bind(this))
|
...this.resourceModelParamSchema,
|
||||||
|
],
|
||||||
|
asyncMiddleware(this.resourceFields.bind(this)),
|
||||||
|
this.handleServiceErrors
|
||||||
);
|
);
|
||||||
return router;
|
return router;
|
||||||
}
|
}
|
||||||
@@ -31,14 +38,39 @@ export default class ResourceController extends BaseController{
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Retrieve resource fields of the given resource.
|
* Retrieve resource fields of the given resource.
|
||||||
|
* @param {Request} req
|
||||||
|
* @param {Response} res
|
||||||
|
* @param {NextFunction} next
|
||||||
*/
|
*/
|
||||||
resourceFields(req: Request, res: Response, next: NextFunction) {
|
resourceFields(req: Request, res: Response, next: NextFunction) {
|
||||||
|
const { tenantId } = req;
|
||||||
const { resource_model: resourceModel } = req.params;
|
const { resource_model: resourceModel } = req.params;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
const resourceFields = this.resourcesService.getResourceFields(tenantId, resourceModel);
|
||||||
|
|
||||||
|
return res.status(200).send({
|
||||||
|
resource_fields: this.transfromToResponse(resourceFields),
|
||||||
|
});
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
next(error);
|
next(error);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Handles service errors.
|
||||||
|
* @param {Error} error
|
||||||
|
* @param {Request} req
|
||||||
|
* @param {Response} res
|
||||||
|
* @param {NextFunction} next
|
||||||
|
*/
|
||||||
|
handleServiceErrors(error: Error, req: Request, res: Response, next: NextFunction) {
|
||||||
|
if (error instanceof ServiceError) {
|
||||||
|
if (error.errorType === 'RESOURCE_MODEL_NOT_FOUND') {
|
||||||
|
return res.status(400).send({
|
||||||
|
errors: [{ type: 'RESOURCE.MODEL.NOT.FOUND', code: 100 }],
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -5,8 +5,6 @@ exports.up = function (knex) {
|
|||||||
const tenancyService = Container.get(TenancyService);
|
const tenancyService = Container.get(TenancyService);
|
||||||
const i18n = tenancyService.i18n(knex.userParams.tenantId);
|
const i18n = tenancyService.i18n(knex.userParams.tenantId);
|
||||||
|
|
||||||
console.log(i18n);
|
|
||||||
|
|
||||||
return knex('accounts').then(() => {
|
return knex('accounts').then(() => {
|
||||||
// Inserts seed entries
|
// Inserts seed entries
|
||||||
return knex('accounts').insert([
|
return knex('accounts').insert([
|
||||||
|
|||||||
@@ -29,6 +29,7 @@ export interface IAccountsFilter extends IDynamicListFilterDTO {
|
|||||||
export interface IAccountType {
|
export interface IAccountType {
|
||||||
id: number,
|
id: number,
|
||||||
key: string,
|
key: string,
|
||||||
|
label: string,
|
||||||
normal: string,
|
normal: string,
|
||||||
rootType: string,
|
rootType: string,
|
||||||
childType: string,
|
childType: string,
|
||||||
|
|||||||
@@ -269,3 +269,30 @@ export function validateFilterRolesFieldsExistance(model, filterRoles: IFilterRo
|
|||||||
return !validateFieldKeyExistance(model, filterRole.fieldKey);
|
return !validateFieldKeyExistance(model, filterRole.fieldKey);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Retrieve model fields keys.
|
||||||
|
* @param {IModel} Model
|
||||||
|
* @return {string[]}
|
||||||
|
*/
|
||||||
|
export function getModelFieldsKeys(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;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
export function getModelFields(Model: IModel) {
|
||||||
|
const fieldsKey = this.getModelFieldsKeys(Model);
|
||||||
|
|
||||||
|
return fieldsKey.map((fieldKey) => {
|
||||||
|
const field = Model.fields[fieldKey];
|
||||||
|
return {
|
||||||
|
...field,
|
||||||
|
key: fieldKey,
|
||||||
|
};
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|||||||
@@ -1,7 +1,5 @@
|
|||||||
{
|
{
|
||||||
"Empty": "",
|
"Petty Cash": "Petty Cash",
|
||||||
"Hello": "Hello",
|
|
||||||
"Petty Cash": "Petty Cash 2",
|
|
||||||
"Bank": "Bank",
|
"Bank": "Bank",
|
||||||
"Other Income": "Other Income",
|
"Other Income": "Other Income",
|
||||||
"Interest Income": "Interest Income",
|
"Interest Income": "Interest Income",
|
||||||
@@ -30,4 +28,14 @@
|
|||||||
"Assets": "Assets",
|
"Assets": "Assets",
|
||||||
"Liabilities": "Liabilities",
|
"Liabilities": "Liabilities",
|
||||||
"Expenses": "Expenses",
|
"Expenses": "Expenses",
|
||||||
|
"Account name": "Account name",
|
||||||
|
"Account type": "Account type",
|
||||||
|
"Account normal": "Account normal",
|
||||||
|
"Description": "Description",
|
||||||
|
"Account code": "Account code",
|
||||||
|
"Currency": "Currency",
|
||||||
|
"Balance": "Balance",
|
||||||
|
"Active": "Active",
|
||||||
|
"Created at": "Created at",
|
||||||
|
"fixed_asset": "Fixed asset"
|
||||||
}
|
}
|
||||||
@@ -121,7 +121,7 @@ export default class Account extends TenantModel {
|
|||||||
static get fields() {
|
static get fields() {
|
||||||
return {
|
return {
|
||||||
name: {
|
name: {
|
||||||
label: 'Name',
|
label: 'Account name',
|
||||||
column: 'name',
|
column: 'name',
|
||||||
},
|
},
|
||||||
type: {
|
type: {
|
||||||
@@ -145,20 +145,25 @@ export default class Account extends TenantModel {
|
|||||||
relationColumn: 'account_types.root_type',
|
relationColumn: 'account_types.root_type',
|
||||||
},
|
},
|
||||||
created_at: {
|
created_at: {
|
||||||
|
label: 'Created at',
|
||||||
column: 'created_at',
|
column: 'created_at',
|
||||||
columnType: 'date',
|
columnType: 'date',
|
||||||
},
|
},
|
||||||
active: {
|
active: {
|
||||||
|
label: 'Active',
|
||||||
column: 'active',
|
column: 'active',
|
||||||
},
|
},
|
||||||
balance: {
|
balance: {
|
||||||
|
label: 'Balance',
|
||||||
column: 'amount',
|
column: 'amount',
|
||||||
columnType: 'number'
|
columnType: 'number'
|
||||||
},
|
},
|
||||||
currency: {
|
currency: {
|
||||||
|
label: 'Currency',
|
||||||
column: 'currency_code',
|
column: 'currency_code',
|
||||||
},
|
},
|
||||||
normal: {
|
normal: {
|
||||||
|
label: 'Account normal',
|
||||||
column: 'account_type_id',
|
column: 'account_type_id',
|
||||||
relation: 'account_types.id',
|
relation: 'account_types.id',
|
||||||
relationColumn: 'account_types.normal'
|
relationColumn: 'account_types.normal'
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ import TenantModel from 'models/TenantModel';
|
|||||||
|
|
||||||
export default class AccountType extends TenantModel {
|
export default class AccountType extends TenantModel {
|
||||||
/**
|
/**
|
||||||
* Table name
|
* Table name.
|
||||||
*/
|
*/
|
||||||
static get tableName() {
|
static get tableName() {
|
||||||
return 'account_types';
|
return 'account_types';
|
||||||
@@ -30,4 +30,26 @@ export default class AccountType extends TenantModel {
|
|||||||
},
|
},
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Accounts types labels.
|
||||||
|
*/
|
||||||
|
static get labels() {
|
||||||
|
return {
|
||||||
|
fixed_asset: 'Fixed asset',
|
||||||
|
current_asset: "Current asset",
|
||||||
|
long_term_liability: "Long term liability",
|
||||||
|
current_liability: "Current liability",
|
||||||
|
equity: "Equity",
|
||||||
|
expense: "Expense",
|
||||||
|
income: "Income",
|
||||||
|
accounts_receivable: "Accounts receivable",
|
||||||
|
accounts_payable: "Accounts payable",
|
||||||
|
other_expense: "Other expense",
|
||||||
|
other_income: "Other income",
|
||||||
|
cost_of_goods_sold: "Cost of goods sold (COGS)",
|
||||||
|
other_liability: "Other liability",
|
||||||
|
other_asset: 'Other asset',
|
||||||
|
};
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,4 @@
|
|||||||
import { IView } from 'interfaces';
|
import { IView } from 'interfaces';
|
||||||
import { View } from 'models';
|
|
||||||
import TenantRepository from 'repositories/TenantRepository';
|
import TenantRepository from 'repositories/TenantRepository';
|
||||||
|
|
||||||
export default class ViewRepository extends TenantRepository {
|
export default class ViewRepository extends TenantRepository {
|
||||||
@@ -50,13 +49,23 @@ export default class ViewRepository extends TenantRepository {
|
|||||||
* @param {IView} view
|
* @param {IView} view
|
||||||
*/
|
*/
|
||||||
async insert(view: IView): Promise<IView> {
|
async insert(view: IView): Promise<IView> {
|
||||||
|
const { View } = this.models;
|
||||||
const insertedView = await View.query().insertGraph({ ...view });
|
const insertedView = await View.query().insertGraph({ ...view });
|
||||||
this.flushCache();
|
this.flushCache();
|
||||||
|
|
||||||
return insertedView;
|
return insertedView;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async update(viewId: number, view: IView): Promise<IView> {
|
||||||
|
const { View } = this.models;
|
||||||
|
const updatedView = await View.query().upsertGraph({
|
||||||
|
id: viewId,
|
||||||
|
...view
|
||||||
|
});
|
||||||
|
this.flushCache();
|
||||||
|
|
||||||
|
return updatedView;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Flushes repository cache.
|
* Flushes repository cache.
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
import { Inject, Service } from 'typedi';
|
import { Inject, Service } from 'typedi';
|
||||||
|
import { omit } from 'lodash';
|
||||||
import TenancyService from 'services/Tenancy/TenancyService';
|
import TenancyService from 'services/Tenancy/TenancyService';
|
||||||
import { IAccountsTypesService, IAccountType } from 'interfaces';
|
import { IAccountsTypesService, IAccountType } from 'interfaces';
|
||||||
|
|
||||||
@@ -12,8 +13,17 @@ export default class AccountsTypesService implements IAccountsTypesService{
|
|||||||
* @param {number} tenantId -
|
* @param {number} tenantId -
|
||||||
* @return {Promise<IAccountType>}
|
* @return {Promise<IAccountType>}
|
||||||
*/
|
*/
|
||||||
getAccountsTypes(tenantId: number): Promise<IAccountType> {
|
async getAccountsTypes(tenantId: number): Promise<IAccountType> {
|
||||||
const { accountTypeRepository } = this.tenancy.repositories(tenantId);
|
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 { Service, Inject } from 'typedi';
|
||||||
import { camelCase, upperFirst } from 'lodash'
|
import { camelCase, upperFirst } from 'lodash';
|
||||||
|
import pluralize from 'pluralize';
|
||||||
import { IModel } from 'interfaces';
|
import { IModel } from 'interfaces';
|
||||||
import resourceFieldsKeys from 'data/ResourceFieldsKeys';
|
import {
|
||||||
|
getModelFields,
|
||||||
|
} from 'lib/ViewRolesBuilder'
|
||||||
import TenancyService from 'services/Tenancy/TenancyService';
|
import TenancyService from 'services/Tenancy/TenancyService';
|
||||||
|
import { ServiceError } from 'exceptions';
|
||||||
|
|
||||||
|
const ERRORS = {
|
||||||
|
RESOURCE_MODEL_NOT_FOUND: 'RESOURCE_MODEL_NOT_FOUND',
|
||||||
|
};
|
||||||
|
|
||||||
@Service()
|
@Service()
|
||||||
export default class ResourceService {
|
export default class ResourceService {
|
||||||
@Inject()
|
@Inject()
|
||||||
tenancy: TenancyService;
|
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.
|
* Transform resource to model name.
|
||||||
* @param {string} resourceName
|
* @param {string} resourceName
|
||||||
*/
|
*/
|
||||||
private resourceToModelName(resourceName: string): string {
|
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 {number} tenantId
|
||||||
* @param {string} resourceName
|
* @param {IModel} Model
|
||||||
*/
|
*/
|
||||||
public getModel(tenantId: number, resourceName: string) {
|
private getModelFields(tenantId: number, Model: IModel) {
|
||||||
const models = this.tenancy.models(tenantId);
|
const { __ } = this.tenancy.i18n(tenantId);
|
||||||
const modelName = this.resourceToModelName(resourceName);
|
const fields = getModelFields(Model);
|
||||||
|
|
||||||
return models[modelName];
|
return fields.map((field) => ({
|
||||||
}
|
label: __(field.label, field.label),
|
||||||
|
key: field.key,
|
||||||
getModelFields(Model: IModel) {
|
dataType: field.columnType,
|
||||||
const fields = Object.keys(Model.fields);
|
}));
|
||||||
|
|
||||||
return fields.sort((a, b) => {
|
|
||||||
if (a < b) { return -1; }
|
|
||||||
if (a > b) { return 1; }
|
|
||||||
return 0;
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
* Retrieve resource fields from resource model name.
|
||||||
* @param {string} resourceName
|
* @param {string} resourceName
|
||||||
*/
|
*/
|
||||||
getResourceFields(Model: IModel) {
|
public getResourceFields(tenantId: number, modelName: string) {
|
||||||
console.log(Model);
|
const resourceModel = this.getResourceModel(tenantId, modelName);
|
||||||
|
|
||||||
if (Model.resourceable) {
|
return this.getModelFields(tenantId, resourceModel);
|
||||||
return this.getModelFields(Model);
|
|
||||||
}
|
|
||||||
return [];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
* Retrieve resource model object.
|
||||||
* @param {string} resourceName
|
* @param {number} tenantId -
|
||||||
|
* @param {string} inputModelName -
|
||||||
*/
|
*/
|
||||||
getResourceColumns(Model: IModel) {
|
public getResourceModel(tenantId: number, inputModelName: string) {
|
||||||
if (Model.resourceable) {
|
const modelName = this.resourceToModelName(inputModelName);
|
||||||
return this.getModelFields(Model);
|
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,
|
IViewDTO,
|
||||||
IView,
|
IView,
|
||||||
IViewEditDTO,
|
IViewEditDTO,
|
||||||
|
IModel,
|
||||||
|
IViewColumnDTO,
|
||||||
|
IViewRoleDTO,
|
||||||
} from 'interfaces';
|
} from 'interfaces';
|
||||||
|
import { getModelFieldsKeys } from 'lib/ViewRolesBuilder';
|
||||||
import TenancyService from 'services/Tenancy/TenancyService';
|
import TenancyService from 'services/Tenancy/TenancyService';
|
||||||
import ResourceService from "services/Resource/ResourceService";
|
import ResourceService from "services/Resource/ResourceService";
|
||||||
import { validateRolesLogicExpression } from 'lib/ViewRolesBuilder';
|
import { validateRolesLogicExpression } from 'lib/ViewRolesBuilder';
|
||||||
@@ -37,14 +41,14 @@ export default class ViewsService implements IViewsService {
|
|||||||
* @param {number} tenantId -
|
* @param {number} tenantId -
|
||||||
* @param {string} resourceModel -
|
* @param {string} resourceModel -
|
||||||
*/
|
*/
|
||||||
public async listResourceViews(tenantId: number, resourceModel: string): Promise<IView[]> {
|
public async listResourceViews(tenantId: number, resourceModelName: string): Promise<IView[]> {
|
||||||
this.logger.info('[views] trying to retrieve resource views.', { tenantId, resourceModel });
|
this.logger.info('[views] trying to retrieve resource views.', { tenantId, resourceModelName });
|
||||||
|
|
||||||
// Validate the resource model name is valid.
|
// Validate the resource model name is valid.
|
||||||
this.getResourceModelOrThrowError(tenantId, resourceModel);
|
const resourceModel = this.getResourceModelOrThrowError(tenantId, resourceModelName);
|
||||||
|
|
||||||
const { viewRepository } = this.tenancy.repositories(tenantId);
|
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
|
* @param {IViewRoleDTO[]} viewRoles
|
||||||
*/
|
*/
|
||||||
private validateResourceRolesFieldsExistance(ResourceModel: IModel, viewRoles: IViewRoleDTO[]) {
|
private validateResourceRolesFieldsExistance(ResourceModel: IModel, viewRoles: IViewRoleDTO[]) {
|
||||||
const resourceFieldsKeys = this.resourceService.getResourceFields(ResourceModel);
|
const resourceFieldsKeys = getModelFieldsKeys(ResourceModel);
|
||||||
|
|
||||||
const fieldsKeys = viewRoles.map(viewRole => viewRole.fieldKey);
|
const fieldsKeys = viewRoles.map(viewRole => viewRole.fieldKey);
|
||||||
const notFoundFieldsKeys = difference(fieldsKeys, resourceFieldsKeys);
|
const notFoundFieldsKeys = difference(fieldsKeys, resourceFieldsKeys);
|
||||||
@@ -70,7 +74,7 @@ export default class ViewsService implements IViewsService {
|
|||||||
* @param {IViewColumnDTO[]} viewColumns
|
* @param {IViewColumnDTO[]} viewColumns
|
||||||
*/
|
*/
|
||||||
private validateResourceColumnsExistance(ResourceModel: IModel, viewColumns: IViewColumnDTO[]) {
|
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 fieldsKeys = viewColumns.map((viewColumn: IViewColumnDTO) => viewColumn.fieldKey);
|
||||||
const notFoundFieldsKeys = difference(fieldsKeys, resourceFieldsKeys);
|
const notFoundFieldsKeys = difference(fieldsKeys, resourceFieldsKeys);
|
||||||
@@ -115,12 +119,7 @@ export default class ViewsService implements IViewsService {
|
|||||||
* @param {number} resourceModel
|
* @param {number} resourceModel
|
||||||
*/
|
*/
|
||||||
private getResourceModelOrThrowError(tenantId: number, resourceModel: string): IModel {
|
private getResourceModelOrThrowError(tenantId: number, resourceModel: string): IModel {
|
||||||
const ResourceModel = this.resourceService.getModel(tenantId, resourceModel);
|
return this.resourceService.getResourceModel(tenantId, resourceModel);
|
||||||
|
|
||||||
if (!ResourceModel || !ResourceModel.resourceable) {
|
|
||||||
throw new ServiceError(ERRORS.RESOURCE_MODEL_NOT_FOUND);
|
|
||||||
}
|
|
||||||
return ResourceModel;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -137,6 +136,8 @@ export default class ViewsService implements IViewsService {
|
|||||||
notViewId?: number
|
notViewId?: number
|
||||||
): void {
|
): void {
|
||||||
const { View } = this.tenancy.models(tenantId);
|
const { View } = this.tenancy.models(tenantId);
|
||||||
|
|
||||||
|
this.logger.info('[views] trying to validate view name uniqiness.', { tenantId, resourceModel, viewName });
|
||||||
const foundViews = await View.query()
|
const foundViews = await View.query()
|
||||||
.where('resource_model', resourceModel)
|
.where('resource_model', resourceModel)
|
||||||
.where('name', viewName)
|
.where('name', viewName)
|
||||||
@@ -165,6 +166,8 @@ export default class ViewsService implements IViewsService {
|
|||||||
* ---------
|
* ---------
|
||||||
* @param {number} tenantId - Tenant id.
|
* @param {number} tenantId - Tenant id.
|
||||||
* @param {IViewDTO} viewDTO - View DTO.
|
* @param {IViewDTO} viewDTO - View DTO.
|
||||||
|
*
|
||||||
|
* @return {Promise<IView>}
|
||||||
*/
|
*/
|
||||||
public async newView(tenantId: number, viewDTO: IViewDTO): Promise<IView> {
|
public async newView(tenantId: number, viewDTO: IViewDTO): Promise<IView> {
|
||||||
const { viewRepository } = this.tenancy.repositories(tenantId);
|
const { viewRepository } = this.tenancy.repositories(tenantId);
|
||||||
@@ -187,6 +190,7 @@ export default class ViewsService implements IViewsService {
|
|||||||
throw new ServiceError(ERRORS.LOGIC_EXPRESSION_INVALID);
|
throw new ServiceError(ERRORS.LOGIC_EXPRESSION_INVALID);
|
||||||
}
|
}
|
||||||
// Save view details.
|
// Save view details.
|
||||||
|
this.logger.info('[views] trying to insert to storage.', { tenantId, viewDTO })
|
||||||
const view = await viewRepository.insert({
|
const view = await viewRepository.insert({
|
||||||
predefined: false,
|
predefined: false,
|
||||||
name: viewDTO.name,
|
name: viewDTO.name,
|
||||||
@@ -216,7 +220,7 @@ export default class ViewsService implements IViewsService {
|
|||||||
* @param {IViewEditDTO}
|
* @param {IViewEditDTO}
|
||||||
*/
|
*/
|
||||||
public async editView(tenantId: number, viewId: number, viewEditDTO: IViewEditDTO): Promise<void> {
|
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 });
|
this.logger.info('[view] trying to edit custom view.', { tenantId, viewId });
|
||||||
|
|
||||||
// Retrieve view details or throw not found error.
|
// 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);
|
await this.validateViewNameUniquiness(tenantId, view.resourceModel, viewEditDTO.name, viewId);
|
||||||
|
|
||||||
// Validate the given fields keys exist on the storage.
|
// 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.
|
// 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.
|
// Validates the view conditional logic expression.
|
||||||
if (!validateRolesLogicExpression(viewEditDTO.logicExpression, viewEditDTO.roles)) {
|
if (!validateRolesLogicExpression(viewEditDTO.logicExpression, viewEditDTO.roles)) {
|
||||||
throw new ServiceError(ERRORS.LOGIC_EXPRESSION_INVALID);
|
throw new ServiceError(ERRORS.LOGIC_EXPRESSION_INVALID);
|
||||||
}
|
}
|
||||||
// Save view details.
|
// Update view details.
|
||||||
await View.query()
|
await viewRepository.update(tenantId, viewId, {
|
||||||
.where('id', view.id)
|
predefined: false,
|
||||||
.patch({
|
|
||||||
name: viewEditDTO.name,
|
name: viewEditDTO.name,
|
||||||
roles_logic_expression: viewEditDTO.logicExpression,
|
rolesLogicExpression: viewEditDTO.logicExpression,
|
||||||
});
|
roles: viewEditDTO.roles,
|
||||||
|
columns: viewEditDTO.columns,
|
||||||
|
})
|
||||||
this.logger.info('[view] edited successfully.', { tenantId, viewId });
|
this.logger.info('[view] edited successfully.', { tenantId, viewId });
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user