patient_zero 0.0.1 → 0.1.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 (36) hide show
  1. checksums.yaml +4 -4
  2. data/.rspec +2 -0
  3. data/lib/patient_zero/analytics/base.rb +35 -0
  4. data/lib/patient_zero/analytics/facebook.rb +25 -0
  5. data/lib/patient_zero/analytics/instagram.rb +13 -0
  6. data/lib/patient_zero/analytics/twitter.rb +13 -0
  7. data/lib/patient_zero/analytics.rb +16 -0
  8. data/lib/patient_zero/authorization.rb +8 -0
  9. data/lib/patient_zero/client.rb +35 -0
  10. data/lib/patient_zero/configurable.rb +21 -0
  11. data/lib/patient_zero/errors.rb +4 -0
  12. data/lib/patient_zero/message/base.rb +11 -0
  13. data/lib/patient_zero/message/facebook.rb +29 -0
  14. data/lib/patient_zero/message/instagram.rb +29 -0
  15. data/lib/patient_zero/message/twitter.rb +21 -0
  16. data/lib/patient_zero/message.rb +16 -0
  17. data/lib/patient_zero/organization.rb +27 -0
  18. data/lib/patient_zero/source.rb +36 -0
  19. data/lib/patient_zero/version.rb +1 -1
  20. data/lib/patient_zero.rb +19 -2
  21. data/patient_zero.gemspec +13 -8
  22. data/spec/patient_zero/analytics/base_spec.rb +54 -0
  23. data/spec/patient_zero/analytics/facebook_spec.rb +40 -0
  24. data/spec/patient_zero/analytics/instagram_spec.rb +35 -0
  25. data/spec/patient_zero/analytics/twitter_spec.rb +34 -0
  26. data/spec/patient_zero/analytics_spec.rb +29 -0
  27. data/spec/patient_zero/authorization_spec.rb +26 -0
  28. data/spec/patient_zero/client_spec.rb +31 -0
  29. data/spec/patient_zero/message/facebook_spec.rb +52 -0
  30. data/spec/patient_zero/message/instagram_spec.rb +53 -0
  31. data/spec/patient_zero/message/twitter_spec.rb +40 -0
  32. data/spec/patient_zero/message_spec.rb +29 -0
  33. data/spec/patient_zero/organization_spec.rb +67 -0
  34. data/spec/patient_zero/source_spec.rb +83 -0
  35. data/spec/spec_helper.rb +14 -0
  36. metadata +106 -3
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 1a4a9252ac8b5ea5e0e30a0ecad9474f702d1f8d
4
- data.tar.gz: 7c6721785383d71cc9c733024d654e847fd30e91
3
+ metadata.gz: 44dbcc4b6d6cf236eb77f548a0b764e7816b7962
4
+ data.tar.gz: 33e6b2e9170ebe01eb61ddb7bb3ddd61661e4e16
5
5
  SHA512:
