api

package
v0.8.0 Latest Latest
Warning

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

Go to latest
Published: Mar 28, 2026 License: Apache-2.0 Imports: 91 Imported by: 0

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

View Source
const (
	DFTypeText                  = "Text"
	DFTypeTextArea              = "TextArea"
	DFTypeCheckbox              = "Checkbox"
	DFTypeDropdown              = "Dropdown"
	DFTypeMultiselect           = "Multiselect"
	DFTypeDate                  = "Date"
	DFTypeDateTime              = "DateTime"
	DFTypeWebserviceDropdown    = "WebserviceDropdown"
	DFTypeWebserviceMultiselect = "WebserviceMultiselect"
)

Field type constants matching OTRS.

View Source
const (
	DFObjectTicket          = "Ticket"
	DFObjectArticle         = "Article"
	DFObjectCustomerUser    = "CustomerUser"
	DFObjectCustomerCompany = "CustomerCompany"
)

Object type constants matching OTRS.

View Source
const (
	DFScreenDisabled = 0
	DFScreenEnabled  = 1
	DFScreenRequired = 2
)

Screen config value constants.

View Source
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

View Source
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

View Source
var (
	HandleAdminListUserTokens      = HandleAdminListTargetTokens
	HandleAdminCreateUserToken     = HandleAdminCreateTargetToken
	HandleAdminRevokeUserToken     = HandleAdminRevokeTargetToken
	HandleAdminListCustomerTokens  = HandleAdminListTargetTokens
	HandleAdminCreateCustomerToken = HandleAdminCreateTargetToken
	HandleAdminRevokeCustomerToken = HandleAdminRevokeTargetToken
)

Admin handler aliases - unified handlers work for both agents and customers

View Source
var (
	HandleLoginPage           = handleLoginPage
	HandleCustomerLoginPage   = handleCustomerLoginPage
	HandleLogout              = handleLogout
	HandleDashboard           = handleDashboard
	HandleDashboardStats      = handleDashboardStats
	HandleRecentTickets       = handleRecentTickets
	HandleActivityStream      = handleActivityStream
	HandlePendingReminderFeed = handlePendingReminderFeed
	HandleUpdateTicketStatus  = handleUpdateTicketStatus
)

Core handlers.

View Source
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)
	}
		dbService, err := adapter.GetDatabase()
		if err != nil {
			c.JSON(http.StatusInternalServerError, gin.H{"error": "Database connection failed"})
			return
		}
		handleAdminUploadCustomerPortalLogo(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.

View Source
var (
	HandleTicketDetail   = handleTicketDetail
	HandleQueueDetail    = handleQueueDetail
	HandleNewTicket      = handleNewTicket
	HandleNewEmailTicket = handleNewEmailTicket
	HandleNewPhoneTicket = handleNewPhoneTicket
)

Ticket handlers.

View Source
var (
	HandleGetAttachments     = handleGetAttachments
	HandleUploadAttachment   = handleUploadAttachment
	HandleDownloadAttachment = handleDownloadAttachment
	HandleDeleteAttachment   = handleDeleteAttachment
	HandleGetThumbnail       = handleGetThumbnail
	HandleViewAttachment     = handleViewAttachment
)

Attachment handlers (exported for routing).

View Source
var (
	HandleAdminSettings  gin.HandlerFunc = handleAdminSettings
	HandleAdminTemplates gin.HandlerFunc = handleAdminTemplates
	HandleAdminReports   gin.HandlerFunc = handleAdminReports
	HandleAdminLogs      gin.HandlerFunc = handleAdminLogs
	HandleAdminBackup    gin.HandlerFunc = handleAdminBackup
)
View Source
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
	HandleAgentTicketDraft    = AgentHandlerExports.HandleAgentTicketDraft
)

Provide package-level handler variables for tests and direct routing.

View Source
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)
	HandleCustomerKnowledgeBase     = wrapAdapterDBHandler(handleCustomerKnowledgeBase)
	HandleCustomerKBSearch          = wrapAdapterDBHandler(handleCustomerKBSearch)
	HandleCustomerKBArticle         = wrapAdapterDBHandler(handleCustomerKBArticle)
	HandleCustomerCompanyInfo       = wrapAdapterDBHandler(handleCustomerCompanyInfo)
	HandleCustomerCompanyUsers      = wrapAdapterDBHandler(handleCustomerCompanyUsers)
	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.

View Source
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
	HandleAgentTicketDraft     gin.HandlerFunc
	HandleAgentCustomerTickets gin.HandlerFunc
	HandleAgentCustomerView    gin.HandlerFunc
	HandleAgentSearch          gin.HandlerFunc
	HandleAgentSearchResults   gin.HandlerFunc
	HandleAgentNewTicket       gin.HandlerFunc
	HandleAgentCreateTicket    gin.HandlerFunc
	HandleAgentQueues          gin.HandlerFunc
	HandleAgentQueueView       gin.HandlerFunc
	HandleAgentQueueLock       gin.HandlerFunc
	HandleAgentCustomers       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),
	HandleAgentTicketDraft:     wrapDBHandler(handleAgentTicketDraft),
	HandleAgentCustomerTickets: wrapDBHandler(handleAgentCustomerTickets),
	HandleAgentCustomerView:    wrapDBHandler(handleAgentCustomerView),
	HandleAgentSearch:          wrapDBHandler(handleAgentSearch),
	HandleAgentSearchResults:   wrapDBHandler(handleAgentSearchResults),
	HandleAgentNewTicket:       wrapDBHandler(HandleAgentNewTicket),
	HandleAgentCreateTicket:    wrapDBHandler(HandleAgentCreateTicket),
	HandleAgentQueues:          wrapDBHandler(handleAgentQueues),
	HandleAgentQueueView:       wrapDBHandler(handleAgentQueueView),
	HandleAgentQueueLock:       wrapDBHandler(handleAgentQueueLock),
	HandleAgentCustomers:       wrapDBHandler(handleAgentCustomers),

	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.

View Source
var ArticleEvents = []string{
	"ArticleCreate",
	"ArticleSend",
	"ArticleBounce",
	"ArticleAgentNotification",
	"ArticleCustomerNotification",
}

Article events that can trigger notifications.

View Source
var CannedResponseHandlerExports = NewCannedResponseHandlers()

CannedResponseHandlerExports provides singleton access for YAML route registration.

View Source
var GlobalAgentHandlers = &AgentHandlerRegistry{}

GlobalAgentHandlers is the global registry for agent handlers.

View Source
var HandleAPIv1AddArticle = HandleCreateArticleAPI

Articles API handlers.

View Source
var HandleAPIv1AuthLogin = HandleLoginAPI

Auth handlers.

View Source
var HandleAPIv1AuthLogout = HandleLogoutAPI
View Source
var HandleAPIv1AuthRefresh = HandleRefreshTokenAPI
View Source
var HandleAPIv1AuthRegister = HandleRegisterAPI
View Source
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},
	})
}
View Source
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},
	})
}
View Source
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.

View Source
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,
	})
}
View Source
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,
	})
}
View Source
var HandleAPIv1QueueDelete = func(c *gin.Context) {
	c.JSON(http.StatusNoContent, gin.H{})
}
View Source
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,
	})
}
View Source
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,
	})
}
View Source
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.

View Source
var HandleAPIv1TicketAssign = HandleAssignTicketAPI
View Source
var HandleAPIv1TicketClose = HandleCloseTicketAPI

Ticket action handlers.

View Source
var HandleAPIv1TicketCreate = HandleCreateTicketAPI
View Source
var HandleAPIv1TicketDelete = HandleDeleteTicketAPI
View Source
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,
	})
}
View Source
var HandleAPIv1TicketReopen = HandleReopenTicketAPI
View Source
var HandleAPIv1TicketUpdate = HandleUpdateTicketAPI
View Source
var HandleAPIv1TicketsList = HandleListTicketsAPI

Tickets API handlers.

View Source
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,
	})
}
View Source
var HandleAPIv1UserDelete = func(c *gin.Context) {
	c.JSON(http.StatusNoContent, gin.H{})
}
View Source
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,
	})
}
View Source
var HandleAPIv1UserMe = HandleUserMeAPI

Users API handlers.

View Source
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,
	})
}
View Source
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,
	})
}
View Source
var HandleAuthCheck = func(c *gin.Context) {
	userID, exists := c.Get("user_id")
	if !exists {
		c.JSON(http.StatusUnauthorized, gin.H{
			"authenticated": false,
		})
		return
	}

	c.JSON(http.StatusOK, gin.H{
		"authenticated": true,
		"userID":        userID,
	})
}

HandleAuthCheck checks if user is authenticated.

View Source
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
	}

	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, accessToken, refreshToken, err := authService.Login(ctx, username, password)
	if err != nil {
		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
	}

	if db, err := database.GetDB(); err == nil && db != nil {
		totpService := service.NewTOTPService(db, "GoatFlow")
		is2FAEnabled := totpService.IsEnabled(int(user.ID))
		if is2FAEnabled {

			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
			}

			c.SetCookie("2fa_pending", token, 300, "/", "", false, true)

			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
	}

	{
		jwtMgr := shared.GetJWTManager()
		if tok, tokErr := jwtMgr.GenerateTokenWithDuration(
			user.ID, user.Login, user.Email, user.Role, user.Role == "Admin", 0,
			time.Duration(sessionTimeout)*time.Second); tokErr == nil {
			accessToken = tok
		} else {
			log.Printf("Failed to regenerate JWT with user duration: %v", tokErr)
		}
	}

	c.SetCookie(
		"auth_token",
		accessToken,
		sessionTimeout,
		"/",
		"",
		false,
		true,
	)

	c.SetCookie(
		"access_token",
		accessToken,
		sessionTimeout,
		"/",
		"",
		false,
		true,
	)

	c.SetCookie(
		"refresh_token",
		refreshToken,
		constants.RefreshTokenTimeout,
		"/",
		"",
		false,
		true,
	)

	c.Set("user", user)
	c.Set("user_id", user.ID)
	if provider != "" {
		c.Set("auth_provider", provider)
	}

	if sessionSvc := shared.GetSessionService(); sessionSvc != nil {
		sessionID, err := sessionSvc.CreateSession(
			int(user.ID),
			username,
			user.Role,
			c.ClientIP(),
			c.Request.UserAgent(),
		)
		if err != nil {

			log.Printf("Failed to create session record: %v", err)
		} else {

			c.SetCookie("session_id", sessionID, sessionTimeout, "/", "", false, true)
		}
	}

	c.SetCookie("goatflow_logged_in", "1", sessionTimeout, "/", "", false, false)

	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.

View Source
var HandleAuthLogout = func(c *gin.Context) {

	if sessionID, err := c.Cookie("session_id"); err == nil && sessionID != "" {
		if sessionSvc := shared.GetSessionService(); sessionSvc != nil {
			if err := sessionSvc.KillSession(sessionID); err != nil {
				log.Printf("Failed to delete session record: %v", err)
			}
		}
	}

	c.SetCookie("auth_token", "", -1, "/", "", false, true)
	c.SetCookie("access_token", "", -1, "/", "", false, true)
	c.SetCookie("refresh_token", "", -1, "/", "", false, true)
	c.SetCookie("session_id", "", -1, "/", "", false, true)
	c.SetCookie("goatflow_logged_in", "", -1, "/", "", false, false)

	c.Redirect(http.StatusSeeOther, "/login")
}

HandleAuthLogout handles user logout.

View Source
var HandleCustomerLogin = func(c *gin.Context) {
	handleCustomerLogin(shared.GetJWTManager())(c)
}

HandleCustomerLogin is the exported handler for customer login POST requests.

View Source
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.

View Source
var TicketEvents = []string{
	"TicketCreate",
	"TicketDelete",
	"TicketTitleUpdate",
	"TicketQueueUpdate",
	"TicketTypeUpdate",
	"TicketServiceUpdate",
	"TicketSLAUpdate",
	"TicketCustomerUpdate",
	"TicketPendingTimeUpdate",
	"TicketLockUpdate",
	"TicketStateUpdate",
	"TicketOwnerUpdate",
	"TicketResponsibleUpdate",
	"TicketPriorityUpdate",
	"TicketSubscribe",
	"TicketUnsubscribe",
	"TicketFlagSet",
	"TicketFlagDelete",
	"TicketMerge",
	"EscalationResponseTimeNotifyBefore",
	"EscalationResponseTimeStart",
	"EscalationResponseTimeStop",
	"EscalationUpdateTimeNotifyBefore",
	"EscalationUpdateTimeStart",
	"EscalationUpdateTimeStop",
	"EscalationSolutionTimeNotifyBefore",
	"EscalationSolutionTimeStart",
	"EscalationSolutionTimeStop",
}

Available ticket events that can trigger notifications.

Functions

func AddTestAuthCookie

func AddTestAuthCookie(req *http.Request, token string)

