zimbra 0.0.4 → 0.0.5

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.
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>