1
0
mirror of https://github.com/pocketbase/pocketbase.git synced 2024-12-01 11:01:04 +02:00
pocketbase/models/collection.go
2023-03-22 17:12:44 +02:00

220 lines
6.1 KiB
Go

package models
import (
"encoding/json"
validation "github.com/go-ozzo/ozzo-validation/v4"
"github.com/go-ozzo/ozzo-validation/v4/is"
"github.com/pocketbase/pocketbase/models/schema"
"github.com/pocketbase/pocketbase/tools/types"
)
var (
_ Model = (*Collection)(nil)
_ FilesManager = (*Collection)(nil)
)
const (
CollectionTypeBase = "base"
CollectionTypeAuth = "auth"
CollectionTypeView = "view"
)
type Collection struct {
BaseModel
Name string `db:"name" json:"name"`
Type string `db:"type" json:"type"`
System bool `db:"system" json:"system"`
Schema schema.Schema `db:"schema" json:"schema"`
Indexes types.JsonArray[string] `db:"indexes" json:"indexes"`
// rules
ListRule *string `db:"listRule" json:"listRule"`
ViewRule *string `db:"viewRule" json:"viewRule"`
CreateRule *string `db:"createRule" json:"createRule"`
UpdateRule *string `db:"updateRule" json:"updateRule"`
DeleteRule *string `db:"deleteRule" json:"deleteRule"`
Options types.JsonMap `db:"options" json:"options"`
}
// TableName returns the Collection model SQL table name.
func (m *Collection) TableName() string {
return "_collections"
}
// BaseFilesPath returns the storage dir path used by the collection.
func (m *Collection) BaseFilesPath() string {
return m.Id
}
// IsBase checks if the current collection has "base" type.
func (m *Collection) IsBase() bool {
return m.Type == CollectionTypeBase
}
// IsAuth checks if the current collection has "auth" type.
func (m *Collection) IsAuth() bool {
return m.Type == CollectionTypeAuth
}
// IsView checks if the current collection has "view" type.
func (m *Collection) IsView() bool {
return m.Type == CollectionTypeView
}
// MarshalJSON implements the [json.Marshaler] interface.
func (m Collection) MarshalJSON() ([]byte, error) {
type alias Collection // prevent recursion
m.NormalizeOptions()
return json.Marshal(alias(m))
}
// BaseOptions decodes the current collection options and returns them
// as new [CollectionBaseOptions] instance.
func (m *Collection) BaseOptions() CollectionBaseOptions {
result := CollectionBaseOptions{}
m.DecodeOptions(&result)
return result
}
// AuthOptions decodes the current collection options and returns them
// as new [CollectionAuthOptions] instance.
func (m *Collection) AuthOptions() CollectionAuthOptions {
result := CollectionAuthOptions{}
m.DecodeOptions(&result)
return result
}
// ViewOptions decodes the current collection options and returns them
// as new [CollectionViewOptions] instance.
func (m *Collection) ViewOptions() CollectionViewOptions {
result := CollectionViewOptions{}
m.DecodeOptions(&result)
return result
}
// NormalizeOptions updates the current collection options with a
// new normalized state based on the collection type.
func (m *Collection) NormalizeOptions() error {
var typedOptions any
switch m.Type {
case CollectionTypeAuth:
typedOptions = m.AuthOptions()
case CollectionTypeView:
typedOptions = m.ViewOptions()
default:
typedOptions = m.BaseOptions()
}
// serialize
raw, err := json.Marshal(typedOptions)
if err != nil {
return err
}
// load into a new JsonMap
m.Options = types.JsonMap{}
if err := json.Unmarshal(raw, &m.Options); err != nil {
return err
}
return nil
}
// DecodeOptions decodes the current collection options into the
// provided "result" (must be a pointer).
func (m *Collection) DecodeOptions(result any) error {
// raw serialize
raw, err := json.Marshal(m.Options)
if err != nil {
return err
}
// decode into the provided result
if err := json.Unmarshal(raw, result); err != nil {
return err
}
return nil
}
// SetOptions normalizes and unmarshals the specified options into m.Options.
func (m *Collection) SetOptions(typedOptions any) error {
// serialize
raw, err := json.Marshal(typedOptions)
if err != nil {
return err
}
m.Options = types.JsonMap{}
if err := json.Unmarshal(raw, &m.Options); err != nil {
return err
}
return m.NormalizeOptions()
}
// -------------------------------------------------------------------
// CollectionBaseOptions defines the "base" Collection.Options fields.
type CollectionBaseOptions struct {
}
// Validate implements [validation.Validatable] interface.
func (o CollectionBaseOptions) Validate() error {
return nil
}
// -------------------------------------------------------------------
// CollectionAuthOptions defines the "auth" Collection.Options fields.
type CollectionAuthOptions struct {
ManageRule *string `form:"manageRule" json:"manageRule"`
AllowOAuth2Auth bool `form:"allowOAuth2Auth" json:"allowOAuth2Auth"`
AllowUsernameAuth bool `form:"allowUsernameAuth" json:"allowUsernameAuth"`
AllowEmailAuth bool `form:"allowEmailAuth" json:"allowEmailAuth"`
RequireEmail bool `form:"requireEmail" json:"requireEmail"`
ExceptEmailDomains []string `form:"exceptEmailDomains" json:"exceptEmailDomains"`
OnlyEmailDomains []string `form:"onlyEmailDomains" json:"onlyEmailDomains"`
MinPasswordLength int `form:"minPasswordLength" json:"minPasswordLength"`
}
// Validate implements [validation.Validatable] interface.
func (o CollectionAuthOptions) Validate() error {
return validation.ValidateStruct(&o,
validation.Field(&o.ManageRule, validation.NilOrNotEmpty),
validation.Field(
&o.ExceptEmailDomains,
validation.When(len(o.OnlyEmailDomains) > 0, validation.Empty).Else(validation.Each(is.Domain)),
),
validation.Field(
&o.OnlyEmailDomains,
validation.When(len(o.ExceptEmailDomains) > 0, validation.Empty).Else(validation.Each(is.Domain)),
),
validation.Field(
&o.MinPasswordLength,
validation.When(o.AllowUsernameAuth || o.AllowEmailAuth, validation.Required),
validation.Min(5),
validation.Max(72),
),
)
}
// -------------------------------------------------------------------
// CollectionViewOptions defines the "view" Collection.Options fields.
type CollectionViewOptions struct {
Query string `form:"query" json:"query"`
}
// Validate implements [validation.Validatable] interface.
func (o CollectionViewOptions) Validate() error {
return validation.ValidateStruct(&o,
validation.Field(&o.Query, validation.Required),
)
}