Browse Source

safety commit before system upgrade

master
peter 5 years ago
parent
commit
f7f770a40c
36 changed files with 650 additions and 124 deletions
  1. 43
    16
      src/backend/Components/Character/CharacterManager.ts
  2. 3
    1
      src/backend/Components/Character/Interface.ts
  3. 2
    0
      src/backend/Components/Character/RPCInterface.ts
  4. 8
    9
      src/backend/Components/Item/ItemManager.ts
  5. 3
    2
      src/backend/Components/Login/Interface.ts
  6. 50
    34
      src/backend/Components/Login/LoginManager.ts
  7. 2
    2
      src/backend/Components/Raid/Interface.ts
  8. 31
    17
      src/backend/Components/Raid/RaidManager.ts
  9. 3
    3
      src/backend/Injector/Injector.ts
  10. 3
    3
      src/backend/Injector/ServiceDecorator.ts
  11. 16
    2
      src/backend/Types/PlayerSpecs.ts
  12. 13
    8
      src/backend/Types/Types.ts
  13. 3
    3
      src/frontend/package-lock.json
  14. 1
    1
      src/frontend/package.json
  15. 1
    1
      src/frontend/src/app/@theme/components/header/header.component.html
  16. 3
    1
      src/frontend/src/app/@theme/components/header/header.component.ts
  17. 1
    0
      src/frontend/src/app/app-routing.module.ts
  18. 0
    1
      src/frontend/src/app/app.module.ts
  19. 1
    1
      src/frontend/src/app/frontcraft/auth/register/register.component.html
  20. 18
    1
      src/frontend/src/app/frontcraft/auth/register/register.component.ts
  21. 10
    0
      src/frontend/src/app/frontcraft/pages/character/character.component.html
  22. 34
    0
      src/frontend/src/app/frontcraft/pages/character/character.component.ts
  23. 35
    1
      src/frontend/src/app/frontcraft/pages/dashboard/dashboard.component.html
  24. 42
    0
      src/frontend/src/app/frontcraft/pages/dashboard/dashboard.component.scss
  25. 54
    7
      src/frontend/src/app/frontcraft/pages/dashboard/dashboard.component.ts
  26. 10
    0
      src/frontend/src/app/frontcraft/pages/dashboard/tree-grid-shared.scss
  27. 10
    1
      src/frontend/src/app/frontcraft/pages/pages-layout.component.ts
  28. 15
    0
      src/frontend/src/app/frontcraft/pages/pages-routing.module.ts
  29. 9
    1
      src/frontend/src/app/frontcraft/pages/pages.module.ts
  30. 36
    0
      src/frontend/src/app/frontcraft/pages/people/people.component.html
  31. 42
    0
      src/frontend/src/app/frontcraft/pages/people/people.component.scss
  32. 64
    0
      src/frontend/src/app/frontcraft/pages/people/people.component.ts
  33. 10
    0
      src/frontend/src/app/frontcraft/pages/people/tree-grid-shared.scss
  34. 24
    0
      src/frontend/src/app/frontcraft/pages/user/user.component.html
  35. 38
    0
      src/frontend/src/app/frontcraft/pages/user/user.component.ts
  36. 12
    8
      src/frontend/src/app/frontcraft/services/login-api.ts

+ 43
- 16
src/backend/Components/Character/CharacterManager.ts View File

1
 import { RPCInterface } from "rpclibrary";
1
 import { RPCInterface } from "rpclibrary";
2
 import { Inject, Module } from "../../Injector/ServiceDecorator";
2
 import { Inject, Module } from "../../Injector/ServiceDecorator";
3
-import { TableDefiniton, Character } from "../../Types/Types";
3
+import { TableDefiniton, Character, Spec, User } from "../../Types/Types";
4
 import { CharacterManagerIfc } from "./RPCInterface";
4
 import { CharacterManagerIfc } from "./RPCInterface";
5
 import { FrontworkComponent } from "../../Types/FrontworkComponent";
5
 import { FrontworkComponent } from "../../Types/FrontworkComponent";
6
 import { getSpecTableData, SpecT } from "../../Types/PlayerSpecs";
6
 import { getSpecTableData, SpecT } from "../../Types/PlayerSpecs";
18
     private admin: IAdmin   
18
     private admin: IAdmin   
19
 
19
 
20
     @Inject(ILoginManager)
20
     @Inject(ILoginManager)
21
-    private loginManager : any
21
+    private loginManager : ILoginManager
22
 
22
 
23
     exportRPCs = () => [
23
     exportRPCs = () => [
24
         {
24
         {
25
-           name: 'getSpecId' as 'getSpecId',
26
-           call: this.getSpecId
25
+            name: 'getSpecId' as 'getSpecId',
26
+            call: this.getSpecId
27
+        },{
28
+            name: 'getCharacterByName' as 'getCharacterByName',
29
+            call: this.getCharacterByName
30
+        },{
31
+            name: 'getCharacters' as 'getCharacters',
32
+            call: this.getCharacters
33
+        },{
34
+            name: 'getCharactersOfUser' as 'getCharactersOfUser',
35
+            call: this.getCharactersOfUser
27
         }
36
         }
28
     ]
37
     ]
29
 
38
 
44
             name: 'characters',
53
             name: 'characters',
45
             tableBuilder: (table) => {
54
             tableBuilder: (table) => {
46
                 table.increments("id").primary()
55
                 table.increments("id").primary()
47
-                table.string("name").notNullable().unique()
56
+                table.string("charactername").notNullable().unique()
48
                 table.integer("specid").notNullable()
57
                 table.integer("specid").notNullable()
49
                 table.foreign("specid").references("specs.id")
58
                 table.foreign("specid").references("specs.id")
50
                 table.integer("userid").notNullable()
59
                 table.integer("userid").notNullable()
55
             tableBuilder: (table) => {
64
             tableBuilder: (table) => {
56
                 table.increments("id")
65
                 table.increments("id")
57
                 table.string('class')
66
                 table.string('class')
58
-                table.string('name')
59
-                table.unique(['class', 'name'])
67
+                table.string('specname')
68
+                table.unique(['class', 'specname'])
60
             }
69
             }
61
         }
70
         }
62
     ]
71
     ]
64
     private initialized = false
73
     private initialized = false
65
     
74
     
66
     initialize = async () => {
75
     initialize = async () => {
67
-        if(!this.initialized)
68
-            this.initialized = true
69
-        //initialize spec table
70
-
71
-        getLogger('CharacterManager').debug('inserting specs')
72
-
76
+        if(this.initialized) return
77
+        this.initialized = true
73
         await this.admin.knex('specs').insert(getSpecTableData()).catch(e => { console.log("skipping spec insertion") })
78
         await this.admin.knex('specs').insert(getSpecTableData()).catch(e => { console.log("skipping spec insertion") })
74
     }
79
     }
75
 
80
 
76
     createCharacter = async (userToken: string, character : Character) : Promise<Character> => {
81
     createCharacter = async (userToken: string, character : Character) : Promise<Character> => {
77
         try{
82
         try{
83
+            character.charactername = character.charactername.toLowerCase()
78
             const user = this.loginManager.getUserRecordByToken(userToken)
84
             const user = this.loginManager.getUserRecordByToken(userToken)
79
             await this.admin.knex('characters').insert(character)
85
             await this.admin.knex('characters').insert(character)
80
             const char : Character = await this.admin.knex.select('*').from('characters').where(character).first()
86
             const char : Character = await this.admin.knex.select('*').from('characters').where(character).first()
90
         return this.admin.knex.select('*').from('characters')
96
         return this.admin.knex.select('*').from('characters')
91
     }
97
     }
92
 
98
 
99
+    getCharacterByName = async(charactername: string) : Promise<(Character & User & Spec) | void> => {
100
+        charactername = charactername.toLowerCase()
101
+        return await this.admin.knex('characters as c')
102
+        .join('specs as s', 's.id', '=', 'c.specid')
103
+        .join('users as u', 'u.id', '=', 'c.userid')
104
+        .select('charactername', 'class', 'specname', 'username', 'rank', 'locked', )
105
+        .where('charactername', '=', charactername)
106
+        .first()
107
+    }
108
+
109
+    getCharactersOfUser = async(username: string) : Promise<(Character & Spec)[]> => {
110
+        username = username.toLowerCase()
111
+        return await this.admin.knex('characters as c')
112
+        .join('users as u', 'u.id', '=', 'c.userid')
113
+        .join('specs as s', 's.id', '=', 'c.specid')
114
+        .select('class', 'charactername', 'class', 'specname')
115
+        .where('u.username', '=', username)
116
+    }
117
+
93
     getSpecId = async <c extends keyof SpecT>(clazz: c, name: SpecT[c]) => await this.admin.knex
118
     getSpecId = async <c extends keyof SpecT>(clazz: c, name: SpecT[c]) => await this.admin.knex
94
     .from('specs')
119
     .from('specs')
95
     .select('id')
120
     .select('id')
96
-    .where({
121
+    .where(<Spec>{
97
         class: clazz,
122
         class: clazz,
98
-        name: name
99
-    }).first().then(spec => spec.id)
123
+        specname: name
124
+    })
125
+    .first()
126
+    .then(spec => spec.id)
100
 
127
 
101
 }
128
 }

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

