瀏覽代碼

change pw, change rank UI, auto-refresh on disconnect, new loading screen

master
peter 5 年之前
父節點
當前提交
96651913cd

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

1050
           }
1050
           }
1051
         },
1051
         },
1052
         "yallist": {
1052
         "yallist": {
1053
-          "version": "3.0.3",
1054
-          "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.0.3.tgz",
1055
-          "integrity": "sha512-S+Zk8DEWE6oKpV+vI3qWkaK+jSbIK86pCwe2IF/xwIpQ8jEuxpw9NyaGjmp9+BoJv5FV2piqCDcoCtStppiq2A==",
1053
+          "version": "3.1.1",
1054
+          "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz",
1055
+          "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==",
1056
           "dev": true
1056
           "dev": true
1057
         }
1057
         }
1058
       }
1058
       }
1476
       "integrity": "sha1-/aGedh/Ad+Af+/3G6f38WeiAbNg="
1476
       "integrity": "sha1-/aGedh/Ad+Af+/3G6f38WeiAbNg="
1477
     },
1477
     },
1478
     "cyclist": {
1478
     "cyclist": {
1479
-      "version": "0.2.2",
1480
-      "resolved": "https://registry.npmjs.org/cyclist/-/cyclist-0.2.2.tgz",
1481
-      "integrity": "sha1-GzN5LhHpFKL9bW7WRHRkRE5fpkA=",
1479
+      "version": "1.0.1",
1480
+      "resolved": "https://registry.npmjs.org/cyclist/-/cyclist-1.0.1.tgz",
1481
+      "integrity": "sha1-WW6WmP0MgOEgOMK4LW6xs1tiJNk=",
1482
       "dev": true
1482
       "dev": true
1483
     },
1483
     },
1484
     "dashdash": {
1484
     "dashdash": {
5465
       "dev": true
5465
       "dev": true
5466
     },
5466
     },
5467
     "parallel-transform": {
5467
     "parallel-transform": {
5468
-      "version": "1.1.0",
5469
-      "resolved": "https://registry.npmjs.org/parallel-transform/-/parallel-transform-1.1.0.tgz",
5470
-      "integrity": "sha1-1BDwZbBdojCB/NEPKIVMKb2jOwY=",
5468
+      "version": "1.2.0",
5469
+      "resolved": "https://registry.npmjs.org/parallel-transform/-/parallel-transform-1.2.0.tgz",
5470
+      "integrity": "sha512-P2vSmIu38uIlvdcU7fDkyrxj33gTUy/ABO5ZUbGowxNCopBq/OoD42bP4UmMrJoPyk4Uqf0mu3mtWBhHCZD8yg==",
5471
       "dev": true,
5471
       "dev": true,
5472
       "requires": {
5472
       "requires": {
5473
-        "cyclist": "~0.2.2",
5473
+        "cyclist": "^1.0.1",
5474
         "inherits": "^2.0.3",
5474
         "inherits": "^2.0.3",
5475
         "readable-stream": "^2.1.5"
5475
         "readable-stream": "^2.1.5"
5476
       }
5476
       }
6130
       }
6130
       }
6131
     },
6131
     },
6132
     "rpclibrary": {
6132
     "rpclibrary": {
6133
-      "version": "1.7.1",
6134
-      "resolved": "https://registry.npmjs.org/rpclibrary/-/rpclibrary-1.7.1.tgz",
6135
-      "integrity": "sha512-Ibo3qfURnQgZAq0eA2o+L9+PWaloJ4PHZs4ak42LL9fRgdWZXn33HAtowV0K2HVckbvrBvFqj/+PWTrWWBSOeg==",
6133
+      "version": "1.8.3",
6134
+      "resolved": "https://registry.npmjs.org/rpclibrary/-/rpclibrary-1.8.3.tgz",
6135
+      "integrity": "sha512-8pQRbMXQKCf3+v+XM01d+1Bw73pg5YzgyhW/ACpYON1I4re5fZAjWGPyLc+ms+MlYQIlKc3Uk92PGot2sbb85Q==",
6136
       "requires": {
6136
       "requires": {
6137
         "bsock": "^0.1.9",
6137
         "bsock": "^0.1.9",
6138
         "http": "0.0.0",
6138
         "http": "0.0.0",
6252
       }
6252
       }
6253
     },
6253
     },
6254
     "serialize-javascript": {
6254
     "serialize-javascript": {
6255
-      "version": "1.8.0",
6256
-      "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-1.8.0.tgz",
6257
-      "integrity": "sha512-3tHgtF4OzDmeKYj6V9nSyceRS0UJ3C7VqyD2Yj28vC/z2j6jG5FmFGahOKMD9CrglxTm3tETr87jEypaYV8DUg==",
6255
+      "version": "2.1.2",
6256
+      "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-2.1.2.tgz",
6257
+      "integrity": "sha512-rs9OggEUF0V4jUSecXazOYsLfu7OGK2qIn3c7IPBiffz32XniEp/TX9Xmc9LQfK2nQ2QKHvZ2oygKUGU0lG4jQ==",
6258
       "dev": true
6258
       "dev": true
6259
     },
6259
     },
6260
     "serve-static": {
6260
     "serve-static": {
6503
       }
6503
       }
6504
     },
6504
     },
6505
     "source-map-support": {
6505
     "source-map-support": {
6506
-      "version": "0.5.13",
6507
-      "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.13.tgz",
6508
-      "integrity": "sha512-SHSKFHadjVA5oR4PPqhtAVdcBWwRYVd6g6cAXnIbRiIwc2EhPrTuKUBdSLvlEKyIP3GCf89fltvcZiP9MMFA1w==",
6506
+      "version": "0.5.16",
6507
+      "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.16.tgz",
6508
+      "integrity": "sha512-efyLRJDr68D9hBBNIPWFjhpFzURh+KJykQwvMyW5UiZzYwoF6l4YMMDIJJEyFWxWCqfyxLzz6tSfUFR+kXXsVQ==",
6509
       "dev": true,
6509
       "dev": true,
6510
       "requires": {
6510
       "requires": {
6511
         "buffer-from": "^1.0.0",
6511
         "buffer-from": "^1.0.0",
6637
       }
6637
       }
6638
     },
6638
     },
6639
     "stream-shift": {
6639
     "stream-shift": {
6640
-      "version": "1.0.0",
6641
-      "resolved": "https://registry.npmjs.org/stream-shift/-/stream-shift-1.0.0.tgz",
6642
-      "integrity": "sha1-1cdSgl5TZ+eG944Y5EXqIjoVWVI=",
6640
+      "version": "1.0.1",
6641
+      "resolved": "https://registry.npmjs.org/stream-shift/-/stream-shift-1.0.1.tgz",
6642
+      "integrity": "sha512-AiisoFqQ0vbGcZgQPY1cdP2I76glaVA/RauYR4G4thNFgkTqr90yXTo4LYX60Jl+sIlPNHHdGSwo01AvbKUSVQ==",
6643
       "dev": true
6643
       "dev": true
6644
     },
6644
     },
6645
     "streamroller": {
6645
     "streamroller": {
6799
       "dev": true
6799
       "dev": true
6800
     },
6800
     },
