Compare commits

...

7 Commits

Author SHA1 Message Date
fb76be406e submissions: accept CheckList in internal changes requested
All checks were successful
continuous-integration/drone/push Build is passing
continuous-integration/drone/pr Build is passing
2025-06-07 23:53:17 -07:00
9bf991aebb validation: hijack check system to report internal error
This should really use the dedicated error audit event somehow
2025-06-07 23:53:17 -07:00
c108d98c8d validation: plumb out CheckList 2025-06-07 23:53:17 -07:00
70d19ab7c0 submissions-api: update changes requested internal endpoint 2025-06-07 23:53:17 -07:00
a3e80e5048 openapi: generate 2025-06-07 23:53:17 -07:00
0ce9abc954 openapi: send detailed CheckList on internal changes requested 2025-06-07 23:53:17 -07:00
c3aba5a56f submissions: AuditEvent CheckReport 2025-06-07 23:53:17 -07:00
19 changed files with 766 additions and 287 deletions

View File

@@ -116,13 +116,12 @@ paths:
- Mapfixes
parameters:
- $ref: '#/components/parameters/MapfixID'
- name: ErrorMessage
in: query
required: true
schema:
type: string
minLength: 0
maxLength: 4096
requestBody:
required: true
content:
application/json:
schema:
$ref: '#/components/schemas/CheckList'
responses:
"204":
description: Successful response
@@ -321,13 +320,12 @@ paths:
- Submissions
parameters:
- $ref: '#/components/parameters/SubmissionID'
- name: ErrorMessage
in: query
required: true
schema:
type: string
minLength: 0
maxLength: 4096
requestBody:
required: true
content:
application/json:
schema:
$ref: '#/components/schemas/CheckList'
responses:
"204":
description: Successful response
@@ -847,6 +845,28 @@ components:
type: integer
format: int32
minimum: 0
Check:
required:
- Name
- Summary
- Passed
- Details
type: object
properties:
Name:
type: string
maxLength: 128
Summary:
type: string
maxLength: 4096
Passed:
type: boolean
Details:
type: object
CheckList:
type: array
items:
$ref: "#/components/schemas/Check"
Error:
description: Represents error object
type: object

View File

