pilot

package
v1.8.2 Latest Latest
Warning

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

Go to latest
Published: Oct 8, 2026 License: AGPL-3.0 Imports: 9 Imported by: 0

Documentation

Overview

Package pilot holds the pilot access list: who may register, and keep using the service, while the pilot access gate is on.

A person is approved per phone number and national ID. Both must match an active pilot_users row. One person may hold several rows (each new SIM is re-approved), so revoking and restoring act on every row sharing the national ID.

Index

Constants

This section is empty.

Variables

View Source
var ErrNotFound = errors.New("pilot: not found")

ErrNotFound is a phone number or national ID with no pilot_users row.

Functions

func NormalizeNationalID

func NormalizeNationalID(id string) string

NormalizeNationalID strips whitespace and upper-cases id.

func NormalizePhone

func NormalizePhone(s string) string

NormalizePhone returns phone as country code and subscriber digits with no leading +, the form users.mobile_number holds, reading 07…/01… as Kenyan. It returns "" when the number cannot be resolved.

Types

type Gate

type Gate interface {
	// PhoneActive reports whether number has an active row.
	PhoneActive(ctx context.Context, number string) (bool, error)
	// Matches reports whether number has an active row for nationalID.
	Matches(ctx context.Context, number, nationalID string) (bool, error)
	// UserActive reports whether a registered user's current phone number and
	// national ID match an active row.
	UserActive(ctx context.Context, userID string) (bool, error)
}

Gate answers access questions while the pilot access gate is on. A nil Gate means the gate is off.

type Selector

type Selector struct {
	Phone      string
	NationalID string
}

Selector picks a person by phone number or national ID; exactly one is set.

type Store

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

Store is the Postgres-backed pilot list.

func NewStore

func NewStore(db *gorm.DB) (*Store, error)

NewStore builds the store.

func (*Store) Add

func (s *Store) Add(ctx context.Context, u User) (User, error)

Add inserts u, or updates the row for its phone number and clears any revoke on it. Phone and national ID are normalised; Language defaults to en.

func (*Store) Get

func (s *Store) Get(ctx context.Context, number string) (User, error)

Get returns the row for number, or ErrNotFound.

func (*Store) List

func (s *Store) List(ctx context.Context, includeRevoked bool) ([]User, error)

List returns rows by creation time, active only unless includeRevoked.

func (*Store) Matches

func (s *Store) Matches(ctx context.Context, number, nationalID string) (bool, error)

Matches implements Gate.

func (*Store) PendingInvites

func (s *Store) PendingInvites(ctx context.Context) ([]User, error)

PendingInvites returns active rows never invited whose number has not registered.

func (*Store) PhoneActive

func (s *Store) PhoneActive(ctx context.Context, number string) (bool, error)

PhoneActive implements Gate.

func (*Store) RecordInvite

func (s *Store) RecordInvite(ctx context.Context, number string, sendErr error) error

RecordInvite records one invite attempt for number: a success stamps invited_at, a failure only the error. Both count the attempt.

func (*Store) Registered

func (s *Store) Registered(ctx context.Context, number string) (bool, error)

Registered reports whether number already belongs to a registered user.

func (*Store) Restore

func (s *Store) Restore(ctx context.Context, sel Selector) ([]User, error)

Restore clears the revoke on every row for the selected person and returns them.

func (*Store) Revoke

func (s *Store) Revoke(ctx context.Context, sel Selector, reason string) ([]User, error)

Revoke revokes every active row for the selected person and returns them.

func (*Store) Unlisted

func (s *Store) Unlisted(ctx context.Context) ([]Unlisted, error)

Unlisted returns registered users the gate would lock out.

func (*Store) UserActive

func (s *Store) UserActive(ctx context.Context, userID string) (bool, error)

UserActive implements Gate.

type Unlisted

type Unlisted struct {
	ID           string
	MobileNumber string
	NationalID   *string
	FullName     *string
}

Unlisted is a registered user without an active row matching both their phone number and national ID.

type User

type User struct {
	PhoneNumber     string `gorm:"primaryKey"`
	NationalID      string
	FullName        string
	Language        string
	Note            *string
	AddedBy         *string
	CreatedAt       time.Time
	UpdatedAt       time.Time
	RevokedAt       *time.Time
	RevokedReason   *string
	InvitedAt       *time.Time
	InviteCount     int
	LastInviteError *string
}

User is one pilot_users row.

func (User) Active

func (u User) Active() bool

Active reports whether the row is not revoked.

func (User) TableName

func (User) TableName() string

TableName maps User to pilot_users.

Jump to

Keyboard shortcuts

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