service

package
v0.10.0 Latest Latest
Warning

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

Go to latest
Published: Oct 4, 2026 License: Apache-2.0 Imports: 30 Imported by: 0

Documentation

Overview

Package service provides business logic services.

Index

Constants

View Source
const SysconfigSetupCompleted = "setup.assistant.completed"

SysconfigSetupCompleted is the sysconfig key that records whether the first-run setup wizard has been completed. Seeded to "false" by migration 000026.

Variables

View Source
var ErrCloneSameUser = errors.New("source and target user must differ")

ErrCloneSameUser is returned when the clone source and target are the same user.

View Source
var ErrInvalidGroup = errors.New("invalid team")

ErrInvalidGroup is wrapped by errors for a team (groups row) that does not exist or is not valid.

Functions

func GetPlaceholderThumbnail

func GetPlaceholderThumbnail(contentType string) ([]byte, string)

GetPlaceholderThumbnail returns a placeholder image for non-image files.

func IsSupportedImageType

func IsSupportedImageType(contentType string) bool

IsSupportedImageType checks if a content type can be thumbnailed. With govips/libvips, we support many more formats than before.

func SuggestCustomerID added in v0.9.0

func SuggestCustomerID(name string) string

SuggestCustomerID derives a customer_id slug from a company name: uppercased, alphanumerics only, spaces/underscores/slashes collapsed to single hyphens, trimmed and capped at 50 chars. The admin may refine it before submitting.

Types

type APITokenService

type APITokenService struct {
	// contains filtered or unexported fields
}

APITokenService handles API token operations

func NewAPITokenService

func NewAPITokenService(db *sql.DB) *APITokenService

NewAPITokenService creates a new API token service

func (*APITokenService) GenerateToken

func (s *APITokenService) GenerateToken(ctx context.Context, req *models.APITokenCreateRequest, userID int, userType models.APITokenUserType, createdBy int) (*models.APITokenCreateResponse, error)

GenerateToken creates a new API token for a user

func (*APITokenService) GenerateTokenForUser

func (s *APITokenService) GenerateTokenForUser(ctx context.Context, req *models.APITokenCreateRequest, targetUserID int, userType models.APITokenUserType, tenantID int, adminID int) (*models.APITokenCreateResponse, error)

GenerateTokenForUser creates a token for a specific user (admin use) This is used when an admin creates a token on behalf of another user. The adminID is recorded as created_by for audit purposes.

func (*APITokenService) GetToken

func (s *APITokenService) GetToken(ctx context.Context, tokenID int64) (*models.APIToken, error)

GetToken returns a token by ID (for admin verification)

func (*APITokenService) ListAllTokens

func (s *APITokenService) ListAllTokens(ctx context.Context, includeRevoked bool) ([]*models.APIToken, error)

ListAllTokens returns all tokens (admin only)

func (*APITokenService) ListUserTokens

func (s *APITokenService) ListUserTokens(ctx context.Context, userID int, userType models.APITokenUserType) ([]*models.APITokenListItem, error)

ListUserTokens returns all tokens for a user

func (*APITokenService) RevokeToken

func (s *APITokenService) RevokeToken(ctx context.Context, tokenID int64, userID int, userType models.APITokenUserType, revokedBy int) error

RevokeToken revokes a token by ID

func (*APITokenService) RevokeTokenAdmin

func (s *APITokenService) RevokeTokenAdmin(ctx context.Context, tokenID int64, revokedBy int) error

RevokeTokenAdmin revokes any token (admin only)

func (*APITokenService) UpdateLastUsed

func (s *APITokenService) UpdateLastUsed(ctx context.Context, tokenID int64, ip string) error

UpdateLastUsed updates the last used timestamp

func (*APITokenService) VerifyToken

func (s *APITokenService) VerifyToken(ctx context.Context, rawToken string) (*models.APIToken, error)

VerifyToken verifies an API token and returns the token record if valid

type AccessibleQueue

type AccessibleQueue struct {
	QueueID   uint   `json:"queue_id"`
	QueueName string `json:"queue_name"`
	GroupID   uint   `json:"group_id"`
	GroupName string `json:"group_name"`
}

AccessibleQueue represents a queue the user can access.

type AgentInput added in v0.9.0

type AgentInput struct {
	Login     string `json:"login" form:"login"`
	FirstName string `json:"first_name" form:"first_name"`
	LastName  string `json:"last_name" form:"last_name"`
	Email     string `json:"email,omitempty" form:"email"`
	GroupIDs  []int  `json:"group_ids,omitempty" form:"group_ids"`
}

AgentInput defines an agent (system user) to create. Each GroupIDs entry follows the same resolution rule as QueueInput.GroupID.

type AgentInputWithGroupIDs added in v0.9.0

type AgentInputWithGroupIDs struct {
	Login     string `json:"login"`
	FirstName string `json:"first_name"`
	LastName  string `json:"last_name"`
	Email     string `json:"email"`
	GroupIDs  []int  `json:"group_ids"`
}

AgentInputWithGroupIDs extends AgentInput with ID and group assignments

type BusinessHoursInput added in v0.9.0

type BusinessHoursInput struct {
	Name        string `json:"name" form:"name"`                   // Configuration name
	Timezone    string `json:"timezone,omitempty" form:"timezone"` // e.g., "America/New_York"
	Description string `json:"description,omitempty" form:"description"`
	// GroupID is the permission group (calendar.group_id) whose members may use
	// the calendar. 0 selects the default "users" group. In a WizardRequest it is
	// a team reference resolved like QueueInput.GroupID.
	GroupID int `json:"group_id,omitempty" form:"group_id"`
}

BusinessHoursInput defines working hours configuration for SLA calculations.