@@ -39,7 +39,7 @@ type Invoker interface {
// (Internal endpoint) Role Validator changes status from Submitting -> ChangesRequested.
//
// POST /mapfixes/{MapfixID}/status/validator-request-changes
ActionMapfixRequestChanges(ctx context.Context, params ActionMapfixRequestChangesParams) error
ActionMapfixRequestChanges(ctx context.Context, request CheckList, params ActionMapfixRequestChangesParams) error
// ActionMapfixSubmitted invokes actionMapfixSubmitted operation.
//
// (Internal endpoint) Role Validator changes status from Submitting -> Submitted.
@@ -75,7 +75,7 @@ type Invoker interface {
// (Internal endpoint) Role Validator changes status from Submitting -> ChangesRequested.
//
// POST /submissions/{SubmissionID}/status/validator-request-changes
ActionSubmissionRequestChanges(ctx context.Context, params ActionSubmissionRequestChangesParams) error
ActionSubmissionRequestChanges(ctx context.Context, request CheckList, params ActionSubmissionRequestChangesParams) error
// ActionSubmissionSubmitted invokes actionSubmissionSubmitted operation.
//
// (Internal endpoint) Role Validator changes status from Submitting -> Submitted.
@@ -311,12 +311,12 @@ func (c *Client) sendActionMapfixAccepted(ctx context.Context, params ActionMapf
// (Internal endpoint) Role Validator changes status from Submitting -> ChangesRequested.
//
// POST /mapfixes/{MapfixID}/status/validator-request-changes
func (c *Client) ActionMapfixRequestChanges(ctx context.Context, params ActionMapfixRequestChangesParams) error {
_, err := c.sendActionMapfixRequestChanges(ctx, params)
func (c *Client) ActionMapfixRequestChanges(ctx context.Context, request CheckList, params ActionMapfixRequestChangesParams) error {
_, err := c.sendActionMapfixRequestChanges(ctx, request, params)
return err
}
func (c *Client) sendActionMapfixRequestChanges(ctx context.Context, params ActionMapfixRequestChangesParams) (res *ActionMapfixRequestChangesNoContent, err error) {
func (c *Client) sendActionMapfixRequestChanges(ctx context.Context, request CheckList, params ActionMapfixRequestChangesParams) (res *ActionMapfixRequestChangesNoContent, err error) {
otelAttrs := []attribute.KeyValue{
otelogen.OperationID("actionMapfixRequestChanges"),
semconv.HTTPRequestMethodKey.String("POST"),
@@ -375,29 +375,14 @@ func (c *Client) sendActionMapfixRequestChanges(ctx context.Context, params Acti
pathParts[2] = "/status/validator-request-changes"
uri.AddPathParts(u, pathParts[:]...)
stage = "EncodeQueryParams"
q := uri.NewQueryEncoder()
{
// Encode "ErrorMessage" parameter.
cfg := uri.QueryParameterEncodingConfig{
Name: "ErrorMessage",
Style: uri.QueryStyleForm,
Explode: true,
}
if err := q.EncodeParam(cfg, func(e uri.Encoder) error {
return e.EncodeValue(conv.StringToString(params.ErrorMessage))
}); err != nil {
return res, errors.Wrap(err, "encode query")
}
}
u.RawQuery = q.Values().Encode()
stage = "EncodeRequest"
r, err := ht.NewRequest(ctx, "POST", u)
if err != nil {
return res, errors.Wrap(err, "create request")
}
if err := encodeActionMapfixRequestChangesRequest(request, r); err != nil {
return res, errors.Wrap(err, "encode request")
}
stage = "SendRequest"
resp, err := c.cfg.Client.Do(r)
@@ -971,12 +956,12 @@ func (c *Client) sendActionSubmissionAccepted(ctx context.Context, params Action
// (Internal endpoint) Role Validator changes status from Submitting -> ChangesRequested.
//
// POST /submissions/{SubmissionID}/status/validator-request-changes
func (c *Client) ActionSubmissionRequestChanges(ctx context.Context, params ActionSubmissionRequestChangesParams) error {
_, err := c.sendActionSubmissionRequestChanges(ctx, params)
func (c *Client) ActionSubmissionRequestChanges(ctx context.Context, request CheckList, params ActionSubmissionRequestChangesParams) error {
_, err := c.sendActionSubmissionRequestChanges(ctx, request, params)
return err
}
func (c *Client) sendActionSubmissionRequestChanges(ctx context.Context, params ActionSubmissionRequestChangesParams) (res *ActionSubmissionRequestChangesNoContent, err error) {
func (c *Client) sendActionSubmissionRequestChanges(ctx context.Context, request CheckList, params ActionSubmissionRequestChangesParams) (res *ActionSubmissionRequestChangesNoContent, err error) {
otelAttrs := []attribute.KeyValue{
otelogen.OperationID("actionSubmissionRequestChanges"),
semconv.HTTPRequestMethodKey.String("POST"),
@@ -1035,29 +1020,14 @@ func (c *Client) sendActionSubmissionRequestChanges(ctx context.Context, params
pathParts[2] = "/status/validator-request-changes"
uri.AddPathParts(u, pathParts[:]...)
stage = "EncodeQueryParams"
q := uri.NewQueryEncoder()
{
// Encode "ErrorMessage" parameter.
cfg := uri.QueryParameterEncodingConfig{
Name: "ErrorMessage",
Style: uri.QueryStyleForm,
Explode: true,
}
if err := q.EncodeParam(cfg, func(e uri.Encoder) error {
return e.EncodeValue(conv.StringToString(params.ErrorMessage))
}); err != nil {
return res, errors.Wrap(err, "encode query")
}
}
u.RawQuery = q.Values().Encode()
stage = "EncodeRequest"
r, err := ht.NewRequest(ctx, "POST", u)
if err != nil {
return res, errors.Wrap(err, "create request")
}
if err := encodeActionSubmissionRequestChangesRequest(request, r); err != nil {
return res, errors.Wrap(err, "encode request")
}
stage = "SendRequest"
resp, err := c.cfg.Client.Do(r)

View File

@@ -267,6 +267,21 @@ func (s *Server) handleActionMapfixRequestChangesRequest(args [1]string, argsEsc
s.cfg.ErrorHandler(ctx, w, r, err)
return
}
request, close, err := s.decodeActionMapfixRequestChangesRequest(r)
if err != nil {
err = &ogenerrors.DecodeRequestError{
OperationContext: opErrContext,
Err: err,
}
defer recordError("DecodeRequest", err)
s.cfg.ErrorHandler(ctx, w, r, err)
return
}
defer func() {
if err := close(); err != nil {
recordError("CloseRequest", err)
}
}()
var response *ActionMapfixRequestChangesNoContent
if m := s.cfg.Middleware; m != nil {
@@ -275,22 +290,18 @@ func (s *Server) handleActionMapfixRequestChangesRequest(args [1]string, argsEsc
OperationName: ActionMapfixRequestChangesOperation,
OperationSummary: "(Internal endpoint) Role Validator changes status from Submitting -> ChangesRequested",
OperationID: "actionMapfixRequestChanges",
Body: nil,
Body: request,
Params: middleware.Parameters{
{
Name: "MapfixID",
In: "path",
}: params.MapfixID,
{
Name: "ErrorMessage",
In: "query",
}: params.ErrorMessage,
},
Raw: r,
}
type (
Request = struct{}
Request = CheckList
Params = ActionMapfixRequestChangesParams
Response = *ActionMapfixRequestChangesNoContent
)
@@ -303,12 +314,12 @@ func (s *Server) handleActionMapfixRequestChangesRequest(args [1]string, argsEsc
mreq,
unpackActionMapfixRequestChangesParams,
func(ctx context.Context, request Request, params Params) (response Response, err error) {
err = s.h.ActionMapfixRequestChanges(ctx, params)
err = s.h.ActionMapfixRequestChanges(ctx, request, params)
return response, err
},
)
} else {
err = s.h.ActionMapfixRequestChanges(ctx, params)
err = s.h.ActionMapfixRequestChanges(ctx, request, params)
}
if err != nil {
if errRes, ok := errors.Into[*ErrorStatusCode](err); ok {
@@ -1189,6 +1200,21 @@ func (s *Server) handleActionSubmissionRequestChangesRequest(args [1]string, arg
s.cfg.ErrorHandler(ctx, w, r, err)
return
}
request, close, err := s.decodeActionSubmissionRequestChangesRequest(r)
if err != nil {
err = &ogenerrors.DecodeRequestError{
OperationContext: opErrContext,
Err: err,
}
defer recordError("DecodeRequest", err)
s.cfg.ErrorHandler(ctx, w, r, err)
return
}
defer func() {
if err := close(); err != nil {
recordError("CloseRequest", err)
}
}()
var response *ActionSubmissionRequestChangesNoContent
if m := s.cfg.Middleware; m != nil {
@@ -1197,22 +1223,18 @@ func (s *Server) handleActionSubmissionRequestChangesRequest(args [1]string, arg
OperationName: ActionSubmissionRequestChangesOperation,
OperationSummary: "(Internal endpoint) Role Validator changes status from Submitting -> ChangesRequested",
OperationID: "actionSubmissionRequestChanges",
Body: nil,
Body: request,
Params: middleware.Parameters{
{
Name: "SubmissionID",
In: "path",
}: params.SubmissionID,
{
Name: "ErrorMessage",
In: "query",
}: params.ErrorMessage,
},
Raw: r,
}
type (
Request = struct{}
Request = CheckList
Params = ActionSubmissionRequestChangesParams
Response = *ActionSubmissionRequestChangesNoContent
)
@@ -1225,12 +1247,12 @@ func (s *Server) handleActionSubmissionRequestChangesRequest(args [1]string, arg
mreq,
unpackActionSubmissionRequestChangesParams,
func(ctx context.Context, request Request, params Params) (response Response, err error) {
err = s.h.ActionSubmissionRequestChanges(ctx, params)
err = s.h.ActionSubmissionRequestChanges(ctx, request, params)
return response, err
},
)
} else {
err = s.h.ActionSubmissionRequestChanges(ctx, params)
err = s.h.ActionSubmissionRequestChanges(ctx, request, params)
}
if err != nil {
if errRes, ok := errors.Into[*ErrorStatusCode](err); ok {

View File

@@ -12,6 +12,245 @@ import (
"github.com/ogen-go/ogen/validate"
)
// Encode implements json.Marshaler.
func (s *Check) Encode(e *jx.Encoder) {
e.ObjStart()
s.encodeFields(e)
e.ObjEnd()
}
// encodeFields encodes fields.
func (s *Check) encodeFields(e *jx.Encoder) {
{
e.FieldStart("Name")
e.Str(s.Name)
}
{
e.FieldStart("Summary")
e.Str(s.Summary)
}
{
e.FieldStart("Passed")
e.Bool(s.Passed)
}
{
e.FieldStart("Details")
s.Details.Encode(e)
}
}
var jsonFieldsNameOfCheck = [4]string{
0: "Name",
1: "Summary",
2: "Passed",
3: "Details",
}
// Decode decodes Check from json.
func (s *Check) Decode(d *jx.Decoder) error {
if s == nil {
return errors.New("invalid: unable to decode Check to nil")
}
var requiredBitSet [1]uint8
if err := d.ObjBytes(func(d *jx.Decoder, k []byte) error {
switch string(k) {
case "Name":
requiredBitSet[0] |= 1 << 0
if err := func() error {
v, err := d.Str()
s.Name = string(v)
if err != nil {
return err
}
return nil
}(); err != nil {
return errors.Wrap(err, "decode field \"Name\"")
}
case "Summary":
requiredBitSet[0] |= 1 << 1
if err := func() error {
v, err := d.Str()
s.Summary = string(v)
if err != nil {
return err
}
return nil
}(); err != nil {
return errors.Wrap(err, "decode field \"Summary\"")
}
case "Passed":
requiredBitSet[0] |= 1 << 2
if err := func() error {
v, err := d.Bool()
s.Passed = bool(v)
if err != nil {
return err
}
return nil
}(); err != nil {
return errors.Wrap(err, "decode field \"Passed\"")
}
case "Details":
requiredBitSet[0] |= 1 << 3
if err := func() error {
if err := s.Details.Decode(d); err != nil {
return err
}
return nil
}(); err != nil {
return errors.Wrap(err, "decode field \"Details\"")
}
default:
return d.Skip()
}
return nil
}); err != nil {
return errors.Wrap(err, "decode Check")
}
// Validate required fields.
var failures []validate.FieldError
for i, mask := range [1]uint8{
0b00001111,
} {
if result := (requiredBitSet[i] & mask) ^ mask; result != 0 {
// Mask only required fields and check equality to mask using XOR.
//
// If XOR result is not zero, result is not equal to expected, so some fields are missed.
// Bits of fields which would be set are actually bits of missed fields.
missed := bits.OnesCount8(result)
for bitN := 0; bitN < missed; bitN++ {
bitIdx := bits.TrailingZeros8(result)
fieldIdx := i*8 + bitIdx
var name string
if fieldIdx < len(jsonFieldsNameOfCheck) {
name = jsonFieldsNameOfCheck[fieldIdx]
} else {
name = strconv.Itoa(fieldIdx)
}
failures = append(failures, validate.FieldError{
Name: name,
Error: validate.ErrFieldRequired,
})
// Reset bit.
result &^= 1 << bitIdx
}
}
}
if len(failures) > 0 {
return &validate.Error{Fields: failures}
}
return nil
}
// MarshalJSON implements stdjson.Marshaler.
func (s *Check) MarshalJSON() ([]byte, error) {
e := jx.Encoder{}
s.Encode(&e)
return e.Bytes(), nil
}
// UnmarshalJSON implements stdjson.Unmarshaler.
func (s *Check) UnmarshalJSON(data []byte) error {
d := jx.DecodeBytes(data)
return s.Decode(d)
}
// Encode implements json.Marshaler.
func (s *CheckDetails) Encode(e *jx.Encoder) {
e.ObjStart()
s.encodeFields(e)
e.ObjEnd()
}
// encodeFields encodes fields.
func (s *CheckDetails) encodeFields(e *jx.Encoder) {
}
var jsonFieldsNameOfCheckDetails = [0]string{}
// Decode decodes CheckDetails from json.
func (s *CheckDetails) Decode(d *jx.Decoder) error {
if s == nil {
return errors.New("invalid: unable to decode CheckDetails to nil")
}
if err := d.ObjBytes(func(d *jx.Decoder, k []byte) error {
switch string(k) {
default:
return d.Skip()
}
}); err != nil {
return errors.Wrap(err, "decode CheckDetails")
}
return nil
}
// MarshalJSON implements stdjson.Marshaler.
func (s *CheckDetails) MarshalJSON() ([]byte, error) {
e := jx.Encoder{}
s.Encode(&e)
return e.Bytes(), nil
}
// UnmarshalJSON implements stdjson.Unmarshaler.
func (s *CheckDetails) UnmarshalJSON(data []byte) error {
d := jx.DecodeBytes(data)
return s.Decode(d)
}
// Encode encodes CheckList as json.
func (s CheckList) Encode(e *jx.Encoder) {
unwrapped := []Check(s)
e.ArrStart()
for _, elem := range unwrapped {
elem.Encode(e)
}
e.ArrEnd()
}
// Decode decodes CheckList from json.
func (s *CheckList) Decode(d *jx.Decoder) error {
if s == nil {
return errors.New("invalid: unable to decode CheckList to nil")
}
var unwrapped []Check
if err := func() error {
unwrapped = make([]Check, 0)
if err := d.Arr(func(d *jx.Decoder) error {
var elem Check
if err := elem.Decode(d); err != nil {
return err
}
unwrapped = append(unwrapped, elem)
return nil
}); err != nil {
return err
}
return nil
}(); err != nil {
return errors.Wrap(err, "alias")
}
*s = CheckList(unwrapped)
return nil
}
// MarshalJSON implements stdjson.Marshaler.
func (s CheckList) MarshalJSON() ([]byte, error) {
e := jx.Encoder{}
s.Encode(&e)
return e.Bytes(), nil
}
// UnmarshalJSON implements stdjson.Unmarshaler.
func (s *CheckList) UnmarshalJSON(data []byte) error {
d := jx.DecodeBytes(data)
return s.Decode(d)
}
// Encode implements json.Marshaler.
func (s *Error) Encode(e *jx.Encoder) {
e.ObjStart()

View File

@@ -162,8 +162,7 @@ func decodeActionMapfixAcceptedParams(args [1]string, argsEscaped bool, r *http.
// ActionMapfixRequestChangesParams is parameters of actionMapfixRequestChanges operation.
type ActionMapfixRequestChangesParams struct {
// The unique identifier for a submission.
MapfixID int64
ErrorMessage string
MapfixID int64
}
func unpackActionMapfixRequestChangesParams(packed middleware.Parameters) (params ActionMapfixRequestChangesParams) {
@@ -174,18 +173,10 @@ func unpackActionMapfixRequestChangesParams(packed middleware.Parameters) (param
}
params.MapfixID = packed[key].(int64)
}
{
key := middleware.ParameterKey{
Name: "ErrorMessage",
In: "query",
}
params.ErrorMessage = packed[key].(string)
}
return params
}
func decodeActionMapfixRequestChangesParams(args [1]string, argsEscaped bool, r *http.Request) (params ActionMapfixRequestChangesParams, _ error) {
q := uri.NewQueryDecoder(r.URL.Query())
// Decode path: MapfixID.
if err := func() error {
param := args[0]
@@ -248,58 +239,6 @@ func decodeActionMapfixRequestChangesParams(args [1]string, argsEscaped bool, r
Err: err,
}
}
// Decode query: ErrorMessage.
if err := func() error {
cfg := uri.QueryParameterDecodingConfig{
Name: "ErrorMessage",
Style: uri.QueryStyleForm,
Explode: true,
}
if err := q.HasParam(cfg); err == nil {
if err := q.DecodeParam(cfg, func(d uri.Decoder) error {
val, err := d.DecodeValue()
if err != nil {
return err
}
c, err := conv.ToString(val)
if err != nil {
return err
}
params.ErrorMessage = c
return nil
}); err != nil {
return err
}
if err := func() error {
if err := (validate.String{
MinLength: 0,
MinLengthSet: true,
MaxLength: 4096,
MaxLengthSet: true,
Email: false,
Hostname: false,
Regex: nil,
}).Validate(string(params.ErrorMessage)); err != nil {
return errors.Wrap(err, "string")
}
return nil
}(); err != nil {
return err
}
} else {
return err
}
return nil
}(); err != nil {
return params, &ogenerrors.DecodeParamError{
Name: "ErrorMessage",
In: "query",
Err: err,
}
}
return params, nil
}
@@ -1087,7 +1026,6 @@ func decodeActionSubmissionAcceptedParams(args [1]string, argsEscaped bool, r *h
type ActionSubmissionRequestChangesParams struct {
// The unique identifier for a submission.
SubmissionID int64
ErrorMessage string
}
func unpackActionSubmissionRequestChangesParams(packed middleware.Parameters) (params ActionSubmissionRequestChangesParams) {
@@ -1098,18 +1036,10 @@ func unpackActionSubmissionRequestChangesParams(packed middleware.Parameters) (p
}
params.SubmissionID = packed[key].(int64)
}
{
key := middleware.ParameterKey{
Name: "ErrorMessage",
In: "query",
}
params.ErrorMessage = packed[key].(string)
}
return params
}
func decodeActionSubmissionRequestChangesParams(args [1]string, argsEscaped bool, r *http.Request) (params ActionSubmissionRequestChangesParams, _ error) {
q := uri.NewQueryDecoder(r.URL.Query())
// Decode path: SubmissionID.
if err := func() error {
param := args[0]
@@ -1172,58 +1102,6 @@ func decodeActionSubmissionRequestChangesParams(args [1]string, argsEscaped bool
Err: err,
}
}
// Decode query: ErrorMessage.
if err := func() error {
cfg := uri.QueryParameterDecodingConfig{
Name: "ErrorMessage",
Style: uri.QueryStyleForm,
Explode: true,
}
if err := q.HasParam(cfg); err == nil {
if err := q.DecodeParam(cfg, func(d uri.Decoder) error {
val, err := d.DecodeValue()
if err != nil {
return err
}
c, err := conv.ToString(val)
if err != nil {
return err
}
params.ErrorMessage = c
return nil
}); err != nil {
return err
}
if err := func() error {
if err := (validate.String{
MinLength: 0,
MinLengthSet: true,
MaxLength: 4096,
MaxLengthSet: true,
Email: false,
Hostname: false,
Regex: nil,
}).Validate(string(params.ErrorMessage)); err != nil {
return errors.Wrap(err, "string")
}
return nil
}(); err != nil {
return err
}
} else {
return err
}
return nil
}(); err != nil {
return params, &ogenerrors.DecodeParamError{
Name: "ErrorMessage",
In: "query",
Err: err,
}
}
return params, nil
}

View File

@@ -14,6 +14,148 @@ import (
"github.com/ogen-go/ogen/validate"
)
func (s *Server) decodeActionMapfixRequestChangesRequest(r *http.Request) (
req CheckList,
close func() error,
rerr error,
) {
var closers []func() error
close = func() error {
var merr error
// Close in reverse order, to match defer behavior.
for i := len(closers) - 1; i >= 0; i-- {
c := closers[i]
merr = errors.Join(merr, c())
}
return merr
}
defer func() {
if rerr != nil {
rerr = errors.Join(rerr, close())
}
}()
ct, _, err := mime.ParseMediaType(r.Header.Get("Content-Type"))
if err != nil {
return req, close, errors.Wrap(err, "parse media type")
}
switch {
case ct == "application/json":
if r.ContentLength == 0 {
return req, close, validate.ErrBodyRequired
}
buf, err := io.ReadAll(r.Body)
if err != nil {
return req, close, err
}
if len(buf) == 0 {
return req, close, validate.ErrBodyRequired
}
d := jx.DecodeBytes(buf)
var request CheckList
if err := func() error {
if err := request.Decode(d); err != nil {
return err
}
if err := d.Skip(); err != io.EOF {
return errors.New("unexpected trailing data")
}
return nil
}(); err != nil {
err = &ogenerrors.DecodeBodyError{
ContentType: ct,
Body: buf,
Err: err,
}
return req, close, err
}
if err := func() error {
if err := request.Validate(); err != nil {
return err
}
return nil
}(); err != nil {
return req, close, errors.Wrap(err, "validate")
}
return request, close, nil
default:
return req, close, validate.InvalidContentType(ct)
}
}
func (s *Server) decodeActionSubmissionRequestChangesRequest(r *http.Request) (
req CheckList,
close func() error,
rerr error,
) {
var closers []func() error
close = func() error {
var merr error
// Close in reverse order, to match defer behavior.
for i := len(closers) - 1; i >= 0; i-- {
c := closers[i]
merr = errors.Join(merr, c())
}
return merr
}
defer func() {
if rerr != nil {
rerr = errors.Join(rerr, close())
}
}()
ct, _, err := mime.ParseMediaType(r.Header.Get("Content-Type"))
if err != nil {
return req, close, errors.Wrap(err, "parse media type")
}
switch {
case ct == "application/json":
if r.ContentLength == 0 {
return req, close, validate.ErrBodyRequired
}
buf, err := io.ReadAll(r.Body)
if err != nil {
return req, close, err
}
if len(buf) == 0 {
return req, close, validate.ErrBodyRequired
}
d := jx.DecodeBytes(buf)
var request CheckList
if err := func() error {
if err := request.Decode(d); err != nil {
return err
}
if err := d.Skip(); err != io.EOF {
return errors.New("unexpected trailing data")
}
return nil
}(); err != nil {
err = &ogenerrors.DecodeBodyError{
ContentType: ct,
Body: buf,
Err: err,
}
return req, close, err
}
if err := func() error {
if err := request.Validate(); err != nil {
return err
}
return nil
}(); err != nil {
return req, close, errors.Wrap(err, "validate")
}
return request, close, nil
default:
return req, close, validate.InvalidContentType(ct)
}
}
func (s *Server) decodeCreateMapfixRequest(r *http.Request) (
req *MapfixCreate,
close func() error,

View File

@@ -11,6 +11,34 @@ import (
ht "github.com/ogen-go/ogen/http"
)
func encodeActionMapfixRequestChangesRequest(
req CheckList,
r *http.Request,
) error {
const contentType = "application/json"
e := new(jx.Encoder)
{
req.Encode(e)
}
encoded := e.Bytes()
ht.SetBody(r, bytes.NewReader(encoded), contentType)
return nil
}
func encodeActionSubmissionRequestChangesRequest(
req CheckList,
r *http.Request,
) error {
const contentType = "application/json"
e := new(jx.Encoder)
{
req.Encode(e)
}
encoded := e.Bytes()
ht.SetBody(r, bytes.NewReader(encoded), contentType)
return nil
}
func encodeCreateMapfixRequest(
req *MapfixCreate,
r *http.Request,

View File

@@ -43,6 +43,58 @@ type ActionSubmissionUploadedNoContent struct{}
// ActionSubmissionValidatedNoContent is response for ActionSubmissionValidated operation.
type ActionSubmissionValidatedNoContent struct{}
// Ref: #/components/schemas/Check
type Check struct {
Name string `json:"Name"`
Summary string `json:"Summary"`
Passed bool `json:"Passed"`
Details CheckDetails `json:"Details"`
}
// GetName returns the value of Name.
func (s *Check) GetName() string {
return s.Name
}
// GetSummary returns the value of Summary.
func (s *Check) GetSummary() string {
return s.Summary
}
// GetPassed returns the value of Passed.
func (s *Check) GetPassed() bool {
return s.Passed
}
// GetDetails returns the value of Details.
func (s *Check) GetDetails() CheckDetails {
return s.Details
}
// SetName sets the value of Name.
func (s *Check) SetName(val string) {
s.Name = val
}
// SetSummary sets the value of Summary.
func (s *Check) SetSummary(val string) {
s.Summary = val
}
// SetPassed sets the value of Passed.
func (s *Check) SetPassed(val bool) {
s.Passed = val
}
// SetDetails sets the value of Details.
func (s *Check) SetDetails(val CheckDetails) {
s.Details = val
}
type CheckDetails struct{}
type CheckList []Check
// Represents error object.
// Ref: #/components/schemas/Error
type Error struct {

View File

@@ -19,7 +19,7 @@ type Handler interface {
// (Internal endpoint) Role Validator changes status from Submitting -> ChangesRequested.
//
// POST /mapfixes/{MapfixID}/status/validator-request-changes
ActionMapfixRequestChanges(ctx context.Context, params ActionMapfixRequestChangesParams) error
ActionMapfixRequestChanges(ctx context.Context, req CheckList, params ActionMapfixRequestChangesParams) error
// ActionMapfixSubmitted implements actionMapfixSubmitted operation.
//
// (Internal endpoint) Role Validator changes status from Submitting -> Submitted.
@@ -55,7 +55,7 @@ type Handler interface {
// (Internal endpoint) Role Validator changes status from Submitting -> ChangesRequested.
//
// POST /submissions/{SubmissionID}/status/validator-request-changes
ActionSubmissionRequestChanges(ctx context.Context, params ActionSubmissionRequestChangesParams) error
ActionSubmissionRequestChanges(ctx context.Context, req CheckList, params ActionSubmissionRequestChangesParams) error
// ActionSubmissionSubmitted implements actionSubmissionSubmitted operation.
//
// (Internal endpoint) Role Validator changes status from Submitting -> Submitted.

View File

@@ -27,7 +27,7 @@ func (UnimplementedHandler) ActionMapfixAccepted(ctx context.Context, params Act
// (Internal endpoint) Role Validator changes status from Submitting -> ChangesRequested.
//
// POST /mapfixes/{MapfixID}/status/validator-request-changes
func (UnimplementedHandler) ActionMapfixRequestChanges(ctx context.Context, params ActionMapfixRequestChangesParams) error {
func (UnimplementedHandler) ActionMapfixRequestChanges(ctx context.Context, req CheckList, params ActionMapfixRequestChangesParams) error {
return ht.ErrNotImplemented
}
@@ -81,7 +81,7 @@ func (UnimplementedHandler) ActionSubmissionAccepted(ctx context.Context, params
// (Internal endpoint) Role Validator changes status from Submitting -> ChangesRequested.
//
// POST /submissions/{SubmissionID}/status/validator-request-changes
func (UnimplementedHandler) ActionSubmissionRequestChanges(ctx context.Context, params ActionSubmissionRequestChangesParams) error {
func (UnimplementedHandler) ActionSubmissionRequestChanges(ctx context.Context, req CheckList, params ActionSubmissionRequestChangesParams) error {
return ht.ErrNotImplemented
}

View File

@@ -3,11 +3,88 @@
package api
import (
"fmt"
"github.com/go-faster/errors"
"github.com/ogen-go/ogen/validate"
)
func (s *Check) Validate() error {
if s == nil {
return validate.ErrNilPointer
}
var failures []validate.FieldError
if err := func() error {
if err := (validate.String{
MinLength: 0,
MinLengthSet: false,
MaxLength: 128,
MaxLengthSet: true,
Email: false,
Hostname: false,
Regex: nil,
}).Validate(string(s.Name)); err != nil {
return errors.Wrap(err, "string")
}
return nil
}(); err != nil {
failures = append(failures, validate.FieldError{
Name: "Name",
Error: err,
})
}
if err := func() error {
if err := (validate.String{
MinLength: 0,
MinLengthSet: false,
MaxLength: 4096,
MaxLengthSet: true,
Email: false,
Hostname: false,
Regex: nil,
}).Validate(string(s.Summary)); err != nil {
return errors.Wrap(err, "string")
}
return nil
}(); err != nil {
failures = append(failures, validate.FieldError{
Name: "Summary",
Error: err,
})
}
if len(failures) > 0 {
return &validate.Error{Fields: failures}
}
return nil
}
func (s CheckList) Validate() error {
alias := ([]Check)(s)
if alias == nil {
return errors.New("nil is invalid value")
}
var failures []validate.FieldError
for i, elem := range alias {
if err := func() error {
if err := elem.Validate(); err != nil {
return err
}
return nil
}(); err != nil {
failures = append(failures, validate.FieldError{
Name: fmt.Sprintf("[%d]", i),
Error: err,
})
}
}
if len(failures) > 0 {
return &validate.Error{Fields: failures}
}
return nil
}
func (s *Error) Validate() error {
if s == nil {
return validate.ErrNilPointer

View File

@@ -48,6 +48,20 @@ type AuditEventDataError struct {
Error string `json:"error"`
}
type Check struct {
Name string `json:"name"`
Summary string `json:"summary"`
Passed bool `json:"passed"`
Details any `json:"details"`
}
// Validator map checks details
const AuditEventTypeCheckReport AuditEventType = 7
type AuditEventDataCheckReport struct {
CheckList []Check `json:"checklist"`
}
type AuditEvent struct {
ID int64 `gorm:"primaryKey"`
CreatedAt time.Time

View File

@@ -122,7 +122,7 @@ func (svc *Service) ActionMapfixSubmitted(ctx context.Context, params internal.A
// (Internal endpoint) Role Validator changes status from Submitting -> RequestChanges.
//
// POST /mapfixes/{MapfixID}/status/validator-request-changes
func (svc *Service) ActionMapfixRequestChanges(ctx context.Context, params internal.ActionMapfixRequestChangesParams) error {
func (svc *Service) ActionMapfixRequestChanges(ctx context.Context, check_list internal.CheckList, params internal.ActionMapfixRequestChangesParams) error {
// transaction
target_status := model.MapfixStatusChangesRequested
smap := datastore.Optional()
@@ -133,8 +133,18 @@ func (svc *Service) ActionMapfixRequestChanges(ctx context.Context, params inter
}
{
event_data := model.AuditEventDataError{
Error: params.ErrorMessage,
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,
Details: check.Details,
}
}
event_data := model.AuditEventDataCheckReport{
CheckList: check_list2,
}
EventData, err := json.Marshal(event_data)

View File

@@ -122,7 +122,7 @@ func (svc *Service) ActionSubmissionSubmitted(ctx context.Context, params intern
// (Internal endpoint) Role Validator changes status from Submitting -> RequestChanges.
//
// POST /submissions/{SubmissionID}/status/validator-request-changes
func (svc *Service) ActionSubmissionRequestChanges(ctx context.Context, params internal.ActionSubmissionRequestChangesParams) error {
func (svc *Service) ActionSubmissionRequestChanges(ctx context.Context, check_list internal.CheckList, params internal.ActionSubmissionRequestChangesParams) error {
// transaction
target_status := model.SubmissionStatusChangesRequested
smap := datastore.Optional()
@@ -134,8 +134,18 @@ func (svc *Service) ActionSubmissionRequestChanges(ctx context.Context, params i
//push an error audit event
{
event_data := model.AuditEventDataError{
Error: params.ErrorMessage,
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,
Details: check.Details,
}
}
event_data := model.AuditEventDataCheckReport{
CheckList: check_list2,
}
EventData, err := json.Marshal(event_data)

View File

@@ -161,10 +161,19 @@ impl Context{
).await.map_err(Error::Response)?
.json().await.map_err(Error::ReqwestJson)
}
pub async fn action_submission_request_changes(&self,config:ActionSubmissionRequestChangesRequest<'_>)->Result<(),Error>{
let url_raw=format!("{}/submissions/{}/status/validator-request-changes",self.0.base_url,config.SubmissionID);
let url=reqwest::Url::parse(url_raw.as_str()).map_err(Error::Parse)?;
let body=serde_json::to_string(&config).map_err(Error::JSON)?;
response_ok(
self.0.post(url,body).await.map_err(Error::Reqwest)?
).await.map_err(Error::Response)?;
Ok(())
}
// simple submission endpoints
action!("submissions",action_submission_request_changes,config,ActionSubmissionRequestChangesRequest,"status/validator-request-changes",config.SubmissionID,
("ErrorMessage",config.ErrorMessage.as_str())
);
action!("submissions",action_submission_submitted,config,ActionSubmissionSubmittedRequest,"status/validator-submitted",config.SubmissionID,
("ModelVersion",config.ModelVersion.to_string().as_str())
("DisplayName",config.DisplayName.as_str())
@@ -193,10 +202,19 @@ impl Context{
).await.map_err(Error::Response)?
.json().await.map_err(Error::ReqwestJson)
}
pub async fn action_mapfix_request_changes(&self,config:ActionMapfixRequestChangesRequest<'_>)->Result<(),Error>{
let url_raw=format!("{}/mapfixes/{}/status/validator-request-changes",self.0.base_url,config.MapfixID);
let url=reqwest::Url::parse(url_raw.as_str()).map_err(Error::Parse)?;
let body=serde_json::to_string(&config).map_err(Error::JSON)?;
response_ok(
self.0.post(url,body).await.map_err(Error::Reqwest)?
).await.map_err(Error::Response)?;
Ok(())
}
// simple mapfixes endpoints
action!("mapfixes",action_mapfix_request_changes,config,ActionMapfixRequestChangesRequest,"status/validator-request-changes",config.MapfixID,
("ErrorMessage",config.ErrorMessage.as_str())
);
action!("mapfixes",action_mapfix_submitted,config,ActionMapfixSubmittedRequest,"status/validator-submitted",config.MapfixID,
("ModelVersion",config.ModelVersion.to_string().as_str())
("DisplayName",config.DisplayName.as_str())

View File

@@ -230,6 +230,15 @@ pub struct UpdateSubmissionModelRequest{
pub ModelVersion:u64,
}
#[allow(nonstandard_style)]
#[derive(Clone,Debug,serde::Serialize)]
pub struct Check{
pub Name:&'static str,
pub Summary:String,
pub Passed:bool,
pub Details:serde_json::Value,
}
#[allow(nonstandard_style)]
#[derive(Clone,Debug)]
pub struct ActionSubmissionSubmittedRequest{
@@ -241,10 +250,10 @@ pub struct ActionSubmissionSubmittedRequest{
}
#[allow(nonstandard_style)]
#[derive(Clone,Debug)]
pub struct ActionSubmissionRequestChangesRequest{
#[derive(Clone,Debug,serde::Serialize)]
pub struct ActionSubmissionRequestChangesRequest<'a>{
pub SubmissionID:i64,
pub ErrorMessage:String,
pub CheckList:&'a [Check],
}
#[allow(nonstandard_style)]
@@ -283,10 +292,10 @@ pub struct ActionMapfixSubmittedRequest{
}
#[allow(nonstandard_style)]
#[derive(Clone,Debug)]
pub struct ActionMapfixRequestChangesRequest{
#[derive(Clone,Debug,serde::Serialize)]
pub struct ActionMapfixRequestChangesRequest<'a>{
pub MapfixID:i64,
pub ErrorMessage:String,
pub CheckList:&'a [Check],
}
#[allow(nonstandard_style)]

View File

@@ -3,6 +3,7 @@ use crate::download::download_asset_version;
use crate::rbx_util::{class_is_a,get_mapinfo,get_root_instance,read_dom,ReadDomError,GameID,ParseGameIDError,MapInfo,GetRootInstanceError,StringValueError};
use heck::{ToSnakeCase,ToTitleCase};
use submissions_api::types::Check;
#[allow(dead_code)]
#[derive(Debug)]
@@ -585,40 +586,34 @@ impl<D:std::fmt::Display> std::fmt::Display for Duplicates<D>{
}
}
#[derive(serde::Serialize)]
struct CheckSummary{
name:&'static str,
summary:String,
passed:bool,
details:serde_json::Value,
}
impl CheckSummary{
const fn passed(name:&'static str)->Self{
Self{
name,
summary:String::new(),
passed:true,
details:serde_json::Value::Null,
macro_rules! passed{
($name:literal)=>{
Check{
Name:$name,
Summary:String::new(),
Passed:true,
Details:serde_json::Value::Null,
}
}
}
macro_rules! summary{
($name:literal,$summary:expr,$details:expr)=>{
CheckSummary{
name:$name,
summary:$summary,
passed:false,
details:serde_json::to_value($details)?,
Check{
Name:$name,
Summary:$summary,
Passed:false,
Details:serde_json::to_value($details)?,
}
};
}
macro_rules! summary_format{
($name:literal,$fmt:literal,$details:expr)=>{
CheckSummary{
name:$name,
summary:format!($fmt),
passed:false,
details:serde_json::to_value($details)?,
Check{
Name:$name,
Summary:format!($fmt),
Passed:false,
Details:serde_json::to_value($details)?,
}
};
}
@@ -628,15 +623,15 @@ macro_rules! summary_format{
impl MapCheck<'_>{
fn itemize(&self)->Result<MapCheckList,serde_json::Error>{
let model_class=match &self.model_class{
StringCheck(Ok(()))=>CheckSummary::passed("ModelClass"),
StringCheck(Ok(()))=>passed!("ModelClass"),
StringCheck(Err(context))=>summary_format!("ModelClass","Invalid model class: {context}",()),
};
let model_name=match &self.model_name{
StringCheck(Ok(()))=>CheckSummary::passed("ModelName"),
StringCheck(Ok(()))=>passed!("ModelName"),
StringCheck(Err(context))=>summary_format!("ModelName","Model name must have snake_case: {context}",()),
};
let display_name=match &self.display_name{
Ok(Ok(StringCheck(Ok(_))))=>CheckSummary::passed("DisplayName"),
Ok(Ok(StringCheck(Ok(_))))=>passed!("DisplayName"),
Ok(Ok(StringCheck(Err(context))))=>summary_format!("DisplayName","DisplayName must have Title Case: {context}",()),
Ok(Err(context))=>summary_format!("DisplayName","Invalid DisplayName: {context}",()),
Err(StringValueError::ObjectNotFound)=>summary!("DisplayName","Missing DisplayName StringValue".to_owned(),()),
@@ -644,22 +639,22 @@ impl MapCheck<'_>{
Err(StringValueError::NonStringValue)=>summary!("DisplayName","DisplayName Value is not a String".to_owned(),()),
};
let creator=match &self.creator{
Ok(Ok(_))=>CheckSummary::passed("Creator"),
Ok(Ok(_))=>passed!("Creator"),
Ok(Err(context))=>summary_format!("Creator","Invalid Creator: {context}",()),
Err(StringValueError::ObjectNotFound)=>summary!("Creator","Missing Creator StringValue".to_owned(),()),
Err(StringValueError::ValueNotSet)=>summary!("Creator","Creator Value not set".to_owned(),()),
Err(StringValueError::NonStringValue)=>summary!("Creator","Creator Value is not a String".to_owned(),()),
};
let game_id=match &self.game_id{
Ok(_)=>CheckSummary::passed("GameID"),
Ok(_)=>passed!("GameID"),
Err(ParseGameIDError)=>summary!("GameID","Model name must be prefixed with bhop_ surf_ or flytrials_".to_owned(),()),
};
let mapstart=match &self.mapstart{
Ok(Exists)=>CheckSummary::passed("MapStart"),
Ok(Exists)=>passed!("MapStart"),
Err(Absent)=>summary_format!("MapStart","Model has no MapStart",()),
};
let duplicate_start=match &self.mode_start_counts{
DuplicateCheck(Ok(()))=>CheckSummary::passed("DuplicateStart"),
DuplicateCheck(Ok(()))=>passed!("DuplicateStart"),
DuplicateCheck(Err(DuplicateCheckContext(context)))=>{
let context=Separated::new(", ",||context.iter().map(|(&mode_id,names)|
Duplicates::new(ModeElement{zone:Zone::Start,mode_id},names.len())
@@ -668,10 +663,10 @@ impl MapCheck<'_>{
}
};
let (extra_finish,missing_finish)=match &self.mode_finish_counts{
SetDifferenceCheck(Ok(()))=>(CheckSummary::passed("ExtraFinish"),CheckSummary::passed("MissingFinish")),
SetDifferenceCheck(Ok(()))=>(passed!("ExtraFinish"),passed!("MissingFinish")),
SetDifferenceCheck(Err(context))=>(
if context.extra.is_empty(){
CheckSummary::passed("ExtraFinish")
passed!("ExtraFinish")
}else{
let plural=if context.extra.len()==1{"zone"}else{"zones"};
let context=Separated::new(", ",||context.extra.iter().map(|(&mode_id,_names)|
@@ -680,7 +675,7 @@ impl MapCheck<'_>{
summary_format!("ExtraFinish","No matching start zone for finish {plural}: {context}",())
},
if context.missing.is_empty(){
CheckSummary::passed("MissingFinish")
passed!("MissingFinish")
}else{
let plural=if context.missing.len()==1{"zone"}else{"zones"};
let context=Separated::new(", ",||context.missing.iter().map(|&mode_id|
@@ -691,10 +686,10 @@ impl MapCheck<'_>{
),
};
let dangling_anticheat=match &self.mode_anticheat_counts{
SetDifferenceCheck(Ok(()))=>CheckSummary::passed("DanglingAnticheat"),
SetDifferenceCheck(Ok(()))=>passed!("DanglingAnticheat"),
SetDifferenceCheck(Err(context))=>{
if context.extra.is_empty(){
CheckSummary::passed("DanglingAnticheat")
passed!("DanglingAnticheat")
}else{
let plural=if context.extra.len()==1{"zone"}else{"zones"};
let context=Separated::new(", ",||context.extra.iter().map(|(&mode_id,_names)|
@@ -705,11 +700,11 @@ impl MapCheck<'_>{
}
};
let spawn1=match &self.spawn1{
Ok(Exists)=>CheckSummary::passed("Spawn1"),
Ok(Exists)=>passed!("Spawn1"),
Err(Absent)=>summary_format!("Spawn1","Model has no Spawn1",()),
};
let dangling_teleport=match &self.teleport_counts{
SetDifferenceCheck(Ok(()))=>CheckSummary::passed("DanglingTeleport"),
SetDifferenceCheck(Ok(()))=>passed!("DanglingTeleport"),
SetDifferenceCheck(Err(context))=>{
let unique_names:HashSet<_>=context.extra.values().flat_map(|names|names.iter().copied()).collect();
let plural=if unique_names.len()==1{"object"}else{"objects"};
@@ -718,7 +713,7 @@ impl MapCheck<'_>{
}
};
let duplicate_spawns=match &self.spawn_counts{
DuplicateCheck(Ok(()))=>CheckSummary::passed("DuplicateSpawn"),
DuplicateCheck(Ok(()))=>passed!("DuplicateSpawn"),
DuplicateCheck(Err(DuplicateCheckContext(context)))=>{
let context=Separated::new(", ",||context.iter().map(|(&stage_id,&names)|
Duplicates::new(StageElement{behaviour:StageElementBehaviour::Spawn,stage_id},names as usize)
@@ -727,10 +722,10 @@ impl MapCheck<'_>{
}
};
let (extra_wormhole_in,missing_wormhole_in)=match &self.wormhole_in_counts{
SetDifferenceCheck(Ok(()))=>(CheckSummary::passed("ExtraWormholeIn"),CheckSummary::passed("MissingWormholeIn")),
SetDifferenceCheck(Ok(()))=>(passed!("ExtraWormholeIn"),passed!("MissingWormholeIn")),
SetDifferenceCheck(Err(context))=>(
if context.extra.is_empty(){
CheckSummary::passed("ExtraWormholeIn")
passed!("ExtraWormholeIn")
}else{
let context=Separated::new(", ",||context.extra.iter().map(|(&wormhole_id,_names)|
WormholeElement{behaviour:WormholeBehaviour::In,wormhole_id}
@@ -738,7 +733,7 @@ impl MapCheck<'_>{
summary_format!("ExtraWormholeIn","WormholeIn with no matching WormholeOut: {context}",())
},
if context.missing.is_empty(){
CheckSummary::passed("MissingWormholeIn")
passed!("MissingWormholeIn")
}else{
// This counts WormholeIn objects, but
// flipped logic is easier to understand
@@ -750,7 +745,7 @@ impl MapCheck<'_>{
)
};
let duplicate_wormhole_out=match &self.wormhole_out_counts{
DuplicateCheck(Ok(()))=>CheckSummary::passed("DuplicateWormholeOut"),
DuplicateCheck(Ok(()))=>passed!("DuplicateWormholeOut"),
DuplicateCheck(Err(DuplicateCheckContext(context)))=>{
let context=Separated::new(", ",||context.iter().map(|(&wormhole_id,&names)|
Duplicates::new(WormholeElement{behaviour:WormholeBehaviour::Out,wormhole_id},names as usize)
@@ -780,24 +775,12 @@ impl MapCheck<'_>{
}
#[derive(serde::Serialize)]
struct MapCheckList{
checks:Box<[CheckSummary;16]>,
}
impl MapCheckList{
fn summary(&self)->String{
Separated::new("; ",||self.checks.iter().filter_map(|check|
(!check.passed).then_some(check.summary.as_str())
)).to_string()
}
}
pub struct Summary{
pub summary:String,
pub json:serde_json::Value,
pub struct MapCheckList{
pub checks:Box<[Check;16]>,
}
pub struct CheckReportAndVersion{
pub status:Result<MapInfoOwned,Summary>,
pub status:Result<MapInfoOwned,MapCheckList>,
pub version:u64,
}
@@ -836,10 +819,7 @@ impl crate::message_handler::MessageHandler{
// check the report, generate an error message if it fails the check
let status=match map_check.result(){
Ok(map_info)=>Ok(map_info),
Err(Ok(summary))=>Err(Summary{
summary:summary.summary(),
json:serde_json::to_value(&summary).map_err(Error::ToJsonValue)?,
}),
Err(Ok(check_list))=>Err(check_list),
Err(Err(e))=>return Err(Error::ToJsonValue(e)),
};

View File

@@ -31,10 +31,10 @@ impl crate::message_handler::MessageHandler{
}
).await.map_err(Error::ApiActionMapfixCheck)?,
// update the mapfix model status to request changes
Ok(CheckReportAndVersion{status:Err(report),..})=>self.api.action_mapfix_request_changes(
Ok(CheckReportAndVersion{status:Err(check_list),..})=>self.api.action_mapfix_request_changes(
submissions_api::types::ActionMapfixRequestChangesRequest{
MapfixID:mapfix_id,
ErrorMessage:report.summary,
CheckList:check_list.checks.as_slice(),
}
).await.map_err(Error::ApiActionMapfixCheck)?,
// update the mapfix model status to request changes
@@ -45,7 +45,12 @@ impl crate::message_handler::MessageHandler{
self.api.action_mapfix_request_changes(
submissions_api::types::ActionMapfixRequestChangesRequest{
MapfixID:mapfix_id,
ErrorMessage:e.to_string(),
CheckList:&[submissions_api::types::Check{
Name:"InternalError",
Summary:e.to_string(),
Passed:false,
Details:serde_json::Value::Null,
}],
}
).await.map_err(Error::ApiActionMapfixCheck)?;
},

View File

@@ -32,10 +32,10 @@ impl crate::message_handler::MessageHandler{
}
).await.map_err(Error::ApiActionSubmissionCheck)?,
// update the submission model status to request changes
Ok(CheckReportAndVersion{status:Err(report),..})=>self.api.action_submission_request_changes(
Ok(CheckReportAndVersion{status:Err(check_list),..})=>self.api.action_submission_request_changes(
submissions_api::types::ActionSubmissionRequestChangesRequest{
SubmissionID:submission_id,
ErrorMessage:report.summary,
CheckList:check_list.checks.as_slice(),
}
).await.map_err(Error::ApiActionSubmissionCheck)?,
// update the submission model status to request changes
@@ -46,7 +46,12 @@ impl crate::message_handler::MessageHandler{
self.api.action_submission_request_changes(
submissions_api::types::ActionSubmissionRequestChangesRequest{
SubmissionID:submission_id,
ErrorMessage:e.to_string(),
CheckList:&[submissions_api::types::Check{
Name:"InternalError",
Summary:e.to_string(),
Passed:false,
Details:serde_json::Value::Null,
}],
}
).await.map_err(Error::ApiActionSubmissionCheck)?;
},