initial v0.8 pre-release
This commit is contained in:
558
models/record.go
558
models/record.go
@@ -2,28 +2,34 @@ package models
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"log"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/pocketbase/dbx"
|
||||
"github.com/pocketbase/pocketbase/models/schema"
|
||||
"github.com/pocketbase/pocketbase/tools/list"
|
||||
"github.com/pocketbase/pocketbase/tools/security"
|
||||
"github.com/pocketbase/pocketbase/tools/types"
|
||||
"github.com/spf13/cast"
|
||||
"golang.org/x/crypto/bcrypt"
|
||||
)
|
||||
|
||||
var _ Model = (*Record)(nil)
|
||||
var _ ColumnValueMapper = (*Record)(nil)
|
||||
var _ FilesManager = (*Record)(nil)
|
||||
var (
|
||||
_ Model = (*Record)(nil)
|
||||
_ ColumnValueMapper = (*Record)(nil)
|
||||
_ FilesManager = (*Record)(nil)
|
||||
)
|
||||
|
||||
type Record struct {
|
||||
BaseModel
|
||||
|
||||
collection *Collection
|
||||
data map[string]any
|
||||
expand map[string]any
|
||||
|
||||
exportUnknown bool // whether to export unknown fields
|
||||
ignoreEmailVisibility bool // whether to ignore the emailVisibility flag for auth collections
|
||||
data map[string]any // any custom data in addition to the base model fields
|
||||
expand map[string]any // expanded relations
|
||||
}
|
||||
|
||||
// NewRecord initializes a new empty Record model.
|
||||
@@ -34,34 +40,43 @@ func NewRecord(collection *Collection) *Record {
|
||||
}
|
||||
}
|
||||
|
||||
// nullStringMapValue returns the raw string value if it exist and
|
||||
// its not NULL, otherwise - nil.
|
||||
func nullStringMapValue(data dbx.NullStringMap, key string) any {
|
||||
nullString, ok := data[key]
|
||||
|
||||
if ok && nullString.Valid {
|
||||
return nullString.String
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// NewRecordFromNullStringMap initializes a single new Record model
|
||||
// with data loaded from the provided NullStringMap.
|
||||
func NewRecordFromNullStringMap(collection *Collection, data dbx.NullStringMap) *Record {
|
||||
resultMap := map[string]any{}
|
||||
|
||||
// load schema fields
|
||||
for _, field := range collection.Schema.Fields() {
|
||||
var rawValue any
|
||||
resultMap[field.Name] = nullStringMapValue(data, field.Name)
|
||||
}
|
||||
|
||||
nullString, ok := data[field.Name]
|
||||
if !ok || !nullString.Valid {
|
||||
rawValue = nil
|
||||
} else {
|
||||
rawValue = nullString.String
|
||||
// load base model fields
|
||||
for _, name := range schema.BaseModelFieldNames() {
|
||||
resultMap[name] = nullStringMapValue(data, name)
|
||||
}
|
||||
|
||||
// load auth fields
|
||||
if collection.IsAuth() {
|
||||
for _, name := range schema.AuthFieldNames() {
|
||||
resultMap[name] = nullStringMapValue(data, name)
|
||||
}
|
||||
|
||||
resultMap[field.Name] = rawValue
|
||||
}
|
||||
|
||||
record := NewRecord(collection)
|
||||
|
||||
// load base mode fields
|
||||
resultMap[schema.ReservedFieldNameId] = data[schema.ReservedFieldNameId].String
|
||||
resultMap[schema.ReservedFieldNameCreated] = data[schema.ReservedFieldNameCreated].String
|
||||
resultMap[schema.ReservedFieldNameUpdated] = data[schema.ReservedFieldNameUpdated].String
|
||||
|
||||
if err := record.Load(resultMap); err != nil {
|
||||
log.Println("Failed to unmarshal record:", err)
|
||||
}
|
||||
record.Load(resultMap)
|
||||
|
||||
return record
|
||||
}
|
||||
@@ -88,77 +103,150 @@ func (m *Record) Collection() *Collection {
|
||||
return m.collection
|
||||
}
|
||||
|
||||
// GetExpand returns a shallow copy of the optional `expand` data
|
||||
// Expand returns a shallow copy of the record.expand data
|
||||
// attached to the current Record model.
|
||||
func (m *Record) GetExpand() map[string]any {
|
||||
func (m *Record) Expand() map[string]any {
|
||||
return shallowCopy(m.expand)
|
||||
}
|
||||
|
||||
// SetExpand assigns the provided data to `record.expand`.
|
||||
func (m *Record) SetExpand(data map[string]any) {
|
||||
m.expand = shallowCopy(data)
|
||||
// SetExpand assigns the provided data to record.expand.
|
||||
func (m *Record) SetExpand(expand map[string]any) {
|
||||
m.expand = shallowCopy(expand)
|
||||
}
|
||||
|
||||
// Data returns a shallow copy of the currently loaded record's data.
|
||||
func (m *Record) Data() map[string]any {
|
||||
return shallowCopy(m.data)
|
||||
}
|
||||
// SchemaData returns a shallow copy ONLY of the defined record schema fields data.
|
||||
func (m *Record) SchemaData() map[string]any {
|
||||
result := map[string]any{}
|
||||
|
||||
// SetDataValue sets the provided key-value data pair for the current Record model.
|
||||
//
|
||||
// This method does nothing if the record doesn't have a `key` field.
|
||||
func (m *Record) SetDataValue(key string, value any) {
|
||||
if m.data == nil {
|
||||
m.data = map[string]any{}
|
||||
for _, field := range m.collection.Schema.Fields() {
|
||||
if v, ok := m.data[field.Name]; ok {
|
||||
result[field.Name] = v
|
||||
}
|
||||
}
|
||||
|
||||
field := m.Collection().Schema.GetFieldByName(key)
|
||||
if field != nil {
|
||||
m.data[key] = field.PrepareValue(value)
|
||||
return result
|
||||
}
|
||||
|
||||
// UnknownData returns a shallow copy ONLY of the unknown record fields data,
|
||||
// aka. fields that are neither one of the base and special system ones,
|
||||
// nor defined by the collection schema.
|
||||
func (m *Record) UnknownData() map[string]any {
|
||||
return m.extractUnknownData(m.data)
|
||||
}
|
||||
|
||||
// IgnoreEmailVisibility toggles the flag to ignore the auth record email visibility check.
|
||||
func (m *Record) IgnoreEmailVisibility(state bool) {
|
||||
m.ignoreEmailVisibility = state
|
||||
}
|
||||
|
||||
// WithUnkownData toggles the export/serialization of unknown data fields
|
||||
// (false by default).
|
||||
func (m *Record) WithUnkownData(state bool) {
|
||||
m.exportUnknown = state
|
||||
}
|
||||
|
||||
// Set sets the provided key-value data pair for the current Record model.
|
||||
//
|
||||
// If the record collection has field with name matching the provided "key",
|
||||
// the value will be further normalized according to the field rules.
|
||||
func (m *Record) Set(key string, value any) {
|
||||
switch key {
|
||||
case schema.FieldNameId:
|
||||
m.Id = cast.ToString(value)
|
||||
case schema.FieldNameCreated:
|
||||
m.Created, _ = types.ParseDateTime(value)
|
||||
case schema.FieldNameUpdated:
|
||||
m.Updated, _ = types.ParseDateTime(value)
|
||||
case schema.FieldNameExpand:
|
||||
m.SetExpand(cast.ToStringMap(value))
|
||||
default:
|
||||
var v = value
|
||||
|
||||
if field := m.Collection().Schema.GetFieldByName(key); field != nil {
|
||||
v = field.PrepareValue(value)
|
||||
} else if m.collection.IsAuth() {
|
||||
// normalize auth fields
|
||||
switch key {
|
||||
case schema.FieldNameEmailVisibility, schema.FieldNameVerified:
|
||||
v = cast.ToBool(value)
|
||||
case schema.FieldNameLastResetSentAt, schema.FieldNameLastVerificationSentAt:
|
||||
v, _ = types.ParseDateTime(value)
|
||||
case schema.FieldNameUsername, schema.FieldNameEmail, schema.FieldNameTokenKey, schema.FieldNamePasswordHash:
|
||||
v = cast.ToString(value)
|
||||
}
|
||||
}
|
||||
|
||||
if m.data == nil {
|
||||
m.data = map[string]any{}
|
||||
}
|
||||
|
||||
m.data[key] = v
|
||||
}
|
||||
}
|
||||
|
||||
// GetDataValue returns the current record's data value for `key`.
|
||||
//
|
||||
// Returns nil if data value with `key` is not found or set.
|
||||
func (m *Record) GetDataValue(key string) any {
|
||||
return m.data[key]
|
||||
// Get returns a single record model data value for "key".
|
||||
func (m *Record) Get(key string) any {
|
||||
switch key {
|
||||
case schema.FieldNameId:
|
||||
return m.Id
|
||||
case schema.FieldNameCreated:
|
||||
return m.Created
|
||||
case schema.FieldNameUpdated:
|
||||
return m.Updated
|
||||
default:
|
||||
if v, ok := m.data[key]; ok {
|
||||
return v
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
// GetBoolDataValue returns the data value for `key` as a bool.
|
||||
func (m *Record) GetBoolDataValue(key string) bool {
|
||||
return cast.ToBool(m.GetDataValue(key))
|
||||
// GetBool returns the data value for "key" as a bool.
|
||||
func (m *Record) GetBool(key string) bool {
|
||||
return cast.ToBool(m.Get(key))
|
||||
}
|
||||
|
||||
// GetStringDataValue returns the data value for `key` as a string.
|
||||
func (m *Record) GetStringDataValue(key string) string {
|
||||
return cast.ToString(m.GetDataValue(key))
|
||||
// GetString returns the data value for "key" as a string.
|
||||
func (m *Record) GetString(key string) string {
|
||||
return cast.ToString(m.Get(key))
|
||||
}
|
||||
|
||||
// GetIntDataValue returns the data value for `key` as an int.
|
||||
func (m *Record) GetIntDataValue(key string) int {
|
||||
return cast.ToInt(m.GetDataValue(key))
|
||||
// GetInt returns the data value for "key" as an int.
|
||||
func (m *Record) GetInt(key string) int {
|
||||
return cast.ToInt(m.Get(key))
|
||||
}
|
||||
|
||||
// GetFloatDataValue returns the data value for `key` as a float64.
|
||||
func (m *Record) GetFloatDataValue(key string) float64 {
|
||||
return cast.ToFloat64(m.GetDataValue(key))
|
||||
// GetFloat returns the data value for "key" as a float64.
|
||||
func (m *Record) GetFloat(key string) float64 {
|
||||
return cast.ToFloat64(m.Get(key))
|
||||
}
|
||||
|
||||
// GetTimeDataValue returns the data value for `key` as a [time.Time] instance.
|
||||
func (m *Record) GetTimeDataValue(key string) time.Time {
|
||||
return cast.ToTime(m.GetDataValue(key))
|
||||
// GetTime returns the data value for "key" as a [time.Time] instance.
|
||||
func (m *Record) GetTime(key string) time.Time {
|
||||
return cast.ToTime(m.Get(key))
|
||||
}
|
||||
|
||||
// GetDateTimeDataValue returns the data value for `key` as a DateTime instance.
|
||||
func (m *Record) GetDateTimeDataValue(key string) types.DateTime {
|
||||
d, _ := types.ParseDateTime(m.GetDataValue(key))
|
||||
// GetDateTime returns the data value for "key" as a DateTime instance.
|
||||
func (m *Record) GetDateTime(key string) types.DateTime {
|
||||
d, _ := types.ParseDateTime(m.Get(key))
|
||||
return d
|
||||
}
|
||||
|
||||
// GetStringSliceDataValue returns the data value for `key` as a slice of unique strings.
|
||||
func (m *Record) GetStringSliceDataValue(key string) []string {
|
||||
return list.ToUniqueStringSlice(m.GetDataValue(key))
|
||||
// GetStringSlice returns the data value for "key" as a slice of unique strings.
|
||||
func (m *Record) GetStringSlice(key string) []string {
|
||||
return list.ToUniqueStringSlice(m.Get(key))
|
||||
}
|
||||
|
||||
// Retrieves the "key" json field value and unmarshals it into "result".
|
||||
//
|
||||
// Example
|
||||
// result := struct {
|
||||
// FirstName string `json:"first_name"`
|
||||
// }{}
|
||||
// err := m.UnmarshalJSONField("my_field_name", &result)
|
||||
func (m *Record) UnmarshalJSONField(key string, result any) error {
|
||||
return json.Unmarshal([]byte(m.GetString(key)), &result)
|
||||
}
|
||||
|
||||
// BaseFilesPath returns the storage dir path used by the record.
|
||||
@@ -171,7 +259,7 @@ func (m *Record) BaseFilesPath() string {
|
||||
func (m *Record) FindFileFieldByFile(filename string) *schema.SchemaField {
|
||||
for _, field := range m.Collection().Schema.Fields() {
|
||||
if field.Type == schema.FieldTypeFile {
|
||||
names := m.GetStringSliceDataValue(field.Name)
|
||||
names := m.GetStringSlice(field.Name)
|
||||
if list.ExistInSlice(filename, names) {
|
||||
return field
|
||||
}
|
||||
@@ -181,63 +269,76 @@ func (m *Record) FindFileFieldByFile(filename string) *schema.SchemaField {
|
||||
}
|
||||
|
||||
// Load bulk loads the provided data into the current Record model.
|
||||
func (m *Record) Load(data map[string]any) error {
|
||||
if data[schema.ReservedFieldNameId] != nil {
|
||||
id, err := cast.ToStringE(data[schema.ReservedFieldNameId])
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
m.Id = id
|
||||
}
|
||||
|
||||
if data[schema.ReservedFieldNameCreated] != nil {
|
||||
m.Created, _ = types.ParseDateTime(data[schema.ReservedFieldNameCreated])
|
||||
}
|
||||
|
||||
if data[schema.ReservedFieldNameUpdated] != nil {
|
||||
m.Updated, _ = types.ParseDateTime(data[schema.ReservedFieldNameUpdated])
|
||||
}
|
||||
|
||||
func (m *Record) Load(data map[string]any) {
|
||||
for k, v := range data {
|
||||
m.SetDataValue(k, v)
|
||||
m.Set(k, v)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// ColumnValueMap implements [ColumnValueMapper] interface.
|
||||
func (m *Record) ColumnValueMap() map[string]any {
|
||||
result := map[string]any{}
|
||||
for key := range m.data {
|
||||
result[key] = m.normalizeDataValueForDB(key)
|
||||
|
||||
// export schema field values
|
||||
for _, field := range m.collection.Schema.Fields() {
|
||||
result[field.Name] = m.getNormalizeDataValueForDB(field.Name)
|
||||
}
|
||||
|
||||
// set base model fields
|
||||
result[schema.ReservedFieldNameId] = m.Id
|
||||
result[schema.ReservedFieldNameCreated] = m.Created
|
||||
result[schema.ReservedFieldNameUpdated] = m.Updated
|
||||
// export auth collection fields
|
||||
if m.collection.IsAuth() {
|
||||
for _, name := range schema.AuthFieldNames() {
|
||||
result[name] = m.getNormalizeDataValueForDB(name)
|
||||
}
|
||||
}
|
||||
|
||||
// export base model fields
|
||||
result[schema.FieldNameId] = m.getNormalizeDataValueForDB(schema.FieldNameId)
|
||||
result[schema.FieldNameCreated] = m.getNormalizeDataValueForDB(schema.FieldNameCreated)
|
||||
result[schema.FieldNameUpdated] = m.getNormalizeDataValueForDB(schema.FieldNameUpdated)
|
||||
|
||||
return result
|
||||
}
|
||||
|
||||
// PublicExport exports only the record fields that are safe to be public.
|
||||
//
|
||||
// This method also skips the "hidden" fields, aka. fields prefixed with `#`.
|
||||
// Fields marked as hidden will be exported only if `m.IgnoreEmailVisibility(true)` is set.
|
||||
func (m *Record) PublicExport() map[string]any {
|
||||
result := skipHiddenFields(m.data)
|
||||
result := map[string]any{}
|
||||
|
||||
// set base model fields
|
||||
result[schema.ReservedFieldNameId] = m.Id
|
||||
result[schema.ReservedFieldNameCreated] = m.Created
|
||||
result[schema.ReservedFieldNameUpdated] = m.Updated
|
||||
// export unknown data fields if allowed
|
||||
if m.exportUnknown {
|
||||
for k, v := range m.UnknownData() {
|
||||
result[k] = v
|
||||
}
|
||||
}
|
||||
|
||||
// add helper collection fields
|
||||
result["@collectionId"] = m.collection.Id
|
||||
result["@collectionName"] = m.collection.Name
|
||||
// export schema field values
|
||||
for _, field := range m.collection.Schema.Fields() {
|
||||
result[field.Name] = m.Get(field.Name)
|
||||
}
|
||||
|
||||
// export some of the safe auth collection fields
|
||||
if m.collection.IsAuth() {
|
||||
result[schema.FieldNameVerified] = m.Verified()
|
||||
result[schema.FieldNameUsername] = m.Username()
|
||||
result[schema.FieldNameEmailVisibility] = m.EmailVisibility()
|
||||
if m.ignoreEmailVisibility || m.EmailVisibility() {
|
||||
result[schema.FieldNameEmail] = m.Email()
|
||||
}
|
||||
}
|
||||
|
||||
// export base model fields
|
||||
result[schema.FieldNameId] = m.GetId()
|
||||
result[schema.FieldNameCreated] = m.GetCreated()
|
||||
result[schema.FieldNameUpdated] = m.GetUpdated()
|
||||
|
||||
// add helper collection reference fields
|
||||
result[schema.FieldNameCollectionId] = m.collection.Id
|
||||
result[schema.FieldNameCollectionName] = m.collection.Name
|
||||
|
||||
// add expand (if set)
|
||||
if m.expand != nil {
|
||||
result["@expand"] = m.expand
|
||||
result[schema.FieldNameExpand] = m.expand
|
||||
}
|
||||
|
||||
return result
|
||||
@@ -258,19 +359,41 @@ func (m *Record) UnmarshalJSON(data []byte) error {
|
||||
return err
|
||||
}
|
||||
|
||||
return m.Load(result)
|
||||
m.Load(result)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// normalizeDataValueForDB returns the `key` data value formatted for db storage.
|
||||
func (m *Record) normalizeDataValueForDB(key string) any {
|
||||
val := m.GetDataValue(key)
|
||||
// getNormalizeDataValueForDB returns the "key" data value formatted for db storage.
|
||||
func (m *Record) getNormalizeDataValueForDB(key string) any {
|
||||
var val any
|
||||
|
||||
// normalize auth fields
|
||||
if m.collection.IsAuth() {
|
||||
switch key {
|
||||
case schema.FieldNameEmailVisibility, schema.FieldNameVerified:
|
||||
return m.GetBool(key)
|
||||
case schema.FieldNameLastResetSentAt, schema.FieldNameLastVerificationSentAt:
|
||||
return m.GetDateTime(key)
|
||||
case schema.FieldNameUsername, schema.FieldNameEmail, schema.FieldNameTokenKey, schema.FieldNamePasswordHash:
|
||||
return m.GetString(key)
|
||||
}
|
||||
}
|
||||
|
||||
val = m.Get(key)
|
||||
|
||||
switch ids := val.(type) {
|
||||
case []string:
|
||||
// encode strings slice
|
||||
// encode string slice
|
||||
return append(types.JsonArray{}, list.ToInterfaceSlice(ids)...)
|
||||
case []int:
|
||||
// encode int slice
|
||||
return append(types.JsonArray{}, list.ToInterfaceSlice(ids)...)
|
||||
case []float64:
|
||||
// encode float64 slice
|
||||
return append(types.JsonArray{}, list.ToInterfaceSlice(ids)...)
|
||||
case []any:
|
||||
// encode interfaces slice
|
||||
// encode interface slice
|
||||
return append(types.JsonArray{}, ids...)
|
||||
default:
|
||||
// no changes
|
||||
@@ -289,17 +412,218 @@ func shallowCopy(data map[string]any) map[string]any {
|
||||
return result
|
||||
}
|
||||
|
||||
// skipHiddenFields returns a new data map without the "#" prefixed fields.
|
||||
func skipHiddenFields(data map[string]any) map[string]any {
|
||||
func (m *Record) extractUnknownData(data map[string]any) map[string]any {
|
||||
knownFields := map[string]struct{}{}
|
||||
|
||||
for _, name := range schema.SystemFieldNames() {
|
||||
knownFields[name] = struct{}{}
|
||||
}
|
||||
for _, name := range schema.BaseModelFieldNames() {
|
||||
knownFields[name] = struct{}{}
|
||||
}
|
||||
|
||||
for _, f := range m.collection.Schema.Fields() {
|
||||
knownFields[f.Name] = struct{}{}
|
||||
}
|
||||
|
||||
if m.collection.IsAuth() {
|
||||
for _, name := range schema.AuthFieldNames() {
|
||||
knownFields[name] = struct{}{}
|
||||
}
|
||||
}
|
||||
|
||||
result := map[string]any{}
|
||||
|
||||
for key, val := range data {
|
||||
// ignore "#" prefixed fields
|
||||
if strings.HasPrefix(key, "#") {
|
||||
continue
|
||||
for k, v := range m.data {
|
||||
if _, ok := knownFields[k]; !ok {
|
||||
result[k] = v
|
||||
}
|
||||
result[key] = val
|
||||
}
|
||||
|
||||
return result
|
||||
}
|
||||
|
||||
// -------------------------------------------------------------------
|
||||
// Auth helpers
|
||||
// -------------------------------------------------------------------
|
||||
|
||||
var notAuthRecordErr = errors.New("Not an auth collection record.")
|
||||
|
||||
// Username returns the "username" auth record data value.
|
||||
func (m *Record) Username() string {
|
||||
return m.GetString(schema.FieldNameUsername)
|
||||
}
|
||||
|
||||
// SetUsername sets the "username" auth record data value.
|
||||
//
|
||||
// This method doesn't check whether the provided value is a valid username.
|
||||
//
|
||||
// Returns an error if the record is not from an auth collection.
|
||||
func (m *Record) SetUsername(username string) error {
|
||||
if !m.collection.IsAuth() {
|
||||
return notAuthRecordErr
|
||||
}
|
||||
|
||||
m.Set(schema.FieldNameUsername, username)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// Email returns the "email" auth record data value.
|
||||
func (m *Record) Email() string {
|
||||
return m.GetString(schema.FieldNameEmail)
|
||||
}
|
||||
|
||||
// SetEmail sets the "email" auth record data value.
|
||||
//
|
||||
// This method doesn't check whether the provided value is a valid email.
|
||||
//
|
||||
// Returns an error if the record is not from an auth collection.
|
||||
func (m *Record) SetEmail(email string) error {
|
||||
if !m.collection.IsAuth() {
|
||||
return notAuthRecordErr
|
||||
}
|
||||
|
||||
m.Set(schema.FieldNameEmail, email)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// Verified returns the "emailVisibility" auth record data value.
|
||||
func (m *Record) EmailVisibility() bool {
|
||||
return m.GetBool(schema.FieldNameEmailVisibility)
|
||||
}
|
||||
|
||||
// SetEmailVisibility sets the "emailVisibility" auth record data value.
|
||||
//
|
||||
// Returns an error if the record is not from an auth collection.
|
||||
func (m *Record) SetEmailVisibility(visible bool) error {
|
||||
if !m.collection.IsAuth() {
|
||||
return notAuthRecordErr
|
||||
}
|
||||
|
||||
m.Set(schema.FieldNameEmailVisibility, visible)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// Verified returns the "verified" auth record data value.
|
||||
func (m *Record) Verified() bool {
|
||||
return m.GetBool(schema.FieldNameVerified)
|
||||
}
|
||||
|
||||
// SetVerified sets the "verified" auth record data value.
|
||||
//
|
||||
// Returns an error if the record is not from an auth collection.
|
||||
func (m *Record) SetVerified(verified bool) error {
|
||||
if !m.collection.IsAuth() {
|
||||
return notAuthRecordErr
|
||||
}
|
||||
|
||||
m.Set(schema.FieldNameVerified, verified)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// TokenKey returns the "tokenKey" auth record data value.
|
||||
func (m *Record) TokenKey() string {
|
||||
return m.GetString(schema.FieldNameTokenKey)
|
||||
}
|
||||
|
||||
// SetTokenKey sets the "tokenKey" auth record data value.
|
||||
//
|
||||
// Returns an error if the record is not from an auth collection.
|
||||
func (m *Record) SetTokenKey(key string) error {
|
||||
if !m.collection.IsAuth() {
|
||||
return notAuthRecordErr
|
||||
}
|
||||
|
||||
m.Set(schema.FieldNameTokenKey, key)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// RefreshTokenKey generates and sets new random auth record "tokenKey".
|
||||
//
|
||||
// Returns an error if the record is not from an auth collection.
|
||||
func (m *Record) RefreshTokenKey() error {
|
||||
return m.SetTokenKey(security.RandomString(50))
|
||||
}
|
||||
|
||||
// LastResetSentAt returns the "lastResentSentAt" auth record data value.
|
||||
func (m *Record) LastResetSentAt() types.DateTime {
|
||||
return m.GetDateTime(schema.FieldNameLastResetSentAt)
|
||||
}
|
||||
|
||||
// SetLastResetSentAt sets the "lastResentSentAt" auth record data value.
|
||||
//
|
||||
// Returns an error if the record is not from an auth collection.
|
||||
func (m *Record) SetLastResetSentAt(dateTime types.DateTime) error {
|
||||
if !m.collection.IsAuth() {
|
||||
return notAuthRecordErr
|
||||
}
|
||||
|
||||
m.Set(schema.FieldNameLastResetSentAt, dateTime)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// LastVerificationSentAt returns the "lastVerificationSentAt" auth record data value.
|
||||
func (m *Record) LastVerificationSentAt() types.DateTime {
|
||||
return m.GetDateTime(schema.FieldNameLastVerificationSentAt)
|
||||
}
|
||||
|
||||
// SetLastVerificationSentAt sets an "lastVerificationSentAt" auth record data value.
|
||||
//
|
||||
// Returns an error if the record is not from an auth collection.
|
||||
func (m *Record) SetLastVerificationSentAt(dateTime types.DateTime) error {
|
||||
if !m.collection.IsAuth() {
|
||||
return notAuthRecordErr
|
||||
}
|
||||
|
||||
m.Set(schema.FieldNameLastVerificationSentAt, dateTime)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// ValidatePassword validates a plain password against the auth record password.
|
||||
//
|
||||
// Returns false if the password is incorrect or record is not from an auth collection.
|
||||
func (m *Record) ValidatePassword(password string) bool {
|
||||
if !m.collection.IsAuth() {
|
||||
return false
|
||||
}
|
||||
|
||||
err := bcrypt.CompareHashAndPassword(
|
||||
[]byte(m.GetString(schema.FieldNamePasswordHash)),
|
||||
[]byte(password),
|
||||
)
|
||||
return err == nil
|
||||
}
|
||||
|
||||
// SetPassword sets cryptographically secure string to the auth record "password" field.
|
||||
// This method also resets the "lastResetSentAt" and the "tokenKey" fields.
|
||||
//
|
||||
// Returns an error if the record is not from an auth collection or
|
||||
// an empty password is provided.
|
||||
func (m *Record) SetPassword(password string) error {
|
||||
if !m.collection.IsAuth() {
|
||||
return notAuthRecordErr
|
||||
}
|
||||
|
||||
if password == "" {
|
||||
return errors.New("The provided plain password is empty")
|
||||
}
|
||||
|
||||
// hash the password
|
||||
hashedPassword, err := bcrypt.GenerateFromPassword([]byte(password), 13)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
m.Set(schema.FieldNamePasswordHash, string(hashedPassword))
|
||||
m.Set(schema.FieldNameLastResetSentAt, types.DateTime{})
|
||||
|
||||
// invalidate previously issued tokens
|
||||
return m.RefreshTokenKey()
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user