File size: 6,002 Bytes
ab82ffd
 
 
73d0319
 
ab82ffd
987726a
ab82ffd
 
 
 
 
 
 
 
 
987726a
73d0319
ab82ffd
 
 
 
 
124871e
ab82ffd
 
124871e
ab82ffd
 
 
124871e
ab82ffd
 
c0722d3
 
 
 
 
 
 
 
 
 
 
ab82ffd
 
132b9f0
124871e
 
 
 
 
 
 
 
 
 
ab82ffd
 
 
c0722d3
 
 
 
 
 
 
 
 
 
ab82ffd
 
 
 
 
 
c0722d3
 
 
 
 
 
 
 
 
 
 
ab82ffd
 
 
 
 
 
 
c0722d3
 
 
 
 
 
 
 
 
 
ab82ffd
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
987726a
c0722d3
 
 
 
 
 
 
 
 
 
 
 
987726a
 
c0722d3
 
987726a
 
 
 
 
 
 
 
a57273b
987726a
 
73d0319
027c2a2
 
 
 
 
 
 
 
 
73d0319
 
 
 
3577b8e
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
package controllers

import (
	"time"

	"abdanhafidz.com/go-boilerplate/models/dto"
	entity "abdanhafidz.com/go-boilerplate/models/entity"
	"abdanhafidz.com/go-boilerplate/services"
	"github.com/gin-gonic/gin"
)

type AuthenticationController interface {
	SignUp(ctx *gin.Context)
	SignIn(ctx *gin.Context)
	ExternalAuth(ctx *gin.Context)
	ChangePassword(ctx *gin.Context)
	UpdateUserRole(ctx *gin.Context)
	SeedSuperAdmin(ctx *gin.Context)
}

type authenticationController struct {
	accountService      services.AccountService
	externalAuthService services.ExternalAuthService
	emailVerification   services.EmailVerificationService
}

func NewAuthenticationController(accountService services.AccountService, externalAuthService services.ExternalAuthService, emailVerification services.EmailVerificationService) AuthenticationController {
	return &authenticationController{
		accountService:      accountService,
		externalAuthService: externalAuthService,
		emailVerification:   emailVerification,
	}
}

// SignUp godoc
// @Summary      User Registration
// @Description  Register a new user account
// @Tags         Authentication
// @Accept       json
// @Produce      json
// @Param        request  body      dto.SignUpRequest  true  "Sign Up Request"
// @Success      200      {object}  dto.SuccessResponse[entity.Account]
// @Failure      400      {object}  dto.ErrorResponse
// @Router       /api/v1/authentication/register [post]
func (c *authenticationController) SignUp(ctx *gin.Context) {
	req := RequestJSON[dto.SignUpRequest](ctx)
	res, err := c.accountService.Create(ctx.Request.Context(), req.Name, req.Email, req.Username, req.Password, "user")
	if err != nil {
		ResponseJSON(ctx, req, entity.Account{}, err)
		return
	}

	if _, err := c.emailVerification.CreateToken(ctx.Request.Context(), res.Email, 0, time.Time{}); err != nil {
		ResponseJSON(ctx, req, entity.Account{}, err)
		return
	}

	ResponseJSON(ctx, req, res, err)
}

// SignIn godoc
// @Summary      User Login
// @Description  Authenticate user and obtain access token
// @Tags         Authentication
// @Accept       json
// @Produce      json
// @Param        request  body      dto.SignInRequest  true  "Sign In Request"
// @Success      200      {object}  dto.SuccessResponse[dto.AuthenticatedUser]
// @Failure      400      {object}  dto.ErrorResponse
// @Router       /api/v1/authentication/login [post]
func (c *authenticationController) SignIn(ctx *gin.Context) {
	req := RequestJSON[dto.SignInRequest](ctx)
	res, err := c.accountService.Validate(ctx, req.EmailorUsername, req.Password)
	ResponseJSON(ctx, req, res, err)
}

// ChangePassword godoc
// @Summary      Change User Password
// @Description  Change the password of the authenticated user
// @Tags         Authentication
// @Accept       json
// @Produce      json
// @Param        request  body      dto.ChangePasswordRequest  true  "Change Password Request"
// @Success      200      {object}  dto.SuccessResponse[dto.AuthenticatedUser]
// @Failure      400      {object}  dto.ErrorResponse
// @Security     BearerAuth
// @Router       /api/v1/authentication/change-password [put]
func (c *authenticationController) ChangePassword(ctx *gin.Context) {
	req := RequestJSON[dto.ChangePasswordRequest](ctx)
	accountId := ParseAccountId(ctx)
	res, err := c.accountService.ChangePassword(ctx.Request.Context(), accountId, req.OldPassword, req.NewPassword)
	ResponseJSON(ctx, req, res, err)
}

// ExternalAuth godoc
// @Summary      External Authentication
// @Description  Authenticate user using external OAuth provider
// @Tags         Authentication
// @Accept       json
// @Produce      json
// @Param        request  body      dto.ExternalAuthRequest  true  "External Auth Request"
// @Success      200      {object}  dto.SuccessResponse[dto.AuthenticatedUser]
// @Failure      400      {object}  dto.ErrorResponse
// @Router       /api/v1/authentication/external-login [post]
func (c *authenticationController) ExternalAuth(ctx *gin.Context) {
	req := RequestJSON[dto.ExternalAuthRequest](ctx)
	var (
		res dto.AuthenticatedUser
		err error
	)

	switch req.OauthProvider {
	case "google":
		res, err = c.externalAuthService.GoogleAuth(ctx.Request.Context(), req.OauthID)
	default:
		ResponseJSON(ctx, req, dto.AuthenticatedUser{}, nil)
		return
	}

	ResponseJSON(ctx, req, res, err)
}

// UpdateUserRole godoc
// @Summary      Update User Role
// @Description  Update the role of a user account
// @Tags         Authentication
// @Accept       json
// @Produce      json
// @Param        accountId  path      string                     true  "Account ID"
// @Param        request    body      dto.UpdateUserRoleRequest  true  "Update User Role Request"
// @Success      200        {object}  dto.SuccessResponse[entity.Account]
// @Failure      400        {object}  dto.ErrorResponse
// @Security     BearerAuth
// @Router       /api/v1/admin/authentication/{account_id}/assign [put]
func (c *authenticationController) UpdateUserRole(ctx *gin.Context) {
	req := RequestJSON[dto.UpdateUserRoleRequest](ctx)
	accountId := ParseUUID(ctx, "accountId")
	acc, err := c.accountService.GetById(ctx.Request.Context(), accountId)
	if err != nil {
		ResponseJSON(ctx, req, entity.Account{}, err)
		return
	}

	accountToUpdate := acc
	accountToUpdate.Role = req.Role

	res, err := c.accountService.UpdateUserRole(ctx.Request.Context(), accountToUpdate)
	ResponseJSON(ctx, req, res, err)
}

// SeedSuperAdmin godoc
// @Summary      Seed Super Admin
// @Description  Seed a super admin account using predefined credentials
// @Tags         Authentication
// @Accept       json
// @Produce      json
// @Success      200  {object}  dto.SuccessResponse[any]
// @Failure      400  {object}  dto.ErrorResponse
// @Router       /api/v1/authentication/seed-superadmin [post]
func (c *authenticationController) SeedSuperAdmin(ctx *gin.Context) {
	err := c.accountService.SeedSuperAdmin(ctx.Request.Context())
	ResponseJSON(ctx, interface{}(nil), interface{}(nil), err)
}