Skip to content

Commit

Permalink
Dev (#97)
Browse files Browse the repository at this point in the history
* chore(nest): add cli to deps

* docs(readme): update

* docs(readme): update badges

* chore(deps): @nestjs/swagger and class-transformer

* feat(common): app api, res model, decorators and errorfilter

* feat(swagger): setup swagger api docs

* feat(api): controllers, endpoints and dto definition

* chore(eslint)L setup linter

* feat: lint script

* feat(eslint): config

* style: apply fixes from lint

* test: fix pipeline

* fix: swagger setup

* fix(birthdaycontroller): class serializer without options throws

* refactor(folder-structure): move model dependent modules into models folder

* refactor: import paths
  • Loading branch information
sanriodev authored May 7, 2024
1 parent f184baa commit a848eb1
Show file tree
Hide file tree
Showing 47 changed files with 3,634 additions and 2,251 deletions.
Binary file modified bun.lockb
Binary file not shown.
10 changes: 10 additions & 0 deletions eslint.config.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
import globals from "globals";
import pluginJs from "@eslint/js";
import tseslint from "typescript-eslint";


export default [
{languageOptions: { globals: globals.browser }, rules: { "no-unused-vars": "error" },},
pluginJs.configs.recommended,
...tseslint.configs.recommended,
];
5,238 changes: 3,154 additions & 2,084 deletions package-lock.json

Large diffs are not rendered by default.

11 changes: 9 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,8 @@
"build:test": "docker build --pull --rm -f \"dockerfiles\\Dockerfile.test\" -t ghcr.io/blvckleg/bingusboingus:test \".\"",
"test:image": "docker run bingusboingus:test npm run test",
"test": "jest",
"test:watch": "jest --watch"
"test:watch": "jest --watch",
"lint": "eslint . --fix"
},
"repository": {
"type": "git",
Expand All @@ -33,8 +34,10 @@
"@nestjs/core": "^10.2.6",
"@nestjs/mongoose": "^10.0.2",
"@nestjs/platform-express": "^10.2.6",
"@nestjs/swagger": "^7.3.1",
"@nestjs/testing": "^10.2.6",
"@types/jest": "^29.5.5",
"class-transformer": "^0.5.1",
"class-validator": "^0.14.1",
"discord-interactions": "^3.4.0",
"discord.js": "^14.13.0",
Expand All @@ -53,8 +56,12 @@
"typescript": "^5.2.2"
},
"devDependencies": {
"@eslint/js": "^9.2.0",
"@types/express": "^4.17.17",
"prettier": "3.0.3"
"eslint": "^8.57.0",
"globals": "^15.1.0",
"prettier": "3.0.3",
"typescript-eslint": "^7.8.0"
},
"jest": {
"moduleFileExtensions": [
Expand Down
12 changes: 12 additions & 0 deletions src/app.controller.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
import { Controller, Get } from '@nestjs/common';
import { AppService } from './app.service';

@Controller()
export class AppController {
constructor(private readonly appService: AppService) {}

@Get('/')
getHello(): string {
return this.appService.getHello();
}
}
4 changes: 4 additions & 0 deletions src/app.module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@ import { EventModule } from './modules/event/event.module';
import { DeployModule } from './deployment/deploy.module';
import { MongoDatabaseProviderModule } from './config/database/mongo/provider/mongo-provider.module';
import { TaskModule } from './modules/cron-tasks/task.module';
import { AppController } from './app.controller';
import { AppService } from './app.service';

@Module({
imports: [
Expand All @@ -17,5 +19,7 @@ import { TaskModule } from './modules/cron-tasks/task.module';
MongoDatabaseProviderModule,
TaskModule
],
controllers: [AppController],
providers: [AppService],
})
export class AppModule {}
9 changes: 9 additions & 0 deletions src/app.service.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
import { Injectable } from '@nestjs/common';

@Injectable()
export class AppService {
getHello(): string {
return 'Hello World!';
}
}

51 changes: 51 additions & 0 deletions src/common/decoratos/apires.decorator.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
import { Type, applyDecorators } from '@nestjs/common';
import {
ApiCreatedResponse,
ApiOkResponse,
getSchemaPath,
} from '@nestjs/swagger';
import { ReS } from '../res.model';

export const ApiReS = <TModel extends Type<any>>(
model: TModel,
description: string,
status?: number,
) => {
if (status === 201) {
return applyDecorators(
ApiCreatedResponse({
description,
schema: {
allOf: [
{ $ref: getSchemaPath(ReS) },
{
properties: {
data: {
$ref: getSchemaPath(model),
},
},
},
],
},
}),
);
}

return applyDecorators(
ApiOkResponse({
description,
schema: {
allOf: [
{ $ref: getSchemaPath(ReS) },
{
properties: {
data: {
$ref: getSchemaPath(model),
},
},
},
],
},
}),
);
};
44 changes: 44 additions & 0 deletions src/common/filters/error.filter.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
import {
ExceptionFilter,
Catch,
HttpException,
ArgumentsHost,
HttpStatus,
} from '@nestjs/common';
import { ReE } from '../res.model';

@Catch()
export class ErrorFilter implements ExceptionFilter {
catch(error: Error, host: ArgumentsHost) {
const ctx = host.switchToHttp();
const response = ctx.getResponse();
const statusCode: number =
error instanceof HttpException
? error.getStatus()
: HttpStatus.INTERNAL_SERVER_ERROR;

let message;
console.error(error);
if (error instanceof HttpException) {
const errorMessage = (error.getResponse() as any)?.message;
message = Array.isArray(errorMessage) ? errorMessage : [errorMessage];
} else {
message = [error.message];
}

const name =
error instanceof HttpException
? (error.getResponse() as any)?.error || error.name
: error.name;

const responseWithStatusCode = response.status(statusCode);
const errorPayload = ReE.FromData(statusCode, name, message);
// watch out for fastify
if (typeof responseWithStatusCode.json === 'undefined') {
responseWithStatusCode.send(errorPayload);
} else {
responseWithStatusCode.json(errorPayload);
}
}
}

35 changes: 35 additions & 0 deletions src/common/res.model.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
import { ApiProperty } from '@nestjs/swagger';

export class ReturnHelper {
@ApiProperty({ example: true, description: 'success indicator' })
public success = true;
}

export class ReS<T> extends ReturnHelper {
static FromData<T>(arg0: T): ReS<T> {
const ret = new ReS<T>();
ret.success = true;
ret.data = arg0;
return ret;
}

public data: T;
}

export class ReE extends ReturnHelper {
static FromData(statusCode: number, error: string, message: string[]): ReE {
const ret = new ReE();
ret.success = false;
ret.message = message;
ret.error = error;
ret.statusCode = statusCode;
return ret;
}
@ApiProperty({ description: 'statusCode' })
public statusCode: number;
@ApiProperty({ description: 'detail message' })
public message: string[];
@ApiProperty({ description: 'error description' })
public error: string;
}

9 changes: 4 additions & 5 deletions src/deployment/deploy.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,20 +2,19 @@ import { REST, RESTPostAPIChatInputApplicationCommandsJSONBody, Routes } from 'd
import { Injectable } from '@nestjs/common';
import { CommandService } from '../modules/command/command.service';
import { AppConfigService } from '../config/config.service';
import { ConfigService } from '@nestjs/config';

@Injectable()
export class DeployServcice {
constructor(
private readonly commandService: CommandService,
private readonly configService: AppConfigService,
) {
var commands = this.loadCommands();
const commands = this.loadCommands();
this.deployCommands(commands);
}

loadCommands(): RESTPostAPIChatInputApplicationCommandsJSONBody[] {
var commands = this.commandService.getAllCommands();
const commands = this.commandService.getAllCommands();
return commands.map((command) => command.data.toJSON());
}

Expand All @@ -28,11 +27,11 @@ export class DeployServcice {
console.log(`Started refreshing ${commands.length} application (/) commands.`);

// The put method is used to fully refresh all commands in the guild with the current set
const data = await rest.put(Routes.applicationGuildCommands(process.env.CLIENT_ID, process.env.SERVER_ID), {
const data = await rest.put(Routes.applicationGuildCommands(process.env.CLIENT_ID ?? '', process.env.SERVER_ID ?? ''), {
body: commands,
});

var log = '';
let log = '';
if (Array.isArray(data)) log = data.length + ' ';
console.log(`Successfully reloaded ${log}application (/) commands.`);
} catch (error) {
Expand Down
28 changes: 27 additions & 1 deletion src/main.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@ import { Reflector } from '@nestjs/core';
import { NestFactory } from '@nestjs/core';
import { AppModule } from './app.module';
import { AppConfigService } from './config/config.service';
import { ErrorFilter } from './common/filters/error.filter';
import { DocumentBuilder, SwaggerModule } from '@nestjs/swagger';

async function bootstrap() {
const app = await NestFactory.create(AppModule, {
Expand All @@ -13,11 +15,35 @@ async function bootstrap() {
const appConfig: AppConfigService = app.get(AppConfigService);

app.setGlobalPrefix('api/v1');
app.useGlobalFilters(new ErrorFilter());
app.useGlobalInterceptors(app.get(Reflector));

bootstrapSwagger(app, appConfig);
await app.startAllMicroservices();

await app.listen(appConfig.appPort);
}

async function bootstrapSwagger(
app: INestApplication,
appConfig: AppConfigService,
) {

const config = new DocumentBuilder()
.setTitle('BingusBoingus API')
.setDescription('BingusBoingus REST API Documentation')
.setVersion('1.0').setBasePath('api/v1')
.build();

const document = SwaggerModule.createDocument(app, config, {
ignoreGlobalPrefix: false,

});

SwaggerModule.setup('api/v1/doc', app, document, {
customSiteTitle: 'API Docs',
explorer: true,
} as unknown as any);
}


bootstrap();
8 changes: 4 additions & 4 deletions src/modules/command/command.module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,16 +8,16 @@ import { BugReport } from './commands/bug';
import { CoinflipCommand } from './commands/coinflip';
import { GoldCommand } from './commands/gold';
import SomeoneOnceSaidCommand from './commands/someone-once-said';
import { SomeoneOnceSaidModule } from '../someone-once-said/module/someone-once-said.module';
import GetRandomQuote from './commands/get-a-quote';
import { PollCommand } from './commands/poll';
import { PollModule } from '../poll/module/poll.module';
import { VersionModule } from '../version/module/version.module';
import { VersionCommand } from './commands/version';
import { BirthdayEntryModule } from '../birthday/module/birthday-entry.module';
import AddBirthdayEntryCommand from './commands/add-birthday-entry';
import ActivateBirthdayEntryShoutoutCommand from './commands/activate-birthday-shoutout';
import DeactivateBirthdayEntryShoutoutCommand from './commands/deactivate-birthday-shoutout';
import { SomeoneOnceSaidModule } from '../models/someone-once-said/module/someone-once-said.module';
import { PollModule } from '../models/poll/module/poll.module';
import { VersionModule } from '../models/version/module/version.module';
import { BirthdayEntryModule } from '../models/birthday/module/birthday-entry.module';

@Module({
providers: [
Expand Down
6 changes: 3 additions & 3 deletions src/modules/command/command.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ export class CommandService {
activateBirthdayEntryShoutoutModule,
];
commands.forEach((command) => {
if (command.data.name && command.execute) {
if (command.data.name && !!command.execute) {
console.log('command-name: ' + command.data.name);
this.commands.set(command.data.name, command);
} else {
Expand All @@ -62,9 +62,9 @@ export class CommandService {
});
}

public getCommand(commandName: string): ACommand {
public getCommand(commandName: string): ACommand | undefined {
if (this.commands.has(commandName)) return this.commands.get(commandName);
return null;
return;
}

getAllCommands() {
Expand Down
8 changes: 4 additions & 4 deletions src/modules/command/commands/activate-birthday-shoutout.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,8 @@ import {
} from 'discord.js';
import { ACommand } from '../command.abstract';
import { Inject } from '@nestjs/common';
import { BirthdayEntryService } from '../../birthday/service/birthday-entry.service';
import { BirthdayEntry } from '../../../schemas/birthday-entry.schema';
import { BirthdayEntryService } from '../../models/birthday/service/birthday-entry.service';
import { CreateOrUpdateBirthdayEntryDto } from '../../models/birthday/dto/create-or-update-birthday-entry.dto';

export default class ActivateBirthdayEntryShoutoutCommand extends ACommand {
constructor(
Expand All @@ -23,11 +23,11 @@ import {

async execute(arg: CommandInteraction<CacheType>): Promise<boolean> {
await arg.deferReply();
const instance = new BirthdayEntry({
const instance: CreateOrUpdateBirthdayEntryDto ={
username: arg.user.username,
secName: arg.user.displayName,
active: true
});
};
const inactive =
await this.birthdayEntryService.updateBirthdayEntry(instance);
if (!inactive) {
Expand Down
Loading

0 comments on commit a848eb1

Please sign in to comment.