chore: history projectId

This commit is contained in:
xiaojunnuo
2026-02-11 18:11:33 +08:00
parent 806a69fef3
commit 638a7f0ab4
15 changed files with 224 additions and 146 deletions

View File

@@ -15,25 +15,25 @@
},
"scripts": {
"start": "lerna bootstrap --hoist",
"start:server": "cd ./packages/ui/certd-server && npm start",
"start:server": "cd ./packages/ui/certd-server && pnpm start",
"devb": "lerna run dev-build",
"i-all": "lerna link && lerna exec npm install ",
"publish": "npm run prepublishOnly2 && lerna publish --force-publish=pro/plus-core --conventional-commits && npm run afterpublishOnly ",
"afterpublishOnly": "npm run copylogs && time /t >trigger/build.trigger && git add ./trigger/build.trigger && git commit -m \"build: trigger build image\" && TIMEOUT /T 10 && npm run commitAll",
"publish": "pnpm run prepublishOnly2 && lerna publish --force-publish=pro/plus-core --conventional-commits && pnpm run afterpublishOnly ",
"afterpublishOnly": "pnpm run copylogs && time /t >trigger/build.trigger && git add ./trigger/build.trigger && git commit -m \"build: trigger build image\" && TIMEOUT /T 10 && pnpm run commitAll",
"transform-sql": "cd ./packages/ui/certd-server/db/ && node --experimental-json-modules transform.js",
"plugin-doc-gen": "cd ./packages/ui/certd-server/ && npm run export-metadata",
"commitAll": "git add . && git commit -m \"build: publish\" && git push && npm run commitPro",
"plugin-doc-gen": "cd ./packages/ui/certd-server/ && pnpm run export-metadata",
"commitAll": "git add . && git commit -m \"build: publish\" && git push && pnpm run commitPro",
"commitPro": "cd ./packages/pro/ && git add . && git commit -m \"build: publish\" && git push",
"copylogs": "copyfiles \"CHANGELOG.md\" ./docs/guide/changelogs/",
"prepublishOnly1": "npm run check && lerna run build ",
"prepublishOnly2": "npm run check && npm run before-build && lerna run build && npm run plugin-doc-gen",
"before-build": "npm run transform-sql && cd ./packages/core/basic && time /t >build.md && git add ./build.md && git commit -m \"build: prepare to build\"",
"prepublishOnly1": "pnpm run check && lerna run build ",
"prepublishOnly2": "pnpm run check && pnpm run before-build && lerna run build && pnpm run plugin-doc-gen",
"before-build": "pnpm run transform-sql && cd ./packages/core/basic && time /t >build.md && git add ./build.md && git commit -m \"build: prepare to build\"",
"deploy1": "node --experimental-json-modules ./scripts/deploy.js ",
"check": "node --experimental-json-modules ./scripts/publish-check.js",
"init": "lerna run build",
"init:dev": "lerna run build",
"docs:dev": "vitepress dev docs",
"docs:build": "npm run copylogs && vitepress build docs",
"docs:build": "pnpm run copylogs && vitepress build docs",
"docs:preview": "vitepress preview docs",
"pub": "echo 1",
"dev": "pnpm run -r --parallel compile ",

View File

@@ -100,5 +100,20 @@ export abstract class BaseController {
await projectService.checkPermission({userId,projectId,permission})
}
/**
*
* @param service 检查记录是否属于某用户或某项目
* @param id
*/
async checkEntityOwner(service:any,id:number,permission:string){
let { projectId,userId } = await this.getProjectUserId(permission)
const authService:any = await this.applicationContext.getAsync("authService");
if (projectId) {
await authService.checkEntityProjectId(service, id, projectId);
}else{
await authService.checkEntityUserId(this.ctx, service, id);
}
return {projectId,userId}
}
}

View File

