calendav 0.1.1 → 0.2.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 6564ba6fca723cd571c786aee0028dd36179fd90ee7bba76a7fbd3526a939b64
4
- data.tar.gz: 670e804269e4f341fee602a5ffad34360ae2d8ae5c15e88167c354227848ce03
3
+ metadata.gz: 605ae687dccd58f74c2c2ec01b44bf27b2cc71de6f5453d26c398b7828325d40
4
+ data.tar.gz: '08c0253e9cc5479f1370a2acb5973901a4d9079078a9f51aba2ac28fccf75b9d'
5
5
  SHA512:
6
- metadata.gz: 63cd2f961d63585f35c46f137b510b5d8378d699e94c54cb195d702961abb0a557d9bcc6a159cdd9d133318290c1cd71921c54f4fc8ed2d38763fe95ef193a06
7
- data.tar.gz: 4fb05941471d086aa9c13aad6a3dca6349106e5d1d527f3b1fae1b7da02a6c8b993cfe55c718c0ddad7371f5db6c18228a4b8f850b1d3c13622f824bcf31c1fa
6
+ metadata.gz: 20d4fefd21bdf9d58a2c76e557b80be9a6f62c0a4c38667ab806f91e9081e34179941ad9238ca25007db41525a9ac21ec1fe2ce84ac311418e50458af55a413a
7
+ data.tar.gz: e3584378cea92199c918f81df44394ccac34b20b2f963abd72d2488d0356dd2108e06ec038ea68e511e2548f9ee48684b3584950cd737d431530479d57430ae2
data/CHANGELOG.md CHANGED
@@ -2,6 +2,11 @@
2
2
 
3
3
  ...
4
4
 
5
+ ## 0.2.0 - 2021-07-07
6
+
7
+ * Improve serialisation of Event and Calendar objects (easily converted to/from hashes).
8
+ * Add `more?` to sync collection objects, indicating whether there are further changes available.
9
+
5
10
  ## 0.1.1 - 2021-06-28
6
11
 
7
12
  * Fix reports lists to just the relevant calendar.
@@ -5,27 +5,35 @@ require_relative "./parsers/calendar_xml"
5
5
 
6
6
  module Calendav
7
7
  class Calendar
8
- attr_reader :url, :display_name, :description, :ctag, :etag, :time_zone,
9
- :color, :components, :reports, :sync_token
8
+ ATTRIBUTES = %i[
9
+ url display_name description ctag etag time_zone color components reports
10
+ sync_token
11
+ ].freeze
10
12
 
11
13
  def self.from_xml(host, node)
12
14
  new(
13
- ContextualURL.call(host, node.xpath("./dav:href").text),
14
- Parsers::CalendarXML.call(node)
15
+ {
16
+ url: ContextualURL.call(host, node.xpath("./dav:href").text)
17
+ }.merge(
18
+ Parsers::CalendarXML.call(node)
19
+ )
15
20
  )
16
21
  end
17
22
 
18
- def initialize(url, attributes = {})
19
- @url = url
20
- @display_name = attributes[:display_name]
21
- @description = attributes[:description]
22
- @ctag = attributes[:ctag]
23
- @etag = attributes[:etag]
24
- @time_zone = attributes[:time_zone]
25
- @color = attributes[:color]
26
- @components = attributes[:components]
27
- @reports = attributes[:reports]
28
- @sync_token = attributes[:sync_token]
23
+ def initialize(attributes = {})
24
+ @attributes = attributes
29
25
  end
26
+
27
+ ATTRIBUTES.each do |attribute|
28
+ define_method(attribute) { attributes[attribute] }
29
+ end
30
+
31
+ def to_h
32
+ attributes.dup
33
+ end
34
+
35
+ private
36
+
37
+ attr_reader :attributes
30
38
  end
31
39
  end
@@ -30,7 +30,7 @@ module Calendav
30
30
  response = endpoint.get(url: event_url)
31
31
 
32
32
  Event.new(
33
- event_url,
33
+ url: event_url,
34
34
  calendar_data: response.body.to_s,
35
35
  etag: response.headers["ETag"]
36
36
  )