AddTestAuthCookie adds the authentication cookie to a request. This is the standard way to add auth to test requests.

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

func BuildRoutesManifest() ([]byte, error)

BuildRoutesManifest constructs the manifest JSON without registering routes (for tooling).

func BulkSetScreenConfigForField

func BulkSetScreenConfigForField(fieldID int, configs map[string]int, userID int) error

BulkSetScreenConfigForField replaces all screen configs for a field.

func CheckDynamicFieldNameExists

func CheckDynamicFieldNameExists(name string, excludeID int) (bool, error)

CheckDynamicFieldNameExists checks if a field name already exists.

func CheckSignatureNameExists

func CheckSignatureNameExists(name string, excludeID int) (bool, error)

CheckSignatureNameExists checks if a signature name already exists.

func CheckTemplateNameExists

func CheckTemplateNameExists(name string, excludeID int) (bool, error)

CheckTemplateNameExists checks if a template name already exists (excluding a specific ID).

func CreateDynamicField

func CreateDynamicField(field *DynamicField, userID int) (int64, error)

CreateDynamicField creates a new dynamic field.

func CreateSignature

func CreateSignature(name, text, contentType, comments string, validID, userID int) (int, error)

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

func DeleteDynamicField(id int) error

DeleteDynamicField deletes a dynamic field and its values.

func DeleteSignature

func DeleteSignature(id int) error

DeleteSignature deletes a signature by ID.

func DeleteStandardTemplate

func DeleteStandardTemplate(id int) error

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

func ExportAllSignatures() ([]byte, error)

ExportAllSignatures exports all signatures to YAML.

func ExportDynamicFieldsYAML

func ExportDynamicFieldsYAML(fieldNames []string, includeScreens bool) ([]byte, error)

ExportDynamicFieldsYAML exports dynamic fields to YAML format.

func ExportSignature

func ExportSignature(id int) ([]byte, error)

ExportSignature exports a single signature to YAML.

func ExtractToken

func ExtractToken(c *gin.Context) string

ExtractToken delegates to the canonical middleware.ExtractToken.

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 GetArticleAttachments

func GetArticleAttachments(articleID int) ([]map[string]interface{}, error)

GetArticleAttachments retrieves attachments for a specific article from the database.

func GetAttachmentTemplateIDs

func GetAttachmentTemplateIDs(attachmentID int) ([]int, error)

GetAttachmentTemplateIDs returns template IDs assigned to an attachment.

func GetAuthService

func GetAuthService() *service.AuthService

GetAuthService returns the singleton auth service instance.

func GetDistinctDynamicFieldValues

func GetDistinctDynamicFieldValues(fieldID int, limit int) ([]string, error)

Useful for populating filter dropdown options.

func GetDynamicFieldsForScreenGeneric

func GetDynamicFieldsForScreenGeneric(screenKey, objectType string) ([]interface{}, error)

Returns []interface{} to avoid import cycles.

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 GetLookupRepository

func GetLookupRepository() repository.LookupRepository

func GetLookupService

func GetLookupService() *service.LookupService

GetLookupService returns the singleton lookup service instance.

func GetPluginManager

func GetPluginManager() *plugin.Manager

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

func GetQueueTemplateIDs(queueID int) ([]int, error)

GetQueueTemplateIDs returns template IDs assigned to a queue.

func GetStorageService

func GetStorageService() service.StorageService

GetStorageService returns the singleton storage service instance.

func GetTemplateAttachments

func GetTemplateAttachments(templateID int) ([]int, error)

GetTemplateAttachments returns all attachment IDs assigned to a template.

func GetTemplateQueues

func GetTemplateQueues(templateID int) ([]int, error)

GetTemplateQueues returns all queues assigned to a template.

func GetTestAuthToken

func GetTestAuthToken(t *testing.T) string

GetTestAuthToken generates a valid JWT token for testing authenticated routes. Uses environment variables for configuration (see GetTestAuthConfig). This is the single source of truth for test authentication - all tests should use this.

func GetTicketAttachments

func GetTicketAttachments(ticketID int) (map[int][]map[string]interface{}, error)

GetTicketAttachments retrieves all attachments for all articles in a ticket.

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

func GetTicketTemplateVariables(ticketID int) map[string]string

GetTicketTemplateVariables returns template variables for a ticket.

func GetUserIDFromCtx

func GetUserIDFromCtx(c *gin.Context, fallback int) int

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

func GetUserIDFromCtxUint(c *gin.Context, fallback uint) uint

GetUserIDFromCtxUint is like GetUserIDFromCtx but returns uint.

func GetUserMapForTemplate

func GetUserMapForTemplate(c *gin.Context) gin.H

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

func HandleAPIQueueDetails(c *gin.Context)

HandleAPIQueueDetails handles GET /api/queues/:id/details.

@Summary		Get queue details
@Description	Get detailed queue information including ticket counts
@Tags			Queues
@Accept			json
@Produce		json
@Param			id	path		int	true	"Queue ID"
@Success		200	{object}	map[string]interface{}	"Queue details with stats"
@Failure		401	{object}	map[string]interface{}	"Unauthorized"
@Failure		404	{object}	map[string]interface{}	"Queue not found"
@Security		BearerAuth
@Router			/queues/{id}/details [get]

func HandleAPIQueueGet

func HandleAPIQueueGet(c *gin.Context)

HandleAPIQueueGet handles GET /api/queues/:id.

@Summary		Get queue (legacy)
@Description	Get queue by ID (legacy endpoint)
@Tags			Queues
@Accept			json
@Produce		json
@Param			id	path		int	true	"Queue ID"
@Success		200	{object}	map[string]interface{}	"Queue details"
@Failure		400	{object}	map[string]interface{}	"Invalid ID"
@Failure		401	{object}	map[string]interface{}	"Unauthorized"
@Failure		404	{object}	map[string]interface{}	"Queue not found"
@Security		BearerAuth
@Router			/queues/{id} [get]

func HandleAPIQueueStatus

func HandleAPIQueueStatus(c *gin.Context)

HandleAPIQueueStatus handles PUT /api/queues/:id/status.

HandleAPIQueueStatus handles GET /api/queues/:id/status.

@Summary		Get queue status
@Description	Get queue status and metrics
@Tags			Queues
@Accept			json
@Produce		json
@Param			id	path		int	true	"Queue ID"
@Success		200	{object}	map[string]interface{}	"Queue status"
@Failure		401	{object}	map[string]interface{}	"Unauthorized"
@Failure		404	{object}	map[string]interface{}	"Queue not found"
@Security		BearerAuth
@Router			/queues/{id}/status [get]

func HandleAddTicketTime

func HandleAddTicketTime(c *gin.Context)

HandleAddTicketTime is the exported wrapper for YAML routing in the routing package It delegates to handleAddTicketTime to keep the implementation in one place.

func HandleAddUserToGroupAPI

func HandleAddUserToGroupAPI(c *gin.Context)

HandleAddUserToGroupAPI handles POST /api/v1/users/:id/groups.

@Summary		Add user to group
@Description	Add a user to a group
@Tags			Users
@Accept			json
@Produce		json
@Param			id		path		int		true	"User ID"
@Param			group	body		object	true	"Group data (group_id, permission)"
@Success		200		{object}	map[string]interface{}	"User added to group"
@Failure		400		{object}	map[string]interface{}	"Invalid request"
@Failure		401		{object}	map[string]interface{}	"Unauthorized"
@Security		BearerAuth
@Router			/users/{id}/groups [post]

func HandleAdminCreateTargetToken

func HandleAdminCreateTargetToken(c *gin.Context)

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

func HandleAdminCustomerUsersBulkAction(c *gin.Context)

HandleAdminCustomerUsersBulkAction handles POST /admin/customer-users/bulk-action.

func HandleAdminCustomerUsersCreate

func HandleAdminCustomerUsersCreate(c *gin.Context)

HandleAdminCustomerUsersCreate handles POST /admin/customer-users.

func HandleAdminCustomerUsersDelete

func HandleAdminCustomerUsersDelete(c *gin.Context)

HandleAdminCustomerUsersDelete handles DELETE /admin/customer-users/:id (soft delete).

func HandleAdminCustomerUsersExport

func HandleAdminCustomerUsersExport(c *gin.Context)

HandleAdminCustomerUsersExport handles GET /admin/customer-users/export.

func HandleAdminCustomerUsersGet

func HandleAdminCustomerUsersGet(c *gin.Context)

HandleAdminCustomerUsersGet handles GET /admin/customer-users/:id.

func HandleAdminCustomerUsersImport

func HandleAdminCustomerUsersImport(c *gin.Context)

HandleAdminCustomerUsersImport handles POST /admin/customer-users/import.

func HandleAdminCustomerUsersImportForm

func HandleAdminCustomerUsersImportForm(c *gin.Context)

HandleAdminCustomerUsersImportForm handles GET /admin/customer-users/import.

func HandleAdminCustomerUsersList

func HandleAdminCustomerUsersList(c *gin.Context)

HandleAdminCustomerUsersList handles GET /admin/customer-users.

func HandleAdminCustomerUsersTickets

func HandleAdminCustomerUsersTickets(c *gin.Context)

HandleAdminCustomerUsersTickets handles GET /admin/customer-users/:id/tickets.

func HandleAdminCustomerUsersUpdate

func HandleAdminCustomerUsersUpdate(c *gin.Context)

HandleAdminCustomerUsersUpdate handles PUT /admin/customer-users/:id.

func HandleAdminDynamicIndex

func HandleAdminDynamicIndex(c *gin.Context)

func HandleAdminDynamicModule

func HandleAdminDynamicModule(c *gin.Context)

func HandleAdminDynamicModuleFor

func HandleAdminDynamicModuleFor(module string) gin.HandlerFunc

HandleAdminDynamicModuleFor returns a handler that forces the module param to a static value.

func HandleAdminGroupsAddUser

func HandleAdminGroupsAddUser(c *gin.Context)

HandleAdminGroupsAddUser handles POST /admin/groups/:id/users.

func HandleAdminGroupsCreate

func HandleAdminGroupsCreate(c *gin.Context)

HandleAdminGroupsCreate handles POST /admin/groups.

func HandleAdminGroupsDelete

func HandleAdminGroupsDelete(c *gin.Context)

HandleAdminGroupsDelete handles DELETE /admin/groups/:id.

func HandleAdminGroupsRemoveUser

func HandleAdminGroupsRemoveUser(c *gin.Context)

HandleAdminGroupsRemoveUser handles DELETE /admin/groups/:id/users/:userId.

func HandleAdminGroupsUpdate

func HandleAdminGroupsUpdate(c *gin.Context)

HandleAdminGroupsUpdate handles PUT /admin/groups/:id.

func HandleAdminGroupsUsers

func HandleAdminGroupsUsers(c *gin.Context)

HandleAdminGroupsUsers handles GET /admin/groups/:id/users.

func HandleAdminListAllTokens

func HandleAdminListAllTokens(c *gin.Context)

HandleAdminListAllTokens returns all tokens (admin only) GET /api/v1/admin/tokens

func HandleAdminListTargetTokens

func HandleAdminListTargetTokens(c *gin.Context)

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 HandleAdminNotificationEventEdit

func HandleAdminNotificationEventEdit(c *gin.Context)

HandleAdminNotificationEventEdit renders the notification event edit form.

func HandleAdminNotificationEventGet

func HandleAdminNotificationEventGet(c *gin.Context)

HandleAdminNotificationEventGet returns a notification event's details as JSON.

func HandleAdminNotificationEventNew

func HandleAdminNotificationEventNew(c *gin.Context)

HandleAdminNotificationEventNew renders the new notification event form.

func HandleAdminNotificationEvents

func HandleAdminNotificationEvents(c *gin.Context)

HandleAdminNotificationEvents renders the notification events management page.

func HandleAdminPluginLogs

func HandleAdminPluginLogs(c *gin.Context)

HandleAdminPluginLogs renders the plugin logs page. Data is fetched client-side from /api/v1/plugins/logs.

func HandleAdminPlugins

func HandleAdminPlugins(c *gin.Context)

HandleAdminPlugins renders the plugin management page. Data is fetched client-side from /api/v1/plugins.

func HandleAdminPostmasterFilterEdit

func HandleAdminPostmasterFilterEdit(c *gin.Context)

handleAdminPostmasterFilterEdit renders the filter edit form.

func HandleAdminPostmasterFilterGet

func HandleAdminPostmasterFilterGet(c *gin.Context)

handleAdminPostmasterFilterGet returns a filter's details as JSON.

func HandleAdminPostmasterFilterNew

func HandleAdminPostmasterFilterNew(c *gin.Context)

handleAdminPostmasterFilterNew renders the new filter creation form.

func HandleAdminPostmasterFilters

func HandleAdminPostmasterFilters(c *gin.Context)

