| package httpdriver |
|
|
| import ( |
| "context" |
| "errors" |
| "fmt" |
| "net/http" |
|
|
| "github.com/samber/lo" |
|
|
| "github.com/openmeterio/openmeter/api" |
| "github.com/openmeterio/openmeter/openmeter/notification" |
| "github.com/openmeterio/openmeter/openmeter/notification/internal" |
| "github.com/openmeterio/openmeter/pkg/framework/commonhttp" |
| "github.com/openmeterio/openmeter/pkg/framework/transport/httptransport" |
| "github.com/openmeterio/openmeter/pkg/models" |
| "github.com/openmeterio/openmeter/pkg/pagination" |
| "github.com/openmeterio/openmeter/pkg/sortx" |
| ) |
|
|
| type ( |
| ListRulesRequest = notification.ListRulesInput |
| ListRulesResponse = api.NotificationRulePaginatedResponse |
| ListRulesParams = api.ListNotificationRulesParams |
| ListRulesHandler httptransport.HandlerWithArgs[ListRulesRequest, ListRulesResponse, ListRulesParams] |
| ) |
|
|
| func (h *handler) ListRules() ListRulesHandler { |
| return httptransport.NewHandlerWithArgs( |
| func(ctx context.Context, r *http.Request, params ListRulesParams) (ListRulesRequest, error) { |
| ns, err := h.resolveNamespace(ctx) |
| if err != nil { |
| return ListRulesRequest{}, fmt.Errorf("failed to resolve namespace: %w", err) |
| } |
|
|
| req := ListRulesRequest{ |
| Namespaces: []string{ns}, |
| IncludeDisabled: lo.FromPtrOr(params.IncludeDisabled, notification.DefaultDisabled), |
| OrderBy: notification.OrderBy(lo.FromPtrOr(params.OrderBy, api.NotificationRuleOrderById)), |
| Order: sortx.Order(lo.FromPtrOr(params.Order, api.SortOrderASC)), |
| Page: pagination.Page{ |
| PageSize: lo.FromPtrOr(params.PageSize, notification.DefaultPageSize), |
| PageNumber: lo.FromPtrOr(params.Page, notification.DefaultPageNumber), |
| }, |
| } |
|
|
| return req, nil |
| }, |
| func(ctx context.Context, request ListRulesRequest) (ListRulesResponse, error) { |
| resp, err := h.service.ListRules(ctx, request) |
| if err != nil { |
| return ListRulesResponse{}, fmt.Errorf("failed to list rules: %w", err) |
| } |
|
|
| items := make([]api.NotificationRule, 0, len(resp.Items)) |
|
|
| for _, rule := range resp.Items { |
| var item CreateRuleResponse |
|
|
| item, err = FromRule(rule) |
| if err != nil { |
| return ListRulesResponse{}, fmt.Errorf("failed to cast rule to notification rule: %w", err) |
| } |
|
|
| items = append(items, item) |
| } |
|
|
| return ListRulesResponse{ |
| Items: items, |
| Page: resp.Page.PageNumber, |
| PageSize: resp.Page.PageSize, |
| TotalCount: resp.TotalCount, |
| }, nil |
| }, |
| commonhttp.JSONResponseEncoderWithStatus[ListRulesResponse](http.StatusOK), |
| httptransport.AppendOptions( |
| h.options, |
| httptransport.WithOperationName("listNotificationRules"), |
| httptransport.WithErrorEncoder(errorEncoder()), |
| )..., |
| ) |
| } |
|
|
| type ( |
| CreateRuleRequest = notification.CreateRuleInput |
| CreateRuleResponse = api.NotificationRule |
| CreateRuleHandler httptransport.Handler[CreateRuleRequest, CreateRuleResponse] |
| ) |
|
|
| func (h *handler) CreateRule() CreateRuleHandler { |
| return httptransport.NewHandler( |
| func(ctx context.Context, r *http.Request) (CreateRuleRequest, error) { |
| body := api.NotificationRuleCreateRequest{} |
| if err := commonhttp.JSONRequestBodyDecoder(r, &body); err != nil { |
| return CreateRuleRequest{}, fmt.Errorf("field to decode create rule request: %w", err) |
| } |
|
|
| ns, err := h.resolveNamespace(ctx) |
| if err != nil { |
| return CreateRuleRequest{}, fmt.Errorf("failed to resolve namespace: %w", err) |
| } |
|
|
| value, err := body.ValueByDiscriminator() |
| if err != nil { |
| return CreateRuleRequest{}, fmt.Errorf("failed to get request type: %w", err) |
| } |
|
|
| var req CreateRuleRequest |
|
|
| switch v := value.(type) { |
| case api.NotificationRuleBalanceThresholdCreateRequest: |
| req = AsRuleBalanceThresholdCreateRequest(v, ns) |
| case api.NotificationRuleEntitlementResetCreateRequest: |
| req = AsRuleEntitlementResetCreateRequest(v, ns) |
| case api.NotificationRuleInvoiceCreatedCreateRequest: |
| req = AsRuleInvoiceCreatedCreateRequest(v, ns) |
| case api.NotificationRuleInvoiceUpdatedCreateRequest: |
| req = AsRuleInvoiceUpdatedCreateRequest(v, ns) |
| } |
|
|
| return req, nil |
| }, |
| func(ctx context.Context, request CreateRuleRequest) (CreateRuleResponse, error) { |
| rule, err := h.service.CreateRule(ctx, request) |
| if err != nil { |
| return CreateRuleResponse{}, fmt.Errorf("failed to create rule: %w", err) |
| } |
|
|
| if rule == nil { |
| return CreateRuleResponse{}, errors.New("failed to create rule: nil rule returned") |
| } |
|
|
| return FromRule(*rule) |
| }, |
| commonhttp.JSONResponseEncoderWithStatus[CreateRuleResponse](http.StatusCreated), |
| httptransport.AppendOptions( |
| h.options, |
| httptransport.WithOperationName("createNotificationRule"), |
| httptransport.WithErrorEncoder(errorEncoder()), |
| )..., |
| ) |
| } |
|
|
| type ( |
| UpdateRuleRequest = notification.UpdateRuleInput |
| UpdateRuleResponse = api.NotificationRule |
| UpdateRuleHandler httptransport.HandlerWithArgs[UpdateRuleRequest, UpdateRuleResponse, string] |
| ) |
|
|
| func (h *handler) UpdateRule() UpdateRuleHandler { |
| return httptransport.NewHandlerWithArgs( |
| func(ctx context.Context, r *http.Request, ruleID string) (UpdateRuleRequest, error) { |
| body := api.NotificationRuleCreateRequest{} |
| if err := commonhttp.JSONRequestBodyDecoder(r, &body); err != nil { |
| return UpdateRuleRequest{}, fmt.Errorf("field to decode update rule request: %w", err) |
| } |
|
|
| ns, err := h.resolveNamespace(ctx) |
| if err != nil { |
| return UpdateRuleRequest{}, fmt.Errorf("failed to resolve namespace: %w", err) |
| } |
|
|
| value, err := body.ValueByDiscriminator() |
| if err != nil { |
| return UpdateRuleRequest{}, fmt.Errorf("failed to get request type: %w", err) |
| } |
|
|
| var req UpdateRuleRequest |
|
|
| switch v := value.(type) { |
| case api.NotificationRuleBalanceThresholdCreateRequest: |
| req = AsRuleBalanceThresholdUpdateRequest(v, ns, ruleID) |
| case api.NotificationRuleEntitlementResetCreateRequest: |
| req = AsRuleEntitlementResetUpdateRequest(v, ns, ruleID) |
| case api.NotificationRuleInvoiceCreatedCreateRequest: |
| req = AsRuleInvoiceCreatedUpdateRequest(v, ns, ruleID) |
| case api.NotificationRuleInvoiceUpdatedCreateRequest: |
| req = AsRuleInvoiceUpdatedUpdateRequest(v, ns, ruleID) |
| } |
|
|
| return req, nil |
| }, |
| func(ctx context.Context, request UpdateRuleRequest) (UpdateRuleResponse, error) { |
| rule, err := h.service.UpdateRule(ctx, request) |
| if err != nil { |
| return UpdateRuleResponse{}, fmt.Errorf("failed to update rule: %w", err) |
| } |
|
|
| if rule == nil { |
| return CreateRuleResponse{}, errors.New("failed to create rule: nil rule returned") |
| } |
|
|
| return FromRule(*rule) |
| }, |
| commonhttp.JSONResponseEncoderWithStatus[UpdateRuleResponse](http.StatusOK), |
| httptransport.AppendOptions( |
| h.options, |
| httptransport.WithOperationName("updateNotificationRule"), |
| httptransport.WithErrorEncoder(errorEncoder()), |
| )..., |
| ) |
| } |
|
|
| type ( |
| DeleteRuleRequest = notification.DeleteRuleInput |
| DeleteRuleResponse = interface{} |
| DeleteRuleHandler httptransport.HandlerWithArgs[DeleteRuleRequest, DeleteRuleResponse, string] |
| ) |
|
|
| func (h *handler) DeleteRule() DeleteRuleHandler { |
| return httptransport.NewHandlerWithArgs( |
| func(ctx context.Context, r *http.Request, ruleID string) (DeleteRuleRequest, error) { |
| ns, err := h.resolveNamespace(ctx) |
| if err != nil { |
| return DeleteRuleRequest{}, fmt.Errorf("failed to resolve namespace: %w", err) |
| } |
|
|
| return DeleteRuleRequest{ |
| Namespace: ns, |
| ID: ruleID, |
| }, nil |
| }, |
| func(ctx context.Context, request DeleteRuleRequest) (DeleteRuleResponse, error) { |
| err := h.service.DeleteRule(ctx, request) |
| if err != nil { |
| return nil, fmt.Errorf("failed to delete rule: %w", err) |
| } |
|
|
| return nil, nil |
| }, |
| commonhttp.EmptyResponseEncoder[DeleteChannelResponse](http.StatusNoContent), |
| httptransport.AppendOptions( |
| h.options, |
| httptransport.WithOperationName("deleteNotificationRule"), |
| httptransport.WithErrorEncoder(errorEncoder()), |
| )..., |
| ) |
| } |
|
|
| type ( |
| GetRuleRequest = notification.GetRuleInput |
| GetRuleResponse = api.NotificationRule |
| GetRuleHandler httptransport.HandlerWithArgs[GetRuleRequest, GetRuleResponse, string] |
| ) |
|
|
| func (h *handler) GetRule() GetRuleHandler { |
| return httptransport.NewHandlerWithArgs( |
| func(ctx context.Context, r *http.Request, ruleID string) (GetRuleRequest, error) { |
| ns, err := h.resolveNamespace(ctx) |
| if err != nil { |
| return GetRuleRequest{}, fmt.Errorf("failed to resolve namespace: %w", err) |
| } |
|
|
| return GetRuleRequest{ |
| Namespace: ns, |
| ID: ruleID, |
| }, nil |
| }, |
| func(ctx context.Context, request GetRuleRequest) (GetRuleResponse, error) { |
| rule, err := h.service.GetRule(ctx, request) |
| if err != nil { |
| return GetRuleResponse{}, fmt.Errorf("failed to get rule: %w", err) |
| } |
|
|
| if rule == nil { |
| return CreateRuleResponse{}, errors.New("failed to create rule: nil rule returned") |
| } |
|
|
| return FromRule(*rule) |
| }, |
| commonhttp.JSONResponseEncoderWithStatus[GetRuleResponse](http.StatusOK), |
| httptransport.AppendOptions( |
| h.options, |
| httptransport.WithOperationName("getNotificationRule"), |
| httptransport.WithErrorEncoder(errorEncoder()), |
| )..., |
| ) |
| } |
|
|
| type TestRuleRequest struct { |
| models.NamespacedModel |
|
|
| |
| RuleID string `json:"ruleId"` |
| } |
|
|
| type ( |
| TestRuleResponse = api.NotificationEvent |
| TestRuleHandler httptransport.HandlerWithArgs[TestRuleRequest, TestRuleResponse, string] |
| ) |
|
|
| func (h *handler) TestRule() TestRuleHandler { |
| return httptransport.NewHandlerWithArgs( |
| func(ctx context.Context, r *http.Request, ruleID string) (TestRuleRequest, error) { |
| ns, err := h.resolveNamespace(ctx) |
| if err != nil { |
| return TestRuleRequest{}, fmt.Errorf("failed to resolve namespace: %w", err) |
| } |
|
|
| req := TestRuleRequest{ |
| NamespacedModel: models.NamespacedModel{ |
| Namespace: ns, |
| }, |
| RuleID: ruleID, |
| } |
|
|
| return req, nil |
| }, |
| func(ctx context.Context, request TestRuleRequest) (TestRuleResponse, error) { |
| rule, err := h.service.GetRule(ctx, notification.GetRuleInput{ |
| Namespace: request.NamespacedModel.Namespace, |
| ID: request.RuleID, |
| }) |
| if err != nil { |
| return TestRuleResponse{}, fmt.Errorf("failed to get rule: %w", err) |
| } |
|
|
| testEvent, err := h.testEventGenerator.Generate(ctx, internal.EventGeneratorInput{ |
| Namespace: request.Namespace, |
| EventType: rule.Type, |
| }) |
| if err != nil { |
| return TestRuleResponse{}, fmt.Errorf("failed to generate test event: %w", err) |
| } |
|
|
| event, err := h.service.CreateEvent(ctx, notification.CreateEventInput{ |
| NamespacedModel: request.NamespacedModel, |
| Type: rule.Type, |
| Payload: testEvent, |
| RuleID: rule.ID, |
| Annotations: models.Annotations{ |
| notification.AnnotationRuleTestEvent: true, |
| }, |
| }) |
| if err != nil { |
| return TestRuleResponse{}, fmt.Errorf("failed to create test event: %w", err) |
| } |
|
|
| if event == nil { |
| return TestRuleResponse{}, errors.New("failed to create test event: nil event returned") |
| } |
|
|
| return FromEvent(*event) |
| }, |
| commonhttp.JSONResponseEncoderWithStatus[TestRuleResponse](http.StatusOK), |
| httptransport.AppendOptions( |
| h.options, |
| httptransport.WithOperationName("createNotificationEvent"), |
| httptransport.WithErrorEncoder(errorEncoder()), |
| )..., |
| ) |
| } |
|
|