type CreateTicketInput

type CreateTicketInput struct {
	Title                         string
	QueueID                       int
	PriorityID                    int
	StateID                       int
	UserID                        int
	Body                          string // optional initial article body
	ArticleSubject                string
	ArticleSenderTypeID           int
	ArticleTypeID                 int
	ArticleIsVisibleForCustomer   *bool
	ArticleMimeType               string
	ArticleCharset                string
	ArticleCommunicationChannelID int
	PendingUntil                  int // unix seconds when pending should elapse; 0 = none
	TypeID                        int // optional ticket type to set on create (0 = none)
	CustomerID                    string
	CustomerUserID                string
}

type CreatedEntity added in v0.9.0

type CreatedEntity struct {
	Kind string `json:"kind"`
	Name string `json:"name"`
	ID   int    `json:"id,omitempty"`
}

CreatedEntity records one entity ExecuteWizard successfully created, so a partial failure still reports what succeeded.

type CustomerCompany added in v0.9.0

type CustomerCompany struct {
	Name     string `json:"name"`
	Street   string `json:"street"`
	Zip      string `json:"zip"`
	City     string `json:"city"`
	Country  string `json:"country"`
	Url      string `json:"url"`
	Comments string `json:"comments"`
}

CustomerCompany holds customer company details

type CustomerConfiguration added in v0.9.0

type CustomerConfiguration struct {
	Customer        *CustomerCompany         `json:"customer"`
	Groups          []GroupWithID            `json:"groups"`
	Queues          []QueueWithGroup         `json:"queues"`
	Agents          []AgentInputWithGroupIDs `json:"agents"`
	MailAccounts    []MailAccountInput       `json:"mail_accounts"`
	Services        []string                 `json:"services"`
	SLAs            []SLAInput               `json:"slas"`
	PortalUsers     []PortalUserInfo         `json:"portal_users"`
	CannedResponses []string                 `json:"canned_responses"`
	BusinessHours   []BusinessHoursInput     `json:"business_hours"`
	EmailTransport  *EmailTransportInput     `json:"mail_transport"`
}

CustomerConfiguration holds all configuration for an existing customer

type CustomerInput added in v0.9.0

type CustomerInput struct {
	CustomerID string            `json:"customer_id" form:"customer_id"`
	Name       string            `json:"name" form:"name"`
	Fields     map[string]string `json:"fields,omitempty" form:"fields"`
}

CustomerInput defines a customer company to create.

type CustomerPreferencesService

type CustomerPreferencesService struct {
	// contains filtered or unexported fields
}

CustomerPreferencesService handles customer preference operations. Note: customer_preferences uses string user_id (login) unlike user_preferences which uses numeric ID.

func NewCustomerPreferencesService

func NewCustomerPreferencesService(db *sql.DB) *CustomerPreferencesService

NewCustomerPreferencesService creates a new customer preferences service.

func (*CustomerPreferencesService) DeletePreference

func (s *CustomerPreferencesService) DeletePreference(userLogin string, key string) error

DeletePreference removes a customer preference.

func (*CustomerPreferencesService) GetLanguage

func (s *CustomerPreferencesService) GetLanguage(userLogin string) string

GetLanguage returns the customer's preferred language. Returns empty string if no preference is set (use system detection).

func (*CustomerPreferencesService) GetPreference

func (s *CustomerPreferencesService) GetPreference(userLogin string, key string) (string, error)

GetPreference retrieves a customer preference by key.

func (*CustomerPreferencesService) GetSessionTimeout

func (s *CustomerPreferencesService) GetSessionTimeout(userLogin string) int

GetSessionTimeout returns the customer's preferred session timeout. Returns 0 if no preference is set (use system default).

func (*CustomerPreferencesService) GetTheme

func (s *CustomerPreferencesService) GetTheme(userLogin string) string

GetTheme returns the customer's preferred theme.

func (*CustomerPreferencesService) GetThemeMode

func (s *CustomerPreferencesService) GetThemeMode(userLogin string) string

GetThemeMode returns the customer's preferred theme mode (light/dark).

func (*CustomerPreferencesService) SetLanguage

func (s *CustomerPreferencesService) SetLanguage(userLogin string, lang string) error

SetLanguage sets the customer's preferred language.

func (*CustomerPreferencesService) SetPreference

func (s *CustomerPreferencesService) SetPreference(userLogin string, key string, value string) error

SetPreference sets a customer preference. Uses delete-then-insert within a transaction to avoid duplicates and ensure atomicity.

func (*CustomerPreferencesService) SetSessionTimeout

func (s *CustomerPreferencesService) SetSessionTimeout(userLogin string, timeout int) error

SetSessionTimeout sets the customer's preferred session timeout.

func (*CustomerPreferencesService) SetTheme

func (s *CustomerPreferencesService) SetTheme(userLogin string, theme string) error

SetTheme sets the customer's preferred theme.

func (*CustomerPreferencesService) SetThemeMode

func (s *CustomerPreferencesService) SetThemeMode(userLogin string, mode string) error

SetThemeMode sets the customer's preferred theme mode (light/dark).

type CustomerUserInput added in v0.9.0

type CustomerUserInput struct {
	Login     string `json:"login" form:"login"`
	Email     string `json:"email" form:"email"`
	FirstName string `json:"first_name" form:"first_name"`
	LastName  string `json:"last_name" form:"last_name"`
	Title     string `json:"title,omitempty" form:"title"`
	Phone     string `json:"phone,omitempty" form:"phone"`
	Mobile    string `json:"mobile,omitempty" form:"mobile"`
}

CustomerUserInput defines one portal user to provision during onboarding.

type EmailTransportInput added in v0.9.0

