109 lines
3.3 KiB
Go
109 lines
3.3 KiB
Go
// Package profile implements a user-profile actor grain (same event-driven
|
|
// framework as the cart, checkout, and order grains). Mutations are the proto
|
|
// messages in proto/profile; the grain's event log is the source of truth and
|
|
// ProfileGrain is the projection rebuilt by replaying them.
|
|
package profile
|
|
|
|
import (
|
|
"encoding/json"
|
|
"sync"
|
|
"time"
|
|
)
|
|
|
|
// LinkedCart records a cart id linked to this profile.
|
|
type LinkedCart struct {
|
|
CartId uint64 `json:"cartId"`
|
|
Label string `json:"label,omitempty"`
|
|
}
|
|
|
|
// LinkedCheckout records a checkout id linked to this profile.
|
|
type LinkedCheckout struct {
|
|
CheckoutId uint64 `json:"checkoutId"`
|
|
CartId uint64 `json:"cartId"`
|
|
}
|
|
|
|
// LinkedOrder records an order linked to this profile.
|
|
type LinkedOrder struct {
|
|
OrderReference string `json:"orderReference"`
|
|
CartId uint64 `json:"cartId"`
|
|
Status string `json:"status,omitempty"`
|
|
}
|
|
|
|
// StoredAddress is a saved address in the user's address book.
|
|
type StoredAddress struct {
|
|
Id uint32 `json:"id"`
|
|
Label string `json:"label,omitempty"`
|
|
FullName string `json:"fullName,omitempty"`
|
|
AddressLine1 string `json:"addressLine1"`
|
|
AddressLine2 string `json:"addressLine2,omitempty"`
|
|
City string `json:"city"`
|
|
State string `json:"state,omitempty"`
|
|
Zip string `json:"zip"`
|
|
Country string `json:"country"`
|
|
Phone string `json:"phone,omitempty"`
|
|
IsDefaultShipping bool `json:"isDefaultShipping,omitempty"`
|
|
IsDefaultBilling bool `json:"isDefaultBilling,omitempty"`
|
|
}
|
|
|
|
// ProfileGrain is the projected current state of a user profile. It implements
|
|
// actor.Grain[ProfileGrain].
|
|
type ProfileGrain struct {
|
|
mu sync.RWMutex
|
|
lastAccess time.Time
|
|
lastChange time.Time
|
|
nextAddrId uint32
|
|
|
|
Id uint64 `json:"id"`
|
|
Name string `json:"name,omitempty"`
|
|
Email string `json:"email,omitempty"`
|
|
Phone string `json:"phone,omitempty"`
|
|
Language string `json:"language,omitempty"`
|
|
Currency string `json:"currency,omitempty"`
|
|
|
|
AvatarUrl string `json:"avatarUrl,omitempty"`
|
|
Carts []LinkedCart `json:"carts,omitempty"`
|
|
Checkouts []LinkedCheckout `json:"checkouts,omitempty"`
|
|
Orders []LinkedOrder `json:"orders,omitempty"`
|
|
Addresses []StoredAddress `json:"addresses,omitempty"`
|
|
}
|
|
|
|
// NewProfileGrain returns an empty profile grain for id.
|
|
func NewProfileGrain(id uint64, ts time.Time) *ProfileGrain {
|
|
return &ProfileGrain{
|
|
Id: id,
|
|
lastAccess: ts,
|
|
lastChange: ts,
|
|
}
|
|
}
|
|
|
|
// --- actor.Grain[ProfileGrain] ---
|
|
|
|
func (p *ProfileGrain) GetId() uint64 { return p.Id }
|
|
|
|
func (p *ProfileGrain) GetLastAccess() time.Time { return p.lastAccess }
|
|
|
|
func (p *ProfileGrain) GetLastChange() time.Time { return p.lastChange }
|
|
|
|
func (p *ProfileGrain) GetCurrentState() (*ProfileGrain, error) {
|
|
p.lastAccess = time.Now()
|
|
return p, nil
|
|
}
|
|
|
|
func (p *ProfileGrain) GetState() ([]byte, error) { return json.Marshal(p) }
|
|
|
|
// NextAddrId returns the next address id and advances the counter.
|
|
func (p *ProfileGrain) NextAddrId() uint32 {
|
|
p.nextAddrId++
|
|
return p.nextAddrId
|
|
}
|
|
|
|
// findAddress returns a pointer to the address with the given id, or nil.
|
|
func (p *ProfileGrain) findAddress(id uint32) *StoredAddress {
|
|
for i := range p.Addresses {
|
|
if p.Addresses[i].Id == id {
|
|
return &p.Addresses[i]
|
|
}
|
|
}
|
|
return nil
|
|
}
|