entitlement

package
v1.0.0-beta.192 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Feb 18, 2025 License: Apache-2.0 Imports: 23 Imported by: 0

Documentation

Index

Constants

View Source
const (
	EventSubsystem metadata.EventSubsystem = "entitlement"
)

Variables

This section is empty.

Functions

func ValidateUniqueConstraint

func ValidateUniqueConstraint(ents []Entitlement) error

ValidateUniqueConstraint validates the uniqueness constraints of the entitlements The constraint is formally stated as follows:

For entitlement E 1. The ActiveFromTime is E.ActiveFrom or E.CreatedAt (if E.ActiveFrom is nil) 2. The ActiveToTime is E.ActiveTo or E.DeletedAt (if E.ActiveTo is nil). This can be nil.

Entitlement E is active at time T if and only if: 1. E.ActiveFromTime <= T and E.ActiveToTime > T 2. E.ActiveFromTime <= T and E.ActiveToTime is nil

For a set of unique entitlements S, where all E in S share the same feature (by key) and subject: 1. Let T1 be the first ActiveFromTime for any E in S sorted ascending 2. Let T2 be the last ActiveToTime for any E in S sorted ascending

The constraint:

For all E in S at any time T where T1 <= T < T2, there is at most one E that is active.

Types

type AlreadyDeletedError

type AlreadyDeletedError struct {
	EntitlementID string
}

func (*AlreadyDeletedError) Error

func (e *AlreadyDeletedError) Error() string

type AlreadyExistsError

type AlreadyExistsError struct {
	EntitlementID string
	FeatureID     string
	SubjectKey    string
}

func (*AlreadyExistsError) Error

func (e *AlreadyExistsError) Error() string

type Connector

type Connector interface {
	CreateEntitlement(ctx context.Context, input CreateEntitlementInputs) (*Entitlement, error)
	ScheduleEntitlement(ctx context.Context, input CreateEntitlementInputs) (*Entitlement, error)
	// OverrideEntitlement replaces a currently active entitlement with a new one.
	OverrideEntitlement(ctx context.Context, subject string, entitlementIdOrFeatureKey string, input CreateEntitlementInputs) (*Entitlement, error)
	// SupersedeEntitlement replaces an entitlement by scheduling a new one
	SupersedeEntitlement(ctx context.Context, entitlementId string, input CreateEntitlementInputs) (*Entitlement, error)

	GetEntitlement(ctx context.Context, namespace string, id string) (*Entitlement, error)
	DeleteEntitlement(ctx context.Context, namespace string, id string, at time.Time) error

	GetEntitlementValue(ctx context.Context, namespace string, subjectKey string, idOrFeatureKey string, at time.Time) (EntitlementValue, error)

	GetEntitlementsOfSubject(ctx context.Context, namespace string, subjectKey string, at time.Time) ([]Entitlement, error)
	ListEntitlements(ctx context.Context, params ListEntitlementsParams) (pagination.PagedResponse[Entitlement], error)

	// Attempts to get the entitlement in an ambiguous situation where it's unclear if the entitlement is referenced by ID or FeatureKey + SubjectKey.
	// First attempts to resolve by ID, then by FeatureKey + SubjectKey.
	//
	// For consistency, it is forbidden for entitlements to be created for featueres the keys of which could be mistaken for entitlement IDs.
	GetEntitlementOfSubjectAt(ctx context.Context, namespace string, subjectKey string, idOrFeatureKey string, at time.Time) (*Entitlement, error)
}

func NewEntitlementConnector

func NewEntitlementConnector(
	entitlementRepo EntitlementRepo,
	featureConnector feature.FeatureConnector,
	meterRepo meter.Repository,
	meteredEntitlementConnector SubTypeConnector,
	staticEntitlementConnector SubTypeConnector,
	booleanEntitlementConnector SubTypeConnector,
	publisher eventbus.Publisher,
) Connector

type CreateEntitlementInputs

