mirror of
https://github.com/MeshCore-Beacon/beacon-server.git
synced 2026-09-01 16:48:19 +00:00
add region filter to observers
This commit is contained in:
@@ -89,11 +89,11 @@ COALESCE((
|
||||
FROM observers o
|
||||
LEFT JOIN observer_brokers ob ON ob.observer_id = o.id
|
||||
WHERE
|
||||
($1 = '' OR (
|
||||
SELECT po.iata FROM packet_observations po
|
||||
WHERE po.observer_id = o.id
|
||||
ORDER BY po.heard_at DESC LIMIT 1
|
||||
) ILIKE $1)
|
||||
($1::text = '' OR (
|
||||
SELECT po.iata FROM packet_observations po
|
||||
WHERE po.observer_id = o.id
|
||||
ORDER BY po.heard_at DESC LIMIT 1
|
||||
) = ANY(string_to_array($1::text, ',')))
|
||||
AND ($2 = '' OR o.observer_type = $2)
|
||||
AND ($3 = '' OR ob.broker_name = $3)
|
||||
AND ($4 = '' OR CASE
|
||||
|
||||
@@ -1745,11 +1745,11 @@ COALESCE((
|
||||
FROM observers o
|
||||
LEFT JOIN observer_brokers ob ON ob.observer_id = o.id
|
||||
WHERE
|
||||
($1 = '' OR (
|
||||
SELECT po.iata FROM packet_observations po
|
||||
WHERE po.observer_id = o.id
|
||||
ORDER BY po.heard_at DESC LIMIT 1
|
||||
) ILIKE $1)
|
||||
($1::text = '' OR (
|
||||
SELECT po.iata FROM packet_observations po
|
||||
WHERE po.observer_id = o.id
|
||||
ORDER BY po.heard_at DESC LIMIT 1
|
||||
) = ANY(string_to_array($1::text, ',')))
|
||||
AND ($2 = '' OR o.observer_type = $2)
|
||||
AND ($3 = '' OR ob.broker_name = $3)
|
||||
AND ($4 = '' OR CASE
|
||||
@@ -1764,7 +1764,7 @@ LIMIT $7
|
||||
`
|
||||
|
||||
type ListObserversParams struct {
|
||||
Column1 interface{} `json:"column_1"`
|
||||
Column1 string `json:"column_1"`
|
||||
Column2 interface{} `json:"column_2"`
|
||||
Column3 interface{} `json:"column_3"`
|
||||
Column4 interface{} `json:"column_4"`
|
||||
|
||||
+3
-2
@@ -612,13 +612,14 @@ func (s *Store) ListChannelMessagesByHash(ctx context.Context, hash []byte, sinc
|
||||
// status is "online" or "offline" derived from last_status_at recency.
|
||||
// ListObservers returns a paginated list of observers with optional filters.
|
||||
// cursor is last_seen epoch ms of the last observer; pass 0 to start from the beginning.
|
||||
func (s *Store) ListObservers(ctx context.Context, iata, observerType, broker, status, name string, cursor int64, limit int32) (api.Page[api.ObserverSummary], error) {
|
||||
func (s *Store) ListObservers(ctx context.Context, iatas []string, observerType, broker, status, name string, cursor int64, limit int32) (api.Page[api.ObserverSummary], error) {
|
||||
var cursorTS pgtype.Timestamptz
|
||||
if cursor > 0 {
|
||||
cursorTS = pgtype.Timestamptz{Time: time.UnixMilli(cursor), Valid: true}
|
||||
}
|
||||
iataFilter := strings.Join(iatas, ",")
|
||||
params := sqlc.ListObserversParams{
|
||||
Column1: iata,
|
||||
Column1: iataFilter,
|
||||
Column2: observerType,
|
||||
Column3: broker,
|
||||
Column4: status,
|
||||
|
||||
+19
-1
@@ -545,10 +545,28 @@ const docTemplate = `{
|
||||
"parameters": [
|
||||
{
|
||||
"type": "string",
|
||||
"description": "Filter by IATA code (case-insensitive)",
|
||||
"description": "Filter by single IATA code (case-insensitive)",
|
||||
"name": "iata",
|
||||
"in": "query"
|
||||
},
|
||||
{
|
||||
"type": "string",
|
||||
"description": "Filter by multiple IATA codes, comma-separated e.g. YVR,YYJ",
|
||||
"name": "iatas",
|
||||
"in": "query"
|
||||
},
|
||||
{
|
||||
"type": "integer",
|
||||
"description": "Filter by region ID, expands to member IATAs",
|
||||
"name": "regionId",
|
||||
"in": "query"
|
||||
},
|
||||
{
|
||||
"type": "string",
|
||||
"description": "Filter by region slug, expands to member IATAs",
|
||||
"name": "region",
|
||||
"in": "query"
|
||||
},
|
||||
{
|
||||
"type": "string",
|
||||
"description": "Filter by observer type (e.g. meshcoretomqtt, meshcore-ha)",
|
||||
|
||||
+19
-1
@@ -543,10 +543,28 @@
|
||||
"parameters": [
|
||||
{
|
||||
"type": "string",
|
||||
"description": "Filter by IATA code (case-insensitive)",
|
||||
"description": "Filter by single IATA code (case-insensitive)",
|
||||
"name": "iata",
|
||||
"in": "query"
|
||||
},
|
||||
{
|
||||
"type": "string",
|
||||
"description": "Filter by multiple IATA codes, comma-separated e.g. YVR,YYJ",
|
||||
"name": "iatas",
|
||||
"in": "query"
|
||||
},
|
||||
{
|
||||
"type": "integer",
|
||||
"description": "Filter by region ID, expands to member IATAs",
|
||||
"name": "regionId",
|
||||
"in": "query"
|
||||
},
|
||||
{
|
||||
"type": "string",
|
||||
"description": "Filter by region slug, expands to member IATAs",
|
||||
"name": "region",
|
||||
"in": "query"
|
||||
},
|
||||
{
|
||||
"type": "string",
|
||||
"description": "Filter by observer type (e.g. meshcoretomqtt, meshcore-ha)",
|
||||
|
||||
+13
-1
@@ -1029,10 +1029,22 @@ paths:
|
||||
/observers:
|
||||
get:
|
||||
parameters:
|
||||
- description: Filter by IATA code (case-insensitive)
|
||||
- description: Filter by single IATA code (case-insensitive)
|
||||
in: query
|
||||
name: iata
|
||||
type: string
|
||||
- description: Filter by multiple IATA codes, comma-separated e.g. YVR,YYJ
|
||||
in: query
|
||||
name: iatas
|
||||
type: string
|
||||
- description: Filter by region ID, expands to member IATAs
|
||||
in: query
|
||||
name: regionId
|
||||
type: integer
|
||||
- description: Filter by region slug, expands to member IATAs
|
||||
in: query
|
||||
name: region
|
||||
type: string
|
||||
- description: Filter by observer type (e.g. meshcoretomqtt, meshcore-ha)
|
||||
in: query
|
||||
name: type
|
||||
|
||||
@@ -32,7 +32,10 @@ func ObserversRouter(reader api.Reader) http.Handler {
|
||||
// @Summary List observers
|
||||
// @Tags Observers
|
||||
// @Produce json
|
||||
// @Param iata query string false "Filter by IATA code (case-insensitive)"
|
||||
// @Param iata query string false "Filter by single IATA code (case-insensitive)"
|
||||
// @Param iatas query string false "Filter by multiple IATA codes, comma-separated e.g. YVR,YYJ"
|
||||
// @Param regionId query int false "Filter by region ID, expands to member IATAs"
|
||||
// @Param region query string false "Filter by region slug, expands to member IATAs"
|
||||
// @Param type query string false "Filter by observer type (e.g. meshcoretomqtt, meshcore-ha)"
|
||||
// @Param broker query string false "Filter by broker name"
|
||||
// @Param status query string false "Filter by status (online or offline)"
|
||||
@@ -45,7 +48,6 @@ func ObserversRouter(reader api.Reader) http.Handler {
|
||||
// @Router /observers [get]
|
||||
func listObservers(reader api.Reader) http.HandlerFunc {
|
||||
return func(w http.ResponseWriter, r *http.Request) {
|
||||
iata := r.URL.Query().Get("iata")
|
||||
observerType := r.URL.Query().Get("type")
|
||||
broker := r.URL.Query().Get("broker")
|
||||
name := r.URL.Query().Get("name")
|
||||
@@ -68,7 +70,16 @@ func listObservers(reader api.Reader) http.HandlerFunc {
|
||||
}
|
||||
limit = int32(l)
|
||||
}
|
||||
observers, err := reader.ListObservers(r.Context(), iata, observerType, broker, status, name, cursor, limit)
|
||||
iatas := parseIATAs(r)
|
||||
if regionIDStr := r.URL.Query().Get("regionId"); regionIDStr != "" || r.URL.Query().Get("region") != "" {
|
||||
regionIATAs, err := resolveRegionIATAs(r.Context(), regionIDStr, r.URL.Query().Get("region"), reader)
|
||||
if err != nil {
|
||||
respondError(w, http.StatusBadRequest, err.Error())
|
||||
return
|
||||
}
|
||||
iatas = append(iatas, regionIATAs...)
|
||||
}
|
||||
observers, err := reader.ListObservers(r.Context(), iatas, observerType, broker, status, name, cursor, limit)
|
||||
if err != nil {
|
||||
respondError(w, http.StatusInternalServerError, "failed to get list of observers")
|
||||
return
|
||||
|
||||
@@ -396,10 +396,10 @@ type Reader interface {
|
||||
// Pass cursor=0 to start from the beginning.
|
||||
ListChannelMessagesByHash(ctx context.Context, hash []byte, since time.Time, limit int32, iata string, cursor int64) (Page[ChannelMessage], error)
|
||||
// ListObservers returns a paginated list of observers with optional filters.
|
||||
// All filter params are optional — pass empty string to skip a filter.
|
||||
// All filter params are optional — pass empty string or nil to skip a filter.
|
||||
// status is "online" or "offline" derived from last_status_at recency.
|
||||
// cursor is last_seen epoch ms of the last observer; pass 0 to start from the beginning.
|
||||
ListObservers(ctx context.Context, iata, observerType, broker, status, name string, cursor int64, limit int32) (Page[ObserverSummary], error)
|
||||
ListObservers(ctx context.Context, iatas []string, observerType, broker, status, name string, cursor int64, limit int32) (Page[ObserverSummary], error)
|
||||
// GetObserver returns full detail for a single observer by UUID.
|
||||
// Returns nil, pgx.ErrNoRows if the observer is not found.
|
||||
GetObserver(ctx context.Context, observerID uuid.UUID) (*Observer, error)
|
||||
|
||||
Reference in New Issue
Block a user