ds

package
v0.0.0-...-7b21f04 Latest Latest
Warning

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

Go to latest
Published: Feb 27, 2026 License: MIT Imports: 17 Imported by: 0

Documentation

Overview

Package ds (Data Structure) All data models belonging to the app are stored here. Global functions should not be created here. Methods on types are welcome.

Index

Constants

View Source
const (
	// PerPageNoLimit disables pagination limits and returns all records.
	PerPageNoLimit = -1

	// PerPageDefault defines the default number of records per page
	// when no explicit per-page value is provided.
	PerPageDefault = 25

	// PerPageMax defines the maximum allowed number of records per page
	// to prevent excessive result sizes.
	PerPageMax = 100
)
View Source
const (
	// DeleteTempFilesAfterDays defines how long temporary files
	// are kept before being eligible for deletion.
	DeleteTempFilesAfterDays = 5

	// CleanupDeletedFilesAfterDays defines how long soft-deleted files
	// are kept before permanent cleanup.
	CleanupDeletedFilesAfterDays = 5
)
View Source
const (
	// CleanupDeletedEntitiesAfterDays defines how long soft-deleted entities
	// are kept before permanent cleanup.
	CleanupDeletedEntitiesAfterDays = 10
)
View Source
const (

	// CleanupDeletedUserAfter ...
	CleanupDeletedUserAfter = 30 * 24 * time.Hour
)

Variables

EntityStatuses defines the list of valid entity statuses.

EntityTypes lists all supported entity types.

EntityVisibilities defines the list of all supported entity visibility values.

View Source
var ErrInvalidIDFormat = errors.New("invalid UUID format")

ErrInvalidIDFormat indicates that a provided ID string is not a valid UUID format.

EventLogTypes lists all supported event log types.

View Source
var IDInputRules = z.CustomFunc(func(val *ID, _ z.Ctx) bool {
	if val == nil || *val == NilID {
		return false
	}

	return true
}, z.Message("Invalid UUID"))

IDInputRules ...

View Source
var NilID = ID(uuid.Nil)

NilID is an empty UUID, all zeros.

View Source
var ReleaseDateLayouts = []string{
	"2006",
	"January 2006",
	"January 2, 2006",
}

ReleaseDateLayouts defines the allowed date layouts for formatting book release dates.

Functions

This section is empty.

Types

type AuthToken

type AuthToken struct {
	ID         ID
	UserID     int64
	User       *User
	ClientName string
	ClientIP   string
	UserAgent  string
	Token      string
	CreatedAt  time.Time
	ExpiresAt  time.Time
}

AuthToken represents container for authentication-related data.

type Book

type Book struct {
	*Entity

	DescriptionRaw string       `json:"-"`
	Description    string       `json:"description"`
	CoverFileID    ID           `json:"cover_file_id"`
	Authors        []BookAuthor `json:"authors"`
	Homepage       string       `json:"homepage"`
	ReleaseDate    string       `json:"release_date"`
}

Book defines the data structure for a book.

func BookFromContext

func BookFromContext(ctx context.Context) *Book

BookFromContext attempts to retrieve book object from the context.

func (*Book) CreateRules

func (b *Book) CreateRules() z.Shape

CreateRules provides the validation map used when saving a new book.

func (*Book) Data

func (b *Book) Data() map[string]any

Data returns the editable fields of the Book as a key-value map.

func (*Book) PropertyType

func (b *Book) PropertyType(key string) prop.Type

PropertyType returns the property type for a given key.

func (*Book) ToContext

func (b *Book) ToContext(ctx context.Context) context.Context

ToContext adds the given book object to the provided context.

func (*Book) UpdateRules

func (b *Book) UpdateRules() z.Shape

UpdateRules provides the validation map used when editing an existing book.

type BookAuthor

type BookAuthor struct {
	Name string `json:"name"`
	Link string `json:"link"`
}

BookAuthor represents an author of a book.

type BooksFilter

type BooksFilter struct {
	EntitiesFilter
}

BooksFilter is used to filter and paginate user queries.

type ChangeEmailRequest

