agcaldav 0.2.1 → 0.2.2

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.
data/README.md CHANGED
@@ -27,23 +27,47 @@ Alternatively, the proxy parameters can be specified:
27
27
 
28
28
  result = cal.create_event(:start => "2012-12-29 10:00", :end => "2012-12-30 12:00", :title => "12345", :description => "sdkvjsdf sdkf sdkfj sdkf dsfj")
29
29
 
30
- Determine Event UID:
30
+ Analyze result:
31
+
32
+ >> result.class
33
+ => Icalendar::Calendar
34
+
35
+ >> result.events.count
36
+ => 1
37
+
38
+ >> result.events.first
39
+ => #<Icalendar::Event:0x007ff653b47520 @name="VEVENT", @components={}, @properties={"sequence"=>0, "dtstamp"=>#<DateTime: 2012-12-30T19:59:04+00:00 (26527957193/10800,0/1,2299161)>, "description"=>"sdkvjsdf sdkf sdkfj sdkf dsfj", "dtend"=>#<DateTime: 2012-12-30T12:00:00+00:00 (2456292/1,0/1,2299161)>, "dtstart"=>#<DateTime: 2012-12-29T10:00:00+00:00 (29475491/12,0/1,2299161)>, "summary"=>"12345", "uid"=>"e795c480-34e0-0130-7d1d-109add70606c", "x-radicale_name"=>"e795c480-34e0-0130-7d1d-109add70606c.ics"}>
31
40
 
32
- result[:uid]
41
+ get UID of this Event:
42
+ >> result.events.first.uid
43
+ => "e795c480-34e0-0130-7d1d-109add70606c"
33
44
 
34
45
 
35
46
  Find Event:
36
47
 
37
- r = cal.find_event(result[:uid])
48
+ r = cal.find_event("e795c480-34e0-0130-7d1d-109add70606c")
49
+
50
+ >> result.class
51
+ => Icalendar::Calendar
38
52
 
39
53
 
40
54
  Find Events within time interval:
41
55
 
42
56
  result = cal.find_events(:start => "2012-10-01 08:00", :end => "2013-01-01")
43
- #TODO.... (no XML -> Icalendar with multiple events....)
44
57
 
45
58
 
59
+ ####TODO's
60
+
61
+ ###############################################################
62
+ # #
63
+ # TODO : #
64
+ # 1. find and notify if overlapping events #
65
+ # 2. "create_event" check for UUID is really unique #
66
+ # 3. errorhandling & code cleanup #
67
+ # #
68
+ ###############################################################
46
69
 
47
- ... next tomorrow ...
48
70
 
71
+ ####Licence
49
72
 
73
+ -> MIT
@@ -1,152 +1,159 @@
1
1
  module AgCalDAV
