Compare commits
10
Commits
c2576180c7
...
bbe080ab7f
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
bbe080ab7f | ||
|
|
75c48273ff | ||
|
|
c2d2917de3 | ||
|
|
78abe78903 | ||
|
|
d4a528e61e | ||
|
|
c09c9ab67c | ||
|
|
f9008e67bd | ||
|
|
7e2c1d5761 | ||
|
|
1765c2eabc | ||
|
|
eb58ffc013 |
@@ -17,6 +17,7 @@ log.txt
|
||||
|
||||
|
||||
!src/**/*
|
||||
!test/**/*
|
||||
!migrations/**/*
|
||||
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": {
|
||||
"version": "1.1.1",
|
||||
"resolved": "https://registry.npmjs.org/@types/color-name/-/color-name-1.1.1.tgz",
|
||||
"integrity": "sha512-rr+OQyAjxze7GgWrSaJwydHStIhHq2lvY3BOC2Mj7KnzI7XK0Uw1TOOdI9lDoajEbSWLiYgoo4f1R51erQfhPQ==",
|
||||
"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": {
|
||||
"version": "3.1.4",
|
||||
"resolved": "https://registry.npmjs.org/@types/engine.io/-/engine.io-3.1.4.tgz",
|
||||
@@ -107,6 +124,27 @@
|
||||
"@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": {
|
||||
"version": "8.0.0",
|
||||
"resolved": "https://registry.npmjs.org/@types/fs-extra/-/fs-extra-8.0.0.tgz",
|
||||
@@ -133,6 +171,11 @@
|
||||
"@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": {
|
||||
"version": "5.2.7",
|
||||
"resolved": "https://registry.npmjs.org/@types/mocha/-/mocha-5.2.7.tgz",
|
||||
@@ -151,6 +194,25 @@
|
||||
"@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": {
|
||||
"version": "2.1.10",
|
||||
"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",
|
||||
"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": {
|
||||
"version": "2.4.0",
|
||||
"resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.4.0.tgz",
|
||||
@@ -4410,9 +4477,9 @@
|
||||
}
|
||||
},
|
||||
"rpclibrary": {
|
||||
"version": "2.0.1",
|
||||
"resolved": "https://registry.npmjs.org/rpclibrary/-/rpclibrary-2.0.1.tgz",
|
||||
"integrity": "sha512-phdU0TkrnNVXdFa5PKkbWvn+MxocowvqalEUG1jfpkc1CoQkJ9AXa4OXSEu5r2a2IFhVauYva/qXv1em5yrHSg==",
|
||||
"version": "2.3.1",
|
||||
"resolved": "https://registry.npmjs.org/rpclibrary/-/rpclibrary-2.3.1.tgz",
|
||||
"integrity": "sha512-y6F6gYxm9joJcnyxNeEoUSAbYGsaogcEKb1bxVB97+HcT4J6q9yw2fGnWS1FeeAUbTLUwASdlqJvRLPLiMPlcQ==",
|
||||
"requires": {
|
||||
"@types/socket.io": "^2.1.8",
|
||||
"@types/socket.io-client": "^1.4.33",
|
||||
|
||||
+3
-1
@@ -25,6 +25,7 @@
|
||||
"author": "frontblock.me",
|
||||
"license": "ISC",
|
||||
"dependencies": {
|
||||
"@types/express": "^4.17.8",
|
||||
"@types/mocha": "^5.2.7",
|
||||
"@types/node": "^14.0.27",
|
||||
"bsert": "0.0.10",
|
||||
@@ -46,9 +47,10 @@
|
||||
"ngx-cookie-service": "^2.4.0",
|
||||
"node-fetch": "^2.6.0",
|
||||
"path": "^0.12.7",
|
||||
"rate-limiter-flexible": "^2.1.10",
|
||||
"reflect-metadata": "^0.1.13",
|
||||
"rimraf": "^3.0.0",
|
||||
"rpclibrary": "^2.0.1",
|
||||
"rpclibrary": "^2.3.1",
|
||||
"simple-git": "^1.124.0",
|
||||
"spawn-sync": "^2.0.0",
|
||||
"sqlite3": "^4.2.0",
|
||||
|
||||
+42
-23
@@ -15,12 +15,14 @@ import { CharacterManager } from '../Components/Character/CharacterManager';
|
||||
import { UserManager } from '../Components/User/UserManager';
|
||||
import { RootComponent } from '../Injector/ServiceDecorator';
|
||||
import { TableDefinitionExporter } from '../Types/Interfaces';
|
||||
import { AdminConf, TableDefiniton } from '../Types/Types';
|
||||
import { AdminConf, TableDefiniton, SomeOf } from '../Types/Types';
|
||||
import { RPCConfigLoader } from '../Components/RPCConfigLoader';
|
||||
import { FrontworkComponent } from '../Types/FrontworkComponent';
|
||||
import { IAdmin } from './Interface';
|
||||
import { Injector } from '../Injector/Injector';
|
||||
import { PubSub } from '../Components/PubSub/PubSub';
|
||||
import { BurstyRateLimiter, RateLimiterMemory, RateLimiterAbstract } from 'rate-limiter-flexible'
|
||||
|
||||
|
||||
@RootComponent({
|
||||
injectable: IAdmin,
|
||||
@@ -39,7 +41,7 @@ export class FrontworkAdmin
|
||||
config: RPCConfigLoader<AdminConf>
|
||||
rpcServer: RPCServer
|
||||
|
||||
private express
|
||||
private express : express.Application
|
||||
private httpServer
|
||||
|
||||
constructor(private frontworkComponents: FrontworkComponent[] = []) {
|
||||
@@ -66,14 +68,26 @@ export class FrontworkAdmin
|
||||
}
|
||||
|
||||
async start() {
|
||||
const ONE_REQUEST = 15
|
||||
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()
|
||||
const app = await this.makeExpress()
|
||||
const app = await this.makeExpress(rateLimiter)
|
||||
const httpServer = new http.Server(app)
|
||||
await this.startWebsocket(httpServer)
|
||||
httpServer.listen(port)
|
||||
await this.attachAngularSSR(app)
|
||||
await this.attachAngularSSR(app, rateLimiter)
|
||||
getLogger('Admin#startWebsocket').debug("Webserver up on", port)
|
||||
|
||||
await Promise.all(this.frontworkComponents.map(c => c.initialize ? c.initialize() : undefined))
|
||||
@@ -125,48 +139,53 @@ export class FrontworkAdmin
|
||||
}
|
||||
], {
|
||||
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)
|
||||
}
|
||||
|
||||
private async makeExpress() {
|
||||
private async makeExpress(rateLimiter : SomeOf<RateLimiterAbstract> = new RateLimiterMemory({ points: 6, duration: 3 })) {
|
||||
if (this.httpServer != null || this.express != null) {
|
||||
getLogger('Admin#startWebserver').warn("Webserver is already running")
|
||||
return
|
||||
}
|
||||
|
||||
this.express = express()
|
||||
|
||||
const distFolder = "../../../../dist"
|
||||
|
||||
this.express.get('*.*', (req, res) => {
|
||||
//console.log('*.*', req.path);
|
||||
try{
|
||||
const filepath = Path.join(__dirname, distFolder, 'browser', decodeURIComponent(req.path))
|
||||
if(!existsSync(filepath)){
|
||||
throw new Error("Bad file access: "+filepath)
|
||||
}
|
||||
res.sendFile(filepath)
|
||||
res.status(200)
|
||||
}catch(e){
|
||||
getLogger('Admin#startWebserver#serveFile').error(String(e))
|
||||
res.send("404 NOT FOUND")
|
||||
res.status(404)
|
||||
}
|
||||
rateLimiter.consume(req.ip)
|
||||
.then(_ => {
|
||||
const filepath = Path.join(__dirname, distFolder, 'browser', decodeURIComponent(req.path))
|
||||
if(!existsSync(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.status(200)
|
||||
})
|
||||
.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
|
||||
}
|
||||
|
||||
attachAngularSSR = async (express : express.Application) => {
|
||||
attachAngularSSR = async (express : express.Application, rateLimiter : SomeOf<RateLimiterAbstract> = new RateLimiterMemory({ points: 6, duration: 3 })) => {
|
||||
const distFolder = "../../../../dist"
|
||||
const ngExpressServer = Path.join(__dirname, distFolder, 'server.js')
|
||||
let port: number = this.config.getConfig().httpPort
|
||||
|
||||
try {
|
||||
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")
|
||||
} catch (e) {
|
||||
getLogger('Admin#startWebserver').error(e)
|
||||
|
||||
@@ -30,7 +30,13 @@ implements FrontworkComponent<CharacterManagerIfc, RPCInterface>, ICharacterMana
|
||||
this.getHeadCount
|
||||
]
|
||||
|
||||
RPCFeatures = () => []
|
||||
RPCFeatures = () => [{
|
||||
name: 'manageCharacter' as 'manageCharacter',
|
||||
RPCs: [
|
||||
this.updateCharacter
|
||||
]
|
||||
}]
|
||||
|
||||
|
||||
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> => {
|
||||
try{
|
||||
character.charactername = character.charactername.toLowerCase()
|
||||
|
||||
@@ -10,4 +10,6 @@ export class ICharacterManager{
|
||||
getCharactersOfUser: (username: string) => Promise<(Character & Spec)[]>
|
||||
getUserOfCharacter: (character:Character) => Promise<User>
|
||||
getHeadCount: (clazz: Class) => Promise<number>
|
||||
updateCharacter: (character: Character) => Promise<Character>
|
||||
|
||||
}
|
||||
@@ -14,5 +14,7 @@ export type CharacterManagerIfc = {
|
||||
}
|
||||
|
||||
export type CharacterManagerFeatureIfc = {
|
||||
|
||||
manageCharacter: {
|
||||
updateCharacter: ICharacterManager['updateCharacter']
|
||||
}
|
||||
}
|
||||
@@ -15,4 +15,7 @@ export class IItemManager{
|
||||
wipeCurrencyAndItems: () => Promise<void>
|
||||
decayTokens: (tier: Tiers, 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: () => [
|
||||
this.decayTokensOfCharacter
|
||||
]
|
||||
}, {
|
||||
name: 'changeReserve' as 'changeReserve',
|
||||
RPCs: () => [
|
||||
this.decreaseReserve,
|
||||
this.increaseReserve
|
||||
]
|
||||
}]
|
||||
|
||||
notifyRaid = async (raid: Raid | { id: number }) => {
|
||||
@@ -253,7 +259,7 @@ export class ItemManager
|
||||
itemname: item.itemname
|
||||
})
|
||||
} else {
|
||||
getLogger('ItemManager').debug('new reserve')
|
||||
//getLogger('ItemManager').debug('new reserve')
|
||||
await this.admin
|
||||
.knex(item.tier + 'tokens')
|
||||
.transacting(tx)
|
||||
@@ -374,7 +380,7 @@ export class ItemManager
|
||||
}
|
||||
|
||||
decayTokens = async (tier: Tiers, amount = 1) => {
|
||||
getLogger('ItemManager#decayTokens').debug(tier)
|
||||
//getLogger('ItemManager#decayTokens').debug(tier)
|
||||
|
||||
await this.admin
|
||||
.knex(tier + 'tokens')
|
||||
@@ -387,7 +393,7 @@ export class ItemManager
|
||||
}
|
||||
|
||||
decayTokensOfCharacter = async (tier: Tiers, character:Character) => {
|
||||
getLogger('ItemManager#decayTokensOfCharacter').debug(character, tier)
|
||||
//getLogger('ItemManager#decayTokensOfCharacter').debug(character, tier)
|
||||
await this.admin
|
||||
.knex(tier + 'tokens')
|
||||
.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){
|
||||
|
||||
@@ -23,4 +23,8 @@ export type ItemManagerFeatureIfc = {
|
||||
decay: {
|
||||
decayTokensOfCharacter: IItemManager['decayTokensOfCharacter']
|
||||
}
|
||||
changeReserve: {
|
||||
increaseReserve: IItemManager['increaseReserve']
|
||||
decreaseReserve: IItemManager['decreaseReserve']
|
||||
}
|
||||
}
|
||||
@@ -16,4 +16,5 @@ export class IRaidManager{
|
||||
startRaid: (raid:Raid) => Promise<RaidData>
|
||||
adminUnsign: (character:Character, raid:Raid) => Promise<any>
|
||||
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 { getLogger } from "log4js";
|
||||
|
||||
|
||||
|
||||
@Injectable(IRaidManager)
|
||||
export class RaidManager
|
||||
implements FrontworkComponent<RaidManagerIfc, RaidManagerFeatureIfc>, IRaidManager {
|
||||
@@ -27,7 +29,7 @@ export class RaidManager
|
||||
@Inject(ICharacterManager)
|
||||
private characterManager: ICharacterManager
|
||||
|
||||
@Inject(ItemManager)
|
||||
@Inject(IItemManager)
|
||||
private itemManager: IItemManager
|
||||
|
||||
@Inject(IPubSub)
|
||||
@@ -189,8 +191,10 @@ export class RaidManager
|
||||
await this.userManager.incrementCurrency(usr, raid.tier, 1)
|
||||
}
|
||||
|
||||
const THREE_DAYS = 259200000;
|
||||
|
||||
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))
|
||||
])
|
||||
|
||||
@@ -307,6 +311,17 @@ export class RaidManager
|
||||
.where('id', '=', raid.id)
|
||||
.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
|
||||
.knex('signups as s')
|
||||
.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 () => {
|
||||
this.exporters = [this, this.guild, this.item, this.raid, this.character]
|
||||
this.exporters = [this.guild, this.item, this.raid, this.character]
|
||||
//set up permissions
|
||||
getLogger('UserManager#initialize').debug('setting up permissions')
|
||||
|
||||
console.log(this.character.RPCFeatures())
|
||||
|
||||
await Promise.all(
|
||||
[this, ...this.exporters].flatMap(exp => exp.RPCFeatures().map(async (feature) => {
|
||||
try {
|
||||
|
||||
+133
-1
@@ -423,6 +423,138 @@ export const ZGMounts = [
|
||||
"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 = {
|
||||
[tier in Tiers]: string[]
|
||||
}
|
||||
@@ -433,5 +565,5 @@ export const allItems: AllItems = {
|
||||
ZG: ZGMounts,
|
||||
AQ20: [],
|
||||
AQ40: AQ40,
|
||||
Naxx: []
|
||||
Naxx: Naxx
|
||||
}
|
||||
Generated
+137
-48
@@ -2730,18 +2730,18 @@
|
||||
"dev": true
|
||||
},
|
||||
"@types/socket.io": {
|
||||
"version": "2.1.10",
|
||||
"resolved": "https://registry.npmjs.org/@types/socket.io/-/socket.io-2.1.10.tgz",
|
||||
"integrity": "sha512-1fQMaDU/x2LPljEI/QI5IKl8sBYHM/zv32YYKvNrVEor7/1+MLqMqmWt8Bb8Vpf+PlIPBiTTC0BnrRx7ju3xOw==",
|
||||
"version": "2.1.11",
|
||||
"resolved": "https://registry.npmjs.org/@types/socket.io/-/socket.io-2.1.11.tgz",
|
||||
"integrity": "sha512-bVprmqPhJMLb9ZCm8g0Xy8kwBFRbnanOWSxzWkDkkIwxTvud5tKMfAJymXX6LQbizUKCS1yima7JM4BeLqjNqA==",
|
||||
"requires": {
|
||||
"@types/engine.io": "*",
|
||||
"@types/node": "*"
|
||||
}
|
||||
},
|
||||
"@types/socket.io-client": {
|
||||
"version": "1.4.33",
|
||||
"resolved": "https://registry.npmjs.org/@types/socket.io-client/-/socket.io-client-1.4.33.tgz",
|
||||
"integrity": "sha512-m4LnxkljsI9fMsjwpW5QhRpMixo2BeeLpFmg0AE+sS4H1pzAd/cs/ftTiL60FLZgfFa8PFRPx5KsHu8O0bADKQ=="
|
||||
"version": "1.4.34",
|
||||
"resolved": "https://registry.npmjs.org/@types/socket.io-client/-/socket.io-client-1.4.34.tgz",
|
||||
"integrity": "sha512-Lzia5OTQFJZJ5R4HsEEldywiiqT9+W2rDbyHJiiTGqOcju89sCsQ8aUXDljY6Ls33wKZZGC0bfMhr/VpOyjtXg=="
|
||||
},
|
||||
"@types/source-list-map": {
|
||||
"version": "0.1.2",
|
||||
@@ -3766,7 +3766,8 @@
|
||||
"base64-arraybuffer": {
|
||||
"version": "0.1.5",
|
||||
"resolved": "https://registry.npmjs.org/base64-arraybuffer/-/base64-arraybuffer-0.1.5.tgz",
|
||||
"integrity": "sha1-c5JncZI7Whl0etZmqlzUv5xunOg="
|
||||
"integrity": "sha1-c5JncZI7Whl0etZmqlzUv5xunOg=",
|
||||
"dev": true
|
||||
},
|
||||
"base64-js": {
|
||||
"version": "1.3.1",
|
||||
@@ -15789,9 +15790,9 @@
|
||||
"integrity": "sha512-ZYzRkETgBrdEGzL5JSKimvjI2CX7ioyZCkX2BpcfyjqI+079W0wHAyj5W4rIZMcDSOHgLZtgz1IdDi/vU77KEQ=="
|
||||
},
|
||||
"rpclibrary": {
|
||||
"version": "2.0.1",
|
||||
"resolved": "https://registry.npmjs.org/rpclibrary/-/rpclibrary-2.0.1.tgz",
|
||||
"integrity": "sha512-phdU0TkrnNVXdFa5PKkbWvn+MxocowvqalEUG1jfpkc1CoQkJ9AXa4OXSEu5r2a2IFhVauYva/qXv1em5yrHSg==",
|
||||
"version": "2.3.1",
|
||||
"resolved": "https://registry.npmjs.org/rpclibrary/-/rpclibrary-2.3.1.tgz",
|
||||
"integrity": "sha512-y6F6gYxm9joJcnyxNeEoUSAbYGsaogcEKb1bxVB97+HcT4J6q9yw2fGnWS1FeeAUbTLUwASdlqJvRLPLiMPlcQ==",
|
||||
"requires": {
|
||||
"@types/socket.io": "^2.1.8",
|
||||
"@types/socket.io-client": "^1.4.33",
|
||||
@@ -15806,6 +15807,11 @@
|
||||
"resolved": "https://registry.npmjs.org/arraybuffer.slice/-/arraybuffer.slice-0.0.7.tgz",
|
||||
"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": {
|
||||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/base64id/-/base64id-2.0.0.tgz",
|
||||
@@ -15840,18 +15846,18 @@
|
||||
}
|
||||
},
|
||||
"engine.io-client": {
|
||||
"version": "3.4.3",
|
||||
"resolved": "https://registry.npmjs.org/engine.io-client/-/engine.io-client-3.4.3.tgz",
|
||||
"integrity": "sha512-0NGY+9hioejTEJCaSJZfWZLk4FPI9dN+1H1C4+wj2iuFba47UgZbJzfWs4aNFajnX/qAaYKbe2lLTfEEWzCmcw==",
|
||||
"version": "3.4.4",
|
||||
"resolved": "https://registry.npmjs.org/engine.io-client/-/engine.io-client-3.4.4.tgz",
|
||||
"integrity": "sha512-iU4CRr38Fecj8HoZEnFtm2EiKGbYZcPn3cHxqNGl/tmdWRf60KhK+9vE0JeSjgnlS/0oynEfLgKbT9ALpim0sQ==",
|
||||
"requires": {
|
||||
"component-emitter": "~1.3.0",
|
||||
"component-inherit": "0.0.3",
|
||||
"debug": "~4.1.0",
|
||||
"debug": "~3.1.0",
|
||||
"engine.io-parser": "~2.2.0",
|
||||
"has-cors": "1.1.0",
|
||||
"indexof": "0.0.1",
|
||||
"parseqs": "0.0.5",
|
||||
"parseuri": "0.0.5",
|
||||
"parseqs": "0.0.6",
|
||||
"parseuri": "0.0.6",
|
||||
"ws": "~6.1.0",
|
||||
"xmlhttprequest-ssl": "~1.5.4",
|
||||
"yeast": "0.1.2"
|
||||
@@ -15862,6 +15868,24 @@
|
||||
"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=="
|
||||
},
|
||||
"ws": {
|
||||
"version": "6.1.4",
|
||||
"resolved": "https://registry.npmjs.org/ws/-/ws-6.1.4.tgz",
|
||||
@@ -15873,13 +15897,13 @@
|
||||
}
|
||||
},
|
||||
"engine.io-parser": {
|
||||
"version": "2.2.0",
|
||||
"resolved": "https://registry.npmjs.org/engine.io-parser/-/engine.io-parser-2.2.0.tgz",
|
||||
"integrity": "sha512-6I3qD9iUxotsC5HEMuuGsKA0cXerGz+4uGcXQEkfBidgKf0amsjrrtwcbwK/nzpZBxclXlV7gGl9dgWvu4LF6w==",
|
||||
"version": "2.2.1",
|
||||
"resolved": "https://registry.npmjs.org/engine.io-parser/-/engine.io-parser-2.2.1.tgz",
|
||||
"integrity": "sha512-x+dN/fBH8Ro8TFwJ+rkB2AmuVw9Yu2mockR/p3W8f8YtExwFgDvBDi0GWyb4ZLkpahtDGZgtr3zLovanJghPqg==",
|
||||
"requires": {
|
||||
"after": "0.8.2",
|
||||
"arraybuffer.slice": "~0.0.7",
|
||||
"base64-arraybuffer": "0.1.5",
|
||||
"base64-arraybuffer": "0.1.4",
|
||||
"blob": "0.0.5",
|
||||
"has-binary2": "~1.0.2"
|
||||
}
|
||||
@@ -15905,6 +15929,61 @@
|
||||
"socket.io-adapter": "~1.1.0",
|
||||
"socket.io-client": "2.3.0",
|
||||
"socket.io-parser": "~3.4.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"base64-arraybuffer": {
|
||||
"version": "0.1.5",
|
||||
"resolved": "https://registry.npmjs.org/base64-arraybuffer/-/base64-arraybuffer-0.1.5.tgz",
|
||||
"integrity": "sha1-c5JncZI7Whl0etZmqlzUv5xunOg="
|
||||
},
|
||||
"socket.io-client": {
|
||||
"version": "2.3.0",
|
||||
"resolved": "https://registry.npmjs.org/socket.io-client/-/socket.io-client-2.3.0.tgz",
|
||||
"integrity": "sha512-cEQQf24gET3rfhxZ2jJ5xzAOo/xhZwK+mOqtGRg5IowZsMgwvHwnf/mCRapAAkadhM26y+iydgwsXGObBB5ZdA==",
|
||||
"requires": {
|
||||
"backo2": "1.0.2",
|
||||
"base64-arraybuffer": "0.1.5",
|
||||
"component-bind": "1.0.0",
|
||||
"component-emitter": "1.2.1",
|
||||
"debug": "~4.1.0",
|
||||
"engine.io-client": "~3.4.0",
|
||||
"has-binary2": "~1.0.2",
|
||||
"has-cors": "1.1.0",
|
||||
"indexof": "0.0.1",
|
||||
"object-component": "0.0.3",
|
||||
"parseqs": "0.0.5",
|
||||
"parseuri": "0.0.5",
|
||||
"socket.io-parser": "~3.3.0",
|
||||
"to-array": "0.1.4"
|
||||
},
|
||||
"dependencies": {
|
||||
"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"
|
||||
},
|
||||
"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"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"socket.io-adapter": {
|
||||
@@ -15913,44 +15992,54 @@
|
||||
"integrity": "sha512-WzZRUj1kUjrTIrUKpZLEzFZ1OLj5FwLlAFQs9kuZJzJi5DKdU7FsWc36SNmA8iDOtwBQyT8FkrriRM8vXLYz8g=="
|
||||
},
|
||||
"socket.io-client": {
|
||||
"version": "2.3.0",
|
||||
"resolved": "https://registry.npmjs.org/socket.io-client/-/socket.io-client-2.3.0.tgz",
|
||||
"integrity": "sha512-cEQQf24gET3rfhxZ2jJ5xzAOo/xhZwK+mOqtGRg5IowZsMgwvHwnf/mCRapAAkadhM26y+iydgwsXGObBB5ZdA==",
|
||||
"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",
|
||||
"base64-arraybuffer": "0.1.5",
|
||||
"component-bind": "1.0.0",
|
||||
"component-emitter": "1.2.1",
|
||||
"debug": "~4.1.0",
|
||||
"component-emitter": "~1.3.0",
|
||||
"debug": "~3.1.0",
|
||||
"engine.io-client": "~3.4.0",
|
||||
"has-binary2": "~1.0.2",
|
||||
"has-cors": "1.1.0",
|
||||
"indexof": "0.0.1",
|
||||
"object-component": "0.0.3",
|
||||
"parseqs": "0.0.5",
|
||||
"parseuri": "0.0.5",
|
||||
"parseqs": "0.0.6",
|
||||
"parseuri": "0.0.6",
|
||||
"socket.io-parser": "~3.3.0",
|
||||
"to-array": "0.1.4"
|
||||
},
|
||||
"dependencies": {
|
||||
"socket.io-parser": {
|
||||
"version": "3.3.0",
|
||||
"resolved": "https://registry.npmjs.org/socket.io-parser/-/socket.io-parser-3.3.0.tgz",
|
||||
"integrity": "sha512-hczmV6bDgdaEbVqhAeVMM/jfUfzuEZHsQg6eOmLgJht6G3mPKMxYm75w2+qhAQZ+4X+1+ATZ+QFKeOZD5riHng==",
|
||||
"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": {
|
||||
"component-emitter": "1.2.1",
|
||||
"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"
|
||||
},
|
||||
"dependencies": {
|
||||
"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"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -15966,9 +16055,9 @@
|
||||
}
|
||||
},
|
||||
"ws": {
|
||||
"version": "7.3.1",
|
||||
"resolved": "https://registry.npmjs.org/ws/-/ws-7.3.1.tgz",
|
||||
"integrity": "sha512-D3RuNkynyHmEJIpD2qrgVkc9DQ23OrN/moAwZX4L8DfvszsJxpjQuUq3LMx6HoYji9fbIOBY18XWBsAux1ZZUA=="
|
||||
"version": "7.4.0",
|
||||
"resolved": "https://registry.npmjs.org/ws/-/ws-7.4.0.tgz",
|
||||
"integrity": "sha512-kyFwXuV/5ymf+IXhS6f0+eAFvydbaBW3zjpT6hUdAh/hbVjTIB5EHBGi0bPoCLSK2wcuz3BrEkB9LrYv1Nm4NQ=="
|
||||
},
|
||||
"xmlhttprequest-ssl": {
|
||||
"version": "1.5.5",
|
||||
|
||||
@@ -79,7 +79,7 @@
|
||||
"normalize.css": "6.0.0",
|
||||
"pace-js": "1.0.2",
|
||||
"roboto-fontface": "0.8.0",
|
||||
"rpclibrary": "^2.0.1",
|
||||
"rpclibrary": "^2.3.1",
|
||||
"rxjs": "6.5.2",
|
||||
"rxjs-compat": "6.3.0",
|
||||
"socicon": "3.0.5",
|
||||
|
||||
+20
-11
@@ -15,15 +15,21 @@ global['alert'] = console.log
|
||||
global['XMLHttpRequest'] = require('xmlhttprequest').XMLHttpRequest;
|
||||
global['fetch'] = fetch.default;
|
||||
|
||||
|
||||
|
||||
export async function attachExpress(app, staticDir = "./dist", logger = console) {
|
||||
/**
|
||||
* Function to attach this SSR application to an express server. Exported as function due to webpack inconsistencies.
|
||||
*
|
||||
* @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);
|
||||
enableProdMode();
|
||||
|
||||
const loggerService = {
|
||||
warn: (...args) => logger.error(...args),
|
||||
error: (...args) => logger.warn(...args),
|
||||
warn: (...args) => logger.warn(...args),
|
||||
error: (...args) => logger.error(...args),
|
||||
log: (...args) => logger.info(...args),
|
||||
table: (...args) => logger.info(...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) => {
|
||||
//console.log('*', req.path);
|
||||
try{
|
||||
rateLimiter.consume(req.ip, 3)
|
||||
.then(_ => {
|
||||
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"
|
||||
}
|
||||
|
||||
ranks = _Rank.splice(5) //remove admin, gm, officer
|
||||
ranks = ["Trial"] //remove admin, gm, officer
|
||||
classes = _Class
|
||||
races = _Race
|
||||
selectedClass : Class = "Warrior"
|
||||
selectedSpec = specs[this.selectedClass][0]
|
||||
specs = specs[this.selectedClass]
|
||||
selectedSpec = specs[this.selectedClass][0]
|
||||
showApplication = false
|
||||
submitted = false
|
||||
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
<nb-card
|
||||
class = "col-12 col-xl-9">
|
||||
<nb-card class="col-12 col-xl-9">
|
||||
<nb-card-header style="text-transform: capitalize;">
|
||||
<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}}
|
||||
</a>
|
||||
</h4>
|
||||
@@ -14,10 +14,31 @@ class = "col-12 col-xl-9">
|
||||
</nb-card-header>
|
||||
|
||||
<nb-card-body>
|
||||
<img style="width:20px; height:20px" [src]="'../../../../assets/images/'+char.race.toLowerCase()+'_xs.gif'" />
|
||||
{{char.race}}<br />
|
||||
<img style="width:20px; height:20px" [src]="'../../../../assets/images/'+char.class.toLowerCase()+'.png'" />
|
||||
{{char.specname}} {{char.class}}<br />
|
||||
<span *ngIf="!canManage">
|
||||
<img style="width:20px; height:20px" [src]="'../../../../assets/images/'+char.race.toLowerCase()+'_xs.gif'" />
|
||||
{{char.race}}<br />
|
||||
<img style="width:20px; height:20px" [src]="'../../../../assets/images/'+char.class.toLowerCase()+'.png'" />
|
||||
|
||||
{{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'">
|
||||
Owned by <a [routerLink]="'/frontcraft/user/'+char.username"> {{char.username}} ({{char.rank}})</a>
|
||||
</span>
|
||||
|
||||
@@ -1,9 +1,10 @@
|
||||
import { Component, OnInit, Input } from '@angular/core';
|
||||
import { ActivatedRoute } from '@angular/router';
|
||||
import { Spec, User, Character, Item } from '../../../../../../backend/Types/Types';
|
||||
import { getClassColor } from '../../../../../../backend/Types/PlayerSpecs';
|
||||
import { Spec, User, Character, Item, _Class, _Race, Class } from '../../../../../../backend/Types/Types';
|
||||
import { getClassColor, specs } from '../../../../../../backend/Types/PlayerSpecs';
|
||||
import { _Tiers } from '../../../../../../backend/Types/Items';
|
||||
import { IApiService } from '../../services/ApiService/ApiService';
|
||||
import { NbToastrService } from '@nebular/theme';
|
||||
|
||||
@Component({
|
||||
selector: 'character',
|
||||
@@ -13,11 +14,17 @@ export class FrontcraftCharacterComponent implements OnInit {
|
||||
|
||||
@Input() name?: string
|
||||
@Input() link?: "owner" | "character" = 'owner'
|
||||
|
||||
char: (Character & User & Spec) = {
|
||||
charactername: "Loading",
|
||||
race: 'Human',
|
||||
class: 'Warrior'
|
||||
class: 'Warrior',
|
||||
spec: 'Arms'
|
||||
} as any
|
||||
|
||||
classes = _Class
|
||||
races = _Race
|
||||
specs = specs[this.char.class]
|
||||
|
||||
color: string
|
||||
tokens
|
||||
dataLink = ""
|
||||
@@ -27,23 +34,32 @@ export class FrontcraftCharacterComponent implements OnInit {
|
||||
boss2 = { name: undefined, date: undefined }
|
||||
gear2: Item[] = []
|
||||
|
||||
canManage: boolean = false
|
||||
|
||||
constructor(
|
||||
private api: IApiService,
|
||||
private route: ActivatedRoute,
|
||||
private toast: NbToastrService,
|
||||
) { }
|
||||
|
||||
async ngOnInit() {
|
||||
const param = this.name || this.route.snapshot.paramMap.get('name');
|
||||
if (!param) return
|
||||
|
||||
const manageChar = this.api.get('manageCharacter')
|
||||
|
||||
if (manageChar) this.canManage = true
|
||||
|
||||
const char = await this.api.get('CharacterManager').getCharacterByName(param)
|
||||
if (char) {
|
||||
this.color = getClassColor(char.class)
|
||||
this.char = char
|
||||
this.specs = specs[this.char.class]
|
||||
this.api.get('ItemManager').getTokens(this.char, _Tiers, true).then(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"
|
||||
|
||||
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 geardata = maybeItems.filter(maybeItem => maybeItem != null)
|
||||
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-body>
|
||||
<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
|
||||
status="warning" size="tiny">
|
||||
B
|
||||
@@ -122,6 +126,10 @@
|
||||
<nb-card-header>Healers ({{raid.healers.length}})</nb-card-header>
|
||||
<nb-card-body>
|
||||
<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
|
||||
status="warning" size="tiny">
|
||||
B
|
||||
@@ -171,6 +179,10 @@
|
||||
<nb-card-header>{{group.key}} ({{group.value.length}})</nb-card-header>
|
||||
<nb-card-body>
|
||||
<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
|
||||
status="warning" size="tiny">
|
||||
B
|
||||
@@ -206,8 +218,9 @@
|
||||
</p>
|
||||
</div>
|
||||
</ng-template>
|
||||
<nb-icon *ngIf="participant.memo" [nbPopover]="memoBox" nbPopoverTrigger="hover"
|
||||
style="width: 0.75em; height: 0.75em;" icon="message-circle-outline">
|
||||
<nb-icon *ngIf="participant.memo" [nbPopover]="memoBox"
|
||||
nbPopoverTrigger="hover" style="width: 0.75em; height: 0.75em;"
|
||||
icon="message-circle-outline">
|
||||
</nb-icon>
|
||||
<span *ngIf="participant.rank=='Trial'" style="font-size: 9px;">
|
||||
Trial
|
||||
@@ -244,7 +257,6 @@
|
||||
<tr>
|
||||
<td>
|
||||
<wowhead [item]="item.value[0]"></wowhead><br />
|
||||
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
@@ -254,7 +266,15 @@
|
||||
<span
|
||||
[ngStyle]="{'text-decoration': token.rank=='Trial'? 'line-through' : 'none currentcolor solid' }">
|
||||
<span style="text-transform: capitalize;">
|
||||
<button (click)="decreaseReserve(token)" *ngIf="changeReserve" nbButton
|
||||
outline status="warning" size="tiny">
|
||||
-
|
||||
</button>
|
||||
[ {{token.level}} ]
|
||||
<button (click)="increaseReserve(token)" *ngIf="changeReserve" nbButton
|
||||
outline status="warning" size="tiny">
|
||||
+
|
||||
</button>
|
||||
<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'}">
|
||||
{{token.charactername}}
|
||||
|
||||
@@ -26,6 +26,7 @@ export class FrontcraftRaidComponent
|
||||
isTier = false
|
||||
reservesShown = true
|
||||
manageRaid
|
||||
changeReserve
|
||||
mySignup: (Signup & Character & Spec)
|
||||
|
||||
raid: RaidData = <any>{
|
||||
@@ -64,6 +65,7 @@ export class FrontcraftRaidComponent
|
||||
|
||||
ngOnInit() {
|
||||
this.manageRaid = this.api.get('manageRaid')
|
||||
this.changeReserve = this.api.get('changeReserve')
|
||||
const signupFeature = this.api.get('signup')
|
||||
|
||||
if (signupFeature) {
|
||||
@@ -187,7 +189,6 @@ export class FrontcraftRaidComponent
|
||||
}
|
||||
|
||||
display = async (raiddata: RaidData) => {
|
||||
this.logger.log(raiddata)
|
||||
this.isTier = allItems[raiddata.tier] != null
|
||||
|
||||
this.raid = raiddata
|
||||
@@ -248,4 +249,31 @@ export class FrontcraftRaidComponent
|
||||
.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{
|
||||
const sock = new RPCSocket(
|
||||
auth.port,
|
||||
window.location.hostname
|
||||
window.location.hostname,
|
||||
)
|
||||
|
||||
sock.hook('kick', () => {
|
||||
@@ -48,7 +48,7 @@ export class ClientApiService implements IApiService{
|
||||
|
||||
sock.on('error', async (e) => {
|
||||
this.logger.log("priv#error", e);
|
||||
|
||||
await this.logout()
|
||||
//handled via unprivileged socket
|
||||
})
|
||||
const authSock = await sock.connect(auth.token.value)
|
||||
@@ -95,7 +95,6 @@ export class ClientApiService implements IApiService{
|
||||
throw new Error("Login failed")
|
||||
}
|
||||
|
||||
//attach error handler now so failed logins dont trigger reloads
|
||||
this.socket.on('error', async (err) => {
|
||||
location.reload()
|
||||
})
|
||||
|
||||
Reference in New Issue
Block a user