contextio 0.5.0 → 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (65) hide show
  1. data/.document +4 -0
  2. data/.gitignore +8 -0
  3. data/.rspec +1 -0
  4. data/.yardopts +1 -0
  5. data/ChangeLog.md +5 -0
  6. data/Gemfile +3 -0
  7. data/LICENSE.md +20 -0
  8. data/README.md +62 -22
  9. data/Rakefile +46 -36
  10. data/contextio.gemspec +30 -0
  11. data/lib/contextio.rb +69 -583
  12. data/lib/contextio/account.rb +132 -0
  13. data/lib/contextio/account_collection.rb +57 -0
  14. data/lib/contextio/account_sync_data.rb +22 -0
  15. data/lib/contextio/api.rb +162 -0
  16. data/lib/contextio/api/association_helpers.rb +17 -0
  17. data/lib/contextio/api/resource.rb +230 -0
  18. data/lib/contextio/api/resource_collection.rb +174 -0
  19. data/lib/contextio/api/url_builder.rb +153 -0
  20. data/lib/contextio/body_part.rb +45 -0
  21. data/lib/contextio/body_part_collection.rb +13 -0
  22. data/lib/contextio/connect_token.rb +57 -0
  23. data/lib/contextio/connect_token_collection.rb +44 -0
  24. data/lib/contextio/contact.rb +43 -0
  25. data/lib/contextio/contact_collection.rb +21 -0
  26. data/lib/contextio/email_address.rb +53 -0
  27. data/lib/contextio/email_address_collection.rb +21 -0
  28. data/lib/contextio/email_settings.rb +146 -0
  29. data/lib/contextio/file.rb +92 -0
  30. data/lib/contextio/file_collection.rb +13 -0
  31. data/lib/contextio/folder.rb +56 -0
  32. data/lib/contextio/folder_collection.rb +18 -0
  33. data/lib/contextio/folder_sync_data.rb +32 -0
  34. data/lib/contextio/message.rb +96 -0
  35. data/lib/contextio/message_collection.rb +35 -0
  36. data/lib/contextio/oauth_provider.rb +29 -0
  37. data/lib/contextio/oauth_provider_collection.rb +46 -0
  38. data/lib/contextio/source.rb +55 -0
  39. data/lib/contextio/source_collection.rb +41 -0
  40. data/lib/contextio/source_sync_data.rb +23 -0
  41. data/lib/contextio/thread.rb +15 -0
  42. data/lib/contextio/thread_collection.rb +25 -0
  43. data/lib/contextio/version.rb +11 -0
  44. data/lib/contextio/webhook.rb +39 -0
  45. data/lib/contextio/webhook_collection.rb +26 -0
  46. data/spec/config.yml.example +3 -0
  47. data/spec/contextio/account_collection_spec.rb +78 -0
  48. data/spec/contextio/account_spec.rb +52 -0
  49. data/spec/contextio/api/association_helpers_spec.rb +28 -0
  50. data/spec/contextio/api/resource_collection_spec.rb +286 -0
  51. data/spec/contextio/api/resource_spec.rb +467 -0
  52. data/spec/contextio/api/url_builder_spec.rb +78 -0
  53. data/spec/contextio/api_spec.rb +123 -0
  54. data/spec/contextio/connect_token_collection_spec.rb +74 -0
  55. data/spec/contextio/connect_token_spec.rb +58 -0
  56. data/spec/contextio/email_settings_spec.rb +112 -0
  57. data/spec/contextio/oauth_provider_collection_spec.rb +36 -0
  58. data/spec/contextio/oauth_provider_spec.rb +120 -0
  59. data/spec/contextio/source_collection_spec.rb +57 -0
  60. data/spec/contextio/source_spec.rb +52 -0
  61. data/spec/contextio/version_spec.rb +10 -0
  62. data/spec/contextio_spec.rb +64 -0
  63. data/spec/spec_helper.rb +17 -0
  64. metadata +234 -12
  65. data/README.textile +0 -29
