Skip to content
This repository was archived by the owner on Jul 8, 2025. It is now read-only.

Commit f4a28a7

Browse files
committed
feat(cgi & cli): supporting login and release with access-token
1 parent f69c4ad commit f4a28a7

File tree

22 files changed

+306
-118
lines changed

22 files changed

+306
-118
lines changed

packages/cgi/src/modules/materials/materials.controller.ts

Lines changed: 23 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,15 @@
11
import {
2+
Body,
23
Controller,
34
Get,
4-
Post,
55
Param,
6-
UseInterceptors,
7-
UploadedFile,
6+
Post,
87
Query,
8+
UploadedFile,
9+
UseInterceptors,
910
} from '@nestjs/common';
1011
import { FileInterceptor } from '@nestjs/platform-express';
11-
import { Maybe, FileInterceptorUploadedFile, WithKeywords } from '../../types';
12+
import { FileInterceptorUploadedFile, Maybe, WithKeywords } from '../../types';
1213
import {
1314
CGICodeMap,
1415
CGIResponse,
@@ -18,6 +19,7 @@ import {
1819
warn,
1920
} from '../../utils';
2021
import { RequestId } from '../../decorators';
22+
import { UserService } from '../user/user.service';
2123
import { MaterialsService } from './materials.service';
2224
import {
2325
createLibPackageSoftLink,
@@ -26,12 +28,16 @@ import {
2628
parseLibs,
2729
saveMaterialsPackage,
2830
} from './materials.utils';
31+
import { UploadLibParams } from './materials.interface';
2932

3033
let cgiMaterialsService: Maybe<MaterialsService> = null;
3134

3235
@Controller('/cgi/materials')
3336
export class MaterialsController {
34-
constructor(private readonly materialsService: MaterialsService) {
37+
constructor(
38+
private readonly materialsService: MaterialsService,
39+
private readonly userServices: UserService,
40+
) {
3541
cgiMaterialsService = materialsService;
3642
}
3743

@@ -75,14 +81,26 @@ export class MaterialsController {
7581
async uploadLibPackage(
7682
@RequestId() requestId,
7783
@UploadedFile() file: FileInterceptorUploadedFile,
84+
@Body() { username, accessToken }: UploadLibParams,
7885
@Param('libName') libName: string,
7986
@Param('version') version: string,
8087
) {
8188
infoRequest(requestId, 'materials.controller.uploadLibPackage', {
8289
libName,
8390
version,
8491
filename: file.filename,
92+
body: { username, accessToken: '*' },
8593
});
94+
95+
const token = await this.userServices.getAccessToken(username);
96+
if (token !== accessToken) {
97+
warn('materials.controller.uploadLibPackage', 'invalid access-token', {
98+
username,
99+
token,
100+
});
101+
return CGIResponse.failed(requestId, CGICodeMap.InvalidAccessToken);
102+
}
103+
86104
const packagePath = await saveMaterialsPackage(
87105
libName,
88106
version,
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
export interface UploadLibParams {
2+
username: string;
3+
accessToken: string;
4+
}

packages/cgi/src/modules/materials/materials.modules.ts

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,15 @@
11
import { Global, Module } from '@nestjs/common';
22
import { TypeOrmModule } from '@nestjs/typeorm';
3+
import { UserService } from '../user/user.service';
4+
import { UserEntity } from '../user/user.entity';
35
import { MaterialsService } from './materials.service';
46
import { MaterialsController } from './materials.controller';
57
import { MaterialsEntity } from './materials.entity';
68

79
@Global()
810
@Module({
9-
imports: [TypeOrmModule.forFeature([MaterialsEntity])],
10-
providers: [MaterialsService],
11+
imports: [TypeOrmModule.forFeature([MaterialsEntity, UserEntity])],
12+
providers: [MaterialsService, UserService],
1113
controllers: [MaterialsController],
1214
exports: [MaterialsService],
1315
})

packages/cgi/src/modules/user/user.controller.ts

Lines changed: 32 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,11 @@ import {
99
import { QueryParams, Maybe, WithKeywords } from '../../types';
1010
import { RequestId, UserName } from '../../decorators';
1111
import { UserService } from './user.service';
12-
import { CreateUserParams, UpdateUserParams } from './user.interface';
12+
import {
13+
CheckTokenParams,
14+
CreateUserParams,
15+
UpdateUserParams,
16+
} from './user.interface';
1317

1418
let cgiUserService: Maybe<UserService> = null;
1519

@@ -64,6 +68,33 @@ export class UserController {
6468
return CGIResponse.success(requestId, result);
6569
}
6670

71+
@Get('/access_token')
72+
async checkAccessToken(
73+
@RequestId() requestId,
74+
@Query() { token, username }: CheckTokenParams,
75+
) {
76+
infoRequest(requestId, 'user.controller.checkAccessToken', {
77+
token,
78+
username,
79+
});
80+
81+
if (!(await this.userService.checkUserExists(username))) {
82+
warn(
83+
'user.controller.checkAccessToken',
84+
`User "${username}" not exists`,
85+
{
86+
requestId,
87+
},
88+
);
89+
return CGIResponse.failed(requestId, CGICodeMap.UserNotExists);
90+
}
91+
92+
const accessToken = await this.userService.getAccessToken(username);
93+
const result = { tokenValid: token === accessToken };
94+
infoResponse(requestId, 'user.controller.checkAccessToken', { result });
95+
return CGIResponse.success(requestId, result);
96+
}
97+
6798
@Post('/access_token/:id')
6899
async generateAccessToken(
69100
@RequestId() requestId,

packages/cgi/src/modules/user/user.interface.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,3 +6,8 @@ export type CreateUserParams = Pick<
66
>;
77

88
export type UpdateUserParams = CreateUserParams;
9+
10+
export interface CheckTokenParams {
11+
username: string;
12+
token: string;
13+
}

packages/cgi/src/modules/user/user.service.ts

Lines changed: 15 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -14,11 +14,15 @@ export class UserService {
1414
) {}
1515

1616
public async getUserEntityById(id: number) {
17-
return this.userRepository.findOne(id);
17+
const result = await this.userRepository.findOne(id);
18+
result && delete result.__developerAccessToken;
19+
return result;
1820
}
1921

2022
public async getUserEntityByName(name: string) {
21-
return this.userRepository.findOne({ name });
23+
const result = await this.userRepository.findOne({ name });
24+
result && delete result.__developerAccessToken;
25+
return result;
2226
}
2327

2428
public async queryUserEntities({
@@ -41,8 +45,11 @@ export class UserService {
4145
where,
4246
};
4347

48+
const result = await this.userRepository.find(options);
49+
result?.forEach(i => delete i.__developerAccessToken);
50+
4451
return {
45-
data: await this.userRepository.find(options),
52+
data: result,
4653
total: await this.userRepository.count({ where }),
4754
};
4855
}
@@ -89,4 +96,9 @@ export class UserService {
8996
const count = await this.userRepository.count({ name });
9097
return count > 0;
9198
}
99+
100+
public async getAccessToken(name: string) {
101+
const result = await this.userRepository.findOne({ name });
102+
return result?.__developerAccessToken;
103+
}
92104
}

packages/cgi/src/utils/response.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,7 @@ export enum CGICodeMap {
5252
UserNotExists = 700002,
5353
UploadResourceCallbackError = 80001,
5454
DeleteResourceCallbackError = 80002,
55+
InvalidAccessToken = 80003,
5556
}
5657

5758
const CGIReasonMap: { [key in CGICodeMap]: string } = {
@@ -68,6 +69,7 @@ const CGIReasonMap: { [key in CGICodeMap]: string } = {
6869
'upload resource callback occurred error',
6970
[CGICodeMap.DeleteResourceCallbackError]:
7071
'delete resource callback occurred error',
72+
[CGICodeMap.InvalidAccessToken]: 'invalid access-token',
7173
};
7274

7375
export type PromiseResult<T> = Promise<[null, T] | [Error, null]>;

packages/cli/src/commands/index.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,3 +2,4 @@ export * from './create';
22
export * from './release';
33
export * from './dev';
44
export * from './dist';
5+
export * from './login';

packages/cli/src/commands/login.ts

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
import * as inquirer from 'inquirer';
2+
import { curl, error, getLibConfig, getLibPaths, writeAccessToken, deleteAccessToken, done } from '../utils';
3+
4+
export async function login() {
5+
const root = process.cwd();
6+
const paths = getLibPaths(root, '');
7+
const { server } = getLibConfig(paths);
8+
9+
const { username, accessToken } = await inquirer.prompt([
10+
{
11+
type: 'input',
12+
name: 'username',
13+
message: 'username',
14+
required: true,
15+
},
16+
{
17+
type: 'input',
18+
name: 'accessToken',
19+
message: 'access-token',
20+
required: true,
21+
},
22+
]);
23+
24+
const { data } = await curl(`${server}/cgi/user/access_token?username=${username}&token=${accessToken}`, {
25+
method: 'GET',
26+
timeout: 10 * 1000,
27+
contentType: 'application/json',
28+
});
29+
30+
if (data.code !== 0) {
31+
error(data.message || `Unknown error with code: "${data.code}"`);
32+
process.exit();
33+
}
34+
35+
if (!data?.data?.tokenValid) {
36+
error('Invalid access-token');
37+
process.exit();
38+
}
39+
40+
await writeAccessToken(server, username, accessToken);
41+
done(`User "${username}" login success for "${server}"`);
42+
}
43+
44+
export async function logout() {
45+
const root = process.cwd();
46+
const paths = getLibPaths(root, '');
47+
const { server } = getLibConfig(paths);
48+
await deleteAccessToken(server);
49+
done('logged out');
50+
}
Lines changed: 1 addition & 86 deletions
Original file line numberDiff line numberDiff line change
@@ -1,91 +1,6 @@
1-
import * as path from 'path';
2-
import * as tar from 'tar';
3-
import * as semver from 'semver';
4-
import { MaterialsLibConfig } from '@vize/types';
5-
import { dist } from '../dist';
6-
import { curl, error, getLibPaths, getLibVersion, getLibConfig, LibPaths } from '../../utils';
1+
import { Releaser } from './releaser';
72

83
export function release() {
94
const releaser = new Releaser();
105
return releaser.runRelease();
116
}
12-
13-
class Releaser {
14-
constructor() {
15-
this.paths = getLibPaths();
16-
this.config = getLibConfig(this.paths);
17-
}
18-
19-
private readonly paths: LibPaths;
20-
21-
private readonly config: MaterialsLibConfig;
22-
23-
private getURI(suffix = '') {
24-
return `${this.config.releaseTo}/cgi/materials/versions/${this.config.libName}${suffix}`;
25-
}
26-
27-
private checkVersionValid = async (): Promise<Maybe<string>> => {
28-
const currentVersion = getLibVersion(this.paths.root);
29-
const uri = this.getURI();
30-
let data;
31-
try {
32-
const result = await curl(uri, {
33-
method: 'GET',
34-
timeout: 10 * 1000,
35-
contentType: 'application/json',
36-
});
37-
data = result.data;
38-
} catch (e) {
39-
console.error(e);
40-
throw new Error('Get versions failed');
41-
}
42-
43-
const {
44-
code,
45-
data: { current: onlineVersion },
46-
} = JSON.parse(data);
47-
if (code !== 0) {
48-
throw new Error(`Request "${uri}" error: code = ${code}`);
49-
}
50-
51-
if (!onlineVersion) {
52-
return currentVersion;
53-
}
54-
55-
return semver.gt(currentVersion, onlineVersion) ? currentVersion : null;
56-
};
57-
58-
private createReleasePackage = async (version: string) => {
59-
const targetPath = path.resolve(this.paths.temp, `${this.config.libName}_${version}.tgz`);
60-
61-
await tar.c(
62-
{
63-
gzip: true,
64-
file: targetPath,
65-
preservePaths: false,
66-
},
67-
['src', 'dist', './.vizerc', './package.json', './package-lock.json'],
68-
);
69-
return targetPath;
70-
};
71-
72-
private uploadReleasePackage = async (version: string, packagePath: string) => {
73-
const uri = this.getURI(`/${version}`);
74-
const { data } = await curl(uri, {
75-
method: 'POST',
76-
files: packagePath,
77-
});
78-
console.log(data.toString());
79-
};
80-
81-
public runRelease = async () => {
82-
const version = await this.checkVersionValid();
83-
if (!version) {
84-
return error(`Materials version already exists.`);
85-
}
86-
87-
await dist();
88-
const packagePath: string = await this.createReleasePackage(version);
89-
await this.uploadReleasePackage(version, packagePath);
90-
};
91-
}

0 commit comments

Comments
 (0)