zimbra 0.0.4 → 0.0.5

Sign up to get free protection for your applications and to get access to all the features.
Files changed (53) hide show
  1. data/.gitignore +4 -0
  2. data/.irbrc +6 -0
  3. data/Gemfile +6 -0
  4. data/README +3 -2
  5. data/Rakefile +1 -0
  6. data/lib/zimbra.rb +31 -6
  7. data/lib/zimbra/appointment.rb +274 -0
  8. data/lib/zimbra/appointment/alarm.rb +101 -0
  9. data/lib/zimbra/appointment/attendee.rb +97 -0
  10. data/lib/zimbra/appointment/invite.rb +360 -0
  11. data/lib/zimbra/appointment/recur_exception.rb +83 -0
  12. data/lib/zimbra/appointment/recur_rule.rb +184 -0
  13. data/lib/zimbra/appointment/reply.rb +91 -0
  14. data/lib/zimbra/calendar.rb +27 -0
  15. data/lib/zimbra/delegate_auth_token.rb +49 -0
  16. data/lib/zimbra/ext/hash.rb +72 -0
  17. data/lib/zimbra/extra/date_helpers.rb +111 -0
  18. data/lib/zimbra/folder.rb +100 -0
  19. data/lib/zimbra/handsoap_account_service.rb +44 -0
  20. data/lib/zimbra/handsoap_service.rb +1 -1
  21. data/lib/zimbra/version.rb +3 -0
  22. data/spec/fixtures/xml_api_requests/appointments/create.xml +84 -0
  23. data/spec/fixtures/xml_api_responses/alarms/15_minutes_before.xml +26 -0
  24. data/spec/fixtures/xml_api_responses/alarms/using_all_intervals.xml +26 -0
  25. data/spec/fixtures/xml_api_responses/appointments/appointment_response_1.xml +40 -0
  26. data/spec/fixtures/xml_api_responses/attendees/one_attendee_and_one_reply.xml +27 -0
  27. data/spec/fixtures/xml_api_responses/attendees/three_attendees_response_1.xml +30 -0
  28. data/spec/fixtures/xml_api_responses/multiple_invites/recurring_with_exceptions.xml +109 -0
  29. data/spec/fixtures/xml_api_responses/recur_rules/day_27_of_every_2_months.xml +27 -0
  30. data/spec/fixtures/xml_api_responses/recur_rules/every_2_days.xml +26 -0
  31. data/spec/fixtures/xml_api_responses/recur_rules/every_3_weeks_on_tuesday_and_friday.xml +30 -0
  32. data/spec/fixtures/xml_api_responses/recur_rules/every_day_50_instances.xml +27 -0
  33. data/spec/fixtures/xml_api_responses/recur_rules/every_monday_wednesday_friday.xml +31 -0
  34. data/spec/fixtures/xml_api_responses/recur_rules/every_tuesday.xml +29 -0
  35. data/spec/fixtures/xml_api_responses/recur_rules/every_weekday_with_end_date.xml +34 -0
  36. data/spec/fixtures/xml_api_responses/recur_rules/every_year_on_february_2.xml +28 -0
  37. data/spec/fixtures/xml_api_responses/recur_rules/first_day_of_every_month.xml +36 -0
  38. data/spec/fixtures/xml_api_responses/recur_rules/first_monday_of_every_february.xml +31 -0
  39. data/spec/fixtures/xml_api_responses/recur_rules/first_weekend_day_of_every_month.xml +31 -0
  40. data/spec/fixtures/xml_api_responses/recur_rules/last_day_of_every_month.xml +36 -0
  41. data/spec/fixtures/xml_api_responses/recur_rules/second_day_of_every_2_months.xml +36 -0
  42. data/spec/fixtures/xml_api_responses/recur_rules/second_wednesday_of_every_month.xml +29 -0
  43. data/spec/fixtures/xml_api_responses/recur_rules/weekly_with_an_exception.xml +44 -0
  44. data/spec/spec_helper.rb +32 -0
  45. data/spec/zimbra/acl_spec.rb +11 -0
  46. data/spec/zimbra/appointment/alarm_spec.rb +33 -0
  47. data/spec/zimbra/appointment/invite_spec.rb +62 -0
  48. data/spec/zimbra/appointment/recur_rule_spec.rb +307 -0
  49. data/spec/zimbra/appointment_spec.rb +175 -0
  50. data/spec/zimbra/common_elements_spec.rb +33 -0
  51. data/spec/zimbra/distribution_list_spec.rb +54 -0
  52. data/zimbra.gemspec +28 -0
  53. metadata +165 -68
