From aa5c7e77fc63297c68a544d66e4e05addeb92198 Mon Sep 17 00:00:00 2001 From: Jean Jacques Avril Date: Mon, 10 Mar 2025 20:48:13 +0000 Subject: [PATCH] refactor: Remove deprecated, bad examples --- docu/code_examples/api_handler.go | 101 ------------------ docu/code_examples/fpgo_repository.go | 52 ---------- docu/code_examples/fpgo_service.go | 99 ------------------ docu/code_examples/gorm_entities.go | 104 ------------------- docu/code_examples/react_component.tsx | 136 ------------------------- 5 files changed, 492 deletions(-) delete mode 100644 docu/code_examples/api_handler.go delete mode 100644 docu/code_examples/fpgo_repository.go delete mode 100644 docu/code_examples/fpgo_service.go delete mode 100644 docu/code_examples/gorm_entities.go delete mode 100644 docu/code_examples/react_component.tsx diff --git a/docu/code_examples/api_handler.go b/docu/code_examples/api_handler.go deleted file mode 100644 index 532ee39..0000000 --- a/docu/code_examples/api_handler.go +++ /dev/null @@ -1,101 +0,0 @@ -// interfaces/http/handlers/time_entry_handler.go -package main - -import ( - "net/http" - - "github.com/email/timetracker/internal/application/timetracking" - "github.com/email/timetracker/internal/interfaces/http/dto" - "github.com/email/timetracker/internal/interfaces/http/middleware" - "github.com/gin-gonic/gin" - "github.com/google/uuid" -) - -// TimeEntryHandler behandelt HTTP-Anfragen für Zeitbuchungen -type TimeEntryHandler struct { - createTimeEntryUseCase *timetracking.CreateTimeEntryUseCase - updateTimeEntryUseCase *timetracking.UpdateTimeEntryUseCase - listTimeEntriesUseCase *timetracking.ListTimeEntriesUseCase - deleteTimeEntryUseCase *timetracking.DeleteTimeEntryUseCase -} - -// NewTimeEntryHandler erstellt einen neuen TimeEntryHandler -func NewTimeEntryHandler( - createTimeEntryUseCase *timetracking.CreateTimeEntryUseCase, - updateTimeEntryUseCase *timetracking.UpdateTimeEntryUseCase, - listTimeEntriesUseCase *timetracking.ListTimeEntriesUseCase, - deleteTimeEntryUseCase *timetracking.DeleteTimeEntryUseCase, -) *TimeEntryHandler { - return &TimeEntryHandler{ - createTimeEntryUseCase: createTimeEntryUseCase, - updateTimeEntryUseCase: updateTimeEntryUseCase, - listTimeEntriesUseCase: listTimeEntriesUseCase, - deleteTimeEntryUseCase: deleteTimeEntryUseCase, - } -} - -// RegisterRoutes registriert die Routen am Router -func (h *TimeEntryHandler) RegisterRoutes(router *gin.RouterGroup) { - timeEntries := router.Group("/time-entries") - { - timeEntries.GET("", h.ListTimeEntries) - timeEntries.POST("", h.CreateTimeEntry) - timeEntries.GET("/:id", h.GetTimeEntry) - timeEntries.PUT("/:id", h.UpdateTimeEntry) - timeEntries.DELETE("/:id", h.DeleteTimeEntry) - } -} - -// CreateTimeEntry behandelt die Erstellung einer neuen Zeitbuchung -func (h *TimeEntryHandler) CreateTimeEntry(c *gin.Context) { - var req dto.CreateTimeEntryRequest - if err := c.ShouldBindJSON(&req); err != nil { - c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()}) - return - } - - // Tenant-ID aus dem Kontext extrahieren - companyID, exists := middleware.GetCompanyID(c) - if !exists { - c.JSON(http.StatusBadRequest, gin.H{"error": "Company ID not found"}) - return - } - - // Benutzer-ID aus dem Kontext oder Request - var userID uuid.UUID - if req.UserID != nil { - userID = *req.UserID - } else { - currentUserID, exists := middleware.GetUserID(c) - if !exists { - c.JSON(http.StatusBadRequest, gin.H{"error": "User ID not found"}) - return - } - userID = currentUserID - } - - // Command erstellen - cmd := timetracking.CreateTimeEntryCommand{ - UserID: userID, - ProjectID: req.ProjectID, - ActivityID: req.ActivityID, - TaskID: req.TaskID, - StartTime: req.StartTime, - EndTime: req.EndTime, - Description: req.Description, - BillablePercentage: req.BillablePercentage, - } - - // UseCase ausführen - result := h.createTimeEntryUseCase.Execute(c.Request.Context(), companyID, cmd) - if result.IsFailure() { - c.JSON(http.StatusInternalServerError, gin.H{"error": result.Error().Error()}) - return - } - - // TimeEntry in Response-DTO umwandeln - timeEntry := result.Value() - response := dto.MapTimeEntryToDTO(*timeEntry) - - c.JSON(http.StatusCreated, response) -} diff --git a/docu/code_examples/fpgo_repository.go b/docu/code_examples/fpgo_repository.go deleted file mode 100644 index 4dfcec2..0000000 --- a/docu/code_examples/fpgo_repository.go +++ /dev/null @@ -1,52 +0,0 @@ -// domain/repositories/time_entry_repository.go -package repositories - -import ( - "context" - "time" - - "github.com/email/timetracker/internal/domain/entities" - "github.com/email/timetracker/pkg/functional" - "github.com/google/uuid" -) - -// TimeEntryFilter enthält Filter für die Suche nach Zeitbuchungen -type TimeEntryFilter struct { - UserID *uuid.UUID - ProjectID *uuid.UUID - CustomerID *uuid.UUID - StartDate *time.Time - EndDate *time.Time - ActivityID *uuid.UUID - TaskID *uuid.UUID -} - -// TimeEntryRepository Interface für den Zugriff auf Zeitbuchungen -type TimeEntryRepository interface { - // FindByID sucht eine Zeitbuchung anhand ihrer ID - FindByID(ctx context.Context, companyID, id uuid.UUID) functional.Result[*entities.TimeEntry] - - // FindAll sucht alle Zeitbuchungen mit optionalen Filtern - FindAll(ctx context.Context, companyID uuid.UUID, filter TimeEntryFilter) functional.Result[[]entities.TimeEntry] - - // Create erstellt eine neue Zeitbuchung - Create(ctx context.Context, entry *entities.TimeEntry) functional.Result[*entities.TimeEntry] - - // Update aktualisiert eine bestehende Zeitbuchung - Update(ctx context.Context, entry *entities.TimeEntry) functional.Result[*entities.TimeEntry] - - // Delete löscht eine Zeitbuchung - Delete(ctx context.Context, companyID, id uuid.UUID) functional.Result[bool] - - // GetSummary berechnet eine Zusammenfassung der Zeitbuchungen - GetSummary(ctx context.Context, companyID uuid.UUID, filter TimeEntryFilter) functional.Result[TimeEntrySummary] -} - -// TimeEntrySummary enthält zusammengefasste Informationen über Zeitbuchungen -type TimeEntrySummary struct { - TotalDuration int - TotalBillableDuration int - TotalAmount float64 - TotalBillableAmount float64 - EntriesCount int -} diff --git a/docu/code_examples/fpgo_service.go b/docu/code_examples/fpgo_service.go deleted file mode 100644 index fc42b6a..0000000 --- a/docu/code_examples/fpgo_service.go +++ /dev/null @@ -1,99 +0,0 @@ -// application/timetracking/create_time_entry.go -package main - -import ( - "context" - "time" - - "github.com/email/timetracker/internal/domain/entities" - "github.com/email/timetracker/internal/domain/repositories" - "github.com/email/timetracker/pkg/functional" - "github.com/email/timetracker/pkg/validator" - "github.com/google/uuid" -) - -// CreateTimeEntryCommand enthält die Daten zum Erstellen einer Zeitbuchung -type CreateTimeEntryCommand struct { - UserID uuid.UUID - ProjectID uuid.UUID - ActivityID uuid.UUID - TaskID *uuid.UUID - StartTime time.Time - EndTime time.Time - Description string - BillablePercentage int -} - -// CreateTimeEntryUseCase repräsentiert den Anwendungsfall zum Erstellen einer Zeitbuchung -type CreateTimeEntryUseCase struct { - timeEntryRepo repositories.TimeEntryRepository - projectRepo repositories.ProjectRepository - activityRepo repositories.ActivityRepository - userRepo repositories.UserRepository -} - -// NewCreateTimeEntryUseCase erstellt eine neue Instanz des UseCase -func NewCreateTimeEntryUseCase( - timeEntryRepo repositories.TimeEntryRepository, - projectRepo repositories.ProjectRepository, - activityRepo repositories.ActivityRepository, - userRepo repositories.UserRepository, -) *CreateTimeEntryUseCase { - return &CreateTimeEntryUseCase{ - timeEntryRepo: timeEntryRepo, - projectRepo: projectRepo, - activityRepo: activityRepo, - userRepo: userRepo, - } -} - -// Execute führt den Anwendungsfall aus -func (uc *CreateTimeEntryUseCase) Execute(ctx context.Context, companyID uuid.UUID, cmd CreateTimeEntryCommand) functional.Result[*entities.TimeEntry] { - // Validierung - if err := validator.ValidateStruct(cmd); err != nil { - return functional.Failure[*entities.TimeEntry](err) - } - - // Überprüfen, ob Projekt existiert und zum gleichen Tenant gehört - projectResult := uc.projectRepo.FindByID(ctx, companyID, cmd.ProjectID) - if projectResult.IsFailure() { - return functional.Failure[*entities.TimeEntry](projectResult.Error()) - } - - // Überprüfen, ob Activity existiert und zum gleichen Tenant gehört - activityResult := uc.activityRepo.FindByID(ctx, companyID, cmd.ActivityID) - if activityResult.IsFailure() { - return functional.Failure[*entities.TimeEntry](activityResult.Error()) - } - activity := activityResult.Value() - - // Benutzer abrufen für den Stundensatz - userResult := uc.userRepo.FindByID(ctx, companyID, cmd.UserID) - if userResult.IsFailure() { - return functional.Failure[*entities.TimeEntry](userResult.Error()) - } - user := userResult.Value() - - // Berechnung der Dauer in Minuten - durationMinutes := int(cmd.EndTime.Sub(cmd.StartTime).Minutes()) - - // TimeEntry erstellen - timeEntry := &entities.TimeEntry{ - TenantEntity: entities.TenantEntity{ - CompanyID: companyID, - }, - UserID: cmd.UserID, - ProjectID: cmd.ProjectID, - ActivityID: cmd.ActivityID, - TaskID: cmd.TaskID, - StartTime: cmd.StartTime, - EndTime: cmd.EndTime, - DurationMinutes: durationMinutes, - Description: cmd.Description, - BillablePercentage: cmd.BillablePercentage, - BillingRate: activity.BillingRate, - } - - // Speichern der TimeEntry - return uc.timeEntryRepo.Create(ctx, timeEntry) -} diff --git a/docu/code_examples/gorm_entities.go b/docu/code_examples/gorm_entities.go deleted file mode 100644 index 444b361..0000000 --- a/docu/code_examples/gorm_entities.go +++ /dev/null @@ -1,104 +0,0 @@ -package models - -import ( - "time" - - "github.com/google/uuid" - "gorm.io/gorm" -) - -// BaseEntity enthält gemeinsame Felder für alle Entitäten -type BaseEntity struct { - ID uuid.UUID `gorm:"type:uuid;primary_key"` - CreatedAt time.Time `gorm:"autoCreateTime"` - UpdatedAt time.Time `gorm:"autoUpdateTime"` - DeletedAt gorm.DeletedAt `gorm:"index"` -} - -// BeforeCreate setzt eine neue UUID vor dem Erstellen -func (base *BaseEntity) BeforeCreate(tx *gorm.DB) error { - if base.ID == uuid.Nil { - base.ID = uuid.New() - } - return nil -} - -// TenantEntity erweitert BaseEntity um Company-ID für Multi-Tenancy -type TenantEntity struct { - BaseEntity - CompanyID uuid.UUID `gorm:"type:uuid;index:idx_tenant"` -} - -// Role repräsentiert eine Benutzerrolle -type Role struct { - BaseEntity - Name string `gorm:"unique;not null"` - Description string - Permissions []Permission `gorm:"many2many:role_permissions;"` -} - -// Permission repräsentiert eine einzelne Berechtigung -type Permission struct { - BaseEntity - Resource string `gorm:"not null"` - Action string `gorm:"not null"` - UniqueID string `gorm:"uniqueIndex"` -} - -// User repräsentiert einen Benutzer im System -type User struct { - TenantEntity - Email string `gorm:"uniqueIndex;not null"` - FirstName string - LastName string - PasswordHash string `gorm:"not null"` - RoleID uuid.UUID `gorm:"type:uuid"` - Role Role `gorm:"foreignKey:RoleID"` - HourlyRate float64 - IsActive bool `gorm:"default:true"` -} - -// FullName gibt den vollständigen Namen des Benutzers zurück -func (u User) FullName() string { - return u.FirstName + " " + u.LastName -} - -// TimeEntry repräsentiert eine Zeitbuchung -type TimeEntry struct { - TenantEntity - UserID uuid.UUID `gorm:"type:uuid;index:idx_user"` - User User `gorm:"foreignKey:UserID"` - ProjectID uuid.UUID `gorm:"type:uuid;index:idx_project"` - Project Project `gorm:"foreignKey:ProjectID"` - ActivityID uuid.UUID `gorm:"type:uuid"` - Activity Activity `gorm:"foreignKey:ActivityID"` - TaskID *uuid.UUID `gorm:"type:uuid;null"` - Task *Task `gorm:"foreignKey:TaskID"` - StartTime time.Time `gorm:"not null;index:idx_time_range"` - EndTime time.Time `gorm:"not null;index:idx_time_range"` - DurationMinutes int `gorm:"not null"` - Description string - BillablePercentage int `gorm:"default:100"` - BillingRate float64 -} - -type Project struct { - TenantEntity - Name string -} - -type Activity struct { - TenantEntity - Name string -} - -type Task struct { - TenantEntity - Name string -} - -// CalculateBillableAmount berechnet den abrechenbaren Betrag -func (t TimeEntry) CalculateBillableAmount() float64 { - hours := float64(t.DurationMinutes) / 60.0 - return hours * t.BillingRate * (float64(t.BillablePercentage) / 100.0) -} diff --git a/docu/code_examples/react_component.tsx b/docu/code_examples/react_component.tsx deleted file mode 100644 index 905f65f..0000000 --- a/docu/code_examples/react_component.tsx +++ /dev/null @@ -1,136 +0,0 @@ -// presentation/components/timeTracker/Timer/Timer.tsx -import React, { useState, useEffect } from 'react'; -import { useTimeTracking } from '../../../hooks/useTimeTracking'; -import { pipe, Option, fromNullable } from '../../../../utils/fp/option'; -import { Button } from '../../common/Button'; -import { formatDuration } from '../../../../utils/date/dateUtils'; - -interface TimerProps { - onComplete?: (duration: number) => void; -} - -export const Timer: React.FC = ({ onComplete }) => { - const [isRunning, setIsRunning] = useState(false); - const [startTime, setStartTime] = useState>(Option.none()); - const [elapsedTime, setElapsedTime] = useState(0); - const [selectedProject, setSelectedProject] = useState>(Option.none()); - const [selectedActivity, setSelectedActivity] = useState>(Option.none()); - - const { lastTimeEntry, projects, activities } = useTimeTracking(); - - // Beim ersten Rendering die letzte Zeitbuchung laden - useEffect(() => { - pipe( - fromNullable(lastTimeEntry), - Option.map(entry => { - setSelectedProject(Option.some(entry.projectId)); - setSelectedActivity(Option.some(entry.activityId)); - }) - ); - }, [lastTimeEntry]); - - // Timer-Logik - useEffect(() => { - let interval: NodeJS.Timeout | null = null; - - if (isRunning) { - interval = setInterval(() => { - const now = new Date(); - pipe( - startTime, - Option.map(start => { - const diff = now.getTime() - start.getTime(); - setElapsedTime(Math.floor(diff / 1000)); - }) - ); - }, 1000); - } else if (interval) { - clearInterval(interval); - } - - return () => { - if (interval) clearInterval(interval); - }; - }, [isRunning, startTime]); - - // Timer starten - const handleStart = () => { - setStartTime(Option.some(new Date())); - setIsRunning(true); - }; - - // Timer stoppen - const handleStop = () => { - setIsRunning(false); - - // Prüfen, ob Projekt und Aktivität ausgewählt wurden - const projectId = pipe( - selectedProject, - Option.getOrElse(() => '') - ); - - const activityId = pipe( - selectedActivity, - Option.getOrElse(() => '') - ); - - if (projectId && activityId && onComplete) { - onComplete(elapsedTime); - } - - // Timer zurücksetzen - setElapsedTime(0); - setStartTime(Option.none()); - }; - - return ( -
-
- {formatDuration(elapsedTime)} -
- -
-
- - -
- -
- - -
-
- -
-
-
- ); -}; \ No newline at end of file