Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@ module github.com/devsy-org/admin-apis
go 1.27.0

require (
github.com/stripe/stripe-go/v81 v81.4.0
github.com/stripe/stripe-go/v87 v87.0.0
k8s.io/kube-openapi v0.0.0-20261001230523-97fa35140926
sigs.k8s.io/yaml v1.6.0
Expand All @@ -18,6 +17,7 @@ require (
github.com/go-openapi/swag/pools v0.27.1 // indirect
github.com/go-openapi/swag/typeutils v0.27.1 // indirect
github.com/google/gnostic-models v0.7.1 // indirect
github.com/shopspring/decimal v1.4.0 // indirect
go.yaml.in/yaml/v2 v2.4.3 // indirect
go.yaml.in/yaml/v3 v3.0.5 // indirect
google.golang.org/protobuf v1.36.11 // indirect
Expand Down
18 changes: 3 additions & 15 deletions go.sum
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/emicklei/go-restful/v3 v3.13.0 h1:C4Bl2xDndpU6nJ4bc1jXd+uTmYPVUwkD6bFY/oTyCes=
github.com/emicklei/go-restful/v3 v3.13.0/go.mod h1:6n3XBCmQQb25CM2LCACGz8ukIrRry+4bhvbpWn3mrbc=
github.com/go-openapi/jsonpointer v1.0.0 h1:kR9tHqY0CtZaOPVFm622dPVNhrvYpwr4uCxgL3h1H8s=
Expand All @@ -23,31 +22,20 @@ github.com/google/gnostic-models v0.7.1 h1:SisTfuFKJSKM5CPZkffwi6coztzzeYUhc3v4y
github.com/google/gnostic-models v0.7.1/go.mod h1:whL5G0m6dmc5cPxKc5bdKdEN3UjI7OUGxBlw57miDrQ=
github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8=
github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/shopspring/decimal v1.4.0 h1:bxl37RwXBklmTi0C79JfXCEBD1cqqHt0bbgBAGFp81k=
github.com/shopspring/decimal v1.4.0/go.mod h1:gawqmDU56v4yIKSwfBSFip1HdCCXN8/+DMd9qYNcwME=
github.com/stretchr/testify v1.12.1 h1:EuwCh5fleGS7H32xRwO3wRGT7DxrDhLAT6FF8MpWDWE=
github.com/stretchr/testify v1.12.1/go.mod h1:MDEgiDPPsNp5cuIrHPPCyornHKgEVbtFUmoNlxoYthg=
github.com/stripe/stripe-go/v81 v81.4.0 h1:AuD9XzdAvl193qUCSaLocf8H+nRopOouXhxqJUzCLbw=
github.com/stripe/stripe-go/v81 v81.4.0/go.mod h1:C/F4jlmnGNacvYtBp/LUHCvVUJEZffFQCobkzwY1WOo=
github.com/stripe/stripe-go/v87 v87.0.0 h1:dDztIAKst1hNfNpv4zo3zhVnoLiXJx0fH3Kl+KlGP6Y=
github.com/stripe/stripe-go/v87 v87.0.0/go.mod h1:UQKKBVL4DY/evB1M1KczpoCaJi1oFnZ/gRPKukRXYYA=
go.yaml.in/yaml/v2 v2.4.3 h1:6gvOSjQoTB3vt1l+CU+tSyi/HOjfOjRLJ4YwYZGwRO0=
go.yaml.in/yaml/v2 v2.4.3/go.mod h1:zSxWcmIDjOzPXpjlTTbAsKokqkDNAVtZO0WOMiT90s8=
go.yaml.in/yaml/v3 v3.0.5 h1:N6y/pJk8buWs9NY5ERU2HSMfm+IuD/OtfdAnq6kESPw=
go.yaml.in/yaml/v3 v3.0.5/go.mod h1:HVTZu1O7/Vkt2N+BFy8Zza+lnLsABggaTM2ZpNIGuKg=
golang.org/x/net v0.0.0-20210520170846-37e1c6afe023 h1:ADo5wSpq2gqaCGQWzk7S5vd//0iyyLeAratkEoG5dLE=
golang.org/x/net v0.0.0-20210520170846-37e1c6afe023/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
golang.org/x/text v0.3.6 h1:aRYxNxv6iGQlyVaZmk6ZgYEDa+Jg18DxebPSrd6bg1M=
golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
google.golang.org/protobuf v1.36.11 h1:fV6ZwhNocDyBLK0dj+fg8ektcVegBBuEolpbTQyBNVE=
google.golang.org/protobuf v1.36.11/go.mod h1:HTf+CrKn2C3g5S8VImy6tdcUvCska2kB7j23XfzDpco=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
k8s.io/kube-openapi v0.0.0-20261001230523-97fa35140926 h1:Fe0G8t8FaMDn2lpat0IHu3X9lHrVyGzDxhhCwKXKp28=
k8s.io/kube-openapi v0.0.0-20261001230523-97fa35140926/go.mod h1:3e2VxsK2svhjvkNik92kYU1a5kgau5tZeAuEWwoN4q0=
sigs.k8s.io/json v0.0.0-20250730193827-2d320260d730 h1:IpInykpT6ceI+QxKBbEflcR5EXP7sU1kvOlxwZh5txg=
Expand Down
112 changes: 54 additions & 58 deletions pkg/util/features/features.go
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
package features

import (
"context"
"fmt"
"maps"

"github.com/devsy-org/admin-apis/pkg/licenseapi"
stripe "github.com/stripe/stripe-go/v81"
stripeclient "github.com/stripe/stripe-go/v81/client"
stripe "github.com/stripe/stripe-go/v87"
)

const (
Expand All @@ -19,7 +19,7 @@ type SyncedFeature struct {
}

func EnsureFeatures(
stripeClient *stripeclient.API,
stripeClient *stripe.Client,
syncedFeatures map[string]SyncedFeature,
features []*licenseapi.Feature,
additionalAttachAllProducts []stripe.Product,
Expand Down Expand Up @@ -47,7 +47,7 @@ func EnsureFeatures(
}

func EnsureStripeFeatures(
stripeClient *stripeclient.API,
stripeClient *stripe.Client,
syncedFeatures map[string]SyncedFeature,
features []*licenseapi.Feature,
isLimit bool,
Expand Down Expand Up @@ -141,10 +141,11 @@ type EnsureFeatureParams struct {
}

func EnsureFeatureExists(
stripeClient *stripeclient.API,
stripeClient *stripe.Client,
syncedFeatures map[string]SyncedFeature,
params EnsureFeatureParams,
) error {
ctx := context.Background()
name := params.Name
displayName := params.DisplayName
extraMetadata := params.ExtraMetadata
Expand All @@ -158,7 +159,7 @@ func EnsureFeatureExists(
return nil
}

stripeParams := stripe.EntitlementsFeatureParams{
stripeParams := stripe.EntitlementsFeatureCreateParams{
Name: &displayName,
LookupKey: &name,
}
Expand All @@ -167,7 +168,7 @@ func EnsureFeatureExists(
stripeParams.AddMetadata(key, value)
}

feature, err := stripeClient.EntitlementsFeatures.New(&stripeParams)
feature, err := stripeClient.V1EntitlementsFeatures.Create(ctx, &stripeParams)
if err != nil {
return fmt.Errorf(
"failed to create Stripe feature from feature %s: %w",
Expand All @@ -181,32 +182,25 @@ func EnsureFeatureExists(
return nil
}

func FindFeature(stripeClient *stripeclient.API, id string) (*SyncedFeature, error) {
list := stripeClient.EntitlementsFeatures.List(&stripe.EntitlementsFeatureListParams{
func FindFeature(stripeClient *stripe.Client, id string) (*SyncedFeature, error) {
ctx := context.Background()
for feature, err := range stripeClient.V1EntitlementsFeatures.List(ctx, &stripe.EntitlementsFeatureListParams{
LookupKey: &id,
})
if err := list.Err(); err != nil {
return nil, fmt.Errorf(
"failed to list features while check if feature [%s] exists: %w",
id,
err,
)
}
if !list.Next() {
return nil, nil
}
feature, ok := list.Current().(*stripe.EntitlementsFeature)
if !ok {
return nil, fmt.Errorf("failed to ")
}
feat := &SyncedFeature{
Feature: feature,
}).All(ctx) {
if err != nil {
return nil, fmt.Errorf(
"failed to list features while check if feature [%s] exists: %w",
id,
err,
)
}
return &SyncedFeature{Feature: feature}, nil
}
return feat, nil
return nil, nil
}

func EnsureFeatureProducts(
stripeClient *stripeclient.API,
stripeClient *stripe.Client,
syncedFeatures map[string]SyncedFeature,
) error {
for key, feature := range syncedFeatures {
Expand All @@ -225,36 +219,36 @@ func EnsureFeatureProducts(
}

func EnsureFeatureProduct(
stripeClient *stripeclient.API,
stripeClient *stripe.Client,
syncedFeature *SyncedFeature,
) (*stripe.Product, error) {
productSearch := stripeClient.Products.Search(&stripe.ProductSearchParams{
ctx := context.Background()
for product, err := range stripeClient.V1Products.Search(ctx, &stripe.ProductSearchParams{
SearchParams: stripe.SearchParams{
Query: fmt.Sprintf(
metadataQueryFmt,
licenseapi.MetadataKeyProductForFeature,
syncedFeature.Feature.LookupKey,
),
},
})
if err := productSearch.Err(); err != nil {
return nil, err
}
if productSearch.Next() {
}).All(ctx) {
if err != nil {
return nil, err
}
// a product exists with features name
return productSearch.Product(), nil
return product, nil
}

usdCurrencyCode := "usd"
unit := int64(2000000) // sample placeholder price
interval := "year"
intervalCount := int64(1)
product, err := stripeClient.Products.New(&stripe.ProductParams{
product, err := stripeClient.V1Products.Create(ctx, &stripe.ProductCreateParams{
Name: &syncedFeature.Feature.Name,
DefaultPriceData: &stripe.ProductDefaultPriceDataParams{
DefaultPriceData: &stripe.ProductCreateDefaultPriceDataParams{
Currency: &usdCurrencyCode,
UnitAmount: &unit,
Recurring: &stripe.ProductDefaultPriceDataRecurringParams{
Recurring: &stripe.ProductCreateDefaultPriceDataRecurringParams{
Interval: &interval,
IntervalCount: &intervalCount,
},
Expand All @@ -267,7 +261,7 @@ func EnsureFeatureProduct(
return nil, err
}

_, err = stripeClient.ProductFeatures.New(&stripe.ProductFeatureParams{
_, err = stripeClient.V1ProductFeatures.Create(ctx, &stripe.ProductFeatureCreateParams{
Product: &product.ID,
EntitlementFeature: &syncedFeature.Feature.ID,
})
Expand All @@ -278,27 +272,26 @@ func EnsureFeatureProduct(
}

func EnsureAttachAll(
stripeClient *stripeclient.API,
stripeClient *stripe.Client,
features map[string]SyncedFeature,
attachTo []stripe.Product,
) error {
ctx := context.Background()
if attachTo == nil {
attachTo = []stripe.Product{}
}
productSearch := stripeClient.Products.Search(&stripe.ProductSearchParams{
for prod, err := range stripeClient.V1Products.Search(ctx, &stripe.ProductSearchParams{
SearchParams: stripe.SearchParams{
Query: fmt.Sprintf(
metadataQueryFmt,
licenseapi.MetadataKeyAttachAll,
licenseapi.MetadataValueTrue,
),
},
})
if err := productSearch.Err(); err != nil {
return err
}
for productSearch.Next() {
prod := productSearch.Product()
}).All(ctx) {
if err != nil {
return err
}
attachTo = append(attachTo, *prod)
}

Expand All @@ -319,10 +312,13 @@ func EnsureAttachAll(
for featureID, feat := range featuresToCheck {
metadataHiddenValue, ok := feat.Feature.Metadata[licenseapi.MetadataKeyFeatureIsHidden]
if !ok || metadataHiddenValue != licenseapi.MetadataValueTrue {
_, err := stripeClient.ProductFeatures.New(&stripe.ProductFeatureParams{
Product: &prod.ID,
EntitlementFeature: &featureID,
})
_, err := stripeClient.V1ProductFeatures.Create(
ctx,
&stripe.ProductFeatureCreateParams{
Product: &prod.ID,
EntitlementFeature: &featureID,
},
)
if err != nil {
return err
}
Expand All @@ -333,18 +329,18 @@ func EnsureAttachAll(
}

func SearchProductForFeatures(
stripeClient *stripeclient.API,
stripeClient *stripe.Client,
productID string,
featuresToCheck map[string]SyncedFeature,
) error {
productFeaturesList := stripeClient.ProductFeatures.List(&stripe.ProductFeatureListParams{
ctx := context.Background()
for productFeature, err := range stripeClient.V1ProductFeatures.List(ctx, &stripe.ProductFeatureListParams{
Product: &productID,
})
for productFeaturesList.Next() {
if err := productFeaturesList.Err(); err != nil {
}).All(ctx) {
if err != nil {
return err
}
delete(featuresToCheck, productFeaturesList.ProductFeature().EntitlementFeature.ID)
delete(featuresToCheck, productFeature.EntitlementFeature.ID)
}
return nil
}
Loading