@@ -0,0 +1,634 @@
|
||||
package client
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"time"
|
||||
)
|
||||
|
||||
// User is the public user representation returned by the API.
|
||||
type User struct {
|
||||
ID int `json:"id"`
|
||||
CreatedAt time.Time `json:"created_at"`
|
||||
UpdatedAt time.Time `json:"updated_at"`
|
||||
Name string `json:"name"`
|
||||
Email string `json:"email"`
|
||||
Color string `json:"color"`
|
||||
Activated bool `json:"activated"`
|
||||
Role string `json:"role"`
|
||||
Permissions []string `json:"permissions"`
|
||||
}
|
||||
|
||||
// AdminUserInviteInput contains the identity fields for an administrator-created
|
||||
// account invitation.
|
||||
type AdminUserInviteInput struct {
|
||||
Name string `json:"name"`
|
||||
Email string `json:"email"`
|
||||
}
|
||||
|
||||
// IsAdmin reports whether the user can manage application roles.
|
||||
func (user User) IsAdmin() bool { return user.Can("roles:manage") }
|
||||
|
||||
// Can reports whether the API-resolved application permissions contain permission.
|
||||
func (user User) Can(permission string) bool {
|
||||
for _, granted := range user.Permissions {
|
||||
if granted == permission || granted == "*" {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// AccountSession describes one server-side login session for the current user.
|
||||
type AccountSession struct {
|
||||
ID string `json:"id"`
|
||||
CreatedAt time.Time `json:"created_at"`
|
||||
ExpiresAt time.Time `json:"expires_at"`
|
||||
Current bool `json:"current"`
|
||||
}
|
||||
|
||||
// Garden is the public garden representation returned by the API.
|
||||
type Garden struct {
|
||||
ID int `json:"id"`
|
||||
Name string `json:"name"`
|
||||
Description string `json:"description"`
|
||||
ImageData string `json:"image_data,omitempty"`
|
||||
ImageID *int `json:"image_id,omitempty"`
|
||||
CreatedAt time.Time `json:"created_at"`
|
||||
UpdatedAt time.Time `json:"updated_at"`
|
||||
Version int `json:"version"`
|
||||
Role string `json:"role"`
|
||||
Permissions []string `json:"permissions"`
|
||||
}
|
||||
|
||||
// Can reports whether the authenticated member has a concrete permission in
|
||||
// this garden. The API resolves role defaults and garden-specific overrides.
|
||||
func (garden Garden) Can(permission string) bool {
|
||||
for _, granted := range garden.Permissions {
|
||||
if granted == permission || granted == "*" || granted == "garden:*" && permission != "garden:delete" {
|
||||
return true
|
||||
}
|
||||
}
|
||||
if garden.Permissions != nil {
|
||||
return false
|
||||
}
|
||||
// Compatibility for older API responses. Custom roles deliberately have no
|
||||
// fallback: their effective permissions must always come from the API.
|
||||
switch garden.Role {
|
||||
case "owner":
|
||||
return validLegacyGardenPermission(permission)
|
||||
case "admin":
|
||||
return validLegacyGardenPermission(permission) && permission != "garden:delete"
|
||||
case "member":
|
||||
switch permission {
|
||||
case "garden:read", "content:write",
|
||||
"plants:create", "plants:read:own", "plants:read:other", "plants:update:own", "plants:delete:own",
|
||||
"locations:create", "locations:read:own", "locations:read:other", "locations:update:own", "locations:delete:own",
|
||||
"tasks:create", "tasks:read:own", "tasks:read:other", "tasks:update:own", "tasks:delete:own", "tasks:complete:own", "tasks:complete:other":
|
||||
return true
|
||||
}
|
||||
case "viewer":
|
||||
return permission == "garden:read" || permission == "plants:read:own" || permission == "plants:read:other" ||
|
||||
permission == "locations:read:own" || permission == "locations:read:other" || permission == "tasks:read:own" || permission == "tasks:read:other"
|
||||
case "worker":
|
||||
return permission == "garden:read" || permission == "tasks:read:own" || permission == "tasks:read:other" ||
|
||||
permission == "tasks:complete:own" || permission == "tasks:complete:other"
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func validLegacyGardenPermission(permission string) bool {
|
||||
switch permission {
|
||||
case "garden:read", "garden:update", "garden:delete", "content:write", "members:write", "species:write",
|
||||
"plants:create", "plants:read:own", "plants:read:other", "plants:update:own", "plants:update:other", "plants:delete:own", "plants:delete:other",
|
||||
"locations:create", "locations:read:own", "locations:read:other", "locations:update:own", "locations:update:other", "locations:delete:own", "locations:delete:other",
|
||||
"tasks:create", "tasks:read:own", "tasks:read:other", "tasks:update:own", "tasks:update:other", "tasks:delete:own", "tasks:delete:other", "tasks:complete:own", "tasks:complete:other":
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// GardenMember describes a user's role within one garden.
|
||||
type GardenMember struct {
|
||||
GardenID int `json:"garden_id"`
|
||||
UserID int `json:"user_id"`
|
||||
Role string `json:"role"`
|
||||
JoinedAt time.Time `json:"joined_at"`
|
||||
Name string `json:"name"`
|
||||
Email string `json:"email"`
|
||||
}
|
||||
|
||||
// GardenInvite describes a pending invitation to a garden.
|
||||
type GardenInvite struct {
|
||||
ID int `json:"id"`
|
||||
GardenID int `json:"garden_id"`
|
||||
Email string `json:"email"`
|
||||
Role string `json:"role"`
|
||||
InvitedBy int `json:"invited_by"`
|
||||
ExpiresAt time.Time `json:"expires_at"`
|
||||
CreatedAt time.Time `json:"created_at"`
|
||||
}
|
||||
|
||||
// GardenInviteInput contains the recipient and role for a garden invitation.
|
||||
type GardenInviteInput struct {
|
||||
Email string `json:"email"`
|
||||
Role string `json:"role"`
|
||||
}
|
||||
|
||||
// Role is an application or garden role with its base permissions.
|
||||
type Role struct {
|
||||
Name string `json:"name"`
|
||||
Scope string `json:"scope"`
|
||||
GardenID *int `json:"garden_id,omitempty"`
|
||||
Label string `json:"label"`
|
||||
System bool `json:"system"`
|
||||
Permissions []string `json:"permissions"`
|
||||
}
|
||||
|
||||
// RoleInput contains writable role fields.
|
||||
type RoleInput struct {
|
||||
Name string `json:"name,omitempty"`
|
||||
Scope string `json:"scope,omitempty"`
|
||||
Label string `json:"label"`
|
||||
Permissions []string `json:"permissions"`
|
||||
}
|
||||
|
||||
// GardenRoleSetting combines a role template with its effective permissions in
|
||||
// one garden.
|
||||
type GardenRoleSetting struct {
|
||||
Role Role `json:"role"`
|
||||
EffectivePermissions []string `json:"effective_permissions"`
|
||||
}
|
||||
|
||||
// CreateGardenInput contains writable fields for a new garden.
|
||||
type CreateGardenInput struct {
|
||||
Name string `json:"name"`
|
||||
Description string `json:"description"`
|
||||
ImageData string `json:"image_data,omitempty"`
|
||||
ImageID *int `json:"image_id,omitempty"`
|
||||
}
|
||||
|
||||
// UpdateGardenInput contains optional garden fields for a partial update.
|
||||
type UpdateGardenInput struct {
|
||||
Name *string `json:"name,omitempty"`
|
||||
Description *string `json:"description,omitempty"`
|
||||
ImageData *string `json:"image_data,omitempty"`
|
||||
ImageID *int `json:"image_id,omitempty"`
|
||||
}
|
||||
|
||||
// Species describes global or garden-specific plant master data.
|
||||
type Species struct {
|
||||
ID int `json:"id"`
|
||||
GardenID *int `json:"garden_id,omitempty"`
|
||||
CommonName string `json:"common_name"`
|
||||
Cultivar string `json:"cultivar"`
|
||||
BotanicalName string `json:"botanical_name"`
|
||||
CategoryID *int `json:"category_id,omitempty"`
|
||||
Category string `json:"category"`
|
||||
SunExposure *string `json:"sun_exposure,omitempty"`
|
||||
SoilCondition *string `json:"soil_condition,omitempty"`
|
||||
SoilReaction *string `json:"soil_reaction,omitempty"`
|
||||
WinterProtection *string `json:"winter_protection,omitempty"`
|
||||
SpacingCM *int `json:"spacing_cm,omitempty"`
|
||||
HeightCM *int `json:"height_cm,omitempty"`
|
||||
SowMonthFrom *int `json:"sow_month_from,omitempty"`
|
||||
SowDayFrom *int `json:"sow_day_from,omitempty"`
|
||||
SowMonthTo *int `json:"sow_month_to,omitempty"`
|
||||
SowDayTo *int `json:"sow_day_to,omitempty"`
|
||||
PlantingMonthFrom *int `json:"planting_month_from,omitempty"`
|
||||
PlantingDayFrom *int `json:"planting_day_from,omitempty"`
|
||||
PlantingMonthTo *int `json:"planting_month_to,omitempty"`
|
||||
PlantingDayTo *int `json:"planting_day_to,omitempty"`
|
||||
HarvestMonthFrom *int `json:"harvest_month_from,omitempty"`
|
||||
HarvestDayFrom *int `json:"harvest_day_from,omitempty"`
|
||||
HarvestMonthTo *int `json:"harvest_month_to,omitempty"`
|
||||
HarvestDayTo *int `json:"harvest_day_to,omitempty"`
|
||||
Notes string `json:"notes"`
|
||||
ImageData string `json:"image_data,omitempty"`
|
||||
ImageID *int `json:"image_id,omitempty"`
|
||||
Attributes json.RawMessage `json:"attributes"`
|
||||
CreatedAt time.Time `json:"created_at"`
|
||||
UpdatedAt time.Time `json:"updated_at"`
|
||||
Version int `json:"version"`
|
||||
Tags []string `json:"tags,omitempty"`
|
||||
CreatedBy int `json:"created_by"`
|
||||
UpdatedBy int `json:"updated_by"`
|
||||
}
|
||||
|
||||
// SpeciesInput contains optional species fields used for creation and updates.
|
||||
type SpeciesInput struct {
|
||||
Global bool `json:"global,omitempty"`
|
||||
Tags []string `json:"tags,omitempty"`
|
||||
CommonName *string `json:"common_name,omitempty"`
|
||||
Cultivar *string `json:"cultivar,omitempty"`
|
||||
BotanicalName *string `json:"botanical_name,omitempty"`
|
||||
CategoryID *int `json:"category_id,omitempty"`
|
||||
ClearCategoryID bool `json:"clear_category_id,omitempty"`
|
||||
SunExposure *string `json:"sun_exposure,omitempty"`
|
||||
SoilCondition *string `json:"soil_condition,omitempty"`
|
||||
SoilReaction *string `json:"soil_reaction,omitempty"`
|
||||
WinterProtection *string `json:"winter_protection,omitempty"`
|
||||
SpacingCM *int `json:"spacing_cm,omitempty"`
|
||||
HeightCM *int `json:"height_cm,omitempty"`
|
||||
SowMonthFrom *int `json:"sow_month_from,omitempty"`
|
||||
SowDayFrom *int `json:"sow_day_from,omitempty"`
|
||||
ClearSowDayFrom bool `json:"clear_sow_day_from,omitempty"`
|
||||
SowMonthTo *int `json:"sow_month_to,omitempty"`
|
||||
SowDayTo *int `json:"sow_day_to,omitempty"`
|
||||
ClearSowDayTo bool `json:"clear_sow_day_to,omitempty"`
|
||||
PlantingMonthFrom *int `json:"planting_month_from,omitempty"`
|
||||
PlantingDayFrom *int `json:"planting_day_from,omitempty"`
|
||||
ClearPlantingDayFrom bool `json:"clear_planting_day_from,omitempty"`
|
||||
PlantingMonthTo *int `json:"planting_month_to,omitempty"`
|
||||
PlantingDayTo *int `json:"planting_day_to,omitempty"`
|
||||
ClearPlantingDayTo bool `json:"clear_planting_day_to,omitempty"`
|
||||
HarvestMonthFrom *int `json:"harvest_month_from,omitempty"`
|
||||
HarvestDayFrom *int `json:"harvest_day_from,omitempty"`
|
||||
ClearHarvestDayFrom bool `json:"clear_harvest_day_from,omitempty"`
|
||||
HarvestMonthTo *int `json:"harvest_month_to,omitempty"`
|
||||
HarvestDayTo *int `json:"harvest_day_to,omitempty"`
|
||||
ClearHarvestDayTo bool `json:"clear_harvest_day_to,omitempty"`
|
||||
ClearSowRange bool `json:"clear_sow_range,omitempty"`
|
||||
ClearPlantingRange bool `json:"clear_planting_range,omitempty"`
|
||||
ClearHarvestRange bool `json:"clear_harvest_range,omitempty"`
|
||||
Notes *string `json:"notes,omitempty"`
|
||||
ImageData *string `json:"image_data,omitempty"`
|
||||
ImageID *int `json:"image_id,omitempty"`
|
||||
Attributes json.RawMessage `json:"attributes,omitempty"`
|
||||
}
|
||||
|
||||
// SpeciesCategory classifies species and optionally supplies a lifecycle.
|
||||
type SpeciesCategory struct {
|
||||
ID int `json:"id"`
|
||||
Name string `json:"name"`
|
||||
SortOrder int `json:"sort_order"`
|
||||
Active bool `json:"active"`
|
||||
CreatedAt time.Time `json:"created_at"`
|
||||
UpdatedAt time.Time `json:"updated_at"`
|
||||
Version int `json:"version"`
|
||||
Lifecycle *string `json:"lifecycle,omitempty"`
|
||||
}
|
||||
|
||||
// SpeciesCategoryInput contains writable category fields.
|
||||
type SpeciesCategoryInput struct {
|
||||
Name *string `json:"name,omitempty"`
|
||||
SortOrder *int `json:"sort_order,omitempty"`
|
||||
Active *bool `json:"active,omitempty"`
|
||||
Lifecycle *string `json:"lifecycle,omitempty"`
|
||||
}
|
||||
|
||||
// TaskPriority maps a display name to the numeric priority stored on tasks.
|
||||
type TaskPriority struct {
|
||||
ID int `json:"id"`
|
||||
Name string `json:"name"`
|
||||
Value int `json:"value"`
|
||||
SortOrder int `json:"sort_order"`
|
||||
Active bool `json:"active"`
|
||||
CreatedAt time.Time `json:"created_at"`
|
||||
UpdatedAt time.Time `json:"updated_at"`
|
||||
Version int `json:"version"`
|
||||
}
|
||||
|
||||
// TaskPriorityInput contains writable priority-catalogue fields.
|
||||
type TaskPriorityInput struct {
|
||||
Name *string `json:"name,omitempty"`
|
||||
Value *int `json:"value,omitempty"`
|
||||
SortOrder *int `json:"sort_order,omitempty"`
|
||||
Active *bool `json:"active,omitempty"`
|
||||
}
|
||||
|
||||
// Plant represents a plant instance owned by a garden.
|
||||
type Plant struct {
|
||||
ID int `json:"id"`
|
||||
GardenID int `json:"garden_id"`
|
||||
SpeciesID *int `json:"species_id,omitempty"`
|
||||
Name string `json:"name"`
|
||||
Notes string `json:"notes"`
|
||||
ImageData string `json:"image_data,omitempty"`
|
||||
ImageID *int `json:"image_id,omitempty"`
|
||||
AcquiredAt *time.Time `json:"acquired_at,omitempty"`
|
||||
Status string `json:"status"`
|
||||
RemovedAt *time.Time `json:"removed_at,omitempty"`
|
||||
Attributes json.RawMessage `json:"attributes"`
|
||||
CreatedAt time.Time `json:"created_at"`
|
||||
UpdatedAt time.Time `json:"updated_at"`
|
||||
Version int `json:"version"`
|
||||
Tags []string `json:"tags,omitempty"`
|
||||
CreatedBy int `json:"created_by"`
|
||||
UpdatedBy int `json:"updated_by"`
|
||||
PlantedBy int `json:"planted_by"`
|
||||
PlantedByName string `json:"planted_by_name,omitempty"`
|
||||
}
|
||||
|
||||
// PlantInput contains optional plant fields used for creation and updates.
|
||||
type PlantInput struct {
|
||||
Tags []string `json:"tags,omitempty"`
|
||||
SpeciesID *int `json:"species_id,omitempty"`
|
||||
ClearSpeciesID bool `json:"clear_species_id,omitempty"`
|
||||
Name *string `json:"name,omitempty"`
|
||||
Notes *string `json:"notes,omitempty"`
|
||||
ImageData *string `json:"image_data,omitempty"`
|
||||
ImageID *int `json:"image_id,omitempty"`
|
||||
AcquiredAt *time.Time `json:"acquired_at,omitempty"`
|
||||
ClearAcquiredAt bool `json:"clear_acquired_at,omitempty"`
|
||||
Status *string `json:"status,omitempty"`
|
||||
RemovedAt *time.Time `json:"removed_at,omitempty"`
|
||||
Attributes json.RawMessage `json:"attributes,omitempty"`
|
||||
}
|
||||
|
||||
// Location describes a hierarchical place within a garden.
|
||||
type Location struct {
|
||||
ID int `json:"id"`
|
||||
GardenID int `json:"garden_id"`
|
||||
ParentID *int `json:"parent_id,omitempty"`
|
||||
Name string `json:"name"`
|
||||
Description string `json:"description"`
|
||||
ImageData string `json:"image_data,omitempty"`
|
||||
ImageID *int `json:"image_id,omitempty"`
|
||||
Kind string `json:"kind"`
|
||||
AreaSQM *float64 `json:"area_sqm,omitempty"`
|
||||
SunExposure *string `json:"sun_exposure,omitempty"`
|
||||
SoilCondition *string `json:"soil_condition,omitempty"`
|
||||
SoilReaction *string `json:"soil_reaction,omitempty"`
|
||||
Attributes json.RawMessage `json:"attributes"`
|
||||
CreatedAt time.Time `json:"created_at"`
|
||||
UpdatedAt time.Time `json:"updated_at"`
|
||||
Version int `json:"version"`
|
||||
CreatedBy int `json:"created_by"`
|
||||
UpdatedBy int `json:"updated_by"`
|
||||
}
|
||||
|
||||
// LocationInput contains optional location fields used for creation and updates.
|
||||
type LocationInput struct {
|
||||
ParentID *int `json:"parent_id,omitempty"`
|
||||
ClearParentID bool `json:"clear_parent_id,omitempty"`
|
||||
Name *string `json:"name,omitempty"`
|
||||
Description *string `json:"description,omitempty"`
|
||||
ImageData *string `json:"image_data,omitempty"`
|
||||
ImageID *int `json:"image_id,omitempty"`
|
||||
Kind *string `json:"kind,omitempty"`
|
||||
AreaSQM *float64 `json:"area_sqm,omitempty"`
|
||||
SunExposure *string `json:"sun_exposure,omitempty"`
|
||||
SoilCondition *string `json:"soil_condition,omitempty"`
|
||||
SoilReaction *string `json:"soil_reaction,omitempty"`
|
||||
Attributes json.RawMessage `json:"attributes,omitempty"`
|
||||
}
|
||||
|
||||
// PlantLocation represents a plant's assignment to a location.
|
||||
type PlantLocation struct {
|
||||
ID int `json:"id"`
|
||||
PlantID int `json:"plant_id"`
|
||||
LocationID int `json:"location_id"`
|
||||
Quantity int `json:"quantity"`
|
||||
PlantedAt *time.Time `json:"planted_at,omitempty"`
|
||||
RemovedAt *time.Time `json:"removed_at,omitempty"`
|
||||
Notes string `json:"notes"`
|
||||
CreatedAt time.Time `json:"created_at"`
|
||||
Version int `json:"version"`
|
||||
}
|
||||
|
||||
// PlantLocationInput contains optional assignment fields used for creation and updates.
|
||||
type PlantLocationInput struct {
|
||||
LocationID *int `json:"location_id,omitempty"`
|
||||
Quantity *int `json:"quantity,omitempty"`
|
||||
PlantedAt *time.Time `json:"planted_at,omitempty"`
|
||||
ClearPlantedAt bool `json:"clear_planted_at,omitempty"`
|
||||
RemovedAt *time.Time `json:"removed_at,omitempty"`
|
||||
Notes *string `json:"notes,omitempty"`
|
||||
}
|
||||
|
||||
// Task represents a manual or generated garden work item.
|
||||
type Task struct {
|
||||
ID int `json:"id"`
|
||||
GardenID int `json:"garden_id"`
|
||||
PlantID *int `json:"plant_id,omitempty"`
|
||||
LocationID *int `json:"location_id,omitempty"`
|
||||
TemplateID *int `json:"template_id,omitempty"`
|
||||
Title string `json:"title"`
|
||||
Description string `json:"description"`
|
||||
DueAtStart *time.Time `json:"due_at_start,omitempty"`
|
||||
DueAtEnd *time.Time `json:"due_at_end,omitempty"`
|
||||
GeneratedFor *time.Time `json:"generated_for,omitempty"`
|
||||
Recurrence string `json:"recurrence,omitempty"`
|
||||
RecurrenceInterval int `json:"recurrence_interval"`
|
||||
RepeatFromID *int `json:"repeat_from_id,omitempty"`
|
||||
CompletedAt *time.Time `json:"completed_at,omitempty"`
|
||||
CompletedBy *int `json:"completed_by,omitempty"`
|
||||
Priority int `json:"priority"`
|
||||
Active *bool `json:"active,omitempty"`
|
||||
CreatedBy int `json:"created_by"`
|
||||
CreatedAt time.Time `json:"created_at"`
|
||||
UpdatedAt time.Time `json:"updated_at"`
|
||||
Version int `json:"version"`
|
||||
Tags []string `json:"tags,omitempty"`
|
||||
PlantStatusOnCompletion *string `json:"plant_status_on_completion,omitempty"`
|
||||
}
|
||||
|
||||
// TaskInput contains writable fields for task creation and partial updates.
|
||||
type TaskInput struct {
|
||||
Tags []string `json:"tags,omitempty"`
|
||||
PlantID *int `json:"plant_id,omitempty"`
|
||||
LocationID *int `json:"location_id,omitempty"`
|
||||
ClearPlantID bool `json:"clear_plant_id,omitempty"`
|
||||
ClearLocationID bool `json:"clear_location_id,omitempty"`
|
||||
Title *string `json:"title,omitempty"`
|
||||
Description *string `json:"description,omitempty"`
|
||||
DueAtStart *time.Time `json:"due_at_start,omitempty"`
|
||||
DueAtEnd *time.Time `json:"due_at_end,omitempty"`
|
||||
ClearDueAtStart bool `json:"clear_due_at_start,omitempty"`
|
||||
ClearDueAtEnd bool `json:"clear_due_at_end,omitempty"`
|
||||
Recurrence *string `json:"recurrence,omitempty"`
|
||||
RecurrenceInterval *int `json:"recurrence_interval,omitempty"`
|
||||
Priority *int `json:"priority,omitempty"`
|
||||
Active *bool `json:"active,omitempty"`
|
||||
Completed *bool `json:"completed,omitempty"`
|
||||
PlantStatusOnCompletion *string `json:"plant_status_on_completion,omitempty"`
|
||||
}
|
||||
|
||||
// CareInstruction is garden-specific cultivation guidance for a species.
|
||||
type CareInstruction struct {
|
||||
ID int `json:"id"`
|
||||
SpeciesID int `json:"species_id"`
|
||||
Text string `json:"text"`
|
||||
Status string `json:"status"`
|
||||
CreatedBy int `json:"created_by"`
|
||||
UpdatedBy int `json:"updated_by"`
|
||||
CreatedAt time.Time `json:"created_at"`
|
||||
UpdatedAt time.Time `json:"updated_at"`
|
||||
Version int `json:"version"`
|
||||
}
|
||||
|
||||
// CareInstructionInput contains writable care-instruction fields.
|
||||
type CareInstructionInput struct {
|
||||
Text *string `json:"text,omitempty"`
|
||||
Status *string `json:"status,omitempty"`
|
||||
}
|
||||
|
||||
// JournalEntry is a garden journal or pinboard entry with related media.
|
||||
type JournalEntry struct {
|
||||
ID int `json:"id"`
|
||||
GardenID int `json:"garden_id"`
|
||||
AuthorID int `json:"author_id"`
|
||||
AuthorName string `json:"author_name"`
|
||||
AuthorColor string `json:"author_color"`
|
||||
EntryType string `json:"entry_type"`
|
||||
Title string `json:"title"`
|
||||
Body string `json:"body"`
|
||||
CreatedAt time.Time `json:"created_at"`
|
||||
UpdatedAt time.Time `json:"updated_at"`
|
||||
Version int `json:"version"`
|
||||
Tags []string `json:"tags,omitempty"`
|
||||
Attachments []JournalAttachment `json:"attachments,omitempty"`
|
||||
}
|
||||
|
||||
// JournalEntryInput contains writable journal-entry fields.
|
||||
type JournalEntryInput struct {
|
||||
Title *string `json:"title,omitempty"`
|
||||
Body *string `json:"body,omitempty"`
|
||||
CreatedAt *time.Time `json:"created_at,omitempty"`
|
||||
Tags []string `json:"tags,omitempty"`
|
||||
EntryType *string `json:"entry_type,omitempty"`
|
||||
}
|
||||
|
||||
// JournalAttachment describes attachment metadata without its binary body.
|
||||
type JournalAttachment struct {
|
||||
ID int `json:"id"`
|
||||
EntryID int `json:"entry_id"`
|
||||
FileName string `json:"file_name"`
|
||||
MediaType string `json:"media_type"`
|
||||
Size int64 `json:"size"`
|
||||
CreatedAt time.Time `json:"created_at"`
|
||||
ImageID *int `json:"image_id,omitempty"`
|
||||
}
|
||||
|
||||
// JournalAttachmentData combines attachment metadata with its binary body.
|
||||
type JournalAttachmentData struct {
|
||||
JournalAttachment
|
||||
Data []byte
|
||||
}
|
||||
|
||||
// SpeciesTaskTemplate describes a rule for generating tasks from species data.
|
||||
type SpeciesTaskTemplate struct {
|
||||
ID int `json:"id"`
|
||||
SpeciesID int `json:"species_id"`
|
||||
Origin string `json:"origin"`
|
||||
Title string `json:"title"`
|
||||
Description string `json:"description"`
|
||||
TriggerType string `json:"trigger_type"`
|
||||
MonthFrom *int `json:"month_from,omitempty"`
|
||||
DayFrom *int `json:"day_from,omitempty"`
|
||||
MonthTo *int `json:"month_to,omitempty"`
|
||||
DayTo *int `json:"day_to,omitempty"`
|
||||
OffsetDaysFrom *int `json:"offset_days_from,omitempty"`
|
||||
OffsetDaysTo *int `json:"offset_days_to,omitempty"`
|
||||
IntervalDays *int `json:"interval_days,omitempty"`
|
||||
TriggerOffset int `json:"trigger_offset"`
|
||||
TriggerOffsetUnit string `json:"trigger_offset_unit"`
|
||||
Duration int `json:"duration"`
|
||||
DurationUnit string `json:"duration_unit"`
|
||||
Recurrence string `json:"recurrence,omitempty"`
|
||||
RecurrenceInterval int `json:"recurrence_interval"`
|
||||
Priority int `json:"priority"`
|
||||
Active bool `json:"active"`
|
||||
CreatedAt time.Time `json:"created_at"`
|
||||
UpdatedAt time.Time `json:"updated_at"`
|
||||
Version int `json:"version"`
|
||||
}
|
||||
|
||||
// ApplicationSettings contains application-wide lifecycle automation settings.
|
||||
type ApplicationSettings struct {
|
||||
LifecycleStatusEnabled bool `json:"lifecycle_status_enabled"`
|
||||
LifecycleRemovalMonth int `json:"lifecycle_removal_month"`
|
||||
LifecycleRemovalDay int `json:"lifecycle_removal_day"`
|
||||
Timezone string `json:"timezone"`
|
||||
UpdatedAt time.Time `json:"updated_at"`
|
||||
Version int `json:"version"`
|
||||
}
|
||||
|
||||
// ApplicationSettingsInput contains writable lifecycle automation settings.
|
||||
type ApplicationSettingsInput struct {
|
||||
LifecycleStatusEnabled *bool `json:"lifecycle_status_enabled,omitempty"`
|
||||
LifecycleRemovalMonth *int `json:"lifecycle_removal_month,omitempty"`
|
||||
LifecycleRemovalDay *int `json:"lifecycle_removal_day,omitempty"`
|
||||
Timezone *string `json:"timezone,omitempty"`
|
||||
}
|
||||
|
||||
// EnvironmentVariable describes one effective process configuration value.
|
||||
// Sensitive values are masked by the API before they leave the process.
|
||||
type EnvironmentVariable struct {
|
||||
Component string `json:"component"`
|
||||
Name string `json:"name"`
|
||||
Value string `json:"value"`
|
||||
}
|
||||
|
||||
// SpeciesTaskTemplateInput contains writable task-template fields.
|
||||
type SpeciesTaskTemplateInput struct {
|
||||
Title *string `json:"title,omitempty"`
|
||||
Description *string `json:"description,omitempty"`
|
||||
TriggerType *string `json:"trigger_type,omitempty"`
|
||||
MonthFrom *int `json:"month_from,omitempty"`
|
||||
DayFrom *int `json:"day_from,omitempty"`
|
||||
ClearDayFrom bool `json:"clear_day_from,omitempty"`
|
||||
MonthTo *int `json:"month_to,omitempty"`
|
||||
DayTo *int `json:"day_to,omitempty"`
|
||||
ClearDayTo bool `json:"clear_day_to,omitempty"`
|
||||
OffsetDaysFrom *int `json:"offset_days_from,omitempty"`
|
||||
OffsetDaysTo *int `json:"offset_days_to,omitempty"`
|
||||
IntervalDays *int `json:"interval_days,omitempty"`
|
||||
ClearIntervalDays bool `json:"clear_interval_days,omitempty"`
|
||||
TriggerOffset *int `json:"trigger_offset,omitempty"`
|
||||
TriggerOffsetUnit *string `json:"trigger_offset_unit,omitempty"`
|
||||
Duration *int `json:"duration,omitempty"`
|
||||
DurationUnit *string `json:"duration_unit,omitempty"`
|
||||
Recurrence *string `json:"recurrence,omitempty"`
|
||||
RecurrenceInterval *int `json:"recurrence_interval,omitempty"`
|
||||
Priority *int `json:"priority,omitempty"`
|
||||
Active *bool `json:"active,omitempty"`
|
||||
}
|
||||
|
||||
// Credentials contains email and password authentication input.
|
||||
type Credentials struct {
|
||||
Email string `json:"email"`
|
||||
Password string `json:"password"`
|
||||
}
|
||||
|
||||
// RegisterUserInput contains the fields required to register an account.
|
||||
type RegisterUserInput struct {
|
||||
Name string `json:"name"`
|
||||
Email string `json:"email"`
|
||||
Password string `json:"password"`
|
||||
}
|
||||
|
||||
// TokenInput wraps a plaintext activation or reset token.
|
||||
type TokenInput struct {
|
||||
Token string `json:"token"`
|
||||
}
|
||||
|
||||
// EmailInput wraps an email address for token requests.
|
||||
type EmailInput struct {
|
||||
Email string `json:"email"`
|
||||
}
|
||||
|
||||
// UpdatePasswordInput contains a new password and its reset token.
|
||||
type UpdatePasswordInput struct {
|
||||
Password string `json:"password"`
|
||||
Token string `json:"token"`
|
||||
}
|
||||
|
||||
// AuthenticationToken is a bearer token and its expiration time.
|
||||
type AuthenticationToken struct {
|
||||
Token string `json:"token"`
|
||||
Expiry time.Time `json:"expiry"`
|
||||
}
|
||||
|
||||
// Health describes API availability and build information.
|
||||
type Health struct {
|
||||
Status string `json:"status"`
|
||||
ServerTime time.Time `json:"server_time"`
|
||||
SystemInfo SystemInfo `json:"system_info"`
|
||||
}
|
||||
|
||||
// SystemInfo identifies the running API environment and version.
|
||||
type SystemInfo struct {
|
||||
Environment string `json:"environment"`
|
||||
Version string `json:"version"`
|
||||
}
|
||||
Reference in New Issue
Block a user