handleAdminPostmasterFilters renders the postmaster filters management page.

func HandleAdminRevokeTargetToken

func HandleAdminRevokeTargetToken(c *gin.Context)

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

func HandleAdminRevokeToken(c *gin.Context)

HandleAdminRevokeToken revokes any token (admin only) DELETE /api/v1/admin/tokens/:id

func HandleAdminTickets

func HandleAdminTickets(c *gin.Context)

HandleAdminTickets displays all tickets for admin management.

func HandleAdminUserCreate

func HandleAdminUserCreate(c *gin.Context)

HandleAdminUserCreate handles POST /admin/users.

func HandleAdminUserDelete

func HandleAdminUserDelete(c *gin.Context)

HandleAdminUserDelete handles DELETE /admin/users/:id.

func HandleAdminUserGet

func HandleAdminUserGet(c *gin.Context)

HandleAdminUserGet handles GET /admin/users/:id.

func HandleAdminUserGroups

func HandleAdminUserGroups(c *gin.Context)

HandleAdminUserGroups handles GET /admin/users/:id/groups.

func HandleAdminUserResetPassword

func HandleAdminUserResetPassword(c *gin.Context)

HandleAdminUserResetPassword handles password reset for a user by admin.

func HandleAdminUserUpdate

func HandleAdminUserUpdate(c *gin.Context)

HandleAdminUserUpdate handles PUT /admin/users/:id.

func HandleAdminUsers

func HandleAdminUsers(c *gin.Context)

HandleAdminUsers renders the admin users management page.

func HandleAdminUsersCreate

func HandleAdminUsersCreate(c *gin.Context)

HandleAdminUsersCreate handles POST /admin/users.

func HandleAdminUsersDelete

func HandleAdminUsersDelete(c *gin.Context)

HandleAdminUsersDelete handles DELETE /admin/users/:id.

func HandleAdminUsersList

func HandleAdminUsersList(c *gin.Context)

HandleAdminUsersList handles GET /admin/users (JSON API).

func HandleAdminUsersStatus

func HandleAdminUsersStatus(c *gin.Context)

HandleAdminUsersStatus handles PUT /admin/users/:id/status to toggle user valid status.

func HandleAdminUsersUpdate

func HandleAdminUsersUpdate(c *gin.Context)

HandleAdminUsersUpdate handles PUT /admin/users/:id.

func HandleAgentChangePassword

func HandleAgentChangePassword(c *gin.Context)

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

func HandleAgentPasswordForm(c *gin.Context)

HandleAgentPasswordForm renders the agent password change form.

func HandleAgentPerformanceAPI

func HandleAgentPerformanceAPI(c *gin.Context)

HandleAgentPerformanceAPI handles GET /api/v1/statistics/agents.

@Summary		Get agent performance
@Description	Get agent performance statistics
@Tags			Statistics
@Accept			json
@Produce		json
@Success		200	{object}	map[string]interface{}	"Agent performance data"
@Failure		401	{object}	map[string]interface{}	"Unauthorized"
@Security		BearerAuth
@Router			/statistics/agents [get]

func HandleAssignQueueGroupAPI

func HandleAssignQueueGroupAPI(c *gin.Context)

HandleAssignQueueGroupAPI handles POST /api/v1/queues/:id/groups.

@Summary		Assign group to queue
@Description	Assign a group to a queue
@Tags			Queues
@Accept			json
@Produce		json
@Param			id		path		int		true	"Queue ID"
@Param			group	body		object	true	"Group assignment (group_id, permission)"
@Success		200		{object}	map[string]interface{}	"Group assigned"
@Failure		400		{object}	map[string]interface{}	"Invalid request"
@Failure		401		{object}	map[string]interface{}	"Unauthorized"
@Security		BearerAuth
@Router			/queues/{id}/groups [post]

func HandleAssignTicketAPI

func HandleAssignTicketAPI(c *gin.Context)

HandleAssignTicketAPI handles ticket assignment via API.

@Summary		Assign ticket
@Description	Assign a ticket to an agent
@Tags			Ticket Actions
@Accept			json
@Produce		json
@Param			id		path		int		true	"Ticket ID"
@Param			assign	body		object	true	"Assignment data (user_id)"
@Success		200		{object}	map[string]interface{}	"Ticket assigned"
@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}/assign [post]

func HandleClearPluginLogs

func HandleClearPluginLogs(c *gin.Context)

HandleClearPluginLogs clears the plugin log buffer. DELETE /api/v1/plugins/logs

func HandleCloseTicketAPI

func HandleCloseTicketAPI(c *gin.Context)

HandleCloseTicketAPI handles ticket closure via API.

@Summary		Close ticket
@Description	Close a ticket with a specific close state
@Tags			Ticket Actions
@Accept			json
@Produce		json
@Param			id		path		int		true	"Ticket ID"
@Param			close	body		object	false	"Close data (state_id, note)"
@Success		200		{object}	map[string]interface{}	"Ticket closed"
@Failure		401		{object}	map[string]interface{}	"Unauthorized"
@Failure		404		{object}	map[string]interface{}	"Ticket not found"
@Security		BearerAuth
@Router			/tickets/{id}/close [post]

func HandleCreateArticleAPI

func HandleCreateArticleAPI(c *gin.Context)

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

func HandleCreateInternalNote(c *gin.Context)

HandleCreateInternalNote creates a new internal note.

func HandleCreateNotificationEvent

func HandleCreateNotificationEvent(c *gin.Context)

HandleCreateNotificationEvent creates a new notification event.

func HandleCreatePostmasterFilter

func HandleCreatePostmasterFilter(c *gin.Context)

handleCreatePostmasterFilter creates a new postmaster filter.

func HandleCreatePriorityAPI

func HandleCreatePriorityAPI(c *gin.Context)

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

func HandleCreateQueueAPI(c *gin.Context)

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 HandleCreateSLAAPI

func HandleCreateSLAAPI(c *gin.Context)

HandleCreateSLAAPI handles POST /api/v1/slas.

@Summary		Create SLA
@Description	Create a new SLA definition
@Tags			SLAs
@Accept			json
@Produce		json
@Param			sla	body		object	true	"SLA data"
@Success		201	{object}	map[string]interface{}	"Created SLA"
@Failure		400	{object}	map[string]interface{}	"Invalid request"
@Failure		401	{object}	map[string]interface{}	"Unauthorized"
@Security		BearerAuth
@Router			/slas [post]

func HandleCreateSalutationAPI

func HandleCreateSalutationAPI(c *gin.Context)

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 HandleCreateSignatureAPI

func HandleCreateSignatureAPI(c *gin.Context)

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

func HandleCreateSystemAddressAPI(c *gin.Context)

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

func HandleCreateTicketAPI(c *gin.Context)

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 HandleCreateTicketStateAPI

func HandleCreateTicketStateAPI(c *gin.Context)

HandleCreateTicketStateAPI handles POST /api/v1/ticket-states.

@Summary		Create ticket state
@Description	Create a new ticket state
@Tags			States
@Accept			json
@Produce		json
@Param			state	body		object	true	"State data"
@Success		201		{object}	map[string]interface{}	"Created state"
@Failure		400		{object}	map[string]interface{}	"Invalid request"
@Failure		401		{object}	map[string]interface{}	"Unauthorized"
@Security		BearerAuth
@Router			/ticket-states [post]

func HandleCreateToken

func HandleCreateToken(c *gin.Context)

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 HandleCreateUserAPI

func HandleCreateUserAPI(c *gin.Context)

HandleCreateUserAPI handles POST /api/v1/users.

@Summary		Create user
@Description	Create a new agent user
@Tags			Users
@Accept			json
@Produce		json
@Param			user	body		object	true	"User data (login, email, first_name, last_name, password)"
@Success		201		{object}	map[string]interface{}	"Created user"
@Failure		400		{object}	map[string]interface{}	"Invalid request"
@Failure		401		{object}	map[string]interface{}	"Unauthorized"
@Security		BearerAuth
@Router			/users [post]

func HandleCustomerStatisticsAPI

func HandleCustomerStatisticsAPI(c *gin.Context)

HandleCustomerStatisticsAPI handles GET /api/v1/statistics/customers.

@Summary		Get customer statistics
@Description	Get customer-related statistics
@Tags			Statistics
@Accept			json
@Produce		json
@Success		200	{object}	map[string]interface{}	"Customer statistics"
@Failure		401	{object}	map[string]interface{}	"Unauthorized"
@Security		BearerAuth
@Router			/statistics/customers [get]

func HandleDashboardStatisticsAPI

func HandleDashboardStatisticsAPI(c *gin.Context)

HandleDashboardStatisticsAPI handles GET /api/v1/statistics/dashboard.

@Summary		Get dashboard statistics
@Description	Retrieve dashboard statistics (ticket counts, trends) - RBAC filtered
@Tags			Statistics
@Accept			json
@Produce		json
@Success		200	{object}	map[string]interface{}	"Dashboard statistics"
@Failure		401	{object}	map[string]interface{}	"Unauthorized"
@Security		BearerAuth
@Router			/statistics/dashboard [get]

func HandleDebugConfigSources

func HandleDebugConfigSources(c *gin.Context)

HandleDebugConfigSources lists configuration settings with their source.

func HandleDebugTicketNumber

func HandleDebugTicketNumber(c *gin.Context)

HandleDebugTicketNumber returns current ticket number generator info.

func HandleDeleteArticleAPI

func HandleDeleteArticleAPI(c *gin.Context)

HandleDeleteArticleAPI handles DELETE /api/v1/tickets/:ticket_id/articles/:id.

@Summary		Delete article
@Description	Delete an article 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

func HandleDeleteInternalNote(c *gin.Context)

HandleDeleteInternalNote deletes an internal note.

func HandleDeleteNotificationEvent

func HandleDeleteNotificationEvent(c *gin.Context)

HandleDeleteNotificationEvent deletes a notification event.

func HandleDeletePostmasterFilter

func HandleDeletePostmasterFilter(c *gin.Context)

handleDeletePostmasterFilter deletes a postmaster filter.

func HandleDeletePriorityAPI

func HandleDeletePriorityAPI(c *gin.Context)

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

func HandleDeleteQueueAPI(c *gin.Context)

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 HandleDeleteSLAAPI

func HandleDeleteSLAAPI(c *gin.Context)

HandleDeleteSLAAPI handles DELETE /api/v1/slas/:id.

@Summary		Delete SLA
@Description	Delete an SLA definition
@Tags			SLAs
@Accept			json
@Produce		json
@Param			id	path		int	true	"SLA ID"
@Success		200	{object}	map[string]interface{}	"SLA deleted"
@Failure		401	{object}	map[string]interface{}	"Unauthorized"
@Failure		404	{object}	map[string]interface{}	"SLA not found"
@Security		BearerAuth
@Router			/slas/{id} [delete]

func HandleDeleteTicketAPI

func HandleDeleteTicketAPI(c *gin.Context)

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 HandleDeleteTicketStateAPI

func HandleDeleteTicketStateAPI(c *gin.Context)

HandleDeleteTicketStateAPI handles DELETE /api/v1/ticket-states/:id.

@Summary		Delete ticket state
@Description	Delete a ticket state
@Tags			States
@Accept			json
@Produce		json
@Param			id	path		int	true	"State ID"
@Success		200	{object}	map[string]interface{}	"State deleted"
@Failure		401	{object}	map[string]interface{}	"Unauthorized"
@Failure		404	{object}	map[string]interface{}	"State not found"
@Security		BearerAuth
@Router			/ticket-states/{id} [delete]

func HandleDeleteUserAPI

func HandleDeleteUserAPI(c *gin.Context)

HandleDeleteUserAPI handles DELETE /api/v1/users/:id. This performs a soft delete by setting valid_id = 2 (OTRS pattern).

@Summary		Delete user
@Description	Soft delete a user (deactivate)
@Tags			Users
@Accept			json
@Produce		json
@Param			id	path		int	true	"User ID"
@Success		200	{object}	map[string]interface{}	"User deleted"
@Failure		401	{object}	map[string]interface{}	"Unauthorized"
@Failure		404	{object}	map[string]interface{}	"User not found"
@Security		BearerAuth
@Router			/users/{id} [delete]

func HandleDeleteWebhookAPI

func HandleDeleteWebhookAPI(c *gin.Context)

HandleDeleteWebhookAPI handles DELETE /api/v1/webhooks/:id.

@Summary		Delete webhook
@Description	Delete a webhook
@Tags			Webhooks
@Accept			json
@Produce		json
@Param			id	path		int	true	"Webhook ID"
@Success		200	{object}	map[string]interface{}	"Webhook deleted"
@Failure		401	{object}	map[string]interface{}	"Unauthorized"
@Failure		404	{object}	map[string]interface{}	"Webhook not found"
@Security		BearerAuth
@Router			/webhooks/{id} [delete]