2
- class Client
3
- include Icalendar
4
- attr_accessor :host, :port, :url, :user, :password, :ssl
5
-
6
- def format=( fmt )
7
- @format = fmt
8
- end
9
-
10
- def format
11
- @format ||= Format::Debug.new
12
- end
13
-
14
- def initialize( data )
15
- unless data[:proxy_uri].nil?
16
- proxy_uri = URI(data[:proxy_uri])
17
- @proxy_host = proxy_uri.host
18
- @proxy_port = proxy_uri.port.to_i
19
- end
20
- uri = URI(data[:uri])
21
- @host = uri.host
22
- @port = uri.port.to_i
23
- @url = uri.path
24
- @user = data[:user]
25
- @password = data[:password]
26
- @ssl = uri.scheme == 'https'
27
- end
28
-
29
- def __create_http
30
- if @proxy_uri.nil?
31
- http = Net::HTTP.new(@host, @port)
32
- else
33
- http = Net::HTTP.new(@host, @port, @proxy_host, @proxy_port)
34
- end
35
- if @ssl
36
- http.use_ssl = @ssl
37
- http.verify_mode = OpenSSL::SSL::VERIFY_NONE
38
- end
39
- http
40
- end
41
-
42
- def find_events data
43
- datetime_start = data[:start]
44
- datetime_stop = data[:end]
45
- res = nil
46
- __create_http.start {|http|
47
- req = Net::HTTP::Report.new(@url, initheader = {'Content-Type'=>'application/xml'} )
48
- req.basic_auth @user, @password
49
- req.body = AgCalDAV::Request::ReportVEVENT.new(DateTime.parse(datetime_start).strftime("%Y%m%dT%H%M"),
50
- DateTime.parse(datetime_stop).strftime("%Y%m%dT%H%M") ).to_xml
51
- res = http.request( req )
52
- }
53
- format.parse_calendar( res.body ) #TODO
54
- #result = Icalendar.parse(res.body)
55
- end
56
-
57
- def find_event uuid
58
- res = nil
59
- __create_http.start {|http|
60
- req = Net::HTTP::Get.new("#{@url}/#{uuid}.ics")
61
- req.basic_auth @user, @password
62
- res = http.request( req )
63
- }
64
- #raise AuthenticationError if res.code.to_i == 401
65
- #raise APIError if res.code.to_i >= 500
66
- result = Icalendar.parse(res.body)
67
- result
68
- end
69
-
70
- def delete_event uuid
71
- __create_http.start {|http|
72
- req = Net::HTTP::Delete.new("#{@url}/#{uuid}.ics")
73
- req.basic_auth @user, @password
74
- res = http.request( req )
75
- }
76
- end
77
-
78
- def create_event event
79
- c = Calendar.new
80
- uuid = UUID.new.generate
81
- c.event do
82
- uid uuid # still a BUG
83
- dtstart DateTime.parse(event[:start])
84
- dtend DateTime.parse(event[:end])
85
- duration event[:duration]
86
- summary event[:title]
87
- description event[:description]
88
- klass event[:accessibility] #PUBLIC, PRIVATE, CONFIDENTIAL
89
- location event[:location]
90
- geo_location event[:geo_location]
91
- status event[:status]
92
- end
93
- c.publish
94
- c.event.uid = uuid
95
- cstring = c.to_ical
96
- res = nil
97
- http = Net::HTTP.new(@host, @port)
98
- __create_http.start { |http|
99
- req = Net::HTTP::Put.new("#{@url}/#{uuid}.ics")
100
- req['Content-Type'] = 'text/calendar'
101
- req.basic_auth @user, @password
102
- req.body = cstring
103
- res = http.request( req )
104
- }
105
- raise AuthenticationError if res.code.to_i == 401
106
- raise APIError if res.code.to_i >= 500
107
- {:uid => uuid, :cal => c, :cal_string => cstring, :response_code => res.code} #TODO
108
- end
109
-
110
- def add_alarm tevent, altCal="Calendar"
111
- # FIXME create icalendar event -> cal.event.new (tevent)
112
-
113
- # TODO
114
-
115
-
116
-
117
-
118
- end
119
-
120
- def update event
121
- # FIXME old one not neat
122
-
123
- # TODO
124
- end
125
-
126
- def todo
127
- res = nil
128
- __create_http.start {|http|
129
- req = Net::HTTP::Report.new(@url, initheader = {'Content-Type'=>'application/xml'} )
130
- req.basic_auth @user, @password
131
- req.body = AgCalDAV::Request::ReportVTODO.new.to_xml
132
- res = http.request( req )
133
- }
134
- # FIXME: process HTTP code
135
- format.parse_todo( res.body )
136
- end
137
-
138
- def filterTimezone( vcal )
139
- data = ""
140
- inTZ = false
141
- vcal.split("\n").each{ |l|
142
- inTZ = true if l.index("BEGIN:VTIMEZONE")
143
- data << l+"\n" unless inTZ
144
- inTZ = false if l.index("END:VTIMEZONE")
145
- }
146
- return data
147
- end
2
+ class Client
3
+ include Icalendar
4
+ attr_accessor :host, :port, :url, :user, :password, :ssl
5
+
6
+ def format=( fmt )
7
+ @format = fmt
8
+ end
9
+
10
+ def format
11
+ @format ||= Format::Debug.new
12
+ end
13
+
14
+ def initialize( data )
15
+ unless data[:proxy_uri].nil?
16
+ proxy_uri = URI(data[:proxy_uri])
17
+ @proxy_host = proxy_uri.host
18
+ @proxy_port = proxy_uri.port.to_i
19
+ end
20
+ uri = URI(data[:uri])
21
+ @host = uri.host
22
+ @port = uri.port.to_i
23
+ @url = uri.path
24
+ @user = data[:user]
25
+ @password = data[:password]
26
+ @ssl = uri.scheme == 'https'
27
+ end
28
+
29
+ def __create_http
30
+ if @proxy_uri.nil?
31
+ http = Net::HTTP.new(@host, @port)
32
+ else
33
+ http = Net::HTTP.new(@host, @port, @proxy_host, @proxy_port)
34
+ end
35
+ if @ssl
36
+ http.use_ssl = @ssl
37
+ http.verify_mode = OpenSSL::SSL::VERIFY_NONE
38
+ end
39
+ http
40
+ end
41
+
42
+ def find_events data
43
+ result = ""
44
+ res = nil
45
+ __create_http.start {|http|
46
+ req = Net::HTTP::Report.new(@url, initheader = {'Content-Type'=>'application/xml'} )
47
+ req.basic_auth @user, @password
48
+ req.body = AgCalDAV::Request::ReportVEVENT.new(DateTime.parse(data[:start]).strftime("%Y%m%dT%H%M"),
49
+ DateTime.parse(data[:end]).strftime("%Y%m%dT%H%M") ).to_xml
50
+ res = http.request(req)
51
+ s = res.body
52
+ result = ""
53
+ xml = REXML::Document.new(s)
54
+ REXML::XPath.each( xml, '//c:calendar-data/', {"c"=>"urn:ietf:params:xml:ns:caldav"} ){|c| result << c.text}
55
+ r = Icalendar.parse(result)
56
+ r.first
57
+
58
+ }
59
+
60
+
61
+ end
62
+
63
+ def find_event uuid
64
+ res = nil
65
+ __create_http.start {|http|
66
+ req = Net::HTTP::Get.new("#{@url}/#{uuid}.ics")
67
+ req.basic_auth @user, @password
68
+ res = http.request( req )
69
+ }
70
+ raise AuthenticationError if res.code.to_i == 401
71
+ raise APIError if res.code.to_i >= 500
72
+ r = Icalendar.parse(res.body)
73
+ r.first
74
+ end
75
+
76
+ def delete_event uuid
77
+ __create_http.start {|http|
78
+ req = Net::HTTP::Delete.new("#{@url}/#{uuid}.ics")
79
+ req.basic_auth @user, @password
80
+ res = http.request( req )
81
+ }
82
+ end
83
+
84
+ def create_event event
85
+ c = Calendar.new
86
+ uuid = UUID.new.generate
87
+ c.event do
88
+ uid uuid # still a BUG
89
+ dtstart DateTime.parse(event[:start])
90
+ dtend DateTime.parse(event[:end])
91
+ duration event[:duration]
92
+ summary event[:title]
93
+ description event[:description]
94
+ klass event[:accessibility] #PUBLIC, PRIVATE, CONFIDENTIAL
95
+ location event[:location]
96
+ geo_location event[:geo_location]
97
+ status event[:status]
98
+ end
99
+ c.publish
100
+ c.event.uid = uuid
101
+ cstring = c.to_ical
102
+ res = nil
103
+ http = Net::HTTP.new(@host, @port)
104
+ __create_http.start { |http|
105
+ req = Net::HTTP::Put.new("#{@url}/#{uuid}.ics")
106
+ req['Content-Type'] = 'text/calendar'
107
+ req.basic_auth @user, @password
108
+ req.body = cstring
109
+ res = http.request( req )
110
+ }
111
+ raise AuthenticationError if res.code.to_i == 401
112
+ raise APIError if res.code.to_i >= 500
113
+ find_event uuid
114
+ #{:uid => uuid, :cal => c, :cal_string => cstring, :response_code => res.code} #TODO
115
+ end
116
+
117
+ def add_alarm tevent, altCal="Calendar"
118
+ # FIXME create icalendar event -> cal.event.new (tevent)
119
+
120
+ # TODO
121
+
122
+
123
+
124
+
148
125
  end
