Files
tm_back/internal/customer/middleware.go
T
Mazyar 1edf42187d
continuous-integration/drone/push Build is passing
Implement AI recommendations for multiple companies and enhance company context handling
- 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.
2026-07-04 13:00:33 +03:30

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
}