defmodule Shift73kWeb.UserShiftsCsvController do use Shift73kWeb, :controller alias Shift73k.Shifts alias Shift73k.Shifts.Shift def new(conn, _params) do render(conn, "new.html", page_title: "CSV Export") end def export(conn, %{"csv_export" => request_params}) do case Map.get(request_params, "user_id") == conn.assigns.current_user.id do true -> export_csv(conn, request_params) false -> conn |> put_flash(:danger, "Unauthorized CSV export request") |> redirect(to: "/") |> halt() end end defp export_csv(conn, %{"date_min" => date_min, "date_max" => date_max}) do date_range = Date.range(Date.from_iso8601!(date_min), Date.from_iso8601!(date_max)) csv_content = build_csv_content(conn.assigns.current_user.id, date_range) filename_dt = DateTime.utc_now() |> Calendar.strftime("%Y%m%dT%H%M%S") filename = "#{conn.assigns.current_user.id}_#{filename_dt}.csv" conn |> put_resp_content_type("text/csv") |> put_resp_header("content-disposition", "attachment; filename=\"#{filename}\"") |> send_resp(200, csv_content) end def build_csv_content(user_id, date_range) do [csv_headers() | csv_data(user_id, date_range)] |> NimbleCSV.RFC4180.dump_to_iodata() |> to_string() end def csv_data(user_id, date_range) do user_id |> Shifts.list_shifts_by_user_in_date_range(date_range) |> Enum.map(&csv_shift_row/1) end def csv_headers do [ "Subject", "Start Date", "Start Time", "End Date", "End Time", "All Day Event", "Description", "Location", "Private" ] end defp csv_shift_row(%Shift{} = s) do dt_start = DateTime.new!(s.date, s.time_start, s.time_zone) shift_length_s = Shifts.shift_length(s) * 60 dt_end = DateTime.add(dt_start, shift_length_s) [ s.subject, csv_date_string(dt_start), csv_time_string(dt_start), csv_date_string(dt_end), csv_time_string(dt_end), false, s.description, s.location, false ] end defp csv_date_string(%DateTime{} = dt) do dt |> DateTime.to_date() |> Calendar.strftime("%m/%d/%Y") end defp csv_time_string(%DateTime{} = dt) do dt |> DateTime.to_time() |> Calendar.strftime("%-I:%M %p") end end