Skip to content

Commit

Permalink
feat: add changelog command
Browse files Browse the repository at this point in the history
  • Loading branch information
SocketSomeone committed Aug 12, 2023
1 parent c89864c commit b8f3273
Show file tree
Hide file tree
Showing 11 changed files with 190 additions and 10 deletions.
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@
"Alexey Filippov <socket.someone@gmail.com>"
],
"dependencies": {
"@necord/pagination": "^1.1.2",
"@nestjs/axios": "3.0.0",
"@nestjs/common": "9.4.3",
"@nestjs/config": "3.0.0",
Expand Down
6 changes: 4 additions & 2 deletions src/app.module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import { BitfieldsModule } from './bitfields/bitfields.module';
import { GeneralModule } from './general/general.module';
import { AppService } from './app.service';
import { TagsModule } from './tags/tags.module';
import { ChangelogModule } from './changelog/changelog.module';

@Module({
imports: [
Expand All @@ -18,14 +19,15 @@ import { TagsModule } from './tags/tags.module';
prefix: '!',
intents: ['Guilds', 'GuildMembers', 'MessageContent'],
development:
configService.get('NODE_ENV') === 'development'
configService.get('NODE_ENV', 'development') === 'development'
? ['742715858157043793', '977861813658075146']
: undefined
}),
inject: [ConfigService]
}),
DocsModule,
BitfieldsModule,
ChangelogModule,
DocsModule,
GeneralModule,
TagsModule
],
Expand Down
80 changes: 80 additions & 0 deletions src/changelog/changelog.controller.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
import { Injectable, OnModuleInit } from '@nestjs/common';
import { ChangelogService } from './changelog.service';
import { Context, SlashCommand, SlashCommandContext } from 'necord';
import { NecordPaginationService, PageBuilder } from '@necord/pagination';
import { map, switchMap, tap, timer } from 'rxjs';
import { EmbedBuilder, time } from 'discord.js';

@Injectable()
export class ChangelogController implements OnModuleInit {
public constructor(
private readonly changelogService: ChangelogService,
private readonly paginationService: NecordPaginationService
) {}

public onModuleInit() {
return timer(0, 1000 * 60 * 60)
.pipe(
switchMap(() => this.changelogService.changelog),
tap(changelog =>
this.paginationService.register(builder =>
builder
.setCustomId('changelog')
.setMaxPages(changelog.length)
.setPages(
changelog.map(release =>
new PageBuilder().addEmbed(
new EmbedBuilder()
.setAuthor({
name: release.author.login,
url: release.author.url,
iconURL: release.author.avatar_url
})
.setTitle(`Changelog`)
.setURL(release.url)
.setDescription(
release.body
.slice(0, 4096)
.replace('\r\n\r\n', '\n')
)
.setColor('Blurple')
.setFields([
{
name: 'Created At',
value: `${time(
new Date(release.created_at)
)} (${time(
new Date(release.created_at),
'R'
)})`,
inline: true
},
{
name: 'Published At',
value: `${time(
new Date(release.published_at)
)} (${time(
new Date(release.published_at),
'R'
)})`,
inline: true
}
])
.setFooter({ text: `Release ${release.tag_name}` })
)
)
)
)
)
)
.subscribe();
}

@SlashCommand({ name: 'changelog', description: 'Get the latest changelog' })
public async changelog(@Context() [interaction]: SlashCommandContext) {
const pageBuilder = this.paginationService.get('changelog');
const pageOptions = await pageBuilder.build();

return interaction.reply(pageOptions);
}
}
42 changes: 42 additions & 0 deletions src/changelog/changelog.module.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
import { Module } from '@nestjs/common';
import { NecordPaginationModule } from '@necord/pagination';
import { HttpModule } from '@nestjs/axios';
import { ChangelogService } from './changelog.service';
import { ChangelogController } from './changelog.controller';
import { ButtonStyle } from 'discord.js';

@Module({
imports: [
HttpModule.register({
baseURL: 'https://api.github.com'
}),
NecordPaginationModule.forRoot({
buttons: {
first: {
label: ' ',
style: ButtonStyle.Primary,
emoji: '⏮️'
},
back: {
label: ' ',
style: ButtonStyle.Primary,
emoji: '⬅️'
},
next: {
label: ' ',
style: ButtonStyle.Primary,
emoji: '➡️'
},
last: {
label: ' ',
style: ButtonStyle.Primary,
emoji: '⏭️'
}
},
allowSkip: true,
allowTraversal: false
})
],
providers: [ChangelogController, ChangelogService]
})
export class ChangelogModule {}
20 changes: 20 additions & 0 deletions src/changelog/changelog.service.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
import { Injectable } from '@nestjs/common';
import { HttpService } from '@nestjs/axios';
import { map } from 'rxjs';
import { Release } from './interfaces';
import { SharedReplayRefresh } from './helpers';

@Injectable()
export class ChangelogService {
private readonly dataSource = new SharedReplayRefresh<Release[]>();

private readonly changelog$ = this.httpService
.get<Release[]>('repos/necordjs/necord/releases')
.pipe(map(res => res.data));

public constructor(private readonly httpService: HttpService) {}

public get changelog() {
return this.dataSource.sharedReplayTimerRefresh(this.changelog$, 1, 1000 * 60 * 60);
}
}
1 change: 1 addition & 0 deletions src/changelog/helpers/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export * from './shared-replay-refresh.helper';
21 changes: 21 additions & 0 deletions src/changelog/helpers/shared-replay-refresh.helper.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
import { Observable, SchedulerLike, shareReplay } from 'rxjs';

export class SharedReplayRefresh<T> {
private sharedReplay$: Observable<T>;
private subscriptionTime: number;

sharedReplayTimerRefresh(
source: Observable<T>,
bufferSize = 1,
windowTime = 3000000,
scheduler?: SchedulerLike
): Observable<T> {
const currentTime = new Date().getTime();
if (!this.sharedReplay$ || currentTime - this.subscriptionTime > windowTime) {
this.sharedReplay$ = source.pipe(shareReplay(bufferSize, windowTime, scheduler));
this.subscriptionTime = currentTime;
}

return this.sharedReplay$;
}
}
1 change: 1 addition & 0 deletions src/changelog/interfaces/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export * from './release.interface';
15 changes: 15 additions & 0 deletions src/changelog/interfaces/release.interface.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
interface ReleaseAuthor {
login: string;
url: string;
avatar_url: string;
}

export interface Release {
tag_name: string;
name: string;
body: string;
url: string;
author: ReleaseAuthor;
created_at: string;
published_at: string;
}
8 changes: 0 additions & 8 deletions src/main.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,11 +11,3 @@ async function bootstrap() {
}

bootstrap();

process.on('uncaughtException', (err, origin) => {
logger.error(`Caught exception: ${err.message}\nException origin: ${origin}`, err);
});

process.on('unhandledRejection', (reason, promise) => {
logger.error(`Unhandled Rejection at: ${String(promise)}\nreason: ${String(reason)}`);
});
5 changes: 5 additions & 0 deletions yarn.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

0 comments on commit b8f3273

Please sign in to comment.