type EmailTransportInput struct {
	Host     string `json:"host" form:"host"`                     // SMTP server host (required)
	Port     int    `json:"port" form:"port"`                     // 25, 465, 587 etc.
	User     string `json:"user,omitempty" form:"user"`           // Username for auth
	Password string `json:"password,omitempty" form:"password"`   // Password (stored securely)
	AuthType string `json:"auth_type,omitempty" form:"auth_type"` // plain, login, crammd5
	TLS      bool   `json:"tls,omitempty" form:"tls"`             // Enable TLS
	TLSMode  string `json:"tls_mode,omitempty" form:"tls_mode"`   // none, starttls, smtps
	From     string `json:"from,omitempty" form:"from"`           // Default from address
	FromName string `json:"from_name,omitempty" form:"from_name"` // Display name for sender
}

EmailTransportInput configures outbound SMTP for the system.

type GroupInput added in v0.9.0

type GroupInput struct {
	Name     string `json:"name" form:"name"`
	Comments string `json:"comments,omitempty" form:"comments"`
}

GroupInput defines a group to create.

type GroupPermissions

type GroupPermissions struct {
	Group       *models.Group
	Permissions map[string]bool
}

GroupPermissions represents permissions for a single group.

type GroupUserMatrix

type GroupUserMatrix struct {
	Group *models.Group
	Users []*UserPermissions
}

GroupUserMatrix represents permissions for all users in a group.

type GroupWithID added in v0.9.0

type GroupWithID struct {
	Name string `json:"name"`
	ID   int    `json:"id"`
}

GroupWithID holds group name with ID from DB

type LookupService

type LookupService struct {
	// contains filtered or unexported fields
}

LookupService provides lookup data for forms and dropdowns.

func NewLookupService

func NewLookupService() *LookupService

NewLookupService creates a new lookup service. The database is resolved on every cache rebuild, so the service never captures a stale or missing pool.

func (*LookupService) GetTicketFormDataWithLang

func (s *LookupService) GetTicketFormDataWithLang(lang string) (*models.TicketFormData, error)

GetTicketFormDataWithLang returns all data needed for ticket forms with translation.

func (*LookupService) InvalidateCache

func (s *LookupService) InvalidateCache()

InvalidateCache forces a cache refresh on next request.

type MailAccountInput added in v0.9.0

type MailAccountInput struct {
	Login              string `json:"login" form:"login"`                                           // mailbox username / email
	Password           string `json:"password" form:"password"`                                     // mailbox password (stored as-is, matching existing admin UI)
	Host               string `json:"host" form:"host"`                                             // IMAP/POP3 host
	AccountType        string `json:"account_type" form:"account_type"`                             // IMAP, IMAPTLS, IMAPS, POP3, POP3S
	QueueID            int    `json:"queue_id" form:"queue_id"`                                     // existing queue fetched mail lands in
	CreateQueueName    string `json:"create_queue_name,omitempty" form:"create_queue_name"`         // if set + QueueID==0, create a new queue
	CreateQueueGroupID int    `json:"create_queue_group_id,omitempty" form:"create_queue_group_id"` // owning team for a created queue
	// CreateQueueUseNewTeam: own the created queue with the team created earlier
	// in this onboarding wizard (no id yet at request time).
	CreateQueueUseNewTeam bool   `json:"create_queue_use_new_team,omitempty" form:"create_queue_use_new_team"`
	IMAPFolder            string `json:"imap_folder,omitempty" form:"imap_folder"`
	Trusted               bool   `json:"trusted,omitempty" form:"trusted"`
	Comments              string `json:"comments,omitempty" form:"comments"`
}

MailAccountInput configures an inbound mailbox (OTRS mail_account) whose fetched messages land in a queue — used to wire up a customer's support email address during onboarding.

type OnboardCustomerRequest added in v0.9.0

type OnboardCustomerRequest struct {
	CustomerID string              `json:"customer_id" form:"customer_id"`
	Name       string              `json:"name" form:"name"`
	Street     string              `json:"street,omitempty" form:"street"`
	City       string              `json:"city,omitempty" form:"city"`
	ZIP        string              `json:"zip,omitempty" form:"zip"`
	Country    string              `json:"country,omitempty" form:"country"`
	URL        string              `json:"url,omitempty" form:"url"`
	Comments   string              `json:"comments,omitempty" form:"comments"`
	Users      []CustomerUserInput `json:"users,omitempty" form:"users"`
	// ManagingGroupIDs: agent teams granted read-write access to this company
	// (OTRS group_customer) — i.e. which teams manage this customer.
	ManagingGroupIDs []int `json:"managing_group_ids,omitempty" form:"managing_group_ids"`
	// CreateManagingGroupName: if set, create a new team with this name (e.g.
	// derived from the customer id) and add it to the managing teams.
	CreateManagingGroupName string `json:"create_managing_group_name,omitempty" form:"create_managing_group_name"`
	// Optional Service/SLA mapping (OTRS service → service_sla → service_customer_user).
	ServiceName string `json:"service_name,omitempty" form:"service_name"`
	SLAID       int    `json:"sla_id,omitempty" form:"sla_id"`
	// Optional inbound mailbox (OTRS mail_account) wired to a destination queue.
	MailAccount *MailAccountInput `json:"mail_account,omitempty" form:"mail_account"`
}

OnboardCustomerRequest is the full payload for the customer onboarding wizard: company identity + address + the initial portal users to provision.

type OnboardCustomerResult added in v0.9.0

