Skip to content

Commit

Permalink
Add fantasy league calendar download
Browse files Browse the repository at this point in the history
  • Loading branch information
axelclark committed Oct 6, 2024
1 parent 045640d commit 4e642b4
Show file tree
Hide file tree
Showing 6 changed files with 212 additions and 0 deletions.
69 changes: 69 additions & 0 deletions lib/ex338/fantasy_leagues.ex
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ defmodule Ex338.FantasyLeagues do

import Ecto.Query

alias Ex338.Championships
alias Ex338.Championships.Championship
alias Ex338.Chats
alias Ex338.DraftPicks
Expand Down Expand Up @@ -187,4 +188,72 @@ defmodule Ex338.FantasyLeagues do

Repo.one(query)
end

def generate_calendar(fantasy_league_id) do
fantasy_league = get(fantasy_league_id)
dues_due_date = generate_dues_deadline(fantasy_league)

championships =
fantasy_league_id
|> Championships.all_for_league()
|> generate_events_for_championships()

events =
[dues_due_date | championships]

events
|> Enum.map(&add_uid_and_dtstamp/1)
|> Ex338.ICalendar.to_ics()
end

defp generate_dues_deadline(fantasy_league) do
%Ex338.ICalendar.Event{
summary: "Deadline to submit entry fee for The 338 Challenge",
dtstart: Date.new!(fantasy_league.championships_start_at.year, 11, 1)
}
end

defp generate_events_for_championships(championships) do
Enum.flat_map(championships, &generate_events_for_championship/1)
end

defp generate_events_for_championship(championship) do
%{
trade_deadline_at: trade_deadline_at,
waiver_deadline_at: waiver_deadline_at,
championship_at: championship_at
} = championship

championship_date =
%Ex338.ICalendar.Event{
summary: "338 Championship: #{championship.title}",
dtstart: DateTime.to_date(championship_at)
}

if DateTime.compare(trade_deadline_at, waiver_deadline_at) == :eq do
[
%Ex338.ICalendar.Event{
summary: "#{championship.title} 338 Waiver and Trade Deadline",
dtstart: DateTime.to_date(championship.waiver_deadline_at)
},
championship_date
]
else
[
%Ex338.ICalendar.Event{
summary: "#{championship.title} 338 Waiver Deadline",
dtstart: DateTime.to_date(championship.waiver_deadline_at)
},
%Ex338.ICalendar.Event{
summary: "#{championship.title} 338 Trade Deadline",
dtstart: DateTime.to_date(championship.trade_deadline_at)
},
championship_date
]
end
end

defp add_uid_and_dtstamp(event) do
%{event | uid: Ecto.UUID.generate(), dtstamp: DateTime.utc_now()}
end
end
73 changes: 73 additions & 0 deletions lib/ex338/icalendar.ex
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
defmodule Ex338.ICalendar do
@moduledoc false

defmodule Event do
@moduledoc false
defstruct summary: nil,
dtstart: nil,
dtend: nil,
dtstamp: nil,
description: nil,
uid: nil
end

def to_ics(events) when is_list(events) do
events = Enum.map(events, &to_ics/1)

"""
BEGIN:VCALENDAR
CALSCALE:GREGORIAN
VERSION:2.0
PRODID:-//Ex338 ICalendar//EN
#{events}END:VCALENDAR
"""
end

def to_ics(event) do
contents = to_kvs(event)

"""
BEGIN:VEVENT
#{contents}END:VEVENT
"""
end

defp to_kvs(event) do
event
|> Map.from_struct()
|> Enum.map(&to_kv/1)
|> List.flatten()
|> Enum.sort()
|> Enum.join()
end

defp to_kv({key, value}) do
name =
key
|> to_string()
|> String.upcase()

build(name, value)
end

def build(_key, nil) do
""
end

def build(key, %Date{} = date) do
"#{key}:#{Date.to_iso8601(date, :basic)}\n"
end

def build(key, %DateTime{} = datetime) do
datetime =
datetime
|> DateTime.truncate(:second)
|> DateTime.to_iso8601(:basic)

"#{key}:#{datetime}\n"
end

def build(key, value) do
"#{key}:#{value}\n"
end
end
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
defmodule Ex338Web.FantasyLeague.CalendarDownloadController do
use Ex338Web, :controller

alias Ex338.FantasyLeagues

def show(conn, %{"fantasy_league_id" => fantasy_league_id}) do
calendar = FantasyLeagues.generate_calendar(fantasy_league_id)

send_download(
conn,
{:binary, calendar},
content_type: "text/calendar",
filename: "338_calendar.ics"
)
end
end
27 changes: 27 additions & 0 deletions lib/ex338_web/live/fantasy_league_live/show.ex
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,9 @@ defmodule Ex338Web.FantasyLeagueLive.Show do
</div>
</div>
</div>
<div class="pb-6">
<.calendar_download fantasy_league={@fantasy_league} />
</div>
</div>
<.live_component
module={Ex338Web.FantasyLeagueLive.StandingsChartComponent}
Expand All @@ -101,4 +104,28 @@ defmodule Ex338Web.FantasyLeagueLive.Show do
</div>
"""
end

defp calendar_download(assigns) do
~H"""
<div class="border-b border-gray-200 bg-white px-4 py-5 sm:px-6 shadow sm:rounded-lg">
<div class="-ml-4 -mt-4 flex flex-wrap items-center justify-between sm:flex-nowrap">
<div class="ml-4 mt-4">
<h3 class="text-base font-semibold leading-6 text-gray-900">Download League Calendar</h3>
<p class="mt-1 text-sm text-gray-500">
Download an ICS file to add key dates to your calendar. These are all-day events, so
you'll need to check the championships page for the specific deadline times.
</p>
</div>
<div class="ml-4 mt-4 flex-shrink-0">
<.link
href={~p"/fantasy_leagues/#{@fantasy_league.id}/calendar_download"}
class="w-full relative inline-flex items-center rounded-md bg-indigo-600 px-3 py-2 text-sm font-semibold text-white shadow-sm hover:bg-indigo-500 focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-indigo-600"
>
Download
</.link>
</div>
</div>
</div>
"""
end
end
1 change: 1 addition & 0 deletions lib/ex338_web/router.ex
Original file line number Diff line number Diff line change
Expand Up @@ -105,6 +105,7 @@ defmodule Ex338Web.Router do
resources("/waivers", WaiverController, only: [:index])
resources("/trades", TradeController, only: [:index])
resources("/injured_reserves", InjuredReserveController, only: [:index])
get("/calendar_download", FantasyLeague.CalendarDownloadController, :show)
end

resources("/archived_leagues", ArchivedLeagueController, only: [:index])
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
defmodule Ex338Web.FantasyLeague.CalendarDownloadTest do
use Ex338Web.ConnCase

setup :register_and_log_in_user

describe "get/2" do
test "allows a user to download the calendar of events for a fantasy league", %{conn: conn} do
fantasy_league = insert(:fantasy_league, year: 2017)
sports_league = insert(:sports_league)
insert(:league_sport, fantasy_league: fantasy_league, sports_league: sports_league)
insert(:league_sport, fantasy_league: fantasy_league, sports_league: sports_league)
championship = insert(:championship, sports_league: sports_league)

_championship_event =
insert(:championship,
sports_league: sports_league,
overall: championship,
category: "event"
)

conn = get(conn, ~p"/fantasy_leagues/#{fantasy_league.id}/calendar_download")

assert response_content_type(conn, :ics)
end
end
end

0 comments on commit 4e642b4

Please sign in to comment.