livefyre 1.1.4 → 1.3.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.
checksums.yaml CHANGED
@@ -1,15 +1,15 @@
1
1
  ---
2
2
  !binary "U0hBMQ==":
3
3
  metadata.gz: !binary |-
4
- YWNlMjA0YzI2MmY2MTE4ZDVjODFhMmIyOWU4NGQ4MjY5NDBlMGQ2ZQ==
4
+ ZGUyOTkxOWQwN2MzZWRmYTZiMjhlMjhiNTliNTU4NTg2N2M5YjVkYg==
5
5
  data.tar.gz: !binary |-
6
- YmNkMGRkZWE5MDY3N2Y1NmM2MDI2NzFiNjg0ZjcwMTkxMTA0NDAyOQ==
6
+ ZTlmOWRlMWU4NTI0NzI5ODM1YmJlN2U1NzkzODA2M2MxMzExOGJmYQ==
7
7
  SHA512:
8
8
  metadata.gz: !binary |-
9
- ZmY0ODM1ZmZiMzk1Y2EwNzJmMmFjY2MwMTc2ZDc2NTY2MjlhNTFjZDI3YmE4
10
- ZjcwNDI2NWQxMzkwZjZmNDJlOTk0YWJhMzZiMTEyMjhjZDUwZjc0MGMwN2Mz
11
- NDNiMmJlOTFlZmVlYWVhYjE0MWFmNzYyMmMwOWY3M2E0ZDdkMDE=
9
+ YjM4ZWIyMWM2YjdhMzVhMjRiZTI4YTZjMzMwNzNjNjFhZjIwMTFkZDE3OTkx
10
+ YmRkZDIzZTY3MjlmOGM4NmY0ZDEzNmMxZDA2YWYyZDBlMmQxZDU0YTg1MzZi
11
+ ZGQxNmJlOTA0ZGEwMDBkZGQ0MjNmYzFiOTA4MTg0N2UwNzhmZjE=
12
12
  data.tar.gz: !binary |-
13
- MDRlYmJjN2U5MWExNmUyZWI4ZDUzYmYyYmU4ZDliMGIxMzdhM2Y4YWIwZjg1
14
- NjkyNzZmYWRkM2E0ZTg0ZGRhNWM2NTQ5MDVkZTU3ZjM0ZDQ4NjkyYTQ5ZGJm
15
- OTRhM2ZlZTUzZDg0MjBmZWU4NzQ3OThjZDBmNzhhZjNkNDFjYjg=
13
+ MmY1NjUwNjk3OTE4Nzc2ZTI4ZWI3MWFkMzFjYmFkZmIwNzJjZGMyMjJiODZh
14
+ OGRmNjc2NDlmNDRhODM4N2NhNzgzYmZkZGI5NWQyODdmMGU3ZDQ3YWJiNTcy
15
+ OTAxOTZhMTgxYzA3MzA5ODM5N2E5MmI3NmEzNzI4ZmVjODc4MjQ=
data/.gitignore CHANGED
@@ -15,3 +15,9 @@ spec/reports
15
15
  test/tmp
16
16
  test/version_tmp
17
17
  tmp
18
+
19
+ .idea/livefyre-ruby-utils.iml
20
+
21
+ .idea/workspace.xml
22
+
23
+ .idea/livefyre-ruby-utils.iml
data/.idea/.name ADDED
@@ -0,0 +1 @@
1
+ livefyre-ruby-utils
data/.idea/.rakeTasks ADDED
@@ -0,0 +1,7 @@
1
+ <?xml version="1.0" encoding="UTF-8"?>
2
+ <Settings><!--This file was automatically generated by Ruby plugin.
3
+ You are allowed to:
4
+ 1. Remove rake task
5
+ 2. Add existing rake tasks
6
+ To add existing rake tasks automatically delete this file and reload the project.
7
+ --><RakeGroup description="" fullCmd="" taksId="rake"><RakeTask description="Build livefyre-1.1.4.gem into the pkg directory" fullCmd="build" taksId="build" /><RakeTask description="Build and install livefyre-1.1.4.gem into system gems" fullCmd="install" taksId="install" /><RakeTask description="Create tag v1.1.4 and build and push livefyre-1.1.4.gem to Rubygems" fullCmd="release" taksId="release" /><RakeTask description="" fullCmd="run_tests" taksId="run_tests" /></RakeGroup></Settings>
@@ -0,0 +1,5 @@
1
+ <?xml version="1.0" encoding="UTF-8"?>
2
+ <project version="4">
3
+ <component name="Encoding" useUTFGuessing="true" native2AsciiForPropertiesFiles="false" />
4
+ </project>
5
+
data/.idea/misc.xml ADDED
@@ -0,0 +1,5 @@
1
+ <?xml version="1.0" encoding="UTF-8"?>
2
+ <project version="4">
3
+ <component name="ProjectRootManager" version="2" project-jdk-name="RVM: ruby-1.9.3-p484 [global]" project-jdk-type="RUBY_SDK" />
4
+ </project>
5
+
data/.idea/modules.xml ADDED
@@ -0,0 +1,9 @@
1
+ <?xml version="1.0" encoding="UTF-8"?>
2
+ <project version="4">
3
+ <component name="ProjectModuleManager">
4
+ <modules>
5
+ <module fileurl="file://$PROJECT_DIR$/.idea/livefyre-ruby-utils.iml" filepath="$PROJECT_DIR$/.idea/livefyre-ruby-utils.iml" />
6
+ </modules>
7
+ </component>
8
+ </project>
9
+
@@ -0,0 +1,5 @@
1
+ <component name="DependencyValidationManager">
2
+ <state>
3
+ <option name="SKIP_IMPORT_STATEMENTS" value="false" />
4
+ </state>
5
+ </component>
data/.idea/vagrant.xml ADDED
@@ -0,0 +1,8 @@
1
+ <?xml version="1.0" encoding="UTF-8"?>
2
+ <project version="4">
3
+ <component name="VagrantProjectSettings">
4
+ <option name="instanceFolder" value="" />
5
+ <option name="provider" value="" />
6
+ </component>
7
+ </project>
8
+
data/.idea/vcs.xml ADDED
@@ -0,0 +1,7 @@
1
+ <?xml version="1.0" encoding="UTF-8"?>
2
+ <project version="4">
3
+ <component name="VcsDirectoryMappings">
4
+ <mapping directory="$PROJECT_DIR$" vcs="Git" />
5
+ </component>
6
+ </project>
7
+
data/.project ADDED
@@ -0,0 +1,11 @@
1
+ <?xml version="1.0" encoding="UTF-8"?>
2
+ <projectDescription>
3
+ <name>livefyre-ruby-utils</name>
4
+ <comment></comment>
5
+ <projects>
6
+ </projects>
7
+ <buildSpec>
8
+ </buildSpec>
9
+ <natures>
10
+ </natures>
11
+ </projectDescription>
data/CHANGELOG CHANGED
@@ -1,3 +1,15 @@
1
+ === 1.3.0 2014-07-30
2
+
3
+ *** CAUTION: THIS VERSION HAS UPDATED METHODS THAT MAKE PREVIOUS FUNCTION CALLS OBSOLETE ***
4
+
5
+ * Jumped from 1.1.0 to 1.3.0 to match other libraries.
6
+ * Added personal stream and timeline support.
7
+ * Updated most API to use SSL.
8
+ * Added create_collection method.
9
+ * Updated checksum formula to match other libraries.
10
+ * Refactored core objects.
11
+ * Updated create_collection_meta to take in a dict of optional params.
12
+
1
13
  === 1.1.4 2014-05-07
