'use strict'; const moment = require("moment/moment"); //获取资源目录 async function getResourceCatalog(ctx) { try { const models = ctx.fs.dc.models; const rslt = await models.ResourceCatalog.findAll({ order: [['id', 'asc']], }); ctx.status = 200; ctx.body = rslt; } catch (error) { ctx.fs.logger.error(`path: ${ctx.path}, error: ${error}`); ctx.status = 400; ctx.body = { "message": "获取资源目录失败" } } } //新建资源目录 async function postResourceCatalog(ctx) { try { const { name, code } = ctx.request.body; const models = ctx.fs.dc.models; const postOne = await models.ResourceCatalog.findOne({ where: { $or: [{ name: name }, { code: code }] } }); if (postOne) { ctx.status = 400; ctx.body = { message: '该资源目录名称或代码已存在' } } else { if (!name || !code) { ctx.body = { message: '参数不全,请重新配置' } ctx.status = 400; } else { await models.ResourceCatalog.create(ctx.request.body); ctx.body = { message: '新建资源目录成功' } ctx.status = 200; } } } catch (error) { ctx.fs.logger.error(`path: ${ctx.path}, error: ${error}`); ctx.status = 400; ctx.body = { "message": "新建资源目录失败" } } } //修改资源目录 async function putResourceCatalog(ctx) { try { const { id } = ctx.params; const { name, code, description } = ctx.request.body; const models = ctx.fs.dc.models; let resourceCatalogInfo = await models.ResourceCatalog.findOne({ where: { id } }); if (resourceCatalogInfo) { const putOne = await models.ResourceCatalog.findOne({ where: { id: { $not: id }, $or: [{ name: name }, { code: code }] } }); if (putOne) { ctx.status = 400; ctx.body = { message: '该资源目录名称或代码已存在' } } else { await models.ResourceCatalog.update(ctx.request.body, { where: { id: id } }); ctx.status = 200; ctx.body = { message: '修改资源目录成功' } } } else { ctx.status = 400; ctx.body = { message: '该资源目录不存在' } } } catch (error) { ctx.fs.logger.error(`path: ${ctx.path}, error: ${error}`); ctx.status = 400; ctx.body = { "message": "修改资源目录失败" } } } //删除资源目录 async function delResourceCatalog(ctx) { const transaction = await ctx.fs.dc.orm.transaction(); try { const models = ctx.fs.dc.models; const { id } = ctx.params; let resourceCatalogInfo = await models.ResourceCatalog.findOne({ where: { id } }); if (resourceCatalogInfo) { let deletable = true; let childResourceCatalogInfo = await models.ResourceCatalog.findOne({ where: { parent: id } }); let databaseInfo = await models.MetadataDatabase.findOne({ where: { catalog: id } }); let fileInfo = await models.MetadataFile.findOne({ where: { catalog: id } }); let restapiInfo = await models.MetadataRestapi.findOne({ where: { catalog: id } }); let dataSourceInfo = await models.DataSource.findOne({ where: { mountPath: id } }); if (childResourceCatalogInfo || databaseInfo || fileInfo || restapiInfo || dataSourceInfo) { ctx.status = 400; ctx.body = { message: '存在关联数据,请删除相关数据,再删除该资源目录' } deletable = false; } if (deletable) { await models.ResourceCatalog.destroy({ where: { id: id }, transaction }) await transaction.commit(); ctx.status = 200; ctx.body = { message: '删除资源目录成功' } } } else { ctx.status = 400; ctx.body = { message: '该资源目录不存在' } } } catch (error) { await transaction.rollback(); ctx.fs.logger.error(`path: ${ctx.path}, error: ${error}`); ctx.status = 400; ctx.body = { message: '删除资源目录失败' } } } //获取库表元数据列表 async function getMetadataDatabases(ctx) { try { const models = ctx.fs.dc.models; const { catalog, limit, offset, keywords, orderBy = 'createAt', orderDirection = 'desc', id = null } = ctx.query; const where = {}; if (catalog) { where.catalog = catalog; } if (id) { where.parent = id; } if (keywords) { where['$or'] = [{ name: { $iLike: `%${keywords}%` } }, { code: { $iLike: `%${keywords}%` } }, { type: { $iLike: `%${keywords}%` } }] } const findObj = { include: [ { model: models.User, attributes: ['id', 'name', 'username'], }, { model: models.TagDatabase, include: [{ model: models.Tag, }] }], where: where, order: [[orderBy, orderDirection]], distinct: true } if (Number(limit) > 0 && Number(offset) >= 0) { findObj.offset = Number(offset) * Number(limit); findObj.limit = Number(limit); } const rslt = await models.MetadataDatabase.findAndCountAll(findObj); ctx.status = 200; ctx.body = rslt; } catch (error) { ctx.fs.logger.error(`path: ${ctx.path}, error: ${error}`); ctx.status = 400; ctx.body = { "message": "获取库表元数据列表失败" } } } //获取文件元数据列表 async function getMetadataFiles(ctx) { try { const models = ctx.fs.dc.models; const { catalog, limit, offset, keywords, orderBy = 'updateAt', orderDirection = 'desc' } = ctx.query; const where = { catalog: catalog }; //文件类型关键字查询时需匹配fileName不能为空。 //因存在编辑时将文件删除,但未重新上传直接点击取消的情况,此时文件已删除不可恢复,数据字段fileName更新为null if (keywords) { where['$or'] = [{ name: { $iLike: `%${keywords}%` } }, { type: { $iLike: `%${keywords}%` }, fileName: { $not: null } }] } const findObj = { include: [ // { // model: models.User, // attributes: ['id', 'name', 'username'], // }, { model: models.TagFile, include: [{ model: models.Tag, }] }], where: where, order: [[orderBy, orderDirection]], distinct: true }; if (Number(limit) > 0 && Number(offset) >= 0) { findObj.offset = Number(offset) * Number(limit); findObj.limit = Number(limit); } const rslt = await models.MetadataFile.findAndCountAll(findObj); ctx.status = 200; ctx.body = rslt; } catch (error) { ctx.fs.logger.error(`path: ${ctx.path}, error: ${error}`); ctx.status = 400; ctx.body = { "message": "获取文件元数据列表失败" } } } //获取接口元数据列表 async function getMetadataRestapis(ctx) { try { const models = ctx.fs.dc.models; const { catalog, limit, offset, keywords, orderBy = 'createAt', orderDirection = 'desc' } = ctx.query; const where = { catalog: catalog }; if (keywords) { where.name = { $iLike: `%${keywords}%` }; } const findObj = { include: [ { model: models.User, attributes: ['id', 'name', 'username'], }, { model: models.TagRestapi, include: [{ model: models.Tag, }] }], where: where, order: [[orderBy, orderDirection]], distinct: true }; if (Number(limit) > 0 && Number(offset) >= 0) { findObj.offset = Number(offset) * Number(limit); findObj.limit = Number(limit); } const rslt = await models.MetadataRestapi.findAndCountAll(findObj); ctx.status = 200; ctx.body = rslt; } catch (error) { ctx.fs.logger.error(`path: ${ctx.path}, error: ${error}`); ctx.status = 400; ctx.body = { "message": "获取接口元数据列表失败" } } } //获取元数据模型 async function getMetadataModels(ctx) { try { const models = ctx.fs.dc.models; const { modelTypes } = ctx.query; let rslt = []; if (modelTypes) { rslt = await models.MetaModel.findAll({ where: { modelType: { $in: modelTypes.split(',') } } }); } ctx.status = 200; ctx.body = rslt; } catch (error) { ctx.fs.logger.error(`path: ${ctx.path}, error: ${error}`); ctx.status = 400; ctx.body = { "message": "获取元数据模型失败" } } } //新建库表元数据 async function postMetadataDatabases(ctx) { try { const { name, code, catalog, parent } = ctx.request.body; const models = ctx.fs.dc.models; const where = { $or: [{ name: name }, { code: code }] }; if (parent) { where.parent = parent; } else { where.parent = null; where.catalog = catalog; } const postOne = await models.MetadataDatabase.findOne({ where: where }); if (postOne) { ctx.status = 400; ctx.body = { message: '同一父节点下该元数据名称或代码已存在' } } else { if (!name || !code || !catalog) { ctx.body = { message: '参数不全,请重新配置' } ctx.status = 400; } else { await models.MetadataDatabase.create({ createAt: moment(), ...ctx.request.body }); ctx.body = { message: '新建元数据成功' } ctx.status = 200; } } } catch (error) { ctx.fs.logger.error(`path: ${ctx.path}, error: ${error}`); ctx.status = 400; ctx.body = { "message": "新建元数据失败" } } } //修改库表元数据 async function putMetadataDatabases(ctx) { try { const { id } = ctx.params; const { catalog, name, code } = ctx.request.body; const models = ctx.fs.dc.models; let metadataDatabaseInfo = await models.MetadataDatabase.findOne({ where: { id } }); if (metadataDatabaseInfo) { const where = { id: { $not: id }, $or: [{ name: name }, { code: code }] } if (metadataDatabaseInfo.parent) { where.parent = metadataDatabaseInfo.parent; } else { where.parent = null; where.catalog = catalog; } const putOne = await models.MetadataDatabase.findOne({ where: where }); if (putOne) { ctx.status = 400; ctx.body = { message: '同一父节点下该元数据名称或代码已存在' } } else { await models.MetadataDatabase.update({ updateAt: moment(), ...ctx.request.body }, { where: { id: id } }); ctx.status = 200; ctx.body = { message: '修改元数据成功' } } } else { ctx.status = 400; ctx.body = { message: '该元数据不存在' } } } catch (error) { ctx.fs.logger.error(`path: ${ctx.path}, error: ${error}`); ctx.status = 400; ctx.body = { "message": "修改元数据失败" } } } //删除库表元数据 async function delMetadataDatabases(ctx) { const transaction = await ctx.fs.dc.orm.transaction(); try { const models = ctx.fs.dc.models; const { id } = ctx.params; let metadataDatabaseInfo = await models.MetadataDatabase.findOne({ where: { id } }); if (metadataDatabaseInfo) { let deletable = true; let childMetadataDatabaseInfo = await models.MetadataDatabase.findOne({ where: { parent: id } }); if (childMetadataDatabaseInfo) { ctx.status = 400; ctx.body = { message: '存在关联子类元数据,请删除相关数据,再删除该元数据' } deletable = false; } else { let tagDatabaseInfo = await models.TagDatabase.findOne({ where: { database: id } }); if (tagDatabaseInfo) { ctx.status = 400; ctx.body = { message: '该元数据已被打标' } deletable = false; } else { let resourceConsumptionInfo = await models.ResourceConsumption.findOne({ where: { resourceName: metadataDatabaseInfo.name, resourceType: '库表' } }); if (resourceConsumptionInfo) { ctx.status = 400; ctx.body = { message: '该元数据存在资源申请' } deletable = false; } } } if (deletable) { await models.MetadataDatabase.destroy({ where: { id: id }, transaction }) await transaction.commit(); ctx.status = 200; ctx.body = { message: '删除元数据成功' } } } else { ctx.status = 400; ctx.body = { message: '该元数据不存在' } } } catch (error) { await transaction.rollback(); ctx.fs.logger.error(`path: ${ctx.path}, error: ${error}`); ctx.status = 400; ctx.body = { message: '删除元数据失败' } } } //获取库表元数据基本信息 async function getMetadataDatabasesById(ctx) { try { const models = ctx.fs.dc.models; const { id } = ctx.params; const findObj = { include: [ { model: models.User, attributes: ['id', 'name', 'username'], }, { model: models.TagDatabase, include: [{ model: models.Tag, }] }], where: { id: id }, } const rslt = await models.MetadataDatabase.findOne(findObj); ctx.status = 200; ctx.body = rslt; } catch (error) { ctx.fs.logger.error(`path: ${ctx.path}, error: ${error}`); ctx.status = 400; ctx.body = { "message": "获取元数据基本信息失败" } } } //打标元数据 async function postTagMetadata(ctx) { const transaction = await ctx.fs.dc.orm.transaction(); try { const { tags, database, file, restapi } = ctx.request.body; const models = ctx.fs.dc.models; if (tags.length && (database || file || restapi)) { if (database) { await models.TagDatabase.destroy({ where: { database: database }, transaction }); const data = tags.map(tag => { return { tagId: tag, database: database } }); if (data.length) await models.TagDatabase.bulkCreate(data, { transaction }); } if (file) { await models.TagFile.destroy({ where: { file: file }, transaction }); const data = tags.map(tag => { return { tagId: tag, file: file } }); if (data.length) await models.TagFile.bulkCreate(data, { transaction }); } if (restapi) { await models.TagRestapi.destroy({ where: { restapi: restapi }, transaction }); const data = tags.map(tag => { return { tagId: tag, restapi: restapi } }); if (data.length) await models.TagRestapi.bulkCreate(data, { transaction }); } await transaction.commit(); ctx.status = 204; } else { ctx.body = { message: '参数不全,请重新配置' } ctx.status = 400; } } catch (error) { await transaction.rollback(); ctx.fs.logger.error(`path: ${ctx.path}, error: ${error}`); ctx.status = 400; ctx.body = { "message": "打标元数据失败" } } } //获取元数据已打标数据 async function getTagMetadata(ctx) { try { const models = ctx.fs.dc.models; const { id } = ctx.params; const { type } = ctx.query; let rslt = []; if (type === 'database') { rslt = await models.Tag.findAll({ where: { '$tagDatabases.database$': id }, include: [{ model: models.TagDatabase, }], order: [['id', 'asc']], }); } if (type === 'file') { rslt = await models.Tag.findAll({ where: { '$tagFiles.file$': id }, include: [{ model: models.TagFile, }], order: [['id', 'asc']], }); } if (type === 'restapi') { rslt = await models.Tag.findAll({ where: { '$tagRestapis.restapi$': id }, include: [{ model: models.TagRestapi, }], order: [['id', 'asc']], }); } ctx.status = 200; ctx.body = rslt; } catch (error) { ctx.fs.logger.error(`path: ${ctx.path}, error: ${error}`); ctx.status = 400; ctx.body = { "message": "获取元数据已打标数据失败" } } } //申请资源 async function postMetadataResourceApplications(ctx) { try { const { resourceName, applyBy, resourceType } = ctx.request.body; if (!resourceName || !applyBy || !resourceType) { ctx.status = 400; ctx.body = { message: '参数不全,请重新申请资源' } } else { const models = ctx.fs.dc.models; const postOne = await models.ResourceConsumption.findOne({ where: { applyBy: applyBy, resourceName: resourceName } }); if (postOne) { ctx.status = 400; ctx.body = { message: '该用户已申请过该元数据资源' } } else { await models.ResourceConsumption.create({ applyAt: moment(), approveState: '审批中', ...ctx.request.body }); ctx.body = { message: '申请资源成功' } ctx.status = 200; } } } catch (error) { ctx.fs.logger.error(`path: ${ctx.path}, error: ${error}`); ctx.status = 400; ctx.body = { "message": "申请资源失败" } } } //获取元数据资源申请记录 async function getMetadataResourceApplications(ctx) { try { const models = ctx.fs.dc.models; const { resourceNames, type } = ctx.query; let rslt = []; if (resourceNames && type) { rslt = await models.ResourceConsumption.findAll({ where: { resourceName: { $in: resourceNames.split(',') }, resourceType: type } }); } ctx.status = 200; ctx.body = rslt; } catch (error) { ctx.fs.logger.error(`path: ${ctx.path}, error: ${error}`); ctx.status = 400; ctx.body = { "message": "获取元数据资源申请记录失败" } } } //新建文件元数据 async function postMetadataFiles(ctx) { try { const { name, catalog, type, fileName } = ctx.request.body; const models = ctx.fs.dc.models; const postOne = await models.MetadataFile.findOne({ where: { name: name, catalog: catalog } }); if (postOne) { ctx.status = 400; ctx.body = { message: '该资源目录下元数据名称已存在' } } else { if (!name || !catalog || !type || !fileName) { ctx.body = { message: '参数不全,请重新配置' } ctx.status = 400; } else { await models.MetadataFile.create({ createAt: moment(), ...ctx.request.body }); ctx.body = { message: '新建元数据成功' } ctx.status = 200; } } } catch (error) { ctx.fs.logger.error(`path: ${ctx.path}, error: ${error}`); ctx.status = 400; ctx.body = { "message": "新建元数据失败" } } } //修改文件元数据 async function putMetadataFiles(ctx) { try { const { id } = ctx.params; const { updateFileName } = ctx.query; const { catalog, name, type } = ctx.request.body; const models = ctx.fs.dc.models; let metadataFileInfo = await models.MetadataFile.findOne({ where: { id } }); if (metadataFileInfo) { if (updateFileName) {//编辑时,将文件删除,后又取消,则更新文件名为null await models.MetadataFile.update({ updateAt: moment(), fileName: null }, { where: { id: id } }); ctx.status = 204; } else { if (!name || !catalog || !type) { ctx.body = { message: '参数不全,请重新配置' } ctx.status = 400; } else { const putOne = await models.MetadataFile.findOne({ where: { id: { $not: id }, catalog: catalog, name: name } }); if (putOne) { ctx.status = 400; ctx.body = { message: '该元数据名称已存在' } } else { await models.MetadataFile.update({ updateAt: moment(), ...ctx.request.body }, { where: { id: id } }); ctx.status = 200; ctx.body = { message: '修改元数据成功' } } } } } else { ctx.status = 400; ctx.body = { message: '该元数据不存在' } } } catch (error) { ctx.fs.logger.error(`path: ${ctx.path}, error: ${error}`); ctx.status = 400; ctx.body = { "message": "修改元数据失败" } } } //删除文件元数据 async function delMetadataFiles(ctx) { const transaction = await ctx.fs.dc.orm.transaction(); try { const models = ctx.fs.dc.models; const { id } = ctx.params; let metadataFileInfo = await models.MetadataFile.findOne({ where: { id } }); if (metadataFileInfo) { let deletable = true; let tagFileInfo = await models.TagFile.findOne({ where: { file: id } }); if (tagFileInfo) { ctx.status = 400; ctx.body = { message: '该元数据已被打标' } deletable = false; } else { let resourceConsumptionInfo = await models.ResourceConsumption.findOne({ where: { resourceName: metadataFileInfo.name, resourceType: '文件' } }); if (resourceConsumptionInfo) { ctx.status = 400; ctx.body = { message: '该元数据存在资源申请' } deletable = false; } } if (deletable) { await models.MetadataFile.destroy({ where: { id: id }, transaction }) await transaction.commit(); ctx.status = 200; ctx.body = { message: '删除元数据成功' } } } else { ctx.status = 400; ctx.body = { message: '该元数据不存在' } } } catch (error) { await transaction.rollback(); ctx.fs.logger.error(`path: ${ctx.path}, error: ${error}`); ctx.status = 400; ctx.body = { message: '删除元数据失败' } } } //新建接口元数据 async function postMetadataRestapis(ctx) { try { const { name, catalog, method, url } = ctx.request.body; const models = ctx.fs.dc.models; const postOne = await models.MetadataRestapi.findOne({ where: { name: name, catalog: catalog } }); if (postOne) { ctx.status = 400; ctx.body = { message: '该资源目录下元数据名称已存在' } } else { if (!name || !catalog || !method || !url) { ctx.body = { message: '参数不全,请重新配置' } ctx.status = 400; } else { await models.MetadataRestapi.create({ createAt: moment(), ...ctx.request.body }); ctx.body = { message: '新建元数据成功' } ctx.status = 200; } } } catch (error) { ctx.fs.logger.error(`path: ${ctx.path}, error: ${error}`); ctx.status = 400; ctx.body = { "message": "新建元数据失败" } } } //修改接口元数据 async function putMetadataRestapis(ctx) { try { const { id } = ctx.params; const { catalog, name, method, url } = ctx.request.body; const models = ctx.fs.dc.models; let metadataRestapiInfo = await models.MetadataRestapi.findOne({ where: { id } }); if (metadataRestapiInfo) { if (!name || !catalog || !method || !url) { ctx.body = { message: '参数不全,请重新修改' } ctx.status = 400; } else { const putOne = await models.MetadataRestapi.findOne({ where: { id: { $not: id }, catalog: catalog, name: name } }); if (putOne) { ctx.status = 400; ctx.body = { message: '该元数据名称已存在' } } else { await models.MetadataRestapi.update({ updateAt: moment(), ...ctx.request.body }, { where: { id: id } }); ctx.status = 200; ctx.body = { message: '修改元数据成功' } } } } else { ctx.status = 400; ctx.body = { message: '该元数据不存在' } } } catch (error) { ctx.fs.logger.error(`path: ${ctx.path}, error: ${error}`); ctx.status = 400; ctx.body = { "message": "修改元数据失败" } } } //删除接口元数据 async function delMetadataRestapis(ctx) { const transaction = await ctx.fs.dc.orm.transaction(); try { const models = ctx.fs.dc.models; const { id } = ctx.params; let metadataRestapiInfo = await models.MetadataRestapi.findOne({ where: { id } }); if (metadataRestapiInfo) { let deletable = true; let tagRestapiInfo = await models.TagRestapi.findOne({ where: { restapi: id } }); if (tagRestapiInfo) { ctx.status = 400; ctx.body = { message: '该元数据已被打标' } deletable = false; } else { let resourceConsumptionInfo = await models.ResourceConsumption.findOne({ where: { resourceName: metadataRestapiInfo.name, resourceType: '接口' } }); if (resourceConsumptionInfo) { ctx.status = 400; ctx.body = { message: '该元数据存在资源申请' } deletable = false; } } if (deletable) { await models.MetadataRestapi.destroy({ where: { id: id }, transaction }) await transaction.commit(); ctx.status = 200; ctx.body = { message: '删除元数据成功' } } } else { ctx.status = 400; ctx.body = { message: '该元数据不存在' } } } catch (error) { await transaction.rollback(); ctx.fs.logger.error(`path: ${ctx.path}, error: ${error}`); ctx.status = 400; ctx.body = { message: '删除元数据失败' } } } module.exports = { getResourceCatalog, postResourceCatalog, putResourceCatalog, delResourceCatalog, getMetadataDatabases, getMetadataFiles, getMetadataRestapis, getMetadataModels, postMetadataDatabases, putMetadataDatabases, delMetadataDatabases, getMetadataDatabasesById, postTagMetadata, getTagMetadata, postMetadataResourceApplications, getMetadataResourceApplications, postMetadataFiles, putMetadataFiles, delMetadataFiles, postMetadataRestapis, putMetadataRestapis, delMetadataRestapis }