6
- metadata.gz: d0fbf5e3550e1284a63ed5654814447f12e3766d80950184c508699cfea8b98d89dc790565eeba83931bb64791b9523924e9c74b5f53304d0897ce6dba827ace
7
- data.tar.gz: 142e969fbc6b4017a9ee83cc9349eaafc6843af035c9fc9a99aa5e1198aba7ea27f7380063adb0c955ecf5b8b9168befa7ba490b3e146732e078402d994707ab
6
+ metadata.gz: 7129206bd4afe74fdb1708a02d6fcfc8040845cd04fec49b67916f8aa928193b27976905a24f0db7dd784d9195c2bc9099c8ce278ffd2cc3897c332bd88d76fe
7
+ data.tar.gz: 10c63b464b5426341cd6393be167ff564ff5dc99a5356fe1493fcd6cc435e52b3fbbe8587ff12761b91437a8b0c7a881c33cd37cb477c51e4809c9d44336f3f2
data/.rspec ADDED
@@ -0,0 +1,2 @@
1
+ --require 'spec_helper'
2
+ --color true
@@ -0,0 +1,35 @@
1
+ module PatientZero
2
+ module Analytics
3
+ class Base < Client
4
+ attr_accessor :token, :source_id, :start_date, :end_date
5
+
6
+ def initialize token:, source_id:, start_date: nil, end_date: nil
7
+ @token = token
8
+ @source_id = source_id
9
+ @end_date = end_date || Date.today.to_s
10
+ @start_date = start_date || Date.today.prev_day(7).to_s
11
+ end
12
+
13
+ def name
14
+ analytical_data['name']
15
+ end
16
+
17
+ def platform
18
+ analytical_data['platform']
19
+ end
20
+
21
+ def messages
22
+ analytical_data['messages'].map { |message| Message.for_platform message['platform'], message }
23
+ end
24
+
25
+ private
26
+
27
+ def analytical_data
28
+ @analytical_data ||= get('/mobile/api/v1/analytics', client_token: token,
29
+ social_object_uid: source_id,
30
+ start_date: start_date,
31
+ end_date: end_date)['stats'].first
32
+ end
33
+ end
34
+ end
35
+ end
@@ -0,0 +1,25 @@
1
+ module PatientZero
2
+ module Analytics
3
+ class Facebook < Base
4
+ def engagements
5
+ @engagements ||= messages.reduce(0) { |sum, message| sum + message.engagements }
6
+ end
7
+
8
+ def impressions
9
+ page_impressions + message_impressions
10
+ end
11
+
12
+ private
13
+
14
+ def message_impressions
15
+ messages.reduce(0) { |sum, message| sum + message.impressions }
16
+ end
17
+
18
+ def page_impressions
19
+ analytical_data['page_impressions'].find do |impressions_hash|
20
+ impressions_hash['key'] == 'Total'
21
+ end['values'].each_value.reduce(:+)
22
+ end
23
+ end
24
+ end
25
+ end
@@ -0,0 +1,13 @@
1
+ module PatientZero
2
+ module Analytics
3
+ class Instagram < Base
4
+ def engagements
5
+ @engagements ||= messages.reduce(0) { |sum, message| sum + message.engagements }
6
+ end
7
+
8
+ def impressions
9
+ @impressions ||= messages.reduce(0) { |sum, message| sum + message.impressions }
10
+ end
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,13 @@
1
+ module PatientZero
2
+ module Analytics
3
+ class Twitter < Base
4
+ def impressions
5
+ analytical_data['total_impressions']
6
+ end
7
+
8
+ def engagements
9
+ @engagements ||= messages.reduce(0) { |sum, message| sum + message.engagements }
10
+ end
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,16 @@
1
+ require 'patient_zero/analytics/base'
2
+ require 'patient_zero/analytics/twitter'
3
+ require 'patient_zero/analytics/facebook'
4
+ require 'patient_zero/analytics/instagram'
5
+
6
+ module PatientZero
7
+ module Analytics
8
+ SOURCE_TYPES = {'twitter' => Twitter,
9
+ 'facebook' => Facebook,
10
+ 'instagram' => Instagram}
11
+
12
+ def self.for_platform platform, params={}
13
+ SOURCE_TYPES[platform].new params
14
+ end
15
+ end
16
+ end
@@ -0,0 +1,8 @@
1
+ module PatientZero
2
+ class Authorization < Client
3
+ def self.token
4
+ response = post '/mobile/api/v1/user/login', email: PatientZero.email, password: PatientZero.password
5
+ response['user_token']
6
+ end
7
+ end
8
+ end
@@ -0,0 +1,35 @@
1
+ module PatientZero
2
+ class Client
3
+ def self.connection
4
+ @@connection ||= Faraday.new(PatientZero.url) do |faraday|
5
+ faraday.request :url_encoded
6
+ faraday.response :logger
7
+ faraday.adapter Faraday.default_adapter
8
+ end
9
+ end
10
+
11
+ def self.parse request
12
+ response = JSON.parse request.body
13
+ raise Error, response['error'] unless response['error'].nil?
14
+ response
15
+ end
16
+
17
+ def self.get *args
18
+ parse connection.get *args
19
+ end
20
+
21
+ def self.post *args
22
+ parse connection.post *args
23
+ end
24
+
25
+ private
26
+
27
+ def get *args
28
+ self.class.get *args
29
+ end
30
+
31
+ def post *args
32
+ self.class.post *args
33
+ end
34
+ end
35
+ end
@@ -0,0 +1,21 @@
1
+ module PatientZero
2
+ module Configurable
3
+ attr_accessor :url, :api_key, :email, :password
4
+
5
+ def self.extended(base)
6
+ base.reset
7
+ end
8
+
9
+ def configure
10
+ yield self
11
+ self
12
+ end
13
+
14
+ def reset
15
+ self.url = 'https://app.viralheat.com'
16
+ self.api_key = ENV['VIRAL_HEAT_API_KEY']
17
+ self.email = ENV['VIRAL_HEAT_EMAIL']
18
+ self.password = ENV['VIRAL_HEAT_PASSWORD']
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,4 @@
1
+ module PatientZero
2
+ class Error < StandardError; end
3
+ class NotFoundError < Error; end
4
+ end
@@ -0,0 +1,11 @@
1
+ module PatientZero
2
+ module Message
3
+ class Base
4
+ attr_reader :data
5
+
6
+ def initialize data
7
+ @data = data
8
+ end
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,29 @@
1
+ module PatientZero
2
+ module Message
3
+ class Facebook < Base
4
+ def engagements
5
+ @engagements ||= likes + comments + shares + clicks
6
+ end
7
+
8
+ def impressions
9
+ data.fetch 'impressions'
10
+ end
11
+
12
+ def likes
13
+ data.fetch 'likes'
14
+ end
15
+
16
+ def comments
17
+ data.fetch 'comments'
18
+ end
19
+
20
+ def shares
21
+ data.fetch 'shares'
22
+ end
23
+
24
+ def clicks
25
+ data.fetch 'clicks'
26
+ end
27
+ end
28
+ end
29
+ end
@@ -0,0 +1,29 @@
1
+ module PatientZero
2
+ module Message
3
+ class Instagram < Base
4
+ def engagements
5
+ @engagements ||= likes + comments + clicks + shares
6
+ end
7
+
8
+ def impressions
9
+ data.fetch 'impressions'
10
+ end
11
+
12
+ def likes
13
+ data.fetch 'likes'
14
+ end
15
+
16
+ def comments
17
+ data.fetch 'comments'
18
+ end
19
+
20
+ def clicks
21
+ data.fetch 'clicks'
22
+ end
23
+
24
+ def shares
25
+ data.fetch('shares').to_i
26
+ end
27
+ end
28
+ end
29
+ end
@@ -0,0 +1,21 @@
1
+ module PatientZero
2
+ module Message
3
+ class Twitter < Base
4
+ def engagements
5
+ @engagements ||= retweets + favorites + clicks
6
+ end
7
+
8
+ def retweets
9
+ data.fetch 'retweets'
10
+ end
11
+
12
+ def favorites
13
+ data.fetch 'favorites'
14
+ end
15
+
16
+ def clicks
17
+ data.fetch 'clicks'
18
+ end
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,16 @@
1
+ require 'patient_zero/message/base'
2
+ require 'patient_zero/message/facebook'
3
+ require 'patient_zero/message/twitter'
4
+ require 'patient_zero/message/instagram'
5
+
6
+ module PatientZero
7
+ module Message
8
+ SOURCE_TYPES = {'TW' => Twitter,
9
+ 'FB' => Facebook,
10
+ 'IG' => Instagram}
11
+
12
+ def self.for_platform platform, params={}
13
+ SOURCE_TYPES[platform].new params
14
+ end
15
+ end
16
+ end
@@ -0,0 +1,27 @@
1
+ module PatientZero
2
+ class Organization < Client
3
+ attr_accessor :id, :name, :avatar
4
+
5
+ def initialize attributes
6
+ @id = attributes.fetch 'id'
7
+ @name = attributes.fetch 'name'
8
+ @avatar = attributes.fetch 'avatar'
9
+ end
10
+
11
+ def self.all
12
+ response = get '/mobile/api/v1/organizations', client_token: Authorization.token
13
+ response['organizations'].map do |organization_attributes|
14
+ new organization_attributes
15
+ end
16
+ end
17
+
18
+ def sources
19
+ Source.all token
20
+ end
21
+
22
+ def token
23
+ response = get "/mobile/api/v1/organizations/#{id}/switch", client_token: Authorization.token
24
+ response['user_token']
25
+ end
26
+ end
27
+ end
@@ -0,0 +1,36 @@
1
+ module PatientZero
2
+ class Source < Client
3
+ attr_accessor :id, :name, :platform, :token
4
+
5
+ def initialize attributes, token
6
+ @id = attributes.fetch 'id'
7
+ @name = attributes.fetch 'name'
8
+ @invalid = attributes.fetch 'is_invalid'
9
+ @tracked = attributes.fetch 'is_tracked'
10
+ @platform = attributes.fetch 'platform'
11
+ @token = token
12
+ end
13
+
14
+ def self.all token=Authorization.token
15
+ response = get '/mobile/api/v1/sources/', client_token: token
16
+ response['sources'].map do |source_attributes|
17
+ new source_attributes, token
18
+ end
19
+ end
20
+
21
+ def self.find source_id, token=Authorization.token
22
+ response = get '/mobile/api/v1/sources/show/', id: source_id, client_token: token
23
+ new response['source'], token
24
+ rescue Error => e
25
+ raise NotFoundError, e
26
+ end
27
+
28
+ def profile_id
29
+ id.split('#').last
30
+ end
31
+
32
+ def analytics start_date: nil, end_date: nil
33
+ @analytics ||= Analytics.for_platform platform, token: token, source_id: id, start_date: start_date, end_date: end_date
34
+ end
35
+ end
36
+ end
@@ -1,3 +1,3 @@
1
1
  module PatientZero
