1
0
forked from noxious/server

Converted more procedural programming to OOP

This commit is contained in:
2024-12-26 23:34:25 +01:00
parent b7f448cb17
commit e571cf2230
46 changed files with 449 additions and 382 deletions

View File

@ -0,0 +1,122 @@
import { Request, Response } from 'express'
import fs from 'fs'
import { BaseController } from '#application/base/baseController'
import { httpLogger } from '#application/logger'
import { getPublicPath } from '#application/storage'
import TileRepository from '#repositories/tileRepository'
import ZoneRepository from '#repositories/zoneRepository'
import SpriteRepository from '#repositories/spriteRepository'
import { AssetData } from '#application/types'
import { FilterValue } from '@mikro-orm/core'
export class AssetsController extends BaseController {
/**
* List tiles
* @param req
* @param res
*/
public async listTiles(req: Request, res: Response) {
const assets: AssetData[] = []
const tiles = await TileRepository.getAll()
for (const tile of tiles) {
assets.push({
key: tile.id,
data: '/assets/tiles/' + tile.getId() + '.png',
group: 'tiles',
updatedAt: tile.getUpdatedAt()
} as AssetData)
}
return this.sendSuccess(res, assets)
}
/**
* List tiles by zone
* @param req
* @param res
*/
public async listTilesByZone(req: Request, res: Response) {
const zoneId = parseInt(req.params.zoneId)
if (!zoneId || zoneId === 0) {
return this.sendError(res, 'Invalid zone ID', 400)
}
const zone = await ZoneRepository.getById(zoneId)
if (!zone) {
return this.sendError(res, 'Zone not found', 404)
}
const assets: AssetData[] = []
const tiles = await TileRepository.getByZoneId(zoneId)
for (const tile of tiles) {
assets.push({
key: tile.getId(),
data: '/assets/tiles/' + tile.getId() + '.png',
group: 'tiles',
updatedAt: tile.getUpdatedAt()
} as AssetData)
}
return this.sendSuccess(res, assets)
}
/**
* List sprite actions
* @param req
* @param res
*/
public async listSpriteActions(req: Request, res: Response) {
const spriteId = req.params.spriteId as FilterValue<`${string}-${string}-${string}-${string}-${string}`>
if (!spriteId) {
return this.sendError(res, 'Invalid sprite ID', 400)
}
const sprite = await SpriteRepository.getById(spriteId)
if (!sprite) {
return this.sendError(res, 'Sprite not found', 404)
}
const assets: AssetData[] = sprite.spriteActions.getItems().map((spriteAction) => ({
key: sprite.id + '-' + spriteAction.action,
data: '/assets/sprites/' + sprite.id + '/' + spriteAction.action + '.png',
group: spriteAction.isAnimated ? 'sprite_animations' : 'sprites',
updatedAt: sprite.updatedAt,
originX: Number(spriteAction.originX.toString()),
originY: Number(spriteAction.originY.toString()),
isAnimated: spriteAction.isAnimated,
frameCount: JSON.parse(JSON.stringify(spriteAction.sprites)).length,
frameWidth: spriteAction.frameWidth,
frameHeight: spriteAction.frameHeight,
frameRate: spriteAction.frameRate
}))
return this.sendSuccess(res, assets)
}
/**
* Download asset
* @param req
* @param res
*/
public async downloadAsset(req: Request, res: Response) {
const { type, spriteId, file } = req.params
const assetPath = type === 'sprites' && spriteId ? getPublicPath(type, spriteId, file) : getPublicPath(type, file)
if (!fs.existsSync(assetPath)) {
httpLogger.error(`File not found: ${assetPath}`)
return this.sendError(res, 'Asset not found', 404)
}
res.sendFile(assetPath, (err) => {
if (err) {
httpLogger.error('Error sending file:', err)
this.sendError(res, 'Error downloading the asset', 500)
}
})
}
}

View File

