Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(api): Add workspace removal notification email template #476

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
34 commits
Select commit Hold shift + click to select a range
0a1f923
feat: add project removal notification email template
Allan2000-Git Oct 4, 2024
e27d394
fix: rename project to workspace and minor ui changes
Allan2000-Git Oct 6, 2024
2fff238
feat: create template using react-email
Allan2000-Git Oct 8, 2024
b1ff06a
feat: add project removal notification email template
Allan2000-Git Oct 4, 2024
f71846e
fix: rename project to workspace and minor ui changes
Allan2000-Git Oct 6, 2024
05cfe56
feat: create template using react-email
Allan2000-Git Oct 8, 2024
66344be
Merge branch 'feat/project-removal-email-template' of https://github.…
Allan2000-Git Oct 13, 2024
257d69b
feat: use react email to create workspace removal email template
Allan2000-Git Oct 13, 2024
ae040dc
Merge branch 'develop' into feat/project-removal-email-template
Allan2000-Git Oct 13, 2024
316f7d6
fix: fix merge conflicts
Allan2000-Git Oct 13, 2024
140a5c5
fix: fix module not found error in test file
Allan2000-Git Oct 13, 2024
87cbf59
fix: revert the changes by removing extension
Allan2000-Git Oct 13, 2024
7b50ef2
nit: rename subject and email template name
Allan2000-Git Oct 14, 2024
155b648
Merge branch 'develop' into feat/project-removal-email-template
Allan2000-Git Oct 16, 2024
7871eca
nit: rename method name from workspaceRemoval to removedFromWorkspace
Allan2000-Git Oct 16, 2024
300e955
Merge branch 'feat/project-removal-email-template' of https://github.…
Allan2000-Git Oct 16, 2024
1955078
Merge branch 'develop' into feat/project-removal-email-template
rajdip-b Oct 17, 2024
d4b11bc
chore: branch update
Allan2000-Git Nov 18, 2024
5b42e4f
fix: rename tsx to ts extension
Allan2000-Git Nov 18, 2024
7b04d40
chore: add tsx to moduleFileExtensions in jest config file
Allan2000-Git Nov 18, 2024
f736123
chore: add tsx to moduleFileExtensions in jest-e2e config file
Allan2000-Git Nov 18, 2024
e948b56
chore: update regex to support tsx in jest & jest-e2e config file
Allan2000-Git Nov 18, 2024
b37cee3
chore: installed react types
Allan2000-Git Nov 19, 2024
1d1802e
chore: updated pnpm lock file
Allan2000-Git Nov 19, 2024
8d48510
fix: remove mail.service.tsx file (renamed to .ts)
Allan2000-Git Nov 19, 2024
4bf5f94
Merge branch 'develop' into feat/project-removal-email-template
rajdip-b Nov 27, 2024
055755c
chore: updated pnpm lock file
Allan2000-Git Nov 27, 2024
7d9585d
feat(api): implement send email upon removal from wrokspace and chang…
muntaxir4 Nov 27, 2024
b832359
fix: fixed formatting of date in the email template using dayjs
Allan2000-Git Dec 1, 2024
ba690ae
chore: updated package.json file for api
Allan2000-Git Dec 1, 2024
0fec7c7
fix: fixed prettier problem of async keyword by moving comment inside…
Allan2000-Git Dec 1, 2024
1d535ce
fix: integrate localized date formatting with dayjs
Allan2000-Git Dec 1, 2024
5acf18e
feat: used custom dayjs format
Allan2000-Git Dec 1, 2024
517affa
Merge branch 'develop' into feat/project-removal-email-template
Allan2000-Git Dec 1, 2024
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions apps/api/jest.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,11 @@ export default {
testMatch: ['**/*.spec.ts'],
testPathIgnorePatterns: ['.*.e2e.spec.ts'],
transform: {
'^.+\\.[tj]s$': ['ts-jest', { tsconfig: '<rootDir>/tsconfig.spec.json' }]
'^.+\\.[tj]sx?$': ['ts-jest', { tsconfig: '<rootDir>/tsconfig.spec.json' }]
},
moduleNameMapper: {
'^@/(.*)$': '<rootDir>/src/$1'
},
moduleFileExtensions: ['ts', 'js', 'html'],
moduleFileExtensions: ['ts', 'js', 'html', 'tsx', 'jsx'],
coverageDirectory: '../../coverage/apps/api'
}
4 changes: 2 additions & 2 deletions apps/api/jest.e2e-config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,12 @@ export default {
testEnvironment: 'node',
testMatch: ['**/*.e2e.spec.ts'],
transform: {
'^.+\\.[tj]s$': ['ts-jest', { tsconfig: '<rootDir>/tsconfig.spec.json' }]
'^.+\\.[tj]sx?$': ['ts-jest', { tsconfig: '<rootDir>/tsconfig.spec.json' }]
},
moduleNameMapper: {
'^@/(.*)$': '<rootDir>/src/$1'
},
moduleFileExtensions: ['ts', 'js', 'html'],
moduleFileExtensions: ['ts', 'js', 'html', 'tsx', 'jsx'],
coverageDirectory: '../../coverage/apps/api',
coverageReporters: ['json'],
collectCoverage: true
Expand Down
2 changes: 2 additions & 0 deletions apps/api/package-lock.json

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

7 changes: 7 additions & 0 deletions apps/api/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -34,17 +34,22 @@
"@nestjs/swagger": "^7.3.0",
"@nestjs/throttler": "^6.2.1",
"@nestjs/websockets": "^10.3.7",
"@react-email/components": "^0.0.25",
"@react-email/preview": "0.0.11",
"@react-email/render": "^1.0.1",
"@socket.io/redis-adapter": "^8.3.0",
"@supabase/supabase-js": "^2.39.6",
"class-transformer": "^0.5.1",
"class-validator": "^0.14.1",
"cookie-parser": "^1.4.6",
"dayjs": "^1.11.11",
"eccrypto": "^1.1.6",
"minio": "^8.0.0",
"nodemailer": "^6.9.9",
"passport-github2": "^0.1.12",
"passport-gitlab2": "^5.0.0",
"passport-google-oauth20": "^2.0.0",
"react": "^18.3.1",
"redis": "^4.6.13",
"rxjs": "^7.8.1",
"socket.io": "^4.7.5",
Expand All @@ -59,10 +64,12 @@
"@types/eccrypto": "^1.1.6",
"@types/express": "^4.17.17",
"@types/multer": "^1.4.11",
"@types/react": "^18.3.12",
"@types/supertest": "^6.0.0",
"@types/uuid": "^9.0.8",
"ajv": "^7",
"dotenv-cli": "^7.4.2",
"file-loader": "^6.2.0",
"jest": "^29.5.0",
"jest-mock-extended": "^3.0.5",
"prettier": "^3.0.0",
Expand Down
151 changes: 151 additions & 0 deletions apps/api/src/mail/emails/workspace-removal.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,151 @@
import * as React from 'react'
import {
Body,
Container,
Head,
Heading,
Html,
Link,
Preview,
Section,
Text
} from '@react-email/components'
import dayjs from 'dayjs'

interface WorkspaceRemovalEmailProps {
workspaceName: string
removedOn: string
}

export const RemovedFromWorkspaceEmail = ({
workspaceName,
removedOn
}: WorkspaceRemovalEmailProps) => {
const formattedRemovedOnDate = dayjs(removedOn).format(
'ddd, MMM D, YYYY h:mm A'
)

return (
<Html>
<Head />
<Preview>Removal from Workspace</Preview>
<Body style={main}>
<Container style={container}>
<Section style={content}>
<Heading style={h1}>Removal from Workspace</Heading>
<Text style={text}>Dear User,</Text>
<Text style={text}>
We hope this email finds you well. We are writing to inform you
that your access to the following workspace has been removed:
</Text>
<Section style={workspaceDetails}>
<Text style={workspaceInfo}>
<strong>Workspace Name:</strong> {workspaceName}
</Text>
<Text style={workspaceInfo}>
<strong>Removed On:</strong> {formattedRemovedOnDate}
</Text>
</Section>
<Text style={text}>
If you believe this action was taken in error or have any
questions regarding this change, please contact your project
administrator or our support team.
</Text>
<Text style={text}>
We appreciate your understanding and thank you for your
contributions to the project.
</Text>
<Text style={text}>
Cheers,
<br />
Team Keyshade
</Text>
</Section>
<Section style={footer}>
<Text style={footerText}>
This is an automated message. Please do not reply to this email.
</Text>
<Text style={footerText}>
Read our{' '}
<Link href="https://www.keyshade.xyz/privacy" style={link}>
Privacy Policy
</Link>{' '}
and{' '}
<Link
href="https://www.keyshade.xyz/terms_and_condition"
style={link}
>
Terms and Conditions
</Link>{' '}
for more information on how we manage your data and services.
</Text>
</Section>
</Container>
</Body>
</Html>
)
}

export default RemovedFromWorkspaceEmail

const main = {
fontFamily: "'Segoe UI', 'Roboto', sans-serif",
lineHeight: '1.6',
color: '#04050a',
backgroundColor: '#fafafa',
margin: '0',
padding: '20px'
}

const container = {
maxWidth: '600px',
margin: '0 auto',
backgroundColor: '#fff',
borderRadius: '5px',
boxShadow: '0 2px 8px rgba(0, 0, 0, 0.05)'
}

const content = {
padding: '20px 40px'
}

const h1 = {
color: '#000',
marginBottom: '20px',
fontSize: '24px',
fontWeight: '600'
}

const text = {
marginBottom: '5px',
color: '#666'
}

const workspaceDetails = {
width: '100%',
backgroundColor: '#fafafa',
borderRadius: '5px',
margin: '20px 0px',
padding: '10px 20px'
}

const workspaceInfo = {
margin: '7px 0px'
}

const footer = {
borderTop: '1px solid #eaeaea',
padding: '20px'
}

const footerText = {
fontSize: '12px',
color: '#999',
textAlign: 'center' as const,
margin: '0'
}

const link = {
color: '#000',
textDecoration: 'underline'
}
6 changes: 6 additions & 0 deletions apps/api/src/mail/services/interface.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,4 +18,10 @@ export interface IMailService {
adminUserCreateEmail(email: string): Promise<void>

feedbackEmail(email: string, feedback: string): Promise<void>

removedFromWorkspace(
email: string,
workspaceName: string,
removedOn: Date
): Promise<void>
}
21 changes: 20 additions & 1 deletion apps/api/src/mail/services/mail.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@ import {
} from '@nestjs/common'
import { IMailService } from './interface.service'
import { Transporter, createTransport } from 'nodemailer'
import RemovedFromWorkspaceEmail from '../emails/workspace-removal'
import { render } from '@react-email/render'

@Injectable()
export class MailService implements IMailService {
Expand Down Expand Up @@ -133,7 +135,7 @@ export class MailService implements IMailService {
<p>keyshade Team</p>
</body>
`
await this.sendEmail(process.env.ADMIN_EMAIL, subject, body)
await this.sendEmail(process.env.ADMIN_EMAIL!, subject, body)
}

async feedbackEmail(email: string, feedback: string): Promise<void> {
Expand All @@ -158,6 +160,23 @@ export class MailService implements IMailService {
await this.sendEmail(email, subject, body)
}

async removedFromWorkspace(
email: string,
workspaceName: string,
removedOn: Date
): Promise<void> {
const subject = `Your access was revoked from ${workspaceName}`

const body = await render(
RemovedFromWorkspaceEmail({
removedOn: removedOn.toISOString(),
workspaceName
})
)

await this.sendEmail(email, subject, body)
}

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

async removedFromWorkspace(
email: string,
workspaceName: string,
removedOn: Date
): Promise<void> {
this.log.log(
`User with email ${email} has been removed from the workspace ${workspaceName} on ${removedOn.toISOString()}`
)
}
}
29 changes: 15 additions & 14 deletions apps/api/src/socket/change-notifier.socket.ts
Original file line number Diff line number Diff line change
Expand Up @@ -94,25 +94,26 @@ export default class ChangeNotifier
)
@UseGuards(AuthGuard, ApiKeyGuard)
@SubscribeMessage('register-client-app')
/**
* This event is emitted from the CLI to register
* itself with our services so that it can receive live updates.
*
* The CLI will send a `ChangeNotifierRegistration` object
* as the message body, containing the workspace slug, project slug,
* and environment slug that the client app wants to receive updates for.
*
* We will then check if the user has access to the workspace,
* project, and environment, and if so, add the client to the
* list of connected clients for that environment.
*
* Finally, we will send an ACK to the client with a status code of 200.
*/
async handleRegister(
@ConnectedSocket() client: Socket,
@MessageBody() data: ChangeNotifierRegistration,
@CurrentUser() user: User
) {
/**
* This event is emitted from the CLI to register
* itself with our services so that it can receive live updates.
*
* The CLI will send a `ChangeNotifierRegistration` object
* as the message body, containing the workspace slug, project slug,
* and environment slug that the client app wants to receive updates for.
*
* We will then check if the user has access to the workspace,
* project, and environment, and if so, add the client to the
* list of connected clients for that environment.
*
* Finally, we will send an ACK to the client with a status code of 200.
*/

try {
// Check if the user has access to the workspace
await this.authorityCheckerService.checkAuthorityOverWorkspace({
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -290,6 +290,18 @@ export class WorkspaceMembershipService {
}
}
})

// Send an email to the removed users
const removedOn = new Date()
const emailPromises = userEmails.map((userEmail) =>
this.mailService.removedFromWorkspace(
userEmail,
workspace.name,
removedOn
)
)

await Promise.all(emailPromises)
}

await createEvent(
Expand Down
3 changes: 2 additions & 1 deletion apps/api/tsconfig.json
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
{
"compilerOptions": {
"jsx": "react-jsx",
"module": "NodeNext",
"declaration": true,
"removeComments": true,
Expand All @@ -20,6 +21,6 @@
"moduleResolution": "NodeNext",
"paths": {
"@/*": ["./src/*"]
}
},
}
}
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -159,7 +159,7 @@
"ts-jest": "^29.1.0",
"tsconfig": "workspace:*",
"tsconfig-paths": "^4.2.0",
"turbo": "^2.3.1"
"turbo": "^2.3.3"
},
"dependencies": {
"@keyshade/api-client": "workspace:*",
Expand Down
18 changes: 9 additions & 9 deletions packages/eslint-config-custom/package.json
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
{
"name": "eslint-config-custom",
"license": "MIT",
"version": "0.0.0",
"private": true,
"devDependencies": {
"@vercel/style-guide": "^5.0.0",
"eslint-config-turbo": "^2.3.1",
"typescript": "^4.5.3"
}
"name": "eslint-config-custom",
"license": "MIT",
"version": "0.0.0",
"private": true,
"devDependencies": {
"@vercel/style-guide": "^5.0.0",
"eslint-config-turbo": "^2.3.1",
"typescript": "^4.5.3"
}
}
Loading