Expand seller store functionality

This commit is contained in:
R524809
2026-09-07 17:51:11 +08:00
parent 4c0f3a4a79
commit ceb644a3f9
35 changed files with 32883 additions and 364 deletions
+24 -4
View File
@@ -1,5 +1,8 @@
import { CanActivate, ExecutionContext, Inject, Injectable } from '@nestjs/common';
import { ExtensionService } from './extension.service.js';
import { CanActivate, ExecutionContext, Inject, Injectable, UnauthorizedException } from '@nestjs/common';
import type { Database } from '@atlas/database';
import { AuthService } from '../auth/auth.service.js';
import { ApiError } from '../common/api-error.js';
import { DATABASE } from '../database/database.module.js';
export type ExtensionAuthenticatedRequest = {
header: (name: string) => string | undefined;
@@ -8,10 +11,27 @@ export type ExtensionAuthenticatedRequest = {
@Injectable()
export class ExtensionAccessGuard implements CanActivate {
public constructor(@Inject(ExtensionService) private readonly extension: ExtensionService) {}
public constructor(@Inject(AuthService) private readonly auth: AuthService, @Inject(DATABASE) private readonly database: Database) {}
public async canActivate(context: ExecutionContext) {
const request = context.switchToHttp().getRequest<ExtensionAuthenticatedRequest>();
request.extensionAuth = await this.extension.authenticate(request.header('authorization'));
// 毛子 ERP 风格:插件携带从 Atlas Web 同步而来的短期 Web access token。
// AuthService 同时核对 JWT 和未撤销的 Web session,不能仅信任 token 声明。
let authenticated: { userId: string; sessionId: string };
try {
authenticated = await this.auth.authenticate(request.header('authorization'));
} catch (error) {
// AuthService 的通用认证守卫会抛 Nest UnauthorizedException;扩展接口
// 应返回稳定、可操作的错误信息,不能在 UI 中退化成“请求无法处理”。
if (error instanceof UnauthorizedException)
throw new ApiError(401, 'SESSION_EXPIRED', 'Atlas ERP 登录已过期,请重新登录');
throw error;
}
const workspace = await this.database.query<{ id: string }>(`SELECT w.id FROM atlas.workspace_memberships m
JOIN atlas.workspaces w ON w.id = m.workspace_id
WHERE m.user_id = $1 AND w.status = 'active'
ORDER BY m.joined_at LIMIT 1`, [authenticated.userId]);
if (!workspace.rows[0]) throw new ApiError(403, 'WORKSPACE_MEMBERSHIP_REQUIRED', '当前账户没有可用工作空间');
request.extensionAuth = { userId: authenticated.userId, workspaceId: workspace.rows[0].id, sessionId: authenticated.sessionId, clientId: 'atlas-web' };
return true;
}
}