livefyre 0.1.2 → 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,220 +0,0 @@
1
- module Livefyre
2
- # Public: Proxy for a Livefyre domain resource
3
- class Domain
4
- attr_accessor :client
5
-
6
- def initialize(client = nil)
7
- @client = client || Livefyre.client
8
- end
9
-
10
- # Public: Get a list of sites for this domain
11
- #
12
- # Returns [Array<Site>] An array of {Site sites}
13
- # Raises [APIException] when response is not valid
14
- def sites
15
- response = client.get "/sites/?actor_token=#{CGI.escape client.system_token}"
16
- if response.success?
17
- JSON.parse(response.body).map do |site|
18
- Site.new(site["id"], client, site)
19
- end
20
- else
21
- raise APIException.new(response.body)
22
- end
23
- end
24
-
25
- # Public: Search conversations on this domain
26
- #
27
- # query - string to query for
28
- # options - [Hash] of options
29
- # :fields - list of fields to search. Default [:article, :title, :body]
30
- # :sort - Sort order for options. Valid values are [:relevance, :created, :updated, :hotness, :ncomments]. Default is :relevance
31
- # :fields - List of fields to return in the result. Valid values are: article_id, site_id, domain_id, title, published, updated, author, url, ncomment, nuser, annotation, nlp, hotness, hottest_value, hottest_time, peak, peak_value, peak_time, comments:5, users:5, comment_state, hit_field, dispurl, relevancy
32
- # :max - Maximum number of fields to return
33
- # :since - [DateTime] Minimum date of results to return
34
- # :until - [DateTime] Maximum date of results to return
35
- # :sites - Array of Sites or site IDs to limit results to. Maximum 5 sites.
36
- # :page - Page of results to fetch. Default 1.
37
- #
38
- # Returns [Array<Conversation>] An array of matching conversations
39
- # Raises [APIException] when response is not valid
40
- def search_conversations(query, options = {})
41
- query = {}
42
- query[:return_fields] = options[:fields] if options[:fields]
43
- query[:fields] = options[:fields] || [:article, :title, :body]
44
- query[:order] = options[:sort] || "relevance"
45
- query[:max] = options[:max].to_i if options[:max]
46
- query[:since] = options[:since].utc.iso8601 if options[:since]
47
- query[:until] = options[:until].utc.iso8601 if options[:until]
48
- query[:sites] = options[:sites].map {|s| s.is_a?(Site) ? s.id : s.to_i }
49
- query[:cursor] = (query[:max] || 10).to_i * options[:page].to_i if options[:page]
50
- query[:apitoken] = client.system_token ## TODO: I expect this is wrong; this param seems to expect the old-style API token.
51
- response = client.search.get "/api/v1.1/public/search/convs/", query
52
- if response.success?
53
- JSON.parse(response.body)
54
- else
55
- raise APIException.new(response.body)
56
- end
57
- end
58
-
59
- # Public: Get a list of users on this domain
60
- #
61
- # Returns [Array<User>] An array of {User users}
62
- # Raises [APIException] when response is not valid
63
- def users
64
- response = client.get "/profiles/?actor_token=#{CGI.escape client.system_token}"
65
- if response.success?
66
- JSON.parse(response.body).map do |site|
67
- User.new(site["id"], client, site["display_name"])
68
- end
69
- else
70
- raise APIException.new(response.body)
71
- end
72
- end
73
-
74
- # Public: Push a user profile to this domain
75
- #
76
- # profile - [Hash] Hash of user data to publish per the Livefyre profile schema
77
- #
78
- # Returns [Bool] true on success
79
- # Raises [APIException] when response is not valid
80
- def add_user(profile)
81
- raise "Invalid ID" if profile["id"].nil?
82
- response = client.post "/profiles/?actor_token=#{CGI.escape client.system_token}&id=#{CGI.escape profile["id"]}", profile
83
- if response.success?
84
- true
85
- else
86
- raise APIException.new(response.body)
87
- end
88
- end
89
-
90
- # Public: Create a new site on this domain
91
- #
92
- # Returns [Site] A new {Site site}.
93
- # Raises [APIException] when response is not valid
94
- def create_site(url)
95
- response = client.post "/sites/?actor_token=#{CGI.escape client.system_token}&url=#{CGI.escape url}"
96
- if response.success?
97
- opts = JSON.parse response.body
98
- Site.new(opts["id"], client, opts)
99
- else
100
- raise APIException.new(response.body)
101
- end
102
- end
103
-
104
- # Public: Retrieve a list of owners associated with this domain
105
- #
106
- # Returns [Array<User>] An array of {User users}
107
- # Raises [APIException] when response is not valid
108
- def owners
109
- response = client.get "/owners/", {:actor_token => client.system_token}
110
- if response.success?
111
- JSON.parse(response.body).map do |u|
112
- client.user u.split("@", 2).first
113
- end
114
- else
115
- raise APIException.new(response.body)
116
- end
117
- end
118
-
119
- # Public: Adds a user to the list of owners for this domain
120
- #
121
- # user - [String, User, Integer] User or user ID to add as an owner
122
- #
123
- # Returns [Bool] true on success
124
- # Raises [APIException] when response is not valid
125
- def add_owner(user)
126
- user = User.get_user(user, client)
127
- response = client.post "/owners/?actor_token=#{CGI.escape client.system_token}", {:jid => user.jid}
128
- if response.success?
129
- true
130
- else
131
- raise APIException.new(response.body)
132
- end
133
- end
134
-
135
- # Public: Removes a user from the list of owners for this domain
136
- #
137
- # user - [String, User, Integer] User or user ID to remove as an owner
138
- #
139
- # Returns [Bool] true on success
140
- # Raises [APIException] when response is not valid
141
- def remove_owner(user)
142
- user = User.get_user(user, client)
143
- response = client.delete "/owner/#{user.jid}/?actor_token=#{CGI.escape client.system_token}"
144
- if response.success?
145
- true
146
- else
147
- raise APIException.new(response.body)
148
- end
149
- end
150
-
151
- # Public: Retrieve a list of owners associated with this domain
152
- #
153
- # Returns [Array<User>] An array of {User users}
154
- # Raises [APIException] when response is not valid
155
- def admins
156
- response = client.get "/admins/", {:actor_token => client.system_token}
157
- if response.success?
158
- JSON.parse(response.body).map do |u|
159
- client.user u.split("@", 2).first
160
- end
161
- else
162
- raise APIException.new(response.body)
163
- end
164
- end
165
-
166
- # Public: Adds a user to the list of owners for this domain
167
- #
168
- # user - [String, User, Integer] User or user ID to add as an admin
169
- #
170
- # Returns [Bool] true on success
171
- # Raises [APIException] when response is not valid
172
- def add_admin(user)
173
- user = User.get_user(user, client)
174
- response = client.post "/admins/?actor_token=#{CGI.escape user.token}", {:jid => user.jid}
175
- if response.success?
176
- true
177
- else
178
- raise APIException.new(response.body)
179
- end
180
- end
181
-
182
- # Public: Removes a user from the list of owners for this domain
183
- #
184
- # user - [String, User, Integer] User or user ID to remove as an admin
185
- #
186
- # Returns [Bool] true on success
187
- # Raises [APIException] when response is not valid
188
- def remove_admin(user)
189
- user = User.get_user(user, client)
190
- response = client.delete "/admin/#{user.jid}/?actor_token=#{CGI.escape client.system_token}"
191
- if response.success?
192
- true
193
- else
194
- raise APIException.new(response.body)
195
- end
196
- end
197
-
198
- # Public: Sets the profile pull URL for the entire network.
199
- #
200
- # url - A URL template that includes the string "{{id}}" in it somewhere
201
- #
202
- # Returns [Bool] true on success
203
- # Raises APIException if the request failed
204
- def set_pull_url(url)
205
- result = client.post "/", {:pull_profile_url => url, :actor_token => client.system_token}
206
- if result.success?
207
- return true
208
- else
209
- raise APIException.new(result.body)
210
- end
211
- end
212
-
213
- # Internal: Returns a cleaner string representation of this object
214
- #
215
- # Returns [String] representation of this class
216
- def to_s
217
- "#<#{self.class.name}:0x#{object_id.to_s(16).rjust(14, "0")} host='#{client.host}'>"
218
- end
219
- end
220
- end
@@ -1,6 +0,0 @@
1
- module Livefyre
2
- module Rails
3
- class Engine < ::Rails::Engine
4
- end
5
- end
6
- end
@@ -1,57 +0,0 @@
1
- module Livefyre
2
- # Public: View helpers for Livefyre
3
- module Helpers
4
-
5
- # Public: Add a Livefyre comment form to this page.
6
- #
7
- # id - [String, Integer] identifier to use for this conversation. Likely a post ID.
8
- # title - [String] Title of this post or conversation
9
- # link - [String] Link to this post or conversation
10
- # tags - [Array, String] Optional array or comma-delimited list of tags on this conversation.
11
- # options - [Hash] Additional options to pass to the created div tag.
12
- #
13
- # Returns [String] div element for insertion into your view
14
- def livefyre_comments(id, title, link, tags = nil, options = {})
15
- meta = livefyre_conversation_metadata(id, title, link, tags)
16
- options.merge!(
17
- :id => "livefyre_comments",
18
- :data => {
19
- :checksum => meta[:checksum],
20
- :"collection-meta" => meta[:collectionMeta],
21
- :"site-id" => meta[:siteId],
22
- :"article-id" => meta[:articleId],
23
- :network => Livefyre.client.host,
24
- :root => Livefyre.config[:domain],
25
- :"post-to-buttons" => Livefyre.config[:postToButtons]
26
- }
27
- )
28
- content_tag(:div, "", options)
29
- end
30
-
31
- private
32
-
33
- # Internal: Generate a metadata hash from the given attributes.
34
- #
35
- # Returns [Hash]
36
- def livefyre_conversation_metadata(id, title, link, tags)
37
- tags = tags.join(",") if tags.is_a? Array
38
-
39
- metadata = {
40
- :title => title,
41
- :url => link,
42
- :tags => tags
43
- }
44
- metadata[:checksum] = Digest::MD5.hexdigest(metadata.to_json)
45
- metadata[:articleId] = id
46
- post_meta = JWT.encode(metadata, Livefyre.config[:site_key])
47
-
48
- {
49
- :el => "livefyre_comments",
50
- :checksum => metadata[:checksum],
51
- :collectionMeta => post_meta,
52
- :siteId => Livefyre.config[:site_id],
53
- :articleId => id.to_s
54
- }
55
- end
56
- end
57
- end
@@ -1,64 +0,0 @@
1
- module Livefyre
2
- module Model
3
- extend ActiveSupport::Concern
4
-
5
- # Public: Ping Livefyre to refresh this user's record
6
- def refresh_livefyre
7
- if _livefyre_callback
8
- _livefyre_callback.call( self, self.send(:_livefyre_id) )
9
- else
10
- Livefyre::User.refresh( self.send(:_livefyre_id) )
11
- end
12
- end
13
-
14
- protected
15
-
16
- def update_livefyre_if_fields_changed
17
- if updates = _livefyre_options[:update_on]
18
- updates.each do |field|
19
- if send("#{field}_changed?")
20
- refresh_livefyre
21
- break
22
- end
23
- end
24
- end
25
- end
26
-
27
- def _livefyre_options
28
- self.class.instance_variable_get("@livefyre_options")
29
- end
30
-
31
- def _livefyre_callback
32
- self.class.instance_variable_get("@livefyre_update_block")
33
- end
34
-
35
- def _livefyre_id
36
- livefyre_id = self.id
37
- if _livefyre_options[:id]
38
- livefyre_id = self.send(_livefyre_options[:id])
39
- end
40
- livefyre_id
41
- end
42
-
43
- public
44
-
45
- module ClassMethods
46
- # Public: Adds callback handlers and additional methods for treating this record as a user record.
47
- #
48
- # options - [Hash] of options to initialize behavior with
49
- # :update_on - [Array<Symbol>] List of fields which should trigger a Livefyre update when they're updated.
50
- # :id - [Symbol] Name of the method to use for determining this record's livefyre ID. If not given, #id is used.
51
- #
52
- # Examples
53
- #
54
- # livefyre_user :update_on => [:email, :first_name, :last_name, :username, :picture_url], :id => :custom_livefyre_id
55
- #
56
- # Returns [nil]
57
- def livefyre_user(options = {}, &block)
58
- @livefyre_options = options
59
- @livefyre_update_block = block
60
- after_save :update_livefyre_if_fields_changed
61
- end
62
- end
63
- end
64
- end
data/lib/livefyre/site.rb DELETED
@@ -1,237 +0,0 @@
1
- module Livefyre
2
- # Public: Exception representing a failure to validate a signature
3
- class InvalidSignatureException < Exception; end
4
-
5
- # Public: An object representing a Livefyre site belonging to a Livefyre domain
6
- class Site
7
- attr_accessor :client, :secret, :options, :id
8
-
9
- # Public: Create a new Site
10
- def initialize(id, client = nil, options = {})
11
- @id = id
12
- @client = client || Livefyre.client
13
- @options = options
14
- @secret = options["api_secret"]
15
- end
16
-
17
- # Public: Search conversations on this domain
18
- #
19
- # query - string to query for
20
- # options - [Hash] of options
21
- # :fields - list of fields to search. Default [:article, :title, :body]
22
- # :sort - Sort order for options. Valid values are [:relevance, :created, :updated, :hotness, :ncomments]. Default is :relevance
23
- # :fields - List of fields to return in the result. Valid values are: article_id, site_id, domain_id, title, published, updated, author, url, ncomment, nuser, annotation, nlp, hotness, hottest_value, hottest_time, peak, peak_value, peak_time, comments:5, users:5, comment_state, hit_field, dispurl, relevancy
24
- # :max - Maximum number of fields to return
25
- # :since - [DateTime] Minimum date of results to return
26
- # :until - [DateTime] Maximum date of results to return
27
- # :page - Page of results to fetch. Default 1.
28
- #
29
- # Returns [Array<Conversation>] An array of matching conversations
30
- # Raises [APIException] when response is not valid
31
- def search_conversations(query, options = {})
32
- options[:sites] = [self]
33
- Domain.new(@client).search_conversations(query, options)
34
- end
35
-
36
- # Public: Get a list of properties for this site
37
- #
38
- # reload - Force a reload when set
39
- #
40
- # Returns [Hash] Site properties
41
- # Raises [APIException] when response is not valid
42
- def properties(reload = false)
43
- return @options unless @options.nil? or @options.empty? or reload
44
- response = client.get "/site/#{id}/", {:actor_token => client.system_token}
45
- if response.success?
46
- @options = JSON.parse response.body
47
- @secret = options["api_secret"]
48
- @options
49
- else
50
- raise APIException.new(response.body)
51
- end
52
- end
53
-
54
- # Public: Fetches a feed of the site's latest activity.
55
- #
56
- # since_id - [Integer] If provided, will return feed items after the given feed item.
57
- #
58
- # Returns [Array<Activity>] List of feed activities
59
- def feed(since_id = nil)
60
- reload if secret.nil?
61
- timestamp = Time.now.utc.to_i
62
- sig = Base64.encode64 HMAC::SHA1.new(Base64.decode64 secret).update("sig_created=%s" % timestamp).digest
63
- url = "/%s/" % ["site", id, "sync", since_id].compact.join("/")
64
- response = client.get url, {:sig_created => timestamp, :sig => sig}
65
- if response.success?
66
- payload = JSON.parse(response.body).map {|item| Activity.new(client, item) }
67
- else
68
- raise APIException.new(response.body)
69
- end
70
- end
71
-
72
- # Public: Fetches the latest comments from this site
73
- #
74
- # since_id - [Integer] If provided, will return feed items after the given comment.
75
- #
76
- # Returns: [Array<Comment>] List of comment
77
- def comments(since = nil)
78
- feed(since).select(&:comment?).map(&:comment)
79
- end
80
-
81
- # Public: Reload this site's properties from Livefyre
82
- #
83
- # Returns self
84
- def reload
85
- properties(true)
86
- self
87
- end
88
-
89
- # Public: Set the postback URL for actions on this site
90
- # See: https://github.com/Livefyre/livefyre-docs/wiki/Accessing-Site-Comment-Data
91
- #
92
- # url - [String] URL to use as the postback URL for actions
93
- #
94
- # Returns [Bool] true on success
95
- # Raises: [APIException] when response is not valid
96
- def set_postback_url(url)
97
- response = client.post "/site/#{id}/", {:actor_token => client.system_token, :postback_url => url}
98
- if response.success?
99
- properties(true) rescue APIException nil
100
- true
101
- else
102
- raise APIException.new(response.body)
103
- end
104
- end
105
-
106
- # Public: Retrieve a list of owners associated with this site
107
- #
108
- # Returns [Array<Livefyre::User>] A list of {Livefyre::User users}
109
- # Raises: APIException when response is not valid
110
- def owners
111
- response = client.get "/site/#{id}/owners/", {:actor_token => client.system_token}
112
- if response.success?
113
- JSON.parse(response.body).map do |u|
114
- client.user u.split("@", 2).first
115
- end
116
- else
117
- raise APIException.new(response.body)
118
- end
119
- end
120
-
121
- # Public: Adds a user to the list of owners for this site
122
- #
123
- # Returns [Bool] true on success
124
- # Raises [APIException] when response is not valid
125
- def add_owner(user)
126
- uid = User.get_user_id(user)
127
- response = client.post "/site/#{id}/owners/?actor_token=#{CGI.escape client.system_token}", {:jid => client.jid(uid)}
128
- if response.success?
129
- true
130
- else
131
- raise APIException.new(response.body)
132
- end
133
- end
134
-
135
- # Public: Removes a user from the list of owners for this site
136
- #
137
- # Returns [Bool] true on success
138
- # Raises [APIException] when response is not valid
139
- def remove_owner(user)
140
- user = User.get_user(user, client)
141
- response = client.delete "/site/#{id}/owner/#{user.jid}/?actor_token=#{CGI.escape client.system_token}"
142
- if response.success?
143
- true
144
- else
145
- raise APIException.new(response.body)
146
- end
147
- end
148
-
149
- # Public: Retrieve a list of owners associated with this site
150
- #
151
- # Returns [Array<Livefyre::User>] A list of {Livefyre::User users}
152
- # Raises: [APIException] when response is not valid
153
- def admins
154
- response = client.get "/site/#{id}/admins/", {:actor_token => client.system_token}
155
- if response.success?
156
- JSON.parse(response.body).map do |u|
157
- client.user u.split("@", 2).first
158
- end
159
- else
160
- raise APIException.new(response.body)
161
- end
162
- end
163
-
164
- # Public: Adds a user to the list of admins for this site
165
- #
166
- # Returns [Bool] true on success
167
- # Raises [APIException] when response is not valid
168
- def add_admin(user)
169
- user = User.get_user(user, client)
170
- response = client.post "/site/#{id}/admins/?actor_token=#{CGI.escape client.system_token}", {:jid => user.jid}
171
- if response.success?
172
- true
173
- else
174
- raise APIException.new(response.body)
175
- end
176
- end
177
-
178
- # Public: Removes a user from the list of admins for this site
179
- #
180
- # Returns [Bool] true on success
181
- # Raises [APIException] when response is not valid
182
- def remove_admin(user)
183
- user = User.get_user(user, client)
184
- response = client.delete "/site/#{id}/admin/#{user.jid}/?actor_token=#{CGI.escape client.system_token}"
185
- if response.success?
186
- true
187
- else
188
- raise APIException.new(response.body)
189
- end
190
- end
191
-
192
- # Public: Create a conversation collection on this site
193
- #
194
- # Returns [Conversation]
195
- def create_conversation(article_id, title, link, tags = nil)
196
- Conversation.create(client, article_id, title, link, tags)
197
- end
198
-
199
- # Internal: Returns a cleaner string representation of this object
200
- #
201
- # Returns [String] representation of this class
202
- def to_s
203
- "#<#{self.class.name}:0x#{object_id.to_s(16).rjust(14, "0")} id='#{id}' secret='#{secret}' options=#{options.inspect}>"
204
- end
205
-
206
- # Public: Validate a signature as passed by the Livefyre postback service
207
- #
208
- # params - Hash of request parameters
209
- # secret - Site key to validate signature with
210
- # time_window - Enforce that the sig_created is within time_window seconds of the current time.
211
- # Slush is given to account for system time drift. Pass nil or false to disable timestamp checking.
212
- #
213
- # Returns [Bool]
214
- # Raises [InvalidSignatureException] on failure
215
- def self.validate_signature(params, secret, time_window = 300)
216
- params = params.clone
217
- params.delete :controller
218
- params.delete :action
219
- sig = (params.delete(:sig) || "").strip
220
- raise InvalidSignatureException.new "Missing sig" if sig.nil?
221
- raise InvalidSignatureException.new "Missing site key" if secret.nil?
222
-
223
- hash_str = params.sort.map {|v| v.join("=") }.join("&")
224
-
225
- if time_window
226
- created_at = params[:sig_created]
227
- raise InvalidSignatureException.new "Missing sig_created" if created_at.nil?
228
- raise InvalidSignatureException.new "Invalid timestamp" if (Time.now.utc - Time.at(created_at.to_i).utc).abs > time_window
229
- end
230
-
231
- check = Base64.encode64 HMAC::SHA1.new(Base64.decode64 secret).update(hash_str).digest
232
- check = check.strip
233
- raise InvalidSignatureException.new "Invalid signature" if check != sig
234
- return sig == check
235
- end
236
- end
237
- end