parent
6d420c3a82
commit
732598266c
pkg
37
pkg/model/mapfix.go
Normal file
37
pkg/model/mapfix.go
Normal file
@ -0,0 +1,37 @@
|
|||||||
|
package model
|
||||||
|
|
||||||
|
import "time"
|
||||||
|
|
||||||
|
type MapfixStatus int32
|
||||||
|
|
||||||
|
const (
|
||||||
|
// Phase: Final MapfixStatus
|
||||||
|
MapfixStatusRejected MapfixStatus = 8
|
||||||
|
MapfixStatusUploaded MapfixStatus = 7 // uploaded to the group, final status for mapfixes
|
||||||
|
|
||||||
|
// Phase: Testing
|
||||||
|
MapfixStatusUploading MapfixStatus = 6
|
||||||
|
MapfixStatusValidated MapfixStatus = 5
|
||||||
|
MapfixStatusValidating MapfixStatus = 4
|
||||||
|
MapfixStatusAccepted MapfixStatus = 3 // pending script review, can re-trigger validation
|
||||||
|
|
||||||
|
// Phase: Creation
|
||||||
|
MapfixStatusChangesRequested MapfixStatus = 2
|
||||||
|
MapfixStatusSubmitted MapfixStatus = 1
|
||||||
|
MapfixStatusUnderConstruction MapfixStatus = 0
|
||||||
|
)
|
||||||
|
|
||||||
|
type Mapfix struct {
|
||||||
|
ID int64 `gorm:"primaryKey"`
|
||||||
|
CreatedAt time.Time
|
||||||
|
UpdatedAt time.Time
|
||||||
|
Submitter int64 // UserID
|
||||||
|
AssetID int64
|
||||||
|
AssetVersion int64
|
||||||
|
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 MapfixStatus
|
||||||
|
StatusMessage string
|
||||||
|
}
|
@ -13,6 +13,13 @@ type ValidateSubmissionRequest struct {
|
|||||||
ValidatedModelID *int64 // optional value
|
ValidatedModelID *int64 // optional value
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type ValidateMapfixRequest struct {
|
||||||
|
MapfixID int64
|
||||||
|
ModelID int64
|
||||||
|
ModelVersion int64
|
||||||
|
ValidatedModelID *int64 // optional value
|
||||||
|
}
|
||||||
|
|
||||||
// Create a new map
|
// Create a new map
|
||||||
type UploadSubmissionRequest struct {
|
type UploadSubmissionRequest struct {
|
||||||
SubmissionID int64
|
SubmissionID int64
|
||||||
|
598
pkg/service/mapfixes.go
Normal file
598
pkg/service/mapfixes.go
Normal file
@ -0,0 +1,598 @@
|
|||||||
|
package service
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"encoding/json"
|
||||||
|
"errors"
|
||||||
|
"fmt"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"git.itzana.me/strafesnet/maps-service/pkg/api"
|
||||||
|
"git.itzana.me/strafesnet/maps-service/pkg/datastore"
|
||||||
|
"git.itzana.me/strafesnet/maps-service/pkg/model"
|
||||||
|
)
|
||||||
|
|
||||||
|
var(
|
||||||
|
CreationPhaseMapfixesLimit = 20
|
||||||
|
CreationPhaseMapfixStatuses = []model.MapfixStatus{
|
||||||
|
model.MapfixStatusChangesRequested,
|
||||||
|
model.MapfixStatusSubmitted,
|
||||||
|
model.MapfixStatusUnderConstruction,
|
||||||
|
}
|
||||||
|
// prevent two mapfixes with same asset id
|
||||||
|
ActiveMapfixStatuses = []model.MapfixStatus{
|
||||||
|
model.MapfixStatusUploading,
|
||||||
|
model.MapfixStatusValidated,
|
||||||
|
model.MapfixStatusValidating,
|
||||||
|
model.MapfixStatusAccepted,
|
||||||
|
model.MapfixStatusChangesRequested,
|
||||||
|
model.MapfixStatusSubmitted,
|
||||||
|
model.MapfixStatusUnderConstruction,
|
||||||
|
}
|
||||||
|
// limit mapfixes in the pipeline to one per target map
|
||||||
|
ActiveAcceptedMapfixStatuses = []model.MapfixStatus{
|
||||||
|
model.MapfixStatusUploading,
|
||||||
|
model.MapfixStatusValidated,
|
||||||
|
model.MapfixStatusValidating,
|
||||||
|
model.MapfixStatusAccepted,
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
ErrCreationPhaseMapfixesLimit = errors.New("Active mapfixes limited to 20")
|
||||||
|
ErrActiveMapfixSameAssetID = errors.New("There is an active mapfix with the same AssetID")
|
||||||
|
ErrActiveMapfixSameTargetAssetID = errors.New("There is an active mapfix with the same TargetAssetID")
|
||||||
|
ErrAcceptOwnMapfix = fmt.Errorf("%w: You cannot accept your own mapfix as the submitter", ErrPermissionDenied)
|
||||||
|
)
|
||||||
|
|
||||||
|
// POST /mapfixes
|
||||||
|
func (svc *Service) CreateMapfix(ctx context.Context, request *api.MapfixCreate) (*api.ID, error) {
|
||||||
|
userInfo, ok := ctx.Value("UserInfo").(UserInfoHandle)
|
||||||
|
if !ok {
|
||||||
|
return nil, ErrUserInfo
|
||||||
|
}
|
||||||
|
|
||||||
|
userId, err := userInfo.GetUserID()
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check if user's mapfixes in the creation phase exceeds the limit
|
||||||
|
{
|
||||||
|
filter := datastore.Optional()
|
||||||
|
filter.Add("submitter", int64(userId))
|
||||||
|
filter.Add("status_id", CreationPhaseMapfixStatuses)
|
||||||
|
creation_mapfixes, err := svc.DB.Mapfixes().List(ctx, filter, model.Page{
|
||||||
|
Number: 1,
|
||||||
|
Size: int32(CreationPhaseMapfixesLimit),
|
||||||
|
},datastore.ListSortDisabled)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
if CreationPhaseMapfixesLimit <= len(creation_mapfixes) {
|
||||||
|
return nil, ErrCreationPhaseMapfixesLimit
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check if an active mapfix 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", ActiveMapfixStatuses)
|
||||||
|
active_mapfixes, err := svc.DB.Mapfixes().List(ctx, filter, model.Page{
|
||||||
|
Number: 1,
|
||||||
|
Size: 1,
|
||||||
|
},datastore.ListSortDisabled)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
if len(active_mapfixes) != 0{
|
||||||
|
return nil, ErrActiveMapfixSameAssetID
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
mapfix, err := svc.DB.Mapfixes().Create(ctx, model.Mapfix{
|
||||||
|
ID: 0,
|
||||||
|
Submitter: int64(userId),
|
||||||
|
AssetID: request.AssetID,
|
||||||
|
AssetVersion: request.AssetVersion,
|
||||||
|
Completed: false,
|
||||||
|
TargetAssetID: request.TargetAssetID,
|
||||||
|
StatusID: model.MapfixStatusUnderConstruction,
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return &api.ID{
|
||||||
|
ID: mapfix.ID,
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetMapfix implements getMapfix operation.
|
||||||
|
//
|
||||||
|
// Retrieve map with ID.
|
||||||
|
//
|
||||||
|
// GET /mapfixes/{MapfixID}
|
||||||
|
func (svc *Service) GetMapfix(ctx context.Context, params api.GetMapfixParams) (*api.Mapfix, error) {
|
||||||
|
mapfix, err := svc.DB.Mapfixes().Get(ctx, params.MapfixID)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return &api.Mapfix{
|
||||||
|
ID: mapfix.ID,
|
||||||
|
CreatedAt: mapfix.CreatedAt.Unix(),
|
||||||
|
UpdatedAt: mapfix.UpdatedAt.Unix(),
|
||||||
|
Submitter: int64(mapfix.Submitter),
|
||||||
|
AssetID: int64(mapfix.AssetID),
|
||||||
|
AssetVersion: int64(mapfix.AssetVersion),
|
||||||
|
Completed: mapfix.Completed,
|
||||||
|
TargetAssetID: int64(mapfix.TargetAssetID),
|
||||||
|
StatusID: int32(mapfix.StatusID),
|
||||||
|
StatusMessage: mapfix.StatusMessage,
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// ListMapfixes implements listMapfixes operation.
|
||||||
|
//
|
||||||
|
// Get list of mapfixes.
|
||||||
|
//
|
||||||
|
// GET /mapfixes
|
||||||
|
func (svc *Service) ListMapfixes(ctx context.Context, params api.ListMapfixesParams) ([]api.Mapfix, error) {
|
||||||
|
filter := datastore.Optional()
|
||||||
|
|
||||||
|
sort := datastore.ListSort(params.Sort.Or(int32(datastore.ListSortDisabled)))
|
||||||
|
|
||||||
|
items, err := svc.DB.Mapfixes().List(ctx, filter, model.Page{
|
||||||
|
Number: params.Page,
|
||||||
|
Size: params.Limit,
|
||||||
|
},sort)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
var resp []api.Mapfix
|
||||||
|
for _, item := range items {
|
||||||
|
resp = append(resp, api.Mapfix{
|
||||||
|
ID: item.ID,
|
||||||
|
CreatedAt: item.CreatedAt.Unix(),
|
||||||
|
UpdatedAt: item.UpdatedAt.Unix(),
|
||||||
|
Submitter: int64(item.Submitter),
|
||||||
|
AssetID: int64(item.AssetID),
|
||||||
|
AssetVersion: int64(item.AssetVersion),
|
||||||
|
Completed: item.Completed,
|
||||||
|
TargetAssetID: int64(item.TargetAssetID),
|
||||||
|
StatusID: int32(item.StatusID),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
return resp, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// PatchMapfixCompleted implements patchMapfixCompleted operation.
|
||||||
|
//
|
||||||
|
// Retrieve map with ID.
|
||||||
|
//
|
||||||
|
// POST /mapfixes/{MapfixID}/completed
|
||||||
|
func (svc *Service) SetMapfixCompleted(ctx context.Context, params api.SetMapfixCompletedParams) error {
|
||||||
|
userInfo, ok := ctx.Value("UserInfo").(UserInfoHandle)
|
||||||
|
if !ok {
|
||||||
|
return ErrUserInfo
|
||||||
|
}
|
||||||
|
|
||||||
|
has_role, err := userInfo.HasRoleMaptest()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
// check if caller has MaptestGame role (request must originate from a maptest roblox game)
|
||||||
|
if !has_role {
|
||||||
|
return ErrPermissionDeniedNeedRoleMaptest
|
||||||
|
}
|
||||||
|
|
||||||
|
pmap := datastore.Optional()
|
||||||
|
pmap.Add("completed", true)
|
||||||
|
return svc.DB.Mapfixes().Update(ctx, params.MapfixID, pmap)
|
||||||
|
}
|
||||||
|
|
||||||
|
// UpdateMapfixModel implements patchMapfixModel operation.
|
||||||
|
//
|
||||||
|
// Update model following role restrictions.
|
||||||
|
//
|
||||||
|
// POST /mapfixes/{MapfixID}/model
|
||||||
|
func (svc *Service) UpdateMapfixModel(ctx context.Context, params api.UpdateMapfixModelParams) error {
|
||||||
|
userInfo, ok := ctx.Value("UserInfo").(UserInfoHandle)
|
||||||
|
if !ok {
|
||||||
|
return ErrUserInfo
|
||||||
|
}
|
||||||
|
|
||||||
|
// read mapfix (this could be done with a transaction WHERE clause)
|
||||||
|
mapfix, err := svc.DB.Mapfixes().Get(ctx, params.MapfixID)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
has_role, err := userInfo.IsSubmitter(uint64(mapfix.Submitter))
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
// check if caller is the submitter
|
||||||
|
if !has_role {
|
||||||
|
return ErrPermissionDeniedNotSubmitter
|
||||||
|
}
|
||||||
|
|
||||||
|
// check if Status is ChangesRequested|Submitted|UnderConstruction
|
||||||
|
pmap := datastore.Optional()
|
||||||
|
pmap.AddNotNil("asset_id", params.ModelID)
|
||||||
|
pmap.AddNotNil("asset_version", params.VersionID)
|
||||||
|
//always reset completed when model changes
|
||||||
|
pmap.Add("completed", false)
|
||||||
|
return svc.DB.Mapfixes().IfStatusThenUpdate(ctx, params.MapfixID, []model.MapfixStatus{model.MapfixStatusChangesRequested, model.MapfixStatusSubmitted, model.MapfixStatusUnderConstruction}, pmap)
|
||||||
|
}
|
||||||
|
|
||||||
|
// ActionMapfixReject invokes actionMapfixReject operation.
|
||||||
|
//
|
||||||
|
// Role Reviewer changes status from Submitted -> Rejected.
|
||||||
|
//
|
||||||
|
// POST /mapfixes/{MapfixID}/status/reject
|
||||||
|
func (svc *Service) ActionMapfixReject(ctx context.Context, params api.ActionMapfixRejectParams) error {
|
||||||
|
userInfo, ok := ctx.Value("UserInfo").(UserInfoHandle)
|
||||||
|
if !ok {
|
||||||
|
return ErrUserInfo
|
||||||
|
}
|
||||||
|
|
||||||
|
has_role, err := userInfo.HasRoleMapfixReview()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
// check if caller has required role
|
||||||
|
if !has_role {
|
||||||
|
return ErrPermissionDeniedNeedRoleMapReview
|
||||||
|
}
|
||||||
|
|
||||||
|
// transaction
|
||||||
|
smap := datastore.Optional()
|
||||||
|
smap.Add("status_id", model.MapfixStatusRejected)
|
||||||
|
return svc.DB.Mapfixes().IfStatusThenUpdate(ctx, params.MapfixID, []model.MapfixStatus{model.MapfixStatusSubmitted}, smap)
|
||||||
|
}
|
||||||
|
|
||||||
|
// ActionMapfixRequestChanges invokes actionMapfixRequestChanges operation.
|
||||||
|
//
|
||||||
|
// Role Reviewer changes status from Validated|Accepted|Submitted -> ChangesRequested.
|
||||||
|
//
|
||||||
|
// POST /mapfixes/{MapfixID}/status/request-changes
|
||||||
|
func (svc *Service) ActionMapfixRequestChanges(ctx context.Context, params api.ActionMapfixRequestChangesParams) error {
|
||||||
|
userInfo, ok := ctx.Value("UserInfo").(UserInfoHandle)
|
||||||
|
if !ok {
|
||||||
|
return ErrUserInfo
|
||||||
|
}
|
||||||
|
|
||||||
|
has_role, err := userInfo.HasRoleMapfixReview()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
// check if caller has required role
|
||||||
|
if !has_role {
|
||||||
|
return ErrPermissionDeniedNeedRoleMapReview
|
||||||
|
}
|
||||||
|
|
||||||
|
// transaction
|
||||||
|
smap := datastore.Optional()
|
||||||
|
smap.Add("status_id", model.MapfixStatusChangesRequested)
|
||||||
|
return svc.DB.Mapfixes().IfStatusThenUpdate(ctx, params.MapfixID, []model.MapfixStatus{model.MapfixStatusValidated, model.MapfixStatusAccepted, model.MapfixStatusSubmitted}, smap)
|
||||||
|
}
|
||||||
|
|
||||||
|
// ActionMapfixRevoke invokes actionMapfixRevoke operation.
|
||||||
|
//
|
||||||
|
// Role Submitter changes status from Submitted|ChangesRequested -> UnderConstruction.
|
||||||
|
//
|
||||||
|
// POST /mapfixes/{MapfixID}/status/revoke
|
||||||
|
func (svc *Service) ActionMapfixRevoke(ctx context.Context, params api.ActionMapfixRevokeParams) error {
|
||||||
|
userInfo, ok := ctx.Value("UserInfo").(UserInfoHandle)
|
||||||
|
if !ok {
|
||||||
|
return ErrUserInfo
|
||||||
|
}
|
||||||
|
|
||||||
|
// read mapfix (this could be done with a transaction WHERE clause)
|
||||||
|
mapfix, err := svc.DB.Mapfixes().Get(ctx, params.MapfixID)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
has_role, err := userInfo.IsSubmitter(uint64(mapfix.Submitter))
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
// check if caller is the submitter
|
||||||
|
if !has_role {
|
||||||
|
return ErrPermissionDeniedNotSubmitter
|
||||||
|
}
|
||||||
|
|
||||||
|
// transaction
|
||||||
|
smap := datastore.Optional()
|
||||||
|
smap.Add("status_id", model.MapfixStatusUnderConstruction)
|
||||||
|
return svc.DB.Mapfixes().IfStatusThenUpdate(ctx, params.MapfixID, []model.MapfixStatus{model.MapfixStatusSubmitted, model.MapfixStatusChangesRequested}, smap)
|
||||||
|
}
|
||||||
|
|
||||||
|
// ActionMapfixSubmit invokes actionMapfixSubmit operation.
|
||||||
|
//
|
||||||
|
// Role Submitter changes status from UnderConstruction|ChangesRequested -> Submitted.
|
||||||
|
//
|
||||||
|
// POST /mapfixes/{MapfixID}/status/submit
|
||||||
|
func (svc *Service) ActionMapfixSubmit(ctx context.Context, params api.ActionMapfixSubmitParams) error {
|
||||||
|
userInfo, ok := ctx.Value("UserInfo").(UserInfoHandle)
|
||||||
|
if !ok {
|
||||||
|
return ErrUserInfo
|
||||||
|
}
|
||||||
|
|
||||||
|
// read mapfix (this could be done with a transaction WHERE clause)
|
||||||
|
mapfix, err := svc.DB.Mapfixes().Get(ctx, params.MapfixID)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
has_role, err := userInfo.IsSubmitter(uint64(mapfix.Submitter))
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
// check if caller is the submitter
|
||||||
|
if !has_role {
|
||||||
|
return ErrPermissionDeniedNotSubmitter
|
||||||
|
}
|
||||||
|
|
||||||
|
// transaction
|
||||||
|
smap := datastore.Optional()
|
||||||
|
smap.Add("status_id", model.MapfixStatusSubmitted)
|
||||||
|
return svc.DB.Mapfixes().IfStatusThenUpdate(ctx, params.MapfixID, []model.MapfixStatus{model.MapfixStatusUnderConstruction, model.MapfixStatusChangesRequested}, smap)
|
||||||
|
}
|
||||||
|
|
||||||
|
// ActionMapfixTriggerUpload invokes actionMapfixTriggerUpload operation.
|
||||||
|
//
|
||||||
|
// Role Admin changes status from Validated -> Uploading.
|
||||||
|
//
|
||||||
|
// POST /mapfixes/{MapfixID}/status/trigger-upload
|
||||||
|
func (svc *Service) ActionMapfixTriggerUpload(ctx context.Context, params api.ActionMapfixTriggerUploadParams) error {
|
||||||
|
userInfo, ok := ctx.Value("UserInfo").(UserInfoHandle)
|
||||||
|
if !ok {
|
||||||
|
return ErrUserInfo
|
||||||
|
}
|
||||||
|
|
||||||
|
has_role, err := userInfo.HasRoleMapfixUpload()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
// check if caller has required role
|
||||||
|
if !has_role {
|
||||||
|
return ErrPermissionDeniedNeedRoleMapUpload
|
||||||
|
}
|
||||||
|
|
||||||
|
// transaction
|
||||||
|
smap := datastore.Optional()
|
||||||
|
smap.Add("status_id", model.MapfixStatusUploading)
|
||||||
|
mapfix, err := svc.DB.Mapfixes().IfStatusThenUpdateAndGet(ctx, params.MapfixID, []model.MapfixStatus{model.MapfixStatusValidated}, smap)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// this is a map fix
|
||||||
|
upload_fix_request := model.UploadMapfixRequest{
|
||||||
|
MapfixID: mapfix.ID,
|
||||||
|
ModelID: mapfix.ValidatedAssetID,
|
||||||
|
ModelVersion: mapfix.ValidatedAssetVersion,
|
||||||
|
TargetAssetID: mapfix.TargetAssetID,
|
||||||
|
}
|
||||||
|
|
||||||
|
j, err := json.Marshal(upload_fix_request)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
svc.Nats.Publish("maptest.mapfixes.uploadfix", []byte(j))
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// ActionMapfixValidate invokes actionMapfixValidate operation.
|
||||||
|
//
|
||||||
|
// Role MapfixRelease changes status from Uploading -> Validated.
|
||||||
|
//
|
||||||
|
// POST /mapfixes/{MapfixID}/status/reset-uploading
|
||||||
|
func (svc *Service) ActionMapfixValidated(ctx context.Context, params api.ActionMapfixValidatedParams) error {
|
||||||
|
userInfo, ok := ctx.Value("UserInfo").(UserInfoHandle)
|
||||||
|
if !ok {
|
||||||
|
return ErrUserInfo
|
||||||
|
}
|
||||||
|
|
||||||
|
has_role, err := userInfo.HasRoleMapfixUpload()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
// check if caller has required role
|
||||||
|
if !has_role {
|
||||||
|
return ErrPermissionDeniedNeedRoleMapUpload
|
||||||
|
}
|
||||||
|
|
||||||
|
// check when mapfix was updated
|
||||||
|
mapfix, err := svc.DB.Mapfixes().Get(ctx, params.MapfixID)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if time.Now().Before(mapfix.UpdatedAt.Add(time.Second*10)) {
|
||||||
|
// the last time the mapfix was updated must be longer than 10 seconds ago
|
||||||
|
return ErrDelayReset
|
||||||
|
}
|
||||||
|
|
||||||
|
// transaction
|
||||||
|
smap := datastore.Optional()
|
||||||
|
smap.Add("status_id", model.MapfixStatusValidated)
|
||||||
|
return svc.DB.Mapfixes().IfStatusThenUpdate(ctx, params.MapfixID, []model.MapfixStatus{model.MapfixStatusUploading}, smap)
|
||||||
|
}
|
||||||
|
|
||||||
|
// ActionMapfixTriggerValidate invokes actionMapfixTriggerValidate operation.
|
||||||
|
//
|
||||||
|
// Role Reviewer triggers validation and changes status from Submitted -> Validating.
|
||||||
|
//
|
||||||
|
// POST /mapfixes/{MapfixID}/status/trigger-validate
|
||||||
|
func (svc *Service) ActionMapfixTriggerValidate(ctx context.Context, params api.ActionMapfixTriggerValidateParams) error {
|
||||||
|
userInfo, ok := ctx.Value("UserInfo").(UserInfoHandle)
|
||||||
|
if !ok {
|
||||||
|
return ErrUserInfo
|
||||||
|
}
|
||||||
|
|
||||||
|
has_role, err := userInfo.HasRoleMapfixReview()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
// check if caller has required role
|
||||||
|
if !has_role {
|
||||||
|
return ErrPermissionDeniedNeedRoleMapReview
|
||||||
|
}
|
||||||
|
|
||||||
|
// read mapfix (this could be done with a transaction WHERE clause)
|
||||||
|
mapfix, err := svc.DB.Mapfixes().Get(ctx, params.MapfixID)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
has_role, err = userInfo.IsSubmitter(uint64(mapfix.Submitter))
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
// check if caller is NOT the submitter
|
||||||
|
if has_role {
|
||||||
|
return ErrAcceptOwnMapfix
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check if an active mapfix with the same target asset id exists
|
||||||
|
if mapfix.TargetAssetID != 0 {
|
||||||
|
filter := datastore.Optional()
|
||||||
|
filter.Add("target_asset_id", mapfix.TargetAssetID)
|
||||||
|
filter.Add("status_id", ActiveAcceptedMapfixStatuses)
|
||||||
|
active_mapfixes, err := svc.DB.Mapfixes().List(ctx, filter, model.Page{
|
||||||
|
Number: 1,
|
||||||
|
Size: 1,
|
||||||
|
},datastore.ListSortDisabled)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if len(active_mapfixes) != 0{
|
||||||
|
return ErrActiveMapfixSameTargetAssetID
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// transaction
|
||||||
|
smap := datastore.Optional()
|
||||||
|
smap.Add("status_id", model.MapfixStatusValidating)
|
||||||
|
mapfix, err = svc.DB.Mapfixes().IfStatusThenUpdateAndGet(ctx, params.MapfixID, []model.MapfixStatus{model.MapfixStatusSubmitted}, smap)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
validate_request := model.ValidateMapfixRequest{
|
||||||
|
MapfixID: mapfix.ID,
|
||||||
|
ModelID: mapfix.AssetID,
|
||||||
|
ModelVersion: mapfix.AssetVersion,
|
||||||
|
ValidatedModelID: nil,
|
||||||
|
}
|
||||||
|
|
||||||
|
// sentinel values because we're not using rust
|
||||||
|
if mapfix.ValidatedAssetID != 0 {
|
||||||
|
validate_request.ValidatedModelID = &mapfix.ValidatedAssetID
|
||||||
|
}
|
||||||
|
|
||||||
|
j, err := json.Marshal(validate_request)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
svc.Nats.Publish("maptest.mapfixes.validate", []byte(j))
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// ActionMapfixRetryValidate invokes actionMapfixRetryValidate operation.
|
||||||
|
//
|
||||||
|
// Role Reviewer re-runs validation and changes status from Accepted -> Validating.
|
||||||
|
//
|
||||||
|
// POST /mapfixes/{MapfixID}/status/retry-validate
|
||||||
|
func (svc *Service) ActionMapfixRetryValidate(ctx context.Context, params api.ActionMapfixRetryValidateParams) error {
|
||||||
|
userInfo, ok := ctx.Value("UserInfo").(UserInfoHandle)
|
||||||
|
if !ok {
|
||||||
|
return ErrUserInfo
|
||||||
|
}
|
||||||
|
|
||||||
|
has_role, err := userInfo.HasRoleMapfixReview()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
// check if caller has required role
|
||||||
|
if !has_role {
|
||||||
|
return ErrPermissionDeniedNeedRoleMapReview
|
||||||
|
}
|
||||||
|
|
||||||
|
// transaction
|
||||||
|
smap := datastore.Optional()
|
||||||
|
smap.Add("status_id", model.MapfixStatusValidating)
|
||||||
|
mapfix, err := svc.DB.Mapfixes().IfStatusThenUpdateAndGet(ctx, params.MapfixID, []model.MapfixStatus{model.MapfixStatusAccepted}, smap)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
validate_request := model.ValidateMapfixRequest{
|
||||||
|
MapfixID: mapfix.ID,
|
||||||
|
ModelID: mapfix.AssetID,
|
||||||
|
ModelVersion: mapfix.AssetVersion,
|
||||||
|
ValidatedModelID: nil,
|
||||||
|
}
|
||||||
|
|
||||||
|
// sentinel values because we're not using rust
|
||||||
|
if mapfix.ValidatedAssetID != 0 {
|
||||||
|
validate_request.ValidatedModelID = &mapfix.ValidatedAssetID
|
||||||
|
}
|
||||||
|
|
||||||
|
j, err := json.Marshal(validate_request)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
svc.Nats.Publish("maptest.mapfixes.validate", []byte(j))
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// ActionMapfixAccepted implements actionMapfixAccepted operation.
|
||||||
|
//
|
||||||
|
// Role MapfixReview changes status from Validating -> Accepted.
|
||||||
|
//
|
||||||
|
// POST /mapfixes/{MapfixID}/status/reset-validating
|
||||||
|
func (svc *Service) ActionMapfixAccepted(ctx context.Context, params api.ActionMapfixAcceptedParams) error {
|
||||||
|
userInfo, ok := ctx.Value("UserInfo").(UserInfoHandle)
|
||||||
|
if !ok {
|
||||||
|
return ErrUserInfo
|
||||||
|
}
|
||||||
|
|
||||||
|
has_role, err := userInfo.HasRoleMapfixReview()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
// check if caller has required role
|
||||||
|
if !has_role {
|
||||||
|
return ErrPermissionDeniedNeedRoleMapReview
|
||||||
|
}
|
||||||
|
|
||||||
|
// check when mapfix was updated
|
||||||
|
mapfix, err := svc.DB.Mapfixes().Get(ctx, params.MapfixID)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if time.Now().Before(mapfix.UpdatedAt.Add(time.Second*10)) {
|
||||||
|
// the last time the mapfix was updated must be longer than 10 seconds ago
|
||||||
|
return ErrDelayReset
|
||||||
|
}
|
||||||
|
|
||||||
|
// transaction
|
||||||
|
smap := datastore.Optional()
|
||||||
|
smap.Add("status_id", model.MapfixStatusAccepted)
|
||||||
|
smap.Add("status_message", "Manually forced reset")
|
||||||
|
return svc.DB.Mapfixes().IfStatusThenUpdate(ctx, params.MapfixID, []model.MapfixStatus{model.MapfixStatusValidating}, smap)
|
||||||
|
}
|
61
pkg/service_internal/mapfixes.go
Normal file
61
pkg/service_internal/mapfixes.go
Normal file
@ -0,0 +1,61 @@
|
|||||||
|
package service_internal
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
|
||||||
|
internal "git.itzana.me/strafesnet/maps-service/pkg/internal"
|
||||||
|
"git.itzana.me/strafesnet/maps-service/pkg/datastore"
|
||||||
|
"git.itzana.me/strafesnet/maps-service/pkg/model"
|
||||||
|
)
|
||||||
|
|
||||||
|
// UpdateMapfixValidatedModel implements patchMapfixModel operation.
|
||||||
|
//
|
||||||
|
// Update model following role restrictions.
|
||||||
|
//
|
||||||
|
// POST /mapfixes/{MapfixID}/validated-model
|
||||||
|
func (svc *Service) UpdateMapfixValidatedModel(ctx context.Context, params internal.UpdateMapfixValidatedModelParams) error {
|
||||||
|
// check if Status is ChangesRequested|Submitted|UnderConstruction
|
||||||
|
pmap := datastore.Optional()
|
||||||
|
pmap.AddNotNil("validated_asset_id", params.ValidatedModelID)
|
||||||
|
pmap.AddNotNil("validated_asset_version", params.ValidatedModelVersion)
|
||||||
|
// DO NOT reset completed when validated model is updated
|
||||||
|
// pmap.Add("completed", false)
|
||||||
|
return svc.DB.Mapfixes().IfStatusThenUpdate(ctx, params.MapfixID, []model.MapfixStatus{model.MapfixStatusValidating}, pmap)
|
||||||
|
}
|
||||||
|
|
||||||
|
// ActionMapfixValidate invokes actionMapfixValidate operation.
|
||||||
|
//
|
||||||
|
// Role Validator changes status from Validating -> Validated.
|
||||||
|
//
|
||||||
|
// POST /mapfixes/{MapfixID}/status/validator-validated
|
||||||
|
func (svc *Service) ActionMapfixValidated(ctx context.Context, params internal.ActionMapfixValidatedParams) error {
|
||||||
|
// transaction
|
||||||
|
smap := datastore.Optional()
|
||||||
|
smap.Add("status_id", model.MapfixStatusValidated)
|
||||||
|
return svc.DB.Mapfixes().IfStatusThenUpdate(ctx, params.MapfixID, []model.MapfixStatus{model.MapfixStatusValidating}, smap)
|
||||||
|
}
|
||||||
|
|
||||||
|
// ActionMapfixAccepted implements actionMapfixAccepted operation.
|
||||||
|
//
|
||||||
|
// (Internal endpoint) Role Validator changes status from Validating -> Accepted.
|
||||||
|
//
|
||||||
|
// POST /mapfixes/{MapfixID}/status/validator-failed
|
||||||
|
func (svc *Service) ActionMapfixAccepted(ctx context.Context, params internal.ActionMapfixAcceptedParams) error {
|
||||||
|
// transaction
|
||||||
|
smap := datastore.Optional()
|
||||||
|
smap.Add("status_id", model.MapfixStatusAccepted)
|
||||||
|
smap.Add("status_message", params.StatusMessage)
|
||||||
|
return svc.DB.Mapfixes().IfStatusThenUpdate(ctx, params.MapfixID, []model.MapfixStatus{model.MapfixStatusValidating}, smap)
|
||||||
|
}
|
||||||
|
|
||||||
|
// ActionMapfixUploaded implements actionMapfixUploaded operation.
|
||||||
|
//
|
||||||
|
// (Internal endpoint) Role Validator changes status from Uploading -> Uploaded.
|
||||||
|
//
|
||||||
|
// POST /mapfixes/{MapfixID}/status/validator-uploaded
|
||||||
|
func (svc *Service) ActionMapfixUploaded(ctx context.Context, params internal.ActionMapfixUploadedParams) error {
|
||||||
|
// transaction
|
||||||
|
smap := datastore.Optional()
|
||||||
|
smap.Add("status_id", model.MapfixStatusUploaded)
|
||||||
|
return svc.DB.Mapfixes().IfStatusThenUpdate(ctx, params.MapfixID, []model.MapfixStatus{model.MapfixStatusUploading}, smap)
|
||||||
|
}
|
Loading…
x
Reference in New Issue
Block a user