2
14
 
3
15
  * Added changelog.
data/README.md CHANGED
@@ -53,10 +53,10 @@ site = network.get_site('site_id', 'site_key')
53
53
  ```
54
54
 
55
55
  Building a collection meta token:
56
- *The 'tags' and type' arguments are optional.*
56
+ *The {options} argument is optional.*
57
57
 
58
58
  ```ruby
59
- site.build_collection_meta_token('title', 'article_id', 'url', 'tags', 'type')
59
+ site.build_collection_meta_token('title', 'article_id', 'url', {options})
60
60
  ```
61
61
 
62
62
  Building a checksum:
@@ -78,7 +78,7 @@ To get a content collection's id:
78
78
  site.get_collection_id('article_id')
79
79
  ```
80
80
 
81
- ## Documentation
81
+ ## Additional Documentation
82
82
 
83
83
  Located [here](http://answers.livefyre.com/developers/libraries).
84
84
 
data/lib/livefyre.rb CHANGED
@@ -1,4 +1,4 @@
1
- require "livefyre/core"
1
+ require 'livefyre/core/network'
2
2
 
3
3
  module Livefyre
4
4
  def self.get_network(network_name, network_key)
@@ -0,0 +1,271 @@
1
+ require 'json'
2
+ require 'jwt'
3
+ require 'rest-client'
4
+ require 'addressable/uri'
5
+
6
+ require 'livefyre/entity/topic'
7
+ require 'livefyre/entity/subscription'
8
+
9
+ module Livefyre
10
+ class PersonalizedStream
11
+ # Topic API
12
+ def self.get_topic(core, topic_id)
13
+ url = self.base_url(core) + self.topic_path(core, topic_id)
14
+
15
+ response = RestClient.get(url, self.get_headers(core))
16
+ data = JSON.parse(response)['data']
17
+
18
+ Topic::serialize_from_json(data['topic'])
19
+ end
20
+
21
+ def self.create_or_update_topic(core, topic_id, label)
22
+ PersonalizedStream::create_or_update_topics(core, { "#{topic_id}" => label })[0]
23
+ end
24
+
25
+ def self.delete_topic(core, topic)
26
+ PersonalizedStream::delete_topics(core, [topic]) == 1
27
+ end
28
+
29
+ # Multiple Topic API
30
+ def self.get_topics(core, limit=100, offset=0)
31
+ url = self.base_url(core) + self.multiple_topic_path(core)
32
+ url += "?limit=#{limit}&offset=#{offset}"
33
+
34
+ response = RestClient.get(url, self.get_headers(core))
35
+ data = JSON.parse(response)['data']
36
+
37
+ topics = []
38
+ data['topics'].each do |topic|
39
+ topics << Topic::serialize_from_json(topic)
40
+ end
41
+
42
+ topics
43
+ end
44
+
45
+ def self.create_or_update_topics(core, topic_map)
46
+ topics = []
47
+
48
+ topic_map.each do |key, value|
49
+ if not value or value.length > 128
50
+ raise ArgumentError, 'label cannot be longer than 128 chars.'
51
+ end
52
+ topics << Topic::create(core, key, value)
53
+ end
54
+
55
+ url = self.base_url(core) + self.multiple_topic_path(core)
56
+ headers = self.get_headers(core)
57
+ headers[:content_type] = :json
58
+
59
+ topics_json = []
60
+ topics.each do |topic|
61
+ topics_json << topic.to_dict
62
+ end
63
+
64
+ response = RestClient.post(url, {topics: topics_json}.to_json, headers)
65
+ JSON.parse(response)['data']
66
+
67
+ return topics
68
+ end
69
+
70
+ def self.delete_topics(core, topics)
71
+ url = self.base_url(core) + self.multiple_topic_path(core)
72
+ headers = self.get_headers(core)
73
+ headers[:content_type] = :json
74
+ form = {delete: self.get_ids(topics)}
75
+
76
+ response = RestClient.patch(url, form.to_json, headers)
77
+ data = JSON.parse(response)['data']
78
+
79
+ data.has_key?('deleted') ? data['deleted'] : 0
80
+ end
81
+
82
+ # Collection Topic API
83
+ def self.get_collection_topics(site, collection_id)
84
+ url = self.base_url(site) + self.collection_topics_path(site, collection_id)
85
+
86
+ response = RestClient.get(url, self.get_headers(site))
87
+ data = JSON.parse(response)['data']
88
+
89
+ data.has_key?('topicIds') ? data['topicIds'] : []
90
+ end
91
+
92
+ def self.add_collection_topics(site, collection_id, topics)
93
+ url = self.base_url(site) + self.collection_topics_path(site, collection_id)
94
+ headers = self.get_headers(site)
95
+ headers[:content_type] = :json
96
+ form = {topicIds: self.get_ids(topics)}
97
+
98
+ response = RestClient.post(url, form.to_json, headers)
99
+ data = JSON.parse(response)['data']
100
+
101
+ data.has_key?('added') ? data['added'] : 0
102
+ end
103
+
104
+ def self.replace_collection_topics(site, collection_id, topics)
105
+ url = self.base_url(site) + self.collection_topics_path(site, collection_id)
106
+ headers = self.get_headers(site)
107
+ headers[:content_type] = :json
108
+ form = {topicIds: self.get_ids(topics)}
109
+
110
+ response = RestClient.put(url, form.to_json, headers)
111
+ data = JSON.parse(response)['data']
112
+
113
+ return data.has_key?('added') ? data['added'] : 0, data.has_key?('removed') ? data['removed'] : 0
114
+ end
115
+
116
+ def self.remove_collection_topics(site, collection_id, topics)
117
+ url = self.base_url(site) + self.collection_topics_path(site, collection_id)
118
+ headers = self.get_headers(site)
119
+ headers[:content_type] = :json
120
+ form = {delete: self.get_ids(topics)}
121
+
122
+ response = RestClient.patch(url, form.to_json, headers)
123
+ data = JSON.parse(response)['data']
124
+
125
+ data.has_key?('removed') ? data['removed'] : 0
126
+ end
127
+
128
+ # Subscription API
129
+ def self.get_subscriptions(network, user_id)
130
+ url = self.base_url(network) + self.user_subscription_path(network.get_user_urn(user_id))
131
+
132
+ response = RestClient.get(url, self.get_headers(network))
133
+ data = JSON.parse(response)['data']
134
+
135
+ subscriptions = []
136
+ if data.has_key?('subscriptions')
137
+ data['subscriptions'].each do |sub_json|
138
+ subscriptions << Subscription::serialize_from_json(sub_json)
139
+ end
140
+ end
141
+
142
+ subscriptions
143
+ end
144
+
145
+ def self.add_subscriptions(network, user_token, topics)
146
+ user_id = JWT.decode(user_token, network.key)['user_id']
147
+ user_urn = network.get_user_urn(user_id)
148
+ url = self.base_url(network) + self.user_subscription_path(user_urn)
149
+ headers = self.get_headers(network, user_token)
150
+ headers[:content_type] = :json
151
+ form = {subscriptions: self.to_subscriptions(topics, user_urn)}
152
+
153
+ response = RestClient.post(url, form.to_json, headers)
154
+ data = JSON.parse(response)['data']
155
+
156
+ data.has_key?('added') ? data['added'] : 0
157
+ end
158
+
159
+ def self.replace_subscriptions(network, user_token, topics)
160
+ user_id = JWT.decode(user_token, network.key)['user_id']
161
+ user_urn = network.get_user_urn(user_id)
162
+ url = self.base_url(network) + self.user_subscription_path(user_urn)
163
+ headers = self.get_headers(network, user_token)
164
+ headers[:content_type] = :json
165
+ form = {subscriptions: self.to_subscriptions(topics, user_urn)}
166
+
167
+ response = RestClient.put(url, form.to_json, headers)
168
+ data = JSON.parse(response)['data']
169
+
170
+ return data.has_key?('added') ? data['added'] : 0, data.has_key?('removed') ? data['removed'] : 0
171
+ end
172
+
173
+ def self.remove_subscriptions(network, user_token, topics)
174
+ user_id = JWT.decode(user_token, network.key)['user_id']
175
+ user_urn = network.get_user_urn(user_id)
176
+ url = self.base_url(network) + self.user_subscription_path(user_urn)
177
+ headers = self.get_headers(network, user_token)
178
+ headers[:content_type] = :json
179
+ form = {delete: self.to_subscriptions(topics, user_urn)}
180
+
181
+ response = RestClient.patch(url, form.to_json, headers)
182
+ data = JSON.parse(response)['data']
183
+
184
+ data.has_key?('removed') ? data['removed'] : 0
185
+ end
186
+
187
+ def self.get_subscribers(network, topic, limit=100, offset=0)
188
+ url = self.base_url(network) + self.topic_subscription_path(topic)
189
+ url += "?limit=#{limit}&offset=#{offset}"
190
+
191
+ response = RestClient.get(url, self.get_headers(network))
192
+ data = JSON.parse(response)['data']
193
+
194
+ subscriptions = []
195
+ if data.has_key?('subscriptions')
196
+ data['subscriptions'].each do |sub_json|
197
+ subscriptions << Subscription::serialize_from_json(sub_json)
198
+ end
199
+ end
200
+
201
+ subscriptions
202
+ end
203
+
204
+ # Stream API
205
+ def self.get_timeline_stream(core, resource, limit=50, t_until=nil, t_since=nil)
206
+ url = STREAM_BASE_URL + TIMELINE_PATH
207
+ url += "?resource=#{resource}&limit=#{limit}"
208
+
209
+ if t_until != nil
210
+ url += "&until=#{t_until}"
211
+ elsif t_since != nil
212
+ url += "&since=#{t_since}"
213
+ end
214
+
215
+ response = RestClient.get(url, self.get_headers(core))
216
+
217
+ JSON.parse(response)
218
+ end
219
+
220
+ private
221
+
222
+ def self.base_url(core)
223
+ "https://#{core.network_name}.quill.fyre.co/api/v4"
224
+ end
225
+
226
+ STREAM_BASE_URL = 'https://bootstrap.livefyre.com/api/v4'
227
+
228
+ def self.topic_path(core, topic_id)
229
+ "/#{Topic.generate_urn(core, topic_id)}/"
230
+ end
231
+
232
+ def self.multiple_topic_path(core)
233
+ "/#{core.get_urn}:topics/"
234
+ end
235
+
236
+ def self.collection_topics_path(site, collection_id)
237
+ "/#{site.get_urn}:collection=#{collection_id}:topics/"
238
+ end
239
+
240
+ def self.user_subscription_path(user_urn)
241
+ "/#{user_urn}:subscriptions/"
242
+ end
243
+
244
+ def self.topic_subscription_path(topic)
245
+ "/#{topic.id}:subscribers/"
246
+ end
247
+
248
+ TIMELINE_PATH = '/timeline/'
249
+
250
+ def self.get_headers(core, user_token=nil)
251
+ {:accepts => :json, :authorization => 'lftoken ' + (user_token == nil ? core.build_livefyre_token : user_token)}
252
+ end
253
+
254
+ def self.get_ids(topics)
255
+ ids = []
256
+ topics.each do |topic|
257
+ ids << topic.id
258
+ end
259
+
260
+ ids
261
+ end
262
+
263
+ def self.to_subscriptions(topics, user)
264
+ subscriptions = []
265
+ topics.each do |topic|
266
+ subscriptions << Subscription.new(topic.id, user, SubscriptionType::PERSONAL_STREAM).to_dict
267
+ end
268
+ subscriptions
269
+ end
270
+ end
271
+ end
@@ -0,0 +1,75 @@
1
+ require 'addressable/uri'
2
+ require 'jwt'
3
+ require 'rest-client'
4
+
5
+ require 'livefyre/core/site'
6
+
7
+ module Livefyre
8
+ class Network
9
+ DEFAULT_USER = 'system'
10
+ DEFAULT_EXPIRES = 86400
11
+
12
+ def initialize(name, key)
13
+ @name = name
14
+ @key = key
15
+ @network_name = name.split('.')[0]
16
+ end
17
+
18
+ attr_reader :name
19
+ attr_reader :key
20
+ attr_reader :network_name
21
+
22
+ def set_user_sync_url(url_template)
23
+ raise ArgumentError, 'url_template should contain {id}' if !url_template.include?('{id}')
24
+
25
+ response = RestClient.post(
26
+ "http://#{@name}",
27
+ { actor_token: build_livefyre_token, pull_profile_url: url_template }
28
+ )
29
+ response.code == 204
30
+ end
31
+
32
+ def sync_user(user_id)
33
+ response = RestClient.post(
34
+ "http://#{@name}/api/v3_0/user/#{user_id}/refresh",
35
+ { lftoken: build_livefyre_token }
36
+ )
37
+ response.code == 200
38
+ end
39
+
40
+ def build_livefyre_token
41
+ build_user_auth_token(DEFAULT_USER, DEFAULT_USER, DEFAULT_EXPIRES)
42
+ end
43
+
44
+ def build_user_auth_token(user_id, display_name, expires)
45
+ raise ArgumentError, 'user_id must be alphanumeric' if !(user_id =~ /\A\p{Alnum}+\z/)
46
+
47
+ JWT.encode({
48
+ domain: @name,
49
+ user_id: user_id,
50
+ display_name: display_name,
51
+ expires: Time.new.to_i + expires},
52
+ @key)
53
+ end
54
+
55
+ def validate_livefyre_token(lf_token)
56
+ token_attributes = JWT.decode(lf_token, @key)
57
+
58
+ token_attributes['domain'] == @name \
59
+ && token_attributes['user_id'] == DEFAULT_USER \
60
+ && token_attributes['expires'] >= Time.new.to_i
61
+ end
62
+
63
+ def get_site(site_id, site_key)
64
+ Site.new(self, site_id, site_key)
65
+ end
66
+
67
+ def get_urn
68
+ "urn:livefyre:#{@name}"
69
+ end
70
+
71
+ def get_user_urn(user)
72
+ "#{get_urn}:user=#{user}"
73
+ end
74
+ end
75
+ end
@@ -0,0 +1,102 @@
1
+ require 'base64'
2
+ require 'digest'
3
+ require 'json'
4
+ require 'jwt'
5
+ require 'rest-client'
6
+ require 'addressable/uri'
7
+
8
+ module Livefyre
9
+ class Site
10
+ TYPE = %w(reviews sidenotes ratings counting liveblog livechat livecomments)
11
+
12
+ def initialize(network, id, key)
13
+ @network = network
14
+ @id = id
15
+ @key = key
16
+ end
17
+
18
+ attr_reader :network
19
+ attr_reader :id
20
+ attr_reader :key
21
+
22
+ def build_collection_meta_token(title, article_id, url, options={})
23
+ raise ArgumentError, 'provided url is not a valid url' if !uri?(url)
24
+ raise ArgumentError, 'title length should be under 255 char' if title.length > 255
25
+
26
+ collection_meta = {
27
+ url: url,
28
+ title: title,
29
+ articleId: article_id
30
+ }
31
+
32
+ if options.has_key?(:type) && !TYPE.include?(options[:type])
33
+ raise ArgumentError, 'type is not a recognized type. should be liveblog, livechat, livecomments, reviews, sidenotes, or an empty string'
34
+ end
35
+
36
+ JWT.encode(collection_meta.merge(options), @key)
37
+ end
38
+
39
+ def build_checksum(title, url, tags='')
40
+ raise ArgumentError, 'provided url is not a valid url' if !uri?(url)
41
+ raise ArgumentError, 'title length should be under 255 char' if title.length > 255
42
+
43
+ collection_meta = { tags: tags, title: title, url: url }
44
+ Digest::MD5.new.update(collection_meta.to_json).hexdigest
45
+ end
46
+
47
+
48
+ def create_collection(title, article_id, url, options={})
49
+ uri = "https://#{network_name}.quill.fyre.co/api/v3.0/site/#{@id}/collection/create/?sync=1"
50
+ data = {
51
+ articleId: article_id,
52
+ collectionMeta: build_collection_meta_token(title, article_id, url, options),
53
+ checksum: build_checksum(title, url, options.has_key?(:tags) ? options[:tags] : '')
54
+ }
55
+ headers = {:accepts => :json, :content_type => :json}
56
+
57
+ response = RestClient.post(uri, data.to_json, headers)
58
+
59
+ if response.code == 200
60
+ return JSON.parse(response)['data']['collectionId']
61
+ end
62
+
63
+ nil
64
+ end
65
+
66
+ def get_collection_content(article_id)
67
+ response = RestClient.get(
68
+ "https://bootstrap.livefyre.com/bs3/#{@network.name}/#{@id}/#{Base64.encode64(article_id.to_s).chomp}/init",
69
+ :accepts => :json
70
+ )
71
+ response.code == 200 ? JSON.parse(response) : nil
72
+ end
73
+
74
+ def get_collection_id(article_id)
75
+ content = get_collection_content(article_id)
76
+ if content
77
+ content['collectionSettings']['collectionId']
78
+ end
79
+ end
80
+
81
+ def network_name
82
+ @network.network_name
83
+ end
84
+
85
+ def build_livefyre_token
86
+ @network.build_livefyre_token
87
+ end
88
+
89
+ def get_urn
90
+ "#{@network.get_urn}:site=#{@id}"
91
+ end
92
+
93
+ def uri?(string)
94
+ uri = Addressable::URI.parse(string)
95
+ %w( ftp ftps http https ).include?(uri.scheme)
96
+ rescue Addressable::URI::BadURIError
97
+ false
98
+ rescue Addressable::URI::InvalidURIError
99
+ false
100
+ end
101
+ end
102
+ end
@@ -0,0 +1,32 @@
1
+ module Livefyre
2
+ class Subscription
3
+ def initialize(to, by, type, created_at=nil)
4
+ @to = to
5
+ @by = by
6
+ @type = type
7
+ @created_at = created_at
8
+ end
9
+
10
+ attr_reader :to
11
+ attr_reader :by
12
+ attr_reader :type
13
+ attr_reader :created_at
14
+
15
+ def self.serialize_from_json(json)
16
+ new(json['to'], json['by'], json['type'], json['createdAt'])
17
+ end
18
+
19
+ def to_dict
20
+ dict = { :to => @to, :by => @by, :type => @type }
21
+ if @created_at != nil
22
+ dict[:createdAt] = @created_at
23
+ end
24
+ dict
25
+ end
26
+
27
+ end
28
+
29
+ module SubscriptionType
30
+ PERSONAL_STREAM = 1
31
+ end
32
+ end
@@ -0,0 +1,41 @@
1
+ require 'livefyre/api/personalized_stream'
2
+
3
+ module Livefyre
4
+ class TimelineCursor
5
+ def initialize(core, resource, limit, date)
6
+ @core = core
7
+ @resource = resource
8
+ @limit = limit
9
+ @next = false
10
+ @previous = false
11
+
12
+ @cursor_time = date.utc.iso8601(3)
13
+ end
14
+
15
+ def next(limit=@limit)
16
+ data = PersonalizedStream::get_timeline_stream(@core, @resource, limit, nil, @cursor_time)
17
+ cursor = data['meta']['cursor']
18
+
19
+ @next = cursor['hasNext']
20
+ @previous = cursor['next'] != nil
21
+ @cursor_time = cursor['next']
22
+
23
+ data
24
+ end
25
+
26
+ def previous(limit=@limit)
27
+ data = PersonalizedStream::get_timeline_stream(@core, @resource, limit, @cursor_time, nil)
28
+ cursor = data['meta']['cursor']
29
+
30
+ @previous = cursor['hasPrev']
31
+ @next = cursor['prev'] != nil
32
+ @cursor_time = cursor['prev']
33
+
34
+ data
35
+ end
36
+
37
+ def set_cursor_time(time)
38
+ @cursor_time = time.utc.iso8601(3)
39
+ end
40
+ end
41
+ end
@@ -0,0 +1,46 @@
1
+ module Livefyre
2
+ class Topic
3
+ TOPIC_IDENTIFIER = ':topic='
4
+
5
+ def initialize(id, label, created_at=nil, modified_at=nil)
6
+ @id = id
7
+ @label = label
8
+ @created_at = created_at
9
+ @modified_at = modified_at
10
+ end
11
+
12
+ attr_reader :id
13
+ attr_reader :label
14
+ attr_reader :created_at
15
+ attr_reader :modified_at
16
+
17
+ def self.create(core, id, label)
18
+ new(Topic::generate_urn(core, id), label)
19
+ end
20
+
21
+ def self.serialize_from_json(json)
22
+ new(json['id'], json['label'], json['createdAt'], json['modifiedAt'])
23
+ end
24
+
25
+ def to_dict
26
+ json = { :id => @id, :label => @label }
27
+ if @created_at != nil
28
+ json[:createdAt] = @created_at
29
+ end
30
+
31
+ if @modified_at != nil
32
+ json[:modifiedAt] = @modified_at
33
+ end
34
+
35
+ json
36
+ end
37
+
38
+ def self.generate_urn(core, id)
39
+ "#{core.get_urn}#{TOPIC_IDENTIFIER}#{id}"
40
+ end
41
+
42
+ def get_truncated_id
43
+ @id[@id.index(TOPIC_IDENTIFIER) + TOPIC_IDENTIFIER.length]
44
+ end
45
+ end
46
+ end
@@ -0,0 +1,15 @@
1
+ require 'livefyre/entity/timeline_cursor'
2
+
3
+ module Livefyre
4
+ class CursorFactory
5
+ def self.get_topic_stream_cursor(core, topic, limit=50, date=Time.new)
6
+ resource = "#{topic.id}:topicStream"
7
+ TimelineCursor.new(core, resource, limit, date)
8
+ end
9
+
10
+ def self.get_personal_stream_cursor(network, user, limit=50, date=Time.new)
11
+ resource = "#{network.get_user_urn(user)}:personalStream"
12
+ TimelineCursor.new(network, resource, limit, date)
13
+ end
14
+ end
15
+ end
@@ -1,3 +1,3 @@
1
1
  module Livefyre
2
- VERSION = "1.1.4"
2
+ VERSION = '1.3.0'
3
3
  end
@@ -0,0 +1,65 @@
1
+ require 'livefyre'
2
+ require 'jwt'
3
+ require 'livefyre/api/personalized_stream'
4
+ require 'livefyre/factory/cursor_factory'
5
+
6
+ RSpec.configure do |c|
7
+ c.filter_run_excluding :broken => true
8
+ end
9
+
10
+ describe Livefyre::Network, :broken => true do
11
+ before(:each) do
12
+ @network = Livefyre.get_network(NETWORK_NAME, NETWORK_KEY)
13
+ @site = @network.get_site(SITE_ID, SITE_KEY)
14
+ end
15
+
16
+ it 'should test that personalized streams api work for topics' do
17
+ Livefyre::PersonalizedStream::create_or_update_topic(@network, 1, 'EINS')
18
+ topic = Livefyre::PersonalizedStream::get_topic(@network, 1)
19
+ Livefyre::PersonalizedStream::delete_topic(@network, topic).should == true
20
+
21
+ Livefyre::PersonalizedStream::create_or_update_topics(@network, {1 => 'EINS', 2 => 'ZWEI'})
22
+ topics = Livefyre::PersonalizedStream::get_topics(@network)
23
+ Livefyre::PersonalizedStream::delete_topics(@network, topics)
24
+ end
25
+
26
+ it 'should test that personalized streams api work for subscriptions' do
27
+ topics = Livefyre::PersonalizedStream::create_or_update_topics(@network, {1 => 'EINS', 2 => 'ZWEI'})
28
+ user_token = @network.build_user_auth_token(USER_ID, "#{USER_ID}@#{NETWORK_NAME}", Livefyre::Network::DEFAULT_EXPIRES)
29
+
30
+ Livefyre::PersonalizedStream::add_subscriptions(@network, user_token, topics)
31
+ Livefyre::PersonalizedStream::get_subscriptions(@network, USER_ID)
32
+ Livefyre::PersonalizedStream::replace_subscriptions(@network, user_token, [topics[1]])
33
+ Livefyre::PersonalizedStream::get_subscribers(@network, topics[1])
34
+ Livefyre::PersonalizedStream::remove_subscriptions(@network, user_token, [topics[1]])
35
+ end
36
+
37
+ it 'should test that personalized streams api work for timelines and cursors' do
38
+ topic = Livefyre::PersonalizedStream::create_or_update_topic(@network, 1, 'EINS')
39
+ cursor = Livefyre::CursorFactory::get_topic_stream_cursor(@network, topic)
40
+
41
+ cursor.next
42
+ cursor.previous
43
+
44
+ Livefyre::PersonalizedStream::delete_topic(@network, topic)
45
+ end
46
+
47
+ it 'should test that personalized streams api work for topics' do
48
+ Livefyre::PersonalizedStream::create_or_update_topic(@site, 1, 'EINS')
49
+ topic = Livefyre::PersonalizedStream::get_topic(@site, 1)
50
+ Livefyre::PersonalizedStream::delete_topic(@site, topic).should == true
51
+
52
+ Livefyre::PersonalizedStream::create_or_update_topics(@site, {1 => 'EINS', 2 => 'ZWEI'})
53
+ topics = Livefyre::PersonalizedStream::get_topics(@site)
54
+ Livefyre::PersonalizedStream::delete_topics(@site, topics)
55
+ end
56
+
57
+ it 'should test that personalized streams api work for collections' do
58
+ topics = Livefyre::PersonalizedStream::create_or_update_topics(@site, {1 => 'EINS', 2 => 'ZWEI'})
59
+
60
+ Livefyre::PersonalizedStream::add_collection_topics(@site, COLLECTION_ID, topics)
61
+ Livefyre::PersonalizedStream::get_collection_topics(@site, COLLECTION_ID)
62
+ Livefyre::PersonalizedStream::replace_collection_topics(@site, COLLECTION_ID, [topics[1]])
63
+ Livefyre::PersonalizedStream::remove_collection_topics(@site, COLLECTION_ID, [topics[1]])
64
+ end
65
+ end
@@ -0,0 +1,24 @@
1
+ require 'livefyre'
2
+ require 'jwt'
3
+
4
+ RSpec.configure do |c|
5
+ c.filter_run_excluding :broken => true
6
+ end
7
+
8
+ describe Livefyre::Network do
9
+ before(:each) do
10
+ @network = Livefyre.get_network(NETWORK_NAME, NETWORK_KEY)
11
+ end
12
+
13
+ it 'should raise ArgumentError if url_template does not contain {id}' do
14
+ expect{ @network.set_user_sync_url('blah.com/') }.to raise_error(ArgumentError)
15
+ end
16
+
17
+ it 'should raise ArgumentError if user_id is not alphanumeric' do
18
+ expect{ @network.build_user_auth_token('fjoiwje.1fj', 'test', 100) }.to raise_error(ArgumentError)
19
+ end
20
+
21
+ it 'should validate a livefyre token' do
22
+ @network.validate_livefyre_token(@network.build_livefyre_token).should == true
23
+ end
24
+ end
@@ -0,0 +1,73 @@
1
+ # coding: utf-8
2
+
3
+ require 'livefyre'
4
+ require 'jwt'
5
+
6
+ RSpec.configure do |c|
7
+ c.filter_run_excluding :broken => true
8
+ end
9
+
10
+ describe Livefyre::Site do
11
+ before(:each) do
12
+ @site = Livefyre.get_network(NETWORK_NAME, NETWORK_KEY).get_site(SITE_ID, SITE_KEY)
13
+ end
14
+
15
+ it 'should raise ArgumentError if url is not a valid url for cmt' do
16
+ expect{ @site.build_collection_meta_token('test', 'test', 'blah.com/', 'test') }.to raise_error(ArgumentError)
17
+ end
18
+
19
+ it 'should raise ArgumentError if title is more than 255 characters for cmt' do
20
+ expect{ @site.build_collection_meta_token('1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456', 'test', 'http://test.com', 'test') }.to raise_error(ArgumentError)
21
+ end
22
+
23
+ it 'should raise ArgumentError if not a valid type is passed in when building a collection meta token' do
24
+ expect{ @site.build_collection_meta_token('', '', 'http://livefyre.com', {type: 'bad type'}) }.to raise_error(ArgumentError)
25
+ end
26
+
27
+ it 'should check type and assign them to the correct field in the collection meta token' do
28
+ @token = @site.build_collection_meta_token('', '', 'http://livefyre.com', {tags: '', type: 'reviews'})
29
+ @decoded = JWT.decode(@token, SITE_KEY)
30
+
31
+ expect(@decoded['type']).to eq('reviews')
32
+
33
+ @token = @site.build_collection_meta_token('', '', 'http://livefyre.com', {type: 'liveblog'})
34
+ @decoded = JWT.decode(@token, SITE_KEY)
35
+
36
+ expect(@decoded['type']).to eq('liveblog')
37
+ end
38
+
39
+ it 'should return a collection meta token' do
40
+ expect{ @site.build_collection_meta_token('title', 'article_id', 'https://www.url.com', 'tags') }.to be_true
41
+ end
42
+
43
+ it 'should raise ArgumentError if url is not a valid url for checksum' do
44
+ expect{ @site.build_checksum('test', 'blah.com/', 'test') }.to raise_error(ArgumentError)
45
+ end
46
+
47
+ it 'should raise ArgumentError if title is more than 255 characters for checksum' do
48
+ expect{ @site.build_checksum('1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456', 'http://test.com', 'test') }.to raise_error(ArgumentError)
49
+ end
50
+
51
+ it 'should return a valid checksum' do
52
+ expect(@site.build_checksum('title', 'https://www.url.com', 'tags')).to eq('4464458a10c305693b5bf4d43a384be7')
53
+ end
54
+
55
+ it 'should check for valid and invalid urls' do
56
+ expect{ @site.build_checksum('', 'test.com', '') }.to raise_error(ArgumentError)
57
+
58
+ @site.build_checksum('', 'http://localhost:8000', '')
59
+ @site.build_checksum('', 'http://清华大学.cn', '')
60
+ @site.build_checksum('', 'http://www.mysite.com/myresumé.html', '')
61
+ @site.build_checksum('', 'https://test.com/', '')
62
+ @site.build_checksum('', 'ftp://test.com/', '')
63
+ @site.build_checksum('', "https://test.com/path/test.-_~!$&'()*+,;=:@/dash", '')
64
+ end
65
+
66
+ it 'should test basic site api', :broken => true do
67
+ @site.get_collection_content(ARTICLE_ID)
68
+
69
+ name = "RubyCreateCollection#{Time.new}"
70
+ id = @site.create_collection(name, name, 'http://answers.livefyre.com/RUBY')
71
+ expect(@site.get_collection_id(name)).to eq(id)
72
+ end
73
+ end
@@ -0,0 +1,7 @@
1
+ NETWORK_NAME = '<NETWORK-NAME>'
2
+ NETWORK_KEY = '<NETWORK-KEY>'
3
+ SITE_ID = '<SITE-ID>'
4
+ SITE_KEY = '<SITE-KEY>'
5
+ COLLECTION_ID = '<COLLECTION-ID>'
6
+ USER = '<USER-ID>'
7
+ ARTICLE_ID = '<ARTICLE-ID>'
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: livefyre
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.1.4
4
+ version: 1.3.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Livefyre
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2014-05-07 00:00:00.000000000 Z
11
+ date: 2014-08-06 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler
@@ -126,16 +126,34 @@ extensions: []
126
126
  extra_rdoc_files: []
127
127
  files:
128
128
  - .gitignore
129
+ - .idea/.name
130
+ - .idea/.rakeTasks
131
+ - .idea/encodings.xml
132
+ - .idea/misc.xml
133
+ - .idea/modules.xml
134
+ - .idea/scopes/scope_settings.xml
135
+ - .idea/vagrant.xml
136
+ - .idea/vcs.xml
137
+ - .project
129
138
  - CHANGELOG
130
139
  - Gemfile
131
140
  - LICENSE.txt
132
141
  - README.md
133
142
  - Rakefile
134
143
  - lib/livefyre.rb
135
- - lib/livefyre/core.rb
144
+ - lib/livefyre/api/personalized_stream.rb
145
+ - lib/livefyre/core/network.rb
146
+ - lib/livefyre/core/site.rb
147
+ - lib/livefyre/entity/subscription.rb
148
+ - lib/livefyre/entity/timeline_cursor.rb
149
+ - lib/livefyre/entity/topic.rb
150
+ - lib/livefyre/factory/cursor_factory.rb
136
151
  - lib/livefyre/version.rb
137
152
  - livefyre.gemspec
138
- - spec/livefyre/core_spec.rb
153
+ - spec/livefyre/api/personalized_stream_spec.rb
154
+ - spec/livefyre/core/network_spec.rb
155
+ - spec/livefyre/core/site_spec.rb
156
+ - spec/livefyre/test_spec.rb
139
157
  homepage: http://github.com/livefyre/livefyre-ruby-utils
140
158
  licenses:
141
159
  - MIT
@@ -164,5 +182,8 @@ signing_key:
164
182
  specification_version: 4
165
183
  summary: Livefyre Ruby utility classes
166
184
  test_files:
167
- - spec/livefyre/core_spec.rb
185
+ - spec/livefyre/api/personalized_stream_spec.rb
186
+ - spec/livefyre/core/network_spec.rb
187
+ - spec/livefyre/core/site_spec.rb
188
+ - spec/livefyre/test_spec.rb
168
189
  has_rdoc:
data/lib/livefyre/core.rb DELETED
@@ -1,129 +0,0 @@
1
- require 'base64'
2
- require 'digest'
3
- require 'json'
4
- require 'jwt'
5
- require 'rest-client'
6
- require 'addressable/uri'
7
-
8
- module Livefyre
9
- class Network
10
- DEFAULT_USER = 'system'
11
- DEFAULT_EXPIRES = 86400
12
-
13
- def initialize(network_name, network_key)
14
- @network_name = network_name
15
- @network_key = network_key
16
- end
17
-
18
- def set_user_sync_url(url_template)
19
- raise ArgumentError, 'url_template should contain {id}' if !url_template.include?('{id}')
20
-
21
- response =
22
- RestClient.post(
23
- "http://#{@network_name}",
24
- { actor_token: build_livefyre_token, pull_profile_url: url_template }
25
- )
26
- response.code == 204
27
- end
28
-
29
- def sync_user(user_id)
30
- response =
31
- RestClient.post(
32
- "http://#{@network_name}/api/v3_0/user/#{user_id}/refresh",
33
- { lftoken: build_livefyre_token }
34
- )
35
- response.code == 200
36
- end
37
-
38
- def build_livefyre_token
39
- build_user_auth_token(DEFAULT_USER, DEFAULT_USER, DEFAULT_EXPIRES)
40
- end
41
-
42
- def build_user_auth_token(user_id, display_name, expires)
43
- raise ArgumentError, 'user_id must be alphanumeric' if !(user_id =~ /\A\p{Alnum}+\z/)
44
-
45
- JWT.encode({
46
- domain: @network_name,
47
- user_id: user_id,
48
- display_name: display_name,
49
- expires: Time.new.to_i + expires},
50
- @network_key)
51
- end
52
-
53
- def validate_livefyre_token(lf_token)
54
- token_attributes = JWT.decode(lf_token, @network_key)
55
-
56
- token_attributes['domain'] == @network_name \
57
- && token_attributes['user_id'] == DEFAULT_USER \
58
- && token_attributes['expires'] >= Time.new.to_i
59
- end
60
-
61
- def get_site(site_id, site_key)
62
- Site.new(@network_name, site_id, site_key)
63
- end
64
-
65
- class Site
66
- TYPE = ['reviews', 'sidenotes', 'ratings', 'counting', 'liveblog', 'livechat', 'livecomments']
67
-
68
- def initialize(network_name, site_id, site_key)
69
- @network_name = network_name
70
- @site_id = site_id
71
- @site_key = site_key
72
- end
73
-
74
- def build_collection_meta_token(title, article_id, url, tags='', type=nil)
75
- raise ArgumentError, 'provided url is not a valid url' if !uri?(url)
76
- raise ArgumentError, 'title length should be under 255 char' if title.length > 255
77
-
78
- collection_meta = {
79
- url: url,
80
- tags: tags,
81
- title: title,
82
- articleId: article_id
83
- }
84
- if type
85
- if TYPE.include? type
86
- collection_meta[:type] = type
87
- else
88
- raise ArgumentError, 'type is not a recognized type. should be liveblog, livechat, livecomments, reviews, sidenotes, or an empty string'
89
- end
90
- end
91
-
92
- JWT.encode(collection_meta, @site_key)
93
- end
94
-
95
- def build_checksum(title, url, tags='')
96
- raise ArgumentError, 'provided url is not a valid url' if !uri?(url)
97
- raise ArgumentError, 'title length should be under 255 char' if title.length > 255
98
-
99
- collection_meta = { url: url, tags: tags, title: title }
100
- Digest::MD5.new.update(collection_meta.to_json).hexdigest
101
- end
102
-
103
- def get_collection_content(article_id)
104
- response =
105
- RestClient.get(
106
- "http://bootstrap.#{@network_name}/bs3/#{@network_name}/#{@site_id}/#{Base64.encode64(article_id.to_s()).chomp}/init",
107
- :accepts => :json
108
- )
109
- response.code == 200 ? JSON.parse(response) : nil
110
- end
111
-
112
- def get_collection_id(article_id)
113
- content = get_collection_content(article_id)
114
- if content
115
- content['collectionSettings']['collectionId']
116
- end
117
- end
118
-
119
- def uri?(string)
120
- uri = Addressable::URI.parse(string)
121
- %w( ftp ftps http https ).include?(uri.scheme)
122
- rescue Addressable::URI::BadURIError
123
- false
124
- rescue Addressable::URI::InvalidURIError
125
- false
126
- end
127
- end
128
- end
129
- end
@@ -1,79 +0,0 @@
1
- # coding: utf-8
2
-
3
- require 'livefyre'
4
- require 'jwt'
5
-
6
- describe Livefyre::Network do
7
- before(:each) do
8
- @network = Livefyre.get_network('networkName', 'networkKey')
9
- end
10
-
11
- it 'should raise ArgumentError if url_template does not contain {id}' do
12
- expect{ @network.set_user_sync_url('blah.com/') }.to raise_error(ArgumentError)
13
- end
14
-
15
- it 'should raise ArgumentError if user_id is not alphanumeric' do
16
- expect{ @network.build_user_auth_token('fjoiwje.1fj', 'test', 100) }.to raise_error(ArgumentError)
17
- end
18
-
19
- it 'should validate a livefyre token' do
20
- @network.validate_livefyre_token(@network.build_livefyre_token).should == true
21
- end
22
- end
23
-
24
- describe Livefyre::Network::Site do
25
- before(:each) do
26
- @site = Livefyre.get_network('networkName', 'networkKey').get_site('siteId', 'siteKey')
27
- end
28
-
29
- it 'should raise ArgumentError if url is not a valid url for cmt' do
30
- expect{ @site.build_collection_meta_token('test', 'test', 'blah.com/', 'test') }.to raise_error(ArgumentError)
31
- end
32
-
33
- it 'should raise ArgumentError if title is more than 255 characters for cmt' do
34
- expect{ @site.build_collection_meta_token('1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456', 'test', 'http://test.com', 'test') }.to raise_error(ArgumentError)
35
- end
36
-
37
- it 'should raise ArgumentError if not a valid type is passed in when building a collection meta token' do
38
- expect{ @site.build_collection_meta_token('', '', 'http://livefyre.com', '', 'bad type') }.to raise_error(ArgumentError)
39
- end
40
-
41
- it 'should check type and assign them to the correct field in the collection meta token' do
42
- @token = @site.build_collection_meta_token('', '', 'http://livefyre.com', '', 'reviews')
43
- @decoded = JWT.decode(@token, 'siteKey')
44
-
45
- expect(@decoded['type']).to eq('reviews')
46
-
47
- @token = @site.build_collection_meta_token('', '', 'http://livefyre.com', '', 'liveblog')
48
- @decoded = JWT.decode(@token, 'siteKey')
49
-
50
- expect(@decoded['type']).to eq('liveblog')
51
- end
52
-
53
- it 'should return a collection meta token' do
54
- expect{ @site.build_collection_meta_token('title', 'article_id', 'https://www.url.com', 'tags') }.to be_true
55
- end
56
-
57
- it 'should raise ArgumentError if url is not a valid url for checksum' do
58
- expect{ @site.build_checksum('test', 'blah.com/', 'test') }.to raise_error(ArgumentError)
59
- end
60
-
61
- it 'should raise ArgumentError if title is more than 255 characters for checksum' do
62
- expect{ @site.build_checksum('1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456', 'http://test.com', 'test') }.to raise_error(ArgumentError)
63
- end
64
-
65
- it 'should return a valid checksum' do
66
- expect(@site.build_checksum('title', 'https://www.url.com', 'tags')).to eq('6e2e4faf7b95f896260fe695eafb34ba')
67
- end
68
-
69
- it 'should check for valid and invalid urls' do
70
- expect{ @site.build_checksum('', 'test.com', '') }.to raise_error(ArgumentError)
71
-
72
- @site.build_checksum('', 'http://localhost:8000', '')
73
- @site.build_checksum('', 'http://清华大学.cn', '')
74
- @site.build_checksum('', 'http://www.mysite.com/myresumé.html', '')
75
- @site.build_checksum('', 'https://test.com/', '')
76
- @site.build_checksum('', 'ftp://test.com/', '')
77
- @site.build_checksum('', "https://test.com/path/test.-_~!$&'()*+,;=:@/dash", '')
78
- end
79
- end