Compare commits
10
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
bbe080ab7f | ||
|
|
75c48273ff | ||
|
|
c2d2917de3 | ||
|
|
78abe78903 | ||
|
|
d4a528e61e | ||
|
|
c09c9ab67c | ||
|
|
f9008e67bd | ||
|
|
7e2c1d5761 | ||
|
|
1765c2eabc | ||
|
|
eb58ffc013 |
@@ -17,6 +17,7 @@ log.txt
|
|||||||
|
|
||||||
|
|
||||||
!src/**/*
|
!src/**/*
|
||||||
|
!test/**/*
|
||||||
!migrations/**/*
|
!migrations/**/*
|
||||||
node_modules
|
node_modules
|
||||||
src/frontend/node_modules
|
src/frontend/node_modules
|
||||||
|
|||||||
Generated
+70
-3
@@ -93,12 +93,29 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"@types/body-parser": {
|
||||||
|
"version": "1.19.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/@types/body-parser/-/body-parser-1.19.0.tgz",
|
||||||
|
"integrity": "sha512-W98JrE0j2K78swW4ukqMleo8R7h/pFETjM2DQ90MF6XK2i4LO4W3gQ71Lt4w3bfm2EvVSyWHplECvB5sK22yFQ==",
|
||||||
|
"requires": {
|
||||||
|
"@types/connect": "*",
|
||||||
|
"@types/node": "*"
|
||||||
|
}
|
||||||
|
},
|
||||||
"@types/color-name": {
|
"@types/color-name": {
|
||||||
"version": "1.1.1",
|
"version": "1.1.1",
|
||||||
"resolved": "https://registry.npmjs.org/@types/color-name/-/color-name-1.1.1.tgz",
|
"resolved": "https://registry.npmjs.org/@types/color-name/-/color-name-1.1.1.tgz",
|
||||||
"integrity": "sha512-rr+OQyAjxze7GgWrSaJwydHStIhHq2lvY3BOC2Mj7KnzI7XK0Uw1TOOdI9lDoajEbSWLiYgoo4f1R51erQfhPQ==",
|
"integrity": "sha512-rr+OQyAjxze7GgWrSaJwydHStIhHq2lvY3BOC2Mj7KnzI7XK0Uw1TOOdI9lDoajEbSWLiYgoo4f1R51erQfhPQ==",
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
|
"@types/connect": {
|
||||||
|
"version": "3.4.33",
|
||||||
|
"resolved": "https://registry.npmjs.org/@types/connect/-/connect-3.4.33.tgz",
|
||||||
|
"integrity": "sha512-2+FrkXY4zllzTNfJth7jOqEHC+enpLeGslEhpnTAkg21GkRrWV4SsAtqchtT4YS9/nODBU2/ZfsBY2X4J/dX7A==",
|
||||||
|
"requires": {
|
||||||
|
"@types/node": "*"
|
||||||
|
}
|
||||||
|
},
|
||||||
"@types/engine.io": {
|
"@types/engine.io": {
|
||||||
"version": "3.1.4",
|
"version": "3.1.4",
|
||||||
"resolved": "https://registry.npmjs.org/@types/engine.io/-/engine.io-3.1.4.tgz",
|
"resolved": "https://registry.npmjs.org/@types/engine.io/-/engine.io-3.1.4.tgz",
|
||||||
@@ -107,6 +124,27 @@
|
|||||||
"@types/node": "*"
|
"@types/node": "*"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"@types/express": {
|
||||||
|
"version": "4.17.8",
|
||||||
|
"resolved": "https://registry.npmjs.org/@types/express/-/express-4.17.8.tgz",
|
||||||
|
"integrity": "sha512-wLhcKh3PMlyA2cNAB9sjM1BntnhPMiM0JOBwPBqttjHev2428MLEB4AYVN+d8s2iyCVZac+o41Pflm/ZH5vLXQ==",
|
||||||
|
"requires": {
|
||||||
|
"@types/body-parser": "*",
|
||||||
|
"@types/express-serve-static-core": "*",
|
||||||
|
"@types/qs": "*",
|
||||||
|
"@types/serve-static": "*"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"@types/express-serve-static-core": {
|
||||||
|
"version": "4.17.13",
|
||||||
|
"resolved": "https://registry.npmjs.org/@types/express-serve-static-core/-/express-serve-static-core-4.17.13.tgz",
|
||||||
|
"integrity": "sha512-RgDi5a4nuzam073lRGKTUIaL3eF2+H7LJvJ8eUnCI0wA6SNjXc44DCmWNiTLs/AZ7QlsFWZiw/gTG3nSQGL0fA==",
|
||||||
|
"requires": {
|
||||||
|
"@types/node": "*",
|
||||||
|
"@types/qs": "*",
|
||||||
|
"@types/range-parser": "*"
|
||||||
|
}
|
||||||
|
},
|
||||||
"@types/fs-extra": {
|
"@types/fs-extra": {
|
||||||
"version": "8.0.0",
|
"version": "8.0.0",
|
||||||
"resolved": "https://registry.npmjs.org/@types/fs-extra/-/fs-extra-8.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/@types/fs-extra/-/fs-extra-8.0.0.tgz",
|
||||||
@@ -133,6 +171,11 @@
|
|||||||
"@types/lodash": "*"
|
"@types/lodash": "*"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"@types/mime": {
|
||||||
|
"version": "2.0.3",
|
||||||
|
"resolved": "https://registry.npmjs.org/@types/mime/-/mime-2.0.3.tgz",
|
||||||
|
"integrity": "sha512-Jus9s4CDbqwocc5pOAnh8ShfrnMcPHuJYzVcSUU7lrh8Ni5HuIqX3oilL86p3dlTrk0LzHRCgA/GQ7uNCw6l2Q=="
|
||||||
|
},
|
||||||
"@types/mocha": {
|
"@types/mocha": {
|
||||||
"version": "5.2.7",
|
"version": "5.2.7",
|
||||||
"resolved": "https://registry.npmjs.org/@types/mocha/-/mocha-5.2.7.tgz",
|
"resolved": "https://registry.npmjs.org/@types/mocha/-/mocha-5.2.7.tgz",
|
||||||
@@ -151,6 +194,25 @@
|
|||||||
"@types/node": "*"
|
"@types/node": "*"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"@types/qs": {
|
||||||
|
"version": "6.9.5",
|
||||||
|
"resolved": "https://registry.npmjs.org/@types/qs/-/qs-6.9.5.tgz",
|
||||||
|
"integrity": "sha512-/JHkVHtx/REVG0VVToGRGH2+23hsYLHdyG+GrvoUGlGAd0ErauXDyvHtRI/7H7mzLm+tBCKA7pfcpkQ1lf58iQ=="
|
||||||
|
},
|
||||||
|
"@types/range-parser": {
|
||||||
|
"version": "1.2.3",
|
||||||
|
"resolved": "https://registry.npmjs.org/@types/range-parser/-/range-parser-1.2.3.tgz",
|
||||||
|
"integrity": "sha512-ewFXqrQHlFsgc09MK5jP5iR7vumV/BYayNC6PgJO2LPe8vrnNFyjQjSppfEngITi0qvfKtzFvgKymGheFM9UOA=="
|
||||||
|
},
|
||||||
|
"@types/serve-static": {
|
||||||
|
"version": "1.13.5",
|
||||||
|
"resolved": "https://registry.npmjs.org/@types/serve-static/-/serve-static-1.13.5.tgz",
|
||||||
|
"integrity": "sha512-6M64P58N+OXjU432WoLLBQxbA0LRGBCRm7aAGQJ+SMC1IMl0dgRVi9EFfoDcS2a7Xogygk/eGN94CfwU9UF7UQ==",
|
||||||
|
"requires": {
|
||||||
|
"@types/express-serve-static-core": "*",
|
||||||
|
"@types/mime": "*"
|
||||||
|
}
|
||||||
|
},
|
||||||
"@types/socket.io": {
|
"@types/socket.io": {
|
||||||
"version": "2.1.10",
|
"version": "2.1.10",
|
||||||
"resolved": "https://registry.npmjs.org/@types/socket.io/-/socket.io-2.1.10.tgz",
|
"resolved": "https://registry.npmjs.org/@types/socket.io/-/socket.io-2.1.10.tgz",
|
||||||
@@ -4227,6 +4289,11 @@
|
|||||||
"resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz",
|
"resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz",
|
||||||
"integrity": "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg=="
|
"integrity": "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg=="
|
||||||
},
|
},
|
||||||
|
"rate-limiter-flexible": {
|
||||||
|
"version": "2.1.10",
|
||||||
|
"resolved": "https://registry.npmjs.org/rate-limiter-flexible/-/rate-limiter-flexible-2.1.10.tgz",
|
||||||
|
"integrity": "sha512-Pa+8TPD4xYaiCUB5K4a/+j2FHDUe4HP1g49JmKEmkOkhqPaeVqxJsZuuVaza/svSCOT+V73vtsyBiSFK/e1yXw=="
|
||||||
|
},
|
||||||
"raw-body": {
|
"raw-body": {
|
||||||
"version": "2.4.0",
|
"version": "2.4.0",
|
||||||
"resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.4.0.tgz",
|
"resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.4.0.tgz",
|
||||||
@@ -4410,9 +4477,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"rpclibrary": {
|
"rpclibrary": {
|
||||||
"version": "2.0.1",
|
"version": "2.3.1",
|
||||||
"resolved": "https://registry.npmjs.org/rpclibrary/-/rpclibrary-2.0.1.tgz",
|
"resolved": "https://registry.npmjs.org/rpclibrary/-/rpclibrary-2.3.1.tgz",
|
||||||
"integrity": "sha512-phdU0TkrnNVXdFa5PKkbWvn+MxocowvqalEUG1jfpkc1CoQkJ9AXa4OXSEu5r2a2IFhVauYva/qXv1em5yrHSg==",
|
"integrity": "sha512-y6F6gYxm9joJcnyxNeEoUSAbYGsaogcEKb1bxVB97+HcT4J6q9yw2fGnWS1FeeAUbTLUwASdlqJvRLPLiMPlcQ==",
|
||||||
"requires": {
|
"requires": {
|
||||||
"@types/socket.io": "^2.1.8",
|
"@types/socket.io": "^2.1.8",
|
||||||
"@types/socket.io-client": "^1.4.33",
|
"@types/socket.io-client": "^1.4.33",
|
||||||
|
|||||||
+3
-1
@@ -25,6 +25,7 @@
|
|||||||
"author": "frontblock.me",
|
"author": "frontblock.me",
|
||||||
"license": "ISC",
|
"license": "ISC",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
"@types/express": "^4.17.8",
|
||||||
"@types/mocha": "^5.2.7",
|
"@types/mocha": "^5.2.7",
|
||||||
"@types/node": "^14.0.27",
|
"@types/node": "^14.0.27",
|
||||||
"bsert": "0.0.10",
|
"bsert": "0.0.10",
|
||||||
@@ -46,9 +47,10 @@
|
|||||||
"ngx-cookie-service": "^2.4.0",
|
"ngx-cookie-service": "^2.4.0",
|
||||||
"node-fetch": "^2.6.0",
|
"node-fetch": "^2.6.0",
|
||||||
"path": "^0.12.7",
|
"path": "^0.12.7",
|
||||||
|
"rate-limiter-flexible": "^2.1.10",
|
||||||
"reflect-metadata": "^0.1.13",
|
"reflect-metadata": "^0.1.13",
|
||||||
"rimraf": "^3.0.0",
|
"rimraf": "^3.0.0",
|
||||||
"rpclibrary": "^2.0.1",
|
"rpclibrary": "^2.3.1",
|
||||||
"simple-git": "^1.124.0",
|
"simple-git": "^1.124.0",
|
||||||
"spawn-sync": "^2.0.0",
|
"spawn-sync": "^2.0.0",
|
||||||
"sqlite3": "^4.2.0",
|
"sqlite3": "^4.2.0",
|
||||||
|
|||||||
+37
-18
@@ -15,12 +15,14 @@ import { CharacterManager } from '../Components/Character/CharacterManager';
|
|||||||
import { UserManager } from '../Components/User/UserManager';
|
import { UserManager } from '../Components/User/UserManager';
|
||||||
import { RootComponent } from '../Injector/ServiceDecorator';
|
import { RootComponent } from '../Injector/ServiceDecorator';
|
||||||
import { TableDefinitionExporter } from '../Types/Interfaces';
|
import { TableDefinitionExporter } from '../Types/Interfaces';
|
||||||
import { AdminConf, TableDefiniton } from '../Types/Types';
|
import { AdminConf, TableDefiniton, SomeOf } from '../Types/Types';
|
||||||
import { RPCConfigLoader } from '../Components/RPCConfigLoader';
|
import { RPCConfigLoader } from '../Components/RPCConfigLoader';
|
||||||
import { FrontworkComponent } from '../Types/FrontworkComponent';
|
import { FrontworkComponent } from '../Types/FrontworkComponent';
|
||||||
import { IAdmin } from './Interface';
|
import { IAdmin } from './Interface';
|
||||||
import { Injector } from '../Injector/Injector';
|
import { Injector } from '../Injector/Injector';
|
||||||
import { PubSub } from '../Components/PubSub/PubSub';
|
import { PubSub } from '../Components/PubSub/PubSub';
|
||||||
|
import { BurstyRateLimiter, RateLimiterMemory, RateLimiterAbstract } from 'rate-limiter-flexible'
|
||||||
|
|
||||||
|
|
||||||
@RootComponent({
|
@RootComponent({
|
||||||
injectable: IAdmin,
|
injectable: IAdmin,
|
||||||
@@ -39,7 +41,7 @@ export class FrontworkAdmin
|
|||||||
config: RPCConfigLoader<AdminConf>
|
config: RPCConfigLoader<AdminConf>
|
||||||
rpcServer: RPCServer
|
rpcServer: RPCServer
|
||||||
|
|
||||||
private express
|
private express : express.Application
|
||||||
private httpServer
|
private httpServer
|
||||||
|
|
||||||
constructor(private frontworkComponents: FrontworkComponent[] = []) {
|
constructor(private frontworkComponents: FrontworkComponent[] = []) {
|
||||||
@@ -66,14 +68,26 @@ export class FrontworkAdmin
|
|||||||
}
|
}
|
||||||
|
|
||||||
async start() {
|
async start() {
|
||||||
|
const ONE_REQUEST = 15
|
||||||
let port: number = this.config.getConfig().httpPort
|
let port: number = this.config.getConfig().httpPort
|
||||||
|
const rateLimiter = new BurstyRateLimiter(
|
||||||
|
new RateLimiterMemory({
|
||||||
|
points: 2*ONE_REQUEST,
|
||||||
|
duration: 1,
|
||||||
|
}),
|
||||||
|
new RateLimiterMemory({
|
||||||
|
keyPrefix: 'burst',
|
||||||
|
points: 5*ONE_REQUEST,
|
||||||
|
duration: 60,
|
||||||
|
})
|
||||||
|
)
|
||||||
|
|
||||||
await this.makeKnex()
|
await this.makeKnex()
|
||||||
const app = await this.makeExpress()
|
const app = await this.makeExpress(rateLimiter)
|
||||||
const httpServer = new http.Server(app)
|
const httpServer = new http.Server(app)
|
||||||
await this.startWebsocket(httpServer)
|
await this.startWebsocket(httpServer)
|
||||||
httpServer.listen(port)
|
httpServer.listen(port)
|
||||||
await this.attachAngularSSR(app)
|
await this.attachAngularSSR(app, rateLimiter)
|
||||||
getLogger('Admin#startWebsocket').debug("Webserver up on", port)
|
getLogger('Admin#startWebsocket').debug("Webserver up on", port)
|
||||||
|
|
||||||
await Promise.all(this.frontworkComponents.map(c => c.initialize ? c.initialize() : undefined))
|
await Promise.all(this.frontworkComponents.map(c => c.initialize ? c.initialize() : undefined))
|
||||||
@@ -125,48 +139,53 @@ export class FrontworkAdmin
|
|||||||
}
|
}
|
||||||
], {
|
], {
|
||||||
errorHandler: (sock, err, rpc, args) => {
|
errorHandler: (sock, err, rpc, args) => {
|
||||||
console.log(rpc, err);
|
getLogger("startWebsocket#errorHandler").error("RPC", rpc)
|
||||||
|
getLogger("startWebsocket#errorHandler").error("ERR", err)
|
||||||
|
getLogger("startWebsocket#errorHandler").error("ARGS", args)
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
.attach(httpServer)
|
.attach(httpServer)
|
||||||
}
|
}
|
||||||
|
|
||||||
private async makeExpress() {
|
private async makeExpress(rateLimiter : SomeOf<RateLimiterAbstract> = new RateLimiterMemory({ points: 6, duration: 3 })) {
|
||||||
if (this.httpServer != null || this.express != null) {
|
if (this.httpServer != null || this.express != null) {
|
||||||
getLogger('Admin#startWebserver').warn("Webserver is already running")
|
getLogger('Admin#startWebserver').warn("Webserver is already running")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
this.express = express()
|
this.express = express()
|
||||||
|
|
||||||
const distFolder = "../../../../dist"
|
const distFolder = "../../../../dist"
|
||||||
|
|
||||||
this.express.get('*.*', (req, res) => {
|
this.express.get('*.*', (req, res) => {
|
||||||
//console.log('*.*', req.path);
|
rateLimiter.consume(req.ip)
|
||||||
try{
|
.then(_ => {
|
||||||
const filepath = Path.join(__dirname, distFolder, 'browser', decodeURIComponent(req.path))
|
const filepath = Path.join(__dirname, distFolder, 'browser', decodeURIComponent(req.path))
|
||||||
if(!existsSync(filepath)){
|
if(!existsSync(filepath)){
|
||||||
throw new Error("Bad file access: "+filepath)
|
getLogger('Admin#startWebserver#serveFile').error(String(new Error("404 BAD REQUEST "+filepath+ " FROM "+req.ip)))
|
||||||
|
res.send("404 Not found")
|
||||||
|
res.status(404)
|
||||||
|
return
|
||||||
}
|
}
|
||||||
res.sendFile(filepath)
|
res.sendFile(filepath)
|
||||||
res.status(200)
|
res.status(200)
|
||||||
}catch(e){
|
|
||||||
getLogger('Admin#startWebserver#serveFile').error(String(e))
|
|
||||||
res.send("404 NOT FOUND")
|
|
||||||
res.status(404)
|
|
||||||
}
|
|
||||||
})
|
})
|
||||||
|
.catch(_ => {
|
||||||
|
getLogger('Admin#startWebserver#serveFile').error(String(new Error("429 BAD REQUEST "+req.path+" FROM "+req.ip)))
|
||||||
|
res.send('429 Too many requests')
|
||||||
|
res.status(429)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
return this.express
|
return this.express
|
||||||
}
|
}
|
||||||
|
|
||||||
attachAngularSSR = async (express : express.Application) => {
|
attachAngularSSR = async (express : express.Application, rateLimiter : SomeOf<RateLimiterAbstract> = new RateLimiterMemory({ points: 6, duration: 3 })) => {
|
||||||
const distFolder = "../../../../dist"
|
const distFolder = "../../../../dist"
|
||||||
const ngExpressServer = Path.join(__dirname, distFolder, 'server.js')
|
const ngExpressServer = Path.join(__dirname, distFolder, 'server.js')
|
||||||
let port: number = this.config.getConfig().httpPort
|
let port: number = this.config.getConfig().httpPort
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const req = require(distFolder + "/server.js")
|
const req = require(distFolder + "/server.js")
|
||||||
await req.attachExpress(express, './dist', getLogger('angularSSR#'))
|
await req.attachExpress(express, './dist', getLogger('angularSSR#'), rateLimiter)
|
||||||
getLogger('Admin#startWebserver').debug('Frontend from ' + ngExpressServer + " loaded")
|
getLogger('Admin#startWebserver').debug('Frontend from ' + ngExpressServer + " loaded")
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
getLogger('Admin#startWebserver').error(e)
|
getLogger('Admin#startWebserver').error(e)
|
||||||
|
|||||||
@@ -30,7 +30,13 @@ implements FrontworkComponent<CharacterManagerIfc, RPCInterface>, ICharacterMana
|
|||||||
this.getHeadCount
|
this.getHeadCount
|
||||||
]
|
]
|
||||||
|
|
||||||
RPCFeatures = () => []
|
RPCFeatures = () => [{
|
||||||
|
name: 'manageCharacter' as 'manageCharacter',
|
||||||
|
RPCs: [
|
||||||
|
this.updateCharacter
|
||||||
|
]
|
||||||
|
}]
|
||||||
|
|
||||||
|
|
||||||
getTableDefinitions = (): TableDefiniton[] => [
|
getTableDefinitions = (): TableDefiniton[] => [
|
||||||
{
|
{
|
||||||
@@ -66,6 +72,22 @@ implements FrontworkComponent<CharacterManagerIfc, RPCInterface>, ICharacterMana
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
updateCharacter = async (character: Character) : Promise<Character> => {
|
||||||
|
await this.admin
|
||||||
|
.knex('characters')
|
||||||
|
.update(<Character>{
|
||||||
|
race: character.race,
|
||||||
|
specid: character.specid,
|
||||||
|
charactername: character.charactername.toLowerCase(),
|
||||||
|
userid: character.userid
|
||||||
|
})
|
||||||
|
.where({
|
||||||
|
id: character.id
|
||||||
|
})
|
||||||
|
|
||||||
|
return await this.getCharacterByName(character.charactername) as Character
|
||||||
|
}
|
||||||
|
|
||||||
createCharacter = async (userToken: string, character : Character) : Promise<Character> => {
|
createCharacter = async (userToken: string, character : Character) : Promise<Character> => {
|
||||||
try{
|
try{
|
||||||
character.charactername = character.charactername.toLowerCase()
|
character.charactername = character.charactername.toLowerCase()
|
||||||
|
|||||||
@@ -10,4 +10,6 @@ export class ICharacterManager{
|
|||||||
getCharactersOfUser: (username: string) => Promise<(Character & Spec)[]>
|
getCharactersOfUser: (username: string) => Promise<(Character & Spec)[]>
|
||||||
getUserOfCharacter: (character:Character) => Promise<User>
|
getUserOfCharacter: (character:Character) => Promise<User>
|
||||||
getHeadCount: (clazz: Class) => Promise<number>
|
getHeadCount: (clazz: Class) => Promise<number>
|
||||||
|
updateCharacter: (character: Character) => Promise<Character>
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -14,5 +14,7 @@ export type CharacterManagerIfc = {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export type CharacterManagerFeatureIfc = {
|
export type CharacterManagerFeatureIfc = {
|
||||||
|
manageCharacter: {
|
||||||
|
updateCharacter: ICharacterManager['updateCharacter']
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -15,4 +15,7 @@ export class IItemManager{
|
|||||||
wipeCurrencyAndItems: () => Promise<void>
|
wipeCurrencyAndItems: () => Promise<void>
|
||||||
decayTokens: (tier: Tiers, amount?:number) => Promise<void>
|
decayTokens: (tier: Tiers, amount?:number) => Promise<void>
|
||||||
decayTokensOfCharacter: (tier: Tiers, character:Character, amount?:number) => Promise<void>
|
decayTokensOfCharacter: (tier: Tiers, character:Character, amount?:number) => Promise<void>
|
||||||
|
|
||||||
|
increaseReserve: (token: Character & SRToken & Item, raidid?:number) => Promise<void>
|
||||||
|
decreaseReserve: (token: Character & SRToken & Item, raidid?:number) => Promise<void>
|
||||||
}
|
}
|
||||||
@@ -62,6 +62,12 @@ export class ItemManager
|
|||||||
RPCs: () => [
|
RPCs: () => [
|
||||||
this.decayTokensOfCharacter
|
this.decayTokensOfCharacter
|
||||||
]
|
]
|
||||||
|
}, {
|
||||||
|
name: 'changeReserve' as 'changeReserve',
|
||||||
|
RPCs: () => [
|
||||||
|
this.decreaseReserve,
|
||||||
|
this.increaseReserve
|
||||||
|
]
|
||||||
}]
|
}]
|
||||||
|
|
||||||
notifyRaid = async (raid: Raid | { id: number }) => {
|
notifyRaid = async (raid: Raid | { id: number }) => {
|
||||||
@@ -253,7 +259,7 @@ export class ItemManager
|
|||||||
itemname: item.itemname
|
itemname: item.itemname
|
||||||
})
|
})
|
||||||
} else {
|
} else {
|
||||||
getLogger('ItemManager').debug('new reserve')
|
//getLogger('ItemManager').debug('new reserve')
|
||||||
await this.admin
|
await this.admin
|
||||||
.knex(item.tier + 'tokens')
|
.knex(item.tier + 'tokens')
|
||||||
.transacting(tx)
|
.transacting(tx)
|
||||||
@@ -374,7 +380,7 @@ export class ItemManager
|
|||||||
}
|
}
|
||||||
|
|
||||||
decayTokens = async (tier: Tiers, amount = 1) => {
|
decayTokens = async (tier: Tiers, amount = 1) => {
|
||||||
getLogger('ItemManager#decayTokens').debug(tier)
|
//getLogger('ItemManager#decayTokens').debug(tier)
|
||||||
|
|
||||||
await this.admin
|
await this.admin
|
||||||
.knex(tier + 'tokens')
|
.knex(tier + 'tokens')
|
||||||
@@ -387,7 +393,7 @@ export class ItemManager
|
|||||||
}
|
}
|
||||||
|
|
||||||
decayTokensOfCharacter = async (tier: Tiers, character:Character) => {
|
decayTokensOfCharacter = async (tier: Tiers, character:Character) => {
|
||||||
getLogger('ItemManager#decayTokensOfCharacter').debug(character, tier)
|
//getLogger('ItemManager#decayTokensOfCharacter').debug(character, tier)
|
||||||
await this.admin
|
await this.admin
|
||||||
.knex(tier + 'tokens')
|
.knex(tier + 'tokens')
|
||||||
.where({
|
.where({
|
||||||
@@ -427,6 +433,35 @@ export class ItemManager
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
increaseReserve = async (token: Character & SRToken & Item, raidid?:number) : Promise<void> => {
|
||||||
|
await this.admin
|
||||||
|
.knex(token.tier+"tokens")
|
||||||
|
.where({
|
||||||
|
characterid: token.characterid,
|
||||||
|
itemname: token.itemname
|
||||||
|
}).update({
|
||||||
|
level: token.level+1
|
||||||
|
})
|
||||||
|
|
||||||
|
if(raidid)
|
||||||
|
this.raidManager.notifyRaid({id: raidid})
|
||||||
|
}
|
||||||
|
|
||||||
|
decreaseReserve = async (token: Character & SRToken & Item, raidid?:number) : Promise<void> => {
|
||||||
|
await this.admin
|
||||||
|
.knex(token.tier+"tokens")
|
||||||
|
.where({
|
||||||
|
characterid: token.characterid,
|
||||||
|
itemname: token.itemname
|
||||||
|
}).update({
|
||||||
|
level: Math.max(1, token.level-1)
|
||||||
|
})
|
||||||
|
|
||||||
|
if(raidid)
|
||||||
|
this.raidManager.notifyRaid({id: raidid})
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function toStats(obj:any){
|
function toStats(obj:any){
|
||||||
|
|||||||
@@ -23,4 +23,8 @@ export type ItemManagerFeatureIfc = {
|
|||||||
decay: {
|
decay: {
|
||||||
decayTokensOfCharacter: IItemManager['decayTokensOfCharacter']
|
decayTokensOfCharacter: IItemManager['decayTokensOfCharacter']
|
||||||
}
|
}
|
||||||
|
changeReserve: {
|
||||||
|
increaseReserve: IItemManager['increaseReserve']
|
||||||
|
decreaseReserve: IItemManager['decreaseReserve']
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -16,4 +16,5 @@ export class IRaidManager{
|
|||||||
startRaid: (raid:Raid) => Promise<RaidData>
|
startRaid: (raid:Raid) => Promise<RaidData>
|
||||||
adminUnsign: (character:Character, raid:Raid) => Promise<any>
|
adminUnsign: (character:Character, raid:Raid) => Promise<any>
|
||||||
cancelRaid: (raid: Raid) => Promise<void>
|
cancelRaid: (raid: Raid) => Promise<void>
|
||||||
|
notifyRaid : (raid: Raid | { id: number }) => Promise<void>
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -13,6 +13,8 @@ import { ItemManager } from "../Item/ItemManager";
|
|||||||
import { IPubSub } from "../PubSub/Interface";
|
import { IPubSub } from "../PubSub/Interface";
|
||||||
import { getLogger } from "log4js";
|
import { getLogger } from "log4js";
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@Injectable(IRaidManager)
|
@Injectable(IRaidManager)
|
||||||
export class RaidManager
|
export class RaidManager
|
||||||
implements FrontworkComponent<RaidManagerIfc, RaidManagerFeatureIfc>, IRaidManager {
|
implements FrontworkComponent<RaidManagerIfc, RaidManagerFeatureIfc>, IRaidManager {
|
||||||
@@ -27,7 +29,7 @@ export class RaidManager
|
|||||||
@Inject(ICharacterManager)
|
@Inject(ICharacterManager)
|
||||||
private characterManager: ICharacterManager
|
private characterManager: ICharacterManager
|
||||||
|
|
||||||
@Inject(ItemManager)
|
@Inject(IItemManager)
|
||||||
private itemManager: IItemManager
|
private itemManager: IItemManager
|
||||||
|
|
||||||
@Inject(IPubSub)
|
@Inject(IPubSub)
|
||||||
@@ -189,8 +191,10 @@ export class RaidManager
|
|||||||
await this.userManager.incrementCurrency(usr, raid.tier, 1)
|
await this.userManager.incrementCurrency(usr, raid.tier, 1)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const THREE_DAYS = 259200000;
|
||||||
|
|
||||||
await Promise.all([
|
await Promise.all([
|
||||||
...archived.participants.bench.map(giveCurrency),
|
...archived.participants.bench.filter(signup => Number(signup.timestamp) < (Number(archived.start)-THREE_DAYS)).map(giveCurrency),
|
||||||
...Object.values(archived.participants).flat().map((b: Signup & Character & Spec) => giveCurrency(b))
|
...Object.values(archived.participants).flat().map((b: Signup & Character & Spec) => giveCurrency(b))
|
||||||
])
|
])
|
||||||
|
|
||||||
@@ -307,6 +311,17 @@ export class RaidManager
|
|||||||
.where('id', '=', raid.id)
|
.where('id', '=', raid.id)
|
||||||
.first()
|
.first()
|
||||||
|
|
||||||
|
if(!raidInDb){
|
||||||
|
return {
|
||||||
|
title : "Not found",
|
||||||
|
description : "Not found",
|
||||||
|
start: "0",
|
||||||
|
size: 0,
|
||||||
|
tier: null,
|
||||||
|
... raiddata
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
const characterData: (Signup & Character & Spec)[] = await this.admin
|
const characterData: (Signup & Character & Spec)[] = await this.admin
|
||||||
.knex('signups as s')
|
.knex('signups as s')
|
||||||
.select('s.id as id', 'charactername', 'rank', 'class', 'specid', 'specname', 'race', 'userid', 'benched', 'late', 'raidid', 'characterid', 'specid', 'memo', 'timestamp', 'absent')
|
.select('s.id as id', 'charactername', 'rank', 'class', 'specid', 'specname', 'race', 'userid', 'benched', 'late', 'raidid', 'characterid', 'specid', 'memo', 'timestamp', 'absent')
|
||||||
|
|||||||
@@ -132,10 +132,12 @@ export class UserManager
|
|||||||
]
|
]
|
||||||
|
|
||||||
initialize = async () => {
|
initialize = async () => {
|
||||||
this.exporters = [this, this.guild, this.item, this.raid, this.character]
|
this.exporters = [this.guild, this.item, this.raid, this.character]
|
||||||
//set up permissions
|
//set up permissions
|
||||||
getLogger('UserManager#initialize').debug('setting up permissions')
|
getLogger('UserManager#initialize').debug('setting up permissions')
|
||||||
|
|
||||||
|
console.log(this.character.RPCFeatures())
|
||||||
|
|
||||||
await Promise.all(
|
await Promise.all(
|
||||||
[this, ...this.exporters].flatMap(exp => exp.RPCFeatures().map(async (feature) => {
|
[this, ...this.exporters].flatMap(exp => exp.RPCFeatures().map(async (feature) => {
|
||||||
try {
|
try {
|
||||||
|
|||||||
+133
-1
@@ -423,6 +423,138 @@ export const ZGMounts = [
|
|||||||
"Primal Hakkari Idol"
|
"Primal Hakkari Idol"
|
||||||
]
|
]
|
||||||
|
|
||||||
|
export const Naxx = [
|
||||||
|
"Band of Unanswered Prayers",
|
||||||
|
"Wristguards of Vengeance",
|
||||||
|
"Gem of Nerubis",
|
||||||
|
"Touch of Frost",
|
||||||
|
"Cryptfiend Silk Cloak",
|
||||||
|
"Claymore of Unholy Might",
|
||||||
|
"Digested Hand of Power",
|
||||||
|
"Gluth's Missing Collar",
|
||||||
|
"Death's Bargain",
|
||||||
|
"Rime Covered Mantle",
|
||||||
|
"Polar Helmet",
|
||||||
|
"Glacial Headdress",
|
||||||
|
"Sadist's Collar",
|
||||||
|
"The Soul Harvester's Bindings",
|
||||||
|
"Boots of Displacement",
|
||||||
|
"Widow's Remorse",
|
||||||
|
"Malice Stone Pendant",
|
||||||
|
"The Widow's Embrace",
|
||||||
|
"Icebane Pauldrons",
|
||||||
|
"Polar Shoulder Pads",
|
||||||
|
"Midnight Haze",
|
||||||
|
"Icy Scale Spaulders",
|
||||||
|
"Toxin Injector",
|
||||||
|
"Glacial Mantle",
|
||||||
|
"The End of Dreams",
|
||||||
|
"Icebane Helmet",
|
||||||
|
"Legplates of Carnage",
|
||||||
|
"Icy Scale Coif",
|
||||||
|
"Necklace of Necropsy",
|
||||||
|
"Preceptor's Hat",
|
||||||
|
"Girdle of the Mentor",
|
||||||
|
"Wand of the Whispering Dead",
|
||||||
|
"Idol of Longevity",
|
||||||
|
"Veil of Eclipse",
|
||||||
|
"Signet of the Fallen Defender",
|
||||||
|
"Iblis, Blade of the Fallen Seraph",
|
||||||
|
"Doomfinger", "Nerubian Slavemaker",
|
||||||
|
"Soulseeker",
|
||||||
|
"Hammer of the Twisting Nether",
|
||||||
|
"The Hungering Cold",
|
||||||
|
"Stormrage's Talisman of Seething",
|
||||||
|
"Gressil, Dawn of Ruin",
|
||||||
|
"Kingsfall",
|
||||||
|
"Might of Menethil",
|
||||||
|
"Gem of Trapped Innocents",
|
||||||
|
"The Phylactery of Kel'Thuzad",
|
||||||
|
"Shield of Condemnation",
|
||||||
|
"Brimstone Staff",
|
||||||
|
"The Eye of Nerub",
|
||||||
|
"Band of Unnatural Forces",
|
||||||
|
"Loatheb's Reflection",
|
||||||
|
"Ring of Spiritual Fervor",
|
||||||
|
"Maexxna's Fang",
|
||||||
|
"Crystal Webbed Robe",
|
||||||
|
"Kiss of the Spider",
|
||||||
|
"Wraith Blade",
|
||||||
|
"Pendant of Forgotten Names",
|
||||||
|
"Cloak of the Scourge",
|
||||||
|
"Hatchet of Sundered Bone",
|
||||||
|
"Band of the Inevitable",
|
||||||
|
"Noth's Frigid Heart",
|
||||||
|
"Totem of Flowing Water",
|
||||||
|
"Libram of Light",
|
||||||
|
"Hailstone Band",
|
||||||
|
"The Plague Bearer",
|
||||||
|
"Cloak of Suturing",
|
||||||
|
"Severance",
|
||||||
|
"Band of Reanimation",
|
||||||
|
"Wand of Fates",
|
||||||
|
"The Face of Death",
|
||||||
|
"Claw of the Frost Wyrm",
|
||||||
|
"Fortitude of the Scourge",
|
||||||
|
"Eye of the Dead",
|
||||||
|
"Sapphiron's Right Eye",
|
||||||
|
"The Restrained Essence of Sapphiron",
|
||||||
|
"Shroud of Dominion",
|
||||||
|
"Slayer's Crest",
|
||||||
|
"Resilience of the Scourge",
|
||||||
|
"Cloak of the Necropolis",
|
||||||
|
"Sapphiron's Left Eye",
|
||||||
|
"Power of the Scourge",
|
||||||
|
"Might of the Scourge",
|
||||||
|
"Spire of Twilight",
|
||||||
|
"Eye of Diminution",
|
||||||
|
"Leggings of Polarity",
|
||||||
|
"Plated Abomination Ribcage",
|
||||||
|
"The Castigator",
|
||||||
|
"Leggings of Apocalypse",
|
||||||
|
"Maul of the Redeemed Crusader",
|
||||||
|
"Seal of the Damned",
|
||||||
|
"Soulstring",
|
||||||
|
"Warmth of Forgiveness",
|
||||||
|
"Corrupted Ashbringer",
|
||||||
|
"Pauldrons of Elemental Fury",
|
||||||
|
"Girdle of Elemental Fury",
|
||||||
|
"Leggings of Elemental Fury",
|
||||||
|
"Belt of the Grand Crusader",
|
||||||
|
"Spaulders of the Grand Crusader",
|
||||||
|
"Ring of the Eternal Flame",
|
||||||
|
"Stygian Buckler",
|
||||||
|
"Misplaced Servo Arm",
|
||||||
|
"Leggings of the Grand Crusader",
|
||||||
|
"Harbinger of Doom",
|
||||||
|
"Necro-Knight's Garb",
|
||||||
|
"Ghoul Skin Tunic",
|
||||||
|
"Desecrated Circlet",
|
||||||
|
"Desecrated Robe",
|
||||||
|
"Desecrated Shoulderpads",
|
||||||
|
"Desecrated Sandals",
|
||||||
|
"Desecrated Bindings",
|
||||||
|
"Desecrated Wristguards",
|
||||||
|
"Desecrated Bracers",
|
||||||
|
"Desecrated Spaulders",
|
||||||
|
"Desecrated Gloves",
|
||||||
|
"Desecrated Belt",
|
||||||
|
"Desecrated Headpiece",
|
||||||
|
"Desecrated Boots",
|
||||||
|
"Desecrated Pauldrons",
|
||||||
|
"Desecrated Tunic",
|
||||||
|
"Desecrated Leggings",
|
||||||
|
"Desecrated Helmet",
|
||||||
|
"Desecrated Legplates",
|
||||||
|
"Desecrated Handguards",
|
||||||
|
"Desecrated Sabatons",
|
||||||
|
"Desecrated Girdle",
|
||||||
|
"Desecrated Legguards",
|
||||||
|
"Desecrated Gauntlets",
|
||||||
|
"Desecrated Waistguard",
|
||||||
|
"Desecrated Breastplate"
|
||||||
|
]
|
||||||
|
|
||||||
export type AllItems = {
|
export type AllItems = {
|
||||||
[tier in Tiers]: string[]
|
[tier in Tiers]: string[]
|
||||||
}
|
}
|
||||||
@@ -433,5 +565,5 @@ export const allItems: AllItems = {
|
|||||||
ZG: ZGMounts,
|
ZG: ZGMounts,
|
||||||
AQ20: [],
|
AQ20: [],
|
||||||
AQ40: AQ40,
|
AQ40: AQ40,
|
||||||
Naxx: []
|
Naxx: Naxx
|
||||||
}
|
}
|
||||||
Generated
+121
-32
@@ -2730,18 +2730,18 @@
|
|||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
"@types/socket.io": {
|
"@types/socket.io": {
|
||||||
"version": "2.1.10",
|
"version": "2.1.11",
|
||||||
"resolved": "https://registry.npmjs.org/@types/socket.io/-/socket.io-2.1.10.tgz",
|
"resolved": "https://registry.npmjs.org/@types/socket.io/-/socket.io-2.1.11.tgz",
|
||||||
"integrity": "sha512-1fQMaDU/x2LPljEI/QI5IKl8sBYHM/zv32YYKvNrVEor7/1+MLqMqmWt8Bb8Vpf+PlIPBiTTC0BnrRx7ju3xOw==",
|
"integrity": "sha512-bVprmqPhJMLb9ZCm8g0Xy8kwBFRbnanOWSxzWkDkkIwxTvud5tKMfAJymXX6LQbizUKCS1yima7JM4BeLqjNqA==",
|
||||||
"requires": {
|
"requires": {
|
||||||
"@types/engine.io": "*",
|
"@types/engine.io": "*",
|
||||||
"@types/node": "*"
|
"@types/node": "*"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"@types/socket.io-client": {
|
"@types/socket.io-client": {
|
||||||
"version": "1.4.33",
|
"version": "1.4.34",
|
||||||
"resolved": "https://registry.npmjs.org/@types/socket.io-client/-/socket.io-client-1.4.33.tgz",
|
"resolved": "https://registry.npmjs.org/@types/socket.io-client/-/socket.io-client-1.4.34.tgz",
|
||||||
"integrity": "sha512-m4LnxkljsI9fMsjwpW5QhRpMixo2BeeLpFmg0AE+sS4H1pzAd/cs/ftTiL60FLZgfFa8PFRPx5KsHu8O0bADKQ=="
|
"integrity": "sha512-Lzia5OTQFJZJ5R4HsEEldywiiqT9+W2rDbyHJiiTGqOcju89sCsQ8aUXDljY6Ls33wKZZGC0bfMhr/VpOyjtXg=="
|
||||||
},
|
},
|
||||||
"@types/source-list-map": {
|
"@types/source-list-map": {
|
||||||
"version": "0.1.2",
|
"version": "0.1.2",
|
||||||
@@ -3766,7 +3766,8 @@
|
|||||||
"base64-arraybuffer": {
|
"base64-arraybuffer": {
|
||||||
"version": "0.1.5",
|
"version": "0.1.5",
|
||||||
"resolved": "https://registry.npmjs.org/base64-arraybuffer/-/base64-arraybuffer-0.1.5.tgz",
|
"resolved": "https://registry.npmjs.org/base64-arraybuffer/-/base64-arraybuffer-0.1.5.tgz",
|
||||||
"integrity": "sha1-c5JncZI7Whl0etZmqlzUv5xunOg="
|
"integrity": "sha1-c5JncZI7Whl0etZmqlzUv5xunOg=",
|
||||||
|
"dev": true
|
||||||
},
|
},
|
||||||
"base64-js": {
|
"base64-js": {
|
||||||
"version": "1.3.1",
|
"version": "1.3.1",
|
||||||
@@ -15789,9 +15790,9 @@
|
|||||||
"integrity": "sha512-ZYzRkETgBrdEGzL5JSKimvjI2CX7ioyZCkX2BpcfyjqI+079W0wHAyj5W4rIZMcDSOHgLZtgz1IdDi/vU77KEQ=="
|
"integrity": "sha512-ZYzRkETgBrdEGzL5JSKimvjI2CX7ioyZCkX2BpcfyjqI+079W0wHAyj5W4rIZMcDSOHgLZtgz1IdDi/vU77KEQ=="
|
||||||
},
|
},
|
||||||
"rpclibrary": {
|
"rpclibrary": {
|
||||||
"version": "2.0.1",
|
"version": "2.3.1",
|
||||||
"resolved": "https://registry.npmjs.org/rpclibrary/-/rpclibrary-2.0.1.tgz",
|
"resolved": "https://registry.npmjs.org/rpclibrary/-/rpclibrary-2.3.1.tgz",
|
||||||
"integrity": "sha512-phdU0TkrnNVXdFa5PKkbWvn+MxocowvqalEUG1jfpkc1CoQkJ9AXa4OXSEu5r2a2IFhVauYva/qXv1em5yrHSg==",
|
"integrity": "sha512-y6F6gYxm9joJcnyxNeEoUSAbYGsaogcEKb1bxVB97+HcT4J6q9yw2fGnWS1FeeAUbTLUwASdlqJvRLPLiMPlcQ==",
|
||||||
"requires": {
|
"requires": {
|
||||||
"@types/socket.io": "^2.1.8",
|
"@types/socket.io": "^2.1.8",
|
||||||
"@types/socket.io-client": "^1.4.33",
|
"@types/socket.io-client": "^1.4.33",
|
||||||
@@ -15806,6 +15807,11 @@
|
|||||||
"resolved": "https://registry.npmjs.org/arraybuffer.slice/-/arraybuffer.slice-0.0.7.tgz",
|
"resolved": "https://registry.npmjs.org/arraybuffer.slice/-/arraybuffer.slice-0.0.7.tgz",
|
||||||
"integrity": "sha512-wGUIVQXuehL5TCqQun8OW81jGzAWycqzFF8lFp+GOM5BXLYj3bKNsYC4daB7n6XjCqxQA/qgTJ+8ANR3acjrog=="
|
"integrity": "sha512-wGUIVQXuehL5TCqQun8OW81jGzAWycqzFF8lFp+GOM5BXLYj3bKNsYC4daB7n6XjCqxQA/qgTJ+8ANR3acjrog=="
|
||||||
},
|
},
|
||||||
|
"base64-arraybuffer": {
|
||||||
|
"version": "0.1.4",
|
||||||
|
"resolved": "https://registry.npmjs.org/base64-arraybuffer/-/base64-arraybuffer-0.1.4.tgz",
|
||||||
|
"integrity": "sha1-mBjHngWbE1X5fgQooBfIOOkLqBI="
|
||||||
|
},
|
||||||
"base64id": {
|
"base64id": {
|
||||||
"version": "2.0.0",
|
"version": "2.0.0",
|
||||||
"resolved": "https://registry.npmjs.org/base64id/-/base64id-2.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/base64id/-/base64id-2.0.0.tgz",
|
||||||
@@ -15840,18 +15846,18 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"engine.io-client": {
|
"engine.io-client": {
|
||||||
"version": "3.4.3",
|
"version": "3.4.4",
|
||||||
"resolved": "https://registry.npmjs.org/engine.io-client/-/engine.io-client-3.4.3.tgz",
|
"resolved": "https://registry.npmjs.org/engine.io-client/-/engine.io-client-3.4.4.tgz",
|
||||||
"integrity": "sha512-0NGY+9hioejTEJCaSJZfWZLk4FPI9dN+1H1C4+wj2iuFba47UgZbJzfWs4aNFajnX/qAaYKbe2lLTfEEWzCmcw==",
|
"integrity": "sha512-iU4CRr38Fecj8HoZEnFtm2EiKGbYZcPn3cHxqNGl/tmdWRf60KhK+9vE0JeSjgnlS/0oynEfLgKbT9ALpim0sQ==",
|
||||||
"requires": {
|
"requires": {
|
||||||
"component-emitter": "~1.3.0",
|
"component-emitter": "~1.3.0",
|
||||||
"component-inherit": "0.0.3",
|
"component-inherit": "0.0.3",
|
||||||
"debug": "~4.1.0",
|
"debug": "~3.1.0",
|
||||||
"engine.io-parser": "~2.2.0",
|
"engine.io-parser": "~2.2.0",
|
||||||
"has-cors": "1.1.0",
|
"has-cors": "1.1.0",
|
||||||
"indexof": "0.0.1",
|
"indexof": "0.0.1",
|
||||||
"parseqs": "0.0.5",
|
"parseqs": "0.0.6",
|
||||||
"parseuri": "0.0.5",
|
"parseuri": "0.0.6",
|
||||||
"ws": "~6.1.0",
|
"ws": "~6.1.0",
|
||||||
"xmlhttprequest-ssl": "~1.5.4",
|
"xmlhttprequest-ssl": "~1.5.4",
|
||||||
"yeast": "0.1.2"
|
"yeast": "0.1.2"
|
||||||
@@ -15862,6 +15868,24 @@
|
|||||||
"resolved": "https://registry.npmjs.org/component-emitter/-/component-emitter-1.3.0.tgz",
|
"resolved": "https://registry.npmjs.org/component-emitter/-/component-emitter-1.3.0.tgz",
|
||||||
"integrity": "sha512-Rd3se6QB+sO1TwqZjscQrurpEPIfO0/yYnSin6Q/rD3mOutHvUrCAhJub3r90uNb+SESBuE0QYoB90YdfatsRg=="
|
"integrity": "sha512-Rd3se6QB+sO1TwqZjscQrurpEPIfO0/yYnSin6Q/rD3mOutHvUrCAhJub3r90uNb+SESBuE0QYoB90YdfatsRg=="
|
||||||
},
|
},
|
||||||
|
"debug": {
|
||||||
|
"version": "3.1.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz",
|
||||||
|
"integrity": "sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==",
|
||||||
|
"requires": {
|
||||||
|
"ms": "2.0.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"parseqs": {
|
||||||
|
"version": "0.0.6",
|
||||||
|
"resolved": "https://registry.npmjs.org/parseqs/-/parseqs-0.0.6.tgz",
|
||||||
|
"integrity": "sha512-jeAGzMDbfSHHA091hr0r31eYfTig+29g3GKKE/PPbEQ65X0lmMwlEoqmhzu0iztID5uJpZsFlUPDP8ThPL7M8w=="
|
||||||
|
},
|
||||||
|
"parseuri": {
|
||||||
|
"version": "0.0.6",
|
||||||
|
"resolved": "https://registry.npmjs.org/parseuri/-/parseuri-0.0.6.tgz",
|
||||||
|
"integrity": "sha512-AUjen8sAkGgao7UyCX6Ahv0gIK2fABKmYjvP4xmy5JaKvcbTRueIqIPHLAfq30xJddqSE033IOMUSOMCcK3Sow=="
|
||||||
|
},
|
||||||
"ws": {
|
"ws": {
|
||||||
"version": "6.1.4",
|
"version": "6.1.4",
|
||||||
"resolved": "https://registry.npmjs.org/ws/-/ws-6.1.4.tgz",
|
"resolved": "https://registry.npmjs.org/ws/-/ws-6.1.4.tgz",
|
||||||
@@ -15873,13 +15897,13 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"engine.io-parser": {
|
"engine.io-parser": {
|
||||||
"version": "2.2.0",
|
"version": "2.2.1",
|
||||||
"resolved": "https://registry.npmjs.org/engine.io-parser/-/engine.io-parser-2.2.0.tgz",
|
"resolved": "https://registry.npmjs.org/engine.io-parser/-/engine.io-parser-2.2.1.tgz",
|
||||||
"integrity": "sha512-6I3qD9iUxotsC5HEMuuGsKA0cXerGz+4uGcXQEkfBidgKf0amsjrrtwcbwK/nzpZBxclXlV7gGl9dgWvu4LF6w==",
|
"integrity": "sha512-x+dN/fBH8Ro8TFwJ+rkB2AmuVw9Yu2mockR/p3W8f8YtExwFgDvBDi0GWyb4ZLkpahtDGZgtr3zLovanJghPqg==",
|
||||||
"requires": {
|
"requires": {
|
||||||
"after": "0.8.2",
|
"after": "0.8.2",
|
||||||
"arraybuffer.slice": "~0.0.7",
|
"arraybuffer.slice": "~0.0.7",
|
||||||
"base64-arraybuffer": "0.1.5",
|
"base64-arraybuffer": "0.1.4",
|
||||||
"blob": "0.0.5",
|
"blob": "0.0.5",
|
||||||
"has-binary2": "~1.0.2"
|
"has-binary2": "~1.0.2"
|
||||||
}
|
}
|
||||||
@@ -15905,12 +15929,12 @@
|
|||||||
"socket.io-adapter": "~1.1.0",
|
"socket.io-adapter": "~1.1.0",
|
||||||
"socket.io-client": "2.3.0",
|
"socket.io-client": "2.3.0",
|
||||||
"socket.io-parser": "~3.4.0"
|
"socket.io-parser": "~3.4.0"
|
||||||
}
|
|
||||||
},
|
},
|
||||||
"socket.io-adapter": {
|
"dependencies": {
|
||||||
"version": "1.1.2",
|
"base64-arraybuffer": {
|
||||||
"resolved": "https://registry.npmjs.org/socket.io-adapter/-/socket.io-adapter-1.1.2.tgz",
|
"version": "0.1.5",
|
||||||
"integrity": "sha512-WzZRUj1kUjrTIrUKpZLEzFZ1OLj5FwLlAFQs9kuZJzJi5DKdU7FsWc36SNmA8iDOtwBQyT8FkrriRM8vXLYz8g=="
|
"resolved": "https://registry.npmjs.org/base64-arraybuffer/-/base64-arraybuffer-0.1.5.tgz",
|
||||||
|
"integrity": "sha1-c5JncZI7Whl0etZmqlzUv5xunOg="
|
||||||
},
|
},
|
||||||
"socket.io-client": {
|
"socket.io-client": {
|
||||||
"version": "2.3.0",
|
"version": "2.3.0",
|
||||||
@@ -15934,15 +15958,20 @@
|
|||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"socket.io-parser": {
|
"socket.io-parser": {
|
||||||
"version": "3.3.0",
|
"version": "3.3.1",
|
||||||
"resolved": "https://registry.npmjs.org/socket.io-parser/-/socket.io-parser-3.3.0.tgz",
|
"resolved": "https://registry.npmjs.org/socket.io-parser/-/socket.io-parser-3.3.1.tgz",
|
||||||
"integrity": "sha512-hczmV6bDgdaEbVqhAeVMM/jfUfzuEZHsQg6eOmLgJht6G3mPKMxYm75w2+qhAQZ+4X+1+ATZ+QFKeOZD5riHng==",
|
"integrity": "sha512-1QLvVAe8dTz+mKmZ07Swxt+LAo4Y1ff50rlyoEx00TQmDFVQYPfcqGvIDJLGaBdhdNCecXtyKpD+EgKGcmmbuQ==",
|
||||||
"requires": {
|
"requires": {
|
||||||
"component-emitter": "1.2.1",
|
"component-emitter": "~1.3.0",
|
||||||
"debug": "~3.1.0",
|
"debug": "~3.1.0",
|
||||||
"isarray": "2.0.1"
|
"isarray": "2.0.1"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
"component-emitter": {
|
||||||
|
"version": "1.3.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/component-emitter/-/component-emitter-1.3.0.tgz",
|
||||||
|
"integrity": "sha512-Rd3se6QB+sO1TwqZjscQrurpEPIfO0/yYnSin6Q/rD3mOutHvUrCAhJub3r90uNb+SESBuE0QYoB90YdfatsRg=="
|
||||||
|
},
|
||||||
"debug": {
|
"debug": {
|
||||||
"version": "3.1.0",
|
"version": "3.1.0",
|
||||||
"resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz",
|
"resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz",
|
||||||
@@ -15954,6 +15983,66 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"socket.io-adapter": {
|
||||||
|
"version": "1.1.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/socket.io-adapter/-/socket.io-adapter-1.1.2.tgz",
|
||||||
|
"integrity": "sha512-WzZRUj1kUjrTIrUKpZLEzFZ1OLj5FwLlAFQs9kuZJzJi5DKdU7FsWc36SNmA8iDOtwBQyT8FkrriRM8vXLYz8g=="
|
||||||
|
},
|
||||||
|
"socket.io-client": {
|
||||||
|
"version": "2.3.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/socket.io-client/-/socket.io-client-2.3.1.tgz",
|
||||||
|
"integrity": "sha512-YXmXn3pA8abPOY//JtYxou95Ihvzmg8U6kQyolArkIyLd0pgVhrfor/iMsox8cn07WCOOvvuJ6XKegzIucPutQ==",
|
||||||
|
"requires": {
|
||||||
|
"backo2": "1.0.2",
|
||||||
|
"component-bind": "1.0.0",
|
||||||
|
"component-emitter": "~1.3.0",
|
||||||
|
"debug": "~3.1.0",
|
||||||
|
"engine.io-client": "~3.4.0",
|
||||||
|
"has-binary2": "~1.0.2",
|
||||||
|
"indexof": "0.0.1",
|
||||||
|
"parseqs": "0.0.6",
|
||||||
|
"parseuri": "0.0.6",
|
||||||
|
"socket.io-parser": "~3.3.0",
|
||||||
|
"to-array": "0.1.4"
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"component-emitter": {
|
||||||
|
"version": "1.3.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/component-emitter/-/component-emitter-1.3.0.tgz",
|
||||||
|
"integrity": "sha512-Rd3se6QB+sO1TwqZjscQrurpEPIfO0/yYnSin6Q/rD3mOutHvUrCAhJub3r90uNb+SESBuE0QYoB90YdfatsRg=="
|
||||||
|
},
|
||||||
|
"debug": {
|
||||||
|
"version": "3.1.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz",
|
||||||
|
"integrity": "sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==",
|
||||||
|
"requires": {
|
||||||
|
"ms": "2.0.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"parseqs": {
|
||||||
|
"version": "0.0.6",
|
||||||
|
"resolved": "https://registry.npmjs.org/parseqs/-/parseqs-0.0.6.tgz",
|
||||||
|
"integrity": "sha512-jeAGzMDbfSHHA091hr0r31eYfTig+29g3GKKE/PPbEQ65X0lmMwlEoqmhzu0iztID5uJpZsFlUPDP8ThPL7M8w=="
|
||||||
|
},
|
||||||
|
"parseuri": {
|
||||||
|
"version": "0.0.6",
|
||||||
|
"resolved": "https://registry.npmjs.org/parseuri/-/parseuri-0.0.6.tgz",
|
||||||
|
"integrity": "sha512-AUjen8sAkGgao7UyCX6Ahv0gIK2fABKmYjvP4xmy5JaKvcbTRueIqIPHLAfq30xJddqSE033IOMUSOMCcK3Sow=="
|
||||||
|
},
|
||||||
|
"socket.io-parser": {
|
||||||
|
"version": "3.3.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/socket.io-parser/-/socket.io-parser-3.3.1.tgz",
|
||||||
|
"integrity": "sha512-1QLvVAe8dTz+mKmZ07Swxt+LAo4Y1ff50rlyoEx00TQmDFVQYPfcqGvIDJLGaBdhdNCecXtyKpD+EgKGcmmbuQ==",
|
||||||
|
"requires": {
|
||||||
|
"component-emitter": "~1.3.0",
|
||||||
|
"debug": "~3.1.0",
|
||||||
|
"isarray": "2.0.1"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
},
|
},
|
||||||
"socket.io-parser": {
|
"socket.io-parser": {
|
||||||
"version": "3.4.1",
|
"version": "3.4.1",
|
||||||
@@ -15966,9 +16055,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"ws": {
|
"ws": {
|
||||||
"version": "7.3.1",
|
"version": "7.4.0",
|
||||||
"resolved": "https://registry.npmjs.org/ws/-/ws-7.3.1.tgz",
|
"resolved": "https://registry.npmjs.org/ws/-/ws-7.4.0.tgz",
|
||||||
"integrity": "sha512-D3RuNkynyHmEJIpD2qrgVkc9DQ23OrN/moAwZX4L8DfvszsJxpjQuUq3LMx6HoYji9fbIOBY18XWBsAux1ZZUA=="
|
"integrity": "sha512-kyFwXuV/5ymf+IXhS6f0+eAFvydbaBW3zjpT6hUdAh/hbVjTIB5EHBGi0bPoCLSK2wcuz3BrEkB9LrYv1Nm4NQ=="
|
||||||
},
|
},
|
||||||
"xmlhttprequest-ssl": {
|
"xmlhttprequest-ssl": {
|
||||||
"version": "1.5.5",
|
"version": "1.5.5",
|
||||||
|
|||||||
@@ -79,7 +79,7 @@
|
|||||||
"normalize.css": "6.0.0",
|
"normalize.css": "6.0.0",
|
||||||
"pace-js": "1.0.2",
|
"pace-js": "1.0.2",
|
||||||
"roboto-fontface": "0.8.0",
|
"roboto-fontface": "0.8.0",
|
||||||
"rpclibrary": "^2.0.1",
|
"rpclibrary": "^2.3.1",
|
||||||
"rxjs": "6.5.2",
|
"rxjs": "6.5.2",
|
||||||
"rxjs-compat": "6.3.0",
|
"rxjs-compat": "6.3.0",
|
||||||
"socicon": "3.0.5",
|
"socicon": "3.0.5",
|
||||||
|
|||||||
+20
-11
@@ -15,15 +15,21 @@ global['alert'] = console.log
|
|||||||
global['XMLHttpRequest'] = require('xmlhttprequest').XMLHttpRequest;
|
global['XMLHttpRequest'] = require('xmlhttprequest').XMLHttpRequest;
|
||||||
global['fetch'] = fetch.default;
|
global['fetch'] = fetch.default;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Function to attach this SSR application to an express server. Exported as function due to webpack inconsistencies.
|
||||||
export async function attachExpress(app, staticDir = "./dist", logger = console) {
|
*
|
||||||
|
* @param app express.Application to run on
|
||||||
|
* @param staticDir Where the static website content is (i.e. ./dist)
|
||||||
|
* @param logger A loggerservice or console
|
||||||
|
* @param rateLimiter a rate-limiter-flexible instance
|
||||||
|
*/
|
||||||
|
export async function attachExpress(app, staticDir, logger, rateLimiter) {
|
||||||
const STATIC_FOLDER = resolve(process.cwd(), staticDir);
|
const STATIC_FOLDER = resolve(process.cwd(), staticDir);
|
||||||
enableProdMode();
|
enableProdMode();
|
||||||
|
|
||||||
const loggerService = {
|
const loggerService = {
|
||||||
warn: (...args) => logger.error(...args),
|
warn: (...args) => logger.warn(...args),
|
||||||
error: (...args) => logger.warn(...args),
|
error: (...args) => logger.error(...args),
|
||||||
log: (...args) => logger.info(...args),
|
log: (...args) => logger.info(...args),
|
||||||
table: (...args) => logger.info(...args),
|
table: (...args) => logger.info(...args),
|
||||||
collapsed: (msg, type, ...args) => loggerService[type](msg, ...args)
|
collapsed: (msg, type, ...args) => loggerService[type](msg, ...args)
|
||||||
@@ -57,11 +63,14 @@ export async function attachExpress(app, staticDir = "./dist", logger = console)
|
|||||||
);
|
);
|
||||||
|
|
||||||
app.get('*', (req, res) => {
|
app.get('*', (req, res) => {
|
||||||
//console.log('*', req.path);
|
rateLimiter.consume(req.ip, 3)
|
||||||
try{
|
.then(_ => {
|
||||||
res.render(resolve(STATIC_FOLDER, 'browser/index'), { req, res })
|
res.render(resolve(STATIC_FOLDER, 'browser/index'), { req, res })
|
||||||
}catch(e){
|
})
|
||||||
loggerService.error(e)
|
.catch(_ => {
|
||||||
}
|
loggerService.error(String(new Error("429 BAD REQUEST "+req.path+" FROM "+req.ip)))
|
||||||
});
|
res.send("429 Too many requests")
|
||||||
|
res.status(429)
|
||||||
|
})
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -21,12 +21,12 @@ export class RegisterComponent implements OnInit{
|
|||||||
race: "Night Elf"
|
race: "Night Elf"
|
||||||
}
|
}
|
||||||
|
|
||||||
ranks = _Rank.splice(5) //remove admin, gm, officer
|
ranks = ["Trial"] //remove admin, gm, officer
|
||||||
classes = _Class
|
classes = _Class
|
||||||
races = _Race
|
races = _Race
|
||||||
selectedClass : Class = "Warrior"
|
selectedClass : Class = "Warrior"
|
||||||
selectedSpec = specs[this.selectedClass][0]
|
|
||||||
specs = specs[this.selectedClass]
|
specs = specs[this.selectedClass]
|
||||||
|
selectedSpec = specs[this.selectedClass][0]
|
||||||
showApplication = false
|
showApplication = false
|
||||||
submitted = false
|
submitted = false
|
||||||
|
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
<nb-card
|
<nb-card class="col-12 col-xl-9">
|
||||||
class = "col-12 col-xl-9">
|
|
||||||
<nb-card-header style="text-transform: capitalize;">
|
<nb-card-header style="text-transform: capitalize;">
|
||||||
<h4>
|
<h4>
|
||||||
<a *ngIf="link === 'character'" [ngStyle]="{'color': color}" [routerLink]="'/frontcraft/character/'+char.charactername">
|
<a *ngIf="link === 'character'" [ngStyle]="{'color': color}"
|
||||||
|
[routerLink]="'/frontcraft/character/'+char.charactername">
|
||||||
{{char.charactername}}
|
{{char.charactername}}
|
||||||
</a>
|
</a>
|
||||||
</h4>
|
</h4>
|
||||||
@@ -14,10 +14,31 @@ class = "col-12 col-xl-9">
|
|||||||
</nb-card-header>
|
</nb-card-header>
|
||||||
|
|
||||||
<nb-card-body>
|
<nb-card-body>
|
||||||
|
<span *ngIf="!canManage">
|
||||||
<img style="width:20px; height:20px" [src]="'../../../../assets/images/'+char.race.toLowerCase()+'_xs.gif'" />
|
<img style="width:20px; height:20px" [src]="'../../../../assets/images/'+char.race.toLowerCase()+'_xs.gif'" />
|
||||||
{{char.race}}<br />
|
{{char.race}}<br />
|
||||||
<img style="width:20px; height:20px" [src]="'../../../../assets/images/'+char.class.toLowerCase()+'.png'" />
|
<img style="width:20px; height:20px" [src]="'../../../../assets/images/'+char.class.toLowerCase()+'.png'" />
|
||||||
|
|
||||||
{{char.specname}} {{char.class}}<br />
|
{{char.specname}} {{char.class}}<br />
|
||||||
|
</span>
|
||||||
|
<span *ngIf="canManage">
|
||||||
|
<input nbInput [required]="true" name="preMember" [(ngModel)]="char.charactername"><br />
|
||||||
|
<nb-select [(selected)]="char.race" placeholder="Race">
|
||||||
|
<nb-option *ngFor="let race of races" [value]="race">{{race}}</nb-option>
|
||||||
|
</nb-select>
|
||||||
|
<nb-select [(selected)]="char.specname" placeholder="Spec">
|
||||||
|
<nb-option *ngFor="let spec of specs" [value]="spec">{{spec}}</nb-option>
|
||||||
|
</nb-select>
|
||||||
|
<nb-select [(selected)]="char.class" placeholder="Class" (selectedChange)="onSelectClass()">
|
||||||
|
<nb-option *ngFor="let class of classes" [value]="class">{{class}}</nb-option>
|
||||||
|
</nb-select>
|
||||||
|
<button nbButton
|
||||||
|
status="primary"
|
||||||
|
[class.btn-pulse]="submitted"
|
||||||
|
(click)="updateCharacter()">
|
||||||
|
Update
|
||||||
|
</button>
|
||||||
|
</span>
|
||||||
<span *ngIf="link === 'owner'">
|
<span *ngIf="link === 'owner'">
|
||||||
Owned by <a [routerLink]="'/frontcraft/user/'+char.username"> {{char.username}} ({{char.rank}})</a>
|
Owned by <a [routerLink]="'/frontcraft/user/'+char.username"> {{char.username}} ({{char.rank}})</a>
|
||||||
</span>
|
</span>
|
||||||
|
|||||||
@@ -1,9 +1,10 @@
|
|||||||
import { Component, OnInit, Input } from '@angular/core';
|
import { Component, OnInit, Input } from '@angular/core';
|
||||||
import { ActivatedRoute } from '@angular/router';
|
import { ActivatedRoute } from '@angular/router';
|
||||||
import { Spec, User, Character, Item } from '../../../../../../backend/Types/Types';
|
import { Spec, User, Character, Item, _Class, _Race, Class } from '../../../../../../backend/Types/Types';
|
||||||
import { getClassColor } from '../../../../../../backend/Types/PlayerSpecs';
|
import { getClassColor, specs } from '../../../../../../backend/Types/PlayerSpecs';
|
||||||
import { _Tiers } from '../../../../../../backend/Types/Items';
|
import { _Tiers } from '../../../../../../backend/Types/Items';
|
||||||
import { IApiService } from '../../services/ApiService/ApiService';
|
import { IApiService } from '../../services/ApiService/ApiService';
|
||||||
|
import { NbToastrService } from '@nebular/theme';
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'character',
|
selector: 'character',
|
||||||
@@ -13,11 +14,17 @@ export class FrontcraftCharacterComponent implements OnInit {
|
|||||||
|
|
||||||
@Input() name?: string
|
@Input() name?: string
|
||||||
@Input() link?: "owner" | "character" = 'owner'
|
@Input() link?: "owner" | "character" = 'owner'
|
||||||
|
|
||||||
char: (Character & User & Spec) = {
|
char: (Character & User & Spec) = {
|
||||||
|
charactername: "Loading",
|
||||||
race: 'Human',
|
race: 'Human',
|
||||||
class: 'Warrior'
|
class: 'Warrior',
|
||||||
|
spec: 'Arms'
|
||||||
} as any
|
} as any
|
||||||
|
|
||||||
|
classes = _Class
|
||||||
|
races = _Race
|
||||||
|
specs = specs[this.char.class]
|
||||||
|
|
||||||
color: string
|
color: string
|
||||||
tokens
|
tokens
|
||||||
dataLink = ""
|
dataLink = ""
|
||||||
@@ -27,23 +34,32 @@ export class FrontcraftCharacterComponent implements OnInit {
|
|||||||
boss2 = { name: undefined, date: undefined }
|
boss2 = { name: undefined, date: undefined }
|
||||||
gear2: Item[] = []
|
gear2: Item[] = []
|
||||||
|
|
||||||
|
canManage: boolean = false
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
private api: IApiService,
|
private api: IApiService,
|
||||||
private route: ActivatedRoute,
|
private route: ActivatedRoute,
|
||||||
|
private toast: NbToastrService,
|
||||||
) { }
|
) { }
|
||||||
|
|
||||||
async ngOnInit() {
|
async ngOnInit() {
|
||||||
const param = this.name || this.route.snapshot.paramMap.get('name');
|
const param = this.name || this.route.snapshot.paramMap.get('name');
|
||||||
if (!param) return
|
if (!param) return
|
||||||
|
|
||||||
|
const manageChar = this.api.get('manageCharacter')
|
||||||
|
|
||||||
|
if (manageChar) this.canManage = true
|
||||||
|
|
||||||
const char = await this.api.get('CharacterManager').getCharacterByName(param)
|
const char = await this.api.get('CharacterManager').getCharacterByName(param)
|
||||||
if (char) {
|
if (char) {
|
||||||
this.color = getClassColor(char.class)
|
this.color = getClassColor(char.class)
|
||||||
this.char = char
|
this.char = char
|
||||||
|
this.specs = specs[this.char.class]
|
||||||
this.api.get('ItemManager').getTokens(this.char, _Tiers, true).then(tokens => {
|
this.api.get('ItemManager').getTokens(this.char, _Tiers, true).then(tokens => {
|
||||||
this.tokens = tokens
|
this.tokens = tokens
|
||||||
})
|
})
|
||||||
|
|
||||||
|
/*
|
||||||
this.dataLink = "https://classic.warcraftlogs.com:443/v1/parses/character/" + this.char.charactername.replace(/^\w/, c => c.toUpperCase()) + "/Gandling/EU?api_key=c698515ab4f592cdb848d80b3abe616c&metric=dps"
|
this.dataLink = "https://classic.warcraftlogs.com:443/v1/parses/character/" + this.char.charactername.replace(/^\w/, c => c.toUpperCase()) + "/Gandling/EU?api_key=c698515ab4f592cdb848d80b3abe616c&metric=dps"
|
||||||
|
|
||||||
const json: any[] = await fetch(this.dataLink).then(raw => raw.json())
|
const json: any[] = await fetch(this.dataLink).then(raw => raw.json())
|
||||||
@@ -68,6 +84,24 @@ export class FrontcraftCharacterComponent implements OnInit {
|
|||||||
const maybeItems: (Item | undefined)[] = await Promise.all(data.gear.filter(item => item.name != "Unknown Item").map(async item => await this.api.get('ItemManager').getItem(item.name)))
|
const maybeItems: (Item | undefined)[] = await Promise.all(data.gear.filter(item => item.name != "Unknown Item").map(async item => await this.api.get('ItemManager').getItem(item.name)))
|
||||||
const geardata = maybeItems.filter(maybeItem => maybeItem != null)
|
const geardata = maybeItems.filter(maybeItem => maybeItem != null)
|
||||||
this.gear2 = geardata
|
this.gear2 = geardata
|
||||||
|
*/
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
updateCharacter = async () => {
|
||||||
|
const manager = this.api.get('manageCharacter')
|
||||||
|
if (manager) {
|
||||||
|
const specid = await this.api.get('CharacterManager').getSpecId(this.char['class'], this.char['specname'] as any)
|
||||||
|
this.char.specid = specid
|
||||||
|
manager.updateCharacter(this.char).then(() => {
|
||||||
|
this.toast.show('Update', 'Success', { status: 'success' })
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
onSelectClass() {
|
||||||
|
this.specs = specs[this.char.class]
|
||||||
|
setTimeout(() => {
|
||||||
|
this.char.specname = this.specs[0]
|
||||||
|
}, 25)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -72,6 +72,10 @@
|
|||||||
<nb-card-header>Tanks ({{raid.tanks.length}})</nb-card-header>
|
<nb-card-header>Tanks ({{raid.tanks.length}})</nb-card-header>
|
||||||
<nb-card-body>
|
<nb-card-body>
|
||||||
<div *ngFor="let participant of raid.tanks">
|
<div *ngFor="let participant of raid.tanks">
|
||||||
|
<button (click)="adminSetAbsent(participant)" *ngIf="manageRaid" nbButton outline
|
||||||
|
status="info" size="tiny">
|
||||||
|
A
|
||||||
|
</button>
|
||||||
<button (click)="setBench(participant)" *ngIf="manageRaid" nbButton outline
|
<button (click)="setBench(participant)" *ngIf="manageRaid" nbButton outline
|
||||||
status="warning" size="tiny">
|
status="warning" size="tiny">
|
||||||
B
|
B
|
||||||
@@ -122,6 +126,10 @@
|
|||||||
<nb-card-header>Healers ({{raid.healers.length}})</nb-card-header>
|
<nb-card-header>Healers ({{raid.healers.length}})</nb-card-header>
|
||||||
<nb-card-body>
|
<nb-card-body>
|
||||||
<div *ngFor="let participant of raid.healers">
|
<div *ngFor="let participant of raid.healers">
|
||||||
|
<button (click)="adminSetAbsent(participant)" *ngIf="manageRaid" nbButton
|
||||||
|
outline status="info" size="tiny">
|
||||||
|
A
|
||||||
|
</button>
|
||||||
<button (click)="setBench(participant)" *ngIf="manageRaid" nbButton outline
|
<button (click)="setBench(participant)" *ngIf="manageRaid" nbButton outline
|
||||||
status="warning" size="tiny">
|
status="warning" size="tiny">
|
||||||
B
|
B
|
||||||
@@ -171,6 +179,10 @@
|
|||||||
<nb-card-header>{{group.key}} ({{group.value.length}})</nb-card-header>
|
<nb-card-header>{{group.key}} ({{group.value.length}})</nb-card-header>
|
||||||
<nb-card-body>
|
<nb-card-body>
|
||||||
<div *ngFor="let participant of group.value">
|
<div *ngFor="let participant of group.value">
|
||||||
|
<button (click)="adminSetAbsent(participant)" *ngIf="manageRaid" nbButton
|
||||||
|
outline status="info" size="tiny">
|
||||||
|
A
|
||||||
|
</button>
|
||||||
<button (click)="setBench(participant)" *ngIf="manageRaid" nbButton outline
|
<button (click)="setBench(participant)" *ngIf="manageRaid" nbButton outline
|
||||||
status="warning" size="tiny">
|
status="warning" size="tiny">
|
||||||
B
|
B
|
||||||
@@ -206,8 +218,9 @@
|
|||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
</ng-template>
|
</ng-template>
|
||||||
<nb-icon *ngIf="participant.memo" [nbPopover]="memoBox" nbPopoverTrigger="hover"
|
<nb-icon *ngIf="participant.memo" [nbPopover]="memoBox"
|
||||||
style="width: 0.75em; height: 0.75em;" icon="message-circle-outline">
|
nbPopoverTrigger="hover" style="width: 0.75em; height: 0.75em;"
|
||||||
|
icon="message-circle-outline">
|
||||||
</nb-icon>
|
</nb-icon>
|
||||||
<span *ngIf="participant.rank=='Trial'" style="font-size: 9px;">
|
<span *ngIf="participant.rank=='Trial'" style="font-size: 9px;">
|
||||||
Trial
|
Trial
|
||||||
@@ -244,7 +257,6 @@
|
|||||||
<tr>
|
<tr>
|
||||||
<td>
|
<td>
|
||||||
<wowhead [item]="item.value[0]"></wowhead><br />
|
<wowhead [item]="item.value[0]"></wowhead><br />
|
||||||
|
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
@@ -254,7 +266,15 @@
|
|||||||
<span
|
<span
|
||||||
[ngStyle]="{'text-decoration': token.rank=='Trial'? 'line-through' : 'none currentcolor solid' }">
|
[ngStyle]="{'text-decoration': token.rank=='Trial'? 'line-through' : 'none currentcolor solid' }">
|
||||||
<span style="text-transform: capitalize;">
|
<span style="text-transform: capitalize;">
|
||||||
|
<button (click)="decreaseReserve(token)" *ngIf="changeReserve" nbButton
|
||||||
|
outline status="warning" size="tiny">
|
||||||
|
-
|
||||||
|
</button>
|
||||||
[ {{token.level}} ]
|
[ {{token.level}} ]
|
||||||
|
<button (click)="increaseReserve(token)" *ngIf="changeReserve" nbButton
|
||||||
|
outline status="warning" size="tiny">
|
||||||
|
+
|
||||||
|
</button>
|
||||||
<a [routerLink]="'/frontcraft/character/'+token.charactername"
|
<a [routerLink]="'/frontcraft/character/'+token.charactername"
|
||||||
[ngStyle]="{'color':token.level>=10?'#ff8000':token.level>=8?'#a335ee':token.level>=6?'#0070dd':token.level>=4?'#1eff00':token.level>=2?'#ffffff':'#9d9d9d'}">
|
[ngStyle]="{'color':token.level>=10?'#ff8000':token.level>=8?'#a335ee':token.level>=6?'#0070dd':token.level>=4?'#1eff00':token.level>=2?'#ffffff':'#9d9d9d'}">
|
||||||
{{token.charactername}}
|
{{token.charactername}}
|
||||||
|
|||||||
@@ -26,6 +26,7 @@ export class FrontcraftRaidComponent
|
|||||||
isTier = false
|
isTier = false
|
||||||
reservesShown = true
|
reservesShown = true
|
||||||
manageRaid
|
manageRaid
|
||||||
|
changeReserve
|
||||||
mySignup: (Signup & Character & Spec)
|
mySignup: (Signup & Character & Spec)
|
||||||
|
|
||||||
raid: RaidData = <any>{
|
raid: RaidData = <any>{
|
||||||
@@ -64,6 +65,7 @@ export class FrontcraftRaidComponent
|
|||||||
|
|
||||||
ngOnInit() {
|
ngOnInit() {
|
||||||
this.manageRaid = this.api.get('manageRaid')
|
this.manageRaid = this.api.get('manageRaid')
|
||||||
|
this.changeReserve = this.api.get('changeReserve')
|
||||||
const signupFeature = this.api.get('signup')
|
const signupFeature = this.api.get('signup')
|
||||||
|
|
||||||
if (signupFeature) {
|
if (signupFeature) {
|
||||||
@@ -187,7 +189,6 @@ export class FrontcraftRaidComponent
|
|||||||
}
|
}
|
||||||
|
|
||||||
display = async (raiddata: RaidData) => {
|
display = async (raiddata: RaidData) => {
|
||||||
this.logger.log(raiddata)
|
|
||||||
this.isTier = allItems[raiddata.tier] != null
|
this.isTier = allItems[raiddata.tier] != null
|
||||||
|
|
||||||
this.raid = raiddata
|
this.raid = raiddata
|
||||||
@@ -248,4 +249,31 @@ export class FrontcraftRaidComponent
|
|||||||
.then(_ => this.refresh())
|
.then(_ => this.refresh())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
adminSetAbsent(signup: Signup) {
|
||||||
|
|
||||||
|
const manageRaid = this.api.get('manageRaid')
|
||||||
|
if(manageRaid){
|
||||||
|
const signupUpdated:Signup = {
|
||||||
|
benched: false,
|
||||||
|
absent: !signup.absent,
|
||||||
|
late: false,
|
||||||
|
characterid: signup.characterid,
|
||||||
|
raidid: signup.raidid,
|
||||||
|
timestamp: signup.timestamp,
|
||||||
|
id: signup.id,
|
||||||
|
memo: signup.memo
|
||||||
|
}
|
||||||
|
manageRaid.updateSignup(signupUpdated)
|
||||||
|
.then(_ => this.refresh())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
increaseReserve(token: Character & SRToken & Item){
|
||||||
|
this.changeReserve.increaseReserve(token, this.raid.id)
|
||||||
|
}
|
||||||
|
|
||||||
|
decreaseReserve(token: Character & SRToken & Item){
|
||||||
|
this.changeReserve.decreaseReserve(token, this.raid.id)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -31,7 +31,7 @@ export class ClientApiService implements IApiService{
|
|||||||
try{
|
try{
|
||||||
const sock = new RPCSocket(
|
const sock = new RPCSocket(
|
||||||
auth.port,
|
auth.port,
|
||||||
window.location.hostname
|
window.location.hostname,
|
||||||
)
|
)
|
||||||
|
|
||||||
sock.hook('kick', () => {
|
sock.hook('kick', () => {
|
||||||
@@ -48,7 +48,7 @@ export class ClientApiService implements IApiService{
|
|||||||
|
|
||||||
sock.on('error', async (e) => {
|
sock.on('error', async (e) => {
|
||||||
this.logger.log("priv#error", e);
|
this.logger.log("priv#error", e);
|
||||||
|
await this.logout()
|
||||||
//handled via unprivileged socket
|
//handled via unprivileged socket
|
||||||
})
|
})
|
||||||
const authSock = await sock.connect(auth.token.value)
|
const authSock = await sock.connect(auth.token.value)
|
||||||
@@ -95,7 +95,6 @@ export class ClientApiService implements IApiService{
|
|||||||
throw new Error("Login failed")
|
throw new Error("Login failed")
|
||||||
}
|
}
|
||||||
|
|
||||||
//attach error handler now so failed logins dont trigger reloads
|
|
||||||
this.socket.on('error', async (err) => {
|
this.socket.on('error', async (err) => {
|
||||||
location.reload()
|
location.reload()
|
||||||
})
|
})
|
||||||
|
|||||||
Reference in New Issue
Block a user