diff --git a/log.txt b/log.txt new file mode 100644 index 0000000..9dafd4e --- /dev/null +++ b/log.txt @@ -0,0 +1,33 @@ +[2020-03-29T12:12:03.477] [DEBUG] Admin#makeKnex - Making new knex: { + client: 'sqlite3', + connection: {(node:1085628) [DEP0005] DeprecationWarning: Buffer() is deprecated due to security and usability issues. Please use the Buffer.alloc(), Buffer.allocUnsafe(), or Buffer.from() methods instead. +Terminated +npm ERR! code ELIFECYCLE +npm ERR! errno 143 +npm ERR! frontcraft@1.0.0 launch: `node lib/src/backend/Launcher.js > log.txt "-"` +npm ERR! Exit status 143 +npm ERR! +npm ERR! Failed at the frontcraft@1.0.0 launch script. +npm ERR! This is probably not a problem with npm. There is likely additional logging output above. + +npm ERR! A complete log of this run can be found in: +npm ERR! /home/cake/.npm/_logs/2020-03-29T10_12_28_351Z-debug.log +s loaded +[2020-03-29T12:12:04.535] [INFO] Admin#startWebserver - Admin panel listening for HTTP on *8080 +[2020-03-29T12:12:17.689] [DEBUG] UserManager#checkConnection - { + celinda: { + connections: { '59288': [Socket] }, + auth: { token: [Object], user: [Object], port: 20001 }, + user: { + id: 3, + username: 'celinda', + rank: 'Officer', + MC: 1, + BWL: 0, + ZG: 1, + AQ20: 1, + AQ40: 1, + Naxx: 1 + } + } +} [ '1563eebe-9da2-4b31-b4ef-ef3aaa7e23b1' ] diff --git a/package.json b/package.json index 8144cc5..2213b5e 100644 --- a/package.json +++ b/package.json @@ -5,7 +5,7 @@ "scripts": { "tsc": "tsc", "knex": "knex", - "launch": "node lib/src/backend/Launcher.js", + "launch": "node lib/src/backend/Launcher.js > log.txt", "start": "npm run build && npm run launch", "start-backend": "npm run build-backend && npm run launch", "test": "rm -rf data && npm run build-backend && mocha lib/test/backendTest.js", diff --git a/src/backend/Admin/Admin.ts b/src/backend/Admin/Admin.ts index f0e83ff..8539faf 100644 --- a/src/backend/Admin/Admin.ts +++ b/src/backend/Admin/Admin.ts @@ -19,7 +19,6 @@ import { RPCConfigLoader } from '../Components/RPCConfigLoader'; import { FrontworkComponent } from '../Types/FrontworkComponent'; import { IAdmin } from './Interface'; import { Injector } from '../Injector/Injector'; -import { Shoutbox } from '../Components/Shoutbox/Shoutbox'; import { PubSub } from '../Components/PubSub/PubSub'; getLogger().level = 'debug' @@ -32,7 +31,6 @@ getLogger().level = 'debug' RaidManager, CharacterManager, UserManager, - Shoutbox, PubSub ] }) @@ -145,7 +143,7 @@ export class FrontworkAdmin try { const req = require(distFolder + "/server.js") - await req.attachExpress(this.express) + await req.attachExpress(this.express, './dist', getLogger('angularSSR#')) getLogger('Admin#startWebserver').info('Frontend from ' + ngExpressServer + " loaded") } catch (e) { getLogger('Admin#startWebserver').error(e) diff --git a/src/backend/Components/Raid/RaidManager.ts b/src/backend/Components/Raid/RaidManager.ts index 5ac5a01..944ac1f 100644 --- a/src/backend/Components/Raid/RaidManager.ts +++ b/src/backend/Components/Raid/RaidManager.ts @@ -145,7 +145,7 @@ export class RaidManager getRaids = async (): Promise => { - const subQuery = this.admin + const countSignups = this.admin .knex('signups') .count('*') .where({ @@ -155,8 +155,18 @@ export class RaidManager }) .as('signupcount') + const countBenches = this.admin + .knex('signups') + .count('*') + .where({ + raidid: this.admin.knex.ref('raids.id'), + benched: true, + late: false + }) + .as('benchcount') + return await this.admin.knex('raids') - .select('*', subQuery) + .select('*', countSignups, countBenches) .orderBy('start', 'asc') } diff --git a/src/backend/Components/Shoutbox/Interface.ts b/src/backend/Components/Shoutbox/Interface.ts deleted file mode 100644 index 6740386..0000000 --- a/src/backend/Components/Shoutbox/Interface.ts +++ /dev/null @@ -1,13 +0,0 @@ -import { Raid, Signup, Character, RaidData } from "../../Types/Types" - -export type ShoutMessage = { - message: string, - sender: string, - date: string -} - -export class IShoutbox{ - shout: (uuid:string, msg: ShoutMessage) => Promise - getFeed: () => Promise - subscribe: (callback) => Promise -} diff --git a/src/backend/Components/Shoutbox/RPCInterface.ts b/src/backend/Components/Shoutbox/RPCInterface.ts deleted file mode 100644 index 2b5a3b7..0000000 --- a/src/backend/Components/Shoutbox/RPCInterface.ts +++ /dev/null @@ -1,13 +0,0 @@ -import { IShoutbox } from "./Interface" - -export type ShoutboxIfc = { - Shoutbox:{ - getFeed: IShoutbox['getFeed'] - shout: IShoutbox['shout'] - subscribe: IShoutbox['subscribe'] - } -} - -export type ShoutboxFeatureIfc = { - -} \ No newline at end of file diff --git a/src/backend/Components/Shoutbox/Shoutbox.ts b/src/backend/Components/Shoutbox/Shoutbox.ts deleted file mode 100644 index b67126d..0000000 --- a/src/backend/Components/Shoutbox/Shoutbox.ts +++ /dev/null @@ -1,64 +0,0 @@ -import { Injectable } from "../../Injector/ServiceDecorator"; -import { ShoutboxFeatureIfc, ShoutboxIfc } from "./RPCInterface"; -import { FrontworkComponent } from "../../Types/FrontworkComponent"; -import { TableDefiniton } from "../../Types/Types"; -import { IShoutbox, ShoutMessage } from "./Interface"; -import * as CircularBuffer from "circular-buffer"; -const uuid = require('uuid/v4') - -@Injectable(IShoutbox) -export class Shoutbox -implements FrontworkComponent, IShoutbox{ - name = "Shoutbox" as "Shoutbox"; - - log: CircularBuffer = new CircularBuffer(500) - subs = {} - - exportRPCs = () => [ - this.shout, - this.getFeed, - { - name: 'subscribe' as 'subscribe', - hook: this.subscribe, - onClose: (subres, rpcName) => { - this.unsubscribe(subres.uuid) - } - } - ] - - exportRPCFeatures = () => [] - - getTableDefinitions(): TableDefiniton[] { - return [] - } - - shout = async (uuid:string, msg: ShoutMessage) : Promise => { - if(!this.subs[uuid]) return - this.broadcast(uuid, msg) - this.log.push(msg) - } - - private broadcast = async (uuid:string, msg: ShoutMessage) => { - await Promise.all(Object.values(this.subs).map(async (callback:any) => { - try{ - await callback(msg) - }catch(e){ - delete this.subs[uuid] - } - })) - } - - getFeed = async () : Promise => { - return this.log.toarray() - } - - subscribe = async (callback) : Promise => { - uuid() - this.subs[uuid] = callback - return uuid - } - - unsubscribe = async (uuid: string) => { - delete this.subs[uuid] - } -} \ No newline at end of file diff --git a/src/backend/Components/User/UserManager.ts b/src/backend/Components/User/UserManager.ts index 4e73e5e..062023b 100644 --- a/src/backend/Components/User/UserManager.ts +++ b/src/backend/Components/User/UserManager.ts @@ -404,6 +404,7 @@ export class UserManager }, errorHandler: (socket, e, rpcName, args) => { getLogger('UserManager#errorHandler').error(rpcName, args, e); + throw(new Error("RPC failed")) }, sesame: (sesame) => this.checkToken(sesame), visibility: '0.0.0.0' diff --git a/src/backend/Types/Types.ts b/src/backend/Types/Types.ts index 3c9e7e8..a1a6e3e 100644 --- a/src/backend/Types/Types.ts +++ b/src/backend/Types/Types.ts @@ -5,7 +5,6 @@ import { UserManagerIfc, UserManagerFeatureIfc } from "../Components/User/RPCInt import { CharacterManagerIfc, CharacterManagerFeatureIfc } from "../Components/Character/RPCInterface"; import { ItemManagerFeatureIfc, ItemManagerIfc } from "../Components/Item/RPCInterface"; import { GuildManagerFeatureIfc, GuildManagerIfc } from "../Components/Guild/RPCInterface"; -import { ShoutboxIfc } from "../Components/Shoutbox/RPCInterface"; import { Tiers } from "./Items"; import { PubSubIfc } from "../Components/PubSub/RPCInterface"; @@ -14,7 +13,6 @@ export type FrontcraftIfc = RaidManagerIfc & CharacterManagerIfc & ItemManagerIfc & GuildManagerIfc - & ShoutboxIfc & PubSubIfc export type FrontcraftFeatureIfc = RaidManagerFeatureIfc @@ -155,6 +153,7 @@ export type Raid = { description: string start: string signupcount?: number + benchcount?: number size: number tier: Tiers } diff --git a/src/frontend/package-lock.json b/src/frontend/package-lock.json index 227c0cb..e8cd0d7 100644 --- a/src/frontend/package-lock.json +++ b/src/frontend/package-lock.json @@ -6288,6 +6288,11 @@ "assert-plus": "^1.0.0" } }, + "date-format": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/date-format/-/date-format-3.0.0.tgz", + "integrity": "sha512-eyTcpKOcamdhWJXj56DpQMo1ylSQpcGtGKXcU0Tb97+K56/CF5amAqqqNj0+KvA0iw2ynxtHWFsPDSClCxe48w==" + }, "dateformat": { "version": "3.0.3", "resolved": "https://registry.npmjs.org/dateformat/-/dateformat-3.0.3.tgz", @@ -6298,7 +6303,6 @@ "version": "4.1.1", "resolved": "https://registry.npmjs.org/debug/-/debug-4.1.1.tgz", "integrity": "sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw==", - "dev": true, "requires": { "ms": "^2.1.1" } @@ -8095,6 +8099,11 @@ } } }, + "flatted": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/flatted/-/flatted-2.0.1.tgz", + "integrity": "sha512-a1hQMktqW9Nmqr5aktAux3JMNqaucxGcjtjWnZLHX7yyPCmlSV3M54nGYbqT8K+0GhF3NBgmJCc3ma+WOgX8Jg==" + }, "flatten": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/flatten/-/flatten-1.0.3.tgz", @@ -8131,6 +8140,11 @@ } } }, + "font-awesome": { + "version": "4.7.0", + "resolved": "https://registry.npmjs.org/font-awesome/-/font-awesome-4.7.0.tgz", + "integrity": "sha1-j6jPBBGhoxr9B7BtKQK7n8gVoTM=" + }, "fontkit": { "version": "1.8.0", "resolved": "https://registry.npmjs.org/fontkit/-/fontkit-1.8.0.tgz", @@ -8324,7 +8338,6 @@ "version": "8.1.0", "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-8.1.0.tgz", "integrity": "sha512-yhlQgA6mnOJUKOsRUFsgJdQCvkKhcz8tlZG5HBQfReYZy46OwLcY+Zia0mtdHsOo9y/hP+CxMN0TU9QxoOtG4g==", - "dev": true, "requires": { "graceful-fs": "^4.2.0", "jsonfile": "^4.0.0", @@ -10435,7 +10448,6 @@ "version": "4.0.0", "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-4.0.0.tgz", "integrity": "sha1-h3Gq4HmbZAdrdmQPygWPnBDjPss=", - "dev": true, "requires": { "graceful-fs": "^4.1.6" } @@ -11327,6 +11339,12 @@ "kind-of": "^3.0.2" } }, + "isarray": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz", + "integrity": "sha1-ihis/Kmo9Bd+Cav8YDiTmwXR7t8=", + "dev": true + }, "kind-of": { "version": "3.2.2", "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", @@ -11342,6 +11360,30 @@ "integrity": "sha1-W/Rejkm6QYnhfUgnid/RW9FAt7Y=", "dev": true }, + "log4js": { + "version": "0.6.38", + "resolved": "https://registry.npmjs.org/log4js/-/log4js-0.6.38.tgz", + "integrity": "sha1-LElBFmldb7JUgJQ9P8hy5mKlIv0=", + "dev": true, + "requires": { + "readable-stream": "~1.0.2", + "semver": "~4.3.3" + }, + "dependencies": { + "readable-stream": { + "version": "1.0.34", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-1.0.34.tgz", + "integrity": "sha1-Elgg40vIQtLyqq+v5MKRbuMsFXw=", + "dev": true, + "requires": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.1", + "isarray": "0.0.1", + "string_decoder": "~0.10.x" + } + } + } + }, "micromatch": { "version": "2.3.11", "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-2.3.11.tgz", @@ -11587,12 +11629,24 @@ } } }, + "semver": { + "version": "4.3.6", + "resolved": "https://registry.npmjs.org/semver/-/semver-4.3.6.tgz", + "integrity": "sha1-MAvG4OhjdPe6YQaLWx7NV/xlMto=", + "dev": true + }, "source-map": { "version": "0.5.7", "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=", "dev": true }, + "string_decoder": { + "version": "0.10.31", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-0.10.31.tgz", + "integrity": "sha1-YuIDvEF2bGwoyfyEMB2rHFMQ+pQ=", + "dev": true + }, "tmp": { "version": "0.0.31", "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.0.31.tgz", @@ -12724,45 +12778,15 @@ } }, "log4js": { - "version": "0.6.38", - "resolved": "https://registry.npmjs.org/log4js/-/log4js-0.6.38.tgz", - "integrity": "sha1-LElBFmldb7JUgJQ9P8hy5mKlIv0=", - "dev": true, + "version": "6.1.2", + "resolved": "https://registry.npmjs.org/log4js/-/log4js-6.1.2.tgz", + "integrity": "sha512-knS4Y30pC1e0n7rfx3VxcLOdBCsEo0o6/C7PVTGxdVK+5b1TYOSGQPn9FDcrhkoQBV29qwmA2mtkznPAQKnxQg==", "requires": { - "readable-stream": "~1.0.2", - "semver": "~4.3.3" - }, - "dependencies": { - "isarray": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz", - "integrity": "sha1-ihis/Kmo9Bd+Cav8YDiTmwXR7t8=", - "dev": true - }, - "readable-stream": { - "version": "1.0.34", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-1.0.34.tgz", - "integrity": "sha1-Elgg40vIQtLyqq+v5MKRbuMsFXw=", - "dev": true, - "requires": { - "core-util-is": "~1.0.0", - "inherits": "~2.0.1", - "isarray": "0.0.1", - "string_decoder": "~0.10.x" - } - }, - "semver": { - "version": "4.3.6", - "resolved": "https://registry.npmjs.org/semver/-/semver-4.3.6.tgz", - "integrity": "sha1-MAvG4OhjdPe6YQaLWx7NV/xlMto=", - "dev": true - }, - "string_decoder": { - "version": "0.10.31", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-0.10.31.tgz", - "integrity": "sha1-YuIDvEF2bGwoyfyEMB2rHFMQ+pQ=", - "dev": true - } + "date-format": "^3.0.0", + "debug": "^4.1.1", + "flatted": "^2.0.1", + "rfdc": "^1.1.4", + "streamroller": "^2.2.3" } }, "loglevel": { @@ -13376,8 +13400,7 @@ "ms": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", - "dev": true + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" }, "multicast-dns": { "version": "6.2.3", @@ -15717,6 +15740,11 @@ "integrity": "sha1-G0KmJmoh8HQh0bC1S33BZ7AcATs=", "dev": true }, + "rfdc": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/rfdc/-/rfdc-1.1.4.tgz", + "integrity": "sha512-5C9HXdzK8EAqN7JDif30jqsBzavB7wLpaubisuQIGHWf2gUXSpzy6ArX/+Da8RjFpagWsCn+pIgxTMAmKw9Zug==" + }, "rimraf": { "version": "2.6.1", "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.6.1.tgz", @@ -17025,6 +17053,23 @@ "integrity": "sha512-AiisoFqQ0vbGcZgQPY1cdP2I76glaVA/RauYR4G4thNFgkTqr90yXTo4LYX60Jl+sIlPNHHdGSwo01AvbKUSVQ==", "dev": true }, + "streamroller": { + "version": "2.2.3", + "resolved": "https://registry.npmjs.org/streamroller/-/streamroller-2.2.3.tgz", + "integrity": "sha512-AegmvQsscTRhHVO46PhCDerjIpxi7E+d2GxgUDu+nzw/HuLnUdxHWr6WQ+mVn/4iJgMKKFFdiUwFcFRDvcjCtw==", + "requires": { + "date-format": "^2.1.0", + "debug": "^4.1.1", + "fs-extra": "^8.1.0" + }, + "dependencies": { + "date-format": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/date-format/-/date-format-2.1.0.tgz", + "integrity": "sha512-bYQuGLeFxhkxNOF3rcMtiZxvCBAquGzZm6oWA1oZ0g2THUzivaRhv8uOhdr19LmoobSOLoIAxeUK2RdbM8IFTA==" + } + } + }, "strict-uri-encode": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/strict-uri-encode/-/strict-uri-encode-1.1.0.tgz", @@ -18508,8 +18553,7 @@ "universalify": { "version": "0.1.2", "resolved": "https://registry.npmjs.org/universalify/-/universalify-0.1.2.tgz", - "integrity": "sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg==", - "dev": true + "integrity": "sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg==" }, "unix-crypt-td-js": { "version": "1.1.4", diff --git a/src/frontend/package.json b/src/frontend/package.json index 5f231b0..8a123a5 100644 --- a/src/frontend/package.json +++ b/src/frontend/package.json @@ -62,10 +62,12 @@ "core-js": "2.5.1", "echarts": "^4.0.2", "eva-icons": "^1.1.0", + "font-awesome": "^4.7.0", "intl": "1.2.5", "ionicons": "2.0.1", "js-cookie": "^2.2.1", "leaflet": "1.2.0", + "log4js": "^6.1.2", "nebular-icons": "1.1.0", "ng2-ckeditor": "^1.2.2", "ng2-completer": "2.0.8", diff --git a/src/frontend/server.ts b/src/frontend/server.ts index e11ec07..a3a7fbb 100644 --- a/src/frontend/server.ts +++ b/src/frontend/server.ts @@ -13,15 +13,22 @@ global['document'] = win.document; global['alert'] = console.log global['XMLHttpRequest'] = require('xmlhttprequest').XMLHttpRequest; -export async function attachExpress(app, staticDir = "./dist", loggerService = console) { +export async function attachExpress(app, staticDir = "./dist", logger = console) { const STATIC_FOLDER = resolve(process.cwd(), staticDir); - enableProdMode(); + const loggerService = { + warn: (...args) => logger.error(...args), + error: (...args) => logger.warn(...args), + log: (...args) => logger.info(...args), + table: (...args) => logger.info(...args), + collapsed: (msg, type, ...args) => loggerService[type](msg, ...args) + } + const bundle = require(staticDir + '/server/main'); const ServerApiService = bundle.ServerApiService - const serviceObj = new ServerApiService(loggerService) + const serviceObj = new ServerApiService(logger) await serviceObj.initialize() app.set('view engine', 'html'); diff --git a/src/frontend/src/app/@theme/components/header/chat.component.ts b/src/frontend/src/app/@theme/components/header/chat.component.ts deleted file mode 100644 index edd9ab8..0000000 --- a/src/frontend/src/app/@theme/components/header/chat.component.ts +++ /dev/null @@ -1,46 +0,0 @@ -import { Component } from '@angular/core'; -import { ShoutMessage } from '../../../../../../backend/Components/Shoutbox/Interface'; -import { IApiService } from '../../../frontcraft/services/ApiService'; - -@Component({ - selector: 'chat', - template: ` - - - - - - - `, - styles: [` - nb-chat { - width: 600px; - margin: 0.5rem 0 2rem 2rem; - }`], -}) -export class ChatComponent { - - messages : ShoutMessage[] = [] - history - - constructor( - private api: IApiService - ) {} - - submit(event){ - this.sendMessage({ - date: ""+Date.now(), - message: event.message, - sender: this.api.getCurrentUser().username - }) - } - - sendMessage : (msg:ShoutMessage)=>Promise -} diff --git a/src/frontend/src/app/@theme/components/header/header.component.html b/src/frontend/src/app/@theme/components/header/header.component.html index f60c2c7..5a9217e 100644 --- a/src/frontend/src/app/@theme/components/header/header.component.html +++ b/src/frontend/src/app/@theme/components/header/header.component.html @@ -14,19 +14,6 @@ icon="settings-2-outline" link="/permissions"> - - - - { @@ -89,29 +83,10 @@ export class HeaderComponent implements OnInit, OnDestroy { } }) - - this.api.get('GuildManager').getGuildInfo().then(info => { this.title = info.name }) - this.api.connectShoutbox((msg) => { - this.chatlog.push(msg) - msg['reply'] = false - - if (msg.message != this.lastmessage) { - this.newmessage = true - msg['reply'] = true - } - if (this.chatwindow) this.chatwindow.messages.push(msg) - }).then(sendMsg => { - this.sendMessage = (msg) => { - sendMsg(msg) - this.lastmessage = msg.message - } - this.api.get('Shoutbox').getFeed().then(log => { this.chatlog = log }) - }) - this.themeService.onThemeChange() .pipe( map(({ name }) => name), @@ -120,20 +95,6 @@ export class HeaderComponent implements OnInit, OnDestroy { .subscribe(themeName => this.currentTheme = themeName); } - openChat() { - this.newmessage = false - const ref = this.dialogService.open(ChatComponent, { - context: { - sendMessage: this.sendMessage, - } - }); - ref.onClose.subscribe(() => { - this.chatwindow = null - }) - this.chatwindow = ref.componentRef.instance - this.chatwindow.messages.push(...this.chatlog) - } - ngOnDestroy() { this.destroy$.next(); this.destroy$.complete(); diff --git a/src/frontend/src/app/@theme/theme.module.ts b/src/frontend/src/app/@theme/theme.module.ts index 1e484a5..03b909d 100644 --- a/src/frontend/src/app/@theme/theme.module.ts +++ b/src/frontend/src/app/@theme/theme.module.ts @@ -42,7 +42,6 @@ import { DEFAULT_THEME } from './styles/theme.default'; import { COSMIC_THEME } from './styles/theme.cosmic'; import { CORPORATE_THEME } from './styles/theme.corporate'; import { DARK_THEME } from './styles/theme.dark'; -import { ChatComponent } from './components/header/chat.component'; const NB_MODULES = [ NbLayoutModule, @@ -70,7 +69,6 @@ const COMPONENTS = [ ThreeColumnsLayoutComponent, TwoColumnsLayoutComponent, OneColumnNoSidebarLayoutComponent, - ChatComponent ]; const PIPES = [ CapitalizePipe, @@ -85,7 +83,6 @@ const PIPES = [ exports: [CommonModule, ...PIPES, ...COMPONENTS], declarations: [...COMPONENTS, ...PIPES], entryComponents: [ - ChatComponent ] }) export class ThemeModule { diff --git a/src/frontend/src/app/app.component.ts b/src/frontend/src/app/app.component.ts index 7a00e3d..23fdd09 100644 --- a/src/frontend/src/app/app.component.ts +++ b/src/frontend/src/app/app.component.ts @@ -3,10 +3,17 @@ * Copyright Akveo. All Rights Reserved. * Licensed under the MIT License. See License.txt in the project root for license information. */ -import { Component, OnInit } from '@angular/core'; +import { Component } from '@angular/core'; +import { NbIconLibraries } from '@nebular/theme'; + @Component({ selector: 'ngx-app', - template: '', + template: ``, + styles: [] }) -export class AppComponent { } +export class AppComponent{ + constructor(private iconLibraries: NbIconLibraries) { + this.iconLibraries.registerFontPack('font-awesome', { iconClassPrefix: 'fa' }); + } +} diff --git a/src/frontend/src/app/app.module.ts b/src/frontend/src/app/app.module.ts index e4e65db..0b24a00 100644 --- a/src/frontend/src/app/app.module.ts +++ b/src/frontend/src/app/app.module.ts @@ -23,6 +23,7 @@ import { NbToastrModule, NbWindowModule, } from '@nebular/theme'; +import { FlashService } from './frontcraft/services/flash-service'; @NgModule({ declarations: [ @@ -49,7 +50,7 @@ import { PermissionsModule ], bootstrap: [AppComponent], - providers: [] + providers: [FlashService] }) export class FrontcraftAppModule { } diff --git a/src/frontend/src/app/frontcraft/UpdatingComponent.ts b/src/frontend/src/app/frontcraft/UpdatingComponent.ts index 018c8c3..dc2e92c 100644 --- a/src/frontend/src/app/frontcraft/UpdatingComponent.ts +++ b/src/frontend/src/app/frontcraft/UpdatingComponent.ts @@ -1,23 +1,41 @@ import { Router, NavigationStart } from '@angular/router' -import { IApiService } from './services/ApiService' +import { IApiService } from './services/ApiService/ApiService' import { AnyFunction } from 'rpclibrary' -import { LoggerService } from './services/logger.service' -import { OnDestroy } from '@angular/core' +import { LoggerService } from './services/LoggerService/logger.service' +import { OnDestroy, Inject, PLATFORM_ID, Injector } from '@angular/core' +import { isPlatformBrowser } from '@angular/common' export abstract class UpdatingComponent implements OnDestroy { + private _uuid: string private _routerCancel: Function + private _router: Router + private _api: IApiService + private _logger: LoggerService + private platformId: Object constructor( - private _router: Router, - private _api: IApiService, - private _logger: LoggerService - ) { } + injector: Injector + ) { + this._router = injector.get(Router) + this._api = injector.get(IApiService) + this._logger = injector.get(LoggerService) + this.platformId = injector.get(PLATFORM_ID) + } protected subscribe = ( topic: string, callback: AnyFunction, ) => { + if (!topic + || topic === "null" + || topic === "undefined" + || !callback + || !isPlatformBrowser(this.platformId)) + { + return + } + const sub = this._router.events.subscribe(event => { if (event instanceof NavigationStart) { this.ngOnDestroy() diff --git a/src/frontend/src/app/frontcraft/auth/login/login.component.ts b/src/frontend/src/app/frontcraft/auth/login/login.component.ts index a4f8c1b..e8efe69 100644 --- a/src/frontend/src/app/frontcraft/auth/login/login.component.ts +++ b/src/frontend/src/app/frontcraft/auth/login/login.component.ts @@ -1,6 +1,6 @@ import { Component, OnInit } from '@angular/core'; import { Router, ActivatedRoute } from '@angular/router'; -import { IApiService } from '../../services/ApiService'; +import { IApiService } from '../../services/ApiService/ApiService'; import { NbToastrService } from '@nebular/theme'; @Component({ diff --git a/src/frontend/src/app/frontcraft/auth/logout/logout.component.ts b/src/frontend/src/app/frontcraft/auth/logout/logout.component.ts index 693eead..e301b60 100644 --- a/src/frontend/src/app/frontcraft/auth/logout/logout.component.ts +++ b/src/frontend/src/app/frontcraft/auth/logout/logout.component.ts @@ -1,5 +1,5 @@ import { Component, OnInit } from '@angular/core'; -import { IApiService } from '../../services/ApiService'; +import { IApiService } from '../../services/ApiService/ApiService'; import { Router, ActivatedRoute } from '@angular/router'; @Component({ diff --git a/src/frontend/src/app/frontcraft/auth/register/register.component.ts b/src/frontend/src/app/frontcraft/auth/register/register.component.ts index 9472538..82b3454 100644 --- a/src/frontend/src/app/frontcraft/auth/register/register.component.ts +++ b/src/frontend/src/app/frontcraft/auth/register/register.component.ts @@ -2,7 +2,7 @@ import { Component, OnInit } from '@angular/core'; import { Router, ActivatedRoute } from '@angular/router'; import { _Rank, _Class, Class, User, _Race } from '../../../../../../backend/Types/Types' import { specs } from '../../../../../../backend/Types/PlayerSpecs' -import { hash, IApiService } from '../../services/ApiService'; +import { hash, IApiService } from '../../services/ApiService/ApiService'; @Component({ diff --git a/src/frontend/src/app/frontcraft/pages/armory/armory.component.ts b/src/frontend/src/app/frontcraft/pages/armory/armory.component.ts index 7ec541b..2f4dc45 100644 --- a/src/frontend/src/app/frontcraft/pages/armory/armory.component.ts +++ b/src/frontend/src/app/frontcraft/pages/armory/armory.component.ts @@ -2,7 +2,7 @@ import { Component, OnInit } from '@angular/core'; import { Item, Stats } from '../../../../../../backend/Types/Types'; import { NbToastrService } from '@nebular/theme'; -import { IApiService } from '../../services/ApiService'; +import { IApiService } from '../../services/ApiService/ApiService'; @Component({ selector: 'armory', 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 b2abf17..0e1b423 100644 --- a/src/frontend/src/app/frontcraft/pages/character/character.component.ts +++ b/src/frontend/src/app/frontcraft/pages/character/character.component.ts @@ -3,7 +3,7 @@ import { ActivatedRoute } from '@angular/router'; import { Spec, User, Character, Item } from '../../../../../../backend/Types/Types'; import { getClassColor } from '../../../../../../backend/Types/PlayerSpecs'; import { _Tiers } from '../../../../../../backend/Types/Items'; -import { IApiService } from '../../services/ApiService'; +import { IApiService } from '../../services/ApiService/ApiService'; @Component({ selector: 'character', diff --git a/src/frontend/src/app/frontcraft/pages/characters/characters.component.ts b/src/frontend/src/app/frontcraft/pages/characters/characters.component.ts index 21b427b..e1c94de 100644 --- a/src/frontend/src/app/frontcraft/pages/characters/characters.component.ts +++ b/src/frontend/src/app/frontcraft/pages/characters/characters.component.ts @@ -2,7 +2,7 @@ import { Component, AfterViewInit, OnDestroy } from '@angular/core'; import { NbThemeService } from '@nebular/theme'; import { _Class } from '../../../../../../backend/Types/Types'; import { getClassColor } from '../../../../../../backend/Types/PlayerSpecs'; -import { IApiService } from '../../services/ApiService'; +import { IApiService } from '../../services/ApiService/ApiService'; @Component({ diff --git a/src/frontend/src/app/frontcraft/pages/pages-layout.component.ts b/src/frontend/src/app/frontcraft/pages/pages-layout.component.ts index e498fd1..79dd517 100644 --- a/src/frontend/src/app/frontcraft/pages/pages-layout.component.ts +++ b/src/frontend/src/app/frontcraft/pages/pages-layout.component.ts @@ -1,7 +1,7 @@ import { Component, OnInit } from '@angular/core'; import { NbMenuItem } from '@nebular/theme'; import { Router } from '@angular/router'; -import { IApiService } from '../services/ApiService'; +import { IApiService } from '../services/ApiService/ApiService'; @Component({ diff --git a/src/frontend/src/app/frontcraft/pages/raid/archive.component.ts b/src/frontend/src/app/frontcraft/pages/raid/archive.component.ts index 1ad3263..f9f88a2 100644 --- a/src/frontend/src/app/frontcraft/pages/raid/archive.component.ts +++ b/src/frontend/src/app/frontcraft/pages/raid/archive.component.ts @@ -1,8 +1,9 @@ import { Component, OnInit } from '@angular/core'; -import { ActivatedRoute } from '@angular/router'; +import { ActivatedRoute, Router } from '@angular/router'; import { RaidData } from '../../../../../../backend/Types/Types'; import { getClassColor } from '../../../../../../backend/Types/PlayerSpecs'; -import { IApiService } from '../../services/ApiService'; +import { IApiService } from '../../services/ApiService/ApiService'; +import { LoggerService } from '../../services/LoggerService/logger.service'; @Component({ selector: 'archive', @@ -40,6 +41,8 @@ export class FrontcraftArchiveComponent implements OnInit{ constructor( private api: IApiService, private route: ActivatedRoute, + private router: Router, + private logger: LoggerService ){ } @@ -51,25 +54,31 @@ export class FrontcraftArchiveComponent implements OnInit{ const param = this.route.snapshot.paramMap.get('id'); const raidManager = this.api.get('RaidManager') - const raiddata = await raidManager.getArchiveRaid(parseInt(param)) + try{ + const raiddata = await raidManager.getArchiveRaid(parseInt(param)) + if(!raiddata) throw new Error('Unable to get raid') - console.log(raiddata); - - - this.raid = raiddata - this.isTier = raiddata.tier != null - this.tokens = raiddata.tokens - this.displayedtokens = this.tokens; - - [ - ...raiddata.tanks, - ...raiddata.healers, - ...Object.values(raiddata.participants).flat() - ].forEach(p => { - p['color'] = getClassColor(p.class) - }) - - this.changeSearch() + this.raid = raiddata + this.isTier = raiddata.tier != null + this.tokens = raiddata.tokens + this.displayedtokens = this.tokens; + + [ + ...raiddata.tanks, + ...raiddata.healers, + ...Object.values(raiddata.participants).flat() + ].forEach(p => { + p['color'] = getClassColor(p.class) + if(!p.timestamp) + p.before = 5.184e+8 //7 days + else + p['before'] = Number.parseInt(this.raid.start) - Date.parse(p.timestamp) + }) + + this.changeSearch() + }catch(e){ + this.router.navigate(["/"]) + } } changeSearch(){ diff --git a/src/frontend/src/app/frontcraft/pages/raid/characterpicker.component.ts b/src/frontend/src/app/frontcraft/pages/raid/characterpicker.component.ts index 5036c2e..b52d965 100644 --- a/src/frontend/src/app/frontcraft/pages/raid/characterpicker.component.ts +++ b/src/frontend/src/app/frontcraft/pages/raid/characterpicker.component.ts @@ -2,7 +2,7 @@ import { OnInit, Component } from '@angular/core'; import { NbToastrService, NbDialogRef } from '@nebular/theme'; import { RaidData, Character } from '../../../../../../backend/Types/Types'; import { getClassColor } from '../../../../../../backend/Types/PlayerSpecs'; -import { IApiService } from '../../services/ApiService'; +import { IApiService } from '../../services/ApiService/ApiService'; @Component({ selector: 'characterpicker', 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 6c9b3fb..3cecaab 100644 --- a/src/frontend/src/app/frontcraft/pages/raid/raid.component.html +++ b/src/frontend/src/app/frontcraft/pages/raid/raid.component.html @@ -86,17 +86,17 @@ style="white-space: pre-line; max-width: 50vw; word-wrap: break-word;"> {{participant.memo}}

