Skip to content

Commit

Permalink
Fixed file sturucture and incorporated feedback
Browse files Browse the repository at this point in the history
  • Loading branch information
jaipise authored and tmthecoder committed Mar 30, 2024
1 parent 6c9e8ed commit 9fc996b
Show file tree
Hide file tree
Showing 8 changed files with 105 additions and 69 deletions.
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@
},
"dependencies": {
"@sendgrid/mail": "^8.1.1",
"axios": "^1.6.7",
"bcrypt": "^5.1.1",
"fs-extra": "^11.2.0",
"jsonwebtoken": "^9.0.2"
Expand Down
9 changes: 1 addition & 8 deletions packages/email-service/src/app.controller.ts
Original file line number Diff line number Diff line change
@@ -1,14 +1,7 @@
import { Post, Body, Controller } from '@nestjs/common';
import { Controller } from '@nestjs/common';
import { AppService } from './app.service';
import { EmailProto } from 'juno-proto';

@Controller()
export class AppController {
constructor(private readonly appService: AppService) {}
@Post('/register-sender')
async registerSender(
@Body() req: EmailProto.RegisterSenderRequest,
): Promise<EmailProto.RegisterSenderResponse> {
return await this.appService.registerSender(req);
}
}
53 changes: 1 addition & 52 deletions packages/email-service/src/app.service.ts
Original file line number Diff line number Diff line change
@@ -1,55 +1,4 @@
import { Injectable } from '@nestjs/common';
import { EmailProto } from 'juno-proto';
import axios from 'axios';
import { RpcException } from '@nestjs/microservices';

@Injectable()
export class AppService {
async registerSender(
req: EmailProto.RegisterSenderRequest,
): Promise<EmailProto.RegisterEmailResponse> {
if (!req.from_email) {
throw new RpcException('Cannot register sender (no email supplied)');
}
if (!req.from_name) {
throw new RpcException('Cannot register sender (no name supplied)');
}
if (!req.reply_to) {
throw new RpcException('Cannot register sender (no reply to specified)');
}

const sendgridApiKey = process.env.SENDGRID_API_KEY;

if (!sendgridApiKey) {
throw new RpcException(
'Cannot register sender (sendgrid API key is missing)',
);
}
const sendgridUrl = 'https://api.sendgrid.com/v3/verified_senders';

try {
const res = await axios.post(
sendgridUrl,
{
from_email: req.from_email,
from_name: req.from_name,
reply_to: req.reply_to,
},
{
headers: {
Authorization: `Bearer ${sendgridApiKey}`,
'Content-Type': 'application/json',
},
},
);

return {
statusCode: res.status,
message: 'Sender registered successfully',
};
} catch (err) {
console.error('error registering sender:', err);
throw new RpcException('Unable to register sender');
}
}
}
export class AppService {}
7 changes: 6 additions & 1 deletion packages/email-service/src/modules/email/email.controller.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import { status } from '@grpc/grpc-js';
@Controller()
@EmailProto.EmailServiceControllerMethods()
export class EmailController implements EmailProto.EmailServiceController {
constructor(private readonly emailService: EmailService) {}
constructor(private readonly emailService: EmailService) { }

async sendEmail(
request: EmailProto.SendEmailRequest,
Expand Down Expand Up @@ -57,4 +57,9 @@ export class EmailController implements EmailProto.EmailServiceController {
throw new RpcException(error.message);
}
}
async registerSender(
req: EmailProto.RegisterSenderRequest,
): Promise<EmailProto.RegisterSenderResponse> {
return await this.emailService.registerSender(req);
}
}
54 changes: 54 additions & 0 deletions packages/email-service/src/modules/email/email.service.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
import { Injectable } from '@nestjs/common';
import { EmailProto } from 'juno-proto';
import { SendGridService } from 'src/sendgrid.service';
import axios from 'axios';
import { RpcException } from '@nestjs/microservices';

@Injectable()
export class EmailService {
Expand All @@ -24,4 +26,56 @@ export class EmailService {
});
}
}

