diff --git a/core/api/oas_defaults_gen.go b/core/api/oas_defaults_gen.go index 8265458c..6d1e3983 100644 --- a/core/api/oas_defaults_gen.go +++ b/core/api/oas_defaults_gen.go @@ -51,17 +51,13 @@ func (s *UnauthorisedErrorError) setDefaults() { } // setDefaults set default value of fields. -func (s *UserGet) setDefaults() { +func (s *UserSettings) setDefaults() { { - val := UserGetLanguage("en") - s.Language = val + val := UserSettingsLanguage("en") + s.Language.SetTo(val) } -} - -// setDefaults set default value of fields. -func (s *UserPatch) setDefaults() { { - val := UserPatchLanguage("en") - s.Language.SetTo(val) + val := UserSettingsScriptType("default") + s.ScriptType.SetTo(val) } } diff --git a/core/api/oas_handlers_gen.go b/core/api/oas_handlers_gen.go index cbc713d4..43b8506d 100644 --- a/core/api/oas_handlers_gen.go +++ b/core/api/oas_handlers_gen.go @@ -348,26 +348,26 @@ func (s *Server) handleGetEventPingRequest(args [0]string, argsEscaped bool, w h } } -// handleGetSettingsUsageRequest handles get-settings-usage operation. +// handleGetUserRequest handles get-user operation. // -// Get the current CPU, memory and disk usage of the server. +// Retrieve the information of the user with the matching user ID. // -// GET /settings/usage -func (s *Server) handleGetSettingsUsageRequest(args [0]string, argsEscaped bool, w http.ResponseWriter, r *http.Request) { +// GET /user +func (s *Server) handleGetUserRequest(args [0]string, argsEscaped bool, w http.ResponseWriter, r *http.Request) { ctx := r.Context() var ( err error opErrContext = ogenerrors.OperationContext{ - Name: "GetSettingsUsage", - ID: "get-settings-usage", + Name: "GetUser", + ID: "get-user", } ) { type bitset = [1]uint8 var satisfied bitset { - sctx, ok, err := s.securityCookieAuth(ctx, "GetSettingsUsage", r) + sctx, ok, err := s.securityCookieAuth(ctx, "GetUser", r) if err != nil { err = &ogenerrors.SecurityError{ OperationContext: opErrContext, @@ -407,7 +407,7 @@ func (s *Server) handleGetSettingsUsageRequest(args [0]string, argsEscaped bool, return } } - params, err := decodeGetSettingsUsageParams(args, argsEscaped, r) + params, err := decodeGetUserParams(args, argsEscaped, r) if err != nil { err = &ogenerrors.DecodeParamsError{ OperationContext: opErrContext, @@ -418,13 +418,13 @@ func (s *Server) handleGetSettingsUsageRequest(args [0]string, argsEscaped bool, return } - var response GetSettingsUsageRes + var response GetUserRes if m := s.cfg.Middleware; m != nil { mreq := middleware.Request{ Context: ctx, - OperationName: "GetSettingsUsage", - OperationSummary: "Get Resource Usage", - OperationID: "get-settings-usage", + OperationName: "GetUser", + OperationSummary: "Get User Info", + OperationID: "get-user", Body: nil, Params: middleware.Parameters{ { @@ -437,8 +437,8 @@ func (s *Server) handleGetSettingsUsageRequest(args [0]string, argsEscaped bool, type ( Request = struct{} - Params = GetSettingsUsageParams - Response = GetSettingsUsageRes + Params = GetUserParams + Response = GetUserRes ) response, err = middleware.HookMiddleware[ Request, @@ -447,14 +447,14 @@ func (s *Server) handleGetSettingsUsageRequest(args [0]string, argsEscaped bool, ]( m, mreq, - unpackGetSettingsUsageParams, + unpackGetUserParams, func(ctx context.Context, request Request, params Params) (response Response, err error) { - response, err = s.h.GetSettingsUsage(ctx, params) + response, err = s.h.GetUser(ctx, params) return response, err }, ) } else { - response, err = s.h.GetSettingsUsage(ctx, params) + response, err = s.h.GetUser(ctx, params) } if err != nil { defer recordError("Internal", err) @@ -462,7 +462,7 @@ func (s *Server) handleGetSettingsUsageRequest(args [0]string, argsEscaped bool, return } - if err := encodeGetSettingsUsageResponse(response, w); err != nil { + if err := encodeGetUserResponse(response, w); err != nil { defer recordError("EncodeResponse", err) if !errors.Is(err, ht.ErrInternalServerErrorResponse) { s.cfg.ErrorHandler(ctx, w, r, err) @@ -471,26 +471,26 @@ func (s *Server) handleGetSettingsUsageRequest(args [0]string, argsEscaped bool, } } -// handleGetUserRequest handles get-user operation. +// handleGetUserUsageRequest handles get-user-usage operation. // -// Retrieve the information of the user with the matching user ID. +// Get the current CPU, memory and disk usage of the server. // -// GET /user -func (s *Server) handleGetUserRequest(args [0]string, argsEscaped bool, w http.ResponseWriter, r *http.Request) { +// GET /user/usage +func (s *Server) handleGetUserUsageRequest(args [0]string, argsEscaped bool, w http.ResponseWriter, r *http.Request) { ctx := r.Context() var ( err error opErrContext = ogenerrors.OperationContext{ - Name: "GetUser", - ID: "get-user", + Name: "GetUserUsage", + ID: "get-user-usage", } ) { type bitset = [1]uint8 var satisfied bitset { - sctx, ok, err := s.securityCookieAuth(ctx, "GetUser", r) + sctx, ok, err := s.securityCookieAuth(ctx, "GetUserUsage", r) if err != nil { err = &ogenerrors.SecurityError{ OperationContext: opErrContext, @@ -530,7 +530,7 @@ func (s *Server) handleGetUserRequest(args [0]string, argsEscaped bool, w http.R return } } - params, err := decodeGetUserParams(args, argsEscaped, r) + params, err := decodeGetUserUsageParams(args, argsEscaped, r) if err != nil { err = &ogenerrors.DecodeParamsError{ OperationContext: opErrContext, @@ -541,13 +541,13 @@ func (s *Server) handleGetUserRequest(args [0]string, argsEscaped bool, w http.R return } - var response GetUserRes + var response GetUserUsageRes if m := s.cfg.Middleware; m != nil { mreq := middleware.Request{ Context: ctx, - OperationName: "GetUser", - OperationSummary: "Get User Info", - OperationID: "get-user", + OperationName: "GetUserUsage", + OperationSummary: "Get Resource Usage", + OperationID: "get-user-usage", Body: nil, Params: middleware.Parameters{ { @@ -560,8 +560,8 @@ func (s *Server) handleGetUserRequest(args [0]string, argsEscaped bool, w http.R type ( Request = struct{} - Params = GetUserParams - Response = GetUserRes + Params = GetUserUsageParams + Response = GetUserUsageRes ) response, err = middleware.HookMiddleware[ Request, @@ -570,14 +570,14 @@ func (s *Server) handleGetUserRequest(args [0]string, argsEscaped bool, w http.R ]( m, mreq, - unpackGetUserParams, + unpackGetUserUsageParams, func(ctx context.Context, request Request, params Params) (response Response, err error) { - response, err = s.h.GetUser(ctx, params) + response, err = s.h.GetUserUsage(ctx, params) return response, err }, ) } else { - response, err = s.h.GetUser(ctx, params) + response, err = s.h.GetUserUsage(ctx, params) } if err != nil { defer recordError("Internal", err) @@ -585,7 +585,7 @@ func (s *Server) handleGetUserRequest(args [0]string, argsEscaped bool, w http.R return } - if err := encodeGetUserResponse(response, w); err != nil { + if err := encodeGetUserUsageResponse(response, w); err != nil { defer recordError("EncodeResponse", err) if !errors.Is(err, ht.ErrInternalServerErrorResponse) { s.cfg.ErrorHandler(ctx, w, r, err) @@ -3096,144 +3096,6 @@ func (s *Server) handleGetWebsitesIDRequest(args [1]string, argsEscaped bool, w } } -// handlePatchSettingsUsageRequest handles patch-settings-usage operation. -// -// Update the resource usage settings of the server. -// -// PATCH /settings/usage -func (s *Server) handlePatchSettingsUsageRequest(args [0]string, argsEscaped bool, w http.ResponseWriter, r *http.Request) { - ctx := r.Context() - - var ( - err error - opErrContext = ogenerrors.OperationContext{ - Name: "PatchSettingsUsage", - ID: "patch-settings-usage", - } - ) - { - type bitset = [1]uint8 - var satisfied bitset - { - sctx, ok, err := s.securityCookieAuth(ctx, "PatchSettingsUsage", r) - if err != nil { - err = &ogenerrors.SecurityError{ - OperationContext: opErrContext, - Security: "CookieAuth", - Err: err, - } - defer recordError("Security:CookieAuth", err) - s.cfg.ErrorHandler(ctx, w, r, 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, - } - defer recordError("Security", err) - s.cfg.ErrorHandler(ctx, w, r, err) - return - } - } - params, err := decodePatchSettingsUsageParams(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 - } - request, close, err := s.decodePatchSettingsUsageRequest(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 PatchSettingsUsageRes - if m := s.cfg.Middleware; m != nil { - mreq := middleware.Request{ - Context: ctx, - OperationName: "PatchSettingsUsage", - OperationSummary: "Update Resource Usage", - OperationID: "patch-settings-usage", - Body: request, - Params: middleware.Parameters{ - { - Name: "_me_sess", - In: "cookie", - }: params.MeSess, - }, - Raw: r, - } - - type ( - Request = *SettingsUsagePatch - Params = PatchSettingsUsageParams - Response = PatchSettingsUsageRes - ) - response, err = middleware.HookMiddleware[ - Request, - Params, - Response, - ]( - m, - mreq, - unpackPatchSettingsUsageParams, - func(ctx context.Context, request Request, params Params) (response Response, err error) { - response, err = s.h.PatchSettingsUsage(ctx, request, params) - return response, err - }, - ) - } else { - response, err = s.h.PatchSettingsUsage(ctx, request, params) - } - if err != nil { - defer recordError("Internal", err) - s.cfg.ErrorHandler(ctx, w, r, err) - return - } - - if err := encodePatchSettingsUsageResponse(response, w); err != nil { - defer recordError("EncodeResponse", err) - if !errors.Is(err, ht.ErrInternalServerErrorResponse) { - s.cfg.ErrorHandler(ctx, w, r, err) - } - return - } -} - // handlePatchUserRequest handles patch-user operation. // // Update a user account's details. diff --git a/core/api/oas_interfaces_gen.go b/core/api/oas_interfaces_gen.go index ce8a6e44..dfc780dc 100644 --- a/core/api/oas_interfaces_gen.go +++ b/core/api/oas_interfaces_gen.go @@ -13,14 +13,14 @@ type GetEventPingRes interface { getEventPingRes() } -type GetSettingsUsageRes interface { - getSettingsUsageRes() -} - type GetUserRes interface { getUserRes() } +type GetUserUsageRes interface { + getUserUsageRes() +} + type GetWebsiteIDBrowsersRes interface { getWebsiteIDBrowsersRes() } @@ -77,10 +77,6 @@ type GetWebsitesRes interface { getWebsitesRes() } -type PatchSettingsUsageRes interface { - patchSettingsUsageRes() -} - type PatchUserRes interface { patchUserRes() } diff --git a/core/api/oas_json_gen.go b/core/api/oas_json_gen.go index 1da08965..0a2eba46 100644 --- a/core/api/oas_json_gen.go +++ b/core/api/oas_json_gen.go @@ -2046,18 +2046,84 @@ func (s *OptString) UnmarshalJSON(data []byte) error { return s.Decode(d) } -// Encode encodes UserPatchLanguage as json. -func (o OptUserPatchLanguage) Encode(e *jx.Encoder) { +// Encode encodes UserSettings as json. +func (o OptUserSettings) Encode(e *jx.Encoder) { + if !o.Set { + return + } + o.Value.Encode(e) +} + +// Decode decodes UserSettings from json. +func (o *OptUserSettings) Decode(d *jx.Decoder) error { + if o == nil { + return errors.New("invalid: unable to decode OptUserSettings to nil") + } + o.Set = true + if err := o.Value.Decode(d); err != nil { + return err + } + return nil +} + +// MarshalJSON implements stdjson.Marshaler. +func (s OptUserSettings) MarshalJSON() ([]byte, error) { + e := jx.Encoder{} + s.Encode(&e) + return e.Bytes(), nil +} + +// UnmarshalJSON implements stdjson.Unmarshaler. +func (s *OptUserSettings) UnmarshalJSON(data []byte) error { + d := jx.DecodeBytes(data) + return s.Decode(d) +} + +// Encode encodes UserSettingsLanguage as json. +func (o OptUserSettingsLanguage) Encode(e *jx.Encoder) { + if !o.Set { + return + } + e.Str(string(o.Value)) +} + +// Decode decodes UserSettingsLanguage from json. +func (o *OptUserSettingsLanguage) Decode(d *jx.Decoder) error { + if o == nil { + return errors.New("invalid: unable to decode OptUserSettingsLanguage to nil") + } + o.Set = true + if err := o.Value.Decode(d); err != nil { + return err + } + return nil +} + +// MarshalJSON implements stdjson.Marshaler. +func (s OptUserSettingsLanguage) MarshalJSON() ([]byte, error) { + e := jx.Encoder{} + s.Encode(&e) + return e.Bytes(), nil +} + +// UnmarshalJSON implements stdjson.Unmarshaler. +func (s *OptUserSettingsLanguage) UnmarshalJSON(data []byte) error { + d := jx.DecodeBytes(data) + return s.Decode(d) +} + +// Encode encodes UserSettingsScriptType as json. +func (o OptUserSettingsScriptType) Encode(e *jx.Encoder) { if !o.Set { return } e.Str(string(o.Value)) } -// Decode decodes UserPatchLanguage from json. -func (o *OptUserPatchLanguage) Decode(d *jx.Decoder) error { +// Decode decodes UserSettingsScriptType from json. +func (o *OptUserSettingsScriptType) Decode(d *jx.Decoder) error { if o == nil { - return errors.New("invalid: unable to decode OptUserPatchLanguage to nil") + return errors.New("invalid: unable to decode OptUserSettingsScriptType to nil") } o.Set = true if err := o.Value.Decode(d); err != nil { @@ -2067,14 +2133,14 @@ func (o *OptUserPatchLanguage) Decode(d *jx.Decoder) error { } // MarshalJSON implements stdjson.Marshaler. -func (s OptUserPatchLanguage) MarshalJSON() ([]byte, error) { +func (s OptUserSettingsScriptType) MarshalJSON() ([]byte, error) { e := jx.Encoder{} s.Encode(&e) return e.Bytes(), nil } // UnmarshalJSON implements stdjson.Unmarshaler. -func (s *OptUserPatchLanguage) UnmarshalJSON(data []byte) error { +func (s *OptUserSettingsScriptType) UnmarshalJSON(data []byte) error { d := jx.DecodeBytes(data) return s.Decode(d) } @@ -2112,100 +2178,175 @@ func (s *OptWebsiteGetSummary) UnmarshalJSON(data []byte) error { return s.Decode(d) } +// Encode encodes StatsBrowsers as json. +func (s StatsBrowsers) Encode(e *jx.Encoder) { + unwrapped := []StatsBrowsersItem(s) + + e.ArrStart() + for _, elem := range unwrapped { + elem.Encode(e) + } + e.ArrEnd() +} + +// Decode decodes StatsBrowsers from json. +func (s *StatsBrowsers) Decode(d *jx.Decoder) error { + if s == nil { + return errors.New("invalid: unable to decode StatsBrowsers to nil") + } + var unwrapped []StatsBrowsersItem + if err := func() error { + unwrapped = make([]StatsBrowsersItem, 0) + if err := d.Arr(func(d *jx.Decoder) error { + var elem StatsBrowsersItem + 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 = StatsBrowsers(unwrapped) + return nil +} + +// MarshalJSON implements stdjson.Marshaler. +func (s StatsBrowsers) MarshalJSON() ([]byte, error) { + e := jx.Encoder{} + s.Encode(&e) + return e.Bytes(), nil +} + +// UnmarshalJSON implements stdjson.Unmarshaler. +func (s *StatsBrowsers) UnmarshalJSON(data []byte) error { + d := jx.DecodeBytes(data) + return s.Decode(d) +} + // Encode implements json.Marshaler. -func (s *SettingsUsageGet) Encode(e *jx.Encoder) { +func (s *StatsBrowsersItem) Encode(e *jx.Encoder) { e.ObjStart() s.encodeFields(e) e.ObjEnd() } // encodeFields encodes fields. -func (s *SettingsUsageGet) encodeFields(e *jx.Encoder) { +func (s *StatsBrowsersItem) encodeFields(e *jx.Encoder) { { - e.FieldStart("cpu") - s.CPU.Encode(e) + e.FieldStart("browser") + e.Str(s.Browser) } { - e.FieldStart("memory") - s.Memory.Encode(e) + e.FieldStart("visitors") + e.Int(s.Visitors) } { - e.FieldStart("disk") - s.Disk.Encode(e) + e.FieldStart("visitors_percentage") + e.Float32(s.VisitorsPercentage) + } + { + if s.BouncePercentage.Set { + e.FieldStart("bounce_percentage") + s.BouncePercentage.Encode(e) + } } { - e.FieldStart("metadata") - s.Metadata.Encode(e) + if s.Duration.Set { + e.FieldStart("duration") + s.Duration.Encode(e) + } } } -var jsonFieldsNameOfSettingsUsageGet = [4]string{ - 0: "cpu", - 1: "memory", - 2: "disk", - 3: "metadata", +var jsonFieldsNameOfStatsBrowsersItem = [5]string{ + 0: "browser", + 1: "visitors", + 2: "visitors_percentage", + 3: "bounce_percentage", + 4: "duration", } -// Decode decodes SettingsUsageGet from json. -func (s *SettingsUsageGet) Decode(d *jx.Decoder) error { +// Decode decodes StatsBrowsersItem from json. +func (s *StatsBrowsersItem) Decode(d *jx.Decoder) error { if s == nil { - return errors.New("invalid: unable to decode SettingsUsageGet to nil") + return errors.New("invalid: unable to decode StatsBrowsersItem to nil") } var requiredBitSet [1]uint8 if err := d.ObjBytes(func(d *jx.Decoder, k []byte) error { switch string(k) { - case "cpu": + case "browser": requiredBitSet[0] |= 1 << 0 if err := func() error { - if err := s.CPU.Decode(d); err != nil { + v, err := d.Str() + s.Browser = string(v) + if err != nil { return err } return nil }(); err != nil { - return errors.Wrap(err, "decode field \"cpu\"") + return errors.Wrap(err, "decode field \"browser\"") } - case "memory": + case "visitors": requiredBitSet[0] |= 1 << 1 if err := func() error { - if err := s.Memory.Decode(d); err != nil { + v, err := d.Int() + s.Visitors = int(v) + if err != nil { return err } return nil }(); err != nil { - return errors.Wrap(err, "decode field \"memory\"") + return errors.Wrap(err, "decode field \"visitors\"") } - case "disk": + case "visitors_percentage": requiredBitSet[0] |= 1 << 2 if err := func() error { - if err := s.Disk.Decode(d); err != nil { + v, err := d.Float32() + s.VisitorsPercentage = float32(v) + if err != nil { return err } return nil }(); err != nil { - return errors.Wrap(err, "decode field \"disk\"") + return errors.Wrap(err, "decode field \"visitors_percentage\"") } - case "metadata": - requiredBitSet[0] |= 1 << 3 + case "bounce_percentage": + if err := func() error { + s.BouncePercentage.Reset() + if err := s.BouncePercentage.Decode(d); err != nil { + return err + } + return nil + }(); err != nil { + return errors.Wrap(err, "decode field \"bounce_percentage\"") + } + case "duration": if err := func() error { - if err := s.Metadata.Decode(d); err != nil { + s.Duration.Reset() + if err := s.Duration.Decode(d); err != nil { return err } return nil }(); err != nil { - return errors.Wrap(err, "decode field \"metadata\"") + return errors.Wrap(err, "decode field \"duration\"") } default: return d.Skip() } return nil }); err != nil { - return errors.Wrap(err, "decode SettingsUsageGet") + return errors.Wrap(err, "decode StatsBrowsersItem") } // Validate required fields. var failures []validate.FieldError for i, mask := range [1]uint8{ - 0b00001111, + 0b00000111, } { if result := (requiredBitSet[i] & mask) ^ mask; result != 0 { // Mask only required fields and check equality to mask using XOR. @@ -2217,8 +2358,8 @@ func (s *SettingsUsageGet) Decode(d *jx.Decoder) error { bitIdx := bits.TrailingZeros8(result) fieldIdx := i*8 + bitIdx var name string - if fieldIdx < len(jsonFieldsNameOfSettingsUsageGet) { - name = jsonFieldsNameOfSettingsUsageGet[fieldIdx] + if fieldIdx < len(jsonFieldsNameOfStatsBrowsersItem) { + name = jsonFieldsNameOfStatsBrowsersItem[fieldIdx] } else { name = strconv.Itoa(fieldIdx) } @@ -2239,98 +2380,182 @@ func (s *SettingsUsageGet) Decode(d *jx.Decoder) error { } // MarshalJSON implements stdjson.Marshaler. -func (s *SettingsUsageGet) MarshalJSON() ([]byte, error) { +func (s *StatsBrowsersItem) MarshalJSON() ([]byte, error) { + e := jx.Encoder{} + s.Encode(&e) + return e.Bytes(), nil +} + +// UnmarshalJSON implements stdjson.Unmarshaler. +func (s *StatsBrowsersItem) UnmarshalJSON(data []byte) error { + d := jx.DecodeBytes(data) + return s.Decode(d) +} + +// Encode encodes StatsCountries as json. +func (s StatsCountries) Encode(e *jx.Encoder) { + unwrapped := []StatsCountriesItem(s) + + e.ArrStart() + for _, elem := range unwrapped { + elem.Encode(e) + } + e.ArrEnd() +} + +// Decode decodes StatsCountries from json. +func (s *StatsCountries) Decode(d *jx.Decoder) error { + if s == nil { + return errors.New("invalid: unable to decode StatsCountries to nil") + } + var unwrapped []StatsCountriesItem + if err := func() error { + unwrapped = make([]StatsCountriesItem, 0) + if err := d.Arr(func(d *jx.Decoder) error { + var elem StatsCountriesItem + 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 = StatsCountries(unwrapped) + return nil +} + +// MarshalJSON implements stdjson.Marshaler. +func (s StatsCountries) MarshalJSON() ([]byte, error) { e := jx.Encoder{} s.Encode(&e) return e.Bytes(), nil } // UnmarshalJSON implements stdjson.Unmarshaler. -func (s *SettingsUsageGet) UnmarshalJSON(data []byte) error { +func (s *StatsCountries) UnmarshalJSON(data []byte) error { d := jx.DecodeBytes(data) return s.Decode(d) } // Encode implements json.Marshaler. -func (s *SettingsUsageGetCPU) Encode(e *jx.Encoder) { +func (s *StatsCountriesItem) Encode(e *jx.Encoder) { e.ObjStart() s.encodeFields(e) e.ObjEnd() } // encodeFields encodes fields. -func (s *SettingsUsageGetCPU) encodeFields(e *jx.Encoder) { +func (s *StatsCountriesItem) encodeFields(e *jx.Encoder) { { - e.FieldStart("usage") - e.Float32(s.Usage) + e.FieldStart("country") + e.Str(s.Country) } { - e.FieldStart("cores") - e.Int(s.Cores) + e.FieldStart("visitors") + e.Int(s.Visitors) } { - e.FieldStart("threads") - e.Int(s.Threads) + e.FieldStart("visitors_percentage") + e.Float32(s.VisitorsPercentage) } -} - -var jsonFieldsNameOfSettingsUsageGetCPU = [3]string{ - 0: "usage", - 1: "cores", - 2: "threads", -} - -// Decode decodes SettingsUsageGetCPU from json. -func (s *SettingsUsageGetCPU) Decode(d *jx.Decoder) error { - if s == nil { - return errors.New("invalid: unable to decode SettingsUsageGetCPU to nil") + { + if s.BouncePercentage.Set { + e.FieldStart("bounce_percentage") + s.BouncePercentage.Encode(e) + } + } + { + if s.Duration.Set { + e.FieldStart("duration") + s.Duration.Encode(e) + } + } +} + +var jsonFieldsNameOfStatsCountriesItem = [5]string{ + 0: "country", + 1: "visitors", + 2: "visitors_percentage", + 3: "bounce_percentage", + 4: "duration", +} + +// Decode decodes StatsCountriesItem from json. +func (s *StatsCountriesItem) Decode(d *jx.Decoder) error { + if s == nil { + return errors.New("invalid: unable to decode StatsCountriesItem to nil") } var requiredBitSet [1]uint8 if err := d.ObjBytes(func(d *jx.Decoder, k []byte) error { switch string(k) { - case "usage": + case "country": requiredBitSet[0] |= 1 << 0 if err := func() error { - v, err := d.Float32() - s.Usage = float32(v) + v, err := d.Str() + s.Country = string(v) if err != nil { return err } return nil }(); err != nil { - return errors.Wrap(err, "decode field \"usage\"") + return errors.Wrap(err, "decode field \"country\"") } - case "cores": + case "visitors": requiredBitSet[0] |= 1 << 1 if err := func() error { v, err := d.Int() - s.Cores = int(v) + s.Visitors = int(v) if err != nil { return err } return nil }(); err != nil { - return errors.Wrap(err, "decode field \"cores\"") + return errors.Wrap(err, "decode field \"visitors\"") } - case "threads": + case "visitors_percentage": requiredBitSet[0] |= 1 << 2 if err := func() error { - v, err := d.Int() - s.Threads = int(v) + v, err := d.Float32() + s.VisitorsPercentage = float32(v) if err != nil { return err } return nil }(); err != nil { - return errors.Wrap(err, "decode field \"threads\"") + return errors.Wrap(err, "decode field \"visitors_percentage\"") + } + case "bounce_percentage": + if err := func() error { + s.BouncePercentage.Reset() + if err := s.BouncePercentage.Decode(d); err != nil { + return err + } + return nil + }(); err != nil { + return errors.Wrap(err, "decode field \"bounce_percentage\"") + } + case "duration": + if err := func() error { + s.Duration.Reset() + if err := s.Duration.Decode(d); err != nil { + return err + } + return nil + }(); err != nil { + return errors.Wrap(err, "decode field \"duration\"") } default: return d.Skip() } return nil }); err != nil { - return errors.Wrap(err, "decode SettingsUsageGetCPU") + return errors.Wrap(err, "decode StatsCountriesItem") } // Validate required fields. var failures []validate.FieldError @@ -2347,8 +2572,8 @@ func (s *SettingsUsageGetCPU) Decode(d *jx.Decoder) error { bitIdx := bits.TrailingZeros8(result) fieldIdx := i*8 + bitIdx var name string - if fieldIdx < len(jsonFieldsNameOfSettingsUsageGetCPU) { - name = jsonFieldsNameOfSettingsUsageGetCPU[fieldIdx] + if fieldIdx < len(jsonFieldsNameOfStatsCountriesItem) { + name = jsonFieldsNameOfStatsCountriesItem[fieldIdx] } else { name = strconv.Itoa(fieldIdx) } @@ -2369,86 +2594,187 @@ func (s *SettingsUsageGetCPU) Decode(d *jx.Decoder) error { } // MarshalJSON implements stdjson.Marshaler. -func (s *SettingsUsageGetCPU) MarshalJSON() ([]byte, error) { +func (s *StatsCountriesItem) MarshalJSON() ([]byte, error) { + e := jx.Encoder{} + s.Encode(&e) + return e.Bytes(), nil +} + +// UnmarshalJSON implements stdjson.Unmarshaler. +func (s *StatsCountriesItem) UnmarshalJSON(data []byte) error { + d := jx.DecodeBytes(data) + return s.Decode(d) +} + +// Encode encodes StatsDevices as json. +func (s StatsDevices) Encode(e *jx.Encoder) { + unwrapped := []StatsDevicesItem(s) + + e.ArrStart() + for _, elem := range unwrapped { + elem.Encode(e) + } + e.ArrEnd() +} + +// Decode decodes StatsDevices from json. +func (s *StatsDevices) Decode(d *jx.Decoder) error { + if s == nil { + return errors.New("invalid: unable to decode StatsDevices to nil") + } + var unwrapped []StatsDevicesItem + if err := func() error { + unwrapped = make([]StatsDevicesItem, 0) + if err := d.Arr(func(d *jx.Decoder) error { + var elem StatsDevicesItem + 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 = StatsDevices(unwrapped) + return nil +} + +// MarshalJSON implements stdjson.Marshaler. +func (s StatsDevices) MarshalJSON() ([]byte, error) { e := jx.Encoder{} s.Encode(&e) return e.Bytes(), nil } // UnmarshalJSON implements stdjson.Unmarshaler. -func (s *SettingsUsageGetCPU) UnmarshalJSON(data []byte) error { +func (s *StatsDevices) UnmarshalJSON(data []byte) error { d := jx.DecodeBytes(data) return s.Decode(d) } // Encode implements json.Marshaler. -func (s *SettingsUsageGetDisk) Encode(e *jx.Encoder) { +func (s *StatsDevicesItem) Encode(e *jx.Encoder) { e.ObjStart() s.encodeFields(e) e.ObjEnd() } // encodeFields encodes fields. -func (s *SettingsUsageGetDisk) encodeFields(e *jx.Encoder) { +func (s *StatsDevicesItem) encodeFields(e *jx.Encoder) { { - e.FieldStart("used") - e.Int64(s.Used) + e.FieldStart("device") + e.Str(s.Device) } { - e.FieldStart("total") - e.Int64(s.Total) + e.FieldStart("visitors") + e.Int(s.Visitors) + } + { + e.FieldStart("visitors_percentage") + e.Float32(s.VisitorsPercentage) + } + { + if s.BouncePercentage.Set { + e.FieldStart("bounce_percentage") + s.BouncePercentage.Encode(e) + } + } + { + if s.Duration.Set { + e.FieldStart("duration") + s.Duration.Encode(e) + } } } -var jsonFieldsNameOfSettingsUsageGetDisk = [2]string{ - 0: "used", - 1: "total", +var jsonFieldsNameOfStatsDevicesItem = [5]string{ + 0: "device", + 1: "visitors", + 2: "visitors_percentage", + 3: "bounce_percentage", + 4: "duration", } -// Decode decodes SettingsUsageGetDisk from json. -func (s *SettingsUsageGetDisk) Decode(d *jx.Decoder) error { +// Decode decodes StatsDevicesItem from json. +func (s *StatsDevicesItem) Decode(d *jx.Decoder) error { if s == nil { - return errors.New("invalid: unable to decode SettingsUsageGetDisk to nil") + return errors.New("invalid: unable to decode StatsDevicesItem to nil") } var requiredBitSet [1]uint8 if err := d.ObjBytes(func(d *jx.Decoder, k []byte) error { switch string(k) { - case "used": + case "device": requiredBitSet[0] |= 1 << 0 if err := func() error { - v, err := d.Int64() - s.Used = int64(v) + v, err := d.Str() + s.Device = string(v) if err != nil { return err } return nil }(); err != nil { - return errors.Wrap(err, "decode field \"used\"") + return errors.Wrap(err, "decode field \"device\"") } - case "total": + case "visitors": requiredBitSet[0] |= 1 << 1 if err := func() error { - v, err := d.Int64() - s.Total = int64(v) + v, err := d.Int() + s.Visitors = int(v) if err != nil { return err } return nil }(); err != nil { - return errors.Wrap(err, "decode field \"total\"") + return errors.Wrap(err, "decode field \"visitors\"") + } + case "visitors_percentage": + requiredBitSet[0] |= 1 << 2 + if err := func() error { + v, err := d.Float32() + s.VisitorsPercentage = float32(v) + if err != nil { + return err + } + return nil + }(); err != nil { + return errors.Wrap(err, "decode field \"visitors_percentage\"") + } + case "bounce_percentage": + if err := func() error { + s.BouncePercentage.Reset() + if err := s.BouncePercentage.Decode(d); err != nil { + return err + } + return nil + }(); err != nil { + return errors.Wrap(err, "decode field \"bounce_percentage\"") + } + case "duration": + if err := func() error { + s.Duration.Reset() + if err := s.Duration.Decode(d); err != nil { + return err + } + return nil + }(); err != nil { + return errors.Wrap(err, "decode field \"duration\"") } default: return d.Skip() } return nil }); err != nil { - return errors.Wrap(err, "decode SettingsUsageGetDisk") + return errors.Wrap(err, "decode StatsDevicesItem") } // Validate required fields. var failures []validate.FieldError for i, mask := range [1]uint8{ - 0b00000011, + 0b00000111, } { if result := (requiredBitSet[i] & mask) ^ mask; result != 0 { // Mask only required fields and check equality to mask using XOR. @@ -2460,8 +2786,8 @@ func (s *SettingsUsageGetDisk) Decode(d *jx.Decoder) error { bitIdx := bits.TrailingZeros8(result) fieldIdx := i*8 + bitIdx var name string - if fieldIdx < len(jsonFieldsNameOfSettingsUsageGetDisk) { - name = jsonFieldsNameOfSettingsUsageGetDisk[fieldIdx] + if fieldIdx < len(jsonFieldsNameOfStatsDevicesItem) { + name = jsonFieldsNameOfStatsDevicesItem[fieldIdx] } else { name = strconv.Itoa(fieldIdx) } @@ -2482,294 +2808,235 @@ func (s *SettingsUsageGetDisk) Decode(d *jx.Decoder) error { } // MarshalJSON implements stdjson.Marshaler. -func (s *SettingsUsageGetDisk) MarshalJSON() ([]byte, error) { +func (s *StatsDevicesItem) MarshalJSON() ([]byte, error) { e := jx.Encoder{} s.Encode(&e) return e.Bytes(), nil } // UnmarshalJSON implements stdjson.Unmarshaler. -func (s *SettingsUsageGetDisk) UnmarshalJSON(data []byte) error { +func (s *StatsDevicesItem) UnmarshalJSON(data []byte) error { d := jx.DecodeBytes(data) return s.Decode(d) } -// Encode implements json.Marshaler. -func (s *SettingsUsageGetMemory) Encode(e *jx.Encoder) { - e.ObjStart() - s.encodeFields(e) - e.ObjEnd() -} +// Encode encodes StatsLanguages as json. +func (s StatsLanguages) Encode(e *jx.Encoder) { + unwrapped := []StatsLanguagesItem(s) -// encodeFields encodes fields. -func (s *SettingsUsageGetMemory) encodeFields(e *jx.Encoder) { - { - e.FieldStart("used") - e.Int64(s.Used) - } - { - e.FieldStart("total") - e.Int64(s.Total) + e.ArrStart() + for _, elem := range unwrapped { + elem.Encode(e) } + e.ArrEnd() } -var jsonFieldsNameOfSettingsUsageGetMemory = [2]string{ - 0: "used", - 1: "total", -} - -// Decode decodes SettingsUsageGetMemory from json. -func (s *SettingsUsageGetMemory) Decode(d *jx.Decoder) error { +// Decode decodes StatsLanguages from json. +func (s *StatsLanguages) Decode(d *jx.Decoder) error { if s == nil { - return errors.New("invalid: unable to decode SettingsUsageGetMemory to nil") + return errors.New("invalid: unable to decode StatsLanguages to nil") } - var requiredBitSet [1]uint8 - - if err := d.ObjBytes(func(d *jx.Decoder, k []byte) error { - switch string(k) { - case "used": - requiredBitSet[0] |= 1 << 0 - if err := func() error { - v, err := d.Int64() - s.Used = int64(v) - if err != nil { - return err - } - return nil - }(); err != nil { - return errors.Wrap(err, "decode field \"used\"") - } - case "total": - requiredBitSet[0] |= 1 << 1 - if err := func() error { - v, err := d.Int64() - s.Total = int64(v) - if err != nil { - return err - } - return nil - }(); err != nil { - return errors.Wrap(err, "decode field \"total\"") + var unwrapped []StatsLanguagesItem + if err := func() error { + unwrapped = make([]StatsLanguagesItem, 0) + if err := d.Arr(func(d *jx.Decoder) error { + var elem StatsLanguagesItem + if err := elem.Decode(d); err != nil { + return err } - default: - return d.Skip() + unwrapped = append(unwrapped, elem) + return nil + }); err != nil { + return err } return nil - }); err != nil { - return errors.Wrap(err, "decode SettingsUsageGetMemory") - } - // Validate required fields. - var failures []validate.FieldError - for i, mask := range [1]uint8{ - 0b00000011, - } { - 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(jsonFieldsNameOfSettingsUsageGetMemory) { - name = jsonFieldsNameOfSettingsUsageGetMemory[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} + }(); err != nil { + return errors.Wrap(err, "alias") } - + *s = StatsLanguages(unwrapped) return nil } // MarshalJSON implements stdjson.Marshaler. -func (s *SettingsUsageGetMemory) MarshalJSON() ([]byte, error) { +func (s StatsLanguages) MarshalJSON() ([]byte, error) { e := jx.Encoder{} s.Encode(&e) return e.Bytes(), nil } // UnmarshalJSON implements stdjson.Unmarshaler. -func (s *SettingsUsageGetMemory) UnmarshalJSON(data []byte) error { +func (s *StatsLanguages) UnmarshalJSON(data []byte) error { d := jx.DecodeBytes(data) return s.Decode(d) } // Encode implements json.Marshaler. -func (s *SettingsUsageGetMetadata) Encode(e *jx.Encoder) { +func (s *StatsLanguagesItem) Encode(e *jx.Encoder) { e.ObjStart() s.encodeFields(e) e.ObjEnd() } // encodeFields encodes fields. -func (s *SettingsUsageGetMetadata) encodeFields(e *jx.Encoder) { +func (s *StatsLanguagesItem) encodeFields(e *jx.Encoder) { + { + e.FieldStart("language") + e.Str(s.Language) + } + { + e.FieldStart("visitors") + e.Int(s.Visitors) + } + { + e.FieldStart("visitors_percentage") + e.Float32(s.VisitorsPercentage) + } { - if s.Threads.Set { - e.FieldStart("threads") - s.Threads.Encode(e) + if s.BouncePercentage.Set { + e.FieldStart("bounce_percentage") + s.BouncePercentage.Encode(e) } } { - if s.MemoryLimit.Set { - e.FieldStart("memory_limit") - s.MemoryLimit.Encode(e) + if s.Duration.Set { + e.FieldStart("duration") + s.Duration.Encode(e) } } } -var jsonFieldsNameOfSettingsUsageGetMetadata = [2]string{ - 0: "threads", - 1: "memory_limit", +var jsonFieldsNameOfStatsLanguagesItem = [5]string{ + 0: "language", + 1: "visitors", + 2: "visitors_percentage", + 3: "bounce_percentage", + 4: "duration", } -// Decode decodes SettingsUsageGetMetadata from json. -func (s *SettingsUsageGetMetadata) Decode(d *jx.Decoder) error { +// Decode decodes StatsLanguagesItem from json. +func (s *StatsLanguagesItem) Decode(d *jx.Decoder) error { if s == nil { - return errors.New("invalid: unable to decode SettingsUsageGetMetadata to nil") + return errors.New("invalid: unable to decode StatsLanguagesItem to nil") } + var requiredBitSet [1]uint8 if err := d.ObjBytes(func(d *jx.Decoder, k []byte) error { switch string(k) { - case "threads": + case "language": + requiredBitSet[0] |= 1 << 0 if err := func() error { - s.Threads.Reset() - if err := s.Threads.Decode(d); err != nil { + v, err := d.Str() + s.Language = string(v) + if err != nil { return err } return nil }(); err != nil { - return errors.Wrap(err, "decode field \"threads\"") + return errors.Wrap(err, "decode field \"language\"") } - case "memory_limit": + case "visitors": + requiredBitSet[0] |= 1 << 1 if err := func() error { - s.MemoryLimit.Reset() - if err := s.MemoryLimit.Decode(d); err != nil { + v, err := d.Int() + s.Visitors = int(v) + if err != nil { return err } return nil }(); err != nil { - return errors.Wrap(err, "decode field \"memory_limit\"") + return errors.Wrap(err, "decode field \"visitors\"") } - default: - return d.Skip() - } - return nil - }); err != nil { - return errors.Wrap(err, "decode SettingsUsageGetMetadata") - } - - return nil -} - -// MarshalJSON implements stdjson.Marshaler. -func (s *SettingsUsageGetMetadata) MarshalJSON() ([]byte, error) { - e := jx.Encoder{} - s.Encode(&e) - return e.Bytes(), nil -} - -// UnmarshalJSON implements stdjson.Unmarshaler. -func (s *SettingsUsageGetMetadata) UnmarshalJSON(data []byte) error { - d := jx.DecodeBytes(data) - return s.Decode(d) -} - -// Encode implements json.Marshaler. -func (s *SettingsUsagePatch) Encode(e *jx.Encoder) { - e.ObjStart() - s.encodeFields(e) - e.ObjEnd() -} - -// encodeFields encodes fields. -func (s *SettingsUsagePatch) encodeFields(e *jx.Encoder) { - { - if s.Threads.Set { - e.FieldStart("threads") - s.Threads.Encode(e) - } - } - { - if s.MemoryLimit.Set { - e.FieldStart("memory_limit") - s.MemoryLimit.Encode(e) - } - } -} - -var jsonFieldsNameOfSettingsUsagePatch = [2]string{ - 0: "threads", - 1: "memory_limit", -} - -// Decode decodes SettingsUsagePatch from json. -func (s *SettingsUsagePatch) Decode(d *jx.Decoder) error { - if s == nil { - return errors.New("invalid: unable to decode SettingsUsagePatch to nil") - } - - if err := d.ObjBytes(func(d *jx.Decoder, k []byte) error { - switch string(k) { - case "threads": + case "visitors_percentage": + requiredBitSet[0] |= 1 << 2 if err := func() error { - s.Threads.Reset() - if err := s.Threads.Decode(d); err != nil { + v, err := d.Float32() + s.VisitorsPercentage = float32(v) + if err != nil { return err } return nil }(); err != nil { - return errors.Wrap(err, "decode field \"threads\"") + return errors.Wrap(err, "decode field \"visitors_percentage\"") + } + case "bounce_percentage": + if err := func() error { + s.BouncePercentage.Reset() + if err := s.BouncePercentage.Decode(d); err != nil { + return err + } + return nil + }(); err != nil { + return errors.Wrap(err, "decode field \"bounce_percentage\"") } - case "memory_limit": + case "duration": if err := func() error { - s.MemoryLimit.Reset() - if err := s.MemoryLimit.Decode(d); err != nil { + s.Duration.Reset() + if err := s.Duration.Decode(d); err != nil { return err } return nil }(); err != nil { - return errors.Wrap(err, "decode field \"memory_limit\"") + return errors.Wrap(err, "decode field \"duration\"") } default: return d.Skip() } return nil }); err != nil { - return errors.Wrap(err, "decode SettingsUsagePatch") + return errors.Wrap(err, "decode StatsLanguagesItem") + } + // Validate required fields. + var failures []validate.FieldError + for i, mask := range [1]uint8{ + 0b00000111, + } { + 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(jsonFieldsNameOfStatsLanguagesItem) { + name = jsonFieldsNameOfStatsLanguagesItem[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 *SettingsUsagePatch) MarshalJSON() ([]byte, error) { +func (s *StatsLanguagesItem) MarshalJSON() ([]byte, error) { e := jx.Encoder{} s.Encode(&e) return e.Bytes(), nil } // UnmarshalJSON implements stdjson.Unmarshaler. -func (s *SettingsUsagePatch) UnmarshalJSON(data []byte) error { +func (s *StatsLanguagesItem) UnmarshalJSON(data []byte) error { d := jx.DecodeBytes(data) return s.Decode(d) } -// Encode encodes StatsBrowsers as json. -func (s StatsBrowsers) Encode(e *jx.Encoder) { - unwrapped := []StatsBrowsersItem(s) +// Encode encodes StatsOS as json. +func (s StatsOS) Encode(e *jx.Encoder) { + unwrapped := []StatsOSItem(s) e.ArrStart() for _, elem := range unwrapped { @@ -2778,16 +3045,16 @@ func (s StatsBrowsers) Encode(e *jx.Encoder) { e.ArrEnd() } -// Decode decodes StatsBrowsers from json. -func (s *StatsBrowsers) Decode(d *jx.Decoder) error { +// Decode decodes StatsOS from json. +func (s *StatsOS) Decode(d *jx.Decoder) error { if s == nil { - return errors.New("invalid: unable to decode StatsBrowsers to nil") + return errors.New("invalid: unable to decode StatsOS to nil") } - var unwrapped []StatsBrowsersItem + var unwrapped []StatsOSItem if err := func() error { - unwrapped = make([]StatsBrowsersItem, 0) + unwrapped = make([]StatsOSItem, 0) if err := d.Arr(func(d *jx.Decoder) error { - var elem StatsBrowsersItem + var elem StatsOSItem if err := elem.Decode(d); err != nil { return err } @@ -2800,35 +3067,35 @@ func (s *StatsBrowsers) Decode(d *jx.Decoder) error { }(); err != nil { return errors.Wrap(err, "alias") } - *s = StatsBrowsers(unwrapped) + *s = StatsOS(unwrapped) return nil } // MarshalJSON implements stdjson.Marshaler. -func (s StatsBrowsers) MarshalJSON() ([]byte, error) { +func (s StatsOS) MarshalJSON() ([]byte, error) { e := jx.Encoder{} s.Encode(&e) return e.Bytes(), nil } // UnmarshalJSON implements stdjson.Unmarshaler. -func (s *StatsBrowsers) UnmarshalJSON(data []byte) error { +func (s *StatsOS) UnmarshalJSON(data []byte) error { d := jx.DecodeBytes(data) return s.Decode(d) } // Encode implements json.Marshaler. -func (s *StatsBrowsersItem) Encode(e *jx.Encoder) { +func (s *StatsOSItem) Encode(e *jx.Encoder) { e.ObjStart() s.encodeFields(e) e.ObjEnd() } // encodeFields encodes fields. -func (s *StatsBrowsersItem) encodeFields(e *jx.Encoder) { +func (s *StatsOSItem) encodeFields(e *jx.Encoder) { { - e.FieldStart("browser") - e.Str(s.Browser) + e.FieldStart("os") + e.Str(s.Os) } { e.FieldStart("visitors") @@ -2852,34 +3119,34 @@ func (s *StatsBrowsersItem) encodeFields(e *jx.Encoder) { } } -var jsonFieldsNameOfStatsBrowsersItem = [5]string{ - 0: "browser", +var jsonFieldsNameOfStatsOSItem = [5]string{ + 0: "os", 1: "visitors", 2: "visitors_percentage", 3: "bounce_percentage", 4: "duration", } -// Decode decodes StatsBrowsersItem from json. -func (s *StatsBrowsersItem) Decode(d *jx.Decoder) error { +// Decode decodes StatsOSItem from json. +func (s *StatsOSItem) Decode(d *jx.Decoder) error { if s == nil { - return errors.New("invalid: unable to decode StatsBrowsersItem to nil") + return errors.New("invalid: unable to decode StatsOSItem to nil") } var requiredBitSet [1]uint8 if err := d.ObjBytes(func(d *jx.Decoder, k []byte) error { switch string(k) { - case "browser": + case "os": requiredBitSet[0] |= 1 << 0 if err := func() error { v, err := d.Str() - s.Browser = string(v) + s.Os = string(v) if err != nil { return err } return nil }(); err != nil { - return errors.Wrap(err, "decode field \"browser\"") + return errors.Wrap(err, "decode field \"os\"") } case "visitors": requiredBitSet[0] |= 1 << 1 @@ -2930,7 +3197,7 @@ func (s *StatsBrowsersItem) Decode(d *jx.Decoder) error { } return nil }); err != nil { - return errors.Wrap(err, "decode StatsBrowsersItem") + return errors.Wrap(err, "decode StatsOSItem") } // Validate required fields. var failures []validate.FieldError @@ -2947,8 +3214,8 @@ func (s *StatsBrowsersItem) Decode(d *jx.Decoder) error { bitIdx := bits.TrailingZeros8(result) fieldIdx := i*8 + bitIdx var name string - if fieldIdx < len(jsonFieldsNameOfStatsBrowsersItem) { - name = jsonFieldsNameOfStatsBrowsersItem[fieldIdx] + if fieldIdx < len(jsonFieldsNameOfStatsOSItem) { + name = jsonFieldsNameOfStatsOSItem[fieldIdx] } else { name = strconv.Itoa(fieldIdx) } @@ -2969,21 +3236,21 @@ func (s *StatsBrowsersItem) Decode(d *jx.Decoder) error { } // MarshalJSON implements stdjson.Marshaler. -func (s *StatsBrowsersItem) MarshalJSON() ([]byte, error) { +func (s *StatsOSItem) MarshalJSON() ([]byte, error) { e := jx.Encoder{} s.Encode(&e) return e.Bytes(), nil } // UnmarshalJSON implements stdjson.Unmarshaler. -func (s *StatsBrowsersItem) UnmarshalJSON(data []byte) error { +func (s *StatsOSItem) UnmarshalJSON(data []byte) error { d := jx.DecodeBytes(data) return s.Decode(d) } -// Encode encodes StatsCountries as json. -func (s StatsCountries) Encode(e *jx.Encoder) { - unwrapped := []StatsCountriesItem(s) +// Encode encodes StatsPages as json. +func (s StatsPages) Encode(e *jx.Encoder) { + unwrapped := []StatsPagesItem(s) e.ArrStart() for _, elem := range unwrapped { @@ -2992,16 +3259,16 @@ func (s StatsCountries) Encode(e *jx.Encoder) { e.ArrEnd() } -// Decode decodes StatsCountries from json. -func (s *StatsCountries) Decode(d *jx.Decoder) error { +// Decode decodes StatsPages from json. +func (s *StatsPages) Decode(d *jx.Decoder) error { if s == nil { - return errors.New("invalid: unable to decode StatsCountries to nil") + return errors.New("invalid: unable to decode StatsPages to nil") } - var unwrapped []StatsCountriesItem + var unwrapped []StatsPagesItem if err := func() error { - unwrapped = make([]StatsCountriesItem, 0) + unwrapped = make([]StatsPagesItem, 0) if err := d.Arr(func(d *jx.Decoder) error { - var elem StatsCountriesItem + var elem StatsPagesItem if err := elem.Decode(d); err != nil { return err } @@ -3014,35 +3281,35 @@ func (s *StatsCountries) Decode(d *jx.Decoder) error { }(); err != nil { return errors.Wrap(err, "alias") } - *s = StatsCountries(unwrapped) + *s = StatsPages(unwrapped) return nil } // MarshalJSON implements stdjson.Marshaler. -func (s StatsCountries) MarshalJSON() ([]byte, error) { +func (s StatsPages) MarshalJSON() ([]byte, error) { e := jx.Encoder{} s.Encode(&e) return e.Bytes(), nil } // UnmarshalJSON implements stdjson.Unmarshaler. -func (s *StatsCountries) UnmarshalJSON(data []byte) error { +func (s *StatsPages) UnmarshalJSON(data []byte) error { d := jx.DecodeBytes(data) return s.Decode(d) } // Encode implements json.Marshaler. -func (s *StatsCountriesItem) Encode(e *jx.Encoder) { +func (s *StatsPagesItem) Encode(e *jx.Encoder) { e.ObjStart() s.encodeFields(e) e.ObjEnd() } // encodeFields encodes fields. -func (s *StatsCountriesItem) encodeFields(e *jx.Encoder) { +func (s *StatsPagesItem) encodeFields(e *jx.Encoder) { { - e.FieldStart("country") - e.Str(s.Country) + e.FieldStart("path") + e.Str(s.Path) } { e.FieldStart("visitors") @@ -3052,6 +3319,18 @@ func (s *StatsCountriesItem) encodeFields(e *jx.Encoder) { e.FieldStart("visitors_percentage") e.Float32(s.VisitorsPercentage) } + { + if s.Pageviews.Set { + e.FieldStart("pageviews") + s.Pageviews.Encode(e) + } + } + { + if s.PageviewsPercentage.Set { + e.FieldStart("pageviews_percentage") + s.PageviewsPercentage.Encode(e) + } + } { if s.BouncePercentage.Set { e.FieldStart("bounce_percentage") @@ -3066,34 +3345,36 @@ func (s *StatsCountriesItem) encodeFields(e *jx.Encoder) { } } -var jsonFieldsNameOfStatsCountriesItem = [5]string{ - 0: "country", +var jsonFieldsNameOfStatsPagesItem = [7]string{ + 0: "path", 1: "visitors", 2: "visitors_percentage", - 3: "bounce_percentage", - 4: "duration", + 3: "pageviews", + 4: "pageviews_percentage", + 5: "bounce_percentage", + 6: "duration", } -// Decode decodes StatsCountriesItem from json. -func (s *StatsCountriesItem) Decode(d *jx.Decoder) error { +// Decode decodes StatsPagesItem from json. +func (s *StatsPagesItem) Decode(d *jx.Decoder) error { if s == nil { - return errors.New("invalid: unable to decode StatsCountriesItem to nil") + return errors.New("invalid: unable to decode StatsPagesItem to nil") } var requiredBitSet [1]uint8 if err := d.ObjBytes(func(d *jx.Decoder, k []byte) error { switch string(k) { - case "country": + case "path": requiredBitSet[0] |= 1 << 0 if err := func() error { v, err := d.Str() - s.Country = string(v) + s.Path = string(v) if err != nil { return err } return nil }(); err != nil { - return errors.Wrap(err, "decode field \"country\"") + return errors.Wrap(err, "decode field \"path\"") } case "visitors": requiredBitSet[0] |= 1 << 1 @@ -3119,6 +3400,26 @@ func (s *StatsCountriesItem) Decode(d *jx.Decoder) error { }(); err != nil { return errors.Wrap(err, "decode field \"visitors_percentage\"") } + case "pageviews": + if err := func() error { + s.Pageviews.Reset() + if err := s.Pageviews.Decode(d); err != nil { + return err + } + return nil + }(); err != nil { + return errors.Wrap(err, "decode field \"pageviews\"") + } + case "pageviews_percentage": + if err := func() error { + s.PageviewsPercentage.Reset() + if err := s.PageviewsPercentage.Decode(d); err != nil { + return err + } + return nil + }(); err != nil { + return errors.Wrap(err, "decode field \"pageviews_percentage\"") + } case "bounce_percentage": if err := func() error { s.BouncePercentage.Reset() @@ -3144,7 +3445,7 @@ func (s *StatsCountriesItem) Decode(d *jx.Decoder) error { } return nil }); err != nil { - return errors.Wrap(err, "decode StatsCountriesItem") + return errors.Wrap(err, "decode StatsPagesItem") } // Validate required fields. var failures []validate.FieldError @@ -3161,8 +3462,8 @@ func (s *StatsCountriesItem) Decode(d *jx.Decoder) error { bitIdx := bits.TrailingZeros8(result) fieldIdx := i*8 + bitIdx var name string - if fieldIdx < len(jsonFieldsNameOfStatsCountriesItem) { - name = jsonFieldsNameOfStatsCountriesItem[fieldIdx] + if fieldIdx < len(jsonFieldsNameOfStatsPagesItem) { + name = jsonFieldsNameOfStatsPagesItem[fieldIdx] } else { name = strconv.Itoa(fieldIdx) } @@ -3183,21 +3484,21 @@ func (s *StatsCountriesItem) Decode(d *jx.Decoder) error { } // MarshalJSON implements stdjson.Marshaler. -func (s *StatsCountriesItem) MarshalJSON() ([]byte, error) { +func (s *StatsPagesItem) MarshalJSON() ([]byte, error) { e := jx.Encoder{} s.Encode(&e) return e.Bytes(), nil } // UnmarshalJSON implements stdjson.Unmarshaler. -func (s *StatsCountriesItem) UnmarshalJSON(data []byte) error { +func (s *StatsPagesItem) UnmarshalJSON(data []byte) error { d := jx.DecodeBytes(data) return s.Decode(d) } -// Encode encodes StatsDevices as json. -func (s StatsDevices) Encode(e *jx.Encoder) { - unwrapped := []StatsDevicesItem(s) +// Encode encodes StatsReferrers as json. +func (s StatsReferrers) Encode(e *jx.Encoder) { + unwrapped := []StatsReferrersItem(s) e.ArrStart() for _, elem := range unwrapped { @@ -3206,16 +3507,16 @@ func (s StatsDevices) Encode(e *jx.Encoder) { e.ArrEnd() } -// Decode decodes StatsDevices from json. -func (s *StatsDevices) Decode(d *jx.Decoder) error { +// Decode decodes StatsReferrers from json. +func (s *StatsReferrers) Decode(d *jx.Decoder) error { if s == nil { - return errors.New("invalid: unable to decode StatsDevices to nil") + return errors.New("invalid: unable to decode StatsReferrers to nil") } - var unwrapped []StatsDevicesItem + var unwrapped []StatsReferrersItem if err := func() error { - unwrapped = make([]StatsDevicesItem, 0) + unwrapped = make([]StatsReferrersItem, 0) if err := d.Arr(func(d *jx.Decoder) error { - var elem StatsDevicesItem + var elem StatsReferrersItem if err := elem.Decode(d); err != nil { return err } @@ -3228,35 +3529,35 @@ func (s *StatsDevices) Decode(d *jx.Decoder) error { }(); err != nil { return errors.Wrap(err, "alias") } - *s = StatsDevices(unwrapped) + *s = StatsReferrers(unwrapped) return nil } // MarshalJSON implements stdjson.Marshaler. -func (s StatsDevices) MarshalJSON() ([]byte, error) { +func (s StatsReferrers) MarshalJSON() ([]byte, error) { e := jx.Encoder{} s.Encode(&e) return e.Bytes(), nil } // UnmarshalJSON implements stdjson.Unmarshaler. -func (s *StatsDevices) UnmarshalJSON(data []byte) error { +func (s *StatsReferrers) UnmarshalJSON(data []byte) error { d := jx.DecodeBytes(data) return s.Decode(d) } // Encode implements json.Marshaler. -func (s *StatsDevicesItem) Encode(e *jx.Encoder) { +func (s *StatsReferrersItem) Encode(e *jx.Encoder) { e.ObjStart() s.encodeFields(e) e.ObjEnd() } // encodeFields encodes fields. -func (s *StatsDevicesItem) encodeFields(e *jx.Encoder) { +func (s *StatsReferrersItem) encodeFields(e *jx.Encoder) { { - e.FieldStart("device") - e.Str(s.Device) + e.FieldStart("referrer") + e.Str(s.Referrer) } { e.FieldStart("visitors") @@ -3280,34 +3581,34 @@ func (s *StatsDevicesItem) encodeFields(e *jx.Encoder) { } } -var jsonFieldsNameOfStatsDevicesItem = [5]string{ - 0: "device", +var jsonFieldsNameOfStatsReferrersItem = [5]string{ + 0: "referrer", 1: "visitors", 2: "visitors_percentage", 3: "bounce_percentage", 4: "duration", } -// Decode decodes StatsDevicesItem from json. -func (s *StatsDevicesItem) Decode(d *jx.Decoder) error { +// Decode decodes StatsReferrersItem from json. +func (s *StatsReferrersItem) Decode(d *jx.Decoder) error { if s == nil { - return errors.New("invalid: unable to decode StatsDevicesItem to nil") + return errors.New("invalid: unable to decode StatsReferrersItem to nil") } var requiredBitSet [1]uint8 if err := d.ObjBytes(func(d *jx.Decoder, k []byte) error { switch string(k) { - case "device": + case "referrer": requiredBitSet[0] |= 1 << 0 if err := func() error { v, err := d.Str() - s.Device = string(v) + s.Referrer = string(v) if err != nil { return err } return nil }(); err != nil { - return errors.Wrap(err, "decode field \"device\"") + return errors.Wrap(err, "decode field \"referrer\"") } case "visitors": requiredBitSet[0] |= 1 << 1 @@ -3358,7 +3659,7 @@ func (s *StatsDevicesItem) Decode(d *jx.Decoder) error { } return nil }); err != nil { - return errors.Wrap(err, "decode StatsDevicesItem") + return errors.Wrap(err, "decode StatsReferrersItem") } // Validate required fields. var failures []validate.FieldError @@ -3375,8 +3676,8 @@ func (s *StatsDevicesItem) Decode(d *jx.Decoder) error { bitIdx := bits.TrailingZeros8(result) fieldIdx := i*8 + bitIdx var name string - if fieldIdx < len(jsonFieldsNameOfStatsDevicesItem) { - name = jsonFieldsNameOfStatsDevicesItem[fieldIdx] + if fieldIdx < len(jsonFieldsNameOfStatsReferrersItem) { + name = jsonFieldsNameOfStatsReferrersItem[fieldIdx] } else { name = strconv.Itoa(fieldIdx) } @@ -3397,187 +3698,112 @@ func (s *StatsDevicesItem) Decode(d *jx.Decoder) error { } // MarshalJSON implements stdjson.Marshaler. -func (s *StatsDevicesItem) MarshalJSON() ([]byte, error) { - e := jx.Encoder{} - s.Encode(&e) - return e.Bytes(), nil -} - -// UnmarshalJSON implements stdjson.Unmarshaler. -func (s *StatsDevicesItem) UnmarshalJSON(data []byte) error { - d := jx.DecodeBytes(data) - return s.Decode(d) -} - -// Encode encodes StatsLanguages as json. -func (s StatsLanguages) Encode(e *jx.Encoder) { - unwrapped := []StatsLanguagesItem(s) - - e.ArrStart() - for _, elem := range unwrapped { - elem.Encode(e) - } - e.ArrEnd() -} - -// Decode decodes StatsLanguages from json. -func (s *StatsLanguages) Decode(d *jx.Decoder) error { - if s == nil { - return errors.New("invalid: unable to decode StatsLanguages to nil") - } - var unwrapped []StatsLanguagesItem - if err := func() error { - unwrapped = make([]StatsLanguagesItem, 0) - if err := d.Arr(func(d *jx.Decoder) error { - var elem StatsLanguagesItem - 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 = StatsLanguages(unwrapped) - return nil -} - -// MarshalJSON implements stdjson.Marshaler. -func (s StatsLanguages) MarshalJSON() ([]byte, error) { +func (s *StatsReferrersItem) MarshalJSON() ([]byte, error) { e := jx.Encoder{} s.Encode(&e) return e.Bytes(), nil } // UnmarshalJSON implements stdjson.Unmarshaler. -func (s *StatsLanguages) UnmarshalJSON(data []byte) error { +func (s *StatsReferrersItem) UnmarshalJSON(data []byte) error { d := jx.DecodeBytes(data) return s.Decode(d) } // Encode implements json.Marshaler. -func (s *StatsLanguagesItem) Encode(e *jx.Encoder) { +func (s *StatsSummary) Encode(e *jx.Encoder) { e.ObjStart() s.encodeFields(e) e.ObjEnd() } // encodeFields encodes fields. -func (s *StatsLanguagesItem) encodeFields(e *jx.Encoder) { - { - e.FieldStart("language") - e.Str(s.Language) - } - { - e.FieldStart("visitors") - e.Int(s.Visitors) - } +func (s *StatsSummary) encodeFields(e *jx.Encoder) { { - e.FieldStart("visitors_percentage") - e.Float32(s.VisitorsPercentage) + e.FieldStart("current") + s.Current.Encode(e) } { - if s.BouncePercentage.Set { - e.FieldStart("bounce_percentage") - s.BouncePercentage.Encode(e) + if s.Previous.Set { + e.FieldStart("previous") + s.Previous.Encode(e) } } { - if s.Duration.Set { - e.FieldStart("duration") - s.Duration.Encode(e) + if s.Interval != nil { + e.FieldStart("interval") + e.ArrStart() + for _, elem := range s.Interval { + elem.Encode(e) + } + e.ArrEnd() } } } -var jsonFieldsNameOfStatsLanguagesItem = [5]string{ - 0: "language", - 1: "visitors", - 2: "visitors_percentage", - 3: "bounce_percentage", - 4: "duration", +var jsonFieldsNameOfStatsSummary = [3]string{ + 0: "current", + 1: "previous", + 2: "interval", } -// Decode decodes StatsLanguagesItem from json. -func (s *StatsLanguagesItem) Decode(d *jx.Decoder) error { +// Decode decodes StatsSummary from json. +func (s *StatsSummary) Decode(d *jx.Decoder) error { if s == nil { - return errors.New("invalid: unable to decode StatsLanguagesItem to nil") + return errors.New("invalid: unable to decode StatsSummary to nil") } var requiredBitSet [1]uint8 if err := d.ObjBytes(func(d *jx.Decoder, k []byte) error { switch string(k) { - case "language": + case "current": requiredBitSet[0] |= 1 << 0 if err := func() error { - v, err := d.Str() - s.Language = string(v) - if err != nil { - return err - } - return nil - }(); err != nil { - return errors.Wrap(err, "decode field \"language\"") - } - case "visitors": - requiredBitSet[0] |= 1 << 1 - if err := func() error { - v, err := d.Int() - s.Visitors = int(v) - if err != nil { - return err - } - return nil - }(); err != nil { - return errors.Wrap(err, "decode field \"visitors\"") - } - case "visitors_percentage": - requiredBitSet[0] |= 1 << 2 - if err := func() error { - v, err := d.Float32() - s.VisitorsPercentage = float32(v) - if err != nil { + if err := s.Current.Decode(d); err != nil { return err } return nil }(); err != nil { - return errors.Wrap(err, "decode field \"visitors_percentage\"") + return errors.Wrap(err, "decode field \"current\"") } - case "bounce_percentage": + case "previous": if err := func() error { - s.BouncePercentage.Reset() - if err := s.BouncePercentage.Decode(d); err != nil { + s.Previous.Reset() + if err := s.Previous.Decode(d); err != nil { return err } return nil }(); err != nil { - return errors.Wrap(err, "decode field \"bounce_percentage\"") + return errors.Wrap(err, "decode field \"previous\"") } - case "duration": + case "interval": if err := func() error { - s.Duration.Reset() - if err := s.Duration.Decode(d); err != nil { + s.Interval = make([]StatsSummaryIntervalItem, 0) + if err := d.Arr(func(d *jx.Decoder) error { + var elem StatsSummaryIntervalItem + if err := elem.Decode(d); err != nil { + return err + } + s.Interval = append(s.Interval, elem) + return nil + }); err != nil { return err } return nil }(); err != nil { - return errors.Wrap(err, "decode field \"duration\"") + return errors.Wrap(err, "decode field \"interval\"") } default: return d.Skip() } return nil }); err != nil { - return errors.Wrap(err, "decode StatsLanguagesItem") + return errors.Wrap(err, "decode StatsSummary") } // Validate required fields. var failures []validate.FieldError for i, mask := range [1]uint8{ - 0b00000111, + 0b00000001, } { if result := (requiredBitSet[i] & mask) ^ mask; result != 0 { // Mask only required fields and check equality to mask using XOR. @@ -3589,8 +3815,8 @@ func (s *StatsLanguagesItem) Decode(d *jx.Decoder) error { bitIdx := bits.TrailingZeros8(result) fieldIdx := i*8 + bitIdx var name string - if fieldIdx < len(jsonFieldsNameOfStatsLanguagesItem) { - name = jsonFieldsNameOfStatsLanguagesItem[fieldIdx] + if fieldIdx < len(jsonFieldsNameOfStatsSummary) { + name = jsonFieldsNameOfStatsSummary[fieldIdx] } else { name = strconv.Itoa(fieldIdx) } @@ -3611,170 +3837,103 @@ func (s *StatsLanguagesItem) Decode(d *jx.Decoder) error { } // MarshalJSON implements stdjson.Marshaler. -func (s *StatsLanguagesItem) MarshalJSON() ([]byte, error) { - e := jx.Encoder{} - s.Encode(&e) - return e.Bytes(), nil -} - -// UnmarshalJSON implements stdjson.Unmarshaler. -func (s *StatsLanguagesItem) UnmarshalJSON(data []byte) error { - d := jx.DecodeBytes(data) - return s.Decode(d) -} - -// Encode encodes StatsOS as json. -func (s StatsOS) Encode(e *jx.Encoder) { - unwrapped := []StatsOSItem(s) - - e.ArrStart() - for _, elem := range unwrapped { - elem.Encode(e) - } - e.ArrEnd() -} - -// Decode decodes StatsOS from json. -func (s *StatsOS) Decode(d *jx.Decoder) error { - if s == nil { - return errors.New("invalid: unable to decode StatsOS to nil") - } - var unwrapped []StatsOSItem - if err := func() error { - unwrapped = make([]StatsOSItem, 0) - if err := d.Arr(func(d *jx.Decoder) error { - var elem StatsOSItem - 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 = StatsOS(unwrapped) - return nil -} - -// MarshalJSON implements stdjson.Marshaler. -func (s StatsOS) MarshalJSON() ([]byte, error) { +func (s *StatsSummary) MarshalJSON() ([]byte, error) { e := jx.Encoder{} s.Encode(&e) return e.Bytes(), nil } // UnmarshalJSON implements stdjson.Unmarshaler. -func (s *StatsOS) UnmarshalJSON(data []byte) error { +func (s *StatsSummary) UnmarshalJSON(data []byte) error { d := jx.DecodeBytes(data) return s.Decode(d) } // Encode implements json.Marshaler. -func (s *StatsOSItem) Encode(e *jx.Encoder) { +func (s *StatsSummaryCurrent) Encode(e *jx.Encoder) { e.ObjStart() s.encodeFields(e) e.ObjEnd() } // encodeFields encodes fields. -func (s *StatsOSItem) encodeFields(e *jx.Encoder) { - { - e.FieldStart("os") - e.Str(s.Os) - } +func (s *StatsSummaryCurrent) encodeFields(e *jx.Encoder) { { e.FieldStart("visitors") e.Int(s.Visitors) } { - e.FieldStart("visitors_percentage") - e.Float32(s.VisitorsPercentage) + e.FieldStart("pageviews") + e.Int(s.Pageviews) } { - if s.BouncePercentage.Set { - e.FieldStart("bounce_percentage") - s.BouncePercentage.Encode(e) - } + e.FieldStart("bounce_percentage") + e.Float32(s.BouncePercentage) } { - if s.Duration.Set { - e.FieldStart("duration") - s.Duration.Encode(e) - } + e.FieldStart("duration") + e.Int(s.Duration) } } -var jsonFieldsNameOfStatsOSItem = [5]string{ - 0: "os", - 1: "visitors", - 2: "visitors_percentage", - 3: "bounce_percentage", - 4: "duration", +var jsonFieldsNameOfStatsSummaryCurrent = [4]string{ + 0: "visitors", + 1: "pageviews", + 2: "bounce_percentage", + 3: "duration", } -// Decode decodes StatsOSItem from json. -func (s *StatsOSItem) Decode(d *jx.Decoder) error { +// Decode decodes StatsSummaryCurrent from json. +func (s *StatsSummaryCurrent) Decode(d *jx.Decoder) error { if s == nil { - return errors.New("invalid: unable to decode StatsOSItem to nil") + return errors.New("invalid: unable to decode StatsSummaryCurrent to nil") } var requiredBitSet [1]uint8 if err := d.ObjBytes(func(d *jx.Decoder, k []byte) error { switch string(k) { - case "os": + case "visitors": requiredBitSet[0] |= 1 << 0 if err := func() error { - v, err := d.Str() - s.Os = string(v) + v, err := d.Int() + s.Visitors = int(v) if err != nil { return err } return nil }(); err != nil { - return errors.Wrap(err, "decode field \"os\"") + return errors.Wrap(err, "decode field \"visitors\"") } - case "visitors": + case "pageviews": requiredBitSet[0] |= 1 << 1 if err := func() error { v, err := d.Int() - s.Visitors = int(v) + s.Pageviews = int(v) if err != nil { return err } return nil }(); err != nil { - return errors.Wrap(err, "decode field \"visitors\"") + return errors.Wrap(err, "decode field \"pageviews\"") } - case "visitors_percentage": + case "bounce_percentage": requiredBitSet[0] |= 1 << 2 if err := func() error { v, err := d.Float32() - s.VisitorsPercentage = float32(v) + s.BouncePercentage = float32(v) if err != nil { return err } return nil - }(); err != nil { - return errors.Wrap(err, "decode field \"visitors_percentage\"") - } - case "bounce_percentage": - if err := func() error { - s.BouncePercentage.Reset() - if err := s.BouncePercentage.Decode(d); err != nil { - return err - } - return nil }(); err != nil { return errors.Wrap(err, "decode field \"bounce_percentage\"") } case "duration": + requiredBitSet[0] |= 1 << 3 if err := func() error { - s.Duration.Reset() - if err := s.Duration.Decode(d); err != nil { + v, err := d.Int() + s.Duration = int(v) + if err != nil { return err } return nil @@ -3786,12 +3945,12 @@ func (s *StatsOSItem) Decode(d *jx.Decoder) error { } return nil }); err != nil { - return errors.Wrap(err, "decode StatsOSItem") + return errors.Wrap(err, "decode StatsSummaryCurrent") } // Validate required fields. var failures []validate.FieldError for i, mask := range [1]uint8{ - 0b00000111, + 0b00001111, } { if result := (requiredBitSet[i] & mask) ^ mask; result != 0 { // Mask only required fields and check equality to mask using XOR. @@ -3803,8 +3962,8 @@ func (s *StatsOSItem) Decode(d *jx.Decoder) error { bitIdx := bits.TrailingZeros8(result) fieldIdx := i*8 + bitIdx var name string - if fieldIdx < len(jsonFieldsNameOfStatsOSItem) { - name = jsonFieldsNameOfStatsOSItem[fieldIdx] + if fieldIdx < len(jsonFieldsNameOfStatsSummaryCurrent) { + name = jsonFieldsNameOfStatsSummaryCurrent[fieldIdx] } else { name = strconv.Itoa(fieldIdx) } @@ -3825,88 +3984,36 @@ func (s *StatsOSItem) Decode(d *jx.Decoder) error { } // MarshalJSON implements stdjson.Marshaler. -func (s *StatsOSItem) MarshalJSON() ([]byte, error) { +func (s *StatsSummaryCurrent) MarshalJSON() ([]byte, error) { e := jx.Encoder{} s.Encode(&e) return e.Bytes(), nil } // UnmarshalJSON implements stdjson.Unmarshaler. -func (s *StatsOSItem) UnmarshalJSON(data []byte) error { +func (s *StatsSummaryCurrent) UnmarshalJSON(data []byte) error { d := jx.DecodeBytes(data) return s.Decode(d) } -// Encode encodes StatsPages as json. -func (s StatsPages) Encode(e *jx.Encoder) { - unwrapped := []StatsPagesItem(s) - - e.ArrStart() - for _, elem := range unwrapped { - elem.Encode(e) - } - e.ArrEnd() +// Encode implements json.Marshaler. +func (s *StatsSummaryIntervalItem) Encode(e *jx.Encoder) { + e.ObjStart() + s.encodeFields(e) + e.ObjEnd() } -// Decode decodes StatsPages from json. -func (s *StatsPages) Decode(d *jx.Decoder) error { - if s == nil { - return errors.New("invalid: unable to decode StatsPages to nil") +// encodeFields encodes fields. +func (s *StatsSummaryIntervalItem) encodeFields(e *jx.Encoder) { + { + e.FieldStart("date") + e.Str(s.Date) } - var unwrapped []StatsPagesItem - if err := func() error { - unwrapped = make([]StatsPagesItem, 0) - if err := d.Arr(func(d *jx.Decoder) error { - var elem StatsPagesItem - if err := elem.Decode(d); err != nil { - return err - } - unwrapped = append(unwrapped, elem) - return nil - }); err != nil { - return err + { + if s.Visitors.Set { + e.FieldStart("visitors") + s.Visitors.Encode(e) } - return nil - }(); err != nil { - return errors.Wrap(err, "alias") - } - *s = StatsPages(unwrapped) - return nil -} - -// MarshalJSON implements stdjson.Marshaler. -func (s StatsPages) MarshalJSON() ([]byte, error) { - e := jx.Encoder{} - s.Encode(&e) - return e.Bytes(), nil -} - -// UnmarshalJSON implements stdjson.Unmarshaler. -func (s *StatsPages) UnmarshalJSON(data []byte) error { - d := jx.DecodeBytes(data) - return s.Decode(d) -} - -// Encode implements json.Marshaler. -func (s *StatsPagesItem) Encode(e *jx.Encoder) { - e.ObjStart() - s.encodeFields(e) - e.ObjEnd() -} - -// encodeFields encodes fields. -func (s *StatsPagesItem) encodeFields(e *jx.Encoder) { - { - e.FieldStart("path") - e.Str(s.Path) - } - { - e.FieldStart("visitors") - e.Int(s.Visitors) - } - { - e.FieldStart("visitors_percentage") - e.Float32(s.VisitorsPercentage) } { if s.Pageviews.Set { @@ -3914,12 +4021,6 @@ func (s *StatsPagesItem) encodeFields(e *jx.Encoder) { s.Pageviews.Encode(e) } } - { - if s.PageviewsPercentage.Set { - e.FieldStart("pageviews_percentage") - s.PageviewsPercentage.Encode(e) - } - } { if s.BouncePercentage.Set { e.FieldStart("bounce_percentage") @@ -3934,61 +4035,45 @@ func (s *StatsPagesItem) encodeFields(e *jx.Encoder) { } } -var jsonFieldsNameOfStatsPagesItem = [7]string{ - 0: "path", +var jsonFieldsNameOfStatsSummaryIntervalItem = [5]string{ + 0: "date", 1: "visitors", - 2: "visitors_percentage", - 3: "pageviews", - 4: "pageviews_percentage", - 5: "bounce_percentage", - 6: "duration", + 2: "pageviews", + 3: "bounce_percentage", + 4: "duration", } -// Decode decodes StatsPagesItem from json. -func (s *StatsPagesItem) Decode(d *jx.Decoder) error { +// Decode decodes StatsSummaryIntervalItem from json. +func (s *StatsSummaryIntervalItem) Decode(d *jx.Decoder) error { if s == nil { - return errors.New("invalid: unable to decode StatsPagesItem to nil") + return errors.New("invalid: unable to decode StatsSummaryIntervalItem to nil") } var requiredBitSet [1]uint8 if err := d.ObjBytes(func(d *jx.Decoder, k []byte) error { switch string(k) { - case "path": + case "date": requiredBitSet[0] |= 1 << 0 if err := func() error { v, err := d.Str() - s.Path = string(v) + s.Date = string(v) if err != nil { return err } return nil }(); err != nil { - return errors.Wrap(err, "decode field \"path\"") + return errors.Wrap(err, "decode field \"date\"") } case "visitors": - requiredBitSet[0] |= 1 << 1 if err := func() error { - v, err := d.Int() - s.Visitors = int(v) - if err != nil { + s.Visitors.Reset() + if err := s.Visitors.Decode(d); err != nil { return err } return nil }(); err != nil { return errors.Wrap(err, "decode field \"visitors\"") } - case "visitors_percentage": - requiredBitSet[0] |= 1 << 2 - if err := func() error { - v, err := d.Float32() - s.VisitorsPercentage = float32(v) - if err != nil { - return err - } - return nil - }(); err != nil { - return errors.Wrap(err, "decode field \"visitors_percentage\"") - } case "pageviews": if err := func() error { s.Pageviews.Reset() @@ -3999,16 +4084,6 @@ func (s *StatsPagesItem) Decode(d *jx.Decoder) error { }(); err != nil { return errors.Wrap(err, "decode field \"pageviews\"") } - case "pageviews_percentage": - if err := func() error { - s.PageviewsPercentage.Reset() - if err := s.PageviewsPercentage.Decode(d); err != nil { - return err - } - return nil - }(); err != nil { - return errors.Wrap(err, "decode field \"pageviews_percentage\"") - } case "bounce_percentage": if err := func() error { s.BouncePercentage.Reset() @@ -4034,12 +4109,12 @@ func (s *StatsPagesItem) Decode(d *jx.Decoder) error { } return nil }); err != nil { - return errors.Wrap(err, "decode StatsPagesItem") + return errors.Wrap(err, "decode StatsSummaryIntervalItem") } // Validate required fields. var failures []validate.FieldError for i, mask := range [1]uint8{ - 0b00000111, + 0b00000001, } { if result := (requiredBitSet[i] & mask) ^ mask; result != 0 { // Mask only required fields and check equality to mask using XOR. @@ -4051,8 +4126,8 @@ func (s *StatsPagesItem) Decode(d *jx.Decoder) error { bitIdx := bits.TrailingZeros8(result) fieldIdx := i*8 + bitIdx var name string - if fieldIdx < len(jsonFieldsNameOfStatsPagesItem) { - name = jsonFieldsNameOfStatsPagesItem[fieldIdx] + if fieldIdx < len(jsonFieldsNameOfStatsSummaryIntervalItem) { + name = jsonFieldsNameOfStatsSummaryIntervalItem[fieldIdx] } else { name = strconv.Itoa(fieldIdx) } @@ -4073,170 +4148,103 @@ func (s *StatsPagesItem) Decode(d *jx.Decoder) error { } // MarshalJSON implements stdjson.Marshaler. -func (s *StatsPagesItem) MarshalJSON() ([]byte, error) { - e := jx.Encoder{} - s.Encode(&e) - return e.Bytes(), nil -} - -// UnmarshalJSON implements stdjson.Unmarshaler. -func (s *StatsPagesItem) UnmarshalJSON(data []byte) error { - d := jx.DecodeBytes(data) - return s.Decode(d) -} - -// Encode encodes StatsReferrers as json. -func (s StatsReferrers) Encode(e *jx.Encoder) { - unwrapped := []StatsReferrersItem(s) - - e.ArrStart() - for _, elem := range unwrapped { - elem.Encode(e) - } - e.ArrEnd() -} - -// Decode decodes StatsReferrers from json. -func (s *StatsReferrers) Decode(d *jx.Decoder) error { - if s == nil { - return errors.New("invalid: unable to decode StatsReferrers to nil") - } - var unwrapped []StatsReferrersItem - if err := func() error { - unwrapped = make([]StatsReferrersItem, 0) - if err := d.Arr(func(d *jx.Decoder) error { - var elem StatsReferrersItem - 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 = StatsReferrers(unwrapped) - return nil -} - -// MarshalJSON implements stdjson.Marshaler. -func (s StatsReferrers) MarshalJSON() ([]byte, error) { +func (s *StatsSummaryIntervalItem) MarshalJSON() ([]byte, error) { e := jx.Encoder{} s.Encode(&e) return e.Bytes(), nil } // UnmarshalJSON implements stdjson.Unmarshaler. -func (s *StatsReferrers) UnmarshalJSON(data []byte) error { +func (s *StatsSummaryIntervalItem) UnmarshalJSON(data []byte) error { d := jx.DecodeBytes(data) return s.Decode(d) } // Encode implements json.Marshaler. -func (s *StatsReferrersItem) Encode(e *jx.Encoder) { +func (s *StatsSummaryPrevious) Encode(e *jx.Encoder) { e.ObjStart() s.encodeFields(e) e.ObjEnd() } // encodeFields encodes fields. -func (s *StatsReferrersItem) encodeFields(e *jx.Encoder) { - { - e.FieldStart("referrer") - e.Str(s.Referrer) - } +func (s *StatsSummaryPrevious) encodeFields(e *jx.Encoder) { { e.FieldStart("visitors") e.Int(s.Visitors) } { - e.FieldStart("visitors_percentage") - e.Float32(s.VisitorsPercentage) + e.FieldStart("pageviews") + e.Int(s.Pageviews) } { - if s.BouncePercentage.Set { - e.FieldStart("bounce_percentage") - s.BouncePercentage.Encode(e) - } + e.FieldStart("bounce_percentage") + e.Float32(s.BouncePercentage) } { - if s.Duration.Set { - e.FieldStart("duration") - s.Duration.Encode(e) - } + e.FieldStart("duration") + e.Int(s.Duration) } } -var jsonFieldsNameOfStatsReferrersItem = [5]string{ - 0: "referrer", - 1: "visitors", - 2: "visitors_percentage", - 3: "bounce_percentage", - 4: "duration", +var jsonFieldsNameOfStatsSummaryPrevious = [4]string{ + 0: "visitors", + 1: "pageviews", + 2: "bounce_percentage", + 3: "duration", } -// Decode decodes StatsReferrersItem from json. -func (s *StatsReferrersItem) Decode(d *jx.Decoder) error { +// Decode decodes StatsSummaryPrevious from json. +func (s *StatsSummaryPrevious) Decode(d *jx.Decoder) error { if s == nil { - return errors.New("invalid: unable to decode StatsReferrersItem to nil") + return errors.New("invalid: unable to decode StatsSummaryPrevious to nil") } var requiredBitSet [1]uint8 if err := d.ObjBytes(func(d *jx.Decoder, k []byte) error { switch string(k) { - case "referrer": + case "visitors": requiredBitSet[0] |= 1 << 0 if err := func() error { - v, err := d.Str() - s.Referrer = string(v) + v, err := d.Int() + s.Visitors = int(v) if err != nil { return err } return nil }(); err != nil { - return errors.Wrap(err, "decode field \"referrer\"") + return errors.Wrap(err, "decode field \"visitors\"") } - case "visitors": + case "pageviews": requiredBitSet[0] |= 1 << 1 if err := func() error { v, err := d.Int() - s.Visitors = int(v) + s.Pageviews = int(v) if err != nil { return err } return nil }(); err != nil { - return errors.Wrap(err, "decode field \"visitors\"") + return errors.Wrap(err, "decode field \"pageviews\"") } - case "visitors_percentage": + case "bounce_percentage": requiredBitSet[0] |= 1 << 2 if err := func() error { v, err := d.Float32() - s.VisitorsPercentage = float32(v) + s.BouncePercentage = float32(v) if err != nil { return err } return nil - }(); err != nil { - return errors.Wrap(err, "decode field \"visitors_percentage\"") - } - case "bounce_percentage": - if err := func() error { - s.BouncePercentage.Reset() - if err := s.BouncePercentage.Decode(d); err != nil { - return err - } - return nil }(); err != nil { return errors.Wrap(err, "decode field \"bounce_percentage\"") } case "duration": + requiredBitSet[0] |= 1 << 3 if err := func() error { - s.Duration.Reset() - if err := s.Duration.Decode(d); err != nil { + v, err := d.Int() + s.Duration = int(v) + if err != nil { return err } return nil @@ -4248,12 +4256,12 @@ func (s *StatsReferrersItem) Decode(d *jx.Decoder) error { } return nil }); err != nil { - return errors.Wrap(err, "decode StatsReferrersItem") + return errors.Wrap(err, "decode StatsSummaryPrevious") } // Validate required fields. var failures []validate.FieldError for i, mask := range [1]uint8{ - 0b00000111, + 0b00001111, } { if result := (requiredBitSet[i] & mask) ^ mask; result != 0 { // Mask only required fields and check equality to mask using XOR. @@ -4265,8 +4273,8 @@ func (s *StatsReferrersItem) Decode(d *jx.Decoder) error { bitIdx := bits.TrailingZeros8(result) fieldIdx := i*8 + bitIdx var name string - if fieldIdx < len(jsonFieldsNameOfStatsReferrersItem) { - name = jsonFieldsNameOfStatsReferrersItem[fieldIdx] + if fieldIdx < len(jsonFieldsNameOfStatsSummaryPrevious) { + name = jsonFieldsNameOfStatsSummaryPrevious[fieldIdx] } else { name = strconv.Itoa(fieldIdx) } @@ -4287,259 +4295,204 @@ func (s *StatsReferrersItem) Decode(d *jx.Decoder) error { } // MarshalJSON implements stdjson.Marshaler. -func (s *StatsReferrersItem) MarshalJSON() ([]byte, error) { +func (s *StatsSummaryPrevious) MarshalJSON() ([]byte, error) { e := jx.Encoder{} s.Encode(&e) return e.Bytes(), nil } // UnmarshalJSON implements stdjson.Unmarshaler. -func (s *StatsReferrersItem) UnmarshalJSON(data []byte) error { +func (s *StatsSummaryPrevious) UnmarshalJSON(data []byte) error { d := jx.DecodeBytes(data) return s.Decode(d) } -// Encode implements json.Marshaler. -func (s *StatsSummary) Encode(e *jx.Encoder) { - e.ObjStart() - s.encodeFields(e) - e.ObjEnd() +// Encode encodes StatsTime as json. +func (s StatsTime) Encode(e *jx.Encoder) { + unwrapped := []StatsTimeItem(s) + + e.ArrStart() + for _, elem := range unwrapped { + elem.Encode(e) + } + e.ArrEnd() } -// encodeFields encodes fields. -func (s *StatsSummary) encodeFields(e *jx.Encoder) { - { - e.FieldStart("current") - s.Current.Encode(e) - } - { - if s.Previous.Set { - e.FieldStart("previous") - s.Previous.Encode(e) - } - } - { - if s.Interval != nil { - e.FieldStart("interval") - e.ArrStart() - for _, elem := range s.Interval { - elem.Encode(e) - } - e.ArrEnd() - } - } -} - -var jsonFieldsNameOfStatsSummary = [3]string{ - 0: "current", - 1: "previous", - 2: "interval", -} - -// Decode decodes StatsSummary from json. -func (s *StatsSummary) Decode(d *jx.Decoder) error { +// Decode decodes StatsTime from json. +func (s *StatsTime) Decode(d *jx.Decoder) error { if s == nil { - return errors.New("invalid: unable to decode StatsSummary to nil") + return errors.New("invalid: unable to decode StatsTime to nil") } - var requiredBitSet [1]uint8 - - if err := d.ObjBytes(func(d *jx.Decoder, k []byte) error { - switch string(k) { - case "current": - requiredBitSet[0] |= 1 << 0 - if err := func() error { - if err := s.Current.Decode(d); err != nil { - return err - } - return nil - }(); err != nil { - return errors.Wrap(err, "decode field \"current\"") - } - case "previous": - if err := func() error { - s.Previous.Reset() - if err := s.Previous.Decode(d); err != nil { - return err - } - return nil - }(); err != nil { - return errors.Wrap(err, "decode field \"previous\"") - } - case "interval": - if err := func() error { - s.Interval = make([]StatsSummaryIntervalItem, 0) - if err := d.Arr(func(d *jx.Decoder) error { - var elem StatsSummaryIntervalItem - if err := elem.Decode(d); err != nil { - return err - } - s.Interval = append(s.Interval, elem) - return nil - }); err != nil { - return err - } - return nil - }(); err != nil { - return errors.Wrap(err, "decode field \"interval\"") + var unwrapped []StatsTimeItem + if err := func() error { + unwrapped = make([]StatsTimeItem, 0) + if err := d.Arr(func(d *jx.Decoder) error { + var elem StatsTimeItem + if err := elem.Decode(d); err != nil { + return err } - default: - return d.Skip() + unwrapped = append(unwrapped, elem) + return nil + }); err != nil { + return err } return nil - }); err != nil { - return errors.Wrap(err, "decode StatsSummary") - } - // Validate required fields. - var failures []validate.FieldError - for i, mask := range [1]uint8{ - 0b00000001, - } { - 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(jsonFieldsNameOfStatsSummary) { - name = jsonFieldsNameOfStatsSummary[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} + }(); err != nil { + return errors.Wrap(err, "alias") } - + *s = StatsTime(unwrapped) return nil } // MarshalJSON implements stdjson.Marshaler. -func (s *StatsSummary) MarshalJSON() ([]byte, error) { +func (s StatsTime) MarshalJSON() ([]byte, error) { e := jx.Encoder{} s.Encode(&e) return e.Bytes(), nil } // UnmarshalJSON implements stdjson.Unmarshaler. -func (s *StatsSummary) UnmarshalJSON(data []byte) error { +func (s *StatsTime) UnmarshalJSON(data []byte) error { d := jx.DecodeBytes(data) return s.Decode(d) } // Encode implements json.Marshaler. -func (s *StatsSummaryCurrent) Encode(e *jx.Encoder) { +func (s *StatsTimeItem) Encode(e *jx.Encoder) { e.ObjStart() s.encodeFields(e) e.ObjEnd() } // encodeFields encodes fields. -func (s *StatsSummaryCurrent) encodeFields(e *jx.Encoder) { - { - e.FieldStart("visitors") - e.Int(s.Visitors) - } +func (s *StatsTimeItem) encodeFields(e *jx.Encoder) { { - e.FieldStart("pageviews") - e.Int(s.Pageviews) + e.FieldStart("path") + e.Str(s.Path) } { - e.FieldStart("bounce_percentage") - e.Float32(s.BouncePercentage) + if s.Visitors.Set { + e.FieldStart("visitors") + s.Visitors.Encode(e) + } } { e.FieldStart("duration") e.Int(s.Duration) } + { + if s.DurationUpperQuartile.Set { + e.FieldStart("duration_upper_quartile") + s.DurationUpperQuartile.Encode(e) + } + } + { + if s.DurationLowerQuartile.Set { + e.FieldStart("duration_lower_quartile") + s.DurationLowerQuartile.Encode(e) + } + } + { + e.FieldStart("duration_percentage") + e.Float32(s.DurationPercentage) + } } -var jsonFieldsNameOfStatsSummaryCurrent = [4]string{ - 0: "visitors", - 1: "pageviews", - 2: "bounce_percentage", - 3: "duration", +var jsonFieldsNameOfStatsTimeItem = [6]string{ + 0: "path", + 1: "visitors", + 2: "duration", + 3: "duration_upper_quartile", + 4: "duration_lower_quartile", + 5: "duration_percentage", } -// Decode decodes StatsSummaryCurrent from json. -func (s *StatsSummaryCurrent) Decode(d *jx.Decoder) error { +// Decode decodes StatsTimeItem from json. +func (s *StatsTimeItem) Decode(d *jx.Decoder) error { if s == nil { - return errors.New("invalid: unable to decode StatsSummaryCurrent to nil") + return errors.New("invalid: unable to decode StatsTimeItem to nil") } var requiredBitSet [1]uint8 if err := d.ObjBytes(func(d *jx.Decoder, k []byte) error { switch string(k) { - case "visitors": + case "path": requiredBitSet[0] |= 1 << 0 if err := func() error { - v, err := d.Int() - s.Visitors = int(v) + v, err := d.Str() + s.Path = string(v) if err != nil { return err } return nil + }(); err != nil { + return errors.Wrap(err, "decode field \"path\"") + } + case "visitors": + if err := func() error { + s.Visitors.Reset() + if err := s.Visitors.Decode(d); err != nil { + return err + } + return nil }(); err != nil { return errors.Wrap(err, "decode field \"visitors\"") } - case "pageviews": - requiredBitSet[0] |= 1 << 1 + case "duration": + requiredBitSet[0] |= 1 << 2 if err := func() error { v, err := d.Int() - s.Pageviews = int(v) + s.Duration = int(v) if err != nil { return err } return nil }(); err != nil { - return errors.Wrap(err, "decode field \"pageviews\"") + return errors.Wrap(err, "decode field \"duration\"") } - case "bounce_percentage": - requiredBitSet[0] |= 1 << 2 + case "duration_upper_quartile": if err := func() error { - v, err := d.Float32() - s.BouncePercentage = float32(v) - if err != nil { + s.DurationUpperQuartile.Reset() + if err := s.DurationUpperQuartile.Decode(d); err != nil { return err } return nil }(); err != nil { - return errors.Wrap(err, "decode field \"bounce_percentage\"") + return errors.Wrap(err, "decode field \"duration_upper_quartile\"") } - case "duration": - requiredBitSet[0] |= 1 << 3 + case "duration_lower_quartile": if err := func() error { - v, err := d.Int() - s.Duration = int(v) + s.DurationLowerQuartile.Reset() + if err := s.DurationLowerQuartile.Decode(d); err != nil { + return err + } + return nil + }(); err != nil { + return errors.Wrap(err, "decode field \"duration_lower_quartile\"") + } + case "duration_percentage": + requiredBitSet[0] |= 1 << 5 + if err := func() error { + v, err := d.Float32() + s.DurationPercentage = float32(v) if err != nil { return err } return nil }(); err != nil { - return errors.Wrap(err, "decode field \"duration\"") + return errors.Wrap(err, "decode field \"duration_percentage\"") } default: return d.Skip() } return nil }); err != nil { - return errors.Wrap(err, "decode StatsSummaryCurrent") + return errors.Wrap(err, "decode StatsTimeItem") } // Validate required fields. var failures []validate.FieldError for i, mask := range [1]uint8{ - 0b00001111, + 0b00100101, } { if result := (requiredBitSet[i] & mask) ^ mask; result != 0 { // Mask only required fields and check equality to mask using XOR. @@ -4551,8 +4504,8 @@ func (s *StatsSummaryCurrent) Decode(d *jx.Decoder) error { bitIdx := bits.TrailingZeros8(result) fieldIdx := i*8 + bitIdx var name string - if fieldIdx < len(jsonFieldsNameOfStatsSummaryCurrent) { - name = jsonFieldsNameOfStatsSummaryCurrent[fieldIdx] + if fieldIdx < len(jsonFieldsNameOfStatsTimeItem) { + name = jsonFieldsNameOfStatsTimeItem[fieldIdx] } else { name = strconv.Itoa(fieldIdx) } @@ -4573,267 +4526,170 @@ func (s *StatsSummaryCurrent) Decode(d *jx.Decoder) error { } // MarshalJSON implements stdjson.Marshaler. -func (s *StatsSummaryCurrent) MarshalJSON() ([]byte, error) { +func (s *StatsTimeItem) MarshalJSON() ([]byte, error) { e := jx.Encoder{} s.Encode(&e) return e.Bytes(), nil } // UnmarshalJSON implements stdjson.Unmarshaler. -func (s *StatsSummaryCurrent) UnmarshalJSON(data []byte) error { - d := jx.DecodeBytes(data) - return s.Decode(d) -} - -// Encode implements json.Marshaler. -func (s *StatsSummaryIntervalItem) Encode(e *jx.Encoder) { - e.ObjStart() - s.encodeFields(e) - e.ObjEnd() -} - -// encodeFields encodes fields. -func (s *StatsSummaryIntervalItem) encodeFields(e *jx.Encoder) { - { - e.FieldStart("date") - e.Str(s.Date) - } - { - if s.Visitors.Set { - e.FieldStart("visitors") - s.Visitors.Encode(e) - } - } - { - if s.Pageviews.Set { - e.FieldStart("pageviews") - s.Pageviews.Encode(e) - } - } - { - if s.BouncePercentage.Set { - e.FieldStart("bounce_percentage") - s.BouncePercentage.Encode(e) - } - } - { - if s.Duration.Set { - e.FieldStart("duration") - s.Duration.Encode(e) - } - } -} - -var jsonFieldsNameOfStatsSummaryIntervalItem = [5]string{ - 0: "date", - 1: "visitors", - 2: "pageviews", - 3: "bounce_percentage", - 4: "duration", -} - -// Decode decodes StatsSummaryIntervalItem from json. -func (s *StatsSummaryIntervalItem) Decode(d *jx.Decoder) error { - if s == nil { - return errors.New("invalid: unable to decode StatsSummaryIntervalItem to nil") - } - var requiredBitSet [1]uint8 - - if err := d.ObjBytes(func(d *jx.Decoder, k []byte) error { - switch string(k) { - case "date": - requiredBitSet[0] |= 1 << 0 - if err := func() error { - v, err := d.Str() - s.Date = string(v) - if err != nil { - return err - } - return nil - }(); err != nil { - return errors.Wrap(err, "decode field \"date\"") - } - case "visitors": - if err := func() error { - s.Visitors.Reset() - if err := s.Visitors.Decode(d); err != nil { - return err - } - return nil - }(); err != nil { - return errors.Wrap(err, "decode field \"visitors\"") - } - case "pageviews": - if err := func() error { - s.Pageviews.Reset() - if err := s.Pageviews.Decode(d); err != nil { - return err - } - return nil - }(); err != nil { - return errors.Wrap(err, "decode field \"pageviews\"") - } - case "bounce_percentage": - if err := func() error { - s.BouncePercentage.Reset() - if err := s.BouncePercentage.Decode(d); err != nil { - return err - } - return nil - }(); err != nil { - return errors.Wrap(err, "decode field \"bounce_percentage\"") - } - case "duration": - if err := func() error { - s.Duration.Reset() - if err := s.Duration.Decode(d); err != nil { - return err - } - return nil - }(); err != nil { - return errors.Wrap(err, "decode field \"duration\"") - } - default: - return d.Skip() - } - return nil - }); err != nil { - return errors.Wrap(err, "decode StatsSummaryIntervalItem") - } - // Validate required fields. - var failures []validate.FieldError - for i, mask := range [1]uint8{ - 0b00000001, - } { - 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(jsonFieldsNameOfStatsSummaryIntervalItem) { - name = jsonFieldsNameOfStatsSummaryIntervalItem[fieldIdx] - } else { - name = strconv.Itoa(fieldIdx) - } - failures = append(failures, validate.FieldError{ - Name: name, - Error: validate.ErrFieldRequired, - }) - // Reset bit. - result &^= 1 << bitIdx +func (s *StatsTimeItem) UnmarshalJSON(data []byte) error { + d := jx.DecodeBytes(data) + return s.Decode(d) +} + +// Encode encodes StatsUTMCampaigns as json. +func (s StatsUTMCampaigns) Encode(e *jx.Encoder) { + unwrapped := []StatsUTMCampaignsItem(s) + + e.ArrStart() + for _, elem := range unwrapped { + elem.Encode(e) + } + e.ArrEnd() +} + +// Decode decodes StatsUTMCampaigns from json. +func (s *StatsUTMCampaigns) Decode(d *jx.Decoder) error { + if s == nil { + return errors.New("invalid: unable to decode StatsUTMCampaigns to nil") + } + var unwrapped []StatsUTMCampaignsItem + if err := func() error { + unwrapped = make([]StatsUTMCampaignsItem, 0) + if err := d.Arr(func(d *jx.Decoder) error { + var elem StatsUTMCampaignsItem + 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") } - if len(failures) > 0 { - return &validate.Error{Fields: failures} - } - + *s = StatsUTMCampaigns(unwrapped) return nil } // MarshalJSON implements stdjson.Marshaler. -func (s *StatsSummaryIntervalItem) MarshalJSON() ([]byte, error) { +func (s StatsUTMCampaigns) MarshalJSON() ([]byte, error) { e := jx.Encoder{} s.Encode(&e) return e.Bytes(), nil } // UnmarshalJSON implements stdjson.Unmarshaler. -func (s *StatsSummaryIntervalItem) UnmarshalJSON(data []byte) error { +func (s *StatsUTMCampaigns) UnmarshalJSON(data []byte) error { d := jx.DecodeBytes(data) return s.Decode(d) } // Encode implements json.Marshaler. -func (s *StatsSummaryPrevious) Encode(e *jx.Encoder) { +func (s *StatsUTMCampaignsItem) Encode(e *jx.Encoder) { e.ObjStart() s.encodeFields(e) e.ObjEnd() } // encodeFields encodes fields. -func (s *StatsSummaryPrevious) encodeFields(e *jx.Encoder) { +func (s *StatsUTMCampaignsItem) encodeFields(e *jx.Encoder) { + { + e.FieldStart("campaign") + e.Str(s.Campaign) + } { e.FieldStart("visitors") e.Int(s.Visitors) } { - e.FieldStart("pageviews") - e.Int(s.Pageviews) + e.FieldStart("visitors_percentage") + e.Float32(s.VisitorsPercentage) } { - e.FieldStart("bounce_percentage") - e.Float32(s.BouncePercentage) + if s.BouncePercentage.Set { + e.FieldStart("bounce_percentage") + s.BouncePercentage.Encode(e) + } } { - e.FieldStart("duration") - e.Int(s.Duration) + if s.Duration.Set { + e.FieldStart("duration") + s.Duration.Encode(e) + } } } -var jsonFieldsNameOfStatsSummaryPrevious = [4]string{ - 0: "visitors", - 1: "pageviews", - 2: "bounce_percentage", - 3: "duration", +var jsonFieldsNameOfStatsUTMCampaignsItem = [5]string{ + 0: "campaign", + 1: "visitors", + 2: "visitors_percentage", + 3: "bounce_percentage", + 4: "duration", } -// Decode decodes StatsSummaryPrevious from json. -func (s *StatsSummaryPrevious) Decode(d *jx.Decoder) error { +// Decode decodes StatsUTMCampaignsItem from json. +func (s *StatsUTMCampaignsItem) Decode(d *jx.Decoder) error { if s == nil { - return errors.New("invalid: unable to decode StatsSummaryPrevious to nil") + return errors.New("invalid: unable to decode StatsUTMCampaignsItem to nil") } var requiredBitSet [1]uint8 if err := d.ObjBytes(func(d *jx.Decoder, k []byte) error { switch string(k) { - case "visitors": + case "campaign": requiredBitSet[0] |= 1 << 0 if err := func() error { - v, err := d.Int() - s.Visitors = int(v) + v, err := d.Str() + s.Campaign = string(v) if err != nil { return err } return nil }(); err != nil { - return errors.Wrap(err, "decode field \"visitors\"") + return errors.Wrap(err, "decode field \"campaign\"") } - case "pageviews": + case "visitors": requiredBitSet[0] |= 1 << 1 if err := func() error { v, err := d.Int() - s.Pageviews = int(v) + s.Visitors = int(v) if err != nil { return err } return nil }(); err != nil { - return errors.Wrap(err, "decode field \"pageviews\"") + return errors.Wrap(err, "decode field \"visitors\"") } - case "bounce_percentage": + case "visitors_percentage": requiredBitSet[0] |= 1 << 2 if err := func() error { v, err := d.Float32() - s.BouncePercentage = float32(v) + s.VisitorsPercentage = float32(v) if err != nil { return err } return nil + }(); err != nil { + return errors.Wrap(err, "decode field \"visitors_percentage\"") + } + case "bounce_percentage": + if err := func() error { + s.BouncePercentage.Reset() + if err := s.BouncePercentage.Decode(d); err != nil { + return err + } + return nil }(); err != nil { return errors.Wrap(err, "decode field \"bounce_percentage\"") } case "duration": - requiredBitSet[0] |= 1 << 3 if err := func() error { - v, err := d.Int() - s.Duration = int(v) - if err != nil { + s.Duration.Reset() + if err := s.Duration.Decode(d); err != nil { return err } return nil @@ -4845,12 +4701,12 @@ func (s *StatsSummaryPrevious) Decode(d *jx.Decoder) error { } return nil }); err != nil { - return errors.Wrap(err, "decode StatsSummaryPrevious") + return errors.Wrap(err, "decode StatsUTMCampaignsItem") } // Validate required fields. var failures []validate.FieldError for i, mask := range [1]uint8{ - 0b00001111, + 0b00000111, } { if result := (requiredBitSet[i] & mask) ^ mask; result != 0 { // Mask only required fields and check equality to mask using XOR. @@ -4862,8 +4718,8 @@ func (s *StatsSummaryPrevious) Decode(d *jx.Decoder) error { bitIdx := bits.TrailingZeros8(result) fieldIdx := i*8 + bitIdx var name string - if fieldIdx < len(jsonFieldsNameOfStatsSummaryPrevious) { - name = jsonFieldsNameOfStatsSummaryPrevious[fieldIdx] + if fieldIdx < len(jsonFieldsNameOfStatsUTMCampaignsItem) { + name = jsonFieldsNameOfStatsUTMCampaignsItem[fieldIdx] } else { name = strconv.Itoa(fieldIdx) } @@ -4884,21 +4740,21 @@ func (s *StatsSummaryPrevious) Decode(d *jx.Decoder) error { } // MarshalJSON implements stdjson.Marshaler. -func (s *StatsSummaryPrevious) MarshalJSON() ([]byte, error) { +func (s *StatsUTMCampaignsItem) MarshalJSON() ([]byte, error) { e := jx.Encoder{} s.Encode(&e) return e.Bytes(), nil } // UnmarshalJSON implements stdjson.Unmarshaler. -func (s *StatsSummaryPrevious) UnmarshalJSON(data []byte) error { +func (s *StatsUTMCampaignsItem) UnmarshalJSON(data []byte) error { d := jx.DecodeBytes(data) return s.Decode(d) } -// Encode encodes StatsTime as json. -func (s StatsTime) Encode(e *jx.Encoder) { - unwrapped := []StatsTimeItem(s) +// Encode encodes StatsUTMMediums as json. +func (s StatsUTMMediums) Encode(e *jx.Encoder) { + unwrapped := []StatsUTMMediumsItem(s) e.ArrStart() for _, elem := range unwrapped { @@ -4907,16 +4763,16 @@ func (s StatsTime) Encode(e *jx.Encoder) { e.ArrEnd() } -// Decode decodes StatsTime from json. -func (s *StatsTime) Decode(d *jx.Decoder) error { +// Decode decodes StatsUTMMediums from json. +func (s *StatsUTMMediums) Decode(d *jx.Decoder) error { if s == nil { - return errors.New("invalid: unable to decode StatsTime to nil") + return errors.New("invalid: unable to decode StatsUTMMediums to nil") } - var unwrapped []StatsTimeItem + var unwrapped []StatsUTMMediumsItem if err := func() error { - unwrapped = make([]StatsTimeItem, 0) + unwrapped = make([]StatsUTMMediumsItem, 0) if err := d.Arr(func(d *jx.Decoder) error { - var elem StatsTimeItem + var elem StatsUTMMediumsItem if err := elem.Decode(d); err != nil { return err } @@ -4929,159 +4785,142 @@ func (s *StatsTime) Decode(d *jx.Decoder) error { }(); err != nil { return errors.Wrap(err, "alias") } - *s = StatsTime(unwrapped) + *s = StatsUTMMediums(unwrapped) return nil } // MarshalJSON implements stdjson.Marshaler. -func (s StatsTime) MarshalJSON() ([]byte, error) { +func (s StatsUTMMediums) MarshalJSON() ([]byte, error) { e := jx.Encoder{} s.Encode(&e) return e.Bytes(), nil } // UnmarshalJSON implements stdjson.Unmarshaler. -func (s *StatsTime) UnmarshalJSON(data []byte) error { +func (s *StatsUTMMediums) UnmarshalJSON(data []byte) error { d := jx.DecodeBytes(data) return s.Decode(d) } // Encode implements json.Marshaler. -func (s *StatsTimeItem) Encode(e *jx.Encoder) { +func (s *StatsUTMMediumsItem) Encode(e *jx.Encoder) { e.ObjStart() s.encodeFields(e) e.ObjEnd() } // encodeFields encodes fields. -func (s *StatsTimeItem) encodeFields(e *jx.Encoder) { +func (s *StatsUTMMediumsItem) encodeFields(e *jx.Encoder) { { - e.FieldStart("path") - e.Str(s.Path) + e.FieldStart("medium") + e.Str(s.Medium) } { - if s.Visitors.Set { - e.FieldStart("visitors") - s.Visitors.Encode(e) - } + e.FieldStart("visitors") + e.Int(s.Visitors) } { - e.FieldStart("duration") - e.Int(s.Duration) + e.FieldStart("visitors_percentage") + e.Float32(s.VisitorsPercentage) } { - if s.DurationUpperQuartile.Set { - e.FieldStart("duration_upper_quartile") - s.DurationUpperQuartile.Encode(e) + if s.BouncePercentage.Set { + e.FieldStart("bounce_percentage") + s.BouncePercentage.Encode(e) } } { - if s.DurationLowerQuartile.Set { - e.FieldStart("duration_lower_quartile") - s.DurationLowerQuartile.Encode(e) + if s.Duration.Set { + e.FieldStart("duration") + s.Duration.Encode(e) } } - { - e.FieldStart("duration_percentage") - e.Float32(s.DurationPercentage) - } } -var jsonFieldsNameOfStatsTimeItem = [6]string{ - 0: "path", +var jsonFieldsNameOfStatsUTMMediumsItem = [5]string{ + 0: "medium", 1: "visitors", - 2: "duration", - 3: "duration_upper_quartile", - 4: "duration_lower_quartile", - 5: "duration_percentage", + 2: "visitors_percentage", + 3: "bounce_percentage", + 4: "duration", } -// Decode decodes StatsTimeItem from json. -func (s *StatsTimeItem) Decode(d *jx.Decoder) error { +// Decode decodes StatsUTMMediumsItem from json. +func (s *StatsUTMMediumsItem) Decode(d *jx.Decoder) error { if s == nil { - return errors.New("invalid: unable to decode StatsTimeItem to nil") + return errors.New("invalid: unable to decode StatsUTMMediumsItem to nil") } var requiredBitSet [1]uint8 if err := d.ObjBytes(func(d *jx.Decoder, k []byte) error { switch string(k) { - case "path": + case "medium": requiredBitSet[0] |= 1 << 0 if err := func() error { v, err := d.Str() - s.Path = string(v) + s.Medium = string(v) if err != nil { return err } return nil }(); err != nil { - return errors.Wrap(err, "decode field \"path\"") + return errors.Wrap(err, "decode field \"medium\"") } case "visitors": + requiredBitSet[0] |= 1 << 1 if err := func() error { - s.Visitors.Reset() - if err := s.Visitors.Decode(d); err != nil { + v, err := d.Int() + s.Visitors = int(v) + if err != nil { return err } return nil }(); err != nil { return errors.Wrap(err, "decode field \"visitors\"") } - case "duration": + case "visitors_percentage": requiredBitSet[0] |= 1 << 2 if err := func() error { - v, err := d.Int() - s.Duration = int(v) + v, err := d.Float32() + s.VisitorsPercentage = float32(v) if err != nil { return err } return nil }(); err != nil { - return errors.Wrap(err, "decode field \"duration\"") - } - case "duration_upper_quartile": - if err := func() error { - s.DurationUpperQuartile.Reset() - if err := s.DurationUpperQuartile.Decode(d); err != nil { - return err - } - return nil - }(); err != nil { - return errors.Wrap(err, "decode field \"duration_upper_quartile\"") + return errors.Wrap(err, "decode field \"visitors_percentage\"") } - case "duration_lower_quartile": + case "bounce_percentage": if err := func() error { - s.DurationLowerQuartile.Reset() - if err := s.DurationLowerQuartile.Decode(d); err != nil { + s.BouncePercentage.Reset() + if err := s.BouncePercentage.Decode(d); err != nil { return err } return nil }(); err != nil { - return errors.Wrap(err, "decode field \"duration_lower_quartile\"") + return errors.Wrap(err, "decode field \"bounce_percentage\"") } - case "duration_percentage": - requiredBitSet[0] |= 1 << 5 + case "duration": if err := func() error { - v, err := d.Float32() - s.DurationPercentage = float32(v) - if err != nil { + s.Duration.Reset() + if err := s.Duration.Decode(d); err != nil { return err } return nil }(); err != nil { - return errors.Wrap(err, "decode field \"duration_percentage\"") + return errors.Wrap(err, "decode field \"duration\"") } default: return d.Skip() } return nil }); err != nil { - return errors.Wrap(err, "decode StatsTimeItem") + return errors.Wrap(err, "decode StatsUTMMediumsItem") } // Validate required fields. var failures []validate.FieldError for i, mask := range [1]uint8{ - 0b00100101, + 0b00000111, } { if result := (requiredBitSet[i] & mask) ^ mask; result != 0 { // Mask only required fields and check equality to mask using XOR. @@ -5093,8 +4932,8 @@ func (s *StatsTimeItem) Decode(d *jx.Decoder) error { bitIdx := bits.TrailingZeros8(result) fieldIdx := i*8 + bitIdx var name string - if fieldIdx < len(jsonFieldsNameOfStatsTimeItem) { - name = jsonFieldsNameOfStatsTimeItem[fieldIdx] + if fieldIdx < len(jsonFieldsNameOfStatsUTMMediumsItem) { + name = jsonFieldsNameOfStatsUTMMediumsItem[fieldIdx] } else { name = strconv.Itoa(fieldIdx) } @@ -5115,21 +4954,21 @@ func (s *StatsTimeItem) Decode(d *jx.Decoder) error { } // MarshalJSON implements stdjson.Marshaler. -func (s *StatsTimeItem) MarshalJSON() ([]byte, error) { +func (s *StatsUTMMediumsItem) MarshalJSON() ([]byte, error) { e := jx.Encoder{} s.Encode(&e) return e.Bytes(), nil } // UnmarshalJSON implements stdjson.Unmarshaler. -func (s *StatsTimeItem) UnmarshalJSON(data []byte) error { +func (s *StatsUTMMediumsItem) UnmarshalJSON(data []byte) error { d := jx.DecodeBytes(data) return s.Decode(d) } -// Encode encodes StatsUTMCampaigns as json. -func (s StatsUTMCampaigns) Encode(e *jx.Encoder) { - unwrapped := []StatsUTMCampaignsItem(s) +// Encode encodes StatsUTMSources as json. +func (s StatsUTMSources) Encode(e *jx.Encoder) { + unwrapped := []StatsUTMSourcesItem(s) e.ArrStart() for _, elem := range unwrapped { @@ -5138,16 +4977,16 @@ func (s StatsUTMCampaigns) Encode(e *jx.Encoder) { e.ArrEnd() } -// Decode decodes StatsUTMCampaigns from json. -func (s *StatsUTMCampaigns) Decode(d *jx.Decoder) error { +// Decode decodes StatsUTMSources from json. +func (s *StatsUTMSources) Decode(d *jx.Decoder) error { if s == nil { - return errors.New("invalid: unable to decode StatsUTMCampaigns to nil") + return errors.New("invalid: unable to decode StatsUTMSources to nil") } - var unwrapped []StatsUTMCampaignsItem + var unwrapped []StatsUTMSourcesItem if err := func() error { - unwrapped = make([]StatsUTMCampaignsItem, 0) + unwrapped = make([]StatsUTMSourcesItem, 0) if err := d.Arr(func(d *jx.Decoder) error { - var elem StatsUTMCampaignsItem + var elem StatsUTMSourcesItem if err := elem.Decode(d); err != nil { return err } @@ -5160,35 +4999,35 @@ func (s *StatsUTMCampaigns) Decode(d *jx.Decoder) error { }(); err != nil { return errors.Wrap(err, "alias") } - *s = StatsUTMCampaigns(unwrapped) + *s = StatsUTMSources(unwrapped) return nil } // MarshalJSON implements stdjson.Marshaler. -func (s StatsUTMCampaigns) MarshalJSON() ([]byte, error) { +func (s StatsUTMSources) MarshalJSON() ([]byte, error) { e := jx.Encoder{} s.Encode(&e) return e.Bytes(), nil } // UnmarshalJSON implements stdjson.Unmarshaler. -func (s *StatsUTMCampaigns) UnmarshalJSON(data []byte) error { +func (s *StatsUTMSources) UnmarshalJSON(data []byte) error { d := jx.DecodeBytes(data) return s.Decode(d) } // Encode implements json.Marshaler. -func (s *StatsUTMCampaignsItem) Encode(e *jx.Encoder) { +func (s *StatsUTMSourcesItem) Encode(e *jx.Encoder) { e.ObjStart() s.encodeFields(e) e.ObjEnd() } // encodeFields encodes fields. -func (s *StatsUTMCampaignsItem) encodeFields(e *jx.Encoder) { +func (s *StatsUTMSourcesItem) encodeFields(e *jx.Encoder) { { - e.FieldStart("campaign") - e.Str(s.Campaign) + e.FieldStart("source") + e.Str(s.Source) } { e.FieldStart("visitors") @@ -5212,34 +5051,34 @@ func (s *StatsUTMCampaignsItem) encodeFields(e *jx.Encoder) { } } -var jsonFieldsNameOfStatsUTMCampaignsItem = [5]string{ - 0: "campaign", +var jsonFieldsNameOfStatsUTMSourcesItem = [5]string{ + 0: "source", 1: "visitors", 2: "visitors_percentage", 3: "bounce_percentage", 4: "duration", } -// Decode decodes StatsUTMCampaignsItem from json. -func (s *StatsUTMCampaignsItem) Decode(d *jx.Decoder) error { +// Decode decodes StatsUTMSourcesItem from json. +func (s *StatsUTMSourcesItem) Decode(d *jx.Decoder) error { if s == nil { - return errors.New("invalid: unable to decode StatsUTMCampaignsItem to nil") + return errors.New("invalid: unable to decode StatsUTMSourcesItem to nil") } var requiredBitSet [1]uint8 if err := d.ObjBytes(func(d *jx.Decoder, k []byte) error { switch string(k) { - case "campaign": + case "source": requiredBitSet[0] |= 1 << 0 if err := func() error { v, err := d.Str() - s.Campaign = string(v) + s.Source = string(v) if err != nil { return err } return nil }(); err != nil { - return errors.Wrap(err, "decode field \"campaign\"") + return errors.Wrap(err, "decode field \"source\"") } case "visitors": requiredBitSet[0] |= 1 << 1 @@ -5267,35 +5106,243 @@ func (s *StatsUTMCampaignsItem) Decode(d *jx.Decoder) error { } case "bounce_percentage": if err := func() error { - s.BouncePercentage.Reset() - if err := s.BouncePercentage.Decode(d); err != nil { + s.BouncePercentage.Reset() + if err := s.BouncePercentage.Decode(d); err != nil { + return err + } + return nil + }(); err != nil { + return errors.Wrap(err, "decode field \"bounce_percentage\"") + } + case "duration": + if err := func() error { + s.Duration.Reset() + if err := s.Duration.Decode(d); err != nil { + return err + } + return nil + }(); err != nil { + return errors.Wrap(err, "decode field \"duration\"") + } + default: + return d.Skip() + } + return nil + }); err != nil { + return errors.Wrap(err, "decode StatsUTMSourcesItem") + } + // Validate required fields. + var failures []validate.FieldError + for i, mask := range [1]uint8{ + 0b00000111, + } { + 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(jsonFieldsNameOfStatsUTMSourcesItem) { + name = jsonFieldsNameOfStatsUTMSourcesItem[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 *StatsUTMSourcesItem) MarshalJSON() ([]byte, error) { + e := jx.Encoder{} + s.Encode(&e) + return e.Bytes(), nil +} + +// UnmarshalJSON implements stdjson.Unmarshaler. +func (s *StatsUTMSourcesItem) UnmarshalJSON(data []byte) error { + d := jx.DecodeBytes(data) + return s.Decode(d) +} + +// Encode implements json.Marshaler. +func (s *UnauthorisedError) Encode(e *jx.Encoder) { + e.ObjStart() + s.encodeFields(e) + e.ObjEnd() +} + +// encodeFields encodes fields. +func (s *UnauthorisedError) encodeFields(e *jx.Encoder) { + { + e.FieldStart("error") + s.Error.Encode(e) + } +} + +var jsonFieldsNameOfUnauthorisedError = [1]string{ + 0: "error", +} + +// Decode decodes UnauthorisedError from json. +func (s *UnauthorisedError) Decode(d *jx.Decoder) error { + if s == nil { + return errors.New("invalid: unable to decode UnauthorisedError to nil") + } + var requiredBitSet [1]uint8 + + if err := d.ObjBytes(func(d *jx.Decoder, k []byte) error { + switch string(k) { + case "error": + requiredBitSet[0] |= 1 << 0 + if err := func() error { + if err := s.Error.Decode(d); err != nil { + return err + } + return nil + }(); err != nil { + return errors.Wrap(err, "decode field \"error\"") + } + default: + return d.Skip() + } + return nil + }); err != nil { + return errors.Wrap(err, "decode UnauthorisedError") + } + // Validate required fields. + var failures []validate.FieldError + for i, mask := range [1]uint8{ + 0b00000001, + } { + 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(jsonFieldsNameOfUnauthorisedError) { + name = jsonFieldsNameOfUnauthorisedError[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 *UnauthorisedError) MarshalJSON() ([]byte, error) { + e := jx.Encoder{} + s.Encode(&e) + return e.Bytes(), nil +} + +// UnmarshalJSON implements stdjson.Unmarshaler. +func (s *UnauthorisedError) UnmarshalJSON(data []byte) error { + d := jx.DecodeBytes(data) + return s.Decode(d) +} + +// Encode implements json.Marshaler. +func (s *UnauthorisedErrorError) Encode(e *jx.Encoder) { + e.ObjStart() + s.encodeFields(e) + e.ObjEnd() +} + +// encodeFields encodes fields. +func (s *UnauthorisedErrorError) encodeFields(e *jx.Encoder) { + { + e.FieldStart("code") + e.Int32(s.Code) + } + { + e.FieldStart("message") + e.Str(s.Message) + } +} + +var jsonFieldsNameOfUnauthorisedErrorError = [2]string{ + 0: "code", + 1: "message", +} + +// Decode decodes UnauthorisedErrorError from json. +func (s *UnauthorisedErrorError) Decode(d *jx.Decoder) error { + if s == nil { + return errors.New("invalid: unable to decode UnauthorisedErrorError to nil") + } + var requiredBitSet [1]uint8 + s.setDefaults() + + if err := d.ObjBytes(func(d *jx.Decoder, k []byte) error { + switch string(k) { + case "code": + requiredBitSet[0] |= 1 << 0 + if err := func() error { + v, err := d.Int32() + s.Code = int32(v) + if err != nil { return err } return nil }(); err != nil { - return errors.Wrap(err, "decode field \"bounce_percentage\"") + return errors.Wrap(err, "decode field \"code\"") } - case "duration": + case "message": + requiredBitSet[0] |= 1 << 1 if err := func() error { - s.Duration.Reset() - if err := s.Duration.Decode(d); err != nil { + v, err := d.Str() + s.Message = string(v) + if err != nil { return err } return nil }(); err != nil { - return errors.Wrap(err, "decode field \"duration\"") + return errors.Wrap(err, "decode field \"message\"") } default: - return d.Skip() + return errors.Errorf("unexpected field %q", k) } return nil }); err != nil { - return errors.Wrap(err, "decode StatsUTMCampaignsItem") + return errors.Wrap(err, "decode UnauthorisedErrorError") } // Validate required fields. var failures []validate.FieldError for i, mask := range [1]uint8{ - 0b00000111, + 0b00000011, } { if result := (requiredBitSet[i] & mask) ^ mask; result != 0 { // Mask only required fields and check equality to mask using XOR. @@ -5307,8 +5354,8 @@ func (s *StatsUTMCampaignsItem) Decode(d *jx.Decoder) error { bitIdx := bits.TrailingZeros8(result) fieldIdx := i*8 + bitIdx var name string - if fieldIdx < len(jsonFieldsNameOfStatsUTMCampaignsItem) { - name = jsonFieldsNameOfStatsUTMCampaignsItem[fieldIdx] + if fieldIdx < len(jsonFieldsNameOfUnauthorisedErrorError) { + name = jsonFieldsNameOfUnauthorisedErrorError[fieldIdx] } else { name = strconv.Itoa(fieldIdx) } @@ -5329,187 +5376,118 @@ func (s *StatsUTMCampaignsItem) Decode(d *jx.Decoder) error { } // MarshalJSON implements stdjson.Marshaler. -func (s *StatsUTMCampaignsItem) MarshalJSON() ([]byte, error) { - e := jx.Encoder{} - s.Encode(&e) - return e.Bytes(), nil -} - -// UnmarshalJSON implements stdjson.Unmarshaler. -func (s *StatsUTMCampaignsItem) UnmarshalJSON(data []byte) error { - d := jx.DecodeBytes(data) - return s.Decode(d) -} - -// Encode encodes StatsUTMMediums as json. -func (s StatsUTMMediums) Encode(e *jx.Encoder) { - unwrapped := []StatsUTMMediumsItem(s) - - e.ArrStart() - for _, elem := range unwrapped { - elem.Encode(e) - } - e.ArrEnd() -} - -// Decode decodes StatsUTMMediums from json. -func (s *StatsUTMMediums) Decode(d *jx.Decoder) error { - if s == nil { - return errors.New("invalid: unable to decode StatsUTMMediums to nil") - } - var unwrapped []StatsUTMMediumsItem - if err := func() error { - unwrapped = make([]StatsUTMMediumsItem, 0) - if err := d.Arr(func(d *jx.Decoder) error { - var elem StatsUTMMediumsItem - 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 = StatsUTMMediums(unwrapped) - return nil -} - -// MarshalJSON implements stdjson.Marshaler. -func (s StatsUTMMediums) MarshalJSON() ([]byte, error) { +func (s *UnauthorisedErrorError) MarshalJSON() ([]byte, error) { e := jx.Encoder{} s.Encode(&e) return e.Bytes(), nil } // UnmarshalJSON implements stdjson.Unmarshaler. -func (s *StatsUTMMediums) UnmarshalJSON(data []byte) error { +func (s *UnauthorisedErrorError) UnmarshalJSON(data []byte) error { d := jx.DecodeBytes(data) return s.Decode(d) } // Encode implements json.Marshaler. -func (s *StatsUTMMediumsItem) Encode(e *jx.Encoder) { +func (s *UserGet) Encode(e *jx.Encoder) { e.ObjStart() s.encodeFields(e) e.ObjEnd() } // encodeFields encodes fields. -func (s *StatsUTMMediumsItem) encodeFields(e *jx.Encoder) { - { - e.FieldStart("medium") - e.Str(s.Medium) - } +func (s *UserGet) encodeFields(e *jx.Encoder) { { - e.FieldStart("visitors") - e.Int(s.Visitors) + e.FieldStart("username") + e.Str(s.Username) } { - e.FieldStart("visitors_percentage") - e.Float32(s.VisitorsPercentage) + e.FieldStart("settings") + s.Settings.Encode(e) } { - if s.BouncePercentage.Set { - e.FieldStart("bounce_percentage") - s.BouncePercentage.Encode(e) - } + e.FieldStart("dateCreated") + e.Int64(s.DateCreated) } { - if s.Duration.Set { - e.FieldStart("duration") - s.Duration.Encode(e) - } + e.FieldStart("dateUpdated") + e.Int64(s.DateUpdated) } } -var jsonFieldsNameOfStatsUTMMediumsItem = [5]string{ - 0: "medium", - 1: "visitors", - 2: "visitors_percentage", - 3: "bounce_percentage", - 4: "duration", +var jsonFieldsNameOfUserGet = [4]string{ + 0: "username", + 1: "settings", + 2: "dateCreated", + 3: "dateUpdated", } -// Decode decodes StatsUTMMediumsItem from json. -func (s *StatsUTMMediumsItem) Decode(d *jx.Decoder) error { +// Decode decodes UserGet from json. +func (s *UserGet) Decode(d *jx.Decoder) error { if s == nil { - return errors.New("invalid: unable to decode StatsUTMMediumsItem to nil") + return errors.New("invalid: unable to decode UserGet to nil") } var requiredBitSet [1]uint8 if err := d.ObjBytes(func(d *jx.Decoder, k []byte) error { switch string(k) { - case "medium": + case "username": requiredBitSet[0] |= 1 << 0 if err := func() error { v, err := d.Str() - s.Medium = string(v) + s.Username = string(v) if err != nil { return err } return nil }(); err != nil { - return errors.Wrap(err, "decode field \"medium\"") + return errors.Wrap(err, "decode field \"username\"") } - case "visitors": + case "settings": requiredBitSet[0] |= 1 << 1 if err := func() error { - v, err := d.Int() - s.Visitors = int(v) - if err != nil { + if err := s.Settings.Decode(d); err != nil { return err } return nil }(); err != nil { - return errors.Wrap(err, "decode field \"visitors\"") + return errors.Wrap(err, "decode field \"settings\"") } - case "visitors_percentage": + case "dateCreated": requiredBitSet[0] |= 1 << 2 if err := func() error { - v, err := d.Float32() - s.VisitorsPercentage = float32(v) + v, err := d.Int64() + s.DateCreated = int64(v) if err != nil { return err } return nil }(); err != nil { - return errors.Wrap(err, "decode field \"visitors_percentage\"") - } - case "bounce_percentage": - if err := func() error { - s.BouncePercentage.Reset() - if err := s.BouncePercentage.Decode(d); err != nil { - return err - } - return nil - }(); err != nil { - return errors.Wrap(err, "decode field \"bounce_percentage\"") + return errors.Wrap(err, "decode field \"dateCreated\"") } - case "duration": + case "dateUpdated": + requiredBitSet[0] |= 1 << 3 if err := func() error { - s.Duration.Reset() - if err := s.Duration.Decode(d); err != nil { + v, err := d.Int64() + s.DateUpdated = int64(v) + if err != nil { return err } return nil }(); err != nil { - return errors.Wrap(err, "decode field \"duration\"") + return errors.Wrap(err, "decode field \"dateUpdated\"") } default: return d.Skip() } return nil }); err != nil { - return errors.Wrap(err, "decode StatsUTMMediumsItem") + return errors.Wrap(err, "decode UserGet") } // Validate required fields. var failures []validate.FieldError for i, mask := range [1]uint8{ - 0b00000111, + 0b00001111, } { if result := (requiredBitSet[i] & mask) ^ mask; result != 0 { // Mask only required fields and check equality to mask using XOR. @@ -5521,8 +5499,8 @@ func (s *StatsUTMMediumsItem) Decode(d *jx.Decoder) error { bitIdx := bits.TrailingZeros8(result) fieldIdx := i*8 + bitIdx var name string - if fieldIdx < len(jsonFieldsNameOfStatsUTMMediumsItem) { - name = jsonFieldsNameOfStatsUTMMediumsItem[fieldIdx] + if fieldIdx < len(jsonFieldsNameOfUserGet) { + name = jsonFieldsNameOfUserGet[fieldIdx] } else { name = strconv.Itoa(fieldIdx) } @@ -5543,281 +5521,353 @@ func (s *StatsUTMMediumsItem) Decode(d *jx.Decoder) error { } // MarshalJSON implements stdjson.Marshaler. -func (s *StatsUTMMediumsItem) MarshalJSON() ([]byte, error) { +func (s *UserGet) MarshalJSON() ([]byte, error) { e := jx.Encoder{} s.Encode(&e) return e.Bytes(), nil } // UnmarshalJSON implements stdjson.Unmarshaler. -func (s *StatsUTMMediumsItem) UnmarshalJSON(data []byte) error { +func (s *UserGet) UnmarshalJSON(data []byte) error { d := jx.DecodeBytes(data) return s.Decode(d) } -// Encode encodes StatsUTMSources as json. -func (s StatsUTMSources) Encode(e *jx.Encoder) { - unwrapped := []StatsUTMSourcesItem(s) +// Encode implements json.Marshaler. +func (s *UserPatch) Encode(e *jx.Encoder) { + e.ObjStart() + s.encodeFields(e) + e.ObjEnd() +} - e.ArrStart() - for _, elem := range unwrapped { - elem.Encode(e) +// encodeFields encodes fields. +func (s *UserPatch) encodeFields(e *jx.Encoder) { + { + if s.Username.Set { + e.FieldStart("username") + s.Username.Encode(e) + } + } + { + if s.Password.Set { + e.FieldStart("password") + s.Password.Encode(e) + } + } + { + if s.Settings.Set { + e.FieldStart("settings") + s.Settings.Encode(e) + } } - e.ArrEnd() } -// Decode decodes StatsUTMSources from json. -func (s *StatsUTMSources) Decode(d *jx.Decoder) error { +var jsonFieldsNameOfUserPatch = [3]string{ + 0: "username", + 1: "password", + 2: "settings", +} + +// Decode decodes UserPatch from json. +func (s *UserPatch) Decode(d *jx.Decoder) error { if s == nil { - return errors.New("invalid: unable to decode StatsUTMSources to nil") + return errors.New("invalid: unable to decode UserPatch to nil") } - var unwrapped []StatsUTMSourcesItem - if err := func() error { - unwrapped = make([]StatsUTMSourcesItem, 0) - if err := d.Arr(func(d *jx.Decoder) error { - var elem StatsUTMSourcesItem - if err := elem.Decode(d); err != nil { - return err + + if err := d.ObjBytes(func(d *jx.Decoder, k []byte) error { + switch string(k) { + case "username": + if err := func() error { + s.Username.Reset() + if err := s.Username.Decode(d); err != nil { + return err + } + return nil + }(); err != nil { + return errors.Wrap(err, "decode field \"username\"") } - unwrapped = append(unwrapped, elem) - return nil - }); err != nil { - return err + case "password": + if err := func() error { + s.Password.Reset() + if err := s.Password.Decode(d); err != nil { + return err + } + return nil + }(); err != nil { + return errors.Wrap(err, "decode field \"password\"") + } + case "settings": + if err := func() error { + s.Settings.Reset() + if err := s.Settings.Decode(d); err != nil { + return err + } + return nil + }(); err != nil { + return errors.Wrap(err, "decode field \"settings\"") + } + default: + return d.Skip() } return nil - }(); err != nil { - return errors.Wrap(err, "alias") + }); err != nil { + return errors.Wrap(err, "decode UserPatch") } - *s = StatsUTMSources(unwrapped) + return nil } // MarshalJSON implements stdjson.Marshaler. -func (s StatsUTMSources) MarshalJSON() ([]byte, error) { +func (s *UserPatch) MarshalJSON() ([]byte, error) { e := jx.Encoder{} s.Encode(&e) return e.Bytes(), nil } // UnmarshalJSON implements stdjson.Unmarshaler. -func (s *StatsUTMSources) UnmarshalJSON(data []byte) error { +func (s *UserPatch) UnmarshalJSON(data []byte) error { d := jx.DecodeBytes(data) return s.Decode(d) } // Encode implements json.Marshaler. -func (s *StatsUTMSourcesItem) Encode(e *jx.Encoder) { +func (s *UserSettings) Encode(e *jx.Encoder) { e.ObjStart() s.encodeFields(e) e.ObjEnd() } // encodeFields encodes fields. -func (s *StatsUTMSourcesItem) encodeFields(e *jx.Encoder) { - { - e.FieldStart("source") - e.Str(s.Source) - } - { - e.FieldStart("visitors") - e.Int(s.Visitors) - } - { - e.FieldStart("visitors_percentage") - e.Float32(s.VisitorsPercentage) - } +func (s *UserSettings) encodeFields(e *jx.Encoder) { { - if s.BouncePercentage.Set { - e.FieldStart("bounce_percentage") - s.BouncePercentage.Encode(e) + if s.Language.Set { + e.FieldStart("language") + s.Language.Encode(e) } } { - if s.Duration.Set { - e.FieldStart("duration") - s.Duration.Encode(e) + if s.ScriptType.Set { + e.FieldStart("script_type") + s.ScriptType.Encode(e) } } } -var jsonFieldsNameOfStatsUTMSourcesItem = [5]string{ - 0: "source", - 1: "visitors", - 2: "visitors_percentage", - 3: "bounce_percentage", - 4: "duration", +var jsonFieldsNameOfUserSettings = [2]string{ + 0: "language", + 1: "script_type", } -// Decode decodes StatsUTMSourcesItem from json. -func (s *StatsUTMSourcesItem) Decode(d *jx.Decoder) error { +// Decode decodes UserSettings from json. +func (s *UserSettings) Decode(d *jx.Decoder) error { if s == nil { - return errors.New("invalid: unable to decode StatsUTMSourcesItem to nil") + return errors.New("invalid: unable to decode UserSettings to nil") } - var requiredBitSet [1]uint8 + s.setDefaults() if err := d.ObjBytes(func(d *jx.Decoder, k []byte) error { switch string(k) { - case "source": - requiredBitSet[0] |= 1 << 0 - if err := func() error { - v, err := d.Str() - s.Source = string(v) - if err != nil { - return err - } - return nil - }(); err != nil { - return errors.Wrap(err, "decode field \"source\"") - } - case "visitors": - requiredBitSet[0] |= 1 << 1 - if err := func() error { - v, err := d.Int() - s.Visitors = int(v) - if err != nil { - return err - } - return nil - }(); err != nil { - return errors.Wrap(err, "decode field \"visitors\"") - } - case "visitors_percentage": - requiredBitSet[0] |= 1 << 2 - if err := func() error { - v, err := d.Float32() - s.VisitorsPercentage = float32(v) - if err != nil { - return err - } - return nil - }(); err != nil { - return errors.Wrap(err, "decode field \"visitors_percentage\"") - } - case "bounce_percentage": + case "language": if err := func() error { - s.BouncePercentage.Reset() - if err := s.BouncePercentage.Decode(d); err != nil { + s.Language.Reset() + if err := s.Language.Decode(d); err != nil { return err } return nil }(); err != nil { - return errors.Wrap(err, "decode field \"bounce_percentage\"") + return errors.Wrap(err, "decode field \"language\"") } - case "duration": + case "script_type": if err := func() error { - s.Duration.Reset() - if err := s.Duration.Decode(d); err != nil { + s.ScriptType.Reset() + if err := s.ScriptType.Decode(d); err != nil { return err } return nil }(); err != nil { - return errors.Wrap(err, "decode field \"duration\"") + return errors.Wrap(err, "decode field \"script_type\"") } default: return d.Skip() } return nil }); err != nil { - return errors.Wrap(err, "decode StatsUTMSourcesItem") + return errors.Wrap(err, "decode UserSettings") } - // Validate required fields. - var failures []validate.FieldError - for i, mask := range [1]uint8{ - 0b00000111, - } { - 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(jsonFieldsNameOfStatsUTMSourcesItem) { - name = jsonFieldsNameOfStatsUTMSourcesItem[fieldIdx] - } else { - name = strconv.Itoa(fieldIdx) - } - failures = append(failures, validate.FieldError{ - Name: name, - Error: validate.ErrFieldRequired, - }) - // Reset bit. - result &^= 1 << bitIdx - } - } + + return nil +} + +// MarshalJSON implements stdjson.Marshaler. +func (s *UserSettings) MarshalJSON() ([]byte, error) { + e := jx.Encoder{} + s.Encode(&e) + return e.Bytes(), nil +} + +// UnmarshalJSON implements stdjson.Unmarshaler. +func (s *UserSettings) UnmarshalJSON(data []byte) error { + d := jx.DecodeBytes(data) + return s.Decode(d) +} + +// Encode encodes UserSettingsLanguage as json. +func (s UserSettingsLanguage) Encode(e *jx.Encoder) { + e.Str(string(s)) +} + +// Decode decodes UserSettingsLanguage from json. +func (s *UserSettingsLanguage) Decode(d *jx.Decoder) error { + if s == nil { + return errors.New("invalid: unable to decode UserSettingsLanguage to nil") } - if len(failures) > 0 { - return &validate.Error{Fields: failures} + v, err := d.StrBytes() + if err != nil { + return err + } + // Try to use constant string. + switch UserSettingsLanguage(v) { + case UserSettingsLanguageEn: + *s = UserSettingsLanguageEn + default: + *s = UserSettingsLanguage(v) } return nil } // MarshalJSON implements stdjson.Marshaler. -func (s *StatsUTMSourcesItem) MarshalJSON() ([]byte, error) { +func (s UserSettingsLanguage) MarshalJSON() ([]byte, error) { e := jx.Encoder{} s.Encode(&e) return e.Bytes(), nil } // UnmarshalJSON implements stdjson.Unmarshaler. -func (s *StatsUTMSourcesItem) UnmarshalJSON(data []byte) error { +func (s *UserSettingsLanguage) UnmarshalJSON(data []byte) error { + d := jx.DecodeBytes(data) + return s.Decode(d) +} + +// Encode encodes UserSettingsScriptType as json. +func (s UserSettingsScriptType) Encode(e *jx.Encoder) { + e.Str(string(s)) +} + +// Decode decodes UserSettingsScriptType from json. +func (s *UserSettingsScriptType) Decode(d *jx.Decoder) error { + if s == nil { + return errors.New("invalid: unable to decode UserSettingsScriptType to nil") + } + v, err := d.StrBytes() + if err != nil { + return err + } + // Try to use constant string. + switch UserSettingsScriptType(v) { + case UserSettingsScriptTypeDefault: + *s = UserSettingsScriptTypeDefault + case UserSettingsScriptTypeTaggedEvents: + *s = UserSettingsScriptTypeTaggedEvents + default: + *s = UserSettingsScriptType(v) + } + + return nil +} + +// MarshalJSON implements stdjson.Marshaler. +func (s UserSettingsScriptType) MarshalJSON() ([]byte, error) { + e := jx.Encoder{} + s.Encode(&e) + return e.Bytes(), nil +} + +// UnmarshalJSON implements stdjson.Unmarshaler. +func (s *UserSettingsScriptType) UnmarshalJSON(data []byte) error { d := jx.DecodeBytes(data) return s.Decode(d) } // Encode implements json.Marshaler. -func (s *UnauthorisedError) Encode(e *jx.Encoder) { +func (s *UserUsageGet) Encode(e *jx.Encoder) { e.ObjStart() s.encodeFields(e) e.ObjEnd() } // encodeFields encodes fields. -func (s *UnauthorisedError) encodeFields(e *jx.Encoder) { +func (s *UserUsageGet) encodeFields(e *jx.Encoder) { { - e.FieldStart("error") - s.Error.Encode(e) + e.FieldStart("cpu") + s.CPU.Encode(e) + } + { + e.FieldStart("memory") + s.Memory.Encode(e) + } + { + e.FieldStart("disk") + s.Disk.Encode(e) } } -var jsonFieldsNameOfUnauthorisedError = [1]string{ - 0: "error", +var jsonFieldsNameOfUserUsageGet = [3]string{ + 0: "cpu", + 1: "memory", + 2: "disk", } -// Decode decodes UnauthorisedError from json. -func (s *UnauthorisedError) Decode(d *jx.Decoder) error { +// Decode decodes UserUsageGet from json. +func (s *UserUsageGet) Decode(d *jx.Decoder) error { if s == nil { - return errors.New("invalid: unable to decode UnauthorisedError to nil") + return errors.New("invalid: unable to decode UserUsageGet to nil") } var requiredBitSet [1]uint8 if err := d.ObjBytes(func(d *jx.Decoder, k []byte) error { switch string(k) { - case "error": + case "cpu": requiredBitSet[0] |= 1 << 0 if err := func() error { - if err := s.Error.Decode(d); err != nil { + if err := s.CPU.Decode(d); err != nil { return err } return nil }(); err != nil { - return errors.Wrap(err, "decode field \"error\"") + return errors.Wrap(err, "decode field \"cpu\"") + } + case "memory": + requiredBitSet[0] |= 1 << 1 + if err := func() error { + if err := s.Memory.Decode(d); err != nil { + return err + } + return nil + }(); err != nil { + return errors.Wrap(err, "decode field \"memory\"") + } + case "disk": + requiredBitSet[0] |= 1 << 2 + if err := func() error { + if err := s.Disk.Decode(d); err != nil { + return err + } + return nil + }(); err != nil { + return errors.Wrap(err, "decode field \"disk\"") } default: return d.Skip() } return nil }); err != nil { - return errors.Wrap(err, "decode UnauthorisedError") + return errors.Wrap(err, "decode UserUsageGet") } // Validate required fields. var failures []validate.FieldError for i, mask := range [1]uint8{ - 0b00000001, + 0b00000111, } { if result := (requiredBitSet[i] & mask) ^ mask; result != 0 { // Mask only required fields and check equality to mask using XOR. @@ -5829,8 +5879,8 @@ func (s *UnauthorisedError) Decode(d *jx.Decoder) error { bitIdx := bits.TrailingZeros8(result) fieldIdx := i*8 + bitIdx var name string - if fieldIdx < len(jsonFieldsNameOfUnauthorisedError) { - name = jsonFieldsNameOfUnauthorisedError[fieldIdx] + if fieldIdx < len(jsonFieldsNameOfUserUsageGet) { + name = jsonFieldsNameOfUserUsageGet[fieldIdx] } else { name = strconv.Itoa(fieldIdx) } @@ -5851,87 +5901,103 @@ func (s *UnauthorisedError) Decode(d *jx.Decoder) error { } // MarshalJSON implements stdjson.Marshaler. -func (s *UnauthorisedError) MarshalJSON() ([]byte, error) { +func (s *UserUsageGet) MarshalJSON() ([]byte, error) { e := jx.Encoder{} s.Encode(&e) return e.Bytes(), nil } // UnmarshalJSON implements stdjson.Unmarshaler. -func (s *UnauthorisedError) UnmarshalJSON(data []byte) error { +func (s *UserUsageGet) UnmarshalJSON(data []byte) error { d := jx.DecodeBytes(data) return s.Decode(d) } // Encode implements json.Marshaler. -func (s *UnauthorisedErrorError) Encode(e *jx.Encoder) { +func (s *UserUsageGetCPU) Encode(e *jx.Encoder) { e.ObjStart() s.encodeFields(e) e.ObjEnd() } // encodeFields encodes fields. -func (s *UnauthorisedErrorError) encodeFields(e *jx.Encoder) { +func (s *UserUsageGetCPU) encodeFields(e *jx.Encoder) { { - e.FieldStart("code") - e.Int32(s.Code) + e.FieldStart("usage") + e.Float32(s.Usage) } { - e.FieldStart("message") - e.Str(s.Message) + e.FieldStart("cores") + e.Int(s.Cores) + } + { + e.FieldStart("threads") + e.Int(s.Threads) } } -var jsonFieldsNameOfUnauthorisedErrorError = [2]string{ - 0: "code", - 1: "message", +var jsonFieldsNameOfUserUsageGetCPU = [3]string{ + 0: "usage", + 1: "cores", + 2: "threads", } -// Decode decodes UnauthorisedErrorError from json. -func (s *UnauthorisedErrorError) Decode(d *jx.Decoder) error { +// Decode decodes UserUsageGetCPU from json. +func (s *UserUsageGetCPU) Decode(d *jx.Decoder) error { if s == nil { - return errors.New("invalid: unable to decode UnauthorisedErrorError to nil") + return errors.New("invalid: unable to decode UserUsageGetCPU to nil") } var requiredBitSet [1]uint8 - s.setDefaults() if err := d.ObjBytes(func(d *jx.Decoder, k []byte) error { switch string(k) { - case "code": + case "usage": requiredBitSet[0] |= 1 << 0 if err := func() error { - v, err := d.Int32() - s.Code = int32(v) + v, err := d.Float32() + s.Usage = float32(v) if err != nil { return err } return nil }(); err != nil { - return errors.Wrap(err, "decode field \"code\"") + return errors.Wrap(err, "decode field \"usage\"") } - case "message": + case "cores": requiredBitSet[0] |= 1 << 1 if err := func() error { - v, err := d.Str() - s.Message = string(v) + v, err := d.Int() + s.Cores = int(v) if err != nil { return err } return nil }(); err != nil { - return errors.Wrap(err, "decode field \"message\"") + return errors.Wrap(err, "decode field \"cores\"") + } + case "threads": + requiredBitSet[0] |= 1 << 2 + if err := func() error { + v, err := d.Int() + s.Threads = int(v) + if err != nil { + return err + } + return nil + }(); err != nil { + return errors.Wrap(err, "decode field \"threads\"") } default: - return errors.Errorf("unexpected field %q", k) + return d.Skip() } return nil }); err != nil { - return errors.Wrap(err, "decode UnauthorisedErrorError") + return errors.Wrap(err, "decode UserUsageGetCPU") } // Validate required fields. var failures []validate.FieldError for i, mask := range [1]uint8{ - 0b00000011, + 0b00000111, } { if result := (requiredBitSet[i] & mask) ^ mask; result != 0 { // Mask only required fields and check equality to mask using XOR. @@ -5943,8 +6009,8 @@ func (s *UnauthorisedErrorError) Decode(d *jx.Decoder) error { bitIdx := bits.TrailingZeros8(result) fieldIdx := i*8 + bitIdx var name string - if fieldIdx < len(jsonFieldsNameOfUnauthorisedErrorError) { - name = jsonFieldsNameOfUnauthorisedErrorError[fieldIdx] + if fieldIdx < len(jsonFieldsNameOfUserUsageGetCPU) { + name = jsonFieldsNameOfUserUsageGetCPU[fieldIdx] } else { name = strconv.Itoa(fieldIdx) } @@ -5965,119 +6031,86 @@ func (s *UnauthorisedErrorError) Decode(d *jx.Decoder) error { } // MarshalJSON implements stdjson.Marshaler. -func (s *UnauthorisedErrorError) MarshalJSON() ([]byte, error) { +func (s *UserUsageGetCPU) MarshalJSON() ([]byte, error) { e := jx.Encoder{} s.Encode(&e) return e.Bytes(), nil } // UnmarshalJSON implements stdjson.Unmarshaler. -func (s *UnauthorisedErrorError) UnmarshalJSON(data []byte) error { +func (s *UserUsageGetCPU) UnmarshalJSON(data []byte) error { d := jx.DecodeBytes(data) return s.Decode(d) } // Encode implements json.Marshaler. -func (s *UserGet) Encode(e *jx.Encoder) { +func (s *UserUsageGetDisk) Encode(e *jx.Encoder) { e.ObjStart() s.encodeFields(e) e.ObjEnd() } // encodeFields encodes fields. -func (s *UserGet) encodeFields(e *jx.Encoder) { - { - e.FieldStart("username") - e.Str(s.Username) - } - { - e.FieldStart("language") - s.Language.Encode(e) - } +func (s *UserUsageGetDisk) encodeFields(e *jx.Encoder) { { - e.FieldStart("dateCreated") - e.Int64(s.DateCreated) + e.FieldStart("used") + e.Int64(s.Used) } { - e.FieldStart("dateUpdated") - e.Int64(s.DateUpdated) + e.FieldStart("total") + e.Int64(s.Total) } } -var jsonFieldsNameOfUserGet = [4]string{ - 0: "username", - 1: "language", - 2: "dateCreated", - 3: "dateUpdated", +var jsonFieldsNameOfUserUsageGetDisk = [2]string{ + 0: "used", + 1: "total", } -// Decode decodes UserGet from json. -func (s *UserGet) Decode(d *jx.Decoder) error { +// Decode decodes UserUsageGetDisk from json. +func (s *UserUsageGetDisk) Decode(d *jx.Decoder) error { if s == nil { - return errors.New("invalid: unable to decode UserGet to nil") + return errors.New("invalid: unable to decode UserUsageGetDisk to nil") } var requiredBitSet [1]uint8 - s.setDefaults() if err := d.ObjBytes(func(d *jx.Decoder, k []byte) error { switch string(k) { - case "username": + case "used": requiredBitSet[0] |= 1 << 0 - if err := func() error { - v, err := d.Str() - s.Username = string(v) - if err != nil { - return err - } - return nil - }(); err != nil { - return errors.Wrap(err, "decode field \"username\"") - } - case "language": - requiredBitSet[0] |= 1 << 1 - if err := func() error { - if err := s.Language.Decode(d); err != nil { - return err - } - return nil - }(); err != nil { - return errors.Wrap(err, "decode field \"language\"") - } - case "dateCreated": - requiredBitSet[0] |= 1 << 2 if err := func() error { v, err := d.Int64() - s.DateCreated = int64(v) + s.Used = int64(v) if err != nil { return err } return nil }(); err != nil { - return errors.Wrap(err, "decode field \"dateCreated\"") + return errors.Wrap(err, "decode field \"used\"") } - case "dateUpdated": - requiredBitSet[0] |= 1 << 3 + case "total": + requiredBitSet[0] |= 1 << 1 if err := func() error { v, err := d.Int64() - s.DateUpdated = int64(v) + s.Total = int64(v) if err != nil { return err } return nil }(); err != nil { - return errors.Wrap(err, "decode field \"dateUpdated\"") + return errors.Wrap(err, "decode field \"total\"") } default: return d.Skip() } return nil }); err != nil { - return errors.Wrap(err, "decode UserGet") + return errors.Wrap(err, "decode UserUsageGetDisk") } // Validate required fields. var failures []validate.FieldError for i, mask := range [1]uint8{ - 0b00001111, + 0b00000011, } { if result := (requiredBitSet[i] & mask) ^ mask; result != 0 { // Mask only required fields and check equality to mask using XOR. @@ -6089,8 +6122,8 @@ func (s *UserGet) Decode(d *jx.Decoder) error { bitIdx := bits.TrailingZeros8(result) fieldIdx := i*8 + bitIdx var name string - if fieldIdx < len(jsonFieldsNameOfUserGet) { - name = jsonFieldsNameOfUserGet[fieldIdx] + if fieldIdx < len(jsonFieldsNameOfUserUsageGetDisk) { + name = jsonFieldsNameOfUserUsageGetDisk[fieldIdx] } else { name = strconv.Itoa(fieldIdx) } @@ -6111,188 +6144,127 @@ func (s *UserGet) Decode(d *jx.Decoder) error { } // MarshalJSON implements stdjson.Marshaler. -func (s *UserGet) MarshalJSON() ([]byte, error) { - e := jx.Encoder{} - s.Encode(&e) - return e.Bytes(), nil -} - -// UnmarshalJSON implements stdjson.Unmarshaler. -func (s *UserGet) UnmarshalJSON(data []byte) error { - d := jx.DecodeBytes(data) - return s.Decode(d) -} - -// Encode encodes UserGetLanguage as json. -func (s UserGetLanguage) Encode(e *jx.Encoder) { - e.Str(string(s)) -} - -// Decode decodes UserGetLanguage from json. -func (s *UserGetLanguage) Decode(d *jx.Decoder) error { - if s == nil { - return errors.New("invalid: unable to decode UserGetLanguage to nil") - } - v, err := d.StrBytes() - if err != nil { - return err - } - // Try to use constant string. - switch UserGetLanguage(v) { - case UserGetLanguageEn: - *s = UserGetLanguageEn - default: - *s = UserGetLanguage(v) - } - - return nil -} - -// MarshalJSON implements stdjson.Marshaler. -func (s UserGetLanguage) MarshalJSON() ([]byte, error) { +func (s *UserUsageGetDisk) MarshalJSON() ([]byte, error) { e := jx.Encoder{} s.Encode(&e) return e.Bytes(), nil } // UnmarshalJSON implements stdjson.Unmarshaler. -func (s *UserGetLanguage) UnmarshalJSON(data []byte) error { +func (s *UserUsageGetDisk) UnmarshalJSON(data []byte) error { d := jx.DecodeBytes(data) return s.Decode(d) } // Encode implements json.Marshaler. -func (s *UserPatch) Encode(e *jx.Encoder) { +func (s *UserUsageGetMemory) Encode(e *jx.Encoder) { e.ObjStart() s.encodeFields(e) e.ObjEnd() } // encodeFields encodes fields. -func (s *UserPatch) encodeFields(e *jx.Encoder) { - { - if s.Username.Set { - e.FieldStart("username") - s.Username.Encode(e) - } - } +func (s *UserUsageGetMemory) encodeFields(e *jx.Encoder) { { - if s.Password.Set { - e.FieldStart("password") - s.Password.Encode(e) - } + e.FieldStart("used") + e.Int64(s.Used) } { - if s.Language.Set { - e.FieldStart("language") - s.Language.Encode(e) - } + e.FieldStart("total") + e.Int64(s.Total) } } -var jsonFieldsNameOfUserPatch = [3]string{ - 0: "username", - 1: "password", - 2: "language", +var jsonFieldsNameOfUserUsageGetMemory = [2]string{ + 0: "used", + 1: "total", } -// Decode decodes UserPatch from json. -func (s *UserPatch) Decode(d *jx.Decoder) error { +// Decode decodes UserUsageGetMemory from json. +func (s *UserUsageGetMemory) Decode(d *jx.Decoder) error { if s == nil { - return errors.New("invalid: unable to decode UserPatch to nil") + return errors.New("invalid: unable to decode UserUsageGetMemory to nil") } - s.setDefaults() + var requiredBitSet [1]uint8 if err := d.ObjBytes(func(d *jx.Decoder, k []byte) error { switch string(k) { - case "username": - if err := func() error { - s.Username.Reset() - if err := s.Username.Decode(d); err != nil { - return err - } - return nil - }(); err != nil { - return errors.Wrap(err, "decode field \"username\"") - } - case "password": + case "used": + requiredBitSet[0] |= 1 << 0 if err := func() error { - s.Password.Reset() - if err := s.Password.Decode(d); err != nil { + v, err := d.Int64() + s.Used = int64(v) + if err != nil { return err } return nil }(); err != nil { - return errors.Wrap(err, "decode field \"password\"") + return errors.Wrap(err, "decode field \"used\"") } - case "language": + case "total": + requiredBitSet[0] |= 1 << 1 if err := func() error { - s.Language.Reset() - if err := s.Language.Decode(d); err != nil { + v, err := d.Int64() + s.Total = int64(v) + if err != nil { return err } return nil }(); err != nil { - return errors.Wrap(err, "decode field \"language\"") + return errors.Wrap(err, "decode field \"total\"") } default: return d.Skip() } return nil }); err != nil { - return errors.Wrap(err, "decode UserPatch") - } - - return nil -} - -// MarshalJSON implements stdjson.Marshaler. -func (s *UserPatch) MarshalJSON() ([]byte, error) { - e := jx.Encoder{} - s.Encode(&e) - return e.Bytes(), nil -} - -// UnmarshalJSON implements stdjson.Unmarshaler. -func (s *UserPatch) UnmarshalJSON(data []byte) error { - d := jx.DecodeBytes(data) - return s.Decode(d) -} - -// Encode encodes UserPatchLanguage as json. -func (s UserPatchLanguage) Encode(e *jx.Encoder) { - e.Str(string(s)) -} - -// Decode decodes UserPatchLanguage from json. -func (s *UserPatchLanguage) Decode(d *jx.Decoder) error { - if s == nil { - return errors.New("invalid: unable to decode UserPatchLanguage to nil") + return errors.Wrap(err, "decode UserUsageGetMemory") } - v, err := d.StrBytes() - if err != nil { - return err + // Validate required fields. + var failures []validate.FieldError + for i, mask := range [1]uint8{ + 0b00000011, + } { + 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(jsonFieldsNameOfUserUsageGetMemory) { + name = jsonFieldsNameOfUserUsageGetMemory[fieldIdx] + } else { + name = strconv.Itoa(fieldIdx) + } + failures = append(failures, validate.FieldError{ + Name: name, + Error: validate.ErrFieldRequired, + }) + // Reset bit. + result &^= 1 << bitIdx + } + } } - // Try to use constant string. - switch UserPatchLanguage(v) { - case UserPatchLanguageEn: - *s = UserPatchLanguageEn - default: - *s = UserPatchLanguage(v) + if len(failures) > 0 { + return &validate.Error{Fields: failures} } return nil } // MarshalJSON implements stdjson.Marshaler. -func (s UserPatchLanguage) MarshalJSON() ([]byte, error) { +func (s *UserUsageGetMemory) MarshalJSON() ([]byte, error) { e := jx.Encoder{} s.Encode(&e) return e.Bytes(), nil } // UnmarshalJSON implements stdjson.Unmarshaler. -func (s *UserPatchLanguage) UnmarshalJSON(data []byte) error { +func (s *UserUsageGetMemory) UnmarshalJSON(data []byte) error { d := jx.DecodeBytes(data) return s.Decode(d) } diff --git a/core/api/oas_parameters_gen.go b/core/api/oas_parameters_gen.go index 3c0e5242..fc79102e 100644 --- a/core/api/oas_parameters_gen.go +++ b/core/api/oas_parameters_gen.go @@ -314,13 +314,13 @@ func decodeGetEventPingParams(args [0]string, argsEscaped bool, r *http.Request) return params, nil } -// GetSettingsUsageParams is parameters of get-settings-usage operation. -type GetSettingsUsageParams struct { +// GetUserParams is parameters of get-user operation. +type GetUserParams struct { // Session token for authentication. MeSess string } -func unpackGetSettingsUsageParams(packed middleware.Parameters) (params GetSettingsUsageParams) { +func unpackGetUserParams(packed middleware.Parameters) (params GetUserParams) { { key := middleware.ParameterKey{ Name: "_me_sess", @@ -331,7 +331,7 @@ func unpackGetSettingsUsageParams(packed middleware.Parameters) (params GetSetti return params } -func decodeGetSettingsUsageParams(args [0]string, argsEscaped bool, r *http.Request) (params GetSettingsUsageParams, _ error) { +func decodeGetUserParams(args [0]string, argsEscaped bool, r *http.Request) (params GetUserParams, _ error) { c := uri.NewCookieDecoder(r) // Decode cookie: _me_sess. if err := func() error { @@ -370,13 +370,13 @@ func decodeGetSettingsUsageParams(args [0]string, argsEscaped bool, r *http.Requ return params, nil } -// GetUserParams is parameters of get-user operation. -type GetUserParams struct { +// GetUserUsageParams is parameters of get-user-usage operation. +type GetUserUsageParams struct { // Session token for authentication. MeSess string } -func unpackGetUserParams(packed middleware.Parameters) (params GetUserParams) { +func unpackGetUserUsageParams(packed middleware.Parameters) (params GetUserUsageParams) { { key := middleware.ParameterKey{ Name: "_me_sess", @@ -387,7 +387,7 @@ func unpackGetUserParams(packed middleware.Parameters) (params GetUserParams) { return params } -func decodeGetUserParams(args [0]string, argsEscaped bool, r *http.Request) (params GetUserParams, _ error) { +func decodeGetUserUsageParams(args [0]string, argsEscaped bool, r *http.Request) (params GetUserUsageParams, _ error) { c := uri.NewCookieDecoder(r) // Decode cookie: _me_sess. if err := func() error { @@ -11017,62 +11017,6 @@ func decodeGetWebsitesIDParams(args [1]string, argsEscaped bool, r *http.Request return params, nil } -// PatchSettingsUsageParams is parameters of patch-settings-usage operation. -type PatchSettingsUsageParams struct { - // Session token for authentication. - MeSess string -} - -func unpackPatchSettingsUsageParams(packed middleware.Parameters) (params PatchSettingsUsageParams) { - { - key := middleware.ParameterKey{ - Name: "_me_sess", - In: "cookie", - } - params.MeSess = packed[key].(string) - } - return params -} - -func decodePatchSettingsUsageParams(args [0]string, argsEscaped bool, r *http.Request) (params PatchSettingsUsageParams, _ error) { - c := uri.NewCookieDecoder(r) - // Decode cookie: _me_sess. - if err := func() error { - cfg := uri.CookieParameterDecodingConfig{ - Name: "_me_sess", - Explode: true, - } - if err := c.HasParam(cfg); err == nil { - if err := c.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.MeSess = c - return nil - }); err != nil { - return err - } - } else { - return validate.ErrFieldRequired - } - return nil - }(); err != nil { - return params, &ogenerrors.DecodeParamError{ - Name: "_me_sess", - In: "cookie", - Err: err, - } - } - return params, nil -} - // PatchUserParams is parameters of patch-user operation. type PatchUserParams struct { // Session token for authentication. diff --git a/core/api/oas_request_decoders_gen.go b/core/api/oas_request_decoders_gen.go index 5686a2f5..e95c0904 100644 --- a/core/api/oas_request_decoders_gen.go +++ b/core/api/oas_request_decoders_gen.go @@ -15,77 +15,6 @@ import ( "github.com/ogen-go/ogen/validate" ) -func (s *Server) decodePatchSettingsUsageRequest(r *http.Request) ( - req *SettingsUsagePatch, - 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 = multierr.Append(merr, c()) - } - return merr - } - defer func() { - if rerr != nil { - rerr = multierr.Append(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 SettingsUsagePatch - 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) decodePatchUserRequest(r *http.Request) ( req *UserPatch, close func() error, diff --git a/core/api/oas_response_encoders_gen.go b/core/api/oas_response_encoders_gen.go index 5a4d191c..8e0c8dd2 100644 --- a/core/api/oas_response_encoders_gen.go +++ b/core/api/oas_response_encoders_gen.go @@ -227,9 +227,9 @@ func encodeGetEventPingResponse(response GetEventPingRes, w http.ResponseWriter) } } -func encodeGetSettingsUsageResponse(response GetSettingsUsageRes, w http.ResponseWriter) error { +func encodeGetUserResponse(response GetUserRes, w http.ResponseWriter) error { switch response := response.(type) { - case *SettingsUsageGet: + case *UserGet: if err := func() error { if err := response.Validate(); err != nil { return err @@ -249,6 +249,18 @@ func encodeGetSettingsUsageResponse(response GetSettingsUsageRes, w http.Respons return nil + case *BadRequestError: + w.Header().Set("Content-Type", "application/json; charset=utf-8") + w.WriteHeader(400) + + e := new(jx.Encoder) + response.Encode(e) + if _, err := e.WriteTo(w); err != nil { + return errors.Wrap(err, "write") + } + + return nil + case *UnauthorisedError: w.Header().Set("Content-Type", "application/json; charset=utf-8") w.WriteHeader(401) @@ -261,6 +273,18 @@ func encodeGetSettingsUsageResponse(response GetSettingsUsageRes, w http.Respons return nil + case *NotFoundError: + w.Header().Set("Content-Type", "application/json; charset=utf-8") + w.WriteHeader(404) + + e := new(jx.Encoder) + response.Encode(e) + if _, err := e.WriteTo(w); err != nil { + return errors.Wrap(err, "write") + } + + return nil + case *InternalServerError: w.Header().Set("Content-Type", "application/json; charset=utf-8") w.WriteHeader(500) @@ -278,9 +302,9 @@ func encodeGetSettingsUsageResponse(response GetSettingsUsageRes, w http.Respons } } -func encodeGetUserResponse(response GetUserRes, w http.ResponseWriter) error { +func encodeGetUserUsageResponse(response GetUserUsageRes, w http.ResponseWriter) error { switch response := response.(type) { - case *UserGet: + case *UserUsageGet: if err := func() error { if err := response.Validate(); err != nil { return err @@ -300,18 +324,6 @@ func encodeGetUserResponse(response GetUserRes, w http.ResponseWriter) error { return nil - case *BadRequestError: - w.Header().Set("Content-Type", "application/json; charset=utf-8") - w.WriteHeader(400) - - e := new(jx.Encoder) - response.Encode(e) - if _, err := e.WriteTo(w); err != nil { - return errors.Wrap(err, "write") - } - - return nil - case *UnauthorisedError: w.Header().Set("Content-Type", "application/json; charset=utf-8") w.WriteHeader(401) @@ -324,18 +336,6 @@ func encodeGetUserResponse(response GetUserRes, w http.ResponseWriter) error { return nil - case *NotFoundError: - w.Header().Set("Content-Type", "application/json; charset=utf-8") - w.WriteHeader(404) - - e := new(jx.Encoder) - response.Encode(e) - if _, err := e.WriteTo(w); err != nil { - return errors.Wrap(err, "write") - } - - return nil - case *InternalServerError: w.Header().Set("Content-Type", "application/json; charset=utf-8") w.WriteHeader(500) @@ -1511,66 +1511,6 @@ func encodeGetWebsitesIDResponse(response GetWebsitesIDRes, w http.ResponseWrite } } -func encodePatchSettingsUsageResponse(response PatchSettingsUsageRes, w http.ResponseWriter) error { - switch response := response.(type) { - case *PatchSettingsUsageCreated: - w.WriteHeader(201) - - return nil - - case *BadRequestError: - w.Header().Set("Content-Type", "application/json; charset=utf-8") - w.WriteHeader(400) - - e := new(jx.Encoder) - response.Encode(e) - if _, err := e.WriteTo(w); err != nil { - return errors.Wrap(err, "write") - } - - return nil - - case *UnauthorisedError: - w.Header().Set("Content-Type", "application/json; charset=utf-8") - w.WriteHeader(401) - - e := new(jx.Encoder) - response.Encode(e) - if _, err := e.WriteTo(w); err != nil { - return errors.Wrap(err, "write") - } - - return nil - - case *ForbiddenError: - w.Header().Set("Content-Type", "application/json; charset=utf-8") - w.WriteHeader(403) - - e := new(jx.Encoder) - response.Encode(e) - if _, err := e.WriteTo(w); err != nil { - return errors.Wrap(err, "write") - } - - return nil - - case *InternalServerError: - w.Header().Set("Content-Type", "application/json; charset=utf-8") - w.WriteHeader(500) - - e := new(jx.Encoder) - response.Encode(e) - if _, err := e.WriteTo(w); err != nil { - return errors.Wrap(err, "write") - } - - return nil - - default: - return errors.Errorf("unexpected response type: %T", response) - } -} - func encodePatchUserResponse(response PatchUserRes, w http.ResponseWriter) error { switch response := response.(type) { case *UserGet: diff --git a/core/api/oas_router_gen.go b/core/api/oas_router_gen.go index 457c40a0..40fd8696 100644 --- a/core/api/oas_router_gen.go +++ b/core/api/oas_router_gen.go @@ -174,29 +174,6 @@ func (s *Server) ServeHTTP(w http.ResponseWriter, r *http.Request) { elem = origElem } - elem = origElem - case 's': // Prefix: "settings/usage" - origElem := elem - if l := len("settings/usage"); len(elem) >= l && elem[0:l] == "settings/usage" { - elem = elem[l:] - } else { - break - } - - if len(elem) == 0 { - // Leaf node. - switch r.Method { - case "GET": - s.handleGetSettingsUsageRequest([0]string{}, elemIsEscaped, w, r) - case "PATCH": - s.handlePatchSettingsUsageRequest([0]string{}, elemIsEscaped, w, r) - default: - s.notAllowed(w, r, "GET,PATCH") - } - - return - } - elem = origElem case 'u': // Prefix: "user" origElem := elem @@ -207,7 +184,6 @@ func (s *Server) ServeHTTP(w http.ResponseWriter, r *http.Request) { } if len(elem) == 0 { - // Leaf node. switch r.Method { case "DELETE": s.handleDeleteUserRequest([0]string{}, elemIsEscaped, w, r) @@ -221,6 +197,29 @@ func (s *Server) ServeHTTP(w http.ResponseWriter, r *http.Request) { return } + switch elem[0] { + case '/': // Prefix: "/usage" + origElem := elem + if l := len("/usage"); len(elem) >= l && elem[0:l] == "/usage" { + elem = elem[l:] + } else { + break + } + + if len(elem) == 0 { + // Leaf node. + switch r.Method { + case "GET": + s.handleGetUserUsageRequest([0]string{}, elemIsEscaped, w, r) + default: + s.notAllowed(w, r, "GET") + } + + return + } + + elem = origElem + } elem = origElem case 'w': // Prefix: "website" @@ -867,39 +866,6 @@ func (s *Server) FindPath(method string, u *url.URL) (r Route, _ bool) { elem = origElem } - elem = origElem - case 's': // Prefix: "settings/usage" - origElem := elem - if l := len("settings/usage"); len(elem) >= l && elem[0:l] == "settings/usage" { - elem = elem[l:] - } else { - break - } - - if len(elem) == 0 { - // Leaf node. - switch method { - case "GET": - r.name = "GetSettingsUsage" - r.summary = "Get Resource Usage" - r.operationID = "get-settings-usage" - r.pathPattern = "/settings/usage" - r.args = args - r.count = 0 - return r, true - case "PATCH": - r.name = "PatchSettingsUsage" - r.summary = "Update Resource Usage" - r.operationID = "patch-settings-usage" - r.pathPattern = "/settings/usage" - r.args = args - r.count = 0 - return r, true - default: - return - } - } - elem = origElem case 'u': // Prefix: "user" origElem := elem @@ -910,7 +876,6 @@ func (s *Server) FindPath(method string, u *url.URL) (r Route, _ bool) { } if len(elem) == 0 { - // Leaf node. switch method { case "DELETE": r.name = "DeleteUser" @@ -940,6 +905,33 @@ func (s *Server) FindPath(method string, u *url.URL) (r Route, _ bool) { return } } + switch elem[0] { + case '/': // Prefix: "/usage" + origElem := elem + if l := len("/usage"); len(elem) >= l && elem[0:l] == "/usage" { + elem = elem[l:] + } else { + break + } + + if len(elem) == 0 { + // Leaf node. + switch method { + case "GET": + r.name = "GetUserUsage" + r.summary = "Get Resource Usage" + r.operationID = "get-user-usage" + r.pathPattern = "/user/usage" + r.args = args + r.count = 0 + return r, true + default: + return + } + } + + elem = origElem + } elem = origElem case 'w': // Prefix: "website" diff --git a/core/api/oas_schemas_gen.go b/core/api/oas_schemas_gen.go index 731ab082..c29a62ed 100644 --- a/core/api/oas_schemas_gen.go +++ b/core/api/oas_schemas_gen.go @@ -69,7 +69,6 @@ func (*BadRequestError) getWebsiteIDSummaryRes() {} func (*BadRequestError) getWebsiteIDTimeRes() {} func (*BadRequestError) getWebsitesIDRes() {} func (*BadRequestError) getWebsitesRes() {} -func (*BadRequestError) patchSettingsUsageRes() {} func (*BadRequestError) patchUserRes() {} func (*BadRequestError) patchWebsitesIDRes() {} func (*BadRequestError) postAuthLoginRes() {} @@ -170,7 +169,7 @@ func (*DeleteWebsitesIDNoContent) deleteWebsitesIDRes() {} // Event with custom properties. // Ref: #/components/schemas/EventCustom type EventCustom struct { - // Beacon ID generated for each user to link multiple events on the same page together. + // Optional Beacon ID generated for each user to link multiple events on the same page together. B OptString `json:"b"` // Group name of events. Currently, only the hostname is supported. G string `json:"g"` @@ -657,7 +656,6 @@ func (*ForbiddenError) getWebsiteIDMediumsRes() {} func (*ForbiddenError) getWebsiteIDOsRes() {} func (*ForbiddenError) getWebsiteIDReferrersRes() {} func (*ForbiddenError) getWebsiteIDSourcesRes() {} -func (*ForbiddenError) patchSettingsUsageRes() {} func (*ForbiddenError) patchUserRes() {} func (*ForbiddenError) patchWebsitesIDRes() {} func (*ForbiddenError) postWebsitesRes() {} @@ -824,8 +822,8 @@ func (s *InternalServerError) SetError(val InternalServerErrorError) { func (*InternalServerError) deleteUserRes() {} func (*InternalServerError) deleteWebsitesIDRes() {} func (*InternalServerError) getEventPingRes() {} -func (*InternalServerError) getSettingsUsageRes() {} func (*InternalServerError) getUserRes() {} +func (*InternalServerError) getUserUsageRes() {} func (*InternalServerError) getWebsiteIDBrowsersRes() {} func (*InternalServerError) getWebsiteIDCampaignsRes() {} func (*InternalServerError) getWebsiteIDCountryRes() {} @@ -840,7 +838,6 @@ func (*InternalServerError) getWebsiteIDSummaryRes() {} func (*InternalServerError) getWebsiteIDTimeRes() {} func (*InternalServerError) getWebsitesIDRes() {} func (*InternalServerError) getWebsitesRes() {} -func (*InternalServerError) patchSettingsUsageRes() {} func (*InternalServerError) patchUserRes() {} func (*InternalServerError) patchWebsitesIDRes() {} func (*InternalServerError) postAuthLoginRes() {} @@ -1301,38 +1298,130 @@ func (o OptString) Or(d string) string { return d } -// NewOptUserPatchLanguage returns new OptUserPatchLanguage with value set to v. -func NewOptUserPatchLanguage(v UserPatchLanguage) OptUserPatchLanguage { - return OptUserPatchLanguage{ +// NewOptUserSettings returns new OptUserSettings with value set to v. +func NewOptUserSettings(v UserSettings) OptUserSettings { + return OptUserSettings{ + Value: v, + Set: true, + } +} + +// OptUserSettings is optional UserSettings. +type OptUserSettings struct { + Value UserSettings + Set bool +} + +// IsSet returns true if OptUserSettings was set. +func (o OptUserSettings) IsSet() bool { return o.Set } + +// Reset unsets value. +func (o *OptUserSettings) Reset() { + var v UserSettings + o.Value = v + o.Set = false +} + +// SetTo sets value to v. +func (o *OptUserSettings) SetTo(v UserSettings) { + o.Set = true + o.Value = v +} + +// Get returns value and boolean that denotes whether value was set. +func (o OptUserSettings) Get() (v UserSettings, 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 OptUserSettings) Or(d UserSettings) UserSettings { + if v, ok := o.Get(); ok { + return v + } + return d +} + +// NewOptUserSettingsLanguage returns new OptUserSettingsLanguage with value set to v. +func NewOptUserSettingsLanguage(v UserSettingsLanguage) OptUserSettingsLanguage { + return OptUserSettingsLanguage{ + Value: v, + Set: true, + } +} + +// OptUserSettingsLanguage is optional UserSettingsLanguage. +type OptUserSettingsLanguage struct { + Value UserSettingsLanguage + Set bool +} + +// IsSet returns true if OptUserSettingsLanguage was set. +func (o OptUserSettingsLanguage) IsSet() bool { return o.Set } + +// Reset unsets value. +func (o *OptUserSettingsLanguage) Reset() { + var v UserSettingsLanguage + o.Value = v + o.Set = false +} + +// SetTo sets value to v. +func (o *OptUserSettingsLanguage) SetTo(v UserSettingsLanguage) { + o.Set = true + o.Value = v +} + +// Get returns value and boolean that denotes whether value was set. +func (o OptUserSettingsLanguage) Get() (v UserSettingsLanguage, 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 OptUserSettingsLanguage) Or(d UserSettingsLanguage) UserSettingsLanguage { + if v, ok := o.Get(); ok { + return v + } + return d +} + +// NewOptUserSettingsScriptType returns new OptUserSettingsScriptType with value set to v. +func NewOptUserSettingsScriptType(v UserSettingsScriptType) OptUserSettingsScriptType { + return OptUserSettingsScriptType{ Value: v, Set: true, } } -// OptUserPatchLanguage is optional UserPatchLanguage. -type OptUserPatchLanguage struct { - Value UserPatchLanguage +// OptUserSettingsScriptType is optional UserSettingsScriptType. +type OptUserSettingsScriptType struct { + Value UserSettingsScriptType Set bool } -// IsSet returns true if OptUserPatchLanguage was set. -func (o OptUserPatchLanguage) IsSet() bool { return o.Set } +// IsSet returns true if OptUserSettingsScriptType was set. +func (o OptUserSettingsScriptType) IsSet() bool { return o.Set } // Reset unsets value. -func (o *OptUserPatchLanguage) Reset() { - var v UserPatchLanguage +func (o *OptUserSettingsScriptType) Reset() { + var v UserSettingsScriptType o.Value = v o.Set = false } // SetTo sets value to v. -func (o *OptUserPatchLanguage) SetTo(v UserPatchLanguage) { +func (o *OptUserSettingsScriptType) SetTo(v UserSettingsScriptType) { o.Set = true o.Value = v } // Get returns value and boolean that denotes whether value was set. -func (o OptUserPatchLanguage) Get() (v UserPatchLanguage, ok bool) { +func (o OptUserSettingsScriptType) Get() (v UserSettingsScriptType, ok bool) { if !o.Set { return v, false } @@ -1340,7 +1429,7 @@ func (o OptUserPatchLanguage) Get() (v UserPatchLanguage, ok bool) { } // Or returns value if set, or given parameter if does not. -func (o OptUserPatchLanguage) Or(d UserPatchLanguage) UserPatchLanguage { +func (o OptUserSettingsScriptType) Or(d UserSettingsScriptType) UserSettingsScriptType { if v, ok := o.Get(); ok { return v } @@ -1393,11 +1482,6 @@ func (o OptWebsiteGetSummary) Or(d WebsiteGetSummary) WebsiteGetSummary { return d } -// PatchSettingsUsageCreated is response for PatchSettingsUsage operation. -type PatchSettingsUsageCreated struct{} - -func (*PatchSettingsUsageCreated) patchSettingsUsageRes() {} - // PostAuthLoginOK is response for PostAuthLogin operation. type PostAuthLoginOK struct { SetCookie string @@ -1437,195 +1521,6 @@ type PostEventHitNoContent struct{} func (*PostEventHitNoContent) postEventHitRes() {} -// Response body for getting CPU, memory and disk usage of the server. -// Ref: #/components/schemas/SettingsUsageGet -type SettingsUsageGet struct { - CPU SettingsUsageGetCPU `json:"cpu"` - Memory SettingsUsageGetMemory `json:"memory"` - Disk SettingsUsageGetDisk `json:"disk"` - Metadata SettingsUsageGetMetadata `json:"metadata"` -} - -// GetCPU returns the value of CPU. -func (s *SettingsUsageGet) GetCPU() SettingsUsageGetCPU { - return s.CPU -} - -// GetMemory returns the value of Memory. -func (s *SettingsUsageGet) GetMemory() SettingsUsageGetMemory { - return s.Memory -} - -// GetDisk returns the value of Disk. -func (s *SettingsUsageGet) GetDisk() SettingsUsageGetDisk { - return s.Disk -} - -// GetMetadata returns the value of Metadata. -func (s *SettingsUsageGet) GetMetadata() SettingsUsageGetMetadata { - return s.Metadata -} - -// SetCPU sets the value of CPU. -func (s *SettingsUsageGet) SetCPU(val SettingsUsageGetCPU) { - s.CPU = val -} - -// SetMemory sets the value of Memory. -func (s *SettingsUsageGet) SetMemory(val SettingsUsageGetMemory) { - s.Memory = val -} - -// SetDisk sets the value of Disk. -func (s *SettingsUsageGet) SetDisk(val SettingsUsageGetDisk) { - s.Disk = val -} - -// SetMetadata sets the value of Metadata. -func (s *SettingsUsageGet) SetMetadata(val SettingsUsageGetMetadata) { - s.Metadata = val -} - -func (*SettingsUsageGet) getSettingsUsageRes() {} - -type SettingsUsageGetCPU struct { - Usage float32 `json:"usage"` - Cores int `json:"cores"` - Threads int `json:"threads"` -} - -// GetUsage returns the value of Usage. -func (s *SettingsUsageGetCPU) GetUsage() float32 { - return s.Usage -} - -// GetCores returns the value of Cores. -func (s *SettingsUsageGetCPU) GetCores() int { - return s.Cores -} - -// GetThreads returns the value of Threads. -func (s *SettingsUsageGetCPU) GetThreads() int { - return s.Threads -} - -// SetUsage sets the value of Usage. -func (s *SettingsUsageGetCPU) SetUsage(val float32) { - s.Usage = val -} - -// SetCores sets the value of Cores. -func (s *SettingsUsageGetCPU) SetCores(val int) { - s.Cores = val -} - -// SetThreads sets the value of Threads. -func (s *SettingsUsageGetCPU) SetThreads(val int) { - s.Threads = val -} - -type SettingsUsageGetDisk struct { - Used int64 `json:"used"` - Total int64 `json:"total"` -} - -// GetUsed returns the value of Used. -func (s *SettingsUsageGetDisk) GetUsed() int64 { - return s.Used -} - -// GetTotal returns the value of Total. -func (s *SettingsUsageGetDisk) GetTotal() int64 { - return s.Total -} - -// SetUsed sets the value of Used. -func (s *SettingsUsageGetDisk) SetUsed(val int64) { - s.Used = val -} - -// SetTotal sets the value of Total. -func (s *SettingsUsageGetDisk) SetTotal(val int64) { - s.Total = val -} - -type SettingsUsageGetMemory struct { - Used int64 `json:"used"` - Total int64 `json:"total"` -} - -// GetUsed returns the value of Used. -func (s *SettingsUsageGetMemory) GetUsed() int64 { - return s.Used -} - -// GetTotal returns the value of Total. -func (s *SettingsUsageGetMemory) GetTotal() int64 { - return s.Total -} - -// SetUsed sets the value of Used. -func (s *SettingsUsageGetMemory) SetUsed(val int64) { - s.Used = val -} - -// SetTotal sets the value of Total. -func (s *SettingsUsageGetMemory) SetTotal(val int64) { - s.Total = val -} - -type SettingsUsageGetMetadata struct { - Threads OptInt `json:"threads"` - MemoryLimit OptString `json:"memory_limit"` -} - -// GetThreads returns the value of Threads. -func (s *SettingsUsageGetMetadata) GetThreads() OptInt { - return s.Threads -} - -// GetMemoryLimit returns the value of MemoryLimit. -func (s *SettingsUsageGetMetadata) GetMemoryLimit() OptString { - return s.MemoryLimit -} - -// SetThreads sets the value of Threads. -func (s *SettingsUsageGetMetadata) SetThreads(val OptInt) { - s.Threads = val -} - -// SetMemoryLimit sets the value of MemoryLimit. -func (s *SettingsUsageGetMetadata) SetMemoryLimit(val OptString) { - s.MemoryLimit = val -} - -// Request body for updating the resource limits of the application. -// Ref: #/components/schemas/SettingsUsagePatch -type SettingsUsagePatch struct { - Threads OptInt `json:"threads"` - MemoryLimit OptString `json:"memory_limit"` -} - -// GetThreads returns the value of Threads. -func (s *SettingsUsagePatch) GetThreads() OptInt { - return s.Threads -} - -// GetMemoryLimit returns the value of MemoryLimit. -func (s *SettingsUsagePatch) GetMemoryLimit() OptString { - return s.MemoryLimit -} - -// SetThreads sets the value of Threads. -func (s *SettingsUsagePatch) SetThreads(val OptInt) { - s.Threads = val -} - -// SetMemoryLimit sets the value of MemoryLimit. -func (s *SettingsUsagePatch) SetMemoryLimit(val OptString) { - s.MemoryLimit = val -} - type StatsBrowsers []StatsBrowsersItem func (*StatsBrowsers) getWebsiteIDBrowsersRes() {} @@ -2606,8 +2501,8 @@ func (s *UnauthorisedError) SetError(val UnauthorisedErrorError) { func (*UnauthorisedError) deleteUserRes() {} func (*UnauthorisedError) deleteWebsitesIDRes() {} -func (*UnauthorisedError) getSettingsUsageRes() {} func (*UnauthorisedError) getUserRes() {} +func (*UnauthorisedError) getUserUsageRes() {} func (*UnauthorisedError) getWebsiteIDBrowsersRes() {} func (*UnauthorisedError) getWebsiteIDCampaignsRes() {} func (*UnauthorisedError) getWebsiteIDCountryRes() {} @@ -2622,7 +2517,6 @@ func (*UnauthorisedError) getWebsiteIDSummaryRes() {} func (*UnauthorisedError) getWebsiteIDTimeRes() {} func (*UnauthorisedError) getWebsitesIDRes() {} func (*UnauthorisedError) getWebsitesRes() {} -func (*UnauthorisedError) patchSettingsUsageRes() {} func (*UnauthorisedError) patchUserRes() {} func (*UnauthorisedError) patchWebsitesIDRes() {} func (*UnauthorisedError) postAuthLoginRes() {} @@ -2657,10 +2551,10 @@ func (s *UnauthorisedErrorError) SetMessage(val string) { // Response body for getting a user. // Ref: #/components/schemas/UserGet type UserGet struct { - Username string `json:"username"` - Language UserGetLanguage `json:"language"` - DateCreated int64 `json:"dateCreated"` - DateUpdated int64 `json:"dateUpdated"` + Username string `json:"username"` + Settings UserSettings `json:"settings"` + DateCreated int64 `json:"dateCreated"` + DateUpdated int64 `json:"dateUpdated"` } // GetUsername returns the value of Username. @@ -2668,9 +2562,9 @@ func (s *UserGet) GetUsername() string { return s.Username } -// GetLanguage returns the value of Language. -func (s *UserGet) GetLanguage() UserGetLanguage { - return s.Language +// GetSettings returns the value of Settings. +func (s *UserGet) GetSettings() UserSettings { + return s.Settings } // GetDateCreated returns the value of DateCreated. @@ -2688,9 +2582,9 @@ func (s *UserGet) SetUsername(val string) { s.Username = val } -// SetLanguage sets the value of Language. -func (s *UserGet) SetLanguage(val UserGetLanguage) { - s.Language = val +// SetSettings sets the value of Settings. +func (s *UserGet) SetSettings(val UserSettings) { + s.Settings = val } // SetDateCreated sets the value of DateCreated. @@ -2706,46 +2600,12 @@ func (s *UserGet) SetDateUpdated(val int64) { func (*UserGet) getUserRes() {} func (*UserGet) patchUserRes() {} -type UserGetLanguage string - -const ( - UserGetLanguageEn UserGetLanguage = "en" -) - -// AllValues returns all UserGetLanguage values. -func (UserGetLanguage) AllValues() []UserGetLanguage { - return []UserGetLanguage{ - UserGetLanguageEn, - } -} - -// MarshalText implements encoding.TextMarshaler. -func (s UserGetLanguage) MarshalText() ([]byte, error) { - switch s { - case UserGetLanguageEn: - return []byte(s), nil - default: - return nil, errors.Errorf("invalid value: %q", s) - } -} - -// UnmarshalText implements encoding.TextUnmarshaler. -func (s *UserGetLanguage) UnmarshalText(data []byte) error { - switch UserGetLanguage(data) { - case UserGetLanguageEn: - *s = UserGetLanguageEn - return nil - default: - return errors.Errorf("invalid value: %q", data) - } -} - // Request body for updating a user. // Ref: #/components/schemas/UserPatch type UserPatch struct { - Username OptString `json:"username"` - Password OptString `json:"password"` - Language OptUserPatchLanguage `json:"language"` + Username OptString `json:"username"` + Password OptString `json:"password"` + Settings OptUserSettings `json:"settings"` } // GetUsername returns the value of Username. @@ -2758,9 +2618,9 @@ func (s *UserPatch) GetPassword() OptString { return s.Password } -// GetLanguage returns the value of Language. -func (s *UserPatch) GetLanguage() OptUserPatchLanguage { - return s.Language +// GetSettings returns the value of Settings. +func (s *UserPatch) GetSettings() OptUserSettings { + return s.Settings } // SetUsername sets the value of Username. @@ -2773,28 +2633,55 @@ func (s *UserPatch) SetPassword(val OptString) { s.Password = val } +// SetSettings sets the value of Settings. +func (s *UserPatch) SetSettings(val OptUserSettings) { + s.Settings = val +} + +// Response body for getting user settings. +// Ref: #/components/schemas/UserSettings +type UserSettings struct { + Language OptUserSettingsLanguage `json:"language"` + ScriptType OptUserSettingsScriptType `json:"script_type"` +} + +// GetLanguage returns the value of Language. +func (s *UserSettings) GetLanguage() OptUserSettingsLanguage { + return s.Language +} + +// GetScriptType returns the value of ScriptType. +func (s *UserSettings) GetScriptType() OptUserSettingsScriptType { + return s.ScriptType +} + // SetLanguage sets the value of Language. -func (s *UserPatch) SetLanguage(val OptUserPatchLanguage) { +func (s *UserSettings) SetLanguage(val OptUserSettingsLanguage) { s.Language = val } -type UserPatchLanguage string +// SetScriptType sets the value of ScriptType. +func (s *UserSettings) SetScriptType(val OptUserSettingsScriptType) { + s.ScriptType = val +} + +type UserSettingsLanguage string const ( - UserPatchLanguageEn UserPatchLanguage = "en" + UserSettingsLanguageEn UserSettingsLanguage = "en" ) -// AllValues returns all UserPatchLanguage values. -func (UserPatchLanguage) AllValues() []UserPatchLanguage { - return []UserPatchLanguage{ - UserPatchLanguageEn, +// AllValues returns all UserSettingsLanguage values. +func (UserSettingsLanguage) AllValues() []UserSettingsLanguage { + return []UserSettingsLanguage{ + UserSettingsLanguageEn, } } // MarshalText implements encoding.TextMarshaler. -func (s UserPatchLanguage) MarshalText() ([]byte, error) { +func (s UserSettingsLanguage) MarshalText() ([]byte, error) { switch s { - case UserPatchLanguageEn: + case UserSettingsLanguageEn: return []byte(s), nil default: return nil, errors.Errorf("invalid value: %q", s) @@ -2802,16 +2689,183 @@ func (s UserPatchLanguage) MarshalText() ([]byte, error) { } // UnmarshalText implements encoding.TextUnmarshaler. -func (s *UserPatchLanguage) UnmarshalText(data []byte) error { - switch UserPatchLanguage(data) { - case UserPatchLanguageEn: - *s = UserPatchLanguageEn +func (s *UserSettingsLanguage) UnmarshalText(data []byte) error { + switch UserSettingsLanguage(data) { + case UserSettingsLanguageEn: + *s = UserSettingsLanguageEn return nil default: return errors.Errorf("invalid value: %q", data) } } +type UserSettingsScriptType string + +const ( + UserSettingsScriptTypeDefault UserSettingsScriptType = "default" + UserSettingsScriptTypeTaggedEvents UserSettingsScriptType = "tagged-events" +) + +// AllValues returns all UserSettingsScriptType values. +func (UserSettingsScriptType) AllValues() []UserSettingsScriptType { + return []UserSettingsScriptType{ + UserSettingsScriptTypeDefault, + UserSettingsScriptTypeTaggedEvents, + } +} + +// MarshalText implements encoding.TextMarshaler. +func (s UserSettingsScriptType) MarshalText() ([]byte, error) { + switch s { + case UserSettingsScriptTypeDefault: + return []byte(s), nil + case UserSettingsScriptTypeTaggedEvents: + return []byte(s), nil + default: + return nil, errors.Errorf("invalid value: %q", s) + } +} + +// UnmarshalText implements encoding.TextUnmarshaler. +func (s *UserSettingsScriptType) UnmarshalText(data []byte) error { + switch UserSettingsScriptType(data) { + case UserSettingsScriptTypeDefault: + *s = UserSettingsScriptTypeDefault + return nil + case UserSettingsScriptTypeTaggedEvents: + *s = UserSettingsScriptTypeTaggedEvents + return nil + default: + return errors.Errorf("invalid value: %q", data) + } +} + +// Response body for getting CPU, memory and disk usage of the server. +// Ref: #/components/schemas/UserUsageGet +type UserUsageGet struct { + CPU UserUsageGetCPU `json:"cpu"` + Memory UserUsageGetMemory `json:"memory"` + Disk UserUsageGetDisk `json:"disk"` +} + +// GetCPU returns the value of CPU. +func (s *UserUsageGet) GetCPU() UserUsageGetCPU { + return s.CPU +} + +// GetMemory returns the value of Memory. +func (s *UserUsageGet) GetMemory() UserUsageGetMemory { + return s.Memory +} + +// GetDisk returns the value of Disk. +func (s *UserUsageGet) GetDisk() UserUsageGetDisk { + return s.Disk +} + +// SetCPU sets the value of CPU. +func (s *UserUsageGet) SetCPU(val UserUsageGetCPU) { + s.CPU = val +} + +// SetMemory sets the value of Memory. +func (s *UserUsageGet) SetMemory(val UserUsageGetMemory) { + s.Memory = val +} + +// SetDisk sets the value of Disk. +func (s *UserUsageGet) SetDisk(val UserUsageGetDisk) { + s.Disk = val +} + +func (*UserUsageGet) getUserUsageRes() {} + +type UserUsageGetCPU struct { + Usage float32 `json:"usage"` + Cores int `json:"cores"` + Threads int `json:"threads"` +} + +// GetUsage returns the value of Usage. +func (s *UserUsageGetCPU) GetUsage() float32 { + return s.Usage +} + +// GetCores returns the value of Cores. +func (s *UserUsageGetCPU) GetCores() int { + return s.Cores +} + +// GetThreads returns the value of Threads. +func (s *UserUsageGetCPU) GetThreads() int { + return s.Threads +} + +// SetUsage sets the value of Usage. +func (s *UserUsageGetCPU) SetUsage(val float32) { + s.Usage = val +} + +// SetCores sets the value of Cores. +func (s *UserUsageGetCPU) SetCores(val int) { + s.Cores = val +} + +// SetThreads sets the value of Threads. +func (s *UserUsageGetCPU) SetThreads(val int) { + s.Threads = val +} + +type UserUsageGetDisk struct { + Used int64 `json:"used"` + Total int64 `json:"total"` +} + +// GetUsed returns the value of Used. +func (s *UserUsageGetDisk) GetUsed() int64 { + return s.Used +} + +// GetTotal returns the value of Total. +func (s *UserUsageGetDisk) GetTotal() int64 { + return s.Total +} + +// SetUsed sets the value of Used. +func (s *UserUsageGetDisk) SetUsed(val int64) { + s.Used = val +} + +// SetTotal sets the value of Total. +func (s *UserUsageGetDisk) SetTotal(val int64) { + s.Total = val +} + +type UserUsageGetMemory struct { + Used int64 `json:"used"` + Total int64 `json:"total"` +} + +// GetUsed returns the value of Used. +func (s *UserUsageGetMemory) GetUsed() int64 { + return s.Used +} + +// GetTotal returns the value of Total. +func (s *UserUsageGetMemory) GetTotal() int64 { + return s.Total +} + +// SetUsed sets the value of Used. +func (s *UserUsageGetMemory) SetUsed(val int64) { + s.Used = val +} + +// SetTotal sets the value of Total. +func (s *UserUsageGetMemory) SetTotal(val int64) { + s.Total = val +} + // Request body for creating a website. // Ref: #/components/schemas/WebsiteCreate type WebsiteCreate struct { diff --git a/core/api/oas_server_gen.go b/core/api/oas_server_gen.go index 41b84a85..de7fc6d6 100644 --- a/core/api/oas_server_gen.go +++ b/core/api/oas_server_gen.go @@ -26,18 +26,18 @@ type Handler interface { // // GET /event/ping GetEventPing(ctx context.Context, params GetEventPingParams) (GetEventPingRes, error) - // GetSettingsUsage implements get-settings-usage operation. - // - // Get the current CPU, memory and disk usage of the server. - // - // GET /settings/usage - GetSettingsUsage(ctx context.Context, params GetSettingsUsageParams) (GetSettingsUsageRes, error) // GetUser implements get-user operation. // // Retrieve the information of the user with the matching user ID. // // GET /user GetUser(ctx context.Context, params GetUserParams) (GetUserRes, error) + // GetUserUsage implements get-user-usage operation. + // + // Get the current CPU, memory and disk usage of the server. + // + // GET /user/usage + GetUserUsage(ctx context.Context, params GetUserUsageParams) (GetUserUsageRes, error) // GetWebsiteIDBrowsers implements get-website-id-browsers operation. // // Get a list of browsers and their stats. @@ -122,12 +122,6 @@ type Handler interface { // // GET /websites/{hostname} GetWebsitesID(ctx context.Context, params GetWebsitesIDParams) (GetWebsitesIDRes, error) - // PatchSettingsUsage implements patch-settings-usage operation. - // - // Update the resource usage settings of the server. - // - // PATCH /settings/usage - PatchSettingsUsage(ctx context.Context, req *SettingsUsagePatch, params PatchSettingsUsageParams) (PatchSettingsUsageRes, error) // PatchUser implements patch-user operation. // // Update a user account's details. diff --git a/core/api/oas_validators_gen.go b/core/api/oas_validators_gen.go index 960f6c4e..9a96aed7 100644 --- a/core/api/oas_validators_gen.go +++ b/core/api/oas_validators_gen.go @@ -150,117 +150,6 @@ func (s GetWebsitesOKApplicationJSON) Validate() error { return nil } -func (s *SettingsUsageGet) Validate() error { - if s == nil { - return validate.ErrNilPointer - } - - var failures []validate.FieldError - if err := func() error { - if err := s.CPU.Validate(); err != nil { - return err - } - return nil - }(); err != nil { - failures = append(failures, validate.FieldError{ - Name: "cpu", - Error: err, - }) - } - if len(failures) > 0 { - return &validate.Error{Fields: failures} - } - return nil -} - -func (s *SettingsUsageGetCPU) Validate() error { - if s == nil { - return validate.ErrNilPointer - } - - var failures []validate.FieldError - if err := func() error { - if err := (validate.Float{}).Validate(float64(s.Usage)); err != nil { - return errors.Wrap(err, "float") - } - return nil - }(); err != nil { - failures = append(failures, validate.FieldError{ - Name: "usage", - Error: err, - }) - } - if len(failures) > 0 { - return &validate.Error{Fields: failures} - } - return nil -} - -func (s *SettingsUsagePatch) Validate() error { - if s == nil { - return validate.ErrNilPointer - } - - var failures []validate.FieldError - if err := func() error { - if value, ok := s.Threads.Get(); ok { - if err := func() error { - if err := (validate.Int{ - MinSet: true, - Min: 1, - MaxSet: false, - Max: 0, - MinExclusive: false, - MaxExclusive: false, - MultipleOfSet: false, - MultipleOf: 0, - }).Validate(int64(value)); err != nil { - return errors.Wrap(err, "int") - } - return nil - }(); err != nil { - return err - } - } - return nil - }(); err != nil { - failures = append(failures, validate.FieldError{ - Name: "threads", - Error: err, - }) - } - if err := func() error { - if value, ok := s.MemoryLimit.Get(); ok { - if err := func() error { - if err := (validate.String{ - MinLength: 1, - MinLengthSet: true, - MaxLength: 0, - MaxLengthSet: false, - 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: "memory_limit", - Error: err, - }) - } - if len(failures) > 0 { - return &validate.Error{Fields: failures} - } - return nil -} - func (s StatsBrowsers) Validate() error { alias := ([]StatsBrowsersItem)(s) if alias == nil { @@ -1155,13 +1044,13 @@ func (s *UserGet) Validate() error { }) } if err := func() error { - if err := s.Language.Validate(); err != nil { + if err := s.Settings.Validate(); err != nil { return err } return nil }(); err != nil { failures = append(failures, validate.FieldError{ - Name: "language", + Name: "settings", Error: err, }) } @@ -1171,15 +1060,6 @@ func (s *UserGet) Validate() error { return nil } -func (s UserGetLanguage) Validate() error { - switch s { - case "en": - return nil - default: - return errors.Errorf("invalid value: %v", s) - } -} - func (s *UserPatch) Validate() error { if s == nil { return validate.ErrNilPointer @@ -1238,6 +1118,36 @@ func (s *UserPatch) Validate() error { Error: err, }) } + if err := func() error { + if value, ok := s.Settings.Get(); ok { + if err := func() error { + if err := value.Validate(); err != nil { + return err + } + return nil + }(); err != nil { + return err + } + } + return nil + }(); err != nil { + failures = append(failures, validate.FieldError{ + Name: "settings", + Error: err, + }) + } + if len(failures) > 0 { + return &validate.Error{Fields: failures} + } + return nil +} + +func (s *UserSettings) Validate() error { + if s == nil { + return validate.ErrNilPointer + } + + var failures []validate.FieldError if err := func() error { if value, ok := s.Language.Get(); ok { if err := func() error { @@ -1256,13 +1166,31 @@ func (s *UserPatch) Validate() error { Error: err, }) } + if err := func() error { + if value, ok := s.ScriptType.Get(); ok { + if err := func() error { + if err := value.Validate(); err != nil { + return err + } + return nil + }(); err != nil { + return err + } + } + return nil + }(); err != nil { + failures = append(failures, validate.FieldError{ + Name: "script_type", + Error: err, + }) + } if len(failures) > 0 { return &validate.Error{Fields: failures} } return nil } -func (s UserPatchLanguage) Validate() error { +func (s UserSettingsLanguage) Validate() error { switch s { case "en": return nil @@ -1271,6 +1199,63 @@ func (s UserPatchLanguage) Validate() error { } } +func (s UserSettingsScriptType) Validate() error { + switch s { + case "default": + return nil + case "tagged-events": + return nil + default: + return errors.Errorf("invalid value: %v", s) + } +} + +func (s *UserUsageGet) Validate() error { + if s == nil { + return validate.ErrNilPointer + } + + var failures []validate.FieldError + if err := func() error { + if err := s.CPU.Validate(); err != nil { + return err + } + return nil + }(); err != nil { + failures = append(failures, validate.FieldError{ + Name: "cpu", + Error: err, + }) + } + if len(failures) > 0 { + return &validate.Error{Fields: failures} + } + return nil +} + +func (s *UserUsageGetCPU) Validate() error { + if s == nil { + return validate.ErrNilPointer + } + + var failures []validate.FieldError + if err := func() error { + if err := (validate.Float{}).Validate(float64(s.Usage)); err != nil { + return errors.Wrap(err, "float") + } + return nil + }(); err != nil { + failures = append(failures, validate.FieldError{ + Name: "usage", + Error: err, + }) + } + if len(failures) > 0 { + return &validate.Error{Fields: failures} + } + return nil +} + func (s *WebsiteCreate) Validate() error { if s == nil { return validate.ErrNilPointer diff --git a/core/db/db.go b/core/db/db.go index 73eb4983..ee36303e 100644 --- a/core/db/db.go +++ b/core/db/db.go @@ -13,14 +13,22 @@ type AppClient interface { // Users // CreateUser adds a new user to the database. CreateUser(ctx context.Context, user *model.User) error + // GetSetting retrieves a user setting from the database. + GetSetting(ctx context.Context, key model.SettingsKey) (string, error) + // GetSettings retrieves all the user settings from the database. + GetSettings(ctx context.Context) (*model.UserSettings, error) // GetUser retrieves a user from the database by id. GetUser(ctx context.Context, id string) (*model.User, error) // GetUserByUsername retrieves a user from the database by username. GetUserByUsername(ctx context.Context, username string) (*model.User, error) // UpdateUserUsername updates a user's username in the database. - UpdateUserUsername(ctx context.Context, id string, username string, dateUpdated int64) error + UpdateUserUsername(ctx context.Context, id string, username string) error // UpdateUserPassword updates a user's password in the database. - UpdateUserPassword(ctx context.Context, id string, password string, dateUpdated int64) error + UpdateUserPassword(ctx context.Context, id string, password string) error + // UpdateSetting updates a user setting in the database. + UpdateSetting(ctx context.Context, key model.SettingsKey, value string) error + // UpdateSettings updates a user's settings in the database. + UpdateSettings(ctx context.Context, id string, settings *model.UserSettings) error // DeleteUser deletes a user from the database. DeleteUser(ctx context.Context, id string) error @@ -42,9 +50,6 @@ type AppClient interface { // AnalyticsClient is the interface that groups all database operations related // to analytics and events. type AnalyticsClient interface { - // Settings - GetSettingsUsage(ctx context.Context) (*model.GetSettingsUsage, error) - PatchSettingsUsage(ctx context.Context, settings *model.GetSettingsUsage) error // Events AddEvents(ctx context.Context, event *[]model.EventHit) error AddPageView(ctx context.Context, event *model.PageViewHit) error diff --git a/core/db/duckdb/general.go b/core/db/duckdb/general.go deleted file mode 100644 index 1b620458..00000000 --- a/core/db/duckdb/general.go +++ /dev/null @@ -1,80 +0,0 @@ -package duckdb - -import ( - "context" - "fmt" - "regexp" - "strconv" - - "github.com/go-faster/errors" - qb "github.com/medama-io/medama/db/duckdb/query" - "github.com/medama-io/medama/model" -) - -func (c *Client) GetSettingsUsage(ctx context.Context) (*model.GetSettingsUsage, error) { - queryThreads := qb.New(). - Select("value AS threads"). - From("duckdb_settings()"). - Where("name = 'threads'") - - queryMemory := qb.New(). - Select("value AS memory_limit"). - From("duckdb_settings()"). - Where("name = 'memory_limit'") - - var usage model.GetSettingsUsage - - // Get the number of threads. - err := c.GetContext(ctx, &usage, queryThreads.Build()) - if err != nil { - return nil, errors.Wrap(err, "db") - } - - // Get the memory limit. - err = c.GetContext(ctx, &usage, queryMemory.Build()) - if err != nil { - return nil, errors.Wrap(err, "db") - } - - return &usage, nil -} - -func (c *Client) PatchSettingsUsage(ctx context.Context, settings *model.GetSettingsUsage) error { - // SET does not support binding parameters, so we need to sanitize the input manually - if settings.Threads > 0 { - exec := fmt.Sprintf("SET threads = %s", strconv.Itoa(settings.Threads)) - _, err := c.ExecContext(ctx, exec) - if err != nil { - return errors.Wrap(err, "db") - } - } - if settings.MemoryLimit != "" { - sanitized, err := sanitizeMemoryLimit(settings.MemoryLimit) - if err != nil { - return errors.Wrap(err, "invalid memory limit") - } - exec := fmt.Sprintf("SET memory_limit = '%s'", sanitized) - _, err = c.ExecContext(ctx, exec) - if err != nil { - return errors.Wrap(err, "db") - } - } - - return nil -} - -func sanitizeMemoryLimit(limit string) (string, error) { - // Regex pattern explanation: - // ^ - Start of string - // (\d+) - One or more digits (captured in group 1) - // (MB|GB|TB|MiB|GiB|TiB) - One of the valid units (captured in group 2) - // $ - End of string - pattern := `^(\d+(?:\.\d+)?)(MB|GB|TB|MiB|GiB|TiB)$` - re := regexp.MustCompile(pattern) - matches := re.FindStringSubmatch(limit) - if matches == nil { - return "", errors.New("invalid memory limit format") - } - - return limit, nil -} diff --git a/core/db/duckdb/general_test.go b/core/db/duckdb/general_test.go deleted file mode 100644 index 742b35c3..00000000 --- a/core/db/duckdb/general_test.go +++ /dev/null @@ -1,15 +0,0 @@ -package duckdb_test - -import ( - "testing" -) - -func TestGetSettingsUsage(t *testing.T) { - assert, require, ctx, client := UseDatabaseFixture(t, SIMPLE_FIXTURE) - - usage, err := client.GetSettingsUsage(ctx) - require.NoError(err) - - assert.NotNil(usage.Threads) - assert.NotNil(usage.MemoryLimit) -} diff --git a/core/db/duckdb/helpers_test.go b/core/db/duckdb/helpers_test.go index 7c40394a..c3661f23 100644 --- a/core/db/duckdb/helpers_test.go +++ b/core/db/duckdb/helpers_test.go @@ -112,12 +112,12 @@ func SetupDatabase(t *testing.T) (*assert.Assertions, *require.Assertions, conte // Create test user userCreate := model.NewUser( - "duckdb", // userID - "duckdb@example.com", // email - "testtest", // password - "en", // language - 1, // dateCreated - 2, // dateUpdated + "duckdb", // userID + "duckdb@example.com", // email + "testtest", // password + model.NewDefaultSettings(), // settings + 1, // dateCreated + 2, // dateUpdated ) err = client.CreateUser(ctx, userCreate) require.NoError(err) diff --git a/core/db/sqlite/client.go b/core/db/sqlite/client.go index d524b844..9cd7c4ac 100644 --- a/core/db/sqlite/client.go +++ b/core/db/sqlite/client.go @@ -15,7 +15,6 @@ var _ db.AppClient = (*Client)(nil) // NewClient returns a new instance of Client with the given configuration. func NewClient(host string) (*Client, error) { - // Enable foreign key support in sqlite db, err := sqlx.Connect("sqlite3", host) if err != nil { return nil, errors.Wrap(err, "sqlite") diff --git a/core/db/sqlite/helpers_test.go b/core/db/sqlite/helpers_test.go index 33a3ffa4..227ca17f 100644 --- a/core/db/sqlite/helpers_test.go +++ b/core/db/sqlite/helpers_test.go @@ -61,7 +61,7 @@ func SetupDatabaseWithUsers(t *testing.T) (*assert.Assertions, context.Context, id, usernames[i], passwords[i], - "en", + model.NewDefaultSettings(), 1, 2, ) diff --git a/core/db/sqlite/settings.go b/core/db/sqlite/settings.go new file mode 100644 index 00000000..65feaaec --- /dev/null +++ b/core/db/sqlite/settings.go @@ -0,0 +1,121 @@ +package sqlite + +import ( + "context" + "database/sql" + "encoding/json" + "time" + + "github.com/go-faster/errors" + "github.com/medama-io/medama/model" +) + +func (c *Client) GetSetting(ctx context.Context, key model.SettingsKey) (string, error) { + name := "$." + string(key) + query := ` + SELECT + JSON_EXTRACT(settings, ?) AS value + FROM users + WHERE JSON_EXTRACT(settings, ?) IS NOT NULL + LIMIT 1` + + var value sql.NullString + err := c.DB.GetContext(ctx, &value, query, name, name) + if err != nil { + if errors.Is(err, sql.ErrNoRows) { + return "", model.ErrSettingNotFound + } + return "", errors.Wrap(err, "db") + } + + if !value.Valid { + return "", model.ErrSettingNotFound + } + + return value.String, nil +} + +func (c *Client) GetSettings(ctx context.Context) (*model.UserSettings, error) { + query := `--sql + SELECT + JSON_EXTRACT(settings, '$.language') AS language, + JSON_EXTRACT(settings, '$.script_type') AS script_type + FROM users LIMIT 1` + + settings := model.NewDefaultSettings() + err := c.DB.GetContext(ctx, settings, query) + if errors.Is(err, sql.ErrNoRows) { + return nil, model.ErrSettingNotFound + } + + if err != nil { + return nil, errors.Wrap(err, "db") + } + + return settings, nil +} + +func (c *Client) UpdateSetting(ctx context.Context, key model.SettingsKey, value string) error { + query := `--sql + UPDATE users + SET settings = JSON_SET(settings, :key, :value), + date_updated = :date_updated` + + params := map[string]interface{}{ + "key": "$." + string(key), + "value": value, + "date_updated": time.Now().Unix(), + } + + result, err := c.DB.NamedExecContext(ctx, query, params) + if err != nil { + return errors.Wrap(err, "db") + } + + rowsAffected, err := result.RowsAffected() + if err != nil { + return errors.Wrap(err, "getting rows affected") + } + + if rowsAffected == 0 { + return model.ErrUserNotFound + } + + return nil +} + +// UpdateSettings updates a user's settings in the database. +func (c *Client) UpdateSettings(ctx context.Context, userID string, settings *model.UserSettings) error { + query := `--sql + UPDATE users + SET settings = :settings, + date_updated = :date_updated + WHERE id = :user_id` + + settingsJSON, err := json.Marshal(settings) + if err != nil { + return errors.Wrap(err, "marshaling settings") + } + + params := map[string]interface{}{ + "date_updated": time.Now().Unix(), + "settings": string(settingsJSON), + "user_id": userID, + } + + result, err := c.DB.NamedExecContext(ctx, query, params) + if err != nil { + return errors.Wrap(err, "db") + } + + rowsAffected, err := result.RowsAffected() + if err != nil { + return errors.Wrap(err, "getting rows affected") + } + + if rowsAffected == 0 { + return model.ErrUserNotFound + } + + return nil +} diff --git a/core/db/sqlite/settings_test.go b/core/db/sqlite/settings_test.go new file mode 100644 index 00000000..2e1592c8 --- /dev/null +++ b/core/db/sqlite/settings_test.go @@ -0,0 +1,63 @@ +package sqlite_test + +import ( + "testing" + + "github.com/medama-io/medama/model" +) + +func TestGetSetting(t *testing.T) { + assert, ctx, client := SetupDatabase(t) + + setting, err := client.GetSetting(ctx, model.SettingsKeyLanguage) + assert.NoError(err) + assert.NotNil(setting) + assert.Equal("en", setting) +} + +func TestGetUnknownSetting(t *testing.T) { + assert, ctx, client := SetupDatabase(t) + + setting, err := client.GetSetting(ctx, "unknown") + assert.ErrorIs(err, model.ErrSettingNotFound) + assert.Empty(setting) +} + +func TestGetSettings(t *testing.T) { + assert, ctx, client := SetupDatabase(t) + + settings, err := client.GetSettings(ctx) + assert.NoError(err) + assert.NotNil(settings) + assert.Equal("en", settings.Language) + assert.Equal("default", settings.ScriptType) +} + +func TestUpdateSetting(t *testing.T) { + assert, ctx, client := SetupDatabase(t) + + err := client.UpdateSetting(ctx, model.SettingsKeyLanguage, "jp") + assert.NoError(err) + + setting, err := client.GetSetting(ctx, model.SettingsKeyLanguage) + assert.NoError(err) + assert.Equal("jp", setting) +} + +func TestUpdateSettings(t *testing.T) { + assert, ctx, client := SetupDatabase(t) + + user, err := client.GetUserByUsername(ctx, "admin") + assert.NoError(err) + + err = client.UpdateSettings(ctx, user.ID, &model.UserSettings{ + Language: "jp", + ScriptType: "tagged-events", + }) + assert.NoError(err) + + settings, err := client.GetSettings(ctx) + assert.NoError(err) + assert.Equal("jp", settings.Language) + assert.Equal("tagged-events", settings.ScriptType) +} diff --git a/core/db/sqlite/users.go b/core/db/sqlite/users.go index 1dc14fec..fe7c4965 100644 --- a/core/db/sqlite/users.go +++ b/core/db/sqlite/users.go @@ -3,6 +3,8 @@ package sqlite import ( "context" "database/sql" + "encoding/json" + "time" "github.com/go-faster/errors" "github.com/medama-io/medama/model" @@ -15,28 +17,34 @@ func (c *Client) CreateUser(ctx context.Context, user *model.User) error { id, username, password, - language, + settings, date_created, date_updated ) VALUES ( :id, :username, :password, - :language, + :settings, :date_created, :date_updated )` + // Marshal settings to JSON + settingsJSON, err := json.Marshal(user.Settings) + if err != nil { + return errors.Wrap(err, "marshaling settings") + } + paramMap := map[string]interface{}{ "id": user.ID, "username": user.Username, "password": user.Password, - "language": user.Language, + "settings": string(settingsJSON), "date_created": user.DateCreated, "date_updated": user.DateUpdated, } - _, err := c.DB.NamedExecContext(ctx, exec, paramMap) + _, err = c.DB.NamedExecContext(ctx, exec, paramMap) if err != nil { if errors.Is(err, sqlite3.CONSTRAINT_UNIQUE) || errors.Is(err, sqlite3.CONSTRAINT_PRIMARYKEY) { return model.ErrUserExists @@ -50,66 +58,80 @@ func (c *Client) CreateUser(ctx context.Context, user *model.User) error { func (c *Client) GetUser(ctx context.Context, id string) (*model.User, error) { query := `--sql - SELECT id, username, password, language, date_created, date_updated FROM users WHERE id = ?` - - res, err := c.DB.QueryxContext(ctx, query, id) + SELECT id, username, password, settings, date_created, date_updated FROM users WHERE id = ?` + + var user model.User + var settingsJSON string + + err := c.DB.QueryRowxContext(ctx, query, id).Scan( + &user.ID, + &user.Username, + &user.Password, + &settingsJSON, + &user.DateCreated, + &user.DateUpdated, + ) if err != nil { if errors.Is(err, sql.ErrNoRows) { return nil, model.ErrUserNotFound } - return nil, errors.Wrap(err, "db") } - defer res.Close() - - if res.Next() { - user := &model.User{} - - err := res.StructScan(user) + // Parse the JSON settings + if settingsJSON != "" { + user.Settings = model.NewDefaultSettings() + err = json.Unmarshal([]byte(settingsJSON), user.Settings) if err != nil { - return nil, errors.Wrap(err, "db") + return nil, errors.Wrap(err, "failed to unmarshal settings") } - - return user, nil } - return nil, model.ErrUserNotFound + return &user, nil } func (c *Client) GetUserByUsername(ctx context.Context, username string) (*model.User, error) { query := `--sql - SELECT id, username, password, language, date_created, date_updated FROM users WHERE username = ?` - - res, err := c.DB.QueryxContext(ctx, query, username) + SELECT id, username, password, settings, date_created, date_updated FROM users WHERE username = ?` + + var user model.User + var settingsJSON string + + err := c.DB.QueryRowxContext(ctx, query, username).Scan( + &user.ID, + &user.Username, + &user.Password, + &settingsJSON, + &user.DateCreated, + &user.DateUpdated, + ) if err != nil { + if errors.Is(err, sql.ErrNoRows) { + return nil, model.ErrUserNotFound + } return nil, errors.Wrap(err, "db") } - defer res.Close() - - if res.Next() { - user := &model.User{} - - err := res.StructScan(user) + // Parse the JSON settings + if settingsJSON != "" { + user.Settings = model.NewDefaultSettings() + err = json.Unmarshal([]byte(settingsJSON), user.Settings) if err != nil { - return nil, errors.Wrap(err, "db") + return nil, errors.Wrap(err, "failed to unmarshal settings") } - - return user, nil } - return nil, model.ErrUserNotFound + return &user, nil } -func (c *Client) UpdateUserUsername(ctx context.Context, id string, username string, dateUpdated int64) error { +func (c *Client) UpdateUserUsername(ctx context.Context, id string, username string) error { exec := `--sql UPDATE users SET username = :username, date_updated = :date_updated WHERE id = :id` paramMap := map[string]interface{}{ "id": id, "username": username, - "date_updated": dateUpdated, + "date_updated": time.Now().Unix(), } _, err := c.DB.NamedExecContext(ctx, exec, paramMap) @@ -127,14 +149,14 @@ func (c *Client) UpdateUserUsername(ctx context.Context, id string, username str return nil } -func (c *Client) UpdateUserPassword(ctx context.Context, id string, password string, dateUpdated int64) error { +func (c *Client) UpdateUserPassword(ctx context.Context, id string, password string) error { exec := `--sql UPDATE users SET password = :password, date_updated = :date_updated WHERE id = :id` paramMap := map[string]interface{}{ "id": id, "password": password, - "date_updated": dateUpdated, + "date_updated": time.Now().Unix(), } _, err := c.DB.NamedExecContext(ctx, exec, paramMap) diff --git a/core/db/sqlite/users_test.go b/core/db/sqlite/users_test.go index 461c3ff4..7ed97c47 100644 --- a/core/db/sqlite/users_test.go +++ b/core/db/sqlite/users_test.go @@ -13,7 +13,7 @@ func TestCreateUser(t *testing.T) { "test", "username", "password", - "en", + model.NewDefaultSettings(), 1, 2, ) @@ -26,7 +26,7 @@ func TestCreateUser(t *testing.T) { assert.NotNil(user) assert.Equal("test", user.ID) assert.Equal("username", user.Username) - assert.Equal("en", user.Language) + assert.Equal("en", user.Settings.Language) assert.Equal(int64(1), user.DateCreated) assert.Equal(int64(2), user.DateUpdated) } @@ -39,7 +39,7 @@ func TestGetUser(t *testing.T) { assert.NotNil(user) assert.Equal("test1", user.ID) assert.Equal("username1", user.Username) - assert.Equal("en", user.Language) + assert.Equal("en", user.Settings.Language) assert.Equal(int64(1), user.DateCreated) assert.Equal(int64(2), user.DateUpdated) } @@ -60,7 +60,7 @@ func TestGetUserByUsername(t *testing.T) { assert.NotNil(user) assert.Equal("test1", user.ID) assert.Equal("username1", user.Username) - assert.Equal("en", user.Language) + assert.Equal("en", user.Settings.Language) assert.Equal(int64(1), user.DateCreated) assert.Equal(int64(2), user.DateUpdated) } @@ -72,7 +72,7 @@ func TestGetDefaultAdminUser(t *testing.T) { assert.NoError(err) assert.NotNil(user) assert.Equal("admin", user.Username) - assert.Equal("en", user.Language) + assert.Equal("en", user.Settings.Language) } func TestGetUserByUsernameNotFound(t *testing.T) { @@ -92,7 +92,9 @@ func TestUpdateUserUsername(t *testing.T) { assert.Equal("test1", user.ID) assert.Equal("username1", user.Username) - err = client.UpdateUserUsername(ctx, "test1", "usernamenew", 3) + dateUpdated := user.DateUpdated + + err = client.UpdateUserUsername(ctx, "test1", "usernamenew") assert.NoError(err) user, err = client.GetUser(ctx, "test1") @@ -100,7 +102,7 @@ func TestUpdateUserUsername(t *testing.T) { assert.NotNil(user) assert.Equal("test1", user.ID) assert.Equal("usernamenew", user.Username) - assert.Equal(int64(3), user.DateUpdated) + assert.Greater(user.DateUpdated, dateUpdated) } func TestUpdateUserUsernameExisting(t *testing.T) { @@ -112,14 +114,14 @@ func TestUpdateUserUsernameExisting(t *testing.T) { assert.Equal("test1", user.ID) assert.Equal("username1", user.Username) - err = client.UpdateUserUsername(ctx, "test1", "username2", 3) + err = client.UpdateUserUsername(ctx, "test1", "username2") assert.ErrorIs(err, model.ErrUserExists) } func TestUpdateUserPassword(t *testing.T) { assert, ctx, client := SetupDatabaseWithUsers(t) - err := client.UpdateUserPassword(ctx, "test1", "password2", 3) + err := client.UpdateUserPassword(ctx, "test1", "password2") assert.NoError(err) user, err := client.GetUser(ctx, "test1") @@ -127,7 +129,6 @@ func TestUpdateUserPassword(t *testing.T) { assert.NotNil(user) assert.Equal("test1", user.ID) assert.Equal("password2", user.Password) - assert.Equal(int64(3), user.DateUpdated) } func TestDeleteUser(t *testing.T) { diff --git a/core/generate.sh b/core/generate.sh index 594a369f..7372f5cc 100755 --- a/core/generate.sh +++ b/core/generate.sh @@ -14,6 +14,6 @@ go run github.com/ogen-go/ogen/cmd/ogen@latest --target api --clean openapi.yaml # # sed also runs differently on macOS and Linux, so we need to add a couple odd flags to # make it portable. -# Line 327 -sed -i'' -e '327c\ +# Line 256 +sed -i'' -e '256c\ case ct == "application/json", ct == "text/plain":' ./api/oas_request_decoders_gen.go diff --git a/core/go.mod b/core/go.mod index 791d7689..8bccbe80 100644 --- a/core/go.mod +++ b/core/go.mod @@ -5,7 +5,7 @@ go 1.22.2 require ( github.com/alexedwards/argon2id v1.0.0 github.com/alphadose/haxmap v1.4.0 - github.com/caarlos0/env/v11 v11.1.0 + github.com/caarlos0/env/v11 v11.2.0 github.com/gkampitakis/go-snaps v0.5.4 github.com/go-faster/errors v0.7.1 github.com/go-faster/jx v1.1.0 @@ -14,13 +14,13 @@ require ( github.com/medama-io/go-referrer-parser v0.0.0-20240706151617-0106555291e7 github.com/medama-io/go-timezone-country v0.0.0-20240125021558-8a6127efd8f7 github.com/medama-io/go-useragent v0.0.0-20240707203018-4bd80a87eb23 - github.com/ncruces/go-sqlite3 v0.17.0 + github.com/ncruces/go-sqlite3 v0.17.1 github.com/ogen-go/ogen v1.2.2 github.com/rs/cors v1.11.0 github.com/rs/zerolog v1.33.0 - github.com/shirou/gopsutil/v4 v4.24.6 + github.com/shirou/gopsutil/v4 v4.24.7 github.com/stretchr/testify v1.9.0 - go.jetify.com/typeid v1.2.0 + go.jetify.com/typeid v1.3.0 go.uber.org/multierr v1.11.0 golang.org/x/text v0.16.0 ) @@ -29,7 +29,7 @@ require ( github.com/apache/arrow/go/v14 v14.0.2 // indirect github.com/boyter/go-string v1.0.5 // indirect github.com/davecgh/go-spew v1.1.1 // indirect - github.com/dlclark/regexp2 v1.11.1 // indirect + github.com/dlclark/regexp2 v1.11.2 // indirect github.com/fatih/color v1.17.0 // indirect github.com/ghodss/yaml v1.0.0 // indirect github.com/gkampitakis/ciinfo v0.3.0 // indirect @@ -68,13 +68,13 @@ require ( github.com/zeebo/xxh3 v1.0.2 // indirect go.uber.org/zap v1.27.0 // indirect golang.org/x/crypto v0.25.0 // indirect - golang.org/x/exp v0.0.0-20240613232115-7f521ea00fb8 // indirect + golang.org/x/exp v0.0.0-20240719175910-8a7402abbf56 // indirect golang.org/x/mod v0.19.0 // indirect golang.org/x/net v0.27.0 // indirect golang.org/x/sync v0.7.0 // indirect golang.org/x/sys v0.22.0 // indirect - golang.org/x/tools v0.22.0 // indirect - golang.org/x/xerrors v0.0.0-20231012003039-104605ab7028 // indirect + golang.org/x/tools v0.23.0 // indirect + golang.org/x/xerrors v0.0.0-20240716161551-93cc26a95ae9 // indirect gopkg.in/yaml.v2 v2.4.0 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect ) diff --git a/core/go.sum b/core/go.sum index a1ecca6d..8e76c419 100644 --- a/core/go.sum +++ b/core/go.sum @@ -8,14 +8,14 @@ github.com/apache/arrow/go/v14 v14.0.2 h1:N8OkaJEOfI3mEZt07BIkvo4sC6XDbL+48MBPWO github.com/apache/arrow/go/v14 v14.0.2/go.mod h1:u3fgh3EdgN/YQ8cVQRguVW3R+seMybFg8QBQ5LU+eBY= github.com/boyter/go-string v1.0.5 h1:/xcOlWdgelLYLVkUU0xBLfioGjZ9KIMUMI/RXG138YY= github.com/boyter/go-string v1.0.5/go.mod h1:Mww9cDld2S2cdJ0tQffBhsZFMQRA2OJdcjWYZXvZ4Ss= -github.com/caarlos0/env/v11 v11.1.0 h1:a5qZqieE9ZfzdvbbdhTalRrHT5vu/4V1/ad1Ka6frhI= -github.com/caarlos0/env/v11 v11.1.0/go.mod h1:LwgkYk1kDvfGpHthrWWLof3Ny7PezzFwS4QrsJdHTMo= +github.com/caarlos0/env/v11 v11.2.0 h1:kvB1ZmwdWgI3JsuuVUE7z4cY/6Ujr03D0w2WkOOH4Xs= +github.com/caarlos0/env/v11 v11.2.0/go.mod h1:LwgkYk1kDvfGpHthrWWLof3Ny7PezzFwS4QrsJdHTMo= github.com/coreos/go-systemd/v22 v22.5.0/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc= github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= -github.com/dlclark/regexp2 v1.11.1 h1:CJs78ewKXO9PuNf6Xwlw6eibMadBkXTRpOeUdv+IcWM= -github.com/dlclark/regexp2 v1.11.1/go.mod h1:DHkYz0B9wPfa6wondMfaivmHpzrQ3v9q8cnmRbL6yW8= +github.com/dlclark/regexp2 v1.11.2 h1:/u628IuisSTwri5/UKloiIsH8+qF2Pu7xEQX+yIKg68= +github.com/dlclark/regexp2 v1.11.2/go.mod h1:DHkYz0B9wPfa6wondMfaivmHpzrQ3v9q8cnmRbL6yW8= github.com/fatih/color v1.17.0 h1:GlRw1BRJxkpqUCBKzKOw098ed57fEsKeNjpTe3cSjK4= github.com/fatih/color v1.17.0/go.mod h1:YZ7TlrGPkiz6ku9fK3TLD/pl3CpsiFyu8N92HLgmosI= github.com/ghodss/yaml v1.0.0 h1:wQHKEahhL6wmXdzwWG11gIVCkOv05bNOh+Rxn0yngAk= @@ -82,8 +82,8 @@ github.com/medama-io/go-useragent v0.0.0-20240707203018-4bd80a87eb23 h1:myjtzE9E github.com/medama-io/go-useragent v0.0.0-20240707203018-4bd80a87eb23/go.mod h1:H9GYWth4IN8vAFZh5LeARza7VwM4jK9uk7Tb9huVzLw= github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyuac5Z2hdY= github.com/mitchellh/mapstructure v1.5.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= -github.com/ncruces/go-sqlite3 v0.17.0 h1:tbrmwAF9Iq6O6i8NX+pO7rQYIwIJ4cZ/nZFQyw7GB18= -github.com/ncruces/go-sqlite3 v0.17.0/go.mod h1:Ik98tXgiGdF2HgHYZlEkh84RAC3U3eqgS7PYsmLwLxY= +github.com/ncruces/go-sqlite3 v0.17.1 h1:VxTjDpCn87FaFlKMaAYC1jP7ND0d4UNj+6G4IQDHbgI= +github.com/ncruces/go-sqlite3 v0.17.1/go.mod h1:FnCyui8SlDoL0mQZ5dTouNo7s7jXS0kJv9lBt1GlM9w= github.com/ncruces/julianday v1.0.0 h1:fH0OKwa7NWvniGQtxdJRxAgkBMolni2BjDHaWTxqt7M= github.com/ncruces/julianday v1.0.0/go.mod h1:Dusn2KvZrrovOMJuOt0TNXL6tB7U2E8kvza5fFc9G7g= github.com/ogen-go/ogen v1.2.2 h1:fFqZzRacbdnOQeqep4efVeqj7/4hI1mlimrY8rn970A= @@ -107,8 +107,8 @@ github.com/rs/zerolog v1.33.0 h1:1cU2KZkvPxNyfgEmhHAz/1A9Bz+llsdYzklWFzgp0r8= github.com/rs/zerolog v1.33.0/go.mod h1:/7mN4D5sKwJLZQ2b/znpjC3/GQWY/xaDXUM0kKWRHss= github.com/segmentio/asm v1.2.0 h1:9BQrFxC+YOHJlTlHGkTrFWf59nbL3XnCoFLTwDCI7ys= github.com/segmentio/asm v1.2.0/go.mod h1:BqMnlJP91P8d+4ibuonYZw9mfnzI9HfxselHZr5aAcs= -github.com/shirou/gopsutil/v4 v4.24.6 h1:9qqCSYF2pgOU+t+NgJtp7Co5+5mHF/HyKBUckySQL64= -github.com/shirou/gopsutil/v4 v4.24.6/go.mod h1:aoebb2vxetJ/yIDZISmduFvVNPHqXQ9SEJwRXxkf0RA= +github.com/shirou/gopsutil/v4 v4.24.7 h1:V9UGTK4gQ8HvcnPKf6Zt3XHyQq/peaekfxpJ2HSocJk= +github.com/shirou/gopsutil/v4 v4.24.7/go.mod h1:0uW/073rP7FYLOkvxolUQM5rMOLTNmRXnFKafpb71rw= github.com/shoenig/go-m1cpu v0.1.6 h1:nxdKQNcEB6vzgA2E2bvzKIYRuNj7XNJ4S/aRSwKzFtM= github.com/shoenig/go-m1cpu v0.1.6/go.mod h1:1JJMcUBvfNwpq05QDQVAnx3gUHr9IYF7GNg9SUEw2VQ= github.com/shoenig/test v0.6.4 h1:kVTaSd7WLz5WZ2IaoM0RSzRsUD+m8wRR+5qvntpn4LU= @@ -138,8 +138,8 @@ github.com/zeebo/assert v1.3.0 h1:g7C04CbJuIDKNPFHmsk4hwZDO5O+kntRxzaUoNXj+IQ= github.com/zeebo/assert v1.3.0/go.mod h1:Pq9JiuJQpG8JLJdtkwrJESF0Foym2/D9XMU5ciN/wJ0= github.com/zeebo/xxh3 v1.0.2 h1:xZmwmqxHZA8AI603jOQ0tMqmBr9lPeFwGg6d+xy9DC0= github.com/zeebo/xxh3 v1.0.2/go.mod h1:5NWz9Sef7zIDm2JHfFlcQvNekmcEl9ekUZQQKCYaDcA= -go.jetify.com/typeid v1.2.0 h1:Nd1MZZoWe9q4kkh82xZHQbqCzxJX/ZxgK8RjQWxygwk= -go.jetify.com/typeid v1.2.0/go.mod h1:CtVGyt2+TSp4Rq5+ARLvGsJqdNypKBAC6INQ9TLPlmk= +go.jetify.com/typeid v1.3.0 h1:fuWV7oxO4mSsgpxwhaVpFXgt0IfjogR29p+XAjDCVKY= +go.jetify.com/typeid v1.3.0/go.mod h1:CtVGyt2+TSp4Rq5+ARLvGsJqdNypKBAC6INQ9TLPlmk= go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto= go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE= go.uber.org/multierr v1.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0= @@ -151,8 +151,8 @@ golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5y golang.org/x/crypto v0.14.0/go.mod h1:MVFd36DqK4CsrnJYDkBA3VC4m2GkXAM0PvzMCn4JQf4= golang.org/x/crypto v0.25.0 h1:ypSNr+bnYL2YhwoMt2zPxHFmbAN1KZs/njMG3hxUp30= golang.org/x/crypto v0.25.0/go.mod h1:T+wALwcMOSE0kXgUAnPAHqTLW+XHgcELELW8VaDgm/M= -golang.org/x/exp v0.0.0-20240613232115-7f521ea00fb8 h1:yixxcjnhBmY0nkL253HFVIm0JsFHwrHdT3Yh6szTnfY= -golang.org/x/exp v0.0.0-20240613232115-7f521ea00fb8/go.mod h1:jj3sYF3dwk5D+ghuXyeI3r5MFf+NT2An6/9dOA95KSI= +golang.org/x/exp v0.0.0-20240719175910-8a7402abbf56 h1:2dVuKD2vS7b0QIHQbpyTISPd0LeHDbnYEryqj5Q1ug8= +golang.org/x/exp v0.0.0-20240719175910-8a7402abbf56/go.mod h1:M4RDyNAINzryxdtnbRXRL/OHtkFuWGRjvuhBJpk2IlY= golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= golang.org/x/mod v0.19.0 h1:fEdghXQSo20giMthA7cd28ZC+jts4amQ3YMXiP5oMQ8= @@ -202,11 +202,11 @@ golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGm golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU= -golang.org/x/tools v0.22.0 h1:gqSGLZqv+AI9lIQzniJ0nZDRG5GBPsSi+DRNHWNz6yA= -golang.org/x/tools v0.22.0/go.mod h1:aCwcsjqvq7Yqt6TNyX7QMU2enbQ/Gt0bo6krSeEri+c= +golang.org/x/tools v0.23.0 h1:SGsXPZ+2l4JsgaCKkx+FQ9YZ5XEtA1GZYuoDjenLjvg= +golang.org/x/tools v0.23.0/go.mod h1:pnu6ufv6vQkll6szChhK3C3L/ruaIv5eBeztNG8wtsI= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -golang.org/x/xerrors v0.0.0-20231012003039-104605ab7028 h1:+cNy6SZtPcJQH3LJVLOSmiC7MMxXNOb3PU/VUEz+EhU= -golang.org/x/xerrors v0.0.0-20231012003039-104605ab7028/go.mod h1:NDW/Ps6MPRej6fsCIbMTohpP40sJ/P/vI1MoTEGwX90= +golang.org/x/xerrors v0.0.0-20240716161551-93cc26a95ae9 h1:LLhsEBxRTBLuKlQxFBYUOU8xyFgXv6cOTp2HASDlsDk= +golang.org/x/xerrors v0.0.0-20240716161551-93cc26a95ae9/go.mod h1:NDW/Ps6MPRej6fsCIbMTohpP40sJ/P/vI1MoTEGwX90= gonum.org/v1/gonum v0.12.0 h1:xKuo6hzt+gMav00meVPUlXwSdoEJP46BR+wdxQEFK2o= gonum.org/v1/gonum v0.12.0/go.mod h1:73TDxJfAAHeA8Mk9mf8NlIppyhQNo5GLTcYeqgo2lvY= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= diff --git a/core/migrations/0001_sqlite_schema.go b/core/migrations/0001_sqlite_schema.go index e4026a02..e8dc1b09 100644 --- a/core/migrations/0001_sqlite_schema.go +++ b/core/migrations/0001_sqlite_schema.go @@ -1,13 +1,7 @@ package migrations import ( - "context" - "time" - "github.com/medama-io/medama/db/sqlite" - "github.com/medama-io/medama/model" - "github.com/medama-io/medama/util" - "go.jetify.com/typeid" ) func Up0001(c *sqlite.Client) error { @@ -61,30 +55,7 @@ func Up0001(c *sqlite.Client) error { return err } - // Create default admin user - // UUIDv7 id generation - typeid, err := typeid.WithPrefix("user") - if err != nil { - return err - } - id := typeid.String() - - // Hash default password - auth, err := util.NewAuthService(context.Background(), false) - if err != nil { - return err - } - pwdHash, err := auth.HashPassword("CHANGE_ME_ON_FIRST_LOGIN") - if err != nil { - return err - } - - dateCreated := time.Now().Unix() - dateUpdated := dateCreated - err = c.CreateUser(context.Background(), model.NewUser(id, "admin", pwdHash, "en", dateCreated, dateUpdated)) - if err != nil { - return err - } + // Moved user creation to 0006_sqlite_settings.go return nil } diff --git a/core/migrations/0006_sqlite_settings.go b/core/migrations/0006_sqlite_settings.go new file mode 100644 index 00000000..bb377d6f --- /dev/null +++ b/core/migrations/0006_sqlite_settings.go @@ -0,0 +1,93 @@ +package migrations + +import ( + "github.com/medama-io/medama/db/sqlite" +) + +func Up0006(c *sqlite.Client) error { + // Begin transaction + tx, err := c.Beginx() + if err != nil { + return err + } + + // Update users table to create new settings JSON column. + _, err = tx.Exec(`--sql + ALTER TABLE users ADD COLUMN settings JSON NOT NULL DEFAULT '{}'`) + if err != nil { + return err + } + + // Move language column to settings JSON column. + _, err = tx.Exec(`--sql + UPDATE users SET settings = JSON_OBJECT('language', language)`) + if err != nil { + return err + } + + // Remove language column from users table. + _, err = tx.Exec(`--sql + ALTER TABLE users DROP COLUMN language`) + if err != nil { + return err + } + + // Update websites table to create new settings JSON column. + _, err = tx.Exec(`--sql + ALTER TABLE websites ADD COLUMN settings JSON NOT NULL DEFAULT '{}'`) + if err != nil { + return err + } + + // Commit transaction + err = tx.Commit() + if err != nil { + return err + } + + return nil +} + +func Down0006(c *sqlite.Client) error { + // Begin transaction + tx, err := c.Beginx() + if err != nil { + return err + } + + // Add language column back to users table. + _, err = tx.Exec(`--sql + ALTER TABLE users ADD COLUMN language TEXT NOT NULL`) + if err != nil { + return err + } + + // Move language from settings JSON column back to language column. + _, err = tx.Exec(`--sql + UPDATE users SET language = JSON_EXTRACT(settings, '$.language')`) + if err != nil { + return err + } + + // Remove settings JSON column from users table. + _, err = tx.Exec(`--sql + ALTER TABLE users DROP COLUMN settings`) + if err != nil { + return err + } + + // Remove settings JSON column from websites table. + _, err = tx.Exec(`--sql + ALTER TABLE websites DROP COLUMN settings`) + if err != nil { + return err + } + + // Commit transaction + err = tx.Commit() + if err != nil { + return err + } + + return nil +} diff --git a/core/migrations/Schema.md b/core/migrations/Schema.md new file mode 100644 index 00000000..6915ba11 --- /dev/null +++ b/core/migrations/Schema.md @@ -0,0 +1,66 @@ +# Schema + +This document describes the current state of the schema for the database. + +## Tables + +### `users` - SQLite + +Stores user data. Currently, only a single `admin` user is supported. + +| Column | Type | Description | +| -------------- | ---------------------------- | ------------------- | +| `id` | `TEXT PRIMARY KEY` | Primary key | +| `username` | `TEXT NOT NULL` | Username | +| `password` | `TEXT NOT NULL` | Password | +| `date_created` | `INTEGER NOT NULL` | Date created (Unix) | +| `date_updated` | `INTEGER NOT NULL` | Date updated (Unix) | +| `settings` | `JSON NOT NULL DEFAULT '{}'` | User settings | + +#### Settings JSON Schema + +```json +{ + "script_type": string, // 'default' or 'tagged-events' + "language": string, // Only supports 'en' for now +} +``` + +### `views` - DuckDB + +Stores page view event data. + + +| Column | Type | Description | +| ------------------ | ---------------------- | -------------------------------------------------------------- | +| `bid` | `TEXT PRIMARY KEY` | Beacon ID used to link `load` and `unload` event data together | +| `hostname` | `TEXT NOT NULL` | Hostname | +| `pathname` | `TEXT NOT NULL` | Pathname | +| `is_unique_user` | `BOOLEAN NOT NULL` | Is unique visitor | +| `is_unique_page` | `BOOLEAN NOT NULL` | Is unique visitor to specific page | +| `referrer_host` | `TEXT` | Referrer hostname | +| `referrer_group` | `TEXT` | Referrer group name | +| `country` | `TEXT` | Country name | +| `language_base` | `TEXT` | Base language | +| `language_dialect` | `TEXT` | Dialect language | +| `ua_browser` | `TEXT NOT NULL` | Browser name | +| `ua_os` | `TEXT NOT NULL` | Operating system | +| `ua_device_type` | `TEXT NOT NULL` | Device type | +| `utm_source` | `TEXT` | UTM source | +| `utm_medium` | `TEXT` | UTM medium | +| `utm_campaign` | `TEXT` | UTM campaign | +| `duration_ms` | `UINTEGER` | Duration (ms) | +| `date_created` | `TIMESTAMPTZ NOT NULL` | Date created | + +### `events` - DuckDB + +Stores custom properties event data. + +| Column | Type | Description | +| -------------- | ---------------------- | ----------------------------------------------------------- | +| `bid` | `TEXT` | Beacon ID used to link to page view event | +| `batch_id` | `TEXT NOT NULL` | Batch ID used to link multiple properties of the same event | +| `group_name` | `TEXT NOT NULL` | Group name, typically the hostname | +| `name` | `TEXT NOT NULL` | Event key name | +| `value` | `TEXT NOT NULL` | Event value | +| `date_created` | `TIMESTAMPTZ NOT NULL` | Date created | diff --git a/core/migrations/migrations.go b/core/migrations/migrations.go index cbdf3a39..9cac3d1b 100644 --- a/core/migrations/migrations.go +++ b/core/migrations/migrations.go @@ -3,11 +3,15 @@ package migrations import ( "context" "database/sql" + "time" "github.com/go-faster/errors" "github.com/medama-io/medama/db/duckdb" "github.com/medama-io/medama/db/sqlite" + "github.com/medama-io/medama/model" + "github.com/medama-io/medama/util" "github.com/medama-io/medama/util/logger" + "go.jetify.com/typeid" ) type MigrationType string @@ -49,6 +53,7 @@ func NewMigrationsService(ctx context.Context, sqliteC *sqlite.Client, duckdbC * // Setup migration functions sqliteMigrations := []*Migration[sqlite.Client]{ {ID: 1, Name: "0001_sqlite_schema.go", Type: SQLite, Up: Up0001, Down: Down0001}, + {ID: 6, Name: "0006_sqlite_settings.go", Type: SQLite, Up: Up0006, Down: Down0006}, } duckdbMigrations := []*Migration[duckdb.Client]{ @@ -146,5 +151,54 @@ func (s *Service) AutoMigrate(ctx context.Context) error { return err } + // Count if there are any users. If there are no users, create the default admin user. + rows, err := s.sqlite.QueryContext(ctx, "SELECT COUNT(*) FROM users") + if err != nil { + return err + } + defer rows.Close() + + var count int + for rows.Next() { + err = rows.Scan(&count) + if err != nil { + return err + } + } + + if count > 0 { + return nil + } + + // Create default admin user + log := logger.Get() + log.Warn().Msg("no users found, creating default admin user") + + // UUIDv7 id generation + typeid, err := typeid.WithPrefix("user") + if err != nil { + return err + } + id := typeid.String() + + // Hash default password + auth, err := util.NewAuthService(context.Background(), false) + if err != nil { + return err + } + pwdHash, err := auth.HashPassword("CHANGE_ME_ON_FIRST_LOGIN") + if err != nil { + return err + } + + dateCreated := time.Now().Unix() + dateUpdated := dateCreated + err = s.sqlite.CreateUser(context.Background(), model.NewUser(id, "admin", pwdHash, model.NewDefaultSettings(), dateCreated, dateUpdated)) + if err != nil { + return err + } + + log.Warn().Msg("default admin user created") + return nil } diff --git a/core/model/errors.go b/core/model/errors.go index 29820a5a..10ab9859 100644 --- a/core/model/errors.go +++ b/core/model/errors.go @@ -36,6 +36,8 @@ var ( ErrInvalidFilterOperation = errors.New("invalid filter operation") // Users + // ErrSettingNotFound is returned when a setting is not found. + ErrSettingNotFound = errors.New("setting not found") // ErrUserExists is returned when a user already exists. ErrUserExists = errors.New("user already exists") // ErrUserInvalidLanguage is returned when a user has an invalid language. diff --git a/core/model/settings.go b/core/model/settings.go index 6290da1d..5238ddd2 100644 --- a/core/model/settings.go +++ b/core/model/settings.go @@ -1,6 +1,20 @@ package model -type GetSettingsUsage struct { - Threads int `db:"threads"` - MemoryLimit string `db:"memory_limit"` +type SettingsKey string + +const ( + // SettingsKeyLanguage is the key for the user's language setting. + SettingsKeyLanguage SettingsKey = "language" + // SettingsKeyScriptType is the key for the user's script type setting. + SettingsKeyScriptType SettingsKey = "script_type" +) + +type UserSettings struct { + // Account + Language string `json:"language" db:"language"` + + // Tracker + ScriptType string `json:"script_type" db:"script_type"` } + +type WebsiteSettings struct{} diff --git a/core/model/user.go b/core/model/user.go index 3b50250c..ade61475 100644 --- a/core/model/user.go +++ b/core/model/user.go @@ -1,32 +1,32 @@ package model -type GetUser struct { - ID string `json:"id" db:"id"` - Email string `json:"email" db:"email"` - Language string `json:"language" db:"language"` - DateCreated int64 `json:"date_created" db:"date_created"` - DateUpdated int64 `json:"date_updated" db:"date_updated"` -} - type User struct { ID string `json:"id" db:"id"` Username string `json:"username" db:"username"` Password string `json:"password" db:"password"` - Language string `json:"language" db:"language"` - DateCreated int64 `json:"date_created" db:"date_created"` - DateUpdated int64 `json:"date_updated" db:"date_updated"` + Settings *UserSettings `json:"settings" db:"settings"` + DateCreated int64 `json:"date_created" db:"date_created"` + DateUpdated int64 `json:"date_updated" db:"date_updated"` } // NewUser returns a new instance of User with the given values. -func NewUser(id string, username string, password string, language string, dateCreated int64, dateUpdated int64) *User { +func NewUser(id string, username string, password string, settings *UserSettings, dateCreated int64, dateUpdated int64) *User { return &User{ ID: id, Username: username, Password: password, - Language: language, + Settings: settings, DateCreated: dateCreated, DateUpdated: dateUpdated, } } + +// NewSettings returns a new instance of Settings with default values. +func NewDefaultSettings() *UserSettings { + return &UserSettings{ + Language: "en", + ScriptType: "default", + } +} diff --git a/core/openapi.yaml b/core/openapi.yaml index 93dfab73..6e7048f7 100644 --- a/core/openapi.yaml +++ b/core/openapi.yaml @@ -165,59 +165,6 @@ paths: servers: - url: "http://localhost:8080" description: Local Server - /settings/usage: - get: - tags: - - Settings - security: - - CookieAuth: [] - summary: Get Resource Usage - description: Get the current CPU, memory and disk usage of the server. - operationId: get-settings-usage - parameters: - - $ref: "#/components/parameters/SessionAuth" - responses: - "200": - description: OK - content: - application/json: - schema: - $ref: "#/components/schemas/SettingsUsageGet" - "401": - $ref: "#/components/responses/UnauthorisedError" - "500": - $ref: "#/components/responses/InternalServerError" - patch: - tags: - - Settings - security: - - CookieAuth: [] - summary: Update Resource Usage - description: Update the resource usage settings of the server. - operationId: patch-settings-usage - parameters: - - $ref: "#/components/parameters/SessionAuth" - requestBody: - description: Resource usage settings to update. - content: - application/json: - schema: - $ref: "#/components/schemas/SettingsUsagePatch" - required: true - responses: - "201": - description: Success - "400": - $ref: "#/components/responses/BadRequestError" - "401": - $ref: "#/components/responses/UnauthorisedError" - "403": - $ref: "#/components/responses/ForbiddenError" - "500": - $ref: "#/components/responses/InternalServerError" - servers: - - url: "http://localhost:8080" - description: Local Server /user: get: tags: @@ -312,6 +259,28 @@ paths: servers: - url: "http://localhost:8080" description: Local Server + /user/usage: + get: + tags: + - User + security: + - CookieAuth: [] + summary: Get Resource Usage + description: Get the current CPU, memory and disk usage of the server. + operationId: get-user-usage + parameters: + - $ref: "#/components/parameters/SessionAuth" + responses: + "200": + description: OK + content: + application/json: + schema: + $ref: "#/components/schemas/UserUsageGet" + "401": + $ref: "#/components/responses/UnauthorisedError" + "500": + $ref: "#/components/responses/InternalServerError" /websites: get: tags: @@ -1476,6 +1445,19 @@ components: not_in: type: string description: Not in. + UserSettings: + type: object + title: UserSettings + description: Response body for getting user settings. + properties: + language: + type: string + enum: [en] + default: en + script_type: + type: string + enum: [default, tagged-events] + default: default UserGet: type: object title: UserGet @@ -1485,10 +1467,8 @@ components: type: string minLength: 3 maxLength: 120 - language: - type: string - enum: [en] - default: en + settings: + $ref: "#/components/schemas/UserSettings" dateCreated: type: integer format: int64 @@ -1497,9 +1477,56 @@ components: format: int64 required: - username - - language + - settings - dateCreated - dateUpdated + UserUsageGet: + type: object + title: UserUsageGet + description: Response body for getting CPU, memory and disk usage of the server. + properties: + cpu: + type: object + properties: + usage: + type: number + format: float + cores: + type: integer + threads: + type: integer + required: + - usage + - cores + - threads + memory: + type: object + properties: + used: + type: integer + format: int64 + total: + type: integer + format: int64 + required: + - used + - total + disk: + type: object + properties: + used: + type: integer + format: int64 + total: + type: integer + format: int64 + required: + - used + - total + required: + - cpu + - memory + - disk UserPatch: type: object title: UserPatch @@ -1514,10 +1541,8 @@ components: minLength: 5 maxLength: 128 format: password - language: - type: string - enum: [en] - default: en + settings: + $ref: "#/components/schemas/UserSettings" WebsiteGet: type: object title: WebsiteGet @@ -1559,72 +1584,6 @@ components: minLength: 1 maxLength: 253 # FQDN limit format: hostname - SettingsUsageGet: - type: object - title: SettingsUsageGet - description: Response body for getting CPU, memory and disk usage of the server. - properties: - cpu: - type: object - properties: - usage: - type: number - format: float - cores: - type: integer - threads: - type: integer - required: - - usage - - cores - - threads - memory: - type: object - properties: - used: - type: integer - format: int64 - total: - type: integer - format: int64 - required: - - used - - total - disk: - type: object - properties: - used: - type: integer - format: int64 - total: - type: integer - format: int64 - required: - - used - - total - metadata: - type: object - properties: - threads: - type: integer - memory_limit: - type: string - required: - - cpu - - memory - - disk - - metadata - SettingsUsagePatch: - type: object - title: SettingsUsagePatch - description: Request body for updating the resource limits of the application. - properties: - threads: - type: integer - minimum: 1 - memory_limit: - type: string - minLength: 1 StatsSummary: type: object title: StatsSummary diff --git a/core/services/oas.go b/core/services/oas.go index 6c6f0b3f..dcdbebcc 100644 --- a/core/services/oas.go +++ b/core/services/oas.go @@ -9,9 +9,23 @@ import ( "github.com/medama-io/go-useragent" "github.com/medama-io/medama/db/duckdb" "github.com/medama-io/medama/db/sqlite" + "github.com/medama-io/medama/model" "github.com/medama-io/medama/util" ) +// This is a runtime config that is read from user settings in the database. +type RuntimeConfig struct { + // Tracker settings. + // Choose what type of script to serve from /script.js. + // + // Options: + // + // - "default" - Default script that collects page view data. + // + // - "tagged-events" - Script that collects page view data and custom event properties. + ScriptType string +} + type Handler struct { auth *util.AuthService db *sqlite.Client @@ -25,6 +39,9 @@ type Handler struct { // Cache store for hostnames hostnames *util.CacheStore + + // Runtime config + runtimeConfig *RuntimeConfig } // NewService returns a new instance of the ogen service handler. @@ -54,6 +71,11 @@ func NewService(ctx context.Context, auth *util.AuthService, sqlite *sqlite.Clie } hostnameCache.AddAll(hostnames) + runtimeConfig, err := NewRuntimeConfig(ctx, sqlite, duckdb) + if err != nil { + return nil, errors.Wrap(err, "services init") + } + return &Handler{ auth: auth, db: sqlite, @@ -63,5 +85,31 @@ func NewService(ctx context.Context, auth *util.AuthService, sqlite *sqlite.Clie timezoneMap: &tzMap, codeCountryMap: &codeCountryMap, hostnames: &hostnameCache, + runtimeConfig: runtimeConfig, }, nil } + +// NewRuntimeConfig creates a new runtime config. +func NewRuntimeConfig(ctx context.Context, user *sqlite.Client, analytics *duckdb.Client) (*RuntimeConfig, error) { + // Load the script type from the database. + settings, err := user.GetSettings(ctx) + if err != nil { + return nil, errors.Wrap(err, "runtime config") + } + + return &RuntimeConfig{ + ScriptType: settings.ScriptType, + }, nil +} + +func (r *RuntimeConfig) UpdateConfig(ctx context.Context, meta *sqlite.Client, settings *model.UserSettings) error { + if settings.ScriptType != "" { + err := meta.UpdateSetting(ctx, model.SettingsKeyScriptType, settings.ScriptType) + if err != nil { + return errors.Wrap(err, "script type update config") + } + r.ScriptType = settings.ScriptType + } + + return nil +} diff --git a/core/services/settings.go b/core/services/settings.go deleted file mode 100644 index 8d8306a2..00000000 --- a/core/services/settings.go +++ /dev/null @@ -1,99 +0,0 @@ -package services - -import ( - "context" - "strings" - - "github.com/medama-io/medama/api" - "github.com/medama-io/medama/model" - "github.com/medama-io/medama/util/logger" - "github.com/shirou/gopsutil/v4/cpu" - "github.com/shirou/gopsutil/v4/disk" - "github.com/shirou/gopsutil/v4/mem" -) - -func (h *Handler) GetSettingsUsage(ctx context.Context, params api.GetSettingsUsageParams) (api.GetSettingsUsageRes, error) { - // CPU statistics. - cpuCores, err := cpu.CountsWithContext(ctx, false) - if err != nil { - return nil, err - } - cpuThreads, err := cpu.CountsWithContext(ctx, true) - if err != nil { - return nil, err - } - - cpuUsageArr, err := cpu.PercentWithContext(ctx, 0, false) - if err != nil { - return nil, err - } - // Get the average CPU usage. - cpuUsage := 0.0 - for _, v := range cpuUsageArr { - cpuUsage += v - } - cpuUsage /= float64(len(cpuUsageArr)) - - // Memory statistics. - vmStat, err := mem.VirtualMemoryWithContext(ctx) - if err != nil { - return nil, err - } - - // Disk statistics. - diskStat, err := disk.UsageWithContext(ctx, "/") - if err != nil { - return nil, err - } - - // Get the current database settings. - metadata, err := h.analyticsDB.GetSettingsUsage(ctx) - if err != nil { - return nil, err - } - - return &api.SettingsUsageGet{ - CPU: api.SettingsUsageGetCPU{ - Usage: float32(cpuUsage), - Cores: cpuCores, - Threads: cpuThreads, - }, - Memory: api.SettingsUsageGetMemory{ - Used: int64(vmStat.Used), - Total: int64(vmStat.Total), - }, - Disk: api.SettingsUsageGetDisk{ - Used: int64(diskStat.Used), - Total: int64(diskStat.Total), - }, - Metadata: api.SettingsUsageGetMetadata{ - Threads: api.NewOptInt(metadata.Threads), - MemoryLimit: api.NewOptString(strings.ReplaceAll(metadata.MemoryLimit, " ", "")), - }, - }, nil -} - -func (h *Handler) PatchSettingsUsage(ctx context.Context, req *api.SettingsUsagePatch, params api.PatchSettingsUsageParams) (api.PatchSettingsUsageRes, error) { - log := logger.Get() - if h.auth.IsDemoMode { - log.Debug().Msg("patch settings rejected in demo mode") - return ErrForbidden(model.ErrDemoMode), nil - } - - // Update the database settings. - settings := &model.GetSettingsUsage{ - Threads: req.GetThreads().Value, - MemoryLimit: req.GetMemoryLimit().Value, - } - - log = log.With().Int("threads", settings.Threads).Str("memory_limit", settings.MemoryLimit).Logger() - - err := h.analyticsDB.PatchSettingsUsage(ctx, settings) - if err != nil { - log.Error().Err(err).Msg("failed to update the usage settings") - return nil, err - } - - log.Warn().Msg("updated the usage settings") - return &api.PatchSettingsUsageCreated{}, nil -} diff --git a/core/services/users.go b/core/services/users.go index 1e740c31..81cd9d16 100644 --- a/core/services/users.go +++ b/core/services/users.go @@ -2,12 +2,14 @@ package services import ( "context" - "time" "github.com/go-faster/errors" "github.com/medama-io/medama/api" "github.com/medama-io/medama/model" "github.com/medama-io/medama/util/logger" + "github.com/shirou/gopsutil/v4/cpu" + "github.com/shirou/gopsutil/v4/disk" + "github.com/shirou/gopsutil/v4/mem" ) func (h *Handler) GetUser(ctx context.Context, params api.GetUserParams) (api.GetUserRes, error) { @@ -31,13 +33,67 @@ func (h *Handler) GetUser(ctx context.Context, params api.GetUserParams) (api.Ge } return &api.UserGet{ - Username: user.Username, - Language: api.UserGetLanguage(user.Language), + Username: user.Username, + Settings: api.UserSettings{ + Language: api.NewOptUserSettingsLanguage(api.UserSettingsLanguage(user.Settings.Language)), + ScriptType: api.NewOptUserSettingsScriptType(api.UserSettingsScriptType(user.Settings.ScriptType)), + }, DateCreated: user.DateCreated, DateUpdated: user.DateUpdated, }, nil } +func (h *Handler) GetUserUsage(ctx context.Context, params api.GetUserUsageParams) (api.GetUserUsageRes, error) { + // CPU statistics. + cpuCores, err := cpu.CountsWithContext(ctx, false) + if err != nil { + return nil, err + } + cpuThreads, err := cpu.CountsWithContext(ctx, true) + if err != nil { + return nil, err + } + + cpuUsageArr, err := cpu.PercentWithContext(ctx, 0, false) + if err != nil { + return nil, err + } + // Get the average CPU usage. + cpuUsage := 0.0 + for _, v := range cpuUsageArr { + cpuUsage += v + } + cpuUsage /= float64(len(cpuUsageArr)) + + // Memory statistics. + vmStat, err := mem.VirtualMemoryWithContext(ctx) + if err != nil { + return nil, err + } + + // Disk statistics. + diskStat, err := disk.UsageWithContext(ctx, "/") + if err != nil { + return nil, err + } + + return &api.UserUsageGet{ + CPU: api.UserUsageGetCPU{ + Usage: float32(cpuUsage), + Cores: cpuCores, + Threads: cpuThreads, + }, + Memory: api.UserUsageGetMemory{ + Used: int64(vmStat.Used), + Total: int64(vmStat.Total), + }, + Disk: api.UserUsageGetDisk{ + Used: int64(diskStat.Used), + Total: int64(diskStat.Total), + }, + }, nil +} + func (h *Handler) PatchUser(ctx context.Context, req *api.UserPatch, params api.PatchUserParams) (api.PatchUserRes, error) { log := logger.Get() if h.auth.IsDemoMode { @@ -65,11 +121,10 @@ func (h *Handler) PatchUser(ctx context.Context, req *api.UserPatch, params api. } // Update values - dateUpdated := time.Now().Unix() - username := req.Username.Value - if username != "" { + if req.Username.IsSet() { + username := req.Username.Value user.Username = username - err = h.db.UpdateUserUsername(ctx, user.ID, username, dateUpdated) + err = h.db.UpdateUserUsername(ctx, user.ID, username) if err != nil { log := log.With().Str("username", username).Err(err).Logger() @@ -88,24 +143,51 @@ func (h *Handler) PatchUser(ctx context.Context, req *api.UserPatch, params api. } } - password := req.Password.Value - if password != "" { + if req.Password.IsSet() { + password := req.Password.Value pwdHash, err := h.auth.HashPassword(password) if err != nil { log.Error().Err(err).Msg("failed to hash password") return nil, errors.Wrap(err, "services") } - err = h.db.UpdateUserPassword(ctx, user.ID, pwdHash, dateUpdated) + err = h.db.UpdateUserPassword(ctx, user.ID, pwdHash) if err != nil { log.Error().Err(err).Msg("failed to update user password") return nil, errors.Wrap(err, "services") } } + // Settings + if req.Settings.IsSet() { + settings := user.Settings + if req.Settings.Value.Language.IsSet() { + settings.Language = string(req.Settings.Value.Language.Value) + } + if req.Settings.Value.ScriptType.IsSet() { + settings.ScriptType = string(req.Settings.Value.ScriptType.Value) + } + + err = h.db.UpdateSettings(ctx, user.ID, settings) + if err != nil { + log.Error().Err(err).Msg("failed to update user settings") + return nil, errors.Wrap(err, "services") + } + + // Also update live runtime config. + err = h.runtimeConfig.UpdateConfig(ctx, h.db, settings) + if err != nil { + log.Error().Err(err).Msg("failed to update runtime config") + return nil, errors.Wrap(err, "services") + } + } + return &api.UserGet{ - Username: user.Username, - Language: api.UserGetLanguage(user.Language), + Username: user.Username, + Settings: api.UserSettings{ + Language: api.NewOptUserSettingsLanguage(api.UserSettingsLanguage(user.Settings.Language)), + ScriptType: api.NewOptUserSettingsScriptType(api.UserSettingsScriptType(user.Settings.ScriptType)), + }, DateCreated: user.DateCreated, DateUpdated: user.DateUpdated, }, nil @@ -141,7 +223,6 @@ func (h *Handler) DeleteUser(ctx context.Context, params api.DeleteUserParams) ( if err != nil { log.Error(). Str("username", user.Username). - Str("language", user.Language). Int64("date_created", user.DateCreated). Int64("date_updated", user.DateUpdated). Err(err). diff --git a/dashboard/app/api/settings.ts b/dashboard/app/api/settings.ts deleted file mode 100644 index 02136081..00000000 --- a/dashboard/app/api/settings.ts +++ /dev/null @@ -1,18 +0,0 @@ -import { type ClientOptions, type DataResponse, client } from './client'; - -const usageGet = async (): Promise> => { - const res = await client('/settings/usage', {}); - return { - data: await res.json(), - res, - }; -}; - -const usagePatch = async ( - opts: ClientOptions<'SettingsUsagePatch'>, -): Promise => { - const res = await client('/settings/usage', { method: 'PATCH', ...opts }); - return { res }; -}; - -export { usageGet, usagePatch }; diff --git a/dashboard/app/api/types.d.ts b/dashboard/app/api/types.d.ts index c5acbfb3..eb58e5d0 100644 --- a/dashboard/app/api/types.d.ts +++ b/dashboard/app/api/types.d.ts @@ -84,7 +84,7 @@ export interface paths { patch?: never; trace?: never; }; - "/settings/usage": { + "/user": { parameters: { query?: never; header?: never; @@ -92,23 +92,27 @@ export interface paths { cookie?: never; }; /** - * Get Resource Usage - * @description Get the current CPU, memory and disk usage of the server. + * Get User Info + * @description Retrieve the information of the user with the matching user ID. */ - get: operations["get-settings-usage"]; + get: operations["get-user"]; put?: never; post?: never; - delete?: never; + /** + * Delete User + * @description Delete a user account. + */ + delete: operations["delete-user"]; options?: never; head?: never; /** - * Update Resource Usage - * @description Update the resource usage settings of the server. + * Update User Info + * @description Update a user account's details. */ - patch: operations["patch-settings-usage"]; + patch: operations["patch-user"]; trace?: never; }; - "/user": { + "/user/usage": { parameters: { query?: never; header?: never; @@ -116,24 +120,16 @@ export interface paths { cookie?: never; }; /** - * Get User Info - * @description Retrieve the information of the user with the matching user ID. + * Get Resource Usage + * @description Get the current CPU, memory and disk usage of the server. */ - get: operations["get-user"]; + get: operations["get-user-usage"]; put?: never; post?: never; - /** - * Delete User - * @description Delete a user account. - */ - delete: operations["delete-user"]; + delete?: never; options?: never; head?: never; - /** - * Update User Info - * @description Update a user account's details. - */ - patch: operations["patch-user"]; + patch?: never; trace?: never; }; "/websites": { @@ -487,7 +483,7 @@ export interface components { * @description Event with custom properties. */ EventCustom: { - /** @description Beacon ID generated for each user to link multiple events on the same page together. */ + /** @description Optional Beacon ID generated for each user to link multiple events on the same page together. */ b?: string; /** @description Group name of events. Currently, only the hostname is supported. */ g: string; @@ -529,21 +525,57 @@ export interface components { not_in?: string; }; /** - * UserGet - * @description Response body for getting a user. + * UserSettings + * @description Response body for getting user settings. */ - UserGet: { - username: string; + UserSettings: { /** * @default en * @enum {string} */ - language: "en"; + language?: "en"; + /** + * @default default + * @enum {string} + */ + script_type?: "default" | "tagged-events"; + }; + /** + * UserGet + * @description Response body for getting a user. + */ + UserGet: { + username: string; + settings: components["schemas"]["UserSettings"]; /** Format: int64 */ dateCreated: number; /** Format: int64 */ dateUpdated: number; }; + /** + * UserUsageGet + * @description Response body for getting CPU, memory and disk usage of the server. + */ + UserUsageGet: { + cpu: { + /** Format: float */ + usage: number; + cores: number; + threads: number; + }; + memory: { + /** Format: int64 */ + used: number; + /** Format: int64 */ + total: number; + }; + disk: { + /** Format: int64 */ + used: number; + /** Format: int64 */ + total: number; + }; + }; /** * UserPatch * @description Request body for updating a user. @@ -552,11 +584,7 @@ export interface components { username?: string; /** Format: password */ password?: string; - /** - * @default en - * @enum {string} - */ - language: "en"; + settings?: components["schemas"]["UserSettings"]; }; /** * WebsiteGet @@ -585,42 +613,6 @@ export interface components { /** Format: hostname */ hostname?: string; }; - /** - * SettingsUsageGet - * @description Response body for getting CPU, memory and disk usage of the server. - */ - SettingsUsageGet: { - cpu: { - /** Format: float */ - usage: number; - cores: number; - threads: number; - }; - memory: { - /** Format: int64 */ - used: number; - /** Format: int64 */ - total: number; - }; - disk: { - /** Format: int64 */ - used: number; - /** Format: int64 */ - total: number; - }; - metadata: { - threads?: number; - memory_limit?: string; - }; - }; - /** - * SettingsUsagePatch - * @description Request body for updating the resource limits of the application. - */ - SettingsUsagePatch: { - threads?: number; - memory_limit?: string; - }; /** StatsSummary */ StatsSummary: { current: { @@ -1136,7 +1128,7 @@ export interface operations { 500: components["responses"]["InternalServerError"]; }; }; - "get-settings-usage": { + "get-user": { parameters: { query?: never; header?: never; @@ -1148,20 +1140,22 @@ export interface operations { }; requestBody?: never; responses: { - /** @description OK */ + /** @description User Found */ 200: { headers: { [name: string]: unknown; }; content: { - "application/json": components["schemas"]["SettingsUsageGet"]; + "application/json": components["schemas"]["UserGet"]; }; }; + 400: components["responses"]["BadRequestError"]; 401: components["responses"]["UnauthorisedError"]; + 404: components["responses"]["NotFoundError"]; 500: components["responses"]["InternalServerError"]; }; }; - "patch-settings-usage": { + "delete-user": { parameters: { query?: never; header?: never; @@ -1171,15 +1165,10 @@ export interface operations { _me_sess: components["parameters"]["SessionAuth"]; }; }; - /** @description Resource usage settings to update. */ - requestBody: { - content: { - "application/json": components["schemas"]["SettingsUsagePatch"]; - }; - }; + requestBody?: never; responses: { - /** @description Success */ - 201: { + /** @description Success No Content */ + 204: { headers: { [name: string]: unknown; }; @@ -1188,10 +1177,11 @@ export interface operations { 400: components["responses"]["BadRequestError"]; 401: components["responses"]["UnauthorisedError"]; 403: components["responses"]["ForbiddenError"]; + 404: components["responses"]["NotFoundError"]; 500: components["responses"]["InternalServerError"]; }; }; - "get-user": { + "patch-user": { parameters: { query?: never; header?: never; @@ -1201,9 +1191,14 @@ export interface operations { _me_sess: components["parameters"]["SessionAuth"]; }; }; - requestBody?: never; + /** @description User details to update. */ + requestBody: { + content: { + "application/json": components["schemas"]["UserPatch"]; + }; + }; responses: { - /** @description User Found */ + /** @description Success */ 200: { headers: { [name: string]: unknown; @@ -1214,37 +1209,13 @@ export interface operations { }; 400: components["responses"]["BadRequestError"]; 401: components["responses"]["UnauthorisedError"]; - 404: components["responses"]["NotFoundError"]; - 500: components["responses"]["InternalServerError"]; - }; - }; - "delete-user": { - parameters: { - query?: never; - header?: never; - path?: never; - cookie: { - /** @description Session token for authentication. */ - _me_sess: components["parameters"]["SessionAuth"]; - }; - }; - requestBody?: never; - responses: { - /** @description Success No Content */ - 204: { - headers: { - [name: string]: unknown; - }; - content?: never; - }; - 400: components["responses"]["BadRequestError"]; - 401: components["responses"]["UnauthorisedError"]; 403: components["responses"]["ForbiddenError"]; 404: components["responses"]["NotFoundError"]; + 409: components["responses"]["ConflictError"]; 500: components["responses"]["InternalServerError"]; }; }; - "patch-user": { + "get-user-usage": { parameters: { query?: never; header?: never; @@ -1254,27 +1225,18 @@ export interface operations { _me_sess: components["parameters"]["SessionAuth"]; }; }; - /** @description User details to update. */ - requestBody: { - content: { - "application/json": components["schemas"]["UserPatch"]; - }; - }; + requestBody?: never; responses: { - /** @description Success */ + /** @description OK */ 200: { headers: { [name: string]: unknown; }; content: { - "application/json": components["schemas"]["UserGet"]; + "application/json": components["schemas"]["UserUsageGet"]; }; }; - 400: components["responses"]["BadRequestError"]; 401: components["responses"]["UnauthorisedError"]; - 403: components["responses"]["ForbiddenError"]; - 404: components["responses"]["NotFoundError"]; - 409: components["responses"]["ConflictError"]; 500: components["responses"]["InternalServerError"]; }; }; diff --git a/dashboard/app/api/user.ts b/dashboard/app/api/user.ts index da892ffd..1fa80a5e 100644 --- a/dashboard/app/api/user.ts +++ b/dashboard/app/api/user.ts @@ -9,6 +9,13 @@ const userGet = async ( return { data: await res.json(), res }; }; +const userUsageGet = async ( + opts?: ClientOptions, +): Promise> => { + const res = await client('/user/usage', { method: 'GET', ...opts }); + return { data: await res.json(), res }; +}; + const userUpdate = async ( opts: ClientOptions<'UserPatch'>, ): Promise> => { @@ -29,4 +36,4 @@ const userLoggedIn = async () => { throw redirect('/login'); }; -export { userGet, userLoggedIn, userUpdate }; +export { userGet, userLoggedIn, userUpdate, userUsageGet }; diff --git a/dashboard/app/routes/settings.account.tsx b/dashboard/app/routes/settings.account.tsx index 7798d4e2..614ed962 100644 --- a/dashboard/app/routes/settings.account.tsx +++ b/dashboard/app/routes/settings.account.tsx @@ -72,7 +72,9 @@ export const clientAction = async ({ request }: ClientActionFunctionArgs) => { body: { username: getString(body, 'username'), password: getString(body, 'password'), - language: 'en', + settings: { + language: 'en', + }, }, noThrow: true, }); @@ -121,7 +123,7 @@ export default function Index() { const handleSubmit = (values: typeof account.values) => { submit(values, { method: 'POST' }); - account.reset(); + account.setFieldValue('password', ''); }; return ( diff --git a/dashboard/app/routes/settings.usage.tsx b/dashboard/app/routes/settings.usage.tsx index 399ecd65..e26fdb1f 100644 --- a/dashboard/app/routes/settings.usage.tsx +++ b/dashboard/app/routes/settings.usage.tsx @@ -1,33 +1,26 @@ import { SimpleGrid } from '@mantine/core'; -import { useForm, zodResolver } from '@mantine/form'; -import { notifications } from '@mantine/notifications'; import { - type ClientActionFunctionArgs, type MetaFunction, json, useLoaderData, useRevalidator, - useSubmit, } from '@remix-run/react'; -import { useEffect, useMemo } from 'react'; -import { z } from 'zod'; +import { useEffect } from 'react'; -import { usageGet, usagePatch } from '@/api/settings'; -import { TextInput, TextInputWithTooltip } from '@/components/settings/Input'; +import { userUsageGet } from '@/api/user'; import { ResourcePanel, ResourcePanelCPU, } from '@/components/settings/Resource'; -import { Section, SectionWrapper } from '@/components/settings/Section'; +import { SectionWrapper } from '@/components/settings/Section'; import { useInterval } from '@/hooks/use-interval'; -import { getNumber, getString, getType } from '@/utils/form'; export const meta: MetaFunction = () => { return [{ title: 'Usage Settings | Medama' }]; }; export const clientLoader = async () => { - const { data } = await usageGet(); + const { data } = await userUsageGet(); if (!data) { throw json('Failed to get server usage metrics.', { @@ -40,135 +33,24 @@ export const clientLoader = async () => { }); }; -export const clientAction = async ({ request }: ClientActionFunctionArgs) => { - const body = await request.formData(); - const type = getType(body); - - let res: Response | undefined; - switch (type) { - case 'usage': { - const update = await usagePatch({ - body: { - threads: getNumber(body, 'threads'), - memory_limit: getString(body, 'memory_limit'), - }, - noThrow: true, - }); - res = update.res; - break; - } - default: - throw new Response('Invalid setting type.', { - status: 400, - }); - } - - if (!res || !res.ok) { - throw new Response(res?.statusText || 'Failed to update usage settings.', { - status: res?.status || 500, - }); - } - - const message = 'Successfully updated usage settings.'; - notifications.show({ - title: 'Success.', - message, - withBorder: true, - color: '#17cd8c', - }); - return json({ message }); -}; - export default function Index() { const { usage } = useLoaderData(); - const submit = useSubmit(); const revalidator = useRevalidator(); const interval = useInterval(revalidator.revalidate, 2500); - const { cpu, memory, disk, metadata } = usage; + const { cpu, memory, disk } = usage; useEffect(() => { interval.start(); return interval.stop; }, [interval.start, interval.stop]); - const usageSchema = useMemo( - () => - z.object({ - _setting: z.literal('usage'), - threads: z.preprocess( - (x) => (x ? x : undefined), - z.coerce - .number() - .int() - .min(1, { - message: 'Threads must be at least 1.', - }) - .max(metadata.threads ?? 1, { - message: `Threads must be less than or equal to ${metadata.threads}.`, - }) - .optional(), - ), - memory_limit: z - .string() - .regex(/^(\d+(?:\.\d+)?)(MB|GB|TB|MiB|GiB|TiB)$/, { - message: - 'Invalid memory limit format. Supported formats: 1MB, 1MiB, 1GB, 1GiB, 1TB, 1TiB.', - }) - .optional(), - }), - [metadata.threads], - ); - - const usageForm = useForm({ - mode: 'uncontrolled', - initialValues: { - _setting: 'usage', - threads: String(metadata.threads), - memory_limit: metadata.memory_limit, - }, - validate: zodResolver(usageSchema), - }); - - const handleSubmit = (values: Partial) => { - submit(values, { method: 'POST' }); - usageForm.reset(); - }; - return ( - <> - - - - - - - -
- - - -
- + + + + + + + ); } diff --git a/dashboard/package.json b/dashboard/package.json index b8f5b5fb..fbfa0db5 100644 --- a/dashboard/package.json +++ b/dashboard/package.json @@ -7,7 +7,7 @@ "dev": "remix vite:dev", "build": "remix vite:build", "preview": "vite preview", - "generate": "openapi-typescript ../core/openapi.yaml -o ./app/api/types.d.ts", + "generate": "openapi-typescript ../core/openapi.yaml -o ./app/api/types.d.ts --default-non-nullable false", "lint": "biome check --write .", "lint:ci": "biome check .", "typecheck": "tsc"