1
-import { Character } from "../../Types/Types"
1
+import { Character, Spec, User } from "../../Types/Types"
2
 import { SpecT } from "../../Types/PlayerSpecs"
2
 import { SpecT } from "../../Types/PlayerSpecs"
3
 
3
 
4
 
4
 
6
     createCharacter: (usertoken: string, char : Character) => Promise<Character>
6
     createCharacter: (usertoken: string, char : Character) => Promise<Character>
7
     getSpecId: <c extends keyof SpecT>(clazz: c, name: SpecT[c]) => Promise<number>
7
     getSpecId: <c extends keyof SpecT>(clazz: c, name: SpecT[c]) => Promise<number>
8
     getCharacters: () => Promise<Character[]>
8
     getCharacters: () => Promise<Character[]>
9
+    getCharacterByName: (charactername: string) => Promise<(Character & User & Spec) | void>
10
+    getCharactersOfUser: (username: string) => Promise<(Character & Spec)[]>
9
 }
11
 }

+ 2
- 0
src/backend/Components/Character/RPCInterface.ts View File

5
     CharacterManager: {
5
     CharacterManager: {
6
         getSpecId : ICharacterManager['getSpecId']
6
         getSpecId : ICharacterManager['getSpecId']
7
         getCharacters : ICharacterManager['getCharacters']
7
         getCharacters : ICharacterManager['getCharacters']
8
+        getCharacterByName : ICharacterManager['getCharacterByName']
9
+        getCharactersOfUser: ICharacterManager['getCharactersOfUser']
8
     }
10
     }
9
 }
11
 }
10
 
12
 

+ 8
- 9
src/backend/Components/Item/ItemManager.ts View File

44
 
44
 
