mirror of
https://github.com/StarFleetCPTN/GoMFT.git
synced 2026-09-08 15:41:20 +02:00
268 lines
8.6 KiB
Go
268 lines
8.6 KiB
Go
package handlers
|
|
|
|
import (
|
|
"fmt"
|
|
"math"
|
|
"net/http"
|
|
"strconv"
|
|
"net/url"
|
|
|
|
"github.com/gin-gonic/gin"
|
|
"github.com/starfleetcptn/gomft/components"
|
|
"github.com/starfleetcptn/gomft/internal/db"
|
|
)
|
|
|
|
// HandleHistory handles the GET /history route
|
|
func (h *Handlers) HandleHistory(c *gin.Context) {
|
|
userID := c.GetUint("userID")
|
|
|
|
// Get pagination parameters
|
|
page, err := strconv.Atoi(c.DefaultQuery("page", "1"))
|
|
if err != nil || page < 1 {
|
|
page = 1
|
|
}
|
|
|
|
pageSize, err := strconv.Atoi(c.DefaultQuery("pageSize", "10"))
|
|
if err != nil {
|
|
pageSize = 10
|
|
}
|
|
// Limit page size options
|
|
if pageSize != 10 && pageSize != 25 && pageSize != 50 && pageSize != 100 {
|
|
pageSize = 10
|
|
}
|
|
|
|
// Get search term
|
|
searchTerm := c.Query("search")
|
|
|
|
// Build the query
|
|
query := h.DB.Model(&db.JobHistory{}).
|
|
Joins("JOIN jobs ON jobs.id = job_histories.job_id").
|
|
Joins("JOIN transfer_configs ON transfer_configs.id = jobs.config_id").
|
|
Where("jobs.created_by = ?", userID)
|
|
|
|
// Apply search if provided
|
|
if searchTerm != "" {
|
|
query = query.Where("transfer_configs.name LIKE ? OR job_histories.status LIKE ?",
|
|
"%"+searchTerm+"%", "%"+searchTerm+"%")
|
|
}
|
|
|
|
// Count total matching records for pagination
|
|
var total int64
|
|
query.Count(&total)
|
|
|
|
// Calculate total pages
|
|
totalPages := int(math.Ceil(float64(total) / float64(pageSize)))
|
|
if totalPages == 0 {
|
|
totalPages = 1
|
|
}
|
|
|
|
// Ensure page is within bounds
|
|
if page > totalPages {
|
|
page = totalPages
|
|
}
|
|
|
|
// Get paginated results
|
|
var history []db.JobHistory
|
|
offset := (page - 1) * pageSize
|
|
|
|
query.Offset(offset).
|
|
Limit(pageSize).
|
|
Preload("Job.Config").
|
|
Order("start_time desc").
|
|
Find(&history)
|
|
|
|
// If we got no results and we're not on page 1, redirect to page 1
|
|
// Only do this for non-HTMX requests to avoid navigation issues
|
|
isHtmxRequest := c.GetHeader("HX-Request") == "true"
|
|
if len(history) == 0 && page > 1 && total > 0 && !isHtmxRequest {
|
|
redirectURL := fmt.Sprintf("/history?page=1&pageSize=%d", pageSize)
|
|
if searchTerm != "" {
|
|
redirectURL += fmt.Sprintf("&search=%s", url.QueryEscape(searchTerm))
|
|
}
|
|
c.Redirect(http.StatusFound, redirectURL)
|
|
return
|
|
}
|
|
|
|
data := components.HistoryData{
|
|
History: history,
|
|
CurrentPage: page,
|
|
TotalPages: totalPages,
|
|
SearchTerm: searchTerm,
|
|
PageSize: pageSize,
|
|
Total: int(total),
|
|
}
|
|
|
|
// If this is an HTMX request, only render the history content component
|
|
if isHtmxRequest {
|
|
components.HistoryContent(c, data).Render(c, c.Writer)
|
|
} else {
|
|
components.History(c, data).Render(c, c.Writer)
|
|
}
|
|
}
|
|
|
|
// HandleDashboardData handles the GET /dashboard/data route
|
|
func (h *Handlers) HandleDashboardData(c *gin.Context) {
|
|
// Get recent job runs
|
|
var recentRuns []db.JobHistory
|
|
if err := h.DB.Preload("Job").Order("start_time desc").Limit(5).Find(&recentRuns).Error; err != nil {
|
|
c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to retrieve recent runs"})
|
|
return
|
|
}
|
|
|
|
c.JSON(http.StatusOK, gin.H{
|
|
"recent_runs": recentRuns,
|
|
})
|
|
}
|
|
|
|
// HandleDashboardJobsData handles the GET /dashboard/jobs route
|
|
func (h *Handlers) HandleDashboardJobsData(c *gin.Context) {
|
|
// Get active jobs
|
|
var activeJobs []db.Job
|
|
if err := h.DB.Where("enabled = ?", true).Find(&activeJobs).Error; err != nil {
|
|
c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to retrieve active jobs"})
|
|
return
|
|
}
|
|
|
|
c.JSON(http.StatusOK, gin.H{
|
|
"active_jobs": activeJobs,
|
|
})
|
|
}
|
|
|
|
// HandleDashboardHistoryData handles the GET /dashboard/history route
|
|
func (h *Handlers) HandleDashboardHistoryData(c *gin.Context) {
|
|
// Get job history stats
|
|
var successCount int64
|
|
var failureCount int64
|
|
var pendingCount int64
|
|
|
|
h.DB.Model(&db.JobHistory{}).Where("status = ?", "success").Count(&successCount)
|
|
h.DB.Model(&db.JobHistory{}).Where("status = ?", "failure").Count(&failureCount)
|
|
h.DB.Model(&db.JobHistory{}).Where("status = ?", "pending").Count(&pendingCount)
|
|
|
|
c.JSON(http.StatusOK, gin.H{
|
|
"success_count": successCount,
|
|
"failure_count": failureCount,
|
|
"pending_count": pendingCount,
|
|
})
|
|
}
|
|
|
|
// RegisterRoutes registers all the routes for the web interface
|
|
func (h *Handlers) RegisterRoutes(router *gin.Engine) {
|
|
// Public routes
|
|
router.GET("/", h.HandleHome)
|
|
router.GET("/login", h.HandleLoginPage)
|
|
router.POST("/login", h.HandleLogin)
|
|
router.GET("/forgot-password", h.HandleForgotPasswordPage)
|
|
router.POST("/forgot-password", h.HandleForgotPassword)
|
|
router.GET("/reset-password", h.HandleResetPasswordPage)
|
|
router.POST("/reset-password", h.HandleResetPassword)
|
|
|
|
// Protected routes
|
|
authorized := router.Group("/")
|
|
authorized.Use(h.AuthMiddleware())
|
|
|
|
// Password change route - only accessed from profile page
|
|
authorized.POST("/change-password", h.HandleChangePassword)
|
|
|
|
{
|
|
authorized.GET("/dashboard", h.HandleDashboard)
|
|
authorized.GET("/configs", h.HandleConfigs)
|
|
authorized.GET("/configs/new", h.HandleNewConfig)
|
|
authorized.GET("/configs/:id", h.HandleEditConfig)
|
|
authorized.POST("/configs", h.HandleCreateConfig)
|
|
authorized.PUT("/configs/:id", h.HandleUpdateConfig)
|
|
authorized.POST("/configs/:id", h.HandleUpdateConfig) // Add POST route for form submission
|
|
authorized.DELETE("/configs/:id", h.HandleDeleteConfig)
|
|
authorized.GET("/jobs", h.HandleJobs)
|
|
authorized.GET("/jobs/new", h.HandleNewJob)
|
|
authorized.GET("/jobs/:id", h.HandleEditJob)
|
|
authorized.POST("/jobs", h.HandleCreateJob)
|
|
authorized.PUT("/jobs/:id", h.HandleUpdateJob)
|
|
authorized.POST("/jobs/:id", h.HandleUpdateJob) // Add POST route for form submission
|
|
authorized.DELETE("/jobs/:id", h.HandleDeleteJob)
|
|
authorized.POST("/jobs/:id/run", h.HandleRunJob)
|
|
authorized.GET("/history", h.HandleHistory)
|
|
authorized.GET("/job-runs/:id", h.HandleJobRunDetails)
|
|
authorized.GET("/profile", h.HandleProfile)
|
|
authorized.POST("/profile/theme", h.HandleUpdateTheme)
|
|
authorized.POST("/logout", h.HandleLogout)
|
|
|
|
// AJAX routes for dashboard
|
|
authorized.GET("/dashboard/data", h.HandleDashboardData)
|
|
authorized.GET("/dashboard/jobs", h.HandleDashboardJobsData)
|
|
authorized.GET("/dashboard/history", h.HandleDashboardHistoryData)
|
|
|
|
// Test connection routes
|
|
authorized.POST("/test-connection", h.HandleTestConnection)
|
|
authorized.POST("/test-sftp-connection", h.HandleTestSFTPConnection)
|
|
authorized.POST("/browse-directory", h.HandleBrowseDirectory)
|
|
}
|
|
|
|
// Admin-only routes
|
|
admin := router.Group("/admin")
|
|
admin.Use(h.AuthMiddleware(), h.AdminMiddleware())
|
|
{
|
|
admin.GET("/users", h.HandleUsers)
|
|
admin.GET("/users/new", h.HandleNewUser)
|
|
admin.POST("/users", h.HandleCreateUser)
|
|
admin.DELETE("/users/:id", h.HandleDeleteUser)
|
|
admin.GET("/register", h.HandleRegisterPage)
|
|
admin.POST("/register", h.HandleRegister)
|
|
|
|
// Admin tools routes
|
|
admin.GET("/tools", h.HandleAdminTools)
|
|
admin.POST("/backup-database", h.HandleBackupDatabase)
|
|
admin.POST("/restore-database", h.HandleRestoreDatabase)
|
|
admin.POST("/restore-database/:filename", h.HandleRestoreDatabaseByFilename)
|
|
admin.GET("/export-configs", h.HandleExportConfigs)
|
|
admin.GET("/export-jobs", h.HandleExportJobs)
|
|
admin.POST("/clear-job-history", h.HandleClearJobHistory)
|
|
admin.POST("/vacuum-database", h.HandleVacuumDatabase)
|
|
admin.GET("/download-backup/:filename", h.HandleDownloadBackup)
|
|
admin.DELETE("/delete-backup/:filename", h.HandleDeleteBackup)
|
|
admin.GET("/refresh-backups", h.HandleRefreshBackups)
|
|
}
|
|
|
|
// API routes
|
|
api := router.Group("/api")
|
|
{
|
|
api.POST("/login", h.HandleAPILogin)
|
|
|
|
// Protected API routes
|
|
apiAuthorized := api.Group("/")
|
|
apiAuthorized.Use(h.APIAuthMiddleware())
|
|
{
|
|
// Config endpoints
|
|
apiAuthorized.GET("/configs", h.HandleAPIConfigs)
|
|
apiAuthorized.GET("/configs/:id", h.HandleAPIConfig)
|
|
apiAuthorized.POST("/configs", h.HandleAPICreateConfig)
|
|
apiAuthorized.PUT("/configs/:id", h.HandleAPIUpdateConfig)
|
|
apiAuthorized.DELETE("/configs/:id", h.HandleAPIDeleteConfig)
|
|
|
|
// Job endpoints
|
|
apiAuthorized.GET("/jobs", h.HandleAPIJobs)
|
|
apiAuthorized.GET("/jobs/:id", h.HandleAPIJob)
|
|
apiAuthorized.POST("/jobs", h.HandleAPICreateJob)
|
|
apiAuthorized.PUT("/jobs/:id", h.HandleAPIUpdateJob)
|
|
apiAuthorized.DELETE("/jobs/:id", h.HandleAPIDeleteJob)
|
|
apiAuthorized.POST("/jobs/:id/run", h.HandleAPIRunJob)
|
|
|
|
// History endpoints
|
|
apiAuthorized.GET("/history", h.HandleAPIHistory)
|
|
apiAuthorized.GET("/job-runs/:id", h.HandleAPIJobRun)
|
|
|
|
// Admin-only API routes
|
|
apiAdmin := apiAuthorized.Group("/admin")
|
|
apiAdmin.Use(h.APIAdminMiddleware())
|
|
{
|
|
// User management
|
|
apiAdmin.GET("/users", h.HandleAPIUsers)
|
|
apiAdmin.GET("/users/:id", h.HandleAPIUser)
|
|
apiAdmin.POST("/users", h.HandleAPICreateUser)
|
|
apiAdmin.PUT("/users/:id", h.HandleAPIUpdateUser)
|
|
apiAdmin.DELETE("/users/:id", h.HandleAPIDeleteUser)
|
|
}
|
|
}
|
|
}
|
|
}
|