func HandleDismissCoachmark

func HandleDismissCoachmark(c *gin.Context)

HandleDismissCoachmark records a coachmark as dismissed for the current user.

func HandleExportStatisticsAPI

func HandleExportStatisticsAPI(c *gin.Context)

HandleExportStatisticsAPI handles GET /api/v1/statistics/export.

@Summary		Export statistics
@Description	Export statistics data
@Tags			Statistics
@Accept			json
@Produce		json
@Param			format	query		string	false	"Export format (csv, json)"
@Success		200		{object}	map[string]interface{}	"Exported data"
@Failure		401		{object}	map[string]interface{}	"Unauthorized"
@Security		BearerAuth
@Router			/statistics/export [get]

func HandleGetArticleAPI

func HandleGetArticleAPI(c *gin.Context)

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"
@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

func HandleGetAvailableLanguages(c *gin.Context)

HandleGetAvailableLanguages returns the list of supported languages (public, no auth required). Used on login pages to allow language selection before authentication.

func HandleGetAvailableThemes

func HandleGetAvailableThemes(c *gin.Context)

HandleGetAvailableThemes returns the list of available themes (public, no auth required). Used on login pages to allow theme selection before authentication.

func HandleGetFormData

func HandleGetFormData(c *gin.Context)

HandleGetFormData returns form data for ticket creation as JSON.

func HandleGetInternalNotes

func HandleGetInternalNotes(c *gin.Context)

HandleGetInternalNotes returns internal notes for a ticket.

func HandleGetLanguage

func HandleGetLanguage(c *gin.Context)

HandleGetLanguage retrieves the user's language preference.

func HandleGetPriorities

func HandleGetPriorities(c *gin.Context)

HandleGetPriorities returns list of priorities as JSON or HTML options for HTMX.

func HandleGetPriorityAPI

func HandleGetPriorityAPI(c *gin.Context)

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

func HandleGetProfile(c *gin.Context)

HandleGetProfile retrieves the current user's profile information.

func HandleGetQueueAPI

func HandleGetQueueAPI(c *gin.Context)

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

func HandleGetQueueAgentsAPI(c *gin.Context)

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

func HandleGetQueueStatsAPI(c *gin.Context)

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

func HandleGetQueues(c *gin.Context)

HandleGetQueues returns list of queues as JSON or HTML options for HTMX.

func HandleGetRemindersEnabled added in v0.7.0

func HandleGetRemindersEnabled(c *gin.Context)

HandleGetRemindersEnabled retrieves the user's reminders enabled preference.

func HandleGetSLAAPI

func HandleGetSLAAPI(c *gin.Context)

HandleGetSLAAPI handles GET /api/v1/slas/:id.

@Summary		Get SLA by ID
@Description	Retrieve a single SLA definition
@Tags			SLAs
@Accept			json
@Produce		json
@Param			id	path		int	true	"SLA ID"
@Success		200	{object}	map[string]interface{}	"SLA details"
@Failure		401	{object}	map[string]interface{}	"Unauthorized"
@Failure		404	{object}	map[string]interface{}	"SLA not found"
@Security		BearerAuth
@Router			/slas/{id} [get]

func HandleGetScopes

func HandleGetScopes(c *gin.Context)

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

func HandleGetSessionTimeout(c *gin.Context)

HandleGetSessionTimeout retrieves the user's session timeout preference.

func HandleGetStatuses

func HandleGetStatuses(c *gin.Context)

HandleGetStatuses returns list of ticket statuses as JSON.

func HandleGetTheme

func HandleGetTheme(c *gin.Context)

HandleGetTheme retrieves the user's theme preferences. Uses UserPreferencesService for agents/admins, CustomerPreferencesService for customers.

func HandleGetTicketAPI

func HandleGetTicketAPI(c *gin.Context)

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 HandleGetTicketStateAPI

func HandleGetTicketStateAPI(c *gin.Context)

HandleGetTicketStateAPI handles GET /api/v1/ticket-states/:id.

@Summary		Get ticket state
@Description	Get a ticket state by ID
@Tags			States
@Accept			json
@Produce		json
@Param			id	path		int	true	"State ID"
@Success		200	{object}	map[string]interface{}	"State details"
@Failure		401	{object}	map[string]interface{}	"Unauthorized"
@Failure		404	{object}	map[string]interface{}	"State not found"
@Security		BearerAuth
@Router			/ticket-states/{id} [get]

func HandleGetTypes

func HandleGetTypes(c *gin.Context)

HandleGetTypes returns list of ticket types as JSON or HTML options for HTMX. Behavior:

  • If a DB connection is available and the query succeeds, return the SQL-backed shape: [{id, name, comments, valid_id}].
  • Otherwise fall back to the lookup service shape (value/label/order/active).
  • For HTMX requests, return HTML <option> elements instead of JSON.

func HandleGetUserAPI

func HandleGetUserAPI(c *gin.Context)

HandleGetUserAPI handles GET /api/v1/users/:id.

@Summary		Get user by ID
@Description	Retrieve a single user by their ID
@Tags			Users
@Accept			json
@Produce		json
@Param			id	path		int	true	"User ID"
@Success		200	{object}	map[string]interface{}	"User details"
@Failure		401	{object}	map[string]interface{}	"Unauthorized"
@Failure		404	{object}	map[string]interface{}	"User not found"
@Security		BearerAuth
@Router			/users/{id} [get]

func HandleGetUserGroupsAPI

func HandleGetUserGroupsAPI(c *gin.Context)

HandleGetUserGroupsAPI handles GET /api/v1/users/:id/groups.

@Summary		Get user groups
@Description	List groups a user belongs to
@Tags			Users
@Accept			json
@Produce		json
@Param			id	path		int	true	"User ID"
@Success		200	{object}	map[string]interface{}	"List of groups"
@Failure		401	{object}	map[string]interface{}	"Unauthorized"
@Failure		404	{object}	map[string]interface{}	"User not found"
@Security		BearerAuth
@Router			/users/{id}/groups [get]

func HandleGetWebhookAPI

func HandleGetWebhookAPI(c *gin.Context)

HandleGetWebhookAPI handles GET /api/v1/webhooks/:id.

@Summary		Get webhook
@Description	Get webhook by ID
@Tags			Webhooks
@Accept			json
@Produce		json
@Param			id	path		int	true	"Webhook ID"
@Success		200	{object}	map[string]interface{}	"Webhook details"
@Failure		401	{object}	map[string]interface{}	"Unauthorized"
@Failure		404	{object}	map[string]interface{}	"Webhook not found"
@Security		BearerAuth
@Router			/webhooks/{id} [get]

func HandleInvalidateLookupCache

func HandleInvalidateLookupCache(c *gin.Context)

HandleInvalidateLookupCache forces a refresh of the lookup cache.

func HandleLegacyAgentTicketViewRedirect

func HandleLegacyAgentTicketViewRedirect(c *gin.Context)

HandleLegacyAgentTicketViewRedirect exported for YAML routing.

func HandleLegacyTicketsViewRedirect

func HandleLegacyTicketsViewRedirect(c *gin.Context)

HandleLegacyTicketsViewRedirect exported for YAML routing.

func HandleListArticlesAPI

func HandleListArticlesAPI(c *gin.Context)

HandleListArticlesAPI handles GET /api/v1/tickets/:ticket_id/articles.

@Summary		List ticket articles
@Description	Retrieve all articles for a ticket
@Tags			Articles
@Accept			json
@Produce		json
@Param			ticket_id	path		int		true	"Ticket ID"
@Param			page		query		int		false	"Page number"				default(1)
@Param			per_page	query		int		false	"Items per page"			default(20)
@Param			limit		query		int		false	"Alias for per_page"
@Param			offset		query		int		false	"Offset for pagination"
@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

func HandleListGroupsAPI(c *gin.Context)

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

func HandleListPrioritiesAPI(c *gin.Context)

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

func HandleListQueuesAPI(c *gin.Context)

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 HandleListSLAsAPI

func HandleListSLAsAPI(c *gin.Context)

HandleListSLAsAPI handles GET /api/v1/slas. 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")

HandleListSLAsAPI handles GET /api/v1/slas.

@Summary		List SLAs
@Description	Retrieve all SLA definitions
@Tags			SLAs
@Accept			json
@Produce		json
@Success		200	{object}	map[string]interface{}	"List of SLAs"
@Failure		401	{object}	map[string]interface{}	"Unauthorized"
@Security		BearerAuth
@Router			/slas [get]

func HandleListSalutationsAPI

func HandleListSalutationsAPI(c *gin.Context)

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 HandleListServicesAPI

func HandleListServicesAPI(c *gin.Context)

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

func HandleListSignaturesAPI(c *gin.Context)

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

func HandleListStatesAPI(c *gin.Context)

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

func HandleListSystemAddressesAPI(c *gin.Context)

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 HandleListTicketStatesAPI

func HandleListTicketStatesAPI(c *gin.Context)

HandleListTicketStatesAPI handles GET /api/v1/ticket-states.

