Documentation
¶
Overview ¶
Package store owns the database: opening it, migrating it and the repositories over it. Self-host runs on SQLite, one file in the data directory; the hosted build can run on Postgres, where row-level security keeps each tenant's rows to that tenant (MAI-150).
Index ¶
- Constants
- Variables
- func CheckSchema(ctx context.Context, db *sql.DB) error
- func Migrate(ctx context.Context, db *sql.DB) error
- func Month(t time.Time) string
- func Open(ctx context.Context, dataDir string) (*sql.DB, error)
- func OpenPostgres(ctx context.Context, dsn string) (*sql.DB, error)
- func OpenSetting(k crypto.TenantKey, name, stored string) (string, error)
- func RoleName(role string) string
- func RoleRank(role string) int
- func SealSetting(k crypto.TenantKey, name, value string) (string, error)
- func TenantOf(ctx context.Context) int64
- func URLHint(raw string) string
- func WithActor(ctx context.Context, a Actor) context.Context
- func WithTenant(ctx context.Context, tenantID int64) context.Context
- func WithoutActor(ctx context.Context) context.Context
- type Account
- type Action
- type ActivityFilter
- type ActivityRow
- type Actor
- type AuditEntry
- type Batch
- type CleanupBatch
- type Contact
- type Correction
- type Decision
- type Delivery
- type Destination
- type DestinationSecret
- type DraftJob
- type DraftRef
- type EndedPlan
- type FeedCursor
- type Filed
- type Folder
- type FollowUps
- type Forget
- type Forgotten
- type Identity
- type Invitation
- type Keyring
- type Ledger
- type MailboxLimitError
- type MasterKeyUses
- type Member
- type Message
- type Move
- type NewRule
- type Notice
- type NoticePayload
- type Plan
- type PlanState
- type Question
- type Removal
- type RemovedMailbox
- type RuleStat
- type RuleUse
- type SeatCheck
- type SeatLimit
- type SeatLimitError
- type SecretsCheck
- type SenderDecision
- type SenderSeen
- type Signals
- type Snapshot
- type Store
- func (s *Store) AIEmails(ctx context.Context, tenantID int64, month string) (int, error)
- func (s *Store) AcceptInvitation(ctx context.Context, tenantID int64, email string, now int64) error
- func (s *Store) Account(ctx context.Context, id int64) (Account, error)
- func (s *Store) AccountSecret(ctx context.Context, id int64) (string, error)
- func (s *Store) AccountTenant(ctx context.Context, accountID int64) (int64, error)
- func (s *Store) Accounts(ctx context.Context) ([]Account, error)
- func (s *Store) Action(ctx context.Context, id int64) (Action, error)
- func (s *Store) Activity(ctx context.Context, v Viewer, f ActivityFilter) ([]ActivityRow, error)
- func (s *Store) ActivityFor(ctx context.Context, v Viewer, messageID int64) (ActivityRow, error)
- func (s *Store) AddBatchProgress(ctx context.Context, id int64, done, skipped, tokens int, costUSD float64) error
- func (s *Store) AddCorrection(ctx context.Context, tenantID, userID int64, c Correction, always string) (int64, error)
- func (s *Store) AddDecision(ctx context.Context, d Decision, state string) (int64, error)
- func (s *Store) AddFolder(ctx context.Context, accountID int64, name string) error
- func (s *Store) AddLearnedSenderRule(ctx context.Context, tenantID, userID int64, address string, ruleID, now int64) (bool, error)
- func (s *Store) AddUnsubscribe(ctx context.Context, accountID int64, address, host string, now int64) error
- func (s *Store) AddUsage(ctx context.Context, tenantID int64, operator bool, ...) error
- func (s *Store) AdvanceFolder(ctx context.Context, ref mail.MsgRef) error
- func (s *Store) AnswerQuestion(ctx context.Context, v Viewer, id int64, yes bool, now int64) (Question, error)
- func (s *Store) AskMove(ctx context.Context, moveID, now int64) (Question, bool, error)
- func (s *Store) Audit(ctx context.Context, tenantID int64, action, target, detail string) error
- func (s *Store) AuditLog(ctx context.Context, tenantID, since, until int64) ([]AuditEntry, error)
- func (s *Store) Batch(ctx context.Context, id int64) (Batch, error)
- func (s *Store) BatchActionCounts(ctx context.Context, v Viewer, batchID int64) (map[string]int, error)
- func (s *Store) BatchActions(ctx context.Context, batchID int64) ([]Action, error)
- func (s *Store) Batches(ctx context.Context, v Viewer, kind string, before int64, limit int) ([]Batch, error)
- func (s *Store) CanSee(ctx context.Context, v Viewer, accountID int64) (bool, error)
- func (s *Store) CheckSecrets(ctx context.Context) (SecretsCheck, error)
- func (s *Store) ClaimSummary(ctx context.Context, userID, dueAt, now int64, maxAttempts int) (id int64, attempt int, ok bool, err error)
- func (s *Store) Corrections(ctx context.Context, v Viewer, limit int) ([]Correction, error)
- func (s *Store) CountMessages(ctx context.Context, v Viewer, state string) (int, error)
- func (s *Store) CreateAccount(ctx context.Context, a Account, secret string) (Account, error)
- func (s *Store) CreateAccountWithin(ctx context.Context, a Account, secret string, max int) (Account, error)
- func (s *Store) CreateBatch(ctx context.Context, tenantID int64, kind, status string, now int64) (int64, error)
- func (s *Store) CreateCleanupBatch(ctx context.Context, accountID int64, folder string, since int64, ...) (Batch, error)
- func (s *Store) CreateCleanupRun(ctx context.Context, cs []CleanupBatch, now int64) ([]Batch, error)
- func (s *Store) CreateDestination(ctx context.Context, d Destination, sec DestinationSecret, now int64) (Destination, error)
- func (s *Store) CreateFirstUser(ctx context.Context, email, passwordHash string, now int64) (User, error)
- func (s *Store) CreateInvitation(ctx context.Context, tenantID int64, inv Invitation, seats SeatLimit, ...) (Invitation, error)
- func (s *Store) CreateRule(ctx context.Context, tenantID int64, r rules.Rule, now int64) (rules.Rule, error)
- func (s *Store) CreateRules(ctx context.Context, tenantID, userID int64, added []NewRule, now int64) ([]rules.Rule, error)
- func (s *Store) CreateSession(ctx context.Context, tokenHash string, userID, now, expiresAt int64) error
- func (s *Store) CreateTenant(ctx context.Context, provider, externalID string, now int64) (int64, error)
- func (s *Store) CreateUser(ctx context.Context, tenantID int64, email, passwordHash string, now int64) (User, error)
- func (s *Store) DecisionDraft(ctx context.Context, tenantID, decisionID int64) (a Action, ok bool, err error)
- func (s *Store) DeleteAccount(ctx context.Context, id, now int64) ([]rules.Rule, error)
- func (s *Store) DeleteDestination(ctx context.Context, tenantID, id, now int64) ([]rules.Rule, error)
- func (s *Store) DeleteOwnAccount(ctx context.Context, provider, subject string, now int64) (Forget, error)
- func (s *Store) DeleteRule(ctx context.Context, tenantID, id int64) error
- func (s *Store) DeleteSenderRule(ctx context.Context, tenantID int64, matchType, value string) error
- func (s *Store) DeleteSession(ctx context.Context, tokenHash string) error
- func (s *Store) DeleteTenantSecrets(ctx context.Context, tenantID, endedAt, now int64) ([]int64, error)
- func (s *Store) Destination(ctx context.Context, id int64) (Destination, error)
- func (s *Store) DestinationSecret(ctx context.Context, id int64) (DestinationSecret, error)
- func (s *Store) Destinations(ctx context.Context, tenantID int64) ([]Destination, error)
- func (s *Store) DoneActionsSince(ctx context.Context, v Viewer, ruleID, since int64) ([]Action, error)
- func (s *Store) DraftDone(ctx context.Context, j DraftJob) error
- func (s *Store) DraftRetry(ctx context.Context, j DraftJob, next int64) error
- func (s *Store) DryRun(ctx context.Context, tenantID int64, def bool) (bool, error)
- func (s *Store) DueForRemoval(ctx context.Context, now int64) ([]Forgotten, error)
- func (s *Store) DueMessages(ctx context.Context, accountID, now int64) ([]Message, error)
- func (s *Store) EndIdentitySessions(ctx context.Context, provider, subject string) error
- func (s *Store) EndTrial(ctx context.Context, tenantID, now int64) (bool, error)
- func (s *Store) EndedPlan(ctx context.Context, tenantID, now int64) (EndedPlan, error)
- func (s *Store) ExpireRemovedMailboxes(ctx context.Context, now int64) ([]RemovedMailbox, error)
- func (s *Store) ExtendSession(ctx context.Context, tokenHash string, expiresAt int64) error
- func (s *Store) FailRunningBatches(ctx context.Context) error
- func (s *Store) FiledSince(ctx context.Context, accountID, since, afterID int64, limit int) ([]Filed, error)
- func (s *Store) FinishAction(ctx context.Context, a Action, then FollowUps) error
- func (s *Store) FinishSummary(ctx context.Context, id int64, sent bool, periodStart, periodEnd, now int64) error
- func (s *Store) FirstCleanupUsed(ctx context.Context, tenantID int64) (int, error)
- func (s *Store) FirstUser(ctx context.Context) (User, error)
- func (s *Store) Folder(ctx context.Context, accountID int64, name string) (Folder, error)
- func (s *Store) Folders(ctx context.Context, accountID int64) ([]Folder, error)
- func (s *Store) ForgetIdentity(ctx context.Context, provider, subject string, now int64) (Forget, error)
- func (s *Store) HasUsers(ctx context.Context) (bool, error)
- func (s *Store) HitSenderRule(ctx context.Context, id int64) error
- func (s *Store) IdentityMailboxes(ctx context.Context, provider, subject string) ([]int64, error)
- func (s *Store) ImportRules(ctx context.Context, tenantID, userID int64, imported []rules.Rule, now int64) (created, updated int, err error)
- func (s *Store) IngestMessage(ctx context.Context, ref mail.MsgRef, now int64) (m Message, fresh bool, err error)
- func (s *Store) InsertAction(ctx context.Context, a Action) (int64, error)
- func (s *Store) Invitations(ctx context.Context, tenantID, now int64) ([]Invitation, error)
- func (s *Store) IsContact(ctx context.Context, accountID int64, address string) (bool, error)
- func (s *Store) LastMailAt(ctx context.Context, accountID int64) (int64, error)
- func (s *Store) LastOwner(ctx context.Context, u User) (bool, error)
- func (s *Store) LastSentSummary(ctx context.Context, userID int64) (Summary, error)
- func (s *Store) LeaveOwnMail(ctx context.Context, tenantID int64) (bool, error)
- func (s *Store) LeftByMailRules(ctx context.Context, accountID int64, folder string, uidValidity, uid uint32, ...) (bool, error)
- func (s *Store) LiveBatch(ctx context.Context, tenantID int64, now time.Time) (int64, error)
- func (s *Store) MarkActionUndone(ctx context.Context, a Action, restored mail.MsgRef, now int64) error
- func (s *Store) MasterKeyUses(ctx context.Context) (MasterKeyUses, error)
- func (s *Store) Members(ctx context.Context, tenantID int64) ([]Member, error)
- func (s *Store) Message(ctx context.Context, id int64) (Message, error)
- func (s *Store) MessageActions(ctx context.Context, messageID int64) ([]Action, error)
- func (s *Store) MessageActivity(ctx context.Context, messageID int64) (ActivityRow, error)
- func (s *Store) MessageByMessageID(ctx context.Context, accountID int64, messageID string, except int64) (Message, error)
- func (s *Store) MessageCorrections(ctx context.Context, messageID int64) ([]Correction, error)
- func (s *Store) MessageDecisions(ctx context.Context, messageID int64) ([]Decision, error)
- func (s *Store) MoveHanded(ctx context.Context, id, now int64) error
- func (s *Store) MoveRetry(ctx context.Context, id, next int64) error
- func (s *Store) NoticeHanded(ctx context.Context, id, now int64) error
- func (s *Store) NoticeRetry(ctx context.Context, id, next int64) error
- func (s *Store) OpenQuestions(ctx context.Context, v Viewer) ([]Question, error)
- func (s *Store) Ping(ctx context.Context) error
- func (s *Store) PlanEndTenants(ctx context.Context, now int64) ([]int64, error)
- func (s *Store) PlanWarned(ctx context.Context, tenantID, endedAt int64, n int, now int64) error
- func (s *Store) PutSenderRule(ctx context.Context, tenantID int64, sr rules.SenderRule, now int64) (rules.SenderRule, error)
- func (s *Store) QueueSeatCheck(ctx context.Context, tenantID, now int64) error
- func (s *Store) QuietRules(ctx context.Context, v Viewer, since int64) (int, error)
- func (s *Store) Rebind(ctx context.Context, fresh, known int64, ref mail.MsgRef) (bool, error)
- func (s *Store) RecentDeliveries(ctx context.Context, tenantID int64, perDestination int) (map[int64][]Delivery, error)
- func (s *Store) RecentSenderDecisions(ctx context.Context, v Viewer, address string, n int) ([]SenderDecision, error)
- func (s *Store) ReconcileRemovedMailboxes(ctx context.Context, now int64) ([]rules.Rule, error)
- func (s *Store) RecordDelivery(ctx context.Context, noticeID int64, sent bool, reason string, at int64) (tenantID int64, err error)
- func (s *Store) RecordMove(ctx context.Context, m Move) (int64, error)
- func (s *Store) RemovalAccounts(ctx context.Context, userID int64) ([]int64, error)
- func (s *Store) RemoveEndedTenant(ctx context.Context, tenantID, endedAt, now int64) (Removal, error)
- func (s *Store) RemoveForgotten(ctx context.Context, userID, now int64) (Removal, error)
- func (s *Store) RemoveMember(ctx context.Context, provider, subject string, now int64) (Forget, error)
- func (s *Store) RemovedMailboxRetry(ctx context.Context, id, next int64) error
- func (s *Store) RemovedMailboxSecret(ctx context.Context, id int64) (string, error)
- func (s *Store) RemovedMailboxTaken(ctx context.Context, id int64) error
- func (s *Store) ReorderRules(ctx context.Context, tenantID int64, ids []int64) error
- func (s *Store) ReplaceUnopenableTenantKeys(ctx context.Context) (int, error)
- func (s *Store) Retain(ctx context.Context, tenantID, now int64, retentionDays int) (blanked, deleted int64, err error)
- func (s *Store) RevokeInvitation(ctx context.Context, tenantID, id int64, why string, now int64) (Invitation, error)
- func (s *Store) RewrapTenantKeys(ctx context.Context) (int, error)
- func (s *Store) Rule(ctx context.Context, tenantID, id int64) (rules.Rule, error)
- func (s *Store) RuleCosts(ctx context.Context, v Viewer, since int64) ([]RuleUse, error)
- func (s *Store) RuleStats(ctx context.Context, v Viewer, since int64) (map[int64]RuleStat, error)
- func (s *Store) Rules(ctx context.Context, tenantID int64) ([]rules.Rule, error)
- func (s *Store) RunInEffect(ctx context.Context, tenantID, decisionID int64) (bool, error)
- func (s *Store) SaveFolders(ctx context.Context, accountID int64, folders []Folder) error
- func (s *Store) SaveMessageSummary(ctx context.Context, m Message) error
- func (s *Store) SeatCheckDone(ctx context.Context, c SeatCheck) error
- func (s *Store) SeatCheckRetry(ctx context.Context, c SeatCheck, next int64) error
- func (s *Store) SeatsUsed(ctx context.Context, tenantID, now int64) (int, error)
- func (s *Store) SenderRules(ctx context.Context, tenantID int64) ([]rules.SenderRule, error)
- func (s *Store) SendersSeen(ctx context.Context, v Viewer, since int64) ([]SenderSeen, error)
- func (s *Store) SessionUser(ctx context.Context, tokenHash string, now int64) (User, int64, error)
- func (s *Store) SetAccountCapabilities(ctx context.Context, id int64, capabilities []string) error
- func (s *Store) SetAccountCert(ctx context.Context, id int64, fingerprint string) error
- func (s *Store) SetAccountSecret(ctx context.Context, id int64, secret string) error
- func (s *Store) SetAccountShared(ctx context.Context, id int64, shared bool) error
- func (s *Store) SetAccountStatus(ctx context.Context, id int64, status, lastError string, now int64) error
- func (s *Store) SetBatchProgress(ctx context.Context, id int64, total, done int) error
- func (s *Store) SetBatchStatus(ctx context.Context, id int64, status string) error
- func (s *Store) SetDryRun(ctx context.Context, tenantID int64, on bool) error
- func (s *Store) SetFolderPosition(ctx context.Context, accountID int64, name string, uidValidity, lastUID uint32) error
- func (s *Store) SetInvitationRecord(ctx context.Context, tenantID, id int64, rec string) error
- func (s *Store) SetMessageState(ctx context.Context, id int64, state string, attempts int, nextAttemptAt int64) error
- func (s *Store) SetPassword(ctx context.Context, userID int64, passwordHash string) error
- func (s *Store) SetPlan(ctx context.Context, tenantID int64, p Plan, now int64) (before, after PlanState, err error)
- func (s *Store) SetRole(ctx context.Context, tenantID, userID int64, role string, now int64) error
- func (s *Store) SetSetting(ctx context.Context, tenantID int64, key, value string) error
- func (s *Store) SetSettings(ctx context.Context, tenantID int64, values map[string]*string) error
- func (s *Store) SetTrashToFolder(ctx context.Context, tenantID int64, on bool) error
- func (s *Store) Setting(ctx context.Context, tenantID int64, key string) (string, error)
- func (s *Store) Settings(ctx context.Context, tenantID int64) (map[string]string, error)
- func (s *Store) SignInIdentity(ctx context.Context, id Identity, now int64, seats SeatLimit) (User, error)
- func (s *Store) SpendAIEmails(ctx context.Context, tenantID int64, at time.Time, n int) error
- func (s *Store) SpendCleanupEmail(ctx context.Context, tenantID int64, at time.Time, grant int) (fromGrant bool, err error)
- func (s *Store) StatsTotals(ctx context.Context, v Viewer, since int64) (Totals, error)
- func (s *Store) SummaryCost(ctx context.Context, v Viewer, from, to int64) (costUSD float64, calls int, err error)
- func (s *Store) SummaryReview(ctx context.Context, v Viewer, limit int) ([]SummaryEmail, int, error)
- func (s *Store) SummaryRules(ctx context.Context, v Viewer, from, to int64) ([]RuleUse, error)
- func (s *Store) SummaryTrashed(ctx context.Context, v Viewer, from, to int64, limit int) ([]SummaryEmail, int, error)
- func (s *Store) TenantAccounts(ctx context.Context, tenantID int64) ([]Account, error)
- func (s *Store) TenantEmails(ctx context.Context, tenantID int64) ([]string, error)
- func (s *Store) TenantKey(ctx context.Context, tenantID int64) (crypto.TenantKey, error)
- func (s *Store) TenantMembers(ctx context.Context, tenantID int64) (int, error)
- func (s *Store) TenantOrganisation(ctx context.Context, tenantID int64) (provider, organisation string, err error)
- func (s *Store) TenantPlan(ctx context.Context, tenantID, now int64) (PlanState, error)
- func (s *Store) Tenants(ctx context.Context) ([]int64, error)
- func (s *Store) TopRules(ctx context.Context, v Viewer, since int64, limit int) ([]RuleUse, error)
- func (s *Store) TrashToFolder(ctx context.Context, tenantID int64) (bool, error)
- func (s *Store) UnsubscribeLinks(ctx context.Context, v Viewer, address string, since int64) ([]UnsubscribeLink, error)
- func (s *Store) UpdateAccount(ctx context.Context, a Account) error
- func (s *Store) UpdateRule(ctx context.Context, tenantID int64, r rules.Rule, now int64) error
- func (s *Store) UpgradeSecrets(ctx context.Context) (int, error)
- func (s *Store) UpsertContacts(ctx context.Context, accountID int64, contacts []Contact) error
- func (s *Store) Usage(ctx context.Context, tenantID int64, sinceDay string) ([]UsageRow, error)
- func (s *Store) User(ctx context.Context, id int64) (User, error)
- func (s *Store) UserByEmail(ctx context.Context, email string) (User, error)
- func (s *Store) UserIdentity(ctx context.Context, userID int64) (Identity, error)
- func (s *Store) Users(ctx context.Context) ([]User, error)
- func (s *Store) VisibleAccount(ctx context.Context, v Viewer, id int64) (Account, error)
- func (s *Store) VisibleAccounts(ctx context.Context, v Viewer) ([]Account, error)
- func (s *Store) VisibleAction(ctx context.Context, v Viewer, id int64) (Action, error)
- func (s *Store) VisibleBatch(ctx context.Context, v Viewer, id int64) (Batch, error)
- func (s *Store) VisibleBatchActions(ctx context.Context, v Viewer, batchID int64) ([]Action, error)
- func (s *Store) VisibleMessage(ctx context.Context, v Viewer, id int64) (Message, error)
- func (s *Store) WaitingDrafts(ctx context.Context, now int64, limit int) ([]DraftJob, error)
- func (s *Store) WaitingMoves(ctx context.Context, now int64, limit int) ([]Move, error)
- func (s *Store) WaitingNotices(ctx context.Context, now int64, limit int) ([]Notice, error)
- func (s *Store) WaitingRemovedMailboxes(ctx context.Context, now int64, limit int) ([]RemovedMailbox, error)
- func (s *Store) WaitingSeatChecks(ctx context.Context, now int64, limit int) ([]SeatCheck, error)
- func (s *Store) WithKeyring(k *Keyring) *Store
- func (s *Store) WithKeys(p crypto.KeyProvider) *Store
- type Summary
- type SummaryEmail
- type Totals
- type UnsubscribeLink
- type UsageRow
- type User
- type Viewer
Constants ¶
const ( ActionDone = "done" ActionDryRun = "dry_run" ActionFailed = "failed" ActionUndone = "undone" )
Action statuses, as stored in actions.status.
const ( BatchLive = "live" BatchCleanup = "cleanup" BatchCorrection = "correction" BatchUndo = "undo" BatchRunning = "running" BatchDone = "done" BatchFailed = "failed" BatchUndone = "undone" )
Batch kinds and statuses, as stored in batches.
const ( SettingTrashToFolder = "trash_to_folder" DefaultTrashToFolder = true )
SettingTrashToFolder is the settings key of the switch that sends trashed mail to an ordinary folder of MailRules' own instead of the server's Trash, which providers empty on their own. DefaultTrashToFolder is in force until it is set, for a new install and an existing one alike.
const ( SettingLeaveOwnMail = "leave_own_mail" DefaultLeaveOwnMail = true )
SettingLeaveOwnMail is the settings key of the switch that leaves mail sent from the mailbox's own address alone (Account.OwnAddresses): no rule, model or action touches it. DefaultLeaveOwnMail is in force until it is set.
const ( AuditRuleCreated = "rule.created" AuditRuleChanged = "rule.changed" AuditRuleDeleted = "rule.deleted" AuditRulesReordered = "rules.reordered" AuditSenderRuleSet = "sender_rule.set" AuditSenderRuleDeleted = "sender_rule.deleted" AuditMailboxAdded = "mailbox.added" AuditMailboxChanged = "mailbox.changed" AuditMailboxRemoved = "mailbox.removed" AuditSettingsChanged = "settings.changed" AuditDestinationAdded = "notification.added" AuditDestinationRemoved = "notification.removed" AuditPlanChanged = "plan.changed" AuditMemberJoined = "member.joined" AuditMemberRoleChanged = "member.role_changed" AuditMemberRemoved = "member.removed" AuditInvitationCreated = "invitation.created" AuditInvitationRevoked = "invitation.revoked" AuditInvitationAccepted = "invitation.accepted" AuditInvitationWithdrawn = "invitation.withdrawn" // An Owner asked the billing service to add or remove the company sign-in add-on; the // change itself is the plan.changed row once the service reports it. AuditCompanySignInAddOn = "company_sign_in.add_on" // An Owner or Admin opened a link to set company sign-in up at the sign-in service. AuditCompanySignInPortal = "company_sign_in.portal" )
What the audit log records (AuditEntry.Action): who changed the tenant's rules, sender rules, mailboxes, members, invitations, settings and plan, and who asked for the company sign-in add-on or opened its setup link.
const ( StateNew = "new" // ingested, not yet decided StateDecided = "decided" // a decision is recorded, its actions are not finished StateActed = "acted" // the decision's actions ran (or were recorded as dry-run) StateReview = "review" // waiting in Needs review StateSkipped = "skipped" // nothing to do: no rule matched, or the message was gone StateError = "error" // failed; the retry job runs it again at NextAttemptAt )
Message states, as stored in messages.state.
const ( CorrectionFix = "correction" CorrectionReview = "review" )
What a correction was: a fix made from the feed, or an answer given in Needs review.
const ( QuestionOpen = "open" QuestionYes = "yes" QuestionNo = "no" )
Question statuses, as stored in move_questions.status.
const ( DestinationWebhook = "webhook" DestinationSlack = "slack" )
Notification destination kinds, as stored in notify_destinations.kind.
const ( DeliverySent = "sent" DeliveryFailed = "failed" )
Delivery statuses, as stored in notify_deliveries.status.
const ( PlanTrial = "trial" // no plan bought yet, within TrialDays of the tenant's creation PlanPersonal = "personal" PlanPro = "pro" PlanTeam = "team" // sold by the seat (Plan.Seats) PlanEnded = "ended" // the trial or the paid plan is over: nothing is sorted )
Plans, as a billing module reports them (SetPlan) and as TenantPlan sees them.
const ( IntervalMonth = "month" IntervalYear = "year" )
Billing intervals (Plan.Interval).
const ( StatusActive = "active" // StatusPastDue: a renewal is unpaid and the billing service retries it; the plan runs. StatusPastDue = "past_due" // StatusCancelsAtPeriodEnd: cancelled, running to PeriodEnd, when it ends. StatusCancelsAtPeriodEnd = "cancels_at_period_end" )
Plan statuses (Plan.Status).
const ( // TrialDays is how long a tenant's trial runs from its creation. TrialDays = 14 // EndedSecretsDays is how many days after a plan ends the tenant's mailbox passwords and // tokens and its model keys are deleted. EndedSecretsDays = 30 // EndedRemovalDays is how many days after a plan ends everything else of the tenant is // removed. EndedRemovalDays = 90 )
const ( SummarySending = "sending" SummarySent = "sent" SummaryFailed = "failed" )
Summary statuses, as stored in summaries.status.
const ( // RoleOwner: billing and the plan, members, everything an admin does. RoleOwner = "owner" // RoleAdmin: mailboxes, the shared rules and sender rules, members, settings, the audit log. RoleAdmin = "admin" // RoleMember: their own mailboxes, sorted by the shared rules. RoleMember = "member" )
The roles a user has in their tenant (User.Role). Who may do what with each is the API's to enforce; the store only keeps them, and keeps a team from losing its last owner.
const ActionDraft = "draft"
ActionDraft is the kind of the action that saves a reply a rule's drafting module wrote in the mailbox's Drafts folder. It changes nothing of the email it answers: its Before and After are where that email was, and Draft is where the reply went.
const ActionInterrupted = "interrupted before it finished"
ActionInterrupted is the error a row is written with before its change is made, which stays only when the daemon stopped before it recorded how the change ended.
const AuditDays = 365
AuditDays is how long a tenant's audit log keeps a row: a year, then the retention job deletes it.
const DefaultTenantKeyCache = time.Hour
DefaultTenantKeyCache is how long an unwrapped tenant key stays in memory unless the Keyring is told otherwise (MAILRULES_TENANT_KEY_CACHE).
const DraftWait = day
DraftWait is how long a draft job is tried, in seconds from when its rule acted: one not written by then is given up and recorded as a failed draft action. A reply drafted a day late is of little use, and the email may be answered by then.
const ForgetDays = 30
ForgetDays is how long what MailRules kept of a forgotten person waits before it is removed. Signing in again with the same identity before then cancels the removal, unless the person deleted their own account (DeleteOwnAccount) or was removed from their team (RemoveMember).
const InvitationDays = 7
InvitationDays is how long an invitation waits to be accepted before it expires; once the sign-in service says it was accepted, it waits as long again for the person's first sign-in.
const KeepMessagesDays = 180
KeepMessagesDays is how long a message's row is kept. After that it is deleted with its decisions and actions, unless one of its actions can still be undone: a move or a flag change that is in effect and was made in the last UndoDays. A recorded "keep" changed nothing worth putting back, so it does not hold a row.
const MoveDays = 30
MoveDays is how long a move the watcher found is kept: what the module was told, and what a question counts.
NewAccountShared is whether a mailbox someone adds starts shared with everyone in their tenant. It starts private: only its owner sees it, its mail and what MailRules did to it, until the owner shares it.
const NoLimit = -1
NoLimit is a limit that does not limit (CreateAccountWithin, and the limits a module sets).
const NoticeDays = 30
NoticeDays is how long a notice, and what its module reported of delivering it, is kept.
const RemovedMailboxDays = ForgetDays
RemovedMailboxDays is how long a removed mailbox waits for the module that connected it to take it (ext.Module.MailboxRemoved); then it is deleted with its copy of the secret.
const SelfHostTenant int64 = 1
SelfHostTenant is the one tenant of a self-hosted install, made by migration 0011.
const SettingSummary = "summary"
SettingSummary holds the summary email's settings, one JSON object (internal/summary).
const UndoDays = 30
UndoDays is how long an action stays undoable. Older ones are history: undo refuses them (actions.ErrTooOld) and they no longer hold their message's row.
Variables ¶
var ( // ErrTenantMismatch is a returning identity that arrived under a different organisation // than the one it signed up with. ErrTenantMismatch = errors.New("identity belongs to another tenant") // ErrEmailInUse is an email another user already has. ErrEmailInUse = errors.New("email in use by another user") // ErrRemovedMember is a person removed from a team (RemoveMember) signing in under its // organisation again without a new invitation. ErrRemovedMember = errors.New("removed from the team: a new invitation is needed") )
var ( // ErrLastOwner is a change that would leave a team with no owner. ErrLastOwner = errors.New("the team's last owner") // ErrBadRole is a role that is not one of Roles. ErrBadRole = errors.New("unknown role") // ErrAlreadyMember is an invitation for someone who is in the team already. ErrAlreadyMember = errors.New("already a member of the team") // ErrAlreadyInvited is an invitation for an address that has one waiting. ErrAlreadyInvited = errors.New("already invited") // ErrHasAccount is an invitation for an address that has a MailRules account of its own, // in any tenant: one person is one user in one tenant. ErrHasAccount = errors.New("the address has a MailRules account") // ErrSeatLimit is what a *SeatLimitError matches with errors.Is. ErrSeatLimit = errors.New("seat limit reached") )
var ErrAlreadySetUp = errors.New("already set up")
ErrAlreadySetUp means the first-run admin account already exists.
var ErrAnswered = errors.New("the person already answered the question about this sender and folder")
ErrAnswered is what AskMove returns when the person already answered the question about that sender and destination. Nothing changed.
var ErrBadPlan = errors.New("unknown plan, interval or status")
ErrBadPlan is what SetPlan returns for a plan, interval, status or seat count it does not know.
var ErrMailboxLimit = errors.New("the mailbox limit is reached")
ErrMailboxLimit is what CreateAccountWithin returns, as a *MailboxLimitError, when the tenant already has as many mailboxes as it may.
var ErrNoKeys = errors.New("store: no key provider")
ErrNoKeys means the store was given no KeyProvider, so it can seal or open no secret.
var ErrNoSecret = errors.New("the mailbox's password was deleted; enter it again")
ErrNoSecret is the answer for a mailbox whose secret was deleted (Account.SecretGone).
var ErrNotFound = errors.New("not found")
ErrNotFound means the row does not exist (or, for a session, has expired).
var ErrPlanNotEnded = errors.New("the tenant's plan has not ended")
ErrPlanNotEnded is what the end-of-plan steps return, changing nothing, for a tenant whose plan no longer ended when the caller saw it end: one bought again meanwhile, or one that ended again at another time.
var ErrRuleSet = errors.New("the list must name every rule exactly once")
ErrRuleSet means a reorder did not name each of the tenant's rules exactly once.
var ErrSchema = errors.New("the database schema does not match this build")
ErrSchema means the database's schema is not the one this build was made for: migrations it has not run, or one from a newer build.
var ErrTenantScope = errors.New("store: a tenant outside the current scope")
ErrTenantScope means a method was asked for one tenant inside the scope of another.
var Outcomes = []string{"sorted", "trashed", "inbox", "review"}
Outcomes are the four places a processed message ends up: the groups of the Overview bar (Totals.Went*) and the values of ActivityFilter.Outcome.
var Roles = []string{RoleOwner, RoleAdmin, RoleMember}
Roles are the roles, from the most a user may do to the least.
Functions ¶
func CheckSchema ¶ added in v0.3.0
CheckSchema reports, without changing anything, whether every embedded migration of the database's dialect has run, and none it does not know: what a daemon on Postgres checks at start, since it never migrates there (the roles it runs as own no table).
func Migrate ¶
Migrate applies every embedded migration of the database's dialect that has not run yet. On Postgres it runs as the role that owns the tables, and holds a session lock so two processes starting at once do not both migrate.
func Month ¶ added in v0.3.0
Month is the calendar month, in UTC as the usage ledger's days are, that an email decided at t counts in: YYYY-MM.
func Open ¶
Open opens (creating if needed) the SQLite database in dataDir, in WAL mode. Every transaction not begun read-only begins IMMEDIATE, holding the write lock from its first statement: a deferred one that read first could not write once another connection had committed meanwhile (SQLITE_BUSY_SNAPSHOT), which mailbox supervisors do all the time. Begin one that only reads with sql.TxOptions{ReadOnly: true}, so that it waits for no writer.
func OpenPostgres ¶ added in v0.3.0
OpenPostgres connects to the Postgres database at dsn (a postgres:// URL or key=value string). The role it signs in as must not own the tables nor bypass row-level security: the store relies on the policies to keep tenants apart. Migrations run as the owner.
func OpenSetting ¶ added in v0.3.0
OpenSetting opens a value SealSetting stored for name with the tenant's key k, or one sealed before tenant keys. A wrong key is crypto.ErrDecrypt.
func RoleRank ¶ added in v0.3.0
RoleRank orders the roles: an owner ranks above an admin, an admin above a member. An unknown role ranks below them all.
func SealSetting ¶ added in v0.3.0
SealSetting seals value for the settings row of name under the tenant's key k, as the row's JSON value.
func URLHint ¶ added in v0.3.0
URLHint is an address as Settings shows it: its scheme and host, then the last four characters when it has a path or query, so a Slack webhook's token stays unread.
func WithActor ¶ added in v0.3.0
WithActor says who makes the changes the store is asked for with ctx: each change to what the audit log covers is then recorded under them, in its own transaction. A request carries the signed-in person; a module's call carries the service it speaks for. Changes made with no actor (the mailbox workers, the startup checks, the retention job) are not recorded.
func WithTenant ¶ added in v0.3.0
WithTenant scopes ctx to the tenant: everything the store runs with it reads and writes that tenant's rows only. Inside a scope for another tenant, statements run with the result fail with ErrTenantScope. Tenant 0 adds nothing.
Types ¶
type Account ¶
type Account struct {
ID int64
UserID int64 // the owner: who added it
TenantID int64 // the owner's tenant
Label string
Preset string
Host string
Port int
TLSMode string
Username string
WatchFolder string
Status string // new | live | reconnecting | auth_failed | reconnect_needed | cert_changed | error | paused
LastError string
LastEventAt int64
Capabilities []string
CreatedAt int64
// CertFingerprint is the server certificate the person accepted, as mail.Cert has it:
// the server must present exactly that one. Empty: the system's trust store decides.
CertFingerprint string
// OAuth marks a mailbox connected with one-click sign-in: the module that signs in to its
// preset turns the stored secret (a refresh token) into an access token before every login.
OAuth bool
// Module marks a mailbox a module added (ext.Host.AddMailbox): its server is the
// module's, so the hosted build connects to it even when it is not on the public
// internet (publicnet). Moving the mailbox to another server clears it.
Module bool
// SecretGone: the mailbox's password or token was deleted (ForgetIdentity), so nothing
// can log in to it and no supervisor is started for it until its owner enters a new one.
SecretGone bool
}
Account is one mailbox the daemon watches. Its password is never part of this struct: read it with AccountSecret at the moment a connection is made.
func (Account) OwnAddresses ¶
OwnAddresses returns the account's own email addresses, lowercase: the username when it is a full address and, for a provider whose domains are known (presets.Preset.Domains), the name before "@" at each of them, so an iCloud username of only "jane" is jane@icloud.com, jane@me.com and jane@mac.com. Aliases are not known. It is nil when no address can be told: a username without "@" on a provider whose domains are not known.
type Action ¶
type Action struct {
ID int64
DecisionID int64 // 0 = none
BatchID int64 // 0 = none
MessageID int64
AccountID int64
Kind string // move | trash | archive | junk | flag | unflag | read | unread | keep | review | draft
Folder string // params.folder: the destination of a move, of a trash sent to MailRules' own folder (trash_to_folder), or the Drafts folder of a draft
// Draft is where a draft action saved its reply, once it did (params.draft); nil for
// every other kind.
Draft *DraftRef
Before Snapshot
After *Snapshot // nil unless the action is done (or was, before an undo)
Status string
Error string
CreatedAt int64
UndoneAt int64
}
Action is one row of actions: one step taken (or, in dry-run, not taken) on a message.
type ActivityFilter ¶
type ActivityFilter struct {
ID int64 // only this message
AccountID int64
RuleID int64
Stage string
State string // a message state; StateReview lists Needs review
Action string // an action kind: only messages with such an action
Outcome string // one of Outcomes: where the message ended up, as the stats count it
After FeedCursor
Limit int // 0 = 50
}
ActivityFilter narrows Activity. Zero fields do not filter.
type ActivityRow ¶
ActivityRow is a message with its latest decision and every action taken on it, oldest first; Decision is nil until one is made.
func (ActivityRow) Cursor ¶
func (r ActivityRow) Cursor() FeedCursor
Cursor is the position of this row in the feed, for the page after it.
type Actor ¶ added in v0.3.0
Actor is who makes the changes of a context (WithActor): a person, by their user and email, or a service by its name (UserID 0).
type AuditEntry ¶ added in v0.3.0
type AuditEntry struct {
ID int64
At int64
ActorID int64 // 0: a service, or a person whose user is gone
Actor string
Action string // one of the Audit* constants
Target string // what was changed, by name: a rule, a mailbox's address, a member's email
Detail string // how, in a few words; never an address (withoutAddresses)
}
AuditEntry is one row of a tenant's audit log. It never holds email content or a secret.
type Batch ¶
type Batch struct {
ID int64
TenantID int64
Kind string // live | cleanup | review | correction | undo
Status string // running | done | failed | undone
Total int // how many items the batch set out to handle; 0 = not counted (live)
Done int // how many it has handled
CreatedAt int64
// What a cleanup batch sorted, and what its model calls have cost so far. Zero for
// the other kinds.
AccountID int64
Folder string
Since int64 // only mail received from this time on; 0 = all of it
Tokens int // model tokens, in and out
CostUSD float64
// Skipped is how many selected emails a cleanup Sort passed over because they were no
// longer where its check found them (MAI-44). 0 for the other kinds.
Skipped int
// ScanLimit is the most emails the cleanup's check was allowed to cover, and ScanMatched
// how many the folder held in the range before that cut (MAI-48). ScanLimit 0 = not
// recorded (a batch made before this), and then ScanMatched means nothing.
ScanLimit int
ScanMatched int
// RunID joins the batches of one manual run over several mailboxes, one per mailbox
// (MAI-43): it is the id of the run's first batch, the same on every one. 0 = not part of
// such a run, which is every other batch and a cleanup of one mailbox.
RunID int64
}
Batch is one row of batches: a group of actions that can be undone together.
type CleanupBatch ¶ added in v0.1.2
type CleanupBatch struct {
AccountID int64
Folder string
Since int64 // only mail received from this time on; 0 = all of it
// ScanLimit and ScanMatched say how much mail the check behind the batch covered: the
// most emails it was allowed and how many the range held before that cut. ScanLimit 0
// records nothing.
ScanLimit, ScanMatched int
Total int // emails the batch sorts
}
CleanupBatch is what a cleanup batch is opened with.
type Correction ¶
type Correction struct {
ID int64
MessageID int64
WrongRuleID int64 // 0 = no rule had been applied
RightRuleID int64 // 0 = keep in the inbox
RightRule string // that rule's name, when read back; empty for keep, or once the rule is deleted
Kind string // CorrectionFix | CorrectionReview; empty is stored as CorrectionFix
Example string // JSON message.Summary, the few-shot example
CreatedAt int64
}
Correction is one row of corrections: the user said a message belongs to another rule.
type Decision ¶
type Decision struct {
ID int64
MessageID int64
Stage string // sender | condition | decider | fallback | none
RuleID int64 // 0 = no rule; in Needs review, the rule the model suggested
RuleName string // the rule's name: as it is now, or as it was when decided if the rule is gone
RuleVersion int
Confidence float64
Reason string
Model string
TokensIn int
TokensOut int
CostUSD float64
LatencyMS int64
CreatedAt int64
// Probabilities is what the decision model gave each candidate rule, by rule id, with
// 0 for "none of these". nil when the model gives no such spread, or none was asked.
Probabilities map[int64]float64
// SenderSource is who made the sender rule that settled the email (Stage sender): user
// or learned. Empty for other stages, and for a sender decision recorded before it was
// kept whose origin cannot be told.
SenderSource string
// Metered: a model on keys the operator holds made the decision, so AddDecision counts the
// email against its tenant's monthly allowance (once per message). It is not stored on
// the decision.
Metered bool
}
Decision is one row of decisions: what was decided for a message, and what it cost.
type Delivery ¶ added in v0.3.0
type Delivery struct {
ID int64
DestinationID int64
NoticeID int64
RuleID int64 // 0 once the rule was deleted
RuleName string
Status string // DeliverySent | DeliveryFailed
Reason string // why it failed; empty when sent
CreatedAt int64
}
Delivery is one result a module reported of delivering a notice.
type Destination ¶ added in v0.3.0
type Destination struct {
ID int64
TenantID int64
Name string
Kind string // DestinationWebhook | DestinationSlack
URLHint string // the address cut short (URLHint), the only form of it shown
CreatedAt int64
// AddressDeleted: the address and secret were deleted with the sign-in of the person who
// was the tenant's only member (ForgetIdentity); nothing can be delivered to it.
AddressDeleted bool
}
Destination is one place a tenant's rule notifications go. Its address and signing secret are never part of it: read them with DestinationSecret when a notice is handed over.
func (Destination) NeedsHTTPS ¶ added in v0.3.0
func (d Destination) NeedsHTTPS() bool
NeedsHTTPS reports a destination added with a plain http address before only https was taken: it stays listed, but no notice is queued or handed over for it until it is replaced.
type DestinationSecret ¶ added in v0.3.0
DestinationSecret is what is sealed for a destination: where notices go and, for a webhook, the secret deliveries are signed with.
type DraftJob ¶ added in v0.3.0
type DraftJob struct {
ID int64
TenantID int64
AccountID int64
MessageID int64 // the Activity id
DecisionID int64
BatchID int64
RuleID int64 // 0 once the rule was deleted
RuleName string
// Instruction and ReadPrevious are the rule's Draft as it stood when it acted.
Instruction string
ReadPrevious bool
// Key is the job's own, the same on every attempt: the draft's Message-ID is made from
// it, so a draft saved before a crash is found again instead of saved twice.
Key string
CreatedAt int64 // when the rule acted
Attempts int // tries that failed so far
}
DraftJob is one reply waiting to be drafted: a rule with Draft set acted on an email live.
type DraftRef ¶ added in v0.3.0
type DraftRef struct {
UIDValidity uint32 `json:"uidvalidity"`
UID uint32 `json:"uid"`
// MessageID is the reply's own Message-ID, without angle brackets: how it is found
// again when its folder's UIDVALIDITY changed, and checked before it is deleted.
MessageID string `json:"message_id"`
}
DraftRef is where a draft action saved its reply: params.draft.
type EndedPlan ¶ added in v0.3.0
type EndedPlan struct {
PlanState
// WarnedAt is when warning number Warned was sent (PlanWarned); 0 while none was.
WarnedAt int64
}
EndedPlan is a tenant's plan as the end-of-plan job sees it: TenantPlan's state, and when the latest warning email was sent.
type FeedCursor ¶
FeedCursor is where a page of Activity ends: the ActedAt and ID of its last row. The next page starts after it in the feed's order. The zero value is the first page.
type Filed ¶ added in v0.3.0
type Filed struct {
ActionID int64
MessageID int64
MsgID string // the RFC 5322 Message-ID, without angle brackets
From string
RuleID int64 // the rule that decided; 0 = none, or deleted since
RuleName string // its name when it decided
Before Snapshot
After Snapshot
FiledAt int64
}
Filed is an email a done move-type action of MailRules left somewhere and that no later MailRules action moved on: where the move watcher expects it.
type Folder ¶
type Folder struct {
AccountID int64
Name string
Delimiter string
SpecialUse string // \Junk \Trash \Archive \Sent \Drafts or empty
UIDValidity uint32
LastUID uint32 // highest UID processed
}
Folder is one folder of an account, with the watch position when it is watched.
type FollowUps ¶ added in v0.3.0
type FollowUps struct {
Notices bool // the rule's notifications (queueNotices)
Draft bool // the rule's draft reply (queueDraft)
}
FollowUps are what a rule's run on one email starts once the action that ends it is recorded, in the same transaction, so they exist exactly when the actions they follow do.
type Forget ¶ added in v0.3.0
type Forget struct {
UserID, TenantID int64 // 0 when no user has the identity
// Accounts are the person's mailboxes whose secrets it deleted: every mailbox of the
// tenant when they are its only member, else the ones they own, shared or not.
Accounts []int64
// Keys is whether it deleted the tenant's stored model API keys, and the addresses and
// signing secrets of its notification destinations: the person is the tenant's only
// member.
Keys bool
}
Forget is what ForgetIdentity did at once.
type Identity ¶ added in v0.2.0
type Identity struct {
Provider, Subject, Email, Tenant string
}
Identity is a person as a sign-in service names them: Subject is the service's stable id for them and Tenant the id of the organisation they signed in under.
type Invitation ¶ added in v0.3.0
type Invitation struct {
ID, TenantID int64
Email string
Role string
// InvitedBy is the user who sent it, and InvitedByEmail their address; 0 and empty once
// they left.
InvitedBy int64
InvitedByEmail string
// Record is the module's own reference to it at the service that sent it.
Record string
CreatedAt int64
ExpiresAt int64
AcceptedAt int64 // 0 until the sign-in service says it was accepted
}
Invitation is an invitation to join a tenant, waiting.
type Keyring ¶ added in v0.3.0
type Keyring struct {
// contains filtered or unexported fields
}
Keyring is a KeyProvider and the tenant keys it has unwrapped. Each stays in memory for a bounded time, then is unwrapped again, so a tenant whose key the provider no longer unwraps (a key service that went away) can open nothing once that time is up. Keys are held by tenant, KEK and wrapped key: one that changes (a new tenant under a reused id, a rotation) is unwrapped anew. Requests that need the same key at once share one unwrap. Every Store that seals with the same provider should share one Keyring (the app's and the worker's connections), so a tenant's key is unwrapped once for both.
func NewKeyring ¶ added in v0.3.0
func NewKeyring(p crypto.KeyProvider, ttl time.Duration) *Keyring
NewKeyring is a Keyring for p that keeps a key unwrapped for ttl (DefaultTenantKeyCache when ttl is not positive).
type Ledger ¶ added in v0.2.0
Ledger books model usage for one tenant (models.UsageStore). Operator says, by the provider a call went to (models.Usage.Provider), whether it used a key the operator holds; nil marks none.
type MailboxLimitError ¶ added in v0.3.0
type MailboxLimitError struct {
Limit, Connected int
}
MailboxLimitError is a mailbox refused because its tenant has Connected mailboxes and may have Limit. Its text is the sentence the screen shows.
func (*MailboxLimitError) Error ¶ added in v0.3.0
func (e *MailboxLimitError) Error() string
func (*MailboxLimitError) Is ¶ added in v0.3.0
func (e *MailboxLimitError) Is(target error) bool
Is makes errors.Is(err, ErrMailboxLimit) true.
type MasterKeyUses ¶ added in v0.3.0
type MasterKeyUses struct {
TenantKeys, Secrets, RemovedMailboxes int
}
MasterKeyUses counts what only the master key opens: tenant keys wrapped under it (kek_id "master"), secrets sealed under it before tenant keys (envelope 1), and removed mailboxes' copies sealed under it (envelope 1, or envelope 3 under "master"). In a build whose module holds the keys, the master key can be retired once all are 0.
func (MasterKeyUses) Total ¶ added in v0.3.0
func (u MasterKeyUses) Total() int
Total is everything that still needs the master key.
type Member ¶ added in v0.3.0
Member is a person of a tenant, as the Members screen lists them. Those forgotten (ForgetIdentity), whose removal waits, are not members.
type Message ¶
type Message struct {
ID int64
AccountID int64
Folder string // where it arrived; with UIDValidity and UID, the dedupe key
UIDValidity uint32
UID uint32
MessageID string // RFC 5322 Message-ID, without angle brackets
FromAddr string
FromName string // the From display name; may be empty
FromDomain string
ToAddrs []string
Subject string
Snippet string
ReceivedAt int64
ListID string
HasAttachment bool
Size int64
Signals Signals
// UnsubscribeURL is the RFC 8058 one-click link the email offers (unsubscribe.OneClick);
// empty when it offers none.
UnsubscribeURL string
State string
Attempts int // retries made after a failure
NextAttemptAt int64 // 0 = not waiting for the retry job
CreatedAt int64
// ActedAt is when MailRules last decided the message, or CreatedAt until a decision is
// made. The feed is ordered by it.
ActedAt int64
// Metered: a model on keys the operator holds decided the email, and it was counted
// against its tenant's monthly allowance (AIEmails). It is counted once, however often
// it is decided again.
Metered bool
// Where the executor last left the message; zero while it is still where it arrived.
CurFolder string
CurUIDValidity uint32
CurUID uint32
}
Message is one row of messages: what is kept of an email. The body never is.
type Move ¶ added in v0.3.0
type Move struct {
ID int64
TenantID int64
AccountID int64
MessageID int64
ActionID int64 // the filing action
From string
RuleID int64
RuleName string
Filed string // where MailRules filed it
Chosen string // where it was found; "" = in no folder
Inbox bool // Chosen is the mailbox's watched folder
// Person: Chosen is the Inbox or an ordinary folder, so the person filed it there; not
// deleted, archived or put there by MailRules itself. Only such moves reach the module.
Person bool
FiledAt int64
CreatedAt int64 // when the watcher found it moved
Attempts int
// Read back only.
Mailbox string // the mailbox's address, as notices name it
Count int // the person's moves of this sender to Chosen kept so far, this one included
}
Move is an email the person moved out of the folder a MailRules action filed it in.
type Notice ¶ added in v0.3.0
type Notice struct {
ID int64
TenantID int64
DestinationID int64
AccountID int64
MessageID int64 // the Activity id
RuleID int64 // 0 once the rule was deleted
RuleName string
CreatedAt int64 // when the rule acted
Attempts int // hand-overs the module refused so far
NoticePayload
}
Notice is one waiting notice: what a rule did to one email, for one destination.
type NoticePayload ¶ added in v0.3.0
type NoticePayload struct {
Mailbox string `json:"mailbox"`
Actions []string `json:"actions"`
Folder string `json:"folder"`
From string `json:"from"`
FromName string `json:"from_name"`
Subject string `json:"subject"`
}
NoticePayload is the part of a notice that holds the email's own details, kept only until the module takes the notice.
type Plan ¶ added in v0.3.0
type Plan struct {
Plan string // PlanPersonal, PlanPro, PlanTeam or PlanEnded
Interval string // IntervalMonth, IntervalYear or empty
Status string // StatusActive, StatusPastDue, StatusCancelsAtPeriodEnd or empty
PeriodEnd int64 // the end of the paid period, unix seconds; 0 = not known
Record string // the module's own record of the tenant (its billing ids); never shown
// Seats is how many seats the tenant bought of a plan sold by the seat (PlanTeam), at
// least 1; 0 for any other plan.
Seats int
// CompanySignInAddOn is whether the company sign-in add-on is on the tenant's Team
// subscription (MAI-246); false for any other plan.
CompanySignInAddOn bool
}
Plan is a tenant's plan as a billing module reports it.
type PlanState ¶ added in v0.3.0
type PlanState struct {
Plan
// TrialEnd is when the tenant's trial ends (or ended): its creation plus TrialDays.
TrialEnd int64
// EndedAt is when the plan ended; 0 while one runs. A trial ends at TrialEnd, a plan
// cancelled at its period's end at PeriodEnd.
EndedAt int64
// Warned is how many of the end-of-plan warning emails were sent; SecretsDeleted whether
// the end-of-plan job deleted the tenant's passwords, tokens and model keys.
Warned int
SecretsDeleted bool
}
PlanState is a tenant's plan as it stands at a moment (TenantPlan).
type Question ¶ added in v0.3.0
type Question struct {
ID int64
TenantID int64
AccountID int64 // the mailbox of the latest move asked about
Mailbox string // its address
From string
Inbox bool // the destination is the Inbox (the mailbox's watched folder)
Folder string // the destination's folder; the watched folder's name for the Inbox
Emails int // how many of the sender's emails the person moved there
Status string // QuestionOpen | QuestionYes | QuestionNo
AskedAt int64
}
Question is one question Activity asks about the person's moves of one sender to one destination.
type Removal ¶ added in v0.3.0
type Removal struct {
TenantID int64
// Tenant is whether the whole tenant went: the user was its only member.
Tenant bool
// Accounts are the mailboxes deleted.
Accounts []int64
// Rules are the team's rules rewritten because a mailbox they named was deleted (as
// DeleteAccount rewrites them), when the tenant stays.
Rules []rules.Rule
}
Removal is what RemoveForgotten removed.
type RemovedMailbox ¶ added in v0.3.0
type RemovedMailbox struct {
ID int64 // the row's own: the same on every hand-over
TenantID int64 // the tenant the row was read in; 0 on SQLite
AccountID int64
Preset string
OAuth bool // connected with one-click sign-in; else through the module's sign-in form
Username string
CreatedAt int64
Attempts int
}
RemovedMailbox is a mailbox a module connected whose secret the daemon let go of, waiting to be handed to that module. Its secret is read with RemovedMailboxSecret.
type RuleStat ¶
type RuleStat struct {
Hits int // messages it was applied to since the time asked for
LastMatchAt int64 // 0 = never
}
RuleStat is how often a rule has been applied.
type RuleUse ¶
type RuleUse struct {
RuleID int64
RuleName string
Emails int
Calls int // decisions a model was asked for
CostUSD float64
}
RuleUse is what one rule did, or cost. RuleID is 0 with a name for a rule that has been deleted since, and 0 without one for "no rule".
type SeatCheck ¶ added in v0.3.0
type SeatCheck struct {
TenantID int64
Version int64 // goes up each time it is queued again
CreatedAt int64 // when it was first queued
Attempts int // the billing module's refusals so far
}
SeatCheck is a tenant whose paid seats may be more than it uses (WaitingSeatChecks).
type SeatLimit ¶ added in v0.3.0
SeatLimit is how many people a tenant on plan p may have: members, and invitations waiting, together. NoLimit is any number. A nil SeatLimit limits nothing.
type SeatLimitError ¶ added in v0.3.0
type SeatLimitError struct {
Limit int // the seats the plan has
Used int // members and invitations waiting
}
SeatLimitError is a member or an invitation refused because every seat of the tenant's plan is taken.
func (*SeatLimitError) Error ¶ added in v0.3.0
func (e *SeatLimitError) Error() string
func (*SeatLimitError) Is ¶ added in v0.3.0
func (e *SeatLimitError) Is(target error) bool
Is makes errors.Is(err, ErrSeatLimit) hold.
type SecretsCheck ¶ added in v0.3.0
type SecretsCheck struct {
Total int // every stored secret
Unreadable int // the ones the store's key provider cannot open
}
SecretsCheck counts the secrets the database holds sealed: mailbox passwords and tokens, provider keys and the addresses of notification destinations.
func (SecretsCheck) Readable ¶ added in v0.3.0
func (c SecretsCheck) Readable() int
Readable is how many secrets the key opens.
type SenderDecision ¶
type SenderDecision struct {
Stage string
RuleID int64
Confidence float64
Corrected bool // the user corrected that message afterwards
}
SenderDecision is one past decision for a sender, as the learner reads it.
type SenderSeen ¶
type SenderSeen struct {
Address string
Name string // the From display name of the newest email; may be empty
Messages int // emails seen since the time asked for
LastSeenAt int64
ListUnsubscribe bool // at least one of them carried a List-Unsubscribe header
// OneClick is set when, on at least one mailbox, one of them offers an RFC 8058
// one-click unsubscribe link.
OneClick bool
// UnsubscribedAt is when MailRules last unsubscribed the address, once every such mailbox
// is unsubscribed (unsubscribes); 0 while one is not.
UnsubscribedAt int64
}
SenderSeen is what the messages table knows about one sender address.
type Signals ¶
type Signals struct {
Bulk bool `json:"bulk"`
Noreply bool `json:"noreply"`
Contact bool `json:"is_contact"`
RepliedBefore bool `json:"replied_before"`
DMARC string `json:"dmarc"`
// ListUnsubscribe is set when the email carries a List-Unsubscribe header.
ListUnsubscribe bool `json:"list_unsubscribe"`
}
Signals is the JSON in messages.signals.
type Snapshot ¶
type Snapshot struct {
Folder string `json:"folder"`
UIDValidity uint32 `json:"uidvalidity"`
UID uint32 `json:"uid"`
Flags []string `json:"flags"`
}
Snapshot is the JSON in actions.before and actions.after: where a message was and which flags it had.
type Store ¶
type Store struct {
// contains filtered or unexported fields
}
Store is the repository over the database. All times are unix seconds. keys seals and opens the secrets it keeps (WithKeys); a store without one keeps none.
func (*Store) AIEmails ¶ added in v0.3.0
AIEmails returns how many emails a model decided for the tenant on keys the operator holds in month (see Month).
func (*Store) AcceptInvitation ¶ added in v0.3.0
func (s *Store) AcceptInvitation(ctx context.Context, tenantID int64, email string, now int64) error
AcceptInvitation records that the person invited to the tenant at email accepted, as the sign-in service reports it. When they already joined (they signed in under the team's organisation before the report came), they get the invitation's role now and it is used up; otherwise it waits InvitationDays more for their first sign-in, which joins them with its role. ErrNotFound when the tenant has no invitation for the address that has not expired.
func (*Store) Account ¶
Account returns one account, or ErrNotFound. It does not look at who asks: it is for internal work on a known account (the worker, the executor). A request reads VisibleAccount.
func (*Store) AccountSecret ¶
AccountSecret decrypts an account's app password or token. It returns crypto.ErrDecrypt when the key it was sealed under does not open, and ErrNoSecret when the secret was deleted.
func (*Store) AccountTenant ¶ added in v0.2.0
AccountTenant returns the tenant an account belongs to, or ErrNotFound.
func (*Store) Accounts ¶
Accounts lists every account of every tenant, oldest first: for the daemon's own work (starting the watchers, the master key check), never for a request.
func (*Store) Action ¶
Action returns one action, or ErrNotFound. It does not look at who asks: a request reads VisibleAction.
func (*Store) Activity ¶
func (s *Store) Activity(ctx context.Context, v Viewer, f ActivityFilter) ([]ActivityRow, error)
Activity lists the messages of the mailboxes the viewer sees, each with its latest decision, by when MailRules acted on them (ActedAt), newest first; messages acted on in the same second come newest row first.
func (*Store) ActivityFor ¶
ActivityFor returns the activity row of one message the viewer sees, or ErrNotFound.
func (*Store) AddBatchProgress ¶
func (s *Store) AddBatchProgress(ctx context.Context, id int64, done, skipped, tokens int, costUSD float64) error
AddBatchProgress records that a cleanup batch handled more emails, passed over some that had moved, and what their model calls cost.
func (*Store) AddCorrection ¶
func (s *Store) AddCorrection(ctx context.Context, tenantID, userID int64, c Correction, always string) (int64, error)
AddCorrection records a correction in one transaction: it inserts the row, forgets the tenant's learned sender rule for that message's sender and marks the message acted. With always (rules.MatchAddress or rules.MatchDomain; "" = neither) it also stores a user sender rule of the tenant, made by userID, that sends the address, or its whole domain, to the right rule (or keeps it in the inbox), replacing whatever that address or domain had. The caller checks that the message and the right rule are the tenant's.
func (*Store) AddDecision ¶
AddDecision records a decision and moves its message to state in one transaction, and returns the decision's id. The message's ActedAt becomes the decision's time. A Metered decision counts the email against its tenant's allowance for the month of CreatedAt in the same transaction, unless the message was counted before: a decision that is not recorded is not counted, and one made again after a failure is not counted twice.
func (*Store) AddFolder ¶
AddFolder records a folder MailRules itself just created on the server, so it shows up before the next folder discovery. A folder already on record is left as it is.
func (*Store) AddLearnedSenderRule ¶
func (s *Store) AddLearnedSenderRule(ctx context.Context, tenantID, userID int64, address string, ruleID, now int64) (bool, error)
AddLearnedSenderRule routes an address to one of the tenant's rules unless the address already has a sender rule there, which is never overwritten. userID is who it is learnt for. It reports whether a rule was created.
func (*Store) AddUnsubscribe ¶ added in v0.3.0
func (s *Store) AddUnsubscribe(ctx context.Context, accountID int64, address, host string, now int64) error
AddUnsubscribe records that MailRules unsubscribed a mailbox from address at host (the site that took it; the link is not kept).
func (*Store) AddUsage ¶
func (s *Store) AddUsage(ctx context.Context, tenantID int64, operator bool, day, provider, model, purpose string, calls, tokensIn, tokensOut int, costUSD float64) error
AddUsage adds model calls to the tenant's cost-ledger row for that day, provider, model and purpose (decide | escalate | compose | test | cleanup), creating it if needed. operator marks calls made with a key the operator holds (MAILRULES_MODE=cloud): they are booked on rows of their own, so billing can charge for them.
func (*Store) AdvanceFolder ¶
AdvanceFolder raises a watched folder's last processed UID to ref's. It never lowers it, except when the folder's UIDVALIDITY changed, where the old position means nothing.
func (*Store) AnswerQuestion ¶ added in v0.3.0
func (s *Store) AnswerQuestion(ctx context.Context, v Viewer, id int64, yes bool, now int64) (Question, error)
AnswerQuestion records the viewer's answer to an open question about a mailbox they see, in one transaction. Yes stores the sender rule a correction's "Always do this for <sender>" stores (putUserSenderRule), made by the viewer: keep the sender's mail in the Inbox, or move it to the folder; it replaces whatever the tenant had for that address. No stores nothing more. Either way the question is not asked again. A question that is not open, or not one the viewer sees, is ErrNotFound.
func (*Store) AskMove ¶ added in v0.3.0
AskMove puts, or keeps, the question about the move's sender and destination open, counting the person's moves kept for them: one question per sender and destination, whichever mailboxes the moves were in. It returns the question and whether it is new or changed. A question already answered is ErrAnswered; a move that is not kept, or not the person's, is ErrNotFound.
func (*Store) Audit ¶ added in v0.3.0
Audit records one row of the tenant's audit log under ctx's actor, for something done outside the store (a request to a module's service); nothing when ctx has none.
func (*Store) AuditLog ¶ added in v0.3.0
AuditLog lists the tenant's audit log from since to until (unix seconds, both included; until 0 = now), oldest first.
func (*Store) Batch ¶
Batch returns one batch, or ErrNotFound. It does not look at who asks: a request reads VisibleBatch.
func (*Store) BatchActionCounts ¶
func (s *Store) BatchActionCounts(ctx context.Context, v Viewer, batchID int64) (map[string]int, error)
BatchActionCounts counts a batch's own actions on the mailboxes the viewer sees, by status.
func (*Store) BatchActions ¶
BatchActions lists a batch's actions, oldest first, whoever's mailbox they are on: for internal work. A request reads VisibleBatchActions.
func (*Store) Batches ¶
func (s *Store) Batches(ctx context.Context, v Viewer, kind string, before int64, limit int) ([]Batch, error)
Batches lists the batches the viewer sees, newest first: of one kind, or of every kind when kind is empty. before is the cursor (only batches with a smaller id; 0 = from the newest).
func (*Store) CanSee ¶ added in v0.2.0
CanSee reports whether the viewer sees the account: the visibility rule for one id.
func (*Store) CheckSecrets ¶ added in v0.3.0
func (s *Store) CheckSecrets(ctx context.Context) (SecretsCheck, error)
CheckSecrets counts every tenant's stored secrets, and those the store's key provider cannot open: whether the key-encryption key is the one they are under, checked by unwrapping each tenant's key, not by opening each secret. A secret sealed before tenant keys (envelope 1) is opened, as it is the master key's own. A store without keys opens none, which is how the caller counts what a key would have to protect before it has one. A secret that fails is counted, not an error; only a database failure is.
func (*Store) ClaimSummary ¶
func (s *Store) ClaimSummary(ctx context.Context, userID, dueAt, now int64, maxAttempts int) (id int64, attempt int, ok bool, err error)
ClaimSummary records an attempt at the summary due at dueAt and reports whether this caller is to make it, and which attempt it is. It is one statement, so of two callers at once only one gets it. It is not to be made when it was sent, when an attempt is running or was cut off (status sending), after maxAttempts, or while the last failed attempt is younger than its back-off: a minute after the first, doubling each time.
func (*Store) Corrections ¶
Corrections lists the newest corrections made to mail in the mailboxes the viewer sees, newest first, with the example each stored: the pool few-shot retrieval ranks.
func (*Store) CountMessages ¶
CountMessages counts the messages in a state in the mailboxes the viewer sees, e.g. StateReview for the Needs review badge.
func (*Store) CreateAccount ¶
CreateAccount stores an account with its secret sealed under its tenant's data key. The account goes into its owner's (a.UserID's) tenant and starts shared or not as NewAccountShared says; a.TenantID and a.Shared are ignored. The ciphertext is bound to the row id, which only exists after the insert, so the row is inserted, sealed and updated in one transaction: no reader ever sees it without a secret. Its tenant may have any number of mailboxes; CreateAccountWithin caps them.
func (*Store) CreateAccountWithin ¶ added in v0.3.0
func (s *Store) CreateAccountWithin(ctx context.Context, a Account, secret string, max int) (Account, error)
CreateAccountWithin is CreateAccount for a tenant that may have at most max mailboxes (NoLimit: any number). The count and the insert are one write transaction, which holds the database's write lock (on Postgres, the tenant's) from its start, so two mailboxes added at once cannot both take the last place. A tenant at or over max gets a *MailboxLimitError and nothing is stored.
func (*Store) CreateBatch ¶
func (s *Store) CreateBatch(ctx context.Context, tenantID int64, kind, status string, now int64) (int64, error)
CreateBatch opens a batch of the tenant, with no mailbox, and returns its id.
func (*Store) CreateCleanupBatch ¶
func (s *Store) CreateCleanupBatch(ctx context.Context, accountID int64, folder string, since int64, scanLimit, scanMatched, total int, now int64) (Batch, error)
CreateCleanupBatch opens the batch of one cleanup run over total emails, running.
scanLimit and scanMatched say how much mail the check behind it covered: the most emails it was allowed and how many the range held before that cut. scanLimit 0 records nothing.
func (*Store) CreateCleanupRun ¶ added in v0.1.2
func (s *Store) CreateCleanupRun(ctx context.Context, cs []CleanupBatch, now int64) ([]Batch, error)
CreateCleanupRun opens one running cleanup batch per mailbox for a manual run over several mailboxes, all or none: they share a RunID, the id of the first, so they read back as one run. A run of one mailbox is a plain cleanup batch with no RunID.
func (*Store) CreateDestination ¶ added in v0.3.0
func (s *Store) CreateDestination(ctx context.Context, d Destination, sec DestinationSecret, now int64) (Destination, error)
CreateDestination stores a destination of the tenant with its address and secret sealed under the tenant's key, and returns it with its id.
func (*Store) CreateFirstUser ¶
func (s *Store) CreateFirstUser(ctx context.Context, email, passwordHash string, now int64) (User, error)
CreateFirstUser inserts the admin account, in the self-host tenant, only if no user exists yet. The admin is the tenant's owner.
func (*Store) CreateInvitation ¶ added in v0.3.0
func (s *Store) CreateInvitation(ctx context.Context, tenantID int64, inv Invitation, seats SeatLimit, now int64) (Invitation, error)
CreateInvitation stores an invitation of the tenant for inv.Email with inv.Role, sent by inv.InvitedBy, expiring InvitationDays from now, and returns it. One that expired for the same address is replaced. It fails, storing nothing, with ErrBadRole, ErrAlreadyMember when a member has the address, ErrHasAccount when a user of any other tenant has it (the person must delete that account first), ErrAlreadyInvited when an invitation for it waits, and a *SeatLimitError when the tenant's plan has no seat left (the count and the insert are one write transaction, so two invitations sent at once cannot both take the last seat).
func (*Store) CreateRule ¶
func (s *Store) CreateRule(ctx context.Context, tenantID int64, r rules.Rule, now int64) (rules.Rule, error)
CreateRule inserts a rule of the tenant at version 1 and returns it with its id. r.UserID is its author. The caller validates the rule first.
func (*Store) CreateRules ¶
func (s *Store) CreateRules(ctx context.Context, tenantID, userID int64, added []NewRule, now int64) ([]rules.Rule, error)
CreateRules inserts rules of the tenant, written by userID, in one transaction and returns them as saved, in the order given. Each lands at its position in the priority order, or at the end; the priorities of all the tenant's rules are then renumbered from 1, which is not an edit, so versions stay. The caller validates the rules first.
func (*Store) CreateSession ¶
func (s *Store) CreateSession(ctx context.Context, tokenHash string, userID, now, expiresAt int64) error
CreateSession stores a login session by the hash of its token, and sweeps expired ones (on Postgres, those of the user's tenant).
func (*Store) CreateTenant ¶ added in v0.2.0
func (s *Store) CreateTenant(ctx context.Context, provider, externalID string, now int64) (int64, error)
CreateTenant adds a tenant for a sign-in service's organisation and returns its id.
func (*Store) CreateUser ¶ added in v0.2.0
func (s *Store) CreateUser(ctx context.Context, tenantID int64, email, passwordHash string, now int64) (User, error)
CreateUser adds a user to a tenant: its owner when it has nobody yet, else a member. An empty passwordHash makes a user who cannot sign in with a password (one made from a sign-in service's identity).
func (*Store) DecisionDraft ¶ added in v0.3.0
func (s *Store) DecisionDraft(ctx context.Context, tenantID, decisionID int64) (a Action, ok bool, err error)
DecisionDraft returns the latest draft action recorded for a decision; ok is false when there is none.
func (*Store) DeleteAccount ¶
DeleteAccount wipes an account with its secret, folders, contacts, messages, decisions, actions and corrections: each references the account with ON DELETE CASCADE. The rules are kept: first, in the same transaction, every user's rules that name the mailbox are rewritten as rules.Rule.DropAccount has it, so a rule limited to it is switched off and marked, with no mailbox, before the cascade could reach it. It returns those rules. A mailbox a module connected is queued for that module (queueRemovedMailboxes).
func (*Store) DeleteDestination ¶ added in v0.3.0
func (s *Store) DeleteDestination(ctx context.Context, tenantID, id, now int64) ([]rules.Rule, error)
DeleteDestination removes one of the tenant's destinations with its delivery log and the notices still waiting for it, and takes it off every rule of the tenant that named it, in one transaction. It returns the rules it changed, as saved (an edit: their versions go up). A destination of another tenant is ErrNotFound.
func (*Store) DeleteOwnAccount ¶ added in v0.3.0
func (s *Store) DeleteOwnAccount(ctx context.Context, provider, subject string, now int64) (Forget, error)
DeleteOwnAccount is a person who deleted their own account: ForgetIdentity, and in the same transaction their user lets go of the identity, so that it never gets their data back: the same identity signing in again, before the removal or after, gets a new, empty user. When they are their tenant's only member, the tenant lets go of the sign-in service's organisation too, so that user gets a new tenant instead of joining the old data's. The old data is removed after ForgetDays all the same, and the service's own deletion notice for the identity afterwards reaches nobody.
func (*Store) DeleteRule ¶
DeleteRule removes one of the tenant's rules. The schema takes the sender rules that route to it along (ON DELETE CASCADE) and keeps its decisions and corrections, with their rule set to NULL.
func (*Store) DeleteSenderRule ¶
func (s *Store) DeleteSenderRule(ctx context.Context, tenantID int64, matchType, value string) error
DeleteSenderRule removes one of the tenant's sender verdicts; deleting a missing one is not an error.
func (*Store) DeleteSession ¶
DeleteSession ends a session; deleting a missing one is not an error.
func (*Store) DeleteTenantSecrets ¶ added in v0.3.0
func (s *Store) DeleteTenantSecrets(ctx context.Context, tenantID, endedAt, now int64) ([]int64, error)
DeleteTenantSecrets deletes, in one transaction, the secrets of a tenant whose plan ended at endedAt, once EndedSecretsDays have passed since by now: every mailbox's password or token (as ForgetIdentity deletes an only member's: each one a module connected is queued for it first, and they show auth_failed, or reconnect_needed, saying the plan ended), the tenant's stored model API keys, and its notification destinations' addresses and signing secrets; the plan records it (PlanState.SecretsDeleted). It returns the tenant's mailboxes, whose supervisors the caller stops before and after. Everything else stays, readable. ErrPlanNotEnded, changing nothing, when the plan no longer ended at endedAt or not long enough ago. Never the self-host tenant.
func (*Store) Destination ¶ added in v0.3.0
Destination returns one destination, or ErrNotFound. It does not look at who asks: it is for the delivery worker.
func (*Store) DestinationSecret ¶ added in v0.3.0
DestinationSecret opens a destination's address and secret. ErrNoSecret when they were deleted (Destination.AddressDeleted), ErrNotFound when there is no such destination.
func (*Store) Destinations ¶ added in v0.3.0
Destinations lists the tenant's destinations, oldest first.
func (*Store) DoneActionsSince ¶
func (s *Store) DoneActionsSince(ctx context.Context, v Viewer, ruleID, since int64) ([]Action, error)
DoneActionsSince lists the actions on the mailboxes the viewer sees made at or after since that are still in effect, newest first: the ones "undo everything since" reverses. With ruleID, only those a decision for that rule led to.
func (*Store) DraftDone ¶ added in v0.3.0
DraftDone deletes a draft job that is settled: its draft action records how.
func (*Store) DraftRetry ¶ added in v0.3.0
DraftRetry records that a draft job could not be done now; it is tried again at next.
func (*Store) DryRun ¶
DryRun reports whether the tenant's dry-run switch is on. def is used until the switch has been set (MAILRULES_DRY_RUN).
func (*Store) DueForRemoval ¶ added in v0.3.0
DueForRemoval lists the forgotten users whose removal time has come by now, the earliest first.
func (*Store) DueMessages ¶
DueMessages lists an account's failed messages whose retry time has come, oldest first.
func (*Store) EndIdentitySessions ¶ added in v0.2.0
EndIdentitySessions deletes every session of the identity's user. An identity nobody has is not an error.
func (*Store) EndTrial ¶ added in v0.3.0
EndTrial records, at now, the end of a trial over with no plan bought: a plans row with plan ended at the trial's end and no warning sent yet, so the end-of-plan job has where to keep its steps. It reports whether it wrote one; a tenant with a row already, whose trial runs, or the self-host tenant (which has no plan) is left as it is.
func (*Store) EndedPlan ¶ added in v0.3.0
EndedPlan returns the tenant's plan at now (TenantPlan) with when its latest warning was sent. ErrNotFound for a tenant that does not exist.
func (*Store) ExpireRemovedMailboxes ¶ added in v0.3.0
ExpireRemovedMailboxes deletes, with their secrets, the removed mailboxes that waited RemovedMailboxDays by now without being taken, and returns them.
func (*Store) ExtendSession ¶
ExtendSession slides a session's expiry forward.
func (*Store) FailRunningBatches ¶
FailRunningBatches marks every batch still running as failed. The daemon calls it at startup: a batch that was running when the daemon stopped will never finish.
func (*Store) FiledSince ¶ added in v0.3.0
func (s *Store) FiledSince(ctx context.Context, accountID, since, afterID int64, limit int) ([]Filed, error)
FiledSince lists, oldest first, the account's emails a MailRules action filed at or after since, with an action id above afterID, that no later action moved on and that have no move recorded yet: at most limit. Dry-run, failed and undone actions file nothing. An email without a Message-ID or a sender cannot be followed and is left out. The rule is the decision's, or, for a fix made in MailRules, the rule it was fixed to.
func (*Store) FinishAction ¶
FinishAction stores how an action ended. For a done action, after is the message's state afterwards, and the message's location is updated with it in the same transaction. then says what a, the last action of its rule's run on the message (done, or the failure that stopped the run), starts: notices (queueNotices) and a draft reply (queueDraft).
func (*Store) FinishSummary ¶
func (s *Store) FinishSummary(ctx context.Context, id int64, sent bool, periodStart, periodEnd, now int64) error
FinishSummary records how a claimed attempt ended: sent, with the time it covered, or failed.
func (*Store) FirstCleanupUsed ¶ added in v0.3.0
FirstCleanupUsed returns how much of its one-time first-cleanup grant the tenant's cleanup checks have used: emails a model decided on keys the operator holds. It never resets.
func (*Store) FirstUser ¶
FirstUser returns the admin account, or ErrNotFound before first-run setup. The command line acts as this user, in its tenant.
func (*Store) ForgetIdentity ¶ added in v0.3.0
func (s *Store) ForgetIdentity(ctx context.Context, provider, subject string, now int64) (Forget, error)
ForgetIdentity is a person the sign-in service deleted. In one transaction it ends every session of the identity's user, frees their email (a new identity may sign up with it at once), deletes their secrets and schedules the removal of the rest of their data for ForgetDays from now. The secrets are the passwords and tokens of their mailboxes (every mailbox of the tenant when they are its only member, else the ones they own, shared or not), which then show auth_failed asking for a new password, and, when they are the tenant's only member, the tenant's stored model API keys. A mailbox a module connected is first queued for that module with its secret (queueRemovedMailboxes). The caller stops those mailboxes' supervisors before (IdentityMailboxes) and after (Forget.Accounts) it. Everything else is left as it is until the removal. An identity nobody has is not an error, and forgetting one again changes nothing, the removal time included. Only users made from an identity are reached, so the self-host admin never is.
func (*Store) HasUsers ¶
HasUsers reports whether first-run setup has been done: whether any tenant has a user.
func (*Store) HitSenderRule ¶
HitSenderRule counts one more email settled by a sender rule.
func (*Store) IdentityMailboxes ¶ added in v0.3.0
IdentityMailboxes lists the mailboxes ForgetIdentity would take the secrets of, as things stand. Their supervisors are stopped before ForgetIdentity runs. An identity nobody has has none.
func (*Store) ImportRules ¶
func (s *Store) ImportRules(ctx context.Context, tenantID, userID int64, imported []rules.Rule, now int64) (created, updated int, err error)
ImportRules stores the rules of a YAML file in the tenant in one transaction; userID is the author of the rules it adds. A rule whose name is already in use replaces that rule, including its mailbox (AccountID, which the caller has set to the one to keep when the file says nothing), and keeps its place, id and author; the others are added after the existing rules, in file order. Rules the file does not name are left alone. The caller validates the rules first.
func (*Store) IngestMessage ¶
func (s *Store) IngestMessage(ctx context.Context, ref mail.MsgRef, now int64) (m Message, fresh bool, err error)
IngestMessage records that a message arrived, once. fresh is false when the row was already there (the watcher repeats a message after a crash); the stored row is returned either way. A known message that the executor itself put at ref (an undo back into the watched folder gets a new UID) is not new mail either: its existing row is returned.
func (*Store) InsertAction ¶
InsertAction writes an action row and returns its id.
func (*Store) Invitations ¶ added in v0.3.0
Invitations lists the tenant's invitations that have not expired at now, oldest first.
func (*Store) LastMailAt ¶
LastMailAt is when the newest email MailRules has seen in an account arrived (its received date, or when it was first seen if it carried none); 0 when it has seen none.
func (*Store) LastOwner ¶ added in v0.3.0
LastOwner reports whether the user is the only owner of a tenant that has other members: a team that would be left with nobody to manage its plan and members.
func (*Store) LastSentSummary ¶
LastSentSummary returns the user's latest summary that went out, or ErrNotFound.
func (*Store) LeaveOwnMail ¶
LeaveOwnMail reports whether, in the tenant, mail from the mailbox's own address is left alone. The pipeline reads it for every email.
func (*Store) LeftByMailRules ¶ added in v0.3.0
func (s *Store) LeftByMailRules(ctx context.Context, accountID int64, folder string, uidValidity, uid uint32, exceptMessage int64) (bool, error)
LeftByMailRules reports whether MailRules itself left an email at (folder, uidValidity, uid) of the account: it is where the executor last put a row other than exceptMessage (a cleanup that sorted the same email under a row of its own).
func (*Store) LiveBatch ¶
LiveBatch returns the batch that collects the tenant's actions of live processing for now's day (UTC), creating it on the day's first action, so "undo today" is one batch undo. Once a day's batch has been undone, later mail that day starts a new one.
func (*Store) MarkActionUndone ¶
func (s *Store) MarkActionUndone(ctx context.Context, a Action, restored mail.MsgRef, now int64) error
MarkActionUndone marks a done action undone and records where its message is now.
func (*Store) MasterKeyUses ¶ added in v0.3.0
func (s *Store) MasterKeyUses(ctx context.Context) (MasterKeyUses, error)
MasterKeyUses counts, over every tenant, what still needs the master key. It needs no key itself.
func (*Store) Members ¶ added in v0.3.0
Members lists the tenant's members, the longest-standing first.
func (*Store) MessageActions ¶
MessageActions lists every action taken on a message, oldest first.
func (*Store) MessageActivity ¶ added in v0.2.0
MessageActivity returns one message's activity row, whoever's it is, or ErrNotFound: for internal work on a known message (the executor, the event publishers).
func (*Store) MessageByMessageID ¶
func (s *Store) MessageByMessageID(ctx context.Context, accountID int64, messageID string, except int64) (Message, error)
MessageByMessageID returns the account's newest row, other than except, for the email with this Message-ID header, or ErrNotFound.
func (*Store) MessageCorrections ¶
MessageCorrections lists the corrections the user made to a message, oldest first.
func (*Store) MessageDecisions ¶
MessageDecisions lists every decision made for a message, oldest first. A message has more than one when the retry job ran it again.
func (*Store) MoveHanded ¶ added in v0.3.0
MoveHanded records that the module took a move.
func (*Store) MoveRetry ¶ added in v0.3.0
MoveRetry records that the module refused a move, to be handed over again at next.
func (*Store) NoticeHanded ¶ added in v0.3.0
NoticeHanded records that the module took a notice: it is not handed over again, and the email's details it held are blanked.
func (*Store) NoticeRetry ¶ added in v0.3.0
NoticeRetry records that the module refused a notice; it is handed over again at next.
func (*Store) OpenQuestions ¶ added in v0.3.0
OpenQuestions lists the open questions about mailboxes the viewer sees, newest first.
func (*Store) PlanEndTenants ¶ added in v0.3.0
PlanEndTenants lists, by id, the tenants other than SelfHostTenant whose plan may have ended by now: those that never bought one and whose trial is over, those the billing module or the job recorded as ended, and those cancelled at a period's end that has passed. It is where the end-of-plan job looks; whether each one ended is TenantPlan's to say (EndedPlan).
func (*Store) PlanWarned ¶ added in v0.3.0
PlanWarned records that warning n (1 to 3) about the plan that ended at endedAt was sent at now. A lower or equal number than the one recorded changes nothing. ErrPlanNotEnded, changing nothing, when the plan no longer ended at endedAt. Never the self-host tenant.
func (*Store) PutSenderRule ¶
func (s *Store) PutSenderRule(ctx context.Context, tenantID int64, sr rules.SenderRule, now int64) (rules.SenderRule, error)
PutSenderRule stores the tenant's verdict for a sender address or domain, replacing any earlier one for the same sender, and returns it with its id. sr.UserID is who made it. A rule_id that is not one of the tenant's rules is refused as ErrNotFound.
func (*Store) QueueSeatCheck ¶ added in v0.3.0
QueueSeatCheck queues a check of the tenant's seats, due at now: for a seat bought for an invitation that was then not kept.
func (*Store) QuietRules ¶
QuietRules counts the enabled rules of the viewer's tenant that were applied to no email of the mailboxes the viewer sees since `since`.
func (*Store) Rebind ¶
Rebind records that the email of row known is now at ref, where it was just ingested as row fresh, and removes fresh, so the email keeps one row. fresh must be a row MailRules has done nothing with yet: when it has a decision, an action or a correction, Rebind changes nothing and reports false.
func (*Store) RecentDeliveries ¶ added in v0.3.0
func (s *Store) RecentDeliveries(ctx context.Context, tenantID int64, perDestination int) (map[int64][]Delivery, error)
RecentDeliveries lists, for each of the tenant's destinations, the last perDestination deliveries reported, newest first.
func (*Store) RecentSenderDecisions ¶
func (s *Store) RecentSenderDecisions(ctx context.Context, v Viewer, address string, n int) ([]SenderDecision, error)
RecentSenderDecisions returns the decisions of the newest n decided emails from one address across the mailboxes the viewer sees, newest first. An email decided more than once (a retry, a cleanup run) counts once, by its latest decision. A decision whose actions were recorded in dry-run is left out, so a dry-run period teaches the learner nothing, then or once MailRules is live.
func (*Store) ReconcileRemovedMailboxes ¶ added in v0.1.3
ReconcileRemovedMailboxes fixes the rules that still name a mailbox removed before DeleteAccount kept them (MAI-132): every mailbox a rule names that has no account any more is dropped from it as DeleteAccount would have, for every tenant, each in one transaction of its own. It returns the rules it changed, by id; a second run changes nothing.
func (*Store) RecordDelivery ¶ added in v0.3.0
func (s *Store) RecordDelivery(ctx context.Context, noticeID int64, sent bool, reason string, at int64) (tenantID int64, err error)
RecordDelivery stores what a module reported of delivering a notice: sent, or failed and why. It returns the notice's tenant. A notice that is no longer kept (its destination or mailbox was removed, or it is older than NoticeDays) is ErrNotFound.
func (*Store) RecordMove ¶ added in v0.3.0
RecordMove writes a move the watcher found, once per filing action, provided the action is still in effect (nothing undid it meanwhile). A move that is not the person's is written as already handed over: the module never gets it. It returns the move's id, or 0 when nothing was written.
func (*Store) RemovalAccounts ¶ added in v0.3.0
RemovalAccounts lists the mailboxes removing the user would delete as things stand: every mailbox of their tenant when nobody else is left in it, else the ones they own, shared or not. Their supervisors are stopped before RemoveForgotten runs.
func (*Store) RemoveEndedTenant ¶ added in v0.3.0
func (s *Store) RemoveEndedTenant(ctx context.Context, tenantID, endedAt, now int64) (Removal, error)
RemoveEndedTenant removes, in one transaction, a tenant whose plan ended at endedAt, once EndedRemovalDays have passed since by now: everything RemoveForgotten removes with a tenant's only member, for every member, the plan too. A mailbox a module connected that still has its secret is queued for that module first. It returns what went; the caller stops the mailboxes before. ErrPlanNotEnded, changing nothing, when the plan no longer ended at endedAt or not long enough ago. Never the self-host tenant.
func (*Store) RemoveForgotten ¶ added in v0.3.0
RemoveForgotten removes, in one transaction, what MailRules kept of a forgotten user whose removal time has come by now. When they are their tenant's only member the whole tenant goes: its mailboxes with their credentials, folders, contacts, messages, decisions, actions and corrections, its rules, sender rules, batches, settings (provider keys included), usage ledger, and notification destinations with their notices and delivery log, the user with their sessions, identity and summaries, and the tenant itself. A member of a team takes all their mailboxes, shared or not (the team's rules naming one are rewritten as DeleteAccount does), with the notices about their mail, their sessions, identity, summaries and user row; the authorship of their rules and sender rules passes to the team (handOver). It answers ErrNotFound, changing nothing, for a user who is not forgotten or not yet due: one who signed in again, or was removed already.
func (*Store) RemoveMember ¶ added in v0.3.0
func (s *Store) RemoveMember(ctx context.Context, provider, subject string, now int64) (Forget, error)
RemoveMember is a member an owner or admin removed from their team: ForgetIdentity, recorded in the audit log as a removal, and in the same transaction their user lets go of the identity, as DeleteOwnAccount's does (MAI-253): the sign-in service has taken them out of the team's organisation, so they cannot come back to their data, and the same identity signing in under another organisation gets a new tenant of their own instead of ErrTenantMismatch. The tenant remembers the identity was removed (removed_identities), so signing in under its organisation again joins it only with a new invitation (SignInIdentity). Their old user's data goes on the team's schedule, ForgetDays later.
func (*Store) RemovedMailboxRetry ¶ added in v0.3.0
RemovedMailboxRetry records that a removed mailbox was not taken; it is handed over again at next.
func (*Store) RemovedMailboxSecret ¶ added in v0.3.0
RemovedMailboxSecret opens the secret a removed mailbox had. It returns crypto.ErrDecrypt when the key-encryption key does not open it, and ErrNotFound when the row is gone.
func (*Store) RemovedMailboxTaken ¶ added in v0.3.0
RemovedMailboxTaken deletes a removed mailbox the module took, with its secret.
func (*Store) ReorderRules ¶
ReorderRules sets the priorities of the tenant's rules to the order of ids, in one transaction. A reorder is not an edit, so versions stay as they are.
func (*Store) ReplaceUnopenableTenantKeys ¶ added in v0.3.0
ReplaceUnopenableTenantKeys drops every tenant key the store's key provider cannot unwrap, so the next secret sealed for that tenant gets a new key: what MAILRULES_NEW_MASTER_KEY asks for once the old master key is gone for good. The secrets sealed under a dropped key can never be opened again, so they go with it, in the same transaction, as ForgetIdentity deletes secrets: a mailbox shows its password deleted (Account.SecretGone), a destination its address deleted, a model key is not set. The person enters them again. It returns how many tenants' keys it dropped; with the right key it drops none. Only a wrong key (crypto.ErrDecrypt) drops one: a provider that cannot answer stops it with crypto.ErrKeyUnavailable, having dropped nothing more.
func (*Store) Retain ¶
func (s *Store) Retain(ctx context.Context, tenantID, now int64, retentionDays int) (blanked, deleted int64, err error)
Retain is the retention job's one step for one tenant: it blanks the snippet of every message of the tenant's mailboxes first seen more than retentionDays ago (the tenant's retention_days), and deletes the tenant's messages first seen more than KeepMessagesDays ago that have no action left to undo, that is, none in effect from the last UndoDays (their decisions, actions and corrections go with them). It returns how many rows each part touched. It also deletes the tenant's notices and delivery records older than NoticeDays, the moves the move watcher found more than MoveDays ago, the audit log's rows older than AuditDays and the invitations that expired, which it does not count.
func (*Store) RevokeInvitation ¶ added in v0.3.0
func (s *Store) RevokeInvitation(ctx context.Context, tenantID, id int64, why string, now int64) (Invitation, error)
RevokeInvitation deletes one of the tenant's invitations and returns it, recorded as revoked, or as withdrawn with why when the daemon takes it back itself (it could not be sent). The seat it held is checked for (queueSeatCheck). ErrNotFound for one it does not have.
func (*Store) RewrapTenantKeys ¶ added in v0.3.0
RewrapTenantKeys wraps again, under the store's key provider, every tenant key wrapped under another KEK (tenants.kek_id): what moving an install from the master key to a module's key service (ext.Module.Keys) does, once per tenant. The secrets stay as they are, since they are sealed under the tenant's key, which does not change. Each tenant is one compare-and-set, so a second run, or two daemons at once, rewrap nothing twice. A tenant key that does not unwrap (crypto.ErrDecrypt: the master key is not the one it was wrapped under, or is gone) is left as it is; MasterKeyUses still counts it. A provider that cannot answer stops it with crypto.ErrKeyUnavailable: what is left is rewrapped at the next run. It returns how many it rewrapped.
func (*Store) RuleCosts ¶
RuleCosts lists, per rule, the emails of the mailboxes the viewer sees decided for it since `since` and what the model decisions among them cost, dearest first. Every decision counts here, a retry too: it was paid for.
func (*Store) RuleStats ¶
RuleStats counts, per rule of the viewer's tenant, the messages it was applied to since `since` in the mailboxes the viewer sees, with the time of the latest one ever. Mail waiting in Needs review does not count: nothing was applied.
func (*Store) Rules ¶
Rules returns all of the tenant's rules, disabled ones included, in priority order.
func (*Store) RunInEffect ¶ added in v0.3.0
RunInEffect reports whether what a decision's rule did to its email still stands: at least one of its actions (a draft aside) is done and none was undone since.
func (*Store) SaveFolders ¶
SaveFolders replaces an account's folder list with what discovery found. Watch positions of folders that still exist are kept; folders that are gone are removed.
func (*Store) SaveMessageSummary ¶
SaveMessageSummary stores the parsed header fields, snippet and signals of a message.
func (*Store) SeatCheckDone ¶ added in v0.3.0
SeatCheckDone deletes a seat check the worker handled, unless it was queued again since it was listed (c.Version): that one waits to be handled in turn.
func (*Store) SeatCheckRetry ¶ added in v0.3.0
SeatCheckRetry records that the billing module did not agree to a seat check: it is handled again at next, unless it was queued again since it was listed (it is due then).
func (*Store) SeatsUsed ¶ added in v0.3.0
SeatsUsed counts the seats the tenant has taken at now: its members (a removed or forgotten person, whose removal waits, is not one) and the invitations waiting. It is the one count of seats: the Members screen, Plan and billing, the downgrade check and the checks that refuse a person over the seats (takeSeat) all use it.
func (*Store) SenderRules ¶
SenderRules returns all of the tenant's sender rules.
func (*Store) SendersSeen ¶
SendersSeen lists every address the mailboxes the viewer sees have had mail from since `since` (by when MailRules first saw the email).
func (*Store) SessionUser ¶
SessionUser returns the user behind a live session and when it expires.
func (*Store) SetAccountCapabilities ¶
SetAccountCapabilities stores what the server advertised at the last login.
func (*Store) SetAccountCert ¶ added in v0.3.0
SetAccountCert stores the server certificate the person accepted for an account; "" leaves the decision to the system's trust store again.
func (*Store) SetAccountSecret ¶
SetAccountSecret replaces an account's app password, sealed under its tenant's key. The change is recorded under ctx's actor: one rotated by a provider is made WithoutActor.
func (*Store) SetAccountShared ¶ added in v0.2.0
SetAccountShared shares an account with everyone in its tenant, or makes it private to its owner again. The caller checks that the owner asks.
func (*Store) SetAccountStatus ¶
func (s *Store) SetAccountStatus(ctx context.Context, id int64, status, lastError string, now int64) error
SetAccountStatus records the connection state; lastError is cleared by passing "".
func (*Store) SetBatchProgress ¶
SetBatchProgress records how far a batch has come.
func (*Store) SetBatchStatus ¶
SetBatchStatus moves a batch to a status.
func (*Store) SetDryRun ¶
SetDryRun turns the tenant's dry-run switch on or off. A running daemon reads it before every action, so it takes effect at once.
func (*Store) SetFolderPosition ¶
func (s *Store) SetFolderPosition(ctx context.Context, accountID int64, name string, uidValidity, lastUID uint32) error
SetFolderPosition records how far a watched folder has been processed.
func (*Store) SetInvitationRecord ¶ added in v0.3.0
SetInvitationRecord keeps the module's reference to one of the tenant's invitations. ErrNotFound for one it does not have.
func (*Store) SetMessageState ¶
func (s *Store) SetMessageState(ctx context.Context, id int64, state string, attempts int, nextAttemptAt int64) error
SetMessageState moves a message to a state. nextAttemptAt is when the retry job should run it again; 0 means it is not waiting.
func (*Store) SetPassword ¶ added in v0.1.2
SetPassword replaces a user's password hash and, in the same transaction, ends every session the user has: a session someone else holds does not outlive the password that opened it. A missing user is ErrNotFound.
func (*Store) SetPlan ¶ added in v0.3.0
func (s *Store) SetPlan(ctx context.Context, tenantID int64, p Plan, now int64) (before, after PlanState, err error)
SetPlan stores the tenant's plan as the billing module reports it, at now, and returns the state before and after. A plan that runs (personal, pro or team) clears what the end of an earlier one left: when it ended, the warnings sent, the secrets deleted. One that ends, or a report that leaves it ended (a cancelled plan whose period is over, reported again), keeps the time it really ended (the trial's end, or the paid period's) when that is earlier than now, and the end-of-plan job's progress. A change of plan, interval, status, seats or the company sign-in add-on is recorded in the audit log. ErrBadPlan for a plan, interval or status it does not know, a team plan with no seat or another plan with seats or the add-on; ErrNotFound for a tenant that does not exist.
func (*Store) SetRole ¶ added in v0.3.0
SetRole gives one of the tenant's members role. It fails, changing nothing, with ErrNotFound for a user who is not a member, ErrBadRole, and ErrLastOwner when it would leave the tenant with no owner.
func (*Store) SetSetting ¶
SetSetting stores a tenant's JSON value under key, replacing any previous one.
func (*Store) SetSettings ¶
SetSettings stores several of a tenant's settings in one transaction, so a change is never half applied. A nil value removes the key, which puts its default back in force. The keys whose value changed are recorded in the audit log by name, with the value only when it is true, false or a number: never a key, an address or a model's name.
func (*Store) SetTrashToFolder ¶
SetTrashToFolder turns the tenant's trash_to_folder switch on or off.
func (*Store) SignInIdentity ¶ added in v0.2.0
func (s *Store) SignInIdentity(ctx context.Context, id Identity, now int64, seats SeatLimit) (User, error)
SignInIdentity finds the user an identity belongs to, or makes one, in one transaction. The tenant is the one of (Provider, Tenant), made when there is none yet. A new identity gets a user in that tenant who cannot sign in with a password; a known one keeps its user, whose email becomes id.Email, and a known one that was forgotten (ForgetIdentity) has its removal called off. One whose person deleted their own account, or was removed from their team, is no longer known (DeleteOwnAccount, RemoveMember), so it gets a new user. It fails, changing nothing, with ErrTenantMismatch when a known identity's user is in another tenant, and with ErrEmailInUse when another user has the email. A new tenant gets its data key at once, wrapped by the store's key provider (when it has one): a provider that cannot answer fails the sign-in with crypto.ErrKeyUnavailable, and no tenant is made.
The person who makes a tenant is its owner. A new identity joining a tenant that exists (the sign-in service let them into its organisation) gets the role of the invitation waiting for their email, which is then used up; without one they join as a member, and only while the tenant's plan has a seat free (seats; nil limits nothing), else the sign-in fails with a *SeatLimitError. An identity removed from the tenant (RemoveMember) joins it again only with an invitation, else the sign-in fails with ErrRemovedMember. Either join is recorded in the tenant's audit log.
It runs before anyone is signed in, so on Postgres it finds the tenants through the definer functions (scope.go) and scopes its transaction once it knows the tenant.
func (*Store) SpendAIEmails ¶ added in v0.3.0
SpendAIEmails counts n emails a model decided for the tenant on keys the operator holds at at, which no decision row records: those of a cleanup check beyond its first-cleanup grant (SpendCleanupEmail). Live sorting counts with the decision (Decision.Metered).
func (*Store) SpendCleanupEmail ¶ added in v0.3.0
func (s *Store) SpendCleanupEmail(ctx context.Context, tenantID int64, at time.Time, grant int) (fromGrant bool, err error)
SpendCleanupEmail counts one email a cleanup check had a model decide on keys the operator holds, at at: against the tenant's one-time first-cleanup grant while less than grant of it is used, else against the month's AI-sorted emails. The grant is taken in one statement, so checks running at once never take more than grant of it. fromGrant reports which it was.
func (*Store) StatsTotals ¶
StatsTotals counts the emails of the mailboxes the viewer sees decided since `since`.
func (*Store) SummaryCost ¶
func (s *Store) SummaryCost(ctx context.Context, v Viewer, from, to int64) (costUSD float64, calls int, err error)
SummaryCost is what the model decisions made in [from, to) on the mail of the mailboxes the viewer sees cost, and how many asked a model.
func (*Store) SummaryReview ¶
func (s *Store) SummaryReview(ctx context.Context, v Viewer, limit int) ([]SummaryEmail, int, error)
SummaryReview lists the emails of the mailboxes the viewer sees waiting in Needs review now, newest first, at most limit of them, and how many there are.
func (*Store) SummaryRules ¶
SummaryRules lists, per rule, the emails of the mailboxes the viewer sees a rule was applied to (sorted or trashed, as the Overview counts them) whose latest decision was made in [from, to), most first.
func (*Store) SummaryTrashed ¶
func (s *Store) SummaryTrashed(ctx context.Context, v Viewer, from, to int64, limit int) ([]SummaryEmail, int, error)
SummaryTrashed lists the emails of the mailboxes the viewer sees trashed (or, in dry-run, recorded as trashed) in [from, to) and still trashed now, as the Overview counts them (outcomeSQL), newest first, at most limit of them, and how many there are. An email trashed more than once in the window is listed once, as its latest such trash left it.
func (*Store) TenantAccounts ¶ added in v0.2.0
TenantAccounts lists every account of a tenant, private ones included, oldest first. It is for checks that span the tenant without showing what they find (a mailbox already connected), never for listing to a person.
func (*Store) TenantEmails ¶ added in v0.3.0
TenantEmails lists the email addresses of a tenant's members, oldest member first, but those forgotten (ForgetIdentity) whose removal waits: who an email about the tenant's plan goes to.
func (*Store) TenantKey ¶ added in v0.3.0
TenantKey is the tenant's data key, made (and stored wrapped) when it has none yet.
func (*Store) TenantMembers ¶ added in v0.2.0
TenantMembers counts a tenant's members, as Members lists them: a removed or forgotten person, whose removal waits, is not one (MAI-249).
func (*Store) TenantOrganisation ¶ added in v0.3.0
func (s *Store) TenantOrganisation(ctx context.Context, tenantID int64) (provider, organisation string, err error)
TenantOrganisation is the sign-in service that made the tenant and its id of the tenant's organisation there; both empty for the self-host tenant. ErrNotFound for a tenant that does not exist.
func (*Store) TenantPlan ¶ added in v0.3.0
TenantPlan returns the tenant's plan at now: the one the billing module last reported, or the trial while no plan was bought and TrialDays have not passed since the tenant was made, else ended. ErrNotFound for a tenant that does not exist.
func (*Store) Tenants ¶ added in v0.2.0
Tenants lists every tenant's id, oldest first: what per-tenant jobs (retention) walk. Within a tenant's scope it is that tenant alone.
func (*Store) TopRules ¶
TopRules lists the rules applied to the most emails of the mailboxes the viewer sees since `since`, most first.
func (*Store) TrashToFolder ¶
TrashToFolder reports whether the tenant's trashed mail goes to MailRules' own folder rather than the server's Trash. The executor reads it before every trash action.
func (*Store) UnsubscribeLinks ¶ added in v0.3.0
func (s *Store) UnsubscribeLinks(ctx context.Context, v Viewer, address string, since int64) ([]UnsubscribeLink, error)
UnsubscribeLinks lists, for every mailbox the viewer sees that MailRules has not unsubscribed from address yet, the one-click link of the newest email from address seen since `since` that offers one. A mailbox whose mail from address offers none is not listed.
func (*Store) UpdateAccount ¶
UpdateAccount stores an account's label, watch folder, server (host, port and TLS mode) and status (the fields the user edits). A new server clears Module: the server is then the person's, not the module's.
func (*Store) UpdateRule ¶
UpdateRule rewrites the editable columns of one of the tenant's rules and bumps its version, so past decisions keep pointing at the wording they were made under. The author (UserID) stays as it is. A rule of another tenant is ErrNotFound.
func (*Store) UpgradeSecrets ¶ added in v0.3.0
UpgradeSecrets reseals every secret still sealed under the master key itself (envelope 1, before tenant keys) under its tenant's key, and every removed mailbox's copy under the store's key-encryption key (envelope 3): those of envelope 1 and those sealed under another KEK (the master key, before a module's key service took over), tenant by tenant, each in one transaction. It returns how many it resealed; a second run reseals none. The daemon runs it at start, after the key check; until it has, envelope 1 still opens wherever a secret is read. A secret the master key does not open is left as it is (CheckSecrets counts it). Without the master key there is nothing it could open, and it does nothing.
func (*Store) UpsertContacts ¶
UpsertContacts adds addresses to an account's contacts, keeping the latest sent time.
func (*Store) Usage ¶
Usage lists the tenant's cost ledger from sinceDay (YYYY-MM-DD) on, oldest day first.
func (*Store) UserByEmail ¶
UserByEmail looks an account up by its (case-insensitive) email.
func (*Store) UserIdentity ¶ added in v0.3.0
UserIdentity is the identity a user was made from (SignInIdentity): its Provider and Subject, the rest left empty. A user with none, such as the self-host admin, is ErrNotFound.
func (*Store) Users ¶ added in v0.2.0
Users lists every user, oldest first, but those forgotten (ForgetIdentity) whose removal waits: who the summary email is checked for.
func (*Store) VisibleAccount ¶ added in v0.2.0
VisibleAccount returns one account the viewer sees, or ErrNotFound: one they do not see is answered as missing.
func (*Store) VisibleAccounts ¶ added in v0.2.0
VisibleAccounts lists the accounts the viewer sees, oldest first.
func (*Store) VisibleAction ¶ added in v0.2.0
VisibleAction returns one action on a mailbox the viewer sees, or ErrNotFound.
func (*Store) VisibleBatch ¶ added in v0.2.0
VisibleBatch returns one batch the viewer sees, or ErrNotFound.
func (*Store) VisibleBatchActions ¶ added in v0.2.0
VisibleBatchActions lists a batch's actions on the mailboxes the viewer sees, oldest first. A tenant's batch without a mailbox (the day's live batch, a correction or an undo) can hold actions on mailboxes of several people; each sees only theirs and shared ones.
func (*Store) VisibleMessage ¶ added in v0.2.0
VisibleMessage returns one message of a mailbox the viewer sees, or ErrNotFound.
func (*Store) WaitingDrafts ¶ added in v0.3.0
WaitingDrafts lists up to limit draft jobs due by now, oldest first.
func (*Store) WaitingMoves ¶ added in v0.3.0
WaitingMoves lists the person's moves the module has not taken yet that are due at now, oldest first: at most limit.
func (*Store) WaitingNotices ¶ added in v0.3.0
WaitingNotices lists up to limit notices the module has not taken yet that are due by now, oldest first.
func (*Store) WaitingRemovedMailboxes ¶ added in v0.3.0
func (s *Store) WaitingRemovedMailboxes(ctx context.Context, now int64, limit int) ([]RemovedMailbox, error)
WaitingRemovedMailboxes lists at most limit removed mailboxes due to be handed over by now, the longest waiting first.
func (*Store) WaitingSeatChecks ¶ added in v0.3.0
WaitingSeatChecks lists at most limit seat checks due by now, the longest due first.
func (*Store) WithKeyring ¶ added in v0.3.0
WithKeyring is the store sealing and opening secrets with k. It shares the database of s.
type Summary ¶
type Summary struct {
ID int64
UserID int64
DueAt int64
Status string
Attempts int
LastAttemptAt int64
PeriodStart int64 // 0 until sent
PeriodEnd int64
SentAt int64
}
Summary is one row of summaries: a scheduled summary email.
type SummaryEmail ¶
type SummaryEmail struct {
MessageID int64
FromName string
FromAddr string
Subject string
Folder string // a trashed email: the folder the trash moved it to; "" = the server's Trash
DryRun bool // a trashed email: the trash was only recorded, in dry-run
}
SummaryEmail is one email as a summary lists it: who sent it, its subject and, for a trashed one, where it went. Never its text.
type Totals ¶
type Totals struct {
Processed int // emails decided
Sorted int // of those, a rule or sender rule was applied (or recorded, in dry-run) and not undone since
WithoutModel int // of those, a sender rule or condition rule acted on, with no model asked; never more than Processed
Trashed int // emails with a trash action that is in effect (or recorded, in dry-run)
// Where the processed emails ended up; the four add up to Processed.
WentSorted int // a rule was applied and it did not trash the email
WentTrash int // a rule was applied and it trashed the email
WentReview int // waiting in Needs review
WentNowhere int // left in the inbox: no rule matched, it was the mailbox's own mail, it could not be handled, or all that was done to it was undone
}
Totals are the counts of the stats tiles.
type UnsubscribeLink ¶ added in v0.3.0
UnsubscribeLink is the one-click unsubscribe link of the newest email from an address on one mailbox.
type UsageRow ¶
type UsageRow struct {
Day string // YYYY-MM-DD, UTC
Provider string
Model string
Purpose string // decide | escalate | compose | test | cleanup | suggest | draft
Operator bool // made with a key the operator holds (MAILRULES_MODE=cloud)
Calls int
TokensIn int
TokensOut int
CostUSD float64
}
UsageRow is one row of the cost ledger.
type User ¶
type User struct {
ID int64
Email string
PasswordHash string
CreatedAt int64
TenantID int64
Role string // RoleOwner, RoleAdmin or RoleMember
}
User is a person who signs in. Self-host has one, the admin, in SelfHostTenant.
type Viewer ¶ added in v0.2.0
type Viewer struct {
UserID, TenantID int64
}
Viewer is the signed-in person a user-facing read or change is made for. They see an account when it is in their tenant and they own it or it is shared (visibleAccounts), and through it its messages, decisions, actions, corrections, contacts, folders, batches, stats, activity and Needs review queue. Rules, sender rules, settings and the usage ledger belong to the tenant.
Source Files
¶
Directories
¶
| Path | Synopsis |
|---|---|
|
Package migrations holds the store's schema migrations, one set per SQL dialect, embedded into the binary and applied by goose.
|
Package migrations holds the store's schema migrations, one set per SQL dialect, embedded into the binary and applied by goose. |
|
Package pgtest gives a test its own Postgres database, migrated to the store's current Postgres schema, with connections as the roles the hosted build runs as.
|
Package pgtest gives a test its own Postgres database, migrated to the store's current Postgres schema, with connections as the roles the hosted build runs as. |
|
Command querycover fails when a statement of the store was never run by the tests behind a coverage profile.
|
Command querycover fails when a statement of the store was never run by the tests behind a coverage profile. |
|
Package storetest gives tests outside the store a fresh, migrated database, so that the backend a test runs against is chosen in one place rather than in every test file: Postgres when MAILRULES_TEST_POSTGRES_DSN is set (see pgtest), SQLite otherwise.
|
Package storetest gives tests outside the store a fresh, migrated database, so that the backend a test runs against is chosen in one place rather than in every test file: Postgres when MAILRULES_TEST_POSTGRES_DSN is set (see pgtest), SQLite otherwise. |