155 lines
4.3 KiB
Go
155 lines
4.3 KiB
Go
package resource
|
|
|
|
import (
|
|
"crypto/sha256"
|
|
"encoding/hex"
|
|
"encoding/json"
|
|
"sort"
|
|
"strings"
|
|
)
|
|
|
|
type ResourceGroupItem struct {
|
|
GroupItemID int64
|
|
GroupID int64
|
|
ItemType string
|
|
ResourceID int64
|
|
Resource Resource
|
|
WalletAssetType string
|
|
WalletAssetAmount int64
|
|
Quantity int64
|
|
DurationMS int64
|
|
SortOrder int32
|
|
CreatedAtMS int64
|
|
UpdatedAtMS int64
|
|
// GiftConfigs is populated only for immutable group snapshots. omitempty preserves the canonical JSON
|
|
// of snapshots written before gift semantics became part of the wallet-owned reward promise.
|
|
GiftConfigs []GiftConfig `json:",omitempty"`
|
|
}
|
|
|
|
type ResourceGroup struct {
|
|
AppCode string
|
|
GroupID int64
|
|
GroupCode string
|
|
Name string
|
|
Status string
|
|
Description string
|
|
SortOrder int32
|
|
Items []ResourceGroupItem
|
|
CreatedByUserID int64
|
|
UpdatedByUserID int64
|
|
CreatedAtMS int64
|
|
UpdatedAtMS int64
|
|
}
|
|
|
|
// ResourceGroupSnapshot is an immutable, owner-controlled reward promise. The embedded group contains
|
|
// complete resource and wallet-asset facts needed both for deterministic grant execution and client display.
|
|
type ResourceGroupSnapshot struct {
|
|
AppCode string
|
|
SnapshotID string
|
|
PinKey string
|
|
SourceGroupID int64
|
|
VersionNo int64
|
|
SnapshotHash string
|
|
Group ResourceGroup
|
|
CreatedByUserID int64
|
|
CreatedAtMS int64
|
|
SourceGroupUpdatedAtMS int64
|
|
SourceContentHash string
|
|
}
|
|
|
|
type PinResourceGroupSnapshotCommand struct {
|
|
AppCode string
|
|
PinKey string
|
|
GroupID int64
|
|
OperatorUserID int64
|
|
ExpectedGroupUpdatedAtMS int64
|
|
ExpectedSourceContentHash string
|
|
RequiredRegionIDs []int64
|
|
RequiredAllRegions bool
|
|
}
|
|
|
|
// CanonicalResourceGroupJSON is the owner-side version identity used by both inspect and pin.
|
|
// It deliberately includes nested Resource bytes so an independently edited resource cannot reuse a stale pin.
|
|
func CanonicalResourceGroupJSON(group ResourceGroup) ([]byte, error) {
|
|
canonical := group
|
|
canonical.Items = append([]ResourceGroupItem(nil), group.Items...)
|
|
for index := range canonical.Items {
|
|
canonical.Items[index].Resource.UsageScopes = append([]string(nil), canonical.Items[index].Resource.UsageScopes...)
|
|
sort.Strings(canonical.Items[index].Resource.UsageScopes)
|
|
canonical.Items[index].GiftConfigs = canonicalGiftConfigs(canonical.Items[index].GiftConfigs)
|
|
}
|
|
sort.SliceStable(canonical.Items, func(left, right int) bool {
|
|
if canonical.Items[left].SortOrder != canonical.Items[right].SortOrder {
|
|
return canonical.Items[left].SortOrder < canonical.Items[right].SortOrder
|
|
}
|
|
return canonical.Items[left].GroupItemID < canonical.Items[right].GroupItemID
|
|
})
|
|
return json.Marshal(canonical)
|
|
}
|
|
|
|
func ResourceGroupContentHash(group ResourceGroup) (string, error) {
|
|
body, err := CanonicalResourceGroupJSON(group)
|
|
if err != nil {
|
|
return "", err
|
|
}
|
|
sum := sha256.Sum256(body)
|
|
return hex.EncodeToString(sum[:]), nil
|
|
}
|
|
|
|
type ResourceGroupItemInput struct {
|
|
ItemType string
|
|
ResourceID int64
|
|
WalletAssetType string
|
|
WalletAssetAmount int64
|
|
Quantity int64
|
|
DurationMS int64
|
|
SortOrder int32
|
|
}
|
|
|
|
type ListResourceGroupsQuery struct {
|
|
AppCode string
|
|
Status string
|
|
Keyword string
|
|
Page int32
|
|
PageSize int32
|
|
ActiveOnly bool
|
|
}
|
|
|
|
type ResourceGroupCommand struct {
|
|
AppCode string
|
|
GroupID int64
|
|
GroupCode string
|
|
Name string
|
|
Status string
|
|
Description string
|
|
SortOrder int32
|
|
Items []ResourceGroupItemInput
|
|
OperatorUserID int64
|
|
}
|
|
|
|
func ValidGrantStrategy(value string) bool {
|
|
switch strings.ToLower(strings.TrimSpace(value)) {
|
|
case GrantStrategyWalletCredit, GrantStrategyNewEntitlement, GrantStrategyExtendExpiry, GrantStrategyIncreaseQuantity, GrantStrategySetActiveFlag:
|
|
return true
|
|
default:
|
|
return false
|
|
}
|
|
}
|
|
|
|
func NormalizeGroupItemType(value string) string {
|
|
value = strings.ToLower(strings.TrimSpace(value))
|
|
if value == "" {
|
|
return GroupItemTypeResource
|
|
}
|
|
return value
|
|
}
|
|
|
|
func ValidGroupItemType(value string) bool {
|
|
switch NormalizeGroupItemType(value) {
|
|
case GroupItemTypeResource, GroupItemTypeWalletAsset:
|
|
return true
|
|
default:
|
|
return false
|
|
}
|
|
}
|