@@ -0,0 +1,111 @@
1
+ module Zimbra
2
+ class DateHelpers
3
+ class Frequency
4
+ FREQUENCIES = [
5
+ { name: :secondly, zimbra_name: 'SEC', abbreviations: [] },
6
+ { name: :minutely, zimbra_name: 'MIN', abbreviations: [] },
7
+ { name: :hourly, zimbra_name: 'HOU', abbreviations: [] },
8
+ { name: :daily, zimbra_name: 'DAI', abbreviations: [] },
9
+ { name: :weekly, zimbra_name: 'WEE', abbreviations: [] },
10
+ { name: :monthly, zimbra_name: 'MON', abbreviations: [] },
11
+ { name: :yearly, zimbra_name: 'YEA', abbreviations: [] }
12
+ ]
13
+
14
+ class << self
15
+ def all
16
+ @all ||= FREQUENCIES.inject([]) do |frequencies, data|
17
+ frequencies << new(data)
18
+ end
19
+ end
20
+
21
+ def find(name_or_abbreviation)
22
+ all.find { |frequency| frequency.match?(name_or_abbreviation) }
23
+ end
24
+ end
25
+
26
+ attr_accessor :name, :zimbra_name, :abbreviations
27
+
28
+ def initialize(args = {})
29
+ @name = args[:name]
30
+ @zimbra_name = args[:zimbra_name]
31
+ @abbreviations = args[:abbreviations]
32
+ end
33
+
34
+ def match?(name_or_abbreviation)
35
+ downcased_matcher = name_or_abbreviation.to_s.downcase
36
+ ([name.to_s, zimbra_name.to_s] + abbreviations).map(&:downcase).include?(downcased_matcher)
37
+ end
38
+
39
+ def to_sym
40
+ name.downcase.to_sym
41
+ end
42
+ end
43
+
44
+ class WeekDay
45
+ WEEK_DAYS = [
46
+ {
47
+ id: 1, name: :Sunday, zimbra_name: 'SU',
48
+ abbreviations: ['su', 'sun']
49
+ },
50
+ {
51
+ id: 2, name: :Monday, zimbra_name: 'MO',
52
+ abbreviations: ['mo', 'mon']
53
+ },
54
+ {
55
+ id: 3, name: :Tuesday, zimbra_name: 'TU',
56
+ abbreviations: ['tu', 'tue']
57
+ },
58
+ {
59
+ id: 4, name: :Wednesday, zimbra_name: 'WE',
60
+ abbreviations: ['we', 'wed']
61
+ },
62
+ {
63
+ id: 5, name: :Thursday, zimbra_name: 'TH',
64
+ abbreviations: ['th', 'thu', 'thur', 'thurs']
65
+ },
66
+ {
67
+ id: 6, name: :Friday, zimbra_name: 'FR',
68
+ abbreviations: ['fr', 'fri']
69
+ },
70
+ {
71
+ id: 7, name: :Saturday, zimbra_name: 'SA',
72
+ abbreviations: ['sa', 'sat']
73
+ }
74
+ ] unless const_defined?(:WEEK_DAYS)
75
+
76
+ class << self
77
+ def all
78
+ @all ||= WEEK_DAYS.inject([]) do |week_days, data|
79
+ week_days << new(data)
80
+ end
81
+ end
82
+
83
+ def find(id_name_or_abbreviation)
84
+ all.find { |week_day| week_day.match?(id_name_or_abbreviation) }
85
+ end
86
+ end
87
+
88
+ attr_accessor :id, :name, :abbreviations, :zimbra_name
89
+
90
+ def initialize(args = {})
91
+ @id = args[:id]
92
+ @name = args[:name]
93
+ @zimbra_name = args[:zimbra_name]
94
+ @abbreviations = args[:abbreviations]
95
+ end
96
+
97
+ def match?(id_name_or_abbreviation)
98
+ if id_name_or_abbreviation.is_a?(Fixnum)
99
+ id_name_or_abbreviation == id
100
+ else
101
+ downcased_matcher = id_name_or_abbreviation.to_s.downcase
102
+ ([name.to_s, zimbra_name.to_s] + abbreviations).map(&:downcase).include?(downcased_matcher)
103
+ end
104
+ end
105
+
106
+ def to_sym
107
+ name.downcase.to_sym
108
+ end
109
+ end
110
+ end
111
+ end
@@ -0,0 +1,100 @@
1
+ # http://files.zimbra.com/docs/soap_api/8.0.4/soap-docs-804/api-reference/zimbraMail/GetFolder.html
2
+ module Zimbra
3
+ class Folder
4
+ class << self
5
+ def all
6
+ FolderService.all
7
+ end
8
+
9
+ def find_all_by_view(view)
10
+ FolderService.find_all_by_view(view)
11
+ end
12
+ end
13
+
14
+ ATTRS = [
15
+ :id, :uuid, :name, :view, :absolute_folder_path,
16
+ :parent_folder_id, :parent_folder_uuid,
17
+ :non_folder_item_count, :non_folder_item_size,
18
+ :revision, :imap_next_uid, :imap_modified_sequence, :modified_sequence, :activesync_disabled,
19
+ :modified_date
20
+ ] unless const_defined?(:ATTRS)
21
+
22
+ attr_accessor *ATTRS
23
+
24
+ def initialize(args = {})
25
+ self.attributes = args
26
+ end
27
+
28
+ def attributes=(args = {})
29
+ ATTRS.each do |attr_name|
30
+ self.send(:"#{attr_name}=", (args[attr_name] || args[attr_name.to_s])) if args.has_key?(attr_name) || args.has_key?(attr_name.to_s)
31
+ end
32
+ end
33
+ end
34
+
35
+ class FolderService < HandsoapAccountService
36
+ def all
37
+ xml = invoke("n2:GetFolderRequest")
38
+ parse_xml_responses(xml)
39
+ end
40
+
41
+ def find_all_by_view(view)
42
+ xml = invoke("n2:GetFolderRequest") do |message|
43
+ Builder.find_all_by_view(message, view)
44
+ end
45
+ parse_xml_responses(xml)
46
+ end
47
+
48
+ def parse_xml_responses(xml)
49
+ Parser.get_all_response(xml)
50
+ end
51
+
52
+ class Builder
53
+ class << self
54
+ def find_all_by_view(message, view)
55
+ message.set_attr 'view', view
56
+ end
57
+ end
58
+ end
59
+
60
+ class Parser
61
+ ATTRIBUTE_MAPPING = {
62
+ :id => :id,
63
+ :uuid => :uuid,
64
+ :name => :name,
65
+ :view => :view,
66
+ :absFolderPath => :absolute_folder_path,
67
+ :l => :parent_folder_id,
68
+ :luuid => :parent_folder_uuid,
69
+ :n => :non_folder_item_count,
70
+ :s => :non_folder_item_size,
71
+ :rev => :revision,
72
+ :i4next => :imap_next_uid,
73
+ :i4ms => :imap_modified_sequence,
74
+ :ms => :modified_sequence,
75
+ :activesyncdisabled => :activesync_disabled,
76
+ :md => :modified_date
77
+ }
78
+
79
+ class << self
80
+ def get_all_response(response)
81
+ (response/"//n2:folder").map do |node|
82
+ folder_response(node)
83
+ end
84
+ end
85
+
86
+ def folder_response(node)
87
+ folder_attributes = ATTRIBUTE_MAPPING.inject({}) do |attrs, (xml_name, attr_name)|
88
+ attrs[attr_name] = (node/"@#{xml_name}").to_s
89
+ attrs
90
+ end
91
+ initialize_from_attributes(folder_attributes)
92
+ end
93
+
94
+ def initialize_from_attributes(folder_attributes)
95
+ Zimbra::Folder.new(folder_attributes)
96
+ end
97
+ end
98
+ end
99
+ end
100
+ end
@@ -0,0 +1,44 @@
1
+ require 'handsoap'
2
+
3
+ module Zimbra
4
+ module HandsoapAccountNamespaces
5
+ def request_namespaces(doc)
6
+ doc.alias 'n1', "urn:zimbra"
7
+ doc.alias 'n2', "urn:zimbraMail"
8
+ doc.alias 'env', 'http://schemas.xmlsoap.org/soap/envelope/'
9
+ end
10
+ def response_namespaces(doc)
11
+ doc.add_namespace 'n2', "urn:zimbraMail"
12
+ end
13
+ end
14
+
15
+ module HandsoapAccountUriOverrides
16
+ def uri
17
+ Zimbra.account_api_url
18
+ end
19
+ def envelope_namespace
20
+ 'http://www.w3.org/2003/05/soap-envelope'
21
+ end
22
+ def request_content_type
23
+ "application/soap+xml"
24
+ end
25
+ end
26
+
27
+ class HandsoapAccountService < Handsoap::Service
28
+ include HandsoapErrors
29
+ include HandsoapAccountNamespaces
30
+ extend HandsoapAccountUriOverrides
31
+
32
+ def on_create_document(doc)
33
+ request_namespaces(doc)
34
+ header = doc.find("Header")
35
+ header.add "n1:context" do |s|
36
+ s.set_attr "env:mustUnderstand", "0"
37
+ s.add "n1:authToken", Zimbra.account_auth_token
38
+ end
39
+ end
40
+ def on_response_document(doc)
41
+ response_namespaces(doc)
42
+ end
43
+ end
44
+ end
@@ -43,7 +43,7 @@ module Zimbra
43
43
 
