diff --git a/handler/routes.go b/handler/routes.go index ede3654..76b35e4 100644 --- a/handler/routes.go +++ b/handler/routes.go @@ -408,6 +408,54 @@ func GetClient(db store.IStore) echo.HandlerFunc { } } +// ListServers handler returns a JSON list of registered servers (step 2 of +// the multi-server extension - read-only, additive alongside the existing +// single-server routes). +func ListServers(db store.IStore) echo.HandlerFunc { + return func(c echo.Context) error { + servers, err := db.GetServers() + if err != nil { + return c.JSON(http.StatusInternalServerError, jsonHTTPResponse{ + false, fmt.Sprintf("Cannot get server list: %v", err), + }) + } + return c.JSON(http.StatusOK, servers) + } +} + +// GetServerClients handler returns a JSON list of clients belonging to a +// single server (step 2 of the multi-server extension). Filtering happens +// in-handler for now since db.GetClients has not yet been switched to a +// server-scoped signature (that's a later step). +func GetServerClients(db store.IStore) echo.HandlerFunc { + return func(c echo.Context) error { + serverID := c.Param("id") + if !util.ValidateRecordID(serverID) { + return c.JSON(http.StatusBadRequest, jsonHTTPResponse{false, "Please provide a valid server ID"}) + } + + if _, err := db.GetServerByID(serverID); err != nil { + return c.JSON(http.StatusNotFound, jsonHTTPResponse{false, "Server not found"}) + } + + clientDataList, err := db.GetClients(false) + if err != nil { + return c.JSON(http.StatusInternalServerError, jsonHTTPResponse{ + false, fmt.Sprintf("Cannot get client list: %v", err), + }) + } + + var filtered []model.ClientData + for _, cd := range clientDataList { + if cd.Client.ServerID == serverID { + filtered = append(filtered, cd) + } + } + + return c.JSON(http.StatusOK, filtered) + } +} + // NewClient handler func NewClient(db store.IStore) echo.HandlerFunc { return func(c echo.Context) error { diff --git a/main.go b/main.go index 1125746..c776b95 100644 --- a/main.go +++ b/main.go @@ -251,6 +251,8 @@ func main() { app.GET(util.BasePath+"/global-settings", handler.GlobalSettings(db), handler.ValidSession, handler.RefreshSession, handler.NeedsAdmin) app.POST(util.BasePath+"/global-settings", handler.GlobalSettingSubmit(db), handler.ValidSession, handler.ContentTypeJson, handler.NeedsAdmin) app.GET(util.BasePath+"/status", handler.Status(db), handler.ValidSession, handler.RefreshSession) + app.GET(util.BasePath+"/servers", handler.ListServers(db), handler.ValidSession) + app.GET(util.BasePath+"/servers/:id/clients", handler.GetServerClients(db), handler.ValidSession) app.GET(util.BasePath+"/api/clients", handler.GetClients(db), handler.ValidSession) app.GET(util.BasePath+"/api/client/:id", handler.GetClient(db), handler.ValidSession) app.GET(util.BasePath+"/api/machine-ips", handler.MachineIPAddresses(), handler.ValidSession) diff --git a/store/jsondb/jsondb.go b/store/jsondb/jsondb.go index c2392ce..12b7330 100644 --- a/store/jsondb/jsondb.go +++ b/store/jsondb/jsondb.go @@ -556,11 +556,20 @@ func (o *JsonDB) GetServers() ([]model.Server, error) { return servers, nil } +// validateServerID checks a server ID before it is ever used as a jsondb +// record key, shared by every server-scoped store method below. +func validateServerID(serverID string) error { + if !util.ValidateRecordID(serverID) { + return fmt.Errorf("invalid server id: %s", serverID) + } + return nil +} + // GetServerByID func to query a single server by id from the database func (o *JsonDB) GetServerByID(serverID string) (model.Server, error) { server := model.Server{} - if !util.ValidateRecordID(serverID) { - return server, fmt.Errorf("invalid server id: %s", serverID) + if err := validateServerID(serverID); err != nil { + return server, err } err := o.conn.Read("servers", serverID, &server) return server, err @@ -571,8 +580,8 @@ func (o *JsonDB) CreateServer(server model.Server) error { if server.ID == "" { return fmt.Errorf("cannot create server: missing id") } - if !util.ValidateRecordID(server.ID) { - return fmt.Errorf("invalid server id: %s", server.ID) + if err := validateServerID(server.ID); err != nil { + return err } if server.Interface != nil && server.Interface.Name != "" && !util.ValidateInterfaceName(server.Interface.Name) { return fmt.Errorf("invalid interface name: %s", server.Interface.Name) @@ -586,8 +595,8 @@ func (o *JsonDB) CreateServer(server model.Server) error { // DeleteServer func to remove a server from the database, refusing if // any client still references it func (o *JsonDB) DeleteServer(serverID string) error { - if !util.ValidateRecordID(serverID) { - return fmt.Errorf("invalid server id: %s", serverID) + if err := validateServerID(serverID); err != nil { + return err } records, err := o.conn.ReadAll("clients") if err != nil && err != scribble.ErrMissingCollection { @@ -612,16 +621,16 @@ func (o *JsonDB) DeleteServer(serverID string) error { // GetServerSettings func to query per-server settings from the database func (o *JsonDB) GetServerSettings(serverID string) (model.ServerSetting, error) { settings := model.ServerSetting{} - if !util.ValidateRecordID(serverID) { - return settings, fmt.Errorf("invalid server id: %s", serverID) + if err := validateServerID(serverID); err != nil { + return settings, err } return settings, o.conn.Read("server_settings", serverID, &settings) } // SaveServerSettings func to save per-server settings in the database func (o *JsonDB) SaveServerSettings(serverID string, settings model.ServerSetting) error { - if !util.ValidateRecordID(serverID) { - return fmt.Errorf("invalid server id: %s", serverID) + if err := validateServerID(serverID); err != nil { + return err } settingsPath := path.Join(o.dbPath, "server_settings", serverID+".json") output := o.conn.Write("server_settings", serverID, settings) @@ -635,16 +644,16 @@ func (o *JsonDB) SaveServerSettings(serverID string, settings model.ServerSettin // GetServerHashes func to query per-server client/server hashes from the database func (o *JsonDB) GetServerHashes(serverID string) (model.ClientServerHashes, error) { hashes := model.ClientServerHashes{} - if !util.ValidateRecordID(serverID) { - return hashes, fmt.Errorf("invalid server id: %s", serverID) + if err := validateServerID(serverID); err != nil { + return hashes, err } return hashes, o.conn.Read("server_hashes", serverID, &hashes) } // SaveServerHashes func to save per-server client/server hashes in the database func (o *JsonDB) SaveServerHashes(serverID string, hashes model.ClientServerHashes) error { - if !util.ValidateRecordID(serverID) { - return fmt.Errorf("invalid server id: %s", serverID) + if err := validateServerID(serverID); err != nil { + return err } hashesPath := path.Join(o.dbPath, "server_hashes", serverID+".json") output := o.conn.Write("server_hashes", serverID, hashes)