Skip to content

Commit

Permalink
优化了单例模式,数据库以及vite的读取环境变量分别作为单例,都使用饿汉模式,时项目更加简洁。优化了所有模块的代码,与之前对比有明显的差别
Browse files Browse the repository at this point in the history
  • Loading branch information
checkma-xh committed Mar 8, 2024
1 parent 10d4982 commit d174b3d
Show file tree
Hide file tree
Showing 14 changed files with 587 additions and 486 deletions.
466 changes: 230 additions & 236 deletions database/src/controller/AuthController.ts

Large diffs are not rendered by default.

45 changes: 25 additions & 20 deletions database/src/controller/OtherController.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,30 +9,35 @@ export class OtherController {
private RepeatInfoRepository = AppDataSource.getRepository(RepeatInfo);

async getPriorities(request: Request, response: Response, next: NextFunction) {
const decodeToken = await tokenVerify(request.headers.authorization.split(" ")[1]);
if (!decodeToken) {
response.status(404).json({ message: "no permission" });
return;
}
const priorities = await this.PriorityInfoRepository.find();
if (!priorities) {
response.status(404).json({ message: "priorities information not found" });
return;
try {
const decodeToken = await tokenVerify(request.headers.authorization.split(" ")[1]);
if (!decodeToken) {
throw new Error('Invalid token');
}

const priorities = await this.PriorityInfoRepository.find();

response.status(200).json(priorities);
} catch (error) {
const errorMessage = error.message || "An unexpected error occurred.";
response.status(500).json({ status: "error", message: errorMessage });
}
response.json(priorities);
}


async getRepeats(request: Request, response: Response, next: NextFunction) {
const decodeToken = await tokenVerify(request.headers.authorization.split(" ")[1]);
if (!decodeToken) {
response.status(404).json({ message: "no permission" });
return;
}
const repeats = await this.RepeatInfoRepository.find();
if (!repeats) {
response.status(404).json({ message: "repeats information not found" });
return;
try {
const decodeToken = await tokenVerify(request.headers.authorization.split(" ")[1]);
if (!decodeToken) {
throw new Error('Invalid token');
}

const repeats = await this.RepeatInfoRepository.find();

response.json(repeats);
} catch (error) {
const errorMessage = error.message || "An unexpected error occurred.";
response.status(500).json({ status: "error", message: errorMessage });
}
response.json(repeats);
}
}
44 changes: 37 additions & 7 deletions database/src/controller/PlanManagementController.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,19 +5,49 @@ import { GroupInfo } from "../entity/GroupInfo";
import { PriorityInfo } from "../entity/PriorityInfo";
import { PlanInfo } from "../entity/PlanInfo";
import * as jwt from "jsonwebtoken";
import * as dotenv from "dotenv";
import { tokenVerify } from "../utils/tokenVerify";
import type { JwtPayload } from "jsonwebtoken";
import { ConfigService } from "../utils/ConfigService";

dotenv.configDotenv();

const SECRET_KEY = process.env.SECRET_KEY;
const config = ConfigService.getConfig();

export class PlanManagementController {
private UserInfoRepository = AppDataSource.getRepository(UserInfo);
private GroupInfoRepository = AppDataSource.getRepository(GroupInfo);
private PriorityInfoRepository = AppDataSource.getRepository(PriorityInfo);
private PlanInfoRepository = AppDataSource.getRepository(PlanInfo);

async createPlan(request: Request, response: Response, next: NextFunction) { }
async createPlan(request: Request, response: Response, next: NextFunction) {
const decodeToken = await tokenVerify(request.headers.authorization.split(" ")[1]);
if (!decodeToken) {
response.status(404).json({ message: "No permission." });
return;
}
const user = await this.UserInfoRepository
.createQueryBuilder("user")
.where("user.id = :id", { id: (decodeToken as JwtPayload).id })
.getOne();
const name: string = request.body.name;
const remark: string = request.body.remark;
const groupName: string = request.body.groupName;
const repeatName: string = request.body.repeatName;
const priorityName: string = request.body.priorityName;
const startDate: string = request.body.startDate;
const endDate: string = request.body.endDate;
let plan = await this.PlanInfoRepository
.createQueryBuilder("plan")
.leftJoinAndSelect("plan.user", "user")
.where("plan.name = :name AND user.id = :id", { name: name , id: (decodeToken as JwtPayload).id })
.getOne();
if (plan){
response.status(409).json({message: "Resource already exists."})
return;
}
plan = new PlanInfo();
plan.name = name;
plan.remark = remark;
plan.group = ;
}

async getPlan(
request: Request,
Expand All @@ -38,7 +68,7 @@ export class PlanManagementController {
async createGroup(request: Request, response: Response, next: NextFunction) { }

async getGroups(request: Request, response: Response, next: NextFunction) {
const decodeToken = jwt.verify(request.headers.authorization.split(" ")[1], SECRET_KEY);
const decodeToken = jwt.verify(request.headers.authorization.split(" ")[1], config.secretKey);
if (!decodeToken) {
response.status(404).json({ message: "no permission" });
return;
Expand All @@ -56,7 +86,7 @@ export class PlanManagementController {
async setGroup(request: Request, response: Response, next: NextFunction) { }

async getPlans(request: Request, response: Response, next: NextFunction) {
const decodeToken = jwt.verify(request.headers.authorization.split(" ")[1], SECRET_KEY);
const decodeToken = jwt.verify(request.headers.authorization.split(" ")[1], config.secretKey);
if (!decodeToken) {
response.status(404).json({ message: "no permission" });
return;
Expand Down
155 changes: 80 additions & 75 deletions database/src/controller/UserInfoController.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,88 +4,93 @@ import { UserInfo } from "../entity/UserInfo";
import { tokenVerify } from "../utils/tokenVerify";
import { VerificationInfoMap } from "../utils/VerificationInfoMap";
import type { JwtPayload } from "jsonwebtoken";
import { findExistingUser } from "../utils/findExistingUser";


export class UserInfoController {
private UserInfoRepository = AppDataSource.getRepository(UserInfo);
private verificationInfoMap = VerificationInfoMap.getVerificationInfoMap();
private UserInfoRepository = AppDataSource.getRepository(UserInfo);
private verificationInfoMap = VerificationInfoMap.getVerificationInfoMap();

async getUserInfo(request: Request, response: Response, next: NextFunction) {
const decodeToken = await tokenVerify(request.headers.authorization.split(" ")[1]);
if (!decodeToken) {
response.status(404).json({ message: "no permission" });
return;
}
const id = parseInt(request.params.id);
const user = await this.UserInfoRepository.findOneBy({ id });
if (!user) {
response.status(404).json({ message: "userInfo not found" });
return;
}
response.json(user);
}
async getUserInfo(request: Request, response: Response, next: NextFunction) {
try {
const decodeToken = await tokenVerify(request.headers.authorization.split(" ")[1]);
if (!decodeToken) {
throw new Error('Invalid token');
}

async editEmail(request: Request, response: Response, next: NextFunction) {
const oldEmail: string = request.body.oldEmail;
const newEmail: string = request.body.newEmail;
const verificationInfo = this.verificationInfoMap.get(newEmail);
if (!verificationInfo?.verificationResult) {
response.status(400).json({ message: "Verification failed." });
return;
}
const user = await this.UserInfoRepository
.createQueryBuilder("user")
.where("user.email = :email AND user.activated = 1", { email: oldEmail })
.getOne();
console.log(oldEmail, newEmail, verificationInfo, user);
user.email = newEmail;
await this.UserInfoRepository.save(user);
response.json(user);
}
const id = parseInt(request.params.id);
const user = await findExistingUser(id, null, null);

// redis hashtable\publisher
// celery
// kafka
response.status(200).json(user);
} catch (error) {
const errorMessage = error.message || "An unexpected error occurred.";
response.status(500).json({ status: "error", message: errorMessage });
}
}

async editPasswordHash(
request: Request,
response: Response,
next: NextFunction,
) {
async editEmail(request: Request, response: Response, next: NextFunction) {
try {
const { newEmail, oldEmail } = request.body;

const email: string = request.body.email;
const passwordHash: string = request.body.passwordHash;
const verificationInfo = this.verificationInfoMap.get(email);
if (!verificationInfo?.verificationResult) {
response.status(400).json({ message: "Verification failed." });
return;
}
const user = await this.UserInfoRepository
.createQueryBuilder("user")
.where("user.email = :email AND user.activated = 1", { email })
.getOne();
user.passwordHash = passwordHash;
await this.UserInfoRepository.save(user);
response.json(user);
}
const verificationInfo = this.verificationInfoMap.get(newEmail);
if (!verificationInfo?.verificationResult) {
throw new Error("Verification failed.");
}

async editAvatarUrl(
request: Request,
response: Response,
next: NextFunction,
) {
const decodeToken = await tokenVerify(request.headers.authorization.split(" ")[1]);
if (!decodeToken) {
response.status(404).json({ message: "No permission." });
return;
}
const avatarUrl: string = request.body.avatarUrl;
const user = await this.UserInfoRepository
.createQueryBuilder("user")
.where("user.id = :id", { id: (decodeToken as JwtPayload).id })
.getOne();
user.avatarUrl = avatarUrl;
await this.UserInfoRepository.save(user);
response.json(user);
}
const user = await findExistingUser(null, oldEmail, null);
user.email = newEmail;
await this.UserInfoRepository.save(user);

response.status(200).json(user);
} catch (error) {
const errorMessage = error.message || "An unexpected error occurred.";
response.status(500).json({ status: "error", message: errorMessage });
}
}


async editPasswordHash(
request: Request,
response: Response,
next: NextFunction,
) {

try {
const { email, passwordHash } = request.body;
const verificationInfo = this.verificationInfoMap.get(email);
if (!verificationInfo?.verificationResult) {
throw new Error("Verification failed.");
}
const user = await findExistingUser(null, email, null);
user.passwordHash = passwordHash;
await this.UserInfoRepository.save(user);

response.status(200).json(user);
} catch (error) {
const errorMessage = error.message || "An unexpected error occurred.";
response.status(500).json({ status: "error", message: errorMessage });
}
}

async editAvatarUrl(
request: Request,
response: Response,
next: NextFunction,
) {
try {
const { avatarUrl } = request.body;
const decodeToken = await tokenVerify(request.headers.authorization.split(" ")[1]);
if (!decodeToken) {
throw new Error("Verification failed.");
}
const user = await findExistingUser((decodeToken as JwtPayload).id, null, null);
user.avatarUrl = avatarUrl;
await this.UserInfoRepository.save(user);

response.status(200).json(user);
} catch (error) {
const errorMessage = error.message || "An unexpected error occurred.";
response.status(500).json({ status: "error", message: errorMessage });
}
}
}
32 changes: 32 additions & 0 deletions database/src/utils/ConfigService.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
import * as dotenv from "dotenv";

dotenv.configDotenv();

export interface Config {
secretKey : string;
accessTokenExpiration : number;
refreshTokenExpiration: number;
systemEmail : string;
systemEmailPassword : string;
verificationCodeLen : number;
verificationMaxCount : number;
}

export class ConfigService {
private static config: Config;
private constructor() { }
public static getConfig() {
if (!ConfigService.config) {
ConfigService.config = {
secretKey : process.env.SECRET_KEY || "",
accessTokenExpiration : parseInt(process.env.ACCESS_TOKEN_EXPIRATION) || 0,
refreshTokenExpiration: parseInt(process.env.REFRESH_TOKEN_EXPIRATION) || 0,
systemEmail : process.env.SYSTEM_EMAIL || "",
systemEmailPassword : process.env.SYSTEM_EMAIL_PASSWORD || "",
verificationCodeLen : parseInt(process.env.VERIFICATION_CODE_LEN) || 4,
verificationMaxCount : parseInt(process.env.VERIFICATION_MAX_COUNT) || 5,
};
}
return ConfigService.config;
}
}
15 changes: 15 additions & 0 deletions database/src/utils/VerificationInfoMap.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,4 +16,19 @@ export class VerificationInfoMap {
}
return VerificationInfoMap.verificationInfoMap;
}

public static createVerificationInfo(verificationCode: string, receiverEmail: string) {
const verificationInfo: VerificationInfo = {
verificationCode,
email: receiverEmail,
timestamp: Date.now(),
verificationResult: false,
verificationCount: 0,
};
VerificationInfoMap.verificationInfoMap.set(receiverEmail, verificationInfo);

setTimeout(() => {
VerificationInfoMap.verificationInfoMap.delete(receiverEmail);
}, 120000);
}
}
22 changes: 22 additions & 0 deletions database/src/utils/findExistingUser.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
import { UserInfo } from "../entity/UserInfo";

export async function findExistingUser(id: number = null, email: string = null, passwordHash: string = null): Promise<UserInfo | null> {
if (id) {
const userById = await this.UserInfoRepository.findOneBy({ id: id, activated: true });
if (userById) {
return userById;
}
} else if (email) {
const queryBuilder = this.UserInfoRepository
.createQueryBuilder("user")
.where("user.email = :email AND user.activated = 1", { email });

if (passwordHash) {
queryBuilder.andWhere("user.passwordHash = :passwordHash", { passwordHash });
}

const userByEmail = await queryBuilder.getOne();
return userByEmail;
}
return null;
}
Loading

0 comments on commit d174b3d

Please sign in to comment.