context-io 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (51) hide show
  1. data/Gemfile +4 -0
  2. data/LICENSE +21 -0
  3. data/README.md +129 -0
  4. data/Rakefile +121 -0
  5. data/SPEC.md +49 -0
  6. data/context-io.gemspec +96 -0
  7. data/lib/context-io.rb +14 -0
  8. data/lib/context-io/account.rb +254 -0
  9. data/lib/context-io/authentication.rb +23 -0
  10. data/lib/context-io/config.rb +103 -0
  11. data/lib/context-io/connection.rb +45 -0
  12. data/lib/context-io/core_ext/hash.rb +31 -0
  13. data/lib/context-io/error.rb +24 -0
  14. data/lib/context-io/error/bad_request.rb +12 -0
  15. data/lib/context-io/error/client_error.rb +10 -0
  16. data/lib/context-io/error/forbidden.rb +12 -0
  17. data/lib/context-io/error/internal_server_error.rb +10 -0
  18. data/lib/context-io/error/not_found.rb +12 -0
  19. data/lib/context-io/error/payment_required.rb +13 -0
  20. data/lib/context-io/error/server_error.rb +10 -0
  21. data/lib/context-io/error/service_unavailable.rb +13 -0
  22. data/lib/context-io/error/unauthorized.rb +12 -0
  23. data/lib/context-io/file.rb +234 -0
  24. data/lib/context-io/folder.rb +90 -0
  25. data/lib/context-io/message.rb +160 -0
  26. data/lib/context-io/oauth_provider.rb +84 -0
  27. data/lib/context-io/request.rb +70 -0
  28. data/lib/context-io/request/oauth.rb +44 -0
  29. data/lib/context-io/resource.rb +16 -0
  30. data/lib/context-io/response.rb +5 -0
  31. data/lib/context-io/response/parse_json.rb +30 -0
  32. data/lib/context-io/response/raise_client_error.rb +59 -0
  33. data/lib/context-io/response/raise_server_error.rb +32 -0
  34. data/lib/context-io/source.rb +193 -0
  35. data/lib/context-io/version.rb +7 -0
  36. data/spec/account_spec.rb +247 -0
  37. data/spec/contextio_spec.rb +45 -0
  38. data/spec/file_spec.rb +101 -0
  39. data/spec/fixtures/accounts.json +21 -0
  40. data/spec/fixtures/files.json +41 -0
  41. data/spec/fixtures/files_group.json +47 -0
  42. data/spec/fixtures/folders.json +1 -0
  43. data/spec/fixtures/messages.json +1 -0
  44. data/spec/fixtures/oauth_providers.json +12 -0
  45. data/spec/fixtures/sources.json +1 -0
  46. data/spec/folder_spec.rb +48 -0
  47. data/spec/message_spec.rb +294 -0
  48. data/spec/oauth_provider_spec.rb +88 -0
  49. data/spec/source_spec.rb +248 -0
  50. data/spec/spec_helper.rb +4 -0
  51. metadata +214 -0
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source :rubygems
2
+
3
+ gemspec
4
+
data/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ The MIT License
2
+
3
+ Copyright (c) Henrik Hodne
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in
13
+ all copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21
+ THE SOFTWARE.
@@ -0,0 +1,129 @@
1
+ ContextIO - Extract data from email
2
+ ===================================
3
+
4
+ [![Build Status](https://secure.travis-ci.org/dvyjones/context-io.png)](http://travis-ci.org/dvyjones/context-io)
5
+ [![Dependency Status](https://gemnasium.com/dvyjones/context-io.png)](https://gemnasium.com/dvyjones/context-io)
6
+
7
+ ## Description
8
+
9
+ ContextIO is a Ruby wrapper for the [Context.IO][contextio] web service.
10
+
11
+ Context.IO is the missing email API that makes it easy and fast
12
+ to integrate your user's email data in your application.
13
+
14
+ ContextIO follows the rules of [Semantic Versioning][semver] and uses
15
+ [TomDoc][tomdoc] for inline documentation.
16
+
17
+ [contextio]: http://context.io
18
+ [semver]: http://semver.org
19
+ [tomdoc]: http://tomdoc.org
20
+
21
+
22
+ ## Installation
23
+
24
+ The best way to install ContextIO is through Rubygems:
25
+
26
+ ```
27
+ $ [sudo] gem install context-io
28
+ ```
29
+
30
+ If you're installing from source, you can use [Bundler][bundler] to pick up all
31
+ the gems:
32
+
33
+ ```
34
+ $ bundle install
35
+ ```
36
+
37
+ [bundler]: http://gembundler.org
38
+
39
+ ## Usage
40
+
41
+ The ContextIO classes map pretty much one-to-one to the Context.IO API
42
+ resources, which you can find [on their documentation site][contextiodocs].
43
+
44
+ [contextiodocs]: http://context.io/docs/2.0
45
+
46
+ ### Authenticate
47
+
48
+ ContextIO uses two-legged [OAuth][oauth] for authentication, which means you
49
+ need to get an API key from [Context.IO][contextio]. The API key consists of a
50
+ consumer key and a consumer secret, and once you have them you can set up
51
+ ContextIO like this:
52
+
53
+ ```ruby
54
+ ContextIO.configure do |config|
55
+ config.consumer_key = 'consumer key'
56
+ config.consumer_secret = 'consumer secret'
57
+ end
58
+ ```
59
+
60
+ [oauth]: http://oauth.net/
61
+
62
+ ### Get an Account object
63
+
64
+ Once you're authenticated, you can get an `Account` object, which is what you
65
+ will be dealing with most of the time.
66
+
67
+ ```ruby
68
+ account = ContextIO::Account.all.first
69
+ ```
70
+
71
+ You can also find accounts matching a given email address.
72
+
73
+ ```ruby
74
+ account = ContextIO::Account.all(:email => 'me@example.org').first
75
+ ```
76
+
77
+ ## Contributing
78
+
79
+ In the spirit of [free software][free-sw], **everyone** is encouraged to help
80
+ improve this project.
81
+
82
+ Here are some ways *you* can contribute:
83
+
84
+ * by using alpha, beta and prerelease versions
85
+ * by reporting bugs
86
+ * by suggesting new features
87
+ * by writing or editing documentation
88
+ * by writing specifications
89
+ * by writing code (**no patch is too small**: fix typos, add comments, clean up
90
+ inconsistent whitespace)
91
+ * by refactoring code
92
+ * by closing [issues][issues]
93
+ * by reviewing patches
94
+
95
+ ### Submitting an Issue
96
+
97
+ We use the [GitHub issue tracker][issues] to track bugs and features. Before
98
+ submitting a bug report or feature request, check to make sure it hasn't
99
+ already been submitted. You can indicate support for an existing issue by
100
+ writing a comment saying you have the same issue (please include what version
101
+ of the gem you are using, as well as what version of ruby). When submitting a
102
+ bug report, please include a [gist][gist] that includes a stack trace and any
103
+ details that may be necessary to reproduce the bug, including your gem version,
104
+ Ruby version and operating system. Ideally, a bug report should include a pull
105
+ request with failing specs.
106
+
107
+ ### Submitting a Pull Request
108
+
109
+ 1. Fork the project.
110
+ 2. Create a topic branch.
111
+ 3. Implement your feature or bug fix.
112
+ 4. Add documentation for your feature or bug fix.
113
+ 5. Run `bundle exec rake rdoc`. If your changes are not 100% documented, go
114
+ back to step 4.
115
+ 6. Add specs for your feature or bug fix.
116
+ 7. Run `bundle exec rake spec`. If your changes are not 100% covered, go back
117
+ to step 6.
118
+ 8. Commit your changes. If necessary, merge in upstream and rebase your
119
+ changes. Push your changes.
120
+ 9. Submit a pull request. Please do not include changes to the gemspec,
121
+ version or history file.
122
+
123
+ [free-sw]: http://www.gnu.org/philosophy/free-sw.html
124
+ [issues]: https://github.com/dvyjones/context-io/issues
125
+
126
+
127
+ ## Copyright
128
+
129
+ Copyright (c) 2012 Henrik Hodne. See LICENSE for details.
@@ -0,0 +1,121 @@
1
+ require 'rubygems'
2
+ require 'rake'
3
+ require 'date'
4
+
5
+ #############################################################################
6
+ #
7
+ # Helper functions
8
+ #
9
+ #############################################################################
10
+
11
+ def name
12
+ @name ||= Dir['*.gemspec'].first.split('.').first
13
+ end
14
+
15
+ def version
16
+ line = File.read("lib/#{name}/version.rb")[/^\s*VERSION\s*=\s*.*/]
17
+ line.match(/.*VERSION\s*=\s*['"](.*)['"]/)[1]
18
+ end
19
+
20
+ def date
21
+ Date.today.to_s
22
+ end
23
+
24
+ def rubyforge_project
25
+ name
26
+ end
27
+
28
+ def gemspec_file
29
+ "#{name}.gemspec"
30
+ end
31
+
32
+ def gem_file
33
+ "#{name}-#{version}.gem"
34
+ end
35
+
36
+ def replace_header(head, header_name)
37
+ head.sub!(/(\.#{header_name}\s*= ').*'/) { "#{$1}#{send(header_name)}'" }
38
+ end
39
+
40
+ #############################################################################
41
+ #
42
+ # Standard tasks
43
+ #
44
+ #############################################################################
45
+
46
+ task :default => :spec
47
+
48
+ require 'rspec/core/rake_task'
49
+
50
+ RSpec::Core::RakeTask.new(:spec)
51
+
52
+ require 'yard'
53
+ YARD::Rake::YardocTask.new
54
+
55
+ #############################################################################
56
+ #
57
+ # Packaging tasks
58
+ #
59
+ #############################################################################
60
+
61
+ desc "Create tag v#{version} and build and push #{gem_file} to Rubygems"
62
+ task :release => :build do
63
+ unless `git branch` =~ /^\* master$/
64
+ puts 'You must be on the master branch to release!'
65
+ exit!
66
+ end
67
+ sh "git commit --allow-empty -a -m 'Release #{version}'"
68
+ sh "git tag v#{version}"
69
+ sh 'git push origin master'
70
+ sh "git push origin v#{version}"
71
+ sh "gem push pkg/#{gem_file}"
72
+ end
73
+
74
+ desc "Build #{gem_file} into the pkg directory"
75
+ task :build => :gemspec do
76
+ sh 'mkdir -p pkg'
77
+ sh "gem build #{gemspec_file}"
78
+ sh "mv #{gem_file} pkg"
79
+ end
80
+
81
+ desc "Generate #{gemspec_file}"
82
+ task :gemspec => :validate do
83
+ # read spec file and split out manifest section
84
+ spec = File.read(gemspec_file)
85
+ head, manifest, tail = spec.split(" # = MANIFEST =\n")
86
+
87
+ # replace name, version and date
88
+ replace_header(head, :name)
89
+ replace_header(head, :version)
90
+ replace_header(head, :date)
91
+ replace_header(head, :rubyforge_project)
92
+
93
+ # determine file list from git ls-files
94
+ files = `git ls-files`.
95
+ split("\n").
96
+ sort.
97
+ reject { |file| file =~ /^\./ }.
98
+ reject { |file| file =~ /^(rdoc|pkg)/ }.
99
+ map { |file| " #{file}" }.
100
+ join("\n")
101
+
102
+ # piece file back together and write
103
+ manifest = " s.files = %w(\n#{files}\n )\n"
104
+ spec = [head, manifest, tail].join(" # = MANIFEST =\n")
105
+ File.open(gemspec_file, 'w') { |io| io.write(spec) }
106
+ puts "Updated #{gemspec_file}"
107
+ end
108
+
109
+ desc "Validate #{gemspec_file}"
110
+ task :validate do
111
+ libfiles = Dir['lib/*'] - ["lib/#{name}.rb", "lib/#{name}"]
112
+ unless libfiles.empty?
113
+ puts "Directory `lib` should only contain a `#{name}.rb` file and `#{name}` dir."
114
+ exit!
115
+ end
116
+ unless Dir['VERSION*'].empty?
117
+ puts 'A `VERSION` file at root level violates Gem best practices.'
118
+ exit!
119
+ end
120
+ end
121
+
data/SPEC.md ADDED
@@ -0,0 +1,49 @@
1
+ ContextIO spec / roadmap
2
+ ========================
3
+
4
+ These are things that will be included in the "Usage" section of the README
5
+ file. Think of this as a roadmap.
6
+
7
+ ### Getting a list of messages
8
+
9
+ Once you have an `Account` object, you can get a list of messages as an array
10
+ of `Message` objects.
11
+
12
+ ```ruby
13
+ account.messages
14
+ # => [#<ContextIO::Message to: 'me@example.com', ...>, ...]
15
+ ```
16
+
17
+ You can also search for messages (see the documentation for
18
+ ContextIO::Message#find for the full list of attributes you can search for.
19
+
20
+ ```ruby
21
+ account.messages(:subject => 'Hello, world!').first
22
+ # => #<ContextIO::Message subject: 'Hello, world!', ...>
23
+ ```
24
+
25
+ ### The Message object
26
+
27
+ `Message` objects contains information about that message.
28
+
29
+ ```ruby
30
+ message = account.messages.first
31
+
32
+ message.subject
33
+ # => "Hello, world!"
34
+
35
+ message.from
36
+ # => "John Doe <john.doe@example.com>"
37
+
38
+ message.to
39
+ # => "me@example.com"
40
+
41
+ message.date
42
+ # => Thu Jan 05 23:30:22 +0100 2012
43
+
44
+ message.message_id
45
+ # => "abcdef0123456789"
46
+
47
+ message.email_message_id
48
+ # => "<20120105233022.abcdef0@mta1.mail.example.com>"
49
+
@@ -0,0 +1,96 @@
1
+ Gem::Specification.new do |s|
2
+ s.specification_version = 2 if s.respond_to? :specification_version=
3
+ s.required_rubygems_version = Gem::Requirement.new('>= 0') if s.respond_to? :required_rubygems_version=
4
+ s.rubygems_version = '1.3.5'
5
+
6
+ s.name = 'context-io'
7
+ s.version = '0.0.1'
8
+ s.date = '2012-01-26'
9
+ s.rubyforge_project = 'context-io'
10
+
11
+ s.summary = 'Ruby wrapper for the context.io API.'
12
+ s.description = 'Ruby wrapper for the context.io API.'
13
+
14
+ s.authors = ['Henrik Hodne']
15
+ s.email = 'dvyjones@dvyjones.com'
16
+ s.homepage = 'https://github.com/dvyjones/context-io'
17
+
18
+ s.require_paths = %w(lib)
19
+
20
+ s.rdoc_options = ['--charset=UTF-8', '--markup tomdoc', '--main README.md']
21
+ s.extra_rdoc_files = %w(README.md LICENSE)
22
+
23
+ s.add_dependency('faraday', '~> 0.7.5')
24
+ s.add_dependency('simple_oauth', '~> 0.1.5')
25
+ s.add_dependency('multi_json', '~> 1.0.0')
26
+ s.add_dependency('webmock', '~> 1.7.10')
27
+
28
+ if RUBY_PLATFORM == 'java'
29
+ s.add_dependency('jruby-openssl', '>= 0')
30
+ end
31
+
32
+ s.add_development_dependency('rspec', '~> 2.8.0')
33
+ s.add_development_dependency('rake', '~> 0.9.0')
34
+ s.add_development_dependency('yard', '~> 0.7.4')
35
+ s.add_development_dependency('yard-rspec', '~> 0.1')
36
+ s.add_development_dependency('redcarpet', '~> 2.1.0')
37
+ s.add_development_dependency('github-markup', '~> 0.7.0')
38
+
39
+ # = MANIFEST =
40
+ s.files = %w(
41
+ Gemfile
42
+ LICENSE
43
+ README.md
44
+ Rakefile
45
+ SPEC.md
46
+ context-io.gemspec
47
+ lib/context-io.rb
48
+ lib/context-io/account.rb
49
+ lib/context-io/authentication.rb
50
+ lib/context-io/config.rb
51
+ lib/context-io/connection.rb
52
+ lib/context-io/core_ext/hash.rb
53
+ lib/context-io/error.rb
54
+ lib/context-io/error/bad_request.rb
55
+ lib/context-io/error/client_error.rb
56
+ lib/context-io/error/forbidden.rb
57
+ lib/context-io/error/internal_server_error.rb
58
+ lib/context-io/error/not_found.rb
59
+ lib/context-io/error/payment_required.rb
60
+ lib/context-io/error/server_error.rb
61
+ lib/context-io/error/service_unavailable.rb
62
+ lib/context-io/error/unauthorized.rb
63
+ lib/context-io/file.rb
64
+ lib/context-io/folder.rb
65
+ lib/context-io/message.rb
66
+ lib/context-io/oauth_provider.rb
67
+ lib/context-io/request.rb
68
+ lib/context-io/request/oauth.rb
69
+ lib/context-io/resource.rb
70
+ lib/context-io/response.rb
71
+ lib/context-io/response/parse_json.rb
72
+ lib/context-io/response/raise_client_error.rb
73
+ lib/context-io/response/raise_server_error.rb
74
+ lib/context-io/source.rb
75
+ lib/context-io/version.rb
76
+ spec/account_spec.rb
77
+ spec/contextio_spec.rb
78
+ spec/file_spec.rb
79
+ spec/fixtures/accounts.json
80
+ spec/fixtures/files.json
81
+ spec/fixtures/files_group.json
82
+ spec/fixtures/folders.json
83
+ spec/fixtures/messages.json
84
+ spec/fixtures/oauth_providers.json
85
+ spec/fixtures/sources.json
86
+ spec/folder_spec.rb
87
+ spec/message_spec.rb
88
+ spec/oauth_provider_spec.rb
89
+ spec/source_spec.rb
90
+ spec/spec_helper.rb
91
+ )
92
+ # = MANIFEST =
93
+
94
+ s.test_files = s.files.select { |path| path =~ /^spec\/spec_.*\.rb/ }
95
+ end
96
+
@@ -0,0 +1,14 @@
1
+ require 'context-io/config'
2
+ require 'context-io/authentication'
3
+ require 'context-io/account'
4
+ require 'context-io/file'
5
+ require 'context-io/oauth_provider'
6
+ require 'context-io/source'
7
+ require 'context-io/message'
8
+ require 'context-io/folder'
9
+
10
+ # The main ContextIO namespace.
11
+ module ContextIO
12
+ extend Config
13
+ extend Authentication
14
+ end
@@ -0,0 +1,254 @@
1
+ # encoding: utf-8
2
+
3
+ require 'context-io/resource'
4
+
5
+ module ContextIO
6
+ # An account. Create one of these for every user.
7
+ #
8
+ # This does not represent a mail account. An Account can have several mail
9
+ # accounts attached to it as {Source}s.
10
+ #
11
+ # Only the {#first_name} and {#last_name} can be changed after creation.
12
+ class Account < ContextIO::Resource
13
+ # @api public
14
+ # @return [String] The unique ID of the account.
15
+ attr_reader :id
16
+
17
+ # @api public
18
+ # @return [String] The username of the account.
19
+ attr_reader :username
20
+
21
+ # @api public
22
+ # @return [Time] When the account was created.
23
+ attr_reader :created
24
+
25
+ # @api public
26
+ # @return [Time, nil] When the account was suspended, or nil if the account
27
+ # isn't suspended.
28
+ attr_reader :suspended
29
+
30
+ # @api public
31
+ # @return [Array<String>] The email addresses associated with the account.
32
+ attr_reader :email_addresses
33
+
34
+ # @api public
35
+ # @return [String] The first name of the account holder.
36
+ attr_accessor :first_name
37
+
38
+ # @api public
39
+ # @return [String] The last name of the account holder.
40
+ attr_accessor :last_name
41
+
42
+ # @api public
43
+ # @return [Time, nil] When the account password expired, or nil if the
44
+ # password hasn't expired.
45
+ attr_reader :password_expired
46
+
47
+ # @api public
48
+ # @return [Array<Source>] The sources associated with this account.
49
+ attr_reader :sources
50
+
51
+ # Get all the accounts, optionally filtered with a query
52
+ #
53
+ # @api public
54
+ #
55
+ # @param [Hash] query The query to filter accounts by. All fields are
56
+ # optional.
57
+ # @option query [String] :email Only return accounts associated with this
58
+ # email address.
59
+ # @option query [:invalid_credentials, :connection_impossible,
60
+ # :no_access_to_all_mail, :ok, :temp_disabled, :disabled] :status Only
61
+ # return accounts with sources whose status is the one given. If an
62
+ # account has several sources, only those matching the given status will
63
+ # be included in the response.
64
+ # @option query [true, false] :status_ok Whether to only return accounts
65
+ # with sources that are working or not working properly (true/false,
66
+ # respectively). As with the `:status` filter above, only sources matching
67
+ # the specific value are included in the response.
68
+ # @option query [Integer] :limit The maximum number of results to return.
69
+ # @option query [Integer] :offset The offset to start the list at (0 is no
70
+ # offset).
71
+ #
72
+ # @example Fetch all accounts
73
+ # ContextIO::Account.all
74
+ #
75
+ # @example Fetch all accounts with the email address me@example.com
76
+ # ContextIO::Account.all(:email => 'me@example.com')
77
+ #
78
+ # @return [Array<Account>] The accounts matching the query, or all if no
79
+ # query is given.
80
+ def self.all(query={})
81
+ query[:status] = query[:status].to_s.upcase if query[:status]
82
+ if query.has_key?(:status_ok)
83
+ query[:status_ok] = query[:status_ok] ? '1' : '0'
84
+ end
85
+ get('/2.0/accounts', query).map do |account|
86
+ Account.from_json(account)
87
+ end
88
+ end
89
+
90
+ # Find an account given its ID
91
+ #
92
+ # @api public
93
+ #
94
+ # @param [String] id The ID of the account to look up.
95
+ #
96
+ # @example Find the account with the ID 'foobar'
97
+ # ContextIO::Account.find('foobar')
98
+ #
99
+ # @return [Account] The account with the given ID.
100
+ def self.find(id)
101
+ Account.from_json(get("/2.0/accounts/#{id}"))
102
+ end
103
+
104
+ # Initialize an Account
105
+ #
106
+ # @api public
107
+ #
108
+ # @param [Hash] attributes The attributes to set on the account (all values
109
+ # are optional).
110
+ # @option attributes [String] :email The primary email address of the
111
+ # account holder.
112
+ # @option attributes [String] :first_name The first name of the account
113
+ # holder.
114
+ # @option attributes [String] :last_name The last name of the account
115
+ # holder.
116
+ #
117
+ # @example Initialize an account with the email 'me@example.com'
118
+ # ContextIO::Account.new(:email => 'me@example.com')
119
+ def initialize(attributes={})
120
+ @email_addresses = [attributes[:email]] if attributes[:email]
121
+ @first_name = attributes[:first_name]
122
+ @last_name = attributes[:last_name]
123
+ end
124
+
125
+ # Send the account info to Context.IO
126
+ #
127
+ # If this is the first time the account is sent to Context.IO, the first
128
+ # email address set will be sent as the primary email address, and the first
129
+ # and last name will be sent if they are specified. You are required to
130
+ # specify one email address.
131
+ #
132
+ # If the account has been sent to Context.IO before, this will update the
133
+ # first and last name.
134
+ #
135
+ # @api public
136
+ #
137
+ # @raise [ArgumentError] If there isn't at least one email address specified
138
+ # in the {#email_addresses} field.
139
+ #
140
+ # @example Create an account
141
+ # account = ContextIO::Account.new(:email => 'me@example.com')
142
+ # account.save
143
+ #
144
+ # @return [true, false] Whether the save succeeded or not.
145
+ def save
146
+ self.id ? update_record : create_record
147
+ end
148
+
149
+ # Update attributes on the account object and then send them to Context.IO
150
+ #
151
+ # @api public
152
+ #
153
+ # @param [Hash] attributes The attributes to update.
154
+ # @option attributes [String] :first_name The first name of the account
155
+ # holder.
156
+ # @option attributes [String] :last_name The last name of the account
157
+ # holder.
158
+ #
159
+ # @example Update the account holder's name to "John Doe"
160
+ # account.update_attributes(:first_name => 'John', :last_name => 'Doe')
161
+ #
162
+ # @return [true, false] Whether the update succeeded or not.
163
+ def update_attributes(attributes)
164
+ @first_name = attributes[:first_name] if attributes[:first_name]
165
+ @last_name = attributes[:last_name] if attributes[:last_name]
166
+
167
+ response = put("/2.0/accounts/#{self.id}", attributes)
168
+
169
+ response['success']
170
+ end
171
+
172
+ # Create the account on Context.IO
173
+ #
174
+ # @api private
175
+ #
176
+ # This will only send the first email address in the email_addresses
177
+ # attribute (which is required) as well as the first and last name if they
178
+ # are not-falsey.
179
+ #
180
+ # @return [true, false] Whether the creation succeeded or not.
181
+ def create_record
182
+ unless self.email_addresses && self.email_addresses.first
183
+ raise ArgumentError.new('You must specify an email address')
184
+ end
185
+
186
+ attributes = { :email => self.email_addresses.first }
187
+ attributes[:first_name] = self.first_name if self.first_name
188
+ attributes[:last_name] = self.last_name if self.last_name
189
+
190
+ response = post('/2.0/accounts', attributes)
191
+ @id = response['id']
192
+
193
+ @saved = response['success']
194
+ end
195
+ private :create_record
196
+
197
+ # Update the account on Context.IO
198
+ #
199
+ # Only sends the first and last name, as they are the only attributes the
200
+ # Context.IO API allows you to update.
201
+ #
202
+ # @api private
203
+ #
204
+ # @return [true, false] Whether the update succeeded or not.
205
+ def update_record
206
+ attributes = {}
207
+ attributes[:first_name] = self.first_name if self.first_name
208
+ attributes[:last_name] = self.last_name if self.last_name
209
+ response = put("/2.0/accounts/#{self.id}", attributes)
210
+
211
+ response['success']
212
+ end
213
+ private :update_record
214
+
215
+ # Create an Account instance from the JSON returned by the Context.IO server
216
+ #
217
+ # @api private
218
+ #
219
+ # @param [Hash] json The parsed JSON object returned by a Context.IO API
220
+ # request. See their documentation for what keys are possible.
221
+ #
222
+ # @return [Account] An account with the given attributes.
223
+ def self.from_json(json)
224
+ account = new
225
+ account.instance_eval do
226
+ @id = json['id']
227
+ @username = json['username']
228
+ if json['created'] == 0
229
+ @created = nil
230
+ else
231
+ @created = Time.at(json['created'])
232
+ end
233
+ if json['suspended'] == 0
234
+ @suspended = nil
235
+ else
236
+ @suspended = Time.at(json['suspended'])
237
+ end
238
+ @email_addresses = json['email_addresses']
239
+ @first_name = json['first_name']
240
+ @last_name = json['last_name']
241
+ if json['password_expired'] == 0
242
+ @password_expired = nil
243
+ else
244
+ @password_expired = json['password_expired']
245
+ end
246
+ @sources = json['sources'].map do |source|
247
+ Source.from_json(@id, source)
248
+ end
249
+ end
250
+
251
+ account
252
+ end
253
+ end
254
+ end