type OnboardCustomerResult struct {
	Success          bool            `json:"success"`
	CustomerID       string          `json:"customer_id"`
	CompanyName      string          `json:"company_name"`
	UsersCreated     []OnboardedUser `json:"users_created"`
	ManagingGroupIDs []int           `json:"managing_group_ids,omitempty"`
	ServiceID        int             `json:"service_id,omitempty"`
	ServiceName      string          `json:"service_name,omitempty"`
	SLALinked        bool            `json:"sla_linked,omitempty"`
	CreatedGroupID   int             `json:"created_group_id,omitempty"`
	CreatedGroupName string          `json:"created_group_name,omitempty"`
	MailAccountID    int             `json:"mail_account_id,omitempty"`
	CreatedQueueID   int             `json:"created_queue_id,omitempty"`
	Error            string          `json:"error,omitempty"`
}

OnboardCustomerResult is the outcome of OnboardCustomer.

type OnboardedUser added in v0.9.0

type OnboardedUser struct {
	Login    string `json:"login"`
	Email    string `json:"email"`
	Password string `json:"password,omitempty"`
}

OnboardedUser records one provisioned portal user and its one-time password.

type PermissionMatrix

type PermissionMatrix struct {
	User   *models.User
	Groups []*GroupPermissions
}

PermissionMatrix represents a user's permissions across all groups.

type PermissionService

type PermissionService struct {
	// contains filtered or unexported fields
}

PermissionService handles business logic for permissions.

func NewPermissionService

func NewPermissionService(db *sql.DB) *PermissionService

NewPermissionService creates a new permission service.

func (*PermissionService) CloneUserPermissions

func (s *PermissionService) CloneUserPermissions(sourceUserID, targetUserID, actorID uint) error

CloneUserPermissions replaces all group permissions of targetUserID with a copy of sourceUserID's. actorID is recorded in the audit columns. A missing source or target yields repository.ErrPermissionUserNotFound.

func (*PermissionService) GetEffectivePermissions

func (s *PermissionService) GetEffectivePermissions(userID, groupID uint) (map[string]bool, error)

GetEffectivePermissions calculates effective permissions considering inheritance.

func (*PermissionService) GetGroupPermissionMatrix

func (s *PermissionService) GetGroupPermissionMatrix(groupID uint) (*GroupUserMatrix, error)

GetGroupPermissionMatrix gets all users and their permissions for a group.

func (*PermissionService) GetUserPermissionMatrix

func (s *PermissionService) GetUserPermissionMatrix(userID uint) (*PermissionMatrix, error)

GetUserPermissionMatrix gets complete permission matrix for a user.

func (*PermissionService) RemoveAllUserPermissions

func (s *PermissionService) RemoveAllUserPermissions(userID uint) error

RemoveAllUserPermissions removes all permissions for a user.

func (*PermissionService) UpdateUserPermissions

func (s *PermissionService) UpdateUserPermissions(userID uint, permissions map[uint]map[string]bool) error

UpdateUserPermissions updates all permissions for a user.

func (*PermissionService) ValidatePermissions

func (s *PermissionService) ValidatePermissions(userID, groupID uint, requiredPerms []string) (bool, error)

ValidatePermissions checks if a user has specific permissions for a group.

type PluginSetupTask added in v0.9.0

type PluginSetupTask struct {
	Plugin      string `json:"plugin"`
	ID          string `json:"id"`
	Title       string `json:"title"`
	Description string `json:"description,omitempty"`
	Icon        string `json:"icon,omitempty"`
	Category    string `json:"category"`
	Handler     string `json:"handler"`
}

PluginSetupTask is one entry in the setup task catalog. Core tasks use Plugin == "setup-assistant"; plugin-contributed tasks carry the plugin name.

type PortalUserInfo added in v0.9.0

type PortalUserInfo struct {
	Login     string `json:"login"`
	Email     string `json:"email"`
	FirstName string `json:"first_name"`
	LastName  string `json:"last_name"`
	Phone     string `json:"phone,omitempty"`
	Title     string `json:"title,omitempty"`
}

PortalUserInfo holds a customer portal user record for the config response.

type QueueAccessService

type QueueAccessService struct {
	// contains filtered or unexported fields
}

QueueAccessService handles queue permission checks for users. It resolves both direct permissions (via group_user) and role-based permissions (via role_user -> group_role) following OTRS compatibility.

func NewQueueAccessService

func NewQueueAccessService(db *sql.DB) *QueueAccessService

NewQueueAccessService creates a new queue access service.

func (*QueueAccessService) GetAccessibleQueueIDs

func (s *QueueAccessService) GetAccessibleQueueIDs(ctx context.Context, userID uint, permType string) ([]uint, error)

GetAccessibleQueueIDs returns all queue IDs the user can access with the specified permission type.

func (*QueueAccessService) GetAccessibleQueues

func (s *QueueAccessService) GetAccessibleQueues(ctx context.Context, userID uint, permType string) ([]AccessibleQueue, error)

GetAccessibleQueues returns full queue information for all queues the user can access with the specified permission type.

func (*QueueAccessService) GetQueueGroupID

func (s *QueueAccessService) GetQueueGroupID(ctx context.Context, queueID uint) (uint, error)

GetQueueGroupID returns the group ID for a specific queue.

func (*QueueAccessService) GetUserEffectiveGroupIDs

func (s *QueueAccessService) GetUserEffectiveGroupIDs(ctx context.Context, userID uint, permType string) ([]uint, error)

GetUserEffectiveGroupIDs returns all group IDs the user has access to with the specified permission type. This includes both direct permissions (from group_user) and role-based permissions (from role_user -> group_role). The 'rw' permission supersedes all others, so if checking for 'ro', users with 'rw' are also included.

func (*QueueAccessService) HasPermissionOnGroup

func (s *QueueAccessService) HasPermissionOnGroup(ctx context.Context, userID, groupID uint, permType string) (bool, error)

HasPermissionOnGroup checks if user has specific permission on a group.

