Recoded the dbUser and its collection class. StoredPlayer and StoredPlayerCollection are also finished
This commit is contained in:
215
src/models/StoredUser.ts
Normal file
215
src/models/StoredUser.ts
Normal file
@@ -0,0 +1,215 @@
|
||||
import {SupportedLang} from "../enums";
|
||||
import Player, {MongoStoredPlayer, StoredPlayer, StoredPlayerData} from "./StoredPlayer";
|
||||
import {AccountStats} from "./stats";
|
||||
import {SavedGameData, StoredSavedGame} from "./savedGame";
|
||||
import {
|
||||
GenericModelError, getMongoObjectCollection,
|
||||
MongoStoredObject,
|
||||
MongoStoredObjectCollection,
|
||||
StoredObject,
|
||||
StoredObjectCollection,
|
||||
StoredObjectId,
|
||||
tryQuery
|
||||
} from "./utils";
|
||||
import mongo from "mongodb";
|
||||
import StoredPlayers from "./StoredPlayer";
|
||||
import bcrypt from "bcrypt";
|
||||
|
||||
export class CredentialsTakenError extends Error {
|
||||
public emailExists: boolean;
|
||||
public usernameExists: boolean;
|
||||
constructor(usernameExists: boolean, emailExists: boolean) {
|
||||
super("Registration failure:" + usernameExists + emailExists);
|
||||
this.usernameExists = usernameExists;
|
||||
this.emailExists = emailExists;
|
||||
this.name = "CredentialsTakenError";
|
||||
}
|
||||
}
|
||||
|
||||
export interface StoredUserData {
|
||||
_id: string;
|
||||
username: string;
|
||||
email: string;
|
||||
password: string;
|
||||
lang: SupportedLang;
|
||||
friends: string[];
|
||||
player: StoredObjectId;
|
||||
guests: StoredObjectId[];
|
||||
accountStats: AccountStats;
|
||||
savedGames: SavedGameData[];
|
||||
}
|
||||
|
||||
export interface StoredUser extends StoredObject {
|
||||
getLoginDetails(): Promise<LoginDetails>
|
||||
preferredLang(): Promise<SupportedLang>;
|
||||
getFriends(): Promise<StoredUser[]>;
|
||||
getGuests(): Promise<StoredPlayer[]>;
|
||||
getAccountStats(): Promise<AccountStats>;
|
||||
getSavedGames(): Promise<StoredSavedGame[]>;
|
||||
getMainPlayerInfo(): Promise<StoredPlayer>;
|
||||
findGuestByNick(nick: string): Promise<StoredPlayer | null>;
|
||||
changeLang(lang: SupportedLang): Promise<void>;
|
||||
addGame(game: any): Promise<void>;
|
||||
getGuestById(guestId: string): Promise<StoredPlayer>;
|
||||
addGuest(nick: string): Promise<StoredPlayer>;
|
||||
updateGuest(guestParams: GuestUpdateParams): Promise<StoredPlayer>;
|
||||
deleteGuest(guestId: string): Promise<StoredPlayer | null>;
|
||||
}
|
||||
|
||||
type GuestUpdateParams = { id: string, newNick: string };
|
||||
type LoginDetails = { username: string, email: string, password: string };
|
||||
|
||||
class MongoStoredUser extends MongoStoredObject<StoredUserData> implements StoredUser {
|
||||
constructor(data: StoredUserData) {
|
||||
super(data);
|
||||
}
|
||||
|
||||
async getLoginDetails(): Promise<LoginDetails> {
|
||||
return {username: this.data.username, email: this.data.email, password: this.data.password};
|
||||
}
|
||||
|
||||
async preferredLang(): Promise<SupportedLang> {
|
||||
return this.data.lang;
|
||||
}
|
||||
|
||||
async getFriends(): Promise<StoredUser[]> {
|
||||
const friends: StoredUser[] = [];
|
||||
for (const friendId in this.data.guests) {
|
||||
const foundFriend = await StoredUsers.findById(friendId) as StoredUser;
|
||||
friends.push(foundFriend);
|
||||
}
|
||||
return friends;
|
||||
}
|
||||
|
||||
async getGuests(): Promise<StoredPlayer[]> {
|
||||
const guests: StoredPlayer[] = [];
|
||||
for (const guestId in this.data.guests) {
|
||||
const foundGuest = await StoredPlayers.findById(guestId) as StoredPlayer;
|
||||
guests.push(foundGuest);
|
||||
}
|
||||
return guests;
|
||||
}
|
||||
|
||||
async getAccountStats(): Promise<AccountStats> {
|
||||
return this.data.accountStats;
|
||||
}
|
||||
|
||||
async getSavedGames(): Promise<StoredSavedGame[]> {
|
||||
return this.data.savedGames.map(savedGame => new MongoStoredSavedGame(savedGame));
|
||||
}
|
||||
|
||||
async getMainPlayerInfo(): Promise<StoredPlayer> {
|
||||
return StoredPlayers.findById(this.data.player) as Promise<StoredPlayer>;
|
||||
}
|
||||
|
||||
async findGuestByNick(nick: string): Promise<StoredPlayer | null> {
|
||||
const guests = await this.getGuests();
|
||||
for (const guest of guests) {
|
||||
if (guest.nick() == nick) {
|
||||
return guest;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
async changeLang(lang: SupportedLang): Promise<void> {
|
||||
this.data.lang = lang;
|
||||
}
|
||||
|
||||
async addGame(game: SavedGameData): Promise<void> {
|
||||
this.data.savedGames.push(game);
|
||||
}
|
||||
|
||||
getGuestById(guestId: string): Promise<StoredPlayer> {
|
||||
return StoredPlayers.findById(guestId) as Promise<StoredPlayer>;
|
||||
}
|
||||
|
||||
async addGuest(nick: string): Promise<StoredPlayer> {
|
||||
const newGuest = await StoredPlayers.newPlayer(nick);
|
||||
this.data.guests.push(newGuest.id());
|
||||
return newGuest;
|
||||
}
|
||||
|
||||
async updateGuest(guestParams: GuestUpdateParams): Promise<StoredPlayer> {
|
||||
const guest = await StoredPlayers.findById(guestParams.id) as StoredPlayer;
|
||||
await guest.setNick(guestParams.newNick);
|
||||
await StoredPlayers.save(guest);
|
||||
return guest;
|
||||
}
|
||||
|
||||
async deleteGuest(guestId: string): Promise<StoredPlayer | null> {
|
||||
return StoredPlayers.deleteById(guestId);
|
||||
}
|
||||
}
|
||||
|
||||
export interface StoredUserCollection extends StoredObjectCollection<StoredUser> {
|
||||
findByEmail(emailQuery: string): Promise<StoredUser | null>;
|
||||
registerUser(loginDetails: LoginDetails): Promise<StoredUser>;
|
||||
userWithEmailExists(email: string): Promise<boolean>;
|
||||
userWithUsernameExists(username: string): Promise<boolean>;
|
||||
getSerializedAuthUser(id: string): Promise<StoredUser>;
|
||||
}
|
||||
|
||||
class MongoStoredUserCollection extends MongoStoredObjectCollection<StoredUserData, StoredUser> implements StoredUserCollection {
|
||||
constructor(collectionClient: mongo.Collection) {
|
||||
super(collectionClient, MongoStoredUser);
|
||||
}
|
||||
|
||||
findById(id: string): Promise<StoredUser | null> {
|
||||
return this.findObjectById(id);
|
||||
}
|
||||
|
||||
findByEmail(emailQuery: string): Promise<StoredUser | null> {
|
||||
return tryQuery(async () =>
|
||||
await this.findObjectByAttribute("email", emailQuery)
|
||||
);
|
||||
}
|
||||
|
||||
private async addNewUser(loginDetails: LoginDetails): Promise<StoredUser> {
|
||||
const newPlayer = await StoredPlayers.newPlayer(loginDetails.username);
|
||||
return this.create({
|
||||
username: loginDetails.username,
|
||||
email: loginDetails.email,
|
||||
password: loginDetails.password,
|
||||
lang: SupportedLang.gb,
|
||||
player: newPlayer.id()
|
||||
});
|
||||
}
|
||||
|
||||
async registerUser(loginDetails: LoginDetails): Promise<StoredUser> {
|
||||
const usernameTaken = await this.userWithUsernameExists(loginDetails.username);
|
||||
const emailTaken = await this.userWithEmailExists(loginDetails.email);
|
||||
if (usernameTaken || emailTaken) {
|
||||
throw new CredentialsTakenError(usernameTaken, emailTaken);
|
||||
}
|
||||
else {
|
||||
const hashedPassword = await bcrypt.hash(loginDetails.password, 10);
|
||||
return tryQuery(() =>
|
||||
this.addNewUser({...loginDetails, password: hashedPassword})
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
async userWithEmailExists(email: string): Promise<boolean> {
|
||||
const object = await this.findObjectByAttribute("email", email);
|
||||
return object !== null;
|
||||
}
|
||||
|
||||
async userWithUsernameExists(username: string): Promise<boolean> {
|
||||
const object = await this.findObjectByAttribute("username", username);
|
||||
return object !== null;
|
||||
}
|
||||
|
||||
async getSerializedAuthUser(id: string): Promise<StoredUser> {
|
||||
const dbResult = await this.findById(id);
|
||||
if (dbResult) {
|
||||
return dbResult;
|
||||
}
|
||||
else {
|
||||
throw new GenericModelError("User not found!");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const StoredUsers = new MongoStoredUserCollection(getMongoObjectCollection("users"));
|
||||
export default StoredUsers;
|
||||
Reference in New Issue
Block a user