From 888c1e3b146d832c2fe038e312e6bb8714fa72b7 Mon Sep 17 00:00:00 2001 From: Thomas Citharel Date: Wed, 3 Apr 2019 15:58:57 +0200 Subject: [PATCH 1/4] Add DTSTAMP support It's a required attribute Signed-off-by: Thomas Citharel --- lib/icalendar/event.ex | 1 + lib/icalendar/util/deserialize.ex | 8 +++++ lib/icalendar/util/kv.ex | 4 +++ test/icalendar/deserialize_test.exs | 2 ++ test/icalendar/event_test.exs | 54 ++++++++++++++++++++++------- test/icalendar_test.exs | 48 +++++++++++++++++++++++++ 6 files changed, 104 insertions(+), 13 deletions(-) diff --git a/lib/icalendar/event.ex b/lib/icalendar/event.ex index 315c757..db3982c 100644 --- a/lib/icalendar/event.ex +++ b/lib/icalendar/event.ex @@ -8,6 +8,7 @@ defmodule ICalendar.Event do dtend: nil, rrule: nil, exdates: [], + dtstamp: nil, description: nil, location: nil, url: nil, diff --git a/lib/icalendar/util/deserialize.ex b/lib/icalendar/util/deserialize.ex index ec65ea4..2733a84 100644 --- a/lib/icalendar/util/deserialize.ex +++ b/lib/icalendar/util/deserialize.ex @@ -91,6 +91,14 @@ defmodule ICalendar.Util.Deserialize do %{acc | dtend: timestamp} end + def parse_attr( + %Property{key: "DTSTAMP", value: dtstamp, params: params}, + acc + ) do + {:ok, timestamp} = to_date(dtstamp, params) + %{acc | dtstamp: timestamp} + end + def parse_attr( %Property{key: "RRULE", value: rrule}, acc diff --git a/lib/icalendar/util/kv.ex b/lib/icalendar/util/kv.ex index 81abb41..6f9023b 100644 --- a/lib/icalendar/util/kv.ex +++ b/lib/icalendar/util/kv.ex @@ -37,6 +37,10 @@ defmodule ICalendar.Util.KV do "ATTENDEE;CN=James SM;PARTSTAT=ACCEPTED:mailto:james@clockk.com\n" """ + def build("DTSTAMP", nil) do + "DTSTAMP:#{Value.to_ics(DateTime.utc_now())}Z\n" + end + def build(_, nil) do "" end diff --git a/test/icalendar/deserialize_test.exs b/test/icalendar/deserialize_test.exs index 5fcd87d..0f8fbbd 100644 --- a/test/icalendar/deserialize_test.exs +++ b/test/icalendar/deserialize_test.exs @@ -11,6 +11,7 @@ defmodule ICalendar.DeserializeTest do COMMENT:Don't forget to take something to eat ! SUMMARY:Going fishing DTEND:20151224T084500Z + DTSTAMP:20151224T080000Z DTSTART:20151224T083000Z LOCATION:123 Fun Street\\, Toronto ON\\, Canada STATUS:TENTATIVE @@ -25,6 +26,7 @@ defmodule ICalendar.DeserializeTest do assert event == %Event{ dtstart: Timex.to_datetime({{2015, 12, 24}, {8, 30, 0}}), dtend: Timex.to_datetime({{2015, 12, 24}, {8, 45, 0}}), + dtstamp: Timex.to_datetime({{2015, 12, 24}, {8, 00, 0}}), summary: "Going fishing", description: "Escape from the world. Stare at some water.", location: "123 Fun Street, Toronto ON, Canada", diff --git a/test/icalendar/event_test.exs b/test/icalendar/event_test.exs index 7b173f7..e14e0ba 100644 --- a/test/icalendar/event_test.exs +++ b/test/icalendar/event_test.exs @@ -4,10 +4,11 @@ defmodule ICalendar.EventTest do alias ICalendar.Event test "ICalendar.to_ics/1 of event" do - ics = %Event{} |> ICalendar.to_ics() + ics = %Event{dtstamp: Timex.to_datetime({{2015, 12, 24}, {8, 45, 00}})} |> ICalendar.to_ics() assert ics == """ BEGIN:VEVENT + DTSTAMP:20151224T084500Z END:VEVENT """ end @@ -17,7 +18,8 @@ defmodule ICalendar.EventTest do %Event{ summary: "Going fishing", description: "Escape from the world. Stare at some water.", - comment: "Don't forget to take something to eat !" + comment: "Don't forget to take something to eat !", + dtstamp: Timex.to_datetime({{2015, 12, 24}, {8, 45, 00}}) } |> ICalendar.to_ics() @@ -25,6 +27,7 @@ defmodule ICalendar.EventTest do BEGIN:VEVENT COMMENT:Don't forget to take something to eat ! DESCRIPTION:Escape from the world. Stare at some water. + DTSTAMP:20151224T084500Z SUMMARY:Going fishing END:VEVENT """ @@ -34,13 +37,15 @@ defmodule ICalendar.EventTest do ics = %Event{ dtstart: Timex.to_date({2015, 12, 24}), - dtend: Timex.to_date({2015, 12, 24}) + dtend: Timex.to_date({2015, 12, 24}), + dtstamp: Timex.to_datetime({{2015, 12, 24}, {8, 45, 00}}) } |> ICalendar.to_ics() assert ics == """ BEGIN:VEVENT DTEND:20151224 + DTSTAMP:20151224T084500Z DTSTART:20151224 END:VEVENT """ @@ -50,13 +55,15 @@ defmodule ICalendar.EventTest do ics = %Event{ dtstart: Timex.to_datetime({{2015, 12, 24}, {8, 30, 00}}), - dtend: Timex.to_datetime({{2015, 12, 24}, {8, 45, 00}}) + dtend: Timex.to_datetime({{2015, 12, 24}, {8, 45, 00}}), + dtstamp: Timex.to_datetime({{2015, 12, 24}, {8, 45, 00}}) } |> ICalendar.to_ics() assert ics == """ BEGIN:VEVENT DTEND:20151224T084500Z + DTSTAMP:20151224T084500Z DTSTART:20151224T083000Z END:VEVENT """ @@ -72,12 +79,17 @@ defmodule ICalendar.EventTest do |> Timex.to_datetime("America/Chicago") ics = - %Event{dtstart: dtstart, dtend: dtend} + %Event{ + dtstart: dtstart, + dtend: dtend, + dtstamp: Timex.to_datetime({{2015, 12, 24}, {8, 45, 00}}) + } |> ICalendar.to_ics() assert ics == """ BEGIN:VEVENT DTEND;TZID=America/Chicago:20151224T084500 + DTSTAMP:20151224T084500Z DTSTART;TZID=America/Chicago:20151224T083000 END:VEVENT """ @@ -89,13 +101,15 @@ defmodule ICalendar.EventTest do summary: "Going fishing", description: "See this link http://example.com/pub" <> - "/calendars/jsmith/mytime.ics" + "/calendars/jsmith/mytime.ics", + dtstamp: Timex.to_datetime({{2015, 12, 24}, {8, 45, 00}}) } |> ICalendar.to_ics() assert ics == """ BEGIN:VEVENT DESCRIPTION:See this link http://example.com/pub/calendars/jsmith/mytime.ics + DTSTAMP:20151224T084500Z SUMMARY:Going fishing END:VEVENT """ @@ -104,12 +118,14 @@ defmodule ICalendar.EventTest do test "ICalendar.to_ics/1 with url" do ics = %Event{ - url: "http://example.com/pub/calendars/jsmith/mytime.ics" + url: "http://example.com/pub/calendars/jsmith/mytime.ics", + dtstamp: Timex.to_datetime({{2015, 12, 24}, {8, 45, 00}}) } |> ICalendar.to_ics() assert ics == """ BEGIN:VEVENT + DTSTAMP:20151224T084500Z URL:http://example.com/pub/calendars/jsmith/mytime.ics END:VEVENT """ @@ -118,12 +134,14 @@ defmodule ICalendar.EventTest do test "ICalendar.to_ics/1 with integer UID" do ics = %Event{ - uid: 815 + uid: 815, + dtstamp: Timex.to_datetime({{2015, 12, 24}, {8, 45, 00}}) } |> ICalendar.to_ics() assert ics == """ BEGIN:VEVENT + DTSTAMP:20151224T084500Z UID:815 END:VEVENT """ @@ -132,12 +150,14 @@ defmodule ICalendar.EventTest do test "ICalendar.to_ics/1 with string UID" do ics = %Event{ - uid: "0815" + uid: "0815", + dtstamp: Timex.to_datetime({{2015, 12, 24}, {8, 45, 00}}) } |> ICalendar.to_ics() assert ics == """ BEGIN:VEVENT + DTSTAMP:20151224T084500Z UID:0815 END:VEVENT """ @@ -146,12 +166,14 @@ defmodule ICalendar.EventTest do test "ICalendar.to_ics/1 with geo" do ics = %Event{ - geo: {43.6978819, -79.3810277} + geo: {43.6978819, -79.3810277}, + dtstamp: Timex.to_datetime({{2015, 12, 24}, {8, 45, 00}}) } |> ICalendar.to_ics() assert ics == """ BEGIN:VEVENT + DTSTAMP:20151224T084500Z GEO:43.6978819;-79.3810277 END:VEVENT """ @@ -160,13 +182,15 @@ defmodule ICalendar.EventTest do test "ICalendar.to_ics/1 with categories" do ics = %Event{ - categories: ["Fishing", "Nature", "Sport"] + categories: ["Fishing", "Nature", "Sport"], + dtstamp: Timex.to_datetime({{2015, 12, 24}, {8, 45, 00}}) } |> ICalendar.to_ics() assert ics == """ BEGIN:VEVENT CATEGORIES:Fishing,Nature,Sport + DTSTAMP:20151224T084500Z END:VEVENT """ end @@ -174,12 +198,14 @@ defmodule ICalendar.EventTest do test "ICalendar.to_ics/1 with status" do ics = %Event{ - status: :tentative + status: :tentative, + dtstamp: Timex.to_datetime({{2015, 12, 24}, {8, 45, 00}}) } |> ICalendar.to_ics() assert ics == """ BEGIN:VEVENT + DTSTAMP:20151224T084500Z STATUS:TENTATIVE END:VEVENT """ @@ -188,13 +214,15 @@ defmodule ICalendar.EventTest do test "ICalendar.to_ics/1 with class" do ics = %Event{ - class: :private + class: :private, + dtstamp: Timex.to_datetime({{2015, 12, 24}, {8, 45, 00}}) } |> ICalendar.to_ics() assert ics == """ BEGIN:VEVENT CLASS:PRIVATE + DTSTAMP:20151224T084500Z END:VEVENT """ end diff --git a/test/icalendar_test.exs b/test/icalendar_test.exs index 74c43dc..92b29e6 100644 --- a/test/icalendar_test.exs +++ b/test/icalendar_test.exs @@ -32,12 +32,14 @@ defmodule ICalendarTest do %ICalendar.Event{ summary: "Film with Amy and Adam", dtstart: Timex.to_datetime({{2015, 12, 24}, {8, 30, 00}}), + dtstamp: Timex.to_datetime({{2015, 12, 23}, {19, 00, 00}}), dtend: Timex.to_datetime({{2015, 12, 24}, {8, 45, 00}}), description: "Let's go see Star Wars." }, %ICalendar.Event{ summary: "Morning meeting", dtstart: Timex.to_datetime({{2015, 12, 24}, {19, 00, 00}}), + dtstamp: Timex.to_datetime({{2015, 12, 24}, {15, 00, 00}}), dtend: Timex.to_datetime({{2015, 12, 24}, {22, 30, 00}}), description: "A big long meeting with lots of details." } @@ -53,12 +55,14 @@ defmodule ICalendarTest do BEGIN:VEVENT DESCRIPTION:Let's go see Star Wars. DTEND:20151224T084500Z + DTSTAMP:20151223T190000Z DTSTART:20151224T083000Z SUMMARY:Film with Amy and Adam END:VEVENT BEGIN:VEVENT DESCRIPTION:A big long meeting with lots of details. DTEND:20151224T223000Z + DTSTAMP:20151224T150000Z DTSTART:20151224T190000Z SUMMARY:Morning meeting END:VEVENT @@ -71,6 +75,7 @@ defmodule ICalendarTest do %ICalendar.Event{ summary: "Film with Amy and Adam", dtstart: Timex.to_datetime({{2015, 12, 24}, {8, 30, 00}}), + dtstamp: Timex.to_datetime({{2015, 12, 24}, {8, 00, 00}}), dtend: Timex.to_datetime({{2015, 12, 24}, {8, 45, 00}}), description: "Let's go see Star Wars, and have fun.", location: "123 Fun Street, Toronto ON, Canada" @@ -87,6 +92,7 @@ defmodule ICalendarTest do BEGIN:VEVENT DESCRIPTION:Let's go see Star Wars\\, and have fun. DTEND:20151224T084500Z + DTSTAMP:20151224T080000Z DTSTART:20151224T083000Z LOCATION:123 Fun Street\\, Toronto ON\\, Canada SUMMARY:Film with Amy and Adam @@ -100,6 +106,7 @@ defmodule ICalendarTest do %ICalendar.Event{ summary: "Film with Amy and Adam", dtstart: Timex.to_datetime({{2015, 12, 24}, {8, 30, 00}}), + dtstamp: Timex.to_datetime({{2015, 12, 24}, {8, 00, 00}}), dtend: Timex.to_datetime({{2015, 12, 24}, {8, 45, 00}}), description: "Let's go see Star Wars, and have fun.", location: "123 Fun Street, Toronto ON, Canada", @@ -117,6 +124,7 @@ defmodule ICalendarTest do BEGIN:VEVENT DESCRIPTION:Let's go see Star Wars\\, and have fun. DTEND:20151224T084500Z + DTSTAMP:20151224T080000Z DTSTART:20151224T083000Z LOCATION:123 Fun Street\\, Toronto ON\\, Canada SUMMARY:Film with Amy and Adam @@ -129,6 +137,7 @@ defmodule ICalendarTest do test "Icalender.to_ics/1 with rrule and exdates" do events = [ %ICalendar.Event{ + dtstamp: Timex.to_datetime({{2015, 12, 24}, {8, 00, 00}}), rrule: %{ byday: ["TH", "WE"], freq: "WEEKLY", @@ -153,6 +162,7 @@ defmodule ICalendarTest do VERSION:2.0 PRODID:-//Elixir ICalendar//Elixir ICalendar//EN BEGIN:VEVENT + DTSTAMP:20151224T080000Z EXDATE;TZID=America/Toronto:20200916T143000 EXDATE;TZID=America/Toronto:20200917T143000 RRULE:FREQ=WEEKLY;BYDAY=TH,WE;BYSETPOS=-1;INTERVAL=-2;UNTIL=20201204T045959 @@ -161,11 +171,40 @@ defmodule ICalendarTest do """ end + test "Icalender.to_ics/1 with default value for DTSTAMP" do + events = [ + %ICalendar.Event{ + summary: "Film with Amy and Adam", + dtstart: Timex.to_datetime({{2015, 12, 24}, {8, 30, 00}}), + dtend: Timex.to_datetime({{2015, 12, 24}, {8, 45, 00}}), + description: "Let's go see Star Wars, and have fun." + } + ] + + ics = %ICalendar{events: events} |> ICalendar.to_ics() + + assert ics == """ + BEGIN:VCALENDAR + CALSCALE:GREGORIAN + VERSION:2.0 + PRODID:-//Elixir ICalendar//Elixir ICalendar//EN + BEGIN:VEVENT + DESCRIPTION:Let's go see Star Wars\\, and have fun. + DTEND:20151224T084500Z + DTSTAMP:#{ICalendar.Value.to_ics(DateTime.utc_now())}Z + DTSTART:20151224T083000Z + SUMMARY:Film with Amy and Adam + END:VEVENT + END:VCALENDAR + """ + end + test "ICalender.to_ics/1 -> ICalendar.from_ics/1 and back again" do events = [ %ICalendar.Event{ summary: "Film with Amy and Adam", dtstart: Timex.to_datetime({{2015, 12, 24}, {8, 30, 00}}), + dtstamp: Timex.to_datetime({{2015, 12, 24}, {8, 00, 00}}), dtend: Timex.to_datetime({{2015, 12, 24}, {8, 45, 00}}), description: "Let's go see Star Wars, and have fun.", location: "123 Fun Street, Toronto ON, Canada", @@ -187,6 +226,7 @@ defmodule ICalendarTest do summary: "Film with Amy and Adam", dtstart: Timex.to_datetime({{2015, 12, 24}, {8, 30, 00}}), dtend: Timex.to_datetime({{2015, 12, 24}, {8, 45, 00}}), + dtstamp: Timex.to_datetime({{2017, 12, 24}, {8, 00, 00}}), description: "First line\nThis is a new line\n\nDouble newline", location: "123 Fun Street, Toronto ON, Canada", url: "http://www.example.com" @@ -206,12 +246,14 @@ defmodule ICalendarTest do %ICalendar.Event{ summary: "Film with Amy and Adam", dtstart: Timex.to_datetime({{2015, 12, 24}, {8, 30, 00}}), + dtstamp: Timex.to_datetime({{2015, 12, 24}, {8, 00, 00}}), dtend: Timex.to_datetime({{2015, 12, 24}, {8, 45, 00}}), description: "Let's go see Star Wars." }, %ICalendar.Event{ summary: "Morning meeting", dtstart: Timex.to_datetime({{2015, 12, 24}, {19, 00, 00}}), + dtstamp: Timex.to_datetime({{2015, 12, 24}, {18, 00, 00}}), dtend: Timex.to_datetime({{2015, 12, 24}, {22, 30, 00}}), description: "A big long meeting with lots of details." } @@ -229,12 +271,14 @@ defmodule ICalendarTest do BEGIN:VEVENT DESCRIPTION:Let's go see Star Wars. DTEND:20151224T084500Z + DTSTAMP:20151224T080000Z DTSTART:20151224T083000Z SUMMARY:Film with Amy and Adam END:VEVENT BEGIN:VEVENT DESCRIPTION:A big long meeting with lots of details. DTEND:20151224T223000Z + DTSTAMP:20151224T180000Z DTSTART:20151224T190000Z SUMMARY:Morning meeting END:VEVENT @@ -247,12 +291,14 @@ defmodule ICalendarTest do %ICalendar.Event{ summary: "Film with Amy and Adam", dtstart: Timex.to_datetime({{2015, 12, 24}, {8, 30, 00}}), + dtstamp: Timex.to_datetime({{2015, 12, 24}, {8, 00, 00}}), dtend: Timex.to_datetime({{2015, 12, 24}, {8, 45, 00}}), description: "Let's go see Star Wars." }, %ICalendar.Event{ summary: "Morning meeting", dtstart: Timex.to_datetime({{2015, 12, 24}, {19, 00, 00}}), + dtstamp: Timex.to_datetime({{2015, 12, 24}, {18, 00, 00}}), dtend: Timex.to_datetime({{2015, 12, 24}, {22, 30, 00}}), description: "A big long meeting with lots of details." } @@ -270,12 +316,14 @@ defmodule ICalendarTest do BEGIN:VEVENT DESCRIPTION:Let's go see Star Wars. DTEND:20151224T084500Z + DTSTAMP:20151224T080000Z DTSTART:20151224T083000Z SUMMARY:Film with Amy and Adam END:VEVENT BEGIN:VEVENT DESCRIPTION:A big long meeting with lots of details. DTEND:20151224T223000Z + DTSTAMP:20151224T180000Z DTSTART:20151224T190000Z SUMMARY:Morning meeting END:VEVENT From 222fce9562b0c495f65b8ae69ae9c3d330375e4d Mon Sep 17 00:00:00 2001 From: Thomas Citharel Date: Fri, 15 Jan 2021 18:17:17 +0100 Subject: [PATCH 2/4] Add CHANGELOG entry Signed-off-by: Thomas Citharel --- CHANGELOG.md | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 4db2190..33e0191 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,11 @@ All notable changes to this project will be documented in this file. This project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). +## Unreleased + +- Add support for the `DTSTAMP` field. + If not provided, it is initialized to the current UTC DateTime when serializing. + ## v1.1.2 - 2022-01-16 - Handle calendars that wrap output such as Google Calendar From 57d6fce6f746b62f748a0077e5fa783110cb0f2e Mon Sep 17 00:00:00 2001 From: Laurent GAY Date: Thu, 31 Jul 2025 12:18:34 +0200 Subject: [PATCH 3/4] Add ATTACH support --- CHANGELOG.md | 3 +++ lib/icalendar/event.ex | 1 + lib/icalendar/util/deserialize.ex | 19 +++++++++++++++++ lib/icalendar/util/kv.ex | 4 ++++ test/icalendar/deserialize_test.exs | 22 +++++++++++++++++++ test/icalendar/event_test.exs | 17 +++++++++++++++ test/icalendar_test.exs | 33 +++++++++++++++++++++++++++++ 7 files changed, 99 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 33e0191..635bfb8 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -9,6 +9,9 @@ This project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.htm - Add support for the `DTSTAMP` field. If not provided, it is initialized to the current UTC DateTime when serializing. +- Add support for the `ATTACH` field. + If not provided + ## v1.1.2 - 2022-01-16 - Handle calendars that wrap output such as Google Calendar diff --git a/lib/icalendar/event.ex b/lib/icalendar/event.ex index db3982c..557bfdd 100644 --- a/lib/icalendar/event.ex +++ b/lib/icalendar/event.ex @@ -22,6 +22,7 @@ defmodule ICalendar.Event do modified: nil, organizer: nil, sequence: nil, + attach: nil, attendees: [] end diff --git a/lib/icalendar/util/deserialize.ex b/lib/icalendar/util/deserialize.ex index 2733a84..5c406f2 100644 --- a/lib/icalendar/util/deserialize.ex +++ b/lib/icalendar/util/deserialize.ex @@ -191,6 +191,13 @@ defmodule ICalendar.Util.Deserialize do %{acc | organizer: organizer} end + def parse_attr( + %Property{key: "ATTACH", value: url, params: params}, + acc + ) do + %{acc | attach = to_attach(url, params)} + end + def parse_attr( %Property{key: "ATTENDEE", params: params, value: value}, acc @@ -281,6 +288,18 @@ defmodule ICalendar.Util.Deserialize do |> List.to_tuple() end + def to_attach(url, %{"FMTTYPE" => type}) do + {url, type} + end + + def to_attach(url, %{}) do + to_attach(url, %{"FMTTYPE" => "image/jpeg"}) + end + + def to_attach(url) do + to_attach(url, %{"FMTTYPE" => "image/jpeg"}) + end + @doc ~S""" This function should strip any sanitization that has been applied to content diff --git a/lib/icalendar/util/kv.ex b/lib/icalendar/util/kv.ex index 6f9023b..ea1b51d 100644 --- a/lib/icalendar/util/kv.ex +++ b/lib/icalendar/util/kv.ex @@ -98,6 +98,10 @@ defmodule ICalendar.Util.KV do "RRULE:FREQ=#{freq}#{rrule_tail_part}\n" end + def build("ATTACH" = key, {url, type}) do + "#{key};FMTTYPE=#{type}:#{url}\n" + end + def build("ATTENDEES", attendees) do Enum.map(attendees, fn attendee -> params = diff --git a/test/icalendar/deserialize_test.exs b/test/icalendar/deserialize_test.exs index 0f8fbbd..cf33072 100644 --- a/test/icalendar/deserialize_test.exs +++ b/test/icalendar/deserialize_test.exs @@ -119,5 +119,27 @@ defmodule ICalendar.DeserializeTest do [event] = ICalendar.from_ics(ics) assert event.url == "http://google.com" end + + test "with attach" do + ics = """ + BEGIN:VEVENT + DESCRIPTION:Escape from the world. Stare at some water. + COMMENT:Don't forget to take something to eat ! + ATTACH;FMTTYPE=image/gif:http://example.com/pub/logo.gif + SUMMARY:Going fishing + DTEND:20151224T084500Z + DTSTART:20151224T083000Z + LOCATION:123 Fun Street\\, Toronto ON\\, Canada + STATUS:TENTATIVE + CATEGORIES:Fishing,Nature + CLASS:PRIVATE + GEO:43.6978819;-79.3810277 + END:VEVENT + """ + + [event] = ICalendar.from_ics(ics) + assert event.attach == {"http://example.com/pub/logo.gif", "image/gif"} + end + end end diff --git a/test/icalendar/event_test.exs b/test/icalendar/event_test.exs index e14e0ba..4dce428 100644 --- a/test/icalendar/event_test.exs +++ b/test/icalendar/event_test.exs @@ -226,4 +226,21 @@ defmodule ICalendar.EventTest do END:VEVENT """ end + + test "ICalendar.to_ics/1 with attach" do + ics = + %Event{ + attach: {"http://example.com/pub/picture.png", "image/png"}, + dtstamp: Timex.to_datetime({{2015, 12, 24}, {8, 45, 00}}) + } + |> ICalendar.to_ics() + + assert ics == """ + BEGIN:VEVENT + ATTACH;FMTTYPE=image/png:http://example.com/pub/picture.png + DTSTAMP:20151224T084500Z + END:VEVENT + """ + end + end diff --git a/test/icalendar_test.exs b/test/icalendar_test.exs index 92b29e6..96f16d4 100644 --- a/test/icalendar_test.exs +++ b/test/icalendar_test.exs @@ -134,6 +134,39 @@ defmodule ICalendarTest do """ end + test "Icalender.to_ics/1 with attach" do + events = [ + %ICalendar.Event{ + summary: "Film with Amy and Adam", + dtstart: Timex.to_datetime({{2015, 12, 24}, {8, 30, 00}}), + dtstamp: Timex.to_datetime({{2015, 12, 24}, {8, 00, 00}}), + dtend: Timex.to_datetime({{2015, 12, 24}, {8, 45, 00}}), + description: "Let's go see Star Wars, and have fun.", + location: "123 Fun Street, Toronto ON, Canada", + attach: {"http://example.com/pub/draw.svg", "image/svg"}, + } + ] + + ics = %ICalendar{events: events} |> ICalendar.to_ics() + + assert ics == """ + BEGIN:VCALENDAR + CALSCALE:GREGORIAN + VERSION:2.0 + PRODID:-//Elixir ICalendar//Elixir ICalendar//EN + BEGIN:VEVENT + ATTACH;FMTTYPE=image/svg:http://example.com/pub/draw.svg + DESCRIPTION:Let's go see Star Wars\\, and have fun. + DTEND:20151224T084500Z + DTSTAMP:20151224T080000Z + DTSTART:20151224T083000Z + LOCATION:123 Fun Street\\, Toronto ON\\, Canada + SUMMARY:Film with Amy and Adam + END:VEVENT + END:VCALENDAR + """ + end + test "Icalender.to_ics/1 with rrule and exdates" do events = [ %ICalendar.Event{ From b8fc5360b1755f60f2768d40f6aca949ef598a00 Mon Sep 17 00:00:00 2001 From: Laurent GAY Date: Thu, 31 Jul 2025 13:04:17 +0200 Subject: [PATCH 4/4] Add ATTACH support : syntax error --- lib/icalendar/util/deserialize.ex | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/icalendar/util/deserialize.ex b/lib/icalendar/util/deserialize.ex index 5c406f2..3e8ebca 100644 --- a/lib/icalendar/util/deserialize.ex +++ b/lib/icalendar/util/deserialize.ex @@ -195,7 +195,7 @@ defmodule ICalendar.Util.Deserialize do %Property{key: "ATTACH", value: url, params: params}, acc ) do - %{acc | attach = to_attach(url, params)} + %{acc | attach: to_attach(url, params)} end def parse_attr(