func (*QueueAccessService) HasQueueAccess

func (s *QueueAccessService) HasQueueAccess(ctx context.Context, userID, queueID uint, permType string) (bool, error)

HasQueueAccess checks if the user has the specified permission type for a specific queue.

func (*QueueAccessService) IsAdmin

func (s *QueueAccessService) IsAdmin(ctx context.Context, userID uint) (bool, error)

IsAdmin checks if the user is in the admin group. Admin users bypass all queue permission checks.

type QueueInput added in v0.9.0

type QueueInput struct {
	Name     string `json:"name" form:"name"`
	GroupID  int    `json:"group_id,omitempty" form:"group_id"`
	Comments string `json:"comments,omitempty" form:"comments"`
}

QueueInput defines a queue to create. A queue is owned by exactly one team (queue.group_id). In the first-run wizard GroupID is a 1-based index into WizardRequest.Groups (the groups do not have database IDs yet) and ExecuteWizard resolves it to the real ID; any value beyond that range is taken as an existing database group ID.

type QueueWithGroup added in v0.10.0

type QueueWithGroup struct {
	Name    string `json:"name"`
	GroupID int    `json:"group_id"`
}

QueueWithGroup is a queue with its owning team (queue.group_id).

type ResponseTemplateInput added in v0.9.0

type ResponseTemplateInput struct {
	Name        string   `json:"name" form:"name"`                           // Display name (required)
	Shortcut    string   `json:"shortcut,omitempty" form:"shortcut"`         // Quick access code
	Category    string   `json:"category,omitempty" form:"category"`         // For organization
	Content     string   `json:"content" form:"content"`                     // Response body (required)
	ContentType string   `json:"content_type,omitempty" form:"content_type"` // text/plain or text/html
	Tags        []string `json:"tags,omitempty" form:"tags"`                 // Search tags
}

ResponseTemplateInput defines a canned response template for customer support.

type SLAInput added in v0.9.0

type SLAInput struct {
	Name              string `json:"name" form:"name"`
	FirstResponseTime int    `json:"first_response_time" form:"first_response_time"`
	SolutionTime      int    `json:"solution_time" form:"solution_time"`
}

SLAInput defines an SLA to create. Times are in minutes.

type SessionService

type SessionService struct {
	// contains filtered or unexported fields
}

SessionService handles session management operations.

func NewSessionService

func NewSessionService(repo repository.SessionRepository) *SessionService

NewSessionService creates a new session service.

func (*SessionService) CleanupByMaxAge

func (s *SessionService) CleanupByMaxAge(maxAge time.Duration) (int, error)

CleanupByMaxAge removes sessions that were created more than maxAge ago. This enforces the maximum session lifetime regardless of activity. Returns the number of sessions cleaned up.

func (*SessionService) CleanupExpired

func (s *SessionService) CleanupExpired(maxAge time.Duration) (int, error)

CleanupExpired removes sessions that have been inactive for longer than maxAge. Returns the number of sessions cleaned up.

func (*SessionService) CreateSession

func (s *SessionService) CreateSession(userID int, userLogin, userType, remoteAddr, userAgent string) (string, error)

CreateSession creates a new session for a user. Returns the generated session ID.

func (*SessionService) CreateSessionWithDetails

func (s *SessionService) CreateSessionWithDetails(userID int, userLogin, userType, userTitle, userFullName, remoteAddr, userAgent string) (string, error)

CreateSessionWithDetails creates a new session with additional user details. Returns the generated session ID.

func (*SessionService) GetSession

func (s *SessionService) GetSession(sessionID string) (*models.Session, error)

GetSession retrieves a session by its ID.

func (*SessionService) GetUserSessions

func (s *SessionService) GetUserSessions(userID int) ([]*models.Session, error)

GetUserSessions retrieves all sessions for a specific user.

func (*SessionService) KillSession

func (s *SessionService) KillSession(sessionID string) error

KillSession terminates a specific session.

func (*SessionService) KillUserSessions

func (s *SessionService) KillUserSessions(userID int) (int, error)

KillUserSessions terminates all sessions for a specific user. Returns the number of sessions killed.

func (*SessionService) ListSessions

func (s *SessionService) ListSessions() ([]*models.Session, error)

ListSessions retrieves all active sessions.

func (*SessionService) TouchSession

func (s *SessionService) TouchSession(sessionID string) error

TouchSession updates the last request time for a session. Should be called on each authenticated request.

type SetupAssistantService added in v0.9.0

type SetupAssistantService struct {
	// contains filtered or unexported fields
}

SetupAssistantService is the business-logic core shared by the HTML and JSON handlers. All entity creation goes through existing repositories; no SQL is built in handlers or templates.

func NewSetupAssistantService added in v0.9.0

func NewSetupAssistantService(db *sql.DB, mgr *pluginmgr.Manager) *SetupAssistantService

NewSetupAssistantService wires the service with its repositories and the plugin manager (nil mgr is allowed — plugin task discovery simply returns none).

func (*SetupAssistantService) AssignAgentToGroups added in v0.9.0

func (s *SetupAssistantService) AssignAgentToGroups(ctx context.Context, userID int, groupIDs []int, createBy int) error

AssignAgentToGroups grants an existing agent (user) rw membership in the given teams. Idempotent per (user, group): an existing 'rw' row is left untouched. Returns an error if the agent does not exist or is inactive.

func (*SetupAssistantService) AssignGroupsToCustomer added in v0.9.0

func (s *SetupAssistantService) AssignGroupsToCustomer(ctx context.Context, customerID string, groupIDs []int, createBy int) error