- {{participant.timestamp | date : 'HH:mm EEE MMM d'}} + {{participant.timestamp | date : 'HH:mm EEE MMM d'}} ({{participant.before | date : 'dd'}} days before start) - - - + + Trial @@ -129,16 +129,15 @@

{{participant.memo}}

- {{participant.timestamp | date : 'HH:mm EEE MMM d'}} + {{participant.timestamp | date : 'HH:mm EEE MMM d'}} ({{participant.before | date : 'dd'}} days before start) - - - + Trial @@ -174,17 +173,17 @@

{{participant.memo}}

- {{participant.timestamp | date : 'HH:mm EEE MMM d'}} + {{participant.timestamp | date : 'HH:mm EEE MMM d'}} ({{participant.before | date : 'dd'}} days before start) - - - + + Trial @@ -213,7 +212,7 @@ - +
- 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 4f0ddf1..2a05d94 100644 --- a/src/frontend/src/app/frontcraft/pages/raid/raid.component.ts +++ b/src/frontend/src/app/frontcraft/pages/raid/raid.component.ts @@ -1,4 +1,4 @@ -import { Component, OnInit } from '@angular/core'; +import { Component, OnInit, Injector } from '@angular/core'; import { ActivatedRoute, Router } from '@angular/router'; import { RaidData, Raid, Signup, Character, Spec, Item, SRToken } from '../../../../../../backend/Types/Types'; import { NbToastrService, NbDialogService } from '@nebular/theme'; @@ -6,202 +6,214 @@ import { FrontcraftCharacerpickerComponent } from './characterpicker.component'; import { getClassColor } from '../../../../../../backend/Types/PlayerSpecs'; import { FrontcraftBuyTokenComponent } from '../shop/buytoken.component'; import { allItems } from '../../../../../../backend/Types/Items'; -import { IApiService } from '../../services/ApiService'; +import { IApiService } from '../../services/ApiService/ApiService'; import { UpdatingComponent } from '../../UpdatingComponent'; -import { LoggerService } from '../../services/logger.service'; +import { LoggerService } from '../../services/LoggerService/logger.service'; +import { FlashService } from '../../services/flash-service'; @Component({ selector: 'raid', templateUrl: './raid.component.html', }) -export class FrontcraftRaidComponent -extends UpdatingComponent -implements OnInit{ +export class FrontcraftRaidComponent + extends UpdatingComponent + implements OnInit { - canSignup = false - isSignedup = false - islate = false - isTier = false - reservesShown = true - manageRaid - mySignup: (Signup & Character & Spec) + now = Date.now() + canSignup = false + isSignedup = false + islate = false + isTier = false + reservesShown = true + manageRaid + mySignup: (Signup & Character & Spec) - raid: RaidData = { - participants:{ - Druid: [], - Hunter: [], - Mage: [], - Paladin: [], - Priest: [], - Rogue: [], - Shaman: [], - Warlock: [], - Warrior: [], - }, - tanks: [], - healers: [], - tokens:{}, - tier: 'null' + raid: RaidData = { + participants: { + Druid: [], + Hunter: [], + Mage: [], + Paladin: [], + Priest: [], + Rogue: [], + Shaman: [], + Warlock: [], + Warrior: [], + }, + tanks: [], + healers: [], + tokens: {}, + tier: 'null' + } + tokens: { [itemname in string]: (Character & SRToken & Item)[] } = {} + displayedtokens = {} + search = "" + + constructor( + injector: Injector, + private api: IApiService, + private route: ActivatedRoute, + private router: Router, + private dialogService: NbDialogService, + private toast: NbToastrService, + private flash: FlashService, + private logger: LoggerService + ) { + super(injector) + } + + ngOnInit() { + this.manageRaid = this.api.get('manageRaid') + const signupFeature = this.api.get('signup') + + if (signupFeature) { + this.canSignup = true } - tokens: {[itemname in string]: (Character & SRToken & Item)[]} = {} - displayedtokens = {} - search = "" + this.refresh().then(() => { + this.subscribe(String(this.raid.id), (data: RaidData) => this.display(data).then(_ => + this.flash.show() + )) + }) + } - constructor( - private api: IApiService, - private route: ActivatedRoute, - private router: Router, - private dialogService : NbDialogService, - private toast: NbToastrService, - logger: LoggerService - ){ - super(router, api, logger) - } - - ngOnInit(){ - this.manageRaid = this.api.get('manageRaid') - const signupFeature = this.api.get('signup') - - if(signupFeature){ - this.canSignup = true + itemSelect = async (item) => { + this.dialogService.open(FrontcraftBuyTokenComponent, { + context: { + item: item, + signup: this.mySignup, + tier: this.raid.tier, + characterName: this.mySignup.charactername } + }).onClose.subscribe(() => { this.refresh().then(() => { - this.subscribe(String(this.raid.id), (data: RaidData) => this.display(data)) + this.reservesShown = true }) - } + }) + } - itemSelect = async(item) => { - this.dialogService.open(FrontcraftBuyTokenComponent, { - context: { - item: item, - signup: this.mySignup, - tier: this.raid.tier, - characterName: this.mySignup.charactername - } - }).onClose.subscribe(() => { - this.refresh().then(()=>{ - this.reservesShown = true - }) + signup = async () => { + const signupFeature = this.api.get('signup') + if (!signupFeature) return + + this.dialogService.open(FrontcraftCharacerpickerComponent, { + closeOnBackdropClick: true, + closeOnEsc: true, + context: { + raid: this.raid, + } + }).onClose.subscribe(() => { + this.refresh().then(() => { + this.reservesShown = false }) - } + }) + } - signup = async () => { - const signupFeature = this.api.get('signup') - if(!signupFeature) return + async archiveRaid(raid: Raid) { + await this.manageRaid!.archiveRaid(raid) + this.toast.show('Raid archived', 'Success', { status: 'success' }) + this.router.navigateByUrl('/frontcraft/archive/' + raid.id) + } - this.dialogService.open(FrontcraftCharacerpickerComponent, { - closeOnBackdropClick: true, - closeOnEsc: true, - context: { - raid: this.raid, - } - }).onClose.subscribe(() => { - this.refresh().then(()=>{ - this.reservesShown = false - }) - }) - } + async startRaid(raid: Raid) { + await this.manageRaid!.startRaid(raid) + this.toast.show('Raid started', 'Success', { status: 'success' }) + this.router.navigateByUrl('/frontcraft/archive/' + raid.id) + } - async archiveRaid(raid:Raid){ - await this.manageRaid!.archiveRaid(raid) - this.toast.show('Raid archived', 'Success', { status: 'success' }) - this.router.navigateByUrl('/frontcraft/archive/'+raid.id) - } + unsign = async () => { + const signupFeature = this.api.get('signup') + if (!signupFeature) return - async startRaid(raid:Raid){ - await this.manageRaid!.startRaid(raid) - this.toast.show('Raid started', 'Success', { status: 'success' }) - this.router.navigateByUrl('/frontcraft/archive/'+raid.id) - } + await signupFeature.unsign(this.api.getAuth().token.value, { + ...this.mySignup, + id: this.mySignup.characterid, + }, this.raid) + this.toast.show('Success', 'Unsigned', { status: 'success' }) + } - unsign = async () => { - const signupFeature = this.api.get('signup') - if(!signupFeature) return + setLate = async (value: boolean) => { + const auth = this.api.getAuth() + const signup = this.api.get('signup') + if (!signup) return - await signupFeature.unsign(this.api.getAuth().token.value, { - ...this.mySignup, - id: this.mySignup.characterid, - }, this.raid) - this.toast.show('Success', 'Unsigned', { status: 'success' }) - } + await signup.sign(auth.token.value, { + ...this.mySignup, + id: this.mySignup.characterid, + }, this.raid, value, this.mySignup.memo) + this.toast.show('Signup', 'Success', { status: 'success' }) + } - setLate = async (value:boolean) => { - const auth = this.api.getAuth() - const signup = this.api.get('signup') - if(!signup) return + adminUnsign = async (character: Character) => { + const manage = this.api.get('manageRaid') + if (!manage) return + await manage.adminUnsign({ + ...character, + id: character['characterid'] + }, this.raid) + } - await signup.sign(auth.token.value, { - ...this.mySignup, - id: this.mySignup.characterid, - }, this.raid, value, this.mySignup.memo) - this.toast.show('Signup', 'Success', { status: 'success' }) - } + refresh = async () => { + const param = this.route.snapshot.paramMap.get('id'); + const raidManager = this.api.get('RaidManager') - adminUnsign = async(character:Character) => { - const manage = this.api.get('manageRaid') - if(!manage) return - await manage.adminUnsign({ - ...character, - id: character['characterid'] - }, this.raid) - } - - refresh = async () => { - const param = this.route.snapshot.paramMap.get('id'); - - const raidManager = this.api.get('RaidManager') + try { const raiddata = await raidManager.getRaidData({ id: param }) - this.display(raiddata) + await this.display(raiddata) + } catch (e) { + this.router.navigate(["/"]) + } + } + + display = async (raiddata: RaidData) => { + this.logger.log(raiddata) + this.isTier = allItems[raiddata.tier] != null + + this.raid = raiddata + this.tokens = raiddata.tokens; + + [...raiddata.tanks, ...raiddata.healers, ...Object.values(raiddata.participants).flat()].forEach(p => { + p['color'] = getClassColor(p.class) + p['before'] = Number.parseInt(this.raid.start) - Date.parse(p.timestamp) + }) + + const user = this.api.getCurrentUser() + const matchingSignup = Object.values(raiddata.participants).flat().find(char => user && char.userid === user.id!) + + if (matchingSignup) { + this.mySignup = matchingSignup + this.isSignedup = true + this.mySignup['status'] = matchingSignup['benched'] ? 'Bench' : matchingSignup['late'] ? 'Late' : 'Attending' + } else { + this.isSignedup = false + this.mySignup = null } - display = async (raiddata:RaidData) => { - this.isTier = allItems[raiddata.tier] != null + this.changeSearch() + } - this.raid = raiddata - this.tokens = raiddata.tokens; - - [...raiddata.tanks, ...raiddata.healers, ...Object.values(raiddata.participants).flat()].forEach(p => { - p['color'] = getClassColor(p.class) + changeSearch() { + if (!this.search || this.search == "") { + this.displayedtokens = this.tokens + } else { + this.displayedtokens = {} + Object.entries(this.tokens).forEach((e: [string /*itemname*/, (Character & SRToken & Item)[]]) => { + const filteredTokens = e[1].filter(item => { + return item.itemname.toLocaleLowerCase().includes(this.search.toLocaleLowerCase()) + }) + if (filteredTokens.length > 0) + this.displayedtokens[e[0]] = filteredTokens }) - - const user = this.api.getCurrentUser() - const matchingSignup = Object.values(raiddata.participants).flat().find(char => user && char.userid === user.id!) - - if(matchingSignup){ - this.mySignup = matchingSignup - this.isSignedup = true - this.mySignup['status'] = matchingSignup['benched']?'Bench':matchingSignup['late']?'Late':'Attending' - }else{ - this.isSignedup = false - this.mySignup = null - } - - this.changeSearch() } + } - changeSearch(){ - if(!this.search || this.search == ""){ - this.displayedtokens = this.tokens - }else{ - this.displayedtokens = {} - Object.entries(this.tokens).forEach((e: [string /*itemname*/, (Character & SRToken & Item)[]]) => { - const filteredTokens = e[1].filter(item => { - return item.itemname.toLocaleLowerCase().includes(this.search.toLocaleLowerCase()) - }) - if(filteredTokens.length > 0) - this.displayedtokens[e[0]] = filteredTokens - }) - } - } - - setBench(signup:Signup){ - this.manageRaid.setBenched({ - characterid: signup.characterid, - raidid: signup.raidid, - late: false, - benched: !signup.benched - }).then(_ => this.refresh()) - } + setBench(signup: Signup) { + this.manageRaid.setBenched({ + characterid: signup.characterid, + raidid: signup.raidid, + late: false, + benched: !signup.benched + }).then(_ => this.refresh()) + } } \ No newline at end of file diff --git a/src/frontend/src/app/frontcraft/pages/raids/createraid.compontent.ts b/src/frontend/src/app/frontcraft/pages/raids/createraid.compontent.ts index 1107c6b..3bf4e73 100644 --- a/src/frontend/src/app/frontcraft/pages/raids/createraid.compontent.ts +++ b/src/frontend/src/app/frontcraft/pages/raids/createraid.compontent.ts @@ -1,8 +1,8 @@ import { Component, OnInit } from '@angular/core'; import { Raid, RaidData } from '../../../../../../backend/Types/Types'; -import { NbDialogRef } from '@nebular/theme'; +import { NbDialogRef, DARK_THEME } from '@nebular/theme'; import { Tiers, _Tiers } from '../../../../../../backend/Types/Items'; -import { IApiService } from '../../services/ApiService'; +import { IApiService } from '../../services/ApiService/ApiService'; const ONE_MINUTE = 60000 const ONE_HOUR = 60 * ONE_MINUTE @@ -34,7 +34,6 @@ export class FrontcraftCreateRaidsComponent implements OnInit { } onTierSelect(){ - } onTemplateSelect(){ @@ -62,7 +61,7 @@ export class FrontcraftCreateRaidsComponent implements OnInit { const manage = this.api.get('manageRaid') if(!manage) return - await manage.createRaid(raid) + const dbraid = await manage.createRaid(raid) this.dialogRef.close() } } diff --git a/src/frontend/src/app/frontcraft/pages/raids/raids.component.html b/src/frontend/src/app/frontcraft/pages/raids/raids.component.html index 30a8317..bd6a352 100644 --- a/src/frontend/src/app/frontcraft/pages/raids/raids.component.html +++ b/src/frontend/src/app/frontcraft/pages/raids/raids.component.html @@ -6,30 +6,33 @@ -
-

@@ -221,30 +220,29 @@
-
-
- - - [ {{token.level}} ]  - - {{token.charactername}} - - +
+
+ + + [ {{token.level}} ]  + + {{token.charactername}} + - -
- Becomes valid when promoted to Raider -
-
- - Trial -
-
+ + +
+ Becomes valid when promoted to Raider +
+
+ +  Trial +
- - +
- -
+ + + - - - - - -
+ +

{{raid.title}}

-
-  {{raid.signupcount}} / {{raid.size}}
-
-  {{raid.start | date : 'HH:mm'}} - -  {{raid.start | date : 'EEE MMM d'}} -
- + + + + +  {{ raid.signupcount | number:'2.0' }} / {{raid.size}} + + +  {{ raid.benchcount }} + + +  {{raid.start | date : 'HH:mm'}} + + +  {{raid.start | date : 'EEE MMM d'}} + + +
@@ -40,30 +43,33 @@ -
- +
-

- {{raid.title}} -

- - - - + + + + -
-  {{raid.signupcount}} / {{raid.size}}
+
+

+ {{raid.title}} +

+
+  {{ raid.signupcount | number:'2.0' }} / {{raid.size}} + +  {{ raid.participants.bench.length }} +  {{raid.start | date : 'HH:mm'}} +  {{raid.start | date : 'EEE MMM d'}}
-
diff --git a/src/frontend/src/app/frontcraft/pages/raids/raids.component.ts b/src/frontend/src/app/frontcraft/pages/raids/raids.component.ts index f98faa4..16d62a1 100644 --- a/src/frontend/src/app/frontcraft/pages/raids/raids.component.ts +++ b/src/frontend/src/app/frontcraft/pages/raids/raids.component.ts @@ -1,19 +1,20 @@ -import { Component, OnInit, OnDestroy } from '@angular/core'; -import { NbDialogService } from '@nebular/theme'; +import { Component, OnInit, OnDestroy, Injector } from '@angular/core'; +import { NbDialogService, NbToastrService } from '@nebular/theme'; import { FrontcraftCreateRaidsComponent } from './createraid.compontent'; import { Router, NavigationStart } from '@angular/router'; -import { IApiService } from '../../services/ApiService'; +import { IApiService } from '../../services/ApiService/ApiService'; import { UpdatingComponent } from '../../UpdatingComponent'; -import { LoggerService } from '../../services/logger.service'; +import { LoggerService } from '../../services/LoggerService/logger.service'; +import { FlashService } from '../../services/flash-service'; @Component({ selector: 'raids', templateUrl: 'raids.component.html', styleUrls: ['raids.component.scss'], }) -export class FrontcraftRaidsComponent -extends UpdatingComponent -implements OnInit { +export class FrontcraftRaidsComponent + extends UpdatingComponent + implements OnInit { manageRaid @@ -22,20 +23,22 @@ implements OnInit { pageSize = 10; constructor( + injector: Injector, private api: IApiService, - router: Router, private dialogService: NbDialogService, - logger: LoggerService + private flash: FlashService, ) { - super(router, api, logger) + super(injector) } - ngOnDestroy(){ + ngOnDestroy() { super.ngOnDestroy() } async ngOnInit() { - this.subscribe("raids", () => this.refresh()) + this.subscribe("raids", () => this.refresh().then(_ => + this.flash.show() + )) this.manageRaid = this.api.get('manageRaid') this.refresh() diff --git a/src/frontend/src/app/frontcraft/pages/rules/rules.component.ts b/src/frontend/src/app/frontcraft/pages/rules/rules.component.ts index f6c3d81..b2eb42c 100644 --- a/src/frontend/src/app/frontcraft/pages/rules/rules.component.ts +++ b/src/frontend/src/app/frontcraft/pages/rules/rules.component.ts @@ -1,6 +1,6 @@ import { Component, OnInit } from '@angular/core'; import { getClassColor } from '../../../../../../backend/Types/PlayerSpecs'; -import { IApiService } from '../../services/ApiService'; +import { IApiService } from '../../services/ApiService/ApiService'; @Component({ selector: 'rules', diff --git a/src/frontend/src/app/frontcraft/pages/shop/buytoken.component.ts b/src/frontend/src/app/frontcraft/pages/shop/buytoken.component.ts index 6a4ef88..b4e6eee 100644 --- a/src/frontend/src/app/frontcraft/pages/shop/buytoken.component.ts +++ b/src/frontend/src/app/frontcraft/pages/shop/buytoken.component.ts @@ -3,7 +3,7 @@ import { NbToastrService, NbDialogRef } from '@nebular/theme'; import { Item, Character, SRToken, Signup } from '../../../../../../backend/Types/Types'; import { getClassColor } from '../../../../../../backend/Types/PlayerSpecs'; import { _Tiers, Tiers } from '../../../../../../backend/Types/Items'; -import { IApiService } from '../../services/ApiService'; +import { IApiService } from '../../services/ApiService/ApiService'; @Component({ selector: 'buyToken', 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 95dc2b2..a07b689 100644 --- a/src/frontend/src/app/frontcraft/pages/shop/itemselector.component.ts +++ b/src/frontend/src/app/frontcraft/pages/shop/itemselector.component.ts @@ -1,7 +1,7 @@ import { Component, OnInit, Input, Output, EventEmitter } from '@angular/core'; -import { ClientApiService } from '../../services/client-login-api'; +import { ClientApiService } from '../../services/ApiService/client-login-api'; import { Item, Character } from '../../../../../../backend/Types/Types'; -import { IApiService } from '../../services/ApiService'; +import { IApiService } from '../../services/ApiService/ApiService'; @Component({ selector: 'itemselect', diff --git a/src/frontend/src/app/frontcraft/pages/shop/wowhead.component.ts b/src/frontend/src/app/frontcraft/pages/shop/wowhead.component.ts index 5980fa4..d5cfdee 100644 --- a/src/frontend/src/app/frontcraft/pages/shop/wowhead.component.ts +++ b/src/frontend/src/app/frontcraft/pages/shop/wowhead.component.ts @@ -8,7 +8,7 @@ import { DomSanitizer, SafeHtml } from '@angular/platform-browser'; template: ` -
+
Promise getCurrentUser: () => User login: (username: string, password: string) => Promise> - connectShoutbox: (callback:Function) => Promise kick: () => Promise logout: () => Promise get: (feature : K) => K extends keyof FrontcraftIfc diff --git a/src/frontend/src/app/frontcraft/services/client-login-api.ts b/src/frontend/src/app/frontcraft/services/ApiService/client-login-api.ts similarity index 89% rename from src/frontend/src/app/frontcraft/services/client-login-api.ts rename to src/frontend/src/app/frontcraft/services/ApiService/client-login-api.ts index def1b23..c999ab0 100644 --- a/src/frontend/src/app/frontcraft/services/client-login-api.ts +++ b/src/frontend/src/app/frontcraft/services/ApiService/client-login-api.ts @@ -1,10 +1,9 @@ import { Injectable } from "@angular/core"; import { RPCSocket } from 'rpclibrary/js/src/Frontend' import { ConnectedSocket } from "rpclibrary" -import { Auth, User, _Class, FrontcraftFeatureIfc, SomeOf, FrontcraftIfc, } from '../../../../../backend/Types/Types' -import { ShoutMessage } from '../../../../../backend/Components/Shoutbox/Interface'; +import { Auth, User, _Class, FrontcraftFeatureIfc, SomeOf, FrontcraftIfc, } from '../../../../../../backend/Types/Types' import { hash, IApiService, GuestUser } from './ApiService'; -import { LoggerService } from './logger.service'; +import { LoggerService } from '../LoggerService/logger.service'; declare const Cookies @@ -12,7 +11,7 @@ declare const Cookies export class ClientApiService implements IApiService{ private socket:ConnectedSocket private auth:Auth - private privSocket: RPCSocket> + private privSocket: ConnectedSocket> constructor( private logger: LoggerService @@ -22,7 +21,7 @@ export class ClientApiService implements IApiService{ getUnprivilegedSocket = () : ConnectedSocket => this.socket - private getPrivilegedSocket = async (auth:Auth) : Promise>> => { + private getPrivilegedSocket = async (auth:Auth) : Promise>> => { if(this.privSocket) { return this.privSocket } @@ -105,11 +104,6 @@ export class ClientApiService implements IApiService{ return sock } - async connectShoutbox(callback:Function) : Promise{ - const uuid = await this.get('Shoutbox').subscribe(callback) - return async (msg: ShoutMessage) => await this.get('Shoutbox').shout(uuid, msg) - } - kick = async () => { await this.logout() location.reload() diff --git a/src/frontend/src/app/frontcraft/services/server-login-api.ts b/src/frontend/src/app/frontcraft/services/ApiService/server-login-api.ts similarity index 57% rename from src/frontend/src/app/frontcraft/services/server-login-api.ts rename to src/frontend/src/app/frontcraft/services/ApiService/server-login-api.ts index 84b579b..83bc0f9 100644 --- a/src/frontend/src/app/frontcraft/services/server-login-api.ts +++ b/src/frontend/src/app/frontcraft/services/ApiService/server-login-api.ts @@ -1,45 +1,48 @@ import { Injectable } from "@angular/core"; -import {RPCSocket} from 'rpclibrary/js/src/Frontend' -import { Auth, User, _Class, FrontcraftFeatureIfc, SomeOf, FrontcraftIfc, } from '../../../../../backend/Types/Types' +import { RPCSocket } from 'rpclibrary/js/src/Frontend' +import { Auth, User, _Class, FrontcraftFeatureIfc, SomeOf, FrontcraftIfc, } from '../../../../../../backend/Types/Types' import { hash, IApiService, GuestUser } from './ApiService'; -import { LoggerService } from './logger.service'; +import { LoggerService } from '../LoggerService/logger.service'; import { ConnectedSocket } from 'rpclibrary'; +import { async } from '@angular/core/testing'; declare const Cookies @Injectable() -export class ServerApiService implements IApiService{ - private socket:ConnectedSocket - private auth:Auth +export class ServerApiService implements IApiService { + private socket: ConnectedSocket + private auth: Auth private privSocket: RPCSocket & SomeOf constructor( private logger: LoggerService - ){} + ) { } - getUnprivilegedSocket = () : ConnectedSocket => this.socket + getUnprivilegedSocket = (): ConnectedSocket => this.socket + + get = (feature: K): + K extends keyof FrontcraftIfc ? FrontcraftIfc[K] : + K extends keyof FrontcraftFeatureIfc ? (FrontcraftFeatureIfc[K] | void) : + never => { - get = (feature : K) : K extends keyof FrontcraftIfc?FrontcraftIfc[K]: - K extends keyof FrontcraftFeatureIfc?(FrontcraftFeatureIfc[K] | void): - never => { //@ts-ignore return this.socket[feature] } - getCurrentUser = () : User => { + getCurrentUser = (): User => { return GuestUser } - login = async (username: string, password: string) : Promise> => { + login = async (username: string, password: string): Promise> => { const pwHash = await hash(password) let auth - try{ + try { auth = await this.socket.UserManager.login(username, pwHash) - }catch(e){ + } catch (e) { return } - if(!auth){ + if (!auth) { await this.logout() throw new Error("Login failed") } @@ -51,7 +54,7 @@ export class ServerApiService implements IApiService{ } - async connectShoutbox(callback:Function) : Promise{ + async connectShoutbox(callback: Function): Promise { return this.logger.log } @@ -60,32 +63,32 @@ export class ServerApiService implements IApiService{ logout = async () => { Cookies.remove('token') - if(this.auth){ - try{ + if (this.auth) { + try { await this.socket.UserManager.logout(this.auth.user.username, this.auth.token.value) - }catch(e){ + } catch (e) { this.logger.warn(e); } - } + } - if(this.privSocket) this.privSocket.destroy() + if (this.privSocket) this.privSocket.destroy() this.privSocket = null - this.auth = null + this.auth = null } - initialize = async () : Promise => { - if(this.socket){ + initialize = async (): Promise => { + if (this.socket) { this.socket.destroy() this.socket = null } - try{ + try { let conn = new RPCSocket(20000, window.location.hostname) conn.on('close', async () => { - }) + }) this.socket = await conn.connect() - }catch(e){ + } catch (e) { this.logger.log(e); throw new Error("Websocket cannot connect") } @@ -93,10 +96,10 @@ export class ServerApiService implements IApiService{ getAuth = () => this.auth - async checkLogin() : Promise{ - if(!this.auth) return false + async checkLogin(): Promise { + if (!this.auth) return false const valid = this.socket.UserManager.checkToken(this.auth.token.value, this.auth.user.rank) - if(valid) return true + if (valid) return true await this.logout() return false } diff --git a/src/frontend/src/app/frontcraft/services/LoggerService/LoggerService.ts b/src/frontend/src/app/frontcraft/services/LoggerService/LoggerService.ts new file mode 100644 index 0000000..c20349b --- /dev/null +++ b/src/frontend/src/app/frontcraft/services/LoggerService/LoggerService.ts @@ -0,0 +1,10 @@ +export interface ILoggerService { + log, + warn, + error, + table, +} + +export interface ICollapsableLoggerService extends ILoggerService{ + collapsed +} \ No newline at end of file diff --git a/src/frontend/src/app/frontcraft/services/LoggerService/logger.service.ts b/src/frontend/src/app/frontcraft/services/LoggerService/logger.service.ts new file mode 100644 index 0000000..99ecc42 --- /dev/null +++ b/src/frontend/src/app/frontcraft/services/LoggerService/logger.service.ts @@ -0,0 +1,30 @@ +import { Injectable, SkipSelf, Optional } from "@angular/core"; +import { environment } from '../../../../environments/environment'; +import { ICollapsableLoggerService, ILoggerService } from './LoggerService'; + +@Injectable() +export class LoggerService implements ICollapsableLoggerService { + + private logger = console + + constructor( + ) { } + + log = (...args) => { this.LOG('log', args) } + warn = (...args) => { this.LOG('warn', args) } + error = (...args) => { this.LOG('error', args) } + table = (...args) => { this.LOG('table', args) } + collapsed = (groupname: string, type: keyof ILoggerService, ...args) => { + if (!environment.production) { + console.groupCollapsed(groupname) + this[type].apply(this.logger, args) + console.groupEnd() + } + } + + private LOG(type, ...args) { + if (!environment.production) { + this.logger[type].apply(this.logger, ...args) + } + } +} \ No newline at end of file diff --git a/src/frontend/src/app/frontcraft/services/flash-service.ts b/src/frontend/src/app/frontcraft/services/flash-service.ts new file mode 100644 index 0000000..dd9883e --- /dev/null +++ b/src/frontend/src/app/frontcraft/services/flash-service.ts @@ -0,0 +1,21 @@ +import { Injectable, Inject } from '@angular/core'; +import { DOCUMENT } from '@angular/common'; + +@Injectable() +export class FlashService { + private displaying = false + constructor(@Inject(DOCUMENT) private document: Document) { } + + show(durationMs = 250) { + if (this.displaying) return + this.displaying = true + this.document.getElementById('glowbox').classList.toggle('glowing'); + this.document.getElementById('glowbox').classList.toggle('not-glowing'); + + setTimeout(() => { + this.displaying = false + this.document.getElementById('glowbox').classList.toggle('glowing'); + this.document.getElementById('glowbox').classList.toggle('not-glowing'); + }, durationMs) + } +} \ No newline at end of file diff --git a/src/frontend/src/app/frontcraft/services/logger.service.ts b/src/frontend/src/app/frontcraft/services/logger.service.ts deleted file mode 100644 index beab1a1..0000000 --- a/src/frontend/src/app/frontcraft/services/logger.service.ts +++ /dev/null @@ -1,37 +0,0 @@ -import { Injectable } from "@angular/core"; -import { environment } from '../../../environments/environment'; - -interface ILoggerService{ - log, - warn, - error, - table, - collapsed -} - -@Injectable() -export class LoggerService implements ILoggerService { - - constructor( - private logger = console - ) { } - - log = (...args) => { this.LOG('log', args) } - warn = (...args) => { this.LOG('warn', args) } - error = (...args) => { this.LOG('error', args) } - table = (...args) => { this.LOG('table', args) } - collapsed = (groupname: string, type: keyof ILoggerService, ...args) => { - if(type === "collapsed") - return this.log(args) - - console.groupCollapsed(groupname) - this[type as any].apply(this.logger, args) - console.groupEnd() - } - - private LOG(type, ...args) { - if (!environment.production) { - this.logger[type].apply(this.logger, ...args) - } - } -} \ No newline at end of file diff --git a/src/frontend/src/index.html b/src/frontend/src/index.html index e484e2c..4b5f07a 100644 --- a/src/frontend/src/index.html +++ b/src/frontend/src/index.html @@ -1,35 +1,57 @@ + Frontcraft @@ -38,13 +60,16 @@ + +

Tranquil

- + - + + \ No newline at end of file diff --git a/src/frontend/src/main.server.ts b/src/frontend/src/main.server.ts index d33b2b9..503ab8d 100644 --- a/src/frontend/src/main.server.ts +++ b/src/frontend/src/main.server.ts @@ -3,7 +3,7 @@ import { enableProdMode } from '@angular/core'; enableProdMode() export { AppServerModule } from './app/app.server.module'; -import { IApiService } from './app/frontcraft/services/ApiService'; +import { IApiService } from './app/frontcraft/services/ApiService/ApiService'; export { IApiService } -export { ServerApiService } from './app/frontcraft/services/server-login-api'; -export { LoggerService } from './app/frontcraft/services/logger.service' \ No newline at end of file +export { ServerApiService } from './app/frontcraft/services/ApiService/server-login-api'; +export { LoggerService } from './app/frontcraft/services/LoggerService/logger.service' \ No newline at end of file diff --git a/src/frontend/src/main.ts b/src/frontend/src/main.ts index 700a2a9..f68c7c7 100644 --- a/src/frontend/src/main.ts +++ b/src/frontend/src/main.ts @@ -8,9 +8,9 @@ import { platformBrowserDynamic } from '@angular/platform-browser-dynamic'; import { FrontcraftAppModule } from './app/app.module'; import { environment } from './environments/environment'; -import { IApiService } from "./app/frontcraft/services/ApiService" -import { ClientApiService } from './app/frontcraft/services/client-login-api'; -import { LoggerService } from './app/frontcraft/services/logger.service'; +import { IApiService } from "./app/frontcraft/services/ApiService/ApiService" +import { ClientApiService } from './app/frontcraft/services/ApiService/client-login-api'; +import { LoggerService } from './app/frontcraft/services/LoggerService/logger.service'; if (environment.production) { enableProdMode();