diff --git a/pkg/model/operation.go b/pkg/model/operation.go index 4949a92..a3fefbc 100644 --- a/pkg/model/operation.go +++ b/pkg/model/operation.go @@ -12,7 +12,7 @@ const ( type Operation struct { ID int32 `gorm:"primaryKey"` CreatedAt time.Time - Owner int64 // UserID + Owner uint64 // UserID StatusID OperationStatus StatusMessage string Path string // redirect to view completed operation e.g. "/mapfixes/4" diff --git a/pkg/service/mapfixes.go b/pkg/service/mapfixes.go index b9d5b78..722d437 100644 --- a/pkg/service/mapfixes.go +++ b/pkg/service/mapfixes.go @@ -103,7 +103,7 @@ func (svc *Service) CreateMapfix(ctx context.Context, request *api.MapfixTrigger } operation, err := svc.DB.Operations().Create(ctx, model.Operation{ - Owner: int64(userId), + Owner: userId, StatusID: model.OperationStatusCreated, }) if err != nil { @@ -121,7 +121,10 @@ func (svc *Service) CreateMapfix(ctx context.Context, request *api.MapfixTrigger return nil, err } - svc.Nats.Publish("maptest.mapfixes.create", []byte(j)) + _, err = svc.Nats.Publish("maptest.mapfixes.create", []byte(j)) + if err != nil { + return nil, err + } return &api.OperationID{ OperationID: operation.ID, @@ -259,22 +262,58 @@ func (svc *Service) UpdateMapfixModel(ctx context.Context, params api.UpdateMapf return err } - has_role, err := userInfo.IsSubmitter(uint64(mapfix.Submitter)) + userId, err := userInfo.GetUserID() if err != nil { return err } + // check if caller is the submitter + has_role := userId == mapfix.Submitter if !has_role { return ErrPermissionDeniedNotSubmitter } + OldModelID := mapfix.AssetID + OldModelVersion := mapfix.AssetVersion + NewModelID := uint64(params.ModelID) + NewModelVersion := uint64(params.ModelVersion) + // check if Status is ChangesRequested|Submitted|UnderConstruction pmap := datastore.Optional() - pmap.Add("asset_id", params.ModelID) - pmap.Add("asset_version", params.ModelVersion) + pmap.Add("asset_id", NewModelID) + pmap.Add("asset_version", NewModelVersion) //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) + err = svc.DB.Mapfixes().IfStatusThenUpdate(ctx, params.MapfixID, []model.MapfixStatus{model.MapfixStatusChangesRequested, model.MapfixStatusSubmitted, model.MapfixStatusUnderConstruction}, pmap) + if err != nil { + return err + } + + event_data := model.AuditEventDataChangeModel{ + OldModelID: OldModelID, + OldModelVersion: OldModelVersion, + NewModelID: NewModelID, + NewModelVersion: NewModelVersion, + } + + EventData, err := json.Marshal(event_data) + if err != nil { + return err + } + + _, err = svc.DB.AuditEvents().Create(ctx, model.AuditEvent{ + ID: 0, + User: userId, + ResourceType: model.ResourceMapfix, + ResourceID: params.MapfixID, + EventType: model.AuditEventTypeChangeModel, + EventData: EventData, + }) + if err != nil { + return err + } + + return nil } // ActionMapfixReject invokes actionMapfixReject operation. @@ -297,10 +336,42 @@ func (svc *Service) ActionMapfixReject(ctx context.Context, params api.ActionMap return ErrPermissionDeniedNeedRoleMapReview } + userId, err := userInfo.GetUserID() + if err != nil { + return err + } + // transaction + target_status := model.MapfixStatusRejected smap := datastore.Optional() - smap.Add("status_id", model.MapfixStatusRejected) - return svc.DB.Mapfixes().IfStatusThenUpdate(ctx, params.MapfixID, []model.MapfixStatus{model.MapfixStatusSubmitted}, smap) + smap.Add("status_id", target_status) + err = svc.DB.Mapfixes().IfStatusThenUpdate(ctx, params.MapfixID, []model.MapfixStatus{model.MapfixStatusSubmitted}, smap) + if err != nil { + return err + } + + event_data := model.AuditEventDataAction{ + TargetStatus: uint32(target_status), + } + + EventData, err := json.Marshal(event_data) + if err != nil { + return err + } + + _, err = svc.DB.AuditEvents().Create(ctx, model.AuditEvent{ + ID: 0, + User: userId, + ResourceType: model.ResourceMapfix, + ResourceID: params.MapfixID, + EventType: model.AuditEventTypeAction, + EventData: EventData, + }) + if err != nil { + return err + } + + return nil } // ActionMapfixRequestChanges invokes actionMapfixRequestChanges operation. @@ -346,19 +417,48 @@ func (svc *Service) ActionMapfixRevoke(ctx context.Context, params api.ActionMap return err } - has_role, err := userInfo.IsSubmitter(uint64(mapfix.Submitter)) + userId, err := userInfo.GetUserID() if err != nil { return err } + // check if caller is the submitter + has_role := userId == mapfix.Submitter if !has_role { return ErrPermissionDeniedNotSubmitter } // transaction + target_status := model.MapfixStatusUnderConstruction smap := datastore.Optional() - smap.Add("status_id", model.MapfixStatusUnderConstruction) - return svc.DB.Mapfixes().IfStatusThenUpdate(ctx, params.MapfixID, []model.MapfixStatus{model.MapfixStatusSubmitted, model.MapfixStatusChangesRequested}, smap) + smap.Add("status_id", target_status) + err = svc.DB.Mapfixes().IfStatusThenUpdate(ctx, params.MapfixID, []model.MapfixStatus{model.MapfixStatusSubmitted, model.MapfixStatusChangesRequested}, smap) + if err != nil { + return err + } + + event_data := model.AuditEventDataAction{ + TargetStatus: uint32(target_status), + } + + EventData, err := json.Marshal(event_data) + if err != nil { + return err + } + + _, err = svc.DB.AuditEvents().Create(ctx, model.AuditEvent{ + ID: 0, + User: userId, + ResourceType: model.ResourceMapfix, + ResourceID: params.MapfixID, + EventType: model.AuditEventTypeAction, + EventData: EventData, + }) + if err != nil { + return err + } + + return nil } // ActionMapfixSubmit invokes actionMapfixSubmit operation. @@ -378,19 +478,48 @@ func (svc *Service) ActionMapfixSubmit(ctx context.Context, params api.ActionMap return err } - has_role, err := userInfo.IsSubmitter(uint64(mapfix.Submitter)) + userId, err := userInfo.GetUserID() if err != nil { return err } + // check if caller is the submitter + has_role := userId == mapfix.Submitter if !has_role { return ErrPermissionDeniedNotSubmitter } // transaction + target_status := model.MapfixStatusSubmitted smap := datastore.Optional() - smap.Add("status_id", model.MapfixStatusSubmitted) - return svc.DB.Mapfixes().IfStatusThenUpdate(ctx, params.MapfixID, []model.MapfixStatus{model.MapfixStatusUnderConstruction, model.MapfixStatusChangesRequested}, smap) + smap.Add("status_id", target_status) + err = svc.DB.Mapfixes().IfStatusThenUpdate(ctx, params.MapfixID, []model.MapfixStatus{model.MapfixStatusUnderConstruction, model.MapfixStatusChangesRequested}, smap) + if err != nil { + return err + } + + event_data := model.AuditEventDataAction{ + TargetStatus: uint32(target_status), + } + + EventData, err := json.Marshal(event_data) + if err != nil { + return err + } + + _, err = svc.DB.AuditEvents().Create(ctx, model.AuditEvent{ + ID: 0, + User: userId, + ResourceType: model.ResourceMapfix, + ResourceID: params.MapfixID, + EventType: model.AuditEventTypeAction, + EventData: EventData, + }) + if err != nil { + return err + } + + return nil } // ActionMapfixTriggerUpload invokes actionMapfixTriggerUpload operation. @@ -413,9 +542,15 @@ func (svc *Service) ActionMapfixTriggerUpload(ctx context.Context, params api.Ac return ErrPermissionDeniedNeedRoleMapUpload } + userId, err := userInfo.GetUserID() + if err != nil { + return err + } + // transaction + target_status := model.MapfixStatusUploading smap := datastore.Optional() - smap.Add("status_id", model.MapfixStatusUploading) + smap.Add("status_id", target_status) mapfix, err := svc.DB.Mapfixes().IfStatusThenUpdateAndGet(ctx, params.MapfixID, []model.MapfixStatus{model.MapfixStatusValidated}, smap) if err != nil { return err @@ -434,7 +569,31 @@ func (svc *Service) ActionMapfixTriggerUpload(ctx context.Context, params api.Ac return err } - svc.Nats.Publish("maptest.mapfixes.uploadfix", []byte(j)) + _, err = svc.Nats.Publish("maptest.mapfixes.uploadfix", []byte(j)) + if err != nil { + return err + } + + event_data := model.AuditEventDataAction{ + TargetStatus: uint32(target_status), + } + + EventData, err := json.Marshal(event_data) + if err != nil { + return err + } + + _, err = svc.DB.AuditEvents().Create(ctx, model.AuditEvent{ + ID: 0, + User: userId, + ResourceType: model.ResourceMapfix, + ResourceID: params.MapfixID, + EventType: model.AuditEventTypeAction, + EventData: EventData, + }) + if err != nil { + return err + } return nil } @@ -459,6 +618,11 @@ func (svc *Service) ActionMapfixValidated(ctx context.Context, params api.Action return ErrPermissionDeniedNeedRoleMapUpload } + userId, err := userInfo.GetUserID() + if err != nil { + return err + } + // check when mapfix was updated mapfix, err := svc.DB.Mapfixes().Get(ctx, params.MapfixID) if err != nil { @@ -470,9 +634,54 @@ func (svc *Service) ActionMapfixValidated(ctx context.Context, params api.Action } // transaction + target_status := model.MapfixStatusValidated smap := datastore.Optional() - smap.Add("status_id", model.MapfixStatusValidated) - return svc.DB.Mapfixes().IfStatusThenUpdate(ctx, params.MapfixID, []model.MapfixStatus{model.MapfixStatusUploading}, smap) + smap.Add("status_id", target_status) + err = svc.DB.Mapfixes().IfStatusThenUpdate(ctx, params.MapfixID, []model.MapfixStatus{model.MapfixStatusUploading}, 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 + } + + _, err = svc.Nats.Publish("maptest.mapfixes.uploadfix", []byte(j)) + if err != nil { + return err + } + + event_data := model.AuditEventDataAction{ + TargetStatus: uint32(target_status), + } + + EventData, err := json.Marshal(event_data) + if err != nil { + return err + } + + _, err = svc.DB.AuditEvents().Create(ctx, model.AuditEvent{ + ID: 0, + User: userId, + ResourceType: model.ResourceMapfix, + ResourceID: params.MapfixID, + EventType: model.AuditEventTypeAction, + EventData: EventData, + }) + if err != nil { + return err + } + + return nil } // ActionMapfixTriggerValidate invokes actionMapfixTriggerValidate operation. @@ -501,11 +710,13 @@ func (svc *Service) ActionMapfixTriggerValidate(ctx context.Context, params api. return err } - has_role, err = userInfo.IsSubmitter(uint64(mapfix.Submitter)) + userId, err := userInfo.GetUserID() if err != nil { return err } + // check if caller is NOT the submitter + has_role = userId == mapfix.Submitter if has_role { return ErrAcceptOwnMapfix } @@ -528,8 +739,9 @@ func (svc *Service) ActionMapfixTriggerValidate(ctx context.Context, params api. } // transaction + target_status := model.MapfixStatusValidating smap := datastore.Optional() - smap.Add("status_id", model.MapfixStatusValidating) + smap.Add("status_id", target_status) mapfix, err = svc.DB.Mapfixes().IfStatusThenUpdateAndGet(ctx, params.MapfixID, []model.MapfixStatus{model.MapfixStatusSubmitted}, smap) if err != nil { return err @@ -552,7 +764,31 @@ func (svc *Service) ActionMapfixTriggerValidate(ctx context.Context, params api. return err } - svc.Nats.Publish("maptest.mapfixes.validate", []byte(j)) + _, err = svc.Nats.Publish("maptest.mapfixes.validate", []byte(j)) + if err != nil { + return err + } + + event_data := model.AuditEventDataAction{ + TargetStatus: uint32(target_status), + } + + EventData, err := json.Marshal(event_data) + if err != nil { + return err + } + + _, err = svc.DB.AuditEvents().Create(ctx, model.AuditEvent{ + ID: 0, + User: userId, + ResourceType: model.ResourceMapfix, + ResourceID: params.MapfixID, + EventType: model.AuditEventTypeAction, + EventData: EventData, + }) + if err != nil { + return err + } return nil } @@ -577,9 +813,15 @@ func (svc *Service) ActionMapfixRetryValidate(ctx context.Context, params api.Ac return ErrPermissionDeniedNeedRoleMapReview } + userId, err := userInfo.GetUserID() + if err != nil { + return err + } + // transaction + target_status := model.MapfixStatusValidating smap := datastore.Optional() - smap.Add("status_id", model.MapfixStatusValidating) + smap.Add("status_id", target_status) mapfix, err := svc.DB.Mapfixes().IfStatusThenUpdateAndGet(ctx, params.MapfixID, []model.MapfixStatus{model.MapfixStatusAcceptedUnvalidated}, smap) if err != nil { return err @@ -602,7 +844,31 @@ func (svc *Service) ActionMapfixRetryValidate(ctx context.Context, params api.Ac return err } - svc.Nats.Publish("maptest.mapfixes.validate", []byte(j)) + _, err = svc.Nats.Publish("maptest.mapfixes.validate", []byte(j)) + if err != nil { + return err + } + + event_data := model.AuditEventDataAction{ + TargetStatus: uint32(target_status), + } + + EventData, err := json.Marshal(event_data) + if err != nil { + return err + } + + _, err = svc.DB.AuditEvents().Create(ctx, model.AuditEvent{ + ID: 0, + User: userId, + ResourceType: model.ResourceMapfix, + ResourceID: params.MapfixID, + EventType: model.AuditEventTypeAction, + EventData: EventData, + }) + if err != nil { + return err + } return nil } @@ -627,6 +893,11 @@ func (svc *Service) ActionMapfixAccepted(ctx context.Context, params api.ActionM return ErrPermissionDeniedNeedRoleMapReview } + userId, err := userInfo.GetUserID() + if err != nil { + return err + } + // check when mapfix was updated mapfix, err := svc.DB.Mapfixes().Get(ctx, params.MapfixID) if err != nil { @@ -638,8 +909,35 @@ func (svc *Service) ActionMapfixAccepted(ctx context.Context, params api.ActionM } // transaction + target_status := model.MapfixStatusAcceptedUnvalidated smap := datastore.Optional() - smap.Add("status_id", model.MapfixStatusAcceptedUnvalidated) + smap.Add("status_id", target_status) smap.Add("status_message", "Manually forced reset") - return svc.DB.Mapfixes().IfStatusThenUpdate(ctx, params.MapfixID, []model.MapfixStatus{model.MapfixStatusValidating}, smap) + err = svc.DB.Mapfixes().IfStatusThenUpdate(ctx, params.MapfixID, []model.MapfixStatus{model.MapfixStatusValidating}, smap) + if err != nil { + return err + } + + event_data := model.AuditEventDataAction{ + TargetStatus: uint32(target_status), + } + + EventData, err := json.Marshal(event_data) + if err != nil { + return err + } + + _, err = svc.DB.AuditEvents().Create(ctx, model.AuditEvent{ + ID: 0, + User: userId, + ResourceType: model.ResourceMapfix, + ResourceID: params.MapfixID, + EventType: model.AuditEventTypeAction, + EventData: EventData, + }) + if err != nil { + return err + } + + return nil } diff --git a/pkg/service/operations.go b/pkg/service/operations.go index eb48adc..5a906f4 100644 --- a/pkg/service/operations.go +++ b/pkg/service/operations.go @@ -24,11 +24,13 @@ func (svc *Service) GetOperation(ctx context.Context, params api.GetOperationPar return nil, err } - has_role, err := userInfo.IsSubmitter(uint64(operation.Owner)) + userId, err := userInfo.GetUserID() if err != nil { return nil, err } - // check if caller is operation owner + + // check if caller is the submitter + has_role := userId == operation.Owner if !has_role { return nil, ErrPermissionDeniedNotSubmitter } @@ -36,7 +38,7 @@ func (svc *Service) GetOperation(ctx context.Context, params api.GetOperationPar return &api.Operation{ OperationID: operation.ID, Date: operation.CreatedAt.Unix(), - Owner: operation.Owner, + Owner: int64(operation.Owner), Status: int32(operation.StatusID), StatusMessage: operation.StatusMessage, Path: operation.Path, diff --git a/pkg/service/security.go b/pkg/service/security.go index 2896aca..33f283b 100644 --- a/pkg/service/security.go +++ b/pkg/service/security.go @@ -88,13 +88,6 @@ func (usr UserInfoHandle) Validate() (bool, error) { } return validate.Valid, nil } -func (usr UserInfoHandle) IsSubmitter(submitter uint64) (bool, error) { - userId, err := usr.GetUserID() - if err != nil { - return false, err - } - return userId == submitter, nil -} func (usr UserInfoHandle) hasRoles(wantRoles Roles) (bool, error) { haveroles, err := usr.GetRoles() if err != nil { diff --git a/pkg/service/submissions.go b/pkg/service/submissions.go index 1bd630e..e7963d1 100644 --- a/pkg/service/submissions.go +++ b/pkg/service/submissions.go @@ -93,7 +93,7 @@ func (svc *Service) CreateSubmission(ctx context.Context, request *api.Submissio } operation, err := svc.DB.Operations().Create(ctx, model.Operation{ - Owner: int64(userId), + Owner: userId, StatusID: model.OperationStatusCreated, }) if err != nil { @@ -110,7 +110,10 @@ func (svc *Service) CreateSubmission(ctx context.Context, request *api.Submissio return nil, err } - svc.Nats.Publish("maptest.submissions.create", []byte(j)) + _, err = svc.Nats.Publish("maptest.submissions.create", []byte(j)) + if err != nil { + return nil, err + } return &api.OperationID{ OperationID: operation.ID, @@ -248,22 +251,58 @@ func (svc *Service) UpdateSubmissionModel(ctx context.Context, params api.Update return err } - has_role, err := userInfo.IsSubmitter(uint64(submission.Submitter)) + userId, err := userInfo.GetUserID() if err != nil { return err } + // check if caller is the submitter + has_role := userId == submission.Submitter if !has_role { return ErrPermissionDeniedNotSubmitter } + OldModelID := submission.AssetID + OldModelVersion := submission.AssetVersion + NewModelID := uint64(params.ModelID) + NewModelVersion := uint64(params.ModelVersion) + // check if Status is ChangesRequested|Submitted|UnderConstruction pmap := datastore.Optional() - pmap.Add("asset_id", params.ModelID) - pmap.Add("asset_version", params.ModelVersion) + pmap.Add("asset_id", NewModelID) + pmap.Add("asset_version", NewModelVersion) //always reset completed when model changes pmap.Add("completed", false) - return svc.DB.Submissions().IfStatusThenUpdate(ctx, params.SubmissionID, []model.SubmissionStatus{model.SubmissionStatusChangesRequested, model.SubmissionStatusUnderConstruction}, pmap) + err = svc.DB.Submissions().IfStatusThenUpdate(ctx, params.SubmissionID, []model.SubmissionStatus{model.SubmissionStatusChangesRequested, model.SubmissionStatusUnderConstruction}, pmap) + if err != nil { + return err + } + + event_data := model.AuditEventDataChangeModel{ + OldModelID: OldModelID, + OldModelVersion: OldModelVersion, + NewModelID: NewModelID, + NewModelVersion: NewModelVersion, + } + + EventData, err := json.Marshal(event_data) + if err != nil { + return err + } + + _, err = svc.DB.AuditEvents().Create(ctx, model.AuditEvent{ + ID: 0, + User: userId, + ResourceType: model.ResourceSubmission, + ResourceID: submission.ID, + EventType: model.AuditEventTypeChangeModel, + EventData: EventData, + }) + if err != nil { + return err + } + + return nil } // ActionSubmissionReject invokes actionSubmissionReject operation. @@ -286,10 +325,42 @@ func (svc *Service) ActionSubmissionReject(ctx context.Context, params api.Actio return ErrPermissionDeniedNeedRoleMapReview } + userId, err := userInfo.GetUserID() + if err != nil { + return err + } + // transaction + target_status := model.SubmissionStatusRejected smap := datastore.Optional() - smap.Add("status_id", model.SubmissionStatusRejected) - return svc.DB.Submissions().IfStatusThenUpdate(ctx, params.SubmissionID, []model.SubmissionStatus{model.SubmissionStatusSubmitted}, smap) + smap.Add("status_id", target_status) + err = svc.DB.Submissions().IfStatusThenUpdate(ctx, params.SubmissionID, []model.SubmissionStatus{model.SubmissionStatusSubmitted}, smap) + if err != nil { + return err + } + + event_data := model.AuditEventDataAction{ + TargetStatus: uint32(target_status), + } + + EventData, err := json.Marshal(event_data) + if err != nil { + return err + } + + _, err = svc.DB.AuditEvents().Create(ctx, model.AuditEvent{ + ID: 0, + User: userId, + ResourceType: model.ResourceSubmission, + ResourceID: params.SubmissionID, + EventType: model.AuditEventTypeAction, + EventData: EventData, + }) + if err != nil { + return err + } + + return nil } // ActionSubmissionRequestChanges invokes actionSubmissionRequestChanges operation. @@ -312,10 +383,42 @@ func (svc *Service) ActionSubmissionRequestChanges(ctx context.Context, params a return ErrPermissionDeniedNeedRoleMapReview } + userId, err := userInfo.GetUserID() + if err != nil { + return err + } + // transaction + target_status := model.SubmissionStatusChangesRequested smap := datastore.Optional() - smap.Add("status_id", model.SubmissionStatusChangesRequested) - return svc.DB.Submissions().IfStatusThenUpdate(ctx, params.SubmissionID, []model.SubmissionStatus{model.SubmissionStatusValidated, model.SubmissionStatusAcceptedUnvalidated, model.SubmissionStatusSubmitted}, smap) + smap.Add("status_id", target_status) + err = svc.DB.Submissions().IfStatusThenUpdate(ctx, params.SubmissionID, []model.SubmissionStatus{model.SubmissionStatusValidated, model.SubmissionStatusAcceptedUnvalidated, model.SubmissionStatusSubmitted}, smap) + if err != nil { + return err + } + + event_data := model.AuditEventDataAction{ + TargetStatus: uint32(target_status), + } + + EventData, err := json.Marshal(event_data) + if err != nil { + return err + } + + _, err = svc.DB.AuditEvents().Create(ctx, model.AuditEvent{ + ID: 0, + User: userId, + ResourceType: model.ResourceSubmission, + ResourceID: params.SubmissionID, + EventType: model.AuditEventTypeAction, + EventData: EventData, + }) + if err != nil { + return err + } + + return nil } // ActionSubmissionRevoke invokes actionSubmissionRevoke operation. @@ -335,19 +438,48 @@ func (svc *Service) ActionSubmissionRevoke(ctx context.Context, params api.Actio return err } - has_role, err := userInfo.IsSubmitter(uint64(submission.Submitter)) + userId, err := userInfo.GetUserID() if err != nil { return err } + // check if caller is the submitter + has_role := userId == submission.Submitter if !has_role { return ErrPermissionDeniedNotSubmitter } // transaction + target_status := model.SubmissionStatusUnderConstruction smap := datastore.Optional() - smap.Add("status_id", model.SubmissionStatusUnderConstruction) - return svc.DB.Submissions().IfStatusThenUpdate(ctx, params.SubmissionID, []model.SubmissionStatus{model.SubmissionStatusSubmitted, model.SubmissionStatusChangesRequested}, smap) + smap.Add("status_id", target_status) + err = svc.DB.Submissions().IfStatusThenUpdate(ctx, params.SubmissionID, []model.SubmissionStatus{model.SubmissionStatusSubmitted, model.SubmissionStatusChangesRequested}, smap) + if err != nil { + return err + } + + event_data := model.AuditEventDataAction{ + TargetStatus: uint32(target_status), + } + + EventData, err := json.Marshal(event_data) + if err != nil { + return err + } + + _, err = svc.DB.AuditEvents().Create(ctx, model.AuditEvent{ + ID: 0, + User: userId, + ResourceType: model.ResourceSubmission, + ResourceID: params.SubmissionID, + EventType: model.AuditEventTypeAction, + EventData: EventData, + }) + if err != nil { + return err + } + + return nil } // ActionSubmissionSubmit invokes actionSubmissionSubmit operation. @@ -367,19 +499,48 @@ func (svc *Service) ActionSubmissionSubmit(ctx context.Context, params api.Actio return err } - has_role, err := userInfo.IsSubmitter(uint64(submission.Submitter)) + userId, err := userInfo.GetUserID() if err != nil { return err } + // check if caller is the submitter + has_role := userId == submission.Submitter if !has_role { return ErrPermissionDeniedNotSubmitter } // transaction + target_status := model.SubmissionStatusSubmitted smap := datastore.Optional() - smap.Add("status_id", model.SubmissionStatusSubmitted) - return svc.DB.Submissions().IfStatusThenUpdate(ctx, params.SubmissionID, []model.SubmissionStatus{model.SubmissionStatusUnderConstruction, model.SubmissionStatusChangesRequested}, smap) + smap.Add("status_id", target_status) + err = svc.DB.Submissions().IfStatusThenUpdate(ctx, params.SubmissionID, []model.SubmissionStatus{model.SubmissionStatusUnderConstruction, model.SubmissionStatusChangesRequested}, smap) + if err != nil { + return err + } + + event_data := model.AuditEventDataAction{ + TargetStatus: uint32(target_status), + } + + EventData, err := json.Marshal(event_data) + if err != nil { + return err + } + + _, err = svc.DB.AuditEvents().Create(ctx, model.AuditEvent{ + ID: 0, + User: userId, + ResourceType: model.ResourceSubmission, + ResourceID: params.SubmissionID, + EventType: model.AuditEventTypeAction, + EventData: EventData, + }) + if err != nil { + return err + } + + return nil } // ActionSubmissionTriggerUpload invokes actionSubmissionTriggerUpload operation. @@ -402,9 +563,15 @@ func (svc *Service) ActionSubmissionTriggerUpload(ctx context.Context, params ap return ErrPermissionDeniedNeedRoleMapUpload } + userId, err := userInfo.GetUserID() + if err != nil { + return err + } + // transaction + target_status := model.SubmissionStatusUploading smap := datastore.Optional() - smap.Add("status_id", model.SubmissionStatusUploading) + smap.Add("status_id", target_status) submission, err := svc.DB.Submissions().IfStatusThenUpdateAndGet(ctx, params.SubmissionID, []model.SubmissionStatus{model.SubmissionStatusValidated}, smap) if err != nil { return err @@ -426,12 +593,36 @@ func (svc *Service) ActionSubmissionTriggerUpload(ctx context.Context, params ap return err } - svc.Nats.Publish("maptest.submissions.upload", []byte(j)) + _, err = svc.Nats.Publish("maptest.submissions.upload", []byte(j)) + if err != nil { + return err + } } else { // refuse to operate return ErrUploadedAssetIDAlreadyExists } + event_data := model.AuditEventDataAction{ + TargetStatus: uint32(target_status), + } + + EventData, err := json.Marshal(event_data) + if err != nil { + return err + } + + _, err = svc.DB.AuditEvents().Create(ctx, model.AuditEvent{ + ID: 0, + User: userId, + ResourceType: model.ResourceSubmission, + ResourceID: params.SubmissionID, + EventType: model.AuditEventTypeAction, + EventData: EventData, + }) + if err != nil { + return err + } + return nil } @@ -455,6 +646,11 @@ func (svc *Service) ActionSubmissionValidated(ctx context.Context, params api.Ac return ErrPermissionDeniedNeedRoleMapUpload } + userId, err := userInfo.GetUserID() + if err != nil { + return err + } + // check when submission was updated submission, err := svc.DB.Submissions().Get(ctx, params.SubmissionID) if err != nil { @@ -466,9 +662,36 @@ func (svc *Service) ActionSubmissionValidated(ctx context.Context, params api.Ac } // transaction + target_status := model.SubmissionStatusValidated smap := datastore.Optional() - smap.Add("status_id", model.SubmissionStatusValidated) - return svc.DB.Submissions().IfStatusThenUpdate(ctx, params.SubmissionID, []model.SubmissionStatus{model.SubmissionStatusUploading}, smap) + smap.Add("status_id", target_status) + err = svc.DB.Submissions().IfStatusThenUpdate(ctx, params.SubmissionID, []model.SubmissionStatus{model.SubmissionStatusUploading}, smap) + if err != nil { + return err + } + + event_data := model.AuditEventDataAction{ + TargetStatus: uint32(target_status), + } + + EventData, err := json.Marshal(event_data) + if err != nil { + return err + } + + _, err = svc.DB.AuditEvents().Create(ctx, model.AuditEvent{ + ID: 0, + User: userId, + ResourceType: model.ResourceSubmission, + ResourceID: params.SubmissionID, + EventType: model.AuditEventTypeAction, + EventData: EventData, + }) + if err != nil { + return err + } + + return nil } // ActionSubmissionTriggerValidate invokes actionSubmissionTriggerValidate operation. @@ -497,18 +720,21 @@ func (svc *Service) ActionSubmissionTriggerValidate(ctx context.Context, params return err } - has_role, err = userInfo.IsSubmitter(uint64(submission.Submitter)) + userId, err := userInfo.GetUserID() if err != nil { return err } + // check if caller is NOT the submitter + has_role = userId == submission.Submitter if has_role { return ErrAcceptOwnSubmission } // transaction + target_status := model.SubmissionStatusValidating smap := datastore.Optional() - smap.Add("status_id", model.SubmissionStatusValidating) + smap.Add("status_id", target_status) submission, err = svc.DB.Submissions().IfStatusThenUpdateAndGet(ctx, params.SubmissionID, []model.SubmissionStatus{model.SubmissionStatusSubmitted}, smap) if err != nil { return err @@ -531,7 +757,31 @@ func (svc *Service) ActionSubmissionTriggerValidate(ctx context.Context, params return err } - svc.Nats.Publish("maptest.submissions.validate", []byte(j)) + _, err = svc.Nats.Publish("maptest.submissions.validate", []byte(j)) + if err != nil { + return err + } + + event_data := model.AuditEventDataAction{ + TargetStatus: uint32(target_status), + } + + EventData, err := json.Marshal(event_data) + if err != nil { + return err + } + + _, err = svc.DB.AuditEvents().Create(ctx, model.AuditEvent{ + ID: 0, + User: userId, + ResourceType: model.ResourceSubmission, + ResourceID: params.SubmissionID, + EventType: model.AuditEventTypeAction, + EventData: EventData, + }) + if err != nil { + return err + } return nil } @@ -556,9 +806,15 @@ func (svc *Service) ActionSubmissionRetryValidate(ctx context.Context, params ap return ErrPermissionDeniedNeedRoleMapReview } + userId, err := userInfo.GetUserID() + if err != nil { + return err + } + // transaction + target_status := model.SubmissionStatusValidating smap := datastore.Optional() - smap.Add("status_id", model.SubmissionStatusValidating) + smap.Add("status_id", target_status) submission, err := svc.DB.Submissions().IfStatusThenUpdateAndGet(ctx, params.SubmissionID, []model.SubmissionStatus{model.SubmissionStatusAcceptedUnvalidated}, smap) if err != nil { return err @@ -581,7 +837,31 @@ func (svc *Service) ActionSubmissionRetryValidate(ctx context.Context, params ap return err } - svc.Nats.Publish("maptest.submissions.validate", []byte(j)) + _, err = svc.Nats.Publish("maptest.submissions.validate", []byte(j)) + if err != nil { + return err + } + + event_data := model.AuditEventDataAction{ + TargetStatus: uint32(target_status), + } + + EventData, err := json.Marshal(event_data) + if err != nil { + return err + } + + _, err = svc.DB.AuditEvents().Create(ctx, model.AuditEvent{ + ID: 0, + User: userId, + ResourceType: model.ResourceSubmission, + ResourceID: params.SubmissionID, + EventType: model.AuditEventTypeAction, + EventData: EventData, + }) + if err != nil { + return err + } return nil } @@ -606,6 +886,11 @@ func (svc *Service) ActionSubmissionAccepted(ctx context.Context, params api.Act return ErrPermissionDeniedNeedRoleMapReview } + userId, err := userInfo.GetUserID() + if err != nil { + return err + } + // check when submission was updated submission, err := svc.DB.Submissions().Get(ctx, params.SubmissionID) if err != nil { @@ -617,10 +902,37 @@ func (svc *Service) ActionSubmissionAccepted(ctx context.Context, params api.Act } // transaction + target_status := model.SubmissionStatusAcceptedUnvalidated smap := datastore.Optional() - smap.Add("status_id", model.SubmissionStatusAcceptedUnvalidated) + smap.Add("status_id", target_status) smap.Add("status_message", "Manually forced reset") - return svc.DB.Submissions().IfStatusThenUpdate(ctx, params.SubmissionID, []model.SubmissionStatus{model.SubmissionStatusValidating}, smap) + err = svc.DB.Submissions().IfStatusThenUpdate(ctx, params.SubmissionID, []model.SubmissionStatus{model.SubmissionStatusValidating}, smap) + if err != nil { + return err + } + + event_data := model.AuditEventDataAction{ + TargetStatus: uint32(target_status), + } + + EventData, err := json.Marshal(event_data) + if err != nil { + return err + } + + _, err = svc.DB.AuditEvents().Create(ctx, model.AuditEvent{ + ID: 0, + User: userId, + ResourceType: model.ResourceSubmission, + ResourceID: params.SubmissionID, + EventType: model.AuditEventTypeAction, + EventData: EventData, + }) + if err != nil { + return err + } + + return nil } // ReleaseSubmissions invokes releaseSubmissions operation. diff --git a/pkg/service_internal/mapfixes.go b/pkg/service_internal/mapfixes.go index b3e428f..5526b20 100644 --- a/pkg/service_internal/mapfixes.go +++ b/pkg/service_internal/mapfixes.go @@ -2,6 +2,7 @@ package service_internal import ( "context" + "encoding/json" "errors" "fmt" @@ -34,13 +35,43 @@ var( // // POST /mapfixes/{MapfixID}/validated-model func (svc *Service) UpdateMapfixValidatedModel(ctx context.Context, params internal.UpdateMapfixValidatedModelParams) error { + ValidatedModelID := uint64(params.ValidatedModelID) + ValidatedModelVersion := uint64(params.ValidatedModelVersion) + // check if Status is ChangesRequested|Submitted|UnderConstruction pmap := datastore.Optional() - pmap.Add("validated_asset_id", params.ValidatedModelID) - pmap.Add("validated_asset_version", params.ValidatedModelVersion) + pmap.Add("validated_asset_id", ValidatedModelID) + pmap.Add("validated_asset_version", 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) + err := svc.DB.Mapfixes().IfStatusThenUpdate(ctx, params.MapfixID, []model.MapfixStatus{model.MapfixStatusValidating}, pmap) + if err != nil { + return err + } + + event_data := model.AuditEventDataChangeValidatedModel{ + ValidatedModelID: ValidatedModelID, + ValidatedModelVersion: ValidatedModelVersion, + } + + EventData, err := json.Marshal(event_data) + if err != nil { + return err + } + + _, err = svc.DB.AuditEvents().Create(ctx, model.AuditEvent{ + ID: 0, + User: ValidtorUserID, + ResourceType: model.ResourceMapfix, + ResourceID: params.MapfixID, + EventType: model.AuditEventTypeChangeValidatedModel, + EventData: EventData, + }) + if err != nil { + return err + } + + return nil } // ActionMapfixValidate invokes actionMapfixValidate operation. @@ -62,10 +93,37 @@ func (svc *Service) ActionMapfixValidated(ctx context.Context, params internal.A // POST /mapfixes/{MapfixID}/status/validator-failed func (svc *Service) ActionMapfixAccepted(ctx context.Context, params internal.ActionMapfixAcceptedParams) error { // transaction + target_status := model.MapfixStatusAcceptedUnvalidated smap := datastore.Optional() - smap.Add("status_id", model.MapfixStatusAcceptedUnvalidated) + smap.Add("status_id", target_status) smap.Add("status_message", params.StatusMessage) - return svc.DB.Mapfixes().IfStatusThenUpdate(ctx, params.MapfixID, []model.MapfixStatus{model.MapfixStatusValidating}, smap) + err := svc.DB.Mapfixes().IfStatusThenUpdate(ctx, params.MapfixID, []model.MapfixStatus{model.MapfixStatusValidating}, smap) + if err != nil { + return err + } + + event_data := model.AuditEventDataAction{ + TargetStatus: uint32(target_status), + } + + EventData, err := json.Marshal(event_data) + if err != nil { + return err + } + + _, err = svc.DB.AuditEvents().Create(ctx, model.AuditEvent{ + ID: 0, + User: ValidtorUserID, + ResourceType: model.ResourceMapfix, + ResourceID: params.MapfixID, + EventType: model.AuditEventTypeAction, + EventData: EventData, + }) + if err != nil { + return err + } + + return nil } // ActionMapfixUploaded implements actionMapfixUploaded operation. @@ -75,9 +133,36 @@ func (svc *Service) ActionMapfixAccepted(ctx context.Context, params internal.Ac // POST /mapfixes/{MapfixID}/status/validator-uploaded func (svc *Service) ActionMapfixUploaded(ctx context.Context, params internal.ActionMapfixUploadedParams) error { // transaction + target_status := model.MapfixStatusUploaded smap := datastore.Optional() - smap.Add("status_id", model.MapfixStatusUploaded) - return svc.DB.Mapfixes().IfStatusThenUpdate(ctx, params.MapfixID, []model.MapfixStatus{model.MapfixStatusUploading}, smap) + smap.Add("status_id", target_status) + err := svc.DB.Mapfixes().IfStatusThenUpdate(ctx, params.MapfixID, []model.MapfixStatus{model.MapfixStatusUploading}, smap) + if err != nil { + return err + } + + event_data := model.AuditEventDataAction{ + TargetStatus: uint32(target_status), + } + + EventData, err := json.Marshal(event_data) + if err != nil { + return err + } + + _, err = svc.DB.AuditEvents().Create(ctx, model.AuditEvent{ + ID: 0, + User: ValidtorUserID, + ResourceType: model.ResourceMapfix, + ResourceID: params.MapfixID, + EventType: model.AuditEventTypeAction, + EventData: EventData, + }) + if err != nil { + return err + } + + return nil } // POST /mapfixes @@ -121,7 +206,7 @@ func (svc *Service) CreateMapfix(ctx context.Context, request *internal.MapfixCr // check if user owns asset // TODO: allow bypass by admin - if operation.Owner != request.AssetOwner { + if operation.Owner != Submitter { return nil, ErrNotAssetOwner } diff --git a/pkg/service_internal/service_internal.go b/pkg/service_internal/service_internal.go index 6b4d94f..6aefe80 100644 --- a/pkg/service_internal/service_internal.go +++ b/pkg/service_internal/service_internal.go @@ -3,12 +3,17 @@ package service_internal import ( "context" "errors" + "math" "git.itzana.me/strafesnet/maps-service/pkg/datastore" internal "git.itzana.me/strafesnet/maps-service/pkg/internal" "github.com/nats-io/nats.go" ) +const ( + ValidtorUserID uint64 = uint64(math.MaxInt64) +) + var ( ErrNegativeID = errors.New("A negative ID was provided") ) diff --git a/pkg/service_internal/submissions.go b/pkg/service_internal/submissions.go index 2fc0465..164eb60 100644 --- a/pkg/service_internal/submissions.go +++ b/pkg/service_internal/submissions.go @@ -2,6 +2,7 @@ package service_internal import ( "context" + "encoding/json" "errors" "fmt" @@ -33,13 +34,43 @@ var( // // POST /submissions/{SubmissionID}/validated-model func (svc *Service) UpdateSubmissionValidatedModel(ctx context.Context, params internal.UpdateSubmissionValidatedModelParams) error { + ValidatedModelID := uint64(params.ValidatedModelID) + ValidatedModelVersion := uint64(params.ValidatedModelVersion) + // check if Status is ChangesRequested|Submitted|UnderConstruction pmap := datastore.Optional() - pmap.Add("validated_asset_id", params.ValidatedModelID) - pmap.Add("validated_asset_version", params.ValidatedModelVersion) + pmap.Add("validated_asset_id", ValidatedModelID) + pmap.Add("validated_asset_version", ValidatedModelVersion) // DO NOT reset completed when validated model is updated // pmap.Add("completed", false) - return svc.DB.Submissions().IfStatusThenUpdate(ctx, params.SubmissionID, []model.SubmissionStatus{model.SubmissionStatusValidating}, pmap) + err := svc.DB.Submissions().IfStatusThenUpdate(ctx, params.SubmissionID, []model.SubmissionStatus{model.SubmissionStatusValidating}, pmap) + if err != nil { + return err + } + + event_data := model.AuditEventDataChangeValidatedModel{ + ValidatedModelID: ValidatedModelID, + ValidatedModelVersion: ValidatedModelVersion, + } + + EventData, err := json.Marshal(event_data) + if err != nil { + return err + } + + _, err = svc.DB.AuditEvents().Create(ctx, model.AuditEvent{ + ID: 0, + User: ValidtorUserID, + ResourceType: model.ResourceSubmission, + ResourceID: params.SubmissionID, + EventType: model.AuditEventTypeChangeValidatedModel, + EventData: EventData, + }) + if err != nil { + return err + } + + return nil } // ActionSubmissionValidate invokes actionSubmissionValidate operation. @@ -49,9 +80,36 @@ func (svc *Service) UpdateSubmissionValidatedModel(ctx context.Context, params i // POST /submissions/{SubmissionID}/status/validator-validated func (svc *Service) ActionSubmissionValidated(ctx context.Context, params internal.ActionSubmissionValidatedParams) error { // transaction + target_status := model.SubmissionStatusValidated smap := datastore.Optional() - smap.Add("status_id", model.SubmissionStatusValidated) - return svc.DB.Submissions().IfStatusThenUpdate(ctx, params.SubmissionID, []model.SubmissionStatus{model.SubmissionStatusValidating}, smap) + smap.Add("status_id", target_status) + err := svc.DB.Submissions().IfStatusThenUpdate(ctx, params.SubmissionID, []model.SubmissionStatus{model.SubmissionStatusValidating}, smap) + if err != nil { + return err + } + + event_data := model.AuditEventDataAction{ + TargetStatus: uint32(target_status), + } + + EventData, err := json.Marshal(event_data) + if err != nil { + return err + } + + _, err = svc.DB.AuditEvents().Create(ctx, model.AuditEvent{ + ID: 0, + User: ValidtorUserID, + ResourceType: model.ResourceSubmission, + ResourceID: params.SubmissionID, + EventType: model.AuditEventTypeAction, + EventData: EventData, + }) + if err != nil { + return err + } + + return nil } // ActionSubmissionAccepted implements actionSubmissionAccepted operation. @@ -61,10 +119,37 @@ func (svc *Service) ActionSubmissionValidated(ctx context.Context, params intern // POST /submissions/{SubmissionID}/status/validator-failed func (svc *Service) ActionSubmissionAccepted(ctx context.Context, params internal.ActionSubmissionAcceptedParams) error { // transaction + target_status := model.SubmissionStatusAcceptedUnvalidated smap := datastore.Optional() - smap.Add("status_id", model.SubmissionStatusAcceptedUnvalidated) + smap.Add("status_id", target_status) smap.Add("status_message", params.StatusMessage) - return svc.DB.Submissions().IfStatusThenUpdate(ctx, params.SubmissionID, []model.SubmissionStatus{model.SubmissionStatusValidating}, smap) + err := svc.DB.Submissions().IfStatusThenUpdate(ctx, params.SubmissionID, []model.SubmissionStatus{model.SubmissionStatusValidating}, smap) + if err != nil { + return err + } + + event_data := model.AuditEventDataAction{ + TargetStatus: uint32(target_status), + } + + EventData, err := json.Marshal(event_data) + if err != nil { + return err + } + + _, err = svc.DB.AuditEvents().Create(ctx, model.AuditEvent{ + ID: 0, + User: ValidtorUserID, + ResourceType: model.ResourceSubmission, + ResourceID: params.SubmissionID, + EventType: model.AuditEventTypeAction, + EventData: EventData, + }) + if err != nil { + return err + } + + return nil } // ActionSubmissionUploaded implements actionSubmissionUploaded operation. @@ -74,10 +159,37 @@ func (svc *Service) ActionSubmissionAccepted(ctx context.Context, params interna // POST /submissions/{SubmissionID}/status/validator-uploaded func (svc *Service) ActionSubmissionUploaded(ctx context.Context, params internal.ActionSubmissionUploadedParams) error { // transaction + target_status := model.SubmissionStatusUploaded smap := datastore.Optional() - smap.Add("status_id", model.SubmissionStatusUploaded) + smap.Add("status_id", target_status) smap.Add("uploaded_asset_id", params.UploadedAssetID) - return svc.DB.Submissions().IfStatusThenUpdate(ctx, params.SubmissionID, []model.SubmissionStatus{model.SubmissionStatusUploading}, smap) + err := svc.DB.Submissions().IfStatusThenUpdate(ctx, params.SubmissionID, []model.SubmissionStatus{model.SubmissionStatusUploading}, smap) + if err != nil { + return err + } + + event_data := model.AuditEventDataAction{ + TargetStatus: uint32(target_status), + } + + EventData, err := json.Marshal(event_data) + if err != nil { + return err + } + + _, err = svc.DB.AuditEvents().Create(ctx, model.AuditEvent{ + ID: 0, + User: ValidtorUserID, + ResourceType: model.ResourceSubmission, + ResourceID: params.SubmissionID, + EventType: model.AuditEventTypeAction, + EventData: EventData, + }) + if err != nil { + return err + } + + return nil } // POST /submissions @@ -119,7 +231,7 @@ func (svc *Service) CreateSubmission(ctx context.Context, request *internal.Subm // check if user owns asset // TODO: allow bypass by admin - if operation.Owner != request.AssetOwner { + if operation.Owner != Submitter { return nil, ErrNotAssetOwner }