Browse Source

AQ update

master
peter 5 years ago
parent
commit
7c1b0b73ed
35 changed files with 1342 additions and 880 deletions
  1. 2
    0
      .gitignore
  2. BIN
      live_db/frontworkAdmin.sqlite
  3. 14
    22
      migrations/000_signups_addColumn_memo_timestamp.js
  4. 1
    1
      migrations/001_items_addColumn_stats.js
  5. 359
    289
      package-lock.json
  6. 3
    2
      package.json
  7. 9
    5
      src/backend/Admin/Admin.ts
  8. 2
    3
      src/backend/Components/Character/CharacterManager.ts
  9. 3
    3
      src/backend/Components/Guild/GuildManager.ts
  10. 3
    1
      src/backend/Components/Item/Interface.ts
  11. 43
    17
      src/backend/Components/Item/ItemManager.ts
  12. 1
    1
      src/backend/Components/PluginLoader.ts
  13. 1
    1
      src/backend/Components/PubSub/PubSub.ts
  14. 1
    1
      src/backend/Components/RPCConfigLoader.ts
  15. 3
    2
      src/backend/Components/Raid/Interface.ts
  16. 2
    1
      src/backend/Components/Raid/RPCInterface.ts
  17. 75
    39
      src/backend/Components/Raid/RaidManager.ts
  18. 24
    25
      src/backend/Components/User/UserManager.ts
  19. 2
    2
      src/backend/Types/FrontworkComponent.ts
  20. 417
    281
      src/backend/Types/Items.ts
  21. 1
    1
      src/backend/Types/Plugin.ts
  22. 1
    1
      src/backend/Types/PrivilegedRPCExporter.ts
  23. 3
    1
      src/backend/Types/Types.ts
  24. 239
    56
      src/frontend/package-lock.json
  25. 2
    2
      src/frontend/package.json
  26. 1
    0
      src/frontend/src/app/frontcraft/pages/armory/armory.component.ts
  27. 0
    19
      src/frontend/src/app/frontcraft/pages/character/character.component.html
  28. 15
    6
      src/frontend/src/app/frontcraft/pages/raid/characterpicker.component.html
  29. 2
    2
      src/frontend/src/app/frontcraft/pages/raid/characterpicker.component.ts
  30. 32
    50
      src/frontend/src/app/frontcraft/pages/raid/raid.component.html
  31. 40
    8
      src/frontend/src/app/frontcraft/pages/raid/raid.component.ts
  32. 5
    5
      src/frontend/src/app/frontcraft/pages/shop/buytoken.component.ts
  33. 3
    3
      src/frontend/src/app/frontcraft/services/ApiService/client-login-api.ts
  34. 2
    2
      src/frontend/src/app/frontcraft/services/ApiService/server-login-api.ts
  35. 31
    28
      test/backendTest.ts

+ 2
- 0
.gitignore View File

13
 *.d.ts
13
 *.d.ts
14
 *.js
14
 *.js
15
 *.ts
15
 *.ts
16
+log.txt
17
+
16
 
18
 
17
 !src/**/*
19
 !src/**/*
18
 node_modules
20
 node_modules

BIN
live_db/frontworkAdmin.sqlite View File


+ 14
- 22
migrations/000_signups_addColumn_memo_timestamp.js View File

11
                     output: process.stdout
11
                     output: process.stdout
12
                 })
12
                 })
13
                 return new Promise((res, rej) => {
13
                 return new Promise((res, rej) => {
14
-                    r1.question('WARNING\n\nAbout to update your signups table. Please make sure there are no active signups. \nContinue? y/N', answer => {
15
-                        if(!answer || answer === "" || answer === "n" || answer === "N"){
16
-                            rej(new Error("User aborted"))
17
-                        }else{
18
-                            knex('signups').select('*').then(rows => {
19
-                                return knex.schema.dropTable('signups').then(_ => {
20
-                                    return knex.schema.createTable('signups', function (table) {
21
-                                        table.increments('id').primary()
22
-                                        table.unique(['raidid', 'characterid'])
23
-                                        table.integer('raidid')
24
-                                        table.foreign('raidid').references('id').inTable('raids').onDelete('CASCADE')
25
-                                        table.integer('characterid')
26
-                                        table.foreign('characterid').references('id').inTable('characters').onDelete('CASCADE')
27
-                                        table.boolean('benched').defaultTo('false')
28
-                                        table.boolean('late')
29
-                                        table.timestamp('timestamp').defaultTo(knex.fn.now())
30
-                                        table.string('memo').nullable()
31
-                                        res()
32
-                                    }).catch(rej)
33
-                                })
34
-                            })
35
-                        }
14
+                    return knex.schema.dropTable('signups').then(_ => {
15
+                        return knex.schema.createTable('signups', function (table) {
16
+                            table.increments('id').primary()
17
+                            table.unique(['raidid', 'characterid'])
18
+                            table.integer('raidid')
19
+                            table.foreign('raidid').references('id').inTable('raids').onDelete('CASCADE')
20
+                            table.integer('characterid')
21
+                            table.foreign('characterid').references('id').inTable('characters').onDelete('CASCADE')
22
+                            table.boolean('benched').defaultTo('false')
23
+                            table.boolean('late')
24
+                            table.timestamp('timestamp').defaultTo(knex.fn.now())
25
+                            table.string('memo').nullable()
26
+                            res()
27
+                        }).catch(rej)
36
                     })
28
                     })
37
                 })
29
                 })
38
             }
30
             }

+ 1
- 1
migrations/001_items_addColumn_stats.js View File

12
 
12
 
13
 
13
 
14
 exports.down = function (knex) {
14
 exports.down = function (knex) {
15
-    return knex.schema.table('signups', function (table) {
15
+    return knex.schema.table('items', function (table) {
16
         table.dropColumn('stats')
16
         table.dropColumn('stats')
17
     })
17
     })
18
 }
18
 }

+ 359
- 289
package-lock.json
File diff suppressed because it is too large
View File


+ 3
- 2
package.json View File

26
   "license": "ISC",
26
   "license": "ISC",
27
   "dependencies": {
27
   "dependencies": {
28
     "@types/mocha": "^5.2.7",
28
     "@types/mocha": "^5.2.7",
29
+    "@types/node": "^14.0.27",
29
     "bsert": "0.0.10",
30
     "bsert": "0.0.10",
30
     "bsock": "^0.1.9",
31
     "bsock": "^0.1.9",
31
     "child-process-promise": "^2.2.1",
32
     "child-process-promise": "^2.2.1",
47
     "path": "^0.12.7",
48
     "path": "^0.12.7",
48
     "reflect-metadata": "^0.1.13",
49
     "reflect-metadata": "^0.1.13",
49
     "rimraf": "^3.0.0",
50
     "rimraf": "^3.0.0",
50
-    "rpclibrary": "^1.10.2",
51
+    "rpclibrary": "^2.0.1",
51
     "simple-git": "^1.124.0",
52
     "simple-git": "^1.124.0",
52
     "spawn-sync": "^2.0.0",
53
     "spawn-sync": "^2.0.0",
53
-    "sqlite3": "^4.1.1",
54
+    "sqlite3": "^4.2.0",
54
     "trash": "^6.0.0",
55
     "trash": "^6.0.0",
55
     "tsyringe": "^4.0.1",
56
     "tsyringe": "^4.0.1",
56
     "upgiter": "^1.0.4",
57
     "upgiter": "^1.0.4",

+ 9
- 5
src/backend/Admin/Admin.ts View File

79
         ])
79
         ])
80
             .catch(e => getLogger('Admin#stop').warn(e))
80
             .catch(e => getLogger('Admin#stop').warn(e))
81
             .finally(() => {
81
             .finally(() => {
82
-                this.rpcServer.destroy()
82
+                this.rpcServer.close()
83
                 process.exit(0)
83
                 process.exit(0)
84
             })
84
             })
85
     }
85
     }
107
     }
107
     }
108
 
108
 
109
     private startWebsocket() {
109
     private startWebsocket() {
110
-        this.rpcServer = new RPCServer(20000, [
110
+        this.rpcServer = new RPCServer([
111
             ...this.frontworkComponents,
111
             ...this.frontworkComponents,
112
             {
112
             {
113
                 name: "debug",
113
                 name: "debug",
114
-                exportRPCs: () => [{
114
+                RPCs: () => [{
115
                     name: 'dumpDb',
115
                     name: 'dumpDb',
116
                     call: async (table) => await this.knex(table).select('*')
116
                     call: async (table) => await this.knex(table).select('*')
117
                 }]
117
                 }]
118
             }
118
             }
119
         ], {
119
         ], {
120
-            visibility: '0.0.0.0'
121
-        })
120
+            errorHandler: (sock, err, rpc, args) => {
121
+                console.log(rpc, err);
122
+                
123
+            }
124
+
125
+        }).listen(20000)
122
         getLogger('Admin#startWebsocket').debug("Websocket up on", 20000)
126
         getLogger('Admin#startWebsocket').debug("Websocket up on", 20000)
123
     }
127
     }
124
 
128
 

+ 2
- 3
src/backend/Components/Character/CharacterManager.ts View File

20
     @Inject(IUserManager)
20
     @Inject(IUserManager)
21
     private loginManager : IUserManager
21
     private loginManager : IUserManager
22
 
22
 
23
-    exportRPCs = () => [
23
+    RPCs = () => [
24
             this.getSpecId,
24
             this.getSpecId,
25
             this.getCharacterByName,
25
             this.getCharacterByName,
26
             this.getCharacters,
26
             this.getCharacters,
30
             this.getHeadCount
30
             this.getHeadCount
31
     ]
31
     ]
32
 
32
 
33
-    exportRPCFeatures = () => [
34
-    ]
33
+    RPCFeatures = () => []
35
     
34
     
36
     getTableDefinitions = (): TableDefiniton[] => [
35
     getTableDefinitions = (): TableDefiniton[] => [
37
         {
36
         {

+ 3
- 3
src/backend/Components/Guild/GuildManager.ts View File

28
         }
28
         }
29
     }, "./config")
29
     }, "./config")
30
 
30
 
31
-    exportRPCs = () => [
31
+    RPCs = () => [
32
         this.getHeadCount,
32
         this.getHeadCount,
33
         this.getGuildInfo
33
         this.getGuildInfo
34
     ]
34
     ]
35
 
35
 
36
-    exportRPCFeatures = () => [{
36
+    RPCFeatures = () => [{
37
         name: 'manageGuild' as 'manageGuild',
37
         name: 'manageGuild' as 'manageGuild',
38
-        exportRPCs: () => [
38
+        RPCs: () => [
39
             this.setName,
39
             this.setName,
40
             this.setRealm,
40
             this.setRealm,
41
             this.setDescription
41
             this.setDescription

+ 3
- 1
src/backend/Components/Item/Interface.ts View File

9
     setPriority: (itemname:string, priority: any) => Promise<void>
9
     setPriority: (itemname:string, priority: any) => Promise<void>
10
     calculatePriorities: (itemname: string, character:Character) => Promise<number>
10
     calculatePriorities: (itemname: string, character:Character) => Promise<number>
11
     deletePriority: (priority:SRPriority) => Promise<void>
11
     deletePriority: (priority:SRPriority) => Promise<void>
12
-    getTokens: (character:Character, tiers: Tiers[], valid?:boolean) => Promise<(SRToken & Character & Item)[] | undefined>
12
+    getTokens: (character:Character, tiers: Tiers[], valid:boolean) => Promise<(SRToken & Character & Item)[] | undefined>
13
     getToken: (character:Character, item:Item, valid?:boolean) => Promise<(SRToken & Character & Item) | undefined>
13
     getToken: (character:Character, item:Item, valid?:boolean) => Promise<(SRToken & Character & Item) | undefined>
14
     getAllPriorities: () => Promise<(SRPriority & Spec & Item)[]>
14
     getAllPriorities: () => Promise<(SRPriority & Spec & Item)[]>
15
     wipeCurrencyAndItems: () => Promise<void>
15
     wipeCurrencyAndItems: () => Promise<void>
16
+    decayTokens: (tier: Tiers, amount?:number) => Promise<void>
17
+    decayTokensOfCharacter: (tier: Tiers, character:Character, amount?:number) => Promise<void>
16
 }
18
 }

+ 43
- 17
src/backend/Components/Item/ItemManager.ts View File

10
 import { ICharacterManager } from "../Character/Interface";
10
 import { ICharacterManager } from "../Character/Interface";
11
 import { IPubSub } from "../PubSub/Interface";
11
 import { IPubSub } from "../PubSub/Interface";
12
 import { IRaidManager } from "../Raid/Interface";
12
 import { IRaidManager } from "../Raid/Interface";
13
-import { getLogger } from "frontblock-generic/Types";
13
+import { getLogger } from "log4js";
14
 
14
 
15
 const fetch = require('node-fetch')
15
 const fetch = require('node-fetch')
16
 const xml2js = require('xml2js');
16
 const xml2js = require('xml2js');
36
     @Inject(IRaidManager)
36
     @Inject(IRaidManager)
37
     private raidManager: IRaidManager
37
     private raidManager: IRaidManager
38
 
38
 
39
-    exportRPCs = () => [
39
+    RPCs = () => [
40
         this.getItems,
40
         this.getItems,
41
         this.getItem,
41
         this.getItem,
42
         this.buyToken,
42
         this.buyToken,
46
         this.getAllPriorities
46
         this.getAllPriorities
47
     ]
47
     ]
48
 
48
 
49
-    exportRPCFeatures = () => [{
49
+    RPCFeatures = () => [{
50
         name: 'managePriorities' as 'managePriorities',
50
         name: 'managePriorities' as 'managePriorities',
51
-        exportRPCs: () => [
51
+        RPCs: () => [
52
             this.setPriority,
52
             this.setPriority,
53
             this.deletePriority
53
             this.deletePriority
54
         ],
54
         ],
55
     }, {
55
     }, {
56
         name: 'reset' as 'reset',
56
         name: 'reset' as 'reset',
57
-        exportRPCs: () => [
57
+        RPCs: () => [
58
             this.wipeCurrencyAndItems
58
             this.wipeCurrencyAndItems
59
         ]
59
         ]
60
     }]
60
     }]
129
             return item
129
             return item
130
 
130
 
131
         }catch(e){
131
         }catch(e){
132
-            getLogger('ItemManager', 'error').error(name, e);
132
+            getLogger('ItemManager').error(name, e);
133
         }
133
         }
134
     }
134
     }
135
 
135
 
191
         const streaks = await this.getTokens(character, [item.tier], false)
191
         const streaks = await this.getTokens(character, [item.tier], false)
192
         const activeTokens = await this.getTokens(character, [item.tier], true)
192
         const activeTokens = await this.getTokens(character, [item.tier], true)
193
 
193
 
194
-        await this.userManager.decrementCurrency(record.user, item.tier, 1)
194
+        await this.userManager.decrementCurrency(record.user, item.tier, currency)
195
         const modifier = await this.calculatePriorities(itemname, character)
195
         const modifier = await this.calculatePriorities(itemname, character)
196
 
196
 
197
         const tx = await this.admin.knex.transaction()
197
         const tx = await this.admin.knex.transaction()
198
 
198
 
199
-        if (streaks.length > 0) {
199
+        if (streaks.length > 0) { //if an old streak already exists
200
             const myStreak = streaks.find(token => token.itemname === itemname)
200
             const myStreak = streaks.find(token => token.itemname === itemname)
201
-            if (myStreak) {
201
+            if (myStreak) { //and the streak is for this item
202
                 //getLogger('ItemManager').debug('update signupid and increment level')
202
                 //getLogger('ItemManager').debug('update signupid and increment level')
203
                 await this.admin
203
                 await this.admin
204
                     .knex(item.tier + 'tokens')
204
                     .knex(item.tier + 'tokens')
209
                     })
209
                     })
210
                     .update({
210
                     .update({
211
                         signupid: signup.id,
211
                         signupid: signup.id,
212
-                        level: myStreak.level + 1
212
+                        level: myStreak.level + currency + 1
213
                     })
213
                     })
214
 
214
 
215
             }
215
             }
216
 
216
 
217
-            //getLogger('ItemManager').debug('delete streaks')
217
+            //getLogger('ItemManager').debug('delete other streaks')
218
             await Promise.all(streaks.map(async s => await this.admin
218
             await Promise.all(streaks.map(async s => await this.admin
219
                 .knex(item.tier + 'tokens')
219
                 .knex(item.tier + 'tokens')
220
                 .transacting(tx)
220
                 .transacting(tx)
226
                 .del()
226
                 .del()
227
             ))
227
             ))
228
 
228
 
229
+            //If there was a streak for this item we're done
229
             if (myStreak) {
230
             if (myStreak) {
230
                 await tx.commit()
231
                 await tx.commit()
231
                 await this.notifyRaid({ id: signup.raidid })
232
                 await this.notifyRaid({ id: signup.raidid })
232
-
233
                 return await this.getToken(character, item)
233
                 return await this.getToken(character, item)
234
             }
234
             }
235
         }
235
         }
236
 
236
 
237
+        //check if there is an active reserve for this item
237
         const matchingReserve = activeTokens.find(token => token.itemname === itemname)
238
         const matchingReserve = activeTokens.find(token => token.itemname === itemname)
238
         if (matchingReserve) {
239
         if (matchingReserve) {
239
-            //getLogger('ItemManager').debug('upgrade reserve')
240
+            getLogger('ItemManager').debug('upgrade reserve')
240
             await this.admin
241
             await this.admin
241
                 .knex(item.tier + 'tokens')
242
                 .knex(item.tier + 'tokens')
242
                 .transacting(tx)
243
                 .transacting(tx)
243
-                .increment('level')
244
+                .increment('level', currency + 1)
244
                 .where({
245
                 .where({
245
                     signupid: signup.id,
246
                     signupid: signup.id,
246
                     characterid: character.id,
247
                     characterid: character.id,
247
                     itemname: item.itemname
248
                     itemname: item.itemname
248
                 })
249
                 })
249
         } else {
250
         } else {
250
-            //getLogger('ItemManager').debug('new reserve')
251
+            getLogger('ItemManager').debug('new reserve')
251
             await this.admin
252
             await this.admin
252
                 .knex(item.tier + 'tokens')
253
                 .knex(item.tier + 'tokens')
253
                 .transacting(tx)
254
                 .transacting(tx)
254
                 .insert({
255
                 .insert({
255
                     characterid: character.id,
256
                     characterid: character.id,
256
                     itemname: item.itemname,
257
                     itemname: item.itemname,
257
-                    level: 1 + modifier,
258
+                    level: 1 + modifier + currency,
258
                     signupid: signup.id
259
                     signupid: signup.id
259
                 })
260
                 })
260
         }
261
         }
346
             .first()
347
             .first()
347
     }
348
     }
348
 
349
 
