Documentation ¶
Index ¶
- Constants
- Variables
- type Affiliation
- type AffiliationStore
- type Application
- type ApplicationStore
- type Balance
- type CatalogProduct
- type CatalogStore
- type CommerceProduct
- type CommerceQuery
- type CommerceSort
- type CommerceSortBy
- type CommerceSortDirection
- type CommerceVendor
- type DataStore
- type Money
- type Organization
- type OrganizationStore
- type Password
- type Person
- type PersonStore
- type Points
- type Product
- type Role
- type Session
- type SessionStore
Constants ¶
const ( // CentsPerDollar describes the number of cents in a US Dollar. CentsPerDollar int = 100 // MaxDollarAmount is the maximum dollar amount a Money can store. MaxDollarAmount int = math.MaxInt64 / CentsPerDollar // MinDollarAmount is the minimum dollar amount a Money can store. MinDollarAmount int = math.MinInt64 / CentsPerDollar // MaxCentAmount is the maximum number of *fractional* cents in a US Dollar. MaxCentAmount int = 99 // MinCentAmount is the minimum number of *fractional* cents in a US Dollar. MinCentAmount int = -99 )
const SessionLength = 6 * time.Hour
SessionLength defines how long a login session for this app will last, at a MAXIMUM. Sessions may be revoked prior.
Variables ¶
var ErrNotFound = errors.New("not found")
ErrNotFound may be returned by a DataStore implementation when the requested data could not be found inside the store.
Suggested check for users of DataStore:
if errors.Is(err, app.ErrNotFound) { // do something for the special not found case }
Suggested use by DataStore implementors:
return errors.Wrapf(app.ErrNotFound, "book #%d", id)
Functions ¶
This section is empty.
Types ¶
type Affiliation ¶
type Affiliation struct { PersonID int `db:"person_id"` OrganizationID int `db:"organization_id"` // Points is the quantity of points this person has with this Organization, // will be null for non-drivers. Points null.Int `db:"points"` }
An Affiliation describes a person's relationship with an organization.
type AffiliationStore ¶
type AffiliationStore interface { AddPersonAffiliation( ctx context.Context, personID, orgID int, role Role, ) error RemovePersonAffiliation( ctx context.Context, personID, orgID int, ) error SetPointsForAffiliation( ctx context.Context, personID, orgID int, points null.Int, ) error GetBalancesForPerson(ctx context.Context, personID int) ([]Balance, error) }
AffiliationStore defines methods for interacting with affiliations between Persons and Organizations, with Points.
type Application ¶
type Application struct { // ID uniquely identifies this application. ID int `db:"application_id" json:"id"` // ApplicantID is the person ID of the driver applying to be sponsored. ApplicantID int `db:"applicant_id" json:"applicant_id"` // OrganizationID is the ID of the organization the driver would like to be // sponsored by. OrganizationID int `db:"organization_id" json:"organization_id"` OrganizationTitle string `db:"name" json:"organization_name"` // Comment is a driver-supplied comment to go with their application. Comment string `db:"comment" json:"comment"` // Approved specifies whether or not the organization has approved this // application or not. Will be null if no decision has been made. Approved null.Bool `db:"approved" json:"approved"` // Reason is the reason the organization accepted/rejected this application. Reason null.String `db:"reason" json:"reason"` // CreatedAt is the timestamp of when the driver submitted this application. CreatedAt time.Time `db:"created_at" json:"created_at"` // ApprovedAt is the timestamp of when the organization approved or rejected // this application. ApprovedAt null.Time `db:"approved_at" json:"approved_at"` }
Application represents a driver application to be sponsored by an organization.
type ApplicationStore ¶
type ApplicationStore interface { GetApplicationByID( ctx context.Context, appID int, ) (Application, error) GetApplicationsForPerson( ctx context.Context, personID int, ) ([]Application, error) GetApplicationsForOrganization( ctx context.Context, orgID int, ) ([]Application, error) CreateApplication(ctx context.Context, a Application) (int, error) UpdateApplicationApproval( ctx context.Context, appID int, status bool, reason string, ) error }
ApplicationStore defines methods for working with app.Application objects in the database.
type Balance ¶
type Balance struct { PersonID int `db:"person_id" json:"person_id"` PersonFirstName string `db:"first_name" json:"person_first_name"` PersonLastName string `db:"last_name" json:"person_last_name"` OrganizationID int `db:"organization_id" json:"organization_id"` OrganizationName string `db:"name" json:"organization_name"` Points int `db:"points" json:"balance"` }
A Balance describes the number of points that a person has within a given Organization.
type CatalogProduct ¶
type CatalogProduct struct { ID int `json:"id"` Title string `json:"title"` Description string `json:"description"` ImageURL null.String `json:"image_url"` Points Points `json:"points"` }
A CatalogProduct is a product affiliated with an organization, with its cost measured in Points.
type CatalogStore ¶
type CatalogStore interface { GetProductsForOrganization( ctx context.Context, orgID int, ) ([]CatalogProduct, error) SearchProductCatalog( ctx context.Context, orgID int, keywords string, ) ([]CatalogProduct, error) GetProductByID( ctx context.Context, productID, orgID int, ) (CatalogProduct, error) AddProduct(ctx context.Context, p Product) (int, error) }
CatalogStore defines methods for working with app.Product and app.CatalogProduct objects.
type CommerceProduct ¶
type CommerceProduct struct { ID int `json:"id"` Title string `json:"title"` Description string `json:"description"` ImageURL null.String `json:"image_url"` Price Money `json:"price"` }
A CommerceProduct describes a product of a third-party vendor.
func (*CommerceProduct) ToProduct ¶
func (cp *CommerceProduct) ToProduct(orgID int) Product
ToProduct converts this commerce product to a Product, given the associated Organization's ID number.
type CommerceQuery ¶
type CommerceQuery struct { Keywords string Sort CommerceSort Limit null.Int PageNo null.Int }
A CommerceQuery desceribes a search query for products.
type CommerceSort ¶
type CommerceSort struct { // By controls which field results are sorted by. By CommerceSortBy // Direction controls which direction results are sorted. Direction CommerceSortDirection // Valid controls whether or not results are sorted. Valid bool }
CommerceSort controls sorting of search results.
type CommerceSortBy ¶
type CommerceSortBy string
CommerceSortBy is a pseudo-enumeration of fields on which products may be sorted in search.
const ( CommerceSortByCreated CommerceSortBy = "created" CommerceSortByPrice CommerceSortBy = "price" CommerceSortByRating CommerceSortBy = "score" )
CommerceSortBy options control the field by which search results are sorted.
type CommerceSortDirection ¶
type CommerceSortDirection string
CommerceSortDirection is a pseudo-enumeration of directions for sorting search results.
const ( CommerceSortDirectionAscending CommerceSortDirection = "up" CommerceSortDirectionDescending CommerceSortDirection = "down" )
CommerceSearchDirection options control the direction search results are sorted.
type CommerceVendor ¶
type CommerceVendor interface { Search(ctx context.Context, q CommerceQuery) ([]CommerceProduct, error) GetProductByID(ctx context.Context, productID int) (CommerceProduct, error) }
CommerceVendor describes a common interface for dealing with third-party eCommerce vendors.
type DataStore ¶
type DataStore interface { PersonStore AffiliationStore SessionStore ApplicationStore OrganizationStore CatalogStore }
DataStore is the common interface for durable data storage.
type Money ¶
type Money int
Money provides an abstraction layer around monetary values stored as an integer count of cents.
func MakeMoneyFromComponents ¶
MakeMoneyFromComponents makes a Money from its dollar and cent component values. Both component values must be within their respective ranges and have matching signs (unless either is zero).
func MakeMoneyFromFloat ¶
MakeMoneyFromFloat makes a Money from a floating point integer. The decimal will be truncated at two places (floored).
func MustMakeMoneyFromComponents ¶
MustMakeMoneyFromComponents runs MakeMoneyFromComponents and follows the same constraints. HOWEVER, when any precondition fails and an error occurs, this function shall panic.
It is intended for this function only to be used by tests and constants where error checking often is impractical. All other use cases should use MakeMoneyFromComponents and check the error.
func ParseMoneyFromString ¶
ParseMoneyFromString attempts to parse Money from a string.
This string must follow these rules:
- if there is a negative sign, it must be the first character
- the dollar sign is optional
- the commas separating thousands in the dollar amount are optional
- the cents are optional, but if present must have two decimal places
Examples of accepted strings:
- "-$40,324,921.76"
- "$503"
- "504.32"
- "-30"
- "$3202.32"
- "8,108.31"
- "244,422"
func (Money) Components ¶
Components breaks a Money down into its dollar and cent components.
func (Money) ConvertToPoints ¶
func (m Money) ConvertToPoints(org Organization) Points
ConvertToPoints converts this Money value into points of the given organization based on the point value.
type Organization ¶
type Organization struct { // ID uniquely identifies this organization. ID int `db:"organization_id" json:"id"` // Name is a human-readable alias for this organization. Name string `db:"name" json:"name"` // PointValue describes the ratio between points and real dollars. // Each point is worth a PointValue amount of Money. PointValue Money `db:"point_value" json:"point_value"` }
An Organization contains information about a particular sponsor organization.
type OrganizationStore ¶
type OrganizationStore interface { GetAllOrganizations(ctx context.Context) ([]Organization, error) GetOrganizationByID(ctx context.Context, orgID int) (Organization, error) CreateOrganization(ctx context.Context, org Organization) (int, error) UpdateOrganization(ctx context.Context, org Organization) error DeleteOrganization(ctx context.Context, orgID int) error }
OrganizationStore defines methods for working with app.Organization objects.
type Password ¶
type Password string
A Password is a wrapper type for bcrypt password hashes.
func NewPassword ¶
NewPassword creates a new hashed Password given its plaintext.
type Person ¶
type Person struct { // ID is the uniquely identifying number for this person's account. ID int `db:"person_id" json:"id"` // FirstName is the person's first name. FirstName string `db:"first_name" json:"first_name"` // LastName is the person's last name. LastName string `db:"last_name" json:"last_name"` // Email is the person's email address. May be changed. Email string `db:"email" json:"email"` // Role is the person's current role. May be changed. Role Role `db:"role_id" json:"role_id"` // Password is the person's current hashed password. Password Password `db:"pass_hash" json:"-"` // IsDeactivated is true when a person's account is deactivated and // therefore cannot be authenticated against. IsDeactivated bool `db:"is_deactivated" json:"is_deactivated"` // Affiliations is a list of organization IDs that this user is // associated with. Affiliations []int `json:"affiliations"` }
A Person represents a user of our app.
type PersonStore ¶
type PersonStore interface { GetAllPeople(ctx context.Context) ([]Person, error) GetPersonByID( ctx context.Context, personID int, ) (Person, error) GetPersonByEmail(ctx context.Context, email string) (Person, error) CreatePerson(ctx context.Context, p Person) (int, error) UpdatePersonName( ctx context.Context, personID int, firstName, lastName string, ) error UpdatePersonEmail(ctx context.Context, personID int, email string) error UpdatePersonRole(ctx context.Context, personID int, roleType Role) error UpdatePersonPassword(ctx context.Context, personID int, p Password) error ActivatePerson(ctx context.Context, personID int) error DeactivatePerson(ctx context.Context, personID int) error }
PersonStore defines methods for working with app.Person objects in the database.
type Points ¶
type Points struct { // Amount describes the quantity of points. Amount int `json:"amount"` // OrganizationID is the identifier of the organization that the points // originated from. OrganizationID int `json:"organization_id"` // PointValue describes the amount of Money that each point is worth. PointValue Money `json:"point_value"` }
Points describes a particular amount of points, the value of each point, and the organization those points are associated with.
type Product ¶
type Product struct { ID int `db:"product_id"` VendorID int `db:"vendor_id"` OrganizationID int `db:"organization_id"` Title string `db:"title"` Description string `db:"description"` ImageURL null.String `db:"image_url"` Price Money `db:"price"` IsAvailable bool `db:"is_available"` }
A Product represents an entry in the product table.
func (*Product) ToCatalogProduct ¶
func (p *Product) ToCatalogProduct(org Organization) CatalogProduct
ToCatalogProduct converts this Product to a CatalogProduct.
type Role ¶
type Role int
A Role specifies what role a user has in our app and therefore what permissions they might have.
const ( // RoleAdmin users can access all parts of the system, even content that is // not owned by their user. RoleAdmin Role = 1 // RoleSponsor can access sponsor control panels for their organization as // well as all driver information for their affiliated drivers. RoleSponsor Role = 2 // RoleUser can access the application system only, since they are not // affiliated with any organization. RoleUser Role = 3 // RoleDriver can access the ordering system and view their point balance, // as they are affiliated with a sponsor organization. RoleDriver Role = 4 )
type Session ¶
type Session struct { // Person holds the user that this session belongs to. Person // ID is the session's identifying number. It is not secret. ID int `db:"session_id"` // Token is a unique, securely random generated UUIDv4 that also uniquely // identifies this session. It must be kept secret between our API server // and the web browser for the session. Token uuid.UUID `db:"token"` // CreatedAt is the timestamp that this session was started at. CreatedAt time.Time `db:"created_at"` // ExpiresAt is the timestamp when this session will expire permanently. ExpiresAt time.Time `db:"expires_at"` // IsRevoked is true when the session was manually revoked. IsRevoked bool `db:"is_revoked"` }
A Session represents an individual user session with our app.
func NewSession ¶
NewSession creates a new login session with a secure random token for a given person. It shall expire after SessionLength time has passed.
type SessionStore ¶
type SessionStore interface { GetSessionsForPerson( ctx context.Context, personID int, includeInvalid bool, ) ([]Session, error) GetSessionByToken(ctx context.Context, token uuid.UUID) (Session, error) CreateSession(ctx context.Context, s Session) (int, error) RevokeSession(ctx context.Context, sessionID int) error RevokeSessionsForPersonExcept( ctx context.Context, personID, sessionID int, ) error }
SessionStore defines methods for working with app.Session objects in the database.