Skip to content

Commit

Permalink
Showing 46 changed files with 1,235 additions and 129 deletions.
16 changes: 10 additions & 6 deletions .env.template
Original file line number Diff line number Diff line change
@@ -5,12 +5,10 @@ BASE_URL= # OpenAI API URL
WEB_PORT=3000 # Front-end port
SERVER_PORT=3001 # Backend port

STATIC_PATH=/static # Static file path
OUTPUT_SRT_THEN_TRANSLATE=true # Whether to output the SRT file first and then translate it
LANGUAGE=zh-CN # Output SRT file and then translate the language
TRANSLATE_DELAY=1500 # Delay between calling translation interface
TRANSLATE_GROUP=4 # Translate sentences for grouping translation, how many sentences can be translated at most at a time
TranslateModel=google # google or gpt3
STATIC_PATH=/static # Static file path

TRANSLATE_DELAY=1500 # Delay between calling translation interface
TRANSLATE_GROUP=4 # Translate sentences for grouping translation, how many sentences can be translated at most at a time

REDIS_PORT=6379 # Redis port
REDIS_HOST=subtitle_redis # Redis address
@@ -28,3 +26,9 @@ NEXT_PUBLIC_WEB_URL=http://localhost:3000 # Same as above. WEB address
GITHUB_CLIENT_ID= # GitHub client ID
GITHUB_CLIENT_SECRET= # GitHub client secret
AUTH_SECRET = YOUR_KEY_HERE # JWT secret you can run `openssl rand -base64 32` to generate a secret

# System Setting
# You can edit in Setting
OUTPUT_SRT_THEN_TRANSLATE=true # Whether to output the SRT file first and then translate it
TranslateModel=google # google or gpt3
LANGUAGE=zh-CN # Output SRT file and then translate the language
3 changes: 3 additions & 0 deletions apps/server/src/app.module.ts
Original file line number Diff line number Diff line change
@@ -21,6 +21,7 @@ import { UsersModule } from "./users/users.module";

import * as fs from "fs-extra";
import * as path from "path";
import { CustomConfigModule } from "./config/config.module";

const {
REDIS_PORT = 6379,
@@ -72,6 +73,8 @@ const rootPath = path.join(__dirname, "..", "..", "..");
serveRoot: "/static",
}),

CustomConfigModule,

TranslateModule,

UploadModule,
17 changes: 16 additions & 1 deletion apps/server/src/auth/auth.controller.spec.ts
Original file line number Diff line number Diff line change
@@ -5,9 +5,10 @@ import { RegisterDto } from "./dto/register.dto";
import { UsersService } from "@/users/users.service";
import { JwtService } from "@nestjs/jwt";
import { getRepositoryToken } from "@nestjs/typeorm";
import { RegularUser, OAuthUser } from "@/users/users.entity";
import { RegularUser, OAuthUser, User } from "@/users/users.entity";
import { RefreshToken } from "@/users/refresh-token.entity";
import { mockAccessToken, mockRegularUser } from "./testConstants";
import { CustomConfigService } from "@/config/custom-config.service";

describe("AuthController", () => {
let controller: AuthController;
@@ -32,6 +33,20 @@ describe("AuthController", () => {
provide: getRepositoryToken(RefreshToken), // Replace 'VideoFileEntity' with your actual entity name
useValue: {}, // Mock the repository methods you need
},
{
provide: getRepositoryToken(User), // Replace 'VideoFileEntity' with your actual entity name
useValue: {
findOne: jest.fn(),
save: jest.fn(),
}, // Mock the repository methods you need
},
{
provide: CustomConfigService,
useValue: {
get: jest.fn(),
set: jest.fn(),
},
},
],
}).compile();

17 changes: 11 additions & 6 deletions apps/server/src/auth/auth.controller.ts
Original file line number Diff line number Diff line change
@@ -39,12 +39,6 @@ export class AuthController {
return this.authService.register(registerDto);
}

// @UseGuards(AuthGuard)
// @Get("profile")
// getProfile(@Request() req) {
// return req.user;
// }

