Skip to content

Commit

Permalink
chore: rework release notifications
Browse files Browse the repository at this point in the history
  • Loading branch information
danieldietzler committed Nov 15, 2024
1 parent 974c46c commit 8f6fa71
Show file tree
Hide file tree
Showing 6 changed files with 130 additions and 58 deletions.
13 changes: 11 additions & 2 deletions src/interfaces/discord.interface.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
import { Message, MessageCreateOptions } from 'discord.js';
import { MessageCreateOptions } from 'discord.js';

export const IDiscordInterface = 'IDiscordInterface';

export enum DiscordChannel {
Announcements = '991930592843272342',
HelpDesk = '1049703391762321418',
General = '994044917355663450',
BotSpam = '1159083520027787307',
Expand All @@ -24,5 +25,13 @@ export enum DiscordEvents {

export interface IDiscordInterface {
login(token: string): Promise<void>;
sendMessage(channel: DiscordChannel, message: string | MessageCreateOptions): Promise<Message | undefined>;
sendMessage({
channel,
message,
crosspost,
}: {
channel: DiscordChannel;
message: string | MessageCreateOptions;
crosspost?: boolean;
}): Promise<void>;
}
18 changes: 15 additions & 3 deletions src/repositories/discord.repository.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { Logger } from '@nestjs/common';
import { IntentsBitField, Message, MessageCreateOptions, Partials } from 'discord.js';
import { IntentsBitField, MessageCreateOptions, Partials } from 'discord.js';
import { Client } from 'discordx';
import { DiscordChannel, IDiscordInterface } from 'src/interfaces/discord.interface';

Expand Down Expand Up @@ -65,10 +65,22 @@ export class DiscordRepository implements IDiscordInterface {
await bot.login(token);
}

async sendMessage(channel: DiscordChannel, message: MessageCreateOptions): Promise<Message | undefined> {
async sendMessage({
channel,
message,
crosspost = false,
}: {
channel: DiscordChannel;
message: MessageCreateOptions;
crosspost?: boolean;
}): Promise<void> {
const textChannel = await bot.channels.fetch(channel);
if (textChannel?.isSendable()) {
return textChannel.send(message);
const sentMessage = await textChannel.send(message);

if (crosspost) {
await sentMessage.crosspost();
}
}
}
}
10 changes: 8 additions & 2 deletions src/services/discord.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,10 @@ export class DiscordService {

@Cron(Constants.Cron.ImmichBirthday)
async onBirthday() {
await this.discord.sendMessage(DiscordChannel.General, `"Happy birthday my other child" - Alex`);
await this.discord.sendMessage({
channel: DiscordChannel.General,
message: `"Happy birthday my other child" - Alex`,
});
}

private async getVersionMessage() {
Expand All @@ -66,7 +69,10 @@ export class DiscordService {
this.logger.log(`Bot ${versionMessage} started`);

if (versionMessage) {
await this.discord.sendMessage(DiscordChannel.BotSpam, `I'm alive, running ${versionMessage}!`);
await this.discord.sendMessage({
channel: DiscordChannel.BotSpam,
message: `I'm alive, running ${versionMessage}!`,
});
}
}

Expand Down
57 changes: 33 additions & 24 deletions src/services/report.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,14 +19,17 @@ export class ReportService {
const endOfYesterday = DateTime.now().minus({ days: 1 }).endOf('day');
const { server, client } = await this.database.getTotalLicenseCount({ day: endOfYesterday });

await this.discord.sendMessage(DiscordChannel.Stripe, {
embeds: [
new EmbedBuilder()
.setTitle(`Daily report for ${endOfYesterday.toLocaleString(DateTime.DATE_FULL)}`)
.setDescription(`Total: ${getTotal({ server, client })}`)
.setColor(Colors.Purple)
.setFields(makeLicenseFields({ server, client })),
],
await this.discord.sendMessage({
channel: DiscordChannel.Stripe,
message: {
embeds: [
new EmbedBuilder()
.setTitle(`Daily report for ${endOfYesterday.toLocaleString(DateTime.DATE_FULL)}`)
.setDescription(`Total: ${getTotal({ server, client })}`)
.setColor(Colors.Purple)
.setFields(makeLicenseFields({ server, client })),
],
},
});
}

Expand All @@ -36,14 +39,17 @@ export class ReportService {
const lastWeek = endOfYesterday.minus({ weeks: 1 });
const { server, client } = await this.database.getTotalLicenseCount({ week: endOfYesterday });

await this.discord.sendMessage(DiscordChannel.Stripe, {
embeds: [
new EmbedBuilder()
.setTitle(`Weekly report for ${lastWeek.toFormat('MMMM dd')} - ${endOfYesterday.toFormat('MMMM dd')}`)
.setDescription(`Total: ${getTotal({ server, client })}`)
.setColor(Colors.Purple)
.setFields(makeLicenseFields({ server, client })),
],
await this.discord.sendMessage({
channel: DiscordChannel.Stripe,
message: {
embeds: [
new EmbedBuilder()
.setTitle(`Weekly report for ${lastWeek.toFormat('MMMM dd')} - ${endOfYesterday.toFormat('MMMM dd')}`)
.setDescription(`Total: ${getTotal({ server, client })}`)
.setColor(Colors.Purple)
.setFields(makeLicenseFields({ server, client })),
],
},
});
}

Expand All @@ -53,14 +59,17 @@ export class ReportService {
const lastMonth = endOfYesterday.minus({ months: 1 });
const { server, client } = await this.database.getTotalLicenseCount({ month: endOfYesterday });

await this.discord.sendMessage(DiscordChannel.Stripe, {
embeds: [
new EmbedBuilder()
.setTitle(`Monthly report for ${lastMonth.toFormat('MMMM dd')} - ${endOfYesterday.toFormat('MMMM dd')}`)
.setDescription(`Total: ${getTotal({ server, client })}`)
.setColor(Colors.Purple)
.setFields(makeLicenseFields({ server, client })),
],
await this.discord.sendMessage({
channel: DiscordChannel.Stripe,
message: {
embeds: [
new EmbedBuilder()
.setTitle(`Monthly report for ${lastMonth.toFormat('MMMM dd')} - ${endOfYesterday.toFormat('MMMM dd')}`)
.setDescription(`Total: ${getTotal({ server, client })}`)
.setColor(Colors.Purple)
.setFields(makeLicenseFields({ server, client })),
],
},
});
}
}
88 changes: 62 additions & 26 deletions src/services/webhook.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,7 @@ export class WebhookService {
});
embed.setColor(color);

await this.discord.sendMessage(DiscordChannel.PullRequests, { embeds: [embed] });
await this.discord.sendMessage({ channel: DiscordChannel.PullRequests, message: { embeds: [embed] } });
return;
}

Expand All @@ -82,7 +82,7 @@ export class WebhookService {
});
embed.setColor(this.getIssueEmbedColor({ action }));

await this.discord.sendMessage(DiscordChannel.IssuesAndDiscussions, { embeds: [embed] });
await this.discord.sendMessage({ channel: DiscordChannel.IssuesAndDiscussions, message: { embeds: [embed] } });
return;
}

Expand All @@ -96,32 +96,44 @@ export class WebhookService {
});
embed.setColor(this.getDiscussionEmbedColor({ action }));

await this.discord.sendMessage(DiscordChannel.IssuesAndDiscussions, { embeds: [embed] });
await this.discord.sendMessage({ channel: DiscordChannel.IssuesAndDiscussions, message: { embeds: [embed] } });
return;
}

if ('release' in dto && action === 'released') {
const content = `${_.sample(ReleaseMessages)} ${dto.release.html_url}`;
const embedProps = {
repositoryName: dto.repository.full_name,
name: dto.release.name,
url: dto.release.html_url,
user: dto.sender,
description: dto.repository.full_name === 'immich-app/immich' ? _.sample(ReleaseMessages) : undefined,
};
const messages = [
(async () => {
const message = await this.discord.sendMessage(DiscordChannel.Releases, {
content: `[${dto.repository.full_name}] ${content}`,
flags: [MessageFlags.SuppressEmbeds],
});
await message?.crosspost();
})(),
this.discord.sendMessage({
channel: DiscordChannel.Releases,
message: {
embeds: [this.getReleaseEmbed(embedProps)],
},
crosspost: true,
}),
];

if (dto.repository.full_name === 'immich-app/immich') {
if (embedProps.description) {
messages.push(
this.discord.sendMessage({
channel: DiscordChannel.Announcements,
message: {
embeds: [this.getReleaseEmbed(embedProps)],
},
crosspost: true,
}),
this.zulip.sendMessage({
stream: Constants.Zulip.Streams.Immich,
topic: Constants.Zulip.Topics.ImmichRelease,
content,
content: embedProps.description,
}),
);
}

await Promise.all(messages);
}
}
Expand Down Expand Up @@ -157,7 +169,7 @@ export class WebhookService {
}
}

await this.discord.sendMessage(DiscordChannel.GithubStatus, { embeds: [embed] });
await this.discord.sendMessage({ channel: DiscordChannel.GithubStatus, message: { embeds: [embed] } });
}
}

