app

package
v0.0.0-...-904e6cd Latest Latest
Warning

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

Go to latest
Published: Apr 12, 2024 License: AGPL-3.0 Imports: 13 Imported by: 0

Documentation

Overview

Package app contains the core functionality of the aplication.

This package makes heavy use of the Command pattern: Functions are encapsulated in individual small structs that do exactly one thing and nothing else. The Command and Query types are both commands in this sense, their names reflecting whether they perform read (query) or write (command) actions.

Index

Constants

View Source
const (
	PermNone  = 0x00000000
	PermLogin = 0x00000001

	PermCreate = 0x00000100
	PermRead   = 0x00000200
	PermEdit   = 0x00000400
	PermDelete = 0x00000800
	PermOwner  = PermCreate | PermRead | PermEdit | PermDelete

	PermCreateFood = 0x00010000
	PermEditFood   = 0x00020000
	PermAdmin      = PermCreateFood | PermEditFood
)

Variables

View Source
var (
	ErrCredentials = errors.New("nomatch")
	ErrExists      = errors.New("exists")
	ErrMissing     = errors.New("missing")
	ErrNoEmail     = errors.New("noemail")
	ErrNotFound    = errors.New("notfound")
	ErrPermission  = errors.New("permission")
	ErrWeakPass    = errors.New("weakpass")
)

Functions

This section is empty.

Types

type AccountPrefs

type AccountPrefs struct {
	Email string `json:"email"`
	Name  string `json:"name"`
}

AccountPrefs holds all user settings directly related to the user's account.

type Activate

type Activate struct {
	Token string
}

Activate is a command to unlock a user's ability to log into the application and to change their e-mail address after a change request was issued. If successful, the token is deleted and cannot be used again.

func (*Activate) Execute

func (c *Activate) Execute(db DB) error

type AddDiaryEntries

type AddDiaryEntries struct {
	Date time.Time
	Food []core.DiaryEntry
	ID   int
}

AddDiaryEntries is a command to add several food items to the diary identified by ID and the day identified by Date. If any of the food already exists, the amount is added on top, otherwise a new entry is created.

Any food with an amount of 0 or a date that does not actually fall on the same day with Date is silently dropped.

func (*AddDiaryEntries) Execute

func (c *AddDiaryEntries) Execute(db DB) error

type Authenticate

type Authenticate struct {
	Email string
	Pass  string
	Lang  string
	Perm  int
	ID    int
}

Authenticate is a query that authenticates a user by checking against e-mail and password. If successful, the user's id, language, and permissions are stored in the command.

func (*Authenticate) Fetch

func (q *Authenticate) Fetch(db DB) error

type Authorize

type Authorize struct {
	ID   int
	Pass string
	Ok   bool
}

Authorize is a query that issues a challenge to pass in order to make sure a user identified by ID has the right to perform a given action. It is intentionally not tied to a specific action or resource. The type of challenge is expressed through the fields of the query.

If successful, the Ok field will be set to true. There is no error if the challenge itself fails, so you still have to check Ok to ultimately know the final result.

Supported types of challenges are:

  • Password: Make sure the user is still the same user by asking for the password again. This type of challenge is often issued before dangerous actions or those with far-reaching consequences.

func (*Authorize) Fetch

func (q *Authorize) Fetch(db DB) error

type ChangeName

type ChangeName struct {
	ID   int    `json:"id"`
	Name string `json:"name"`
}

ChangeName is a command to assign a new user name to the user identified by ID. The name is randomly generated. If successful, Name contains the new name.

func (*ChangeName) Execute

func (c *ChangeName) Execute(db DB) error

type ChangePassword

type ChangePassword struct {
	Token string
	Pass  string
	ID    int
}

ChangePassword is a command to change a registered user's password. It expects either the ID or the Token field to be set, where ID points to a valid user id or the token can be used to retrieve such an id.

func (*ChangePassword) Execute

func (c *ChangePassword) Execute(db DB) error

type Command

type Command interface {
	Execute(db DB) error
}

A Command encapsulates a single action that changes the underlying data. It can carry input and output parameters.

type CreateFood

type CreateFood struct {
	Food core.Food
}

CreateFood is a command to create a new food item in the food database. If successful, the new item id is stored in the command.

func (*CreateFood) Execute

func (c *CreateFood) Execute(db DB) error

type CreateRecipe

type CreateRecipe struct {
	Name   string
	Recipe core.Recipe
}

CreateRecipe is a command to create a new named recipe in the food database. If successful, the new item is stored in the command.

func (*CreateRecipe) Execute

func (c *CreateRecipe) Execute(db DB) error

type CreateUser

type CreateUser struct {
	Email string
	Pass  string
	Token string
	ID    int
}

CreateUser is a command to create a new user with a unique id and e-mail address. If successful, the new user's id is stored in the command.