6801
     "terser": {
6801
     "terser": {
6802
-      "version": "4.2.0",
6803
-      "resolved": "https://registry.npmjs.org/terser/-/terser-4.2.0.tgz",
6804
-      "integrity": "sha512-6lPt7lZdZ/13icQJp8XasFOwZjFJkxFFIb/N1fhYEQNoNI3Ilo3KABZ9OocZvZoB39r6SiIk/0+v/bt8nZoSeA==",
6802
+      "version": "4.6.4",
6803
+      "resolved": "https://registry.npmjs.org/terser/-/terser-4.6.4.tgz",
6804
+      "integrity": "sha512-5fqgBPLgVHZ/fVvqRhhUp9YUiGXhFJ9ZkrZWD9vQtFBR4QIGTnbsb+/kKqSqfgp3WnBwGWAFnedGTtmX1YTn0w==",
6805
       "dev": true,
6805
       "dev": true,
6806
       "requires": {
6806
       "requires": {
6807
         "commander": "^2.20.0",
6807
         "commander": "^2.20.0",
6810
       }
6810
       }
6811
     },
6811
     },
6812
     "terser-webpack-plugin": {
6812
     "terser-webpack-plugin": {
6813
-      "version": "1.4.1",
6814
-      "resolved": "https://registry.npmjs.org/terser-webpack-plugin/-/terser-webpack-plugin-1.4.1.tgz",
6815
-      "integrity": "sha512-ZXmmfiwtCLfz8WKZyYUuuHf3dMYEjg8NrjHMb0JqHVHVOSkzp3cW2/XG1fP3tRhqEqSzMwzzRQGtAPbs4Cncxg==",
6813
+      "version": "1.4.3",
6814
+      "resolved": "https://registry.npmjs.org/terser-webpack-plugin/-/terser-webpack-plugin-1.4.3.tgz",
6815
+      "integrity": "sha512-QMxecFz/gHQwteWwSo5nTc6UaICqN1bMedC5sMtUc7y3Ha3Q8y6ZO0iCR8pq4RJC8Hjf0FEPEHZqcMB/+DFCrA==",
6816
       "dev": true,
6816
       "dev": true,
6817
       "requires": {
6817
       "requires": {
6818
         "cacache": "^12.0.2",
6818
         "cacache": "^12.0.2",
6819
         "find-cache-dir": "^2.1.0",
6819
         "find-cache-dir": "^2.1.0",
6820
         "is-wsl": "^1.1.0",
6820
         "is-wsl": "^1.1.0",
6821
         "schema-utils": "^1.0.0",
6821
         "schema-utils": "^1.0.0",
6822
-        "serialize-javascript": "^1.7.0",
6822
+        "serialize-javascript": "^2.1.2",
6823
         "source-map": "^0.6.1",
6823
         "source-map": "^0.6.1",
6824
         "terser": "^4.1.2",
6824
         "terser": "^4.1.2",
6825
         "webpack-sources": "^1.4.0",
6825
         "webpack-sources": "^1.4.0",

+ 1
- 1
package.json 查看文件

45
     "path": "^0.12.7",
45
     "path": "^0.12.7",
46
     "reflect-metadata": "^0.1.13",
46
     "reflect-metadata": "^0.1.13",
47
     "rimraf": "^3.0.0",
47
     "rimraf": "^3.0.0",
48
-    "rpclibrary": "^1.7.1",
48
+    "rpclibrary": "^1.8.3",
49
     "simple-git": "^1.124.0",
49
     "simple-git": "^1.124.0",
50
     "spawn-sync": "^2.0.0",
50
     "spawn-sync": "^2.0.0",
51
     "sqlite3": "^4.1.1",
51
     "sqlite3": "^4.1.1",

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

74
     }
74
     }
75
 
75
 
76
     stop(){
76
     stop(){
77
-        Promise.race([
78
-            Promise.all( this.frontworkComponents.map(c => c.stop?c.stop():undefined )),
79
-            new Promise((res, rej) => { setTimeout(res, 250);})
80
-        ]).catch(e => logger.warn(e))
81
-        .finally(() => { process.exit(0) })
77
+        Promise.all([ 
78
+            ...this.frontworkComponents.map(c => c.stop?c.stop():undefined ),
79
+        ])
80
+        .catch(e => logger.warn(e))
81
+        .finally(() => { 
82
+            this.rpcServer.destroy()
83
+            process.exit(0)
84
+         })
82
     }
85
     }
83
 
86
 
84
     protected configChangeHandler = (conf:AdminConf, key?:string) => {
87
     protected configChangeHandler = (conf:AdminConf, key?:string) => {
202
                     return await this.knex.schema.createTable(def.name, def.tableBuilder)
205
                     return await this.knex.schema.createTable(def.name, def.tableBuilder)
203
             })
206
             })
204
         )
207
         )
205
-        
206
         return this.knex
208
         return this.knex
207
     }
209
     }
208
 }
210
 }

+ 1
- 1
src/backend/Components/Item/RPCInterface.ts 查看文件

18
     }
18
     }
19
     managePriorities: {
19
     managePriorities: {
20
         setPriority:IItemManager['setPriority']
20
         setPriority:IItemManager['setPriority']
21
-        deletePriorits: IItemManager['deletePriority']
21
+        deletePriority: IItemManager['deletePriority']
22
     }
22
     }
23
 }
23
 }

+ 3
- 1
src/backend/Components/User/Interface.ts 查看文件

11
     checkToken: (token: string, rank: Rank) => boolean
11
     checkToken: (token: string, rank: Rank) => boolean
12
     getUserRecordByToken: (tokenValue: string) => UserRecord | void
12
     getUserRecordByToken: (tokenValue: string) => UserRecord | void
13
     getUser: (username: string) => Promise<User | void>
13
     getUser: (username: string) => Promise<User | void>
14
-
14
+    adminLogout: (username: string) => Promise<void>
15
     decrementCurrency: (user: User, tier:Tiers, value: number) => Promise<void>
15
     decrementCurrency: (user: User, tier:Tiers, value: number) => Promise<void>
16
     incrementCurrency: (user: User, tier:Tiers, value: number) => Promise<void>
16
     incrementCurrency: (user: User, tier:Tiers, value: number) => Promise<void>
17
     setCurrency: (user: User, tier:Tiers, value: number) => Promise<void>
17
     setCurrency: (user: User, tier:Tiers, value: number) => Promise<void>
18
     getCurrency: (user:User, tier:Tiers) => Promise<number>
18
     getCurrency: (user:User, tier:Tiers) => Promise<number>
19
     changeRank: (user:User, rank: Rank) => Promise<User>
19
     changeRank: (user:User, rank: Rank) => Promise<User>
20
     wipeCurrency: () => Promise<void>
20
     wipeCurrency: () => Promise<void>
21
+    changePassword: (userToken: string, pwHash: string) => Promise<User>
22
+    adminChangePassword: (user:User, pwHash: string) => Promise<User>
21
 }
23
 }

+ 7
- 1
src/backend/Components/User/RPCInterface.ts 查看文件

8
         createUser: IUserManager['createUser']
8
         createUser: IUserManager['createUser']
9
         getAuth: IUserManager['getAuth']
9
         getAuth: IUserManager['getAuth']
10
         getUser: IUserManager['getUser']
10
         getUser: IUserManager['getUser']
11
+        changePassword: IUserManager['changePassword']
11
     }
12
     }
12
 }
13
 }
13
 
14
 