Expand Down Expand Up @@ -207,17 +219,41 @@ export class WebhookService {
});

const licenseType = description.split('-')[1];
await this.discord.sendMessage(DiscordChannel.Stripe, {
embeds: [
new EmbedBuilder()
.setTitle(`${livemode ? '' : 'TEST PAYMENT - '}Immich ${licenseType} license purchased`)
.setURL(`https://dashboard.stripe.com/${livemode ? '' : 'test/'}payments/${id}`)
.setAuthor({ name: 'Stripe Payments', url: 'https://stripe.com' })
.setDescription(`Price: ${(amount / 100).toLocaleString()} ${currency.toUpperCase()}`)
.setColor(livemode ? Colors.Green : Colors.Yellow)
.setFields(makeLicenseFields({ server, client })),
],
flags: [MessageFlags.SuppressNotifications],
await this.discord.sendMessage({
channel: DiscordChannel.Stripe,
message: {
embeds: [
new EmbedBuilder()
.setTitle(`${livemode ? '' : 'TEST PAYMENT - '}Immich ${licenseType} license purchased`)
.setURL(`https://dashboard.stripe.com/${livemode ? '' : 'test/'}payments/${id}`)
.setAuthor({ name: 'Stripe Payments', url: 'https://stripe.com' })
.setDescription(`Price: ${(amount / 100).toLocaleString()} ${currency.toUpperCase()}`)
.setColor(livemode ? Colors.Green : Colors.Yellow)
.setFields(makeLicenseFields({ server, client })),
],
flags: [MessageFlags.SuppressNotifications],
},
});
}

private getReleaseEmbed({
repositoryName,
name,
user,
url,
description,
}: {
repositoryName: string;
name: string;
user: User;
url: string;
description?: string;
}) {
return new EmbedBuilder({
title: `[${repositoryName}] New release: ${name}`,
author: { name: user.login, url: user.html_url, iconURL: user.avatar_url },
url,
description,
});
}

Expand Down
2 changes: 1 addition & 1 deletion src/util.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ type Repos = { discord: IDiscordInterface; logger: Logger };
export const logError = async (message: string, error: unknown, { discord, logger }: Repos) => {
logger.error(message, error);
try {
await discord.sendMessage(DiscordChannel.BotSpam, `${message}: ${error}`);
await discord.sendMessage({ channel: DiscordChannel.BotSpam, message: `${message}: ${error}` });
} catch (error) {
logger.error('Failed to send error message to bot spam channel', error);
}
Expand Down

0 comments on commit 8f6fa71

Please sign in to comment.