Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix: Handle platform closures #2107

Merged
merged 32 commits into from
Jul 18, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
32 commits
Select commit Hold shift + click to select a range
b4d70a9
Added field to struct.
cmaddox5 Jul 3, 2024
4e4410d
Added fetch for all platform IDs at a station.
cmaddox5 Jul 3, 2024
57c3c0d
Added edge cases so widgets can handle single platform closures.
cmaddox5 Jul 3, 2024
2926d70
Added PreFare alert tests.
cmaddox5 Jul 3, 2024
f1bb921
Added SubwayStatus tests.
cmaddox5 Jul 3, 2024
c1b1e08
Credo.
cmaddox5 Jul 3, 2024
58bcfc7
Fixed check so function can be used by WidgetInstances.
cmaddox5 Jul 8, 2024
28ac71f
Fixed platform closure logic for SubwayStatus.
cmaddox5 Jul 8, 2024
cdaa97f
Name changes.
cmaddox5 Jul 8, 2024
c54d518
Refactor to pattern match
cmaddox5 Jul 9, 2024
220c610
Changed reject to filter.
cmaddox5 Jul 9, 2024
b6f0a66
Formatting.
cmaddox5 Jul 9, 2024
0b057cb
Fixed route selection for station closures at JFK.
cmaddox5 Jul 10, 2024
d5275ba
Added cldr_messages to help with pluralizing strings.
cmaddox5 Jul 10, 2024
2af409e
Pluralized strings.
cmaddox5 Jul 10, 2024
038742c
Added more tests.
cmaddox5 Jul 10, 2024
8ca4e97
Merge branch 'main' into cm/alert-handle-platform-closure
cmaddox5 Jul 10, 2024
0973d2d
Fixed platform names.
cmaddox5 Jul 10, 2024
a010dfd
Changed how we determine if ie is for a subway platform.
cmaddox5 Jul 12, 2024
288958a
Fixed tests.
cmaddox5 Jul 12, 2024
3296956
Added platform support for GL.
cmaddox5 Jul 16, 2024
11613b6
Use existing function.
cmaddox5 Jul 16, 2024
9f72d40
No single pipes.
cmaddox5 Jul 16, 2024
ed575ed
Exclude partial closures from dual_screen_alert?.
cmaddox5 Jul 16, 2024
d8fd5a5
Added typespecs.
cmaddox5 Jul 16, 2024
02e7fbd
Added a struct to describe alerts WidgetInstance.SubwayStatus expects.
cmaddox5 Jul 16, 2024
286a0a7
Added provider so we don't see warnings.
cmaddox5 Jul 16, 2024
cd4a08a
Moved partial closure logic to CG.
cmaddox5 Jul 17, 2024
112d98b
Added a comment.
cmaddox5 Jul 17, 2024
0876ad6
Added better type.
cmaddox5 Jul 18, 2024
776f822
Fixed default.
cmaddox5 Jul 18, 2024
efe032a
Merge branch 'main' into cm/alert-handle-platform-closure
cmaddox5 Jul 18, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions config/config.exs
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,11 @@ config :ueberauth, Ueberauth,
keycloak: nil
]

config :ex_cldr,
default_locale: "en",
default_backend: Screens.Cldr,
json_library: Jason

config :screens,
gds_dms_username: "[email protected]",
config_fetcher: Screens.Config.Fetch.S3,
Expand Down
29 changes: 29 additions & 0 deletions lib/screens/alerts/alert.ex
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
defmodule Screens.Alerts.Alert do
@moduledoc false

alias Screens.Alerts.InformedEntity
alias Screens.Routes.Route
alias Screens.RouteType
alias Screens.Stops.Stop
Expand Down Expand Up @@ -592,4 +593,32 @@ defmodule Screens.Alerts.Alert do

def direction_id(%__MODULE__{informed_entities: informed_entities}),
do: List.first(informed_entities).direction_id

def informed_parent_stations(%__MODULE__{
informed_entities: informed_entities
}) do
Enum.filter(informed_entities, &InformedEntity.parent_station?/1)
end

