Skip to content
This repository was archived by the owner on Nov 6, 2023. It is now read-only.

Asset plugin #198

Open
wants to merge 2 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 14 additions & 0 deletions packages/plugin-asset-api/.env.sample
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
# general
NODE_ENV=development
PORT=4011

# MongoDB
MONGO_URL=mongodb://localhost/erxes

# RabbitMQ
RABBITMQ_HOST=amqp://localhost

# Redis
REDIS_HOST=localhost
REDIS_PORT=6379
REDIS_PASSWORD=
10 changes: 10 additions & 0 deletions packages/plugin-asset-api/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
{
"name": "@erxes/plugin-asset-api",
"version": "1.0.0",
"scripts": {
"install-deps": "cd .erxes && yarn install",
"dev": "cd .erxes && yarn dev",
"build": "cd .erxes && yarn build",
"start": "cd .erxes/dist/plugin-asset-api/.erxes && node src"
}
}
41 changes: 41 additions & 0 deletions packages/plugin-asset-api/src/configs.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
import typeDefs from './graphql/typeDefs';
import resolvers from './graphql/resolvers';

import { initBroker } from './messageBroker';
import { getSubdomain } from '@erxes/api-utils/src/core';
import { generateModels } from './connectionResolver';

export let mainDb;
export let debug;
export let graphqlPubsub;
export let serviceDiscovery;

export default {
name: 'asset',
graphql: async sd => {
serviceDiscovery = sd;

return {
typeDefs: await typeDefs(sd),
resolvers: await resolvers(sd)
};
},
apolloServerContext: async (context, req) => {
const subdomain = getSubdomain(req);
const models = await generateModels(subdomain);

context.subdomain = req.hostname;
context.models = models;

return context;
},
onServerInit: async options => {
mainDb = options.db;

initBroker(options.messageBrokerClient);

graphqlPubsub = options.pubsubClient;

debug = options.debug;
}
};
48 changes: 48 additions & 0 deletions packages/plugin-asset-api/src/connectionResolver.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
import * as mongoose from 'mongoose';
import { IContext as IMainContext } from '@erxes/api-utils/src';
import {
IAssetCategoryModel,
IAssetModel,
loadAssetCategoryClass,
loadAssetClass
} from './models/Assets';
import { IAssetCategoryDocument, IAssetDocument } from './models/definitions/assets';
import { IUomModel, loadUomClass } from './models/Uoms';
import { IUomDocument } from './models/definitions/uoms';
import { IAssetsConfigDocument } from './models/definitions/configs';
import { IAssetsConfigModel, loadAssetsConfigClass } from './models/Configs';
import { createGenerateModels } from '@erxes/api-utils/src/core';
export interface IModels {
Assets: IAssetModel;
AssetCategories: IAssetCategoryModel;
AssetsConfigs: IAssetsConfigModel;
Uoms: IUomModel;
}
export interface IContext extends IMainContext {
subdomain: string;
models: IModels;
}

export let models: IModels | null = null;

export const loadClasses = (db: mongoose.Connection, subdomain: string): IModels => {
models = {} as IModels;

models.Assets = db.model<IAssetDocument, IAssetModel>(
'assets',
loadAssetClass(models, subdomain)
);
models.Uoms = db.model<IUomDocument, IUomModel>('uoms', loadUomClass(models, subdomain));
models.AssetsConfigs = db.model<IAssetsConfigDocument, IAssetsConfigModel>(
'assets_configs',
loadAssetsConfigClass(models)
);
models.AssetCategories = db.model<IAssetCategoryDocument, IAssetCategoryModel>(
'asset_categories',
loadAssetCategoryClass(models)
);

return models;
};

export const generateModels = createGenerateModels<IModels>(models, loadClasses);
36 changes: 36 additions & 0 deletions packages/plugin-asset-api/src/constants.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
export const PRODUCT_INFO = {
code: 'Code',
name: 'Name',
type: 'Type',
category: 'Category',
vendor: 'Vendor',
description: 'Description',
sku: 'Sku',
assetCount: 'Product count',

ALL: [
{ field: 'code', label: 'Code' },
{ field: 'name', label: 'Name' },
{ field: 'type', label: 'Type' },
{ field: 'category', label: 'Category' },
{ field: 'vendor', label: 'Vendor' },
{ field: 'description', label: 'Description' },
{ field: 'sku', label: 'Sku' },
{ field: 'assetCount', label: 'Product count' }
]
};

export const EXTEND_FIELDS = [
{
_id: Math.random(),
name: 'categoryName',
label: 'Category Name',
type: 'string'
},
{
_id: Math.random(),
name: 'tag',
label: 'Tag',
type: 'string'
}
];
13 changes: 13 additions & 0 deletions packages/plugin-asset-api/src/dataloaders/assetCategory.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
import * as DataLoader from 'dataloader';
import * as _ from 'underscore';
import { IModels } from '../connectionResolver';