type ChangeEmailRequest struct {
	ID        ID        `json:"-"`
	UserID    ID        `json:"-"`
	NewEmail  string    `json:"-"`
	Token     string    `json:"-"`
	ExpiresAt time.Time `json:"-"`
	CreatedAt time.Time `json:"-"`
}

ChangeEmailRequest represents a record in the change_email_requests table. It stores a single-use token for a user to confirm a change to their email address.

func (*ChangeEmailRequest) Invalid

func (r *ChangeEmailRequest) Invalid() bool

Invalid returns true if token has expired.

type ChangeRequestsFilter

type ChangeRequestsFilter struct {
	Page      int
	PerPage   int
	Status    EntityChangeStatus
	WithCount bool
}

ChangeRequestsFilter is used to filter and paginate change requests.

type DataProvider

type DataProvider interface {
	Data() map[string]any
	PropertyType(key string) prop.Type
}

DataProvider exposes entity data in a generic key-value form.

It is used to extract mutable fields of an entity for diffing, change requests, and edit workflows.

type EmailConfirmation

type EmailConfirmation struct {
	ID          ID
	UserID      ID
	Code        string
	CreatedAt   time.Time
	ExpiresAt   time.Time
	ConfirmedAt *time.Time
}

EmailConfirmation represents a record used to verify a user's email address after registration or a change request.

func (*EmailConfirmation) Invalid

func (c *EmailConfirmation) Invalid() bool

Invalid checks if the confirmation record is expired. Returns true if the token is no longer valid, false otherwise.

type EntitiesFilter

type EntitiesFilter struct {
	Page           int
	PerPage        int
	WithCount      bool
	CreatedAt      *FilterDT
	DeletedAt      *FilterDT
	Deleted        bool
	Title          *FilterString
	Visibility     []EntityVisibility
	Status         []EntityStatus
	Topics         []string
	OrderBy        string
	OrderDirection string
}

EntitiesFilter is used to filter entities.

type Entity

type Entity struct {
	ID            ID               `json:"id"`
	PublicID      string           `json:"public_id"`
	OwnerID       ID               `json:"-"`
	PreviewFileID ID               `json:"preview_file_id"`
	Type          EntityType       `json:"-"`
	Title         string           `json:"title"`
	SummaryRaw    string           `json:"-"`
	Summary       string           `json:"summary"`
	Status        EntityStatus     `json:"status"`
	Visibility    EntityVisibility `json:"visibility"`
	PublishedAt   *time.Time       `json:"published_at,omitempty"`
	CreatedAt     time.Time        `json:"created_at"`
	UpdatedAt     *time.Time       `json:"updated_at,omitempty"`
	DeletedAt     *time.Time       `json:"-"`

	Topics []Topic `json:"topics"`
	Owner  *string `db:"owner" json:"owner,omitempty"`
}

Entity represents the base metadata for any user-content in the system.

func (*Entity) CreateRules

func (e *Entity) CreateRules() z.Shape

CreateRules returns the validation schema for creating a new entity.

func (*Entity) Data

func (e *Entity) Data() map[string]any

Data returns the editable fields of the Book as a key-value map.

func (*Entity) PropertyType

func (e *Entity) PropertyType(key string) prop.Type

PropertyType returns the property type for a given key.

func (*Entity) SetPublicID

func (e *Entity) SetPublicID()

SetPublicID ensures that the entity has a non-empty, human-readable PublicID. If it cannot be derived from the Title, it falls back to "{type}_{shortuuid}".

func (*Entity) UpdateRules

func (e *Entity) UpdateRules() z.Shape

UpdateRules returns the validation schema for updating an existing entity.

func (*Entity) ViewURL

func (e *Entity) ViewURL() string

ViewURL returns the public-facing URL path for viewing the entity.

func (*Entity) WithEntityData

func (e *Entity) WithEntityData(data map[string]any) map[string]any

WithEntityData merges the provided data map with the entity's existing data and returns the combined result.

type EntityChangeRequest