@Summary		List ticket states
@Description	Retrieve all ticket states (alias for /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			/ticket-states [get]

func HandleListTicketsAPI

func HandleListTicketsAPI(c *gin.Context)

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

func HandleListTokens(c *gin.Context)

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

func HandleListTypesAPI(c *gin.Context)

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")

HandleListTypesAPI handles GET /api/v1/types.

@Summary		List types
@Description	Retrieve all ticket types
@Tags			Types
@Accept			json
@Produce		json
@Success		200	{object}	map[string]interface{}	"List of types"
@Failure		401	{object}	map[string]interface{}	"Unauthorized"
@Security		BearerAuth
@Router			/types [get]

func HandleListUsersAPI

func HandleListUsersAPI(c *gin.Context)

HandleListUsersAPI handles GET /api/v1/users.

@Summary		List users
@Description	Retrieve a paginated list of users (agents)
@Tags			Users
@Accept			json
@Produce		json
@Param			page		query		int		false	"Page number"		default(1)
@Param			per_page	query		int		false	"Items per page"	default(20)
@Param			search		query		string	false	"Search in login, name, email"
@Param			group_id	query		int		false	"Filter by group membership"
@Success		200			{object}	map[string]interface{}	"List of users"
@Failure		401			{object}	map[string]interface{}	"Unauthorized"
@Security		BearerAuth
@Router			/users [get]

func HandleListWebhooksAPI

func HandleListWebhooksAPI(c *gin.Context)

HandleListWebhooksAPI handles GET /api/v1/webhooks.

@Summary		List webhooks
@Description	List all registered webhooks
@Tags			Webhooks
@Accept			json
@Produce		json
@Success		200	{object}	map[string]interface{}	"List of webhooks"
@Failure		401	{object}	map[string]interface{}	"Unauthorized"
@Security		BearerAuth
@Router			/webhooks [get]

func HandleLoginAPI

func HandleLoginAPI(c *gin.Context)

HandleLoginAPI authenticates a user and returns JWT tokens.

@Summary		Login
@Description	Authenticate user with login/password and return JWT tokens
@Tags			Authentication
@Accept			json
@Produce		json
@Param			credentials	body		object	true	"Login credentials (login, password)"
@Success		200			{object}	map[string]interface{}	"JWT tokens (access_token, refresh_token)"
@Failure		400			{object}	map[string]interface{}	"Invalid request"
@Failure		401			{object}	map[string]interface{}	"Invalid credentials"
@Router			/auth/login [post]

func HandleLogoutAPI

func HandleLogoutAPI(c *gin.Context)

HandleLogoutAPI logs out a user (client-side token removal).

@Summary		Logout
@Description	Logout user (invalidates session, client should discard tokens)
@Tags			Authentication
@Accept			json
@Produce		json
@Success		200	{object}	map[string]interface{}	"Logout successful"
@Security		BearerAuth
@Router			/auth/logout [post]

func HandleMCP

func HandleMCP(c *gin.Context)

HandleMCP handles POST /api/mcp for MCP JSON-RPC messages. Requires Bearer token authentication via API token.

@Summary		MCP JSON-RPC endpoint
@Description	Model Context Protocol endpoint for AI assistant integration
@Tags			MCP
@Accept			json
@Produce		json
@Param			request	body		object	true	"JSON-RPC 2.0 request"
@Success		200		{object}	object	"JSON-RPC 2.0 response"
@Failure		401		{object}	map[string]interface{}	"Unauthorized"
@Security		BearerAuth
@Router			/mcp [post]

func HandleMCPInfo

func HandleMCPInfo(c *gin.Context)

HandleMCPInfo returns information about the MCP endpoint.

@Summary		MCP endpoint info
@Description	Get information about the MCP endpoint and available tools
@Tags			MCP
@Produce		json
@Success		200	{object}	map[string]interface{}	"MCP info"
@Router			/mcp [get]

func HandleMailAccountPollStatus

func HandleMailAccountPollStatus(c *gin.Context)

HandleMailAccountPollStatus returns the last poll status for a mail account from Valkey.

func HandlePasswordPolicy

func HandlePasswordPolicy(c *gin.Context)

HandlePasswordPolicy returns the current password policy settings.

func HandlePluginCall

func HandlePluginCall(c *gin.Context)

HandlePluginCall invokes a plugin function. POST /api/v1/plugins/:name/call/:fn

func HandlePluginDisable

func HandlePluginDisable(c *gin.Context)

HandlePluginDisable disables a plugin. POST /api/v1/plugins/:name/disable

func HandlePluginEnable

func HandlePluginEnable(c *gin.Context)

HandlePluginEnable enables a plugin. POST /api/v1/plugins/:name/enable

func HandlePluginList

func HandlePluginList(c *gin.Context)

HandlePluginList returns all registered plugins. GET /api/v1/plugins

func HandlePluginLogs

func HandlePluginLogs(c *gin.Context)

HandlePluginLogs returns plugin log entries. GET /api/v1/plugins/logs?plugin=name&level=info&limit=100

func HandlePluginUpload

func HandlePluginUpload(c *gin.Context)

HandlePluginUpload handles uploading a new WASM plugin. POST /api/v1/plugins/upload

func HandlePluginWidget

func HandlePluginWidget(c *gin.Context)

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

func HandlePluginWidgetList(c *gin.Context)

HandlePluginWidgetList returns available widgets for a location (triggers lazy load). GET /api/v1/plugins/widgets?location=dashboard

func HandleProfile

func HandleProfile(c *gin.Context)

HandleProfile is the exported version of handleProfile.

func HandleQueueMetricsAPI

func HandleQueueMetricsAPI(c *gin.Context)

HandleQueueMetricsAPI handles GET /api/v1/statistics/queues.

@Summary		Get queue metrics
@Description	Get queue performance metrics
@Tags			Statistics
@Accept			json
@Produce		json
@Success		200	{object}	map[string]interface{}	"Queue metrics"
@Failure		401	{object}	map[string]interface{}	"Unauthorized"
@Security		BearerAuth
@Router			/statistics/queues [get]

func HandleRedirect

func HandleRedirect(c *gin.Context)

HandleRedirect handles redirect routes.

func HandleRedirectProfile

func HandleRedirectProfile(c *gin.Context)

HandleRedirectProfile is the exported version of redirect handler.

func HandleRedirectQueues

func HandleRedirectQueues(c *gin.Context)

HandleRedirectQueues is the exported version.

func HandleRedirectSettings

func HandleRedirectSettings(c *gin.Context)

HandleRedirectSettings is the exported version.

func HandleRedirectTickets

func HandleRedirectTickets(c *gin.Context)

HandleRedirectTickets is the exported version.

func HandleRedirectTicketsNew

func HandleRedirectTicketsNew(c *gin.Context)

HandleRedirectTicketsNew is the exported version.

func HandleRefreshTokenAPI

func HandleRefreshTokenAPI(c *gin.Context)

HandleRefreshTokenAPI refreshes an expired JWT token.

@Summary		Refresh token
@Description	Exchange a refresh token for a new access token
@Tags			Authentication
@Accept			json
@Produce		json
@Param			token	body		object	true	"Refresh token"
@Success		200		{object}	map[string]interface{}	"New access token"
@Failure		400		{object}	map[string]interface{}	"Invalid request"
@Failure		401		{object}	map[string]interface{}	"Invalid or expired refresh token"
@Router			/auth/refresh [post]

func HandleRegisterAPI

func HandleRegisterAPI(c *gin.Context)

HandleRegisterAPI registers a new user (if enabled).

@Summary		Register user
@Description	Register a new user (if self-registration is enabled)
@Tags			Authentication
@Accept			json
@Produce		json
@Param			user	body		object	true	"User registration data"
@Success		201		{object}	map[string]interface{}	"Registered user"
@Failure		400		{object}	map[string]interface{}	"Invalid request or registration disabled"
@Router			/auth/register [post]

func HandleRegisterWebhookAPI

func HandleRegisterWebhookAPI(c *gin.Context)

HandleRegisterWebhookAPI handles POST /api/v1/webhooks.

@Summary		Register webhook
@Description	Register a new webhook endpoint
@Tags			Webhooks
@Accept			json
@Produce		json
@Param			webhook	body		object	true	"Webhook data (url, events, secret)"
@Success		201		{object}	map[string]interface{}	"Webhook registered"
@Failure		400		{object}	map[string]interface{}	"Invalid request"
@Failure		401		{object}	map[string]interface{}	"Unauthorized"
@Security		BearerAuth
@Router			/webhooks [post]

func HandleReindexAPI

func HandleReindexAPI(c *gin.Context)

HandleReindexAPI handles POST /api/v1/search/reindex.

@Summary		Reindex search
@Description	Trigger a search index rebuild
@Tags			Search
@Accept			json
@Produce		json
@Success		200	{object}	map[string]interface{}	"Reindex started"
@Failure		401	{object}	map[string]interface{}	"Unauthorized"
@Security		BearerAuth
@Router			/search/reindex [post]

func HandleRemoveQueueGroupAPI

func HandleRemoveQueueGroupAPI(c *gin.Context)

HandleRemoveQueueGroupAPI handles DELETE /api/v1/queues/:id/groups/:group_id.

@Summary		Remove group from queue
@Description	Remove a group assignment from a queue
@Tags			Queues
@Accept			json
@Produce		json
@Param			id			path		int	true	"Queue ID"
@Param			group_id	path		int	true	"Group ID"
@Success		200			{object}	map[string]interface{}	"Group removed"
@Failure		401			{object}	map[string]interface{}	"Unauthorized"
@Failure		404			{object}	map[string]interface{}	"Not found"
@Security		BearerAuth
@Router			/queues/{id}/groups/{group_id} [delete]

func HandleRemoveUserFromGroupAPI

func HandleRemoveUserFromGroupAPI(c *gin.Context)

HandleRemoveUserFromGroupAPI handles DELETE /api/v1/users/:id/groups/:group_id.

@Summary		Remove user from group
@Description	Remove a user from a group
@Tags			Users
@Accept			json
@Produce		json
@Param			id			path		int	true	"User ID"
@Param			group_id	path		int	true	"Group ID"
@Success		200			{object}	map[string]interface{}	"User removed from group"
@Failure		401			{object}	map[string]interface{}	"Unauthorized"
@Failure		404			{object}	map[string]interface{}	"Not found"
@Security		BearerAuth
@Router			/users/{id}/groups/{group_id} [delete]

func HandleReopenTicketAPI

func HandleReopenTicketAPI(c *gin.Context)

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 HandleRetryWebhookDeliveryAPI

func HandleRetryWebhookDeliveryAPI(c *gin.Context)

HandleRetryWebhookDeliveryAPI handles POST /api/v1/webhooks/deliveries/:id/retry.

@Summary		Retry webhook delivery
@Description	Retry a failed webhook delivery
@Tags			Webhooks
@Accept			json
@Produce		json
@Param			id	path		int	true	"Delivery ID"
@Success		200	{object}	map[string]interface{}	"Retry result"
@Failure		401	{object}	map[string]interface{}	"Unauthorized"
@Failure		404	{object}	map[string]interface{}	"Delivery not found"
@Security		BearerAuth
@Router			/webhooks/deliveries/{id}/retry [post]

func HandleRevokeToken

func HandleRevokeToken(c *gin.Context)

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 HandleSLAMetricsAPI

func HandleSLAMetricsAPI(c *gin.Context)

HandleSLAMetricsAPI handles GET /api/v1/slas/:id/metrics.

@Summary		Get SLA metrics
@Description	Retrieve performance metrics for an SLA
@Tags			SLAs
@Accept			json
@Produce		json
@Param			id	path		int	true	"SLA ID"
@Success		200	{object}	map[string]interface{}	"SLA metrics"
@Failure		401	{object}	map[string]interface{}	"Unauthorized"
@Failure		404	{object}	map[string]interface{}	"SLA not found"
@Security		BearerAuth
@Router			/slas/{id}/metrics [get]

func HandleSearchAPI

func HandleSearchAPI(c *gin.Context)

HandleSearchAPI handles POST /api/v1/search.

@Summary		Search tickets
@Description	Full-text search across tickets
@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"
@Security		BearerAuth
@Router			/search [post]

func HandleSearchHealthAPI

func HandleSearchHealthAPI(c *gin.Context)

HandleSearchHealthAPI handles GET /api/v1/search/health.

@Summary		Search health
@Description	Check search engine health status
@Tags			Search
@Accept			json
@Produce		json
@Success		200	{object}	map[string]interface{}	"Search health status"
@Failure		401	{object}	map[string]interface{}	"Unauthorized"
@Security		BearerAuth
@Router			/search/health [get]

func HandleSearchSuggestionsAPI

func HandleSearchSuggestionsAPI(c *gin.Context)

HandleSearchSuggestionsAPI handles GET /api/v1/search/suggestions.

@Summary		Get search suggestions
@Description	Get autocomplete suggestions for search
@Tags			Search
@Accept			json
@Produce		json
@Param			q	query		string	true	"Search query prefix"
@Success		200	{object}	map[string]interface{}	"Suggestions"
@Failure		401	{object}	map[string]interface{}	"Unauthorized"
@Security		BearerAuth
@Router			/search/suggestions [get]

func HandleSetLanguage

func HandleSetLanguage(c *gin.Context)

HandleSetLanguage sets the user's language preference.

func HandleSetPreLoginLanguage

func HandleSetPreLoginLanguage(c *gin.Context)

HandleSetPreLoginLanguage sets the language preference cookie (public, no auth required). This is used on login pages before the user authenticates.

func HandleSetPreLoginTheme

func HandleSetPreLoginTheme(c *gin.Context)

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

func HandleSetRemindersEnabled(c *gin.Context)

HandleSetRemindersEnabled sets the user's reminders enabled preference.

func HandleSetSessionTimeout

func HandleSetSessionTimeout(c *gin.Context)

HandleSetSessionTimeout sets the user's session timeout preference.

func HandleSetTheme

func HandleSetTheme(c *gin.Context)

HandleSetTheme sets the user's theme preferences and persists to database. Uses UserPreferencesService for agents/admins, CustomerPreferencesService for customers.

func HandleSetWallpaper

func HandleSetWallpaper(c *gin.Context)

HandleSetWallpaper saves the user's wallpaper preference (on/off).

func HandleStaticFiles

func HandleStaticFiles(c *gin.Context)

HandleStaticFiles serves static files from the static directory.

func HandleTemplate

func HandleTemplate(c *gin.Context)

HandleTemplate handles template rendering routes.

func HandleTestWebhookAPI

func HandleTestWebhookAPI(c *gin.Context)

HandleTestWebhookAPI handles POST /api/v1/webhooks/:id/test.

@Summary		Test webhook
@Description	Send a test event to a webhook
@Tags			Webhooks
@Accept			json
@Produce		json
@Param			id	path		int	true	"Webhook ID"
@Success		200	{object}	map[string]interface{}	"Test result"
@Failure		401	{object}	map[string]interface{}	"Unauthorized"
@Failure		404	{object}	map[string]interface{}	"Webhook not found"
@Security		BearerAuth
@Router			/webhooks/{id}/test [post]

func HandleTicketHistoryFragment

func HandleTicketHistoryFragment(c *gin.Context)

HandleTicketHistoryFragment is an HTMX handler for ticket history fragment in tab panel.

func HandleTicketLinksFragment

func HandleTicketLinksFragment(c *gin.Context)

HandleTicketLinksFragment is an HTMX handler for ticket links fragment in tab panel.

func HandleTicketStateStatisticsAPI

func HandleTicketStateStatisticsAPI(c *gin.Context)

HandleTicketStateStatisticsAPI handles GET /api/v1/ticket-states/statistics.

@Summary		Get state statistics
@Description	Get ticket counts by state
@Tags			States
@Accept			json
@Produce		json
@Success		200	{object}	map[string]interface{}	"State statistics"
@Failure		401	{object}	map[string]interface{}	"Unauthorized"
@Security		BearerAuth
@Router			/ticket-states/statistics [get]

func HandleTicketTrendsAPI

func HandleTicketTrendsAPI(c *gin.Context)

HandleTicketTrendsAPI handles GET /api/v1/statistics/trends.

@Summary		Get ticket trends
@Description	Retrieve ticket creation/resolution trends over time
@Tags			Statistics
@Accept			json
@Produce		json
@Param			period	query		string	false	"Time period (day, week, month)"
@Success		200		{object}	map[string]interface{}	"Trend data"
@Failure		401		{object}	map[string]interface{}	"Unauthorized"
@Security		BearerAuth
@Router			/statistics/trends [get]

func HandleTimeBasedAnalyticsAPI

func HandleTimeBasedAnalyticsAPI(c *gin.Context)

HandleTimeBasedAnalyticsAPI handles GET /api/v1/statistics/analytics.

@Summary		Get time-based analytics
@Description	Get time-based ticket analytics
@Tags			Statistics
@Accept			json
@Produce		json
@Param			period	query		string	false	"Time period"
@Success		200		{object}	map[string]interface{}	"Analytics data"
@Failure		401		{object}	map[string]interface{}	"Unauthorized"
@Security		BearerAuth
@Router			/statistics/analytics [get]

func HandleUpdateArticleAPI

func HandleUpdateArticleAPI(c *gin.Context)

HandleUpdateArticleAPI handles PUT /api/v1/tickets/:ticket_id/articles/:id.

@Summary		Update article
@Description	Update 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"
@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

func HandleUpdateInternalNote(c *gin.Context)

HandleUpdateInternalNote updates an existing internal note.

func HandleUpdateNotificationEvent

func HandleUpdateNotificationEvent(c *gin.Context)

HandleUpdateNotificationEvent updates an existing notification event.

func HandleUpdatePostmasterFilter

func HandleUpdatePostmasterFilter(c *gin.Context)

handleUpdatePostmasterFilter updates an existing postmaster filter.

func HandleUpdatePriorityAPI

func HandleUpdatePriorityAPI(c *gin.Context)

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

func HandleUpdateProfile(c *gin.Context)

HandleUpdateProfile updates the current user's profile information.

func HandleUpdateQueueAPI

func HandleUpdateQueueAPI(c *gin.Context)

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 HandleUpdateSLAAPI

func HandleUpdateSLAAPI(c *gin.Context)

HandleUpdateSLAAPI handles PUT /api/v1/slas/:id.

@Summary		Update SLA
@Description	Update an existing SLA definition
@Tags			SLAs
@Accept			json
@Produce		json
@Param			id	path		int		true	"SLA ID"
@Param			sla	body		object	true	"SLA update data"
@Success		200	{object}	map[string]interface{}	"Updated SLA"
@Failure		400	{object}	map[string]interface{}	"Invalid request"
@Failure		401	{object}	map[string]interface{}	"Unauthorized"
@Failure		404	{object}	map[string]interface{}	"SLA not found"
@Security		BearerAuth
@Router			/slas/{id} [put]

func HandleUpdateSalutationAPI

func HandleUpdateSalutationAPI(c *gin.Context)

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 HandleUpdateSignatureAPI

func HandleUpdateSignatureAPI(c *gin.Context)

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

func HandleUpdateSystemAddressAPI(c *gin.Context)

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

func HandleUpdateTicketAPI(c *gin.Context)

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 HandleUpdateTicketStateAPI

func HandleUpdateTicketStateAPI(c *gin.Context)

HandleUpdateTicketStateAPI handles PUT /api/v1/ticket-states/:id.

@Summary		Update ticket state
@Description	Update a ticket state
@Tags			States
@Accept			json
@Produce		json
@Param			id		path		int		true	"State ID"
@Param			state	body		object	true	"State update data"
@Success		200		{object}	map[string]interface{}	"Updated state"
@Failure		400		{object}	map[string]interface{}	"Invalid request"
@Failure		401		{object}	map[string]interface{}	"Unauthorized"
@Failure		404		{object}	map[string]interface{}	"State not found"
@Security		BearerAuth
@Router			/ticket-states/{id} [put]

func HandleUpdateUserAPI

func HandleUpdateUserAPI(c *gin.Context)

HandleUpdateUserAPI handles PUT /api/v1/users/:id.

@Summary		Update user
@Description	Update an existing user's properties
@Tags			Users
@Accept			json
@Produce		json
@Param			id		path		int		true	"User ID"
@Param			user	body		object	true	"User update data"
@Success		200		{object}	map[string]interface{}	"Updated user"
@Failure		400		{object}	map[string]interface{}	"Invalid request"
@Failure		401		{object}	map[string]interface{}	"Unauthorized"
@Failure		404		{object}	map[string]interface{}	"User not found"
@Security		BearerAuth
@Router			/users/{id} [put]

func HandleUpdateWebhookAPI

func HandleUpdateWebhookAPI(c *gin.Context)

HandleUpdateWebhookAPI handles PUT /api/v1/webhooks/:id.

@Summary		Update webhook
@Description	Update a webhook
@Tags			Webhooks
@Accept			json
@Produce		json
@Param			id		path		int		true	"Webhook ID"
@Param			webhook	body		object	true	"Webhook update data"
@Success		200		{object}	map[string]interface{}	"Updated webhook"
@Failure		400		{object}	map[string]interface{}	"Invalid request"
@Failure		401		{object}	map[string]interface{}	"Unauthorized"
@Failure		404		{object}	map[string]interface{}	"Webhook not found"
@Security		BearerAuth
@Router			/webhooks/{id} [put]

func HandleUserMeAPI

func HandleUserMeAPI(c *gin.Context)

HandleUserMeAPI returns the current authenticated user's information.

@Summary		Get current user
@Description	Get the authenticated user's profile
@Tags			Users
@Accept			json
@Produce		json
@Success		200	{object}	map[string]interface{}	"User profile"
@Failure		401	{object}	map[string]interface{}	"Unauthorized"
@Security		BearerAuth
@Router			/users/me [get]

func HandleWebhookDeliveriesAPI

func HandleWebhookDeliveriesAPI(c *gin.Context)

HandleWebhookDeliveriesAPI handles GET /api/v1/webhooks/:id/deliveries.

@Summary		List webhook deliveries
@Description	List delivery history for a webhook
@Tags			Webhooks
@Accept			json
@Produce		json
@Param			id	path		int	true	"Webhook ID"
@Success		200	{object}	map[string]interface{}	"List of deliveries"
@Failure		401	{object}	map[string]interface{}	"Unauthorized"
@Failure		404	{object}	map[string]interface{}	"Webhook not found"
@Security		BearerAuth
@Router			/webhooks/{id}/deliveries [get]

func ImportSignatures

func ImportSignatures(data []byte, overwrite bool) (imported int, skipped int, err error)

ImportSignatures imports signatures from YAML data.

func ImportTemplates

func ImportTemplates(data []byte, overwrite bool, userID int) (imported int, skipped int, errors []string)

ImportTemplates imports templates from YAML data.

func ImprovedHandleAdminUserGet

func ImprovedHandleAdminUserGet(c *gin.Context)

ImprovedHandleAdminUserGet handles GET /admin/users/:id with enhanced error handling and logging.

func ImprovedHandleAdminUserUpdate

func ImprovedHandleAdminUserUpdate(c *gin.Context)

ImprovedHandleAdminUserUpdate handles PUT /admin/users/:id with enhanced group handling.

func InitAPITokenService

func InitAPITokenService(db *sql.DB)

InitAPITokenService initializes the API token service with a database connection

func InitializeLDAPService

func InitializeLDAPService()

InitializeLDAPService initializes the LDAP service with repositories.

func InitializeServices

func InitializeServices()

InitializeServices initializes singleton service instances.

func JWTAuthMiddleware

func JWTAuthMiddleware() gin.HandlerFunc

JWTAuthMiddleware is a middleware that requires JWT authentication.

func JoinTemplateTypes

func JoinTemplateTypes(types []string) string

JoinTemplateTypes joins template types into a sorted comma-separated string.

func ListHandlers

func ListHandlers() []string

ListHandlers returns sorted handler names (for diagnostics / tests).

func LoadTicketStatesForForm

func LoadTicketStatesForForm(db *sql.DB) ([]gin.H, map[string]gin.H, error)

LoadTicketStatesForForm fetches valid ticket states and builds alias lookup data for forms.

func MountDynamicEngine added in v0.7.0

func MountDynamicEngine(r *gin.Engine, routesDir string)

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 NewHTMXRouter

func NewHTMXRouter(jwtManager *auth.JWTManager, ldapProvider *ldap.Provider) *gin.Engine

NewHTMXRouter creates all routes for the HTMX UI.

func NewSimpleRouter

func NewSimpleRouter() *gin.Engine

NewSimpleRouter creates a router with basic routes.

func NewSimpleRouterWithDB

func NewSimpleRouterWithDB(db *sql.DB) *gin.Engine

NewSimpleRouterWithDB creates a router with basic routes and a specific database connection.

func ParseTemplateTypes

func ParseTemplateTypes(typeStr string) []string

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 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 RegisterCannedResponseHandlers

func RegisterCannedResponseHandlers(r *gin.RouterGroup)

RegisterCannedResponseHandlers registers all canned response API routes.

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)

