浏览代码

visual polish and bugfixes. auto-refreshing

master
peter 5 年前
父节点
当前提交
18f3b32e3c

+ 3
- 3
package-lock.json 查看文件

@@ -6130,9 +6130,9 @@
6130 6130
       }
6131 6131
     },
6132 6132
     "rpclibrary": {
6133
-      "version": "1.7.0",
6134
-      "resolved": "https://registry.npmjs.org/rpclibrary/-/rpclibrary-1.7.0.tgz",
6135
-      "integrity": "sha512-HIL5YzFF53fACOWvI403hJZnGYoXLJGrGc0n1HYZH6rnnfEaBcogemZrCbyoOvnG204LH882e8VdpB+WBTEY/g==",
6133
+      "version": "1.7.1",
6134
+      "resolved": "https://registry.npmjs.org/rpclibrary/-/rpclibrary-1.7.1.tgz",
6135
+      "integrity": "sha512-Ibo3qfURnQgZAq0eA2o+L9+PWaloJ4PHZs4ak42LL9fRgdWZXn33HAtowV0K2HVckbvrBvFqj/+PWTrWWBSOeg==",
6136 6136
       "requires": {
6137 6137
         "bsock": "^0.1.9",
6138 6138
         "http": "0.0.0",

+ 11
- 10
package.json 查看文件

@@ -5,15 +5,16 @@
5 5
   "scripts": {
6 6
     "tsc": "tsc",
7 7
     "launch": "node lib/src/backend/Launcher.js",
8
-    "start": "npm run build; npm run launch",
9
-    "start-backend": "npm run build-backend; node lib/src/backend/Launcher.js",
10
-    "build": "npm run build-backend; npm run build-frontend",
11
-    "test": "npm run clean && npm run build-backend && mocha lib/test/backendTest.js",
12
-    "build-backend": "tsc;",
13
-    "build-frontend": "mkdir dist; mkdir dist/static; npm run build-dashboard;",
14
-    "build-dashboard": "cd src/frontend; npm i && npm run build; cp -r dist/* ../../dist/static",
15
-    "clean": "rm -rf lib plugins conf widget .rpt2_cache *.js *.ts src/frontend/dist data",
16
-    "update-frontblock": "npm remove frontblock frontblock-generic; npm install frontblock-generic@latest frontblock@latest",
8
+    "start": "npm run build && npm run launch",
9
+    "start-backend": "npm run build-backend && npm run launch",
10
+    "test": "npm run backend && npm run build-backend && mocha lib/test/backendTest.js",
11
+    "build": "npm run build-backend && npm run build-frontend",
12
+    "build-backend": "npm run clean-backend && tsc",
13
+    "build-frontend": "npm run clean-frontend && (mkdir static || rm -rf static/*) && npm run build-dashboard",
14
+    "build-dashboard": "cd src/frontend && npm i && npm run build && cp -r dist/* ../../static",
15
+    "clean": "rm -rf data && npm run clean-backend && npm run clean-frontend",
16
+    "clean-backend": "rm -rf lib plugins config widget .rpt2_cache *.js *.ts",
17
+    "clean-frontend": "rm -rf src/frontend/dist static",
17 18
     "webpack": "webpack --config src/backend/webpack.prod.js --progress --colors"
18 19
   },
19 20
   "repository": {
@@ -44,7 +45,7 @@
44 45
     "path": "^0.12.7",
45 46
     "reflect-metadata": "^0.1.13",
46 47
     "rimraf": "^3.0.0",
47
-    "rpclibrary": "^1.7.0",
48
+    "rpclibrary": "^1.7.1",
48 49
     "simple-git": "^1.124.0",
49 50
     "spawn-sync": "^2.0.0",
50 51
     "sqlite3": "^4.1.1",

+ 8
- 4
src/backend/Admin/Admin.ts 查看文件

@@ -20,6 +20,7 @@ import { FrontworkComponent } from '../Types/FrontworkComponent';
20 20
 import { IAdmin } from './Interface';
21 21
 import { Injector } from '../Injector/Injector';
22 22
 import { Shoutbox } from '../Components/Shoutbox/Shoutbox';
23
+import { PubSub } from '../Components/PubSub/PubSub';
23 24
 
24 25
 
25 26
 const logger = getLogger("admin", 'debug') 
@@ -32,7 +33,8 @@ const logger = getLogger("admin", 'debug')
32 33
         RaidManager,
33 34
         CharacterManager,
34 35
         UserManager,
35
-        Shoutbox
36
+        Shoutbox,
37
+        PubSub
36 38
     ]
37 39
 })
38 40
 export class FrontworkAdmin 