type EntityChangeRequest struct {
	ID       ID                 `json:"id"`
	EntityID ID                 `json:"entity_id,omitzero"`
	UserID   ID                 `json:"user_id,omitzero"`
	Status   EntityChangeStatus `json:"status"`

	// Diff contains the proposed changes.
	Diff map[string]any `json:"diff"`

	Message    string     `json:"message,omitempty"`
	Revision   int        `json:"revision"`
	ReviewerID *ID        `json:"reviewer_id,omitempty"`
	ReviewedAt *time.Time `json:"reviewed_at,omitempty"`
	ReviewNote string     `json:"review_note,omitempty"`
	CreatedAt  time.Time  `json:"created_at"`
	UpdatedAt  *time.Time `json:"updated_at"`

	// props needed to be returned from filter action
	Username       string     `json:"username"`
	EntityType     EntityType `json:"entity_type"`
	EntityTitle    string     `json:"entity_title"`
	EntityPublicID string     `json:"entity_public_id"`
}

EntityChangeRequest describes a user's requested changes to an entity.

type EntityChangeStatus

type EntityChangeStatus string

EntityChangeStatus represents the lifecycle state of an entity change request.

const (
	// EntityChangePending indicates a change request awaiting review.
	EntityChangePending EntityChangeStatus = "pending"

	// EntityChangeCommitted indicates an approved and applied change request.
	EntityChangeCommitted EntityChangeStatus = "committed"

	// EntityChangeRejected indicates a change request that was reviewed and rejected.
	EntityChangeRejected EntityChangeStatus = "rejected"
)

type EntityStatus

type EntityStatus string

EntityStatus defines the moderation state of an entity.

const (
	// EntityStatusUnderReview means the entity is awaiting moderation.
	EntityStatusUnderReview EntityStatus = "review"

	// EntityStatusApproved means the entity is live and approved.
	EntityStatusApproved EntityStatus = "approved"

	// EntityStatusRejected means the entity failed moderation.
	EntityStatusRejected EntityStatus = "rejected"
)

func (EntityStatus) Is

func (v EntityStatus) Is(v2 ...EntityStatus) bool

Is reports whether the status matches any of the provided values.

func (EntityStatus) Not

func (v EntityStatus) Not(v2 ...EntityStatus) bool

Not reports whether the status does not match any of the provided values.

func (EntityStatus) Valid

func (v EntityStatus) Valid() bool

Valid reports whether the status value is one of the supported entity statuses.

type EntityTopic

type EntityTopic struct {
	Topic

	EntityID ID `json:"-"`
	TopicID  ID `json:"-"`
}

EntityTopic links an entity to a topic (many-to-many).

type EntityType

type EntityType string

EntityType defines the type of the entity content.

const (
	EntityTypeBook EntityType = "book"
	EntityTypePage EntityType = "page"
)

Supported entity types.

func (EntityType) Valid

func (t EntityType) Valid() bool

Valid reports whether the entity type is supported.

type EntityVisibility

type EntityVisibility string

EntityVisibility controls how the entity is accessed in listings and search results.

const (

	// EntityVisibilityPublic means the entity is visible to everyone and indexed.
	EntityVisibilityPublic EntityVisibility = "public"

	// EntityVisibilityPrivate means the entity is restricted to the owner and collaborators.
	EntityVisibilityPrivate EntityVisibility = "private"

	// EntityVisibilityUnlisted means the entity is accessible only via direct link.
	EntityVisibilityUnlisted EntityVisibility = "unlisted"
)

func (EntityVisibility) Is

Is reports whether the visibility matches any of the provided values.

func (EntityVisibility) Not

func (v EntityVisibility) Not(v2 ...EntityVisibility) bool

Not reports whether the visibility does not match any of the provided values.

func (EntityVisibility) Valid

func (v EntityVisibility) Valid() bool

Valid reports whether the visibility value is one of the supported visibilities.

type EventLog

type EventLog struct {
	ID           ID      `json:"id"`
	UserID       *ID     `json:"user_id"`
	UserUsername *string `json:"-"`

	Type EventLogType `json:"action_type"`

	EntityID       *ID         `json:"entity_id"`
	EntityType     *EntityType `json:"-"`
	EntityTitle    *string     `json:"-"`
	EntityPublicID *string     `json:"-"`
	EntityChangeID *ID         `json:"entity_change_id"`

	// Message is an optional pre-rendered text for the event.
	// When set, it takes precedence over automatically generated messages.
	// This is primarily used for system events.
	Message string `json:"message"`

	// Meta holds custom data relevant to log
	Meta map[string]any `json:"-"`

	IsPublic  bool      `json:"is_public"`
	CreatedAt time.Time `json:"created_at"`
}

