before frontend login
This commit is contained in:
@@ -0,0 +1,34 @@
|
||||
import { RPCExporter } from "rpclibrary"
|
||||
import { FrontworkAdmin } from "../../Admin/Admin"
|
||||
import { TableDefiniton } from "../../Types/Types"
|
||||
import { PrivilegedRPCExporter } from "../../Types/PrivilegedRPCExporter"
|
||||
import { FrontworkComponent } from "../../Types/FrontworkComponent"
|
||||
|
||||
export class Debugger
|
||||
implements FrontworkComponent<any,any>{
|
||||
public admin: FrontworkAdmin
|
||||
name = "Debugger"
|
||||
|
||||
|
||||
constructor(private exporters: PrivilegedRPCExporter[]){
|
||||
}
|
||||
|
||||
exportRPCs(){
|
||||
|
||||
return [{
|
||||
name: 'getTable',
|
||||
call: async(table:string) => this.admin.knex.select('*').from(table)
|
||||
},
|
||||
...this.exporters.flatMap(e => e.exportRPCs()),
|
||||
...this.exporters.flatMap(e => e.exportRPCFeatures().flatMap(e => e.exportRPCs()))]
|
||||
}
|
||||
|
||||
exportRPCFeatures(): RPCExporter<any, any, {}>[] {
|
||||
return []
|
||||
}
|
||||
|
||||
getTableDefinitions(): TableDefiniton[] {
|
||||
return []
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,100 @@
|
||||
import { RPCExporter, SubscriptionResponse, ErrorResponse, SuccessResponse } from "rpclibrary";
|
||||
import { FrontworkAdmin } from "../Admin/Admin";
|
||||
import { TableDefinitionExporter } from "../Types/Interfaces";
|
||||
import { getLogger } from 'frontblock-generic/Types';
|
||||
|
||||
import * as uuid from 'uuid/v4'
|
||||
import { TableDefiniton } from "../Types/Types";
|
||||
|
||||
export type NotificationSeverity = 'Info' | 'Important' | 'Error'
|
||||
|
||||
export type Notification = {
|
||||
ID?:number,
|
||||
severity: NotificationSeverity,
|
||||
topic: string,
|
||||
message:string,
|
||||
time?: number
|
||||
}
|
||||
|
||||
export type EventbusIfc = {
|
||||
Eventbus: {
|
||||
getNotificationLog: () => Promise<Notification[]>
|
||||
pushNotification: (notification:Notification) => Promise<void>
|
||||
subscribeNotifications: (callback:Function) => Promise<SubscriptionResponse | ErrorResponse>
|
||||
}
|
||||
}
|
||||
|
||||
const logger = getLogger("Eventbus", 'debug')
|
||||
|
||||
export class FrontworkEventBus
|
||||
implements RPCExporter<EventbusIfc, "Eventbus">, TableDefinitionExporter {
|
||||
name = "Eventbus" as "Eventbus"
|
||||
private subscriptions : { [uid in string]:Function } = {}
|
||||
|
||||
constructor(private admin: FrontworkAdmin){
|
||||
}
|
||||
|
||||
async subscribeNotifications(callback) : Promise<SubscriptionResponse>{
|
||||
const uid = uuid()
|
||||
this.subscriptions[uid] = callback
|
||||
return { result: 'Success', uuid: uid }
|
||||
}
|
||||
|
||||
async getNotificationLog() : Promise<Notification[]>{
|
||||
try{
|
||||
return await this.admin.knex.select('*').from('notifications')
|
||||
}catch(e){
|
||||
logger.error(e)
|
||||
throw e
|
||||
}
|
||||
}
|
||||
|
||||
async unsubscribeNotifications(uid:string) : Promise<SuccessResponse | ErrorResponse>{
|
||||
if(!this.subscriptions[uid]) return { result: 'Error', message: "Unknown subscription" }
|
||||
delete this.subscriptions[uid]
|
||||
return { result: 'Success' }
|
||||
}
|
||||
|
||||
async pushNotification(notification: Notification){
|
||||
if(!notification.time) notification.time = Date.now()
|
||||
logger.debug("inserting into notifications", notification)
|
||||
try{
|
||||
await this.admin.knex('notifications').insert(notification)
|
||||
}catch(e){
|
||||
logger.error(e)
|
||||
throw e
|
||||
}
|
||||
|
||||
Object.values(this.subscriptions).forEach(callback => {
|
||||
callback(notification)
|
||||
})
|
||||
}
|
||||
|
||||
exportRPCs(){
|
||||
return [{
|
||||
name: 'getNotificationLog' as 'getNotificationLog',
|
||||
call: async () => await this.getNotificationLog()
|
||||
},{
|
||||
name: 'pushNotification' as 'pushNotification',
|
||||
call: async (notification: Notification) => { return await this.pushNotification(notification) }
|
||||
},{
|
||||
name: 'subscribeNotificaitons' as 'subscribeNotifications',
|
||||
hook: async (callback: Function) => {
|
||||
return await this.subscribeNotifications(callback)
|
||||
}
|
||||
}]
|
||||
}
|
||||
|
||||
getTableDefinitions(): TableDefiniton[]{
|
||||
return [{
|
||||
name: 'notifications',
|
||||
tableBuilder: (table) => {
|
||||
table.increments('ID').primary();
|
||||
table.string('severity');
|
||||
table.string('topic');
|
||||
table.string('message');
|
||||
table.timestamp('time');
|
||||
}
|
||||
}]
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,107 @@
|
||||
import { TableDefinitionExporter } from "../../Types/Interfaces";
|
||||
import { TableDefiniton, _Rank } from "../../Types/Types";
|
||||
import { FrontworkAdmin } from "../../Admin/Admin";
|
||||
import { T1 } from "../../Types/Items";
|
||||
import { FrontworkComponent } from "../../Types/FrontworkComponent";
|
||||
import { RPC } from "rpclibrary";
|
||||
const fetch = require('node-fetch')
|
||||
const xml2js = require('xml2js');
|
||||
const parser = new xml2js.Parser(/* options */);
|
||||
|
||||
|
||||
export type ItemManagerFeatureIfc = any
|
||||
|
||||
export type Item = {
|
||||
id?:number
|
||||
name:string
|
||||
iconname:string
|
||||
url:string
|
||||
quality:string
|
||||
hidden:boolean
|
||||
}
|
||||
|
||||
export class ItemManager
|
||||
implements FrontworkComponent<ItemManagerFeatureIfc>, TableDefinitionExporter{
|
||||
|
||||
admin:FrontworkAdmin
|
||||
name = "ItemManager";
|
||||
|
||||
exportRPCs(): RPC<any, any>[]{
|
||||
return [{
|
||||
name: 'getItems',
|
||||
call: async () => await this.getItems()
|
||||
},{
|
||||
name: 'getItem',
|
||||
call: async (name:string) => await this.getItem(name)
|
||||
}]
|
||||
}
|
||||
|
||||
exportRPCFeatures() {
|
||||
return []
|
||||
}
|
||||
|
||||
getItems = async () :Promise<Item[]> => await this.admin.knex.select('*').from('items')
|
||||
|
||||
getItem = async (name:string):Promise<Item> => {
|
||||
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>{
|
||||
name: 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]._,
|
||||
}
|
||||
}catch (e){
|
||||
console.log(name)
|
||||
throw e
|
||||
}
|
||||
}
|
||||
|
||||
getTableDefinitions(): TableDefiniton[] {
|
||||
return [
|
||||
{
|
||||
name: 'reservations',
|
||||
tableBuilder: (table) => {
|
||||
table.integer("user_id").primary()
|
||||
table.foreign("user_id").references("id").inTable('users')
|
||||
table.integer("item_id").primary()
|
||||
table.foreign("item_id").references("id").inTable('items')
|
||||
table.integer("raid_id").primary()
|
||||
table.foreign("raid_id").references("id").inTable('raids')
|
||||
}
|
||||
},{
|
||||
name: 'items',
|
||||
tableBuilder: (table) => {
|
||||
table.increments("id").primary()
|
||||
table.string('name').unique().notNullable()
|
||||
table.string('iconname').notNullable()
|
||||
table.string('url').notNullable()
|
||||
table.string('quality').defaultTo('Epic').notNullable()
|
||||
table.boolean('hidden').defaultTo(false).notNullable()
|
||||
}
|
||||
}]
|
||||
}
|
||||
|
||||
countItems = async() :Promise<number> => {
|
||||
const count = await this.admin.knex('items').count('*');
|
||||
return <number>count[0]['count(*)']
|
||||
}
|
||||
|
||||
initialize = async() => {
|
||||
const allItems = [...T1]
|
||||
const countCache = await this.countItems()
|
||||
if(countCache != allItems.length){
|
||||
const items:Item[] = await Promise.all(allItems.map(async (i) => this.getItem(i)))
|
||||
try{
|
||||
await this.admin
|
||||
.knex('items')
|
||||
.insert(items)
|
||||
}catch(e){
|
||||
console.error(e)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,196 @@
|
||||
import { RPCServer } from "rpclibrary";
|
||||
import { TableDefiniton, AnyRPCExporter, User, RPCPermission, _Rank, Token, Auth } from "../../Types/Types";
|
||||
import { FrontworkAdmin } from "../../Admin/Admin";
|
||||
import { PrivilegedRPCExporter } from "../../Types/PrivilegedRPCExporter";
|
||||
import { FrontworkComponent } from "../../Types/FrontworkComponent";
|
||||
const uuid = require('uuid/v4')
|
||||
|
||||
|
||||
export class LoginManager
|
||||
implements FrontworkComponent{
|
||||
name = "Authenticator" as "Authenticator";
|
||||
admin:FrontworkAdmin
|
||||
|
||||
constructor(private exporters: PrivilegedRPCExporter[]){}
|
||||
|
||||
exportRPCs() {
|
||||
return [
|
||||
{
|
||||
name: 'login' as 'login',
|
||||
call: async (username:string, pwHash:string) => await this.login(username, pwHash)
|
||||
},{
|
||||
name: 'authenticate' as 'authenticate',
|
||||
call: async (tokenValue:string | Token) => await this.authenticate(tokenValue)
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
onSetAdmin(admin:FrontworkAdmin){
|
||||
this.exporters.forEach(e => e['admin'] = admin)
|
||||
}
|
||||
|
||||
exportRPCFeatures() {
|
||||
return [{
|
||||
name: 'createUser' as 'createUser',
|
||||
exportRPCs: () => [{
|
||||
name: 'createUser' as 'createUser',
|
||||
call: async (user:User) => {
|
||||
return await this.createUser(user)
|
||||
}
|
||||
}]
|
||||
},{
|
||||
name: 'modifyPermissions' as 'modifyPermissions',
|
||||
exportRPCs: () => [{
|
||||
name: 'getPermissions' as 'getPermissions',
|
||||
call: async () => await this.getPermissions()
|
||||
},{
|
||||
name: 'setPermission' as 'setPermission',
|
||||
call: async (perm: RPCPermission) => await this.setPermission(perm)
|
||||
}]
|
||||
}]
|
||||
}
|
||||
|
||||
getTableDefinitions(): TableDefiniton[] {
|
||||
return [
|
||||
{
|
||||
name: 'users',
|
||||
tableBuilder: (table) => {
|
||||
table.increments("id").primary()
|
||||
table.string("name").notNullable().unique()
|
||||
table.string("pwhash").notNullable()
|
||||
table.string("rank").notNullable()
|
||||
table.string("class").notNullable()
|
||||
table.string("email").nullable().unique()
|
||||
}
|
||||
},{
|
||||
name: 'rpcpermissions',
|
||||
tableBuilder: (table) => {
|
||||
table.string("rpcName").primary().notNullable()
|
||||
table.boolean("ADMIN").defaultTo(true).notNullable()
|
||||
_Rank.forEach(r => table.boolean(r).defaultTo(false).notNullable())
|
||||
}
|
||||
},{
|
||||
name: 'tokens',
|
||||
tableBuilder: (table) => {
|
||||
table.string('value').primary()
|
||||
table.integer('user_id').notNullable()
|
||||
table.foreign('user_id').references('users')
|
||||
table.dateTime('created').defaultTo(this.admin.knex.fn.now())
|
||||
}
|
||||
}
|
||||
,...this.exporters.flatMap(exp => exp['getTableDefinitions']?exp['getTableDefinitions']():undefined)]
|
||||
}
|
||||
|
||||
async initialize(){
|
||||
await Promise.all(
|
||||
[this, ...this.exporters].flatMap(exp => exp.exportRPCFeatures().map(async (rpc) => {
|
||||
try{
|
||||
await this.admin.knex.insert({ rpcname: rpc.name }).into('rpcpermissions')
|
||||
}catch(e){}
|
||||
})))
|
||||
|
||||
await Promise.all(this.exporters.map(ex => ex['initialize']?ex['initialize']():undefined))
|
||||
}
|
||||
|
||||
async setPermission(permission: RPCPermission){
|
||||
await this.admin.knex('rpcpermissions')
|
||||
.where('rpcname', '=', permission.name)
|
||||
.update(permission)
|
||||
}
|
||||
|
||||
getPermissions = async () : Promise<RPCPermission[]> => {
|
||||
return await this.admin.knex.select('*').from('rpcpermissions')
|
||||
}
|
||||
|
||||
getRPCForUser = async (user:User): Promise<AnyRPCExporter[]> => {
|
||||
return [...this.exportRPCFeatures(), ...this.exporters.flatMap((exp) => exp.exportRPCFeatures())]
|
||||
}
|
||||
|
||||
createUser = async(user:User): Promise<User> => {
|
||||
await this.admin.knex('users')
|
||||
.insert(user)
|
||||
|
||||
const users = await this.admin.knex
|
||||
.select("*")
|
||||
.from('users')
|
||||
.where(user)
|
||||
return users[0]
|
||||
}
|
||||
|
||||
login = async(username:string, pwHash:string) : Promise<Token> => {
|
||||
const res:User[] = await this.admin.knex
|
||||
.select("*")
|
||||
.from('users')
|
||||
.where({ name: username })
|
||||
|
||||
if(res.length > 0 && pwHash === res[0].pwhash){
|
||||
return await this.createToken(res[0])
|
||||
}
|
||||
|
||||
throw new Error('login failed')
|
||||
}
|
||||
|
||||
authenticate = async(tokenValue: string | Token) : Promise<Auth> => {
|
||||
if(typeof tokenValue !== 'string') tokenValue = tokenValue.value
|
||||
|
||||
const res : User[] = await this.admin.knex
|
||||
.select('users.id', 'name', 'class', 'rank', 'email')
|
||||
.from('tokens')
|
||||
.join('users', function(){
|
||||
this.on('users.id', '=', 'tokens.user_id')
|
||||
})
|
||||
.where({ value: tokenValue})
|
||||
|
||||
if(res.length === 0)
|
||||
throw new Error('authentication failed')
|
||||
|
||||
const allowedRPCs = await this.getRPCForUser(res[0])
|
||||
const randomPort = 20000 + Math.floor(Math.random() * 10000)
|
||||
while(true){
|
||||
try{
|
||||
let commSock = new RPCServer(randomPort, allowedRPCs, {
|
||||
closeHandler: () => {
|
||||
console.log(res[0].name, 'disconnected')
|
||||
commSock.destroy()
|
||||
},
|
||||
connectionHandler: () => {
|
||||
console.log(res[0].name, 'connected')
|
||||
cancelTimeout()
|
||||
},
|
||||
sesame: tokenValue
|
||||
})
|
||||
const timeout = setTimeout(() => {
|
||||
console.log(res[0].name, 'timeout')
|
||||
commSock.destroy()
|
||||
}, 10000)
|
||||
const cancelTimeout = () => { clearTimeout(timeout) }
|
||||
break;
|
||||
}catch(e){
|
||||
//retry
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
port: randomPort,
|
||||
user: res[0],
|
||||
token: {
|
||||
value: tokenValue,
|
||||
user_id: res[0].id!
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
createToken = async(user:User): Promise<Token> => {
|
||||
const old = await this.admin.knex.select('*').from('tokens').where({user_id: user.id})
|
||||
if(old.length === 0){
|
||||
const token:Token = {
|
||||
value: uuid(),
|
||||
user_id: user.id!
|
||||
}
|
||||
await this.admin.knex('tokens').insert(token)
|
||||
return token
|
||||
}else{
|
||||
return old[0]
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,167 @@
|
||||
import { RPCExporter } from "rpclibrary";
|
||||
import { Git } from "upgiter"
|
||||
import { FolderStatus } from "upgiter/js/src/Types";
|
||||
import { Plugin } from "../Types/Plugin";
|
||||
import { FrontworkAdmin } from "../Admin/Admin";
|
||||
|
||||
class PluginLoader {
|
||||
private runningPlugins: Plugin[] = []
|
||||
private pluginUpdaters:{[name in string]:Git.Updater} = {}
|
||||
|
||||
constructor(private admin:FrontworkAdmin){}
|
||||
|
||||
async selfUpdate(force:boolean = false){
|
||||
const updater = new Git.Updater({
|
||||
schema: 'https',
|
||||
localPath: './dist',
|
||||
remoteHost: 'www.versioncontrol.me',
|
||||
remotePath: 'frontwork-distribution',
|
||||
repoName: 'admin'
|
||||
})
|
||||
|
||||
let status = await updater.getStatus()
|
||||
if(force || !status.remote || !status.remote.includes("fb-dist/admin") || !status.exists || status.empty || !status.currentTag){
|
||||
//logger.warn("Cloning fb-dist/admin into ./dist ..."+(force?" USING FORCE!":""))
|
||||
status = await updater.cloneRepo(force)
|
||||
const installer = eval("require")("./Installer").installAdmin
|
||||
installer(this.getPlugins())
|
||||
}
|
||||
return status
|
||||
}
|
||||
|
||||
async installPlugin(name: string, force:boolean = false):Promise<FolderStatus>{
|
||||
//logger.warn("Cloning fb-dist/"+name+".git into ./plugins/"+name+" ..."+(force?" USING FORCE!":""))
|
||||
this.pluginUpdaters[name] = new Git.Updater({
|
||||
schema: 'https',
|
||||
localPath: './plugins/'+name,
|
||||
remoteHost: 'www.versioncontrol.me',
|
||||
remotePath: 'frontblock-distribution',
|
||||
repoName: name
|
||||
})
|
||||
const status = await this.pluginUpdaters[name].cloneRepo(force)
|
||||
return status
|
||||
}
|
||||
|
||||
async startPlugin(name:string):Promise<boolean>{
|
||||
if(!this.pluginUpdaters[name]) return false
|
||||
const status = await this.pluginUpdaters[name].getStatus()
|
||||
if(!status.exists || status.empty || !status.tags || status.tags.length === 0){
|
||||
if(status.currentTag && !status.latestTag){
|
||||
//git glitches sometimes if you check immediately after clone
|
||||
//logger.warn("re-fetching tag for "+name+"...")
|
||||
return await this.startPlugin(name)
|
||||
}
|
||||
//logger.error("Bad repo status", name, status)
|
||||
return false
|
||||
}
|
||||
|
||||
/* if(this.loadedPlugins[name]){
|
||||
logger.error("Plugin", name, "is already started")
|
||||
return false
|
||||
}
|
||||
*/
|
||||
|
||||
let evalstr = "../plugins/"+name+"/Plugin"
|
||||
const pluginClass = await eval('require')(evalstr)
|
||||
const pluginObj = new pluginClass.default(this.admin)
|
||||
try{
|
||||
if(pluginObj.start)
|
||||
await pluginObj.start()
|
||||
//this.pushNotification({message: "Started plugin "+pluginObj.name, severity: "Important", topic:"admin"})
|
||||
this.addPlugin(pluginObj)
|
||||
return true
|
||||
}catch(e){
|
||||
//logger.error(e)
|
||||
//this.pushNotification({message: "Start of plugin "+pluginObj.name+" failed because of "+String(e), severity: "Error", topic:"admin"})
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
async updatePlugin(name:string):Promise<boolean>{
|
||||
if(!this.pluginUpdaters[name]) return false
|
||||
const status = await this.pluginUpdaters[name].getStatus()
|
||||
if(!status.exists || status.empty || !status.tags || status.tags.length === 0){
|
||||
//logger.error("Bad repo status", name, status)
|
||||
return false
|
||||
}
|
||||
if(status.currentTag == status.latestTag){
|
||||
//logger.warn(name, "already at latest tag")
|
||||
return false
|
||||
}
|
||||
|
||||
/*
|
||||
if(this.loadedPlugins[name]){
|
||||
logger.error("Plugin", name, "is running. Stop it first")
|
||||
return false
|
||||
}
|
||||
*/
|
||||
|
||||
this.pluginUpdaters[name].checkoutTag(status.latestTag!)
|
||||
return true
|
||||
}
|
||||
|
||||
async setPluginVersion(pluginName:string, tag:string):Promise<FolderStatus>{
|
||||
const status = await this.pluginUpdaters[pluginName].getStatus()
|
||||
if(!status.exists || !status.tags || status.tags.length === 0 || !status.tags.includes(tag)){
|
||||
//logger.error("Bad repo status", pluginName, status)
|
||||
return status
|
||||
}
|
||||
|
||||
return await this.pluginUpdaters[pluginName].checkoutTag(tag)
|
||||
}
|
||||
|
||||
async addPlugin(plugin: Plugin){
|
||||
this.runningPlugins.push(plugin)
|
||||
if(plugin.getTableDefinitions().length != 0)
|
||||
await this.admin.makeKnex()
|
||||
}
|
||||
|
||||
removePlugin(plugin: Plugin){
|
||||
this.runningPlugins = this.runningPlugins.filter(p => p.name !== plugin.name)
|
||||
}
|
||||
|
||||
getPlugins():Plugin[]{
|
||||
return [...this.runningPlugins]
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
export type PluginLoaderIfc = {
|
||||
PluginLoader: {
|
||||
installPlugin: (name:string, force:boolean) => Promise<FolderStatus>
|
||||
startPlugin: (name:string) => Promise<boolean>
|
||||
updatePlugin: (name:string) => Promise<boolean>
|
||||
setPluginVersion: (name:string, tag:string) => Promise<FolderStatus>
|
||||
getLoadedPluginNames: () => Promise<String[]>
|
||||
selfUpdate: (force:boolean) => Promise<FolderStatus>
|
||||
}
|
||||
}
|
||||
|
||||
export class RPCPluginLoader
|
||||
extends PluginLoader
|
||||
implements RPCExporter<PluginLoaderIfc, "PluginLoader">{
|
||||
|
||||
name = "PluginLoader" as "PluginLoader";
|
||||
|
||||
exportRPCs(){
|
||||
return [{
|
||||
name: "installPlugin" as "installPlugin",
|
||||
call: async (name:string, force = false) => {return await this.installPlugin(name, force)},
|
||||
},{
|
||||
name: "startPlugin" as "startPlugin",
|
||||
call: async (name:string) => {return await this.startPlugin(name)},
|
||||
},{
|
||||
name: "updatePlugin" as "updatePlugin",
|
||||
call: async (name:string) => {return await this.updatePlugin(name)},
|
||||
},{
|
||||
name: "setPluginVersion" as "setPluginVersion",
|
||||
call: async (name:string, tag:string) => {return await this.setPluginVersion(name, tag)},
|
||||
},{
|
||||
name: "getLoadedPluginNames" as "getLoadedPluginNames",
|
||||
call: async () => {return this.getPlugins().map(p => p.name)},
|
||||
},{
|
||||
name: "selfUpdate" as "selfUpdate",
|
||||
call: async (force: boolean) => {return await this.selfUpdate(force)},
|
||||
}]
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,42 @@
|
||||
import { ConfigLoader } from 'loadson'
|
||||
import { RPCExporter } from 'rpclibrary'
|
||||
|
||||
export type ConfigLoaderIfc<ConfT> = {
|
||||
Config : {
|
||||
getConfig: () => ConfT
|
||||
resetConfig: () => ConfT
|
||||
setConfig: (conf:ConfT) => ConfT
|
||||
setConfigKey: (key:string, value:any) => ConfT
|
||||
deleteConfigKey: (key:string) => ConfT
|
||||
getConfigKey: (key:string) => any
|
||||
}
|
||||
}
|
||||
|
||||
export class RPCConfigLoader<ConfT>
|
||||
extends ConfigLoader<ConfT>
|
||||
implements RPCExporter<ConfigLoaderIfc<ConfT>, "Config">{
|
||||
|
||||
name = "Config" as "Config"
|
||||
|
||||
exportRPCs() {
|
||||
return [{
|
||||
name: "getConfig" as "getConfig",
|
||||
call: () => { return this.getConfig() }
|
||||
},{
|
||||
name: "resetConfig" as "resetConfig",
|
||||
call: () => { return this.resetConfig() }
|
||||
},{
|
||||
name: "setConfig" as "setConfig",
|
||||
call: (conf:ConfT) => { return this.setConfig(conf) }
|
||||
},{
|
||||
name: "setConfigKey" as "setConfigKey",
|
||||
call: (key:string, value:any) => { return this.setConfigKey(key, value) }
|
||||
},{
|
||||
name: "deleteConfigKey" as "deleteConfigKey",
|
||||
call: (key:string) => { return this.deleteConfigKey(key) }
|
||||
},{
|
||||
name: "getConfigKey" as "getConfigKey",
|
||||
call: (key:string) => { return this.getConfigKey(key) }
|
||||
}]
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,95 @@
|
||||
import { TableDefiniton, User, _Rank, Raid, Signup, RaidManagerFeatureIfc } from "../../Types/Types";
|
||||
import { FrontworkAdmin } from "../../Admin/Admin";
|
||||
import { FrontworkComponent } from "../../Types/FrontworkComponent";
|
||||
|
||||
|
||||
export class RaidManager
|
||||
implements FrontworkComponent<RaidManagerFeatureIfc>{
|
||||
name = "RaidManager";
|
||||
admin: FrontworkAdmin
|
||||
|
||||
exportRPCs = () => []
|
||||
|
||||
exportRPCFeatures() {
|
||||
return [{
|
||||
name: 'manageRaid' as 'manageRaid',
|
||||
exportRPCs: () => [{
|
||||
name: 'createRaid' as 'createRaid',
|
||||
call: async (raid:Raid) => await this.createRaid(raid)
|
||||
},{
|
||||
name: 'addSignup' as 'addSignup',
|
||||
call: async(signup: Signup) => await this.addSignup(signup)
|
||||
},{
|
||||
name: 'removeSignup' as 'removeSignup',
|
||||
call: async(signup: Signup) => await this.removeSignup(signup)
|
||||
}]
|
||||
},{
|
||||
name: 'signup' as 'signup',
|
||||
exportRPCs: () => [{
|
||||
name: 'getRaids' as 'getRaids',
|
||||
call: async () => await this.getRaids()
|
||||
},{
|
||||
name: 'getSingups' as 'getSingups',
|
||||
call: async(raid: Raid) => await this.getSignups(raid)
|
||||
},{
|
||||
name: 'sign' as 'sign',
|
||||
call: async(user:User, raid:Raid) => await this.sign(user, raid)
|
||||
}]
|
||||
},]
|
||||
}
|
||||
|
||||
getTableDefinitions(): TableDefiniton[] {
|
||||
return [
|
||||
{
|
||||
name: 'raids',
|
||||
tableBuilder: (table) => {
|
||||
table.increments('id').primary()
|
||||
table.dateTime('start').notNullable()
|
||||
table.string('description').notNullable()
|
||||
table.string('title').notNullable()
|
||||
table.integer('minrank').notNullable()
|
||||
}
|
||||
},{
|
||||
name: 'signups',
|
||||
tableBuilder: (table) => {
|
||||
table.integer('raid_id').primary()
|
||||
table.foreign('raid_id').references('id').inTable('raids')
|
||||
table.integer('user_id').primary()
|
||||
table.foreign('user_id').references('id').inTable('users')
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
createRaid = async (raid:Raid) => await this.admin
|
||||
.knex('raids')
|
||||
.insert(raid)
|
||||
|
||||
addSignup = async (signup: Signup) => await this.admin
|
||||
.knex('signups')
|
||||
.insert(signup)
|
||||
|
||||
removeSignup = async (signup: Signup) => await this.admin
|
||||
.knex('signups')
|
||||
.where({
|
||||
raid_id: signup.raid_id,
|
||||
user_id: signup.user_id
|
||||
})
|
||||
.delete()
|
||||
|
||||
getRaids = async () => await this.admin.knex
|
||||
.select('*')
|
||||
.from('raids')
|
||||
|
||||
getSignups = async (raid:Raid) => await this.admin.knex
|
||||
.select('*')
|
||||
.from('signups')
|
||||
.where('raid_id', '=', raid.id!)
|
||||
|
||||
sign = async (user:User, raid:Raid) => await this.admin
|
||||
.knex('signups')
|
||||
.insert({
|
||||
raid_id: raid.id!,
|
||||
user_id: user.id!
|
||||
})
|
||||
}
|
||||
Reference in New Issue
Block a user