turash/bugulma/backend/internal/middleware/context.go
Damir Mukimov 000eab4740
Major repository reorganization and missing backend endpoints implementation
Repository Structure:
- Move files from cluttered root directory into organized structure
- Create archive/ for archived data and scraper results
- Create bugulma/ for the complete application (frontend + backend)
- Create data/ for sample datasets and reference materials
- Create docs/ for comprehensive documentation structure
- Create scripts/ for utility scripts and API tools

Backend Implementation:
- Implement 3 missing backend endpoints identified in gap analysis:
  * GET /api/v1/organizations/{id}/matching/direct - Direct symbiosis matches
  * GET /api/v1/users/me/organizations - User organizations
  * POST /api/v1/proposals/{id}/status - Update proposal status
- Add complete proposal domain model, repository, and service layers
- Create database migration for proposals table
- Fix CLI server command registration issue

API Documentation:
- Add comprehensive proposals.md API documentation
- Update README.md with Users and Proposals API sections
- Document all request/response formats, error codes, and business rules

Code Quality:
- Follow existing Go backend architecture patterns
- Add proper error handling and validation
- Match frontend expected response schemas
- Maintain clean separation of concerns (handler -> service -> repository)
2025-11-25 06:01:16 +01:00

123 lines
3.0 KiB
Go

package middleware
import (
"bugulma/backend/internal/service"
"context"
"log"
"strings"
"github.com/gin-gonic/gin"
)
// Context keys for storing user/org info
type contextKey string
const (
UserIDKey contextKey = "user_id"
OrgIDKey contextKey = "org_id"
)
// ContextMiddleware extracts user and organization information from headers/tokens
func ContextMiddleware(authService *service.AuthService) gin.HandlerFunc {
return func(c *gin.Context) {
// Try to extract user ID from JWT token
userID, orgID := extractFromJWT(c, authService)
if userID != "" {
ctx := context.WithValue(c.Request.Context(), UserIDKey, userID)
c.Request = c.Request.WithContext(ctx)
}
if orgID != "" {
ctx := context.WithValue(c.Request.Context(), OrgIDKey, orgID)
c.Request = c.Request.WithContext(ctx)
}
// Fallback to headers/query params for development
if userID == "" {
userID = extractUserID(c)
if userID != "" {
ctx := context.WithValue(c.Request.Context(), UserIDKey, userID)
c.Request = c.Request.WithContext(ctx)
}
}
if orgID == "" {
orgID = extractOrgID(c)
if orgID != "" {
ctx := context.WithValue(c.Request.Context(), OrgIDKey, orgID)
c.Request = c.Request.WithContext(ctx)
}
}
c.Next()
}
}
// extractFromJWT extracts user and organization info from JWT token
func extractFromJWT(c *gin.Context, authService *service.AuthService) (string, string) {
authHeader := c.GetHeader("Authorization")
if !strings.HasPrefix(authHeader, "Bearer ") {
return "", ""
}
tokenString := strings.TrimPrefix(authHeader, "Bearer ")
if tokenString == "" {
return "", ""
}
// Validate token and extract claims
_, claims, err := authService.ValidateTokenWithClaims(c.Request.Context(), tokenString)
if err != nil {
log.Printf("JWT validation failed: %v", err)
return "", ""
}
return claims.UserID, claims.OrgID
}
// extractUserID extracts user ID from request (fallback for development)
func extractUserID(c *gin.Context) string {
// Check query parameter (for development/testing)
if userID := c.Query("user_id"); userID != "" {
return userID
}
// Default fallback
return "system"
}
// extractOrgID extracts organization ID from request
func extractOrgID(c *gin.Context) string {
// Check X-Organization-ID header
if orgID := c.GetHeader("X-Organization-ID"); orgID != "" {
return orgID
}
// Check query parameter (for development/testing)
if orgID := c.Query("org_id"); orgID != "" {
return orgID
}
// For resource flow operations, we might need to determine org from path params
// This would be handled in the service layer based on the entity being operated on
return ""
}
// GetUserIDFromContext extracts user ID from context
func GetUserIDFromContext(ctx context.Context) string {
if userID, ok := ctx.Value(UserIDKey).(string); ok {
return userID
}
return "system"
}
// GetOrgIDFromContext extracts organization ID from context
func GetOrgIDFromContext(ctx context.Context) string {
if orgID, ok := ctx.Value(OrgIDKey).(string); ok {
return orgID
}
return ""
}