type CreateEntitlementInputs struct {
	Namespace       string            `json:"namespace"`
	FeatureID       *string           `json:"featureId"`
	FeatureKey      *string           `json:"featureKey"`
	SubjectKey      string            `json:"subjectKey"`
	EntitlementType EntitlementType   `json:"type"`
	Metadata        map[string]string `json:"metadata,omitempty"`

	// ActiveFrom allows entitlements to be scheduled for future activation.
	// If not set, the entitlement is active immediately.
	ActiveFrom *time.Time `json:"activeFrom,omitempty"`
	// ActiveTo allows entitlements to be descheduled for future activation.
	// If not set, the entitlement is active until deletion.
	ActiveTo *time.Time `json:"activeTo,omitempty"`

	MeasureUsageFrom        *MeasureUsageFromInput `json:"measureUsageFrom,omitempty"`
	IssueAfterReset         *float64               `json:"issueAfterReset,omitempty"`
	IssueAfterResetPriority *uint8                 `json:"issueAfterResetPriority,omitempty"`
	IsSoftLimit             *bool                  `json:"isSoftLimit,omitempty"`
	Config                  []byte                 `json:"config,omitempty"`
	UsagePeriod             *UsagePeriod           `json:"usagePeriod,omitempty"`
	PreserveOverageAtReset  *bool                  `json:"preserveOverageAtReset,omitempty"`

	SubscriptionManaged bool `json:"subscriptionManaged,omitempty"`
}

func (CreateEntitlementInputs) Equal

func (CreateEntitlementInputs) GetType

func (CreateEntitlementInputs) Validate

func (c CreateEntitlementInputs) Validate() error

type CreateEntitlementRepoInputs

type CreateEntitlementRepoInputs struct {
	Namespace       string            `json:"namespace"`
	FeatureID       string            `json:"featureId"`
	FeatureKey      string            `json:"featureKey"`
	SubjectKey      string            `json:"subjectKey"`
	EntitlementType EntitlementType   `json:"type"`
	Metadata        map[string]string `json:"metadata,omitempty"`
	ActiveFrom      *time.Time        `json:"activeFrom,omitempty"`
	ActiveTo        *time.Time        `json:"activeTo,omitempty"`

	MeasureUsageFrom        *time.Time         `json:"measureUsageFrom,omitempty"`
	IssueAfterReset         *float64           `json:"issueAfterReset,omitempty"`
	IssueAfterResetPriority *uint8             `json:"issueAfterResetPriority,omitempty"`
	IsSoftLimit             *bool              `json:"isSoftLimit,omitempty"`
	Config                  []byte             `json:"config,omitempty"`
	UsagePeriod             *UsagePeriod       `json:"usagePeriod,omitempty"`
	CurrentUsagePeriod      *recurrence.Period `json:"currentUsagePeriod,omitempty"`
	PreserveOverageAtReset  *bool              `json:"preserveOverageAtReset,omitempty"`

	SubscriptionManaged bool `json:"subscriptionManaged,omitempty"`
}

type Entitlement

type Entitlement struct {
	GenericProperties

	// All none-core fields are optional
	// metered
	MeasureUsageFrom        *time.Time `json:"measureUsageFrom,omitempty"`
	IssueAfterReset         *float64   `json:"issueAfterReset,omitempty"`
	IssueAfterResetPriority *uint8     `json:"issueAfterResetPriority,omitempty"`
	IsSoftLimit             *bool      `json:"isSoftLimit,omitempty"`
	LastReset               *time.Time `json:"lastReset,omitempty"`
	PreserveOverageAtReset  *bool      `json:"preserveOverageAtReset,omitempty"`

	// static
	Config []byte `json:"config,omitempty"`
}

Normalized representation of an entitlement in the system

func (Entitlement) AsCreateEntitlementInputs

func (e Entitlement) AsCreateEntitlementInputs() CreateEntitlementInputs

func (Entitlement) GetType

func (e Entitlement) GetType() EntitlementType

func (Entitlement) IsActive

func (e Entitlement) IsActive(at time.Time) bool

IsActive returns if the entitlement is active at the given time Period start is determined by

type EntitlementCreatedEvent

type EntitlementCreatedEvent entitlementEvent

func (EntitlementCreatedEvent) EventMetadata

func (EntitlementCreatedEvent) EventName

func (e EntitlementCreatedEvent) EventName() string

func (EntitlementCreatedEvent) Validate

func (e EntitlementCreatedEvent) Validate() error

type EntitlementDeletedEvent

type EntitlementDeletedEvent entitlementEvent

func (EntitlementDeletedEvent) EventMetadata

func (EntitlementDeletedEvent) EventName

func (e EntitlementDeletedEvent) EventName() string

func (EntitlementDeletedEvent) Validate

func (e EntitlementDeletedEvent) Validate() error

type EntitlementRepo

