redd 0.4.3 → 0.5.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 +4 -4
- data/README.md +7 -12
- data/lib/redd.rb +0 -12
- data/lib/redd/base.rb +10 -6
- data/lib/redd/client/authenticated.rb +2 -1
- data/lib/redd/client/authenticated/account.rb +2 -0
- data/lib/redd/client/authenticated/apps.rb +1 -0
- data/lib/redd/client/authenticated/flair.rb +33 -7
- data/lib/redd/client/authenticated/gold.rb +1 -0
- data/lib/redd/client/authenticated/links_comments.rb +86 -10
- data/lib/redd/client/authenticated/live.rb +1 -0
- data/lib/redd/client/authenticated/moderation.rb +65 -16
- data/lib/redd/client/authenticated/multis.rb +1 -1
- data/lib/redd/client/authenticated/private_messages.rb +50 -4
- data/lib/redd/client/authenticated/subreddits.rb +28 -0
- data/lib/redd/client/authenticated/users.rb +1 -1
- data/lib/redd/client/authenticated/wiki.rb +1 -1
- data/lib/redd/client/oauth2.rb +2 -2
- data/lib/redd/client/oauth2/authorization.rb +44 -11
- data/lib/redd/client/oauth2/identity.rb +4 -0
- data/lib/redd/client/unauthenticated/account.rb +13 -1
- data/lib/redd/client/unauthenticated/captcha.rb +7 -0
- data/lib/redd/client/unauthenticated/links_comments.rb +23 -4
- data/lib/redd/client/unauthenticated/listing.rb +43 -25
- data/lib/redd/client/unauthenticated/live.rb +1 -0
- data/lib/redd/client/unauthenticated/moderation.rb +9 -1
- data/lib/redd/client/unauthenticated/subreddits.rb +30 -0
- data/lib/redd/client/unauthenticated/utilities.rb +7 -4
- data/lib/redd/client/unauthenticated/wiki.rb +18 -4
- data/lib/redd/error.rb +5 -3
- data/lib/redd/oauth2_access.rb +21 -3
- data/lib/redd/object/more_comments.rb +1 -0
- data/lib/redd/object/private_message.rb +2 -1
- data/lib/redd/object/submission.rb +4 -0
- data/lib/redd/object/user.rb +1 -0
- data/lib/redd/response/raise_error.rb +2 -1
- data/lib/redd/thing/editable.rb +1 -0
- data/lib/redd/thing/hideable.rb +1 -0
- data/lib/redd/thing/inboxable.rb +1 -0
- data/lib/redd/thing/messageable.rb +2 -8
- data/lib/redd/thing/moderatable.rb +1 -0
- data/lib/redd/thing/reportable.rb +1 -0
- data/lib/redd/thing/saveable.rb +1 -0
- data/lib/redd/thing/voteable.rb +1 -1
- data/lib/redd/version.rb +1 -1
- data/spec/redd/client/unauthenticated_spec.rb +1 -1
- data/spec/redd/rate_limit_spec.rb +5 -5
- data/spec/redd_spec.rb +1 -1
- data/spec/spec_helper.rb +1 -1
- metadata +2 -3
- data/github/redd.png +0 -0
@@ -1,32 +1,78 @@
|
|
1
1
|
module Redd
|
2
2
|
module Client
|
3
3
|
class Authenticated
|
4
|
+
# Methods for sending and reading private messages
|
4
5
|
module PrivateMessages
|
6
|
+
# Block the sender of the message from sending any more.
|
7
|
+
#
|
8
|
+
# @param message [Redd::Object::PrivateMessage, String] The message
|
9
|
+
# whose sender to block.
|
5
10
|
def block_message(message)
|
6
11
|
fullname = extract_fullname(message)
|
7
12
|
post "/api/block", id: fullname
|
8
13
|
end
|
9
14
|
|
15
|
+
# Compose a message to a person or the moderators of a subreddit.
|
16
|
+
#
|
17
|
+
# @param to [Redd::Object::User, Redd::Object::Subreddit, String] The
|
18
|
+
# thing to send a message to.
|
19
|
+
# @param subject [String] The subject of the message.
|
20
|
+
# @param text [String] The message text.
|
21
|
+
# @param captcha [String] A possible captcha result to send if one
|
22
|
+
# is required.
|
23
|
+
# @param identifier [String] The identifier for the captcha if one
|
24
|
+
# is required.
|
10
25
|
def compose_message(to, subject, text, captcha = nil, identifier = nil)
|
11
|
-
params =
|
12
|
-
|
13
|
-
|
26
|
+
params[:to] =
|
27
|
+
case to
|
28
|
+
when Redd::Object::User
|
29
|
+
to.name
|
30
|
+
when Redd::Object::Subreddit
|
31
|
+
to.display_name
|
32
|
+
when String
|
33
|
+
to
|
34
|
+
end
|
35
|
+
|
36
|
+
params = {api_type: "json", subject: subject, text: text}
|
14
37
|
params << {captcha: captcha, iden: identifier} if captcha
|
15
38
|
|
16
39
|
post "/api/compose", params
|
17
40
|
end
|
18
41
|
|
42
|
+
# Mark a message as read.
|
43
|
+
#
|
44
|
+
# @param message [Redd::Object::PrivateMessage, String] The message
|
45
|
+
# to mark as read.
|
19
46
|
def mark_as_read(message)
|
20
47
|
fullname = extract_fullname(message)
|
21
48
|
post "/api/read_message", id: fullname
|
22
49
|
end
|
23
50
|
|
51
|
+
# Mark a message as unread.
|
52
|
+
#
|
53
|
+
# @param message [Redd::Object::PrivateMessage, String] The message
|
54
|
+
# to mark as unread.
|
24
55
|
def mark_as_unread(message)
|
25
56
|
fullname = extract_fullname(message)
|
26
57
|
post "/api/unread_message", id: fullname
|
27
58
|
end
|
28
59
|
|
29
|
-
|
60
|
+
# Return a list of a user's private messages.
|
61
|
+
#
|
62
|
+
# @param category [String] The category of messages to view.
|
63
|
+
# @param mark [Boolean] Whether to remove the orangered from the
|
64
|
+
# user's inbox.
|
65
|
+
# @param params [Hash] A list of params to send with the request.
|
66
|
+
# @option params [String] :after Return results after the given
|
67
|
+
# fullname.
|
68
|
+
# @option params [String] :before Return results before the given
|
69
|
+
# fullname.
|
70
|
+
# @option params [Integer] :count (0) The number of items already seen
|
71
|
+
# in the listing.
|
72
|
+
# @option params [1..100] :limit (25) The maximum number of things to
|
73
|
+
# return.
|
74
|
+
def messages(category = "inbox", mark = false, params = {})
|
75
|
+
params[:mark] = mark
|
30
76
|
object_from_response :get, "/message/#{category}.json", params
|
31
77
|
end
|
32
78
|
end
|
@@ -1,15 +1,38 @@
|
|
1
1
|
module Redd
|
2
2
|
module Client
|
3
3
|
class Authenticated
|
4
|
+
# Methods to interact with subreddits
|
4
5
|
module Subreddits
|
6
|
+
# Subscribe to a subreddit.
|
7
|
+
#
|
8
|
+
# @param subreddit [Redd::Object::Subreddit, String] The subreddit to
|
9
|
+
# subscribe to.
|
5
10
|
def subscribe(subreddit)
|
6
11
|
edit_subscription(:sub, subreddit)
|
7
12
|
end
|
8
13
|
|
14
|
+
# Unsubscribe from a subreddit.
|
15
|
+
#
|
16
|
+
# @param subreddit [Redd::Object::Subreddit, String] The subreddit to
|
17
|
+
# unsubscribe from.
|
9
18
|
def unsubscribe(subreddit)
|
10
19
|
edit_subscription(:unsub, subreddit)
|
11
20
|
end
|
12
21
|
|
22
|
+
# Get a listing of subreddits.
|
23
|
+
#
|
24
|
+
# @param where [:popular, :new, :subscriber, :contributor, :moderator]
|
25
|
+
# The order of subreddits to return.
|
26
|
+
# @param params [Hash] A list of params to send with the request.
|
27
|
+
# @option params [String] :after Return results after the given
|
28
|
+
# fullname.
|
29
|
+
# @option params [String] :before Return results before the given
|
30
|
+
# fullname.
|
31
|
+
# @option params [Integer] :count (0) The number of items already seen
|
32
|
+
# in the listing.
|
33
|
+
# @option params [1..100] :limit (25) The maximum number of things to
|
34
|
+
# return.
|
35
|
+
# @return [Redd::Object::Listing] A listing of subreddits.
|
13
36
|
def get_subreddits(where = :subscriber, params = {})
|
14
37
|
path =
|
15
38
|
if [:popular, :new].include?(where)
|
@@ -22,6 +45,11 @@ module Redd
|
|
22
45
|
|
23
46
|
private
|
24
47
|
|
48
|
+
# Subscribe or unsubscribe to a subreddit.
|
49
|
+
#
|
50
|
+
# @param action [:sub, :unsub] The type of action to perform.
|
51
|
+
# @param subreddit [Redd::Object::Subreddit, String] The subreddit to
|
52
|
+
# perform the action on.
|
25
53
|
def edit_subscription(action, subreddit)
|
26
54
|
fullname = extract_fullname(subreddit)
|
27
55
|
post "/api/subscribe", action: action, sr: fullname
|
data/lib/redd/client/oauth2.rb
CHANGED
@@ -44,14 +44,14 @@ module Redd
|
|
44
44
|
|
45
45
|
private
|
46
46
|
|
47
|
-
def connection
|
47
|
+
def connection
|
48
48
|
@connection ||= Faraday.new(url: api_endpoint) do |faraday|
|
49
49
|
faraday.use Faraday::Request::UrlEncoded
|
50
50
|
faraday.use Redd::Response::RaiseError
|
51
51
|
faraday.use Redd::Response::ParseJson
|
52
52
|
faraday.adapter Faraday.default_adapter
|
53
53
|
|
54
|
-
faraday.headers["Authorization"] = "bearer #{access_token}"
|
54
|
+
faraday.headers["Authorization"] = "bearer #{@access.access_token}"
|
55
55
|
faraday.headers["User-Agent"] = "Redd/Ruby, v#{Redd::VERSION}"
|
56
56
|
end
|
57
57
|
end
|
@@ -3,40 +3,73 @@ require "redd/oauth2_access"
|
|
3
3
|
module Redd
|
4
4
|
module Client
|
5
5
|
class OAuth2
|
6
|
+
# Methods for obtaining an access token
|
6
7
|
module Authorization
|
7
|
-
|
8
|
+
# Build an authorization url to redirect the user to.
|
9
|
+
#
|
10
|
+
# @param scopes [Array<String>] The access scopes to request from the
|
11
|
+
# user.
|
12
|
+
# @param duration [:temporary, :permanent] The duration of your access
|
13
|
+
# to the user's account.
|
14
|
+
# @param state [String] A random string to check later.
|
15
|
+
# @return [String] The url.
|
16
|
+
#
|
17
|
+
# @note The access tokens from both duration last only an hour, but you
|
18
|
+
# also get a refresh token when the duration is permanent.
|
19
|
+
# @note You may be tempted to let the state remain "x", but seriously,
|
20
|
+
# use this; it helps prevent against CSRF attacks.
|
21
|
+
def auth_url(scopes = ["identity"], duration = :temporary, state = "x")
|
8
22
|
path = "https://ssl.reddit.com/api/v1/authorize"
|
23
|
+
scope = scopes.is_a?(Array) ? scopes.join(",") : scopes
|
9
24
|
query = {
|
10
25
|
client_id: @client_id,
|
11
26
|
redirect_uri: @redirect_uri,
|
12
27
|
response_type: "code",
|
13
28
|
state: state,
|
14
|
-
scope: scope
|
29
|
+
scope: scope,
|
15
30
|
duration: duration
|
16
31
|
}
|
17
32
|
string_query = query.map { |key, value| "#{key}=#{value}" }.join("&")
|
18
|
-
|
19
33
|
"#{path}?#{string_query}"
|
20
34
|
end
|
21
35
|
|
22
|
-
|
36
|
+
# Request an access token from the code that is sent with the redirect.
|
37
|
+
#
|
38
|
+
# @param code [String] The code that was sent in the GET request.
|
39
|
+
# @param set_access [Boolean] Whether to automatically use this token
|
40
|
+
# for all future requests with this client.
|
41
|
+
# @return [Redd::OAuth2Access] A package of the necessary information
|
42
|
+
# to access the user's information.
|
43
|
+
def request_access(code, set_access = true)
|
23
44
|
response = auth_connection.post "/api/v1/access_token",
|
24
|
-
|
25
|
-
|
45
|
+
grant_type: "authorization_code",
|
46
|
+
code: code,
|
47
|
+
redirect_uri: @redirect_uri
|
26
48
|
|
27
49
|
access = Redd::OAuth2Access.new(response.body)
|
28
50
|
@access = access if set_access
|
29
51
|
access
|
30
52
|
end
|
31
53
|
|
32
|
-
|
33
|
-
|
54
|
+
# Obtain a new access token using a refresh token.
|
55
|
+
#
|
56
|
+
# @param token [Redd::OAuth2Access, String, nil] The refresh token or
|
57
|
+
# OAuth2Access. If none is provided, it'll refresh the one the client
|
58
|
+
# is currently using.
|
59
|
+
# @param set_access [Boolean] Whether to automatically use this token
|
60
|
+
# for all future requests with this client.
|
61
|
+
# @return [Redd::OAuth2Access] The refreshed information.
|
62
|
+
def refresh_access(token = nil, set_access = true)
|
63
|
+
refresh_token = extract_attribute(token, :refresh_token)
|
34
64
|
response = auth_connection.post "/api/v1/access_token",
|
35
|
-
|
65
|
+
grant_type: "refresh_token",
|
66
|
+
refresh_token: refresh_token
|
36
67
|
|
37
|
-
case
|
38
|
-
when
|
68
|
+
case token
|
69
|
+
when nil
|
39
70
|
access.refresh(response.body)
|
71
|
+
when Redd::OAuth2Access
|
72
|
+
token.refresh(response.body)
|
40
73
|
when ::String
|
41
74
|
new_access = Redd::OAuth2Access.new(response.body)
|
42
75
|
@access = new_access if set_access
|
@@ -1,7 +1,11 @@
|
|
1
1
|
module Redd
|
2
2
|
module Client
|
3
3
|
class OAuth2
|
4
|
+
# Methods to interact with the user logged-in via OAuth2
|
4
5
|
module Identity
|
6
|
+
# @return [Redd::Object::User] The logged-in user.
|
7
|
+
# @note This overrides the Authenticated class's method, since that
|
8
|
+
# method doesn't apply here but does the same thing.
|
5
9
|
def me
|
6
10
|
response = get "/api/v1/me.json"
|
7
11
|
object_from_body kind: "t2", data: response
|
@@ -1,10 +1,22 @@
|
|
1
1
|
module Redd
|
2
2
|
module Client
|
3
3
|
class Unauthenticated
|
4
|
+
# Methods for managing accounts.
|
4
5
|
module Account
|
6
|
+
# Login to the reddit account.
|
7
|
+
#
|
8
|
+
# @param username [String] The username.
|
9
|
+
# @param password [String] The password.
|
10
|
+
# @param remember [Boolean] Indicates whether you intend to use the
|
11
|
+
# returned cookie for a long time.
|
12
|
+
# @param options [Hash] The options to create an instance of
|
13
|
+
# {Redd::Client::Authenticated}.
|
5
14
|
def login(username, password, remember = false, options = {})
|
6
15
|
response = post "/api/login",
|
7
|
-
|
16
|
+
api_type: "json",
|
17
|
+
user: username,
|
18
|
+
passwd: password,
|
19
|
+
rem: remember
|
8
20
|
data = response[:json][:data]
|
9
21
|
|
10
22
|
require "redd/client/authenticated"
|
@@ -1,16 +1,23 @@
|
|
1
1
|
module Redd
|
2
2
|
module Client
|
3
3
|
class Unauthenticated
|
4
|
+
# Methods to get captchas.
|
5
|
+
# Many things like sending messages and posting links require captchas.
|
4
6
|
module Captcha
|
7
|
+
# @return [Boolean] Whether a captcha is required for some API methods.
|
5
8
|
def needs_captcha?
|
6
9
|
get "/api/needs_captcha.json"
|
7
10
|
end
|
8
11
|
|
12
|
+
# Create a new captcha identifier.
|
13
|
+
# @return [String] The identifier.
|
9
14
|
def new_captcha
|
10
15
|
response = get "/api/new_captcha", api_type: "json"
|
11
16
|
response[:json][:data][:iden]
|
12
17
|
end
|
13
18
|
|
19
|
+
# @param identifier [String] The captcha identifier.
|
20
|
+
# @return The url for the captcha image.
|
14
21
|
def captcha_url(identifier)
|
15
22
|
"http://www.reddit.com/captcha/#{identifier}.png"
|
16
23
|
end
|
@@ -2,20 +2,37 @@ module Redd
|
|
2
2
|
module Client
|
3
3
|
class Unauthenticated
|
4
4
|
module LinksComments
|
5
|
+
# @param params [Hash] A hash of parameters to send to reddit.
|
6
|
+
# @option params [String] :id The fullname of a thing.
|
7
|
+
# @option params [String] :url The url of a thing. If an id is also
|
8
|
+
# provided, the id will take precedence.
|
9
|
+
# @return [Redd::Object::Submission, Redd::Object::Comment] The object.
|
10
|
+
#
|
5
11
|
# @note Reddit does accept a subreddit, but with fullnames and urls, I
|
6
12
|
# assumed that was unnecessary.
|
7
13
|
def get_info(params = {})
|
8
|
-
object_from_response :get, "/api/info.json", params
|
14
|
+
object = object_from_response :get, "/api/info.json", params
|
15
|
+
object.first
|
9
16
|
end
|
10
17
|
|
18
|
+
# Get the comments for a submission.
|
19
|
+
#
|
20
|
+
# @param submission [String, Redd::Object::Submission] The submission
|
21
|
+
# to get the comments for.
|
22
|
+
# @return [Redd::Object::Listing] A listing of comments.
|
11
23
|
def submission_comments(submission)
|
12
24
|
id = extract_id(submission)
|
13
25
|
comments_from_response :get, "/comments/#{id}.json"
|
14
26
|
end
|
15
27
|
|
28
|
+
# Get the replies for a comment.
|
29
|
+
#
|
30
|
+
# @param comment [String, Redd::Object::Submission] The comment to get
|
31
|
+
# the replies for.
|
32
|
+
# @return [Redd::Object::Listing] A listing of comments.
|
16
33
|
def get_replies(comment)
|
17
34
|
replies = comment.attributes[:replies]
|
18
|
-
return [] unless replies.is_a?(Hash)
|
35
|
+
return [] unless replies.is_a?(Hash) && replies.key?(:kind)
|
19
36
|
object_from_body(replies)
|
20
37
|
end
|
21
38
|
|
@@ -30,8 +47,10 @@ module Redd
|
|
30
47
|
get_info(id: parent_id).first.link_id
|
31
48
|
end
|
32
49
|
|
33
|
-
response = post "/api/morechildren",
|
34
|
-
|
50
|
+
response = post "/api/morechildren",
|
51
|
+
api_type: "json",
|
52
|
+
link_id: link_id,
|
53
|
+
children: morecomments.children.join(",")
|
35
54
|
comments = response[:json][:data][:things]
|
36
55
|
|
37
56
|
# No idea how to increase the depth of the comments.
|
@@ -1,38 +1,56 @@
|
|
1
1
|
module Redd
|
2
2
|
module Client
|
3
3
|
class Unauthenticated
|
4
|
+
# Methods that return a listing
|
4
5
|
module Listing
|
5
|
-
|
6
|
-
|
7
|
-
|
6
|
+
# Get an object based on its id.
|
7
|
+
#
|
8
|
+
# @param fullname [String] The fullname of a thing.
|
9
|
+
# @return [Redd::Object] The object with the id.
|
10
|
+
def by_id(fullname)
|
11
|
+
object_from_response :get, "/by_id/#{fullname}.json"
|
8
12
|
end
|
9
13
|
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
def get_controversial(*args)
|
27
|
-
get_listing(:controversial, *args)
|
28
|
-
end
|
29
|
-
|
30
|
-
def get_comments(*args)
|
31
|
-
get_listing(:comments, *args)
|
14
|
+
# @!method get_hot
|
15
|
+
# @!method get_new
|
16
|
+
# @!method get_random
|
17
|
+
# @!method get_top
|
18
|
+
# @!method get_controversial
|
19
|
+
# @!method get_comments
|
20
|
+
#
|
21
|
+
# Get the appropriate listing.
|
22
|
+
# @param subreddit [Redd::Object::Subreddit] The subreddit to query.
|
23
|
+
# @param params [Hash] A list of params to send with the request.
|
24
|
+
#
|
25
|
+
# @see #get_listing
|
26
|
+
%w(hot new random top controversial comments).each do |sort|
|
27
|
+
define_method :"get_#{sort}" do |subreddit = nil, params = {}|
|
28
|
+
get_listing(sort, subreddit, params)
|
29
|
+
end
|
32
30
|
end
|
33
31
|
|
34
32
|
private
|
35
33
|
|
34
|
+
# Get the front page of reddit or a subreddit sorted by type.
|
35
|
+
#
|
36
|
+
# @param type [:hot, :new, :random, :top, :controversial, :comments]
|
37
|
+
# The type of listing to return
|
38
|
+
# @param subreddit [Redd::Object::Subreddit, String] The subreddit to
|
39
|
+
# query.
|
40
|
+
# @param params [Hash] A list of params to send with the request.
|
41
|
+
# @option params [String] :after Return results after the given
|
42
|
+
# fullname.
|
43
|
+
# @option params [String] :before Return results before the given
|
44
|
+
# fullname.
|
45
|
+
# @option params [Integer] :count (0) The number of items already seen
|
46
|
+
# in the listing.
|
47
|
+
# @option params [1..100] :limit (25) The maximum number of things to
|
48
|
+
# return.
|
49
|
+
# @option params [:hour, :day, :week, :month, :year, :all] :t The
|
50
|
+
# time period to consider when sorting.
|
51
|
+
# @return [Redd::Object::Listing] A listing of submissions or comments.
|
52
|
+
#
|
53
|
+
# @note The option :t only applies to the top and controversial sorts.
|
36
54
|
def get_listing(type, subreddit = nil, params = {})
|
37
55
|
name = extract_attribute(subreddit, :display_name) if subreddit
|
38
56
|
|