@@ -54,7 +56,7 @@ implements TableDefinitionExporter, IAdmin {
54 56
                     dbConf: {
55 57
                         client: 'sqlite3',
56 58
                         connection: {
57
-                            filename: Path.join(__dirname, "data/frontworkAdmin.sqlite")
59
+                            filename: Path.resolve(__dirname, '../../../..', "data/frontworkAdmin.sqlite")
58 60
                         },
59 61
                         useNullAsDefault: true,
60 62
                     }
@@ -96,7 +98,9 @@ implements TableDefinitionExporter, IAdmin {
96 98
     getTableDefinitions(): TableDefiniton[]{
97 99
         return [
98 100
             ...this.frontworkComponents
99
-        ].flatMap(exporter => exporter.getTableDefinitions())
101
+        ]
102
+        .filter(exp => exp.getTableDefinitions != null)
103
+        .flatMap(exp => exp.getTableDefinitions())
100 104
     }
101 105
 
102 106
     private startWebsocket(){
@@ -123,7 +127,7 @@ implements TableDefinitionExporter, IAdmin {
123 127
         
124 128
         let port:number = this.config.getConfig().httpPort
125 129
         this.express = express()
126
-        this.express.use('/', express.static('dist/static'))
130
+        this.express.use('/', express.static('static'))
127 131
 
128 132
         /**
129 133
          * get the compiled FrontendPlugins.js

+ 25
- 4
src/backend/Components/Item/ItemManager.ts 查看文件

@@ -1,14 +1,16 @@
1
-import { T1, T2, allItems, _Tiers, Tiers } from "../../Types/Items";
1
+import { allItems, _Tiers, Tiers } from "../../Types/Items";
2 2
 import { Inject, Injectable } from "../../Injector/ServiceDecorator";
3 3
 import { ItemManagerFeatureIfc, ItemManagerIfc } from "./RPCInterface";
4 4
 import { FrontworkComponent } from "../../Types/FrontworkComponent";
5 5
 import { TableDefinitionExporter } from "../../Types/Interfaces";
6
-import { TableDefiniton, Item, User, Character, SRToken, SRPriority, Spec, Signup } from "../../Types/Types";
6
+import { TableDefiniton, Item, User, Character, SRToken, SRPriority, Spec, Signup, Raid } from "../../Types/Types";
7 7
 import { IAdmin } from "../../Admin/Interface";
8 8
 import { IItemManager } from "./Interface";
9 9
 import { getLogger } from "log4js";
10 10
 import { IUserManager } from "../User/Interface";
11 11
 import { ICharacterManager } from "../Character/Interface";
12
+import { IPubSub } from "../PubSub/Interface";
13
+import { IRaidManager } from "../Raid/Interface";
12 14
 
13 15
 const fetch = require('node-fetch')
14 16
 const xml2js = require('xml2js');
@@ -28,6 +30,12 @@ implements FrontworkComponent<ItemManagerIfc, ItemManagerFeatureIfc>, TableDefin
28 30
     @Inject(ICharacterManager)
29 31
     private character: ICharacterManager
30 32
 
33
+    @Inject(IPubSub)
34
+    private pubsub: IPubSub<any>
35
+
36
+    @Inject(IRaidManager)
37
+    private raidManager: IRaidManager
38
+
31 39
     exportRPCs = () => [
32 40
         this.getItems,
33 41
         this.getItem,
@@ -51,6 +59,16 @@ implements FrontworkComponent<ItemManagerIfc, ItemManagerFeatureIfc>, TableDefin
51 59
         ]
52 60
     }]
53 61
 
62
+    notifyRaid = async (raid:Raid | {id:number}) => {
63
+        const data = await this.raidManager.getRaidData(<Raid>raid)
64
+        this.pubsub.publish(""+raid.id, data)
65
+        await this.notifyRaids()
66
+    }
67
+
68
+    notifyRaids = async () => {
69
+        this.pubsub.publish('raids', undefined)
70
+    }
71
+
54 72
     wipeCurrencyAndItems = async () => {
55 73
         await Promise.all([
56 74
             this.userManager.wipeCurrency(),
@@ -140,13 +158,12 @@ implements FrontworkComponent<ItemManagerIfc, ItemManagerFeatureIfc>, TableDefin
140 158
 
141 159
         await this.userManager.decrementCurrency(record.user, item.tier, 1)
142 160
         const modifier = await this.calculatePriorities(itemname, character)
143
-
161
+        
144 162
         const tx = await this.admin.knex.transaction()
145 163
 
146 164
         if(streaks.length > 0){
147 165
             const myStreak = streaks.find(token => token.itemname === itemname)
148 166
             if(myStreak){
149
-
150 167
                 //getLogger('ItemManager').debug('update signupid and increment level')
151 168
                 await this.admin
152 169
                 .knex(item.tier+'tokens')
@@ -176,6 +193,8 @@ implements FrontworkComponent<ItemManagerIfc, ItemManagerFeatureIfc>, TableDefin
176 193
 
177 194
             if(myStreak){
178 195
                 await tx.commit()
196
+                await this.notifyRaid({id: signup.raidid})
197
+
179 198
                 return await this.getToken(character, item)
180 199
             }
181 200
         }
@@ -205,6 +224,8 @@ implements FrontworkComponent<ItemManagerIfc, ItemManagerFeatureIfc>, TableDefin
205 224
             })
206 225
         }
207 226
         await tx.commit()
227
+        await this.notifyRaid({id: signup.raidid})
228
+
208 229
         return await this.getToken(character, item)
209 230
     }
210 231
 

+ 7
- 0
src/backend/Components/PubSub/Interface.ts 查看文件

@@ -0,0 +1,7 @@
1
+import { SubscriptionResponse } from "rpclibrary"
2
+
3
+export class IPubSub<UpdateType>{
4
+    publish: (topic: string, p: UpdateType) => void
5
+    subscribe: (topic:string, callback: (p:UpdateType)=>any) => Promise<SubscriptionResponse>
6
+    unsubscribe: (uuid: string) => Promise<void>
7
+}

+ 53
- 0
src/backend/Components/PubSub/PubSub.ts 查看文件

@@ -0,0 +1,53 @@
1
+import { Injectable } from "../../Injector/ServiceDecorator";
2
+import { SubscriptionResponse, makeSubResponse, RPCExporter } from "rpclibrary";
3
+import { IPubSub } from "./Interface";
4
+
5
+@Injectable(IPubSub)
6
+export class PubSub<UpdateType = any>
7
+implements RPCExporter{
8
+    name = "PubSub"
9
+    subs : {
10
+        [topic in string]: {
11
+            [uuid in string]: (p:UpdateType)=>any
12
+        }
13
+    }= {}
14
+
15
+    exportRPCs = () => [
16
+        this.unsubscribe,
17
+        {
18
+            name: 'subscribe',
19
+            hook: this.subscribe,
20
+            onClose: (subres, rpcName) => {
21
+                this.unsubscribe(subres.uuid)
22
+            }
23
+        }
24
+    ]
25
+
26
+    publish = ( topic: string, msg: UpdateType ) => {
27
+        if(!this.subs[topic]) this.subs[topic] = {}
28
+        Object.entries(this.subs[topic]).forEach(([uuid, callback]:[string, Function]) => {
29
+            try{
30
+                callback(msg)
31
+            }catch(e){
32
+                delete this.subs[topic][uuid]
33
+            }
34
+        })
35
+    }
36
+
37
+    subscribe = async (topic:string, callback:(p:UpdateType)=>any) : Promise<SubscriptionResponse<{topic: string}>> => {
38
+        const resp = makeSubResponse({
39
+            topic: topic
40
+        })
41
+        if(!this.subs[topic]) this.subs[topic] = {}
42
+        this.subs[topic][resp.uuid] = callback
43
+        return resp
44
+    }
45
+
46
+    private unsubscribe = async (uuid: string) => {
47
+        Object.entries(this.subs).forEach(([topic, submap]) => {           
48
+            delete submap[uuid]
49
+            if(Object.keys(submap).length === 0)
50
+                delete this.subs[topic]
51
+        })
52
+    }
53
+}

+ 8
- 0
src/backend/Components/PubSub/RPCInterface.ts 查看文件

@@ -0,0 +1,8 @@
1
+import { IPubSub } from "./Interface";
2
+
3
+export type PubSubIfc<UpdateType = any> = {
4
+    PubSub:{
5
+        subscribe: IPubSub<UpdateType>['subscribe']
6
+        unsubscribe: IPubSub<UpdateType>['unsubscribe']
7
+    }
8
+}

+ 242
- 214
src/backend/Components/Raid/RaidManager.ts 查看文件

@@ -9,11 +9,12 @@ import { ICharacterManager } from "../Character/Interface";
9 9
 import { _Tiers } from "../../Types/Items";
10 10
 import { IItemManager } from "../Item/Interface";
11 11
 import { ItemManager } from "../Item/ItemManager";
12
+import { IPubSub } from "../PubSub/Interface";
12 13
 
13 14
 @Injectable(IRaidManager)
14 15
 export class RaidManager
15
-implements FrontworkComponent<RaidManagerIfc, RaidManagerFeatureIfc>, IRaidManager{
16
-    name = "RaidManager" as "RaidManager";    
16
+    implements FrontworkComponent<RaidManagerIfc, RaidManagerFeatureIfc>, IRaidManager {
17
+    name = "RaidManager" as "RaidManager";
17 18
 
18 19
     @Inject(IAdmin)
19 20
     private admin: IAdmin
@@ -27,6 +28,9 @@ implements FrontworkComponent<RaidManagerIfc, RaidManagerFeatureIfc>, IRaidManag
27 28
     @Inject(ItemManager)
28 29
     private itemManager: IItemManager
29 30
 
31
+    @Inject(IPubSub)
32
+    private pubsub: IPubSub<any>
33
+
30 34
     exportRPCs = () => [
31 35
         this.getRaids,
32 36
         this.getRaidData,
@@ -46,7 +50,7 @@ implements FrontworkComponent<RaidManagerIfc, RaidManagerFeatureIfc>, IRaidManag
46 50
                 this.startRaid,
47 51
                 this.adminUnsign
48 52
             ]
49
-        },{
53
+        }, {
50 54
             name: 'signup' as 'signup',
51 55
             exportRPCs: () => [
52 56
                 this.getSignups,
@@ -55,7 +59,7 @@ implements FrontworkComponent<RaidManagerIfc, RaidManagerFeatureIfc>, IRaidManag
55 59
             ]
56 60
         }]
57 61
     }
58
-    
62
+
59 63
     getTableDefinitions(): TableDefiniton[] {
60 64
         return [
61 65
             {
@@ -68,13 +72,13 @@ implements FrontworkComponent<RaidManagerIfc, RaidManagerFeatureIfc>, IRaidManag
68 72
                     table.integer('size').defaultTo(40)
69 73
                     table.string('tier').defaultTo('null')
70 74
                 }
71
-            },{
75
+            }, {
72 76
                 name: 'archive',
73 77
                 tableBuilder: (table) => {
74 78
                     table.integer('id').primary()
75 79
                     table.json('raiddata').notNullable()
76 80
                 }
77
-            },{
81
+            }, {
78 82
                 name: 'signups',
79 83
                 tableBuilder: (table) => {
80 84
                     table.increments('id').primary()
@@ -86,55 +90,67 @@ implements FrontworkComponent<RaidManagerIfc, RaidManagerFeatureIfc>, IRaidManag
86 90
                     table.boolean('benched').defaultTo('false')
87 91
                     table.boolean('late')
88 92
                 }
89
-            }            
93
+            }
90 94
         ]
91 95
     }
92 96
 
93
-    createRaid = async (raid:Raid) : Promise<Raid>=> {
94
-        const ids:number[] = await this.admin
95
-        .knex('raids')
96
-        .insert(raid)
97
+    notifyRaid = async (raid:Raid | {id:number}) => {
98
+        const data = await this.getRaidData(<Raid>raid)
99
+        this.pubsub.publish(""+raid.id, data)
100
+        await this.notifyRaids()
101
+    }
97 102
 
98
-        return await this.admin.knex('raids').where({id: ids[0]}).first()
103
+    notifyRaids = async () => {
104
+        this.pubsub.publish('raids', undefined)
99 105
     }
100 106
 
101
-    addSignup = async (signup: Signup) => {
107
+    createRaid = async (raid: Raid): Promise<Raid> => {
108
+        const ids: number[] = await this.admin
109
+            .knex('raids')
110
+            .insert(raid)
102 111
 
103
-        const ids:number[] = await this.admin
104
-        .knex('signups')
105
-        .insert(signup)
106
-        return await this.admin.knex('signups').where({id: ids[0]}).first()
112
+        await this.notifyRaid({ id: ids[0] })
107 113
 
114
+        return await this.admin.knex('raids').where({ id: ids[0] }).first()
108 115
     }
109 116
 
110
-    removeSignup = async (signup: Signup) => await this.admin
111
-    .knex('signups')
112
-    .where({
113
-        raid_id: signup.raidid, 
114
-        character_id: signup.characterid
115
-    })
116
-    .del()
117
+    addSignup = async (signup: Signup) => {
117 118
 
118
-    getRaids = async () : Promise<Raid[]> => {
119
+        const ids: number[] = await this.admin
120
+            .knex('signups')
121
+            .insert(signup)
122
+        return await this.admin.knex('signups').where({ id: ids[0] }).first()
119 123
 
120
-        const subQuery = this.admin
124
+    }
125
+
126
+    removeSignup = async (signup: Signup) => await this.admin
121 127
         .knex('signups')
122
-        .count('*')
123 128
         .where({
124
-            raidid: this.admin.knex.ref('raids.id'),
125
-            benched: false,
126
-            late: false
129
+            raid_id: signup.raidid,
130
+            character_id: signup.characterid
127 131
         })
128
-        .as('signupcount')
129
-        
132
+        .del()
133
+
134
+    getRaids = async (): Promise<Raid[]> => {
135
+
136
+        const subQuery = this.admin
137
+            .knex('signups')
138
+            .count('*')
139
+            .where({
140
+                raidid: this.admin.knex.ref('raids.id'),
141
+                benched: false,
142
+                late: false
143
+            })
144
+            .as('signupcount')
145
+
130 146
         return await this.admin.knex('raids')
131
-        .select('*', subQuery)
132
-        .orderBy('start', 'asc')
147
+            .select('*', subQuery)
148
+            .orderBy('start', 'asc')
133 149
     }
134 150
 
135
-    startRaid = async (raid:Raid) : Promise<RaidData> => {
151
+    startRaid = async (raid: Raid): Promise<RaidData> => {
136 152
         const archived = await this.archiveRaid(raid)
137
-        
153
+
138 154
         const giveCurrency = async (b: Character) => {
139 155
             const usr = await this.characterManager.getUserOfCharacter(b)
140 156
             await this.userManager.incrementCurrency(usr, raid.tier, 1)
@@ -142,122 +158,125 @@ implements FrontworkComponent<RaidManagerIfc, RaidManagerFeatureIfc>, IRaidManag
142 158
 
143 159
         await Promise.all([
144 160
             ...archived.participants.bench.map(giveCurrency),
145
-            ...Object.values(archived.participants).map((group: any) => group.map(giveCurrency))
161
+            ...Object.values(archived.participants).flat().flatMap((b:Signup & Character & Spec) => giveCurrency(b))
146 162
         ])
147 163
 
164
+        await this.notifyRaids()
165
+
148 166
         return archived
149 167
     }
150 168
 
151
-    archiveRaid = async (raid:Raid) : Promise<RaidData> => {
169
+    archiveRaid = async (raid: Raid): Promise<RaidData> => {
152 170
         const raidData = await this.getRaidData(raid)
153 171
 
154 172
         //const tx = await this.admin.knex.transaction()
155 173
 
156 174
         await this.admin.knex('archive')
157
-        //.transacting(tx)
158
-        .insert({
159
-            id:raidData.id,
160
-            raiddata: JSON.stringify(raidData)
161
-        })       
175
+            //.transacting(tx)
176
+            .insert({
177
+                id: raidData.id,
178
+                raiddata: JSON.stringify(raidData)
179
+            })
162 180
 
163 181
         await Promise.all(
164
-            Object.values(raidData.participants).flat().flatMap((signup) => this.admin
165
-                .knex(raid.tier+'tokens')
182
+            Object.values(raidData.participants).flat().flatMap((p: (Signup & Character & Spec)) => 
183
+                this.admin
184
+                .knex(raid.tier + 'tokens')
166 185
                 //.transacting(tx)
167 186
                 .where({
168
-                    characterid: signup.characterid,
187
+                    characterid: p.characterid,
169 188
                     signupid: null
170 189
                 })
171 190
                 .del()
172
-        ))
191
+            ))
173 192
 
174 193
         await this.admin.knex('raids')
175
-        //.transacting(tx)
176
-        .where('id', '=', raid.id)
177
-        .del()
194
+            //.transacting(tx)
195
+            .where('id', '=', raid.id)
196
+            .del()
178 197
         //await tx.commit()
179 198
 
180
-    
199
+
181 200
         const row = await this.admin.knex('archive')
182
-        .select('*')
183
-        .where({
184
-            id:raidData.id,
185
-        })
186
-        .first()
201
+            .select('*')
202
+            .where({
203
+                id: raidData.id,
204
+            })
205
+            .first()
187 206
         return JSON.parse(row.raiddata)
188 207
     }
189 208
 
190
-    getArchiveRaid = async(id:number) : Promise<RaidData> => {
209
+    getArchiveRaid = async (id: number): Promise<RaidData> => {
191 210
         const data = await this.admin.knex('archive').select('raiddata').where({
192 211
             id: id
193 212
         }).first()
194
-        
213
+
195 214
         return JSON.parse(data.raiddata)
196 215
     }
197 216
 
198
-    getPastRaids = async(limit: number) : Promise<RaidData[]> => {
217
+    getPastRaids = async (limit: number): Promise<RaidData[]> => {
199 218
         const raids = await this.admin.knex('archive')
200
-        .select('*')
201
-        .orderBy('id', 'desc')
202
-        .limit(limit)
219
+            .select('*')
220
+            .orderBy('id', 'desc')
221
+            .limit(limit)
203 222
 
204 223
         return raids.map(raid => JSON.parse(raid.raiddata))
205 224
     }
206 225
 
207
-    getRaidData = async (raid:Raid) : Promise<RaidData> => {
226
+    getRaidData = async (raid: Raid): Promise<RaidData> => {
208 227
         const raiddata = {
209
-            participants:{
210
-                Druid: <(Signup&Character&Spec)[]>[],
211
-                Hunter: <(Signup&Character&Spec)[]>[],
212
-                Mage: <(Signup&Character&Spec)[]>[],
213
-                Paladin: <(Signup&Character&Spec)[]>[],
214
-                Priest: <(Signup&Character&Spec)[]>[],
215
-                Rogue: <(Signup&Character&Spec)[]>[],
216
-                Shaman: <(Signup&Character&Spec)[]>[],
217
-                Warlock: <(Signup&Character&Spec)[]>[],
218
-                Warrior: <(Signup&Character&Spec)[]>[],
219
-                late: <(Signup&Character&Spec)[]>[],
220
-                bench: <(Signup&Character&Spec)[]>[],
228
+            participants: {
229
+                Druid: <(Signup & Character & Spec)[]>[],
230
+                Hunter: <(Signup & Character & Spec)[]>[],
231
+                Mage: <(Signup & Character & Spec)[]>[],
232
+                Paladin: <(Signup & Character & Spec)[]>[],
233
+                Priest: <(Signup & Character & Spec)[]>[],
234
+                Rogue: <(Signup & Character & Spec)[]>[],
235
+                Shaman: <(Signup & Character & Spec)[]>[],
236
+                Warlock: <(Signup & Character & Spec)[]>[],
237
+                Warrior: <(Signup & Character & Spec)[]>[],
238
+                late: <(Signup & Character & Spec)[]>[],
239
+                bench: <(Signup & Character & Spec)[]>[],
221 240
             },
222
-            tokens:{},
223
-            healers:<(Signup&Character&Spec)[]>[],
224
-            tanks:<(Signup&Character&Spec)[]>[]
241
+            tokens: {},
242
+            healers: <(Signup & Character & Spec)[]>[],
243
+            tanks: <(Signup & Character & Spec)[]>[]
225 244
         }
226 245
         //const tx = await this.admin.knex.transaction()
227 246
 
228 247
         const subQuery = this.admin
229
-        .knex('signups')
230
-        .count('*')
231
-        .where({
232
-            raidid: this.admin.knex.ref('raids.id'),
233
-            benched: false,
234
-            late: false
235
-        })
236
-        .as('signupcount')
248
+            .knex('signups')
249
+            .count('*')
250
+            .where({
251
+                raidid: this.admin.knex.ref('raids.id'),
252
+                benched: false,
253
+                late: false
254
+            })
255
+            .as('signupcount')
237 256
 
238 257
 
239 258
         const raidInDb: Raid = await this.admin.knex('raids')
240
-        .select('*', subQuery)
241
-        //.transacting(tx)
242
-        .where('id','=',raid.id)
243
-        .first()
259
+            .select('*', subQuery)
260
+            //.transacting(tx)
261
+            .where('id', '=', raid.id)
262
+            .first()
244 263
 
245 264
         const characterData: (Signup & Character & Spec)[] = await this.admin
246
-        .knex('signups as s')
247
-        //.transacting(tx)
248
-        .select('s.id as id', 'charactername', 'class', 'specid', 'specname', 'race', 'userid', 'benched', 'late', 'raidid', 'characterid', 'specid')
249
-        .join('raids as r', 's.raidid','=','r.id')
250
-        .join('characters as c', 's.characterid','=','c.id')
251
-        .join('users as u', 'c.userid','=','u.id')
252
-        .join('specs as sp', 'specid','=','sp.id')
253
-        .where('r.id','=',raid.id)
254
-        
265
+            .knex('signups as s')
266
+            //.transacting(tx)
267
+            .select('s.id as id', 'charactername', 'class', 'specid', 'specname', 'race', 'userid', 'benched', 'late', 'raidid', 'characterid', 'specid')
268
+            .join('raids as r', 's.raidid', '=', 'r.id')
269
+            .join('characters as c', 's.characterid', '=', 'c.id')
270
+            .join('users as u', 'c.userid', '=', 'u.id')
271
+            .join('specs as sp', 'specid', '=', 'sp.id')
272
+            .where('r.id', '=', raid.id)
273
+
255 274
         characterData.forEach(data => {
256
-            if(data.benched){
275
+            if (data.benched) {
257 276
                 raiddata.participants.bench.push(data)
258 277
                 return
259 278
             }
260
-            if(data.late){
279
+            if (data.late) {
261 280
                 raiddata.participants.late.push(data)
262 281
                 return
263 282
             }
@@ -265,42 +284,42 @@ implements FrontworkComponent<RaidManagerIfc, RaidManagerFeatureIfc>, IRaidManag
265 284
         })
266 285
 
267 286
         const tokenData: (Character & SRToken & Item)[] = await this.admin
268
-        .knex('signups as s')
269
-        //.transacting(tx)
270
-        .select('*', 's.id as id')
271
-        .join('raids as r', 's.raidid','=','r.id')
272
-        .join('characters as c', 's.characterid','=','c.id')
273
-        .join(raidInDb.tier+'tokens as t', 't.characterid','=','c.id')
274
-        .join('items as i', 'i.itemname','=','t.itemname')
275
-        .where({
276
-            'r.id': raid.id,
277
-        })
278
-        .andWhere(function(){
279
-            this.whereNotNull('t.signupid')
280
-        })
287
+            .knex('signups as s')
288
+            //.transacting(tx)
289
+            .select('*', 's.id as id')
290
+            .join('raids as r', 's.raidid', '=', 'r.id')
291
+            .join('characters as c', 's.characterid', '=', 'c.id')
292
+            .join(raidInDb.tier + 'tokens as t', 't.characterid', '=', 'c.id')
293
+            .join('items as i', 'i.itemname', '=', 't.itemname')
294
+            .where({
295
+                'r.id': raid.id,
296
+            })
297
+            .andWhere(function () {
298
+                this.whereNotNull('t.signupid')
299
+            })
281 300
 
282 301
         //await tx.commit()
283 302
 
284 303
         tokenData.forEach(data => {
285
-            if(!raiddata.tokens[data.itemname])
304
+            if (!raiddata.tokens[data.itemname])
286 305
                 raiddata.tokens[data.itemname] = []
287 306
             raiddata.tokens[data.itemname].push(data)
288 307
         })
289 308
 
290 309
         raiddata.tanks = Object.values(raiddata.participants).flatMap(
291
-            (tanks:any[]) => tanks.filter((p:any) => 
292
-                !p.benched 
293
-                && !p.late 
294
-                && (p.specname==="Protection" 
295
-                    || p.specname==="Feral (Tank)"))
310
+            (tanks: any[]) => tanks.filter((p: any) =>
311
+                !p.benched
312
+                && !p.late
313
+                && (p.specname === "Protection"
314
+                    || p.specname === "Feral (Tank)"))
296 315
         )
297 316
         raiddata.healers = Object.values(raiddata.participants).flatMap(
298
-            (healers:any[]) => healers.filter((p:any) => 
299
-                !p.benched 
300
-                && !p.late 
301
-                && (p.specname==="Holy" 
302
-                    || p.specname==="Discipline" 
303
-                    || p.specname==="Restoration"))
317
+            (healers: any[]) => healers.filter((p: any) =>
318
+                !p.benched
319
+                && !p.late
320
+                && (p.specname === "Holy"
321
+                    || p.specname === "Discipline"
322
+                    || p.specname === "Restoration"))
304 323
         )
305 324
 
306 325
         return {
@@ -308,128 +327,137 @@ implements FrontworkComponent<RaidManagerIfc, RaidManagerFeatureIfc>, IRaidManag
308 327
             ...raiddata
309 328
         }
310 329
     }
311
-    
312
-    getSignups = async (raid:Raid) : Promise<(Signup & Character & Spec & User)[]> => await this.admin
313
-    .knex('signups as si')
314
-    .join('characters as c', 'c.id', '=', 'characterid')
315
-    .join('specs as s', 's.id', '=', 'specid')
316
-    .join('users as u', 'u.id', '=', 'userid')
317
-    .select('*','si.id as id')
318
-    .where('raidid', '=', raid.id!)
319
-    
320
-    sign = async (usertoken:string, character:Character, raid:Raid, late:boolean) => {
330
+
331
+    getSignups = async (raid: Raid): Promise<(Signup & Character & Spec & User)[]> => await this.admin
332
+        .knex('signups as si')
333
+        .join('characters as c', 'c.id', '=', 'characterid')
334
+        .join('specs as s', 's.id', '=', 'specid')
335
+        .join('users as u', 'u.id', '=', 'userid')
336
+        .select('*', 'si.id as id')
337
+        .where('raidid', '=', raid.id!)
338
+
339
+    sign = async (usertoken: string, character: Character, raid: Raid, late: boolean) => {
321 340
         const maybeUserRecord = this.userManager.getUserRecordByToken(usertoken)
322
-        if(!maybeUserRecord || maybeUserRecord.user.id != character.userid){
341
+        if (!maybeUserRecord || maybeUserRecord.user.id != character.userid) {
323 342
             throw new Error("Bad Usertoken")
324 343
         }
325 344
         //const tx = await this.admin.knex.transaction()
326 345
 
327 346
         const exists = await this.admin
328
-        .knex('signups')
329
-        //.transacting(tx)
330
-        .select('*')
331
-        .where({
332
-            raidid: raid.id!,
333
-            characterid: character.id!,
334
-        })
335
-        .first()
336
-
337
-        if(!exists){
338
-            await this.admin
339 347
             .knex('signups')
340 348
             //.transacting(tx)
341
-            .insert({
349
+            .select('*')
350
+            .where({
342 351
                 raidid: raid.id!,
343 352
                 characterid: character.id!,
344
-                late: late,
345
-                benched: false,
346 353
             })
347
-        }else{
354
+            .first()
355
+
356
+        if (!exists) {
357
+            await this.admin
358
+                .knex('signups')
359
+                //.transacting(tx)
360
+                .insert({
361
+                    raidid: raid.id!,
362
+                    characterid: character.id!,
363
+                    late: late,
364
+                    benched: false,
365
+                })
366
+        } else {
348 367
             await this.admin
368
+                .knex('signups')
369
+                //.transacting(tx)
370
+                .where({
371
+                    id: exists.id
372
+                })
373
+                .update({
374
+                    raidid: raid.id!,
375
+                    characterid: character.id!,
376
+                    late: late,
377
+                    benched: false,
378
+                })
379
+        }
380
+        //await tx.commit()
381
+
382
+        await this.notifyRaid(raid)
383
+        
384
+        return await this.admin
349 385
             .knex('signups')
350
-            //.transacting(tx)
386
+            .select('*')
351 387
             .where({
352
-                id: exists.id 
353
-            })
354
-            .update({
355 388
                 raidid: raid.id!,
356 389
                 characterid: character.id!,
357
-                late: late,
358
-                benched: false,
359 390
             })
360
-        }
361
-        //await tx.commit()
362
-
363
-        return await this.admin
364
-        .knex('signups')
365
-        .select('*')
366
-        .where({
367
-            raidid: raid.id!,
368
-            characterid: character.id!,
369
-        })
370
-        .first()
391
+            .first()
371 392
     }
372 393
 
373
-    unsign = async (usertoken:string, character:Character, raid:Raid) => {
394
+    unsign = async (usertoken: string, character: Character, raid: Raid) => {
374 395
         const maybeUserRecord = this.userManager.getUserRecordByToken(usertoken)
375
-        if(!maybeUserRecord || maybeUserRecord.user.id != character.userid){
396
+        if (!maybeUserRecord || maybeUserRecord.user.id != character.userid) {
376 397
             throw new Error("Bad Usertoken")
377 398
         }
378 399
 
379
-        return await this.adminUnsign(character, raid)       
400
+        return await this.adminUnsign(character, raid)
380 401
     }
381 402
 
382
-    adminUnsign = async (character:Character, raid:Raid) => {
383
-        
403
+    adminUnsign = async (character: Character, raid: Raid) => {
404
+
384 405
         const user = await this.characterManager.getUserOfCharacter(character)
385 406
 
386 407
         const signup = await this.admin.knex('signups as si')
387
-        .where({
388
-            "si.raidid": raid.id!,
389
-            "si.characterid": character.id!,
390
-        }).first()
408
+            .where({
409
+                "si.raidid": raid.id!,
410
+                "si.characterid": character.id!,
411
+            }).first()
412
+
413
+        const tokens = await this.itemManager.getTokens(character, [raid.tier], true)
391 414
 
392
-        const tokens = await this.admin.knex(raid.tier+'tokens as t')
393
-        .where('t.signupid', signup.id)
394
-        
395 415
         //check if token has to be deleted
396
-        Promise.all(
397
-            tokens.map(async token => {
398
-                await this.userManager.incrementCurrency(user, raid.tier, 1)       
399
-                const prio = await this.itemManager.calculatePriorities(token.itemname, character)
400
-                if(token.level <= prio+1){
401
-                    await this.admin.knex(raid.tier+'tokens')
402
-                    .where({
403
-                        characterid: character.id,
404
-                        itemname: token.itemname
405
-                    }).del()
406
-                }else{
407
-                    await this.admin.knex(raid.tier+'tokens')
408
-                    .where({
409
-                        characterid: character.id,
410
-                        itemname: token.itemname
411
-                    }).update({
412
-                        signupid: null,
413
-                        level: token.level-1
414
-                    })
415
-                }
416
-            })
417
-        )
416
+        if (tokens) {
417
+            Promise.all(
418
+                tokens.map(async token => {
419
+                    await this.userManager.incrementCurrency(user, raid.tier, 1)
420
+                    const prio = await this.itemManager.calculatePriorities(token.itemname, character)
421
+                    if (token.level <= prio + 1) {
422
+                        await this.admin
423
+                            .knex(raid.tier + 'tokens')
424
+                            .where({
425
+                                characterid: character.id,
426
+                                itemname: token.itemname
427
+                            }).del()
428
+                    } else {
429
+                        await this.admin
430
+                            .knex(raid.tier + 'tokens')
431
+                            .where({
432
+                                characterid: character.id,
433
+                                itemname: token.itemname
434
+                            }).update({
435
+                                signupid: null,
436
+                                level: token.level - 1
437
+                            })
438
+                    }
439
+                })
440
+            )
441
+        }
418 442
 
419 443
         await this.admin.knex('signups')
420
-        .where({
421
-            raidid: raid.id!,
422
-            characterid: character.id!,
423
-        })
424
-        .del()
444
+            .where({
445
+                raidid: raid.id!,
446
+                characterid: character.id!,
447
+            })
448
+            .del()
449
+
450
+        await this.notifyRaid(raid)
425 451
     }
426 452
 
427
-    setBenched = async (signup: Signup) : Promise<void> => {
453
+    setBenched = async (signup: Signup): Promise<void> => {
428 454
         await this.admin.knex('signups')
429
-        .where({
430
-            raidid: signup.raidid,
431
-            characterid: signup.characterid
432
-        })
433
-        .update(signup)
455
+            .where({
456
+                raidid: signup.raidid,
457
+                characterid: signup.characterid
458
+            })
459
+            .update(signup)
460
+    
461
+        await this.notifyRaid({ id: signup.raidid })
434 462
     }
435 463
 }

+ 0
- 2
src/backend/Components/User/UserManager.ts 查看文件

@@ -455,6 +455,4 @@ implements FrontworkComponent<UserManagerIfc, UserManagerFeatureIfc>, IUserManag
455 455
         .where('id', '=', user.id)
456 456
         .update(tier, value)
457 457
     }
458
-
459
-
460 458
 }

+ 2
- 1
src/backend/Injector/ServiceDecorator.ts 查看文件

@@ -1,6 +1,7 @@
1 1
 import { Injector } from "./Injector";
2 2
 import { Type, GenericClassDecorator } from "./Util";
3 3
 import { FrontworkComponent } from "../Types/FrontworkComponent";
4
+import { RPCExporter } from "rpclibrary";
4 5
 
5 6
 /**
6 7
  * @returns {GenericClassDecorator<Type<any>>}
@@ -21,7 +22,7 @@ export const Injectable = (_interface?: Type<any>) : GenericClassDecorator<Type<
21 22
  */
22 23
 export const RootComponent = (config : {
23 24
     injectable : Type<any>
24
-    injects : Type<FrontworkComponent>[]
25
+    injects : Type<RPCExporter>[]
25 26
   }) : GenericClassDecorator<Type<any>> => {
26 27
   return (target: Type<any>) => {
27 28
     Injector.rootModules = config.injects

+ 2
- 0
src/backend/Types/Types.ts 查看文件

@@ -7,6 +7,7 @@ import { ItemManagerFeatureIfc, ItemManagerIfc } from "../Components/Item/RPCInt
7 7
 import { GuildManagerFeatureIfc, GuildManagerIfc } from "../Components/Guild/RPCInterface";
8 8
 import { ShoutboxIfc } from "../Components/Shoutbox/RPCInterface";
9 9
 import { Tiers } from "./Items";
10
+import { PubSubIfc } from "../Components/PubSub/RPCInterface";
10 11
 
11 12
 export type FrontcraftIfc = RaidManagerIfc
12 13
                           & UserManagerIfc
@@ -14,6 +15,7 @@ export type FrontcraftIfc = RaidManagerIfc
14 15
                           & ItemManagerIfc
15 16
                           & GuildManagerIfc
16 17
                           & ShoutboxIfc
18
+                          & PubSubIfc
17 19
 
18 20
 export type FrontcraftFeatureIfc = RaidManagerFeatureIfc 
19 21
                                  & UserManagerFeatureIfc

+ 3
- 3
src/frontend/package-lock.json 查看文件

@@ -14269,9 +14269,9 @@
14269 14269
       "integrity": "sha512-ZYzRkETgBrdEGzL5JSKimvjI2CX7ioyZCkX2BpcfyjqI+079W0wHAyj5W4rIZMcDSOHgLZtgz1IdDi/vU77KEQ=="
14270 14270
     },
14271 14271
     "rpclibrary": {
14272
-      "version": "1.6.2",
14273
-      "resolved": "https://registry.npmjs.org/rpclibrary/-/rpclibrary-1.6.2.tgz",
14274
-      "integrity": "sha512-lQTU4XkB9CSHz7YgtAcpVfyR5XrmTRX4P4eQjK6DDUjqKSFvJb5ChXjHnt1BcaNWbJ2VqmhCNVbcoyunJ2u7Rg==",
14272
+      "version": "1.7.1",
14273
+      "resolved": "https://registry.npmjs.org/rpclibrary/-/rpclibrary-1.7.1.tgz",
14274
+      "integrity": "sha512-Ibo3qfURnQgZAq0eA2o+L9+PWaloJ4PHZs4ak42LL9fRgdWZXn33HAtowV0K2HVckbvrBvFqj/+PWTrWWBSOeg==",
14275 14275
       "requires": {
14276 14276
         "bsock": "^0.1.9",
14277 14277
         "http": "0.0.0",

+ 1
- 1
src/frontend/package.json 查看文件

@@ -69,7 +69,7 @@
69 69
     "normalize.css": "6.0.0",
70 70
     "pace-js": "1.0.2",
71 71
     "roboto-fontface": "0.8.0",
72
-    "rpclibrary": "^1.6.2",
72
+    "rpclibrary": "^1.7.1",
73 73
     "rxjs": "6.5.2",
74 74
     "rxjs-compat": "6.3.0",
75 75
     "socicon": "3.0.5",

+ 161
- 202
src/frontend/src/app/frontcraft/pages/raid/raid.component.html 查看文件

@@ -1,213 +1,172 @@
1
-<nb-card class="col-12 col-xl-9">
2
-    <nb-card-body>
3
-        <nb-tabset>
4
-            <nb-tab tabTitle="Info">
5
-                <h1>          
6
-                    <img [src]="'../../../../assets/images/'+(raid.tier || 'null').toLowerCase()+'.png'" style="height: 100px" />
7
-                    {{raid.title}}
8
-                </h1>
9
-                <p>
10
-                    {{raid.signupcount}} / {{raid.size}} signups
11
-                </p>
12
-                <p>
13
-                    {{raid.description}}
14
-                </p>
15
-                <div *ngIf="canSignup">
16
-                    <div *ngIf="isSignedup">
17
-
1
+<div class="row">
2
+    <div class="col-12 col-xl-6">
3
+        <nb-card  [size]="giant">
4
+            <nb-card-body>
5
+                <nb-tabset>
6
+                    <nb-tab tabTitle="Info">
7
+                        <h1>
8
+                            <img [src]="'../../../../assets/images/'+(raid.tier || 'null').toLowerCase()+'.png'"
9
+                                style="height: 100px" />
10
+                            {{raid.title}}
11
+                        </h1>
12
+                        <p>
13
+                            {{raid.signupcount}} / {{raid.size}} signups
14
+                        </p>
18 15
                         <p>
19
-                            You are signed as: {{mySignup.charactername}} ({{mySignup.race}} {{mySignup.specname}} {{mySignup.class}})<br />
20
-                            Status: {{mySignup.status}}
16
+                            {{raid.description}}
21 17
                         </p>
22
-                        
23
-                        <button
24
-                            (click)="setLate(true)"
25
-                            *ngIf="mySignup.status !== 'Late'"
26
-                            nbButton 
27
-                            outline 
28
-                            status="warning" 
29
-                            size="medium">
30
-                            <nb-icon icon="clock-outline"></nb-icon> Late
31
-                        </button>        
32
-                        <button
33
-                            (click)="setLate(false)"
34
-                            *ngIf="mySignup.status === 'Late'"
35
-                            nbButton 
36
-                            outline 
37
-                            status="success" 
38
-                            size="medium">
39
-                            <nb-icon icon="checkmark-outline"></nb-icon> On Time
40
-                        </button>  
41
-                        <button
42
-                            (click)="unsign()"
43
-                            nbButton 
44
-                            outline 
45
-                            status="danger" 
46
-                            size="medium">
47
-                            <nb-icon icon="close"></nb-icon>unsign
48
-                        </button>               
49
-                    </div>
50
-                    <div *ngIf="!isSignedup">
51
-                        <button
52
-                            (click)="signup()"
53
-                            nbButton 
54
-                            outline 
55
-                            status="success" 
56
-                            size="medium">
57
-                            <nb-icon icon="person-done-outline"></nb-icon> sign up
58
-                        </button>                     
59
-                    </div>
60
-                </div>
61
-            </nb-tab>
62
-            
63
-            <nb-tab tabTitle="Signups"
64
-              [badgeText]="raid.signupcount"
65
-              badgePosition="top right"
66
-              [badgeStatus]="raid.signupcount<40?'warning':'success'">
67
-                <div class="row">
68
-                    <nb-card
69
-                    class="col-12 col-md-6" 
70
-                    *ngIf="raid.tanks.length > 0">
71
-                        <nb-card-header>Tanks ({{raid.tanks.length}})</nb-card-header>
72
-                        <nb-card-body>
73
-                            <div *ngFor="let participant of raid.tanks">
74
-                                <button
75
-                                    (click)="setBench(participant)"
76
-                                    *ngIf="manageRaid" 
77
-                                    nbButton 
78
-                                    outline 
79
-                                    status="warning" 
80
-                                    size="tiny">
81
-                                    B
18
+                        <div *ngIf="canSignup">
19
+                            <div *ngIf="isSignedup">
20
+
21
+                                <p>
22
+                                    You are signed as: {{mySignup.charactername}} ({{mySignup.race}}
23
+                                    {{mySignup.specname}}
24
+                                    {{mySignup.class}})<br />
25
+                                    Status: {{mySignup.status}}
26
+                                </p>
27
+
28
+                                <button (click)="setLate(true)" *ngIf="mySignup.status !== 'Late'" nbButton outline
29
+                                    status="warning" size="medium">
30
+                                    <nb-icon icon="clock-outline"></nb-icon> Late
82 31
                                 </button>
83
-                                <button
84
-                                    (click)="adminUnsign(participant)"
85
-                                    *ngIf="manageRaid" 
86
-                                    nbButton 
87
-                                    outline 
88
-                                    status="danger" 
89
-                                    size="tiny">
90
-                                    X
32
+                                <button (click)="setLate(false)" *ngIf="mySignup.status === 'Late'" nbButton outline
33
+                                    status="success" size="medium">
34
+                                    <nb-icon icon="checkmark-outline"></nb-icon> On Time
91 35
                                 </button>
92
-                                <a [ngStyle]="{'color': participant.color}" style="text-transform: capitalize;" 
93
-                                [routerLink]="'/frontcraft/character/'+participant.charactername">
94
-                                <img style="width:20px; height:20px" [src]="'../../../../assets/images/'+participant.race.toLowerCase()+'_xs.gif'" />
95
-                                <img style="width:20px; height:20px" [src]="'../../../../assets/images/'+participant.class.toLowerCase()+'.png'" />
96
-                                {{ participant.charactername }}
97
-                                </a>
98
-                            </div>
99
-                        </nb-card-body>
100
-                    </nb-card>
101
-
102
-                    <nb-card
103
-                    class="col-12 col-md-6" 
104
-                    *ngIf="raid.tanks.length > 0">
105
-                        <nb-card-header>Healers ({{raid.healers.length}})</nb-card-header>
106
-                        <nb-card-body>
107
-                            <div *ngFor="let participant of raid.healers">
108
-                                <button
109
-                                    (click)="setBench(participant)"
110
-                                    *ngIf="manageRaid" 
111
-                                    nbButton 
112
-                                    outline 
113
-                                    status="warning" 
114
-                                    size="tiny">
115
-                                    B
36
+                                <button (click)="unsign()" nbButton outline status="danger" size="medium">
37
+                                    <nb-icon icon="close"></nb-icon>unsign
116 38
                                 </button>
117
-                                <button
118
-                                    (click)="adminUnsign(participant)"
119
-                                    *ngIf="manageRaid" 
120
-                                    nbButton 
121
-                                    outline 
122
-                                    status="danger" 
123
-                                    size="tiny">
124
-                                    X
39
+                            </div>
40
+                            <div *ngIf="!isSignedup">
41
+                                <button (click)="signup()" nbButton outline status="success" size="medium">
42
+                                    <nb-icon icon="person-done-outline"></nb-icon> sign up
125 43
                                 </button>
126
-                                <a [ngStyle]="{'color': participant.color}" style="text-transform: capitalize;" 
127
-                                [routerLink]="'/frontcraft/character/'+participant.charactername">
128
-                                <img style="width:20px; height:20px" [src]="'../../../../assets/images/'+participant.race.toLowerCase()+'_xs.gif'" />
129
-                                <img style="width:20px; height:20px" [src]="'../../../../assets/images/'+participant.class.toLowerCase()+'.png'" />
130
-                                {{ participant.charactername }}
131
-                                </a>
132 44
                             </div>
133
-                        </nb-card-body>
134
-                    </nb-card>
135
-
136
-                    <ng-container *ngFor="let group of raid.participants | keyvalue">
137
-                        <nb-card
138
-                        class="col-12 col-md-6 col-xl-4" 
139
-                        *ngIf="group.value.length > 0">
140
-                            <nb-card-header>{{group.key}} ({{group.value.length}})</nb-card-header>
141
-                            <nb-card-body>
142
-                                <div *ngFor="let participant of group.value">
143
-                                    <button
144
-                                        (click)="setBench(participant)"
145
-                                        *ngIf="manageRaid" 
146
-                                        nbButton 
147
-                                        outline 
148
-                                        status="warning" 
149
-                                        size="tiny">
150
-                                        B
151
-                                    </button>
152
-                                    <button
153
-                                        (click)="adminUnsign(participant)"
154
-                                        *ngIf="manageRaid" 
155
-                                        nbButton 
156
-                                        outline 
157
-                                        status="danger" 
158
-                                        size="tiny">
159
-                                        X
160
-                                    </button>
161
-                                    <a [ngStyle]="{'color': participant.color}" style="text-transform: capitalize;" 
162
-                                    [routerLink]="'/frontcraft/character/'+participant.charactername">
163
-                                    <img style="width:20px; height:20px" [src]="'../../../../assets/images/'+participant.race.toLowerCase()+'_xs.gif'" />
164
-                                    <img style="width:20px; height:20px" [src]="'../../../../assets/images/'+participant.class.toLowerCase()+'.png'" />
165
-                                    {{ participant.charactername }}
166
-                                    </a>
167
-                                </div>
168
-                            </nb-card-body>
169
-                        </nb-card>
170
-                    </ng-container>
171
-                </div>
172
-            </nb-tab>
173
-            <nb-tab tabTitle="Items" *ngIf="isSignedup && isTier">
174
-                <shop [tier]="raid.tier" (onSelect)="itemSelect($event)"></shop>
175
-            </nb-tab>
176
-            <nb-tab tabTitle="Reserves" *ngIf="isTier">
177
-                <input type="text" nbInput [(ngModel)]="search" (change)="changeSearch()" placeholder="Search" fullWidth="true">
45
+                        </div>
46
+                    </nb-tab>
47
+                    <nb-tab tabTitle="Signups" [badgeText]="raid.signupcount" badgePosition="top right"
48
+                        [badgeStatus]="raid.signupcount<40?'warning':'success'">
178 49
 
179
-                <nb-list>
180
-                    <nb-list-item *ngFor="let item of displayedtokens | keyvalue">
181
-                        <a [ngStyle]="{'color':item.value[0].quality=='Epic'?'#a335ee':'#ff8000'}" 
182
-                           target="_blank" 
183
-                           [href]="item.value[0].url">
184
-                           <img style="min-width: 25px; width: 2.25vw; max-width: 50px" 
185
-                           [src]="'https://wow.zamimg.com/images/wow/icons/large/'+item.value[0].iconname+'.jpg'" />
186
-                           &nbsp;
187
-                           {{item.key}}
188
-                        </a><br />
189 50
                         <div class="row">
190
-                            <div *ngFor="let token of item.value" class="col-12 col-md-6 col-xl-4">
191
-                                [ {{token.level}} ]  
192
-                                <span style="text-transform: capitalize;" [ngStyle]="{'color':token.level>=10?'#ff8000':token.level>=8?'#a335ee':token.level>=6?'#0070dd':token.level>=4?'#1eff00':token.level>=2?'#ffffff':'#9d9d9d'}">
193
-                                    {{token.charactername}}
194
-                                </span><br />
195
-                            </div>
51
+                            <nb-card class="col-12 col-md-6" *ngIf="raid.tanks.length > 0">
52
+                                <nb-card-header>Tanks ({{raid.tanks.length}})</nb-card-header>
53
+                                <nb-card-body>
54
+                                    <div *ngFor="let participant of raid.tanks">
55
+                                        <button (click)="setBench(participant)" *ngIf="manageRaid" nbButton outline
56
+                                            status="warning" size="tiny">
57
+                                            B
58
+                                        </button>
59
+                                        <button (click)="adminUnsign(participant)" *ngIf="manageRaid" nbButton outline
60
+                                            status="danger" size="tiny">
61
+                                            X
62
+                                        </button>
63
+                                        <a [ngStyle]="{'color': participant.color}" style="text-transform: capitalize;"
64
+                                            [routerLink]="'/frontcraft/character/'+participant.charactername">
65
+                                            <img style="width:20px; height:20px"
66
+                                                [src]="'../../../../assets/images/'+participant.race.toLowerCase()+'_xs.gif'" />
67
+                                            <img style="width:20px; height:20px"
68
+                                                [src]="'../../../../assets/images/'+participant.class.toLowerCase()+'.png'" />
69
+                                            {{ participant.charactername }}
70
+                                        </a>
71
+                                    </div>
72
+                                </nb-card-body>
73
+                            </nb-card>
74
+
75
+                            <nb-card class="col-12 col-md-6" *ngIf="raid.tanks.length > 0">
76
+                                <nb-card-header>Healers ({{raid.healers.length}})</nb-card-header>
77
+                                <nb-card-body>
78
+                                    <div *ngFor="let participant of raid.healers">
79
+                                        <button (click)="setBench(participant)" *ngIf="manageRaid" nbButton outline
80
+                                            status="warning" size="tiny">
81
+                                            B
82
+                                        </button>
83
+                                        <button (click)="adminUnsign(participant)" *ngIf="manageRaid" nbButton outline
84
+                                            status="danger" size="tiny">
85
+                                            X
86
+                                        </button>
87
+                                        <a [ngStyle]="{'color': participant.color}" style="text-transform: capitalize;"
88
+                                            [routerLink]="'/frontcraft/character/'+participant.charactername">
89
+                                            <img style="width:20px; height:20px"
90
+                                                [src]="'../../../../assets/images/'+participant.race.toLowerCase()+'_xs.gif'" />
91
+                                            <img style="width:20px; height:20px"
92
+                                                [src]="'../../../../assets/images/'+participant.class.toLowerCase()+'.png'" />
93
+                                            {{ participant.charactername }}
94
+                                        </a>
95
+                                    </div>
96
+                                </nb-card-body>
97
+                            </nb-card>
98
+
99
+                            <ng-container *ngFor="let group of raid.participants | keyvalue">
100
+                                <nb-card class="col-12 col-md-6 col-xl-4" *ngIf="group.value.length > 0">
101
+                                    <nb-card-header>{{group.key}} ({{group.value.length}})</nb-card-header>
102
+                                    <nb-card-body>
103
+                                        <div *ngFor="let participant of group.value">
104
+                                            <button (click)="setBench(participant)" *ngIf="manageRaid" nbButton outline
105
+                                                status="warning" size="tiny">
106
+                                                B
107
+                                            </button>
108
+                                            <button (click)="adminUnsign(participant)" *ngIf="manageRaid" nbButton
109
+                                                outline status="danger" size="tiny">
110
+                                                X
111
+                                            </button>
112
+                                            <a [ngStyle]="{'color': participant.color}"
113
+                                                style="text-transform: capitalize;"
114
+                                                [routerLink]="'/frontcraft/character/'+participant.charactername">
115
+                                                <img style="width:20px; height:20px"
116
+                                                    [src]="'../../../../assets/images/'+participant.race.toLowerCase()+'_xs.gif'" />
117
+                                                <img style="width:20px; height:20px"
118
+                                                    [src]="'../../../../assets/images/'+participant.class.toLowerCase()+'.png'" />
119
+                                                {{ participant.charactername }}
120
+                                            </a>
121
+                                        </div>
122
+                                    </nb-card-body>
123
+                                </nb-card>
124
+                            </ng-container>
196 125
                         </div>
197
-                    </nb-list-item>
198
-                </nb-list>
199
-            </nb-tab>
200
-            <nb-tab tabTitle="Admin" *ngIf="manageRaid">
201
-                <button
202
-                    (click)="startRaid(raid)"
203
-                    nbButton 
204
-                    outline 
205
-                    status="success" 
206
-                    size="medium">
207
-                    start
208
-                </button>
209
-            </nb-tab>
210
-        </nb-tabset>
211
-    </nb-card-body>
212
-</nb-card>
126
+                    </nb-tab>
127
+                    <nb-tab tabTitle="Admin" *ngIf="manageRaid">
128
+                        <button (click)="startRaid(raid)" nbButton outline status="success" size="medium">
129
+                            start
130
+                        </button>
131
+                    </nb-tab>
132
+                </nb-tabset>
133
+            </nb-card-body>
134
+        </nb-card>
135
+    </div>
136
+    <div class="col-12 col-xl-6">
137
+        <nb-card  *ngIf="isTier">
138
+            <nb-card-body>
139
+                <nb-tabset>
140
+                    <nb-tab tabTitle="Reserves">
141
+                        <input type="text" nbInput [(ngModel)]="search" (change)="changeSearch()" placeholder="Search"
142
+                            fullWidth="true">
213 143
 
144
+                        <nb-list>
145
+                            <nb-list-item *ngFor="let item of displayedtokens | keyvalue">
146
+                                <a [ngStyle]="{'color':item.value[0].quality=='Epic'?'#a335ee':'#ff8000'}"
147
+                                    target="_blank" [href]="item.value[0].url">
148
+                                    <img style="min-width: 25px; width: 2.25vw; max-width: 50px"
149
+                                        [src]="'https://wow.zamimg.com/images/wow/icons/large/'+item.value[0].iconname+'.jpg'" />
150
+                                    &nbsp;
151
+                                    {{item.key}}
152
+                                </a><br />
153
+                                <div class="row">
154
+                                    <div *ngFor="let token of item.value" class="col-12 col-md-6 col-xl-4">
155
+                                        [ {{token.level}} ]
156
+                                        <span style="text-transform: capitalize;"
157
+                                            [ngStyle]="{'color':token.level>=10?'#ff8000':token.level>=8?'#a335ee':token.level>=6?'#0070dd':token.level>=4?'#1eff00':token.level>=2?'#ffffff':'#9d9d9d'}">
158
+                                            {{token.charactername}}
159
+                                        </span><br />
160
+                                    </div>
161
+                                </div>
162
+                            </nb-list-item>
163
+                        </nb-list>
164
+                    </nb-tab>
165
+                    <nb-tab tabTitle="Items" *ngIf="isSignedup">
166
+                        <shop [tier]="raid.tier" (onSelect)="itemSelect($event)"></shop>
167
+                    </nb-tab>
168
+                </nb-tabset>
169
+            </nb-card-body>
170
+        </nb-card>
171
+    </div>
172
+</div>

+ 29
- 11
src/frontend/src/app/frontcraft/pages/raid/raid.component.ts 查看文件

@@ -1,5 +1,5 @@
1
-import { Component, OnInit } from '@angular/core';
2
-import { ActivatedRoute, Router } from '@angular/router';
1
+import { Component, OnInit, OnDestroy } from '@angular/core';
2
+import { ActivatedRoute, Router, NavigationStart } from '@angular/router';
3 3
 import { ApiService as ApiService } from '../../services/login-api';
4 4
 import { RaidData, Raid, Signup, Character, Spec, Item, SRToken } from '../../../../../../backend/Types/Types';
5 5
 import { NbWindowService, NbToastrService, NbDialogService } from '@nebular/theme';
@@ -12,7 +12,7 @@ import { allItems } from '../../../../../../backend/Types/Items';
12 12
   selector: 'raid',
13 13
   templateUrl: './raid.component.html',
14 14
 })
15
-export class FrontcraftRaidComponent implements OnInit{
15
+export class FrontcraftRaidComponent implements OnInit, OnDestroy{
16 16
 
17 17
     canSignup = false
18 18
     isSignedup = false
@@ -41,6 +41,7 @@ export class FrontcraftRaidComponent implements OnInit{
41 41
     tokens = {}
42 42
     displayedtokens = {}
43 43
     search = ""
44
+    uuid
44 45
 
45 46
     constructor(
46 47
       private api: ApiService,
@@ -50,6 +51,16 @@ export class FrontcraftRaidComponent implements OnInit{
50 51
       private toast: NbToastrService
51 52
     ){
52 53
       window['r'] = this
54
+      router.events.subscribe(event => {
55
+        if (event instanceof NavigationStart) {
56
+          this.ngOnDestroy()
57
+        }
58
+      })
59
+    }
60
+
61
+    ngOnDestroy = () => {
62
+      if(this.uuid)
63
+        this.api.get('PubSub').unsubscribe(this.uuid)
53 64
     }
54 65
 
55 66
     async ngOnInit(){
@@ -60,9 +71,16 @@ export class FrontcraftRaidComponent implements OnInit{
60 71
       if(signupFeature){
61 72
         this.canSignup = true
62 73
       }
63
-      this.refresh()
74
+      await this.refresh()
75
+
76
+      const res = await this.api.get('PubSub').subscribe(""+this.raid.id!, (data: RaidData) => {
77
+        this.display(data)
78
+      })
79
+      this.uuid = res.uuid
64 80
     }
65 81
 
82
+ 
83
+
66 84
     itemSelect = async(item) => {
67 85
       this.dialogService.open(FrontcraftBuyTokenComponent, {
68 86
         context: {
@@ -71,7 +89,7 @@ export class FrontcraftRaidComponent implements OnInit{
71 89
           tier: this.raid.tier,
72 90
           characterName: this.mySignup.charactername
73 91
         }
74
-      }).onClose.subscribe(() => this.refresh())
92
+      })
75 93
     }
76 94
 
77 95
     signup = async () => {
@@ -84,9 +102,7 @@ export class FrontcraftRaidComponent implements OnInit{
84 102
         context: {
85 103
           raid: this.raid,
86 104
         } 
87
-      }).onClose.subscribe(()=>{
88
-        this.refresh()
89
-      });
105
+      })
90 106
     }
91 107
 
92 108
     async archiveRaid(raid:Raid){
@@ -110,7 +126,6 @@ export class FrontcraftRaidComponent implements OnInit{
110 126
         id: this.mySignup.characterid, 
111 127
       }, this.raid)
112 128
       this.toast.show('Success', 'Unsigned', { status: 'success' })
113
-      this.refresh()
114 129
     }
115 130
 
116 131
     setLate = async (value:boolean) => {
@@ -123,7 +138,6 @@ export class FrontcraftRaidComponent implements OnInit{
123 138
         id: this.mySignup.characterid,
124 139
       }, this.raid, value)
125 140
       this.toast.show('Signup', 'Success', { status: 'success' })
126
-      this.refresh()
127 141
     }
128 142
 
129 143
     adminUnsign = async() => {
@@ -133,7 +147,6 @@ export class FrontcraftRaidComponent implements OnInit{
133 147
         ...this.mySignup,
134 148
         id: this.mySignup.characterid, 
135 149
       }, this.raid)
136
-      this.refresh()
137 150
     }
138 151
 
139 152
     refresh = async () => {
@@ -143,6 +156,11 @@ export class FrontcraftRaidComponent implements OnInit{
143 156
       const raiddata = await raidManager.getRaidData(<any>{
144 157
         id: param
145 158
       })
159
+      this.display(raiddata)
160
+      
161
+    }
162
+
163
+    display =  async (raiddata:RaidData)  => {
146 164
       this.isTier = allItems[raiddata.tier] != null
147 165
 
148 166
       this.raid = raiddata

+ 24
- 17
src/frontend/src/app/frontcraft/pages/raids/raids.component.html 查看文件

@@ -16,24 +16,31 @@
16 16
     class="raidlist"
17 17
     style="cursor: pointer;">
18 18
       <div class="row">
19
-        <div class="col-2">
20
-          <img [src]="'../../../../assets/images/'+(raid.tier || 'null').toLowerCase()+'.png'" style="height: 75px" />
21
-        </div>
22
-
23
-        <div class="col-2 vcenter">
24
-          {{raid.title}}
25
-         </div>
26
-        
27
-        <div class="col-2 vcenter">
28
-          <nb-icon icon="checkmark-circle"></nb-icon> {{raid.signupcount}} / {{raid.size}}<br>
29
-        </div>
30
-
31
-        <div class="col-2 vcenter">
32
-          <nb-icon icon="clock-outline"></nb-icon> {{raid.start | date : 'HH:mm'}}
33
-        </div>
19
+        <img [src]="'../../../../assets/images/'+(raid.tier || 'null').toLowerCase()+'.png'" 
20
+        style="object-fit: contain"
21
+        class="col-1 col-s-3" />
34 22
 
35
-        <div class="col-4 vcenter">
36
-          <nb-icon icon="calendar-outline"></nb-icon> {{raid.start | date : 'EEEE MMMM d'}}
23
+        <div class="col-11 col-s-9" >
24
+          <div class="row">
25
+            <div class="col-12" style="padding-top: 5px">
26
+              <h4>
27
+                {{raid.title}}
28
+              </h4>
29
+            </div>
30
+          </div>
31
+          <div class="row" style="padding-top: 5px; padding-bottom: 5px; color:darkgray">
32
+            <div class="col-6 col-md-3">
33
+              <nb-icon icon="checkmark-circle"></nb-icon> {{raid.signupcount}} / {{raid.size}}<br>
34
+            </div>
35
+    
36
+            <div class="col-6 col-md-3">
37
+              <nb-icon icon="clock-outline"></nb-icon> {{raid.start | date : 'HH:mm'}}
38
+            </div>
39
+    
40
+            <div class="col-12 col-md-6">
41
+              <nb-icon icon="calendar-outline"></nb-icon> {{raid.start | date : 'EEE MMM d'}}
42
+            </div>
43
+          </div>
37 44
         </div>
38 45
       </div>
39 46
     </nb-list-item>

+ 10
- 3
src/frontend/src/app/frontcraft/pages/raids/raids.component.scss 查看文件

@@ -10,7 +10,14 @@
10 10
   background-color: #293259;
11 11
 }
12 12
 
13
-.vcenter {
14
-  height: 75px;
15
-  padding-top: 30px;
13
+.raid {
14
+  height: 75px
15
+}
16
+
17
+.row {
18
+  margin: -0.5rem;
19
+}
20
+
21
+h4 {
22
+  font-weight: normal
16 23
 }

+ 22
- 6
src/frontend/src/app/frontcraft/pages/raids/raids.component.ts 查看文件

@@ -1,30 +1,48 @@
1
-import { Component, OnInit } from '@angular/core';
1
+import { Component, OnInit, OnDestroy } from '@angular/core';
2 2
 import { ApiService } from '../../services/login-api';
3 3
 import { NbWindowService, NbDialogService } from '@nebular/theme';
4 4
 import { FrontcraftCreateRaidsComponent } from './createraid.compontent';
5
+import { Router, NavigationStart } from '@angular/router';
5 6
 
6 7
 @Component({
7 8
   selector: 'raids',
8 9
   templateUrl: 'raids.component.html',
9 10
   styleUrls: ['raids.component.scss'],
10 11
 })
11
-export class FrontcraftRaidsComponent implements OnInit{
12
+export class FrontcraftRaidsComponent implements OnInit, OnDestroy{
12 13
 
13 14
 
14 15
   manageRaid
15 16
   raids = []
16 17
   oldraids = []
17 18
   pageSize = 10;
19
+  uuid
18 20
 
19 21
   constructor(
20 22
     private api: ApiService,
23
+    private router: Router,
21 24
     private dialogService: NbDialogService
22 25
   ) {
23 26
     this.manageRaid = this.api.get('manageRaid')
27
+    router.events.subscribe(event => {
28
+      if (event instanceof NavigationStart) {
29
+        this.ngOnDestroy()
30
+      }
31
+    })
32
+  }
24 33
 
34
+  ngOnDestroy = () => {
35
+    console.log("boom");
36
+
37
+    if(this.uuid)
38
+      this.api.get('PubSub').unsubscribe(this.uuid)
25 39
   }
26 40
 
27
-  ngOnInit(): void {
41
+  async ngOnInit() {
42
+    const res = await this.api.get('PubSub').subscribe("raids", () => {
43
+      this.refresh()
44
+    })
45
+    this.uuid = res.uuid
28 46
     this.refresh()
29 47
   }
30 48
 
@@ -46,9 +64,7 @@ export class FrontcraftRaidsComponent implements OnInit{
46 64
       context: {
47 65
         templates: this.oldraids
48 66
       } 
49
-    }).onClose.subscribe(()=>{
50
-      this.refresh()
51
-    });
67
+    })
52 68
 
53 69
   }
54 70
 }

+ 58
- 7
src/frontend/src/app/frontcraft/pages/rules/rules.component.html 查看文件

@@ -2,18 +2,69 @@
2 2
     <nb-card-body>
3 3
         <nb-tabset>
4 4
             <nb-tab tabTitle="Info">
5
-                Smart text here
5
+                <h3>How it works</h3>
6
+                <ul>
7
+                    <li>
8
+                        Everyone starts out with 1 soft reserve right per raid tier (you can see them in your user profile)
9
+                    </li>
10
+                    <li>
11
+                        The tiers are: MC+Ony, BWL, ZG, AQ20, AQ40, Naxx
12
+                    </li>
13
+                    <li>
14
+                        You gain 1 reserve right for a raid you attend. 2 if you were benched. Rights are granted on raid start.
15
+                    </li>
16
+                    <li>
17
+                        When you sign up to a raid you can spend your reserve rights
18
+                    </li>
19
+                    <li>
20
+                        Every week you can re-reserve the same item to build a streak on it
21
+                    </li>
22
+                    <!--
23
+                    <li>
24
+                        Steaks are color coded. If this means anything will be decided by guild culture: 
25
+                        <span style="color: #ff8000">[+ 10]</span>
26
+                        <span style="color: #a335ee">[9. 8]</span>
27
+                        <span style="color: #0070dd">[7, 6]</span>
28
+                        <span style="color: #1eff00">[5, 4]</span>
29
+                        <span style="color: #ffffff">[3, 2]</span>
30
+                        <span style="color: #9d9d9d">[1]</span>
31
+                    </li>
32
+                    -->
33
+                </ul>
34
+                <br />
35
+                <h3>Specifics about streaks</h3>
36
+                <ul>
37
+                    <li>
38
+                        Some classes and races get an initial boost to specific reserves. The list is on the second tab. 
39
+                    </li>
40
+                    <li>
41
+                        Switching the selected item destroys previous streaks. (Streaks must be continued without switchup)    
42
+                    </li>
43
+                    <li>
44
+                        If you have more than 1 softreserve you can reserve multiple different items. You may only continue one streak the following raid.
45
+                    </li>
46
+                    <li>
47
+                        If you have more than 1 softreserve you can reserve the same item several times to increase its streak.
48
+                    </li>
49
+                    <li>
50
+                        The softreserve counter, Reserves, and Streaks are tiers-specific and only count within their tier.
51
+                    </li>
52
+                    <li>
53
+                        Canceling the signup refunds active reserves and continued streaks. Destroyed streaks cannot be recovered. 
54
+                    </li>
55
+                </ul>
6 56
             </nb-tab>
7 57
             <nb-tab tabTitle="priorities">
8 58
                 <nb-list>
9 59
                     <nb-list-item *ngFor="let item of rules | keyvalue">
10 60
                         <wowhead [item]="item.value[0]"></wowhead><br>
11
-                        <span *ngFor="let rule of item.value" [nbPopover]="templateRef" nbPopoverTrigger="hover">
12
-                            <ng-template #templateRef>
13
-                                <span style="color:white">{{rule.description}}</span>
14
-                            </ng-template>
15
-                            <span *ngIf="rule.modifier>0">+</span>{{rule.modifier}} {{rule.race}} <span [ngStyle]="{'color':rule.color}">{{rule.specname}} {{rule.class}}</span> <br />
16
-                        </span>
61
+                        <div class="row" *ngFor="let rule of item.value">
62
+                            <div class="col-4">
63
+                                <span *ngIf="rule.modifier>0">+</span>{{rule.modifier}} {{rule.race}} <span [ngStyle]="{'color':rule.color}">{{rule.specname}} {{rule.class}}</span> 
64
+                            </div>
65
+                            <div class="col-8" style="color:white"> ({{rule.description}})</div>
66
+                            <br />
67
+                        </div>
17 68
                     </nb-list-item>
18 69
                 </nb-list>
19 70
             </nb-tab>

+ 312
- 251
test/backendTest.ts 查看文件

@@ -1,6 +1,6 @@
1 1
 import { Injector } from "../src/backend/Injector/Injector";
2 2
 import { FrontworkAdmin } from "../src/backend/Admin/Admin";
3
-import { T1 } from "../src/backend/Types/Items";
3
+import { T1, T2, Tiers } from "../src/backend/Types/Items";
4 4
 
5 5
 import { RPCSocket } from "rpclibrary";
6 6
 import { FrontcraftIfc, Auth, User, FrontcraftFeatureIfc, Raid, Character, Rank, Class, Race, SRPriority, Spec, Signup } from "../src/backend/Types/Types";
@@ -8,9 +8,9 @@ import { SpecT } from "../src/backend/Types/PlayerSpecs";
8 8
 
9 9
 
10 10
 type protoAccount<C extends Class = Class> = {
11
-    name : string,
11
+    name: string,
12 12
     pwHash?: string
13
-    rank : Rank,
13
+    rank: Rank,
14 14
     race: Race,
15 15
     class: C,
16 16
     spec: SpecT[C]
@@ -39,65 +39,72 @@ const adminsOnly = {
39 39
 }
40 40
 
41 41
 const defaultPermissions = [
42
-{   rpcname: 'signup', ...trialsAndUp
43
-},{ rpcname: 'reset', ...adminsOnly 
44
-},{ rpcname: 'modifyPermissions', ...adminsOnly 
45
-},{ rpcname: 'manageGuild', ...adminsOnly
46
-},{ rpcname: 'managePriorities', ...adminsOnly
47
-},{ rpcname: 'softreserveCurrency', ...adminsOnly
48
-},{ rpcname: 'manageRaid', ...adminsOnly
49
-}]
50
-
51
-const testAccounts : protoAccount[] = [
42
+    {
43
+        rpcname: 'signup', ...trialsAndUp
44
+    }, {
45
+        rpcname: 'reset', ...adminsOnly
46
+    }, {
47
+        rpcname: 'modifyPermissions', ...adminsOnly
48
+    }, {
49
+        rpcname: 'manageGuild', ...adminsOnly
50
+    }, {
51
+        rpcname: 'managePriorities', ...adminsOnly
52
+    }, {
53
+        rpcname: 'softreserveCurrency', ...adminsOnly
54
+    }, {
55
+        rpcname: 'manageRaid', ...adminsOnly
56
+    }]
57
+
58
+const testAccounts: protoAccount[] = [
52 59
     {
53 60
         name: 'Rain',
54 61
         race: 'Human',
55 62
         class: 'Warrior',
56 63
         spec: 'Protection',
57 64
         rank: 'Guildmaster'
58
-    },{
65
+    }, {
59 66
         name: 'Celinda',
60 67
         class: 'Warrior',
61 68
         race: 'Night Elf',
62 69
         spec: 'Protection',
63 70
         rank: 'Officer'
64
-    },{
71
+    }, {
65 72
         name: 'Silver',
66 73
         class: 'Druid',
67 74
         race: 'Night Elf',
68 75
         spec: 'Restoration',
69 76
         rank: 'Raider'
70
-    },{
77
+    }, {
71 78
         name: 'Dagger',
72 79
         race: 'Dwarf',
73 80
         class: 'Rogue',
74 81
         spec: 'Assassination',
75 82
         rank: 'Classleader'
76
-    },{
83
+    }, {
77 84
         name: 'Hope',
78 85
         class: 'Paladin',
79 86
         race: 'Human',
80 87
         spec: 'Holy',
81 88
         rank: 'Classleader'
82
-    },{
89
+    }, {
83 90
         name: 'Shrekd',
84 91
         class: 'Warrior',
85 92
         race: 'Dwarf',
86 93
         spec: 'Fury',
87 94
         rank: 'Classleader'
88
-    },{
95
+    }, {
89 96
         name: 'Teeniweeni',
90 97
         class: 'Warlock',
91 98
         race: 'Gnome',
92 99
         spec: 'Demonology',
93 100
         rank: 'Classleader'
94
-    },{
101
+    }, {
95 102
         name: 'Hagibaba',
96 103
         class: 'Priest',
97 104
         race: 'Human',
98 105
         spec: 'Discipline',
99 106
         rank: 'Classleader'
100
-    },{
107
+    }, {
101 108
         name: 'Muffinbreak',
102 109
         class: 'Mage',
103 110
         race: 'Gnome',
@@ -109,18 +116,18 @@ const testAccounts : protoAccount[] = [
109 116
 
110 117
 describe('Frontcraft', () => {
111 118
     let auth: Auth,
112
-        adminUser : User,
119
+        adminUser: User,
113 120
         server: FrontworkAdmin,
114
-        client : RPCSocket & FrontcraftIfc,
115
-        adminClient : RPCSocket & FrontcraftFeatureIfc,
121
+        client: RPCSocket & FrontcraftIfc,
122
+        adminClient: RPCSocket & FrontcraftFeatureIfc,
116 123
         raids: Raid[] = [],
117
-        users : {[username in string] : { account: User, character: Character, auth: Auth, signup?:Signup, item?:string }} = {}
124
+        users: { [username in string]: { account: User, character: Character, auth: Auth, signup?: Signup, item?: string } } = {}
118 125
 
119 126
     const createAccount = (user: User) => {
120 127
         return client.UserManager.createUser(user)
121 128
     }
122 129
 
123
-    const createAccountAndUser = async (acc : protoAccount) => {
130
+    const createAccountAndUser = async (acc: protoAccount) => {
124 131
         const account = await createAccount({
125 132
             pwhash: 'ca978112ca1bbdcafac231b39a23dc4da786eff8147c4e72b9807785afee48bb', //sha256("a")
126 133
             rank: acc.rank,
@@ -141,15 +148,15 @@ describe('Frontcraft', () => {
141 148
         }
142 149
     }
143 150
 
144
-    before(function (done){
145
-        this.timeout(10000); 
151
+    before(function (done) {
152
+        this.timeout(10000);
146 153
 
147 154
         server = Injector.resolve<FrontworkAdmin>(FrontworkAdmin)
148 155
         server.start().then((_server) => {
149
-            
156
+
150 157
             RPCSocket.makeSocket<FrontcraftIfc>(20000, 'localhost').then(_client => {
151 158
                 client = _client
152
-                
159
+
153 160
 
154 161
                 createAccount({
155 162
                     pwhash: 'ca978112ca1bbdcafac231b39a23dc4da786eff8147c4e72b9807785afee48bb', //hash("a")
@@ -160,7 +167,7 @@ describe('Frontcraft', () => {
160 167
 
161 168
                     client.UserManager.login(adminUser.username, 'ca978112ca1bbdcafac231b39a23dc4da786eff8147c4e72b9807785afee48bb').then(auth => {
162 169
                         const sock = new RPCSocket(
163
-                            auth.port, 
170
+                            auth.port,
164 171
                             "localhost"
165 172
                         )
166 173
 
@@ -170,11 +177,11 @@ describe('Frontcraft', () => {
170 177
                                 console.log("I got kicked");
171 178
                             })
172 179
                             sock.hook('getUserData', () => auth)
173
-                            sock.hook('navigate', (where:string) => {
174
-                                console.log("Nagivate client to "+where);
180
+                            sock.hook('navigate', (where: string) => {
181
+                                console.log("Nagivate client to " + where);
175 182
                             })
176 183
                             sock.on('error', (e) => {
177
-                                console.log('Socket error',  e)
184
+                                console.log('Socket error', e)
178 185
                             })
179 186
                             done()
180 187
                         })
@@ -184,7 +191,7 @@ describe('Frontcraft', () => {
184 191
         }).catch(done)
185 192
     })
186 193
 
187
-    after(()=>{
194
+    after(() => {
188 195
         client.destroy()
189 196
         adminClient.destroy()
190 197
         server.stop()
@@ -193,16 +200,16 @@ describe('Frontcraft', () => {
193 200
     it('create raids', (done) => {
194 201
         let insertRaid = <Raid>{
195 202
             description: "Test raid 1",
196
-            title: 'MC',
203
+            title: 'BWL :D',
197 204
             start: Date.now().toString(),
198
-            tier: 'MC'
205
+            tier: 'BWL'
199 206
         }
200 207
 
201 208
         adminClient.manageRaid.createRaid(insertRaid).then(() => {
202
-            client.RaidManager.getRaids().then((r)=>{
203
-                if(r[0].title === insertRaid.title 
204
-                && r[0].description === insertRaid.description
205
-                && r[0].tier === "MC"){
209
+            client.RaidManager.getRaids().then((r) => {
210
+                if (r[0].title === insertRaid.title
211
+                    && r[0].description === insertRaid.description
212
+                    && r[0].tier === "BWL") {
206 213
                     raids.push(r[0])
207 214
                     done()
208 215
                 }
@@ -210,9 +217,9 @@ describe('Frontcraft', () => {
210 217
         }).catch(done)
211 218
     })
212 219
 
213
-    it('create users', (done)=>{
220
+    it('create users', (done) => {
214 221
         Promise.all(testAccounts.map(acc => createAccountAndUser(acc))).then(accs => {
215
-            if(accs.length === testAccounts.length){
222
+            if (accs.length === testAccounts.length) {
216 223
                 accs.forEach(acc => {
217 224
                     users[acc.account.username] = acc
218 225
                 })
@@ -221,29 +228,29 @@ describe('Frontcraft', () => {
221 228
         }).catch(done)
222 229
     })
223 230
 
224
-    it('should sign up', (done)=>{
231
+    it('should sign up', (done) => {
225 232
         Promise.all(Object.values(users).map((user) =>
226 233
             adminClient.signup.sign(user.auth.token.value, user.character, raids[0], false).catch(done)
227 234
         )).then(x => {
228 235
             adminClient.signup.getSignups(raids[0]).then(s => {
229
-                if(s.length == testAccounts.length){
236
+                if (s.length == testAccounts.length) {
230 237
                     s.forEach(sign => {
231 238
                         users[sign.username].signup = sign
232 239
                     })
233 240
                     done()
234
-                }else{
235
-                    done("Unexpected number of signups: "+s.length)
241
+                } else {
242
+                    done("Unexpected number of signups: " + s.length)
236 243
                 }
237 244
             })
238 245
         })
239 246
     })
240 247
 
241
-    it('calculate priorities', (done)=>{
242
-        const makePrio = async (itemname:string, spec?: Spec, race?:Race, mod:number = 0, description:string = "") => {
248
+    it('calculate priorities', (done) => {
249
+        const makePrio = async (itemname: string, spec?: Spec, race?: Race, mod: number = 0, description: string = "") => {
243 250
             let specid
244
-            if(spec)
251
+            if (spec)
245 252
                 specid = await client.CharacterManager.getSpecId(spec.class, <any>spec.specname)
246
-            
253
+
247 254
             await adminClient.managePriorities.setPriority(itemname, {
248 255
                 specid: specid,
249 256
                 race: race,
@@ -252,273 +259,288 @@ describe('Frontcraft', () => {
252 259
             })
253 260
         }
254 261
 
255
-              
262
+
256 263
         Promise.all([
257 264
             makePrio(
258
-                'Bracers of Arcane Accuracy', 
259
-                {class:'Warlock', specname:'Demonology'}, 
265
+                'Bracers of Arcane Accuracy',
266
+                { class: 'Warlock', specname: 'Demonology' },
260 267
                 undefined, 2, "hit bias"
261 268
             ),
262 269
             makePrio(
263
-                'Bracers of Arcane Accuracy', 
264
-                {class:'Warlock', specname:'Affliction'}, 
270
+                'Bracers of Arcane Accuracy',
271
+                { class: 'Warlock', specname: 'Affliction' },
265 272
                 undefined, 2, "hit bias"
266 273
             ),
267 274
             makePrio(
268
-                'Bracers of Arcane Accuracy', 
269
-                {class:'Warlock', specname:'Destruction'}, 
275
+                'Bracers of Arcane Accuracy',
276
+                { class: 'Warlock', specname: 'Destruction' },
270 277
                 undefined, 2, "hit bias"
271 278
             ),
272 279
             makePrio(
273
-                'Bracers of Arcane Accuracy', 
274
-                {class:'Mage', specname:'Arcane'}, 
280
+                'Bracers of Arcane Accuracy',
281
+                { class: 'Mage', specname: 'Arcane' },
275 282
                 undefined, 1, "hit bias"
276 283
             ),
277 284
             makePrio(
278
-                'Bracers of Arcane Accuracy', 
279
-                {class:'Mage', specname:'Frost'}, 
285
+                'Bracers of Arcane Accuracy',
286
+                { class: 'Mage', specname: 'Frost' },
280 287
                 undefined, 1, "hit bias"
281 288
             ),
282 289
             makePrio(
283
-                'Bracers of Arcane Accuracy', 
284
-                {class:'Mage', specname:'Fire'}, 
290
+                'Bracers of Arcane Accuracy',
291
+                { class: 'Mage', specname: 'Fire' },
285 292
                 undefined, 1, "hit bias"
286 293
             ),
287 294
 
288 295
             makePrio(
289
-                'Maladath, Runed Blade of the Black Flight', 
296
+                'Maladath, Runed Blade of the Black Flight',
290 297
                 undefined,
291
-                "Human", -2, "(1) Non-Human"
292
-            ),
293
-            makePrio(
294
-                'Maladath, Runed Blade of the Black Flight', 
295
-                {class:'Rogue', specname:'Subtlety'}, 
296
-                undefined, 2, "...Rogues (weapon skill bias)"
298
+                "Human", -2, "[1] Non-Human"
297 299
             ),
298 300
             makePrio(
299
-                'Maladath, Runed Blade of the Black Flight', 
300
-                {class:'Rogue', specname:'Combat'}, 
301
-                undefined, 2, "...Rogues (weapon skill bias)"
301
+                'Maladath, Runed Blade of the Black Flight',
302
+                { class: 'Rogue', specname: 'Combat' },
303
+                undefined, 2, "Weapon skill bias"
302 304
             ),
303 305
             makePrio(
304
-                'Maladath, Runed Blade of the Black Flight', 
305
-                {class:'Rogue', specname:'Assassination'}, 
306
-                undefined, 2, "...Rogues (weapon skill bias)"
306
+                'Maladath, Runed Blade of the Black Flight',
307
+                { class: 'Warrior', specname: 'Fury' },
308
+                'Human', 4, "+2 Fury Warrior (weapon skill bias), +2 to offset [1]"
307 309
             ),
308 310
             makePrio(
309
-                'Maladath, Runed Blade of the Black Flight', 
310
-                {class:'Warrior', specname:'Fury'}, 
311
-                'Human', 4, "+2 Fury Warrior (weapon skill bias), +2 to offset (1)"
311
+                'Maladath, Runed Blade of the Black Flight',
312
+                { class: 'Warrior', specname: 'Protection' },
313
+                'Human', 5, "+3 Prot Warrior, +2 to offset [1]"
312 314
             ),
313 315
 
314 316
             makePrio(
315
-                'Cloak of Firemaw', 
316
-                {class:'Rogue', specname:'Assassination'}, 
317
+                'Cloak of Firemaw',
318
+                { class: 'Rogue', specname: 'Assassination' },
317 319
                 undefined, 2, "agi-to-ap bias"
318 320
             ),
319 321
             makePrio(
320
-                'Cloak of Firemaw', 
321
-                {class:'Rogue', specname:'Combat'}, 
322
+                'Cloak of Firemaw',
323
+                { class: 'Rogue', specname: 'Combat' },
322 324
                 undefined, 2, "agi-to-ap bias"
323 325
             ),
324 326
             makePrio(
325
-                'Cloak of Firemaw', 
326
-                {class:'Rogue', specname:'Subtlety'}, 
327
+                'Cloak of Firemaw',
328
+                { class: 'Rogue', specname: 'Subtlety' },
327 329
                 undefined, 2, "agi-to-ap bias"
328 330
             ),
329 331
 
330 332
             makePrio(
331
-                'Band of Forced Concentration', 
332
-                {class:'Warlock', specname:'Demonology'}, 
333
+                'Band of Forced Concentration',
334
+                { class: 'Warlock', specname: 'Demonology' },
333 335
                 undefined, 2, "hit bias"
334 336
             ),
335 337
             makePrio(
336
-                'Band of Forced Concentration', 
337
-                {class:'Warlock', specname:'Affliction'}, 
338
+                'Band of Forced Concentration',
339
+                { class: 'Warlock', specname: 'Affliction' },
338 340
                 undefined, 2, "hit bias"
339 341
             ),
340 342
             makePrio(
341
-                'Band of Forced Concentration', 
342
-                {class:'Warlock', specname:'Destruction'}, 
343
+                'Band of Forced Concentration',
344
+                { class: 'Warlock', specname: 'Destruction' },
343 345
                 undefined, 2, "hit bias"
344 346
             ),
345 347
             makePrio(
346
-                'Band of Forced Concentration', 
347
-                {class:'Mage', specname:'Arcane'}, 
348
+                'Band of Forced Concentration',
349
+                { class: 'Mage', specname: 'Arcane' },
348 350
                 undefined, 1, "hit bias"
349 351
             ),
350 352
             makePrio(
351
-                'Band of Forced Concentration', 
352
-                {class:'Mage', specname:'Frost'}, 
353
+                'Band of Forced Concentration',
354
+                { class: 'Mage', specname: 'Frost' },
353 355
                 undefined, 1, "hit bias"
354 356
             ),
355 357
             makePrio(
356
-                'Band of Forced Concentration', 
357
-                {class:'Mage', specname:'Fire'}, 
358
+                'Band of Forced Concentration',
359
+                { class: 'Mage', specname: 'Fire' },
358 360
                 undefined, 1, "hit bias"
359 361
             ),
360 362
 
361 363
             makePrio(
362
-                'Drake Fang Talisman', 
363
-                {class:'Rogue', specname:'Assassination'}, 
364
+                'Chromatic Boots',
365
+                { class: 'Warrior', specname: 'Protection' },
366
+                undefined, 2, "hit bias"
367
+            ),
368
+
369
+            makePrio(
370
+                'Crul\'shorukh, Edge of Chaos',
371
+                undefined,
372
+                "Human", -2, "Non-human"
373
+            ),
374
+            makePrio(
375
+                'Crul\'shorukh, Edge of Chaos',
376
+                { class: 'Warrior', specname: 'Protection' },
377
+                undefined, 2, "nice dps bias"
378
+            ),
379
+            makePrio(
380
+                'Crul\'shorukh, Edge of Chaos',
381
+                { class: 'Warrior', specname: 'Fury' },
382
+                undefined, 2, "nice dps bias"
383
+            ),
384
+
385
+            makePrio(
386
+                'Drake Talon Pauldrons',
387
+                { class: 'Warrior', specname:'Protection'},
388
+                undefined, 2, 'dodge + stats-to-threat bias'
389
+            ),
390
+            
391
+            makePrio(
392
+                'Helm of Endless Rage',
393
+                { class: 'Warrior', specname:'Protection'},
394
+                undefined, 2, 'stats-to-threat bias'
395
+            ),
396
+
397
+            makePrio(
398
+                'Drake Fang Talisman',
399
+                { class: 'Warrior', specname: 'Protection' },
400
+                undefined, 5, "hit bias"
401
+            ),
402
+            makePrio(
403
+                'Drake Fang Talisman',
404
+                { class: 'Rogue', specname: 'Assassination' },
364 405
                 undefined, 4, "hit bias"
365 406
             ),
366 407
             makePrio(
367
-                'Drake Fang Talisman', 
368
-                {class:'Rogue', specname:'Combat'}, 
408
+                'Drake Fang Talisman',
409
+                { class: 'Rogue', specname: 'Combat' },
369 410
                 undefined, 4, "hit bias"
370 411
             ),
371 412
             makePrio(
372
-                'Drake Fang Talisman', 
373
-                {class:'Rogue', specname:'Subtlety'}, 
413
+                'Drake Fang Talisman',
414
+                { class: 'Rogue', specname: 'Subtlety' },
374 415
                 undefined, 4, "hit bias"
375 416
             ),
376 417
             makePrio(
377
-                'Drake Fang Talisman', 
378
-                {class:'Warrior', specname:'Fury'}, 
418
+                'Drake Fang Talisman',
419
+                { class: 'Warrior', specname: 'Fury' },
379 420
                 undefined, 2, "hit bias"
380 421
             ),
381 422
             makePrio(
382
-                'Drake Fang Talisman', 
383
-                {class:'Druid', specname:'Feral (DPS)'}, 
423
+                'Drake Fang Talisman',
424
+                { class: 'Druid', specname: 'Feral (DPS)' },
384 425
                 undefined, 2, "hit bias"
385 426
             ),
386 427
 
387 428
             makePrio(
388
-                'Circle of Applied Force', 
389
-                {class:'Warrior', specname:'Fury'}, 
429
+                'Circle of Applied Force',
430
+                { class: 'Warrior', specname: 'Fury' },
390 431
                 undefined, 2, "str-to-ap bias"
391 432
             ),
392 433
             makePrio(
393
-                'Circle of Applied Force', 
394
-                {class:'Druid', specname:'Feral (DPS)'}, 
395
-                undefined, 2, "str-to-ap bias"
434
+                'Circle of Applied Force',
435
+                { class: 'Druid', specname: 'Feral (DPS)' },
436
+                undefined, 3, "str-to-ap bias + agi-to-ap bias"
396 437
             ),
397 438
 
398 439
             makePrio(
399
-                'Empowered Leggings', 
400
-                {class:'Paladin', specname:'Holy'}, 
440
+                'Empowered Leggings',
441
+                { class: 'Paladin', specname: 'Holy' },
401 442
                 undefined, 2, "crit bias"
402 443
             ),
403 444
             makePrio(
404
-                'Empowered Leggings', 
405
-                {class:'Druid', specname:'Restoration'}, 
445
+                'Empowered Leggings',
446
+                { class: 'Druid', specname: 'Restoration' },
406 447
                 undefined, 2, "crit bias"
407 448
             ),
408 449
 
409 450
             makePrio(
410
-                'Boots of the Shadow Flame', 
411
-                {class:'Rogue', specname:'Assassination'}, 
451
+                'Boots of the Shadow Flame',
452
+                { class: 'Rogue', specname: 'Assassination' },
412 453
                 undefined, 2, "hit bias"
413 454
             ),
414 455
             makePrio(
415
-                'Boots of the Shadow Flame', 
416
-                {class:'Rogue', specname:'Combat'}, 
456
+                'Boots of the Shadow Flame',
457
+                { class: 'Rogue', specname: 'Combat' },
417 458
                 undefined, 2, "hit bias"
418 459
             ),
419 460
             makePrio(
420
-                'Boots of the Shadow Flame', 
421
-                {class:'Rogue', specname:'Subtlety'}, 
461
+                'Boots of the Shadow Flame',
462
+                { class: 'Rogue', specname: 'Subtlety' },
422 463
                 undefined, 2, "hit bias"
423 464
             ),
424 465
             makePrio(
425
-                'Boots of the Shadow Flame', 
426
-                {class:'Druid', specname:'Feral (DPS)'}, 
466
+                'Boots of the Shadow Flame',
467
+                { class: 'Druid', specname: 'Feral (DPS)' },
427 468
                 undefined, 2, "hit bias"
428 469
             ),
429 470
 
430 471
             makePrio(
431
-                'Neltharion\'s Tear', 
432
-                {class:'Warlock', specname:'Demonology'}, 
472
+                'Neltharion\'s Tear',
473
+                { class: 'Warlock', specname: 'Demonology' },
433 474
                 undefined, 4, "hit bias"
434 475
             ),
435 476
             makePrio(
436
-                'Neltharion\'s Tear', 
437
-                {class:'Warlock', specname:'Affliction'}, 
477
+                'Neltharion\'s Tear',
478
+                { class: 'Warlock', specname: 'Affliction' },
438 479
                 undefined, 4, "hit bias"
439 480
             ),
440 481
             makePrio(
441
-                'Neltharion\'s Tear', 
442
-                {class:'Warlock', specname:'Destruction'}, 
482
+                'Neltharion\'s Tear',
483
+                { class: 'Warlock', specname: 'Destruction' },
443 484
                 undefined, 4, "hit bias"
444 485
             ),
445 486
             makePrio(
446
-                'Neltharion\'s Tear', 
447
-                {class:'Mage', specname:'Arcane'}, 
487
+                'Neltharion\'s Tear',
488
+                { class: 'Mage', specname: 'Arcane' },
448 489
                 undefined, 2, "hit bias"
449 490
             ),
450 491
             makePrio(
451
-                'Neltharion\'s Tear', 
452
-                {class:'Mage', specname:'Frost'}, 
492
+                'Neltharion\'s Tear',
493
+                { class: 'Mage', specname: 'Frost' },
453 494
                 undefined, 2, "hit bias"
454 495
             ),
455 496
             makePrio(
456
-                'Neltharion\'s Tear', 
457
-                {class:'Mage', specname:'Fire'}, 
497
+                'Neltharion\'s Tear',
498
+                { class: 'Mage', specname: 'Fire' },
458 499
                 undefined, 2, "hit bias"
459 500
             ),
460 501
 
461 502
             makePrio(
462
-                'Cloak of Draconic Might', 
463
-                {class:'Warrior', specname:'Fury'}, 
503
+                'Cloak of Draconic Might',
504
+                { class: 'Warrior', specname: 'Fury' },
464 505
                 undefined, 2, "str-to-ap bias"
465 506
             ),
466 507
             makePrio(
467
-                'Cloak of Draconic Might', 
468
-                {class:'Druid', specname:'Feral (DPS)'}, 
469
-                undefined, 2, "str-to-ap bias"
508
+                'Cloak of Draconic Might',
509
+                { class: 'Druid', specname: 'Feral (DPS)' },
510
+                undefined, 1, "str-to-ap bias"
470 511
             ),
471
-        ])
472
-
473
-
474
-        const user = Object.values(users)[0]
475
-        adminClient.managePriorities.setPriority(T1[0], {
476
-            race: user.character.race,
477
-            specid: user.character.specid,
478
-            modifier: 1,
479
-            description:'AAA'
480
-        }).then(() => {
481
-            adminClient.managePriorities.setPriority(T1[0], {
482
-                race: user.character.race,
483
-                specid: undefined,
484
-                modifier: 2,
485
-                description:'BBB'
486
-            }).then(()=>{
487
-                adminClient.managePriorities.setPriority(T1[0], {
488
-                    race: undefined,
489
-                    specid: user.character.specid,
490
-                    modifier: 3,
491
-                    description:'CCC'
492
-                }).then(()=>{
493
-                    client.ItemManager.calculatePriorities(T1[0], user.character).then(sum => {
494
-                        if(sum === 6)
495
-                            done()
496
-                    })
497
-                })
512
+        ]).then(() => {
513
+            const user = Object.values(users)[0]
514
+            client.ItemManager.calculatePriorities("Maladath, Runed Blade of the Black Flight", user.character).then(sum => {
515
+                if (sum === 3)
516
+                    done()
517
+                else
518
+                    console.log("Expected prio on maladath to be 4, but was:", sum, user.character);
498 519
             })
520
+
499 521
         })
500 522
     })
501 523
 
502
-    it('buy token', (done)=>{
503
-        Promise.all(Object.values(users).map(async (user) =>{
504
-            const itemname = T1[0]//T1[Math.floor(T1.length*Math.random())]
524
+    it('buy token', (done) => {
525
+        Promise.all(Object.values(users).map(async (user) => {
526
+            const itemname = "Maladath, Runed Blade of the Black Flight" //T1[Math.floor(T1.length*Math.random())]
505 527
             const modifier = await client.ItemManager.calculatePriorities(itemname, user.character)
506 528
 
507 529
             const token = await client.ItemManager.buyToken(user.auth.token.value, user.character.charactername, itemname, user.signup!)
508 530
             users[user.account.username].item = itemname
509
-            
510
-            if(!token) return false
511
-            return modifier+1 === token.level
531
+
532
+            if (!token) return false
533
+            return modifier + 1 === token.level
512 534
         })).then(success => {
513
-            if(success.reduce((prev, curr)=>prev&&curr, true)) done()
535
+            if (success.reduce((prev, curr) => prev && curr, true)) done()
514 536
         })
515 537
     })
516 538
 
517
-    it('not buy token without currency', (done)=>{
539
+    it('not buy token without currency', (done) => {
518 540
         const user = Object.values(users)[0]
519
-        const itemname = T1[0]
541
+        const itemname = "Maladath, Runed Blade of the Black Flight"
520 542
         client.ItemManager.buyToken(user.auth.token.value, user.character.charactername, itemname, user.signup!).then(token => {
521
-            if(!token) 
543
+            if (!token)
522 544
                 done()
523 545
             else {
524 546
                 console.log("Unexpected token", token);
@@ -526,24 +548,23 @@ describe('Frontcraft', () => {
526 548
         })
527 549
     })
528 550
 
529
-    it('upgrade token', (done)=>{
551
+    it('upgrade token', (done) => {
530 552
         const user = Object.values(users)[0]
531
-        const itemname = T1[0]
532
-
533
-        adminClient.softreserveCurrency.incrementCurrency(user.account, raids[0].tier, 2).then(async ()=>{
534
-            const item = await client.ItemManager.getItem(itemname)
553
+        const itemname = "Maladath, Runed Blade of the Black Flight"
554
+        client.ItemManager.getItem(itemname).then(async item => {
555
+            await adminClient.softreserveCurrency.incrementCurrency(user.account, item.tier, 2)
535 556
             const before = await client.ItemManager.getToken(user.character, item)
536
-            
537
-            if(!before || before.level !== 7) {
538
-                console.log("expected level to be 7", before);
557
+
558
+            if (!before || before.level !== 4) {
559
+                console.log("expected level to be 4", before ? before.level : '?');
539 560
                 return
540 561
             }
541
-            
562
+
542 563
             await client.ItemManager.buyToken(user.auth.token.value, user.character.charactername, itemname, user.signup!)
543 564
             const after = await client.ItemManager.buyToken(user.auth.token.value, user.character.charactername, itemname, user.signup!)
544 565
 
545
-            if(!after || after.level !== 9) {
546
-                console.log("expected level to be 9", after);
566
+            if (!after || after.level !== 6) {
567
+                console.log("expected level after to be 6", after ? after.level : '?');
547 568
                 return
548 569
             }
549 570
             done()
@@ -552,14 +573,14 @@ describe('Frontcraft', () => {
552 573
 
553 574
     it('should buy more tokens', (done) => {
554 575
         Promise.all(Object.values(users).map(async (user) => {
555
-            await adminClient.softreserveCurrency.incrementCurrency(user.account,raids[0].tier, 1)
576
+            await adminClient.softreserveCurrency.incrementCurrency(user.account, raids[0].tier, 1)
556 577
             return await client.ItemManager
557
-            .buyToken(
558
-                user.auth.token.value, 
559
-                user.character.charactername, 
560
-                T1[Math.floor(T1.length*Math.random())],
561
-                user.signup!
562
-            )
578
+                .buyToken(
579
+                    user.auth.token.value,
580
+                    user.character.charactername,
581
+                    T2[Math.floor(T2.length * Math.random())],
582
+                    user.signup!
583
+                )
563 584
         })).then(_ => {
564 585
             done()
565 586
         })
@@ -574,21 +595,21 @@ describe('Frontcraft', () => {
574 595
     })
575 596
 
576 597
     it('start raid', (done) => {
577
-        client.RaidManager.getRaids().then((r)=>{
598
+        client.RaidManager.getRaids().then((r) => {
578 599
             adminClient.manageRaid.startRaid(raids[0]).then(async data => {
579 600
                 const dbRaids = await client.RaidManager.getRaids()
580
-                if(dbRaids.length === 0){
601
+                if (dbRaids.length === 0) {
581 602
                     await client.UserManager.getUser(testAccounts[0].name).then(dbUser => {
582
-                        if(dbUser && dbUser.MC === 1){
603
+                        if (dbUser && dbUser.BWL === 1) {
583 604
                             adminClient.signup.getSignups(raids[0]).then(signups => {
584
-                                if(signups.length === 0){
605
+                                if (signups.length === 0) {
585 606
                                     done()
586
-                                }else{
607
+                                } else {
587 608
                                     console.log(signups);
588 609
                                 }
589 610
                             })
590 611
                         }
591
-                        else{
612
+                        else {
592 613
                             console.log("Bad user currency", dbUser);
593 614
                         }
594 615
                     })
@@ -600,81 +621,121 @@ describe('Frontcraft', () => {
600 621
     it('reset system', (done) => {
601 622
         adminClient.reset.wipeCurrencyAndItems().then(() => {
602 623
             client.UserManager.getUser(testAccounts[0].name).then(user => {
603
-                if(user && user.MC === 1){
604
-                    client.ItemManager.getTokens(users[testAccounts[0].name.toLowerCase()].character, ['MC']).then(tokens => {
605
-                        if(tokens!.length === 0){
624
+                if (user && user.MC === 1) {
625
+                    client.ItemManager.getTokens(users[testAccounts[0].name.toLowerCase()].character, ['BWL']).then(tokens => {
626
+                        if (tokens!.length === 0) {
606 627
                             done()
607
-                        }else{
628
+                        } else {
608 629
                             console.log(tokens);
609 630
                         }
610 631
                     })
611
-                }else{
632
+                } else {
612 633
                     console.log(user)
613 634
                 }
614 635
             })
615 636
         })
616 637
     })
617 638
 
618
-    it('implements loot system correctly', (done)=>{
639
+    it('implements loot system correctly', (done) => {
619 640
         const ONE_WEEK = 4800000000
620
-        
621
-        const Raid = (week:number, tier:string) => {
622
-                return <Raid>{
623
-                description: tier+" Test raid 1",
641
+
642
+        const Raid = (week: number, tier: string) => {
643
+            return <Raid>{
644
+                description: tier + " Test raid 1",
624 645
                 title: tier,
625
-                start: (week*ONE_WEEK + Date.now()).toString(),
646
+                start: (week * ONE_WEEK + Date.now()).toString(),
626 647
                 tier: tier
627 648
             }
628 649
         }
629 650
         const user = Object.values(users)[0]
630 651
         const createRaid = adminClient.manageRaid.createRaid
631
-        const sign = async (raid:Raid, late = false) => await adminClient.signup.sign(user.auth.token.value, user.character, raid, late)
652
+        const sign = async (raid: Raid, late = false) => await adminClient.signup.sign(user.auth.token.value, user.character, raid, late)
632 653
         const buyToken = async (signup: Signup, itemname: string) => await client.ItemManager.buyToken(user.auth.token.value, user.character.charactername, itemname, signup)
654
+        const getCurrency = async (tier: Tiers) => {
655
+            const dbUser = await client.UserManager.getUser(user.account.username)
656
+            return dbUser[tier]
657
+        }
633 658
 
634
-        createRaid(Raid(0, 'MC')).then(async (MC0:Raid) => {
635
-            const T1_0 = await client.ItemManager.getItem(T1[0])
659
+        createRaid(Raid(0, 'BWL')).then(async (BWL0: Raid) => {
660
+            const T2_0 = await client.ItemManager.getItem(T2[0])
636 661
             //const BWL0 = await createRaid(Raid(0, 'BWL'))
637
-            const signupMC0 = await sign(MC0)
638
-            let token = await buyToken(signupMC0, T1[0])
639
-            if(!token){
640
-                console.log(MC0, signupMC0)
641
-                done("No token created")
662
+            const signupBWL0 = await sign(BWL0)
663
+            let BWL = await getCurrency(BWL0.tier)
664
+            let token = await buyToken(signupBWL0, T2[0])
665
+            const BWLAfter = await getCurrency(BWL0.tier)
666
+
667
+            if (!token
668
+                || BWL - BWLAfter != 1) {
669
+                console.log("Bad Token status", BWL0, signupBWL0, BWL, BWLAfter)
670
+                done(new Error("Bad Token status 0"))
642 671
                 return
643 672
             }
644 673
 
645
-            let reserves = await client.ItemManager.getTokens(user.character, [MC0.tier], true)
646
-            let streaks = await client.ItemManager.getTokens(user.character, [MC0.tier], false)
647
-            if(reserves!.length != 1 
648
-            || streaks!.length != 0
649
-            || reserves![0].itemname !== T1_0.itemname
650
-            || reserves![0].level !== 7){
651
-                console.log(reserves, streaks);
652
-                done("Bad token status")
674
+            let reserves = await client.ItemManager.getTokens(user.character, [BWL0.tier], true)
675
+            let streaks = await client.ItemManager.getTokens(user.character, [BWL0.tier], false)
676
+            if (reserves!.length != 1
677
+                || streaks!.length != 0
678
+                || reserves![0].itemname !== T2_0.itemname
679
+                || reserves![0].level !== 1) {
680
+                console.log("Bad Token status 1", reserves, streaks);
681
+                done(new Error("Bad Token status"))
682
+                return
683
+            }
684
+            await adminClient.manageRaid.startRaid(BWL0)
685
+            reserves = await client.ItemManager.getTokens(user.character, [BWL0.tier], true)
686
+            streaks = await client.ItemManager.getTokens(user.character, [BWL0.tier], false)
687
+            if (reserves!.length != 0
688
+                || streaks!.length != 1
689
+                || streaks![0].itemname !== T2[0]
690
+                || streaks![0].level !== 1) {
691
+                console.log("Bad Token status", reserves, streaks);
692
+                done(new Error("Bad Token status 2"))
653 693
                 return
654 694
             }
655
-            await adminClient.manageRaid.startRaid(MC0)
656
-            reserves = await client.ItemManager.getTokens(user.character, [MC0.tier], true)
657
-            streaks = await client.ItemManager.getTokens(user.character, [MC0.tier], false)
658
-            if(reserves!.length != 0 
659
-            || streaks!.length != 1
660
-            || streaks![0].itemname !== T1[0]
661
-            || streaks![0].level !== 7){
662
-                console.log(reserves, streaks);
663
-                done("Bad token status")
695
+
696
+            const BWL1 = await createRaid(Raid(1, 'BWL'))
697
+
698
+            let signupBWL1 = await sign(BWL1)
699
+            BWL = await getCurrency(BWL1.tier)
700
+            await adminClient.manageRaid.adminUnsign(user.character, BWL1)
701
+            let afterUnsign = await getCurrency(BWL1.tier)
702
+            if (BWL !== afterUnsign) {
703
+                console.log("Expected currency to be equal", BWL, afterUnsign)
704
+                done(new Error("Expected currency to be equal"))
664 705
                 return
665 706
             }
666 707
 
667
-            const MC1 = await createRaid(Raid(1, 'MC'))
668
-            const signupMC1 = await sign(MC1)
669
-            token = await buyToken(signupMC1, T1[1])
670
-            reserves = await client.ItemManager.getTokens(user.character, [MC1.tier], true)
671
-            streaks = await client.ItemManager.getTokens(user.character, [MC1.tier], false)
672
-            if(reserves!.length != 1 
673
-            || streaks!.length != 0
674
-            || reserves![0].itemname !== T1[1]
675
-            || reserves![0].level !== 1){
676
-                console.log(reserves, streaks);
677
-                done("Bad token status")
708
+            signupBWL1 = await sign(BWL1)
709
+            BWL = await getCurrency(BWL1.tier)
710
+            await buyToken(signupBWL1, T2[1])
711
+            await adminClient.manageRaid.adminUnsign(user.character, BWL1)
712
+            afterUnsign = await getCurrency(BWL1.tier)
713
+            if (BWL !== afterUnsign) {
714
+                console.log("Expected currency to be equal", BWL, afterUnsign)
715
+                done(new Error("Expected currency to be equal"))
716
+                return
717
+            }
718
+
719
+            signupBWL1 = await sign(BWL1)
720
+            await buyToken(signupBWL1, T2[1])
721
+            reserves = await client.ItemManager.getTokens(user.character, [BWL1.tier], true)
722
+            streaks = await client.ItemManager.getTokens(user.character, [BWL1.tier], false)
723
+            if (reserves!.length != 1
724
+                || streaks!.length != 0
725
+                || reserves![0].itemname !== T2[1]
726
+                || reserves![0].level !== 1) {
727
+                console.log("Bad Token status", reserves, streaks);
728
+                done(new Error("Bad Token status 3"))
729
+                return
730
+            }
731
+
732
+            BWL = await getCurrency(BWL1.tier)
733
+            const data = await adminClient.manageRaid.startRaid(BWL1)
734
+
735
+            const afterStart = await getCurrency(BWL1.tier)
736
+            if (BWL != 0 || afterStart != 1) {
737
+                console.log("Wrong currency values", BWL, afterStart)
738
+                done(new Error("Wrong currency values"))
678 739
                 return
679 740
             }
680 741
 
@@ -682,7 +743,7 @@ describe('Frontcraft', () => {
682 743
 
683 744
         }).catch(e => {
684 745
             console.log(e);
685
-            
746
+
686 747
             done(e)
687 748
         })
688 749
     })

正在加载...
取消
保存