Yimaru-BackEnd/internal/web_server/handlers/customer.go

271 lines
8.6 KiB
Go

package handlers
import (
"strconv"
"time"
"github.com/SamuelTariku/FortuneBet-Backend/internal/domain"
"github.com/SamuelTariku/FortuneBet-Backend/internal/services/authentication"
"github.com/SamuelTariku/FortuneBet-Backend/internal/web_server/response"
"github.com/gofiber/fiber/v2"
)
type CustomersRes struct {
ID int64 `json:"id"`
FirstName string `json:"first_name"`
LastName string `json:"last_name"`
Email string `json:"email"`
PhoneNumber string `json:"phone_number"`
Role domain.Role `json:"role"`
EmailVerified bool `json:"email_verified"`
PhoneVerified bool `json:"phone_verified"`
CreatedAt time.Time `json:"created_at"`
UpdatedAt time.Time `json:"updated_at"`
LastLogin time.Time `json:"last_login"`
SuspendedAt time.Time `json:"suspended_at"`
Suspended bool `json:"suspended"`
}
// GetAllCustomers godoc
// @Summary Get all Customers
// @Description Get all Customers
// @Tags customer
// @Accept json
// @Produce json
// @Param page query int false "Page number"
// @Param page_size query int false "Page size"
// @Success 200 {object} CustomersRes
// @Failure 400 {object} response.APIResponse
// @Failure 401 {object} response.APIResponse
// @Failure 500 {object} response.APIResponse
// @Router /customer [get]
func (h *Handler) GetAllCustomers(c *fiber.Ctx) error {
role := c.Locals("role").(domain.Role)
companyId := c.Locals("company_id").(domain.ValidInt64)
// Checking to make sure that admin user has a company id in the token
if role != domain.RoleSuperAdmin && !companyId.Valid {
return fiber.NewError(fiber.StatusInternalServerError, "Cannot get company ID")
}
searchQuery := c.Query("query")
searchString := domain.ValidString{
Value: searchQuery,
Valid: searchQuery != "",
}
createdBeforeQuery := c.Query("created_before")
var createdBefore domain.ValidTime
if createdBeforeQuery != "" {
createdBeforeParsed, err := time.Parse(time.RFC3339, createdBeforeQuery)
if err != nil {
h.logger.Error("invalid start_time format", "error", err)
return response.WriteJSON(c, fiber.StatusBadRequest, "Invalid start_time format", nil, nil)
}
createdBefore = domain.ValidTime{
Value: createdBeforeParsed,
Valid: true,
}
}
createdAfterQuery := c.Query("created_after")
var createdAfter domain.ValidTime
if createdAfterQuery != "" {
createdAfterParsed, err := time.Parse(time.RFC3339, createdAfterQuery)
if err != nil {
h.logger.Error("invalid start_time format", "error", err)
return response.WriteJSON(c, fiber.StatusBadRequest, "Invalid start_time format", nil, nil)
}
createdAfter = domain.ValidTime{
Value: createdAfterParsed,
Valid: true,
}
}
filter := domain.UserFilter{
Role: string(domain.RoleCustomer),
CompanyID: companyId,
Page: domain.ValidInt{
Value: c.QueryInt("page", 1) - 1,
Valid: true,
},
PageSize: domain.ValidInt{
Value: c.QueryInt("page_size", 10),
Valid: true,
},
Query: searchString,
CreatedBefore: createdBefore,
CreatedAfter: createdAfter,
}
valErrs, ok := h.validator.Validate(c, filter)
if !ok {
return response.WriteJSON(c, fiber.StatusBadRequest, "Invalid request", valErrs, nil)
}
customers, total, err := h.userSvc.GetAllUsers(c.Context(), filter)
if err != nil {
h.logger.Error("GetAllCustomers failed", "error", err)
return response.WriteJSON(c, fiber.StatusInternalServerError, "Failed to get Customers", err, nil)
}
var result []CustomersRes = make([]CustomersRes, len(customers))
for index, customer := range customers {
lastLogin, err := h.authSvc.GetLastLogin(c.Context(), customer.ID)
if err != nil {
if err == authentication.ErrRefreshTokenNotFound {
lastLogin = &customer.CreatedAt
} else {
h.logger.Error("Failed to get user last login", "userID", customer.ID, "error", err)
return fiber.NewError(fiber.StatusInternalServerError, "Failed to retrieve user last login")
}
}
result[index] = CustomersRes{
ID: customer.ID,
FirstName: customer.FirstName,
LastName: customer.LastName,
Email: customer.Email,
PhoneNumber: customer.PhoneNumber,
Role: customer.Role,
EmailVerified: customer.EmailVerified,
PhoneVerified: customer.PhoneVerified,
CreatedAt: customer.CreatedAt,
UpdatedAt: customer.UpdatedAt,
SuspendedAt: customer.SuspendedAt,
Suspended: customer.Suspended,
LastLogin: *lastLogin,
}
}
return response.WritePaginatedJSON(c, fiber.StatusOK, "Customers retrieved successfully", result, nil, filter.Page.Value, int(total))
}
// GetCustomerByID godoc
// @Summary Get customer by id
// @Description Get a single customer by id
// @Tags customer
// @Accept json
// @Produce json
// @Param id path int true "User ID"
// @Success 200 {object} CustomersRes
// @Failure 400 {object} response.APIResponse
// @Failure 401 {object} response.APIResponse
// @Failure 500 {object} response.APIResponse
// @Router /customer/{id} [get]
func (h *Handler) GetCustomerByID(c *fiber.Ctx) error {
userIDstr := c.Params("id")
userID, err := strconv.ParseInt(userIDstr, 10, 64)
if err != nil {
return fiber.NewError(fiber.StatusBadRequest, "Invalid customers ID")
}
user, err := h.userSvc.GetUserByID(c.Context(), userID)
if err != nil {
return fiber.NewError(fiber.StatusInternalServerError, "Failed to get customers")
}
lastLogin, err := h.authSvc.GetLastLogin(c.Context(), user.ID)
if err != nil {
if err != authentication.ErrRefreshTokenNotFound {
h.logger.Error("Failed to get user last login", "userID", user.ID, "error", err)
return fiber.NewError(fiber.StatusInternalServerError, "Failed to retrieve user last login")
}
lastLogin = &user.CreatedAt
}
res := CustomersRes{
ID: user.ID,
FirstName: user.FirstName,
LastName: user.LastName,
Email: user.Email,
PhoneNumber: user.PhoneNumber,
Role: user.Role,
EmailVerified: user.EmailVerified,
PhoneVerified: user.PhoneVerified,
CreatedAt: user.CreatedAt,
UpdatedAt: user.UpdatedAt,
SuspendedAt: user.SuspendedAt,
Suspended: user.Suspended,
LastLogin: *lastLogin,
}
return response.WriteJSON(c, fiber.StatusOK, "User retrieved successfully", res, nil)
}
type updateCustomerReq struct {
FirstName string `json:"first_name" example:"John"`
LastName string `json:"last_name" example:"Doe"`
Suspended bool `json:"suspended" example:"false"`
CompanyID *int64 `json:"company_id,omitempty" example:"1"`
}
// UpdateCustomers godoc
// @Summary Update Customers
// @Description Update Customers
// @Tags customer
// @Accept json
// @Produce json
// @Param Customers body updateCustomerReq true "Update Customers"
// @Success 200 {object} response.APIResponse
// @Failure 400 {object} response.APIResponse
// @Failure 401 {object} response.APIResponse
// @Failure 500 {object} response.APIResponse
// @Router /customer/{id} [put]
func (h *Handler) UpdateCustomer(c *fiber.Ctx) error {
var req updateCustomerReq
if err := c.BodyParser(&req); err != nil {
h.logger.Error("UpdateCustomers failed", "error", err)
return response.WriteJSON(c, fiber.StatusBadRequest, "Invalid request", nil, nil)
}
valErrs, ok := h.validator.Validate(c, req)
if !ok {
return response.WriteJSON(c, fiber.StatusBadRequest, "Invalid request", valErrs, nil)
}
CustomersIdStr := c.Params("id")
CustomersId, err := strconv.ParseInt(CustomersIdStr, 10, 64)
if err != nil {
h.logger.Error("UpdateCustomers failed", "error", err)
return response.WriteJSON(c, fiber.StatusBadRequest, "Invalid Customers ID", nil, nil)
}
// var companyID domain.ValidInt64
// role := c.Locals("role").(domain.Role)
// if req.CompanyID != nil {
// if role != domain.RoleSuperAdmin {
// h.logger.Error("UpdateCustomers failed", "error", err)
// return response.WriteJSON(c, fiber.StatusUnauthorized, "This user role cannot modify company ID", nil, nil)
// }
// companyID = domain.ValidInt64{
// Value: *req.CompanyID,
// Valid: true,
// }
// }
err = h.userSvc.UpdateUser(c.Context(), domain.UpdateUserReq{
UserId: CustomersId,
FirstName: domain.ValidString{
Value: req.FirstName,
Valid: req.FirstName != "",
},
LastName: domain.ValidString{
Value: req.LastName,
Valid: req.LastName != "",
},
Suspended: domain.ValidBool{
Value: req.Suspended,
Valid: true,
},
},
)
if err != nil {
h.logger.Error("UpdateCustomers failed", "error", err)
return response.WriteJSON(c, fiber.StatusInternalServerError, "Failed to update Customers", nil, nil)
}
return response.WriteJSON(c, fiber.StatusOK, "Customers updated successfully", nil, nil)
}