EventLog represents a single event entry used for activity feeds, audits, and system transparency.

func (EventLog) RenderMessage

func (l EventLog) RenderMessage() string

RenderMessage builds a human-readable, public-facing description of the event.

The message format is {user} {verb} [{entityType} "{title}"] e.g.

  • ognev.dev created book "Hello world"
  • ognev.dev joined

If Message is explicitly set, it is returned as-is. This is primarily used for system events where the text cannot be reliably derived from structured data. Otherwise, the message is composed from User, Type, and Entity.

type EventLogType

type EventLogType string

EventLogType defines a stable identifier of a system or user event.

const (
	// EventLogSystem represents a system-level event that is not directly
	// initiated by a user action (e.g. deployment, maintenance, background jobs).
	EventLogSystem EventLogType = "system_event"

	// EventLogUserAccountCreated is recorded when a user account record
	// is created in the system (email/password or OAuth).
	EventLogUserAccountCreated EventLogType = "user_account_created"

	// EventLogUserEmailConfirmed is recorded when a user successfully
	// confirms ownership of their email address.
	EventLogUserEmailConfirmed EventLogType = "user_email_confirmed"

	// EventLogUserRequestPasswordReset is recorded when a user initiates
	// a password reset flow.
	EventLogUserRequestPasswordReset EventLogType = "user_request_password_reset"

	// EventLogUserPasswordChangedByResetRequest is recorded when a user
	// changes their password via a password reset request.
	EventLogUserPasswordChangedByResetRequest EventLogType = "user_password_changed_by_reset_request"

	// EventLogUserPasswordChanged is recorded when a user changes their
	// password while authenticated.
	EventLogUserPasswordChanged EventLogType = "user_password_changed"

	// EventLogUserEmailChangeRequested is recorded when a user initiates
	// an email address change flow.
	EventLogUserEmailChangeRequested EventLogType = "user_email_change_requested"

	// EventLogUserEmailChanged is recorded when a user's email address
	// has been successfully changed.
	EventLogUserEmailChanged EventLogType = "user_email_changed"

	// EventLogUserUsernameChanged is recorded when a user changes
	// their username.
	EventLogUserUsernameChanged EventLogType = "user_username_changed"

	// EventLogUserAccountActivated is recorded when a user account becomes
	// active and eligible to appear in public-facing activity feeds.
	EventLogUserAccountActivated EventLogType = "user_account_activated"

	// EventLogEntitySubmitted is recorded when an entity is submitted
	// for moderation or review.
	EventLogEntitySubmitted EventLogType = "entity_submitted"

	// EventLogEntityApproved is recorded when an entity is approved
	// by a moderator or administrator.
	EventLogEntityApproved EventLogType = "entity_approved"

	// EventLogEntityRejected is recorded when an entity submission
	// is rejected during moderation.
	EventLogEntityRejected EventLogType = "entity_rejected"

	// EventLogEntityAdded is recorded when an entity becomes visible
	// and available to other users (published/accepted).
	EventLogEntityAdded EventLogType = "entity_added"

	// EventLogEntityUpdated is recorded when an existing entity
	// is updated.
	EventLogEntityUpdated EventLogType = "entity_updated"

	// EventLogEntityRenamed is recorded when an entity is only renamed.
	EventLogEntityRenamed EventLogType = "entity_renamed"
)

func (EventLogType) Verb

func (t EventLogType) Verb() string

Verb returns a short, human-readable verb describing the event.

type EventLogsFilter

type EventLogsFilter struct {
	Page       int
	PerPage    int
	OnlyPublic bool
	WithCount  bool
}

EventLogsFilter is used to filter and paginate event logs.

type File

type File struct {
	ID          ID          `json:"id"`
	OwnerID     ID          `json:"owner_id"`
	Name        string      `json:"name"`
	Path        string      `json:"-"`
	PreviewPath string      `json:"-"`
	Hash        string      `json:"-"`
	Type        file.Type   `json:"type"`
	MimeType    string      `json:"mime_type"`
	Purpose     FilePurpose `json:"purpose"`
	Size        int64       `json:"size"`
	CreatedAt   time.Time   `json:"created_at"`
	DeletedAt   *time.Time  `json:"-"`
	Temp        bool        `json:"-"`
}

