You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

RaidManager.ts 10KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336
  1. import { Inject, Injectable } from "../../Injector/ServiceDecorator";
  2. import { RaidManagerIfc, RaidManagerFeatureIfc } from "./RPCInterface";
  3. import { FrontworkComponent } from "../../Types/FrontworkComponent";
  4. import { TableDefiniton, Signup, Raid, Character, RaidData, Spec, SRToken, Item, User } from "../../Types/Types";
  5. import { IAdmin } from "../../Admin/Interface";
  6. import { IRaidManager } from "./Interface";
  7. import { IUserManager } from "../User/Interface";
  8. import { ICharacterManager } from "../Character/Interface";
  9. import { _Tiers } from "../../Types/Items";
  10. @Injectable(IRaidManager)
  11. export class RaidManager
  12. implements FrontworkComponent<RaidManagerIfc, RaidManagerFeatureIfc>, IRaidManager{
  13. name = "RaidManager" as "RaidManager";
  14. @Inject(IAdmin)
  15. private admin: IAdmin
  16. @Inject(IUserManager)
  17. private userManager: IUserManager
  18. @Inject(ICharacterManager)
  19. private characterManager: ICharacterManager
  20. exportRPCs = () => [
  21. this.getRaids,
  22. this.getRaidData,
  23. this.getPastRaids,
  24. this.getArchiveRaid
  25. ]
  26. exportRPCFeatures() {
  27. return [{
  28. name: 'manageRaid' as 'manageRaid',
  29. exportRPCs: () => [
  30. this.createRaid,
  31. this.addSignup,
  32. this.removeSignup,
  33. this.archiveRaid,
  34. this.setBenched,
  35. this.startRaid
  36. ]
  37. },{
  38. name: 'signup' as 'signup',
  39. exportRPCs: () => [
  40. this.getSignups,
  41. this.sign,
  42. this.unsign
  43. ]
  44. }]
  45. }
  46. getTableDefinitions(): TableDefiniton[] {
  47. return [
  48. {
  49. name: 'raids',
  50. tableBuilder: (table) => {
  51. table.increments('id').primary()
  52. table.dateTime('start').notNullable()
  53. table.string('description').notNullable()
  54. table.string('title').notNullable()
  55. table.integer('size').defaultTo(40)
  56. table.enu('tier', _Tiers).defaultTo(null as any)
  57. }
  58. },{
  59. name: 'archive',
  60. tableBuilder: (table) => {
  61. table.integer('id').primary()
  62. table.json('raiddata').notNullable()
  63. }
  64. },{
  65. name: 'signups',
  66. tableBuilder: (table) => {
  67. table.increments('id').primary()
  68. table.unique(['raidid', 'characterid'])
  69. table.integer('raidid')
  70. table.foreign('raidid').references('id').inTable('raids').onDelete('CASCADE')
  71. table.integer('characterid')
  72. table.foreign('characterid').references('id').inTable('characters').onDelete('CASCADE')
  73. table.boolean('benched').defaultTo('false')
  74. table.boolean('late')
  75. }
  76. }
  77. ]
  78. }
  79. createRaid = async (raid:Raid) => await this.admin
  80. .knex('raids')
  81. .insert(raid)
  82. addSignup = async (signup: Signup) => await this.admin
  83. .knex('signups')
  84. .insert(signup)
  85. removeSignup = async (signup: Signup) => await this.admin
  86. .knex('signups')
  87. .where({
  88. raid_id: signup.raidid,
  89. character_id: signup.characterid
  90. })
  91. .del()
  92. getRaids = async () : Promise<Raid[]> => {
  93. const subQuery = this.admin
  94. .knex('signups')
  95. .count('*')
  96. .where({
  97. raidid: this.admin.knex.ref('raids.id'),
  98. benched: false,
  99. late: false
  100. })
  101. .as('signupcount')
  102. return await this.admin.knex('raids')
  103. .select('*', subQuery)
  104. .orderBy('start', 'asc')
  105. }
  106. startRaid = async (raid:Raid) : Promise<RaidData> => {
  107. const archived = await this.archiveRaid(raid)
  108. delete archived.participants.late
  109. const giveCurrency = async (b: Character) => {
  110. const usr = await this.characterManager.getUserOfCharacter(b)
  111. await this.userManager.incrementCurrency(usr, 1)
  112. }
  113. await Promise.all([
  114. ...archived.participants.bench.map(giveCurrency),
  115. ...Object.values(archived.participants).map((group: any) => group.map(giveCurrency))
  116. ])
  117. return archived
  118. }
  119. archiveRaid = async (raid:Raid) : Promise<RaidData> => {
  120. const raidData = await this.getRaidData(raid)
  121. await this.admin.knex('archive')
  122. .insert({
  123. id:raidData.id,
  124. raiddata: JSON.stringify(raidData)
  125. })
  126. await Promise.all(
  127. Object.values(raidData.participants).flat().flatMap((signup) => this.admin
  128. .knex('tokens')
  129. .where({
  130. characterid: signup.characterid,
  131. signupid: null
  132. })
  133. .del()
  134. ))
  135. await this.admin.knex('raids')
  136. .where('id', '=', raid.id)
  137. .del()
  138. const row = await this.admin.knex('archive')
  139. .select('*')
  140. .where({
  141. id:raidData.id,
  142. })
  143. .first()
  144. return JSON.parse(row.raiddata)
  145. }
  146. getArchiveRaid = async(id:number) : Promise<RaidData> => {
  147. const data = await this.admin.knex('archive').select('raiddata').where({
  148. id: id
  149. }).first()
  150. return JSON.parse(data.raiddata)
  151. }
  152. getPastRaids = async(limit: number) : Promise<RaidData[]> => {
  153. const raids = await this.admin.knex('archive')
  154. .select('*')
  155. .orderBy('id', 'desc')
  156. .limit(limit)
  157. return raids.map(raid => JSON.parse(raid.raiddata))
  158. }
  159. getRaidData = async (raid:Raid) : Promise<RaidData> => {
  160. const ret = {
  161. participants:{
  162. Druid: <(Signup&Character&Spec)[]>[],
  163. Hunter: <(Signup&Character&Spec)[]>[],
  164. Mage: <(Signup&Character&Spec)[]>[],
  165. Paladin: <(Signup&Character&Spec)[]>[],
  166. Priest: <(Signup&Character&Spec)[]>[],
  167. Rogue: <(Signup&Character&Spec)[]>[],
  168. Shaman: <(Signup&Character&Spec)[]>[],
  169. Warlock: <(Signup&Character&Spec)[]>[],
  170. Warrior: <(Signup&Character&Spec)[]>[],
  171. late: <(Signup&Character&Spec)[]>[],
  172. bench: <(Signup&Character&Spec)[]>[],
  173. },
  174. tokens:{}
  175. }
  176. const subQuery = this.admin
  177. .knex('signups')
  178. .count('*')
  179. .where({
  180. raidid: this.admin.knex.ref('raids.id'),
  181. benched: false,
  182. late: false
  183. })
  184. .as('signupcount')
  185. const raidInDb: Raid = await this.admin.knex('raids')
  186. .select('*', subQuery)
  187. .where('id','=',raid.id)
  188. .first()
  189. const characterData: (Signup & Character & Spec)[] = await this.admin
  190. .knex('signups as s')
  191. .select('s.id as id', 'charactername', 'class', 'specname', 'race', 'userid', 'benched', 'late', 'raidid', 'characterid')
  192. .join('raids as r', 's.raidid','=','r.id')
  193. .join('characters as c', 's.characterid','=','c.id')
  194. .join('users as u', 'c.userid','=','u.id')
  195. .join('specs as sp', 'specid','=','sp.id')
  196. .where('r.id','=',raid.id)
  197. characterData.forEach(data => {
  198. if(data.benched){
  199. ret.participants.bench.push(data)
  200. return
  201. }
  202. if(data.late){
  203. ret.participants.late.push(data)
  204. return
  205. }
  206. ret.participants[data.class].push(data)
  207. })
  208. const tokenData: (Character & SRToken & Item)[] = await this.admin
  209. .knex('signups as s')
  210. .select('*', 's.id as id')
  211. .join('raids as r', 's.raidid','=','r.id')
  212. .where('r.id','=',raid.id)
  213. .andWhere(function(){
  214. this.whereNotNull('t.signupid')
  215. })
  216. .join('characters as c', 's.characterid','=','c.id')
  217. .join('tokens as t', 't.characterid','=','c.id')
  218. .join('items as i', 'i.itemname','=','t.itemname')
  219. tokenData.forEach(data => {
  220. if(!ret.tokens[data.itemname])
  221. ret.tokens[data.itemname] = []
  222. ret.tokens[data.itemname].push(data)
  223. })
  224. return {
  225. ...raidInDb,
  226. ...ret
  227. }
  228. }
  229. getSignups = async (raid:Raid) : Promise<(Signup & Character & Spec & User)[]> => await this.admin
  230. .knex('signups as si')
  231. .join('characters as c', 'c.id', '=', 'characterid')
  232. .join('specs as s', 's.id', '=', 'specid')
  233. .join('users as u', 'u.id', '=', 'userid')
  234. .select('*','si.id as id')
  235. .where('raidid', '=', raid.id!)
  236. sign = async (usertoken:string, character:Character, raid:Raid, late:boolean) => {
  237. const maybeUserRecord = this.userManager.getUserRecordByToken(usertoken)
  238. if(!maybeUserRecord || maybeUserRecord.user.id != character.userid){
  239. throw new Error("Bad Usertoken")
  240. }
  241. const exists = await this.admin
  242. .knex('signups')
  243. .select('*')
  244. .where({
  245. raidid: raid.id!,
  246. characterid: character.id!,
  247. })
  248. .first()
  249. if(!exists){
  250. await this.admin
  251. .knex('signups')
  252. .insert({
  253. raidid: raid.id!,
  254. characterid: character.id!,
  255. late: late
  256. })
  257. }else{
  258. await this.admin
  259. .knex('signups')
  260. .update({
  261. raidid: raid.id!,
  262. characterid: character.id!,
  263. late: late
  264. })
  265. }
  266. return await this.admin
  267. .knex('signups')
  268. .select('*')
  269. .where({
  270. raidid: raid.id!,
  271. characterid: character.id!,
  272. })
  273. .first()
  274. }
  275. unsign = async (usertoken:string, character:Character, raid:Raid) => {
  276. const maybeUserRecord = this.userManager.getUserRecordByToken(usertoken)
  277. if(!maybeUserRecord || maybeUserRecord.user.id != character.userid){
  278. throw new Error("Bad Usertoken")
  279. }
  280. await this.admin.knex('signups')
  281. .where({
  282. raidid: raid.id!,
  283. characterid: character.id!,
  284. })
  285. .del()
  286. }
  287. setBenched = async (signup: Signup) : Promise<void> => {
  288. await this.admin.knex('signups')
  289. .where({
  290. raidid: signup.raidid,
  291. characterid: signup.characterid
  292. })
  293. .update(signup)
  294. }
  295. }