livefyre 0.0.1 → 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
|