type EntitlementRepo interface {
	// GetActiveEntitlementsOfSubject returns all active entitlements of a subject at a given time
	GetActiveEntitlementsOfSubject(ctx context.Context, namespace string, subjectKey string, at time.Time) ([]Entitlement, error)

	// GetActiveEntitlementOfSubjectAt returns the active entitlement of a subject at a given time by feature key
	GetActiveEntitlementOfSubjectAt(ctx context.Context, namespace string, subjectKey string, featureKey string, at time.Time) (*Entitlement, error)

	// GetScheduledEntitlements returns all scheduled entitlements for a given subject-feature pair that become inactive after the given time, sorted by the time they become active
	GetScheduledEntitlements(ctx context.Context, namespace string, subjectKey string, featureKey string, starting time.Time) ([]Entitlement, error)

	// DeactivateEntitlement deactivates an entitlement by setting the activeTo time. If the entitlement is already deactivated, it returns an error.
	DeactivateEntitlement(ctx context.Context, entitlementID models.NamespacedID, at time.Time) error

	CreateEntitlement(ctx context.Context, entitlement CreateEntitlementRepoInputs) (*Entitlement, error)
	GetEntitlement(ctx context.Context, entitlementID models.NamespacedID) (*Entitlement, error)
	DeleteEntitlement(ctx context.Context, entitlementID models.NamespacedID, at time.Time) error

	ListEntitlements(ctx context.Context, params ListEntitlementsParams) (pagination.PagedResponse[Entitlement], error)

	// ListNamespacesWithActiveEntitlements returns a list of namespaces that have active entitlements
	//
	// Active in this context means the entitlement is active at any point between now and the given time.
	// If includeDeletedAfter is before the current time, it will include namespaces that have entitlements active at that instance.
	ListNamespacesWithActiveEntitlements(ctx context.Context, includeDeletedAfter time.Time) ([]string, error)

	// HasEntitlementForMeter returns true if the meter has any active or inactive entitlements
	HasEntitlementForMeter(ctx context.Context, namespace string, meterSlug string) (bool, error)

	UpdateEntitlementUsagePeriod(ctx context.Context, entitlementID models.NamespacedID, params UpdateEntitlementUsagePeriodParams) error

	// ListActiveEntitlementsWithExpiredUsagePeriod returns a list of active entitlements with usage period that expired before the highwatermark
	//
	// Only entitlements active at the highwatermark are considered. FIXME: this implementation might be incorrect
	ListActiveEntitlementsWithExpiredUsagePeriod(ctx context.Context, namespaces []string, highwatermark time.Time) ([]Entitlement, error)

	LockEntitlementForTx(ctx context.Context, tx *entutils.TxDriver, entitlementID models.NamespacedID) error

	entutils.TxCreator
}

type EntitlementType

type EntitlementType string
const (
	// EntitlementTypeMetered represents entitlements where access is determined by usage and balance calculations
	EntitlementTypeMetered EntitlementType = "metered"
	// EntitlementTypeStatic represents entitlements where access is described by a static configuration
	EntitlementTypeStatic EntitlementType = "static"
	// EntitlementTypeBoolean represents boolean access
	EntitlementTypeBoolean EntitlementType = "boolean"
)

func (EntitlementType) StrValues

func (e EntitlementType) StrValues() []string

func (EntitlementType) String

func (e EntitlementType) String() string

func (EntitlementType) Values

func (e EntitlementType) Values() []EntitlementType

type EntitlementValue

type EntitlementValue interface {
	HasAccess() bool
}

type ForbiddenError

type ForbiddenError struct {
	Message string
}

func (*ForbiddenError) Error

func (e *ForbiddenError) Error() string

type GenericProperties

type GenericProperties struct {
	models.NamespacedModel
	models.ManagedModel
	models.AnnotatedModel

	// ActiveFrom allows entitlements to be scheduled for future activation.
	// If not set, the entitlement is active immediately.
	ActiveFrom *time.Time `json:"activeFrom,omitempty"`
	// ActiveTo allows entitlements to be descheduled for future activation.
	// If not set, the entitlement is active until deletion.
	ActiveTo *time.Time `json:"activeTo,omitempty"`

	ID              string          `json:"id,omitempty"`
	FeatureID       string          `json:"featureId,omitempty"`
	FeatureKey      string          `json:"featureKey,omitempty"`
	SubjectKey      string          `json:"subjectKey,omitempty"`
	EntitlementType EntitlementType `json:"type,omitempty"`

	UsagePeriod        *UsagePeriod       `json:"usagePeriod,omitempty"`
	CurrentUsagePeriod *recurrence.Period `json:"currentUsagePeriod,omitempty"`

	SubscriptionManaged bool `json:"subscriptionManaged,omitempty"`
}

GenericProperties is the core fields of an entitlement that are always applicable regadless of type

func (GenericProperties) ActiveFromTime

func (e GenericProperties) ActiveFromTime() time.Time

