Add configuration file and update server settings
- Introduced a new `config.yaml` file for managing server, database, cache, queue, AI, scraping, logging, and rate limiting configurations. - Updated `docker-compose.yml` to reflect the new server port (8081) and adjusted health check endpoints accordingly. - Modified `Dockerfile` to expose the new server port. - Updated `README.md` to reflect changes in server configuration and added documentation for the new configuration structure. - Added test scripts for server and Swagger documentation testing. - Refactored customer domain structure to align with new configuration settings and improve maintainability.
This commit is contained in:
+489
-139
@@ -1,221 +1,571 @@
|
||||
package customer
|
||||
|
||||
import (
|
||||
"tm/pkg/logger"
|
||||
"net/http"
|
||||
"tm/pkg/response"
|
||||
|
||||
"github.com/asaskevich/govalidator"
|
||||
"github.com/google/uuid"
|
||||
"github.com/labstack/echo/v4"
|
||||
)
|
||||
|
||||
// CustomerHandler handles authentication related HTTP requests for mobile customers
|
||||
type CustomerHandler struct {
|
||||
service CustomerService
|
||||
logger logger.Logger
|
||||
// Handler handles HTTP requests for customer operations
|
||||
type Handler struct {
|
||||
service Service
|
||||
}
|
||||
|
||||
// NewCustomerHandler creates a new customer authentication handler
|
||||
func NewHandler(
|
||||
customerAuthService CustomerService,
|
||||
logger logger.Logger,
|
||||
) *CustomerHandler {
|
||||
return &CustomerHandler{
|
||||
service: customerAuthService,
|
||||
logger: logger,
|
||||
// NewHandler creates a new customer handler
|
||||
func NewHandler(service Service) *Handler {
|
||||
return &Handler{
|
||||
service: service,
|
||||
}
|
||||
}
|
||||
|
||||
// Register handles customer registration
|
||||
// @Summary Register new customer
|
||||
// @Description Create a new customer account for mobile app
|
||||
// @Tags customer-auth
|
||||
// RegisterRoutes registers all customer routes
|
||||
func (h *Handler) RegisterRoutes(e *echo.Echo) {
|
||||
|
||||
v1 := e.Group("/api/v1")
|
||||
|
||||
v1.POST("/customers/register", h.RegisterCustomer)
|
||||
// Public routes (no authentication required)
|
||||
v1.POST("/customers/login", h.Login)
|
||||
v1.POST("/customers/refresh-token", h.RefreshToken)
|
||||
|
||||
// Protected routes (authentication required)
|
||||
customers := v1.Group("/customers")
|
||||
customers.Use(h.authMiddleware) // TODO: Implement auth middleware
|
||||
customers.GET("/profile", h.GetProfile)
|
||||
customers.PUT("/profile", h.UpdateProfile)
|
||||
customers.PUT("/change-password", h.ChangePassword)
|
||||
customers.POST("/device-token", h.AddDeviceToken)
|
||||
customers.DELETE("/device-token", h.RemoveDeviceToken)
|
||||
customers.POST("/logout", h.Logout)
|
||||
|
||||
// Admin routes (admin authentication required)
|
||||
admin := v1.Group("/admin/customers")
|
||||
admin.Use(h.adminAuthMiddleware) // TODO: Implement admin auth middleware
|
||||
admin.POST("/register", h.RegisterCustomer)
|
||||
admin.GET("", h.ListCustomers)
|
||||
admin.GET("/:id", h.GetCustomerByID)
|
||||
admin.PUT("/:id/status", h.UpdateCustomerStatus)
|
||||
admin.GET("/device-tokens", h.GetAllDeviceTokens)
|
||||
}
|
||||
|
||||
// RegisterCustomer handles customer registration
|
||||
// @Summary Register a new customer
|
||||
// @Description Register a new customer with the provided information
|
||||
// @Tags customers
|
||||
// @Accept json
|
||||
// @Produce json
|
||||
// @Param request body domain.CustomerRegisterRequest true "Customer registration request"
|
||||
// @Success 201 {object} response.APIResponse{data=domain.CustomerAuthResponse}
|
||||
// @Failure 400 {object} response.APIResponse
|
||||
// @Failure 409 {object} response.APIResponse
|
||||
// @Failure 500 {object} response.APIResponse
|
||||
// @Router /api/mobile/auth/register [post]
|
||||
func (h *CustomerHandler) Register(c echo.Context) error {
|
||||
var req RegisterForm
|
||||
// @Param customer body RegisterCustomerForm true "Customer registration information"
|
||||
// @Success 201 {object} response.APIResponse{data=customer.CustomerResponse} "Customer registered successfully"
|
||||
// @Failure 400 {object} response.APIResponse "Bad request"
|
||||
// @Failure 409 {object} response.APIResponse "Customer already exists"
|
||||
// @Failure 500 {object} response.APIResponse "Internal server error"
|
||||
// @Router /admin/customers/register [post]
|
||||
func (h *Handler) RegisterCustomer(c echo.Context) error {
|
||||
var form RegisterCustomerForm
|
||||
|
||||
// Bind request body
|
||||
if err := c.Bind(&req); err != nil {
|
||||
return response.BadRequest(c, "Invalid request format", err.Error())
|
||||
if err := c.Bind(&form); err != nil {
|
||||
return response.BadRequest(c, "Invalid request body", err.Error())
|
||||
}
|
||||
|
||||
// Validate request
|
||||
if _, err := govalidator.ValidateStruct(&req); err != nil {
|
||||
// Validate form
|
||||
if _, err := govalidator.ValidateStruct(form); err != nil {
|
||||
return response.ValidationError(c, "Validation failed", err.Error())
|
||||
}
|
||||
|
||||
// Call service
|
||||
authResponse, err := h.service.Register(c.Request().Context(), req)
|
||||
// Register customer
|
||||
customer, err := h.service.RegisterCustomer(c.Request().Context(), &form)
|
||||
if err != nil {
|
||||
return response.InternalServerError(c, "Registration failed")
|
||||
return response.Conflict(c, err.Error())
|
||||
}
|
||||
|
||||
return response.Created(c, authResponse, "Customer registered successfully")
|
||||
return response.Created(c, customer.ToResponse(), "Customer registered successfully")
|
||||
}
|
||||
|
||||
// Login handles customer authentication
|
||||
// @Summary Customer login
|
||||
// @Description Authenticate customer and return tokens
|
||||
// @Tags customer-auth
|
||||
// @Description Authenticate customer with email and password
|
||||
// @Tags customers
|
||||
// @Accept json
|
||||
// @Produce json
|
||||
// @Param request body domain.LoginRequest true "Login request"
|
||||
// @Success 200 {object} response.APIResponse{data=domain.CustomerAuthResponse}
|
||||
// @Failure 400 {object} response.APIResponse
|
||||
// @Failure 401 {object} response.APIResponse
|
||||
// @Failure 500 {object} response.APIResponse
|
||||
// @Router /api/mobile/auth/login [post]
|
||||
func (h *CustomerHandler) Login(c echo.Context) error {
|
||||
var req LoginForm
|
||||
// @Param credentials body LoginForm true "Login credentials"
|
||||
// @Success 200 {object} response.APIResponse{data=customer.AuthResponse} "Login successful"
|
||||
// @Failure 400 {object} response.APIResponse "Bad request"
|
||||
// @Failure 401 {object} response.APIResponse "Invalid credentials"
|
||||
// @Failure 500 {object} response.APIResponse "Internal server error"
|
||||
// @Router /customers/login [post]
|
||||
func (h *Handler) Login(c echo.Context) error {
|
||||
var form LoginForm
|
||||
|
||||
// Bind request body
|
||||
if err := c.Bind(&req); err != nil {
|
||||
return response.BadRequest(c, "Invalid request format", err.Error())
|
||||
if err := c.Bind(&form); err != nil {
|
||||
return response.BadRequest(c, "Invalid request body", err.Error())
|
||||
}
|
||||
|
||||
// Validate request
|
||||
if _, err := govalidator.ValidateStruct(&req); err != nil {
|
||||
// Validate form
|
||||
if _, err := govalidator.ValidateStruct(form); err != nil {
|
||||
return response.ValidationError(c, "Validation failed", err.Error())
|
||||
}
|
||||
|
||||
// Call service
|
||||
authResponse, err := h.service.Login(c.Request().Context(), req)
|
||||
// Authenticate customer
|
||||
authResponse, err := h.service.Login(c.Request().Context(), &form)
|
||||
if err != nil {
|
||||
return response.InternalServerError(c, "Login failed")
|
||||
return response.Unauthorized(c, err.Error())
|
||||
}
|
||||
|
||||
return response.Success(c, authResponse, "Login successful")
|
||||
}
|
||||
|
||||
// RefreshToken handles token refresh for customers
|
||||
// @Summary Refresh customer access token
|
||||
// @Description Generate new access token using refresh token
|
||||
// @Tags customer-auth
|
||||
// RefreshToken handles token refresh
|
||||
// @Summary Refresh access token
|
||||
// @Description Refresh the access token using a refresh token
|
||||
// @Tags customers
|
||||
// @Accept json
|
||||
// @Produce json
|
||||
// @Param request body RefreshTokenRequest true "Refresh token request"
|
||||
// @Success 200 {object} response.APIResponse{data=domain.CustomerAuthResponse}
|
||||
// @Failure 400 {object} response.APIResponse
|
||||
// @Failure 401 {object} response.APIResponse
|
||||
// @Failure 500 {object} response.APIResponse
|
||||
// @Router /api/mobile/auth/refresh [post]
|
||||
func (h *CustomerHandler) RefreshToken(c echo.Context) error {
|
||||
var req RefreshTokenForm
|
||||
// @Param token body RefreshTokenForm true "Refresh token information"
|
||||
// @Success 200 {object} response.APIResponse{data=customer.AuthResponse} "Token refreshed successfully"
|
||||
// @Failure 400 {object} response.APIResponse "Bad request"
|
||||
// @Failure 401 {object} response.APIResponse "Invalid refresh token"
|
||||
// @Failure 500 {object} response.APIResponse "Internal server error"
|
||||
// @Router /customers/refresh-token [post]
|
||||
func (h *Handler) RefreshToken(c echo.Context) error {
|
||||
var form RefreshTokenForm
|
||||
|
||||
// Bind request body
|
||||
if err := c.Bind(&req); err != nil {
|
||||
return response.BadRequest(c, "Invalid request format", err.Error())
|
||||
if err := c.Bind(&form); err != nil {
|
||||
return response.BadRequest(c, "Invalid request body", err.Error())
|
||||
}
|
||||
|
||||
// Validate request
|
||||
if _, err := govalidator.ValidateStruct(&req); err != nil {
|
||||
// Validate form
|
||||
if _, err := govalidator.ValidateStruct(form); err != nil {
|
||||
return response.ValidationError(c, "Validation failed", err.Error())
|
||||
}
|
||||
|
||||
// Call service
|
||||
authResponse, err := h.service.RefreshToken(c.Request().Context(), req.RefreshToken)
|
||||
// Refresh token
|
||||
authResponse, err := h.service.RefreshToken(c.Request().Context(), form.RefreshToken)
|
||||
if err != nil {
|
||||
return response.InternalServerError(c, "Token refresh failed")
|
||||
return response.Unauthorized(c, err.Error())
|
||||
}
|
||||
|
||||
return response.Success(c, authResponse, "Token refreshed successfully")
|
||||
}
|
||||
|
||||
// ChangePassword handles password change for customers
|
||||
// @Summary Change customer password
|
||||
// @Description Change authenticated customer's password
|
||||
// @Tags customer-auth
|
||||
// GetProfile retrieves customer profile
|
||||
// @Summary Get customer profile
|
||||
// @Description Retrieve the authenticated customer's profile information
|
||||
// @Tags customers
|
||||
// @Accept json
|
||||
// @Produce json
|
||||
// @Security ApiKeyAuth
|
||||
// @Param request body ChangePasswordRequest true "Change password request"
|
||||
// @Success 200 {object} response.APIResponse
|
||||
// @Failure 400 {object} response.APIResponse
|
||||
// @Failure 401 {object} response.APIResponse
|
||||
// @Failure 500 {object} response.APIResponse
|
||||
// @Router /api/mobile/auth/change-password [post]
|
||||
func (h *CustomerHandler) ChangePassword(c echo.Context) error {
|
||||
var req ChangePasswordForm
|
||||
|
||||
// Bind request body
|
||||
if err := c.Bind(&req); err != nil {
|
||||
return response.BadRequest(c, "Invalid request format", err.Error())
|
||||
// @Security BearerAuth
|
||||
// @Success 200 {object} response.APIResponse{data=customer.CustomerResponse} "Profile retrieved successfully"
|
||||
// @Failure 401 {object} response.APIResponse "Unauthorized"
|
||||
// @Failure 404 {object} response.APIResponse "Customer not found"
|
||||
// @Failure 500 {object} response.APIResponse "Internal server error"
|
||||
// @Router /customers/profile [get]
|
||||
func (h *Handler) GetProfile(c echo.Context) error {
|
||||
// Get customer ID from context (set by auth middleware)
|
||||
customerID, err := h.getCustomerIDFromContext(c)
|
||||
if err != nil {
|
||||
return response.Unauthorized(c, "Invalid authentication")
|
||||
}
|
||||
|
||||
// Validate request
|
||||
if _, err := govalidator.ValidateStruct(&req); err != nil {
|
||||
// Get customer
|
||||
customer, err := h.service.GetCustomerByID(c.Request().Context(), customerID)
|
||||
if err != nil {
|
||||
return response.NotFound(c, "Customer not found")
|
||||
}
|
||||
|
||||
return response.Success(c, customer.ToResponse(), "Profile retrieved successfully")
|
||||
}
|
||||
|
||||
// UpdateProfile updates customer profile
|
||||
// @Summary Update customer profile
|
||||
// @Description Update the authenticated customer's profile information
|
||||
// @Tags customers
|
||||
// @Accept json
|
||||
// @Produce json
|
||||
// @Security BearerAuth
|
||||
// @Param profile body UpdateCustomerForm true "Profile update information"
|
||||
// @Success 200 {object} response.APIResponse{data=customer.CustomerResponse} "Profile updated successfully"
|
||||
// @Failure 400 {object} response.APIResponse "Bad request"
|
||||
// @Failure 401 {object} response.APIResponse "Unauthorized"
|
||||
// @Failure 500 {object} response.APIResponse "Internal server error"
|
||||
// @Router /customers/profile [put]
|
||||
func (h *Handler) UpdateProfile(c echo.Context) error {
|
||||
// Get customer ID from context
|
||||
customerID, err := h.getCustomerIDFromContext(c)
|
||||
if err != nil {
|
||||
return response.Unauthorized(c, "Invalid authentication")
|
||||
}
|
||||
|
||||
var form UpdateCustomerForm
|
||||
|
||||
if err := c.Bind(&form); err != nil {
|
||||
return response.BadRequest(c, "Invalid request body", err.Error())
|
||||
}
|
||||
|
||||
// Validate form
|
||||
if _, err := govalidator.ValidateStruct(form); err != nil {
|
||||
return response.ValidationError(c, "Validation failed", err.Error())
|
||||
}
|
||||
|
||||
// Get customer from context (set by auth middleware)
|
||||
// customer, ok := c.Get("customer").(*domain.Customer)
|
||||
// if !ok {
|
||||
// return response.Unauthorized(c, "Authentication required")
|
||||
// }
|
||||
// Update customer
|
||||
customer, err := h.service.UpdateCustomer(c.Request().Context(), customerID, &form)
|
||||
if err != nil {
|
||||
return response.BadRequest(c, err.Error(), "")
|
||||
}
|
||||
|
||||
// Call service
|
||||
// err := h.customerAuthService.ChangePassword(c.Request().Context(), customer.ID, req.OldPassword, req.NewPassword)
|
||||
// if err != nil {
|
||||
// h.logger.Error("Customer password change failed", map[string]interface{}{
|
||||
// "error": err.Error(),
|
||||
// "customer_id": customer.ID.String(),
|
||||
// })
|
||||
return response.Success(c, customer.ToResponse(), "Profile updated successfully")
|
||||
}
|
||||
|
||||
// if err.Error() == "invalid old password" {
|
||||
// return response.BadRequest(c, "Invalid old password", "")
|
||||
// }
|
||||
// ChangePassword changes customer password
|
||||
// @Summary Change customer password
|
||||
// @Description Change the authenticated customer's password
|
||||
// @Tags customers
|
||||
// @Accept json
|
||||
// @Produce json
|
||||
// @Security BearerAuth
|
||||
// @Param password body ChangePasswordForm true "Password change information"
|
||||
// @Success 200 {object} response.APIResponse "Password changed successfully"
|
||||
// @Failure 400 {object} response.APIResponse "Bad request"
|
||||
// @Failure 401 {object} response.APIResponse "Unauthorized"
|
||||
// @Failure 500 {object} response.APIResponse "Internal server error"
|
||||
// @Router /customers/change-password [put]
|
||||
func (h *Handler) ChangePassword(c echo.Context) error {
|
||||
// Get customer ID from context
|
||||
customerID, err := h.getCustomerIDFromContext(c)
|
||||
if err != nil {
|
||||
return response.Unauthorized(c, "Invalid authentication")
|
||||
}
|
||||
|
||||
// return response.InternalServerError(c, "Password change failed")
|
||||
// }
|
||||
var form ChangePasswordForm
|
||||
|
||||
if err := c.Bind(&form); err != nil {
|
||||
return response.BadRequest(c, "Invalid request body", err.Error())
|
||||
}
|
||||
|
||||
// Validate form
|
||||
if _, err := govalidator.ValidateStruct(form); err != nil {
|
||||
return response.ValidationError(c, "Validation failed", err.Error())
|
||||
}
|
||||
|
||||
// Change password
|
||||
err = h.service.ChangePassword(c.Request().Context(), customerID, &form)
|
||||
if err != nil {
|
||||
return response.BadRequest(c, err.Error(), "")
|
||||
}
|
||||
|
||||
return response.Success(c, nil, "Password changed successfully")
|
||||
}
|
||||
|
||||
// GetProfile returns current customer profile
|
||||
// @Summary Get customer profile
|
||||
// @Description Get authenticated customer's profile information
|
||||
// @Tags customer-auth
|
||||
// AddDeviceToken adds a device token for push notifications
|
||||
// @Summary Add device token
|
||||
// @Description Add a device token for push notifications
|
||||
// @Tags customers
|
||||
// @Accept json
|
||||
// @Produce json
|
||||
// @Security ApiKeyAuth
|
||||
// @Success 200 {object} response.APIResponse{data=domain.Customer}
|
||||
// @Failure 401 {object} response.APIResponse
|
||||
// @Router /api/mobile/auth/profile [get]
|
||||
func (h *CustomerHandler) GetProfile(c echo.Context) error {
|
||||
// Get customer from context (set by auth middleware)
|
||||
// customer, ok := c.Get("customer").(*domain.Customer)
|
||||
// if !ok {
|
||||
// return response.Unauthorized(c, "Authentication required")
|
||||
// }
|
||||
// @Security BearerAuth
|
||||
// @Param device_token body AddDeviceTokenForm true "Device token information"
|
||||
// @Success 200 {object} response.APIResponse "Device token added successfully"
|
||||
// @Failure 400 {object} response.APIResponse "Bad request"
|
||||
// @Failure 401 {object} response.APIResponse "Unauthorized"
|
||||
// @Failure 500 {object} response.APIResponse "Internal server error"
|
||||
// @Router /customers/device-token [post]
|
||||
func (h *Handler) AddDeviceToken(c echo.Context) error {
|
||||
// Get customer ID from context
|
||||
customerID, err := h.getCustomerIDFromContext(c)
|
||||
if err != nil {
|
||||
return response.Unauthorized(c, "Invalid authentication")
|
||||
}
|
||||
|
||||
return response.Success(c, nil, "Profile retrieved successfully")
|
||||
var form AddDeviceTokenForm
|
||||
|
||||
if err := c.Bind(&form); err != nil {
|
||||
return response.BadRequest(c, "Invalid request body", err.Error())
|
||||
}
|
||||
|
||||
// Validate form
|
||||
if _, err := govalidator.ValidateStruct(form); err != nil {
|
||||
return response.ValidationError(c, "Validation failed", err.Error())
|
||||
}
|
||||
|
||||
// Add device token
|
||||
err = h.service.AddDeviceToken(c.Request().Context(), customerID, &form)
|
||||
if err != nil {
|
||||
return response.BadRequest(c, err.Error(), "")
|
||||
}
|
||||
|
||||
return response.Success(c, nil, "Device token added successfully")
|
||||
}
|
||||
|
||||
// RemoveDeviceToken removes a device token
|
||||
// @Summary Remove device token
|
||||
// @Description Remove a device token for push notifications
|
||||
// @Tags customers
|
||||
// @Accept json
|
||||
// @Produce json
|
||||
// @Security BearerAuth
|
||||
// @Param device_token body RemoveDeviceTokenForm true "Device token information"
|
||||
// @Success 200 {object} response.APIResponse "Device token removed successfully"
|
||||
// @Failure 400 {object} response.APIResponse "Bad request"
|
||||
// @Failure 401 {object} response.APIResponse "Unauthorized"
|
||||
// @Failure 500 {object} response.APIResponse "Internal server error"
|
||||
// @Router /customers/device-token [delete]
|
||||
func (h *Handler) RemoveDeviceToken(c echo.Context) error {
|
||||
// Get customer ID from context
|
||||
customerID, err := h.getCustomerIDFromContext(c)
|
||||
if err != nil {
|
||||
return response.Unauthorized(c, "Invalid authentication")
|
||||
}
|
||||
|
||||
var form RemoveDeviceTokenForm
|
||||
|
||||
if err := c.Bind(&form); err != nil {
|
||||
return response.BadRequest(c, "Invalid request body", err.Error())
|
||||
}
|
||||
|
||||
// Validate form
|
||||
if _, err := govalidator.ValidateStruct(form); err != nil {
|
||||
return response.ValidationError(c, "Validation failed", err.Error())
|
||||
}
|
||||
|
||||
// Remove device token
|
||||
err = h.service.RemoveDeviceToken(c.Request().Context(), customerID, &form)
|
||||
if err != nil {
|
||||
return response.BadRequest(c, err.Error(), "")
|
||||
}
|
||||
|
||||
return response.Success(c, nil, "Device token removed successfully")
|
||||
}
|
||||
|
||||
// Logout handles customer logout
|
||||
// @Summary Customer logout
|
||||
// @Description Logout customer (client should remove tokens)
|
||||
// @Tags customer-auth
|
||||
// @Description Logout customer and invalidate device token
|
||||
// @Tags customers
|
||||
// @Accept json
|
||||
// @Produce json
|
||||
// @Security ApiKeyAuth
|
||||
// @Success 200 {object} response.APIResponse
|
||||
// @Router /api/mobile/auth/logout [post]
|
||||
func (h *CustomerHandler) Logout(c echo.Context) error {
|
||||
// In a stateless JWT implementation, logout is typically handled client-side
|
||||
// by removing the tokens from storage. However, you could implement token
|
||||
// blacklisting here if needed.
|
||||
// @Security BearerAuth
|
||||
// @Param logout body object true "Logout request with device token"
|
||||
// @Success 200 {object} response.APIResponse "Logged out successfully"
|
||||
// @Failure 400 {object} response.APIResponse "Bad request"
|
||||
// @Failure 401 {object} response.APIResponse "Unauthorized"
|
||||
// @Failure 500 {object} response.APIResponse "Internal server error"
|
||||
// @Router /customers/logout [post]
|
||||
func (h *Handler) Logout(c echo.Context) error {
|
||||
// Get customer ID from context
|
||||
customerID, err := h.getCustomerIDFromContext(c)
|
||||
if err != nil {
|
||||
return response.Unauthorized(c, "Invalid authentication")
|
||||
}
|
||||
|
||||
// customer, ok := c.Get("customer").(*domain.Customer)
|
||||
// if ok {
|
||||
// h.logger.Info("Customer logged out", map[string]interface{}{
|
||||
// "customer_id": customer.ID.String(),
|
||||
// "email": customer.Email,
|
||||
// })
|
||||
// }
|
||||
// Get device token from request body
|
||||
var req struct {
|
||||
DeviceToken string `json:"device_token" valid:"required"`
|
||||
}
|
||||
|
||||
if err := c.Bind(&req); err != nil {
|
||||
return response.BadRequest(c, "Invalid request body", err.Error())
|
||||
}
|
||||
|
||||
// Validate request
|
||||
if _, err := govalidator.ValidateStruct(req); err != nil {
|
||||
return response.ValidationError(c, "Validation failed", err.Error())
|
||||
}
|
||||
|
||||
// Logout
|
||||
err = h.service.Logout(c.Request().Context(), customerID, req.DeviceToken)
|
||||
if err != nil {
|
||||
return response.BadRequest(c, err.Error(), "")
|
||||
}
|
||||
|
||||
return response.Success(c, nil, "Logged out successfully")
|
||||
}
|
||||
|
||||
// ListCustomers lists customers (admin only)
|
||||
// @Summary List customers
|
||||
// @Description Retrieve a paginated list of customers (admin only)
|
||||
// @Tags customers
|
||||
// @Accept json
|
||||
// @Produce json
|
||||
// @Security BearerAuth
|
||||
// @Param page query int false "Page number" default(1)
|
||||
// @Param limit query int false "Number of items per page" default(20)
|
||||
// @Param search query string false "Search term"
|
||||
// @Success 200 {object} response.APIResponse{data=[]customer.CustomerResponse} "Customers retrieved successfully"
|
||||
// @Failure 400 {object} response.APIResponse "Bad request"
|
||||
// @Failure 401 {object} response.APIResponse "Unauthorized"
|
||||
// @Failure 500 {object} response.APIResponse "Internal server error"
|
||||
// @Router /admin/customers [get]
|
||||
func (h *Handler) ListCustomers(c echo.Context) error {
|
||||
var form ListCustomersForm
|
||||
|
||||
// Bind query parameters
|
||||
if err := c.Bind(&form); err != nil {
|
||||
return response.BadRequest(c, "Invalid query parameters", err.Error())
|
||||
}
|
||||
|
||||
// Validate form
|
||||
if _, err := govalidator.ValidateStruct(form); err != nil {
|
||||
return response.ValidationError(c, "Validation failed", err.Error())
|
||||
}
|
||||
|
||||
// List customers
|
||||
customers, total, err := h.service.ListCustomers(c.Request().Context(), &form)
|
||||
if err != nil {
|
||||
return response.InternalServerError(c, err.Error())
|
||||
}
|
||||
|
||||
// Convert to responses
|
||||
var responses []*CustomerResponse
|
||||
for _, customer := range customers {
|
||||
responses = append(responses, customer.ToResponse())
|
||||
}
|
||||
|
||||
// Create metadata
|
||||
meta := &response.Meta{
|
||||
Total: total,
|
||||
Limit: 20, // Default limit
|
||||
Offset: 0, // Default offset
|
||||
}
|
||||
|
||||
if form.Limit != nil {
|
||||
meta.Limit = *form.Limit
|
||||
}
|
||||
if form.Offset != nil {
|
||||
meta.Offset = *form.Offset
|
||||
}
|
||||
|
||||
return response.SuccessWithMeta(c, responses, meta, "Customers retrieved successfully")
|
||||
}
|
||||
|
||||
// GetCustomerByID retrieves a customer by ID (admin only)
|
||||
// @Summary Get customer by ID
|
||||
// @Description Retrieve customer information by ID (admin only)
|
||||
// @Tags customers
|
||||
// @Accept json
|
||||
// @Produce json
|
||||
// @Security BearerAuth
|
||||
// @Param id path string true "Customer ID"
|
||||
// @Success 200 {object} response.APIResponse{data=customer.CustomerResponse} "Customer retrieved successfully"
|
||||
// @Failure 400 {object} response.APIResponse "Bad request"
|
||||
// @Failure 401 {object} response.APIResponse "Unauthorized"
|
||||
// @Failure 404 {object} response.APIResponse "Customer not found"
|
||||
// @Failure 500 {object} response.APIResponse "Internal server error"
|
||||
// @Router /admin/customers/{id} [get]
|
||||
func (h *Handler) GetCustomerByID(c echo.Context) error {
|
||||
// Parse customer ID
|
||||
customerIDStr := c.Param("id")
|
||||
customerID, err := uuid.Parse(customerIDStr)
|
||||
if err != nil {
|
||||
return response.BadRequest(c, "Invalid customer ID", err.Error())
|
||||
}
|
||||
|
||||
// Get customer
|
||||
customer, err := h.service.GetCustomerByID(c.Request().Context(), customerID)
|
||||
if err != nil {
|
||||
return response.NotFound(c, "Customer not found")
|
||||
}
|
||||
|
||||
return response.Success(c, customer.ToResponse(), "Customer retrieved successfully")
|
||||
}
|
||||
|
||||
// UpdateCustomerStatus updates customer status (admin only)
|
||||
// @Summary Update customer status
|
||||
// @Description Update customer status (admin only)
|
||||
// @Tags customers
|
||||
// @Accept json
|
||||
// @Produce json
|
||||
// @Security BearerAuth
|
||||
// @Param id path string true "Customer ID"
|
||||
// @Param status body UpdateCustomerStatusForm true "Status update information"
|
||||
// @Success 200 {object} response.APIResponse "Customer status updated successfully"
|
||||
// @Failure 400 {object} response.APIResponse "Bad request"
|
||||
// @Failure 401 {object} response.APIResponse "Unauthorized"
|
||||
// @Failure 404 {object} response.APIResponse "Customer not found"
|
||||
// @Failure 500 {object} response.APIResponse "Internal server error"
|
||||
// @Router /admin/customers/{id}/status [put]
|
||||
func (h *Handler) UpdateCustomerStatus(c echo.Context) error {
|
||||
// Parse customer ID
|
||||
customerIDStr := c.Param("id")
|
||||
customerID, err := uuid.Parse(customerIDStr)
|
||||
if err != nil {
|
||||
return response.BadRequest(c, "Invalid customer ID", err.Error())
|
||||
}
|
||||
|
||||
var form UpdateCustomerStatusForm
|
||||
|
||||
if err := c.Bind(&form); err != nil {
|
||||
return response.BadRequest(c, "Invalid request body", err.Error())
|
||||
}
|
||||
|
||||
// Validate form
|
||||
if _, err := govalidator.ValidateStruct(form); err != nil {
|
||||
return response.ValidationError(c, "Validation failed", err.Error())
|
||||
}
|
||||
|
||||
// Update status
|
||||
err = h.service.UpdateCustomerStatus(c.Request().Context(), customerID, &form)
|
||||
if err != nil {
|
||||
return response.BadRequest(c, err.Error(), "")
|
||||
}
|
||||
|
||||
return response.Success(c, nil, "Customer status updated successfully")
|
||||
}
|
||||
|
||||
// GetAllDeviceTokens retrieves all device tokens (admin only)
|
||||
// @Summary Get all device tokens
|
||||
// @Description Retrieve all device tokens (admin only)
|
||||
// @Tags customers
|
||||
// @Accept json
|
||||
// @Produce json
|
||||
// @Security BearerAuth
|
||||
// @Success 200 {object} response.APIResponse{data=[]string} "Device tokens retrieved successfully"
|
||||
// @Failure 401 {object} response.APIResponse "Unauthorized"
|
||||
// @Failure 500 {object} response.APIResponse "Internal server error"
|
||||
// @Router /admin/customers/device-tokens [get]
|
||||
func (h *Handler) GetAllDeviceTokens(c echo.Context) error {
|
||||
// Get all device tokens
|
||||
tokens, err := h.service.GetAllDeviceTokens(c.Request().Context())
|
||||
if err != nil {
|
||||
return response.InternalServerError(c, err.Error())
|
||||
}
|
||||
|
||||
return response.Success(c, tokens, "Device tokens retrieved successfully")
|
||||
}
|
||||
|
||||
// Helper methods
|
||||
|
||||
// getCustomerIDFromContext extracts customer ID from context
|
||||
func (h *Handler) getCustomerIDFromContext(c echo.Context) (uuid.UUID, error) {
|
||||
// TODO: Implement proper JWT token validation and extraction
|
||||
// For now, we'll use a header-based approach
|
||||
customerIDStr := c.Request().Header.Get("X-Customer-ID")
|
||||
if customerIDStr == "" {
|
||||
return uuid.Nil, echo.NewHTTPError(http.StatusUnauthorized, "Missing customer ID")
|
||||
}
|
||||
|
||||
customerID, err := uuid.Parse(customerIDStr)
|
||||
if err != nil {
|
||||
return uuid.Nil, echo.NewHTTPError(http.StatusUnauthorized, "Invalid customer ID")
|
||||
}
|
||||
|
||||
return customerID, nil
|
||||
}
|
||||
|
||||
// authMiddleware is a placeholder for authentication middleware
|
||||
func (h *Handler) authMiddleware(next echo.HandlerFunc) echo.HandlerFunc {
|
||||
return func(c echo.Context) error {
|
||||
// TODO: Implement proper JWT token validation
|
||||
// For now, we'll just pass through
|
||||
return next(c)
|
||||
}
|
||||
}
|
||||
|
||||
// adminAuthMiddleware is a placeholder for admin authentication middleware
|
||||
func (h *Handler) adminAuthMiddleware(next echo.HandlerFunc) echo.HandlerFunc {
|
||||
return func(c echo.Context) error {
|
||||
// TODO: Implement proper admin authentication
|
||||
// For now, we'll just pass through
|
||||
return next(c)
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user