visual polish and bugfixes. auto-refreshing

This commit is contained in:
peter
2020-02-09 02:50:06 +01:00
parent e828a29db6
commit 18f3b32e3c
20 changed files with 996 additions and 754 deletions
+3 -3
View File
@@ -6130,9 +6130,9 @@
} }
}, },
"rpclibrary": { "rpclibrary": {
"version": "1.7.0", "version": "1.7.1",
"resolved": "https://registry.npmjs.org/rpclibrary/-/rpclibrary-1.7.0.tgz", "resolved": "https://registry.npmjs.org/rpclibrary/-/rpclibrary-1.7.1.tgz",
"integrity": "sha512-HIL5YzFF53fACOWvI403hJZnGYoXLJGrGc0n1HYZH6rnnfEaBcogemZrCbyoOvnG204LH882e8VdpB+WBTEY/g==", "integrity": "sha512-Ibo3qfURnQgZAq0eA2o+L9+PWaloJ4PHZs4ak42LL9fRgdWZXn33HAtowV0K2HVckbvrBvFqj/+PWTrWWBSOeg==",
"requires": { "requires": {
"bsock": "^0.1.9", "bsock": "^0.1.9",
"http": "0.0.0", "http": "0.0.0",
+11 -10
View File
@@ -5,15 +5,16 @@
"scripts": { "scripts": {
"tsc": "tsc", "tsc": "tsc",
"launch": "node lib/src/backend/Launcher.js", "launch": "node lib/src/backend/Launcher.js",
"start": "npm run build; npm run launch", "start": "npm run build && npm run launch",
"start-backend": "npm run build-backend; node lib/src/backend/Launcher.js", "start-backend": "npm run build-backend && npm run launch",
"build": "npm run build-backend; npm run build-frontend", "test": "npm run backend && npm run build-backend && mocha lib/test/backendTest.js",
"test": "npm run clean && npm run build-backend && mocha lib/test/backendTest.js", "build": "npm run build-backend && npm run build-frontend",
"build-backend": "tsc;", "build-backend": "npm run clean-backend && tsc",
"build-frontend": "mkdir dist; mkdir dist/static; npm run build-dashboard;", "build-frontend": "npm run clean-frontend && (mkdir static || rm -rf static/*) && npm run build-dashboard",
"build-dashboard": "cd src/frontend; npm i && npm run build; cp -r dist/* ../../dist/static", "build-dashboard": "cd src/frontend && npm i && npm run build && cp -r dist/* ../../static",
"clean": "rm -rf lib plugins conf widget .rpt2_cache *.js *.ts src/frontend/dist data", "clean": "rm -rf data && npm run clean-backend && npm run clean-frontend",
"update-frontblock": "npm remove frontblock frontblock-generic; npm install frontblock-generic@latest frontblock@latest", "clean-backend": "rm -rf lib plugins config widget .rpt2_cache *.js *.ts",
"clean-frontend": "rm -rf src/frontend/dist static",
"webpack": "webpack --config src/backend/webpack.prod.js --progress --colors" "webpack": "webpack --config src/backend/webpack.prod.js --progress --colors"
}, },
"repository": { "repository": {
@@ -44,7 +45,7 @@
"path": "^0.12.7", "path": "^0.12.7",
"reflect-metadata": "^0.1.13", "reflect-metadata": "^0.1.13",
"rimraf": "^3.0.0", "rimraf": "^3.0.0",
"rpclibrary": "^1.7.0", "rpclibrary": "^1.7.1",
"simple-git": "^1.124.0", "simple-git": "^1.124.0",
"spawn-sync": "^2.0.0", "spawn-sync": "^2.0.0",
"sqlite3": "^4.1.1", "sqlite3": "^4.1.1",
+8 -4
View File
@@ -20,6 +20,7 @@ import { FrontworkComponent } from '../Types/FrontworkComponent';
import { IAdmin } from './Interface'; import { IAdmin } from './Interface';
import { Injector } from '../Injector/Injector'; import { Injector } from '../Injector/Injector';
import { Shoutbox } from '../Components/Shoutbox/Shoutbox'; import { Shoutbox } from '../Components/Shoutbox/Shoutbox';
import { PubSub } from '../Components/PubSub/PubSub';
const logger = getLogger("admin", 'debug') const logger = getLogger("admin", 'debug')
@@ -32,7 +33,8 @@ const logger = getLogger("admin", 'debug')
RaidManager, RaidManager,
CharacterManager, CharacterManager,
UserManager, UserManager,
Shoutbox Shoutbox,
PubSub
] ]
}) })
export class FrontworkAdmin export class FrontworkAdmin
@@ -54,7 +56,7 @@ implements TableDefinitionExporter, IAdmin {
dbConf: { dbConf: {
client: 'sqlite3', client: 'sqlite3',
connection: { connection: {
filename: Path.join(__dirname, "data/frontworkAdmin.sqlite") filename: Path.resolve(__dirname, '../../../..', "data/frontworkAdmin.sqlite")
}, },
useNullAsDefault: true, useNullAsDefault: true,
} }
@@ -96,7 +98,9 @@ implements TableDefinitionExporter, IAdmin {
getTableDefinitions(): TableDefiniton[]{ getTableDefinitions(): TableDefiniton[]{
return [ return [
...this.frontworkComponents ...this.frontworkComponents
].flatMap(exporter => exporter.getTableDefinitions()) ]
.filter(exp => exp.getTableDefinitions != null)
.flatMap(exp => exp.getTableDefinitions())
} }
private startWebsocket(){ private startWebsocket(){
@@ -123,7 +127,7 @@ implements TableDefinitionExporter, IAdmin {
let port:number = this.config.getConfig().httpPort let port:number = this.config.getConfig().httpPort
this.express = express() this.express = express()
this.express.use('/', express.static('dist/static')) this.express.use('/', express.static('static'))
/** /**
* get the compiled FrontendPlugins.js * get the compiled FrontendPlugins.js
+24 -3
View File
@@ -1,14 +1,16 @@
import { T1, T2, allItems, _Tiers, Tiers } from "../../Types/Items"; import { allItems, _Tiers, Tiers } from "../../Types/Items";
import { Inject, Injectable } from "../../Injector/ServiceDecorator"; import { Inject, Injectable } from "../../Injector/ServiceDecorator";
import { ItemManagerFeatureIfc, ItemManagerIfc } from "./RPCInterface"; import { ItemManagerFeatureIfc, ItemManagerIfc } from "./RPCInterface";
import { FrontworkComponent } from "../../Types/FrontworkComponent"; import { FrontworkComponent } from "../../Types/FrontworkComponent";
import { TableDefinitionExporter } from "../../Types/Interfaces"; import { TableDefinitionExporter } from "../../Types/Interfaces";
import { TableDefiniton, Item, User, Character, SRToken, SRPriority, Spec, Signup } from "../../Types/Types"; import { TableDefiniton, Item, User, Character, SRToken, SRPriority, Spec, Signup, Raid } from "../../Types/Types";
import { IAdmin } from "../../Admin/Interface"; import { IAdmin } from "../../Admin/Interface";
import { IItemManager } from "./Interface"; import { IItemManager } from "./Interface";
import { getLogger } from "log4js"; import { getLogger } from "log4js";
import { IUserManager } from "../User/Interface"; import { IUserManager } from "../User/Interface";
import { ICharacterManager } from "../Character/Interface"; import { ICharacterManager } from "../Character/Interface";
import { IPubSub } from "../PubSub/Interface";
import { IRaidManager } from "../Raid/Interface";
const fetch = require('node-fetch') const fetch = require('node-fetch')
const xml2js = require('xml2js'); const xml2js = require('xml2js');
@@ -28,6 +30,12 @@ implements FrontworkComponent<ItemManagerIfc, ItemManagerFeatureIfc>, TableDefin
@Inject(ICharacterManager) @Inject(ICharacterManager)
private character: ICharacterManager private character: ICharacterManager
@Inject(IPubSub)
private pubsub: IPubSub<any>
@Inject(IRaidManager)
private raidManager: IRaidManager
exportRPCs = () => [ exportRPCs = () => [
this.getItems, this.getItems,
this.getItem, this.getItem,
@@ -51,6 +59,16 @@ implements FrontworkComponent<ItemManagerIfc, ItemManagerFeatureIfc>, TableDefin
] ]
}] }]
notifyRaid = async (raid:Raid | {id:number}) => {
const data = await this.raidManager.getRaidData(<Raid>raid)
this.pubsub.publish(""+raid.id, data)
await this.notifyRaids()
}
notifyRaids = async () => {
this.pubsub.publish('raids', undefined)
}
wipeCurrencyAndItems = async () => { wipeCurrencyAndItems = async () => {
await Promise.all([ await Promise.all([
this.userManager.wipeCurrency(), this.userManager.wipeCurrency(),
@@ -146,7 +164,6 @@ implements FrontworkComponent<ItemManagerIfc, ItemManagerFeatureIfc>, TableDefin
if(streaks.length > 0){ if(streaks.length > 0){
const myStreak = streaks.find(token => token.itemname === itemname) const myStreak = streaks.find(token => token.itemname === itemname)
if(myStreak){ if(myStreak){
//getLogger('ItemManager').debug('update signupid and increment level') //getLogger('ItemManager').debug('update signupid and increment level')
await this.admin await this.admin
.knex(item.tier+'tokens') .knex(item.tier+'tokens')
@@ -176,6 +193,8 @@ implements FrontworkComponent<ItemManagerIfc, ItemManagerFeatureIfc>, TableDefin
if(myStreak){ if(myStreak){
await tx.commit() await tx.commit()
await this.notifyRaid({id: signup.raidid})
return await this.getToken(character, item) return await this.getToken(character, item)
} }
} }
@@ -205,6 +224,8 @@ implements FrontworkComponent<ItemManagerIfc, ItemManagerFeatureIfc>, TableDefin
}) })
} }
await tx.commit() await tx.commit()
await this.notifyRaid({id: signup.raidid})
return await this.getToken(character, item) return await this.getToken(character, item)
} }
@@ -0,0 +1,7 @@
import { SubscriptionResponse } from "rpclibrary"
export class IPubSub<UpdateType>{
publish: (topic: string, p: UpdateType) => void
subscribe: (topic:string, callback: (p:UpdateType)=>any) => Promise<SubscriptionResponse>
unsubscribe: (uuid: string) => Promise<void>
}
+53
View File
@@ -0,0 +1,53 @@
import { Injectable } from "../../Injector/ServiceDecorator";
import { SubscriptionResponse, makeSubResponse, RPCExporter } from "rpclibrary";
import { IPubSub } from "./Interface";
@Injectable(IPubSub)
export class PubSub<UpdateType = any>
implements RPCExporter{
name = "PubSub"
subs : {
[topic in string]: {
[uuid in string]: (p:UpdateType)=>any
}
}= {}
exportRPCs = () => [
this.unsubscribe,
{
name: 'subscribe',
hook: this.subscribe,
onClose: (subres, rpcName) => {
this.unsubscribe(subres.uuid)
}
}
]
publish = ( topic: string, msg: UpdateType ) => {
if(!this.subs[topic]) this.subs[topic] = {}
Object.entries(this.subs[topic]).forEach(([uuid, callback]:[string, Function]) => {
try{
callback(msg)
}catch(e){
delete this.subs[topic][uuid]
}
})
}
subscribe = async (topic:string, callback:(p:UpdateType)=>any) : Promise<SubscriptionResponse<{topic: string}>> => {
const resp = makeSubResponse({
topic: topic
})
if(!this.subs[topic]) this.subs[topic] = {}
this.subs[topic][resp.uuid] = callback
return resp
}
private unsubscribe = async (uuid: string) => {
Object.entries(this.subs).forEach(([topic, submap]) => {
delete submap[uuid]
if(Object.keys(submap).length === 0)
delete this.subs[topic]
})
}
}
@@ -0,0 +1,8 @@
import { IPubSub } from "./Interface";
export type PubSubIfc<UpdateType = any> = {
PubSub:{
subscribe: IPubSub<UpdateType>['subscribe']
unsubscribe: IPubSub<UpdateType>['unsubscribe']
}
}
+226 -198
View File
@@ -9,10 +9,11 @@ import { ICharacterManager } from "../Character/Interface";
import { _Tiers } from "../../Types/Items"; import { _Tiers } from "../../Types/Items";
import { IItemManager } from "../Item/Interface"; import { IItemManager } from "../Item/Interface";
import { ItemManager } from "../Item/ItemManager"; import { ItemManager } from "../Item/ItemManager";
import { IPubSub } from "../PubSub/Interface";
@Injectable(IRaidManager) @Injectable(IRaidManager)
export class RaidManager export class RaidManager
implements FrontworkComponent<RaidManagerIfc, RaidManagerFeatureIfc>, IRaidManager{ implements FrontworkComponent<RaidManagerIfc, RaidManagerFeatureIfc>, IRaidManager {
name = "RaidManager" as "RaidManager"; name = "RaidManager" as "RaidManager";
@Inject(IAdmin) @Inject(IAdmin)
@@ -27,6 +28,9 @@ implements FrontworkComponent<RaidManagerIfc, RaidManagerFeatureIfc>, IRaidManag
@Inject(ItemManager) @Inject(ItemManager)
private itemManager: IItemManager private itemManager: IItemManager
@Inject(IPubSub)
private pubsub: IPubSub<any>
exportRPCs = () => [ exportRPCs = () => [
this.getRaids, this.getRaids,
this.getRaidData, this.getRaidData,
@@ -46,7 +50,7 @@ implements FrontworkComponent<RaidManagerIfc, RaidManagerFeatureIfc>, IRaidManag
this.startRaid, this.startRaid,
this.adminUnsign this.adminUnsign
] ]
},{ }, {
name: 'signup' as 'signup', name: 'signup' as 'signup',
exportRPCs: () => [ exportRPCs: () => [
this.getSignups, this.getSignups,
@@ -68,13 +72,13 @@ implements FrontworkComponent<RaidManagerIfc, RaidManagerFeatureIfc>, IRaidManag
table.integer('size').defaultTo(40) table.integer('size').defaultTo(40)
table.string('tier').defaultTo('null') table.string('tier').defaultTo('null')
} }
},{ }, {
name: 'archive', name: 'archive',
tableBuilder: (table) => { tableBuilder: (table) => {
table.integer('id').primary() table.integer('id').primary()
table.json('raiddata').notNullable() table.json('raiddata').notNullable()
} }
},{ }, {
name: 'signups', name: 'signups',
tableBuilder: (table) => { tableBuilder: (table) => {
table.increments('id').primary() table.increments('id').primary()
@@ -90,49 +94,61 @@ implements FrontworkComponent<RaidManagerIfc, RaidManagerFeatureIfc>, IRaidManag
] ]
} }
createRaid = async (raid:Raid) : Promise<Raid>=> { notifyRaid = async (raid:Raid | {id:number}) => {
const ids:number[] = await this.admin const data = await this.getRaidData(<Raid>raid)
.knex('raids') this.pubsub.publish(""+raid.id, data)
.insert(raid) await this.notifyRaids()
}
return await this.admin.knex('raids').where({id: ids[0]}).first() notifyRaids = async () => {
this.pubsub.publish('raids', undefined)
}
createRaid = async (raid: Raid): Promise<Raid> => {
const ids: number[] = await this.admin
.knex('raids')
.insert(raid)
await this.notifyRaid({ id: ids[0] })
return await this.admin.knex('raids').where({ id: ids[0] }).first()
} }
addSignup = async (signup: Signup) => { addSignup = async (signup: Signup) => {
const ids:number[] = await this.admin const ids: number[] = await this.admin
.knex('signups') .knex('signups')
.insert(signup) .insert(signup)
return await this.admin.knex('signups').where({id: ids[0]}).first() return await this.admin.knex('signups').where({ id: ids[0] }).first()
} }
removeSignup = async (signup: Signup) => await this.admin removeSignup = async (signup: Signup) => await this.admin
.knex('signups') .knex('signups')
.where({ .where({
raid_id: signup.raidid, raid_id: signup.raidid,
character_id: signup.characterid character_id: signup.characterid
}) })
.del() .del()
getRaids = async () : Promise<Raid[]> => { getRaids = async (): Promise<Raid[]> => {
const subQuery = this.admin const subQuery = this.admin
.knex('signups') .knex('signups')
.count('*') .count('*')
.where({ .where({
raidid: this.admin.knex.ref('raids.id'), raidid: this.admin.knex.ref('raids.id'),
benched: false, benched: false,
late: false late: false
}) })
.as('signupcount') .as('signupcount')
return await this.admin.knex('raids') return await this.admin.knex('raids')
.select('*', subQuery) .select('*', subQuery)
.orderBy('start', 'asc') .orderBy('start', 'asc')
} }
startRaid = async (raid:Raid) : Promise<RaidData> => { startRaid = async (raid: Raid): Promise<RaidData> => {
const archived = await this.archiveRaid(raid) const archived = await this.archiveRaid(raid)
const giveCurrency = async (b: Character) => { const giveCurrency = async (b: Character) => {
@@ -142,52 +158,55 @@ implements FrontworkComponent<RaidManagerIfc, RaidManagerFeatureIfc>, IRaidManag
await Promise.all([ await Promise.all([
...archived.participants.bench.map(giveCurrency), ...archived.participants.bench.map(giveCurrency),
...Object.values(archived.participants).map((group: any) => group.map(giveCurrency)) ...Object.values(archived.participants).flat().flatMap((b:Signup & Character & Spec) => giveCurrency(b))
]) ])
await this.notifyRaids()
return archived return archived
} }
archiveRaid = async (raid:Raid) : Promise<RaidData> => { archiveRaid = async (raid: Raid): Promise<RaidData> => {
const raidData = await this.getRaidData(raid) const raidData = await this.getRaidData(raid)
//const tx = await this.admin.knex.transaction() //const tx = await this.admin.knex.transaction()
await this.admin.knex('archive') await this.admin.knex('archive')
//.transacting(tx) //.transacting(tx)
.insert({ .insert({
id:raidData.id, id: raidData.id,
raiddata: JSON.stringify(raidData) raiddata: JSON.stringify(raidData)
}) })
await Promise.all( await Promise.all(
Object.values(raidData.participants).flat().flatMap((signup) => this.admin Object.values(raidData.participants).flat().flatMap((p: (Signup & Character & Spec)) =>
.knex(raid.tier+'tokens') this.admin
.knex(raid.tier + 'tokens')
//.transacting(tx) //.transacting(tx)
.where({ .where({
characterid: signup.characterid, characterid: p.characterid,
signupid: null signupid: null
}) })
.del() .del()
)) ))
await this.admin.knex('raids') await this.admin.knex('raids')
//.transacting(tx) //.transacting(tx)
.where('id', '=', raid.id) .where('id', '=', raid.id)
.del() .del()
//await tx.commit() //await tx.commit()
const row = await this.admin.knex('archive') const row = await this.admin.knex('archive')
.select('*') .select('*')
.where({ .where({
id:raidData.id, id: raidData.id,
}) })
.first() .first()
return JSON.parse(row.raiddata) return JSON.parse(row.raiddata)
} }
getArchiveRaid = async(id:number) : Promise<RaidData> => { getArchiveRaid = async (id: number): Promise<RaidData> => {
const data = await this.admin.knex('archive').select('raiddata').where({ const data = await this.admin.knex('archive').select('raiddata').where({
id: id id: id
}).first() }).first()
@@ -195,69 +214,69 @@ implements FrontworkComponent<RaidManagerIfc, RaidManagerFeatureIfc>, IRaidManag
return JSON.parse(data.raiddata) return JSON.parse(data.raiddata)
} }
getPastRaids = async(limit: number) : Promise<RaidData[]> => { getPastRaids = async (limit: number): Promise<RaidData[]> => {
const raids = await this.admin.knex('archive') const raids = await this.admin.knex('archive')
.select('*') .select('*')
.orderBy('id', 'desc') .orderBy('id', 'desc')
.limit(limit) .limit(limit)
return raids.map(raid => JSON.parse(raid.raiddata)) return raids.map(raid => JSON.parse(raid.raiddata))
} }
getRaidData = async (raid:Raid) : Promise<RaidData> => { getRaidData = async (raid: Raid): Promise<RaidData> => {
const raiddata = { const raiddata = {
participants:{ participants: {
Druid: <(Signup&Character&Spec)[]>[], Druid: <(Signup & Character & Spec)[]>[],
Hunter: <(Signup&Character&Spec)[]>[], Hunter: <(Signup & Character & Spec)[]>[],
Mage: <(Signup&Character&Spec)[]>[], Mage: <(Signup & Character & Spec)[]>[],
Paladin: <(Signup&Character&Spec)[]>[], Paladin: <(Signup & Character & Spec)[]>[],
Priest: <(Signup&Character&Spec)[]>[], Priest: <(Signup & Character & Spec)[]>[],
Rogue: <(Signup&Character&Spec)[]>[], Rogue: <(Signup & Character & Spec)[]>[],
Shaman: <(Signup&Character&Spec)[]>[], Shaman: <(Signup & Character & Spec)[]>[],
Warlock: <(Signup&Character&Spec)[]>[], Warlock: <(Signup & Character & Spec)[]>[],
Warrior: <(Signup&Character&Spec)[]>[], Warrior: <(Signup & Character & Spec)[]>[],
late: <(Signup&Character&Spec)[]>[], late: <(Signup & Character & Spec)[]>[],
bench: <(Signup&Character&Spec)[]>[], bench: <(Signup & Character & Spec)[]>[],
}, },
tokens:{}, tokens: {},
healers:<(Signup&Character&Spec)[]>[], healers: <(Signup & Character & Spec)[]>[],
tanks:<(Signup&Character&Spec)[]>[] tanks: <(Signup & Character & Spec)[]>[]
} }
//const tx = await this.admin.knex.transaction() //const tx = await this.admin.knex.transaction()
const subQuery = this.admin const subQuery = this.admin
.knex('signups') .knex('signups')
.count('*') .count('*')
.where({ .where({
raidid: this.admin.knex.ref('raids.id'), raidid: this.admin.knex.ref('raids.id'),
benched: false, benched: false,
late: false late: false
}) })
.as('signupcount') .as('signupcount')
const raidInDb: Raid = await this.admin.knex('raids') const raidInDb: Raid = await this.admin.knex('raids')
.select('*', subQuery) .select('*', subQuery)
//.transacting(tx) //.transacting(tx)
.where('id','=',raid.id) .where('id', '=', raid.id)
.first() .first()
const characterData: (Signup & Character & Spec)[] = await this.admin const characterData: (Signup & Character & Spec)[] = await this.admin
.knex('signups as s') .knex('signups as s')
//.transacting(tx) //.transacting(tx)
.select('s.id as id', 'charactername', 'class', 'specid', 'specname', 'race', 'userid', 'benched', 'late', 'raidid', 'characterid', 'specid') .select('s.id as id', 'charactername', 'class', 'specid', 'specname', 'race', 'userid', 'benched', 'late', 'raidid', 'characterid', 'specid')
.join('raids as r', 's.raidid','=','r.id') .join('raids as r', 's.raidid', '=', 'r.id')
.join('characters as c', 's.characterid','=','c.id') .join('characters as c', 's.characterid', '=', 'c.id')
.join('users as u', 'c.userid','=','u.id') .join('users as u', 'c.userid', '=', 'u.id')
.join('specs as sp', 'specid','=','sp.id') .join('specs as sp', 'specid', '=', 'sp.id')
.where('r.id','=',raid.id) .where('r.id', '=', raid.id)
characterData.forEach(data => { characterData.forEach(data => {
if(data.benched){ if (data.benched) {
raiddata.participants.bench.push(data) raiddata.participants.bench.push(data)
return return
} }
if(data.late){ if (data.late) {
raiddata.participants.late.push(data) raiddata.participants.late.push(data)
return return
} }
@@ -265,42 +284,42 @@ implements FrontworkComponent<RaidManagerIfc, RaidManagerFeatureIfc>, IRaidManag
}) })
const tokenData: (Character & SRToken & Item)[] = await this.admin const tokenData: (Character & SRToken & Item)[] = await this.admin
.knex('signups as s') .knex('signups as s')
//.transacting(tx) //.transacting(tx)
.select('*', 's.id as id') .select('*', 's.id as id')
.join('raids as r', 's.raidid','=','r.id') .join('raids as r', 's.raidid', '=', 'r.id')
.join('characters as c', 's.characterid','=','c.id') .join('characters as c', 's.characterid', '=', 'c.id')
.join(raidInDb.tier+'tokens as t', 't.characterid','=','c.id') .join(raidInDb.tier + 'tokens as t', 't.characterid', '=', 'c.id')
.join('items as i', 'i.itemname','=','t.itemname') .join('items as i', 'i.itemname', '=', 't.itemname')
.where({ .where({
'r.id': raid.id, 'r.id': raid.id,
}) })
.andWhere(function(){ .andWhere(function () {
this.whereNotNull('t.signupid') this.whereNotNull('t.signupid')
}) })
//await tx.commit() //await tx.commit()
tokenData.forEach(data => { tokenData.forEach(data => {
if(!raiddata.tokens[data.itemname]) if (!raiddata.tokens[data.itemname])
raiddata.tokens[data.itemname] = [] raiddata.tokens[data.itemname] = []
raiddata.tokens[data.itemname].push(data) raiddata.tokens[data.itemname].push(data)
}) })
raiddata.tanks = Object.values(raiddata.participants).flatMap( raiddata.tanks = Object.values(raiddata.participants).flatMap(
(tanks:any[]) => tanks.filter((p:any) => (tanks: any[]) => tanks.filter((p: any) =>
!p.benched !p.benched
&& !p.late && !p.late
&& (p.specname==="Protection" && (p.specname === "Protection"
|| p.specname==="Feral (Tank)")) || p.specname === "Feral (Tank)"))
) )
raiddata.healers = Object.values(raiddata.participants).flatMap( raiddata.healers = Object.values(raiddata.participants).flatMap(
(healers:any[]) => healers.filter((p:any) => (healers: any[]) => healers.filter((p: any) =>
!p.benched !p.benched
&& !p.late && !p.late
&& (p.specname==="Holy" && (p.specname === "Holy"
|| p.specname==="Discipline" || p.specname === "Discipline"
|| p.specname==="Restoration")) || p.specname === "Restoration"))
) )
return { return {
@@ -309,127 +328,136 @@ implements FrontworkComponent<RaidManagerIfc, RaidManagerFeatureIfc>, IRaidManag
} }
} }
getSignups = async (raid:Raid) : Promise<(Signup & Character & Spec & User)[]> => await this.admin getSignups = async (raid: Raid): Promise<(Signup & Character & Spec & User)[]> => await this.admin
.knex('signups as si') .knex('signups as si')
.join('characters as c', 'c.id', '=', 'characterid') .join('characters as c', 'c.id', '=', 'characterid')
.join('specs as s', 's.id', '=', 'specid') .join('specs as s', 's.id', '=', 'specid')
.join('users as u', 'u.id', '=', 'userid') .join('users as u', 'u.id', '=', 'userid')
.select('*','si.id as id') .select('*', 'si.id as id')
.where('raidid', '=', raid.id!) .where('raidid', '=', raid.id!)
sign = async (usertoken:string, character:Character, raid:Raid, late:boolean) => { sign = async (usertoken: string, character: Character, raid: Raid, late: boolean) => {
const maybeUserRecord = this.userManager.getUserRecordByToken(usertoken) const maybeUserRecord = this.userManager.getUserRecordByToken(usertoken)
if(!maybeUserRecord || maybeUserRecord.user.id != character.userid){ if (!maybeUserRecord || maybeUserRecord.user.id != character.userid) {
throw new Error("Bad Usertoken") throw new Error("Bad Usertoken")
} }
//const tx = await this.admin.knex.transaction() //const tx = await this.admin.knex.transaction()
const exists = await this.admin const exists = await this.admin
.knex('signups')
//.transacting(tx)
.select('*')
.where({
raidid: raid.id!,
characterid: character.id!,
})
.first()
if(!exists){
await this.admin
.knex('signups')
//.transacting(tx)
.insert({
raidid: raid.id!,
characterid: character.id!,
late: late,
benched: false,
})
}else{
await this.admin
.knex('signups') .knex('signups')
//.transacting(tx) //.transacting(tx)
.select('*')
.where({ .where({
id: exists.id
})
.update({
raidid: raid.id!, raidid: raid.id!,
characterid: character.id!, characterid: character.id!,
late: late,
benched: false,
}) })
.first()
if (!exists) {
await this.admin
.knex('signups')
//.transacting(tx)
.insert({
raidid: raid.id!,
characterid: character.id!,
late: late,
benched: false,
})
} else {
await this.admin
.knex('signups')
//.transacting(tx)
.where({
id: exists.id
})
.update({
raidid: raid.id!,
characterid: character.id!,
late: late,
benched: false,
})
} }
//await tx.commit() //await tx.commit()
await this.notifyRaid(raid)
return await this.admin return await this.admin
.knex('signups') .knex('signups')
.select('*') .select('*')
.where({ .where({
raidid: raid.id!, raidid: raid.id!,
characterid: character.id!, characterid: character.id!,
}) })
.first() .first()
} }
unsign = async (usertoken:string, character:Character, raid:Raid) => { unsign = async (usertoken: string, character: Character, raid: Raid) => {
const maybeUserRecord = this.userManager.getUserRecordByToken(usertoken) const maybeUserRecord = this.userManager.getUserRecordByToken(usertoken)
if(!maybeUserRecord || maybeUserRecord.user.id != character.userid){ if (!maybeUserRecord || maybeUserRecord.user.id != character.userid) {
throw new Error("Bad Usertoken") throw new Error("Bad Usertoken")
} }
return await this.adminUnsign(character, raid) return await this.adminUnsign(character, raid)
} }
adminUnsign = async (character:Character, raid:Raid) => { adminUnsign = async (character: Character, raid: Raid) => {
const user = await this.characterManager.getUserOfCharacter(character) const user = await this.characterManager.getUserOfCharacter(character)
const signup = await this.admin.knex('signups as si') const signup = await this.admin.knex('signups as si')
.where({ .where({
"si.raidid": raid.id!, "si.raidid": raid.id!,
"si.characterid": character.id!, "si.characterid": character.id!,
}).first() }).first()
const tokens = await this.admin.knex(raid.tier+'tokens as t') const tokens = await this.itemManager.getTokens(character, [raid.tier], true)
.where('t.signupid', signup.id)
//check if token has to be deleted //check if token has to be deleted
Promise.all( if (tokens) {
tokens.map(async token => { Promise.all(
await this.userManager.incrementCurrency(user, raid.tier, 1) tokens.map(async token => {
const prio = await this.itemManager.calculatePriorities(token.itemname, character) await this.userManager.incrementCurrency(user, raid.tier, 1)
if(token.level <= prio+1){ const prio = await this.itemManager.calculatePriorities(token.itemname, character)
await this.admin.knex(raid.tier+'tokens') if (token.level <= prio + 1) {
.where({ await this.admin
characterid: character.id, .knex(raid.tier + 'tokens')
itemname: token.itemname .where({
}).del() characterid: character.id,
}else{ itemname: token.itemname
await this.admin.knex(raid.tier+'tokens') }).del()
.where({ } else {
characterid: character.id, await this.admin
itemname: token.itemname .knex(raid.tier + 'tokens')
}).update({ .where({
signupid: null, characterid: character.id,
level: token.level-1 itemname: token.itemname
}) }).update({
} signupid: null,
}) level: token.level - 1
) })
}
})
)
}
await this.admin.knex('signups') await this.admin.knex('signups')
.where({ .where({
raidid: raid.id!, raidid: raid.id!,
characterid: character.id!, characterid: character.id!,
}) })
.del() .del()
await this.notifyRaid(raid)
} }
setBenched = async (signup: Signup) : Promise<void> => { setBenched = async (signup: Signup): Promise<void> => {
await this.admin.knex('signups') await this.admin.knex('signups')
.where({ .where({
raidid: signup.raidid, raidid: signup.raidid,
characterid: signup.characterid characterid: signup.characterid
}) })
.update(signup) .update(signup)
await this.notifyRaid({ id: signup.raidid })
} }
} }
@@ -455,6 +455,4 @@ implements FrontworkComponent<UserManagerIfc, UserManagerFeatureIfc>, IUserManag
.where('id', '=', user.id) .where('id', '=', user.id)
.update(tier, value) .update(tier, value)
} }
} }
+2 -1
View File
@@ -1,6 +1,7 @@
import { Injector } from "./Injector"; import { Injector } from "./Injector";
import { Type, GenericClassDecorator } from "./Util"; import { Type, GenericClassDecorator } from "./Util";
import { FrontworkComponent } from "../Types/FrontworkComponent"; import { FrontworkComponent } from "../Types/FrontworkComponent";
import { RPCExporter } from "rpclibrary";
/** /**
* @returns {GenericClassDecorator<Type<any>>} * @returns {GenericClassDecorator<Type<any>>}
@@ -21,7 +22,7 @@ export const Injectable = (_interface?: Type<any>) : GenericClassDecorator<Type<
*/ */
export const RootComponent = (config : { export const RootComponent = (config : {
injectable : Type<any> injectable : Type<any>
injects : Type<FrontworkComponent>[] injects : Type<RPCExporter>[]
}) : GenericClassDecorator<Type<any>> => { }) : GenericClassDecorator<Type<any>> => {
return (target: Type<any>) => { return (target: Type<any>) => {
Injector.rootModules = config.injects Injector.rootModules = config.injects
+2
View File
@@ -7,6 +7,7 @@ import { ItemManagerFeatureIfc, ItemManagerIfc } from "../Components/Item/RPCInt
import { GuildManagerFeatureIfc, GuildManagerIfc } from "../Components/Guild/RPCInterface"; import { GuildManagerFeatureIfc, GuildManagerIfc } from "../Components/Guild/RPCInterface";
import { ShoutboxIfc } from "../Components/Shoutbox/RPCInterface"; import { ShoutboxIfc } from "../Components/Shoutbox/RPCInterface";
import { Tiers } from "./Items"; import { Tiers } from "./Items";
import { PubSubIfc } from "../Components/PubSub/RPCInterface";
export type FrontcraftIfc = RaidManagerIfc export type FrontcraftIfc = RaidManagerIfc
& UserManagerIfc & UserManagerIfc
@@ -14,6 +15,7 @@ export type FrontcraftIfc = RaidManagerIfc
& ItemManagerIfc & ItemManagerIfc
& GuildManagerIfc & GuildManagerIfc
& ShoutboxIfc & ShoutboxIfc
& PubSubIfc
export type FrontcraftFeatureIfc = RaidManagerFeatureIfc export type FrontcraftFeatureIfc = RaidManagerFeatureIfc
& UserManagerFeatureIfc & UserManagerFeatureIfc
+3 -3
View File
@@ -14269,9 +14269,9 @@
"integrity": "sha512-ZYzRkETgBrdEGzL5JSKimvjI2CX7ioyZCkX2BpcfyjqI+079W0wHAyj5W4rIZMcDSOHgLZtgz1IdDi/vU77KEQ==" "integrity": "sha512-ZYzRkETgBrdEGzL5JSKimvjI2CX7ioyZCkX2BpcfyjqI+079W0wHAyj5W4rIZMcDSOHgLZtgz1IdDi/vU77KEQ=="
}, },
"rpclibrary": { "rpclibrary": {
"version": "1.6.2", "version": "1.7.1",
"resolved": "https://registry.npmjs.org/rpclibrary/-/rpclibrary-1.6.2.tgz", "resolved": "https://registry.npmjs.org/rpclibrary/-/rpclibrary-1.7.1.tgz",
"integrity": "sha512-lQTU4XkB9CSHz7YgtAcpVfyR5XrmTRX4P4eQjK6DDUjqKSFvJb5ChXjHnt1BcaNWbJ2VqmhCNVbcoyunJ2u7Rg==", "integrity": "sha512-Ibo3qfURnQgZAq0eA2o+L9+PWaloJ4PHZs4ak42LL9fRgdWZXn33HAtowV0K2HVckbvrBvFqj/+PWTrWWBSOeg==",
"requires": { "requires": {
"bsock": "^0.1.9", "bsock": "^0.1.9",
"http": "0.0.0", "http": "0.0.0",
+1 -1
View File
@@ -69,7 +69,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": "^1.6.2", "rpclibrary": "^1.7.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",
@@ -1,213 +1,172 @@
<nb-card class="col-12 col-xl-9"> <div class="row">
<nb-card-body> <div class="col-12 col-xl-6">
<nb-tabset> <nb-card [size]="giant">
<nb-tab tabTitle="Info"> <nb-card-body>
<h1> <nb-tabset>
<img [src]="'../../../../assets/images/'+(raid.tier || 'null').toLowerCase()+'.png'" style="height: 100px" /> <nb-tab tabTitle="Info">
{{raid.title}} <h1>
</h1> <img [src]="'../../../../assets/images/'+(raid.tier || 'null').toLowerCase()+'.png'"
<p> style="height: 100px" />
{{raid.signupcount}} / {{raid.size}} signups {{raid.title}}
</p> </h1>
<p>
{{raid.description}}
</p>
<div *ngIf="canSignup">
<div *ngIf="isSignedup">
<p> <p>
You are signed as: {{mySignup.charactername}} ({{mySignup.race}} {{mySignup.specname}} {{mySignup.class}})<br /> {{raid.signupcount}} / {{raid.size}} signups
Status: {{mySignup.status}}
</p> </p>
<p>
{{raid.description}}
</p>
<div *ngIf="canSignup">
<div *ngIf="isSignedup">
<button <p>
(click)="setLate(true)" You are signed as: {{mySignup.charactername}} ({{mySignup.race}}
*ngIf="mySignup.status !== 'Late'" {{mySignup.specname}}
nbButton {{mySignup.class}})<br />
outline Status: {{mySignup.status}}
status="warning" </p>
size="medium">
<nb-icon icon="clock-outline"></nb-icon> Late
</button>
<button
(click)="setLate(false)"
*ngIf="mySignup.status === 'Late'"
nbButton
outline
status="success"
size="medium">
<nb-icon icon="checkmark-outline"></nb-icon> On Time
</button>
<button
(click)="unsign()"
nbButton
outline
status="danger"
size="medium">
<nb-icon icon="close"></nb-icon>unsign
</button>
</div>
<div *ngIf="!isSignedup">
<button
(click)="signup()"
nbButton
outline
status="success"
size="medium">
<nb-icon icon="person-done-outline"></nb-icon> sign up
</button>
</div>
</div>
</nb-tab>
<nb-tab tabTitle="Signups" <button (click)="setLate(true)" *ngIf="mySignup.status !== 'Late'" nbButton outline
[badgeText]="raid.signupcount" status="warning" size="medium">
badgePosition="top right" <nb-icon icon="clock-outline"></nb-icon> Late
[badgeStatus]="raid.signupcount<40?'warning':'success'">
<div class="row">
<nb-card
class="col-12 col-md-6"
*ngIf="raid.tanks.length > 0">
<nb-card-header>Tanks ({{raid.tanks.length}})</nb-card-header>
<nb-card-body>
<div *ngFor="let participant of raid.tanks">
<button
(click)="setBench(participant)"
*ngIf="manageRaid"
nbButton
outline
status="warning"
size="tiny">
B
</button> </button>
<button <button (click)="setLate(false)" *ngIf="mySignup.status === 'Late'" nbButton outline
(click)="adminUnsign(participant)" status="success" size="medium">
*ngIf="manageRaid" <nb-icon icon="checkmark-outline"></nb-icon> On Time
nbButton </button>
outline <button (click)="unsign()" nbButton outline status="danger" size="medium">
status="danger" <nb-icon icon="close"></nb-icon>unsign
size="tiny">
X
</button> </button>
<a [ngStyle]="{'color': participant.color}" style="text-transform: capitalize;"
[routerLink]="'/frontcraft/character/'+participant.charactername">
<img style="width:20px; height:20px" [src]="'../../../../assets/images/'+participant.race.toLowerCase()+'_xs.gif'" />
<img style="width:20px; height:20px" [src]="'../../../../assets/images/'+participant.class.toLowerCase()+'.png'" />
{{ participant.charactername }}
</a>
</div> </div>
</nb-card-body> <div *ngIf="!isSignedup">
</nb-card> <button (click)="signup()" nbButton outline status="success" size="medium">
<nb-icon icon="person-done-outline"></nb-icon> sign up
<nb-card
class="col-12 col-md-6"
*ngIf="raid.tanks.length > 0">
<nb-card-header>Healers ({{raid.healers.length}})</nb-card-header>
<nb-card-body>
<div *ngFor="let participant of raid.healers">
<button
(click)="setBench(participant)"
*ngIf="manageRaid"
nbButton
outline
status="warning"
size="tiny">
B
</button> </button>
<button
(click)="adminUnsign(participant)"
*ngIf="manageRaid"
nbButton
outline
status="danger"
size="tiny">
X
</button>
<a [ngStyle]="{'color': participant.color}" style="text-transform: capitalize;"
[routerLink]="'/frontcraft/character/'+participant.charactername">
<img style="width:20px; height:20px" [src]="'../../../../assets/images/'+participant.race.toLowerCase()+'_xs.gif'" />
<img style="width:20px; height:20px" [src]="'../../../../assets/images/'+participant.class.toLowerCase()+'.png'" />
{{ participant.charactername }}
</a>
</div>
</nb-card-body>
</nb-card>
<ng-container *ngFor="let group of raid.participants | keyvalue">
<nb-card
class="col-12 col-md-6 col-xl-4"
*ngIf="group.value.length > 0">
<nb-card-header>{{group.key}} ({{group.value.length}})</nb-card-header>
<nb-card-body>
<div *ngFor="let participant of group.value">
<button
(click)="setBench(participant)"
*ngIf="manageRaid"
nbButton
outline
status="warning"
size="tiny">
B
</button>
<button
(click)="adminUnsign(participant)"
*ngIf="manageRaid"
nbButton
outline
status="danger"
size="tiny">
X
</button>
<a [ngStyle]="{'color': participant.color}" style="text-transform: capitalize;"
[routerLink]="'/frontcraft/character/'+participant.charactername">
<img style="width:20px; height:20px" [src]="'../../../../assets/images/'+participant.race.toLowerCase()+'_xs.gif'" />
<img style="width:20px; height:20px" [src]="'../../../../assets/images/'+participant.class.toLowerCase()+'.png'" />
{{ participant.charactername }}
</a>
</div>
</nb-card-body>
</nb-card>
</ng-container>
</div>
</nb-tab>
<nb-tab tabTitle="Items" *ngIf="isSignedup && isTier">
<shop [tier]="raid.tier" (onSelect)="itemSelect($event)"></shop>
</nb-tab>
<nb-tab tabTitle="Reserves" *ngIf="isTier">
<input type="text" nbInput [(ngModel)]="search" (change)="changeSearch()" placeholder="Search" fullWidth="true">
<nb-list>
<nb-list-item *ngFor="let item of displayedtokens | keyvalue">
<a [ngStyle]="{'color':item.value[0].quality=='Epic'?'#a335ee':'#ff8000'}"
target="_blank"
[href]="item.value[0].url">
<img style="min-width: 25px; width: 2.25vw; max-width: 50px"
[src]="'https://wow.zamimg.com/images/wow/icons/large/'+item.value[0].iconname+'.jpg'" />
&nbsp;
{{item.key}}
</a><br />
<div class="row">
<div *ngFor="let token of item.value" class="col-12 col-md-6 col-xl-4">
[ {{token.level}} ]
<span style="text-transform: capitalize;" [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}}
</span><br />
</div> </div>
</div> </div>
</nb-list-item> </nb-tab>
</nb-list> <nb-tab tabTitle="Signups" [badgeText]="raid.signupcount" badgePosition="top right"
</nb-tab> [badgeStatus]="raid.signupcount<40?'warning':'success'">
<nb-tab tabTitle="Admin" *ngIf="manageRaid">
<button
(click)="startRaid(raid)"
nbButton
outline
status="success"
size="medium">
start
</button>
</nb-tab>
</nb-tabset>
</nb-card-body>
</nb-card>
<div class="row">
<nb-card class="col-12 col-md-6" *ngIf="raid.tanks.length > 0">
<nb-card-header>Tanks ({{raid.tanks.length}})</nb-card-header>
<nb-card-body>
<div *ngFor="let participant of raid.tanks">
<button (click)="setBench(participant)" *ngIf="manageRaid" nbButton outline
status="warning" size="tiny">
B
</button>
<button (click)="adminUnsign(participant)" *ngIf="manageRaid" nbButton outline
status="danger" size="tiny">
X
</button>
<a [ngStyle]="{'color': participant.color}" style="text-transform: capitalize;"
[routerLink]="'/frontcraft/character/'+participant.charactername">
<img style="width:20px; height:20px"
[src]="'../../../../assets/images/'+participant.race.toLowerCase()+'_xs.gif'" />
<img style="width:20px; height:20px"
[src]="'../../../../assets/images/'+participant.class.toLowerCase()+'.png'" />
{{ participant.charactername }}
</a>
</div>
</nb-card-body>
</nb-card>
<nb-card class="col-12 col-md-6" *ngIf="raid.tanks.length > 0">
<nb-card-header>Healers ({{raid.healers.length}})</nb-card-header>
<nb-card-body>
<div *ngFor="let participant of raid.healers">
<button (click)="setBench(participant)" *ngIf="manageRaid" nbButton outline
status="warning" size="tiny">
B
</button>
<button (click)="adminUnsign(participant)" *ngIf="manageRaid" nbButton outline
status="danger" size="tiny">
X
</button>
<a [ngStyle]="{'color': participant.color}" style="text-transform: capitalize;"
[routerLink]="'/frontcraft/character/'+participant.charactername">
<img style="width:20px; height:20px"
[src]="'../../../../assets/images/'+participant.race.toLowerCase()+'_xs.gif'" />
<img style="width:20px; height:20px"
[src]="'../../../../assets/images/'+participant.class.toLowerCase()+'.png'" />
{{ participant.charactername }}
</a>
</div>
</nb-card-body>
</nb-card>
<ng-container *ngFor="let group of raid.participants | keyvalue">
<nb-card class="col-12 col-md-6 col-xl-4" *ngIf="group.value.length > 0">
<nb-card-header>{{group.key}} ({{group.value.length}})</nb-card-header>
<nb-card-body>
<div *ngFor="let participant of group.value">
<button (click)="setBench(participant)" *ngIf="manageRaid" nbButton outline
status="warning" size="tiny">
B
</button>
<button (click)="adminUnsign(participant)" *ngIf="manageRaid" nbButton
outline status="danger" size="tiny">
X
</button>
<a [ngStyle]="{'color': participant.color}"
style="text-transform: capitalize;"
[routerLink]="'/frontcraft/character/'+participant.charactername">
<img style="width:20px; height:20px"
[src]="'../../../../assets/images/'+participant.race.toLowerCase()+'_xs.gif'" />
<img style="width:20px; height:20px"
[src]="'../../../../assets/images/'+participant.class.toLowerCase()+'.png'" />
{{ participant.charactername }}
</a>
</div>
</nb-card-body>
</nb-card>
</ng-container>
</div>
</nb-tab>
<nb-tab tabTitle="Admin" *ngIf="manageRaid">
<button (click)="startRaid(raid)" nbButton outline status="success" size="medium">
start
</button>
</nb-tab>
</nb-tabset>
</nb-card-body>
</nb-card>
</div>
<div class="col-12 col-xl-6">
<nb-card *ngIf="isTier">
<nb-card-body>
<nb-tabset>
<nb-tab tabTitle="Reserves">
<input type="text" nbInput [(ngModel)]="search" (change)="changeSearch()" placeholder="Search"
fullWidth="true">
<nb-list>
<nb-list-item *ngFor="let item of displayedtokens | keyvalue">
<a [ngStyle]="{'color':item.value[0].quality=='Epic'?'#a335ee':'#ff8000'}"
target="_blank" [href]="item.value[0].url">
<img style="min-width: 25px; width: 2.25vw; max-width: 50px"
[src]="'https://wow.zamimg.com/images/wow/icons/large/'+item.value[0].iconname+'.jpg'" />
&nbsp;
{{item.key}}
</a><br />
<div class="row">
<div *ngFor="let token of item.value" class="col-12 col-md-6 col-xl-4">
[ {{token.level}} ]
<span style="text-transform: capitalize;"
[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}}
</span><br />
</div>
</div>
</nb-list-item>
</nb-list>
</nb-tab>
<nb-tab tabTitle="Items" *ngIf="isSignedup">
<shop [tier]="raid.tier" (onSelect)="itemSelect($event)"></shop>
</nb-tab>
</nb-tabset>
</nb-card-body>
</nb-card>
</div>
</div>
@@ -1,5 +1,5 @@
import { Component, OnInit } from '@angular/core'; import { Component, OnInit, OnDestroy } from '@angular/core';
import { ActivatedRoute, Router } from '@angular/router'; import { ActivatedRoute, Router, NavigationStart } from '@angular/router';
import { ApiService as ApiService } from '../../services/login-api'; import { ApiService as ApiService } from '../../services/login-api';
import { RaidData, Raid, Signup, Character, Spec, Item, SRToken } from '../../../../../../backend/Types/Types'; import { RaidData, Raid, Signup, Character, Spec, Item, SRToken } from '../../../../../../backend/Types/Types';
import { NbWindowService, NbToastrService, NbDialogService } from '@nebular/theme'; import { NbWindowService, NbToastrService, NbDialogService } from '@nebular/theme';
@@ -12,7 +12,7 @@ import { allItems } from '../../../../../../backend/Types/Items';
selector: 'raid', selector: 'raid',
templateUrl: './raid.component.html', templateUrl: './raid.component.html',
}) })
export class FrontcraftRaidComponent implements OnInit{ export class FrontcraftRaidComponent implements OnInit, OnDestroy{
canSignup = false canSignup = false
isSignedup = false isSignedup = false
@@ -41,6 +41,7 @@ export class FrontcraftRaidComponent implements OnInit{
tokens = {} tokens = {}
displayedtokens = {} displayedtokens = {}
search = "" search = ""
uuid
constructor( constructor(
private api: ApiService, private api: ApiService,
@@ -50,6 +51,16 @@ export class FrontcraftRaidComponent implements OnInit{
private toast: NbToastrService private toast: NbToastrService
){ ){
window['r'] = this window['r'] = this
router.events.subscribe(event => {
if (event instanceof NavigationStart) {
this.ngOnDestroy()
}
})
}
ngOnDestroy = () => {
if(this.uuid)
this.api.get('PubSub').unsubscribe(this.uuid)
} }
async ngOnInit(){ async ngOnInit(){
@@ -60,9 +71,16 @@ export class FrontcraftRaidComponent implements OnInit{
if(signupFeature){ if(signupFeature){
this.canSignup = true this.canSignup = true
} }
this.refresh() await this.refresh()
const res = await this.api.get('PubSub').subscribe(""+this.raid.id!, (data: RaidData) => {
this.display(data)
})
this.uuid = res.uuid
} }
itemSelect = async(item) => { itemSelect = async(item) => {
this.dialogService.open(FrontcraftBuyTokenComponent, { this.dialogService.open(FrontcraftBuyTokenComponent, {
context: { context: {
@@ -71,7 +89,7 @@ export class FrontcraftRaidComponent implements OnInit{
tier: this.raid.tier, tier: this.raid.tier,
characterName: this.mySignup.charactername characterName: this.mySignup.charactername
} }
}).onClose.subscribe(() => this.refresh()) })
} }
signup = async () => { signup = async () => {
@@ -84,9 +102,7 @@ export class FrontcraftRaidComponent implements OnInit{
context: { context: {
raid: this.raid, raid: this.raid,
} }
}).onClose.subscribe(()=>{ })
this.refresh()
});
} }
async archiveRaid(raid:Raid){ async archiveRaid(raid:Raid){
@@ -110,7 +126,6 @@ export class FrontcraftRaidComponent implements OnInit{
id: this.mySignup.characterid, id: this.mySignup.characterid,
}, this.raid) }, this.raid)
this.toast.show('Success', 'Unsigned', { status: 'success' }) this.toast.show('Success', 'Unsigned', { status: 'success' })
this.refresh()
} }
setLate = async (value:boolean) => { setLate = async (value:boolean) => {
@@ -123,7 +138,6 @@ export class FrontcraftRaidComponent implements OnInit{
id: this.mySignup.characterid, id: this.mySignup.characterid,
}, this.raid, value) }, this.raid, value)
this.toast.show('Signup', 'Success', { status: 'success' }) this.toast.show('Signup', 'Success', { status: 'success' })
this.refresh()
} }
adminUnsign = async() => { adminUnsign = async() => {
@@ -133,7 +147,6 @@ export class FrontcraftRaidComponent implements OnInit{
...this.mySignup, ...this.mySignup,
id: this.mySignup.characterid, id: this.mySignup.characterid,
}, this.raid) }, this.raid)
this.refresh()
} }
refresh = async () => { refresh = async () => {
@@ -143,6 +156,11 @@ export class FrontcraftRaidComponent implements OnInit{
const raiddata = await raidManager.getRaidData(<any>{ const raiddata = await raidManager.getRaidData(<any>{
id: param id: param
}) })
this.display(raiddata)
}
display = async (raiddata:RaidData) => {
this.isTier = allItems[raiddata.tier] != null this.isTier = allItems[raiddata.tier] != null
this.raid = raiddata this.raid = raiddata
@@ -16,24 +16,31 @@
class="raidlist" class="raidlist"
style="cursor: pointer;"> style="cursor: pointer;">
<div class="row"> <div class="row">
<div class="col-2"> <img [src]="'../../../../assets/images/'+(raid.tier || 'null').toLowerCase()+'.png'"
<img [src]="'../../../../assets/images/'+(raid.tier || 'null').toLowerCase()+'.png'" style="height: 75px" /> style="object-fit: contain"
</div> class="col-1 col-s-3" />
<div class="col-2 vcenter"> <div class="col-11 col-s-9" >
{{raid.title}} <div class="row">
</div> <div class="col-12" style="padding-top: 5px">
<h4>
{{raid.title}}
</h4>
</div>
</div>
<div class="row" style="padding-top: 5px; padding-bottom: 5px; color:darkgray">
<div class="col-6 col-md-3">
<nb-icon icon="checkmark-circle"></nb-icon> {{raid.signupcount}} / {{raid.size}}<br>
</div>
<div class="col-2 vcenter"> <div class="col-6 col-md-3">
<nb-icon icon="checkmark-circle"></nb-icon> {{raid.signupcount}} / {{raid.size}}<br> <nb-icon icon="clock-outline"></nb-icon> {{raid.start | date : 'HH:mm'}}
</div> </div>
<div class="col-2 vcenter"> <div class="col-12 col-md-6">
<nb-icon icon="clock-outline"></nb-icon> {{raid.start | date : 'HH:mm'}} <nb-icon icon="calendar-outline"></nb-icon> {{raid.start | date : 'EEE MMM d'}}
</div> </div>
</div>
<div class="col-4 vcenter">
<nb-icon icon="calendar-outline"></nb-icon> {{raid.start | date : 'EEEE MMMM d'}}
</div> </div>
</div> </div>
</nb-list-item> </nb-list-item>
@@ -10,7 +10,14 @@
background-color: #293259; background-color: #293259;
} }
.vcenter { .raid {
height: 75px; height: 75px
padding-top: 30px; }
.row {
margin: -0.5rem;
}
h4 {
font-weight: normal
} }
@@ -1,30 +1,48 @@
import { Component, OnInit } from '@angular/core'; import { Component, OnInit, OnDestroy } from '@angular/core';
import { ApiService } from '../../services/login-api'; import { ApiService } from '../../services/login-api';
import { NbWindowService, NbDialogService } from '@nebular/theme'; import { NbWindowService, NbDialogService } from '@nebular/theme';
import { FrontcraftCreateRaidsComponent } from './createraid.compontent'; import { FrontcraftCreateRaidsComponent } from './createraid.compontent';
import { Router, NavigationStart } from '@angular/router';
@Component({ @Component({
selector: 'raids', selector: 'raids',
templateUrl: 'raids.component.html', templateUrl: 'raids.component.html',
styleUrls: ['raids.component.scss'], styleUrls: ['raids.component.scss'],
}) })
export class FrontcraftRaidsComponent implements OnInit{ export class FrontcraftRaidsComponent implements OnInit, OnDestroy{
manageRaid manageRaid
raids = [] raids = []
oldraids = [] oldraids = []
pageSize = 10; pageSize = 10;
uuid
constructor( constructor(
private api: ApiService, private api: ApiService,
private router: Router,
private dialogService: NbDialogService private dialogService: NbDialogService
) { ) {
this.manageRaid = this.api.get('manageRaid') this.manageRaid = this.api.get('manageRaid')
router.events.subscribe(event => {
if (event instanceof NavigationStart) {
this.ngOnDestroy()
}
})
} }
ngOnInit(): void { ngOnDestroy = () => {
console.log("boom");
if(this.uuid)
this.api.get('PubSub').unsubscribe(this.uuid)
}
async ngOnInit() {
const res = await this.api.get('PubSub').subscribe("raids", () => {
this.refresh()
})
this.uuid = res.uuid
this.refresh() this.refresh()
} }
@@ -46,9 +64,7 @@ export class FrontcraftRaidsComponent implements OnInit{
context: { context: {
templates: this.oldraids templates: this.oldraids
} }
}).onClose.subscribe(()=>{ })
this.refresh()
});
} }
} }
@@ -2,18 +2,69 @@
<nb-card-body> <nb-card-body>
<nb-tabset> <nb-tabset>
<nb-tab tabTitle="Info"> <nb-tab tabTitle="Info">
Smart text here <h3>How it works</h3>
<ul>
<li>
Everyone starts out with 1 soft reserve right per raid tier (you can see them in your user profile)
</li>
<li>
The tiers are: MC+Ony, BWL, ZG, AQ20, AQ40, Naxx
</li>
<li>
You gain 1 reserve right for a raid you attend. 2 if you were benched. Rights are granted on raid start.
</li>
<li>
When you sign up to a raid you can spend your reserve rights
</li>
<li>
Every week you can re-reserve the same item to build a streak on it
</li>
<!--
<li>
Steaks are color coded. If this means anything will be decided by guild culture:
<span style="color: #ff8000">[+ 10]</span>
<span style="color: #a335ee">[9. 8]</span>
<span style="color: #0070dd">[7, 6]</span>
<span style="color: #1eff00">[5, 4]</span>
<span style="color: #ffffff">[3, 2]</span>
<span style="color: #9d9d9d">[1]</span>
</li>
-->
</ul>
<br />
<h3>Specifics about streaks</h3>
<ul>
<li>
Some classes and races get an initial boost to specific reserves. The list is on the second tab.
</li>
<li>
Switching the selected item destroys previous streaks. (Streaks must be continued without switchup)
</li>
<li>
If you have more than 1 softreserve you can reserve multiple different items. You may only continue one streak the following raid.
</li>
<li>
If you have more than 1 softreserve you can reserve the same item several times to increase its streak.
</li>
<li>
The softreserve counter, Reserves, and Streaks are tiers-specific and only count within their tier.
</li>
<li>
Canceling the signup refunds active reserves and continued streaks. Destroyed streaks cannot be recovered.
</li>
</ul>
</nb-tab> </nb-tab>
<nb-tab tabTitle="priorities"> <nb-tab tabTitle="priorities">
<nb-list> <nb-list>
<nb-list-item *ngFor="let item of rules | keyvalue"> <nb-list-item *ngFor="let item of rules | keyvalue">
<wowhead [item]="item.value[0]"></wowhead><br> <wowhead [item]="item.value[0]"></wowhead><br>
<span *ngFor="let rule of item.value" [nbPopover]="templateRef" nbPopoverTrigger="hover"> <div class="row" *ngFor="let rule of item.value">
<ng-template #templateRef> <div class="col-4">
<span style="color:white">{{rule.description}}</span> <span *ngIf="rule.modifier>0">+</span>{{rule.modifier}} {{rule.race}} <span [ngStyle]="{'color':rule.color}">{{rule.specname}} {{rule.class}}</span>
</ng-template> </div>
<span *ngIf="rule.modifier>0">+</span>{{rule.modifier}} {{rule.race}} <span [ngStyle]="{'color':rule.color}">{{rule.specname}} {{rule.class}}</span> <br /> <div class="col-8" style="color:white"> ({{rule.description}})</div>
</span> <br />
</div>
</nb-list-item> </nb-list-item>
</nb-list> </nb-list>
</nb-tab> </nb-tab>
+260 -199
View File
@@ -1,6 +1,6 @@
import { Injector } from "../src/backend/Injector/Injector"; import { Injector } from "../src/backend/Injector/Injector";
import { FrontworkAdmin } from "../src/backend/Admin/Admin"; import { FrontworkAdmin } from "../src/backend/Admin/Admin";
import { T1 } from "../src/backend/Types/Items"; import { T1, T2, Tiers } from "../src/backend/Types/Items";
import { RPCSocket } from "rpclibrary"; import { RPCSocket } from "rpclibrary";
import { FrontcraftIfc, Auth, User, FrontcraftFeatureIfc, Raid, Character, Rank, Class, Race, SRPriority, Spec, Signup } from "../src/backend/Types/Types"; import { FrontcraftIfc, Auth, User, FrontcraftFeatureIfc, Raid, Character, Rank, Class, Race, SRPriority, Spec, Signup } from "../src/backend/Types/Types";
@@ -8,9 +8,9 @@ import { SpecT } from "../src/backend/Types/PlayerSpecs";
type protoAccount<C extends Class = Class> = { type protoAccount<C extends Class = Class> = {
name : string, name: string,
pwHash?: string pwHash?: string
rank : Rank, rank: Rank,
race: Race, race: Race,
class: C, class: C,
spec: SpecT[C] spec: SpecT[C]
@@ -39,65 +39,72 @@ const adminsOnly = {
} }
const defaultPermissions = [ const defaultPermissions = [
{ rpcname: 'signup', ...trialsAndUp {
},{ rpcname: 'reset', ...adminsOnly rpcname: 'signup', ...trialsAndUp
},{ rpcname: 'modifyPermissions', ...adminsOnly }, {
},{ rpcname: 'manageGuild', ...adminsOnly rpcname: 'reset', ...adminsOnly
},{ rpcname: 'managePriorities', ...adminsOnly }, {
},{ rpcname: 'softreserveCurrency', ...adminsOnly rpcname: 'modifyPermissions', ...adminsOnly
},{ rpcname: 'manageRaid', ...adminsOnly }, {
}] rpcname: 'manageGuild', ...adminsOnly
}, {
rpcname: 'managePriorities', ...adminsOnly
}, {
rpcname: 'softreserveCurrency', ...adminsOnly
}, {
rpcname: 'manageRaid', ...adminsOnly
}]
const testAccounts : protoAccount[] = [ const testAccounts: protoAccount[] = [
{ {
name: 'Rain', name: 'Rain',
race: 'Human', race: 'Human',
class: 'Warrior', class: 'Warrior',
spec: 'Protection', spec: 'Protection',
rank: 'Guildmaster' rank: 'Guildmaster'
},{ }, {
name: 'Celinda', name: 'Celinda',
class: 'Warrior', class: 'Warrior',
race: 'Night Elf', race: 'Night Elf',
spec: 'Protection', spec: 'Protection',
rank: 'Officer' rank: 'Officer'
},{ }, {
name: 'Silver', name: 'Silver',
class: 'Druid', class: 'Druid',
race: 'Night Elf', race: 'Night Elf',
spec: 'Restoration', spec: 'Restoration',
rank: 'Raider' rank: 'Raider'
},{ }, {
name: 'Dagger', name: 'Dagger',
race: 'Dwarf', race: 'Dwarf',
class: 'Rogue', class: 'Rogue',
spec: 'Assassination', spec: 'Assassination',
rank: 'Classleader' rank: 'Classleader'
},{ }, {
name: 'Hope', name: 'Hope',
class: 'Paladin', class: 'Paladin',
race: 'Human', race: 'Human',
spec: 'Holy', spec: 'Holy',
rank: 'Classleader' rank: 'Classleader'
},{ }, {
name: 'Shrekd', name: 'Shrekd',
class: 'Warrior', class: 'Warrior',
race: 'Dwarf', race: 'Dwarf',
spec: 'Fury', spec: 'Fury',
rank: 'Classleader' rank: 'Classleader'
},{ }, {
name: 'Teeniweeni', name: 'Teeniweeni',
class: 'Warlock', class: 'Warlock',
race: 'Gnome', race: 'Gnome',
spec: 'Demonology', spec: 'Demonology',
rank: 'Classleader' rank: 'Classleader'
},{ }, {
name: 'Hagibaba', name: 'Hagibaba',
class: 'Priest', class: 'Priest',
race: 'Human', race: 'Human',
spec: 'Discipline', spec: 'Discipline',
rank: 'Classleader' rank: 'Classleader'
},{ }, {
name: 'Muffinbreak', name: 'Muffinbreak',
class: 'Mage', class: 'Mage',
race: 'Gnome', race: 'Gnome',
@@ -109,18 +116,18 @@ const testAccounts : protoAccount[] = [
describe('Frontcraft', () => { describe('Frontcraft', () => {
let auth: Auth, let auth: Auth,
adminUser : User, adminUser: User,
server: FrontworkAdmin, server: FrontworkAdmin,
client : RPCSocket & FrontcraftIfc, client: RPCSocket & FrontcraftIfc,
adminClient : RPCSocket & FrontcraftFeatureIfc, adminClient: RPCSocket & FrontcraftFeatureIfc,
raids: Raid[] = [], raids: Raid[] = [],
users : {[username in string] : { account: User, character: Character, auth: Auth, signup?:Signup, item?:string }} = {} users: { [username in string]: { account: User, character: Character, auth: Auth, signup?: Signup, item?: string } } = {}
const createAccount = (user: User) => { const createAccount = (user: User) => {
return client.UserManager.createUser(user) return client.UserManager.createUser(user)
} }
const createAccountAndUser = async (acc : protoAccount) => { const createAccountAndUser = async (acc: protoAccount) => {
const account = await createAccount({ const account = await createAccount({
pwhash: 'ca978112ca1bbdcafac231b39a23dc4da786eff8147c4e72b9807785afee48bb', //sha256("a") pwhash: 'ca978112ca1bbdcafac231b39a23dc4da786eff8147c4e72b9807785afee48bb', //sha256("a")
rank: acc.rank, rank: acc.rank,
@@ -141,7 +148,7 @@ describe('Frontcraft', () => {
} }
} }
before(function (done){ before(function (done) {
this.timeout(10000); this.timeout(10000);
server = Injector.resolve<FrontworkAdmin>(FrontworkAdmin) server = Injector.resolve<FrontworkAdmin>(FrontworkAdmin)
@@ -170,11 +177,11 @@ describe('Frontcraft', () => {
console.log("I got kicked"); console.log("I got kicked");
}) })
sock.hook('getUserData', () => auth) sock.hook('getUserData', () => auth)
sock.hook('navigate', (where:string) => { sock.hook('navigate', (where: string) => {
console.log("Nagivate client to "+where); console.log("Nagivate client to " + where);
}) })
sock.on('error', (e) => { sock.on('error', (e) => {
console.log('Socket error', e) console.log('Socket error', e)
}) })
done() done()
}) })
@@ -184,7 +191,7 @@ describe('Frontcraft', () => {
}).catch(done) }).catch(done)
}) })
after(()=>{ after(() => {
client.destroy() client.destroy()
adminClient.destroy() adminClient.destroy()
server.stop() server.stop()
@@ -193,16 +200,16 @@ describe('Frontcraft', () => {
it('create raids', (done) => { it('create raids', (done) => {
let insertRaid = <Raid>{ let insertRaid = <Raid>{
description: "Test raid 1", description: "Test raid 1",
title: 'MC', title: 'BWL :D',
start: Date.now().toString(), start: Date.now().toString(),
tier: 'MC' tier: 'BWL'
} }
adminClient.manageRaid.createRaid(insertRaid).then(() => { adminClient.manageRaid.createRaid(insertRaid).then(() => {
client.RaidManager.getRaids().then((r)=>{ client.RaidManager.getRaids().then((r) => {
if(r[0].title === insertRaid.title if (r[0].title === insertRaid.title
&& r[0].description === insertRaid.description && r[0].description === insertRaid.description
&& r[0].tier === "MC"){ && r[0].tier === "BWL") {
raids.push(r[0]) raids.push(r[0])
done() done()
} }
@@ -210,9 +217,9 @@ describe('Frontcraft', () => {
}).catch(done) }).catch(done)
}) })
it('create users', (done)=>{ it('create users', (done) => {
Promise.all(testAccounts.map(acc => createAccountAndUser(acc))).then(accs => { Promise.all(testAccounts.map(acc => createAccountAndUser(acc))).then(accs => {
if(accs.length === testAccounts.length){ if (accs.length === testAccounts.length) {
accs.forEach(acc => { accs.forEach(acc => {
users[acc.account.username] = acc users[acc.account.username] = acc
}) })
@@ -221,27 +228,27 @@ describe('Frontcraft', () => {
}).catch(done) }).catch(done)
}) })
it('should sign up', (done)=>{ it('should sign up', (done) => {
Promise.all(Object.values(users).map((user) => Promise.all(Object.values(users).map((user) =>
adminClient.signup.sign(user.auth.token.value, user.character, raids[0], false).catch(done) adminClient.signup.sign(user.auth.token.value, user.character, raids[0], false).catch(done)
)).then(x => { )).then(x => {
adminClient.signup.getSignups(raids[0]).then(s => { adminClient.signup.getSignups(raids[0]).then(s => {
if(s.length == testAccounts.length){ if (s.length == testAccounts.length) {
s.forEach(sign => { s.forEach(sign => {
users[sign.username].signup = sign users[sign.username].signup = sign
}) })
done() done()
}else{ } else {
done("Unexpected number of signups: "+s.length) done("Unexpected number of signups: " + s.length)
} }
}) })
}) })
}) })
it('calculate priorities', (done)=>{ it('calculate priorities', (done) => {
const makePrio = async (itemname:string, spec?: Spec, race?:Race, mod:number = 0, description:string = "") => { const makePrio = async (itemname: string, spec?: Spec, race?: Race, mod: number = 0, description: string = "") => {
let specid let specid
if(spec) if (spec)
specid = await client.CharacterManager.getSpecId(spec.class, <any>spec.specname) specid = await client.CharacterManager.getSpecId(spec.class, <any>spec.specname)
await adminClient.managePriorities.setPriority(itemname, { await adminClient.managePriorities.setPriority(itemname, {
@@ -256,269 +263,284 @@ describe('Frontcraft', () => {
Promise.all([ Promise.all([
makePrio( makePrio(
'Bracers of Arcane Accuracy', 'Bracers of Arcane Accuracy',
{class:'Warlock', specname:'Demonology'}, { class: 'Warlock', specname: 'Demonology' },
undefined, 2, "hit bias" undefined, 2, "hit bias"
), ),
makePrio( makePrio(
'Bracers of Arcane Accuracy', 'Bracers of Arcane Accuracy',
{class:'Warlock', specname:'Affliction'}, { class: 'Warlock', specname: 'Affliction' },
undefined, 2, "hit bias" undefined, 2, "hit bias"
), ),
makePrio( makePrio(
'Bracers of Arcane Accuracy', 'Bracers of Arcane Accuracy',
{class:'Warlock', specname:'Destruction'}, { class: 'Warlock', specname: 'Destruction' },
undefined, 2, "hit bias" undefined, 2, "hit bias"
), ),
makePrio( makePrio(
'Bracers of Arcane Accuracy', 'Bracers of Arcane Accuracy',
{class:'Mage', specname:'Arcane'}, { class: 'Mage', specname: 'Arcane' },
undefined, 1, "hit bias" undefined, 1, "hit bias"
), ),
makePrio( makePrio(
'Bracers of Arcane Accuracy', 'Bracers of Arcane Accuracy',
{class:'Mage', specname:'Frost'}, { class: 'Mage', specname: 'Frost' },
undefined, 1, "hit bias" undefined, 1, "hit bias"
), ),
makePrio( makePrio(
'Bracers of Arcane Accuracy', 'Bracers of Arcane Accuracy',
{class:'Mage', specname:'Fire'}, { class: 'Mage', specname: 'Fire' },
undefined, 1, "hit bias" undefined, 1, "hit bias"
), ),
makePrio( makePrio(
'Maladath, Runed Blade of the Black Flight', 'Maladath, Runed Blade of the Black Flight',
undefined, undefined,
"Human", -2, "(1) Non-Human" "Human", -2, "[1] Non-Human"
), ),
makePrio( makePrio(
'Maladath, Runed Blade of the Black Flight', 'Maladath, Runed Blade of the Black Flight',
{class:'Rogue', specname:'Subtlety'}, { class: 'Rogue', specname: 'Combat' },
undefined, 2, "...Rogues (weapon skill bias)" undefined, 2, "Weapon skill bias"
), ),
makePrio( makePrio(
'Maladath, Runed Blade of the Black Flight', 'Maladath, Runed Blade of the Black Flight',
{class:'Rogue', specname:'Combat'}, { class: 'Warrior', specname: 'Fury' },
undefined, 2, "...Rogues (weapon skill bias)" 'Human', 4, "+2 Fury Warrior (weapon skill bias), +2 to offset [1]"
), ),
makePrio( makePrio(
'Maladath, Runed Blade of the Black Flight', 'Maladath, Runed Blade of the Black Flight',
{class:'Rogue', specname:'Assassination'}, { class: 'Warrior', specname: 'Protection' },
undefined, 2, "...Rogues (weapon skill bias)" 'Human', 5, "+3 Prot Warrior, +2 to offset [1]"
),
makePrio(
'Maladath, Runed Blade of the Black Flight',
{class:'Warrior', specname:'Fury'},
'Human', 4, "+2 Fury Warrior (weapon skill bias), +2 to offset (1)"
), ),
makePrio( makePrio(
'Cloak of Firemaw', 'Cloak of Firemaw',
{class:'Rogue', specname:'Assassination'}, { class: 'Rogue', specname: 'Assassination' },
undefined, 2, "agi-to-ap bias" undefined, 2, "agi-to-ap bias"
), ),
makePrio( makePrio(
'Cloak of Firemaw', 'Cloak of Firemaw',
{class:'Rogue', specname:'Combat'}, { class: 'Rogue', specname: 'Combat' },
undefined, 2, "agi-to-ap bias" undefined, 2, "agi-to-ap bias"
), ),
makePrio( makePrio(
'Cloak of Firemaw', 'Cloak of Firemaw',
{class:'Rogue', specname:'Subtlety'}, { class: 'Rogue', specname: 'Subtlety' },
undefined, 2, "agi-to-ap bias" undefined, 2, "agi-to-ap bias"
), ),
makePrio( makePrio(
'Band of Forced Concentration', 'Band of Forced Concentration',
{class:'Warlock', specname:'Demonology'}, { class: 'Warlock', specname: 'Demonology' },
undefined, 2, "hit bias" undefined, 2, "hit bias"
), ),
makePrio( makePrio(
'Band of Forced Concentration', 'Band of Forced Concentration',
{class:'Warlock', specname:'Affliction'}, { class: 'Warlock', specname: 'Affliction' },
undefined, 2, "hit bias" undefined, 2, "hit bias"
), ),
makePrio( makePrio(
'Band of Forced Concentration', 'Band of Forced Concentration',
{class:'Warlock', specname:'Destruction'}, { class: 'Warlock', specname: 'Destruction' },
undefined, 2, "hit bias" undefined, 2, "hit bias"
), ),
makePrio( makePrio(
'Band of Forced Concentration', 'Band of Forced Concentration',
{class:'Mage', specname:'Arcane'}, { class: 'Mage', specname: 'Arcane' },
undefined, 1, "hit bias" undefined, 1, "hit bias"
), ),
makePrio( makePrio(
'Band of Forced Concentration', 'Band of Forced Concentration',
{class:'Mage', specname:'Frost'}, { class: 'Mage', specname: 'Frost' },
undefined, 1, "hit bias" undefined, 1, "hit bias"
), ),
makePrio( makePrio(
'Band of Forced Concentration', 'Band of Forced Concentration',
{class:'Mage', specname:'Fire'}, { class: 'Mage', specname: 'Fire' },
undefined, 1, "hit bias" undefined, 1, "hit bias"
), ),
makePrio(
'Chromatic Boots',
{ class: 'Warrior', specname: 'Protection' },
undefined, 2, "hit bias"
),
makePrio(
'Crul\'shorukh, Edge of Chaos',
undefined,
"Human", -2, "Non-human"
),
makePrio(
'Crul\'shorukh, Edge of Chaos',
{ class: 'Warrior', specname: 'Protection' },
undefined, 2, "nice dps bias"
),
makePrio(
'Crul\'shorukh, Edge of Chaos',
{ class: 'Warrior', specname: 'Fury' },
undefined, 2, "nice dps bias"
),
makePrio(
'Drake Talon Pauldrons',
{ class: 'Warrior', specname:'Protection'},
undefined, 2, 'dodge + stats-to-threat bias'
),
makePrio(
'Helm of Endless Rage',
{ class: 'Warrior', specname:'Protection'},
undefined, 2, 'stats-to-threat bias'
),
makePrio( makePrio(
'Drake Fang Talisman', 'Drake Fang Talisman',
{class:'Rogue', specname:'Assassination'}, { class: 'Warrior', specname: 'Protection' },
undefined, 5, "hit bias"
),
makePrio(
'Drake Fang Talisman',
{ class: 'Rogue', specname: 'Assassination' },
undefined, 4, "hit bias" undefined, 4, "hit bias"
), ),
makePrio( makePrio(
'Drake Fang Talisman', 'Drake Fang Talisman',
{class:'Rogue', specname:'Combat'}, { class: 'Rogue', specname: 'Combat' },
undefined, 4, "hit bias" undefined, 4, "hit bias"
), ),
makePrio( makePrio(
'Drake Fang Talisman', 'Drake Fang Talisman',
{class:'Rogue', specname:'Subtlety'}, { class: 'Rogue', specname: 'Subtlety' },
undefined, 4, "hit bias" undefined, 4, "hit bias"
), ),
makePrio( makePrio(
'Drake Fang Talisman', 'Drake Fang Talisman',
{class:'Warrior', specname:'Fury'}, { class: 'Warrior', specname: 'Fury' },
undefined, 2, "hit bias" undefined, 2, "hit bias"
), ),
makePrio( makePrio(
'Drake Fang Talisman', 'Drake Fang Talisman',
{class:'Druid', specname:'Feral (DPS)'}, { class: 'Druid', specname: 'Feral (DPS)' },
undefined, 2, "hit bias" undefined, 2, "hit bias"
), ),
makePrio( makePrio(
'Circle of Applied Force', 'Circle of Applied Force',
{class:'Warrior', specname:'Fury'}, { class: 'Warrior', specname: 'Fury' },
undefined, 2, "str-to-ap bias" undefined, 2, "str-to-ap bias"
), ),
makePrio( makePrio(
'Circle of Applied Force', 'Circle of Applied Force',
{class:'Druid', specname:'Feral (DPS)'}, { class: 'Druid', specname: 'Feral (DPS)' },
undefined, 2, "str-to-ap bias" undefined, 3, "str-to-ap bias + agi-to-ap bias"
), ),
makePrio( makePrio(
'Empowered Leggings', 'Empowered Leggings',
{class:'Paladin', specname:'Holy'}, { class: 'Paladin', specname: 'Holy' },
undefined, 2, "crit bias" undefined, 2, "crit bias"
), ),
makePrio( makePrio(
'Empowered Leggings', 'Empowered Leggings',
{class:'Druid', specname:'Restoration'}, { class: 'Druid', specname: 'Restoration' },
undefined, 2, "crit bias" undefined, 2, "crit bias"
), ),
makePrio( makePrio(
'Boots of the Shadow Flame', 'Boots of the Shadow Flame',
{class:'Rogue', specname:'Assassination'}, { class: 'Rogue', specname: 'Assassination' },
undefined, 2, "hit bias" undefined, 2, "hit bias"
), ),
makePrio( makePrio(
'Boots of the Shadow Flame', 'Boots of the Shadow Flame',
{class:'Rogue', specname:'Combat'}, { class: 'Rogue', specname: 'Combat' },
undefined, 2, "hit bias" undefined, 2, "hit bias"
), ),
makePrio( makePrio(
'Boots of the Shadow Flame', 'Boots of the Shadow Flame',
{class:'Rogue', specname:'Subtlety'}, { class: 'Rogue', specname: 'Subtlety' },
undefined, 2, "hit bias" undefined, 2, "hit bias"
), ),
makePrio( makePrio(
'Boots of the Shadow Flame', 'Boots of the Shadow Flame',
{class:'Druid', specname:'Feral (DPS)'}, { class: 'Druid', specname: 'Feral (DPS)' },
undefined, 2, "hit bias" undefined, 2, "hit bias"
), ),
makePrio( makePrio(
'Neltharion\'s Tear', 'Neltharion\'s Tear',
{class:'Warlock', specname:'Demonology'}, { class: 'Warlock', specname: 'Demonology' },
undefined, 4, "hit bias" undefined, 4, "hit bias"
), ),
makePrio( makePrio(
'Neltharion\'s Tear', 'Neltharion\'s Tear',
{class:'Warlock', specname:'Affliction'}, { class: 'Warlock', specname: 'Affliction' },
undefined, 4, "hit bias" undefined, 4, "hit bias"
), ),
makePrio( makePrio(
'Neltharion\'s Tear', 'Neltharion\'s Tear',
{class:'Warlock', specname:'Destruction'}, { class: 'Warlock', specname: 'Destruction' },
undefined, 4, "hit bias" undefined, 4, "hit bias"
), ),
makePrio( makePrio(
'Neltharion\'s Tear', 'Neltharion\'s Tear',
{class:'Mage', specname:'Arcane'}, { class: 'Mage', specname: 'Arcane' },
undefined, 2, "hit bias" undefined, 2, "hit bias"
), ),
makePrio( makePrio(
'Neltharion\'s Tear', 'Neltharion\'s Tear',
{class:'Mage', specname:'Frost'}, { class: 'Mage', specname: 'Frost' },
undefined, 2, "hit bias" undefined, 2, "hit bias"
), ),
makePrio( makePrio(
'Neltharion\'s Tear', 'Neltharion\'s Tear',
{class:'Mage', specname:'Fire'}, { class: 'Mage', specname: 'Fire' },
undefined, 2, "hit bias" undefined, 2, "hit bias"
), ),
makePrio( makePrio(
'Cloak of Draconic Might', 'Cloak of Draconic Might',
{class:'Warrior', specname:'Fury'}, { class: 'Warrior', specname: 'Fury' },
undefined, 2, "str-to-ap bias" undefined, 2, "str-to-ap bias"
), ),
makePrio( makePrio(
'Cloak of Draconic Might', 'Cloak of Draconic Might',
{class:'Druid', specname:'Feral (DPS)'}, { class: 'Druid', specname: 'Feral (DPS)' },
undefined, 2, "str-to-ap bias" undefined, 1, "str-to-ap bias"
), ),
]) ]).then(() => {
const user = Object.values(users)[0]
client.ItemManager.calculatePriorities("Maladath, Runed Blade of the Black Flight", user.character).then(sum => {
const user = Object.values(users)[0] if (sum === 3)
adminClient.managePriorities.setPriority(T1[0], { done()
race: user.character.race, else
specid: user.character.specid, console.log("Expected prio on maladath to be 4, but was:", sum, user.character);
modifier: 1,
description:'AAA'
}).then(() => {
adminClient.managePriorities.setPriority(T1[0], {
race: user.character.race,
specid: undefined,
modifier: 2,
description:'BBB'
}).then(()=>{
adminClient.managePriorities.setPriority(T1[0], {
race: undefined,
specid: user.character.specid,
modifier: 3,
description:'CCC'
}).then(()=>{
client.ItemManager.calculatePriorities(T1[0], user.character).then(sum => {
if(sum === 6)
done()
})
})
}) })
}) })
}) })
it('buy token', (done)=>{ it('buy token', (done) => {
Promise.all(Object.values(users).map(async (user) =>{ Promise.all(Object.values(users).map(async (user) => {
const itemname = T1[0]//T1[Math.floor(T1.length*Math.random())] const itemname = "Maladath, Runed Blade of the Black Flight" //T1[Math.floor(T1.length*Math.random())]
const modifier = await client.ItemManager.calculatePriorities(itemname, user.character) const modifier = await client.ItemManager.calculatePriorities(itemname, user.character)
const token = await client.ItemManager.buyToken(user.auth.token.value, user.character.charactername, itemname, user.signup!) const token = await client.ItemManager.buyToken(user.auth.token.value, user.character.charactername, itemname, user.signup!)
users[user.account.username].item = itemname users[user.account.username].item = itemname
if(!token) return false if (!token) return false
return modifier+1 === token.level return modifier + 1 === token.level
})).then(success => { })).then(success => {
if(success.reduce((prev, curr)=>prev&&curr, true)) done() if (success.reduce((prev, curr) => prev && curr, true)) done()
}) })
}) })
it('not buy token without currency', (done)=>{ it('not buy token without currency', (done) => {
const user = Object.values(users)[0] const user = Object.values(users)[0]
const itemname = T1[0] const itemname = "Maladath, Runed Blade of the Black Flight"
client.ItemManager.buyToken(user.auth.token.value, user.character.charactername, itemname, user.signup!).then(token => { client.ItemManager.buyToken(user.auth.token.value, user.character.charactername, itemname, user.signup!).then(token => {
if(!token) if (!token)
done() done()
else { else {
console.log("Unexpected token", token); console.log("Unexpected token", token);
@@ -526,24 +548,23 @@ describe('Frontcraft', () => {
}) })
}) })
it('upgrade token', (done)=>{ it('upgrade token', (done) => {
const user = Object.values(users)[0] const user = Object.values(users)[0]
const itemname = T1[0] const itemname = "Maladath, Runed Blade of the Black Flight"
client.ItemManager.getItem(itemname).then(async item => {
adminClient.softreserveCurrency.incrementCurrency(user.account, raids[0].tier, 2).then(async ()=>{ await adminClient.softreserveCurrency.incrementCurrency(user.account, item.tier, 2)
const item = await client.ItemManager.getItem(itemname)
const before = await client.ItemManager.getToken(user.character, item) const before = await client.ItemManager.getToken(user.character, item)
if(!before || before.level !== 7) { if (!before || before.level !== 4) {
console.log("expected level to be 7", before); console.log("expected level to be 4", before ? before.level : '?');
return return
} }
await client.ItemManager.buyToken(user.auth.token.value, user.character.charactername, itemname, user.signup!) await client.ItemManager.buyToken(user.auth.token.value, user.character.charactername, itemname, user.signup!)
const after = await client.ItemManager.buyToken(user.auth.token.value, user.character.charactername, itemname, user.signup!) const after = await client.ItemManager.buyToken(user.auth.token.value, user.character.charactername, itemname, user.signup!)
if(!after || after.level !== 9) { if (!after || after.level !== 6) {
console.log("expected level to be 9", after); console.log("expected level after to be 6", after ? after.level : '?');
return return
} }
done() done()
@@ -552,14 +573,14 @@ describe('Frontcraft', () => {
it('should buy more tokens', (done) => { it('should buy more tokens', (done) => {
Promise.all(Object.values(users).map(async (user) => { Promise.all(Object.values(users).map(async (user) => {
await adminClient.softreserveCurrency.incrementCurrency(user.account,raids[0].tier, 1) await adminClient.softreserveCurrency.incrementCurrency(user.account, raids[0].tier, 1)
return await client.ItemManager return await client.ItemManager
.buyToken( .buyToken(
user.auth.token.value, user.auth.token.value,
user.character.charactername, user.character.charactername,
T1[Math.floor(T1.length*Math.random())], T2[Math.floor(T2.length * Math.random())],
user.signup! user.signup!
) )
})).then(_ => { })).then(_ => {
done() done()
}) })
@@ -574,21 +595,21 @@ describe('Frontcraft', () => {
}) })
it('start raid', (done) => { it('start raid', (done) => {
client.RaidManager.getRaids().then((r)=>{ client.RaidManager.getRaids().then((r) => {
adminClient.manageRaid.startRaid(raids[0]).then(async data => { adminClient.manageRaid.startRaid(raids[0]).then(async data => {
const dbRaids = await client.RaidManager.getRaids() const dbRaids = await client.RaidManager.getRaids()
if(dbRaids.length === 0){ if (dbRaids.length === 0) {
await client.UserManager.getUser(testAccounts[0].name).then(dbUser => { await client.UserManager.getUser(testAccounts[0].name).then(dbUser => {
if(dbUser && dbUser.MC === 1){ if (dbUser && dbUser.BWL === 1) {
adminClient.signup.getSignups(raids[0]).then(signups => { adminClient.signup.getSignups(raids[0]).then(signups => {
if(signups.length === 0){ if (signups.length === 0) {
done() done()
}else{ } else {
console.log(signups); console.log(signups);
} }
}) })
} }
else{ else {
console.log("Bad user currency", dbUser); console.log("Bad user currency", dbUser);
} }
}) })
@@ -600,81 +621,121 @@ describe('Frontcraft', () => {
it('reset system', (done) => { it('reset system', (done) => {
adminClient.reset.wipeCurrencyAndItems().then(() => { adminClient.reset.wipeCurrencyAndItems().then(() => {
client.UserManager.getUser(testAccounts[0].name).then(user => { client.UserManager.getUser(testAccounts[0].name).then(user => {
if(user && user.MC === 1){ if (user && user.MC === 1) {
client.ItemManager.getTokens(users[testAccounts[0].name.toLowerCase()].character, ['MC']).then(tokens => { client.ItemManager.getTokens(users[testAccounts[0].name.toLowerCase()].character, ['BWL']).then(tokens => {
if(tokens!.length === 0){ if (tokens!.length === 0) {
done() done()
}else{ } else {
console.log(tokens); console.log(tokens);
} }
}) })
}else{ } else {
console.log(user) console.log(user)
} }
}) })
}) })
}) })
it('implements loot system correctly', (done)=>{ it('implements loot system correctly', (done) => {
const ONE_WEEK = 4800000000 const ONE_WEEK = 4800000000
const Raid = (week:number, tier:string) => { const Raid = (week: number, tier: string) => {
return <Raid>{ return <Raid>{
description: tier+" Test raid 1", description: tier + " Test raid 1",
title: tier, title: tier,
start: (week*ONE_WEEK + Date.now()).toString(), start: (week * ONE_WEEK + Date.now()).toString(),
tier: tier tier: tier
} }
} }
const user = Object.values(users)[0] const user = Object.values(users)[0]
const createRaid = adminClient.manageRaid.createRaid const createRaid = adminClient.manageRaid.createRaid
const sign = async (raid:Raid, late = false) => await adminClient.signup.sign(user.auth.token.value, user.character, raid, late) const sign = async (raid: Raid, late = false) => await adminClient.signup.sign(user.auth.token.value, user.character, raid, late)
const buyToken = async (signup: Signup, itemname: string) => await client.ItemManager.buyToken(user.auth.token.value, user.character.charactername, itemname, signup) const buyToken = async (signup: Signup, itemname: string) => await client.ItemManager.buyToken(user.auth.token.value, user.character.charactername, itemname, signup)
const getCurrency = async (tier: Tiers) => {
const dbUser = await client.UserManager.getUser(user.account.username)
return dbUser[tier]
}
createRaid(Raid(0, 'MC')).then(async (MC0:Raid) => { createRaid(Raid(0, 'BWL')).then(async (BWL0: Raid) => {
const T1_0 = await client.ItemManager.getItem(T1[0]) const T2_0 = await client.ItemManager.getItem(T2[0])
//const BWL0 = await createRaid(Raid(0, 'BWL')) //const BWL0 = await createRaid(Raid(0, 'BWL'))
const signupMC0 = await sign(MC0) const signupBWL0 = await sign(BWL0)
let token = await buyToken(signupMC0, T1[0]) let BWL = await getCurrency(BWL0.tier)
if(!token){ let token = await buyToken(signupBWL0, T2[0])
console.log(MC0, signupMC0) const BWLAfter = await getCurrency(BWL0.tier)
done("No token created")
if (!token
|| BWL - BWLAfter != 1) {
console.log("Bad Token status", BWL0, signupBWL0, BWL, BWLAfter)
done(new Error("Bad Token status 0"))
return return
} }
let reserves = await client.ItemManager.getTokens(user.character, [MC0.tier], true) let reserves = await client.ItemManager.getTokens(user.character, [BWL0.tier], true)
let streaks = await client.ItemManager.getTokens(user.character, [MC0.tier], false) let streaks = await client.ItemManager.getTokens(user.character, [BWL0.tier], false)
if(reserves!.length != 1 if (reserves!.length != 1
|| streaks!.length != 0 || streaks!.length != 0
|| reserves![0].itemname !== T1_0.itemname || reserves![0].itemname !== T2_0.itemname
|| reserves![0].level !== 7){ || reserves![0].level !== 1) {
console.log(reserves, streaks); console.log("Bad Token status 1", reserves, streaks);
done("Bad token status") done(new Error("Bad Token status"))
return return
} }
await adminClient.manageRaid.startRaid(MC0) await adminClient.manageRaid.startRaid(BWL0)
reserves = await client.ItemManager.getTokens(user.character, [MC0.tier], true) reserves = await client.ItemManager.getTokens(user.character, [BWL0.tier], true)
streaks = await client.ItemManager.getTokens(user.character, [MC0.tier], false) streaks = await client.ItemManager.getTokens(user.character, [BWL0.tier], false)
if(reserves!.length != 0 if (reserves!.length != 0
|| streaks!.length != 1 || streaks!.length != 1
|| streaks![0].itemname !== T1[0] || streaks![0].itemname !== T2[0]
|| streaks![0].level !== 7){ || streaks![0].level !== 1) {
console.log(reserves, streaks); console.log("Bad Token status", reserves, streaks);
done("Bad token status") done(new Error("Bad Token status 2"))
return return
} }
const MC1 = await createRaid(Raid(1, 'MC')) const BWL1 = await createRaid(Raid(1, 'BWL'))
const signupMC1 = await sign(MC1)
token = await buyToken(signupMC1, T1[1]) let signupBWL1 = await sign(BWL1)
reserves = await client.ItemManager.getTokens(user.character, [MC1.tier], true) BWL = await getCurrency(BWL1.tier)
streaks = await client.ItemManager.getTokens(user.character, [MC1.tier], false) await adminClient.manageRaid.adminUnsign(user.character, BWL1)
if(reserves!.length != 1 let afterUnsign = await getCurrency(BWL1.tier)
|| streaks!.length != 0 if (BWL !== afterUnsign) {
|| reserves![0].itemname !== T1[1] console.log("Expected currency to be equal", BWL, afterUnsign)
|| reserves![0].level !== 1){ done(new Error("Expected currency to be equal"))
console.log(reserves, streaks); return
done("Bad token status") }
signupBWL1 = await sign(BWL1)
BWL = await getCurrency(BWL1.tier)
await buyToken(signupBWL1, T2[1])
await adminClient.manageRaid.adminUnsign(user.character, BWL1)
afterUnsign = await getCurrency(BWL1.tier)
if (BWL !== afterUnsign) {
console.log("Expected currency to be equal", BWL, afterUnsign)
done(new Error("Expected currency to be equal"))
return
}
signupBWL1 = await sign(BWL1)
await buyToken(signupBWL1, T2[1])
reserves = await client.ItemManager.getTokens(user.character, [BWL1.tier], true)
streaks = await client.ItemManager.getTokens(user.character, [BWL1.tier], false)
if (reserves!.length != 1
|| streaks!.length != 0
|| reserves![0].itemname !== T2[1]
|| reserves![0].level !== 1) {
console.log("Bad Token status", reserves, streaks);
done(new Error("Bad Token status 3"))
return
}
BWL = await getCurrency(BWL1.tier)
const data = await adminClient.manageRaid.startRaid(BWL1)
const afterStart = await getCurrency(BWL1.tier)
if (BWL != 0 || afterStart != 1) {
console.log("Wrong currency values", BWL, afterStart)
done(new Error("Wrong currency values"))
return return
} }