redd 0.6.5 → 0.7.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/.gitignore +34 -33
- data/.rspec +3 -4
- data/.rubocop.yml +5 -5
- data/.travis.yml +9 -7
- data/{LICENSE.md → LICENSE.txt} +22 -22
- data/README.md +126 -241
- data/Rakefile +5 -6
- data/{RedditKit.LICENSE.md → RedditKit.LICENSE.txt} +13 -13
- data/lib/redd.rb +50 -4
- data/lib/redd/access.rb +76 -0
- data/lib/redd/clients/base.rb +178 -0
- data/lib/redd/clients/base/account.rb +20 -0
- data/lib/redd/clients/base/identity.rb +22 -0
- data/lib/redd/clients/base/none.rb +27 -0
- data/lib/redd/clients/base/privatemessages.rb +28 -0
- data/lib/redd/clients/base/read.rb +66 -0
- data/lib/redd/clients/base/stream.rb +74 -0
- data/lib/redd/clients/base/submit.rb +54 -0
- data/lib/redd/clients/base/utilities.rb +80 -0
- data/lib/redd/clients/base/wikiread.rb +33 -0
- data/lib/redd/clients/installed.rb +55 -0
- data/lib/redd/clients/script.rb +37 -0
- data/lib/redd/clients/userless.rb +31 -0
- data/lib/redd/clients/web.rb +57 -0
- data/lib/redd/error.rb +138 -153
- data/lib/redd/objects/base.rb +36 -0
- data/lib/redd/objects/comment.rb +22 -0
- data/lib/redd/objects/listing.rb +29 -0
- data/lib/redd/objects/more_comments.rb +10 -0
- data/lib/redd/objects/private_message.rb +18 -0
- data/lib/redd/objects/submission.rb +72 -0
- data/lib/redd/objects/subreddit.rb +152 -0
- data/lib/redd/objects/thing.rb +33 -0
- data/lib/redd/objects/thing/editable.rb +22 -0
- data/lib/redd/objects/thing/hideable.rb +18 -0
- data/lib/redd/objects/thing/inboxable.rb +25 -0
- data/lib/redd/objects/thing/messageable.rb +34 -0
- data/lib/redd/objects/thing/moderatable.rb +43 -0
- data/lib/redd/objects/thing/refreshable.rb +14 -0
- data/lib/redd/objects/thing/saveable.rb +21 -0
- data/lib/redd/objects/thing/votable.rb +33 -0
- data/lib/redd/objects/user.rb +52 -0
- data/lib/redd/objects/wiki_page.rb +15 -0
- data/lib/redd/rate_limit.rb +50 -49
- data/lib/redd/response/parse_json.rb +17 -33
- data/lib/redd/response/raise_error.rb +16 -25
- data/lib/redd/version.rb +4 -5
- data/redd.gemspec +30 -31
- data/spec/redd/objects/base_spec.rb +1 -0
- data/spec/redd/rate_limit_spec.rb +29 -29
- data/spec/redd/response/parse_json_spec.rb +12 -0
- data/spec/redd/response/raise_error_spec.rb +11 -0
- data/spec/redd_spec.rb +7 -5
- data/spec/spec_helper.rb +69 -50
- metadata +73 -136
- data/.yardopts +0 -1
- data/lib/redd/base.rb +0 -56
- data/lib/redd/client/authenticated.rb +0 -83
- data/lib/redd/client/authenticated/account.rb +0 -13
- data/lib/redd/client/authenticated/apps.rb +0 -13
- data/lib/redd/client/authenticated/flair.rb +0 -71
- data/lib/redd/client/authenticated/gold.rb +0 -13
- data/lib/redd/client/authenticated/links_comments.rb +0 -189
- data/lib/redd/client/authenticated/live.rb +0 -13
- data/lib/redd/client/authenticated/moderation.rb +0 -126
- data/lib/redd/client/authenticated/multis.rb +0 -9
- data/lib/redd/client/authenticated/private_messages.rb +0 -73
- data/lib/redd/client/authenticated/subreddits.rb +0 -172
- data/lib/redd/client/authenticated/users.rb +0 -9
- data/lib/redd/client/authenticated/wiki.rb +0 -9
- data/lib/redd/client/oauth2.rb +0 -71
- data/lib/redd/client/oauth2/authorization.rb +0 -108
- data/lib/redd/client/oauth2/identity.rb +0 -16
- data/lib/redd/client/oauth2_script.rb +0 -24
- data/lib/redd/client/oauth2_script/authorization.rb +0 -21
- data/lib/redd/client/unauthenticated.rb +0 -118
- data/lib/redd/client/unauthenticated/account.rb +0 -30
- data/lib/redd/client/unauthenticated/captcha.rb +0 -27
- data/lib/redd/client/unauthenticated/links_comments.rb +0 -60
- data/lib/redd/client/unauthenticated/listing.rb +0 -65
- data/lib/redd/client/unauthenticated/live.rb +0 -9
- data/lib/redd/client/unauthenticated/moderation.rb +0 -26
- data/lib/redd/client/unauthenticated/subreddits.rb +0 -49
- data/lib/redd/client/unauthenticated/users.rb +0 -67
- data/lib/redd/client/unauthenticated/utilities.rb +0 -109
- data/lib/redd/client/unauthenticated/wiki.rb +0 -33
- data/lib/redd/oauth2_access.rb +0 -70
- data/lib/redd/object/comment.rb +0 -74
- data/lib/redd/object/listing.rb +0 -29
- data/lib/redd/object/more_comments.rb +0 -14
- data/lib/redd/object/private_message.rb +0 -35
- data/lib/redd/object/submission.rb +0 -94
- data/lib/redd/object/subreddit.rb +0 -74
- data/lib/redd/object/user.rb +0 -34
- data/lib/redd/object/wiki_page.rb +0 -27
- data/lib/redd/thing.rb +0 -27
- data/lib/redd/thing/commentable.rb +0 -27
- data/lib/redd/thing/editable.rb +0 -16
- data/lib/redd/thing/hideable.rb +0 -16
- data/lib/redd/thing/inboxable.rb +0 -20
- data/lib/redd/thing/messageable.rb +0 -12
- data/lib/redd/thing/moderatable.rb +0 -32
- data/lib/redd/thing/reportable.rb +0 -12
- data/lib/redd/thing/saveable.rb +0 -16
- data/lib/redd/thing/voteable.rb +0 -22
- data/spec/README.md +0 -18
- data/spec/redd/base_spec.rb +0 -36
- data/spec/redd/client/authenticated/account_spec.rb +0 -5
- data/spec/redd/client/authenticated/apps_spec.rb +0 -2
- data/spec/redd/client/authenticated/flair_spec.rb +0 -26
- data/spec/redd/client/authenticated/gold_spec.rb +0 -2
- data/spec/redd/client/authenticated/links_comments_spec.rb +0 -231
- data/spec/redd/client/authenticated/live_spec.rb +0 -2
- data/spec/redd/client/unauthenticated/account_spec.rb +0 -15
- data/spec/redd/client/unauthenticated/captcha_spec.rb +0 -23
- data/spec/redd/client/unauthenticated/links_comments_spec.rb +0 -28
- data/spec/redd/client/unauthenticated/listing_spec.rb +0 -23
- data/spec/redd/client/unauthenticated/live_spec.rb +0 -2
- data/spec/redd/client/unauthenticated/moderation_spec.rb +0 -14
- data/spec/redd/client/unauthenticated/subreddits_spec.rb +0 -35
- data/spec/redd/client/unauthenticated/users_spec.rb +0 -34
- data/spec/redd/client/unauthenticated/wiki_spec.rb +0 -18
- data/spec/redd/oauth2_access_spec.rb +0 -83
- data/spec/redd/thing_spec.rb +0 -22
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
module Redd
|
|
2
|
+
module Clients
|
|
3
|
+
class Base
|
|
4
|
+
# Methods that require the "read" scope
|
|
5
|
+
module Read
|
|
6
|
+
# @param [Array<String>] fnames A list of fullnames.
|
|
7
|
+
# @return [Objects::Listing<Objects::Thing>] A listing of things with
|
|
8
|
+
# the fullname.
|
|
9
|
+
def from_fullname(*fnames)
|
|
10
|
+
names = fnames.join(",")
|
|
11
|
+
request_object(:get, "/api/info", id: names)
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
# @param [String] url The url of the thing.
|
|
15
|
+
# @return [Objects::Thing] The thing.
|
|
16
|
+
def from_url(url)
|
|
17
|
+
request_object(:get, "/api/info", url: url).first
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
# @param [String] name The username.
|
|
21
|
+
# @return [Objects::User] The user.
|
|
22
|
+
def user_from_name(name)
|
|
23
|
+
request_object(:get, "/user/#{name}/about.json")
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
# @param [String] name The subreddit's display name.
|
|
27
|
+
# @return [Objects::Subreddit] The subreddit if found.
|
|
28
|
+
def subreddit_from_name(name)
|
|
29
|
+
request_object(:get, "/r/#{name}/about.json")
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
# @!method get_hot(subreddit = nil, **params)
|
|
33
|
+
# @!method get_new(subreddit = nil, **params)
|
|
34
|
+
# @!method get_top(subreddit = nil, **params)
|
|
35
|
+
# @!method get_controversial(subreddit = nil, **params)
|
|
36
|
+
# @!method get_comments(subreddit = nil, **params)
|
|
37
|
+
#
|
|
38
|
+
# Get the appropriate listing.
|
|
39
|
+
# @param subreddit [Objects::Subreddit, String] The subreddit to 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
|
+
#
|
|
52
|
+
# @note The option :t only applies to the top and controversial sorts.
|
|
53
|
+
# @return [Objects::Listing<Objects::Thing>]
|
|
54
|
+
# @todo Move all listing methods into a helper?
|
|
55
|
+
%w(hot new top controversial comments).each do |sort|
|
|
56
|
+
define_method :"get_#{sort}" do |subreddit = nil, **params|
|
|
57
|
+
srname = property(subreddit, :display_name) if subreddit
|
|
58
|
+
path = "/#{sort}.json"
|
|
59
|
+
path = path.prepend("/r/#{srname}") if subreddit
|
|
60
|
+
request_object(:get, path, params)
|
|
61
|
+
end
|
|
62
|
+
end
|
|
63
|
+
end
|
|
64
|
+
end
|
|
65
|
+
end
|
|
66
|
+
end
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
require "set"
|
|
2
|
+
|
|
3
|
+
module Redd
|
|
4
|
+
module Clients
|
|
5
|
+
class Base
|
|
6
|
+
# Methods that stream delicious content into your bot's lazy mouth.
|
|
7
|
+
module Stream
|
|
8
|
+
# A class similar to PRAW's implementation of a BoundedSet.
|
|
9
|
+
class PRAWBoundedQueueSet < Set
|
|
10
|
+
def initialize(max, *args, &block)
|
|
11
|
+
@max = max
|
|
12
|
+
@queue = []
|
|
13
|
+
super(*args, &block)
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
# Add an element to the front if it isn't already in the queue.
|
|
17
|
+
# @param element
|
|
18
|
+
# @return [PRAWBoundedQueueSet] self
|
|
19
|
+
def enqueue(element)
|
|
20
|
+
@queue.push(element) if add?(element)
|
|
21
|
+
dequeue! if size > @max
|
|
22
|
+
self
|
|
23
|
+
end
|
|
24
|
+
alias_method :enq, :enqueue
|
|
25
|
+
|
|
26
|
+
# Add an element to the front if it isn't already in the queue.
|
|
27
|
+
# @param element
|
|
28
|
+
# @return [Boolean] Whether the element was added to the queue.
|
|
29
|
+
def enqueue?(element)
|
|
30
|
+
added = add?(element)
|
|
31
|
+
if added
|
|
32
|
+
@queue.push(element)
|
|
33
|
+
dequeue if size > @max
|
|
34
|
+
end
|
|
35
|
+
added
|
|
36
|
+
end
|
|
37
|
+
alias_method :enq?, :enqueue?
|
|
38
|
+
|
|
39
|
+
# Remove the last element of the queue.
|
|
40
|
+
# @return The removed element.
|
|
41
|
+
def dequeue
|
|
42
|
+
element = @queue.shift
|
|
43
|
+
delete(element)
|
|
44
|
+
element
|
|
45
|
+
end
|
|
46
|
+
alias_method :deq, :dequeue
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
# Stream the results of a method call to the given block.
|
|
50
|
+
# @param [Symbol] meth A method that returns a listing and has a
|
|
51
|
+
# keyword parameter named `:before`.
|
|
52
|
+
# @param [Array] args The arguments supplied to the method.
|
|
53
|
+
# @param [Hash] kwargs The keyword arguments supplied to the method.
|
|
54
|
+
# @yield An element of the returned listing.
|
|
55
|
+
def stream(meth = :get_new, *args, **kwargs)
|
|
56
|
+
bset = PRAWBoundedQueueSet.new(10)
|
|
57
|
+
before = ""
|
|
58
|
+
loop do
|
|
59
|
+
# Get the latest comments from the subreddit. By the way, this line
|
|
60
|
+
# is the one where the sleeping/rate-limiting happens.
|
|
61
|
+
params = kwargs.merge(before: before)
|
|
62
|
+
listing = send(meth, *args, **params)
|
|
63
|
+
# Run the loop for each of the item in the listing
|
|
64
|
+
listing.reverse_each do |thing|
|
|
65
|
+
yield thing if bset.enqueue?(thing.fullname)
|
|
66
|
+
end
|
|
67
|
+
# Set the latest comment.
|
|
68
|
+
before = listing.first.fullname unless listing.empty?
|
|
69
|
+
end
|
|
70
|
+
end
|
|
71
|
+
end
|
|
72
|
+
end
|
|
73
|
+
end
|
|
74
|
+
end
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
module Redd
|
|
2
|
+
module Clients
|
|
3
|
+
class Base
|
|
4
|
+
# Methods that require the "submit" scope
|
|
5
|
+
module Submit
|
|
6
|
+
# Submit a link or a text post to a subreddit.
|
|
7
|
+
#
|
|
8
|
+
# @param [Objects::Submission, String] subreddit The subreddit
|
|
9
|
+
# to submit to.
|
|
10
|
+
# @param [String] title The title of the submission.
|
|
11
|
+
# @param [String] captcha A possible captcha result to send if one
|
|
12
|
+
# is required.
|
|
13
|
+
# @param [String] identifier The identifier for the captcha if one
|
|
14
|
+
# is required.
|
|
15
|
+
# @param [String] text The text of the self-post.
|
|
16
|
+
# @param [String] url The URL of the link.
|
|
17
|
+
# @param [Boolean] resubmit Whether to post a link to a subreddit
|
|
18
|
+
# despite it having been posted there before (you monster).
|
|
19
|
+
# @param [Boolean] sendreplies Whether to send the replies to your
|
|
20
|
+
# inbox.
|
|
21
|
+
# @return [Objects::Thing] The returned result (url, id and name).
|
|
22
|
+
def submit(
|
|
23
|
+
subreddit, title, captcha = nil, identifier = nil, text: nil,
|
|
24
|
+
url: nil, resubmit: false, sendreplies: true
|
|
25
|
+
)
|
|
26
|
+
|
|
27
|
+
params = {
|
|
28
|
+
extension: "json", title: title,
|
|
29
|
+
resubmit: resubmit, sendreplies: sendreplies,
|
|
30
|
+
sr: property(subreddit, :display_name)
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
params << {captcha: captcha, iden: identifier} if captcha
|
|
34
|
+
params[:kind], params[:text] = :self, text if text
|
|
35
|
+
params[:kind], params[:url] = :link, url if url
|
|
36
|
+
|
|
37
|
+
response = post("/api/submit", params)
|
|
38
|
+
Objects::Thing.new(self, response.body[:json][:data])
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
# Add a comment to a link, reply to a comment or reply to a message.
|
|
42
|
+
# Bit of an all-purpose method, this one.
|
|
43
|
+
# @param thing [Objects::Submission, Objects::Comment,
|
|
44
|
+
# Objects::PrivateMessage] A thing to add a comment to.
|
|
45
|
+
# @param text [String] The text to comment.
|
|
46
|
+
# @return [Objects::Comment, Objects::PrivateMessage] The reply.
|
|
47
|
+
def add_comment(thing, text)
|
|
48
|
+
response = post("/api/comment", text: text, thing_id: thing.fullname)
|
|
49
|
+
object_from_body(response.body[:json][:data][:things][0])
|
|
50
|
+
end
|
|
51
|
+
end
|
|
52
|
+
end
|
|
53
|
+
end
|
|
54
|
+
end
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
require_relative "../../objects/base"
|
|
2
|
+
require_relative "../../objects/thing"
|
|
3
|
+
require_relative "../../objects/listing"
|
|
4
|
+
require_relative "../../objects/wiki_page"
|
|
5
|
+
require_relative "../../objects/more_comments"
|
|
6
|
+
require_relative "../../objects/comment"
|
|
7
|
+
require_relative "../../objects/user"
|
|
8
|
+
require_relative "../../objects/submission"
|
|
9
|
+
require_relative "../../objects/private_message"
|
|
10
|
+
require_relative "../../objects/subreddit"
|
|
11
|
+
|
|
12
|
+
module Redd
|
|
13
|
+
module Clients
|
|
14
|
+
class Base
|
|
15
|
+
# Internal methods that make life easier.
|
|
16
|
+
# @todo Move this out to Redd::Utils?
|
|
17
|
+
module Utilities
|
|
18
|
+
# The kind strings and the objects that should be used for them.
|
|
19
|
+
OBJECT_KINDS = {
|
|
20
|
+
"Listing" => Objects::Listing,
|
|
21
|
+
"wikipage" => Objects::WikiPage,
|
|
22
|
+
"more" => Objects::MoreComments,
|
|
23
|
+
"t1" => Objects::Comment,
|
|
24
|
+
"t2" => Objects::User,
|
|
25
|
+
"t3" => Objects::Submission,
|
|
26
|
+
"t4" => Objects::PrivateMessage,
|
|
27
|
+
"t5" => Objects::Subreddit
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
# Request and create an object from the response.
|
|
31
|
+
# @param [Symbol] meth The method to use.
|
|
32
|
+
# @param [String] path The path to visit.
|
|
33
|
+
# @param [Hash] params The data to send with the request.
|
|
34
|
+
# @return [Objects::Base] The object returned from the request.
|
|
35
|
+
def request_object(meth, path, params = {})
|
|
36
|
+
body = send(meth, path, params).body
|
|
37
|
+
object_from_body(body)
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
# Create an object instance with the correct attributes when given a
|
|
41
|
+
# body.
|
|
42
|
+
#
|
|
43
|
+
# @param [Hash] body A JSON hash.
|
|
44
|
+
# @return [Objects::Thing, Objects::Listing]
|
|
45
|
+
def object_from_body(body)
|
|
46
|
+
return body unless body.is_a?(Hash) || body.key?(:kind)
|
|
47
|
+
object = object_from_kind(body[:kind])
|
|
48
|
+
flat = flatten_body(body)
|
|
49
|
+
object.new(self, flat)
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
private
|
|
53
|
+
|
|
54
|
+
# Get a given property of a given object.
|
|
55
|
+
# @param [Objects::Base, String] object The object with the property.
|
|
56
|
+
# @param [Symbol] property The property to get.
|
|
57
|
+
def property(object, property)
|
|
58
|
+
object.respond_to?(property) ? object.send(property) : object.to_s
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
# Take a multilevel body ({kind: "tx", data: {...}}) and flatten it
|
|
62
|
+
# into something like {kind: "tx", ...}
|
|
63
|
+
# @param [Hash] body The response body.
|
|
64
|
+
# @return [Hash] The flattened hash.
|
|
65
|
+
def flatten_body(body)
|
|
66
|
+
data = body[:data]
|
|
67
|
+
data[:kind] = body[:kind]
|
|
68
|
+
data
|
|
69
|
+
end
|
|
70
|
+
|
|
71
|
+
# @param [String] kind A kind in the format /t[1-5]/.
|
|
72
|
+
# @return [Objects::Base, Objects::Listing] The appropriate object for
|
|
73
|
+
# a given kind.
|
|
74
|
+
def object_from_kind(kind)
|
|
75
|
+
OBJECT_KINDS.fetch(kind, Objects::Base)
|
|
76
|
+
end
|
|
77
|
+
end
|
|
78
|
+
end
|
|
79
|
+
end
|
|
80
|
+
end
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
module Redd
|
|
2
|
+
module Clients
|
|
3
|
+
class Base
|
|
4
|
+
# Methods that require the "wikiread" scope.
|
|
5
|
+
# @note This method is not limited to {Objects::Subreddit} because there
|
|
6
|
+
# are also top-level wiki pages.
|
|
7
|
+
module Wikiread
|
|
8
|
+
# Get a list of pages in the subreddit wiki.
|
|
9
|
+
# @param subreddit [Objects::Subreddit, String] The subreddit to
|
|
10
|
+
# look in.
|
|
11
|
+
# @return [Array<String>] An array of wikipage titles.
|
|
12
|
+
def get_wikipages(subreddit = nil)
|
|
13
|
+
path = "/wiki/pages.json"
|
|
14
|
+
name = property(subreddit, :display_name)
|
|
15
|
+
path.prepend("/r/#{name}") if subreddit
|
|
16
|
+
get(path).body[:data]
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
# Get a wiki page.
|
|
20
|
+
# @param page [String] The title of the wiki page.
|
|
21
|
+
# @param subreddit [Objects::Subreddit, String] The subreddit to
|
|
22
|
+
# look in.
|
|
23
|
+
# @return [Objects::WikiPage] A wiki page.
|
|
24
|
+
def wikipage(page, subreddit = nil)
|
|
25
|
+
path = "/wiki/#{page}.json"
|
|
26
|
+
name = property(subreddit, :display_name)
|
|
27
|
+
path.prepend("/r/#{name}") if subreddit
|
|
28
|
+
request_object(:get, path)
|
|
29
|
+
end
|
|
30
|
+
end
|
|
31
|
+
end
|
|
32
|
+
end
|
|
33
|
+
end
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
require "cgi"
|
|
2
|
+
require_relative "base"
|
|
3
|
+
|
|
4
|
+
module Redd
|
|
5
|
+
module Clients
|
|
6
|
+
# The client for installed apps that can't keep a secret.
|
|
7
|
+
# It might even work with Rubymotion (fingers crossed).
|
|
8
|
+
class Installed < Base
|
|
9
|
+
# @!attribute [r] client_id
|
|
10
|
+
attr_reader :client_id
|
|
11
|
+
|
|
12
|
+
# @!attribute [r] redirect_uri
|
|
13
|
+
attr_reader :redirect_uri
|
|
14
|
+
|
|
15
|
+
# @param [Hash] options The options to create the client with.
|
|
16
|
+
# @see Redd.it
|
|
17
|
+
def initialize(client_id, redirect_uri, **options)
|
|
18
|
+
@client_id = client_id
|
|
19
|
+
@redirect_uri = redirect_uri
|
|
20
|
+
super(**options)
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
# @param [String] state A random string to double-check later.
|
|
24
|
+
# @param [Array<String>] scope The scope to request access to.
|
|
25
|
+
# @param [:temporary, :permanent] duration
|
|
26
|
+
# @return [String] The url to redirect the user to.
|
|
27
|
+
def auth_url(state, scope = ["identity"], duration = :temporary)
|
|
28
|
+
query = {
|
|
29
|
+
response_type: "token",
|
|
30
|
+
client_id: @client_id,
|
|
31
|
+
redirect_uri: @redirect_uri,
|
|
32
|
+
state: state,
|
|
33
|
+
scope: scope.join(","),
|
|
34
|
+
duration: duration
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
url = URI.join(auth_endpoint, "/api/v1/authorize")
|
|
38
|
+
url.query = URI.encode_www_form(query)
|
|
39
|
+
url.to_s
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
# Authorize using the url fragment.
|
|
43
|
+
# @param [String] fragment The part of the url after the "#".
|
|
44
|
+
# @return [Access] The access given by reddit.
|
|
45
|
+
def authorize!(fragment)
|
|
46
|
+
parsed = CGI.parse(fragment)
|
|
47
|
+
@access = Access.new(
|
|
48
|
+
access_token: parsed[:access_token].first,
|
|
49
|
+
expires_in: parsed[:expires_in].first,
|
|
50
|
+
scope: parsed[:scope]
|
|
51
|
+
)
|
|
52
|
+
end
|
|
53
|
+
end
|
|
54
|
+
end
|
|
55
|
+
end
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
require_relative "base"
|
|
2
|
+
|
|
3
|
+
module Redd
|
|
4
|
+
module Clients
|
|
5
|
+
# The client for an account you own (e.g. bots).
|
|
6
|
+
class Script < Base
|
|
7
|
+
# @!attribute [r] client_id
|
|
8
|
+
attr_reader :client_id
|
|
9
|
+
|
|
10
|
+
# @!attribute [r] username
|
|
11
|
+
attr_reader :username
|
|
12
|
+
|
|
13
|
+
# @param [Hash] options The options to create the client with.
|
|
14
|
+
# @see Redd.it
|
|
15
|
+
def initialize(client_id, secret, username, password, **options)
|
|
16
|
+
@client_id = client_id
|
|
17
|
+
@secret = secret
|
|
18
|
+
@username = username
|
|
19
|
+
@password = password
|
|
20
|
+
super(**options)
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
# Authorize using the given data.
|
|
24
|
+
# @return [Access] The access given by reddit.
|
|
25
|
+
def authorize!
|
|
26
|
+
response = auth_connection.post(
|
|
27
|
+
"/api/v1/access_token",
|
|
28
|
+
grant_type: "password",
|
|
29
|
+
username: @username,
|
|
30
|
+
password: @password
|
|
31
|
+
)
|
|
32
|
+
|
|
33
|
+
@access = Access.new(response.body)
|
|
34
|
+
end
|
|
35
|
+
end
|
|
36
|
+
end
|
|
37
|
+
end
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
require_relative "base"
|
|
2
|
+
|
|
3
|
+
module Redd
|
|
4
|
+
module Clients
|
|
5
|
+
# The client that doesn't need a user to function.
|
|
6
|
+
# @note Of course, that means many editing methods throw an error.
|
|
7
|
+
class Userless < Base
|
|
8
|
+
# @!attribute [r] client_id
|
|
9
|
+
attr_reader :client_id
|
|
10
|
+
|
|
11
|
+
# @param [Hash] options The options to create the client with.
|
|
12
|
+
# @see Redd.it
|
|
13
|
+
def initialize(client_id, secret, **options)
|
|
14
|
+
@client_id = client_id
|
|
15
|
+
@secret = secret
|
|
16
|
+
super(**options)
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
# Authorize using the given data.
|
|
20
|
+
# @return [Access] The access given by reddit.
|
|
21
|
+
def authorize!
|
|
22
|
+
response = auth_connection.post(
|
|
23
|
+
"/api/v1/access_token",
|
|
24
|
+
grant_type: "client_credentials"
|
|
25
|
+
)
|
|
26
|
+
|
|
27
|
+
@access = Access.new(response.body)
|
|
28
|
+
end
|
|
29
|
+
end
|
|
30
|
+
end
|
|
31
|
+
end
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
require "uri"
|
|
2
|
+
require_relative "base"
|
|
3
|
+
|
|
4
|
+
module Redd
|
|
5
|
+
module Clients
|
|
6
|
+
# The client for a web-based flow (e.g. "login with reddit")
|
|
7
|
+
class Web < Base
|
|
8
|
+
# @!attribute [r] client_id
|
|
9
|
+
attr_reader :client_id
|
|
10
|
+
|
|
11
|
+
# @!attribute [r] redirect_uri
|
|
12
|
+
attr_reader :redirect_uri
|
|
13
|
+
|
|
14
|
+
# @param [Hash] options The options to create the client with.
|
|
15
|
+
# @see Redd.it
|
|
16
|
+
def initialize(client_id, secret, redirect_uri, **options)
|
|
17
|
+
@client_id = client_id
|
|
18
|
+
@secret = secret
|
|
19
|
+
@redirect_uri = redirect_uri
|
|
20
|
+
super(**options)
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
# @param [String] state A random string to double-check later.
|
|
24
|
+
# @param [Array<String>] scope The scope to request access to.
|
|
25
|
+
# @param [:temporary, :permanent] duration
|
|
26
|
+
# @return [String] The url to redirect the user to.
|
|
27
|
+
def auth_url(state, scope = ["identity"], duration = :temporary)
|
|
28
|
+
query = {
|
|
29
|
+
response_type: "code",
|
|
30
|
+
client_id: @client_id,
|
|
31
|
+
redirect_uri: @redirect_uri,
|
|
32
|
+
state: state,
|
|
33
|
+
scope: scope.join(","),
|
|
34
|
+
duration: duration
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
url = URI.join(auth_endpoint, "/api/v1/authorize")
|
|
38
|
+
url.query = URI.encode_www_form(query)
|
|
39
|
+
url.to_s
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
# Authorize using the code given.
|
|
43
|
+
# @param [String] code The code from the get params.
|
|
44
|
+
# @return [Access] The access given by reddit.
|
|
45
|
+
def authorize!(code)
|
|
46
|
+
response = auth_connection.post(
|
|
47
|
+
"/api/v1/access_token",
|
|
48
|
+
grant_type: "authorization_code",
|
|
49
|
+
code: code,
|
|
50
|
+
redirect_uri: @redirect_uri
|
|
51
|
+
)
|
|
52
|
+
|
|
53
|
+
@access = Access.new(response.body)
|
|
54
|
+
end
|
|
55
|
+
end
|
|
56
|
+
end
|
|
57
|
+
end
|