AssignGroupsToCustomer grants agent teams (groups) read-write access to a customer company via the OTRS `group_customer` table — i.e. which teams can see and manage this customer's tickets. Idempotent per (customer, group).

func (*SetupAssistantService) AssignQueueToGroup added in v0.9.0

func (s *SetupAssistantService) AssignQueueToGroup(ctx context.Context, queueID int, groupID int, createBy int) error

AssignQueueToGroup makes groupID the team that owns an existing queue. A queue has exactly one permission group (queue.group_id; users reach the queue through membership in that team), so this replaces the current owner. Idempotent.

func (*SetupAssistantService) AssignServiceToCustomerUser added in v0.9.0

func (s *SetupAssistantService) AssignServiceToCustomerUser(ctx context.Context, login string, serviceID, createBy int) error

AssignServiceToCustomerUser grants a service to a customer user by login via the OTRS `service_customer_user` table.

func (*SetupAssistantService) CallPluginTask added in v0.9.0

func (s *SetupAssistantService) CallPluginTask(ctx context.Context, pluginName, taskID string, args []byte) ([]byte, error)

CallPluginTask dispatches a plugin setup task by invoking its handler via the plugin manager. Returns the handler's raw JSON response.

func (*SetupAssistantService) CreateAgent added in v0.9.0

func (s *SetupAssistantService) CreateAgent(ctx context.Context, login, firstName, lastName, email string, groupIDs []int, createBy int) (int, error)

CreateAgent creates a system user and grants rw access to the given groups via group_user. groupIDs must be real database group IDs.

func (*SetupAssistantService) CreateBusinessHours added in v0.9.0

func (s *SetupAssistantService) CreateBusinessHours(ctx context.Context, cfg BusinessHoursInput, createBy int) error

CreateBusinessHours creates a business hours calendar for SLA calculations. calendar.group_id is the permission group cfg.GroupID (default: "users"); an unknown or invalid group yields an error wrapping ErrInvalidGroup.

func (*SetupAssistantService) CreateCannedResponses added in v0.9.0

func (s *SetupAssistantService) CreateCannedResponses(ctx context.Context, templates []ResponseTemplateInput, createBy int) error

CreateCannedResponses creates multiple canned response templates for customer onboarding.

func (*SetupAssistantService) CreateCustomerCompany added in v0.9.0

func (s *SetupAssistantService) CreateCustomerCompany(ctx context.Context, customerID, name string, fields map[string]string, createBy int) error

CreateCustomerCompany inserts a customer_company row. Fields carries optional columns (street, zip, city, country, url, comments).

func (*SetupAssistantService) CreateEmailTransport added in v0.9.0

func (s *SetupAssistantService) CreateEmailTransport(ctx context.Context, cfg EmailTransportInput, createBy int) error

CreateEmailTransport configures outbound SMTP settings via sysconfig.

func (*SetupAssistantService) CreateGroup added in v0.9.0

func (s *SetupAssistantService) CreateGroup(ctx context.Context, name, comments string, createBy int) (int, error)

CreateGroup creates a group and returns its new ID.

func (*SetupAssistantService) CreateMailAccount added in v0.9.0

func (s *SetupAssistantService) CreateMailAccount(ctx context.Context, m MailAccountInput, createBy int) (int, error)

CreateMailAccount provisions an inbound mailbox via the existing EmailAccountRepository (no raw SQL in the service). Fetched messages land in the chosen queue. The password is stored as provided, matching the existing admin UI and the inbound poller (which reads `pw` directly).

func (*SetupAssistantService) CreateQueue added in v0.9.0

func (s *SetupAssistantService) CreateQueue(ctx context.Context, name string, groupID int, comments string, createBy int) (int, error)