2
- VERSION = "0.0.1"
2
+ VERSION = "0.1.0"
3
3
  end
data/lib/patient_zero.rb CHANGED
@@ -1,5 +1,22 @@
1
- require "patient_zero/version"
1
+ require 'json'
2
+ require 'faraday'
3
+ require 'patient_zero/version'
4
+ require 'patient_zero/errors'
5
+ require 'patient_zero/client'
6
+ require 'patient_zero/configurable'
7
+ require 'patient_zero/authorization'
8
+ require 'patient_zero/organization'
9
+ require 'patient_zero/analytics'
10
+ require 'patient_zero/source'
11
+ require 'patient_zero/message'
2
12
 
3
13
  module PatientZero
4
- # Your code goes here...
14
+ extend PatientZero::Configurable
5
15
  end
16
+
17
+ # Configuration Example
18
+ # PatientZero.configure do |config|
19
+ # config.api_key = 'somethingsomethingdangerzone'
20
+ # config.email = 'duchess@cia.gov'
21
+ # config.password = 'password'
22
+ # end
data/patient_zero.gemspec CHANGED
@@ -4,20 +4,25 @@ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
4
  require 'patient_zero/version'
5
5
 
6
6
  Gem::Specification.new do |spec|
7
- spec.name = "patient_zero"
7
+ spec.name = 'patient_zero'
8
8
  spec.version = PatientZero::VERSION
9
- spec.authors = ["Adam Zaninovich"]
10
- spec.email = ["adam.zaninovich@gmail.com"]
9
+ spec.authors = ['Adam Zaninovich','Devin Clark']
10
+ spec.email = ['adam.zaninovich@gmail.com', 'notdevinclark@gmail.com']
11
11
  spec.summary = %q{A gem to use the Viral Heat API}
12
12
  spec.description = %q{A gem to use the Viral Heat API}
13
- spec.homepage = ""
14
- spec.license = "MIT"
13
+ spec.homepage = ''
14
+ spec.license = 'MIT'
15
15
 
16
16
  spec.files = `git ls-files -z`.split("\x0")
17
17
  spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
18
18
  spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
19
- spec.require_paths = ["lib"]
19
+ spec.require_paths = ['lib']
20
20
 
21
- spec.add_development_dependency "bundler", "~> 1.7"
22
- spec.add_development_dependency "rake", "~> 10.0"
21
+ spec.add_development_dependency 'bundler', '~> 1.7'
22
+ spec.add_development_dependency 'rake', '~> 10.0'
23
+ spec.add_development_dependency 'rspec'
24
+ spec.add_development_dependency 'pry'
25
+
26
+ spec.add_dependency 'faraday'
27
+ spec.add_dependency 'json'
23
28
  end