@@ -86,7 +86,7 @@ module Calendav
86
86
  HTTP.auth("Bearer #{credentials.password}")
87
87
  else
88
88
  raise "Unexpected authentication approach: " \
89
- "#{credentials.authentication}"
89
+ "#{credentials.authentication}"
90
90
  end
91
91
  end
92
92
 
@@ -5,19 +5,28 @@ require_relative "./parsers/event_xml"
5
5
 
6
6
  module Calendav
7
7
  class Event
8
- attr_reader :url, :calendar_data, :etag
8
+ ATTRIBUTES = %i[url calendar_data etag].freeze
9
9
 
10
10
  def self.from_xml(host, node)
11
11
  new(
12
- ContextualURL.call(host, node.xpath("./dav:href").text),
13
- Parsers::EventXML.call(node)
12
+ {
13
+ url: ContextualURL.call(host, node.xpath("./dav:href").text)
14
+ }.merge(
15
+ Parsers::EventXML.call(node)
16
+ )
14
17
  )
15
18
  end
16
19
 
17
- def initialize(url, attributes = {})
18
- @url = url
19
- @calendar_data = attributes[:calendar_data]
20
- @etag = attributes[:etag]
20
+ def initialize(attributes = {})
21
+ @attributes = attributes
22
+ end
23
+
24
+ ATTRIBUTES.each do |attribute|
25
+ define_method(attribute) { attributes[attribute] }
26
+ end
27
+
28
+ def to_h
29
+ attributes.dup
21
30
  end
22
31
 
23
32
  def summary
@@ -38,6 +47,8 @@ module Calendav
38
47
 
39
48
  private
40
49
 
50
+ attr_reader :attributes
51
+
41
52
  def inner_calendar
42
53
  Icalendar::Calendar.parse(calendar_data).first
43
54
  end
@@ -17,7 +17,7 @@ module Calendav
17
17
  end
18
18
 
19
19
  def call
20
- SyncCollection.new(events, deleted_urls, token)
20
+ SyncCollection.new(events, deleted_urls, token, more?)
21
21
  end
22
22
 
23
23
  private
@@ -40,11 +40,23 @@ module Calendav
40
40
  @calendar_path ||= URI(calendar_url).path
41
41
  end
42
42
 
43
+ def calendar_response
44
+ multi_response
45
+ .detect { |node| node.xpath("./dav:href").text == calendar_path }
46
+ end
47
+
43
48
  def individual_responses
44
49
  multi_response
45
50
  .reject { |node| node.xpath("./dav:href").text == calendar_path }
46
51
  end
47
52
 
53
+ def more?
54
+ return false if calendar_response.nil?
55
+
56
+ status = calendar_response.xpath("./dav:propstat/dav:status").text
57
+ !status["507 Insufficient Storage"].nil?
58
+ end
59
+
48
60
  def token
49
61
  multi_response.xpath("/dav:multistatus/dav:sync-token").text
50
62
  end
@@ -2,12 +2,17 @@
2
2
 
3
3
  module Calendav
4
4
  class SyncCollection
5
- attr_reader :changes, :deletions, :sync_token
5
+ attr_reader :changes, :deletions, :sync_token, :more
6
6
 
7
- def initialize(changes, deletions, sync_token)
7
+ def initialize(changes, deletions, sync_token, more)
8
8
  @changes = changes
9
9
  @deletions = deletions
10
10
  @sync_token = sync_token
11
+ @more = more
12
+ end
13
+
14
+ def more?
15
+ more
11
16
  end
12
17
  end
13
18
  end
@@ -1,5 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require "google/apis/calendar_v3"
3
4
  require "googleauth"
4
5
  require "icalendar"
5
6
  require "securerandom"
@@ -12,20 +13,22 @@ RSpec.describe "Google" do
12
13
  let(:username) { ENV.fetch("GOOGLE_USERNAME") }
13
14
  let(:access_token) { @access_token }
14
15
  let(:credentials) { Calendav.credentials(provider, username, access_token) }
16
+ let(:google_auth) { @google_auth }
15
17
 
16
18
  subject { Calendav.client(credentials) }
17
19
 
18
20
  before :context do
