Add user-scoped data filtering for env operations

Co-authored-by: whyour <22700758+whyour@users.noreply.github.com>
This commit is contained in:
copilot-swe-agent[bot] 2025-11-07 16:33:31 +00:00
parent 489454daa0
commit f355b4e441
2 changed files with 51 additions and 22 deletions

View File

@ -26,7 +26,7 @@ export default (app: Router) => {
const logger: Logger = Container.get('logger'); const logger: Logger = Container.get('logger');
try { try {
const envService = Container.get(EnvService); const envService = Container.get(EnvService);
const data = await envService.envs(req.query.searchValue as string); const data = await envService.envs(req.query.searchValue as string, {}, req.user?.userId);
return res.send({ code: 200, data }); return res.send({ code: 200, data });
} catch (e) { } catch (e) {
logger.error('🔥 error: %o', e); logger.error('🔥 error: %o', e);
@ -54,7 +54,7 @@ export default (app: Router) => {
if (!req.body?.length) { if (!req.body?.length) {
return res.send({ code: 400, message: '参数不正确' }); return res.send({ code: 400, message: '参数不正确' });
} }
const data = await envService.create(req.body); const data = await envService.create(req.body, req.user?.userId);
return res.send({ code: 200, data }); return res.send({ code: 200, data });
} catch (e) { } catch (e) {
return next(e); return next(e);
@ -93,10 +93,10 @@ export default (app: Router) => {
const logger: Logger = Container.get('logger'); const logger: Logger = Container.get('logger');
try { try {
const envService = Container.get(EnvService); const envService = Container.get(EnvService);
const data = await envService.remove(req.body); const data = await envService.remove(req.body, req.user?.userId);
return res.send({ code: 200, data }); return res.send({ code: 200, data });
} catch (e) { } catch (e: any) {
return next(e); return res.send({ code: 400, message: e.message });
} }
}, },
); );
@ -132,10 +132,10 @@ export default (app: Router) => {
const logger: Logger = Container.get('logger'); const logger: Logger = Container.get('logger');
try { try {
const envService = Container.get(EnvService); const envService = Container.get(EnvService);
const data = await envService.disabled(req.body); const data = await envService.disabled(req.body, req.user?.userId);
return res.send({ code: 200, data }); return res.send({ code: 200, data });
} catch (e) { } catch (e: any) {
return next(e); return res.send({ code: 400, message: e.message });
} }
}, },
); );
@ -149,10 +149,10 @@ export default (app: Router) => {
const logger: Logger = Container.get('logger'); const logger: Logger = Container.get('logger');
try { try {
const envService = Container.get(EnvService); const envService = Container.get(EnvService);
const data = await envService.enabled(req.body); const data = await envService.enabled(req.body, req.user?.userId);
return res.send({ code: 200, data }); return res.send({ code: 200, data });
} catch (e) { } catch (e: any) {
return next(e); return res.send({ code: 400, message: e.message });
} }
}, },
); );
@ -169,10 +169,10 @@ export default (app: Router) => {
const logger: Logger = Container.get('logger'); const logger: Logger = Container.get('logger');
try { try {
const envService = Container.get(EnvService); const envService = Container.get(EnvService);
const data = await envService.updateNames(req.body); const data = await envService.updateNames(req.body, req.user?.userId);
return res.send({ code: 200, data }); return res.send({ code: 200, data });
} catch (e) { } catch (e: any) {
return next(e); return res.send({ code: 400, message: e.message });
} }
}, },
); );

View File

@ -19,8 +19,32 @@ import { writeFileWithLock } from '../shared/utils';
export default class EnvService { export default class EnvService {
constructor(@Inject('logger') private logger: winston.Logger) {} constructor(@Inject('logger') private logger: winston.Logger) {}
public async create(payloads: Env[]): Promise<Env[]> { private addUserIdFilter(query: any, userId?: number) {
const envs = await this.envs(); if (userId !== undefined) {
query.userId = userId;
}
return query;
}
private async checkOwnership(ids: number[], userId?: number): Promise<void> {
if (userId === undefined) {
// Admin can access all envs
return;
}
const envs = await EnvModel.findAll({
where: { id: ids },
attributes: ['id', 'userId'],
});
const unauthorized = envs.filter(
(env) => env.userId !== userId && env.userId !== undefined
);
if (unauthorized.length > 0) {
throw new Error('无权限操作该环境变量');
}
}
public async create(payloads: Env[], userId?: number): Promise<Env[]> {
const envs = await this.envs('', {}, userId);
let position = initPosition; let position = initPosition;
if ( if (
envs && envs &&
@ -31,7 +55,7 @@ export default class EnvService {
} }
const tabs = payloads.map((x) => { const tabs = payloads.map((x) => {
position = position - stepPosition; position = position - stepPosition;
const tab = new Env({ ...x, position }); const tab = new Env({ ...x, position, userId });
return tab; return tab;
}); });
const docs = await this.insert(tabs); const docs = await this.insert(tabs);
@ -62,7 +86,8 @@ export default class EnvService {
return await this.getDb({ id: payload.id }); return await this.getDb({ id: payload.id });
} }
public async remove(ids: number[]) { public async remove(ids: number[], userId?: number) {
await this.checkOwnership(ids, userId);
await EnvModel.destroy({ where: { id: ids } }); await EnvModel.destroy({ where: { id: ids } });
await this.set_envs(); await this.set_envs();
} }
@ -119,8 +144,9 @@ export default class EnvService {
return parseFloat(position.toPrecision(16)); return parseFloat(position.toPrecision(16));
} }
public async envs(searchText: string = '', query: any = {}): Promise<Env[]> { public async envs(searchText: string = '', query: any = {}, userId?: number): Promise<Env[]> {
let condition = { ...query }; let condition = { ...query };
this.addUserIdFilter(condition, userId);
if (searchText) { if (searchText) {
const encodeText = encodeURI(searchText); const encodeText = encodeURI(searchText);
const reg = { const reg = {
@ -172,7 +198,8 @@ export default class EnvService {
return doc.get({ plain: true }); return doc.get({ plain: true });
} }
public async disabled(ids: number[]) { public async disabled(ids: number[], userId?: number) {
await this.checkOwnership(ids, userId);
await EnvModel.update( await EnvModel.update(
{ status: EnvStatus.disabled }, { status: EnvStatus.disabled },
{ where: { id: ids } }, { where: { id: ids } },
@ -180,12 +207,14 @@ export default class EnvService {
await this.set_envs(); await this.set_envs();
} }
public async enabled(ids: number[]) { public async enabled(ids: number[], userId?: number) {
await this.checkOwnership(ids, userId);
await EnvModel.update({ status: EnvStatus.normal }, { where: { id: ids } }); await EnvModel.update({ status: EnvStatus.normal }, { where: { id: ids } });
await this.set_envs(); await this.set_envs();
} }
public async updateNames({ ids, name }: { ids: number[]; name: string }) { public async updateNames({ ids, name }: { ids: number[]; name: string }, userId?: number) {
await this.checkOwnership(ids, userId);
await EnvModel.update({ name }, { where: { id: ids } }); await EnvModel.update({ name }, { where: { id: ids } });
await this.set_envs(); await this.set_envs();
} }