Compare commits
3 Commits
Author | SHA1 | Date | |
---|---|---|---|
e86d909e07 | |||
|
39ba4856a2 | ||
51a95f9bf1 |
@ -4,10 +4,12 @@ import ip from 'ip';
|
|||||||
|
|
||||||
import Server from './framework/express/server';
|
import Server from './framework/express/server';
|
||||||
import UserModel from './framework/mongo/user';
|
import UserModel from './framework/mongo/user';
|
||||||
|
import CardModel from './framework/mongo/card';
|
||||||
import { Config } from './config';
|
import { Config } from './config';
|
||||||
|
|
||||||
export type Services = {
|
export type Services = {
|
||||||
userModel: UserModel;
|
userModel: UserModel;
|
||||||
|
cardModel: CardModel;
|
||||||
};
|
};
|
||||||
|
|
||||||
const configFile = process.env.CONFIGFILE;
|
const configFile = process.env.CONFIGFILE;
|
||||||
@ -23,6 +25,7 @@ const db = mongo.db(config.mongo.dbName);
|
|||||||
|
|
||||||
const services: Services = {
|
const services: Services = {
|
||||||
userModel: new UserModel(db),
|
userModel: new UserModel(db),
|
||||||
|
cardModel: new CardModel(db),
|
||||||
};
|
};
|
||||||
|
|
||||||
const server = new Server(config.server, config.mongo, services);
|
const server = new Server(config.server, config.mongo, services);
|
||||||
@ -34,10 +37,10 @@ process.on('SIGINT', async () => {
|
|||||||
process.exit();
|
process.exit();
|
||||||
});
|
});
|
||||||
|
|
||||||
server.start(() =>
|
server.start().then(() => {
|
||||||
console.log(
|
console.log(
|
||||||
`Running on http://127.0.0.1:${config.server.port} http://${ip.address()}:${
|
`Running on http://127.0.0.1:${config.server.port} http://${ip.address()}:${
|
||||||
config.server.port
|
config.server.port
|
||||||
}`,
|
}`,
|
||||||
),
|
|
||||||
);
|
);
|
||||||
|
});
|
||||||
|
37
api/src/entities/card.ts
Normal file
37
api/src/entities/card.ts
Normal file
@ -0,0 +1,37 @@
|
|||||||
|
import { CardCtor, CardInfo, CardRarity, CombatStats } from '@core';
|
||||||
|
import { Entity } from './entity';
|
||||||
|
|
||||||
|
export class Card extends Entity implements CardInfo {
|
||||||
|
name: string;
|
||||||
|
rarity: keyof typeof CardRarity;
|
||||||
|
stats: CombatStats;
|
||||||
|
thumbnail: string;
|
||||||
|
model: string;
|
||||||
|
|
||||||
|
constructor(raw: CardCtor) {
|
||||||
|
super(raw);
|
||||||
|
this.name = raw.name || '';
|
||||||
|
this.rarity = raw.rarity || CardRarity.COMMON;
|
||||||
|
this.stats = raw.stats || {
|
||||||
|
baseAtk: 0,
|
||||||
|
baseCrit: 0,
|
||||||
|
baseDef: 0,
|
||||||
|
multAtk: 0,
|
||||||
|
multCrit: 0,
|
||||||
|
multDef: 0,
|
||||||
|
};
|
||||||
|
this.thumbnail = raw.thumbnail || '';
|
||||||
|
this.model = raw.model || '';
|
||||||
|
}
|
||||||
|
|
||||||
|
Info(): CardInfo {
|
||||||
|
return {
|
||||||
|
uuid: this.uuid,
|
||||||
|
name: this.name,
|
||||||
|
rarity: this.rarity,
|
||||||
|
stats: this.stats,
|
||||||
|
thumbnail: this.thumbnail,
|
||||||
|
model: this.model,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
@ -1,12 +1,15 @@
|
|||||||
import { EntityCtor, EntityInfo } from '@core';
|
import { EntityCtor, EntityInfo } from '@core';
|
||||||
import { randomUUID } from 'crypto';
|
import { randomUUID } from 'crypto';
|
||||||
|
import { ObjectId } from 'mongodb';
|
||||||
|
|
||||||
export class Entity implements EntityInfo {
|
export class Entity implements EntityInfo {
|
||||||
|
_id: ObjectId;
|
||||||
uuid: string;
|
uuid: string;
|
||||||
createdAt: Date;
|
createdAt: Date;
|
||||||
updatedAt: Date;
|
updatedAt: Date;
|
||||||
|
|
||||||
constructor(raw: EntityCtor) {
|
constructor(raw: EntityCtor) {
|
||||||
|
this._id = raw._id || new ObjectId();
|
||||||
this.uuid = raw.uuid || randomUUID();
|
this.uuid = raw.uuid || randomUUID();
|
||||||
this.createdAt = raw.createdAt || new Date();
|
this.createdAt = raw.createdAt || new Date();
|
||||||
this.updatedAt = raw.updatedAt || new Date();
|
this.updatedAt = raw.updatedAt || new Date();
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
import {
|
import {
|
||||||
|
CardInfo,
|
||||||
UserCtor,
|
UserCtor,
|
||||||
UserInfo,
|
UserInfo,
|
||||||
UserInfoWithPassword,
|
UserInfoWithPassword,
|
||||||
@ -6,17 +7,20 @@ import {
|
|||||||
UserWithPasswordCtor,
|
UserWithPasswordCtor,
|
||||||
} from '@core';
|
} from '@core';
|
||||||
import { getHashedPassword } from '../functions/password';
|
import { getHashedPassword } from '../functions/password';
|
||||||
|
import { Card } from './card';
|
||||||
import { Entity } from './entity';
|
import { Entity } from './entity';
|
||||||
|
|
||||||
export class User extends Entity implements UserInfo {
|
export class User extends Entity implements UserInfo {
|
||||||
username: string;
|
username: string;
|
||||||
role: keyof typeof UserRoles;
|
role: keyof typeof UserRoles;
|
||||||
|
cards: Card[];
|
||||||
|
|
||||||
constructor(raw: UserCtor) {
|
constructor(raw: UserCtor) {
|
||||||
super(raw);
|
super(raw);
|
||||||
|
|
||||||
this.username = raw.username || '';
|
this.username = raw.username || '';
|
||||||
this.role = raw.role || UserRoles.USER;
|
this.role = raw.role || UserRoles.USER;
|
||||||
|
this.cards = raw.cards ? raw.cards.map(card => new Card(card)) : [];
|
||||||
}
|
}
|
||||||
|
|
||||||
Info(): UserInfo {
|
Info(): UserInfo {
|
||||||
@ -24,6 +28,7 @@ export class User extends Entity implements UserInfo {
|
|||||||
uuid: this.uuid,
|
uuid: this.uuid,
|
||||||
username: this.username,
|
username: this.username,
|
||||||
role: this.role,
|
role: this.role,
|
||||||
|
cards: this.cards.map(card => card.Info()),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -42,6 +47,7 @@ export class UserWithPassword extends User implements UserInfoWithPassword {
|
|||||||
uuid: this.uuid,
|
uuid: this.uuid,
|
||||||
username: this.username,
|
username: this.username,
|
||||||
role: this.role,
|
role: this.role,
|
||||||
|
cards: this.cards.map(card => card.Info()),
|
||||||
password: this.password,
|
password: this.password,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
66
api/src/framework/express/card.ts
Normal file
66
api/src/framework/express/card.ts
Normal file
@ -0,0 +1,66 @@
|
|||||||
|
import { RequestHandler, Router } from 'express';
|
||||||
|
import { CreateCard, ListCards, ReadCard } from '../../functions/card';
|
||||||
|
import { Services } from '../../app';
|
||||||
|
import { CheckPermissions, getRequestId, ValidateSchema } from './middleware';
|
||||||
|
import { CreateCardSchema, ReadCardSchema } from './schema/card';
|
||||||
|
|
||||||
|
function CreateHandler(services: Services): RequestHandler {
|
||||||
|
const createCard = CreateCard(services);
|
||||||
|
|
||||||
|
return async (req, res, next) => {
|
||||||
|
try {
|
||||||
|
const card = await createCard(getRequestId(req), req.body);
|
||||||
|
res.status(200).send(card);
|
||||||
|
} catch (error) {
|
||||||
|
next({ status: 409, message: 'Card Already Exists' });
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
function ReadHandler(services: Services): RequestHandler {
|
||||||
|
const readCard = ReadCard(services);
|
||||||
|
|
||||||
|
return async (req, res, next) => {
|
||||||
|
try {
|
||||||
|
const card = await readCard(getRequestId(req), req.params.uuid);
|
||||||
|
res.status(200).send(card);
|
||||||
|
} catch (error) {
|
||||||
|
next({ status: 404, message: 'Card Not Found' });
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
function ListHandler(services: Services): RequestHandler {
|
||||||
|
const listCards = ListCards(services);
|
||||||
|
|
||||||
|
return async (req, res, next) => {
|
||||||
|
try {
|
||||||
|
const cards = await listCards(getRequestId(req));
|
||||||
|
res.status(200).send(cards);
|
||||||
|
} catch (error) {
|
||||||
|
next({ message: 'Unknown Error' });
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
export function Routes(services: Services) {
|
||||||
|
const router = Router();
|
||||||
|
|
||||||
|
router.post(
|
||||||
|
'/create',
|
||||||
|
CheckPermissions(),
|
||||||
|
CreateCardSchema(),
|
||||||
|
ValidateSchema(),
|
||||||
|
CreateHandler(services),
|
||||||
|
);
|
||||||
|
router.get(
|
||||||
|
'/read/:uuid',
|
||||||
|
CheckPermissions(),
|
||||||
|
ReadCardSchema(),
|
||||||
|
ValidateSchema(),
|
||||||
|
ReadHandler(services),
|
||||||
|
);
|
||||||
|
router.get('/list', CheckPermissions(), ListHandler(services));
|
||||||
|
|
||||||
|
return router;
|
||||||
|
}
|
@ -56,8 +56,6 @@ export function CheckPermissions(): RequestHandler {
|
|||||||
|
|
||||||
export function ValidateSchema(): RequestHandler {
|
export function ValidateSchema(): RequestHandler {
|
||||||
return (req, res, next) => {
|
return (req, res, next) => {
|
||||||
const error = validationResult(req);
|
|
||||||
|
|
||||||
const oldBody = req.body;
|
const oldBody = req.body;
|
||||||
req.body = matchedData(req, { locations: ['body'] });
|
req.body = matchedData(req, { locations: ['body'] });
|
||||||
|
|
||||||
@ -67,6 +65,7 @@ export function ValidateSchema(): RequestHandler {
|
|||||||
message: 'Unprocessable Entity',
|
message: 'Unprocessable Entity',
|
||||||
});
|
});
|
||||||
|
|
||||||
|
const error = validationResult(req);
|
||||||
error.isEmpty()
|
error.isEmpty()
|
||||||
? next()
|
? next()
|
||||||
: next({
|
: next({
|
||||||
@ -76,6 +75,12 @@ export function ValidateSchema(): RequestHandler {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function NotFoundHandler(): RequestHandler {
|
||||||
|
return (req, res, next) => {
|
||||||
|
next({ status: 404, message: 'Not Found' });
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
export function ErrorHandler(): ErrorRequestHandler {
|
export function ErrorHandler(): ErrorRequestHandler {
|
||||||
return (error, req, res, next) => {
|
return (error, req, res, next) => {
|
||||||
error.status
|
error.status
|
||||||
|
@ -1,11 +1,13 @@
|
|||||||
import { Router } from 'express';
|
import { Router } from 'express';
|
||||||
import { Services } from '../../app';
|
import { Services } from '../../app';
|
||||||
import * as user from './user';
|
import * as user from './user';
|
||||||
|
import * as card from './card';
|
||||||
|
|
||||||
export function Routes(services: Services) {
|
export function Routes(services: Services) {
|
||||||
const router = Router();
|
const router = Router();
|
||||||
|
|
||||||
router.use('/user', user.Routes(services));
|
router.use('/user', user.Routes(services));
|
||||||
|
router.use('/card', card.Routes(services));
|
||||||
|
|
||||||
return router;
|
return router;
|
||||||
}
|
}
|
||||||
|
29
api/src/framework/express/schema/card.ts
Normal file
29
api/src/framework/express/schema/card.ts
Normal file
@ -0,0 +1,29 @@
|
|||||||
|
import { checkSchema } from 'express-validator';
|
||||||
|
import { CardRarity } from '@core';
|
||||||
|
|
||||||
|
export const CreateCardSchema = () =>
|
||||||
|
checkSchema({
|
||||||
|
name: {
|
||||||
|
isString: true,
|
||||||
|
},
|
||||||
|
rarity: {
|
||||||
|
isIn: {
|
||||||
|
options: [Object.values(CardRarity)],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
thumbnail: {
|
||||||
|
isString: true,
|
||||||
|
},
|
||||||
|
model: {
|
||||||
|
isString: true,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
export const ReadCardSchema = () =>
|
||||||
|
checkSchema({
|
||||||
|
uuid: {
|
||||||
|
isUUID: {
|
||||||
|
options: 4,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
@ -1,15 +1,6 @@
|
|||||||
import { checkSchema } from 'express-validator';
|
import { checkSchema } from 'express-validator';
|
||||||
import { UserRoles } from '@core';
|
import { UserRoles } from '@core';
|
||||||
|
|
||||||
export const ReadUserSchema = () =>
|
|
||||||
checkSchema({
|
|
||||||
uuid: {
|
|
||||||
isUUID: {
|
|
||||||
options: 4,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
export const LoginUserSchema = () =>
|
export const LoginUserSchema = () =>
|
||||||
checkSchema({
|
checkSchema({
|
||||||
username: {
|
username: {
|
||||||
@ -37,8 +28,24 @@ export const CreateUserSchema = () =>
|
|||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
|
export const ReadUserSchema = () =>
|
||||||
|
checkSchema({
|
||||||
|
uuid: {
|
||||||
|
isUUID: {
|
||||||
|
options: 4,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
export const ListUsersSchema = () => checkSchema({});
|
||||||
|
|
||||||
export const UpdateUserSchema = () =>
|
export const UpdateUserSchema = () =>
|
||||||
checkSchema({
|
checkSchema({
|
||||||
|
uuid: {
|
||||||
|
isUUID: {
|
||||||
|
options: 4,
|
||||||
|
},
|
||||||
|
},
|
||||||
username: {
|
username: {
|
||||||
isString: true,
|
isString: true,
|
||||||
optional: true,
|
optional: true,
|
||||||
@ -54,3 +61,31 @@ export const UpdateUserSchema = () =>
|
|||||||
optional: true,
|
optional: true,
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
|
export const AddCardToUserSchema = () =>
|
||||||
|
checkSchema({
|
||||||
|
uuid: {
|
||||||
|
isUUID: {
|
||||||
|
options: 4,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
cardUuid: {
|
||||||
|
isUUID: {
|
||||||
|
options: 4,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
export const RemoveCardFromUserSchema = () =>
|
||||||
|
checkSchema({
|
||||||
|
uuid: {
|
||||||
|
isUUID: {
|
||||||
|
options: 4,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
cardUuid: {
|
||||||
|
isUUID: {
|
||||||
|
options: 4,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
@ -6,7 +6,7 @@ import { randomUUID } from 'crypto';
|
|||||||
import * as http from 'http';
|
import * as http from 'http';
|
||||||
|
|
||||||
import { Routes } from './router';
|
import { Routes } from './router';
|
||||||
import { RequestId, ErrorHandler } from './middleware';
|
import { RequestId, ErrorHandler, NotFoundHandler } from './middleware';
|
||||||
import { Services } from '../../app';
|
import { Services } from '../../app';
|
||||||
import { MongoConfig, ServerConfig } from '../../config';
|
import { MongoConfig, ServerConfig } from '../../config';
|
||||||
|
|
||||||
@ -32,7 +32,6 @@ class Server {
|
|||||||
origin: this.config.origin,
|
origin: this.config.origin,
|
||||||
}),
|
}),
|
||||||
);
|
);
|
||||||
this.app.use(RequestId());
|
|
||||||
this.app.use(
|
this.app.use(
|
||||||
session({
|
session({
|
||||||
proxy: process.env.NODE_ENV === 'production',
|
proxy: process.env.NODE_ENV === 'production',
|
||||||
@ -52,12 +51,16 @@ class Server {
|
|||||||
saveUninitialized: false,
|
saveUninitialized: false,
|
||||||
}),
|
}),
|
||||||
);
|
);
|
||||||
|
this.app.use(RequestId());
|
||||||
this.app.use(Routes(services));
|
this.app.use(Routes(services));
|
||||||
|
this.app.use(NotFoundHandler());
|
||||||
this.app.use(ErrorHandler());
|
this.app.use(ErrorHandler());
|
||||||
}
|
}
|
||||||
|
|
||||||
start(func: () => void): void {
|
async start(): Promise<void> {
|
||||||
this.server = this.app.listen(this.config.port, func);
|
return new Promise<void>((resolve, reject) => {
|
||||||
|
this.server = this.app.listen(this.config.port, resolve);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
async close(): Promise<void> {
|
async close(): Promise<void> {
|
||||||
|
@ -5,6 +5,8 @@ import {
|
|||||||
ReadUser,
|
ReadUser,
|
||||||
LoginUser,
|
LoginUser,
|
||||||
UpdateUser,
|
UpdateUser,
|
||||||
|
ListUsers,
|
||||||
|
AddCardToUser,
|
||||||
} from '../../functions/user';
|
} from '../../functions/user';
|
||||||
import {
|
import {
|
||||||
LoginUserSchema,
|
LoginUserSchema,
|
||||||
@ -12,10 +14,13 @@ import {
|
|||||||
ReadUserSchema,
|
ReadUserSchema,
|
||||||
LogoutUserSchema,
|
LogoutUserSchema,
|
||||||
UpdateUserSchema,
|
UpdateUserSchema,
|
||||||
|
ListUsersSchema,
|
||||||
|
AddCardToUserSchema,
|
||||||
|
RemoveCardFromUserSchema,
|
||||||
} from './schema/user';
|
} from './schema/user';
|
||||||
import { CheckPermissions, getRequestId, ValidateSchema } from './middleware';
|
import { CheckPermissions, getRequestId, ValidateSchema } from './middleware';
|
||||||
|
|
||||||
function LoginHandler(services: Services): RequestHandler {
|
function LoginUserHandler(services: Services): RequestHandler {
|
||||||
const login = LoginUser(services);
|
const login = LoginUser(services);
|
||||||
|
|
||||||
return async (req, res, next) => {
|
return async (req, res, next) => {
|
||||||
@ -29,7 +34,7 @@ function LoginHandler(services: Services): RequestHandler {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
function LogoutHandler(services: Services): RequestHandler {
|
function LogoutUserHandler(services: Services): RequestHandler {
|
||||||
return async (req, res, next) => {
|
return async (req, res, next) => {
|
||||||
if (req.session.user) {
|
if (req.session.user) {
|
||||||
req.session.user = null;
|
req.session.user = null;
|
||||||
@ -40,7 +45,7 @@ function LogoutHandler(services: Services): RequestHandler {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
function CreateHandler(services: Services): RequestHandler {
|
function CreateUserHandler(services: Services): RequestHandler {
|
||||||
const createUser = CreateUser(services);
|
const createUser = CreateUser(services);
|
||||||
|
|
||||||
return async (req, res, next) => {
|
return async (req, res, next) => {
|
||||||
@ -53,7 +58,7 @@ function CreateHandler(services: Services): RequestHandler {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
function ReadHandler(services: Services): RequestHandler {
|
function ReadUserHandler(services: Services): RequestHandler {
|
||||||
const readUser = ReadUser(services);
|
const readUser = ReadUser(services);
|
||||||
|
|
||||||
return async (req, res, next) => {
|
return async (req, res, next) => {
|
||||||
@ -66,7 +71,7 @@ function ReadHandler(services: Services): RequestHandler {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
function UpdateHandler(services: Services): RequestHandler {
|
function UpdateUserHandler(services: Services): RequestHandler {
|
||||||
const updateUser = UpdateUser(services);
|
const updateUser = UpdateUser(services);
|
||||||
|
|
||||||
return async (req, res, next) => {
|
return async (req, res, next) => {
|
||||||
@ -83,43 +88,95 @@ function UpdateHandler(services: Services): RequestHandler {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function ListUserHandler(services: Services): RequestHandler {
|
||||||
|
const listUsers = ListUsers(services);
|
||||||
|
|
||||||
|
return async (req, res, next) => {
|
||||||
|
try {
|
||||||
|
const users = await listUsers(getRequestId(req));
|
||||||
|
res.status(200).send(users);
|
||||||
|
} catch (error) {
|
||||||
|
next({ message: 'Unknown Error' });
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
function AddCardToUserHandler(services: Services): RequestHandler {
|
||||||
|
const addCardToUser = AddCardToUser(services);
|
||||||
|
|
||||||
|
return async (req, res, next) => {
|
||||||
|
try {
|
||||||
|
const user = await addCardToUser(
|
||||||
|
getRequestId(req),
|
||||||
|
req.params.uuid,
|
||||||
|
req.body.cardUuid,
|
||||||
|
);
|
||||||
|
res.status(200).send(user);
|
||||||
|
} catch (error) {
|
||||||
|
next({ message: 'Unknown Error' });
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
export function Routes(services: Services) {
|
export function Routes(services: Services) {
|
||||||
const router = Router();
|
const router = Router();
|
||||||
|
|
||||||
|
//User
|
||||||
router.post(
|
router.post(
|
||||||
'/login',
|
'/login',
|
||||||
LoginUserSchema(),
|
LoginUserSchema(),
|
||||||
ValidateSchema(),
|
ValidateSchema(),
|
||||||
LoginHandler(services),
|
LoginUserHandler(services),
|
||||||
);
|
);
|
||||||
router.post(
|
router.post(
|
||||||
'/logout',
|
'/logout',
|
||||||
LogoutUserSchema(),
|
LogoutUserSchema(),
|
||||||
ValidateSchema(),
|
ValidateSchema(),
|
||||||
LogoutHandler(services),
|
LogoutUserHandler(services),
|
||||||
);
|
);
|
||||||
router.get(
|
router.get(
|
||||||
'/read/:uuid',
|
'/read/:uuid',
|
||||||
CheckPermissions(),
|
CheckPermissions(),
|
||||||
ReadUserSchema(),
|
ReadUserSchema(),
|
||||||
ValidateSchema(),
|
ValidateSchema(),
|
||||||
ReadHandler(services),
|
ReadUserHandler(services),
|
||||||
);
|
);
|
||||||
|
|
||||||
router.post(
|
router.post(
|
||||||
'/create',
|
'/create',
|
||||||
CheckPermissions(),
|
CheckPermissions(),
|
||||||
CreateUserSchema(),
|
CreateUserSchema(),
|
||||||
ValidateSchema(),
|
ValidateSchema(),
|
||||||
CreateHandler(services),
|
CreateUserHandler(services),
|
||||||
);
|
);
|
||||||
|
|
||||||
router.patch(
|
router.patch(
|
||||||
'/update/:uuid',
|
'/update/:uuid',
|
||||||
CheckPermissions(),
|
CheckPermissions(),
|
||||||
UpdateUserSchema(),
|
UpdateUserSchema(),
|
||||||
ValidateSchema(),
|
ValidateSchema(),
|
||||||
UpdateHandler(services),
|
UpdateUserHandler(services),
|
||||||
|
);
|
||||||
|
router.get(
|
||||||
|
'/list',
|
||||||
|
CheckPermissions(),
|
||||||
|
ListUsersSchema(),
|
||||||
|
ValidateSchema(),
|
||||||
|
ListUserHandler(services),
|
||||||
|
);
|
||||||
|
|
||||||
|
//Alteration
|
||||||
|
router.post(
|
||||||
|
'/addCard/:uuid',
|
||||||
|
CheckPermissions(),
|
||||||
|
AddCardToUserSchema(),
|
||||||
|
ValidateSchema(),
|
||||||
|
AddCardToUserHandler(services),
|
||||||
|
);
|
||||||
|
router.post(
|
||||||
|
'/removeCard/:uuid',
|
||||||
|
CheckPermissions(),
|
||||||
|
RemoveCardFromUserSchema(),
|
||||||
|
ValidateSchema(),
|
||||||
|
//RemoveCardFromUserHandler(),
|
||||||
);
|
);
|
||||||
|
|
||||||
return router;
|
return router;
|
||||||
|
74
api/src/framework/mongo/card.ts
Normal file
74
api/src/framework/mongo/card.ts
Normal file
@ -0,0 +1,74 @@
|
|||||||
|
import { Collection, Db } from 'mongodb';
|
||||||
|
import { UpdateCardBody } from '@core';
|
||||||
|
import { Card } from '../../entities/card';
|
||||||
|
import { log } from '../../functions/logger';
|
||||||
|
|
||||||
|
class CardModel {
|
||||||
|
private collection: Collection<Card>;
|
||||||
|
|
||||||
|
constructor(db: Db) {
|
||||||
|
this.collection = db.collection<Card>('cards');
|
||||||
|
}
|
||||||
|
|
||||||
|
public async create(tracker: string, cardInfo: Card): Promise<Card> {
|
||||||
|
const checkCard = await this.collection.findOne({
|
||||||
|
uuid: cardInfo.uuid,
|
||||||
|
});
|
||||||
|
if (checkCard) {
|
||||||
|
log(tracker, 'Card Already Exists');
|
||||||
|
throw new Error();
|
||||||
|
}
|
||||||
|
|
||||||
|
await this.collection.insertOne(cardInfo);
|
||||||
|
|
||||||
|
const card = await this.read(tracker, cardInfo.uuid);
|
||||||
|
log(tracker, 'CREATE USER', card);
|
||||||
|
return card;
|
||||||
|
}
|
||||||
|
|
||||||
|
public async read(tracker: string, uuid: string): Promise<Card> {
|
||||||
|
const cardDocument = await this.collection.findOne({ uuid });
|
||||||
|
if (!cardDocument) {
|
||||||
|
log(tracker, 'Card Not Found');
|
||||||
|
throw new Error();
|
||||||
|
}
|
||||||
|
|
||||||
|
const card = new Card(cardDocument);
|
||||||
|
log(tracker, 'READ CARD', card);
|
||||||
|
return card;
|
||||||
|
}
|
||||||
|
|
||||||
|
public async update(
|
||||||
|
tracker: string,
|
||||||
|
uuid: string,
|
||||||
|
cardInfo: UpdateCardBody,
|
||||||
|
): Promise<Card> {
|
||||||
|
const checkCard = await this.collection.findOne({ uuid });
|
||||||
|
if (!checkCard) {
|
||||||
|
log(tracker, 'Card Does Not Exist');
|
||||||
|
throw new Error();
|
||||||
|
}
|
||||||
|
|
||||||
|
await this.collection.updateOne(
|
||||||
|
{ uuid },
|
||||||
|
{
|
||||||
|
$set: {
|
||||||
|
...cardInfo,
|
||||||
|
updatedAt: new Date(),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
|
const card = await this.read(tracker, uuid);
|
||||||
|
log(tracker, 'UPDATE CARD', card);
|
||||||
|
return card;
|
||||||
|
}
|
||||||
|
|
||||||
|
public async list(tracker: string): Promise<Card[]> {
|
||||||
|
const cardCollection = await this.collection.find().toArray();
|
||||||
|
log(tracker, 'LIST CARDS');
|
||||||
|
return cardCollection.map((cardDocument) => new Card(cardDocument));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export default CardModel;
|
@ -1,5 +1,5 @@
|
|||||||
import { Collection, Db } from 'mongodb';
|
import { Collection, Db } from 'mongodb';
|
||||||
import { LoginUserBody, UpdateUserBody } from '@core';
|
import { Card, CardInfo, LoginUserBody, UpdateUserBody, UserInfo } from '@core';
|
||||||
import { User, UserWithPassword } from '../../entities/user';
|
import { User, UserWithPassword } from '../../entities/user';
|
||||||
import { log } from '../../functions/logger';
|
import { log } from '../../functions/logger';
|
||||||
import { getHashedPassword } from '../../functions/password';
|
import { getHashedPassword } from '../../functions/password';
|
||||||
@ -11,9 +11,9 @@ class UserModel {
|
|||||||
this.collection = db.collection<User>('users');
|
this.collection = db.collection<User>('users');
|
||||||
}
|
}
|
||||||
|
|
||||||
public async login(tracker: string, data: LoginUserBody): Promise<User> {
|
public async login(tracker: string, userInfo: LoginUserBody): Promise<User> {
|
||||||
const checkUser = await this.collection.findOne({
|
const checkUser = await this.collection.findOne({
|
||||||
username: data.username,
|
username: userInfo.username,
|
||||||
});
|
});
|
||||||
if (!checkUser) {
|
if (!checkUser) {
|
||||||
log(tracker, 'User Not Found');
|
log(tracker, 'User Not Found');
|
||||||
@ -22,7 +22,7 @@ class UserModel {
|
|||||||
|
|
||||||
const userDocument = await this.collection.findOne({
|
const userDocument = await this.collection.findOne({
|
||||||
uuid: checkUser.uuid,
|
uuid: checkUser.uuid,
|
||||||
password: getHashedPassword(checkUser.uuid, data.password),
|
password: getHashedPassword(checkUser.uuid, userInfo.password),
|
||||||
});
|
});
|
||||||
if (!userDocument) {
|
if (!userDocument) {
|
||||||
log(tracker, 'Wrong Password');
|
log(tracker, 'Wrong Password');
|
||||||
@ -54,7 +54,22 @@ class UserModel {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public async read(tracker: string, uuid: string): Promise<User> {
|
public async read(tracker: string, uuid: string): Promise<User> {
|
||||||
const userDocument = await this.collection.findOne({ uuid });
|
const [userDocument] = await this.collection.aggregate<UserInfo>([
|
||||||
|
{
|
||||||
|
$match:{
|
||||||
|
uuid
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
$lookup: {
|
||||||
|
from: "cards",
|
||||||
|
localField: "cards",
|
||||||
|
foreignField: "_id",
|
||||||
|
as: "cards"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]).toArray();
|
||||||
|
console.log(JSON.stringify(userDocument));
|
||||||
if (!userDocument) {
|
if (!userDocument) {
|
||||||
log(tracker, 'User Not Found');
|
log(tracker, 'User Not Found');
|
||||||
throw new Error();
|
throw new Error();
|
||||||
@ -93,6 +108,40 @@ class UserModel {
|
|||||||
log(tracker, 'UPDATE USER', user);
|
log(tracker, 'UPDATE USER', user);
|
||||||
return user;
|
return user;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public async list(tracker: string): Promise<User[]> {
|
||||||
|
const userCollection = await this.collection.find().toArray();
|
||||||
|
log(tracker, 'LIST USERS');
|
||||||
|
return userCollection.map((userDocument) => new User(userDocument));
|
||||||
|
}
|
||||||
|
|
||||||
|
public async addCard(
|
||||||
|
tracker: string,
|
||||||
|
uuid: string,
|
||||||
|
card: Card,
|
||||||
|
): Promise<User> {
|
||||||
|
const checkUser = await this.collection.findOne({ uuid });
|
||||||
|
if (!checkUser) {
|
||||||
|
log(tracker, 'User Does Not Exist');
|
||||||
|
throw new Error();
|
||||||
|
}
|
||||||
|
|
||||||
|
await this.collection.updateOne(
|
||||||
|
{ uuid },
|
||||||
|
{
|
||||||
|
$set: {
|
||||||
|
updatedAt: new Date(),
|
||||||
|
},
|
||||||
|
$addToSet: {
|
||||||
|
cards: card._id,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
|
const user = await this.read(tracker, uuid);
|
||||||
|
log(tracker, 'ADD CARD TO USER', user, card);
|
||||||
|
return user;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export default UserModel;
|
export default UserModel;
|
||||||
|
36
api/src/functions/card.ts
Normal file
36
api/src/functions/card.ts
Normal file
@ -0,0 +1,36 @@
|
|||||||
|
import { CardInfo, CreateCardBody } from '@core';
|
||||||
|
import { Card } from '../entities/card';
|
||||||
|
import { Services } from '../app';
|
||||||
|
|
||||||
|
export function CreateCard(
|
||||||
|
services: Services,
|
||||||
|
): (tracker: string, raw: CreateCardBody) => Promise<CardInfo> {
|
||||||
|
const { cardModel } = services;
|
||||||
|
|
||||||
|
return async (tracker, raw) => {
|
||||||
|
const card = await cardModel.create(tracker, new Card(raw));
|
||||||
|
return card.Info();
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
export function ReadCard(
|
||||||
|
services: Services,
|
||||||
|
): (tracker: string, uuid: string) => Promise<CardInfo> {
|
||||||
|
const { cardModel } = services;
|
||||||
|
|
||||||
|
return async (tracker, uuid) => {
|
||||||
|
const card = await cardModel.read(tracker, uuid);
|
||||||
|
return card.Info();
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
export function ListCards(
|
||||||
|
services: Services,
|
||||||
|
): (tracker: string) => Promise<CardInfo[]> {
|
||||||
|
const { cardModel } = services;
|
||||||
|
|
||||||
|
return async (tracker) => {
|
||||||
|
const cards = await cardModel.list(tracker);
|
||||||
|
return cards.map((card) => card.Info());
|
||||||
|
};
|
||||||
|
}
|
@ -45,3 +45,27 @@ export function UpdateUser(
|
|||||||
return user.Info();
|
return user.Info();
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function ListUsers(
|
||||||
|
services: Services,
|
||||||
|
): (tracker: string) => Promise<UserInfo[]> {
|
||||||
|
const { userModel } = services;
|
||||||
|
|
||||||
|
return async (tracker) => {
|
||||||
|
const users = await userModel.list(tracker);
|
||||||
|
return users.map((user) => user.Info());
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
export function AddCardToUser(
|
||||||
|
services: Services,
|
||||||
|
): (tracker: string, uuid: string, cardUuid: string) => Promise<UserInfo> {
|
||||||
|
const { userModel, cardModel } = services;
|
||||||
|
|
||||||
|
return async (tracker, uuid, cardUuid) => {
|
||||||
|
const card = await cardModel.read(tracker, cardUuid);
|
||||||
|
|
||||||
|
const user = await userModel.addCard(tracker, uuid, card);
|
||||||
|
return user.Info();
|
||||||
|
};
|
||||||
|
}
|
||||||
|
2568
core/package-lock.json
generated
2568
core/package-lock.json
generated
File diff suppressed because it is too large
Load Diff
@ -11,6 +11,7 @@
|
|||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@types/node": "^18.8.4",
|
"@types/node": "^18.8.4",
|
||||||
"prettier": "^2.7.1",
|
"prettier": "^2.7.1",
|
||||||
|
"mongodb": "^4.10.0",
|
||||||
"typescript": "^4.8.3"
|
"typescript": "^4.8.3"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
12
core/src/alteration.ts
Normal file
12
core/src/alteration.ts
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
import { EntityInfo } from './entity';
|
||||||
|
import { CardInfo } from './card';
|
||||||
|
|
||||||
|
export type AlerationInfo = {
|
||||||
|
card: CardInfo;
|
||||||
|
level: number;
|
||||||
|
xp: number;
|
||||||
|
};
|
||||||
|
|
||||||
|
export type Ateration = AlerationInfo & EntityInfo;
|
||||||
|
|
||||||
|
export type AlerationCtor = Partial<Ateration>;
|
40
core/src/card.ts
Normal file
40
core/src/card.ts
Normal file
@ -0,0 +1,40 @@
|
|||||||
|
import { EntityInfo } from './entity';
|
||||||
|
|
||||||
|
export enum CardRarity {
|
||||||
|
COMMON = 'COMMON',
|
||||||
|
RARE = 'RARE',
|
||||||
|
EPIC = 'EPIC',
|
||||||
|
LEGENDARY = 'LEGENDARY',
|
||||||
|
}
|
||||||
|
|
||||||
|
export type CombatStats = {
|
||||||
|
baseAtk: number;
|
||||||
|
baseDef: number;
|
||||||
|
baseCrit: number;
|
||||||
|
multAtk: number;
|
||||||
|
multDef: number;
|
||||||
|
multCrit: number;
|
||||||
|
};
|
||||||
|
|
||||||
|
export type CardInfo = {
|
||||||
|
uuid: string;
|
||||||
|
name: string;
|
||||||
|
rarity: keyof typeof CardRarity;
|
||||||
|
stats: CombatStats;
|
||||||
|
thumbnail: string;
|
||||||
|
model: string;
|
||||||
|
};
|
||||||
|
|
||||||
|
export type CreateCardBody = {
|
||||||
|
name: string;
|
||||||
|
rarity: keyof typeof CardRarity;
|
||||||
|
stats: CombatStats;
|
||||||
|
thumbnail: string;
|
||||||
|
model: string;
|
||||||
|
};
|
||||||
|
|
||||||
|
export type Card = CardInfo & EntityInfo;
|
||||||
|
|
||||||
|
export type CardCtor = Partial<Card>;
|
||||||
|
|
||||||
|
export type UpdateCardBody = Partial<Omit<CardInfo, 'uuid'>>;
|
@ -1,4 +1,7 @@
|
|||||||
|
import { ObjectId } from 'mongodb';
|
||||||
|
|
||||||
export type EntityInfo = {
|
export type EntityInfo = {
|
||||||
|
_id: ObjectId;
|
||||||
uuid: string;
|
uuid: string;
|
||||||
createdAt: Date;
|
createdAt: Date;
|
||||||
updatedAt: Date;
|
updatedAt: Date;
|
||||||
|
@ -1,2 +1,4 @@
|
|||||||
|
export * from './alteration';
|
||||||
|
export * from './card';
|
||||||
export * from './user';
|
export * from './user';
|
||||||
export * from './entity';
|
export * from './entity';
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
import { EntityInfo } from './entity';
|
import { EntityInfo } from './entity';
|
||||||
|
import { CardInfo } from './card';
|
||||||
|
|
||||||
export enum UserRoles {
|
export enum UserRoles {
|
||||||
ADMIN = 'ADMIN',
|
ADMIN = 'ADMIN',
|
||||||
@ -9,6 +10,7 @@ export type UserInfo = {
|
|||||||
uuid: string;
|
uuid: string;
|
||||||
username: string;
|
username: string;
|
||||||
role: keyof typeof UserRoles;
|
role: keyof typeof UserRoles;
|
||||||
|
cards: CardInfo[];
|
||||||
};
|
};
|
||||||
|
|
||||||
export type User = UserInfo & EntityInfo;
|
export type User = UserInfo & EntityInfo;
|
||||||
|
Loading…
x
Reference in New Issue
Block a user