21
+ @google_auth = Google::Auth::UserRefreshCredentials.new(
22
+ client_id: ENV.fetch("GOOGLE_CLIENT_ID"),
23
+ scope: [],
24
+ client_secret: ENV.fetch("GOOGLE_CLIENT_SECRET"),
25
+ refresh_token: ENV.fetch("GOOGLE_REFRESH_TOKEN"),
26
+ additional_parameters: { "access_type" => "offline" }
27
+ )
28
+
19
29
  @access_token = begin
20
- credentials = Google::Auth::UserRefreshCredentials.new(
21
- client_id: ENV.fetch("GOOGLE_CLIENT_ID"),
22
- scope: [],
23
- client_secret: ENV.fetch("GOOGLE_CLIENT_SECRET"),
24
- refresh_token: ENV.fetch("GOOGLE_REFRESH_TOKEN"),
25
- additional_parameters: { "access_type" => "offline" }
26
- )
27
- credentials.fetch_access_token!
28
- credentials.access_token
30
+ @google_auth.fetch_access_token!
31
+ @google_auth.access_token
29
32
  end
30
33
  end
31
34
 
@@ -61,15 +64,20 @@ RSpec.describe "Google" do
61
64
 
62
65
  context "with a calendar" do
63
66
  let(:calendars) { subject.calendars.list }
64
- let(:calendar) do
65
- calendars.detect { |cal| cal.display_name == "Calendav Test" }
67
+ let(:calendar) { calendars.detect { |cal| cal.display_name == name } }
68
+ let(:name) { "Calendav Test #{Time.now.to_i}" }
69
+ let(:service) { Google::Apis::CalendarV3::CalendarService.new }
70
+ let(:entry) { Google::Apis::CalendarV3::Calendar.new(summary: name) }
71
+
72
+ before :each do
73
+ service.authorization = google_auth
74
+
75
+ result = service.insert_calendar entry
76
+ entry.update!(**result.to_h)
66
77
  end
67
78
 
68
79
  after :each do
69
- subject
70
- .events
71
- .list(calendar.url)
72
- .each { |event| subject.events.delete(event.url) }
80
+ service.delete_calendar entry.id
73
81
  end
74
82
 
75
83
  it_behaves_like "supporting event management"
@@ -105,6 +105,9 @@ RSpec.shared_examples "supporting event management" do
105
105
 
106
106
  expect(subject.events.find(event_url).summary).to eq("Coffee")
107
107
 
108
+ # Wait for server to catch up
109
+ sleep 1
110
+
108
111
  # Updating with the old etag should fail
109
112
  expect(
110
113
  subject.events.update(
@@ -139,6 +142,7 @@ RSpec.shared_examples "supporting event management" do
139
142
  .to match_encoded_urls([first_url, second_url])
140
143
 
141
144
  expect(collection.deletions).to be_empty
145
+ expect(collection.more?).to eq(false)
142
146
 
143
147
  subject.events.update(first_url, update_summary(first, "Brunch"))
144
148
  subject.events.delete(second_url)
@@ -150,6 +154,7 @@ RSpec.shared_examples "supporting event management" do
150
154
 
151
155
  expect(collection.deletions.length).to eq(1)
152
156
  expect(collection.deletions.first).to eq_encoded_url(second_url)
157
+ expect(collection.more?).to eq(false)
153
158
 
154
159
  subject.events.delete(first_url)
155
160
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: calendav
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.1
4
+ version: 0.2.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Pat Allan
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2021-06-28 00:00:00.000000000 Z
11
+ date: 2021-07-07 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: http
@@ -66,6 +66,20 @@ dependencies:
66
66
  - - ">="
67
67
  - !ruby/object:Gem::Version
68
68
  version: '0'
69
+ - !ruby/object:Gem::Dependency
70
+ name: google-api-client
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - ">="
74
+ - !ruby/object:Gem::Version
75
+ version: '0'
76
+ type: :development
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - ">="
81
+ - !ruby/object:Gem::Version
82
+ version: '0'
69
83
  - !ruby/object:Gem::Dependency
70
84
  name: googleauth
71
85
  requirement: !ruby/object:Gem::Requirement