# Although Alerts UI allows you to create partial closures affecting multiple stations,
# we are assuming that will never happen.
@spec is_partial_station_closure?(__MODULE__.t(), list(Stop.t())) :: boolean()
def is_partial_station_closure?(
%__MODULE__{effect: :station_closure, informed_entities: informed_entities} = alert,
all_platforms_at_informed_station
) do
informed_parent_stations = informed_parent_stations(alert)

case informed_parent_stations do
[_] ->
platform_ids = Enum.map(all_platforms_at_informed_station, & &1.id)
informed_platforms = Enum.filter(informed_entities, &(&1.stop in platform_ids))
length(informed_platforms) != length(all_platforms_at_informed_station)

_ ->
false
end
end

def is_partial_station_closure?(_, _), do: false
end
13 changes: 13 additions & 0 deletions lib/screens/cldr.ex
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
defmodule Screens.Cldr do
@moduledoc """
Define a backend module that will host our
Cldr configuration and public API.
Most function calls in Cldr will be calls
to functions on this module.
"""
use Cldr,
locales: ["en"],
default_locale: "en",
providers: [Cldr.Number]
end
9 changes: 7 additions & 2 deletions lib/screens/stops/parser.ex
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,17 @@ defmodule Screens.Stops.Parser do

def parse_stop(%{
"id" => id,
"attributes" => %{"name" => name, "platform_code" => platform_code}
"attributes" => %{
"name" => name,
"platform_code" => platform_code,
"platform_name" => platform_name
}
}) do
%Screens.Stops.Stop{
id: id,
name: name,
platform_code: platform_code
platform_code: platform_code,
platform_name: platform_name
}
end
end
24 changes: 21 additions & 3 deletions lib/screens/stops/stop.ex
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ defmodule Screens.Stops.Stop do

alias Screens.LocationContext
alias Screens.RoutePatterns.RoutePattern
alias Screens.Routes
alias Screens.{Routes, Stops}
alias Screens.Routes.Route
alias Screens.RouteType
alias Screens.Stops.StationsWithRoutesAgent
Expand All @@ -22,14 +22,16 @@ defmodule Screens.Stops.Stop do

defstruct id: nil,
name: nil,
platform_code: nil
platform_code: nil,
platform_name: nil

@type id :: String.t()

@type t :: %__MODULE__{
id: id,
name: String.t(),
platform_code: String.t() | nil
platform_code: String.t() | nil,
platform_name: String.t() | nil
}

@type screen_type :: BusEink | BusShelter | GlEink | PreFare | Dup | Triptych
Expand Down Expand Up @@ -361,6 +363,22 @@ defmodule Screens.Stops.Stop do
end
end

def fetch_subway_platforms_for_stop(stop_id) do
case Screens.V3Api.get_json("stops/" <> stop_id, %{"include" => "child_stops"}) do
{:ok, %{"included" => child_stop_data}} ->
child_stop_data
|> Enum.filter(fn %{
"attributes" => %{
"location_type" => location_type,
"vehicle_type" => vehicle_type
}
} ->
location_type == 0 and vehicle_type in [0, 1]
end)
|> Enum.map(&Stops.Parser.parse_stop/1)
end
end

# --- END API functions ---

def stop_on_route?(stop_id, stop_sequence) when not is_nil(stop_id) do
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,8 @@ defmodule Screens.V2.CandidateGenerator.Widgets.ReconstructedAlert do
now \\ DateTime.utc_now(),
fetch_alerts_fn \\ &Alert.fetch/1,
fetch_stop_name_fn \\ &Stop.fetch_stop_name/1,
fetch_location_context_fn \\ &Stop.fetch_location_context/3
fetch_location_context_fn \\ &Stop.fetch_location_context/3,
fetch_subway_platforms_for_stop_fn \\ &Stop.fetch_subway_platforms_for_stop/1
) do
%PreFare{
reconstructed_alert_widget: %CurrentStopId{stop_id: stop_id}
Expand All @@ -75,7 +76,8 @@ defmodule Screens.V2.CandidateGenerator.Widgets.ReconstructedAlert do
location_context: location_context,
fetch_stop_name_fn: fetch_stop_name_fn,
is_terminal_station: is_terminal_station,
now: now
now: now,
fetch_subway_platforms_for_stop_fn: fetch_subway_platforms_for_stop_fn
]

