Documentation
¶
Overview ¶
Package api provides HTTP handlers for the GoatFlow application.
Package api provides HTTP API handlers for GoatFlow.
Package api provides HTTP handlers for the GoatFlow application.
Package api provides HTTP handlers for the API.
Index ¶
- Constants
- Variables
- func BroadcastTicketUpdate(eventType string, ticketData interface{})
- func BuildDynamicFieldFilterSQL(filters []DynamicFieldFilter, startArgNum int) (string, []interface{}, error)
- func BuildRoutesManifest() ([]byte, error)
- func BulkSetScreenConfigForField(fieldID int, configs map[string]int, userID int) error
- func CheckDynamicFieldNameExists(name string, excludeID int) (bool, error)
- func CheckSignatureNameExists(name string, excludeID int) (bool, error)
- func CheckTemplateNameExists(name string, excludeID int) (bool, error)
- func CombineRoutePath(prefix, route string) string
- func CreateDynamicField(field *DynamicField, userID int) (int64, error)
- func CreateSignature(name, text, contentType, comments string, validID, userID int) (int, error)
- func CreateStandardTemplate(t *StandardTemplate, userID int) (int, error)
- func CustomerOnlyGuard(enabled bool) gin.HandlerFunc
- func DeleteDynamicField(id int) error
- func DeleteSignature(id int) error
- func DeleteStandardTemplate(id int) error
- func EnsurePluginGroups()
- func ExportAllSignatures() ([]byte, error)
- func ExportDynamicFieldsYAML(fieldNames []string, includeScreens bool) ([]byte, error)
- func ExportSignature(id int) ([]byte, error)
- func GenerateRoutesManifest() error
- func GetAttachmentTemplateIDs(attachmentID int) ([]int, error)
- func GetAuthService() *platformservice.AuthService
- func GetDistinctDynamicFieldValues(fieldID int, limit int) ([]string, error)
- func GetDynamicFieldsGroupedByObjectType() (map[string][]DynamicField, error)
- func GetDynamicHandler() *dynamic.DynamicModuleHandler
- func GetHandler(name string) (gin.HandlerFunc, bool)
- func GetLookupService() *service.LookupService
- func GetPluginManager() *plugin.Manager
- func GetPluginMenuItems(location string) []plugin.PluginMenuItem
- func GetPriorityRepository() *repository.PriorityRepository
- func GetQueueRepository() *repository.QueueRepository
- func GetQueueTemplateIDs(queueID int) ([]int, error)
- func GetTemplateAttachments(templateID int) ([]int, error)
- func GetTemplateQueues(templateID int) ([]int, error)
- func GetTicketRepository() repository.ITicketRepository
- func GetTicketService() *service.SimpleTicketService
- func GetTicketTemplateVariables(ticketID int) map[string]string
- func GetUserIDFromCtx(c *gin.Context, fallback int) int
- func GetUserIDFromCtxUint(c *gin.Context, fallback uint) uint
- func GetUserMapForTemplate(c *gin.Context) gin.H
- func GetUserRepository() *repository.UserRepository
- func HandleAPIQueueDetails(c *gin.Context)
- func HandleAPIQueueGet(c *gin.Context)
- func HandleAPIQueueStatus(c *gin.Context)
- func HandleAPISetupOnboardCustomer(c *gin.Context)
- func HandleAPISetupRecce(c *gin.Context)
- func HandleAPISetupTask(c *gin.Context)
- func HandleAPISetupTasks(c *gin.Context)
- func HandleAPISetupWizard(c *gin.Context)
- func HandleAddTicketTime(c *gin.Context)
- func HandleAdminCreateTargetToken(c *gin.Context)
- func HandleAdminCustomerUsersBulkAction(c *gin.Context)
- func HandleAdminCustomerUsersCreate(c *gin.Context)
- func HandleAdminCustomerUsersDelete(c *gin.Context)
- func HandleAdminCustomerUsersExport(c *gin.Context)
- func HandleAdminCustomerUsersGet(c *gin.Context)
- func HandleAdminCustomerUsersImport(c *gin.Context)
- func HandleAdminCustomerUsersImportForm(c *gin.Context)
- func HandleAdminCustomerUsersList(c *gin.Context)
- func HandleAdminCustomerUsersTickets(c *gin.Context)
- func HandleAdminCustomerUsersUpdate(c *gin.Context)
- func HandleAdminDynamicModule(c *gin.Context)
- func HandleAdminDynamicModuleFor(module string) gin.HandlerFunc
- func HandleAdminExecuteSQL(c *gin.Context)
- func HandleAdminGroupsAddUser(c *gin.Context)
- func HandleAdminGroupsCreate(c *gin.Context)
- func HandleAdminGroupsDelete(c *gin.Context)
- func HandleAdminGroupsRemoveUser(c *gin.Context)
- func HandleAdminGroupsUpdate(c *gin.Context)
- func HandleAdminGroupsUsers(c *gin.Context)
- func HandleAdminListAllTokens(c *gin.Context)
- func HandleAdminListTargetTokens(c *gin.Context)
- func HandleAdminMarketplace(c *gin.Context)
- func HandleAdminNotificationEventEdit(c *gin.Context)
- func HandleAdminNotificationEventGet(c *gin.Context)
- func HandleAdminNotificationEventNew(c *gin.Context)
- func HandleAdminNotificationEvents(c *gin.Context)
- func HandleAdminPluginLogs(c *gin.Context)
- func HandleAdminPluginUIs(c *gin.Context)
- func HandleAdminPlugins(c *gin.Context)
- func HandleAdminPostmasterFilterEdit(c *gin.Context)
- func HandleAdminPostmasterFilterGet(c *gin.Context)
- func HandleAdminPostmasterFilterNew(c *gin.Context)
- func HandleAdminPostmasterFilters(c *gin.Context)
- func HandleAdminRevokeTargetToken(c *gin.Context)
- func HandleAdminRevokeToken(c *gin.Context)
- func HandleAdminTickets(c *gin.Context)
- func HandleAdminUserCreate(c *gin.Context)
- func HandleAdminUserDelete(c *gin.Context)
- func HandleAdminUserGet(c *gin.Context)
- func HandleAdminUserGroups(c *gin.Context)
- func HandleAdminUserResetPassword(c *gin.Context)
- func HandleAdminUserUpdate(c *gin.Context)
- func HandleAdminUsers(c *gin.Context)
- func HandleAdminUsersList(c *gin.Context)
- func HandleAdminUsersStatus(c *gin.Context)
- func HandleAgentChangePassword(c *gin.Context)
- func HandleAgentCreateTicket(db *sql.DB) gin.HandlerFunc
- func HandleAgentNewTicket(db *sql.DB) gin.HandlerFunc
- func HandleAgentPasswordForm(c *gin.Context)
- func HandleAgentPerformanceAPI(c *gin.Context)
- func HandleAssignQueueGroupAPI(c *gin.Context)
- func HandleAssignTicketAPI(c *gin.Context)
- func HandleClearPluginLogs(c *gin.Context)
- func HandleCloseTicketAPI(c *gin.Context)
- func HandleCreateArticleAPI(c *gin.Context)
- func HandleCreateInternalNote(c *gin.Context)
- func HandleCreateNotificationEvent(c *gin.Context)
- func HandleCreatePostmasterFilter(c *gin.Context)
- func HandleCreatePriorityAPI(c *gin.Context)
- func HandleCreateQueueAPI(c *gin.Context)
- func HandleCreateSalutationAPI(c *gin.Context)
- func HandleCreateSavedSearchAPI(c *gin.Context)
- func HandleCreateSignatureAPI(c *gin.Context)
- func HandleCreateSystemAddressAPI(c *gin.Context)
- func HandleCreateTicketAPI(c *gin.Context)
- func HandleCreateToken(c *gin.Context)
- func HandleCustomerStatisticsAPI(c *gin.Context)
- func HandleDashboardStatisticsAPI(c *gin.Context)
- func HandleDebugConfigSources(c *gin.Context)
- func HandleDebugTicketNumber(c *gin.Context)
- func HandleDeleteArticleAPI(c *gin.Context)
- func HandleDeleteInternalNote(c *gin.Context)
- func HandleDeleteNotificationEvent(c *gin.Context)
- func HandleDeletePostmasterFilter(c *gin.Context)
- func HandleDeletePriorityAPI(c *gin.Context)
- func HandleDeleteQueueAPI(c *gin.Context)
- func HandleDeleteSavedSearchAPI(c *gin.Context)
- func HandleDeleteTicketAPI(c *gin.Context)
- func HandleDetailedHealthCheck(c *gin.Context)
- func HandleDismissCoachmark(c *gin.Context)
- func HandleExecuteSavedSearchAPI(c *gin.Context)
- func HandleExportStatisticsAPI(c *gin.Context)
- func HandleGetArticleAPI(c *gin.Context)
- func HandleGetAvailableLanguages(c *gin.Context)
- func HandleGetAvailableThemes(c *gin.Context)
- func HandleGetFormData(c *gin.Context)
- func HandleGetInternalNotes(c *gin.Context)
- func HandleGetLanguage(c *gin.Context)
- func HandleGetPriorities(c *gin.Context)
- func HandleGetPriorityAPI(c *gin.Context)
- func HandleGetProfile(c *gin.Context)
- func HandleGetQueueAPI(c *gin.Context)
- func HandleGetQueueAgentsAPI(c *gin.Context)
- func HandleGetQueueStatsAPI(c *gin.Context)
- func HandleGetQueues(c *gin.Context)
- func HandleGetRemindersEnabled(c *gin.Context)
- func HandleGetSavedSearchAPI(c *gin.Context)
- func HandleGetScopes(c *gin.Context)
- func HandleGetSessionTimeout(c *gin.Context)
- func HandleGetStatuses(c *gin.Context)
- func HandleGetTheme(c *gin.Context)
- func HandleGetTicketAPI(c *gin.Context)
- func HandleGetTypes(c *gin.Context)
- func HandleHealthCheck(c *gin.Context)
- func HandleInvalidateLookupCache(c *gin.Context)
- func HandleLegacyAgentTicketViewRedirect(c *gin.Context)
- func HandleLegacyTicketsViewRedirect(c *gin.Context)
- func HandleListArticlesAPI(c *gin.Context)
- func HandleListGroupsAPI(c *gin.Context)
- func HandleListPrioritiesAPI(c *gin.Context)
- func HandleListQueuesAPI(c *gin.Context)
- func HandleListSalutationsAPI(c *gin.Context)
- func HandleListSavedSearchesAPI(c *gin.Context)
- func HandleListServicesAPI(c *gin.Context)
- func HandleListSignaturesAPI(c *gin.Context)
- func HandleListStatesAPI(c *gin.Context)
- func HandleListSystemAddressesAPI(c *gin.Context)
- func HandleListTicketsAPI(c *gin.Context)
- func HandleListTokens(c *gin.Context)
- func HandleListTypesAPI(c *gin.Context)
- func HandleMCP(c *gin.Context)
- func HandleMCPInfo(c *gin.Context)
- func HandleMCPSSE(c *gin.Context)
- func HandleMCPSSEDelete(c *gin.Context)
- func HandleMCPSSEStream(c *gin.Context)
- func HandleMailAccountPollStatus(c *gin.Context)
- func HandleMarketplaceIndex(c *gin.Context)
- func HandleMarketplaceInstall(c *gin.Context)
- func HandleMarketplaceSearch(c *gin.Context)
- func HandleMetrics(c *gin.Context)
- func HandlePasswordPolicy(c *gin.Context)
- func HandlePluginCall(c *gin.Context)
- func HandlePluginDisable(c *gin.Context)
- func HandlePluginEnable(c *gin.Context)
- func HandlePluginHealth(c *gin.Context)
- func HandlePluginList(c *gin.Context)
- func HandlePluginLogs(c *gin.Context)
- func HandlePluginResetCrashLoop(c *gin.Context)
- func HandlePluginSSEChannel(c *gin.Context)
- func HandlePluginUIAdminList(c *gin.Context)
- func HandlePluginUIAdminToggle(c *gin.Context)
- func HandlePluginUIAdminUpdate(c *gin.Context)
- func HandlePluginUninstall(c *gin.Context)
- func HandlePluginUpload(c *gin.Context)
- func HandlePluginWidget(c *gin.Context)
- func HandlePluginWidgetList(c *gin.Context)
- func HandleProfile(c *gin.Context)
- func HandleQueueMetricsAPI(c *gin.Context)
- func HandleRedirect(c *gin.Context)
- func HandleRedirectProfile(c *gin.Context)
- func HandleRedirectQueues(c *gin.Context)
- func HandleRedirectSettings(c *gin.Context)
- func HandleRedirectTickets(c *gin.Context)
- func HandleRedirectTicketsNew(c *gin.Context)
- func HandleReindexAPI(c *gin.Context)
- func HandleRemoveQueueGroupAPI(c *gin.Context)
- func HandleReopenTicketAPI(c *gin.Context)
- func HandleRevokeToken(c *gin.Context)
- func HandleSearchAPI(c *gin.Context)
- func HandleSearchHealthAPI(c *gin.Context)
- func HandleServiceWorkerConfig(c *gin.Context)
- func HandleSetLanguage(c *gin.Context)
- func HandleSetPreLoginLanguage(c *gin.Context)
- func HandleSetPreLoginTheme(c *gin.Context)
- func HandleSetRemindersEnabled(c *gin.Context)
- func HandleSetSessionTimeout(c *gin.Context)
- func HandleSetTheme(c *gin.Context)
- func HandleSetWallpaper(c *gin.Context)
- func HandleStaticFiles(c *gin.Context)
- func HandleTemplate(c *gin.Context)
- func HandleTicketHistoryFragment(c *gin.Context)
- func HandleTicketLinksFragment(c *gin.Context)
- func HandleTicketSearchAPI(c *gin.Context)
- func HandleTicketStateStatisticsAPI(c *gin.Context)
- func HandleTicketTrendsAPI(c *gin.Context)
- func HandleTimeBasedAnalyticsAPI(c *gin.Context)
- func HandleUpdateArticleAPI(c *gin.Context)
- func HandleUpdateInternalNote(c *gin.Context)
- func HandleUpdateNotificationEvent(c *gin.Context)
- func HandleUpdatePostmasterFilter(c *gin.Context)
- func HandleUpdatePriorityAPI(c *gin.Context)
- func HandleUpdateProfile(c *gin.Context)
- func HandleUpdateQueueAPI(c *gin.Context)
- func HandleUpdateSalutationAPI(c *gin.Context)
- func HandleUpdateSavedSearchAPI(c *gin.Context)
- func HandleUpdateSignatureAPI(c *gin.Context)
- func HandleUpdateSystemAddressAPI(c *gin.Context)
- func HandleUpdateTicketAPI(c *gin.Context)
- func HasPluginAccess(c *gin.Context, pluginName string) bool
- func ImportSignatures(data []byte, overwrite bool, userID int) (imported int, skipped int, err error)
- func ImportTemplates(data []byte, overwrite bool, userID int) (imported int, skipped int, errors []string)
- func InitAPITokenService(db *sql.DB)
- func InitializeServices()
- func JoinTemplateTypes(types []string) string
- func ListHandlers() []string
- func MissingCoreRoutes(r *gin.Engine) []string
- func MountDynamicEngine(r *gin.Engine, routesDir string)
- func ParseTemplateTypes(typeStr string) []string
- func ProcessArticleDynamicFieldsFromForm(formValues map[string][]string, articleID int, screenKey string) error
- func ProcessDynamicFieldsFromForm(formValues map[string][]string, objectID int, objectType, screenKey string) error
- func RebuildDynamicEngine()
- func RefreshPluginMCPTools()
- func RegisterAdminRoutes(group *gin.RouterGroup, routes []AdminRouteDefinition)
- func RegisterAgentHandlers()
- func RegisterAgentHandlersForRouting()
- func RegisterAgentRoutes(r *gin.RouterGroup, db *sql.DB)
- func RegisterCoreRoutes(r *gin.Engine, sse http.Handler)
- func RegisterCustomerRoutes(r *gin.RouterGroup, db *sql.DB)
- func RegisterDynamicFieldRoutes(router *gin.RouterGroup, adminRouter *gin.RouterGroup)
- func RegisterDynamicModuleHandlersIntoRegistry(reg *routing.HandlerRegistry)
- func RegisterHandler(name string, h gin.HandlerFunc)
- func RegisterPluginAPIRoutes(r *gin.RouterGroup)
- func RegisterWithRouting(registry interface{}) error
- func RenderMarkdown(content string) string
- func RequireAdmin() gin.HandlerFunc
- func RequireGroup(groupName string) gin.HandlerFunc
- func RequirePluginAccess(pluginName, agentGroup string) gin.HandlerFunc
- func RootRedirectTarget() string
- func SessionOrJWTAuth() gin.HandlerFunc
- func SetAPITokenService(svc *service.APITokenService)
- func SetAttachmentTemplates(attachmentID int, templateIDs []int, userID int) error
- func SetDynamicFieldValue(value *DynamicFieldValue) error
- func SetPluginDir(dir string)
- func SetPluginManager(mgr *plugin.Manager)
- func SetPluginReloader(fn func(ctx context.Context, name string) error)
- func SetPluginSSEBroker(b *plugin.SSEBroker)
- func SetPluginUnloader(fn func(ctx context.Context, name string) error)
- func SetQueueTemplates(queueID int, templateIDs []int, userID int) error
- func SetScreenConfig(fieldID int, screenKey string, configValue int, userID int) error
- func SetTemplateAttachments(templateID int, attachmentIDs []int, userID int) error
- func SetTemplateQueues(templateID int, queueIDs []int, userID int) error
- func SetValkeyCache(c *cache.RedisCache)
- func SetupDynamicModules(db *sql.DB) error
- func SetupHTMXRoutes(r *gin.Engine)
- func SetupTestRouterWithRoutes(routes []AdminRouteDefinition) *gin.Engine
- func SubstituteSignatureVariables(text string, vars map[string]string) string
- func SubstituteTemplateVariables(text string, vars map[string]string) string
- func SupportsAutoConfig(fieldType string) bool
- func UpdateDynamicField(field *DynamicField, userID int) error
- func UpdateSignature(id int, name, text, contentType, comments string, validID, userID int) error
- func UpdateStandardTemplate(t *StandardTemplate, userID int) error
- func ValidFieldTypes() []string
- func ValidObjectTypes() []string
- func ValidateAllTemplates(templatesDir string) ([]string, error)
- func ValidateContractHeaders(contract *EndpointContract, headers map[string]string) []string
- func ValidateTemplatesReferencedInRoutes(routesDir, templatesDir string) ([]string, error)
- func ValidateUploadedFile(header *multipart.FileHeader) error
- func WebhookAuth(pluginName string) gin.HandlerFunc
- func WebhookRateLimit(pluginName string) gin.HandlerFunc
- type ACL
- type ACLConfigChange
- type ACLConfigMatch
- type AdditionalDFStorageConfig
- type AdminRouteDefinition
- type AgentHandlerRegistry
- type ArticleInsertParams
- type ArticleMimeParams
- type AttachmentBasicInfo
- type AttachmentInfo
- type AttachmentWithTemplateCount
- type BulkActionRequest
- type BulkActionResult
- type BulkAssignRequest
- type BulkLockRequest
- type BulkMergeRequest
- type BulkPriorityRequest
- type BulkQueueRequest
- type BulkStatusRequest
- type CannedResponse
- type CannedResponseDB
- type CannedResponseFilters
- type CannedResponseRepository
- func (r *CannedResponseRepository) CheckDuplicate(name, scope string, ownerID, teamID int) (bool, error)
- func (r *CannedResponseRepository) Create(cr *CannedResponse, userID int) (int, error)
- func (r *CannedResponseRepository) Delete(id, userID int) error
- func (r *CannedResponseRepository) GetByID(id int) (*CannedResponse, error)
- func (r *CannedResponseRepository) IncrementUsage(id int) error
- func (r *CannedResponseRepository) ListAccessible(userID, teamID int, filters CannedResponseFilters) ([]*CannedResponse, error)
- func (r *CannedResponseRepository) ListCategories() ([]string, error)
- func (r *CannedResponseRepository) Update(id int, cr *CannedResponse, userID int) error
- type CustomerCompanyInfo
- type CustomerGroupAssignment
- type CustomerGroupPermission
- type CustomerUserInfo
- type CustomerUserWithPermissions
- type CustomerWithPermissions
- type DynamicField
- type DynamicFieldConfig
- type DynamicFieldDisplay
- type DynamicFieldExport
- type DynamicFieldExportItem
- type DynamicFieldFilter
- type DynamicFieldScreenConfig
- type DynamicFieldValue
- type EndpointContract
- type FieldWithScreenConfig
- type GenericAgentJob
- type GroupCustomerAssignment
- type GroupInfo
- type GroupWithCustomerUserPermissions
- type GroupWithPermissions
- type ImportPreviewItem
- type ImportResult
- type InternalNote
- type LookupItem
- type NotificationEvent
- type NotificationEventFull
- type NotificationEventInput
- type NotificationEventItem
- type NotificationEventMessage
- type PaginationInfo
- type PluginArticleAttachmentStore
- func (PluginArticleAttachmentStore) DeleteArticleAttachment(ctx context.Context, db *sql.DB, articleID, fileID int64) error
- func (PluginArticleAttachmentStore) ListArticleAttachments(ctx context.Context, db *sql.DB, articleID int64) ([]pkgplugin.ArticleAttachment, error)
- func (PluginArticleAttachmentStore) WriteArticleAttachment(ctx context.Context, db *sql.DB, articleID, createdBy int64, ...) (int64, error)
- type PluginWidgetData
- type PostmasterFilterInput
- type QueueBasic
- type QueueInfo
- type QueueWithTemplateCount
- type RegEx
- type Role
- type RoleGroupPermission
- type RoleUser
- type RouteDoc
- type RouteSpec
- type RoutingHandlerResolver
- func (r RoutingHandlerResolver) Get(name string) (gin.HandlerFunc, error)
- func (r RoutingHandlerResolver) GetMiddleware(name string) (gin.HandlerFunc, error)
- func (r RoutingHandlerResolver) HandlerExists(name string) bool
- func (r RoutingHandlerResolver) IsFeatureEnabled(name string) bool
- func (RoutingHandlerResolver) RegisteredHandlers() map[string]gin.HandlerFunc
- func (r RoutingHandlerResolver) Registry() *routing.HandlerRegistry
- type SLADefinition
- type SLAWithStats
- type ScreenConfigMatrix
- type ScreenDefinition
- type SearchableDynamicField
- type Service
- type ServiceWithStats
- type Signature
- type SignatureExportData
- type SignatureForAgent
- type SignatureWithStats
- type StandardAttachment
- type StandardTemplate
- type StandardTemplateWithStats
- type State
- type StateType
- type StateWithType
- type TemplateExport
- type TemplateExportFile
- type TemplateForAgent
- type TemplateOption
- type TemplateTypeOption
- type TemplateWithAttachmentCount
- type TemplateWithQueueCount
- type TicketDisplay
- type TicketListResponse
- type TicketTemplate
- type TicketType
- type WidgetInfo
Constants ¶
const ( DFTypeText = "Text" DFTypeTextArea = "TextArea" DFTypeCheckbox = "Checkbox" DFTypeDropdown = "Dropdown" DFTypeMultiselect = "Multiselect" DFTypeDate = "Date" DFTypeDateTime = "DateTime" DFTypeWebserviceDropdown = "WebserviceDropdown" DFTypeWebserviceMultiselect = "WebserviceMultiselect" )
Field type constants matching OTRS.
const ( DFObjectTicket = "Ticket" DFObjectArticle = "Article" DFObjectCustomerUser = "CustomerUser" DFObjectCustomerCompany = "CustomerCompany" )
Object type constants matching OTRS.
const ( DFScreenDisabled = 0 DFScreenEnabled = 1 DFScreenRequired = 2 )
Screen config value constants.
const ( MaxFileSize = 10 * 1024 * 1024 // 10MB per file MaxTotalSize = 50 * 1024 * 1024 // 50MB total per ticket MaxAttachments = 20 // Max 20 attachments per ticket )
File upload limits.
Variables ¶
var ( HandleCustomerListTokens = HandleListTokens HandleCustomerCreateToken = HandleCreateToken HandleCustomerRevokeToken = HandleRevokeToken )
Customer handlers are aliases to the unified handlers above The handlers detect agent vs customer from context automatically
var ( HandleAdminListUserTokens = HandleAdminListTargetTokens HandleAdminCreateUserToken = HandleAdminCreateTargetToken HandleAdminRevokeUserToken = HandleAdminRevokeTargetToken HandleAdminListCustomerTokens = HandleAdminListTargetTokens HandleAdminCreateCustomerToken = HandleAdminCreateTargetToken HandleAdminRevokeCustomerToken = HandleAdminRevokeTargetToken )
Admin handler aliases - unified handlers work for both agents and customers
var ( HandleLoginPage = handleLoginPage HandleCustomerLoginPage = handleCustomerLoginPage HandleLogout = handleLogout HandleDashboard = handleDashboard HandleRecentTickets = handleRecentTickets HandleActivityStream = handleActivityStream HandlePendingReminderFeed = handlePendingReminderFeed HandleUpdateTicketStatus = handleUpdateTicketStatus )
Core handlers.
var ( HandleAdminDashboard = handleAdminDashboard // Users are handled by dynamic modules and admin_users_handlers.go. HandleAdminUserEdit = HandleAdminUserGet // Same handler for edit form HandleAdminPasswordPolicy = HandlePasswordPolicy HandleAdminGroups = handleAdminGroups HandleGetGroup = handleGetGroup HandleCreateGroup = handleCreateGroup HandleUpdateGroup = handleUpdateGroup HandleDeleteGroup = handleDeleteGroup HandleGroupMembers = handleGetGroupMembers HandleAddUserToGroup = handleAddUserToGroup HandleRemoveUserFromGroup = handleRemoveUserFromGroup HandleGroupPermissions = handleGroupPermissions HandleSaveGroupPermissions = handleSaveGroupPermissions HandleAdminQueues = handleAdminQueues HandleAdminEmailIdentities = handleAdminEmailIdentities HandleAdminPriorities = handleAdminPriorities HandleAdminPermissions = handleAdminPermissions // Renamed from roles HandleGetUserPermissionMatrix = handleGetUserPermissionMatrix HandleUpdateUserPermissions = handleUpdateUserPermissions HandleAdminEmailQueue = handleAdminEmailQueue HandleAdminEmailQueueRetry = handleAdminEmailQueueRetry HandleAdminEmailQueueDelete = handleAdminEmailQueueDelete HandleAdminEmailQueueRetryAll = handleAdminEmailQueueRetryAll HandleAdminStates = handleAdminStates HandleAdminTypes = handleAdminTypes HandleAdminServices = handleAdminServices HandleAdminServiceCreate = handleAdminServiceCreate HandleAdminServiceUpdate = handleAdminServiceUpdate HandleAdminServiceDelete = handleAdminServiceDelete HandleAdminSLA = handleAdminSLA HandleAdminSLACreate = handleAdminSLACreate HandleAdminSLAUpdate = handleAdminSLAUpdate HandleAdminSLADelete = handleAdminSLADelete HandleAdminLookups = handleAdminLookups // Roles management. HandleAdminRoles = handleAdminRoles HandleAdminRoleCreate = handleAdminRoleCreate HandleAdminRoleGet = handleAdminRoleGet HandleAdminRoleUpdate = handleAdminRoleUpdate HandleAdminRoleDelete = handleAdminRoleDelete HandleAdminRoleUsers = handleAdminRoleUsers HandleAdminRoleUsersSearch = handleAdminRoleUsersSearch HandleAdminRoleUserAdd = handleAdminRoleUserAdd HandleAdminRoleUserRemove = handleAdminRoleUserRemove HandleAdminRolePermissions = handleAdminRolePermissions HandleAdminRolePermissionsUpdate = handleAdminRolePermissionsUpdate // Customer company handlers - wrapped to get database from adapter. HandleAdminCustomerCompanies = func(c *gin.Context) { dbService, err := adapter.GetDatabase() if err != nil { handleAdminCustomerCompanies(nil)(c) return } handleAdminCustomerCompanies(dbService.GetDB())(c) } HandleAdminCustomerCompanyUsers = func(c *gin.Context) { dbService, err := adapter.GetDatabase() if err != nil { c.JSON(http.StatusInternalServerError, gin.H{"error": "Database connection failed"}) return } handleAdminCustomerCompanyUsers(dbService.GetDB())(c) } HandleAdminCustomerCompanyTickets = func(c *gin.Context) { dbService, err := adapter.GetDatabase() if err != nil { c.JSON(http.StatusInternalServerError, gin.H{"error": "Database connection failed"}) return } handleAdminCustomerCompanyTickets(dbService.GetDB())(c) } HandleAdminCustomerCompanyServices = func(c *gin.Context) { dbService, err := adapter.GetDatabase() if err != nil { c.JSON(http.StatusInternalServerError, gin.H{"error": "Database connection failed"}) return } handleAdminCustomerCompanyServices(dbService.GetDB())(c) } HandleAdminCustomerPortalSettings = func(c *gin.Context) { dbService, err := adapter.GetDatabase() if err != nil { c.JSON(http.StatusInternalServerError, gin.H{"error": "Database connection failed"}) return } handleAdminCustomerPortalSettings(dbService.GetDB())(c) } HandleAdminNewCustomerCompany = func(c *gin.Context) { dbService, err := adapter.GetDatabase() if err != nil { handleAdminNewCustomerCompany(nil)(c) return } handleAdminNewCustomerCompany(dbService.GetDB())(c) } HandleAdminCreateCustomerCompany = func(c *gin.Context) { dbService, err := adapter.GetDatabase() if err != nil { c.JSON(http.StatusInternalServerError, gin.H{"error": "Database connection failed"}) return } handleAdminCreateCustomerCompany(dbService.GetDB())(c) } HandleAdminEditCustomerCompany = func(c *gin.Context) { dbService, err := adapter.GetDatabase() if err != nil { c.JSON(http.StatusInternalServerError, gin.H{"error": "Database connection failed"}) return } handleAdminEditCustomerCompany(dbService.GetDB())(c) } HandleAdminUpdateCustomerCompany = func(c *gin.Context) { dbService, err := adapter.GetDatabase() if err != nil { c.JSON(http.StatusInternalServerError, gin.H{"error": "Database connection failed"}) return } handleAdminUpdateCustomerCompany(dbService.GetDB())(c) } HandleAdminDeleteCustomerCompany = func(c *gin.Context) { dbService, err := adapter.GetDatabase() if err != nil { c.JSON(http.StatusInternalServerError, gin.H{"error": "Database connection failed"}) return } handleAdminDeleteCustomerCompany(dbService.GetDB())(c) } HandleAdminUpdateCustomerCompanyServices = func(c *gin.Context) { dbService, err := adapter.GetDatabase() if err != nil { c.JSON(http.StatusInternalServerError, gin.H{"error": "Database connection failed"}) return } handleAdminUpdateCustomerCompanyServices(dbService.GetDB())(c) } HandleAdminUpdateCustomerPortalSettings = func(c *gin.Context) { dbService, err := adapter.GetDatabase() if err != nil { c.JSON(http.StatusInternalServerError, gin.H{"error": "Database connection failed"}) return } handleAdminUpdateCustomerPortalSettings(dbService.GetDB())(c) } HandleAdminActivateCustomerCompany = func(c *gin.Context) { dbService, err := adapter.GetDatabase() if err != nil { c.JSON(http.StatusInternalServerError, gin.H{"error": "Database connection failed"}) return } handleAdminActivateCustomerCompany(dbService.GetDB())(c) } // Customer user ↔ services management. HandleAdminCustomerUserServices = func(c *gin.Context) { dbService, err := adapter.GetDatabase() if err != nil { c.JSON(http.StatusInternalServerError, gin.H{"error": "Database connection failed"}) return } handleAdminCustomerUserServices(dbService.GetDB())(c) } HandleAdminCustomerUserServicesAllocate = func(c *gin.Context) { dbService, err := adapter.GetDatabase() if err != nil { c.JSON(http.StatusInternalServerError, gin.H{"error": "Database connection failed"}) return } handleAdminCustomerUserServicesAllocate(dbService.GetDB())(c) } HandleAdminCustomerUserServicesUpdate = func(c *gin.Context) { dbService, err := adapter.GetDatabase() if err != nil { c.JSON(http.StatusInternalServerError, gin.H{"error": "Database connection failed"}) return } handleAdminCustomerUserServicesUpdate(dbService.GetDB())(c) } HandleAdminServiceCustomerUsersAllocate = func(c *gin.Context) { dbService, err := adapter.GetDatabase() if err != nil { c.JSON(http.StatusInternalServerError, gin.H{"error": "Database connection failed"}) return } handleAdminServiceCustomerUsersAllocate(dbService.GetDB())(c) } HandleAdminServiceCustomerUsersUpdate = func(c *gin.Context) { dbService, err := adapter.GetDatabase() if err != nil { c.JSON(http.StatusInternalServerError, gin.H{"error": "Database connection failed"}) return } handleAdminServiceCustomerUsersUpdate(dbService.GetDB())(c) } HandleAdminDefaultServices = func(c *gin.Context) { dbService, err := adapter.GetDatabase() if err != nil { c.JSON(http.StatusInternalServerError, gin.H{"error": "Database connection failed"}) return } handleAdminDefaultServices(dbService.GetDB())(c) } HandleAdminDefaultServicesUpdate = func(c *gin.Context) { dbService, err := adapter.GetDatabase() if err != nil { c.JSON(http.StatusInternalServerError, gin.H{"error": "Database connection failed"}) return } handleAdminDefaultServicesUpdate(dbService.GetDB())(c) } // Dynamic Fields management. HandleAdminDynamicFields = handleAdminDynamicFields HandleAdminDynamicFieldNew = handleAdminDynamicFieldNew HandleAdminDynamicFieldEdit = handleAdminDynamicFieldEdit HandleAdminDynamicFieldScreenConfig = handleAdminDynamicFieldScreenConfig HandleCreateDynamicField = handleCreateDynamicField HandleUpdateDynamicField = handleUpdateDynamicField HandleDeleteDynamicField = handleDeleteDynamicField HandleAdminDynamicFieldScreenConfigSave = handleAdminDynamicFieldScreenConfigSave HandleAdminDynamicFieldScreenConfigSingle = handleAdminDynamicFieldScreenConfigSingle )
Admin handlers.
var ( HandleTicketDetail = handleTicketDetail HandleQueueDetail = handleQueueDetail HandleNewTicket = handleNewTicket HandleNewEmailTicket = handleNewEmailTicket HandleNewPhoneTicket = handleNewPhoneTicket )
Ticket handlers.
var ( HandleGetAttachments = handleGetAttachments HandleUploadAttachment = handleUploadAttachment HandleDownloadAttachment = handleDownloadAttachment HandleDeleteAttachment = handleDeleteAttachment HandleGetThumbnail = handleGetThumbnail HandleViewAttachment = handleViewAttachment )
Attachment handlers (exported for routing).
var ( HandleAgentTickets = AgentHandlerExports.HandleAgentTickets HandleAgentTicketReply = AgentHandlerExports.HandleAgentTicketReply HandleAgentTicketNote = AgentHandlerExports.HandleAgentTicketNote HandleAgentTicketPhone = AgentHandlerExports.HandleAgentTicketPhone HandleAgentTicketStatus = AgentHandlerExports.HandleAgentTicketStatus HandleAgentTicketAssign = AgentHandlerExports.HandleAgentTicketAssign HandleAgentTicketPriority = AgentHandlerExports.HandleAgentTicketPriority HandleAgentTicketQueue = AgentHandlerExports.HandleAgentTicketQueue HandleAgentTicketMerge = AgentHandlerExports.HandleAgentTicketMerge )
Provide package-level handler variables for tests and direct routing.
var ( HandleCustomerDashboard = wrapAdapterDBHandler(handleCustomerDashboard) HandleCustomerTickets = wrapAdapterDBHandler(handleCustomerTickets) HandleCustomerNewTicket = wrapAdapterDBHandler(handleCustomerNewTicket) HandleCustomerCreateTicket = wrapAdapterDBHandler(handleCustomerCreateTicket) HandleCustomerTicketView = wrapAdapterDBHandler(handleCustomerTicketView) HandleCustomerTicketReply = wrapAdapterDBHandler(handleCustomerTicketReply) HandleCustomerCloseTicket = wrapAdapterDBHandler(handleCustomerCloseTicket) HandleCustomerProfile = wrapAdapterDBHandler(handleCustomerProfile) HandleCustomerUpdateProfile = wrapAdapterDBHandler(handleCustomerUpdateProfile) HandleCustomerPasswordForm = wrapAdapterDBHandler(handleCustomerPasswordForm) HandleCustomerChangePassword = wrapAdapterDBHandler(handleCustomerChangePassword) HandleCustomerGetLanguage = wrapAdapterDBHandler(handleCustomerGetLanguage) HandleCustomerSetLanguage = wrapAdapterDBHandler(handleCustomerSetLanguage) HandleCustomerGetSessionTimeout = wrapAdapterDBHandler(handleCustomerGetSessionTimeout) HandleCustomerSetSessionTimeout = wrapAdapterDBHandler(handleCustomerSetSessionTimeout) // Customer attachment handlers HandleCustomerGetAttachments = wrapAdapterDBHandler(handleCustomerGetAttachments) HandleCustomerUploadAttachment = wrapAdapterDBHandler(handleCustomerUploadAttachment) HandleCustomerDownloadAttachment = wrapAdapterDBHandler(handleCustomerDownloadAttachment) HandleCustomerGetThumbnail = wrapAdapterDBHandler(handleCustomerGetThumbnail) HandleCustomerViewAttachment = wrapAdapterDBHandler(handleCustomerViewAttachment) )
Customer handler exports that get database from connection pool.
var AgentHandlerExports = struct { HandleAgentTickets gin.HandlerFunc HandleAgentTicketReply gin.HandlerFunc HandleAgentTicketNote gin.HandlerFunc HandleAgentTicketPhone gin.HandlerFunc HandleAgentTicketStatus gin.HandlerFunc HandleAgentTicketAssign gin.HandlerFunc HandleAgentTicketPriority gin.HandlerFunc HandleAgentTicketQueue gin.HandlerFunc HandleAgentTicketMerge gin.HandlerFunc HandleAgentNewTicket gin.HandlerFunc HandleAgentCreateTicket gin.HandlerFunc HandleAgentQueues gin.HandlerFunc // Bulk ticket actions HandleBulkTicketStatus gin.HandlerFunc HandleBulkTicketPriority gin.HandlerFunc HandleBulkTicketQueue gin.HandlerFunc HandleBulkTicketAssign gin.HandlerFunc HandleBulkTicketLock gin.HandlerFunc HandleBulkTicketMerge gin.HandlerFunc HandleGetBulkActionOptions gin.HandlerFunc HandleGetFilteredTicketIds gin.HandlerFunc }{ HandleAgentTickets: wrapDBHandler(handleAgentTickets), HandleAgentTicketReply: wrapDBHandler(handleAgentTicketReply), HandleAgentTicketNote: wrapDBHandler(handleAgentTicketNote), HandleAgentTicketPhone: wrapDBHandler(handleAgentTicketPhone), HandleAgentTicketStatus: wrapDBHandler(handleAgentTicketStatus), HandleAgentTicketAssign: wrapDBHandler(handleAgentTicketAssign), HandleAgentTicketPriority: wrapDBHandler(handleAgentTicketPriority), HandleAgentTicketQueue: wrapDBHandler(handleAgentTicketQueue), HandleAgentTicketMerge: wrapDBHandler(handleAgentTicketMerge), HandleAgentNewTicket: wrapDBHandler(HandleAgentNewTicket), HandleAgentCreateTicket: wrapDBHandler(HandleAgentCreateTicket), HandleAgentQueues: wrapDBHandler(handleAgentQueues), HandleBulkTicketStatus: wrapDBHandler(handleBulkTicketStatus), HandleBulkTicketPriority: wrapDBHandler(handleBulkTicketPriority), HandleBulkTicketQueue: wrapDBHandler(handleBulkTicketQueue), HandleBulkTicketAssign: wrapDBHandler(handleBulkTicketAssign), HandleBulkTicketLock: wrapDBHandler(handleBulkTicketLock), HandleBulkTicketMerge: wrapDBHandler(handleBulkTicketMerge), HandleGetBulkActionOptions: wrapDBHandler(handleGetBulkActionOptions), HandleGetFilteredTicketIds: wrapDBHandler(handleGetFilteredTicketIds), }
AgentHandlerExports provides exported handler functions for agent routes.
var GlobalAgentHandlers = &AgentHandlerRegistry{}
GlobalAgentHandlers is the global registry for agent handlers.
var HandleAPIv1AddArticle = HandleCreateArticleAPI
Articles API handlers.
var HandleAPIv1AuthLogin = platformapi.HandleLoginAPI
Auth handlers.
var HandleAPIv1AuthLogout = platformapi.HandleLogoutAPI
var HandleAPIv1GetTicketArticle = func(c *gin.Context) { ticketID := c.Param("id") articleID := c.Param("article_id") c.JSON(http.StatusOK, gin.H{ "success": true, "message": "Get ticket article endpoint - under construction", "data": gin.H{"ticket_id": ticketID, "article_id": articleID}, }) }
var HandleAPIv1GetTicketArticles = func(c *gin.Context) { ticketID := c.Param("id") c.JSON(http.StatusOK, gin.H{ "success": true, "message": "Get ticket articles endpoint - under construction", "data": gin.H{"ticket_id": ticketID}, }) }
var HandleAPIv1PrioritiesList = func(c *gin.Context) { priorityRepo := GetPriorityRepository() if priorityRepo == nil { c.JSON(http.StatusInternalServerError, gin.H{ "success": false, "error": "Priority repository not initialized", }) return } priorities, err := priorityRepo.List() if err != nil { c.JSON(http.StatusInternalServerError, gin.H{ "success": false, "error": err.Error(), }) return } priorityList := make([]gin.H, 0, len(priorities)) for _, p := range priorities { priorityList = append(priorityList, gin.H{ "id": p.ID, "name": p.Name, }) } c.JSON(http.StatusOK, gin.H{ "success": true, "data": priorityList, }) }
Priorities API handlers.
var HandleAPIv1PriorityGet = func(c *gin.Context) { id := c.Param("id") priorityRepo := GetPriorityRepository() if priorityRepo == nil { c.JSON(http.StatusInternalServerError, gin.H{ "success": false, "error": "Priority repository not initialized", }) return } priorityID, err := strconv.ParseUint(id, 10, 32) if err != nil { c.JSON(http.StatusBadRequest, gin.H{ "success": false, "error": "Invalid priority ID", }) return } priority, err := priorityRepo.GetByID(uint(priorityID)) if err != nil { c.JSON(http.StatusNotFound, gin.H{ "success": false, "error": "Priority not found", }) return } c.JSON(http.StatusOK, gin.H{ "success": true, "data": priority, }) }
var HandleAPIv1QueueCreate = func(c *gin.Context) { c.JSON(http.StatusCreated, gin.H{ "success": true, "message": "Endpoint /api/v1/queues (POST) is under construction", "data": nil, }) }
var HandleAPIv1QueueDelete = func(c *gin.Context) { c.JSON(http.StatusNoContent, gin.H{}) }
var HandleAPIv1QueueGet = func(c *gin.Context) { id := c.Param("id") queueRepo := GetQueueRepository() if queueRepo == nil { c.JSON(http.StatusInternalServerError, gin.H{ "success": false, "error": "Queue repository not initialized", }) return } queueID, err := strconv.ParseUint(id, 10, 32) if err != nil { c.JSON(http.StatusBadRequest, gin.H{ "success": false, "error": "Invalid queue ID", }) return } queue, err := queueRepo.GetByID(uint(queueID)) if err != nil { c.JSON(http.StatusNotFound, gin.H{ "success": false, "error": "Queue not found", }) return } c.JSON(http.StatusOK, gin.H{ "success": true, "data": queue, }) }
var HandleAPIv1QueueUpdate = func(c *gin.Context) { c.JSON(http.StatusOK, gin.H{ "success": true, "message": "Endpoint /api/v1/queues/:id (PUT) is under construction", "data": nil, }) }
var HandleAPIv1QueuesList = func(c *gin.Context) { queueRepo := GetQueueRepository() if queueRepo == nil { c.JSON(http.StatusInternalServerError, gin.H{ "success": false, "error": "Queue repository not initialized", }) return } queues, err := queueRepo.List() if err != nil { c.JSON(http.StatusInternalServerError, gin.H{ "success": false, "error": err.Error(), }) return } queueList := make([]gin.H, 0, len(queues)) for _, q := range queues { queueList = append(queueList, gin.H{ "id": q.ID, "name": q.Name, }) } c.JSON(http.StatusOK, gin.H{ "success": true, "data": queueList, }) }
Queues API handlers.
var HandleAPIv1TicketAssign = HandleAssignTicketAPI
var HandleAPIv1TicketClose = HandleCloseTicketAPI
Ticket action handlers.
var HandleAPIv1TicketCreate = HandleCreateTicketAPI
var HandleAPIv1TicketDelete = HandleDeleteTicketAPI
var HandleAPIv1TicketGet = func(c *gin.Context) { id := c.Param("id") ticketRepo := GetTicketRepository() if ticketRepo == nil { c.JSON(http.StatusInternalServerError, gin.H{ "success": false, "error": "Ticket repository not initialized", }) return } ticketID, err := strconv.ParseUint(id, 10, 32) if err != nil { c.JSON(http.StatusBadRequest, gin.H{ "success": false, "error": "Invalid ticket ID", }) return } ticket, err := ticketRepo.GetByID(uint(ticketID)) if err != nil { c.JSON(http.StatusNotFound, gin.H{ "success": false, "error": "Ticket not found", }) return } c.JSON(http.StatusOK, gin.H{ "success": true, "data": ticket, }) }
var HandleAPIv1TicketReopen = HandleReopenTicketAPI
var HandleAPIv1TicketUpdate = HandleUpdateTicketAPI
var HandleAPIv1TicketsList = HandleListTicketsAPI
Tickets API handlers.
var HandleAPIv1UserCreate = func(c *gin.Context) { c.JSON(http.StatusCreated, gin.H{ "success": true, "message": "Endpoint /api/v1/users (POST) is under construction", "data": nil, }) }
var HandleAPIv1UserDelete = func(c *gin.Context) { c.JSON(http.StatusNoContent, gin.H{}) }
var HandleAPIv1UserGet = func(c *gin.Context) { id := c.Param("id") userRepo := GetUserRepository() if userRepo == nil { c.JSON(http.StatusInternalServerError, gin.H{ "success": false, "error": "User repository not initialized", }) return } // Convert string ID to uint var userID uint if _, err := fmt.Sscanf(id, "%d", &userID); err != nil { c.JSON(http.StatusBadRequest, gin.H{ "success": false, "error": "Invalid user ID", }) return } user, err := userRepo.GetByID(userID) if err != nil { c.JSON(http.StatusNotFound, gin.H{ "success": false, "error": "User not found", }) return } c.JSON(http.StatusOK, gin.H{ "success": true, "data": user, }) }
var HandleAPIv1UserMe = platformapi.HandleUserMeAPI
Users API handlers.
var HandleAPIv1UserUpdate = func(c *gin.Context) { c.JSON(http.StatusOK, gin.H{ "success": true, "message": "Endpoint /api/v1/users/:id (PUT) is under construction", "data": nil, }) }
var HandleAPIv1UsersList = func(c *gin.Context) { userRepo := GetUserRepository() if userRepo == nil { c.JSON(http.StatusInternalServerError, gin.H{ "success": false, "error": "User repository not initialized", }) return } users, err := userRepo.List() if err != nil { c.JSON(http.StatusInternalServerError, gin.H{ "success": false, "error": err.Error(), }) return } c.JSON(http.StatusOK, gin.H{ "success": true, "data": users, }) }
var HandleAuthLogin = func(c *gin.Context) { contentType := c.GetHeader("Content-Type") var username, password string if strings.Contains(contentType, "application/json") { var payload struct { Login string `json:"login"` Username string `json:"username"` Email string `json:"email"` Password string `json:"password"` } if err := c.ShouldBindJSON(&payload); err == nil { username = payload.Login if username == "" { username = payload.Username } if username == "" { username = payload.Email } password = payload.Password } } else { username = c.PostForm("username") password = c.PostForm("password") if username == "" { username = c.PostForm("login") } if username == "" { username = c.PostForm("email") } if username == "" { username = c.PostForm("user") } } provider := c.PostForm("provider") if provider == "" { provider = c.Query("provider") } provider = strings.ToLower(provider) if username == "" || password == "" { if strings.Contains(contentType, "application/json") { c.JSON(http.StatusBadRequest, gin.H{"success": false, "error": "username and password required"}) } else { getPongo2Renderer().HTML(c, http.StatusBadRequest, "components/error.pongo2", pongo2.Context{"error": "Username and password are required"}) } return } clientIP := c.ClientIP() if blocked, remaining := auth.DefaultLoginRateLimiter.IsBlocked(clientIP, username); blocked { switch { case strings.Contains(contentType, "application/json"): tooManyAttemptsJSON(c, remaining) case c.GetHeader("HX-Request") == "true": html := `<div class="rounded-md bg-red-50 dark:bg-red-900/20 p-4 mt-4">` + `<div class="text-sm text-red-800 dark:text-red-200">` + `Too many failed attempts. Try again later.</div></div>` c.Data(http.StatusTooManyRequests, "text/html; charset=utf-8", []byte(html)) default: c.Redirect(http.StatusSeeOther, "/login?error=Too+many+failed+attempts.+Try+again+later") } return } authService := GetAuthService() if authService == nil { if strings.Contains(contentType, "application/json") { c.JSON(http.StatusUnauthorized, gin.H{"success": false, "error": "authentication unavailable"}) return } if c.GetHeader("HX-Request") == "true" { html := `<div class="rounded-md bg-yellow-50 dark:bg-yellow-900/20 p-4 mt-4">` + `<div class="text-sm text-yellow-800 dark:text-yellow-100">` + `Authentication temporarily unavailable</div></div>` c.Data(http.StatusUnauthorized, "text/html; charset=utf-8", []byte(html)) return } c.Redirect(http.StatusSeeOther, "/login?error=Authentication+temporarily+unavailable") return } ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second) defer cancel() user, err := authService.Login(ctx, username, password) if err != nil { auth.DefaultLoginRateLimiter.RecordFailure(clientIP, username) if strings.Contains(contentType, "application/json") { c.JSON(http.StatusUnauthorized, gin.H{"success": false, "error": "invalid credentials"}) return } if c.GetHeader("HX-Request") == "true" { html := `<div class="rounded-md bg-red-50 dark:bg-red-900/20 p-4 mt-4">` + `<div class="text-sm text-red-800 dark:text-red-200">` + `Invalid username or password</div></div>` c.Data(http.StatusUnauthorized, "text/html; charset=utf-8", []byte(html)) } else { c.Redirect(http.StatusSeeOther, "/login?error=Invalid+username+or+password") } return } auth.DefaultLoginRateLimiter.RecordSuccess(clientIP, username) mfaDB, mfaErr := database.GetDB() var mfa mfaStatus if mfaErr == nil { mfa, mfaErr = agentMFAStatus(mfaDB, int(user.ID)) } if mfaErr != nil { log.Printf("login: second-factor status for user %d unavailable: %v", user.ID, mfaErr) if strings.Contains(contentType, "application/json") { c.JSON(http.StatusInternalServerError, gin.H{"success": false, "error": "Login temporarily unavailable"}) } else { c.Redirect(http.StatusSeeOther, "/login?error=server_error") } return } if mfa.Enabled() { sessionMgr := auth.GetTOTPSessionManager() token, err := sessionMgr.CreateAgentSession(int(user.ID), username, c.ClientIP(), c.Request.UserAgent()) if err != nil { if strings.Contains(contentType, "application/json") { c.JSON(http.StatusInternalServerError, gin.H{"success": false, "error": "Failed to create 2FA session"}) } else { c.Redirect(http.StatusSeeOther, "/login?error=2FA+session+error") } return } httpcookie.SetAuth(c, "2fa_pending", token, 300) if c.GetHeader("HX-Request") == "true" { c.Redirect(http.StatusFound, "/login/2fa") } else if strings.Contains(contentType, "application/json") { c.JSON(http.StatusOK, gin.H{ "success": true, "requires_2fa": true, "redirect": "/login/2fa", }) } else { c.Redirect(http.StatusFound, "/login/2fa") } return } sessionTimeout := shared.GetSystemSessionMaxTime() if db, err := database.GetDB(); err == nil && db != nil { prefService := service.NewUserPreferencesService(db) if userTimeout := prefService.GetSessionTimeout(int(user.ID)); userTimeout > 0 { sessionTimeout = shared.ResolveSessionTimeout(userTimeout) } if preLoginLang, err := c.Cookie("goatflow_lang"); err == nil && preLoginLang != "" { if setErr := prefService.SetLanguage(int(user.ID), preLoginLang); setErr != nil { log.Printf("Failed to save language preference: %v", setErr) } } } if sessionTimeout <= 0 { sessionTimeout = constants.DefaultSessionTimeout } sessionID, accessToken, refreshToken, err := authService.IssueTokens(user, c.ClientIP(), c.Request.UserAgent(), time.Duration(sessionTimeout)*time.Second) if err != nil { log.Printf("login: issue tokens for %s: %v", username, err) if strings.Contains(contentType, "application/json") { c.JSON(http.StatusInternalServerError, gin.H{"success": false, "error": "Login temporarily unavailable"}) } else { c.Redirect(http.StatusSeeOther, "/login?error=server_error") } return } httpcookie.SetAuth(c, "auth_token", accessToken, sessionTimeout) httpcookie.SetAuth(c, "access_token", accessToken, sessionTimeout) httpcookie.SetAuth(c, "refresh_token", refreshToken, constants.RefreshTokenTimeout) httpcookie.SetAuth(c, "session_id", sessionID, sessionTimeout) c.Set("user", user) c.Set("user_id", user.ID) if provider != "" { c.Set("auth_provider", provider) } httpcookie.SetAuthState(c, "goatflow_logged_in", "1", sessionTimeout) redirectTarget := "/dashboard" if strings.EqualFold(user.Role, "customer") { redirectTarget = "/customer" } if lp := shared.GetLandingPage(); lp != "" && redirectTarget == "/dashboard" { redirectTarget = lp } if strings.Contains(contentType, "application/json") { c.JSON(http.StatusOK, gin.H{ "success": true, "access_token": accessToken, "refresh_token": refreshToken, "token_type": "Bearer", "redirect": redirectTarget, }) return } if c.GetHeader("HX-Request") == "true" { c.Header("HX-Redirect", redirectTarget) c.String(http.StatusOK, "Login successful, redirecting...") return } c.Redirect(http.StatusSeeOther, redirectTarget) }
HandleAuthLogin handles the login form submission.
var HandleCustomerLogin = func(c *gin.Context) { handleCustomerLogin(shared.GetJWTManager())(c) }
HandleCustomerLogin is the exported handler for customer login POST requests.
var HandleTicketCustomerUsersWrapper gin.HandlerFunc = func(c *gin.Context) { db, err := database.GetDB() if err != nil { c.JSON(500, gin.H{"error": "Database unavailable"}) return } handleTicketCustomerUsers(db)(c) }
HandleTicketCustomerUsersWrapper wraps handleTicketCustomerUsers with DB lookup.
Functions ¶
func BroadcastTicketUpdate ¶
func BroadcastTicketUpdate(eventType string, ticketData interface{})
BroadcastTicketUpdate sends an update to all connected clients.
func BuildDynamicFieldFilterSQL ¶
func BuildDynamicFieldFilterSQL(filters []DynamicFieldFilter, startArgNum int) (string, []interface{}, error)
Returns the WHERE clause fragment and arguments to append.
func BuildRoutesManifest ¶
BuildRoutesManifest constructs the manifest JSON without registering routes (for tooling).
func BulkSetScreenConfigForField ¶
BulkSetScreenConfigForField replaces all screen configs for a field.
func CheckDynamicFieldNameExists ¶
CheckDynamicFieldNameExists checks if a field name already exists.
func CheckSignatureNameExists ¶
CheckSignatureNameExists checks if a signature name already exists.
func CheckTemplateNameExists ¶
CheckTemplateNameExists checks if a template name already exists (excluding a specific ID).
func CombineRoutePath ¶ added in v0.8.2
CombineRoutePath joins a route group prefix with a route path.
func CreateDynamicField ¶
func CreateDynamicField(field *DynamicField, userID int) (int64, error)
CreateDynamicField creates a new dynamic field.
func CreateSignature ¶
CreateSignature creates a new signature.
func CreateStandardTemplate ¶
func CreateStandardTemplate(t *StandardTemplate, userID int) (int, error)
CreateStandardTemplate creates a new template.
func CustomerOnlyGuard ¶
func CustomerOnlyGuard(enabled bool) gin.HandlerFunc
CustomerOnlyGuard blocks non-customer paths when enabled, to keep admin/auth UIs off the customer FE.
func DeleteDynamicField ¶
DeleteDynamicField deletes a dynamic field and its values.
func DeleteSignature ¶
DeleteSignature deletes a signature by ID.
func DeleteStandardTemplate ¶
DeleteStandardTemplate deletes a template and its relationships.
func EnsurePluginGroups ¶ added in v0.7.0
func EnsurePluginGroups()
EnsurePluginGroups auto-creates groups declared by plugins in their GKRegistration. Called after plugin loading to ensure the groups exist in the GoatFlow groups table. Idempotent — skips groups that already exist.
func ExportAllSignatures ¶
ExportAllSignatures exports all signatures to YAML.
func ExportDynamicFieldsYAML ¶
ExportDynamicFieldsYAML exports dynamic fields to YAML format.
func ExportSignature ¶
ExportSignature exports a single signature to YAML.
func GenerateRoutesManifest ¶
func GenerateRoutesManifest() error
GenerateRoutesManifest creates a temporary gin engine, registers YAML routes and ensures the manifest file exists. Used by tooling (make routes-generate) without starting full server.
func GetAttachmentTemplateIDs ¶
GetAttachmentTemplateIDs returns template IDs assigned to an attachment.
func GetAuthService ¶
func GetAuthService() *platformservice.AuthService
GetAuthService returns the singleton auth service instance.
func GetDistinctDynamicFieldValues ¶
Useful for populating filter dropdown options.
func GetDynamicFieldsGroupedByObjectType ¶
func GetDynamicFieldsGroupedByObjectType() (map[string][]DynamicField, error)
GetDynamicFieldsGroupedByObjectType returns fields grouped by object type for admin display.
func GetDynamicHandler ¶
func GetDynamicHandler() *dynamic.DynamicModuleHandler
GetDynamicHandler returns the initialized dynamic handler.
func GetHandler ¶
func GetHandler(name string) (gin.HandlerFunc, bool)
GetHandler retrieves a registered handler.
func GetLookupService ¶
func GetLookupService() *service.LookupService
GetLookupService returns the singleton lookup service instance.
func GetPluginManager ¶
GetPluginManager returns the global plugin manager.
func GetPluginMenuItems ¶
func GetPluginMenuItems(location string) []plugin.PluginMenuItem
GetPluginMenuItems returns menu items for a location.
func GetPriorityRepository ¶
func GetPriorityRepository() *repository.PriorityRepository
GetPriorityRepository returns the singleton priority repository instance.
func GetQueueRepository ¶
func GetQueueRepository() *repository.QueueRepository
GetQueueRepository returns the singleton queue repository instance.
func GetQueueTemplateIDs ¶
GetQueueTemplateIDs returns template IDs assigned to a queue.
func GetTemplateAttachments ¶
GetTemplateAttachments returns all attachment IDs assigned to a template.
func GetTemplateQueues ¶
GetTemplateQueues returns all queues assigned to a template.
func GetTicketRepository ¶
func GetTicketRepository() repository.ITicketRepository
GetTicketRepository returns the singleton ticket repository instance.
func GetTicketService ¶
func GetTicketService() *service.SimpleTicketService
GetTicketService returns the singleton simple ticket service instance.
func GetTicketTemplateVariables ¶
GetTicketTemplateVariables returns template variables for a ticket.
func GetUserIDFromCtx ¶
GetUserIDFromCtx extracts the authenticated user's ID from gin context. Handles multiple types since different auth middleware may set different types. Returns the fallback value if user_id is not found or cannot be converted.
func GetUserIDFromCtxUint ¶
GetUserIDFromCtxUint is like GetUserIDFromCtx but returns uint.
func GetUserMapForTemplate ¶
GetUserMapForTemplate exposes the internal user-context builder for reuse across packages without duplicating logic.
func GetUserRepository ¶
func GetUserRepository() *repository.UserRepository
GetUserRepository returns the singleton user repository instance.
func HandleAPIQueueDetails ¶
HandleAPIQueueDetails handles GET /api/queues/:id/details (internal UI API, outside the /api/v1 Swagger base path).
func HandleAPIQueueGet ¶
HandleAPIQueueGet handles GET /api/queues/:id and, through HandleGetQueueAPI, GET /api/v1/queues/:id (documented in api/openapi.yaml).
func HandleAPIQueueStatus ¶
HandleAPIQueueStatus handles PUT /api/queues/:id/status (internal UI API, outside the /api/v1 Swagger base path).
func HandleAPISetupOnboardCustomer ¶ added in v0.9.0
HandleAPISetupOnboardCustomer provisions a full customer setup (company + portal users with generated passwords) from one JSON payload. Lets an LLM or script onboard a customer end-to-end without the wizard UI. POST /api/v1/admin/setup/onboard-customer
func HandleAPISetupRecce ¶ added in v0.9.0
HandleAPISetupRecce returns the system snapshot (entity counts + setup status) as JSON. Lets an LLM or script understand current state. GET /api/v1/admin/setup/recce
func HandleAPISetupTask ¶ added in v0.9.0
HandleAPISetupTask dispatches a plugin setup task, forwarding the JSON body (minus client-supplied envelope keys, plus the host envelope) to the plugin handler. Core tasks use the HTML route (handleAdminSetupTask). POST /api/v1/admin/setup/tasks/:plugin/:task_id
func HandleAPISetupTasks ¶ added in v0.9.0
HandleAPISetupTasks returns the combined core + plugin task catalog. GET /api/v1/admin/setup/tasks
func HandleAPISetupWizard ¶ added in v0.9.0
HandleAPISetupWizard accepts a full WizardRequest JSON payload and creates every entity in dependency order. Does NOT auto-mark setup complete — the caller (UI or LLM) decides by calling the mark-complete task afterwards. POST /api/v1/admin/setup/wizard
func HandleAddTicketTime ¶
HandleAddTicketTime is the exported wrapper for YAML routing in the routing package It delegates to handleAddTicketTime to keep the implementation in one place.
func HandleAdminCreateTargetToken ¶
HandleAdminCreateTargetToken creates a token for a specific user or customer (admin only) POST /api/v1/admin/users/:userId/tokens or /api/v1/admin/customer-users/:customerId/tokens
func HandleAdminCustomerUsersBulkAction ¶
HandleAdminCustomerUsersBulkAction handles POST /admin/customer-users/bulk-action.
func HandleAdminCustomerUsersCreate ¶
HandleAdminCustomerUsersCreate handles POST /admin/customer-users.
func HandleAdminCustomerUsersDelete ¶
HandleAdminCustomerUsersDelete handles DELETE /admin/customer-users/:id (soft delete).
func HandleAdminCustomerUsersExport ¶
HandleAdminCustomerUsersExport handles GET /admin/customer-users/export.
func HandleAdminCustomerUsersGet ¶
HandleAdminCustomerUsersGet handles GET /admin/customer-users/:id.
func HandleAdminCustomerUsersImport ¶
HandleAdminCustomerUsersImport handles POST /admin/customer-users/import.
func HandleAdminCustomerUsersImportForm ¶
HandleAdminCustomerUsersImportForm handles GET /admin/customer-users/import.
func HandleAdminCustomerUsersList ¶
HandleAdminCustomerUsersList handles GET /admin/customer-users.
func HandleAdminCustomerUsersTickets ¶
HandleAdminCustomerUsersTickets handles GET /admin/customer-users/:id/tickets.
func HandleAdminCustomerUsersUpdate ¶
HandleAdminCustomerUsersUpdate handles PUT /admin/customer-users/:id.
func HandleAdminDynamicModuleFor ¶
func HandleAdminDynamicModuleFor(module string) gin.HandlerFunc
HandleAdminDynamicModuleFor returns a handler that forces the module param to a static value.
func HandleAdminExecuteSQL ¶ added in v0.8.2
HandleAdminExecuteSQL executes a read-only SQL query. Requires admin middleware. Only allowlisted statement types are permitted: SELECT, DESCRIBE, EXPLAIN, SHOW TABLES, SHOW COLUMNS.
@Summary Execute read-only SQL query
@Description Execute a read-only SQL query (admin only). Allowed statements: SELECT, DESCRIBE, EXPLAIN, SHOW TABLES, SHOW COLUMNS.
@Tags Admin
@Accept json
@Produce json
@Param request body adminSQLRequest true "SQL query and optional arguments"
@Success 200 {object} map[string]interface{} "Query results"
@Failure 400 {object} map[string]interface{} "Bad request"
@Failure 403 {object} map[string]interface{} "Forbidden"
@Security BearerAuth
@Router /admin/sql [post]
func HandleAdminGroupsAddUser ¶
HandleAdminGroupsAddUser handles POST /admin/groups/:id/users.
func HandleAdminGroupsCreate ¶
HandleAdminGroupsCreate handles POST /admin/groups.
func HandleAdminGroupsDelete ¶
HandleAdminGroupsDelete handles DELETE /admin/groups/:id.
func HandleAdminGroupsRemoveUser ¶
HandleAdminGroupsRemoveUser handles DELETE /admin/groups/:id/users/:userId.
func HandleAdminGroupsUpdate ¶
HandleAdminGroupsUpdate handles PUT /admin/groups/:id.
func HandleAdminGroupsUsers ¶
HandleAdminGroupsUsers handles GET /admin/groups/:id/users.
func HandleAdminListAllTokens ¶
HandleAdminListAllTokens returns all tokens (admin only) GET /api/v1/admin/tokens
func HandleAdminListTargetTokens ¶
HandleAdminListTargetTokens returns tokens for a specific user or customer (admin only) GET /api/v1/admin/users/:userId/tokens or /api/v1/admin/customer-users/:customerId/tokens
func HandleAdminMarketplace ¶ added in v0.9.0
HandleAdminMarketplace renders the marketplace browser page.
func HandleAdminNotificationEventEdit ¶
HandleAdminNotificationEventEdit renders the notification event edit form.
func HandleAdminNotificationEventGet ¶
HandleAdminNotificationEventGet returns a notification event's details as JSON.
func HandleAdminNotificationEventNew ¶
HandleAdminNotificationEventNew renders the new notification event form.
func HandleAdminNotificationEvents ¶
HandleAdminNotificationEvents renders the notification events management page.
func HandleAdminPluginLogs ¶
HandleAdminPluginLogs renders the plugin logs page. Data is fetched client-side from /api/v1/plugins/logs.
func HandleAdminPluginUIs ¶ added in v0.8.3
HandleAdminPluginUIs renders the plugin UI management page.
func HandleAdminPlugins ¶
HandleAdminPlugins renders the plugin management page. Data is fetched client-side from /api/v1/plugins.
func HandleAdminPostmasterFilterEdit ¶
handleAdminPostmasterFilterEdit renders the filter edit form.
func HandleAdminPostmasterFilterGet ¶
handleAdminPostmasterFilterGet returns a filter's details as JSON.
func HandleAdminPostmasterFilterNew ¶
handleAdminPostmasterFilterNew renders the new filter creation form.
func HandleAdminPostmasterFilters ¶
handleAdminPostmasterFilters renders the postmaster filters management page.
func HandleAdminRevokeTargetToken ¶
HandleAdminRevokeTargetToken revokes a specific user's or customer's token (admin only) DELETE /api/v1/admin/users/:userId/tokens/:tokenId or /api/v1/admin/customer-users/:customerId/tokens/:tokenId
func HandleAdminRevokeToken ¶
HandleAdminRevokeToken revokes any token (admin only) DELETE /api/v1/admin/tokens/:id
func HandleAdminTickets ¶
HandleAdminTickets displays all tickets for admin management.
func HandleAdminUserCreate ¶
HandleAdminUserCreate handles POST /admin/users.
func HandleAdminUserDelete ¶
HandleAdminUserDelete handles DELETE /admin/users/:id.
func HandleAdminUserGet ¶
HandleAdminUserGet handles GET /admin/users/:id.
func HandleAdminUserGroups ¶
HandleAdminUserGroups handles GET /admin/users/:id/groups.
func HandleAdminUserResetPassword ¶
HandleAdminUserResetPassword handles password reset for a user by admin.
func HandleAdminUserUpdate ¶
HandleAdminUserUpdate handles PUT /admin/users/:id.
func HandleAdminUsers ¶
HandleAdminUsers renders the admin users management page.
func HandleAdminUsersList ¶
HandleAdminUsersList handles GET /admin/users (JSON API).
func HandleAdminUsersStatus ¶
HandleAdminUsersStatus handles PUT /admin/users/:id/status to toggle user valid status.
func HandleAgentChangePassword ¶
HandleAgentChangePassword processes the agent password change request.
func HandleAgentCreateTicket ¶
func HandleAgentCreateTicket(db *sql.DB) gin.HandlerFunc
HandleAgentCreateTicket creates a new ticket from the agent interface.
func HandleAgentNewTicket ¶
func HandleAgentNewTicket(db *sql.DB) gin.HandlerFunc
HandleAgentNewTicket displays the agent ticket creation form with necessary data.
func HandleAgentPasswordForm ¶
HandleAgentPasswordForm renders the agent password change form.
func HandleAgentPerformanceAPI ¶
HandleAgentPerformanceAPI handles GET /api/v1/statistics/agents.
Admins get every valid agent, including agents with no activity. Other agents get only the agents with activity (assigned, closed or articles) on tickets in the queues they can read: those agents are already visible on those tickets, while the full roster is not.
@Summary Get agent performance
@Description Per-agent tickets assigned, tickets closed and articles created in the period (RBAC filtered). Admins see every valid agent; other agents see only agents with activity on tickets in queues they can read.
@Tags Statistics
@Accept json
@Produce json
@Param period query string false "Rolling window ending now" Enums(24h, 7d, 30d) default(7d)
@Success 200 {object} map[string]interface{} "period, agents[], top_performers[]"
@Failure 400 {object} map[string]interface{} "Invalid parameter"
@Failure 401 {object} map[string]interface{} "Unauthorized"
@Failure 403 {object} map[string]interface{} "Customer caller or no readable queue"
@Failure 500 {object} map[string]interface{} "Database error"
@Security BearerAuth
@Router /statistics/agents [get]
func HandleAssignQueueGroupAPI ¶
HandleAssignQueueGroupAPI handles POST /api/v1/queues/:id/groups.
@Summary Set queue group
@Description Make the given group the queue's permission group (queue.group_id), replacing the current one. A queue has exactly one group.
@Tags Queues
@Accept json
@Produce json
@Param id path int true "Queue ID"
@Param group body object true "Group assignment (group_id)"
@Success 200 {object} map[string]interface{} "Group assigned"
@Failure 400 {object} map[string]interface{} "Invalid request or group"
@Failure 401 {object} map[string]interface{} "Unauthorized"
@Failure 404 {object} map[string]interface{} "Queue not found"
@Security BearerAuth
@Router /queues/{id}/groups [post]
func HandleAssignTicketAPI ¶
HandleAssignTicketAPI handles ticket assignment via API. No production route serves it.
func HandleClearPluginLogs ¶
HandleClearPluginLogs clears the plugin log buffer. DELETE /api/v1/plugins/logs
func HandleCloseTicketAPI ¶
HandleCloseTicketAPI handles ticket closure via API. No production route serves it.
func HandleCreateArticleAPI ¶
HandleCreateArticleAPI handles POST /api/v1/tickets/:ticket_id/articles.
@Summary Create article
@Description Add a new article (reply/note) to a ticket
@Tags Articles
@Accept json
@Produce json
@Param ticket_id path int true "Ticket ID"
@Param article body object true "Article data (body, subject, article_type, sender_type, etc.)"
@Success 201 {object} map[string]interface{} "Created article"
@Failure 400 {object} map[string]interface{} "Invalid request"
@Failure 401 {object} map[string]interface{} "Unauthorized"
@Failure 404 {object} map[string]interface{} "Ticket not found"
@Security BearerAuth
@Router /tickets/{ticket_id}/articles [post]
func HandleCreateInternalNote ¶
HandleCreateInternalNote creates a new internal note.
func HandleCreateNotificationEvent ¶
HandleCreateNotificationEvent creates a new notification event.
func HandleCreatePostmasterFilter ¶
handleCreatePostmasterFilter creates a new postmaster filter.
func HandleCreatePriorityAPI ¶
HandleCreatePriorityAPI handles POST /api/v1/priorities.
@Summary Create priority
@Description Create a new ticket priority
@Tags Priorities
@Accept json
@Produce json
@Param priority body object true "Priority data"
@Success 201 {object} map[string]interface{} "Created priority"
@Failure 400 {object} map[string]interface{} "Invalid request"
@Failure 401 {object} map[string]interface{} "Unauthorized"
@Security BearerAuth
@Router /priorities [post]
func HandleCreateQueueAPI ¶
HandleCreateQueueAPI handles POST /api/v1/queues.
@Summary Create queue
@Description Create a new queue
@Tags Queues
@Accept json
@Produce json
@Param queue body object true "Queue data (name, group_id, etc.)"
@Success 201 {object} map[string]interface{} "Created queue"
@Failure 400 {object} map[string]interface{} "Invalid request"
@Failure 401 {object} map[string]interface{} "Unauthorized"
@Security BearerAuth
@Router /queues [post]
func HandleCreateSalutationAPI ¶
HandleCreateSalutationAPI handles POST /api/v1/salutations.
@Summary Create salutation
@Description Create a new email salutation
@Tags Email Identity
@Accept json
@Produce json
@Param salutation body object true "Salutation data"
@Success 201 {object} map[string]interface{} "Created salutation"
@Failure 400 {object} map[string]interface{} "Invalid request"
@Failure 401 {object} map[string]interface{} "Unauthorized"
@Security BearerAuth
@Router /salutations [post]
func HandleCreateSavedSearchAPI ¶ added in v0.10.0
HandleCreateSavedSearchAPI saves a ticket search under a new name.
@Summary Create saved search
@Tags Search
@Accept json
@Produce json
@Param search body object true "{name, type: TicketSearch (optional), parameters: {<search parameter>: string | [string]}}"
@Success 201 {object} map[string]interface{} "{success, data: {name, type, parameters}}"
@Failure 400 {object} map[string]interface{} "Invalid name or parameters"
@Failure 409 {object} map[string]interface{} "Name already used"
@Security BearerAuth
@Router /search/saved [post]
func HandleCreateSignatureAPI ¶
HandleCreateSignatureAPI handles POST /api/v1/signatures.
@Summary Create signature
@Description Create a new email signature
@Tags Email Identity
@Accept json
@Produce json
@Param signature body object true "Signature data"
@Success 201 {object} map[string]interface{} "Created signature"
@Failure 400 {object} map[string]interface{} "Invalid request"
@Failure 401 {object} map[string]interface{} "Unauthorized"
@Security BearerAuth
@Router /signatures [post]
func HandleCreateSystemAddressAPI ¶
HandleCreateSystemAddressAPI handles POST /api/v1/system-addresses.
@Summary Create system address
@Description Create a new system email address
@Tags Email Identity
@Accept json
@Produce json
@Param address body object true "System address data"
@Success 201 {object} map[string]interface{} "Created address"
@Failure 400 {object} map[string]interface{} "Invalid request"
@Failure 401 {object} map[string]interface{} "Unauthorized"
@Security BearerAuth
@Router /system-addresses [post]
func HandleCreateTicketAPI ¶
HandleCreateTicketAPI handles ticket creation via API.
@Summary Create ticket
@Description Create a new ticket with optional initial article
@Tags Tickets
@Accept json
@Produce json
@Param ticket body object true "Ticket data (title, queue_id, priority_id, customer_user_id, article)"
@Success 201 {object} map[string]interface{} "Created ticket"
@Failure 400 {object} map[string]interface{} "Invalid request"
@Failure 401 {object} map[string]interface{} "Unauthorized"
@Security BearerAuth
@Router /tickets [post]
func HandleCreateToken ¶
HandleCreateToken creates a new API token (agent or customer) POST /api/v1/tokens or /customer/api/v1/tokens
@Summary Create API token
@Description Create a new API token for the authenticated user
@Tags API Tokens
@Accept json
@Produce json
@Param token body object true "Token data (name, scopes, expires_at)"
@Success 201 {object} map[string]interface{} "Created token (includes raw token - save it!)"
@Failure 400 {object} map[string]interface{} "Invalid request"
@Failure 401 {object} map[string]interface{} "Unauthorized"
@Security BearerAuth
@Router /tokens [post]
func HandleCustomerStatisticsAPI ¶
HandleCustomerStatisticsAPI handles GET /api/v1/statistics/customers.
@Summary Get customer statistics
@Description All-time top customers by ticket count and customer totals (RBAC filtered)
@Tags Statistics
@Accept json
@Produce json
@Param top query int false "Number of top customers returned" minimum(1) maximum(100) default(10)
@Success 200 {object} map[string]interface{} "top_customers[], customer_metrics"
@Failure 400 {object} map[string]interface{} "Invalid parameter"
@Failure 401 {object} map[string]interface{} "Unauthorized"
@Failure 403 {object} map[string]interface{} "Customer caller or no readable queue"
@Failure 500 {object} map[string]interface{} "Database error"
@Security BearerAuth
@Router /statistics/customers [get]
func HandleDashboardStatisticsAPI ¶
HandleDashboardStatisticsAPI handles GET /api/v1/statistics/dashboard.
@Summary Get dashboard statistics
@Description All-time ticket counts by state bucket, valid queue and valid priority, plus the 10 newest tickets (RBAC filtered)
@Tags Statistics
@Accept json
@Produce json
@Success 200 {object} map[string]interface{} "overview, by_queue[], by_priority[], recent_activity[]"
@Failure 401 {object} map[string]interface{} "Unauthorized"
@Failure 403 {object} map[string]interface{} "Customer caller or no readable queue"
@Failure 500 {object} map[string]interface{} "Database error"
@Security BearerAuth
@Router /statistics/dashboard [get]
func HandleDebugConfigSources ¶
HandleDebugConfigSources lists configuration settings with their source.
func HandleDebugTicketNumber ¶
HandleDebugTicketNumber returns current ticket number generator info.
func HandleDeleteArticleAPI ¶
HandleDeleteArticleAPI handles DELETE /api/v1/tickets/:ticket_id/articles/:id.
@Summary Delete article
@Description Delete an article, its MIME data and attachments from a ticket
@Tags Articles
@Accept json
@Produce json
@Param ticket_id path int true "Ticket ID"
@Param id path int true "Article ID"
@Success 200 {object} map[string]interface{} "Article deleted"
@Failure 401 {object} map[string]interface{} "Unauthorized"
@Failure 404 {object} map[string]interface{} "Article not found"
@Security BearerAuth
@Router /tickets/{ticket_id}/articles/{id} [delete]
func HandleDeleteInternalNote ¶
HandleDeleteInternalNote deletes an internal note (the underlying article).
func HandleDeleteNotificationEvent ¶
HandleDeleteNotificationEvent deletes a notification event.
func HandleDeletePostmasterFilter ¶
handleDeletePostmasterFilter deletes a postmaster filter.
func HandleDeletePriorityAPI ¶
HandleDeletePriorityAPI handles DELETE /api/v1/priorities/:id.
@Summary Delete priority
@Description Delete a priority
@Tags Priorities
@Accept json
@Produce json
@Param id path int true "Priority ID"
@Success 200 {object} map[string]interface{} "Priority deleted"
@Failure 401 {object} map[string]interface{} "Unauthorized"
@Failure 404 {object} map[string]interface{} "Priority not found"
@Security BearerAuth
@Router /priorities/{id} [delete]
func HandleDeleteQueueAPI ¶
HandleDeleteQueueAPI handles DELETE /api/v1/queues/:id.
@Summary Delete queue
@Description Delete a queue (soft delete)
@Tags Queues
@Accept json
@Produce json
@Param id path int true "Queue ID"
@Success 200 {object} map[string]interface{} "Queue deleted"
@Failure 401 {object} map[string]interface{} "Unauthorized"
@Failure 404 {object} map[string]interface{} "Queue not found"
@Security BearerAuth
@Router /queues/{id} [delete]
func HandleDeleteSavedSearchAPI ¶ added in v0.10.0
HandleDeleteSavedSearchAPI deletes a saved search.
@Summary Delete saved search
@Tags Search
@Param name path string true "Saved search name"
@Success 204
@Failure 404 {object} map[string]interface{} "Not found"
@Security BearerAuth
@Router /search/saved/{name} [delete]
func HandleDeleteTicketAPI ¶
HandleDeleteTicketAPI handles DELETE /api/v1/tickets/:id. In OTRS, tickets are never hard deleted, only archived.
@Summary Delete (archive) ticket
@Description Archive a ticket (soft delete - tickets are never hard deleted)
@Tags Tickets
@Accept json
@Produce json
@Param id path int true "Ticket ID"
@Success 200 {object} map[string]interface{} "Ticket archived"
@Failure 401 {object} map[string]interface{} "Unauthorized"
@Failure 404 {object} map[string]interface{} "Ticket not found"
@Security BearerAuth
@Router /tickets/{id} [delete]
func HandleDetailedHealthCheck ¶ added in v0.10.0
HandleDetailedHealthCheck reports every probeable component plus uptime and build information. It is admin-gated at route level (routes/basic.yaml): an operator endpoint, not a probe target — /health covers Docker/TrueNAS/k8s probes and stays public.
func HandleDismissCoachmark ¶
HandleDismissCoachmark records a coachmark as dismissed for the current user.
func HandleExecuteSavedSearchAPI ¶ added in v0.10.0
HandleExecuteSavedSearchAPI runs a saved search. Paging and ordering come from the query string (page, limit, sort, order).
@Summary Execute saved search
@Tags Search
@Produce json
@Param name path string true "Saved search name"
@Success 200 {object} map[string]interface{} "{success, data: {name, parameters, ignored_parameters, tickets, pagination}}"
@Failure 404 {object} map[string]interface{} "Not found"
@Security BearerAuth
@Router /search/saved/{name}/execute [post]
func HandleExportStatisticsAPI ¶
HandleExportStatisticsAPI handles GET /api/v1/statistics/export.
@Summary Export statistics
@Description Download a summary or the ticket list for tickets created in the period, as JSON or CSV (RBAC filtered)
@Tags Statistics
@Accept json
@Produce json
@Produce text/csv
@Param format query string false "File format" Enums(json, csv) default(json)
@Param type query string false "Export content" Enums(summary, tickets) default(summary)
@Param period query string false "Rolling window ending now" Enums(24h, 7d, 30d) default(7d)
@Success 200 {file} file "statistics_<YYYYMMDD_HHMMSS>.json or .csv attachment"
@Failure 400 {object} map[string]interface{} "Invalid parameter"
@Failure 401 {object} map[string]interface{} "Unauthorized"
@Failure 403 {object} map[string]interface{} "Customer caller or no readable queue"
@Failure 500 {object} map[string]interface{} "Database error"
@Security BearerAuth
@Router /statistics/export [get]
func HandleGetArticleAPI ¶
HandleGetArticleAPI handles GET /api/v1/tickets/:ticket_id/articles/:id.
@Summary Get article by ID
@Description Retrieve a single article by its ID
@Tags Articles
@Accept json
@Produce json
@Param ticket_id path int true "Ticket ID"
@Param id path int true "Article ID"
@Param include_attachments query bool false "Include attachment metadata"
@Success 200 {object} map[string]interface{} "Article details"
@Failure 401 {object} map[string]interface{} "Unauthorized"
@Failure 404 {object} map[string]interface{} "Article not found"
@Security BearerAuth
@Router /tickets/{ticket_id}/articles/{id} [get]
func HandleGetAvailableLanguages ¶
HandleGetAvailableLanguages returns the list of supported languages (public, no auth required). Used on login pages to allow language selection before authentication.
func HandleGetAvailableThemes ¶
HandleGetAvailableThemes returns the list of available themes (public, no auth required). Used on login pages to allow theme selection before authentication.
func HandleGetFormData ¶
HandleGetFormData returns form data for ticket creation as JSON.
func HandleGetInternalNotes ¶
HandleGetInternalNotes returns internal notes for a ticket.
func HandleGetLanguage ¶
HandleGetLanguage retrieves the user's language preference.
func HandleGetPriorities ¶
HandleGetPriorities returns list of priorities as JSON or HTML options for HTMX.
func HandleGetPriorityAPI ¶
HandleGetPriorityAPI handles GET /api/v1/priorities/:id.
@Summary Get priority by ID
@Description Retrieve a single priority
@Tags Priorities
@Accept json
@Produce json
@Param id path int true "Priority ID"
@Success 200 {object} map[string]interface{} "Priority details"
@Failure 401 {object} map[string]interface{} "Unauthorized"
@Failure 404 {object} map[string]interface{} "Priority not found"
@Security BearerAuth
@Router /priorities/{id} [get]
func HandleGetProfile ¶
HandleGetProfile retrieves the current user's profile information.
func HandleGetQueueAPI ¶
HandleGetQueueAPI handles GET /api/v1/queues/:id.
@Summary Get queue by ID
@Description Retrieve a single queue by its ID
@Tags Queues
@Accept json
@Produce json
@Param id path int true "Queue ID"
@Success 200 {object} map[string]interface{} "Queue details"
@Failure 401 {object} map[string]interface{} "Unauthorized"
@Failure 404 {object} map[string]interface{} "Queue not found"
@Security BearerAuth
@Router /queues/{id} [get]
func HandleGetQueueAgentsAPI ¶
HandleGetQueueAgentsAPI handles GET /api/v1/queues/:id/agents.
@Summary Get queue agents
@Description List agents assigned to a queue
@Tags Queues
@Accept json
@Produce json
@Param id path int true "Queue ID"
@Success 200 {object} map[string]interface{} "List of agents"
@Failure 401 {object} map[string]interface{} "Unauthorized"
@Failure 404 {object} map[string]interface{} "Queue not found"
@Security BearerAuth
@Router /queues/{id}/agents [get]
func HandleGetQueueStatsAPI ¶
HandleGetQueueStatsAPI handles GET /api/v1/queues/:id/stats.
@Summary Get queue statistics
@Description Get ticket statistics for a queue
@Tags Queues
@Accept json
@Produce json
@Param id path int true "Queue ID"
@Success 200 {object} map[string]interface{} "Queue statistics"
@Failure 401 {object} map[string]interface{} "Unauthorized"
@Failure 404 {object} map[string]interface{} "Queue not found"
@Security BearerAuth
@Router /queues/{id}/stats [get]
func HandleGetQueues ¶
HandleGetQueues returns list of queues as JSON or HTML options for HTMX.
func HandleGetRemindersEnabled ¶ added in v0.7.0
HandleGetRemindersEnabled retrieves the user's reminders enabled preference.
func HandleGetSavedSearchAPI ¶ added in v0.10.0
HandleGetSavedSearchAPI returns one saved search.
@Summary Get saved search
@Tags Search
@Produce json
@Param name path string true "Saved search name"
@Success 200 {object} map[string]interface{} "{success, data: {name, type, parameters, ignored_parameters}}"
@Failure 404 {object} map[string]interface{} "Not found"
@Security BearerAuth
@Router /search/saved/{name} [get]
func HandleGetScopes ¶
HandleGetScopes returns available scopes for token creation GET /api/v1/tokens/scopes Scopes are filtered based on the user's role and type
@Summary Get available scopes
@Description List available scopes for token creation (filtered by user role)
@Tags API Tokens
@Accept json
@Produce json
@Success 200 {object} map[string]interface{} "List of available scopes"
@Failure 401 {object} map[string]interface{} "Unauthorized"
@Security BearerAuth
@Router /tokens/scopes [get]
func HandleGetSessionTimeout ¶
HandleGetSessionTimeout retrieves the user's session timeout preference.
func HandleGetStatuses ¶
HandleGetStatuses returns list of ticket statuses as JSON.
func HandleGetTheme ¶
HandleGetTheme retrieves the user's theme preferences. Uses UserPreferencesService for agents/admins, CustomerPreferencesService for customers.
func HandleGetTicketAPI ¶
HandleGetTicketAPI handles GET /api/v1/tickets/:id.
@Summary Get ticket by ID
@Description Retrieve a single ticket by its ID with optional related data
@Tags Tickets
@Accept json
@Produce json
@Param id path int true "Ticket ID"
@Param include query string false "Include related data (comma-separated: articles, customer, queue)"
@Success 200 {object} map[string]interface{} "Ticket details"
@Failure 401 {object} map[string]interface{} "Unauthorized"
@Failure 404 {object} map[string]interface{} "Ticket not found"
@Security BearerAuth
@Router /tickets/{id} [get]
func HandleGetTypes ¶
HandleGetTypes returns the valid ticket_type rows (id/value/label/order/active) as JSON, or as HTML <option> elements (value = type id) for HTMX.
func HandleHealthCheck ¶ added in v0.10.0
HandleHealthCheck is the liveness/readiness probe used by the Dockerfile HEALTHCHECK, the TrueNAS app template and Kubernetes probes. It performs a real (short-timeout) database ping so a backend with a dead DB reports 503 instead of a misleading "healthy".
func HandleInvalidateLookupCache ¶
HandleInvalidateLookupCache forces a refresh of the lookup cache.
func HandleLegacyAgentTicketViewRedirect ¶
HandleLegacyAgentTicketViewRedirect exported for YAML routing.
func HandleLegacyTicketsViewRedirect ¶
HandleLegacyTicketsViewRedirect exported for YAML routing.
func HandleListArticlesAPI ¶
HandleListArticlesAPI handles GET /api/v1/tickets/:ticket_id/articles.
@Summary List ticket articles
@Description Retrieve all articles for a ticket, newest first
@Tags Articles
@Accept json
@Produce json
@Param ticket_id path int true "Ticket ID"
@Param include_attachments query bool false "Include attachment metadata"
@Success 200 {object} map[string]interface{} "List of articles"
@Failure 401 {object} map[string]interface{} "Unauthorized"
@Failure 404 {object} map[string]interface{} "Ticket not found"
@Security BearerAuth
@Router /tickets/{ticket_id}/articles [get]
func HandleListGroupsAPI ¶
HandleListGroupsAPI handles GET /api/v1/groups.
@Summary List groups
@Description Retrieve all groups
@Tags Groups
@Accept json
@Produce json
@Success 200 {object} map[string]interface{} "List of groups"
@Failure 401 {object} map[string]interface{} "Unauthorized"
@Security BearerAuth
@Router /groups [get]
func HandleListPrioritiesAPI ¶
HandleListPrioritiesAPI handles GET /api/v1/priorities. Supports optional filtering via ticket attribute relations:
- filter_attribute: The attribute to filter by (e.g., "Queue", "State")
- filter_value: The value of that attribute (e.g., "Sales", "new")
HandleListPrioritiesAPI handles GET /api/v1/priorities.
@Summary List priorities
@Description Retrieve all ticket priorities
@Tags Priorities
@Accept json
@Produce json
@Success 200 {object} map[string]interface{} "List of priorities"
@Failure 401 {object} map[string]interface{} "Unauthorized"
@Security BearerAuth
@Router /priorities [get]
func HandleListQueuesAPI ¶
HandleListQueuesAPI handles GET /api/v1/queues.
@Summary List queues
@Description Retrieve all queues the user has access to (RBAC filtered)
@Tags Queues
@Accept json
@Produce json
@Param page query int false "Page number" default(1)
@Param per_page query int false "Items per page" default(20)
@Success 200 {object} map[string]interface{} "List of queues"
@Failure 401 {object} map[string]interface{} "Unauthorized"
@Security BearerAuth
@Router /queues [get]
func HandleListSalutationsAPI ¶
HandleListSalutationsAPI handles GET /api/v1/salutations.
@Summary List salutations
@Description List all email salutations
@Tags Email Identity
@Accept json
@Produce json
@Success 200 {object} map[string]interface{} "List of salutations"
@Failure 401 {object} map[string]interface{} "Unauthorized"
@Security BearerAuth
@Router /salutations [get]
func HandleListSavedSearchesAPI ¶ added in v0.10.0
HandleListSavedSearchesAPI lists the caller's saved ticket searches.
@Summary List saved searches
@Tags Search
@Produce json
@Success 200 {object} map[string]interface{} "{success, data: {searches: [{name, type}], total}}"
@Security BearerAuth
@Router /search/saved [get]
func HandleListServicesAPI ¶
HandleListServicesAPI handles GET /api/v1/services. Supports optional filtering via ticket attribute relations:
- filter_attribute: The attribute to filter by (e.g., "Queue", "Type")
- filter_value: The value of that attribute (e.g., "Sales", "incident")
- valid: Filter by valid_id (1 = valid, 2 = invalid, "all" = no filter)
HandleListServicesAPI handles GET /api/v1/services.
@Summary List services
@Description Retrieve all services
@Tags Services
@Accept json
@Produce json
@Param valid query string false "Filter by validity (1=valid, 2=invalid, all)"
@Success 200 {object} map[string]interface{} "List of services"
@Failure 401 {object} map[string]interface{} "Unauthorized"
@Security BearerAuth
@Router /services [get]
func HandleListSignaturesAPI ¶
HandleListSignaturesAPI handles GET /api/v1/signatures.
@Summary List signatures
@Description List all email signatures
@Tags Email Identity
@Accept json
@Produce json
@Success 200 {object} map[string]interface{} "List of signatures"
@Failure 401 {object} map[string]interface{} "Unauthorized"
@Security BearerAuth
@Router /signatures [get]
func HandleListStatesAPI ¶
HandleListStatesAPI handles GET /api/v1/states. Supports optional filtering via ticket attribute relations:
- filter_attribute: The attribute to filter by (e.g., "Queue", "Priority")
- filter_value: The value of that attribute (e.g., "Sales", "new")
HandleListStatesAPI handles GET /api/v1/states.
@Summary List states
@Description Retrieve all ticket states
@Tags States
@Accept json
@Produce json
@Success 200 {object} map[string]interface{} "List of states"
@Failure 401 {object} map[string]interface{} "Unauthorized"
@Security BearerAuth
@Router /states [get]
func HandleListSystemAddressesAPI ¶
HandleListSystemAddressesAPI handles GET /api/v1/system-addresses.
@Summary List system addresses
@Description List all system email addresses
@Tags Email Identity
@Accept json
@Produce json
@Success 200 {object} map[string]interface{} "List of system addresses"
@Failure 401 {object} map[string]interface{} "Unauthorized"
@Security BearerAuth
@Router /system-addresses [get]
func HandleListTicketsAPI ¶
HandleListTicketsAPI handles GET /api/v1/tickets.
@Summary List tickets
@Description Retrieve a paginated list of tickets with optional filtering, sorting, and search
@Tags Tickets
@Accept json
@Produce json
@Param page query int false "Page number" default(1)
@Param per_page query int false "Items per page (max 100)" default(20)
@Param limit query int false "Alias for per_page (max 100)" default(20)
@Param offset query int false "Offset for pagination (alternative to page)"
@Param status query string false "Filter by status" Enums(open, closed, pending)
@Param queue_id query int false "Filter by queue ID"
@Param priority_id query int false "Filter by priority ID"
@Param customer_user_id query string false "Filter by customer user ID/login"
@Param assigned_user_id query int false "Filter by assigned agent user ID"
@Param search query string false "Search in ticket number, title, customer"
@Param sort query string false "Sort field" Enums(created, updated, priority, tn) default(created)
@Param order query string false "Sort order" Enums(asc, desc) default(desc)
@Param include query string false "Include related data (comma-separated: article_count, last_article)"
@Success 200 {object} map[string]interface{} "List of tickets with pagination"
@Failure 401 {object} map[string]interface{} "Unauthorized"
@Failure 500 {object} map[string]interface{} "Internal server error"
@Security BearerAuth
@Router /tickets [get]
func HandleListTokens ¶
HandleListTokens returns all tokens for the current user (agent or customer) GET /api/v1/tokens or /customer/api/v1/tokens
@Summary List my API tokens
@Description List all API tokens for the authenticated user
@Tags API Tokens
@Accept json
@Produce json
@Success 200 {object} map[string]interface{} "List of tokens"
@Failure 401 {object} map[string]interface{} "Unauthorized"
@Security BearerAuth
@Router /tokens [get]
func HandleListTypesAPI ¶
HandleListTypesAPI handles GET /api/v1/types. Supports optional filtering via ticket attribute relations:
- filter_attribute: The attribute to filter by (e.g., "Queue", "Service")
- filter_value: The value of that attribute (e.g., "Sales", "Gold Support")
The list is restricted to valid types unless ?valid=false|0 or ?valid=all is given.
@Summary List types
@Description Retrieve ticket types (valid ones by default)
@Tags Types
@Accept json
@Produce json
@Param valid query string false "Filter by validity (true/1 = valid (default), false/0 = invalid, all)"
@Success 200 {object} map[string]interface{} "List of types"
@Failure 401 {object} map[string]interface{} "Unauthorized"
@Failure 500 {object} map[string]interface{} "Lookup failed"
@Security BearerAuth
@Router /types [get]
func HandleMCP ¶
HandleMCP handles POST /api/mcp for MCP JSON-RPC messages. Requires Bearer token authentication via API token. Documented in docs/api/MCP.md (the route is outside the /api/v1 Swagger base path).
func HandleMCPInfo ¶
HandleMCPInfo returns information about the MCP endpoint.
func HandleMCPSSE ¶ added in v0.8.2
HandleMCPSSE handles POST /api/mcp/sse for MCP Streamable HTTP transport. Creates sessions on "initialize", processes JSON-RPC messages on subsequent requests. Documented in docs/api/MCP.md (outside the /api/v1 Swagger base path).
func HandleMCPSSEDelete ¶ added in v0.8.2
HandleMCPSSEDelete handles DELETE /api/mcp/sse for session termination.
func HandleMCPSSEStream ¶ added in v0.8.2
HandleMCPSSEStream handles GET /api/mcp/sse for server→client SSE notification stream.
func HandleMailAccountPollStatus ¶
HandleMailAccountPollStatus returns the last poll status for a mail account from Valkey.
func HandleMarketplaceIndex ¶ added in v0.9.0
HandleMarketplaceIndex returns the marketplace index annotated with install state and per-version compatibility with this GoatFlow. GET /api/v1/plugins/marketplace
func HandleMarketplaceInstall ¶ added in v0.9.0
HandleMarketplaceInstall downloads, verifies, and installs a plugin from the marketplace. POST /api/v1/plugins/marketplace/install {"name": "goat-kb", "version": "1.2.0"} version is optional: without it a new install gets the newest version this GoatFlow can run and an installed plugin gets its newest compatible update.
func HandleMarketplaceSearch ¶ added in v0.9.0
HandleMarketplaceSearch searches the marketplace index. GET /api/v1/plugins/marketplace/search?q=knowledge
func HandleMetrics ¶ added in v0.10.0
HandleMetrics serves the Prometheus exposition format from the default registerer. Cache metrics (cache_hits_total, cache_misses_total, cache_errors_total, cache_set_total, cache_delete_total, cache_latency_seconds, cache_size) are already recorded into the default registry by the Valkey cache via promauto, so they appear here with no extra wiring.
func HandlePasswordPolicy ¶
HandlePasswordPolicy returns the agent password policy (PreferencesGroups###Password) that admin-set and self-chosen agent passwords are validated against.
func HandlePluginCall ¶
HandlePluginCall invokes a plugin function directly, bypassing the plugin's own route middleware, so it is mounted admin-only. POST /api/v1/plugins/:name/call/:fn
func HandlePluginDisable ¶
HandlePluginDisable disables a plugin. POST /api/v1/plugins/:name/disable
func HandlePluginEnable ¶
HandlePluginEnable enables a plugin. POST /api/v1/plugins/:name/enable
func HandlePluginHealth ¶ added in v0.8.3
HandlePluginHealth returns the live health snapshot for every loaded plugin. Used by the admin UI's plugin-health widget to show which plugins are healthy, in restart backoff, or abandoned. Includes the optional rich payload that plugins return from their __health_ping__ handler. GET /api/v1/plugins/health
func HandlePluginList ¶
HandlePluginList returns all registered plugins. GET /api/v1/plugins
func HandlePluginLogs ¶
HandlePluginLogs returns plugin log entries. GET /api/v1/plugins/logs?plugin=name&level=info&limit=100
func HandlePluginResetCrashLoop ¶ added in v0.8.3
HandlePluginResetCrashLoop clears the crash-loop-abandoned flag for a plugin so auto-recovery can resume. Called by the admin UI after the operator has fixed the underlying problem (replaced a broken binary, patched a config error, etc.). POST /api/v1/plugins/:name/reset-crashloop
func HandlePluginSSEChannel ¶ added in v0.8.1
HandlePluginSSEChannel serves an SSE stream scoped to a specific plugin and channel. GET /api/v1/plugins/:name/events/:channel Agents only (route group). When the plugin declares an EventAuthorizer, the plugin decides per caller and channel before the stream is opened.
func HandlePluginUIAdminList ¶ added in v0.8.3
HandlePluginUIAdminList returns all registered plugin UIs for administrators.
func HandlePluginUIAdminToggle ¶ added in v0.8.3
HandlePluginUIAdminToggle enables or disables a plugin UI.
func HandlePluginUIAdminUpdate ¶ added in v0.8.3
HandlePluginUIAdminUpdate updates admin-managed UI settings.
func HandlePluginUninstall ¶ added in v0.9.0
HandlePluginUninstall removes a plugin: shuts it down, cleans up DB side-effects, removes the directory from disk, and clears in-memory state. DELETE /api/v1/plugins/:name
func HandlePluginUpload ¶
HandlePluginUpload handles uploading a new WASM plugin. POST /api/v1/plugins/upload
func HandlePluginWidget ¶
HandlePluginWidget returns a specific widget's HTML. GET /api/v1/plugins/:name/widgets/:id This triggers lazy loading if needed, making it HTMX-friendly.
func HandlePluginWidgetList ¶
HandlePluginWidgetList returns available widgets for a location (triggers lazy load). GET /api/v1/plugins/widgets?location=dashboard
func HandleProfile ¶
HandleProfile is the exported version of handleProfile.
func HandleQueueMetricsAPI ¶
HandleQueueMetricsAPI handles GET /api/v1/statistics/queues.
@Summary Get queue metrics
@Description All-time per-queue total, open and backlog counts for valid queues (RBAC filtered)
@Tags Statistics
@Accept json
@Produce json
@Success 200 {object} map[string]interface{} "queues[], totals"
@Failure 401 {object} map[string]interface{} "Unauthorized"
@Failure 403 {object} map[string]interface{} "Customer caller or no readable queue"
@Failure 500 {object} map[string]interface{} "Database error"
@Security BearerAuth
@Router /statistics/queues [get]
func HandleRedirectProfile ¶
HandleRedirectProfile is the exported version of redirect handler.
func HandleRedirectQueues ¶
HandleRedirectQueues is the exported version.
func HandleRedirectSettings ¶
HandleRedirectSettings is the exported version.
func HandleRedirectTickets ¶
HandleRedirectTickets is the exported version.
func HandleRedirectTicketsNew ¶
HandleRedirectTicketsNew is the exported version.
func HandleReindexAPI ¶
HandleReindexAPI handles POST /api/v1/search/reindex.
@Summary Reindex search
@Description Start a full rebuild of the Zinc or Elasticsearch index in the background (admin only). Progress is reported by GET /search/health. The database backend needs no index.
@Tags Search
@Produce json
@Success 200 {object} map[string]interface{} "Database backend: nothing to do"
@Success 202 {object} map[string]interface{} "Reindex started"
@Failure 401 {object} map[string]interface{} "Unauthorized"
@Failure 403 {object} map[string]interface{} "Admin access required"
@Failure 409 {object} map[string]interface{} "A reindex is already running"
@Failure 503 {object} map[string]interface{} "Search backend misconfigured"
@Security BearerAuth
@Router /search/reindex [post]
func HandleRemoveQueueGroupAPI ¶
HandleRemoveQueueGroupAPI handles DELETE /api/v1/queues/:id/groups/:group_id. A queue must always have a group, so removing its group is rejected; assign a different group (POST /queues/:id/groups) to move the queue instead.
@Summary Remove group from queue (always rejected)
@Description A queue has exactly one group, which cannot be removed. Returns 409 for the queue's group and 404 for any other group. Use POST /queues/{id}/groups to change it.
@Tags Queues
@Accept json
@Produce json
@Param id path int true "Queue ID"
@Param group_id path int true "Group ID"
@Failure 401 {object} map[string]interface{} "Unauthorized"
@Failure 404 {object} map[string]interface{} "Queue not found or group not assigned"
@Failure 409 {object} map[string]interface{} "Queue must keep its group"
@Security BearerAuth
@Router /queues/{id}/groups/{group_id} [delete]
func HandleReopenTicketAPI ¶
HandleReopenTicketAPI handles ticket reopening via API.
@Summary Reopen ticket
@Description Reopen a closed ticket
@Tags Ticket Actions
@Accept json
@Produce json
@Param id path int true "Ticket ID"
@Success 200 {object} map[string]interface{} "Ticket reopened"
@Failure 401 {object} map[string]interface{} "Unauthorized"
@Failure 404 {object} map[string]interface{} "Ticket not found"
@Security BearerAuth
@Router /tickets/{id}/reopen [post]
func HandleRevokeToken ¶
HandleRevokeToken revokes a token by ID (agent or customer) DELETE /api/v1/tokens/:id or /customer/api/v1/tokens/:id
@Summary Revoke API token
@Description Revoke an API token (user can only revoke own tokens)
@Tags API Tokens
@Accept json
@Produce json
@Param id path int true "Token ID"
@Success 200 {object} map[string]interface{} "Token revoked"
@Failure 401 {object} map[string]interface{} "Unauthorized"
@Failure 404 {object} map[string]interface{} "Token not found"
@Security BearerAuth
@Router /tokens/{id} [delete]
func HandleSearchAPI ¶
HandleSearchAPI handles POST /api/v1/search.
@Summary Search tickets
@Description Full-text search across tickets, articles and customers. Ticket and article hits are limited to queues the caller can read.
@Tags Search
@Accept json
@Produce json
@Param query body object true "Search query"
@Success 200 {object} map[string]interface{} "Search results"
@Failure 400 {object} map[string]interface{} "Invalid request"
@Failure 401 {object} map[string]interface{} "Unauthorized"
@Failure 503 {object} map[string]interface{} "Search backend unavailable or index not built"
@Security BearerAuth
@Router /search [post]
func HandleSearchHealthAPI ¶
HandleSearchHealthAPI handles GET /api/v1/search/health.
@Summary Search health
@Description Report whether the search backend can serve searches; for Zinc and Elasticsearch also the index state, document counts and the latest reindex started by this server.
@Tags Search
@Produce json
@Success 200 {object} map[string]interface{} "Search health status"
@Failure 401 {object} map[string]interface{} "Unauthorized"
@Failure 503 {object} map[string]interface{} "Backend unreachable, misconfigured or index not built"
@Security BearerAuth
@Router /search/health [get]
func HandleServiceWorkerConfig ¶ added in v0.8.3
HandleServiceWorkerConfig returns the runtime cache configuration consumed by /sw.js.
func HandleSetLanguage ¶
HandleSetLanguage sets the user's language preference.
func HandleSetPreLoginLanguage ¶
HandleSetPreLoginLanguage sets the language preference cookie (public, no auth required). This is used on login pages before the user authenticates.
func HandleSetPreLoginTheme ¶
HandleSetPreLoginTheme sets the theme and mode preference cookies (public, no auth required). This is used on login pages before the user authenticates.
func HandleSetRemindersEnabled ¶ added in v0.7.0
HandleSetRemindersEnabled sets the user's reminders enabled preference.
func HandleSetSessionTimeout ¶
HandleSetSessionTimeout sets the user's session timeout preference.
func HandleSetTheme ¶
HandleSetTheme sets the user's theme preferences and persists to database. Uses UserPreferencesService for agents/admins, CustomerPreferencesService for customers.
func HandleSetWallpaper ¶
HandleSetWallpaper saves the user's wallpaper preference (on/off).
func HandleStaticFiles ¶
HandleStaticFiles serves static files from the static directory.
func HandleTemplate ¶
HandleTemplate handles template rendering routes.
func HandleTicketHistoryFragment ¶
HandleTicketHistoryFragment is an HTMX handler for ticket history fragment in tab panel.
func HandleTicketLinksFragment ¶
HandleTicketLinksFragment is an HTMX handler for ticket links fragment in tab panel.
func HandleTicketSearchAPI ¶ added in v0.10.0
HandleTicketSearchAPI searches tickets in the caller's readable queues.
@Summary Search tickets
@Description Agent ticket search over ticket, article and customer data. Text parameters match case-insensitively anywhere ('*' is a wildcard); ID and state_type parameters take comma-separated or repeated values; created_/changed_ take YYYY-MM-DD (whole day) or timestamps.
@Tags Search
@Produce json
@Param q query string false "Words that must each match ticket number, title, customer, customer user (login, name, email), company name, or an article's subject, body, from or to"
@Param tn query string false "Ticket number"
@Param title query string false "Ticket title"
@Param customer_id query string false "Customer (company) ID"
@Param customer_user_login query string false "Customer user login"
@Param from query string false "Article From"
@Param to query string false "Article To or Cc"
@Param subject query string false "Article subject"
@Param body query string false "Article body"
@Param state_type query string false "State types (new, open, pending, pending reminder, pending auto, closed, merged, removed)"
@Param state_id query string false "State IDs"
@Param queue_id query string false "Queue IDs"
@Param priority_id query string false "Priority IDs"
@Param type_id query string false "Ticket type IDs"
@Param owner_id query string false "Owner agent IDs"
@Param responsible_id query string false "Responsible agent IDs"
@Param lock_id query string false "Lock IDs"
@Param created_after query string false "Created at or after"
@Param created_before query string false "Created before (date: up to the end of that day)"
@Param changed_after query string false "Changed at or after"
@Param changed_before query string false "Changed before (date: up to the end of that day)"
@Param sort query string false "created, changed, priority, tn, title" default(created)
@Param order query string false "asc or desc" default(desc)
@Param page query int false "Page" default(1)
@Param limit query int false "Page size (max 100)" default(25)
@Success 200 {object} map[string]interface{} "{success, data: {tickets, pagination: {page, limit, total}}}"
@Failure 400 {object} map[string]interface{} "Invalid parameter"
@Failure 401 {object} map[string]interface{} "Unauthorized"
@Failure 403 {object} map[string]interface{} "Customer, or agent without queue access"
@Security BearerAuth
@Router /search/tickets [get]
func HandleTicketStateStatisticsAPI ¶
HandleTicketStateStatisticsAPI handles GET /api/v1/ticket-states/statistics.
@Summary Get state statistics
@Description All-time ticket count per valid ticket state (RBAC filtered)
@Tags States
@Accept json
@Produce json
@Success 200 {object} map[string]interface{} "statistics[], total_tickets"
@Failure 401 {object} map[string]interface{} "Unauthorized"
@Failure 403 {object} map[string]interface{} "Customer caller or no readable queue"
@Failure 500 {object} map[string]interface{} "Database error"
@Security BearerAuth
@Router /ticket-states/statistics [get]
func HandleTicketTrendsAPI ¶
HandleTicketTrendsAPI handles GET /api/v1/statistics/trends.
@Summary Get ticket trends
@Description Tickets created, closed and still open per UTC day or month (RBAC filtered)
@Tags Statistics
@Accept json
@Produce json
@Param period query string false "Bucket size" Enums(daily, monthly) default(daily)
@Param days query int false "Number of daily buckets (period=daily)" minimum(1) maximum(366) default(7)
@Param months query int false "Number of monthly buckets (period=monthly)" minimum(1) maximum(24) default(3)
@Success 200 {object} map[string]interface{} "period, days|months, trends[] {date, created, closed, open}, summary"
@Failure 400 {object} map[string]interface{} "Invalid parameter"
@Failure 401 {object} map[string]interface{} "Unauthorized"
@Failure 403 {object} map[string]interface{} "Customer caller or no readable queue"
@Failure 500 {object} map[string]interface{} "Database error"
@Security BearerAuth
@Router /statistics/trends [get]
func HandleTimeBasedAnalyticsAPI ¶
HandleTimeBasedAnalyticsAPI handles GET /api/v1/statistics/analytics.
@Summary Get time-based analytics
@Description Tickets created and closed in the last days, by UTC hour of day or by weekday (RBAC filtered)
@Tags Statistics
@Accept json
@Produce json
@Param type query string false "Bucketing" Enums(hourly, day_of_week) default(hourly)
@Param days query int false "Window in days ending now" minimum(1) maximum(366) default(30)
@Success 200 {object} map[string]interface{} "type, days, data[], peak_hours[] (hourly) or busiest_days[] (day_of_week)"
@Failure 400 {object} map[string]interface{} "Invalid parameter"
@Failure 401 {object} map[string]interface{} "Unauthorized"
@Failure 403 {object} map[string]interface{} "Customer caller or no readable queue"
@Failure 500 {object} map[string]interface{} "Database error"
@Security BearerAuth
@Router /statistics/analytics [get]
func HandleUpdateArticleAPI ¶
HandleUpdateArticleAPI handles PUT /api/v1/tickets/:ticket_id/articles/:id.
@Summary Update article
@Description Update the subject and/or body of an existing article
@Tags Articles
@Accept json
@Produce json
@Param ticket_id path int true "Ticket ID"
@Param id path int true "Article ID"
@Param article body object true "Article update data (subject, body)"
@Success 200 {object} map[string]interface{} "Updated article"
@Failure 400 {object} map[string]interface{} "Invalid request"
@Failure 401 {object} map[string]interface{} "Unauthorized"
@Failure 404 {object} map[string]interface{} "Article not found"
@Security BearerAuth
@Router /tickets/{ticket_id}/articles/{id} [put]
func HandleUpdateInternalNote ¶
HandleUpdateInternalNote updates the content of an existing internal note.
func HandleUpdateNotificationEvent ¶
HandleUpdateNotificationEvent updates an existing notification event.
func HandleUpdatePostmasterFilter ¶
handleUpdatePostmasterFilter updates an existing postmaster filter.
func HandleUpdatePriorityAPI ¶
HandleUpdatePriorityAPI handles PUT /api/v1/priorities/:id.
@Summary Update priority
@Description Update an existing priority
@Tags Priorities
@Accept json
@Produce json
@Param id path int true "Priority ID"
@Param priority body object true "Priority update data"
@Success 200 {object} map[string]interface{} "Updated priority"
@Failure 400 {object} map[string]interface{} "Invalid request"
@Failure 401 {object} map[string]interface{} "Unauthorized"
@Failure 404 {object} map[string]interface{} "Priority not found"
@Security BearerAuth
@Router /priorities/{id} [put]
func HandleUpdateProfile ¶
HandleUpdateProfile updates the current user's profile information.
func HandleUpdateQueueAPI ¶
HandleUpdateQueueAPI handles PUT /api/v1/queues/:id.
@Summary Update queue
@Description Update an existing queue
@Tags Queues
@Accept json
@Produce json
@Param id path int true "Queue ID"
@Param queue body object true "Queue update data"
@Success 200 {object} map[string]interface{} "Updated queue"
@Failure 400 {object} map[string]interface{} "Invalid request"
@Failure 401 {object} map[string]interface{} "Unauthorized"
@Failure 404 {object} map[string]interface{} "Queue not found"
@Security BearerAuth
@Router /queues/{id} [put]
func HandleUpdateSalutationAPI ¶
HandleUpdateSalutationAPI handles PUT /api/v1/salutations/:id.
@Summary Update salutation
@Description Update an email salutation
@Tags Email Identity
@Accept json
@Produce json
@Param id path int true "Salutation ID"
@Param salutation body object true "Salutation update data"
@Success 200 {object} map[string]interface{} "Updated salutation"
@Failure 400 {object} map[string]interface{} "Invalid request"
@Failure 401 {object} map[string]interface{} "Unauthorized"
@Security BearerAuth
@Router /salutations/{id} [put]
func HandleUpdateSavedSearchAPI ¶ added in v0.10.0
HandleUpdateSavedSearchAPI replaces the parameters of a saved search.
@Summary Update saved search
@Tags Search
@Accept json
@Produce json
@Param name path string true "Saved search name"
@Param search body object true "{parameters: {<search parameter>: string | [string]}}"
@Success 200 {object} map[string]interface{} "{success, data: {name, type, parameters}}"
@Failure 400 {object} map[string]interface{} "Invalid parameters"
@Failure 404 {object} map[string]interface{} "Not found"
@Security BearerAuth
@Router /search/saved/{name} [put]
func HandleUpdateSignatureAPI ¶
HandleUpdateSignatureAPI handles PUT /api/v1/signatures/:id.
@Summary Update signature
@Description Update an email signature
@Tags Email Identity
@Accept json
@Produce json
@Param id path int true "Signature ID"
@Param signature body object true "Signature update data"
@Success 200 {object} map[string]interface{} "Updated signature"
@Failure 400 {object} map[string]interface{} "Invalid request"
@Failure 401 {object} map[string]interface{} "Unauthorized"
@Security BearerAuth
@Router /signatures/{id} [put]
func HandleUpdateSystemAddressAPI ¶
HandleUpdateSystemAddressAPI handles PUT /api/v1/system-addresses/:id.
@Summary Update system address
@Description Update a system email address
@Tags Email Identity
@Accept json
@Produce json
@Param id path int true "Address ID"
@Param address body object true "Address update data"
@Success 200 {object} map[string]interface{} "Updated address"
@Failure 400 {object} map[string]interface{} "Invalid request"
@Failure 401 {object} map[string]interface{} "Unauthorized"
@Failure 404 {object} map[string]interface{} "Address not found"
@Security BearerAuth
@Router /system-addresses/{id} [put]
func HandleUpdateTicketAPI ¶
HandleUpdateTicketAPI handles PUT /api/v1/tickets/:id.
@Summary Update ticket
@Description Update an existing ticket's properties
@Tags Tickets
@Accept json
@Produce json
@Param id path int true "Ticket ID"
@Param ticket body object true "Ticket update data (title, queue_id, priority_id, state_id, etc.)"
@Success 200 {object} map[string]interface{} "Updated ticket"
@Failure 400 {object} map[string]interface{} "Invalid request"
@Failure 401 {object} map[string]interface{} "Unauthorized"
@Failure 404 {object} map[string]interface{} "Ticket not found"
@Security BearerAuth
@Router /tickets/{id} [put]
func HasPluginAccess ¶ added in v0.8.3
HasPluginAccess returns true iff the caller is entitled to use pluginName. Read-only equivalent of RequirePluginAccess, safe to call from template rendering.
func ImportSignatures ¶
func ImportSignatures(data []byte, overwrite bool, userID int) (imported int, skipped int, err error)
ImportSignatures imports signatures from YAML data, attributing the writes to userID.
func ImportTemplates ¶
func ImportTemplates(data []byte, overwrite bool, userID int) (imported int, skipped int, errors []string)
ImportTemplates imports templates from YAML data.
func InitAPITokenService ¶
InitAPITokenService initializes the API token service with a database connection
func InitializeServices ¶
func InitializeServices()
InitializeServices (re)builds the singleton services for the current database handle. Without a reachable database the DB-backed services stay nil and the getters return nil, so handlers report the outage (HTTP 500) instead of serving fake data; the next call after the database returns rebuilds them.
func JoinTemplateTypes ¶
JoinTemplateTypes joins template types into a sorted comma-separated string.
func ListHandlers ¶
func ListHandlers() []string
ListHandlers returns sorted handler names (for diagnostics / tests).
func MissingCoreRoutes ¶ added in v0.10.0
MissingCoreRoutes returns the core routes that neither the main engine r nor the dynamic engine serves. YAML and plugin routes live on the dynamic engine (reached through r's NoRoute handler), not in r.Routes().
func MountDynamicEngine ¶ added in v0.7.0
MountDynamicEngine installs a unified dynamic engine that serves both YAML routes and plugin routes. The engine is atomically swappable — rebuilt when YAML files change or plugins are loaded/reloaded. Static API routes registered directly on the main engine take priority (Gin matches those first, NoRoute catches the rest).
func ParseTemplateTypes ¶
ParseTemplateTypes splits a comma-separated type string into a slice.
func ProcessArticleDynamicFieldsFromForm ¶
func ProcessArticleDynamicFieldsFromForm(formValues map[string][]string, articleID int, screenKey string) error
ProcessArticleDynamicFieldsFromForm processes dynamic fields with "ArticleDynamicField_" prefix.
func ProcessDynamicFieldsFromForm ¶
func ProcessDynamicFieldsFromForm(formValues map[string][]string, objectID int, objectType, screenKey string) error
ProcessDynamicFieldsFromForm processes dynamic fields with "DynamicField_" prefix. screenKey is the screen being used (e.g., "AgentTicketPhone").
func RebuildDynamicEngine ¶ added in v0.7.0
func RebuildDynamicEngine()
RebuildDynamicEngine rebuilds the unified dynamic engine with current YAML + plugin routes. Safe to call from any goroutine.
func RefreshPluginMCPTools ¶ added in v0.8.2
func RefreshPluginMCPTools()
RefreshPluginMCPTools rebuilds the plugin tools in the MCP registry. Called from plugin enable/disable/upload handlers.
func RegisterAdminRoutes ¶
func RegisterAdminRoutes(group *gin.RouterGroup, routes []AdminRouteDefinition)
RegisterAdminRoutes registers routes from definitions onto a router group.
func RegisterAgentHandlers ¶
func RegisterAgentHandlers()
RegisterAgentHandlers registers agent handlers for YAML routing.
func RegisterAgentHandlersForRouting ¶
func RegisterAgentHandlersForRouting()
RegisterAgentHandlersForRouting registers agent handlers for YAML routing.
func RegisterAgentRoutes ¶
func RegisterAgentRoutes(r *gin.RouterGroup, db *sql.DB)
RegisterAgentRoutes registers all agent interface routes.
func RegisterCoreRoutes ¶ added in v0.10.0
RegisterCoreRoutes registers the routes that live on the main engine instead of in routes/*.yaml: the i18n API, the plugin management API and the plugin SSE stream. cmd/goats and the route authorization test both use it, so the test covers exactly what production serves.
func RegisterCustomerRoutes ¶
func RegisterCustomerRoutes(r *gin.RouterGroup, db *sql.DB)
RegisterCustomerRoutes registers all customer portal routes.
func RegisterDynamicFieldRoutes ¶
func RegisterDynamicFieldRoutes(router *gin.RouterGroup, adminRouter *gin.RouterGroup)
RegisterDynamicFieldRoutes registers all dynamic field admin routes.
func RegisterDynamicModuleHandlersIntoRegistry ¶
func RegisterDynamicModuleHandlersIntoRegistry(reg *routing.HandlerRegistry)
RegisterDynamicModuleHandlersIntoRegistry exposes the dynamic module handlers to the routing registry used by the main server.
func RegisterHandler ¶
func RegisterHandler(name string, h gin.HandlerFunc)
RegisterHandler adds/overwrites a handler under a given name. Registers to both the local handlerRegistry AND routing.GlobalHandlerMap so that YAML route loader can find all handlers regardless of where they're registered.
func RegisterPluginAPIRoutes ¶
func RegisterPluginAPIRoutes(r *gin.RouterGroup)
RegisterPluginAPIRoutes registers the plugin management API endpoints. Listing, health, widgets and per-plugin SSE channels are for agents only: their callers are the agent dashboard and admin pages, and customers' customer_user ids overlap users ids. Direct function calls skip the plugin's own route middleware, so they are admin-only alongside the management endpoints.
func RegisterWithRouting ¶
func RegisterWithRouting(registry interface{}) error
The routing registration should be handled at the application level.
func RenderMarkdown ¶
RenderMarkdown converts markdown content to sanitized HTML with Tailwind styling. Markdown→HTML defers to the shared pkg/markdown renderer (goldmark GFM + bluemonday), so ticket notes and plugin UI render identically and any raw/unsafe HTML is stripped; addTailwindClasses layers Tailwind styling on top of the sanitized output.
func RequireAdmin ¶
func RequireAdmin() gin.HandlerFunc
RequireAdmin middleware checks if the user is an admin. Supports both session-based auth (user_role) and JWT auth (isInAdminGroup).
func RequireGroup ¶ added in v0.7.0
func RequireGroup(groupName string) gin.HandlerFunc
RequireGroup checks that the authenticated agent belongs to a specific group. Admin users (role=Admin or isInAdminGroup) bypass group checks. Customers are refused: groups hold agents (group_user.user_id = users.id), and a customer's customer_user.id would otherwise match an unrelated agent's memberships. Used by plugins via "group:<name>" middleware, e.g. "group:myplugin-users".
func RequirePluginAccess ¶ added in v0.8.3
func RequirePluginAccess(pluginName, agentGroup string) gin.HandlerFunc
RequirePluginAccess gates a plugin route. Admins bypass; customers pass when the active org has a gk_org_plugin_access binding for pluginName and the customer is in one of those groups; agents pass when they're a member of agentGroup.
func RootRedirectTarget ¶
func RootRedirectTarget() string
func SessionOrJWTAuth ¶ added in v0.7.0
func SessionOrJWTAuth() gin.HandlerFunc
SessionOrJWTAuth middleware accepts either session-based auth (cookie) or JWT token auth. Session auth is checked first (user_id already set by session middleware), then falls back to JWT.
func SetAPITokenService ¶
func SetAPITokenService(svc *service.APITokenService)
SetAPITokenService sets the global API token service
func SetAttachmentTemplates ¶
SetAttachmentTemplates replaces all template assignments for an attachment.
func SetDynamicFieldValue ¶
func SetDynamicFieldValue(value *DynamicFieldValue) error
SetDynamicFieldValue sets a value for a dynamic field on an object.
func SetPluginDir ¶
func SetPluginDir(dir string)
SetPluginDir sets the plugin directory for uploads.
func SetPluginManager ¶
SetPluginManager sets the global plugin manager and wires up the lazy-load callback so MCP tools and dynamic routes are refreshed when a plugin is loaded on demand.
func SetPluginReloader ¶ added in v0.7.0
SetPluginReloader sets the callback used to load/reload a plugin after upload.
func SetPluginSSEBroker ¶ added in v0.8.1
SetPluginSSEBroker sets the global SSE broker for plugin channel endpoints.
func SetPluginUnloader ¶ added in v0.8.2
SetPluginUnloader sets the callback used to stop a running plugin before binary replacement.
func SetQueueTemplates ¶
SetQueueTemplates replaces all template assignments for a queue.
func SetScreenConfig ¶
SetScreenConfig sets a single field-screen config.
func SetTemplateAttachments ¶
SetTemplateAttachments sets the attachment assignments for a template.
func SetTemplateQueues ¶
SetTemplateQueues sets the queue assignments for a template.
func SetValkeyCache ¶
func SetValkeyCache(c *cache.RedisCache)
SetValkeyCache allows main to provide the shared Redis/Valkey cache.
func SetupDynamicModules ¶
SetupDynamicModules initializes the dynamic module system. Route registration is handled via YAML; this ensures endpoints exist even before the handler is ready.
func SetupHTMXRoutes ¶
SetupHTMXRoutes sets up all HTMX routes on the given router.
func SetupTestRouterWithRoutes ¶
func SetupTestRouterWithRoutes(routes []AdminRouteDefinition) *gin.Engine
SetupTestRouterWithRoutes creates a test router using canonical route definitions. Tests MUST use this instead of manually registering routes.
func SubstituteSignatureVariables ¶
Reuses the same variable substitution logic as templates.
func SubstituteTemplateVariables ¶
SubstituteTemplateVariables replaces template variables with actual values. Like OTRS, any unmatched variables are replaced with "-" rather than left as raw tags. Handles both raw tags (<OTRS_*>) and HTML-encoded tags (<OTRS_*>).
func SupportsAutoConfig ¶
SupportsAutoConfig returns true if the field type can use automatic configuration with sensible defaults, without requiring manual configuration input. Dropdown and Multiselect require PossibleValues and cannot use auto-config.
func UpdateDynamicField ¶
func UpdateDynamicField(field *DynamicField, userID int) error
UpdateDynamicField updates an existing dynamic field.
func UpdateSignature ¶
UpdateSignature updates an existing signature.
func UpdateStandardTemplate ¶
func UpdateStandardTemplate(t *StandardTemplate, userID int) error
UpdateStandardTemplate updates an existing template.
func ValidFieldTypes ¶
func ValidFieldTypes() []string
ValidFieldTypes returns all supported field types.
func ValidObjectTypes ¶
func ValidObjectTypes() []string
ValidObjectTypes returns all supported object types.
func ValidateAllTemplates ¶
ValidateAllTemplates walks templatesDir, parses every .pongo2 file, and returns a list of failures.
func ValidateContractHeaders ¶
func ValidateContractHeaders(contract *EndpointContract, headers map[string]string) []string
ValidateContractHeaders checks that a request includes all required headers per the endpoint contract. Returns a list of missing headers.
func ValidateTemplatesReferencedInRoutes ¶
ValidateTemplatesReferencedInRoutes loads YAML route groups from routesDir and attempts to parse each route's Template against templatesDir. Returns a list of failures (missing/unparsable).
func ValidateUploadedFile ¶
func ValidateUploadedFile(header *multipart.FileHeader) error
ValidateUploadedFile is a small exported wrapper around validateFile to enable focused unit tests from an external test package without importing all api tests.
func WebhookAuth ¶ added in v0.8.1
func WebhookAuth(pluginName string) gin.HandlerFunc
WebhookAuth provides authentication for webhook endpoints. No session/JWT required — instead, verifies HMAC-SHA256 signature from the request header. The signing secret is stored in the plugin's secure config under the key "<plugin>_webhook_secret".
If no webhook secret is configured, requests are REJECTED by default. Set GOATFLOW_WEBHOOK_ALLOW_UNSIGNED=true to allow unsigned webhooks during development (NOT recommended for production).
Signature verification supports:
- Standard HMAC: X-Signature-256, X-Hub-Signature-256, X-Webhook-Signature (format: "sha256=<hex>" or plain "<hex>")
- Stripe: Stripe-Signature header (format: "t=<timestamp>,v1=<signature>") Stripe signatures are computed as HMAC-SHA256(secret, "<timestamp>.<body>")
func WebhookRateLimit ¶ added in v0.8.1
func WebhookRateLimit(pluginName string) gin.HandlerFunc
WebhookRateLimit applies IP-based rate limiting scoped to the plugin name. This runs BEFORE signature verification to reject floods cheaply.
Types ¶
type ACL ¶
type ACL struct {
ID int `json:"id"`
Name string `json:"name"`
Comments *string `json:"comments,omitempty"`
Description *string `json:"description,omitempty"`
ValidID int `json:"valid_id"`
StopAfterMatch *int `json:"stop_after_match,omitempty"`
ConfigMatch *ACLConfigMatch `json:"config_match,omitempty"`
ConfigChange *ACLConfigChange `json:"config_change,omitempty"`
CreateTime time.Time `json:"create_time"`
CreateBy int `json:"create_by"`
ChangeTime time.Time `json:"change_time"`
ChangeBy int `json:"change_by"`
}
ACL represents an Access Control List entry.
type ACLConfigChange ¶
type ACLConfigChange struct {
Possible map[string]interface{} `json:"Possible,omitempty"`
PossibleNot map[string]interface{} `json:"PossibleNot,omitempty"`
PossibleAdd map[string]interface{} `json:"PossibleAdd,omitempty"`
}
ACLConfigChange defines what changes the ACL makes.
type ACLConfigMatch ¶
type ACLConfigMatch struct {
Properties map[string]interface{} `json:"Properties,omitempty"`
}
ACLConfigMatch defines the conditions for when an ACL applies.
type AdditionalDFStorageConfig ¶
type AdditionalDFStorageConfig struct {
Type string `yaml:"Type"` // "Backend" (store in DB) or "Frontend" (display only)
DynamicField string `yaml:"DynamicField"` // Target field name (without DynamicField_ prefix)
Key string `yaml:"Key"` // Source key from webservice response
}
AdditionalDFStorageConfig defines auto-fill behavior for webservice fields. When a webservice returns data, additional fields can be populated from the response.
type AdminRouteDefinition ¶
type AdminRouteDefinition struct {
Method string
Path string
Handler gin.HandlerFunc
}
AdminRouteDefinition defines a single admin route for both production and testing.
func GetAdminDynamicFieldsRoutes ¶
func GetAdminDynamicFieldsRoutes() []AdminRouteDefinition
GetAdminDynamicFieldsRoutes returns the canonical route definitions for dynamic fields admin. This MUST be used by both htmx_routes.go and test files to prevent route divergence.
func GetAdminRolesRoutes ¶
func GetAdminRolesRoutes() []AdminRouteDefinition
GetAdminRolesRoutes returns the canonical route definitions for admin roles. This MUST be used by both htmx_routes.go and test files to prevent route divergence.
type AgentHandlerRegistry ¶
type AgentHandlerRegistry struct {
NewTicket gin.HandlerFunc
CreateTicket gin.HandlerFunc
}
AgentHandlerRegistry holds references to agent handlers for external registration.
type ArticleInsertParams ¶
type ArticleInsertParams struct {
TicketID int64
CommunicationChannel int // constants.CommunicationChannel*
IsVisibleForCustomer int
CreateBy int64
}
ArticleInsertParams holds parameters for creating an article.
type ArticleMimeParams ¶
type ArticleMimeParams struct {
ArticleID int64
From string
To string // optional, empty for notes
Subject string
Body string
ContentType string
IncomingTime int64
CreateBy int64
}
ArticleMimeParams holds parameters for article MIME data.
type AttachmentBasicInfo ¶
AttachmentBasicInfo represents basic attachment information for the admin UI.
func GetAttachmentBasicInfo ¶
func GetAttachmentBasicInfo(attachmentID int) (*AttachmentBasicInfo, error)
GetAttachmentBasicInfo returns basic attachment information by ID.
type AttachmentInfo ¶
type AttachmentInfo struct {
ID int `json:"id"`
Name string `json:"name"`
Filename string `json:"filename"`
ContentType string `json:"content_type"`
ContentSize int64 `json:"content_size"`
}
AttachmentInfo represents minimal attachment info for agent API.
func GetAttachmentsByIDs ¶
func GetAttachmentsByIDs(ids []int) []AttachmentInfo
GetAttachmentsByIDs returns attachment details for given IDs.
type AttachmentWithTemplateCount ¶
AttachmentWithTemplateCount represents an attachment with its template assignment count.
func GetAttachmentsWithTemplateCounts ¶
func GetAttachmentsWithTemplateCounts() ([]AttachmentWithTemplateCount, error)
GetAttachmentsWithTemplateCounts returns all valid attachments with their template assignment counts.
type BulkActionRequest ¶
type BulkActionRequest struct {
TicketIDs []int `json:"ticket_ids" form:"ticket_ids"`
}
BulkActionRequest represents a request for bulk ticket operations
type BulkActionResult ¶
type BulkActionResult struct {
Success bool `json:"success"`
Total int `json:"total"`
Succeeded int `json:"succeeded"`
Failed int `json:"failed"`
Errors []string `json:"errors,omitempty"`
}
BulkActionResult represents the result of a bulk operation
type BulkAssignRequest ¶
type BulkAssignRequest struct {
BulkActionRequest
UserID int `json:"user_id" form:"user_id"`
}
BulkAssignRequest represents a bulk assignment request
type BulkLockRequest ¶
type BulkLockRequest struct {
BulkActionRequest
Lock bool `json:"lock" form:"lock"`
}
BulkLockRequest represents a bulk lock/unlock request
type BulkMergeRequest ¶
type BulkMergeRequest struct {
BulkActionRequest
TargetTicketID int `json:"target_ticket_id" form:"target_ticket_id"`
}
BulkMergeRequest represents a bulk merge request
type BulkPriorityRequest ¶
type BulkPriorityRequest struct {
BulkActionRequest
PriorityID int `json:"priority_id" form:"priority_id"`
}
BulkPriorityRequest represents a bulk priority change request
type BulkQueueRequest ¶
type BulkQueueRequest struct {
BulkActionRequest
QueueID int `json:"queue_id" form:"queue_id"`
}
BulkQueueRequest represents a bulk queue move request
type BulkStatusRequest ¶
type BulkStatusRequest struct {
BulkActionRequest
StatusID int `json:"status_id" form:"status_id"`
PendingUntil int64 `json:"pending_until" form:"pending_until"`
}
BulkStatusRequest represents a bulk status change request
type CannedResponse ¶
type CannedResponse struct {
ID int `json:"id"`
Name string `json:"name"`
Category string `json:"category"`
Content string `json:"content"`
ContentType string `json:"content_type"`
Tags []string `json:"tags"`
Scope string `json:"scope"`
OwnerID int `json:"owner_id"`
TeamID int `json:"team_id,omitempty"`
Placeholders []string `json:"placeholders"`
UsageCount int `json:"usage_count"`
LastUsed *time.Time `json:"last_used,omitempty"`
CreatedAt time.Time `json:"created_at"`
UpdatedAt time.Time `json:"updated_at"`
}
CannedResponse represents a pre-written response.
type CannedResponseDB ¶
type CannedResponseDB struct {
ID int
Name string
Category sql.NullString
Content string
ContentType string
Tags sql.NullString
Scope string
OwnerID int
TeamID sql.NullInt64
Placeholders sql.NullString
UsageCount int
LastUsed sql.NullTime
ValidID int
CreateTime time.Time
CreateBy int
ChangeTime time.Time
ChangeBy int
}
CannedResponseDB represents a canned response in the database.
func (*CannedResponseDB) ToCannedResponse ¶
func (r *CannedResponseDB) ToCannedResponse() *CannedResponse
ToCannedResponse converts database model to API model.
type CannedResponseFilters ¶
type CannedResponseFilters struct {
Category string
Scope string
Search string
Tags []string
SortBy string
SortOrder string
}
CannedResponseFilters holds filter options for listing responses.
type CannedResponseRepository ¶
type CannedResponseRepository struct {
// contains filtered or unexported fields
}
CannedResponseRepository handles database operations for canned responses.
func NewCannedResponseRepository ¶
func NewCannedResponseRepository() (*CannedResponseRepository, error)
NewCannedResponseRepository creates a new repository.
func (*CannedResponseRepository) CheckDuplicate ¶
func (r *CannedResponseRepository) CheckDuplicate(name, scope string, ownerID, teamID int) (bool, error)
CheckDuplicate checks if a response with the same name exists in the same scope.
func (*CannedResponseRepository) Create ¶
func (r *CannedResponseRepository) Create(cr *CannedResponse, userID int) (int, error)
Create inserts a new canned response.
func (*CannedResponseRepository) Delete ¶
func (r *CannedResponseRepository) Delete(id, userID int) error
Delete soft-deletes a canned response by setting valid_id = 2.
func (*CannedResponseRepository) GetByID ¶
func (r *CannedResponseRepository) GetByID(id int) (*CannedResponse, error)
GetByID retrieves a valid (not deleted) canned response by ID.
func (*CannedResponseRepository) IncrementUsage ¶
func (r *CannedResponseRepository) IncrementUsage(id int) error
IncrementUsage increments usage count and updates last_used.
func (*CannedResponseRepository) ListAccessible ¶
func (r *CannedResponseRepository) ListAccessible(userID, teamID int, filters CannedResponseFilters) ([]*CannedResponse, error)
ListAccessible returns canned responses accessible to a user.
func (*CannedResponseRepository) ListCategories ¶
func (r *CannedResponseRepository) ListCategories() ([]string, error)
ListCategories returns all canned response categories.
func (*CannedResponseRepository) Update ¶
func (r *CannedResponseRepository) Update(id int, cr *CannedResponse, userID int) error
Update updates a canned response.
type CustomerCompanyInfo ¶
CustomerCompanyInfo holds customer company data for display
type CustomerGroupAssignment ¶
type CustomerGroupAssignment struct {
Customer CustomerCompanyInfo
Permissions map[int]map[string]bool // group_id -> permission_key -> enabled
}
CustomerGroupAssignment holds the permission matrix for a customer
type CustomerGroupPermission ¶
type CustomerGroupPermission struct {
CustomerID string
GroupID int
PermissionKey string
PermissionValue int
PermissionContext string
}
CustomerGroupPermission represents a permission assignment
type CustomerUserInfo ¶
type CustomerUserInfo struct {
Login string
FirstName string
LastName string
Email string
ValidID int
ValidName string
}
CustomerUserInfo holds customer user data for display
type CustomerUserWithPermissions ¶
type CustomerUserWithPermissions struct {
Login string
FirstName string
LastName string
Email string
ValidID int
ValidName string
Permissions map[string]bool // permission_key -> enabled
}
CustomerUserWithPermissions holds customer user data with permission flags for templates
type CustomerWithPermissions ¶
type CustomerWithPermissions struct {
CustomerID string
Name string
ValidID int
ValidName string
Permissions map[string]bool // permission_key -> enabled
}
CustomerWithPermissions holds customer data with permission flags for templates
type DynamicField ¶
type DynamicField struct {
ID int `json:"id" db:"id"`
InternalField int `json:"internal_field" db:"internal_field"`
Name string `json:"name" db:"name"`
Label string `json:"label" db:"label"`
FieldOrder int `json:"field_order" db:"field_order"`
FieldType string `json:"field_type" db:"field_type"`
ObjectType string `json:"object_type" db:"object_type"`
Config *DynamicFieldConfig `json:"config"`
ConfigRaw []byte `json:"-" db:"config"` // YAML blob from DB
ValidID int `json:"valid_id" db:"valid_id"`
CreateTime time.Time `json:"create_time" db:"create_time"`
CreateBy int `json:"create_by" db:"create_by"`
ChangeTime time.Time `json:"change_time" db:"change_time"`
ChangeBy int `json:"change_by" db:"change_by"`
}
DynamicField represents a field definition from dynamic_field table.
func GetDynamicField ¶
func GetDynamicField(id int) (*DynamicField, error)
GetDynamicField retrieves a single dynamic field by ID.
func GetDynamicFieldByName ¶
func GetDynamicFieldByName(name string) (*DynamicField, error)
GetDynamicFieldByName retrieves a single dynamic field by name.
func GetDynamicFields ¶
func GetDynamicFields(objectType, fieldType string) ([]DynamicField, error)
GetDynamicFields retrieves all dynamic fields.
func GetDynamicFieldsForScreen ¶
func GetDynamicFieldsForScreen(objectType, screenKey string) ([]DynamicField, error)
GetDynamicFieldsForScreen retrieves active fields for a specific screen.
func (*DynamicField) GetValueColumn ¶
func (df *DynamicField) GetValueColumn() string
GetValueColumn returns the database column name used for storing values of this field type.
func (*DynamicField) IsActive ¶
func (df *DynamicField) IsActive() bool
IsActive returns true if the field is valid (active).
func (*DynamicField) IsInternal ¶
func (df *DynamicField) IsInternal() bool
IsInternal returns true if this is an internal/system field.
func (*DynamicField) ParseConfig ¶
func (df *DynamicField) ParseConfig() error
ParseConfig deserializes YAML config blob into DynamicFieldConfig.
func (*DynamicField) SerializeConfig ¶
func (df *DynamicField) SerializeConfig() error
SerializeConfig serializes DynamicFieldConfig to YAML for storage.
func (*DynamicField) Validate ¶
func (df *DynamicField) Validate() error
Validate checks the dynamic field for errors.
type DynamicFieldConfig ¶
type DynamicFieldConfig struct {
// Common to all types
DefaultValue string `yaml:"DefaultValue,omitempty"`
// Text/TextArea fields
MaxLength int `yaml:"MaxLength,omitempty"`
RegExList []RegEx `yaml:"RegExList,omitempty"` // OTRS uses RegExList
Link string `yaml:"Link,omitempty"`
LinkPreview string `yaml:"LinkPreview,omitempty"`
Rows int `yaml:"Rows,omitempty"` // TextArea only
Cols int `yaml:"Cols,omitempty"` // TextArea only
// Dropdown/Multiselect
PossibleValues map[string]string `yaml:"PossibleValues,omitempty"`
PossibleNone int `yaml:"PossibleNone,omitempty"` // OTRS uses 0/1 not bool
TranslatableValues int `yaml:"TranslatableValues,omitempty"`
TreeView int `yaml:"TreeView,omitempty"`
// Date/DateTime
YearsInPast int `yaml:"YearsInPast,omitempty"`
YearsInFuture int `yaml:"YearsInFuture,omitempty"`
DateRestriction string `yaml:"DateRestriction,omitempty"` // none, DisablePastDates, DisableFutureDates
YearsPeriod int `yaml:"YearsPeriod,omitempty"`
// WebserviceDropdown/WebserviceMultiselect - OTRS compatible
Webservice string `yaml:"Webservice,omitempty"` // Webservice name
InvokerSearch string `yaml:"InvokerSearch,omitempty"` // Invoker for search/autocomplete
InvokerGet string `yaml:"InvokerGet,omitempty"` // Invoker for get-by-id
Backend string `yaml:"Backend,omitempty"` // Backend type (DirectRequest, etc.)
StoredValue string `yaml:"StoredValue,omitempty"` // Field key to store (e.g., "ID")
DisplayedValues string `yaml:"DisplayedValues,omitempty"` // Fields to display (comma-sep, e.g., "Name,Code")
DisplayedValuesSeparator string `yaml:"DisplayedValuesSeparator,omitempty"` // Separator for display (e.g., " - ")
SearchKeys string `yaml:"SearchKeys,omitempty"` // Fields to search (comma-sep)
AutocompleteMinLength int `yaml:"AutocompleteMinLength,omitempty"` // Min chars before autocomplete (default: 3)
QueryDelay int `yaml:"QueryDelay,omitempty"` // Delay in ms before query (default: 500)
CacheTTL int `yaml:"CacheTTL,omitempty"` // Cache TTL in seconds (default: 60)
Limit int `yaml:"Limit,omitempty"` // Result limit (default: 20)
AdditionalDFStorage []AdditionalDFStorageConfig `yaml:"AdditionalDFStorage,omitempty"` // Auto-fill other fields from response
}
DynamicFieldConfig stores type-specific configuration (YAML-serialized for OTRS compatibility).
func DefaultDynamicFieldConfig ¶
func DefaultDynamicFieldConfig(fieldType string) *DynamicFieldConfig
DefaultDynamicFieldConfig returns sensible default configuration for each field type. Used when auto-config mode is enabled to skip manual configuration.
type DynamicFieldDisplay ¶
type DynamicFieldDisplay struct {
Field DynamicField
Value interface{} // The raw value (string, int, time, etc.)
DisplayValue string // Human-readable display value
}
DynamicFieldDisplay represents a dynamic field with its value for display purposes.
func GetDynamicFieldValuesForDisplay ¶
func GetDynamicFieldValuesForDisplay(objectID int, objectType string, screenKey string) ([]DynamicFieldDisplay, error)
screenKey is the screen (e.g., "AgentTicketZoom") - if empty, returns all enabled fields.
type DynamicFieldExport ¶
type DynamicFieldExport struct {
DynamicFields map[string]DynamicFieldExportItem `yaml:"DynamicFields"`
DynamicFieldScreens map[string]map[string]int `yaml:"DynamicFieldScreens,omitempty"`
}
DynamicFieldExport represents the full export structure (OTRS-compatible format).
func ExportDynamicFields ¶
func ExportDynamicFields(fieldNames []string, includeScreens bool) (*DynamicFieldExport, error)
ExportDynamicFields exports the specified dynamic fields to an OTRS-compatible format.
func ParseDynamicFieldsYAML ¶
func ParseDynamicFieldsYAML(data []byte) (*DynamicFieldExport, error)
ParseDynamicFieldsYAML parses a YAML file into a DynamicFieldExport structure.
type DynamicFieldExportItem ¶
type DynamicFieldExportItem struct {
Name string `yaml:"Name"`
Label string `yaml:"Label"`
FieldType string `yaml:"FieldType"`
ObjectType string `yaml:"ObjectType"`
FieldOrder int `yaml:"FieldOrder"`
ValidID int `yaml:"ValidID"`
Config *DynamicFieldConfig `yaml:"Config,omitempty"`
}
DynamicFieldExportItem represents a single field for export.
type DynamicFieldFilter ¶
type DynamicFieldFilter struct {
FieldID int // ID of the dynamic field
FieldName string // Name of the dynamic field (alternative to ID)
Operator string // eq, ne, contains, gt, lt, gte, lte, in, notin, empty, notempty
Value string // Value to compare against (comma-separated for 'in' operator)
}
DynamicFieldFilter represents a filter condition for dynamic field values.
func ParseDynamicFieldFiltersFromQuery ¶
func ParseDynamicFieldFiltersFromQuery(queryParams map[string][]string) []DynamicFieldFilter
Expected format: df_FieldName=value or df_FieldName_op=value (e.g., df_CustomerType=VIP, df_Amount_gt=1000).
type DynamicFieldScreenConfig ¶
type DynamicFieldScreenConfig struct {
ID int `json:"id" db:"id"`
FieldID int `json:"field_id" db:"field_id"`
ScreenKey string `json:"screen_key" db:"screen_key"`
ConfigValue int `json:"config_value" db:"config_value"` // 0=disabled, 1=enabled, 2=required
CreateTime time.Time `json:"create_time" db:"create_time"`
CreateBy int `json:"create_by" db:"create_by"`
ChangeTime time.Time `json:"change_time" db:"change_time"`
ChangeBy int `json:"change_by" db:"change_by"`
}
DynamicFieldScreenConfig maps fields to screens.
func GetScreenConfigForField ¶
func GetScreenConfigForField(fieldID int) ([]DynamicFieldScreenConfig, error)
GetScreenConfigForField gets all screen configs for a single field.
func GetScreenConfigForScreen ¶
func GetScreenConfigForScreen(screenKey string) ([]DynamicFieldScreenConfig, error)
GetScreenConfigForScreen gets all field configs for a specific screen.
type DynamicFieldValue ¶
type DynamicFieldValue struct {
ID int `json:"id" db:"id"`
FieldID int `json:"field_id" db:"field_id"`
ObjectID int64 `json:"object_id" db:"object_id"`
ValueText *string `json:"value_text,omitempty" db:"value_text"`
ValueDate *time.Time `json:"value_date,omitempty" db:"value_date"`
ValueInt *int64 `json:"value_int,omitempty" db:"value_int"`
}
DynamicFieldValue represents a stored value from dynamic_field_value table.
func GetDynamicFieldValues ¶
func GetDynamicFieldValues(objectID int64) ([]DynamicFieldValue, error)
GetDynamicFieldValues retrieves all values for an object.
type EndpointContract ¶
type EndpointContract struct {
Method string // HTTP method
Path string // Route path pattern
RequiredHeaders map[string]string // Headers the client MUST send for JSON response
ContentType string // Expected Content-Type for request body (if any)
ResponseType string // Expected response type: "json" or "html"
JSFunction string // Name of JavaScript function that calls this endpoint
}
EndpointContract documents the expected request/response contract for an endpoint. This MUST be kept in sync with both the handler logic AND the JavaScript client code. When writing tests, use these contracts to ensure test requests mirror real client requests.
func ContractForPath ¶
func ContractForPath(contracts []EndpointContract, method, path string) *EndpointContract
ContractForPath returns the endpoint contract for a given method and path. Use this in tests to ensure requests include the required headers.
func GetAdminRolesContracts ¶
func GetAdminRolesContracts() []EndpointContract
GetAdminRolesContracts returns the endpoint contracts for admin roles. CRITICAL: When handlers check headers to decide JSON vs HTML response, document the required headers here AND ensure JS client sends them.
type FieldWithScreenConfig ¶
type FieldWithScreenConfig struct {
Field DynamicField
ConfigValue int // 0=disabled, 1=enabled, 2=required
}
FieldWithScreenConfig pairs a field with its screen configuration value.
func GetFieldsForScreenWithConfig ¶
func GetFieldsForScreenWithConfig(screenKey, objectType string) ([]FieldWithScreenConfig, error)
GetFieldsForScreenWithConfig gets fields enabled for a specific screen.
type GenericAgentJob ¶
type GenericAgentJob struct {
Name string `json:"name"`
Valid bool `json:"valid"`
Config map[string]string `json:"config"`
}
GenericAgentJob represents a generic agent job configuration. Generic agent jobs are stored as key-value pairs in the database.
type GroupCustomerAssignment ¶
type GroupCustomerAssignment struct {
Group GroupInfo
Permissions map[string]map[string]bool // customer_id -> permission_key -> enabled
}
GroupCustomerAssignment holds the permission matrix for a group
type GroupWithCustomerUserPermissions ¶
type GroupWithCustomerUserPermissions struct {
ID int
Name string
ValidID int
ValidName string
Permissions map[string]bool // permission_key -> enabled
}
GroupWithCustomerUserPermissions holds group data with permission flags for customer user templates
type GroupWithPermissions ¶
type GroupWithPermissions struct {
ID int
Name string
ValidID int
ValidName string
Permissions map[string]bool // permission_key -> enabled
}
GroupWithPermissions holds group data with permission flags for templates
type ImportPreviewItem ¶
type ImportPreviewItem struct {
Name string `json:"name"`
Label string `json:"label"`
FieldType string `json:"field_type"`
ObjectType string `json:"object_type"`
Exists bool `json:"exists"`
HasScreens bool `json:"has_screens"`
ScreenCount int `json:"screen_count"`
WillCreate bool `json:"will_create"`
WillOverwrite bool `json:"will_overwrite"`
}
ImportPreviewItem represents a field in the import preview.
func GetImportPreview ¶
func GetImportPreview(export *DynamicFieldExport) ([]ImportPreviewItem, error)
GetImportPreview returns a preview of what will happen when importing.
type ImportResult ¶
type ImportResult struct {
Created []string `json:"created"`
Updated []string `json:"updated"`
Skipped []string `json:"skipped"`
Errors []string `json:"errors"`
ScreensOK int `json:"screens_ok"`
}
ImportResult contains the results of an import operation.
func ImportDynamicFields ¶
func ImportDynamicFields( export *DynamicFieldExport, selectedFields []string, selectedScreens []string, overwrite bool, userID int, ) (*ImportResult, error)
ImportDynamicFields imports dynamic fields from an export structure.
type InternalNote ¶
type InternalNote struct {
ID int `json:"id"`
TicketID int `json:"ticket_id"`
Content string `json:"content"`
FormattedContent string `json:"formatted_content"`
AuthorID int `json:"author_id"`
AuthorName string `json:"author_name"`
Visibility string `json:"visibility"` // always "internal"
CustomerVisible bool `json:"customer_visible"` // always false
Mentions []string `json:"mentions"`
HasMentions bool `json:"has_mentions"`
HasTeamMention bool `json:"has_team_mention"`
CreatedAt time.Time `json:"created_at"`
UpdatedAt time.Time `json:"updated_at"`
}
InternalNote is an internal (agent-only) note on a ticket. It is stored as an OTRS article on the Internal communication channel that is not visible to the customer.
type LookupItem ¶
LookupItem represents a simple ID/Name lookup option for templates.
type NotificationEvent ¶
type NotificationEvent struct {
ID int `json:"id"`
Name string `json:"name"`
ValidID int `json:"valid_id"`
Comments string `json:"comments"`
CreateTime time.Time `json:"create_time"`
CreateBy int `json:"create_by"`
ChangeTime time.Time `json:"change_time"`
ChangeBy int `json:"change_by"`
}
NotificationEvent represents a notification event from the database.
type NotificationEventFull ¶
type NotificationEventFull struct {
NotificationEvent
Events []string `json:"events"`
Filters map[string][]string `json:"filters"`
Recipients map[string][]string `json:"recipients"`
Messages map[string]NotificationEventMessage `json:"messages"`
}
NotificationEventFull represents a complete notification with all related data.
type NotificationEventInput ¶
type NotificationEventInput struct {
Name string `json:"name" binding:"required"`
ValidID int `json:"valid_id"`
Comments string `json:"comments"`
Events []string `json:"events"`
Filters map[string][]string `json:"filters"`
Recipients map[string][]string `json:"recipients"`
Messages map[string]NotificationEventMessage `json:"messages"`
}
NotificationEventInput represents the JSON input for creating/updating notification events.
type NotificationEventItem ¶
type NotificationEventItem struct {
NotificationID int `json:"notification_id"`
EventKey string `json:"event_key"`
EventValue string `json:"event_value"`
}
NotificationEventItem represents an event trigger condition.
type NotificationEventMessage ¶
type NotificationEventMessage struct {
ID int `json:"id"`
NotificationID int `json:"notification_id"`
Subject string `json:"subject"`
Text string `json:"text"`
ContentType string `json:"content_type"`
Language string `json:"language"`
}
NotificationEventMessage represents a notification message for a specific language.
type PaginationInfo ¶
type PaginationInfo struct {
Page int `json:"page"`
PerPage int `json:"per_page"`
Total int `json:"total"`
TotalPages int `json:"total_pages"`
HasNext bool `json:"has_next"`
HasPrev bool `json:"has_prev"`
}
PaginationInfo contains pagination metadata.
type PluginArticleAttachmentStore ¶ added in v0.10.0
type PluginArticleAttachmentStore struct{}
PluginArticleAttachmentStore serves the plugin HostAPI attachment calls from the configured article content store (internal/storage).
func (PluginArticleAttachmentStore) DeleteArticleAttachment ¶ added in v0.10.0
func (PluginArticleAttachmentStore) DeleteArticleAttachment(ctx context.Context, db *sql.DB, articleID, fileID int64) error
DeleteArticleAttachment implements plugin.ArticleAttachmentStore.
func (PluginArticleAttachmentStore) ListArticleAttachments ¶ added in v0.10.0
func (PluginArticleAttachmentStore) ListArticleAttachments(ctx context.Context, db *sql.DB, articleID int64) ([]pkgplugin.ArticleAttachment, error)
ListArticleAttachments implements plugin.ArticleAttachmentStore. HTML body parts are not attachments and are left out (OTRS ExcludeHTMLBody).
func (PluginArticleAttachmentStore) WriteArticleAttachment ¶ added in v0.10.0
func (PluginArticleAttachmentStore) WriteArticleAttachment(ctx context.Context, db *sql.DB, articleID, createdBy int64, filename, contentType string, content []byte) (int64, error)
WriteArticleAttachment implements plugin.ArticleAttachmentStore.
type PluginWidgetData ¶
type PluginWidgetData struct {
ID string
Title string
PluginName string
HTML string
Size string
Refreshable bool
RefreshSec int
GridX int
GridY int
GridW int
GridH int
}
PluginWidgetData is the rendered widget data for templates. Unavailable marks a widget whose plugin call failed; it is shown with an error state instead of content.
func GetPluginWidgets ¶
func GetPluginWidgets(ctx context.Context, location string, ginCtx ...*gin.Context) []PluginWidgetData
GetPluginWidgets returns rendered widgets for a dashboard location. Used by dashboard handlers to include plugin widgets. Pass a gin.Context so each widget call carries the caller's envelope (identity, organisation, language) for i18n, RBAC and org scoping.
type PostmasterFilterInput ¶
type PostmasterFilterInput struct {
Name string `json:"name" binding:"required"`
Stop bool `json:"stop"`
Matches []repository.FilterMatch `json:"matches"`
Sets []repository.FilterSet `json:"sets"`
}
PostmasterFilterInput represents the JSON input for creating/updating filters.
type QueueBasic ¶
QueueBasic represents minimal queue info for display.
func GetSignatureQueues ¶
func GetSignatureQueues(signatureID int) ([]QueueBasic, error)
GetSignatureQueues returns queues that use a specific signature.
type QueueInfo ¶
QueueInfo represents basic queue information.
func GetQueueInfo ¶
GetQueueInfo returns basic queue information by ID.
type QueueWithTemplateCount ¶
QueueWithTemplateCount represents a queue with its template assignment count.
func GetQueuesWithTemplateCounts ¶
func GetQueuesWithTemplateCounts() ([]QueueWithTemplateCount, error)
GetQueuesWithTemplateCounts returns all valid queues with their template assignment counts.
type Role ¶
type Role struct {
ID int `json:"id"`
Name string `json:"name"`
Comments *string `json:"comments"`
Description string `json:"description"` // Computed from Comments for template
ValidID int `json:"valid_id"`
CreateTime time.Time `json:"create_time"`
CreateBy int `json:"create_by"`
ChangeTime time.Time `json:"change_time"`
ChangeBy int `json:"change_by"`
UserCount int `json:"user_count"`
GroupCount int `json:"group_count"`
IsActive bool `json:"is_active"` // Computed from ValidID
IsSystem bool `json:"is_system"` // True for built-in roles
Permissions []string `json:"permissions"` // Simple permissions list
}
Role represents a role in the system.
type RoleGroupPermission ¶
type RoleGroupPermission struct {
GroupID int `json:"group_id"`
GroupName string `json:"group_name"`
Permissions map[string]bool `json:"permissions"`
}
RoleGroup represents group permissions for a role.
type RoleUser ¶
type RoleUser struct {
UserID int `json:"user_id"`
Login string `json:"login"`
FirstName string `json:"first_name"`
LastName string `json:"last_name"`
Email string `json:"email"`
}
RoleUser represents a user assigned to a role.
type RouteDoc ¶ added in v0.8.2
type RouteDoc = topRouteDoc
RouteDoc represents a parsed YAML route group document.
func LoadYAMLRouteGroups ¶ added in v0.8.2
LoadYAMLRouteGroups scans the routes directory and returns parsed groups. Exported for use by the MCP tool generator initialization in mcp_handler.go.
type RouteSpec ¶ added in v0.8.2
type RouteSpec = routeSpec
RouteSpec represents a single route definition from YAML.
type RoutingHandlerResolver ¶ added in v0.9.0
type RoutingHandlerResolver struct {
// contains filtered or unexported fields
}
RoutingHandlerResolver exposes API-registered handlers through routing's resolver interface.
func NewRoutingHandlerResolver ¶ added in v0.9.0
func NewRoutingHandlerResolver() RoutingHandlerResolver
NewRoutingHandlerResolver initializes core API handlers and returns a routing resolver.
func (RoutingHandlerResolver) Get ¶ added in v0.9.0
func (r RoutingHandlerResolver) Get(name string) (gin.HandlerFunc, error)
Get resolves a registered API handler by route handler name.
func (RoutingHandlerResolver) GetMiddleware ¶ added in v0.9.0
func (r RoutingHandlerResolver) GetMiddleware(name string) (gin.HandlerFunc, error)
GetMiddleware resolves registered routing middleware by name.
func (RoutingHandlerResolver) HandlerExists ¶ added in v0.9.0
func (r RoutingHandlerResolver) HandlerExists(name string) bool
HandlerExists reports whether a route handler name is registered.
func (RoutingHandlerResolver) IsFeatureEnabled ¶ added in v0.9.0
func (r RoutingHandlerResolver) IsFeatureEnabled(name string) bool
IsFeatureEnabled reports whether a route feature flag is enabled.
func (RoutingHandlerResolver) RegisteredHandlers ¶ added in v0.9.0
func (RoutingHandlerResolver) RegisteredHandlers() map[string]gin.HandlerFunc
RegisteredHandlers returns a copy of all API handlers known to the resolver.
func (RoutingHandlerResolver) Registry ¶ added in v0.9.0
func (r RoutingHandlerResolver) Registry() *routing.HandlerRegistry
Registry returns the populated routing registry for callers that need registry-specific APIs.
type SLADefinition ¶
type SLADefinition struct {
ID int `json:"id"`
Name string `json:"name"`
CalendarName *string `json:"calendar_name,omitempty"`
FirstResponseTime *int `json:"first_response_time,omitempty"`
FirstResponseNotify *int `json:"first_response_notify,omitempty"`
UpdateTime *int `json:"update_time,omitempty"`
UpdateNotify *int `json:"update_notify,omitempty"`
SolutionTime *int `json:"solution_time,omitempty"`
SolutionNotify *int `json:"solution_notify,omitempty"`
Comments *string `json:"comments,omitempty"`
ValidID int `json:"valid_id"`
CreateTime time.Time `json:"create_time"`
CreateBy int `json:"create_by"`
ChangeTime time.Time `json:"change_time"`
ChangeBy int `json:"change_by"`
}
SLADefinition represents a Service Level Agreement configuration.
type SLAWithStats ¶
type SLAWithStats struct {
SLADefinition
TicketCount int `json:"ticket_count"`
}
SLAWithStats includes additional statistics.
type ScreenConfigMatrix ¶
type ScreenConfigMatrix struct {
ObjectType string
Fields []DynamicField
Screens []ScreenDefinition
ConfigMap map[int]map[string]int // fieldID -> screenKey -> configValue
}
ScreenConfigMatrix provides a full view of field-screen mappings for admin UI.
func GetScreenConfigMatrix ¶
func GetScreenConfigMatrix(objectType string) (*ScreenConfigMatrix, error)
GetScreenConfigMatrix builds a matrix of all fields and their screen configs.
type ScreenDefinition ¶
type ScreenDefinition struct {
Key string `json:"key"`
Name string `json:"name"`
ObjectType string `json:"object_type"`
SupportsRequired bool `json:"supports_required"`
IsDisplayOnly bool `json:"is_display_only"`
}
ScreenDefinition describes a screen that can display dynamic fields.
func GetScreenDefinitions ¶
func GetScreenDefinitions() []ScreenDefinition
GetScreenDefinitions returns all screens that support dynamic fields.
type SearchableDynamicField ¶
type SearchableDynamicField struct {
DynamicField
Options []map[string]string `json:"options"` // [{key: "value", value: "display_name"}, ...]
}
SearchableDynamicField wraps DynamicField with template-friendly Options.
func GetFieldsForSearch ¶
func GetFieldsForSearch() ([]SearchableDynamicField, error)
Results are cached for 30 seconds to improve performance.
type ServiceWithStats ¶
type ServiceWithStats struct {
Service
TicketCount int `json:"ticket_count"`
SLACount int `json:"sla_count"`
}
ServiceWithStats includes additional statistics.
type Signature ¶
type Signature struct {
ID int `json:"id"`
Name string `json:"name"`
Text string `json:"text"`
ContentType string `json:"content_type"`
Comments string `json:"comments"`
ValidID int `json:"valid_id"`
CreateTime time.Time `json:"create_time"`
CreateBy int `json:"create_by"`
ChangeTime time.Time `json:"change_time"`
ChangeBy int `json:"change_by"`
}
Signature represents an email signature in the system.
func GetAllSignatures ¶
GetAllSignatures returns all valid signatures for dropdowns.
func GetSignature ¶
GetSignature returns a single signature by ID.
type SignatureExportData ¶
type SignatureExportData struct {
Name string `yaml:"name"`
Text string `yaml:"text"`
ContentType string `yaml:"content_type,omitempty"`
Comments string `yaml:"comments,omitempty"`
Valid bool `yaml:"valid"`
Queues []string `yaml:"queues,omitempty"`
}
SignatureExportData represents a signature for YAML export.
type SignatureForAgent ¶
type SignatureForAgent struct {
ID int `json:"id"`
Name string `json:"name"`
Text string `json:"text"`
ContentType string `json:"content_type"`
}
SignatureForAgent represents a signature available to agents.
func GetQueueSignature ¶
func GetQueueSignature(queueID int) (*SignatureForAgent, error)
GetQueueSignature returns the signature assigned to a specific queue.
type SignatureWithStats ¶
SignatureWithStats includes queue usage statistics.
func ListSignatures ¶
func ListSignatures(search string, validFilter string, sortBy string, sortOrder string) ([]SignatureWithStats, error)
ListSignatures returns all signatures with optional filters.
type StandardAttachment ¶
type StandardAttachment struct {
ID int `json:"id"`
Name string `json:"name"`
Filename string `json:"filename"`
ContentType string `json:"content_type"`
Content []byte `json:"-"` // Don't send raw content in JSON
ContentSize int64 `json:"content_size"`
ContentSizeFormatted string `json:"content_size_formatted"`
Comments *string `json:"comments"`
ValidID int `json:"valid_id"`
CreateTime time.Time `json:"create_time"`
CreateBy int `json:"create_by"`
ChangeTime time.Time `json:"change_time"`
ChangeBy int `json:"change_by"`
}
StandardAttachment represents a standard attachment in OTRS.
func ListStandardAttachments ¶
func ListStandardAttachments() ([]StandardAttachment, error)
ListStandardAttachments returns all valid standard attachments.
type StandardTemplate ¶
type StandardTemplate struct {
ID int `json:"id"`
Name string `json:"name"`
Text string `json:"text"`
ContentType string `json:"content_type"`
TemplateType string `json:"template_type"` // comma-separated: Answer,Forward,Note
Comments string `json:"comments"`
ValidID int `json:"valid_id"`
CreateTime time.Time `json:"create_time"`
CreateBy int `json:"create_by"`
ChangeTime time.Time `json:"change_time"`
ChangeBy int `json:"change_by"`
}
StandardTemplate represents a response template in the system.
func GetStandardTemplate ¶
func GetStandardTemplate(id int) (*StandardTemplate, error)
GetStandardTemplate retrieves a single template by ID.
type StandardTemplateWithStats ¶
type StandardTemplateWithStats struct {
StandardTemplate
QueueCount int `json:"queue_count"`
}
StandardTemplateWithStats includes usage statistics.
func ListStandardTemplates ¶
func ListStandardTemplates( search string, validFilter string, typeFilter string, sortBy string, sortOrder string, ) ([]StandardTemplateWithStats, error)
ListStandardTemplates returns all templates with optional filters.
type State ¶
type State struct {
ID int `json:"id"`
Name string `json:"name"`
TypeID *int `json:"type_id,omitempty"`
Comments *string `json:"comments,omitempty"`
ValidID *int `json:"valid_id,omitempty"`
}
State represents a ticket state.
type StateType ¶
type StateType struct {
ID int `json:"id"`
Name string `json:"name"`
Comments *string `json:"comments,omitempty"`
}
StateType represents a ticket state type.
type StateWithType ¶
type StateWithType struct {
ID int `json:"id"`
Name string `json:"name"`
TypeID int `json:"type_id"`
TypeName string `json:"type_name"`
Comments *string `json:"comments,omitempty"`
ValidID int `json:"valid_id"`
TicketCount int `json:"ticket_count"`
}
StateWithType includes type information.
type TemplateExport ¶
type TemplateExport struct {
Name string `yaml:"name"`
Text string `yaml:"text,omitempty"`
ContentType string `yaml:"content_type,omitempty"`
TemplateType string `yaml:"template_type,omitempty"`
Comments string `yaml:"comments,omitempty"`
Valid bool `yaml:"valid"`
Queues []string `yaml:"queues,omitempty"`
Attachments []string `yaml:"attachments,omitempty"`
}
TemplateExport represents a single template for YAML export.
func ExportTemplate ¶
func ExportTemplate(id int) (*TemplateExport, error)
ExportTemplate exports a single template with its relationships.
type TemplateExportFile ¶
type TemplateExportFile struct {
Version string `yaml:"version"`
ExportedAt string `yaml:"exported_at"`
Templates []TemplateExport `yaml:"templates"`
}
TemplateExportFile represents the full export file structure.
func ExportAllTemplates ¶
func ExportAllTemplates() (*TemplateExportFile, error)
ExportAllTemplates exports all templates.
type TemplateForAgent ¶
type TemplateForAgent struct {
ID int `json:"id"`
Name string `json:"name"`
Text string `json:"text"`
ContentType string `json:"content_type"`
TemplateType string `json:"template_type"`
}
TemplateForAgent represents a template available to agents.
func GetTemplatesForQueue ¶
func GetTemplatesForQueue(queueID int, templateType string) ([]TemplateForAgent, error)
GetTemplatesForQueue returns templates available for a specific queue and optional type filter.
type TemplateOption ¶
TemplateOption represents a template option for checkbox selection.
type TemplateTypeOption ¶
TemplateTypeOption represents a template type for UI selection.
func ValidTemplateTypes ¶
func ValidTemplateTypes() []TemplateTypeOption
ValidTemplateTypes returns all available template types matching OTRS.
type TemplateWithAttachmentCount ¶
type TemplateWithAttachmentCount struct {
ID int
Name string
TemplateType string
AttachmentCount int
}
TemplateWithAttachmentCount represents a template with its attachment assignment count.
func GetTemplatesWithAttachmentCounts ¶
func GetTemplatesWithAttachmentCounts() ([]TemplateWithAttachmentCount, error)
GetTemplatesWithAttachmentCounts returns all valid templates with their attachment assignment counts.
type TemplateWithQueueCount ¶
TemplateWithQueueCount represents a template with its queue assignment count.
func GetTemplatesWithQueueCounts ¶
func GetTemplatesWithQueueCounts() ([]TemplateWithQueueCount, error)
GetTemplatesWithQueueCounts returns all valid templates with their queue assignment counts.
type TicketDisplay ¶
type TicketDisplay struct {
models.Ticket
QueueName string
PriorityName string
StateName string
OwnerName string
CustomerName string
}
TicketDisplay represents ticket data for display purposes.
type TicketListResponse ¶
type TicketListResponse struct {
Success bool `json:"success"`
Data []map[string]interface{} `json:"data"`
Pagination PaginationInfo `json:"pagination"`
Error string `json:"error,omitempty"`
}
TicketListResponse represents the response for ticket list API.
type TicketTemplate ¶
type TicketTemplate struct {
ID int `json:"id"`
Name string `json:"name"`
Description string `json:"description"`
Subject string `json:"subject"`
Body string `json:"body"`
Priority string `json:"priority"`
QueueID int `json:"queue_id"`
TypeID int `json:"type_id"`
Tags []string `json:"tags"`
Placeholders []string `json:"placeholders"`
IsSystem bool `json:"is_system"`
CreatedBy int `json:"created_by"`
CreatedAt time.Time `json:"created_at"`
UpdatedAt time.Time `json:"updated_at"`
}
TicketTemplate represents a reusable ticket template.
type TicketType ¶
type TicketType struct {
ID int `json:"id"`
Name string `json:"name"`
ValidID int `json:"valid_id"`
CreateBy int `json:"create_by"`
ChangeBy int `json:"change_by"`
TicketCount int `json:"ticket_count"`
}
TicketType represents a ticket type.
type WidgetInfo ¶
type WidgetInfo struct {
ID string `json:"id"` // "plugin_name:widget_id"
PluginName string `json:"plugin_name"`
WidgetID string `json:"widget_id"`
Title string `json:"title"`
Size string `json:"size"`
Enabled bool `json:"enabled"`
Position int `json:"position"`
X int `json:"x"`
Y int `json:"y"`
W int `json:"w"`
H int `json:"h"`
}
WidgetInfo describes a widget for the configuration UI.
Source Files
¶
- admin_acl_handlers.go
- admin_acl_init.go
- admin_attachment_handler.go
- admin_attachment_init.go
- admin_crud_handlers.go
- admin_custom_fields_handlers.go
- admin_customer_company.go
- admin_customer_company_pages.go
- admin_customer_groups_handlers.go
- admin_customer_user_groups_handlers.go
- admin_customer_user_services.go
- admin_customer_user_services_init.go
- admin_customer_users_handlers.go
- admin_debug_config_sources_handler.go
- admin_debug_ticket_number_handler.go
- admin_dynamic_field_webservice_ajax.go
- admin_dynamic_fields_handlers.go
- admin_email_handlers.go
- admin_generic_agent_handlers.go
- admin_generic_agent_init.go
- admin_groups_handlers.go
- admin_identity_providers_handlers.go
- admin_lookups_handlers.go
- admin_notification_event_handlers.go
- admin_notification_event_init.go
- admin_plugins_handlers.go
- admin_postmaster_filters_handlers.go
- admin_postmaster_filters_init.go
- admin_queue_templates_handlers.go
- admin_queue_templates_init.go
- admin_roles_handler.go
- admin_roles_init.go
- admin_service_handlers.go
- admin_session_handlers.go
- admin_setup_handlers.go
- admin_signatures_handlers.go
- admin_signatures_init.go
- admin_sla_handlers.go
- admin_sla_init.go
- admin_sql_handler.go
- admin_sql_init.go
- admin_state_handlers.go
- admin_system_maintenance_handlers.go
- admin_system_maintenance_init.go
- admin_template_attachments_handlers.go
- admin_template_attachments_init.go
- admin_templates_handlers.go
- admin_templates_init.go
- admin_ticket_attribute_relations_handlers.go
- admin_tickets_handler.go
- admin_type_handlers.go
- admin_user_password_handler.go
- admin_users_handlers.go
- admin_webhooks_handlers.go
- admin_webservice_handlers.go
- agent_handlers_init.go
- agent_routes.go
- agent_signatures_handlers.go
- agent_signatures_init.go
- agent_templates_handlers.go
- agent_templates_init.go
- agent_ticket_actions.go
- agent_ticket_bulk_actions.go
- agent_ticket_bulk_actions_init.go
- agent_ticket_create_handler.go
- agent_ticket_handlers.go
- agent_ticket_new_handler.go
- api_token_handlers.go
- api_token_init.go
- article_access.go
- article_attachments.go
- article_create_handler.go
- article_delete_handler.go
- article_get_handler.go
- article_helper.go
- article_list_handler.go
- article_update_handler.go
- attachment_helper.go
- auth_customer.go
- auth_handlers.go
- auth_htmx_handlers.go
- auth_oidc_handlers.go
- auth_saml_handlers.go
- auth_sso_browser_binding.go
- basic_handlers.go
- canned_response_handler.go
- canned_response_repository.go
- coachmarks_handler.go
- core_routes.go
- customer_attachment_handlers.go
- customer_company_portal.go
- customer_only_guard.go
- customer_portal_config.go
- customer_routes.go
- dashboard_htmx_handlers.go
- dashboard_widgets_handler.go
- db_error_response.go
- dynamic_field_import_export.go
- dynamic_field_repository.go
- dynamic_field_screen_config.go
- dynamic_field_search.go
- dynamic_field_types.go
- dynamic_integration.go
- dynamic_router.go
- email_identity_handlers.go
- exports.go
- exports_agent.go
- exports_api_v1.go
- exports_customer.go
- group_list_handler.go
- handler_registry.go
- health.go
- helpers.go
- htmx_routes.go
- htmx_utils.go
- login_throttle.go
- lookup_crud_handlers.go
- lookup_handlers.go
- mail_account_status.go
- markdown_render_handler.go
- marketplace_handlers.go
- mcp_handler.go
- mcp_init.go
- mcp_sse_handler.go
- metrics.go
- mfa_account.go
- mfa_status.go
- misc_init.go
- org_plugin_access_handlers.go
- plugin_article_attachments.go
- plugin_handlers.go
- plugin_ui_admin_handlers.go
- preferences_handler.go
- priority_create_handler.go
- priority_delete_handler.go
- priority_get_handler.go
- priority_list_handler.go
- priority_update_handler.go
- profile_exports.go
- push_handlers.go
- push_init.go
- queue_api_handlers.go
- queue_create_handler.go
- queue_delete_handler.go
- queue_get_handler.go
- queue_groups_handler.go
- queue_handlers_api.go
- queue_htmx_handlers.go
- queue_list_handler.go
- queue_stats_handler.go
- queue_update_handler.go
- redirect_handlers.go
- register_handlers.go
- repository_instances.go
- root_redirect.go
- route_audit.go
- routes_watcher.go
- search_handler.go
- service_list_handler.go
- setup_api_handlers.go
- state_list_handler.go
- statistics_handlers.go
- swagger.go
- template_validation.go
- test_router_registry.go
- ticket_actions_api.go
- ticket_actions_handlers.go
- ticket_api_handlers.go
- ticket_attachment_handler.go
- ticket_attachment_ics.go
- ticket_body_authz.go
- ticket_create_handler.go
- ticket_create_handlers.go
- ticket_create_with_attachments.go
- ticket_delete_api.go
- ticket_detail_handlers.go
- ticket_escalation_view.go
- ticket_events.go
- ticket_fragment_handlers.go
- ticket_get_handler.go
- ticket_internal_note_handler.go
- ticket_list_handler.go
- ticket_list_handlers.go
- ticket_merge_handler.go
- ticket_messages_handler.go
- ticket_notes_handlers.go
- ticket_read_scope.go
- ticket_search_api.go
- ticket_state_helper.go
- ticket_template_handler.go
- ticket_update_handler.go
- time_helpers.go
- totp_handlers.go
- type_list_handler.go
- wallpaper_handler.go
- webauthn_handlers.go
- webhook_handlers.go
- yaml_router_loader.go