func (*CreateUser) Execute

func (c *CreateUser) Execute(db DB) error

type Crypter

type Crypter interface {
	Encrypt(pass string) string
	Match(hash, pass string) bool
}

Crypter decrypts and encrypts passwords.

func NewCrypter

func NewCrypter() Crypter

NewCrypter returns a default implementation of the Crypter interface. The cost parameter is used for the cost of the underlying hash function.

type DB

type DB interface {
	Execute(Command) error
	Fetch(Query) error

	NewUser(email, hash, token string) (int, error)
	SetUser(User) error
	DelUser(id int) error
	UserByEmail(email string) (User, error)
	UserByName(name string) (User, error)
	UserByID(id int) (User, error)
	UserNames(prefix string) ([]string, error)
	UserPrefs(id int) (StoredPrefs, error)
	NewToken(id int, hash string, data interface{}) error
	DelToken(string) error
	Token(string) (Token, error)

	NewFood() (int, error)
	SetFood(core.Food) error
	Food(id int) (core.Food, error)
	Foods(core.Filter) ([]core.Food, error)
	FoodExists(id int) (bool, error)

	NewRecipe(string) (int, error)
	SetRecipe(core.Recipe) error
	SetRecipeAccess(user, rec, perms int) error
	SetRecipeInstructions(id int, text string) error
	DelRecipeInstructions(id int) error
	Recipe(id int) (core.Recipe, error)
	Recipes(uid int, f core.Filter) ([]core.Recipe, error)
	RecipeAccess(user, rec int) (int, error)
	RecipeInstructions(id int) (string, error)

	NewDiaryEntries(id int, entries ...core.DiaryEntry) error
	SetDiaryEntries(id int, entries ...core.DiaryEntry) error
	DelDiaryEntries(id int, entries ...core.DiaryEntry) error
	DiaryEntries(id int, date time.Time) ([]core.DiaryEntry, error)
	DiaryDays(id, year, month, day int) ([]core.DiaryDay, error)

	SetShoppingListDone(id int, done map[int]bool) error
	ShoppingList(id int, date ...time.Time) ([]core.ShopItem, error)
}

DB provides access to persistent storage.

type DeleteUser

type DeleteUser struct {
	ID int
}

DeleteUser is a command to delete an existing user from the system. No error is returned if the user doesn't exist.

func (*DeleteUser) Execute

func (c *DeleteUser) Execute(db DB) error

type DiaryDays

type DiaryDays struct {
	Days  []core.DiaryDay
	ID    int
	Year  int
	Month int
	Day   int
}

DiaryDays is a query to fetch diary summaries for all days that fit the Year and Month query fields. The diary that is searched belongs to the user identified by ID.

func (*DiaryDays) Fetch

func (q *DiaryDays) Fetch(db DB) error

type DiaryEntries

type DiaryEntries struct {
	Date    time.Time
	Entries []core.DiaryEntry
	ID      int
}

DiaryEntries is a query to fetch diary entries for a given date and a user identified by ID from the food database.

func (*DiaryEntries) Fetch

func (q *DiaryEntries) Fetch(db DB) error

type GetFood

type GetFood struct {
	Item core.Food
}

GetFood is a query to retrieve a single food item from the food database. The item's ID is expected to be set before the query is executed.

func (*GetFood) Fetch

func (q *GetFood) Fetch(db DB) error

type GetFoods

type GetFoods struct {
	Filter core.Filter
	Items  []core.Food
}

GetFoods is a query to retrieve all food items from the food database.

func (*GetFoods) Fetch

func (q *GetFoods) Fetch(db DB) error

type Log

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

func NewLog

func NewLog(wr io.Writer) *Log

func (*Log) Error

func (l *Log) Error(i interface{})

func (*Log) Log

func (l *Log) Log(i interface{})

func (*Log) Warn

func (l *Log) Warn(i interface{})

type Logger

type Logger interface {
	Log(interface{})
	Warn(interface{})
	Error(interface{})
}

type MacroPrefs

type MacroPrefs struct {
	KCal    float32 `json:"kcal"`
	Fat     float32 `json:"fat"`
	Carbs   float32 `json:"carb"`
	Protein float32 `json:"prot"`
}

MacroPrefs holds all user settings related to personal macronutrient targets.

type Notification

type Notification int
const (
	RegisterNotification Notification = iota + 1
	RenameNotification
	ResetNotification
)

type NotificationData

type NotificationData map[string]interface{}

type Notifier

type Notifier interface {
	Send(to string, msg Notification, data NotificationData) error
}

Notifier provides functions for sending messages to users of the application.

type Preferences

type Preferences struct {
	ID    int
	Prefs Prefs
}

