Leon4gr45's picture
Upload folder using huggingface_hub (part 4)
1f10f31 verified
Raw
History Blame Contribute Delete
6.8 kB
package subscriptions
import (
"context"
"errors"
"fmt"
"net/http"
"github.com/samber/lo"
api "github.com/openmeterio/openmeter/api/v3"
"github.com/openmeterio/openmeter/api/v3/apierrors"
"github.com/openmeterio/openmeter/api/v3/request"
"github.com/openmeterio/openmeter/openmeter/customer"
"github.com/openmeterio/openmeter/openmeter/productcatalog"
"github.com/openmeterio/openmeter/openmeter/productcatalog/plan"
plansubscription "github.com/openmeterio/openmeter/openmeter/productcatalog/subscription"
"github.com/openmeterio/openmeter/pkg/framework/commonhttp"
"github.com/openmeterio/openmeter/pkg/framework/transport/httptransport"
models "github.com/openmeterio/openmeter/pkg/models"
)
type (
CreateSubscriptionRequest = plansubscription.CreateSubscriptionRequest
CreateSubscriptionResponse = api.BillingSubscription
CreateSubscriptionHandler = httptransport.Handler[CreateSubscriptionRequest, CreateSubscriptionResponse]
)
// CreateSubscription returns a new httptransport.Handler for creating a subscription.
func (h *handler) CreateSubscription() CreateSubscriptionHandler {
return httptransport.NewHandler(
func(ctx context.Context, r *http.Request) (plansubscription.CreateSubscriptionRequest, error) {
// Parse the request body
body := api.BillingSubscriptionCreate{}
if err := request.ParseBody(r, &body); err != nil {
return CreateSubscriptionRequest{}, err
}
// Resolve the namespace
ns, err := h.resolveNamespace(ctx)
if err != nil {
return CreateSubscriptionRequest{}, err
}
var settlementMode *productcatalog.SettlementMode
if body.SettlementMode != nil {
settlementMode = lo.ToPtr(productcatalog.SettlementMode(*body.SettlementMode))
}
// Validate that either customer ID or customer key is provided
if body.Customer.Id == nil && body.Customer.Key == nil {
reason := "one of customer.id or customer.key is required"
return CreateSubscriptionRequest{}, apierrors.NewBadRequestError(
ctx,
errors.New(reason),
[]apierrors.InvalidParameter{
{
Field: "customer.id",
Reason: reason,
Source: apierrors.InvalidParamSourceBody,
Rule: "required",
},
{
Field: "customer.key",
Reason: reason,
Source: apierrors.InvalidParamSourceBody,
Rule: "required",
},
},
)
}
// Get the customer to validate it exists
customerEntity, err := h.getCustomerByIDOrKey(ctx, ns, body.Customer.Id, body.Customer.Key)
if err != nil {
return CreateSubscriptionRequest{}, fmt.Errorf("failed to get customer: %w", err)
}
// TODO: implement custom subscription creation
if body.Plan.Id == nil && body.Plan.Key == nil {
reason := "one of plan.id or plan.key is required"
// We use bad request error because not implemented does not provide the error context
return CreateSubscriptionRequest{}, apierrors.NewBadRequestError(
ctx,
errors.New(reason),
[]apierrors.InvalidParameter{
{
Field: "plan.id",
Reason: reason,
Source: apierrors.InvalidParamSourceBody,
Rule: "required",
},
{
Field: "plan.key",
Reason: reason,
Source: apierrors.InvalidParamSourceBody,
Rule: "required",
},
},
)
}
// Get the plan entity by ID or key to validate it exists
planEntity, err := h.getPlanByIDOrKey(ctx, ns, body.Plan.Id, body.Plan.Key, body.Plan.Version)
if err != nil {
return CreateSubscriptionRequest{}, fmt.Errorf("failed to get plan: %w", err)
}
// Convert the plan entity to a plan input
planInput := plansubscription.PlanInput{}
planInput.FromRef(&plansubscription.PlanRefInput{
Key: planEntity.Key,
Version: &planEntity.Version,
})
// Convert the request to a create subscription workflow input
subscriptionName := fmt.Sprintf("%s v%d", planEntity.Key, planEntity.Version)
workflowInput, err := FromAPIBillingSubscriptionCreate(
ns,
customerEntity.GetID(),
subscriptionName,
body,
)
if err != nil {
return CreateSubscriptionRequest{}, err
}
return plansubscription.CreateSubscriptionRequest{
WorkflowInput: workflowInput,
PlanInput: planInput,
SettlementMode: settlementMode,
}, nil
},
func(ctx context.Context, request plansubscription.CreateSubscriptionRequest) (CreateSubscriptionResponse, error) {
// Create the subscription from a plan
m, err := h.planSubscriptionService.Create(ctx, request)
if err != nil {
return CreateSubscriptionResponse{}, err
}
// Convert the subscription to an API subscription
return ToAPIBillingSubscription(m), nil
},
commonhttp.JSONResponseEncoderWithStatus[CreateSubscriptionResponse](http.StatusCreated),
httptransport.AppendOptions(
h.options,
httptransport.WithOperationName("create-subscription"),
httptransport.WithErrorEncoder(apierrors.GenericErrorEncoder()),
)...,
)
}
// getCustomerByIDOrKey gets a customer by ID or key helper function
// TODO: move this to the customer service
func (h *handler) getCustomerByIDOrKey(ctx context.Context, namespace string, customerID *string, customerKey *string) (*customer.Customer, error) {
var getCustomerInput customer.GetCustomerInput
if customerID != nil {
getCustomerInput = customer.GetCustomerInput{
CustomerID: &customer.CustomerID{
Namespace: namespace,
ID: *customerID,
},
}
} else if customerKey != nil {
getCustomerInput = customer.GetCustomerInput{
CustomerKey: &customer.CustomerKey{
Namespace: namespace,
Key: *customerKey,
},
}
} else {
return nil, fmt.Errorf("customer id or customer key is required")
}
return h.customerService.GetCustomer(ctx, getCustomerInput)
}
// getPlanByIDOrKey gets a plan by ID or key helper function
// TODO: move this to the plan service
func (h *handler) getPlanByIDOrKey(ctx context.Context, namespace string, planID *string, planKey *string, planVersion *int) (*plan.Plan, error) {
// Get the plan entity, to validate it exists
var getPlanInput plan.GetPlanInput
if planID != nil {
getPlanInput = plan.GetPlanInput{
NamespacedID: models.NamespacedID{
Namespace: namespace,
ID: *planID,
},
}
} else if planKey != nil {
getPlanInput = plan.GetPlanInput{}
// We use setters because namespace only exists on namespaced ID
// But here we don't have a namespaced ID
getPlanInput.Namespace = namespace
getPlanInput.Key = *planKey
if planVersion != nil {
getPlanInput.Version = *planVersion
} else {
getPlanInput.IncludeLatest = true
}
} else {
return nil, errors.New("plan id or plan key must be set")
}
// Get the plan entity
return h.planService.GetPlan(ctx, getPlanInput)
}