diff --git a/cmd/probers.go b/cmd/probers.go new file mode 100644 index 0000000..1d65f1c --- /dev/null +++ b/cmd/probers.go @@ -0,0 +1,65 @@ +package cmd + +import ( + "fmt" + "os" + "strings" + "text/tabwriter" + "time" + "xmr-remote-nodes/internal/database" + "xmr-remote-nodes/internal/repo" + + "github.com/spf13/cobra" +) + +var probersCmd = &cobra.Command{ + Use: "probers [search]", + Short: "[server] Get registered probers", + Long: `Get list of registered prober machines. + +Use [search] args to filter results by name or api key. + +"sort-by" flag can be "id" or "last_submit_ts" +"sort-dir" flag can be "asc" or "desc"`, + Example: `# To sort probers by last submit time in ascending order that contains "sin1": +xmr-nodes probers -s last_submit_ts -d asc sin1`, + Run: func(cmd *cobra.Command, args []string) { + if err := database.ConnectDB(); err != nil { + panic(err) + } + sortBy, _ := cmd.Flags().GetString("sort-by") + sortDir, _ := cmd.Flags().GetString("sort-dir") + + probersRepo := repo.NewProberRepo(database.GetDB()) + probers, err := probersRepo.Probers(repo.ProbersQueryParams{ + Search: strings.Join(args, " "), + SortBy: sortBy, + SortDirection: sortDir, + }) + if err != nil { + fmt.Println(err) + return + } + if len(probers) == 0 { + fmt.Println("No probers found") + return + } + w := tabwriter.NewWriter(os.Stdout, 1, 1, 1, ' ', 0) + fmt.Fprintf(w, "ID\t| Name\t| Last Submit\t| API Key\n") + for _, prober := range probers { + fmt.Fprintf(w, "%d\t| %s\t| %s\t| %s\n", + prober.Id, + prober.Name, + time.Unix(prober.LastSubmitTs, 0).Format(time.RFC3339), + prober.ApiKey, + ) + } + w.Flush() + }, +} + +func init() { + rootCmd.AddCommand(probersCmd) + probersCmd.Flags().StringP("sort-by", "s", "last_submit_ts", "Sort by column name, can be id or last_submit_ts") + probersCmd.Flags().StringP("sort-dir", "d", "desc", "Sort direction, can be asc or desc") +} diff --git a/handler/response.go b/handler/response.go index 89ad66e..f29247f 100644 --- a/handler/response.go +++ b/handler/response.go @@ -60,101 +60,6 @@ func Logout(c *fiber.Ctx) error { }) } -func Prober(c *fiber.Ctx) error { - proberRepo := repo.NewProberRepo(database.GetDB()) - - if c.Method() == "POST" { - payload := repo.Prober{} - if err := c.BodyParser(&payload); err != nil { - return c.Status(fiber.StatusUnprocessableEntity).JSON(fiber.Map{ - "status": "error", - "message": err.Error(), - "data": nil, - }) - } - if payload.Name == "" { - return c.Status(fiber.StatusUnprocessableEntity).JSON(fiber.Map{ - "status": "error", - "message": "Please fill prober name", - "data": nil, - }) - } - err := proberRepo.AddProber(payload.Name) - if err != nil { - return c.Status(fiber.StatusInternalServerError).JSON(fiber.Map{ - "status": "error", - "message": err.Error(), - "data": nil, - }) - } - } else if c.Method() == "DELETE" { - id, _ := strconv.Atoi(c.Params("id")) - err := proberRepo.Delete(id) - if err != nil { - return c.Status(fiber.StatusInternalServerError).JSON(fiber.Map{ - "status": "error", - "message": err.Error(), - "data": nil, - }) - } - - return c.JSON(fiber.Map{ - "status": "ok", - "message": "Success", - "data": nil, - }) - } else if c.Method() == "PATCH" { - payload := repo.Prober{} - if err := c.BodyParser(&payload); err != nil { - return c.Status(fiber.StatusUnprocessableEntity).JSON(fiber.Map{ - "status": "error", - "message": err.Error(), - "data": nil, - }) - } - if payload.Name == "" { - return c.Status(fiber.StatusUnprocessableEntity).JSON(fiber.Map{ - "status": "error", - "message": "Please fill prober name", - "data": nil, - }) - } - id, _ := strconv.Atoi(c.Params("id")) - err := proberRepo.Update(id, payload.Name) - if err != nil { - return c.Status(fiber.StatusInternalServerError).JSON(fiber.Map{ - "status": "error", - "message": err.Error(), - "data": nil, - }) - } - } - - query := repo.ProbersQueryParams{ - RowsPerPage: c.QueryInt("limit", 10), - Page: c.QueryInt("page", 1), - SortBy: c.Query("sort_by", "id"), - SortDirection: c.Query("sort_direction", "desc"), - Name: c.Query("name"), - ApiKey: c.Query("api_key"), - } - - prober, err := proberRepo.Probers(query) - if err != nil { - return c.Status(fiber.StatusInternalServerError).JSON(fiber.Map{ - "status": "error", - "message": err.Error(), - "data": nil, - }) - } - - return c.JSON(fiber.Map{ - "status": "ok", - "message": "Success", - "data": prober, - }) -} - func MoneroNode(c *fiber.Ctx) error { nodeId, err := c.ParamsInt("id", 0) if err != nil { diff --git a/handler/routes.go b/handler/routes.go index 052210d..c0cbaf6 100644 --- a/handler/routes.go +++ b/handler/routes.go @@ -12,10 +12,6 @@ func AppRoute(app *fiber.App) { func V1Api(app *fiber.App) { v1 := app.Group("/api/v1") - v1.Get("/prober", CookieProtected, Prober) - 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) diff --git a/internal/repo/prober.go b/internal/repo/prober.go index 9e3f0d5..1e80427 100644 --- a/internal/repo/prober.go +++ b/internal/repo/prober.go @@ -12,7 +12,7 @@ import ( type ProberRepository interface { AddProber(name string) error Update(id int, name string) error - Probers(q ProbersQueryParams) (Probers, error) + Probers(q ProbersQueryParams) ([]Prober, error) CheckApi(key string) (Prober, error) Delete(id int) error } @@ -28,24 +28,6 @@ type Prober struct { LastSubmitTs int64 `json:"last_submit_ts" db:"last_submit_ts"` } -type ProbersQueryParams struct { - Name string - ApiKey string - - RowsPerPage int - Page int - SortBy string - SortDirection string -} - -type Probers struct { - TotalRows int `json:"total_rows"` - RowsPerPage int `json:"rows_per_page"` - CurrentPage int `json:"current_page"` - NextPage int `json:"next_page"` - Items []*Prober `json:"items"` -} - func NewProberRepo(db *database.DB) ProberRepository { return &ProberRepo{db} } @@ -71,35 +53,31 @@ func (repo *ProberRepo) Delete(id int) error { return err } -func (repo *ProberRepo) Probers(q ProbersQueryParams) (Probers, error) { +type ProbersQueryParams struct { + Search string + SortBy string + SortDirection string +} + +func (repo *ProberRepo) Probers(q ProbersQueryParams) ([]Prober, error) { queryParams := []interface{}{} whereQueries := []string{} where := "" - if q.Name != "" { - whereQueries = append(whereQueries, "name LIKE ?") - queryParams = append(queryParams, "%"+q.Name+"%") - } - if q.ApiKey != "" { - whereQueries = append(whereQueries, "api_key LIKE ?") - queryParams = append(queryParams, "%"+q.ApiKey+"%") + if q.Search != "" { + whereQueries = append(whereQueries, "(name LIKE ? OR api_key LIKE ?)") + queryParams = append(queryParams, "%"+q.Search+"%") + queryParams = append(queryParams, "%"+q.Search+"%") } if len(whereQueries) > 0 { where = "WHERE " + strings.Join(whereQueries, " AND ") } - probers := Probers{} - queryTotalRows := fmt.Sprintf("SELECT COUNT(id) AS total_rows FROM tbl_prober %s", where) - - err := repo.db.QueryRow(queryTotalRows, queryParams...).Scan(&probers.TotalRows) - if err != nil { - return probers, err - } - queryParams = append(queryParams, q.RowsPerPage, (q.Page-1)*q.RowsPerPage) + probers := []Prober{} allowedSort := []string{"id", "last_submit_ts"} - sortBy := "id" + sortBy := "last_submit_ts" if slices.Contains(allowedSort, q.SortBy) { sortBy = q.SortBy } @@ -108,7 +86,7 @@ func (repo *ProberRepo) Probers(q ProbersQueryParams) (Probers, error) { sortDirection = "ASC" } - query := fmt.Sprintf("SELECT id, name, api_key, last_submit_ts FROM tbl_prober %s ORDER BY %s %s LIMIT ? OFFSET ?", where, sortBy, sortDirection) + query := fmt.Sprintf("SELECT id, name, api_key, last_submit_ts FROM tbl_prober %s ORDER BY %s %s", where, sortBy, sortDirection) row, err := repo.db.Query(query, queryParams...) if err != nil { @@ -116,17 +94,13 @@ func (repo *ProberRepo) Probers(q ProbersQueryParams) (Probers, error) { } defer row.Close() - probers.RowsPerPage = q.RowsPerPage - probers.CurrentPage = q.Page - probers.NextPage = q.Page + 1 - for row.Next() { prober := Prober{} err = row.Scan(&prober.Id, &prober.Name, &prober.ApiKey, &prober.LastSubmitTs) if err != nil { return probers, err } - probers.Items = append(probers.Items, &prober) + probers = append(probers, prober) } return probers, nil }