RyZ commited on
Commit
3ddcd86
·
1 Parent(s): a13a65d

feature: RBAC for admin, user and worker

Browse files
controllers/auth_controller.go ADDED
@@ -0,0 +1,156 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ package controllers
2
+
3
+ import (
4
+ "net/http"
5
+
6
+ "dinacom-11.0-backend/models/dto"
7
+ "dinacom-11.0-backend/services"
8
+ "dinacom-11.0-backend/utils"
9
+
10
+ "github.com/gin-gonic/gin"
11
+ )
12
+
13
+ type AuthController interface {
14
+ RegisterUser(ctx *gin.Context)
15
+ VerifyOTP(ctx *gin.Context)
16
+ LoginUser(ctx *gin.Context)
17
+ LoginAdmin(ctx *gin.Context)
18
+ LoginWorker(ctx *gin.Context)
19
+ }
20
+
21
+ type authController struct {
22
+ authService services.AuthService
23
+ }
24
+
25
+ func NewAuthController(authService services.AuthService) AuthController {
26
+ return &authController{authService: authService}
27
+ }
28
+
29
+ // RegisterUser godoc
30
+ // @Summary Register a new user
31
+ // @Description Register a new user with email verification via OTP
32
+ // @Tags Auth
33
+ // @Accept json
34
+ // @Produce json
35
+ // @Param request body dto.RegisterRequest true "Register Request"
36
+ // @Success 200 {object} map[string]string
37
+ // @Failure 400 {object} map[string]string
38
+ // @Router /api/auth/user/register [post]
39
+ func (c *authController) RegisterUser(ctx *gin.Context) {
40
+ var req dto.RegisterRequest
41
+ if err := ctx.ShouldBindJSON(&req); err != nil {
42
+ utils.SendErrorResponse(ctx, http.StatusBadRequest, err.Error())
43
+ return
44
+ }
45
+
46
+ if err := c.authService.RegisterUser(req); err != nil {
47
+ utils.SendErrorResponse(ctx, http.StatusBadRequest, err.Error())
48
+ return
49
+ }
50
+
51
+ utils.SendSuccessResponse(ctx, "OTP sent to email", nil)
52
+ }
53
+
54
+ // VerifyOTP godoc
55
+ // @Summary Verify OTP
56
+ // @Description Verify OTP to activate user account and get access token
57
+ // @Tags Auth
58
+ // @Accept json
59
+ // @Produce json
60
+ // @Param request body dto.VerifyOTPRequest true "Verify OTP Request"
61
+ // @Success 200 {object} dto.AuthResponse
62
+ // @Failure 401 {object} map[string]string
63
+ // @Router /api/auth/user/verify-otp [post]
64
+ func (c *authController) VerifyOTP(ctx *gin.Context) {
65
+ var req dto.VerifyOTPRequest
66
+ if err := ctx.ShouldBindJSON(&req); err != nil {
67
+ utils.SendErrorResponse(ctx, http.StatusBadRequest, err.Error())
68
+ return
69
+ }
70
+
71
+ token, err := c.authService.VerifyOTP(req)
72
+ if err != nil {
73
+ utils.SendErrorResponse(ctx, http.StatusUnauthorized, err.Error())
74
+ return
75
+ }
76
+
77
+ utils.SendSuccessResponse(ctx, "Verification successful", dto.AuthResponse{Token: token})
78
+ }
79
+
80
+ // LoginUser godoc
81
+ // @Summary Login User
82
+ // @Description Login for users
83
+ // @Tags Auth
84
+ // @Accept json
85
+ // @Produce json
86
+ // @Param request body dto.LoginRequest true "Login Request"
87
+ // @Success 200 {object} dto.AuthResponse
88
+ // @Failure 401 {object} map[string]string
89
+ // @Router /api/auth/user/login [post]
90
+ func (c *authController) LoginUser(ctx *gin.Context) {
91
+ var req dto.LoginRequest
92
+ if err := ctx.ShouldBindJSON(&req); err != nil {
93
+ utils.SendErrorResponse(ctx, http.StatusBadRequest, err.Error())
94
+ return
95
+ }
96
+
97
+ token, err := c.authService.LoginUser(req)
98
+ if err != nil {
99
+ utils.SendErrorResponse(ctx, http.StatusUnauthorized, err.Error())
100
+ return
101
+ }
102
+
103
+ utils.SendSuccessResponse(ctx, "Login successful", dto.AuthResponse{Token: token})
104
+ }
105
+
106
+ // LoginAdmin godoc
107
+ // @Summary Login Admin
108
+ // @Description Login for admins
109
+ // @Tags Auth
110
+ // @Accept json
111
+ // @Produce json
112
+ // @Param request body dto.LoginRequest true "Login Request"
113
+ // @Success 200 {object} dto.AuthResponse
114
+ // @Failure 401 {object} map[string]string
115
+ // @Router /api/auth/admin/login [post]
116
+ func (c *authController) LoginAdmin(ctx *gin.Context) {
117
+ var req dto.LoginRequest
118
+ if err := ctx.ShouldBindJSON(&req); err != nil {
119
+ utils.SendErrorResponse(ctx, http.StatusBadRequest, err.Error())
120
+ return
121
+ }
122
+
123
+ token, err := c.authService.LoginAdmin(req)
124
+ if err != nil {
125
+ utils.SendErrorResponse(ctx, http.StatusUnauthorized, err.Error())
126
+ return
127
+ }
128
+
129
+ utils.SendSuccessResponse(ctx, "Login successful", dto.AuthResponse{Token: token})
130
+ }
131
+
132
+ // LoginWorker godoc
133
+ // @Summary Login Worker
134
+ // @Description Login for workers
135
+ // @Tags Auth
136
+ // @Accept json
137
+ // @Produce json
138
+ // @Param request body dto.LoginRequest true "Login Request"
139
+ // @Success 200 {object} dto.AuthResponse
140
+ // @Failure 401 {object} map[string]string
141
+ // @Router /api/auth/worker/login [post]
142
+ func (c *authController) LoginWorker(ctx *gin.Context) {
143
+ var req dto.LoginRequest
144
+ if err := ctx.ShouldBindJSON(&req); err != nil {
145
+ utils.SendErrorResponse(ctx, http.StatusBadRequest, err.Error())
146
+ return
147
+ }
148
+
149
+ token, err := c.authService.LoginWorker(req)
150
+ if err != nil {
151
+ utils.SendErrorResponse(ctx, http.StatusUnauthorized, err.Error())
152
+ return
153
+ }
154
+
155
+ utils.SendSuccessResponse(ctx, "Login successful", dto.AuthResponse{Token: token})
156
+ }
docs/docs.go ADDED
@@ -0,0 +1,319 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ // Package docs Code generated by swaggo/swag. DO NOT EDIT
2
+ package docs
3
+
4
+ import "github.com/swaggo/swag"
5
+
6
+ const docTemplate = `{
7
+ "schemes": {{ marshal .Schemes }},
8
+ "swagger": "2.0",
9
+ "info": {
10
+ "description": "{{escape .Description}}",
11
+ "title": "{{.Title}}",
12
+ "contact": {},
13
+ "version": "{{.Version}}"
14
+ },
15
+ "host": "{{.Host}}",
16
+ "basePath": "{{.BasePath}}",
17
+ "paths": {
18
+ "/api/auth/admin/login": {
19
+ "post": {
20
+ "description": "Login for admins",
21
+ "consumes": [
22
+ "application/json"
23
+ ],
24
+ "produces": [
25
+ "application/json"
26
+ ],
27
+ "tags": [
28
+ "Auth"
29
+ ],
30
+ "summary": "Login Admin",
31
+ "parameters": [
32
+ {
33
+ "description": "Login Request",
34
+ "name": "request",
35
+ "in": "body",
36
+ "required": true,
37
+ "schema": {
38
+ "$ref": "#/definitions/dto.LoginRequest"
39
+ }
40
+ }
41
+ ],
42
+ "responses": {
43
+ "200": {
44
+ "description": "OK",
45
+ "schema": {
46
+ "$ref": "#/definitions/dto.AuthResponse"
47
+ }
48
+ },
49
+ "401": {
50
+ "description": "Unauthorized",
51
+ "schema": {
52
+ "type": "object",
53
+ "additionalProperties": {
54
+ "type": "string"
55
+ }
56
+ }
57
+ }
58
+ }
59
+ }
60
+ },
61
+ "/api/auth/user/login": {
62
+ "post": {
63
+ "description": "Login for users",
64
+ "consumes": [
65
+ "application/json"
66
+ ],
67
+ "produces": [
68
+ "application/json"
69
+ ],
70
+ "tags": [
71
+ "Auth"
72
+ ],
73
+ "summary": "Login User",
74
+ "parameters": [
75
+ {
76
+ "description": "Login Request",
77
+ "name": "request",
78
+ "in": "body",
79
+ "required": true,
80
+ "schema": {
81
+ "$ref": "#/definitions/dto.LoginRequest"
82
+ }
83
+ }
84
+ ],
85
+ "responses": {
86
+ "200": {
87
+ "description": "OK",
88
+ "schema": {
89
+ "$ref": "#/definitions/dto.AuthResponse"
90
+ }
91
+ },
92
+ "401": {
93
+ "description": "Unauthorized",
94
+ "schema": {
95
+ "type": "object",
96
+ "additionalProperties": {
97
+ "type": "string"
98
+ }
99
+ }
100
+ }
101
+ }
102
+ }
103
+ },
104
+ "/api/auth/user/register": {
105
+ "post": {
106
+ "description": "Register a new user with email verification via OTP",
107
+ "consumes": [
108
+ "application/json"
109
+ ],
110
+ "produces": [
111
+ "application/json"
112
+ ],
113
+ "tags": [
114
+ "Auth"
115
+ ],
116
+ "summary": "Register a new user",
117
+ "parameters": [
118
+ {
119
+ "description": "Register Request",
120
+ "name": "request",
121
+ "in": "body",
122
+ "required": true,
123
+ "schema": {
124
+ "$ref": "#/definitions/dto.RegisterRequest"
125
+ }
126
+ }
127
+ ],
128
+ "responses": {
129
+ "200": {
130
+ "description": "OK",
131
+ "schema": {
132
+ "type": "object",
133
+ "additionalProperties": {
134
+ "type": "string"
135
+ }
136
+ }
137
+ },
138
+ "400": {
139
+ "description": "Bad Request",
140
+ "schema": {
141
+ "type": "object",
142
+ "additionalProperties": {
143
+ "type": "string"
144
+ }
145
+ }
146
+ }
147
+ }
148
+ }
149
+ },
150
+ "/api/auth/user/verify-otp": {
151
+ "post": {
152
+ "description": "Verify OTP to activate user account and get access token",
153
+ "consumes": [
154
+ "application/json"
155
+ ],
156
+ "produces": [
157
+ "application/json"
158
+ ],
159
+ "tags": [
160
+ "Auth"
161
+ ],
162
+ "summary": "Verify OTP",
163
+ "parameters": [
164
+ {
165
+ "description": "Verify OTP Request",
166
+ "name": "request",
167
+ "in": "body",
168
+ "required": true,
169
+ "schema": {
170
+ "$ref": "#/definitions/dto.VerifyOTPRequest"
171
+ }
172
+ }
173
+ ],
174
+ "responses": {
175
+ "200": {
176
+ "description": "OK",
177
+ "schema": {
178
+ "$ref": "#/definitions/dto.AuthResponse"
179
+ }
180
+ },
181
+ "401": {
182
+ "description": "Unauthorized",
183
+ "schema": {
184
+ "type": "object",
185
+ "additionalProperties": {
186
+ "type": "string"
187
+ }
188
+ }
189
+ }
190
+ }
191
+ }
192
+ },
193
+ "/api/auth/worker/login": {
194
+ "post": {
195
+ "description": "Login for workers",
196
+ "consumes": [
197
+ "application/json"
198
+ ],
199
+ "produces": [
200
+ "application/json"
201
+ ],
202
+ "tags": [
203
+ "Auth"
204
+ ],
205
+ "summary": "Login Worker",
206
+ "parameters": [
207
+ {
208
+ "description": "Login Request",
209
+ "name": "request",
210
+ "in": "body",
211
+ "required": true,
212
+ "schema": {
213
+ "$ref": "#/definitions/dto.LoginRequest"
214
+ }
215
+ }
216
+ ],
217
+ "responses": {
218
+ "200": {
219
+ "description": "OK",
220
+ "schema": {
221
+ "$ref": "#/definitions/dto.AuthResponse"
222
+ }
223
+ },
224
+ "401": {
225
+ "description": "Unauthorized",
226
+ "schema": {
227
+ "type": "object",
228
+ "additionalProperties": {
229
+ "type": "string"
230
+ }
231
+ }
232
+ }
233
+ }
234
+ }
235
+ }
236
+ },
237
+ "definitions": {
238
+ "dto.AuthResponse": {
239
+ "type": "object",
240
+ "properties": {
241
+ "token": {
242
+ "type": "string"
243
+ }
244
+ }
245
+ },
246
+ "dto.LoginRequest": {
247
+ "type": "object",
248
+ "required": [
249
+ "email",
250
+ "password"
251
+ ],
252
+ "properties": {
253
+ "email": {
254
+ "type": "string"
255
+ },
256
+ "password": {
257
+ "type": "string"
258
+ }
259
+ }
260
+ },
261
+ "dto.RegisterRequest": {
262
+ "type": "object",
263
+ "required": [
264
+ "email",
265
+ "fullname",
266
+ "password",
267
+ "username"
268
+ ],
269
+ "properties": {
270
+ "email": {
271
+ "type": "string"
272
+ },
273
+ "fullname": {
274
+ "type": "string"
275
+ },
276
+ "password": {
277
+ "type": "string",
278
+ "minLength": 6
279
+ },
280
+ "username": {
281
+ "type": "string"
282
+ }
283
+ }
284
+ },
285
+ "dto.VerifyOTPRequest": {
286
+ "type": "object",
287
+ "required": [
288
+ "email",
289
+ "otp"
290
+ ],
291
+ "properties": {
292
+ "email": {
293
+ "type": "string"
294
+ },
295
+ "otp": {
296
+ "type": "string"
297
+ }
298
+ }
299
+ }
300
+ }
301
+ }`
302
+
303
+ // SwaggerInfo holds exported Swagger Info so clients can modify it
304
+ var SwaggerInfo = &swag.Spec{
305
+ Version: "",
306
+ Host: "",
307
+ BasePath: "",
308
+ Schemes: []string{},
309
+ Title: "",
310
+ Description: "",
311
+ InfoInstanceName: "swagger",
312
+ SwaggerTemplate: docTemplate,
313
+ LeftDelim: "{{",
314
+ RightDelim: "}}",
315
+ }
316
+
317
+ func init() {
318
+ swag.Register(SwaggerInfo.InstanceName(), SwaggerInfo)
319
+ }
docs/swagger.json ADDED
@@ -0,0 +1,290 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "swagger": "2.0",
3
+ "info": {
4
+ "contact": {}
5
+ },
6
+ "paths": {
7
+ "/api/auth/admin/login": {
8
+ "post": {
9
+ "description": "Login for admins",
10
+ "consumes": [
11
+ "application/json"
12
+ ],
13
+ "produces": [
14
+ "application/json"
15
+ ],
16
+ "tags": [
17
+ "Auth"
18
+ ],
19
+ "summary": "Login Admin",
20
+ "parameters": [
21
+ {
22
+ "description": "Login Request",
23
+ "name": "request",
24
+ "in": "body",
25
+ "required": true,
26
+ "schema": {
27
+ "$ref": "#/definitions/dto.LoginRequest"
28
+ }
29
+ }
30
+ ],
31
+ "responses": {
32
+ "200": {
33
+ "description": "OK",
34
+ "schema": {
35
+ "$ref": "#/definitions/dto.AuthResponse"
36
+ }
37
+ },
38
+ "401": {
39
+ "description": "Unauthorized",
40
+ "schema": {
41
+ "type": "object",
42
+ "additionalProperties": {
43
+ "type": "string"
44
+ }
45
+ }
46
+ }
47
+ }
48
+ }
49
+ },
50
+ "/api/auth/user/login": {
51
+ "post": {
52
+ "description": "Login for users",
53
+ "consumes": [
54
+ "application/json"
55
+ ],
56
+ "produces": [
57
+ "application/json"
58
+ ],
59
+ "tags": [
60
+ "Auth"
61
+ ],
62
+ "summary": "Login User",
63
+ "parameters": [
64
+ {
65
+ "description": "Login Request",
66
+ "name": "request",
67
+ "in": "body",
68
+ "required": true,
69
+ "schema": {
70
+ "$ref": "#/definitions/dto.LoginRequest"
71
+ }
72
+ }
73
+ ],
74
+ "responses": {
75
+ "200": {
76
+ "description": "OK",
77
+ "schema": {
78
+ "$ref": "#/definitions/dto.AuthResponse"
79
+ }
80
+ },
81
+ "401": {
82
+ "description": "Unauthorized",
83
+ "schema": {
84
+ "type": "object",
85
+ "additionalProperties": {
86
+ "type": "string"
87
+ }
88
+ }
89
+ }
90
+ }
91
+ }
92
+ },
93
+ "/api/auth/user/register": {
94
+ "post": {
95
+ "description": "Register a new user with email verification via OTP",
96
+ "consumes": [
97
+ "application/json"
98
+ ],
99
+ "produces": [
100
+ "application/json"
101
+ ],
102
+ "tags": [
103
+ "Auth"
104
+ ],
105
+ "summary": "Register a new user",
106
+ "parameters": [
107
+ {
108
+ "description": "Register Request",
109
+ "name": "request",
110
+ "in": "body",
111
+ "required": true,
112
+ "schema": {
113
+ "$ref": "#/definitions/dto.RegisterRequest"
114
+ }
115
+ }
116
+ ],
117
+ "responses": {
118
+ "200": {
119
+ "description": "OK",
120
+ "schema": {
121
+ "type": "object",
122
+ "additionalProperties": {
123
+ "type": "string"
124
+ }
125
+ }
126
+ },
127
+ "400": {
128
+ "description": "Bad Request",
129
+ "schema": {
130
+ "type": "object",
131
+ "additionalProperties": {
132
+ "type": "string"
133
+ }
134
+ }
135
+ }
136
+ }
137
+ }
138
+ },
139
+ "/api/auth/user/verify-otp": {
140
+ "post": {
141
+ "description": "Verify OTP to activate user account and get access token",
142
+ "consumes": [
143
+ "application/json"
144
+ ],
145
+ "produces": [
146
+ "application/json"
147
+ ],
148
+ "tags": [
149
+ "Auth"
150
+ ],
151
+ "summary": "Verify OTP",
152
+ "parameters": [
153
+ {
154
+ "description": "Verify OTP Request",
155
+ "name": "request",
156
+ "in": "body",
157
+ "required": true,
158
+ "schema": {
159
+ "$ref": "#/definitions/dto.VerifyOTPRequest"
160
+ }
161
+ }
162
+ ],
163
+ "responses": {
164
+ "200": {
165
+ "description": "OK",
166
+ "schema": {
167
+ "$ref": "#/definitions/dto.AuthResponse"
168
+ }
169
+ },
170
+ "401": {
171
+ "description": "Unauthorized",
172
+ "schema": {
173
+ "type": "object",
174
+ "additionalProperties": {
175
+ "type": "string"
176
+ }
177
+ }
178
+ }
179
+ }
180
+ }
181
+ },
182
+ "/api/auth/worker/login": {
183
+ "post": {
184
+ "description": "Login for workers",
185
+ "consumes": [
186
+ "application/json"
187
+ ],
188
+ "produces": [
189
+ "application/json"
190
+ ],
191
+ "tags": [
192
+ "Auth"
193
+ ],
194
+ "summary": "Login Worker",
195
+ "parameters": [
196
+ {
197
+ "description": "Login Request",
198
+ "name": "request",
199
+ "in": "body",
200
+ "required": true,
201
+ "schema": {
202
+ "$ref": "#/definitions/dto.LoginRequest"
203
+ }
204
+ }
205
+ ],
206
+ "responses": {
207
+ "200": {
208
+ "description": "OK",
209
+ "schema": {
210
+ "$ref": "#/definitions/dto.AuthResponse"
211
+ }
212
+ },
213
+ "401": {
214
+ "description": "Unauthorized",
215
+ "schema": {
216
+ "type": "object",
217
+ "additionalProperties": {
218
+ "type": "string"
219
+ }
220
+ }
221
+ }
222
+ }
223
+ }
224
+ }
225
+ },
226
+ "definitions": {
227
+ "dto.AuthResponse": {
228
+ "type": "object",
229
+ "properties": {
230
+ "token": {
231
+ "type": "string"
232
+ }
233
+ }
234
+ },
235
+ "dto.LoginRequest": {
236
+ "type": "object",
237
+ "required": [
238
+ "email",
239
+ "password"
240
+ ],
241
+ "properties": {
242
+ "email": {
243
+ "type": "string"
244
+ },
245
+ "password": {
246
+ "type": "string"
247
+ }
248
+ }
249
+ },
250
+ "dto.RegisterRequest": {
251
+ "type": "object",
252
+ "required": [
253
+ "email",
254
+ "fullname",
255
+ "password",
256
+ "username"
257
+ ],
258
+ "properties": {
259
+ "email": {
260
+ "type": "string"
261
+ },
262
+ "fullname": {
263
+ "type": "string"
264
+ },
265
+ "password": {
266
+ "type": "string",
267
+ "minLength": 6
268
+ },
269
+ "username": {
270
+ "type": "string"
271
+ }
272
+ }
273
+ },
274
+ "dto.VerifyOTPRequest": {
275
+ "type": "object",
276
+ "required": [
277
+ "email",
278
+ "otp"
279
+ ],
280
+ "properties": {
281
+ "email": {
282
+ "type": "string"
283
+ },
284
+ "otp": {
285
+ "type": "string"
286
+ }
287
+ }
288
+ }
289
+ }
290
+ }
docs/swagger.yaml ADDED
@@ -0,0 +1,189 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ definitions:
2
+ dto.AuthResponse:
3
+ properties:
4
+ token:
5
+ type: string
6
+ type: object
7
+ dto.LoginRequest:
8
+ properties:
9
+ email:
10
+ type: string
11
+ password:
12
+ type: string
13
+ required:
14
+ - email
15
+ - password
16
+ type: object
17
+ dto.RegisterRequest:
18
+ properties:
19
+ email:
20
+ type: string
21
+ fullname:
22
+ type: string
23
+ password:
24
+ minLength: 6
25
+ type: string
26
+ username:
27
+ type: string
28
+ required:
29
+ - email
30
+ - fullname
31
+ - password
32
+ - username
33
+ type: object
34
+ dto.VerifyOTPRequest:
35
+ properties:
36
+ email:
37
+ type: string
38
+ otp:
39
+ type: string
40
+ required:
41
+ - email
42
+ - otp
43
+ type: object
44
+ info:
45
+ contact: {}
46
+ paths:
47
+ /api/auth/admin/login:
48
+ post:
49
+ consumes:
50
+ - application/json
51
+ description: Login for admins
52
+ parameters:
53
+ - description: Login Request
54
+ in: body
55
+ name: request
56
+ required: true
57
+ schema:
58
+ $ref: '#/definitions/dto.LoginRequest'
59
+ produces:
60
+ - application/json
61
+ responses:
62
+ "200":
63
+ description: OK
64
+ schema:
65
+ $ref: '#/definitions/dto.AuthResponse'
66
+ "401":
67
+ description: Unauthorized
68
+ schema:
69
+ additionalProperties:
70
+ type: string
71
+ type: object
72
+ summary: Login Admin
73
+ tags:
74
+ - Auth
75
+ /api/auth/user/login:
76
+ post:
77
+ consumes:
78
+ - application/json
79
+ description: Login for users
80
+ parameters:
81
+ - description: Login Request
82
+ in: body
83
+ name: request
84
+ required: true
85
+ schema:
86
+ $ref: '#/definitions/dto.LoginRequest'
87
+ produces:
88
+ - application/json
89
+ responses:
90
+ "200":
91
+ description: OK
92
+ schema:
93
+ $ref: '#/definitions/dto.AuthResponse'
94
+ "401":
95
+ description: Unauthorized
96
+ schema:
97
+ additionalProperties:
98
+ type: string
99
+ type: object
100
+ summary: Login User
101
+ tags:
102
+ - Auth
103
+ /api/auth/user/register:
104
+ post:
105
+ consumes:
106
+ - application/json
107
+ description: Register a new user with email verification via OTP
108
+ parameters:
109
+ - description: Register Request
110
+ in: body
111
+ name: request
112
+ required: true
113
+ schema:
114
+ $ref: '#/definitions/dto.RegisterRequest'
115
+ produces:
116
+ - application/json
117
+ responses:
118
+ "200":
119
+ description: OK
120
+ schema:
121
+ additionalProperties:
122
+ type: string
123
+ type: object
124
+ "400":
125
+ description: Bad Request
126
+ schema:
127
+ additionalProperties:
128
+ type: string
129
+ type: object
130
+ summary: Register a new user
131
+ tags:
132
+ - Auth
133
+ /api/auth/user/verify-otp:
134
+ post:
135
+ consumes:
136
+ - application/json
137
+ description: Verify OTP to activate user account and get access token
138
+ parameters:
139
+ - description: Verify OTP Request
140
+ in: body
141
+ name: request
142
+ required: true
143
+ schema:
144
+ $ref: '#/definitions/dto.VerifyOTPRequest'
145
+ produces:
146
+ - application/json
147
+ responses:
148
+ "200":
149
+ description: OK
150
+ schema:
151
+ $ref: '#/definitions/dto.AuthResponse'
152
+ "401":
153
+ description: Unauthorized
154
+ schema:
155
+ additionalProperties:
156
+ type: string
157
+ type: object
158
+ summary: Verify OTP
159
+ tags:
160
+ - Auth
161
+ /api/auth/worker/login:
162
+ post:
163
+ consumes:
164
+ - application/json
165
+ description: Login for workers
166
+ parameters:
167
+ - description: Login Request
168
+ in: body
169
+ name: request
170
+ required: true
171
+ schema:
172
+ $ref: '#/definitions/dto.LoginRequest'
173
+ produces:
174
+ - application/json
175
+ responses:
176
+ "200":
177
+ description: OK
178
+ schema:
179
+ $ref: '#/definitions/dto.AuthResponse'
180
+ "401":
181
+ description: Unauthorized
182
+ schema:
183
+ additionalProperties:
184
+ type: string
185
+ type: object
186
+ summary: Login Worker
187
+ tags:
188
+ - Auth
189
+ swagger: "2.0"
go.mod CHANGED
@@ -11,6 +11,24 @@ require (
11
  gorm.io/gorm v1.31.1
12
  )