44
44
  module HandsoapUriOverrides
45
45
  def uri
46
- Zimbra.url
46
+ Zimbra.admin_api_url
47
47
  end
48
48
  def envelope_namespace
49
49
  'http://www.w3.org/2003/05/soap-envelope'
@@ -0,0 +1,3 @@
1
+ module Zimbra
2
+ VERSION = "0.0.5"
3
+ end
@@ -0,0 +1,84 @@
1
+ <?xml version='1.0' ?>
2
+ <CreateAppointmentRequest>
3
+ <m l="10">
4
+ <inv allDay="0" loc="Conference Room" status="CONF">
5
+ <comp class="PUB" fb="B" isOrg="1" name="fdsafdsafdsafdsafdsafdsa" transp="O">
6
+ <description>This is a recurring series</description>
7
+ <s u="1386597600000" d="20131209T140000Z" />
8
+ <e u="1386599400000" d="20131209T143000Z" />
9
+ <alarm action="DISPLAY">
10
+ <trigger>
11
+ <rel neg="1" m="5" related="START" />
12
+ </trigger>
13
+ </alarm>
14
+ <recur>
15
+ <add>
16
+ <rule freq="DAI">
17
+ <interval ival="1" />
18
+ <byday>
19
+ <wkday day="MO" />
20
+ <wkday day="TU" />
21
+ <wkday day="WE" />
22
+ <wkday day="TH" />
23
+ <wkday day="FR" />
24
+ </byday>
25
+ </rule>
26
+ </add>
27
+ </recur>
28
+ <or a="mail03@greenviewdata.com" />
29
+ </comp>
30
+ </inv>
31
+ <inv allDay="0" loc="" status="CONF">
32
+ <comp class="PUB" fb="B" isOrg="1" name="fdsafdsafdsafdsafdsafdsa" transp="O">
33
+ <s u="1387551600000" d="20131220T150000Z" />
34
+ <e u="1387553400000" d="20131220T153000Z" />
35
+ <alarm action="DISPLAY">
36
+ <trigger>
37
+ <rel neg="1" m="5" related="START" />
38
+ </trigger>
39
+ </alarm>
40
+ <or a="mail03@greenviewdata.com" />
41
+ <exceptId d="20131220T090000" tz="America/New_York" />
42
+ </comp>
43
+ </inv>
44
+ <inv allDay="0" loc="" status="CONF">
45
+ <comp class="PUB" fb="B" isOrg="1" name="fdsafdsafdsafdsafdsafdsa" transp="O">
46
+ <description>This instance occurs at 1PM instead</description>
47
+ <s u="1390500000000" d="20140123T180000Z" />
48
+ <e u="1390501800000" d="20140123T183000Z" />
49
+ <alarm action="DISPLAY">
50
+ <trigger>
51
+ <rel neg="1" m="5" related="START" />
52
+ </trigger>
53
+ </alarm>
54
+ <or a="mail03@greenviewdata.com" />
55
+ <exceptId d="20140123T090000" tz="America/New_York" />
56
+ </comp>
57
+ </inv>
58
+ <inv allDay="0" loc="" status="CONF">
59
+ <comp class="PUB" fb="B" isOrg="1" name="fdsafdsafdsafdsafdsafdsa" transp="O">
60
+ <description>This is a recurring series
61
+
62
+ with a few exceptions</description>
63
+ <s u="1390928400000" d="20140128T170000Z" />
64
+ <e u="1390930200000" d="20140128T173000Z" />
65
+ <alarm action="DISPLAY">
66
+ <trigger>
67
+ <rel neg="1" m="5" related="START" />
68
+ </trigger>
69
+ </alarm>
70
+ <or a="mail03@greenviewdata.com" />
71
+ <exceptId d="20140128T090000" tz="America/New_York" />
72
+ </comp>
73
+ </inv>
74
+ <inv allDay="0" loc="" status="CANC">
75
+ <comp class="PUB" fb="B" isOrg="1" name="Cancelled: fdsafdsafdsafdsafdsafdsa" transp="O">
76
+ <comment>A single instance of a recurring meeting has been cancelled.</comment>
77
+ <s u="1391176800000" d="20140131T140000Z" />
78
+ <e u="1391178600000" d="20140131T143000Z" />
79
+ <or a="mail03@greenviewdata.com" />
80
+ <exceptId d="20140131T090000" tz="America/New_York" />
81
+ </comp>
82
+ </inv>
83
+ </m>
84
+ </CreateAppointmentRequest>
@@ -0,0 +1,26 @@
1
+ <appt uid="1b33102b-6d2e-4d98-ad27-c59a92de9798" id="498" rev="27627" nextAlarm="1387486500000" d="1387472221000" s="0" l="10">
2
+ <inv id="497" seq="3" compNum="0" type="appt">
3
+ <tz id="America/New_York" stdoff="-300" stdname="EST" dayoff="-240" dayname="EDT">
4
+ <standard wkday="1" min="0" sec="0" mon="11" hour="2" week="1"/>
5
+ <daylight wkday="1" min="0" sec="0" mon="3" hour="2" week="2"/>
6
+ </tz>
7
+ <comp uid="1b33102b-6d2e-4d98-ad27-c59a92de9798" d="1387472221000" status="CONF" noBlob="1" ciFolder="10" isOrg="1" class="PUB" loc="" compNum="0" apptId="498" url="" fb="B" calItemId="498" x_uid="1b33102b-6d2e-4d98-ad27-c59a92de9798" name="RECURTEST" seq="3" rsvp="0" fba="B" method="PUBLISH" transp="O">
8
+ <alarm action="DISPLAY">
9
+ <trigger>
10
+ <rel neg="1" m="15" related="START"/>
11
+ </trigger>
12
+ <desc/>
13
+ </alarm>
14
+ <or d="Mail03" a="mail03@greenviewdata.com" url="mail03@greenviewdata.com"/>
15
+ <recur>
16
+ <add>
17
+ <rule freq="DAI">
18
+ <interval ival="2"/>
19
+ </rule>
20
+ </add>
21
+ </recur>
22
+ <s u="1387486800000" d="20131219T160000" tz="America/New_York"/>
23
+ <e u="1387490400000" d="20131219T170000" tz="America/New_York"/>
24
+ </comp>
25
+ </inv>
26
+ </appt>
@@ -0,0 +1,26 @@
1
+ <appt uid="1b33102b-6d2e-4d98-ad27-c59a92de9798" id="498" rev="27627" nextAlarm="1387486500000" d="1387472221000" s="0" l="10">
2
+ <inv id="497" seq="3" compNum="0" type="appt">
3
+ <tz id="America/New_York" stdoff="-300" stdname="EST" dayoff="-240" dayname="EDT">
4
+ <standard wkday="1" min="0" sec="0" mon="11" hour="2" week="1"/>
5
+ <daylight wkday="1" min="0" sec="0" mon="3" hour="2" week="2"/>
6
+ </tz>
7
+ <comp uid="1b33102b-6d2e-4d98-ad27-c59a92de9798" d="1387472221000" status="CONF" noBlob="1" ciFolder="10" isOrg="1" class="PUB" loc="" compNum="0" apptId="498" url="" fb="B" calItemId="498" x_uid="1b33102b-6d2e-4d98-ad27-c59a92de9798" name="RECURTEST" seq="3" rsvp="0" fba="B" method="PUBLISH" transp="O">
8
+ <alarm action="DISPLAY">
9
+ <trigger>
10
+ <rel neg="0" m="15" w="1" d="2" h="3" s="25" count="2" related="END"/>
11
+ </trigger>
12
+ <desc/>
13
+ </alarm>
14
+ <or d="Mail03" a="mail03@greenviewdata.com" url="mail03@greenviewdata.com"/>
15
+ <recur>
16
+ <add>
17
+ <rule freq="DAI">
18
+ <interval ival="2"/>
19
+ </rule>
20
+ </add>
21
+ </recur>
22
+ <s u="1387486800000" d="20131219T160000" tz="America/New_York"/>
23
+ <e u="1387490400000" d="20131219T170000" tz="America/New_York"/>
24
+ </comp>
25
+ </inv>
26
+ </appt>
@@ -0,0 +1,40 @@
1
+ <soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">
2
+ <soap:Header>
3
+ <context xmlns="urn:zimbra">
4
+ <change token="27762"/>
5
+ </context>
6
+ </soap:Header>
7
+ <soap:Body>
8
+ <GetAppointmentResponse xmlns="urn:zimbraMail">
9
+ <appt id="518" uid="1c71d474-5c1f-4048-84e3-9725c0825a44" nextAlarm="1392233100000" d="1387571704000" rev="27656" s="0" l="10">
10
+ <inv id="517" seq="4" compNum="0" type="appt">
11
+ <tz id="America/New_York" stdoff="-300" dayname="EDT" dayoff="-240" stdname="EST">
12
+ <standard min="0" wkday="1" sec="0" mon="11" hour="2" week="1"/>
13
+ <daylight min="0" wkday="1" sec="0" mon="3" hour="2" week="2"/>
14
+ </tz>
15
+ <comp uid="1c71d474-5c1f-4048-84e3-9725c0825a44" d="1387571704000" status="CONF" noBlob="1" ciFolder="10" isOrg="1" class="PUB" loc="" compNum="0" apptId="518" fb="B" url="" calItemId="518" x_uid="1c71d474-5c1f-4048-84e3-9725c0825a44" name="Test2222" seq="4" rsvp="0" fba="B" method="PUBLISH" transp="O">
16
+ <alarm action="DISPLAY">
17
+ <trigger>
18
+ <rel neg="1" m="5" related="START"/>
19
+ </trigger>
20
+ <desc/>
21
+ </alarm>
22
+ <or d="Mail03" a="mail03@greenviewdata.com" url="mail03@greenviewdata.com"/>
23
+ <recur>
24
+ <add>
25
+ <rule freq="MON">
26
+ <interval ival="1"/>
27
+ <byday>
28
+ <wkday ordwk="2" day="WE"/>
29
+ </byday>
30
+ </rule>
31
+ </add>
32
+ </recur>
33
+ <s u="1355340600000" d="20121212T143000" tz="America/New_York"/>
34
+ <e d="20121212T153000" u="1355344200000" tz="America/New_York"/>
35
+ </comp>
36
+ </inv>
37
+ </appt>
38
+ </GetAppointmentResponse>
39
+ </soap:Body>
40
+ </soap:Envelope>