livefyre 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.
- data/.gitignore +1 -1
- data/README.md +24 -2
- data/Rakefile +4 -2
- data/app/assets/javascripts/livefyre.js +177 -0
- data/app/assets/javascripts/livefyre.js.coffee +59 -26
- data/gem-public_cert.pem +20 -0
- data/lib/livefyre/activity.rb +43 -0
- data/lib/livefyre/client.rb +25 -1
- data/lib/livefyre/comment.rb +190 -0
- data/lib/livefyre/controller_extensions.rb +24 -0
- data/lib/livefyre/conversation.rb +133 -0
- data/lib/livefyre/domain.rb +36 -2
- data/lib/livefyre/engine.rb +0 -0
- data/lib/livefyre/helpers.rb +0 -0
- data/lib/livefyre/model_extensions.rb +11 -23
- data/lib/livefyre/site.rb +108 -9
- data/lib/livefyre/user.rb +59 -7
- data/lib/livefyre/version.rb +1 -1
- data/lib/livefyre.rb +4 -0
- data/livefyre.gemspec +7 -0
- data/railties/railtie.rb +0 -0
- data/spec/livefyre/client_spec.rb +1 -1
- data/spec/livefyre/domain_spec.rb +2 -2
- data/spec/livefyre/livefyre_spec.rb +0 -0
- data/spec/livefyre/model_spec.rb +17 -13
- data/spec/livefyre/site_spec.rb +2 -1
- data/spec/livefyre/user_spec.rb +9 -20
- data/spec/spec_helper.rb +0 -0
- data.tar.gz.sig +0 -0
- metadata +111 -20
- metadata.gz.sig +0 -0
- data/app/assets/javascripts/livefyre.js.js +0 -117
data/.gitignore
CHANGED
data/README.md
CHANGED
|
@@ -91,16 +91,38 @@ Or you can have the gem do it automatically from the model:
|
|
|
91
91
|
livefyre_user :update_on => [:email, :display_name]
|
|
92
92
|
end
|
|
93
93
|
|
|
94
|
-
You can
|
|
94
|
+
You can provide your own update callback, in case you want to use something like Sidekiq to do the updates:
|
|
95
95
|
|
|
96
96
|
class User < ActiveRecord::Base
|
|
97
97
|
# ...
|
|
98
98
|
|
|
99
|
-
livefyre_user :update_on => [:email, :display_name]
|
|
99
|
+
livefyre_user :update_on => [:email, :display_name] do |user, livefyre_id|
|
|
100
|
+
Livefyre::User.delay.refresh livefyre_id
|
|
101
|
+
end
|
|
100
102
|
end
|
|
101
103
|
|
|
102
104
|
This will enqueue a ping-to-pull job in the "livefyre" queue. Make sure you have a worker running that'll handle that queue!
|
|
103
105
|
|
|
106
|
+
### Handling Postbacks
|
|
107
|
+
|
|
108
|
+
To handle postbacks, you'll need to set up a postback route:
|
|
109
|
+
|
|
110
|
+
match '/livefyre/postback', to: 'comments#postback'
|
|
111
|
+
|
|
112
|
+
You'll also need to tell Livefyre about this URL (similar to the ping-to-pull URL, via a console or elsewhere)
|
|
113
|
+
|
|
114
|
+
Livefyre::Site.new.set_postback_url "http://foo.com/livefyre/postback"
|
|
115
|
+
|
|
116
|
+
Finally, the gem provides a helper for validating Livefyre postback requests.
|
|
117
|
+
|
|
118
|
+
class CommentsController < ApplicationController
|
|
119
|
+
validate_postback_signature :only => [:postback], :key => "your_site_key"
|
|
120
|
+
|
|
121
|
+
def postback
|
|
122
|
+
# Handle the postback
|
|
123
|
+
end
|
|
124
|
+
end
|
|
125
|
+
|
|
104
126
|
### View integration
|
|
105
127
|
|
|
106
128
|
|
data/Rakefile
CHANGED
|
@@ -0,0 +1,177 @@
|
|
|
1
|
+
// Generated by CoffeeScript 1.3.3
|
|
2
|
+
(function() {
|
|
3
|
+
var cookie, defaultDelegate, load, utils, _initialized;
|
|
4
|
+
|
|
5
|
+
defaultDelegate = function(options) {
|
|
6
|
+
var authDelegate, k, v, _ref;
|
|
7
|
+
authDelegate = new fyre.conv.RemoteAuthDelegate();
|
|
8
|
+
_ref = options.auth;
|
|
9
|
+
for (k in _ref) {
|
|
10
|
+
v = _ref[k];
|
|
11
|
+
authDelegate[k] = v;
|
|
12
|
+
}
|
|
13
|
+
return authDelegate;
|
|
14
|
+
};
|
|
15
|
+
|
|
16
|
+
load = null;
|
|
17
|
+
|
|
18
|
+
(function() {
|
|
19
|
+
var head, __loadedScripts;
|
|
20
|
+
__loadedScripts = [];
|
|
21
|
+
head = null;
|
|
22
|
+
return load = function(source, id, content, options) {
|
|
23
|
+
var js, k, v;
|
|
24
|
+
if (!content) {
|
|
25
|
+
content = null;
|
|
26
|
+
}
|
|
27
|
+
if (document.getElementById(id)) {
|
|
28
|
+
return;
|
|
29
|
+
}
|
|
30
|
+
if (__loadedScripts[id]) {
|
|
31
|
+
return;
|
|
32
|
+
}
|
|
33
|
+
__loadedScripts[id] = true;
|
|
34
|
+
if (!head) {
|
|
35
|
+
head = document.getElementsByTagName('head')[0];
|
|
36
|
+
}
|
|
37
|
+
js = document.createElement("script");
|
|
38
|
+
js.id = id;
|
|
39
|
+
js.async = true;
|
|
40
|
+
js.src = source;
|
|
41
|
+
js.innerHTML = content;
|
|
42
|
+
if (options) {
|
|
43
|
+
for (k in options) {
|
|
44
|
+
v = options[k];
|
|
45
|
+
js[k] = v;
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
head.appendChild(js);
|
|
49
|
+
return js;
|
|
50
|
+
};
|
|
51
|
+
})();
|
|
52
|
+
|
|
53
|
+
cookie = function(token) {
|
|
54
|
+
var m;
|
|
55
|
+
m = document.cookie.match(new RegExp(token + "=([^;]+)"));
|
|
56
|
+
if (m) {
|
|
57
|
+
return m[1];
|
|
58
|
+
} else {
|
|
59
|
+
return null;
|
|
60
|
+
}
|
|
61
|
+
};
|
|
62
|
+
|
|
63
|
+
utils = function(options) {
|
|
64
|
+
var obj;
|
|
65
|
+
return obj = {
|
|
66
|
+
load: load,
|
|
67
|
+
startLogin: function(url, width, height, callback) {
|
|
68
|
+
var left, popup, top;
|
|
69
|
+
if (width == null) {
|
|
70
|
+
width = 600;
|
|
71
|
+
}
|
|
72
|
+
if (height == null) {
|
|
73
|
+
height = 400;
|
|
74
|
+
}
|
|
75
|
+
if (callback == null) {
|
|
76
|
+
callback = null;
|
|
77
|
+
}
|
|
78
|
+
left = (screen.width / 2) - (width / 2);
|
|
79
|
+
top = (screen.height / 2) - (height / 2);
|
|
80
|
+
popup = window.open(url, name, "menubar=no,toolbar=no,status=no,width=" + width + ",height=" + height + ",toolbar=no,left=" + left + ",top=" + top);
|
|
81
|
+
this.finishCallback = callback;
|
|
82
|
+
return this.startLoginPopup(popup);
|
|
83
|
+
},
|
|
84
|
+
startLoginPopup: function(popup) {
|
|
85
|
+
var _this = this;
|
|
86
|
+
this.tries = 0;
|
|
87
|
+
this.popup = popup;
|
|
88
|
+
return this.timer = setInterval(function() {
|
|
89
|
+
_this.tries += 1;
|
|
90
|
+
return _this.__checkLogin();
|
|
91
|
+
}, 100);
|
|
92
|
+
},
|
|
93
|
+
__checkLogin: function() {
|
|
94
|
+
var token;
|
|
95
|
+
token = cookie(options.cookie_name || "livefyre_utoken");
|
|
96
|
+
if (this.popup) {
|
|
97
|
+
try {
|
|
98
|
+
if (this.popup.closed === false && this.tries > 30) {
|
|
99
|
+
clearInterval(this.timer);
|
|
100
|
+
this.timer = null;
|
|
101
|
+
this.popup = null;
|
|
102
|
+
}
|
|
103
|
+
} catch (err) {
|
|
104
|
+
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
if (token) {
|
|
108
|
+
clearInterval(this.timer);
|
|
109
|
+
this.popup.close();
|
|
110
|
+
this.popup = null;
|
|
111
|
+
this.timer = null;
|
|
112
|
+
if (this.finishCallback) {
|
|
113
|
+
this.finishCallback();
|
|
114
|
+
}
|
|
115
|
+
return window.fyre.conv.login(token);
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
};
|
|
119
|
+
};
|
|
120
|
+
|
|
121
|
+
_initialized = false;
|
|
122
|
+
|
|
123
|
+
this.initLivefyre = function(options) {
|
|
124
|
+
var e, element, returnable;
|
|
125
|
+
if (_initialized && !options.force) {
|
|
126
|
+
throw "Livefyre has already been initialized";
|
|
127
|
+
}
|
|
128
|
+
_initialized = true;
|
|
129
|
+
e = document.getElementById(options.element_id || "livefyre_comments");
|
|
130
|
+
if (e) {
|
|
131
|
+
options.config || (options.config = {
|
|
132
|
+
checksum: e.getAttribute("data-checksum"),
|
|
133
|
+
collectionMeta: e.getAttribute("data-collection-meta"),
|
|
134
|
+
articleId: e.getAttribute("data-article-id"),
|
|
135
|
+
siteId: e.getAttribute("data-site-id"),
|
|
136
|
+
el: e.id
|
|
137
|
+
});
|
|
138
|
+
options.network || (options.network = e.getAttribute("data-network"));
|
|
139
|
+
options.domain || (options.domain = e.getAttribute("data-domain"));
|
|
140
|
+
options.root || (options.root = e.getAttribute("data-root"));
|
|
141
|
+
returnable = utils(options);
|
|
142
|
+
this.FYRE_LOADED_CB = function() {
|
|
143
|
+
var opts;
|
|
144
|
+
if (options.preLoad) {
|
|
145
|
+
options.preLoad(fyre);
|
|
146
|
+
}
|
|
147
|
+
opts = {
|
|
148
|
+
network: options.network,
|
|
149
|
+
authDelegate: options.delegate || defaultDelegate(options)
|
|
150
|
+
};
|
|
151
|
+
return fyre.conv.load(opts, [options.config], function(widget) {
|
|
152
|
+
var token;
|
|
153
|
+
returnable.widget = widget;
|
|
154
|
+
token = cookie(options.cookie_name || "livefyre_utoken");
|
|
155
|
+
if (token) {
|
|
156
|
+
try {
|
|
157
|
+
return fyre.conv.login(token);
|
|
158
|
+
} catch (error) {
|
|
159
|
+
if (window.console) {
|
|
160
|
+
return window.console.log("Error logging in:", e);
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
});
|
|
165
|
+
};
|
|
166
|
+
if (!options.manualLoad) {
|
|
167
|
+
element = load("http://" + options.root + "/wjs/v3.0/javascripts/livefyre.js", null, null, {
|
|
168
|
+
"data-lf-domain": options.network
|
|
169
|
+
});
|
|
170
|
+
}
|
|
171
|
+
return returnable;
|
|
172
|
+
} else {
|
|
173
|
+
return null;
|
|
174
|
+
}
|
|
175
|
+
};
|
|
176
|
+
|
|
177
|
+
}).call(this);
|
|
@@ -1,28 +1,13 @@
|
|
|
1
1
|
defaultDelegate = (options) ->
|
|
2
2
|
authDelegate = new fyre.conv.RemoteAuthDelegate()
|
|
3
|
-
authDelegate
|
|
4
|
-
|
|
5
|
-
options.login(handlers)
|
|
3
|
+
authDelegate[k] = v for k, v of options.auth
|
|
4
|
+
authDelegate
|
|
6
5
|
|
|
7
|
-
|
|
8
|
-
if options.logout
|
|
9
|
-
options.logout(handlers)
|
|
10
|
-
authDelegate.viewProfile = (handlers, author) ->
|
|
11
|
-
if options.viewProfile
|
|
12
|
-
if options.viewProfile(handlers, author)
|
|
13
|
-
handlers.success()
|
|
14
|
-
|
|
15
|
-
authDelegate.editProfile = (handlers, author) ->
|
|
16
|
-
if options.editProfile
|
|
17
|
-
if options.editProfile(handlers, author)
|
|
18
|
-
handlers.success()
|
|
19
|
-
|
|
20
|
-
loadScriptAsync = null
|
|
6
|
+
load = null
|
|
21
7
|
(->
|
|
22
8
|
__loadedScripts = []
|
|
23
9
|
fjs = null
|
|
24
|
-
|
|
25
|
-
content = null if !content
|
|
10
|
+
load = (source, id, options) ->
|
|
26
11
|
return if (document.getElementById(id))
|
|
27
12
|
return if __loadedScripts[id]
|
|
28
13
|
__loadedScripts[id] = true
|
|
@@ -31,18 +16,57 @@ loadScriptAsync = null
|
|
|
31
16
|
js.id = id
|
|
32
17
|
js.async = true
|
|
33
18
|
js.src = source
|
|
34
|
-
js.innerHTML = content
|
|
35
19
|
js[k] = v for k, v of options if options
|
|
36
20
|
|
|
37
21
|
fjs.parentNode.insertBefore(js, fjs)
|
|
38
22
|
js
|
|
39
23
|
)()
|
|
40
24
|
|
|
41
|
-
|
|
25
|
+
cookie = (token) ->
|
|
26
|
+
m = document.cookie.match(new RegExp(token + "=([^;]+)"))
|
|
27
|
+
if m then m[1] else null
|
|
28
|
+
|
|
29
|
+
utils = (options) ->
|
|
30
|
+
obj =
|
|
31
|
+
load: load
|
|
32
|
+
startLogin: (url, width = 600, height = 400, callback = null) ->
|
|
33
|
+
left = (screen.width / 2) - (width / 2)
|
|
34
|
+
top = (screen.height / 2) - (height / 2)
|
|
35
|
+
popup = window.open url, name, "menubar=no,toolbar=no,status=no,width=#{width},height=#{height},toolbar=no,left=#{left},top=#{top}"
|
|
36
|
+
@finishCallback = callback
|
|
37
|
+
@startLoginPopup(popup)
|
|
38
|
+
|
|
39
|
+
startLoginPopup: (popup) ->
|
|
40
|
+
@tries = 0
|
|
41
|
+
@popup = popup
|
|
42
|
+
@timer = setInterval(=>
|
|
43
|
+
@tries += 1
|
|
44
|
+
@__checkLogin()
|
|
45
|
+
, 100)
|
|
46
|
+
|
|
47
|
+
__checkLogin: ->
|
|
48
|
+
token = cookie(options.cookie_name || "livefyre_utoken")
|
|
49
|
+
if @popup
|
|
50
|
+
try
|
|
51
|
+
if @popup.closed == false and @tries > 30 # 3 seconds
|
|
52
|
+
clearInterval(@timer)
|
|
53
|
+
@timer = null
|
|
54
|
+
@popup = null
|
|
55
|
+
catch err
|
|
56
|
+
|
|
57
|
+
if token
|
|
58
|
+
clearInterval(@timer)
|
|
59
|
+
@popup.close()
|
|
60
|
+
@popup = null
|
|
61
|
+
@timer = null
|
|
62
|
+
@finishCallback() if @finishCallback
|
|
63
|
+
window.fyre.conv.login(token)
|
|
64
|
+
|
|
65
|
+
_initialized = false
|
|
42
66
|
@initLivefyre = (options) ->
|
|
43
|
-
if
|
|
67
|
+
if _initialized and !options.force
|
|
44
68
|
throw "Livefyre has already been initialized"
|
|
45
|
-
|
|
69
|
+
_initialized = true
|
|
46
70
|
e = document.getElementById(options.element_id || "livefyre_comments")
|
|
47
71
|
if e
|
|
48
72
|
options.config ||=
|
|
@@ -56,17 +80,26 @@ livefyreInitialized = false
|
|
|
56
80
|
options.domain ||= e.getAttribute("data-domain")
|
|
57
81
|
options.root ||= e.getAttribute("data-root")
|
|
58
82
|
|
|
83
|
+
returnable = utils(options)
|
|
84
|
+
|
|
59
85
|
@FYRE_LOADED_CB = ->
|
|
86
|
+
options.preLoad(fyre) if options.preLoad
|
|
60
87
|
opts =
|
|
61
88
|
network: options.network
|
|
62
89
|
authDelegate: options.delegate || defaultDelegate(options)
|
|
63
90
|
|
|
64
|
-
fyre.conv.load opts, [options.config], ->
|
|
65
|
-
|
|
91
|
+
fyre.conv.load opts, [options.config], (widget) ->
|
|
92
|
+
returnable.widget = widget
|
|
93
|
+
token = cookie(options.cookie_name || "livefyre_utoken")
|
|
66
94
|
if token
|
|
67
95
|
try
|
|
68
96
|
fyre.conv.login(token)
|
|
69
97
|
catch error
|
|
70
98
|
window.console.log "Error logging in:", e if window.console
|
|
71
99
|
|
|
72
|
-
|
|
100
|
+
unless options.manualLoad
|
|
101
|
+
element = load "http://#{options.root}/wjs/v3.0/javascripts/livefyre.js", null, {"data-lf-domain": options.network}
|
|
102
|
+
returnable
|
|
103
|
+
|
|
104
|
+
else
|
|
105
|
+
null
|
data/gem-public_cert.pem
ADDED
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
-----BEGIN CERTIFICATE-----
|
|
2
|
+
MIIDNDCCAhygAwIBAgIBADANBgkqhkiG9w0BAQUFADBAMQ8wDQYDVQQDDAZjaGVh
|
|
3
|
+
bGQxGDAWBgoJkiaJk/IsZAEZFghtYXNoYWJsZTETMBEGCgmSJomT8ixkARkWA2Nv
|
|
4
|
+
bTAeFw0xMzAxMzExNzI2NDBaFw0xNDAxMzExNzI2NDBaMEAxDzANBgNVBAMMBmNo
|
|
5
|
+
ZWFsZDEYMBYGCgmSJomT8ixkARkWCG1hc2hhYmxlMRMwEQYKCZImiZPyLGQBGRYD
|
|
6
|
+
Y29tMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA4AMfgtORekddgqRx
|
|
7
|
+
mHdKSRuQ7Pks2LN96uINU9lWhmppM/mrbHUvkW28wdfC27MTtR1cQUZWAzS8eWsH
|
|
8
|
+
Fq0hdm5R5tsrXLM8Y7tUcoKu5qTJEmDyN2TH3lx9hH/fzwhU2rhb/DrIhtOJNBsg
|
|
9
|
+
5AERbX/LA6nmQLEQlbVoVHH5tmIGnAYY96WfCNeJyexLfuOeAn1NFyBJqsU7VhFf
|
|
10
|
+
JBhyHKdMDRY3HkQD6LHVVDidwEOyi+vKb13GlHwproUPutp3qTEG24IhuQGARV+f
|
|
11
|
+
zSwQ1Ay6L7CmMZmznwPaPBd/zOMbe1RGg5ofCvNAgxspbNGQPJvNp+DxRENdY06N
|
|
12
|
+
qeO/GQIDAQABozkwNzAJBgNVHRMEAjAAMB0GA1UdDgQWBBRqk99cHYdBntfkSYOk
|
|
13
|
+
ZfXJcbaTAjALBgNVHQ8EBAMCBLAwDQYJKoZIhvcNAQEFBQADggEBAHaKNSM783Da
|
|
14
|
+
/BGQv6DRjxi3wYmnn4RHJIQK4DiJjR6umtCtlBuMbhQbUBbu8sIFnqtdsKHaC097
|
|
15
|
+
ygk9anqygAOYtYk2+hfn2fBFYZTflvgSuo6/IzMWucOpGrbIWczDMnH8p4biJNp+
|
|
16
|
+
24du/MH+9ODiInly0UwcDyE4TW2chmvOCjLowa7bvJY3LXCDpSUMXjIO/4Cysfwk
|
|
17
|
+
F5adOPFD5KcabVlHmRpprAw2GYYbWwuuV11tA+4Fhkz0ClB25/gEkFZWevs5wsEC
|
|
18
|
+
miAJUwubyGI/SoFFe9MYI4i01qPX/Hqa9wqLbbEaUSCUQfcHNzgK3o2SYjmQe6Nm
|
|
19
|
+
yld6FGg9zOY=
|
|
20
|
+
-----END CERTIFICATE-----
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
module Livefyre
|
|
2
|
+
# Public: Proxy object for an item from a Conversation activity feed
|
|
3
|
+
class Activity
|
|
4
|
+
attr_accessor :id, :user, :conversation, :body, :state, :created_at
|
|
5
|
+
def initialize(client, params = {})
|
|
6
|
+
@client = Livefyre.client
|
|
7
|
+
@params = params
|
|
8
|
+
@id = params["activity_id"]
|
|
9
|
+
@conversation = Conversation.new(@params["lf_conv_id"], @params["article_identifier"])
|
|
10
|
+
@created_at = Time.at(@params["created"]) - Time.at(0).utc_offset
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
# Public: Cast this activity to a Comment
|
|
14
|
+
#
|
|
15
|
+
# Return [Comment]
|
|
16
|
+
def comment
|
|
17
|
+
Comment.new(@params["lf_comment_id"], conversation,
|
|
18
|
+
:body => @params["body_text"],
|
|
19
|
+
:user => user,
|
|
20
|
+
:parent_id => @params["lf_parent_comment_id"],
|
|
21
|
+
:author_ip => @params["author_ip"],
|
|
22
|
+
:state => @params["state"]
|
|
23
|
+
)
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
# Public: Fetch the user that created this record
|
|
27
|
+
#
|
|
28
|
+
# Returns [User]
|
|
29
|
+
def user
|
|
30
|
+
User.new((@params["lf_jid"] || "").split("@", 2).first, @client, @params["author"],
|
|
31
|
+
:email => @params["author_email"],
|
|
32
|
+
:url => @params["author_url"]
|
|
33
|
+
)
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
# Internal: Test if this activity represented a comment
|
|
37
|
+
#
|
|
38
|
+
# Returns [Boolean]
|
|
39
|
+
def comment?
|
|
40
|
+
@params["activity_type"] == "comment-add"
|
|
41
|
+
end
|
|
42
|
+
end
|
|
43
|
+
end
|
data/lib/livefyre/client.rb
CHANGED
|
@@ -8,7 +8,7 @@ module Livefyre
|
|
|
8
8
|
# Public: Valid scopes for #set_user_role
|
|
9
9
|
SCOPES = %w(domain site conv)
|
|
10
10
|
|
|
11
|
-
attr_accessor :host, :key, :options, :system_token, :http_client
|
|
11
|
+
attr_accessor :host, :key, :options, :system_token, :http_client, :site_key, :quill, :stream, :bootstrap, :search
|
|
12
12
|
|
|
13
13
|
def_delegators :http_client, :get, :post, :delete, :put
|
|
14
14
|
|
|
@@ -23,6 +23,11 @@ module Livefyre
|
|
|
23
23
|
@host = options.delete(:network) || options.delete(:host)
|
|
24
24
|
raise "Invalid host" if @host.nil?
|
|
25
25
|
@http_client = Faraday.new(:url => "http://#{@host}")
|
|
26
|
+
@quill = Faraday.new(:url => "http://quill.#{@host}")
|
|
27
|
+
@stream = Faraday.new(:url => "http://stream.#{@host}")
|
|
28
|
+
@search = Faraday.new(:url => "http://search.#{@host}")
|
|
29
|
+
@bootstrap = Faraday.new(:url => "http://bootstrap.#{@host}")
|
|
30
|
+
@site_key = options[:site_key]
|
|
26
31
|
|
|
27
32
|
@key = options.delete(:secret) || options.delete(:key) || options.delete(:network_key)
|
|
28
33
|
raise "Invalid secret key" if @key.nil?
|
|
@@ -107,11 +112,30 @@ module Livefyre
|
|
|
107
112
|
"%s@%s" % [id, host]
|
|
108
113
|
end
|
|
109
114
|
|
|
115
|
+
# Internal: Identifier to use to uniquely identify this client.
|
|
116
|
+
#
|
|
117
|
+
# Returns string ID
|
|
118
|
+
def identifier
|
|
119
|
+
@identifier ||= "RubyLib-#{Process.pid}-#{local_ip}-#{object_id}"
|
|
120
|
+
end
|
|
121
|
+
|
|
110
122
|
# Internal: Returns a cleaner string representation of this object
|
|
111
123
|
#
|
|
112
124
|
# Returns [String] representation of this class
|
|
113
125
|
def to_s
|
|
114
126
|
"#<#{self.class.name}:0x#{object_id.to_s(16).rjust(14, "0")} host='#{host}' key='#{key}'>"
|
|
115
127
|
end
|
|
128
|
+
|
|
129
|
+
private
|
|
130
|
+
|
|
131
|
+
def local_ip
|
|
132
|
+
orig, Socket.do_not_reverse_lookup = Socket.do_not_reverse_lookup, true # turn off reverse DNS resolution temporarily
|
|
133
|
+
UDPSocket.open do |s|
|
|
134
|
+
s.connect '64.233.187.99', 1
|
|
135
|
+
s.addr.last
|
|
136
|
+
end
|
|
137
|
+
ensure
|
|
138
|
+
Socket.do_not_reverse_lookup = orig
|
|
139
|
+
end
|
|
116
140
|
end
|
|
117
141
|
end
|
|
@@ -0,0 +1,190 @@
|
|
|
1
|
+
module Livefyre
|
|
2
|
+
# Public: Proxy object for a [Comment] on a [Livefyre::Conversation]
|
|
3
|
+
class Comment
|
|
4
|
+
private
|
|
5
|
+
SOURCES = %w(Livefyre Twitter Twitter Facebook Livefyre Livefyre Facebook Twitter Livefyre)
|
|
6
|
+
VISIBILITIES = %w(None Everyone Owner Group)
|
|
7
|
+
CONTENT_TYPES = %w(Message Opinion)
|
|
8
|
+
PERMISSIONS = %w(Global Network Site Collection CollectionRule)
|
|
9
|
+
REASONS = %w(disagree spam offensive off-topic)
|
|
10
|
+
|
|
11
|
+
public
|
|
12
|
+
|
|
13
|
+
attr_accessor :id, :body, :user, :parent_id, :ip, :conversation, :created_at
|
|
14
|
+
def initialize(id, conversation, options = {})
|
|
15
|
+
@id = id
|
|
16
|
+
@body = options[:body]
|
|
17
|
+
@user = options[:user]
|
|
18
|
+
@parent_id = options[:parent_id]
|
|
19
|
+
@ip = options[:author_ip]
|
|
20
|
+
@conversation = conversation
|
|
21
|
+
@created_at = options[:created_at]
|
|
22
|
+
@client = options[:client] || Livefyre.client
|
|
23
|
+
@options = options
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
# Public: Flag a comment
|
|
27
|
+
#
|
|
28
|
+
# reason - one of [disagree, spam, offensive, off-topic]
|
|
29
|
+
# notes - String containing the reason for the flag
|
|
30
|
+
# email - email address of the flagger
|
|
31
|
+
# user - [User] If set, will include the user token for validation of the flag
|
|
32
|
+
def flag(reason, notes, email, user = nil)
|
|
33
|
+
raise "invalid reason" unless REASONS.include? reason
|
|
34
|
+
payload = {
|
|
35
|
+
:message_id => @id,
|
|
36
|
+
:collection_id => @conversation.id,
|
|
37
|
+
:flag => reason,
|
|
38
|
+
:notes => notes,
|
|
39
|
+
:email => email
|
|
40
|
+
}
|
|
41
|
+
payload[:lftoken] = user.token if user
|
|
42
|
+
response = client.quill.post "/api/v3.0/message/25818122/flag/#{reason}/", payload.to_json
|
|
43
|
+
if response.success?
|
|
44
|
+
true
|
|
45
|
+
else
|
|
46
|
+
raise APIException.new(response.body)
|
|
47
|
+
end
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
# Public: Delete this comment
|
|
51
|
+
#
|
|
52
|
+
# Returns [Boolean] true on success
|
|
53
|
+
# Raises [APIException] on failure
|
|
54
|
+
def delete!
|
|
55
|
+
response = client.quill.post "/api/v3.0/message/#{id}/delete", {:lftoken => @client.system_token}
|
|
56
|
+
if response.success?
|
|
57
|
+
true
|
|
58
|
+
else
|
|
59
|
+
raise APIException.new(response.body)
|
|
60
|
+
end
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
# Public: Update this comment's content
|
|
64
|
+
#
|
|
65
|
+
# Returns [Boolean] true on success
|
|
66
|
+
# Raises [APIException] on failure
|
|
67
|
+
def update(body)
|
|
68
|
+
response = client.quill.post "/api/v3.0/message/#{id}/edit", {:lftoken => @client.system_token, :body => body}
|
|
69
|
+
if response.success?
|
|
70
|
+
true
|
|
71
|
+
else
|
|
72
|
+
raise APIException.new(response.body)
|
|
73
|
+
end
|
|
74
|
+
end
|
|
75
|
+
|
|
76
|
+
# Public: Get the comment source as a string.
|
|
77
|
+
# Currently only populated when created via ::create
|
|
78
|
+
#
|
|
79
|
+
# Returns [Enum<SOURCES>]
|
|
80
|
+
def source
|
|
81
|
+
source_id ? SOURCES[source_id] : nil
|
|
82
|
+
end
|
|
83
|
+
|
|
84
|
+
# Public: Get the comment source as an integer.
|
|
85
|
+
# Currently only populated when created via ::create
|
|
86
|
+
#
|
|
87
|
+
# Returns [Integer]
|
|
88
|
+
def source_id
|
|
89
|
+
@options[:source]
|
|
90
|
+
end
|
|
91
|
+
|
|
92
|
+
# Public: Get the comment visibility as a string.
|
|
93
|
+
# Currently only populated when created via ::create
|
|
94
|
+
#
|
|
95
|
+
# Returns [Enum<VISIBILITIES>]
|
|
96
|
+
def visibility
|
|
97
|
+
visibility_id ? VISIBILITIES[visibility_id] : nil
|
|
98
|
+
end
|
|
99
|
+
|
|
100
|
+
# Public: Get the comment visibility as an integer.
|
|
101
|
+
# Currently only populated when created via ::create
|
|
102
|
+
#
|
|
103
|
+
# Returns [Integer]
|
|
104
|
+
def visibility_id
|
|
105
|
+
@options[:visibility]
|
|
106
|
+
end
|
|
107
|
+
|
|
108
|
+
# Public: Get the comment content type as a string.
|
|
109
|
+
# Currently only populated when created via ::create
|
|
110
|
+
#
|
|
111
|
+
# Returns [Enum<CONTENT_TYPES>]
|
|
112
|
+
def content_type
|
|
113
|
+
content_type_id ? CONTENT_TYPES[content_type_id] : nil
|
|
114
|
+
end
|
|
115
|
+
|
|
116
|
+
# Public: Get the comment visibility as an integer.
|
|
117
|
+
# Currently only populated when created via ::create
|
|
118
|
+
#
|
|
119
|
+
# Returns [Integer]
|
|
120
|
+
def content_type_id
|
|
121
|
+
@options[:type]
|
|
122
|
+
end
|
|
123
|
+
|
|
124
|
+
# Public: Likes a comment as the passed user
|
|
125
|
+
#
|
|
126
|
+
# Returns [Boolean] true on success
|
|
127
|
+
# Raises [APIException] on failure
|
|
128
|
+
def like!(user)
|
|
129
|
+
response = @client.quill.post "/api/v3.0/message/#{id}/like/", {:collection_id => conversation.id, :lftoken => user.token}
|
|
130
|
+
if response.success?
|
|
131
|
+
true
|
|
132
|
+
else
|
|
133
|
+
raise APIException.new(response.body)
|
|
134
|
+
end
|
|
135
|
+
end
|
|
136
|
+
|
|
137
|
+
# Public: Unlikes a comment as the passed user
|
|
138
|
+
#
|
|
139
|
+
# Returns [Boolean] true on success
|
|
140
|
+
# Raises [APIException] on failure
|
|
141
|
+
def unlike!(user)
|
|
142
|
+
response = @client.quill.post "/api/v3.0/message/#{id}/unlike/", {:collection_id => conversation.id, :lftoken => user.token}
|
|
143
|
+
if response.success?
|
|
144
|
+
true
|
|
145
|
+
else
|
|
146
|
+
raise APIException.new(response.body)
|
|
147
|
+
end
|
|
148
|
+
end
|
|
149
|
+
|
|
150
|
+
# Public: create a new comment on a conversation
|
|
151
|
+
#
|
|
152
|
+
# client - [Client] representing the site to use when creating the conversation
|
|
153
|
+
# user - [User] to create the comment as
|
|
154
|
+
# conversation - [Conversation] to create
|
|
155
|
+
# body - [String] Comment body
|
|
156
|
+
#
|
|
157
|
+
# Returns [Comment]
|
|
158
|
+
# Raises [APIException] when the API call fails
|
|
159
|
+
def self.create(client, user, conversation, body, reply_to = nil)
|
|
160
|
+
response = client.quill.post "/api/v3.0/collection/#{conversation.id}/post/", {:lftoken => user.token, :body => body, :_bi => client.identifier, :parent_id => reply_to}
|
|
161
|
+
if response.success?
|
|
162
|
+
puts JSON.parse(response.body).inspect
|
|
163
|
+
data = JSON.parse(response.body)["data"]
|
|
164
|
+
|
|
165
|
+
data["messages"].map do |entry|
|
|
166
|
+
c = entry["content"]
|
|
167
|
+
Comment.new(c["id"], conversation, {
|
|
168
|
+
:body => c["bodyHtml"],
|
|
169
|
+
:parent_id => c["parentId"],
|
|
170
|
+
:user => User.new(c["authorId"], data["authors"].first.last["displayName"], data["authors"].first.last),
|
|
171
|
+
:created_at => Time.at(c["createdAt"]),
|
|
172
|
+
:source => entry["source"],
|
|
173
|
+
:visibility => entry["vis"],
|
|
174
|
+
:client => client,
|
|
175
|
+
:type => entry["type"]
|
|
176
|
+
})
|
|
177
|
+
end.first
|
|
178
|
+
else
|
|
179
|
+
raise APIException.new(response.body)
|
|
180
|
+
end
|
|
181
|
+
end
|
|
182
|
+
|
|
183
|
+
# Internal: Returns a cleaner string representation of this object
|
|
184
|
+
#
|
|
185
|
+
# Returns [String] representation of this class
|
|
186
|
+
def to_s
|
|
187
|
+
"#<#{self.class.name}:0x#{object_id.to_s(16).rjust(14, "0")} id='#{id}' options=#{@options.inspect}>"
|
|
188
|
+
end
|
|
189
|
+
end
|
|
190
|
+
end
|