func RegisterPluginRoutes

func RegisterPluginRoutes(r *gin.Engine) int

RegisterPluginRoutes is a no-op kept for backwards compatibility. Plugin routes are now handled by the unified dynamic engine (MountDynamicEngine). Deprecated: Use MountDynamicEngine instead.

func RegisterWithRouting

func RegisterWithRouting(registry interface{}) error

The routing registration should be handled at the application level.

func RenderMarkdown

func RenderMarkdown(content string) string

RenderMarkdown converts markdown content to HTML with Tailwind styling.

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 user belongs to a specific group. Admin users (role=Admin or isInAdminGroup) bypass group checks. Used by plugins via "group:<name>" middleware, e.g. "group:fictus-users".

func RootRedirectTarget

func RootRedirectTarget() string

func SessionOrJWTAuth added in v0.7.0

func SessionOrJWTAuth() gin.HandlerFunc

RegisterPluginAPIRoutes registers the plugin management API endpoints. GET /api/v1/plugins - List all plugins (authenticated) POST /api/v1/plugins/:name/call/:fn - Call a plugin function (authenticated) GET /api/v1/plugins/:name/widgets/:id - Get widget HTML (authenticated, HTMX-friendly) POST /api/v1/plugins/:name/enable - Enable a plugin (admin only) POST /api/v1/plugins/:name/disable - Disable a plugin (admin only) 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

func SetAttachmentTemplates(attachmentID int, templateIDs []int, userID int) error

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

func SetPluginManager(mgr *plugin.Manager)

SetPluginManager sets the global plugin manager.

func SetPluginReloader added in v0.7.0

func SetPluginReloader(fn func(ctx context.Context, name string) error)

SetPluginReloader sets the callback used to load/reload a plugin after upload.

func SetQueueTemplates

func SetQueueTemplates(queueID int, templateIDs []int, userID int) error

SetQueueTemplates replaces all template assignments for a queue.

func SetScreenConfig

func SetScreenConfig(fieldID int, screenKey string, configValue int, userID int) error

SetScreenConfig sets a single field-screen config.

func SetTemplateAttachments

func SetTemplateAttachments(templateID int, attachmentIDs []int, userID int) error

SetTemplateAttachments sets the attachment assignments for a template.

func SetTemplateQueues

func SetTemplateQueues(templateID int, queueIDs []int, userID int) error

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 SetupAPIv1Routes

func SetupAPIv1Routes(r *gin.Engine, jwtManager *auth.JWTManager, ldapProvider *ldap.Provider, i18nSvc interface{})

SetupAPIv1Routes configures the v1 API routes.

func SetupBasicRoutes

func SetupBasicRoutes(r *gin.Engine)

SetupBasicRoutes adds basic routes to an existing router.

func SetupDynamicModules

func SetupDynamicModules(db *sql.DB) error

SetupDynamicModules initializes the dynamic module system. Route registration is handled via YAML; this ensures endpoints exist even before the handler is ready.

func SetupHTMXRoutes

func SetupHTMXRoutes(r *gin.Engine)

SetupHTMXRoutes sets up all HTMX routes on the given router.

func SetupLDAPRoutes

func SetupLDAPRoutes(r *gin.Engine)

SetupLDAPRoutes configures LDAP API routes.

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 SetupTestTemplateRenderer

func SetupTestTemplateRenderer(t *testing.T)

SetupTestTemplateRenderer initializes the global template renderer for tests. This MUST be called by any test that exercises handlers calling shared.GetGlobalRenderer(). Safe to call multiple times - initialization happens only once.

func SubstituteSignatureVariables

func SubstituteSignatureVariables(text string, vars map[string]string) string

Reuses the same variable substitution logic as templates.

func SubstituteTemplateVariables

func SubstituteTemplateVariables(text string, vars map[string]string) string

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 (&lt;OTRS_*&gt;).

func SupportsAutoConfig

func SupportsAutoConfig(fieldType string) bool

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

func UpdateSignature(id int, name, text, contentType, comments string, validID, userID int) error

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

func ValidateAllTemplates(templatesDir string) ([]string, error)

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

func ValidateTemplatesReferencedInRoutes(routesDir, templatesDir string) ([]string, error)

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.

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 ACLHelper

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

ACLHelper provides ACL filtering for ticket-related data.

func NewACLHelper

func NewACLHelper(db *sql.DB) *ACLHelper

NewACLHelper creates a new ACL helper with the given database connection.

