package validator_controller import ( "context" "errors" "fmt" "git.itzana.me/strafesnet/go-grpc/validator" "git.itzana.me/strafesnet/maps-service/pkg/datastore" "git.itzana.me/strafesnet/maps-service/pkg/model" "git.itzana.me/strafesnet/maps-service/pkg/service" ) type Mapfixes struct { *validator.UnimplementedValidatorMapfixServiceServer inner *service.Service } func NewMapfixesController( inner *service.Service, ) Mapfixes { return Mapfixes{ inner: inner, } } var( // prevent two mapfixes with same asset id ActiveMapfixStatuses = []model.MapfixStatus{ model.MapfixStatusReleasing, model.MapfixStatusUploaded, 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 *Mapfixes) SetValidatedModel(ctx context.Context, params *validator.ValidatedModelRequest) (*validator.NullResponse, error) { MapfixID := int64(params.ID) // check if Status is ChangesRequested|Submitted|UnderConstruction update := service.NewMapfixUpdate() update.SetValidatedAssetID(params.ValidatedModelID) update.SetValidatedAssetVersion(params.ValidatedModelVersion) // DO NOT reset completed when validated model is updated // update.Add("completed", false) allow_statuses := []model.MapfixStatus{model.MapfixStatusValidating} err := svc.inner.UpdateMapfixIfStatus(ctx, MapfixID, allow_statuses, update) if err != nil { return nil, err } event_data := model.AuditEventDataChangeValidatedModel{ ValidatedModelID: params.ValidatedModelID, ValidatedModelVersion: params.ValidatedModelVersion, } err = svc.inner.CreateAuditEventChangeValidatedModel( ctx, model.ValidatorUserID, model.Resource{ ID: MapfixID, Type: model.ResourceMapfix, }, event_data, ) if err != nil { return nil, err } return &validator.NullResponse{}, nil } // ActionMapfixSubmitted invokes actionMapfixSubmitted operation. // // Role Validator changes status from Submitting -> Submitted. // // POST /mapfixes/{MapfixID}/status/validator-submitted func (svc *Mapfixes) SetStatusSubmitted(ctx context.Context, params *validator.SubmittedRequest) (*validator.NullResponse, error) { MapfixID := int64(params.ID) // 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, MapfixID, allow_statuses, update) if err != nil { return nil, err } event_data := model.AuditEventDataAction{ TargetStatus: uint32(target_status), } err = svc.inner.CreateAuditEventAction( ctx, model.ValidatorUserID, model.Resource{ ID: MapfixID, Type: model.ResourceMapfix, }, event_data, ) if err != nil { return nil, err } return &validator.NullResponse{}, nil } // ActionMapfixRequestChanges implements actionMapfixRequestChanges operation. // // (Internal endpoint) Role Validator changes status from Submitting -> RequestChanges. // // POST /mapfixes/{MapfixID}/status/validator-request-changes func (svc *Mapfixes) SetStatusRequestChanges(ctx context.Context, params *validator.MapfixID) (*validator.NullResponse, error) { MapfixID := int64(params.ID) // transaction target_status := model.MapfixStatusChangesRequested update := service.NewMapfixUpdate() update.SetStatusID(target_status) allow_statuses := []model.MapfixStatus{model.MapfixStatusSubmitting} err := svc.inner.UpdateMapfixIfStatus(ctx, MapfixID, allow_statuses, update) if err != nil { return nil, err } event_data := model.AuditEventDataAction{ TargetStatus: uint32(target_status), } err = svc.inner.CreateAuditEventAction( ctx, model.ValidatorUserID, model.Resource{ ID: MapfixID, Type: model.ResourceMapfix, }, event_data, ) if err != nil { return nil, err } return &validator.NullResponse{}, nil } // ActionMapfixValidate invokes actionMapfixValidate operation. // // Role Validator changes status from Validating -> Validated. // // POST /mapfixes/{MapfixID}/status/validator-validated func (svc *Mapfixes) SetStatusValidated(ctx context.Context, params *validator.MapfixID) (*validator.NullResponse, error) { MapfixID := int64(params.ID) // transaction update := service.NewMapfixUpdate() update.SetStatusID(model.MapfixStatusValidated) allow_statuses := []model.MapfixStatus{model.MapfixStatusValidating} err := svc.inner.UpdateMapfixIfStatus(ctx, MapfixID, allow_statuses, update) if err != nil { return nil, err } return &validator.NullResponse{}, nil } // ActionMapfixAccepted implements actionMapfixAccepted operation. // // (Internal endpoint) Role Validator changes status from Validating -> Accepted. // // POST /mapfixes/{MapfixID}/status/validator-failed func (svc *Mapfixes) SetStatusNotValidated(ctx context.Context, params *validator.MapfixID) (*validator.NullResponse, error) { MapfixID := int64(params.ID) // transaction target_status := model.MapfixStatusAcceptedUnvalidated update := service.NewMapfixUpdate() update.SetStatusID(target_status) allow_statuses := []model.MapfixStatus{model.MapfixStatusValidating} err := svc.inner.UpdateMapfixIfStatus(ctx, MapfixID, allow_statuses, update) if err != nil { return nil, err } // push an action audit event event_data := model.AuditEventDataAction{ TargetStatus: uint32(target_status), } err = svc.inner.CreateAuditEventAction( ctx, model.ValidatorUserID, model.Resource{ ID: MapfixID, Type: model.ResourceMapfix, }, event_data, ) if err != nil { return nil, err } return &validator.NullResponse{}, nil } // ActionMapfixUploaded implements actionMapfixUploaded operation. // // (Internal endpoint) Role Validator changes status from Uploading -> Uploaded. // // POST /mapfixes/{MapfixID}/status/validator-uploaded func (svc *Mapfixes) SetStatusUploaded(ctx context.Context, params *validator.MapfixID) (*validator.NullResponse, error) { MapfixID := int64(params.ID) // transaction target_status := model.MapfixStatusUploaded update := service.NewMapfixUpdate() update.SetStatusID(target_status) allow_statuses := []model.MapfixStatus{model.MapfixStatusUploading} err := svc.inner.UpdateMapfixIfStatus(ctx, MapfixID, allow_statuses, update) if err != nil { return nil, err } event_data := model.AuditEventDataAction{ TargetStatus: uint32(target_status), } err = svc.inner.CreateAuditEventAction( ctx, model.ValidatorUserID, model.Resource{ ID: MapfixID, Type: model.ResourceMapfix, }, event_data, ) if err != nil { return nil, err } return &validator.NullResponse{}, nil } func (svc *Mapfixes) SetStatusNotUploaded(ctx context.Context, params *validator.MapfixID) (*validator.NullResponse, error) { MapfixID := int64(params.ID) // transaction target_status := model.MapfixStatusValidated update := service.NewMapfixUpdate() update.SetStatusID(target_status) allow_statuses := []model.MapfixStatus{model.MapfixStatusUploading} err := svc.inner.UpdateMapfixIfStatus(ctx, MapfixID, allow_statuses, update) if err != nil { return nil, err } // push an action audit event event_data := model.AuditEventDataAction{ TargetStatus: uint32(target_status), } err = svc.inner.CreateAuditEventAction( ctx, model.ValidatorUserID, model.Resource{ ID: MapfixID, Type: model.ResourceMapfix, }, event_data, ) if err != nil { return nil, err } return &validator.NullResponse{}, nil } // ActionMapfixReleased implements actionMapfixReleased operation. // // (Internal endpoint) Role Validator changes status from Releasing -> Released. // // POST /mapfixes/{MapfixID}/status/validator-released func (svc *Mapfixes) SetStatusReleased(ctx context.Context, params *validator.MapfixReleaseRequest) (*validator.NullResponse, error) { MapfixID := int64(params.MapfixID) // transaction target_status := model.MapfixStatusReleased update := service.NewMapfixUpdate() update.SetStatusID(target_status) allow_statuses := []model.MapfixStatus{model.MapfixStatusReleasing} err := svc.inner.UpdateMapfixIfStatus(ctx, MapfixID, allow_statuses, update) if err != nil { return nil, err } event_data := model.AuditEventDataAction{ TargetStatus: uint32(target_status), } err = svc.inner.CreateAuditEventAction( ctx, model.ValidatorUserID, model.Resource{ ID: MapfixID, Type: model.ResourceMapfix, }, event_data, ) if err != nil { return nil, err } // metadata maintenance map_update := service.NewMapUpdate() map_update.SetAssetVersion(params.AssetVersion) map_update.SetModes(params.Modes) err = svc.inner.UpdateMap(ctx, int64(params.TargetAssetID), map_update) if err != nil { return nil, err } return &validator.NullResponse{}, nil } func (svc *Mapfixes) SetStatusNotReleased(ctx context.Context, params *validator.MapfixID) (*validator.NullResponse, error) { MapfixID := int64(params.ID) // transaction target_status := model.MapfixStatusUploaded update := service.NewMapfixUpdate() update.SetStatusID(target_status) allow_statuses := []model.MapfixStatus{model.MapfixStatusReleasing} err := svc.inner.UpdateMapfixIfStatus(ctx, MapfixID, allow_statuses, update) if err != nil { return nil, err } // push an action audit event event_data := model.AuditEventDataAction{ TargetStatus: uint32(target_status), } err = svc.inner.CreateAuditEventAction( ctx, model.ValidatorUserID, model.Resource{ ID: MapfixID, Type: model.ResourceMapfix, }, event_data, ) if err != nil { return nil, err } return &validator.NullResponse{}, nil } // CreateMapfixAuditError implements createMapfixAuditError operation. // // Post an error to the audit log // // POST /mapfixes/{MapfixID}/error func (svc *Mapfixes) CreateAuditError(ctx context.Context, params *validator.AuditErrorRequest) (*validator.NullResponse, error) { MapfixID := int64(params.ID) event_data := model.AuditEventDataError{ Error: params.ErrorMessage, } err := svc.inner.CreateAuditEventError( ctx, model.ValidatorUserID, model.Resource{ ID: MapfixID, Type: model.ResourceMapfix, }, event_data, ) if err != nil { return nil, err } return &validator.NullResponse{}, nil } // CreateMapfixAuditCheckList implements createMapfixAuditCheckList operation. // // Post a checklist to the audit log // // POST /mapfixes/{MapfixID}/checklist func (svc *Mapfixes) CreateAuditChecklist(ctx context.Context, params *validator.AuditChecklistRequest) (*validator.NullResponse, error) { MapfixID := int64(params.ID) check_list := make([]model.Check, len(params.CheckList)) for i, check := range params.CheckList { check_list[i] = model.Check{ Name: check.Name, Summary: check.Summary, Passed: check.Passed, } } event_data := model.AuditEventDataCheckList{ CheckList: check_list, } err := svc.inner.CreateAuditEventCheckList( ctx, model.ValidatorUserID, model.Resource{ ID: MapfixID, Type: model.ResourceMapfix, }, event_data, ) if err != nil { return nil, err } return &validator.NullResponse{}, nil } // POST /mapfixes func (svc *Mapfixes) Create(ctx context.Context, request *validator.MapfixCreate) (*validator.MapfixID, error) { var Submitter=request.AssetOwner; // Check if an active mapfix with the same asset id exists { filter := service.NewMapfixFilter() filter.SetAssetID(request.AssetID) filter.SetAssetVersion(request.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 } } OperationID := int32(request.OperationID) operation, err := svc.inner.GetOperation(ctx, 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: request.GameID, Submitter: Submitter, AssetID: request.AssetID, AssetVersion: request.AssetVersion, Completed: false, TargetAssetID: request.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, OperationID, params) if err != nil { return nil, err } return &validator.MapfixID{ ID: uint64(mapfix.ID), }, nil }