Skip to content

Commit 3d3fbce

Browse files
authored
omg: migrate nest server to netlify functions (#977)
1 parent 8b8d43d commit 3d3fbce

File tree

128 files changed

+10916
-739
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

128 files changed

+10916
-739
lines changed

.env

Lines changed: 0 additions & 6 deletions
This file was deleted.

.env.development

Lines changed: 0 additions & 6 deletions
This file was deleted.

.gitignore

Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,4 +41,79 @@ debug.log
4141

4242
# Next.js
4343
.next
44+
server/src/app.module.ts
45+
server/src/logger.ts
46+
server/src/main.ts
47+
server/src/config/index.ts
48+
server/src/database/database.module.ts
49+
server/src/database/database.providers.ts
50+
server/src/middlewares/auth.middleware.ts
51+
server/src/modules/admin/admin.controller.ts
52+
server/src/modules/admin/admin.module.ts
53+
server/src/modules/admin/__tests__/mentors.controller.spec.ts
54+
server/src/modules/common/auth0.service.ts
55+
server/src/modules/common/common.module.ts
56+
server/src/modules/common/common.providers.ts
57+
server/src/modules/common/file.service.ts
58+
server/src/modules/common/mentors.service.ts
59+
server/src/modules/common/users.service.ts
60+
server/src/modules/common/dto/application.dto.ts
61+
server/src/modules/common/dto/filter.dto.ts
62+
server/src/modules/common/dto/findOneParams.dto.ts
63+
server/src/modules/common/dto/mentorfilters.dto.ts
64+
server/src/modules/common/dto/pagination.dto.ts
65+
server/src/modules/common/dto/user-record.dto.ts
66+
server/src/modules/common/dto/user.dto.ts
67+
server/src/modules/common/interfaces/application.interface.ts
68+
server/src/modules/common/interfaces/filemeta.interface.ts
69+
server/src/modules/common/interfaces/user-record.interface.ts
70+
server/src/modules/common/interfaces/user.interface.ts
71+
server/src/modules/common/pipes/pagination.pipe.ts
72+
server/src/modules/common/schemas/application.schema.ts
73+
server/src/modules/common/schemas/user-record.schema.ts
74+
server/src/modules/common/schemas/user.schema.ts
75+
server/src/modules/email/email.module.ts
76+
server/src/modules/email/email.service.ts
77+
server/src/modules/email/interfaces/email.interface.ts
78+
server/src/modules/lists/favorites.controller.ts
79+
server/src/modules/lists/list.providers.ts
80+
server/src/modules/lists/lists.controller.ts
81+
server/src/modules/lists/lists.module.ts
82+
server/src/modules/lists/lists.service.ts
83+
server/src/modules/lists/__tests__/favorites.controller.spec.ts
84+
server/src/modules/lists/__tests__/lists.controller.spec.ts
85+
server/src/modules/lists/dto/list.dto.ts
86+
server/src/modules/lists/interfaces/list.interface.ts
87+
server/src/modules/lists/schemas/list.schema.ts
88+
server/src/modules/mentors/mentors.controller.ts
89+
server/src/modules/mentors/mentors.module.ts
90+
server/src/modules/mentors/__tests__/mentors.controller.spec.ts
91+
server/src/modules/mentorships/mentorships.controller.ts
92+
server/src/modules/mentorships/mentorships.module.ts
93+
server/src/modules/mentorships/mentorships.providers.ts
94+
server/src/modules/mentorships/mentorships.service.ts
95+
server/src/modules/mentorships/mentorshipsToDto.ts
96+
server/src/modules/mentorships/__tests__/mentorships.controller.spec.ts
97+
server/src/modules/mentorships/dto/mentorship.dto.ts
98+
server/src/modules/mentorships/dto/mentorshipSummary.dto.ts
99+
server/src/modules/mentorships/dto/mentorshipUpdatePayload.dto.ts
100+
server/src/modules/mentorships/interfaces/mentorship.interface.ts
101+
server/src/modules/mentorships/schemas/mentorship.schema.ts
102+
server/src/modules/reports/reports.controller.ts
103+
server/src/modules/reports/reports.module.ts
104+
server/src/modules/reports/reports.service.ts
105+
server/src/modules/reports/__tests__/reports.controller.spec.ts
106+
server/src/modules/reports/interfaces/totals.interface.ts
107+
server/src/modules/users/users.controller.ts
108+
server/src/modules/users/users.module.ts
109+
server/src/modules/users/__tests__/users.controller.spec.ts
110+
server/src/utils/mimes.ts
111+
server/src/utils/objectid.ts
112+
server/src/utils/request.d.ts
113+
114+
# Local Netlify folder
115+
.netlify
116+
netlify/functions/**/*.js
117+
# Environment variables
118+
.env*
44119
.netlify

.prettierignore

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
11
.next
22
build
3-
tsconfig.json
3+
tsconfig.json
4+
netlify

README.md

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,9 +6,6 @@
66
[![TypeScript](https://img.shields.io/badge/%3C%2F%3E-TypeScript-%230074c1.svg)](http://www.typescriptlang.org/)
77

88

9-
[![Powered By Vercel](https://github.com/Coding-Coach/find-a-mentor/blob/3390fb723a8148c06ea88a7fdb972fd81b5a6064/src/assets/powered-by-vercel.svg)](https://vercel.com/codingcoach?utm_source=coding-coach&utm_campaign=oss)
10-
11-
129
## Support Us
1310

1411
CodingCoach is a FREE platform that is built and managed entirely by volunteers. As always, there are ongoing costs to run this site such as servers, domains, email, and more. Please consider becoming a patron so we can continue our mission of being accessible and free ❤️

api-types/errorCodes.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
export enum ErrorCodes {
2+
EmailNotVerified = 1,
3+
}

docs/auth.md

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
# Authentication System
2+
3+
We're using Auth0 to handle authentication in our application. This document outlines the authentication flow and how to set up your environment for development.
4+
5+
## Registration
6+
7+
1. User clicks on the "Sign Up" button.
8+
2. User is redirected to the Auth0 login page.
9+
3. User enters their email and password.
10+
4. Auth0 sends a verification email, which we leverage for the welcome email.
11+
5. User clicks on the verification link in the email.
12+
6. User is redirected to the application with a verification token. For more information about the redirection see the [docs](https://auth0.com/docs/customize/email/email-templates#configure-template-fields) - open the "Redirect the URL" section.
13+
> **ℹ️ Info**
14+
> Remember. The application.callback_domain variable will contain the origin of the first URL listed in the application's Allowed Callback URL list
15+
16+
## Authentication
17+
18+
1. User clicks on the "Log In" button.
19+
2. User is redirected to the Auth0 login page.
20+
3. User enters their email and password.
21+
4. Auth0 verifies the credentials and redirects the user back to the application with an access token which includes auth0id and an `email_verified` and `picture` added by a [custom action](https://manage.auth0.com/dashboard/eu/codingcoach/actions/library/details/e425e5f6-fcd0-4ec9-a3b5-68b3ef8eca75). `email_verified` is enabled by the `email` scope and `picture` is enabled by the `profile` scope.

netlify.toml

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,16 @@
22
command = "yarn build"
33
publish = ".next"
44

5+
[functions]
6+
directory = "netlify/functions-src/functions"
7+
included_files = ["netlify/functions-src/functions/email/templates/**.html"]
8+
9+
[dev]
10+
command = "yarn start"
11+
512
[build.environment]
613
NEXT_TELEMETRY_DISABLED = "1"
714
NODE_VERSION = "18"
815

916
[[plugins]]
10-
package = "@netlify/plugin-nextjs"
17+
package = "@netlify/plugin-nextjs"
Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
import Config from '../config';
2+
3+
const auth0Domain = Config.auth0.backend.DOMAIN;
4+
5+
const getAdminAccessToken = async (): Promise<string> => {
6+
try {
7+
8+
const response = await fetch(`https://${auth0Domain}/oauth/token`, {
9+
method: 'POST',
10+
headers: {
11+
'Content-Type': 'application/json',
12+
},
13+
body: JSON.stringify({
14+
client_id: Config.auth0.backend.CLIENT_ID,
15+
client_secret: Config.auth0.backend.CLIENT_SECRET,
16+
audience: Config.auth0.backend.AUDIENCE,
17+
grant_type: 'client_credentials',
18+
}),
19+
});
20+
const data = await response.json();
21+
return data.access_token;
22+
} catch (error) {
23+
// eslint-disable-next-line no-console
24+
console.error('Error fetching admin access token:', error);
25+
throw new Error('Failed to fetch access token');
26+
}
27+
};
28+
29+
30+
export const deleteUser = async (userId: string): Promise<void> => {
31+
const accessToken = await getAdminAccessToken();
32+
if (!accessToken) {
33+
throw new Error('Failed to get access token');
34+
}
35+
36+
const response = await fetch(`https://${auth0Domain}/api/v2/users/${userId}`, {
37+
method: 'DELETE',
38+
headers: {
39+
Authorization: `Bearer ${accessToken}`,
40+
},
41+
});
42+
43+
if (!response.ok) {
44+
throw new Error(`Failed to delete user: ${response.statusText}`);
45+
}
46+
47+
return response.json();
48+
}
Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,79 @@
1+
import axios, { type AxiosResponse } from 'axios'
2+
import Config from '../config'
3+
4+
class Auth0Service {
5+
private readonly auth0Domain = Config.auth0.backend.DOMAIN
6+
private readonly clientId = Config.auth0.backend.CLIENT_ID
7+
private readonly clientSecret = Config.auth0.backend.CLIENT_SECRET
8+
private readonly audience = Config.auth0.backend.AUDIENCE
9+
10+
async getAdminAccessToken(): Promise<AxiosResponse<{ access_token: string }>['data']> {
11+
try {
12+
const response = await axios.post(`https://${this.auth0Domain}/oauth/token`, {
13+
client_id: this.clientId,
14+
client_secret: this.clientSecret,
15+
audience: this.audience,
16+
grant_type: 'client_credentials',
17+
})
18+
return response.data
19+
} catch (error) {
20+
console.error('getAdminAccessToken, Error:', error)
21+
throw new Error('Error getting access token')
22+
}
23+
}
24+
25+
async getUserProfile(auth0Id: string): Promise<AxiosResponse<{ email: string, nickname: string, picture: string }>['data']> {
26+
try {
27+
const { access_token } = await this.getAdminAccessToken();
28+
const response = await axios.get(`https://${this.auth0Domain}/api/v2/users/${auth0Id}`, {
29+
headers: {
30+
Authorization: `Bearer ${access_token}`,
31+
},
32+
})
33+
return response.data
34+
} catch (error) {
35+
console.error('getUserProfile, Error:', error)
36+
throw new Error('Error getting user profile')
37+
}
38+
}
39+
40+
async deleteUser(accessToken: string, userId: string): Promise<void> {
41+
await axios.delete(`https://${this.auth0Domain}/api/v2/users/${userId}`, {
42+
headers: {
43+
Authorization: `Bearer ${accessToken}`,
44+
},
45+
})
46+
}
47+
48+
async createVerificationEmailTicket(
49+
auth0UserId: string,
50+
) {
51+
try {
52+
const { access_token: accessToken } = await this.getAdminAccessToken();
53+
const [provider, userId] = auth0UserId.split('|');
54+
const payload = {
55+
result_url: Config.urls.CLIENT_BASE_URL,
56+
user_id: auth0UserId,
57+
identity: { user_id: userId, provider },
58+
};
59+
60+
const response = await axios.post(
61+
`https://${Config.auth0.backend.DOMAIN}/api/v2/tickets/email-verification`,
62+
payload,
63+
{
64+
headers: {
65+
Authorization: `Bearer ${accessToken}`,
66+
'content-type': 'application/json',
67+
},
68+
},
69+
);
70+
71+
return response.data;
72+
} catch (error) {
73+
console.error('createVerificationEmailTicket, Error:', error)
74+
throw error;
75+
}
76+
}
77+
}
78+
79+
export const auth0Service = new Auth0Service();

0 commit comments

Comments
 (0)