mirror of
https://github.com/hanzoai/base.git
synced 2026-10-21 03:41:50 +00:00
Seven field types a CRM record needs, each one JSON column whose parts a filter, a sort or an aggregate reaches by name: currency (amountMicros, currencyCode), emails, phones, links, address, fullName and actor, plus rating. Empty is NULL. Emails, phones and links normalize what is typed and can keep their primary part unique. An actor is stamped by the server from the writer the save's context states; nothing a request sends sets it. Every field carries a label, description, icon and position, a select's values carry a label, colour and position, and a base collection carries a label, plural, icon, description and an opt-in history flag. Editor HTML is sanitized before it is written. A rule reads the caller's authority in the org it acts in: @request.auth.admin and @request.auth.role, off the token. An IAM-mirrored auth record is never saved, so its fields are now read off the record rather than joined against a row that is not there, which also makes @request.auth.org_id match for the first time. A host that opens one Base per org names it, and a token acting in another org is refused there.
62 lines
2.3 KiB
Go
62 lines
2.3 KiB
Go
package core
|
|
|
|
import (
|
|
"regexp"
|
|
|
|
validation "github.com/go-ozzo/ozzo-validation/v4"
|
|
)
|
|
|
|
// FieldMeta is what a person reads about a field: the label it is shown under,
|
|
// what it is for, the icon drawn beside it and where it sits among the others.
|
|
// It changes nothing about the value, the column or the rules.
|
|
//
|
|
// Every field type embeds it, so it travels with the field in the collection's
|
|
// own schema (an export, an import and a module carry it) and there is no second
|
|
// table of presentation rows to keep in step with the fields it describes.
|
|
type FieldMeta struct {
|
|
// Label is the name a person reads. Empty means the field's name.
|
|
Label string `form:"label" json:"label,omitempty"`
|
|
|
|
// Description says what the field holds, for the person filling it in.
|
|
Description string `form:"description" json:"description,omitempty"`
|
|
|
|
// Icon names the icon drawn beside the field (a Tabler icon name, such as
|
|
// "IconUser" or "user").
|
|
Icon string `form:"icon" json:"icon,omitempty"`
|
|
|
|
// Position orders the field among the collection's fields where a client
|
|
// lays them out. Ties fall back to the schema's own order.
|
|
Position int `form:"position" json:"position,omitempty"`
|
|
}
|
|
|
|
// Meta returns the field's presentation, for a caller holding the Field
|
|
// interface (every field type embeds FieldMeta, so every field answers it).
|
|
func (m *FieldMeta) Meta() *FieldMeta {
|
|
return m
|
|
}
|
|
|
|
// FieldMetaHolder is a field that carries [FieldMeta].
|
|
type FieldMetaHolder interface {
|
|
Meta() *FieldMeta
|
|
}
|
|
|
|
var iconRegex = regexp.MustCompile(`^[A-Za-z0-9][A-Za-z0-9_-]{0,63}$`)
|
|
|
|
// Validate checks the presentation's bounds.
|
|
func (m *FieldMeta) Validate() error {
|
|
return validation.ValidateStruct(m,
|
|
validation.Field(&m.Label, validation.Length(0, 255)),
|
|
validation.Field(&m.Description, validation.Length(0, 1000)),
|
|
validation.Field(&m.Icon, validation.Match(iconRegex)),
|
|
validation.Field(&m.Position, validation.Min(0)),
|
|
)
|
|
}
|
|
|
|
// TagColors is the palette a select option, a collection or a view may be
|
|
// coloured from. Gray is the default.
|
|
var TagColors = []string{
|
|
"red", "ruby", "crimson", "tomato", "orange", "amber", "yellow", "lime",
|
|
"grass", "green", "jade", "mint", "turquoise", "cyan", "sky", "blue",
|
|
"iris", "violet", "purple", "plum", "pink", "bronze", "gold", "brown", "gray",
|
|
}
|