func (*ACLHelper) BuildACLContext

func (h *ACLHelper) BuildACLContext(ticket *models.Ticket, userID int, action string) *models.ACLContext

BuildACLContext creates an ACL context from ticket and user information.

func (*ACLHelper) FilterActions

func (h *ACLHelper) FilterActions(ctx context.Context, aclCtx *models.ACLContext, actions []string) []string

FilterActions filters available actions (buttons) based on ACLs.

func (*ACLHelper) FilterPriorities

func (h *ACLHelper) FilterPriorities(ctx context.Context, aclCtx *models.ACLContext, priorities []map[string]interface{}) []map[string]interface{}

FilterPriorities filters available priorities based on ACLs.

func (*ACLHelper) FilterQueues

func (h *ACLHelper) FilterQueues(ctx context.Context, aclCtx *models.ACLContext, queues []map[string]interface{}) []map[string]interface{}

FilterQueues filters available queues based on ACLs.

func (*ACLHelper) FilterSLAs

func (h *ACLHelper) FilterSLAs(ctx context.Context, aclCtx *models.ACLContext, slas []map[string]interface{}) []map[string]interface{}

FilterSLAs filters available SLAs based on ACLs.

func (*ACLHelper) FilterServices

func (h *ACLHelper) FilterServices(ctx context.Context, aclCtx *models.ACLContext, services []map[string]interface{}) []map[string]interface{}

FilterServices filters available services based on ACLs.

func (*ACLHelper) FilterStates

func (h *ACLHelper) FilterStates(ctx context.Context, aclCtx *models.ACLContext, states []map[string]interface{}) []map[string]interface{}

FilterStates filters available ticket states based on ACLs. The states parameter is a slice of maps with "id" and "name" keys.

func (*ACLHelper) FilterTypes

func (h *ACLHelper) FilterTypes(ctx context.Context, aclCtx *models.ACLContext, types []map[string]interface{}) []map[string]interface{}

FilterTypes filters available ticket types based on ACLs.

func (*ACLHelper) RefreshCache

func (h *ACLHelper) RefreshCache(ctx context.Context) error

RefreshCache refreshes the cached ACLs.

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 // 1=email, 2=phone, 3=internal, 4=chat
	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 Attachment

type Attachment struct {
	ID          int       `json:"id"`
	TicketID    int       `json:"ticket_id"`
	Filename    string    `json:"filename"`
	ContentType string    `json:"content_type"`
	Size        int64     `json:"size"`
	StoragePath string    `json:"-"` // Hidden from JSON
	Description string    `json:"description"`
	Tags        []string  `json:"tags"`
	Internal    bool      `json:"internal"`
	UploadedBy  int       `json:"uploaded_by"`
	UploadedAt  time.Time `json:"uploaded_at"`
	Downloaded  int       `json:"download_count"`
}

Attachment represents a file attached to a ticket.

type AttachmentBasicInfo

type AttachmentBasicInfo struct {
	ID       int
	Name     string
	Filename string
}

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

type AttachmentWithTemplateCount struct {
	ID            int
	Name          string
	Filename      string
	TemplateCount int
}

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 AuthHandler

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

func NewAuthHandler

func NewAuthHandler(authService *service.AuthService) *AuthHandler

func (*AuthHandler) ChangePassword

func (h *AuthHandler) ChangePassword(c *gin.Context)

func (*AuthHandler) GetCurrentUser

func (h *AuthHandler) GetCurrentUser(c *gin.Context)

func (*AuthHandler) Login

func (h *AuthHandler) Login(c *gin.Context)

func (*AuthHandler) Logout

func (h *AuthHandler) Logout(c *gin.Context)

func (*AuthHandler) RefreshToken

func (h *AuthHandler) RefreshToken(c *gin.Context)

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 CannedResponseHandlers

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

CannedResponseHandlers manages canned response API endpoints.

func NewCannedResponseHandlers

func NewCannedResponseHandlers() *CannedResponseHandlers

NewCannedResponseHandlers creates a new canned response handlers instance.

func (*CannedResponseHandlers) ApplyResponse

func (h *CannedResponseHandlers) ApplyResponse(c *gin.Context)

ApplyResponse applies a canned response to a ticket.

func (*CannedResponseHandlers) CreateResponse

func (h *CannedResponseHandlers) CreateResponse(c *gin.Context)

CreateResponse creates a new canned response.

func (*CannedResponseHandlers) DeleteResponse

func (h *CannedResponseHandlers) DeleteResponse(c *gin.Context)

DeleteResponse deletes a canned response.

func (*CannedResponseHandlers) ExportResponses

func (h *CannedResponseHandlers) ExportResponses(c *gin.Context)

ExportResponses exports all canned responses as JSON.

func (*CannedResponseHandlers) GetCategories

func (h *CannedResponseHandlers) GetCategories(c *gin.Context)

GetCategories retrieves all canned response categories.

func (*CannedResponseHandlers) GetPopularResponses

func (h *CannedResponseHandlers) GetPopularResponses(c *gin.Context)

GetPopularResponses retrieves the most used responses.

func (*CannedResponseHandlers) GetQuickResponses

func (h *CannedResponseHandlers) GetQuickResponses(c *gin.Context)

GetQuickResponses retrieves responses with shortcuts.

func (*CannedResponseHandlers) GetResponseByID

func (h *CannedResponseHandlers) GetResponseByID(c *gin.Context)

GetResponseByID retrieves a specific canned response.

func (*CannedResponseHandlers) GetResponses

func (h *CannedResponseHandlers) GetResponses(c *gin.Context)

GetResponses retrieves all active canned responses.

func (*CannedResponseHandlers) GetResponsesByCategory

func (h *CannedResponseHandlers) GetResponsesByCategory(c *gin.Context)

GetResponsesByCategory retrieves responses by category.

func (*CannedResponseHandlers) GetResponsesForUser

func (h *CannedResponseHandlers) GetResponsesForUser(c *gin.Context)

GetResponsesForUser retrieves responses accessible to the current user.

func (*CannedResponseHandlers) ImportResponses

func (h *CannedResponseHandlers) ImportResponses(c *gin.Context)

ImportResponses imports canned responses from JSON.

func (*CannedResponseHandlers) SearchResponses

func (h *CannedResponseHandlers) SearchResponses(c *gin.Context)

SearchResponses searches for canned responses.

func (*CannedResponseHandlers) UpdateResponse

func (h *CannedResponseHandlers) UpdateResponse(c *gin.Context)

UpdateResponse updates an existing canned response.

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 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 CoverageResponse

type CoverageResponse struct {
	Languages []LanguageCoverage `json:"languages"`
	Summary   struct {
		TotalKeys       int     `json:"total_keys"`
		AverageCoverage float64 `json:"average_coverage"`
	} `json:"summary"`
}

CoverageResponse represents the coverage statistics response.

type CreateUserRequest

type CreateUserRequest struct {
	Login     string `json:"login" binding:"required"`
	Email     string `json:"email" binding:"required,email"`
	Password  string `json:"password" binding:"required,min=8"`
	FirstName string `json:"first_name"`
	LastName  string `json:"last_name"`
	ValidID   int    `json:"valid_id"`
	Groups    []int  `json:"groups"` // Optional group IDs to assign
}

CreateUserRequest represents the request to create a new user.

type CustomerCompanyInfo

type CustomerCompanyInfo struct {
	CustomerID string
	Name       string
	ValidID    int
	ValidName  string
}

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 EscalationResult

type EscalationResult struct {
	ShouldEscalate  bool     `json:"should_escalate"`
	EscalationLevel string   `json:"escalation_level"`
	NotifyList      []string `json:"notify_list"`
	Level           string   `json:"level"`
}

EscalationResult represents the result of escalation check.

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 GroupInfo

type GroupInfo struct {
	ID        int
	Name      string
	ValidID   int
	ValidName string
}

GroupInfo holds group data for display

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 I18nHandlers

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

I18nHandlers handles internationalization-related requests.

func NewI18nHandlers

func NewI18nHandlers() *I18nHandlers

NewI18nHandlers creates new i18n handlers.

func (*I18nHandlers) ExportTranslations

func (h *I18nHandlers) ExportTranslations(c *gin.Context)

@Router /api/v1/i18n/export/{lang} [get].

func (*I18nHandlers) GetCurrentTranslations

func (h *I18nHandlers) GetCurrentTranslations(c *gin.Context)

@Router /api/v1/i18n/translations [get].

func (*I18nHandlers) GetLanguageStats

func (h *I18nHandlers) GetLanguageStats(c *gin.Context)

@Router /api/v1/i18n/stats [get].

func (*I18nHandlers) GetMissingTranslations

func (h *I18nHandlers) GetMissingTranslations(c *gin.Context)

@Router /api/v1/i18n/missing/{lang} [get].

func (*I18nHandlers) GetSupportedLanguages

func (h *I18nHandlers) GetSupportedLanguages(c *gin.Context)

@Router /api/v1/i18n/languages [get].

func (*I18nHandlers) GetTranslationCoverage

func (h *I18nHandlers) GetTranslationCoverage(c *gin.Context)

@Router /api/v1/i18n/coverage [get].

func (*I18nHandlers) GetTranslations

func (h *I18nHandlers) GetTranslations(c *gin.Context)

@Router /api/v1/i18n/translations/{lang} [get].

func (*I18nHandlers) RegisterRoutes

func (h *I18nHandlers) RegisterRoutes(router *gin.RouterGroup)

RegisterRoutes registers i18n routes.

func (*I18nHandlers) SetLanguage

func (h *I18nHandlers) SetLanguage(c *gin.Context)

@Router /api/v1/i18n/language [post].

func (*I18nHandlers) Translate

func (h *I18nHandlers) Translate(c *gin.Context)

@Router /api/v1/i18n/translate [post].

func (*I18nHandlers) ValidateTranslations

func (h *I18nHandlers) ValidateTranslations(c *gin.Context)

@Router /api/v1/i18n/validate/{lang} [get].

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
	IsPriority       bool       `json:"is_priority"`
	Category         string     `json:"category"`
	Mentions         []string   `json:"mentions"`
	HasMentions      bool       `json:"has_mentions"`
	HasTeamMention   bool       `json:"has_team_mention"`
	Attachments      []int      `json:"attachments"`
	IsEdited         bool       `json:"is_edited"`
	EditedAt         *time.Time `json:"edited_at,omitempty"`
	CreatedAt        time.Time  `json:"created_at"`
	UpdatedAt        time.Time  `json:"updated_at"`
}

InternalNote represents an internal note on a ticket.

type InternalNoteHandlers

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

InternalNoteHandlers manages internal note API endpoints.

func NewInternalNoteHandlers

func NewInternalNoteHandlers() *InternalNoteHandlers

NewInternalNoteHandlers creates a new internal note handlers instance.

func (*InternalNoteHandlers) CreateNote

func (h *InternalNoteHandlers) CreateNote(c *gin.Context)

CreateNote creates a new internal note.

func (*InternalNoteHandlers) CreateNoteFromTemplate

func (h *InternalNoteHandlers) CreateNoteFromTemplate(c *gin.Context)

CreateNoteFromTemplate creates a note from a template.

func (*InternalNoteHandlers) CreateTemplate

func (h *InternalNoteHandlers) CreateTemplate(c *gin.Context)

CreateTemplate creates a new template.

func (*InternalNoteHandlers) DeleteNote

func (h *InternalNoteHandlers) DeleteNote(c *gin.Context)

DeleteNote deletes a note.

func (*InternalNoteHandlers) DeleteTemplate

func (h *InternalNoteHandlers) DeleteTemplate(c *gin.Context)

DeleteTemplate deletes a template.

func (*InternalNoteHandlers) ExportNotes

func (h *InternalNoteHandlers) ExportNotes(c *gin.Context)

ExportNotes exports notes in various formats.

func (*InternalNoteHandlers) GetCategories

func (h *InternalNoteHandlers) GetCategories(c *gin.Context)

GetCategories retrieves all note categories.

func (*InternalNoteHandlers) GetEditHistory

func (h *InternalNoteHandlers) GetEditHistory(c *gin.Context)

GetEditHistory retrieves edit history for a note.

func (*InternalNoteHandlers) GetImportantNotes

func (h *InternalNoteHandlers) GetImportantNotes(c *gin.Context)

GetImportantNotes retrieves important notes for a ticket.

func (*InternalNoteHandlers) GetNoteByID

func (h *InternalNoteHandlers) GetNoteByID(c *gin.Context)

GetNoteByID retrieves a specific note.

func (*InternalNoteHandlers) GetNoteStatistics

func (h *InternalNoteHandlers) GetNoteStatistics(c *gin.Context)

GetNoteStatistics retrieves statistics for notes.

func (*InternalNoteHandlers) GetNotes

func (h *InternalNoteHandlers) GetNotes(c *gin.Context)

