safety commit before system upgrade

This commit is contained in:
peter
2020-01-30 15:22:05 +01:00
parent 78ad241526
commit f7f770a40c
36 changed files with 651 additions and 125 deletions
@@ -1,6 +1,6 @@
import { RPCInterface } from "rpclibrary"; import { RPCInterface } from "rpclibrary";
import { Inject, Module } from "../../Injector/ServiceDecorator"; import { Inject, Module } from "../../Injector/ServiceDecorator";
import { TableDefiniton, Character } from "../../Types/Types"; import { TableDefiniton, Character, Spec, User } from "../../Types/Types";
import { CharacterManagerIfc } from "./RPCInterface"; import { CharacterManagerIfc } from "./RPCInterface";
import { FrontworkComponent } from "../../Types/FrontworkComponent"; import { FrontworkComponent } from "../../Types/FrontworkComponent";
import { getSpecTableData, SpecT } from "../../Types/PlayerSpecs"; import { getSpecTableData, SpecT } from "../../Types/PlayerSpecs";
@@ -18,12 +18,21 @@ implements FrontworkComponent<CharacterManagerIfc, RPCInterface>, ICharacterMana
private admin: IAdmin private admin: IAdmin
@Inject(ILoginManager) @Inject(ILoginManager)
private loginManager : any private loginManager : ILoginManager
exportRPCs = () => [ exportRPCs = () => [
{ {
name: 'getSpecId' as 'getSpecId', name: 'getSpecId' as 'getSpecId',
call: this.getSpecId call: this.getSpecId
},{
name: 'getCharacterByName' as 'getCharacterByName',
call: this.getCharacterByName
},{
name: 'getCharacters' as 'getCharacters',
call: this.getCharacters
},{
name: 'getCharactersOfUser' as 'getCharactersOfUser',
call: this.getCharactersOfUser
} }
] ]
@@ -44,7 +53,7 @@ implements FrontworkComponent<CharacterManagerIfc, RPCInterface>, ICharacterMana
name: 'characters', name: 'characters',
tableBuilder: (table) => { tableBuilder: (table) => {
table.increments("id").primary() table.increments("id").primary()
table.string("name").notNullable().unique() table.string("charactername").notNullable().unique()
table.integer("specid").notNullable() table.integer("specid").notNullable()
table.foreign("specid").references("specs.id") table.foreign("specid").references("specs.id")
table.integer("userid").notNullable() table.integer("userid").notNullable()
@@ -55,8 +64,8 @@ implements FrontworkComponent<CharacterManagerIfc, RPCInterface>, ICharacterMana
tableBuilder: (table) => { tableBuilder: (table) => {
table.increments("id") table.increments("id")
table.string('class') table.string('class')
table.string('name') table.string('specname')
table.unique(['class', 'name']) table.unique(['class', 'specname'])
} }
} }
] ]
@@ -64,17 +73,14 @@ implements FrontworkComponent<CharacterManagerIfc, RPCInterface>, ICharacterMana
private initialized = false private initialized = false
initialize = async () => { initialize = async () => {
if(!this.initialized) if(this.initialized) return
this.initialized = true this.initialized = true
//initialize spec table
getLogger('CharacterManager').debug('inserting specs')
await this.admin.knex('specs').insert(getSpecTableData()).catch(e => { console.log("skipping spec insertion") }) await this.admin.knex('specs').insert(getSpecTableData()).catch(e => { console.log("skipping spec insertion") })
} }
createCharacter = async (userToken: string, character : Character) : Promise<Character> => { createCharacter = async (userToken: string, character : Character) : Promise<Character> => {
try{ try{
character.charactername = character.charactername.toLowerCase()
const user = this.loginManager.getUserRecordByToken(userToken) const user = this.loginManager.getUserRecordByToken(userToken)
await this.admin.knex('characters').insert(character) await this.admin.knex('characters').insert(character)
const char : Character = await this.admin.knex.select('*').from('characters').where(character).first() const char : Character = await this.admin.knex.select('*').from('characters').where(character).first()
@@ -90,12 +96,33 @@ implements FrontworkComponent<CharacterManagerIfc, RPCInterface>, ICharacterMana
return this.admin.knex.select('*').from('characters') return this.admin.knex.select('*').from('characters')
} }
getCharacterByName = async(charactername: string) : Promise<(Character & User & Spec) | void> => {
charactername = charactername.toLowerCase()
return await this.admin.knex('characters as c')
.join('specs as s', 's.id', '=', 'c.specid')
.join('users as u', 'u.id', '=', 'c.userid')
.select('charactername', 'class', 'specname', 'username', 'rank', 'locked', )
.where('charactername', '=', charactername)
.first()
}
getCharactersOfUser = async(username: string) : Promise<(Character & Spec)[]> => {
username = username.toLowerCase()
return await this.admin.knex('characters as c')
.join('users as u', 'u.id', '=', 'c.userid')
.join('specs as s', 's.id', '=', 'c.specid')
.select('class', 'charactername', 'class', 'specname')
.where('u.username', '=', username)
}
getSpecId = async <c extends keyof SpecT>(clazz: c, name: SpecT[c]) => await this.admin.knex getSpecId = async <c extends keyof SpecT>(clazz: c, name: SpecT[c]) => await this.admin.knex
.from('specs') .from('specs')
.select('id') .select('id')
.where({ .where(<Spec>{
class: clazz, class: clazz,
name: name specname: name
}).first().then(spec => spec.id) })
.first()
.then(spec => spec.id)
} }
@@ -1,4 +1,4 @@
import { Character } from "../../Types/Types" import { Character, Spec, User } from "../../Types/Types"
import { SpecT } from "../../Types/PlayerSpecs" import { SpecT } from "../../Types/PlayerSpecs"
@@ -6,4 +6,6 @@ export class ICharacterManager{
createCharacter: (usertoken: string, char : Character) => Promise<Character> createCharacter: (usertoken: string, char : Character) => Promise<Character>
getSpecId: <c extends keyof SpecT>(clazz: c, name: SpecT[c]) => Promise<number> getSpecId: <c extends keyof SpecT>(clazz: c, name: SpecT[c]) => Promise<number>
getCharacters: () => Promise<Character[]> getCharacters: () => Promise<Character[]>
getCharacterByName: (charactername: string) => Promise<(Character & User & Spec) | void>
getCharactersOfUser: (username: string) => Promise<(Character & Spec)[]>
} }
@@ -5,6 +5,8 @@ export type CharacterManagerIfc = {
CharacterManager: { CharacterManager: {
getSpecId : ICharacterManager['getSpecId'] getSpecId : ICharacterManager['getSpecId']
getCharacters : ICharacterManager['getCharacters'] getCharacters : ICharacterManager['getCharacters']
getCharacterByName : ICharacterManager['getCharacterByName']
getCharactersOfUser: ICharacterManager['getCharactersOfUser']
} }
} }
+8 -9
View File
@@ -44,7 +44,7 @@ implements FrontworkComponent<ItemManagerIfc, ItemManagerFeatureIfc>, TableDefin
try{ try{
return <Item>{ return <Item>{
name: r.wowhead.item[0].name[0], itemname: r.wowhead.item[0].name[0],
iconname: r.wowhead.item[0].icon[0]._, iconname: r.wowhead.item[0].icon[0]._,
url: r.wowhead.item[0].link[0], url: r.wowhead.item[0].link[0],
quality: r.wowhead.item[0].quality[0]._, quality: r.wowhead.item[0].quality[0]._,
@@ -58,20 +58,19 @@ implements FrontworkComponent<ItemManagerIfc, ItemManagerFeatureIfc>, TableDefin
getTableDefinitions(): TableDefiniton[] { getTableDefinitions(): TableDefiniton[] {
return [ return [
{ {
name: 'reservations', name: 'tokens',
tableBuilder: (table) => { tableBuilder: (table) => {
table.integer("user_id").primary() table.integer("characterid").primary()
table.foreign("user_id").references("id").inTable('users') table.foreign("characterid").references("id").inTable('characters')
table.integer("item_id").primary() table.integer("itemid").primary()
table.foreign("item_id").references("id").inTable('items') table.foreign("itemid").references("id").inTable('items')
table.integer("raid_id").primary() table.integer("level")
table.foreign("raid_id").references("id").inTable('raids')
} }
},{ },{
name: 'items', name: 'items',
tableBuilder: (table) => { tableBuilder: (table) => {
table.increments("id").primary() table.increments("id").primary()
table.string('name').unique().notNullable() table.string('itemname').unique().notNullable()
table.string('iconname').notNullable() table.string('iconname').notNullable()
table.string('url').notNullable() table.string('url').notNullable()
table.string('quality').defaultTo('Epic').notNullable() table.string('quality').defaultTo('Epic').notNullable()
+3 -2
View File
@@ -1,11 +1,12 @@
import { Auth, Rank, User, RPCPermission } from "../../Types/Types" import { Auth, Rank, User, RPCPermission, UserRecord } from "../../Types/Types"
export class ILoginManager{ export class ILoginManager{
login: (username:string, pwHash:string) => Promise<Auth> login: (username:string, pwHash:string) => Promise<Auth>
logout: (username: string, tokenValue :string) => Promise<void> logout: (username: string, tokenValue :string) => Promise<void>
getAuth: (tokenValue: string) => Promise<Auth> getAuth: (tokenValue: string) => Promise<Auth | void>
createUser: (user:User) => Promise<User> createUser: (user:User) => Promise<User>
setPermission: (perm: RPCPermission) => Promise<void> setPermission: (perm: RPCPermission) => Promise<void>
getPermissions: () => Promise<RPCPermission[]> getPermissions: () => Promise<RPCPermission[]>
checkToken: (token: string, rank: Rank) => boolean checkToken: (token: string, rank: Rank) => boolean
getUserRecordByToken: (tokenValue: string) => UserRecord | void
} }
+46 -30
View File
@@ -7,10 +7,10 @@ import { RaidManager } from "../Raid/RaidManager";
import { CharacterManager } from "../Character/CharacterManager"; import { CharacterManager } from "../Character/CharacterManager";
import { LoginManagerIfc, LoginManagerFeatureIfc } from "./RPCInterface"; import { LoginManagerIfc, LoginManagerFeatureIfc } from "./RPCInterface";
import { FrontworkComponent } from "../../Types/FrontworkComponent"; import { FrontworkComponent } from "../../Types/FrontworkComponent";
import { Rank, User, Auth, _Rank, TableDefiniton, RPCPermission, FrontcraftFeatureIfc, AnyRPCExporter, Token } from "../../Types/Types"; import { Rank, User, Auth, _Rank, TableDefiniton, RPCPermission, FrontcraftFeatureIfc, AnyRPCExporter, Token, UserRecord } from "../../Types/Types";
import { IAdmin } from "../../Admin/Interface"; import { IAdmin } from "../../Admin/Interface";
import { ILoginManager } from "./Interface"; import { ILoginManager } from "./Interface";
import { getLogger } from "log4js"; import { getLogger, Logger } from "log4js";
const uuid = require('uuid/v4') const uuid = require('uuid/v4')
@@ -45,11 +45,7 @@ implements FrontworkComponent<LoginManagerIfc, LoginManagerFeatureIfc>, ILoginMa
exporters :any[] = [] exporters :any[] = []
rankServers : {[rank in Rank] : Serverstate} rankServers : {[rank in Rank] : Serverstate}
userLogins : {[username in string] : { userLogins : {[username in string] : UserRecord} = {}
user: User
connections: {[port in number]: Socket}
auth: Auth
}} = {}
exportRPCs = () => [ exportRPCs = () => [
{ {
@@ -89,7 +85,7 @@ implements FrontworkComponent<LoginManagerIfc, LoginManagerFeatureIfc>, ILoginMa
name: 'users', name: 'users',
tableBuilder: (table) => { tableBuilder: (table) => {
table.increments("id").primary() table.increments("id").primary()
table.string("name").notNullable().unique() table.string("username").notNullable().unique()
table.string("pwhash").notNullable() table.string("pwhash").notNullable()
table.string("rank").notNullable() table.string("rank").notNullable()
table.string("email").nullable().unique() table.string("email").nullable().unique()
@@ -98,7 +94,7 @@ implements FrontworkComponent<LoginManagerIfc, LoginManagerFeatureIfc>, ILoginMa
},{ },{
name: 'rpcpermissions', name: 'rpcpermissions',
tableBuilder: (table) => { tableBuilder: (table) => {
table.string("name").primary().notNullable() table.string("rpcname").primary().notNullable()
_Rank.forEach(r => { _Rank.forEach(r => {
if(r === 'ADMIN') if(r === 'ADMIN')
table.boolean(r).defaultTo(true).notNullable() table.boolean(r).defaultTo(true).notNullable()
@@ -118,7 +114,7 @@ implements FrontworkComponent<LoginManagerIfc, LoginManagerFeatureIfc>, ILoginMa
await Promise.all( await Promise.all(
[this, ...this.exporters].flatMap(exp => exp.exportRPCFeatures().map(async (feature) => { [this, ...this.exporters].flatMap(exp => exp.exportRPCFeatures().map(async (feature) => {
try{ try{
await this.admin.knex.insert({ name: feature.name }).into('rpcpermissions') await this.admin.knex.insert({ rpcname: feature.name }).into('rpcpermissions')
}catch(e){ }catch(e){
console.log(e); console.log(e);
} }
@@ -163,32 +159,37 @@ implements FrontworkComponent<LoginManagerIfc, LoginManagerFeatureIfc>, ILoginMa
Object.values(this.userLogins).map(userLogin => { Object.values(this.userLogins).map(userLogin => {
const auth = userLogin.auth const auth = userLogin.auth
if(!this.checkToken(auth.token.value, auth.user.rank)){ if(!this.checkToken(auth.token.value, auth.user.rank)){
this.logout(auth.user.name, auth.token.value) this.logout(auth.user.username, auth.token.value)
} }
}) })
} }
checkConnection = async (socket: Socket) => { checkConnection = async (socket: Socket) => {
let data : any let data : any
let tries = 0 let tries = 0
while(!data){ while(!data){
tries ++ tries ++
if(tries === 5){ if(tries === 5){
getLogger('LoginManager').debug('Connection check failed for connection *'+socket.port) getLogger('LoginManager').debug('Connection check failed for connection *'+socket.port)
socket.destroy() socket.destroy()
return return false
} }
data = await Promise.race([socket.call('getUserData'), new Promise((res, rej) => { setTimeout(res, 250);})]) data = await Promise.race([socket.call('getUserData'), new Promise((res, rej) => { setTimeout(res, 1000);})])
} }
this.userLogins[data.user.name].connections[socket.port] = socket if(!this.userLogins[data.user.username]){
await this.logout(data.user.username, data.token.value)
return false
}
this.userLogins[data.user.username].connections[socket.port] = socket
await socket.call('navigate', ["/frontcraft/dashboard"]) await socket.call('navigate', ["/frontcraft/dashboard"])
return true return true
} }
setPermission = async (permission: RPCPermission) => { setPermission = async (permission: RPCPermission) => {
await this.admin.knex('rpcpermissions') await this.admin.knex('rpcpermissions')
.where('rpcname', '=', permission.name) .where('rpcname', '=', permission.rpcnamename)
.update(permission) .update(permission)
} }
@@ -200,7 +201,7 @@ implements FrontworkComponent<LoginManagerIfc, LoginManagerFeatureIfc>, ILoginMa
const perm : RPCPermission[] = await this.admin.knex const perm : RPCPermission[] = await this.admin.knex
.select(rank) .select(rank)
.from('rpcpermissions') .from('rpcpermissions')
.where('name', '=', <string>feature) .where('rpcname', '=', <string>feature)
if(perm.length === 0) return false if(perm.length === 0) return false
return perm[0][rank] return perm[0][rank]
@@ -233,6 +234,8 @@ implements FrontworkComponent<LoginManagerIfc, LoginManagerFeatureIfc>, ILoginMa
user.locked = false user.locked = false
} }
user.username = user.username.toLowerCase()
await this.admin.knex('users') await this.admin.knex('users')
.insert(user) .insert(user)
@@ -246,10 +249,20 @@ implements FrontworkComponent<LoginManagerIfc, LoginManagerFeatureIfc>, ILoginMa
logout = async (username:string, tokenValue : string) : Promise<void> => { logout = async (username:string, tokenValue : string) : Promise<void> => {
try{ try{
username = username.toLowerCase()
const maybeRecord = this.getUserRecordByToken(tokenValue)
if(maybeRecord && maybeRecord.auth.user.username != username){
getLogger('LoginManager').warn(`Bad logout attempt
token by: ${maybeRecord.auth.user.username}
tried to logout: ${username}`)
return
}
if(this.userLogins[username]){
await Promise.all (Object.values(this.userLogins[username].connections).map(async (sock) => { await Promise.all (Object.values(this.userLogins[username].connections).map(async (sock) => {
await sock.call('navigate', '/auth/login') await sock.call('navigate', '/auth/login')
})) }))
}
Object.values(this.rankServers) Object.values(this.rankServers)
.forEach(state => { .forEach(state => {
@@ -263,10 +276,11 @@ implements FrontworkComponent<LoginManagerIfc, LoginManagerFeatureIfc>, ILoginMa
} }
login = async(username:string, pwHash:string) : Promise<Auth> => { login = async(username:string, pwHash:string) : Promise<Auth> => {
username = username.toLowerCase()
const res:User[] = await this.admin.knex const res:User[] = await this.admin.knex
.select('*') .select('*')
.from('users') .from('users')
.where({ name: username }) .where({ username: username })
if(res.length > 0 && pwHash === res[0].pwhash){ if(res.length > 0 && pwHash === res[0].pwhash){
const user:User = res[0] const user:User = res[0]
@@ -284,9 +298,8 @@ implements FrontworkComponent<LoginManagerIfc, LoginManagerFeatureIfc>, ILoginMa
port: this.rankServers[user.rank].port port: this.rankServers[user.rank].port
} }
this.userLogins[user.name] = {connections: {}, auth: userAuth, user:user} this.userLogins[user.username] = {connections: {}, auth: userAuth, user:user}
this.rankServers[user.rank].allowed.push(token.value) this.rankServers[user.rank].allowed.push(token.value)
return userAuth return userAuth
} }
@@ -294,16 +307,14 @@ implements FrontworkComponent<LoginManagerIfc, LoginManagerFeatureIfc>, ILoginMa
} }
getUserRecordByToken(tokenValue: string){ getUserRecordByToken(tokenValue: string){
const maybeRecord = Object.values(this.userLogins).find(login => login.auth.token.value === tokenValue) return Object.values(this.userLogins).find(login => login.auth.token.value === tokenValue)
return maybeRecord?maybeRecord:undefined
} }
getAuth = async (tokenValue:string) : Promise<Auth> => { getAuth = async (tokenValue:string) : Promise<Auth | void> => {
const maybeAuth = this.getUserRecordByToken(tokenValue) const maybeAuth = this.getUserRecordByToken(tokenValue)
if(maybeAuth) if(maybeAuth)
return maybeAuth.auth return maybeAuth.auth
return
throw new Error("Bad token")
} }
startRankServer = async (rank : Rank, port: number) : Promise<RPCServer> => { startRankServer = async (rank : Rank, port: number) : Promise<RPCServer> => {
@@ -322,9 +333,14 @@ implements FrontworkComponent<LoginManagerIfc, LoginManagerFeatureIfc>, ILoginMa
}, },
connectionHandler: (socket) => { connectionHandler: (socket) => {
this.checkConnection(socket).catch((e) => { this.checkConnection(socket).then(res => {
console.log(e); if(!res){
}) //sometimes times out if you go too fast socket.destroy();
}
}).catch((e) => {
socket.destroy();
getLogger('LoginManager').warn(e);
})
}, },
errorHandler: (socket, e, rpcName, args) => { errorHandler: (socket, e, rpcName, args) => {
console.log(rpcName, args); console.log(rpcName, args);
@@ -346,8 +362,8 @@ implements FrontworkComponent<LoginManagerIfc, LoginManagerFeatureIfc>, ILoginMa
createToken = (user:User): Token => { createToken = (user:User): Token => {
if(this.userLogins[user.name]){ if(this.userLogins[user.username]){
return this.userLogins[user.name].auth.token return this.userLogins[user.username].auth.token
} }
const token:Token = { const token:Token = {
+2 -2
View File
@@ -1,4 +1,4 @@
import { User, Raid, Signup } from "../../Types/Types" import { Raid, Signup, Character } from "../../Types/Types"
export class IRaidManager{ export class IRaidManager{
getRaids: () => Promise<Raid[]> getRaids: () => Promise<Raid[]>
@@ -6,5 +6,5 @@ export class IRaidManager{
addSignup: (signup: Signup) => Promise<any> addSignup: (signup: Signup) => Promise<any>
removeSignup: (signup: Signup) => Promise<any> removeSignup: (signup: Signup) => Promise<any>
getSignups: (raid:Raid) => Promise<Signup[]> getSignups: (raid:Raid) => Promise<Signup[]>
sign: (user:User, raid:Raid, attending:boolean) => Promise<any> sign: (userToken: string, character:Character, raid:Raid, attending:boolean) => Promise<any>
} }
+28 -14
View File
@@ -1,9 +1,10 @@
import { Inject, Module } from "../../Injector/ServiceDecorator"; import { Inject, Module } from "../../Injector/ServiceDecorator";
import { RaidManagerIfc, RaidManagerFeatureIfc } from "./RPCInterface"; import { RaidManagerIfc, RaidManagerFeatureIfc } from "./RPCInterface";
import { FrontworkComponent } from "../../Types/FrontworkComponent"; import { FrontworkComponent } from "../../Types/FrontworkComponent";
import { TableDefiniton, Signup, Raid, User } from "../../Types/Types"; import { TableDefiniton, Signup, Raid, User, Character } from "../../Types/Types";
import { IAdmin } from "../../Admin/Interface"; import { IAdmin } from "../../Admin/Interface";
import { IRaidManager } from "./Interface"; import { IRaidManager } from "./Interface";
import { ILoginManager } from "../Login/Interface";
@Module(IRaidManager) @Module(IRaidManager)
export class RaidManager export class RaidManager
@@ -13,6 +14,9 @@ implements FrontworkComponent<RaidManagerIfc, RaidManagerFeatureIfc>, IRaidManag
@Inject(IAdmin) @Inject(IAdmin)
private admin: IAdmin private admin: IAdmin
@Inject(ILoginManager)
private login: ILoginManager
exportRPCs = () => [{ exportRPCs = () => [{
name: 'getRaids' as 'getRaids', name: 'getRaids' as 'getRaids',
call: this.getRaids call: this.getRaids
@@ -57,11 +61,11 @@ implements FrontworkComponent<RaidManagerIfc, RaidManagerFeatureIfc>, IRaidManag
},{ },{
name: 'signups', name: 'signups',
tableBuilder: (table) => { tableBuilder: (table) => {
table.primary(['raid_id', 'user_id']) table.primary(['raidid', 'characterid'])
table.integer('raid_id') table.integer('raidid')
table.foreign('raid_id').references('id').inTable('raids') table.foreign('raidid').references('id').inTable('raids')
table.integer('user_id') table.integer('characterid')
table.foreign('user_id').references('id').inTable('users') table.foreign('characterid').references('id').inTable('characters')
} }
} }
] ]
@@ -78,8 +82,8 @@ implements FrontworkComponent<RaidManagerIfc, RaidManagerFeatureIfc>, IRaidManag
removeSignup = async (signup: Signup) => await this.admin removeSignup = async (signup: Signup) => await this.admin
.knex('signups') .knex('signups')
.where({ .where({
raid_id: signup.raid_id, raid_id: signup.raidid,
user_id: signup.user_id character_id: signup.characterid
}) })
.delete() .delete()
@@ -87,15 +91,25 @@ implements FrontworkComponent<RaidManagerIfc, RaidManagerFeatureIfc>, IRaidManag
.select('*') .select('*')
.from('raids') .from('raids')
getSignups = async (raid:Raid) : Promise<Signup[]> => await this.admin.knex getSignups = async (raid:Raid) : Promise<Signup[]> => await this.admin
.knex('signups')
.join('characters as c', 'c.id', '=', 'characterid')
.join('specs as s', 's.id', '=', 'specid')
.join('users as u', 'u.id', '=', 'userid')
.select('*') .select('*')
.from('signups') .where('raidid', '=', raid.id!)
.where('raid_id', '=', raid.id!)
sign = async (user:User, raid:Raid) => await this.admin sign = async (usertoken:string, character:Character, raid:Raid) => {
const maybeUserRecord = this.login.getUserRecordByToken(usertoken)
if(!maybeUserRecord || maybeUserRecord.user.id != character.userid){
throw new Error("Bad Usertoken")
}
await this.admin
.knex('signups') .knex('signups')
.insert({ .insert({
raid_id: raid.id!, raidid: raid.id!,
user_id: user.id! characterid: character.id!
}) })
}
} }
+3 -3
View File
@@ -13,7 +13,7 @@ export const Injector = new class {
rootInterface : Type<any> rootInterface : Type<any>
root : Type<any> root : Type<any>
rootModules: Type<any>[] = [] rootModules: Type<any>[] = []
modules : {ifc?: Type<any>, implementation: Type<any>}[] = [] modules : {implements?: Type<any>, implementation: Type<any>}[] = []
moduleObjs : {[key in string] : FrontworkComponent} = {} moduleObjs : {[key in string] : FrontworkComponent} = {}
@@ -31,8 +31,8 @@ export const Injector = new class {
if(target.name === this.rootInterface.name || target.name === this.root.name){ if(target.name === this.rootInterface.name || target.name === this.root.name){
let modules = this.modules.map(m => { let modules = this.modules.map(m => {
const module = new m.implementation() const module = new m.implementation()
if(m.ifc) if(m.implements)
this.moduleObjs[m.ifc.name] = module this.moduleObjs[m.implements.name] = module
this.moduleObjs[m.implementation.name] = module this.moduleObjs[m.implementation.name] = module
return module return module
}) })
+3 -3
View File
@@ -9,7 +9,7 @@ import { FrontworkComponent } from "../Types/FrontworkComponent";
export const Module = (ifc?: Type<any>) : GenericClassDecorator<Type<any>> => { export const Module = (ifc?: Type<any>) : GenericClassDecorator<Type<any>> => {
return (target: Type<any>) => { return (target: Type<any>) => {
Injector.modules.push({ Injector.modules.push({
ifc: ifc, extends: ifc,
implementation: target implementation: target
}) })
} }
@@ -20,12 +20,12 @@ export const Module = (ifc?: Type<any>) : GenericClassDecorator<Type<any>> => {
* @constructor * @constructor
*/ */
export const RootComponent = (config : { export const RootComponent = (config : {
rootInterface : Type<any> implements : Type<any>
imports : Type<FrontworkComponent>[] imports : Type<FrontworkComponent>[]
}) : GenericClassDecorator<Type<any>> => { }) : GenericClassDecorator<Type<any>> => {
return (target: Type<any>) => { return (target: Type<any>) => {
Injector.rootModules = config.imports Injector.rootModules = config.imports
Injector.rootInterface = config.rootInterface Injector.rootInterface = config.implements
Injector.root = target Injector.root = target
} }
} }
+16 -2
View File
@@ -1,4 +1,4 @@
import { Spec, _Class } from "./Types" import { Spec, _Class, Class } from "./Types"
export type SpecT = { export type SpecT = {
Warrior : 'Arms' | 'Fury' | 'Protection' Warrior : 'Arms' | 'Fury' | 'Protection'
@@ -74,9 +74,23 @@ export function getSpecTableData() : Spec[]{
const specNames : string[] = specs[_class] const specNames : string[] = specs[_class]
return specNames.map(specName => { return specNames.map(specName => {
return { return {
name: specName, specname: specName,
class: _class class: _class
} }
}) })
}) })
} }
export function getClassColor(c: Class) : string{
switch(c){
case "Warrior": return "#C79C6E"
case "Warlock": return "#8787ED"
case "Shaman": return "#0070DE"
case "Rogue": return "#FFF569"
case "Priest": return "#FFFFFF"
case "Paladin": return "#F58CBA"
case "Mage": return "#40C7EB"
case "Druid": return "#FF7D0A"
case "Hunter": return "#A9D271"
}
}
+13 -8
View File
@@ -1,5 +1,5 @@
import * as Knex from "knex" import * as Knex from "knex"
import { RPCExporter } from "rpclibrary"; import { RPCExporter, Socket } from "rpclibrary";
import { RaidManagerIfc, RaidManagerFeatureIfc } from "../Components/Raid/RPCInterface"; import { RaidManagerIfc, RaidManagerFeatureIfc } from "../Components/Raid/RPCInterface";
import { LoginManagerIfc, LoginManagerFeatureIfc } from "../Components/Login/RPCInterface"; import { LoginManagerIfc, LoginManagerFeatureIfc } from "../Components/Login/RPCInterface";
import { CharacterManagerIfc, CharacterManagerFeatureIfc } from "../Components/Character/RPCInterface"; import { CharacterManagerIfc, CharacterManagerFeatureIfc } from "../Components/Character/RPCInterface";
@@ -33,14 +33,14 @@ export const _Class : Class[] = ["Warrior" , "Rogue" , "Hunter" , "Mage" , "Warl
export type AnyRPCExporter = RPCExporter<any,any> export type AnyRPCExporter = RPCExporter<any,any>
export type RPCPermission = { export type RPCPermission = {
name: string rpcnamename: string
} & { } & {
[rank in Rank] : boolean [rank in Rank] : boolean
} }
export type Item = { export type Item = {
id?:number id?:number
name:string itemname:string
iconname:string iconname:string
url:string url:string
quality:string quality:string
@@ -49,7 +49,7 @@ export type Item = {
export type User = { export type User = {
id?: number id?: number
name: string username: string
pwhash: string pwhash: string
rank: Rank rank: Rank
email?: string email?: string
@@ -65,13 +65,13 @@ export type Raid = {
} }
export type Signup = { export type Signup = {
raid_id: number raidid: number
user_id: number characterid: number
} }
export type Character = { export type Character = {
id? : number id? : number
name : string charactername : string
specid : number specid : number
userid : number userid : number
} }
@@ -84,11 +84,16 @@ export type Token = {
export type Auth = {port: number, user: User, token: Token} export type Auth = {port: number, user: User, token: Token}
export type UserRecord = {
user: User
connections: {[port in number]: Socket}
auth: Auth
}
export type Spec = { export type Spec = {
id?: number, id?: number,
class: Class, class: Class,
name: string specname: string
} }
export type SomeOf<T> = { export type SomeOf<T> = {
+3 -3
View File
@@ -17366,9 +17366,9 @@
} }
}, },
"tslib": { "tslib": {
"version": "1.9.0", "version": "1.10.0",
"resolved": "https://registry.npmjs.org/tslib/-/tslib-1.9.0.tgz", "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.10.0.tgz",
"integrity": "sha512-f/qGG2tUkrISBlQZEjEqoZ3B2+npJjIf04H1wuAv9iA8i04Icp+61KRXxFdha22670NJopsZCIjhC3SnjPRKrQ==" "integrity": "sha512-qOebF53frne81cf0S9B41ByenJ3/IuH8yJKngAX35CmiZySA0khhkovshKK+jGCaMnVomla7gVlIcc3EvKPbTQ=="
}, },
"tslint": { "tslint": {
"version": "5.7.0", "version": "5.7.0",
+1 -1
View File
@@ -74,7 +74,7 @@
"rxjs-compat": "6.3.0", "rxjs-compat": "6.3.0",
"socicon": "3.0.5", "socicon": "3.0.5",
"tinymce": "4.5.7", "tinymce": "4.5.7",
"tslib": "^1.9.0", "tslib": "^1.10.0",
"typeface-exo": "0.0.22", "typeface-exo": "0.0.22",
"web-animations-js": "github:angular/web-animations-js#release_pr208", "web-animations-js": "github:angular/web-animations-js#release_pr208",
"zone.js": "~0.9.1" "zone.js": "~0.9.1"
@@ -16,7 +16,7 @@
<nb-action class="user-action"> <nb-action class="user-action">
<nb-user [nbContextMenu]="userMenu" <nb-user [nbContextMenu]="userMenu"
[onlyPicture]="false" [onlyPicture]="false"
[name]="user?.name" [name]="user?.username"
[picture]="user?.picture"> [picture]="user?.picture">
</nb-user> </nb-user>
</nb-action> </nb-action>
@@ -39,7 +39,7 @@ export class HeaderComponent implements OnInit, OnDestroy {
currentTheme = 'dark'; currentTheme = 'dark';
userMenu : NbMenuItem[] = [ { title: 'Profile' }, { title: 'Log out', url: '/auth/logout' } ]; userMenu : NbMenuItem[] = [ { title: 'Log out', link: '/auth/logout' } ];
constructor(private sidebarService: NbSidebarService, constructor(private sidebarService: NbSidebarService,
private menuService: NbMenuService, private menuService: NbMenuService,
@@ -53,6 +53,8 @@ export class HeaderComponent implements OnInit, OnDestroy {
this.currentTheme = this.themeService.currentTheme; this.currentTheme = this.themeService.currentTheme;
this.user = this.loginService.getCurrentUser() this.user = this.loginService.getCurrentUser()
if(this.user)
this.userMenu.unshift({ title: 'Profile', link: '/frontcraft/user/'+this.user.username });
/* /*
this.userService.getUsers() this.userService.getUsers()
@@ -2,6 +2,7 @@ import { ExtraOptions, RouterModule, Routes } from '@angular/router';
import { NgModule } from '@angular/core'; import { NgModule } from '@angular/core';
const routes: Routes = [ const routes: Routes = [
{ {
path: 'auth', path: 'auth',
loadChildren: () => import('./frontcraft/auth/auth.module') loadChildren: () => import('./frontcraft/auth/auth.module')
-1
View File
@@ -20,7 +20,6 @@ import {
NbToastrModule, NbToastrModule,
NbWindowModule, NbWindowModule,
} from '@nebular/theme'; } from '@nebular/theme';
import { LoginApiService } from './frontcraft/services/login-api';
@NgModule({ @NgModule({
declarations: [AppComponent], declarations: [AppComponent],
@@ -21,7 +21,7 @@
<label class="label" for="input-username">Username:</label> <label class="label" for="input-username">Username:</label>
<input nbInput <input nbInput
fullWidth fullWidth
[(ngModel)]="user.name" [(ngModel)]="user.username"
#email="ngModel" #email="ngModel"
name="name" name="name"
id="input-username" id="input-username"
@@ -52,6 +52,7 @@ export class RegisterComponent implements OnInit{
} }
async onSubmit(){ async onSubmit(){
const pw = this.user.pwhash
this.user.pwhash = await hash(this.user.pwhash) this.user.pwhash = await hash(this.user.pwhash)
const user = this.user const user = this.user
this.user = {} as User this.user = {} as User
@@ -60,9 +61,25 @@ export class RegisterComponent implements OnInit{
try{ try{
const usr = await this.loginApi.getUnprivilegedSocket().Authenticator.createUser(user) const usr = await this.loginApi.getUnprivilegedSocket().Authenticator.createUser(user)
}catch(e){ }catch(e){
alert("Error creating user"+e) alert("Error creating user"+e)
return
}
try{
await this.loginApi.login(user.username, pw)
await this.loginApi.getFeature('createCharacter').then(async feature => {
if(!feature) return
const specid = await this.loginApi.getUnprivilegedSocket().CharacterManager.getSpecId(char['class'], char['spec'])
await feature.createCharacter(this.loginApi.getAuth().token.value, {
charactername: char.name,
specid: specid,
userid: this.loginApi.getAuth().user.id!
})
})
}catch(e){
alert("Error creating character"+e)
return
} }
} }
@@ -0,0 +1,10 @@
<nb-card
status="control">
<nb-card-header [ngStyle]="{'color': color}" style="text-transform: capitalize;">
{{char.charactername}}
</nb-card-header>
<nb-card-body>
{{char.specname}} {{char.class}}<br />
Owned by <a [routerLink]="'/frontcraft/user/'+char.username"> {{char.username}} ({{char.rank}})</a>
</nb-card-body>
</nb-card>
@@ -0,0 +1,34 @@
import { Component, OnInit } from '@angular/core';
import { ActivatedRoute, Router } from '@angular/router';
import { LoginApiService } from '../../services/login-api';
import { Spec, User, Character } from '../../../../../../backend/Types/Types';
import { getClassColor } from '../../../../../../backend/Types/PlayerSpecs';
@Component({
selector: 'character',
templateUrl: './character.component.html',
})
export class FrontcraftCharacterComponent implements OnInit{
char : (Character & User & Spec) = {} as any
color : string
constructor(
private login: LoginApiService,
private route: ActivatedRoute,
private router: Router,
){}
async ngOnInit(){
const param = this.route.snapshot.paramMap.get('name');
this.login.getUnprivilegedSocket()
.CharacterManager
.getCharacterByName(param)
.then((char) => {
if(char){
this.color = getClassColor(char.class)
this.char = char
}
})
}
}
@@ -1 +1,35 @@
<strong> Dashboard </strong> <nb-card>
<nb-card-body>
<label class="search-label" for="search">Search:</label>
<input nbInput [nbFilterInput]="dataSource" id="search" class="search-input">
<table [nbTreeGrid]="dataSource" [nbSort]="dataSource" (sort)="updateSort($event)">
<tr nbTreeGridHeaderRow *nbTreeGridHeaderRowDef="allColumns"></tr>
<tr nbTreeGridRow *nbTreeGridRowDef="let row; columns: allColumns"></tr>
<ng-container [nbTreeGridColumnDef]="customColumn">
<th nbTreeGridHeaderCell [nbSortHeader]="getSortDirection(customColumn)" *nbTreeGridHeaderCellDef>
{{customColumn}}
</th>
<td nbTreeGridCell *nbTreeGridCellDef="let row">
<nb-tree-grid-row-toggle
*ngIf="row.children && row.children.length">
</nb-tree-grid-row-toggle>
{{row.data[customColumn]}}
</td>
</ng-container>
<ng-container *ngFor="let column of defaultColumns; let index = index"
[nbTreeGridColumnDef]="column"
[showOn]="getShowOn(index)">
<th nbTreeGridHeaderCell [nbSortHeader]="getSortDirection(column)" *nbTreeGridHeaderCellDef>
{{column}}
</th>
<td nbTreeGridCell *nbTreeGridCellDef="let row">{{row.data[column] || '-'}}</td>
</ng-container>
</table>
</nb-card-body>
</nb-card>
@@ -0,0 +1,42 @@
button[nbTreeGridRowToggle] {
background: transparent;
border: none;
padding: 0;
}
.search-label {
display: block;
}
.search-input {
margin-bottom: 1rem;
}
.nb-column-name {
width: 100%;
}
@media screen and (min-width: 400px) {
.nb-column-name,
.nb-column-size {
width: 50%;
}
}
@media screen and (min-width: 500px) {
.nb-column-name,
.nb-column-size,
.nb-column-kind {
width: 33.333%;
}
}
@media screen and (min-width: 600px) {
.nb-column-name {
width: 31%;
}
.nb-column-size,
.nb-column-kind,
.nb-column-items {
width: 23%;
}
}
@@ -1,16 +1,63 @@
import { Component, OnInit } from '@angular/core'; import { Component } from '@angular/core';
import { LoginApiService } from '../../services/login-api'; import { NbSortDirection, NbSortRequest, NbTreeGridDataSourceBuilder, NbTreeGridDataSource } from '@nebular/theme';
interface TreeNode<T> {
data: T;
children?: TreeNode<T>[];
expanded?: boolean;
}
interface Row {
name: string,
character: any,
SRC: any,
}
type TreeType = TreeNode<Row>
@Component({ @Component({
selector: 'dashboard', selector: 'dashboard',
templateUrl: './dashboard.component.html', templateUrl: './dashboard.component.html',
styleUrls: ['./tree-grid-shared.scss', './dashboard.component.scss'],
}) })
export class FrontcraftDashboardComponent implements OnInit{ export class FrontcraftDashboardComponent{
customColumn = 'name';
defaultColumns = [ 'character', 'SRC'/*, 'Profile'*/ ];
allColumns = [ this.customColumn, ...this.defaultColumns ];
constructor(private loginApi : LoginApiService){} dataSource: NbTreeGridDataSource<TreeType>;
ngOnInit(){ sortColumn: string;
console.log(this.loginApi) sortDirection: NbSortDirection = NbSortDirection.NONE;
constructor(private dataSourceBuilder: NbTreeGridDataSourceBuilder<TreeType>) {
this.dataSource = this.dataSourceBuilder.create(this.data);
} }
updateSort(sortRequest: NbSortRequest): void {
this.sortColumn = sortRequest.column;
this.sortDirection = sortRequest.direction;
}
getSortDirection(column: string): NbSortDirection {
if (this.sortColumn === column) {
return this.sortDirection;
}
return NbSortDirection.NONE;
}
private data: TreeType[] = [
{
data: {name: 'a', character: 2, SRC: 0},
children: [
{data: {name: 'a', character: 'Warrior', SRC: 'Arms'}}
]
}
];
getShowOn(index: number) {
const minWithForMultipleColumns = 400;
const nextColumnStep = 100;
return minWithForMultipleColumns + (nextColumnStep * index);
}
} }
@@ -0,0 +1,10 @@
::ng-deep {
body {
min-height: 20rem;
}
.nb-tree-grid-header-cell,
.nb-tree-grid-header-cell button {
text-transform: capitalize;
}
}
@@ -17,10 +17,19 @@ import { Router } from '@angular/router';
export class PagesLayoutComponent implements OnInit{ export class PagesLayoutComponent implements OnInit{
menu:NbMenuItem[] = [{ menu:NbMenuItem[] = [{
icon: 'people-outline', icon: 'people-outline',
title: 'People' title: 'People',
link: '/frontcraft/people'
},{ },{
icon: 'clock-outline', icon: 'clock-outline',
title: 'Raids' title: 'Raids'
},{
icon: 'clock-outline',
title: 'character',
link: '/frontcraft/character/a'
},{
icon: 'clock-outline',
title: 'user',
link: '/frontcraft/user/a'
}] }]
constructor( constructor(
@@ -2,12 +2,27 @@ import { NgModule } from '@angular/core';
import { RouterModule, Routes } from '@angular/router'; import { RouterModule, Routes } from '@angular/router';
import { FrontcraftDashboardComponent } from './dashboard/dashboard.component'; import { FrontcraftDashboardComponent } from './dashboard/dashboard.component';
import { PagesLayoutComponent } from './pages-layout.component'; import { PagesLayoutComponent } from './pages-layout.component';
import { FrontcraftCharacterComponent } from './character/character.component';
import { FrontcraftUserComponent } from './user/user.component';
import { FrontcraftPeopleComponent } from './people/people.component';
export const routes: Routes = [ export const routes: Routes = [
{ {
path: '', path: '',
component: PagesLayoutComponent, component: PagesLayoutComponent,
children: [ children: [
{
path: 'people',
component: FrontcraftPeopleComponent
},
{
path: 'user/:name',
component: FrontcraftUserComponent
},
{
path: 'character/:name',
component: FrontcraftCharacterComponent
},
{ {
path: 'dashboard', path: 'dashboard',
component: FrontcraftDashboardComponent, component: FrontcraftDashboardComponent,
@@ -9,7 +9,8 @@ import {
NbCheckboxModule, NbCheckboxModule,
NbInputModule, NbInputModule,
NbMenuModule, NbMenuModule,
NbCardModule NbCardModule,
NbTreeGridModule
} from '@nebular/theme'; } from '@nebular/theme';
import { MyAuthRoutingModule } from './pages-routing.module'; import { MyAuthRoutingModule } from './pages-routing.module';
import { FrontcraftDashboardComponent } from './dashboard/dashboard.component'; import { FrontcraftDashboardComponent } from './dashboard/dashboard.component';
@@ -18,11 +19,15 @@ import { ThemeModule } from '../../@theme/theme.module';
import { DashboardModule } from '../../demo_pages/dashboard/dashboard.module'; import { DashboardModule } from '../../demo_pages/dashboard/dashboard.module';
import { ECommerceModule } from '../../demo_pages/e-commerce/e-commerce.module'; import { ECommerceModule } from '../../demo_pages/e-commerce/e-commerce.module';
import { MiscellaneousModule } from '../../demo_pages/miscellaneous/miscellaneous.module'; import { MiscellaneousModule } from '../../demo_pages/miscellaneous/miscellaneous.module';
import { FrontcraftCharacterComponent } from './character/character.component';
import { FrontcraftUserComponent } from './user/user.component';
import { FrontcraftPeopleComponent } from './people/people.component';
@NgModule({ @NgModule({
imports: [ imports: [
MyAuthRoutingModule, MyAuthRoutingModule,
NbTreeGridModule,
CommonModule, CommonModule,
FormsModule, FormsModule,
RouterModule, RouterModule,
@@ -39,6 +44,9 @@ import { MiscellaneousModule } from '../../demo_pages/miscellaneous/miscellaneou
], ],
declarations: [ declarations: [
FrontcraftPeopleComponent,
FrontcraftUserComponent,
FrontcraftCharacterComponent,
PagesLayoutComponent, PagesLayoutComponent,
FrontcraftDashboardComponent FrontcraftDashboardComponent
], ],
@@ -0,0 +1,36 @@
<nb-card>
<nb-card-body>
<label class="search-label" for="search">Search:</label>
<input nbInput [nbFilterInput]="dataSource" id="search" class="search-input">
<table [nbTreeGrid]="dataSource" [nbSort]="dataSource" (sort)="updateSort($event)">
<tr nbTreeGridHeaderRow *nbTreeGridHeaderRowDef="allColumns"></tr>
<tr nbTreeGridRow *nbTreeGridRowDef="let row; columns: allColumns"></tr>
<ng-container [nbTreeGridColumnDef]="customColumn">
<th nbTreeGridHeaderCell [nbSortHeader]="getSortDirection(customColumn)" *nbTreeGridHeaderCellDef>
{{customColumn}}
</th>
<td nbTreeGridCell *nbTreeGridCellDef="let row">
<nb-tree-grid-row-toggle
*ngIf="row.children && row.children.length">
</nb-tree-grid-row-toggle>
<span style="text-transform: capitalize;">
{{row.data[customColumn]}}
</span>
</td>
</ng-container>
<ng-container *ngFor="let column of defaultColumns; let index = index"
[nbTreeGridColumnDef]="column"
[showOn]="getShowOn(index)">
<th nbTreeGridHeaderCell [nbSortHeader]="getSortDirection(column)" *nbTreeGridHeaderCellDef>
{{column}}
</th>
<td nbTreeGridCell *nbTreeGridCellDef="let row">{{row.data[column] || '-'}}</td>
</ng-container>
</table>
</nb-card-body>
</nb-card>
@@ -0,0 +1,42 @@
button[nbTreeGridRowToggle] {
background: transparent;
border: none;
padding: 0;
}
.search-label {
display: block;
}
.search-input {
margin-bottom: 1rem;
}
.nb-column-name {
width: 100%;
}
@media screen and (min-width: 400px) {
.nb-column-name,
.nb-column-size {
width: 50%;
}
}
@media screen and (min-width: 500px) {
.nb-column-name,
.nb-column-size,
.nb-column-kind {
width: 33.333%;
}
}
@media screen and (min-width: 600px) {
.nb-column-name {
width: 31%;
}
.nb-column-size,
.nb-column-kind,
.nb-column-items {
width: 23%;
}
}
@@ -0,0 +1,64 @@
import { Component } from '@angular/core';
import { NbSortDirection, NbSortRequest, NbTreeGridDataSourceBuilder, NbTreeGridDataSource } from '@nebular/theme';
interface TreeNode<T> {
data: T;
children?: TreeNode<T>[];
expanded?: boolean;
}
interface Row {
name: string,
character: any,
SRC: any,
kind: 'Character' | 'Account'
}
type TreeType = TreeNode<Row>
@Component({
selector: 'people-component',
templateUrl: './people.component.html',
styleUrls: ['./tree-grid-shared.scss', './people.component.scss'],
})
export class FrontcraftPeopleComponent{
customColumn = 'name';
defaultColumns = [ 'character', 'SRC'/*, 'Profile'*/ ];
allColumns = [ this.customColumn, ...this.defaultColumns ];
dataSource: NbTreeGridDataSource<TreeType>;
sortColumn: string;
sortDirection: NbSortDirection = NbSortDirection.NONE;
constructor(private dataSourceBuilder: NbTreeGridDataSourceBuilder<TreeType>) {
this.dataSource = this.dataSourceBuilder.create(this.data);
}
updateSort(sortRequest: NbSortRequest): void {
this.sortColumn = sortRequest.column;
this.sortDirection = sortRequest.direction;
}
getSortDirection(column: string): NbSortDirection {
if (this.sortColumn === column) {
return this.sortDirection;
}
return NbSortDirection.NONE;
}
private data: TreeType[] = [
{
data: {name: 'a', character: 2, SRC: 0, kind: 'Account'},
children: [
{data: {name: 'a', character: 'Warrior', SRC: 'Arms', kind: 'Character'}}
]
}
];
getShowOn(index: number) {
const minWithForMultipleColumns = 400;
const nextColumnStep = 100;
return minWithForMultipleColumns + (nextColumnStep * index);
}
}
@@ -0,0 +1,10 @@
::ng-deep {
body {
min-height: 20rem;
}
.nb-tree-grid-header-cell,
.nb-tree-grid-header-cell button {
text-transform: capitalize;
}
}
@@ -0,0 +1,24 @@
<nb-card
accent="info">
<nb-card-header>
<h2 style="text-transform: capitalize;">{{user.username}}</h2>
</nb-card-header>
<nb-card-body>
<nb-card
accent="control"
*ngFor="let char of characters">
<nb-card-header>
<h4>
<a [ngStyle]="{'color': char.color}" style="text-transform: capitalize;" [routerLink]="'/frontcraft/character/'+char.charactername">
{{char.charactername}}
</a>
</h4>
</nb-card-header>
<nb-card-body>
{{char.specname}} {{char.class}}
</nb-card-body>
</nb-card>
</nb-card-body>
</nb-card>
@@ -0,0 +1,38 @@
import { Component, OnInit } from '@angular/core';
import { LoginApiService } from '../../services/login-api';
import { Router } from '@angular/router';
import { User, Spec, Character } from '../../../../../../backend/Types/Types';
import { getClassColor } from '../../../../../../backend/Types/PlayerSpecs';
@Component({
selector: 'user-component',
templateUrl: './user.component.html',
})
export class FrontcraftUserComponent implements OnInit{
user:User = {} as any
characters : (Character & Spec)[] = []
constructor(
private router : Router,
private loginApi : LoginApiService
){}
ngOnInit(){
const auth = this.loginApi.getAuth()
if(!auth){
this.router.navigateByUrl('/auth/login')
return
}
this.user = auth.user
this.loginApi.getUnprivilegedSocket()
.CharacterManager
.getCharactersOfUser(this.user.username)
.then((characters) => {
characters.forEach(c => {
c['color'] = getClassColor(c.class)
})
this.characters = characters
})
}
}
@@ -31,16 +31,18 @@ export class LoginApiService{
const authSock = await sock.connect<RPCSocket & SomeOf<FrontcraftFeatureIfc>>(auth.token.value) const authSock = await sock.connect<RPCSocket & SomeOf<FrontcraftFeatureIfc>>(auth.token.value)
sock.hook('kick', () => this.logout()) sock.hook('kick', () => {
console.log("I got kicked");
})
sock.hook('getUserData', () => auth) sock.hook('getUserData', () => auth)
sock.hook('navigate', (where:string) => { sock.hook('navigate', (where:string) => {
this.ngZone.run(() => { this.ngZone.run( () => {
this.injector.get(Router).navigateByUrl(where); this.injector.get(Router).navigateByUrl('/')
}) })
}) })
sock.on('error', (e) => { sock.on('error', (e) => {
console.log('Socket error', e) sock.destroy();
this.logout()
}) })
this.auth = auth this.auth = auth
@@ -62,7 +64,9 @@ export class LoginApiService{
} }
} }
getCurrentUser = () : User | undefined => this.auth?this.auth.user:undefined getCurrentUser = () : User | undefined => {
return this.auth?this.auth.user:undefined
}
login = async (username: string, password: string) : Promise<RPCSocket & SomeOf<FrontcraftFeatureIfc>> => { login = async (username: string, password: string) : Promise<RPCSocket & SomeOf<FrontcraftFeatureIfc>> => {
const pwHash = await hash(password) const pwHash = await hash(password)
@@ -78,7 +82,7 @@ export class LoginApiService{
logout = async () => { logout = async () => {
this.cookieSvc.set('token', undefined) this.cookieSvc.set('token', undefined)
if(this.auth) await this.socket.Authenticator.logout(this.auth.user.name, this.auth.token.value) if(this.auth) await this.socket.Authenticator.logout(this.auth.user.username, this.auth.token.value)
if(this.privSocket) this.privSocket.destroy() if(this.privSocket) this.privSocket.destroy()
this.privSocket = null this.privSocket = null
this.auth = null this.auth = null