package handler import ( "context" "omega-server/local/model" "omega-server/local/service" "strings" "github.com/gofiber/fiber/v2" ) // GraphQLHandler handles GraphQL requests type GraphQLHandler struct { membershipService *service.MembershipService } // NewGraphQLHandler creates a new GraphQL handler func NewGraphQLHandler(membershipService *service.MembershipService) *GraphQLHandler { return &GraphQLHandler{ membershipService: membershipService, } } // GraphQLRequest represents a GraphQL request type GraphQLRequest struct { Query string `json:"query"` Variables map[string]interface{} `json:"variables"` } // GraphQLResponse represents a GraphQL response type GraphQLResponse struct { Data interface{} `json:"data,omitempty"` Errors []GraphQLError `json:"errors,omitempty"` } // GraphQLError represents a GraphQL error type GraphQLError struct { Message string `json:"message"` Path []string `json:"path,omitempty"` } // Handle processes GraphQL requests func (h *GraphQLHandler) Handle(c *fiber.Ctx) error { var req GraphQLRequest if err := c.BodyParser(&req); err != nil { return c.Status(400).JSON(GraphQLResponse{ Errors: []GraphQLError{{Message: "Invalid request body"}}, }) } // Basic query parsing and handling ctx := c.UserContext() // Simple query routing based on query string query := strings.TrimSpace(req.Query) switch { case strings.Contains(query, "mutation") && strings.Contains(query, "login"): return h.handleLogin(c, ctx, req) case strings.Contains(query, "mutation") && strings.Contains(query, "createUser"): return h.handleCreateUser(c, ctx, req) case strings.Contains(query, "mutation") && strings.Contains(query, "createProject"): return h.handleCreateProject(c, ctx, req) case strings.Contains(query, "mutation") && strings.Contains(query, "createTask"): return h.handleCreateTask(c, ctx, req) case strings.Contains(query, "query") && strings.Contains(query, "me"): return h.handleMe(c, ctx, req) case strings.Contains(query, "query") && strings.Contains(query, "users"): return h.handleUsers(c, ctx, req) case strings.Contains(query, "query") && strings.Contains(query, "projects"): return h.handleProjects(c, ctx, req) case strings.Contains(query, "query") && strings.Contains(query, "tasks"): return h.handleTasks(c, ctx, req) default: return c.Status(400).JSON(GraphQLResponse{ Errors: []GraphQLError{{Message: "Query not supported"}}, }) } } // handleLogin handles login mutations func (h *GraphQLHandler) handleLogin(c *fiber.Ctx, ctx context.Context, req GraphQLRequest) error { // Extract variables email, ok := req.Variables["email"].(string) if !ok { return c.Status(400).JSON(GraphQLResponse{ Errors: []GraphQLError{{Message: "Email is required"}}, }) } password, ok := req.Variables["password"].(string) if !ok { return c.Status(400).JSON(GraphQLResponse{ Errors: []GraphQLError{{Message: "Password is required"}}, }) } // Call service token, err := h.membershipService.Login(ctx, email, password) if err != nil { return c.Status(401).JSON(GraphQLResponse{ Errors: []GraphQLError{{Message: "Invalid credentials"}}, }) } // Mock user data for now userData := map[string]interface{}{ "id": "1", "email": email, "fullName": "User", "createdAt": "2024-01-01T00:00:00Z", "updatedAt": "2024-01-01T00:00:00Z", } response := map[string]interface{}{ "login": map[string]interface{}{ "token": token, "user": userData, }, } return c.JSON(GraphQLResponse{Data: response}) } // handleCreateUser handles user creation mutations func (h *GraphQLHandler) handleCreateUser(c *fiber.Ctx, ctx context.Context, req GraphQLRequest) error { // Extract variables email, ok := req.Variables["email"].(string) if !ok { return c.Status(400).JSON(GraphQLResponse{ Errors: []GraphQLError{{Message: "Email is required"}}, }) } password, ok := req.Variables["password"].(string) if !ok { return c.Status(400).JSON(GraphQLResponse{ Errors: []GraphQLError{{Message: "Password is required"}}, }) } fullName, ok := req.Variables["fullName"].(string) if !ok { fullName = "" } // Create domain model user := &model.User{ Email: email, FullName: fullName, } if err := user.SetPassword(password); err != nil { return c.Status(400).JSON(GraphQLResponse{ Errors: []GraphQLError{{Message: err.Error()}}, }) } // Call service createdUser, err := h.membershipService.CreateUser(ctx, user, []string{"user"}) if err != nil { return c.Status(400).JSON(GraphQLResponse{ Errors: []GraphQLError{{Message: err.Error()}}, }) } // Convert user to response format userData := map[string]interface{}{ "id": createdUser.ID, "email": createdUser.Email, "fullName": createdUser.FullName, "createdAt": createdUser.CreatedAt.Format("2006-01-02T15:04:05Z07:00"), "updatedAt": createdUser.UpdatedAt.Format("2006-01-02T15:04:05Z07:00"), } response := map[string]interface{}{ "createUser": userData, } return c.JSON(GraphQLResponse{Data: response}) } // handleMe handles me queries func (h *GraphQLHandler) handleMe(c *fiber.Ctx, ctx context.Context, req GraphQLRequest) error { // This would typically extract user ID from JWT token // For now, return mock data userData := map[string]interface{}{ "id": "1", "email": "admin@example.com", "fullName": "System Administrator", "createdAt": "2024-01-01T00:00:00Z", "updatedAt": "2024-01-01T00:00:00Z", } response := map[string]interface{}{ "me": userData, } return c.JSON(GraphQLResponse{Data: response}) } // handleUsers handles users queries func (h *GraphQLHandler) handleUsers(c *fiber.Ctx, ctx context.Context, req GraphQLRequest) error { // Call service users, err := h.membershipService.ListUsers(ctx) if err != nil { return c.Status(500).JSON(GraphQLResponse{ Errors: []GraphQLError{{Message: "Failed to fetch users"}}, }) } // Convert users to response format usersData := make([]map[string]interface{}, len(users)) for i, user := range users { usersData[i] = map[string]interface{}{ "id": user.ID, "email": user.Email, "fullName": user.FullName, "createdAt": user.CreatedAt.Format("2006-01-02T15:04:05Z07:00"), "updatedAt": user.UpdatedAt.Format("2006-01-02T15:04:05Z07:00"), } } response := map[string]interface{}{ "users": usersData, } return c.JSON(GraphQLResponse{Data: response}) } // handleCreateProject handles project creation mutations func (h *GraphQLHandler) handleCreateProject(c *fiber.Ctx, ctx context.Context, req GraphQLRequest) error { // Extract variables name, ok := req.Variables["name"].(string) if !ok { return c.Status(400).JSON(GraphQLResponse{ Errors: []GraphQLError{{Message: "Name is required"}}, }) } ownerId, ok := req.Variables["ownerId"].(string) if !ok { return c.Status(400).JSON(GraphQLResponse{ Errors: []GraphQLError{{Message: "Owner ID is required"}}, }) } description, _ := req.Variables["description"].(string) // Mock project data for now projectData := map[string]interface{}{ "id": "mock-project-id", "name": name, "description": description, "ownerId": ownerId, "createdAt": "2024-01-01T00:00:00Z", "updatedAt": "2024-01-01T00:00:00Z", } response := map[string]interface{}{ "createProject": projectData, } return c.JSON(GraphQLResponse{Data: response}) } // handleCreateTask handles task creation mutations func (h *GraphQLHandler) handleCreateTask(c *fiber.Ctx, ctx context.Context, req GraphQLRequest) error { // Extract variables title, ok := req.Variables["title"].(string) if !ok { return c.Status(400).JSON(GraphQLResponse{ Errors: []GraphQLError{{Message: "Title is required"}}, }) } projectId, ok := req.Variables["projectId"].(string) if !ok { return c.Status(400).JSON(GraphQLResponse{ Errors: []GraphQLError{{Message: "Project ID is required"}}, }) } description, _ := req.Variables["description"].(string) status, _ := req.Variables["status"].(string) if status == "" { status = "todo" } priority, _ := req.Variables["priority"].(string) if priority == "" { priority = "medium" } // Mock task data for now taskData := map[string]interface{}{ "id": "mock-task-id", "title": title, "description": description, "status": status, "priority": priority, "projectId": projectId, "createdAt": "2024-01-01T00:00:00Z", "updatedAt": "2024-01-01T00:00:00Z", } response := map[string]interface{}{ "createTask": taskData, } return c.JSON(GraphQLResponse{Data: response}) } // handleProjects handles projects queries func (h *GraphQLHandler) handleProjects(c *fiber.Ctx, ctx context.Context, req GraphQLRequest) error { // Mock empty projects list for now response := map[string]interface{}{ "projects": []interface{}{}, } return c.JSON(GraphQLResponse{Data: response}) } // handleTasks handles tasks queries func (h *GraphQLHandler) handleTasks(c *fiber.Ctx, ctx context.Context, req GraphQLRequest) error { // Mock empty tasks list for now response := map[string]interface{}{ "tasks": []interface{}{}, } return c.JSON(GraphQLResponse{Data: response}) } // GetSchema returns the GraphQL schema func (h *GraphQLHandler) GetSchema() string { return ` # Core Types type User { id: String! email: String! fullName: String createdAt: String! updatedAt: String! } type Project { id: String! name: String! description: String ownerId: String! createdAt: String! updatedAt: String! } type Task { id: String! title: String! description: String status: String! priority: String! projectId: String! createdAt: String! updatedAt: String! } # Input Types input LoginInput { email: String! password: String! } input UserCreateInput { email: String! fullName: String! password: String! } input ProjectCreateInput { name: String! description: String ownerId: String! } input TaskCreateInput { title: String! description: String status: String priority: String projectId: String! } # Response Types type AuthResponse { token: String! user: User! } type MessageResponse { message: String! success: Boolean! } # Queries type Query { me: User! users: [User!]! user(id: String!): User projects: [Project!]! project(id: String!): Project tasks(projectId: String): [Task!]! task(id: String!): Task } # Mutations type Mutation { login(input: LoginInput!): AuthResponse! createUser(input: UserCreateInput!): User! createProject(input: ProjectCreateInput!): Project! createTask(input: TaskCreateInput!): Task! } ` }