diff --git a/src/backend/Admin/Admin.ts b/src/backend/Admin/Admin.ts index 65a6e11..be0a143 100644 --- a/src/backend/Admin/Admin.ts +++ b/src/backend/Admin/Admin.ts @@ -102,6 +102,13 @@ implements TableDefinitionExporter, IAdmin { private startWebsocket(){ this.rpcServer = new RPCServer(20000, [ ...this.frontworkComponents, + { + name: "debug", + exportRPCs: () => [{ + name: 'dumpDb', + call: async (table) => await this.knex(table).select('*') + }] + } ], { visibility: '0.0.0.0' }) diff --git a/src/backend/Components/Item/Interface.ts b/src/backend/Components/Item/Interface.ts index 9704e6e..007f7d4 100644 --- a/src/backend/Components/Item/Interface.ts +++ b/src/backend/Components/Item/Interface.ts @@ -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{ getItems: () => Promise fetchItem: (name:string) => Promise - 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 calculatePriorities: (itemname: string, character:Character) => Promise deletePriority: (priority:SRPriority) => Promise diff --git a/src/backend/Components/Item/ItemManager.ts b/src/backend/Components/Item/ItemManager.ts index dbdb473..f24965a 100644 --- a/src/backend/Components/Item/ItemManager.ts +++ b/src/backend/Components/Item/ItemManager.ts @@ -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 { ItemManagerFeatureIfc, ItemManagerIfc } from "./RPCInterface"; import { FrontworkComponent } from "../../Types/FrontworkComponent"; 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 { IItemManager } from "./Interface"; import { getLogger } from "log4js"; @@ -87,19 +87,21 @@ implements FrontworkComponent, TableDefin { name: 'tokens', tableBuilder: (table) => { - table.primary(['characterid', 'itemid']) + table.primary(['characterid', 'itemname']) table.integer("characterid") table.foreign("characterid").references("id").inTable('characters') - table.integer("itemid") - table.foreign("itemid").references("id").inTable('items') + table.string("itemname") + 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) } },{ name: 'priorities', tableBuilder: (table) => { table.increments('id').primary() - table.integer('itemid') - table.foreign('itemid').references('id').inTable('items') + table.string('itemname') + table.foreign('itemname').references('itemname').inTable('items') table.string('race').nullable() table.integer('specid').nullable() table.foreign('specid').references('id').inTable('specs') @@ -109,17 +111,17 @@ implements FrontworkComponent, TableDefin },{ name: 'items', tableBuilder: (table) => { - table.increments("id").primary() - table.string('itemname').unique().notNullable() + table.string('itemname').unique().notNullable().primary() table.string('iconname').notNullable() table.string('url').notNullable() table.string('quality').defaultTo('Epic').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 character = await this.character.getCharacterByName(charactername) @@ -131,30 +133,62 @@ implements FrontworkComponent, TableDefin const currency = await this.userManager.getCurrency(record.user) 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) + const modifier = await this.calculatePriorities(itemname, character) - if(!existingToken){ - const modifier = await this.calculatePriorities(itemname, character) - await this.admin.knex('tokens').insert({ - characterid: character.id, - itemid: item.id, - level: 1+modifier - }) - }else{ - await this.admin.knex('tokens').where({ - characterid: character.id, - itemid: item.id - }).increment('level') + //tokens with deleted signups + if(shadowTokens.length > 0){ + //token for current item + const matchingtoken = shadowTokens.find(token => token.itemname === itemname) + if(matchingtoken){ + //update signupid and increment level + + console.log("delete shadow tokens"); + + await this.admin + .knex('tokens') + .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) } getAllPriorities = async() :Promise<(SRPriority & Spec & Item)[]> => this.admin .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') .select('*') @@ -170,24 +204,24 @@ implements FrontworkComponent, TableDefin await this.admin .knex('priorities') .insert({ - itemid: item.id, + itemname: item.itemname, ...priority }) } getPriorities = async(itemname:string) : Promise => { - const item = await this.getItem(itemname) - - return await this.admin.knex('priorities') - .where('itemid', '=', item.id) + return await this.admin + .knex('priorities as p') + .where('p.itemname', '=', itemname) .select('*') } calculatePriorities = async (itemname: string, character:Character):Promise=> { - const rules : SRPriority[] = await this.admin.knex('priorities as p') + const rules : SRPriority[] = await this.admin + .knex('priorities as p') .select('*') - .join('items as i', 'i.id', '=', 'p.itemid') - .where('itemname', '=', itemname) + .join('items as i', 'i.itemname', '=', 'p.itemname') + .where('p.itemname', '=', itemname) return rules.map(rule => { if(rule.specid && rule.race){ @@ -219,28 +253,37 @@ implements FrontworkComponent, TableDefin .knex('tokens as t') .select('*') .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({ characterid: character.id, - itemid: item.id + "i.itemname": item.itemname }) .first() } - getTokens = async (character:Character) : Promise<(SRToken & Character & Item)[]> => { + getTokens = async (character:Character, valid=true) : Promise<(SRToken & Character & Item)[]> => { return await this.admin .knex('tokens as t') .select('*') - .select('*') .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({ characterid: character.id, }) + .andWhere(function(){ + if(valid){ + this.whereNotNull('t.signupid') + }else{ + this.whereNull('t.signupid') + } + }) } countItems = async() :Promise => { - const count = await this.admin.knex('items').count('*'); + const count = await this.admin + .knex('items') + .count('*'); + return count[0]['count(*)'] } @@ -249,20 +292,24 @@ implements FrontworkComponent, TableDefin if(this.initialized) return this.initialized = true - const allItems = [...T1, ...T2] + const itemTiers = allItems const countCache = await this.countItems() - getLogger('ItemManager').debug('Checking items, got: ',countCache, 'expected: ', allItems.length) - if(countCache != allItems.length){ - const items:Item[] = await Promise.all(allItems.map((i) => this.fetchItem(i))) - try{ - await this.admin - .knex('items') - .insert(items) - }catch(e){ - getLogger('ItemManager').debug("Skipping item insertion") - } + if(countCache != Object.values(itemTiers).flat().length){ + await Promise.all( + Object.entries(itemTiers) + .map((kv) => Promise.all( + kv[1].map(i => this.fetchItem(i) + .then(item => this.admin + .knex('items') + .insert({ + tier: kv[0], + ...item + }) + )) + )) + ) } } } \ No newline at end of file diff --git a/src/backend/Components/Raid/Interface.ts b/src/backend/Components/Raid/Interface.ts index 6b9fe25..0b173a8 100644 --- a/src/backend/Components/Raid/Interface.ts +++ b/src/backend/Components/Raid/Interface.ts @@ -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{ getRaids: () => Promise createRaid: (raid:Raid) => Promise addSignup: (signup: Signup) => Promise removeSignup: (signup: Signup) => Promise - getSignups: (raid:Raid) => Promise + getSignups: (raid:Raid) => Promise<(Signup & Character & Spec & User)[]> sign: (userToken: string, character:Character, raid:Raid, late:boolean) => Promise unsign: (userToken: string, character:Character, raid:Raid,) => Promise archiveRaid: (raid:Raid) => Promise diff --git a/src/backend/Components/Raid/RaidManager.ts b/src/backend/Components/Raid/RaidManager.ts index 7cabd50..b12b241 100644 --- a/src/backend/Components/Raid/RaidManager.ts +++ b/src/backend/Components/Raid/RaidManager.ts @@ -1,11 +1,12 @@ import { Inject, Injectable } from "../../Injector/ServiceDecorator"; import { RaidManagerIfc, RaidManagerFeatureIfc } from "./RPCInterface"; 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 { IRaidManager } from "./Interface"; import { IUserManager } from "../User/Interface"; import { ICharacterManager } from "../Character/Interface"; +import { _Tiers } from "../../Types/Items"; @Injectable(IRaidManager) export class RaidManager @@ -59,6 +60,7 @@ implements FrontworkComponent, IRaidManag table.string('description').notNullable() table.string('title').notNullable() table.integer('size').defaultTo(40) + table.enu('tier', _Tiers).defaultTo(null as any) } },{ name: 'archive', @@ -69,7 +71,8 @@ implements FrontworkComponent, IRaidManag },{ name: 'signups', tableBuilder: (table) => { - table.primary(['raidid', 'characterid']) + table.increments('id').primary() + table.unique(['raidid', 'characterid']) table.integer('raidid') table.foreign('raidid').references('id').inTable('raids').onDelete('CASCADE') table.integer('characterid') @@ -95,7 +98,7 @@ implements FrontworkComponent, IRaidManag raid_id: signup.raidid, character_id: signup.characterid }) - .delete() + .del() getRaids = async () : Promise => { @@ -116,7 +119,6 @@ implements FrontworkComponent, IRaidManag startRaid = async (raid:Raid) : Promise => { const archived = await this.archiveRaid(raid) - delete archived.participants.late const giveCurrency = async (b: Character) => { @@ -138,8 +140,17 @@ implements FrontworkComponent, IRaidManag .insert({ id:raidData.id, 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') .where('id', '=', raid.id) @@ -175,17 +186,17 @@ implements FrontworkComponent, IRaidManag getRaidData = async (raid:Raid) : Promise => { const ret = { participants:{ - Druid: <(Character&Spec)[]>[], - Hunter: <(Character&Spec)[]>[], - Mage: <(Character&Spec)[]>[], - Paladin: <(Character&Spec)[]>[], - Priest: <(Character&Spec)[]>[], - Rogue: <(Character&Spec)[]>[], - Shaman: <(Character&Spec)[]>[], - Warlock: <(Character&Spec)[]>[], - Warrior: <(Character&Spec)[]>[], - late: <(Character&Spec)[]>[], - bench: <(Character&Spec)[]>[], + Druid: <(Signup&Character&Spec)[]>[], + Hunter: <(Signup&Character&Spec)[]>[], + Mage: <(Signup&Character&Spec)[]>[], + Paladin: <(Signup&Character&Spec)[]>[], + Priest: <(Signup&Character&Spec)[]>[], + Rogue: <(Signup&Character&Spec)[]>[], + Shaman: <(Signup&Character&Spec)[]>[], + Warlock: <(Signup&Character&Spec)[]>[], + Warrior: <(Signup&Character&Spec)[]>[], + late: <(Signup&Character&Spec)[]>[], + bench: <(Signup&Character&Spec)[]>[], }, tokens:{} } @@ -205,9 +216,9 @@ implements FrontworkComponent, IRaidManag .where('id','=',raid.id) .first() - const characterData: (Character & Spec & Signup)[] = await this.admin + const characterData: (Signup & Character & Spec)[] = await this.admin .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('characters as c', 's.characterid','=','c.id') .join('users as u', 'c.userid','=','u.id') @@ -228,12 +239,15 @@ implements FrontworkComponent, IRaidManag const tokenData: (Character & SRToken & Item)[] = await this.admin .knex('signups as s') - .select('*') + .select('*', 's.id as id') .join('raids as r', 's.raidid','=','r.id') .where('r.id','=',raid.id) + .andWhere(function(){ + this.whereNotNull('t.signupid') + }) .join('characters as c', 's.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 => { if(!ret.tokens[data.itemname]) @@ -246,12 +260,12 @@ implements FrontworkComponent, IRaidManag } } - getSignups = async (raid:Raid) : Promise => await this.admin - .knex('signups') + getSignups = async (raid:Raid) : Promise<(Signup & Character & Spec & User)[]> => await this.admin + .knex('signups as si') .join('characters as c', 'c.id', '=', 'characterid') .join('specs as s', 's.id', '=', 'specid') .join('users as u', 'u.id', '=', 'userid') - .select('*') + .select('*','si.id as id') .where('raidid', '=', raid.id!) sign = async (usertoken:string, character:Character, raid:Raid, late:boolean) => { @@ -286,6 +300,15 @@ implements FrontworkComponent, IRaidManag 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) => { diff --git a/src/backend/Components/User/UserManager.ts b/src/backend/Components/User/UserManager.ts index ca62a0f..7f7f5b4 100644 --- a/src/backend/Components/User/UserManager.ts +++ b/src/backend/Components/User/UserManager.ts @@ -118,14 +118,13 @@ implements FrontworkComponent, IUserManag initialize = async () => { this.exporters = [this.guild, this.item, this.raid, this.character] //set up permissions - getLogger('UserManager').debug('inserting permissions') + getLogger('UserManager').debug('setting up permissions') await Promise.all( [this, ...this.exporters].flatMap(exp => exp.exportRPCFeatures().map(async (feature) => { try{ await this.admin.knex.insert({ rpcname: feature.name }).into('rpcpermissions') }catch(e){ - getLogger('UserManager').debug(feature.name); } }))) diff --git a/src/backend/Types/Items.ts b/src/backend/Types/Items.ts index 49c5d25..29325d3 100644 --- a/src/backend/Types/Items.ts +++ b/src/backend/Types/Items.ts @@ -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 = [ "Robe of Volatile Power", "Salamander Scale Pants", @@ -132,4 +135,17 @@ export const T2:string[] = [ "Draconic Avenger", "Interlaced Shadow Jerkin", "Ringo's Blizzard Boots" -] \ No newline at end of file +] + +export type AllItems = { + [tier in Tiers] : string[] +} + +export const allItems : AllItems = { + MC: T1, + BWL: T2, + ZG:[], + AQ20: [], + AQ40: [], + Naxx: [] +} \ No newline at end of file diff --git a/src/backend/Types/Types.ts b/src/backend/Types/Types.ts index 5621aef..33c0cdf 100644 --- a/src/backend/Types/Types.ts +++ b/src/backend/Types/Types.ts @@ -6,6 +6,7 @@ import { CharacterManagerIfc, CharacterManagerFeatureIfc } from "../Components/C import { ItemManagerFeatureIfc, ItemManagerIfc } from "../Components/Item/RPCInterface"; import { GuildManagerFeatureIfc, GuildManagerIfc } from "../Components/Guild/RPCInterface"; import { ShoutboxIfc } from "../Components/Shoutbox/RPCInterface"; +import { Tiers } from "./Items"; export type FrontcraftIfc = RaidManagerIfc & UserManagerIfc @@ -49,10 +50,10 @@ export type RPCPermission = { export type RaidData = Raid & { participants: { - [clazz in Class] : (Character & Spec)[] + [clazz in Class] : (Signup & Character & Spec)[] } & { - late: (Character & Spec)[] - bench: (Character & Spec)[] + late: (Signup & Character & Spec)[] + bench: (Signup & Character & Spec)[] } tokens: { [itemname in string]: (Character & SRToken & Item)[] @@ -60,8 +61,9 @@ export type RaidData = Raid & { } export type SRToken = { + signupid?:number characterid: number, - itemid: number, + itemname: string, level: number } @@ -69,18 +71,18 @@ export type SRPriority = { id?:number race?:Race specid?:number, - itemid?:number, + itemname?:string, description?:string, modifier:number } export type Item = { - id?:number itemname:string iconname:string url:string quality:string hidden:boolean + tier: Tiers } export type User = { @@ -98,9 +100,11 @@ export type Raid = { start: string signupcount?: number size: number + tier: Tiers } export type Signup = { + id?:number raidid: number characterid: number benched: boolean diff --git a/src/frontend/src/app/frontcraft/pages/character/character.component.html b/src/frontend/src/app/frontcraft/pages/character/character.component.html index 2a4da72..0c011b9 100644 --- a/src/frontend/src/app/frontcraft/pages/character/character.component.html +++ b/src/frontend/src/app/frontcraft/pages/character/character.component.html @@ -1,13 +1,25 @@ - - {{char.charactername}} + +

+ + {{char.charactername}} + +

+

+ + {{char.charactername}} + +

+ {{char.race}}
{{char.specname}} {{char.class}}
- Owned by {{char.username}} ({{char.rank}}) + + Owned by {{char.username}} ({{char.rank}}) +

[ {{token.level}} ] diff --git a/src/frontend/src/app/frontcraft/pages/character/character.component.ts b/src/frontend/src/app/frontcraft/pages/character/character.component.ts index 104ed73..8980fac 100644 --- a/src/frontend/src/app/frontcraft/pages/character/character.component.ts +++ b/src/frontend/src/app/frontcraft/pages/character/character.component.ts @@ -1,4 +1,4 @@ -import { Component, OnInit } from '@angular/core'; +import { Component, OnInit, Input } from '@angular/core'; import { ActivatedRoute, Router } from '@angular/router'; import { ApiService as ApiService } from '../../services/login-api'; import { Spec, User, Character } from '../../../../../../backend/Types/Types'; @@ -10,6 +10,9 @@ import { getClassColor } from '../../../../../../backend/Types/PlayerSpecs'; }) export class FrontcraftCharacterComponent implements OnInit{ + @Input() name?: string + @Input() link?: "owner" | "character" = 'owner' + char : (Character & User & Spec) = {} as any color : string tokens @@ -20,7 +23,9 @@ export class FrontcraftCharacterComponent implements OnInit{ ){} 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') .getCharacterByName(param) .then((char) => { diff --git a/src/frontend/src/app/frontcraft/pages/characters/characters.component.html b/src/frontend/src/app/frontcraft/pages/characters/characters.component.html index 2f40914..9134289 100644 --- a/src/frontend/src/app/frontcraft/pages/characters/characters.component.html +++ b/src/frontend/src/app/frontcraft/pages/characters/characters.component.html @@ -6,9 +6,6 @@
- - - diff --git a/src/frontend/src/app/frontcraft/pages/pages.module.ts b/src/frontend/src/app/frontcraft/pages/pages.module.ts index 941968b..b2e5879 100644 --- a/src/frontend/src/app/frontcraft/pages/pages.module.ts +++ b/src/frontend/src/app/frontcraft/pages/pages.module.ts @@ -32,11 +32,12 @@ import { FrontcraftRaidComponent } from './raid/raid.component'; import { FrontcraftArchiveComponent } from './raid/archive.component'; import { NbEvaIconsModule } from '@nebular/eva-icons'; 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 { FrontcraftItemSelectComponent } from './shop/itemselector.component'; import { NgxEchartsModule } from 'ngx-echarts'; import { FrontcraftCharactersComponent } from './characters/characters.component'; +import { FrontcraftBuyTokenComponent } from './shop/buytoken.component'; @NgModule({ diff --git a/src/frontend/src/app/frontcraft/pages/raid/raid.component.html b/src/frontend/src/app/frontcraft/pages/raid/raid.component.html index 2a89726..ff6b63a 100644 --- a/src/frontend/src/app/frontcraft/pages/raid/raid.component.html +++ b/src/frontend/src/app/frontcraft/pages/raid/raid.component.html @@ -67,14 +67,15 @@ - + + + - diff --git a/src/frontend/src/app/frontcraft/pages/raid/raid.component.ts b/src/frontend/src/app/frontcraft/pages/raid/raid.component.ts index 6b21fc8..cdaed87 100644 --- a/src/frontend/src/app/frontcraft/pages/raid/raid.component.ts +++ b/src/frontend/src/app/frontcraft/pages/raid/raid.component.ts @@ -5,6 +5,7 @@ import { RaidData, Raid, Signup } from '../../../../../../backend/Types/Types'; import { NbWindowService, NbToastrService, NbDialogService } from '@nebular/theme'; import { FrontcraftCharacerpickerComponent } from './characterpicker.component'; import { getClassColor } from '../../../../../../backend/Types/PlayerSpecs'; +import { FrontcraftBuyTokenComponent } from '../shop/buytoken.component'; @Component({ selector: 'raid', @@ -52,6 +53,15 @@ export class FrontcraftRaidComponent implements OnInit{ this.refresh() } + itemSelect = async(item) => { + this.dialogService.open(FrontcraftBuyTokenComponent, { + context: { + item: item, + signup: this.mySignup + } + }).onClose.subscribe(() => this.refresh()) + } + signup = async () => { const signupFeature = this.api.get('signup') if(!signupFeature) return @@ -60,7 +70,7 @@ export class FrontcraftRaidComponent implements OnInit{ closeOnBackdropClick: true, closeOnEsc: true, context: { - 'raid': this.raid, + raid: this.raid, } }).onClose.subscribe(()=>{ this.refresh() @@ -83,7 +93,7 @@ export class FrontcraftRaidComponent implements OnInit{ const signupFeature = this.api.get('signup') if(!signupFeature) return - await signupFeature.unsign(this.api.getAuth().token.value, this.mySignup, this.raid) + await signupFeature.unsign(this.api.getAuth().token.value, {id: this.mySignup.characterid, userid: this.mySignup.userid}, this.raid) this.toast.show('Success', 'Unsigned', { status: 'success' }) this.refresh() } @@ -102,7 +112,8 @@ export class FrontcraftRaidComponent implements OnInit{ }) const user = this.api.getCurrentUser() const matchingSignup = Object.values(raiddata.participants).flat().find(char => user && char.userid === user.id!) - if(matchingSignup){ + if(matchingSignup){ + this.isSignedup = true this.mySignup = matchingSignup this.mySignup.status = matchingSignup['benched']?'Bench':matchingSignup['late']?'Late':'Attending' diff --git a/src/frontend/src/app/frontcraft/pages/rules/rules.component.html b/src/frontend/src/app/frontcraft/pages/rules/rules.component.html index caed67f..0450bd2 100644 --- a/src/frontend/src/app/frontcraft/pages/rules/rules.component.html +++ b/src/frontend/src/app/frontcraft/pages/rules/rules.component.html @@ -4,7 +4,7 @@ Smart text here - + + + Buy {{item.itemname}} + + +

+ You currently have {{currency}} softreserve currency +

+
+
+ + {{kv.key}} (+{{kv.value}} from priorities) +
+
+ + {{token.charactername}} [ {{token.level}} ] => [ {{token.level+1}} ] +
+
+
+ + + `, + }) + 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, + 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() + } + } \ No newline at end of file diff --git a/src/frontend/src/app/frontcraft/pages/shop/itemselector.component.ts b/src/frontend/src/app/frontcraft/pages/shop/itemselector.component.ts index f2ba204..8cc41ac 100644 --- a/src/frontend/src/app/frontcraft/pages/shop/itemselector.component.ts +++ b/src/frontend/src/app/frontcraft/pages/shop/itemselector.component.ts @@ -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 { Item } from '../../../../../../backend/Types/Types'; @@ -10,10 +10,11 @@ export class FrontcraftItemSelectComponent implements OnInit{ selected: Item search: string - items: any[] + allItems:Item[] = [] displayedItems: any[] - callbacks = [] + @Input() items: string[] + @Output() onSelect = new EventEmitter(); constructor( private api: ApiService, @@ -21,25 +22,23 @@ export class FrontcraftItemSelectComponent implements OnInit{ } async ngOnInit(){ - this.api.get('ItemManager').getItems().then(items => { - this.items = items - this.displayedItems = items + Promise.all(this.items.map(itemname => + this.api.get('ItemManager').getItem(itemname) + )).then(items => { + this.allItems = items + this.displayedItems = this.allItems }) } changeSearch(){ if(!this.search || this.search == "") - this.displayedItems = this.items + this.displayedItems = this.allItems 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){ - this.selected = item - this.callbacks.forEach(cb => cb(item)) + this.onSelect.emit(item) } - onselect(callback:Function){ - this.callbacks.push(callback) - } } \ No newline at end of file diff --git a/src/frontend/src/app/frontcraft/pages/shop/shop.component.html b/src/frontend/src/app/frontcraft/pages/shop/shop.component.html index f0b54c4..d7308c7 100644 --- a/src/frontend/src/app/frontcraft/pages/shop/shop.component.html +++ b/src/frontend/src/app/frontcraft/pages/shop/shop.component.html @@ -1,13 +1,7 @@ +

+ {{tier}} items +

- - - - - - - - - - - - + diff --git a/src/frontend/src/app/frontcraft/pages/shop/shop.component.ts b/src/frontend/src/app/frontcraft/pages/shop/shop.component.ts index ac48f52..39f92dd 100644 --- a/src/frontend/src/app/frontcraft/pages/shop/shop.component.ts +++ b/src/frontend/src/app/frontcraft/pages/shop/shop.component.ts @@ -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 { FrontcraftItemSelectComponent } from './itemselector.component'; 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 { _Tiers, allItems } from '../../../../../../backend/Types/Items'; @Component({ selector: 'shop', templateUrl: './shop.component.html', }) -export class FrontcraftShopComponent implements AfterViewInit{ +export class FrontcraftShopComponent{ - @ViewChild(FrontcraftItemSelectComponent, {static: false}) - itemselect !: FrontcraftItemSelectComponent + @Input() character: Character + @Input() signup: Signup + + @Input() tier = _Tiers[0] + @Output() onSelect = new EventEmitter() + allItems = allItems constructor( private api: ApiService, 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({ diff --git a/src/frontend/src/app/frontcraft/pages/user/user.component.html b/src/frontend/src/app/frontcraft/pages/user/user.component.html index 580598b..46779ee 100644 --- a/src/frontend/src/app/frontcraft/pages/user/user.component.html +++ b/src/frontend/src/app/frontcraft/pages/user/user.component.html @@ -7,32 +7,8 @@ accent="info"> {{user.currency}} - - -

- - {{char.charactername}} - -

- - - {{char.race}}
- {{char.specname}} {{char.class}} -
-
- - [ {{token.level}} ] - - - {{token.itemname}} -
-
-
- + + + diff --git a/src/frontend/src/app/frontcraft/services/login-api.ts b/src/frontend/src/app/frontcraft/services/login-api.ts index 9f751d2..70f8c71 100644 --- a/src/frontend/src/app/frontcraft/services/login-api.ts +++ b/src/frontend/src/app/frontcraft/services/login-api.ts @@ -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{ return saltedHash(value, "") } diff --git a/test/backendTest.ts b/test/backendTest.ts index 592b9c0..fa03588 100644 --- a/test/backendTest.ts +++ b/test/backendTest.ts @@ -3,7 +3,7 @@ import { FrontworkAdmin } from "../src/backend/Admin/Admin"; import { T1 } from "../src/backend/Types/Items"; 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"; @@ -107,7 +107,7 @@ describe('Frontcraft', () => { client : RPCSocket & FrontcraftIfc, adminClient : RPCSocket & FrontcraftFeatureIfc, 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) => { 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) )).then(x => { 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() - else{ + }else{ 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 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 if(!token) return false @@ -480,7 +483,7 @@ describe('Frontcraft', () => { it('not buy token without currency', (done)=>{ const user = Object.values(users)[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) done() else { @@ -497,12 +500,18 @@ describe('Frontcraft', () => { const item = await client.ItemManager.getItem(itemname) 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) - const after = 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, user.signup!) - if(!after || after.level !== 9) return + if(!after || after.level !== 9) { + console.log("expected level to be 9", after); + return + } done() }) }) @@ -510,11 +519,12 @@ describe('Frontcraft', () => { it('should buy more tokens', (done) => { Promise.all(Object.values(users).map(async (user) => { await adminClient.softreserveCurrency.incrementCurrency(user.account, 1) - await client.ItemManager + return await client.ItemManager .buyToken( user.auth.token.value, user.character.charactername, - T1[Math.floor(T1.length*Math.random())] + T1[Math.floor(T1.length*Math.random())], + user.signup! ) })).then(_ => { done()