@@ -0,0 +1,54 @@
1
+ require 'spec_helper'
2
+
3
+ module PatientZero
4
+ module Analytics
5
+ describe Base do
6
+ let(:source_id) { "12345##{platform}#1234567890" }
7
+ let(:name) { 'account_name' }
8
+ let(:platform) { 'account_type' }
9
+ let(:messages) { [ { 'platform' => 'FB' } ] }
10
+ let(:token) { 'token-shmoken' }
11
+ let(:analytical_data) { { 'stats' => [ { 'id' => source_id, 'platform' => platform, 'name' => name, 'messages' => messages } ] } }
12
+ subject(:analytics_base) { Base.new token: token, source_id: source_id }
13
+ before { allow(Client).to receive(:get).with('/mobile/api/v1/analytics', anything).and_return analytical_data }
14
+
15
+ describe '#name' do
16
+ it 'calls the analytics API endpoint' do
17
+ expect(Client).to receive(:get).with('/mobile/api/v1/analytics', anything)
18
+ analytics_base.name
19
+ end
20
+ it 'pulls the name from the analytical_data hash' do
21
+ expect(analytics_base.name).to be name
22
+ end
23
+ end
24
+
25
+ describe '#platform' do
26
+ it 'calls the analytics API endpoint' do
27
+ expect(Client).to receive(:get).with('/mobile/api/v1/analytics', anything)
28
+ analytics_base.name
29
+ end
30
+ it 'pulls the platform from the analytical_data hash' do
31
+ expect(analytics_base.platform).to be platform
32
+ end
33
+ end
34
+
35
+ describe '#messages' do
36
+ it 'calls the analytics API endpoint' do
37
+ expect(Client).to receive(:get).with('/mobile/api/v1/analytics', anything)
38
+ analytics_base.name
39
+ end
40
+ context 'when there are messages' do
41
+ it 'returns an array of messages' do
42
+ expect(analytics_base.messages.first).to be_a Message::Facebook
43
+ end
44
+ end
45
+ context 'when there are no messages' do
46
+ let(:messages) { [] }
47
+ it 'returns an empty array' do
48
+ expect(analytics_base.messages).to be_empty
49
+ end
50
+ end
51
+ end
52
+ end
53
+ end
54
+ end
@@ -0,0 +1,40 @@
1
+ require 'spec_helper'
2
+
3
+ module PatientZero
4
+ module Analytics
5
+ describe Facebook do
6
+ let(:source_id) { "12345##{platform}#1234567890" }
7
+ let(:platform) { 'facebook' }
8
+ let(:message) do
9
+ { 'platform' => 'FB',
10
+ 'likes' => 93,
11
+ 'comments' => 7,
12
+ 'impressions' => 345,
13
+ 'shares' => 22,
14
+ 'clicks' => 38 }
15
+ end
16
+ let(:messages) { [ message ] }
17
+ let(:page_impressions) do
18
+ [ { 'key'=>'Total',
19
+ 'values'=>
20
+ { '2010-10-10'=> 99 } } ]
21
+ end
22
+ let(:token) { 'token-shmoken' }
23
+ let(:analytical_data) { { 'messages' => messages, 'page_impressions' => page_impressions } }
24
+ let(:facebook_analytics) { Facebook.new token: token, source_id: source_id }
25
+ before{ allow(facebook_analytics).to receive(:analytical_data).and_return analytical_data }
26
+
27
+ describe '#impressions' do
28
+ it 'returns the total for message and page impressions' do
29
+ expect(facebook_analytics.impressions).to eq 444
30
+ end
31
+ end
32
+
33
+ describe '#engagements' do
34
+ it 'returns the sum of likes, comments, shares, and clicks' do
35
+ expect(facebook_analytics.engagements).to eq 160
36
+ end
37
+ end
38
+ end
39
+ end
40
+ end
@@ -0,0 +1,35 @@
1
+ require 'spec_helper'
2
+
3
+ module PatientZero
4
+ module Analytics
5
+ describe Instagram do
6
+ let(:source_id) { "12345##{platform}#1234567890" }
7
+ let(:platform) { 'instagram' }
8
+ let(:message) do
9
+ { 'platform' => 'IG',
10
+ 'impressions' => 10101,
11
+ 'shares'=>'3',
12
+ 'likes'=>52,
13
+ 'comments'=>3,
14
+ 'clicks'=>14 }
15
+ end
16
+ let(:messages) { [ message ] }
17
+ let(:token) { 'token-shmoken' }
18
+ let(:analytical_data) { { 'messages' => messages } }
19
+ let(:instagram_analytics) { Instagram.new token: token, source_id: source_id }
20
+ before{ allow(instagram_analytics).to receive(:analytical_data).and_return analytical_data }
21
+
22
+ describe '#impressions' do
23
+ it 'returns the sum of impressions for all messages' do
24
+ expect(instagram_analytics.impressions).to eq 10101
25
+ end
26
+ end
27
+
28
+ describe '#engagements' do
29
+ it 'returns the sum of retweets, favorites, and clicks for all messages' do
30
+ expect(instagram_analytics.engagements).to eq 72
31
+ end
32
+ end
33
+ end
34
+ end
35
+ end
@@ -0,0 +1,34 @@
1
+ require 'spec_helper'
2
+
3
+ module PatientZero
4
+ module Analytics
5
+ describe Twitter do
6
+ let(:source_id) { "12345##{platform}#1234567890" }
7
+ let(:platform) { 'twitter' }
8
+ let(:message) do
9
+ { 'platform' => 'TW',
10
+ 'retweets' => 6,
11
+ 'impressions' => 13,
12
+ 'favorites' => 2,
13
+ 'clicks' => 12 }
14
+ end
15
+ let(:messages) { [ message ] }
16
+ let(:token) { 'token-shmoken' }
17
+ let(:analytical_data) { { 'messages' => messages, 'total_impressions' => 13 } }
18
+ let(:twitter_analytics) { Twitter.new token: token, source_id: source_id }
19
+ before{ allow(twitter_analytics).to receive(:analytical_data).and_return analytical_data }
20
+
21
+ describe '#impressions' do
22
+ it 'returns the total_impressions value from the analytical_data hash' do
23
+ expect(twitter_analytics.impressions).to eq 13
24
+ end
25
+ end
26
+
27
+ describe '#engagements' do
28
+ it 'returns the sum of retweets, favorites, and clicks for all messages' do
29
+ expect(twitter_analytics.engagements).to eq 20
30
+ end
31
+ end
32
+ end
33
+ end
34
+ end
@@ -0,0 +1,29 @@
1
+ require 'spec_helper'
2
+
3
+ module PatientZero
4
+ describe Analytics do
5
+ describe '.for_platform' do
6
+ let(:data_hash) { { token: "", source_id: "" } }
7
+ context 'when platform is Facebook' do
8
+ let(:platform) { 'facebook' }
9
+ it 'news up a Analytics::Facebook object' do
10
+ expect(Analytics.for_platform(platform, data_hash)).to be_a Analytics::Facebook
11
+ end
12
+ end
13
+
14
+ context 'when platform is Twitter' do
15
+ let(:platform) { 'twitter' }
16
+ it 'news up a Analytics::Twitter object' do
17
+ expect(Analytics.for_platform(platform, data_hash)).to be_a Analytics::Twitter
18
+ end
19
+ end
20
+
21
+ context 'when platform is Instagram' do
22
+ let(:platform) { 'instagram' }
23
+ it 'news up a Analytics::Instagram object' do
24
+ expect(Analytics.for_platform(platform, data_hash)).to be_a Analytics::Instagram
25
+ end
26
+ end
27
+ end
28
+ end
29
+ end
@@ -0,0 +1,26 @@
1
+ require 'spec_helper'
2
+
3
+ module PatientZero
4
+ describe Authorization do
5
+ describe '.token' do
6
+ let(:token) { 'token-shmoken' }
7
+ let(:authorization_response) { response_with_body user_token: token }
8
+ before{ allow(Client.connection).to receive(:post).with('/mobile/api/v1/user/login', anything).and_return authorization_response }
9
+ it 'calls the login api endpoint' do
10
+ expect(Client.connection).to receive(:post).with('/mobile/api/v1/user/login', anything)
11
+ Authorization.token
12
+ end
13
+ context 'when email and password are correct' do
14
+ it 'returns a user_token' do
15
+ expect(Authorization.token).to eq token
16
+ end
17
+ end
18
+ context 'when email and password are incorrect' do
19
+ let(:authorization_response) { response_with_body error: 'Invalid login/password' }
20
+ it 'raises a PatientZero::Error error' do
21
+ expect{ Authorization.token }.to raise_error PatientZero::Error
22
+ end
23
+ end
24
+ end
25
+ end
26
+ end
@@ -0,0 +1,31 @@
1
+ require 'spec_helper'
2
+
3
+ module PatientZero
4
+ describe Client do
5
+ let(:token) { 'token-shmoken' }
6
+ let(:body) { "{}" }
7
+ let(:response) { double body: body }
8
+
9
+ describe '.connection' do
10
+ it 'news up a connection to the Viral Heat API' do
11
+ expect(Client.connection).to be_a Faraday::Connection
12
+ end
13
+ end
14
+
15
+ describe '.parse' do
16
+ subject(:parse) { Client.parse response }
17
+ context 'when the response contains an error key with nil' do
18
+ let(:body) { "{\"status\":200,\"error\":null,\"user_token\":\"#{token}\"}" }
19
+ it 'returns a hash of data' do
20
+ expect(parse).to be_a Hash
21
+ end
22
+ end
23
+ context 'when the response contains an error key that is not nil' do
24
+ let(:body) { "{\"status\":403,\"error\":\"Invalid login/password\",\"user_token\":null}" }
25
+ it 'raises an error' do
26
+ expect { parse }.to raise_error Error
27
+ end
28
+ end
29
+ end
30
+ end
31
+ end
@@ -0,0 +1,52 @@
1
+ require 'spec_helper'
2
+
3
+ module PatientZero
4
+ module Message
5
+ describe Facebook do
6
+ let(:data) do
7
+ { 'platform' => 'FB',
8
+ 'likes' => 93,
9
+ 'comments' => 7,
10
+ 'impressions' => 345,
11
+ 'shares' => 22,
12
+ 'clicks' => 38 }
13
+ end
14
+ subject(:facebook_message) { Facebook.new data }
15
+ describe '#engagements' do
16
+ it 'returns the sum of likes, comments, shares, and clicks' do
17
+ expect(facebook_message.engagements).to eq 160
18
+ end
19
+ end
20
+
21
+ describe '#impressions' do
22
+ it 'returns the impression variable from the data hash' do
23
+ expect(facebook_message.impressions).to eq 345
24
+ end
25
+ end
26
+
27
+ describe '#likes' do
28
+ it 'returns the likes variable from the data hash' do
29
+ expect(facebook_message.likes).to eq 93
30
+ end
31
+ end
32
+
33
+ describe '#comments' do
34
+ it 'returns the comments variable from the data hash' do
35
+ expect(facebook_message.comments).to eq 7
36
+ end
37
+ end
38
+
39
+ describe '#shares' do
40
+ it 'returns the shares variable from the data hash' do
41
+ expect(facebook_message.shares).to eq 22
42
+ end
43
+ end
44
+
45
+ describe '#clicks' do
46
+ it 'returns the clicks variable from the data hash' do
47
+ expect(facebook_message.clicks).to eq 38
48
+ end
49
+ end
50
+ end
51
+ end
52
+ end
@@ -0,0 +1,53 @@
1
+ require 'spec_helper'
2
+
3
+ module PatientZero
4
+ module Message
5
+ describe Instagram do
6
+ let(:data) do
7
+ { 'platform' => 'IG',
8
+ 'likes' => 93,
9
+ 'comments' => 7,
10
+ 'impressions' => 345,
11
+ 'shares' => '22',
12
+ 'clicks' => 38 }
13
+ end
14
+ subject(:instagram_message) { Instagram.new data }
15
+
16
+ describe '#engagements' do
17
+ it 'returns the sum of likes, comments, shares, and clicks' do
18
+ expect(instagram_message.engagements).to eq 160
19
+ end
20
+ end
21
+
22
+ describe '#impressions' do
23
+ it 'returns the impression variable from the data hash' do
24
+ expect(instagram_message.impressions).to eq 345
25
+ end
26
+ end
27
+
28
+ describe '#likes' do
29
+ it 'returns the likes variable from the data hash' do
30
+ expect(instagram_message.likes).to eq 93
31
+ end
32
+ end
33
+
34
+ describe '#comments' do
35
+ it 'returns the comments variable from the data hash' do
36
+ expect(instagram_message.comments).to eq 7
37
+ end
38
+ end
39
+
40
+ describe '#shares' do
41
+ it 'returns the shares variable from the data hash' do
42
+ expect(instagram_message.shares).to eq 22
43
+ end
44
+ end
45
+
46
+ describe '#clicks' do
47
+ it 'returns the clicks variable from the data hash' do
48
+ expect(instagram_message.clicks).to eq 38
49
+ end
50
+ end
51
+ end
52
+ end
53
+ end
@@ -0,0 +1,40 @@
1
+ require 'spec_helper'
2
+
3
+ module PatientZero
4
+ module Message
5
+ describe Twitter do
6
+ let(:data) do
7
+ { 'platform' => 'TW',
8
+ 'favorites' => 7,
9
+ 'impressions' => 345,
10
+ 'retweets' => 22,
11
+ 'clicks' => 38 }
12
+ end
13
+ subject(:twitter_message) { Twitter.new data }
14
+
15
+ describe '#engagements' do
16
+ it 'returns the sum of retweets, favorites, and clicks' do
17
+ expect(twitter_message.engagements).to eq 67
18
+ end
19
+ end
20
+
21
+ describe '#retweets' do
22
+ it 'returns the retweets variable from the data hash' do
23
+ expect(twitter_message.retweets).to eq 22
24
+ end
25
+ end
26
+
27
+ describe '#favorites' do
28
+ it 'returns the favorites variable from the data hash' do
29
+ expect(twitter_message.favorites).to eq 7
30
+ end
31
+ end
32
+
33
+ describe '#clicks' do
34
+ it 'returns the clicks variable from the data hash' do
35
+ expect(twitter_message.clicks).to eq 38
36
+ end
37
+ end
38
+ end
39
+ end
40
+ end
@@ -0,0 +1,29 @@
1
+ require 'spec_helper'
2
+
3
+ module PatientZero
4
+ describe Message do
5
+ describe '.for_platform' do
6
+ let(:data_hash) { { } }
7
+ context 'when platform is Facebook' do
8
+ let(:platform) { 'FB' }
9
+ it 'news up a Message::Facebook object' do
10
+ expect(Message.for_platform(platform, data_hash)).to be_a Message::Facebook
11
+ end
12
+ end
13
+
14
+ context 'when platform is Twitter' do
15
+ let(:platform) { 'TW' }
16
+ it 'news up a Message::Twitter object' do
17
+ expect(Message.for_platform(platform, data_hash)).to be_a Message::Twitter
18
+ end
19
+ end
20
+
21
+ context 'when platform is Instagram' do
22
+ let(:platform) { 'IG' }
23
+ it 'news up a Message::Instagram object' do
24
+ expect(Message.for_platform(platform, data_hash)).to be_a Message::Instagram
25
+ end
26
+ end
27
+ end
28
+ end
29
+ end
@@ -0,0 +1,67 @@
1
+ require 'spec_helper'
2
+
3
+ module PatientZero
4
+ describe Organization do
5
+ let(:id) { 12345 }
6
+ let(:token) { 'token-shmoken' }
7
+ let(:organization) { Organization.new organization_response_data }
8
+ let(:organizations_response_data) { [organization_response_data] }
9
+ let(:organization_response_data) do
10
+ { "id"=>id,
11
+ "name"=>"Organization One",
12
+ "avatar"=>
13
+ { "thumbnail"=>"https://s3.amazonaws.com/viralheat/avatars/organizations/12345/thumb/fake_img_1.png",
14
+ "medium"=>"https://s3.amazonaws.com/viralheat/avatars/organizations/12345/medium/fake_img_1.png",
15
+ "large"=>"https://s3.amazonaws.com/viralheat/avatars/organizations/12345/large/fake_img_1.png" } }
16
+ end
17
+
18
+ before { allow(Authorization).to receive(:token).and_return token }
19
+
20
+ describe '.all' do
21
+ let(:organizations) { [organization] }
22
+ let(:organizations_response) { response_with_body organizations: organizations_response_data }
23
+ before { allow(Client.connection).to receive(:get).with('/mobile/api/v1/organizations', anything) { organizations_response } }
24
+
25
+ it 'calls the organizations api endpoint' do
26
+ expect(Client.connection).to receive(:get).with('/mobile/api/v1/organizations', anything)
27
+ Organization.all
28
+ end
29
+
30
+ context 'if the user has organizations' do
31
+ it 'returns an array of all organizations available' do
32
+ expect(Organization.all.map(&:id)).to eq organizations.map(&:id)
33
+ end
34
+ end
35
+
36
+ context 'if the user has no organizations' do
37
+ let(:organizations_response_data) { [] }
38
+ it 'returns an empty array' do
39
+ expect(Organization.all).to be_empty
40
+ end
41
+ end
42
+ end
43
+
44
+ describe '#sources' do
45
+ it 'calls Source.all and passes its own organization user_token' do
46
+ allow(organization).to receive(:token).and_return token
47
+ expect(Source).to receive(:all).with(token)
48
+ organization.sources
49
+ end
50
+ end
51
+
52
+ describe '#token' do
53
+ let(:organization_specific_token) { 'organization-token' }
54
+ let(:switch_response) { response_with_body user_token: organization_specific_token }
55
+ before { allow(Client.connection).to receive(:get).with("/mobile/api/v1/organizations/#{id}/switch", anything).and_return switch_response }
56
+
57
+ it 'calls the organization switch api endpoint' do
58
+ expect(Client.connection).to receive(:get).with("/mobile/api/v1/organizations/#{id}/switch", anything)
59
+ organization.token
60
+ end
61
+
62
+ it 'returns the organization specific user_token' do
63
+ expect(organization.token).to eq organization_specific_token
64
+ end
65
+ end
66
+ end
67
+ end
@@ -0,0 +1,83 @@
1
+ require 'spec_helper'
2
+
3
+ module PatientZero
4
+ describe Source do
5
+ let(:id) { '12345#instagram_account#1234567890' }
6
+ let(:token) { 'token-shmoken' }
7
+ let(:sources_response_data) { [source_response_data] }
8
+ let(:source_response_data) do
9
+ {'id'=> id,
10
+ 'name' => 'account_name',
11
+ 'is_invalid' => false,
12
+ 'is_tracked' => true,
13
+ 'platform' => 'instagram',
14
+ 'delete_id' => id }
15
+ end
16
+ let(:source) { Source.new source_response_data, token }
17
+
18
+ describe '.all' do
19
+ before do
20
+ allow(Authorization).to receive(:token).and_return token
21
+ allow(Client.connection).to receive(:get).with('/mobile/api/v1/sources/', anything).and_return response_with_body sources: sources_response_data
22
+ end
23
+ it 'calls the sources index api' do
24
+ expect(Client.connection).to receive(:get).with('/mobile/api/v1/sources/', anything)
25
+ Source.all
26
+ end
27
+ it 'calls Authorization.token if no token is passed in' do
28
+ expect(Authorization).to receive(:token)
29
+ Source.all
30
+ end
31
+ context 'when the associated organization token has sources' do
32
+ it 'returns an array of sources' do
33
+ expect(Source.all.first.id).to eq source.id
34
+ end
35
+ end
36
+ context 'when the associated organization token has no sources' do
37
+ it 'returns an empty array' do
38
+ allow(Client.connection).to receive(:get).with('/mobile/api/v1/sources/', anything).and_return response_with_body sources: []
39
+ expect(Source.all).to be_empty
40
+ end
41
+ end
42
+ end
43
+
44
+ describe '.find' do
45
+ before do
46
+ allow(Authorization).to receive(:token).and_return token
47
+ allow(Client.connection).to receive(:get).with('/mobile/api/v1/sources/show/', anything).and_return response_with_body source: source_response_data
48
+ end
49
+ it 'calls the sources show api' do
50
+ expect(Client.connection).to receive(:get).with('/mobile/api/v1/sources/show/', anything)
51
+ Source.find id
52
+ end
53
+ it 'calls Authorization.token if no token is passed in' do
54
+ expect(Authorization).to receive(:token)
55
+ Source.find id
56
+ end
57
+ context 'when the source exists' do
58
+ it 'returns a source' do
59
+ expect(Source.find(id).id).to eq source.id
60
+ end
61
+ end
62
+ context 'when no source exists' do
63
+ it 'throws an PatientZero::Error' do
64
+ allow(Client).to receive(:get).and_raise Error, 'The source could not be found. Please check your inputs.'
65
+ expect{ Source.find id }.to raise_error PatientZero::NotFoundError
66
+ end
67
+ end
68
+ end
69
+
70
+ describe '#profile_id' do
71
+ it 'returns the number at the end of the id' do
72
+ expect(source.profile_id).to eq '1234567890'
73
+ end
74
+ end
75
+
76
+ describe '#analytics' do
77
+ it 'calls Analytics.for_platorm to create an analytics object' do
78
+ expect(Analytics).to receive(:for_platform).with(source.platform, { token: source.token, source_id: source.id, start_date: nil, end_date: nil })
79
+ source.analytics
80
+ end
81
+ end
82
+ end
83
+ end
@@ -0,0 +1,14 @@
1
+ require 'bundler/setup'
2
+ Bundler.setup
3
+
4
+ require 'patient_zero'
5
+
6
+ module Helpers
7
+ def response_with_body body
8
+ double :response, body: body.to_json
9
+ end
10
+ end
11
+
12
+ RSpec.configure do |config|
13
+ config.include Helpers
14
+ end
metadata CHANGED
@@ -1,14 +1,15 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: patient_zero
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.1
4
+ version: 0.1.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Adam Zaninovich
8
+ - Devin Clark
8
9
  autorequire:
9
10
  bindir: bin
10
11
  cert_chain: []
11
- date: 2015-03-30 00:00:00.000000000 Z
12
+ date: 2015-04-16 00:00:00.000000000 Z
12
13
  dependencies:
13
14
  - !ruby/object:Gem::Dependency
14
15
  name: bundler
@@ -38,21 +39,109 @@ dependencies:
38
39
  - - "~>"
39
40
  - !ruby/object:Gem::Version
40
41
  version: '10.0'
42
+ - !ruby/object:Gem::Dependency
43
+ name: rspec
44
+ requirement: !ruby/object:Gem::Requirement
45
+ requirements:
46
+ - - ">="
47
+ - !ruby/object:Gem::Version
48
+ version: '0'
49
+ type: :development
50
+ prerelease: false
51
+ version_requirements: !ruby/object:Gem::Requirement
52
+ requirements:
53
+ - - ">="
54
+ - !ruby/object:Gem::Version
55
+ version: '0'
56
+ - !ruby/object:Gem::Dependency
57
+ name: pry
58
+ requirement: !ruby/object:Gem::Requirement
59
+ requirements:
60
+ - - ">="
61
+ - !ruby/object:Gem::Version
62
+ version: '0'
63
+ type: :development
64
+ prerelease: false
65
+ version_requirements: !ruby/object:Gem::Requirement
66
+ requirements:
67
+ - - ">="
68
+ - !ruby/object:Gem::Version
69
+ version: '0'
70
+ - !ruby/object:Gem::Dependency
71
+ name: faraday
72
+ requirement: !ruby/object:Gem::Requirement
73
+ requirements:
74
+ - - ">="
75
+ - !ruby/object:Gem::Version
76
+ version: '0'
77
+ type: :runtime
78
+ prerelease: false
79
+ version_requirements: !ruby/object:Gem::Requirement
80
+ requirements:
81
+ - - ">="
82
+ - !ruby/object:Gem::Version
83
+ version: '0'
84
+ - !ruby/object:Gem::Dependency
85
+ name: json
86
+ requirement: !ruby/object:Gem::Requirement
87
+ requirements:
88
+ - - ">="
89
+ - !ruby/object:Gem::Version
90
+ version: '0'
91
+ type: :runtime
92
+ prerelease: false
93
+ version_requirements: !ruby/object:Gem::Requirement
94
+ requirements:
95
+ - - ">="
96
+ - !ruby/object:Gem::Version
97
+ version: '0'
41
98
  description: A gem to use the Viral Heat API