CreateQueue creates a queue owned by groupID (queue.group_id, the queue's one permission group). groupID must be a real, valid database group ID.

func (*SetupAssistantService) CreateSLA added in v0.9.0

func (s *SetupAssistantService) CreateSLA(ctx context.Context, name string, firstResponseTime, solutionTime int, createBy int) (int, error)

CreateSLA inserts an SLA row and returns its new ID. Times are in minutes.

func (*SetupAssistantService) CreateService added in v0.9.0

func (s *SetupAssistantService) CreateService(ctx context.Context, name string, createBy int) (int, error)

CreateService inserts an OTRS `service` row and returns its new id. Used by the onboarding flow to give a customer SLA coverage the OTRS way (service → service_sla → service_customer_user).

func (*SetupAssistantService) ExecuteWizard added in v0.9.0

func (s *SetupAssistantService) ExecuteWizard(ctx context.Context, req WizardRequest) *WizardResult

ExecuteWizard creates every entity in WizardRequest in dependency order: groups → queues (queue.group_id) → agents (group_user) → customers → SLAs. On any failure it returns a WizardResult describing what succeeded and what failed. It is not wrapped in a single transaction (entity creation spans several repositories); on a fresh system partial state is re-runnable.

func (*SetupAssistantService) GetAllTasks added in v0.9.0

func (s *SetupAssistantService) GetAllTasks() []PluginSetupTask

GetAllTasks returns the combined core + plugin task catalog, grouped in catalog order (core first, then plugins).

func (*SetupAssistantService) GetCoreTasks added in v0.9.0

func (s *SetupAssistantService) GetCoreTasks() []PluginSetupTask

GetCoreTasks returns the built-in setup task catalog. These dispatch to the core HTML/API task handlers, not to plugins.

func (*SetupAssistantService) GetPluginTasks added in v0.9.0

func (s *SetupAssistantService) GetPluginTasks() []PluginSetupTask

GetPluginTasks returns setup tasks contributed by registered plugins.

func (*SetupAssistantService) IsSetupComplete added in v0.9.0

func (s *SetupAssistantService) IsSetupComplete(ctx context.Context) bool

IsSetupComplete reads the setup.assistant.completed sysconfig flag.

func (*SetupAssistantService) LinkServiceSLA added in v0.9.0

func (s *SetupAssistantService) LinkServiceSLA(ctx context.Context, serviceID, slaID int) error

LinkServiceSLA links an SLA to a service via the OTRS `service_sla` table. Idempotent: a duplicate link is not an error (INSERT IGNORE on the service_sla (service_id, sla_id) unique key).

func (*SetupAssistantService) LoadExistingCustomer added in v0.9.0

func (s *SetupAssistantService) LoadExistingCustomer(ctx context.Context, customerID string) (*CustomerConfiguration, error)

LoadExistingCustomer loads an existing customer company and its associated configuration for review and modification in the wizard.

func (*SetupAssistantService) MarkSetupComplete added in v0.9.0

func (s *SetupAssistantService) MarkSetupComplete(ctx context.Context) error

MarkSetupComplete sets the setup.assistant.completed flag to "true". Uses an UPDATE-then-INSERT sequence that works on both MySQL and PostgreSQL without depending on a unique constraint.

func (*SetupAssistantService) OnboardCustomer added in v0.9.0

OnboardCustomer provisions a full customer setup in one shot: creates the company, then each initial portal user (with a generated temporary password the admin distributes). On any failure it reports what succeeded and stops. If CustomerID is empty it is derived from Name via SuggestCustomerID.

func (*SetupAssistantService) Recce added in v0.9.0

Recce returns the current system snapshot. Each count is independent and defaults to 0 on error (missing table / query failure) so a partial schema never breaks the wizard gating — mirrors handleAdminDashboard's pattern.

type SimpleAttachment

type SimpleAttachment struct {
	ID          uint      `json:"id"`
	MessageID   uint      `json:"message_id"`
	Filename    string    `json:"filename"`
	ContentType string    `json:"content_type"`
	Size        int64     `json:"size"`
	URL         string    `json:"url"` // Download URL for the attachment
	CreatedAt   time.Time `json:"created_at"`
}

SimpleAttachment is a simplified attachment model.

type SimpleTicketMessage

type SimpleTicketMessage struct {
	ID           uint                `json:"id"`
	TicketID     uint                `json:"ticket_id"`
	Body         string              `json:"body"`
	Subject      string              `json:"subject"`
	ContentType  string              `json:"content_type"`
	CreatedBy    uint                `json:"created_by"`
	AuthorName   string              `json:"author_name"`
	AuthorEmail  string              `json:"author_email"`
	AuthorType   string              `json:"author_type"` // "Customer", "Agent", "System"
	SenderTypeID int                 `json:"sender_type_id"`
	SenderColor  string              `json:"sender_color,omitempty"` // Hex color from article_color
	IsPublic     bool                `json:"is_public"`
	IsInternal   bool                `json:"is_internal"`
	CreatedAt    time.Time           `json:"created_at"`
	Attachments  []*SimpleAttachment `json:"attachments,omitempty"`
}

SimpleTicketMessage is a simplified message model.

type SimpleTicketService

type SimpleTicketService struct {
	// contains filtered or unexported fields
}

SimpleTicketService provides ticket and article (message) access backed by the database.

func NewSimpleTicketService

func NewSimpleTicketService(repo repository.ITicketRepository, db *sql.DB) *SimpleTicketService

NewSimpleTicketService creates a new simple ticket service.

func (*SimpleTicketService) AddMessage

func (s *SimpleTicketService) AddMessage(ticketID uint, message *SimpleTicketMessage) error

AddMessage persists a message as an article (article + article_data_mime) on the ticket. On success message.ID, TicketID and CreatedAt are set from the stored row.

func (*SimpleTicketService) CreateTicket

func (s *SimpleTicketService) CreateTicket(ticket *models.Ticket) error

CreateTicket creates a new ticket.

func (*SimpleTicketService) DeleteTicket

func (s *SimpleTicketService) DeleteTicket(ticketID uint) error

DeleteTicket deletes a ticket.

func (*SimpleTicketService) GetMessages

func (s *SimpleTicketService) GetMessages(ticketID uint) ([]*SimpleTicketMessage, error)

GetMessages retrieves all articles of a ticket as messages.

func (*SimpleTicketService) GetTicket

func (s *SimpleTicketService) GetTicket(ticketID uint) (*models.Ticket, error)

GetTicket retrieves a ticket by ID.

func (*SimpleTicketService) ListTickets

ListTickets returns a paginated list of tickets.

func (*SimpleTicketService) UpdateTicket

func (s *SimpleTicketService) UpdateTicket(ticket *models.Ticket) error

UpdateTicket updates an existing ticket.

type SystemSnapshot added in v0.9.0

type SystemSnapshot struct {
	Groups         int  `json:"groups"`
	Queues         int  `json:"queues"`
	Agents         int  `json:"agents"`
	Customers      int  `json:"customers"`
	SLAs           int  `json:"slas"`
	Roles          int  `json:"roles"`
	SetupCompleted bool `json:"setup_completed"`
}

SystemSnapshot is the "recce" result: live counts of each core entity plus whether first-run setup has been marked complete. Drives both wizard gating (Mode 1) and the assistant dashboard (Mode 2).

type ThumbnailOptions

type ThumbnailOptions struct {
	Width   int
	Height  int
	Quality int    // JPEG quality 1-100
	Format  string // "jpeg" or "png"
}

ThumbnailOptions defines options for thumbnail generation.

func DefaultThumbnailOptions

func DefaultThumbnailOptions() ThumbnailOptions

DefaultThumbnailOptions returns sensible defaults.

type ThumbnailService

type ThumbnailService struct {
	// contains filtered or unexported fields
}

func NewThumbnailService

func NewThumbnailService(redisClient *redis.Client) *ThumbnailService

NewThumbnailService creates a new thumbnail service with Redis caching.

func (*ThumbnailService) GenerateThumbnail

func (s *ThumbnailService) GenerateThumbnail(data []byte, contentType string, opts ThumbnailOptions) (thumbnailData []byte, outputFormat string, err error)

GenerateThumbnail generates a thumbnail from image data using libvips. Supports JPEG, PNG, GIF, WebP, AVIF, HEIC, TIFF, and more.

func (*ThumbnailService) GetOrCreateThumbnail

func (s *ThumbnailService) GetOrCreateThumbnail(ctx context.Context, attachmentID int, data []byte, contentType string, opts ThumbnailOptions) ([]byte, string, error)

GetOrCreateThumbnail gets a thumbnail from cache or generates it.

func (*ThumbnailService) InvalidateThumbnail

func (s *ThumbnailService) InvalidateThumbnail(ctx context.Context, attachmentID int) error

InvalidateThumbnail removes a thumbnail from cache.

type TicketService

type TicketService interface {
	Create(ctx context.Context, req CreateTicketInput) (*models.Ticket, error)
}

type TicketServiceOption

type TicketServiceOption func(*ticketService)

func WithArticleRepository

func WithArticleRepository(repo *repository.ArticleRepository) TicketServiceOption

WithArticleRepository wires the optional article repository used for the initial article.

type TicketTemplateService

type TicketTemplateService struct {
	// contains filtered or unexported fields
}

TicketTemplateService handles business logic for ticket templates.

func NewTicketTemplateService

func NewTicketTemplateService(repo repository.TicketTemplateRepository, ticketService *SimpleTicketService) *TicketTemplateService

NewTicketTemplateService creates a new ticket template service.

func (*TicketTemplateService) ApplyTemplate

func (s *TicketTemplateService) ApplyTemplate(ctx context.Context, application *models.TemplateApplication) (*models.Ticket, error)

ApplyTemplate creates a new ticket from a template.

func (*TicketTemplateService) CreateTemplate

func (s *TicketTemplateService) CreateTemplate(ctx context.Context, template *models.TicketTemplate) error

CreateTemplate creates a new ticket template.

func (*TicketTemplateService) DeleteTemplate

func (s *TicketTemplateService) DeleteTemplate(ctx context.Context, id uint) error

DeleteTemplate deletes a template.

func (*TicketTemplateService) GetActiveTemplates

func (s *TicketTemplateService) GetActiveTemplates(ctx context.Context) ([]models.TicketTemplate, error)

GetActiveTemplates retrieves all active templates.

func (*TicketTemplateService) GetCategories

GetCategories retrieves all template categories.

func (*TicketTemplateService) GetPopularTemplates

func (s *TicketTemplateService) GetPopularTemplates(ctx context.Context, limit int) ([]models.TicketTemplate, error)

GetPopularTemplates returns the most used templates.

func (*TicketTemplateService) GetTemplate

func (s *TicketTemplateService) GetTemplate(ctx context.Context, id uint) (*models.TicketTemplate, error)

GetTemplate retrieves a template by ID.

func (*TicketTemplateService) GetTemplatesByCategory

func (s *TicketTemplateService) GetTemplatesByCategory(ctx context.Context, category string) ([]models.TicketTemplate, error)

GetTemplatesByCategory retrieves templates by category.

func (*TicketTemplateService) SearchTemplates

func (s *TicketTemplateService) SearchTemplates(ctx context.Context, query string) ([]models.TicketTemplate, error)

SearchTemplates searches for templates.

func (*TicketTemplateService) UpdateTemplate

func (s *TicketTemplateService) UpdateTemplate(ctx context.Context, template *models.TicketTemplate) error

UpdateTemplate updates an existing template.

type UserPermissions

type UserPermissions struct {
	User        *models.User
	Permissions map[string]bool
}

UserPermissions represents a user's permissions in a group.

type WizardRequest added in v0.9.0

type WizardRequest struct {
	OrgType            string                  `json:"org_type" form:"org_type"`
	Groups             []GroupInput            `json:"groups" form:"groups"`
	Queues             []QueueInput            `json:"queues" form:"queues"`
	Agents             []AgentInput            `json:"agents" form:"agents"`
	CustomerCompanies  []CustomerInput         `json:"customer_companies" form:"customer_companies"`
	SLAs               []SLAInput              `json:"slas" form:"slas"`
	ResponseTemplates  []ResponseTemplateInput `json:"response_templates,omitempty" form:"response_templates"`
	BusinessHours      []BusinessHoursInput    `json:"business_hours,omitempty" form:"business_hours"`
	MailTransport      *EmailTransportInput    `json:"mail_transport,omitempty" form:"mail_transport"`
	ExistingCustomerID string                  `json:"existing_customer_id,omitempty" form:"existing_customer_id"`
	CreateBy           int                     `json:"-" form:"-"`
}

WizardRequest is the single structured payload the wizard (UI or LLM) submits. Submitting everything at once makes the flow idempotent and API-friendly.

type WizardResult added in v0.9.0

type WizardResult struct {
	Success bool            `json:"success"`
	Created []CreatedEntity `json:"created,omitempty"`
	Error   string          `json:"error,omitempty"`
}

WizardResult is the outcome of ExecuteWizard.

Directories

Path Synopsis
Package genericinterface provides the GenericInterface service for web service execution.
Package genericinterface provides the GenericInterface service for web service execution.
Package ticket_number provides ticket number generation strategies.
Package ticket_number provides ticket number generation strategies.

Jump to

Keyboard shortcuts

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