45
         try{
45
         try{
46
             return <Item>{
46
             return <Item>{
47
-                name: r.wowhead.item[0].name[0],
47
+                itemname: r.wowhead.item[0].name[0],
48
                 iconname: r.wowhead.item[0].icon[0]._,
48
                 iconname: r.wowhead.item[0].icon[0]._,
49
                 url: r.wowhead.item[0].link[0],
49
                 url: r.wowhead.item[0].link[0],
50
                 quality: r.wowhead.item[0].quality[0]._,
50
                 quality: r.wowhead.item[0].quality[0]._,
58
     getTableDefinitions(): TableDefiniton[] {
58
     getTableDefinitions(): TableDefiniton[] {
59
         return [
59
         return [
60
             {
60
             {
61
-                name: 'reservations',
61
+                name: 'tokens',
62
                 tableBuilder: (table) => {
62
                 tableBuilder: (table) => {
63
-                    table.integer("user_id").primary()
64
-                    table.foreign("user_id").references("id").inTable('users')
65
-                    table.integer("item_id").primary()
66
-                    table.foreign("item_id").references("id").inTable('items')
67
-                    table.integer("raid_id").primary()
68
-                    table.foreign("raid_id").references("id").inTable('raids')
63
+                    table.integer("characterid").primary()
64
+                    table.foreign("characterid").references("id").inTable('characters')
65
+                    table.integer("itemid").primary()
66
+                    table.foreign("itemid").references("id").inTable('items')
67
+                    table.integer("level")
69
                 }
68
                 }
70
             },{
69
             },{
71
                 name: 'items',
70
                 name: 'items',
72
                 tableBuilder: (table) => {
71
                 tableBuilder: (table) => {
73
                     table.increments("id").primary()
72
                     table.increments("id").primary()
74
-                    table.string('name').unique().notNullable()
73
+                    table.string('itemname').unique().notNullable()
75
                     table.string('iconname').notNullable()
74
                     table.string('iconname').notNullable()
76
                     table.string('url').notNullable()
75
                     table.string('url').notNullable()
77
                     table.string('quality').defaultTo('Epic').notNullable()
76
                     table.string('quality').defaultTo('Epic').notNullable()

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

1
-import { Auth, Rank, User, RPCPermission } from "../../Types/Types"
1
+import { Auth, Rank, User, RPCPermission, UserRecord } from "../../Types/Types"
2
 
2
 
3
 export class ILoginManager{
3
 export class ILoginManager{
4
     login: (username:string, pwHash:string) => Promise<Auth>
4
     login: (username:string, pwHash:string) => Promise<Auth>
5
     logout: (username: string, tokenValue :string) => Promise<void>
5
     logout: (username: string, tokenValue :string) => Promise<void>
6
-    getAuth: (tokenValue: string) => Promise<Auth>
6
+    getAuth: (tokenValue: string) => Promise<Auth | void>
7
     createUser: (user:User) => Promise<User>
7
     createUser: (user:User) => Promise<User>
8
     setPermission: (perm: RPCPermission) => Promise<void>
8
     setPermission: (perm: RPCPermission) => Promise<void>
9
     getPermissions: () => Promise<RPCPermission[]>
9
     getPermissions: () => Promise<RPCPermission[]>
10
     checkToken: (token: string, rank: Rank) => boolean
10
     checkToken: (token: string, rank: Rank) => boolean
11
+    getUserRecordByToken: (tokenValue: string) => UserRecord | void
11
 }
12
 }

+ 50
- 34
src/backend/Components/Login/LoginManager.ts View File

7
 import { CharacterManager } from "../Character/CharacterManager";
7
 import { CharacterManager } from "../Character/CharacterManager";
8
 import { LoginManagerIfc, LoginManagerFeatureIfc } from "./RPCInterface";
8
 import { LoginManagerIfc, LoginManagerFeatureIfc } from "./RPCInterface";
9
 import { FrontworkComponent } from "../../Types/FrontworkComponent";
9
 import { FrontworkComponent } from "../../Types/FrontworkComponent";
10
-import { Rank, User, Auth, _Rank, TableDefiniton, RPCPermission, FrontcraftFeatureIfc, AnyRPCExporter, Token } from "../../Types/Types";
10
+import { Rank, User, Auth, _Rank, TableDefiniton, RPCPermission, FrontcraftFeatureIfc, AnyRPCExporter, Token, UserRecord } from "../../Types/Types";
11
 import { IAdmin } from "../../Admin/Interface";
11
 import { IAdmin } from "../../Admin/Interface";
12
 import { ILoginManager } from "./Interface";
12
 import { ILoginManager } from "./Interface";
13
-import { getLogger } from "log4js";
13
+import { getLogger, Logger } from "log4js";
14
 
14
 
15
 const uuid = require('uuid/v4')
15
 const uuid = require('uuid/v4')
16
 
16
 
45
     
45
     
46
     exporters :any[] = []
46
     exporters :any[] = []
47
     rankServers : {[rank in Rank] : Serverstate}
47
     rankServers : {[rank in Rank] : Serverstate}
48
-    userLogins : {[username in string] : {
49
-        user: User
50
-        connections: {[port in number]: Socket}
51
-        auth: Auth
52
-    }} = {}
48
+    userLogins : {[username in string] : UserRecord} = {}
53
 
49
 
54
     exportRPCs = () => [
50
     exportRPCs = () => [
55
         {
51
         {
89
             name: 'users',
85
             name: 'users',
90
             tableBuilder: (table) => {
86
             tableBuilder: (table) => {
91
                 table.increments("id").primary()
87
                 table.increments("id").primary()
92
-                table.string("name").notNullable().unique()
88
+                table.string("username").notNullable().unique()
93
                 table.string("pwhash").notNullable()
89
                 table.string("pwhash").notNullable()
94
                 table.string("rank").notNullable()
90
                 table.string("rank").notNullable()
95
                 table.string("email").nullable().unique()
91
                 table.string("email").nullable().unique()
98
         },{
94
         },{
99
             name: 'rpcpermissions',
95
             name: 'rpcpermissions',
100
             tableBuilder: (table) => {
96
             tableBuilder: (table) => {
101
-                table.string("name").primary().notNullable()
97
+                table.string("rpcname").primary().notNullable()
102
                 _Rank.forEach(r => {
98
                 _Rank.forEach(r => {
103
                     if(r === 'ADMIN')
99
                     if(r === 'ADMIN')
104
                         table.boolean(r).defaultTo(true).notNullable()
100
                         table.boolean(r).defaultTo(true).notNullable()
118
         await Promise.all( 
114
         await Promise.all( 
119
             [this, ...this.exporters].flatMap(exp => exp.exportRPCFeatures().map(async (feature) => {
115
             [this, ...this.exporters].flatMap(exp => exp.exportRPCFeatures().map(async (feature) => {
120
             try{
116
             try{
121
-                await this.admin.knex.insert({ name: feature.name }).into('rpcpermissions')
117
+                await this.admin.knex.insert({ rpcname: feature.name }).into('rpcpermissions')
122
             }catch(e){
118
             }catch(e){
123
                 console.log(e);
119
                 console.log(e);
124
             }
120
             }
163
         Object.values(this.userLogins).map(userLogin => {
159
         Object.values(this.userLogins).map(userLogin => {
164
             const auth = userLogin.auth
160
             const auth = userLogin.auth
165
             if(!this.checkToken(auth.token.value, auth.user.rank)){
161
             if(!this.checkToken(auth.token.value, auth.user.rank)){
166
-                this.logout(auth.user.name, auth.token.value)
162
+                this.logout(auth.user.username, auth.token.value)
167
             }
163
             }
168
         })
164
         })
169
     }
165
     }
170
 
166
 
171
     checkConnection = async (socket: Socket) => {
167
     checkConnection = async (socket: Socket) => {
168
+        
172
         let data : any
169
         let data : any
173
         let tries = 0
170
         let tries = 0
174
         while(!data){
171
         while(!data){
175
             tries ++
172
             tries ++
176
             if(tries === 5){
173
             if(tries === 5){
177
                 getLogger('LoginManager').debug('Connection check failed for connection *'+socket.port)
174
                 getLogger('LoginManager').debug('Connection check failed for connection *'+socket.port)
178
-
179
                 socket.destroy()
175
                 socket.destroy()
180
-                return
176
+                return false
181
             }
177
             }
182
-            data = await Promise.race([socket.call('getUserData'), new Promise((res, rej) => { setTimeout(res, 250);})])
183
-        } 
184
-        this.userLogins[data.user.name].connections[socket.port] = socket
178
+            data = await Promise.race([socket.call('getUserData'), new Promise((res, rej) => { setTimeout(res, 1000);})])
179
+        }
180
+        if(!this.userLogins[data.user.username]){
181
+            await this.logout(data.user.username, data.token.value)
182
+            return false
183
+        }
184
+
185
+        this.userLogins[data.user.username].connections[socket.port] = socket
185
         await socket.call('navigate', ["/frontcraft/dashboard"])
186
         await socket.call('navigate', ["/frontcraft/dashboard"])
186
         return true
187
         return true
187
     }
188
     }
188
 
189
 
189
     setPermission = async (permission: RPCPermission) => {
190
     setPermission = async (permission: RPCPermission) => {
190
         await this.admin.knex('rpcpermissions')
191
         await this.admin.knex('rpcpermissions')
191
-        .where('rpcname', '=', permission.name)
192
+        .where('rpcname', '=', permission.rpcnamename)
192
         .update(permission)
193
         .update(permission)
193
     }
194
     }
194
 
195
 
200
         const perm : RPCPermission[] = await this.admin.knex
201
         const perm : RPCPermission[] = await this.admin.knex
201
             .select(rank)
202
             .select(rank)
202
             .from('rpcpermissions')
203
             .from('rpcpermissions')
203
-            .where('name', '=', <string>feature)
204
+            .where('rpcname', '=', <string>feature)
204
 
205
 
205
         if(perm.length === 0) return false
206
         if(perm.length === 0) return false
206
         return perm[0][rank]
207
         return perm[0][rank]
233
 
234
 
234
             user.locked = false
235
             user.locked = false
235
         }
236
         }
237
+        user.username = user.username.toLowerCase()
238
+
236
         await this.admin.knex('users')
239
         await this.admin.knex('users')
237
         .insert(user)
240
         .insert(user)
238
 
241
 
246
 
249
 
247
     logout = async (username:string, tokenValue : string) : Promise<void> => {
250
     logout = async (username:string, tokenValue : string) : Promise<void> => {
248
         try{
251
         try{
252
+            username = username.toLowerCase()
253
+            const maybeRecord = this.getUserRecordByToken(tokenValue)
254
+            if(maybeRecord && maybeRecord.auth.user.username != username){
255
+                getLogger('LoginManager').warn(`Bad logout attempt
256
+                token by: ${maybeRecord.auth.user.username}
257
+                tried to logout: ${username}`)
258
+                return
259
+            } 
249
 
260
 
250
-            await Promise.all (Object.values(this.userLogins[username].connections).map(async (sock) => {
251
-                await sock.call('navigate', '/auth/login')
252
-            }))
261
+            if(this.userLogins[username]){
262
+                await Promise.all (Object.values(this.userLogins[username].connections).map(async (sock) => {
263
+                    await sock.call('navigate', '/auth/login')
264
+                }))
265
+            }
253
 
266
 
254
             Object.values(this.rankServers)
267
             Object.values(this.rankServers)
255
                 .forEach(state => {
268
                 .forEach(state => {
263
     }
276
     }
264
 
277
 
265
     login = async(username:string, pwHash:string) : Promise<Auth> => {
278
     login = async(username:string, pwHash:string) : Promise<Auth> => {
279
+        username = username.toLowerCase()
266
         const res:User[] = await this.admin.knex
280
         const res:User[] = await this.admin.knex
267
         .select('*')
281
         .select('*')
268
         .from('users')
282
         .from('users')
269
-        .where({ name: username })
283
+        .where({ username: username })
270
 
284
 
271
         if(res.length > 0 && pwHash === res[0].pwhash){
285
         if(res.length > 0 && pwHash === res[0].pwhash){
272
             const user:User = res[0]
286
             const user:User = res[0]
284
                 port: this.rankServers[user.rank].port
298
                 port: this.rankServers[user.rank].port
285
             }
299
             }
286
 
300
 
287
-            this.userLogins[user.name] = {connections: {}, auth: userAuth, user:user}
301
+            this.userLogins[user.username] = {connections: {}, auth: userAuth, user:user}
288
             this.rankServers[user.rank].allowed.push(token.value)
302
             this.rankServers[user.rank].allowed.push(token.value)
289
-
290
             return userAuth 
303
             return userAuth 
291
         }
304
         }
292
 
305
 
294
     }
307
     }
295
 
308
 
296
     getUserRecordByToken(tokenValue: string){
309
     getUserRecordByToken(tokenValue: string){
297
-        const maybeRecord = Object.values(this.userLogins).find(login => login.auth.token.value === tokenValue)
298
-        return maybeRecord?maybeRecord:undefined
310
+        return Object.values(this.userLogins).find(login => login.auth.token.value === tokenValue)
299
     }
311
     }
300
 
312
 
301
-    getAuth = async (tokenValue:string) : Promise<Auth> => {
313
+    getAuth = async (tokenValue:string) : Promise<Auth | void> => {
302
         const maybeAuth = this.getUserRecordByToken(tokenValue)
314
         const maybeAuth = this.getUserRecordByToken(tokenValue)
303
         if(maybeAuth)
315
         if(maybeAuth)
304
             return maybeAuth.auth
316
             return maybeAuth.auth
305
-
306
-        throw new Error("Bad token")
317
+        return
307
     }
318
     }
308
 
319
 
309
     startRankServer = async (rank : Rank, port: number) : Promise<RPCServer> => {
320
     startRankServer = async (rank : Rank, port: number) : Promise<RPCServer> => {
322
             
333
             
323
                         },
334
                         },
324
                         connectionHandler: (socket) => {
335
                         connectionHandler: (socket) => {
325
-                            this.checkConnection(socket).catch((e) => {
326
-                                console.log(e);
327
-                            }) //sometimes times out if you go too fast
336
+                            this.checkConnection(socket).then(res => {
337
+                                if(!res){
338
+                                    socket.destroy();
339
+                                }
340
+                            }).catch((e) => {
341
+                                socket.destroy();
342
+                                getLogger('LoginManager').warn(e);
343
+                            })
328
                         },
344
                         },
329
                         errorHandler: (socket, e, rpcName, args) => {
345
                         errorHandler: (socket, e, rpcName, args) => {
330
                             console.log(rpcName, args);
346
                             console.log(rpcName, args);
346
 
362
 
347
     createToken = (user:User): Token => {
363
     createToken = (user:User): Token => {
348
         
364
         
349
-        if(this.userLogins[user.name]){
350
-            return this.userLogins[user.name].auth.token
365
+        if(this.userLogins[user.username]){
366
+            return this.userLogins[user.username].auth.token
351
         }
367
         }
352
 
368
 
353
         const token:Token = {
369
         const token:Token = {

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

1
-import { User, Raid, Signup } from "../../Types/Types"
1
+import { Raid, Signup, Character } from "../../Types/Types"
2
 
2
 
3
 export class IRaidManager{
3
 export class IRaidManager{
4
     getRaids: () => Promise<Raid[]>
4
     getRaids: () => Promise<Raid[]>
6
     addSignup: (signup: Signup) => Promise<any>
6
     addSignup: (signup: Signup) => Promise<any>
7
     removeSignup: (signup: Signup) => Promise<any>    
7
     removeSignup: (signup: Signup) => Promise<any>    
8
     getSignups: (raid:Raid) => Promise<Signup[]>
8
     getSignups: (raid:Raid) => Promise<Signup[]>
9
-    sign: (user:User, raid:Raid, attending:boolean) => Promise<any>
9
+    sign: (userToken: string, character:Character, raid:Raid, attending:boolean) => Promise<any>
10
 }
10
 }

+ 31
- 17
src/backend/Components/Raid/RaidManager.ts View File

1
 import { Inject, Module } from "../../Injector/ServiceDecorator";
1
 import { Inject, Module } from "../../Injector/ServiceDecorator";
2
 import { RaidManagerIfc, RaidManagerFeatureIfc } from "./RPCInterface";
2
 import { RaidManagerIfc, RaidManagerFeatureIfc } from "./RPCInterface";
3
 import { FrontworkComponent } from "../../Types/FrontworkComponent";
3
 import { FrontworkComponent } from "../../Types/FrontworkComponent";
4
-import { TableDefiniton, Signup, Raid, User } from "../../Types/Types";
4
+import { TableDefiniton, Signup, Raid, User, Character } from "../../Types/Types";
5
 import { IAdmin } from "../../Admin/Interface";
5
 import { IAdmin } from "../../Admin/Interface";
6
 import { IRaidManager } from "./Interface";
6
 import { IRaidManager } from "./Interface";
7
+import { ILoginManager } from "../Login/Interface";
7
 
8
 
8
 @Module(IRaidManager)
9
 @Module(IRaidManager)
9
 export class RaidManager
10
 export class RaidManager
13
     @Inject(IAdmin)
14
     @Inject(IAdmin)
14
     private admin: IAdmin
15
     private admin: IAdmin
15
 
16
 
17
+    @Inject(ILoginManager)
18
+    private login: ILoginManager
19
+
16
     exportRPCs = () => [{
20
     exportRPCs = () => [{
17
         name: 'getRaids' as 'getRaids',
21
         name: 'getRaids' as 'getRaids',
18
         call: this.getRaids
22
         call: this.getRaids
57
             },{
61
             },{
58
                 name: 'signups',
62
                 name: 'signups',
59
                 tableBuilder: (table) => {
63
                 tableBuilder: (table) => {
60
-                    table.primary(['raid_id', 'user_id'])
61
-                    table.integer('raid_id')
62
-                    table.foreign('raid_id').references('id').inTable('raids')
63
-                    table.integer('user_id')
64
-                    table.foreign('user_id').references('id').inTable('users')
64
+                    table.primary(['raidid', 'characterid'])
65
+                    table.integer('raidid')
66
+                    table.foreign('raidid').references('id').inTable('raids')
67
+                    table.integer('characterid')
68
+                    table.foreign('characterid').references('id').inTable('characters')
65
                 }
69
                 }
66
             }            
70
             }            
67
         ]
71
         ]
78
     removeSignup = async (signup: Signup) => await this.admin
82
     removeSignup = async (signup: Signup) => await this.admin
79
     .knex('signups')
83
     .knex('signups')
80
     .where({
84
     .where({
81
-        raid_id: signup.raid_id, 
82
-        user_id: signup.user_id
85
+        raid_id: signup.raidid, 
86
+        character_id: signup.characterid
83
     })
87
     })
84
     .delete()
88
     .delete()
85
 
89
 
87
     .select('*')
91
     .select('*')
88
     .from('raids')
92
     .from('raids')
89
     
93
     
90
-    getSignups = async (raid:Raid) : Promise<Signup[]> => await this.admin.knex
94
+    getSignups = async (raid:Raid) : Promise<Signup[]> => await this.admin
95
+    .knex('signups')
96
+    .join('characters as c', 'c.id', '=', 'characterid')
97
+    .join('specs as s', 's.id', '=', 'specid')
98
+    .join('users as u', 'u.id', '=', 'userid')
91
     .select('*')
99
     .select('*')
92
-    .from('signups')
93
-    .where('raid_id', '=', raid.id!)
100
+    .where('raidid', '=', raid.id!)
94
     
101
     
95
-    sign = async (user:User, raid:Raid) => await this.admin
96
-    .knex('signups')
97
-    .insert({
98
-        raid_id: raid.id!,
99
-        user_id: user.id!
100
-    })
102
+    sign = async (usertoken:string, character:Character, raid:Raid) => {
103
+        const maybeUserRecord = this.login.getUserRecordByToken(usertoken)
104
+        if(!maybeUserRecord || maybeUserRecord.user.id != character.userid){
105
+            throw new Error("Bad Usertoken")
106
+        }
107
+
108
+        await this.admin
109
+        .knex('signups')
110
+        .insert({
111
+            raidid: raid.id!,
112
+            characterid: character.id!
113
+        })
114
+    }
101
 }
115
 }

+ 3
- 3
src/backend/Injector/Injector.ts View File

13
   rootInterface : Type<any>
13
   rootInterface : Type<any>
14
   root : Type<any>
14
   root : Type<any>
15
   rootModules: Type<any>[] = []
15
   rootModules: Type<any>[] = []
16
-  modules : {ifc?: Type<any>, implementation: Type<any>}[] = []
16
+  modules : {implements?: Type<any>, implementation: Type<any>}[] = []
17
 
17
 
18
   moduleObjs : {[key in string] : FrontworkComponent} = {}
18
   moduleObjs : {[key in string] : FrontworkComponent} = {}
19
 
19
 
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
       let modules = this.modules.map(m => {
32
       let modules = this.modules.map(m => {
33
         const module = new m.implementation()
33
         const module = new m.implementation()
34
-        if(m.ifc)
35
-          this.moduleObjs[m.ifc.name] = module
34
+        if(m.implements)
35
+          this.moduleObjs[m.implements.name] = module
36
         this.moduleObjs[m.implementation.name] = module
36
         this.moduleObjs[m.implementation.name] = module
37
         return module
37
         return module
38
       })
38
       })

+ 3
- 3
src/backend/Injector/ServiceDecorator.ts View File

9
 export const Module = (ifc?: Type<any>) : GenericClassDecorator<Type<any>> => {
9
 export const Module = (ifc?: Type<any>) : GenericClassDecorator<Type<any>> => {
10
   return (target: Type<any>) => {
10
   return (target: Type<any>) => {
11
     Injector.modules.push({
11
     Injector.modules.push({
12
-      ifc: ifc,
12
+      extends: ifc,
13
       implementation: target
13
       implementation: target
14
     })
14
     })
15
   }
15
   }
20
  * @constructor
20
  * @constructor
21
  */
21
  */
22
 export const RootComponent = (config : {
22
 export const RootComponent = (config : {
23
-    rootInterface : Type<any>
23
+    implements : Type<any>
24
     imports : Type<FrontworkComponent>[]
24
     imports : Type<FrontworkComponent>[]
25
   }) : GenericClassDecorator<Type<any>> => {
25
   }) : GenericClassDecorator<Type<any>> => {
26
   return (target: Type<any>) => {
26
   return (target: Type<any>) => {
27
     Injector.rootModules = config.imports
27
     Injector.rootModules = config.imports
28
-    Injector.rootInterface = config.rootInterface
28
+    Injector.rootInterface = config.implements
29
     Injector.root = target
29
     Injector.root = target
30
   }
30
   }
31
 }
31
 }

+ 16
- 2
src/backend/Types/PlayerSpecs.ts View File

1
-import { Spec, _Class } from "./Types"
1
+import { Spec, _Class, Class } from "./Types"
2
 
2
 
3
 export type SpecT = {
3
 export type SpecT = {
4
     Warrior : 'Arms' | 'Fury' | 'Protection'
4
     Warrior : 'Arms' | 'Fury' | 'Protection'
74
         const specNames : string[] = specs[_class]
74
         const specNames : string[] = specs[_class]
75
         return specNames.map(specName => {
75
         return specNames.map(specName => {
76
             return {
76
             return {
77
-                name: specName,
77
+                specname: specName,
78
                 class: _class
78
                 class: _class
79
             }
79
             }
80
         })
80
         })
81
     })
81
     })
82
+}
83
+
84
+export function getClassColor(c: Class) : string{
85
+    switch(c){
86
+        case "Warrior": return "#C79C6E"
87
+        case "Warlock": return "#8787ED"
88
+        case "Shaman": return "#0070DE"
89
+        case "Rogue": return "#FFF569"
90
+        case "Priest": return "#FFFFFF"
91
+        case "Paladin": return "#F58CBA"
92
+        case "Mage": return "#40C7EB"
93
+        case "Druid": return "#FF7D0A"
94
+        case "Hunter": return "#A9D271"
95
+    }
82
 }
96
 }

+ 13
- 8
src/backend/Types/Types.ts View File

1
 import * as Knex from "knex"
1
 import * as Knex from "knex"
2
-import { RPCExporter } from "rpclibrary";
2
+import { RPCExporter, Socket } from "rpclibrary";
3
 import { RaidManagerIfc, RaidManagerFeatureIfc } from "../Components/Raid/RPCInterface";
3
 import { RaidManagerIfc, RaidManagerFeatureIfc } from "../Components/Raid/RPCInterface";
4
 import { LoginManagerIfc, LoginManagerFeatureIfc } from "../Components/Login/RPCInterface";
4
 import { LoginManagerIfc, LoginManagerFeatureIfc } from "../Components/Login/RPCInterface";
5
 import { CharacterManagerIfc, CharacterManagerFeatureIfc } from "../Components/Character/RPCInterface";
5
 import { CharacterManagerIfc, CharacterManagerFeatureIfc } from "../Components/Character/RPCInterface";
33
 export type AnyRPCExporter = RPCExporter<any,any>
33
 export type AnyRPCExporter = RPCExporter<any,any>
34
 
34
 
35
 export type RPCPermission = {
35
 export type RPCPermission = {
36
-    name: string
36
+    rpcnamename: string
37
 } & {
37
 } & {
38
     [rank in Rank] : boolean
38
     [rank in Rank] : boolean
39
 }
39
 }
40
 
40
 
41
 export type Item = {
41
 export type Item = {
42
     id?:number
42
     id?:number
43
-    name:string
43
+    itemname:string
44
     iconname:string
44
     iconname:string
45
     url:string
45
     url:string
46
     quality:string
46
     quality:string
49
 
49
 
50
 export type User = {
50
 export type User = {
51
     id?: number
51
     id?: number
52
-    name: string
52
+    username: string
53
     pwhash: string
53
     pwhash: string
54
     rank: Rank
54
     rank: Rank
55
     email?: string
55
     email?: string
65
 }
65
 }
66
 
66
 
67
 export type Signup = {
67
 export type Signup = {
68
-    raid_id: number
69
-    user_id: number
68
+    raidid: number
69
+    characterid: number
70
 }
70
 }
71
 
71
 
72
 export type Character = {
72
 export type Character = {
73
     id? : number
73
     id? : number
74
-    name : string
74
+    charactername : string
75
     specid : number
75
     specid : number
76
     userid : number
76
     userid : number
77
 }
77
 }
84
 
84
 
85
 export type Auth = {port: number, user: User, token: Token}
85
 export type Auth = {port: number, user: User, token: Token}
86
 
86
 
87
+export type UserRecord = {
88
+    user: User
89
+    connections: {[port in number]: Socket}
90
+    auth: Auth
91
+}
87
 
92
 
88
 export type Spec = {
93
 export type Spec = {
89
     id?: number,
94
     id?: number,
90
     class: Class,
95
     class: Class,
91
-    name: string
96
+    specname: string
92
 }
97
 }
93
 
98
 
94
 export type SomeOf<T> = {
99
 export type SomeOf<T> = {

+ 3
- 3
src/frontend/package-lock.json View File

17366
       }
17366
       }
17367
     },
17367
     },
17368
     "tslib": {
17368
     "tslib": {
17369
-      "version": "1.9.0",
17370
-      "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.9.0.tgz",
17371
-      "integrity": "sha512-f/qGG2tUkrISBlQZEjEqoZ3B2+npJjIf04H1wuAv9iA8i04Icp+61KRXxFdha22670NJopsZCIjhC3SnjPRKrQ=="
17369
+      "version": "1.10.0",
17370
+      "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.10.0.tgz",
17371
+      "integrity": "sha512-qOebF53frne81cf0S9B41ByenJ3/IuH8yJKngAX35CmiZySA0khhkovshKK+jGCaMnVomla7gVlIcc3EvKPbTQ=="
17372
     },
17372
     },
17373
     "tslint": {
17373
     "tslint": {
17374
       "version": "5.7.0",
17374
       "version": "5.7.0",

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

74
     "rxjs-compat": "6.3.0",
74
     "rxjs-compat": "6.3.0",
75
     "socicon": "3.0.5",
75
     "socicon": "3.0.5",
76
     "tinymce": "4.5.7",
76
     "tinymce": "4.5.7",
77
-    "tslib": "^1.9.0",
77
+    "tslib": "^1.10.0",
78
     "typeface-exo": "0.0.22",
78
     "typeface-exo": "0.0.22",
79
     "web-animations-js": "github:angular/web-animations-js#release_pr208",
79
     "web-animations-js": "github:angular/web-animations-js#release_pr208",
80
     "zone.js": "~0.9.1"
80
     "zone.js": "~0.9.1"

+ 1
- 1
src/frontend/src/app/@theme/components/header/header.component.html View File

16
     <nb-action class="user-action">
16
     <nb-action class="user-action">
17
       <nb-user [nbContextMenu]="userMenu"
17
       <nb-user [nbContextMenu]="userMenu"
18
                [onlyPicture]="false"
18
                [onlyPicture]="false"
19
-               [name]="user?.name"
19
+               [name]="user?.username"
20
                [picture]="user?.picture">
20
                [picture]="user?.picture">
21
       </nb-user>
21
       </nb-user>
22
     </nb-action>
22
     </nb-action>

+ 3
- 1
src/frontend/src/app/@theme/components/header/header.component.ts View File

39
 
39
 
40
   currentTheme = 'dark';
40
   currentTheme = 'dark';
41
 
41
 
42
-  userMenu : NbMenuItem[] = [ { title: 'Profile' }, { title: 'Log out', url: '/auth/logout' } ];
42
+  userMenu : NbMenuItem[] = [ { title: 'Log out', link: '/auth/logout' } ];
43
 
43
 
44
   constructor(private sidebarService: NbSidebarService,
44
   constructor(private sidebarService: NbSidebarService,
45
               private menuService: NbMenuService,
45
               private menuService: NbMenuService,
53
     this.currentTheme = this.themeService.currentTheme;
53
     this.currentTheme = this.themeService.currentTheme;
54
 
54
 
55
     this.user = this.loginService.getCurrentUser()
55
     this.user = this.loginService.getCurrentUser()
56
+    if(this.user)
57
+      this.userMenu.unshift({ title: 'Profile', link: '/frontcraft/user/'+this.user.username });
56
 
58
 
57
     /*
59
     /*
58
     this.userService.getUsers()
60
     this.userService.getUsers()

+ 1
- 0
src/frontend/src/app/app-routing.module.ts View File

2
 import { NgModule } from '@angular/core';
2
 import { NgModule } from '@angular/core';
3
 
3
 
4
 const routes: Routes = [
4
 const routes: Routes = [
5
+
5
   {
6
   {
6
     path: 'auth',
7
     path: 'auth',
7
     loadChildren: () => import('./frontcraft/auth/auth.module')
8
     loadChildren: () => import('./frontcraft/auth/auth.module')

+ 0
- 1
src/frontend/src/app/app.module.ts View File

20
   NbToastrModule,
20
   NbToastrModule,
21
   NbWindowModule,
21
   NbWindowModule,
22
 } from '@nebular/theme';
22
 } from '@nebular/theme';
23
-import { LoginApiService } from './frontcraft/services/login-api';
24
 
23
 
25
 @NgModule({
24
 @NgModule({
26
   declarations: [AppComponent],
25
   declarations: [AppComponent],

+ 1
- 1
src/frontend/src/app/frontcraft/auth/register/register.component.html View File

21
     <label class="label" for="input-username">Username:</label>
21
     <label class="label" for="input-username">Username:</label>
22
     <input nbInput
22
     <input nbInput
23
            fullWidth
23
            fullWidth
24
-           [(ngModel)]="user.name"
24
+           [(ngModel)]="user.username"
25
            #email="ngModel"
25
            #email="ngModel"
26
            name="name"
26
            name="name"
27
            id="input-username"
27
            id="input-username"

+ 18
- 1
src/frontend/src/app/frontcraft/auth/register/register.component.ts View File

52
   }
52
   }
53
 
53
 
54
   async onSubmit(){
54
   async onSubmit(){
55
+    const pw = this.user.pwhash
55
     this.user.pwhash = await hash(this.user.pwhash)
56
     this.user.pwhash = await hash(this.user.pwhash)
56
     const user = this.user
57
     const user = this.user
57
     this.user = {} as User
58
     this.user = {} as User
60
 
61
 
61
     try{
62
     try{
62
       const usr = await this.loginApi.getUnprivilegedSocket().Authenticator.createUser(user)
63
       const usr = await this.loginApi.getUnprivilegedSocket().Authenticator.createUser(user)
63
-      
64
     }catch(e){
64
     }catch(e){
65
       alert("Error creating user"+e)
65
       alert("Error creating user"+e)
66
+      return
67
+    }
68
+
69
+    try{
70
+      await this.loginApi.login(user.username, pw)
71
+      await this.loginApi.getFeature('createCharacter').then(async feature => {
72
+        if(!feature) return
73
+        const specid = await this.loginApi.getUnprivilegedSocket().CharacterManager.getSpecId(char['class'], char['spec'])
74
+        await feature.createCharacter(this.loginApi.getAuth().token.value, {
75
+          charactername: char.name,
76
+          specid: specid,
77
+          userid: this.loginApi.getAuth().user.id!
78
+        })
79
+      })
80
+    }catch(e){
81
+      alert("Error creating character"+e)
82
+      return
66
     }
83
     }
67
   }
84
   }
68
 
85
 

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

1
+<nb-card 
2
+status="control">
3
+    <nb-card-header [ngStyle]="{'color': color}" style="text-transform: capitalize;">
4
+        {{char.charactername}}
5
+    </nb-card-header>
6
+    <nb-card-body>
7
+        {{char.specname}} {{char.class}}<br />
8
+        Owned by <a [routerLink]="'/frontcraft/user/'+char.username"> {{char.username}} ({{char.rank}})</a>
9
+    </nb-card-body>
10
+</nb-card>

+ 34
- 0
src/frontend/src/app/frontcraft/pages/character/character.component.ts View File

1
+import { Component, OnInit } from '@angular/core';
2
+import { ActivatedRoute, Router } from '@angular/router';
3
+import { LoginApiService } from '../../services/login-api';
4
+import { Spec, User, Character } from '../../../../../../backend/Types/Types';
5
+import { getClassColor } from '../../../../../../backend/Types/PlayerSpecs';
6
+
7
+@Component({
8
+  selector: 'character',
9
+  templateUrl: './character.component.html',
10
+})
11
+export class FrontcraftCharacterComponent implements OnInit{
12
+
13
+    char : (Character & User & Spec) = {} as any
14
+    color : string
15
+
16
+    constructor(
17
+      private login: LoginApiService,
18
+      private route: ActivatedRoute,
19
+      private router: Router,
20
+    ){}
21
+
22
+    async ngOnInit(){
23
+      const param = this.route.snapshot.paramMap.get('name');
24
+      this.login.getUnprivilegedSocket()      
25
+      .CharacterManager
26
+      .getCharacterByName(param)
27
+      .then((char) => {
28
+        if(char){
29
+          this.color = getClassColor(char.class)
30
+          this.char = char
31
+        }
32
+      })
33
+    }
34
+}

+ 35
- 1
src/frontend/src/app/frontcraft/pages/dashboard/dashboard.component.html View File

1
-<strong> Dashboard </strong>
1
+<nb-card>
2
+    <nb-card-body>
3
+
4
+        <label class="search-label" for="search">Search:</label>
5
+        <input nbInput [nbFilterInput]="dataSource" id="search" class="search-input">
6
+
7
+        <table [nbTreeGrid]="dataSource" [nbSort]="dataSource" (sort)="updateSort($event)">
8
+
9
+            <tr nbTreeGridHeaderRow *nbTreeGridHeaderRowDef="allColumns"></tr>
10
+            <tr nbTreeGridRow *nbTreeGridRowDef="let row; columns: allColumns"></tr>
11
+
12
+            <ng-container [nbTreeGridColumnDef]="customColumn">
13
+                <th nbTreeGridHeaderCell [nbSortHeader]="getSortDirection(customColumn)" *nbTreeGridHeaderCellDef>
14
+                {{customColumn}}
15
+                </th>
16
+                <td nbTreeGridCell *nbTreeGridCellDef="let row">
17
+                    <nb-tree-grid-row-toggle
18
+                        *ngIf="row.children && row.children.length">
19
+                    </nb-tree-grid-row-toggle>
20
+                    
21
+                    {{row.data[customColumn]}}
22
+                </td>
23
+            </ng-container>
24
+
25
+            <ng-container *ngFor="let column of defaultColumns; let index = index"
26
+                            [nbTreeGridColumnDef]="column"
27
+                            [showOn]="getShowOn(index)">
28
+                <th nbTreeGridHeaderCell [nbSortHeader]="getSortDirection(column)" *nbTreeGridHeaderCellDef>
29
+                {{column}}
30
+                </th>
31
+                <td nbTreeGridCell *nbTreeGridCellDef="let row">{{row.data[column] || '-'}}</td>
32
+            </ng-container>
33
+        </table>
34
+    </nb-card-body>
35
+</nb-card>

+ 42
- 0
src/frontend/src/app/frontcraft/pages/dashboard/dashboard.component.scss View File

1
+button[nbTreeGridRowToggle] {
2
+    background: transparent;
3
+    border: none;
4
+    padding: 0;
5
+  }
6
+  
7
+  .search-label {
8
+    display: block;
9
+  }
10
+  .search-input {
11
+    margin-bottom: 1rem;
12
+  }
13
+  
14
+  .nb-column-name {
15
+    width: 100%;
16
+  }
17
+  
18
+  @media screen and (min-width: 400px) {
19
+    .nb-column-name,
20
+    .nb-column-size {
21
+      width: 50%;
22
+    }
23
+  }
24
+  
25
+  @media screen and (min-width: 500px) {
26
+    .nb-column-name,
27
+    .nb-column-size,
28
+    .nb-column-kind {
29
+      width: 33.333%;
30
+    }
31
+  }
32
+  
33
+  @media screen and (min-width: 600px) {
34
+    .nb-column-name {
35
+      width: 31%;
36
+    }
37
+    .nb-column-size,
38
+    .nb-column-kind,
39
+    .nb-column-items {
40
+      width: 23%;
41
+    }
42
+  }

+ 54
- 7
src/frontend/src/app/frontcraft/pages/dashboard/dashboard.component.ts View File

1
-import { Component, OnInit } from '@angular/core';
2
-import { LoginApiService } from '../../services/login-api';
1
+import { Component } from '@angular/core';
2
+import { NbSortDirection, NbSortRequest, NbTreeGridDataSourceBuilder, NbTreeGridDataSource } from '@nebular/theme';
3
+
4
+interface TreeNode<T> {
5
+  data: T;
6
+  children?: TreeNode<T>[];
7
+  expanded?: boolean;
8
+}
9
+
10
+interface Row {
11
+  name: string,
12
+  character: any,
13
+  SRC: any,
14
+}
15
+
16
+type TreeType = TreeNode<Row>
3
 
17
 
4
 @Component({
18
 @Component({
5
   selector: 'dashboard',
19
   selector: 'dashboard',
6
   templateUrl: './dashboard.component.html',
20
   templateUrl: './dashboard.component.html',
21
+  styleUrls: ['./tree-grid-shared.scss', './dashboard.component.scss'],
7
 })
22
 })
8
-export class FrontcraftDashboardComponent implements OnInit{
23
+export class FrontcraftDashboardComponent{
24
+  customColumn = 'name';
25
+  defaultColumns = [ 'character', 'SRC'/*, 'Profile'*/ ];
26
+  allColumns = [ this.customColumn, ...this.defaultColumns ];
27
+
28
+  dataSource: NbTreeGridDataSource<TreeType>;
9
 
29
 
10
-    constructor(private loginApi : LoginApiService){}
30
+  sortColumn: string;
31
+  sortDirection: NbSortDirection = NbSortDirection.NONE;
11
 
32
 
12
-    ngOnInit(){
13
-        console.log(this.loginApi)
33
+  constructor(private dataSourceBuilder: NbTreeGridDataSourceBuilder<TreeType>) {
34
+    this.dataSource = this.dataSourceBuilder.create(this.data);
35
+  }
36
+
37
+  updateSort(sortRequest: NbSortRequest): void {
38
+    this.sortColumn = sortRequest.column;
39
+    this.sortDirection = sortRequest.direction;
40
+  }
41
+
42
+  getSortDirection(column: string): NbSortDirection {
43
+    if (this.sortColumn === column) {
44
+      return this.sortDirection;
14
     }
45
     }
46
+    return NbSortDirection.NONE;
47
+  }
48
+
49
+  private data: TreeType[] = [
50
+   {
51
+     data: {name: 'a', character: 2, SRC: 0},
52
+     children: [
53
+       {data: {name: 'a', character: 'Warrior', SRC: 'Arms'}}
54
+     ]
55
+   }
56
+  ];
15
 
57
 
16
-}
58
+  getShowOn(index: number) {
59
+    const minWithForMultipleColumns = 400;
60
+    const nextColumnStep = 100;
61
+    return minWithForMultipleColumns + (nextColumnStep * index);
62
+  }
63
+}

+ 10
- 0
src/frontend/src/app/frontcraft/pages/dashboard/tree-grid-shared.scss View File

1
+::ng-deep {
2
+    body {
3
+      min-height: 20rem;
4
+    }
5
+  
6
+    .nb-tree-grid-header-cell,
7
+    .nb-tree-grid-header-cell button {
8
+      text-transform: capitalize;
9
+    }
10
+  }

+ 10
- 1
src/frontend/src/app/frontcraft/pages/pages-layout.component.ts View File

17
 export class PagesLayoutComponent implements OnInit{
17
 export class PagesLayoutComponent implements OnInit{
18
   menu:NbMenuItem[] = [{
18
   menu:NbMenuItem[] = [{
19
     icon: 'people-outline',
19
     icon: 'people-outline',
20
-    title: 'People'
20
+    title: 'People',
21
+    link: '/frontcraft/people'
21
   },{
22
   },{
22
     icon: 'clock-outline',
23
     icon: 'clock-outline',
23
     title: 'Raids'
24
     title: 'Raids'
25
+  },{
26
+    icon: 'clock-outline',
27
+    title: 'character',
28
+    link: '/frontcraft/character/a'
29
+  },{
30
+    icon: 'clock-outline',
31
+    title: 'user',
32
+    link: '/frontcraft/user/a'
24
   }]
33
   }]
25
   
34
   
26
   constructor(
35
   constructor(

+ 15
- 0
src/frontend/src/app/frontcraft/pages/pages-routing.module.ts View File

2
 import { RouterModule, Routes } from '@angular/router';
2
 import { RouterModule, Routes } from '@angular/router';
3
 import { FrontcraftDashboardComponent } from './dashboard/dashboard.component';
3
 import { FrontcraftDashboardComponent } from './dashboard/dashboard.component';
4
 import { PagesLayoutComponent } from './pages-layout.component';
4
 import { PagesLayoutComponent } from './pages-layout.component';
5
+import { FrontcraftCharacterComponent } from './character/character.component';
6
+import { FrontcraftUserComponent } from './user/user.component';
7
+import { FrontcraftPeopleComponent } from './people/people.component';
5
 
8
 
6
 export const routes: Routes = [
9
 export const routes: Routes = [
7
     {
10
     {
8
         path: '',
11
         path: '',
9
         component: PagesLayoutComponent,
12
         component: PagesLayoutComponent,
10
         children: [
13
         children: [
14
+            {
15
+                path: 'people',
16
+                component: FrontcraftPeopleComponent
17
+            },
18
+            {
19
+                path: 'user/:name',
20
+                component: FrontcraftUserComponent
21
+            },
22
+            {
23
+                path: 'character/:name',
24
+                component: FrontcraftCharacterComponent
25
+            },
11
             {
26
             {
12
                 path: 'dashboard',
27
                 path: 'dashboard',
13
                 component: FrontcraftDashboardComponent,
28
                 component: FrontcraftDashboardComponent,

+ 9
- 1
src/frontend/src/app/frontcraft/pages/pages.module.ts View File

9
   NbCheckboxModule,
9
   NbCheckboxModule,
10
   NbInputModule,
10
   NbInputModule,
11
   NbMenuModule,
11
   NbMenuModule,
12
-  NbCardModule
12
+  NbCardModule,
13
+  NbTreeGridModule
13
 } from '@nebular/theme';
14
 } from '@nebular/theme';
14
 import { MyAuthRoutingModule } from './pages-routing.module';
15
 import { MyAuthRoutingModule } from './pages-routing.module';
15
 import { FrontcraftDashboardComponent } from './dashboard/dashboard.component';
16
 import { FrontcraftDashboardComponent } from './dashboard/dashboard.component';
18
 import { DashboardModule } from '../../demo_pages/dashboard/dashboard.module';
19
 import { DashboardModule } from '../../demo_pages/dashboard/dashboard.module';
19
 import { ECommerceModule } from '../../demo_pages/e-commerce/e-commerce.module';
20
 import { ECommerceModule } from '../../demo_pages/e-commerce/e-commerce.module';
20
 import { MiscellaneousModule } from '../../demo_pages/miscellaneous/miscellaneous.module';
21
 import { MiscellaneousModule } from '../../demo_pages/miscellaneous/miscellaneous.module';
22
+import { FrontcraftCharacterComponent } from './character/character.component';
23
+import { FrontcraftUserComponent } from './user/user.component';
24
+import { FrontcraftPeopleComponent } from './people/people.component';
21
 
25
 
22
 
26
 
23
 @NgModule({
27
 @NgModule({
24
   imports: [
28
   imports: [
25
     MyAuthRoutingModule,
29
     MyAuthRoutingModule,
30
+    NbTreeGridModule,
26
     CommonModule,
31
     CommonModule,
27
     FormsModule,
32
     FormsModule,
28
     RouterModule,
33
     RouterModule,
39
     
44
     
40
   ],
45
   ],
41
   declarations: [
46
   declarations: [
47
+    FrontcraftPeopleComponent,
48
+    FrontcraftUserComponent,
49
+    FrontcraftCharacterComponent,
42
     PagesLayoutComponent,
50
     PagesLayoutComponent,
43
     FrontcraftDashboardComponent
51
     FrontcraftDashboardComponent
44
   ],
52
   ],

+ 36
- 0
src/frontend/src/app/frontcraft/pages/people/people.component.html View File

1
+<nb-card>
2
+    <nb-card-body>
3
+
4
+        <label class="search-label" for="search">Search:</label>
5
+        <input nbInput [nbFilterInput]="dataSource" id="search" class="search-input">
6
+
7
+        <table [nbTreeGrid]="dataSource" [nbSort]="dataSource" (sort)="updateSort($event)">
8
+
9
+            <tr nbTreeGridHeaderRow *nbTreeGridHeaderRowDef="allColumns"></tr>
10
+            <tr nbTreeGridRow *nbTreeGridRowDef="let row; columns: allColumns"></tr>
11
+
12
+            <ng-container [nbTreeGridColumnDef]="customColumn">
13
+                <th nbTreeGridHeaderCell [nbSortHeader]="getSortDirection(customColumn)" *nbTreeGridHeaderCellDef>
14
+                {{customColumn}}
15
+                </th>
16
+                <td nbTreeGridCell *nbTreeGridCellDef="let row">
17
+                    <nb-tree-grid-row-toggle
18
+                        *ngIf="row.children && row.children.length">
19
+                    </nb-tree-grid-row-toggle>
20
+                    <span style="text-transform: capitalize;">
21
+                        {{row.data[customColumn]}}
22
+                    </span>
23
+                </td>
24
+            </ng-container>
25
+
26
+            <ng-container *ngFor="let column of defaultColumns; let index = index"
27
+                            [nbTreeGridColumnDef]="column"
28
+                            [showOn]="getShowOn(index)">
29
+                <th nbTreeGridHeaderCell [nbSortHeader]="getSortDirection(column)" *nbTreeGridHeaderCellDef>
30
+                {{column}}
31
+                </th>
32
+                <td nbTreeGridCell *nbTreeGridCellDef="let row">{{row.data[column] || '-'}}</td>
33
+            </ng-container>
34
+        </table>
35
+    </nb-card-body>
36
+</nb-card>

+ 42
- 0
src/frontend/src/app/frontcraft/pages/people/people.component.scss View File

1
+button[nbTreeGridRowToggle] {
2
+    background: transparent;
3
+    border: none;
4
+    padding: 0;
5
+  }
6
+  
7
+  .search-label {
8
+    display: block;
9
+  }
10
+  .search-input {
11
+    margin-bottom: 1rem;
12
+  }
13
+  
14
+  .nb-column-name {
15
+    width: 100%;
16
+  }
17
+  
18
+  @media screen and (min-width: 400px) {
19
+    .nb-column-name,
20
+    .nb-column-size {
21
+      width: 50%;
22
+    }
23
+  }
24
+  
25
+  @media screen and (min-width: 500px) {
26
+    .nb-column-name,
27
+    .nb-column-size,
28
+    .nb-column-kind {
29
+      width: 33.333%;
30
+    }
31
+  }
32
+  
33
+  @media screen and (min-width: 600px) {
34
+    .nb-column-name {
35
+      width: 31%;
36
+    }
37
+    .nb-column-size,
38
+    .nb-column-kind,
39
+    .nb-column-items {
40
+      width: 23%;
41
+    }
42
+  }

+ 64
- 0
src/frontend/src/app/frontcraft/pages/people/people.component.ts View File

1
+import { Component } from '@angular/core';
2
+import { NbSortDirection, NbSortRequest, NbTreeGridDataSourceBuilder, NbTreeGridDataSource } from '@nebular/theme';
3
+
4
+interface TreeNode<T> {
5
+  data: T;
6
+  children?: TreeNode<T>[];
7
+  expanded?: boolean;
8
+}
9
+
10
+interface Row {
11
+  name: string,
12
+  character: any,
13
+  SRC: any,
14
+  kind: 'Character' | 'Account'
15
+}
16
+
17
+type TreeType = TreeNode<Row>
18
+
19
+@Component({
20
+  selector: 'people-component',
21
+  templateUrl: './people.component.html',
22
+  styleUrls: ['./tree-grid-shared.scss', './people.component.scss'],
23
+})
24
+export class FrontcraftPeopleComponent{
25
+  customColumn = 'name';
26
+  defaultColumns = [ 'character', 'SRC'/*, 'Profile'*/ ];
27
+  allColumns = [ this.customColumn, ...this.defaultColumns ];
28
+
29
+  dataSource: NbTreeGridDataSource<TreeType>;
30
+
31
+  sortColumn: string;
32
+  sortDirection: NbSortDirection = NbSortDirection.NONE;
33
+
34
+  constructor(private dataSourceBuilder: NbTreeGridDataSourceBuilder<TreeType>) {
35
+    this.dataSource = this.dataSourceBuilder.create(this.data);
36
+  }
37
+
38
+  updateSort(sortRequest: NbSortRequest): void {
39
+    this.sortColumn = sortRequest.column;
40
+    this.sortDirection = sortRequest.direction;
41
+  }
42
+
43
+  getSortDirection(column: string): NbSortDirection {
44
+    if (this.sortColumn === column) {
45
+      return this.sortDirection;
46
+    }
47
+    return NbSortDirection.NONE;
48
+  }
49
+
50
+  private data: TreeType[] = [
51
+   {
52
+     data: {name: 'a', character: 2, SRC: 0, kind: 'Account'},
53
+     children: [
54
+       {data: {name: 'a', character: 'Warrior', SRC: 'Arms', kind: 'Character'}}
55
+     ]
56
+   }
57
+  ];
58
+
59
+  getShowOn(index: number) {
60
+    const minWithForMultipleColumns = 400;
61
+    const nextColumnStep = 100;
62
+    return minWithForMultipleColumns + (nextColumnStep * index);
63
+  }
64
+}

+ 10
- 0
src/frontend/src/app/frontcraft/pages/people/tree-grid-shared.scss View File

1
+::ng-deep {
2
+    body {
3
+      min-height: 20rem;
4
+    }
5
+  
6
+    .nb-tree-grid-header-cell,
7
+    .nb-tree-grid-header-cell button {
8
+      text-transform: capitalize;
9
+    }
10
+  }

+ 24
- 0
src/frontend/src/app/frontcraft/pages/user/user.component.html View File

1
+
2
+
3
+<nb-card
4
+accent="info">
5
+    <nb-card-header>
6
+        <h2 style="text-transform: capitalize;">{{user.username}}</h2>
7
+    </nb-card-header>
8
+    <nb-card-body>
9
+      <nb-card
10
+      accent="control"
11
+      *ngFor="let char of characters">
12
+          <nb-card-header>
13
+              <h4>
14
+                  <a [ngStyle]="{'color': char.color}" style="text-transform: capitalize;" [routerLink]="'/frontcraft/character/'+char.charactername">
15
+                      {{char.charactername}}
16
+                  </a>
17
+              </h4>
18
+          </nb-card-header>
19
+          <nb-card-body>
20
+              {{char.specname}} {{char.class}}
21
+          </nb-card-body>
22
+      </nb-card>
23
+    </nb-card-body>
24
+</nb-card>

+ 38
- 0
src/frontend/src/app/frontcraft/pages/user/user.component.ts View File

1
+import { Component, OnInit } from '@angular/core';
2
+import { LoginApiService } from '../../services/login-api';
3
+import { Router } from '@angular/router';
4
+import { User, Spec, Character } from '../../../../../../backend/Types/Types';
5
+import { getClassColor } from '../../../../../../backend/Types/PlayerSpecs';
6
+
7
+@Component({
8
+  selector: 'user-component',
9
+  templateUrl: './user.component.html',
10
+})
11
+export class FrontcraftUserComponent implements OnInit{
12
+
13
+  user:User = {} as any
14
+  characters : (Character & Spec)[] = []
15
+
16
+  constructor(
17
+    private router : Router,  
18
+    private loginApi : LoginApiService
19
+  ){}
20
+
21
+  ngOnInit(){
22
+    const auth = this.loginApi.getAuth()
23
+    if(!auth){
24
+      this.router.navigateByUrl('/auth/login')
25
+      return
26
+    }
27
+    this.user = auth.user
28
+    this.loginApi.getUnprivilegedSocket()
29
+    .CharacterManager
30
+    .getCharactersOfUser(this.user.username)
31
+    .then((characters) => {
32
+      characters.forEach(c => {
33
+        c['color'] = getClassColor(c.class)
34
+      })
35
+      this.characters = characters
36
+    })  
37
+  }
38
+}

+ 12
- 8
src/frontend/src/app/frontcraft/services/login-api.ts View File

31
            
31
            
32
             const authSock = await sock.connect<RPCSocket & SomeOf<FrontcraftFeatureIfc>>(auth.token.value)
32
             const authSock = await sock.connect<RPCSocket & SomeOf<FrontcraftFeatureIfc>>(auth.token.value)
33
 
33
 
34
-            sock.hook('kick', () => this.logout())
34
+            sock.hook('kick', () => {
35
+                console.log("I got kicked");
36
+            })
35
             sock.hook('getUserData', () => auth)
37
             sock.hook('getUserData', () => auth)
36
             sock.hook('navigate', (where:string) => {
38
             sock.hook('navigate', (where:string) => {
37
-                this.ngZone.run(() => {
38
-                    this.injector.get(Router).navigateByUrl(where);
39
+                this.ngZone.run( () => {
40
+                    this.injector.get(Router).navigateByUrl('/')
39
                 })
41
                 })
40
             })
42
             })
41
             sock.on('error', (e) => {
43
             sock.on('error', (e) => {
42
-                console.log('Socket error',  e)
43
-                this.logout()
44
+                sock.destroy();
45
+                
44
             })
46
             })
45
-
47
+            
46
             this.auth = auth
48
             this.auth = auth
47
             this.privSocket = authSock
49
             this.privSocket = authSock
48
             this.cookieSvc.set('token', JSON.stringify(auth))
50
             this.cookieSvc.set('token', JSON.stringify(auth))
62
         }
64
         }
63
     }
65
     }
64
 
66
 
65
-    getCurrentUser = () : User | undefined => this.auth?this.auth.user:undefined
67
+    getCurrentUser = () : User | undefined => {
68
+        return this.auth?this.auth.user:undefined
69
+    }
66
 
70
 
67
     login = async (username: string, password: string) : Promise<RPCSocket & SomeOf<FrontcraftFeatureIfc>> => {
71
     login = async (username: string, password: string) : Promise<RPCSocket & SomeOf<FrontcraftFeatureIfc>> => {
68
         const pwHash = await hash(password)
72
         const pwHash = await hash(password)
78
 
82
 
79
     logout = async () => {
83
     logout = async () => {
80
         this.cookieSvc.set('token', undefined)
84
         this.cookieSvc.set('token', undefined)
81
-        if(this.auth) await this.socket.Authenticator.logout(this.auth.user.name, this.auth.token.value)
85
+        if(this.auth) await this.socket.Authenticator.logout(this.auth.user.username, this.auth.token.value)
82
         if(this.privSocket) this.privSocket.destroy()
86
         if(this.privSocket) this.privSocket.destroy()
83
         this.privSocket = null
87
         this.privSocket = null
84
         this.auth  = null
88
         this.auth  = null

Loading…
Cancel
Save