cell_force 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 6fd8af7240d36472b094418d8ef3fd322e3178f5
4
+ data.tar.gz: e790f1469e248b37b5e40d4ff89bf36aaee875d9
5
+ SHA512:
6
+ metadata.gz: 91037b7369f21e6311686dc279be5204e69d53a49ddaa7cbc0e1d27497763552d53acd6b518b3fb6fa302dba9870d1292db8bfb5b3b1f9dfaf85fc34fd5c1e15
7
+ data.tar.gz: 0746e22d1759e817fb9b1757f61c2a09267156aeeec44108b5b84fc72cfa5cc3bfbc6c86bd7cb494eb72d0d3fabc08b3ec7bade64bb252c216de28687963499c
data/.gitignore ADDED
@@ -0,0 +1,15 @@
1
+ /.bundle/
2
+ /.yardoc
3
+ /Gemfile.lock
4
+ /_yardoc/
5
+ /coverage/
6
+ /doc/
7
+ /pkg/
8
+ /spec/reports/
9
+ /tmp/
10
+ *.bundle
11
+ *.so
12
+ *.o
13
+ *.a
14
+ mkmf.log
15
+ secrets.yml
data/.rspec ADDED
@@ -0,0 +1,2 @@
1
+ --color
2
+ --order random
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in cell_force.gemspec
4
+ gemspec
data/LICENSE.txt ADDED
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2015 Isaac Betesh
2
+
3
+ MIT License
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining
6
+ a copy of this software and associated documentation files (the
7
+ "Software"), to deal in the Software without restriction, including
8
+ without limitation the rights to use, copy, modify, merge, publish,
9
+ distribute, sublicense, and/or sell copies of the Software, and to
10
+ permit persons to whom the Software is furnished to do so, subject to
11
+ the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be
14
+ included in all copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,97 @@
1
+ # CellForce
2
+
3
+ We use HTTParty to send SMS messages using the CellForce API. See USAGE below for details.
4
+
5
+ ## Installation
6
+
7
+ Add this line to your application's Gemfile:
8
+
9
+ ```ruby
10
+ gem 'cell_force'
11
+ ```
12
+
13
+ And then execute:
14
+
15
+ ``` bash
16
+ $ bundle
17
+ ```
18
+
19
+ Or install it yourself as:
20
+
21
+ ``` bash
22
+ $ gem install cell_force
23
+ ```
24
+
25
+ ## Usage
26
+
27
+ #### Configuration
28
+
29
+ cell_force requires you to provide a username, password and API key. Configure them before attempting to post to any AOI resource.
30
+
31
+ ```ruby
32
+ CellForce.configure do |config|
33
+ config.username = "Me"
34
+ config.password = "MyPassword"
35
+ config.api_key = "ReallyLongRandomString1234567789"
36
+ end
37
+ ```
38
+
39
+ Since cell_force depends on sms_validation (https://github.com/betesh/sms_validation/), it is also recommended that you configure sms_validation.
40
+ cell_force uses sms_validation's logger. In a Rails environment, you will probably want to rely on the default configuration,
41
+ but outside of Rails, you will need to configure it if you want any logging:
42
+
43
+ ```ruby
44
+ SmsValidation.configure do |config|
45
+ config.logger = ::Logger.new(STDOUT)
46
+ end
47
+ ```
48
+
49
+ #### Sending an SMS
50
+
51
+ Once configured, cell_force will automatically log you in before the first API call and will store your credentials for all subsequent API calls.
52
+ cell_force transparently logs in again whenever you session expires (i.e. if you log out or if 1 hours has elapsed since your last API call).
53
+
54
+ So once configured, just fire away with API calls, which are done using CellForce::Api#post:
55
+
56
+ ```ruby
57
+ api = CellForce::Api
58
+ api.post("shortcode/getusershortcodes")
59
+ api.post("shortcode/getshortcodecarriers", shortcode_id: ENV['SHORT_CODE'])
60
+ ```
61
+
62
+ But don't use CellForce::Api#post to send an SMS. If you do, you'll bypass sms_validation. Instead, use CellForce::MobileDevice#send_mt, so that everything gets validated.
63
+
64
+ ```ruby
65
+ mobile_device = CellForce::MobileDevice.new(my_phone_number)
66
+ mobile_device.send_mt(my_phone_number, "Hi, How are you?")
67
+ ```
68
+ sms_validation allows you to configure what to do when a message is too long. cell_force is only designed to work with the default behavior: :raise_error
69
+
70
+ If you need the :truncate or :split behavior instead, instantiate an SmsValidation::Sms and iterate through its messages:
71
+
72
+ ```ruby
73
+ mobile_device = CellForce::MobileDevice.new(my_phone_number)
74
+
75
+ SmsValidation::Sms.new(my_phone_number, "Hi, How are you?"*387).messages.each do |message|
76
+ mobile_device.send_mt(message)
77
+ end
78
+ ```
79
+
80
+ CellForce's documentation does recommend that you log out at the end of your activity
81
+ ```ruby
82
+ CellForce::Api.log_out
83
+ ```
84
+
85
+ ## Testing
86
+
87
+ Copy spec/secrets.yml.example to spec/secrets.yml and modify it to set appropriate credentails. Then run `rspec`.
88
+
89
+ Note that none of the tests set any expectations. If you run them and they all pass, it only verifies that nothing through an exception. So make sure to check your phone after running the tests to make sure you received all the expected text messages.
90
+
91
+ ## Contributing
92
+
93
+ 1. Fork it ( https://github.com/[my-github-username]/cell_force/fork )
94
+ 2. Create your feature branch (`git checkout -b my-new-feature`)
95
+ 3. Commit your changes (`git commit -am 'Add some feature'`)
96
+ 4. Push to the branch (`git push origin my-new-feature`)
97
+ 5. Create a new Pull Request
data/Rakefile ADDED
@@ -0,0 +1,43 @@
1
+ require "bundler/gem_tasks"
2
+
3
+ $LOAD_PATH << File.expand_path("#{File.dirname(__FILE__)}/lib") << File.expand_path(File.dirname(__FILE__))
4
+ require "cell_force"
5
+
6
+ namespace :cell_force do
7
+ desc "configure CellForce API"
8
+ task :configure do
9
+ require "sms_validation"
10
+ SmsValidation.configure do |config|
11
+ require "logger"
12
+ config.logger = ::Logger.new(STDOUT)
13
+ config.logger.level = Logger::INFO
14
+ config.log_at :info
15
+ end
16
+
17
+ require "yaml"
18
+ secrets = YAML::load(File.open('spec/secrets.yml'))
19
+ CellForce.configure do |config|
20
+ config.username, config.password, config.api_key = secrets["username"], secrets["password"], secrets["api_key"]
21
+ end
22
+ end
23
+
24
+ desc "Reserve a keyword (KEYWORD=XXX rake cell_force:reserve_keyword)"
25
+ task reserve_keyword: :configure do
26
+ CellForce::TcpaOptInCampaign.new(ENV['KEYWORD']).keyword_id
27
+ end
28
+
29
+ desc "Enable a keyword (KEYWORD=XXX rake cell_force:enable_keyword)"
30
+ task enable_keyword: :configure do
31
+ CellForce::Api.post("keyword/enable", row_id: CellForce::TcpaOptInCampaign.new(ENV['KEYWORD']).keyword_id)
32
+ end
33
+
34
+ desc "List all keywords associated with the account"
35
+ task list_keywords: :configure do
36
+ puts CellForce::Api.post("keyword/list").data.collect { |k| "#{k["keyword"]}#{" (campaign: '#{k["campaign"]}')" unless "N/A" == k["campaign"] }" }.join(", ")
37
+ end
38
+
39
+ desc "Send an MT (PHONE=NNNNNNNNNN rake cell_force:send_mt)"
40
+ task send_mt: :configure do
41
+ CellForce::MobileDevice.new(ENV['PHONE']).send_mt("Test message via CellForce. Sent at #{Time.now}")
42
+ end
43
+ end
@@ -0,0 +1,27 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'cell_force/version'
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = "cell_force"
8
+ spec.version = CellForce::VERSION
9
+ spec.authors = ["Isaac Betesh"]
10
+ spec.email = ["iybetesh@gmail.com"]
11
+ spec.description = "Send SMS messages using the CellForce API"
12
+ spec.summary = `cat README.md`
13
+ spec.homepage = "https://github.com/betesh/cell_force/"
14
+ spec.license = "MIT"
15
+
16
+ spec.files = `git ls-files -z`.split("\x0")
17
+ spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
18
+ spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
19
+ spec.require_paths = ["lib"]
20
+
21
+ spec.add_development_dependency "bundler", "~> 1.7"
22
+ spec.add_development_dependency "rake", "~> 10.0"
23
+ spec.add_development_dependency "rspec"
24
+
25
+ spec.add_dependency "sms_validation"
26
+ spec.add_dependency "httparty"
27
+ end
data/lib/cell_force.rb ADDED
@@ -0,0 +1,6 @@
1
+ require "cell_force/version"
2
+ require "cell_force/mobile_device"
3
+
4
+ module CellForce
5
+ # Your code goes here...
6
+ end
@@ -0,0 +1,82 @@
1
+ require "httparty"
2
+ require "sms_validation"
3
+ require "cell_force/configuration"
4
+
5
+ module CellForce
6
+ class Api
7
+ class Http
8
+ include HTTParty
9
+ base_uri "https://www.mycellforce.com"
10
+ end
11
+
12
+ module Util
13
+ class << self
14
+ def filtered(hash)
15
+ hash.is_a?(Hash) ? hash.reject{ |k,v| PARAMETER_FILTER.include?(k.to_sym) } : hash
16
+ end
17
+
18
+ def hash_to_log(hash)
19
+ hash.sort_by{ |k,v| k }.collect{|k,v| "\t\t\t#{k}:#{" " * (15 - k.length)}\t#{v}" }.join("\n")
20
+ end
21
+
22
+ def parse_response(response)
23
+ body = JSON.parse(response.body)
24
+ SmsValidation.log { "CellForce API: #{response.code}:#{response.message}" }
25
+ SmsValidation.configuration.logger.debug { "\n\t\tHeaders:\n#{hash_to_log(response.headers)}" }
26
+ SmsValidation.log { "\n\t\tBody:\n#{hash_to_log(body.inject({}) { |hash, (k,v)| hash[k] = filtered(v); hash })}" }
27
+ raise Failure, body["error"] if "failure" == body["status"]
28
+ Struct.new(*body.keys.collect(&:to_sym)).new(*body.values)
29
+ end
30
+
31
+ def convert_sms_args(args)
32
+ validation = args.delete(:sms_validation)
33
+ unless validation.is_a?(SmsValidation::Sms)
34
+ raise StandardError, "You cannot send an SMS by calling #{CellForce::Api}#post directly. Use #{CellForce::Api}#send_sms(phone, message) instead."
35
+ end
36
+ args.merge(cellnumber: validation.phone[1..-1], message: validation.message)
37
+ end
38
+ end
39
+ end
40
+
41
+ class Failure < StandardError; end
42
+
43
+ LOG_IN_RESOURCE = "users/login"
44
+ SEND_SMS_RESOURCE = "member/sendsms"
45
+ PARAMETER_FILTER = [:password, :user_key]
46
+
47
+ class << self
48
+ def post(resource, body={})
49
+ body = Util.convert_sms_args(body.dup) if SEND_SMS_RESOURCE == resource
50
+ Util.parse_response(post_with_automatic_login(resource, body))
51
+ end
52
+
53
+ def log_out
54
+ post("users/logout").tap { @login_data = nil }
55
+ end
56
+
57
+ private
58
+ def post_with_automatic_login(resource, body)
59
+ body = body.merge(login_data) unless LOG_IN_RESOURCE == resource
60
+ SmsValidation.log { "CellForce API: POST #{resource}#{filtered_body = Util.filtered(body); " -- #{filtered_body.inspect}" unless filtered_body.empty?}" }
61
+ result = Http.post("/exlapiservice/#{resource}", headers: configuration.headers, body: body )
62
+ if "The user key is invalid" == JSON.parse(result.body)["error"]
63
+ @login_data = nil
64
+ post_with_automatic_login(resource, body)
65
+ else
66
+ result
67
+ end
68
+ end
69
+
70
+ def configuration
71
+ CellForce.configuration
72
+ end
73
+
74
+ def login_data
75
+ @login_data ||= begin
76
+ SmsValidation.log { "CellForce API: Logged out. Logging in again..." }
77
+ post(LOG_IN_RESOURCE, configuration.credentials).data
78
+ end
79
+ end
80
+ end
81
+ end
82
+ end
@@ -0,0 +1,37 @@
1
+ module CellForce
2
+ class << self
3
+ def configuration
4
+ @configuration ||= Configuration.new
5
+ end
6
+
7
+ def configure
8
+ yield configuration
9
+ end
10
+ end
11
+
12
+ class Configuration
13
+ class Error < ::StandardError; end
14
+ [:username, :password, :api_key].each do |accessor|
15
+ define_method(:"#{accessor}=") do |arg|
16
+ raise Error, "#{accessor} must be a String" unless arg.nil? || arg.is_a?(String)
17
+ raise Error, "#{accessor} cannot be blank" if arg.nil? || arg.empty?
18
+ @credentials = @headers = nil
19
+ instance_variable_set("@#{accessor}", arg)
20
+ end
21
+
22
+ define_method(accessor) do
23
+ instance_variable_get("@#{accessor}").tap do |result|
24
+ raise Error, "#{accessor} has not been set. Set it with `CellForce.configuration.#{accessor} = ...`" if result.nil?
25
+ end
26
+ end
27
+ end
28
+
29
+ def credentials
30
+ @credentials ||= { username: username, password: password }
31
+ end
32
+
33
+ def headers
34
+ @headers ||= { "apikey" => api_key }
35
+ end
36
+ end
37
+ end
@@ -0,0 +1,17 @@
1
+ require "cell_force/api"
2
+
3
+ module CellForce
4
+ module DefaultShortCode
5
+ def short_code_id
6
+ @short_code_id ||= begin
7
+ data = Api.post("shortcode/getusershortcodes").data
8
+ if short_code
9
+ data.find{ |e| short_code.to_s == e["shortcode"].to_s }
10
+ else
11
+ # If the instance was not initialized with a short_code, we use the first one we find
12
+ data[0].tap { |s| @short_code = s["shortcode"] }
13
+ end["shortcode_id"]
14
+ end
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,30 @@
1
+ require "cell_force/default_short_code"
2
+ require "cell_force/tcpa_opt_in_campaign"
3
+
4
+ module CellForce
5
+ class MobileDevice
6
+ include DefaultShortCode
7
+
8
+ attr_reader :phone, :short_code
9
+ def initialize(phone, short_code=nil)
10
+ @phone, @short_code = phone, short_code
11
+ end
12
+
13
+ def send_mt(message)
14
+ Api.post(Api::SEND_SMS_RESOURCE, sms_validation: SmsValidation::Sms.new(phone, message), shortcode_id: short_code_id).data["mt_id"]
15
+ end
16
+
17
+ def simulate_mo(keyword, campaign_options={})
18
+ tcpa_opt_in_campaign = TcpaOptInCampaign.new(keyword)
19
+ if tcpa_opt_in_campaign.campaign_ids.empty?
20
+ tcpa_opt_in_campaign.create_campaign(campaign_options)
21
+ end
22
+ Api.post("sms/mo", cellnumber: phone, message: keyword, shortcode_id: short_code_id, carrier_id: carrier_id, trigger: "DOUBLEOPTIN")
23
+ end
24
+
25
+ private
26
+ def carrier_id
27
+ @carrier_id ||= Api.post("member/networklookup", cellphone: phone).data["id"]
28
+ end
29
+ end
30
+ end
@@ -0,0 +1,41 @@
1
+ require "cell_force/default_short_code"
2
+
3
+ module CellForce
4
+ class TcpaOptInCampaign
5
+ include DefaultShortCode
6
+
7
+ REQUIRED_KEYS_TO_CREATE_CAMPAIGN = [:name, :first_message, :second_message, :error_message]
8
+
9
+ attr_reader :keyword, :short_code
10
+ def initialize(keyword, short_code=nil)
11
+ @keyword, @short_code = keyword, short_code
12
+ end
13
+
14
+ def keyword_id
15
+ @keyword_id ||= begin
16
+ begin
17
+ Api.post("keyword/create", keyword: keyword, shortcodes: short_code_id, action: "check").data["message"]
18
+ Api.post("keyword/create", keyword: keyword, shortcodes: short_code_id).data["row_id"]
19
+ rescue CellForce::Api::Failure => e
20
+ raise e unless e.to_s == "Keyword is already Exist"
21
+ if (keyword_record = Api.post("keyword/list").data.find{ |r| keyword == r["keyword"] }) #Intentional assignment operator
22
+ keyword_record["id"]
23
+ else
24
+ raise StandardError, "This keyword is already in use by another consumer of the short_code #{short_code}"
25
+ end
26
+ end
27
+ end
28
+ end
29
+
30
+ def campaign_ids
31
+ @campaign_ids ||= Api.post("campaign/list").data.collect do |campaign|
32
+ campaign["campaign_id"] if keyword_id == Api.post("campaign/detail", row_id: campaign["campaign_id"]).data["keyword_id"]
33
+ end.compact
34
+ end
35
+
36
+ def create_campaign(options)
37
+ raise ArgumentError, "Some options were missing for creating a campaign: #{REQUIRED_KEYS_TO_CREATE_CAMPAIGN - options.keys}" unless (REQUIRED_KEYS_TO_CREATE_CAMPAIGN - options.keys).empty?
38
+ Api.post("campaign/tcpaoptin", keyword_id: keyword_id, shortcode_id: short_code_id, optinkeyword: "Y", name: options[:name], message: options[:first_message], doubleoptinmessage: options[:second_message], errormessage: options[:error_message]).data["campaign_id"]
39
+ end
40
+ end
41
+ end
@@ -0,0 +1,3 @@
1
+ module CellForce
2
+ VERSION = "0.0.1"
3
+ end
data/spec/api_spec.rb ADDED
@@ -0,0 +1,27 @@
1
+ require "spec_helper"
2
+ require "cell_force/api"
3
+ require "support/configuration_from_yaml"
4
+
5
+ describe CellForce::Api do
6
+ include ConfigurationFromYaml
7
+
8
+ subject { described_class }
9
+
10
+ it "should log_out" do
11
+ subject.log_out
12
+ end
13
+
14
+ describe "with the wrong API key" do
15
+ before(:each) do
16
+ CellForce.configuration.api_key = "12345"
17
+ end
18
+
19
+ after(:each) do
20
+ CellForce.configuration.api_key = api_key
21
+ end
22
+
23
+ it "should raise an Api::Failure" do
24
+ expect{subject.post("shortcode/getusershortcodes")}.to raise_error(CellForce::Api::Failure, "Invalid API Key")
25
+ end
26
+ end
27
+ end
@@ -0,0 +1,141 @@
1
+ require "spec_helper"
2
+ require "cell_force/configuration"
3
+
4
+ describe CellForce::Configuration do
5
+ subject { CellForce.configuration }
6
+
7
+ before(:each) { reset_configuration }
8
+
9
+ describe "#username" do
10
+ it "cannot be nil" do
11
+ expect{subject.username = nil}.to raise_error(CellForce::Configuration::Error, "username cannot be blank")
12
+ end
13
+
14
+ it "cannot be an empty String" do
15
+ expect{subject.username = ""}.to raise_error(CellForce::Configuration::Error, "username cannot be blank")
16
+ end
17
+
18
+ it "cannot be a Hash" do
19
+ expect{subject.username = {}}.to raise_error(CellForce::Configuration::Error, "username must be a String")
20
+ end
21
+
22
+ describe "when password and api_key are already set" do
23
+ before(:each) do
24
+ subject.password = "VerySecret"
25
+ subject.api_key = "LongApiKey"
26
+ end
27
+
28
+ it "must be set before calling #credentials" do
29
+ expect{subject.credentials}.to raise_error(CellForce::Configuration::Error, "username has not been set. Set it with `CellForce.configuration.username = ...`")
30
+ end
31
+
32
+ it "need not be set before calling #headers" do
33
+ expect{subject.headers}.not_to raise_error
34
+ end
35
+ end
36
+ end
37
+
38
+ describe "#password" do
39
+ it "cannot be nil" do
40
+ expect{subject.password = nil}.to raise_error(CellForce::Configuration::Error, "password cannot be blank")
41
+ end
42
+
43
+ it "cannot be an empty String" do
44
+ expect{subject.password = ""}.to raise_error(CellForce::Configuration::Error, "password cannot be blank")
45
+ end
46
+
47
+ it "cannot be a Hash" do
48
+ expect{subject.password = {}}.to raise_error(CellForce::Configuration::Error, "password must be a String")
49
+ end
50
+
51
+ describe "when username and api_key are already set" do
52
+ before(:each) do
53
+ subject.username = "Placeholder"
54
+ subject.api_key = "LongApiKey"
55
+ end
56
+
57
+ it "must be set before calling #credentials" do
58
+ expect{subject.credentials}.to raise_error(CellForce::Configuration::Error, "password has not been set. Set it with `CellForce.configuration.password = ...`")
59
+ end
60
+
61
+ it "need not be set before calling #headers" do
62
+ expect{subject.headers}.not_to raise_error
63
+ end
64
+ end
65
+ end
66
+
67
+ describe "#api_key" do
68
+ it "cannot be nil" do
69
+ expect{subject.api_key = nil}.to raise_error(CellForce::Configuration::Error, "api_key cannot be blank")
70
+ end
71
+
72
+ it "cannot be an empty String" do
73
+ expect{subject.api_key = ""}.to raise_error(CellForce::Configuration::Error, "api_key cannot be blank")
74
+ end
75
+
76
+ it "cannot be a Hash" do
77
+ expect{subject.api_key = {}}.to raise_error(CellForce::Configuration::Error, "api_key must be a String")
78
+ end
79
+
80
+ describe "when username and password are already set" do
81
+ before(:each) do
82
+ subject.username = "Placeholder"
83
+ subject.password = "VerySecret"
84
+ end
85
+
86
+ it "need not be set before calling #credentials" do
87
+ expect{subject.credentials}.not_to raise_error
88
+ end
89
+
90
+ it "must be set before calling #headers" do
91
+ expect{subject.headers}.to raise_error(CellForce::Configuration::Error, "api_key has not been set. Set it with `CellForce.configuration.api_key = ...`")
92
+ end
93
+ end
94
+ end
95
+
96
+ describe "#credentials" do
97
+ let(:username) { "PercyWeasley" }
98
+ let(:password) { "FredWeasley" }
99
+
100
+ let(:new_username) { "GeorgeWeasley" }
101
+ let(:new_password) { "RonaldWeasley" }
102
+
103
+ before(:each) do
104
+ CellForce.configure do |config|
105
+ config.username = username
106
+ config.password = password
107
+ end
108
+ end
109
+
110
+ it "should contain username and password" do
111
+ expect(subject.credentials).to eq(username: username, password: password)
112
+ end
113
+
114
+ it "should detect changes to username" do
115
+ expect{subject.username = new_username}.to change{subject.credentials}.from(username: username, password: password).to(username: new_username, password: password)
116
+ end
117
+
118
+ it "should detect changes to password" do
119
+ expect{subject.password = new_password}.to change{subject.credentials}.from(username: username, password: password).to(username: username, password: new_password)
120
+ end
121
+ end
122
+
123
+ describe "#headers" do
124
+ let(:api_key) { "DracoMalfoy" }
125
+ let(:new_api_key) { "HarryPotter" }
126
+
127
+ before(:each) do
128
+ CellForce.configure do |config|
129
+ config.api_key = api_key
130
+ end
131
+ end
132
+
133
+ it "should contain api_key" do
134
+ expect(subject.headers).to eq("apikey" => api_key)
135
+ end
136
+
137
+ it "should detect changes to username" do
138
+ expect{subject.api_key = new_api_key}.to change{subject.headers}.from("apikey" => api_key).to("apikey" => new_api_key)
139
+ end
140
+ end
141
+ end
@@ -0,0 +1,81 @@
1
+ require "spec_helper"
2
+ require "cell_force/mobile_device"
3
+ require "support/configuration_from_yaml"
4
+
5
+ describe CellForce::MobileDevice do
6
+ include ConfigurationFromYaml
7
+
8
+ subject { described_class.new(phone) }
9
+ let(:api) { CellForce::Api }
10
+
11
+ it "should send an sms" do
12
+ subject.send_mt("Test message via CellForce. Sent at #{Time.now}")
13
+ end
14
+
15
+ describe "simulating an MO" do
16
+ def clean_up
17
+ keyword_record = api.post("keyword/list").data.find{ |r| keyword == r["keyword"] }
18
+ if keyword_record
19
+ api.post("campaign/list").data.each do |campaign|
20
+ if keyword_record["id"] == api.post("campaign/detail", row_id: campaign["campaign_id"]).data["keyword_id"]
21
+ api.post("campaign/delete", row_id: campaign["campaign_id"])
22
+ end
23
+ end
24
+ api.post("keyword/delete", row_id: keyword_record["id"])
25
+ end
26
+ end
27
+
28
+ let(:keyword) { "CDF" }
29
+ let(:keyword_id) do
30
+ api.post("keyword/create", keyword: keyword, shortcodes: subject.send(:short_code_id)).data["row_id"]
31
+ end
32
+
33
+ let(:campaign_id) do
34
+ api.post(
35
+ "campaign/tcpaoptin",
36
+ keyword_id: keyword_id,
37
+ shortcode_id: subject.send(:short_code_id),
38
+ optinkeyword: "Y",
39
+ name: "Opt in to Keyword #{keyword}",
40
+ message: "Welcome to keyword #{keyword} campaigns. To join, reply Y",
41
+ doubleoptinmessage: "Thanks, you have joined keyword #{keyword} campaigns",
42
+ errormessage: "We could not understand your response. Please reply Y to join"
43
+ ).data["campaign_id"]
44
+ end
45
+
46
+ before(:each) do
47
+ clean_up
48
+ end
49
+
50
+ let(:campaign_options) {
51
+ {
52
+ name: "Opt in to Keyword #{keyword}",
53
+ first_message: "Welcome to keyword #{keyword} campaigns. To join, reply Y",
54
+ second_message: "Thanks, you have joined keyword #{keyword} campaigns",
55
+ error_message: "We could not understand your response. Please reply Y to join"
56
+ }
57
+ }
58
+
59
+ after(:each) do
60
+ tcpa_opt_in = CellForce::TcpaOptInCampaign.new(keyword)
61
+ tcpa_opt_in.campaign_ids.each do |id|
62
+ api.post("campaign/delete", row_id: id)
63
+ end
64
+ api.post("keyword/delete", row_id: tcpa_opt_in.keyword_id)
65
+ end
66
+
67
+ it "should simulate an MO when the keyword does not already exist" do
68
+ subject.simulate_mo(keyword, campaign_options)
69
+ end
70
+
71
+ it "should simulate an MO when the keyword exists but the campaign does not" do
72
+ keyword_id
73
+ subject.simulate_mo(keyword, campaign_options)
74
+ end
75
+
76
+ it "should simulate an MO when the keyword and campaign already exist" do
77
+ campaign_id
78
+ subject.simulate_mo(keyword)
79
+ end
80
+ end
81
+ end
@@ -0,0 +1,5 @@
1
+ # Use a username and password from the client level of the hierarchy
2
+ username: MyClient
3
+ password: MyClientPassword
4
+ api_key: ReallyLongRandomString1234567789
5
+ phone: [Put a phone number here. Just digits, no hyphens. That phone number should receive SMS messages during these tests.]
@@ -0,0 +1,7 @@
1
+ RSpec.configure do |config|
2
+ def reset_configuration
3
+ CellForce.instance_variable_set("@configuration", nil)
4
+ end
5
+
6
+ config.after(:all) { reset_configuration }
7
+ end
@@ -0,0 +1,21 @@
1
+ require "yaml"
2
+ require "logger"
3
+ require "rspec/core/shared_context"
4
+
5
+ module ConfigurationFromYaml
6
+ extend RSpec::Core::SharedContext
7
+ SECRETS = YAML::load(File.open('spec/secrets.yml'))
8
+
9
+ [:phone, :username, :password, :api_key].each do |key|
10
+ let(key) { SECRETS[key.to_s] }
11
+ end
12
+
13
+ before(:each) do
14
+ SmsValidation.configure do |config|
15
+ config.logger = ::Logger.new(STDOUT)
16
+ end
17
+ CellForce.configure do |config|
18
+ config.username, config.password, config.api_key = username, password, api_key
19
+ end
20
+ end
21
+ end
metadata ADDED
@@ -0,0 +1,176 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: cell_force
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ platform: ruby
6
+ authors:
7
+ - Isaac Betesh
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2015-04-14 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: bundler
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: '1.7'
20
+ type: :development
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: '1.7'
27
+ - !ruby/object:Gem::Dependency
28
+ name: rake
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: '10.0'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
39
+ - !ruby/object:Gem::Version
40
+ version: '10.0'
41
+ - !ruby/object:Gem::Dependency
42
+ name: rspec
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - ">="
46
+ - !ruby/object:Gem::Version
47
+ version: '0'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - ">="
53
+ - !ruby/object:Gem::Version
54
+ version: '0'
55
+ - !ruby/object:Gem::Dependency
56
+ name: sms_validation
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - ">="
60
+ - !ruby/object:Gem::Version
61
+ version: '0'
62
+ type: :runtime
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - ">="
67
+ - !ruby/object:Gem::Version
68
+ version: '0'
69
+ - !ruby/object:Gem::Dependency
70
+ name: httparty
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - ">="
74
+ - !ruby/object:Gem::Version
75
+ version: '0'
76
+ type: :runtime
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - ">="
81
+ - !ruby/object:Gem::Version
82
+ version: '0'
83
+ description: Send SMS messages using the CellForce API
84
+ email:
85
+ - iybetesh@gmail.com
86
+ executables: []
87
+ extensions: []
88
+ extra_rdoc_files: []
89
+ files:
90
+ - ".gitignore"
91
+ - ".rspec"
92
+ - Gemfile
93
+ - LICENSE.txt
94
+ - README.md
95
+ - Rakefile
96
+ - cell_force.gemspec
97
+ - lib/cell_force.rb
98
+ - lib/cell_force/api.rb
99
+ - lib/cell_force/configuration.rb
100
+ - lib/cell_force/default_short_code.rb
101
+ - lib/cell_force/mobile_device.rb
102
+ - lib/cell_force/tcpa_opt_in_campaign.rb
103
+ - lib/cell_force/version.rb
104
+ - spec/api_spec.rb
105
+ - spec/configuration_spec.rb
106
+ - spec/mobile_device_spec.rb
107
+ - spec/secrets.yml.example
108
+ - spec/spec_helper.rb
109
+ - spec/support/configuration_from_yaml.rb
110
+ homepage: https://github.com/betesh/cell_force/
111
+ licenses:
112
+ - MIT
113
+ metadata: {}
114
+ post_install_message:
115
+ rdoc_options: []
116
+ require_paths:
117
+ - lib
118
+ required_ruby_version: !ruby/object:Gem::Requirement
119
+ requirements:
120
+ - - ">="
121
+ - !ruby/object:Gem::Version
122
+ version: '0'
123
+ required_rubygems_version: !ruby/object:Gem::Requirement
124
+ requirements:
125
+ - - ">="
126
+ - !ruby/object:Gem::Version
127
+ version: '0'
128
+ requirements: []
129
+ rubyforge_project:
130
+ rubygems_version: 2.2.2
131
+ signing_key:
132
+ specification_version: 4
133
+ summary: '# CellForce We use HTTParty to send SMS messages using the CellForce API. See
134
+ USAGE below for details. ## Installation Add this line to your application''s
135
+ Gemfile: ```ruby gem ''cell_force'' ``` And then execute: ``` bash $ bundle ``` Or
136
+ install it yourself as: ``` bash $ gem install cell_force ``` ## Usage #### Configuration cell_force
137
+ requires you to provide a username, password and API key. Configure them before
138
+ attempting to post to any AOI resource. ```ruby CellForce.configure do |config|
139
+ config.username = "Me" config.password = "MyPassword" config.api_key = "ReallyLongRandomString1234567789"
140
+ end ``` Since cell_force depends on sms_validation (https://github.com/betesh/sms_validation/),
141
+ it is also recommended that you configure sms_validation. cell_force uses sms_validation''s
142
+ logger. In a Rails environment, you will probably want to rely on the default configuration,
143
+ but outside of Rails, you will need to configure it if you want any logging: ```ruby
144
+ SmsValidation.configure do |config| config.logger = ::Logger.new(STDOUT) end ``` ####
145
+ Sending an SMS Once configured, cell_force will automatically log you in before
146
+ the first API call and will store your credentials for all subsequent API calls.
147
+ cell_force transparently logs in again whenever you session expires (i.e. if you
148
+ log out or if 1 hours has elapsed since your last API call). So once configured,
149
+ just fire away with API calls, which are done using CellForce::Api#post: ```ruby
150
+ api = CellForce::Api api.post("shortcode/getusershortcodes") api.post("shortcode/getshortcodecarriers",
151
+ shortcode_id: ENV[''SHORT_CODE'']) ``` But don''t use CellForce::Api#post to send
152
+ an SMS. If you do, you''ll bypass sms_validation. Instead, use CellForce::MobileDevice#send_mt,
153
+ so that everything gets validated. ```ruby mobile_device = CellForce::MobileDevice.new(my_phone_number)
154
+ mobile_device.send_mt(my_phone_number, "Hi, How are you?") ``` sms_validation allows
155
+ you to configure what to do when a message is too long. cell_force is only designed
156
+ to work with the default behavior: :raise_error If you need the :truncate or :split
157
+ behavior instead, instantiate an SmsValidation::Sms and iterate through its messages: ```ruby
158
+ mobile_device = CellForce::MobileDevice.new(my_phone_number) SmsValidation::Sms.new(my_phone_number,
159
+ "Hi, How are you?"*387).messages.each do |message| mobile_device.send_mt(message)
160
+ end ``` CellForce''s documentation does recommend that you log out at the end of
161
+ your activity ```ruby CellForce::Api.log_out ``` ## Testing Copy spec/secrets.yml.example
162
+ to spec/secrets.yml and modify it to set appropriate credentails. Then run `rspec`. Note
163
+ that none of the tests set any expectations. If you run them and they all pass,
164
+ it only verifies that nothing through an exception. So make sure to check your
165
+ phone after running the tests to make sure you received all the expected text messages. ##
166
+ Contributing 1. Fork it ( https://github.com/[my-github-username]/cell_force/fork
167
+ ) 2. Create your feature branch (`git checkout -b my-new-feature`) 3. Commit your
168
+ changes (`git commit -am ''Add some feature''`) 4. Push to the branch (`git push
169
+ origin my-new-feature`) 5. Create a new Pull Request'
170
+ test_files:
171
+ - spec/api_spec.rb
172
+ - spec/configuration_spec.rb
173
+ - spec/mobile_device_spec.rb
174
+ - spec/secrets.yml.example
175
+ - spec/spec_helper.rb
176
+ - spec/support/configuration_from_yaml.rb