@Post("logout")
async logout(@Request() req, @Response() res) {
// If you're using a blacklist, add the token to it.
@@ -60,4 +54,15 @@ export class AuthController {
async oauthSignIn(@Body() oauthSignInDto: OAuthSignInDto) {
return this.authService.oauthSignIn(oauthSignInDto);
}

@UseGuards(AuthGuard)
@Get("profile")
async getProfile(@Request() req) {
return this.authService.getProfile(req.user.sub);
}

@Post("updateProfile")
async updateProfile(@Request() req, @Body() body) {
return this.authService.updateProfile(req.user.sub, body);
}
}
1 change: 0 additions & 1 deletion apps/server/src/auth/auth.guard.ts
Original file line number Diff line number Diff line change
@@ -30,7 +30,6 @@ export class AuthGuard implements CanActivate {

const request = context.switchToHttp().getRequest();
const token = this.extractTokenFromHeader(request);
console.debug("AuthGuard", token);
if (!token) {
throw new UnauthorizedException();
}
17 changes: 16 additions & 1 deletion apps/server/src/auth/auth.service.spec.ts
Original file line number Diff line number Diff line change
@@ -3,7 +3,7 @@ import { AuthService } from "./auth.service";
import { UsersService } from "@/users/users.service";
import { JwtService } from "@nestjs/jwt";
import { getRepositoryToken } from "@nestjs/typeorm";
import { OAuthUser, RegularUser } from "@/users/users.entity";
import { OAuthUser, RegularUser, User } from "@/users/users.entity";
import { UnauthorizedException } from "@nestjs/common";
import { RegisterDto } from "./dto/register.dto";
import { RefreshToken } from "@/users/refresh-token.entity";
@@ -15,6 +15,7 @@ import {
mockRegularUser,
} from "./testConstants";
import { jwtConstants } from "./constants";
import { CustomConfigService } from "@/config/custom-config.service";

describe("AuthService", () => {
let authService: AuthService;
@@ -43,6 +44,13 @@ describe("AuthService", () => {
verifyAsync: jest.fn(),
},
},
{
provide: CustomConfigService,
useValue: {
get: jest.fn(),
set: jest.fn(),
},
},
{
provide: getRepositoryToken(RegularUser), // Replace 'VideoFileEntity' with your actual entity name
useValue: {}, // Mock the repository methods you need
@@ -55,6 +63,13 @@ describe("AuthService", () => {
provide: getRepositoryToken(RefreshToken), // Replace 'VideoFileEntity' with your actual entity name
useValue: {}, // Mock the repository methods you need
},
{
provide: getRepositoryToken(User), // Replace 'VideoFileEntity' with your actual entity name
useValue: {
findOne: jest.fn(),
save: jest.fn(),
}, // Mock the repository methods you need
},
],
}).compile();

41 changes: 38 additions & 3 deletions apps/server/src/auth/auth.service.ts
Original file line number Diff line number Diff line change
@@ -4,12 +4,14 @@ import { JwtService } from "@nestjs/jwt";
import { RegisterDto } from "./dto/register.dto";
import { jwtConstants } from "./constants";
import { OAuthSignInDto } from "./dto/outhSignIn.dto";
import { CustomConfigService } from "@/config/custom-config.service";

@Injectable()
export class AuthService {
constructor(
private usersService: UsersService,
private jwtService: JwtService
private jwtService: JwtService,
private configService: CustomConfigService
) {}

async signIn(username: string, pass: string): Promise<any> {
@@ -45,8 +47,8 @@ export class AuthService {

// Optional: Check if the refresh token is in the database and still valid
// if not, throw an exception
console.debug("refreshToken payload: " + JSON.stringify(payload));
console.debug("refreshToken userExists: " + JSON.stringify(userExists));
// console.debug("refreshToken payload: " + JSON.stringify(payload));
// console.debug("refreshToken userExists: " + JSON.stringify(userExists));

// Create a new access token
const user = { sub: payload.id, username: payload.username }; // this is just a placeholder. Adjust according to your payload structure
@@ -94,4 +96,37 @@ export class AuthService {
},
};
}

async getProfile(userId: number) {
const user = await this.usersService.findOneById(userId);
return {
id: user.id,
username: user.username,
userType: user.userType,
};
}

async updateProfile(
user,
{ username, password, OUTPUT_SRT_THEN_TRANSLATE, TranslateModel, LANGUAGE }
) {
if (typeof OUTPUT_SRT_THEN_TRANSLATE === "boolean") {
this.configService.set(
"OUTPUT_SRT_THEN_TRANSLATE",
OUTPUT_SRT_THEN_TRANSLATE ? "1" : "0"
);
}
if (TranslateModel) {
this.configService.set("TranslateModel", TranslateModel);
}

if (LANGUAGE) {
this.configService.set("LANGUAGE", LANGUAGE);
}

return this.usersService.updateProfile(user.id, {
username,
password,
});
}
}
4 changes: 2 additions & 2 deletions apps/server/src/auth/testConstants.ts
Original file line number Diff line number Diff line change
@@ -4,7 +4,7 @@ export const mockRegularUser: RegularUser = {
id: 1,
username: "testuser",
password: "testpassword",
userType: "regular",
userType: "RegularUser",
email: null,
image: null,
name: null,
@@ -13,7 +13,7 @@ export const mockRegularUser: RegularUser = {
export const mockOAuthUser: OAuthUser = {
id: 1,
username: "testuser",
userType: "oauth",
userType: "OAuthUser",
email: "test_email",
image: "test_image",
name: "test_name",
23 changes: 23 additions & 0 deletions apps/server/src/config/config.controller.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
import {
Controller,
Get,
Post,
Body,
Put,
Param,
Delete,
} from "@nestjs/common";

import { CustomConfigService } from "./custom-config.service";
import { Public } from "@/auth/decorators/public.decorator";

@Controller("config")
export class ConfigController {
constructor(private readonly configService: CustomConfigService) {}

@Public()
@Get()
findAll() {
return this.configService.getAll();
}
}
13 changes: 13 additions & 0 deletions apps/server/src/config/config.entity.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
import { Entity, Column, PrimaryGeneratedColumn } from "typeorm";

@Entity()
export class Config {
@PrimaryGeneratedColumn()
id: number;

@Column()
key: string;

@Column()
value: string;
}
16 changes: 16 additions & 0 deletions apps/server/src/config/config.module.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
import { Global, Module } from "@nestjs/common";
import { CustomConfigService } from "./custom-config.service";
import { Config } from "./config.entity";
import { TypeOrmModule } from "@nestjs/typeorm";
import { DatabaseConfigService } from "./config.service";
import { ConfigModule } from "@nestjs/config";
import { ConfigController } from "./config.controller";

@Global()
@Module({
imports: [TypeOrmModule.forFeature([Config]), ConfigModule],
providers: [DatabaseConfigService, CustomConfigService],
exports: [CustomConfigService],
controllers: [ConfigController],
})
export class CustomConfigModule {}
26 changes: 26 additions & 0 deletions apps/server/src/config/config.service.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
import { Test, TestingModule } from "@nestjs/testing";
import { DatabaseConfigService } from "./config.service";
import { Config } from "./config.entity";
import { getRepositoryToken } from "@nestjs/typeorm";

describe("ConfigService", () => {
let service: DatabaseConfigService;

beforeEach(async () => {
const module: TestingModule = await Test.createTestingModule({
providers: [
DatabaseConfigService,
{
provide: getRepositoryToken(Config),
useValue: {},
},
],
}).compile();

service = module.get<DatabaseConfigService>(DatabaseConfigService);
});

it("should be defined", () => {
expect(service).toBeDefined();
});
});
35 changes: 35 additions & 0 deletions apps/server/src/config/config.service.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
// config.service.ts
import { Injectable } from "@nestjs/common";
import { InjectRepository } from "@nestjs/typeorm";
import { Repository } from "typeorm";
import { Config } from "./config.entity";

@Injectable()
export class DatabaseConfigService {
constructor(
@InjectRepository(Config)
private configRepository: Repository<Config>
) {}

async get(key: string): Promise<Config> {
return this.configRepository.findOne({ where: { key } });
}

async set(key: string, value: string): Promise<Config> {
let config = await this.configRepository.findOne({ where: { key } });
if (config) {
config.value = value;
} else {
config = this.configRepository.create({ key, value });
}
return this.configRepository.save(config);
}

async getAll(): Promise<Record<string, string>> {
const configs = await this.configRepository.find();
return configs.reduce((acc, config) => {
acc[config.key] = config.value;
return acc;
}, {});
}
}
33 changes: 33 additions & 0 deletions apps/server/src/config/custom-config.service.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
import { Injectable } from "@nestjs/common";
import { ConfigService as NextConfigService } from "@nestjs/config";
import { DatabaseConfigService } from "./config.service";

@Injectable()
export class CustomConfigService {
constructor(
private readonly configService: DatabaseConfigService,
private readonly nextConfigService: NextConfigService
) {}

getStatic(key: string): string {
return this.nextConfigService.get<string>(key);
}

async getDynamic(key: string): Promise<string> {
const config = await this.configService.get(key);
return config?.value;
}

async get(key: string): Promise<string> {
return (await this.getDynamic(key)) || this.getStatic(key);
}

async set(key: string, value: string): Promise<void> {
if (!key || !value) return;
await this.configService.set(key, value);
}

async getAll(): Promise<Record<string, string>> {
return this.configService.getAll();
}
}
Loading

0 comments on commit 7cc4ce2

Please sign in to comment.