Class: Async::Caldav::Client::Calendar

Inherits:
Object
  • Object
show all
Defined in:
lib/async/caldav/client/calendar.rb

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(client, path, props = {}) ⇒ Calendar

Returns a new instance of Calendar.



12
13
14
15
16
17
18
19
# File 'lib/async/caldav/client/calendar.rb', line 12

def initialize(client, path, props = {})
  @client = client
  @path = path
  @displayname = props[:displayname]
  @description = props[:description]
  @color = props[:color]
  @ctag = props[:ctag]
end

Instance Attribute Details

#colorObject (readonly)

Returns the value of attribute color.



10
11
12
# File 'lib/async/caldav/client/calendar.rb', line 10

def color
  @color
end

#ctagObject (readonly)

Returns the value of attribute ctag.



10
11
12
# File 'lib/async/caldav/client/calendar.rb', line 10

def ctag
  @ctag
end

#descriptionObject (readonly)

Returns the value of attribute description.



10
11
12
# File 'lib/async/caldav/client/calendar.rb', line 10

def description
  @description
end

#displaynameObject (readonly)

Returns the value of attribute displayname.



10
11
12
# File 'lib/async/caldav/client/calendar.rb', line 10

def displayname
  @displayname
end

#pathObject (readonly)

Returns the value of attribute path.



10
11
12
# File 'lib/async/caldav/client/calendar.rb', line 10

def path
  @path
end

Instance Method Details

#deleteObject



90
91
92
93
94
95
96
97
98
# File 'lib/async/caldav/client/calendar.rb', line 90

def delete
  status, = @client.request('DELETE', @path)

  case status
  when 204 then true
  when 404 then raise NotFound, "Not found: #{@path}"
  else raise Error, "DELETE failed: #{status}"
  end
end

#delete_event(filename) ⇒ Object



79
80
81
82
83
84
85
86
87
88
# File 'lib/async/caldav/client/calendar.rb', line 79

def delete_event(filename)
  path = "#{@path}#{filename}"
  status, = @client.request('DELETE', path)

  case status
  when 204 then true
  when 404 then raise NotFound, "Not found: #{path}"
  else raise Error, "DELETE failed: #{status}"
  end
end

#events(filter: nil) ⇒ Object

Raises:



21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
# File 'lib/async/caldav/client/calendar.rb', line 21

def events(filter: nil)
  body = if filter
    <<~XML
      <?xml version="1.0" encoding="UTF-8"?>
      <c:calendar-query xmlns:d="DAV:" xmlns:c="urn:ietf:params:xml:ns:caldav">
        <d:prop><d:getetag/><c:calendar-data/></d:prop>
        #{filter}
      </c:calendar-query>
    XML
  else
    <<~XML
      <?xml version="1.0" encoding="UTF-8"?>
      <c:calendar-query xmlns:d="DAV:" xmlns:c="urn:ietf:params:xml:ns:caldav">
        <d:prop><d:getetag/><c:calendar-data/></d:prop>
      </c:calendar-query>
    XML
  end

  status, _, resp_body = @client.request('REPORT', @path, body: body, headers: { 'Content-Type' => 'text/xml' })
  raise Error, "REPORT failed: #{status}" unless status == 207

  @client.parse_multistatus_items(resp_body, data_tag: 'calendar-data')
end

#get_event(filename) ⇒ Object



65
66
67
68
69
70
71
72
73
74
75
76
77
# File 'lib/async/caldav/client/calendar.rb', line 65

def get_event(filename)
  path = "#{@path}#{filename}"
  status, headers, body = @client.request('GET', path)

  case status
  when 200
    { path: path, body: body, etag: headers['etag'], content_type: headers['content-type'] }
  when 404
    raise NotFound, "Not found: #{path}"
  else
    raise Error, "GET failed: #{status}"
  end
end

#propfindObject

Raises:



100
101
102
103
104
# File 'lib/async/caldav/client/calendar.rb', line 100

def propfind
  status, _, body = @client.request('PROPFIND', @path, headers: { 'Depth' => '0' })
  raise Error, "PROPFIND failed: #{status}" unless status == 207
  @client.parse_collection_props(body)
end

#proppatch(displayname: nil, description: nil, color: nil) ⇒ Object

Raises:



106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
# File 'lib/async/caldav/client/calendar.rb', line 106

def proppatch(displayname: nil, description: nil, color: nil)
  props = []
  props << "<d:displayname>#{Protocol::Caldav::Xml.escape(displayname)}</d:displayname>" if displayname
  props << "<c:calendar-description>#{Protocol::Caldav::Xml.escape(description)}</c:calendar-description>" if description
  props << "<x:calendar-color>#{Protocol::Caldav::Xml.escape(color)}</x:calendar-color>" if color

  body = <<~XML
    <?xml version="1.0" encoding="UTF-8"?>
    <d:propertyupdate xmlns:d="DAV:" xmlns:c="urn:ietf:params:xml:ns:caldav" xmlns:x="http://apple.com/ns/ical/">
      <d:set><d:prop>#{props.join}</d:prop></d:set>
    </d:propertyupdate>
  XML

  status, = @client.request('PROPPATCH', @path, body: body, headers: { 'Content-Type' => 'text/xml' })
  raise Error, "PROPPATCH failed: #{status}" unless status == 207

  @displayname = displayname if displayname
  @description = description if description
  @color = color if color
  self
end

#put_event(filename, body, if_match: nil, if_none_match: nil) ⇒ Object



45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
# File 'lib/async/caldav/client/calendar.rb', line 45

def put_event(filename, body, if_match: nil, if_none_match: nil)
  headers = { 'Content-Type' => 'text/calendar' }
  headers['If-Match'] = if_match if if_match
  headers['If-None-Match'] = if_none_match if if_none_match

  path = "#{@path}#{filename}"
  status, resp_headers, = @client.request('PUT', path, body: body, headers: headers)

  case status
  when 201, 204
    { path: path, etag: resp_headers['etag'], status: status }
  when 412
    raise PreconditionFailed, "Precondition failed for #{path}"
  when 409
    raise Conflict, "UID conflict for #{path}"
  else
    raise Error, "PUT failed: #{status}"
  end
end

#sync(token: nil) ⇒ Object

Raises:



128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
# File 'lib/async/caldav/client/calendar.rb', line 128

def sync(token: nil)
  token_xml = token ? "<d:sync-token>#{token}</d:sync-token>" : "<d:sync-token/>"
  body = <<~XML
    <?xml version="1.0" encoding="UTF-8"?>
    <d:sync-collection xmlns:d="DAV:">
      <d:prop><d:getetag/></d:prop>
      #{token_xml}
    </d:sync-collection>
  XML

  status, _, resp_body = @client.request('REPORT', @path, body: body, headers: { 'Content-Type' => 'text/xml' })

  if status == 403
    raise InvalidSyncToken, "Invalid sync token"
  end
  raise Error, "REPORT failed: #{status}" unless status == 207

  new_token = resp_body.match(/<[^>]*sync-token[^>]*>([^<]+)</)[1] rescue nil
  items = @client.parse_sync_items(resp_body)
  [items, new_token]
end