From e4e4065c2b84410ac7cd2e96276227ea9d7947e8 Mon Sep 17 00:00:00 2001 From: dvdrw Date: Sat, 16 May 2026 20:55:00 +0200 Subject: [PATCH] feat: add current room occupancy endpoint --- .../web/controllers/tag_controller.ex | 37 ++++++++++++++++++- lib/localiser/web/router.ex | 1 + lib/localiser/web/schemas.ex | 24 ++++++++++-- 3 files changed, 57 insertions(+), 5 deletions(-) diff --git a/lib/localiser/web/controllers/tag_controller.ex b/lib/localiser/web/controllers/tag_controller.ex index 82f1d63..4070620 100644 --- a/lib/localiser/web/controllers/tag_controller.ex +++ b/lib/localiser/web/controllers/tag_controller.ex @@ -2,12 +2,21 @@ defmodule Localiser.Web.Controllers.TagController do use Phoenix.Controller, formats: [:json] use OpenApiSpex.ControllerSpecs - alias Localiser.Domain.Tags + alias Localiser.Domain.{Rooms, Tags} + alias Localiser.Localisation.Tag.Filter, as: TagFilter alias Localiser.Web.Schemas tags ["Tags"] security [%{"bearerAuth" => []}] + operation :occupancy, + summary: "Get every tag's current room", + responses: [ + ok: {"Tag occupancy list", "application/json", + %OpenApiSpex.Schema{type: :array, items: Schemas.TagOccupancy}}, + unauthorized: {"Unauthorized", "application/json", Schemas.Error} + ] + operation :index, summary: "List all tags", responses: [ @@ -50,6 +59,18 @@ defmodule Localiser.Web.Controllers.TagController do unauthorized: {"Unauthorized", "application/json", Schemas.Error} ] + def occupancy(conn, _params) do + tag_to_room = build_tag_to_room_map() + + result = + Tags.list_tags() + |> Enum.map(fn tag -> + %{id: tag.id, tag_id: tag.tag_id, name: tag.name, room_id: Map.get(tag_to_room, tag.tag_id)} + end) + + json(conn, result) + end + def index(conn, _params) do json(conn, Enum.map(Tags.list_tags(), &render_tag/1)) end @@ -94,6 +115,20 @@ defmodule Localiser.Web.Controllers.TagController do send_resp(conn, :no_content, "") end + defp build_tag_to_room_map do + Rooms.list_rooms() + |> Enum.flat_map(fn room -> + occupants = + case Registry.lookup(Localiser.Registry, {:room, room.id}) do + [{pid, _}] -> GenServer.call(pid, :get_occupants) + [] -> MapSet.new() + end + + Enum.map(MapSet.to_list(occupants), &{&1, room.id}) + end) + |> Map.new() + end + defp render_tag(tag) do live = TagFilter.get_live_state(tag.tag_id) diff --git a/lib/localiser/web/router.ex b/lib/localiser/web/router.ex index 76758bc..c26a1bb 100644 --- a/lib/localiser/web/router.ex +++ b/lib/localiser/web/router.ex @@ -71,6 +71,7 @@ defmodule Localiser.Web.Router do resources "/floors", FloorController, except: [:new, :edit] resources "/floors/:floor_id/rooms", RoomController, except: [:new, :edit] + get "/tags/occupancy", TagController, :occupancy resources "/tags", TagController, except: [:new, :edit] # Sensors diff --git a/lib/localiser/web/schemas.ex b/lib/localiser/web/schemas.ex index 6694660..2485889 100644 --- a/lib/localiser/web/schemas.ex +++ b/lib/localiser/web/schemas.ex @@ -67,11 +67,13 @@ defmodule Localiser.Web.Schemas do OpenApiSpex.schema(%{ title: "Tag", type: :object, properties: %{ - id: %Schema{type: :integer}, - tag_id: %Schema{type: :string}, - name: %Schema{type: :string} + id: %Schema{type: :integer}, + tag_id: %Schema{type: :string}, + name: %Schema{type: :string}, + room_id: %Schema{type: :integer, nullable: true}, + last_seen: %Schema{type: :string, format: :"date-time", nullable: true} }, - required: [:id, :tag_id, :name] + required: [:id, :tag_id, :name, :room_id, :last_seen] }) end @@ -303,6 +305,20 @@ defmodule Localiser.Web.Schemas do }) end + defmodule TagOccupancy do + require OpenApiSpex + OpenApiSpex.schema(%{ + title: "TagOccupancy", type: :object, + properties: %{ + id: %Schema{type: :integer}, + tag_id: %Schema{type: :string}, + name: %Schema{type: :string}, + room_id: %Schema{type: :integer, nullable: true} + }, + required: [:id, :tag_id, :name, :room_id] + }) + end + defmodule TagParams do require OpenApiSpex OpenApiSpex.schema(%{