From 49d6402365c090a7c389f65bd674c8353828dd4f Mon Sep 17 00:00:00 2001 From: Trivernis Date: Sun, 7 Apr 2019 16:58:57 +0200 Subject: [PATCH] gitflow-feature-stash: api-rewrite --- lib/guilds/index.js | 43 ++++++++++++--- lib/web/graphql-schema.js | 101 +++++++++++++++++++++++++++++++--- lib/web/index.js | 107 ++++++++++++++++++++++--------------- lib/web/schema.graphqls | 9 +++- web/api/graphql/schema.gql | 10 ++++ 5 files changed, 213 insertions(+), 57 deletions(-) diff --git a/lib/guilds/index.js b/lib/guilds/index.js index 9b55a78..79ff9f3 100644 --- a/lib/guilds/index.js +++ b/lib/guilds/index.js @@ -48,24 +48,47 @@ class GuildDatabase extends dblib.Database { * Returns the value of the column where the key has the value keyvalue * @param table {String} - the table name * @param column {String} - the name of the column - * @param keyname {String} - the name of the key + * @param keycolumn {String} - the name of the key * @param keyvalue {*} - the value of the key * @returns {Promise<*>} */ - async getSingleValue(table, column, keyname, keyvalue) { - let result = await this.get(this.sql.select(table, false, column, + async getValueByKey(table, column, keycolumn, keyvalue) { + let result = await this.get(this.sql.select(table, false, valuecolumn, this.sql.where(this.sql.parameter(1), '=', this.sql.parameter(2))), - [keyname, keyvalue]); + [keycolumn, keyvalue]); if (result) return result[column]; else return null; } + /** + * Sets a value column to a value with a key column. + * @param table + * @param valuecolumn + * @param value + * @param keycolumn + * @param keyvalue + * @returns {Promise} + */ + async setValueForKey(table, valuecolumn, value, keycolumn, keyvalue) { + let row = await this.getValueByKey(table, valuecolumn, keycolumn, keyvalue); + let newRow = {}; + newRow[valuecolumn] = this.sql.parameter(1); + if (!row || Number(row.count) === 0) { + newRow[keycolumn] = this.sql.parameter(2); + await this.run(this.sql.insert(table, newRow), + [value, keyvalue]); + } else { + await this.run(this.sql.update(table, {value: this.sql.parameter(1)}, + this.sql.where(this.sql.parameter(2), '=', this.sql.parameter(3))), [value, keycolumn, keyvalue]); + } + } + /** * Returns either the whole table or a limited version - * @param tablename - * @param limit + * @param tablename {String} - the name of the table + * @param [limit] {Number} - the limit of rows to get * @returns {Promise} */ async getTableContent(tablename, limit) { @@ -77,6 +100,14 @@ class GuildDatabase extends dblib.Database { return await this.all(this.sql.select(tablename, false, ['*'], [], [])); } + /** + * Returns all saved media entries. + * @returns {Promise} + */ + async getMediaEntries() { + return this.getTableContent('savedmedia'); + } + /** * Get the value of a setting * @param name diff --git a/lib/web/graphql-schema.js b/lib/web/graphql-schema.js index 95e484e..4d2e128 100644 --- a/lib/web/graphql-schema.js +++ b/lib/web/graphql-schema.js @@ -1,6 +1,31 @@ const graphql = require('graphql'), + md5 = require('js-md5'), fs = require('fs'); +/** + * generating an id + * @param valArr + * @returns {*} + */ +function generateID(valArr) { + let b64 = Buffer.from(valArr.map(x => { + if (x) + return x.toString(); + else + return 'null'; + }).join('_')).toString('base64'); + return md5(b64); +} + +/** + * generating an unique id + * @param input + * @returns {*} + */ +function generateUUID(input) { + return generateID([input, (new Date()).getMilliseconds()]) + Date.now(); +} + class BotGraphql { constructor(bot) { this.schema = graphql.buildSchema(fs.readFileSync('.lib/web/schema.graphqls', 'utf-8')); @@ -38,7 +63,7 @@ class Edge { /** * contructor. * @param node {Object} - the node belonging to the edge - * @param edgeProps {Object} - additional properties of the edge + * @param [edgeProps] {Object} - additional properties of the edge */ constructor(node, edgeProps) { this.node = node; @@ -102,6 +127,18 @@ class Paginator { } } +class User { + constructor(user) { + + } +} + +class GuildMember { + constructor(guildMember) { + + } +} + class MusicPlayer { constructor(guildHandler) { @@ -110,7 +147,15 @@ class MusicPlayer { class Guild { constructor(guild) { + this._guild = guild; + this.name = guild.name; + this.discordId = guild.id; + this.id = this.discordId + generateID(['guild', this.discordId, this.name]); + this.owner = new GuildMember(guild.owner); + this.icon = guild.iconURL; + this.memberPaginator = new Paginator(); + this.rolePaginator = new Paginator(); } } @@ -118,23 +163,63 @@ class Client { constructor(bot) { this._bot = bot; this._client = bot.client; - this.guildPaginator = new Paginator() + this.guildPaginator = new Paginator(this._getGuildEdges(), 10); + this.user = new User(this._client.user); } _getGuildEdges() { - let guildHandlerPaginator = Array.from(this._client.guilds.values()).map(x => new Edge( - - )); return Array.from(this._client.guilds.values()).map(x => new Edge( new Guild(x), { musicPlayer: new MusicPlayer(this._bot.getGuildHandler(x)), - new Connection( - bot.getGuildHandler(x).savedMedia - ) + savedMedia: (args) => new Paginator( + this._bot.getGuildHandler(x).db.getMediaEntries().map(x => new Edge(x)), + 10 + ).getPage(args.page || 1, args.perPage) } )); } + + guilds(args) { + if (args.id) { + let guild = Array.from(this._client.guilds.values()).find(x => x.id === args.id); + let gh = this._bot.getGuildHandler(guild); + let edge = new Edge( + new Guild(guild), + { + musicPlayer: new MusicPlayer(gh), + savedMedia: (args) => new Paginator( + gh.db.getMediaEntries().map(x => new Edge(x)), + 10 + ).getPage(args.page || 1, args.perPage) + } + ); + return new Connection( + [edge], + new PageInfo(1, 1, 1, 1, false) + ); + } else { + let page = args.page || 1; + return this.guildPaginator.getPage(page, args.perPage); + } + } + + get voiceConnectionCount() { + return this._client.voiceConnections.size; + } + + get ping() { + return this._client.ping; + } + + get status() { + return this._client.status; + } + + get uptime() { + return this._client.uptime; + } + } class Query { diff --git a/lib/web/index.js b/lib/web/index.js index ed3b9ca..3730b76 100644 --- a/lib/web/index.js +++ b/lib/web/index.js @@ -51,7 +51,7 @@ exports.WebServer = class { filter: (req, res) => { if (req.headers['x-no-compression']) return false; - else + else return compression.filter(req, res); } @@ -81,7 +81,7 @@ exports.WebServer = class { this.app.use((req, res, next) => { if (req.session.user) next(); - else + else res.render('login'); }); this.app.get('/', (req, res) => { @@ -89,7 +89,10 @@ exports.WebServer = class { }); this.app.use('/graphql', graphqlHTTP({ schema: this.schema, - rootValue: this.root, + rootValue: Object.assign({ + query: this.query, + mutation: this.mutation + }, this.query), graphiql: config.webinterface.graphiql || false })); } @@ -163,15 +166,15 @@ exports.WebServer = class { new dblib.Column('token', sql.types.getVarchar(255), [sql.constraints.unique, sql.constraints.notNull]), new dblib.Column('scope', sql.types.integer, [sql.constraints.notNull, sql.default(0)]) ])); - this.root = { + this.query = { client: { - guilds: async (args) => { + async guilds(args) { let dcGuilds = objects.client.guilds.values(); if (args.id) return [(await Promise.all(Array.from(dcGuilds) .map(async (x) => new Guild(x, await objects.getGuildHandler(x))))) .find(x => (x.id === args.id))]; - else + else try { return await Promise.all(Array.from(dcGuilds) .slice(args.offset, args.offset + args.first) @@ -182,22 +185,22 @@ exports.WebServer = class { } }, - guildCount: () => { + guildCount() { return Array.from(objects.client.guilds.values()).length; }, - user: () => { + user() { return new User(objects.client.user); }, - ping: () => { + ping() { return objects.client.ping; }, - status: () => { + status() { return objects.client.status; }, - uptime: () => { + uptime() { return objects.client.uptime; }, - voiceConnectionCount: () => { + voiceConnectionCount() { let dcGuilds = Array.from(objects.client.guilds.values()); return dcGuilds.filter((x) => { let gh = objects.guildHandlers[x.id]; @@ -206,7 +209,7 @@ exports.WebServer = class { return gh.musicPlayer.playing; else return false; - else + else return false; }).length; @@ -214,12 +217,12 @@ exports.WebServer = class { }, prefix: objects.prefix, presences: objects.presences, - config: () => { + config() { let newConfig = JSON.parse(JSON.stringify(config)); delete newConfig.api; return JSON.stringify(newConfig, null, ' '); }, - logs: (args) => { + logs(args) { return new Promise((resolve) => { let logEntries = []; let lineReader = require('readline').createInterface({ @@ -238,7 +241,7 @@ exports.WebServer = class { if (args.first) logEntries = logEntries.slice(args.offset, args.offset + args.first); - else + else logEntries = logEntries.slice(logEntries.length - args.last); resolve(logEntries); @@ -246,6 +249,19 @@ exports.WebServer = class { }); } }; + this.mutation = { + togglePause(args) { + if (args.guildId) { + let guildId = resolveId(args.guildId).replace('Guild', ''); + let gh = objects.guildHandlers[guildId]; + + if (gh.musicPlayer.paused) + gh.musicPlayer.resume(); + else + gh.musicPlayer.pause(); + } + } + }; } }; @@ -255,13 +271,20 @@ exports.WebServer = class { * @returns {*} */ function generateID(valArr) { - let b64 = Buffer.from(valArr.map(x => { + return Buffer.from(valArr.map(x => { if (x) return x.toString(); else return 'null'; }).join('_')).toString('base64'); - return md5(b64); +} + +/** + * resolves an id string + * @param id {String} + */ +function resolveId(id) { + return Buffer.from(id, 'base64'); } /** @@ -282,22 +305,6 @@ class MusicPlayer { this.quality = musicPlayer.quality; } - queue(args) { - let queue = this.musicPlayer.queue.map((x) => { - return { - id: generateID(['Media', x.url]), - name: x.title, - url: x.url, - thumbnail: utils.YouTube.getVideoThumbnailUrlFromUrl(x.url) - }; - }); - if (args.id) - return [queue.find(x => (x.id === args.id))]; - else - return queue.slice(args.offset, args.offset + args.first); - - } - get playing() { return this.musicPlayer.playing; } @@ -307,7 +314,7 @@ class MusicPlayer { } get paused() { - return this.musicPlayer.disp? this.musicPlayer.disp.paused : false; + return this.musicPlayer.disp ? this.musicPlayer.disp.paused : false; } get queueCount() { @@ -339,6 +346,22 @@ class MusicPlayer { get voiceChannel() { return this.musicPlayer.voiceChannel.name; } + + queue(args) { + let queue = this.musicPlayer.queue.map((x) => { + return { + id: generateID(['Media', x.url]), + name: x.title, + url: x.url, + thumbnail: utils.YouTube.getVideoThumbnailUrlFromUrl(x.url) + }; + }); + if (args.id) + return [queue.find(x => (x.id === args.id))]; + else + return queue.slice(args.offset, args.offset + args.first); + + } } /** @@ -382,16 +405,16 @@ class Guild { let result = await this.querySaved(); if (args.id) return [result.find(x => (x.id === args.id))]; - else if (args.name) + else if (args.name) return [result.find(x => (x.name === args.name))]; - else + else return result.slice(args.offset, args.offset + args.first); } roles(args) { if (args.id) return [this.prRoles.find(x => (x.id === args.id))]; - else + else return this.prRoles.slice(args.offset, args.offset + args.first); } @@ -399,7 +422,7 @@ class Guild { members(args) { if (args.id) return [this.prMembers.find(x => (x.id === args.id))]; - else + else return this.prMembers.slice(args.offset, args.offset + args.first); } @@ -421,7 +444,7 @@ class Role { members(args) { if (args.id) return [this.prMembers.find(x => (x.id === args.id))]; - else + else return this.prMembers.slice(args.offset, args.offset + args.first); } @@ -444,7 +467,7 @@ class GuildMember { roles(args) { if (args.id) return [this.prRoles.find(x => (x.id === args.id))]; - else + else return this.prRoles.slice(args.offset, args.offset + args.first); } @@ -463,7 +486,7 @@ class User { this.tag = discordUser.tag; this.tag = discordUser.tag; this.presence = { - game: discordUser.presence.game? discordUser.presence.game.name : null, + game: discordUser.presence.game ? discordUser.presence.game.name : null, status: discordUser.presence.status }; } diff --git a/lib/web/schema.graphqls b/lib/web/schema.graphqls index 437dc31..8152910 100644 --- a/lib/web/schema.graphqls +++ b/lib/web/schema.graphqls @@ -292,7 +292,14 @@ type GuildEdge { musicPlayer: MusicPlayer # the saved media of the guild - savedMedia: mediaEntryConnection + # + # Arguments + # page: the number of the page + # perPage: the number of entries per page + savedMedia ( + page: Int, + perPage: Int + ): mediaEntryConnection } type GuildConnection { diff --git a/web/api/graphql/schema.gql b/web/api/graphql/schema.gql index bd14138..7866ed0 100644 --- a/web/api/graphql/schema.gql +++ b/web/api/graphql/schema.gql @@ -82,3 +82,13 @@ type Query { prefix: String logs(first: Int, offset: Int = 0, id: String, last: Int = 10, level: String): [LogEntry] } + +type Mutation { + togglePause(guildId: ID!): MusicPlayer + toggleRepeat(guildId: ID!): MusicPlayer + skipSong(guildId: ID!): MusicPlayer + addMediaToQueue( + guildId: ID!, + url: String! + ): MusicPlayer +}