googlecalendar 0.0.6 → 1.0.0

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.
@@ -0,0 +1,23 @@
1
+ module Googlecalendar
2
+ class Calendar
3
+ attr_accessor :product_id, :version, :scale, :method, :events
4
+
5
+ def add(event)
6
+ # create events if it doesn't exist
7
+ @events ||= []
8
+ @events.push event
9
+ end
10
+
11
+ def to_s
12
+ data = "########## calendar ##########\n"
13
+ data << 'version: ' + @version.to_s + "\n"
14
+ data << 'scale: ' + @scale.to_s + "\n"
15
+ data << 'method: ' + @method.to_s + "\n"
16
+ data << 'number of events: ' + @events.size.to_s + "\n"
17
+ @events.each do |event|
18
+ data << event.to_s
19
+ end
20
+ return data
21
+ end
22
+ end
23
+ end # module Googlecalendar
@@ -0,0 +1,52 @@
1
+ require 'net/http'
2
+ # require 'net/https'
3
+ # require 'uri'
4
+
5
+ def parse(data)
6
+ parser = Googlecalendar::ICALParser.new
7
+ parser.parse(data)
8
+ end
9
+
10
+ def scan(ical_url, base_url='www.google.com')
11
+ Net::HTTP.start(base_url, 80) do |http|
12
+ response, data = http.get(ical_url)
13
+ case response
14
+ when Net::HTTPSuccess, Net::HTTPRedirection
15
+ return data
16
+ else
17
+ response.error!
18
+ end
19
+ end
20
+ end
21
+
22
+ def scan_proxy(proxy_addr, proxy_port, ical_url, base_url='www.google.com')
23
+ Net::HTTP::Proxy(proxy_addr, proxy_port).start(base_url, 80) do |http|
24
+ response, data = http.get(ical_url)
25
+ case response
26
+ when Net::HTTPSuccess, Net::HTTPRedirection
27
+ return data
28
+ else
29
+ response.error!
30
+ end
31
+ end
32
+ end
33
+
34
+ # Builder DSL
35
+ def text(calendar, filename)
36
+ dirname = File.dirname(filename)
37
+ Dir.mkdir(dirname) unless File.exists?(dirname)
38
+ text_builder = Googlecalendar::TextBuilder.new
39
+ text_builder.calendar = calendar
40
+ text_builder.filename = filename
41
+ text_builder.export
42
+ end
43
+
44
+ def html(calendar, filename)
45
+ dirname = File.dirname(filename)
46
+ Dir.mkdir(dirname) unless File.exists?(dirname)
47
+ html_builder = Googlecalendar::HtmlBuilder.new
48
+ html_builder.calendar = calendar
49
+ html_builder.filename = filename
50
+ html_builder.date_format = "%d-%m-%y" #"%F"#"%A %B %d %Y" #"%d-%m-%Y"
51
+ html_builder.export
52
+ end
@@ -0,0 +1,32 @@
1
+ module Googlecalendar
2
+ class Event
3
+ attr_accessor :start_date, :end_date, :time_stamp, :class_name, :created, :last_modified, :status, :summary, :description, :location, :rrule
4
+
5
+ def to_s
6
+ data = "---------- event ----------\n"
7
+ data << 'start_date: ' + @start_date.to_s + "\n"
8
+ data << 'end_date: ' + @end_date.to_s + "\n"
9
+ data << 'time_stamp: ' + @time_stamp.to_s + "\n"
10
+ data << 'class_name: ' + @class_name.to_s + "\n"
11
+ data << 'created: ' + @created.to_s + "\n"
12
+ data << 'last_modified: ' + @last_modified.to_s + "\n"
13
+ data << 'status: ' + @status.to_s + "\n"
14
+ data << 'rrule: ' + @rrule.to_s + "\n"
15
+ data << 'summary: ' + @summary.to_s + "\n"
16
+ data << 'desription: ' + @desription.to_s + "\n"
17
+ data << 'location: ' + @location.to_s + "\n"
18
+ return data
19
+ end
20
+
21
+ # 'FREQ=WEEKLY;BYDAY=MO;WKST=MO'
22
+ def rrule_as_hash
23
+ array = @rrule.split(';')
24
+ hash = Hash.new
25
+ array.each do |item|
26
+ pair = item.split('=')
27
+ hash[pair[0]] = pair[1]
28
+ end
29
+ return hash
30
+ end
31
+ end # class Event
32
+ end # module Googlecalendar
@@ -0,0 +1,10 @@
1
+ module Googlecalendar
2
+ class GCalendar
3
+ attr_reader :title, :url
4
+
5
+ def initialize(title, url)
6
+ @title = title
7
+ @url = url
8
+ end
9
+ end # class GCalendar
10
+ end # module Googlecalendar
@@ -0,0 +1,200 @@
1
+ require 'net/http'
2
+ require 'net/https'
3
+ require 'uri'
4
+ require "rexml/document"
5
+
6
+ module Googlecalendar
7
+ # A ruby class to wrap calls to the Google Data API
8
+ #
9
+ # More informations
10
+ #
11
+ # Google calendar API: http://code.google.com/apis/calendar/developers_guide_protocol.html
12
+ class GData
13
+ attr_accessor :google_url
14
+
15
+ def initialize(google='www.google.com')
16
+ @calendars = []
17
+ @google_url = google
18
+ end
19
+
20
+ #Convinient method to create the conf file use in login_with_conf_file
21
+ #if you don't want to create it by hand
22
+ def self.create_conf_file(email, pwd)
23
+ p = {'email' => email, 'password' => pwd}
24
+ path = File.expand_path("~/.googlecalendar4ruby/google.yaml")
25
+ unless File.exists?(path)
26
+ puts "Creating file in #{path}"
27
+ Dir.mkdir(File.dirname(path))
28
+ end
29
+ f = File.new(path, File::CREAT|File::TRUNC|File::RDWR)
30
+ f << p.to_yaml
31
+ f.close
32
+ end
33
+
34
+ #Log into google data
35
+ #This method is basically the same as the login with user and password
36
+ #but it tries to find a ~/.googlecalendar4ruby/google.yml
37
+ #Use this if you don't want to hardcode your user/password in your .rb files
38
+ def login_with_conf_file(file='~/.googlecalendar4ruby/google.yaml')
39
+ path = File.expand_path(file)
40
+ if(File.exists?(path))
41
+ File.open(path) { |f| @yaml = YAML::load(f) }
42
+ else
43
+ GData::create_conf_file('REPLACE_WITH_YOUR_MAIL@gmail.com', 'REPLACE_WITH_YOUR_PASSWORD')
44
+ throw "Created a default file in: #{path}, you need to edit it !!"
45
+ end
46
+ email = @yaml['email']
47
+ pwd = @yaml['password']
48
+ login(email, pwd)
49
+ end # login
50
+
51
+ #Log into google data, this method needs to be call once before using other methods of the class
52
+ #* Email The user's email address.
53
+ #* Passwd The user's password.
54
+ #* source Identifies your client application. Should take the form companyName-applicationName-versionID
55
+ #*Warning* Replace the default value with something like:
56
+ #+companyName-applicationName-versionID+
57
+ def login(email, pwd, source='googlecalendar.rubyforge.org-googlecalendar-default')
58
+ # service The string cl, which is the service name for Google Calendar.
59
+ @user_id = email
60
+ response = Net::HTTPS.post_form(URI.parse("https://#{@google_url}/accounts/ClientLogin"),
61
+ { 'Email' => email,
62
+ 'Passwd' => pwd,
63
+ 'source' => source,
64
+ 'accountType' => 'HOSTED_OR_GOOGLE',
65
+ 'service' => 'cl'})
66
+ response.error! unless response.kind_of? Net::HTTPSuccess
67
+ @token = response.body.split(/=/).last
68
+ @headers = {
69
+ 'Authorization' => "GoogleLogin auth=#{@token}",
70
+ 'Content-Type' => 'application/atom+xml'
71
+ }
72
+ return @token
73
+ end # login
74
+
75
+ # Reset reminders
76
+ def reset_reminders(event)
77
+ event[:reminders] = ""
78
+ end
79
+
80
+ # Add a reminder to the event hash
81
+ #* reminderMinutes
82
+ #* reminderMethod [email, alert, sms, none]
83
+ def add_reminder(event, reminderMinutes, reminderMethod)
84
+ event[:reminders] = event[:reminders].to_s +
85
+ "<gd:reminder minutes='#{reminderMinutes}' method='#{reminderMethod}' />\n"
86
+ end
87
+
88
+ # Create a quick add event
89
+ #
90
+ # <tt>text = 'Tennis with John April 11 3pm-3:30pm'</tt>
91
+ #
92
+ # http://code.google.com/apis/calendar/developers_guide_protocol.html#CreatingQuickAdd
93
+ def quick_add(text)
94
+ content = <<EOF
95
+ <entry xmlns='http://www.w3.org/2005/Atom' xmlns:gCal='http://schemas.google.com/gCal/2005'>
96
+ <content type="html">#{text}</content>
97
+ <gCal:quickadd value="true"/>
98
+ </entry>
99
+ EOF
100
+ post_event(content)
101
+ end # quick_add
102
+
103
+ #'event' param is a hash containing
104
+ #* :title
105
+ #* :content
106
+ #* :author
107
+ #* :email
108
+ #* :where
109
+ #* :startTime '2007-06-06T15:00:00.000Z'
110
+ #* :endTime '2007-06-06T17:00:00.000Z'
111
+ #
112
+ # Use add_reminder(event, reminderMinutes, reminderMethod) method to add reminders
113
+ def new_event(event={},calendar = nil)
114
+ new_event = template(event)
115
+ post_event(new_event, calendar)
116
+ end
117
+
118
+ def post_event(xml, calendar = nil)
119
+ #Get calendar url
120
+ calendar_url = if calendar
121
+ get_calendars
122
+ find_calendar(calendar).url
123
+ else
124
+ # We will use user'default calendar in this case
125
+ '/calendar/feeds/default/private/full'
126
+ end
127
+
128
+ http = Net::HTTP.new(@google_url, 80)
129
+ response, data = http.post(calendar_url, xml, @headers)
130
+ case response
131
+ when Net::HTTPSuccess, Net::HTTPRedirection
132
+ redirect_response, redirect_data = http.post(response['location'], xml, @headers)
133
+ case response
134
+ when Net::HTTPSuccess, Net::HTTPRedirection
135
+ return redirect_response
136
+ else
137
+ response.error!
138
+ end
139
+ else
140
+ response.error!
141
+ end
142
+ end # post_event
143
+
144
+ # Retreive user's calendar urls.
145
+ def get_calendars
146
+ http = Net::HTTP.new(@google_url, 80)
147
+ response, data = http.get("http://#{@google_url}/calendar/feeds/" + @user_id, @headers)
148
+ case response
149
+ when Net::HTTPSuccess, Net::HTTPRedirection
150
+ redirect_response, redirect_data = http.get(response['location'], @headers)
151
+ case response
152
+ when Net::HTTPSuccess, Net::HTTPRedirection
153
+ doc = REXML::Document.new redirect_data
154
+ doc.elements.each('//entry')do |e|
155
+ title = e.elements['title'].text
156
+ url = e.elements['link'].attributes['href']
157
+ @calendars << GCalendar.new(title, url.sub!("http://#{@google_url}",''))
158
+ end
159
+ return redirect_response
160
+ else
161
+ response.error!
162
+ end
163
+ else
164
+ response.error!
165
+ end
166
+ end # get_calendars
167
+
168
+ def find_calendar(x)
169
+ @calendars.find {|c| c.title.match x}
170
+ end
171
+
172
+ # The atom event template to submit a new event
173
+ def template(event={})
174
+ content = <<EOF
175
+ <?xml version="1.0"?>
176
+ <entry xmlns='http://www.w3.org/2005/Atom'
177
+ xmlns:gd='http://schemas.google.com/g/2005'>
178
+ <category scheme='http://schemas.google.com/g/2005#kind'
179
+ term='http://schemas.google.com/g/2005#event'></category>
180
+ <title type='text'>#{event[:title]}</title>
181
+ <content type='text'>#{event[:content]}</content>
182
+ <author>
183
+ <name>#{event[:author]}</name>
184
+ <email>#{event[:email]}</email>
185
+ </author>
186
+ <gd:transparency
187
+ value='http://schemas.google.com/g/2005#event.opaque'>
188
+ </gd:transparency>
189
+ <gd:eventStatus
190
+ value='http://schemas.google.com/g/2005#event.confirmed'>
191
+ </gd:eventStatus>
192
+ <gd:where valueString='#{event[:where]}'></gd:where>
193
+ <gd:when startTime='#{event[:startTime]}' endTime='#{event[:endTime]}'>
194
+ #{event[:reminders]}
195
+ </gd:when>
196
+ </entry>
197
+ EOF
198
+ end # template
199
+ end # GData class
200
+ end # module Googlecalendar
@@ -0,0 +1,126 @@
1
+ module Googlecalendar
2
+ class ICALParser
3
+ attr_reader :calendar
4
+
5
+ def parse(data)
6
+ lines = data.split("\n")
7
+
8
+ reset_prefix
9
+ lines.each do |line|
10
+ handle_element(line)
11
+ end
12
+
13
+ return @calendar
14
+ end
15
+
16
+ # An ICal line consist of 2 part XXX: YYYY
17
+ # Get the first part of the line and after a small transformation call the appropriate method
18
+ # example:
19
+ # line is: VCALENDAR:BEGIN
20
+ # VERSION:VALUE
21
+ # method call: handle_vcalendar_version
22
+ # kind of work like a sax parser...
23
+ def handle_element(line)
24
+ pair = line.split(':', 2) # avoid problems when summary contains ':'
25
+ name = pair[0]
26
+ value = pair[1]
27
+ handler_method = @method_prefix + name.split(';')[0].tr('-', '_').downcase
28
+ if self.respond_to? handler_method
29
+ self.send(handler_method, value.chomp)
30
+ end
31
+ end
32
+
33
+ def reset_prefix
34
+ @method_prefix = "handle_"
35
+ end
36
+
37
+ def handle_begin(value)
38
+ if value == "VCALENDAR"
39
+ handle_vcalendar_begin(value)
40
+ elsif value == "VEVENT"
41
+ handle_vevent_begin(value)
42
+ end
43
+ end
44
+
45
+ def handle_vcalendar_end(value)
46
+ reset_prefix
47
+ end
48
+
49
+ def handle_vcalendar_begin(value)
50
+ @calendar = Calendar.new
51
+ @method_prefix = @method_prefix + value.downcase + "_"
52
+ end
53
+
54
+ # def handle_vcalendar_prodid(value)
55
+ # @calendar.product_id = value
56
+ # end
57
+
58
+ def handle_vcalendar_version(value)
59
+ @calendar.version = value
60
+ end
61
+
62
+ def handle_vcalendar_calscale(value)
63
+ @calendar.scale = value
64
+ end
65
+
66
+ def handle_vcalendar_method(value)
67
+ @calendar.method = value
68
+ # FIXME don't like to do this!
69
+ reset_prefix
70
+ end
71
+
72
+ def handle_vevent_begin(value)
73
+ event = Event.new
74
+ @calendar.add event
75
+ @method_prefix = @method_prefix + value.downcase + "_"
76
+ end
77
+
78
+ def handle_vevent_end(value)
79
+ reset_prefix
80
+ end
81
+
82
+ def handle_vevent_dtstart(value)
83
+ @calendar.events.last.start_date = Date.parse(value)
84
+ end
85
+
86
+ def handle_vevent_dtend(value)
87
+ @calendar.events.last.end_date = Date.parse(value)
88
+ end
89
+
90
+ def handle_vevent_dtstamp(value)
91
+ @calendar.events.last.time_stamp = DateTime.parse(value)
92
+ end
93
+
94
+ def handle_vevent_class(value)
95
+ @calendar.events.last.class_name = value
96
+ end
97
+
98
+ def handle_vevent_created(value)
99
+ @calendar.events.last.created = DateTime.parse(value)
100
+ end
101
+
102
+ def handle_vevent_last_modified(value)
103
+ @calendar.events.last.last_modified = DateTime.parse(value)
104
+ end
105
+
106
+ def handle_vevent_status(value)
107
+ @calendar.events.last.status = value
108
+ end
109
+
110
+ def handle_vevent_summary(value)
111
+ @calendar.events.last.summary = value
112
+ end
113
+
114
+ def handle_vevent_rrule(value)
115
+ @calendar.events.last.rrule = value
116
+ end
117
+
118
+ def handle_vevent_description(value)
119
+ @calendar.events.last.description = value
120
+ end
121
+
122
+ def handle_vevent_location(value)
123
+ @calendar.events.last.location = value
124
+ end
125
+ end # class ICALParser
126
+ end # module Googlecalendar