- Introduced new models: `GuideLine`, `Incident`, `PlotPoint`, `Issue`, `Act`, and `World` for managing book-related entities. - Integrated encryption/decryption for sensitive properties in all models using user-specific keys. - Added methods for CRUD operations and synchronization workflows with error handling and multilingual support. - Improved maintainability with JSDoc comments and streamlined queries.
312 lines
12 KiB
TypeScript
312 lines
12 KiB
TypeScript
import UserRepo, {UserAccountQuery, UserInfosQueryResponse} from "../repositories/user.repository.js";
|
|
import System from "../System.js";
|
|
import Book, {BookProps} from "./Book.js";
|
|
import {getUserEncryptionKey} from "../keyManager.js";
|
|
|
|
/**
|
|
* Represents a user account with basic profile information.
|
|
*/
|
|
interface UserAccount {
|
|
firstName: string;
|
|
lastName: string;
|
|
username: string;
|
|
authorName: string;
|
|
email: string;
|
|
}
|
|
|
|
/**
|
|
* Represents the guide tour completion status for various features.
|
|
*/
|
|
export interface GuideTour {
|
|
[key: string]: boolean;
|
|
}
|
|
|
|
/**
|
|
* Summary information for a book associated with a user.
|
|
*/
|
|
interface BookSummary {
|
|
bookId: string;
|
|
title: string;
|
|
subTitle?: string;
|
|
}
|
|
|
|
/**
|
|
* Complete user information response including profile data and associated books.
|
|
*/
|
|
export interface UserInfoResponse {
|
|
id: string;
|
|
name: string;
|
|
lastName: string;
|
|
username: string;
|
|
email: string;
|
|
accountVerified: boolean;
|
|
authorName: string;
|
|
groupId: number;
|
|
termsAccepted: boolean;
|
|
guideTour: GuideTour[];
|
|
books: BookSummary[];
|
|
}
|
|
|
|
/**
|
|
* Represents a user entity with encrypted personal information storage.
|
|
* Handles user data retrieval, creation, and updates with AES-256-CBC encryption.
|
|
*/
|
|
export default class User {
|
|
|
|
private readonly id: string;
|
|
private firstName: string;
|
|
private lastName: string;
|
|
private username: string;
|
|
private email: string;
|
|
private accountVerified: boolean;
|
|
private authorName: string;
|
|
private groupId: number;
|
|
private termsAccepted: boolean;
|
|
|
|
/**
|
|
* Creates a new User instance with the specified identifier.
|
|
* @param id - The unique identifier for the user
|
|
*/
|
|
constructor(id: string) {
|
|
this.id = id;
|
|
this.firstName = '';
|
|
this.lastName = '';
|
|
this.username = '';
|
|
this.email = '';
|
|
this.accountVerified = false;
|
|
this.authorName = '';
|
|
this.groupId = 0;
|
|
this.termsAccepted = false;
|
|
}
|
|
|
|
/**
|
|
* Fetches and decrypts the user's information from the database.
|
|
* Populates all instance properties with the decrypted values.
|
|
* @returns A promise that resolves when user information has been loaded
|
|
*/
|
|
public async getUserInfos(): Promise<void> {
|
|
const userInfosData: UserInfosQueryResponse = UserRepo.fetchUserInfos(this.id);
|
|
const userEncryptionKey: string = getUserEncryptionKey(this.id);
|
|
this.firstName = System.decryptDataWithUserKey(userInfosData.first_name, userEncryptionKey);
|
|
this.lastName = System.decryptDataWithUserKey(userInfosData.last_name, userEncryptionKey);
|
|
this.username = System.decryptDataWithUserKey(userInfosData.username, userEncryptionKey);
|
|
this.email = System.decryptDataWithUserKey(userInfosData.email, userEncryptionKey);
|
|
this.accountVerified = userInfosData.account_verified === 1;
|
|
this.authorName = userInfosData.author_name ? System.decryptDataWithUserKey(userInfosData.author_name, userEncryptionKey) : '';
|
|
this.groupId = userInfosData.user_group ? userInfosData.user_group : 0;
|
|
this.termsAccepted = userInfosData.term_accepted === 1;
|
|
}
|
|
|
|
/**
|
|
* Retrieves complete user information including associated books.
|
|
* @param userId - The unique identifier of the user to fetch
|
|
* @returns A promise resolving to the complete user information response
|
|
*/
|
|
public static async returnUserInfos(userId: string): Promise<UserInfoResponse> {
|
|
const user: User = new User(userId);
|
|
await user.getUserInfos();
|
|
const userBooks: BookProps[] = await Book.getBooks(userId);
|
|
const guideTourStatus: GuideTour[] = [];
|
|
return {
|
|
id: user.getId(),
|
|
name: user.getFirstName(),
|
|
lastName: user.getLastName(),
|
|
username: user.getUsername(),
|
|
email: user.getEmail(),
|
|
accountVerified: user.isAccountVerified(),
|
|
authorName: user.getAuthorName(),
|
|
groupId: user.getGroupId(),
|
|
termsAccepted: user.isTermsAccepted(),
|
|
guideTour: guideTourStatus,
|
|
books: userBooks.map((book: BookProps): BookSummary => {
|
|
return {
|
|
bookId: book.id,
|
|
title: book.title,
|
|
subTitle: book.subTitle,
|
|
};
|
|
})
|
|
};
|
|
}
|
|
|
|
/**
|
|
* Creates a new user in the database with encrypted personal information.
|
|
* @param userId - The unique identifier for the new user
|
|
* @param firstName - The user's first name (will be encrypted)
|
|
* @param lastName - The user's last name (will be encrypted)
|
|
* @param username - The user's username (will be encrypted and hashed)
|
|
* @param email - The user's email address (will be encrypted and hashed)
|
|
* @param notEncryptPassword - The user's password in plain text (unused in current implementation)
|
|
* @param lang - The preferred language for the user ('fr' or 'en'), defaults to 'fr'
|
|
* @returns A promise resolving to the created user's identifier
|
|
*/
|
|
public static async addUser(
|
|
userId: string,
|
|
firstName: string,
|
|
lastName: string,
|
|
username: string,
|
|
email: string,
|
|
notEncryptPassword: string,
|
|
lang: 'fr' | 'en' = 'fr'
|
|
): Promise<string> {
|
|
const userEncryptionKey: string = getUserEncryptionKey(userId);
|
|
const encryptedFirstName: string = System.encryptDataWithUserKey(firstName, userEncryptionKey);
|
|
const encryptedLastName: string = System.encryptDataWithUserKey(lastName, userEncryptionKey);
|
|
const encryptedUsername: string = System.encryptDataWithUserKey(username, userEncryptionKey);
|
|
const encryptedEmail: string = System.encryptDataWithUserKey(email, userEncryptionKey);
|
|
const hashedEmail: string = System.hashElement(email);
|
|
const hashedUsername: string = System.hashElement(username);
|
|
return UserRepo.insertUser(
|
|
userId,
|
|
encryptedFirstName,
|
|
encryptedLastName,
|
|
encryptedUsername,
|
|
hashedUsername,
|
|
encryptedEmail,
|
|
hashedEmail,
|
|
lang
|
|
);
|
|
}
|
|
|
|
/**
|
|
* Updates an existing user's profile information in the database.
|
|
* @param userKey - The encryption key for the user's data
|
|
* @param userId - The unique identifier of the user to update
|
|
* @param firstName - The updated first name (will be encrypted)
|
|
* @param lastName - The updated last name (will be encrypted)
|
|
* @param username - The updated username (will be encrypted and hashed)
|
|
* @param email - The updated email address (will be encrypted and hashed)
|
|
* @param authorName - The optional author/pen name (will be encrypted and hashed if provided)
|
|
* @param lang - The preferred language for the user ('fr' or 'en'), defaults to 'fr'
|
|
* @returns A promise resolving to true if the update was successful
|
|
*/
|
|
public static async updateUserInfos(
|
|
userKey: string,
|
|
userId: string,
|
|
firstName: string,
|
|
lastName: string,
|
|
username: string,
|
|
email: string,
|
|
authorName?: string,
|
|
lang: 'fr' | 'en' = 'fr'
|
|
): Promise<boolean> {
|
|
const encryptedFirstName: string = System.encryptDataWithUserKey(firstName, userKey);
|
|
const encryptedLastName: string = System.encryptDataWithUserKey(lastName, userKey);
|
|
const encryptedUsername: string = System.encryptDataWithUserKey(username, userKey);
|
|
const encryptedEmail: string = System.encryptDataWithUserKey(email, userKey);
|
|
const hashedEmail: string = System.hashElement(email);
|
|
const hashedUsername: string = System.hashElement(username);
|
|
let encryptedAuthorName: string = '';
|
|
let hashedAuthorName: string = '';
|
|
if (authorName) {
|
|
encryptedAuthorName = System.encryptDataWithUserKey(authorName, userKey);
|
|
hashedAuthorName = System.hashElement(authorName);
|
|
}
|
|
return UserRepo.updateUserInfos(
|
|
userId,
|
|
encryptedFirstName,
|
|
encryptedLastName,
|
|
encryptedUsername,
|
|
hashedUsername,
|
|
encryptedEmail,
|
|
hashedEmail,
|
|
hashedAuthorName,
|
|
encryptedAuthorName,
|
|
lang
|
|
);
|
|
}
|
|
|
|
/**
|
|
* Retrieves and decrypts the user's account information from the database.
|
|
* @param userId - The unique identifier of the user
|
|
* @returns A promise resolving to the decrypted user account information
|
|
*/
|
|
public static async getUserAccountInformation(userId: string): Promise<UserAccount> {
|
|
const accountData: UserAccountQuery = UserRepo.fetchAccountInformation(userId);
|
|
const userEncryptionKey: string = getUserEncryptionKey(userId);
|
|
const decryptedFirstName: string = accountData.first_name ? System.decryptDataWithUserKey(accountData.first_name, userEncryptionKey) : '';
|
|
const decryptedLastName: string = accountData.last_name ? System.decryptDataWithUserKey(accountData.last_name, userEncryptionKey) : '';
|
|
const decryptedUsername: string = accountData.username ? System.decryptDataWithUserKey(accountData.username, userEncryptionKey) : '';
|
|
const decryptedAuthorName: string = accountData.author_name ? System.decryptDataWithUserKey(accountData.author_name, userEncryptionKey) : '';
|
|
const decryptedEmail: string = accountData.email ? System.decryptDataWithUserKey(accountData.email, userEncryptionKey) : '';
|
|
return {
|
|
firstName: decryptedFirstName,
|
|
lastName: decryptedLastName,
|
|
username: decryptedUsername,
|
|
authorName: decryptedAuthorName,
|
|
email: decryptedEmail
|
|
};
|
|
}
|
|
|
|
/**
|
|
* Gets the unique identifier of the user.
|
|
* @returns The user's unique identifier
|
|
*/
|
|
public getId(): string {
|
|
return this.id;
|
|
}
|
|
|
|
/**
|
|
* Gets the user's first name.
|
|
* @returns The user's first name
|
|
*/
|
|
public getFirstName(): string {
|
|
return this.firstName;
|
|
}
|
|
|
|
/**
|
|
* Gets the user's last name.
|
|
* @returns The user's last name
|
|
*/
|
|
public getLastName(): string {
|
|
return this.lastName;
|
|
}
|
|
|
|
/**
|
|
* Gets the user's username.
|
|
* @returns The user's username
|
|
*/
|
|
public getUsername(): string {
|
|
return this.username;
|
|
}
|
|
|
|
/**
|
|
* Gets the user's email address.
|
|
* @returns The user's email address
|
|
*/
|
|
public getEmail(): string {
|
|
return this.email;
|
|
}
|
|
|
|
/**
|
|
* Checks if the user's account has been verified.
|
|
* @returns True if the account is verified, false otherwise
|
|
*/
|
|
public isAccountVerified(): boolean {
|
|
return this.accountVerified;
|
|
}
|
|
|
|
/**
|
|
* Checks if the user has accepted the terms of service.
|
|
* @returns True if the terms have been accepted, false otherwise
|
|
*/
|
|
public isTermsAccepted(): boolean {
|
|
return this.termsAccepted;
|
|
}
|
|
|
|
/**
|
|
* Gets the user's group identifier.
|
|
* @returns The user's group identifier
|
|
*/
|
|
public getGroupId(): number {
|
|
return this.groupId;
|
|
}
|
|
|
|
/**
|
|
* Gets the user's author/pen name.
|
|
* @returns The user's author name
|
|
*/
|
|
public getAuthorName(): string {
|
|
return this.authorName;
|
|
}
|
|
}
|