File represents a file uploaded to the system along with its metadata. Some fields are internal-only and intentionally excluded from JSON output.

func (*File) CreateRules

func (f *File) CreateRules() z.Shape

CreateRules returns the validation schema for creating a new File.

func (*File) IsBookCover

func (f *File) IsBookCover() bool

IsBookCover reports whether the file is an image intended to be used as a book cover.

func (*File) IsOwner

func (f *File) IsOwner(ownerID ID) bool

IsOwner reports whether the file belongs to the given owner.

type FilePurpose

type FilePurpose string

FilePurpose describes the semantic purpose of a file in the system.

const (
	// FilePurposeBookCover marks a file used as a book cover image.
	FilePurposeBookCover FilePurpose = "book-cover"
)

func (FilePurpose) Valid

func (p FilePurpose) Valid() bool

Valid ...

type FilesFilter

type FilesFilter struct {
	Page           int
	PerPage        int
	WithCount      bool
	CreatedAt      *FilterDT
	DeletedAt      *FilterDT
	Deleted        bool
	OrderBy        string
	OrderDirection string
}

FilesFilter is used to filter, sort, and paginate file queries.

type FilterDT

type FilterDT struct {
	DT   *time.Time
	From *time.Time
	To   *time.Time
}

FilterDT ...

func DtAfter

func DtAfter(t time.Time) *FilterDT

DtAfter ...

func DtAt

func DtAt(t time.Time) *FilterDT

DtAt ...

func DtBefore

func DtBefore(t time.Time) *FilterDT

DtBefore ...

func DtBetween

func DtBetween(from, to time.Time) *FilterDT

DtBetween ...

type FilterString

type FilterString struct {
	NotNull     *bool
	NotEmpty    *bool
	ExactMatch  *string
	Contains    *string
	NotContains *string
	StartsWith  *string
	EndsWith    *string
}

FilterString defines options for filtering string-type data.

type ID

type ID uuid.UUID //nolint:recvcheck

ID is a domain-specific UUID (v7). Add `json:",omitzero"` to JSON payloads where ID is optional, or zero ID will happily serialize itself as "00000000-0000-0000-0000-000000000000".

func NewID

func NewID() ID

NewID generates a new UUID v7. It panics if the system clock is severely misconfigured.

func ParseID

func ParseID(s string) (ID, error)

ParseID converts a string into a ds.ID. It supports standard UUID formats.

func (ID) IsNil

func (id ID) IsNil() bool

IsNil ...

func (ID) MarshalJSON

func (id ID) MarshalJSON() ([]byte, error)

MarshalJSON uses the built-in MarshalText from google/uuid.

func (*ID) Scan

func (id *ID) Scan(src any) error

Scan implements sql.Scanner to allow reading UUID from the database into ID.

func (ID) String

func (id ID) String() string

String returns the standard UUID string representation.

func (*ID) UnmarshalJSON

func (id *ID) UnmarshalJSON(data []byte) error

UnmarshalJSON decodes ID from JSON. It treats null and empty string ("") as zero (empty) ID.

func (*ID) UnmarshalYAML

func (id *ID) UnmarshalYAML(value *yaml.Node) error

UnmarshalYAML implements the yaml.Unmarshaler interface.

func (ID) Value

func (id ID) Value() (driver.Value, error)

Value implements driver.Valuer to allow ID to be used in SQL queries.

type OAuthUserAccount

type OAuthUserAccount struct {
	ID             ID            `json:"id"`
	UserID         ID            `json:"user_id"`
	Provider       provider.Type `json:"provider"`
	ProviderUserID string        `json:"provider_user_id"`
	CreatedAt      time.Time     `json:"created_at"`
}

OAuthUserAccount links a local user to their external identity provider credentials.

type Page

type Page struct {
	*Entity

	ContentRaw string `json:"-"`
	Content    string `json:"content"`
}

Page defines the data structure for a page.

func PageFromContext

func PageFromContext(ctx context.Context) *Page

PageFromContext attempts to retrieve page object from the context.

