Files
History_Api/internal/services/commitService.go
AzenKain 6918a100fc
All checks were successful
Build and Release / release (push) Successful in 1m15s
Module project, commit, submission
2026-04-26 16:31:03 +07:00

169 lines
5.0 KiB
Go

package services
import (
"context"
"history-api/internal/dtos/request"
"history-api/internal/dtos/response"
"history-api/internal/gen/sqlc"
"history-api/internal/models"
"history-api/internal/repositories"
"history-api/pkg/constants"
"history-api/pkg/convert"
"github.com/gofiber/fiber/v3"
"github.com/jackc/pgx/v5/pgtype"
"github.com/jackc/pgx/v5/pgxpool"
)
type CommitService interface {
CreateCommit(ctx context.Context, userID string, projectID string, dto *request.CreateCommitDto) (*response.CommitResponse, error)
RestoreCommit(ctx context.Context, userID string, projectID string, dto *request.RestoreCommitDto) error
GetProjectCommits(ctx context.Context, projectID string) ([]*response.CommitResponse, error)
}
type commitService struct {
db *pgxpool.Pool
commitRepo repositories.CommitRepository
projectRepo repositories.ProjectRepository
}
func NewCommitService(
db *pgxpool.Pool,
commitRepo repositories.CommitRepository,
projectRepo repositories.ProjectRepository,
) CommitService {
return &commitService{
db: db,
commitRepo: commitRepo,
projectRepo: projectRepo,
}
}
func (s *commitService) checkWritePermission(ctx context.Context, userID string, projectUUID pgtype.UUID) error {
project, err := s.projectRepo.GetByID(ctx, projectUUID)
if err != nil {
return fiber.NewError(fiber.StatusNotFound, "Project not found")
}
if project.UserID == userID {
return nil
}
userUUID, _ := convert.StringToUUID(userID)
roleVal, err := s.projectRepo.CheckPermission(ctx, sqlc.CheckProjectPermissionParams{
ProjectID: projectUUID,
UserID: userUUID,
})
if err != nil {
return fiber.NewError(fiber.StatusForbidden, "You do not have permission to write to this project")
}
role := constants.ParseProjectMemberRole(roleVal)
if !role.CanWrite() {
return fiber.NewError(fiber.StatusForbidden, "You do not have permission to write to this project")
}
return nil
}
func (s *commitService) CreateCommit(ctx context.Context, userID string, projectID string, dto *request.CreateCommitDto) (*response.CommitResponse, error) {
tx, err := s.db.Begin(ctx)
if err != nil {
return nil, fiber.NewError(fiber.StatusInternalServerError, "Failed to start transaction")
}
defer tx.Rollback(ctx)
cRepoTx := s.commitRepo.WithTx(tx)
pRepoTx := s.projectRepo.WithTx(tx)
projectUUID, err := convert.StringToUUID(projectID)
if err != nil {
return nil, fiber.NewError(fiber.StatusBadRequest, "Invalid project ID")
}
if err := s.checkWritePermission(ctx, userID, projectUUID); err != nil {
return nil, err
}
userUUID, err := convert.StringToUUID(userID)
if err != nil {
return nil, fiber.NewError(fiber.StatusBadRequest, "Invalid user ID")
}
commit, err := cRepoTx.Create(ctx, sqlc.CreateCommitParams{
ProjectID: projectUUID,
SnapshotJson: dto.SnapshotJson,
UserID: userUUID,
EditSummary: convert.StringToText(dto.EditSummary),
})
if err != nil {
return nil, fiber.NewError(fiber.StatusInternalServerError, "Failed to create commit")
}
commitUUID, err := convert.StringToUUID(commit.ID)
if err != nil {
return nil, fiber.NewError(fiber.StatusBadRequest, "Invalid commit ID")
}
err = pRepoTx.UpdateLatestCommit(ctx, sqlc.UpdateLatestCommitParams{
ID: projectUUID,
LatestCommitID: commitUUID,
})
if err != nil {
return nil, fiber.NewError(fiber.StatusInternalServerError, "Failed to update project latest commit")
}
if err := tx.Commit(ctx); err != nil {
return nil, fiber.NewError(fiber.StatusInternalServerError, "Failed to commit transaction")
}
return commit.ToResponse(), nil
}
func (s *commitService) RestoreCommit(ctx context.Context, userID string, projectID string, dto *request.RestoreCommitDto) error {
projectUUID, err := convert.StringToUUID(projectID)
if err != nil {
return fiber.NewError(fiber.StatusBadRequest, "Invalid project ID")
}
if err := s.checkWritePermission(ctx, userID, projectUUID); err != nil {
return err
}
commitUUID, err := convert.StringToUUID(dto.CommitID)
if err != nil {
return fiber.NewError(fiber.StatusBadRequest, "Invalid commit ID")
}
commit, err := s.commitRepo.GetByID(ctx, commitUUID)
if err != nil {
return fiber.NewError(fiber.StatusNotFound, "Commit not found")
}
if commit.ProjectID != projectID {
return fiber.NewError(fiber.StatusBadRequest, "Commit does not belong to this project")
}
err = s.projectRepo.UpdateLatestCommit(ctx, sqlc.UpdateLatestCommitParams{
ID: projectUUID,
LatestCommitID: commitUUID,
})
if err != nil {
return fiber.NewError(fiber.StatusInternalServerError, "Failed to restore commit")
}
return nil
}
func (s *commitService) GetProjectCommits(ctx context.Context, projectID string) ([]*response.CommitResponse, error) {
projectUUID, err := convert.StringToUUID(projectID)
if err != nil {
return nil, fiber.NewError(fiber.StatusBadRequest, "Invalid project ID")
}
commits, err := s.commitRepo.GetByProjectID(ctx, projectUUID)
if err != nil {
return nil, fiber.NewError(fiber.StatusInternalServerError, "Failed to fetch commits")
}
return models.CommitsEntityToResponse(commits), nil
}