From 00fdbd9611d73c829e2beb49d97841abc09761fb Mon Sep 17 00:00:00 2001 From: Quaternions Date: Fri, 13 Dec 2024 22:15:05 -0800 Subject: [PATCH] openapi: GET /script-policy endpoint to list script policies --- openapi.yaml | 49 ++++++ pkg/api/oas_client_gen.go | 146 +++++++++++++++++ pkg/api/oas_handlers_gen.go | 199 +++++++++++++++++++++++ pkg/api/oas_operations_gen.go | 1 + pkg/api/oas_parameters_gen.go | 111 +++++++++++++ pkg/api/oas_response_decoders_gen.go | 117 +++++++++++++ pkg/api/oas_response_encoders_gen.go | 18 ++ pkg/api/oas_router_gen.go | 12 +- pkg/api/oas_schemas_gen.go | 94 +++++++++++ pkg/api/oas_server_gen.go | 6 + pkg/api/oas_unimplemented_gen.go | 9 + pkg/api/oas_uri_gen.go | 159 ++++++++++++++++++ pkg/api/oas_validators_gen.go | 38 +++++ pkg/datastore/datastore.go | 1 + pkg/datastore/gormstore/script_policy.go | 9 + pkg/service/script_policy.go | 36 ++++ 16 files changed, 1004 insertions(+), 1 deletion(-) diff --git a/openapi.yaml b/openapi.yaml index 066e6f2..e7a8b43 100644 --- a/openapi.yaml +++ b/openapi.yaml @@ -295,6 +295,39 @@ paths: schema: $ref: "#/components/schemas/Error" /script-policy: + get: + summary: Get list of script policies + operationId: listScriptPolicy + tags: + - ScriptPolicy + parameters: + - name: page + in: query + required: true + schema: + $ref: "#/components/schemas/Pagination" + - name: filter + in: query + required: false + schema: + $ref: "#/components/schemas/ScriptPolicyFilter" + security: + - cookieAuth: [] + responses: + "200": + description: Successful response + content: + application/json: + schema: + type: array + items: + $ref: "#/components/schemas/ScriptPolicy" + default: + description: General Error + content: + application/json: + schema: + $ref: "#/components/schemas/Error" post: summary: Create a new script policy operationId: createScriptPolicy @@ -715,6 +748,22 @@ components: Policy: type: integer format: int32 + ScriptPolicyFilter: + type: object + properties: + ID: + type: integer + format: int64 + FromScriptHash: + type: string + minLength: 16 + maxLength: 16 + ToScriptID: + type: integer + format: int64 + Policy: + type: integer + format: int32 ScriptPolicyCreate: required: - FromScriptID diff --git a/pkg/api/oas_client_gen.go b/pkg/api/oas_client_gen.go index e8515c1..12f56b1 100644 --- a/pkg/api/oas_client_gen.go +++ b/pkg/api/oas_client_gen.go @@ -126,6 +126,12 @@ type Invoker interface { // // GET /submissions/{SubmissionID} GetSubmission(ctx context.Context, params GetSubmissionParams) (*Submission, error) + // ListScriptPolicy invokes listScriptPolicy operation. + // + // Get list of script policies. + // + // GET /script-policy + ListScriptPolicy(ctx context.Context, params ListScriptPolicyParams) ([]ScriptPolicy, error) // ListSubmissions invokes listSubmissions operation. // // Get list of submissions. @@ -2200,6 +2206,146 @@ func (c *Client) sendGetSubmission(ctx context.Context, params GetSubmissionPara return result, nil } +// ListScriptPolicy invokes listScriptPolicy operation. +// +// Get list of script policies. +// +// GET /script-policy +func (c *Client) ListScriptPolicy(ctx context.Context, params ListScriptPolicyParams) ([]ScriptPolicy, error) { + res, err := c.sendListScriptPolicy(ctx, params) + return res, err +} + +func (c *Client) sendListScriptPolicy(ctx context.Context, params ListScriptPolicyParams) (res []ScriptPolicy, err error) { + otelAttrs := []attribute.KeyValue{ + otelogen.OperationID("listScriptPolicy"), + semconv.HTTPRequestMethodKey.String("GET"), + semconv.HTTPRouteKey.String("/script-policy"), + } + + // Run stopwatch. + startTime := time.Now() + defer func() { + // Use floating point division here for higher precision (instead of Millisecond method). + elapsedDuration := time.Since(startTime) + c.duration.Record(ctx, float64(elapsedDuration)/float64(time.Millisecond), metric.WithAttributes(otelAttrs...)) + }() + + // Increment request counter. + c.requests.Add(ctx, 1, metric.WithAttributes(otelAttrs...)) + + // Start a span for this request. + ctx, span := c.cfg.Tracer.Start(ctx, ListScriptPolicyOperation, + trace.WithAttributes(otelAttrs...), + clientSpanKind, + ) + // Track stage for error reporting. + var stage string + defer func() { + if err != nil { + span.RecordError(err) + span.SetStatus(codes.Error, stage) + c.errors.Add(ctx, 1, metric.WithAttributes(otelAttrs...)) + } + span.End() + }() + + stage = "BuildURL" + u := uri.Clone(c.requestURL(ctx)) + var pathParts [1]string + pathParts[0] = "/script-policy" + uri.AddPathParts(u, pathParts[:]...) + + stage = "EncodeQueryParams" + q := uri.NewQueryEncoder() + { + // Encode "page" parameter. + cfg := uri.QueryParameterEncodingConfig{ + Name: "page", + Style: uri.QueryStyleForm, + Explode: true, + } + + if err := q.EncodeParam(cfg, func(e uri.Encoder) error { + return params.Page.EncodeURI(e) + }); err != nil { + return res, errors.Wrap(err, "encode query") + } + } + { + // Encode "filter" parameter. + cfg := uri.QueryParameterEncodingConfig{ + Name: "filter", + Style: uri.QueryStyleForm, + Explode: true, + } + + if err := q.EncodeParam(cfg, func(e uri.Encoder) error { + if val, ok := params.Filter.Get(); ok { + return val.EncodeURI(e) + } + return nil + }); err != nil { + return res, errors.Wrap(err, "encode query") + } + } + u.RawQuery = q.Values().Encode() + + stage = "EncodeRequest" + r, err := ht.NewRequest(ctx, "GET", u) + if err != nil { + return res, errors.Wrap(err, "create request") + } + + { + type bitset = [1]uint8 + var satisfied bitset + { + stage = "Security:CookieAuth" + switch err := c.securityCookieAuth(ctx, ListScriptPolicyOperation, r); { + case err == nil: // if NO error + satisfied[0] |= 1 << 0 + case errors.Is(err, ogenerrors.ErrSkipClientSecurity): + // Skip this security. + default: + return res, errors.Wrap(err, "security \"CookieAuth\"") + } + } + + if ok := func() bool { + nextRequirement: + for _, requirement := range []bitset{ + {0b00000001}, + } { + for i, mask := range requirement { + if satisfied[i]&mask != mask { + continue nextRequirement + } + } + return true + } + return false + }(); !ok { + return res, ogenerrors.ErrSecurityRequirementIsNotSatisfied + } + } + + stage = "SendRequest" + resp, err := c.cfg.Client.Do(r) + if err != nil { + return res, errors.Wrap(err, "do request") + } + defer resp.Body.Close() + + stage = "DecodeResponse" + result, err := decodeListScriptPolicyResponse(resp) + if err != nil { + return res, errors.Wrap(err, "decode response") + } + + return result, nil +} + // ListSubmissions invokes listSubmissions operation. // // Get list of submissions. diff --git a/pkg/api/oas_handlers_gen.go b/pkg/api/oas_handlers_gen.go index 90e7620..4ca3aa3 100644 --- a/pkg/api/oas_handlers_gen.go +++ b/pkg/api/oas_handlers_gen.go @@ -3253,6 +3253,205 @@ func (s *Server) handleGetSubmissionRequest(args [1]string, argsEscaped bool, w } } +// handleListScriptPolicyRequest handles listScriptPolicy operation. +// +// Get list of script policies. +// +// GET /script-policy +func (s *Server) handleListScriptPolicyRequest(args [0]string, argsEscaped bool, w http.ResponseWriter, r *http.Request) { + statusWriter := &codeRecorder{ResponseWriter: w} + w = statusWriter + otelAttrs := []attribute.KeyValue{ + otelogen.OperationID("listScriptPolicy"), + semconv.HTTPRequestMethodKey.String("GET"), + semconv.HTTPRouteKey.String("/script-policy"), + } + + // Start a span for this request. + ctx, span := s.cfg.Tracer.Start(r.Context(), ListScriptPolicyOperation, + trace.WithAttributes(otelAttrs...), + serverSpanKind, + ) + defer span.End() + + // Add Labeler to context. + labeler := &Labeler{attrs: otelAttrs} + ctx = contextWithLabeler(ctx, labeler) + + // Run stopwatch. + startTime := time.Now() + defer func() { + elapsedDuration := time.Since(startTime) + + attrSet := labeler.AttributeSet() + attrs := attrSet.ToSlice() + code := statusWriter.status + if code != 0 { + codeAttr := semconv.HTTPResponseStatusCode(code) + attrs = append(attrs, codeAttr) + span.SetAttributes(codeAttr) + } + attrOpt := metric.WithAttributes(attrs...) + + // Increment request counter. + s.requests.Add(ctx, 1, attrOpt) + + // Use floating point division here for higher precision (instead of Millisecond method). + s.duration.Record(ctx, float64(elapsedDuration)/float64(time.Millisecond), attrOpt) + }() + + var ( + recordError = func(stage string, err error) { + span.RecordError(err) + + // https://opentelemetry.io/docs/specs/semconv/http/http-spans/#status + // Span Status MUST be left unset if HTTP status code was in the 1xx, 2xx or 3xx ranges, + // unless there was another error (e.g., network error receiving the response body; or 3xx codes with + // max redirects exceeded), in which case status MUST be set to Error. + code := statusWriter.status + if code >= 100 && code < 500 { + span.SetStatus(codes.Error, stage) + } + + attrSet := labeler.AttributeSet() + attrs := attrSet.ToSlice() + if code != 0 { + attrs = append(attrs, semconv.HTTPResponseStatusCode(code)) + } + + s.errors.Add(ctx, 1, metric.WithAttributes(attrs...)) + } + err error + opErrContext = ogenerrors.OperationContext{ + Name: ListScriptPolicyOperation, + ID: "listScriptPolicy", + } + ) + { + type bitset = [1]uint8 + var satisfied bitset + { + sctx, ok, err := s.securityCookieAuth(ctx, ListScriptPolicyOperation, r) + if err != nil { + err = &ogenerrors.SecurityError{ + OperationContext: opErrContext, + Security: "CookieAuth", + Err: err, + } + if encodeErr := encodeErrorResponse(s.h.NewError(ctx, err), w, span); encodeErr != nil { + defer recordError("Security:CookieAuth", err) + } + return + } + if ok { + satisfied[0] |= 1 << 0 + ctx = sctx + } + } + + if ok := func() bool { + nextRequirement: + for _, requirement := range []bitset{ + {0b00000001}, + } { + for i, mask := range requirement { + if satisfied[i]&mask != mask { + continue nextRequirement + } + } + return true + } + return false + }(); !ok { + err = &ogenerrors.SecurityError{ + OperationContext: opErrContext, + Err: ogenerrors.ErrSecurityRequirementIsNotSatisfied, + } + if encodeErr := encodeErrorResponse(s.h.NewError(ctx, err), w, span); encodeErr != nil { + defer recordError("Security", err) + } + return + } + } + params, err := decodeListScriptPolicyParams(args, argsEscaped, r) + if err != nil { + err = &ogenerrors.DecodeParamsError{ + OperationContext: opErrContext, + Err: err, + } + defer recordError("DecodeParams", err) + s.cfg.ErrorHandler(ctx, w, r, err) + return + } + + var response []ScriptPolicy + if m := s.cfg.Middleware; m != nil { + mreq := middleware.Request{ + Context: ctx, + OperationName: ListScriptPolicyOperation, + OperationSummary: "Get list of script policies", + OperationID: "listScriptPolicy", + Body: nil, + Params: middleware.Parameters{ + { + Name: "page", + In: "query", + }: params.Page, + { + Name: "filter", + In: "query", + }: params.Filter, + }, + Raw: r, + } + + type ( + Request = struct{} + Params = ListScriptPolicyParams + Response = []ScriptPolicy + ) + response, err = middleware.HookMiddleware[ + Request, + Params, + Response, + ]( + m, + mreq, + unpackListScriptPolicyParams, + func(ctx context.Context, request Request, params Params) (response Response, err error) { + response, err = s.h.ListScriptPolicy(ctx, params) + return response, err + }, + ) + } else { + response, err = s.h.ListScriptPolicy(ctx, params) + } + if err != nil { + if errRes, ok := errors.Into[*ErrorStatusCode](err); ok { + if err := encodeErrorResponse(errRes, w, span); err != nil { + defer recordError("Internal", err) + } + return + } + if errors.Is(err, ht.ErrNotImplemented) { + s.cfg.ErrorHandler(ctx, w, r, err) + return + } + if err := encodeErrorResponse(s.h.NewError(ctx, err), w, span); err != nil { + defer recordError("Internal", err) + } + return + } + + if err := encodeListScriptPolicyResponse(response, w, span); err != nil { + defer recordError("EncodeResponse", err) + if !errors.Is(err, ht.ErrInternalServerErrorResponse) { + s.cfg.ErrorHandler(ctx, w, r, err) + } + return + } +} + // handleListSubmissionsRequest handles listSubmissions operation. // // Get list of submissions. diff --git a/pkg/api/oas_operations_gen.go b/pkg/api/oas_operations_gen.go index fefd6f6..6288ee8 100644 --- a/pkg/api/oas_operations_gen.go +++ b/pkg/api/oas_operations_gen.go @@ -23,6 +23,7 @@ const ( GetScriptPolicyOperation OperationName = "GetScriptPolicy" GetScriptPolicyFromHashOperation OperationName = "GetScriptPolicyFromHash" GetSubmissionOperation OperationName = "GetSubmission" + ListScriptPolicyOperation OperationName = "ListScriptPolicy" ListSubmissionsOperation OperationName = "ListSubmissions" SetSubmissionCompletedOperation OperationName = "SetSubmissionCompleted" UpdateScriptOperation OperationName = "UpdateScript" diff --git a/pkg/api/oas_parameters_gen.go b/pkg/api/oas_parameters_gen.go index 1ee7167..8928941 100644 --- a/pkg/api/oas_parameters_gen.go +++ b/pkg/api/oas_parameters_gen.go @@ -954,6 +954,117 @@ func decodeGetSubmissionParams(args [1]string, argsEscaped bool, r *http.Request return params, nil } +// ListScriptPolicyParams is parameters of listScriptPolicy operation. +type ListScriptPolicyParams struct { + Page Pagination + Filter OptScriptPolicyFilter +} + +func unpackListScriptPolicyParams(packed middleware.Parameters) (params ListScriptPolicyParams) { + { + key := middleware.ParameterKey{ + Name: "page", + In: "query", + } + params.Page = packed[key].(Pagination) + } + { + key := middleware.ParameterKey{ + Name: "filter", + In: "query", + } + if v, ok := packed[key]; ok { + params.Filter = v.(OptScriptPolicyFilter) + } + } + return params +} + +func decodeListScriptPolicyParams(args [0]string, argsEscaped bool, r *http.Request) (params ListScriptPolicyParams, _ error) { + q := uri.NewQueryDecoder(r.URL.Query()) + // Decode query: page. + if err := func() error { + cfg := uri.QueryParameterDecodingConfig{ + Name: "page", + Style: uri.QueryStyleForm, + Explode: true, + Fields: []uri.QueryParameterObjectField{{Name: "Page", Required: true}, {Name: "Limit", Required: true}}, + } + + if err := q.HasParam(cfg); err == nil { + if err := q.DecodeParam(cfg, func(d uri.Decoder) error { + return params.Page.DecodeURI(d) + }); err != nil { + return err + } + if err := func() error { + if err := params.Page.Validate(); err != nil { + return err + } + return nil + }(); err != nil { + return err + } + } else { + return validate.ErrFieldRequired + } + return nil + }(); err != nil { + return params, &ogenerrors.DecodeParamError{ + Name: "page", + In: "query", + Err: err, + } + } + // Decode query: filter. + if err := func() error { + cfg := uri.QueryParameterDecodingConfig{ + Name: "filter", + Style: uri.QueryStyleForm, + Explode: true, + Fields: []uri.QueryParameterObjectField{{Name: "ID", Required: false}, {Name: "FromScriptHash", Required: false}, {Name: "ToScriptID", Required: false}, {Name: "Policy", Required: false}}, + } + + if err := q.HasParam(cfg); err == nil { + if err := q.DecodeParam(cfg, func(d uri.Decoder) error { + var paramsDotFilterVal ScriptPolicyFilter + if err := func() error { + return paramsDotFilterVal.DecodeURI(d) + }(); err != nil { + return err + } + params.Filter.SetTo(paramsDotFilterVal) + return nil + }); err != nil { + return err + } + if err := func() error { + if value, ok := params.Filter.Get(); ok { + if err := func() error { + if err := value.Validate(); err != nil { + return err + } + return nil + }(); err != nil { + return err + } + } + return nil + }(); err != nil { + return err + } + } + return nil + }(); err != nil { + return params, &ogenerrors.DecodeParamError{ + Name: "filter", + In: "query", + Err: err, + } + } + return params, nil +} + // ListSubmissionsParams is parameters of listSubmissions operation. type ListSubmissionsParams struct { Page Pagination diff --git a/pkg/api/oas_response_decoders_gen.go b/pkg/api/oas_response_decoders_gen.go index db875be..e58bd6d 100644 --- a/pkg/api/oas_response_decoders_gen.go +++ b/pkg/api/oas_response_decoders_gen.go @@ -1142,6 +1142,123 @@ func decodeGetSubmissionResponse(resp *http.Response) (res *Submission, _ error) return res, errors.Wrap(defRes, "error") } +func decodeListScriptPolicyResponse(resp *http.Response) (res []ScriptPolicy, _ error) { + switch resp.StatusCode { + case 200: + // Code 200. + ct, _, err := mime.ParseMediaType(resp.Header.Get("Content-Type")) + if err != nil { + return res, errors.Wrap(err, "parse media type") + } + switch { + case ct == "application/json": + buf, err := io.ReadAll(resp.Body) + if err != nil { + return res, err + } + d := jx.DecodeBytes(buf) + + var response []ScriptPolicy + if err := func() error { + response = make([]ScriptPolicy, 0) + if err := d.Arr(func(d *jx.Decoder) error { + var elem ScriptPolicy + if err := elem.Decode(d); err != nil { + return err + } + response = append(response, elem) + return nil + }); 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 res, err + } + // Validate response. + if err := func() error { + if response == nil { + return errors.New("nil is invalid value") + } + var failures []validate.FieldError + for i, elem := range response { + 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 + }(); err != nil { + return res, errors.Wrap(err, "validate") + } + return response, nil + default: + return res, validate.InvalidContentType(ct) + } + } + // Convenient error response. + defRes, err := func() (res *ErrorStatusCode, err error) { + ct, _, err := mime.ParseMediaType(resp.Header.Get("Content-Type")) + if err != nil { + return res, errors.Wrap(err, "parse media type") + } + switch { + case ct == "application/json": + buf, err := io.ReadAll(resp.Body) + if err != nil { + return res, err + } + d := jx.DecodeBytes(buf) + + var response Error + if err := func() error { + if err := response.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 res, err + } + return &ErrorStatusCode{ + StatusCode: resp.StatusCode, + Response: response, + }, nil + default: + return res, validate.InvalidContentType(ct) + } + }() + if err != nil { + return res, errors.Wrapf(err, "default (code %d)", resp.StatusCode) + } + return res, errors.Wrap(defRes, "error") +} + func decodeListSubmissionsResponse(resp *http.Response) (res []Submission, _ error) { switch resp.StatusCode { case 200: diff --git a/pkg/api/oas_response_encoders_gen.go b/pkg/api/oas_response_encoders_gen.go index e5b235c..cfd12f2 100644 --- a/pkg/api/oas_response_encoders_gen.go +++ b/pkg/api/oas_response_encoders_gen.go @@ -181,6 +181,24 @@ func encodeGetSubmissionResponse(response *Submission, w http.ResponseWriter, sp return nil } +func encodeListScriptPolicyResponse(response []ScriptPolicy, w http.ResponseWriter, span trace.Span) error { + w.Header().Set("Content-Type", "application/json; charset=utf-8") + w.WriteHeader(200) + span.SetStatus(codes.Ok, http.StatusText(200)) + + e := new(jx.Encoder) + e.ArrStart() + for _, elem := range response { + elem.Encode(e) + } + e.ArrEnd() + if _, err := e.WriteTo(w); err != nil { + return errors.Wrap(err, "write") + } + + return nil +} + func encodeListSubmissionsResponse(response []Submission, w http.ResponseWriter, span trace.Span) error { w.Header().Set("Content-Type", "application/json; charset=utf-8") w.WriteHeader(200) diff --git a/pkg/api/oas_router_gen.go b/pkg/api/oas_router_gen.go index 3051eb8..e9a4b0c 100644 --- a/pkg/api/oas_router_gen.go +++ b/pkg/api/oas_router_gen.go @@ -83,10 +83,12 @@ func (s *Server) ServeHTTP(w http.ResponseWriter, r *http.Request) { if len(elem) == 0 { switch r.Method { + case "GET": + s.handleListScriptPolicyRequest([0]string{}, elemIsEscaped, w, r) case "POST": s.handleCreateScriptPolicyRequest([0]string{}, elemIsEscaped, w, r) default: - s.notAllowed(w, r, "POST") + s.notAllowed(w, r, "GET,POST") } return @@ -714,6 +716,14 @@ func (s *Server) FindPath(method string, u *url.URL) (r Route, _ bool) { if len(elem) == 0 { switch method { + case "GET": + r.name = ListScriptPolicyOperation + r.summary = "Get list of script policies" + r.operationID = "listScriptPolicy" + r.pathPattern = "/script-policy" + r.args = args + r.count = 0 + return r, true case "POST": r.name = CreateScriptPolicyOperation r.summary = "Create a new script policy" diff --git a/pkg/api/oas_schemas_gen.go b/pkg/api/oas_schemas_gen.go index fb6c9b6..5fa2e91 100644 --- a/pkg/api/oas_schemas_gen.go +++ b/pkg/api/oas_schemas_gen.go @@ -214,6 +214,52 @@ func (o OptInt64) Or(d int64) int64 { return d } +// NewOptScriptPolicyFilter returns new OptScriptPolicyFilter with value set to v. +func NewOptScriptPolicyFilter(v ScriptPolicyFilter) OptScriptPolicyFilter { + return OptScriptPolicyFilter{ + Value: v, + Set: true, + } +} + +// OptScriptPolicyFilter is optional ScriptPolicyFilter. +type OptScriptPolicyFilter struct { + Value ScriptPolicyFilter + Set bool +} + +// IsSet returns true if OptScriptPolicyFilter was set. +func (o OptScriptPolicyFilter) IsSet() bool { return o.Set } + +// Reset unsets value. +func (o *OptScriptPolicyFilter) Reset() { + var v ScriptPolicyFilter + o.Value = v + o.Set = false +} + +// SetTo sets value to v. +func (o *OptScriptPolicyFilter) SetTo(v ScriptPolicyFilter) { + o.Set = true + o.Value = v +} + +// Get returns value and boolean that denotes whether value was set. +func (o OptScriptPolicyFilter) Get() (v ScriptPolicyFilter, ok bool) { + if !o.Set { + return v, false + } + return o.Value, true +} + +// Or returns value if set, or given parameter if does not. +func (o OptScriptPolicyFilter) Or(d ScriptPolicyFilter) ScriptPolicyFilter { + if v, ok := o.Get(); ok { + return v + } + return d +} + // NewOptString returns new OptString with value set to v. func NewOptString(v string) OptString { return OptString{ @@ -491,6 +537,54 @@ func (s *ScriptPolicyCreate) SetPolicy(val int32) { s.Policy = val } +// Ref: #/components/schemas/ScriptPolicyFilter +type ScriptPolicyFilter struct { + ID OptInt64 `json:"ID"` + FromScriptHash OptString `json:"FromScriptHash"` + ToScriptID OptInt64 `json:"ToScriptID"` + Policy OptInt32 `json:"Policy"` +} + +// GetID returns the value of ID. +func (s *ScriptPolicyFilter) GetID() OptInt64 { + return s.ID +} + +// GetFromScriptHash returns the value of FromScriptHash. +func (s *ScriptPolicyFilter) GetFromScriptHash() OptString { + return s.FromScriptHash +} + +// GetToScriptID returns the value of ToScriptID. +func (s *ScriptPolicyFilter) GetToScriptID() OptInt64 { + return s.ToScriptID +} + +// GetPolicy returns the value of Policy. +func (s *ScriptPolicyFilter) GetPolicy() OptInt32 { + return s.Policy +} + +// SetID sets the value of ID. +func (s *ScriptPolicyFilter) SetID(val OptInt64) { + s.ID = val +} + +// SetFromScriptHash sets the value of FromScriptHash. +func (s *ScriptPolicyFilter) SetFromScriptHash(val OptString) { + s.FromScriptHash = val +} + +// SetToScriptID sets the value of ToScriptID. +func (s *ScriptPolicyFilter) SetToScriptID(val OptInt64) { + s.ToScriptID = val +} + +// SetPolicy sets the value of Policy. +func (s *ScriptPolicyFilter) SetPolicy(val OptInt32) { + s.Policy = val +} + // Ref: #/components/schemas/ScriptPolicyUpdate type ScriptPolicyUpdate struct { ID int64 `json:"ID"` diff --git a/pkg/api/oas_server_gen.go b/pkg/api/oas_server_gen.go index c88fc17..36c6a21 100644 --- a/pkg/api/oas_server_gen.go +++ b/pkg/api/oas_server_gen.go @@ -110,6 +110,12 @@ type Handler interface { // // GET /submissions/{SubmissionID} GetSubmission(ctx context.Context, params GetSubmissionParams) (*Submission, error) + // ListScriptPolicy implements listScriptPolicy operation. + // + // Get list of script policies. + // + // GET /script-policy + ListScriptPolicy(ctx context.Context, params ListScriptPolicyParams) ([]ScriptPolicy, error) // ListSubmissions implements listSubmissions operation. // // Get list of submissions. diff --git a/pkg/api/oas_unimplemented_gen.go b/pkg/api/oas_unimplemented_gen.go index 10ef8ac..5b5295c 100644 --- a/pkg/api/oas_unimplemented_gen.go +++ b/pkg/api/oas_unimplemented_gen.go @@ -166,6 +166,15 @@ func (UnimplementedHandler) GetSubmission(ctx context.Context, params GetSubmiss return r, ht.ErrNotImplemented } +// ListScriptPolicy implements listScriptPolicy operation. +// +// Get list of script policies. +// +// GET /script-policy +func (UnimplementedHandler) ListScriptPolicy(ctx context.Context, params ListScriptPolicyParams) (r []ScriptPolicy, _ error) { + return r, ht.ErrNotImplemented +} + // ListSubmissions implements listSubmissions operation. // // Get list of submissions. diff --git a/pkg/api/oas_uri_gen.go b/pkg/api/oas_uri_gen.go index e80687d..83d6123 100644 --- a/pkg/api/oas_uri_gen.go +++ b/pkg/api/oas_uri_gen.go @@ -121,6 +121,165 @@ func (s *Pagination) DecodeURI(d uri.Decoder) error { return nil } +// EncodeURI encodes ScriptPolicyFilter as URI form. +func (s *ScriptPolicyFilter) EncodeURI(e uri.Encoder) error { + if err := e.EncodeField("ID", func(e uri.Encoder) error { + if val, ok := s.ID.Get(); ok { + return e.EncodeValue(conv.Int64ToString(val)) + } + return nil + }); err != nil { + return errors.Wrap(err, "encode field \"ID\"") + } + if err := e.EncodeField("FromScriptHash", func(e uri.Encoder) error { + if val, ok := s.FromScriptHash.Get(); ok { + return e.EncodeValue(conv.StringToString(val)) + } + return nil + }); err != nil { + return errors.Wrap(err, "encode field \"FromScriptHash\"") + } + if err := e.EncodeField("ToScriptID", func(e uri.Encoder) error { + if val, ok := s.ToScriptID.Get(); ok { + return e.EncodeValue(conv.Int64ToString(val)) + } + return nil + }); err != nil { + return errors.Wrap(err, "encode field \"ToScriptID\"") + } + if err := e.EncodeField("Policy", func(e uri.Encoder) error { + if val, ok := s.Policy.Get(); ok { + return e.EncodeValue(conv.Int32ToString(val)) + } + return nil + }); err != nil { + return errors.Wrap(err, "encode field \"Policy\"") + } + return nil +} + +var uriFieldsNameOfScriptPolicyFilter = [4]string{ + 0: "ID", + 1: "FromScriptHash", + 2: "ToScriptID", + 3: "Policy", +} + +// DecodeURI decodes ScriptPolicyFilter from URI form. +func (s *ScriptPolicyFilter) DecodeURI(d uri.Decoder) error { + if s == nil { + return errors.New("invalid: unable to decode ScriptPolicyFilter to nil") + } + + if err := d.DecodeFields(func(k string, d uri.Decoder) error { + switch k { + case "ID": + if err := func() error { + var sDotIDVal int64 + if err := func() error { + val, err := d.DecodeValue() + if err != nil { + return err + } + + c, err := conv.ToInt64(val) + if err != nil { + return err + } + + sDotIDVal = c + return nil + }(); err != nil { + return err + } + s.ID.SetTo(sDotIDVal) + return nil + }(); err != nil { + return errors.Wrap(err, "decode field \"ID\"") + } + case "FromScriptHash": + if err := func() error { + var sDotFromScriptHashVal string + if err := func() error { + val, err := d.DecodeValue() + if err != nil { + return err + } + + c, err := conv.ToString(val) + if err != nil { + return err + } + + sDotFromScriptHashVal = c + return nil + }(); err != nil { + return err + } + s.FromScriptHash.SetTo(sDotFromScriptHashVal) + return nil + }(); err != nil { + return errors.Wrap(err, "decode field \"FromScriptHash\"") + } + case "ToScriptID": + if err := func() error { + var sDotToScriptIDVal int64 + if err := func() error { + val, err := d.DecodeValue() + if err != nil { + return err + } + + c, err := conv.ToInt64(val) + if err != nil { + return err + } + + sDotToScriptIDVal = c + return nil + }(); err != nil { + return err + } + s.ToScriptID.SetTo(sDotToScriptIDVal) + return nil + }(); err != nil { + return errors.Wrap(err, "decode field \"ToScriptID\"") + } + case "Policy": + if err := func() error { + var sDotPolicyVal int32 + if err := func() error { + val, err := d.DecodeValue() + if err != nil { + return err + } + + c, err := conv.ToInt32(val) + if err != nil { + return err + } + + sDotPolicyVal = c + return nil + }(); err != nil { + return err + } + s.Policy.SetTo(sDotPolicyVal) + return nil + }(); err != nil { + return errors.Wrap(err, "decode field \"Policy\"") + } + default: + return nil + } + return nil + }); err != nil { + return errors.Wrap(err, "decode ScriptPolicyFilter") + } + + return nil +} + // EncodeURI encodes SubmissionFilter as URI form. func (s *SubmissionFilter) EncodeURI(e uri.Encoder) error { if err := e.EncodeField("ID", func(e uri.Encoder) error { diff --git a/pkg/api/oas_validators_gen.go b/pkg/api/oas_validators_gen.go index acb3e27..5ec5638 100644 --- a/pkg/api/oas_validators_gen.go +++ b/pkg/api/oas_validators_gen.go @@ -172,6 +172,44 @@ func (s *ScriptPolicy) Validate() error { return nil } +func (s *ScriptPolicyFilter) Validate() error { + if s == nil { + return validate.ErrNilPointer + } + + var failures []validate.FieldError + if err := func() error { + if value, ok := s.FromScriptHash.Get(); ok { + if err := func() error { + if err := (validate.String{ + MinLength: 16, + MinLengthSet: true, + MaxLength: 16, + MaxLengthSet: true, + Email: false, + Hostname: false, + Regex: nil, + }).Validate(string(value)); err != nil { + return errors.Wrap(err, "string") + } + return nil + }(); err != nil { + return err + } + } + return nil + }(); err != nil { + failures = append(failures, validate.FieldError{ + Name: "FromScriptHash", + Error: err, + }) + } + if len(failures) > 0 { + return &validate.Error{Fields: failures} + } + return nil +} + func (s *ScriptUpdate) Validate() error { if s == nil { return validate.ErrNilPointer diff --git a/pkg/datastore/datastore.go b/pkg/datastore/datastore.go index 89c0b07..e5bd32a 100644 --- a/pkg/datastore/datastore.go +++ b/pkg/datastore/datastore.go @@ -41,4 +41,5 @@ type ScriptPolicy interface { Create(ctx context.Context, smap model.ScriptPolicy) (model.ScriptPolicy, error) Update(ctx context.Context, id int64, values OptionalMap) error Delete(ctx context.Context, id int64) error + List(ctx context.Context, filters OptionalMap, page model.Page) ([]model.ScriptPolicy, error) } diff --git a/pkg/datastore/gormstore/script_policy.go b/pkg/datastore/gormstore/script_policy.go index 9c292bc..72f1b6f 100644 --- a/pkg/datastore/gormstore/script_policy.go +++ b/pkg/datastore/gormstore/script_policy.go @@ -62,3 +62,12 @@ func (env *ScriptPolicy) Delete(ctx context.Context, id int64) error { return nil } + +func (env *ScriptPolicy) List(ctx context.Context, filters datastore.OptionalMap, page model.Page) ([]model.ScriptPolicy, error) { + var maps []model.ScriptPolicy + if err := env.db.Where(filters.Map()).Offset(int((page.Number - 1) * page.Size)).Limit(int(page.Size)).Find(&maps).Error; err != nil { + return nil, err + } + + return maps, nil +} diff --git a/pkg/service/script_policy.go b/pkg/service/script_policy.go index 170d420..855e79b 100644 --- a/pkg/service/script_policy.go +++ b/pkg/service/script_policy.go @@ -47,6 +47,42 @@ func (svc *Service) CreateScriptPolicy(ctx context.Context, req *api.ScriptPolic }, nil } + +// ListScriptPolicy implements listScriptPolicy operation. +// +// Get list of script policies. +// +// GET /script-policy +func (svc *Service) ListScriptPolicy(ctx context.Context, params api.ListScriptPolicyParams) ([]api.ScriptPolicy, error) { + filter := datastore.Optional() + //fmt.Println(request) + if params.Filter.IsSet() { + filter.AddNotNil("from_script_hash", params.Filter.Value.FromScriptHash) + filter.AddNotNil("to_script_id", params.Filter.Value.ToScriptID) + filter.AddNotNil("policy", params.Filter.Value.Policy) + } + + items, err := svc.DB.ScriptPolicy().List(ctx, filter, model.Page{ + Number: params.Page.GetPage(), + Size: params.Page.GetLimit(), + }) + if err != nil { + return nil, err + } + + var resp []api.ScriptPolicy + for i := 0; i < len(items); i++ { + resp = append(resp, api.ScriptPolicy{ + ID: items[i].ID, + FromScriptHash: fmt.Sprintf("%x", items[i].FromScriptHash), + ToScriptID: items[i].ToScriptID, + Policy: int32(items[i].Policy), + }) + } + + return resp, nil +} + // DeleteScriptPolicy implements deleteScriptPolicy operation. // // Delete the specified script policy by ID.