149
126
 
127
+ def update event
128
+ # FIXME old one not neat
129
+
130
+ # TODO
131
+ end
132
+
133
+ def todo
134
+ res = nil
135
+ __create_http.start {|http|
136
+ req = Net::HTTP::Report.new(@url, initheader = {'Content-Type'=>'application/xml'} )
137
+ req.basic_auth @user, @password
138
+ req.body = AgCalDAV::Request::ReportVTODO.new.to_xml
139
+ res = http.request( req )
140
+ }
141
+ # FIXME: process HTTP code
142
+ format.parse_todo( res.body )
143
+ end
144
+
145
+ def filterTimezone( vcal )
146
+ data = ""
147
+ inTZ = false
148
+ vcal.split("\n").each{ |l|
149
+ inTZ = true if l.index("BEGIN:VTIMEZONE")
150
+ data << l+"\n" unless inTZ
151
+ inTZ = false if l.index("END:VTIMEZONE")
152
+ }
153
+ return data
154
+ end
155
+ end
156
+
150
157
  class AgCalDAVError < StandardError
151
158
  end
152
159
  class AuthenticationError < AgCalDAVError; end
@@ -0,0 +1,121 @@
1
+
2
+
3
+ module Icalendar
4
+ # A Event calendar component is a grouping of component
5
+ # properties, and possibly including Alarm calendar components, that
6
+ # represents a scheduled amount of time on a calendar. For example, it
7
+ # can be an activity; such as a one-hour long, department meeting from
8
+ # 8:00 AM to 9:00 AM, tomorrow. Generally, an event will take up time
9
+ # on an individual calendar.
10
+ class Event < Component
11
+ ical_component :alarms
12
+
13
+ ## Single instance properties
14
+
15
+ # Access classification (PUBLIC, PRIVATE, CONFIDENTIAL...)
16
+ ical_property :ip_class, :klass
17
+
18
+ # Date & time of creation
19
+ ical_property :created
20
+
21
+ # Complete description of the calendar component
22
+ ical_property :description
23
+
24
+ attr_accessor :tzid
25
+
26
+ # Specifies date-time when calendar component begins
27
+ ical_property :dtstart, :start
28
+
29
+ # Latitude & longitude for specified activity
30
+ ical_property :geo, :geo_location
31
+
32
+ # Date & time this item was last modified
33
+ ical_property :last_modified
34
+
35
+ # Specifies the intended venue for this activity
36
+ ical_property :location
37
+
38
+ # Defines organizer of this item
39
+ ical_property :organizer
40
+
41
+ # Defines relative priority for this item (1-9... 1 = best)
42
+ ical_property :priority
43
+
44
+ # Indicate date & time when this item was created
45
+ ical_property :dtstamp, :timestamp
46
+
47
+ # Revision sequence number for this item
48
+ ical_property :sequence, :seq
49
+
50
+ # Defines overall status or confirmation of this item
51
+ ical_property :status
52
+ ical_property :summary
53
+ ical_property :transp, :transparency
54
+
55
+ # Defines a persistent, globally unique id for this item
56
+ ical_property :uid, :unique_id
57
+
58
+ # Defines a URL associated with this item
59
+ ical_property :url
60
+ ical_property :recurrence_id, :recurid
61
+
62
+ ## Single but mutually exclusive properties (Not testing though)
63
+
64
+ # Specifies a date and time that this item ends
65
+ ical_property :dtend, :end
66
+
67
+ # Specifies a positive duration time
68
+ ical_property :duration
69
+
70
+ ## Multi-instance properties
71
+
72
+ # Associates a URI or binary blob with this item
73
+ ical_multi_property :attach, :attachment, :attachments
74
+
75
+ # Defines an attendee for this calendar item
76
+ ical_multiline_property :attendee, :attendee, :attendees
77
+
78
+ # Defines the categories for a calendar component (school, work...)
79
+ ical_multi_property :categories, :category, :categories
80
+
81
+ # Simple comment for the calendar user.
82
+ ical_multi_property :comment, :comment, :comments
83
+
84
+ # Contact information associated with this item.
85
+ ical_multi_property :contact, :contact, :contacts
86
+ ical_multi_property :exdate, :exception_date, :exception_dates
87
+ ical_multi_property :exrule, :exception_rule, :exception_rules
88
+ ical_multi_property :rstatus, :request_status, :request_statuses
89
+
90
+ # Used to represent a relationship between two calendar items
91
+ ical_multi_property :related_to, :related_to, :related_tos
92
+ ical_multi_property :resources, :resource, :resources
93
+
94
+ # Used with the UID & SEQUENCE to identify a specific instance of a
95
+ # recurring calendar item.
96
+ ical_multi_property :rdate, :recurrence_date, :recurrence_dates
97
+ ical_multi_property :rrule, :recurrence_rule, :recurrence_rules
98
+
99
+ def initialize()
100
+ super("VEVENT")
101
+
102
+ # Now doing some basic initialization
103
+ sequence 0
104
+ timestamp DateTime.now
105
+ end
106
+
107
+ def alarm(&block)
108
+ a = Alarm.new
109
+ self.add a
110
+
111
+ a.instance_eval(&block) if block
112
+
113
+ a
114
+ end
115
+
116
+ def occurrences_starting(time)
117
+ recurrence_rules.first.occurrences_of_event_starting(self, time)
118
+ end
119
+
120
+ end
121
+ end
@@ -1,64 +1,60 @@
1
1
  module AgCalDAV