13
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
14
  require (
15
  github.com/bytedance/gopkg v0.1.3 // indirect
16
  github.com/bytedance/sonic v1.14.2 // indirect
@@ -38,6 +56,7 @@ require (
38
  github.com/pelletier/go-toml/v2 v2.2.4 // indirect
39
  github.com/quic-go/qpack v0.6.0 // indirect
40
  github.com/quic-go/quic-go v0.58.0 // indirect
 
41
  github.com/twitchyliquid64/golang-asm v0.15.1 // indirect
42
  github.com/ugorji/go/codec v1.3.1 // indirect
43
  golang.org/x/arch v0.23.0 // indirect
 
11
  gorm.io/gorm v1.31.1
12
  )
13
 
14
+ require (
15
+ github.com/KyleBanks/depth v1.2.1 // indirect
16
+ github.com/PuerkitoBio/purell v1.1.1 // indirect
17
+ github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578 // indirect
18
+ github.com/go-openapi/jsonpointer v0.19.5 // indirect
19
+ github.com/go-openapi/jsonreference v0.19.6 // indirect
20
+ github.com/go-openapi/spec v0.20.4 // indirect
21
+ github.com/go-openapi/swag v0.19.15 // indirect
22
+ github.com/golang-jwt/jwt/v5 v5.3.1 // indirect
23
+ github.com/josharian/intern v1.0.0 // indirect
24
+ github.com/mailru/easyjson v0.7.6 // indirect
25
+ github.com/swaggo/files v1.0.1 // indirect
26
+ github.com/swaggo/gin-swagger v1.6.1 // indirect
27
+ golang.org/x/mod v0.30.0 // indirect
28
+ golang.org/x/tools v0.39.0 // indirect
29
+ gopkg.in/yaml.v2 v2.4.0 // indirect
30
+ )
31
+
32
  require (
33
  github.com/bytedance/gopkg v0.1.3 // indirect
34
  github.com/bytedance/sonic v1.14.2 // indirect
 
56
  github.com/pelletier/go-toml/v2 v2.2.4 // indirect
57
  github.com/quic-go/qpack v0.6.0 // indirect
58
  github.com/quic-go/quic-go v0.58.0 // indirect
59
+ github.com/swaggo/swag v1.16.6
60
  github.com/twitchyliquid64/golang-asm v0.15.1 // indirect
61
  github.com/ugorji/go/codec v1.3.1 // indirect
62
  golang.org/x/arch v0.23.0 // indirect
go.sum CHANGED
@@ -1,3 +1,9 @@
 
 
 
 
 
 
1
  github.com/bytedance/gopkg v0.1.3 h1:TPBSwH8RsouGCBcMBktLt1AymVo2TVsBVCY4b6TnZ/M=
2
  github.com/bytedance/gopkg v0.1.3/go.mod h1:576VvJ+eJgyCzdjS+c4+77QF3p7ubbtiKARP3TxducM=
3
  github.com/bytedance/sonic v1.14.2 h1:k1twIoe97C1DtYUo+fZQy865IuHia4PR5RPiuGPPIIE=
@@ -6,6 +12,7 @@ github.com/bytedance/sonic/loader v0.4.0 h1:olZ7lEqcxtZygCK9EKYKADnpQoYkRQxaeY2N
6
  github.com/bytedance/sonic/loader v0.4.0/go.mod h1:AR4NYCk5DdzZizZ5djGqQ92eEhCCcdf5x77udYiSJRo=
7
  github.com/cloudwego/base64x v0.1.6 h1:t11wG9AECkCDk5fMSoxmufanudBtJ+/HemLstXDLI2M=
8
  github.com/cloudwego/base64x v0.1.6/go.mod h1:OFcloc187FXDaYHvrNIjxSe8ncn0OOM8gEHfghB2IPU=
 
9
  github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
10
  github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
11
  github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
@@ -17,6 +24,16 @@ github.com/gin-contrib/sse v1.1.0 h1:n0w2GMuUpWDVp7qSpvze6fAu9iRxJY4Hmj6AmBOU05w
17
  github.com/gin-contrib/sse v1.1.0/go.mod h1:hxRZ5gVpWMT7Z0B0gSNYqqsSCNIJMjzvm6fqCz9vjwM=
18
  github.com/gin-gonic/gin v1.11.0 h1:OW/6PLjyusp2PPXtyxKHU0RbX6I/l28FTdDlae5ueWk=
19
  github.com/gin-gonic/gin v1.11.0/go.mod h1:+iq/FyxlGzII0KHiBGjuNn4UNENUlKbGlNmc+W50Dls=
 
 
 
 
 
 
 
 
 
 
20
  github.com/go-playground/assert/v2 v2.2.0 h1:JvknZsQTYeFEAhQwI4qEt9cyV5ONwRHC+lYKSsYSR8s=
21
  github.com/go-playground/assert/v2 v2.2.0/go.mod h1:VDjEfimB/XKnb+ZQfWdccd7VUvScMdVu0Titje2rxJ4=
22
  github.com/go-playground/locales v0.14.1 h1:EWaQ/wswjilfKLTECiXz7Rh+3BjFhfDFKv/oXslEjJA=
@@ -29,6 +46,8 @@ github.com/goccy/go-json v0.10.5 h1:Fq85nIqj+gXn/S5ahsiTlK3TmC85qgirsdTP/+DeaC4=
29
  github.com/goccy/go-json v0.10.5/go.mod h1:oq7eo15ShAhp70Anwd5lgX2pLfOS3QCiwU/PULtXL6M=
30
  github.com/goccy/go-yaml v1.19.1 h1:3rG3+v8pkhRqoQ/88NYNMHYVGYztCOCIZ7UQhu7H+NE=
31
  github.com/goccy/go-yaml v1.19.1/go.mod h1:XBurs7gK8ATbW4ZPGKgcbrY1Br56PdM69F7LkFRi1kA=
 
 
32
  github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8=
33
  github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU=
34
  github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
@@ -48,12 +67,22 @@ github.com/jinzhu/now v1.1.5 h1:/o9tlHleP7gOFmsnYNz3RGnqzefHA47wQpKrrdTIwXQ=
48
  github.com/jinzhu/now v1.1.5/go.mod h1:d3SSVoowX0Lcu0IBviAWJpolVfI5UJVZZ7cO71lE/z8=
49
  github.com/joho/godotenv v1.5.1 h1:7eLL/+HRGLY0ldzfGMeQkb7vMd0as4CfYvUVzLqw0N0=
50
  github.com/joho/godotenv v1.5.1/go.mod h1:f4LDr5Voq0i2e/R5DDNOoa2zzDfwtkZa6DnEwAbqwq4=
 
 
51
  github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM=
52
  github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo=
53
  github.com/klauspost/cpuid/v2 v2.3.0 h1:S4CRMLnYUhGeDFDqkGriYKdfoFlDnMtqTiI/sFzhA9Y=
54
  github.com/klauspost/cpuid/v2 v2.3.0/go.mod h1:hqwkgyIinND0mEev00jJYCxPNVRVXFQeu1XKlok6oO0=
 
 
 
 
55
  github.com/leodido/go-urn v1.4.0 h1:WT9HwE9SGECu3lg4d/dIA+jxlljEa1/ffXKmRjqdmIQ=
56
  github.com/leodido/go-urn v1.4.0/go.mod h1:bvxc+MVxLKB4z00jd1z+Dvzr47oO32F/QSNjSBOlFxI=
 
 
 
 
57
  github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY=
58
  github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
59
  github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
@@ -61,6 +90,7 @@ github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w
61
  github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
62
  github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9Gz0M=
63
  github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk=
 
64
  github.com/pelletier/go-toml/v2 v2.2.4 h1:mye9XuhQ6gvn5h28+VilKrrPoQVanw5PMw/TB0t5Ec4=
65
  github.com/pelletier/go-toml/v2 v2.2.4/go.mod h1:2gIqNv+qfxSVS7cM2xJQKtLSTLUE9V8t9Stt+h56mCY=
66
  github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
@@ -74,6 +104,7 @@ github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSS
74
  github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo=
75
  github.com/stretchr/objx v0.5.2/go.mod h1:FRsXN1f5AsAjCGJKqEizvkpNtU+EGNCLh3NxZ/8L+MA=
76
  github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
 
77
  github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
78
  github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
79
  github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
@@ -81,29 +112,75 @@ github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXl
81
  github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
82
  github.com/stretchr/testify v1.11.1 h1:7s2iGBzp5EwR7/aIZr8ao5+dra3wiQyKjjFuvgVKu7U=
83
  github.com/stretchr/testify v1.11.1/go.mod h1:wZwfW3scLgRK+23gO65QZefKpKQRnfz6sD981Nm4B6U=
 
 
 
 
 
 
84
  github.com/twitchyliquid64/golang-asm v0.15.1 h1:SU5vSMR7hnwNxj24w34ZyCi/FmDZTkS4MhqMhdFk5YI=
85
  github.com/twitchyliquid64/golang-asm v0.15.1/go.mod h1:a1lVb/DtPvCB8fslRZhAngC2+aY1QWCk3Cedj/Gdt08=
86
  github.com/ugorji/go/codec v1.3.1 h1:waO7eEiFDwidsBN6agj1vJQ4AG7lh2yqXyOXqhgQuyY=
87
  github.com/ugorji/go/codec v1.3.1/go.mod h1:pRBVtBSKl77K30Bv8R2P+cLSGaTtex6fsA2Wjqmfxj4=
 
88
  go.uber.org/mock v0.6.0 h1:hyF9dfmbgIX5EfOdasqLsWD6xqpNZlXblLB/Dbnwv3Y=
89
  go.uber.org/mock v0.6.0/go.mod h1:KiVJ4BqZJaMj4svdfmHM0AUx4NJYO8ZNpPnZn1Z+BBU=
90
  golang.org/x/arch v0.23.0 h1:lKF64A2jF6Zd8L0knGltUnegD62JMFBiCPBmQpToHhg=
91
  golang.org/x/arch v0.23.0/go.mod h1:dNHoOeKiyja7GTvF9NJS1l3Z2yntpQNzgrjh1cU103A=
 
 
92
  golang.org/x/crypto v0.46.0 h1:cKRW/pmt1pKAfetfu+RCEvjvZkA9RimPbh7bhFjGVBU=
93
  golang.org/x/crypto v0.46.0/go.mod h1:Evb/oLKmMraqjZ2iQTwDwvCtJkczlDuTmdJXoZVzqU0=
 
 
 
 
 
 
 
 
94
  golang.org/x/net v0.48.0 h1:zyQRTTrjc33Lhh0fBgT/H3oZq9WuvRR5gPC70xpDiQU=
95
  golang.org/x/net v0.48.0/go.mod h1:+ndRgGjkh8FGtu1w1FGbEC31if4VrNVMuKTgcAAnQRY=
 
 
96
  golang.org/x/sync v0.19.0 h1:vV+1eWNmZ5geRlYjzm2adRgW2/mcpevXNg50YZtPCE4=
97
  golang.org/x/sync v0.19.0/go.mod h1:9KTHXmSnoGruLpwFjVSX0lNNA75CykiMECbovNTZqGI=
 
 
 
 
 
 
 
98
  golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
99
  golang.org/x/sys v0.39.0 h1:CvCKL8MeisomCi6qNZ+wbb0DN9E5AATixKsvNtMoMFk=
100
  golang.org/x/sys v0.39.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks=
 
 
 
 
 
 
 
 
101
  golang.org/x/text v0.32.0 h1:ZD01bjUt1FQ9WJ0ClOL5vxgxOI/sVCNgX1YtKwcY0mU=
102
  golang.org/x/text v0.32.0/go.mod h1:o/rUWzghvpD5TXrTIBuJU77MTaN0ljMWE47kxGJQ7jY=
 
 
 
 
 
 
103
  google.golang.org/protobuf v1.36.11 h1:fV6ZwhNocDyBLK0dj+fg8ektcVegBBuEolpbTQyBNVE=
104
  google.golang.org/protobuf v1.36.11/go.mod h1:HTf+CrKn2C3g5S8VImy6tdcUvCska2kB7j23XfzDpco=
105
  gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
 
 
 
 
 
106
  gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
 
107
  gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
108
  gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
109
  gorm.io/driver/postgres v1.6.0 h1:2dxzU8xJ+ivvqTRph34QX+WrRaJlmfyPqXmoGVjMBa4=
 
1
+ github.com/KyleBanks/depth v1.2.1 h1:5h8fQADFrWtarTdtDudMmGsC7GPbOAu6RVB3ffsVFHc=
2
+ github.com/KyleBanks/depth v1.2.1/go.mod h1:jzSb9d0L43HxTQfT+oSA1EEp2q+ne2uh6XgeJcm8brE=
3
+ github.com/PuerkitoBio/purell v1.1.1 h1:WEQqlqaGbrPkxLJWfBwQmfEAE1Z7ONdDLqrN38tNFfI=
4
+ github.com/PuerkitoBio/purell v1.1.1/go.mod h1:c11w/QuzBsJSee3cPx9rAFu61PvFxuPbtSwDGJws/X0=
5
+ github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578 h1:d+Bc7a5rLufV/sSk/8dngufqelfh6jnri85riMAaF/M=
6
+ github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578/go.mod h1:uGdkoq3SwY9Y+13GIhn11/XLaGBb4BfwItxLd5jeuXE=
7
  github.com/bytedance/gopkg v0.1.3 h1:TPBSwH8RsouGCBcMBktLt1AymVo2TVsBVCY4b6TnZ/M=
8
  github.com/bytedance/gopkg v0.1.3/go.mod h1:576VvJ+eJgyCzdjS+c4+77QF3p7ubbtiKARP3TxducM=
9
  github.com/bytedance/sonic v1.14.2 h1:k1twIoe97C1DtYUo+fZQy865IuHia4PR5RPiuGPPIIE=
 
12
  github.com/bytedance/sonic/loader v0.4.0/go.mod h1:AR4NYCk5DdzZizZ5djGqQ92eEhCCcdf5x77udYiSJRo=
13
  github.com/cloudwego/base64x v0.1.6 h1:t11wG9AECkCDk5fMSoxmufanudBtJ+/HemLstXDLI2M=
14
  github.com/cloudwego/base64x v0.1.6/go.mod h1:OFcloc187FXDaYHvrNIjxSe8ncn0OOM8gEHfghB2IPU=
15
+ github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
16
  github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
17
  github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
18
  github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
 
24
  github.com/gin-contrib/sse v1.1.0/go.mod h1:hxRZ5gVpWMT7Z0B0gSNYqqsSCNIJMjzvm6fqCz9vjwM=
25
  github.com/gin-gonic/gin v1.11.0 h1:OW/6PLjyusp2PPXtyxKHU0RbX6I/l28FTdDlae5ueWk=
26
  github.com/gin-gonic/gin v1.11.0/go.mod h1:+iq/FyxlGzII0KHiBGjuNn4UNENUlKbGlNmc+W50Dls=
27
+ github.com/go-openapi/jsonpointer v0.19.3/go.mod h1:Pl9vOtqEWErmShwVjC8pYs9cog34VGT37dQOVbmoatg=
28
+ github.com/go-openapi/jsonpointer v0.19.5 h1:gZr+CIYByUqjcgeLXnQu2gHYQC9o73G2XUeOFYEICuY=
29
+ github.com/go-openapi/jsonpointer v0.19.5/go.mod h1:Pl9vOtqEWErmShwVjC8pYs9cog34VGT37dQOVbmoatg=
30
+ github.com/go-openapi/jsonreference v0.19.6 h1:UBIxjkht+AWIgYzCDSv2GN+E/togfwXUJFRTWhl2Jjs=
31
+ github.com/go-openapi/jsonreference v0.19.6/go.mod h1:diGHMEHg2IqXZGKxqyvWdfWU/aim5Dprw5bqpKkTvns=
32
+ github.com/go-openapi/spec v0.20.4 h1:O8hJrt0UMnhHcluhIdUgCLRWyM2x7QkBXRvOs7m+O1M=
33
+ github.com/go-openapi/spec v0.20.4/go.mod h1:faYFR1CvsJZ0mNsmsphTMSoRrNV3TEDoAM7FOEWeq8I=
34
+ github.com/go-openapi/swag v0.19.5/go.mod h1:POnQmlKehdgb5mhVOsnJFsivZCEZ/vjK9gh66Z9tfKk=
35
+ github.com/go-openapi/swag v0.19.15 h1:D2NRCBzS9/pEY3gP9Nl8aDqGUcPFrwG2p+CNFrLyrCM=
36
+ github.com/go-openapi/swag v0.19.15/go.mod h1:QYRuS/SOXUCsnplDa677K7+DxSOj6IPNl/eQntq43wQ=
37
  github.com/go-playground/assert/v2 v2.2.0 h1:JvknZsQTYeFEAhQwI4qEt9cyV5ONwRHC+lYKSsYSR8s=
38
  github.com/go-playground/assert/v2 v2.2.0/go.mod h1:VDjEfimB/XKnb+ZQfWdccd7VUvScMdVu0Titje2rxJ4=
39
  github.com/go-playground/locales v0.14.1 h1:EWaQ/wswjilfKLTECiXz7Rh+3BjFhfDFKv/oXslEjJA=
 
46
  github.com/goccy/go-json v0.10.5/go.mod h1:oq7eo15ShAhp70Anwd5lgX2pLfOS3QCiwU/PULtXL6M=
47
  github.com/goccy/go-yaml v1.19.1 h1:3rG3+v8pkhRqoQ/88NYNMHYVGYztCOCIZ7UQhu7H+NE=
48
  github.com/goccy/go-yaml v1.19.1/go.mod h1:XBurs7gK8ATbW4ZPGKgcbrY1Br56PdM69F7LkFRi1kA=
49
+ github.com/golang-jwt/jwt/v5 v5.3.1 h1:kYf81DTWFe7t+1VvL7eS+jKFVWaUnK9cB1qbwn63YCY=
50
+ github.com/golang-jwt/jwt/v5 v5.3.1/go.mod h1:fxCRLWMO43lRc8nhHWY6LGqRcf+1gQWArsqaEUEa5bE=
51
  github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8=
52
  github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU=
53
  github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
 
67
  github.com/jinzhu/now v1.1.5/go.mod h1:d3SSVoowX0Lcu0IBviAWJpolVfI5UJVZZ7cO71lE/z8=
68
  github.com/joho/godotenv v1.5.1 h1:7eLL/+HRGLY0ldzfGMeQkb7vMd0as4CfYvUVzLqw0N0=
69
  github.com/joho/godotenv v1.5.1/go.mod h1:f4LDr5Voq0i2e/R5DDNOoa2zzDfwtkZa6DnEwAbqwq4=
70
+ github.com/josharian/intern v1.0.0 h1:vlS4z54oSdjm0bgjRigI+G1HpF+tI+9rE5LLzOg8HmY=
71
+ github.com/josharian/intern v1.0.0/go.mod h1:5DoeVV0s6jJacbCEi61lwdGj/aVlrQvzHFFd8Hwg//Y=
72
  github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM=
73
  github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo=
74
  github.com/klauspost/cpuid/v2 v2.3.0 h1:S4CRMLnYUhGeDFDqkGriYKdfoFlDnMtqTiI/sFzhA9Y=
75
  github.com/klauspost/cpuid/v2 v2.3.0/go.mod h1:hqwkgyIinND0mEev00jJYCxPNVRVXFQeu1XKlok6oO0=
76
+ github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
77
+ github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
78
+ github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
79
+ github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
80
  github.com/leodido/go-urn v1.4.0 h1:WT9HwE9SGECu3lg4d/dIA+jxlljEa1/ffXKmRjqdmIQ=
81
  github.com/leodido/go-urn v1.4.0/go.mod h1:bvxc+MVxLKB4z00jd1z+Dvzr47oO32F/QSNjSBOlFxI=
82
+ github.com/mailru/easyjson v0.0.0-20190614124828-94de47d64c63/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc=
83
+ github.com/mailru/easyjson v0.0.0-20190626092158-b2ccc519800e/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc=
84
+ github.com/mailru/easyjson v0.7.6 h1:8yTIVnZgCoiM1TgqoeTl+LfU5Jg6/xL3QhGQnimLYnA=
85
+ github.com/mailru/easyjson v0.7.6/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc=
86
  github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY=
87
  github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
88
  github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
 
90
  github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
91
  github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9Gz0M=
92
  github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk=
93
+ github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno=
94
  github.com/pelletier/go-toml/v2 v2.2.4 h1:mye9XuhQ6gvn5h28+VilKrrPoQVanw5PMw/TB0t5Ec4=
95
  github.com/pelletier/go-toml/v2 v2.2.4/go.mod h1:2gIqNv+qfxSVS7cM2xJQKtLSTLUE9V8t9Stt+h56mCY=
96
  github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
 
104
  github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo=
105
  github.com/stretchr/objx v0.5.2/go.mod h1:FRsXN1f5AsAjCGJKqEizvkpNtU+EGNCLh3NxZ/8L+MA=
106
  github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
107
+ github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
108
  github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
109
  github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
110
  github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
 
112
  github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
113
  github.com/stretchr/testify v1.11.1 h1:7s2iGBzp5EwR7/aIZr8ao5+dra3wiQyKjjFuvgVKu7U=
114
  github.com/stretchr/testify v1.11.1/go.mod h1:wZwfW3scLgRK+23gO65QZefKpKQRnfz6sD981Nm4B6U=
115
+ github.com/swaggo/files v1.0.1 h1:J1bVJ4XHZNq0I46UU90611i9/YzdrF7x92oX1ig5IdE=
116
+ github.com/swaggo/files v1.0.1/go.mod h1:0qXmMNH6sXNf+73t65aKeB+ApmgxdnkQzVTAj2uaMUg=
117
+ github.com/swaggo/gin-swagger v1.6.1 h1:Ri06G4gc9N4t4k8hekMigJ9zKTFSlqj/9paAQCQs7cY=
118
+ github.com/swaggo/gin-swagger v1.6.1/go.mod h1:LQ+hJStHakCWRiK/YNYtJOu4mR2FP+pxLnILT/qNiTw=
119
+ github.com/swaggo/swag v1.16.6 h1:qBNcx53ZaX+M5dxVyTrgQ0PJ/ACK+NzhwcbieTt+9yI=
120
+ github.com/swaggo/swag v1.16.6/go.mod h1:ngP2etMK5a0P3QBizic5MEwpRmluJZPHjXcMoj4Xesg=
121
  github.com/twitchyliquid64/golang-asm v0.15.1 h1:SU5vSMR7hnwNxj24w34ZyCi/FmDZTkS4MhqMhdFk5YI=
122
  github.com/twitchyliquid64/golang-asm v0.15.1/go.mod h1:a1lVb/DtPvCB8fslRZhAngC2+aY1QWCk3Cedj/Gdt08=
123
  github.com/ugorji/go/codec v1.3.1 h1:waO7eEiFDwidsBN6agj1vJQ4AG7lh2yqXyOXqhgQuyY=
124
  github.com/ugorji/go/codec v1.3.1/go.mod h1:pRBVtBSKl77K30Bv8R2P+cLSGaTtex6fsA2Wjqmfxj4=
125
+ github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY=
126
  go.uber.org/mock v0.6.0 h1:hyF9dfmbgIX5EfOdasqLsWD6xqpNZlXblLB/Dbnwv3Y=
127
  go.uber.org/mock v0.6.0/go.mod h1:KiVJ4BqZJaMj4svdfmHM0AUx4NJYO8ZNpPnZn1Z+BBU=
128
  golang.org/x/arch v0.23.0 h1:lKF64A2jF6Zd8L0knGltUnegD62JMFBiCPBmQpToHhg=
129
  golang.org/x/arch v0.23.0/go.mod h1:dNHoOeKiyja7GTvF9NJS1l3Z2yntpQNzgrjh1cU103A=
130
+ golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
131
+ golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
132
  golang.org/x/crypto v0.46.0 h1:cKRW/pmt1pKAfetfu+RCEvjvZkA9RimPbh7bhFjGVBU=
133
  golang.org/x/crypto v0.46.0/go.mod h1:Evb/oLKmMraqjZ2iQTwDwvCtJkczlDuTmdJXoZVzqU0=
134
+ golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4=
135
+ golang.org/x/mod v0.30.0 h1:fDEXFVZ/fmCKProc/yAXXUijritrDzahmwwefnjoPFk=
136
+ golang.org/x/mod v0.30.0/go.mod h1:lAsf5O2EvJeSFMiBxXDki7sCgAxEUcZHXoXMKT4GJKc=
137
+ golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
138
+ golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
139
+ golang.org/x/net v0.0.0-20210421230115-4e50805a0758/go.mod h1:72T/g9IO56b78aLF+1Kcs5dz7/ng1VjMUvfKvpfy+jM=
140
+ golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
141
+ golang.org/x/net v0.7.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs=
142
  golang.org/x/net v0.48.0 h1:zyQRTTrjc33Lhh0fBgT/H3oZq9WuvRR5gPC70xpDiQU=
143
  golang.org/x/net v0.48.0/go.mod h1:+ndRgGjkh8FGtu1w1FGbEC31if4VrNVMuKTgcAAnQRY=
144
+ golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
145
+ golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
146
  golang.org/x/sync v0.19.0 h1:vV+1eWNmZ5geRlYjzm2adRgW2/mcpevXNg50YZtPCE4=
147
  golang.org/x/sync v0.19.0/go.mod h1:9KTHXmSnoGruLpwFjVSX0lNNA75CykiMECbovNTZqGI=
148
+ golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
149
+ golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
150
+ golang.org/x/sys v0.0.0-20210420072515-93ed5bcd2bfe/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
151
+ golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
152
+ golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
153
+ golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
154
+ golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
155
  golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
156
  golang.org/x/sys v0.39.0 h1:CvCKL8MeisomCi6qNZ+wbb0DN9E5AATixKsvNtMoMFk=
157
  golang.org/x/sys v0.39.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks=
158
+ golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
159
+ golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
160
+ golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k=
161
+ golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
162
+ golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
163
+ golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
164
+ golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
165
+ golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
166
  golang.org/x/text v0.32.0 h1:ZD01bjUt1FQ9WJ0ClOL5vxgxOI/sVCNgX1YtKwcY0mU=
167
  golang.org/x/text v0.32.0/go.mod h1:o/rUWzghvpD5TXrTIBuJU77MTaN0ljMWE47kxGJQ7jY=
168
+ golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
169
+ golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
170
+ golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc=
171
+ golang.org/x/tools v0.39.0 h1:ik4ho21kwuQln40uelmciQPp9SipgNDdrafrYA4TmQQ=
172
+ golang.org/x/tools v0.39.0/go.mod h1:JnefbkDPyD8UU2kI5fuf8ZX4/yUeh9W877ZeBONxUqQ=
173
+ golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
174
  google.golang.org/protobuf v1.36.11 h1:fV6ZwhNocDyBLK0dj+fg8ektcVegBBuEolpbTQyBNVE=
175
  google.golang.org/protobuf v1.36.11/go.mod h1:HTf+CrKn2C3g5S8VImy6tdcUvCska2kB7j23XfzDpco=
176
  gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
177
+ gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
178
+ gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
179
+ gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
180
+ gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY=
181
+ gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=
182
  gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
183
+ gopkg.in/yaml.v3 v3.0.0-20200615113413-eeeca48fe776/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
184
  gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
185
  gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
186
  gorm.io/driver/postgres v1.6.0 h1:2dxzU8xJ+ivvqTRph34QX+WrRaJlmfyPqXmoGVjMBa4=
middleware/auth_middleware.go ADDED
@@ -0,0 +1,60 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ package middleware
2
+
3
+ import (
4
+ "net/http"
5
+ "strings"
6
+
7
+ "dinacom-11.0-backend/utils"
8
+
9
+ "github.com/gin-gonic/gin"
10
+ )
11
+
12
+ func AuthMiddleware() gin.HandlerFunc {
13
+ return func(c *gin.Context) {
14
+ authHeader := c.GetHeader("Authorization")
15
+ if authHeader == "" {
16
+ c.AbortWithStatusJSON(http.StatusUnauthorized, gin.H{"error": "Authorization header is required"})
17
+ return
18
+ }
19
+
20
+ parts := strings.Split(authHeader, " ")
21
+ if len(parts) != 2 || parts[0] != "Bearer" {
22
+ c.AbortWithStatusJSON(http.StatusUnauthorized, gin.H{"error": "Invalid authorization header format"})
23
+ return
24
+ }
25
+
26
+ tokenString := parts[1]
27
+ claims, err := utils.ValidateToken(tokenString)
28
+ if err != nil {
29
+ c.AbortWithStatusJSON(http.StatusUnauthorized, gin.H{"error": "Invalid or expired token"})
30
+ return
31
+ }
32
+
33
+ // Set context variables
34
+ c.Set("user_id", claims.UserID)
35
+ c.Set("role", claims.Role)
36
+ c.Set("email", claims.Email)
37
+
38
+ c.Next()
39
+ }
40
+ }
41
+
42
+ func RoleMiddleware(allowedRoles ...string) gin.HandlerFunc {
43
+ return func(c *gin.Context) {
44
+ role, exists := c.Get("role")
45
+ if !exists {
46
+ c.AbortWithStatusJSON(http.StatusUnauthorized, gin.H{"error": "Unauthorized"})
47
+ return
48
+ }
49
+
50
+ userRole := role.(string)
51
+ for _, allowed := range allowedRoles {
52
+ if userRole == allowed {
53
+ c.Next()
54
+ return
55
+ }
56
+ }
57
+
58
+ c.AbortWithStatusJSON(http.StatusForbidden, gin.H{"error": "Forbidden: insufficient permissions"})
59
+ }
60
+ }
models/dto/auth_dto.go ADDED
@@ -0,0 +1,33 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ package dto
2
+
3
+ import "github.com/google/uuid"
4
+
5
+ type RegisterRequest struct {
6
+ FullName string `json:"fullname" binding:"required"`
7
+ Username string `json:"username" binding:"required"`
8
+ Email string `json:"email" binding:"required,email"`
9
+ Password string `json:"password" binding:"required,min=6"`
10
+ }
11
+
12
+ type LoginRequest struct {
13
+ Email string `json:"email" binding:"required,email"`
14
+ Password string `json:"password" binding:"required"`
15
+ }
16
+
17
+ type VerifyOTPRequest struct {
18
+ Email string `json:"email" binding:"required,email"`
19
+ OTP string `json:"otp" binding:"required,len=6"`
20
+ }
21
+
22
+ type AuthResponse struct {
23
+ Token string `json:"token"`
24
+ }
25
+
26
+ type UserResponse struct {
27
+ ID uuid.UUID `json:"id"`
28
+ Username string `json:"username"`
29
+ Fullname string `json:"fullname"`
30
+ Email string `json:"email"`
31
+ Role string `json:"role"`
32
+ Verified bool `json:"verified"`
33
+ }
models/entity/entity.go CHANGED
@@ -1 +1,21 @@
1
- package models
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ package entity
2
+
3
+ import (
4
+ "time"
5
+
6
+ "github.com/google/uuid"
7
+ "gorm.io/gorm"
8
+ )
9
+
10
+ type User struct {
11
+ ID uuid.UUID `gorm:"type:uuid;primary_key;default:gen_random_uuid()" json:"id"`
12
+ Username string `gorm:"type:varchar(100);not null;unique" json:"username"`
13
+ Fullname string `gorm:"column:name;type:varchar(100);not null" json:"fullname"`
14
+ Email string `gorm:"type:varchar(100);not null;unique" json:"email"`
15
+ Role string `gorm:"type:varchar(20);not null;default:'user'" json:"role"` // user, admin, worker
16
+ Password string `gorm:"type:varchar(255);not null" json:"-"`
17
+ Verified bool `gorm:"default:false" json:"verified"`
18
+ CreatedAt time.Time `json:"created_at"`
19
+ UpdatedAt time.Time `json:"updated_at"`
20
+ DeletedAt gorm.DeletedAt `gorm:"index" json:"deleted_at"`
21
+ }
provider/controller_provider.go CHANGED
@@ -4,20 +4,28 @@ import "dinacom-11.0-backend/controllers"
4
 
5
  type ControllerProvider interface {
6
  ProvideConnectionController() controllers.ConnectionController
 
7
  }
8
 
9
  type controllerProvider struct {
10
  connectionController controllers.ConnectionController
 
11
  }
12
 
13
  func NewControllerProvider(servicesProvider ServicesProvider) ControllerProvider {
14
 
15
  connectionController := controllers.NewConnectionController(servicesProvider.ProvideConnectionService())
 
16
  return &controllerProvider{
17
  connectionController: connectionController,
 
18
  }
19
  }
20
 
21
  func (c *controllerProvider) ProvideConnectionController() controllers.ConnectionController {
22
  return c.connectionController
23
  }
 
 
 
 
 
4
 
5
  type ControllerProvider interface {
6
  ProvideConnectionController() controllers.ConnectionController
7
+ ProvideAuthController() controllers.AuthController
8
  }
9
 
10
  type controllerProvider struct {
11
  connectionController controllers.ConnectionController
12
+ authController controllers.AuthController
13
  }
14
 
15
  func NewControllerProvider(servicesProvider ServicesProvider) ControllerProvider {
16
 
17
  connectionController := controllers.NewConnectionController(servicesProvider.ProvideConnectionService())
18
+ authController := controllers.NewAuthController(servicesProvider.ProvideAuthService())
19
  return &controllerProvider{
20
  connectionController: connectionController,
21
+ authController: authController,
22
  }
23
  }
24
 
25
  func (c *controllerProvider) ProvideConnectionController() controllers.ConnectionController {
26
  return c.connectionController
27
  }
28
+
29
+ func (c *controllerProvider) ProvideAuthController() controllers.AuthController {
30
+ return c.authController
31
+ }
provider/middleware_provider.go CHANGED
@@ -1,11 +1,25 @@
1
  package provider
2
 
 
 
 
 
 
 
3
  type MiddlewareProvider interface {
 
4
  }
5
 
6
  type middlewareProvider struct {
 
7
  }
8
 
9
  func NewMiddlewareProvider(servicesProvider ServicesProvider) MiddlewareProvider {
10
- return &middlewareProvider{}
 
 
 
 
 
 
11
  }
 
1
  package provider
2
 
3
+ import (
4
+ "dinacom-11.0-backend/middleware"
5
+
6
+ "github.com/gin-gonic/gin"
7
+ )
8
+
9
  type MiddlewareProvider interface {
10
+ ProvideAuthMiddleware() gin.HandlerFunc
11
  }
12
 
13
  type middlewareProvider struct {
14
+ authMiddleware gin.HandlerFunc
15
  }
16
 
17
  func NewMiddlewareProvider(servicesProvider ServicesProvider) MiddlewareProvider {
18
+ return &middlewareProvider{
19
+ authMiddleware: middleware.AuthMiddleware(),
20
+ }
21
+ }
22
+
23
+ func (m *middlewareProvider) ProvideAuthMiddleware() gin.HandlerFunc {
24
+ return m.authMiddleware
25
  }
provider/provider.go CHANGED
@@ -1,6 +1,7 @@
1
  package provider
2
 
3
  import (
 
4
  "github.com/gin-gonic/gin"
5
  )
6
 
@@ -28,7 +29,7 @@ func NewAppProvider() AppProvider {
28
  servicesProvider := NewServicesProvider(repositoriesProvider, configProvider)
29
  controllerProvider := NewControllerProvider(servicesProvider)
30
  middlewareProvider := NewMiddlewareProvider(servicesProvider)
31
- // configProvider.ProvideDatabaseConfig().AutoMigrateAll()
32
 
33
  return &appProvider{
34
  ginRouter: ginRouter,
 
1
  package provider
2
 
3
  import (
4
+ "dinacom-11.0-backend/models/entity"
5
  "github.com/gin-gonic/gin"
6
  )
7
 
 
29
  servicesProvider := NewServicesProvider(repositoriesProvider, configProvider)
30
  controllerProvider := NewControllerProvider(servicesProvider)
31
  middlewareProvider := NewMiddlewareProvider(servicesProvider)
32
+ configProvider.ProvideDatabaseConfig().AutoMigrateAll(&entity.User{})
33
 
34
  return &appProvider{
35
  ginRouter: ginRouter,
provider/repositories_provider.go CHANGED
@@ -4,17 +4,27 @@ import "dinacom-11.0-backend/repositories"
4
 
5
  type RepositoriesProvider interface {
6
  ProvideConnectionRepository() repositories.ConnectionRepository
 
7
  }
8
 
9
  type repositoriesProvider struct {
10
  connectionRepository repositories.ConnectionRepository
 
11
  }
12
 
13
  func NewRepositoriesProvider(cfg ConfigProvider) RepositoriesProvider {
14
  connectionRepository := repositories.NewConnectionRepository(cfg.ProvideDatabaseConfig().GetInstance())
15
- return &repositoriesProvider{connectionRepository: connectionRepository}
 
 
 
 
16
  }
17
 
18
  func (rp *repositoriesProvider) ProvideConnectionRepository() repositories.ConnectionRepository {
19
  return rp.connectionRepository
20
  }
 
 
 
 
 
4
 
5
  type RepositoriesProvider interface {
6
  ProvideConnectionRepository() repositories.ConnectionRepository
7
+ ProvideUserRepository() repositories.UserRepository
8
  }
9
 
10
  type repositoriesProvider struct {
11
  connectionRepository repositories.ConnectionRepository
12
+ userRepository repositories.UserRepository
13
  }
14
 
15
  func NewRepositoriesProvider(cfg ConfigProvider) RepositoriesProvider {
16
  connectionRepository := repositories.NewConnectionRepository(cfg.ProvideDatabaseConfig().GetInstance())
17
+ userRepository := repositories.NewUserRepository(cfg.ProvideDatabaseConfig().GetInstance())
18
+ return &repositoriesProvider{
19
+ connectionRepository: connectionRepository,
20
+ userRepository: userRepository,
21
+ }
22
  }
23
 
24
  func (rp *repositoriesProvider) ProvideConnectionRepository() repositories.ConnectionRepository {
25
  return rp.connectionRepository
26
  }
27
+
28
+ func (rp *repositoriesProvider) ProvideUserRepository() repositories.UserRepository {
29
+ return rp.userRepository
30
+ }
provider/services_provider.go CHANGED
@@ -4,17 +4,27 @@ import "dinacom-11.0-backend/services"
4
 
5
  type ServicesProvider interface {
6
  ProvideConnectionService() services.ConnectionService
 
7
  }
8
 
9
  type servicesProvider struct {
10
  connectionService services.ConnectionService
 
11
  }
12
 
13
  func NewServicesProvider(repoProvider RepositoriesProvider, configProvider ConfigProvider) ServicesProvider {
14
  connectionService := services.NewConnectionService(repoProvider.ProvideConnectionRepository())
15
- return &servicesProvider{connectionService: connectionService}
 
 
 
 
16
  }
17
 
18
  func (s *servicesProvider) ProvideConnectionService() services.ConnectionService {
19
  return s.connectionService
20
  }
 
 
 
 
 
4
 
5
  type ServicesProvider interface {
6
  ProvideConnectionService() services.ConnectionService
7
+ ProvideAuthService() services.AuthService
8
  }
9
 
10
  type servicesProvider struct {
11
  connectionService services.ConnectionService
12
+ authService services.AuthService
13
  }
14
 
15
  func NewServicesProvider(repoProvider RepositoriesProvider, configProvider ConfigProvider) ServicesProvider {
16
  connectionService := services.NewConnectionService(repoProvider.ProvideConnectionRepository())
17
+ authService := services.NewAuthService(repoProvider.ProvideUserRepository())
18
+ return &servicesProvider{
19
+ connectionService: connectionService,
20
+ authService: authService,
21
+ }
22
  }
23
 
24
  func (s *servicesProvider) ProvideConnectionService() services.ConnectionService {
25
  return s.connectionService
26
  }
27
+
28
+ func (s *servicesProvider) ProvideAuthService() services.AuthService {
29
+ return s.authService
30
+ }
repositories/user_repository.go ADDED
@@ -0,0 +1,43 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ package repositories
2
+
3
+ import (
4
+ "errors"
5
+
6
+ entity "dinacom-11.0-backend/models/entity"
7
+
8
+ "gorm.io/gorm"
9
+ )
10
+
11
+ type UserRepository interface {
12
+ CreateUser(user *entity.User) error
13
+ FindUserByEmail(email string) (*entity.User, error)
14
+ UpdateUserVerified(email string, verified bool) error
15
+ }
16
+
17
+ type userRepository struct {
18
+ db *gorm.DB
19
+ }
20
+
21
+ func NewUserRepository(db *gorm.DB) UserRepository {
22
+ return &userRepository{db: db}
23
+ }
24
+
25
+ func (r *userRepository) CreateUser(user *entity.User) error {
26
+ return r.db.Create(user).Error
27
+ }
28
+
29
+ func (r *userRepository) FindUserByEmail(email string) (*entity.User, error) {
30
+ var user entity.User
31
+ err := r.db.Where("email = ?", email).First(&user).Error
32
+ if err != nil {
33
+ if errors.Is(err, gorm.ErrRecordNotFound) {
34
+ return nil, nil // Not found is not an error in this context, just nil user
35
+ }
36
+ return nil, err
37
+ }
38
+ return &user, nil
39
+ }
40
+
41
+ func (r *userRepository) UpdateUserVerified(email string, verified bool) error {
42
+ return r.db.Model(&entity.User{}).Where("email = ?", email).Update("verified", verified).Error
43
+ }
router/auth_router.go ADDED
@@ -0,0 +1,43 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ package router
2
+
3
+ import (
4
+ "dinacom-11.0-backend/controllers"
5
+
6
+ "github.com/gin-gonic/gin"
7
+ "github.com/gin-contrib/gzip"
8
+ )
9
+
10
+ type AuthRouter interface {
11
+ Setup(router *gin.RouterGroup)
12
+ }
13
+
14
+ type authRouter struct {
15
+ authController controllers.AuthController
16
+ }
17
+
18
+ func NewAuthRouter(authController controllers.AuthController) AuthRouter {
19
+ return &authRouter{authController: authController}
20
+ }
21
+
22
+ func (r *authRouter) Setup(router *gin.RouterGroup) {
23
+ authGroup := router.Group("/auth")
24
+ authGroup.Use(gzip.Gzip(gzip.DefaultCompression))
25
+ {
26
+ userGroup := authGroup.Group("/user")
27
+ {
28
+ userGroup.POST("/register", r.authController.RegisterUser)
29
+ userGroup.POST("/verify-otp", r.authController.VerifyOTP)
30
+ userGroup.POST("/login", r.authController.LoginUser)
31
+ }
32
+
33
+ adminGroup := authGroup.Group("/admin")
34
+ {
35
+ adminGroup.POST("/login", r.authController.LoginAdmin)
36
+ }
37
+
38
+ workerGroup := authGroup.Group("/worker")
39
+ {
40
+ workerGroup.POST("/login", r.authController.LoginWorker)
41
+ }
42
+ }
43
+ }
router/router.go CHANGED
@@ -1,12 +1,21 @@
1
  package router
2
 
3
  import (
 
4
  "dinacom-11.0-backend/provider"
 
 
5
  )
6
 
7
  func RunRouter(appProvider provider.AppProvider) {
8
  router, controller, config := appProvider.ProvideRouter(), appProvider.ProvideControllers(), appProvider.ProvideConfig()
9
  ConnectionRouter(router, controller)
 
 
 
 
 
 
10
  err := router.Run(config.ProvideEnvConfig().GetTCPAddress())
11
  if err != nil {
12
  panic(err)
 
1
  package router
2
 
3
  import (
4
+ _ "dinacom-11.0-backend/docs"
5
  "dinacom-11.0-backend/provider"
6
+ swaggerFiles "github.com/swaggo/files"
7
+ ginSwagger "github.com/swaggo/gin-swagger"
8
  )
9
 
10
  func RunRouter(appProvider provider.AppProvider) {
11
  router, controller, config := appProvider.ProvideRouter(), appProvider.ProvideControllers(), appProvider.ProvideConfig()
12
  ConnectionRouter(router, controller)
13
+
14
+ authRouter := NewAuthRouter(controller.ProvideAuthController())
15
+ authRouter.Setup(router.Group("/api"))
16
+
17
+ router.GET("/swagger/*any", ginSwagger.WrapHandler(swaggerFiles.Handler))
18
+
19
  err := router.Run(config.ProvideEnvConfig().GetTCPAddress())
20
  if err != nil {
21
  panic(err)
services/auth_service.go ADDED
@@ -0,0 +1,174 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ package services
2
+
3
+ import (
4
+ "errors"
5
+ "sync"
6
+
7
+ "dinacom-11.0-backend/models/dto"
8
+ entity "dinacom-11.0-backend/models/entity"
9
+ "dinacom-11.0-backend/repositories"
10
+ "dinacom-11.0-backend/utils"
11
+ )
12
+
13
+ type AuthService interface {
14
+ RegisterUser(req dto.RegisterRequest) error
15
+ VerifyOTP(req dto.VerifyOTPRequest) (string, error)
16
+ LoginUser(req dto.LoginRequest) (string, error)
17
+ LoginAdmin(req dto.LoginRequest) (string, error)
18
+ LoginWorker(req dto.LoginRequest) (string, error)
19
+ }
20
+
21
+ type authService struct {
22
+ userRepo repositories.UserRepository
23
+ otpStore map[string]string // Simple in-memory store for OTPs: email -> otp
24
+ mutex sync.RWMutex
25
+ }
26
+
27
+ func NewAuthService(userRepo repositories.UserRepository) AuthService {
28
+ return &authService{
29
+ userRepo: userRepo,
30
+ otpStore: make(map[string]string),
31
+ }
32
+ }
33
+
34
+ func (s *authService) RegisterUser(req dto.RegisterRequest) error {
35
+ // Check if user exists
36
+ existingUser, err := s.userRepo.FindUserByEmail(req.Email)
37
+ if err != nil {
38
+ return err
39
+ }
40
+ if existingUser != nil {
41
+ return errors.New("email already registered")
42
+ }
43
+
44
+ // Hash password
45
+ hashedPassword, err := utils.HashPassword(req.Password)
46
+ if err != nil {
47
+ return err
48
+ }
49
+
50
+ // Create user (verified = false)
51
+ user := &entity.User{
52
+ Username: req.Username,
53
+ Fullname: req.FullName,
54
+ Email: req.Email,
55
+ Role: "user",
56
+ Password: hashedPassword,
57
+ Verified: false,
58
+ }
59
+
60
+ if err := s.userRepo.CreateUser(user); err != nil {
61
+ return err
62
+ }
63
+
64
+ // Generate and Send OTP
65
+ otp := utils.GenerateOTP()
66
+
67
+ s.mutex.Lock()
68
+ s.otpStore[req.Email] = otp
69
+ s.mutex.Unlock()
70
+
71
+ utils.SendOTP(req.Email, otp)
72
+
73
+ return nil
74
+ }
75
+
76
+ func (s *authService) VerifyOTP(req dto.VerifyOTPRequest) (string, error) {
77
+ s.mutex.RLock()
78
+ storedOTP, exists := s.otpStore[req.Email]
79
+ s.mutex.RUnlock()
80
+
81
+ if !exists || storedOTP != req.OTP {
82
+ return "", errors.New("invalid or expired OTP")
83
+ }
84
+
85
+ // Verify user in DB
86
+ if err := s.userRepo.UpdateUserVerified(req.Email, true); err != nil {
87
+ return "", err
88
+ }
89
+
90
+ // Get User to generate token
91
+ user, err := s.userRepo.FindUserByEmail(req.Email)
92
+ if err != nil {
93
+ return "", err
94
+ }
95
+
96
+ // Clear OTP
97
+ s.mutex.Lock()
98
+ delete(s.otpStore, req.Email)
99
+ s.mutex.Unlock()
100
+
101
+ // Generate Token
102
+ return utils.GenerateAccessToken(user.ID, user.Role, user.Email)
103
+ }
104
+
105
+ func (s *authService) LoginUser(req dto.LoginRequest) (string, error) {
106
+ user, err := s.userRepo.FindUserByEmail(req.Email)
107
+ if err != nil {
108
+ return "", err
109
+ }
110
+ if user == nil {
111
+ return "", errors.New("invalid email or password")
112
+ }
113
+
114
+ if user.Role != "user" {
115
+ return "", errors.New("unauthorized: user role required")
116
+ }
117
+
118
+ if !user.Verified {
119
+ // Prepare new OTP if not verified (optional, but good UX to allow re-verify)
120
+ // For now, just block
121
+ return "", errors.New("account not verified. please verify OTP")
122
+ }
123
+
124
+ if err := utils.ComparePassword(user.Password, req.Password); err != nil {
125
+ return "", errors.New("invalid email or password")
126
+ }
127
+
128
+ return utils.GenerateAccessToken(user.ID, user.Role, user.Email)
129
+ }
130
+
131
+ func (s *authService) LoginAdmin(req dto.LoginRequest) (string, error) {
132
+ // For admin, we assume they might be pre-seeded or created via different flow.
133
+ // But validation logic is similar, just role check.
134
+ // NOTE: If Admin doesn't exist, we can't login.
135
+ // For testing, user might need to seed an admin.
136
+
137
+ user, err := s.userRepo.FindUserByEmail(req.Email)
138
+ if err != nil {
139
+ return "", err
140
+ }
141
+ if user == nil {
142
+ return "", errors.New("invalid email or password")
143
+ }
144
+
145
+ if user.Role != "admin" {
146
+ return "", errors.New("unauthorized: admin role required")
147
+ }
148
+
149
+ if err := utils.ComparePassword(user.Password, req.Password); err != nil {
150
+ return "", errors.New("invalid email or password")
151
+ }
152
+
153
+ return utils.GenerateAccessToken(user.ID, user.Role, user.Email)
154
+ }
155
+
156
+ func (s *authService) LoginWorker(req dto.LoginRequest) (string, error) {
157
+ user, err := s.userRepo.FindUserByEmail(req.Email)
158
+ if err != nil {
159
+ return "", err
160
+ }
161
+ if user == nil {
162
+ return "", errors.New("invalid email or password")
163
+ }
164
+
165
+ if user.Role != "worker" {
166
+ return "", errors.New("unauthorized: worker role required")
167
+ }
168
+
169
+ if err := utils.ComparePassword(user.Password, req.Password); err != nil {
170
+ return "", errors.New("invalid email or password")
171
+ }
172
+
173
+ return utils.GenerateAccessToken(user.ID, user.Role, user.Email)
174
+ }
setup_swagger.bat ADDED
@@ -0,0 +1,21 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ @echo off
2
+ echo Installing swag...
3
+ go install github.com/swaggo/swag/cmd/swag@latest
4
+ if %errorlevel% neq 0 (
5
+ echo Failed to install swag
6
+ exit /b %errorlevel%
7
+ )
8
+
9
+ echo Running swag init...
10
+ %USERPROFILE%\go\bin\swag init
11
+ if %errorlevel% neq 0 (
12
+ echo Failed to run swag init. Trying just 'swag init'
13
+ swag init
14
+ if %errorlevel% neq 0 (
15
+ echo Failed to run swag init
16
+ exit /b %errorlevel%
17
+ )
18
+ )
19
+
20
+ echo Running go mod tidy...
21
+ go mod tidy
utils/jwt_util.go ADDED
@@ -0,0 +1,62 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ package utils
2
+
3
+ import (
4
+ "errors"
5
+ "fmt"
6
+ "os"
7
+ "time"
8
+
9
+ "github.com/golang-jwt/jwt/v5"
10
+ "github.com/google/uuid"
11
+ )
12
+
13
+ type Claims struct {
14
+ UserID uuid.UUID `json:"user_id"`
15
+ Role string `json:"role"`
16
+ Email string `json:"email"`
17
+ jwt.RegisteredClaims
18
+ }
19
+
20
+ func GenerateAccessToken(userID uuid.UUID, role, email string) (string, error) {
21
+ jwtSecret := os.Getenv("JWT_SECRET_KEY")
22
+ if jwtSecret == "" {
23
+ return "", errors.New("JWT_SECRET_KEY is not set")
24
+ }
25
+
26
+ claims := Claims{
27
+ UserID: userID,
28
+ Role: role,
29
+ Email: email,
30
+ RegisteredClaims: jwt.RegisteredClaims{
31
+ ExpiresAt: jwt.NewNumericDate(time.Now().Add(30 * time.Minute)),
32
+ Issuer: "dinacom-backend",
33
+ },
34
+ }
35
+
36
+ token := jwt.NewWithClaims(jwt.SigningMethodHS256, claims)
37
+ return token.SignedString([]byte(jwtSecret))
38
+ }
39
+
40
+ func ValidateToken(tokenString string) (*Claims, error) {
41
+ jwtSecret := os.Getenv("JWT_SECRET_KEY")
42
+ if jwtSecret == "" {
43
+ return nil, errors.New("JWT_SECRET_KEY is not set")
44
+ }
45
+
46
+ token, err := jwt.ParseWithClaims(tokenString, &Claims{}, func(token *jwt.Token) (interface{}, error) {
47
+ if _, ok := token.Method.(*jwt.SigningMethodHMAC); !ok {
48
+ return nil, fmt.Errorf("unexpected signing method: %v", token.Header["alg"])
49
+ }
50
+ return []byte(jwtSecret), nil
51
+ })
52
+
53
+ if err != nil {
54
+ return nil, err
55
+ }
56
+
57
+ if claims, ok := token.Claims.(*Claims); ok && token.Valid {
58
+ return claims, nil
59
+ }
60
+
61
+ return nil, errors.New("invalid token")
62
+ }
utils/otp_util.go ADDED
@@ -0,0 +1,56 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ package utils
2
+
3
+ import (
4
+ "fmt"
5
+ "math/rand"
6
+ "net/smtp"
7
+ "os"
8
+ "time"
9
+ )
10
+
11
+ func GenerateOTP() string {
12
+ r := rand.New(rand.NewSource(time.Now().UnixNano()))
13
+ return fmt.Sprintf("%06d", r.Intn(1000000))
14
+ }
15
+
16
+ func SendOTP(email, otp string) error {
17
+ smtpHost := os.Getenv("SMTP_HOST")
18
+ smtpPort := os.Getenv("SMTP_PORT")
19
+ smtpEmail := os.Getenv("SMTP_EMAIL")
20
+ smtpPassword := os.Getenv("SMTP_PASSWORD")
21
+
22
+ if smtpHost == "" || smtpPort == "" || smtpEmail == "" || smtpPassword == "" {
23
+ fmt.Printf("----------------------------------------------------------------\n")
24
+ fmt.Printf("SENDING OTP TO: %s\n", email)
25
+ fmt.Printf("OTP CODE: %s\n", otp)
26
+ fmt.Printf("----------------------------------------------------------------\n")
27
+ return nil
28
+ }
29
+
30
+ auth := smtp.PlainAuth("", smtpEmail, smtpPassword, smtpHost)
31
+
32
+ subject := "Your OTP Verification Code"
33
+ body := fmt.Sprintf(`
34
+ Hello,
35
+
36
+ Your OTP verification code is: %s
37
+
38
+ This code will expire in 5 minutes. Do not share this code with anyone.
39
+
40
+ Best regards,
41
+ Dinacom Team
42
+ `, otp)
43
+
44
+ msg := []byte(fmt.Sprintf("From: %s\r\nTo: %s\r\nSubject: %s\r\nMIME-Version: 1.0\r\nContent-Type: text/plain; charset=UTF-8\r\n\r\n%s",
45
+ smtpEmail, email, subject, body))
46
+
47
+ addr := fmt.Sprintf("%s:%s", smtpHost, smtpPort)
48
+ err := smtp.SendMail(addr, auth, smtpEmail, []string{email}, msg)
49
+ if err != nil {
50
+ fmt.Printf("Failed to send OTP email: %v\n", err)
51
+ return err
52
+ }
53
+
54
+ fmt.Printf("OTP sent successfully to: %s\n", email)
55
+ return nil
56
+ }
utils/password_util.go ADDED
@@ -0,0 +1,12 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ package utils
2
+
3
+ import "golang.org/x/crypto/bcrypt"
4
+
5
+ func HashPassword(password string) (string, error) {
6
+ bytes, err := bcrypt.GenerateFromPassword([]byte(password), bcrypt.DefaultCost)
7
+ return string(bytes), err
8
+ }
9
+
10
+ func ComparePassword(hashedPassword, password string) error {
11
+ return bcrypt.CompareHashAndPassword([]byte(hashedPassword), []byte(password))
12
+ }
utils/response_util.go CHANGED
@@ -86,3 +86,13 @@ func SendResponse[Tdata any, TMetaData any](c *gin.Context, metaData TMetaData,
86
  }
87
 
88
  }
 
 
 
 
 
 
 
 
 
 
 
86
  }
87
 
88
  }
89
+ func SendSuccessResponse(c *gin.Context, message string, data interface{}) {
90
+ ResponseOK[interface{}, interface{}](c, nil, data)
91
+ }
92
+
93
+ func SendErrorResponse(c *gin.Context, code int, message string) {
94
+ c.JSON(code, dto.ErrorResponse{
95
+ Status: "error",
96
+ Message: message,
97
+ })
98
+ }