feat/enterpriseportal: subscriptions read APIs use enterprise portal DB

This commit is contained in:
Robert Lin 2024-07-18 15:31:42 -07:00
parent 5726960c23
commit 16bc317557
12 changed files with 153 additions and 356 deletions

View File

@ -71,7 +71,7 @@ func TestCodyGatewayStore(t *testing.T) {
} {
l, err := subscriptions.NewLicensesStore(db).CreateLicenseKey(ctx,
subscriptionID,
&subscriptions.LicenseKey{
&subscriptions.DataLicenseKey{
Info: license.Info{
// Set properties that are easy to assert on later
Tags: []string{

View File

@ -265,7 +265,7 @@ func (i *Importer) importLicense(ctx context.Context, subscriptionID string, dot
tr.SetAttributes(attribute.Bool("already_imported", false))
if _, err := i.licenses.CreateLicenseKey(ctx, subscriptionID,
&subscriptions.LicenseKey{
&subscriptions.DataLicenseKey{
Info: license.Info{
Tags: dotcomLicense.Tags,
UserCount: uint(pointers.DerefZero(dotcomLicense.UserCount)),

View File

@ -247,9 +247,9 @@ func (c CreateLicenseOpts) getLicenseID() (string, error) {
return licenseID.String(), nil
}
// LicenseKey corresponds to *subscriptionsv1.EnterpriseSubscriptionLicenseKey
// DataLicenseKey corresponds to *subscriptionsv1.EnterpriseSubscriptionLicenseKey
// and the 'ENTERPRISE_SUBSCRIPTION_LICENSE_TYPE_KEY' license type.
type LicenseKey struct {
type DataLicenseKey struct {
Info internallicense.Info
// Signed license key with the license information in Info.
SignedKey string
@ -259,7 +259,7 @@ type LicenseKey struct {
func (s *LicensesStore) CreateLicenseKey(
ctx context.Context,
subscriptionID string,
license *LicenseKey,
license *DataLicenseKey,
opts CreateLicenseOpts,
) (_ *LicenseWithConditions, err error) {
// Special behaviour: the license key embeds the creation time, and it must

View File

@ -72,7 +72,7 @@ func TestLicensesStore(t *testing.T) {
}
got, err := licenses.CreateLicenseKey(ctx, subscriptionID1,
&subscriptions.LicenseKey{
&subscriptions.DataLicenseKey{
Info: license.Info{
Tags: []string{"foo"},
CreatedAt: time.Time{}.Add(1 * time.Hour),
@ -94,7 +94,7 @@ func TestLicensesStore(t *testing.T) {
createdLicenses = append(createdLicenses, got)
got, err = licenses.CreateLicenseKey(ctx, subscriptionID1,
&subscriptions.LicenseKey{
&subscriptions.DataLicenseKey{
Info: license.Info{
Tags: []string{"baz"},
CreatedAt: time.Time{}.Add(24 * time.Hour),
@ -116,7 +116,7 @@ func TestLicensesStore(t *testing.T) {
createdLicenses = append(createdLicenses, got)
got, err = licenses.CreateLicenseKey(ctx, subscriptionID2,
&subscriptions.LicenseKey{
&subscriptions.DataLicenseKey{
Info: license.Info{
Tags: []string{"tag"},
CreatedAt: time.Time{}.Add(24 * time.Hour),
@ -139,7 +139,7 @@ func TestLicensesStore(t *testing.T) {
t.Run("createdAt does not match", func(t *testing.T) {
_, err = licenses.CreateLicenseKey(ctx, subscriptionID2,
&subscriptions.LicenseKey{
&subscriptions.DataLicenseKey{
Info: license.Info{
Tags: []string{"tag"},
CreatedAt: time.Time{}.Add(24 * time.Hour),
@ -155,7 +155,7 @@ func TestLicensesStore(t *testing.T) {
})
t.Run("expiresAt does not match", func(t *testing.T) {
_, err = licenses.CreateLicenseKey(ctx, subscriptionID2,
&subscriptions.LicenseKey{
&subscriptions.DataLicenseKey{
Info: license.Info{
Tags: []string{"tag"},
CreatedAt: time.Time{},

View File

@ -14,9 +14,8 @@ import (
"github.com/sourcegraph/log/logtest"
"github.com/sourcegraph/sourcegraph-accounts-sdk-go/scopes"
sams "github.com/sourcegraph/sourcegraph-accounts-sdk-go"
"github.com/sourcegraph/sourcegraph-accounts-sdk-go/scopes"
"github.com/sourcegraph/sourcegraph/cmd/enterprise-portal/internal/codyaccessservice"
"github.com/sourcegraph/sourcegraph/cmd/enterprise-portal/internal/database"

View File

@ -45,7 +45,6 @@ go_test(
embed = [":subscriptionsservice"],
deps = [
"//cmd/enterprise-portal/internal/database/subscriptions",
"//cmd/enterprise-portal/internal/dotcomdb",
"//cmd/enterprise-portal/internal/samsm2m",
"//lib/enterpriseportal/subscriptions/v1:subscriptions",
"//lib/managedservicesplatform/iam",

View File

@ -1,75 +1,88 @@
package subscriptionsservice
import (
"encoding/json"
"google.golang.org/protobuf/types/known/timestamppb"
"github.com/sourcegraph/sourcegraph/cmd/enterprise-portal/internal/database/subscriptions"
"github.com/sourcegraph/sourcegraph/cmd/enterprise-portal/internal/dotcomdb"
subscriptionsv1 "github.com/sourcegraph/sourcegraph/lib/enterpriseportal/subscriptions/v1"
"github.com/sourcegraph/sourcegraph/lib/errors"
"github.com/sourcegraph/sourcegraph/lib/managedservicesplatform/iam"
"github.com/sourcegraph/sourcegraph/lib/pointers"
)
func convertLicenseAttrsToProto(attrs *dotcomdb.LicenseAttributes) *subscriptionsv1.EnterpriseSubscriptionLicense {
conds := []*subscriptionsv1.EnterpriseSubscriptionLicenseCondition{
{
Status: subscriptionsv1.EnterpriseSubscriptionLicenseCondition_STATUS_CREATED,
LastTransitionTime: timestamppb.New(attrs.CreatedAt),
},
}
if attrs.RevokedAt != nil {
conds = append(conds, &subscriptionsv1.EnterpriseSubscriptionLicenseCondition{
Status: subscriptionsv1.EnterpriseSubscriptionLicenseCondition_STATUS_REVOKED,
LastTransitionTime: timestamppb.New(*attrs.RevokedAt),
Message: pointers.DerefZero(attrs.RevokeReason),
})
}
return &subscriptionsv1.EnterpriseSubscriptionLicense{
Id: subscriptionsv1.EnterpriseSubscriptionLicenseIDPrefix + attrs.ID,
SubscriptionId: subscriptionsv1.EnterpriseSubscriptionIDPrefix + attrs.SubscriptionID,
Conditions: conds,
License: &subscriptionsv1.EnterpriseSubscriptionLicense_Key{
Key: &subscriptionsv1.EnterpriseSubscriptionLicenseKey{
InfoVersion: pointers.DerefZero(attrs.InfoVersion),
Info: &subscriptionsv1.EnterpriseSubscriptionLicenseKey_Info{
Tags: attrs.Tags,
UserCount: pointers.DerefZero(attrs.UserCount),
ExpireTime: timestamppb.New(*attrs.ExpiresAt),
SalesforceSubscriptionId: pointers.DerefZero(attrs.SalesforceSubscriptionID),
SalesforceOpportunityId: pointers.DerefZero(attrs.SalesforceOpportunityID),
},
LicenseKey: attrs.LicenseKey,
InstanceId: pointers.DerefZero(attrs.InstanceID),
},
},
}
}
func convertSubscriptionToProto(subscription *subscriptions.Subscription, attrs *dotcomdb.SubscriptionAttributes) *subscriptionsv1.EnterpriseSubscription {
// Dotcom equivalent missing is surprising, but let's not panic just yet
if attrs == nil {
attrs = &dotcomdb.SubscriptionAttributes{
ID: subscription.ID,
func convertLicenseToProto(license *subscriptions.LicenseWithConditions) (*subscriptionsv1.EnterpriseSubscriptionLicense, error) {
conds := make([]*subscriptionsv1.EnterpriseSubscriptionLicenseCondition, len(license.Conditions))
for i, c := range license.Conditions {
conds[i] = &subscriptionsv1.EnterpriseSubscriptionLicenseCondition{
LastTransitionTime: timestamppb.New(c.TransitionTime.AsTime()),
Status: subscriptionsv1.EnterpriseSubscriptionLicenseCondition_Status(
subscriptionsv1.EnterpriseSubscriptionLicenseCondition_Status_value[c.Status],
),
Message: pointers.DerefZero(c.Message),
}
}
conds := []*subscriptionsv1.EnterpriseSubscriptionCondition{
{
Status: subscriptionsv1.EnterpriseSubscriptionCondition_STATUS_CREATED,
LastTransitionTime: timestamppb.New(attrs.CreatedAt),
},
proto := &subscriptionsv1.EnterpriseSubscriptionLicense{
Id: subscriptionsv1.EnterpriseSubscriptionLicenseIDPrefix + license.ID,
SubscriptionId: subscriptionsv1.EnterpriseSubscriptionIDPrefix + license.SubscriptionID,
Conditions: conds,
}
if attrs.ArchivedAt != nil {
conds = append(conds, &subscriptionsv1.EnterpriseSubscriptionCondition{
Status: subscriptionsv1.EnterpriseSubscriptionCondition_STATUS_ARCHIVED,
LastTransitionTime: timestamppb.New(*attrs.ArchivedAt),
})
switch t := license.LicenseType; t {
case subscriptionsv1.EnterpriseSubscriptionLicenseType_ENTERPRISE_SUBSCRIPTION_LICENSE_TYPE_KEY.String():
var data subscriptions.DataLicenseKey
if err := json.Unmarshal(license.LicenseData, &data); err != nil {
return proto, errors.Wrap(err, "unmarshal license data")
}
proto.License = &subscriptionsv1.EnterpriseSubscriptionLicense_Key{
Key: &subscriptionsv1.EnterpriseSubscriptionLicenseKey{
InfoVersion: uint32(data.Info.Version()),
Info: &subscriptionsv1.EnterpriseSubscriptionLicenseKey_Info{
Tags: data.Info.Tags,
UserCount: uint64(data.Info.UserCount),
ExpireTime: timestamppb.New(data.Info.ExpiresAt),
SalesforceSubscriptionId: pointers.DerefZero(data.Info.SalesforceSubscriptionID),
SalesforceOpportunityId: pointers.DerefZero(data.Info.SalesforceOpportunityID),
},
LicenseKey: data.SignedKey,
InstanceId: "", // TODO
},
}
default:
return proto, errors.Newf("unknown license type %q", t)
}
return proto, nil
}
func convertSubscriptionToProto(subscription *subscriptions.SubscriptionWithConditions) *subscriptionsv1.EnterpriseSubscription {
conds := make([]*subscriptionsv1.EnterpriseSubscriptionCondition, len(subscription.Conditions))
for i, c := range subscription.Conditions {
conds[i] = &subscriptionsv1.EnterpriseSubscriptionCondition{
LastTransitionTime: timestamppb.New(c.TransitionTime.AsTime()),
Status: subscriptionsv1.EnterpriseSubscriptionCondition_Status(
subscriptionsv1.EnterpriseSubscriptionCondition_Status_value[c.Status],
),
Message: pointers.DerefZero(c.Message),
}
}
var sf *subscriptionsv1.EnterpriseSubscription_SalesforceMetadata
if subscription.SalesforceSubscriptionID != nil || subscription.SalesforceOpportunityID != nil {
sf = &subscriptionsv1.EnterpriseSubscription_SalesforceMetadata{
SubscriptionId: pointers.DerefZero(subscription.SalesforceSubscriptionID),
OpportunityId: pointers.DerefZero(subscription.SalesforceOpportunityID),
}
}
return &subscriptionsv1.EnterpriseSubscription{
Id: subscriptionsv1.EnterpriseSubscriptionIDPrefix + attrs.ID,
Id: subscriptionsv1.EnterpriseSubscriptionIDPrefix + subscription.ID,
Conditions: conds,
InstanceDomain: pointers.DerefZero(subscription.InstanceDomain),
DisplayName: pointers.DerefZero(subscription.DisplayName),
Salesforce: sf,
}
}

View File

@ -13,8 +13,6 @@ import (
sourcegraphaccountssdkgo "github.com/sourcegraph/sourcegraph-accounts-sdk-go"
v1 "github.com/sourcegraph/sourcegraph-accounts-sdk-go/clients/v1"
subscriptions "github.com/sourcegraph/sourcegraph/cmd/enterprise-portal/internal/database/subscriptions"
dotcomdb "github.com/sourcegraph/sourcegraph/cmd/enterprise-portal/internal/dotcomdb"
v11 "github.com/sourcegraph/sourcegraph/lib/enterpriseportal/subscriptions/v1"
iam "github.com/sourcegraph/sourcegraph/lib/managedservicesplatform/iam"
)
@ -38,14 +36,10 @@ type MockStoreV1 struct {
// IntrospectSAMSTokenFunc is an instance of a mock function object
// controlling the behavior of the method IntrospectSAMSToken.
IntrospectSAMSTokenFunc *StoreV1IntrospectSAMSTokenFunc
// ListDotcomEnterpriseSubscriptionLicensesFunc is an instance of a mock
// ListEnterpriseSubscriptionLicensesFunc is an instance of a mock
// function object controlling the behavior of the method
// ListDotcomEnterpriseSubscriptionLicenses.
ListDotcomEnterpriseSubscriptionLicensesFunc *StoreV1ListDotcomEnterpriseSubscriptionLicensesFunc
// ListDotcomEnterpriseSubscriptionsFunc is an instance of a mock
// function object controlling the behavior of the method
// ListDotcomEnterpriseSubscriptions.
ListDotcomEnterpriseSubscriptionsFunc *StoreV1ListDotcomEnterpriseSubscriptionsFunc
// ListEnterpriseSubscriptionLicenses.
ListEnterpriseSubscriptionLicensesFunc *StoreV1ListEnterpriseSubscriptionLicensesFunc
// ListEnterpriseSubscriptionsFunc is an instance of a mock function
// object controlling the behavior of the method
// ListEnterpriseSubscriptions.
@ -85,13 +79,8 @@ func NewMockStoreV1() *MockStoreV1 {
return
},
},
ListDotcomEnterpriseSubscriptionLicensesFunc: &StoreV1ListDotcomEnterpriseSubscriptionLicensesFunc{
defaultHook: func(context.Context, []*v11.ListEnterpriseSubscriptionLicensesFilter, int) (r0 []*dotcomdb.LicenseAttributes, r1 error) {
return
},
},
ListDotcomEnterpriseSubscriptionsFunc: &StoreV1ListDotcomEnterpriseSubscriptionsFunc{
defaultHook: func(context.Context, dotcomdb.ListEnterpriseSubscriptionsOptions) (r0 []*dotcomdb.SubscriptionAttributes, r1 error) {
ListEnterpriseSubscriptionLicensesFunc: &StoreV1ListEnterpriseSubscriptionLicensesFunc{
defaultHook: func(context.Context, subscriptions.ListLicensesOpts) (r0 []*subscriptions.LicenseWithConditions, r1 error) {
return
},
},
@ -137,14 +126,9 @@ func NewStrictMockStoreV1() *MockStoreV1 {
panic("unexpected invocation of MockStoreV1.IntrospectSAMSToken")
},
},
ListDotcomEnterpriseSubscriptionLicensesFunc: &StoreV1ListDotcomEnterpriseSubscriptionLicensesFunc{
defaultHook: func(context.Context, []*v11.ListEnterpriseSubscriptionLicensesFilter, int) ([]*dotcomdb.LicenseAttributes, error) {
panic("unexpected invocation of MockStoreV1.ListDotcomEnterpriseSubscriptionLicenses")
},
},
ListDotcomEnterpriseSubscriptionsFunc: &StoreV1ListDotcomEnterpriseSubscriptionsFunc{
defaultHook: func(context.Context, dotcomdb.ListEnterpriseSubscriptionsOptions) ([]*dotcomdb.SubscriptionAttributes, error) {
panic("unexpected invocation of MockStoreV1.ListDotcomEnterpriseSubscriptions")
ListEnterpriseSubscriptionLicensesFunc: &StoreV1ListEnterpriseSubscriptionLicensesFunc{
defaultHook: func(context.Context, subscriptions.ListLicensesOpts) ([]*subscriptions.LicenseWithConditions, error) {
panic("unexpected invocation of MockStoreV1.ListEnterpriseSubscriptionLicenses")
},
},
ListEnterpriseSubscriptionsFunc: &StoreV1ListEnterpriseSubscriptionsFunc{
@ -179,11 +163,8 @@ func NewMockStoreV1From(i StoreV1) *MockStoreV1 {
IntrospectSAMSTokenFunc: &StoreV1IntrospectSAMSTokenFunc{
defaultHook: i.IntrospectSAMSToken,
},
ListDotcomEnterpriseSubscriptionLicensesFunc: &StoreV1ListDotcomEnterpriseSubscriptionLicensesFunc{
defaultHook: i.ListDotcomEnterpriseSubscriptionLicenses,
},
ListDotcomEnterpriseSubscriptionsFunc: &StoreV1ListDotcomEnterpriseSubscriptionsFunc{
defaultHook: i.ListDotcomEnterpriseSubscriptions,
ListEnterpriseSubscriptionLicensesFunc: &StoreV1ListEnterpriseSubscriptionLicensesFunc{
defaultHook: i.ListEnterpriseSubscriptionLicenses,
},
ListEnterpriseSubscriptionsFunc: &StoreV1ListEnterpriseSubscriptionsFunc{
defaultHook: i.ListEnterpriseSubscriptions,
@ -729,153 +710,37 @@ func (c StoreV1IntrospectSAMSTokenFuncCall) Results() []interface{} {
return []interface{}{c.Result0, c.Result1}
}
// StoreV1ListDotcomEnterpriseSubscriptionLicensesFunc describes the
// behavior when the ListDotcomEnterpriseSubscriptionLicenses method of the
// parent MockStoreV1 instance is invoked.
type StoreV1ListDotcomEnterpriseSubscriptionLicensesFunc struct {
defaultHook func(context.Context, []*v11.ListEnterpriseSubscriptionLicensesFilter, int) ([]*dotcomdb.LicenseAttributes, error)
hooks []func(context.Context, []*v11.ListEnterpriseSubscriptionLicensesFilter, int) ([]*dotcomdb.LicenseAttributes, error)
history []StoreV1ListDotcomEnterpriseSubscriptionLicensesFuncCall
mutex sync.Mutex
}
// ListDotcomEnterpriseSubscriptionLicenses delegates to the next hook
// function in the queue and stores the parameter and result values of this
// invocation.
func (m *MockStoreV1) ListDotcomEnterpriseSubscriptionLicenses(v0 context.Context, v1 []*v11.ListEnterpriseSubscriptionLicensesFilter, v2 int) ([]*dotcomdb.LicenseAttributes, error) {
r0, r1 := m.ListDotcomEnterpriseSubscriptionLicensesFunc.nextHook()(v0, v1, v2)
m.ListDotcomEnterpriseSubscriptionLicensesFunc.appendCall(StoreV1ListDotcomEnterpriseSubscriptionLicensesFuncCall{v0, v1, v2, r0, r1})
return r0, r1
}
// SetDefaultHook sets function that is called when the
// ListDotcomEnterpriseSubscriptionLicenses method of the parent MockStoreV1
// instance is invoked and the hook queue is empty.
func (f *StoreV1ListDotcomEnterpriseSubscriptionLicensesFunc) SetDefaultHook(hook func(context.Context, []*v11.ListEnterpriseSubscriptionLicensesFilter, int) ([]*dotcomdb.LicenseAttributes, error)) {
f.defaultHook = hook
}
// PushHook adds a function to the end of hook queue. Each invocation of the
// ListDotcomEnterpriseSubscriptionLicenses method of the parent MockStoreV1
// instance invokes the hook at the front of the queue and discards it.
// After the queue is empty, the default hook function is invoked for any
// future action.
func (f *StoreV1ListDotcomEnterpriseSubscriptionLicensesFunc) PushHook(hook func(context.Context, []*v11.ListEnterpriseSubscriptionLicensesFilter, int) ([]*dotcomdb.LicenseAttributes, error)) {
f.mutex.Lock()
f.hooks = append(f.hooks, hook)
f.mutex.Unlock()
}
// SetDefaultReturn calls SetDefaultHook with a function that returns the
// given values.
func (f *StoreV1ListDotcomEnterpriseSubscriptionLicensesFunc) SetDefaultReturn(r0 []*dotcomdb.LicenseAttributes, r1 error) {
f.SetDefaultHook(func(context.Context, []*v11.ListEnterpriseSubscriptionLicensesFilter, int) ([]*dotcomdb.LicenseAttributes, error) {
return r0, r1
})
}
// PushReturn calls PushHook with a function that returns the given values.
func (f *StoreV1ListDotcomEnterpriseSubscriptionLicensesFunc) PushReturn(r0 []*dotcomdb.LicenseAttributes, r1 error) {
f.PushHook(func(context.Context, []*v11.ListEnterpriseSubscriptionLicensesFilter, int) ([]*dotcomdb.LicenseAttributes, error) {
return r0, r1
})
}
func (f *StoreV1ListDotcomEnterpriseSubscriptionLicensesFunc) nextHook() func(context.Context, []*v11.ListEnterpriseSubscriptionLicensesFilter, int) ([]*dotcomdb.LicenseAttributes, error) {
f.mutex.Lock()
defer f.mutex.Unlock()
if len(f.hooks) == 0 {
return f.defaultHook
}
hook := f.hooks[0]
f.hooks = f.hooks[1:]
return hook
}
func (f *StoreV1ListDotcomEnterpriseSubscriptionLicensesFunc) appendCall(r0 StoreV1ListDotcomEnterpriseSubscriptionLicensesFuncCall) {
f.mutex.Lock()
f.history = append(f.history, r0)
f.mutex.Unlock()
}
// History returns a sequence of
// StoreV1ListDotcomEnterpriseSubscriptionLicensesFuncCall objects
// describing the invocations of this function.
func (f *StoreV1ListDotcomEnterpriseSubscriptionLicensesFunc) History() []StoreV1ListDotcomEnterpriseSubscriptionLicensesFuncCall {
f.mutex.Lock()
history := make([]StoreV1ListDotcomEnterpriseSubscriptionLicensesFuncCall, len(f.history))
copy(history, f.history)
f.mutex.Unlock()
return history
}
// StoreV1ListDotcomEnterpriseSubscriptionLicensesFuncCall is an object that
// describes an invocation of method
// ListDotcomEnterpriseSubscriptionLicenses on an instance of MockStoreV1.
type StoreV1ListDotcomEnterpriseSubscriptionLicensesFuncCall struct {
// Arg0 is the value of the 1st argument passed to this method
// invocation.
Arg0 context.Context
// Arg1 is the value of the 2nd argument passed to this method
// invocation.
Arg1 []*v11.ListEnterpriseSubscriptionLicensesFilter
// Arg2 is the value of the 3rd argument passed to this method
// invocation.
Arg2 int
// Result0 is the value of the 1st result returned from this method
// invocation.
Result0 []*dotcomdb.LicenseAttributes
// Result1 is the value of the 2nd result returned from this method
// invocation.
Result1 error
}
// Args returns an interface slice containing the arguments of this
// invocation.
func (c StoreV1ListDotcomEnterpriseSubscriptionLicensesFuncCall) Args() []interface{} {
return []interface{}{c.Arg0, c.Arg1, c.Arg2}
}
// Results returns an interface slice containing the results of this
// invocation.
func (c StoreV1ListDotcomEnterpriseSubscriptionLicensesFuncCall) Results() []interface{} {
return []interface{}{c.Result0, c.Result1}
}
// StoreV1ListDotcomEnterpriseSubscriptionsFunc describes the behavior when
// the ListDotcomEnterpriseSubscriptions method of the parent MockStoreV1
// StoreV1ListEnterpriseSubscriptionLicensesFunc describes the behavior when
// the ListEnterpriseSubscriptionLicenses method of the parent MockStoreV1
// instance is invoked.
type StoreV1ListDotcomEnterpriseSubscriptionsFunc struct {
defaultHook func(context.Context, dotcomdb.ListEnterpriseSubscriptionsOptions) ([]*dotcomdb.SubscriptionAttributes, error)
hooks []func(context.Context, dotcomdb.ListEnterpriseSubscriptionsOptions) ([]*dotcomdb.SubscriptionAttributes, error)
history []StoreV1ListDotcomEnterpriseSubscriptionsFuncCall
type StoreV1ListEnterpriseSubscriptionLicensesFunc struct {
defaultHook func(context.Context, subscriptions.ListLicensesOpts) ([]*subscriptions.LicenseWithConditions, error)
hooks []func(context.Context, subscriptions.ListLicensesOpts) ([]*subscriptions.LicenseWithConditions, error)
history []StoreV1ListEnterpriseSubscriptionLicensesFuncCall
mutex sync.Mutex
}
// ListDotcomEnterpriseSubscriptions delegates to the next hook function in
// ListEnterpriseSubscriptionLicenses delegates to the next hook function in
// the queue and stores the parameter and result values of this invocation.
func (m *MockStoreV1) ListDotcomEnterpriseSubscriptions(v0 context.Context, v1 dotcomdb.ListEnterpriseSubscriptionsOptions) ([]*dotcomdb.SubscriptionAttributes, error) {
r0, r1 := m.ListDotcomEnterpriseSubscriptionsFunc.nextHook()(v0, v1)
m.ListDotcomEnterpriseSubscriptionsFunc.appendCall(StoreV1ListDotcomEnterpriseSubscriptionsFuncCall{v0, v1, r0, r1})
func (m *MockStoreV1) ListEnterpriseSubscriptionLicenses(v0 context.Context, v1 subscriptions.ListLicensesOpts) ([]*subscriptions.LicenseWithConditions, error) {
r0, r1 := m.ListEnterpriseSubscriptionLicensesFunc.nextHook()(v0, v1)
m.ListEnterpriseSubscriptionLicensesFunc.appendCall(StoreV1ListEnterpriseSubscriptionLicensesFuncCall{v0, v1, r0, r1})
return r0, r1
}
// SetDefaultHook sets function that is called when the
// ListDotcomEnterpriseSubscriptions method of the parent MockStoreV1
// ListEnterpriseSubscriptionLicenses method of the parent MockStoreV1
// instance is invoked and the hook queue is empty.
func (f *StoreV1ListDotcomEnterpriseSubscriptionsFunc) SetDefaultHook(hook func(context.Context, dotcomdb.ListEnterpriseSubscriptionsOptions) ([]*dotcomdb.SubscriptionAttributes, error)) {
func (f *StoreV1ListEnterpriseSubscriptionLicensesFunc) SetDefaultHook(hook func(context.Context, subscriptions.ListLicensesOpts) ([]*subscriptions.LicenseWithConditions, error)) {
f.defaultHook = hook
}
// PushHook adds a function to the end of hook queue. Each invocation of the
// ListDotcomEnterpriseSubscriptions method of the parent MockStoreV1
// ListEnterpriseSubscriptionLicenses method of the parent MockStoreV1
// instance invokes the hook at the front of the queue and discards it.
// After the queue is empty, the default hook function is invoked for any
// future action.
func (f *StoreV1ListDotcomEnterpriseSubscriptionsFunc) PushHook(hook func(context.Context, dotcomdb.ListEnterpriseSubscriptionsOptions) ([]*dotcomdb.SubscriptionAttributes, error)) {
func (f *StoreV1ListEnterpriseSubscriptionLicensesFunc) PushHook(hook func(context.Context, subscriptions.ListLicensesOpts) ([]*subscriptions.LicenseWithConditions, error)) {
f.mutex.Lock()
f.hooks = append(f.hooks, hook)
f.mutex.Unlock()
@ -883,20 +748,20 @@ func (f *StoreV1ListDotcomEnterpriseSubscriptionsFunc) PushHook(hook func(contex
// SetDefaultReturn calls SetDefaultHook with a function that returns the
// given values.
func (f *StoreV1ListDotcomEnterpriseSubscriptionsFunc) SetDefaultReturn(r0 []*dotcomdb.SubscriptionAttributes, r1 error) {
f.SetDefaultHook(func(context.Context, dotcomdb.ListEnterpriseSubscriptionsOptions) ([]*dotcomdb.SubscriptionAttributes, error) {
func (f *StoreV1ListEnterpriseSubscriptionLicensesFunc) SetDefaultReturn(r0 []*subscriptions.LicenseWithConditions, r1 error) {
f.SetDefaultHook(func(context.Context, subscriptions.ListLicensesOpts) ([]*subscriptions.LicenseWithConditions, error) {
return r0, r1
})
}
// PushReturn calls PushHook with a function that returns the given values.
func (f *StoreV1ListDotcomEnterpriseSubscriptionsFunc) PushReturn(r0 []*dotcomdb.SubscriptionAttributes, r1 error) {
f.PushHook(func(context.Context, dotcomdb.ListEnterpriseSubscriptionsOptions) ([]*dotcomdb.SubscriptionAttributes, error) {
func (f *StoreV1ListEnterpriseSubscriptionLicensesFunc) PushReturn(r0 []*subscriptions.LicenseWithConditions, r1 error) {
f.PushHook(func(context.Context, subscriptions.ListLicensesOpts) ([]*subscriptions.LicenseWithConditions, error) {
return r0, r1
})
}
func (f *StoreV1ListDotcomEnterpriseSubscriptionsFunc) nextHook() func(context.Context, dotcomdb.ListEnterpriseSubscriptionsOptions) ([]*dotcomdb.SubscriptionAttributes, error) {
func (f *StoreV1ListEnterpriseSubscriptionLicensesFunc) nextHook() func(context.Context, subscriptions.ListLicensesOpts) ([]*subscriptions.LicenseWithConditions, error) {
f.mutex.Lock()
defer f.mutex.Unlock()
@ -909,37 +774,37 @@ func (f *StoreV1ListDotcomEnterpriseSubscriptionsFunc) nextHook() func(context.C
return hook
}
func (f *StoreV1ListDotcomEnterpriseSubscriptionsFunc) appendCall(r0 StoreV1ListDotcomEnterpriseSubscriptionsFuncCall) {
func (f *StoreV1ListEnterpriseSubscriptionLicensesFunc) appendCall(r0 StoreV1ListEnterpriseSubscriptionLicensesFuncCall) {
f.mutex.Lock()
f.history = append(f.history, r0)
f.mutex.Unlock()
}
// History returns a sequence of
// StoreV1ListDotcomEnterpriseSubscriptionsFuncCall objects describing the
// StoreV1ListEnterpriseSubscriptionLicensesFuncCall objects describing the
// invocations of this function.
func (f *StoreV1ListDotcomEnterpriseSubscriptionsFunc) History() []StoreV1ListDotcomEnterpriseSubscriptionsFuncCall {
func (f *StoreV1ListEnterpriseSubscriptionLicensesFunc) History() []StoreV1ListEnterpriseSubscriptionLicensesFuncCall {
f.mutex.Lock()
history := make([]StoreV1ListDotcomEnterpriseSubscriptionsFuncCall, len(f.history))
history := make([]StoreV1ListEnterpriseSubscriptionLicensesFuncCall, len(f.history))
copy(history, f.history)
f.mutex.Unlock()
return history
}
// StoreV1ListDotcomEnterpriseSubscriptionsFuncCall is an object that
// describes an invocation of method ListDotcomEnterpriseSubscriptions on an
// instance of MockStoreV1.
type StoreV1ListDotcomEnterpriseSubscriptionsFuncCall struct {
// StoreV1ListEnterpriseSubscriptionLicensesFuncCall is an object that
// describes an invocation of method ListEnterpriseSubscriptionLicenses on
// an instance of MockStoreV1.
type StoreV1ListEnterpriseSubscriptionLicensesFuncCall struct {
// Arg0 is the value of the 1st argument passed to this method
// invocation.
Arg0 context.Context
// Arg1 is the value of the 2nd argument passed to this method
// invocation.
Arg1 dotcomdb.ListEnterpriseSubscriptionsOptions
Arg1 subscriptions.ListLicensesOpts
// Result0 is the value of the 1st result returned from this method
// invocation.
Result0 []*dotcomdb.SubscriptionAttributes
Result0 []*subscriptions.LicenseWithConditions
// Result1 is the value of the 2nd result returned from this method
// invocation.
Result1 error
@ -947,13 +812,13 @@ type StoreV1ListDotcomEnterpriseSubscriptionsFuncCall struct {
// Args returns an interface slice containing the arguments of this
// invocation.
func (c StoreV1ListDotcomEnterpriseSubscriptionsFuncCall) Args() []interface{} {
func (c StoreV1ListEnterpriseSubscriptionLicensesFuncCall) Args() []interface{} {
return []interface{}{c.Arg0, c.Arg1}
}
// Results returns an interface slice containing the results of this
// invocation.
func (c StoreV1ListDotcomEnterpriseSubscriptionsFuncCall) Results() []interface{} {
func (c StoreV1ListEnterpriseSubscriptionLicensesFuncCall) Results() []interface{} {
return []interface{}{c.Result0, c.Result1}
}

View File

@ -175,42 +175,11 @@ func (s *handlerV1) ListEnterpriseSubscriptions(ctx context.Context, req *connec
return nil, connectutil.InternalError(ctx, logger, err, "list subscriptions")
}
// List from dotcom DB and merge attributes.
dotcomSubscriptions, err := s.store.ListDotcomEnterpriseSubscriptions(ctx, dotcomdb.ListEnterpriseSubscriptionsOptions{
SubscriptionIDs: subscriptionIDs.Values(),
IsArchived: isArchived,
})
if err != nil {
return nil, connectutil.InternalError(ctx, logger, err, "list subscriptions from dotcom DB")
}
dotcomSubscriptionsSet := make(map[string]*dotcomdb.SubscriptionAttributes, len(dotcomSubscriptions))
for _, s := range dotcomSubscriptions {
dotcomSubscriptionsSet[s.ID] = s
}
// Add the "real" subscriptions we already track to the results
respSubscriptions := make([]*subscriptionsv1.EnterpriseSubscription, 0, len(subs))
for _, s := range subs {
respSubscriptions = append(
respSubscriptions,
convertSubscriptionToProto(&s.Subscription, dotcomSubscriptionsSet[s.ID]),
)
delete(dotcomSubscriptionsSet, s.ID)
}
// Add any remaining dotcom subscriptions to the results set
for _, s := range dotcomSubscriptionsSet {
respSubscriptions = append(
respSubscriptions,
convertSubscriptionToProto(&subscriptions.Subscription{
ID: subscriptionsv1.EnterpriseSubscriptionIDPrefix + s.ID,
}, s),
)
}
accessedSubscriptions := map[string]struct{}{}
for _, s := range respSubscriptions {
accessedSubscriptions[s.GetId()] = struct{}{}
protoSubscriptions := make([]*subscriptionsv1.EnterpriseSubscription, len(subs))
for i, s := range subs {
protoSubscriptions[i] = convertSubscriptionToProto(s)
accessedSubscriptions[s.ID] = struct{}{}
}
logger.Scoped("audit").Info("ListEnterpriseSubscriptions",
log.Strings("accessedSubscriptions", maps.Keys(accessedSubscriptions)),
@ -221,7 +190,7 @@ func (s *handlerV1) ListEnterpriseSubscriptions(ctx context.Context, req *connec
// Never a next page, pagination is not implemented yet:
// https://linear.app/sourcegraph/issue/CORE-134
NextPageToken: "",
Subscriptions: respSubscriptions,
Subscriptions: protoSubscriptions,
},
), nil
}
@ -244,6 +213,10 @@ func (s *handlerV1) ListEnterpriseSubscriptionLicenses(ctx context.Context, req
return nil, connect.NewError(connect.CodeUnimplemented, errors.New("pagination not implemented"))
}
opts := subscriptions.ListLicensesOpts{
PageSize: int(req.Msg.GetPageSize()),
}
// Validate filters
filters := req.Msg.GetFilters()
for _, filter := range filters {
@ -262,13 +235,17 @@ func (s *handlerV1) ListEnterpriseSubscriptionLicenses(ctx context.Context, req
errors.New(`invalid filter: "subscription_id"" provided but is empty`),
)
}
if opts.SubscriptionID != "" {
return nil, connect.NewError(
connect.CodeInvalidArgument,
errors.New(`invalid filter: "subscription_id"" provided multiple times`),
)
}
opts.SubscriptionID = f.SubscriptionId
}
}
licenses, err := s.store.ListDotcomEnterpriseSubscriptionLicenses(ctx, filters,
// Provide page size to allow "active license" functionality, by only
// retrieving the most recently created result.
int(req.Msg.GetPageSize()))
licenses, err := s.store.ListEnterpriseSubscriptionLicenses(ctx, opts)
if err != nil {
if errors.Is(err, dotcomdb.ErrCodyGatewayAccessNotFound) {
return nil, connect.NewError(connect.CodeNotFound, err)
@ -287,10 +264,15 @@ func (s *handlerV1) ListEnterpriseSubscriptionLicenses(ctx context.Context, req
accessedSubscriptions := map[string]struct{}{}
accessedLicenses := make([]string, len(licenses))
for i, l := range licenses {
resp.Licenses[i] = convertLicenseAttrsToProto(l)
resp.Licenses[i], err = convertLicenseToProto(l)
if err != nil {
return nil, connectutil.InternalError(ctx, logger, err,
"failed to read Enterprise Subscription license")
}
accessedSubscriptions[resp.Licenses[i].GetSubscriptionId()] = struct{}{}
accessedLicenses[i] = resp.Licenses[i].GetId()
}
logger.Scoped("audit").Info("ListEnterpriseSubscriptionLicenses",
log.Strings("accessedSubscriptions", maps.Keys(accessedSubscriptions)),
log.Strings("accessedLicenses", accessedLicenses))
@ -313,17 +295,6 @@ func (s *handlerV1) UpdateEnterpriseSubscription(ctx context.Context, req *conne
return nil, connect.NewError(connect.CodeInvalidArgument, errors.New("subscription.id is required"))
}
// TEMPORARY: Double check with the dotcom DB that the subscription ID is valid.
// This currently ensures we never actually create new subscriptions.
subscriptionAttrs, err := s.store.ListDotcomEnterpriseSubscriptions(ctx, dotcomdb.ListEnterpriseSubscriptionsOptions{
SubscriptionIDs: []string{subscriptionID},
})
if err != nil {
return nil, connectutil.InternalError(ctx, logger, err, "get dotcom enterprise subscription")
} else if len(subscriptionAttrs) != 1 {
return nil, connect.NewError(connect.CodeNotFound, errors.New("subscription not found"))
}
var opts subscriptions.UpsertSubscriptionOptions
fieldPaths := req.Msg.GetUpdateMask().GetPaths()
@ -374,7 +345,7 @@ func (s *handlerV1) UpdateEnterpriseSubscription(ctx context.Context, req *conne
return nil, connectutil.InternalError(ctx, logger, err, "upsert subscription")
}
respSubscription := convertSubscriptionToProto(&subscription.Subscription, subscriptionAttrs[0])
respSubscription := convertSubscriptionToProto(subscription)
logger.Scoped("audit").Info("UpdateEnterpriseSubscription",
log.String("updatedSubscription", respSubscription.GetId()),
)
@ -420,9 +391,9 @@ func (s *handlerV1) UpdateEnterpriseSubscriptionMembership(ctx context.Context,
}
if subscriptionID != "" {
// Double check with the dotcom DB that the subscription ID is valid.
subscriptionAttrs, err := s.store.ListDotcomEnterpriseSubscriptions(ctx, dotcomdb.ListEnterpriseSubscriptionsOptions{
SubscriptionIDs: []string{subscriptionID},
// Double check that the subscription ID is valid.
subscriptionAttrs, err := s.store.ListEnterpriseSubscriptions(ctx, subscriptions.ListEnterpriseSubscriptionsOptions{
IDs: []string{subscriptionID},
})
if err != nil {
return nil, connectutil.InternalError(ctx, logger, err, "get dotcom enterprise subscription")

View File

@ -8,8 +8,6 @@ import (
"github.com/sourcegraph/sourcegraph/cmd/enterprise-portal/internal/database"
"github.com/sourcegraph/sourcegraph/cmd/enterprise-portal/internal/database/subscriptions"
"github.com/sourcegraph/sourcegraph/cmd/enterprise-portal/internal/dotcomdb"
subscriptionsv1 "github.com/sourcegraph/sourcegraph/lib/enterpriseportal/subscriptions/v1"
"github.com/sourcegraph/sourcegraph/lib/managedservicesplatform/iam"
)
@ -23,19 +21,11 @@ type StoreV1 interface {
// ListEnterpriseSubscriptions returns a list of enterprise subscriptions based
// on the given options.
ListEnterpriseSubscriptions(ctx context.Context, opts subscriptions.ListEnterpriseSubscriptionsOptions) ([]*subscriptions.SubscriptionWithConditions, error)
// ListDotcomEnterpriseSubscriptionLicenses returns a list of enterprise
// subscription license attributes with the given filters. It silently ignores
// any non-matching filters. The caller should check the length of the returned
// slice to ensure all requested licenses were found.
ListDotcomEnterpriseSubscriptionLicenses(context.Context, []*subscriptionsv1.ListEnterpriseSubscriptionLicensesFilter, int) ([]*dotcomdb.LicenseAttributes, error)
// ListDotcomEnterpriseSubscriptions returns a list of enterprise subscription
// attributes with the given IDs from dotcom DB. It silently ignores any
// non-existent subscription IDs. The caller should check the length of the
// returned slice to ensure all requested subscriptions were found.
//
// If no IDs are provided, it returns all subscriptions.
ListDotcomEnterpriseSubscriptions(ctx context.Context, opts dotcomdb.ListEnterpriseSubscriptionsOptions) ([]*dotcomdb.SubscriptionAttributes, error)
ListEnterpriseSubscriptionLicenses(ctx context.Context, opts subscriptions.ListLicensesOpts) ([]*subscriptions.LicenseWithConditions, error)
// IntrospectSAMSToken takes a SAMS access token and returns relevant metadata.
//
@ -60,14 +50,12 @@ type StoreV1 interface {
type storeV1 struct {
db *database.DB
dotcomDB *dotcomdb.Reader
SAMSClient *sams.ClientV1
IAMClient *iam.ClientV1
}
type NewStoreV1Options struct {
DB *database.DB
DotcomDB *dotcomdb.Reader
SAMSClient *sams.ClientV1
IAMClient *iam.ClientV1
}
@ -76,7 +64,6 @@ type NewStoreV1Options struct {
func NewStoreV1(opts NewStoreV1Options) StoreV1 {
return &storeV1{
db: opts.DB,
dotcomDB: opts.DotcomDB,
SAMSClient: opts.SAMSClient,
IAMClient: opts.IAMClient,
}
@ -90,12 +77,8 @@ func (s *storeV1) ListEnterpriseSubscriptions(ctx context.Context, opts subscrip
return s.db.Subscriptions().List(ctx, opts)
}
func (s *storeV1) ListDotcomEnterpriseSubscriptionLicenses(ctx context.Context, filters []*subscriptionsv1.ListEnterpriseSubscriptionLicensesFilter, limit int) ([]*dotcomdb.LicenseAttributes, error) {
return s.dotcomDB.ListEnterpriseSubscriptionLicenses(ctx, filters, limit)
}
func (s *storeV1) ListDotcomEnterpriseSubscriptions(ctx context.Context, opts dotcomdb.ListEnterpriseSubscriptionsOptions) ([]*dotcomdb.SubscriptionAttributes, error) {
return s.dotcomDB.ListEnterpriseSubscriptions(ctx, opts)
func (s *storeV1) ListEnterpriseSubscriptionLicenses(ctx context.Context, opts subscriptions.ListLicensesOpts) ([]*subscriptions.LicenseWithConditions, error) {
return s.db.Subscriptions().Licenses().List(ctx, opts)
}
func (s *storeV1) IntrospectSAMSToken(ctx context.Context, token string) (*sams.IntrospectTokenResponse, error) {

View File

@ -19,7 +19,6 @@ import (
"github.com/sourcegraph/sourcegraph-accounts-sdk-go/scopes"
"github.com/sourcegraph/sourcegraph/cmd/enterprise-portal/internal/database/subscriptions"
"github.com/sourcegraph/sourcegraph/cmd/enterprise-portal/internal/dotcomdb"
"github.com/sourcegraph/sourcegraph/cmd/enterprise-portal/internal/samsm2m"
subscriptionsv1 "github.com/sourcegraph/sourcegraph/lib/enterpriseportal/subscriptions/v1"
"github.com/sourcegraph/sourcegraph/lib/managedservicesplatform/iam"
@ -197,31 +196,6 @@ func TestHandlerV1_ListEnterpriseSubscriptions(t *testing.T) {
}
})
}
// This is a temporary behaviour that will be removed
t.Run("no filters also checks dotcom", func(t *testing.T) {
req := connect.NewRequest(&subscriptionsv1.ListEnterpriseSubscriptionsRequest{})
req.Header().Add("Authorization", "Bearer foolmeifyoucan")
h := newTestHandlerV1()
h.mockStore.ListEnterpriseSubscriptionsFunc.SetDefaultHook(func(_ context.Context, opts subscriptions.ListEnterpriseSubscriptionsOptions) ([]*subscriptions.SubscriptionWithConditions, error) {
return []*subscriptions.SubscriptionWithConditions{}, nil
})
h.mockStore.ListDotcomEnterpriseSubscriptionsFunc.SetDefaultHook(func(_ context.Context, opts dotcomdb.ListEnterpriseSubscriptionsOptions) ([]*dotcomdb.SubscriptionAttributes, error) {
assert.Empty(t, opts.SubscriptionIDs)
assert.False(t, opts.IsArchived)
return []*dotcomdb.SubscriptionAttributes{{
ID: "80ca12e2-54b4-448c-a61a-390b1a9c1224",
}}, nil
})
_, err := h.ListEnterpriseSubscriptions(ctx, req)
require.NoError(t, err)
mockrequire.Called(t, h.mockStore.ListEnterpriseSubscriptionsFunc)
mockrequire.Called(t, h.mockStore.ListDotcomEnterpriseSubscriptionsFunc)
resp, err := h.ListEnterpriseSubscriptions(ctx, req)
require.NoError(t, err)
assert.NotNil(t, resp.Msg.Subscriptions)
})
}
func TestHandlerV1_UpdateEnterpriseSubscription(t *testing.T) {
@ -306,9 +280,11 @@ func TestHandlerV1_UpdateEnterpriseSubscription(t *testing.T) {
req.Header().Add("Authorization", "Bearer foolmeifyoucan")
h := newTestHandlerV1()
h.mockStore.ListDotcomEnterpriseSubscriptionsFunc.SetDefaultReturn(
[]*dotcomdb.SubscriptionAttributes{
{ID: "80ca12e2-54b4-448c-a61a-390b1a9c1224"},
h.mockStore.ListEnterpriseSubscriptionsFunc.SetDefaultReturn(
[]*subscriptions.SubscriptionWithConditions{
{Subscription: subscriptions.Subscription{
ID: "80ca12e2-54b4-448c-a61a-390b1a9c1224",
}},
}, nil)
h.mockStore.UpsertEnterpriseSubscriptionFunc.SetDefaultHook(func(_ context.Context, _ string, opts subscriptions.UpsertSubscriptionOptions) (*subscriptions.SubscriptionWithConditions, error) {
tc.wantUpdateOpts.Equal(t, opts)
@ -448,14 +424,6 @@ func TestHandlerV1_UpdateEnterpriseSubscriptionMembership(t *testing.T) {
req.Header().Add("Authorization", "Bearer foolmeifyoucan")
h := newTestHandlerV1()
h.mockStore.ListDotcomEnterpriseSubscriptionsFunc.SetDefaultHook(
func(_ context.Context, opts dotcomdb.ListEnterpriseSubscriptionsOptions) ([]*dotcomdb.SubscriptionAttributes, error) {
if slices.Contains(opts.SubscriptionIDs, subscriptionID) {
return []*dotcomdb.SubscriptionAttributes{{ID: subscriptionID}}, nil
}
return nil, nil
},
)
h.mockStore.ListEnterpriseSubscriptionsFunc.SetDefaultHook(
func(_ context.Context, opts subscriptions.ListEnterpriseSubscriptionsOptions) ([]*subscriptions.SubscriptionWithConditions, error) {
if slices.Contains(opts.IDs, subscriptionID) ||

View File

@ -118,7 +118,6 @@ func (Service) Initialize(ctx context.Context, logger log.Logger, contract runti
subscriptionsservice.NewStoreV1(
subscriptionsservice.NewStoreV1Options{
DB: dbHandle,
DotcomDB: dotcomDB,
SAMSClient: samsClient,
IAMClient: iamClient,
},