Files
maps-service/pkg/validator_controller/mapfixes.go
Rhys Lloyd a45fbb370c
All checks were successful
continuous-integration/drone/push Build is passing
submissions: rename services
2025-07-17 20:51:03 -07:00

330 lines
9.3 KiB
Go

package validator_controller
import (
"context"
"errors"
"fmt"
"git.itzana.me/strafesnet/maps-service/pkg/datastore"
internal "git.itzana.me/strafesnet/maps-service/pkg/internal"
"git.itzana.me/strafesnet/maps-service/pkg/model"
"git.itzana.me/strafesnet/maps-service/pkg/service"
)
var(
// prevent two mapfixes with same asset id
ActiveMapfixStatuses = []model.MapfixStatus{
model.MapfixStatusUploading,
model.MapfixStatusValidated,
model.MapfixStatusValidating,
model.MapfixStatusAcceptedUnvalidated,
model.MapfixStatusChangesRequested,
model.MapfixStatusSubmitted,
model.MapfixStatusUnderConstruction,
}
)
var(
ErrActiveMapfixSameAssetID = errors.New("There is an active mapfix with the same AssetID")
ErrNotAssetOwner = errors.New("You can only submit an asset you own")
)
// UpdateMapfixValidatedModel implements patchMapfixModel operation.
//
// Update model following role restrictions.
//
// POST /mapfixes/{MapfixID}/validated-model
func (svc *Controller) UpdateMapfixValidatedModel(ctx context.Context, params internal.UpdateMapfixValidatedModelParams) error {
ValidatedModelID := uint64(params.ValidatedModelID)
ValidatedModelVersion := uint64(params.ValidatedModelVersion)
// check if Status is ChangesRequested|Submitted|UnderConstruction
update := service.NewMapfixUpdate()
update.SetValidatedAssetID(ValidatedModelID)
update.SetValidatedAssetVersion(ValidatedModelVersion)
// DO NOT reset completed when validated model is updated
// update.Add("completed", false)
err := svc.inner.UpdateMapfixIfStatus(ctx, params.MapfixID, []model.MapfixStatus{model.MapfixStatusValidating}, update)
if err != nil {
return err
}
event_data := model.AuditEventDataChangeValidatedModel{
ValidatedModelID: ValidatedModelID,
ValidatedModelVersion: ValidatedModelVersion,
}
return svc.inner.CreateAuditEventChangeValidatedModel(
ctx,
ValidtorUserID,
model.Resource{
ID: params.MapfixID,
Type: model.ResourceMapfix,
},
event_data,
)
}
// ActionMapfixSubmitted invokes actionMapfixSubmitted operation.
//
// Role Validator changes status from Submitting -> Submitted.
//
// POST /mapfixes/{MapfixID}/status/validator-submitted
func (svc *Controller) ActionMapfixSubmitted(ctx context.Context, params internal.ActionMapfixSubmittedParams) error {
// transaction
target_status := model.MapfixStatusSubmitted
update := service.NewMapfixUpdate()
update.SetStatusID(target_status)
update.SetAssetVersion(uint64(params.ModelVersion))
update.SetDisplayName(params.DisplayName)
update.SetCreator(params.Creator)
update.SetGameID(uint32(params.GameID))
allow_statuses := []model.MapfixStatus{model.MapfixStatusSubmitting}
err := svc.inner.UpdateMapfixIfStatus(ctx, params.MapfixID, allow_statuses, update)
if err != nil {
return err
}
event_data := model.AuditEventDataAction{
TargetStatus: uint32(target_status),
}
return svc.inner.CreateAuditEventAction(
ctx,
ValidtorUserID,
model.Resource{
ID: params.MapfixID,
Type: model.ResourceMapfix,
},
event_data,
)
}
// ActionMapfixRequestChanges implements actionMapfixRequestChanges operation.
//
// (Internal endpoint) Role Validator changes status from Submitting -> RequestChanges.
//
// POST /mapfixes/{MapfixID}/status/validator-request-changes
func (svc *Controller) ActionMapfixRequestChanges(ctx context.Context, params internal.ActionMapfixRequestChangesParams) error {
// transaction
target_status := model.MapfixStatusChangesRequested
update := service.NewMapfixUpdate()
update.SetStatusID(target_status)
err := svc.inner.UpdateMapfixIfStatus(ctx, params.MapfixID, []model.MapfixStatus{model.MapfixStatusSubmitting}, update)
if err != nil {
return err
}
event_data := model.AuditEventDataAction{
TargetStatus: uint32(target_status),
}
return svc.inner.CreateAuditEventAction(
ctx,
ValidtorUserID,
model.Resource{
ID: params.MapfixID,
Type: model.ResourceMapfix,
},
event_data,
)
}
// ActionMapfixValidate invokes actionMapfixValidate operation.
//
// Role Validator changes status from Validating -> Validated.
//
// POST /mapfixes/{MapfixID}/status/validator-validated
func (svc *Controller) ActionMapfixValidated(ctx context.Context, params internal.ActionMapfixValidatedParams) error {
// transaction
update := service.NewMapfixUpdate()
update.SetStatusID(model.MapfixStatusValidated)
return svc.inner.UpdateMapfixIfStatus(ctx, params.MapfixID, []model.MapfixStatus{model.MapfixStatusValidating}, update)
}
// ActionMapfixAccepted implements actionMapfixAccepted operation.
//
// (Internal endpoint) Role Validator changes status from Validating -> Accepted.
//
// POST /mapfixes/{MapfixID}/status/validator-failed
func (svc *Controller) ActionMapfixAccepted(ctx context.Context, params internal.ActionMapfixAcceptedParams) error {
// transaction
target_status := model.MapfixStatusAcceptedUnvalidated
update := service.NewMapfixUpdate()
update.SetStatusID(target_status)
err := svc.inner.UpdateMapfixIfStatus(ctx, params.MapfixID, []model.MapfixStatus{model.MapfixStatusValidating}, update)
if err != nil {
return err
}
// push an action audit event
event_data := model.AuditEventDataAction{
TargetStatus: uint32(target_status),
}
return svc.inner.CreateAuditEventAction(
ctx,
ValidtorUserID,
model.Resource{
ID: params.MapfixID,
Type: model.ResourceMapfix,
},
event_data,
)
}
// ActionMapfixUploaded implements actionMapfixUploaded operation.
//
// (Internal endpoint) Role Validator changes status from Uploading -> Uploaded.
//
// POST /mapfixes/{MapfixID}/status/validator-uploaded
func (svc *Controller) ActionMapfixUploaded(ctx context.Context, params internal.ActionMapfixUploadedParams) error {
// transaction
target_status := model.MapfixStatusUploaded
update := service.NewMapfixUpdate()
update.SetStatusID(target_status)
err := svc.inner.UpdateMapfixIfStatus(ctx, params.MapfixID, []model.MapfixStatus{model.MapfixStatusUploading}, update)
if err != nil {
return err
}
event_data := model.AuditEventDataAction{
TargetStatus: uint32(target_status),
}
return svc.inner.CreateAuditEventAction(
ctx,
ValidtorUserID,
model.Resource{
ID: params.MapfixID,
Type: model.ResourceMapfix,
},
event_data,
)
}
// CreateMapfixAuditError implements createMapfixAuditError operation.
//
// Post an error to the audit log
//
// POST /mapfixes/{MapfixID}/error
func (svc *Controller) CreateMapfixAuditError(ctx context.Context, params internal.CreateMapfixAuditErrorParams) (error) {
event_data := model.AuditEventDataError{
Error: params.ErrorMessage,
}
return svc.inner.CreateAuditEventError(
ctx,
ValidtorUserID,
model.Resource{
ID: params.MapfixID,
Type: model.ResourceMapfix,
},
event_data,
)
}
// CreateMapfixAuditCheckList implements createMapfixAuditCheckList operation.
//
// Post a checklist to the audit log
//
// POST /mapfixes/{MapfixID}/checklist
func (svc *Controller) CreateMapfixAuditCheckList(ctx context.Context, check_list internal.CheckList, params internal.CreateMapfixAuditCheckListParams) (error) {
check_list2 := make([]model.Check, len(check_list))
for i, check := range check_list {
check_list2[i] = model.Check{
Name: check.Name,
Summary: check.Summary,
Passed: check.Passed,
}
}
event_data := model.AuditEventDataCheckList{
CheckList: check_list2,
}
return svc.inner.CreateAuditEventCheckList(
ctx,
ValidtorUserID,
model.Resource{
ID: params.MapfixID,
Type: model.ResourceMapfix,
},
event_data,
)
}
// POST /mapfixes
func (svc *Controller) CreateMapfix(ctx context.Context, request *internal.MapfixCreate) (*internal.MapfixID, error) {
// sanitization
if request.GameID<0||
request.AssetOwner<0||
request.AssetID<0||
request.AssetVersion<0||
request.TargetAssetID<0{
return nil, ErrNegativeID
}
var GameID=uint32(request.GameID);
var Submitter=uint64(request.AssetOwner);
var AssetID=uint64(request.AssetID);
var AssetVersion=uint64(request.AssetVersion);
var TargetAssetID=uint64(request.TargetAssetID);
// Check if an active mapfix with the same asset id exists
{
filter := service.NewMapfixFilter()
filter.SetAssetID(AssetID)
filter.SetAssetVersion(AssetVersion)
filter.SetStatuses(ActiveMapfixStatuses)
active_mapfixes, err := svc.inner.ListMapfixes(ctx, filter, model.Page{
Number: 1,
Size: 1,
},datastore.ListSortDisabled)
if err != nil {
return nil, err
}
if len(active_mapfixes) != 0{
return nil, ErrActiveMapfixSameAssetID
}
}
operation, err := svc.inner.GetOperation(ctx, request.OperationID)
if err != nil {
return nil, err
}
// check if user owns asset
// TODO: allow bypass by admin
if operation.Owner != Submitter {
return nil, ErrNotAssetOwner
}
mapfix, err := svc.inner.CreateMapfix(ctx, model.Mapfix{
ID: 0,
DisplayName: request.DisplayName,
Creator: request.Creator,
GameID: GameID,
Submitter: Submitter,
AssetID: AssetID,
AssetVersion: AssetVersion,
Completed: false,
TargetAssetID: TargetAssetID,
StatusID: model.MapfixStatusUnderConstruction,
Description: request.Description,
})
if err != nil {
return nil, err
}
// mark the operation as completed and provide the path
params := service.NewOperationCompleteParams(fmt.Sprintf("/mapfixes/%d", mapfix.ID))
err = svc.inner.CompleteOperation(ctx, request.OperationID, params)
if err != nil {
return nil, err
}
return &internal.MapfixID{
MapfixID: mapfix.ID,
}, nil
}