Preferences is a query to collect all user preferences from the database. If successful, the Prefs field will contain all preferences that were found.

As long as the user exists, a valid set of preferences will be generated. For users who never changed their settings in any way, this is identical to the set of default preferences.

func (*Preferences) Fetch

func (q *Preferences) Fetch(db DB) error

type Prefs

type Prefs struct {
	Account AccountPrefs  `json:"account"`
	Macros  [7]MacroPrefs `json:"macros"`
	RDI     RDIPrefs      `json:"rdi"`
	UI      UIPrefs       `json:"ui"`
}

Prefs holds all individual preferences types and is the object that gets passed around the application.

type Query

type Query interface {
	Fetch(db DB) error
}

A Query encapsulates a single read action on the underlying data. It should not make any changes to the data. It can carry input and output parameters.

type RDIPrefs

type RDIPrefs struct {
	FatSat float32 `json:"fatsat"`
	FatO3  float32 `json:"fato3"`
	FatO6  float32 `json:"fato6"`
	Fiber  float32 `json:"fib"`
	Salt   float32 `json:"salt"`

	Potassium  float32 `json:"pot"`
	Chlorine   float32 `json:"chl"`
	Sodium     float32 `json:"sod"`
	Calcium    float32 `json:"calc"`
	Phosphorus float32 `json:"phos"`
	Magnesium  float32 `json:"mag"`
	Iron       float32 `json:"iron"`
	Zinc       float32 `json:"zinc"`
	Manganse   float32 `json:"mang"`
	Copper     float32 `json:"cop"`
	Iodine     float32 `json:"iod"`
	Chromium   float32 `json:"chr"`
	Molybdenum float32 `json:"mol"`
	Selenium   float32 `json:"sel"`

	VitA   float32 `json:"vita"`
	VitB1  float32 `json:"vitb1"`
	VitB2  float32 `json:"vitb2"`
	VitB3  float32 `json:"vitb3"`
	VitB5  float32 `json:"vitb5"`
	VitB6  float32 `json:"vitb6"`
	VitB7  float32 `json:"vitb7"`
	VitB9  float32 `json:"vitb9"`
	VitB12 float32 `json:"vitb12"`
	VitC   float32 `json:"vitc"`
	VitD   float32 `json:"vitd"`
	VitE   float32 `json:"vite"`
	VitK   float32 `json:"vitk"`
}

RDIPrefs holds all user settings related to the recommended daily intake of various nutrients.

type Recipe

type Recipe struct {
	Item core.Recipe
}

Recipe is a query to retrieve a single recipe from the food database. The item's ID is expected to be set before the query is executed.

func (*Recipe) Fetch

func (q *Recipe) Fetch(db DB) error

type RecipeAccess

type RecipeAccess struct {
	UserID     int
	RecID      int
	Permission int
}

RecipeAccess is a query that fetches a user's access rights for a given recipe. If successful, the permission value is stored in the query.

func (*RecipeAccess) Fetch

func (q *RecipeAccess) Fetch(db DB) error

func (*RecipeAccess) HasPerms

func (q *RecipeAccess) HasPerms(perms int) bool

type RecipeInstructions

type RecipeInstructions struct {
	RecID        int    `json:"id"`
	Instructions string `json:"inst"`
}

RecipeInstructions is a query that fetches preparation instructions for a given recipe. If successful, the text is stored in the query.

func (*RecipeInstructions) Fetch

func (q *RecipeInstructions) Fetch(db DB) error

type Recipes

type Recipes struct {
	Filter core.Filter
	Items  []core.Recipe
	UserID int
}

Recipes is a query to retrieve all recipes from the food database.

func (*Recipes) Fetch

func (q *Recipes) Fetch(db DB) error

type RequestEmailChange

type RequestEmailChange struct {
	ID    int
	Email string
	Token string
}

RequestEmailChange is a command to start the process of changing a user's e-mail address. When successful, the Token field contains a token that can be used to confirm and complete the request.

func (*RequestEmailChange) Execute

func (c *RequestEmailChange) Execute(db DB) error

type ResetPassword

type ResetPassword struct {
	Email string
	Token string
}

ResetPassword is a command to create a password reset token that allows an anonymous user to change the password that's associated with a registered user.

func (*ResetPassword) Execute

func (c *ResetPassword) Execute(db DB) error

type SaveDiaryEntries

type SaveDiaryEntries struct {
	Date time.Time
	Food []core.DiaryEntry
	ID   int
}

SaveDiaryEntries is a command to update existing food items in the diary identified by ID with the given amount. The old amount is always replaced with the new one.

Any food with an amount of 0 will be removed from the database. Any food with a date that does not fall on the same day with Date is silently dropped.

func (*SaveDiaryEntries) Execute

func (c *SaveDiaryEntries) Execute(db DB) error

type SaveFood

