calendav 0.1.1 → 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
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