agcaldav 0.2.1 → 0.2.2

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