gcal_mapper 0.1.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (58) hide show
  1. data/.gitignore +32 -0
  2. data/.travis.yml +16 -0
  3. data/CHANGELOG.md +15 -0
  4. data/Gemfile +20 -0
  5. data/Guardfile +19 -0
  6. data/LICENSE +22 -0
  7. data/README.md +370 -0
  8. data/Rakefile +32 -0
  9. data/bin/ci/file/auth.yaml +7 -0
  10. data/bin/ci/file/bad_yaml.yaml +0 -0
  11. data/bin/ci/file/config.yaml +8 -0
  12. data/bin/ci/file/privatekey.p12 +0 -0
  13. data/bin/ci/travis_build.sh +4 -0
  14. data/bin/ci/vcr/GcalMapper_Authentification/access_token_should_exist_with_assertion_auth.yml +49 -0
  15. data/bin/ci/vcr/GcalMapper_Authentification/should_be_fasle_if_bad_client_email_is_given.yml +47 -0
  16. data/bin/ci/vcr/GcalMapper_Authentification_Assertion/should_have_access_token_attribute.yml +49 -0
  17. data/bin/ci/vcr/GcalMapper_Authentification_Assertion/should_have_refresh_token_attribute.yml +49 -0
  18. data/bin/ci/vcr/GcalMapper_Calendar/should_get_the_calendar_list.yml +190 -0
  19. data/bin/ci/vcr/GcalMapper_Calendar/should_get_the_events_list.yml +45 -0
  20. data/bin/ci/vcr/GcalMapper_Calendar/should_raise_error_if_the_calendar_id_isn_t_accessible.yml +56 -0
  21. data/bin/ci/vcr/GcalMapper_Calendar/should_raise_error_if_the_token_is_bad.yml +60 -0
  22. data/bin/ci/vcr/GcalMapper_Mapper/should_save_all_events.yml +232 -0
  23. data/bin/ci/vcr/GcalMapper_Mapper/should_save_events_only_once.yml +232 -0
  24. data/bin/gcal-mapper +108 -0
  25. data/gcal_mapper.gemspec +25 -0
  26. data/lib/gcal_mapper.rb +15 -0
  27. data/lib/gcal_mapper/authentification.rb +57 -0
  28. data/lib/gcal_mapper/authentification/assertion.rb +110 -0
  29. data/lib/gcal_mapper/authentification/base.rb +20 -0
  30. data/lib/gcal_mapper/authentification/oauth2.rb +68 -0
  31. data/lib/gcal_mapper/calendar.rb +51 -0
  32. data/lib/gcal_mapper/configuration.rb +23 -0
  33. data/lib/gcal_mapper/errors.rb +40 -0
  34. data/lib/gcal_mapper/mapper.rb +76 -0
  35. data/lib/gcal_mapper/mapper/active_record.rb +74 -0
  36. data/lib/gcal_mapper/mapper/dsl.rb +57 -0
  37. data/lib/gcal_mapper/mapper/simple.rb +97 -0
  38. data/lib/gcal_mapper/railtie.rb +8 -0
  39. data/lib/gcal_mapper/rest_request.rb +73 -0
  40. data/lib/gcal_mapper/sync.rb +159 -0
  41. data/lib/gcal_mapper/version.rb +4 -0
  42. data/spec/authentification/assertion_spec.rb +15 -0
  43. data/spec/authentification/base_spec.rb +18 -0
  44. data/spec/authentification/oauth2_spec.rb +15 -0
  45. data/spec/authentification_spec.rb +34 -0
  46. data/spec/calendar_spec.rb +33 -0
  47. data/spec/gcal_mapper_spec.rb +5 -0
  48. data/spec/mapper/active_record_spec.rb +46 -0
  49. data/spec/mapper/dsl_spec.rb +31 -0
  50. data/spec/mapper/simple_spec.rb +48 -0
  51. data/spec/mapper_spec.rb +32 -0
  52. data/spec/rest_request_spec.rb +5 -0
  53. data/spec/spec_helper.rb +51 -0
  54. data/spec/support/models/event.rb +25 -0
  55. data/spec/support/models/event_jeu.rb +22 -0
  56. data/spec/support/schema.rb +28 -0
  57. data/spec/sync_spec.rb +28 -0
  58. metadata +200 -0
@@ -0,0 +1,159 @@
1
+ module GcalMapper
2
+ #
3
+ # Provide methods to synch google calendar and local bd
4
+ #
5
+ class Sync
6
+
7
+ # proxy to call sync methods and set new instance
8
+ #
9
+ # @param [Configuration] config configuration class seted by DSL
10
+ # @param [Class] base class of the caller
11
+ def self.sync(config, base)
12
+ new(config, base).sync_gcal
13
+ end
14
+
15
+ # new Sync object
16
+ #
17
+ # @param [Configuration] config configuration class seted by DSL
18
+ # @param [Class] base class of the calle
19
+ def initialize(config, base)
20
+ @config = config
21
+ @base = base
22
+ end
23
+
24
+ # full synchronization step by step
25
+ #
26
+ def sync_gcal
27
+ authenticate
28
+ fetch_events
29
+ save_events
30
+ end
31
+
32
+ private
33
+ # call Authentification class to authenticate the API
34
+ #
35
+ def authenticate
36
+ @auth = GcalMapper::Authentification.new(@config.file, @config.client_email, @config.user_email, @config.password)
37
+ @auth.authenticate
38
+ end
39
+
40
+ # Get all events from specified calendar(s).
41
+ #
42
+ # @return [Array] all events from given calendar(s) id.
43
+ def fetch_events
44
+ events_list = []
45
+
46
+ calendar = GcalMapper::Calendar.new
47
+ retried = false
48
+ begin
49
+ calendars_list = calendar.get_calendars_list(@auth.access_token)
50
+ rescue
51
+ if !retried
52
+ @auth.refresh_token
53
+ retried = true
54
+ retry
55
+ else
56
+ raise
57
+ end
58
+ end
59
+
60
+ if calendars_list.empty?
61
+ raise GcalMapper::CalendarAvailabilityError
62
+ end
63
+
64
+ @config.calendars.each do |cal|
65
+ events_list = []
66
+ if calendars_list.include?(cal)
67
+ retried = false
68
+ begin
69
+ events_list += (calendar.get_events_list(@auth.access_token, cal))
70
+ rescue
71
+ if !retried
72
+ @auth.refresh_token
73
+ retried = true
74
+ retry
75
+ else
76
+ raise
77
+ end
78
+ end
79
+ else
80
+ raise GcalMapper::CalendarAccessibilityError
81
+ end
82
+ end
83
+
84
+ @events_list = events_list
85
+ end
86
+
87
+ # Get all events from specified calendar(s). an keep synchronize with the online gcal
88
+ #
89
+ def save_events
90
+ adapter = Mapper.adapter
91
+
92
+ @events_list.each do |event|
93
+
94
+ existed_event = adapter.find_by(@config.gid, event['id'])
95
+ event_exist = !existed_event.nil?
96
+
97
+ if event_exist
98
+ if event['status'] == 'cancelled'
99
+ adapter.delete!(existed_event.id)
100
+ else
101
+ updated_attrib = set_attrib(event)
102
+ current_attrib = existed_event.attributes
103
+ current_attrib.delete('id')
104
+ if current_attrib != updated_attrib
105
+ adapter.update!(existed_event.id, updated_attrib)
106
+ end
107
+ end
108
+ end
109
+
110
+ if !event_exist && event['status'] != 'cancelled'
111
+ adapter.create!(set_attrib(event))
112
+ end
113
+ end
114
+ end
115
+
116
+ # set the object from fields configuration
117
+ #
118
+ # @param [Hash] event event to save in obj
119
+ # @return [hash] hash of setted attributes
120
+ def set_attrib(event)
121
+ attrib_hash = {@config.gid => event['id']}
122
+ @config.fields.each do |field, source|
123
+ if source[:source].include?('.')
124
+ data = source[:source].split('.')
125
+ attrib_hash[field] = eval_value(source, event[data[0]][data[1]])
126
+ else
127
+ attrib_hash[field] = eval_value(source, event[source[:source]])
128
+ end
129
+ if (attrib_hash[field].nil? && source.has_key?(:if_empty))
130
+ if source[:if_empty].include?('.')
131
+ data = source[:if_empty].split('.')
132
+ attrib_hash[field] = eval_value(source, event[data[0]][data[1]])
133
+ else
134
+ attrib_hash[field] = eval_value(source, event[source[:if_empty]])
135
+ end
136
+ end
137
+ end
138
+
139
+ attrib_hash
140
+ end
141
+
142
+ # eval the value from the source options
143
+ #
144
+ # @param [Hash] source source of the field
145
+ # @param [string] raw_data the string extract form google event data
146
+ # @return the data asked
147
+ def eval_value(source, raw_data)
148
+ if source[:match]
149
+ data = source[:match].match(raw_data).to_s
150
+ data = source[:default] if data == ''
151
+ else
152
+ data = raw_data
153
+ end
154
+
155
+ data
156
+ end
157
+
158
+ end
159
+ end
@@ -0,0 +1,4 @@
1
+ module GcalMapper
2
+ #version number of GcalMapper
3
+ VERSION = '0.1.1'
4
+ end
@@ -0,0 +1,15 @@
1
+ require 'spec_helper'
2
+
3
+ describe GcalMapper::Authentification::Assertion do
4
+
5
+ it "should have access_token attribute", :vcr do
6
+ auth = GcalMapper::Authentification::Assertion.new(@p12, @client_email, @user_email, 'notasecret')
7
+ auth.should respond_to(:access_token)
8
+ end
9
+
10
+ it "should have refresh_token attribute", :vcr do
11
+ auth = GcalMapper::Authentification::Assertion.new(@p12, @client_email, @user_email, 'notasecret')
12
+ auth.should respond_to(:refresh_token)
13
+ end
14
+
15
+ end
@@ -0,0 +1,18 @@
1
+ require 'spec_helper'
2
+
3
+ describe GcalMapper::Authentification::Base do
4
+ before :all do
5
+ class DummyClass < GcalMapper::Authentification::Base
6
+ end
7
+
8
+ @dummy = DummyClass.new
9
+ end
10
+
11
+ it "should raise error if access_token don't exist" do
12
+ expect {@dummy.access_token}.to raise_error(NotImplementedError)
13
+ end
14
+
15
+ it "should raise error if refresh_token don't exist" do
16
+ expect {@dummy.refresh_token}.to raise_error(NotImplementedError)
17
+ end
18
+ end
@@ -0,0 +1,15 @@
1
+ require 'spec_helper'
2
+
3
+ describe GcalMapper::Authentification::Oauth2 do
4
+
5
+ it "should have access_token attribute" do
6
+ auth = GcalMapper::Authentification::Oauth2.new(@yaml)
7
+ auth.should respond_to(:access_token)
8
+ end
9
+
10
+ it "should have refresh_token attribute", :vcr do
11
+ auth = GcalMapper::Authentification::Oauth2.new(@yaml)
12
+ auth.should respond_to(:refresh_token)
13
+ end
14
+
15
+ end
@@ -0,0 +1,34 @@
1
+ require 'spec_helper'
2
+
3
+ describe GcalMapper::Authentification do
4
+
5
+ it "should raise an error if the file is don't exist" do
6
+ expect {GcalMapper::Authentification.new('/home/test')}.to raise_error
7
+ end
8
+
9
+ it "should return an error if bad yaml file is given" do
10
+ auth = GcalMapper::Authentification.new(@bad_yaml)
11
+ expect {auth.authenticate}.to raise_error
12
+ end
13
+
14
+ it "should not raise an error if relative path is given" do
15
+ auth = GcalMapper::Authentification.new(@yaml_relative)
16
+ expect {auth.authenticate}.to_not raise_error
17
+ end
18
+
19
+ it "access token should exist with oauth2 auth" do
20
+ auth = GcalMapper::Authentification.new(@yaml)
21
+ auth.authenticate.should be_true
22
+ end
23
+
24
+ it "access token should exist with assertion auth", :vcr do
25
+ auth = GcalMapper::Authentification.new(@p12, @client_email)
26
+ auth.authenticate.should be_true
27
+ end
28
+
29
+ it "should be fasle if bad client email is given", :vcr do
30
+ auth = GcalMapper::Authentification.new(@p12, 'test@dtest.com')
31
+ expect {auth.authenticate}.to raise_error
32
+ end
33
+
34
+ end
@@ -0,0 +1,33 @@
1
+ require 'spec_helper'
2
+
3
+ describe GcalMapper::Calendar do
4
+ before :all do
5
+ @auth_oauth2 = GcalMapper::Authentification.new(@yaml)
6
+ @auth_oauth2.authenticate
7
+ @list = GcalMapper::Calendar.new
8
+ @bad_token = 'a bad token'
9
+
10
+ end
11
+
12
+ it "should get the calendar list", :vcr do
13
+ begin
14
+ calendar = @list.get_calendars_list(@auth_oauth2.access_token)
15
+ rescue
16
+ @auth_oauth2.refresh_token
17
+ calendar = @list.get_calendars_list(@auth_oauth2.access_token)
18
+ end
19
+ @list.get_calendars_list(@auth_oauth2.access_token).should_not be_nil
20
+ end
21
+
22
+ it "should get the events list", :vcr do
23
+ @list.get_events_list(@auth_oauth2.access_token, @calendar_id).should_not be_nil
24
+ end
25
+
26
+ it "should raise error if the token is bad", :vcr do
27
+ expect {@list.get_calendars_list(@bad_token)}.to raise_error
28
+ end
29
+
30
+ it "should raise error if the calendar id isn't accessible", :vcr do
31
+ expect {@list.get_events_list(@auth_oauth2.access_token, 'test')}.to raise_error
32
+ end
33
+ end
@@ -0,0 +1,5 @@
1
+ require 'spec_helper'
2
+
3
+ describe GcalMapper do
4
+
5
+ end
@@ -0,0 +1,46 @@
1
+ require 'spec_helper'
2
+
3
+ describe GcalMapper::Mapper::ActiveRecord do
4
+
5
+ before :all do
6
+ class User < ActiveRecord::Base
7
+
8
+ end
9
+
10
+ @klass = GcalMapper::Mapper::ActiveRecord::ActiveRecord.new(User)
11
+ end
12
+
13
+ it "should create a new object and save it" do
14
+ @klass.create!({'first_name' => 'a_name', 'name' => 'a_name'})
15
+ User.all.should_not eql([])
16
+ end
17
+
18
+ it "shoudl list all stored entry" do
19
+ @klass.find_all.should eql(User.all)
20
+ end
21
+
22
+ it "should update an entry" do
23
+ user = User.first
24
+ name_before = user.name
25
+ @klass.update!(user.id, {'name' => 'another_name'})
26
+ name_after = User.first.name
27
+
28
+ name_before.should_not eql(name_after)
29
+ end
30
+
31
+ it "should delete an entry" do
32
+ user = User.first
33
+ @klass.delete!(user.id)
34
+
35
+ User.all.should eql([])
36
+ end
37
+
38
+ it "should find an entry from field name and value" do
39
+ @klass.create!({'first_name' => 'a_name', 'name' => 'a_name'})
40
+ @klass.create!({'first_name' => 'a_name', 'name' => 'another_name'})
41
+ @klass.create!({'first_name' => 'a_name', 'name' => 'different_name'})
42
+
43
+ @klass.find_by('name', 'a_name').should be_an_instance_of(User)
44
+ end
45
+
46
+ end
@@ -0,0 +1,31 @@
1
+ require 'spec_helper'
2
+
3
+ describe GcalMapper::Mapper::DSL do
4
+ before :all do
5
+ @dsl = GcalMapper::Mapper::DSL.new(GcalMapper::Configuration.new)
6
+ end
7
+
8
+ describe :field do
9
+ it "should raise error if field option don't exist" do
10
+ expect {@dsl.field('test', {:source => 'test', :test => 'test'})}.to raise_error
11
+ end
12
+
13
+ it "should accept :source, :match, :default" do
14
+ expect {@dsl.field('test', {:source => 'test', :match => /test/, :default => 'test'})}.to_not raise_error
15
+ end
16
+
17
+ it "should raise error if regexp is invalid" do
18
+ expect {@dsl.field('test', {:source => 'test', :match => test, :default => 'test'})}.to raise_error
19
+ end
20
+
21
+ it "should raise error if :source isn't present" do
22
+ expect {@dsl.field('test', {:match => /test/, :default => 'test'})}.to raise_error
23
+ end
24
+ end
25
+
26
+ describe :configure do
27
+ it "should raise an error if :file isn't present" do
28
+ expect {@dsl.configure({:client_email => '87', :user_email => 'web', :password => 'notasecret'})}.to raise_error
29
+ end
30
+ end
31
+ end
@@ -0,0 +1,48 @@
1
+ require 'spec_helper'
2
+
3
+ describe GcalMapper::Mapper::Simple do
4
+ before :all do
5
+ class User2
6
+ include GcalMapper::Mapper::Simple
7
+ attr_accessor :id, :first_name, :name
8
+
9
+ end
10
+
11
+ @base = GcalMapper::Mapper::Simple::Simple.new(User2)
12
+ end
13
+
14
+ it "should create a new object and save it" do
15
+ @base.create!({'first_name' => 'a_name', 'name' => 'a_name'})
16
+ @base.events.should_not eql([])
17
+ end
18
+
19
+ it "shoudl list all stored entry" do
20
+ @base.find_all.should eql(@base.events)
21
+ end
22
+
23
+ it "should update an entry" do
24
+ user = @base.events[0]
25
+ name_before = user.name
26
+ @base.update!(user.id, {'name' => 'another_name'})
27
+ name_after = @base.events[0].name
28
+
29
+ name_before.should_not eql(name_after)
30
+ end
31
+
32
+ it "should delete an entry" do
33
+ @base.create!({'first_name' => 'a_name', 'name' => 'a_name'})
34
+ before_count = @base.events.count
35
+ user = @base.events[0]
36
+ @base.delete!(user.id)
37
+
38
+ before_count.should > (@base.events.count)
39
+ end
40
+
41
+ it "should find an entry from field name and value" do
42
+ @base.create!({'first_name' => 'a_name', 'name' => 'another_name'})
43
+ @base.create!({'first_name' => 'a_name', 'name' => 'different_name'})
44
+
45
+ @base.find_by('name', 'a_name').should be_an_instance_of(User2)
46
+ end
47
+
48
+ end
@@ -0,0 +1,32 @@
1
+ require 'spec_helper'
2
+
3
+ describe GcalMapper::Mapper do
4
+
5
+ before :all do
6
+ load File.dirname(__FILE__) + '/support/models/event.rb'
7
+ end
8
+
9
+ it "should load a file containing DSL with no error" do
10
+ expect{load File.dirname(__FILE__) + '/support/models/event.rb'}.to_not raise_error
11
+ end
12
+
13
+ it "should save all events", :vcr do
14
+ Event.synchronize_calendar
15
+ Event.all.should_not eql([])
16
+ end
17
+
18
+ it "should save events only once", :vcr do
19
+ before = Event.count
20
+ Event.synchronize_calendar
21
+ Event.count.should eq(before)
22
+ end
23
+
24
+ it "should erase cancelled event", :vcr do
25
+ cancelled = 0
26
+ Event.all.each do |event|
27
+ cancelled += 1 if event.status == 'cancelled'
28
+ end
29
+ cancelled.should eq(0)
30
+ end
31
+
32
+ end