diff --git a/pkg/zero/cluster/client.gen.go b/pkg/zero/cluster/client.gen.go index 21e183063..4ec9ec035 100644 --- a/pkg/zero/cluster/client.gen.go +++ b/pkg/zero/cluster/client.gen.go @@ -107,6 +107,11 @@ type ClientInterface interface { ExchangeClusterIdentityTokenWithBody(ctx context.Context, contentType string, body io.Reader, reqEditors ...RequestEditorFn) (*http.Response, error) ExchangeClusterIdentityToken(ctx context.Context, body ExchangeClusterIdentityTokenJSONRequestBody, reqEditors ...RequestEditorFn) (*http.Response, error) + + // ReportUsageWithBody request with any body + ReportUsageWithBody(ctx context.Context, contentType string, body io.Reader, reqEditors ...RequestEditorFn) (*http.Response, error) + + ReportUsage(ctx context.Context, body ReportUsageJSONRequestBody, reqEditors ...RequestEditorFn) (*http.Response, error) } func (c *Client) GetClusterBootstrapConfig(ctx context.Context, reqEditors ...RequestEditorFn) (*http.Response, error) { @@ -193,6 +198,30 @@ func (c *Client) ExchangeClusterIdentityToken(ctx context.Context, body Exchange return c.Client.Do(req) } +func (c *Client) ReportUsageWithBody(ctx context.Context, contentType string, body io.Reader, reqEditors ...RequestEditorFn) (*http.Response, error) { + req, err := NewReportUsageRequestWithBody(c.Server, contentType, body) + if err != nil { + return nil, err + } + req = req.WithContext(ctx) + if err := c.applyEditors(ctx, req, reqEditors); err != nil { + return nil, err + } + return c.Client.Do(req) +} + +func (c *Client) ReportUsage(ctx context.Context, body ReportUsageJSONRequestBody, reqEditors ...RequestEditorFn) (*http.Response, error) { + req, err := NewReportUsageRequest(c.Server, body) + if err != nil { + return nil, err + } + req = req.WithContext(ctx) + if err := c.applyEditors(ctx, req, reqEditors); err != nil { + return nil, err + } + return c.Client.Do(req) +} + // NewGetClusterBootstrapConfigRequest generates requests for GetClusterBootstrapConfig func NewGetClusterBootstrapConfigRequest(server string) (*http.Request, error) { var err error @@ -368,6 +397,46 @@ func NewExchangeClusterIdentityTokenRequestWithBody(server string, contentType s return req, nil } +// NewReportUsageRequest calls the generic ReportUsage builder with application/json body +func NewReportUsageRequest(server string, body ReportUsageJSONRequestBody) (*http.Request, error) { + var bodyReader io.Reader + buf, err := json.Marshal(body) + if err != nil { + return nil, err + } + bodyReader = bytes.NewReader(buf) + return NewReportUsageRequestWithBody(server, "application/json", bodyReader) +} + +// NewReportUsageRequestWithBody generates requests for ReportUsage with any type of body +func NewReportUsageRequestWithBody(server string, contentType string, body io.Reader) (*http.Request, error) { + var err error + + serverURL, err := url.Parse(server) + if err != nil { + return nil, err + } + + operationPath := fmt.Sprintf("/reportUsage") + if operationPath[0] == '/' { + operationPath = "." + operationPath + } + + queryURL, err := serverURL.Parse(operationPath) + if err != nil { + return nil, err + } + + req, err := http.NewRequest("POST", queryURL.String(), body) + if err != nil { + return nil, err + } + + req.Header.Add("Content-Type", contentType) + + return req, nil +} + func (c *Client) applyEditors(ctx context.Context, req *http.Request, additionalEditors []RequestEditorFn) error { for _, r := range c.RequestEditors { if err := r(ctx, req); err != nil { @@ -429,6 +498,11 @@ type ClientWithResponsesInterface interface { ExchangeClusterIdentityTokenWithBodyWithResponse(ctx context.Context, contentType string, body io.Reader, reqEditors ...RequestEditorFn) (*ExchangeClusterIdentityTokenResp, error) ExchangeClusterIdentityTokenWithResponse(ctx context.Context, body ExchangeClusterIdentityTokenJSONRequestBody, reqEditors ...RequestEditorFn) (*ExchangeClusterIdentityTokenResp, error) + + // ReportUsageWithBodyWithResponse request with any body + ReportUsageWithBodyWithResponse(ctx context.Context, contentType string, body io.Reader, reqEditors ...RequestEditorFn) (*ReportUsageResp, error) + + ReportUsageWithResponse(ctx context.Context, body ReportUsageJSONRequestBody, reqEditors ...RequestEditorFn) (*ReportUsageResp, error) } type GetClusterBootstrapConfigResp struct { @@ -551,6 +625,27 @@ func (r ExchangeClusterIdentityTokenResp) StatusCode() int { return 0 } +type ReportUsageResp struct { + Body []byte + HTTPResponse *http.Response +} + +// Status returns HTTPResponse.Status +func (r ReportUsageResp) Status() string { + if r.HTTPResponse != nil { + return r.HTTPResponse.Status + } + return http.StatusText(0) +} + +// StatusCode returns HTTPResponse.StatusCode +func (r ReportUsageResp) StatusCode() int { + if r.HTTPResponse != nil { + return r.HTTPResponse.StatusCode + } + return 0 +} + // GetClusterBootstrapConfigWithResponse request returning *GetClusterBootstrapConfigResp func (c *ClientWithResponses) GetClusterBootstrapConfigWithResponse(ctx context.Context, reqEditors ...RequestEditorFn) (*GetClusterBootstrapConfigResp, error) { rsp, err := c.GetClusterBootstrapConfig(ctx, reqEditors...) @@ -612,6 +707,23 @@ func (c *ClientWithResponses) ExchangeClusterIdentityTokenWithResponse(ctx conte return ParseExchangeClusterIdentityTokenResp(rsp) } +// ReportUsageWithBodyWithResponse request with arbitrary body returning *ReportUsageResp +func (c *ClientWithResponses) ReportUsageWithBodyWithResponse(ctx context.Context, contentType string, body io.Reader, reqEditors ...RequestEditorFn) (*ReportUsageResp, error) { + rsp, err := c.ReportUsageWithBody(ctx, contentType, body, reqEditors...) + if err != nil { + return nil, err + } + return ParseReportUsageResp(rsp) +} + +func (c *ClientWithResponses) ReportUsageWithResponse(ctx context.Context, body ReportUsageJSONRequestBody, reqEditors ...RequestEditorFn) (*ReportUsageResp, error) { + rsp, err := c.ReportUsage(ctx, body, reqEditors...) + if err != nil { + return nil, err + } + return ParseReportUsageResp(rsp) +} + // ParseGetClusterBootstrapConfigResp parses an HTTP response from a GetClusterBootstrapConfigWithResponse call func ParseGetClusterBootstrapConfigResp(rsp *http.Response) (*GetClusterBootstrapConfigResp, error) { bodyBytes, err := io.ReadAll(rsp.Body) @@ -812,6 +924,22 @@ func ParseExchangeClusterIdentityTokenResp(rsp *http.Response) (*ExchangeCluster return response, nil } +// ParseReportUsageResp parses an HTTP response from a ReportUsageWithResponse call +func ParseReportUsageResp(rsp *http.Response) (*ReportUsageResp, error) { + bodyBytes, err := io.ReadAll(rsp.Body) + defer func() { _ = rsp.Body.Close() }() + if err != nil { + return nil, err + } + + response := &ReportUsageResp{ + Body: bodyBytes, + HTTPResponse: rsp, + } + + return response, nil +} + // GetHTTPResponse implements apierror.APIResponse func (r *GetClusterBootstrapConfigResp) GetHTTPResponse() *http.Response { return r.HTTPResponse @@ -951,3 +1079,16 @@ func (r *ExchangeClusterIdentityTokenResp) GetInternalServerError() (string, boo } return r.JSON500.Error, true } + +// GetHTTPResponse implements apierror.APIResponse +func (r *ReportUsageResp) GetHTTPResponse() *http.Response { + return r.HTTPResponse +} + +// GetValue implements apierror.APIResponse +func (r *ReportUsageResp) GetValue() *EmptyResponse { + if r.StatusCode()/100 != 2 { + return nil + } + return &EmptyResponse{} +} diff --git a/pkg/zero/cluster/models.gen.go b/pkg/zero/cluster/models.gen.go index ac33f9099..2aec18fa3 100644 --- a/pkg/zero/cluster/models.gen.go +++ b/pkg/zero/cluster/models.gen.go @@ -3,6 +3,10 @@ // Code generated by github.com/oapi-codegen/oapi-codegen/v2 version v2.3.0 DO NOT EDIT. package cluster +import ( + "time" +) + const ( BearerAuthScopes = "bearerAuth.Scopes" ) @@ -95,6 +99,18 @@ type GetBundlesResponse struct { Bundles []Bundle `json:"bundles"` } +// ReportUsageRequest defines model for ReportUsageRequest. +type ReportUsageRequest struct { + Users []ReportUsageUser `json:"users"` +} + +// ReportUsageUser defines model for ReportUsageUser. +type ReportUsageUser struct { + LastSignedInAt time.Time `json:"lastSignedInAt"` + PseudonymousEmail string `json:"pseudonymousEmail"` + PseudonymousId string `json:"pseudonymousId"` +} + // BundleId defines model for bundleId. type BundleId = string @@ -103,3 +119,6 @@ type ReportClusterResourceBundleStatusJSONRequestBody = BundleStatus // ExchangeClusterIdentityTokenJSONRequestBody defines body for ExchangeClusterIdentityToken for application/json ContentType. type ExchangeClusterIdentityTokenJSONRequestBody = ExchangeTokenRequest + +// ReportUsageJSONRequestBody defines body for ReportUsage for application/json ContentType. +type ReportUsageJSONRequestBody = ReportUsageRequest diff --git a/pkg/zero/cluster/openapi.yaml b/pkg/zero/cluster/openapi.yaml index df1c2d466..10d20b0fb 100644 --- a/pkg/zero/cluster/openapi.yaml +++ b/pkg/zero/cluster/openapi.yaml @@ -149,6 +149,21 @@ paths: schema: $ref: "#/components/schemas/ErrorResponse" + /reportUsage: + post: + description: Report usage for the cluster + operationId: reportUsage + tags: [usage] + requestBody: + required: true + content: + application/json: + schema: + $ref: "#/components/schemas/ReportUsageRequest" + responses: + "204": + description: OK + components: parameters: bundleId: @@ -279,3 +294,26 @@ components: $ref: "#/components/schemas/Bundle" required: - bundles + ReportUsageRequest: + type: object + properties: + users: + type: array + items: + $ref: "#/components/schemas/ReportUsageUser" + required: + - users + ReportUsageUser: + type: object + properties: + lastSignedInAt: + type: string + format: "date-time" + pseudonymousEmail: + type: string + pseudonymousId: + type: string + required: + - lastSignedInAt + - pseudonymousEmail + - pseudonymousId diff --git a/pkg/zero/cluster/server.gen.go b/pkg/zero/cluster/server.gen.go index d12303d69..d8cd60eec 100644 --- a/pkg/zero/cluster/server.gen.go +++ b/pkg/zero/cluster/server.gen.go @@ -31,6 +31,9 @@ type ServerInterface interface { // (POST /exchangeToken) ExchangeClusterIdentityToken(w http.ResponseWriter, r *http.Request) + + // (POST /reportUsage) + ReportUsage(w http.ResponseWriter, r *http.Request) } // Unimplemented server implementation that returns http.StatusNotImplemented for each endpoint. @@ -62,6 +65,11 @@ func (_ Unimplemented) ExchangeClusterIdentityToken(w http.ResponseWriter, r *ht w.WriteHeader(http.StatusNotImplemented) } +// (POST /reportUsage) +func (_ Unimplemented) ReportUsage(w http.ResponseWriter, r *http.Request) { + w.WriteHeader(http.StatusNotImplemented) +} + // ServerInterfaceWrapper converts contexts to parameters. type ServerInterfaceWrapper struct { Handler ServerInterface @@ -176,6 +184,23 @@ func (siw *ServerInterfaceWrapper) ExchangeClusterIdentityToken(w http.ResponseW handler.ServeHTTP(w, r.WithContext(ctx)) } +// ReportUsage operation middleware +func (siw *ServerInterfaceWrapper) ReportUsage(w http.ResponseWriter, r *http.Request) { + ctx := r.Context() + + ctx = context.WithValue(ctx, BearerAuthScopes, []string{}) + + handler := http.Handler(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + siw.Handler.ReportUsage(w, r) + })) + + for i := len(siw.HandlerMiddlewares) - 1; i >= 0; i-- { + handler = siw.HandlerMiddlewares[i](handler) + } + + handler.ServeHTTP(w, r.WithContext(ctx)) +} + type UnescapedCookieParamError struct { ParamName string Err error @@ -304,6 +329,9 @@ func HandlerWithOptions(si ServerInterface, options ChiServerOptions) http.Handl r.Group(func(r chi.Router) { r.Post(options.BaseURL+"/exchangeToken", wrapper.ExchangeClusterIdentityToken) }) + r.Group(func(r chi.Router) { + r.Post(options.BaseURL+"/reportUsage", wrapper.ReportUsage) + }) return r } @@ -490,6 +518,22 @@ func (response ExchangeClusterIdentityToken500JSONResponse) VisitExchangeCluster return json.NewEncoder(w).Encode(response) } +type ReportUsageRequestObject struct { + Body *ReportUsageJSONRequestBody +} + +type ReportUsageResponseObject interface { + VisitReportUsageResponse(w http.ResponseWriter) error +} + +type ReportUsage204Response struct { +} + +func (response ReportUsage204Response) VisitReportUsageResponse(w http.ResponseWriter) error { + w.WriteHeader(204) + return nil +} + // StrictServerInterface represents all server handlers. type StrictServerInterface interface { @@ -507,6 +551,9 @@ type StrictServerInterface interface { // (POST /exchangeToken) ExchangeClusterIdentityToken(ctx context.Context, request ExchangeClusterIdentityTokenRequestObject) (ExchangeClusterIdentityTokenResponseObject, error) + + // (POST /reportUsage) + ReportUsage(ctx context.Context, request ReportUsageRequestObject) (ReportUsageResponseObject, error) } type StrictHandlerFunc = strictnethttp.StrictHTTPHandlerFunc @@ -675,3 +722,34 @@ func (sh *strictHandler) ExchangeClusterIdentityToken(w http.ResponseWriter, r * sh.options.ResponseErrorHandlerFunc(w, r, fmt.Errorf("unexpected response type: %T", response)) } } + +// ReportUsage operation middleware +func (sh *strictHandler) ReportUsage(w http.ResponseWriter, r *http.Request) { + var request ReportUsageRequestObject + + var body ReportUsageJSONRequestBody + if err := json.NewDecoder(r.Body).Decode(&body); err != nil { + sh.options.RequestErrorHandlerFunc(w, r, fmt.Errorf("can't decode JSON body: %w", err)) + return + } + request.Body = &body + + handler := func(ctx context.Context, w http.ResponseWriter, r *http.Request, request interface{}) (interface{}, error) { + return sh.ssi.ReportUsage(ctx, request.(ReportUsageRequestObject)) + } + for _, middleware := range sh.middlewares { + handler = middleware(handler, "ReportUsage") + } + + response, err := handler(r.Context(), w, r, request) + + if err != nil { + sh.options.ResponseErrorHandlerFunc(w, r, err) + } else if validResponse, ok := response.(ReportUsageResponseObject); ok { + if err := validResponse.VisitReportUsageResponse(w); err != nil { + sh.options.ResponseErrorHandlerFunc(w, r, err) + } + } else if response != nil { + sh.options.ResponseErrorHandlerFunc(w, r, fmt.Errorf("unexpected response type: %T", response)) + } +}