From 39e35185914b3803af0c4389096b3ea5f3c012ea Mon Sep 17 00:00:00 2001 From: Solomon Cammack Date: Sat, 26 Nov 2022 16:52:49 +0000 Subject: [PATCH 1/3] Move repeated functions to utils file --- server/src/action-utils.js | 43 ++++++++++++++++++++++++- server/src/actions/manage-prediction.js | 30 +++++------------ server/src/actions/set-title.js | 29 ++++------------- server/src/actions/start-commercial.js | 19 +++-------- 4 files changed, 62 insertions(+), 59 deletions(-) diff --git a/server/src/action-utils.js b/server/src/action-utils.js index bac03da6..97066ce3 100644 --- a/server/src/action-utils.js +++ b/server/src/action-utils.js @@ -1,5 +1,7 @@ const Airtable = require("airtable"); const Cache = require("./cache"); +const { StaticAuthProvider } = require("@twurple/auth"); +const { ApiClient } = require("@twurple/api"); const airtable = new Airtable({ apiKey: process.env.AIRTABLE_KEY }); const slmngg = airtable.base(process.env.AIRTABLE_APP); @@ -100,6 +102,45 @@ async function getValidHeroes() { return heroes.filter(h => h.game === "Overwatch"); } +async function getTwitchChannel(client, requestedScopes, { get, auth }, { success, error }) { + const broadcast = await get(client?.broadcast?.[0]); + if (!broadcast) return error("No broadcast associated"); + if (!broadcast.channel) return error("No channel associated with broadcast"); + + const channel = await auth.getChannel(broadcast?.channel?.[0]); + if (!channel.twitch_refresh_token) return error("No twitch auth token associated with channel"); + if (!channel.channel_id || !channel.name || !channel.twitch_scopes) return error("Invalid channel data"); + let scopes = channel.twitch_scopes.split(" "); + if (!requestedScopes.every(scope => scopes.includes(scope))) return error("Token doesn't have the required scopes"); + return { + broadcast, + channel, + scopes + }; +} + +async function getMatchData(broadcast, requireAll, { get }, { success, error }) { + const match = await get(broadcast?.live_match?.[0]); + if (!match) return error("No match associated"); + + const team1 = await get(match?.teams?.[0]); + const team2 = await get(match?.teams?.[1]); + if (requireAll && (!team1 || !team2)) return error("Did not find two teams!"); + + return { + match, + team1, + team2 + }; +} + +async function getTwitchAPI(channel, auth) { + const accessToken = await auth.getTwitchAccessToken(channel); + const authProvider = new StaticAuthProvider(process.env.TWITCH_CLIENT_ID, accessToken); + return new ApiClient({authProvider}); +} + + module.exports = { - getSelfClient, dirtyID, deAirtable, updateRecord, getValidHeroes, createRecord + getSelfClient, dirtyID, deAirtable, updateRecord, getValidHeroes, createRecord, getTwitchChannel, getMatchData, getTwitchAPIClient: getTwitchAPI }; diff --git a/server/src/actions/manage-prediction.js b/server/src/actions/manage-prediction.js index b2566077..6742ea5b 100644 --- a/server/src/actions/manage-prediction.js +++ b/server/src/actions/manage-prediction.js @@ -1,5 +1,9 @@ const { ApiClient } = require("@twurple/api"); const { StaticAuthProvider, refreshUserToken } = require("@twurple/auth"); +const { getTwitchChannel, + getTwitchAPIClient, + getMatchData +} = require("../action-utils"); const automaticPredictionTitleStartCharacter = "⬥"; @@ -49,30 +53,12 @@ module.exports = { if (!(["create", "lock", "resolve", "cancel"].includes(predictionAction))) return error("Invalid action"); console.log(predictionAction); - const broadcast = await get(client?.broadcast?.[0]); - if (!broadcast) return error("No broadcast associated"); - if (!broadcast.channel) return error("No channel associated with broadcast"); - - const channel = await auth.getChannel(broadcast?.channel?.[0]); - if (!channel.twitch_refresh_token) return error("No twitch auth token associated with channel"); - if (!channel.channel_id || !channel.name || !channel.twitch_scopes) return error("Invalid channel data"); - let scopes = channel.twitch_scopes.split(" "); - if (!["channel:manage:predictions", "channel:read:predictions"].every(scope => scopes.includes(scope))) return error("Token doesn't have the required scopes"); - - console.log(channel); - const accessToken = await auth.getTwitchAccessToken(channel); - - const authProvider = new StaticAuthProvider(process.env.TWITCH_CLIENT_ID, accessToken); - const api = new ApiClient({authProvider}); - // TODO: move cancel action to here - const match = await get(broadcast?.live_match?.[0]); - if (!match) return error("No match associated"); - - const team1 = await get(match?.teams?.[0]); - const team2 = await get(match?.teams?.[1]); - if (!team1 || !team2) return error("Did not find two teams!"); + const { broadcast, channel } = getTwitchChannel(client, ["channel:manage:predictions", "channel:read:predictions"], { get, auth }, { success, error }); + // console.log(channel); + const api = await getTwitchAPIClient(channel, auth); + const { match, team1, team2 } = await getMatchData(broadcast, true, { get }, { success, error }); const maps = await Promise.all((match.maps || []).map(async m => { let map = await get(m); diff --git a/server/src/actions/set-title.js b/server/src/actions/set-title.js index 56323736..a37ff2ff 100644 --- a/server/src/actions/set-title.js +++ b/server/src/actions/set-title.js @@ -1,5 +1,9 @@ const { ApiClient } = require("@twurple/api"); const { StaticAuthProvider } = require("@twurple/auth"); +const { getTwitchChannel, + getMatchData, + getTwitchAPIClient +} = require("../action-utils"); module.exports = { key: "set-title", auth: ["client"], @@ -15,32 +19,13 @@ module.exports = { */ // eslint-disable-next-line no-empty-pattern async handler(success, error, { }, { client }, { get, auth }) { - const broadcast = await get(client?.broadcast?.[0]); - if (!broadcast) return error("No broadcast associated"); - if (!broadcast.channel) return error("No channel associated with broadcast"); + const { broadcast, channel } = getTwitchChannel(client, ["channel:manage:broadcast"], { get, auth }, { success, error }); const event = await get(broadcast.event?.[0]); if (!event) return error("No event associated with broadcast"); - - const channel = await auth.getChannel(broadcast?.channel?.[0]); - if (!channel.twitch_refresh_token) return error("No twitch auth token associated with channel"); - if (!channel.channel_id || !channel.name || !channel.twitch_scopes) return error("Invalid channel data"); - let scopes = channel.twitch_scopes.split(" "); - if (!["channel:manage:broadcast"].every(scope => scopes.includes(scope))) return error("Token doesn't have the required scopes"); - - const accessToken = await auth.getTwitchAccessToken(channel); - - const authProvider = new StaticAuthProvider(process.env.TWITCH_CLIENT_ID, accessToken); - const api = new ApiClient({authProvider}); - - - const match = await get(broadcast?.live_match?.[0]); - if (!match) return error("No match associated"); - - const team1 = await get(match?.teams?.[0]); - const team2 = await get(match?.teams?.[1]); - if (!team1 || !team2) return error("Did not find two teams!"); + const api = await getTwitchAPIClient(channel, auth); + const { match, team1, team2 } = await getMatchData(broadcast, true, { get }, { success, error }); const formatOptions = { "event": event.name, diff --git a/server/src/actions/start-commercial.js b/server/src/actions/start-commercial.js index b0816f4e..0be02878 100644 --- a/server/src/actions/start-commercial.js +++ b/server/src/actions/start-commercial.js @@ -1,5 +1,8 @@ const { ApiClient } = require("@twurple/api"); const { StaticAuthProvider } = require("@twurple/auth"); +const { getTwitchChannel, + getTwitchAPIClient +} = require("../action-utils"); module.exports = { key: "start-commercial", auth: ["client"], @@ -16,20 +19,8 @@ module.exports = { */ // eslint-disable-next-line no-empty-pattern async handler(success, error, { commercialDuration }, { client }, { get, auth }) { - const broadcast = await get(client?.broadcast?.[0]); - if (!broadcast) return error("No broadcast associated"); - if (!broadcast.channel) return error("No channel associated with broadcast"); - - const channel = await auth.getChannel(broadcast?.channel?.[0]); - if (!channel.twitch_refresh_token) return error("No twitch auth token associated with channel"); - if (!channel.channel_id || !channel.name || !channel.twitch_scopes) return error("Invalid channel data"); - let scopes = channel.twitch_scopes.split(" "); - if (!["channel:edit:commercial"].every(scope => scopes.includes(scope))) return error("Token doesn't have the required scopes"); - - const accessToken = await auth.getTwitchAccessToken(channel); - - const authProvider = new StaticAuthProvider(process.env.TWITCH_CLIENT_ID, accessToken); - const api = new ApiClient({authProvider}); + const { channel } = getTwitchChannel(client, ["channel:edit:commercial"], { get, auth }, { success, error }); + const api = getTwitchAPIClient(channel, auth); try { await api.channels.startChannelCommercial(channel.channel_id, commercialDuration); From f083d9531aa5b18906efa6657c4f5c8b7eb659b1 Mon Sep 17 00:00:00 2001 From: Solomon Cammack Date: Sat, 26 Nov 2022 17:43:08 +0000 Subject: [PATCH 2/3] Update actions to use internal functions where appropriate --- server/src/action-utils.js | 9 +++++---- server/src/actions/manage-prediction.js | 6 +++--- server/src/actions/set-title.js | 4 ++-- server/src/actions/start-commercial.js | 4 ++-- 4 files changed, 12 insertions(+), 11 deletions(-) diff --git a/server/src/action-utils.js b/server/src/action-utils.js index 97066ce3..52fa0e09 100644 --- a/server/src/action-utils.js +++ b/server/src/action-utils.js @@ -2,6 +2,7 @@ const Airtable = require("airtable"); const Cache = require("./cache"); const { StaticAuthProvider } = require("@twurple/auth"); const { ApiClient } = require("@twurple/api"); +const { get, auth } = require("./cache"); const airtable = new Airtable({ apiKey: process.env.AIRTABLE_KEY }); const slmngg = airtable.base(process.env.AIRTABLE_APP); @@ -102,7 +103,7 @@ async function getValidHeroes() { return heroes.filter(h => h.game === "Overwatch"); } -async function getTwitchChannel(client, requestedScopes, { get, auth }, { success, error }) { +async function getTwitchChannel(client, requestedScopes, { success, error }) { const broadcast = await get(client?.broadcast?.[0]); if (!broadcast) return error("No broadcast associated"); if (!broadcast.channel) return error("No channel associated with broadcast"); @@ -119,7 +120,7 @@ async function getTwitchChannel(client, requestedScopes, { get, auth }, { succes }; } -async function getMatchData(broadcast, requireAll, { get }, { success, error }) { +async function getMatchData(broadcast, requireAll, { success, error }) { const match = await get(broadcast?.live_match?.[0]); if (!match) return error("No match associated"); @@ -134,7 +135,7 @@ async function getMatchData(broadcast, requireAll, { get }, { success, error }) }; } -async function getTwitchAPI(channel, auth) { +async function getTwitchAPIClient(channel) { const accessToken = await auth.getTwitchAccessToken(channel); const authProvider = new StaticAuthProvider(process.env.TWITCH_CLIENT_ID, accessToken); return new ApiClient({authProvider}); @@ -142,5 +143,5 @@ async function getTwitchAPI(channel, auth) { module.exports = { - getSelfClient, dirtyID, deAirtable, updateRecord, getValidHeroes, createRecord, getTwitchChannel, getMatchData, getTwitchAPIClient: getTwitchAPI + getSelfClient, dirtyID, deAirtable, updateRecord, getValidHeroes, createRecord, getTwitchChannel, getMatchData, getTwitchAPIClient }; diff --git a/server/src/actions/manage-prediction.js b/server/src/actions/manage-prediction.js index 6742ea5b..e7b5c859 100644 --- a/server/src/actions/manage-prediction.js +++ b/server/src/actions/manage-prediction.js @@ -55,10 +55,10 @@ module.exports = { // TODO: move cancel action to here - const { broadcast, channel } = getTwitchChannel(client, ["channel:manage:predictions", "channel:read:predictions"], { get, auth }, { success, error }); + const { broadcast, channel } = getTwitchChannel(client, ["channel:manage:predictions", "channel:read:predictions"], { success, error }); // console.log(channel); - const api = await getTwitchAPIClient(channel, auth); - const { match, team1, team2 } = await getMatchData(broadcast, true, { get }, { success, error }); + const api = await getTwitchAPIClient(channel); + const { match, team1, team2 } = await getMatchData(broadcast, true, { success, error }); const maps = await Promise.all((match.maps || []).map(async m => { let map = await get(m); diff --git a/server/src/actions/set-title.js b/server/src/actions/set-title.js index a37ff2ff..d23a6cea 100644 --- a/server/src/actions/set-title.js +++ b/server/src/actions/set-title.js @@ -19,13 +19,13 @@ module.exports = { */ // eslint-disable-next-line no-empty-pattern async handler(success, error, { }, { client }, { get, auth }) { - const { broadcast, channel } = getTwitchChannel(client, ["channel:manage:broadcast"], { get, auth }, { success, error }); + const { broadcast, channel } = getTwitchChannel(client, ["channel:manage:broadcast"], { success, error }); const event = await get(broadcast.event?.[0]); if (!event) return error("No event associated with broadcast"); const api = await getTwitchAPIClient(channel, auth); - const { match, team1, team2 } = await getMatchData(broadcast, true, { get }, { success, error }); + const { match, team1, team2 } = await getMatchData(broadcast, true, { success, error }); const formatOptions = { "event": event.name, diff --git a/server/src/actions/start-commercial.js b/server/src/actions/start-commercial.js index 0be02878..5c947615 100644 --- a/server/src/actions/start-commercial.js +++ b/server/src/actions/start-commercial.js @@ -19,8 +19,8 @@ module.exports = { */ // eslint-disable-next-line no-empty-pattern async handler(success, error, { commercialDuration }, { client }, { get, auth }) { - const { channel } = getTwitchChannel(client, ["channel:edit:commercial"], { get, auth }, { success, error }); - const api = getTwitchAPIClient(channel, auth); + const { channel } = getTwitchChannel(client, ["channel:edit:commercial"], { success, error }); + const api = getTwitchAPIClient(channel); try { await api.channels.startChannelCommercial(channel.channel_id, commercialDuration); From cbca19e649cecd5a8b0d92459cf71e93811a13f3 Mon Sep 17 00:00:00 2001 From: Solomon Cammack Date: Sat, 26 Nov 2022 17:44:36 +0000 Subject: [PATCH 3/3] Remove unused imports --- server/src/actions/manage-prediction.js | 2 -- server/src/actions/set-title.js | 2 -- server/src/actions/start-commercial.js | 2 -- 3 files changed, 6 deletions(-) diff --git a/server/src/actions/manage-prediction.js b/server/src/actions/manage-prediction.js index e7b5c859..f8634fd2 100644 --- a/server/src/actions/manage-prediction.js +++ b/server/src/actions/manage-prediction.js @@ -1,5 +1,3 @@ -const { ApiClient } = require("@twurple/api"); -const { StaticAuthProvider, refreshUserToken } = require("@twurple/auth"); const { getTwitchChannel, getTwitchAPIClient, getMatchData diff --git a/server/src/actions/set-title.js b/server/src/actions/set-title.js index d23a6cea..710ec2a3 100644 --- a/server/src/actions/set-title.js +++ b/server/src/actions/set-title.js @@ -1,5 +1,3 @@ -const { ApiClient } = require("@twurple/api"); -const { StaticAuthProvider } = require("@twurple/auth"); const { getTwitchChannel, getMatchData, getTwitchAPIClient diff --git a/server/src/actions/start-commercial.js b/server/src/actions/start-commercial.js index 5c947615..43c36690 100644 --- a/server/src/actions/start-commercial.js +++ b/server/src/actions/start-commercial.js @@ -1,5 +1,3 @@ -const { ApiClient } = require("@twurple/api"); -const { StaticAuthProvider } = require("@twurple/auth"); const { getTwitchChannel, getTwitchAPIClient } = require("../action-utils");