implement loot system feedback
This commit is contained in:
@@ -102,6 +102,13 @@ implements TableDefinitionExporter, IAdmin {
|
|||||||
private startWebsocket(){
|
private startWebsocket(){
|
||||||
this.rpcServer = new RPCServer(20000, [
|
this.rpcServer = new RPCServer(20000, [
|
||||||
...this.frontworkComponents,
|
...this.frontworkComponents,
|
||||||
|
{
|
||||||
|
name: "debug",
|
||||||
|
exportRPCs: () => [{
|
||||||
|
name: 'dumpDb',
|
||||||
|
call: async (table) => await this.knex(table).select('*')
|
||||||
|
}]
|
||||||
|
}
|
||||||
], {
|
], {
|
||||||
visibility: '0.0.0.0'
|
visibility: '0.0.0.0'
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -1,9 +1,9 @@
|
|||||||
import { Item, Character, SRToken, SRPriority, Spec } from "../../Types/Types"
|
import { Item, Character, SRToken, SRPriority, Spec, Signup } from "../../Types/Types"
|
||||||
|
|
||||||
export class IItemManager{
|
export class IItemManager{
|
||||||
getItems: () => Promise<Item[]>
|
getItems: () => Promise<Item[]>
|
||||||
fetchItem: (name:string) => Promise<Item>
|
fetchItem: (name:string) => Promise<Item>
|
||||||
buyToken: (usertoken: string, charactername:string, itemname:string) => Promise<(SRToken & Character & Item) | void>
|
buyToken: (usertoken: string, charactername:string, itemname:string, signup:Signup) => Promise<(SRToken & Character & Item) | void>
|
||||||
setPriority: (itemname:string, priority: any) => Promise<void>
|
setPriority: (itemname:string, priority: any) => Promise<void>
|
||||||
calculatePriorities: (itemname: string, character:Character) => Promise<number>
|
calculatePriorities: (itemname: string, character:Character) => Promise<number>
|
||||||
deletePriority: (priority:SRPriority) => Promise<void>
|
deletePriority: (priority:SRPriority) => Promise<void>
|
||||||
|
|||||||
@@ -1,9 +1,9 @@
|
|||||||
import { T1, T2 } from "../../Types/Items";
|
import { T1, T2, allItems, _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 } from "../../Types/Types";
|
import { TableDefiniton, Item, User, Character, SRToken, SRPriority, Spec, Signup } 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";
|
||||||
@@ -87,19 +87,21 @@ implements FrontworkComponent<ItemManagerIfc, ItemManagerFeatureIfc>, TableDefin
|
|||||||
{
|
{
|
||||||
name: 'tokens',
|
name: 'tokens',
|
||||||
tableBuilder: (table) => {
|
tableBuilder: (table) => {
|
||||||
table.primary(['characterid', 'itemid'])
|
table.primary(['characterid', 'itemname'])
|
||||||
table.integer("characterid")
|
table.integer("characterid")
|
||||||
table.foreign("characterid").references("id").inTable('characters')
|
table.foreign("characterid").references("id").inTable('characters')
|
||||||
table.integer("itemid")
|
table.string("itemname")
|
||||||
table.foreign("itemid").references("id").inTable('items')
|
table.foreign("itemname").references("itemname").inTable('items')
|
||||||
|
table.string("signupid").nullable()
|
||||||
|
table.foreign("signupid").references("id").inTable('signups').onDelete('SET NULL')
|
||||||
table.integer("level").defaultTo(1)
|
table.integer("level").defaultTo(1)
|
||||||
}
|
}
|
||||||
},{
|
},{
|
||||||
name: 'priorities',
|
name: 'priorities',
|
||||||
tableBuilder: (table) => {
|
tableBuilder: (table) => {
|
||||||
table.increments('id').primary()
|
table.increments('id').primary()
|
||||||
table.integer('itemid')
|
table.string('itemname')
|
||||||
table.foreign('itemid').references('id').inTable('items')
|
table.foreign('itemname').references('itemname').inTable('items')
|
||||||
table.string('race').nullable()
|
table.string('race').nullable()
|
||||||
table.integer('specid').nullable()
|
table.integer('specid').nullable()
|
||||||
table.foreign('specid').references('id').inTable('specs')
|
table.foreign('specid').references('id').inTable('specs')
|
||||||
@@ -109,17 +111,17 @@ implements FrontworkComponent<ItemManagerIfc, ItemManagerFeatureIfc>, TableDefin
|
|||||||
},{
|
},{
|
||||||
name: 'items',
|
name: 'items',
|
||||||
tableBuilder: (table) => {
|
tableBuilder: (table) => {
|
||||||
table.increments("id").primary()
|
table.string('itemname').unique().notNullable().primary()
|
||||||
table.string('itemname').unique().notNullable()
|
|
||||||
table.string('iconname').notNullable()
|
table.string('iconname').notNullable()
|
||||||
table.string('url').notNullable()
|
table.string('url').notNullable()
|
||||||
table.string('quality').defaultTo('Epic').notNullable()
|
table.string('quality').defaultTo('Epic').notNullable()
|
||||||
table.boolean('hidden').defaultTo(false).notNullable()
|
table.boolean('hidden').defaultTo(false).notNullable()
|
||||||
|
table.enu('tier', _Tiers).notNullable()
|
||||||
}
|
}
|
||||||
}]
|
}]
|
||||||
}
|
}
|
||||||
|
|
||||||
buyToken = async (usertoken: string, charactername:string, itemname:string): Promise<(SRToken & Character & Item) | void> => {
|
buyToken = async (usertoken: string, charactername:string, itemname:string, signup: Signup): Promise<(SRToken & Character & Item) | void> => {
|
||||||
const record = this.userManager.getUserRecordByToken(usertoken)
|
const record = this.userManager.getUserRecordByToken(usertoken)
|
||||||
const character = await this.character.getCharacterByName(charactername)
|
const character = await this.character.getCharacterByName(charactername)
|
||||||
|
|
||||||
@@ -131,30 +133,62 @@ implements FrontworkComponent<ItemManagerIfc, ItemManagerFeatureIfc>, TableDefin
|
|||||||
const currency = await this.userManager.getCurrency(record.user)
|
const currency = await this.userManager.getCurrency(record.user)
|
||||||
if(currency < 1) return
|
if(currency < 1) return
|
||||||
|
|
||||||
const existingToken = await this.getToken(character, item)
|
const shadowTokens = await this.getTokens(character, false)
|
||||||
|
const activeTokens = await this.getTokens(character, true)
|
||||||
|
|
||||||
await this.userManager.decrementCurrency(record.user, 1)
|
await this.userManager.decrementCurrency(record.user, 1)
|
||||||
|
const modifier = await this.calculatePriorities(itemname, character)
|
||||||
|
|
||||||
if(!existingToken){
|
//tokens with deleted signups
|
||||||
const modifier = await this.calculatePriorities(itemname, character)
|
if(shadowTokens.length > 0){
|
||||||
await this.admin.knex('tokens').insert({
|
//token for current item
|
||||||
characterid: character.id,
|
const matchingtoken = shadowTokens.find(token => token.itemname === itemname)
|
||||||
itemid: item.id,
|
if(matchingtoken){
|
||||||
level: 1+modifier
|
//update signupid and increment level
|
||||||
})
|
|
||||||
}else{
|
console.log("delete shadow tokens");
|
||||||
await this.admin.knex('tokens').where({
|
|
||||||
characterid: character.id,
|
await this.admin
|
||||||
itemid: item.id
|
.knex('tokens')
|
||||||
}).increment('level')
|
.update({
|
||||||
|
signupid: signup.id,
|
||||||
|
level: matchingtoken.level+1
|
||||||
|
})
|
||||||
|
.where({
|
||||||
|
characterid: character.id,
|
||||||
|
itemname: item.itemname
|
||||||
|
})
|
||||||
|
return await this.getToken(character, item)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const matchingtoken = activeTokens.find(token => token.itemname === itemname)
|
||||||
|
if(matchingtoken){
|
||||||
|
//power up token
|
||||||
|
await this.admin
|
||||||
|
.knex('tokens')
|
||||||
|
.increment('level')
|
||||||
|
.where({
|
||||||
|
signupid: signup.id,
|
||||||
|
characterid: character.id,
|
||||||
|
itemname: item.itemname
|
||||||
|
})
|
||||||
|
}else{
|
||||||
|
await this.admin
|
||||||
|
.knex('tokens')
|
||||||
|
.insert({
|
||||||
|
characterid: character.id,
|
||||||
|
itemname: item.itemname,
|
||||||
|
level: 1+modifier,
|
||||||
|
signupid: signup.id
|
||||||
|
})
|
||||||
|
}
|
||||||
return await this.getToken(character, item)
|
return await this.getToken(character, item)
|
||||||
}
|
}
|
||||||
|
|
||||||
getAllPriorities = async() :Promise<(SRPriority & Spec & Item)[]> => this.admin
|
getAllPriorities = async() :Promise<(SRPriority & Spec & Item)[]> => this.admin
|
||||||
.knex('priorities as p')
|
.knex('priorities as p')
|
||||||
.join('items as i', 'p.itemid', '=', 'i.id')
|
.join('items as i', 'p.itemname', '=', 'i.itemname')
|
||||||
.leftJoin('specs as s', 'p.specid', '=', 's.id')
|
.leftJoin('specs as s', 'p.specid', '=', 's.id')
|
||||||
.select('*')
|
.select('*')
|
||||||
|
|
||||||
@@ -170,24 +204,24 @@ implements FrontworkComponent<ItemManagerIfc, ItemManagerFeatureIfc>, TableDefin
|
|||||||
await this.admin
|
await this.admin
|
||||||
.knex('priorities')
|
.knex('priorities')
|
||||||
.insert(<SRPriority>{
|
.insert(<SRPriority>{
|
||||||
itemid: item.id,
|
itemname: item.itemname,
|
||||||
...priority
|
...priority
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
getPriorities = async(itemname:string) : Promise<SRPriority[]> => {
|
getPriorities = async(itemname:string) : Promise<SRPriority[]> => {
|
||||||
const item = await this.getItem(itemname)
|
return await this.admin
|
||||||
|
.knex('priorities as p')
|
||||||
return await this.admin.knex('priorities')
|
.where('p.itemname', '=', itemname)
|
||||||
.where('itemid', '=', item.id)
|
|
||||||
.select('*')
|
.select('*')
|
||||||
}
|
}
|
||||||
|
|
||||||
calculatePriorities = async (itemname: string, character:Character):Promise<number>=> {
|
calculatePriorities = async (itemname: string, character:Character):Promise<number>=> {
|
||||||
const rules : SRPriority[] = await this.admin.knex('priorities as p')
|
const rules : SRPriority[] = await this.admin
|
||||||
|
.knex('priorities as p')
|
||||||
.select('*')
|
.select('*')
|
||||||
.join('items as i', 'i.id', '=', 'p.itemid')
|
.join('items as i', 'i.itemname', '=', 'p.itemname')
|
||||||
.where('itemname', '=', itemname)
|
.where('p.itemname', '=', itemname)
|
||||||
|
|
||||||
return rules.map(rule => {
|
return rules.map(rule => {
|
||||||
if(rule.specid && rule.race){
|
if(rule.specid && rule.race){
|
||||||
@@ -219,28 +253,37 @@ implements FrontworkComponent<ItemManagerIfc, ItemManagerFeatureIfc>, TableDefin
|
|||||||
.knex('tokens as t')
|
.knex('tokens as t')
|
||||||
.select('*')
|
.select('*')
|
||||||
.join('characters as c', 'c.id', '=', 't.characterid')
|
.join('characters as c', 'c.id', '=', 't.characterid')
|
||||||
.join('items as i', 'i.id', '=', 't.itemid')
|
.join('items as i', 'i.itemname', '=', 't.itemname')
|
||||||
.where({
|
.where({
|
||||||
characterid: character.id,
|
characterid: character.id,
|
||||||
itemid: item.id
|
"i.itemname": item.itemname
|
||||||
})
|
})
|
||||||
.first()
|
.first()
|
||||||
}
|
}
|
||||||
|
|
||||||
getTokens = async (character:Character) : Promise<(SRToken & Character & Item)[]> => {
|
getTokens = async (character:Character, valid=true) : Promise<(SRToken & Character & Item)[]> => {
|
||||||
return await this.admin
|
return await this.admin
|
||||||
.knex('tokens as t')
|
.knex('tokens as t')
|
||||||
.select('*')
|
.select('*')
|
||||||
.select('*')
|
|
||||||
.join('characters as c', 'c.id', '=', 't.characterid')
|
.join('characters as c', 'c.id', '=', 't.characterid')
|
||||||
.join('items as i', 'i.id', '=', 't.itemid')
|
.join('items as i', 'i.itemname', '=', 't.itemname')
|
||||||
.where({
|
.where({
|
||||||
characterid: character.id,
|
characterid: character.id,
|
||||||
})
|
})
|
||||||
|
.andWhere(function(){
|
||||||
|
if(valid){
|
||||||
|
this.whereNotNull('t.signupid')
|
||||||
|
}else{
|
||||||
|
this.whereNull('t.signupid')
|
||||||
|
}
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
countItems = async() :Promise<number> => {
|
countItems = async() :Promise<number> => {
|
||||||
const count = await this.admin.knex('items').count('*');
|
const count = await this.admin
|
||||||
|
.knex('items')
|
||||||
|
.count('*');
|
||||||
|
|
||||||
return <number>count[0]['count(*)']
|
return <number>count[0]['count(*)']
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -249,20 +292,24 @@ implements FrontworkComponent<ItemManagerIfc, ItemManagerFeatureIfc>, TableDefin
|
|||||||
if(this.initialized) return
|
if(this.initialized) return
|
||||||
this.initialized = true
|
this.initialized = true
|
||||||
|
|
||||||
const allItems = [...T1, ...T2]
|
const itemTiers = allItems
|
||||||
|
|
||||||
const countCache = await this.countItems()
|
const countCache = await this.countItems()
|
||||||
getLogger('ItemManager').debug('Checking items, got: ',countCache, 'expected: ', allItems.length)
|
|
||||||
|
|
||||||
if(countCache != allItems.length){
|
if(countCache != Object.values(itemTiers).flat().length){
|
||||||
const items:Item[] = await Promise.all(allItems.map((i) => this.fetchItem(i)))
|
await Promise.all(
|
||||||
try{
|
Object.entries(itemTiers)
|
||||||
await this.admin
|
.map((kv) => Promise.all(
|
||||||
.knex('items')
|
kv[1].map(i => this.fetchItem(i)
|
||||||
.insert(items)
|
.then(item => this.admin
|
||||||
}catch(e){
|
.knex('items')
|
||||||
getLogger('ItemManager').debug("Skipping item insertion")
|
.insert({
|
||||||
}
|
tier: kv[0],
|
||||||
|
...item
|
||||||
|
})
|
||||||
|
))
|
||||||
|
))
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1,11 +1,11 @@
|
|||||||
import { Raid, Signup, Character, RaidData } from "../../Types/Types"
|
import { Raid, Signup, Character, RaidData, User, Spec } from "../../Types/Types"
|
||||||
|
|
||||||
export class IRaidManager{
|
export class IRaidManager{
|
||||||
getRaids: () => Promise<Raid[]>
|
getRaids: () => Promise<Raid[]>
|
||||||
createRaid: (raid:Raid) => Promise<any>
|
createRaid: (raid:Raid) => Promise<any>
|
||||||
addSignup: (signup: Signup) => Promise<any>
|
addSignup: (signup: Signup) => Promise<any>
|
||||||
removeSignup: (signup: Signup) => Promise<any>
|
removeSignup: (signup: Signup) => Promise<any>
|
||||||
getSignups: (raid:Raid) => Promise<Signup[]>
|
getSignups: (raid:Raid) => Promise<(Signup & Character & Spec & User)[]>
|
||||||
sign: (userToken: string, character:Character, raid:Raid, late:boolean) => Promise<any>
|
sign: (userToken: string, character:Character, raid:Raid, late:boolean) => Promise<any>
|
||||||
unsign: (userToken: string, character:Character, raid:Raid,) => Promise<any>
|
unsign: (userToken: string, character:Character, raid:Raid,) => Promise<any>
|
||||||
archiveRaid: (raid:Raid) => Promise<RaidData>
|
archiveRaid: (raid:Raid) => Promise<RaidData>
|
||||||
|
|||||||
@@ -1,11 +1,12 @@
|
|||||||
import { Inject, Injectable } from "../../Injector/ServiceDecorator";
|
import { Inject, Injectable } from "../../Injector/ServiceDecorator";
|
||||||
import { RaidManagerIfc, RaidManagerFeatureIfc } from "./RPCInterface";
|
import { RaidManagerIfc, RaidManagerFeatureIfc } from "./RPCInterface";
|
||||||
import { FrontworkComponent } from "../../Types/FrontworkComponent";
|
import { FrontworkComponent } from "../../Types/FrontworkComponent";
|
||||||
import { TableDefiniton, Signup, Raid, Character, RaidData, Spec, SRToken, Item } from "../../Types/Types";
|
import { TableDefiniton, Signup, Raid, Character, RaidData, Spec, SRToken, Item, User } from "../../Types/Types";
|
||||||
import { IAdmin } from "../../Admin/Interface";
|
import { IAdmin } from "../../Admin/Interface";
|
||||||
import { IRaidManager } from "./Interface";
|
import { IRaidManager } from "./Interface";
|
||||||
import { IUserManager } from "../User/Interface";
|
import { IUserManager } from "../User/Interface";
|
||||||
import { ICharacterManager } from "../Character/Interface";
|
import { ICharacterManager } from "../Character/Interface";
|
||||||
|
import { _Tiers } from "../../Types/Items";
|
||||||
|
|
||||||
@Injectable(IRaidManager)
|
@Injectable(IRaidManager)
|
||||||
export class RaidManager
|
export class RaidManager
|
||||||
@@ -59,6 +60,7 @@ implements FrontworkComponent<RaidManagerIfc, RaidManagerFeatureIfc>, IRaidManag
|
|||||||
table.string('description').notNullable()
|
table.string('description').notNullable()
|
||||||
table.string('title').notNullable()
|
table.string('title').notNullable()
|
||||||
table.integer('size').defaultTo(40)
|
table.integer('size').defaultTo(40)
|
||||||
|
table.enu('tier', _Tiers).defaultTo(null as any)
|
||||||
}
|
}
|
||||||
},{
|
},{
|
||||||
name: 'archive',
|
name: 'archive',
|
||||||
@@ -69,7 +71,8 @@ implements FrontworkComponent<RaidManagerIfc, RaidManagerFeatureIfc>, IRaidManag
|
|||||||
},{
|
},{
|
||||||
name: 'signups',
|
name: 'signups',
|
||||||
tableBuilder: (table) => {
|
tableBuilder: (table) => {
|
||||||
table.primary(['raidid', 'characterid'])
|
table.increments('id').primary()
|
||||||
|
table.unique(['raidid', 'characterid'])
|
||||||
table.integer('raidid')
|
table.integer('raidid')
|
||||||
table.foreign('raidid').references('id').inTable('raids').onDelete('CASCADE')
|
table.foreign('raidid').references('id').inTable('raids').onDelete('CASCADE')
|
||||||
table.integer('characterid')
|
table.integer('characterid')
|
||||||
@@ -95,7 +98,7 @@ implements FrontworkComponent<RaidManagerIfc, RaidManagerFeatureIfc>, IRaidManag
|
|||||||
raid_id: signup.raidid,
|
raid_id: signup.raidid,
|
||||||
character_id: signup.characterid
|
character_id: signup.characterid
|
||||||
})
|
})
|
||||||
.delete()
|
.del()
|
||||||
|
|
||||||
getRaids = async () : Promise<Raid[]> => {
|
getRaids = async () : Promise<Raid[]> => {
|
||||||
|
|
||||||
@@ -116,7 +119,6 @@ implements FrontworkComponent<RaidManagerIfc, RaidManagerFeatureIfc>, IRaidManag
|
|||||||
|
|
||||||
startRaid = async (raid:Raid) : Promise<RaidData> => {
|
startRaid = async (raid:Raid) : Promise<RaidData> => {
|
||||||
const archived = await this.archiveRaid(raid)
|
const archived = await this.archiveRaid(raid)
|
||||||
|
|
||||||
delete archived.participants.late
|
delete archived.participants.late
|
||||||
|
|
||||||
const giveCurrency = async (b: Character) => {
|
const giveCurrency = async (b: Character) => {
|
||||||
@@ -138,8 +140,17 @@ implements FrontworkComponent<RaidManagerIfc, RaidManagerFeatureIfc>, IRaidManag
|
|||||||
.insert({
|
.insert({
|
||||||
id:raidData.id,
|
id:raidData.id,
|
||||||
raiddata: JSON.stringify(raidData)
|
raiddata: JSON.stringify(raidData)
|
||||||
})
|
})
|
||||||
|
|
||||||
|
await Promise.all(
|
||||||
|
Object.values(raidData.participants).flat().flatMap((signup) => this.admin
|
||||||
|
.knex('tokens')
|
||||||
|
.where({
|
||||||
|
characterid: signup.characterid,
|
||||||
|
signupid: null
|
||||||
|
})
|
||||||
|
.del()
|
||||||
|
))
|
||||||
|
|
||||||
await this.admin.knex('raids')
|
await this.admin.knex('raids')
|
||||||
.where('id', '=', raid.id)
|
.where('id', '=', raid.id)
|
||||||
@@ -175,17 +186,17 @@ implements FrontworkComponent<RaidManagerIfc, RaidManagerFeatureIfc>, IRaidManag
|
|||||||
getRaidData = async (raid:Raid) : Promise<RaidData> => {
|
getRaidData = async (raid:Raid) : Promise<RaidData> => {
|
||||||
const ret = {
|
const ret = {
|
||||||
participants:{
|
participants:{
|
||||||
Druid: <(Character&Spec)[]>[],
|
Druid: <(Signup&Character&Spec)[]>[],
|
||||||
Hunter: <(Character&Spec)[]>[],
|
Hunter: <(Signup&Character&Spec)[]>[],
|
||||||
Mage: <(Character&Spec)[]>[],
|
Mage: <(Signup&Character&Spec)[]>[],
|
||||||
Paladin: <(Character&Spec)[]>[],
|
Paladin: <(Signup&Character&Spec)[]>[],
|
||||||
Priest: <(Character&Spec)[]>[],
|
Priest: <(Signup&Character&Spec)[]>[],
|
||||||
Rogue: <(Character&Spec)[]>[],
|
Rogue: <(Signup&Character&Spec)[]>[],
|
||||||
Shaman: <(Character&Spec)[]>[],
|
Shaman: <(Signup&Character&Spec)[]>[],
|
||||||
Warlock: <(Character&Spec)[]>[],
|
Warlock: <(Signup&Character&Spec)[]>[],
|
||||||
Warrior: <(Character&Spec)[]>[],
|
Warrior: <(Signup&Character&Spec)[]>[],
|
||||||
late: <(Character&Spec)[]>[],
|
late: <(Signup&Character&Spec)[]>[],
|
||||||
bench: <(Character&Spec)[]>[],
|
bench: <(Signup&Character&Spec)[]>[],
|
||||||
},
|
},
|
||||||
tokens:{}
|
tokens:{}
|
||||||
}
|
}
|
||||||
@@ -205,9 +216,9 @@ implements FrontworkComponent<RaidManagerIfc, RaidManagerFeatureIfc>, IRaidManag
|
|||||||
.where('id','=',raid.id)
|
.where('id','=',raid.id)
|
||||||
.first()
|
.first()
|
||||||
|
|
||||||
const characterData: (Character & Spec & Signup)[] = await this.admin
|
const characterData: (Signup & Character & Spec)[] = await this.admin
|
||||||
.knex('signups as s')
|
.knex('signups as s')
|
||||||
.select('characterid as id', 'charactername', 'class', 'specname', 'race', 'userid', 'benched', 'late', 'raidid', 'characterid')
|
.select('s.id as id', 'charactername', 'class', 'specname', 'race', 'userid', 'benched', 'late', 'raidid', 'characterid')
|
||||||
.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')
|
||||||
@@ -228,12 +239,15 @@ 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')
|
||||||
.select('*')
|
.select('*', 's.id as id')
|
||||||
.join('raids as r', 's.raidid','=','r.id')
|
.join('raids as r', 's.raidid','=','r.id')
|
||||||
.where('r.id','=',raid.id)
|
.where('r.id','=',raid.id)
|
||||||
|
.andWhere(function(){
|
||||||
|
this.whereNotNull('t.signupid')
|
||||||
|
})
|
||||||
.join('characters as c', 's.characterid','=','c.id')
|
.join('characters as c', 's.characterid','=','c.id')
|
||||||
.join('tokens as t', 't.characterid','=','c.id')
|
.join('tokens as t', 't.characterid','=','c.id')
|
||||||
.join('items as i', 'i.id','=','t.itemid')
|
.join('items as i', 'i.itemname','=','t.itemname')
|
||||||
|
|
||||||
tokenData.forEach(data => {
|
tokenData.forEach(data => {
|
||||||
if(!ret.tokens[data.itemname])
|
if(!ret.tokens[data.itemname])
|
||||||
@@ -246,12 +260,12 @@ implements FrontworkComponent<RaidManagerIfc, RaidManagerFeatureIfc>, IRaidManag
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
getSignups = async (raid:Raid) : Promise<Signup[]> => await this.admin
|
getSignups = async (raid:Raid) : Promise<(Signup & Character & Spec & User)[]> => await this.admin
|
||||||
.knex('signups')
|
.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('*')
|
.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) => {
|
||||||
@@ -286,6 +300,15 @@ implements FrontworkComponent<RaidManagerIfc, RaidManagerFeatureIfc>, IRaidManag
|
|||||||
late: late
|
late: late
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return await this.admin
|
||||||
|
.knex('signups')
|
||||||
|
.select('*')
|
||||||
|
.where({
|
||||||
|
raidid: raid.id!,
|
||||||
|
characterid: character.id!,
|
||||||
|
})
|
||||||
|
.first()
|
||||||
}
|
}
|
||||||
|
|
||||||
unsign = async (usertoken:string, character:Character, raid:Raid) => {
|
unsign = async (usertoken:string, character:Character, raid:Raid) => {
|
||||||
|
|||||||
@@ -118,14 +118,13 @@ implements FrontworkComponent<UserManagerIfc, UserManagerFeatureIfc>, IUserManag
|
|||||||
initialize = async () => {
|
initialize = async () => {
|
||||||
this.exporters = [this.guild, this.item, this.raid, this.character]
|
this.exporters = [this.guild, this.item, this.raid, this.character]
|
||||||
//set up permissions
|
//set up permissions
|
||||||
getLogger('UserManager').debug('inserting permissions')
|
getLogger('UserManager').debug('setting up permissions')
|
||||||
|
|
||||||
await Promise.all(
|
await Promise.all(
|
||||||
[this, ...this.exporters].flatMap(exp => exp.exportRPCFeatures().map(async (feature) => {
|
[this, ...this.exporters].flatMap(exp => exp.exportRPCFeatures().map(async (feature) => {
|
||||||
try{
|
try{
|
||||||
await this.admin.knex.insert({ rpcname: feature.name }).into('rpcpermissions')
|
await this.admin.knex.insert({ rpcname: feature.name }).into('rpcpermissions')
|
||||||
}catch(e){
|
}catch(e){
|
||||||
getLogger('UserManager').debug(feature.name);
|
|
||||||
}
|
}
|
||||||
})))
|
})))
|
||||||
|
|
||||||
|
|||||||
@@ -1,3 +1,6 @@
|
|||||||
|
export type Tiers = "MC" | 'BWL' | 'ZG' | 'AQ20' | 'AQ40' | 'Naxx'
|
||||||
|
export const _Tiers = ["MC", 'BWL', 'ZG', 'AQ20', 'AQ40', 'Naxx']
|
||||||
|
|
||||||
export const T1 = [
|
export const T1 = [
|
||||||
"Robe of Volatile Power",
|
"Robe of Volatile Power",
|
||||||
"Salamander Scale Pants",
|
"Salamander Scale Pants",
|
||||||
@@ -132,4 +135,17 @@ export const T2:string[] = [
|
|||||||
"Draconic Avenger",
|
"Draconic Avenger",
|
||||||
"Interlaced Shadow Jerkin",
|
"Interlaced Shadow Jerkin",
|
||||||
"Ringo's Blizzard Boots"
|
"Ringo's Blizzard Boots"
|
||||||
]
|
]
|
||||||
|
|
||||||
|
export type AllItems = {
|
||||||
|
[tier in Tiers] : string[]
|
||||||
|
}
|
||||||
|
|
||||||
|
export const allItems : AllItems = {
|
||||||
|
MC: T1,
|
||||||
|
BWL: T2,
|
||||||
|
ZG:[],
|
||||||
|
AQ20: [],
|
||||||
|
AQ40: [],
|
||||||
|
Naxx: []
|
||||||
|
}
|
||||||
@@ -6,6 +6,7 @@ import { CharacterManagerIfc, CharacterManagerFeatureIfc } from "../Components/C
|
|||||||
import { ItemManagerFeatureIfc, ItemManagerIfc } from "../Components/Item/RPCInterface";
|
import { ItemManagerFeatureIfc, ItemManagerIfc } from "../Components/Item/RPCInterface";
|
||||||
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";
|
||||||
|
|
||||||
export type FrontcraftIfc = RaidManagerIfc
|
export type FrontcraftIfc = RaidManagerIfc
|
||||||
& UserManagerIfc
|
& UserManagerIfc
|
||||||
@@ -49,10 +50,10 @@ export type RPCPermission = {
|
|||||||
|
|
||||||
export type RaidData = Raid & {
|
export type RaidData = Raid & {
|
||||||
participants: {
|
participants: {
|
||||||
[clazz in Class] : (Character & Spec)[]
|
[clazz in Class] : (Signup & Character & Spec)[]
|
||||||
} & {
|
} & {
|
||||||
late: (Character & Spec)[]
|
late: (Signup & Character & Spec)[]
|
||||||
bench: (Character & Spec)[]
|
bench: (Signup & Character & Spec)[]
|
||||||
}
|
}
|
||||||
tokens: {
|
tokens: {
|
||||||
[itemname in string]: (Character & SRToken & Item)[]
|
[itemname in string]: (Character & SRToken & Item)[]
|
||||||
@@ -60,8 +61,9 @@ export type RaidData = Raid & {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export type SRToken = {
|
export type SRToken = {
|
||||||
|
signupid?:number
|
||||||
characterid: number,
|
characterid: number,
|
||||||
itemid: number,
|
itemname: string,
|
||||||
level: number
|
level: number
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -69,18 +71,18 @@ export type SRPriority = {
|
|||||||
id?:number
|
id?:number
|
||||||
race?:Race
|
race?:Race
|
||||||
specid?:number,
|
specid?:number,
|
||||||
itemid?:number,
|
itemname?:string,
|
||||||
description?:string,
|
description?:string,
|
||||||
modifier:number
|
modifier:number
|
||||||
}
|
}
|
||||||
|
|
||||||
export type Item = {
|
export type Item = {
|
||||||
id?:number
|
|
||||||
itemname:string
|
itemname:string
|
||||||
iconname:string
|
iconname:string
|
||||||
url:string
|
url:string
|
||||||
quality:string
|
quality:string
|
||||||
hidden:boolean
|
hidden:boolean
|
||||||
|
tier: Tiers
|
||||||
}
|
}
|
||||||
|
|
||||||
export type User = {
|
export type User = {
|
||||||
@@ -98,9 +100,11 @@ export type Raid = {
|
|||||||
start: string
|
start: string
|
||||||
signupcount?: number
|
signupcount?: number
|
||||||
size: number
|
size: number
|
||||||
|
tier: Tiers
|
||||||
}
|
}
|
||||||
|
|
||||||
export type Signup = {
|
export type Signup = {
|
||||||
|
id?:number
|
||||||
raidid: number
|
raidid: number
|
||||||
characterid: number
|
characterid: number
|
||||||
benched: boolean
|
benched: boolean
|
||||||
|
|||||||
@@ -1,13 +1,25 @@
|
|||||||
<nb-card
|
<nb-card
|
||||||
class = "col-12 col-xl-9"
|
class = "col-12 col-xl-9"
|
||||||
status="control">
|
status="control">
|
||||||
<nb-card-header [ngStyle]="{'color': color}" style="text-transform: capitalize;">
|
<nb-card-header style="text-transform: capitalize;">
|
||||||
{{char.charactername}}
|
<h4>
|
||||||
|
<a *ngIf="link === 'character'" [ngStyle]="{'color': color}" [routerLink]="'/frontcraft/character/'+char.charactername">
|
||||||
|
{{char.charactername}}
|
||||||
|
</a>
|
||||||
|
</h4>
|
||||||
|
<h3>
|
||||||
|
<span [ngStyle]="{'color': color}" *ngIf="link !== 'character'">
|
||||||
|
{{char.charactername}}
|
||||||
|
</span>
|
||||||
|
</h3>
|
||||||
</nb-card-header>
|
</nb-card-header>
|
||||||
|
|
||||||
<nb-card-body>
|
<nb-card-body>
|
||||||
{{char.race}}<br />
|
{{char.race}}<br />
|
||||||
{{char.specname}} {{char.class}}<br />
|
{{char.specname}} {{char.class}}<br />
|
||||||
Owned by <a [routerLink]="'/frontcraft/user/'+char.username"> {{char.username}} ({{char.rank}})</a>
|
<span *ngIf="link === 'owner'">
|
||||||
|
Owned by <a [routerLink]="'/frontcraft/user/'+char.username"> {{char.username}} ({{char.rank}})</a>
|
||||||
|
</span>
|
||||||
<br/><br />
|
<br/><br />
|
||||||
<span *ngFor="let token of tokens">
|
<span *ngFor="let token of tokens">
|
||||||
[ {{token.level}} ]
|
[ {{token.level}} ]
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import { Component, OnInit } from '@angular/core';
|
import { Component, OnInit, Input } from '@angular/core';
|
||||||
import { ActivatedRoute, Router } from '@angular/router';
|
import { ActivatedRoute, Router } from '@angular/router';
|
||||||
import { ApiService as ApiService } from '../../services/login-api';
|
import { ApiService as ApiService } from '../../services/login-api';
|
||||||
import { Spec, User, Character } from '../../../../../../backend/Types/Types';
|
import { Spec, User, Character } from '../../../../../../backend/Types/Types';
|
||||||
@@ -10,6 +10,9 @@ import { getClassColor } from '../../../../../../backend/Types/PlayerSpecs';
|
|||||||
})
|
})
|
||||||
export class FrontcraftCharacterComponent implements OnInit{
|
export class FrontcraftCharacterComponent implements OnInit{
|
||||||
|
|
||||||
|
@Input() name?: string
|
||||||
|
@Input() link?: "owner" | "character" = 'owner'
|
||||||
|
|
||||||
char : (Character & User & Spec) = {} as any
|
char : (Character & User & Spec) = {} as any
|
||||||
color : string
|
color : string
|
||||||
tokens
|
tokens
|
||||||
@@ -20,7 +23,9 @@ export class FrontcraftCharacterComponent implements OnInit{
|
|||||||
){}
|
){}
|
||||||
|
|
||||||
async ngOnInit(){
|
async ngOnInit(){
|
||||||
const param = this.route.snapshot.paramMap.get('name');
|
const param = this.name || this.route.snapshot.paramMap.get('name');
|
||||||
|
if(!param) return
|
||||||
|
|
||||||
this.api.get('CharacterManager')
|
this.api.get('CharacterManager')
|
||||||
.getCharacterByName(param)
|
.getCharacterByName(param)
|
||||||
.then((char) => {
|
.then((char) => {
|
||||||
|
|||||||
@@ -6,9 +6,6 @@
|
|||||||
</nb-card-body>
|
</nb-card-body>
|
||||||
</nb-card>
|
</nb-card>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
<nb-card class="col-12 col-xl-9">
|
<nb-card class="col-12 col-xl-9">
|
||||||
<nb-card-body>
|
<nb-card-body>
|
||||||
<input type="text" nbInput [(ngModel)]="search" (change)="changeSearch()" placeholder="Search" fullWidth="true" />
|
<input type="text" nbInput [(ngModel)]="search" (change)="changeSearch()" placeholder="Search" fullWidth="true" />
|
||||||
|
|||||||
@@ -32,11 +32,12 @@ import { FrontcraftRaidComponent } from './raid/raid.component';
|
|||||||
import { FrontcraftArchiveComponent } from './raid/archive.component';
|
import { FrontcraftArchiveComponent } from './raid/archive.component';
|
||||||
import { NbEvaIconsModule } from '@nebular/eva-icons';
|
import { NbEvaIconsModule } from '@nebular/eva-icons';
|
||||||
import { FrontcraftCharacerpickerComponent } from './raid/characterpicker.component';
|
import { FrontcraftCharacerpickerComponent } from './raid/characterpicker.component';
|
||||||
import { FrontcraftShopComponent, FrontcraftBuyTokenComponent } from './shop/shop.component';
|
import { FrontcraftShopComponent } from './shop/shop.component';
|
||||||
import { FrontcraftRulesComponent } from './rules/rules.component';
|
import { FrontcraftRulesComponent } from './rules/rules.component';
|
||||||
import { FrontcraftItemSelectComponent } from './shop/itemselector.component';
|
import { FrontcraftItemSelectComponent } from './shop/itemselector.component';
|
||||||
import { NgxEchartsModule } from 'ngx-echarts';
|
import { NgxEchartsModule } from 'ngx-echarts';
|
||||||
import { FrontcraftCharactersComponent } from './characters/characters.component';
|
import { FrontcraftCharactersComponent } from './characters/characters.component';
|
||||||
|
import { FrontcraftBuyTokenComponent } from './shop/buytoken.component';
|
||||||
|
|
||||||
|
|
||||||
@NgModule({
|
@NgModule({
|
||||||
|
|||||||
@@ -67,14 +67,15 @@
|
|||||||
</div>
|
</div>
|
||||||
</nb-card-body>
|
</nb-card-body>
|
||||||
</nb-card>
|
</nb-card>
|
||||||
|
|
||||||
</ng-container>
|
</ng-container>
|
||||||
</div>
|
</div>
|
||||||
</nb-tab>
|
</nb-tab>
|
||||||
|
<nb-tab tabTitle="Shop">
|
||||||
|
<shop (onSelect)="itemSelect($event)"></shop>
|
||||||
|
</nb-tab>
|
||||||
<nb-tab tabTitle="Reserves">
|
<nb-tab tabTitle="Reserves">
|
||||||
<nb-list>
|
<nb-list>
|
||||||
<nb-list-item *ngFor="let item of raid.tokens | keyvalue">
|
<nb-list-item *ngFor="let item of raid.tokens | keyvalue">
|
||||||
|
|
||||||
<a [ngStyle]="{'color':item.value[0].quality=='Epic'?'#a335ee':'#ff8000'}"
|
<a [ngStyle]="{'color':item.value[0].quality=='Epic'?'#a335ee':'#ff8000'}"
|
||||||
target="_blank"
|
target="_blank"
|
||||||
[href]="item.value[0].url">
|
[href]="item.value[0].url">
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ import { RaidData, Raid, Signup } from '../../../../../../backend/Types/Types';
|
|||||||
import { NbWindowService, NbToastrService, NbDialogService } from '@nebular/theme';
|
import { NbWindowService, NbToastrService, NbDialogService } from '@nebular/theme';
|
||||||
import { FrontcraftCharacerpickerComponent } from './characterpicker.component';
|
import { FrontcraftCharacerpickerComponent } from './characterpicker.component';
|
||||||
import { getClassColor } from '../../../../../../backend/Types/PlayerSpecs';
|
import { getClassColor } from '../../../../../../backend/Types/PlayerSpecs';
|
||||||
|
import { FrontcraftBuyTokenComponent } from '../shop/buytoken.component';
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'raid',
|
selector: 'raid',
|
||||||
@@ -52,6 +53,15 @@ export class FrontcraftRaidComponent implements OnInit{
|
|||||||
this.refresh()
|
this.refresh()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
itemSelect = async(item) => {
|
||||||
|
this.dialogService.open(FrontcraftBuyTokenComponent, {
|
||||||
|
context: {
|
||||||
|
item: item,
|
||||||
|
signup: this.mySignup
|
||||||
|
}
|
||||||
|
}).onClose.subscribe(() => this.refresh())
|
||||||
|
}
|
||||||
|
|
||||||
signup = async () => {
|
signup = async () => {
|
||||||
const signupFeature = this.api.get('signup')
|
const signupFeature = this.api.get('signup')
|
||||||
if(!signupFeature) return
|
if(!signupFeature) return
|
||||||
@@ -60,7 +70,7 @@ export class FrontcraftRaidComponent implements OnInit{
|
|||||||
closeOnBackdropClick: true,
|
closeOnBackdropClick: true,
|
||||||
closeOnEsc: true,
|
closeOnEsc: true,
|
||||||
context: {
|
context: {
|
||||||
'raid': this.raid,
|
raid: this.raid,
|
||||||
}
|
}
|
||||||
}).onClose.subscribe(()=>{
|
}).onClose.subscribe(()=>{
|
||||||
this.refresh()
|
this.refresh()
|
||||||
@@ -83,7 +93,7 @@ export class FrontcraftRaidComponent implements OnInit{
|
|||||||
const signupFeature = this.api.get('signup')
|
const signupFeature = this.api.get('signup')
|
||||||
if(!signupFeature) return
|
if(!signupFeature) return
|
||||||
|
|
||||||
await signupFeature.unsign(this.api.getAuth().token.value, this.mySignup, this.raid)
|
await signupFeature.unsign(this.api.getAuth().token.value, <any>{id: this.mySignup.characterid, userid: this.mySignup.userid}, this.raid)
|
||||||
this.toast.show('Success', 'Unsigned', { status: 'success' })
|
this.toast.show('Success', 'Unsigned', { status: 'success' })
|
||||||
this.refresh()
|
this.refresh()
|
||||||
}
|
}
|
||||||
@@ -102,7 +112,8 @@ export class FrontcraftRaidComponent implements OnInit{
|
|||||||
})
|
})
|
||||||
const user = this.api.getCurrentUser()
|
const user = this.api.getCurrentUser()
|
||||||
const matchingSignup = Object.values(raiddata.participants).flat().find(char => user && char.userid === user.id!)
|
const matchingSignup = Object.values(raiddata.participants).flat().find(char => user && char.userid === user.id!)
|
||||||
if(matchingSignup){
|
if(matchingSignup){
|
||||||
|
|
||||||
this.isSignedup = true
|
this.isSignedup = true
|
||||||
this.mySignup = matchingSignup
|
this.mySignup = matchingSignup
|
||||||
this.mySignup.status = matchingSignup['benched']?'Bench':matchingSignup['late']?'Late':'Attending'
|
this.mySignup.status = matchingSignup['benched']?'Bench':matchingSignup['late']?'Late':'Attending'
|
||||||
|
|||||||
@@ -4,7 +4,7 @@
|
|||||||
<nb-tab tabTitle="Info">
|
<nb-tab tabTitle="Info">
|
||||||
Smart text here
|
Smart text here
|
||||||
</nb-tab>
|
</nb-tab>
|
||||||
<nb-tab *ngIf="managePriorities" 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">
|
||||||
<a [ngStyle]="{'color':item.value[0].quality=='Epic'?'#a335ee':'#ff8000'}"
|
<a [ngStyle]="{'color':item.value[0].quality=='Epic'?'#a335ee':'#ff8000'}"
|
||||||
|
|||||||
@@ -0,0 +1,104 @@
|
|||||||
|
import { Component, OnInit, ContentChild, AfterContentInit, ViewChild, AfterViewInit, Input, Output, EventEmitter } from '@angular/core';
|
||||||
|
import { ApiService as ApiService } from '../../services/login-api';
|
||||||
|
import { FrontcraftItemSelectComponent } from './itemselector.component';
|
||||||
|
import { NbWindowService, NbWindowRef, NbToastrService, NbDialogService, NbDialogRef } from '@nebular/theme';
|
||||||
|
import { Item, Character, SRToken, Signup } from '../../../../../../backend/Types/Types';
|
||||||
|
import { getClassColor } from '../../../../../../backend/Types/PlayerSpecs';
|
||||||
|
import { _Tiers, allItems, Tiers } from '../../../../../../backend/Types/Items';
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
selector: 'buyToken',
|
||||||
|
template: `
|
||||||
|
<nb-card class="col-12 col-xl-9">
|
||||||
|
<nb-card-header>
|
||||||
|
Buy {{item.itemname}}
|
||||||
|
</nb-card-header>
|
||||||
|
<nb-card-body>
|
||||||
|
<p>
|
||||||
|
You currently have {{currency}} softreserve currency
|
||||||
|
</p>
|
||||||
|
<div *ngIf="currency>0">
|
||||||
|
<div *ngFor="let kv of modifier | keyvalue">
|
||||||
|
<button
|
||||||
|
(click)="buyToken(kv.key)"
|
||||||
|
[disabled]="currency<=0"
|
||||||
|
nbButton
|
||||||
|
outline
|
||||||
|
status="success"
|
||||||
|
size="tiny">
|
||||||
|
buy
|
||||||
|
</button>
|
||||||
|
{{kv.key}} <span *ngIf="kv.value>0">(<b>+{{kv.value}}</b> from priorities)</span>
|
||||||
|
</div>
|
||||||
|
<div *ngFor="let token of ownedtokens">
|
||||||
|
<button
|
||||||
|
(click)="buyToken(token.charactername)"
|
||||||
|
nbButton
|
||||||
|
outline
|
||||||
|
status="success"
|
||||||
|
size="tiny">
|
||||||
|
buy
|
||||||
|
</button>
|
||||||
|
{{token.charactername}} [ {{token.level}} ] => [ {{token.level+1}} ]
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</nb-card-body>
|
||||||
|
</nb-card>
|
||||||
|
|
||||||
|
`,
|
||||||
|
})
|
||||||
|
export class FrontcraftBuyTokenComponent implements OnInit{
|
||||||
|
|
||||||
|
@Input() item : Item
|
||||||
|
@Input() signup : Signup
|
||||||
|
|
||||||
|
@Input() tier: Tiers
|
||||||
|
|
||||||
|
characters: Character[]
|
||||||
|
modifier = {}
|
||||||
|
currency: number = 0
|
||||||
|
ownedtokens: SRToken[] = []
|
||||||
|
|
||||||
|
constructor(
|
||||||
|
private toastr: NbToastrService,
|
||||||
|
protected dialogRef: NbDialogRef<FrontcraftBuyTokenComponent>,
|
||||||
|
private api : ApiService
|
||||||
|
){}
|
||||||
|
|
||||||
|
ngOnInit(): void {
|
||||||
|
const usr = this.api.getCurrentUser()
|
||||||
|
this.api.get('CharacterManager')
|
||||||
|
.getCharactersOfUser(usr.username)
|
||||||
|
.then(chars => {
|
||||||
|
chars.forEach(char => {
|
||||||
|
char['color'] = getClassColor(char.class)
|
||||||
|
this.api.get('ItemManager').getToken(char, this.item).then(token => {
|
||||||
|
if(token) this.ownedtokens.push(token)
|
||||||
|
else{
|
||||||
|
this.api.get('ItemManager').calculatePriorities(this.item.itemname, char).then(modifier => {
|
||||||
|
this.modifier[char.charactername] = modifier
|
||||||
|
})
|
||||||
|
}
|
||||||
|
})
|
||||||
|
})
|
||||||
|
this.characters = chars
|
||||||
|
})
|
||||||
|
this.api.get('UserManager').getUser(usr.username).then(u => {
|
||||||
|
if(!u) return
|
||||||
|
this.currency = u.currency
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
buyToken = async (charactername:string) => {
|
||||||
|
|
||||||
|
const src = this.api.get('ItemManager')
|
||||||
|
const token = await src.buyToken(this.api.getAuth().token.value, charactername, this.item.itemname, this.signup)
|
||||||
|
|
||||||
|
if(token){
|
||||||
|
this.toastr.show(token.characterid+' now has a token for '+token.itemname+' of level '+token.level, 'Yay', {status: 'success'})
|
||||||
|
}else{
|
||||||
|
this.toastr.show('Error (something went wrong)', 'Oh no', {status: 'danger'})
|
||||||
|
}
|
||||||
|
this.dialogRef.close()
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
import { Component, OnInit } from '@angular/core';
|
import { Component, OnInit, Input, Output, EventEmitter } from '@angular/core';
|
||||||
import { ApiService } from '../../services/login-api';
|
import { ApiService } from '../../services/login-api';
|
||||||
import { Item } from '../../../../../../backend/Types/Types';
|
import { Item } from '../../../../../../backend/Types/Types';
|
||||||
|
|
||||||
@@ -10,10 +10,11 @@ export class FrontcraftItemSelectComponent implements OnInit{
|
|||||||
|
|
||||||
selected: Item
|
selected: Item
|
||||||
search: string
|
search: string
|
||||||
items: any[]
|
allItems:Item[] = []
|
||||||
displayedItems: any[]
|
displayedItems: any[]
|
||||||
|
|
||||||
callbacks = []
|
@Input() items: string[]
|
||||||
|
@Output() onSelect = new EventEmitter<Item>();
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
private api: ApiService,
|
private api: ApiService,
|
||||||
@@ -21,25 +22,23 @@ export class FrontcraftItemSelectComponent implements OnInit{
|
|||||||
}
|
}
|
||||||
|
|
||||||
async ngOnInit(){
|
async ngOnInit(){
|
||||||
this.api.get('ItemManager').getItems().then(items => {
|
Promise.all(this.items.map(itemname =>
|
||||||
this.items = items
|
this.api.get('ItemManager').getItem(itemname)
|
||||||
this.displayedItems = items
|
)).then(items => {
|
||||||
|
this.allItems = items
|
||||||
|
this.displayedItems = this.allItems
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
changeSearch(){
|
changeSearch(){
|
||||||
if(!this.search || this.search == "")
|
if(!this.search || this.search == "")
|
||||||
this.displayedItems = this.items
|
this.displayedItems = this.allItems
|
||||||
else
|
else
|
||||||
this.displayedItems = this.items.filter(it => it.itemname.toLowerCase().includes(this.search.toLowerCase()))
|
this.displayedItems = this.allItems.filter(it => it.itemname.toLowerCase().includes(this.search.toLowerCase()))
|
||||||
}
|
}
|
||||||
|
|
||||||
select(item: Item){
|
select(item: Item){
|
||||||
this.selected = item
|
this.onSelect.emit(item)
|
||||||
this.callbacks.forEach(cb => cb(item))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
onselect(callback:Function){
|
|
||||||
this.callbacks.push(callback)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
@@ -1,13 +1,7 @@
|
|||||||
|
<h3>
|
||||||
|
{{tier}} items
|
||||||
|
</h3>
|
||||||
|
|
||||||
<nb-card class="col-12 col-xl-9">
|
<itemselect
|
||||||
<nb-card-body>
|
[items]="allItems[tier]"
|
||||||
<nb-tabset>
|
(onSelect)="onSelect.emit($event)"></itemselect>
|
||||||
<nb-tab tabTitle="Items">
|
|
||||||
<itemselect></itemselect>
|
|
||||||
</nb-tab>
|
|
||||||
<nb-tab tabTitle="About">
|
|
||||||
</nb-tab>
|
|
||||||
</nb-tabset>
|
|
||||||
</nb-card-body>
|
|
||||||
</nb-card>
|
|
||||||
|
|
||||||
|
|||||||
@@ -1,43 +1,28 @@
|
|||||||
import { Component, OnInit, ContentChild, AfterContentInit, ViewChild, AfterViewInit } from '@angular/core';
|
import { Component, OnInit, ContentChild, AfterContentInit, ViewChild, AfterViewInit, Input, Output, EventEmitter } from '@angular/core';
|
||||||
import { ApiService as ApiService } from '../../services/login-api';
|
import { ApiService as ApiService } from '../../services/login-api';
|
||||||
import { FrontcraftItemSelectComponent } from './itemselector.component';
|
import { FrontcraftItemSelectComponent } from './itemselector.component';
|
||||||
import { NbWindowService, NbWindowRef, NbToastrService, NbDialogService, NbDialogRef } from '@nebular/theme';
|
import { NbWindowService, NbWindowRef, NbToastrService, NbDialogService, NbDialogRef } from '@nebular/theme';
|
||||||
import { Item, Character, SRToken } from '../../../../../../backend/Types/Types';
|
import { Item, Character, SRToken, Signup } from '../../../../../../backend/Types/Types';
|
||||||
import { getClassColor } from '../../../../../../backend/Types/PlayerSpecs';
|
import { getClassColor } from '../../../../../../backend/Types/PlayerSpecs';
|
||||||
|
import { _Tiers, allItems } from '../../../../../../backend/Types/Items';
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'shop',
|
selector: 'shop',
|
||||||
templateUrl: './shop.component.html',
|
templateUrl: './shop.component.html',
|
||||||
})
|
})
|
||||||
export class FrontcraftShopComponent implements AfterViewInit{
|
export class FrontcraftShopComponent{
|
||||||
|
|
||||||
@ViewChild(FrontcraftItemSelectComponent, {static: false})
|
@Input() character: Character
|
||||||
itemselect !: FrontcraftItemSelectComponent
|
@Input() signup: Signup
|
||||||
|
|
||||||
|
@Input() tier = _Tiers[0]
|
||||||
|
@Output() onSelect = new EventEmitter<Item>()
|
||||||
|
allItems = allItems
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
private api: ApiService,
|
private api: ApiService,
|
||||||
private dialogService : NbDialogService
|
private dialogService : NbDialogService
|
||||||
|
){}
|
||||||
){
|
|
||||||
window['shop'] = this
|
|
||||||
}
|
|
||||||
|
|
||||||
buy = (item) => {
|
|
||||||
|
|
||||||
this.dialogService.open(FrontcraftBuyTokenComponent, {
|
|
||||||
closeOnBackdropClick: true,
|
|
||||||
closeOnEsc: true,
|
|
||||||
context: {
|
|
||||||
item: item
|
|
||||||
}
|
|
||||||
}).onClose.subscribe(()=>{
|
|
||||||
});
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
ngAfterViewInit(){
|
|
||||||
this.itemselect.onselect(this.buy)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
|
|||||||
@@ -7,32 +7,8 @@ accent="info">
|
|||||||
</nb-card-header>
|
</nb-card-header>
|
||||||
<nb-card-body>
|
<nb-card-body>
|
||||||
{{user.currency}}
|
{{user.currency}}
|
||||||
<nb-card
|
<ng-container *ngFor="let char of characters">
|
||||||
accent="control"
|
<character [name]="char.charactername" [link]="'character'"></character>
|
||||||
*ngFor="let char of characters">
|
</ng-container>
|
||||||
<nb-card-header>
|
|
||||||
<h4>
|
|
||||||
<a [ngStyle]="{'color': char.color}" style="text-transform: capitalize;" [routerLink]="'/frontcraft/character/'+char.charactername">
|
|
||||||
{{char.charactername}}
|
|
||||||
</a>
|
|
||||||
</h4>
|
|
||||||
</nb-card-header>
|
|
||||||
<nb-card-body>
|
|
||||||
{{char.race}}<br />
|
|
||||||
{{char.specname}} {{char.class}}
|
|
||||||
<br />
|
|
||||||
<br />
|
|
||||||
<span *ngFor="let token of char.tokens">
|
|
||||||
[ {{token.level}} ]
|
|
||||||
<a [ngStyle]="{'color':token.quality=='Epic'?'#a335ee':'#ff8000'}"
|
|
||||||
target="_blank"
|
|
||||||
[href]="token.url">
|
|
||||||
<img style="min-width: 25px; width: 2.25vw; max-width: 50px"
|
|
||||||
[src]="'https://wow.zamimg.com/images/wow/icons/large/'+token.iconname+'.jpg'" />
|
|
||||||
{{token.itemname}}
|
|
||||||
</a><br />
|
|
||||||
</span>
|
|
||||||
</nb-card-body>
|
|
||||||
</nb-card>
|
|
||||||
</nb-card-body>
|
</nb-card-body>
|
||||||
</nb-card>
|
</nb-card>
|
||||||
|
|||||||
@@ -134,14 +134,6 @@ export class ApiService{
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function str2arraybuf(str:string): ArrayBuffer {
|
|
||||||
return new Buffer(str)
|
|
||||||
}
|
|
||||||
|
|
||||||
function buf2hex(buffer: ArrayBuffer) {
|
|
||||||
return Array.prototype.map.call(new Uint8Array(buffer), x => ('00' + x.toString(16)).slice(-2)).join('');
|
|
||||||
}
|
|
||||||
|
|
||||||
export async function hash(value:string) : Promise<string>{
|
export async function hash(value:string) : Promise<string>{
|
||||||
return saltedHash(value, "")
|
return saltedHash(value, "")
|
||||||
}
|
}
|
||||||
|
|||||||
+22
-12
@@ -3,7 +3,7 @@ import { FrontworkAdmin } from "../src/backend/Admin/Admin";
|
|||||||
import { T1 } from "../src/backend/Types/Items";
|
import { T1 } 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 } from "../src/backend/Types/Types";
|
import { FrontcraftIfc, Auth, User, FrontcraftFeatureIfc, Raid, Character, Rank, Class, Race, SRPriority, Spec, Signup } from "../src/backend/Types/Types";
|
||||||
import { SpecT } from "../src/backend/Types/PlayerSpecs";
|
import { SpecT } from "../src/backend/Types/PlayerSpecs";
|
||||||
|
|
||||||
|
|
||||||
@@ -107,7 +107,7 @@ describe('Frontcraft', () => {
|
|||||||
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, 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)
|
||||||
@@ -217,9 +217,12 @@ describe('Frontcraft', () => {
|
|||||||
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 => {
|
||||||
|
users[sign.username].signup = sign
|
||||||
|
})
|
||||||
done()
|
done()
|
||||||
else{
|
}else{
|
||||||
done("Unexpected number of signups: "+s.length)
|
done("Unexpected number of signups: "+s.length)
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
@@ -467,7 +470,7 @@ describe('Frontcraft', () => {
|
|||||||
const itemname = T1[0]//T1[Math.floor(T1.length*Math.random())]
|
const itemname = T1[0]//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)
|
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
|
||||||
@@ -480,7 +483,7 @@ describe('Frontcraft', () => {
|
|||||||
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 = T1[0]
|
||||||
client.ItemManager.buyToken(user.auth.token.value, user.character.charactername, itemname).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 {
|
||||||
@@ -497,12 +500,18 @@ describe('Frontcraft', () => {
|
|||||||
const item = await client.ItemManager.getItem(itemname)
|
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) return
|
if(!before || before.level !== 7) {
|
||||||
|
console.log("expected level to be 7", before);
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
await client.ItemManager.buyToken(user.auth.token.value, user.character.charactername, itemname)
|
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)
|
const after = await client.ItemManager.buyToken(user.auth.token.value, user.character.charactername, itemname, user.signup!)
|
||||||
|
|
||||||
if(!after || after.level !== 9) return
|
if(!after || after.level !== 9) {
|
||||||
|
console.log("expected level to be 9", after);
|
||||||
|
return
|
||||||
|
}
|
||||||
done()
|
done()
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
@@ -510,11 +519,12 @@ 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, 1)
|
await adminClient.softreserveCurrency.incrementCurrency(user.account, 1)
|
||||||
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())]
|
T1[Math.floor(T1.length*Math.random())],
|
||||||
|
user.signup!
|
||||||
)
|
)
|
||||||
})).then(_ => {
|
})).then(_ => {
|
||||||
done()
|
done()
|
||||||
|
|||||||
Reference in New Issue
Block a user