Source-reviewed hardening changes and regression tests. UNBUILT / UNTESTED: not a deployable release. Go formatting, compilation, automated regression tests, full frontend validation and staging acceptance remain required. See docs/hardening/VALIDATION.md. Main remains the original clean snapshot; no upstream Git history imported.
528 lines
23 KiB
Go
528 lines
23 KiB
Go
// Modified in the independent hardening fork; see docs/hardening.
|
|
|
|
package bootstrap
|
|
|
|
import (
|
|
"time"
|
|
|
|
"agent-desk/internal/handlers/api"
|
|
"agent-desk/internal/handlers/dashboard"
|
|
"agent-desk/internal/handlers/third"
|
|
"agent-desk/internal/middleware"
|
|
"agent-desk/internal/pkg/config"
|
|
"agent-desk/internal/pkg/ratelimit"
|
|
|
|
"github.com/gin-gonic/gin"
|
|
)
|
|
|
|
// publicRateLimits holds one limiter per abuse-prone unauthenticated endpoint.
|
|
// They are built once per server rather than per request, and the middleware keys
|
|
// them by client address.
|
|
//
|
|
// Channel webhooks under /api/third, the websocket routes and /api/webhooks are
|
|
// deliberately absent. A platform that receives a 429 from its webhook stops
|
|
// retrying and eventually disables the delivery, which would take a whole channel
|
|
// offline; those endpoints authenticate by signature instead. The dashboard is
|
|
// absent too - it is already behind AuthMiddleware, and staff sharing one office
|
|
// address would throttle each other.
|
|
type publicRateLimits struct {
|
|
login *ratelimit.Limiter
|
|
supportRegister *ratelimit.Limiter
|
|
sessionExchange *ratelimit.Limiter
|
|
upload *ratelimit.Limiter
|
|
docFeedback *ratelimit.Limiter
|
|
emailRequest *ratelimit.Limiter
|
|
}
|
|
|
|
// Limits are sized for a human driving a browser, not for a machine. They are
|
|
// deliberately generous: the point is to make flooding expensive, not to police
|
|
// legitimate use. The session exchange budget in particular has to absorb a whole
|
|
// support office loading the widget from behind one NAT address.
|
|
const (
|
|
limitLogin = 20
|
|
limitSupportRegister = 10
|
|
limitSessionExchange = 120
|
|
limitUpload = 30
|
|
limitDocFeedback = 20
|
|
// An integration filing requests on a visitor's behalf is machine traffic, but it
|
|
// should not be able to queue a support office's worth of work in one window.
|
|
limitEmailRequest = 30
|
|
)
|
|
|
|
func newPublicRateLimits(cfg config.RateLimitConfig) publicRateLimits {
|
|
if !cfg.IsEnabled() {
|
|
// Every field stays nil and a nil limiter allows everything, so "disabled"
|
|
// needs no branch at any call site.
|
|
return publicRateLimits{}
|
|
}
|
|
window := time.Duration(cfg.WindowSecondsOrDefault()) * time.Second
|
|
return publicRateLimits{
|
|
login: ratelimit.New(limitLogin, window),
|
|
supportRegister: ratelimit.New(limitSupportRegister, window),
|
|
sessionExchange: ratelimit.New(limitSessionExchange, window),
|
|
upload: ratelimit.New(limitUpload, window),
|
|
docFeedback: ratelimit.New(limitDocFeedback, window),
|
|
emailRequest: ratelimit.New(limitEmailRequest, window),
|
|
}
|
|
}
|
|
|
|
func registerApiAuthRoutes(group *gin.RouterGroup, limits publicRateLimits) {
|
|
group.POST("/login", middleware.RateLimit(limits.login), api.Login)
|
|
group.POST("/logout", api.Logout)
|
|
group.GET("/profile", api.Profile)
|
|
group.POST("/profile/update", api.UpdateProfile)
|
|
group.POST("/profile/avatar/upload", api.UploadProfileAvatar)
|
|
group.GET("/oidc_callback", api.OIDCCallback)
|
|
group.GET("/callback/custom", api.OIDCCallback)
|
|
group.POST("/oidc_exchange", api.OIDCExchange)
|
|
group.GET("/oidc_login", api.OIDCLogin)
|
|
}
|
|
|
|
func registerApiChannelRoutes(group *gin.RouterGroup) {
|
|
group.Any("/config", api.ChannelAnyConfig)
|
|
}
|
|
|
|
func registerApiWebhookRoutes(group *gin.RouterGroup) {
|
|
group.POST("/org-sync", api.OrgSyncWebhook)
|
|
group.POST("/dos-org-sync", api.DOSOrgSyncWebhook)
|
|
}
|
|
|
|
func registerApiCustomerRoutes(group *gin.RouterGroup, limits publicRateLimits) {
|
|
group.POST("/session_exchange", middleware.RateLimit(limits.sessionExchange), api.CustomerPostSession_exchange)
|
|
group.POST("/session_refresh", middleware.RateLimit(limits.sessionExchange), api.CustomerPostSession_refresh)
|
|
}
|
|
|
|
func registerApiConversationRoutes(group *gin.RouterGroup) {
|
|
group.GET("/:id", api.ConversationGetBy)
|
|
group.Any("/list", api.ConversationAnyList)
|
|
group.POST("/close", api.ConversationPostClose)
|
|
group.POST("/create", api.ConversationPostCreate)
|
|
group.POST("/create_or_match", api.ConversationPostCreate_or_match)
|
|
group.POST("/satisfaction", api.ConversationPostSatisfaction)
|
|
}
|
|
|
|
func registerApiMessageRoutes(group *gin.RouterGroup, limits publicRateLimits) {
|
|
group.Any("/list", api.MessageAnyList)
|
|
group.POST("/read", api.MessagePostRead)
|
|
group.POST("/send", api.MessagePostSend)
|
|
// One shared budget for both upload routes: what matters is how many bytes an
|
|
// unauthenticated caller can push at the storage layer, not which of the two
|
|
// endpoints they used.
|
|
uploadLimit := middleware.RateLimit(limits.upload)
|
|
group.POST("/upload_attachment", uploadLimit, api.MessagePostUpload_attachment)
|
|
group.POST("/upload_image", uploadLimit, api.MessagePostUpload_image)
|
|
}
|
|
|
|
func registerApiSupportRoutes(group *gin.RouterGroup, limits publicRateLimits) {
|
|
group.GET("/config", api.SupportConfigGetConfig)
|
|
group.POST("/auth/register", middleware.RateLimit(limits.supportRegister), api.SupportAuthPostRegister)
|
|
group.GET("/me", api.SupportGetMe)
|
|
group.Any("/doc-page/list", api.DocPageAnyList)
|
|
group.GET("/doc-page/navigation", api.DocPageGetNavigation)
|
|
group.GET("/doc-page/:id", api.DocPageGetBy)
|
|
group.POST("/doc-page/feedback", middleware.RateLimit(limits.docFeedback), api.DocPagePostFeedback)
|
|
group.Any("/community/categories/list", api.CategoryAnyList)
|
|
group.Any("/community/posts/list", api.PostAnyList)
|
|
group.GET("/community/posts/:id", api.PostGetBy)
|
|
group.POST("/community/posts/create", api.PostPostCreate)
|
|
group.POST("/community/posts/update", api.PostPostUpdate)
|
|
group.POST("/community/posts/accept_comment", api.PostPostAcceptComment)
|
|
group.Any("/community/comments/list", api.CommentAnyList)
|
|
group.POST("/community/comments/create", api.CommentPostCreate)
|
|
group.POST("/community/comments/update", api.CommentPostUpdate)
|
|
group.POST("/community/comments/delete", api.CommentPostDelete)
|
|
group.POST("/community/comments/report", api.CommentPostReport)
|
|
group.POST("/community/reactions/toggle", api.ReactionPostToggle)
|
|
}
|
|
|
|
func registerDashboardSupportConfigRoutes(group *gin.RouterGroup) {
|
|
group.GET("", dashboard.SupportConfigGetConfig)
|
|
group.POST("/save", dashboard.SupportConfigPostSave)
|
|
}
|
|
|
|
func registerDashboardBrandingRoutes(group *gin.RouterGroup) {
|
|
group.GET("", dashboard.BrandingGetConfig)
|
|
group.POST("/save", dashboard.BrandingPostSave)
|
|
}
|
|
|
|
func registerDashboardDashboardRoutes(group *gin.RouterGroup) {
|
|
group.GET("/overview", dashboard.DashboardGetOverview)
|
|
}
|
|
|
|
func registerDashboardSetupRoutes(group *gin.RouterGroup) {
|
|
group.GET("/readiness", dashboard.SetupGetReadiness)
|
|
group.POST("/simulate_route", dashboard.SetupPostSimulate_route)
|
|
group.POST("/quick_fix", dashboard.SetupPostQuick_fix)
|
|
}
|
|
|
|
func registerDashboardUserRoutes(group *gin.RouterGroup) {
|
|
group.GET("/:id", dashboard.UserGetBy)
|
|
group.POST("/assign_role", dashboard.UserPostAssign_role)
|
|
group.POST("/change_password", dashboard.UserPostChange_password)
|
|
group.POST("/create", dashboard.UserPostCreate)
|
|
group.POST("/delete", dashboard.UserPostDelete)
|
|
group.Any("/list", dashboard.UserAnyList)
|
|
group.Any("/list_all", dashboard.UserAnyList_all)
|
|
group.POST("/reset_password", dashboard.UserPostReset_password)
|
|
group.POST("/update", dashboard.UserPostUpdate)
|
|
group.POST("/update_status", dashboard.UserPostUpdate_status)
|
|
}
|
|
|
|
func registerDashboardOrganizationRoutes(group *gin.RouterGroup) {
|
|
group.GET("/my_list", dashboard.OrganizationUserList)
|
|
group.POST("/switch", dashboard.OrganizationSwitch)
|
|
}
|
|
|
|
func registerDashboardCompanyRoutes(group *gin.RouterGroup) {
|
|
group.GET("/:id", dashboard.CompanyGetBy)
|
|
group.POST("/create", dashboard.CompanyPostCreate)
|
|
group.POST("/delete", dashboard.CompanyPostDelete)
|
|
group.Any("/list", dashboard.CompanyAnyList)
|
|
group.POST("/update", dashboard.CompanyPostUpdate)
|
|
group.POST("/update_status", dashboard.CompanyPostUpdate_status)
|
|
}
|
|
|
|
func registerDashboardCustomerRoutes(group *gin.RouterGroup) {
|
|
group.GET("/:id", dashboard.CustomerGetBy)
|
|
group.POST("/create", dashboard.CustomerPostCreate)
|
|
group.POST("/delete", dashboard.CustomerPostDelete)
|
|
group.POST("/list", dashboard.CustomerPostList)
|
|
group.POST("/save_profile", dashboard.CustomerPostSave_profile)
|
|
group.POST("/update", dashboard.CustomerPostUpdate)
|
|
group.POST("/update_status", dashboard.CustomerPostUpdate_status)
|
|
}
|
|
|
|
func registerDashboardCustomerContactRoutes(group *gin.RouterGroup) {
|
|
group.POST("/create", dashboard.CustomerContactPostCreate)
|
|
group.POST("/delete", dashboard.CustomerContactPostDelete)
|
|
group.Any("/list", dashboard.CustomerContactAnyList)
|
|
group.POST("/update", dashboard.CustomerContactPostUpdate)
|
|
}
|
|
|
|
func registerDashboardRoleRoutes(group *gin.RouterGroup) {
|
|
group.GET("/:id", dashboard.RoleGetBy)
|
|
group.POST("/assign_permission", dashboard.RolePostAssign_permission)
|
|
group.POST("/create", dashboard.RolePostCreate)
|
|
group.POST("/delete", dashboard.RolePostDelete)
|
|
group.Any("/list", dashboard.RoleAnyList)
|
|
group.GET("/list_all", dashboard.RoleGetList_all)
|
|
group.POST("/update", dashboard.RolePostUpdate)
|
|
group.POST("/update_sort", dashboard.RolePostUpdate_sort)
|
|
group.POST("/update_status", dashboard.RolePostUpdate_status)
|
|
}
|
|
|
|
func registerDashboardPermissionRoutes(group *gin.RouterGroup) {
|
|
group.GET("/:id", dashboard.PermissionGetBy)
|
|
group.Any("/list", dashboard.PermissionAnyList)
|
|
group.POST("/sync", dashboard.PermissionPostSync)
|
|
}
|
|
|
|
func registerDashboardSessionRoutes(group *gin.RouterGroup) {
|
|
group.Any("/list", dashboard.SessionAnyList)
|
|
group.POST("/revoke", dashboard.SessionPostRevoke)
|
|
group.POST("/revoke/by/user", dashboard.SessionPostRevokeByUser)
|
|
}
|
|
|
|
func registerDashboardTagRoutes(group *gin.RouterGroup) {
|
|
group.GET("/:id", dashboard.TagGetBy)
|
|
group.POST("/create", dashboard.TagPostCreate)
|
|
group.POST("/delete", dashboard.TagPostDelete)
|
|
group.Any("/list", dashboard.TagAnyList)
|
|
group.GET("/list_all", dashboard.TagGetList_all)
|
|
group.POST("/update", dashboard.TagPostUpdate)
|
|
group.POST("/update_sort", dashboard.TagPostUpdate_sort)
|
|
group.POST("/update_status", dashboard.TagPostUpdate_status)
|
|
}
|
|
|
|
func registerDashboardConversationRoutes(group *gin.RouterGroup) {
|
|
group.GET("/:id", dashboard.ConversationGetBy)
|
|
group.POST("/add_tag", dashboard.ConversationPostAdd_tag)
|
|
group.POST("/assign", dashboard.ConversationPostAssign)
|
|
group.POST("/close", dashboard.ConversationPostClose)
|
|
group.Any("/conversations", dashboard.ConversationAnyConversations)
|
|
group.POST("/dispatch", dashboard.ConversationPostDispatch)
|
|
group.POST("/link_customer", dashboard.ConversationPostLink_customer)
|
|
group.Any("/list", dashboard.ConversationAnyList)
|
|
group.Any("/message_list", dashboard.ConversationAnyMessage_list)
|
|
group.POST("/read", dashboard.ConversationPostRead)
|
|
group.POST("/recall_message", dashboard.ConversationPostRecall_message)
|
|
group.POST("/remove_tag", dashboard.ConversationPostRemove_tag)
|
|
group.POST("/send_message", dashboard.ConversationPostSend_message)
|
|
group.POST("/suggest_reply", dashboard.ConversationPostSuggest_reply)
|
|
group.POST("/summarize", dashboard.ConversationPostSummarize)
|
|
group.POST("/transfer", dashboard.ConversationPostTransfer)
|
|
group.POST("/upload_attachment", dashboard.ConversationPostUpload_attachment)
|
|
group.POST("/upload_image", dashboard.ConversationPostUpload_image)
|
|
}
|
|
|
|
func registerDashboardTicketRoutes(group *gin.RouterGroup) {
|
|
group.GET("/:id", dashboard.TicketGetBy)
|
|
group.POST("/assign", dashboard.TicketPostAssign)
|
|
group.POST("/change_status", dashboard.TicketPostChange_status)
|
|
group.POST("/create", dashboard.TicketPostCreate)
|
|
group.POST("/create_from_conversation", dashboard.TicketPostCreate_from_conversation)
|
|
group.POST("/delete_view", dashboard.TicketPostDelete_view)
|
|
group.POST("/link_customer", dashboard.TicketPostLink_customer)
|
|
group.Any("/list", dashboard.TicketAnyList)
|
|
group.POST("/progress/create", dashboard.TicketPostProgressCreate)
|
|
group.Any("/progress/list", dashboard.TicketAnyProgressList)
|
|
group.POST("/save_view", dashboard.TicketPostSave_view)
|
|
group.Any("/summary", dashboard.TicketAnySummary)
|
|
group.POST("/update", dashboard.TicketPostUpdate)
|
|
group.Any("/view_list", dashboard.TicketAnyView_list)
|
|
}
|
|
|
|
func registerDashboardNotificationRoutes(group *gin.RouterGroup) {
|
|
group.Any("/list", dashboard.NotificationAnyList)
|
|
group.POST("/mark_all_read", dashboard.NotificationPostMark_all_read)
|
|
group.POST("/mark_read", dashboard.NotificationPostMark_read)
|
|
group.GET("/unread_count", dashboard.NotificationGetUnread_count)
|
|
}
|
|
|
|
func registerDashboardQuickReplyRoutes(group *gin.RouterGroup) {
|
|
group.GET("/:id", dashboard.QuickReplyGetBy)
|
|
group.POST("/create", dashboard.QuickReplyPostCreate)
|
|
group.POST("/delete", dashboard.QuickReplyPostDelete)
|
|
group.Any("/list", dashboard.QuickReplyAnyList)
|
|
group.GET("/list_all", dashboard.QuickReplyGetList_all)
|
|
group.POST("/update", dashboard.QuickReplyPostUpdate)
|
|
}
|
|
|
|
func registerDashboardChannelRoutes(group *gin.RouterGroup) {
|
|
group.GET("/:id", dashboard.ChannelGetBy)
|
|
group.POST("/create", dashboard.ChannelPostCreate)
|
|
group.POST("/delete", dashboard.ChannelPostDelete)
|
|
group.Any("/list", dashboard.ChannelAnyList)
|
|
group.POST("/reset_user_token_secret", dashboard.ChannelPostReset_user_token_secret)
|
|
group.POST("/rollback_ai_agent_rollout", dashboard.ChannelPostRollback_ai_agent_rollout)
|
|
group.POST("/update", dashboard.ChannelPostUpdate)
|
|
group.POST("/update_status", dashboard.ChannelPostUpdate_status)
|
|
// Verifying a bound mail server is a configuration action, so it sits under
|
|
// channel.update rather than inventing a permission nobody can be granted
|
|
// without a migration.
|
|
group.POST("/test_email", dashboard.ChannelPostTest_email)
|
|
}
|
|
|
|
func registerDashboardAgentRoutes(group *gin.RouterGroup) {
|
|
group.GET("/:id", dashboard.AgentGetBy)
|
|
group.POST("/create", dashboard.AgentPostCreate)
|
|
group.POST("/delete", dashboard.AgentPostDelete)
|
|
group.Any("/list", dashboard.AgentAnyList)
|
|
group.GET("/list_all", dashboard.AgentGetList_all)
|
|
group.POST("/update", dashboard.AgentPostUpdate)
|
|
}
|
|
|
|
func registerDashboardAgentTeamRoutes(group *gin.RouterGroup) {
|
|
group.GET("/:id", dashboard.AgentTeamGetBy)
|
|
group.POST("/create", dashboard.AgentTeamPostCreate)
|
|
group.POST("/delete", dashboard.AgentTeamPostDelete)
|
|
group.Any("/list", dashboard.AgentTeamAnyList)
|
|
group.GET("/list_all", dashboard.AgentTeamGetList_all)
|
|
group.POST("/update", dashboard.AgentTeamPostUpdate)
|
|
}
|
|
|
|
func registerDashboardAgentTeamScheduleRoutes(group *gin.RouterGroup) {
|
|
group.GET("/:id", dashboard.AgentTeamScheduleGetBy)
|
|
group.POST("/batch_generate", dashboard.AgentTeamSchedulePostBatch_generate)
|
|
group.POST("/batch_preview", dashboard.AgentTeamSchedulePostBatch_preview)
|
|
group.Any("/calendar", dashboard.AgentTeamScheduleAnyCalendar)
|
|
group.POST("/create", dashboard.AgentTeamSchedulePostCreate)
|
|
group.POST("/delete", dashboard.AgentTeamSchedulePostDelete)
|
|
group.Any("/list", dashboard.AgentTeamScheduleAnyList)
|
|
group.POST("/update", dashboard.AgentTeamSchedulePostUpdate)
|
|
}
|
|
|
|
func registerDashboardAIAgentRoutes(group *gin.RouterGroup) {
|
|
group.POST("/publish", dashboard.AIAgentPostPublish)
|
|
group.POST("/rollback", dashboard.AIAgentPostRollback)
|
|
group.POST("/rollback_rollout", dashboard.AIAgentPostRollback_rollout)
|
|
group.Any("/:id/revision/list", dashboard.AIAgentAnyRevisionList)
|
|
group.GET("/:id", dashboard.AIAgentGetBy)
|
|
group.POST("/create", dashboard.AIAgentPostCreate)
|
|
group.POST("/delete", dashboard.AIAgentPostDelete)
|
|
group.Any("/list", dashboard.AIAgentAnyList)
|
|
group.GET("/list_all", dashboard.AIAgentGetList_all)
|
|
group.POST("/update", dashboard.AIAgentPostUpdate)
|
|
group.POST("/update_sort", dashboard.AIAgentPostUpdate_sort)
|
|
group.POST("/update_status", dashboard.AIAgentPostUpdate_status)
|
|
}
|
|
|
|
func registerDashboardAIWorkflowRoutes(group *gin.RouterGroup) {
|
|
group.POST("/create", dashboard.AIWorkflowPostCreate)
|
|
group.POST("/update", dashboard.AIWorkflowPostUpdate)
|
|
group.POST("/delete", dashboard.AIWorkflowPostDelete)
|
|
group.POST("/restore-version", dashboard.AIWorkflowPostRestoreVersion)
|
|
group.Any("/list", dashboard.AIWorkflowAnyList)
|
|
group.GET("/node-spec/list", dashboard.AIWorkflowGetNodeSpecList)
|
|
group.GET("/default-definition", dashboard.AIWorkflowGetDefaultDefinition)
|
|
group.GET("/template/list", dashboard.AIWorkflowGetTemplateList)
|
|
group.POST("/validate", dashboard.AIWorkflowPostValidate)
|
|
group.POST("/publish", dashboard.AIWorkflowPostPublish)
|
|
group.Any("/run/list", dashboard.AIWorkflowAnyRunList)
|
|
group.GET("/run/:id", dashboard.AIWorkflowGetRunBy)
|
|
group.Any("/version/list", dashboard.AIWorkflowAnyVersionList)
|
|
group.GET("/version/:id", dashboard.AIWorkflowGetVersionBy)
|
|
group.GET("/:id/usage", dashboard.AIWorkflowGetUsage)
|
|
group.GET("/:id", dashboard.AIWorkflowGetBy)
|
|
}
|
|
|
|
func registerDashboardAgentRunRoutes(group *gin.RouterGroup) {
|
|
group.Any("/metrics", dashboard.AgentRunAnyMetrics)
|
|
group.POST("/evaluate", dashboard.AgentRunPostEvaluate)
|
|
group.Any("/list", dashboard.AgentRunAnyList)
|
|
group.POST("/quality_feedback", dashboard.AgentRunPostSave_quality_feedback)
|
|
group.GET("/:id", dashboard.AgentRunGetBy)
|
|
}
|
|
|
|
func registerDashboardAIConfigRoutes(group *gin.RouterGroup) {
|
|
group.GET("/:id", dashboard.AIConfigGetBy)
|
|
group.POST("/create", dashboard.AIConfigPostCreate)
|
|
group.POST("/delete", dashboard.AIConfigPostDelete)
|
|
group.Any("/list", dashboard.AIConfigAnyList)
|
|
group.Any("/list_all", dashboard.AIConfigAnyList_all)
|
|
group.POST("/update", dashboard.AIConfigPostUpdate)
|
|
group.POST("/update_sort", dashboard.AIConfigPostUpdateSort)
|
|
group.POST("/update_status", dashboard.AIConfigPostUpdate_status)
|
|
}
|
|
|
|
func registerDashboardAssetRoutes(group *gin.RouterGroup) {
|
|
group.GET("/:id", dashboard.AssetGetBy)
|
|
group.POST("/create", dashboard.AssetPostCreate)
|
|
group.POST("/delete", dashboard.AssetPostDelete)
|
|
group.Any("/list", dashboard.AssetAnyList)
|
|
}
|
|
|
|
func registerDashboardKnowledgeBaseRoutes(group *gin.RouterGroup) {
|
|
group.GET("/:id", dashboard.KnowledgeBaseGetBy)
|
|
group.POST("/create", dashboard.KnowledgeBasePostCreate)
|
|
group.POST("/delete", dashboard.KnowledgeBasePostDelete)
|
|
group.Any("/list", dashboard.KnowledgeBaseAnyList)
|
|
group.Any("/list_all", dashboard.KnowledgeBaseAnyList_all)
|
|
group.POST("/rebuild_index", dashboard.KnowledgeBasePostRebuild_index)
|
|
group.POST("/update", dashboard.KnowledgeBasePostUpdate)
|
|
group.POST("/update_sort", dashboard.KnowledgeBasePostUpdate_sort)
|
|
}
|
|
|
|
func registerDashboardKnowledgeDirectoryRoutes(group *gin.RouterGroup) {
|
|
group.GET("/list_all", dashboard.KnowledgeDirectoryGetList_all)
|
|
group.POST("/create", dashboard.KnowledgeDirectoryPostCreate)
|
|
group.POST("/delete", dashboard.KnowledgeDirectoryPostDelete)
|
|
group.POST("/update", dashboard.KnowledgeDirectoryPostUpdate)
|
|
group.POST("/update_sort", dashboard.KnowledgeDirectoryPostUpdate_sort)
|
|
}
|
|
|
|
func registerDashboardKnowledgeDocumentRoutes(group *gin.RouterGroup) {
|
|
group.GET("/:id", dashboard.KnowledgeDocumentGetBy)
|
|
group.POST("/batch_delete", dashboard.KnowledgeDocumentPostBatch_delete)
|
|
group.POST("/batch_move", dashboard.KnowledgeDocumentPostBatch_move)
|
|
group.POST("/create", dashboard.KnowledgeDocumentPostCreate)
|
|
group.POST("/delete", dashboard.KnowledgeDocumentPostDelete)
|
|
group.Any("/list", dashboard.KnowledgeDocumentAnyList)
|
|
group.POST("/update", dashboard.KnowledgeDocumentPostUpdate)
|
|
}
|
|
|
|
func registerDashboardKnowledgeFAQRoutes(group *gin.RouterGroup) {
|
|
group.GET("/import_template", dashboard.KnowledgeFAQGetImport_template)
|
|
group.GET("/export", dashboard.KnowledgeFAQGetExport)
|
|
group.GET("/:id", dashboard.KnowledgeFAQGetBy)
|
|
group.POST("/batch_delete", dashboard.KnowledgeFAQPostBatch_delete)
|
|
group.POST("/batch_move", dashboard.KnowledgeFAQPostBatch_move)
|
|
group.POST("/create", dashboard.KnowledgeFAQPostCreate)
|
|
group.POST("/delete", dashboard.KnowledgeFAQPostDelete)
|
|
group.POST("/import", dashboard.KnowledgeFAQPostImport)
|
|
group.Any("/list", dashboard.KnowledgeFAQAnyList)
|
|
group.POST("/update", dashboard.KnowledgeFAQPostUpdate)
|
|
}
|
|
|
|
func registerDashboardKnowledgeRetrieveRoutes(group *gin.RouterGroup) {
|
|
group.POST("/build", dashboard.KnowledgeRetrievePostBuild)
|
|
group.POST("/debug/answer", dashboard.KnowledgeRetrievePostDebugAnswer)
|
|
group.POST("/debug/search", dashboard.KnowledgeRetrievePostDebugSearch)
|
|
}
|
|
|
|
func registerDashboardKnowledgeRetrieveLogRoutes(group *gin.RouterGroup) {
|
|
group.GET("/:id", dashboard.KnowledgeRetrieveLogGetBy)
|
|
group.Any("/list", dashboard.KnowledgeRetrieveLogAnyList)
|
|
}
|
|
|
|
func registerDashboardDocPageRoutes(group *gin.RouterGroup) {
|
|
group.GET("/:id", dashboard.DocPageGetBy)
|
|
group.POST("/create", dashboard.DocPagePostCreate)
|
|
group.POST("/delete", dashboard.DocPagePostDelete)
|
|
group.Any("/list", dashboard.DocPageAnyList)
|
|
group.GET("/list_all", dashboard.DocPageGetList_all)
|
|
group.POST("/update", dashboard.DocPagePostUpdate)
|
|
group.POST("/update_settings", dashboard.DocPagePostUpdate_settings)
|
|
group.POST("/update_sort", dashboard.DocPagePostUpdate_sort)
|
|
group.POST("/change_status", dashboard.DocPagePostChange_status)
|
|
}
|
|
|
|
func registerDashboardCommunityCategoryRoutes(group *gin.RouterGroup) {
|
|
group.POST("/create", dashboard.CategoryPostCreate)
|
|
group.POST("/delete", dashboard.CategoryPostDelete)
|
|
group.Any("/list", dashboard.CategoryAnyList)
|
|
group.GET("/list_all", dashboard.CategoryGetList_all)
|
|
group.POST("/update", dashboard.CategoryPostUpdate)
|
|
group.POST("/update_sort", dashboard.CategoryPostUpdateSort)
|
|
}
|
|
|
|
func registerDashboardCommunityPostRoutes(group *gin.RouterGroup) {
|
|
group.GET("/:id", dashboard.PostGetBy)
|
|
group.POST("/accept_comment", dashboard.PostPostAcceptComment)
|
|
group.POST("/comment/create", dashboard.CommentPostCreate)
|
|
group.POST("/comment/moderate", dashboard.CommentPostModerate)
|
|
group.Any("/list", dashboard.PostAnyList)
|
|
group.POST("/moderate", dashboard.PostPostModerate)
|
|
}
|
|
|
|
func registerDashboardSkillDefinitionRoutes(group *gin.RouterGroup) {
|
|
group.GET("/:id", dashboard.SkillDefinitionGetBy)
|
|
group.POST("/create", dashboard.SkillDefinitionPostCreate)
|
|
group.POST("/debug_resume", dashboard.SkillDefinitionPostDebug_resume)
|
|
group.POST("/debug_run", dashboard.SkillDefinitionPostDebug_run)
|
|
group.POST("/delete", dashboard.SkillDefinitionPostDelete)
|
|
group.Any("/list", dashboard.SkillDefinitionAnyList)
|
|
group.GET("/list_all", dashboard.SkillDefinitionGetList_all)
|
|
group.POST("/restore", dashboard.SkillDefinitionPostRestore)
|
|
group.POST("/update", dashboard.SkillDefinitionPostUpdate)
|
|
group.POST("/update_status", dashboard.SkillDefinitionPostUpdate_status)
|
|
}
|
|
|
|
func registerDashboardMCPRoutes(group *gin.RouterGroup) {
|
|
group.POST("/call_tool", dashboard.MCPPostCall_tool)
|
|
group.Any("/catalog", dashboard.MCPAnyCatalog)
|
|
group.Any("/list_servers", dashboard.MCPAnyList_servers)
|
|
group.POST("/list_tools", dashboard.MCPPostList_tools)
|
|
group.POST("/test_connection", dashboard.MCPPostTest_connection)
|
|
}
|
|
|
|
func registerThirdTelegramRoutes(group *gin.RouterGroup) {
|
|
group.POST("/webhook", third.TelegramPostWebhook)
|
|
group.POST("/webhook/:channel_id", third.TelegramPostWebhook)
|
|
}
|
|
|
|
func registerThirdZaloRoutes(group *gin.RouterGroup) {
|
|
group.POST("/webhook", third.ZaloPostWebhook)
|
|
group.POST("/webhook/:channel_id", third.ZaloPostWebhook)
|
|
}
|
|
|
|
func registerThirdSlackRoutes(group *gin.RouterGroup) {
|
|
group.POST("/webhook", third.SlackPostWebhook)
|
|
group.POST("/webhook/:channel_id", third.SlackPostWebhook)
|
|
}
|
|
|
|
func registerThirdDiscordRoutes(group *gin.RouterGroup) {
|
|
group.POST("/webhook", third.DiscordPostWebhook)
|
|
group.POST("/webhook/:channel_id", third.DiscordPostWebhook)
|
|
}
|
|
|
|
func registerThirdEmailRoutes(group *gin.RouterGroup, limits publicRateLimits) {
|
|
group.POST("/webhook", third.EmailPostWebhook)
|
|
group.POST("/webhook/:channel_id", third.EmailPostWebhook)
|
|
// Programmatic intake, rate limited per caller rather than left open: unlike a
|
|
// mail provider webhook this endpoint is reachable by anyone who learns the URL,
|
|
// and each call can create a conversation.
|
|
group.POST("/request", middleware.RateLimit(limits.emailRequest), third.EmailPostRequest)
|
|
group.POST("/request/:channel_id", middleware.RateLimit(limits.emailRequest), third.EmailPostRequest)
|
|
}
|