checkpoint

This commit is contained in:
peter
2020-03-08 14:16:06 +01:00
parent c4ca96fef9
commit b2707bb88f
22 changed files with 5904 additions and 509 deletions
+25
View File
@@ -0,0 +1,25 @@
{
"$schema": "./node_modules/@angular/cli/lib/config/schema.json",
"version": 1,
"newProjectRoot": "projects",
"projects": {
"frontcraft": {
"projectType": "application",
"schematics": {},
"root": "",
"sourceRoot": "src/backend",
"prefix": "app",
"architect": {
"server": {
"builder": "@angular-devkit/build-angular:server",
"options": {
"outputPath": "dist/server",
"main": "src/backend/Launcher.ts",
"tsConfig": "tsconfig.server.json"
}
}
}
}
},
"defaultProject": "frontcraft"
}
+5581 -388
View File
File diff suppressed because it is too large Load Diff
+13 -4
View File
@@ -1,6 +1,6 @@
{
"name": "frontblock-admin",
"description": "Dynamic configurator for frontblock",
"name": "frontcraft",
"description": "Guild website framework",
"version": "1.0.0",
"scripts": {
"tsc": "tsc",
@@ -9,13 +9,14 @@
"start-backend": "npm run build-backend && npm run launch",
"test": "rm -rf data && npm run build-backend && mocha lib/test/backendTest.js",
"build": "npm run build-backend && npm run build-frontend",
"build-backend": "npm run clean-backend && tsc",
"build-backend": "npm run clean-backend && ng v && ng run frontcraft:server",
"build-frontend": "npm run clean-frontend && (mkdir static || rm -rf static/*) && npm run build-dashboard",
"build-dashboard": "cd src/frontend && npm i && npm run build && cp -r dist/* ../../static",
"clean": "rm -rf data && npm run clean-backend && npm run clean-frontend",
"clean-backend": "rm -rf lib plugins config widget .rpt2_cache *.js *.ts",
"clean-frontend": "rm -rf src/frontend/dist static",
"webpack": "webpack --config src/backend/webpack.prod.js --progress --colors"
"webpack": "webpack --config src/backend/webpack.prod.js --progress --colors",
"setangular": "ng update @angular/cli@8.2.2 @angular/core@8.2.2 @angular/compiler-cli@8.2.2"
},
"repository": {
"type": "git",
@@ -24,7 +25,14 @@
"author": "frontblock.me",
"license": "ISC",
"dependencies": {
"@angular-devkit/build-angular": "^0.900.5",
"@angular/compiler": "^9.0.5",
"@angular/compiler-cli": "^9.0.5",
"@angular/platform-server": "^9.0.5",
"@nguniversal/express-engine": "^9.0.1",
"@nguniversal/module-map-ngfactory-loader": "^8.2.6",
"@types/mocha": "^5.2.7",
"angular": "^1.7.9",
"bsert": "0.0.10",
"bsock": "^0.1.9",
"child-process-promise": "^2.2.1",
@@ -56,6 +64,7 @@
"xml2js": "^0.4.22"
},
"devDependencies": {
"@angular/cli": "^9.0.5",
"@types/express": "^4.17.0",
"@types/node": "^11.13.19",
"@types/semver": "^6.0.1",
+22
View File
@@ -22,6 +22,10 @@ import { Injector } from '../Injector/Injector';
import { Shoutbox } from '../Components/Shoutbox/Shoutbox';
import { PubSub } from '../Components/PubSub/PubSub';
import { ngExpressEngine } from '@nguniversal/express-engine';
import { APP_BASE_HREF } from '@angular/common';
import { AppServerModule } from './app.server.module';
const logger = getLogger("admin", 'debug')
@@ -132,6 +136,24 @@ implements TableDefinitionExporter, IAdmin {
this.express = express()
this.express.use('/', express.static('static'))
this.express.engine('html', ngExpressEngine({
bootstrap: AppServerModule,
}));
this.express.set('view engine', 'html');
this.express.set('views', 'static');
// Serve static files from /browser
this.express.get('*.*', express.static('static', {
maxAge: '1y'
}));
// All regular routes use the Universal engine
this.express.get('*', (req, res) => {
res.render('index', { req, providers: [{ provide: APP_BASE_HREF, useValue: req.baseUrl }] });
});
/**
* get the compiled FrontendPlugins.js
*/
+19
View File
@@ -0,0 +1,19 @@
import { NgModule } from '@angular/core';
import { ServerModule } from '@angular/platform-server';
import { ModuleMapLoaderModule } from '@nguniversal/module-map-ngfactory-loader';
import { AppModule } from '../../frontend/src/app/app.module';
import { AppComponent } from '../../frontend/src/app/app.component';
@NgModule({
imports: [
AppModule,
ServerModule,
ModuleMapLoaderModule
],
providers: [
// Add universal-only providers here
],
bootstrap: [ AppComponent ],
})
export class AppServerModule {}
+2 -6
View File
@@ -2,15 +2,11 @@ import { ConfigLoader } from "loadson";
import { Inject, Injectable } from "../../Injector/ServiceDecorator";
import { GuildManagerFeatureIfc, GuildManagerIfc } from "./RPCInterface";
import { FrontworkComponent } from "../../Types/FrontworkComponent";
import { _Rank, Rank } from "../../Types/Types";
import { _Rank, Rank, Guild } from "../../Types/Types";
import { IAdmin } from "../../Admin/Interface";
import { IGuildManager } from "./Interface";
export type Guild = {
name: string
realm: string
description: string
};
@Injectable(IGuildManager)
export class GuildManager
+1 -2
View File
@@ -1,5 +1,4 @@
import { Rank } from "../../Types/Types"
import { Guild } from "./GuildManager"
import { Rank, Guild } from "../../Types/Types"
export class IGuildManager{
getHeadCount: () => Promise<{rank:Rank, count: number}[]>
+2 -1
View File
@@ -3,7 +3,8 @@ import { Tiers } from "../../Types/Items"
export class IItemManager{
getItems: () => Promise<Item[]>
fetchItem: (name:string) => Promise<Item>
getItem: (name:string, tier?:Tiers) => Promise<Item | undefined>
fetchItem: (name:string, tier?:Tiers) => Promise<Item | undefined>
buyToken: (usertoken: string, charactername:string, itemname:string, signup:Signup) => Promise<(SRToken & Character & Item) | undefined>
setPriority: (itemname:string, priority: any) => Promise<void>
calculatePriorities: (itemname: string, character:Character) => Promise<number>
+94 -25
View File
@@ -3,14 +3,14 @@ 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, Signup, Raid } from "../../Types/Types";
import { TableDefiniton, Item, User, Character, SRToken, SRPriority, Spec, Signup, Raid, Stats } from "../../Types/Types";
import { IAdmin } from "../../Admin/Interface";
import { IItemManager } from "./Interface";
import { getLogger } from "log4js";
import { IUserManager } from "../User/Interface";
import { ICharacterManager } from "../Character/Interface";
import { IPubSub } from "../PubSub/Interface";
import { IRaidManager } from "../Raid/Interface";
import { getLogger } from "frontblock-generic/Types";
const fetch = require('node-fetch')
const xml2js = require('xml2js');
@@ -60,13 +60,13 @@ export class ItemManager
}]
notifyRaid = async (raid: Raid | { id: number }) => {
const data = await this.raidManager.getRaidData(<Raid>raid)
this.pubsub.publish("" + raid.id, data)
await this.notifyRaids()
const data = await this.raidManager.getRaidData(<Raid>raid)
await this.pubsub.publish("" + raid.id, data)
}
notifyRaids = async () => {
this.pubsub.publish('raids', undefined)
await this.pubsub.publish('raids', undefined)
}
wipeCurrencyAndItems = async () => {
@@ -78,26 +78,58 @@ export class ItemManager
getItems = async (): Promise<Item[]> => await this.admin.knex.select('*').from('items')
getItem = async (name: string): Promise<Item> => {
return await this.admin.knex('items').select('*').where('itemname', '=', name).first()
getItem = async (name: string, tier?:Tiers): Promise<Item | undefined> => {
let item = await this.admin.knex('items').select('*').where('itemname', '=', name).first()
if(!item){
item = await this.fetchItem(name, tier)
if (!item)
return
await this.admin
.knex('items')
.insert({
...item,
stats: JSON.stringify(item.stats)
})
return this.getItem(name, tier)
}
fetchItem = async (name: string): Promise<Item> => {
item.stats = JSON.parse(item.stats)
return item
}
fetchItem = async (name: string, tier?:Tiers): Promise<Item | undefined> => {
const res = await fetch('https://classic.wowhead.com/item=' + name + '&xml');
const txt = await res.text();
const r = await parser.parseStringPromise(txt);
try{
return <Item>{
if(!r.wowhead.item || !r.wowhead.item[0])
return
const j = JSON.parse('{'+r.wowhead.item[0].json[0]+"}")
if(!tier){
if(j.sourcemore && Number.isInteger(j.sourcemore[0].t) && j.sourcemore[0].t > 0){
tier = _Tiers[j.sourcemore[0].t-1]
}else{
tier = "MC"
}
}
const stats = JSON.parse('{'+r.wowhead.item[0].jsonEquip[0]+"}")
const item = <Item>{
itemname: r.wowhead.item[0].name[0],
iconname: r.wowhead.item[0].icon[0]._,
url: r.wowhead.item[0].link[0],
quality: r.wowhead.item[0].quality[0]._,
tooltip: r.wowhead.item[0].htmlTooltip[0]
tooltip: r.wowhead.item[0].htmlTooltip[0],
stats: toStats(stats),
tier: tier
}
return item
}catch(e){
console.log(name)
throw e
getLogger('ItemManager', 'error').error(name, e);
}
}
@@ -139,6 +171,7 @@ export class ItemManager
table.boolean('hidden').defaultTo(false).notNullable()
table.string('tooltip').notNullable()
table.enu('tier', _Tiers).notNullable()
table.json('stats').notNullable()
}
}]
}
@@ -249,7 +282,7 @@ export class ItemManager
await this.admin
.knex('priorities')
.insert(<SRPriority>{
itemname: item.itemname,
itemname: item!.itemname,
...priority
})
}
@@ -354,19 +387,55 @@ export class ItemManager
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
}).catch(() => { })
)
)
.map((kv: [string, string[]]) => Promise.all(
kv[1].map(i => this.getItem(i, kv[0] as Tiers) )
))
)
}
}
}
function toStats(obj:any){
if(!obj) obj = {}
return {
stamina: obj.sta || 0,
agility: obj.agi || 0,
strength: obj.str || 0,
intellect: obj.int || 0,
spirit: obj.spi || 0,
attackpower: obj.atkpwr || 0,
meleehit: obj.mlehitpct || 0,
meleecrit: obj.mlecritstrkpct || 0,
rangeattackpower: obj.rgdatkpwr || 0,
rangehit: obj.rgdhitpct || 0,
rangecrit: obj.rgdcritstrkpct || 0,
spellpower: obj.splpwr || 0,
spellhit: obj.splhitpct || 0,
spellcrit: obj.splcritstrkpct || 0,
heal: obj.splheal || 0,
frostspellpower: obj.frosplpwr || 0,
firespellpower: obj.firsplpwr || 0,
naturespellpower: obj.natsplpwr || 0,
shadowspellpower: obj.shasplpwr || 0,
arcanespellpower: obj.arcsplpwr || 0,
fireresist: obj.firres || 0,
arcaneresist: obj.arcres || 0,
frostresist: obj.frores || 0,
natureresist: obj.natres || 0,
shadowresist: obj.shares || 0,
armor: obj.armor || 0,
defense: obj.def || 0,
block: obj.blockpct || 0,
blockvalue: obj.blockamount || 0,
dodge: obj.dodgepct || 0,
parry: obj.parrypct || 0,
} as Stats
}
+1 -1
View File
@@ -2,7 +2,7 @@ import { IItemManager } from "./Interface"
export type ItemManagerIfc = {
ItemManager: {
getItem: IItemManager['fetchItem']
getItem: IItemManager['getItem']
getItems: IItemManager['getItems']
buyToken: IItemManager['buyToken']
calculatePriorities: IItemManager['calculatePriorities']
-4
View File
@@ -70,7 +70,6 @@ export const T1 = [
"Cenarion Bracers",
"Cenarion Vestments",
"Cenarion Helm",
"Cenarion Helm",
"Cenarion Leggings",
"Cenarion Spaulders",
"Giantstalker's Belt",
@@ -106,7 +105,6 @@ export const T1 = [
"Robes of Prophecy",
"Vambraces of Prophecy",
"Nightslayer Belt",
"Nightslayer Belt",
"Nightslayer Bracelets",
"Nightslayer Chestpiece",
"Nightslayer Cover",
@@ -120,7 +118,6 @@ export const T1 = [
"Felheart Robes",
"Felheart Shoulder Pads",
"Felheart Horns",
"Felheart Horns",
"Belt of Might",
"Bracers of Might",
"Breastplate of Might",
@@ -150,7 +147,6 @@ export const T1 = [
"Bloodfang Hood",
"Bloodfang Pants",
"Helmet of Ten Storms",
"Helmet of Ten Storms",
"Nemesis Skullcap",
"Nemesis Leggings",
"Helm of Wrath",
+48
View File
@@ -81,6 +81,53 @@ export type SRPriority = {
modifier:number
}
export type Stats = {
stamina: number,
agility: number,
strength: number,
intellect: number,
spirit: number,
fireresist: number,
frostresist: number,
arcaneresist: number,
shadowresist: number,
natureresist: number,
spellpower: number,
spellhit: number,
spellcrit: number,
heal: number,
frostspellpower: number,
firespellpower: number,
naturespellpower: number,
shadowspellpower: number,
arcanespellpower: number,
attackpower: number,
meleehit: number,
meleecrit: number,
rangeattackpower: number,
rangehit: number,
rangecrit: number,
armor:number,
defense: number,
block: number,
blockvalue: number,
parry: number,
dodge:number
}
export type Guild = {
name: string
realm: string
description: string
};
export type Item = {
itemname:string
iconname:string
@@ -89,6 +136,7 @@ export type Item = {
hidden:boolean
tooltip: string
tier: Tiers
stats: Stats
}
export type User = {
+1 -1
View File
@@ -13,7 +13,7 @@
"ng": "ng",
"conventional-changelog": "conventional-changelog",
"start": "ng serve",
"build": "ng build",
"build": "ng build --aot",
"build:prod": "npm run build -- --prod --aot",
"test": "ng test",
"test:coverage": "rimraf coverage && npm run test -- --code-coverage",
@@ -31,8 +31,7 @@
<nb-action class="user-action">
<nb-user [nbContextMenu]="userMenu"
[onlyPicture]="false"
[name]="user?.username"
[picture]="user?.picture">
[name]="user?.username">
</nb-user>
</nb-action>
@@ -29,6 +29,7 @@ export class RegisterComponent implements OnInit{
selectedSpec = specs[this.selectedClass][0]
specs = specs[this.selectedClass]
showApplication = false
submitted = false
constructor(
private router : Router,
@@ -1,6 +1,8 @@
import { Component, OnInit } from '@angular/core';
import { Item } from '../../../../../../backend/Types/Types';
import { Item, Stats } from '../../../../../../backend/Types/Types';
import { NbToastrService } from '@nebular/theme';
import { ApiService } from '../../services/login-api';
@Component({
selector: 'armory',
@@ -9,19 +11,21 @@ import { NbToastrService } from '@nebular/theme';
export class FrontcraftArmoryComponent implements OnInit {
servers = servers
submitted = false
charactername = ""
server = "Gandling"
region = "EU"
gear:string[] = []
gear: Item[] = []
constructor(
private api: ApiService,
private toastr: NbToastrService
) { }
async submit() {
const dataLink = "https://classic.warcraftlogs.com:443/v1/parses/character/" + this.charactername.toLowerCase().replace(/^\w/, c => c.toUpperCase()) + "/" + this.server + "/" + this.region + "?api_key=c698515ab4f592cdb848d80b3abe616c&metric=dps"
fetch(dataLink).then(raw => raw.json().then((json:any[]) => {
fetch(dataLink).then(raw => raw.json().then(async (json: any[]) => {
if (json.length < 1) return
let min = -1
let data
@@ -39,12 +43,14 @@ export class FrontcraftArmoryComponent implements OnInit{
return
}
this.gear = data.gear.map(item => {return <Item>{
itemname: item.name,
iconname: item.icon.replace('.jpg', ''),
quality: item.quality.replace(/^\w/, c => c.toUpperCase()),
url: "https://classic.wowhead.com/item="+item.id,
}}).filter(item => item.itemname != "Unknown Item")
const maybeItems: (Item | undefined)[] = await Promise.all(data.gear
.filter(item => item.name != "Unknown Item")
.map(async item => await this.api.get('ItemManager').getItem(item.name)))
const geardata = maybeItems.filter(maybeItem => maybeItem != null)
this.gear = geardata
console.log(this.gear.map(g => g.stats).reduce(sumStats))
}))
}
@@ -53,6 +59,16 @@ export class FrontcraftArmoryComponent implements OnInit{
}
}
function sumStats(stat1: Stats, stat2: Stats):Stats{
const ret = {} as any
Object.keys(stat1).forEach(key => {
ret[key] = stat1[key] + stat2[key]
})
return ret
}
const servers = [
"Ashbringer"
, "Bloodfang"
@@ -24,7 +24,7 @@ export class FrontcraftCharacterComponent implements OnInit{
boss1 = {}
gear1:string[] = []
boss2= {}
boss2= {name: undefined, date:undefined}
gear2:string[] = []
constructor(
@@ -10,6 +10,7 @@ import { getClassColor } from '../../../../../../backend/Types/PlayerSpecs';
})
export class FrontcraftArchiveComponent implements OnInit{
manageRaid = false
canSignup = false
isSignedup = false
canManage = false
@@ -1,6 +1,6 @@
<div class="row">
<div class="col-12 col-xl-6">
<nb-card [size]="giant">
<nb-card [size]="'giant'">
<nb-card-body>
<nb-tabset>
<nb-tab tabTitle="Info">
+4 -16
View File
@@ -3,7 +3,7 @@ import { FrontworkAdmin } from "../src/backend/Admin/Admin";
import { T1, T2, Tiers } from "../src/backend/Types/Items";
import { RPCSocket } from "rpclibrary";
import { FrontcraftIfc, Auth, User, FrontcraftFeatureIfc, Raid, Character, Rank, Class, Race, SRPriority, Spec, Signup } from "../src/backend/Types/Types";
import { FrontcraftIfc, Auth, User, FrontcraftFeatureIfc, Raid, Character, Rank, Class, Race, Spec, Signup } from "../src/backend/Types/Types";
import { SpecT } from "../src/backend/Types/PlayerSpecs";
@@ -129,18 +129,6 @@ describe('Frontcraft', () => {
return client.UserManager.createUser(user)
}
const login = async (name: string) : Promise<Auth> => {
const auth = await client.UserManager.login(name, 'ca978112ca1bbdcafac231b39a23dc4da786eff8147c4e72b9807785afee48bb')
if(users[name]) users[name] = {
...users[name],
auth: auth
}
return auth
}
const createAccountAndUser = async (acc: protoAccount) => {
const account = await createAccount({
pwhash: 'ca978112ca1bbdcafac231b39a23dc4da786eff8147c4e72b9807785afee48bb', //sha256("a")
@@ -573,8 +561,8 @@ describe('Frontcraft', () => {
const user = Object.values(users)[0]
const itemname = "Maladath, Runed Blade of the Black Flight"
client.ItemManager.getItem(itemname).then(async item => {
await adminClient.softreserveCurrency.incrementCurrency(user.account, item.tier, 2)
const before = await client.ItemManager.getToken(user.character, item)
await adminClient.softreserveCurrency.incrementCurrency(user.account, item!.tier, 2)
const before = await client.ItemManager.getToken(user.character, item!)
if (!before || before.level !== 4) {
console.log("expected level to be 4", before ? before.level : '?');
@@ -690,7 +678,7 @@ describe('Frontcraft', () => {
let streaks = await client.ItemManager.getTokens(user.character, [BWL0.tier], false)
if (reserves!.length != 1
|| streaks!.length != 0
|| reserves![0].itemname !== T2_0.itemname
|| reserves![0].itemname !== T2_0!.itemname
|| reserves![0].level !== 1) {
console.log("Bad Token status 1", reserves, streaks);
done(new Error("Bad Token status"))
+3 -4
View File
@@ -3,13 +3,12 @@
"strictPropertyInitialization": false,
"noImplicitAny": false,
"target": "ESnext",
"module": "commonjs",
"declaration": true,
"outDir": "./lib",
"strict": true,
"experimentalDecorators": true,
"emitDecoratorMetadata": true
},
"include": ["src/backend/**/*", "test/**/*"],
"exclude": ["node_modules", "**/__tests__/*"]
"angularCompilerOptions": {
"entryModule": "./src/backend/Admin/app.server.module#AppServerModule"
}
}
+14
View File
@@ -0,0 +1,14 @@
{
"extends": "./tsconfig.json",
"compilerOptions": {
"outDir": "./lib",
"module": "commonjs",
"types": ["node"]
},
"include": ["src/backend/**/*", "test/**/*"],
"exclude": ["node_modules", "**/__tests__/*"],
"angularCompilerOptions": {
"entryModule": "./src/app/app.server.module#AppServerModule"
}
}