calendav 0.3.0 → 0.5.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/CHANGELOG.md +14 -0
- data/README.md +79 -9
- data/lib/calendav/calendar.rb +2 -2
- data/lib/calendav/client.rb +10 -5
- data/lib/calendav/clients/calendars_client.rb +1 -1
- data/lib/calendav/clients/events_client.rb +14 -6
- data/lib/calendav/clients/todos_client.rb +73 -0
- data/lib/calendav/credentials/apple.rb +1 -1
- data/lib/calendav/credentials/fastmail.rb +1 -1
- data/lib/calendav/credentials/google.rb +1 -1
- data/lib/calendav/endpoint.rb +8 -10
- data/lib/calendav/error_handler.rb +34 -0
- data/lib/calendav/errors.rb +8 -2
- data/lib/calendav/event.rb +2 -2
- data/lib/calendav/parsers/todo_xml.rb +37 -0
- data/lib/calendav/requests/list_events.rb +13 -2
- data/lib/calendav/requests/list_todos.rb +49 -0
- data/lib/calendav/requests/make_calendar.rb +1 -0
- data/lib/calendav/todo.rb +60 -0
- data/lib/calendav.rb +4 -4
- metadata +9 -188
- data/.rspec +0 -3
- data/Gemfile +0 -9
- data/Rakefile +0 -12
- data/spec/acceptance/apple_spec.rb +0 -45
- data/spec/acceptance/google_spec.rb +0 -101
- data/spec/acceptance/radicale_spec.rb +0 -48
- data/spec/acceptance/shared.rb +0 -180
- data/spec/data/radicale/config.ini +0 -10
- data/spec/data/radicale/users +0 -1
- data/spec/spec_helper.rb +0 -18
- data/spec/support/encoded_matchers.rb +0 -29
- data/spec/support/event_helpers.rb +0 -39
- data/spec/support/vcr.rb +0 -26
data/spec/acceptance/shared.rb
DELETED
@@ -1,180 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
require "icalendar"
|
4
|
-
require "icalendar/tzinfo"
|
5
|
-
require "securerandom"
|
6
|
-
require "uri"
|
7
|
-
|
8
|
-
RSpec.shared_examples "supporting calendar management" do
|
9
|
-
it "supports calendar creation" do
|
10
|
-
expect(subject.calendars.create?).to eq(true)
|
11
|
-
end
|
12
|
-
|
13
|
-
it "can create, find, update and delete calendars" do
|
14
|
-
identifier = "calendav-test"
|
15
|
-
time_zone = TZInfo::Timezone.get "UTC"
|
16
|
-
ical_time_zone = time_zone.ical_timezone Time.now.utc
|
17
|
-
|
18
|
-
url = subject.calendars.create(
|
19
|
-
identifier,
|
20
|
-
display_name: "Calendav Test",
|
21
|
-
description: "For test purposes only",
|
22
|
-
color: "#00FF00",
|
23
|
-
time_zone: ical_time_zone.to_ical
|
24
|
-
)
|
25
|
-
expect(url).to include(URI.decode_www_form_component(identifier))
|
26
|
-
expect(url).to start_with(host)
|
27
|
-
|
28
|
-
calendars = subject.calendars.list
|
29
|
-
expect(calendars.collect(&:display_name)).to include("Calendav Test")
|
30
|
-
|
31
|
-
expect(
|
32
|
-
subject.calendars.update(url, display_name: "Calendav Update")
|
33
|
-
).to eq(true)
|
34
|
-
|
35
|
-
calendars = subject.calendars.list
|
36
|
-
expect(calendars.collect(&:display_name)).to include("Calendav Update")
|
37
|
-
|
38
|
-
subject.calendars.delete(url)
|
39
|
-
end
|
40
|
-
end
|
41
|
-
|
42
|
-
RSpec.shared_examples "supporting event management" do
|
43
|
-
it "supports events" do
|
44
|
-
expect(calendar.components).to include("VEVENT")
|
45
|
-
end
|
46
|
-
|
47
|
-
it "supports WebDAV-Sync" do
|
48
|
-
expect(calendar.reports).to include("sync-collection")
|
49
|
-
end
|
50
|
-
|
51
|
-
it "can create, find, update and delete events" do
|
52
|
-
# Create an event
|
53
|
-
event_url = subject.events.create(
|
54
|
-
calendar.url, "calendav-event-1.ics", ical_event("Brunch", 10, 30)
|
55
|
-
)
|
56
|
-
expect(event_url).to include(URI.decode_www_form_component(calendar.url))
|
57
|
-
event = subject.events.find(event_url)
|
58
|
-
|
59
|
-
# Search for the event
|
60
|
-
events = subject.events.list(
|
61
|
-
calendar.url, from: time_at(0, 0), to: time_at(23, 59)
|
62
|
-
)
|
63
|
-
expect(events.length).to eq(1)
|
64
|
-
expect(events.first.summary).to eq("Brunch")
|
65
|
-
expect(events.first.dtstart.to_time).to eq(time_at(10, 30))
|
66
|
-
expect(events.first.url).to eq_encoded_url(event_url)
|
67
|
-
|
68
|
-
# Update the event
|
69
|
-
subject.events.update(event_url, update_summary(event, "Coffee"))
|
70
|
-
|
71
|
-
# Search again
|
72
|
-
events = subject.events.list(
|
73
|
-
calendar.url, from: time_at(0, 0), to: time_at(23, 59)
|
74
|
-
)
|
75
|
-
expect(events.length).to eq(1)
|
76
|
-
expect(events.first.summary).to eq("Coffee")
|
77
|
-
expect(events.first.dtstart.to_time).to eq(time_at(10, 30))
|
78
|
-
expect(events.first.url).to eq_encoded_url(event_url)
|
79
|
-
|
80
|
-
# Create another event
|
81
|
-
another_url = subject.events.create(
|
82
|
-
calendar.url, "calendav-event-2.ics", ical_event("Brunch", 10, 30)
|
83
|
-
)
|
84
|
-
|
85
|
-
# Search for all events
|
86
|
-
events = subject.events.list(calendar.url)
|
87
|
-
expect(events.length).to eq(2)
|
88
|
-
|
89
|
-
# Delete the events
|
90
|
-
expect(subject.events.delete(event_url)).to eq(true)
|
91
|
-
expect(subject.events.delete(another_url)).to eq(true)
|
92
|
-
end
|
93
|
-
|
94
|
-
it "respects etag conditions with updates" do
|
95
|
-
event_url = subject.events.create(
|
96
|
-
calendar.url, "calendav-event.ics", ical_event("Brunch", 10, 30)
|
97
|
-
)
|
98
|
-
event = subject.events.find(event_url)
|
99
|
-
|
100
|
-
expect(
|
101
|
-
subject.events.update(
|
102
|
-
event_url, update_summary(event, "Coffee"), etag: event.etag
|
103
|
-
)
|
104
|
-
).to eq(true)
|
105
|
-
|
106
|
-
expect(subject.events.find(event_url).summary).to eq("Coffee")
|
107
|
-
|
108
|
-
# Wait for server to catch up
|
109
|
-
sleep 1
|
110
|
-
|
111
|
-
# Updating with the old etag should fail
|
112
|
-
expect(
|
113
|
-
subject.events.update(
|
114
|
-
event_url, update_summary(event, "Brunch"), etag: event.etag
|
115
|
-
)
|
116
|
-
).to eq(false)
|
117
|
-
|
118
|
-
expect(subject.events.find(event_url).summary).to eq("Coffee")
|
119
|
-
|
120
|
-
expect(subject.events.delete(event_url)).to eq(true)
|
121
|
-
end
|
122
|
-
|
123
|
-
it "handles synchronisation requests" do
|
124
|
-
first_url = subject.events.create(
|
125
|
-
calendar.url, "calendav-event-1.ics", ical_event("Brunch", 10, 30)
|
126
|
-
)
|
127
|
-
first = subject.events.find(first_url)
|
128
|
-
token = subject.calendars.find(calendar.url, sync: true).sync_token
|
129
|
-
|
130
|
-
events = subject.events.list(calendar.url)
|
131
|
-
expect(events.length).to eq(1)
|
132
|
-
|
133
|
-
second_url = subject.events.create(
|
134
|
-
calendar.url, "calendav-event-2.ics", ical_event("Brunch Again", 11, 30)
|
135
|
-
)
|
136
|
-
|
137
|
-
subject.events.update(first_url, update_summary(first, "Coffee"))
|
138
|
-
first = subject.events.find(first_url)
|
139
|
-
|
140
|
-
collection = subject.calendars.sync(calendar.url, token)
|
141
|
-
expect(collection.changes.collect(&:url))
|
142
|
-
.to match_encoded_urls([first_url, second_url])
|
143
|
-
|
144
|
-
expect(collection.deletions).to be_empty
|
145
|
-
expect(collection.more?).to eq(false)
|
146
|
-
|
147
|
-
subject.events.update(first_url, update_summary(first, "Brunch"))
|
148
|
-
subject.events.delete(second_url)
|
149
|
-
|
150
|
-
collection = subject.calendars.sync(calendar.url, collection.sync_token)
|
151
|
-
urls = collection.changes.collect(&:url)
|
152
|
-
expect(urls.length).to eq(1)
|
153
|
-
expect(urls[0]).to eq_encoded_url(first_url)
|
154
|
-
|
155
|
-
expect(collection.deletions.length).to eq(1)
|
156
|
-
expect(collection.deletions.first).to eq_encoded_url(second_url)
|
157
|
-
expect(collection.more?).to eq(false)
|
158
|
-
|
159
|
-
subject.events.delete(first_url)
|
160
|
-
end
|
161
|
-
end
|
162
|
-
|
163
|
-
RSpec.shared_examples "supporting event deletion with etags" do
|
164
|
-
it "respects etag conditions with deletions" do
|
165
|
-
event_url = subject.events.create(
|
166
|
-
calendar.url, "calendav-event.ics", ical_event("Brunch", 10, 30)
|
167
|
-
)
|
168
|
-
event = subject.events.find(event_url)
|
169
|
-
|
170
|
-
expect(
|
171
|
-
subject.events.update(
|
172
|
-
event_url, update_summary(event, "Coffee"), etag: event.etag
|
173
|
-
)
|
174
|
-
).to eq(true)
|
175
|
-
expect(subject.events.find(event_url).summary).to eq("Coffee")
|
176
|
-
|
177
|
-
expect(subject.events.delete(event_url, etag: event.etag)).to eq(false)
|
178
|
-
expect(subject.events.delete(event_url)).to eq(true)
|
179
|
-
end
|
180
|
-
end
|
data/spec/data/radicale/users
DELETED
@@ -1 +0,0 @@
|
|
1
|
-
test:$2y$05$O.Z0365vM0GOv.YN1WlIEOnd0gaGEB/SmoRiSjIHnstXIm6ZURl/y
|
data/spec/spec_helper.rb
DELETED
@@ -1,18 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
require "calendav"
|
4
|
-
require "dotenv"
|
5
|
-
|
6
|
-
Dotenv.load
|
7
|
-
|
8
|
-
require_relative "support/encoded_matchers"
|
9
|
-
require_relative "support/event_helpers"
|
10
|
-
require_relative "support/vcr"
|
11
|
-
|
12
|
-
RSpec.configure do |config|
|
13
|
-
config.disable_monkey_patching!
|
14
|
-
|
15
|
-
config.expect_with :rspec do |c|
|
16
|
-
c.syntax = :expect
|
17
|
-
end
|
18
|
-
end
|
@@ -1,29 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
module EncodedMatchers
|
4
|
-
def eq_encoded_url(expected)
|
5
|
-
eq(RecodeURI.call(expected))
|
6
|
-
end
|
7
|
-
|
8
|
-
def match_encoded_urls(expected)
|
9
|
-
match_array(expected.collect { |uri| RecodeURI.call(uri) })
|
10
|
-
end
|
11
|
-
end
|
12
|
-
|
13
|
-
class RecodeURI
|
14
|
-
def self.call(uri)
|
15
|
-
encoded = URI(uri)
|
16
|
-
|
17
|
-
encoded.path = encoded.path.split("/").collect do |piece|
|
18
|
-
URI.encode_www_form_component(piece)
|
19
|
-
end.join("/")
|
20
|
-
|
21
|
-
encoded.path += "/" if uri.end_with?("/")
|
22
|
-
|
23
|
-
encoded.to_s
|
24
|
-
end
|
25
|
-
end
|
26
|
-
|
27
|
-
RSpec.configure do |config|
|
28
|
-
config.include EncodedMatchers
|
29
|
-
end
|
@@ -1,39 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
# require "active_support"
|
4
|
-
require "icalendar"
|
5
|
-
require "securerandom"
|
6
|
-
|
7
|
-
module EventHelpers
|
8
|
-
def ical_event(summary, hour, minute)
|
9
|
-
start = time_at(hour, minute)
|
10
|
-
|
11
|
-
ics = Icalendar::Calendar.new
|
12
|
-
|
13
|
-
ics.event do |event|
|
14
|
-
event.dtstart = start
|
15
|
-
event.dtend = start + 3600
|
16
|
-
event.summary = summary
|
17
|
-
end
|
18
|
-
|
19
|
-
ics.tap(&:publish).to_ical
|
20
|
-
end
|
21
|
-
|
22
|
-
def time_at(hour, minute = 0)
|
23
|
-
now = Time.now
|
24
|
-
|
25
|
-
Time.utc(now.year, now.month, now.day, hour, minute)
|
26
|
-
end
|
27
|
-
|
28
|
-
def update_summary(event, summary)
|
29
|
-
ics = Icalendar::Calendar.parse(event.calendar_data).first
|
30
|
-
|
31
|
-
ics.events.first.summary = summary
|
32
|
-
|
33
|
-
ics.to_ical
|
34
|
-
end
|
35
|
-
end
|
36
|
-
|
37
|
-
RSpec.configure do |config|
|
38
|
-
config.include EventHelpers
|
39
|
-
end
|
data/spec/support/vcr.rb
DELETED
@@ -1,26 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
require "timecop"
|
4
|
-
require "webmock/rspec"
|
5
|
-
require "vcr"
|
6
|
-
require "vcr_assistant/rspec"
|
7
|
-
|
8
|
-
VCR.configure do |config|
|
9
|
-
config.cassette_library_dir = File.expand_path(
|
10
|
-
File.join(__dir__, "../cassettes")
|
11
|
-
)
|
12
|
-
config.hook_into :webmock
|
13
|
-
config.ignore_hosts "127.0.0.1"
|
14
|
-
end
|
15
|
-
|
16
|
-
RSpec.configure do |config|
|
17
|
-
config.around(:each, :vcr) do |example|
|
18
|
-
assisted_cassette(example) do |_assistant|
|
19
|
-
Timecop.freeze(Time.gm(2022))
|
20
|
-
|
21
|
-
example.run
|
22
|
-
|
23
|
-
Timecop.return
|
24
|
-
end
|
25
|
-
end
|
26
|
-
end
|