exp-node-server 1.1.7 → 2.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +82 -20
- package/dist/cli.js +525 -0
- package/package.json +29 -9
- package/templates/mongoose/.dockerignore +10 -0
- package/templates/mongoose/.env.example +56 -7
- package/templates/mongoose/.prettierignore +3 -0
- package/templates/mongoose/.prettierrc +7 -0
- package/templates/mongoose/Dockerfile +33 -0
- package/templates/mongoose/_gitignore +32 -0
- package/templates/mongoose/docker-compose.yml +21 -0
- package/templates/mongoose/eslint.config.js +35 -0
- package/templates/mongoose/package-lock.json +6377 -0
- package/templates/mongoose/package.json +49 -10
- package/templates/mongoose/readme.md +85 -0
- package/templates/mongoose/src/app/configs/index.ts +178 -26
- package/templates/mongoose/src/app/errors/zodError.ts +16 -16
- package/templates/mongoose/src/app/lib/db.ts +18 -0
- package/templates/mongoose/src/app/lib/logger.ts +12 -0
- package/templates/mongoose/src/app/middlewares/auth.ts +48 -44
- package/templates/mongoose/src/app/middlewares/global_error_handler.ts +59 -65
- package/templates/mongoose/src/app/middlewares/not_found_api.ts +7 -7
- package/templates/mongoose/src/app/middlewares/rate_limiter.ts +153 -0
- package/templates/mongoose/src/app/middlewares/request_validator.ts +11 -10
- package/templates/mongoose/src/app/middlewares/uploader.ts +17 -13
- package/templates/mongoose/src/app/modules/account/account.controller.ts +156 -0
- package/templates/mongoose/src/app/modules/account/account.interface.ts +65 -0
- package/templates/mongoose/src/app/modules/account/account.route.ts +101 -0
- package/templates/mongoose/src/app/modules/account/account.schema.ts +97 -0
- package/templates/mongoose/src/app/modules/account/account.service.ts +422 -0
- package/templates/mongoose/src/app/modules/account/account.swagger.ts +278 -0
- package/templates/mongoose/src/app/modules/account/account.validation.ts +63 -0
- package/templates/mongoose/src/app/modules/profile/profile.controller.ts +17 -0
- package/templates/mongoose/src/app/modules/profile/profile.interface.ts +7 -0
- package/templates/mongoose/src/app/modules/profile/profile.route.ts +28 -0
- package/templates/mongoose/src/app/modules/profile/profile.schema.ts +13 -0
- package/templates/mongoose/src/app/modules/profile/profile.service.ts +28 -0
- package/templates/mongoose/src/app/modules/profile/profile.swagger.ts +34 -0
- package/templates/mongoose/src/app/modules/profile/profile.validation.ts +8 -0
- package/templates/mongoose/src/app/passport-js/index.ts +87 -0
- package/templates/mongoose/src/app/passport-js/oauth-state.ts +150 -0
- package/templates/mongoose/src/app/passport-js/providers.ts +258 -0
- package/templates/mongoose/src/app/passport-js/social-account.ts +141 -0
- package/templates/mongoose/src/app/queues/agenda.ts +24 -0
- package/templates/mongoose/src/app/queues/email.queue.ts +53 -0
- package/templates/mongoose/src/app/queues/index.ts +13 -0
- package/templates/mongoose/src/app/templates/otpEmailTemplate.ts +185 -0
- package/templates/mongoose/src/app/templates/resetPasswordEmailTemplate.ts +157 -0
- package/templates/mongoose/src/app/types/error.d.ts +7 -7
- package/templates/mongoose/src/app/types/express.d.ts +11 -0
- package/templates/mongoose/src/app/types/passport-oauth1.d.ts +51 -0
- package/templates/mongoose/src/app/utils/JWT.ts +38 -18
- package/templates/mongoose/src/app/utils/app_error.ts +10 -10
- package/templates/mongoose/src/app/utils/auth_cookie.ts +27 -0
- package/templates/mongoose/src/app/utils/catch_async.ts +8 -8
- package/templates/mongoose/src/app/utils/cloudinary.ts +26 -59
- package/templates/mongoose/src/app/utils/mail_sender.ts +26 -92
- package/templates/mongoose/src/app/utils/manage_response.ts +19 -19
- package/templates/mongoose/src/app/utils/otp.ts +20 -0
- package/templates/mongoose/src/app/utils/session.ts +55 -0
- package/templates/mongoose/src/app.ts +73 -42
- package/templates/mongoose/src/routes.ts +13 -13
- package/templates/mongoose/src/server.ts +38 -18
- package/templates/mongoose/src/swaggerOptions.ts +23 -23
- package/templates/mongoose/tests/app.test.ts +97 -0
- package/templates/mongoose/tests/global-setup.ts +15 -0
- package/templates/mongoose/tests/helpers/fixtures.ts +42 -0
- package/templates/mongoose/tests/routes/account.test.ts +614 -0
- package/templates/mongoose/tests/routes/profile.test.ts +95 -0
- package/templates/mongoose/tests/routes/social.test.ts +310 -0
- package/templates/mongoose/tests/setup.ts +25 -0
- package/templates/mongoose/tsconfig.json +16 -20
- package/templates/mongoose/vitest.config.ts +43 -0
- package/templates/prisma/.dockerignore +2 -0
- package/templates/prisma/.env.example +62 -6
- package/templates/prisma/.prettierignore +3 -0
- package/templates/prisma/.prettierrc +7 -0
- package/templates/prisma/.projectrc.json +1 -1
- package/templates/prisma/Dockerfile +21 -7
- package/templates/prisma/_gitignore +35 -0
- package/templates/prisma/docker-compose.yml +8 -7
- package/templates/prisma/eslint.config.js +35 -0
- package/templates/prisma/package-lock.json +7327 -0
- package/templates/prisma/package.json +47 -9
- package/templates/prisma/prisma/schema/account.schema.prisma +92 -10
- package/templates/prisma/prisma/schema/profile.schema.prisma +8 -3
- package/templates/prisma/prisma/schema/schema.prisma +1 -2
- package/templates/prisma/prisma.config.ts +5 -5
- package/templates/prisma/readme.md +81 -0
- package/templates/prisma/src/app/configs/index.ts +175 -26
- package/templates/prisma/src/app/errors/zodError.ts +16 -16
- package/templates/prisma/src/app/lib/logger.ts +12 -0
- package/templates/prisma/src/app/lib/prisma.ts +4 -6
- package/templates/prisma/src/app/middlewares/auth.ts +37 -16
- package/templates/prisma/src/app/middlewares/global_error_handler.ts +42 -35
- package/templates/prisma/src/app/middlewares/not_found_api.ts +7 -7
- package/templates/prisma/src/app/middlewares/rate_limiter.ts +124 -0
- package/templates/prisma/src/app/middlewares/request_validator.ts +4 -3
- package/templates/prisma/src/app/middlewares/uploader.ts +17 -13
- package/templates/prisma/src/app/modules/account/account.controller.ts +74 -34
- package/templates/prisma/src/app/modules/account/account.route.ts +68 -22
- package/templates/prisma/src/app/modules/account/account.service.ts +329 -309
- package/templates/prisma/src/app/modules/account/account.swagger.ts +167 -76
- package/templates/prisma/src/app/modules/account/account.validation.ts +41 -19
- package/templates/prisma/src/app/modules/profile/profile.controller.ts +4 -4
- package/templates/prisma/src/app/modules/profile/profile.route.ts +18 -12
- package/templates/prisma/src/app/modules/profile/profile.service.ts +11 -18
- package/templates/prisma/src/app/modules/profile/profile.swagger.ts +11 -11
- package/templates/prisma/src/app/modules/profile/profile.validation.ts +2 -2
- package/templates/prisma/src/app/passport-js/index.ts +87 -0
- package/templates/prisma/src/app/passport-js/oauth-state.ts +150 -0
- package/templates/prisma/src/app/passport-js/providers.ts +263 -0
- package/templates/prisma/src/app/passport-js/social-account.ts +147 -0
- package/templates/prisma/src/app/queues/boss.ts +8 -0
- package/templates/prisma/src/app/queues/email.queue.ts +56 -0
- package/templates/prisma/src/app/queues/index.ts +14 -0
- package/templates/prisma/src/app/queues/maintenance.queue.ts +30 -0
- package/templates/prisma/src/app/templates/otpEmailTemplate.ts +185 -0
- package/templates/prisma/src/app/templates/resetPasswordEmailTemplate.ts +157 -0
- package/templates/prisma/src/app/types/error.d.ts +7 -7
- package/templates/prisma/src/app/types/express.d.ts +11 -0
- package/templates/prisma/src/app/types/passport-oauth1.d.ts +51 -0
- package/templates/prisma/src/app/utils/JWT.ts +36 -17
- package/templates/prisma/src/app/utils/app_error.ts +10 -10
- package/templates/prisma/src/app/utils/auth_cookie.ts +27 -0
- package/templates/prisma/src/app/utils/catch_async.ts +8 -8
- package/templates/prisma/src/app/utils/cloudinary.ts +26 -59
- package/templates/prisma/src/app/utils/mail_sender.ts +26 -92
- package/templates/prisma/src/app/utils/manage_response.ts +19 -19
- package/templates/prisma/src/app/utils/otp.ts +20 -0
- package/templates/prisma/src/app/utils/session.ts +57 -0
- package/templates/prisma/src/app.ts +73 -42
- package/templates/prisma/src/routes.ts +12 -10
- package/templates/prisma/src/server.ts +37 -19
- package/templates/prisma/src/swaggerOptions.ts +22 -26
- package/templates/prisma/tests/app.test.ts +86 -0
- package/templates/prisma/tests/helpers/fixtures.ts +35 -0
- package/templates/prisma/tests/helpers/prisma.ts +32 -0
- package/templates/prisma/tests/routes/account.test.ts +627 -0
- package/templates/prisma/tests/routes/profile.test.ts +91 -0
- package/templates/prisma/tests/routes/social.test.ts +317 -0
- package/templates/prisma/tests/setup.ts +10 -0
- package/templates/prisma/tsconfig.json +16 -23
- package/templates/prisma/vitest.config.ts +38 -0
- package/bin/cli.js +0 -41
- package/src/createProject.js +0 -61
- package/src/generateModule.js +0 -93
- package/src/utils/getProjectType.js +0 -13
- package/src/utils/mongoose/controllerGenerator.js +0 -70
- package/src/utils/mongoose/routeGenerator.js +0 -27
- package/src/utils/mongoose/schemaGenerator.js +0 -11
- package/src/utils/mongoose/serviceGenerator.js +0 -49
- package/src/utils/mongoose/swaggerGenerator.js +0 -112
- package/src/utils/mongoose/validationGenerator.js +0 -13
- package/src/utils/prisma/prismaSchemaGenerator.js +0 -10
- package/src/utils/prisma/prismaServiceGenerator.js +0 -47
- package/src/utils/routeInjector.js +0 -40
- package/src/utils/swaggerInjector.js +0 -52
- package/src/utils/validateModuleName.js +0 -17
- package/src/utils/validateProjectName.js +0 -15
- package/src/utils.js +0 -26
- package/templates/mongoose/src/app/errors/castError.ts +0 -23
- package/templates/mongoose/src/app/errors/duplicateError.ts +0 -26
- package/templates/mongoose/src/app/errors/validationError.ts +0 -25
- package/templates/mongoose/src/app/modules/auth/auth.controller.ts +0 -127
- package/templates/mongoose/src/app/modules/auth/auth.interface.ts +0 -24
- package/templates/mongoose/src/app/modules/auth/auth.route.ts +0 -46
- package/templates/mongoose/src/app/modules/auth/auth.schema.ts +0 -19
- package/templates/mongoose/src/app/modules/auth/auth.service.ts +0 -324
- package/templates/mongoose/src/app/modules/auth/auth.swagger.ts +0 -214
- package/templates/mongoose/src/app/modules/auth/auth.validation.ts +0 -37
- package/templates/mongoose/src/app/modules/user/user.controller.ts +0 -17
- package/templates/mongoose/src/app/modules/user/user.interface.ts +0 -15
- package/templates/mongoose/src/app/modules/user/user.route.ts +0 -20
- package/templates/mongoose/src/app/modules/user/user.schema.ts +0 -22
- package/templates/mongoose/src/app/modules/user/user.service.ts +0 -22
- package/templates/mongoose/src/app/modules/user/user.swagger.ts +0 -75
- package/templates/mongoose/src/app/modules/user/user.validation.ts +0 -18
- package/templates/mongoose/src/app/types/index.d.ts +0 -12
- package/templates/mongoose/src/app/utils/isAccountExist.ts +0 -31
- package/templates/prisma/src/app/types/index.d.ts +0 -12
- package/templates/prisma/src/app/utils/otpGenerator.ts +0 -29
|
@@ -1,186 +1,277 @@
|
|
|
1
1
|
export const accountSwaggerDocs = {
|
|
2
|
-
|
|
2
|
+
'/api/auth/sign-up': {
|
|
3
3
|
post: {
|
|
4
|
-
tags: [
|
|
5
|
-
summary:
|
|
6
|
-
description:
|
|
4
|
+
tags: ['auth'],
|
|
5
|
+
summary: 'Create new account',
|
|
6
|
+
description: '',
|
|
7
7
|
requestBody: {
|
|
8
8
|
required: true,
|
|
9
9
|
content: {
|
|
10
|
-
|
|
10
|
+
'application/json': {
|
|
11
11
|
example: JSON.stringify({
|
|
12
|
-
email:
|
|
13
|
-
password:
|
|
14
|
-
fullName:
|
|
12
|
+
email: 'user@gmail.com',
|
|
13
|
+
password: 'password',
|
|
14
|
+
fullName: 'User',
|
|
15
15
|
}),
|
|
16
16
|
},
|
|
17
17
|
},
|
|
18
18
|
},
|
|
19
19
|
responses: {
|
|
20
|
-
201: { description:
|
|
21
|
-
500: { description:
|
|
20
|
+
201: { description: 'account created successfully' },
|
|
21
|
+
500: { description: 'Validation error or internal server error' },
|
|
22
22
|
},
|
|
23
23
|
},
|
|
24
24
|
},
|
|
25
|
-
|
|
25
|
+
'/api/auth/sign-in': {
|
|
26
26
|
post: {
|
|
27
|
-
tags: [
|
|
28
|
-
summary:
|
|
29
|
-
description:
|
|
27
|
+
tags: ['auth'],
|
|
28
|
+
summary: 'Sign In your account',
|
|
29
|
+
description: '',
|
|
30
30
|
requestBody: {
|
|
31
31
|
required: true,
|
|
32
32
|
content: {
|
|
33
|
-
|
|
33
|
+
'application/json': {
|
|
34
34
|
example: JSON.stringify({
|
|
35
|
-
email:
|
|
36
|
-
password:
|
|
35
|
+
email: 'user@gmail.com',
|
|
36
|
+
password: 'password',
|
|
37
37
|
}),
|
|
38
38
|
},
|
|
39
39
|
},
|
|
40
40
|
},
|
|
41
41
|
responses: {
|
|
42
|
-
201: { description:
|
|
43
|
-
500: { description:
|
|
42
|
+
201: { description: 'User signed in successfully' },
|
|
43
|
+
500: { description: 'Validation error or internal server error' },
|
|
44
44
|
},
|
|
45
45
|
},
|
|
46
46
|
},
|
|
47
|
-
|
|
47
|
+
'/api/auth/verify-otp': {
|
|
48
48
|
put: {
|
|
49
|
-
tags: [
|
|
50
|
-
summary:
|
|
51
|
-
description:
|
|
49
|
+
tags: ['auth'],
|
|
50
|
+
summary: 'Verify OTP',
|
|
51
|
+
description: '',
|
|
52
52
|
requestBody: {
|
|
53
53
|
required: true,
|
|
54
54
|
content: {
|
|
55
|
-
|
|
55
|
+
'application/json': {
|
|
56
56
|
example: JSON.stringify({
|
|
57
|
-
email:
|
|
58
|
-
otp:
|
|
57
|
+
email: 'user@gmail.com',
|
|
58
|
+
otp: '654321',
|
|
59
59
|
}),
|
|
60
60
|
},
|
|
61
61
|
},
|
|
62
62
|
},
|
|
63
63
|
responses: {
|
|
64
|
-
201: { description:
|
|
65
|
-
500: { description:
|
|
64
|
+
201: { description: 'OTP verification successfully' },
|
|
65
|
+
500: { description: 'Validation error or internal server error' },
|
|
66
66
|
},
|
|
67
67
|
},
|
|
68
68
|
},
|
|
69
|
-
|
|
69
|
+
'/api/auth/verify-link': {
|
|
70
70
|
put: {
|
|
71
|
-
tags: [
|
|
72
|
-
summary:
|
|
73
|
-
description:
|
|
71
|
+
tags: ['auth'],
|
|
72
|
+
summary: 'Verify Link',
|
|
73
|
+
description: '',
|
|
74
74
|
requestBody: {
|
|
75
75
|
required: true,
|
|
76
76
|
content: {
|
|
77
|
-
|
|
77
|
+
'application/json': {
|
|
78
78
|
example: JSON.stringify({
|
|
79
|
-
token:
|
|
79
|
+
token: 'dsakfjasdkj',
|
|
80
80
|
}),
|
|
81
81
|
},
|
|
82
82
|
},
|
|
83
83
|
},
|
|
84
84
|
responses: {
|
|
85
|
-
201: { description:
|
|
86
|
-
500: { description:
|
|
85
|
+
201: { description: 'Token verification successfully' },
|
|
86
|
+
500: { description: 'Validation error or internal server error' },
|
|
87
87
|
},
|
|
88
88
|
},
|
|
89
89
|
},
|
|
90
|
-
|
|
90
|
+
'/api/auth/me': {
|
|
91
91
|
get: {
|
|
92
|
-
tags: [
|
|
93
|
-
summary:
|
|
94
|
-
description:
|
|
92
|
+
tags: ['auth'],
|
|
93
|
+
summary: 'Get me account',
|
|
94
|
+
description: '',
|
|
95
95
|
responses: {
|
|
96
|
-
200: { description:
|
|
97
|
-
401: { description:
|
|
96
|
+
200: { description: 'account fetched successfully' },
|
|
97
|
+
401: { description: 'unauthorized' },
|
|
98
98
|
},
|
|
99
99
|
},
|
|
100
100
|
},
|
|
101
|
-
|
|
101
|
+
'/api/auth/change-password': {
|
|
102
102
|
put: {
|
|
103
|
-
tags: [
|
|
104
|
-
summary:
|
|
105
|
-
description:
|
|
103
|
+
tags: ['auth'],
|
|
104
|
+
summary: 'Change Password',
|
|
105
|
+
description: '',
|
|
106
106
|
requestBody: {
|
|
107
107
|
required: true,
|
|
108
108
|
content: {
|
|
109
|
-
|
|
109
|
+
'application/json': {
|
|
110
110
|
example: JSON.stringify({
|
|
111
|
-
oldPassword:
|
|
112
|
-
newPassword:
|
|
111
|
+
oldPassword: '123456',
|
|
112
|
+
newPassword: '654321',
|
|
113
113
|
}),
|
|
114
114
|
},
|
|
115
115
|
},
|
|
116
116
|
},
|
|
117
117
|
responses: {
|
|
118
|
-
201: { description:
|
|
119
|
-
500: { description:
|
|
118
|
+
201: { description: 'Passwrod change successfully' },
|
|
119
|
+
500: { description: 'Validation error or internal server error' },
|
|
120
120
|
},
|
|
121
121
|
},
|
|
122
122
|
},
|
|
123
|
-
|
|
123
|
+
'/api/auth/resend-otp': {
|
|
124
124
|
put: {
|
|
125
|
-
tags: [
|
|
126
|
-
summary:
|
|
127
|
-
description:
|
|
125
|
+
tags: ['auth'],
|
|
126
|
+
summary: 'Resend OTP',
|
|
127
|
+
description: '',
|
|
128
128
|
requestBody: {
|
|
129
129
|
required: true,
|
|
130
130
|
content: {
|
|
131
|
-
|
|
131
|
+
'application/json': {
|
|
132
132
|
example: JSON.stringify({
|
|
133
|
-
email:
|
|
133
|
+
email: 'user@gmail.com',
|
|
134
134
|
}),
|
|
135
135
|
},
|
|
136
136
|
},
|
|
137
137
|
},
|
|
138
138
|
responses: {
|
|
139
|
-
201: { description:
|
|
140
|
-
500: { description:
|
|
139
|
+
201: { description: 'OTP resend successfully' },
|
|
140
|
+
500: { description: 'Validation error or internal server error' },
|
|
141
141
|
},
|
|
142
142
|
},
|
|
143
143
|
},
|
|
144
|
-
|
|
144
|
+
'/api/auth/forget-password': {
|
|
145
145
|
put: {
|
|
146
|
-
tags: [
|
|
147
|
-
summary:
|
|
148
|
-
description:
|
|
146
|
+
tags: ['auth'],
|
|
147
|
+
summary: 'Forget Password',
|
|
148
|
+
description: '',
|
|
149
149
|
requestBody: {
|
|
150
150
|
required: true,
|
|
151
151
|
content: {
|
|
152
|
-
|
|
152
|
+
'application/json': {
|
|
153
153
|
example: JSON.stringify({
|
|
154
|
-
email:
|
|
154
|
+
email: 'user@gmail.com',
|
|
155
155
|
}),
|
|
156
156
|
},
|
|
157
157
|
},
|
|
158
158
|
},
|
|
159
159
|
responses: {
|
|
160
|
-
201: { description:
|
|
161
|
-
500: { description:
|
|
160
|
+
201: { description: 'Forget password successfully' },
|
|
161
|
+
500: { description: 'Validation error or internal server error' },
|
|
162
162
|
},
|
|
163
163
|
},
|
|
164
164
|
},
|
|
165
|
-
|
|
165
|
+
'/api/auth/reset-password': {
|
|
166
166
|
put: {
|
|
167
|
-
tags: [
|
|
168
|
-
summary:
|
|
169
|
-
description:
|
|
167
|
+
tags: ['auth'],
|
|
168
|
+
summary: 'Reset Password',
|
|
169
|
+
description: '',
|
|
170
170
|
requestBody: {
|
|
171
171
|
required: true,
|
|
172
172
|
content: {
|
|
173
|
-
|
|
173
|
+
'application/json': {
|
|
174
174
|
example: JSON.stringify({
|
|
175
|
-
token:
|
|
176
|
-
newPass:
|
|
175
|
+
token: 'dkfjadskfds',
|
|
176
|
+
newPass: 'newpass',
|
|
177
177
|
}),
|
|
178
178
|
},
|
|
179
179
|
},
|
|
180
180
|
},
|
|
181
181
|
responses: {
|
|
182
|
-
201: { description:
|
|
183
|
-
500: { description:
|
|
182
|
+
201: { description: 'Password reset successfully' },
|
|
183
|
+
500: { description: 'Validation error or internal server error' },
|
|
184
|
+
},
|
|
185
|
+
},
|
|
186
|
+
},
|
|
187
|
+
'/api/auth/refresh-token': {
|
|
188
|
+
post: {
|
|
189
|
+
tags: ['auth'],
|
|
190
|
+
summary: 'Get a new access token (and a rotated refresh token)',
|
|
191
|
+
description:
|
|
192
|
+
'Browsers send the `refresh_token` cookie automatically; other clients send it in the body. ' +
|
|
193
|
+
'Every call returns a new refresh token and invalidates the old one. Reusing an old ' +
|
|
194
|
+
'refresh token ends the whole session.',
|
|
195
|
+
requestBody: {
|
|
196
|
+
required: false,
|
|
197
|
+
content: {
|
|
198
|
+
'application/json': {
|
|
199
|
+
example: JSON.stringify({ refreshToken: 'only-for-non-browser-clients' }),
|
|
200
|
+
},
|
|
201
|
+
},
|
|
202
|
+
},
|
|
203
|
+
responses: {
|
|
204
|
+
200: { description: '{ accessToken, refreshToken }, both also set as httpOnly cookies' },
|
|
205
|
+
401: { description: 'Missing, invalid, expired or reused refresh token' },
|
|
206
|
+
},
|
|
207
|
+
},
|
|
208
|
+
},
|
|
209
|
+
'/api/auth/sign-out': {
|
|
210
|
+
post: {
|
|
211
|
+
tags: ['auth'],
|
|
212
|
+
summary: 'Sign out this device (revokes its refresh token, clears the cookies)',
|
|
213
|
+
responses: { 200: { description: 'Signed out' } },
|
|
214
|
+
},
|
|
215
|
+
},
|
|
216
|
+
'/api/auth/sign-out-all': {
|
|
217
|
+
post: {
|
|
218
|
+
tags: ['auth'],
|
|
219
|
+
summary: 'Sign out from all devices (revokes every access token)',
|
|
220
|
+
responses: {
|
|
221
|
+
200: { description: 'Signed out everywhere' },
|
|
222
|
+
401: { description: 'unauthorized' },
|
|
223
|
+
},
|
|
224
|
+
},
|
|
225
|
+
},
|
|
226
|
+
'/api/auth/social/providers': {
|
|
227
|
+
get: {
|
|
228
|
+
tags: ['social auth'],
|
|
229
|
+
summary: 'List the enabled social login providers',
|
|
230
|
+
responses: { 200: { description: 'Providers, with the URL that starts each login' } },
|
|
231
|
+
},
|
|
232
|
+
},
|
|
233
|
+
'/api/auth/social/{provider}': {
|
|
234
|
+
get: {
|
|
235
|
+
tags: ['social auth'],
|
|
236
|
+
summary: 'Start a social login (open in the browser, not via fetch)',
|
|
237
|
+
description:
|
|
238
|
+
"Link to it from the front-end: <a href='/api/auth/social/google?returnTo=/dashboard'>Login with Google</a>. " +
|
|
239
|
+
'After the provider, the browser is redirected to SOCIAL_REDIRECT_URL with `?code=` (and `returnTo`) on success, ' +
|
|
240
|
+
'or `?error=` (access_denied, invalid_state, email_unverified, account_disabled, social_login_failed).',
|
|
241
|
+
parameters: [
|
|
242
|
+
{
|
|
243
|
+
name: 'provider',
|
|
244
|
+
in: 'path',
|
|
245
|
+
required: true,
|
|
246
|
+
schema: {
|
|
247
|
+
type: 'string',
|
|
248
|
+
enum: ['google', 'facebook', 'github', 'twitter', 'linkedin', 'discord'],
|
|
249
|
+
},
|
|
250
|
+
},
|
|
251
|
+
{
|
|
252
|
+
name: 'returnTo',
|
|
253
|
+
in: 'query',
|
|
254
|
+
required: false,
|
|
255
|
+
schema: { type: 'string', example: '/dashboard' },
|
|
256
|
+
description: 'Path on the front-end to come back to. Only same-site paths are kept.',
|
|
257
|
+
},
|
|
258
|
+
],
|
|
259
|
+
responses: { 302: { description: 'Redirect to the provider' } },
|
|
260
|
+
},
|
|
261
|
+
},
|
|
262
|
+
'/api/auth/social/exchange': {
|
|
263
|
+
post: {
|
|
264
|
+
tags: ['social auth'],
|
|
265
|
+
summary: 'Trade the single-use code from the social login redirect for an access token',
|
|
266
|
+
requestBody: {
|
|
267
|
+
required: true,
|
|
268
|
+
content: {
|
|
269
|
+
'application/json': { example: JSON.stringify({ code: 'code-from-redirect' }) },
|
|
270
|
+
},
|
|
271
|
+
},
|
|
272
|
+
responses: {
|
|
273
|
+
200: { description: 'Logged in (token in body and httpOnly cookie)' },
|
|
274
|
+
401: { description: 'Invalid, expired or already used code' },
|
|
184
275
|
},
|
|
185
276
|
},
|
|
186
277
|
},
|
|
@@ -1,41 +1,63 @@
|
|
|
1
|
-
import z from
|
|
1
|
+
import z from 'zod';
|
|
2
|
+
|
|
3
|
+
const email = z.email('A valid email is required.').transform((e) => e.toLowerCase());
|
|
4
|
+
const password = z
|
|
5
|
+
.string('Password is required.')
|
|
6
|
+
.min(8, 'Password must be at least 8 characters.')
|
|
7
|
+
.max(72, 'Password must be at most 72 characters.'); // bcrypt ignores bytes past 72
|
|
2
8
|
|
|
3
9
|
const sign_up = z.object({
|
|
4
|
-
email
|
|
5
|
-
password
|
|
6
|
-
fullName: z.string(
|
|
10
|
+
email,
|
|
11
|
+
password,
|
|
12
|
+
fullName: z.string('Full name is required.').trim().min(1).max(100),
|
|
7
13
|
});
|
|
8
14
|
|
|
9
|
-
const
|
|
10
|
-
email
|
|
11
|
-
password: z.string(
|
|
15
|
+
const sign_in = z.object({
|
|
16
|
+
email,
|
|
17
|
+
password: z.string('Password is required.').max(72),
|
|
12
18
|
});
|
|
13
19
|
|
|
14
20
|
const change_password = z.object({
|
|
15
|
-
oldPassword: z.string(
|
|
16
|
-
newPassword:
|
|
21
|
+
oldPassword: z.string('Old Password is required').max(72),
|
|
22
|
+
newPassword: password,
|
|
17
23
|
});
|
|
18
24
|
|
|
19
25
|
const verify_otp = z.object({
|
|
20
|
-
email
|
|
21
|
-
otp: z.string(
|
|
26
|
+
email,
|
|
27
|
+
otp: z.string('OTP is required').regex(/^\d{6}$/, 'OTP must be 6 digits'),
|
|
22
28
|
});
|
|
29
|
+
|
|
30
|
+
const token = z.string('Token is required').min(1).max(2048);
|
|
31
|
+
|
|
23
32
|
const verify_link = z.object({
|
|
24
|
-
token
|
|
33
|
+
token,
|
|
25
34
|
});
|
|
26
|
-
|
|
27
|
-
|
|
35
|
+
|
|
36
|
+
const email_only = z.object({
|
|
37
|
+
email,
|
|
28
38
|
});
|
|
39
|
+
|
|
29
40
|
const reset_pass = z.object({
|
|
30
|
-
token
|
|
31
|
-
newPass:
|
|
41
|
+
token,
|
|
42
|
+
newPass: password,
|
|
32
43
|
});
|
|
44
|
+
|
|
45
|
+
// optional: browsers send the refresh token as a cookie instead
|
|
46
|
+
const refresh_token = z.object({ refreshToken: z.string().min(1).max(256).optional() }).optional();
|
|
47
|
+
|
|
48
|
+
const social_exchange = z.object({
|
|
49
|
+
code: z.string('Code is required').min(1).max(256),
|
|
50
|
+
});
|
|
51
|
+
|
|
33
52
|
export const account_validation = {
|
|
34
53
|
sign_up,
|
|
35
|
-
|
|
54
|
+
sign_in,
|
|
36
55
|
change_password,
|
|
37
56
|
verify_otp,
|
|
38
|
-
resend_otp,
|
|
57
|
+
resend_otp: email_only,
|
|
58
|
+
forget_password: email_only,
|
|
39
59
|
verify_link,
|
|
40
|
-
reset_pass
|
|
60
|
+
reset_pass,
|
|
61
|
+
social_exchange,
|
|
62
|
+
refresh_token,
|
|
41
63
|
};
|
|
@@ -1,13 +1,13 @@
|
|
|
1
|
-
import catchAsync from
|
|
2
|
-
import manageResponse from
|
|
3
|
-
import { profile_service } from
|
|
1
|
+
import catchAsync from '../../utils/catch_async.js';
|
|
2
|
+
import manageResponse from '../../utils/manage_response.js';
|
|
3
|
+
import { profile_service } from './profile.service.js';
|
|
4
4
|
|
|
5
5
|
const update_profile = catchAsync(async (req, res) => {
|
|
6
6
|
const result = await profile_service.update_profile_into_db(req);
|
|
7
7
|
manageResponse(res, {
|
|
8
8
|
success: true,
|
|
9
9
|
statusCode: 200,
|
|
10
|
-
message:
|
|
10
|
+
message: 'profile updated successfully.',
|
|
11
11
|
data: result,
|
|
12
12
|
});
|
|
13
13
|
});
|
|
@@ -1,19 +1,25 @@
|
|
|
1
|
-
import { Router } from
|
|
2
|
-
import
|
|
3
|
-
import
|
|
4
|
-
import
|
|
5
|
-
import
|
|
6
|
-
import
|
|
1
|
+
import { Router } from 'express';
|
|
2
|
+
import auth from '../../middlewares/auth.js';
|
|
3
|
+
import RequestValidator from '../../middlewares/request_validator.js';
|
|
4
|
+
import uploader from '../../middlewares/uploader.js';
|
|
5
|
+
import { AppError } from '../../utils/app_error.js';
|
|
6
|
+
import { profile_controller } from './profile.controller.js';
|
|
7
|
+
import { profile_validations } from './profile.validation.js';
|
|
7
8
|
|
|
8
9
|
const router = Router();
|
|
9
10
|
|
|
10
11
|
router.patch(
|
|
11
|
-
|
|
12
|
-
auth(
|
|
13
|
-
uploader.single(
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
12
|
+
'/',
|
|
13
|
+
auth(),
|
|
14
|
+
uploader.single('file'),
|
|
15
|
+
// multipart forms send the JSON fields as a `data` string
|
|
16
|
+
(req, _res, next) => {
|
|
17
|
+
try {
|
|
18
|
+
req.body = req.body?.data ? JSON.parse(req.body.data) : {};
|
|
19
|
+
next();
|
|
20
|
+
} catch {
|
|
21
|
+
next(new AppError('`data` must be valid JSON', 400));
|
|
22
|
+
}
|
|
17
23
|
},
|
|
18
24
|
RequestValidator(profile_validations.update_profile),
|
|
19
25
|
profile_controller.update_profile,
|
|
@@ -1,24 +1,17 @@
|
|
|
1
|
-
import { Request } from
|
|
2
|
-
import
|
|
3
|
-
import
|
|
4
|
-
import { JwtPayloadType } from "../../utils/JWT";
|
|
1
|
+
import { Request } from 'express';
|
|
2
|
+
import { prisma } from '../../lib/prisma.js';
|
|
3
|
+
import uploadCloud from '../../utils/cloudinary.js';
|
|
5
4
|
|
|
6
5
|
const update_profile_into_db = async (req: Request) => {
|
|
7
|
-
const
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
const result = await prisma.profile.update({
|
|
16
|
-
where: {
|
|
17
|
-
accountId: user.accountId as string,
|
|
18
|
-
},
|
|
19
|
-
data: payload,
|
|
6
|
+
const payload: { fullName?: string } = req.body;
|
|
7
|
+
|
|
8
|
+
// validation already ran (see profile.route.ts), so only valid requests upload
|
|
9
|
+
const profilePhoto = req.file ? (await uploadCloud(req.file, 'profiles')).secure_url : undefined;
|
|
10
|
+
|
|
11
|
+
return prisma.profile.update({
|
|
12
|
+
where: { accountId: req.user!.accountId },
|
|
13
|
+
data: { fullName: payload.fullName, profilePhoto },
|
|
20
14
|
});
|
|
21
|
-
return result;
|
|
22
15
|
};
|
|
23
16
|
|
|
24
17
|
export const profile_service = {
|
|
@@ -1,24 +1,24 @@
|
|
|
1
1
|
export const profileSwaggerDocs = {
|
|
2
|
-
|
|
2
|
+
'/api/profile': {
|
|
3
3
|
patch: {
|
|
4
|
-
tags: [
|
|
5
|
-
summary:
|
|
4
|
+
tags: ['profile'],
|
|
5
|
+
summary: 'Update profile',
|
|
6
6
|
requestBody: {
|
|
7
7
|
required: true,
|
|
8
8
|
content: {
|
|
9
|
-
|
|
9
|
+
'multipart/form-data': {
|
|
10
10
|
schema: {
|
|
11
|
-
type:
|
|
11
|
+
type: 'object',
|
|
12
12
|
properties: {
|
|
13
13
|
data: {
|
|
14
|
-
type:
|
|
14
|
+
type: 'object',
|
|
15
15
|
properties: {
|
|
16
|
-
fullName: { type:
|
|
16
|
+
fullName: { type: 'string' },
|
|
17
17
|
},
|
|
18
18
|
},
|
|
19
19
|
file: {
|
|
20
|
-
type:
|
|
21
|
-
format:
|
|
20
|
+
type: 'string',
|
|
21
|
+
format: 'binary',
|
|
22
22
|
},
|
|
23
23
|
},
|
|
24
24
|
},
|
|
@@ -26,8 +26,8 @@ export const profileSwaggerDocs = {
|
|
|
26
26
|
},
|
|
27
27
|
},
|
|
28
28
|
responses: {
|
|
29
|
-
200: { description:
|
|
30
|
-
500: { description:
|
|
29
|
+
200: { description: 'profile updated successfully' },
|
|
30
|
+
500: { description: 'Validation error or internal server error' },
|
|
31
31
|
},
|
|
32
32
|
},
|
|
33
33
|
},
|