From 7d57d1ac4da80793979d075834e889d5d35bc7bf Mon Sep 17 00:00:00 2001
From: Quaternions <krakow20@gmail.com>
Date: Wed, 26 Mar 2025 11:56:57 -0700
Subject: [PATCH 1/4] submissions: improve error granularity

---
 pkg/service/submissions.go | 37 +++++++++++++++++++++++--------------
 1 file changed, 23 insertions(+), 14 deletions(-)

diff --git a/pkg/service/submissions.go b/pkg/service/submissions.go
index 2280acf..35ceffd 100644
--- a/pkg/service/submissions.go
+++ b/pkg/service/submissions.go
@@ -4,6 +4,7 @@ import (
 	"context"
 	"encoding/json"
 	"errors"
+	"fmt"
 	"time"
 
 	"git.itzana.me/strafesnet/go-grpc/maps"
@@ -37,6 +38,14 @@ var (
 	ErrActiveSubmissionSameTargetAssetID = errors.New("There is an active submission with the same TargetAssetID")
 	ErrReleaseInvalidStatus = errors.New("Only submissions with Uploaded status can be released")
 	ErrReleaseNoTargetAssetID = errors.New("Only submissions with a TargetAssetID can be released")
+	ErrAcceptOwnSubmission = fmt.Errorf("%w: You cannot accept your own submission as the submitter", ErrPermissionDenied)
+	ErrDelayReset = errors.New("Please give the validator at least 10 seconds to operate before attempting to reset the status")
+	ErrPermissionDeniedNotSubmitter = fmt.Errorf("%w: You must be the submitter to perform this action", ErrPermissionDenied)
+	ErrPermissionDeniedNeedSubmissionPublish = fmt.Errorf("%w: Need Role SubmissionPublish", ErrPermissionDenied)
+	ErrPermissionDeniedNeedRoleSubmissionReview = fmt.Errorf("%w: Need Role SubmissionReview", ErrPermissionDenied)
+	ErrPermissionDeniedNeedRoleMapDownload = fmt.Errorf("%w: Need Role MapDownload", ErrPermissionDenied)
+	ErrPermissionDeniedNeedRoleScriptWrite = fmt.Errorf("%w: Need Role ScriptWrite", ErrPermissionDenied)
+	ErrPermissionDeniedNeedRoleMaptest = fmt.Errorf("%w: Need Role Maptest", ErrPermissionDenied)
 )
 
 // POST /submissions
@@ -216,7 +225,7 @@ func (svc *Service) SetSubmissionCompleted(ctx context.Context, params api.SetSu
 	}
 	// check if caller has MaptestGame role (request must originate from a maptest roblox game)
 	if !has_role {
-		return ErrPermissionDenied
+		return ErrPermissionDeniedNeedRoleMaptest
 	}
 
 	pmap := datastore.Optional()
@@ -247,7 +256,7 @@ func (svc *Service) UpdateSubmissionModel(ctx context.Context, params api.Update
 	}
 	// check if caller is the submitter
 	if !has_role {
-		return ErrPermissionDenied
+		return ErrPermissionDeniedNotSubmitter
 	}
 
 	// check if Status is ChangesRequested|Submitted|UnderConstruction
@@ -276,7 +285,7 @@ func (svc *Service) ActionSubmissionReject(ctx context.Context, params api.Actio
 	}
 	// check if caller has required role
 	if !has_role {
-		return ErrPermissionDenied
+		return ErrPermissionDeniedNeedRoleSubmissionReview
 	}
 
 	// transaction
@@ -302,7 +311,7 @@ func (svc *Service) ActionSubmissionRequestChanges(ctx context.Context, params a
 	}
 	// check if caller has required role
 	if !has_role {
-		return ErrPermissionDenied
+		return ErrPermissionDeniedNeedRoleSubmissionReview
 	}
 
 	// transaction
@@ -334,7 +343,7 @@ func (svc *Service) ActionSubmissionRevoke(ctx context.Context, params api.Actio
 	}
 	// check if caller is the submitter
 	if !has_role {
-		return ErrPermissionDenied
+		return ErrPermissionDeniedNotSubmitter
 	}
 
 	// transaction
@@ -366,7 +375,7 @@ func (svc *Service) ActionSubmissionSubmit(ctx context.Context, params api.Actio
 	}
 	// check if caller is the submitter
 	if !has_role {
-		return ErrPermissionDenied
+		return ErrPermissionDeniedNotSubmitter
 	}
 
 	// transaction
@@ -392,7 +401,7 @@ func (svc *Service) ActionSubmissionTriggerUpload(ctx context.Context, params ap
 	}
 	// check if caller has required role
 	if !has_role {
-		return ErrPermissionDenied
+		return ErrPermissionDeniedNeedSubmissionPublish
 	}
 
 	// transaction
@@ -457,7 +466,7 @@ func (svc *Service) ActionSubmissionValidated(ctx context.Context, params api.Ac
 	}
 	// check if caller has required role
 	if !has_role {
-		return ErrPermissionDenied
+		return ErrPermissionDeniedNeedSubmissionPublish
 	}
 
 	// check when submission was updated
@@ -467,7 +476,7 @@ func (svc *Service) ActionSubmissionValidated(ctx context.Context, params api.Ac
 	}
 	if time.Now().Before(submission.UpdatedAt.Add(time.Second*10)) {
 		// the last time the submission was updated must be longer than 10 seconds ago
-		return ErrPermissionDenied
+		return ErrDelayReset
 	}
 
 	// transaction
@@ -493,7 +502,7 @@ func (svc *Service) ActionSubmissionTriggerValidate(ctx context.Context, params
 	}
 	// check if caller has required role
 	if !has_role {
-		return ErrPermissionDenied
+		return ErrPermissionDeniedNeedRoleSubmissionReview
 	}
 
 	// read submission (this could be done with a transaction WHERE clause)
@@ -508,7 +517,7 @@ func (svc *Service) ActionSubmissionTriggerValidate(ctx context.Context, params
 	}
 	// check if caller is NOT the submitter
 	if has_role {
-		return ErrPermissionDenied
+		return ErrAcceptOwnSubmission
 	}
 
 	// transaction
@@ -553,7 +562,7 @@ func (svc *Service) ActionSubmissionAccepted(ctx context.Context, params api.Act
 	}
 	// check if caller has required role
 	if !has_role {
-		return ErrPermissionDenied
+		return ErrPermissionDeniedNeedRoleSubmissionReview
 	}
 
 	// check when submission was updated
@@ -563,7 +572,7 @@ func (svc *Service) ActionSubmissionAccepted(ctx context.Context, params api.Act
 	}
 	if time.Now().Before(submission.UpdatedAt.Add(time.Second*10)) {
 		// the last time the submission was updated must be longer than 10 seconds ago
-		return ErrPermissionDenied
+		return ErrDelayReset
 	}
 
 	// transaction
@@ -590,7 +599,7 @@ func (svc *Service) ReleaseSubmissions(ctx context.Context, request []api.Releas
 	}
 	// check if caller has required role
 	if !has_role {
-		return ErrPermissionDenied
+		return ErrPermissionDeniedNeedSubmissionPublish
 	}
 
 	idList := make([]int64, len(request))
-- 
2.47.1


From 87fd7adb93e2159c1eb37f8a925330ad6272fdd2 Mon Sep 17 00:00:00 2001
From: Quaternions <krakow20@gmail.com>
Date: Wed, 26 Mar 2025 11:59:42 -0700
Subject: [PATCH 2/4] submissions: rename SubmissionPublish to SubmissionUpload

---
 pkg/service/security.go    | 12 ++++++------
 pkg/service/submissions.go | 14 +++++++-------
 2 files changed, 13 insertions(+), 13 deletions(-)

diff --git a/pkg/service/security.go b/pkg/service/security.go
index 6f6ac58..e128908 100644
--- a/pkg/service/security.go
+++ b/pkg/service/security.go
@@ -18,7 +18,7 @@ var (
 type Roles int32
 var (
 	RolesScriptWrite Roles = 8
-	RolesSubmissionPublish Roles = 4
+	RolesSubmissionUpload Roles = 4
 	RolesSubmissionReview Roles = 2
 	RolesMapDownload Roles = 1
 	RolesEmpty Roles = 0
@@ -31,10 +31,10 @@ var (
 	RoleQuat GroupRole = 255
 	RoleItzaname GroupRole = 254
 	RoleStagingDeveloper GroupRole = 240
-	RolesAll Roles = RolesScriptWrite|RolesSubmissionPublish|RolesSubmissionReview|RolesMapDownload
-	// has SubmissionPublish
+	RolesAll Roles = RolesScriptWrite|RolesSubmissionUpload|RolesSubmissionReview|RolesMapDownload
+	// has SubmissionUpload
 	RoleMapAdmin GroupRole = 128
-	RolesMapAdmin Roles = RolesSubmissionPublish|RolesSubmissionReview|RolesMapDownload
+	RolesMapAdmin Roles = RolesSubmissionUpload|RolesSubmissionReview|RolesMapDownload
 	// has SubmissionReview
 	RoleMapCouncil GroupRole = 64
 	RolesMapCouncil Roles = RolesSubmissionReview|RolesMapDownload
@@ -128,8 +128,8 @@ func (usr UserInfoHandle) GetRoles() (Roles, error) {
 
 // RoleThumbnail
 // RoleMapDownload
-func (usr UserInfoHandle) HasRoleSubmissionPublish() (bool, error) {
-	return usr.hasRoles(RolesSubmissionPublish)
+func (usr UserInfoHandle) HasRoleSubmissionUpload() (bool, error) {
+	return usr.hasRoles(RolesSubmissionUpload)
 }
 func (usr UserInfoHandle) HasRoleSubmissionReview() (bool, error) {
 	return usr.hasRoles(RolesSubmissionReview)
diff --git a/pkg/service/submissions.go b/pkg/service/submissions.go
index 35ceffd..db76f40 100644
--- a/pkg/service/submissions.go
+++ b/pkg/service/submissions.go
@@ -41,7 +41,7 @@ var (
 	ErrAcceptOwnSubmission = fmt.Errorf("%w: You cannot accept your own submission as the submitter", ErrPermissionDenied)
 	ErrDelayReset = errors.New("Please give the validator at least 10 seconds to operate before attempting to reset the status")
 	ErrPermissionDeniedNotSubmitter = fmt.Errorf("%w: You must be the submitter to perform this action", ErrPermissionDenied)
-	ErrPermissionDeniedNeedSubmissionPublish = fmt.Errorf("%w: Need Role SubmissionPublish", ErrPermissionDenied)
+	ErrPermissionDeniedNeedSubmissionUpload = fmt.Errorf("%w: Need Role SubmissionUpload", ErrPermissionDenied)
 	ErrPermissionDeniedNeedRoleSubmissionReview = fmt.Errorf("%w: Need Role SubmissionReview", ErrPermissionDenied)
 	ErrPermissionDeniedNeedRoleMapDownload = fmt.Errorf("%w: Need Role MapDownload", ErrPermissionDenied)
 	ErrPermissionDeniedNeedRoleScriptWrite = fmt.Errorf("%w: Need Role ScriptWrite", ErrPermissionDenied)
@@ -395,13 +395,13 @@ func (svc *Service) ActionSubmissionTriggerUpload(ctx context.Context, params ap
 		return ErrUserInfo
 	}
 
-	has_role, err := userInfo.HasRoleSubmissionPublish()
+	has_role, err := userInfo.HasRoleSubmissionUpload()
 	if err != nil {
 		return err
 	}
 	// check if caller has required role
 	if !has_role {
-		return ErrPermissionDeniedNeedSubmissionPublish
+		return ErrPermissionDeniedNeedSubmissionUpload
 	}
 
 	// transaction
@@ -460,13 +460,13 @@ func (svc *Service) ActionSubmissionValidated(ctx context.Context, params api.Ac
 		return ErrUserInfo
 	}
 
-	has_role, err := userInfo.HasRoleSubmissionPublish()
+	has_role, err := userInfo.HasRoleSubmissionUpload()
 	if err != nil {
 		return err
 	}
 	// check if caller has required role
 	if !has_role {
-		return ErrPermissionDeniedNeedSubmissionPublish
+		return ErrPermissionDeniedNeedSubmissionUpload
 	}
 
 	// check when submission was updated
@@ -593,13 +593,13 @@ func (svc *Service) ReleaseSubmissions(ctx context.Context, request []api.Releas
 		return ErrUserInfo
 	}
 
-	has_role, err := userInfo.HasRoleSubmissionPublish()
+	has_role, err := userInfo.HasRoleSubmissionUpload()
 	if err != nil {
 		return err
 	}
 	// check if caller has required role
 	if !has_role {
-		return ErrPermissionDeniedNeedSubmissionPublish
+		return ErrPermissionDeniedNeedSubmissionUpload
 	}
 
 	idList := make([]int64, len(request))
-- 
2.47.1


From 539e09fe063180a4e487ab779acfb335e4ebca00 Mon Sep 17 00:00:00 2001
From: Quaternions <krakow20@gmail.com>
Date: Wed, 26 Mar 2025 12:00:20 -0700
Subject: [PATCH 3/4] validator: correct enum item name

---
 validation/src/publish_new.rs | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/validation/src/publish_new.rs b/validation/src/publish_new.rs
index 6ef91bc..fc6ad5e 100644
--- a/validation/src/publish_new.rs
+++ b/validation/src/publish_new.rs
@@ -7,7 +7,7 @@ pub enum PublishError{
 	Json(serde_json::Error),
 	Create(rbx_asset::cookie::CreateError),
 	SystemTime(std::time::SystemTimeError),
-	ApiActionSubmissionPublish(submissions_api::Error),
+	ApiActionSubmissionUploaded(submissions_api::Error),
 }
 impl std::fmt::Display for PublishError{
 	fn fmt(&self,f:&mut std::fmt::Formatter<'_>)->std::fmt::Result{
@@ -53,7 +53,7 @@ impl Publisher{
 		self.api.action_submission_uploaded(submissions_api::types::ActionSubmissionUploadedRequest{
 			SubmissionID:publish_info.SubmissionID,
 			TargetAssetID:Some(upload_response.AssetId),
-		}).await.map_err(PublishError::ApiActionSubmissionPublish)?;
+		}).await.map_err(PublishError::ApiActionSubmissionUploaded)?;
 
 		Ok(())
 	}
-- 
2.47.1


From a8dc6cd35aa1647a88aa2c09679f0c2e128db355 Mon Sep 17 00:00:00 2001
From: Quaternions <krakow20@gmail.com>
Date: Wed, 26 Mar 2025 12:06:49 -0700
Subject: [PATCH 4/4] submissions: introduce new role SubmissionRelease

---
 pkg/service/security.go    | 17 ++++++++++-------
 pkg/service/submissions.go |  5 +++--
 2 files changed, 13 insertions(+), 9 deletions(-)

diff --git a/pkg/service/security.go b/pkg/service/security.go
index e128908..7c8ffe3 100644
--- a/pkg/service/security.go
+++ b/pkg/service/security.go
@@ -17,10 +17,11 @@ var (
 // Submissions roles bitflag
 type Roles int32
 var (
-	RolesScriptWrite Roles = 8
-	RolesSubmissionUpload Roles = 4
-	RolesSubmissionReview Roles = 2
-	RolesMapDownload Roles = 1
+	RolesSubmissionRelease Roles = 1<<4
+	RolesScriptWrite Roles = 1<<3
+	RolesSubmissionUpload Roles = 1<<2
+	RolesSubmissionReview Roles = 1<<1
+	RolesMapDownload Roles = 1<<0
 	RolesEmpty Roles = 0
 )
 
@@ -31,10 +32,10 @@ var (
 	RoleQuat GroupRole = 255
 	RoleItzaname GroupRole = 254
 	RoleStagingDeveloper GroupRole = 240
-	RolesAll Roles = RolesScriptWrite|RolesSubmissionUpload|RolesSubmissionReview|RolesMapDownload
+	RolesAll Roles = RolesScriptWrite|RolesSubmissionRelease|RolesSubmissionUpload|RolesSubmissionReview|RolesMapDownload
 	// has SubmissionUpload
 	RoleMapAdmin GroupRole = 128
-	RolesMapAdmin Roles = RolesSubmissionUpload|RolesSubmissionReview|RolesMapDownload
+	RolesMapAdmin Roles = RolesSubmissionRelease|RolesSubmissionUpload|RolesSubmissionReview|RolesMapDownload
 	// has SubmissionReview
 	RoleMapCouncil GroupRole = 64
 	RolesMapCouncil Roles = RolesSubmissionReview|RolesMapDownload
@@ -127,7 +128,9 @@ func (usr UserInfoHandle) GetRoles() (Roles, error) {
 }
 
 // RoleThumbnail
-// RoleMapDownload
+func (usr UserInfoHandle) HasRoleSubmissionRelease() (bool, error) {
+	return usr.hasRoles(RolesSubmissionRelease)
+}
 func (usr UserInfoHandle) HasRoleSubmissionUpload() (bool, error) {
 	return usr.hasRoles(RolesSubmissionUpload)
 }
diff --git a/pkg/service/submissions.go b/pkg/service/submissions.go
index db76f40..baa1308 100644
--- a/pkg/service/submissions.go
+++ b/pkg/service/submissions.go
@@ -41,6 +41,7 @@ var (
 	ErrAcceptOwnSubmission = fmt.Errorf("%w: You cannot accept your own submission as the submitter", ErrPermissionDenied)
 	ErrDelayReset = errors.New("Please give the validator at least 10 seconds to operate before attempting to reset the status")
 	ErrPermissionDeniedNotSubmitter = fmt.Errorf("%w: You must be the submitter to perform this action", ErrPermissionDenied)
+	ErrPermissionDeniedNeedSubmissionRelease = fmt.Errorf("%w: Need Role SubmissionRelease", ErrPermissionDenied)
 	ErrPermissionDeniedNeedSubmissionUpload = fmt.Errorf("%w: Need Role SubmissionUpload", ErrPermissionDenied)
 	ErrPermissionDeniedNeedRoleSubmissionReview = fmt.Errorf("%w: Need Role SubmissionReview", ErrPermissionDenied)
 	ErrPermissionDeniedNeedRoleMapDownload = fmt.Errorf("%w: Need Role MapDownload", ErrPermissionDenied)
@@ -593,13 +594,13 @@ func (svc *Service) ReleaseSubmissions(ctx context.Context, request []api.Releas
 		return ErrUserInfo
 	}
 
-	has_role, err := userInfo.HasRoleSubmissionUpload()
+	has_role, err := userInfo.HasRoleSubmissionRelease()
 	if err != nil {
 		return err
 	}
 	// check if caller has required role
 	if !has_role {
-		return ErrPermissionDeniedNeedSubmissionUpload
+		return ErrPermissionDeniedNeedSubmissionRelease
 	}
 
 	idList := make([]int64, len(request))
-- 
2.47.1