UPDATE: logout
All checks were successful
Build and Release / release (push) Successful in 1m28s

This commit is contained in:
2026-04-07 17:59:15 +07:00
parent 677ae95c8f
commit a1d7f2b9ee
4 changed files with 102 additions and 31 deletions

View File

@@ -432,3 +432,40 @@ func (h *AuthController) GoogleCallback(c fiber.Ctx) error {
return c.Redirect().To(redirectURL)
}
func (h *AuthController) Logout(c fiber.Ctx) error {
ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
defer cancel()
userId := c.Locals("uid").(string)
err := h.service.Logout(ctx, userId)
if err != nil {
return c.Status(fiber.StatusInternalServerError).JSON(response.CommonResponse{
Status: false,
Message: err.Error(),
})
}
c.Cookie(&fiber.Cookie{
Name: "access_token",
Value: "",
Expires: time.Now().Add(-time.Hour),
HTTPOnly: true,
Secure: true,
Path: "/",
})
c.Cookie(&fiber.Cookie{
Name: "refresh_token",
Value: "",
Expires: time.Now().Add(-time.Hour),
HTTPOnly: true,
Secure: true,
Path: "/",
})
return c.Status(fiber.StatusOK).JSON(response.CommonResponse{
Status: true,
Message: "Logged out successfully",
})
}

View File

@@ -18,4 +18,5 @@ func AuthRoutes(app *fiber.App, controller *controllers.AuthController, userRepo
route.Post("/forgot-password", controller.ForgotPassword)
route.Get("/google/login", controller.GoogleLogin)
route.Get("/google/callback", controller.GoogleCallback)
route.Post("/logout", middlewares.JwtAccess(userRepo), controller.Logout)
}

View File

@@ -33,6 +33,7 @@ import (
type AuthService interface {
Signin(ctx context.Context, dto *request.SignInDto) (*response.AuthResponse, error)
Signup(ctx context.Context, dto *request.SignUpDto) (*response.AuthResponse, error)
Logout(ctx context.Context, userId string) error
ForgotPassword(ctx context.Context, dto *request.ForgotPasswordDto) error
VerifyToken(ctx context.Context, dto *request.VerifyTokenDto) (*response.VerifyTokenResponse, error)
CreateToken(ctx context.Context, dto *request.CreateTokenDto) error
@@ -170,6 +171,38 @@ func (a *authService) Signin(ctx context.Context, dto *request.SignInDto) (*resp
}
func (a *authService) Logout(ctx context.Context, userId string) error {
pgID, err := convert.StringToUUID(userId)
if err != nil {
return fiber.NewError(fiber.StatusInternalServerError, err.Error())
}
user , err := a.userRepo.GetByID(ctx, pgID)
if err != nil || user == nil {
return fiber.NewError(fiber.StatusInternalServerError, "Invalid user data")
}
err = a.userRepo.UpdateTokenVersion(ctx, sqlc.UpdateTokenVersionParams{
ID: pgID,
TokenVersion: user.TokenVersion + 1,
})
if err != nil {
return fiber.NewError(fiber.StatusInternalServerError, err.Error())
}
err = a.userRepo.UpdateRefreshToken(ctx, sqlc.UpdateUserRefreshTokenParams{
ID: pgID,
RefreshToken: pgtype.Text{
String: "",
Valid: false,
},
})
if err != nil {
return fiber.NewError(fiber.StatusInternalServerError, err.Error())
}
return nil
}
func (a *authService) RefreshToken(ctx context.Context, id string) (*response.AuthResponse, error) {
var pgID pgtype.UUID
err := pgID.Scan(id)

View File

@@ -210,8 +210,8 @@ func (u *userService) RestoreUser(ctx context.Context, userId string) (*response
func (u *userService) SearchUser(ctx context.Context, dto *request.SearchUserDto) (*response.PaginatedResponse, error) {
arg := sqlc.SearchUsersParams{
Limit: int32(dto.Limit + 1),
}
Limit: int32(dto.Limit + 1),
}
if dto.Sort != "" {
arg.Sort = pgtype.Text{String: dto.Sort, Valid: true}
@@ -225,64 +225,64 @@ func (u *userService) SearchUser(ctx context.Context, dto *request.SearchUserDto
arg.Order = pgtype.Text{String: "asc", Valid: true}
}
if dto.Cursor != "" {
if dto.Cursor != "" {
pgID, err := convert.StringToUUID(dto.Cursor)
if err != nil {
return nil, fiber.NewError(fiber.StatusBadRequest, "Invalid cursor format")
}
arg.Cursor = pgID
}
arg.Cursor = pgID
}
if dto.Search != "" {
if dto.Search != "" {
pgID, err := convert.StringToUUID(dto.Search)
if err == nil {
arg.SearchID = pgID
} else {
arg.SearchText = pgtype.Text{String: dto.Search, Valid: true}
}
}
}
if dto.IsDeleted != nil {
arg.IsDeleted = pgtype.Bool{Bool: *dto.IsDeleted, Valid: true}
}
arg.IsDeleted = pgtype.Bool{Bool: *dto.IsDeleted, Valid: true}
}
if len(dto.RoleIDs) > 0 {
var pgRoleIDs []pgtype.UUID
for _, idStr := range dto.RoleIDs {
var pgRoleIDs []pgtype.UUID
for _, idStr := range dto.RoleIDs {
pgID, err := convert.StringToUUID(idStr)
if err != nil {
continue
}
pgRoleIDs = append(pgRoleIDs, pgID)
}
arg.RoleIds = pgRoleIDs
}
}
arg.RoleIds = pgRoleIDs
}
rows, err := u.userRepo.Search(ctx, arg)
if err != nil {
return nil, err
}
if err != nil {
return nil, err
}
hasMore := false
var nextCursor string
var nextCursor string
if len(rows) > dto.Limit {
hasMore = true
nextCursor = rows[dto.Limit-1].ID
rows = rows[:dto.Limit]
}
if len(rows) > dto.Limit {
hasMore = true
nextCursor = rows[dto.Limit-1].ID
rows = rows[:dto.Limit]
}
users := models.UsersEntityToResponse(rows)
res := &response.PaginatedResponse{
Data: users,
Status: true,
Message: "",
}
Data: users,
Status: true,
Message: "",
}
res.Pagination.HasMore = hasMore
res.Pagination.NextCursor = nextCursor
res.Pagination.HasMore = hasMore
res.Pagination.NextCursor = nextCursor
return res, nil
return res, nil
}
func (u *userService) GetUserByID(ctx context.Context, userId string) (*response.UserResponse, error) {