cond do
Expand Down Expand Up @@ -157,21 +159,42 @@ defmodule Screens.V2.CandidateGenerator.Widgets.ReconstructedAlert do
location_context: location_context,
fetch_stop_name_fn: fetch_stop_name_fn,
is_terminal_station: is_terminal_station,
now: now
now: now,
fetch_subway_platforms_for_stop_fn: fetch_subway_platforms_for_stop_fn
) do
Enum.map(alerts, fn alert ->
all_platforms_names_at_informed_station =
get_platform_names_at_informed_station(alert, fetch_subway_platforms_for_stop_fn)

%ReconstructedAlert{
screen: config,
alert: alert,
now: now,
location_context: location_context,
informed_stations: get_stations(alert, fetch_stop_name_fn),
is_terminal_station: is_terminal_station,
is_full_screen: is_full_screen
is_full_screen: is_full_screen,
partial_closure_platform_names: all_platforms_names_at_informed_station
}
end)
end

defp get_platform_names_at_informed_station(
%Alert{effect: :station_closure, informed_entities: informed_entities} = alert,
fetch_subway_platforms_for_stop_fn
) do
with [informed_parent_station] <- Alert.informed_parent_stations(alert),
platforms <- fetch_subway_platforms_for_stop_fn.(informed_parent_station.stop),
true <- Alert.is_partial_station_closure?(alert, platforms) do
informed_stop_ids = Enum.map(informed_entities, & &1.stop)
platforms |> Enum.filter(&(&1.id in informed_stop_ids)) |> Enum.map(& &1.platform_name)
else
_ -> []
end
end

defp get_platform_names_at_informed_station(_, _), do: []

defp find_closest_downstream_alerts(alerts, stop_id, stop_sequences) do
home_stop_distance_map = build_distance_map(stop_id, stop_sequences)
# Map each alert with its distance from home.
Expand Down
38 changes: 35 additions & 3 deletions lib/screens/v2/candidate_generator/widgets/subway_status.ex
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,23 @@ defmodule Screens.V2.CandidateGenerator.Widgets.SubwayStatus do
@moduledoc false

alias Screens.Alerts.Alert
alias Screens.Stops.Stop
alias Screens.V2.WidgetInstance.SubwayStatus

def subway_status_instances(config, now \\ DateTime.utc_now()) do
def subway_status_instances(
config,
now \\ DateTime.utc_now(),
fetch_subway_platforms_for_stop_fn \\ &Stop.fetch_subway_platforms_for_stop/1
) do
route_ids = ["Blue", "Orange", "Red", "Green-B", "Green-C", "Green-D", "Green-E"]

case Screens.Alerts.Alert.fetch(route_ids: route_ids) do
{:ok, alerts} ->
relevant_alerts = Enum.filter(alerts, &relevant?(&1, now))
relevant_alerts =
alerts
|> Enum.filter(&relevant?(&1, now))
|> Enum.map(&append_context(&1, fetch_subway_platforms_for_stop_fn))

[%SubwayStatus{screen: config, subway_alerts: relevant_alerts}]

:error ->
Expand All @@ -27,5 +36,28 @@ defmodule Screens.V2.CandidateGenerator.Widgets.SubwayStatus do
defp relevant_effect?(%Alert{effect: effect}),
do: effect in [:suspension, :shuttle, :station_closure]

defp suppressed?(alert), do: alert.id == "529291"
defp suppressed?(_alert), do: false

defp append_context(
%Alert{effect: :station_closure} = alert,
fetch_subway_platforms_for_stop_fn
) do
informed_parent_stations = Alert.informed_parent_stations(alert)

all_platforms_at_informed_station =
case informed_parent_stations do
[informed_parent_station] ->
fetch_subway_platforms_for_stop_fn.(informed_parent_station.stop)

_ ->
[]
end

%SubwayStatus.SubwayStatusAlert{
alert: alert,
context: %{all_platforms_at_informed_station: all_platforms_at_informed_station}
}
end

defp append_context(alert, _), do: struct(SubwayStatus.SubwayStatusAlert, alert: alert)
digitalcora marked this conversation as resolved.
Show resolved Hide resolved
end
Loading
Loading