14
 export type UserManagerFeatureIfc = {
15
 export type UserManagerFeatureIfc = {
16
+    manageUser: {
17
+        changeRank: IUserManager['changeRank']
18
+        adminLogout: IUserManager['adminLogout']
19
+        adminChangePassword: IUserManager['adminChangePassword']
20
+    }
21
+    
15
     modifyPermissions: {
22
     modifyPermissions: {
16
         setPermission: IUserManager['setPermission']
23
         setPermission: IUserManager['setPermission']
17
         getPermissions: IUserManager['getPermissions']
24
         getPermissions: IUserManager['getPermissions']
18
-        changeRank: IUserManager['changeRank']
19
     }
25
     }
20
 
26
 
21
     softreserveCurrency: {
27
     softreserveCurrency: {

+ 69
- 36
src/backend/Components/User/UserManager.ts 查看文件

13
 import { getLogger, Logger } from "log4js";
13
 import { getLogger, Logger } from "log4js";
14
 import { saltedHash } from "../../Util/hash";
14
 import { saltedHash } from "../../Util/hash";
15
 import { _Tiers, Tiers } from "../../Types/Items";
15
 import { _Tiers, Tiers } from "../../Types/Items";
16
+import { ICharacterManager } from "../Character/Interface";
17
+import { IRaidManager } from "../Raid/Interface";
18
+import { IItemManager } from "../Item/Interface";
19
+import { IGuildManager } from "../Guild/Interface";
16
 
20
 
17
 const uuid = require('uuid/v4')
21
 const uuid = require('uuid/v4')
18
 
22
 
34
     @Inject(IAdmin)
38
     @Inject(IAdmin)
35
     private admin: FrontworkAdmin
39
     private admin: FrontworkAdmin
36
 
40
 
37
-    @Inject(GuildManager)
41
+    @Inject(IGuildManager)
38
     private guild : GuildManager
42
     private guild : GuildManager
39
     
43
     
40
-    @Inject(ItemManager)
44
+    @Inject(IItemManager)
41
     private item : ItemManager
45
     private item : ItemManager
42
     
46
     
43
-    @Inject(RaidManager)
47
+    @Inject(IRaidManager)
44
     private raid : RaidManager
48
     private raid : RaidManager
45
     
49
     
46
-    @Inject(CharacterManager)
50
+    @Inject(ICharacterManager)
47
     private character : CharacterManager
51
     private character : CharacterManager
48
     
52
     
49
     exporters :any[] = []
53
     exporters :any[] = []
56
         this.getAuth,
60
         this.getAuth,
57
         this.checkToken,
61
         this.checkToken,
58
         this.createUser,
62
         this.createUser,
59
-        this.getUser
63
+        this.getUser,
64
+        this.changePassword
60
     ]
65
     ]
61
 
66
 
62
-    exportRPCFeatures = () => [{
67
+    exportRPCFeatures = () => [
68
+    {
69
+        name: 'manageUser' as 'manageUser',
70
+        exportRPCs: () => [
71
+            this.adminLogout,
72
+            this.changeRank,
73
+            this.adminChangePassword
74
+        ]
75
+    },{
63
         name: 'modifyPermissions' as 'modifyPermissions',
76
         name: 'modifyPermissions' as 'modifyPermissions',
64
         exportRPCs: () => [
77
         exportRPCs: () => [
65
             this.getPermissions,
78
             this.getPermissions,
66
             this.setPermission,
79
             this.setPermission,
67
-            this.changeRank
68
         ]
80
         ]
69
     },{
81
     },{
70
         name: 'softreserveCurrency' as 'softreserveCurrency',
82
         name: 'softreserveCurrency' as 'softreserveCurrency',
84
             rank: rank
96
             rank: rank
85
         })
97
         })
86
 
98
 
99
+        await this.adminLogout(user.username)
100
+
87
         return await this.admin
101
         return await this.admin
88
         .knex('users')
102
         .knex('users')
89
         .where({
103
         .where({
132
         })))
146
         })))
133
 
147
 
134
         //start rankServers
148
         //start rankServers
135
-        getLogger('UserManager').debug('Starting rank servers')
136
-
137
         let rankServers = { } as any
149
         let rankServers = { } as any
138
         await Promise.all(_Rank.map(async (r,i) => {
150
         await Promise.all(_Rank.map(async (r,i) => {
139
             const port = 20001 + i
151
             const port = 20001 + i
145
             }
157
             }
146
         }))
158
         }))
147
         this.rankServers = rankServers
159
         this.rankServers = rankServers
148
-        
149
-    
160
+        getLogger('UserManager').debug(Object.values(this.rankServers).length+" rank servers started")
150
         setInterval(this.checkExpiredSessions, 600_000)   
161
         setInterval(this.checkExpiredSessions, 600_000)   
151
     }
162
     }
152
 
163
 
153
     stop = async () => {
164
     stop = async () => {
154
-        Object.values(this.userLogins).forEach(x => Object.values(x.connections).forEach(c => c.destroy()))
155
-
156
-        await Promise.all(Object
157
-            .values(this.rankServers)
158
-            .map(async state => {
159
-                try{
160
-                    //return await state.server.destroy()
161
-                }catch(e){
162
-                    getLogger('UserManager').warn(e)
163
-                }
164
-            })
165
-        );
166
-        
165
+        Object.values(this.userLogins).forEach(x => {
166
+            Object.values(x.connections).forEach(c => c.destroy())
167
+        })
168
+
169
+        Object.values(this.rankServers)
170
+        .map(state => {
171
+            try{
172
+                return state.server.destroy()
173
+            }catch(e){
174
+                getLogger('UserManager').warn(e)
175
+            }
176
+        })
167
     }
177
     }
168
 
178
 
169
     checkExpiredSessions = () => {
179
     checkExpiredSessions = () => {
198
         return true
208
         return true
199
     }
209
     }
200
 
210
 
