contextio 0.5.0 → 1.0.0

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