42
99
  email:
43
100
  - adam.zaninovich@gmail.com
101
+ - notdevinclark@gmail.com
44
102
  executables: []
45
103
  extensions: []
46
104
  extra_rdoc_files: []
47
105
  files:
48
106
  - ".gitignore"
107
+ - ".rspec"
49
108
  - Gemfile
50
109
  - LICENSE.txt
51
110
  - README.md
52
111
  - Rakefile
53
112
  - lib/patient_zero.rb
113
+ - lib/patient_zero/analytics.rb
114
+ - lib/patient_zero/analytics/base.rb
115
+ - lib/patient_zero/analytics/facebook.rb
116
+ - lib/patient_zero/analytics/instagram.rb
117
+ - lib/patient_zero/analytics/twitter.rb
118
+ - lib/patient_zero/authorization.rb
119
+ - lib/patient_zero/client.rb
120
+ - lib/patient_zero/configurable.rb
121
+ - lib/patient_zero/errors.rb
122
+ - lib/patient_zero/message.rb
123
+ - lib/patient_zero/message/base.rb
124
+ - lib/patient_zero/message/facebook.rb
125
+ - lib/patient_zero/message/instagram.rb
126
+ - lib/patient_zero/message/twitter.rb
127
+ - lib/patient_zero/organization.rb
128
+ - lib/patient_zero/source.rb
54
129
  - lib/patient_zero/version.rb