211
+    changePassword = async (userToken:string, pwHash:string) : Promise<User> => {
212
+        const record = this.getUserRecordByToken(userToken)
213
+        if(!record) return {} as User
214
+        return await this.adminChangePassword(record.user, pwHash)
215
+    }
216
+
217
+    adminChangePassword = async(user:User, pwHash:string) : Promise<User> => {
218
+        const salted = await saltedHash(pwHash, salt)
219
+        await this.admin.knex('users')
220
+        .update({pwhash: salted})
221
+        .where({
222
+            username: user.username
223
+        })
224
+
225
+        const usr = await this.getUser(user.username)
226
+        if(!usr) return {} as any
227
+        await this.adminLogout(usr.username)
228
+        return usr
229
+    }
230
+
201
     setPermission = async (permission: RPCPermission) => {
231
     setPermission = async (permission: RPCPermission) => {
202
         await this.admin.knex('rpcpermissions')
232
         await this.admin.knex('rpcpermissions')
203
         .where('rpcname', '=', permission.rpcname)
233
         .where('rpcname', '=', permission.rpcname)
270
     logout = async (username:string, tokenValue : string) : Promise<void> => {
300
     logout = async (username:string, tokenValue : string) : Promise<void> => {
271
         try{
301
         try{
272
             if(!this.checkTokenOwnedByUser(username, tokenValue)) return
302
             if(!this.checkTokenOwnedByUser(username, tokenValue)) return
303
+            return await this.adminLogout(username)
304
+        }catch(e){
273
 
305
 
306
+        }
307
+    }
308
+
309
+    adminLogout = async(username: string) : Promise<void> => {
310
+        try{
274
             if(this.userLogins[username]){
311
             if(this.userLogins[username]){
275
                 await Promise.all (Object.values(this.userLogins[username].connections).map(async (sock) => {
312
                 await Promise.all (Object.values(this.userLogins[username].connections).map(async (sock) => {
276
-                    await sock.call('navigate', '/auth/login')
313
+                    await sock.call('kick')
277
                 }))
314
                 }))
278
-            }
279
-
280
-            Object.values(this.rankServers)
315
+            
316
+                Object.values(this.rankServers)
281
                 .forEach(state => {
317
                 .forEach(state => {
282
-                    state.allowed = state.allowed.filter(allowed => allowed !== tokenValue)
283
-            })
284
-
285
-            delete this.userLogins[username]
318
+                    state.allowed = state.allowed.filter(allowed => allowed !== this.userLogins[username].auth.token.value)
319
+                })
320
+                delete this.userLogins[username]
321
+            }
286
         }catch(e){
322
         }catch(e){
287
-            console.log(e)
323
+            getLogger('UserManager').warn(e)
288
         }
324
         }
289
     }
325
     }
290
 
326
 
390
         username = username.toLowerCase()
426
         username = username.toLowerCase()
391
         const maybeRecord = this.getUserRecordByToken(tokenValue)
427
         const maybeRecord = this.getUserRecordByToken(tokenValue)
392
         if(!maybeRecord || maybeRecord.auth.user.username != username){
428
         if(!maybeRecord || maybeRecord.auth.user.username != username){
393
-            getLogger('UserManager').warn(`Bad logout attempt
394
-            token by: ${maybeRecord?maybeRecord.auth.user.username:tokenValue}
395
-            tried to logout: ${username}`)
396
             return false
429
             return false
397
         } 
430
         } 
398
         return true
431
         return true

+ 7
- 6
src/backend/Injector/Injector.ts 查看文件

9
 export const Injector = new class {
9
 export const Injector = new class {
10
 
10
 
11
   injectionQueue :any[] = []
11
   injectionQueue :any[] = []
12
-
12
+  rootObj: any
13
   rootInterface : Type<any>
13
   rootInterface : Type<any>
14
   root : Type<any>
14
   root : Type<any>
15
   rootModules: Type<any>[] = []
15
   rootModules: Type<any>[] = []
29
       return this.moduleObjs[target.name] as any
29
       return this.moduleObjs[target.name] as any
30
 
30
 
31
     if(target.name === this.rootInterface.name || target.name === this.root.name){
31
     if(target.name === this.rootInterface.name || target.name === this.root.name){
32
+      if(this.rootObj) return this.rootObj
32
       let modules = this.modules.map(m => {
33
       let modules = this.modules.map(m => {
33
         const module = new m.implementation()
34
         const module = new m.implementation()
34
         if(m.implements)
35
         if(m.implements)
36
         this.moduleObjs[m.implementation.name] = module
37
         this.moduleObjs[m.implementation.name] = module
37
         return module
38
         return module
38
       })
39
       })
39
-      const rootobj = new this.root(modules);
40
+      const rootObj = new this.root(modules);
40
 
41
 
41
-      this.moduleObjs[this.rootInterface.name] = rootobj
42
-      this.moduleObjs[target.name] = rootobj
42
+      this.moduleObjs[this.rootInterface.name] = rootObj
43
+      this.moduleObjs[target.name] = rootObj
43
       while(this.injectionQueue.length > 0){
44
       while(this.injectionQueue.length > 0){
44
         const i = this.injectionQueue.shift()
45
         const i = this.injectionQueue.shift()
45
         if(this.moduleObjs[i.what.name])
46
         if(this.moduleObjs[i.what.name])
47
         else
48
         else
48
           this.injectionQueue.push(i)
49
           this.injectionQueue.push(i)
49
       }
50
       }
50
-
51
-      return rootobj
51
+      this.rootObj = rootObj
52
+      return rootObj
52
     }
53
     }
53
     this.moduleObjs[target.name] = new target()
54
     this.moduleObjs[target.name] = new target()
54
     return this.moduleObjs[target.name] as any   
55
     return this.moduleObjs[target.name] as any   

+ 2
- 6
src/frontend/angular.json 查看文件

9
       "projectType": "application",
9
       "projectType": "application",
10
       "architect": {
10
       "architect": {
11
         "build": {
11
         "build": {
12
-          "builder": "@angular-builders/custom-webpack:browser",
12
+          "builder": "@angular-devkit/build-angular:browser",
13
           "options": {
13
           "options": {
14
-            "customWebpackConfig": {
15
-              "path": "./custom-webpack.config.js",
16
-              "replaceDuplicatePlugins": true
17
-            },
18
             "preserveSymlinks": true,
14
             "preserveSymlinks": true,
19
             "rebaseRootRelativeCssUrls": true,
15
             "rebaseRootRelativeCssUrls": true,
20
             "outputPath": "dist",
16
             "outputPath": "dist",
79
           }
75
           }
80
         },
76
         },
81
         "serve": {
77
         "serve": {
82
-          "builder": "@angular-builders/custom-webpack:dev-server",
78
+          "builder": "@angular-devkit/build-angular:dev-server",
83
           "options": {
79
           "options": {
84
             "browserTarget": "ngx-admin-demo:build"
80
             "browserTarget": "ngx-admin-demo:build"
85
           },
81
           },

+ 0
- 4
src/frontend/custom-webpack.config.js 查看文件

1
-module.exports = {
2
-    externals: ['http', 'fs'],
3
-    node: {global: true, fs: 'empty'}
4
-}

+ 14184
- 10876
src/frontend/package-lock.json
文件差異過大導致無法顯示
查看文件


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

50
     "angular2-chartjs": "0.4.1",
50
     "angular2-chartjs": "0.4.1",
51
     "angular2-toaster": "^7.0.0",
51
     "angular2-toaster": "^7.0.0",
52
     "bootstrap": "4.3.1",
52
     "bootstrap": "4.3.1",
53
-    "chart.js": "2.7.1",
53
+    "chart.js": "^2.9.3",
54
     "ckeditor": "4.7.3",
54
     "ckeditor": "4.7.3",
55
     "classlist.js": "1.1.20150312",
55
     "classlist.js": "1.1.20150312",
56
     "core-js": "2.5.1",
56
     "core-js": "2.5.1",
65
     "ng2-smart-table": "1.3.5",
65
     "ng2-smart-table": "1.3.5",
66
     "ngx-cookie-service": "^2.2.0",
66
     "ngx-cookie-service": "^2.2.0",
67
     "ngx-echarts": "^4.0.1",
67
     "ngx-echarts": "^4.0.1",
68
-    "node-sass": "^4.12.0",
68
+    "node-sass": "^4.13.1",
69
     "normalize.css": "6.0.0",
69
     "normalize.css": "6.0.0",
70
     "pace-js": "1.0.2",
70
     "pace-js": "1.0.2",
71
     "roboto-fontface": "0.8.0",
71
     "roboto-fontface": "0.8.0",
72
-    "rpclibrary": "^1.7.1",
72
+    "rpclibrary": "^1.8.3",
73
     "rxjs": "6.5.2",
73
     "rxjs": "6.5.2",
74
     "rxjs-compat": "6.3.0",
74
     "rxjs-compat": "6.3.0",
75
     "socicon": "3.0.5",
75
     "socicon": "3.0.5",
80
     "zone.js": "~0.9.1"
80
     "zone.js": "~0.9.1"
81
   },
81
   },
82
   "devDependencies": {
82
   "devDependencies": {
83
-    "@angular-devkit/build-angular": "~0.800.2",
83
+    "@angular-devkit/build-angular": "~0.803.24",
84
     "@angular/cli": "^8.0.2",
84
     "@angular/cli": "^8.0.2",
85
     "@angular/compiler-cli": "^8.0.0",
85
     "@angular/compiler-cli": "^8.0.0",
86
     "@angular/language-service": "8.0.0",
86
     "@angular/language-service": "8.0.0",
87
-    "@compodoc/compodoc": "1.0.1",
87
+    "@compodoc/compodoc": "^1.1.11",
88
     "@fortawesome/fontawesome-free": "^5.2.0",
88
     "@fortawesome/fontawesome-free": "^5.2.0",
89
     "@types/d3-color": "1.0.5",
89
     "@types/d3-color": "1.0.5",
90
     "@types/googlemaps": "^3.30.4",
90
     "@types/googlemaps": "^3.30.4",

+ 0
- 5
src/frontend/src/app/@theme/components/header/header.component.html 查看文件

1
 <div class="header-container">
1
 <div class="header-container">
2
-  <div>
3
-    <a (click)="toggleSidebar()" href="#" class="sidebar-toggle">
4
-      <nb-icon icon="menu-2-outline"></nb-icon>
5
-    </a>
6
-  </div>
7
   <div class="logo-container">
2
   <div class="logo-container">
8
     <a (click)="toggleSidebar()" href="#" class="sidebar-toggle">
3
     <a (click)="toggleSidebar()" href="#" class="sidebar-toggle">
9
       <nb-icon icon="menu-2-outline"></nb-icon>
4
       <nb-icon icon="menu-2-outline"></nb-icon>

+ 1
- 6
src/frontend/src/app/frontcraft/auth/login/login.component.html 查看文件

35
            [maxlength]="15"
35
            [maxlength]="15"
36
            [attr.aria-invalid]="password.invalid && password.touched ? true : null">
36
            [attr.aria-invalid]="password.invalid && password.touched ? true : null">
37
   </div>
37
   </div>
38
-
39
-  <div class="form-control-group accept-group">
40
-    <nb-checkbox name="rememberMe" [(ngModel)]="user.rememberMe" *ngIf="rememberMe">Remember me</nb-checkbox>
41
-    <a class="forgot-password" routerLink="../request-password">Forgot Password?</a>
42
-  </div>
43
-
38
+  <br />
44
   <button nbButton
39
   <button nbButton
45
           fullWidth
40
           fullWidth
46
           status="primary"
41
           status="primary"

+ 12
- 8
src/frontend/src/app/frontcraft/auth/register/register.component.html 查看文件

35
            [attr.aria-invalid]="password.invalid && password.touched ? true : null">
35
            [attr.aria-invalid]="password.invalid && password.touched ? true : null">
36
   </div>
36
   </div>
37
 
37
 
38
-  <div class="form-control-group accept-group">
39
-    <nb-checkbox name="rememberMe" [(ngModel)]="user.rememberMe" *ngIf="rememberMe">Remember me</nb-checkbox>
40
-  </div>
41
-
42
   <nb-card>
38
   <nb-card>
43
     <nb-card-body>
39
     <nb-card-body>
44
       <nb-checkbox [(ngModel)]="showApplication" name="amMember" #checkbox><!--I am already a member-->I understand this is super beta and things might not work or are not very pretty</nb-checkbox>
40
       <nb-checkbox [(ngModel)]="showApplication" name="amMember" #checkbox><!--I am already a member-->I understand this is super beta and things might not work or are not very pretty</nb-checkbox>
45
       <br />
41
       <br />
46
       
42
       
47
       <span > <!--*ngIf="showApplication"-->
43
       <span > <!--*ngIf="showApplication"-->
48
-        And my main is &nbsp; <input name="preMember" [(ngModel)]="character.name"  nbInput>, a 
44
+        And my main is &nbsp; <input nbInput [required]="true" name="preMember" [(ngModel)]="character.name"  >, a 
49
         <nb-select [(selected)]="character.race" placeholder="Race" (selectedChange)="onSelectRace()">
45
         <nb-select [(selected)]="character.race" placeholder="Race" (selectedChange)="onSelectRace()">
50
           <nb-option *ngFor="let race of races" [value]="race">{{race}}</nb-option>
46
           <nb-option *ngFor="let race of races" [value]="race">{{race}}</nb-option>
51
         </nb-select>
47
         </nb-select>
52
-        <nb-select [(selected)]="character.spec" placeholder="Spec" (selectedChange)="onSelectSpec()">
48
+        <nb-select 
49
+          [(selected)]="character.spec" 
50
+          placeholder="Spec" 
51
+          (selectedChange)="onSelectSpec()">
53
           <nb-option *ngFor="let spec of specs" [value]="spec">{{spec}}</nb-option>
52
           <nb-option *ngFor="let spec of specs" [value]="spec">{{spec}}</nb-option>
54
         </nb-select>
53
         </nb-select>
55
-        <nb-select [(selected)]="character.class" placeholder="Class" (selectedChange)="onSelectClass()">
54
+        <nb-select 
55
+          [(selected)]="character.class" 
56
+          placeholder="Class" 
57
+          (selectedChange)="onSelectClass()">
56
           <nb-option *ngFor="let class of classes"  [value]="class">{{class}}</nb-option>
58
           <nb-option *ngFor="let class of classes"  [value]="class">{{class}}</nb-option>
57
         </nb-select>
59
         </nb-select>
58
          with rank 
60
          with rank 
59
-        <nb-select [(selected)]="user.rank" placeholder="Rank">
61
+        <nb-select 
62
+        [(selected)]="user.rank" 
63
+        placeholder="Rank">
60
           <nb-option *ngFor="let rank of ranks" [value]="rank" >{{rank}}</nb-option>
64
           <nb-option *ngFor="let rank of ranks" [value]="rank" >{{rank}}</nb-option>
61
         </nb-select>
65
         </nb-select>
62
       </span>
66
       </span>

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

195
         this.displayedtokens = this.tokens
195
         this.displayedtokens = this.tokens
196
       }else{
196
       }else{
197
         this.displayedtokens = {}
197
         this.displayedtokens = {}
198
-        Object.entries(this.tokens).forEach((e: [string, (Character & SRToken & Item)[]]) => {
198
+        Object.entries(this.tokens).forEach((e: [string /*itemname*/, (Character & SRToken & Item)[]]) => {
199
           const filteredTokens = e[1].filter(item => {
199
           const filteredTokens = e[1].filter(item => {
200
             return item.itemname.toLocaleLowerCase().includes(this.search.toLocaleLowerCase())
200
             return item.itemname.toLocaleLowerCase().includes(this.search.toLocaleLowerCase())
201
           })
201
           })

+ 5
- 3
src/frontend/src/app/frontcraft/pages/shop/buytoken.component.ts 查看文件

9
 @Component({
9
 @Component({
10
     selector: 'buyToken',
10
     selector: 'buyToken',
11
     template: `
11
     template: `
12
-    <nb-card class="col-12 col-xl-9">
12
+    <nb-card style="width: 500px">
13
       <nb-card-header>
13
       <nb-card-header>
14
         Buy {{item.itemname}}
14
         Buy {{item.itemname}}
15
       </nb-card-header>
15
       </nb-card-header>
19
         </p>  
19
         </p>  
20
         <div *ngIf="currency>0">
20
         <div *ngIf="currency>0">
21
             <nb-alert accent="danger" *ngIf="invalidatedTokens.length > 0">
21
             <nb-alert accent="danger" *ngIf="invalidatedTokens.length > 0">
22
-                Claiming this reserve invalidates the following streaks. <br />
23
-                This is not reversible.
22
+                Claiming this reserve puts the following streaks to zero <br />
23
+                <span>
24
+                  <nb-icon icon="alert-triangle-outline" status="warning"></nb-icon>&nbsp;This is not reversible&nbsp;<nb-icon icon="alert-triangle-outline" status="warning"></nb-icon>
25
+                </span>
24
                 <ul *ngFor="let item of invalidatedTokens">
26
                 <ul *ngFor="let item of invalidatedTokens">
25
                     <li>
27
                     <li>
26
                         [ {{item.level}} ] 
28
                         [ {{item.level}} ] 

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

6
         <h2 style="text-transform: capitalize;">{{user.username}}</h2>
6
         <h2 style="text-transform: capitalize;">{{user.username}}</h2>
7
     </nb-card-header>
7
     </nb-card-header>
8
     <nb-card-body>
8
     <nb-card-body>
9
-        {{user.MC}} MC
10
-        {{user.BWL}} BWL
11
-        {{user.ZG}} ZG
12
-        {{user.AQ20}} AQ20
13
-        {{user.AQ40}} AQ40
9
+
10
+        <h3>Rank</h3>
11
+        <span *ngIf="!manageUser">
12
+            {{user.rank}}
13
+        </span>
14
+        <nb-select 
15
+            *ngIf="manageUser"
16
+            [(selected)]="user.rank" 
17
+            placeholder="Rank"
18
+            (selectedChange)="onSelectRank()">
19
+
20
+          <nb-option *ngFor="let rank of ranks" [value]="rank" >{{rank}}</nb-option>
21
+        </nb-select>
22
+
23
+        <h3 *ngIf="myProfile || manageUser">Password</h3>
24
+        <form (ngSubmit)="submitPasswordChange()" #form="ngForm" aria-labelledby="title" *ngIf="myProfile || manageUser">
25
+            <input nbInput
26
+                fullWidth
27
+                type="password"
28
+                [(ngModel)]="newPw"
29
+                name="newPw"
30
+                id="input-newPw"
31
+                pattern=".+"
32
+                placeholder="New Password"
33
+                fieldSize="small"
34
+                autofocus
35
+                [required]="true">
36
+
37
+            <input nbInput
38
+                fullWidth
39
+                type="password"
40
+                [(ngModel)]="newPwConfirm"
41
+                name="newPwConfirm"
42
+                id="input-newPwConfirm"
43
+                pattern=".+"
44
+                placeholder="Confirm Password"
45
+                fieldSize="small"
46
+                autofocus
47
+                [required]="true">
48
+
49
+            <button nbButton
50
+                fullWidth
51
+                status="primary"
52
+                size="small"
53
+                [disabled]="!form.valid || newPw != newPwConfirm"
54
+                [class.btn-pulse]="submitted">
55
+                Change
56
+            </button>
57
+        </form>
58
+        <br />
59
+
60
+        <h3>Avaiable Reserves</h3>
61
+        {{user.MC}} MC |
62
+        {{user.BWL}} BWL |
63
+        {{user.ZG}} ZG |
64
+        {{user.AQ20}} AQ20 |
65
+        {{user.AQ40}} AQ40 |
14
         {{user.Naxx}} Naxx
66
         {{user.Naxx}} Naxx
67
+        <br />
15
       <ng-container *ngFor="let char of characters">
68
       <ng-container *ngFor="let char of characters">
16
           <character [name]="char.charactername" [link]="'character'"></character>
69
           <character [name]="char.charactername" [link]="'character'"></character>
17
       </ng-container>
70
       </ng-container>

+ 34
- 3
src/frontend/src/app/frontcraft/pages/user/user.component.ts 查看文件

1
 import { Component, OnInit } from '@angular/core';
1
 import { Component, OnInit } from '@angular/core';
2
-import { ApiService } from '../../services/login-api';
2
+import { ApiService, hash } from '../../services/login-api';
3
 import { Router, ActivatedRoute } from '@angular/router';
3
 import { Router, ActivatedRoute } from '@angular/router';
4
 import { User, Spec, Character } from '../../../../../../backend/Types/Types';
4
 import { User, Spec, Character } from '../../../../../../backend/Types/Types';
5
 import { getClassColor } from '../../../../../../backend/Types/PlayerSpecs';
5
 import { getClassColor } from '../../../../../../backend/Types/PlayerSpecs';
6
 import { _Tiers } from '../../../../../../backend/Types/Items';
6
 import { _Tiers } from '../../../../../../backend/Types/Items';
7
+import { _Rank } from '../../../../../../backend/Types/Types';
8
+import { NbToastrService } from '@nebular/theme';
7
 
9
 
8
 @Component({
10
 @Component({
9
   selector: 'user-component',
11
   selector: 'user-component',
11
 })
13
 })
12
 export class FrontcraftUserComponent implements OnInit{
14
 export class FrontcraftUserComponent implements OnInit{
13
 
15
 
16
+  newPw
17
+  newPwConfirm
18
+
19
+  ranks = _Rank
20
+  myProfile = false
21
+  manageUser
14
   user:User = {} as any
22
   user:User = {} as any
15
   characters : (Character & Spec)[] = []
23
   characters : (Character & Spec)[] = []
16
 
24
 
17
   constructor(
25
   constructor(
18
     private route: ActivatedRoute,
26
     private route: ActivatedRoute,
19
-    private api : ApiService
27
+    private api : ApiService,
28
+    private toastr: NbToastrService
20
   ){}
29
   ){}
21
 
30
 
22
   async ngOnInit(){
31
   async ngOnInit(){
23
     const param = this.route.snapshot.paramMap.get('name');
32
     const param = this.route.snapshot.paramMap.get('name');
24
     const usr = await this.api.get('UserManager').getUser(param)
33
     const usr = await this.api.get('UserManager').getUser(param)
25
 
34
 
26
-
27
     if(!usr) return
35
     if(!usr) return
28
     this.user = usr
36
     this.user = usr
29
 
37
 
38
+    this.manageUser = this.api.get('manageUser')
39
+    this.myProfile = this.api.getCurrentUser().username === this.user.username
40
+    
30
     const characters = await this.api.get('CharacterManager').getCharactersOfUser(this.user.username)
41
     const characters = await this.api.get('CharacterManager').getCharactersOfUser(this.user.username)
31
     characters.forEach(async c => {
42
     characters.forEach(async c => {
32
       const tokens = await this.api.get('ItemManager').getTokens(c, _Tiers, true)
43
       const tokens = await this.api.get('ItemManager').getTokens(c, _Tiers, true)
35
     })
46
     })
36
     this.characters = characters
47
     this.characters = characters
37
   }
48
   }
49
+
50
+  async onSelectRank(){
51
+    const manage = this.api.get('manageUser')
52
+    if(!manage) return
53
+    await manage.changeRank(this.user, this.user.rank)
54
+    this.toastr.success("Rank changed to "+this.user.rank, "Update success")
55
+  }
56
+
57
+  async submitPasswordChange(){
58
+    const pw = await hash(this.newPw)
59
+    this.newPw = null
60
+    this.newPwConfirm = null
61
+
62
+    const manage = this.api.get('manageUser')
63
+    if(!manage){
64
+      await this.api.get('UserManager').changePassword(this.api.getAuth().token.value, pw)
65
+    }else{
66
+      await manage.adminChangePassword(this.user, pw)
67
+    }
68
+  }
38
 }
69
 }

+ 58
- 15
src/frontend/src/app/frontcraft/services/login-api.ts 查看文件

6
 import { Router } from '@angular/router';
6
 import { Router } from '@angular/router';
7
 import { ShoutMessage } from '../../../../../backend/Components/Shoutbox/Interface';
7
 import { ShoutMessage } from '../../../../../backend/Components/Shoutbox/Interface';
8
 import { saltedHash } from '../../../../../backend/Util/hash';
8
 import { saltedHash } from '../../../../../backend/Util/hash';
9
+import { NbToastrService } from '@nebular/theme';
9
 
10
 
10
 @Injectable()
11
 @Injectable()
11
 export class ApiService{
12
 export class ApiService{
16
     constructor(
17
     constructor(
17
         private injector: Injector,
18
         private injector: Injector,
18
         private cookieSvc : CookieService,
19
         private cookieSvc : CookieService,
19
-        private ngZone : NgZone
20
+        private ngZone : NgZone,
21
+        private toastr: NbToastrService
20
     ){}
22
     ){}
21
 
23
 
22
     getUnprivilegedSocket = () : RPCSocket & FrontcraftIfc => this.socket
24
     getUnprivilegedSocket = () : RPCSocket & FrontcraftIfc => this.socket
30
                 auth.port, 
32
                 auth.port, 
31
                 window.location.hostname
33
                 window.location.hostname
32
             )
34
             )
33
-           
34
-            const authSock = await sock.connect<RPCSocket & SomeOf<FrontcraftFeatureIfc>>(auth.token.value)
35
 
35
 
36
             sock.hook('kick', () => {
36
             sock.hook('kick', () => {
37
-                console.log("I got kicked");
37
+                this.logout()
38
             })
38
             })
39
+
39
             sock.hook('getUserData', () => auth)
40
             sock.hook('getUserData', () => auth)
40
             sock.hook('navigate', (where:string) => {
41
             sock.hook('navigate', (where:string) => {
41
                 this.ngZone.run( () => {
42
                 this.ngZone.run( () => {
42
                     this.injector.get(Router).navigateByUrl(where)
43
                     this.injector.get(Router).navigateByUrl(where)
43
                 })
44
                 })
44
             })
45
             })
45
-            sock.on('error', (e) => {
46
-                sock.destroy();
47
-                
46
+
47
+            sock.on('close', async () => {
48
+                //handled via unprivileged socket
48
             })
49
             })
50
+
51
+            sock.on('error', async (e) => {
52
+                //handled via unprivileged socket
53
+            })
54
+            const authSock = await sock.connect<RPCSocket & SomeOf<FrontcraftFeatureIfc>>(auth.token.value)
49
             
55
             
50
             this.auth = auth
56
             this.auth = auth
51
             this.privSocket = authSock
57
             this.privSocket = authSock
52
             this.cookieSvc.set('token', JSON.stringify(auth))
58
             this.cookieSvc.set('token', JSON.stringify(auth))
53
             return authSock
59
             return authSock
54
         }catch(e){ 
60
         }catch(e){ 
55
-            //login failed
56
-            throw new Error(e)
61
+            if(this.privSocket) this.privSocket.destroy()
62
+            return;
57
         }
63
         }
58
     }
64
     }
59
 
65
 
76
 
82
 
77
     login = async (username: string, password: string) : Promise<RPCSocket & SomeOf<FrontcraftFeatureIfc>> => {
83
     login = async (username: string, password: string) : Promise<RPCSocket & SomeOf<FrontcraftFeatureIfc>> => {
78
         const pwHash = await hash(password)
84
         const pwHash = await hash(password)
79
-        const auth = await this.socket.UserManager.login(username, pwHash)
85
+        let auth
86
+        try{
87
+            auth = await this.socket.UserManager.login(username, pwHash)
88
+        }catch(e){
89
+            this.toastr.danger("Login failed", "Error")
90
+            return
91
+        }
80
 
92
 
81
         if(!auth){ 
93
         if(!auth){ 
82
             await this.logout()
94
             await this.logout()
95
+            this.toastr.danger("Login failed", "Error")
83
             throw new Error("Login failed")
96
             throw new Error("Login failed")
84
         }
97
         }
98
+
99
+        //attach error handler now so failed logins dont trigger reloads
100
+        this.socket.on('error', async (err) => {
101
+            location.reload()
102
+        })
103
+
85
         const sock = await this.getPrivilegedSocket(auth)
104
         const sock = await this.getPrivilegedSocket(auth)
86
         return sock
105
         return sock
87
     }
106
     }
93
 
112
 
94
     logout = async () => {
113
     logout = async () => {
95
         this.cookieSvc.set('token', undefined)
114
         this.cookieSvc.set('token', undefined)
96
-        if(this.auth) await this.socket.UserManager.logout(this.auth.user.username, this.auth.token.value)
115
+        if(this.auth){
116
+            try{
117
+                await this.socket.UserManager.logout(this.auth.user.username, this.auth.token.value)
118
+            }catch(e){
119
+                //socket is dead
120
+            }
121
+        } 
122
+
97
         if(this.privSocket) this.privSocket.destroy()
123
         if(this.privSocket) this.privSocket.destroy()
98
         this.privSocket = null
124
         this.privSocket = null
99
         this.auth  = null
125
         this.auth  = null
126
+        
100
         this.ngZone.run(() => {
127
         this.ngZone.run(() => {
101
             this.injector.get(Router).navigate(['/auth']);
128
             this.injector.get(Router).navigate(['/auth']);
102
         })
129
         })
103
     }
130
     }
104
 
131
 
105
     initialize = async () : Promise<any> => {
132
     initialize = async () : Promise<any> => {
106
-        const sock = await RPCSocket.makeSocket<FrontcraftIfc>(20000, window.location.hostname)
133
+        if(this.socket){
134
+            this.socket.destroy()
135
+            this.socket = null
136
+        }
137
+
138
+        try{
139
+            let conn = new RPCSocket(20000, window.location.hostname)
140
+            conn.on('close', async () => {
141
+            })
142
+
143
+            
144
+
145
+            this.socket = await conn.connect<FrontcraftIfc>()
146
+        }catch(e){
147
+            alert('Unable to connect. The server appears to be down.\nPress OK to refresh the page')
148
+            location.reload()
149
+            return;
150
+        }
107
 
151
 
108
-        this.socket = sock
109
         try{
152
         try{
110
             const cookie = JSON.parse(this.cookieSvc.get('token'))
153
             const cookie = JSON.parse(this.cookieSvc.get('token'))
111
             
154
             
112
             if(cookie != null) {
155
             if(cookie != null) {
113
                 try{
156
                 try{
114
-                    const auth = await sock.UserManager.getAuth(cookie.token.value)
115
-                    if(!auth) return sock
157
+                    const auth = await this.socket.UserManager.getAuth(cookie.token.value)
158
+                    if(!auth) return this.socket
116
                     return await this.getPrivilegedSocket(auth)
159
                     return await this.getPrivilegedSocket(auth)
117
                 }catch(e){
160
                 }catch(e){
118
                     await this.logout()
161
                     await this.logout()

+ 35
- 12
src/frontend/src/index.html 查看文件

2
 <html>
2
 <html>
3
 <head>
3
 <head>
4
   <meta charset="utf-8">
4
   <meta charset="utf-8">
5
-  <title>ngx-admin Demo Application</title>
5
+  <title>Frontcraft</title>
6
+  <link rel="stylesheet" href="https://fonts.googleapis.com/css?family=Montserrat">
7
+  <style>
8
+  @import url('https://fonts.googleapis.com/css?family=Montserrat');
9
+
10
+  .loadTitle {
11
+    font-family: 'Montserrat';
12
+    text-align: center;
13
+    color: #FFF;
14
+    display: flex;
15
+    flex-direction: column;
16
+    align-items: center;
17
+    justify-content: center;
18
+    letter-spacing: 1px;
19
+    padding-top: calc(50vh - 120px);
20
+  }
21
+
22
+  .loadH {
23
+    background-image: url('https://media.giphy.com/media/26BROrSHlmyzzHf3i/giphy.gif');
24
+    background-size: cover;
25
+    color: transparent;
26
+    background-clip: text;
27
+    -moz-background-clip: text;
28
+    -webkit-background-clip: text;
29
+    text-transform: uppercase;
30
+    font-size: min(10vw, 120px);
31
+    margin: 10px 0;
32
+  }
33
+  </style>
6
 
34
 
7
   <base href="/">
35
   <base href="/">
8
 
36
 
11
   <link rel="icon" type="image/x-icon" href="favicon.ico">
39
   <link rel="icon" type="image/x-icon" href="favicon.ico">
12
 </head>
40
 </head>
13
 <body>
41
 <body>
14
-  <ngx-app>Loading...</ngx-app>
15
-
16
-  <style>@-webkit-keyframes spin{0%{transform:rotate(0)}100%{transform:rotate(360deg)}}@-moz-keyframes spin{0%{-moz-transform:rotate(0)}100%{-moz-transform:rotate(360deg)}}@keyframes spin{0%{transform:rotate(0)}100%{transform:rotate(360deg)}}.spinner{position:fixed;top:0;left:0;width:100%;height:100%;z-index:1003;background: #000000;overflow:hidden}  .spinner div:first-child{display:block;position:relative;left:50%;top:50%;width:150px;height:150px;margin:-75px 0 0 -75px;border-radius:50%;box-shadow:0 3px 3px 0 rgba(255,56,106,1);transform:translate3d(0,0,0);animation:spin 2s linear infinite}  .spinner div:first-child:after,.spinner div:first-child:before{content:'';position:absolute;border-radius:50%}  .spinner div:first-child:before{top:5px;left:5px;right:5px;bottom:5px;box-shadow:0 3px 3px 0 rgb(255, 228, 32);-webkit-animation:spin 3s linear infinite;animation:spin 3s linear infinite}  .spinner div:first-child:after{top:15px;left:15px;right:15px;bottom:15px;box-shadow:0 3px 3px 0 rgba(61, 175, 255,1);animation:spin 1.5s linear infinite}</style>
17
-  <div id="nb-global-spinner" class="spinner">
18
-    <div class="blob blob-0"></div>
19
-    <div class="blob blob-1"></div>
20
-    <div class="blob blob-2"></div>
21
-    <div class="blob blob-3"></div>
22
-    <div class="blob blob-4"></div>
23
-    <div class="blob blob-5"></div>
42
+  <ngx-app></ngx-app>
43
+  <div id="nb-global-spinner" class="spinner" style="background-color: #111; height: 100vh;">
44
+    <div class="loadTitle">
45
+      <h1 class="loadH">Tranquil</h1>
46
+    </div>
24
   </div>
47
   </div>
25
-
48
+  
26
 </body>
49
 </body>
27
 </html>
50
 </html>

+ 3
- 0
src/frontend/src/polyfills.ts 查看文件

55
 if (typeof SVGElement.prototype.contains === 'undefined') {
55
 if (typeof SVGElement.prototype.contains === 'undefined') {
56
   SVGElement.prototype.contains = HTMLDivElement.prototype.contains;
56
   SVGElement.prototype.contains = HTMLDivElement.prototype.contains;
57
 }
57
 }
58
+
59
+(window as any).global = window;
60
+(window as any).global.Buffer = (window as any).global.Buffer || require('buffer').Buffer;

+ 2
- 17
test/backendTest.ts 查看文件

53
         rpcname: 'softreserveCurrency', ...adminsOnly
53
         rpcname: 'softreserveCurrency', ...adminsOnly
54
     }, {
54
     }, {
55
         rpcname: 'manageRaid', ...adminsOnly
55
         rpcname: 'manageRaid', ...adminsOnly
56
+    }, {
57
+        rpcname: 'manageUser', ...adminsOnly
56
     }]
58
     }]
57
 
59
 
58
 const testAccounts: protoAccount[] = [
60
 const testAccounts: protoAccount[] = [
271
                 undefined, 2, "str-to-ap bias"
273
                 undefined, 2, "str-to-ap bias"
272
             ),
274
             ),
273
 
275
 
274
-            makePrio(
275
-                'Band of Accuria',
276
-                { class: 'Warrior', specname: 'Protection' },
277
-                undefined, 2, "hit bias"
278
-            ),
279
-
280
             makePrio(
276
             makePrio(
281
                 'Bracers of Arcane Accuracy',
277
                 'Bracers of Arcane Accuracy',
282
                 { class: 'Warlock', specname: 'Demonology' },
278
                 { class: 'Warlock', specname: 'Demonology' },
376
                 undefined, 1, "hit bias"
372
                 undefined, 1, "hit bias"
377
             ),
373
             ),
378
 
374
 
379
-            makePrio(
380
-                'Chromatic Boots',
381
-                { class: 'Warrior', specname: 'Protection' },
382
-                undefined, 2, "hit bias"
383
-            ),
384
-
385
             makePrio(
375
             makePrio(
386
                 'Crul\'shorukh, Edge of Chaos',
376
                 'Crul\'shorukh, Edge of Chaos',
387
                 undefined,
377
                 undefined,
388
                 "Human", -2, "Non-human"
378
                 "Human", -2, "Non-human"
389
             ),
379
             ),
390
-            makePrio(
391
-                'Crul\'shorukh, Edge of Chaos',
392
-                { class: 'Warrior', specname: 'Protection' },
393
-                undefined, 2, "nice dps bias"
394
-            ),
395
             makePrio(
380
             makePrio(
396
                 'Crul\'shorukh, Edge of Chaos',
381
                 'Crul\'shorukh, Edge of Chaos',
397
                 { class: 'Warrior', specname: 'Fury' },
382
                 { class: 'Warrior', specname: 'Fury' },

Loading…
取消
儲存