@ -0,0 +1,104 @@
import jwt from 'jsonwebtoken'
import { Request, Response } from 'express'
import { BaseController } from '#application/base/baseController'
import UserService from '#services/userService'
import config from '#application/config'
import { loginAccountSchema, registerAccountSchema, resetPasswordSchema, newPasswordSchema } from '#application/zodTypes'
export class AuthController extends BaseController {
private userService: UserService
constructor() {
super()
this.userService = new UserService()
}
/**
* Login user
* @param req
* @param res
*/
public async login(req: Request, res: Response) {
const { username, password } = req.body
try {
loginAccountSchema.parse({ username, password })
const user = await this.userService.login(username, password)
if (user && typeof user !== 'boolean') {
const token = jwt.sign({ id: user.getId() }, config.JWT_SECRET, { expiresIn: '4h' })
return this.sendSuccess(res, { token })
}
return this.sendError(res, 'Invalid credentials')
} catch (error: any) {
return this.sendError(res, error.errors?.[0]?.message || 'Validation error')
}
}
/**
* Register user
* @param req
* @param res
*/
public async register(req: Request, res: Response) {
const { username, email, password } = req.body
try {
registerAccountSchema.parse({ username, email, password })
const user = await this.userService.register(username, email, password)
if (user) {
return this.sendSuccess(res, null, 'User registered successfully')
}
return this.sendError(res, 'Failed to register user')
} catch (error: any) {
return this.sendError(res, error.errors?.[0]?.message || 'Validation error')
}
}
/**
* Request password reset
* @param req
* @param res
*/
public async requestPasswordReset(req: Request, res: Response) {
const { email } = req.body
try {
resetPasswordSchema.parse({ email })
const sentEmail = await this.userService.requestPasswordReset(email)
if (sentEmail) {
return this.sendSuccess(res, null, 'Password reset email sent')
}
return this.sendError(res, 'Failed to send password reset request')
} catch (error: any) {
return this.sendError(res, error.errors?.[0]?.message || 'Validation error')
}
}
/**
* Reset password
* @param req
* @param res
*/
public async resetPassword(req: Request, res: Response) {
const { urlToken, password } = req.body
try {
newPasswordSchema.parse({ urlToken, password })
const resetPassword = await this.userService.resetPassword(urlToken, password)
if (resetPassword) {
return this.sendSuccess(res, null, 'Password has been reset')
}
return this.sendError(res, 'Failed to reset password')
} catch (error: any) {
return this.sendError(res, error.errors?.[0]?.message || 'Validation error')
}
}
}

View File

@ -0,0 +1,85 @@
import { Request, Response } from 'express'
import sharp from 'sharp'
import fs from 'fs'
import { BaseController } from '#application/base/baseController'
import CharacterRepository from '#repositories/characterRepository'
import CharacterHairRepository from '#repositories/characterHairRepository'
import CharacterTypeRepository from '#repositories/characterTypeRepository'
import { getPublicPath } from '#application/storage'
interface AvatarOptions {
characterTypeId: number
characterHairId?: number
}
export class AvatarController extends BaseController {
/**
* Get avatar by character
* @param req
* @param res
*/
public async getByName(req: Request, res: Response) {
const character = await CharacterRepository.getByName(req.params.characterName)
if (!character?.characterType) {
return this.sendError(res, 'Character or character type not found', 404)
}
return this.generateAvatar(res, {
characterTypeId: character.characterType.id,
characterHairId: character.characterHair?.id
})
}
/**
* Get avatar by character type and hair
* @param req
* @param res
*/
public async getByParams(req: Request, res: Response) {
return this.generateAvatar(res, {
characterTypeId: parseInt(req.params.characterTypeId),
characterHairId: req.params.characterHairId ? parseInt(req.params.characterHairId) : undefined
})
}
/**
* Generate avatar
* @param res
* @param options
* @private
*/
private async generateAvatar(res: Response, options: AvatarOptions) {
try {
const characterType = await CharacterTypeRepository.getById(options.characterTypeId)
if (!characterType?.sprite?.id) {
return this.sendError(res, 'Character type not found', 404)
}
const bodySpritePath = getPublicPath('sprites', characterType.sprite.id, 'idle_right_down.png')
if (!fs.existsSync(bodySpritePath)) {
return this.sendError(res, 'Body sprite file not found', 404)
}
let avatar = sharp(bodySpritePath).extend({
top: 2,
bottom: 2,
background: { r: 0, g: 0, b: 0, alpha: 0 }
})
if (options.characterHairId) {
const characterHair = await CharacterHairRepository.getById(options.characterHairId)
if (characterHair?.sprite?.id) {
const hairSpritePath = getPublicPath('sprites', characterHair.sprite.id, 'front.png')
if (fs.existsSync(hairSpritePath)) {
avatar = avatar.composite([{ input: hairSpritePath, gravity: 'north' }])
}
}
}
res.setHeader('Content-Type', 'image/png')
return avatar.pipe(res)
} catch (error) {
return this.sendError(res, 'Error generating avatar', 500)
}
}
}