func (*Page) CreateRules

func (p *Page) CreateRules() z.Shape

CreateRules provides the validation map used when saving a new book.

func (*Page) Data

func (p *Page) Data() map[string]any

Data returns the editable fields of the Page as a key-value map.

func (*Page) PropertyType

func (p *Page) PropertyType(key string) prop.Type

PropertyType returns the property type for a given key.

func (*Page) ToContext

func (p *Page) ToContext(ctx context.Context) context.Context

ToContext adds the given book object to the provided context.

func (*Page) UpdateRules

func (p *Page) UpdateRules() z.Shape

UpdateRules provides the validation map used when editing an existing book.

type PasswordResetToken

type PasswordResetToken struct {
	ID        ID        `json:"-"`
	UserID    ID        `json:"-"`
	Token     string    `json:"-"`
	ExpiresAt time.Time `json:"-"`
	CreatedAt time.Time `json:"-"`
}

PasswordResetToken represents a record in the password_reset_tokens table. It stores a single-use token for a user to reset their password.

func (*PasswordResetToken) Invalid

func (t *PasswordResetToken) Invalid() bool

Invalid returns true if the password reset token has expired.

type Topic

type Topic struct {
	ID          ID         `json:"id,omitzero"`
	Type        EntityType `json:"entity_type,omitempty"`
	PublicID    string     `json:"public_id,omitempty"`
	Name        string     `json:"name"`
	Description string     `json:"description,omitzero"`
	CreatedAt   time.Time  `json:"created_at,omitzero"`
	UpdatedAt   *time.Time `json:"updated_at,omitempty"`
	DeletedAt   *time.Time `json:"deleted_at,omitempty"`
}

Topic represents a topic scoped to a specific entity type (e.g. "book"). Topics are linked to entities through the entity_topics pivot table.

type TopicsFilter

type TopicsFilter struct {
	Page           int
	PerPage        int
	Type           EntityType
	PublicIDs      []string
	WithCount      bool
	OrderBy        string
	OrderDirection string
}

TopicsFilter is used to filter and paginate user queries.

type User

type User struct {
	ID             ID         `json:"id"`
	Username       string     `json:"username"`
	Email          string     `json:"email"`
	EmailConfirmed bool       `json:"-"`
	Password       string     `json:"-"`
	CreatedAt      time.Time  `json:"-"`
	UpdatedAt      *time.Time `json:"-"`
	DeletedAt      *time.Time `json:"-"`

	// IsAdmin is true if the user ID is listed in "admins" key in config file.
	// This field is set by the auth middleware.
	// Until proper RBAC/ACL is implemented, we trust authority generously granted by the devs themselves.
	IsAdmin bool `json:"-"`
}

User ...

func UserFromContext

func UserFromContext(ctx context.Context) *User

UserFromContext attempts to retrieve user object from the context.

func (*User) Deleted

func (u *User) Deleted() bool

Deleted ...

func (*User) ToContext

func (u *User) ToContext(ctx context.Context) context.Context

ToContext adds the given user object to the provided context.

type UserSession

type UserSession struct {
	ID        ID         `json:"id"`
	UserID    ID         `json:"user_id"`
	CreatedAt time.Time  `json:"-"`
	UpdatedAt *time.Time `json:"-"`
	ExpiresAt time.Time  `json:"-"`
}

UserSession represents an active session for a logged-in user.

func UserSessionFromContext

func UserSessionFromContext(ctx context.Context) *UserSession

UserSessionFromContext attempts to retrieve the user session object from the context.

func (*UserSession) ToContext

func (s *UserSession) ToContext(ctx context.Context) context.Context

ToContext adds the given user session object to the provided context.

type UsersFilter

type UsersFilter struct {
	Page           int
	PerPage        int
	WithCount      bool
	CreatedAt      *FilterDT
	DeletedAt      *FilterDT
	Deleted        bool
	OrderBy        string
	OrderDirection string
}

UsersFilter is used to filter and paginate user queries.

Directories

Path Synopsis
Package prop provides property type definitions and utilities for handling different kinds of properties .
Package prop provides property type definitions and utilities for handling different kinds of properties .

Jump to

Keyboard shortcuts

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