@@ -206,18 +206,28 @@ export abstract class BaseService<T> {
return await qb.getMany();
}
async checkUserId(id: any = 0, userId: number, userKey = 'userId') {
const res = await this.getRepository().findOne({
async checkUserId(ids: number | number[] = 0, userId: number, userKey = 'userId') {
if (ids == null) {
throw new ValidateException('id不能为空');
}
if (userId == null) {
throw new ValidateException('userId不能为空');
}
if (!Array.isArray(ids)) {
ids = [ids];
}
const res = await this.getRepository().find({
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-ignore
select: { [userKey]: true },
where: {
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-ignore
id,
id: In(ids),
[userKey]: userId,
},
});
if (!res || res[userKey] === userId) {
if (!res || res.length === ids.length) {
return;
}
throw new PermissionException('权限不足');

View File

@@ -52,12 +52,17 @@ export const useProjectStore = defineStore("app.project", () => {
}
const projects = await api.MyProjectList();
myProjects.value = projects;
if (projects.length > 0 && !currentProjectId.value) {
changeCurrentProject(projects[0].id, true);
}
}
function changeCurrentProject(id: string) {
function changeCurrentProject(id: string, silent?: boolean) {
currentProjectId.value = id;
LocalStorage.set("currentProjectId", id);
message.success("切换项目成功");
if (!silent) {
message.success("切换项目成功");
}
}
async function reload() {

View File

@@ -19,6 +19,8 @@ export const projectPermissionDict = dict({
export const myProjectDict = dict({
url: "/enterprise/project/list",
value: "id",
label: "name",
});
export const userDict = dict({

View File

@@ -640,6 +640,9 @@ export default function ({ crudExpose, context: { selectedRowKeys, openCertApply
title: t("certd.fields.projectName"),
type: "dict-select",
dict: myProjectDict,
form: {
show: false,
},
},
updateTime: {
title: t("certd.fields.updateTime"),

View File

@@ -13,8 +13,7 @@ CREATE TABLE "cd_project"
CREATE INDEX "index_project_user_id" ON "cd_project" ("user_id");
CREATE INDEX "index_project_admin_id" ON "cd_project" ("admin_id");
INSERT INTO cd_project (id, user_id, "name", "disabled") VALUES (1, 1, 'default', false);
INSERT INTO cd_project (id, user_id, "admin_id", "name", "disabled") VALUES (1, 0, 1,'default', false);
ALTER TABLE cd_cert_info ADD COLUMN project_id integer;
CREATE INDEX "index_cert_project_id" ON "cd_cert_info" ("project_id");

View File

@@ -19,16 +19,16 @@
"dev-new": "cross-env NODE_ENV=dev-new mwtsc --watch --run @midwayjs/mock/app",
"rm-newdb": "rimraf ./data/db-new.sqlite",
"test": "cross-env NODE_ENV=unittest mocha",
"cov": "cross-env c8 --all --reporter=text --reporter=lcovonly npm run test",
"cov": "cross-env c8 --all --reporter=text --reporter=lcovonly pnpm run test",
"lint": "mwts check",
"lint:fix": "mwts fix",
"ci": "npm run cov",
"ci": "pnpm run cov",
"build-only": "cross-env NODE_ENV=production mwtsc --cleanOutDir --skipLibCheck",
"build": "npm run build-only && npm run export-metadata",
"build": "pnpm run build-only && pnpm run export-metadata",
"export-metadata": "node export-plugin-yaml.js",
"export-metadata-only": "node export-plugin-yaml.js docoff",
"dev-build": "echo 1",
"build-on-docker": "node ./before-build.js && npm run build-only && npm run export-metadata-only",
"build-on-docker": "node ./before-build.js && pnpm run build-only && pnpm run export-metadata-only",
"up-mw-deps": "npx midway-version -u -w",
"heap": "cross-env NODE_ENV=production clinic heapprofiler -- node --optimize-for-size --inspect ./bootstrap.js",
"flame": "clinic flame -- node ./bootstrap.js",

View File

@@ -1,17 +1,17 @@
import { ALL, Body, Controller, Get, Inject, Post, Provide, Query } from "@midwayjs/core";
import { CommonException, Constants, CrudController, PermissionException, SysSettingsService } from "@certd/lib-server";
import { PipelineEntity } from "../../../modules/pipeline/entity/pipeline.js";
import { HistoryService } from "../../../modules/pipeline/service/history-service.js";
import { HistoryLogService } from "../../../modules/pipeline/service/history-log-service.js";
import { HistoryEntity } from "../../../modules/pipeline/entity/history.js";
import { HistoryLogEntity } from "../../../modules/pipeline/entity/history-log.js";
import { PipelineService } from "../../../modules/pipeline/service/pipeline-service.js";
import * as fs from "fs";
import { logger } from "@certd/basic";
import { AuthService } from "../../../modules/sys/authority/service/auth-service.js";
import { CommonException, Constants, CrudController, PermissionException, SysSettingsService } from "@certd/lib-server";
import { ALL, Body, Controller, Get, Inject, Post, Provide, Query } from "@midwayjs/core";
import * as fs from "fs";
import { In } from "typeorm";
import { UserSettingsService } from "../../../modules/mine/service/user-settings-service.js";
import { UserGrantSetting } from "../../../modules/mine/service/models.js";
import { UserSettingsService } from "../../../modules/mine/service/user-settings-service.js";
import { HistoryLogEntity } from "../../../modules/pipeline/entity/history-log.js";
import { HistoryEntity } from "../../../modules/pipeline/entity/history.js";
import { PipelineEntity } from "../../../modules/pipeline/entity/pipeline.js";
import { HistoryLogService } from "../../../modules/pipeline/service/history-log-service.js";
import { HistoryService } from "../../../modules/pipeline/service/history-service.js";
import { PipelineService } from "../../../modules/pipeline/service/pipeline-service.js";
import { AuthService } from "../../../modules/sys/authority/service/auth-service.js";
/**
* 证书
@@ -41,12 +41,18 @@ export class HistoryController extends CrudController<HistoryService> {
@Post('/page', { summary: Constants.per.authOnly })
async page(@Body(ALL) body: any) {
const { projectId, userId } = await this.getProjectUserIdRead()
body.query.projectId = projectId
const isAdmin = await this.authService.isAdmin(this.ctx);
const publicSettings = await this.sysSettingsService.getPublicSettings();
const pipelineQuery: any = {};
if (!(publicSettings.managerOtherUserPipeline && isAdmin)) {
body.query.userId = this.getUserId();
pipelineQuery.userId = this.getUserId();
body.query.userId = userId;
pipelineQuery.userId = userId;
}
if (projectId) {
pipelineQuery.projectId = projectId;
}
let pipelineIds: any = null;
@@ -82,10 +88,14 @@ export class HistoryController extends CrudController<HistoryService> {
@Post('/list', { summary: Constants.per.authOnly })
async list(@Body(ALL) body) {
const { projectId, userId } = await this.getProjectUserIdRead()
body.query.projectId = projectId
const isAdmin = this.authService.isAdmin(this.ctx);
if (!isAdmin) {
body.userId = this.getUserId();
body.userId = userId;
}
if (body.pipelineId == null) {
return this.ok([]);
}
@@ -106,7 +116,8 @@ export class HistoryController extends CrudController<HistoryService> {
triggerType: true,
endTime: true,
createTime: true,
updateTime: true
updateTime: true,
projectId: true,
};
}
const listRet = await this.getService().list({
@@ -135,32 +146,45 @@ export class HistoryController extends CrudController<HistoryService> {
@Post('/add', { summary: Constants.per.authOnly })
async add(@Body(ALL) bean: PipelineEntity) {
bean.userId = this.getUserId();
const { projectId, userId } = await this.getProjectUserIdRead()
bean.projectId = projectId
bean.userId = userId;
return super.add(bean);
}
@Post('/update', { summary: Constants.per.authOnly })
async update(@Body(ALL) bean) {
await this.authService.checkEntityUserId(this.ctx, this.getService(), bean.id);
await this.checkEntityOwner(this.getService(), bean.id,"write");
delete bean.userId;
return super.update(bean);
}
@Post('/save', { summary: Constants.per.authOnly })
async save(@Body(ALL) bean: HistoryEntity) {
bean.userId = this.getUserId();
const { projectId,userId } = await this.getProjectUserIdWrite()
bean.userId = userId;
bean.projectId = projectId;
if (bean.id > 0) {
await this.authService.checkEntityUserId(this.ctx, this.getService(), bean.id);
//修改
delete bean.projectId;
delete bean.userId;
await this.checkEntityOwner(this.getService(), bean.id,"write");
}
await this.service.save(bean);
return this.ok(bean.id);
}
@Post('/saveLog', { summary: Constants.per.authOnly })
async saveLog(@Body(ALL) bean: HistoryLogEntity) {
bean.userId = this.getUserId();
const { projectId,userId } = await this.getProjectUserIdWrite()
bean.projectId = projectId;
bean.userId = userId;
if (bean.id > 0) {
await this.authService.checkEntityUserId(this.ctx, this.getService(), bean.id);
//修改
delete bean.projectId;
delete bean.userId;
await this.checkEntityOwner(this.logService, bean.id,"write");
}
await this.logService.save(bean);
return this.ok(bean.id);
@@ -168,30 +192,30 @@ export class HistoryController extends CrudController<HistoryService> {
@Post('/delete', { summary: Constants.per.authOnly })
async delete(@Query('id') id: number) {
await this.authService.checkEntityUserId(this.ctx, this.getService(), id);
await this.checkEntityOwner(this.getService(), id,"write");
await super.delete(id);
return this.ok();
}
@Post('/deleteByIds', { summary: Constants.per.authOnly })
async deleteByIds(@Body(ALL) body: any) {
await this.authService.checkEntityUserId(this.ctx, this.getService(), body.ids);
let {userId} = await this.checkEntityOwner(this.getService(), body.ids,"write");
const isAdmin = await this.authService.isAdmin(this.ctx);
const userId = isAdmin ? null : this.getUserId();
userId = isAdmin ? null : userId;
await this.getService().deleteByIds(body.ids, userId);
return this.ok();
}
@Post('/detail', { summary: Constants.per.authOnly })
async detail(@Query('id') id: number) {
await this.authService.checkEntityUserId(this.ctx, this.getService(), id);
await this.checkEntityOwner(this.getService(), id,"read");
const detail = await this.service.detail(id);
return this.ok(detail);
}
@Post('/logs', { summary: Constants.per.authOnly })
async logs(@Query('id') id: number) {
await this.authService.checkEntityUserId(this.ctx, this.logService, id);
await this.checkEntityOwner(this.logService, id,"read");
const logInfo = await this.logService.info(id);
return this.ok(logInfo);
}
@@ -213,7 +237,14 @@ export class HistoryController extends CrudController<HistoryService> {
if (history == null) {
throw new CommonException('historyId is null');
}
if (history.userId !== this.getUserId()) {
const {projectId} = await this.getProjectUserIdRead()
if (projectId) {
//enterprise模式
if(history.projectId !== projectId){
throw new PermissionException("您没有权限下载该流水线证书,请先加入该项目:"+history.projectId);
}
//有权限下载
}else if (history.userId !== this.getUserId()) {
// 如果是管理员,检查用户是否有授权管理员查看
const isAdmin = await this.isAdmin()
if (!isAdmin) {

View File

@@ -95,25 +95,16 @@ export class PipelineController extends CrudController<PipelineService> {
@Post('/update', { summary: Constants.per.authOnly })
async update(@Body(ALL) bean) {
const { projectId } = await this.getProjectUserIdWrite()
if (projectId) {
await this.authService.checkEntityProjectId(this.getService(), projectId, bean.id);
} else {
await this.authService.checkEntityUserId(this.ctx, this.getService(), bean.id);
}
await this.checkEntityOwner(this.getService(), bean.id,"write");
delete bean.userId;
return super.update(bean);
}
@Post('/save', { summary: Constants.per.authOnly })
async save(@Body(ALL) bean: { addToMonitorEnabled: boolean, addToMonitorDomains: string } & PipelineEntity) {
const { projectId, userId } = await this.getProjectUserIdWrite()
const { userId } = await this.getProjectUserIdWrite()
if (bean.id > 0) {
if (projectId) {
await this.authService.checkEntityProjectId(this.getService(), projectId, bean.id);
} else {
await this.authService.checkEntityUserId(this.ctx, this.getService(), bean.id);
}
await this.checkEntityOwner(this.getService(), bean.id,"write");
} else {
bean.userId = userId;
}
@@ -140,24 +131,14 @@ export class PipelineController extends CrudController<PipelineService> {
@Post('/delete', { summary: Constants.per.authOnly })
async delete(@Query('id') id: number) {
const { projectId } = await this.getProjectUserIdWrite()
if (projectId) {
await this.authService.checkEntityProjectId(this.getService(), projectId, id);
} else {
await this.authService.checkEntityUserId(this.ctx, this.getService(), id);
}
await this.checkEntityOwner(this.getService(), id,"write");
await this.service.delete(id);
return this.ok({});
}
@Post('/disabled', { summary: Constants.per.authOnly })
async disabled(@Body(ALL) bean) {
const { projectId } = await this.getProjectUserIdWrite()
if (projectId) {
await this.authService.checkEntityProjectId(this.getService(), projectId, bean.id);
} else {
await this.authService.checkEntityUserId(this.ctx, this.getService(), bean.id);
}
await this.checkEntityOwner(this.getService(), bean.id,"write");
delete bean.userId;
await this.service.disabled(bean.id, bean.disabled);
return this.ok({});
@@ -165,36 +146,21 @@ export class PipelineController extends CrudController<PipelineService> {
@Post('/detail', { summary: Constants.per.authOnly })
async detail(@Query('id') id: number) {
const { projectId } = await this.getProjectUserIdRead()
if (projectId) {
await this.authService.checkEntityProjectId(this.getService(), projectId, id);
} else {
await this.authService.checkEntityUserId(this.ctx, this.getService(), id);
}
await this.checkEntityOwner(this.getService(), id,"read");
const detail = await this.service.detail(id);
return this.ok(detail);
}
@Post('/trigger', { summary: Constants.per.authOnly })
async trigger(@Query('id') id: number, @Query('stepId') stepId?: string) {
const { projectId } = await this.getProjectUserIdWrite()
if (projectId) {
await this.authService.checkEntityProjectId(this.getService(), projectId, id);
} else {
await this.authService.checkEntityUserId(this.ctx, this.getService(), id);
}
await this.checkEntityOwner(this.getService(), id,"write");
await this.service.trigger(id, stepId, true);
return this.ok({});
}
@Post('/cancel', { summary: Constants.per.authOnly })
async cancel(@Query('historyId') historyId: number) {
const { projectId } = await this.getProjectUserIdWrite()
if (projectId) {
await this.authService.checkEntityProjectId(this.historyService, projectId, historyId);
} else {
await this.authService.checkEntityUserId(this.ctx, this.historyService, historyId);
}
await this.checkEntityOwner(this.historyService, historyId,"write");
await this.service.cancel(historyId);
return this.ok({});
}

View File

@@ -66,7 +66,8 @@ export class HistoryService extends BaseService<HistoryEntity> {
pipelineId: pipeline.id,
title: pipeline.title,
status: 'start',
triggerType
triggerType,
projectId: pipeline.projectId,
};
const { id } = await this.add(bean);
//清除大于pipeline.keepHistoryCount的历史记录

View File

@@ -747,20 +747,35 @@ export class PipelineService extends BaseService<PipelineEntity> {
return;
}
async getProjectId(pipelineId: number) {
const pipelineEntity = await this.repository.findOne({
select: {
projectId: true,
},
where: {
id: pipelineId,
},
});
return pipelineEntity.projectId;
}
private async saveHistory(history: RunHistory) {
//修改pipeline状态
const pipelineEntity = new PipelineEntity();
let pipelineEntity = new PipelineEntity();
pipelineEntity.id = parseInt(history.pipeline.id);
pipelineEntity.status = history.pipeline.status.result + "";
pipelineEntity.lastHistoryTime = history.pipeline.status.startTime;
await this.update(pipelineEntity);
const projectId = await this.getProjectId(pipelineEntity.id);
pipelineEntity.projectId = projectId;
const entity: HistoryEntity = new HistoryEntity();
entity.id = parseInt(history.id);
entity.userId = history.pipeline.userId;
entity.status = pipelineEntity.status;
entity.pipeline = JSON.stringify(history.pipeline);
entity.pipelineId = parseInt(history.pipeline.id);
entity.projectId = pipelineEntity.projectId;
await this.historyService.save(entity);
const logEntity: HistoryLogEntity = new HistoryLogEntity();
@@ -769,6 +784,7 @@ export class PipelineService extends BaseService<PipelineEntity> {
logEntity.pipelineId = entity.pipelineId;
logEntity.historyId = entity.id;
logEntity.logs = JSON.stringify(history.logs);
logEntity.projectId = pipelineEntity.projectId;
await this.historyLogService.addOrUpdate(logEntity);
}
@@ -984,7 +1000,7 @@ export class PipelineService extends BaseService<PipelineEntity> {
throw new NeedVIPException("此功能需要升级专业版");
}
if (!userId || ids.length === 0) {
if (userId == null || ids.length === 0) {
return;
}
const where:any = {

View File

@@ -28,15 +28,15 @@ export class AuthService {
}
//管理员有权限查看其他用户的数据
async checkEntityUserId(ctx: any, service: any, id: any = 0, userKey = 'userId') {
async checkEntityUserId(ctx: any, service: any, ids: number| number[] = null, userKey = 'userId') {
const isAdmin = await this.isAdmin(ctx);
if (isAdmin) {
return true;
}
await service.checkUserId(id, ctx.user.id, userKey);
await service.checkUserId(ids, ctx.user.id, userKey);
}
async checkEntityProjectId(service:any,projectId = 0,id:any=0){
await service.checkUserId(id, projectId , "projectId");
async checkEntityProjectId(service:any,ids:number| number[] = null,projectId = null){
await service.checkUserId(ids, projectId , "projectId");
}
}

View File

@@ -9,6 +9,12 @@ import { PermissionService } from './permission-service.js';
import * as _ from 'lodash-es';
import { RolePermissionService } from './role-permission-service.js';
import { LRUCache } from 'lru-cache';
const permissionCache = new LRUCache<string, any>({
max: 1000,
ttl: 1000 * 60 * 10,
});
/**
* 角色
*/
@@ -24,10 +30,7 @@ export class RoleService extends BaseService<RoleEntity> {
@Inject()
rolePermissionService: RolePermissionService;
permissionCache = new LRUCache<string, any>({
max: 1000,
ttl: 1000 * 60 * 10,
});
//@ts-ignore
getRepository() {
@@ -84,7 +87,7 @@ export class RoleService extends BaseService<RoleEntity> {
//再添加
await this.addRoles(userId, roles);
this.permissionCache.clear();
permissionCache.clear();
}
async getPermissionTreeByRoleId(id: any) {
@@ -105,7 +108,7 @@ export class RoleService extends BaseService<RoleEntity> {
permissionId,
});
}
this.permissionCache.clear();
permissionCache.clear();
}
async getPermissionSetByRoleIds(roleIds: number[]): Promise<Set<string>> {
@@ -120,12 +123,12 @@ export class RoleService extends BaseService<RoleEntity> {
async getCachedPermissionSetByRoleIds(roleIds: number[]): Promise<Set<string>> {
const roleIdsKey = roleIds.join(',');
let permissionSet = this.permissionCache.get(roleIdsKey);
let permissionSet = permissionCache.get(roleIdsKey);
if (permissionSet) {
return permissionSet;
}
permissionSet = await this.getPermissionSetByRoleIds(roleIds);
this.permissionCache.set(roleIdsKey, permissionSet);
permissionCache.set(roleIdsKey, permissionSet);
return permissionSet;
}

View File

@@ -1,10 +1,16 @@
import { BaseService, SysSettingsService } from '@certd/lib-server';
import { Inject, Provide, Scope, ScopeEnum } from '@midwayjs/core';
import { InjectEntityModel } from '@midwayjs/typeorm';
import { LRUCache } from 'lru-cache';
import { Repository } from 'typeorm';
import { ProjectEntity } from '../entity/project.js';
import { ProjectMemberService } from './project-member-service.js';
const projectCache = new LRUCache<string, any>({
max: 1000,
ttl: 1000 * 60 * 10,
});
@Provide()
@Scope(ScopeEnum.Request, { allowDowngrade: true })
export class ProjectService extends BaseService<ProjectEntity> {
@@ -23,7 +29,7 @@ export class ProjectService extends BaseService<ProjectEntity> {
}
async add(bean: ProjectEntity) {
const {name} = bean;
const { name } = bean;
if (!name) {
throw new Error('项目名称不能为空');
}
@@ -33,17 +39,25 @@ export class ProjectService extends BaseService<ProjectEntity> {
userId: 0,
},
});
if (exist) {
throw new Error('项目名称已存在');
}
bean.disabled = false
return await super.add(bean)
if (exist) {
throw new Error('项目名称已存在');
}
bean.disabled = false
const res= await super.add(bean)
projectCache.clear();
return res;
}
async update( bean: ProjectEntity) {
const res= await super.update(bean)
projectCache.clear();
return res;
}
async setDisabled(id: number, disabled: boolean) {
await this.repository.update({
id,
userId:0,
userId: 0,
}, {
disabled,
});
@@ -55,7 +69,7 @@ export class ProjectService extends BaseService<ProjectEntity> {
const projectIds = memberList.map(item => item.projectId);
const projectList = await this.repository.createQueryBuilder('project')
.where(' project.disabled = false')
.where(' project.userId = :userId', { userId:0 })
.where(' project.userId = :userId', { userId: 0 })
.where(' project.id IN (:...projectIds) or project.adminId = :userId', { projectIds, userId })
.getMany();
@@ -67,7 +81,7 @@ export class ProjectService extends BaseService<ProjectEntity> {
projectList.forEach(item => {
if (item.adminId === userId) {
item.permission = 'admin';
}else{
} else {
item.permission = memberPermissionMap[item.id] || 'read';
}
})
@@ -75,21 +89,21 @@ export class ProjectService extends BaseService<ProjectEntity> {
return projectList
}
async checkAdminPermission({userId, projectId}: {userId: number, projectId: number}) {
async checkAdminPermission({ userId, projectId }: { userId: number, projectId: number }) {
return await this.checkPermission({
userId,
projectId,
permission: 'admin',
})
}
async checkWritePermission({userId, projectId}: {userId: number, projectId: number}) {
async checkWritePermission({ userId, projectId }: { userId: number, projectId: number }) {
return await this.checkPermission({
userId,
projectId,
permission: 'write',
})
}
async checkReadPermission({userId, projectId}: {userId: number, projectId: number}) {
async checkReadPermission({ userId, projectId }: { userId: number, projectId: number }) {
return await this.checkPermission({
userId,
projectId,
@@ -97,47 +111,60 @@ export class ProjectService extends BaseService<ProjectEntity> {
})
}
async checkPermission({userId, projectId, permission}: {userId: number, projectId: number, permission: string}) {
if (permission !== 'admin' && permission !== 'write' && permission !== 'read') {
throw new Error('权限类型错误');
}
if (!userId ){
throw new Error('用户ID不能为空');
}
if (!projectId ){
throw new Error('项目ID不能为空');
}
const project = await this.findOne({
select: ['id', 'userId', 'adminId', 'disabled'],
where: {
id: projectId,
},
});
if (!project) {
throw new Error('项目不存在');
async checkPermission({ userId, projectId, permission }: { userId: number, projectId: number, permission: string }) {
if (permission !== 'admin' && permission !== 'write' && permission !== 'read') {
throw new Error('权限类型错误');
}
if (project.adminId === userId) {
//创建者拥有管理权限
return true
if (!userId) {
throw new Error('用户ID不能为空');
}
if (project.disabled) {
throw new Error('项目已禁用');
if (!projectId) {
throw new Error('项目ID不能为空');
}
const member = await this.projectMemberService.getMember(projectId,userId);
if (!member) {
throw new Error('项目成员不存在');
const cacheKey = `projectPermission:${projectId}:${userId}`
let savedPermission = projectCache.get(cacheKey);
if (!savedPermission){
const project = await this.findOne({
select: ['id', 'userId', 'adminId', 'disabled'],
where: {
id: projectId,
},
});
if (!project) {
throw new Error('项目不存在');
}
if (project.adminId === userId) {
//创建者拥有管理权限
savedPermission = 'admin';
}else{
if (project.disabled) {
throw new Error('项目已禁用');
}
const member = await this.projectMemberService.getMember(projectId, userId);
if (!member) {
throw new Error('项目成员不存在');
}
savedPermission = member.permission;
}
}
projectCache.set(cacheKey, savedPermission,{ttl: 3 * 60 * 1000});
if (!savedPermission) {
throw new Error('权限不足');
}
if (permission === 'read') {
return true
}
if (permission === 'write') {
if (member.permission === 'admin' || member.permission === 'write') {
if (savedPermission === 'admin' || savedPermission === 'write') {
return true
}else{
} else {
throw new Error('权限不足');
}
}
if (member.permission !== permission) {
if (savedPermission !== permission) {
throw new Error('权限不足');
}
return true