smartstories 7.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.
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: d26602f7f9ce9279bf889b4447b3064d9be0da85
4
+ data.tar.gz: 78731afc631ac2f8549fc4e27fd587f068f5123c
5
+ SHA512:
6
+ metadata.gz: 1cc5b66f78a4999b748565ef4de1dfed9cb09d85b338272348a35404ede0d5f62d103cf29eff5e1d15bc189600e70d2904a84d65f9f6f5e79d9a4dc065d3eeb4
7
+ data.tar.gz: 3da483c63636c775ce6cece6996dd2ce98cea427a7c10ca404d9a9fcac5e50a4a0e9108c9ecce3e1bb6d7442695863d28bd05fd1606b8789e277b92d54ded472
@@ -0,0 +1,16 @@
1
+ require "httparty"
2
+ require "json"
3
+ require "logger"
4
+
5
+ require_relative "smartstories/errors"
6
+ require_relative "smartstories/config"
7
+ require_relative "smartstories/request"
8
+ require_relative "smartstories/client"
9
+
10
+ module Smartstories
11
+ class << self
12
+ def client
13
+ @client ||= Client.new
14
+ end
15
+ end
16
+ end
@@ -0,0 +1,15 @@
1
+ require 'smartstories/api/article'
2
+ require 'smartstories/api/breaking'
3
+ require 'smartstories/api/conversation'
4
+ require 'smartstories/api/influencer'
5
+ require 'smartstories/api/geo'
6
+ require 'smartstories/api/media'
7
+ require 'smartstories/api/people'
8
+ require 'smartstories/api/picture'
9
+ require 'smartstories/api/recent'
10
+ require 'smartstories/api/sentiment'
11
+ require 'smartstories/api/trending'
12
+ require 'smartstories/api/volume'
13
+
14
+ require 'smartstories/node'
15
+ require 'smartstories/monitor_subscription'
@@ -0,0 +1,15 @@
1
+ # http://api-staging.timelinelabs.net:8888/static/docs/rest.html#articles-resource
2
+ require 'smartstories/api/util'
3
+
4
+ module Smartstories
5
+ module Api
6
+ module Article
7
+ extend Api::Util
8
+
9
+ def self.news(topic_ids, opts)
10
+ opts[:count] ||= 50
11
+ http.get("/api/v1/articles", common_parameters(topic_ids, opts))
12
+ end
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,19 @@
1
+ # For v1 reference:
2
+ # http://api.timelinelabs.net:8888/static/docs/rest.html#tracker-resource
3
+ require 'smartstories/api/util'
4
+
5
+ module Smartstories
6
+ module Api
7
+ module Breaking
8
+ extend Api::Util
9
+
10
+ def self.for_topics(topic_ids, filter: nil, **common_options)
11
+ query = common_parameters(topic_ids, common_options)
12
+ query[:filter] = filter if filter
13
+ query[:breaking] = true
14
+
15
+ http.get("/api/v1/tracker", query)
16
+ end
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,15 @@
1
+ # http://api-staging.timelinelabs.net:8888/static/docs/rest.html#conversation-resource
2
+ require 'smartstories/api/util'
3
+
4
+ module Smartstories
5
+ module Api
6
+ module Conversation
7
+ extend Api::Util
8
+
9
+ def self.conversations(topic_ids, opts)
10
+ opts[:count] ||= 25
11
+ http.get("/api/v1/conversations", common_parameters(topic_ids, opts))
12
+ end
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,27 @@
1
+ # http://api-staging.timelinelabs.net:8888/static/docs/rest.html#geo-resource
2
+
3
+ module Smartstories
4
+ module Api
5
+ module Geo
6
+ extend Api::Util
7
+
8
+ def self.for_topics(topic_ids, start_time: start_time, end_time: end_time, **common_options)
9
+ query = common_parameters(topic_ids, common_options)
10
+ query[:starttime] = start_time
11
+ query[:endtime] = end_time
12
+
13
+ http.get("/api/v1/geo", query)
14
+ end
15
+
16
+ private
17
+
18
+ def self.start_time
19
+ Time.now.utc.to_i
20
+ end
21
+
22
+ def self.end_time
23
+ (Time.now - 86400).utc.to_i
24
+ end
25
+ end
26
+ end
27
+ end
@@ -0,0 +1,15 @@
1
+ # http://api-staging.timelinelabs.net:8888/static/docs/rest.html#influencers-resource
2
+ require 'smartstories/api/util'
3
+
4
+ module Smartstories
5
+ module Api
6
+ module Influencer
7
+ extend Api::Util
8
+
9
+ def self.influencers(topic_ids, opts)
10
+ opts[:count] ||= 75
11
+ http.get("/api/v1/influencers", common_parameters(topic_ids, opts))
12
+ end
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,15 @@
1
+ # http://api-staging.timelinelabs.net:8888/static/docs/rest.html#media-resource
2
+ require 'smartstories/api/util'
3
+
4
+ module Smartstories
5
+ module Api
6
+ module Media
7
+ extend Api::Util
8
+
9
+ def self.videos(topic_ids, opts)
10
+ opts[:count] ||= 50
11
+ http.get("/api/v1/media", common_parameters(topic_ids, opts))
12
+ end
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,14 @@
1
+ # http://api-staging.timelinelabs.net:8888/static/docs/rest.html#people-resource
2
+ require 'smartstories/api/util'
3
+
4
+ module Smartstories
5
+ module Api
6
+ module People
7
+ extend Api::Util
8
+
9
+ def self.for_topics(topic_ids, opts)
10
+ http.get("/api/v1/people", common_parameters(topic_ids, opts))
11
+ end
12
+ end
13
+ end
14
+ end
@@ -0,0 +1,14 @@
1
+ # http://api-staging.timelinelabs.net:8888/static/docs/rest.html#pictures-resource
2
+
3
+ module Smartstories
4
+ module Api
5
+ module Picture
6
+ extend Api::Util
7
+
8
+ def self.photos(topic_ids, opts)
9
+ opts[:count] = 50
10
+ http.get("/api/v1/pics", common_parameters(topic_ids, opts))
11
+ end
12
+ end
13
+ end
14
+ end
@@ -0,0 +1,13 @@
1
+ # http://api-staging.timelinelabs.net:8888/static/docs/rest.html#recent-resource
2
+
3
+ module Smartstories
4
+ module Api
5
+ module Recent
6
+ extend Api::Util
7
+
8
+ def self.for_topics(topic_ids, **extraneous)
9
+ http.get("/api/v1/recent", :topics => topic_ids.join(','))
10
+ end
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,26 @@
1
+ # http://api-staging.timelinelabs.net:8888/static/docs/rest.html#sentiment-resource
2
+
3
+ module Smartstories
4
+ module Api
5
+ module Sentiment
6
+ extend Api::Util
7
+
8
+ def self.sentiment(topic_ids, opts)
9
+ opts[:type] = 'volume'
10
+ raw_sentiment(topic_ids, opts)
11
+ end
12
+
13
+ def self.sentiment_ts(topic_ids, opts)
14
+ opts[:type] = 'ts'
15
+ raw_sentiment(topic_ids, opts)
16
+ end
17
+
18
+ def self.raw_sentiment(topic_ids, opts)
19
+ query = common_parameters(topic_ids, opts)
20
+ query[:type] = opts[:type]
21
+ query.delete(:count)
22
+ http.get("/api/v1/sentiment", query)
23
+ end
24
+ end
25
+ end
26
+ end
@@ -0,0 +1,19 @@
1
+ # http://api.timelinelabs.net:8888/static/docs/rest.html#tracker-resource
2
+ require 'smartstories/api/util'
3
+
4
+ module Smartstories
5
+ module Api
6
+ module Trending
7
+ extend Api::Util
8
+
9
+ def self.for_topics(topic_ids, filter: nil, count: 100, **common_options)
10
+ query = common_parameters(topic_ids, common_options)
11
+ query[:count] = count
12
+ query[:breaking] = false
13
+ query[:filter] = filter if filter
14
+
15
+ http.get("/api/v1/tracker", query)
16
+ end
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,19 @@
1
+ module Smartstories
2
+ module Api
3
+ module Util
4
+ def common_parameters(topic_ids, count: 10, interval: 3600, starttime: nil, endtime: nil, **extraneous)
5
+ query = {}
6
+ query[:topics] = topic_ids.join(',') if topic_ids
7
+ query[:starttime] = starttime if starttime
8
+ query[:endtime] = endtime if endtime
9
+ query[:interval] = interval if interval
10
+ query[:count] = count if count
11
+ query
12
+ end
13
+
14
+ def http
15
+ Smartstories::Request.new
16
+ end
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,34 @@
1
+ # http://api-staging.timelinelabs.net:8888/static/docs/rest.html#volume-resource
2
+
3
+ module Smartstories
4
+ module Api
5
+ module Volume
6
+ extend Api::Util
7
+
8
+ def self.messages_timeline(topic_ids, opts)
9
+ raw_volume(topic_ids, opts)
10
+ end
11
+
12
+ def self.volume_ts(topic_ids, opts)
13
+ raw_volume(topic_ids, opts)
14
+ end
15
+
16
+ def self.volume_unique(topic_ids, opts)
17
+ opts[:type] = 'thread'
18
+ raw_volume(topic_ids, opts)
19
+ end
20
+
21
+ def self.volume(topic_ids, opts)
22
+ opts[:type] = 'volume'
23
+ raw_volume(topic_ids, opts)
24
+ end
25
+
26
+ def self.raw_volume(topic_ids, opts)
27
+ query = common_parameters(topic_ids, opts)
28
+ query[:type] = opts[:type] if opts[:type]
29
+ query.delete(:count)
30
+ http.get("/api/v1/volume", query)
31
+ end
32
+ end
33
+ end
34
+ end
@@ -0,0 +1,76 @@
1
+ require 'smartstories/api'
2
+
3
+ module Smartstories
4
+ class Client
5
+ def initialize(topic_ids = [])
6
+ @topic_ids = topic_ids
7
+ end
8
+
9
+ def recent(opts = {})
10
+ Api::Recent.for_topics(@topic_ids, opts)
11
+ end
12
+
13
+ def breaking(opts = {})
14
+ Api::Breaking.for_topics(@topic_ids, opts)
15
+ end
16
+
17
+ def trending(opts = {})
18
+ Api::Trending.for_topics(@topic_ids, opts)
19
+ end
20
+
21
+ def geo(opts = {})
22
+ Api::Geo.for_topics(@topic_ids, opts)
23
+ end
24
+
25
+ def people(opts = {})
26
+ Api::People.for_topics(@topic_ids, opts)
27
+ end
28
+ #################################################
29
+
30
+ ###TOTALLY OLD SHIT, MAYBE WILL DIE##############
31
+ ###MAYBE IN SUPPORT OF PANELS####################
32
+ def photos(opts = {})
33
+ Api::Picture.photos(@topic_ids, opts)
34
+ end
35
+
36
+ def videos(opts = {})
37
+ Api::Media.videos(@topic_ids, opts)
38
+ end
39
+
40
+ def influencers(opts = {})
41
+ Api::Influencer.influencers(@topic_ids, opts)
42
+ end
43
+
44
+ def conversations(opts = {})
45
+ Api::Conversation.conversations(@topic_ids, opts)
46
+ end
47
+
48
+ def news(opts = {})
49
+ Api::Article.news(@topic_ids, opts)
50
+ end
51
+
52
+ def messages_timeline(opts = {})
53
+ Api::Volume.messages_timeline(@topic_ids, opts)
54
+ end
55
+
56
+ def volume(opts = {})
57
+ Api::Volume.volume(@topic_ids, opts)
58
+ end
59
+
60
+ def volume_ts(opts = {})
61
+ Api::Volume.volume_ts(@topic_ids, opts)
62
+ end
63
+
64
+ def volume_unique(opts = {})
65
+ Api::Volume.volume_unique(@topic_ids, opts)
66
+ end
67
+
68
+ def sentiment(opts = {})
69
+ Api::Sentiment.sentiment(@topic_ids, opts)
70
+ end
71
+
72
+ def sentiment_ts(opts = {})
73
+ Api::Sentiment.sentiment_ts(@topic_ids, opts)
74
+ end
75
+ end
76
+ end
@@ -0,0 +1,21 @@
1
+ module Smartstories
2
+ class Config
3
+ class << self
4
+ attr_reader :host
5
+ attr_writer :api_key, :logger
6
+
7
+ def host=(new_host)
8
+ @host = new_host
9
+ Request.base_uri(@host)
10
+ end
11
+
12
+ def logger
13
+ @logger || Logger.new('/dev/null')
14
+ end
15
+
16
+ def api_key
17
+ @api_key || raise(MissingApiKey, "Missing SmartStories API key.")
18
+ end
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,13 @@
1
+ module Smartstories
2
+ # generic error
3
+ class Error < StandardError; end
4
+
5
+ class MissingApiKey < Smartstories::Error; end
6
+ class MissingParam < Smartstories::Error; end
7
+
8
+ class ParserError < Smartstories::Error; end
9
+ class MissingError < Smartstories::Error; end
10
+ class TimeoutError < Smartstories::Error; end
11
+ class SocketError < Smartstories::Error; end
12
+ class ServerError < Smartstories::Error; end
13
+ end
@@ -0,0 +1,37 @@
1
+ # http://api-staging.timelinelabs.net:8888/static/docs/rest.html#monitor-subscriptions
2
+
3
+ module Smartstories
4
+ class MonitorSubscription
5
+ DEFAULT_EXPIRE_DURATION = 1800 # seconds
6
+
7
+ def initialize(http=Request.new)
8
+ @http = http
9
+ end
10
+
11
+ def self.update_environment!(environment_subscription_info)
12
+ client = self.new
13
+ client.update(environment_subscription_info)
14
+ end
15
+
16
+ def add(monitor_subscription_info)
17
+ attrs = format_payload(monitor_subscription_info)
18
+ @http.post("/api/v1/monitor/subscriptions/#{monitor_subscription_info.environment}", attrs.to_json)
19
+ end
20
+
21
+ def update(monitor_subscription_info)
22
+ attrs = format_payload(monitor_subscription_info)
23
+ @http.put("/api/v1/monitor/subscriptions/#{monitor_subscription_info.environment}", attrs.to_json)
24
+ end
25
+
26
+ private
27
+
28
+ def format_payload(param)
29
+ {
30
+ environment: param.environment,
31
+ nodes: param.nodes,
32
+ pusher_prefix: param.pusher_prefix,
33
+ expire: param.expire
34
+ }
35
+ end
36
+ end
37
+ end
@@ -0,0 +1,47 @@
1
+ # http://api-staging.timelinelabs.net:8888/static/docs/rest.html#nodes
2
+
3
+ module Smartstories
4
+ # Maybe the following methods should be at the class level, and they
5
+ # wrap the API results by calling Node.new(node_json)
6
+ # Node.add => wrap newly created node and return Node object
7
+ # Node.update => wrap updated node and return Node object
8
+ # Node.all => wrap each element of returned array, return array
9
+ # Node.find => wrap found node and return Node object
10
+ #
11
+ # Downside is that node_info would need to be a private class method and that
12
+ # we couldn't call Request.new on instantiation, meaning we would have to stub
13
+ # Request out in our tests.
14
+ #
15
+ # Maybe delegate :get, :post, to: Request.new ?
16
+ #
17
+ # node_info could be replaced by a NodeInfo or NodeFormatter object?
18
+ class Node
19
+ def initialize(http = Request.new)
20
+ @http = http
21
+ end
22
+
23
+ def add(node)
24
+ attrs = format_node(node)
25
+ @http.post("/api/v1/nodes/#{node.uuid}", attrs.to_json)
26
+ end
27
+
28
+ def update(node)
29
+ attrs = format_node(node)
30
+ @http.put("/api/v1/nodes/#{node.uuid}", attrs.to_json)
31
+ end
32
+
33
+ def delete(node_uuid)
34
+ @http.delete("/api/v1/nodes/#{node_uuid}")
35
+ end
36
+
37
+ private
38
+ def format_node(node)
39
+ {
40
+ id: node.id.to_s,
41
+ uuid: node.uuid,
42
+ description: node.name,
43
+ topics: node.topics
44
+ }
45
+ end
46
+ end
47
+ end
@@ -0,0 +1,24 @@
1
+ Old endpoints:
2
+
3
+ Completed:
4
+ trackers: {
5
+ endpoint: '/api/tracker',
6
+ count: 100
7
+ },
8
+
9
+ photos: { endpoint: '/api/pics', count: 50 },
10
+ videos: { endpoint: '/api/media', count: 50 }, #DONE
11
+ influencers: { endpoint: '/api/influencers', count: 75 }, #DONE
12
+ conversations: { endpoint: '/api/conversations', count: 25 }, #DONE
13
+ news: { endpoint: '/api/articles', count: 50 }, #DONE
14
+ recent: { endpoint: '/api/recent' } #DONE
15
+ messages_timeline: { endpoint: '/api/volume', count: nil },
16
+ volume: { endpoint: '/api/volume', count: nil, type: 'volume' },
17
+ volume_ts: { endpoint: '/api/volume', count: nil },
18
+ volume_unique: { endpoint: '/api/volume', count: nil, type: 'thread' },
19
+ sentiment: { endpoint: '/api/sentiment', count: nil, type: 'volume' },
20
+ sentiment_ts: { endpoint: '/api/sentiment', count: nil, type: 'ts' },
21
+
22
+ Dead:
23
+ country_map: { endpoint: '/api/country_map', count: nil },
24
+ bar_graph: { endpoint: '/api/bar_graph', count: nil },
@@ -0,0 +1,55 @@
1
+ module Smartstories
2
+ class Request
3
+ include HTTParty
4
+ default_timeout 90
5
+
6
+ def get(endpoint, query = {})
7
+ request(:get, endpoint, query)
8
+ end
9
+
10
+ def post(endpoint, query = {})
11
+ request(:post, endpoint, query)
12
+ end
13
+
14
+ def put(endpoint, query = {})
15
+ request(:put, endpoint, query)
16
+ end
17
+
18
+ def delete(endpoint)
19
+ request(:delete, endpoint)
20
+ end
21
+
22
+ private
23
+ def request(method, endpoint, query = nil)
24
+ auth = { username: Config.api_key, password: '' }
25
+ options = { basic_auth: auth }
26
+ if [:post, :put].include? method
27
+ options[:body] = query
28
+ options[:content_type] = 'application/json'
29
+ else
30
+ options[:query] = query
31
+ end
32
+
33
+ response = self.class.send(method, endpoint, options)
34
+
35
+ case response.code.to_s
36
+ when "200"
37
+ JSON.parse(response.body)
38
+ when "204"
39
+ true
40
+ when "404"
41
+ raise Smartstories::MissingError, "Missing resource: #{response.request.last_uri.to_s}", self.inspect
42
+ when /^5\d\d$/
43
+ raise Smartstories::ServerError, "#{response.code} Series error", self.inspect
44
+ else
45
+ raise Smartstories::Error, "Error: #{response.request.last_uri.to_s}\n\n#{response.code}", self.inspect
46
+ end
47
+ rescue JSON::ParserError
48
+ raise Smartstories::ParserError
49
+ rescue Errno::ETIMEDOUT
50
+ raise Smartstories::TimeoutError
51
+ rescue ::SocketError
52
+ raise Smartstories::SocketError
53
+ end
54
+ end
55
+ end
metadata ADDED
@@ -0,0 +1,106 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: smartstories
3
+ version: !ruby/object:Gem::Version
4
+ version: '7.0'
5
+ platform: ruby
6
+ authors:
7
+ - Timeline Labs
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2015-02-11 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: httparty
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ~>
18
+ - !ruby/object:Gem::Version
19
+ version: 0.12.0
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ~>
25
+ - !ruby/object:Gem::Version
26
+ version: 0.12.0
27
+ - !ruby/object:Gem::Dependency
28
+ name: rspec
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ~>
32
+ - !ruby/object:Gem::Version
33
+ version: '2.14'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - ~>
39
+ - !ruby/object:Gem::Version
40
+ version: '2.14'
41
+ - !ruby/object:Gem::Dependency
42
+ name: webmock
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - ~>
46
+ - !ruby/object:Gem::Version
47
+ version: '1.17'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - ~>
53
+ - !ruby/object:Gem::Version
54
+ version: '1.17'
55
+ description:
56
+ email:
57
+ executables: []
58
+ extensions: []
59
+ extra_rdoc_files: []
60
+ files:
61
+ - lib/smartstories/api/article.rb
62
+ - lib/smartstories/api/breaking.rb
63
+ - lib/smartstories/api/conversation.rb
64
+ - lib/smartstories/api/geo.rb
65
+ - lib/smartstories/api/influencer.rb
66
+ - lib/smartstories/api/media.rb
67
+ - lib/smartstories/api/people.rb
68
+ - lib/smartstories/api/picture.rb
69
+ - lib/smartstories/api/recent.rb
70
+ - lib/smartstories/api/sentiment.rb
71
+ - lib/smartstories/api/trending.rb
72
+ - lib/smartstories/api/util.rb
73
+ - lib/smartstories/api/volume.rb
74
+ - lib/smartstories/api.rb
75
+ - lib/smartstories/client.rb
76
+ - lib/smartstories/config.rb
77
+ - lib/smartstories/errors.rb
78
+ - lib/smartstories/monitor_subscription.rb
79
+ - lib/smartstories/node.rb
80
+ - lib/smartstories/notes
81
+ - lib/smartstories/request.rb
82
+ - lib/smartstories.rb
83
+ homepage:
84
+ licenses: []
85
+ metadata: {}
86
+ post_install_message:
87
+ rdoc_options: []
88
+ require_paths:
89
+ - lib
90
+ required_ruby_version: !ruby/object:Gem::Requirement
91
+ requirements:
92
+ - - '>='
93
+ - !ruby/object:Gem::Version
94
+ version: '0'
95
+ required_rubygems_version: !ruby/object:Gem::Requirement
96
+ requirements:
97
+ - - '>='
98
+ - !ruby/object:Gem::Version
99
+ version: '0'
100
+ requirements: []
101
+ rubyforge_project:
102
+ rubygems_version: 2.0.14
103
+ signing_key:
104
+ specification_version: 4
105
+ summary: TLL Smartstories Client API Wrapper
106
+ test_files: []