async registerSender(
req: EmailProto.RegisterSenderRequest,
): Promise<EmailProto.RegisterSenderResponse> {
if (process.env.SENDGRID_API_KEY) {
if (!req.fromEmail) {
throw new RpcException('Cannot register sender (no email supplied)');
}
if (!req.fromName) {
throw new RpcException('Cannot register sender (no name supplied)');
}
if (!req.replyTo) {
throw new RpcException(
'Cannot register sender (no reply to specified)',
);
}

const sendgridApiKey = process.env.SENDGRID_API_KEY;
const sendgridUrl = 'https://api.sendgrid.com/v3/verified_senders';

if (!sendgridApiKey) {
throw new RpcException(
'Cannot register sender (sendgrid API key is missing)',
);
}

try {
const res = await axios.post(
sendgridUrl,
{
fromEmail: req.fromEmail,
fromName: req.fromName,
replyTo: req.replyTo,
},
{
headers: {
Authorization: `Bearer ${sendgridApiKey}`,
'Content-Type': 'application/json',
},
},
);

return {
statusCode: res.status,
message: 'Sender registered successfully',
};
} catch (err) {
console.error('error registering sender:', err);
throw new RpcException('Unable to register sender');
}
}
}
}
20 changes: 14 additions & 6 deletions packages/email-service/test/app.e2e-spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -38,12 +38,20 @@ beforeAll(async () => {

const protoGRPC = GRPC.loadPackageDefinition(proto) as any;

const resetClient = new protoGRPC.juno.reset_db.DatabaseReset(
process.env.DB_SERVICE_ADDR,
GRPC.credentials.createInsecure(),
);

const emailClient = new protoGRPC.juno.emailService(
process.env.DB_SERVICE_ADDR,
GRPC.credentials.createInsecure(),
);

await new Promise((resolve) => {
resetClient.resetDb({}, () => {
resolve(0);
});
emailClient.resetDb({}, () => {
resolve(0);
});
Expand All @@ -59,9 +67,9 @@ it('should successfully register a sender', async () => {
(resolve, reject) => {
emailClient.registerSender(
{
from_email: '[email protected]',
from_name: 'example',
reply_to: '[email protected]',
fromEmail: '[email protected]',
fromName: 'example',
replyTo: '[email protected]',
},
(err: any, response: EmailProto.RegisterSenderResponse) => {
if (err) {
Expand All @@ -83,9 +91,9 @@ it('should fail to register a sender', async () => {
(resolve, reject) => {
emailClient.registerSender(
{
from_email: '',
from_name: '',
reply_to: '',
fromEmail: '',
fromName: '',
replyTo: '',
},
(err: any, response: EmailProto.RegisterSenderResponse) => {
if (err) {
Expand Down
28 changes: 27 additions & 1 deletion packages/proto/src/gen/email.ts
Original file line number Diff line number Diff line change
Expand Up @@ -51,10 +51,29 @@ export interface UpdateEmailRequest {
updateParams: EmailUpdateParams | undefined;
}

export interface SendEmailRequestResponse {
success: boolean;
}

export interface RegisterSenderRequest {
fromEmail: string;
fromName: string;
replyTo: string;
}

export interface RegisterSenderResponse {
statusCode: number;
message: string;
}

export const JUNO_EMAIL_PACKAGE_NAME = 'juno.email';

export interface EmailServiceClient {
sendEmail(request: SendEmailRequest): Observable<SendEmailResponse>;

registerSender(
request: RegisterSenderRequest,
): Observable<RegisterSenderResponse>;
}

export interface EmailServiceController {
Expand All @@ -64,11 +83,18 @@ export interface EmailServiceController {
| Promise<SendEmailResponse>
| Observable<SendEmailResponse>
| SendEmailResponse;

registerSender(
request: RegisterSenderRequest,
):
| Promise<RegisterSenderResponse>
| Observable<RegisterSenderResponse>
| RegisterSenderResponse;
}

export function EmailServiceControllerMethods() {
return function (constructor: Function) {
const grpcMethods: string[] = ['sendEmail'];
const grpcMethods: string[] = ['sendEmail', 'registerSender'];
for (const method of grpcMethods) {
const descriptor: any = Reflect.getOwnPropertyDescriptor(
constructor.prototype,
Expand Down
2 changes: 1 addition & 1 deletion yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -1828,7 +1828,7 @@ [email protected]:
form-data "^4.0.0"
proxy-from-env "^1.1.0"

axios@^1.6.0, axios@^1.6.4:
axios@^1.6.0, axios@^1.6.4, axios@^1.6.7:
version "1.6.8"
resolved "https://registry.yarnpkg.com/axios/-/axios-1.6.8.tgz#66d294951f5d988a00e87a0ffb955316a619ea66"
integrity sha512-v/ZHtJDU39mDpyBoFVkETcd/uNdxrWRrg3bKpOKzXFA6Bvqopts6ALSMU3y6ijYxbw2B+wPrIv46egTzJXCLGQ==
Expand Down

0 comments on commit 9fc996b

Please sign in to comment.