2
- module Format
3
- class Raw
4
- def method_missing(m, *args, &block)
5
- return *args
6
- end
7
- end
2
+ module Format
3
+ class Raw
4
+ def method_missing(m, *args, &block)
5
+ return *args
6
+ end
7
+ end
8
+
9
+ class Debug < Raw
10
+ end
8
11
 
9
- class Debug < Raw
10
- end
12
+ class Pretty < Raw
13
+ def parse_calendar(s)
14
+ result = ""
15
+ xml = REXML::Document.new(s)
16
+ puts "-"*10
17
+ p s
18
+ puts "-"*10
19
+ REXML::XPath.each( xml, '//c:calendar-data/', {"c"=>"urn:ietf:params:xml:ns:caldav"} ){|c| result << c.text}
20
+ r = Icalendar.parse(result)
11
21
 
12
- class Pretty < Raw
13
- def parse_calendar( body )
14
- result = []
15
- xml = REXML::Document.new( res.body )
16
- REXML::XPath.each( xml, '//c:calendar-data/', { "c"=>"urn:ietf:params:xml:ns:caldav"} ){ |c|
17
- result += parse_events( c.text )
18
- }
19
- return result
20
- end
22
+ puts "."*10
23
+ p r
24
+ puts "."*10
25
+ r
26
+ end
21
27
 
