From 88c38666542c10d8971182311b68ebdec93076c1 Mon Sep 17 00:00:00 2001 From: Quaternions Date: Mon, 31 Mar 2025 14:39:06 -0700 Subject: [PATCH 01/18] Revert "submissions: add AcceptedBy, UploadedBy fields to model" This reverts commit 4c17a3c9e966c5af5c0da2001f0a59c39edac87d. --- pkg/model/submission.go | 4 ---- pkg/service/submissions.go | 13 ++----------- 2 files changed, 2 insertions(+), 15 deletions(-) diff --git a/pkg/model/submission.go b/pkg/model/submission.go index a01e1cd..11f1775 100644 --- a/pkg/model/submission.go +++ b/pkg/model/submission.go @@ -40,10 +40,6 @@ type Submission struct { CreatedAt time.Time UpdatedAt time.Time Submitter int64 // UserID - // Who clicked the Accept button - AcceptedBy int64 // UserID - // Who clicked the Upload button - UploadedBy int64 // UserID AssetID int64 AssetVersion int64 ValidatedAssetID int64 diff --git a/pkg/service/submissions.go b/pkg/service/submissions.go index 940d39f..94a76c1 100644 --- a/pkg/service/submissions.go +++ b/pkg/service/submissions.go @@ -396,16 +396,9 @@ func (svc *Service) ActionSubmissionTriggerUpload(ctx context.Context, params ap return ErrPermissionDeniedNeedRoleSubmissionUpload } - // track who is performing the upload action - userId, err := userInfo.GetUserID() - if err != nil { - return err - } - // transaction smap := datastore.Optional() smap.Add("status_id", model.StatusUploading) - smap.Add("uploaded_by", userId) submission, err := svc.DB.Submissions().IfStatusThenUpdateAndGet(ctx, params.SubmissionID, []model.Status{model.StatusValidated}, smap) if err != nil { return err @@ -510,13 +503,12 @@ func (svc *Service) ActionSubmissionTriggerValidate(ctx context.Context, params return err } - // track who is performing the accept action - userId, err := userInfo.GetUserID() + has_role, err = userInfo.IsSubmitter(uint64(submission.Submitter)) if err != nil { return err } // check if caller is NOT the submitter - if userId == uint64(submission.Submitter) { + if has_role { return ErrAcceptOwnSubmission } @@ -540,7 +532,6 @@ func (svc *Service) ActionSubmissionTriggerValidate(ctx context.Context, params // transaction smap := datastore.Optional() smap.Add("status_id", model.StatusValidating) - smap.Add("accepted_by", userId) submission, err = svc.DB.Submissions().IfStatusThenUpdateAndGet(ctx, params.SubmissionID, []model.Status{model.StatusSubmitted}, smap) if err != nil { return err -- 2.49.1 From dfc2a605f4b881bb52b112ecf8bd6df8cd5ad618 Mon Sep 17 00:00:00 2001 From: Quaternions Date: Mon, 31 Mar 2025 14:44:26 -0700 Subject: [PATCH 02/18] submissions: prepare for separate mapfixes --- pkg/datastore/datastore.go | 17 ++- pkg/datastore/gormstore/scripts.go | 2 +- pkg/datastore/gormstore/submissions.go | 18 +-- pkg/model/submission.go | 38 +++--- pkg/service/security.go | 26 ++-- pkg/service/service.go | 9 ++ pkg/service/submissions.go | 158 ++++++++++--------------- pkg/service_internal/submissions.go | 14 +-- 8 files changed, 129 insertions(+), 153 deletions(-) diff --git a/pkg/datastore/datastore.go b/pkg/datastore/datastore.go index eb7ca73..8a256b1 100644 --- a/pkg/datastore/datastore.go +++ b/pkg/datastore/datastore.go @@ -9,7 +9,16 @@ import ( var ( ErrNotExist = errors.New("resource does not exist") ErroNoRowsAffected = errors.New("query did not affect any rows") - ErrInvalidSubmissionListSort = errors.New("invalid submission list sort parameter [1,2,3,4]") + ErrInvalidListSort = errors.New("invalid list sort parameter [1,2,3,4]") +) + +type ListSort uint32 +const ( + ListSortDisabled ListSort = 0 + ListSortDisplayNameAscending ListSort = 1 + ListSortDisplayNameDescending ListSort = 2 + ListSortDateAscending ListSort = 3 + ListSortDateDescending ListSort = 4 ) type Datastore interface { @@ -23,10 +32,10 @@ type Submissions interface { GetList(ctx context.Context, id []int64) ([]model.Submission, error) Create(ctx context.Context, smap model.Submission) (model.Submission, error) Update(ctx context.Context, id int64, values OptionalMap) error - IfStatusThenUpdate(ctx context.Context, id int64, statuses []model.Status, values OptionalMap) error - IfStatusThenUpdateAndGet(ctx context.Context, id int64, statuses []model.Status, values OptionalMap) (model.Submission, error) + IfStatusThenUpdate(ctx context.Context, id int64, statuses []model.SubmissionStatus, values OptionalMap) error + IfStatusThenUpdateAndGet(ctx context.Context, id int64, statuses []model.SubmissionStatus, values OptionalMap) (model.Submission, error) Delete(ctx context.Context, id int64) error - List(ctx context.Context, filters OptionalMap, page model.Page, sort model.SubmissionListSort) ([]model.Submission, error) + List(ctx context.Context, filters OptionalMap, page model.Page, sort ListSort) ([]model.Submission, error) } type Scripts interface { diff --git a/pkg/datastore/gormstore/scripts.go b/pkg/datastore/gormstore/scripts.go index 1aa7f1f..600d107 100644 --- a/pkg/datastore/gormstore/scripts.go +++ b/pkg/datastore/gormstore/scripts.go @@ -53,7 +53,7 @@ func (env *Scripts) Update(ctx context.Context, id int64, values datastore.Optio } // the update can only occur if the status matches one of the provided values. -func (env *Scripts) IfStatusThenUpdate(ctx context.Context, id int64, statuses []model.Status, values datastore.OptionalMap) error { +func (env *Scripts) IfStatusThenUpdate(ctx context.Context, id int64, statuses []model.SubmissionStatus, values datastore.OptionalMap) error { if err := env.db.Model(&model.Script{}).Where("id = ?", id).Where("status IN ?", statuses).Updates(values.Map()).Error; err != nil { if err == gorm.ErrRecordNotFound { return datastore.ErrNotExist diff --git a/pkg/datastore/gormstore/submissions.go b/pkg/datastore/gormstore/submissions.go index b7073ab..dc384c6 100644 --- a/pkg/datastore/gormstore/submissions.go +++ b/pkg/datastore/gormstore/submissions.go @@ -54,7 +54,7 @@ func (env *Submissions) Update(ctx context.Context, id int64, values datastore.O } // the update can only occur if the status matches one of the provided values. -func (env *Submissions) IfStatusThenUpdate(ctx context.Context, id int64, statuses []model.Status, values datastore.OptionalMap) error { +func (env *Submissions) IfStatusThenUpdate(ctx context.Context, id int64, statuses []model.SubmissionStatus, values datastore.OptionalMap) error { if err := env.db.Model(&model.Submission{}).Where("id = ?", id).Where("status_id IN ?", statuses).Updates(values.Map()).Error; err != nil { if err == gorm.ErrRecordNotFound { return datastore.ErrNotExist @@ -67,7 +67,7 @@ func (env *Submissions) IfStatusThenUpdate(ctx context.Context, id int64, status // the update can only occur if the status matches one of the provided values. // returns the updated value -func (env *Submissions) IfStatusThenUpdateAndGet(ctx context.Context, id int64, statuses []model.Status, values datastore.OptionalMap) (model.Submission, error) { +func (env *Submissions) IfStatusThenUpdateAndGet(ctx context.Context, id int64, statuses []model.SubmissionStatus, values datastore.OptionalMap) (model.Submission, error) { var submission model.Submission result := env.db.Model(&submission). Clauses(clause.Returning{}). @@ -99,29 +99,29 @@ func (env *Submissions) Delete(ctx context.Context, id int64) error { return nil } -func (env *Submissions) List(ctx context.Context, filters datastore.OptionalMap, page model.Page, sort model.SubmissionListSort) ([]model.Submission, error) { +func (env *Submissions) List(ctx context.Context, filters datastore.OptionalMap, page model.Page, sort datastore.ListSort) ([]model.Submission, error) { var maps []model.Submission db := env.db switch sort { - case model.SubmissionListSortDisabled: + case datastore.ListSortDisabled: // No sort break - case model.SubmissionListSortDisplayNameAscending: + case datastore.ListSortDisplayNameAscending: db=db.Order("display_name ASC") break - case model.SubmissionListSortDisplayNameDescending: + case datastore.ListSortDisplayNameDescending: db=db.Order("display_name DESC") break - case model.SubmissionListSortDateAscending: + case datastore.ListSortDateAscending: db=db.Order("created_at ASC") break - case model.SubmissionListSortDateDescending: + case datastore.ListSortDateDescending: db=db.Order("created_at DESC") break default: - return nil, datastore.ErrInvalidSubmissionListSort + return nil, datastore.ErrInvalidListSort } if err := db.Where(filters.Map()).Offset(int((page.Number - 1) * page.Size)).Limit(int(page.Size)).Find(&maps).Error; err != nil { diff --git a/pkg/model/submission.go b/pkg/model/submission.go index 11f1775..aa2c708 100644 --- a/pkg/model/submission.go +++ b/pkg/model/submission.go @@ -2,34 +2,24 @@ package model import "time" -type Status int32 +type SubmissionStatus int32 const ( - // Phase: Final Status - StatusReleased Status = 9 - StatusRejected Status = 8 + // Phase: Final SubmissionStatus + SubmissionStatusReleased SubmissionStatus = 9 + SubmissionStatusRejected SubmissionStatus = 8 // Phase: Testing - StatusUploaded Status = 7 // uploaded to the group, but pending release - StatusUploading Status = 6 - StatusValidated Status = 5 - StatusValidating Status = 4 - StatusAccepted Status = 3 // pending script review, can re-trigger validation + SubmissionStatusUploaded SubmissionStatus = 7 // uploaded to the group, but pending release + SubmissionStatusUploading SubmissionStatus = 6 + SubmissionStatusValidated SubmissionStatus = 5 + SubmissionStatusValidating SubmissionStatus = 4 + SubmissionStatusAccepted SubmissionStatus = 3 // pending script review, can re-trigger validation // Phase: Creation - StatusChangesRequested Status = 2 - StatusSubmitted Status = 1 - StatusUnderConstruction Status = 0 -) - -type SubmissionListSort uint32 - -const ( - SubmissionListSortDisabled SubmissionListSort = 0 - SubmissionListSortDisplayNameAscending SubmissionListSort = 1 - SubmissionListSortDisplayNameDescending SubmissionListSort = 2 - SubmissionListSortDateAscending SubmissionListSort = 3 - SubmissionListSortDateDescending SubmissionListSort = 4 + SubmissionStatusChangesRequested SubmissionStatus = 2 + SubmissionStatusSubmitted SubmissionStatus = 1 + SubmissionStatusUnderConstruction SubmissionStatus = 0 ) type Submission struct { @@ -45,7 +35,7 @@ type Submission struct { ValidatedAssetID int64 ValidatedAssetVersion int64 Completed bool // Has this version of the map been completed at least once on maptest - TargetAssetID int64 // where to upload map fix. if the TargetAssetID is 0, it's a new map. - StatusID Status + UploadedAssetID int64 // where to upload map fix. if the TargetAssetID is 0, it's a new map. + StatusID SubmissionStatus StatusMessage string } diff --git a/pkg/service/security.go b/pkg/service/security.go index 9584672..8bc2efb 100644 --- a/pkg/service/security.go +++ b/pkg/service/security.go @@ -19,8 +19,8 @@ type Roles int32 var ( RolesSubmissionRelease Roles = 1<<4 RolesScriptWrite Roles = 1<<3 - RolesSubmissionUpload Roles = 1<<2 - RolesSubmissionReview Roles = 1<<1 + RolesMapUpload Roles = 1<<2 + RolesMapReview Roles = 1<<1 RolesMapDownload Roles = 1<<0 RolesEmpty Roles = 0 ) @@ -32,13 +32,13 @@ var ( RoleQuat GroupRole = 255 RoleItzaname GroupRole = 254 RoleStagingDeveloper GroupRole = 240 - RolesAll Roles = RolesScriptWrite|RolesSubmissionRelease|RolesSubmissionUpload|RolesSubmissionReview|RolesMapDownload + RolesAll Roles = RolesScriptWrite|RolesSubmissionRelease|RolesMapUpload|RolesMapReview|RolesMapDownload // has SubmissionUpload RoleMapAdmin GroupRole = 128 - RolesMapAdmin Roles = RolesSubmissionRelease|RolesSubmissionUpload|RolesSubmissionReview|RolesMapDownload + RolesMapAdmin Roles = RolesSubmissionRelease|RolesMapUpload|RolesMapReview|RolesMapDownload // has SubmissionReview RoleMapCouncil GroupRole = 64 - RolesMapCouncil Roles = RolesSubmissionReview|RolesSubmissionUpload|RolesMapDownload + RolesMapCouncil Roles = RolesMapReview|RolesMapUpload|RolesMapDownload // access to downloading maps RoleMapAccess GroupRole = 32 RolesMapAccess Roles = RolesMapDownload @@ -128,17 +128,23 @@ func (usr UserInfoHandle) GetRoles() (Roles, error) { } // RoleThumbnail +func (usr UserInfoHandle) HasRoleMapfixUpload() (bool, error) { + return usr.hasRoles(RolesMapUpload) +} +func (usr UserInfoHandle) HasRoleMapfixReview() (bool, error) { + return usr.hasRoles(RolesMapReview) +} +func (usr UserInfoHandle) HasRoleMapDownload() (bool, error) { + return usr.hasRoles(RolesMapDownload) +} func (usr UserInfoHandle) HasRoleSubmissionRelease() (bool, error) { return usr.hasRoles(RolesSubmissionRelease) } func (usr UserInfoHandle) HasRoleSubmissionUpload() (bool, error) { - return usr.hasRoles(RolesSubmissionUpload) + return usr.hasRoles(RolesMapUpload) } func (usr UserInfoHandle) HasRoleSubmissionReview() (bool, error) { - return usr.hasRoles(RolesSubmissionReview) -} -func (usr UserInfoHandle) HasRoleMapDownload() (bool, error) { - return usr.hasRoles(RolesMapDownload) + return usr.hasRoles(RolesMapReview) } func (usr UserInfoHandle) HasRoleScriptWrite() (bool, error) { return usr.hasRoles(RolesScriptWrite) diff --git a/pkg/service/service.go b/pkg/service/service.go index ac0c2f6..1815060 100644 --- a/pkg/service/service.go +++ b/pkg/service/service.go @@ -3,6 +3,7 @@ package service import ( "context" "errors" + "fmt" "git.itzana.me/strafesnet/go-grpc/maps" "git.itzana.me/strafesnet/maps-service/pkg/api" @@ -15,6 +16,14 @@ var ( ErrPermissionDenied = errors.New("Permission denied") // ErrUserInfo user info is missing for some reason ErrUserInfo = errors.New("Missing user info") + 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) + ErrPermissionDeniedNeedRoleSubmissionRelease = fmt.Errorf("%w: Need Role SubmissionRelease", ErrPermissionDenied) + ErrPermissionDeniedNeedRoleMapUpload = fmt.Errorf("%w: Need Role MapUpload", ErrPermissionDenied) + ErrPermissionDeniedNeedRoleMapReview = fmt.Errorf("%w: Need Role MapReview", 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) ) type Service struct { diff --git a/pkg/service/submissions.go b/pkg/service/submissions.go index 94a76c1..8583675 100644 --- a/pkg/service/submissions.go +++ b/pkg/service/submissions.go @@ -15,45 +15,37 @@ import ( var( CreationPhaseSubmissionsLimit = 20 - CreationPhaseSubmissionStatuses = []model.Status{ - model.StatusChangesRequested, - model.StatusSubmitted, - model.StatusUnderConstruction, + CreationPhaseSubmissionStatuses = []model.SubmissionStatus{ + model.SubmissionStatusChangesRequested, + model.SubmissionStatusSubmitted, + model.SubmissionStatusUnderConstruction, } // prevent two mapfixes with same asset id - ActiveSubmissionStatuses = []model.Status{ - model.StatusUploading, - model.StatusValidated, - model.StatusValidating, - model.StatusAccepted, - model.StatusChangesRequested, - model.StatusSubmitted, - model.StatusUnderConstruction, + ActiveSubmissionStatuses = []model.SubmissionStatus{ + model.SubmissionStatusUploading, + model.SubmissionStatusValidated, + model.SubmissionStatusValidating, + model.SubmissionStatusAccepted, + model.SubmissionStatusChangesRequested, + model.SubmissionStatusSubmitted, + model.SubmissionStatusUnderConstruction, } // limit mapfixes in the pipeline to one per target map - ActiveAcceptedSubmissionStatuses = []model.Status{ - model.StatusUploading, - model.StatusValidated, - model.StatusValidating, - model.StatusAccepted, + ActiveAcceptedSubmissionStatuses = []model.SubmissionStatus{ + model.SubmissionStatusUploading, + model.SubmissionStatusValidated, + model.SubmissionStatusValidating, + model.SubmissionStatusAccepted, } ) var ( ErrCreationPhaseSubmissionsLimit = errors.New("Active submissions limited to 20") ErrActiveSubmissionSameAssetID = errors.New("There is an active submission with the same AssetID") - ErrActiveSubmissionSameTargetAssetID = errors.New("There is an active submission with the same TargetAssetID") + ErrUploadedAssetIDAlreadyExists = errors.New("The submission UploadedAssetID is already set") ErrReleaseInvalidStatus = errors.New("Only submissions with Uploaded status can be released") - ErrReleaseNoTargetAssetID = errors.New("Only submissions with a TargetAssetID can be released") + ErrReleaseNoUploadedAssetID = errors.New("Only submissions with a UploadedAssetID 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) - ErrPermissionDeniedNeedRoleSubmissionRelease = fmt.Errorf("%w: Need Role SubmissionRelease", ErrPermissionDenied) - ErrPermissionDeniedNeedRoleSubmissionUpload = 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) - ErrPermissionDeniedNeedRoleMaptest = fmt.Errorf("%w: Need Role Maptest", ErrPermissionDenied) ) // POST /submissions @@ -76,7 +68,7 @@ func (svc *Service) CreateSubmission(ctx context.Context, request *api.Submissio creation_submissions, err := svc.DB.Submissions().List(ctx, filter, model.Page{ Number: 1, Size: int32(CreationPhaseSubmissionsLimit), - },model.SubmissionListSortDisabled) + },datastore.ListSortDisabled) if err != nil { return nil, err } @@ -95,7 +87,7 @@ func (svc *Service) CreateSubmission(ctx context.Context, request *api.Submissio active_submissions, err := svc.DB.Submissions().List(ctx, filter, model.Page{ Number: 1, Size: 1, - },model.SubmissionListSortDisabled) + },datastore.ListSortDisabled) if err != nil { return nil, err } @@ -113,8 +105,7 @@ func (svc *Service) CreateSubmission(ctx context.Context, request *api.Submissio AssetID: request.AssetID, AssetVersion: request.AssetVersion, Completed: false, - TargetAssetID: request.TargetAssetID.Value, - StatusID: model.StatusUnderConstruction, + StatusID: model.SubmissionStatusUnderConstruction, }) if err != nil { return nil, err @@ -145,7 +136,7 @@ func (svc *Service) GetSubmission(ctx context.Context, params api.GetSubmissionP AssetID: int64(submission.AssetID), AssetVersion: int64(submission.AssetVersion), Completed: submission.Completed, - TargetAssetID: api.NewOptInt64(int64(submission.TargetAssetID)), + UploadedAssetID: api.NewOptInt64(int64(submission.UploadedAssetID)), StatusID: int32(submission.StatusID), StatusMessage: submission.StatusMessage, }, nil @@ -169,7 +160,7 @@ func (svc *Service) ListSubmissions(ctx context.Context, params api.ListSubmissi filter.Add("game_id", params.GameID.Value) } - sort := model.SubmissionListSort(params.Sort.Or(int32(model.SubmissionListSortDisabled))) + sort := datastore.ListSort(params.Sort.Or(int32(datastore.ListSortDisabled))) items, err := svc.DB.Submissions().List(ctx, filter, model.Page{ Number: params.Page, @@ -192,7 +183,7 @@ func (svc *Service) ListSubmissions(ctx context.Context, params api.ListSubmissi AssetID: int64(item.AssetID), AssetVersion: int64(item.AssetVersion), Completed: item.Completed, - TargetAssetID: api.NewOptInt64(int64(item.TargetAssetID)), + UploadedAssetID: api.NewOptInt64(int64(item.UploadedAssetID)), StatusID: int32(item.StatusID), }) } @@ -257,7 +248,7 @@ func (svc *Service) UpdateSubmissionModel(ctx context.Context, params api.Update pmap.AddNotNil("asset_version", params.VersionID) //always reset completed when model changes pmap.Add("completed", false) - return svc.DB.Submissions().IfStatusThenUpdate(ctx, params.SubmissionID, []model.Status{model.StatusChangesRequested, model.StatusSubmitted, model.StatusUnderConstruction}, pmap) + return svc.DB.Submissions().IfStatusThenUpdate(ctx, params.SubmissionID, []model.SubmissionStatus{model.SubmissionStatusChangesRequested, model.SubmissionStatusSubmitted, model.SubmissionStatusUnderConstruction}, pmap) } // ActionSubmissionReject invokes actionSubmissionReject operation. @@ -277,13 +268,13 @@ func (svc *Service) ActionSubmissionReject(ctx context.Context, params api.Actio } // check if caller has required role if !has_role { - return ErrPermissionDeniedNeedRoleSubmissionReview + return ErrPermissionDeniedNeedRoleMapReview } // transaction smap := datastore.Optional() - smap.Add("status_id", model.StatusRejected) - return svc.DB.Submissions().IfStatusThenUpdate(ctx, params.SubmissionID, []model.Status{model.StatusSubmitted}, smap) + smap.Add("status_id", model.SubmissionStatusRejected) + return svc.DB.Submissions().IfStatusThenUpdate(ctx, params.SubmissionID, []model.SubmissionStatus{model.SubmissionStatusSubmitted}, smap) } // ActionSubmissionRequestChanges invokes actionSubmissionRequestChanges operation. @@ -303,13 +294,13 @@ func (svc *Service) ActionSubmissionRequestChanges(ctx context.Context, params a } // check if caller has required role if !has_role { - return ErrPermissionDeniedNeedRoleSubmissionReview + return ErrPermissionDeniedNeedRoleMapReview } // transaction smap := datastore.Optional() - smap.Add("status_id", model.StatusChangesRequested) - return svc.DB.Submissions().IfStatusThenUpdate(ctx, params.SubmissionID, []model.Status{model.StatusValidated, model.StatusAccepted, model.StatusSubmitted}, smap) + smap.Add("status_id", model.SubmissionStatusChangesRequested) + return svc.DB.Submissions().IfStatusThenUpdate(ctx, params.SubmissionID, []model.SubmissionStatus{model.SubmissionStatusValidated, model.SubmissionStatusAccepted, model.SubmissionStatusSubmitted}, smap) } // ActionSubmissionRevoke invokes actionSubmissionRevoke operation. @@ -340,8 +331,8 @@ func (svc *Service) ActionSubmissionRevoke(ctx context.Context, params api.Actio // transaction smap := datastore.Optional() - smap.Add("status_id", model.StatusUnderConstruction) - return svc.DB.Submissions().IfStatusThenUpdate(ctx, params.SubmissionID, []model.Status{model.StatusSubmitted, model.StatusChangesRequested}, smap) + smap.Add("status_id", model.SubmissionStatusUnderConstruction) + return svc.DB.Submissions().IfStatusThenUpdate(ctx, params.SubmissionID, []model.SubmissionStatus{model.SubmissionStatusSubmitted, model.SubmissionStatusChangesRequested}, smap) } // ActionSubmissionSubmit invokes actionSubmissionSubmit operation. @@ -372,8 +363,8 @@ func (svc *Service) ActionSubmissionSubmit(ctx context.Context, params api.Actio // transaction smap := datastore.Optional() - smap.Add("status_id", model.StatusSubmitted) - return svc.DB.Submissions().IfStatusThenUpdate(ctx, params.SubmissionID, []model.Status{model.StatusUnderConstruction, model.StatusChangesRequested}, smap) + smap.Add("status_id", model.SubmissionStatusSubmitted) + return svc.DB.Submissions().IfStatusThenUpdate(ctx, params.SubmissionID, []model.SubmissionStatus{model.SubmissionStatusUnderConstruction, model.SubmissionStatusChangesRequested}, smap) } // ActionSubmissionTriggerUpload invokes actionSubmissionTriggerUpload operation. @@ -393,19 +384,19 @@ func (svc *Service) ActionSubmissionTriggerUpload(ctx context.Context, params ap } // check if caller has required role if !has_role { - return ErrPermissionDeniedNeedRoleSubmissionUpload + return ErrPermissionDeniedNeedRoleMapUpload } // transaction smap := datastore.Optional() - smap.Add("status_id", model.StatusUploading) - submission, err := svc.DB.Submissions().IfStatusThenUpdateAndGet(ctx, params.SubmissionID, []model.Status{model.StatusValidated}, smap) + smap.Add("status_id", model.SubmissionStatusUploading) + submission, err := svc.DB.Submissions().IfStatusThenUpdateAndGet(ctx, params.SubmissionID, []model.SubmissionStatus{model.SubmissionStatusValidated}, smap) if err != nil { return err } // sentinel value because we are not using rust - if submission.TargetAssetID == 0 { + if submission.UploadedAssetID == 0 { // this is a new map upload_new_request := model.UploadNewRequest{ SubmissionID: submission.ID, @@ -422,20 +413,8 @@ func (svc *Service) ActionSubmissionTriggerUpload(ctx context.Context, params ap svc.Nats.Publish("maptest.submissions.uploadnew", []byte(j)) } else { - // this is a map fix - upload_fix_request := model.UploadFixRequest{ - SubmissionID: submission.ID, - ModelID: submission.ValidatedAssetID, - ModelVersion: submission.ValidatedAssetVersion, - TargetAssetID: submission.TargetAssetID, - } - - j, err := json.Marshal(upload_fix_request) - if err != nil { - return err - } - - svc.Nats.Publish("maptest.submissions.uploadfix", []byte(j)) + // refuse to operate + return ErrUploadedAssetIDAlreadyExists } return nil @@ -458,7 +437,7 @@ func (svc *Service) ActionSubmissionValidated(ctx context.Context, params api.Ac } // check if caller has required role if !has_role { - return ErrPermissionDeniedNeedRoleSubmissionUpload + return ErrPermissionDeniedNeedRoleMapUpload } // check when submission was updated @@ -473,8 +452,8 @@ func (svc *Service) ActionSubmissionValidated(ctx context.Context, params api.Ac // transaction smap := datastore.Optional() - smap.Add("status_id", model.StatusValidated) - return svc.DB.Submissions().IfStatusThenUpdate(ctx, params.SubmissionID, []model.Status{model.StatusUploading}, smap) + smap.Add("status_id", model.SubmissionStatusValidated) + return svc.DB.Submissions().IfStatusThenUpdate(ctx, params.SubmissionID, []model.SubmissionStatus{model.SubmissionStatusUploading}, smap) } // ActionSubmissionTriggerValidate invokes actionSubmissionTriggerValidate operation. @@ -494,7 +473,7 @@ func (svc *Service) ActionSubmissionTriggerValidate(ctx context.Context, params } // check if caller has required role if !has_role { - return ErrPermissionDeniedNeedRoleSubmissionReview + return ErrPermissionDeniedNeedRoleMapReview } // read submission (this could be done with a transaction WHERE clause) @@ -512,27 +491,10 @@ func (svc *Service) ActionSubmissionTriggerValidate(ctx context.Context, params return ErrAcceptOwnSubmission } - // Check if an active submission with the same target asset id exists - if submission.TargetAssetID != 0 { - filter := datastore.Optional() - filter.Add("target_asset_id", submission.TargetAssetID) - filter.Add("status_id", ActiveAcceptedSubmissionStatuses) - active_submissions, err := svc.DB.Submissions().List(ctx, filter, model.Page{ - Number: 1, - Size: 1, - },model.SubmissionListSortDisabled) - if err != nil { - return err - } - if len(active_submissions) != 0{ - return ErrActiveSubmissionSameTargetAssetID - } - } - // transaction smap := datastore.Optional() - smap.Add("status_id", model.StatusValidating) - submission, err = svc.DB.Submissions().IfStatusThenUpdateAndGet(ctx, params.SubmissionID, []model.Status{model.StatusSubmitted}, smap) + smap.Add("status_id", model.SubmissionStatusValidating) + submission, err = svc.DB.Submissions().IfStatusThenUpdateAndGet(ctx, params.SubmissionID, []model.SubmissionStatus{model.SubmissionStatusSubmitted}, smap) if err != nil { return err } @@ -576,13 +538,13 @@ func (svc *Service) ActionSubmissionRetryValidate(ctx context.Context, params ap } // check if caller has required role if !has_role { - return ErrPermissionDeniedNeedRoleSubmissionReview + return ErrPermissionDeniedNeedRoleMapReview } // transaction smap := datastore.Optional() - smap.Add("status_id", model.StatusValidating) - submission, err := svc.DB.Submissions().IfStatusThenUpdateAndGet(ctx, params.SubmissionID, []model.Status{model.StatusAccepted}, smap) + smap.Add("status_id", model.SubmissionStatusValidating) + submission, err := svc.DB.Submissions().IfStatusThenUpdateAndGet(ctx, params.SubmissionID, []model.SubmissionStatus{model.SubmissionStatusAccepted}, smap) if err != nil { return err } @@ -626,7 +588,7 @@ func (svc *Service) ActionSubmissionAccepted(ctx context.Context, params api.Act } // check if caller has required role if !has_role { - return ErrPermissionDeniedNeedRoleSubmissionReview + return ErrPermissionDeniedNeedRoleMapReview } // check when submission was updated @@ -641,9 +603,9 @@ func (svc *Service) ActionSubmissionAccepted(ctx context.Context, params api.Act // transaction smap := datastore.Optional() - smap.Add("status_id", model.StatusAccepted) + smap.Add("status_id", model.SubmissionStatusAccepted) smap.Add("status_message", "Manually forced reset") - return svc.DB.Submissions().IfStatusThenUpdate(ctx, params.SubmissionID, []model.Status{model.StatusValidating}, smap) + return svc.DB.Submissions().IfStatusThenUpdate(ctx, params.SubmissionID, []model.SubmissionStatus{model.SubmissionStatusValidating}, smap) } // ReleaseSubmissions invokes releaseSubmissions operation. @@ -679,11 +641,11 @@ func (svc *Service) ReleaseSubmissions(ctx context.Context, request []api.Releas // check each submission to make sure it is ready to release for _,submission := range submissions{ - if submission.StatusID != model.StatusUploaded{ + if submission.StatusID != model.SubmissionStatusUploaded{ return ErrReleaseInvalidStatus } - if submission.TargetAssetID == 0{ - return ErrReleaseNoTargetAssetID + if submission.UploadedAssetID == 0{ + return ErrReleaseNoUploadedAssetID } } @@ -691,7 +653,7 @@ func (svc *Service) ReleaseSubmissions(ctx context.Context, request []api.Releas date := request[i].Date.Unix() // create each map with go-grpc _, err := svc.Client.Create(ctx, &maps.MapRequest{ - ID: submission.TargetAssetID, + ID: submission.UploadedAssetID, DisplayName: &submission.DisplayName, Creator: &submission.Creator, GameID: &submission.GameID, @@ -703,8 +665,8 @@ func (svc *Service) ReleaseSubmissions(ctx context.Context, request []api.Releas // update each status to Released smap := datastore.Optional() - smap.Add("status_id", model.StatusReleased) - err = svc.DB.Submissions().IfStatusThenUpdate(ctx, submission.ID, []model.Status{model.StatusUploaded}, smap) + smap.Add("status_id", model.SubmissionStatusReleased) + err = svc.DB.Submissions().IfStatusThenUpdate(ctx, submission.ID, []model.SubmissionStatus{model.SubmissionStatusUploaded}, smap) if err != nil { return err } diff --git a/pkg/service_internal/submissions.go b/pkg/service_internal/submissions.go index 0d3a33a..93b6daf 100644 --- a/pkg/service_internal/submissions.go +++ b/pkg/service_internal/submissions.go @@ -20,7 +20,7 @@ func (svc *Service) UpdateSubmissionValidatedModel(ctx context.Context, params i pmap.AddNotNil("validated_asset_version", params.ValidatedModelVersion) // DO NOT reset completed when validated model is updated // pmap.Add("completed", false) - return svc.DB.Submissions().IfStatusThenUpdate(ctx, params.SubmissionID, []model.Status{model.StatusValidating}, pmap) + return svc.DB.Submissions().IfStatusThenUpdate(ctx, params.SubmissionID, []model.SubmissionStatus{model.SubmissionStatusValidating}, pmap) } // ActionSubmissionValidate invokes actionSubmissionValidate operation. @@ -33,8 +33,8 @@ func (svc *Service) ActionSubmissionValidated(ctx context.Context, params intern // transaction smap := datastore.Optional() - smap.Add("status_id", model.StatusValidated) - return svc.DB.Submissions().IfStatusThenUpdate(ctx, params.SubmissionID, []model.Status{model.StatusValidating}, smap) + smap.Add("status_id", model.SubmissionStatusValidated) + return svc.DB.Submissions().IfStatusThenUpdate(ctx, params.SubmissionID, []model.SubmissionStatus{model.SubmissionStatusValidating}, smap) } // ActionSubmissionAccepted implements actionSubmissionAccepted operation. @@ -47,9 +47,9 @@ func (svc *Service) ActionSubmissionAccepted(ctx context.Context, params interna // transaction smap := datastore.Optional() - smap.Add("status_id", model.StatusAccepted) + smap.Add("status_id", model.SubmissionStatusAccepted) smap.Add("status_message", params.StatusMessage) - return svc.DB.Submissions().IfStatusThenUpdate(ctx, params.SubmissionID, []model.Status{model.StatusValidating}, smap) + return svc.DB.Submissions().IfStatusThenUpdate(ctx, params.SubmissionID, []model.SubmissionStatus{model.SubmissionStatusValidating}, smap) } // ActionSubmissionUploaded implements actionSubmissionUploaded operation. @@ -62,9 +62,9 @@ func (svc *Service) ActionSubmissionUploaded(ctx context.Context, params interna // transaction smap := datastore.Optional() - smap.Add("status_id", model.StatusUploaded) + smap.Add("status_id", model.SubmissionStatusUploaded) if params.TargetAssetID.IsSet() { smap.AddNotNil("target_asset_id", params.TargetAssetID.Value) } - return svc.DB.Submissions().IfStatusThenUpdate(ctx, params.SubmissionID, []model.Status{model.StatusUploading}, smap) + return svc.DB.Submissions().IfStatusThenUpdate(ctx, params.SubmissionID, []model.SubmissionStatus{model.SubmissionStatusUploading}, smap) } -- 2.49.1 From 2d2691b5518223202f9a93b7aae59d1211d71841 Mon Sep 17 00:00:00 2001 From: Quaternions Date: Mon, 31 Mar 2025 15:23:07 -0700 Subject: [PATCH 03/18] openapi: tweak Submission fields --- openapi.yaml | 12 ++---------- 1 file changed, 2 insertions(+), 10 deletions(-) diff --git a/openapi.yaml b/openapi.yaml index 21e2748..b17a186 100644 --- a/openapi.yaml +++ b/openapi.yaml @@ -737,8 +737,7 @@ components: - AssetID - AssetVersion - Completed - - SubmissionType -# - TargetAssetID +# - UploadedAssetID - StatusID - StatusMessage type: object @@ -772,10 +771,7 @@ components: format: int64 Completed: type: boolean - SubmissionType: - type: integer - format: int32 - TargetAssetID: + UploadedAssetID: type: integer format: int64 StatusID: @@ -791,7 +787,6 @@ components: - GameID - AssetID - AssetVersion -# - TargetAssetID type: object properties: DisplayName: @@ -809,9 +804,6 @@ components: AssetVersion: type: integer format: int64 - TargetAssetID: - type: integer - format: int64 ReleaseInfo: required: - SubmissionID -- 2.49.1 From 9740cbe91a2e25caff62cf9dd7039b47ce0ba13b Mon Sep 17 00:00:00 2001 From: Quaternions Date: Mon, 31 Mar 2025 15:23:22 -0700 Subject: [PATCH 04/18] openapi: generate --- pkg/api/oas_json_gen.go | 64 ++++++++-------------------------- pkg/api/oas_schemas_gen.go | 70 +++++++++++++------------------------- 2 files changed, 39 insertions(+), 95 deletions(-) diff --git a/pkg/api/oas_json_gen.go b/pkg/api/oas_json_gen.go index ab1cd86..756801d 100644 --- a/pkg/api/oas_json_gen.go +++ b/pkg/api/oas_json_gen.go @@ -1451,13 +1451,9 @@ func (s *Submission) encodeFields(e *jx.Encoder) { e.Bool(s.Completed) } { - e.FieldStart("SubmissionType") - e.Int32(s.SubmissionType) - } - { - if s.TargetAssetID.Set { - e.FieldStart("TargetAssetID") - s.TargetAssetID.Encode(e) + if s.UploadedAssetID.Set { + e.FieldStart("UploadedAssetID") + s.UploadedAssetID.Encode(e) } } { @@ -1470,7 +1466,7 @@ func (s *Submission) encodeFields(e *jx.Encoder) { } } -var jsonFieldsNameOfSubmission = [14]string{ +var jsonFieldsNameOfSubmission = [13]string{ 0: "ID", 1: "DisplayName", 2: "Creator", @@ -1481,10 +1477,9 @@ var jsonFieldsNameOfSubmission = [14]string{ 7: "AssetID", 8: "AssetVersion", 9: "Completed", - 10: "SubmissionType", - 11: "TargetAssetID", - 12: "StatusID", - 13: "StatusMessage", + 10: "UploadedAssetID", + 11: "StatusID", + 12: "StatusMessage", } // Decode decodes Submission from json. @@ -1616,30 +1611,18 @@ func (s *Submission) Decode(d *jx.Decoder) error { }(); err != nil { return errors.Wrap(err, "decode field \"Completed\"") } - case "SubmissionType": - requiredBitSet[1] |= 1 << 2 + case "UploadedAssetID": if err := func() error { - v, err := d.Int32() - s.SubmissionType = int32(v) - if err != nil { + s.UploadedAssetID.Reset() + if err := s.UploadedAssetID.Decode(d); err != nil { return err } return nil }(); err != nil { - return errors.Wrap(err, "decode field \"SubmissionType\"") - } - case "TargetAssetID": - if err := func() error { - s.TargetAssetID.Reset() - if err := s.TargetAssetID.Decode(d); err != nil { - return err - } - return nil - }(); err != nil { - return errors.Wrap(err, "decode field \"TargetAssetID\"") + return errors.Wrap(err, "decode field \"UploadedAssetID\"") } case "StatusID": - requiredBitSet[1] |= 1 << 4 + requiredBitSet[1] |= 1 << 3 if err := func() error { v, err := d.Int32() s.StatusID = int32(v) @@ -1651,7 +1634,7 @@ func (s *Submission) Decode(d *jx.Decoder) error { return errors.Wrap(err, "decode field \"StatusID\"") } case "StatusMessage": - requiredBitSet[1] |= 1 << 5 + requiredBitSet[1] |= 1 << 4 if err := func() error { v, err := d.Str() s.StatusMessage = string(v) @@ -1673,7 +1656,7 @@ func (s *Submission) Decode(d *jx.Decoder) error { var failures []validate.FieldError for i, mask := range [2]uint8{ 0b11111111, - 0b00110111, + 0b00011011, } { if result := (requiredBitSet[i] & mask) ^ mask; result != 0 { // Mask only required fields and check equality to mask using XOR. @@ -1748,21 +1731,14 @@ func (s *SubmissionCreate) encodeFields(e *jx.Encoder) { e.FieldStart("AssetVersion") e.Int64(s.AssetVersion) } - { - if s.TargetAssetID.Set { - e.FieldStart("TargetAssetID") - s.TargetAssetID.Encode(e) - } - } } -var jsonFieldsNameOfSubmissionCreate = [6]string{ +var jsonFieldsNameOfSubmissionCreate = [5]string{ 0: "DisplayName", 1: "Creator", 2: "GameID", 3: "AssetID", 4: "AssetVersion", - 5: "TargetAssetID", } // Decode decodes SubmissionCreate from json. @@ -1834,16 +1810,6 @@ func (s *SubmissionCreate) Decode(d *jx.Decoder) error { }(); err != nil { return errors.Wrap(err, "decode field \"AssetVersion\"") } - case "TargetAssetID": - if err := func() error { - s.TargetAssetID.Reset() - if err := s.TargetAssetID.Decode(d); err != nil { - return err - } - return nil - }(); err != nil { - return errors.Wrap(err, "decode field \"TargetAssetID\"") - } default: return d.Skip() } diff --git a/pkg/api/oas_schemas_gen.go b/pkg/api/oas_schemas_gen.go index b463864..b779939 100644 --- a/pkg/api/oas_schemas_gen.go +++ b/pkg/api/oas_schemas_gen.go @@ -590,20 +590,19 @@ type SetSubmissionCompletedNoContent struct{} // Ref: #/components/schemas/Submission type Submission struct { - ID int64 `json:"ID"` - DisplayName string `json:"DisplayName"` - Creator string `json:"Creator"` - GameID int32 `json:"GameID"` - CreatedAt int64 `json:"CreatedAt"` - UpdatedAt int64 `json:"UpdatedAt"` - Submitter int64 `json:"Submitter"` - AssetID int64 `json:"AssetID"` - AssetVersion int64 `json:"AssetVersion"` - Completed bool `json:"Completed"` - SubmissionType int32 `json:"SubmissionType"` - TargetAssetID OptInt64 `json:"TargetAssetID"` - StatusID int32 `json:"StatusID"` - StatusMessage string `json:"StatusMessage"` + ID int64 `json:"ID"` + DisplayName string `json:"DisplayName"` + Creator string `json:"Creator"` + GameID int32 `json:"GameID"` + CreatedAt int64 `json:"CreatedAt"` + UpdatedAt int64 `json:"UpdatedAt"` + Submitter int64 `json:"Submitter"` + AssetID int64 `json:"AssetID"` + AssetVersion int64 `json:"AssetVersion"` + Completed bool `json:"Completed"` + UploadedAssetID OptInt64 `json:"UploadedAssetID"` + StatusID int32 `json:"StatusID"` + StatusMessage string `json:"StatusMessage"` } // GetID returns the value of ID. @@ -656,14 +655,9 @@ func (s *Submission) GetCompleted() bool { return s.Completed } -// GetSubmissionType returns the value of SubmissionType. -func (s *Submission) GetSubmissionType() int32 { - return s.SubmissionType -} - -// GetTargetAssetID returns the value of TargetAssetID. -func (s *Submission) GetTargetAssetID() OptInt64 { - return s.TargetAssetID +// GetUploadedAssetID returns the value of UploadedAssetID. +func (s *Submission) GetUploadedAssetID() OptInt64 { + return s.UploadedAssetID } // GetStatusID returns the value of StatusID. @@ -726,14 +720,9 @@ func (s *Submission) SetCompleted(val bool) { s.Completed = val } -// SetSubmissionType sets the value of SubmissionType. -func (s *Submission) SetSubmissionType(val int32) { - s.SubmissionType = val -} - -// SetTargetAssetID sets the value of TargetAssetID. -func (s *Submission) SetTargetAssetID(val OptInt64) { - s.TargetAssetID = val +// SetUploadedAssetID sets the value of UploadedAssetID. +func (s *Submission) SetUploadedAssetID(val OptInt64) { + s.UploadedAssetID = val } // SetStatusID sets the value of StatusID. @@ -748,12 +737,11 @@ func (s *Submission) SetStatusMessage(val string) { // Ref: #/components/schemas/SubmissionCreate type SubmissionCreate struct { - DisplayName string `json:"DisplayName"` - Creator string `json:"Creator"` - GameID int32 `json:"GameID"` - AssetID int64 `json:"AssetID"` - AssetVersion int64 `json:"AssetVersion"` - TargetAssetID OptInt64 `json:"TargetAssetID"` + DisplayName string `json:"DisplayName"` + Creator string `json:"Creator"` + GameID int32 `json:"GameID"` + AssetID int64 `json:"AssetID"` + AssetVersion int64 `json:"AssetVersion"` } // GetDisplayName returns the value of DisplayName. @@ -781,11 +769,6 @@ func (s *SubmissionCreate) GetAssetVersion() int64 { return s.AssetVersion } -// GetTargetAssetID returns the value of TargetAssetID. -func (s *SubmissionCreate) GetTargetAssetID() OptInt64 { - return s.TargetAssetID -} - // SetDisplayName sets the value of DisplayName. func (s *SubmissionCreate) SetDisplayName(val string) { s.DisplayName = val @@ -811,11 +794,6 @@ func (s *SubmissionCreate) SetAssetVersion(val int64) { s.AssetVersion = val } -// SetTargetAssetID sets the value of TargetAssetID. -func (s *SubmissionCreate) SetTargetAssetID(val OptInt64) { - s.TargetAssetID = val -} - // UpdateScriptNoContent is response for UpdateScript operation. type UpdateScriptNoContent struct{} -- 2.49.1 From 0e29ca98dd7fa0a8135351c962db46800b88fa5f Mon Sep 17 00:00:00 2001 From: Quaternions Date: Mon, 31 Mar 2025 15:36:58 -0700 Subject: [PATCH 05/18] web: remove TargetAssetID --- web/src/app/submit/page.tsx | 14 +------------- 1 file changed, 1 insertion(+), 13 deletions(-) diff --git a/web/src/app/submit/page.tsx b/web/src/app/submit/page.tsx index 6f3c1b7..38cc9e3 100644 --- a/web/src/app/submit/page.tsx +++ b/web/src/app/submit/page.tsx @@ -1,6 +1,6 @@ "use client" -import { FormControl, FormControlLabel, Button, TextField, Checkbox } from "@mui/material" +import { Button, TextField } from "@mui/material" import GameSelection from "./_game"; import SendIcon from '@mui/icons-material/Send'; @@ -15,7 +15,6 @@ interface SubmissionPayload { GameID: number; AssetID: number; AssetVersion: number; - TargetAssetID: number; } interface IdResponse { ID: number; @@ -23,7 +22,6 @@ interface IdResponse { export default function SubmissionInfoPage() { const [game, setGame] = useState(1); - const [isFixingMap, setIsFixingMap] = useState(false); const handleSubmit = async (event: React.FormEvent) => { event.preventDefault(); @@ -37,7 +35,6 @@ export default function SubmissionInfoPage() { GameID: game, AssetID: Number((formData.get("asset-id") as string) ?? "0"), AssetVersion: 0, - TargetAssetID: isFixingMap ? Number((formData.get("target-asset-id") as string) ?? "0") : 0, }; console.log(payload) @@ -84,15 +81,6 @@ export default function SubmissionInfoPage() { {/* I think this is Quat's job to figure this one out (to be set when someone clicks review(?)) */} {/* */} - - setIsFixingMap(e.target.checked)} />} label="Fixing an Existing Map?" /> - -