mirror of
https://github.com/kirameki-cafe/Yumi.git
synced 2026-09-13 10:49:20 +00:00
Merge pull request #23 from kirameki-cafe/more-env-checks
More environment variables check
This commit is contained in:
@@ -44,15 +44,15 @@ Take a look inside [.env.example](https://github.com/kirameki-cafe/Yumi/blob/mai
|
||||
- ``NODE_ENV`` Environment type, ``development`` or ``production``
|
||||
- ``DATABASE_URL`` Connection URL to your database. [More info](https://www.prisma.io/docs/getting-started/setup-prisma/start-from-scratch/relational-databases/connect-your-database-typescript-postgres)
|
||||
- ``DISCORD_TOKEN`` Your discord bot token
|
||||
- ``DEVELOPER_IDS`` List of Discord Snowflake User ID that can access developer only modules, separated by ``,``
|
||||
- ``DEVELOPER_IDS`` (Optional) List of Discord Snowflake User ID that can access developer only modules, separated by ``,``
|
||||
- ``PRIVATE_BOT`` Should the bot invite be public? ``true`` or ``false``
|
||||
- ``SUPPORT_URL`` (Optional) URL to your support server (If not set, support module will show not available message)
|
||||
- ``OSU_API_KEY`` [osu! API v1 key](https://github.com/ppy/osu-api/wiki)
|
||||
- ``YOUTUBE_COOKIE_BASE64`` YouTube cookies encoded in base64 [How to get cookies?](https://github.com/play-dl/play-dl/tree/main/instructions#youtube-cookies=) *
|
||||
- ``SPOTIFY_CLIENT_ID`` Spotify client ID
|
||||
- ``SPOTIFY_CLIENT_SECRET`` Spotify client secret
|
||||
- ``SPOTIFY_REFRESH_TOKEN`` Spotify refresh token **
|
||||
- ``SPOTIFY_CLIENT_MARKET`` Spotify market country code
|
||||
- ``OSU_API_KEY`` (Optional) [osu! API v1 key](https://github.com/ppy/osu-api/wiki)
|
||||
- ``YOUTUBE_COOKIE_BASE64`` (Optional) YouTube cookies encoded in base64 [How to get cookies?](https://github.com/play-dl/play-dl/tree/main/instructions#youtube-cookies=) *
|
||||
- ``SPOTIFY_CLIENT_ID`` (Optional) Spotify client ID
|
||||
- ``SPOTIFY_CLIENT_SECRET`` (Optional) Spotify client secret
|
||||
- ``SPOTIFY_REFRESH_TOKEN`` (Optional) Spotify refresh token **
|
||||
- ``SPOTIFY_CLIENT_MARKET`` (Optional) Spotify market country code
|
||||
|
||||
\* Encode the cookies from the request headers base64 and put it in here instead of creating new file with ``play.authorization();`` code
|
||||
|
||||
|
||||
@@ -13,8 +13,11 @@ const EMBEDS = {
|
||||
INVITE_INFO: (data: HybridInteractionMessage, locale: I18n) => {
|
||||
const user = data.getUser();
|
||||
let message;
|
||||
if (!(Environment.get().PRIVATE_BOT === 'true') || user != null && Users.isDeveloper(user.id))
|
||||
message = locale.__('invite.info', { BOT_NAME: DiscordProvider.client.user!.username, LINK: `https://discord.com/api/oauth2/authorize?client_id=${DiscordProvider.client.user?.id}&permissions=8&scope=bot%20applications.commands`});
|
||||
if (!(Environment.get().PRIVATE_BOT.toLowerCase() === 'true') || (user != null && Users.isDeveloper(user.id)))
|
||||
message = locale.__('invite.info', {
|
||||
BOT_NAME: DiscordProvider.client.user!.username,
|
||||
LINK: `https://discord.com/api/oauth2/authorize?client_id=${DiscordProvider.client.user?.id}&permissions=8&scope=bot%20applications.commands`
|
||||
});
|
||||
|
||||
return makeInfoEmbed({
|
||||
title: `Invite`,
|
||||
|
||||
+26
-38
@@ -73,6 +73,12 @@ const EMBEDS = {
|
||||
title: `No osu! beatmap id provided`,
|
||||
user: data.getUser()
|
||||
});
|
||||
},
|
||||
NOT_INITIALIZED: (data: HybridInteractionMessage) => {
|
||||
return makeErrorEmbed({
|
||||
title: `osu! feature is disabled`,
|
||||
user: data.getUser()
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
@@ -93,6 +99,12 @@ export default class osu extends DiscordModule {
|
||||
const Guild = await Prisma.client.guild.findFirst({ where: { id: data.getGuild()!.id } });
|
||||
if (!Guild) return;
|
||||
|
||||
|
||||
if (!osuAPI.client)
|
||||
return await sendHybridInteractionMessageResponse(data, {
|
||||
embeds: [EMBEDS.NOT_INITIALIZED(data)]
|
||||
});
|
||||
|
||||
const funct = {
|
||||
user: async (data: HybridInteractionMessage) => {
|
||||
let user;
|
||||
@@ -111,7 +123,7 @@ export default class osu extends DiscordModule {
|
||||
embeds: [EMBEDS.INVALID_USER_MENTIONED(data)]
|
||||
});
|
||||
|
||||
let result = await osuAPI.client.getUser({ u: user });
|
||||
let result = await osuAPI.client!.getUser({ u: user });
|
||||
|
||||
if (result instanceof Array && result.length === 0)
|
||||
return await sendHybridInteractionMessageResponse(data, {
|
||||
@@ -123,12 +135,8 @@ export default class osu extends DiscordModule {
|
||||
}
|
||||
|
||||
const level = {
|
||||
number: (Math.round((result.level + Number.EPSILON) * 100) / 100)
|
||||
.toFixed(2)
|
||||
.split('.')[0],
|
||||
progression: (Math.round((result.level + Number.EPSILON) * 100) / 100)
|
||||
.toFixed(2)
|
||||
.split('.')[1]
|
||||
number: (Math.round((result.level + Number.EPSILON) * 100) / 100).toFixed(2).split('.')[0],
|
||||
progression: (Math.round((result.level + Number.EPSILON) * 100) / 100).toFixed(2).split('.')[1]
|
||||
};
|
||||
const embed = makeInfoEmbed({
|
||||
icon: '',
|
||||
@@ -142,10 +150,7 @@ export default class osu extends DiscordModule {
|
||||
)}**, totaling in **${this.numberWithCommas(
|
||||
parseFloat(
|
||||
(
|
||||
Math.round(
|
||||
(result.secondsPlayed / (60 * 60) + Number.EPSILON) *
|
||||
100
|
||||
) / 100
|
||||
Math.round((result.secondsPlayed / (60 * 60) + Number.EPSILON) * 100) / 100
|
||||
).toFixed(2)
|
||||
)
|
||||
)} ${result.secondsPlayed < 60 ? 'hour' : 'hours'}** of songs played
|
||||
@@ -236,9 +241,7 @@ export default class osu extends DiscordModule {
|
||||
name: `❤ Account Information`,
|
||||
value: `Joined: <t:${Math.round(
|
||||
new Date(result.raw_joinDate).getTime() / 1000
|
||||
)}:R>, <t:${Math.round(
|
||||
new Date(result.raw_joinDate).getTime() / 1000
|
||||
)}:f>`
|
||||
)}:R>, <t:${Math.round(new Date(result.raw_joinDate).getTime() / 1000)}:f>`
|
||||
} //,
|
||||
/*{
|
||||
name: `💌 Recent Events (Coming soon)`,
|
||||
@@ -255,8 +258,7 @@ export default class osu extends DiscordModule {
|
||||
|
||||
// TODO: Fix for ppl with no image
|
||||
embed.setThumbnail(
|
||||
`https://a.ppy.sh/${result.id}` ||
|
||||
'https://osu.ppy.sh/images/layout/avatar-guest.png'
|
||||
`https://a.ppy.sh/${result.id}` || 'https://osu.ppy.sh/images/layout/avatar-guest.png'
|
||||
);
|
||||
|
||||
const row = new ActionRowBuilder<ButtonBuilder>().addComponents([
|
||||
@@ -289,7 +291,7 @@ export default class osu extends DiscordModule {
|
||||
embeds: [EMBEDS.INVALID_BEATMAP_ID_MENTIONED(data)]
|
||||
});
|
||||
|
||||
let result = await osuAPI.client.getBeatmaps({ b: beatmap });
|
||||
let result = await osuAPI.client!.getBeatmaps({ b: beatmap });
|
||||
|
||||
if (result instanceof Array && result.length === 0)
|
||||
return await sendHybridInteractionMessageResponse(data, {
|
||||
@@ -331,17 +333,13 @@ export default class osu extends DiscordModule {
|
||||
{
|
||||
name: '⭐ Star Difficulty',
|
||||
value: `**${(
|
||||
Math.round((bm_result.difficulty.rating + Number.EPSILON) * 100) /
|
||||
100
|
||||
Math.round((bm_result.difficulty.rating + Number.EPSILON) * 100) / 100
|
||||
).toFixed(2)}**`,
|
||||
inline: true
|
||||
},
|
||||
{
|
||||
name: `⌛ Length`,
|
||||
value: `**${(
|
||||
Math.round((bm_result.length.total / 60 + Number.EPSILON) * 100) /
|
||||
100
|
||||
)
|
||||
value: `**${(Math.round((bm_result.length.total / 60 + Number.EPSILON) * 100) / 100)
|
||||
.toFixed(2)
|
||||
.replace('.', ':')}**`,
|
||||
inline: true
|
||||
@@ -389,19 +387,13 @@ export default class osu extends DiscordModule {
|
||||
Genre: **${bm_result.genre}**
|
||||
Submission Date: <t:${Math.round(
|
||||
new Date(bm_result.raw_submitDate).getTime() / 1000
|
||||
)}:R>, <t:${Math.round(
|
||||
new Date(bm_result.raw_submitDate).getTime() / 1000
|
||||
)}:f>
|
||||
)}:R>, <t:${Math.round(new Date(bm_result.raw_submitDate).getTime() / 1000)}:f>
|
||||
Last updated: <t:${Math.round(
|
||||
new Date(bm_result.raw_lastUpdate).getTime() / 1000
|
||||
)}:R>, <t:${Math.round(
|
||||
new Date(bm_result.raw_lastUpdate).getTime() / 1000
|
||||
)}:f>
|
||||
)}:R>, <t:${Math.round(new Date(bm_result.raw_lastUpdate).getTime() / 1000)}:f>
|
||||
Approved: <t:${Math.round(
|
||||
new Date(bm_result.raw_approvedDate).getTime() / 1000
|
||||
)}:R>, <t:${Math.round(
|
||||
new Date(bm_result.raw_approvedDate).getTime() / 1000
|
||||
)}:f>
|
||||
)}:R>, <t:${Math.round(new Date(bm_result.raw_approvedDate).getTime() / 1000)}:f>
|
||||
\u200b`
|
||||
},
|
||||
{
|
||||
@@ -433,9 +425,7 @@ export default class osu extends DiscordModule {
|
||||
url: `https://osu.ppy.sh/beatmapsets/${bm_result.beatmapSetId}${url_mode}/${bm_result.id}`,
|
||||
iconURL: `https://upload.wikimedia.org/wikipedia/commons/e/e3/Osulogo.png`
|
||||
});
|
||||
embed2.setImage(
|
||||
`https://assets.ppy.sh/beatmaps/${bm_result.beatmapSetId}/covers/cover.jpg`
|
||||
);
|
||||
embed2.setImage(`https://assets.ppy.sh/beatmaps/${bm_result.beatmapSetId}/covers/cover.jpg`);
|
||||
|
||||
const row = new ActionRowBuilder<ButtonBuilder>();
|
||||
if (bm_result.hasDownload)
|
||||
@@ -455,9 +445,7 @@ export default class osu extends DiscordModule {
|
||||
new ButtonBuilder()
|
||||
.setEmoji('💬')
|
||||
.setLabel(' Open discussion')
|
||||
.setURL(
|
||||
`https://osu.ppy.sh/beatmapsets/${bm_result.beatmapSetId}/discussion`
|
||||
)
|
||||
.setURL(`https://osu.ppy.sh/beatmapsets/${bm_result.beatmapSetId}/discussion`)
|
||||
.setStyle(ButtonStyle.Link)
|
||||
]);
|
||||
|
||||
|
||||
@@ -39,11 +39,19 @@ class App {
|
||||
}
|
||||
|
||||
public load_osu(): void {
|
||||
if (!Environment.get().OSU_API_KEY) {
|
||||
Logger.log('warn', 'OSU_API_KEY is not defined in .env, osu! features will be disabled');
|
||||
return;
|
||||
}
|
||||
Logger.log('info', 'Loading osu! Client');
|
||||
osu.init();
|
||||
}
|
||||
|
||||
public loadExpress(): void {
|
||||
if (!Environment.get().WEB_HOST || !Environment.get().WEB_PORT) {
|
||||
Logger.log('warn', 'WEB_HOST or WEB_PORT is not defined in .env, not starting web server');
|
||||
return;
|
||||
}
|
||||
Logger.log('info', 'Loading Express');
|
||||
Express.init();
|
||||
}
|
||||
|
||||
@@ -1,24 +1,54 @@
|
||||
import * as path from 'path';
|
||||
import * as dotenv from 'dotenv';
|
||||
import validator from 'validator';
|
||||
|
||||
import Logger from '../libs/Logger';
|
||||
|
||||
const requiredENV = ['NODE_ENV', 'DATABASE_URL', 'DISCORD_TOKEN', 'PRIVATE_BOT', 'OSU_API_KEY'];
|
||||
const requiredENV = ['NODE_ENV', 'DATABASE_URL', 'DISCORD_TOKEN', 'PRIVATE_BOT'];
|
||||
|
||||
class Environment {
|
||||
public init(): void {
|
||||
dotenv.config({ path: path.resolve(__dirname, '../../.env') });
|
||||
|
||||
for (let param of requiredENV) {
|
||||
if (this.isUndefinedOrEmpty(process.env[param]))
|
||||
throw new Error(`.env ${param} is undefined`);
|
||||
if (this.isUndefinedOrEmpty(process.env[param])) throw new Error(`.env ${param} is undefined`);
|
||||
}
|
||||
|
||||
// NODE_ENV Checks
|
||||
if (this.get().NODE_ENV != 'production' && this.get().NODE_ENV != 'development')
|
||||
throw new Error('.env NODE_ENV must be either "production" or "development"');
|
||||
|
||||
// TODO: Discord token check
|
||||
// DISCORD_TOKEN Checks
|
||||
if (this.get().DISCORD_TOKEN.length != 59)
|
||||
throw new Error('.env DISCORD_TOKEN is not a valid discord bot token');
|
||||
|
||||
// DEVELOPER_IDS Checks
|
||||
if (this.get().DEVELOPER_IDS) {
|
||||
let developerIds = this.get().DEVELOPER_IDS.split(',');
|
||||
for (let id of developerIds) {
|
||||
if (isNaN(parseInt(id))) throw new Error(`.env DEVELOPER_IDS contains an invalid id: ${id}`);
|
||||
}
|
||||
}
|
||||
|
||||
// PRIVATE_BOT Checks
|
||||
if (this.get().PRIVATE_BOT.toLowerCase() != 'true' && this.get().PRIVATE_BOT.toLowerCase() != 'false')
|
||||
throw new Error('.env PRIVATE_BOT must be either "true" or "false"');
|
||||
|
||||
// SUPPORT_URL Checks
|
||||
if (this.get().SUPPORT_URL && !validator.isURL(this.get().SUPPORT_URL))
|
||||
throw new Error('.env SUPPORT_URL is not a valid URL');
|
||||
|
||||
// WEB_HOST Checks
|
||||
if (this.get().WEB_HOST && this.get().WEB_HOST.toLowerCase() != 'localhost' && !validator.isIP(this.get().WEB_HOST))
|
||||
throw new Error('.env WEB_HOST must be either localhost or a valid IP address');
|
||||
|
||||
// WEB_PORT Checks
|
||||
if (this.get().WEB_PORT && !validator.isPort(this.get().WEB_PORT))
|
||||
throw new Error('.env WEB_PORT must be a valid port number');
|
||||
|
||||
// YOUTUBE_COOKIE_BASE64 Checks
|
||||
if (this.get().YOUTUBE_COOKIE_BASE64 && !validator.isBase64(this.get().YOUTUBE_COOKIE_BASE64))
|
||||
throw new Error('.env YOUTUBE_COOKIE_BASE64 must be a valid base64 string');
|
||||
|
||||
Logger.log('info', `Running in ${process.env.NODE_ENV} environment`);
|
||||
}
|
||||
|
||||
@@ -30,7 +30,7 @@ class Express {
|
||||
}
|
||||
|
||||
public end(): void {
|
||||
if(this.server != null)
|
||||
if(this.server)
|
||||
this.server.close();
|
||||
}
|
||||
|
||||
|
||||
@@ -2,14 +2,10 @@ import { Api } from 'node-osu';
|
||||
import Environment from './Environment';
|
||||
|
||||
class osuAPI {
|
||||
public client: Api;
|
||||
public client: Api | null;
|
||||
|
||||
constructor() {
|
||||
this.client = new Api(Environment.get().OSU_API_KEY, {
|
||||
notFoundAsError: false,
|
||||
completeScores: true,
|
||||
parseNumeric: true
|
||||
});
|
||||
this.client = null;
|
||||
}
|
||||
|
||||
public init(): void {
|
||||
|
||||
@@ -3,8 +3,11 @@ import Environment from '../providers/Environment';
|
||||
|
||||
class Users {
|
||||
public static isDeveloper(user: User | Snowflake) {
|
||||
const developers: Snowflake[] = Environment.get().DEVELOPER_IDS.split(',');
|
||||
|
||||
if(!Environment.get().DEVELOPERS)
|
||||
return false;
|
||||
|
||||
const developers: Snowflake[] = Environment.get().DEVELOPER_IDS.split(',');
|
||||
let userID;
|
||||
|
||||
if (user instanceof User) userID = user.id;
|
||||
|
||||
Reference in New Issue
Block a user