Class: Tilia::CalDav::IcsExportPlugin
- Inherits:
-
Dav::ServerPlugin
- Object
- Dav::ServerPlugin
- Tilia::CalDav::IcsExportPlugin
- Defined in:
- lib/tilia/cal_dav/ics_export_plugin.rb
Overview
ICS Exporter
This plugin adds the ability to export entire calendars as .ics files. This is useful for clients that don’t support CalDAV yet. They often do support ics files.
To use this, point a http client to a caldav calendar, and add ?expand to the url.
Further options that can be added to the url:
start=123456789 - Only return events after the given unix timestamp
end=123245679 - Only return events from before the given unix timestamp
expand=1 - Strip timezone information and expand recurring events.
If you'd like to expand, you _must_ also specify start
and end.
By default this plugin returns data in the text/calendar format (iCalendar 2.0). If you’d like to receive jCal data instead, you can use an Accept header:
Accept: application/calendar+json
Alternatively, you can also specify this in the url using accept=application/calendar+json, or accept=jcal for short. If the url parameter and Accept header is specified, the url parameter wins.
Note that specifying a start or end data implies that only events will be returned. VTODO and VJOURNAL will be stripped.
Instance Method Summary collapse
-
#http_get(request, response) ⇒ Object
Intercepts GET requests on calendar urls ending with ?export.
-
#merge_objects(properties, input_objects) ⇒ Object
Merges all calendar objects, and builds one big iCalendar blob.
-
#plugin_info ⇒ Object
Returns a bunch of meta-data about the plugin.
-
#plugin_name ⇒ Object
Returns a plugin name.
-
#setup(server) ⇒ Object
Initializes the plugin and registers event handlers.
Methods inherited from Dav::ServerPlugin
#features, #http_methods, #supported_report_set
Instance Method Details
#http_get(request, response) ⇒ Object
Intercepts GET requests on calendar urls ending with ?export.
62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 |
# File 'lib/tilia/cal_dav/ics_export_plugin.rb', line 62 def http_get(request, response) query_params = request.query_parameters return true unless query_params.key?('export') path = request.path node = @server.properties( path, [ '{DAV:}resourcetype', '{DAV:}displayname', '{http://sabredav.org/ns}sync-token', '{DAV:}sync-token', '{http://apple.com/ns/ical/}calendar-color' ] ) return true unless node.key?('{DAV:}resourcetype') && node['{DAV:}resourcetype'].is("{#{Plugin::NS_CALDAV}}calendar") # Marking the transactionType, for logging purposes. @server.transaction_type = 'get-calendar-export' properties = node start = nil ending = nil = false component_type = '' if query_params.key?('start') fail Dav::Exception::BadRequest, 'The start= parameter must contain a unix timestamp' unless query_params['start'] =~ /^\d+$/ start = Time.zone.at(query_params['start'].to_i) end if query_params.key?('end') fail Dav::Exception::BadRequest, 'The end= parameter must contain a unix timestamp' unless query_params['end'] =~ /^\d+$/ ending = Time.zone.at(query_params['end'].to_i) end unless query_params['expand'].blank? fail Dav::Exception::BadRequest, 'If you\'d like to expand recurrences, you must specify both a start= and end= parameter.' unless start && ending = true component_type = 'VEVENT' end if query_params.key?('componentType') unless %w(VEVENT VTODO VJOURNAL).include?(query_params['componentType']) fail Dav::Exception::BadRequest, "You are not allowed to search for components of type: #{query_params['componentType']} here" end component_type = query_params['componentType'] end format = Http::Util.negotiate( request.header('Accept'), [ 'text/calendar', 'application/calendar+json' ] ) if query_params.key?('accept') if query_params['accept'] == 'application/calendar+json' || query_params['accept'] == 'jcal' format = 'application/calendar+json' end end format = 'text/calendar' if format.blank? generate_response(path, start, ending, , component_type, format, properties, response) # Returning false to break the event chain false end |
#merge_objects(properties, input_objects) ⇒ Object
Merges all calendar objects, and builds one big iCalendar blob.
249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 |
# File 'lib/tilia/cal_dav/ics_export_plugin.rb', line 249 def merge_objects(properties, input_objects) calendar = VObject::Component::VCalendar.new calendar['VERSION'] = '2.0' if Dav::Server.expose_version calendar['PRODID'] = "-//TiliaDAV//TiliaDAV #{Dav::Version::VERSION}//EN" else calendar['PRODID'] = '-//SabreDAV//SabreDAV//EN' end if properties.key?('{DAV:}displayname') calendar['X-WR-CALNAME'] = properties['{DAV:}displayname'] end if properties.key?('{http://apple.com/ns/ical/}calendar-color') calendar['X-APPLE-CALENDAR-COLOR'] = properties['{http://apple.com/ns/ical/}calendar-color'] end collected_timezones = [] timezones = [] objects = [] input_objects.each do |_href, input_object| node_comp = VObject::Reader.read(input_object) node_comp.children.each do |child| case child.name when 'VEVENT', 'VTODO', 'VJOURNAL' objects << child.clone # VTIMEZONE is special, because we need to filter out the duplicates when 'VTIMEZONE' # Naively just checking tzid. next if collected_timezones.include?(child['TZID'].to_s) timezones << child.clone collected_timezones << child['TZID'].to_s end end # Destroy circular references to PHP will GC the object. node_comp.destroy node_comp = nil end timezones.each { |tz| calendar.add(tz) } objects.each { |obj| calendar.add(obj) } calendar end |
#plugin_info ⇒ Object
Returns a bunch of meta-data about the plugin.
Providing this information is optional, and is mainly displayed by the Browser plugin.
The description key in the returned array may contain html and will not be sanitized.
318 319 320 321 322 323 324 |
# File 'lib/tilia/cal_dav/ics_export_plugin.rb', line 318 def plugin_info { 'name' => plugin_name, 'description' => 'Adds the ability to export CalDAV calendars as a single iCalendar file.', 'link' => 'http://sabre.io/dav/ics-export-plugin/' } end |
#plugin_name ⇒ Object
Returns a plugin name.
Using this name other plugins will be able to access other plugins using SabreDAVServer::getPlugin
305 306 307 |
# File 'lib/tilia/cal_dav/ics_export_plugin.rb', line 305 def plugin_name 'ics-export' end |
#setup(server) ⇒ Object
Initializes the plugin and registers event handlers
42 43 44 45 46 47 48 49 50 51 52 53 54 55 |
# File 'lib/tilia/cal_dav/ics_export_plugin.rb', line 42 def setup(server) @server = server @server.on('method:GET', method(:http_get), 90) @server.on( 'browserButtonActions', lambda do |path, node, actions| if node.is_a?(ICalendar) actions.value += '<a href="' actions.value += CGI.escapeHTML(path) actions.value += '?export"><span class="oi" data-glyph="calendar"></span></a>' end end ) end |