ActiveFromTime returns the time the entitlement is active from. Its either the ActiveFrom field or the CreatedAt field

func (GenericProperties) ActiveToTime

func (e GenericProperties) ActiveToTime() *time.Time

ActiveToTime returns the time the entitlement is active to. Its either the ActiveTo field or the DeletedAt field or nil

type InvalidFeatureError

type InvalidFeatureError struct {
	FeatureID string
	Message   string
}

func (*InvalidFeatureError) Error

func (e *InvalidFeatureError) Error() string

type InvalidValueError

type InvalidValueError struct {
	Message string
	Type    EntitlementType
}

func (*InvalidValueError) Error

func (e *InvalidValueError) Error() string

type ListEntitlementsOrderBy

type ListEntitlementsOrderBy string
const (
	ListEntitlementsOrderByCreatedAt ListEntitlementsOrderBy = "created_at"
	ListEntitlementsOrderByUpdatedAt ListEntitlementsOrderBy = "updated_at"
)

func (ListEntitlementsOrderBy) StrValues

func (o ListEntitlementsOrderBy) StrValues() []string

func (ListEntitlementsOrderBy) Values

type ListEntitlementsParams

type ListEntitlementsParams struct {
	IDs                 []string
	Namespaces          []string
	SubjectKeys         []string
	FeatureIDs          []string
	FeatureKeys         []string
	FeatureIDsOrKeys    []string
	EntitlementTypes    []EntitlementType
	OrderBy             ListEntitlementsOrderBy
	Order               sortx.Order
	IncludeDeleted      bool
	IncludeDeletedAfter time.Time
	ExcludeInactive     bool
	Page                pagination.Page
	// will be deprecated
	Limit int
	// will be deprecated
	Offset int
}

type MeasureUsageFromEnum

type MeasureUsageFromEnum string
const (
	MeasureUsageFromCurrentPeriodStart MeasureUsageFromEnum = "CURRENT_PERIOD_START"
	MeasureUsageFromNow                MeasureUsageFromEnum = "NOW"
)

func (MeasureUsageFromEnum) Validate

func (e MeasureUsageFromEnum) Validate() error

func (MeasureUsageFromEnum) Values

type MeasureUsageFromInput

type MeasureUsageFromInput struct {
	// contains filtered or unexported fields
}

func (MeasureUsageFromInput) Equal

func (*MeasureUsageFromInput) FromEnum

func (*MeasureUsageFromInput) FromTime

func (m *MeasureUsageFromInput) FromTime(t time.Time) error

func (MeasureUsageFromInput) Get

type NoAccessValue

type NoAccessValue struct{}

func (NoAccessValue) HasAccess

func (NoAccessValue) HasAccess() bool

type NotFoundError

type NotFoundError struct {
	EntitlementID models.NamespacedID
}

func (*NotFoundError) Error

func (e *NotFoundError) Error() string

type SubTypeConnector

type SubTypeConnector interface {
	GetValue(ctx context.Context, entitlement *Entitlement, at time.Time) (EntitlementValue, error)

	// Runs before creating the entitlement, building the Repository inputs.
	// If it returns an error the operation has to fail.
	BeforeCreate(entitlement CreateEntitlementInputs, feature feature.Feature) (*CreateEntitlementRepoInputs, error)

	// Runs after entitlement creation.
	// If it returns an error the operation has to fail.
	AfterCreate(ctx context.Context, entitlement *Entitlement) error
}

type TypedEntitlement

type TypedEntitlement interface {
	GetType() EntitlementType
}

type UniquenessConstraintError

type UniquenessConstraintError struct {
	// contains filtered or unexported fields
}

func (*UniquenessConstraintError) Error

func (e *UniquenessConstraintError) Error() string

type UpdateEntitlementUsagePeriodParams

type UpdateEntitlementUsagePeriodParams struct {
	NewAnchor          *time.Time
	CurrentUsagePeriod recurrence.Period
}

type UsagePeriod

type UsagePeriod recurrence.Recurrence

func (UsagePeriod) Equal

func (u UsagePeriod) Equal(other UsagePeriod) bool

func (UsagePeriod) GetCurrentPeriodAt

func (u UsagePeriod) GetCurrentPeriodAt(at time.Time) (recurrence.Period, error)

The returned period is exclusive at the end end inclusive in the start

func (UsagePeriod) Validate

func (u UsagePeriod) Validate() error

type WrongTypeError

type WrongTypeError struct {
	Expected EntitlementType
	Actual   EntitlementType
}

func (*WrongTypeError) Error

func (e *WrongTypeError) Error() string

Directories

Path Synopsis

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL