gcal_mapper 0.1.1

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 (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,23 @@
1
+ module GcalMapper
2
+ #
3
+ # Gem's configuration
4
+ #
5
+ class Configuration
6
+
7
+ attr_accessor :gid # name of the field that contains google event id
8
+ attr_accessor :fields # hash that contains all the field with their source config
9
+ attr_accessor :calendars # array that contains all the calendar id to fetch
10
+ attr_accessor :file # Auth file path
11
+ attr_accessor :client_email # Service account email
12
+ attr_accessor :user_email # email of user to impersonat
13
+ attr_accessor :password # passowrd for p12 key
14
+
15
+ # New configuration object
16
+ #
17
+ def initialize
18
+ @fields = {}
19
+ @calendars = []
20
+ end
21
+
22
+ end
23
+ end
@@ -0,0 +1,40 @@
1
+
2
+
3
+ module GcalMapper
4
+ #
5
+ # An error which is raised when the authentification process fails
6
+ #
7
+ class AuthentificationError < StandardError
8
+ end
9
+
10
+ #
11
+ # An error which is raised when the yaml or p12 key does not contains what expected
12
+ #
13
+ class AuthFileError < StandardError
14
+ end
15
+
16
+ #
17
+ # An error which is raised when the http status code of the respose is not within 200..300
18
+ #
19
+ class ResponseStatusError < StandardError
20
+ end
21
+
22
+ #
23
+ # An exception which is raised when no calenards are accessible.
24
+ #
25
+ class CalendarAvailabilityError < StandardError
26
+ end
27
+
28
+ #
29
+ # An exception which is raised when specified calendar is not available.
30
+ #
31
+ class CalendarAccessibilityError < StandardError
32
+ end
33
+
34
+ #
35
+ # Error when there is error in user DSL
36
+ #
37
+ class DSLSyntaxError < StandardError
38
+ end
39
+
40
+ end
@@ -0,0 +1,76 @@
1
+ require 'gcal_mapper/mapper/dsl'
2
+ require 'gcal_mapper/mapper/active_record'
3
+ require 'gcal_mapper/mapper/simple'
4
+
5
+ module GcalMapper
6
+ #
7
+ # Provide dsl en sync methods
8
+ #
9
+ module Mapper
10
+
11
+ # setter for class varaible base
12
+ #
13
+ # @return [Class] class name of the includer
14
+ def self.base=(base)
15
+ @@base = base
16
+ end
17
+
18
+ # reader for class varaible base
19
+ #
20
+ # @return [Class] class name of the includer
21
+ def self.base
22
+ @@base
23
+ end
24
+
25
+ # setter for config class attributes
26
+ #
27
+ # @param [Configuration] config configuration class
28
+ def self.config=(config)
29
+ @@config = config
30
+ end
31
+
32
+ # getter for config class attributes
33
+ #
34
+ # @return [Configuration] configuration class
35
+ def self.config
36
+ @@config
37
+ end
38
+
39
+ # setter for adapter class attributes
40
+ #
41
+ # @param [Configuration] config configuration class
42
+ def self.adapter=(adapter)
43
+ @@adapter = adapter
44
+ end
45
+
46
+ # getter for adapter class attributes
47
+ #
48
+ # @return [Configuration] configuration class
49
+ def self.adapter
50
+ @@adapter
51
+ end
52
+
53
+ #
54
+ # module to add class methods to the includer
55
+ #
56
+ module ClassMethods
57
+
58
+ # provide dsl function
59
+ #
60
+ # @param [Block] block contain dsl of th caller
61
+ def calendar(&block)
62
+ Mapper.config = GcalMapper::Configuration.new
63
+ dsl = DSL.new(Mapper.config)
64
+ dsl.instance_eval(&block)
65
+ end
66
+
67
+ # synchronize methods for the caller
68
+ #
69
+ def synchronize_calendar
70
+ Sync.sync(Mapper.config, Mapper.base)
71
+ end
72
+
73
+ end
74
+
75
+ end
76
+ end
@@ -0,0 +1,74 @@
1
+ require 'active_record'
2
+
3
+ module GcalMapper
4
+ module Mapper
5
+ #
6
+ # module to include when active record is in use
7
+ #
8
+ module ActiveRecord
9
+
10
+ # execute when the file is included
11
+ #
12
+ # @param [Class] base class of the includer
13
+ def self.included(base)
14
+ base.extend(GcalMapper::Mapper::ClassMethods)
15
+ Mapper.base = base
16
+ Mapper.adapter = ActiveRecord.new(base)
17
+ end
18
+
19
+ #
20
+ # Adapter for ActiveRecord
21
+ #
22
+ class ActiveRecord
23
+
24
+ def initialize(base)
25
+ @base = base
26
+ end
27
+
28
+ # create and save object using attributes
29
+ #
30
+ # @param [Hash] attributes all the attributes to save in the new object
31
+ # return [Object] createrd object
32
+ def create!(attributes)
33
+ @base.create(attributes)
34
+ end
35
+
36
+ # update an object
37
+ #
38
+ # @param [Int] id id of the object in the DB
39
+ # @param [Hash] attributes hash containing the field to update
40
+ # @return [Object] updated object
41
+ def update!(id, attributes)
42
+ obj = @base.find(id)
43
+ obj.update_attributes!(attributes)
44
+ end
45
+
46
+ # delet an object
47
+ #
48
+ # @param [Int] id id of the object in the DB
49
+ # @return [Object] the destroyed object
50
+ def delete!(id)
51
+ obj = @base.find(id)
52
+ obj.destroy
53
+ end
54
+
55
+ # Find all models
56
+ #
57
+ # @return [Array] all the object from a calss
58
+ def find_all
59
+ @base.all
60
+ end
61
+
62
+ # find an object from a field and a value
63
+ #
64
+ # @param [String] field name of the field where to search
65
+ # @param [String] value the value to find
66
+ # @return [Object] the finded object or nil
67
+ def find_by(field, value)
68
+ @base.send('find_by_' + field, value)
69
+ end
70
+
71
+ end
72
+ end
73
+ end
74
+ end
@@ -0,0 +1,57 @@
1
+ module GcalMapper
2
+ module Mapper
3
+ #
4
+ # Provide DSL to configure gem
5
+ #
6
+ class DSL
7
+ VALID_FIELD_OPTIONS = [:source, :if_empty, :match, :default] # options available in DSL
8
+
9
+ # Intitialize config
10
+ #
11
+ def initialize(config)
12
+ @config = config
13
+ end
14
+
15
+ # Add new calendar id
16
+ #
17
+ # @param [string] id calendar id to add
18
+ def calendar (id)
19
+ @config.calendars.push(id)
20
+ end
21
+
22
+ # Add a new field
23
+ #
24
+ # @param [String] name DB field name
25
+ # @param [Hash] options contains source options used to fill the field
26
+ def field(name, options = {})
27
+ raise GcalMapper::DSLSyntaxError, 'Source option must be present' if !options.include?(:source)
28
+ raise GcalMapper::DSLSyntaxError, 'field option not available' if (options.keys != VALID_FIELD_OPTIONS & options.keys)
29
+
30
+ if options[:match]
31
+ raise GcalMapper::DSLSyntaxError, 'invalid regex' if options[:match].class != Regexp
32
+ end
33
+
34
+ @config.fields.merge!(name => options)
35
+ end
36
+
37
+ # Add authentification configuration
38
+ #
39
+ # @param [Hash] options contains the stuff to configure authetification
40
+ def configure(options = {})
41
+ raise GcalMapper::DSLSyntaxError, 'you must give a credential file' if options[:file].nil?
42
+ @config.file = options[:file]
43
+ @config.client_email = options[:client_email]
44
+ @config.user_email = options[:user_email]
45
+ @config.password = options[:password]
46
+ end
47
+
48
+ # Give the field in DB that is reserved to put event id given by google
49
+ #
50
+ # @param [String] name DB field name
51
+ def google_id(name)
52
+ @config.gid = name
53
+ end
54
+
55
+ end
56
+ end
57
+ end
@@ -0,0 +1,97 @@
1
+ module GcalMapper
2
+ module Mapper
3
+ #
4
+ # module to include when no orm is used
5
+ #
6
+ module Simple
7
+
8
+ # execute when the file is included
9
+ #
10
+ # @param [Class] base class of the includer
11
+ def self.included(base)
12
+ base.extend(GcalMapper::Mapper::ClassMethods)
13
+ Mapper.base = base
14
+ Mapper.adapter = Simple.new(base)
15
+ end
16
+
17
+ #
18
+ # Adapter to use without an orm
19
+ #
20
+ class Simple
21
+ attr_reader :events # array of the synchronized events
22
+
23
+ # new object
24
+ #
25
+ # @param [class] klass class that need an adapter
26
+ def initialize(base)
27
+ @base = base
28
+ @events = []
29
+ end
30
+
31
+ # create and save object using attributes
32
+ #
33
+ # @param [Hash] attributes all the attributes to save in the new object
34
+ def create!(attributes)
35
+ obj = @base.new
36
+ obj.id = @events.count
37
+ attributes.each do |key, value|
38
+ obj.send(key+'=', value)
39
+ end
40
+
41
+ @events << obj
42
+ end
43
+
44
+ # update an object
45
+ #
46
+ # @param [Int] id id of the object in the DB
47
+ # @param [Hash] attributes hash containing the field to update
48
+ def update!(id, attributes)
49
+ obj = @events[id]
50
+ attributes.each do |key, value|
51
+ obj.send(key+'=', value)
52
+ end
53
+
54
+ @events << obj
55
+ end
56
+
57
+ # delet an object
58
+ #
59
+ # @param [Int] id id of the object in the DB
60
+ def delete!(id)
61
+ @events[id] = nil
62
+
63
+ @events.each_with_index do |item, index|
64
+ if item
65
+ if @events[index + 1]
66
+ item = @events[index + 1]
67
+ item.id =- 1
68
+ end
69
+ end
70
+ end
71
+
72
+ @events.delete(nil)
73
+ end
74
+
75
+ # Find all models
76
+ #
77
+ def find_all
78
+ @events
79
+ end
80
+
81
+ # find an object from a field and a value
82
+ #
83
+ # @param [String] field name of the field where to search
84
+ # @param [String] value the value to find
85
+ def find_by(field, value)
86
+ find_event = nil
87
+ @events.each do |event|
88
+ find_event = event if event.send(field) == value
89
+ end
90
+
91
+ find_event
92
+ end
93
+
94
+ end
95
+ end
96
+ end
97
+ end
@@ -0,0 +1,8 @@
1
+ module GcalMapper
2
+ #
3
+ # Extends Rails framework
4
+ #
5
+ class Railtie < Rails::Railtie
6
+
7
+ end
8
+ end
@@ -0,0 +1,73 @@
1
+ require 'net/http'
2
+ require 'json'
3
+
4
+ module GcalMapper
5
+ #
6
+ # Make a REST get or post request
7
+ #
8
+ class RestRequest
9
+
10
+ attr_accessor :url # Complete url for the request
11
+ attr_accessor :options # Options for the REST request
12
+
13
+ # Initialize a new request
14
+ #
15
+ # @param [String] url the complete url of where to send the request
16
+ # @datarequest.rbparam [Hash] options contain all the options that can be included in REST request
17
+ def initialize (url, options = {})
18
+ @url = url
19
+ @options = options
20
+ end
21
+
22
+ # Set a proxy if the connection needs it
23
+ #
24
+ def proxy
25
+ http_proxy = ENV["http_proxy"]
26
+ URI.parse(http_proxy) rescue nil
27
+ end
28
+
29
+ # Execute REST request
30
+ #
31
+ # @return [Hash] a Json parsed hash that contains the body of the response.
32
+ def execute
33
+ options = {
34
+ :parameters => {}, :debug => false,
35
+ :http_timeout => 60, :method => :get,
36
+ :headers => {}, :redirect_count => 0,
37
+ :max_redirects => 10
38
+ }.merge(@options)
39
+ url = URI(@url)
40
+
41
+ if proxy
42
+ http = Net::HTTP::Proxy(proxy.host, proxy.port).new(url.host, url.port)
43
+ else
44
+ http = Net::HTTP.new(url.host, url.port)
45
+ end
46
+
47
+ if url.scheme == 'https'
48
+ http.use_ssl = true
49
+ end
50
+
51
+ http.open_timeout = http.read_timeout = options[:http_timeout]
52
+ http.set_debug_output $stderr if options[:debug]
53
+
54
+ request = case options[:method]
55
+ when :post
56
+ request = Net::HTTP::Post.new(url.request_uri)
57
+ request.set_form_data(options[:parameters])
58
+ request
59
+ else
60
+ request = Net::HTTP::Get.new(url.request_uri)
61
+ end
62
+
63
+ options[:headers].each { |key, value| request[key] = value }
64
+ response = http.request(request)
65
+ if !(200..300).include?(response.code.to_i)
66
+ raise GcalMapper::ResponseStatusError
67
+ end
68
+
69
+ JSON.parse(response.body)
70
+ end
71
+
72
+ end
73
+ end