Skip to content

Commit

Permalink
feat(Api): Added Feedback Form Controller
Browse files Browse the repository at this point in the history
  • Loading branch information
rayaanoidPrime committed May 12, 2024
1 parent 8762354 commit f5bf431
Show file tree
Hide file tree
Showing 10 changed files with 225 additions and 1 deletion.
4 changes: 3 additions & 1 deletion apps/api/src/app/app.module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ import { ProviderModule } from '../provider/provider.module'
import { ScheduleModule } from '@nestjs/schedule'
import { EnvSchema } from '../common/env/env.schema'
import { IntegrationModule } from '../integration/integration.module'
import { FeedbackModule } from '../feedback/feedback.module'

@Module({
controllers: [AppController],
Expand Down Expand Up @@ -54,7 +55,8 @@ import { IntegrationModule } from '../integration/integration.module'
ApprovalModule,
SocketModule,
ProviderModule,
IntegrationModule
IntegrationModule,
FeedbackModule
],
providers: [
{
Expand Down
25 changes: 25 additions & 0 deletions apps/api/src/feedback/controller/feedback.controller.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
import { Test, TestingModule } from '@nestjs/testing'
import { FeedbackController } from './feedback.controller'
import { FeedbackService } from '../service/feedback.service'
import { MAIL_SERVICE } from '../../mail/services/interface.service'
import { MockMailService } from '../../mail/services/mock.service'

describe('FeedbackController', () => {
let controller: FeedbackController

beforeEach(async () => {
const module: TestingModule = await Test.createTestingModule({
controllers: [FeedbackController],
providers: [
FeedbackService,
{ provide: MAIL_SERVICE, useValue: MockMailService }
]
}).compile()

controller = module.get<FeedbackController>(FeedbackController)
})

it('should be defined', () => {
expect(controller).toBeDefined()
})
})
16 changes: 16 additions & 0 deletions apps/api/src/feedback/controller/feedback.controller.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
import { Controller, Post, Body } from '@nestjs/common'
import { Public } from '../../decorators/public.decorator'
import { FeedbackService } from '../service/feedback.service'
import { ApiTags } from '@nestjs/swagger'

@ApiTags('Feedback Controller')
@Controller('feedback')
export class FeedbackController {
constructor(private readonly feedbackService: FeedbackService) {}

@Public()
@Post()
async registerFeedback(@Body('feedback') feedback: string): Promise<void> {
await this.feedbackService.registerFeedback(feedback)
}
}
100 changes: 100 additions & 0 deletions apps/api/src/feedback/feedback.e2e.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,100 @@
import { Test, TestingModule } from '@nestjs/testing'
import { AppModule } from '../app/app.module'
import { FeedbackService } from '../feedback/service/feedback.service'
import { MockMailService } from '../mail/services/mock.service'
import {
FastifyAdapter,
NestFastifyApplication
} from '@nestjs/platform-fastify'
import { MAIL_SERVICE } from '../mail/services/interface.service'
import { FeedbackModule } from './feedback.module'
import { MailModule } from '../mail/mail.module'
import { PrismaService } from '../prisma/prisma.service'
import { User } from '@prisma/client'
import cleanUp from '../common/cleanup'

describe('Feedback Controller (E2E)', () => {
let app: NestFastifyApplication
let feedbackService: FeedbackService
let mockMailService: MockMailService
let prisma: PrismaService
let user: User

beforeAll(async () => {
const moduleRef: TestingModule = await Test.createTestingModule({
imports: [AppModule, FeedbackModule, MailModule]
})
.overrideProvider(MAIL_SERVICE)
.useClass(MockMailService)
.compile()

app = moduleRef.createNestApplication<NestFastifyApplication>(
new FastifyAdapter()
)
feedbackService = moduleRef.get(FeedbackService)
mockMailService = moduleRef.get(MAIL_SERVICE)

prisma = moduleRef.get(PrismaService)

await app.init()
await app.getHttpAdapter().getInstance().ready()

await cleanUp(prisma)

user = await prisma.user.create({
data: {
email: '[email protected]',
name: 'John',
isActive: true,
isAdmin: false,
isOnboardingFinished: false
}
})
})

afterAll(async () => {
await cleanUp(prisma)
await prisma.$disconnect()
await app.close()
})

it('should be defined', async () => {
expect(app).toBeDefined()
expect(feedbackService).toBeDefined()
expect(mockMailService).toBeDefined()
expect(prisma).toBeDefined()
})

it('should register feedback successfully', async () => {
const feedbackMessage = 'Test feedback message'

const { statusCode } = await app.inject({
method: 'POST',
url: '/feedback',
payload: { feedback: feedbackMessage },
headers: {
'x-e2e-user-email': user.email
}
})

expect(statusCode).toBe(201)
})

it('should handle empty feedback', async () => {
const { statusCode, payload } = await app.inject({
method: 'POST',
url: '/feedback',
payload: { feedback: '' },
headers: {
'x-e2e-user-email': user.email
}
})

expect(statusCode).toBe(400)
expect(JSON.parse(payload)).toEqual({
error: 'Bad Request',
message: 'Feedback cannot be null',
statusCode: 400
})
})
})
9 changes: 9 additions & 0 deletions apps/api/src/feedback/feedback.module.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
import { Module } from '@nestjs/common'
import { FeedbackService } from './service/feedback.service'
import { FeedbackController } from './controller/feedback.controller'

@Module({
providers: [FeedbackService],
controllers: [FeedbackController]
})
export class FeedbackModule {}
23 changes: 23 additions & 0 deletions apps/api/src/feedback/service/feedback.service.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
import { Test, TestingModule } from '@nestjs/testing'
import { FeedbackService } from './feedback.service'
import { MAIL_SERVICE } from '../../mail/services/interface.service'
import { MockMailService } from '../../mail/services/mock.service'

describe('FeedbackService', () => {
let service: FeedbackService

beforeEach(async () => {
const module: TestingModule = await Test.createTestingModule({
providers: [
FeedbackService,
{ provide: MAIL_SERVICE, useClass: MockMailService }
]
}).compile()

service = module.get<FeedbackService>(FeedbackService)
})

it('should be defined', () => {
expect(service).toBeDefined()
})
})
21 changes: 21 additions & 0 deletions apps/api/src/feedback/service/feedback.service.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
import { BadRequestException, Inject, Injectable } from '@nestjs/common'
import {
IMailService,
MAIL_SERVICE
} from '../../mail/services/interface.service'

@Injectable()
export class FeedbackService {
constructor(
@Inject(MAIL_SERVICE) private readonly mailService: IMailService
) {}

async registerFeedback(feedback: string): Promise<void> {
if (!feedback) {
throw new BadRequestException('Feedback cannot be null')
}
const adminEmail = '[email protected]'

await this.mailService.feedbackEmail(adminEmail, feedback)
}
}
2 changes: 2 additions & 0 deletions apps/api/src/mail/services/interface.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,4 +14,6 @@ export interface IMailService {
accountLoginEmail(email: string): Promise<void>

adminUserCreateEmail(email: string): Promise<void>

feedbackEmail(email: string, feedback: string): Promise<void>
}
22 changes: 22 additions & 0 deletions apps/api/src/mail/services/mail.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -111,6 +111,28 @@ export class MailService implements IMailService {
await this.sendEmail(process.env.ADMIN_EMAIL, subject, body)
}

async feedbackEmail(email: string, feedback: string): Promise<void> {
const subject = 'New Feedback Received !'
const body = `<!DOCTYPE html>
<html>
<head>
<title>New Feedback Received !</title>
</head>
<body>
<h1>New Feedback Received</h1>
<p>Hello,</p>
<p>We have received new feedback from a user:</p>
<blockquote>${feedback}</blockquote>
<p>Please review this feedback as soon as possible.</p>
<p>Thank you.</p>
<p>Best Regards,</p>
<p>Keyshade Team</p>
</body>
</html>
`
await this.sendEmail(email, subject, body)
}

private async sendEmail(
email: string,
subject: string,
Expand Down
4 changes: 4 additions & 0 deletions apps/api/src/mail/services/mock.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -30,4 +30,8 @@ export class MockMailService implements IMailService {
async accountLoginEmail(email: string): Promise<void> {
this.log.log(`Account Login Email for ${email}`)
}

async feedbackEmail(email: string, feedback: string): Promise<void> {
this.log.log(`Feedback is : ${feedback}, for email : ${email}`)
}
}

0 comments on commit f5bf431

Please sign in to comment.