215 lines
7.3 KiB
TypeScript
215 lines
7.3 KiB
TypeScript
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; |