@@ -0,0 +1,18 @@
1
+ require_relative 'api/resource_collection'
2
+ require_relative 'folder'
3
+
4
+ class ContextIO
5
+ class FolderCollection
6
+ include ContextIO::API::ResourceCollection
7
+
8
+ self.resource_class = ContextIO::Folder
9
+ self.association_name = :folders
10
+
11
+ belongs_to :source
12
+
13
+ def create(folder_name, folder_delimiter='/')
14
+ api.request(:put, "#{resource_url}/#{folder_name}", delim: folder_delimiter)['success']
15
+ end
16
+ end
17
+ end
18
+
@@ -0,0 +1,32 @@
1
+ class ContextIO
2
+ class FolderSyncData
3
+ attr_reader :name
4
+
5
+ def initialize(name, attr_hash)
6
+ @name = name
7
+ @attr_hash = attr_hash
8
+ end
9
+
10
+ def initial_import_finished?
11
+ attr_hash['initial_import_finished']
12
+ end
13
+
14
+ def last_expunged_at
15
+ Time.at(attr_hash['last_expunge'])
16
+ end
17
+
18
+ def last_sync_started_at
19
+ Time.at(attr_hash['last_sync_start'])
20
+ end
21
+
22
+ def last_sync_stopped_at
23
+ Time.at(attr_hash['last_sync_stop'])
24
+ end
25
+
26
+ private
27
+
28
+ def attr_hash
29
+ @attr_hash
30
+ end
31
+ end
32
+ end
@@ -0,0 +1,96 @@
1
+ require 'contextio/api/resource'
2
+
3
+ class ContextIO
4
+ class Message
5
+ include ContextIO::API::Resource
6
+
7
+ self.primary_key = :message_id
8
+ self.association_name = :message
9
+
10
+ belongs_to :account
11
+ has_many :sources
12
+ has_many :body_parts
13
+
14
+ lazy_attributes :date, :folders, :addresses, :subject, :list_help,
15
+ :list_unsubscribe, :message_id, :email_message_id,
16
+ :gmail_message_id, :gmail_thread_id, :person_info,
17
+ :date_received, :date_indexed
18
+ private :date_received, :date_indexed
19
+
20
+ def received_at
21
+ @received_at ||= Time.at(date_received)
22
+ end
23
+
24
+ def indexed_at
25
+ @indexed_at ||= Time.at(date_indexed)
26
+ end
27
+
28
+ def flags
29
+ api.request(:get, "#{resource_url}/flags")
30
+ end
31
+
32
+ # As of this writing, the documented valid flags are: seen, answered,
33
+ # flagged, deleted, and draft. However, this will send whatever you send it.
34
+ def set_flags(flag_hash)
35
+ args = flag_hash.map({}) do |memo, (flag_name, value)|
36
+ memo[flag_name] = value ? 1 : 0
37
+ memo
38
+ end
39
+
40
+ api.request(:post, resource_url, args)['success']
41
+ end
42
+
43
+ def folders
44
+ api.request(:get, "#{resource_url}/folders").collect { |f| f['name'] }
45
+ end
46
+
47
+ def headers
48
+ api.request(:get, "#{resource_url}/headers")
49
+ end
50
+
51
+ def raw
52
+ api.raw_request(:get, "#{resource_url}/source")
53
+ end
54
+
55
+ # You can call this with a Folder object, in which case, the source from the
56
+ # folder will be used, or you can pass in a folder name and source label.
57
+ def copy_to(folder, source = nil)
58
+ if folder.is_a?(ContextIO::Folder)
59
+ folder_name = folder.name
60
+ source_label = folder.source.label
61
+ else
62
+ folder_name = folder.to_s
63
+ source_label = source.to_s
64
+ end
65
+
66
+ api.request(:post, resource_url, dst_folder: folder_name, dst_source: source_label)['success']
67
+ end
68
+
69
+ # You can call this with a Folder object, in which case, the source from the
70
+ # folder will be used, or you can pass in a folder name and source label.
71
+ def move_to(folder, source = nil)
72
+ if folder.is_a?(ContextIO::Folder)
73
+ folder_name = folder.name
74
+ source_label = folder.source.label
75
+ else
76
+ folder_name = folder.to_s
77
+ source_label = source.to_s
78
+ end
79
+
80
+ api.request(:post, resource_url, dst_folder: folder_name, dst_source: source_label, move: 1)['success']
81
+ end
82
+
83
+ def delete
84
+ api.request(:delete, resource_url)['success']
85
+ end
86
+
87
+ private
88
+
89
+ # The API doesn't return enough information to build a resource_url for this
90
+ # resource, or the resource_url its self, making this problematic. Marking
91
+ # this private until something is sorted on that front.
92
+ def thread
93
+ ContextIO::Thread.new(api, api.request(:get, "#{resource_url}/thread").merge(account: account))
94
+ end
95
+ end
96
+ end
@@ -0,0 +1,35 @@
1
+ require_relative 'api/resource_collection'
2
+ require_relative 'message'
3
+
4
+ class ContextIO
5
+ class MessageCollection
6
+ include ContextIO::API::ResourceCollection
7
+
8
+ self.resource_class = ContextIO::Message
9
+ self.association_name = :messages
10
+
11
+ belongs_to :account
12
+
13
+ # You can pass a Folder object and this'll use the source from it, or you
14
+ # can pass a folder label and a source label (from the API), if that's
15
+ # easier for you.
16
+ #
17
+ # This is private because AFAICT, the oauth gem doesn't do POST requests
18
+ # with Content-Type = 'multipart/form-data' easily. I think it might behoove
19
+ # us to replace that dependency in the future, anyway, and we can fix this
20
+ # at that point. In any case, this functionality was missing from previous
21
+ # releases of the contextio gem, too.
22
+ def create(raw_message, folder, source = nil)
23
+ if folder.is_a?(ContextIO::Folder)
24
+ folder_label = folder.name
25
+ source_label = source || folder.source.label
26
+ else
27
+ folder_label = folder.to_s
28
+ source_label = source.to_s
29
+ end
30
+
31
+ api.request(:post, resource_url, message: raw_message, dst_folder: folder_label, dst_source: source_label)['success']
32
+ end
33
+ private :create
34
+ end
35
+ end
@@ -0,0 +1,29 @@
1
+ require 'contextio/api/resource'
2
+
3
+ class ContextIO
4
+ # Represents a single OAuth provider for an account. You can use this to
5
+ # inspect or delete the provider. Most of the attributes are lazily loaded,
6
+ # meaning that the API won't get hit until you ask for an attribute the object
7
+ # doesn't already have (presumably from a previous API call).
8
+ class OAuthProvider
9
+ include API::Resource
10
+
11
+ # @!attribute [r] provider_consumer_key
12
+ # @return [String] The consumer key associated with this provider. Will
13
+ # fetch from the API if necessary.
14
+ # @!attribute [r] provider_consumer_secret
15
+ # @return [String] The consumer secret associated with this provider. Will
16
+ # fetch from the API if necessary.
17
+ # @!attribute [r] type
18
+ # @return [String] The consumer key associated with this provider. Will
19
+ # fetch from the API if necessary.
20
+ lazy_attributes :provider_consumer_key, :provider_consumer_secret, :type
21
+
22
+ self.primary_key = :provider_consumer_key
23
+ self.association_name = :oauth_provider
24
+
25
+ def delete
26
+ api.request(:delete, resource_url)['success']
27
+ end
28
+ end
29
+ end
@@ -0,0 +1,46 @@
1
+ require_relative 'oauth_provider'
2
+ require_relative 'api/resource_collection'
3
+
4
+ class ContextIO
5
+ # Represents a collection of OAuth providers for an account. You can use this
6
+ # to create a proider, fetch a specific one or iterate over them.
7
+ #
8
+ # @example You can iterate over them with `each`:
9
+ # contextio.oauth_providers.each do |oauth_provider|
10
+ # puts oauth_provider.type
11
+ # end
12
+ #
13
+ # @example You can lazily access a specific one with square brackets:
14
+ # provider = contextio.oauth_providers['some_provider_consumer_key']
15
+ class OAuthProviderCollection
16
+ include ContextIO::API::ResourceCollection
17
+
18
+ self.resource_class = ContextIO::OAuthProvider
19
+ self.association_name = :oauth_providers
20
+
21
+ # Creates a new OAuth provider for your account.
22
+ #
23
+ # @param [String] type The type of provider. As of this writing, the API
24
+ # only accepts 'GMAIL' and 'GOOGLEAPPSMARKETPLACE'.
25
+ # @param [String] provider_consumer_key The Provider Consumer Key you got
26
+ # when you OAuthed the user.
27
+ # @param [String] provider_consumer_secret The Provider Consumer Secret you
28
+ # got when you OAuthed the user.
29
+ #
30
+ # @return [OAuthProvider] A new provider instance based on the data you
31
+ # input.
32
+ def create(type, provider_consumer_key, provider_consumer_secret)
33
+ result_hash = api.request(
34
+ :post,
35
+ resource_url,
36
+ type: type,
37
+ provider_consumer_key: provider_consumer_key,
38
+ provider_consumer_secret: provider_consumer_secret
39
+ )
40
+
41
+ result_hash.delete('success')
42
+
43
+ resource_class.new(api, result_hash)
44
+ end
45
+ end
46
+ end
@@ -0,0 +1,55 @@
1
+ require 'contextio/api/resource'
2
+
3
+ class ContextIO
4
+ class Source
5
+ include ContextIO::API::Resource
6
+
7
+ self.primary_key = :label
8
+ self.association_name = :source
9
+
10
+ belongs_to :account
11
+ has_many :folders
12
+
13
+ lazy_attributes :server, :label, :username, :port, :authentication_type,
14
+ :status, :service_level, :sync_period, :use_ssl, :type
15
+ private :use_ssl
16
+
17
+ # @!attribute [r] use_ssl?
18
+ # @return [Boolean] Whether or not this source uses SSL.
19
+ def use_ssl?
20
+ use_ssl
21
+ end
22
+
23
+ # Updates the source.
24
+ #
25
+ # @params [Hash{String, Symbol => String}] options You can update the
26
+ # following: status, sync_period, service_level, password, provider_token,
27
+ # provider_token_secret, provider_consumer_key. See the Context.IO docs
28
+ # for more details on these fields.
29
+ def update(options={})
30
+ updatable_attrs = %w(status sync_period service_level password
31
+ provider_token provider_token_secret
32
+ provider_consumer_key)
33
+
34
+ options.keep_if do |key, value|
35
+ updatable_attrs.include?(key.to_s)
36
+ end
37
+
38
+ return nil if options.empty?
39
+
40
+ it_worked = api.request(:post, resource_url, options)['success']
41
+
42
+ if it_worked
43
+ options.each do |key, value|
44
+ instance_variable_set("@#{key}", value)
45
+ end
46
+ end
47
+
48
+ it_worked
49
+ end
50
+
51
+ def delete
52
+ api.request(:delete, resource_url)['success']
53
+ end
54
+ end
55
+ end
@@ -0,0 +1,41 @@
1
+ require_relative 'api/resource_collection'
2
+ require_relative 'source'
3
+
4
+ class ContextIO
5
+ class SourceCollection
6
+ include ContextIO::API::ResourceCollection
7
+
8
+ self.resource_class = ContextIO::Source
9
+ self.association_name = :sources
10
+
11
+ belongs_to :account
12
+
13
+ # Creates a new source for an account.
14
+ #
15
+ # @param [String] email The email address for the new source.
16
+ # @param [String] server The address of the server for the source.
17
+ # @param [String] username The name for logging into the server. Often the
18
+ # same as the email.
19
+ # @param [Boolean] use_ssl Whether to use SSL for the new source.
20
+ # @param [Numeric, String] port The port to connect on.
21
+ # @param [String] type Currently, only 'IMAP' is supported.
22
+ # @param [Hash{String, Symbol => String}] options Information you can
23
+ # provide at creation. Check out the Context.IO documentation for what's
24
+ # required and what's optional.
25
+ def create(email, server, username, use_ssl, port, type, options={})
26
+ api_args = options.merge(
27
+ 'email' => email,
28
+ 'username' => username,
29
+ 'use_ssl' => use_ssl ? '1' : '0',
30
+ 'port' => port.to_s,
31
+ 'type' => type
32
+ )
33
+
34
+ result_hash = api.request(:post, resource_url, api_args)
35
+
36
+ result_hash.delete('success')
37
+
38
+ resource_class.new(api, result_hash)
39
+ end
40
+ end
41
+ end
@@ -0,0 +1,23 @@
1
+ require_relative 'folder_sync_data'
2
+
3
+ class ContextIO
4
+ class SourceSyncData
5
+ attr_reader :folder_names, :folders, :source_label
6
+
7
+ def initialize(source_label, folder_hash)
8
+ @folder_hash = folder_hash
9
+ @source_label = source_label
10
+ @folder_names = folder_hash.keys
11
+
12
+ @folders = folder_hash.collect do |folder_name, attr_hash|
13
+ ContextIO::FolderSyncData.new(folder_name, attr_hash)
14
+ end
15
+ end
16
+
17
+ private
18
+
19
+ def folder_hash
20
+ @folder_hash
21
+ end
22
+ end
23
+ end
@@ -0,0 +1,15 @@
1
+ require 'contextio/api/resource'
2
+
3
+ class ContextIO
4
+ class Thread
5
+ include ContextIO::API::Resource
6
+
7
+ self.primary_key = :gmail_thread_id
8
+ self.association_name = :thread
9
+
10
+ belongs_to :account
11
+ has_many :messages
12
+
13
+ lazy_attributes :gmail_thread_id, :email_message_ids, :person_info
14
+ end
15
+ end
@@ -0,0 +1,25 @@
1
+ require_relative 'api/resource_collection'
2
+ require_relative 'thread'
3
+
4
+ class ContextIO
5
+ class ThreadCollection
6
+ include ContextIO::API::ResourceCollection
7
+
8
+ self.resource_class = ContextIO::Thread
9
+ self.association_name = :threads
10
+
11
+ belongs_to :account
12
+
13
+ # Iterates over the resources in question.
14
+ #
15
+ # @example
16
+ # contextio.connect_tokens.each do |connect_token|
17
+ # puts connect_token.email
18
+ # end
19
+ def each(&block)
20
+ attribute_hashes.each do |actually_a_resource_url|
21
+ yield resource_class.new(api, {resource_url: actually_a_resource_url}.merge(associations_hash))
22
+ end
23
+ end
24
+ end
25
+ end
@@ -0,0 +1,11 @@
1
+ class ContextIO
2
+ # @private
3
+ VERSION = "1.0.0"
4
+
5
+ # The gem version.
6
+ #
7
+ # @return [String] The gem version.
8
+ def self.version
9
+ VERSION
10
+ end
11
+ end
@@ -0,0 +1,39 @@
1
+ require 'contextio/api/resource'
2
+
3
+ class ContextIO
4
+ class Webhook
5
+ include ContextIO::API::Resource
6
+
7
+ self.primary_key = :webhook_id
8
+ self.association_name = :webhook
9
+
10
+ belongs_to :account
11
+
12
+ lazy_attributes :callback_url, :failure_notif_url, :active, :sync_period,
13
+ :failure, :webhook_id, :filter_to, :filter_from, :filter_cc,
14
+ :filter_subject, :filter_thread, :filter_new_important,
15
+ :filter_file_name, :filter_file_revisions,
16
+ :filter_folder_added, :filter_folder_removed
17
+ private :active, :failure
18
+
19
+ def active?
20
+ !!active
21
+ end
22
+
23
+ def failure?
24
+ !!failure
25
+ end
26
+
27
+ def activate
28
+ api.request(:post, resource_url, active: 1)['success']
29
+ end
30
+
31
+ def deactivate
32
+ api.request(:post, resource_url, active: 0)['success']
33
+ end
34
+
35
+ def delete
36
+ api.request(:delete, resource_url)['success']
37
+ end
38
+ end
39
+ end