55
130
  - patient_zero.gemspec
131
+ - spec/patient_zero/analytics/base_spec.rb
132
+ - spec/patient_zero/analytics/facebook_spec.rb
133
+ - spec/patient_zero/analytics/instagram_spec.rb
134
+ - spec/patient_zero/analytics/twitter_spec.rb
135
+ - spec/patient_zero/analytics_spec.rb
136
+ - spec/patient_zero/authorization_spec.rb
137
+ - spec/patient_zero/client_spec.rb
138
+ - spec/patient_zero/message/facebook_spec.rb
139
+ - spec/patient_zero/message/instagram_spec.rb
140
+ - spec/patient_zero/message/twitter_spec.rb
141
+ - spec/patient_zero/message_spec.rb
142
+ - spec/patient_zero/organization_spec.rb
143
+ - spec/patient_zero/source_spec.rb
144
+ - spec/spec_helper.rb
56
145
  homepage: ''
57
146
  licenses:
58
147
  - MIT
@@ -77,4 +166,18 @@ rubygems_version: 2.4.5
77
166
  signing_key:
78
167
  specification_version: 4
79
168
  summary: A gem to use the Viral Heat API
80
- test_files: []
169
+ test_files:
170
+ - spec/patient_zero/analytics/base_spec.rb
171
+ - spec/patient_zero/analytics/facebook_spec.rb
172
+ - spec/patient_zero/analytics/instagram_spec.rb
173
+ - spec/patient_zero/analytics/twitter_spec.rb
174
+ - spec/patient_zero/analytics_spec.rb
175
+ - spec/patient_zero/authorization_spec.rb
176
+ - spec/patient_zero/client_spec.rb
177
+ - spec/patient_zero/message/facebook_spec.rb
178
+ - spec/patient_zero/message/instagram_spec.rb
179
+ - spec/patient_zero/message/twitter_spec.rb
180
+ - spec/patient_zero/message_spec.rb
181
+ - spec/patient_zero/organization_spec.rb
182
+ - spec/patient_zero/source_spec.rb
183
+ - spec/spec_helper.rb