349
-    getTokens = async (character: Character, tiers: Tiers[], valid = true): Promise<(SRToken & Character & Item)[]> => {
350
+    getTokens = async (character: Character, tiers: Tiers[], valid:boolean): Promise<(SRToken & Character & Item)[]> => {
350
         const ret = await Promise.all(tiers.map(async tier => {
351
         const ret = await Promise.all(tiers.map(async tier => {
351
             return await this.admin
352
             return await this.admin
352
                 .knex(tier + 'tokens as t')
353
                 .knex(tier + 'tokens as t')
367
         return ret.flat()
368
         return ret.flat()
368
     }
369
     }
369
 
370
 
371
+    decayTokens = async (tier: Tiers, amount = 1) => {
372
+        await this.admin
373
+        .knex(tier + 'tokens')
374
+        .decrement('level', Math.max(amount, 1))
375
+
376
+        await this.admin
377
+        .knex(tier + 'tokens as t')
378
+        .where('level', '<=', 0)
379
+        .del()
380
+    }
381
+
382
+    decayTokensOfCharacter = async (tier: Tiers, character:Character, amount = 1) => {
383
+        await this.admin
384
+        .knex(tier + 'tokens')
385
+        .where({
386
+            characterid: character.id
387
+        })
388
+        .decrement('level', Math.max(amount, 1))
389
+
390
+        await this.admin
391
+        .knex(tier + 'tokens as t')
392
+        .where('level', '<=', 0)
393
+        .del()
394
+    }
395
+
370
     countItems = async (): Promise<number> => {
396
     countItems = async (): Promise<number> => {
371
         const count = await this.admin
397
         const count = await this.admin
372
             .knex('items')
398
             .knex('items')

+ 1
- 1
src/backend/Components/PluginLoader.ts View File

143
 
143
 
144
     name = "PluginLoader" as "PluginLoader";
144
     name = "PluginLoader" as "PluginLoader";
145
 
145
 
146
-    exportRPCs(){
146
+    RPCs(){
147
         return [{
147
         return [{
148
             name: "installPlugin" as "installPlugin",
148
             name: "installPlugin" as "installPlugin",
149
             call: this.installPlugin,
149
             call: this.installPlugin,

+ 1
- 1
src/backend/Components/PubSub/PubSub.ts View File

13
         }
13
         }
14
     }= {}
14
     }= {}
15
 
15
 
16
-    exportRPCs = () => [
16
+    RPCs = () => [
17
         this.unsubscribe,
17
         this.unsubscribe,
18
         {
18
         {
19
             name: 'subscribe',
19
             name: 'subscribe',

+ 1
- 1
src/backend/Components/RPCConfigLoader.ts View File

18
 
18
 
19
     name = "Config" as "Config"
19
     name = "Config" as "Config"
20
 
20
 
21
-    exportRPCs = () => [
21
+    RPCs = () => [
22
         this.getConfig,
22
         this.getConfig,
23
         this.resetConfig,
23
         this.resetConfig,
24
         this.setConfig,
24
         this.setConfig,

+ 3
- 2
src/backend/Components/Raid/Interface.ts View File

6
     addSignup: (signup: Signup) => Promise<Signup>
6
     addSignup: (signup: Signup) => Promise<Signup>
7
     removeSignup: (signup: Signup) => Promise<any>    
7
     removeSignup: (signup: Signup) => Promise<any>    
8
     getSignups: (raid:Raid) => Promise<(Signup & Character & Spec & User)[]>
8
     getSignups: (raid:Raid) => Promise<(Signup & Character & Spec & User)[]>
9
-    sign: (userToken: string, character:Character, raid:Raid, late:boolean, memo?: string) => Promise<any>
9
+    sign: (userToken: string, character:Character, raid:Raid, late:boolean, absent:boolean, memo?: string) => Promise<any>
10
     unsign: (userToken: string, character:Character, raid:Raid,) => Promise<any>
10
     unsign: (userToken: string, character:Character, raid:Raid,) => Promise<any>
11
     archiveRaid: (raid:Raid) => Promise<RaidData>
11
     archiveRaid: (raid:Raid) => Promise<RaidData>
12
     getRaidData: (raid:Raid) => Promise<RaidData>
12
     getRaidData: (raid:Raid) => Promise<RaidData>
13
-    setBenched: (signup: Signup) => Promise<void>
13
+    updateSignup: (signup: Signup) => Promise<void>
14
     getPastRaids: (limit: number) => Promise<RaidData[]>
14
     getPastRaids: (limit: number) => Promise<RaidData[]>
15
     getArchiveRaid: (id:number) => Promise<RaidData>
15
     getArchiveRaid: (id:number) => Promise<RaidData>
16
     startRaid: (raid:Raid) => Promise<RaidData>
16
     startRaid: (raid:Raid) => Promise<RaidData>
17
     adminUnsign: (character:Character, raid:Raid) => Promise<any>
17
     adminUnsign: (character:Character, raid:Raid) => Promise<any>
18
+    cancelRaid: (raid: Raid) => Promise<void>
18
 }
19
 }

+ 2
- 1
src/backend/Components/Raid/RPCInterface.ts View File

15
         addSignup: IRaidManager['addSignup']
15
         addSignup: IRaidManager['addSignup']
16
         removeSignup: IRaidManager['removeSignup'] 
16
         removeSignup: IRaidManager['removeSignup'] 
17
         archiveRaid: IRaidManager['archiveRaid']
17
         archiveRaid: IRaidManager['archiveRaid']
18
-        setBenched: IRaidManager['setBenched']
18
+        updateSignup: IRaidManager['updateSignup']
19
         startRaid: IRaidManager['startRaid']
19
         startRaid: IRaidManager['startRaid']
20
         adminUnsign: IRaidManager['adminUnsign']
20
         adminUnsign: IRaidManager['adminUnsign']
21
+        cancelRaid: IRaidManager['cancelRaid']
21
     }
22
     }
22
     signup: {
23
     signup: {
23
         getSignups: IRaidManager['getSignups']
24
         getSignups: IRaidManager['getSignups']

+ 75
- 39
src/backend/Components/Raid/RaidManager.ts View File

33
     @Inject(IPubSub)
33
     @Inject(IPubSub)
34
     private pubsub: IPubSub<any>
34
     private pubsub: IPubSub<any>
35
 
35
 
36
-    exportRPCs = () => [
36
+    RPCs = () => [
37
         this.getRaids,
37
         this.getRaids,
38
         this.getRaidData,
38
         this.getRaidData,
39
         this.getPastRaids,
39
         this.getPastRaids,
40
         this.getArchiveRaid
40
         this.getArchiveRaid
41
     ]
41
     ]
42
 
42
 
43
-    exportRPCFeatures() {
43
+    RPCFeatures() {
44
         return [{
44
         return [{
45
             name: 'manageRaid' as 'manageRaid',
45
             name: 'manageRaid' as 'manageRaid',
46
-            exportRPCs: () => [
46
+            RPCs: () => [
47
                 this.createRaid,
47
                 this.createRaid,
48
                 this.addSignup,
48
                 this.addSignup,
49
                 this.removeSignup,
49
                 this.removeSignup,
50
                 this.archiveRaid,
50
                 this.archiveRaid,
51
-                this.setBenched,
51
+                this.updateSignup,
52
                 this.startRaid,
52
                 this.startRaid,
53
-                this.adminUnsign
53
+                this.adminUnsign,
54
+                this.cancelRaid
54
             ]
55
             ]
55
         }, {
56
         }, {
56
             name: 'signup' as 'signup',
57
             name: 'signup' as 'signup',
57
-            exportRPCs: () => [
58
+            RPCs: () => [
58
                 this.getSignups,
59
                 this.getSignups,
59
                 this.sign,
60
                 this.sign,
60
                 this.unsign
61
                 this.unsign
98
         ]
99
         ]
99
     }
100
     }
100
 
101
 
101
-    notifyRaid = async (raid:Raid | {id:number}) => {
102
+    notifyRaid = async (raid: Raid | { id: number }) => {
102
         const data = await this.getRaidData(<Raid>raid)
103
         const data = await this.getRaidData(<Raid>raid)
103
-        try{
104
+        try {
104
             await this.pubsub.publish(String(raid.id), data)
105
             await this.pubsub.publish(String(raid.id), data)
105
             await this.notifyRaids()
106
             await this.notifyRaids()
106
-        }catch(e){
107
+        } catch (e) {
107
             getLogger('RaidManager#notifyRaid').debug(e);
108
             getLogger('RaidManager#notifyRaid').debug(e);
108
         }
109
         }
109
     }
110
     }
110
 
111
 
111
     notifyRaids = async () => {
112
     notifyRaids = async () => {
112
-        try{
113
+        try {
113
             await this.pubsub.publish('raids', undefined)
114
             await this.pubsub.publish('raids', undefined)
114
-        }catch(e){
115
+        } catch (e) {
115
             getLogger('RaidManager#notifyRaids').debug(e);
116
             getLogger('RaidManager#notifyRaids').debug(e);
116
         }
117
         }
117
     }
118
     }
171
     }
172
     }
172
 
173
 
173
     startRaid = async (raid: Raid): Promise<RaidData> => {
174
     startRaid = async (raid: Raid): Promise<RaidData> => {
175
+        const data = await this.getRaidData(raid)
176
+        data.participants.absent.map(p => this.itemManager.decayTokensOfCharacter(raid.tier, p, 1))
177
+        await this.itemManager.decayTokens(data.tier)      
174
         const archived = await this.archiveRaid(raid)
178
         const archived = await this.archiveRaid(raid)
175
 
179
 
176
         const giveCurrency = async (b: Character) => {
180
         const giveCurrency = async (b: Character) => {
180
 
184
 
181
         await Promise.all([
185
         await Promise.all([
182
             ...archived.participants.bench.map(giveCurrency),
186
             ...archived.participants.bench.map(giveCurrency),
183
-            ...Object.values(archived.participants).flat().map((b:Signup & Character & Spec) => giveCurrency(b))
187
+            ...Object.values(archived.participants).flat().map((b: Signup & Character & Spec) => giveCurrency(b))
184
         ])
188
         ])
185
 
189
 
186
         await this.notifyRaids()
190
         await this.notifyRaids()
187
-
188
         return archived
191
         return archived
189
     }
192
     }
190
 
193
 
191
     archiveRaid = async (raid: Raid): Promise<RaidData> => {
194
     archiveRaid = async (raid: Raid): Promise<RaidData> => {
192
         const raidData = await this.getRaidData(raid)
195
         const raidData = await this.getRaidData(raid)
193
-
194
         const tx = await this.admin.knex.transaction()
196
         const tx = await this.admin.knex.transaction()
195
 
197
 
196
         await this.admin.knex('archive')
198
         await this.admin.knex('archive')
201
             })
203
             })
202
 
204
 
203
         await Promise.all(
205
         await Promise.all(
204
-            Object.values(raidData.participants).flat().flatMap((p: (Signup & Character & Spec)) => 
206
+            Object.values(raidData.participants).flat().flatMap((p: (Signup & Character & Spec)) =>
205
                 this.admin
207
                 this.admin
206
-                .knex(raid.tier + 'tokens')
207
-                .transacting(tx)
208
-                .where({
209
-                    characterid: p.characterid,
210
-                    signupid: null
211
-                })
212
-                .del()
208
+                    .knex(raid.tier + 'tokens')
209
+                    .transacting(tx)
210
+                    .where({
211
+                        characterid: p.characterid,
212
+                        signupid: null
213
+                    })
214
+                    .del()
213
             ))
215
             ))
214
 
216
 
215
         await this.admin.knex('raids')
217
         await this.admin.knex('raids')
225
                 id: raidData.id,
227
                 id: raidData.id,
226
             })
228
             })
227
             .first()
229
             .first()
228
-        return JSON.parse(row.raiddata)
230
+
231
+        try {
232
+            return JSON.parse(row.raiddata)
233
+        } catch (e) {
234
+            getLogger('RaidManager#archiveRaid').error(row.id + " could not get parsed")
235
+            return {} as RaidData
236
+        }
229
     }
237
     }
230
 
238
 
231
     getArchiveRaid = async (id: number): Promise<RaidData> => {
239
     getArchiveRaid = async (id: number): Promise<RaidData> => {
232
-        const data = await this.admin.knex('archive').select('raiddata').where({
233
-            id: id
234
-        }).first()
240
+        const data = await this.admin
241
+            .knex('archive')
242
+            .select('raiddata')
243
+            .where({
244
+                id: id
245
+            })
246
+            .first()
235
 
247
 
236
-        return JSON.parse(data.raiddata)
248
+        try {
249
+            return JSON.parse(data.raiddata)
250
+        } catch (e) {
251
+            getLogger('RaidManager#getArchiveRaid').error(id + " could not get parsed")
252
+            return {} as RaidData
253
+        }
237
     }
254
     }
238
 
255
 
239
     getPastRaids = async (limit: number): Promise<RaidData[]> => {
256
     getPastRaids = async (limit: number): Promise<RaidData[]> => {
259
                 Warrior: <(Signup & Character & Spec)[]>[],
276
                 Warrior: <(Signup & Character & Spec)[]>[],
260
                 late: <(Signup & Character & Spec)[]>[],
277
                 late: <(Signup & Character & Spec)[]>[],
261
                 bench: <(Signup & Character & Spec)[]>[],
278
                 bench: <(Signup & Character & Spec)[]>[],
279
+                absent: <(Signup & Character & Spec)[]>[]
262
             },
280
             },
263
             tokens: {},
281
             tokens: {},
264
             healers: <(Signup & Character & Spec)[]>[],
282
             healers: <(Signup & Character & Spec)[]>[],
271
             .where({
289
             .where({
272
                 raidid: this.admin.knex.ref('raids.id'),
290
                 raidid: this.admin.knex.ref('raids.id'),
273
                 benched: false,
291
                 benched: false,
274
-                late: false
292
+                late: false,
293
+                absent: false
275
             })
294
             })
276
             .as('signupcount')
295
             .as('signupcount')
277
 
296
 
283
 
302
 
284
         const characterData: (Signup & Character & Spec)[] = await this.admin
303
         const characterData: (Signup & Character & Spec)[] = await this.admin
285
             .knex('signups as s')
304
             .knex('signups as s')
286
-            .select('s.id as id', 'charactername', 'rank', 'class', 'specid', 'specname', 'race', 'userid', 'benched', 'late', 'raidid', 'characterid', 'specid', 'memo', 'timestamp')
305
+            .select('s.id as id', 'charactername', 'rank', 'class', 'specid', 'specname', 'race', 'userid', 'benched', 'late', 'raidid', 'characterid', 'specid', 'memo', 'timestamp', 'absent')
287
             .join('raids as r', 's.raidid', '=', 'r.id')
306
             .join('raids as r', 's.raidid', '=', 'r.id')
288
             .join('characters as c', 's.characterid', '=', 'c.id')
307
             .join('characters as c', 's.characterid', '=', 'c.id')
289
             .join('users as u', 'c.userid', '=', 'u.id')
308
             .join('users as u', 'c.userid', '=', 'u.id')
291
             .where('r.id', '=', raid.id)
310
             .where('r.id', '=', raid.id)
292
 
311
 
293
         characterData.forEach(data => {
312
         characterData.forEach(data => {
313
+            if(data.absent){
314
+                raiddata.participants.absent.push(data)
315
+                return
316
+            }
294
             if (data.benched) {
317
             if (data.benched) {
295
                 raiddata.participants.bench.push(data)
318
                 raiddata.participants.bench.push(data)
296
                 return
319
                 return
307
             .select('*', 's.id as id')
330
             .select('*', 's.id as id')
308
             .join('raids as r', 's.raidid', '=', 'r.id')
331
             .join('raids as r', 's.raidid', '=', 'r.id')
309
             .join('characters as c', 's.characterid', '=', 'c.id')
332
             .join('characters as c', 's.characterid', '=', 'c.id')
310
-            .join('users as u', 'u.id', '=' ,'c.userid')
333
+            .join('users as u', 'u.id', '=', 'c.userid')
311
             .join(raidInDb.tier + 'tokens as t', 't.characterid', '=', 'c.id')
334
             .join(raidInDb.tier + 'tokens as t', 't.characterid', '=', 'c.id')
312
             .join('items as i', 'i.itemname', '=', 't.itemname')
335
             .join('items as i', 'i.itemname', '=', 't.itemname')
313
             .where({
336
             .where({
327
         raiddata.tanks = Object.values(raiddata.participants).flatMap(
350
         raiddata.tanks = Object.values(raiddata.participants).flatMap(
328
             (tanks: any[]) => tanks.filter((p: any) =>
351
             (tanks: any[]) => tanks.filter((p: any) =>
329
                 !p.benched
352
                 !p.benched
353
+                && !p.absent
330
                 && !p.late
354
                 && !p.late
331
                 && (p.specname === "Protection"
355
                 && (p.specname === "Protection"
332
                     || p.specname === "Feral (Tank)"))
356
                     || p.specname === "Feral (Tank)"))
334
         raiddata.healers = Object.values(raiddata.participants).flatMap(
358
         raiddata.healers = Object.values(raiddata.participants).flatMap(
335
             (healers: any[]) => healers.filter((p: any) =>
359
             (healers: any[]) => healers.filter((p: any) =>
336
                 !p.benched
360
                 !p.benched
361
+                && !p.absent
337
                 && !p.late
362
                 && !p.late
338
                 && (p.specname === "Holy"
363
                 && (p.specname === "Holy"
339
                     || p.specname === "Discipline"
364
                     || p.specname === "Discipline"
354
         .select('*', 'si.id as id')
379
         .select('*', 'si.id as id')
355
         .where('raidid', '=', raid.id!)
380
         .where('raidid', '=', raid.id!)
356
 
381
 
357
-    sign = async (usertoken: string, character: Character, raid: Raid, late: boolean, memo?: string) => {
382
+    sign = async (usertoken: string, character: Character, raid: Raid, late: boolean, absent:boolean, memo?: string) => {
358
         const maybeUserRecord = this.userManager.getUserRecordByToken(usertoken)
383
         const maybeUserRecord = this.userManager.getUserRecordByToken(usertoken)
359
         if (!maybeUserRecord || maybeUserRecord.user.id != character.userid) {
384
         if (!maybeUserRecord || maybeUserRecord.user.id != character.userid) {
360
             throw new Error("Bad Usertoken")
385
             throw new Error("Bad Usertoken")
361
         }
386
         }
362
 
387
 
363
-        if(memo) memo = memo.substring(0, MAX_MEMO_LENGTH)
388
+        if (memo) memo = memo.substring(0, MAX_MEMO_LENGTH)
364
         const exists = await this.admin
389
         const exists = await this.admin
365
             .knex('signups')
390
             .knex('signups')
366
             .select('*')
391
             .select('*')
377
                     raidid: raid.id!,
402
                     raidid: raid.id!,
378
                     characterid: character.id!,
403
                     characterid: character.id!,
379
                     late: late,
404
                     late: late,
405
+                    absent: absent,
380
                     benched: false,
406
                     benched: false,
381
                     memo: memo
407
                     memo: memo
382
                 })
408
                 })
390
                     raidid: raid.id!,
416
                     raidid: raid.id!,
391
                     characterid: character.id!,
417
                     characterid: character.id!,
392
                     late: late,
418
                     late: late,
419
+                    absent: absent,
393
                     benched: false,
420
                     benched: false,
394
                     memo: memo
421
                     memo: memo
395
                 })
422
                 })
396
         }
423
         }
397
 
424
 
398
         await this.notifyRaid(raid)
425
         await this.notifyRaid(raid)
399
-        
426
+
400
         return await this.admin
427
         return await this.admin
401
             .knex('signups')
428
             .knex('signups')
402
             .select('*')
429
             .select('*')
407
             .first()
434
             .first()
408
     }
435
     }
409
 
436
 
437
+    cancelRaid = async (raid: Raid) => {
438
+        const data = await this.getRaidData(raid)
439
+        const participants = Object.values(data.participants).flat()
440
+        await Promise.all(
441
+            participants.map(async p => await this.adminUnsign({...p, id: p.characterid}, raid))
442
+        )
443
+        await this.admin.knex('raids').where({id: raid.id}).del()
444
+        await this.notifyRaids()
445
+    }
446
+
410
     unsign = async (usertoken: string, character: Character, raid: Raid) => {
447
     unsign = async (usertoken: string, character: Character, raid: Raid) => {
411
         const maybeUserRecord = this.userManager.getUserRecordByToken(usertoken)
448
         const maybeUserRecord = this.userManager.getUserRecordByToken(usertoken)
412
         if (!maybeUserRecord || maybeUserRecord.user.id != character.userid) {
449
         if (!maybeUserRecord || maybeUserRecord.user.id != character.userid) {
417
     }
454
     }
418
 
455
 
419
     adminUnsign = async (character: Character, raid: Raid) => {
456
     adminUnsign = async (character: Character, raid: Raid) => {
420
-
421
         const user = await this.characterManager.getUserOfCharacter(character)
457
         const user = await this.characterManager.getUserOfCharacter(character)
422
         const tokens = await this.itemManager.getTokens(character, [raid.tier], true)
458
         const tokens = await this.itemManager.getTokens(character, [raid.tier], true)
423
 
459
 
424
         //check if token has to be deleted
460
         //check if token has to be deleted
425
         if (tokens) {
461
         if (tokens) {
426
-            Promise.all(
462
+            await Promise.all(
427
                 tokens.map(async token => {
463
                 tokens.map(async token => {
428
                     await this.userManager.incrementCurrency(user, raid.tier, 1)
464
                     await this.userManager.incrementCurrency(user, raid.tier, 1)
429
                     const prio = await this.itemManager.calculatePriorities(token.itemname, character)
465
                     const prio = await this.itemManager.calculatePriorities(token.itemname, character)
430
-                    if (token.level <= prio + 1) {
466
+                    if (token.level <= prio + 2) {
431
                         await this.admin
467
                         await this.admin
432
                             .knex(raid.tier + 'tokens')
468
                             .knex(raid.tier + 'tokens')
433
                             .where({
469
                             .where({
442
                                 itemname: token.itemname
478
                                 itemname: token.itemname
443
                             }).update({
479
                             }).update({
444
                                 signupid: null,
480
                                 signupid: null,
445
-                                level: token.level - 1
481
+                                level: token.level - 2
446
                             })
482
                             })
447
                     }
483
                     }
448
                 })
484
                 })
459
         await this.notifyRaid(raid)
495
         await this.notifyRaid(raid)
460
     }
496
     }
461
 
497
 
462
-    setBenched = async (signup: Signup): Promise<void> => {
498
+    updateSignup = async (signup: Signup): Promise<void> => {
463
         await this.admin.knex('signups')
499
         await this.admin.knex('signups')
464
             .where({
500
             .where({
465
                 raidid: signup.raidid,
501
                 raidid: signup.raidid,
466
                 characterid: signup.characterid
502
                 characterid: signup.characterid
467
             })
503
             })
468
             .update(signup)
504
             .update(signup)
469
-    
505
+
470
         await this.notifyRaid({ id: signup.raidid })
506
         await this.notifyRaid({ id: signup.raidid })
471
     }
507
     }
472
 }
508
 }

+ 24
- 25
src/backend/Components/User/UserManager.ts View File

53
     userLogins: { [username in string]: UserRecord } = {}
53
     userLogins: { [username in string]: UserRecord } = {}
54
     allowed: string[] = []
54
     allowed: string[] = []
55
 
55
 
56
-    exportRPCs = () => [
56
+    RPCs = () => [
57
         this.login,
57
         this.login,
58
         this.logout,
58
         this.logout,
59
         this.getAuth,
59
         this.getAuth,
63
         this.changePassword
63
         this.changePassword
64
     ]
64
     ]
65
 
65
 
66
-    exportRPCFeatures = () => [
66
+    RPCFeatures = () => [
67
         {
67
         {
68
             name: 'manageUser' as 'manageUser',
68
             name: 'manageUser' as 'manageUser',
69
-            exportRPCs: () => [
69
+            RPCs: () => [
70
                 this.adminLogout,
70
                 this.adminLogout,
71
                 this.changeRank,
71
                 this.changeRank,
72
                 this.adminChangePassword
72
                 this.adminChangePassword
73
             ]
73
             ]
74
         }, {
74
         }, {
75
             name: 'modifyPermissions' as 'modifyPermissions',
75
             name: 'modifyPermissions' as 'modifyPermissions',
76
-            exportRPCs: () => [
76
+            RPCs: () => [
77
                 this.getPermissions,
77
                 this.getPermissions,
78
                 this.setPermission,
78
                 this.setPermission,
79
             ]
79
             ]
80
         }, {
80
         }, {
81
             name: 'softreserveCurrency' as 'softreserveCurrency',
81
             name: 'softreserveCurrency' as 'softreserveCurrency',
82
-            exportRPCs: () => [
82
+            RPCs: () => [
83
                 this.incrementCurrency,
83
                 this.incrementCurrency,
84
                 this.decrementCurrency,
84
                 this.decrementCurrency,
85
                 this.setCurrency
85
                 this.setCurrency
137
         getLogger('UserManager#initialize').debug('setting up permissions')
137
         getLogger('UserManager#initialize').debug('setting up permissions')
138
 
138
 
139
         await Promise.all(
139
         await Promise.all(
140
-            [this, ...this.exporters].flatMap(exp => exp.exportRPCFeatures().map(async (feature) => {
140
+            [this, ...this.exporters].flatMap(exp => exp.RPCFeatures().map(async (feature) => {
141
                 try {
141
                 try {
142
                     await this.admin.knex.insert({ rpcname: feature.name }).into('rpcpermissions')
142
                     await this.admin.knex.insert({ rpcname: feature.name }).into('rpcpermissions')
143
                 } catch (e) {
143
                 } catch (e) {
149
             server: rankServer,
149
             server: rankServer,
150
             port: 20001
150
             port: 20001
151
         }
151
         }
152
-        setInterval(this.checkExpiredSessions, 600_000)
152
+        //setInterval(this.checkExpiredSessions, 600_000)
153
     }
153
     }
154
 
154
 
155
     stop = async () => {
155
     stop = async () => {
156
         Object.values(this.userLogins).forEach(x => {
156
         Object.values(this.userLogins).forEach(x => {
157
-            Object.values(x.connections).forEach(c => c.destroy())
157
+            Object.values(x.connections).forEach(c => c.close())
158
         })
158
         })
159
 
159
 
160
         try {
160
         try {
161
-            return this.rankServer.server.destroy()
161
+            return this.rankServer.server.close()
162
         } catch (e) {
162
         } catch (e) {
163
             getLogger('UserManager#stop').debug(String(e))
163
             getLogger('UserManager#stop').debug(String(e))
164
         }
164
         }
200
             return false
200
             return false
201
         }
201
         }
202
 
202
 
203
-        this.userLogins[data.user.username].connections[socket.port] = socket
203
+        this.userLogins[data.user.username].connections[socket.id] = socket
204
         //getLogger('UserManager#checkConnection').debug(this.userLogins, this.allowed);
204
         //getLogger('UserManager#checkConnection').debug(this.userLogins, this.allowed);
205
         
205
         
206
         return true
206
         return true
376
 
376
 
377
     startRankServer = async (port: number): Promise<RPCServer<FrontcraftFeatureIfc>> => {
377
     startRankServer = async (port: number): Promise<RPCServer<FrontcraftFeatureIfc>> => {
378
         let rpcs = [
378
         let rpcs = [
379
-            ...this.exportRPCFeatures(),
380
-            ...this.exporters.flatMap((exp) => exp.exportRPCFeatures())
379
+            ...this.RPCFeatures(),
380
+            ...this.exporters.flatMap((exp) => exp.RPCFeatures())
381
         ]
381
         ]
382
-        let rpcServer = new RPCServer<FrontcraftFeatureIfc>(port, rpcs, {
382
+        let rpcServer = new RPCServer<FrontcraftFeatureIfc>(rpcs, {
383
             accessFilter: async (sesame, exporter) => {
383
             accessFilter: async (sesame, exporter) => {
384
                 const record = this.getUserRecordByToken(sesame!)
384
                 const record = this.getUserRecordByToken(sesame!)
385
                 if (!record) return false
385
                 if (!record) return false
386
                 return await this.getPermission(exporter.name, record.user.rank)
386
                 return await this.getPermission(exporter.name, record.user.rank)
387
             },
387
             },
388
             closeHandler: (socket) => {
388
             closeHandler: (socket) => {
389
-                Object.values(this.userLogins).forEach(login => delete login.connections[socket.port])
390
-                getLogger('UserManager#closeHandler').debug(this.userLogins, this.allowed)
389
+                Object.values(this.userLogins).forEach(login => delete login.connections[socket.id])
390
+                //getLogger('UserManager#closeHandler').debug(this.userLogins, this.allowed)
391
             },
391
             },
392
             connectionHandler: (socket) => {
392
             connectionHandler: (socket) => {
393
                 this.checkConnection(socket, 10).then(res => {
393
                 this.checkConnection(socket, 10).then(res => {
394
                     if (!res) {
394
                     if (!res) {
395
-                        getLogger('UserManager#connectionHandler').debug("Connection on "+socket.port+" failed to authenticate")
396
-                        socket.destroy();
395
+                        getLogger('UserManager#connectionHandler').debug("Connection "+socket.id+" failed to authenticate")
396
+                        socket.close();
397
                     }
397
                     }
398
                 }).catch((e) => {
398
                 }).catch((e) => {
399
                     getLogger('UserManager#connectionHandler').debug(String(e))
399
                     getLogger('UserManager#connectionHandler').debug(String(e))
400
-                    socket.destroy();
400
+                    socket.close();
401
                 })
401
                 })
402
             },
402
             },
403
             errorHandler: (socket, e, rpcName, args) => {
403
             errorHandler: (socket, e, rpcName, args) => {
405
                 throw(new Error("RPC failed"))
405
                 throw(new Error("RPC failed"))
406
             },
406
             },
407
             sesame: (sesame) => this.checkToken(sesame),
407
             sesame: (sesame) => this.checkToken(sesame),
408
-            visibility: '0.0.0.0'
409
-        })
408
+        }).listen(port)
410
 
409
 
411
         return rpcServer
410
         return rpcServer
412
     }
411
     }
451
         return usr[tier]!
450
         return usr[tier]!
452
     }
451
     }
453
 
452
 
454
-    decrementCurrency = async (user: User, tier?: Tiers, value = 1) => {
455
-        if (!tier || value < 1) return
453
+    decrementCurrency = async (user: User, tier: Tiers, value = 1) => {
454
+        if (value < 1) return
456
 
455
 
457
         const usr: User = await this.admin
456
         const usr: User = await this.admin
458
             .knex('users')
457
             .knex('users')
460
             .select('*')
459
             .select('*')
461
             .first()
460
             .first()
462
 
461
 
463
-        if (!usr || usr[tier]! <= 0) return
462
+        if (!usr || usr[tier]!-value < 0) return
464
 
463
 
465
         await this.admin
464
         await this.admin
466
             .knex('users')
465
             .knex('users')
476
             .increment(tier, value)
475
             .increment(tier, value)
477
     }
476
     }
478
 
477
 
479
-    setCurrency = async (user: User, tier?: Tiers, value = 0) => {
480
-        if (!tier || value < 0) return
478
+    setCurrency = async (user: User, tier: Tiers, value = 0) => {
479
+        if (value < 0) return
481
         await this.admin
480
         await this.admin
482
             .knex('users')
481
             .knex('users')
483
             .where('id', '=', user.id)
482
             .where('id', '=', user.id)

+ 2
- 2
src/backend/Types/FrontworkComponent.ts View File

14
 {
14
 {
15
     name: Name;
15
     name: Name;
16
 
16
 
17
-    exportRPCFeatures(): RPCExporter<FeatureIfc, FeatureName>[] 
18
-    exportRPCs(): RPCDefinitions<Ifc>[Name]
17
+    RPCFeatures(): RPCExporter<FeatureIfc, FeatureName>[] 
18
+    RPCs(): RPCDefinitions<Ifc>[Name]
19
     getTableDefinitions(): TableDefiniton[] 
19
     getTableDefinitions(): TableDefiniton[] 
20
 
20
 
21
     initialize?(): Promise<any>
21
     initialize?(): Promise<any>

+ 417
- 281
src/backend/Types/Items.ts View File

1
-export type Tiers =  "MC" | 'BWL' | 'ZG' | 'AQ20' | 'AQ40' | 'Naxx'
2
-export const _Tiers:Tiers[] = ["MC", 'BWL', 'ZG', 'AQ20', 'AQ40', 'Naxx']
1
+export type Tiers = "MC" | 'BWL' | 'ZG' | 'AQ20' | 'AQ40' | 'Naxx'
2
+export const _Tiers: Tiers[] = ["MC", 'BWL', 'ZG', 'AQ20', 'AQ40', 'Naxx']
3
 
3
 
4
 export const T1 = [
4
 export const T1 = [
5
-"Robe of Volatile Power",
6
-"Salamander Scale Pants",
7
-"Heavy Dark Iron Ring",
8
-"Ring of Spell Power",
9
-"Sorcerous Dagger",
10
-"Wristguards of Stability",
11
-"Helm of the Lifegiver",
12
-"Fire Runed Grimoire",
13
-"Crimson Shocker",
14
-"Mana Igniting Cord",
15
-"Quick Strike Ring",
16
-"Seal of the Archmagus",
17
-"Talisman of Ephemeral Power",
18
-"Flameguard Gauntlets",
19
-"Magma Tempered Boots",
20
-"Obsidian Edged Blade",
21
-"Aged Core Leather Gloves",
22
-"Sabatons of the Flamewalker",
23
-"Striker's Mark",
24
-"Medallion of Steadfast Might",
25
-"Earthshaker",
26
-"Brutality Blade",
27
-"Aurastone Hammer",
28
-"Gutgore Ripper",
29
-"Drillborer Disk",
30
-"Azuresong Mageblade",
31
-"Staff of Dominance",
32
-"Blastershot Launcher",
33
-"The Eye of Divinity",
34
-"Ancient Petrified Leaf",
35
-"Finkle's Lava Dredger",
36
-"Core Hound Tooth",
37
-"Core Forged Greaves",
38
-"Gloves of the Hypnotic Flame",
39
-"Sash of Whispered Secrets",
40
-"Wild Growth Spaulders",
41
-"Fireproof Cloak",
42
-"Wristguards of True Flight",
43
-"Fireguard Shoulders",
44
-"Cauterizing Band",
45
-"Onslaught Girdle",
46
-"Perdition's Blade",
47
-"Cloak of the Shrouded Mists",
48
-"Band of Accuria",
49
-"Crown of Destruction",
50
-"Choker of the Fire Lord",
51
-"Band of Sulfuras",
52
-"Dragon's Blood Cape",
53
-"Malistar's Defender",
54
-"Spinal Reaper",
55
-"Bonereaver's Edge",
56
-"Shard of the Flame",
57
-"Essence of the Pure Flame",
58
-"Eye of Sulfuras",
59
-"Deathbringer",
60
-"Vis'kag the Bloodletter",
61
-"Sapphiron Drape",
62
-"Ancient Cornerstone Grimoire",
63
-"Eskhandar's Collar",
64
-"Ring of Binding",
65
-"Shard of the Scale",
66
-"Head of Onyxia",
67
-"Bindings of the Windseeker",
68
-"Cenarion Belt",
69
-"Cenarion Boots",
70
-"Cenarion Bracers",
71
-"Cenarion Vestments",
72
-"Cenarion Helm",
73
-"Cenarion Leggings",
74
-"Cenarion Spaulders",
75
-"Giantstalker's Belt",
76
-"Giantstalker's Boots",
77
-"Giantstalker's Bracers",
78
-"Giantstalker's Breastplate",
79
-"Giantstalker's Epaulets",
80
-"Giantstalker's Gloves",
81
-"Giantstalker's Helmet",
82
-"Giantstalker's Leggings",
83
-"Arcanist Belt",
84
-"Arcanist Bindings",
85
-"Arcanist Crown",
86
-"Arcanist Boots",
87
-"Arcanist Gloves",
88
-"Arcanist Leggings",
89
-"Arcanist Mantle",
90
-"Arcanist Robes",
91
-"Lawbringer Belt",
92
-"Lawbringer Boots",
93
-"Lawbringer Bracers",
94
-"Lawbringer Chestguard",
95
-"Lawbringer Gauntlets",
96
-"Lawbringer Helm",
97
-"Lawbringer Legplates",
98
-"Lawbringer Spaulders",
99
-"Boots of Prophecy",
100
-"Circlet of Prophecy",
101
-"Girdle of Prophecy",
102
-"Gloves of Prophecy",
103
-"Pants of Prophecy",
104
-"Mantle of Prophecy",
105
-"Robes of Prophecy",
106
-"Vambraces of Prophecy",
107
-"Nightslayer Belt",
108
-"Nightslayer Bracelets",
109
-"Nightslayer Chestpiece",
110
-"Nightslayer Cover",
111
-"Nightslayer Gloves",
112
-"Nightslayer Pants",
113
-"Nightslayer Shoulder Pads",
114
-"Felheart Belt",
115
-"Felheart Bracers",
116
-"Felheart Gloves",
117
-"Felheart Pants",
118
-"Felheart Robes",
119
-"Felheart Shoulder Pads",
120
-"Felheart Horns",
121
-"Belt of Might",
122
-"Bracers of Might",
123
-"Breastplate of Might",
124
-"Gauntlets of Might",
125
-"Helm of Might",
126
-"Legplates of Might",
127
-"Pauldrons of Might",
128
-"Sabatons of Might",
129
-"Earthfury Belt",
130
-"Earthfury Boots",
131
-"Earthfury Bracers",
132
-"Earthfury Vestments",
133
-"Earthfury Epaulets",
134
-"Earthfury Gauntlets",
135
-"Earthfury Helmet",
136
-"Earthfury Legguards",
137
-"Stormrage Cover",
138
-"Stormrage Legguards",
139
-"Dragonstalker's Helm",
140
-"Dragonstalker's Legguards",
141
-"Netherwind Crown",
142
-"Netherwind Pants",
143
-"Judgement Crown",
144
-"Judgement Legplates",
145
-"Halo of Transcendence",
146
-"Leggings of Transcendence",
147
-"Bloodfang Hood",
148
-"Bloodfang Pants",
149
-"Helmet of Ten Storms",
150
-"Nemesis Skullcap",
151
-"Nemesis Leggings",
152
-"Helm of Wrath",
153
-"Legplates of Wrath",
5
+    "Robe of Volatile Power",
6
+    "Salamander Scale Pants",
7
+    "Heavy Dark Iron Ring",
8
+    "Ring of Spell Power",
9
+    "Sorcerous Dagger",
10
+    "Wristguards of Stability",
11
+    "Helm of the Lifegiver",
12
+    "Fire Runed Grimoire",
13
+    "Crimson Shocker",
14
+    "Mana Igniting Cord",
15
+    "Quick Strike Ring",
16
+    "Seal of the Archmagus",
17
+    "Talisman of Ephemeral Power",
18
+    "Flameguard Gauntlets",
19
+    "Magma Tempered Boots",
20
+    "Obsidian Edged Blade",
21
+    "Aged Core Leather Gloves",
22
+    "Sabatons of the Flamewalker",
23
+    "Striker's Mark",
24
+    "Medallion of Steadfast Might",
25
+    "Earthshaker",
26
+    "Brutality Blade",
27
+    "Aurastone Hammer",
28
+    "Gutgore Ripper",
29
+    "Drillborer Disk",
30
+    "Azuresong Mageblade",
31
+    "Staff of Dominance",
32
+    "Blastershot Launcher",
33
+    "The Eye of Divinity",
34
+    "Ancient Petrified Leaf",
35
+    "Finkle's Lava Dredger",
36
+    "Core Hound Tooth",
37
+    "Core Forged Greaves",
38
+    "Gloves of the Hypnotic Flame",
39
+    "Sash of Whispered Secrets",
40
+    "Wild Growth Spaulders",
41
+    "Fireproof Cloak",
42
+    "Wristguards of True Flight",
43
+    "Fireguard Shoulders",
44
+    "Cauterizing Band",
45
+    "Onslaught Girdle",
46
+    "Perdition's Blade",
47
+    "Cloak of the Shrouded Mists",
48
+    "Band of Accuria",
49
+    "Crown of Destruction",
50
+    "Choker of the Fire Lord",
51
+    "Band of Sulfuras",
52
+    "Dragon's Blood Cape",
53
+    "Malistar's Defender",
54
+    "Spinal Reaper",
55
+    "Bonereaver's Edge",
56
+    "Shard of the Flame",
57
+    "Essence of the Pure Flame",
58
+    "Eye of Sulfuras",
59
+    "Deathbringer",
60
+    "Vis'kag the Bloodletter",
61
+    "Sapphiron Drape",
62
+    "Ancient Cornerstone Grimoire",
63
+    "Eskhandar's Collar",
64
+    "Ring of Binding",
65
+    "Shard of the Scale",
66
+    "Head of Onyxia",
67
+    "Bindings of the Windseeker",
68
+    "Cenarion Belt",
69
+    "Cenarion Boots",
70
+    "Cenarion Bracers",
71
+    "Cenarion Vestments",
72
+    "Cenarion Helm",
73
+    "Cenarion Leggings",
74
+    "Cenarion Spaulders",
75
+    "Giantstalker's Belt",
76
+    "Giantstalker's Boots",
77
+    "Giantstalker's Bracers",
78
+    "Giantstalker's Breastplate",
79
+    "Giantstalker's Epaulets",
80
+    "Giantstalker's Gloves",
81
+    "Giantstalker's Helmet",
82
+    "Giantstalker's Leggings",
83
+    "Arcanist Belt",
84
+    "Arcanist Bindings",
85
+    "Arcanist Crown",
86
+    "Arcanist Boots",
87
+    "Arcanist Gloves",
88
+    "Arcanist Leggings",
89
+    "Arcanist Mantle",
90
+    "Arcanist Robes",
91
+    "Lawbringer Belt",
92
+    "Lawbringer Boots",
93
+    "Lawbringer Bracers",
94
+    "Lawbringer Chestguard",
95
+    "Lawbringer Gauntlets",
96
+    "Lawbringer Helm",
97
+    "Lawbringer Legplates",
98
+    "Lawbringer Spaulders",
99
+    "Boots of Prophecy",
100
+    "Circlet of Prophecy",
101
+    "Girdle of Prophecy",
102
+    "Gloves of Prophecy",
103
+    "Pants of Prophecy",
104
+    "Mantle of Prophecy",
105
+    "Robes of Prophecy",
106
+    "Vambraces of Prophecy",
107
+    "Nightslayer Belt",
108
+    "Nightslayer Bracelets",
109
+    "Nightslayer Chestpiece",
110
+    "Nightslayer Cover",
111
+    "Nightslayer Gloves",
112
+    "Nightslayer Pants",
113
+    "Nightslayer Shoulder Pads",
114
+    "Felheart Belt",
115
+    "Felheart Bracers",
116
+    "Felheart Gloves",
117
+    "Felheart Pants",
118
+    "Felheart Robes",
119
+    "Felheart Shoulder Pads",
120
+    "Felheart Horns",
121
+    "Belt of Might",
122
+    "Bracers of Might",
123
+    "Breastplate of Might",
124
+    "Gauntlets of Might",
125
+    "Helm of Might",
126
+    "Legplates of Might",
127
+    "Pauldrons of Might",
128
+    "Sabatons of Might",
129
+    "Earthfury Belt",
130
+    "Earthfury Boots",
131
+    "Earthfury Bracers",
132
+    "Earthfury Vestments",
133
+    "Earthfury Epaulets",
134
+    "Earthfury Gauntlets",
135
+    "Earthfury Helmet",
136
+    "Earthfury Legguards",
137
+    "Stormrage Cover",
138
+    "Stormrage Legguards",
139
+    "Dragonstalker's Helm",
140
+    "Dragonstalker's Legguards",
141
+    "Netherwind Crown",
142
+    "Netherwind Pants",
143
+    "Judgement Crown",
144
+    "Judgement Legplates",
145
+    "Halo of Transcendence",
146
+    "Leggings of Transcendence",
147
+    "Bloodfang Hood",
148
+    "Bloodfang Pants",
149
+    "Helmet of Ten Storms",
150
+    "Nemesis Skullcap",
151
+    "Nemesis Leggings",
152
+    "Helm of Wrath",
153
+    "Legplates of Wrath",
154
 ]
154
 ]
155
 
155
 
156
-export const T2:string[] = [
157
-"Gloves of Rapid Evolution",
158
-"Mantle of the Blackwing Cabal",
159
-"Spineshatter",
160
-"The Untamed Blade",
161
-"Pendant of the Fallen Dragon",
162
-"Helm of Endless Rage",
163
-"Dragonfang Blade",
164
-"Red Dragonscale Protector",
165
-"Black Brood Pauldrons",
166
-"Bracers of Arcane Accuracy",
167
-"Heartstriker",
168
-"Maladath, Runed Blade of the Black Flight",
169
-"Black Ash Robe",
170
-"Firemaw's Clutch",
171
-"Claw of the Black Drake",
172
-"Cloak of Firemaw",
173
-"Legguards of the Fallen Crusader",
174
-"Taut Dragonhide Belt",
175
-"Drake Talon Pauldrons",
176
-"Rejuvenating Gem",
177
-"Drake Talon Cleaver",
178
-"Band of Forced Concentration",
179
-"Drake Fang Talisman",
180
-"Ebony Flame Gloves",
181
-"Malfurion's Blessed Bulwark",
182
-"Dragonbreath Hand Cannon",
183
-"Shadow Wing Focus Staff",
184
-"Shroud of Pure Thought",
185
-"Circle of Applied Force",
186
-"Emberweave Leggings",
187
-"Styleen's Impeding Scarab",
188
-"Dragon's Touch",
189
-"Herald of Woe",
190
-"Taut Dragonhide Shoulderpads",
191
-"Chromatic Boots",
192
-"Taut Dragonhide Gloves",
193
-"Shimmering Geta",
194
-"Ring of Blackrock",
195
-"Elementium Threaded Cloak",
196
-"Angelista's Grasp",
197
-"Girdle of the Fallen Crusader",
198
-"Empowered Leggings",
199
-"Chromatically Tempered Sword",
200
-"Claw of Chromaggus",
201
-"Primalist's Linked Waistguard",
202
-"Ashjre'thul, Crossbow of Smiting",
203
-"Elementium Reinforced Bulwark",
204
-"Head of Nefarian",
205
-"Cloak of the Brood Lord",
206
-"Boots of the Shadow Flame",
207
-"Therazane's Link",
208
-"Archimtiros' Ring of Reckoning",
209
-"Neltharion's Tear",
210
-"Pure Elementium Band",
211
-"Mish'undare, Circlet of the Mind Flayer",
212
-"Prestor's Talisman of Connivery",
213
-"Staff of the Shadow Flame",
214
-"Ashkandi, Greatsword of the Brotherhood",
215
-"Crul'shorukh, Edge of Chaos",
216
-"Lok'amir il Romathis",
217
-"Boots of Pure Thought",
218
-"Cloak of Draconic Might",
219
-"Draconic Maul",
220
-"Doom's Edge",
221
-"Essence Gatherer",
222
-"Band of Dark Dominion",
223
-"Draconic Avenger",
224
-"Interlaced Shadow Jerkin",
225
-"Ringo's Blizzard Boots",
226
-"Scrolls of Blinding Light",
227
-"Rune of Metamorphosis",
228
-"Natural Alignment Crystal",
229
-"Mind Quickening Gem",
230
-"Lifegiving Gem",
231
-"Arcane Infused Gem",
232
-"The Black Book",
233
-"Venomous Totem",
234
-"Nemesis Spaulders",
235
-"Nemesis Robes",
236
-"Nemesis Bracers",
237
-"Nemesis Gloves",
238
-"Nemesis Belt",
239
-"Nemesis Boots",
240
-"Netherwind Mantle",
241
-"Netherwind Robes",
242
-"Netherwind Bindings",
243
-"Netherwind Gloves",
244
-"Netherwind Belt",
245
-"Netherwind Boots",
246
-"Bloodfang Spaulders",
247
-"Bloodfang Chestpiece",
248
-"Bloodfang Bracers",
249
-"Bloodfang Gloves",
250
-"Bloodfang Belt",
251
-"Bloodfang Boots",
252
-"Stormrage Pauldrons",
253
-"Stormrage Chestguard",
254
-"Stormrage Bracers",
255
-"Stormrage Handguards",
256
-"Stormrage Belt",
257
-"Stormrage Boots",
258
-"Dragonstalker's Spaulders",
259
-"Dragonstalker's Breastplate",
260
-"Dragonstalker's Bracers",
261
-"Dragonstalker's Gauntlets",
262
-"Dragonstalker's Belt",
263
-"Dragonstalker's Greaves",
264
-"Judgement Spaulders",
265
-"Judgement Breastplate",
266
-"Judgement Bindings",
267
-"Judgement Gauntlets",
268
-"Judgement Belt",
269
-"Judgement Sabatons",
270
-"Pauldrons of Transcendence",
271
-"Robes of Transcendence",
272
-"Bindings of Transcendence",
273
-"Handguards of Transcendence",
274
-"Belt of Transcendence",
275
-"Boots of Transcendence",
276
-"Pauldrons of Wrath",
277
-"Breastplate of Wrath",
278
-"Bracelets of Wrath",
279
-"Gauntlets of Wrath",
280
-"Waistband of Wrath",
281
-"Sabatons of Wrath"
156
+export const T2: string[] = [
157
+    "Gloves of Rapid Evolution",
158
+    "Mantle of the Blackwing Cabal",
159
+    "Spineshatter",
160
+    "The Untamed Blade",
161
+    "Pendant of the Fallen Dragon",
162
+    "Helm of Endless Rage",
163
+    "Dragonfang Blade",
164
+    "Red Dragonscale Protector",
165
+    "Black Brood Pauldrons",
166
+    "Bracers of Arcane Accuracy",
167
+    "Heartstriker",
168
+    "Maladath, Runed Blade of the Black Flight",
169
+    "Black Ash Robe",
170
+    "Firemaw's Clutch",
171
+    "Claw of the Black Drake",
172
+    "Cloak of Firemaw",
173
+    "Legguards of the Fallen Crusader",
174
+    "Taut Dragonhide Belt",
175
+    "Drake Talon Pauldrons",
176
+    "Rejuvenating Gem",
177
+    "Drake Talon Cleaver",
178
+    "Band of Forced Concentration",
179
+    "Drake Fang Talisman",
180
+    "Ebony Flame Gloves",
181
+    "Malfurion's Blessed Bulwark",
182
+    "Dragonbreath Hand Cannon",
183
+    "Shadow Wing Focus Staff",
184
+    "Shroud of Pure Thought",
185
+    "Circle of Applied Force",
186
+    "Emberweave Leggings",
187
+    "Styleen's Impeding Scarab",
188
+    "Dragon's Touch",
189
+    "Herald of Woe",
190
+    "Taut Dragonhide Shoulderpads",
191
+    "Chromatic Boots",
192
+    "Taut Dragonhide Gloves",
193
+    "Shimmering Geta",
194
+    "Ring of Blackrock",
195
+    "Elementium Threaded Cloak",
196
+    "Angelista's Grasp",
197
+    "Girdle of the Fallen Crusader",
198
+    "Empowered Leggings",
199
+    "Chromatically Tempered Sword",
200
+    "Claw of Chromaggus",
201
+    "Primalist's Linked Waistguard",
202
+    "Ashjre'thul, Crossbow of Smiting",
203
+    "Elementium Reinforced Bulwark",
204
+    "Head of Nefarian",
205
+    "Cloak of the Brood Lord",
206
+    "Boots of the Shadow Flame",
207
+    "Therazane's Link",
208
+    "Archimtiros' Ring of Reckoning",
209
+    "Neltharion's Tear",
210
+    "Pure Elementium Band",
211
+    "Mish'undare, Circlet of the Mind Flayer",
212
+    "Prestor's Talisman of Connivery",
213
+    "Staff of the Shadow Flame",
214
+    "Ashkandi, Greatsword of the Brotherhood",
215
+    "Crul'shorukh, Edge of Chaos",
216
+    "Lok'amir il Romathis",
217
+    "Boots of Pure Thought",
218
+    "Cloak of Draconic Might",
219
+    "Draconic Maul",
220
+    "Doom's Edge",
221
+    "Essence Gatherer",
222
+    "Band of Dark Dominion",
223
+    "Draconic Avenger",
224
+    "Interlaced Shadow Jerkin",
225
+    "Ringo's Blizzard Boots",
226
+    "Scrolls of Blinding Light",
227
+    "Rune of Metamorphosis",
228
+    "Natural Alignment Crystal",
229
+    "Mind Quickening Gem",
230
+    "Lifegiving Gem",
231
+    "Arcane Infused Gem",
232
+    "The Black Book",
233
+    "Venomous Totem",
234
+    "Nemesis Spaulders",
235
+    "Nemesis Robes",
236
+    "Nemesis Bracers",
237
+    "Nemesis Gloves",
238
+    "Nemesis Belt",
239
+    "Nemesis Boots",
240
+    "Netherwind Mantle",
241
+    "Netherwind Robes",
242
+    "Netherwind Bindings",
243
+    "Netherwind Gloves",
244
+    "Netherwind Belt",
245
+    "Netherwind Boots",
246
+    "Bloodfang Spaulders",
247
+    "Bloodfang Chestpiece",
248
+    "Bloodfang Bracers",
249
+    "Bloodfang Gloves",
250
+    "Bloodfang Belt",
251
+    "Bloodfang Boots",
252
+    "Stormrage Pauldrons",
253
+    "Stormrage Chestguard",
254
+    "Stormrage Bracers",
255
+    "Stormrage Handguards",
256
+    "Stormrage Belt",
257
+    "Stormrage Boots",
258
+    "Dragonstalker's Spaulders",
259
+    "Dragonstalker's Breastplate",
260
+    "Dragonstalker's Bracers",
261
+    "Dragonstalker's Gauntlets",
262
+    "Dragonstalker's Belt",
263
+    "Dragonstalker's Greaves",
264
+    "Judgement Spaulders",
265
+    "Judgement Breastplate",
266
+    "Judgement Bindings",
267
+    "Judgement Gauntlets",
268
+    "Judgement Belt",
269
+    "Judgement Sabatons",
270
+    "Pauldrons of Transcendence",
271
+    "Robes of Transcendence",
272
+    "Bindings of Transcendence",
273
+    "Handguards of Transcendence",
274
+    "Belt of Transcendence",
275
+    "Boots of Transcendence",
276
+    "Pauldrons of Wrath",
277
+    "Breastplate of Wrath",
278
+    "Bracelets of Wrath",
279
+    "Gauntlets of Wrath",
280
+    "Waistband of Wrath",
281
+    "Sabatons of Wrath"
282
+]
283
+
284
+const AQ40 = [
285
+    //Tokens
286
+    "Qiraji Bindings of Command",
287
+    "Qiraji Bindings of Dominance",
288
+    "Vek'lor's Diadem",
289
+    "Vek'nilash's Circlet",
290
+    "Ouro's Intact Hide",
291
+    "Skin of the Great Sandworm",
292
+    "Carapace of the Old God",
293
+    "Husk of the Old God",
294
+    "Imperial Qiraji Armaments",
295
+    "Imperial Qiraji Regalia",
296
+
297
+    //Prophet Skeram
298
+    "Beetle Scaled Wristguards",
299
+    "Boots of the Unwavering Will",
300
+    "Breastplate of Annihilation",
301
+    "Cloak of Concentrated Hatred",
302
+    "Leggings of Immersion",
303
+    "Barrage Shoulders",
304
+    "Pendant of the Qiraji Guardian",
305
+    "Ring of Swarming Thought",
306
+    "Amulet of Foul Warding",
307
+    "Boots of the Redeemed Prophecy",
308
+    "Hammer of Ji'zhi",
309
+    "Staff of the Qiraji Prophets",
310
+    "Boots of the Fallen Prophet",
311
+
312
+    //Battleguard Sartura
313
+    "Robes of the Battleguard",
314
+    "Thick Qirajihide Belt",
315
+    "Creeping Vine Helm",
316
+    "Gauntlets of Steadfast Determination",
317
+    "Gloves of Enforcement",
318
+    "Leggings of the Festering Swarm",
319
+    "Necklace of Purity",
320
+    "Recomposed Boots",
321
+    "Badge of the Swarmguard",
322
+    "Legplates of Blazing Light",
323
+    "Sartura's Might",
324
+    "Scaled Leggings of Qiraji Fury",
325
+    "Silithid Claw",
326
+
327
+    //Fankriss the Unyielding
328
+    "Hive Tunneler's Boots",
329
+    "Pauldrons of the Unrelenting",
330
+    "Robes of the Guardian Saint",
331
+    "Barbed Choker",
332
+    "Fetish of the Sand Reaver",
333
+    "Mantle of Wicked Revenge",
334
+    "Scaled Sand Reaver Leggings",
335
+    "Silithid Carapace Chestguard",
336
+    "Cloak of Untold Secrets",
337
+    "Barb of the Sand Reaver",
338
+    "Libram of Grace",
339
+    "Ancient Qiraji Ripper",
340
+    "Totem of Life",
341
+
342
+    //Princess Huhuran
343
+    "Hive Defiler Wristguards",
344
+    "Wasphide Gauntlets",
345
+    "Cloak of the Golden Hive",
346
+    "Ring of the Martyr",
347
+    "Gloves of the Messiah",
348
+    "Huhuran's Stinger",
349
+
350
+    //Twin Emperors
351
+    "Boots of Epiphany",
352
+    "Vek'lor's Gloves of Devastation",
353
+    "Royal Qiraji Belt",
354
+    "Royal Scepter of Vek'lor",
355
+    "Ring of Emperor Vek'lor",
356
+    "Gloves of the Hidden Temple",
357
+    "Amulet of Vek'nilash",
358
+    "Regenerating Belt of Vek'nilash",
359
+    "Belt of the Fallen Emperor",
360
+    "Bracelets of Royal Redemption",
361
+    "Kalimdor's Revenge",
362
+    "Grasp of the Fallen Emperor",
363
+    "Qiraji Execution Bracers",
364
+
365
+    //C'Thun
366
+    "Eye of C'Thun",
367
+    "Ring of the Godslayer",
368
+    "Eyestalk Waist Cord",
369
+    "Cloak of the Devoured",
370
+    "Gauntlets of Annihilation",
371
+    "Scepter of the False Prophet",
372
+    "Mark of C'Thun",
373
+    "Cloak of Clarity",
374
+    "Dark Storm Gauntlets",
375
+    "Grasp of the Old God",
376
+    "Belt of Never-ending Agony",
377
+    "Vanquished Tentacle of C'Thun",
378
+    "Dark Edge of Insanity",
379
+    "Death's Sting",
380
+
381
+    //Viscidus
382
+    "Gauntlets of Kalimdor",
383
+    "Gauntlets of the Righteous Champion",
384
+    "Idol of Health",
385
+    "Ring of the Qiraji Fury",
386
+    "Sharpened Silithid Femur",
387
+    "Slime-coated Leggings",
388
+    "Scarab Brooch",
389
+
390
+    //Ouro
391
+    "Don Rigoberto's Lost Hat",
392
+    "Larvae of the Great Worm",
393
+    "The Burrower's Shell",
394
+    "Wormscale Blocker",
395
+    "Burrower Bracers",
396
+    "Jom Gabbar",
397
+
398
+    //3 Bugs
399
+    "Guise of the Devourer",
400
+    "Ternary Mantle",
401
+    "Cape of the Trinity",
402
+    "Robes of the Triumvirate",
403
+    "Triad Girdle",
404
+    "Angelista's Touch",
405
+    "Vest of Swift Execution",
406
+    "Ring of the Devoured",
407
+    "Petrified Scarab",
408
+    "Wand of Qiraji Nobility",
409
+    "Angelista's Charm",
410
+    "Gloves of Ebru",
411
+    "Ooze-ridden Gauntlets",
412
+    "Boots of the Fallen Hero",
413
+    "Mantle of Phrenic Power",
414
+    "Mantle of the Desert's Fury",
415
+    "Mantle of the Desert Crusade",
416
+    "Bile-Covered Gauntlets",
417
+    "Ukko's Ring of Darkness",
282
 ]
418
 ]
283
 
419
 
284
 export const ZGMounts = [
420
 export const ZGMounts = [
285
     "Swift Zulian Tiger",
421
     "Swift Zulian Tiger",
286
     "Swift Razzashi Raptor",
422
     "Swift Razzashi Raptor",
287
     "Primal Hakkari Idol"
423
     "Primal Hakkari Idol"
288
-] 
424
+]
289
 
425
 
290
 export type AllItems = {
426
 export type AllItems = {
291
-    [tier in Tiers] : string[]
427
+    [tier in Tiers]: string[]
292
 }
428
 }
293
 
429
 
294
-export const allItems : AllItems = {
430
+export const allItems: AllItems = {
295
     MC: T1,
431
     MC: T1,
296
     BWL: T2,
432
     BWL: T2,
297
     ZG: ZGMounts,
433
     ZG: ZGMounts,
298
     AQ20: [],
434
     AQ20: [],
299
-    AQ40: [],
435
+    AQ40: AQ40,
300
     Naxx: []
436
     Naxx: []
301
 }
437
 }

+ 1
- 1
src/backend/Types/Plugin.ts View File

18
 
18
 
19
     abstract getTableDefinitions(): TableDefiniton[]
19
     abstract getTableDefinitions(): TableDefiniton[]
20
     abstract getDefaultConfig(): ConfType
20
     abstract getDefaultConfig(): ConfType
21
-    abstract exportRPCs(): RPC<any,any>[]
21
+    abstract RPCs(): RPC<any,any>[]
22
 }
22
 }

+ 1
- 1
src/backend/Types/PrivilegedRPCExporter.ts View File

6
     Name extends keyof Ifc = keyof Ifc, 
6
     Name extends keyof Ifc = keyof Ifc, 
7
     FeatureName extends keyof FeatureIfc = keyof FeatureIfc, 
7
     FeatureName extends keyof FeatureIfc = keyof FeatureIfc, 
8
 >extends RPCExporter<Ifc, Name>{
8
 >extends RPCExporter<Ifc, Name>{
9
-    exportRPCFeatures() : RPCExporter<FeatureIfc, FeatureName>[]
9
+    RPCFeatures() : RPCExporter<FeatureIfc, FeatureName>[]
10
 }
10
 }

+ 3
- 1
src/backend/Types/Types.ts View File

54
         [clazz in Class] : (Signup & Character & Spec)[] 
54
         [clazz in Class] : (Signup & Character & Spec)[] 
55
     } & {
55
     } & {
56
         late: (Signup & Character & Spec)[]
56
         late: (Signup & Character & Spec)[]
57
-        bench: (Signup & Character & Spec)[] 
57
+        bench: (Signup & Character & Spec)[]
58
+        absent: (Signup & Character & Spec)[]
58
     }
59
     }
59
     tokens: {
60
     tokens: {
60
         [itemname in string]: (Character & SRToken & Item)[]
61
         [itemname in string]: (Character & SRToken & Item)[]
163
     characterid: number
164
     characterid: number
164
     benched: boolean
165
     benched: boolean
165
     late: boolean
166
     late: boolean
167
+    absent:boolean
166
     timestamp: string
168
     timestamp: string
167
     memo?: string
169
     memo?: string
168
 }
170
 }

+ 239
- 56
src/frontend/package-lock.json View File

2645
       "integrity": "sha1-ytdV8Pxt57cPpuXgivqB70wiSN4=",
2645
       "integrity": "sha1-ytdV8Pxt57cPpuXgivqB70wiSN4=",
2646
       "dev": true
2646
       "dev": true
2647
     },
2647
     },
2648
+    "@types/engine.io": {
2649
+      "version": "3.1.4",
2650
+      "resolved": "https://registry.npmjs.org/@types/engine.io/-/engine.io-3.1.4.tgz",
2651
+      "integrity": "sha512-98rXVukLD6/ozrQ2O80NAlWDGA4INg+tqsEReWJldqyi2fulC9V7Use/n28SWgROXKm6003ycWV4gZHoF8GA6w==",
2652
+      "requires": {
2653
+        "@types/node": "*"
2654
+      }
2655
+    },
2648
     "@types/events": {
2656
     "@types/events": {
2649
       "version": "3.0.0",
2657
       "version": "3.0.0",
2650
       "resolved": "https://registry.npmjs.org/@types/events/-/events-3.0.0.tgz",
2658
       "resolved": "https://registry.npmjs.org/@types/events/-/events-3.0.0.tgz",
2705
       "dev": true
2713
       "dev": true
2706
     },
2714
     },
2707
     "@types/node": {
2715
     "@types/node": {
2708
-      "version": "6.0.90",
2709
-      "resolved": "https://registry.npmjs.org/@types/node/-/node-6.0.90.tgz",
2710
-      "integrity": "sha512-tXoGRVdi7wZX7P1VWoV9Wfk0uYDOAHdEYXAttuWgSrN76Q32wQlSrMX0Rgyv3RTEaQY2ZLQrzYHVM2e8rfo8sA==",
2711
-      "dev": true
2716
+      "version": "14.0.27",
2717
+      "resolved": "https://registry.npmjs.org/@types/node/-/node-14.0.27.tgz",
2718
+      "integrity": "sha512-kVrqXhbclHNHGu9ztnAwSncIgJv/FaxmzXJvGXNdcCpV1b8u1/Mi6z6m0vwy0LzKeXFTPLH0NzwmoJ3fNCIq0g=="
2712
     },
2719
     },
2713
     "@types/q": {
2720
     "@types/q": {
2714
       "version": "0.0.32",
2721
       "version": "0.0.32",
2722
       "integrity": "sha512-/DJGXtMuklLQef49qDsmjQofzaGU6D5To2xJZRLBNZO4GLAi30IjxLy6hHRQdycXP+IZKKXqJhYyNJ53SglJ8w==",
2729
       "integrity": "sha512-/DJGXtMuklLQef49qDsmjQofzaGU6D5To2xJZRLBNZO4GLAi30IjxLy6hHRQdycXP+IZKKXqJhYyNJ53SglJ8w==",
2723
       "dev": true
2730
       "dev": true
2724
     },
2731
     },
2732
+    "@types/socket.io": {
2733
+      "version": "2.1.10",
2734
+      "resolved": "https://registry.npmjs.org/@types/socket.io/-/socket.io-2.1.10.tgz",
2735
+      "integrity": "sha512-1fQMaDU/x2LPljEI/QI5IKl8sBYHM/zv32YYKvNrVEor7/1+MLqMqmWt8Bb8Vpf+PlIPBiTTC0BnrRx7ju3xOw==",
2736
+      "requires": {
2737
+        "@types/engine.io": "*",
2738
+        "@types/node": "*"
2739
+      }
2740
+    },
2741
+    "@types/socket.io-client": {
2742
+      "version": "1.4.33",
2743
+      "resolved": "https://registry.npmjs.org/@types/socket.io-client/-/socket.io-client-1.4.33.tgz",
2744
+      "integrity": "sha512-m4LnxkljsI9fMsjwpW5QhRpMixo2BeeLpFmg0AE+sS4H1pzAd/cs/ftTiL60FLZgfFa8PFRPx5KsHu8O0bADKQ=="
2745
+    },
2725
     "@types/source-list-map": {
2746
     "@types/source-list-map": {
2726
       "version": "0.1.2",
2747
       "version": "0.1.2",
2727
       "resolved": "https://registry.npmjs.org/@types/source-list-map/-/source-list-map-0.1.2.tgz",
2748
       "resolved": "https://registry.npmjs.org/@types/source-list-map/-/source-list-map-0.1.2.tgz",
2952
       "version": "1.3.7",
2973
       "version": "1.3.7",
2953
       "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.7.tgz",
2974
       "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.7.tgz",
2954
       "integrity": "sha512-Il80Qs2WjYlJIBNzNkK6KYqlVMTbZLXgHx2oT0pU/fjRHyEp+PEfEPY0R3WCwAGVOtauxh1hOxNgIf5bv7dQpA==",
2975
       "integrity": "sha512-Il80Qs2WjYlJIBNzNkK6KYqlVMTbZLXgHx2oT0pU/fjRHyEp+PEfEPY0R3WCwAGVOtauxh1hOxNgIf5bv7dQpA==",
2955
-      "dev": true,
2956
       "requires": {
2976
       "requires": {
2957
         "mime-types": "~2.1.24",
2977
         "mime-types": "~2.1.24",
2958
         "negotiator": "0.6.2"
2978
         "negotiator": "0.6.2"
3004
     "after": {
3024
     "after": {
3005
       "version": "0.8.2",
3025
       "version": "0.8.2",
3006
       "resolved": "https://registry.npmjs.org/after/-/after-0.8.2.tgz",
3026
       "resolved": "https://registry.npmjs.org/after/-/after-0.8.2.tgz",
3007
-      "integrity": "sha1-/ts5T58OAqqXaOcCvaI7UF+ufh8=",
3008
-      "dev": true
3027
+      "integrity": "sha1-/ts5T58OAqqXaOcCvaI7UF+ufh8="
3009
     },
3028
     },
3010
     "agent-base": {
3029
     "agent-base": {
3011
       "version": "4.3.0",
3030
       "version": "4.3.0",
3437
     "async-limiter": {
3456
     "async-limiter": {
3438
       "version": "1.0.1",
3457
       "version": "1.0.1",
3439
       "resolved": "https://registry.npmjs.org/async-limiter/-/async-limiter-1.0.1.tgz",
3458
       "resolved": "https://registry.npmjs.org/async-limiter/-/async-limiter-1.0.1.tgz",
3440
-      "integrity": "sha512-csOlWGAcRFJaI6m+F2WKdnMKr4HhdhFVBk0H/QbJFMCr+uO2kwohwXQPxw/9OCxp05r5ghVBFSyioixx3gfkNQ==",
3441
-      "dev": true
3459
+      "integrity": "sha512-csOlWGAcRFJaI6m+F2WKdnMKr4HhdhFVBk0H/QbJFMCr+uO2kwohwXQPxw/9OCxp05r5ghVBFSyioixx3gfkNQ=="
3442
     },
3460
     },
3443
     "asynckit": {
3461
     "asynckit": {
3444
       "version": "0.4.0",
3462
       "version": "0.4.0",
3683
     "backo2": {
3701
     "backo2": {
3684
       "version": "1.0.2",
3702
       "version": "1.0.2",
3685
       "resolved": "https://registry.npmjs.org/backo2/-/backo2-1.0.2.tgz",
3703
       "resolved": "https://registry.npmjs.org/backo2/-/backo2-1.0.2.tgz",
3686
-      "integrity": "sha1-MasayLEpNjRj41s+u2n038+6eUc=",
3687
-      "dev": true
3704
+      "integrity": "sha1-MasayLEpNjRj41s+u2n038+6eUc="
3688
     },
3705
     },
3689
     "balanced-match": {
3706
     "balanced-match": {
3690
       "version": "1.0.0",
3707
       "version": "1.0.0",
3749
     "base64-arraybuffer": {
3766
     "base64-arraybuffer": {
3750
       "version": "0.1.5",
3767
       "version": "0.1.5",
3751
       "resolved": "https://registry.npmjs.org/base64-arraybuffer/-/base64-arraybuffer-0.1.5.tgz",
3768
       "resolved": "https://registry.npmjs.org/base64-arraybuffer/-/base64-arraybuffer-0.1.5.tgz",
3752
-      "integrity": "sha1-c5JncZI7Whl0etZmqlzUv5xunOg=",
3753
-      "dev": true
3769
+      "integrity": "sha1-c5JncZI7Whl0etZmqlzUv5xunOg="
3754
     },
3770
     },
3755
     "base64-js": {
3771
     "base64-js": {
3756
       "version": "1.3.1",
3772
       "version": "1.3.1",
3797
       "version": "1.0.2",
3813
       "version": "1.0.2",
3798
       "resolved": "https://registry.npmjs.org/better-assert/-/better-assert-1.0.2.tgz",
3814
       "resolved": "https://registry.npmjs.org/better-assert/-/better-assert-1.0.2.tgz",
3799
       "integrity": "sha1-QIZrnhueC1W0gYlDEeaPr/rrxSI=",
3815
       "integrity": "sha1-QIZrnhueC1W0gYlDEeaPr/rrxSI=",
3800
-      "dev": true,
3801
       "requires": {
3816
       "requires": {
3802
         "callsite": "1.0.0"
3817
         "callsite": "1.0.0"
3803
       }
3818
       }
4076
         "node-releases": "^1.1.47"
4091
         "node-releases": "^1.1.47"
4077
       }
4092
       }
4078
     },
4093
     },
4079
-    "bsert": {
4080
-      "version": "0.0.10",
4081
-      "resolved": "https://registry.npmjs.org/bsert/-/bsert-0.0.10.tgz",
4082
-      "integrity": "sha512-NHNwlac+WPy4t2LoNh8pXk8uaIGH3NSaIUbTTRXGpE2WEbq0te/tDykYHkFK57YKLPjv/aGHmbqvnGeVWDz57Q=="
4083
-    },
4084
-    "bsock": {
4085
-      "version": "0.1.9",
4086
-      "resolved": "https://registry.npmjs.org/bsock/-/bsock-0.1.9.tgz",
4087
-      "integrity": "sha512-/l9Kg/c5o+n/0AqreMxh2jpzDMl1ikl4gUxT7RFNe3A3YRIyZkiREhwcjmqxiymJSRI/Qhew357xGn1SLw/xEw==",
4088
-      "requires": {
4089
-        "bsert": "~0.0.10"
4090
-      }
4091
-    },
4092
     "buffer": {
4094
     "buffer": {
4093
       "version": "4.9.2",
4095
       "version": "4.9.2",
4094
       "resolved": "https://registry.npmjs.org/buffer/-/buffer-4.9.2.tgz",
4096
       "resolved": "https://registry.npmjs.org/buffer/-/buffer-4.9.2.tgz",
4277
     "callsite": {
4279
     "callsite": {
4278
       "version": "1.0.0",
4280
       "version": "1.0.0",
4279
       "resolved": "https://registry.npmjs.org/callsite/-/callsite-1.0.0.tgz",
4281
       "resolved": "https://registry.npmjs.org/callsite/-/callsite-1.0.0.tgz",
4280
-      "integrity": "sha1-KAOY5dZkvXQDi28JBRU+borxvCA=",
4281
-      "dev": true
4282
+      "integrity": "sha1-KAOY5dZkvXQDi28JBRU+borxvCA="
4282
     },
4283
     },
4283
     "callsites": {
4284
     "callsites": {
4284
       "version": "2.0.0",
4285
       "version": "2.0.0",
4752
     "component-bind": {
4753
     "component-bind": {
4753
       "version": "1.0.0",
4754
       "version": "1.0.0",
4754
       "resolved": "https://registry.npmjs.org/component-bind/-/component-bind-1.0.0.tgz",
4755
       "resolved": "https://registry.npmjs.org/component-bind/-/component-bind-1.0.0.tgz",
4755
-      "integrity": "sha1-AMYIq33Nk4l8AAllGx06jh5zu9E=",
4756
-      "dev": true
4756
+      "integrity": "sha1-AMYIq33Nk4l8AAllGx06jh5zu9E="
4757
     },
4757
     },
4758
     "component-emitter": {
4758
     "component-emitter": {
4759
       "version": "1.3.0",
4759
       "version": "1.3.0",
4764
     "component-inherit": {
4764
     "component-inherit": {
4765
       "version": "0.0.3",
4765
       "version": "0.0.3",
4766
       "resolved": "https://registry.npmjs.org/component-inherit/-/component-inherit-0.0.3.tgz",
4766
       "resolved": "https://registry.npmjs.org/component-inherit/-/component-inherit-0.0.3.tgz",
4767
-      "integrity": "sha1-ZF/ErfWLcrZJ1crmUTVhnbJv8UM=",
4768
-      "dev": true
4767
+      "integrity": "sha1-ZF/ErfWLcrZJ1crmUTVhnbJv8UM="
4769
     },
4768
     },
4770
     "compressible": {
4769
     "compressible": {
4771
       "version": "2.0.18",
4770
       "version": "2.0.18",
9131
         }
9130
         }
9132
       }
9131
       }
9133
     },
9132
     },
9133
+    "has-binary2": {
9134
+      "version": "1.0.3",
9135
+      "resolved": "https://registry.npmjs.org/has-binary2/-/has-binary2-1.0.3.tgz",
9136
+      "integrity": "sha512-G1LWKhDSvhGeAQ8mPVQlqNcOB2sJdwATtZKl2pDKKHfpf/rYj24lkinxf69blJbnsvtqqNU+L3SL50vzZhXOnw==",
9137
+      "requires": {
9138
+        "isarray": "2.0.1"
9139
+      },
9140
+      "dependencies": {
9141
+        "isarray": {
9142
+          "version": "2.0.1",
9143
+          "resolved": "https://registry.npmjs.org/isarray/-/isarray-2.0.1.tgz",
9144
+          "integrity": "sha1-o32U7ZzaLVmGXJ92/llu4fM4dB4="
9145
+        }
9146
+      }
9147
+    },
9134
     "has-cors": {
9148
     "has-cors": {
9135
       "version": "1.1.0",
9149
       "version": "1.1.0",
9136
       "resolved": "https://registry.npmjs.org/has-cors/-/has-cors-1.1.0.tgz",
9150
       "resolved": "https://registry.npmjs.org/has-cors/-/has-cors-1.1.0.tgz",
9137
-      "integrity": "sha1-XkdHk/fqmEPRu5nCPu9J/xJv/zk=",
9138
-      "dev": true
9151
+      "integrity": "sha1-XkdHk/fqmEPRu5nCPu9J/xJv/zk="
9139
     },
9152
     },
9140
     "has-flag": {
9153
     "has-flag": {
9141
       "version": "3.0.0",
9154
       "version": "3.0.0",
9571
     "indexof": {
9584
     "indexof": {
9572
       "version": "0.0.1",
9585
       "version": "0.0.1",
9573
       "resolved": "https://registry.npmjs.org/indexof/-/indexof-0.0.1.tgz",
9586
       "resolved": "https://registry.npmjs.org/indexof/-/indexof-0.0.1.tgz",
9574
-      "integrity": "sha1-gtwzbSMrkGIXnQWrMpOmYFn9Q10=",
9575
-      "dev": true
9587
+      "integrity": "sha1-gtwzbSMrkGIXnQWrMpOmYFn9Q10="
9576
     },
9588
     },
9577
     "infer-owner": {
9589
     "infer-owner": {
9578
       "version": "1.0.4",
9590
       "version": "1.0.4",
13468
     "negotiator": {
13480
     "negotiator": {
13469
       "version": "0.6.2",
13481
       "version": "0.6.2",
13470
       "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.2.tgz",
13482
       "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.2.tgz",
13471
-      "integrity": "sha512-hZXc7K2e+PgeI1eDBe/10Ard4ekbfrrqG8Ep+8Jmf4JID2bNg7NvCPOZN+kfF574pFQI7mum2AUqDidoKqcTOw==",
13472
-      "dev": true
13483
+      "integrity": "sha512-hZXc7K2e+PgeI1eDBe/10Ard4ekbfrrqG8Ep+8Jmf4JID2bNg7NvCPOZN+kfF574pFQI7mum2AUqDidoKqcTOw=="
13473
     },
13484
     },
13474
     "neo-async": {
13485
     "neo-async": {
13475
       "version": "2.6.1",
13486
       "version": "2.6.1",
13925
     "object-component": {
13936
     "object-component": {
13926
       "version": "0.0.3",
13937
       "version": "0.0.3",
13927
       "resolved": "https://registry.npmjs.org/object-component/-/object-component-0.0.3.tgz",
13938
       "resolved": "https://registry.npmjs.org/object-component/-/object-component-0.0.3.tgz",
13928
-      "integrity": "sha1-8MaapQ78lbhmwYb0AKM3acsvEpE=",
13929
-      "dev": true
13939
+      "integrity": "sha1-8MaapQ78lbhmwYb0AKM3acsvEpE="
13930
     },
13940
     },
13931
     "object-copy": {
13941
     "object-copy": {
13932
       "version": "0.1.0",
13942
       "version": "0.1.0",
14440
       "version": "0.0.5",
14450
       "version": "0.0.5",
14441
       "resolved": "https://registry.npmjs.org/parseqs/-/parseqs-0.0.5.tgz",
14451
       "resolved": "https://registry.npmjs.org/parseqs/-/parseqs-0.0.5.tgz",
14442
       "integrity": "sha1-1SCKNzjkZ2bikbouoXNoSSGouJ0=",
14452
       "integrity": "sha1-1SCKNzjkZ2bikbouoXNoSSGouJ0=",
14443
-      "dev": true,
14444
       "requires": {
14453
       "requires": {
14445
         "better-assert": "~1.0.0"
14454
         "better-assert": "~1.0.0"
14446
       }
14455
       }
14449
       "version": "0.0.5",
14458
       "version": "0.0.5",
14450
       "resolved": "https://registry.npmjs.org/parseuri/-/parseuri-0.0.5.tgz",
14459
       "resolved": "https://registry.npmjs.org/parseuri/-/parseuri-0.0.5.tgz",
14451
       "integrity": "sha1-gCBKUNTbt3m/3G6+J3jZDkvOMgo=",
14460
       "integrity": "sha1-gCBKUNTbt3m/3G6+J3jZDkvOMgo=",
14452
-      "dev": true,
14453
       "requires": {
14461
       "requires": {
14454
         "better-assert": "~1.0.0"
14462
         "better-assert": "~1.0.0"
14455
       }
14463
       }
15043
         "webdriver-manager": "^12.0.6"
15051
         "webdriver-manager": "^12.0.6"
15044
       },
15052
       },
15045
       "dependencies": {
15053
       "dependencies": {
15054
+        "@types/node": {
15055
+          "version": "6.14.10",
15056
+          "resolved": "https://registry.npmjs.org/@types/node/-/node-6.14.10.tgz",
15057
+          "integrity": "sha512-pF4HjZGSog75kGq7B1InK/wt/N08BuPATo+7HRfv7gZUzccebwv/fmWVGs/j6LvSiLWpCuGGhql51M/wcQsNzA==",
15058
+          "dev": true
15059
+        },
15046
         "del": {
15060
         "del": {
15047
           "version": "2.2.2",
15061
           "version": "2.2.2",
15048
           "resolved": "https://registry.npmjs.org/del/-/del-2.2.2.tgz",
15062
           "resolved": "https://registry.npmjs.org/del/-/del-2.2.2.tgz",
15775
       "integrity": "sha512-ZYzRkETgBrdEGzL5JSKimvjI2CX7ioyZCkX2BpcfyjqI+079W0wHAyj5W4rIZMcDSOHgLZtgz1IdDi/vU77KEQ=="
15789
       "integrity": "sha512-ZYzRkETgBrdEGzL5JSKimvjI2CX7ioyZCkX2BpcfyjqI+079W0wHAyj5W4rIZMcDSOHgLZtgz1IdDi/vU77KEQ=="
15776
     },
15790
     },
15777
     "rpclibrary": {
15791
     "rpclibrary": {
15778
-      "version": "1.10.2",
15779
-      "resolved": "https://registry.npmjs.org/rpclibrary/-/rpclibrary-1.10.2.tgz",
15780
-      "integrity": "sha512-uf4FtylK+tyVo1O8YVihxYxaI4KHnKBzq05SsLYe8ZPXdO8Hqrv7Je5cwv3bfx0FBCO1vVrSc8DT1P6ypGY6uQ==",
15792
+      "version": "2.0.1",
15793
+      "resolved": "https://registry.npmjs.org/rpclibrary/-/rpclibrary-2.0.1.tgz",
15794
+      "integrity": "sha512-phdU0TkrnNVXdFa5PKkbWvn+MxocowvqalEUG1jfpkc1CoQkJ9AXa4OXSEu5r2a2IFhVauYva/qXv1em5yrHSg==",
15781
       "requires": {
15795
       "requires": {
15782
-        "bsock": "^0.1.9",
15783
-        "crypto-js": "^4.0.0",
15796
+        "@types/socket.io": "^2.1.8",
15797
+        "@types/socket.io-client": "^1.4.33",
15784
         "http": "0.0.0",
15798
         "http": "0.0.0",
15799
+        "socket.io": "^2.3.0",
15800
+        "socket.io-client": "^2.3.0",
15785
         "uuid": "^3.3.3"
15801
         "uuid": "^3.3.3"
15786
       },
15802
       },
15787
       "dependencies": {
15803
       "dependencies": {
15788
-        "crypto-js": {
15789
-          "version": "4.0.0",
15790
-          "resolved": "https://registry.npmjs.org/crypto-js/-/crypto-js-4.0.0.tgz",
15791
-          "integrity": "sha512-bzHZN8Pn+gS7DQA6n+iUmBfl0hO5DJq++QP3U6uTucDtk/0iGpXd/Gg7CGR0p8tJhofJyaKoWBuJI4eAO00BBg=="
15804
+        "arraybuffer.slice": {
15805
+          "version": "0.0.7",
15806
+          "resolved": "https://registry.npmjs.org/arraybuffer.slice/-/arraybuffer.slice-0.0.7.tgz",
15807
+          "integrity": "sha512-wGUIVQXuehL5TCqQun8OW81jGzAWycqzFF8lFp+GOM5BXLYj3bKNsYC4daB7n6XjCqxQA/qgTJ+8ANR3acjrog=="
15808
+        },
15809
+        "base64id": {
15810
+          "version": "2.0.0",
15811
+          "resolved": "https://registry.npmjs.org/base64id/-/base64id-2.0.0.tgz",
15812
+          "integrity": "sha512-lGe34o6EHj9y3Kts9R4ZYs/Gr+6N7MCaMlIFA3F1R2O5/m7K06AxfSeO5530PEERE6/WyEg3lsuyw4GHlPZHog=="
15813
+        },
15814
+        "blob": {
15815
+          "version": "0.0.5",
15816
+          "resolved": "https://registry.npmjs.org/blob/-/blob-0.0.5.tgz",
15817
+          "integrity": "sha512-gaqbzQPqOoamawKg0LGVd7SzLgXS+JH61oWprSLH+P+abTczqJbhTR8CmJ2u9/bUYNmHTGJx/UEmn6doAvvuig=="
15818
+        },
15819
+        "component-emitter": {
15820
+          "version": "1.2.1",
15821
+          "resolved": "https://registry.npmjs.org/component-emitter/-/component-emitter-1.2.1.tgz",
15822
+          "integrity": "sha1-E3kY1teCg/ffemt8WmPhQOaUJeY="
15823
+        },
15824
+        "cookie": {
15825
+          "version": "0.3.1",
15826
+          "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.3.1.tgz",
15827
+          "integrity": "sha1-5+Ch+e9DtMi6klxcWpboBtFoc7s="
15828
+        },
15829
+        "engine.io": {
15830
+          "version": "3.4.2",
15831
+          "resolved": "https://registry.npmjs.org/engine.io/-/engine.io-3.4.2.tgz",
15832
+          "integrity": "sha512-b4Q85dFkGw+TqgytGPrGgACRUhsdKc9S9ErRAXpPGy/CXKs4tYoHDkvIRdsseAF7NjfVwjRFIn6KTnbw7LwJZg==",
15833
+          "requires": {
15834
+            "accepts": "~1.3.4",
15835
+            "base64id": "2.0.0",
15836
+            "cookie": "0.3.1",
15837
+            "debug": "~4.1.0",
15838
+            "engine.io-parser": "~2.2.0",
15839
+            "ws": "^7.1.2"
15840
+          }
15841
+        },
15842
+        "engine.io-client": {
15843
+          "version": "3.4.3",
15844
+          "resolved": "https://registry.npmjs.org/engine.io-client/-/engine.io-client-3.4.3.tgz",
15845
+          "integrity": "sha512-0NGY+9hioejTEJCaSJZfWZLk4FPI9dN+1H1C4+wj2iuFba47UgZbJzfWs4aNFajnX/qAaYKbe2lLTfEEWzCmcw==",
15846
+          "requires": {
15847
+            "component-emitter": "~1.3.0",
15848
+            "component-inherit": "0.0.3",
15849
+            "debug": "~4.1.0",
15850
+            "engine.io-parser": "~2.2.0",
15851
+            "has-cors": "1.1.0",
15852
+            "indexof": "0.0.1",
15853
+            "parseqs": "0.0.5",
15854
+            "parseuri": "0.0.5",
15855
+            "ws": "~6.1.0",
15856
+            "xmlhttprequest-ssl": "~1.5.4",
15857
+            "yeast": "0.1.2"
15858
+          },
15859
+          "dependencies": {
15860
+            "component-emitter": {
15861
+              "version": "1.3.0",
15862
+              "resolved": "https://registry.npmjs.org/component-emitter/-/component-emitter-1.3.0.tgz",
15863
+              "integrity": "sha512-Rd3se6QB+sO1TwqZjscQrurpEPIfO0/yYnSin6Q/rD3mOutHvUrCAhJub3r90uNb+SESBuE0QYoB90YdfatsRg=="
15864
+            },
15865
+            "ws": {
15866
+              "version": "6.1.4",
15867
+              "resolved": "https://registry.npmjs.org/ws/-/ws-6.1.4.tgz",
15868
+              "integrity": "sha512-eqZfL+NE/YQc1/ZynhojeV8q+H050oR8AZ2uIev7RU10svA9ZnJUddHcOUZTJLinZ9yEfdA2kSATS2qZK5fhJA==",
15869
+              "requires": {
15870
+                "async-limiter": "~1.0.0"
15871
+              }
15872
+            }
15873
+          }
15874
+        },
15875
+        "engine.io-parser": {
15876
+          "version": "2.2.0",
15877
+          "resolved": "https://registry.npmjs.org/engine.io-parser/-/engine.io-parser-2.2.0.tgz",
15878
+          "integrity": "sha512-6I3qD9iUxotsC5HEMuuGsKA0cXerGz+4uGcXQEkfBidgKf0amsjrrtwcbwK/nzpZBxclXlV7gGl9dgWvu4LF6w==",
15879
+          "requires": {
15880
+            "after": "0.8.2",
15881
+            "arraybuffer.slice": "~0.0.7",
15882
+            "base64-arraybuffer": "0.1.5",
15883
+            "blob": "0.0.5",
15884
+            "has-binary2": "~1.0.2"
15885
+          }
15886
+        },
15887
+        "isarray": {
15888
+          "version": "2.0.1",
15889
+          "resolved": "https://registry.npmjs.org/isarray/-/isarray-2.0.1.tgz",
15890
+          "integrity": "sha1-o32U7ZzaLVmGXJ92/llu4fM4dB4="
15891
+        },
15892
+        "ms": {
15893
+          "version": "2.0.0",
15894
+          "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
15895
+          "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g="
15896
+        },
15897
+        "socket.io": {
15898
+          "version": "2.3.0",
15899
+          "resolved": "https://registry.npmjs.org/socket.io/-/socket.io-2.3.0.tgz",
15900
+          "integrity": "sha512-2A892lrj0GcgR/9Qk81EaY2gYhCBxurV0PfmmESO6p27QPrUK1J3zdns+5QPqvUYK2q657nSj0guoIil9+7eFg==",
15901
+          "requires": {
15902
+            "debug": "~4.1.0",
15903
+            "engine.io": "~3.4.0",
15904
+            "has-binary2": "~1.0.2",
15905
+            "socket.io-adapter": "~1.1.0",
15906
+            "socket.io-client": "2.3.0",
15907
+            "socket.io-parser": "~3.4.0"
15908
+          }
15909
+        },
15910
+        "socket.io-adapter": {
15911
+          "version": "1.1.2",
15912
+          "resolved": "https://registry.npmjs.org/socket.io-adapter/-/socket.io-adapter-1.1.2.tgz",
15913
+          "integrity": "sha512-WzZRUj1kUjrTIrUKpZLEzFZ1OLj5FwLlAFQs9kuZJzJi5DKdU7FsWc36SNmA8iDOtwBQyT8FkrriRM8vXLYz8g=="
15914
+        },
15915
+        "socket.io-client": {
15916
+          "version": "2.3.0",
15917
+          "resolved": "https://registry.npmjs.org/socket.io-client/-/socket.io-client-2.3.0.tgz",
15918
+          "integrity": "sha512-cEQQf24gET3rfhxZ2jJ5xzAOo/xhZwK+mOqtGRg5IowZsMgwvHwnf/mCRapAAkadhM26y+iydgwsXGObBB5ZdA==",
15919
+          "requires": {
15920
+            "backo2": "1.0.2",
15921
+            "base64-arraybuffer": "0.1.5",
15922
+            "component-bind": "1.0.0",
15923
+            "component-emitter": "1.2.1",
15924
+            "debug": "~4.1.0",
15925
+            "engine.io-client": "~3.4.0",
15926
+            "has-binary2": "~1.0.2",
15927
+            "has-cors": "1.1.0",
15928
+            "indexof": "0.0.1",
15929
+            "object-component": "0.0.3",
15930
+            "parseqs": "0.0.5",
15931
+            "parseuri": "0.0.5",
15932
+            "socket.io-parser": "~3.3.0",
15933
+            "to-array": "0.1.4"
15934
+          },
15935
+          "dependencies": {
15936
+            "socket.io-parser": {
15937
+              "version": "3.3.0",
15938
+              "resolved": "https://registry.npmjs.org/socket.io-parser/-/socket.io-parser-3.3.0.tgz",
15939
+              "integrity": "sha512-hczmV6bDgdaEbVqhAeVMM/jfUfzuEZHsQg6eOmLgJht6G3mPKMxYm75w2+qhAQZ+4X+1+ATZ+QFKeOZD5riHng==",
15940
+              "requires": {
15941
+                "component-emitter": "1.2.1",
15942
+                "debug": "~3.1.0",
15943
+                "isarray": "2.0.1"
15944
+              },
15945
+              "dependencies": {
15946
+                "debug": {
15947
+                  "version": "3.1.0",
15948
+                  "resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz",
15949
+                  "integrity": "sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==",
15950
+                  "requires": {
15951
+                    "ms": "2.0.0"
15952
+                  }
15953
+                }
15954
+              }
15955
+            }
15956
+          }
15957
+        },
15958
+        "socket.io-parser": {
15959
+          "version": "3.4.1",
15960
+          "resolved": "https://registry.npmjs.org/socket.io-parser/-/socket.io-parser-3.4.1.tgz",
15961
+          "integrity": "sha512-11hMgzL+WCLWf1uFtHSNvliI++tcRUWdoeYuwIl+Axvwy9z2gQM+7nJyN3STj1tLj5JyIUH8/gpDGxzAlDdi0A==",
15962
+          "requires": {
15963
+            "component-emitter": "1.2.1",
15964
+            "debug": "~4.1.0",
15965
+            "isarray": "2.0.1"
15966
+          }
15967
+        },
15968
+        "ws": {
15969
+          "version": "7.3.1",
15970
+          "resolved": "https://registry.npmjs.org/ws/-/ws-7.3.1.tgz",
15971
+          "integrity": "sha512-D3RuNkynyHmEJIpD2qrgVkc9DQ23OrN/moAwZX4L8DfvszsJxpjQuUq3LMx6HoYji9fbIOBY18XWBsAux1ZZUA=="
15972
+        },
15973
+        "xmlhttprequest-ssl": {
15974
+          "version": "1.5.5",
15975
+          "resolved": "https://registry.npmjs.org/xmlhttprequest-ssl/-/xmlhttprequest-ssl-1.5.5.tgz",
15976
+          "integrity": "sha1-wodrBhaKrcQOV9l+gRkayPQ5iz4="
15792
         }
15977
         }
15793
       }
15978
       }
15794
     },
15979
     },
17979
     "to-array": {
18164
     "to-array": {
17980
       "version": "0.1.4",
18165
       "version": "0.1.4",
17981
       "resolved": "https://registry.npmjs.org/to-array/-/to-array-0.1.4.tgz",
18166
       "resolved": "https://registry.npmjs.org/to-array/-/to-array-0.1.4.tgz",
17982
-      "integrity": "sha1-F+bBH3PdTz10zaek/zI46a2b+JA=",
17983
-      "dev": true
18167
+      "integrity": "sha1-F+bBH3PdTz10zaek/zI46a2b+JA="
17984
     },
18168
     },
17985
     "to-arraybuffer": {
18169
     "to-arraybuffer": {
17986
       "version": "1.0.1",
18170
       "version": "1.0.1",
21030
     "yeast": {
21214
     "yeast": {
21031
       "version": "0.1.2",
21215
       "version": "0.1.2",
21032
       "resolved": "https://registry.npmjs.org/yeast/-/yeast-0.1.2.tgz",
21216
       "resolved": "https://registry.npmjs.org/yeast/-/yeast-0.1.2.tgz",
21033
-      "integrity": "sha1-AI4G2AlDIMNy28L47XagymyKxBk=",
21034
-      "dev": true
21217
+      "integrity": "sha1-AI4G2AlDIMNy28L47XagymyKxBk="
21035
     },
21218
     },
21036
     "yn": {
21219
     "yn": {
21037
       "version": "3.1.1",
21220
       "version": "3.1.1",

+ 2
- 2
src/frontend/package.json View File

79
     "normalize.css": "6.0.0",
79
     "normalize.css": "6.0.0",
80
     "pace-js": "1.0.2",
80
     "pace-js": "1.0.2",
81
     "roboto-fontface": "0.8.0",
81
     "roboto-fontface": "0.8.0",
82
-    "rpclibrary": "^1.10.2",
82
+    "rpclibrary": "^2.0.1",
83
     "rxjs": "6.5.2",
83
     "rxjs": "6.5.2",
84
     "rxjs-compat": "6.3.0",
84
     "rxjs-compat": "6.3.0",
85
     "socicon": "3.0.5",
85
     "socicon": "3.0.5",
102
     "@types/jasmine": "2.5.54",
102
     "@types/jasmine": "2.5.54",
103
     "@types/jasminewd2": "2.0.3",
103
     "@types/jasminewd2": "2.0.3",
104
     "@types/leaflet": "1.2.3",
104
     "@types/leaflet": "1.2.3",
105
-    "@types/node": "6.0.90",
105
+    "@types/node": "^14.0.27",
106
     "codelyzer": "^5.0.1",
106
     "codelyzer": "^5.0.1",
107
     "conventional-changelog-cli": "1.3.4",
107
     "conventional-changelog-cli": "1.3.4",
108
     "jasmine-core": "2.6.4",
108
     "jasmine-core": "2.6.4",

+ 1
- 0
src/frontend/src/app/frontcraft/pages/armory/armory.component.ts View File

51
       const geardata = maybeItems.filter(maybeItem => maybeItem != null)
51
       const geardata = maybeItems.filter(maybeItem => maybeItem != null)
52
 
52
 
53
       this.gear = geardata
53
       this.gear = geardata
54
+      console.log(this.gear)
54
       console.log(this.gear.map(g => g.stats).reduce(sumStats))
55
       console.log(this.gear.map(g => g.stats).reduce(sumStats))
55
     }))
56
     }))
56
   }
57
   }

+ 0
- 19
src/frontend/src/app/frontcraft/pages/character/character.component.html View File

21
         <span *ngIf="link === 'owner'">
21
         <span *ngIf="link === 'owner'">
22
             Owned by <a [routerLink]="'/frontcraft/user/'+char.username"> {{char.username}} ({{char.rank}})</a>
22
             Owned by <a [routerLink]="'/frontcraft/user/'+char.username"> {{char.username}} ({{char.rank}})</a>
23
         </span>
23
         </span>
24
-        <br/>
25
-        <br />
26
-        <br />
27
-
28
-        <h3>Tokens</h3>
29
-        <span *ngFor="let token of tokens">
30
-            [ {{token.level}} ]
31
-            <wowhead [item]="token"></wowhead><br />
32
-        </span>
33
-
34
-        <br />
35
-        <br />
36
-        <br />
37
-        <h3>Gear of the last reported kill <a target="_blank" *ngIf="dataLink != null && dataLink != ''" style="size: 0.5em;" [href]="dataLink">(data)</a></h3>
38
-        <h5>{{boss2.name}} {{boss2.date | date : 'MMM d @ HH : mm'}}</h5>
39
-        <ng-container *ngFor="let item of gear2">
40
-            <wowhead [item]="item"></wowhead><br />
41
-        </ng-container>
42
-
43
     </nb-card-body>
24
     </nb-card-body>
44
 </nb-card>
25
 </nb-card>

+ 15
- 6
src/frontend/src/app/frontcraft/pages/raid/characterpicker.component.html View File

4
     </nb-card-header>
4
     </nb-card-header>
5
     <nb-card-body>
5
     <nb-card-body>
6
         <textarea 
6
         <textarea 
7
+            fullWidth
7
             placeholder="Add a note (optional)"
8
             placeholder="Add a note (optional)"
8
             rows="7" 
9
             rows="7" 
9
             cols="50" 
10
             cols="50" 
13
         <br />
14
         <br />
14
         <br />
15
         <br />
15
         <nb-card *ngFor="let character of characters">
16
         <nb-card *ngFor="let character of characters">
16
-            <nb-card-header [ngStyle]="{'color': character.color}">
17
+            <nb-card-header [ngStyle]="{'color': character.color}" style="text-transform: capitalize;">
17
                 <img [src]="'../../../../assets/images/'+character.class.toLowerCase()+'.png'" />
18
                 <img [src]="'../../../../assets/images/'+character.class.toLowerCase()+'.png'" />
18
                 {{character.charactername}}
19
                 {{character.charactername}}
19
             </nb-card-header>
20
             </nb-card-header>
20
             <nb-card-body>
21
             <nb-card-body>
21
                 <button
22
                 <button
22
-                    (click)="signup(character, false)"
23
+                    (click)="signup(character, false, false)"
23
                     nbButton 
24
                     nbButton 
24
                     outline 
25
                     outline 
26
+                    fullWidth
25
                     status="success" 
27
                     status="success" 
26
                     size="medium">
28
                     size="medium">
27
                     <nb-icon icon="checkmark-outline"></nb-icon> On Time
29
                     <nb-icon icon="checkmark-outline"></nb-icon> On Time
28
                 </button>
30
                 </button>
29
-                &nbsp;
30
-                &nbsp;
31
-                &nbsp;
32
                 <button
31
                 <button
33
-                    (click)="signup(character, true)"
32
+                    (click)="signup(character, true, false)"
34
                     nbButton 
33
                     nbButton 
35
                     outline 
34
                     outline 
35
+                    fullWidth
36
                     status="warning" 
36
                     status="warning" 
37
                     size="medium">
37
                     size="medium">
38
                     <nb-icon icon="clock-outline"></nb-icon> Late
38
                     <nb-icon icon="clock-outline"></nb-icon> Late
39
                 </button>
39
                 </button>
40
+                <button
41
+                    (click)="signup(character, false, true)"
42
+                    nbButton 
43
+                    outline 
44
+                    fullWidth
45
+                    status="danger" 
46
+                    size="medium">
47
+                    <nb-icon icon="person-delete-outline"></nb-icon> Absent
48
+                </button>
40
             </nb-card-body>
49
             </nb-card-body>
41
         </nb-card>
50
         </nb-card>
42
     </nb-card-body>
51
     </nb-card-body>

+ 2
- 2
src/frontend/src/app/frontcraft/pages/raid/characterpicker.component.ts View File

20
         private toast : NbToastrService
20
         private toast : NbToastrService
21
     ){}
21
     ){}
22
 
22
 
23
-    signup = async (character: Character, late: boolean) => {
23
+    signup = async (character: Character, late: boolean, attending: boolean = true) => {
24
         const auth = this.api.getAuth()
24
         const auth = this.api.getAuth()
25
         const signup = this.api.get('signup')
25
         const signup = this.api.get('signup')
26
         if(!signup) return
26
         if(!signup) return
27
 
27
 
28
-        await signup.sign(auth.token.value, character, this.raid, late, this.memo)
28
+        await signup.sign(auth.token.value, character, this.raid, late, attending, this.memo)
29
         this.toast.show('Signup', 'Success', { status: 'success' })
29
         this.toast.show('Signup', 'Success', { status: 'success' })
30
         this.dialogRef.close()
30
         this.dialogRef.close()
31
     }
31
     }

+ 32
- 50
src/frontend/src/app/frontcraft/pages/raid/raid.component.html View File

26
                                     ({{mySignup.race}} {{mySignup.specname}} {{mySignup.class}})
26
                                     ({{mySignup.race}} {{mySignup.specname}} {{mySignup.class}})
27
                                     <br />
27
                                     <br />
28
                                     Status: {{mySignup.status}}<br /><br />
28
                                     Status: {{mySignup.status}}<br /><br />
29
-                                    <textarea [status]="mySignup.status === 'Attending'?'success':'warning'"
29
+                                    <textarea fullWidth *ngIf="mySignup.status !== 'Absent'"
30
+                                        [status]="mySignup.status === 'Attending'?'success':'warning'"
30
                                         placeholder="Add a note (optional)" rows="10" cols="50" nbInput
31
                                         placeholder="Add a note (optional)" rows="10" cols="50" nbInput
31
                                         style="white-space: pre-line;" [(ngModel)]="mySignup.memo">
32
                                         style="white-space: pre-line;" [(ngModel)]="mySignup.memo">
32
                                     </textarea>
33
                                     </textarea>
33
                                 </p>
34
                                 </p>
34
 
35
 
35
-                                <button *ngIf="mySignup.status === 'Late'" (click)="setLate(false)" nbButton outline
36
-                                    status="success" size="medium">
36
+                                <button *ngIf="mySignup.status !== 'Attending'" (click)="setLate(false)" nbButton
37
+                                    fullWidth outline status="success" size="medium">
37
                                     <nb-icon icon="checkmark-outline"></nb-icon> On Time
38
                                     <nb-icon icon="checkmark-outline"></nb-icon> On Time
38
                                 </button>
39
                                 </button>
39
                                 <button *ngIf="mySignup.status === 'Attending'" (click)="setLate(false)" nbButton
40
                                 <button *ngIf="mySignup.status === 'Attending'" (click)="setLate(false)" nbButton
40
-                                    outline status="success" size="medium">
41
+                                    fullWidth outline status="success" size="medium">
41
                                     <nb-icon icon="checkmark-outline"></nb-icon> Update
42
                                     <nb-icon icon="checkmark-outline"></nb-icon> Update
42
                                 </button>
43
                                 </button>
43
-                                <button *ngIf="mySignup.status === 'Late'" (click)="setLate(true)" nbButton outline
44
-                                    status="warning" size="medium">
44
+                                <button *ngIf="mySignup.status === 'Late'" (click)="setLate(true)" nbButton fullWidth
45
+                                    outline status="warning" size="medium">
45
                                     <nb-icon icon="clock-outline"></nb-icon> Update
46
                                     <nb-icon icon="clock-outline"></nb-icon> Update
46
                                 </button>
47
                                 </button>
47
-                                <button *ngIf="mySignup.status === 'Attending'" (click)="setLate(true)" nbButton outline
48
-                                    status="warning" size="medium">
48
+                                <button *ngIf="mySignup.status !== 'Late'" (click)="setLate(true)" nbButton fullWidth
49
+                                    outline status="warning" size="medium">
49
                                     <nb-icon icon="clock-outline"></nb-icon> Late
50
                                     <nb-icon icon="clock-outline"></nb-icon> Late
50
                                 </button>
51
                                 </button>
51
-
52
-                                <button (click)="unsign()" nbButton outline status="danger" size="medium">
52
+                                <button *ngIf="mySignup.status !== 'Absent'" (click)="setAbsent()" nbButton fullWidth
53
+                                    outline status="danger" size="medium">
54
+                                    <nb-icon icon="person-delete-outline"></nb-icon> Absent
55
+                                </button>
56
+                                <p>&nbsp;</p>
57
+                                <button (click)="unsign()" nbButton fullWidth status="danger" size="medium">
53
                                     <nb-icon icon="close"></nb-icon>unsign
58
                                     <nb-icon icon="close"></nb-icon>unsign
54
                                 </button>
59
                                 </button>
55
                             </div>
60
                             </div>
56
                             <div *ngIf="!isSignedup">
61
                             <div *ngIf="!isSignedup">
57
-                                <button (click)="signup()" nbButton outline status="success" size="medium">
62
+                                <button (click)="signup()" fullWidth nbButton outline status="success" size="medium">
58
                                     <nb-icon icon="person-done-outline"></nb-icon> sign up
63
                                     <nb-icon icon="person-done-outline"></nb-icon> sign up
59
                                 </button>
64
                                 </button>
60
                             </div>
65
                             </div>
83
                                                 [src]="'/assets/images/'+participant.class.toLowerCase()+'.png'" />
88
                                                 [src]="'/assets/images/'+participant.class.toLowerCase()+'.png'" />
84
                                             {{ participant.charactername }}
89
                                             {{ participant.charactername }}
85
                                         </a>
90
                                         </a>
86
-                                        <ng-template #template>
91
+                                        <ng-template #timeInfo>
92
+                                            <div style="padding: 10px">
93
+                                                {{participant.timestamp | date : 'HH:mm EEE MMM d'}}
94
+                                                ({{participant.before | date : 'dd'}} days before start)
95
+                                            </div>
96
+                                        </ng-template>
97
+                                        <nb-icon [nbPopover]="timeInfo" nbPopoverTrigger="hover"
98
+                                            style="width: 0.75em; height: 0.75em;" icon="clock-outline"
99
+                                            [status]="participant.before>8.64e+7?(participant.before>2.592e+8?'success':'warning'):'danger'">
100
+                                        </nb-icon>
101
+                                        <ng-template #memoBox>
87
                                             <div style="padding: 10px">
102
                                             <div style="padding: 10px">
88
                                                 <p
103
                                                 <p
89
                                                     style="white-space: pre-line; max-width: 50vw; word-wrap: break-word;">
104
                                                     style="white-space: pre-line; max-width: 50vw; word-wrap: break-word;">
90
                                                     {{participant.memo}}
105
                                                     {{participant.memo}}
91
                                                 </p>
106
                                                 </p>
92
-                                                {{participant.timestamp | date : 'HH:mm EEE MMM d'}} ({{participant.before | date : 'dd'}} days before start)
93
                                             </div>
107
                                             </div>
94
                                         </ng-template>
108
                                         </ng-template>
95
-                                        <nb-icon
96
-                                        [nbPopover]="template" 
97
-                                        nbPopoverTrigger="hover"
98
-                                        style="width: 0.75em; height: 0.75em;" 
99
-                                        [icon]="participant.memo != null && participant.memo != ''?'message-circle-outline':'clock-outline'"
100
-                                        [status]="participant.before>8.64e+7?(participant.before>2.592e+8?'success':'warning'):'danger'">
109
+                                        <nb-icon *ngIf="participant.memo" [nbPopover]="memoBox" nbPopoverTrigger="hover"
110
+                                            style="width: 0.75em; height: 0.75em;" icon="message-circle-outline">
101
                                         </nb-icon>
111
                                         </nb-icon>
102
 
112
 
103
                                         <span *ngIf="participant.rank=='Trial'" style="font-size: 9px;">
113
                                         <span *ngIf="participant.rank=='Trial'" style="font-size: 9px;">
127
                                                 [src]="'/assets/images/'+participant.class.toLowerCase()+'.png'" />
137
                                                 [src]="'/assets/images/'+participant.class.toLowerCase()+'.png'" />
128
                                             {{ participant.charactername }}
138
                                             {{ participant.charactername }}
129
                                         </a>
139
                                         </a>
130
-                                        <ng-template #template>
131
-                                            <div style="padding: 10px">
132
-                                                <p style="white-space: pre-line;">
133
-                                                    {{participant.memo}}
134
-                                                </p>
135
-                                                {{participant.timestamp | date : 'HH:mm EEE MMM d'}} ({{participant.before | date : 'dd'}} days before start)
136
-                                            </div>
137
-                                        </ng-template>
138
-                                        <nb-icon
139
-                                            [nbPopover]="template" 
140
-                                            nbPopoverTrigger="hover"
141
-                                            style="width: 0.75em; height: 0.75em;" 
142
-                                            [icon]="participant.memo != null && participant.memo != ''?'message-circle-outline':'clock-outline'"
143
-                                            [status]="participant.before>8.64e+7?(participant.before>2.592e+8?'success':'warning'):'danger'">
144
-                                        </nb-icon>
145
                                         <span *ngIf="participant.rank=='Trial'" style="font-size: 9px;">
140
                                         <span *ngIf="participant.rank=='Trial'" style="font-size: 9px;">
146
                                             Trial
141
                                             Trial
147
                                         </span>
142
                                         </span>
171
                                                     [src]="'/assets/images/'+participant.class.toLowerCase()+'.png'" />
166
                                                     [src]="'/assets/images/'+participant.class.toLowerCase()+'.png'" />
172
                                                 {{ participant.charactername }}
167
                                                 {{ participant.charactername }}
173
                                             </a>
168
                                             </a>
174
-                                            <ng-template #template>
175
-                                                <div style="padding: 10px">
176
-                                                    <p style="white-space: pre-line;">
177
-                                                        {{participant.memo}}
178
-                                                    </p>
179
-                                                    {{participant.timestamp | date : 'HH:mm EEE MMM d'}} ({{participant.before | date : 'dd'}} days before start)
180
-                                                </div>
181
-                                            </ng-template>
182
-                                            <nb-icon
183
-                                                [nbPopover]="template" 
184
-                                                nbPopoverTrigger="hover"
185
-                                                style="width: 0.75em; height: 0.75em;" 
186
-                                                [icon]="participant.memo != null && participant.memo != ''?'message-circle-outline':'clock-outline'"
187
-                                                [status]="participant.before>8.64e+7?(participant.before>2.592e+8?'success':'warning'):'danger'">
188
-                                            </nb-icon>
189
-
190
                                             <span *ngIf="participant.rank=='Trial'" style="font-size: 9px;">
169
                                             <span *ngIf="participant.rank=='Trial'" style="font-size: 9px;">
191
                                                 Trial
170
                                                 Trial
192
                                             </span>
171
                                             </span>
200
                         <button (click)="startRaid(raid)" nbButton outline status="success" size="medium">
179
                         <button (click)="startRaid(raid)" nbButton outline status="success" size="medium">
201
                             start
180
                             start
202
                         </button>
181
                         </button>
182
+                        <button (click)="cancelRaid(raid)" nbButton outline status="danger" size="medium">
183
+                            cancel
184
+                        </button>
203
                     </nb-tab>
185
                     </nb-tab>
204
                 </nb-tabset>
186
                 </nb-tabset>
205
             </nb-card-body>
187
             </nb-card-body>

+ 40
- 8
src/frontend/src/app/frontcraft/pages/raid/raid.component.ts View File

120
     this.router.navigateByUrl('/frontcraft/archive/' + raid.id)
120
     this.router.navigateByUrl('/frontcraft/archive/' + raid.id)
121
   }
121
   }
122
 
122
 
123
+  async cancelRaid(raid: Raid) {
124
+    await this.manageRaid!.cancelRaid(raid)
125
+    this.toast.show('Raid cancelled', 'Success', { status: 'success' })
126
+    this.router.navigateByUrl('/frontcraft/raids')
127
+  }
128
+
123
   unsign = async () => {
129
   unsign = async () => {
124
     const signupFeature = this.api.get('signup')
130
     const signupFeature = this.api.get('signup')
125
     if (!signupFeature) return
131
     if (!signupFeature) return
139
     await signup.sign(auth.token.value, {
145
     await signup.sign(auth.token.value, {
140
       ...this.mySignup,
146
       ...this.mySignup,
141
       id: this.mySignup.characterid,
147
       id: this.mySignup.characterid,
142
-    }, this.raid, value, this.mySignup.memo)
148
+    }, this.raid, value, false, this.mySignup.memo)
149
+
150
+    this.toast.show('Signup', 'Success', { status: 'success' })
151
+  }
152
+
153
+  setAbsent = async () => {
154
+    const auth = this.api.getAuth()
155
+    const signup = this.api.get('signup')
156
+    if (!signup) return
157
+
158
+    await signup.sign(auth.token.value, {
159
+      ...this.mySignup,
160
+      id: this.mySignup.characterid,
161
+    }, this.raid, false, true, this.mySignup.memo)
162
+    
143
     this.toast.show('Signup', 'Success', { status: 'success' })
163
     this.toast.show('Signup', 'Success', { status: 'success' })
144
   }
164
   }
145
 
165
 
184
     if (matchingSignup) {
204
     if (matchingSignup) {
185
       this.mySignup = matchingSignup
205
       this.mySignup = matchingSignup
186
       this.isSignedup = true
206
       this.isSignedup = true
187
-      this.mySignup['status'] = matchingSignup['benched'] ? 'Bench' : matchingSignup['late'] ? 'Late' : 'Attending'
207
+      console.log(this.mySignup);
208
+      
209
+      this.mySignup['status'] = matchingSignup['absent'] ? 'Absent' : matchingSignup['benched'] ? 'Bench' : matchingSignup['late'] ? 'Late' : 'Attending'
188
     } else {
210
     } else {
189
       this.isSignedup = false
211
       this.isSignedup = false
190
       this.mySignup = null
212
       this.mySignup = null
209
   }
231
   }
210
 
232
 
211
   setBench(signup: Signup) {
233
   setBench(signup: Signup) {
212
-    this.manageRaid.setBenched({
213
-      characterid: signup.characterid,
214
-      raidid: signup.raidid,
215
-      late: false,
216
-      benched: !signup.benched
217
-    }).then(_ => this.refresh())
234
+
235
+    const manageRaid = this.api.get('manageRaid')
236
+    if(manageRaid){
237
+      const signupUpdated:Signup = {
238
+        benched: !signup.benched,
239
+        absent: false,
240
+        late: false,
241
+        characterid: signup.characterid,
242
+        raidid: signup.raidid,
243
+        timestamp: signup.timestamp,
244
+        id: signup.id,
245
+        memo: signup.memo
246
+      }
247
+      manageRaid.updateSignup(signupUpdated)
248
+      .then(_ => this.refresh())
249
+    }
218
   }
250
   }
219
 }
251
 }

+ 5
- 5
src/frontend/src/app/frontcraft/pages/shop/buytoken.component.ts View File

14
       </nb-card-header>
14
       </nb-card-header>
15
       <nb-card-body>
15
       <nb-card-body>
16
         <p>
16
         <p>
17
-          {{currency}} softreserves remaining
17
+          You have {{currency}} softreserve(s) remaining
18
         </p>  
18
         </p>  
19
         <div *ngIf="currency>0">
19
         <div *ngIf="currency>0">
20
             <nb-alert accent="danger" *ngIf="invalidatedTokens.length > 0">
20
             <nb-alert accent="danger" *ngIf="invalidatedTokens.length > 0">
37
                 The following reserve will be created<br />
37
                 The following reserve will be created<br />
38
                 <ul>
38
                 <ul>
39
                     <li>
39
                     <li>
40
-                        [ {{1+modifier}} ] 
40
+                        [ {{1+currency+modifier}} ] 
41
                         <img style="min-width: 20px; width: 2.25vw; max-width: 35px" [src]="'https://wow.zamimg.com/images/wow/icons/large/'+item.iconname+'.jpg'" />
41
                         <img style="min-width: 20px; width: 2.25vw; max-width: 35px" [src]="'https://wow.zamimg.com/images/wow/icons/large/'+item.iconname+'.jpg'" />
42
                         <span [ngStyle]="{'color':item.quality=='Epic'?'#a335ee':'#ff8000'}">
42
                         <span [ngStyle]="{'color':item.quality=='Epic'?'#a335ee':'#ff8000'}">
43
                         {{item.itemname}}
43
                         {{item.itemname}}
49
             </nb-alert>
49
             </nb-alert>
50
 
50
 
51
             <nb-alert accent="info" *ngIf="upgradableToken != null">
51
             <nb-alert accent="info" *ngIf="upgradableToken != null">
52
-                The following reserve will be created<br />
52
+                The following reserve will be upgraded<br />
53
                 <ul>
53
                 <ul>
54
                     <li>
54
                     <li>
55
-                        [ {{upgradableToken.level}} ] => [ {{upgradableToken.level+1}} ] <img style="min-width: 20px; width: 2.25vw; max-width: 35px" [src]="'https://wow.zamimg.com/images/wow/icons/large/'+upgradableToken.iconname+'.jpg'" />
55
+                        [ {{upgradableToken.level}} ] => [ {{upgradableToken.level+1+currency}} ] <img style="min-width: 20px; width: 2.25vw; max-width: 35px" [src]="'https://wow.zamimg.com/images/wow/icons/large/'+upgradableToken.iconname+'.jpg'" />
56
                         <span [ngStyle]="{'color':upgradableToken.quality=='Epic'?'#a335ee':'#ff8000'}">{{upgradableToken.itemname}}</span>
56
                         <span [ngStyle]="{'color':upgradableToken.quality=='Epic'?'#a335ee':'#ff8000'}">{{upgradableToken.itemname}}</span>
57
                     </li>
57
                     </li>
58
                 </ul>
58
                 </ul>
65
                   outline 
65
                   outline 
66
                   status="success" 
66
                   status="success" 
67
                   size="small">
67
                   size="small">
68
-                  <nb-icon icon="checkmark-outline"></nb-icon> claim
68
+                  <nb-icon icon="checkmark-outline"></nb-icon> okay
69
             </button>
69
             </button>
70
       </nb-card-body>
70
       </nb-card-body>
71
   </nb-card>
71
   </nb-card>

+ 3
- 3
src/frontend/src/app/frontcraft/services/ApiService/client-login-api.ts View File

59
 //            document.cookie = JSON.stringify(auth)
59
 //            document.cookie = JSON.stringify(auth)
60
             return authSock
60
             return authSock
61
         }catch(e){ 
61
         }catch(e){ 
62
-            if(this.privSocket) this.privSocket.destroy()
62
+            if(this.privSocket) this.privSocket.close()
63
             return;
63
             return;
64
         }
64
         }
65
     }
65
     }
120
             }
120
             }
121
         } 
121
         } 
122
 
122
 
123
-        if(this.privSocket) this.privSocket.destroy()
123
+        if(this.privSocket) this.privSocket.close()
124
         this.privSocket = null
124
         this.privSocket = null
125
         this.auth  = null
125
         this.auth  = null
126
     }
126
     }
127
 
127
 
128
     initialize = async (force = false) : Promise<any> => {
128
     initialize = async (force = false) : Promise<any> => {
129
         if(this.socket){
129
         if(this.socket){
130
-            this.socket.destroy()
130
+            this.socket.close()
131
             this.socket = null
131
             this.socket = null
132
         }
132
         }
133
 
133
 

+ 2
- 2
src/frontend/src/app/frontcraft/services/ApiService/server-login-api.ts View File

71
             }
71
             }
72
         }
72
         }
73
 
73
 
74
-        if (this.privSocket) this.privSocket.destroy()
74
+        if (this.privSocket) this.privSocket.close()
75
         this.privSocket = null
75
         this.privSocket = null
76
         this.auth = null
76
         this.auth = null
77
     }
77
     }
78
 
78
 
79
     initialize = async (): Promise<any> => {
79
     initialize = async (): Promise<any> => {
80
         if (this.socket) {
80
         if (this.socket) {
81
-            this.socket.destroy()
81
+            this.socket.close()
82
             this.socket = null
82
             this.socket = null
83
         }
83
         }
84
 
84
 

+ 31
- 28
test/backendTest.ts View File

5
 import { RPCSocket, ConnectedSocket } from "rpclibrary";
5
 import { RPCSocket, ConnectedSocket } from "rpclibrary";
6
 import { FrontcraftIfc, Auth, User, FrontcraftFeatureIfc, Raid, Character, Rank, Class, Race, Spec, Signup } from "../src/backend/Types/Types";
6
 import { FrontcraftIfc, Auth, User, FrontcraftFeatureIfc, Raid, Character, Rank, Class, Race, Spec, Signup } from "../src/backend/Types/Types";
7
 import { SpecT } from "../src/backend/Types/PlayerSpecs";
7
 import { SpecT } from "../src/backend/Types/PlayerSpecs";
8
+import { ItemManager } from "src/backend/Components/Item/ItemManager";
8
 
9
 
9
 
10
 
10
 type protoAccount<C extends Class = Class> = {
11
 type protoAccount<C extends Class = Class> = {
166
                     username: 'a',
167
                     username: 'a',
167
                     MC: 2
168
                     MC: 2
168
                 }).then(adminUser => {
169
                 }).then(adminUser => {
169
-
170
                     client.UserManager.login(adminUser.username, 'ca978112ca1bbdcafac231b39a23dc4da786eff8147c4e72b9807785afee48bb').then(auth => {
170
                     client.UserManager.login(adminUser.username, 'ca978112ca1bbdcafac231b39a23dc4da786eff8147c4e72b9807785afee48bb').then(auth => {
171
                         const sock = new RPCSocket<FrontcraftFeatureIfc>(
171
                         const sock = new RPCSocket<FrontcraftFeatureIfc>(
172
                             auth.port,
172
                             auth.port,
194
     })
194
     })
195
 
195
 
196
     after(() => {
196
     after(() => {
197
-        client.destroy()
198
-        adminClient.destroy()
197
+        client.close()
198
+        adminClient.close()
199
         server.stop()
199
         server.stop()
200
     })
200
     })
201
 
201
 
240
 
240
 
241
     it('should sign up', (done) => {
241
     it('should sign up', (done) => {
242
         Promise.all(Object.values(users).map((user) =>
242
         Promise.all(Object.values(users).map((user) =>
243
-            adminClient.signup.sign(user.auth.token.value, user.character, raids[0], false, ""+Math.floor(Math.random()*10000)).catch(done)
244
-        )).then(x => {
243
+            adminClient.signup.sign(user.auth.token.value, user.character, raids[0], false, true, ""+Math.floor(Math.random()*10000)).catch(done)
244
+        )).then(_ => {
245
             adminClient.signup.getSignups(raids[0]).then(s => {
245
             adminClient.signup.getSignups(raids[0]).then(s => {
246
                 if (s.length == testAccounts.length) {
246
                 if (s.length == testAccounts.length) {
247
                     s.forEach(sign => {
247
                     s.forEach(sign => {
539
             users[user.account.username].item = itemname
539
             users[user.account.username].item = itemname
540
 
540
 
541
             if (!token) return false
541
             if (!token) return false
542
-            return modifier + 1 === token.level
542
+            return modifier + 2 === token.level
543
         })).then(success => {
543
         })).then(success => {
544
             if (success.reduce((prev, curr) => prev && curr, true)) done()
544
             if (success.reduce((prev, curr) => prev && curr, true)) done()
545
         })
545
         })
564
             await adminClient.softreserveCurrency.incrementCurrency(user.account, item!.tier, 2)
564
             await adminClient.softreserveCurrency.incrementCurrency(user.account, item!.tier, 2)
565
             const before = await client.ItemManager.getToken(user.character, item!)
565
             const before = await client.ItemManager.getToken(user.character, item!)
566
 
566
 
567
-            if (!before || before.level !== 4) {
568
-                console.log("expected level to be 4", before ? before.level : '?');
569
-                return
570
-            }
571
-
572
-            await client.ItemManager.buyToken(user.auth.token.value, user.character.charactername, itemname, user.signup!)
573
-            const after = await client.ItemManager.buyToken(user.auth.token.value, user.character.charactername, itemname, user.signup!)
574
-
575
-            if (!after || after.level !== 6) {
576
-                console.log("expected level after to be 6", after ? after.level : '?');
567
+            if (!before || before.level !== 5) {
568
+                console.log("expected level to be 5", before ? before.level : '?');
577
                 return
569
                 return
578
             }
570
             }
579
             done()
571
             done()
625
         adminClient.reset.wipeCurrencyAndItems().then(() => {
617
         adminClient.reset.wipeCurrencyAndItems().then(() => {
626
             client.UserManager.getUser(testAccounts[0].name).then(user => {
618
             client.UserManager.getUser(testAccounts[0].name).then(user => {
627
                 if (user && user.MC === 1) {
619
                 if (user && user.MC === 1) {
628
-                    client.ItemManager.getTokens(users[testAccounts[0].name.toLowerCase()].character, ['BWL']).then(tokens => {
620
+                    client.ItemManager.getTokens(users[testAccounts[0].name.toLowerCase()].character, ['BWL'], true).then(tokens => {
629
                         if (tokens!.length === 0) {
621
                         if (tokens!.length === 0) {
630
                             done()
622
                             done()
631
                         } else {
623
                         } else {
652
         }
644
         }
653
         const user = Object.values(users)[0]
645
         const user = Object.values(users)[0]
654
         const createRaid = adminClient.manageRaid.createRaid
646
         const createRaid = adminClient.manageRaid.createRaid
655
-        const sign = async (raid: Raid, late = false) => await adminClient.signup.sign(user.auth.token.value, user.character, raid, late)
647
+        const sign = async (raid: Raid, late = false) => await adminClient.signup.sign(user.auth.token.value, user.character, raid, late, false)
656
         const buyToken = async (signup: Signup, itemname: string) => await client.ItemManager.buyToken(user.auth.token.value, user.character.charactername, itemname, signup)
648
         const buyToken = async (signup: Signup, itemname: string) => await client.ItemManager.buyToken(user.auth.token.value, user.character.charactername, itemname, signup)
657
         const getCurrency = async (tier: Tiers) => {
649
         const getCurrency = async (tier: Tiers) => {
658
             const dbUser = await client.UserManager.getUser(user.account.username)
650
             const dbUser = await client.UserManager.getUser(user.account.username)
661
 
653
 
662
         createRaid(Raid(0, 'BWL')).then(async (BWL0: Raid) => {
654
         createRaid(Raid(0, 'BWL')).then(async (BWL0: Raid) => {
663
             const T2_0 = await client.ItemManager.getItem(T2[0])
655
             const T2_0 = await client.ItemManager.getItem(T2[0])
664
-            //const BWL0 = await createRaid(Raid(0, 'BWL'))
665
             const signupBWL0 = await sign(BWL0)
656
             const signupBWL0 = await sign(BWL0)
666
             let BWL = await getCurrency(BWL0.tier)
657
             let BWL = await getCurrency(BWL0.tier)
667
             let token = await buyToken(signupBWL0, T2[0])
658
             let token = await buyToken(signupBWL0, T2[0])
676
 
667
 
677
             let reserves = await client.ItemManager.getTokens(user.character, [BWL0.tier], true)
668
             let reserves = await client.ItemManager.getTokens(user.character, [BWL0.tier], true)
678
             let streaks = await client.ItemManager.getTokens(user.character, [BWL0.tier], false)
669
             let streaks = await client.ItemManager.getTokens(user.character, [BWL0.tier], false)
679
-            if (reserves!.length != 1
680
-                || streaks!.length != 0
681
-                || reserves![0].itemname !== T2_0!.itemname
682
-                || reserves![0].level !== 1) {
683
-                console.log("Bad Token status 1", reserves, streaks);
670
+            if (reserves!.length != 1){
671
+                console.log("Expected reserves to be of length 1", reserves);
672
+                done(new Error("Bad token status"))
673
+            }
674
+
675
+            if(streaks!.length != 0){
676
+                console.log("Expected streaks to be of length 0", streaks);
677
+                done(new Error("Bad token status"))
678
+            }
679
+
680
+            if(reserves![0].itemname !== T2_0!.itemname){
681
+                console.log("Expected reserve to to be of item "+T2_0!.itemname, reserves![0]);
682
+                done(new Error("Bad token status"))
683
+            }
684
+            
685
+            if(reserves![0].level !== 2){
686
+                console.log("Expected reserve to to be of level "+2, reserves![0].level);
684
                 done(new Error("Bad Token status"))
687
                 done(new Error("Bad Token status"))
685
-                return
686
             }
688
             }
689
+
687
             await adminClient.manageRaid.startRaid(BWL0)
690
             await adminClient.manageRaid.startRaid(BWL0)
688
             reserves = await client.ItemManager.getTokens(user.character, [BWL0.tier], true)
691
             reserves = await client.ItemManager.getTokens(user.character, [BWL0.tier], true)
689
             streaks = await client.ItemManager.getTokens(user.character, [BWL0.tier], false)
692
             streaks = await client.ItemManager.getTokens(user.character, [BWL0.tier], false)
691
                 || streaks!.length != 1
694
                 || streaks!.length != 1
692
                 || streaks![0].itemname !== T2[0]
695
                 || streaks![0].itemname !== T2[0]
693
                 || streaks![0].level !== 1) {
696
                 || streaks![0].level !== 1) {
694
-                console.log("Bad Token status", reserves, streaks);
697
+                console.log("Bad Token status 2", reserves, streaks);
695
                 done(new Error("Bad Token status 2"))
698
                 done(new Error("Bad Token status 2"))
696
                 return
699
                 return
697
             }
700
             }
726
             if (reserves!.length != 1
729
             if (reserves!.length != 1
727
                 || streaks!.length != 0
730
                 || streaks!.length != 0
728
                 || reserves![0].itemname !== T2[1]
731
                 || reserves![0].itemname !== T2[1]
729
-                || reserves![0].level !== 1) {
730
-                console.log("Bad Token status", reserves, streaks);
732
+                || reserves![0].level !== 2) {
733
+                console.log("Bad Token status 3", reserves, streaks);
731
                 done(new Error("Bad Token status 3"))
734
                 done(new Error("Bad Token status 3"))
732
                 return
735
                 return
733
             }
736
             }

Loading…
Cancel
Save