GetNotes retrieves all notes for a ticket.

func (*InternalNoteHandlers) GetPinnedNotes

func (h *InternalNoteHandlers) GetPinnedNotes(c *gin.Context)

GetPinnedNotes retrieves pinned notes for a ticket.

func (*InternalNoteHandlers) GetRecentActivity

func (h *InternalNoteHandlers) GetRecentActivity(c *gin.Context)

GetRecentActivity retrieves recent activity.

func (*InternalNoteHandlers) GetTemplates

func (h *InternalNoteHandlers) GetTemplates(c *gin.Context)

GetTemplates retrieves all note templates.

func (*InternalNoteHandlers) MarkImportant

func (h *InternalNoteHandlers) MarkImportant(c *gin.Context)

MarkImportant marks or unmarks a note as important.

func (*InternalNoteHandlers) PinNote

func (h *InternalNoteHandlers) PinNote(c *gin.Context)

PinNote pins or unpins a note.

func (*InternalNoteHandlers) SearchNotes

func (h *InternalNoteHandlers) SearchNotes(c *gin.Context)

SearchNotes searches for notes.

func (*InternalNoteHandlers) UpdateNote

func (h *InternalNoteHandlers) UpdateNote(c *gin.Context)

UpdateNote updates an existing note.

func (*InternalNoteHandlers) UpdateTemplate

func (h *InternalNoteHandlers) UpdateTemplate(c *gin.Context)

UpdateTemplate updates a template.

type LanguageCoverage

type LanguageCoverage struct {
	Code           string  `json:"code"`
	Name           string  `json:"name"`
	TotalKeys      int     `json:"total_keys"`
	TranslatedKeys int     `json:"translated_keys"`
	MissingCount   int     `json:"missing_count"`
	Coverage       float64 `json:"coverage"`
}

LanguageCoverage represents coverage data for a language.

type LanguageInfo

type LanguageInfo struct {
	Code       string `json:"code"`
	Name       string `json:"name"`
	NativeName string `json:"native_name"`
	Active     bool   `json:"active"`
}

LanguageInfo represents information about a language.

type LanguageStats

type LanguageStats struct {
	Code       string  `json:"code"`
	Users      int     `json:"users"`
	Percentage float64 `json:"percentage"`
}

LanguageStats represents language usage statistics.

type LanguageStatsResponse

type LanguageStatsResponse struct {
	TotalUsers      int             `json:"total_users"`
	Languages       []LanguageStats `json:"languages"`
	DefaultLanguage string          `json:"default_language"`
}

LanguageStatsResponse represents language statistics response.

type LanguagesResponse

type LanguagesResponse struct {
	Languages []LanguageInfo `json:"languages"`
	Current   string         `json:"current"`
	Default   string         `json:"default"`
}

LanguagesResponse represents the response for supported languages.

type LookupItem

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

LookupItem represents a simple ID/Name lookup option for templates.

type MergeHistory

type MergeHistory struct {
	Action      string    `json:"action"`       // "merged" or "unmerged"
	Tickets     []int     `json:"tickets"`      // Ticket IDs involved
	Reason      string    `json:"reason"`       // Reason for action
	PerformedBy string    `json:"performed_by"` // User who performed action
	PerformedAt time.Time `json:"performed_at"` // When action was performed
}

MergeHistory represents merge/unmerge history.

type MergeRequest

type MergeRequest struct {
	TicketIDs string `form:"ticket_ids"`
	Reason    string `form:"reason"`
}

MergeRequest represents a ticket merge request.

type MissingKey

type MissingKey struct {
	Key          string `json:"key"`
	EnglishValue string `json:"english_value"`
	Category     string `json:"category"`
}

MissingKey represents a missing translation key.

type MissingKeysResponse

type MissingKeysResponse struct {
	Language    string       `json:"language"`
	MissingKeys []MissingKey `json:"missing_keys"`
	Count       int          `json:"count"`
}

MissingKeysResponse represents missing keys response.

type NoteHistory

type NoteHistory struct {
	ID       int       `json:"id"`
	NoteID   int       `json:"note_id"`
	Content  string    `json:"content"`
	EditedBy int       `json:"edited_by"`
	EditedAt time.Time `json:"edited_at"`
	Version  int       `json:"version"`
}

NoteHistory represents edit history for a note.

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 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.

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 to enable i18n and RBAC support in widgets.

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

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

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

type QueueInfo struct {
	ID   int
	Name string
}

QueueInfo represents basic queue information.

func GetQueueInfo

func GetQueueInfo(queueID int) (*QueueInfo, error)

GetQueueInfo returns basic queue information by ID.

type QueueWithTemplateCount

type QueueWithTemplateCount struct {
	ID            int
	Name          string
	TemplateCount int
}

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 RegEx

type RegEx struct {
	Value        string `yaml:"Value"`
	ErrorMessage string `yaml:"ErrorMessage"`
}

RegEx represents a regex validation pattern (OTRS format).

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 SLA

type SLA struct {
	Status        string    `json:"status"` // within, warning, overdue
	Deadline      time.Time `json:"deadline"`
	PercentUsed   float64   `json:"percent_used"`
	TimeRemaining string    `json:"time_remaining"`
}

SLA represents Service Level Agreement status.

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 SavedSearch

type SavedSearch struct {
	ID        int       `json:"id"`
	UserID    int       `json:"user_id"`
	Name      string    `json:"name"`
	Query     string    `json:"query"`
	Filters   string    `json:"filters"`
	CreatedAt time.Time `json:"created_at"`
	UpdatedAt time.Time `json:"updated_at"`
}

SavedSearch represents a user's saved search.

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 SearchHandlers

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

SearchHandlers handles search-related API endpoints.

func NewSearchHandlers

func NewSearchHandlers() *SearchHandlers

NewSearchHandlers creates new search handlers.

func (*SearchHandlers) AdvancedSearch

func (h *SearchHandlers) AdvancedSearch(c *gin.Context)

AdvancedSearch performs an advanced search with filters.

func (*SearchHandlers) DeleteTicketFromIndex

func (h *SearchHandlers) DeleteTicketFromIndex(c *gin.Context)

DeleteTicketFromIndex removes a ticket from the search index.

func (*SearchHandlers) ExecuteSavedSearch

func (h *SearchHandlers) ExecuteSavedSearch(c *gin.Context)

ExecuteSavedSearch executes a saved search.

func (*SearchHandlers) GetSavedSearch

func (h *SearchHandlers) GetSavedSearch(c *gin.Context)

GetSavedSearch retrieves a specific saved search.

func (*SearchHandlers) GetSavedSearches

func (h *SearchHandlers) GetSavedSearches(c *gin.Context)

GetSavedSearches retrieves saved searches for a user.

func (*SearchHandlers) GetSearchAnalytics

func (h *SearchHandlers) GetSearchAnalytics(c *gin.Context)

GetSearchAnalytics retrieves search analytics.

func (*SearchHandlers) GetSearchHistory

func (h *SearchHandlers) GetSearchHistory(c *gin.Context)

GetSearchHistory retrieves search history for a user.

func (*SearchHandlers) GetSearchSuggestions

func (h *SearchHandlers) GetSearchSuggestions(c *gin.Context)

GetSearchSuggestions provides search suggestions.

func (*SearchHandlers) IndexTicket

func (h *SearchHandlers) IndexTicket(c *gin.Context)

IndexTicket indexes a single ticket.

func (*SearchHandlers) ReindexTickets

func (h *SearchHandlers) ReindexTickets(c *gin.Context)

ReindexTickets triggers reindexing of all tickets.

func (*SearchHandlers) SaveSearch

func (h *SearchHandlers) SaveSearch(c *gin.Context)

SaveSearch saves a search query.

func (*SearchHandlers) SearchTickets

func (h *SearchHandlers) SearchTickets(c *gin.Context)

SearchTickets performs a ticket search.

func (*SearchHandlers) UpdateTicketIndex

func (h *SearchHandlers) UpdateTicketIndex(c *gin.Context)

UpdateTicketIndex updates a ticket in the search index.

type SearchHistory

type SearchHistory struct {
	ID        int       `json:"id"`
	UserID    int       `json:"user_id"`
	Query     string    `json:"query"`
	Name      string    `json:"name,omitempty"`
	Results   int       `json:"results"`
	CreatedAt time.Time `json:"created_at"`
}

SearchHistory represents a user's search history entry.

type SearchResult

type SearchResult struct {
	ID           int               `json:"id"`
	Subject      string            `json:"subject"`
	Body         string            `json:"body"`
	Status       string            `json:"status"`
	Priority     string            `json:"priority"`
	QueueID      int               `json:"queue_id"`
	QueueName    string            `json:"queue_name"`
	AssigneeID   int               `json:"assignee_id"`
	AssigneeName string            `json:"assignee_name"`
	CreatedAt    time.Time         `json:"created_at"`
	UpdatedAt    time.Time         `json:"updated_at"`
	Score        float64           `json:"score"`
	Highlights   map[string]string `json:"highlights,omitempty"`
}

SearchResult represents a search result item.

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 Service

type Service struct {
	ID         int       `json:"id"`
	Name       string    `json:"name"`
	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"`
}

type ServiceWithStats

type ServiceWithStats struct {
	Service
	TicketCount int `json:"ticket_count"`
	SLACount    int `json:"sla_count"`
}

ServiceWithStats includes additional statistics.

type SetLanguageRequest

type SetLanguageRequest struct {
	Language string `json:"language" binding:"required"`
}

SetLanguageRequest represents a request to set language.

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

func GetAllSignatures() ([]Signature, error)

GetAllSignatures returns all valid signatures for dropdowns.

func GetSignature

func GetSignature(id int) (*Signature, error)

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

type SignatureWithStats struct {
	Signature
	QueueCount int `json:"queue_count"`
}

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

type TemplateOption struct {
	ID           int
	Name         string
	TemplateType string
	Selected     bool
}

TemplateOption represents a template option for checkbox selection.

type TemplateTypeOption

type TemplateTypeOption struct {
	Key   string `json:"key"`
	Label string `json:"label"`
}

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

type TemplateWithQueueCount struct {
	ID           int
	Name         string
	TemplateType string
	QueueCount   int
}

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 TestAuthConfig

type TestAuthConfig struct {
	UserID  uint
	Email   string
	Role    string
	IsAdmin bool
}

TestAuthConfig holds configuration for test authentication.

func GetTestAuthConfig

func GetTestAuthConfig() TestAuthConfig

GetTestAuthConfig returns auth configuration from environment variables with defaults. Environment variables:

  • TEST_AUTH_USER_ID: User ID for test token (default: 1)
  • TEST_AUTH_EMAIL: Email for test token (default: root@localhost)
  • TEST_AUTH_ROLE: Role for test token (default: Admin)
  • TEST_AUTH_IS_ADMIN: Whether user is admin (default: true)

type TestConfig

type TestConfig struct {
	UserLogin     string
	UserFirstName string
	UserLastName  string
	UserEmail     string
	UserGroups    []string
	QueueName     string
	GroupName     string
	CompanyName   string
}

GetTestConfig returns test configuration from environment variables with safe defaults.

func GetTestConfig

func GetTestConfig() TestConfig

GetTestConfig retrieves parameterized test configuration.

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 TranslateRequest

type TranslateRequest struct {
	Key      string        `json:"key" binding:"required"`
	Language string        `json:"language"`
	Args     []interface{} `json:"args"`
}

TranslateRequest represents a request to translate a key.

type TranslateResponse

type TranslateResponse struct {
	Key         string `json:"key"`
	Translation string `json:"translation"`
	Language    string `json:"language"`
}

TranslateResponse represents the response for translation.

type TranslationsResponse

type TranslationsResponse struct {
	Language     string                 `json:"language"`
	Translations map[string]interface{} `json:"translations"`
}

TranslationsResponse represents the response for translations.

type UnmergeRequest

type UnmergeRequest struct {
	Reason string `form:"reason"`
}

UnmergeRequest represents a ticket unmerge request.

type UpdateUserRequest

type UpdateUserRequest struct {
	Email     *string `json:"email"`
	FirstName *string `json:"first_name"`
	LastName  *string `json:"last_name"`
	Password  *string `json:"password"`
	ValidID   *int    `json:"valid_id"`
}

UpdateUserRequest represents the request to update a user.

type ValidationResponse

type ValidationResponse struct {
	Language   string   `json:"language"`
	IsValid    bool     `json:"is_valid"`
	IsComplete bool     `json:"is_complete"`
	Coverage   float64  `json:"coverage"`
	Errors     []string `json:"errors"`
	Warnings   []string `json:"warnings"`
}

ValidationResponse represents translation validation response.

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

Directories

Path Synopsis
Package api provides shared API handlers and utilities for article creation.
Package api provides shared API handlers and utilities for article creation.

Jump to

Keyboard shortcuts

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