diff --git a/frontend/src/routes/(loggedin)/app/crons/+page.svelte b/frontend/src/routes/(loggedin)/app/crons/+page.svelte index 2290970..207ea8c 100644 --- a/frontend/src/routes/(loggedin)/app/crons/+page.svelte +++ b/frontend/src/routes/(loggedin)/app/crons/+page.svelte @@ -10,7 +10,7 @@ DtSrAutoRefresh } from '$lib/components/datatables/server'; - const handler = new DataHandler([], { rowsPerPage: 1000, totalRows: 0 }); + const handler = new DataHandler([], { rowsPerPage: 10, totalRows: 0 }); let rows = handler.getRows(); /** @type {string | number} */ @@ -73,8 +73,8 @@ }} > - - + + @@ -89,8 +89,8 @@ }} > - - + + diff --git a/frontend/src/routes/(loggedin)/app/crons/api-handler.js b/frontend/src/routes/(loggedin)/app/crons/api-handler.js index 3f095df..f8dc121 100644 --- a/frontend/src/routes/(loggedin)/app/crons/api-handler.js +++ b/frontend/src/routes/(loggedin)/app/crons/api-handler.js @@ -1,18 +1,23 @@ import { apiUri } from '$lib/utils/common'; +import { goto } from '$app/navigation'; /** @param {import('@vincjo/datatables/remote/state')} state */ export const loadData = async (state) => { const response = await fetch(apiUri(`/api/v1/crons?${getParams(state)}`)); const json = await response.json(); + if (json.data === null) { + goto('/login'); + return; + } state.setTotalRows(json.data.length ?? 0); - return json.data ?? []; + return json.data.items ?? []; }; const getParams = ({ pageNumber, rowsPerPage, sort, filters }) => { let params = `page=${pageNumber}&limit=${rowsPerPage}`; if (sort) { - params += `&orderBy=${sort.orderBy}&orderDir=${sort.direction}`; + params += `&sort_by=${sort.orderBy}&sort_direction=${sort.direction}`; } if (filters) { params += filters.map(({ filterBy, value }) => `&${filterBy}=${value}`).join(''); diff --git a/handler/response.go b/handler/response.go index 4b572c2..77ed8a3 100644 --- a/handler/response.go +++ b/handler/response.go @@ -355,8 +355,18 @@ func ProcessJob(c *fiber.Ctx) error { func Crons(c *fiber.Ctx) error { cronRepo := repo.NewCron(database.GetDB()) + query := repo.CronQueryParams{ + RowsPerPage: c.QueryInt("limit", 10), + Page: c.QueryInt("page", 1), + SortBy: c.Query("sort_by", "id"), + SortDirection: c.Query("sort_direction", "desc"), + Title: c.Query("title"), + Description: c.Query("description"), + IsEnabled: c.QueryInt("is_enabled", -1), + CronState: c.QueryInt("cron_state", -1), + } - crons, err := cronRepo.Crons() + crons, err := cronRepo.Crons(query) if err != nil { return c.Status(fiber.StatusInternalServerError).JSON(fiber.Map{ "status": "error", @@ -367,7 +377,7 @@ func Crons(c *fiber.Ctx) error { return c.JSON(fiber.Map{ "status": "ok", - "message": "Crons", + "message": "Success", "data": crons, }) } diff --git a/handler/routes.go b/handler/routes.go index 1dff19f..052210d 100644 --- a/handler/routes.go +++ b/handler/routes.go @@ -16,6 +16,7 @@ func V1Api(app *fiber.App) { v1.Post("/prober", CookieProtected, Prober) v1.Patch("/prober/:id", CookieProtected, Prober) v1.Delete("/prober/:id", CookieProtected, Prober) + v1.Get("/crons", CookieProtected, Crons) v1.Get("/nodes", MoneroNodes) v1.Post("/nodes", AddNode) v1.Get("/nodes/id/:id", MoneroNode) @@ -24,5 +25,4 @@ func V1Api(app *fiber.App) { v1.Get("/countries", Countries) v1.Get("/job", CheckProber, GiveJob) v1.Post("/job", CheckProber, ProcessJob) - v1.Get("/crons", Crons) } diff --git a/internal/repo/cron.go b/internal/repo/cron.go index aec1f57..30798e7 100644 --- a/internal/repo/cron.go +++ b/internal/repo/cron.go @@ -3,6 +3,8 @@ package repo import ( "fmt" "math" + "slices" + "strings" "time" "github.com/ditatompel/xmr-nodes/internal/database" @@ -10,14 +12,14 @@ import ( type CronRepository interface { RunCronProcess() - Crons() ([]CronTask, error) + Crons(q CronQueryParams) (CronTasks, error) } type CronRepo struct { db *database.DB } -type CronTask struct { +type Cron struct { Id int `json:"id" db:"id"` Title string `json:"title" db:"title"` Slug string `json:"slug" db:"slug"` @@ -68,15 +70,77 @@ func (repo *CronRepo) RunCronProcess() { } } -func (repo *CronRepo) Crons() ([]CronTask, error) { - tasks := []CronTask{} - query := `SELECT * FROM tbl_cron` - err := repo.db.Select(&tasks, query) - return tasks, err +type CronQueryParams struct { + Title string + Description string + IsEnabled int + CronState int + RowsPerPage int + Page int + SortBy string + SortDirection string } -func (repo *CronRepo) queueList() ([]CronTask, error) { - tasks := []CronTask{} +type CronTasks struct { + TotalRows int `json:"total_rows"` + RowsPerPage int `json:"rows_per_page"` + Items []*Cron `json:"items"` +} + +func (repo *CronRepo) Crons(q CronQueryParams) (CronTasks, error) { + queryParams := []interface{}{} + whereQueries := []string{} + where := "" + + if q.Title != "" { + whereQueries = append(whereQueries, "title LIKE ?") + queryParams = append(queryParams, "%"+q.Title+"%") + } + if q.Description != "" { + whereQueries = append(whereQueries, "description LIKE ?") + queryParams = append(queryParams, "%"+q.Description+"%") + } + if q.IsEnabled != -1 { + whereQueries = append(whereQueries, "is_enabled = ?") + queryParams = append(queryParams, q.IsEnabled) + } + if q.CronState != -1 { + whereQueries = append(whereQueries, "cron_state = ?") + queryParams = append(queryParams, q.CronState) + } + if len(whereQueries) > 0 { + where = "WHERE " + strings.Join(whereQueries, " AND ") + } + tasks := CronTasks{} + + queryTotalRows := fmt.Sprintf("SELECT COUNT(id) FROM tbl_cron %s", where) + err := repo.db.QueryRow(queryTotalRows, queryParams...).Scan(&tasks.TotalRows) + if err != nil { + return tasks, err + } + queryParams = append(queryParams, q.RowsPerPage, (q.Page-1)*q.RowsPerPage) + allowedSort := []string{"id", "run_every", "last_run", "next_run", "run_time"} + sortBy := "id" + if slices.Contains(allowedSort, q.SortBy) { + sortBy = q.SortBy + } + sortDirection := "DESC" + if q.SortDirection == "asc" { + sortDirection = "ASC" + } + + query := fmt.Sprintf("SELECT id, title, slug, description, run_every, last_run, next_run, run_time, cron_state, is_enabled FROM tbl_cron %s ORDER BY %s %s LIMIT ? OFFSET ?", where, sortBy, sortDirection) + err = repo.db.Select(&tasks.Items, query, queryParams...) + if err != nil { + return tasks, err + } + tasks.RowsPerPage = q.RowsPerPage + + return tasks, nil +} + +func (repo *CronRepo) queueList() ([]Cron, error) { + tasks := []Cron{} query := `SELECT id, run_every, last_run, slug, next_run, cron_state FROM tbl_cron WHERE is_enabled = ? AND next_run <= ?` err := repo.db.Select(&tasks, query, 1, time.Now().Unix())