22
- def parse_todo( body )
23
- result = []
24
- xml = REXML::Document.new( body )
25
- REXML::XPath.each( xml, '//c:calendar-data/', { "c"=>"urn:ietf:params:xml:ns:caldav"} ){ |c|
26
- p c.text
27
- p parse_tasks( c.text )
28
- result += parse_tasks( c.text )
29
- }
30
- return result
31
- end
28
+ def parse_todo( body )
29
+ result = []
30
+ xml = REXML::Document.new( body )
31
+ REXML::XPath.each( xml, '//c:calendar-data/', { "c"=>"urn:ietf:params:xml:ns:caldav"} ){ |c|
32
+ p c.text
33
+ p parse_tasks( c.text )
34
+ result += parse_tasks( c.text )
35
+ }
36
+ return result
37
+ end
32
38
 
33
- def parse_tasks( vcal )
34
- return_tasks = Array.new
35
- cals = Icalendar.parse(vcal)
36
- cals.each { |tcal|
37
- tcal.todos.each { |ttask| # FIXME
38
- return_tasks << ttask
39
- }
40
- }
41
- return return_tasks
42
- end
39
+ def parse_tasks( vcal )
40
+ return_tasks = Array.new
41
+ cals = Icalendar.parse(vcal)
42
+ cals.each { |tcal|
43
+ tcal.todos.each { |ttask| # FIXME
44
+ return_tasks << ttask
45
+ }
46
+ }
47
+ return return_tasks
48
+ end
43
49
 
44
- def parse_events( vcal )
45
- return_events = Array.new
46
- cals = Icalendar.parse(vcal)
47
- cals.each { |tcal|
48
- tcal.events.each { |tevent|
49
- if tevent.recurrence_id.to_s.empty? # skip recurring events
50
- return_events << tevent
51
- end
52
- }
53
- }
54
- return return_events
55
- end
50
+ def parse_events( vcal )
51
+ Icalendar.parse(vcal)
52
+ end
56
53
 
57
- def parse_single( body )
58
- # FIXME: parse event/todo/vcard
59
- parse_events( body )
60
- end
61
- end
54
+ def parse_single( body )
55
+ # FIXME: parse event/todo/vcard
56
+ parse_events( body )
57
+ end
62
58
  end
59
+ end
63
60
  end
64
-
@@ -1,3 +1,3 @@
1
1
  module AgCalDAV
2
- VERSION="0.2.1"
2
+ VERSION="0.2.2"
3
3
  end
data/lib/agcaldav.rb CHANGED
@@ -6,14 +6,6 @@ require 'icalendar'
6
6
  require 'time'
7
7
  require 'date'
8
8
 
9
- ['client.rb', 'request.rb', 'net.rb', 'query.rb', 'filter.rb', 'format.rb'].each do |f|
9
+ ['client.rb', 'request.rb', 'net.rb', 'query.rb', 'filter.rb', 'event.rb', 'format.rb'].each do |f|
10
10
  require File.join( File.dirname(__FILE__), 'agcaldav', f )
11
- end
12
-
13
- class Event
14
- attr_accessor :uid, :created, :dtstart, :dtend, :lastmodified, :summary, :description, :name, :action, :to_ical
15
- end
16
-
17
- class Todo
18
- attr_accessor :uid, :created, :summary, :dtstart, :status, :completed
19
11
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: agcaldav
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.1
4
+ version: 0.2.2
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -86,6 +86,7 @@ files:
86
86
  - agcaldav.gemspec
87
87
  - lib/agcaldav.rb
88
88
  - lib/agcaldav/client.rb
89
+ - lib/agcaldav/event.rb
89
90
  - lib/agcaldav/filter.rb
90
91
  - lib/agcaldav/format.rb
91
92
  - lib/agcaldav/net.rb