import { Inject, Injectable } from "../../Injector/ServiceDecorator"; import { RaidManagerIfc, RaidManagerFeatureIfc } from "./RPCInterface"; import { FrontworkComponent } from "../../Types/FrontworkComponent"; import { TableDefiniton, Signup, Raid, Character, RaidData, Spec, SRToken, Item, User } from "../../Types/Types"; import { IAdmin } from "../../Admin/Interface"; import { IRaidManager } from "./Interface"; import { IUserManager } from "../User/Interface"; import { ICharacterManager } from "../Character/Interface"; import { _Tiers } from "../../Types/Items"; @Injectable(IRaidManager) export class RaidManager implements FrontworkComponent, IRaidManager{ name = "RaidManager" as "RaidManager"; @Inject(IAdmin) private admin: IAdmin @Inject(IUserManager) private userManager: IUserManager @Inject(ICharacterManager) private characterManager: ICharacterManager exportRPCs = () => [ this.getRaids, this.getRaidData, this.getPastRaids, this.getArchiveRaid ] exportRPCFeatures() { return [{ name: 'manageRaid' as 'manageRaid', exportRPCs: () => [ this.createRaid, this.addSignup, this.removeSignup, this.archiveRaid, this.setBenched, this.startRaid ] },{ name: 'signup' as 'signup', exportRPCs: () => [ this.getSignups, this.sign, this.unsign ] }] } getTableDefinitions(): TableDefiniton[] { return [ { name: 'raids', tableBuilder: (table) => { table.increments('id').primary() table.dateTime('start').notNullable() table.string('description').notNullable() table.string('title').notNullable() table.integer('size').defaultTo(40) table.enu('tier', _Tiers).defaultTo(null as any) } },{ name: 'archive', tableBuilder: (table) => { table.integer('id').primary() table.json('raiddata').notNullable() } },{ name: 'signups', tableBuilder: (table) => { table.increments('id').primary() table.unique(['raidid', 'characterid']) table.integer('raidid') table.foreign('raidid').references('id').inTable('raids').onDelete('CASCADE') table.integer('characterid') table.foreign('characterid').references('id').inTable('characters').onDelete('CASCADE') table.boolean('benched').defaultTo('false') table.boolean('late') } } ] } createRaid = async (raid:Raid) => await this.admin .knex('raids') .insert(raid) addSignup = async (signup: Signup) => await this.admin .knex('signups') .insert(signup) removeSignup = async (signup: Signup) => await this.admin .knex('signups') .where({ raid_id: signup.raidid, character_id: signup.characterid }) .del() getRaids = async () : Promise => { const subQuery = this.admin .knex('signups') .count('*') .where({ raidid: this.admin.knex.ref('raids.id'), benched: false, late: false }) .as('signupcount') return await this.admin.knex('raids') .select('*', subQuery) .orderBy('start', 'asc') } startRaid = async (raid:Raid) : Promise => { const archived = await this.archiveRaid(raid) delete archived.participants.late const giveCurrency = async (b: Character) => { const usr = await this.characterManager.getUserOfCharacter(b) await this.userManager.incrementCurrency(usr, 1) } await Promise.all([ ...archived.participants.bench.map(giveCurrency), ...Object.values(archived.participants).map((group: any) => group.map(giveCurrency)) ]) return archived } archiveRaid = async (raid:Raid) : Promise => { const raidData = await this.getRaidData(raid) await this.admin.knex('archive') .insert({ id:raidData.id, raiddata: JSON.stringify(raidData) }) await Promise.all( Object.values(raidData.participants).flat().flatMap((signup) => this.admin .knex('tokens') .where({ characterid: signup.characterid, signupid: null }) .del() )) await this.admin.knex('raids') .where('id', '=', raid.id) .del() const row = await this.admin.knex('archive') .select('*') .where({ id:raidData.id, }) .first() return JSON.parse(row.raiddata) } getArchiveRaid = async(id:number) : Promise => { const data = await this.admin.knex('archive').select('raiddata').where({ id: id }).first() return JSON.parse(data.raiddata) } getPastRaids = async(limit: number) : Promise => { const raids = await this.admin.knex('archive') .select('*') .orderBy('id', 'desc') .limit(limit) return raids.map(raid => JSON.parse(raid.raiddata)) } getRaidData = async (raid:Raid) : Promise => { const ret = { participants:{ Druid: <(Signup&Character&Spec)[]>[], Hunter: <(Signup&Character&Spec)[]>[], Mage: <(Signup&Character&Spec)[]>[], Paladin: <(Signup&Character&Spec)[]>[], Priest: <(Signup&Character&Spec)[]>[], Rogue: <(Signup&Character&Spec)[]>[], Shaman: <(Signup&Character&Spec)[]>[], Warlock: <(Signup&Character&Spec)[]>[], Warrior: <(Signup&Character&Spec)[]>[], late: <(Signup&Character&Spec)[]>[], bench: <(Signup&Character&Spec)[]>[], }, tokens:{} } const subQuery = this.admin .knex('signups') .count('*') .where({ raidid: this.admin.knex.ref('raids.id'), benched: false, late: false }) .as('signupcount') const raidInDb: Raid = await this.admin.knex('raids') .select('*', subQuery) .where('id','=',raid.id) .first() const characterData: (Signup & Character & Spec)[] = await this.admin .knex('signups as s') .select('s.id as id', 'charactername', 'class', 'specname', 'race', 'userid', 'benched', 'late', 'raidid', 'characterid') .join('raids as r', 's.raidid','=','r.id') .join('characters as c', 's.characterid','=','c.id') .join('users as u', 'c.userid','=','u.id') .join('specs as sp', 'specid','=','sp.id') .where('r.id','=',raid.id) characterData.forEach(data => { if(data.benched){ ret.participants.bench.push(data) return } if(data.late){ ret.participants.late.push(data) return } ret.participants[data.class].push(data) }) const tokenData: (Character & SRToken & Item)[] = await this.admin .knex('signups as s') .select('*', 's.id as id') .join('raids as r', 's.raidid','=','r.id') .where('r.id','=',raid.id) .andWhere(function(){ this.whereNotNull('t.signupid') }) .join('characters as c', 's.characterid','=','c.id') .join('tokens as t', 't.characterid','=','c.id') .join('items as i', 'i.itemname','=','t.itemname') tokenData.forEach(data => { if(!ret.tokens[data.itemname]) ret.tokens[data.itemname] = [] ret.tokens[data.itemname].push(data) }) return { ...raidInDb, ...ret } } getSignups = async (raid:Raid) : Promise<(Signup & Character & Spec & User)[]> => await this.admin .knex('signups as si') .join('characters as c', 'c.id', '=', 'characterid') .join('specs as s', 's.id', '=', 'specid') .join('users as u', 'u.id', '=', 'userid') .select('*','si.id as id') .where('raidid', '=', raid.id!) sign = async (usertoken:string, character:Character, raid:Raid, late:boolean) => { const maybeUserRecord = this.userManager.getUserRecordByToken(usertoken) if(!maybeUserRecord || maybeUserRecord.user.id != character.userid){ throw new Error("Bad Usertoken") } const exists = await this.admin .knex('signups') .select('*') .where({ raidid: raid.id!, characterid: character.id!, }) .first() if(!exists){ await this.admin .knex('signups') .insert({ raidid: raid.id!, characterid: character.id!, late: late }) }else{ await this.admin .knex('signups') .update({ raidid: raid.id!, characterid: character.id!, late: late }) } return await this.admin .knex('signups') .select('*') .where({ raidid: raid.id!, characterid: character.id!, }) .first() } unsign = async (usertoken:string, character:Character, raid:Raid) => { const maybeUserRecord = this.userManager.getUserRecordByToken(usertoken) if(!maybeUserRecord || maybeUserRecord.user.id != character.userid){ throw new Error("Bad Usertoken") } await this.admin.knex('signups') .where({ raidid: raid.id!, characterid: character.id!, }) .del() } setBenched = async (signup: Signup) : Promise => { await this.admin.knex('signups') .where({ raidid: signup.raidid, characterid: signup.characterid }) .update(signup) } }