From b69daa7b54f36c167531b065bd5dfac32405c0c7 Mon Sep 17 00:00:00 2001 From: Thomas Citharel Date: Mon, 21 Dec 2020 15:47:26 +0100 Subject: [PATCH] Attach event ics files to event-related emails Signed-off-by: Thomas Citharel --- lib/service/export/icalendar.ex | 13 +++++++++++-- lib/web/email/email.ex | 18 +++++++++++++++++- lib/web/email/event.ex | 1 + lib/web/email/notification.ex | 1 + lib/web/email/participation.ex | 1 + mix.exs | 1 + test/service/export/icalendar_test.exs | 2 +- 7 files changed, 33 insertions(+), 4 deletions(-) diff --git a/lib/service/export/icalendar.ex b/lib/service/export/icalendar.ex index a9d06e94..90271233 100644 --- a/lib/service/export/icalendar.ex +++ b/lib/service/export/icalendar.ex @@ -3,7 +3,7 @@ defmodule Mobilizon.Service.Export.ICalendar do Export an event to iCalendar format. """ - alias Mobilizon.{Actors, Events, Users} + alias Mobilizon.{Actors, Config, Events, Users} alias Mobilizon.Actors.Actor alias Mobilizon.Addresses.Address alias Mobilizon.Events.{Event, FeedToken} @@ -11,6 +11,8 @@ defmodule Mobilizon.Service.Export.ICalendar do alias Mobilizon.Storage.Page alias Mobilizon.Users.User + @vendor "Mobilizon #{Config.instance_version()}" + @doc """ Export a public event to iCalendar format. @@ -19,12 +21,19 @@ defmodule Mobilizon.Service.Export.ICalendar do @spec export_public_event(Event.t()) :: {:ok, String.t()} def export_public_event(%Event{visibility: visibility} = event) when visibility in [:public, :unlisted] do - {:ok, %ICalendar{events: [do_export_event(event)]} |> ICalendar.to_ics(vendor: "Mobilizon")} + export_event(event) end @spec export_public_event(Event.t()) :: {:error, :event_not_public} def export_public_event(%Event{}), do: {:error, :event_not_public} + @doc """ + Export an event to iCalendar format + """ + def export_event(%Event{} = event) do + {:ok, %ICalendar{events: [do_export_event(event)]} |> ICalendar.to_ics(vendor: @vendor)} + end + @spec do_export_event(Event.t()) :: ICalendar.Event.t() defp do_export_event(%Event{} = event) do %ICalendar.Event{ diff --git a/lib/web/email/email.ex b/lib/web/email/email.ex index ac5a31e4..936503f8 100644 --- a/lib/web/email/email.ex +++ b/lib/web/email/email.ex @@ -6,7 +6,9 @@ defmodule Mobilizon.Web.Email do use Bamboo.Phoenix, view: Mobilizon.Web.EmailView alias Ecto.UUID - alias Mobilizon.Config + alias Mobilizon.{Config, Events} + alias Mobilizon.Events.Event + alias Mobilizon.Service.Export.ICalendar alias Mobilizon.Web.EmailView @spec base_email(keyword()) :: Bamboo.Email.t() @@ -40,4 +42,18 @@ defmodule Mobilizon.Web.Email do Timex.format!(DateTime.utc_now(), "{WDshort}, {D} {Mshort} {YYYY} {h24}:{m}:{s} {Z}") end end + + def add_event_attachment(%Bamboo.Email{} = email, %Event{id: event_id}) do + with {:ok, %Event{} = event} <- Events.get_event_with_preload(event_id), + {:ok, event_ics_data} <- ICalendar.export_event(event) do + put_attachment(email, %Bamboo.Attachment{ + filename: Slugger.slugify_downcase(event.title), + content_type: "text/calendar", + data: event_ics_data + }) + else + _ -> + email + end + end end diff --git a/lib/web/email/event.ex b/lib/web/email/event.ex index b7b36e48..2a34fb34 100644 --- a/lib/web/email/event.ex +++ b/lib/web/email/event.ex @@ -46,6 +46,7 @@ defmodule Mobilizon.Web.Email.Event do |> assign(:changes, changes) |> assign(:subject, subject) |> assign(:timezone, timezone) + |> Email.add_event_attachment(event) |> render(:event_updated) end diff --git a/lib/web/email/notification.ex b/lib/web/email/notification.ex index 76fd83ff..e27b13ef 100644 --- a/lib/web/email/notification.ex +++ b/lib/web/email/notification.ex @@ -30,6 +30,7 @@ defmodule Mobilizon.Web.Email.Notification do |> assign(:locale, locale) |> assign(:participant, participant) |> assign(:subject, subject) + |> Email.add_event_attachment(event) |> render(:before_event_notification) end diff --git a/lib/web/email/participation.ex b/lib/web/email/participation.ex index d3cc31ac..132c0d8a 100644 --- a/lib/web/email/participation.ex +++ b/lib/web/email/participation.ex @@ -118,6 +118,7 @@ defmodule Mobilizon.Web.Email.Participation do |> assign(:locale, locale) |> assign(:event, event) |> assign(:subject, subject) + |> Email.add_event_attachment(event) |> render(:event_participation_approved) end diff --git a/mix.exs b/mix.exs index bdd09654..5294e8c9 100644 --- a/mix.exs +++ b/mix.exs @@ -133,6 +133,7 @@ defmodule Mobilizon.Mixfile do {:xml_builder, "~> 2.1.1", override: true}, {:remote_ip, "~> 0.2.0"}, {:ex_cldr_languages, "~> 0.2.1"}, + {:slugger, "~> 0.3"}, # Dev and test dependencies {:phoenix_live_reload, "~> 1.2", only: [:dev, :e2e]}, {:ex_machina, "~> 2.3", only: [:dev, :test]}, diff --git a/test/service/export/icalendar_test.exs b/test/service/export/icalendar_test.exs index 94c17065..9d5329f0 100644 --- a/test/service/export/icalendar_test.exs +++ b/test/service/export/icalendar_test.exs @@ -17,7 +17,7 @@ defmodule Mobilizon.Service.ICalendarTest do BEGIN:VCALENDAR CALSCALE:GREGORIAN VERSION:2.0 - PRODID:-//ICalendar//Mobilizon//EN + PRODID:-//ICalendar//Mobilizon #{Mobilizon.Config.instance_version()}//EN BEGIN:VEVENT CATEGORIES:#{event.tags |> Enum.map(& &1.title) |> Enum.join(",")} DESCRIPTION:Ceci est une description avec une première phrase assez longue\\,\\n puis sur une seconde ligne