1edf42187d
continuous-integration/drone/push Build is passing
- Added functionality to retrieve merged AI recommendations for multiple companies, improving the relevance of tender suggestions based on company-specific data. - Introduced normalization functions to clean and deduplicate company IDs, ensuring accurate processing of recommendations. - Enhanced the company context resolution in customer middleware to support multiple assigned companies, improving the handling of company-specific requests. - Updated the tender recommendation logic to utilize the new merged recommendations and handle exclusions for rejected tenders accordingly. - Added unit tests to verify the new recommendation merging logic and company ID normalization, ensuring robust functionality. This update significantly enhances the tender recommendation process by allowing for more comprehensive and relevant suggestions based on multiple company contexts, improving user experience and satisfaction.
116 lines
3.5 KiB
Go
116 lines
3.5 KiB
Go
package customer
|
|
|
|
import (
|
|
"errors"
|
|
"net/http"
|
|
"strings"
|
|
"tm/pkg/audit"
|
|
"tm/pkg/response"
|
|
|
|
"github.com/labstack/echo/v4"
|
|
)
|
|
|
|
// AuthMiddleware validates JWT access tokens and extracts customer information
|
|
func (h *Handler) AuthMiddleware() echo.MiddlewareFunc {
|
|
return func(next echo.HandlerFunc) echo.HandlerFunc {
|
|
return func(c echo.Context) error {
|
|
// Extract token from Authorization header
|
|
authHeader := c.Request().Header.Get("Authorization")
|
|
if authHeader == "" {
|
|
return response.Unauthorized(c, "Authorization header required")
|
|
}
|
|
|
|
// Check if it's a Bearer token
|
|
if !strings.HasPrefix(authHeader, "Bearer ") {
|
|
return response.Unauthorized(c, "Invalid authorization format. Use 'Bearer <token>'")
|
|
}
|
|
|
|
// Extract the token
|
|
tokenString := strings.TrimPrefix(authHeader, "Bearer ")
|
|
|
|
// Validate the access token using authorization service
|
|
validationResult, err := h.authService.ValidateAccessToken(tokenString)
|
|
if err != nil {
|
|
h.logger.Error("Token validation error", map[string]interface{}{
|
|
"error": err.Error(),
|
|
})
|
|
return response.Unauthorized(c, "Invalid token")
|
|
}
|
|
|
|
if !validationResult.Valid {
|
|
if validationResult.Expired {
|
|
return response.Unauthorized(c, "Token expired")
|
|
}
|
|
return response.Unauthorized(c, validationResult.Error)
|
|
}
|
|
|
|
// Extract customer information from token
|
|
customerID := validationResult.Claims.UserID
|
|
|
|
// Store customer information in context for handlers to use
|
|
c.Set("customer_id", customerID)
|
|
c.Set("customer_email", validationResult.Claims.Email)
|
|
c.Set("customer_role", validationResult.Claims.Role)
|
|
c.Set("company_id", validationResult.Claims.CompanyID)
|
|
c.Set("access_token", tokenString)
|
|
|
|
audit.EnrichEchoContext(c, audit.ActorTypeCustomer)
|
|
|
|
// Continue to next handler
|
|
return next(c)
|
|
}
|
|
}
|
|
}
|
|
|
|
// CompanyContextMiddleware resolves company_id from current customer assignments.
|
|
// JWT company_id can be stale after admin reassigns companies; this keeps tender
|
|
// recommendations and other company-scoped APIs in sync with the database.
|
|
func (h *Handler) CompanyContextMiddleware() echo.MiddlewareFunc {
|
|
return func(next echo.HandlerFunc) echo.HandlerFunc {
|
|
return func(c echo.Context) error {
|
|
customerID, err := GetCustomerIDFromContext(c)
|
|
if err != nil {
|
|
return response.Unauthorized(c, "User not authenticated")
|
|
}
|
|
|
|
tokenCompanyID, _ := c.Get("company_id").(string)
|
|
requestedCompanyID := strings.TrimSpace(c.QueryParam("company_id"))
|
|
|
|
companyID, companyIDs, err := h.service.ResolveCompanyContext(
|
|
c.Request().Context(),
|
|
customerID,
|
|
tokenCompanyID,
|
|
requestedCompanyID,
|
|
)
|
|
if err != nil {
|
|
if errors.Is(err, errCompanyNotAssigned) {
|
|
return response.Forbidden(c, "Company is not assigned to customer")
|
|
}
|
|
return response.Unauthorized(c, "User not authenticated")
|
|
}
|
|
|
|
c.Set("company_id", companyID)
|
|
c.Set("company_ids", companyIDs)
|
|
return next(c)
|
|
}
|
|
}
|
|
}
|
|
|
|
// GetCustomerIDFromContext extracts customer ID from Echo context
|
|
func GetCustomerIDFromContext(c echo.Context) (string, error) {
|
|
customerID, ok := c.Get("customer_id").(string)
|
|
if !ok {
|
|
return "", echo.NewHTTPError(http.StatusUnauthorized, "Customer ID not found in context")
|
|
}
|
|
return customerID, nil
|
|
}
|
|
|
|
// GetAccessTokenFromContext extracts access token from Echo context
|
|
func GetAccessTokenFromContext(c echo.Context) (string, error) {
|
|
accessToken, ok := c.Get("access_token").(string)
|
|
if !ok {
|
|
return "", echo.NewHTTPError(http.StatusUnauthorized, "Access token not found in context")
|
|
}
|
|
return accessToken, nil
|
|
}
|