export default function generateDataLoaderAssetCategory(models: IModels) {
return new DataLoader<string, any>(async (ids: readonly string[]) => {
const result: any[] = await models.AssetCategories.find({
_id: { $in: ids }
}).lean();
const resultById = _.indexBy(result, '_id');
return ids.map(id => resultById[id]);
});
}
20 changes: 20 additions & 0 deletions packages/plugin-asset-api/src/dataloaders/company.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
import * as DataLoader from 'dataloader';
import * as _ from 'underscore';
import { sendContactsMessage } from '../messageBroker';

export default function generateDataLoaderCompany(subdomain) {
return new DataLoader<string, any>(async (ids: readonly string[]) => {
const result = await sendContactsMessage({
subdomain,
action: 'companies.findActiveCompanies',
data: {
selector: {
_id: { $in: ids }
}
},
isRPC: true
});
const resultById = _.indexBy(result, '_id');
return ids.map(id => resultById[id]);
});
}
23 changes: 23 additions & 0 deletions packages/plugin-asset-api/src/dataloaders/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
import * as DataLoader from 'dataloader';
import * as _ from 'underscore';
import assetCategory from './assetCategory';
import tag from './tag';
import company from './company';
import uom from './uom';
import { IModels } from '../connectionResolver';

export interface IDataLoaders {
assetCategory: DataLoader<string, any>;
tag: DataLoader<string, any>;
company: DataLoader<string, any>;
uom: DataLoader<string, any>;
}

export function generateAllDataLoaders(models: IModels, subdomain: string): IDataLoaders {
return {
assetCategory: assetCategory(models),
tag: tag(subdomain),
company: company(subdomain),
uom: uom(models)
};
}
38 changes: 38 additions & 0 deletions packages/plugin-asset-api/src/dataloaders/resolvers/asset.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
import { IContext } from '../../connectionResolver';
import { IAssetDocument } from '../../models/definitions/assets';

export default {
__resolveReference({ _id }, { models }: IContext) {
return models.Assets.findOne({ _id });
},

category(asset: IAssetDocument, _, { dataLoaders }: IContext) {
return (asset.categoryId && dataLoaders.assetCategory.load(asset.categoryId)) || null;
},

async getTags(asset: IAssetDocument, _, { dataLoaders }: IContext) {
const tags = await dataLoaders.tag.loadMany(asset.tagIds || []);
return tags.filter(tag => tag);
},

vendor(asset: IAssetDocument, _, { dataLoaders }: IContext) {
return (asset.vendorId && dataLoaders.company.load(asset.vendorId)) || null;
},

async uom(asset: IAssetDocument, _, { dataLoaders, models }: IContext) {
if (!(await models.AssetsConfigs.getConfig('isReqiureUOM', ''))) {
return null;
}

let uomId = asset.uomId;
if (!uomId) {
uomId = await models.AssetsConfigs.getConfig('default_uom', '');
}

if (!uomId) {
return null;
}

return await models.Uoms.findOne({ _id: uomId });
}
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
import { IContext } from '../../connectionResolver';
import { IAssetCategoryDocument, ASSET_STATUSES } from '../../models/definitions/assets';

export default {
__resolveReference({ _id }, { models }: IContext) {
return models.AssetCategories.findOne({ _id });
},

isRoot(category: IAssetCategoryDocument, {}) {
return category.parentId ? false : true;
},

async assetCount(category: IAssetCategoryDocument, {}, { models }: IContext) {
const asset_category_ids = await models.AssetCategories.find(
{ order: { $regex: new RegExp(category.order) } },
{ _id: 1 }
);
return models.Assets.countDocuments({
categoryId: { $in: asset_category_ids },
status: { $ne: ASSET_STATUSES.DELETED }
});
}
};
33 changes: 33 additions & 0 deletions packages/plugin-asset-api/src/dataloaders/resolvers/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
import customScalars from '@erxes/api-utils/src/customScalars';
import Asset from './asset';
import AssetCategory from './assetCategory';

import {
Assets as Mutations,
AssetConfigs as MutationsAssetConfig,
Uoms as MutationsUom
} from './mutations';

import {
Assets as Queries,
AssetConfigs as QueriesAssetConfig,
Uoms as QueriesUom
} from './queries';

const resolvers: any = {
...customScalars,
Asset,
AssetCategory,
Mutation: {
...Mutations,
...MutationsAssetConfig,
...MutationsUom
},
Query: {
...Queries,
...QueriesAssetConfig,
...QueriesUom
}
};

export default resolvers;
Loading