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) }