Files
2025-07-06 19:19:36 +02:00

422 lines
10 KiB
Go

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!
}
`
}