Skip to content
This repository has been archived by the owner on Dec 30, 2022. It is now read-only.

Commit

Permalink
Relese/1.8.2 (#16)
Browse files Browse the repository at this point in the history
* feat: user associated project

* fix: add histoy creatBy

* fix: import env fail

* fix: add script for migration
  • Loading branch information
buqiyuan authored Oct 18, 2022
1 parent 0421bad commit 6313848
Show file tree
Hide file tree
Showing 23 changed files with 338 additions and 82 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -38,4 +38,5 @@ lerna-debug.log*
/sample

# env
.env.local
.env.prodction
2 changes: 1 addition & 1 deletion docker-compose.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ services:
eoapi-remote-server:
# build: 从当前路径构建镜像
build: .
image: eoapi/eoapi-remote-server:1.8.1
image: eoapi/eoapi-remote-server:1.8.2
container_name: eoapi-remote-server
restart: always
env_file:
Expand Down
4 changes: 2 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "eoapi-remote-server",
"version": "1.8.1",
"version": "1.8.2",
"description": "Storage api data in remote server",
"author": "eoapi",
"private": true,
Expand All @@ -16,7 +16,7 @@
"migration:create": "npx typeorm-ts-node-commonjs migration:create ./src/migrations/create-table",
"migration:generate": "node ./scripts/migration-generate.js",
"migration:run": "npm run build&&npx typeorm-ts-node-commonjs migration:run -d ./src/config/data-source.ts",
"migration:revert": "npm run typeorm migration:revert",
"migration:revert": "npx typeorm-ts-node-commonjs migration:revert -d ./src/config/data-source.ts",
"lint": "eslint \"{src,apps,libs,test}/**/*.ts\" --fix",
"typeorm": "npx typeorm-ts-node-commonjs",
"test": "jest",
Expand Down
24 changes: 24 additions & 0 deletions src/common/class/page.class.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
export default class Page<T> {
records: Array<T>;

pageNumber: number;

pageSize: number;

pageCount: number;

total: number;

constructor(
pageNumber: number,
pageSize: number,
total: number,
records: Array<T>,
) {
this.pageNumber = pageNumber;
this.pageSize = pageSize;
this.total = total;
this.records = records;
this.pageCount = Math.ceil(total / pageSize);
}
}
77 changes: 44 additions & 33 deletions src/config/configuration.ts
Original file line number Diff line number Diff line change
@@ -1,37 +1,48 @@
import { DataSourceOptions } from 'typeorm';
import { DataSource, DataSourceOptions } from 'typeorm';

export const getConfiguration = () => ({
// jwt sign secret
jwt: {
secret: process.env.JWT_SECRET || '123456',
},
// typeorm config
database: {
type: 'mysql',
host: process.env.MYSQL_HOST,
port: Number.parseInt(process.env.MYSQL_PORT, 10),
username: process.env.MYSQL_USERNAME,
password: process.env.MYSQL_ROOT_PASSWORD,
database: process.env.MYSQL_DATABASE,
entities: [__dirname + '/../**/entities/*.entity.{ts,js}'],
autoLoadEntities: true,
synchronize: false,
logging: ['error'],
timezone: '+08:00', // 东八区
migrations: ['dist/src/migrations/**/*.js'],
migrationsRun: true,
cli: {
migrationsDir: 'src/migrations',
export let appDataSource: DataSource;

export const getAppDataSource = (): DataSource => {
return appDataSource;
};

export const getConfiguration = () => {
const config = {
// jwt sign secret
jwt: {
secret: process.env.JWT_SECRET || '123456',
},
// typeorm config
database: {
type: 'mysql',
host: process.env.MYSQL_HOST,
port: Number.parseInt(process.env.MYSQL_PORT, 10),
username: process.env.MYSQL_USERNAME,
password: process.env.MYSQL_ROOT_PASSWORD,
database: process.env.MYSQL_DATABASE,
entities: [__dirname + '/../**/entities/*.entity.{ts,js}'],
autoLoadEntities: true,
synchronize: false,
logging: ['error'],
timezone: '+08:00', // 东八区
migrations: ['dist/src/migrations/**/*.js'],
migrationsRun: true,
cli: {
migrationsDir: 'src/migrations',
},
} as DataSourceOptions,
// swagger
swagger: {
enable: process.env.SWAGGER_ENABLE === 'true',
path: process.env.SWAGGER_PATH,
title: process.env.SWAGGER_TITLE,
desc: process.env.SWAGGER_DESC,
version: process.env.SWAGGER_VERSION,
},
} as DataSourceOptions,
// swagger
swagger: {
enable: process.env.SWAGGER_ENABLE === 'true',
path: process.env.SWAGGER_PATH,
title: process.env.SWAGGER_TITLE,
desc: process.env.SWAGGER_DESC,
version: process.env.SWAGGER_VERSION,
},
});
};
appDataSource = new DataSource(config.database);
// appDataSource.initialize();
return config;
};

export default getConfiguration();
2 changes: 1 addition & 1 deletion src/config/data-source.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,4 +4,4 @@ import { DataSource } from 'typeorm';
import { getConfiguration } from './configuration';
dotenv.config();

export const AppDataSource = new DataSource(getConfiguration().database);
export default new DataSource(getConfiguration().database);
4 changes: 2 additions & 2 deletions src/entities/apiTestHistory.entity.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
import { Column, Entity } from 'typeorm';
import { FictitiousBase } from './base.entity';
import { OperatorBase } from './base.entity';

@Entity({ name: 'api_test_history' })
export class ApiTestHistory extends FictitiousBase {
export class ApiTestHistory extends OperatorBase {
@Column({ default: 0 })
projectID: number;

Expand Down
26 changes: 26 additions & 0 deletions src/entities/base.entity.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { ApiProperty } from '@nestjs/swagger';
import {
BeforeUpdate,
Column,
CreateDateColumn,
PrimaryGeneratedColumn,
Expand All @@ -20,6 +21,31 @@ export abstract class TimestampBase {
updatedAt: Date;
}

export abstract class OperatorBase extends TimestampBase {
@PrimaryGeneratedColumn()
@ApiProperty()
uuid: number;

@Column({ update: false })
@ApiProperty()
createBy!: number;

@Column()
@ApiProperty()
updateBy!: number;

/**
* 以下两个事件需要创建一个新的实例时才会执行
* mapper.save(Object.assign(this.mapper.create(), entity)) -> 执行
* mapper.save(entity)) -> 不执行
* [实体监听器和订阅者](https://typeorm.bootcss.com/listeners-and-subscribers)
*/
// @BeforeUpdate()
// updateUpdateBy() {
// // console.log('before-update....');
// }
}

export abstract class FictitiousBase extends TimestampBase {
@PrimaryGeneratedColumn()
@ApiProperty()
Expand Down
12 changes: 10 additions & 2 deletions src/entities/project.entity.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
import { ApiProperty } from '@nestjs/swagger';
import { Entity, ManyToOne } from 'typeorm';
import { ApiHideProperty, ApiProperty } from '@nestjs/swagger';
import { Exclude } from 'class-transformer';
import { Entity, JoinTable, ManyToMany, ManyToOne } from 'typeorm';
import { Base } from './base.entity';
import { WorkspaceEntity } from './workspace.entity';
import { UserEntity } from './user.entity';

@Entity({ name: 'project' })
export class Project extends Base {
Expand All @@ -10,4 +12,10 @@ export class Project extends Base {
onDelete: 'CASCADE',
})
workspace: WorkspaceEntity;

@Exclude()
@ApiHideProperty()
@ManyToMany(() => UserEntity, (user) => user.projects)
@JoinTable()
users: UserEntity[];
}
4 changes: 4 additions & 0 deletions src/entities/user.entity.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import { IsEmail, IsMobilePhone, IsString } from 'class-validator';
import { Column, Entity, ManyToMany, PrimaryGeneratedColumn } from 'typeorm';
import { WorkspaceEntity } from './workspace.entity';
import { TimestampBase } from './base.entity';
import { Project } from './project.entity';

@Entity({ name: 'user' })
export class UserEntity extends TimestampBase {
Expand Down Expand Up @@ -46,4 +47,7 @@ export class UserEntity extends TimestampBase {
@Exclude()
@ManyToMany(() => WorkspaceEntity, (workspace) => workspace.users)
workspaces: WorkspaceEntity[];

@ManyToMany(() => Project, (project) => project.users)
projects: Project[];
}
58 changes: 58 additions & 0 deletions src/migrations/1666095643523-update-table_1_8_2.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
import { MigrationInterface, QueryRunner } from 'typeorm';

export class updateTable1821666095643523 implements MigrationInterface {
name = 'updateTable1821666095643523';

public async up(queryRunner: QueryRunner): Promise<void> {
await queryRunner.query(
`CREATE TABLE \`project_users_user\` (\`projectUuid\` int NOT NULL, \`userId\` int NOT NULL, INDEX \`IDX_6a2f9d94e82e85ba623237023b\` (\`projectUuid\`), INDEX \`IDX_f8300efd87679e1e21532be980\` (\`userId\`), PRIMARY KEY (\`projectUuid\`, \`userId\`)) ENGINE=InnoDB`,
);
await queryRunner.query(
`ALTER TABLE \`api_test_history\` ADD \`createBy\` int NOT NULL`,
);
await queryRunner.query(
`ALTER TABLE \`api_test_history\` ADD \`updateBy\` int NOT NULL`,
);
await queryRunner.query(
`ALTER TABLE \`project_users_user\` ADD CONSTRAINT \`FK_6a2f9d94e82e85ba623237023bd\` FOREIGN KEY (\`projectUuid\`) REFERENCES \`project\`(\`uuid\`) ON DELETE CASCADE ON UPDATE CASCADE`,
);
await queryRunner.query(
`ALTER TABLE \`project_users_user\` ADD CONSTRAINT \`FK_f8300efd87679e1e21532be9808\` FOREIGN KEY (\`userId\`) REFERENCES \`user\`(\`id\`) ON DELETE NO ACTION ON UPDATE NO ACTION`,
);

const workspaces = await queryRunner.query(
`SELECT * FROM workspace_users_user`,
);

const values = workspaces.map((item) => [item.workspaceId, item.userId]);
console.log('values', values);
if (values.length) {
await queryRunner.query(
`INSERT INTO project_users_user (projectUuid, userId) VALUES ?`,
[values],
);
}
}

public async down(queryRunner: QueryRunner): Promise<void> {
await queryRunner.query(
`ALTER TABLE \`project_users_user\` DROP FOREIGN KEY \`FK_f8300efd87679e1e21532be9808\``,
);
await queryRunner.query(
`ALTER TABLE \`project_users_user\` DROP FOREIGN KEY \`FK_6a2f9d94e82e85ba623237023bd\``,
);
await queryRunner.query(
`ALTER TABLE \`api_test_history\` DROP COLUMN \`updateBy\``,
);
await queryRunner.query(
`ALTER TABLE \`api_test_history\` DROP COLUMN \`createBy\``,
);
await queryRunner.query(
`DROP INDEX \`IDX_f8300efd87679e1e21532be980\` ON \`project_users_user\``,
);
await queryRunner.query(
`DROP INDEX \`IDX_6a2f9d94e82e85ba623237023b\` ON \`project_users_user\``,
);
await queryRunner.query(`DROP TABLE \`project_users_user\``);
}
}
2 changes: 2 additions & 0 deletions src/modules/auth/auth.module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,13 +9,15 @@ import { UserModule } from '@/modules/user/user.module';
import { AuthService } from '@/modules/auth/auth.service';
import { JwtAuthGuard } from '@/modules/auth/guards/jwt-auth.guard';
import { AuthEntity } from '@/entities/auth.entity';
import { WorkspaceModule } from '@/modules/workspace/workspace.module';

@Module({
imports: [
TypeOrmModule.forFeature([AuthEntity]),
PassportModule,
ConfigModule,
UserModule,
WorkspaceModule,
PassportModule,
JwtModule.registerAsync({
imports: [ConfigModule],
Expand Down
19 changes: 19 additions & 0 deletions src/modules/auth/guards/jwt-auth.guard.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import { IS_PUBLIC_KEY } from '@/common/decorators/public.decorator';
import { AuthService } from '@/modules/auth/auth.service';
import { IUser } from '@/common/decorators/user.decorator';
import { UserService } from '@/modules/user/user.service';
import { ProjectService } from '@/modules/workspace/project/project.service';

/**
* admin perm check guard
Expand All @@ -23,6 +24,7 @@ export class JwtAuthGuard implements CanActivate {
private jwtService: JwtService,
private authService: AuthService,
private userService: UserService,
private projectService: ProjectService,
) {}

async canActivate(context: ExecutionContext): Promise<boolean> {
Expand Down Expand Up @@ -59,17 +61,34 @@ export class JwtAuthGuard implements CanActivate {
}

const workspaceID = Number(request?.params?.workspaceID);
const projectID = Number(request?.params?.projectID);
if (!Number.isNaN(workspaceID)) {
const hasWorkspaceAuth = await this.userService.findOneBy({
id: request.currentUser.userId,
workspaces: {
id: workspaceID,
},
...(Number.isNaN(projectID)
? {}
: {
projects: {
uuid: projectID,
},
}),
});
if (!hasWorkspaceAuth) {
throw new ForbiddenException('没有该空间访问权限');
}
}
if (!Number.isNaN(projectID)) {
const hasProjectAuth = await this.projectService.findOne(
workspaceID,
projectID,
);
if (!hasProjectAuth) {
throw new ForbiddenException('没有该项目访问权限');
}
}

// pass
return true;
Expand Down
4 changes: 4 additions & 0 deletions src/modules/user/user.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -211,4 +211,8 @@ export class UserService implements OnModuleInit {
isFirstLogin: false,
});
}

updateUser(user: UserEntity) {
return this.userRepository.save(user);
}
}
Loading

0 comments on commit 6313848

Please sign in to comment.