From 2125c458efb0ef06d4c284832a5542b0cd356e46 Mon Sep 17 00:00:00 2001
From: Quaternions <krakow20@gmail.com>
Date: Fri, 27 Dec 2024 19:10:48 -0800
Subject: [PATCH] submissions: reject duplicate submissions

closes #6
---
 pkg/service/submissions.go | 84 ++++++++++++++++++++++++++++++++------
 1 file changed, 72 insertions(+), 12 deletions(-)

diff --git a/pkg/service/submissions.go b/pkg/service/submissions.go
index 10be8cf..6239499 100644
--- a/pkg/service/submissions.go
+++ b/pkg/service/submissions.go
@@ -3,6 +3,7 @@ package service
 import (
 	"context"
 	"encoding/json"
+	"errors"
 
 	"git.itzana.me/strafesnet/maps-service/pkg/api"
 	"git.itzana.me/strafesnet/maps-service/pkg/datastore"
@@ -10,7 +11,28 @@ import (
 )
 
 var(
-	ActiveSubmissionsLimit = 20
+	CreationPhaseSubmissionsLimit = 20
+	CreationPhaseSubmissionStatuses = []model.Status{
+		model.StatusChangesRequested,
+		model.StatusSubmitted,
+		model.StatusUnderConstruction,
+	}
+	ActiveSubmissionStatuses = []model.Status{
+		model.StatusUploaded,
+		model.StatusUploading,
+		model.StatusValidated,
+		model.StatusValidating,
+		model.StatusAccepted,
+		model.StatusChangesRequested,
+		model.StatusSubmitted,
+		model.StatusUnderConstruction,
+	}
+)
+
+var (
+	ErrCreationPhaseSubmissionsLimit = errors.New("Active submissions limited to 20")
+	ErrSubmissionSameAssetID = errors.New("There is an active submission with the same AssetID")
+	ErrActiveSubmissionSameTargetAssetID = errors.New("There is a submission with the same TargetAssetID")
 )
 
 // POST /submissions
@@ -25,19 +47,57 @@ func (svc *Service) CreateSubmission(ctx context.Context, request *api.Submissio
 		return nil, err
 	}
 
-	filter := datastore.Optional()
-	filter.Add("submitter", int64(userId))
-	filter.Add("status_id", []model.Status{model.StatusChangesRequested, model.StatusSubmitted, model.StatusUnderConstruction})
-	active_submissions, err := svc.DB.Submissions().List(ctx, filter, model.Page{
-		Number: 1,
-		Size:   int32(ActiveSubmissionsLimit),
-	})
-	if err != nil {
-		return nil, err
+	// Check if user's submissions in the creation phase exceeds the limit
+	{
+		filter := datastore.Optional()
+		filter.Add("submitter", int64(userId))
+		filter.Add("status_id", CreationPhaseSubmissionStatuses)
+		creation_submissions, err := svc.DB.Submissions().List(ctx, filter, model.Page{
+			Number: 1,
+			Size:   int32(CreationPhaseSubmissionsLimit),
+		})
+		if err != nil {
+			return nil, err
+		}
+
+		if CreationPhaseSubmissionsLimit <= len(creation_submissions) {
+			return nil, ErrCreationPhaseSubmissionsLimit
+		}
 	}
 
-	if ActiveSubmissionsLimit <= len(active_submissions) {
-		return nil, ErrPermissionDenied
+	// Check if an active submission with the same asset id exists
+	{
+		filter := datastore.Optional()
+		filter.Add("asset_id", request.AssetID)
+		filter.Add("asset_version", request.AssetVersion)
+		filter.Add("status_id", ActiveSubmissionStatuses)
+		active_submissions, err := svc.DB.Submissions().List(ctx, filter, model.Page{
+			Number: 1,
+			Size:   1,
+		})
+		if err != nil {
+			return nil, err
+		}
+		if len(active_submissions) != 0{
+			return nil, ErrSubmissionSameAssetID
+		}
+	}
+
+	// Check if an active submission with the same target asset id exists
+	if request.TargetAssetID.IsSet() && request.TargetAssetID.Value != 0{
+		filter := datastore.Optional()
+		filter.Add("target_asset_id", request.TargetAssetID.Value)
+		filter.Add("status_id", ActiveSubmissionStatuses)
+		active_submissions, err := svc.DB.Submissions().List(ctx, filter, model.Page{
+			Number: 1,
+			Size:   1,
+		})
+		if err != nil {
+			return nil, err
+		}
+		if len(active_submissions) != 0{
+			return nil, ErrActiveSubmissionSameTargetAssetID
+		}
 	}
 
 	submission, err := svc.DB.Submissions().Create(ctx, model.Submission{