fix: resolve 500 errors on /activity and /changelog

- Activity feed: use schema modules instead of string table names in Ecto
  queries to fix UUID encoding (Postgrex expected binary, got string)
- Changelog parser: remove plain hyphen from separator character class
  to prevent splitting on date hyphens (2026-02-13)
This commit is contained in:
Graham McIntire 2026-02-13 19:49:12 -06:00
parent 67eac2f1c9
commit 0fc36524b4
2 changed files with 24 additions and 17 deletions

View file

@ -13,6 +13,12 @@ defmodule Towerops.ActivityFeed do
import Ecto.Query
alias Towerops.Alerts.Alert
alias Towerops.ConfigChanges.ConfigChangeEvent
alias Towerops.Devices.Device
alias Towerops.Devices.Event, as: DeviceEvent
alias Towerops.Preseem.SyncLog
alias Towerops.Sites.Site
alias Towerops.Repo
@type activity_item :: %{
@ -109,10 +115,10 @@ defmodule Towerops.ActivityFeed do
defp fetch_source(:config_change, org_id, after_dt, before_dt, limit) do
query =
from(c in "config_change_events",
join: d in "devices",
from(c in ConfigChangeEvent,
join: d in Device,
on: d.id == c.device_id,
left_join: s in "sites",
left_join: s in Site,
on: s.id == d.site_id,
where: c.organization_id == ^org_id,
select: %{
@ -155,10 +161,10 @@ defmodule Towerops.ActivityFeed do
defp fetch_source(:alert_fired, org_id, after_dt, before_dt, limit) do
query =
from(a in "alerts",
join: d in "devices",
from(a in Alert,
join: d in Device,
on: d.id == a.device_id,
left_join: s in "sites",
left_join: s in Site,
on: s.id == d.site_id,
where: d.organization_id == ^org_id,
where: a.alert_type == "device_down",
@ -201,10 +207,10 @@ defmodule Towerops.ActivityFeed do
defp fetch_source(:alert_resolved, org_id, after_dt, before_dt, limit) do
query =
from(a in "alerts",
join: d in "devices",
from(a in Alert,
join: d in Device,
on: d.id == a.device_id,
left_join: s in "sites",
left_join: s in Site,
on: s.id == d.site_id,
where: d.organization_id == ^org_id,
where: not is_nil(a.resolved_at),
@ -247,10 +253,10 @@ defmodule Towerops.ActivityFeed do
defp fetch_source(:device_event, org_id, after_dt, before_dt, limit) do
query =
from(e in "device_events",
join: d in "devices",
from(e in DeviceEvent,
join: d in Device,
on: d.id == e.device_id,
left_join: s in "sites",
left_join: s in Site,
on: s.id == d.site_id,
where: d.organization_id == ^org_id,
select: %{
@ -291,7 +297,7 @@ defmodule Towerops.ActivityFeed do
defp fetch_source(:sync, org_id, after_dt, before_dt, limit) do
query =
from(sl in "preseem_sync_logs",
from(sl in SyncLog,
where: sl.organization_id == ^org_id,
select: %{
id: sl.id,
@ -331,8 +337,8 @@ defmodule Towerops.ActivityFeed do
defp fetch_source(:device_added, org_id, after_dt, before_dt, limit) do
query =
from(d in "devices",
left_join: s in "sites",
from(d in Device,
left_join: s in Site,
on: s.id == d.site_id,
where: d.organization_id == ^org_id,
select: %{

View file

@ -17,8 +17,9 @@ defmodule ToweropsWeb.ChangelogParser do
|> Enum.reduce([], fn line, acc ->
cond do
# Date header with title: "2026-02-13 — Title"
Regex.match?(~r/^\d{4}-\d{2}-\d{2}\s*[—–-]\s*.+/, line) ->
[date_str, title] = String.split(line, ~r/\s*[—–-]\s*/, parts: 2)
Regex.match?(~r/^\d{4}-\d{2}-\d{2}\s+[—–]\s+.+/, line) ->
[date_str | rest] = String.split(line, ~r/\s+[—–]\s+/, parts: 2)
title = List.first(rest, "")
entry = %{date: Date.from_iso8601!(String.trim(date_str)), title: String.trim(title), items: []}
[entry | acc]