redd 0.7.10 → 0.8.0.pre.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.gitignore +5 -30
- data/.rspec +1 -1
- data/.rubocop.yml +16 -3
- data/.travis.yml +13 -7
- data/Gemfile +3 -1
- data/LICENSE.txt +21 -0
- data/README.md +40 -126
- data/Rakefile +10 -3
- data/TODO.md +11 -0
- data/bin/console +84 -0
- data/bin/setup +8 -0
- data/lib/redd.rb +84 -46
- data/lib/redd/api_client.rb +109 -0
- data/lib/redd/auth_strategies/auth_strategy.rb +60 -0
- data/lib/redd/auth_strategies/installed.rb +22 -0
- data/lib/redd/auth_strategies/script.rb +23 -0
- data/lib/redd/auth_strategies/userless.rb +17 -0
- data/lib/redd/auth_strategies/web.rb +29 -0
- data/lib/redd/client.rb +88 -0
- data/lib/redd/error.rb +19 -142
- data/lib/redd/models/access.rb +20 -0
- data/lib/redd/models/basic_model.rb +124 -0
- data/lib/redd/models/comment.rb +51 -0
- data/lib/redd/models/front_page.rb +71 -0
- data/lib/redd/models/inboxable.rb +23 -0
- data/lib/redd/models/lazy_model.rb +63 -0
- data/lib/redd/models/listing.rb +26 -0
- data/lib/redd/models/messageable.rb +20 -0
- data/lib/redd/models/moderatable.rb +41 -0
- data/lib/redd/models/more_comments.rb +10 -0
- data/lib/redd/models/multireddit.rb +32 -0
- data/lib/redd/models/postable.rb +70 -0
- data/lib/redd/models/private_message.rb +29 -0
- data/lib/redd/models/replyable.rb +16 -0
- data/lib/redd/models/session.rb +86 -0
- data/lib/redd/models/submission.rb +40 -0
- data/lib/redd/models/subreddit.rb +201 -0
- data/lib/redd/models/user.rb +72 -0
- data/lib/redd/models/wiki_page.rb +24 -0
- data/lib/redd/utilities/error_handler.rb +35 -0
- data/lib/redd/utilities/rate_limiter.rb +21 -0
- data/lib/redd/utilities/stream.rb +63 -0
- data/lib/redd/utilities/unmarshaller.rb +39 -0
- data/lib/redd/version.rb +4 -3
- data/logo.png +0 -0
- data/redd.gemspec +26 -22
- metadata +73 -99
- data/LICENSE.md +0 -22
- data/RedditKit.LICENSE.md +0 -9
- data/lib/redd/access.rb +0 -76
- data/lib/redd/clients/base.rb +0 -188
- data/lib/redd/clients/base/account.rb +0 -20
- data/lib/redd/clients/base/identity.rb +0 -22
- data/lib/redd/clients/base/none.rb +0 -27
- data/lib/redd/clients/base/privatemessages.rb +0 -33
- data/lib/redd/clients/base/read.rb +0 -113
- data/lib/redd/clients/base/stream.rb +0 -81
- data/lib/redd/clients/base/submit.rb +0 -19
- data/lib/redd/clients/base/utilities.rb +0 -104
- data/lib/redd/clients/base/wikiread.rb +0 -33
- data/lib/redd/clients/installed.rb +0 -57
- data/lib/redd/clients/script.rb +0 -41
- data/lib/redd/clients/userless.rb +0 -32
- data/lib/redd/clients/web.rb +0 -58
- data/lib/redd/objects/base.rb +0 -39
- data/lib/redd/objects/comment.rb +0 -22
- data/lib/redd/objects/labeled_multi.rb +0 -13
- data/lib/redd/objects/listing.rb +0 -29
- data/lib/redd/objects/more_comments.rb +0 -11
- data/lib/redd/objects/private_message.rb +0 -28
- data/lib/redd/objects/submission.rb +0 -139
- data/lib/redd/objects/subreddit.rb +0 -330
- data/lib/redd/objects/thing.rb +0 -26
- data/lib/redd/objects/thing/editable.rb +0 -22
- data/lib/redd/objects/thing/hideable.rb +0 -18
- data/lib/redd/objects/thing/inboxable.rb +0 -25
- data/lib/redd/objects/thing/messageable.rb +0 -34
- data/lib/redd/objects/thing/moderatable.rb +0 -43
- data/lib/redd/objects/thing/refreshable.rb +0 -14
- data/lib/redd/objects/thing/saveable.rb +0 -21
- data/lib/redd/objects/thing/votable.rb +0 -33
- data/lib/redd/objects/user.rb +0 -52
- data/lib/redd/objects/wiki_page.rb +0 -15
- data/lib/redd/rate_limit.rb +0 -88
- data/lib/redd/response/parse_json.rb +0 -18
- data/lib/redd/response/raise_error.rb +0 -16
- data/spec/redd/objects/base_spec.rb +0 -1
- data/spec/redd/response/raise_error_spec.rb +0 -11
- data/spec/redd_spec.rb +0 -5
- data/spec/spec_helper.rb +0 -71
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: bc08060b2e7111adfd18a83c7d23e464f20a92dc
|
4
|
+
data.tar.gz: 79897c294f7f612e90acee7184b91a4982d54cb6
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 0ccfa94a4923e3748931c6ca5e5515f23c10bd23d979c1ef79e5f3f62a87c78ff66ed01f72033d95d3da3e8ca0e47cf9ebd412d758d3b751d3d935545abd787c
|
7
|
+
data.tar.gz: f2881316388b4b3b1183aebdc867184aa64750c57ac29cfb6b17532ef099f0c4de309f064f3160a3eb670ee4d70d91cee335367b9c43a34c5f70eb3254781743
|
data/.gitignore
CHANGED
@@ -1,34 +1,9 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
|
1
|
+
/.bundle/
|
2
|
+
/.yardoc
|
3
|
+
/Gemfile.lock
|
4
|
+
/_yardoc/
|
4
5
|
/coverage/
|
5
|
-
/
|
6
|
+
/doc/
|
6
7
|
/pkg/
|
7
8
|
/spec/reports/
|
8
|
-
/test/tmp/
|
9
|
-
/test/version_tmp/
|
10
9
|
/tmp/
|
11
|
-
|
12
|
-
## Specific to RubyMotion:
|
13
|
-
.dat*
|
14
|
-
.repl_history
|
15
|
-
build/
|
16
|
-
|
17
|
-
## Documentation cache and generated files:
|
18
|
-
/.yardoc/
|
19
|
-
/_yardoc/
|
20
|
-
/doc/
|
21
|
-
/rdoc/
|
22
|
-
|
23
|
-
## Environment normalisation:
|
24
|
-
/.bundle/
|
25
|
-
/lib/bundler/man/
|
26
|
-
|
27
|
-
# for a library or gem, you might want to ignore these files since the code is
|
28
|
-
# intended to run in multiple environments; otherwise, check them in:
|
29
|
-
Gemfile.lock
|
30
|
-
.ruby-version
|
31
|
-
.ruby-gemset
|
32
|
-
|
33
|
-
# unless supporting rvm < 1.11.0 or doing something fancy, ignore this:
|
34
|
-
.rvmrc
|
data/.rspec
CHANGED
data/.rubocop.yml
CHANGED
@@ -1,5 +1,18 @@
|
|
1
|
-
|
2
|
-
|
1
|
+
AllCops:
|
2
|
+
TargetRubyVersion: 2.3
|
3
3
|
|
4
|
-
|
4
|
+
Metrics/LineLength:
|
5
|
+
Max: 100
|
6
|
+
|
7
|
+
# Allows for raising Redd::ResponseErrors with a Response object.
|
8
|
+
Style/RaiseArgs:
|
5
9
|
Enabled: false
|
10
|
+
|
11
|
+
# Many reddit calls demand a lot of parameters.
|
12
|
+
Metrics/ParameterLists:
|
13
|
+
CountKeywordArgs: false
|
14
|
+
|
15
|
+
# Stop rubocop from complaining about large `describe` blocks.
|
16
|
+
Metrics/BlockLength:
|
17
|
+
Exclude:
|
18
|
+
- spec/**/*_spec.rb
|
data/.travis.yml
CHANGED
@@ -1,9 +1,15 @@
|
|
1
|
+
sudo: false
|
1
2
|
language: ruby
|
2
|
-
before_install:
|
3
|
-
- gem install bundler -v 1.12
|
4
3
|
rvm:
|
5
|
-
- ruby-
|
6
|
-
-
|
7
|
-
-
|
8
|
-
-
|
9
|
-
- jruby-9.
|
4
|
+
- ruby-head
|
5
|
+
- 2.4.0
|
6
|
+
- 2.1.0
|
7
|
+
- jruby-head
|
8
|
+
- jruby-9.1.7.0
|
9
|
+
matrix:
|
10
|
+
allow_failures:
|
11
|
+
- rvm: ruby-head
|
12
|
+
- rvm: jruby-head
|
13
|
+
|
14
|
+
before_install: gem install bundler -v 1.13.7
|
15
|
+
cache: bundler
|
data/Gemfile
CHANGED
data/LICENSE.txt
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
The MIT License (MIT)
|
2
|
+
|
3
|
+
Copyright (c) 2017 Avinash Dwarapu
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
7
|
+
in the Software without restriction, including without limitation the rights
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
10
|
+
furnished to do so, subject to the following conditions:
|
11
|
+
|
12
|
+
The above copyright notice and this permission notice shall be included in
|
13
|
+
all copies or substantial portions of the Software.
|
14
|
+
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
21
|
+
THE SOFTWARE.
|
data/README.md
CHANGED
@@ -1,142 +1,56 @@
|
|
1
|
-
<
|
2
|
-
|
3
|
-
<
|
4
|
-
<a href="https://travis-ci.org/avidw/redd"><img src="http://img.shields.io/travis/avinashbot/redd.svg?style=flat-square" alt="Build Status"></a>
|
5
|
-
<a href="https://rubygems.org/gems/redd"><img src="http://img.shields.io/badge/license-MIT-blue.svg?style=flat-square" alt="MIT License"></a>
|
6
|
-
</p>
|
1
|
+
<div align="center">
|
2
|
+
<!-- Redd -->
|
3
|
+
<img src="logo.png" width="500"><br>
|
7
4
|
|
8
|
-
|
5
|
+
<!-- Intro Text -->
|
6
|
+
<strong>Redd</strong> is an API wrapper
|
7
|
+
for <a href="https://www.reddit.com/dev/api">reddit</a>
|
8
|
+
that is all about being <strong>simple</strong>
|
9
|
+
and <strong>intuitive</strong>.
|
10
|
+
</div>
|
9
11
|
|
10
12
|
---
|
11
13
|
|
12
|
-
#### Gemfile
|
13
14
|
```ruby
|
14
|
-
|
15
|
+
require 'redd'
|
15
16
|
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
w = Redd.it(:web, "CLIENT_ID", "SECRET", "REDIRECT_URI", user_agent: "TestSite v1.0.0")
|
24
|
-
url = w.auth_url("random_state", ["identity", "read"], :temporary)
|
25
|
-
puts "Please go to #{url} and enter the code below:"
|
26
|
-
code = gets.chomp
|
27
|
-
w.authorize!(code)
|
28
|
-
|
29
|
-
# Authorization
|
30
|
-
r = Redd.it(:script, "CLIENT_ID", "SECRET", "Unidan", "hunter2", user_agent: "TestBot v1.0.0")
|
31
|
-
r.authorize!
|
32
|
-
|
33
|
-
# See documentation for more grants.
|
34
|
-
```
|
35
|
-
|
36
|
-
```ruby
|
37
|
-
# Access
|
38
|
-
require "secure_random"
|
39
|
-
require "sinatra"
|
40
|
-
|
41
|
-
enable :sessions
|
42
|
-
|
43
|
-
get "/auth" do
|
44
|
-
state = SecureRandom.urlsafe_base64
|
45
|
-
session[:state] = state
|
46
|
-
redirect w.auth_url(state, %w(identity), :permanent)
|
47
|
-
end
|
48
|
-
|
49
|
-
get "/redirect" do
|
50
|
-
halt 500, "Your state doesn't match!" unless session[:state] == params[:state]
|
51
|
-
access = w.authorize!(params[:code])
|
52
|
-
session[:access] = access.to_json
|
53
|
-
redirect to("/name")
|
54
|
-
end
|
17
|
+
session = Redd.it(
|
18
|
+
user_agent: 'Redd:RandomBot:v1.0.0 (by /u/Mustermind)',
|
19
|
+
client_id: 'PQgS0UaX9l70oQ',
|
20
|
+
secret: 'PsF_kVZrW8nSVCG5kNsIgl-AaXE',
|
21
|
+
username: 'RandomBot',
|
22
|
+
password: 'hunter2'
|
23
|
+
)
|
55
24
|
|
56
|
-
|
57
|
-
if
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
end
|
63
|
-
else
|
64
|
-
redirect to("/auth")
|
25
|
+
session.subreddit('all').comment_stream do |comment|
|
26
|
+
if comment.body.include?('roll a dice')
|
27
|
+
comment.reply("I just rolled a dice! It's a #{rand(1..6)}!")
|
28
|
+
elsif comment.body.include?('flip a coin') || comment.body.include?('coin flip')
|
29
|
+
coin_face = (rand(0..1) == 1 ? 'heads' : 'tails')
|
30
|
+
comment.reply("I just flipped a coin! It's #{coin_face}!")
|
65
31
|
end
|
66
32
|
end
|
67
|
-
|
68
|
-
```
|
69
|
-
|
70
|
-
```ruby
|
71
|
-
# Getting a model
|
72
|
-
vargas = r.user_from_name("_vargas_")
|
73
|
-
puts vargas.keys
|
74
|
-
puts vargas.over_18?
|
75
|
-
|
76
|
-
picturegame = r.subreddit_from_name("picturegame")
|
77
|
-
puts picturegame.display_name
|
78
|
-
puts picturegame.public_description
|
79
33
|
```
|
80
34
|
|
81
|
-
|
82
|
-
# Listings
|
83
|
-
hot = r.get_hot("all")
|
84
|
-
hot.each { |link| puts "#{link.title} by /u/#{link.author}" }
|
85
|
-
```
|
86
|
-
|
87
|
-
```ruby
|
88
|
-
# Streaming
|
89
|
-
def stream_all!
|
90
|
-
r.stream :get_comments, "all" do |comment|
|
91
|
-
reddit.refresh_access! if reddit.access.expired? # for :web
|
92
|
-
comment.reply("World!") if comment.body == "Hello?"
|
93
|
-
end
|
94
|
-
end
|
95
|
-
```
|
96
|
-
|
97
|
-
```ruby
|
98
|
-
# Escaping Errors
|
99
|
-
begin
|
100
|
-
stream_all!
|
101
|
-
rescue Redd::Error::RateLimited => error
|
102
|
-
sleep(error.time)
|
103
|
-
retry
|
104
|
-
rescue Redd::Error => error
|
105
|
-
# 5-something errors are usually errors on reddit's end.
|
106
|
-
raise error unless (500...600).include?(error.code)
|
107
|
-
retry
|
108
|
-
end
|
109
|
-
```
|
110
|
-
|
111
|
-
#### Extras
|
112
|
-
```ruby
|
113
|
-
# Extending Redd.rb
|
35
|
+
---
|
114
36
|
|
115
|
-
|
116
|
-
def gild!
|
117
|
-
# We're using post instead of request_object, because we don't
|
118
|
-
# expect any object from the response.
|
119
|
-
post("/api/v1/gold/gild/#{fullname}")
|
120
|
-
end
|
121
|
-
end
|
37
|
+
### FAQ
|
122
38
|
|
123
|
-
|
124
|
-
|
125
|
-
|
39
|
+
#### Is that bot fully functional?
|
40
|
+
**Yes**, that's all there is to it! You don't need to handle rate-limiting, refresh access tokens
|
41
|
+
or protect against issues on reddit's end (like 5xx errors).
|
126
42
|
|
127
|
-
|
128
|
-
|
129
|
-
|
130
|
-
|
131
|
-
3. [Profit](https://www.reddit.com/r/requestabot)
|
43
|
+
#### How can I contact you?
|
44
|
+
[Reddit](https://www.reddit.com/message/compose/?to=Mustermind) /
|
45
|
+
[GitHub](https://github.com/avinashbot/redd/issues/new) /
|
46
|
+
[Email](mailto:avinash@dwarapu.me)
|
132
47
|
|
133
|
-
|
134
|
-
1. [Help](https://github.com/avidw/redd/issues/new)
|
135
|
-
```
|
48
|
+
---
|
136
49
|
|
137
|
-
|
138
|
-
|
139
|
-
|
140
|
-
|
141
|
-
|
142
|
-
|
50
|
+
<div align="center">
|
51
|
+
<!-- Copyright Notice -->
|
52
|
+
<em>
|
53
|
+
This project is available under the MIT License. See LICENSE.txt for more details.<br>
|
54
|
+
The Redd logo uses the FARRAY font by Coquet Adrien.
|
55
|
+
</em>
|
56
|
+
</div>
|
data/Rakefile
CHANGED
@@ -1,5 +1,12 @@
|
|
1
|
-
|
2
|
-
require "rspec/core/rake_task"
|
1
|
+
# frozen_string_literal: true
|
3
2
|
|
3
|
+
require 'bundler/gem_tasks'
|
4
|
+
require 'rubocop/rake_task'
|
5
|
+
require 'rspec/core/rake_task'
|
6
|
+
|
7
|
+
RuboCop::RakeTask.new do |t|
|
8
|
+
t.fail_on_error = false
|
9
|
+
end
|
4
10
|
RSpec::Core::RakeTask.new(:spec)
|
5
|
-
|
11
|
+
|
12
|
+
task default: [:rubocop, :spec]
|
data/TODO.md
ADDED
@@ -0,0 +1,11 @@
|
|
1
|
+
# v0.8.0 checklist
|
2
|
+
|
3
|
+
- [ ] Make v0.8.0 feature-complete with v0.7.x
|
4
|
+
- [ ] `Messageable`
|
5
|
+
- [ ] `MoreComments` and expansion
|
6
|
+
- [ ] make rubocop fail on error
|
7
|
+
- [ ] unduplicate duplicated code
|
8
|
+
- [ ] Write tests (oh boy)
|
9
|
+
- [ ] More comprehensive error checking
|
10
|
+
- [ ] A `FrontPage` object
|
11
|
+
- [ ] Add `#==` and `#to_s` methods to models
|
data/bin/console
ADDED
@@ -0,0 +1,84 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
# frozen_string_literal: true
|
3
|
+
|
4
|
+
require 'webrick'
|
5
|
+
require 'redd'
|
6
|
+
|
7
|
+
server = WEBrick::HTTPServer.new(
|
8
|
+
Port: 8000,
|
9
|
+
BindAddress: '0.0.0.0',
|
10
|
+
Logger: WEBrick::Log.new(File.open(File::NULL, 'w')),
|
11
|
+
AccessLog: []
|
12
|
+
)
|
13
|
+
|
14
|
+
server.mount_proc '/' do |_, res|
|
15
|
+
res.body = <<-EOS
|
16
|
+
<!doctype html>
|
17
|
+
<title>Redd Quickstart</title>
|
18
|
+
<style>
|
19
|
+
html, body { margin: 0; height: 100vh; }
|
20
|
+
.wrapper { padding-top: 30vh; text-align: center; font-family: sans-serif; }
|
21
|
+
#btn { background-color: #3D9970; margin: 5px; border-radius: 5px; padding: 10px; color: #fff; text-decoration: none; }
|
22
|
+
</style>
|
23
|
+
<div class="wrapper">
|
24
|
+
<h1>redd // quickstart</h1>
|
25
|
+
<a onclick="window.open('/authenticate', '', 'width=960,height=640')" href="#" id="btn">Start</a>
|
26
|
+
<span>a new session in your terminal?</span>
|
27
|
+
</div>
|
28
|
+
EOS
|
29
|
+
end
|
30
|
+
|
31
|
+
server.mount_proc '/authenticate' do |_, res|
|
32
|
+
res.set_redirect(
|
33
|
+
WEBrick::HTTPStatus[302],
|
34
|
+
Redd.url(
|
35
|
+
client_id: 'P4txR-D6TzF8cg',
|
36
|
+
response_type: 'code',
|
37
|
+
state: '0',
|
38
|
+
redirect_uri: 'http://localhost:8000/redirect',
|
39
|
+
'scope': %w(identity read subscribe privatemessages wikiread submit vote edit modposts history
|
40
|
+
modflair)
|
41
|
+
)
|
42
|
+
)
|
43
|
+
end
|
44
|
+
|
45
|
+
server.mount_proc '/redirect' do |req, res|
|
46
|
+
err = req.query['error']
|
47
|
+
should_exit = err.nil? || err == 'access_denied'
|
48
|
+
res.body = <<-EOS
|
49
|
+
<!doctype html>
|
50
|
+
<title>Done!</title>
|
51
|
+
#{should_exit ? '<script>window.close();</script>' : "<p>Uh oh, there was an error: #{err}</p>"}
|
52
|
+
EOS
|
53
|
+
|
54
|
+
unless err
|
55
|
+
R = Redd.it(
|
56
|
+
user_agent: "Ruby:Redd-Quickstart:v#{Redd::VERSION} (by unknown)",
|
57
|
+
client_id: 'P4txR-D6TzF8cg',
|
58
|
+
redirect_uri: 'http://localhost:8000/redirect',
|
59
|
+
code: req.query['code']
|
60
|
+
)
|
61
|
+
server.stop
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
65
|
+
# Get the server going and shut it all down if user hits Ctrl-C
|
66
|
+
begin
|
67
|
+
puts "Listening at \e[34mhttp://localhost:8000\e[0m..."
|
68
|
+
server.start
|
69
|
+
rescue Interrupt
|
70
|
+
server.shutdown
|
71
|
+
exit
|
72
|
+
end
|
73
|
+
|
74
|
+
# Post a colourful welcome message
|
75
|
+
suggestions = [
|
76
|
+
'R.me.link_karma',
|
77
|
+
"R.subreddit('pics').hot.first.title",
|
78
|
+
"puts R.subreddit('all').hot.map(&:title)"
|
79
|
+
]
|
80
|
+
puts "Welcome, \e[35m/u/#{R.me.name}\e[0m! Try `\e[34m#{suggestions.sample}\e[0m`."
|
81
|
+
|
82
|
+
# Load Pry
|
83
|
+
require 'pry'
|
84
|
+
Pry.start
|
data/bin/setup
ADDED
data/lib/redd.rb
CHANGED
@@ -1,50 +1,88 @@
|
|
1
|
-
|
2
|
-
require_relative "redd/clients/installed"
|
3
|
-
require_relative "redd/clients/script"
|
4
|
-
require_relative "redd/clients/userless"
|
5
|
-
require_relative "redd/clients/web"
|
1
|
+
# frozen_string_literal: true
|
6
2
|
|
7
|
-
|
3
|
+
require 'uri'
|
4
|
+
|
5
|
+
# Redd Version
|
6
|
+
require_relative 'redd/version'
|
7
|
+
# Models
|
8
|
+
Dir[File.join(__dir__, 'redd', 'models', '*.rb')].each { |f| require f }
|
9
|
+
# Authentication Clients
|
10
|
+
Dir[File.join(__dir__, 'redd', 'auth_strategies', '*.rb')].each { |f| require f }
|
11
|
+
# Regular Client
|
12
|
+
require_relative 'redd/api_client'
|
13
|
+
|
14
|
+
# Redd is a simple and intuitive API wrapper.
|
8
15
|
module Redd
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
16
|
+
class << self
|
17
|
+
# Guesses the appropriate authentication strategy, creates an API client and starts you off with
|
18
|
+
# a {Models::Session}.
|
19
|
+
# @see https://www.reddit.com/prefs/apps
|
20
|
+
# @param opts [Hash] the options to create the object with
|
21
|
+
# @option opts [String] :user_agent your app's *unique* and *descriptive* user agent
|
22
|
+
# @option opts [String] :client_id the client id of your app
|
23
|
+
# @option opts [String] :secret the app secret (for confidential types, i.e. *not* *installed*)
|
24
|
+
# @option opts [String] :username the username of your bot (only for *script*)
|
25
|
+
# @option opts [String] :password the plaintext password of your bot (only for *script*)
|
26
|
+
# @option opts [String] :redirect_uri the provided redirect URI (only for *web* and *installed*)
|
27
|
+
# @option opts [String] :code the code given by reddit (required for *web* and *installed*)
|
28
|
+
# @return [Models::Session] a fresh {Models::Session} for you to make requests with
|
29
|
+
def it(opts = {})
|
30
|
+
api_client = script(opts) || web(opts) || installed(opts) || userless(opts)
|
31
|
+
raise "couldn't guess app type" unless api_client
|
32
|
+
Models::Session.new(api_client) { |client| client.get('/api/v1/me').body }
|
33
|
+
end
|
34
|
+
|
35
|
+
# Create a url to send to users for authorization.
|
36
|
+
# @param response_type ['code', 'token'] the type of response from reddit
|
37
|
+
# @param state [String] a randomly generated token to avoid CSRF attacks.
|
38
|
+
# @param client_id [String] the client id of the app
|
39
|
+
# @param redirect_uri [String] the URI for reddit to redirect to after authorization
|
40
|
+
# @param scope [Array<String>] an array of scopes to request
|
41
|
+
# @return [String] the generated url
|
42
|
+
def url(client_id:, redirect_uri:, response_type: 'code', state: '', scope: ['identity'])
|
43
|
+
'https://www.reddit.com/api/v1/authorize?' + URI.encode_www_form(
|
44
|
+
client_id: client_id,
|
45
|
+
redirect_uri: redirect_uri,
|
46
|
+
state: state,
|
47
|
+
scope: scope.join(','),
|
48
|
+
response_type: response_type
|
49
|
+
)
|
50
|
+
end
|
51
|
+
|
52
|
+
private
|
53
|
+
|
54
|
+
def filter_auth(opts)
|
55
|
+
opts.select { |k| %i(client_id secret username password redirect_uri user_agent).include?(k) }
|
56
|
+
end
|
57
|
+
|
58
|
+
def filter_api(opts)
|
59
|
+
opts.select { |k| %i(user_agent).include?(k) }
|
60
|
+
end
|
61
|
+
|
62
|
+
def script(opts = {})
|
63
|
+
return unless %i(client_id secret username password).all? { |o| opts.include?(o) }
|
64
|
+
api = APIClient.new(AuthStrategies::Script.new(**filter_auth(opts)), **filter_api(opts))
|
65
|
+
api.tap(&:authenticate)
|
66
|
+
end
|
67
|
+
|
68
|
+
def web(opts = {})
|
69
|
+
return unless %i(client_id secret redirect_uri code).all? { |o| opts.include?(o) }
|
70
|
+
code = opts.delete(:code)
|
71
|
+
api = APIClient.new(AuthStrategies::Web.new(**filter_auth(opts)), **filter_api(opts))
|
72
|
+
api.tap { |c| c.authenticate(code) }
|
73
|
+
end
|
74
|
+
|
75
|
+
def installed(opts = {})
|
76
|
+
return unless %i(client_id redirect_uri code).all? { |o| opts.include?(o) }
|
77
|
+
code = opts.delete(:code)
|
78
|
+
api = APIClient.new(AuthStrategies::Installed.new(**filter_auth(opts)), **filter_api(opts))
|
79
|
+
api.tap { |c| c.authenticate(code) }
|
80
|
+
end
|
81
|
+
|
82
|
+
def userless(opts = {})
|
83
|
+
return unless %i(client_id secret).all? { |o| opts.include?(o) }
|
84
|
+
api = APIClient.new(AuthStrategies::Userless.new(**filter_auth(opts)), **filter_api(opts))
|
85
|
+
api.tap(&:authenticate)
|
86
|
+
end
|
49
87
|
end
|
50
88
|
end
|