mwilden-disqus 1.0.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,51 @@
1
+ module Disqus
2
+
3
+ class Post
4
+ attr_reader :id, :forum, :thread, :created_at, :message, :parent_post, :shown, :is_anonymous, :author
5
+
6
+ def initialize(id, forum, thread, created_at, message, parent_post, shown, is_anonymous, author)
7
+ @id, @forum, @thread, @created_at, @message, @parent_post, @shown, @is_anonymous, @author = id.to_i, forum, thread, Time.parse(created_at.to_s), message, parent_post, shown, is_anonymous, author
8
+ end
9
+
10
+ # Returns an array of Post objects representing all posts belonging to the
11
+ # given thread. The array is sorted by the "created_at" date descending.
12
+ def self.list(thread)
13
+ response = Disqus::Api::get_thread_posts(:thread_id =>thread.id, :forum_api_key => thread.forum.key)
14
+ if response["succeeded"]
15
+ posts = response["message"].map do |post|
16
+ author = nil
17
+ if post["is_anonymous"]
18
+ author = AnonymousAuthor.new(
19
+ post["anonymous_author"]["name"],
20
+ post["anonymous_author"]["url"],
21
+ post["anonymous_author"]["email_hash"]
22
+ )
23
+ else
24
+ author = Author.new(
25
+ post["author"]["id"].to_i,
26
+ post["author"]["username"],
27
+ post["author"]["display_name"],
28
+ post["author"]["url"],
29
+ post["author"]["email_hash"],
30
+ post["author"]["has_avatar"]
31
+ )
32
+ end
33
+ Post.new(
34
+ post["id"],
35
+ thread.forum,
36
+ thread,
37
+ post["created_at"],
38
+ post["message"],
39
+ post["parent_post"],
40
+ post["shown"],
41
+ post["is_anonymous"],
42
+ author
43
+ )
44
+ end
45
+ posts.sort!{|a,b| a.created_at <=> b.created_at}
46
+ end
47
+ end
48
+ end
49
+ end
50
+
51
+
@@ -0,0 +1,73 @@
1
+ module Disqus
2
+
3
+ class Thread
4
+ attr_reader :id, :forum, :slug, :title, :created_at, :allow_comments, :url, :identifier, :forum
5
+
6
+ def initialize(id, forum, slug, title, created_at, allow_comments, url, identifier)
7
+ @id, @forum, @slug, @title, @created_at, @allow_comments, @url, @identifier = id.to_i, forum, slug, title, Time.parse(created_at.to_s), allow_comments, url, identifier
8
+ @posts = []
9
+ end
10
+
11
+ # Threads are equal if all their attributes are equal.
12
+ def ==(other_thread)
13
+ id == other_thread.id &&
14
+ forum == other_thread.forum &&
15
+ slug == other_thread.slug &&
16
+ title == other_thread.title &&
17
+ created_at == other_thread.created_at &&
18
+ allow_comments == other_thread.allow_comments &&
19
+ url == other_thread.url &&
20
+ identifier == other_thread.identifier
21
+ end
22
+
23
+ # Returns an array of Thread objects representing the threads belonging to the given Forum.
24
+ def self.list(forum, opts = {})
25
+ response = Disqus::Api::get_thread_list(opts.merge(:forum_id =>forum.id, :forum_api_key => forum.key))
26
+ if response["succeeded"]
27
+ list = response["message"].map do |thread|
28
+ Thread.new(
29
+ thread["id"],
30
+ forum,
31
+ thread["slug"],
32
+ thread["title"],
33
+ thread["created_at"],
34
+ thread["allow_comments"],
35
+ thread["url"],
36
+ thread["identifier"]
37
+ )
38
+ end
39
+ end
40
+ end
41
+
42
+ # Returns an array of posts belonging to this thread.
43
+ def posts(force_update = false)
44
+ if (@posts.nil? or @posts.empty? or force_update)
45
+ @posts = Disqus::Post.list(self)
46
+ end
47
+ @posts
48
+ end
49
+
50
+ # Sets the provided values on the thread object.
51
+ #
52
+ # Options:
53
+ #
54
+ # * :thread_id
55
+ # * :title
56
+ # * :slug
57
+ # * :url
58
+ # * :allow_comments
59
+ def update(opts = {})
60
+ result = Disqus::Api::update_thread(opts.merge(
61
+ :forum_api_key => forum.key,
62
+ :thread_id => id,
63
+ :title => title,
64
+ :slug => slug,
65
+ :url => url,
66
+ :allow_comments => allow_comments)
67
+ )
68
+ return result["succeeded"]
69
+ end
70
+
71
+ end
72
+
73
+ end
@@ -0,0 +1,8 @@
1
+ module Disqus
2
+ module Version
3
+ MAJOR = 1
4
+ MINOR = 0
5
+ TINY = 3
6
+ STRING = [MAJOR, MINOR, TINY].join('.')
7
+ end
8
+ end
@@ -0,0 +1,9 @@
1
+ # Shortcuts to access the widgets as simple functions as opposed to using
2
+ # their full qualified names.
3
+ %w[combo comment_counts popular_threads recent_comments thread top_commenters].each do |method|
4
+ eval(<<-EOM)
5
+ def disqus_#{method}(options = {})
6
+ Disqus::Widget.#{method}(options)
7
+ end
8
+ EOM
9
+ end
@@ -0,0 +1,185 @@
1
+ module Disqus
2
+
3
+ # Disqus Widget generator.
4
+ #
5
+ # All of the methods accept various options, and "account" is required for
6
+ # all of them. You can avoid having to pass in the account each time by
7
+ # setting it in the defaults like this:
8
+ #
9
+ # Disqus::defaults[:account] = "my_account"
10
+ class Widget
11
+
12
+ VALID_COLORS = ['blue', 'grey', 'green', 'red', 'orange']
13
+ VALID_NUM_ITEMS = 5..20
14
+ VALID_DEFAULT_TABS = ['people', 'recent', 'popular']
15
+ VALID_AVATAR_SIZES = [24, 32, 48, 92, 128]
16
+ VALID_ORIENTATIONS = ['horizontal', 'vertical']
17
+
18
+ ROOT_PATH = 'http://disqus.com/forums/%s/'
19
+ THREAD = ROOT_PATH + 'embed.js'
20
+ COMBO = ROOT_PATH + 'combination_widget.js?num_items=%d&color=%s&default_tab=%s'
21
+ RECENT = ROOT_PATH + 'recent_comments_widget.js?num_items=%d&avatar_size=%d'
22
+ POPULAR = ROOT_PATH + 'popular_threads_widget.js?num_items=%d'
23
+ TOP = ROOT_PATH + 'top_commenters_widget.js?num_items=%d&avatar_size=%d&orientation=%s'
24
+ class << self
25
+
26
+ # Show the main Disqus thread widget.
27
+ # Options:
28
+ # * <tt>account:</tt> Your Discus account (required).
29
+ def thread(opts = {})
30
+ opts = Disqus::defaults.merge(opts)
31
+ opts[:view_thread_text] ||= "View the discussion thread"
32
+ validate_opts!(opts)
33
+ s = ''
34
+ if opts[:developer]
35
+ s << '<script type="text/javascript">var disqus_developer = 1;</script>'
36
+ end
37
+ s << '<div id="disqus_thread"></div>'
38
+ s << '<script type="text/javascript" src="' + THREAD + '"></script>'
39
+ s << '<noscript><a href="http://%s.disqus.com/?url=ref">'
40
+ s << opts[:view_thread_text]
41
+ s << '</a></noscript>'
42
+ if opts[:show_powered_by]
43
+ s << '<a href="http://disqus.com" class="dsq-brlink">blog comments '
44
+ s << 'powered by <span class="logo-disqus">Disqus</span></a>'
45
+ end
46
+ s % [opts[:account], opts[:account]]
47
+ end
48
+
49
+ # Loads Javascript to show the number of comments for the page.
50
+ #
51
+ # The Javascript sets the inner html to the comment count for any links
52
+ # on the page that have the anchor "disqus_thread". For example, "View
53
+ # Comments" below would be replaced by "1 comment" or "23 comments" etc.
54
+ #
55
+ # <a href="http://my.website/article-permalink#disqus_thread">View Comments</a>
56
+ # <a href="http://my.website/different-permalink#disqus_thread">View Comments</a>
57
+ # Options:
58
+ # * <tt>account:</tt> Your Discus account (required).
59
+ def comment_counts(opts = {})
60
+ opts = Disqus::defaults.merge(opts)
61
+ validate_opts!(opts)
62
+ s = <<-WHIMPER
63
+ <script type="text/javascript">
64
+ //<![CDATA[
65
+ (function() {
66
+ var links = document.getElementsByTagName('a');
67
+ var query = '?';
68
+ for(var i = 0; i < links.length; i++) {
69
+ if(links[i].href.indexOf('#disqus_thread') >= 0) {
70
+ query += 'url' + i + '=' + encodeURIComponent(links[i].href) + '&';
71
+ }
72
+ }
73
+ document.write('<' + 'script type="text/javascript" src="#{ROOT_PATH}get_num_replies.js' + query + '"></' + 'script>');
74
+ })();
75
+ //]]>
76
+ </script>
77
+ WHIMPER
78
+ s % opts[:account]
79
+ end
80
+
81
+ # Show the top commenters Disqus thread widget.
82
+ # Options:
83
+ # * <tt>account:</tt> Your Discus account (required).
84
+ # * <tt>header:</tt> HTML snipper with header (default h2) tag and text.
85
+ # * <tt>show_powered_by:</tt> Show or hide the powered by Disqus text.
86
+ # * <tt>num_items:</tt>: How many items to show.
87
+ # * <tt>hide_mods:</tt> Don't show moderators.
88
+ # * <tt>hide_avatars:</tt> Don't show avatars.
89
+ # * <tt>avatar_size:</tt> Avatar size.
90
+ def top_commenters(opts = {})
91
+ opts = Disqus::defaults.merge(opts)
92
+ opts[:header] ||= '<h2 class="dsq-widget-title">Top Commenters</h2>'
93
+ validate_opts!(opts)
94
+ s = '<div id="dsq-topcommenters" class="dsq-widget">'
95
+ s << opts[:header]
96
+ s << '<script type="text/javascript" src="'
97
+ s << TOP
98
+ s << '&hide_avatars=1' if opts[:hide_avatars]
99
+ s << '&hide_mods=1' if opts[:hide_mods]
100
+ s << '"></script>'
101
+ s << '</div>'
102
+ if opts[:show_powered_by]
103
+ s << '<a href="http://disqus.com">Powered by Disqus</a>'
104
+ end
105
+ s % [opts[:account], opts[:num_items], opts[:avatar_size], opts[:orientation]]
106
+ end
107
+
108
+ # Show the popular threads Disqus widget.
109
+ # Options:
110
+ # * <tt>account:</tt> Your Discus account (required).
111
+ # * <tt>header:</tt> HTML snipper with header (default h2) tag and text.
112
+ # * <tt>num_items:</tt>: How many items to show.
113
+ # * <tt>hide_mods:</tt> Don't show moderators.
114
+ def popular_threads(opts = {})
115
+ opts = Disqus::defaults.merge(opts)
116
+ opts[:header] ||= '<h2 class="dsq-widget-title">Popular Threads</h2>'
117
+ validate_opts!(opts)
118
+ s = '<div id="dsq-popthreads" class="dsq-widget">'
119
+ s << opts[:header]
120
+ s << '<script type="text/javascript" src="'
121
+ s << POPULAR
122
+ s << '&hide_mods=1' if opts[:hide_mods]
123
+ s << '"></script>'
124
+ s << '</div>'
125
+ s << '<a href="http://disqus.com">Powered by Disqus</a>' if opts[:show_powered_by]
126
+ s % [opts[:account], opts[:num_items]]
127
+ end
128
+
129
+ # Show the recent comments Disqus widget.
130
+ # Options:
131
+ # * <tt>account:</tt> Your Discus account (required).
132
+ # * <tt>header:</tt> HTML snipper with header (default h2) tag and text.
133
+ # * <tt>num_items:</tt>: How many items to show.
134
+ # * <tt>hide_avatars:</tt> Don't show avatars.
135
+ # * <tt>avatar_size:</tt> Avatar size.
136
+ def recent_comments(opts = {})
137
+ opts = Disqus::defaults.merge(opts)
138
+ opts[:header] ||= '<h2 class="dsq-widget-title">Recent Comments</h2>'
139
+ validate_opts!(opts)
140
+ s = '<div id="dsq-recentcomments" class="dsq-widget">'
141
+ s << opts[:header]
142
+ s << '<script type="text/javascript" src="'
143
+ s << RECENT
144
+ s << '&hide_avatars=1' if opts[:hide_avatars]
145
+ s << '"></script>'
146
+ s << '</div>'
147
+ if opts[:show_powered_by]
148
+ s << '<a href="http://disqus.com">Powered by Disqus</a>'
149
+ end
150
+ s % [opts[:account], opts[:num_items], opts[:avatar_size]]
151
+ end
152
+
153
+ # Show the Disqus combo widget. This is a three-tabbed box with links
154
+ # popular threads, top posters, and recent threads.
155
+ # Options:
156
+ # * <tt>:account:</tt> Your Discus account (required).
157
+ # * <tt>:num_items:</tt> How many items to show.
158
+ # * <tt>:hide_mods:</tt> Don't show moderators.
159
+ # * <tt>:default_tab:</tt> Should be 'people', 'recent', or 'popular'.
160
+ def combo(opts = {})
161
+ opts = Disqus::defaults.merge(opts)
162
+ validate_opts!(opts)
163
+ s = '<script type="text/javascript" src="'
164
+ s << COMBO
165
+ s << '&hide_mods=1' if opts[:hide_mods]
166
+ s << '"></script>'
167
+ s % [opts[:account], opts[:num_items], opts[:color], opts[:default_tab]]
168
+ end
169
+
170
+ private
171
+
172
+ def validate_opts!(opts)
173
+ raise ArgumentError.new("You must specify an :account") if !opts[:account]
174
+ raise ArgumentError.new("Invalid color") if opts[:color] && !VALID_COLORS.include?(opts[:color])
175
+ raise ArgumentError.new("Invalid num_items") if opts[:num_items] && !VALID_NUM_ITEMS.include?(opts[:num_items])
176
+ raise ArgumentError.new("Invalid default_tab") if opts[:default_tab] && !VALID_DEFAULT_TABS.include?(opts[:default_tab])
177
+ raise ArgumentError.new("Invalid avatar size") if opts[:avatar_size] && !VALID_AVATAR_SIZES.include?(opts[:avatar_size])
178
+ raise ArgumentError.new("Invalid orientation") if opts[:orientation] && !VALID_ORIENTATIONS.include?(opts[:orientation])
179
+ end
180
+
181
+ end
182
+
183
+ end
184
+
185
+ end
data/lib/disqus.rb ADDED
@@ -0,0 +1,52 @@
1
+ %w[api author forum post thread version view_helpers widget].each do |file|
2
+ require File.join(File.dirname(__FILE__), "disqus", file)
3
+ end
4
+
5
+ # == From the {Disqus Website}[http://disqus.com]:
6
+
7
+ # "Disqus, pronounced "discuss", is a service and tool for web comments and
8
+ # discussions. The Disqus comment system can be plugged into any website, blog,
9
+ # or application. Disqus makes commenting easier and more interactive, while
10
+ # connecting websites and commenters across a thriving discussion community."
11
+ #
12
+ # "Disqus is a free service to the general public with absolutely no inline
13
+ # advertisements."
14
+
15
+ # The Disqus gem helps you quickly and easily integrate Disqus's Javascript
16
+ # widgets into your Ruby-based website. Adding Disqus to your site literally
17
+ # takes only a few minutes. The Disqus gem also provides a complete
18
+ # implementation of the Disqus API for more complex applications.
19
+
20
+ # To use this code, please first create an account on Disqus[http://disqus.com].
21
+ module Disqus
22
+
23
+ @defaults = {
24
+ :api_key => "",
25
+ :account => "",
26
+ :developer => false,
27
+ :container_id => 'disqus_thread',
28
+ :avatar_size => 48,
29
+ :color => "grey",
30
+ :default_tab => "popular",
31
+ :hide_avatars => false,
32
+ :hide_mods => true,
33
+ :num_items => 15,
34
+ :show_powered_by => true,
35
+ :orientation => "horizontal"
36
+ }
37
+
38
+ # Disqus defaults:
39
+ # :account => "",
40
+ # :avatar_size => 48,
41
+ # :color => "grey",
42
+ # :default_tab => "popular",
43
+ # :hide_avatars => false,
44
+ # :hide_mods => true,
45
+ # :num_items => 15,
46
+ # :show_powered_by => true,
47
+ # :orientation => "horizontal"
48
+ def self.defaults
49
+ @defaults
50
+ end
51
+
52
+ end
data/test/api_test.rb ADDED
@@ -0,0 +1,79 @@
1
+ require File.dirname(__FILE__) + '/test_helper'
2
+
3
+ class ApiTest < Test::Unit::TestCase
4
+
5
+ def setup
6
+ Disqus.defaults[:api_key] = DISQUS_TEST["api_key"]
7
+ end
8
+
9
+ def test_create_post
10
+ mock_post_response('create_post.json')
11
+ the_post = Disqus::Api::create_post()
12
+ assert_equal "This is a mock post", the_post["message"]["message"]
13
+ end
14
+
15
+ def test_get_forum_list
16
+ mock_get_response('get_forum_list.json')
17
+ forum_list = Disqus::Api::get_forum_list
18
+ assert_equal "Disqus Test", forum_list["message"][0]["name"]
19
+ end
20
+
21
+ def test_get_forum_api_key
22
+ mock_get_response('get_forum_api_key.json')
23
+ forum_api_key = Disqus::Api::get_forum_api_key(:forum_id => 1234, :user_api_key=>"FAKE_KEY")
24
+ assert_equal "FAKE_FORUM_API_KEY", forum_api_key["message"]
25
+ end
26
+
27
+ def test_get_thread_list
28
+ mock_get_response('get_thread_list.json')
29
+ thread_list = Disqus::Api::get_thread_list(:forum_api_key=>"FAKE_KEY")
30
+ assert_equal "this_is_the_thread_identifier", thread_list["message"].first["identifier"]
31
+ end
32
+
33
+ def test_get_num_posts
34
+ mock_get_response('get_num_posts.json')
35
+ nums = Disqus::Api::get_num_posts(:thread_ids => [123,456], :forum_api_key=>"FAKE_KEY")
36
+ assert_equal [10,12], nums["message"][nums["message"].keys.first]
37
+ end
38
+
39
+ def test_get_thread_by_url
40
+ mock_get_response('get_thread_by_url.json')
41
+ thread = Disqus::Api::get_thread_by_url(:url => "FAKE_URL", :forum_api_key=>"FAKE_KEY")
42
+ assert_equal "test_thread", thread["message"]["slug"]
43
+ end
44
+
45
+ def test_get_thread_posts
46
+ mock_get_response('get_thread_posts.json')
47
+ thread_posts = Disqus::Api::get_thread_posts(:thread_id =>1234, :forum_api_key => "FAKE_KEY")
48
+ assert_equal "This is a mock post", thread_posts["message"].first["message"]
49
+ end
50
+
51
+ def test_thread_by_identifier
52
+ mock_post_response('thread_by_identifier.json')
53
+ thread = Disqus::Api::thread_by_identifier(:identifier =>'foo_bar', :title => "Foo Bar", :forum_api_key => "FAKE_KEY")
54
+ assert_equal "Test thread", thread["message"]["thread"]["title"]
55
+ end
56
+
57
+ def test_update_thread
58
+ mock_post_response('update_thread.json')
59
+ result = Disqus::Api::thread_by_identifier(:thread_id =>123, :title => "Foo Bar", :forum_api_key => "FAKE_KEY")
60
+ assert result["succeeded"]
61
+ end
62
+
63
+ def test_comment_form
64
+ c = Disqus::Api::comment_form("myforum", "mythread")
65
+ assert_match(/myforum/, c)
66
+ assert_match(/mythread/, c)
67
+ end
68
+
69
+ private
70
+
71
+ def mock_get_response(file)
72
+ Disqus::Api.expects(:get).returns(File.read(File.dirname(__FILE__) + "/responses/#{file}"))
73
+ end
74
+
75
+ def mock_post_response(file)
76
+ Disqus::Api.expects(:post).returns(File.read(File.dirname(__FILE__) + "/responses/#{file}"))
77
+ end
78
+
79
+ end