redd 0.8.8 → 0.9.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/.rubocop.yml +4 -1
- data/CONTRIBUTING.md +63 -0
- data/Guardfile +7 -0
- data/README.md +6 -5
- data/Rakefile +1 -1
- data/TODO.md +423 -0
- data/bin/console +91 -77
- data/bin/guard +2 -0
- data/lib/redd.rb +7 -5
- data/lib/redd/api_client.rb +2 -3
- data/lib/redd/auth_strategies/auth_strategy.rb +7 -2
- data/lib/redd/auth_strategies/script.rb +7 -0
- data/lib/redd/auth_strategies/userless.rb +7 -0
- data/lib/redd/auth_strategies/web.rb +6 -1
- data/lib/redd/client.rb +0 -3
- data/lib/redd/errors.rb +56 -0
- data/lib/redd/middleware.rb +10 -8
- data/lib/redd/models/access.rb +30 -18
- data/lib/redd/models/comment.rb +185 -27
- data/lib/redd/models/front_page.rb +16 -36
- data/lib/redd/models/gildable.rb +1 -1
- data/lib/redd/models/inboxable.rb +13 -3
- data/lib/redd/models/listing.rb +27 -6
- data/lib/redd/models/live_thread.rb +76 -23
- data/lib/redd/models/live_update.rb +46 -0
- data/lib/redd/models/messageable.rb +1 -1
- data/lib/redd/models/mod_action.rb +59 -0
- data/lib/redd/models/model.rb +23 -0
- data/lib/redd/models/moderatable.rb +6 -6
- data/lib/redd/models/modmail.rb +61 -0
- data/lib/redd/models/modmail_conversation.rb +154 -0
- data/lib/redd/models/modmail_message.rb +35 -0
- data/lib/redd/models/more_comments.rb +29 -5
- data/lib/redd/models/multireddit.rb +63 -20
- data/lib/redd/models/paginated_listing.rb +113 -0
- data/lib/redd/models/postable.rb +11 -13
- data/lib/redd/models/private_message.rb +78 -11
- data/lib/redd/models/replyable.rb +2 -2
- data/lib/redd/models/reportable.rb +14 -0
- data/lib/redd/models/searchable.rb +2 -2
- data/lib/redd/models/self.rb +17 -0
- data/lib/redd/models/session.rb +75 -31
- data/lib/redd/models/submission.rb +309 -56
- data/lib/redd/models/subreddit.rb +330 -103
- data/lib/redd/models/trophy.rb +34 -0
- data/lib/redd/models/user.rb +185 -46
- data/lib/redd/models/wiki_page.rb +37 -16
- data/lib/redd/utilities/error_handler.rb +13 -13
- data/lib/redd/utilities/unmarshaller.rb +7 -5
- data/lib/redd/version.rb +1 -1
- data/redd.gemspec +18 -15
- metadata +82 -16
- data/lib/redd/error.rb +0 -53
- data/lib/redd/models/basic_model.rb +0 -80
- data/lib/redd/models/lazy_model.rb +0 -75
- data/lib/redd/models/mod_mail.rb +0 -142
- data/lib/redd/utilities/stream.rb +0 -61
data/lib/redd/models/access.rb
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require_relative '
|
3
|
+
require_relative 'model'
|
4
4
|
|
5
5
|
module Redd
|
6
6
|
module Models
|
@@ -8,35 +8,47 @@ module Redd
|
|
8
8
|
# @note This model also supports an additional key, called `:created_at` which is a UNIX time
|
9
9
|
# representing the time the access was created. The default value is the time the object was
|
10
10
|
# initialized.
|
11
|
-
class Access <
|
11
|
+
class Access < Model
|
12
12
|
# Create a non-lazily initialized Access.
|
13
|
-
# @param
|
14
|
-
# @param attributes [Hash] the Access's attributes
|
13
|
+
# @param attributes [Hash] the access's attributes
|
15
14
|
# @example
|
16
15
|
# access = Redd::Models::Access.new(access_token: ...)
|
17
|
-
def initialize(
|
18
|
-
|
19
|
-
|
20
|
-
else
|
21
|
-
super(client, attributes)
|
22
|
-
end
|
16
|
+
def initialize(attributes = {})
|
17
|
+
super(nil, attributes)
|
18
|
+
@creation_time = Time.now
|
23
19
|
end
|
24
20
|
|
21
|
+
# Whether the access has expired.
|
22
|
+
# @param grace_period [Integer] the grace period where the model expires early
|
23
|
+
# @return [Boolean] whether the access has expired
|
25
24
|
def expired?(grace_period = 60)
|
26
|
-
|
27
|
-
return false unless @attributes[:expires_in]
|
28
|
-
Time.now.to_i > @attributes[:created_at] + (@attributes[:expires_in] - grace_period)
|
25
|
+
Time.now > read_attribute(:created_at) + read_attribute(:expires_in) - grace_period
|
29
26
|
end
|
30
27
|
|
28
|
+
# @return [Boolean] whether the access can be refreshed
|
31
29
|
def permanent?
|
32
|
-
|
30
|
+
read_attribute(:refresh_token).nil?
|
33
31
|
end
|
34
32
|
|
35
|
-
|
33
|
+
# @!attribute [r] access_token
|
34
|
+
# @return [String] the access token
|
35
|
+
property :access_token
|
36
36
|
|
37
|
-
|
38
|
-
|
39
|
-
|
37
|
+
# @!attribute [r] refresh_token
|
38
|
+
# @return [String] the (optional) refresh token
|
39
|
+
property :refresh_token, :nil
|
40
|
+
|
41
|
+
# @!attribute [r] expires_in
|
42
|
+
# @return [Integer] the number of seconds before the access expires
|
43
|
+
property :expires_in
|
44
|
+
|
45
|
+
# @!attribute [r] created_at
|
46
|
+
# @return [Time] the time the access was created
|
47
|
+
property :created_at, default: ->() { @creation_time }
|
48
|
+
|
49
|
+
# @!attribute [r] scope
|
50
|
+
# @return [Array<String>] the scopes that the user is allowed to access
|
51
|
+
property :scope, with: ->(scope) { scope.split(' ') }
|
40
52
|
end
|
41
53
|
end
|
42
54
|
end
|
data/lib/redd/models/comment.rb
CHANGED
@@ -1,11 +1,12 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require_relative '
|
3
|
+
require_relative 'model'
|
4
4
|
require_relative 'gildable'
|
5
5
|
require_relative 'inboxable'
|
6
6
|
require_relative 'moderatable'
|
7
7
|
require_relative 'postable'
|
8
8
|
require_relative 'replyable'
|
9
|
+
require_relative 'reportable'
|
9
10
|
|
10
11
|
require_relative 'listing'
|
11
12
|
require_relative 'subreddit'
|
@@ -14,47 +15,204 @@ require_relative 'user'
|
|
14
15
|
module Redd
|
15
16
|
module Models
|
16
17
|
# A comment.
|
17
|
-
class Comment <
|
18
|
+
class Comment < Model
|
18
19
|
include Gildable
|
19
20
|
include Inboxable
|
20
21
|
include Moderatable
|
21
22
|
include Postable
|
22
23
|
include Replyable
|
24
|
+
include Reportable
|
23
25
|
|
24
|
-
#
|
25
|
-
#
|
26
|
-
|
27
|
-
# @return [Comment]
|
28
|
-
def self.from_id(client, id)
|
29
|
-
new(client, name: id)
|
30
|
-
end
|
26
|
+
# @!attribute [r] subreddit_id
|
27
|
+
# @return [String] the subreddit fullname
|
28
|
+
property :subreddit_id
|
31
29
|
|
32
|
-
|
30
|
+
# @!attribute [r] approved_at
|
31
|
+
# @return [Time, nil] the time when the comment was approved
|
32
|
+
property :approved_at, from: :approved_at_utc, with: ->(t) { Time.at(t) if t }
|
33
33
|
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
34
|
+
# @!attribute [r] banned_by
|
35
|
+
# @return [String] the user (?) that banned this comment
|
36
|
+
property :banned_by
|
37
|
+
|
38
|
+
# @!attribute [r] removal_reason
|
39
|
+
# @return [String, nil] the reason for comment removal
|
40
|
+
property :removal_reason
|
41
|
+
|
42
|
+
# @!attribute [r] link
|
43
|
+
# @return [Submission] the link that the comment was posted to
|
44
|
+
property :link, from: :link_id, with: ->(id) { Submission.new(client, name: id) }
|
45
|
+
|
46
|
+
# @!attribute [r] upvoted?
|
47
|
+
# @return [Boolean, nil] whether the user liked/disliked this comment
|
48
|
+
property :upvoted?, from: :likes
|
49
|
+
|
50
|
+
# @!attribute [r] replies
|
51
|
+
# @return [Listing<Comment>] the comment replies
|
52
|
+
property :replies, with: ->(l) { Listing.new(client, l[:data]) if l.is_a?(Hash) }
|
53
|
+
|
54
|
+
# @!attribute [r] user_reports
|
55
|
+
# @return [Array<String>] user reports
|
56
|
+
property :user_reports
|
57
|
+
|
58
|
+
# @!attribute [r] saved?
|
59
|
+
# @return [Boolean] whether the submission was saved by the logged-in user
|
60
|
+
property :saved?, from: :saved
|
61
|
+
|
62
|
+
# @!attribute [r] id
|
63
|
+
# @return [String] the comment id
|
64
|
+
property :id
|
65
|
+
|
66
|
+
# @!attribute [r] banned_at
|
67
|
+
# @return [Time, nil] the time when the comment was banned
|
68
|
+
property :banned_at, from: :banned_at_utc, with: ->(t) { Time.at(t) if t }
|
69
|
+
|
70
|
+
# @!attribute [r] gilded
|
71
|
+
# @return [Integer] the number of times the comment was gilded
|
72
|
+
property :gilded
|
73
|
+
|
74
|
+
# @!attribute [r] archived?
|
75
|
+
# @return [Boolean] whether this comment was archived
|
76
|
+
property :archived?, from: :archived
|
77
|
+
|
78
|
+
# @!attribute [r] report_reasons
|
79
|
+
# @return [Array<String>] report reasons
|
80
|
+
property :report_reasons
|
81
|
+
|
82
|
+
# @!attribute [r] author
|
83
|
+
# @return [User] the comment author
|
84
|
+
property :author, with: ->(name) { User.new(client, name: name) }
|
85
|
+
|
86
|
+
# @!attribute [r] can_mod_post?
|
87
|
+
# @return [Boolean] whether the logged-in user can mod post
|
88
|
+
property :can_mod_post?, from: :can_mod_post
|
89
|
+
|
90
|
+
# @!attribute [r] ups
|
91
|
+
# @return [Integer] the comment upvotes
|
92
|
+
# @deprecated use {#score} instead
|
93
|
+
property :ups
|
94
|
+
|
95
|
+
# @!attribute [r] downs
|
96
|
+
# @return [Integer] the comment downvotes
|
97
|
+
# @deprecated is always 0; use {#score} instead
|
98
|
+
property :downs
|
99
|
+
|
100
|
+
# @!attribute [r] parent
|
101
|
+
# @return [Comment, Submission] the comment parent
|
102
|
+
property :parent,
|
103
|
+
from: :parent_id,
|
104
|
+
with: ->(id) { Session.new(client).from_fullnames(id).first }
|
105
|
+
|
106
|
+
# @!attribute [r] score
|
107
|
+
# @return [Integer] the comment score
|
108
|
+
property :score
|
109
|
+
|
110
|
+
# @!attribute [r] approved_by
|
111
|
+
# @return [String] the user that approved the comment
|
112
|
+
property :approved_by
|
113
|
+
|
114
|
+
# @!attribute [r] body
|
115
|
+
# @return [String] the markdown comment body
|
116
|
+
property :body
|
117
|
+
|
118
|
+
# @!attribute [r] body_html
|
119
|
+
# @return [String] the html-rendered version of the body
|
120
|
+
property :body_html
|
121
|
+
|
122
|
+
# @!attribute [r] edited_at
|
123
|
+
# @return [Time, nil] the time when the comment was edited
|
124
|
+
property :edited_at, from: :edited, with: ->(t) { Time.at(t) if t }
|
125
|
+
|
126
|
+
# @!attribute [r] author_flair_css_class
|
127
|
+
# @return [String] the author flair css class
|
128
|
+
property :author_flair_css_class
|
129
|
+
|
130
|
+
# @!attribute [r] collapsed?
|
131
|
+
# @return [Boolean] whether the comment was collapsed
|
132
|
+
property :collapsed?, from: :collapsed
|
133
|
+
|
134
|
+
# @!attribute [r] submitter?
|
135
|
+
# @return [Boolean] whether the comment author is the link submitter
|
136
|
+
property :submitter?, from: :is_submitter
|
137
|
+
|
138
|
+
# @!attribute [r] collapsed_reason
|
139
|
+
# @return [String] the reason for collapse (?)
|
140
|
+
property :collapsed_reason
|
141
|
+
|
142
|
+
# @!attribute [r] stickied?
|
143
|
+
# @return [Boolean] whether the comment was stickied
|
144
|
+
property :stickied?, from: :stickied
|
145
|
+
|
146
|
+
# @!attribute [r] can_gild?
|
147
|
+
# @return [Boolean] whether the comment is gildable
|
148
|
+
property :can_gild?, from: :can_gild
|
149
|
+
|
150
|
+
# @!attribute [r] subreddit
|
151
|
+
# @return [Subreddit] the comment's subreddit
|
152
|
+
property :subreddit, with: ->(n) { Subreddit.new(client, display_name: n) }
|
153
|
+
|
154
|
+
# @!attribute [r] score_hidden
|
155
|
+
# @return [Boolean] whether the comment score is hidden
|
156
|
+
property :score_hidden?, from: :score_hidden
|
157
|
+
|
158
|
+
# @!attribute [r] subreddit_type
|
159
|
+
# @return [String] subreddit type
|
160
|
+
property :subreddit_type
|
161
|
+
|
162
|
+
# @!attribute [r] name
|
163
|
+
# @return [String] the comment fullname
|
164
|
+
property :name
|
165
|
+
|
166
|
+
# @!attribute [r] author_flair_text
|
167
|
+
# @return [String] the author flair text
|
168
|
+
property :author_flair_text
|
169
|
+
|
170
|
+
# @!attribute [r] created_at
|
171
|
+
# @return [String] the time when the model was created
|
172
|
+
property :created_at, from: :created_utc, with: ->(t) { Time.at(t) }
|
173
|
+
|
174
|
+
# @!attribute [r] subreddit_name_prefixed
|
175
|
+
# @return [String] the subreddit name, prefixed with "r/"
|
176
|
+
property :subreddit_name_prefixed
|
177
|
+
|
178
|
+
# @!attribute [r] controversiality
|
179
|
+
# @return [Integer] the comment controversiality
|
180
|
+
property :controversiality
|
181
|
+
|
182
|
+
# @!attribute [r] depth
|
183
|
+
# @return [Integer] the comment depth
|
184
|
+
property :depth
|
185
|
+
|
186
|
+
# @!attribute [r] mod_reports
|
187
|
+
# @return [Array<String>] the moderator reports
|
188
|
+
property :mod_reports
|
189
|
+
|
190
|
+
# @!attribute [r] report_count
|
191
|
+
# @return [Integer] the report count
|
192
|
+
property :report_count, from: :num_reports
|
193
|
+
|
194
|
+
# @!attribute [r] distinguished?
|
195
|
+
# @return [Boolean] whether the comment is distinguished
|
196
|
+
property :distinguished?, from: :distinguished
|
197
|
+
|
198
|
+
private
|
44
199
|
|
45
|
-
def
|
46
|
-
|
200
|
+
def lazer_reload
|
201
|
+
self[:link] ? load_with_comments : load_without_comments
|
47
202
|
end
|
48
203
|
|
49
204
|
def load_with_comments
|
50
|
-
|
51
|
-
|
52
|
-
|
205
|
+
fully_loaded!
|
206
|
+
id = self[:id] || read_attribute(:name).sub('t1_', '')
|
207
|
+
link_id = read_attribute(:link).name.sub('t3_', '')
|
208
|
+
client.get("/comments/#{link_id}/_/#{id}").body[1][:data][:children][0][:data]
|
53
209
|
end
|
54
210
|
|
55
211
|
def load_without_comments
|
56
|
-
id =
|
57
|
-
|
212
|
+
id = self[:id] || read_attribute(:name).sub('t1_', '')
|
213
|
+
response = client.get('/api/info', id: "t1_#{id}").body[:data][:children][0][:data]
|
214
|
+
response.delete(:replies) # Make sure replies are lazy-loaded later.
|
215
|
+
response
|
58
216
|
end
|
59
217
|
end
|
60
218
|
end
|
@@ -1,41 +1,41 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require_relative '
|
4
|
-
require_relative '../utilities/stream'
|
3
|
+
require_relative 'model'
|
5
4
|
|
6
5
|
module Redd
|
7
6
|
module Models
|
8
7
|
# The front page.
|
9
8
|
# FIXME: deal with serious code duplication from Subreddit
|
10
|
-
class FrontPage <
|
9
|
+
class FrontPage < Model
|
11
10
|
# @return [Array<String>] reddit's base wiki pages
|
12
11
|
def wiki_pages
|
13
|
-
|
12
|
+
client.get('/wiki/pages').body[:data]
|
14
13
|
end
|
15
14
|
|
16
15
|
# Get a wiki page by its title.
|
17
16
|
# @param title [String] the page's title
|
18
17
|
# @return [WikiPage]
|
19
18
|
def wiki_page(title)
|
20
|
-
WikiPage.new(
|
19
|
+
WikiPage.new(client, title: title)
|
21
20
|
end
|
22
21
|
|
23
22
|
# Get the appropriate listing.
|
24
23
|
# @param sort [:hot, :new, :top, :controversial, :comments, :rising, :gilded] the type of
|
25
24
|
# listing
|
26
|
-
# @param
|
27
|
-
# @option
|
28
|
-
# @option
|
29
|
-
# @option
|
30
|
-
# @option
|
31
|
-
# @option params [:hour, :day, :week, :month, :year, :all] :time the time period to consider
|
25
|
+
# @param options [Hash] a list of options to send with the request
|
26
|
+
# @option options [String] :after return results after the given fullname
|
27
|
+
# @option options [String] :before return results before the given fullname
|
28
|
+
# @option options [Integer, nil] :limit maximum number of items to return (nil for no limit)
|
29
|
+
# @option options [:hour, :day, :week, :month, :year, :all] :time the time period to consider
|
32
30
|
# when sorting.
|
33
31
|
#
|
34
32
|
# @note The option :time only applies to the top and controversial sorts.
|
35
|
-
# @return [
|
36
|
-
def listing(sort, **
|
37
|
-
|
38
|
-
|
33
|
+
# @return [PaginatedListing<Submission>]
|
34
|
+
def listing(sort, **options)
|
35
|
+
options[:t] = options.delete(:time) if options.key?(:time)
|
36
|
+
PaginatedListing.new(client, options) do |**req_options|
|
37
|
+
client.model(:get, "/#{sort}", options.merge(req_options))
|
38
|
+
end
|
39
39
|
end
|
40
40
|
|
41
41
|
# @!method hot(**params)
|
@@ -47,29 +47,9 @@ module Redd
|
|
47
47
|
# @!method gilded(**params)
|
48
48
|
#
|
49
49
|
# @see #listing
|
50
|
-
%i
|
50
|
+
%i[hot new top controversial comments rising gilded].each do |sort|
|
51
51
|
define_method(sort) { |**params| listing(sort, **params) }
|
52
52
|
end
|
53
|
-
|
54
|
-
# Stream newly submitted posts.
|
55
|
-
def post_stream(**params, &block)
|
56
|
-
params[:limit] ||= 100
|
57
|
-
stream = Utilities::Stream.new do |previous|
|
58
|
-
before = previous ? previous.first.name : nil
|
59
|
-
listing(:new, params.merge(before: before))
|
60
|
-
end
|
61
|
-
block_given? ? stream.stream(&block) : stream.enum_for(:stream)
|
62
|
-
end
|
63
|
-
|
64
|
-
# Stream newly submitted comments.
|
65
|
-
def comment_stream(**params, &block)
|
66
|
-
params[:limit] ||= 100
|
67
|
-
stream = Utilities::Stream.new do |previous|
|
68
|
-
before = previous ? previous.first.name : nil
|
69
|
-
listing(:comments, params.merge(before: before))
|
70
|
-
end
|
71
|
-
block_given? ? stream.stream(&block) : stream.enum_for(:stream)
|
72
|
-
end
|
73
53
|
end
|
74
54
|
end
|
75
55
|
end
|
data/lib/redd/models/gildable.rb
CHANGED
@@ -6,17 +6,27 @@ module Redd
|
|
6
6
|
module Inboxable
|
7
7
|
# Block the user that sent this item.
|
8
8
|
def block
|
9
|
-
|
9
|
+
client.post('/api/block', id: read_attribute(:name))
|
10
|
+
end
|
11
|
+
|
12
|
+
# Collapse the item.
|
13
|
+
def collapse
|
14
|
+
client.post('/api/collapse_message', id: read_attribute(:name))
|
15
|
+
end
|
16
|
+
|
17
|
+
# Uncollapse the item.
|
18
|
+
def uncollapse
|
19
|
+
client.post('/api/uncollapse_message', id: read_attribute(:name))
|
10
20
|
end
|
11
21
|
|
12
22
|
# Mark this thing as read.
|
13
23
|
def mark_as_read
|
14
|
-
|
24
|
+
client.post('/api/read_message', id: read_attribute(:name))
|
15
25
|
end
|
16
26
|
|
17
27
|
# Mark one or more messages as unread.
|
18
28
|
def mark_as_unread
|
19
|
-
|
29
|
+
client.post('/api/unread_message', id: read_attribute(:name))
|
20
30
|
end
|
21
31
|
end
|
22
32
|
end
|
data/lib/redd/models/listing.rb
CHANGED
@@ -1,24 +1,45 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require_relative '
|
3
|
+
require_relative 'model'
|
4
4
|
|
5
5
|
module Redd
|
6
6
|
module Models
|
7
7
|
# A backward-expading listing of items.
|
8
8
|
# @see Stream
|
9
|
-
class Listing <
|
9
|
+
class Listing < Model
|
10
10
|
include Enumerable
|
11
11
|
|
12
|
+
# Create a fully initialized listing.
|
13
|
+
# @param client [APIClient] the api client
|
14
|
+
# @param attributes [Hash] the attribute hash
|
15
|
+
def initialize(client, attributes = {})
|
16
|
+
super
|
17
|
+
fully_loaded!
|
18
|
+
end
|
19
|
+
|
12
20
|
# @return [Array<Comment, Submission, PrivateMessage>] an array representation of self
|
13
|
-
def
|
14
|
-
|
21
|
+
def to_a
|
22
|
+
read_attribute(:children)
|
15
23
|
end
|
24
|
+
alias to_ary to_a
|
16
25
|
|
17
|
-
%i
|
26
|
+
%i[[] each empty? first last].each do |method_name|
|
18
27
|
define_method(method_name) do |*args, &block|
|
19
|
-
|
28
|
+
read_attribute(:children).public_send(method_name, *args, &block)
|
20
29
|
end
|
21
30
|
end
|
31
|
+
|
32
|
+
# @!attribute [r] before
|
33
|
+
# @return [String] the fullname of the item before this listing
|
34
|
+
property :before, :nil
|
35
|
+
|
36
|
+
# @!attribute [r] after
|
37
|
+
# @return [String] the fullname of the item that the next listing will start from
|
38
|
+
property :after, :nil
|
39
|
+
|
40
|
+
# @!attribute [r] children
|
41
|
+
# @return [Array<Model>] the listing's children
|
42
|
+
property :children, :required, with: ->(a) { a.map { |m| client.unmarshal(m) } }
|
22
43
|
end
|
23
44
|
end
|
24
45
|
end
|