| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508 |
- 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";
- import { MAX_MEMO_LENGTH } from "../../Types/Constants";
- import { IItemManager } from "../Item/Interface";
- import { ItemManager } from "../Item/ItemManager";
- import { IPubSub } from "../PubSub/Interface";
- import { getLogger } from "log4js";
-
- @Injectable(IRaidManager)
- export class RaidManager
- implements FrontworkComponent<RaidManagerIfc, RaidManagerFeatureIfc>, IRaidManager {
- name = "RaidManager" as "RaidManager";
-
- @Inject(IAdmin)
- private admin: IAdmin
-
- @Inject(IUserManager)
- private userManager: IUserManager
-
- @Inject(ICharacterManager)
- private characterManager: ICharacterManager
-
- @Inject(ItemManager)
- private itemManager: IItemManager
-
- @Inject(IPubSub)
- private pubsub: IPubSub<any>
-
- RPCs = () => [
- this.getRaids,
- this.getRaidData,
- this.getPastRaids,
- this.getArchiveRaid
- ]
-
- RPCFeatures() {
- return [{
- name: 'manageRaid' as 'manageRaid',
- RPCs: () => [
- this.createRaid,
- this.addSignup,
- this.removeSignup,
- this.archiveRaid,
- this.updateSignup,
- this.startRaid,
- this.adminUnsign,
- this.cancelRaid
- ]
- }, {
- name: 'signup' as 'signup',
- RPCs: () => [
- 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.string('tier').defaultTo('null')
- }
- }, {
- 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')
- table.timestamp('timestamp').defaultTo(this.admin.knex.fn.now())
- table.string('memo').nullable()
- }
- }
- ]
- }
-
- notifyRaid = async (raid: Raid | { id: number }) => {
- const data = await this.getRaidData(<Raid>raid)
- try {
- await this.pubsub.publish(String(raid.id), data)
- await this.notifyRaids()
- } catch (e) {
- getLogger('RaidManager#notifyRaid').debug(e);
- }
- }
-
- notifyRaids = async () => {
- try {
- await this.pubsub.publish('raids', undefined)
- } catch (e) {
- getLogger('RaidManager#notifyRaids').debug(e);
- }
- }
-
- createRaid = async (raid: Raid): Promise<Raid> => {
- const ids: number[] = await this.admin
- .knex('raids')
- .insert(raid)
-
- await this.notifyRaid({ id: ids[0] })
-
- return await this.admin.knex('raids').where({ id: ids[0] }).first()
- }
-
- addSignup = async (signup: Signup) => {
-
- const ids: number[] = await this.admin
- .knex('signups')
- .insert(signup)
- return await this.admin.knex('signups').where({ id: ids[0] }).first()
-
- }
-
- removeSignup = async (signup: Signup) => await this.admin
- .knex('signups')
- .where({
- raid_id: signup.raidid,
- character_id: signup.characterid
- })
- .del()
-
- getRaids = async (): Promise<Raid[]> => {
-
- const countSignups = this.admin
- .knex('signups')
- .count('*')
- .where({
- raidid: this.admin.knex.ref('raids.id'),
- benched: false,
- late: false
- })
- .as('signupcount')
-
- const countBenches = this.admin
- .knex('signups')
- .count('*')
- .where({
- raidid: this.admin.knex.ref('raids.id'),
- benched: true,
- late: false
- })
- .as('benchcount')
-
- return await this.admin.knex('raids')
- .select('*', countSignups, countBenches)
- .orderBy('start', 'asc')
- }
-
- startRaid = async (raid: Raid): Promise<RaidData> => {
- const data = await this.getRaidData(raid)
- data.participants.absent.map(p => this.itemManager.decayTokensOfCharacter(raid.tier, p, 1))
- await this.itemManager.decayTokens(data.tier)
- const archived = await this.archiveRaid(raid)
-
- const giveCurrency = async (b: Character) => {
- const usr = await this.characterManager.getUserOfCharacter(b)
- await this.userManager.incrementCurrency(usr, raid.tier, 1)
- }
-
- await Promise.all([
- ...archived.participants.bench.map(giveCurrency),
- ...Object.values(archived.participants).flat().map((b: Signup & Character & Spec) => giveCurrency(b))
- ])
-
- await this.notifyRaids()
- return archived
- }
-
- archiveRaid = async (raid: Raid): Promise<RaidData> => {
- const raidData = await this.getRaidData(raid)
- const tx = await this.admin.knex.transaction()
-
- await this.admin.knex('archive')
- .transacting(tx)
- .insert({
- id: raidData.id,
- raiddata: JSON.stringify(raidData)
- })
-
- await Promise.all(
- Object.values(raidData.participants).flat().flatMap((p: (Signup & Character & Spec)) =>
- this.admin
- .knex(raid.tier + 'tokens')
- .transacting(tx)
- .where({
- characterid: p.characterid,
- signupid: null
- })
- .del()
- ))
-
- await this.admin.knex('raids')
- .transacting(tx)
- .where('id', '=', raid.id)
- .del()
- await tx.commit()
-
-
- const row = await this.admin.knex('archive')
- .select('*')
- .where({
- id: raidData.id,
- })
- .first()
-
- try {
- return JSON.parse(row.raiddata)
- } catch (e) {
- getLogger('RaidManager#archiveRaid').error(row.id + " could not get parsed")
- return {} as RaidData
- }
- }
-
- getArchiveRaid = async (id: number): Promise<RaidData> => {
- const data = await this.admin
- .knex('archive')
- .select('raiddata')
- .where({
- id: id
- })
- .first()
-
- try {
- return JSON.parse(data.raiddata)
- } catch (e) {
- getLogger('RaidManager#getArchiveRaid').error(id + " could not get parsed")
- return {} as RaidData
- }
- }
-
- getPastRaids = async (limit: number): Promise<RaidData[]> => {
- 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<RaidData> => {
- const raiddata = {
- 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)[]>[],
- absent: <(Signup & Character & Spec)[]>[]
- },
- tokens: {},
- healers: <(Signup & Character & Spec)[]>[],
- tanks: <(Signup & Character & Spec)[]>[]
- }
-
- const subQuery = this.admin
- .knex('signups')
- .count('*')
- .where({
- raidid: this.admin.knex.ref('raids.id'),
- benched: false,
- late: false,
- absent: 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', 'rank', 'class', 'specid', 'specname', 'race', 'userid', 'benched', 'late', 'raidid', 'characterid', 'specid', 'memo', 'timestamp', 'absent')
- .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.absent){
- raiddata.participants.absent.push(data)
- return
- }
- if (data.benched) {
- raiddata.participants.bench.push(data)
- return
- }
- if (data.late) {
- raiddata.participants.late.push(data)
- return
- }
- raiddata.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')
- .join('characters as c', 's.characterid', '=', 'c.id')
- .join('users as u', 'u.id', '=', 'c.userid')
- .join(raidInDb.tier + 'tokens as t', 't.characterid', '=', 'c.id')
- .join('items as i', 'i.itemname', '=', 't.itemname')
- .where({
- 'r.id': raid.id,
- })
- .andWhere(function () {
- //this.whereNotIn('u.rank', ['Trial', 'Guest'])
- this.whereNotNull('t.signupid')
- })
-
- tokenData.forEach(data => {
- if (!raiddata.tokens[data.itemname])
- raiddata.tokens[data.itemname] = []
- raiddata.tokens[data.itemname].push(data)
- })
-
- raiddata.tanks = Object.values(raiddata.participants).flatMap(
- (tanks: any[]) => tanks.filter((p: any) =>
- !p.benched
- && !p.absent
- && !p.late
- && (p.specname === "Protection"
- || p.specname === "Feral (Tank)"))
- )
- raiddata.healers = Object.values(raiddata.participants).flatMap(
- (healers: any[]) => healers.filter((p: any) =>
- !p.benched
- && !p.absent
- && !p.late
- && (p.specname === "Holy"
- || p.specname === "Discipline"
- || p.specname === "Restoration"))
- )
-
- return {
- ...raidInDb,
- ...raiddata
- }
- }
-
- 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, absent:boolean, memo?: string) => {
- const maybeUserRecord = this.userManager.getUserRecordByToken(usertoken)
- if (!maybeUserRecord || maybeUserRecord.user.id != character.userid) {
- throw new Error("Bad Usertoken")
- }
-
- if (memo) memo = memo.substring(0, MAX_MEMO_LENGTH)
- 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,
- absent: absent,
- benched: false,
- memo: memo
- })
- } else {
- await this.admin
- .knex('signups')
- .where({
- id: exists.id
- })
- .update({
- raidid: raid.id!,
- characterid: character.id!,
- late: late,
- absent: absent,
- benched: false,
- memo: memo
- })
- }
-
- await this.notifyRaid(raid)
-
- return await this.admin
- .knex('signups')
- .select('*')
- .where({
- raidid: raid.id!,
- characterid: character.id!,
- })
- .first()
- }
-
- cancelRaid = async (raid: Raid) => {
- const data = await this.getRaidData(raid)
- const participants = Object.values(data.participants).flat()
- await Promise.all(
- participants.map(async p => await this.adminUnsign({...p, id: p.characterid}, raid))
- )
- await this.admin.knex('raids').where({id: raid.id}).del()
- await this.notifyRaids()
- }
-
- 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")
- }
-
- return await this.adminUnsign(character, raid)
- }
-
- adminUnsign = async (character: Character, raid: Raid) => {
- const user = await this.characterManager.getUserOfCharacter(character)
- const tokens = await this.itemManager.getTokens(character, [raid.tier], true)
-
- //check if token has to be deleted
- if (tokens) {
- await Promise.all(
- tokens.map(async token => {
- await this.userManager.incrementCurrency(user, raid.tier, 1)
- const prio = await this.itemManager.calculatePriorities(token.itemname, character)
- if (token.level <= prio + 2) {
- await this.admin
- .knex(raid.tier + 'tokens')
- .where({
- characterid: character.id,
- itemname: token.itemname
- }).del()
- } else {
- await this.admin
- .knex(raid.tier + 'tokens')
- .where({
- characterid: character.id,
- itemname: token.itemname
- }).update({
- signupid: null,
- level: token.level - 2
- })
- }
- })
- )
- }
-
- await this.admin.knex('signups')
- .where({
- raidid: raid.id!,
- characterid: character.id!,
- })
- .del()
-
- await this.notifyRaid(raid)
- }
-
- updateSignup = async (signup: Signup): Promise<void> => {
- await this.admin.knex('signups')
- .where({
- raidid: signup.raidid,
- characterid: signup.characterid
- })
- .update(signup)
-
- await this.notifyRaid({ id: signup.raidid })
- }
- }
|