type SaveFood struct {
	Data map[string]float32
	ID   int
}

SaveFood is a command that changes the specified values of a food item identified by ID.

func (*SaveFood) Execute

func (c *SaveFood) Execute(db DB) error

type SaveIngredient

type SaveIngredient struct {
	RecipeID     int
	IngredientID int
	Amount       float32
	Replace      bool
}

SaveIngredient is a command to make changes to a recipe's list of ingredients. If Amount is 0, the ingredient will be removed from the recipe, otherwise it will be added or updated. If Replace is true, it will replace the current amount, otherwise it will add to it. In any case, the recipe's cached nutrients will be recalculated after the operation.

func (*SaveIngredient) Execute

func (c *SaveIngredient) Execute(db DB) error

type SaveRecipe

type SaveRecipe struct {
	Data map[string]interface{}
	ID   int
}

SaveRecipe is a command that upates a recipe's data, including the name and the number of servings but never the list of ingredients.

func (*SaveRecipe) Execute

func (c *SaveRecipe) Execute(db DB) error

type SaveRecipeAccess

type SaveRecipeAccess struct {
	UserID     int
	RecID      int
	Permission int
}

SaveRecipeAccess is a command that changes a user's access rights for a given recipe.

func (*SaveRecipeAccess) Execute

func (c *SaveRecipeAccess) Execute(db DB) error

type SaveRecipeInstructions

type SaveRecipeInstructions struct {
	RecipeID     int
	Instructions string
}

SaveRecipeInstructions is a command to make changes to a recipe's preparation instructions. An empty instructions string will delete the instructions for this recipe along with all associated data like images and videos.

NOTE: images and video storage for recipe instructions is not yet implemented as of 2024-02-22.

func (*SaveRecipeInstructions) Execute

func (c *SaveRecipeInstructions) Execute(db DB) error

type SaveShoppingListDone

type SaveShoppingListDone struct {
	Items map[int]bool
	Name  string
	ID    int
}

func (*SaveShoppingListDone) Execute

func (c *SaveShoppingListDone) Execute(db DB) error

type ShoppingList

type ShoppingList struct {
	Name  string
	Date  []time.Time
	Items []core.ShopItem
	ID    int
}

func (*ShoppingList) Fetch

func (q *ShoppingList) Fetch(db DB) error

type StoredPrefs

type StoredPrefs struct {
	Macros [7]MacroPrefs `json:"macros"`
	UIPrefs
}

StoredPrefs contains preferences that cannot be inferred from other objects. These are the absolute minimum that need to be stored in persistent storage in order to reconstruct a complete set of user preferences.

Most notably, we really don't want to store individual RDI values because doing so would bloat the stored data size with largely the same values for most users.

type SwitchLanguage

type SwitchLanguage struct {
	Lang string
	ID   int
}

SwitchLanguage is a command to change a user's UI language preference.

func (*SwitchLanguage) Execute

func (c *SwitchLanguage) Execute(db DB) error

type Token

type Token struct {
	Data interface{} `json:"data,omitempty"`
	ID   int         `json:"id"`
}

Token is a piece of data used for anonymous authorization.

type Tokenizer

type Tokenizer interface {
	Create() string
}

Tokenizer creates cryptographically secure tokens.

func NewTokenizer

func NewTokenizer() Tokenizer

NewTokenizer returns a default implementation of the Tokenizer interface.

type Translator

type Translator interface {
	Translate(input interface{}, lang string) string
	Get(lang string) map[string]interface{}
	Default() string
}

Translator defines functions for text localization.

type UIPrefs

type UIPrefs struct {
	NeutralCharts     bool `json:"neutralCharts"`
	TrackSaltAsSodium bool `json:"trackSaltAsSodium"`
}

UIPrefs holds all user settings related to the presentation of data in a client application. It contains options for filtering, sorting, and display preferences.

type User

type User struct {
	Email string `json:"email"`
	Name  string `json:"name"`
	Pass  string `json:"pass"`
	Lang  string `json:"lang"`
	Perm  int    `json:"perm"`
	ID    int    `json:"id"`
}

User represents a human user of the system, identified by their e-mail address or id. The password is always stored as an encrypted hash.

type Validator

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

Validator provides validation for different types of user input.

func NewValidator

func NewValidator() Validator

NewValidator returns a new Validator.

func (Validator) MatchEmail

func (v Validator) MatchEmail(s string) bool

MatchEmail returns true when s is a valid e-mail address.

func (Validator) MatchLang

func (v Validator) MatchLang(s string) bool

MatchLang returns true when s is a valid IETF BCP 47 language tag.

func (Validator) MatchPass

func (v Validator) MatchPass(s string) bool

MatchPass returns true when s is a valid password.

Jump to

Keyboard shortcuts

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