completed go backend
This commit is contained in:
parent
f151fa7eae
commit
aca98554d0
@ -22,10 +22,10 @@ Router getRouter(ProviderContainer container) {
|
|||||||
final timeEntryService = container.read(timeEntryServiceProvider);
|
final timeEntryService = container.read(timeEntryServiceProvider);
|
||||||
|
|
||||||
// UserService-Router
|
// UserService-Router
|
||||||
router.mount('/users/', userService.router.call);
|
router.mount('/api/users/', userService.router.call);
|
||||||
router.mount('/projects/', projectService.router.call);
|
router.mount('/api/projects/', projectService.router.call);
|
||||||
router.mount('/project-tasks/', projectTaskService.router.call);
|
router.mount('/api/project-tasks/', projectTaskService.router.call);
|
||||||
router.mount('/time-entries/', timeEntryService.router.call);
|
router.mount('/api/time-entries/', timeEntryService.router.call);
|
||||||
|
|
||||||
return router;
|
return router;
|
||||||
}
|
}
|
||||||
|
@ -1,7 +1,10 @@
|
|||||||
package main
|
package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"actatempus_backend/internal/application/repository"
|
||||||
|
"actatempus_backend/internal/application/services"
|
||||||
"actatempus_backend/internal/infrastructure/config"
|
"actatempus_backend/internal/infrastructure/config"
|
||||||
|
"actatempus_backend/internal/infrastructure/data"
|
||||||
"actatempus_backend/internal/interfaces/http"
|
"actatempus_backend/internal/interfaces/http"
|
||||||
"fmt"
|
"fmt"
|
||||||
"log"
|
"log"
|
||||||
@ -14,8 +17,27 @@ func main() {
|
|||||||
log.Fatalf("could not load config: %v", err)
|
log.Fatalf("could not load config: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Starte den HTTP-Server
|
database, err := data.NewPrismaDatabase()
|
||||||
server := http.NewServer(cfg)
|
|
||||||
|
if err != nil {
|
||||||
|
log.Fatalf("could not initialize database: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Initialize repositories
|
||||||
|
userRepo := repository.NewUserRepository(database.Users())
|
||||||
|
projectRepo := repository.NewProjectRepository(database.Projects())
|
||||||
|
projectTaskRepo := repository.NewProjectTaskRepository(database.ProjectTasks())
|
||||||
|
timeEntryRepo := repository.NewTimeEntryRepository(database.TimeEntries())
|
||||||
|
|
||||||
|
// Initialize services
|
||||||
|
userService := services.NewUserService(userRepo)
|
||||||
|
projectService := services.NewProjectService(projectRepo)
|
||||||
|
projectTaskService := services.NewProjectTaskService(projectTaskRepo)
|
||||||
|
timeEntryService := services.NewTimeEntryService(timeEntryRepo)
|
||||||
|
|
||||||
|
// Initialize and start the server
|
||||||
|
server := http.NewServer(cfg, userService, projectService, projectTaskService, timeEntryService)
|
||||||
|
|
||||||
fmt.Println("Starting ActaTempus server on port 8080...")
|
fmt.Println("Starting ActaTempus server on port 8080...")
|
||||||
if err := server.Start(); err != nil {
|
if err := server.Start(); err != nil {
|
||||||
log.Fatalf("server failed to start: %v", err)
|
log.Fatalf("server failed to start: %v", err)
|
||||||
|
@ -6,7 +6,7 @@ import (
|
|||||||
E "github.com/IBM/fp-go/either"
|
E "github.com/IBM/fp-go/either"
|
||||||
)
|
)
|
||||||
|
|
||||||
// curried delegiert eine Methode mit Kontext und gibt eine Funktion zurück.
|
// curried is a helper function to simplify currying by taking a context and returning a function.
|
||||||
func curried[T any, R any](ctx context.Context, fn func(context.Context, T) E.Either[error, R]) func(T) E.Either[error, R] {
|
func curried[T any, R any](ctx context.Context, fn func(context.Context, T) E.Either[error, R]) func(T) E.Either[error, R] {
|
||||||
return func(input T) E.Either[error, R] {
|
return func(input T) E.Either[error, R] {
|
||||||
return fn(ctx, input)
|
return fn(ctx, input)
|
||||||
|
@ -20,28 +20,28 @@ func NewProjectRepository(dataSource data.ProjectDataSource) repository.ProjectR
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Create delegates the creation of a project to the data source.
|
// Create delegates the creation of a project to the data source.
|
||||||
func (r *ProjectRepositoryImpl) Create(ctx context.Context, project entities.ProjectCreate) E.Either[error, entities.Project] {
|
func (r *ProjectRepositoryImpl) Create(ctx context.Context) func(project entities.ProjectCreate) E.Either[error, entities.Project] {
|
||||||
return r.dataSource.Create(ctx, project)
|
return curried(ctx, r.dataSource.Create)
|
||||||
}
|
}
|
||||||
|
|
||||||
// FindByID delegates fetching a project by ID to the data source.
|
// FindByID delegates fetching a project by ID to the data source.
|
||||||
func (r *ProjectRepositoryImpl) FindByID(ctx context.Context, id string) E.Either[error, entities.Project] {
|
func (r *ProjectRepositoryImpl) FindByID(ctx context.Context) func(id string) E.Either[error, entities.Project] {
|
||||||
return r.dataSource.FindByID(ctx, id)
|
return curried(ctx, r.dataSource.FindByID)
|
||||||
}
|
}
|
||||||
|
|
||||||
// FindByUserID delegates fetching all projects for a user to the data source.
|
// FindByUserID delegates fetching projects by user ID to the data source.
|
||||||
func (r *ProjectRepositoryImpl) FindByUserID(ctx context.Context, userID string) E.Either[error, []entities.Project] {
|
func (r *ProjectRepositoryImpl) FindByUserID(ctx context.Context) func(userID string) E.Either[error, []entities.Project] {
|
||||||
return r.dataSource.FindByUserID(ctx, userID)
|
return curried(ctx, r.dataSource.FindByUserID)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Update delegates updating a project to the data source.
|
// Update delegates updating a project to the data source.
|
||||||
func (r *ProjectRepositoryImpl) Update(ctx context.Context, project entities.ProjectUpdate) E.Either[error, entities.Project] {
|
func (r *ProjectRepositoryImpl) Update(ctx context.Context) func(project entities.ProjectUpdate) E.Either[error, entities.Project] {
|
||||||
return r.dataSource.Update(ctx, project)
|
return curried(ctx, r.dataSource.Update)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Delete delegates deleting a project to the data source.
|
// Delete delegates deleting a project to the data source.
|
||||||
func (r *ProjectRepositoryImpl) Delete(ctx context.Context, id string) E.Either[error, entities.Project] {
|
func (r *ProjectRepositoryImpl) Delete(ctx context.Context) func(id string) E.Either[error, entities.Project] {
|
||||||
return r.dataSource.Delete(ctx, id)
|
return curried(ctx, r.dataSource.Delete)
|
||||||
}
|
}
|
||||||
|
|
||||||
// FindAll delegates fetching all projects to the data source.
|
// FindAll delegates fetching all projects to the data source.
|
||||||
|
@ -13,33 +13,35 @@ import (
|
|||||||
type ProjectTaskRepositoryImpl struct {
|
type ProjectTaskRepositoryImpl struct {
|
||||||
dataSource data.ProjectTaskDataSource
|
dataSource data.ProjectTaskDataSource
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewProjectTaskRepository creates a new instance of ProjectTaskRepositoryImpl.
|
// NewProjectTaskRepository creates a new instance of ProjectTaskRepositoryImpl.
|
||||||
func NewProjectTaskRepository(dataSource data.ProjectTaskDataSource) repository.ProjectTaskRepository {
|
func NewProjectTaskRepository(dataSource data.ProjectTaskDataSource) repository.ProjectTaskRepository {
|
||||||
return &ProjectTaskRepositoryImpl{dataSource: dataSource}
|
return &ProjectTaskRepositoryImpl{dataSource: dataSource}
|
||||||
}
|
}
|
||||||
// FindByProjectID implements repository.ProjectTaskRepository.
|
|
||||||
func (r *ProjectTaskRepositoryImpl) FindByProjectID(ctx context.Context, projectID string) E.Either[error, []entities.ProjectTask] {
|
|
||||||
return r.dataSource.FindByProjectID(ctx, projectID)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Create delegates the creation of a project task to the data source.
|
// Create delegates the creation of a project task to the data source.
|
||||||
func (r *ProjectTaskRepositoryImpl) Create(ctx context.Context, task entities.ProjectTaskCreate) E.Either[error, entities.ProjectTask] {
|
func (r *ProjectTaskRepositoryImpl) Create(ctx context.Context) func(task entities.ProjectTaskCreate) E.Either[error, entities.ProjectTask] {
|
||||||
return r.dataSource.Create(ctx, task)
|
return curried(ctx, r.dataSource.Create)
|
||||||
}
|
}
|
||||||
|
|
||||||
// FindByID delegates fetching a project task by ID to the data source.
|
// FindByID delegates fetching a project task by ID to the data source.
|
||||||
func (r *ProjectTaskRepositoryImpl) FindByID(ctx context.Context, id string) E.Either[error, entities.ProjectTask] {
|
func (r *ProjectTaskRepositoryImpl) FindByID(ctx context.Context) func(id string) E.Either[error, entities.ProjectTask] {
|
||||||
return r.dataSource.FindByID(ctx, id)
|
return curried(ctx, r.dataSource.FindByID)
|
||||||
|
}
|
||||||
|
|
||||||
|
// FindByProjectID delegates fetching project tasks by project ID to the data source.
|
||||||
|
func (r *ProjectTaskRepositoryImpl) FindByProjectID(ctx context.Context) func(projectID string) E.Either[error, []entities.ProjectTask] {
|
||||||
|
return curried(ctx, r.dataSource.FindByProjectID)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Update delegates updating a project task to the data source.
|
// Update delegates updating a project task to the data source.
|
||||||
func (r *ProjectTaskRepositoryImpl) Update(ctx context.Context, task entities.ProjectTaskUpdate) E.Either[error, entities.ProjectTask] {
|
func (r *ProjectTaskRepositoryImpl) Update(ctx context.Context) func(task entities.ProjectTaskUpdate) E.Either[error, entities.ProjectTask] {
|
||||||
return r.dataSource.Update(ctx, task)
|
return curried(ctx, r.dataSource.Update)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Delete delegates deleting a project task to the data source.
|
// Delete delegates deleting a project task to the data source.
|
||||||
func (r *ProjectTaskRepositoryImpl) Delete(ctx context.Context, id string) E.Either[error, entities.ProjectTask] {
|
func (r *ProjectTaskRepositoryImpl) Delete(ctx context.Context) func(id string) E.Either[error, entities.ProjectTask] {
|
||||||
return r.dataSource.Delete(ctx, id)
|
return curried(ctx, r.dataSource.Delete)
|
||||||
}
|
}
|
||||||
|
|
||||||
// FindAll delegates fetching all project tasks to the data source.
|
// FindAll delegates fetching all project tasks to the data source.
|
||||||
|
@ -19,37 +19,37 @@ func NewTimeEntryRepository(dataSource data.TimeEntryDataSource) repository.Time
|
|||||||
return &TimeEntryRepositoryImpl{dataSource: dataSource}
|
return &TimeEntryRepositoryImpl{dataSource: dataSource}
|
||||||
}
|
}
|
||||||
|
|
||||||
// FindByProjectID implements repository.TimeEntryRepository.
|
// Create delegates the creation of a TimeEntry to the data source.
|
||||||
func (r *TimeEntryRepositoryImpl) FindByProjectID(ctx context.Context, projectID string) E.Either[error, []entities.TimeEntry] {
|
func (r *TimeEntryRepositoryImpl) Create(ctx context.Context) func(entry entities.TimeEntryCreate) E.Either[error, entities.TimeEntry] {
|
||||||
return r.dataSource.FindByProjectID(ctx, projectID)
|
return curried(ctx, r.dataSource.Create)
|
||||||
}
|
}
|
||||||
|
|
||||||
// FindByUserID implements repository.TimeEntryRepository.
|
// FindByID delegates fetching a TimeEntry by ID to the data source.
|
||||||
func (r *TimeEntryRepositoryImpl) FindByUserID(ctx context.Context, userID string) E.Either[error, []entities.TimeEntry] {
|
func (r *TimeEntryRepositoryImpl) FindByID(ctx context.Context) func(id string) E.Either[error, entities.TimeEntry] {
|
||||||
return r.dataSource.FindByUserID(ctx, userID)
|
return curried(ctx, r.dataSource.FindByID)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Create delegates the creation of a time entry to the data source.
|
// FindByUserID delegates fetching TimeEntries by UserID to the data source.
|
||||||
func (r *TimeEntryRepositoryImpl) Create(ctx context.Context, entry entities.TimeEntryCreate) E.Either[error, entities.TimeEntry] {
|
func (r *TimeEntryRepositoryImpl) FindByUserID(ctx context.Context) func(userID string) E.Either[error, []entities.TimeEntry] {
|
||||||
return r.dataSource.Create(ctx, entry)
|
return curried(ctx, r.dataSource.FindByUserID)
|
||||||
}
|
}
|
||||||
|
|
||||||
// FindByID delegates fetching a time entry by ID to the data source.
|
// FindByProjectID delegates fetching TimeEntries by ProjectID to the data source.
|
||||||
func (r *TimeEntryRepositoryImpl) FindByID(ctx context.Context, id string) E.Either[error, entities.TimeEntry] {
|
func (r *TimeEntryRepositoryImpl) FindByProjectID(ctx context.Context) func(projectID string) E.Either[error, []entities.TimeEntry] {
|
||||||
return r.dataSource.FindByID(ctx, id)
|
return curried(ctx, r.dataSource.FindByProjectID)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Update delegates updating a time entry to the data source.
|
// Update delegates updating a TimeEntry to the data source.
|
||||||
func (r *TimeEntryRepositoryImpl) Update(ctx context.Context, entry entities.TimeEntryUpdate) E.Either[error, entities.TimeEntry] {
|
func (r *TimeEntryRepositoryImpl) Update(ctx context.Context) func(entry entities.TimeEntryUpdate) E.Either[error, entities.TimeEntry] {
|
||||||
return r.dataSource.Update(ctx, entry)
|
return curried(ctx, r.dataSource.Update)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Delete delegates deleting a time entry to the data source.
|
// Delete delegates deleting a TimeEntry to the data source.
|
||||||
func (r *TimeEntryRepositoryImpl) Delete(ctx context.Context, id string) E.Either[error, entities.TimeEntry] {
|
func (r *TimeEntryRepositoryImpl) Delete(ctx context.Context) func(id string) E.Either[error, entities.TimeEntry] {
|
||||||
return r.dataSource.Delete(ctx, id)
|
return curried(ctx, r.dataSource.Delete)
|
||||||
}
|
}
|
||||||
|
|
||||||
// FindAll delegates fetching all time entries to the data source.
|
// FindAll delegates fetching all TimeEntries to the data source.
|
||||||
func (r *TimeEntryRepositoryImpl) FindAll(ctx context.Context) E.Either[error, []entities.TimeEntry] {
|
func (r *TimeEntryRepositoryImpl) FindAll(ctx context.Context) E.Either[error, []entities.TimeEntry] {
|
||||||
return r.dataSource.FindAll(ctx)
|
return r.dataSource.FindAll(ctx)
|
||||||
}
|
}
|
||||||
|
@ -3,6 +3,7 @@ package repository
|
|||||||
import (
|
import (
|
||||||
"actatempus_backend/internal/domain/data"
|
"actatempus_backend/internal/domain/data"
|
||||||
"actatempus_backend/internal/domain/entities"
|
"actatempus_backend/internal/domain/entities"
|
||||||
|
"actatempus_backend/internal/domain/repository"
|
||||||
"context"
|
"context"
|
||||||
|
|
||||||
E "github.com/IBM/fp-go/either"
|
E "github.com/IBM/fp-go/either"
|
||||||
@ -13,32 +14,37 @@ type UserRepositoryImpl struct {
|
|||||||
dataSource data.UserDataSource
|
dataSource data.UserDataSource
|
||||||
}
|
}
|
||||||
|
|
||||||
// Create delegiert die Erstellung eines Benutzers an die Datenquelle.
|
// NewUserRepository creates a new instance of UserRepositoryImpl.
|
||||||
|
func NewUserRepository(dataSource data.UserDataSource) repository.UserRepository {
|
||||||
|
return &UserRepositoryImpl{dataSource: dataSource}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create delegates the creation of a user to the data source.
|
||||||
func (r *UserRepositoryImpl) Create(ctx context.Context) func(user entities.UserCreate) E.Either[error, entities.User] {
|
func (r *UserRepositoryImpl) Create(ctx context.Context) func(user entities.UserCreate) E.Either[error, entities.User] {
|
||||||
return curried(ctx, r.dataSource.Create)
|
return curried(ctx, r.dataSource.Create)
|
||||||
}
|
}
|
||||||
|
|
||||||
// FindByID delegiert das Abrufen eines Benutzers nach ID an die Datenquelle.
|
// FindByID delegates fetching a user by ID to the data source.
|
||||||
func (r *UserRepositoryImpl) FindByID(ctx context.Context) func(id string) E.Either[error, entities.User] {
|
func (r *UserRepositoryImpl) FindByID(ctx context.Context) func(id string) E.Either[error, entities.User] {
|
||||||
return curried(ctx, r.dataSource.FindByID)
|
return curried(ctx, r.dataSource.FindByID)
|
||||||
}
|
}
|
||||||
|
|
||||||
// FindByEmail delegiert das Abrufen eines Benutzers nach E-Mail an die Datenquelle.
|
// FindByEmail delegates fetching a user by email to the data source.
|
||||||
func (r *UserRepositoryImpl) FindByEmail(ctx context.Context) func(email string) E.Either[error, entities.User] {
|
func (r *UserRepositoryImpl) FindByEmail(ctx context.Context) func(email string) E.Either[error, entities.User] {
|
||||||
return curried(ctx, r.dataSource.FindByEmail)
|
return curried(ctx, r.dataSource.FindByEmail)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Update delegiert das Aktualisieren eines Benutzers an die Datenquelle.
|
// Update delegates updating a user to the data source.
|
||||||
func (r *UserRepositoryImpl) Update(ctx context.Context) func(user entities.UserUpdate) E.Either[error, entities.User] {
|
func (r *UserRepositoryImpl) Update(ctx context.Context) func(user entities.UserUpdate) E.Either[error, entities.User] {
|
||||||
return curried(ctx, r.dataSource.Update)
|
return curried(ctx, r.dataSource.Update)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Delete delegiert das Löschen eines Benutzers an die Datenquelle.
|
// Delete delegates deleting a user to the data source.
|
||||||
func (r *UserRepositoryImpl) Delete(ctx context.Context) func(id string) E.Either[error, entities.User] {
|
func (r *UserRepositoryImpl) Delete(ctx context.Context) func(id string) E.Either[error, entities.User] {
|
||||||
return curried(ctx, r.dataSource.Delete)
|
return curried(ctx, r.dataSource.Delete)
|
||||||
}
|
}
|
||||||
|
|
||||||
// FindAll delegiert das Abrufen aller Benutzer an die Datenquelle.
|
// FindAll delegates fetching all users to the data source.
|
||||||
func (r *UserRepositoryImpl) FindAll(ctx context.Context) E.Either[error, []entities.User] {
|
func (r *UserRepositoryImpl) FindAll(ctx context.Context) E.Either[error, []entities.User] {
|
||||||
return r.dataSource.FindAll(ctx)
|
return r.dataSource.FindAll(ctx)
|
||||||
}
|
}
|
||||||
|
@ -1,14 +1,30 @@
|
|||||||
package services
|
package services
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"actatempus_backend/internal/domain/app_error"
|
||||||
"net/http"
|
"net/http"
|
||||||
|
|
||||||
"github.com/gin-gonic/gin"
|
"github.com/gin-gonic/gin"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// HandleError handles errors by formatting them as JSON.
|
||||||
func HandleError(c *gin.Context) func(error) any {
|
func HandleError(c *gin.Context) func(error) any {
|
||||||
return func(err error) any {
|
return func(err error) any {
|
||||||
c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
|
// Check if the error is of type *AppError
|
||||||
|
if appErr, ok := err.(*app_error.AppError); ok {
|
||||||
|
// Use the AppError fields for the JSON response
|
||||||
|
c.JSON(appErr.Status, gin.H{
|
||||||
|
"code": appErr.Code,
|
||||||
|
"message": appErr.Message,
|
||||||
|
"details": appErr.Err.Error(), // Original error if available
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
// Fallback for non-AppError errors
|
||||||
|
c.JSON(http.StatusInternalServerError, gin.H{
|
||||||
|
"error": err.Error(),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
109
backend-go/internal/application/services/project_service.go
Normal file
109
backend-go/internal/application/services/project_service.go
Normal file
@ -0,0 +1,109 @@
|
|||||||
|
package services
|
||||||
|
|
||||||
|
import (
|
||||||
|
"actatempus_backend/internal/application/services/dto"
|
||||||
|
mappers "actatempus_backend/internal/application/services/mapper"
|
||||||
|
"actatempus_backend/internal/domain/repository"
|
||||||
|
"net/http"
|
||||||
|
|
||||||
|
A "github.com/IBM/fp-go/array"
|
||||||
|
E "github.com/IBM/fp-go/either"
|
||||||
|
F "github.com/IBM/fp-go/function"
|
||||||
|
"github.com/gin-gonic/gin"
|
||||||
|
)
|
||||||
|
|
||||||
|
// ProjectService handles project-related HTTP requests.
|
||||||
|
type ProjectService struct {
|
||||||
|
repository repository.ProjectRepository
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewProjectService creates a new instance of ProjectService.
|
||||||
|
func NewProjectService(repo repository.ProjectRepository) *ProjectService {
|
||||||
|
return &ProjectService{repository: repo}
|
||||||
|
}
|
||||||
|
|
||||||
|
// RegisterRoutes registers the project-related routes with Gin.
|
||||||
|
func (s *ProjectService) RegisterRoutes(router *gin.RouterGroup) {
|
||||||
|
router.POST("/", s.CreateProject)
|
||||||
|
router.GET("/:id", s.GetProjectByID)
|
||||||
|
router.GET("/", s.GetAllProjects)
|
||||||
|
router.PUT("/:id", s.UpdateProject)
|
||||||
|
router.DELETE("/:id", s.DeleteProject)
|
||||||
|
}
|
||||||
|
|
||||||
|
// CreateProject handles the creation of a new project.
|
||||||
|
func (s *ProjectService) CreateProject(c *gin.Context) {
|
||||||
|
var projectCreateDTO dto.ProjectCreateDTO
|
||||||
|
if err := c.ShouldBindJSON(&projectCreateDTO); err != nil {
|
||||||
|
c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
F.Pipe3(
|
||||||
|
mappers.MapCreateDTOToProject(projectCreateDTO),
|
||||||
|
s.repository.Create(c.Request.Context()),
|
||||||
|
E.Map[error](mappers.MapProjectToDTO),
|
||||||
|
E.Fold(
|
||||||
|
HandleError(c),
|
||||||
|
HandleSuccess[dto.ProjectDTO](c, http.StatusCreated),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetProjectByID handles fetching a project by its ID.
|
||||||
|
func (s *ProjectService) GetProjectByID(c *gin.Context) {
|
||||||
|
F.Pipe3(
|
||||||
|
c.Param("id"),
|
||||||
|
s.repository.FindByID(c.Request.Context()),
|
||||||
|
E.Map[error](mappers.MapProjectToDTO),
|
||||||
|
E.Fold(
|
||||||
|
HandleError(c),
|
||||||
|
HandleSuccess[dto.ProjectDTO](c, http.StatusOK),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetAllProjects handles fetching all projects.
|
||||||
|
func (s *ProjectService) GetAllProjects(c *gin.Context) {
|
||||||
|
F.Pipe2(
|
||||||
|
s.repository.FindAll(c.Request.Context()),
|
||||||
|
E.Map[error](A.Map(mappers.MapProjectToDTO)),
|
||||||
|
E.Fold(
|
||||||
|
HandleError(c),
|
||||||
|
HandleSuccess[[]dto.ProjectDTO](c, http.StatusOK),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
// UpdateProject handles updating an existing project.
|
||||||
|
func (s *ProjectService) UpdateProject(c *gin.Context) {
|
||||||
|
id := c.Param("id")
|
||||||
|
var projectUpdateDTO dto.ProjectUpdateDTO
|
||||||
|
|
||||||
|
if err := c.ShouldBindJSON(&projectUpdateDTO); err != nil {
|
||||||
|
c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
F.Pipe3(
|
||||||
|
mappers.MapUpdateDTOToProject(projectUpdateDTO, id),
|
||||||
|
s.repository.Update(c.Request.Context()),
|
||||||
|
E.Map[error](mappers.MapProjectToDTO),
|
||||||
|
E.Fold(
|
||||||
|
HandleError(c),
|
||||||
|
HandleSuccess[dto.ProjectDTO](c, http.StatusOK),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
// DeleteProject handles deleting a project by its ID.
|
||||||
|
func (s *ProjectService) DeleteProject(c *gin.Context) {
|
||||||
|
F.Pipe3(
|
||||||
|
c.Param("id"),
|
||||||
|
s.repository.Delete(c.Request.Context()),
|
||||||
|
E.Map[error](mappers.MapProjectToDTO),
|
||||||
|
E.Fold(
|
||||||
|
HandleError(c),
|
||||||
|
HandleSuccess[dto.ProjectDTO](c, http.StatusOK),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
}
|
123
backend-go/internal/application/services/project_task_service.go
Normal file
123
backend-go/internal/application/services/project_task_service.go
Normal file
@ -0,0 +1,123 @@
|
|||||||
|
package services
|
||||||
|
|
||||||
|
import (
|
||||||
|
"actatempus_backend/internal/application/services/dto"
|
||||||
|
mappers "actatempus_backend/internal/application/services/mapper"
|
||||||
|
"actatempus_backend/internal/domain/repository"
|
||||||
|
"net/http"
|
||||||
|
|
||||||
|
A "github.com/IBM/fp-go/array"
|
||||||
|
E "github.com/IBM/fp-go/either"
|
||||||
|
F "github.com/IBM/fp-go/function"
|
||||||
|
"github.com/gin-gonic/gin"
|
||||||
|
)
|
||||||
|
|
||||||
|
// ProjectTaskService handles project task-related HTTP requests.
|
||||||
|
type ProjectTaskService struct {
|
||||||
|
repository repository.ProjectTaskRepository
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewProjectTaskService creates a new instance of ProjectTaskService.
|
||||||
|
func NewProjectTaskService(repo repository.ProjectTaskRepository) *ProjectTaskService {
|
||||||
|
return &ProjectTaskService{repository: repo}
|
||||||
|
}
|
||||||
|
|
||||||
|
// RegisterRoutes registers the project task-related routes with Gin.
|
||||||
|
func (s *ProjectTaskService) RegisterRoutes(router *gin.RouterGroup) {
|
||||||
|
router.POST("/", s.CreateTask)
|
||||||
|
router.GET("/:id", s.GetTaskByID)
|
||||||
|
router.GET("/", s.GetAllTasks)
|
||||||
|
router.GET("/project/:projectID", s.GetTasksByProjectID)
|
||||||
|
router.PUT("/:id", s.UpdateTask)
|
||||||
|
router.DELETE("/:id", s.DeleteTask)
|
||||||
|
}
|
||||||
|
|
||||||
|
// CreateTask handles the creation of a new project task.
|
||||||
|
func (s *ProjectTaskService) CreateTask(c *gin.Context) {
|
||||||
|
var taskCreateDTO dto.ProjectTaskCreateDTO
|
||||||
|
if err := c.ShouldBindJSON(&taskCreateDTO); err != nil {
|
||||||
|
c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
F.Pipe3(
|
||||||
|
mappers.MapCreateDTOToProjectTask(taskCreateDTO),
|
||||||
|
s.repository.Create(c.Request.Context()),
|
||||||
|
E.Map[error](mappers.MapProjectTaskToDTO),
|
||||||
|
E.Fold(
|
||||||
|
HandleError(c),
|
||||||
|
HandleSuccess[dto.ProjectTaskDTO](c, http.StatusCreated),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetTaskByID handles fetching a project task by its ID.
|
||||||
|
func (s *ProjectTaskService) GetTaskByID(c *gin.Context) {
|
||||||
|
F.Pipe3(
|
||||||
|
c.Param("id"),
|
||||||
|
s.repository.FindByID(c.Request.Context()),
|
||||||
|
E.Map[error](mappers.MapProjectTaskToDTO),
|
||||||
|
E.Fold(
|
||||||
|
HandleError(c),
|
||||||
|
HandleSuccess[dto.ProjectTaskDTO](c, http.StatusOK),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetTasksByProjectID handles fetching project tasks by project ID.
|
||||||
|
func (s *ProjectTaskService) GetTasksByProjectID(c *gin.Context) {
|
||||||
|
F.Pipe3(
|
||||||
|
c.Param("projectID"),
|
||||||
|
s.repository.FindByProjectID(c.Request.Context()),
|
||||||
|
E.Map[error](A.Map(mappers.MapProjectTaskToDTO)),
|
||||||
|
E.Fold(
|
||||||
|
HandleError(c),
|
||||||
|
HandleSuccess[[]dto.ProjectTaskDTO](c, http.StatusOK),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetAllTasks handles fetching all project tasks.
|
||||||
|
func (s *ProjectTaskService) GetAllTasks(c *gin.Context) {
|
||||||
|
F.Pipe2(
|
||||||
|
s.repository.FindAll(c.Request.Context()),
|
||||||
|
E.Map[error](A.Map(mappers.MapProjectTaskToDTO)),
|
||||||
|
E.Fold(
|
||||||
|
HandleError(c),
|
||||||
|
HandleSuccess[[]dto.ProjectTaskDTO](c, http.StatusOK),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
// UpdateTask handles updating an existing project task.
|
||||||
|
func (s *ProjectTaskService) UpdateTask(c *gin.Context) {
|
||||||
|
id := c.Param("id")
|
||||||
|
var taskUpdateDTO dto.ProjectTaskUpdateDTO
|
||||||
|
|
||||||
|
if err := c.ShouldBindJSON(&taskUpdateDTO); err != nil {
|
||||||
|
c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
F.Pipe3(
|
||||||
|
mappers.MapUpdateDTOToProjectTask(taskUpdateDTO, id),
|
||||||
|
s.repository.Update(c.Request.Context()),
|
||||||
|
E.Map[error](mappers.MapProjectTaskToDTO),
|
||||||
|
E.Fold(
|
||||||
|
HandleError(c),
|
||||||
|
HandleSuccess[dto.ProjectTaskDTO](c, http.StatusOK),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
// DeleteTask handles deleting a project task by its ID and returns the deleted object.
|
||||||
|
func (s *ProjectTaskService) DeleteTask(c *gin.Context) {
|
||||||
|
F.Pipe3(
|
||||||
|
c.Param("id"),
|
||||||
|
s.repository.Delete(c.Request.Context()),
|
||||||
|
E.Map[error](mappers.MapProjectTaskToDTO),
|
||||||
|
E.Fold(
|
||||||
|
HandleError(c),
|
||||||
|
HandleSuccess[dto.ProjectTaskDTO](c, http.StatusOK),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
}
|
137
backend-go/internal/application/services/time_entry_service.go
Normal file
137
backend-go/internal/application/services/time_entry_service.go
Normal file
@ -0,0 +1,137 @@
|
|||||||
|
package services
|
||||||
|
|
||||||
|
import (
|
||||||
|
"actatempus_backend/internal/application/services/dto"
|
||||||
|
mappers "actatempus_backend/internal/application/services/mapper"
|
||||||
|
"actatempus_backend/internal/domain/repository"
|
||||||
|
"net/http"
|
||||||
|
|
||||||
|
A "github.com/IBM/fp-go/array"
|
||||||
|
E "github.com/IBM/fp-go/either"
|
||||||
|
F "github.com/IBM/fp-go/function"
|
||||||
|
"github.com/gin-gonic/gin"
|
||||||
|
)
|
||||||
|
|
||||||
|
// TimeEntryService handles time entry-related HTTP requests.
|
||||||
|
type TimeEntryService struct {
|
||||||
|
repository repository.TimeEntryRepository
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewTimeEntryService creates a new instance of TimeEntryService.
|
||||||
|
func NewTimeEntryService(repo repository.TimeEntryRepository) *TimeEntryService {
|
||||||
|
return &TimeEntryService{repository: repo}
|
||||||
|
}
|
||||||
|
|
||||||
|
// RegisterRoutes registers the time entry-related routes with Gin.
|
||||||
|
func (s *TimeEntryService) RegisterRoutes(router *gin.RouterGroup) {
|
||||||
|
router.POST("/", s.CreateTimeEntry)
|
||||||
|
router.GET("/:id", s.GetTimeEntryByID)
|
||||||
|
router.GET("/", s.GetAllTimeEntries)
|
||||||
|
router.GET("/user/:userID", s.GetTimeEntriesByUserID)
|
||||||
|
router.GET("/project/:projectID", s.GetTimeEntriesByProjectID)
|
||||||
|
router.PUT("/:id", s.UpdateTimeEntry)
|
||||||
|
router.DELETE("/:id", s.DeleteTimeEntry)
|
||||||
|
}
|
||||||
|
|
||||||
|
// CreateTimeEntry handles the creation of a new time entry.
|
||||||
|
func (s *TimeEntryService) CreateTimeEntry(c *gin.Context) {
|
||||||
|
var timeEntryCreateDTO dto.TimeEntryCreateDTO
|
||||||
|
if err := c.ShouldBindJSON(&timeEntryCreateDTO); err != nil {
|
||||||
|
c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
F.Pipe3(
|
||||||
|
mappers.MapCreateDTOToTimeEntry(timeEntryCreateDTO),
|
||||||
|
s.repository.Create(c.Request.Context()),
|
||||||
|
E.Map[error](mappers.MapTimeEntryToDTO),
|
||||||
|
E.Fold(
|
||||||
|
HandleError(c),
|
||||||
|
HandleSuccess[dto.TimeEntryDTO](c, http.StatusCreated),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetTimeEntryByID handles fetching a time entry by its ID.
|
||||||
|
func (s *TimeEntryService) GetTimeEntryByID(c *gin.Context) {
|
||||||
|
F.Pipe3(
|
||||||
|
c.Param("id"),
|
||||||
|
s.repository.FindByID(c.Request.Context()),
|
||||||
|
E.Map[error](mappers.MapTimeEntryToDTO),
|
||||||
|
E.Fold(
|
||||||
|
HandleError(c),
|
||||||
|
HandleSuccess[dto.TimeEntryDTO](c, http.StatusOK),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetTimeEntriesByUserID handles fetching time entries by user ID.
|
||||||
|
func (s *TimeEntryService) GetTimeEntriesByUserID(c *gin.Context) {
|
||||||
|
F.Pipe3(
|
||||||
|
c.Param("userID"),
|
||||||
|
s.repository.FindByUserID(c.Request.Context()),
|
||||||
|
E.Map[error](A.Map(mappers.MapTimeEntryToDTO)),
|
||||||
|
E.Fold(
|
||||||
|
HandleError(c),
|
||||||
|
HandleSuccess[[]dto.TimeEntryDTO](c, http.StatusOK),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetTimeEntriesByProjectID handles fetching time entries by project ID.
|
||||||
|
func (s *TimeEntryService) GetTimeEntriesByProjectID(c *gin.Context) {
|
||||||
|
F.Pipe3(
|
||||||
|
c.Param("projectID"),
|
||||||
|
s.repository.FindByProjectID(c.Request.Context()),
|
||||||
|
E.Map[error](A.Map(mappers.MapTimeEntryToDTO)),
|
||||||
|
E.Fold(
|
||||||
|
HandleError(c),
|
||||||
|
HandleSuccess[[]dto.TimeEntryDTO](c, http.StatusOK),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetAllTimeEntries handles fetching all time entries.
|
||||||
|
func (s *TimeEntryService) GetAllTimeEntries(c *gin.Context) {
|
||||||
|
F.Pipe2(
|
||||||
|
s.repository.FindAll(c.Request.Context()),
|
||||||
|
E.Map[error](A.Map(mappers.MapTimeEntryToDTO)),
|
||||||
|
E.Fold(
|
||||||
|
HandleError(c),
|
||||||
|
HandleSuccess[[]dto.TimeEntryDTO](c, http.StatusOK),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
// UpdateTimeEntry handles updating an existing time entry.
|
||||||
|
func (s *TimeEntryService) UpdateTimeEntry(c *gin.Context) {
|
||||||
|
id := c.Param("id")
|
||||||
|
var timeEntryUpdateDTO dto.TimeEntryUpdateDTO
|
||||||
|
|
||||||
|
if err := c.ShouldBindJSON(&timeEntryUpdateDTO); err != nil {
|
||||||
|
c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
F.Pipe3(
|
||||||
|
mappers.MapUpdateDTOToTimeEntry(timeEntryUpdateDTO, id),
|
||||||
|
s.repository.Update(c.Request.Context()),
|
||||||
|
E.Map[error](mappers.MapTimeEntryToDTO),
|
||||||
|
E.Fold(
|
||||||
|
HandleError(c),
|
||||||
|
HandleSuccess[dto.TimeEntryDTO](c, http.StatusOK),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
// DeleteTimeEntry handles deleting a time entry by its ID and returns the deleted object.
|
||||||
|
func (s *TimeEntryService) DeleteTimeEntry(c *gin.Context) {
|
||||||
|
F.Pipe3(
|
||||||
|
c.Param("id"),
|
||||||
|
s.repository.Delete(c.Request.Context()),
|
||||||
|
E.Map[error](mappers.MapTimeEntryToDTO),
|
||||||
|
E.Fold(
|
||||||
|
HandleError(c),
|
||||||
|
HandleSuccess[dto.TimeEntryDTO](c, http.StatusOK),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
}
|
8
backend-go/internal/domain/data/database.go
Normal file
8
backend-go/internal/domain/data/database.go
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
package data
|
||||||
|
|
||||||
|
type Database struct {
|
||||||
|
users UserDataSource
|
||||||
|
timeEntries TimeEntryDataSource
|
||||||
|
projectTasks ProjectTaskDataSource
|
||||||
|
projects ProjectDataSource
|
||||||
|
}
|
@ -9,10 +9,11 @@ import (
|
|||||||
|
|
||||||
// ProjectRepository defines the operations for interacting with project data.
|
// ProjectRepository defines the operations for interacting with project data.
|
||||||
type ProjectRepository interface {
|
type ProjectRepository interface {
|
||||||
Create(ctx context.Context, project entities.ProjectCreate) E.Either[error,entities.Project]
|
Create(ctx context.Context) func(project entities.ProjectCreate) E.Either[error, entities.Project]
|
||||||
FindByID(ctx context.Context, id string) E.Either[error,entities.Project]
|
FindByID(ctx context.Context) func(id string) E.Either[error, entities.Project]
|
||||||
FindByUserID(ctx context.Context, userID string) E.Either[error,[]entities.Project]
|
FindByUserID(ctx context.Context) func(userID string) E.Either[error, []entities.Project]
|
||||||
Update(ctx context.Context, project entities.ProjectUpdate) E.Either[error,entities.Project]
|
Update(ctx context.Context) func(project entities.ProjectUpdate) E.Either[error, entities.Project]
|
||||||
Delete(ctx context.Context, id string) E.Either[error,entities.Project]
|
Delete(ctx context.Context) func(id string) E.Either[error, entities.Project]
|
||||||
FindAll(ctx context.Context) E.Either[error,[]entities.Project]
|
FindAll(ctx context.Context) E.Either[error, []entities.Project]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -9,10 +9,10 @@ import (
|
|||||||
|
|
||||||
// ProjectTaskRepository defines the operations for interacting with project task data.
|
// ProjectTaskRepository defines the operations for interacting with project task data.
|
||||||
type ProjectTaskRepository interface {
|
type ProjectTaskRepository interface {
|
||||||
Create(ctx context.Context, task entities.ProjectTaskCreate) E.Either[error,entities.ProjectTask]
|
Create(ctx context.Context) func(task entities.ProjectTaskCreate) E.Either[error, entities.ProjectTask]
|
||||||
FindByID(ctx context.Context, id string) E.Either[error,entities.ProjectTask]
|
FindByID(ctx context.Context) func(id string) E.Either[error, entities.ProjectTask]
|
||||||
FindByProjectID(ctx context.Context, projectID string) E.Either[error,[]entities.ProjectTask]
|
FindByProjectID(ctx context.Context) func(projectID string) E.Either[error, []entities.ProjectTask]
|
||||||
Update(ctx context.Context, task entities.ProjectTaskUpdate) E.Either[error,entities.ProjectTask]
|
Update(ctx context.Context) func(task entities.ProjectTaskUpdate) E.Either[error, entities.ProjectTask]
|
||||||
Delete(ctx context.Context, id string) E.Either[error,entities.ProjectTask]
|
Delete(ctx context.Context) func(id string) E.Either[error, entities.ProjectTask]
|
||||||
FindAll(ctx context.Context) E.Either[error,[]entities.ProjectTask]
|
FindAll(ctx context.Context) E.Either[error, []entities.ProjectTask]
|
||||||
}
|
}
|
||||||
|
@ -9,11 +9,11 @@ import (
|
|||||||
|
|
||||||
// TimeEntryRepository defines the operations for interacting with time entry data.
|
// TimeEntryRepository defines the operations for interacting with time entry data.
|
||||||
type TimeEntryRepository interface {
|
type TimeEntryRepository interface {
|
||||||
Create(ctx context.Context, entry entities.TimeEntryCreate) E.Either[error,entities.TimeEntry]
|
Create(ctx context.Context) func(entry entities.TimeEntryCreate) E.Either[error, entities.TimeEntry]
|
||||||
FindByID(ctx context.Context, id string) E.Either[error,entities.TimeEntry]
|
FindByID(ctx context.Context) func(id string) E.Either[error, entities.TimeEntry]
|
||||||
FindByUserID(ctx context.Context, userID string) E.Either[error,[]entities.TimeEntry]
|
FindByUserID(ctx context.Context) func(userID string) E.Either[error, []entities.TimeEntry]
|
||||||
FindByProjectID(ctx context.Context, projectID string) E.Either[error,[]entities.TimeEntry]
|
FindByProjectID(ctx context.Context) func(projectID string) E.Either[error, []entities.TimeEntry]
|
||||||
Update(ctx context.Context, entry entities.TimeEntryUpdate) E.Either[error,entities.TimeEntry]
|
Update(ctx context.Context) func(entry entities.TimeEntryUpdate) E.Either[error, entities.TimeEntry]
|
||||||
Delete(ctx context.Context, id string) E.Either[error,entities.TimeEntry]
|
Delete(ctx context.Context) func(id string) E.Either[error, entities.TimeEntry]
|
||||||
FindAll(ctx context.Context) E.Either[error,[]entities.TimeEntry]
|
FindAll(ctx context.Context) E.Either[error, []entities.TimeEntry]
|
||||||
}
|
}
|
||||||
|
@ -13,7 +13,6 @@ func handleDBError(err error, notFoundMessage string) error {
|
|||||||
return app_error.NewInternalError(err)
|
return app_error.NewInternalError(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
func NullableField[T any](getter func() (T, bool)) *T {
|
func NullableField[T any](getter func() (T, bool)) *T {
|
||||||
if value, ok := getter(); ok {
|
if value, ok := getter(); ok {
|
||||||
return &value
|
return &value
|
||||||
|
@ -38,7 +38,6 @@ func mapPrismaProjectToDomain(project db.ProjectDboModel) entities.Project {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
func mapPrismaProjectsToDomain(projects []db.ProjectDboModel) []entities.Project {
|
func mapPrismaProjectsToDomain(projects []db.ProjectDboModel) []entities.Project {
|
||||||
domainProjects := make([]entities.Project, len(projects))
|
domainProjects := make([]entities.Project, len(projects))
|
||||||
for i, project := range projects {
|
for i, project := range projects {
|
||||||
|
@ -62,5 +62,5 @@ func (db *PrismaDatabase) Projects() data.ProjectDataSource {
|
|||||||
// Close releases the Prisma client connection.
|
// Close releases the Prisma client connection.
|
||||||
func (db *PrismaDatabase) Close(ctx context.Context) error {
|
func (db *PrismaDatabase) Close(ctx context.Context) error {
|
||||||
log.Println("Closing database connection")
|
log.Println("Closing database connection")
|
||||||
return db.client.Disconnect();
|
return db.client.Disconnect()
|
||||||
}
|
}
|
||||||
|
@ -25,17 +25,16 @@ func (ds *PrismaProjectDataSource) Create(ctx context.Context, project entities.
|
|||||||
db.ProjectDbo.User.Link(
|
db.ProjectDbo.User.Link(
|
||||||
db.UserDbo.ID.Equals(project.UserID),
|
db.UserDbo.ID.Equals(project.UserID),
|
||||||
),
|
),
|
||||||
db.ProjectDbo.UserID.Set(project.UserID),
|
|
||||||
db.ProjectDbo.Description.SetIfPresent(project.Description),
|
db.ProjectDbo.Description.SetIfPresent(project.Description),
|
||||||
db.ProjectDbo.ClientID.SetIfPresent(project.ClientID),
|
db.ProjectDbo.ClientID.SetIfPresent(project.ClientID),
|
||||||
).Exec(ctx)
|
).Exec(ctx)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return E.Left[entities.Project,error](app_error.NewInternalError(err))
|
return E.Left[entities.Project, error](app_error.NewInternalError(err))
|
||||||
}
|
}
|
||||||
|
|
||||||
if createdProject == nil {
|
if createdProject == nil {
|
||||||
return E.Left[entities.Project,error](app_error.NewInternalError(fmt.Errorf("Could not create project")))
|
return E.Left[entities.Project, error](app_error.NewInternalError(fmt.Errorf("Could not create project")))
|
||||||
}
|
}
|
||||||
|
|
||||||
return E.Right[error](mapPrismaProjectToDomain(*createdProject))
|
return E.Right[error](mapPrismaProjectToDomain(*createdProject))
|
||||||
@ -52,7 +51,7 @@ func (ds *PrismaProjectDataSource) FindByID(ctx context.Context, id string) E.Ei
|
|||||||
}
|
}
|
||||||
|
|
||||||
if project == nil {
|
if project == nil {
|
||||||
return E.Left[entities.Project,error](app_error.NewNotFoundError(fmt.Sprintf("Project with ID %s not found", id)))
|
return E.Left[entities.Project, error](app_error.NewNotFoundError(fmt.Sprintf("Project with ID %s not found", id)))
|
||||||
}
|
}
|
||||||
|
|
||||||
return E.Right[error](mapPrismaProjectToDomain(*project))
|
return E.Right[error](mapPrismaProjectToDomain(*project))
|
||||||
@ -77,7 +76,7 @@ func (ds *PrismaProjectDataSource) Update(ctx context.Context, project entities.
|
|||||||
}
|
}
|
||||||
|
|
||||||
if updatedProject == nil {
|
if updatedProject == nil {
|
||||||
return E.Left[entities.Project,error](app_error.NewNotFoundError(fmt.Sprintf("Project with ID %s not found", project.ID)))
|
return E.Left[entities.Project, error](app_error.NewNotFoundError(fmt.Sprintf("Project with ID %s not found", project.ID)))
|
||||||
}
|
}
|
||||||
|
|
||||||
return E.Right[error](mapPrismaProjectToDomain(*updatedProject))
|
return E.Right[error](mapPrismaProjectToDomain(*updatedProject))
|
||||||
@ -94,7 +93,7 @@ func (ds *PrismaProjectDataSource) Delete(ctx context.Context, id string) E.Eith
|
|||||||
}
|
}
|
||||||
|
|
||||||
if deleted == nil {
|
if deleted == nil {
|
||||||
return E.Left[entities.Project,error](app_error.NewNotFoundError(fmt.Sprintf("Project with ID %s not found", id)))
|
return E.Left[entities.Project, error](app_error.NewNotFoundError(fmt.Sprintf("Project with ID %s not found", id)))
|
||||||
}
|
}
|
||||||
|
|
||||||
return E.Right[error](mapPrismaProjectToDomain(*deleted))
|
return E.Right[error](mapPrismaProjectToDomain(*deleted))
|
||||||
|
@ -29,11 +29,11 @@ func (ds *PrismaProjectTaskDataSource) Create(ctx context.Context, task entities
|
|||||||
).Exec(ctx)
|
).Exec(ctx)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return E.Left[entities.ProjectTask,error](handleDBError(err, fmt.Sprintf("Could not create project task")))
|
return E.Left[entities.ProjectTask, error](handleDBError(err, fmt.Sprintf("Could not create project task")))
|
||||||
}
|
}
|
||||||
|
|
||||||
if createdTask == nil {
|
if createdTask == nil {
|
||||||
return E.Left[entities.ProjectTask,error](app_error.NewInternalError(fmt.Errorf("Could not create project task")))
|
return E.Left[entities.ProjectTask, error](app_error.NewInternalError(fmt.Errorf("Could not create project task")))
|
||||||
}
|
}
|
||||||
|
|
||||||
return E.Right[error](mapPrismaProjectTaskToDomain(*createdTask))
|
return E.Right[error](mapPrismaProjectTaskToDomain(*createdTask))
|
||||||
@ -50,7 +50,7 @@ func (ds *PrismaProjectTaskDataSource) FindByID(ctx context.Context, id string)
|
|||||||
}
|
}
|
||||||
|
|
||||||
if task == nil {
|
if task == nil {
|
||||||
return E.Left[entities.ProjectTask,error](app_error.NewNotFoundError(fmt.Sprintf("ProjectTask with ID %s not found", id)))
|
return E.Left[entities.ProjectTask, error](app_error.NewNotFoundError(fmt.Sprintf("ProjectTask with ID %s not found", id)))
|
||||||
}
|
}
|
||||||
|
|
||||||
return E.Right[error](mapPrismaProjectTaskToDomain(*task))
|
return E.Right[error](mapPrismaProjectTaskToDomain(*task))
|
||||||
@ -73,7 +73,7 @@ func (ds *PrismaProjectTaskDataSource) Update(ctx context.Context, task entities
|
|||||||
}
|
}
|
||||||
|
|
||||||
if updatedTask == nil {
|
if updatedTask == nil {
|
||||||
return E.Left[entities.ProjectTask,error](app_error.NewNotFoundError(fmt.Sprintf("ProjectTask with ID %s not found", task.ID)))
|
return E.Left[entities.ProjectTask, error](app_error.NewNotFoundError(fmt.Sprintf("ProjectTask with ID %s not found", task.ID)))
|
||||||
}
|
}
|
||||||
|
|
||||||
return E.Right[error](mapPrismaProjectTaskToDomain(*updatedTask))
|
return E.Right[error](mapPrismaProjectTaskToDomain(*updatedTask))
|
||||||
@ -90,7 +90,7 @@ func (ds *PrismaProjectTaskDataSource) Delete(ctx context.Context, id string) E.
|
|||||||
}
|
}
|
||||||
|
|
||||||
if deletedTask == nil {
|
if deletedTask == nil {
|
||||||
return E.Left[entities.ProjectTask,error](app_error.NewNotFoundError(fmt.Sprintf("ProjectTask with ID %s not found", id)))
|
return E.Left[entities.ProjectTask, error](app_error.NewNotFoundError(fmt.Sprintf("ProjectTask with ID %s not found", id)))
|
||||||
}
|
}
|
||||||
|
|
||||||
return E.Right[error](mapPrismaProjectTaskToDomain(*deletedTask))
|
return E.Right[error](mapPrismaProjectTaskToDomain(*deletedTask))
|
||||||
|
@ -29,15 +29,14 @@ func (ds *PrismaTimeEntryDataSource) Create(ctx context.Context, entry entities.
|
|||||||
),
|
),
|
||||||
db.TimeEntryDbo.EndTime.SetIfPresent(entry.EndTime),
|
db.TimeEntryDbo.EndTime.SetIfPresent(entry.EndTime),
|
||||||
db.TimeEntryDbo.Description.SetIfPresent(entry.Description),
|
db.TimeEntryDbo.Description.SetIfPresent(entry.Description),
|
||||||
|
|
||||||
).Exec(ctx)
|
).Exec(ctx)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return E.Left[entities.TimeEntry,error](app_error.NewInternalError(err))
|
return E.Left[entities.TimeEntry, error](app_error.NewInternalError(err))
|
||||||
}
|
}
|
||||||
|
|
||||||
if createdEntry == nil {
|
if createdEntry == nil {
|
||||||
return E.Left[entities.TimeEntry,error](app_error.NewInternalError(fmt.Errorf("Could not create time entry")))
|
return E.Left[entities.TimeEntry, error](app_error.NewInternalError(fmt.Errorf("Could not create time entry")))
|
||||||
}
|
}
|
||||||
|
|
||||||
return E.Right[error](mapPrismaTimeEntryToDomain(*createdEntry))
|
return E.Right[error](mapPrismaTimeEntryToDomain(*createdEntry))
|
||||||
@ -54,7 +53,7 @@ func (ds *PrismaTimeEntryDataSource) FindByID(ctx context.Context, id string) E.
|
|||||||
}
|
}
|
||||||
|
|
||||||
if entry == nil {
|
if entry == nil {
|
||||||
return E.Left[entities.TimeEntry,error](app_error.NewNotFoundError(fmt.Sprintf("TimeEntry with ID %s not found", id)))
|
return E.Left[entities.TimeEntry, error](app_error.NewNotFoundError(fmt.Sprintf("TimeEntry with ID %s not found", id)))
|
||||||
}
|
}
|
||||||
|
|
||||||
return E.Right[error](mapPrismaTimeEntryToDomain(*entry))
|
return E.Right[error](mapPrismaTimeEntryToDomain(*entry))
|
||||||
@ -77,11 +76,11 @@ func (ds *PrismaTimeEntryDataSource) Update(ctx context.Context, entry entities.
|
|||||||
).Exec(ctx)
|
).Exec(ctx)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return E.Left[entities.TimeEntry,error](handleDBError(err, fmt.Sprintf("Could not update time entry with ID %s", entry.ID)))
|
return E.Left[entities.TimeEntry, error](handleDBError(err, fmt.Sprintf("Could not update time entry with ID %s", entry.ID)))
|
||||||
}
|
}
|
||||||
|
|
||||||
if updatedEntry == nil {
|
if updatedEntry == nil {
|
||||||
return E.Left[entities.TimeEntry,error](app_error.NewNotFoundError(fmt.Sprintf("TimeEntry with ID %s not found", entry.ID)))
|
return E.Left[entities.TimeEntry, error](app_error.NewNotFoundError(fmt.Sprintf("TimeEntry with ID %s not found", entry.ID)))
|
||||||
}
|
}
|
||||||
|
|
||||||
return E.Right[error](mapPrismaTimeEntryToDomain(*updatedEntry))
|
return E.Right[error](mapPrismaTimeEntryToDomain(*updatedEntry))
|
||||||
@ -98,7 +97,7 @@ func (ds *PrismaTimeEntryDataSource) Delete(ctx context.Context, id string) E.Ei
|
|||||||
}
|
}
|
||||||
|
|
||||||
if deletedEntry == nil {
|
if deletedEntry == nil {
|
||||||
return E.Left[entities.TimeEntry,error](app_error.NewNotFoundError(fmt.Sprintf("TimeEntry with ID %s not found", id)))
|
return E.Left[entities.TimeEntry, error](app_error.NewNotFoundError(fmt.Sprintf("TimeEntry with ID %s not found", id)))
|
||||||
}
|
}
|
||||||
|
|
||||||
return E.Right[error](mapPrismaTimeEntryToDomain(*deletedEntry))
|
return E.Right[error](mapPrismaTimeEntryToDomain(*deletedEntry))
|
||||||
@ -126,7 +125,6 @@ func (ds *PrismaTimeEntryDataSource) FindByUserID(ctx context.Context, userID st
|
|||||||
return E.Right[error](mapPrismaTimeEntriesToDomain(entries))
|
return E.Right[error](mapPrismaTimeEntriesToDomain(entries))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// FindByProjectID retrieves all TimeEntries by ProjectID
|
// FindByProjectID retrieves all TimeEntries by ProjectID
|
||||||
func (ds *PrismaTimeEntryDataSource) FindByProjectID(ctx context.Context, projectID string) E.Either[error, []entities.TimeEntry] {
|
func (ds *PrismaTimeEntryDataSource) FindByProjectID(ctx context.Context, projectID string) E.Either[error, []entities.TimeEntry] {
|
||||||
entries, err := ds.client.TimeEntryDbo.FindMany(
|
entries, err := ds.client.TimeEntryDbo.FindMany(
|
||||||
|
@ -18,7 +18,7 @@ func NewPrismaUserDataSource(client *db.PrismaClient) *PrismaUserDataSource {
|
|||||||
return &PrismaUserDataSource{client: client}
|
return &PrismaUserDataSource{client: client}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (ds *PrismaUserDataSource) Create(ctx context.Context, user entities.UserCreate) E.Either[error,entities.User] {
|
func (ds *PrismaUserDataSource) Create(ctx context.Context, user entities.UserCreate) E.Either[error, entities.User] {
|
||||||
createdUser, err := ds.client.UserDbo.CreateOne(
|
createdUser, err := ds.client.UserDbo.CreateOne(
|
||||||
db.UserDbo.Name.Set(user.Name),
|
db.UserDbo.Name.Set(user.Name),
|
||||||
db.UserDbo.Email.Set(user.Email),
|
db.UserDbo.Email.Set(user.Email),
|
||||||
@ -26,48 +26,48 @@ func (ds *PrismaUserDataSource) Create(ctx context.Context, user entities.UserCr
|
|||||||
).Exec(ctx)
|
).Exec(ctx)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return E.Left[entities.User,error](app_error.NewInternalError(err))
|
return E.Left[entities.User, error](app_error.NewInternalError(err))
|
||||||
}
|
}
|
||||||
if createdUser == nil {
|
if createdUser == nil {
|
||||||
return E.Left[entities.User,error](app_error.NewInternalError(fmt.Errorf("Could not create user")))
|
return E.Left[entities.User, error](app_error.NewInternalError(fmt.Errorf("Could not create user")))
|
||||||
}
|
}
|
||||||
return E.Right[error](mapPrismaUserToDomain(*createdUser))
|
return E.Right[error](mapPrismaUserToDomain(*createdUser))
|
||||||
}
|
}
|
||||||
|
|
||||||
func (ds *PrismaUserDataSource) FindByID(ctx context.Context, id string) E.Either[error,entities.User] {
|
func (ds *PrismaUserDataSource) FindByID(ctx context.Context, id string) E.Either[error, entities.User] {
|
||||||
user, err := ds.client.UserDbo.FindUnique(
|
user, err := ds.client.UserDbo.FindUnique(
|
||||||
db.UserDbo.ID.Equals(id),
|
db.UserDbo.ID.Equals(id),
|
||||||
).Exec(ctx)
|
).Exec(ctx)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return E.Left[entities.User,error](handleDBError(err, fmt.Sprintf("Query for user with ID %s failed", id)))
|
return E.Left[entities.User, error](handleDBError(err, fmt.Sprintf("Query for user with ID %s failed", id)))
|
||||||
}
|
}
|
||||||
|
|
||||||
if user == nil {
|
if user == nil {
|
||||||
return E.Left[entities.User,error](app_error.NewNotFoundError(fmt.Sprintf("User with ID %s not found", id)))
|
return E.Left[entities.User, error](app_error.NewNotFoundError(fmt.Sprintf("User with ID %s not found", id)))
|
||||||
}
|
}
|
||||||
|
|
||||||
return E.Right[error](mapPrismaUserToDomain(*user))
|
return E.Right[error](mapPrismaUserToDomain(*user))
|
||||||
}
|
}
|
||||||
|
|
||||||
func (ds *PrismaUserDataSource) FindByEmail(ctx context.Context, email string) E.Either[error,entities.User]{
|
func (ds *PrismaUserDataSource) FindByEmail(ctx context.Context, email string) E.Either[error, entities.User] {
|
||||||
user, err := ds.client.UserDbo.FindUnique(
|
user, err := ds.client.UserDbo.FindUnique(
|
||||||
db.UserDbo.Email.Equals(email),
|
db.UserDbo.Email.Equals(email),
|
||||||
).Exec(ctx)
|
).Exec(ctx)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return E.Left[entities.User,error](handleDBError(err, fmt.Sprintf("Query for user with email %s failed", email)))
|
return E.Left[entities.User, error](handleDBError(err, fmt.Sprintf("Query for user with email %s failed", email)))
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if user == nil {
|
if user == nil {
|
||||||
return E.Left[entities.User,error](app_error.NewNotFoundError(fmt.Sprintf("User with email %s not found", email)))
|
return E.Left[entities.User, error](app_error.NewNotFoundError(fmt.Sprintf("User with email %s not found", email)))
|
||||||
}
|
}
|
||||||
|
|
||||||
return E.Right[error](mapPrismaUserToDomain(*user))
|
return E.Right[error](mapPrismaUserToDomain(*user))
|
||||||
}
|
}
|
||||||
|
|
||||||
func (ds *PrismaUserDataSource) Update(ctx context.Context, user entities.UserUpdate) E.Either[error,entities.User] {
|
func (ds *PrismaUserDataSource) Update(ctx context.Context, user entities.UserUpdate) E.Either[error, entities.User] {
|
||||||
|
|
||||||
updatedUser, err := ds.client.UserDbo.FindUnique(
|
updatedUser, err := ds.client.UserDbo.FindUnique(
|
||||||
db.UserDbo.ID.Equals(user.ID),
|
db.UserDbo.ID.Equals(user.ID),
|
||||||
@ -78,37 +78,36 @@ func (ds *PrismaUserDataSource) Update(ctx context.Context, user entities.UserUp
|
|||||||
).Exec(ctx)
|
).Exec(ctx)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return E.Left[entities.User,error](handleDBError(err, fmt.Sprintf("Could not update user with ID %s", user.ID)))
|
return E.Left[entities.User, error](handleDBError(err, fmt.Sprintf("Could not update user with ID %s", user.ID)))
|
||||||
}
|
}
|
||||||
|
|
||||||
if updatedUser == nil {
|
if updatedUser == nil {
|
||||||
return E.Left[entities.User,error](app_error.NewNotFoundError(fmt.Sprintf("User with ID %s not found", user.ID)))
|
return E.Left[entities.User, error](app_error.NewNotFoundError(fmt.Sprintf("User with ID %s not found", user.ID)))
|
||||||
}
|
}
|
||||||
|
|
||||||
return E.Right[error](mapPrismaUserToDomain(*updatedUser))
|
return E.Right[error](mapPrismaUserToDomain(*updatedUser))
|
||||||
}
|
}
|
||||||
|
|
||||||
func (ds *PrismaUserDataSource) Delete(ctx context.Context, id string) E.Either[error,entities.User] {
|
func (ds *PrismaUserDataSource) Delete(ctx context.Context, id string) E.Either[error, entities.User] {
|
||||||
deleted, err := ds.client.UserDbo.FindUnique(
|
deleted, err := ds.client.UserDbo.FindUnique(
|
||||||
db.UserDbo.ID.Equals(id),
|
db.UserDbo.ID.Equals(id),
|
||||||
).Delete().Exec(ctx)
|
).Delete().Exec(ctx)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return E.Left[entities.User,error](handleDBError(err, fmt.Sprintf("Could not delete user with ID %s", id)))
|
return E.Left[entities.User, error](handleDBError(err, fmt.Sprintf("Could not delete user with ID %s", id)))
|
||||||
}
|
}
|
||||||
|
|
||||||
if deleted == nil {
|
if deleted == nil {
|
||||||
return E.Left[entities.User,error](app_error.NewNotFoundError(fmt.Sprintf("User with ID %s not found", id)))
|
return E.Left[entities.User, error](app_error.NewNotFoundError(fmt.Sprintf("User with ID %s not found", id)))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
return E.Right[error](mapPrismaUserToDomain(*deleted))
|
return E.Right[error](mapPrismaUserToDomain(*deleted))
|
||||||
}
|
}
|
||||||
|
|
||||||
func (ds *PrismaUserDataSource) FindAll(ctx context.Context) E.Either[error,[]entities.User] {
|
func (ds *PrismaUserDataSource) FindAll(ctx context.Context) E.Either[error, []entities.User] {
|
||||||
users, err := ds.client.UserDbo.FindMany().Exec(ctx)
|
users, err := ds.client.UserDbo.FindMany().Exec(ctx)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return E.Left[[]entities.User,error](handleDBError(err, "Could not retrieve users"))
|
return E.Left[[]entities.User, error](handleDBError(err, "Could not retrieve users"))
|
||||||
}
|
}
|
||||||
|
|
||||||
return E.Right[error](mapPrismaUsersToDomain(users))
|
return E.Right[error](mapPrismaUsersToDomain(users))
|
||||||
|
@ -1,32 +1,72 @@
|
|||||||
package http
|
package http
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"actatempus_backend/internal/application/services"
|
||||||
"actatempus_backend/internal/infrastructure/config"
|
"actatempus_backend/internal/infrastructure/config"
|
||||||
"fmt"
|
|
||||||
"net/http"
|
"net/http"
|
||||||
|
"strings"
|
||||||
|
|
||||||
"github.com/gin-gonic/gin"
|
"github.com/gin-gonic/gin"
|
||||||
)
|
)
|
||||||
|
|
||||||
type Server struct {
|
type Server struct {
|
||||||
cfg *config.Config
|
cfg *config.Config
|
||||||
|
userService *services.UserService
|
||||||
|
projectService *services.ProjectService
|
||||||
|
projectTaskService *services.ProjectTaskService
|
||||||
|
timeEntryService *services.TimeEntryService
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewServer(cfg *config.Config) *Server {
|
// NewServer initializes the Server with its dependencies.
|
||||||
return &Server{cfg: cfg}
|
func NewServer(
|
||||||
|
cfg *config.Config,
|
||||||
|
userService *services.UserService,
|
||||||
|
projectService *services.ProjectService,
|
||||||
|
projectTaskService *services.ProjectTaskService,
|
||||||
|
timeEntryService *services.TimeEntryService,
|
||||||
|
) *Server {
|
||||||
|
return &Server{
|
||||||
|
cfg: cfg,
|
||||||
|
userService: userService,
|
||||||
|
projectService: projectService,
|
||||||
|
projectTaskService: projectTaskService,
|
||||||
|
timeEntryService: timeEntryService,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *Server) Start() error {
|
func (s *Server) Start() error {
|
||||||
http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
|
|
||||||
fmt.Fprintln(w, "Welcome to ActaTempus!")
|
|
||||||
})
|
|
||||||
|
|
||||||
r := gin.Default()
|
r := gin.Default()
|
||||||
r.GET("/ping", func(c *gin.Context) {
|
r.GET("/", func(c *gin.Context) {
|
||||||
c.JSON(http.StatusOK, gin.H{
|
c.JSON(http.StatusOK, gin.H{
|
||||||
"message": "pong",
|
"message": "Welcome to ActaTempus!",
|
||||||
|
})
|
||||||
|
})
|
||||||
|
// Health Check
|
||||||
|
r.GET("/health", func(c *gin.Context) {
|
||||||
|
c.JSON(http.StatusOK, gin.H{
|
||||||
|
"message": "Server is running",
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
return r.Run()
|
// Register Service Routes
|
||||||
|
api := r.Group("/api")
|
||||||
|
{
|
||||||
|
userRouter := api.Group("/users")
|
||||||
|
s.userService.RegisterRoutes(userRouter)
|
||||||
|
|
||||||
|
projectRouter := api.Group("/projects")
|
||||||
|
s.projectService.RegisterRoutes(projectRouter)
|
||||||
|
|
||||||
|
projectTaskRouter := api.Group("/project-tasks")
|
||||||
|
s.projectTaskService.RegisterRoutes(projectTaskRouter)
|
||||||
|
|
||||||
|
timeEntryRouter := api.Group("/time-entries")
|
||||||
|
s.timeEntryService.RegisterRoutes(timeEntryRouter)
|
||||||
|
}
|
||||||
|
|
||||||
|
port := s.cfg.Port
|
||||||
|
if !strings.HasPrefix(port, ":") {
|
||||||
|
port = ":" + port // Add the colon if it's missing
|
||||||
|
}
|
||||||
|
return r.Run(port) // Start the server on the configured port
|
||||||
}
|
}
|
||||||
|
2
backend-go/run.sh
Normal file
2
backend-go/run.sh
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
#!/bin/sh
|
||||||
|
go run cmd/actatempus/main.go
|
Loading…
x
Reference in New Issue
Block a user