spinels-redd 0.9.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 +7 -0
- data/.github/dependabot.yml +7 -0
- data/.github/workflows/ci.yml +52 -0
- data/.gitignore +10 -0
- data/.rspec +3 -0
- data/.rubocop.yml +29 -0
- data/CONTRIBUTING.md +63 -0
- data/Gemfile +6 -0
- data/Guardfile +7 -0
- data/LICENSE.txt +21 -0
- data/README.md +119 -0
- data/Rakefile +12 -0
- data/TODO.md +423 -0
- data/bin/console +127 -0
- data/bin/guard +2 -0
- data/bin/setup +8 -0
- data/docs/guides/.keep +0 -0
- data/docs/tutorials/creating-bots-with-redd.md +101 -0
- data/docs/tutorials/creating-webapps-with-redd.md +124 -0
- data/docs/tutorials/make-a-grammar-bot.md +5 -0
- data/docs/tutorials.md +7 -0
- data/lib/redd/api_client.rb +116 -0
- data/lib/redd/assist/delete_badly_scoring.rb +64 -0
- data/lib/redd/auth_strategies/auth_strategy.rb +68 -0
- data/lib/redd/auth_strategies/script.rb +35 -0
- data/lib/redd/auth_strategies/userless.rb +29 -0
- data/lib/redd/auth_strategies/web.rb +36 -0
- data/lib/redd/client.rb +91 -0
- data/lib/redd/errors.rb +65 -0
- data/lib/redd/middleware.rb +125 -0
- data/lib/redd/models/access.rb +54 -0
- data/lib/redd/models/comment.rb +229 -0
- data/lib/redd/models/front_page.rb +55 -0
- data/lib/redd/models/gildable.rb +13 -0
- data/lib/redd/models/inboxable.rb +33 -0
- data/lib/redd/models/listing.rb +52 -0
- data/lib/redd/models/live_thread.rb +133 -0
- data/lib/redd/models/live_update.rb +46 -0
- data/lib/redd/models/messageable.rb +20 -0
- data/lib/redd/models/mod_action.rb +59 -0
- data/lib/redd/models/model.rb +23 -0
- data/lib/redd/models/moderatable.rb +46 -0
- 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 +96 -0
- data/lib/redd/models/multireddit.rb +104 -0
- data/lib/redd/models/paginated_listing.rb +124 -0
- data/lib/redd/models/postable.rb +83 -0
- data/lib/redd/models/private_message.rb +105 -0
- data/lib/redd/models/replyable.rb +16 -0
- data/lib/redd/models/reportable.rb +14 -0
- data/lib/redd/models/searchable.rb +35 -0
- data/lib/redd/models/self.rb +17 -0
- data/lib/redd/models/session.rb +198 -0
- data/lib/redd/models/submission.rb +405 -0
- data/lib/redd/models/subreddit.rb +670 -0
- data/lib/redd/models/trophy.rb +34 -0
- data/lib/redd/models/user.rb +239 -0
- data/lib/redd/models/wiki_page.rb +56 -0
- data/lib/redd/utilities/error_handler.rb +73 -0
- data/lib/redd/utilities/rate_limiter.rb +21 -0
- data/lib/redd/utilities/unmarshaller.rb +70 -0
- data/lib/redd/version.rb +5 -0
- data/lib/redd.rb +129 -0
- data/lib/spinels-redd.rb +3 -0
- data/logo.png +0 -0
- data/spinels-redd.gemspec +39 -0
- metadata +298 -0
@@ -0,0 +1,670 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative 'model'
|
4
|
+
require_relative 'messageable'
|
5
|
+
require_relative 'searchable'
|
6
|
+
|
7
|
+
module Redd
|
8
|
+
module Models
|
9
|
+
# A subreddit.
|
10
|
+
class Subreddit < Model # rubocop:disable Metrics/ClassLength
|
11
|
+
include Messageable
|
12
|
+
include Searchable
|
13
|
+
|
14
|
+
# A mapping from keys returned by #settings to keys required by #modify_settings
|
15
|
+
SETTINGS_MAP = {
|
16
|
+
subreddit_type: :type,
|
17
|
+
language: :lang,
|
18
|
+
content_options: :link_type,
|
19
|
+
default_set: :allow_top,
|
20
|
+
header_hover_text: :'header-title'
|
21
|
+
}
|
22
|
+
|
23
|
+
# @!group Listings
|
24
|
+
|
25
|
+
# Get the appropriate listing.
|
26
|
+
# @param sort [:hot, :new, :top, :controversial, :comments, :rising, :gilded] the type of
|
27
|
+
# listing
|
28
|
+
# @param options [Hash] a list of options to send with the request
|
29
|
+
# @option options [String] :after return results after the given fullname
|
30
|
+
# @option options [String] :before return results before the given fullname
|
31
|
+
# @option options [Integer, nil] :limit maximum number of items to return (nil for no limit)
|
32
|
+
# @option options [:hour, :day, :week, :month, :year, :all] :time the time period to consider
|
33
|
+
# when sorting
|
34
|
+
#
|
35
|
+
# @note The option :time only applies to the top and controversial sorts.
|
36
|
+
# @return [Listing<Submission, Comment>]
|
37
|
+
def listing(sort, **options)
|
38
|
+
options[:t] = options.delete(:time) if options.key?(:time)
|
39
|
+
PaginatedListing.new(client, **options) do |**req_options|
|
40
|
+
client.model(
|
41
|
+
:get, "/r/#{read_attribute(:display_name)}/#{sort}", options.merge(req_options)
|
42
|
+
)
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
# @!method hot(**options)
|
47
|
+
# @!method new(**options)
|
48
|
+
# @!method top(**options)
|
49
|
+
# @!method controversial(**options)
|
50
|
+
# @!method comments(**options)
|
51
|
+
# @!method rising(**options)
|
52
|
+
# @!method gilded(**options)
|
53
|
+
#
|
54
|
+
# @see #listing
|
55
|
+
%i[hot new top controversial comments rising gilded].each do |sort|
|
56
|
+
define_method(sort) { |**options| listing(sort, **options) }
|
57
|
+
end
|
58
|
+
|
59
|
+
# @!endgroup
|
60
|
+
# @!group Moderator Listings
|
61
|
+
|
62
|
+
# Get the appropriate moderator listing.
|
63
|
+
# @param type [:reports, :spam, :modqueue, :unmoderated, :edited] the type of listing
|
64
|
+
# @param params [Hash] a list of params to send with the request
|
65
|
+
# @option params [String] :after return results after the given fullname
|
66
|
+
# @option params [String] :before return results before the given fullname
|
67
|
+
# @option params [Integer] :count the number of items already seen in the listing
|
68
|
+
# @option params [1..100] :limit the maximum number of things to return
|
69
|
+
# @option params [:links, :comments] :only the type of objects required
|
70
|
+
#
|
71
|
+
# @return [Listing<Submission, Comment>]
|
72
|
+
def moderator_listing(type, **params)
|
73
|
+
client.model(:get, "/r/#{read_attribute(:display_name)}/about/#{type}", params)
|
74
|
+
end
|
75
|
+
|
76
|
+
# @!method reports(**params)
|
77
|
+
# @!method spam(**params)
|
78
|
+
# @!method modqueue(**params)
|
79
|
+
# @!method unmoderated(**params)
|
80
|
+
# @!method edited(**params)
|
81
|
+
#
|
82
|
+
# @see #moderator_listing
|
83
|
+
%i[reports spam modqueue unmoderated edited].each do |type|
|
84
|
+
define_method(type) { |**params| moderator_listing(type, **params) }
|
85
|
+
end
|
86
|
+
|
87
|
+
# @!endgroup
|
88
|
+
# @!group Relationship Listings
|
89
|
+
|
90
|
+
# Get the appropriate relationship listing.
|
91
|
+
# @param type [:banned, :muted, :wikibanned, :contributors, :wikicontributors, :moderators]
|
92
|
+
# the type of listing
|
93
|
+
# @param params [Hash] a list of params to send with the request
|
94
|
+
# @option params [String] :after return results after the given fullname
|
95
|
+
# @option params [String] :before return results before the given fullname
|
96
|
+
# @option params [Integer] :count the number of items already seen in the listing
|
97
|
+
# @option params [1..100] :limit the maximum number of things to return
|
98
|
+
# @option params [String] :user find a specific user
|
99
|
+
#
|
100
|
+
# @return [Array<Hash>]
|
101
|
+
def relationship_listing(type, **params)
|
102
|
+
# TODO: add methods to determine if a certain user was banned/muted/etc
|
103
|
+
# TODO: return User types?
|
104
|
+
user_list = client.get("/r/#{read_attribute(:display_name)}/about/#{type}", params).body
|
105
|
+
user_list[:data][:children]
|
106
|
+
end
|
107
|
+
|
108
|
+
# @!method banned(**params)
|
109
|
+
# @!method muted(**params)
|
110
|
+
# @!method wikibanned(**params)
|
111
|
+
# @!method contributors(**params)
|
112
|
+
# @!method wikicontributors(**params)
|
113
|
+
# @!method moderators(**params)
|
114
|
+
#
|
115
|
+
# @see #relationship_listing
|
116
|
+
%i[banned muted wikibanned contributors wikicontributors moderators].each do |type|
|
117
|
+
define_method(type) { |**params| relationship_listing(type, **params) }
|
118
|
+
end
|
119
|
+
|
120
|
+
# @!endgroup
|
121
|
+
|
122
|
+
# @return [Array<String>] the subreddit's wiki pages
|
123
|
+
def wiki_pages
|
124
|
+
client.get("/r/#{read_attribute(:display_name)}/wiki/pages").body[:data]
|
125
|
+
end
|
126
|
+
|
127
|
+
# Get a wiki page by its title.
|
128
|
+
# @param title [String] the page's title
|
129
|
+
# @return [WikiPage]
|
130
|
+
def wiki_page(title)
|
131
|
+
WikiPage.new(client, title: title, subreddit: self)
|
132
|
+
end
|
133
|
+
|
134
|
+
# Search a subreddit.
|
135
|
+
# @param query [String] the search query
|
136
|
+
# @param params [Hash] refer to {Searchable} to see search parameters
|
137
|
+
# @see Searchable#search
|
138
|
+
def search(query, **params)
|
139
|
+
restricted_params = { restrict_to: read_attribute(:display_name) }.merge(params)
|
140
|
+
super(query, restricted_params)
|
141
|
+
end
|
142
|
+
|
143
|
+
# Submit a link or a text post to the subreddit.
|
144
|
+
# @note If both text and url are provided, url takes precedence.
|
145
|
+
#
|
146
|
+
# @param title [String] the title of the submission
|
147
|
+
# @param text [String] the text of the self-post
|
148
|
+
# @param url [String] the URL of the link
|
149
|
+
# @param resubmit [Boolean] whether to post a link to the subreddit despite it having been
|
150
|
+
# posted there before (you monster)
|
151
|
+
# @param sendreplies [Boolean] whether to send the replies to your inbox
|
152
|
+
# @return [Submission] The returned object (url, id and name)
|
153
|
+
def submit(title, text: nil, url: nil, resubmit: false, sendreplies: true)
|
154
|
+
params = {
|
155
|
+
title: title, sr: read_attribute(:display_name),
|
156
|
+
resubmit: resubmit, sendreplies: sendreplies
|
157
|
+
}
|
158
|
+
params[:kind] = url ? 'link' : 'self'
|
159
|
+
params[:url] = url if url
|
160
|
+
params[:text] = text if text
|
161
|
+
Submission.new(client, client.post('/api/submit', params).body[:json][:data])
|
162
|
+
end
|
163
|
+
|
164
|
+
# Compose a message to the moderators of a subreddit.
|
165
|
+
#
|
166
|
+
# @param subject [String] the subject of the message
|
167
|
+
# @param text [String] the message text
|
168
|
+
# @param from [Subreddit, nil] the subreddit to send the message on behalf of
|
169
|
+
def send_message(subject:, text:, from: nil)
|
170
|
+
super(to: "/r/#{read_attribute(:display_name)}", subject: subject, text: text, from: from)
|
171
|
+
end
|
172
|
+
|
173
|
+
# Set the flair for a link or a user for this subreddit.
|
174
|
+
# @param thing [User, Submission] the object whose flair to edit
|
175
|
+
# @param text [String] a string no longer than 64 characters
|
176
|
+
# @param css_class [String] the css class to assign to the flair
|
177
|
+
def set_flair(thing, text, css_class: nil)
|
178
|
+
key = thing.is_a?(User) ? :name : :link
|
179
|
+
params = { :text => text, key => thing.name }
|
180
|
+
params[:css_class] = css_class if css_class
|
181
|
+
client.post("/r/#{read_attribute(:display_name)}/api/flair", params)
|
182
|
+
end
|
183
|
+
|
184
|
+
# Get a listing of all user flairs.
|
185
|
+
# @param params [Hash] a list of params to send with the request
|
186
|
+
# @option params [String] :after return results after the given fullname
|
187
|
+
# @option params [String] :before return results before the given fullname
|
188
|
+
# @option params [Integer] :count the number of items already seen in the listing
|
189
|
+
# @option params [String] :name prefer {#get_flair}
|
190
|
+
# @option params [:links, :comments] :only the type of objects required
|
191
|
+
#
|
192
|
+
# @return [Listing<Hash<Symbol, String>>]
|
193
|
+
def flair_listing(**params)
|
194
|
+
res = client.get("/r/#{read_attribute(:display_name)}/api/flairlist", params).body
|
195
|
+
Listing.new(client, children: res[:users], before: res[:prev], after: res[:next])
|
196
|
+
end
|
197
|
+
|
198
|
+
# Get the user's flair data.
|
199
|
+
# @param user [User] the user whose flair to fetch
|
200
|
+
# @return [Hash, nil]
|
201
|
+
def get_flair(user)
|
202
|
+
# We have to do this because reddit returns all flairs if given a nonexistent user
|
203
|
+
flair = flair_listing(name: user.name).first
|
204
|
+
return flair if flair && flair[:user].casecmp(user.name).zero?
|
205
|
+
|
206
|
+
nil
|
207
|
+
end
|
208
|
+
|
209
|
+
# Remove the flair from a user
|
210
|
+
# @param thing [User, String] a User from which to remove flair
|
211
|
+
def delete_flair(user)
|
212
|
+
name = user.is_a?(User) ? user.name : user
|
213
|
+
client.post("/r/#{read_attribute(:display_name)}/api/deleteflair", name: name)
|
214
|
+
end
|
215
|
+
|
216
|
+
# Set a Submission's or User's flair based on a flair template id.
|
217
|
+
# @param thing [User, Submission] an object to assign a template to
|
218
|
+
# @param template_id [String] the UUID of the flair template to assign
|
219
|
+
# @param text [String] optional text for the flair
|
220
|
+
def set_flair_template(thing, template_id, text: nil)
|
221
|
+
key = thing.is_a?(User) ? :name : :link
|
222
|
+
params = { key => thing.name, flair_template_id: template_id, text: text }
|
223
|
+
client.post("/r/#{read_attribute(:display_name)}/api/selectflair", params)
|
224
|
+
end
|
225
|
+
|
226
|
+
# Add the subreddit to the user's subscribed subreddits.
|
227
|
+
def subscribe(action: :sub, skip_initial_defaults: false)
|
228
|
+
client.post(
|
229
|
+
'/api/subscribe',
|
230
|
+
sr_name: read_attribute(:display_name),
|
231
|
+
action: action,
|
232
|
+
skip_initial_defaults: skip_initial_defaults
|
233
|
+
)
|
234
|
+
end
|
235
|
+
|
236
|
+
# Remove the subreddit from the user's subscribed subreddits.
|
237
|
+
def unsubscribe
|
238
|
+
subscribe(action: :unsub)
|
239
|
+
end
|
240
|
+
|
241
|
+
# Get the subreddit's CSS.
|
242
|
+
# @return [String, nil] the stylesheet or nil if no stylesheet exists
|
243
|
+
def stylesheet
|
244
|
+
url = client.get("/r/#{read_attribute(:display_name)}/stylesheet").headers['location']
|
245
|
+
HTTP.get(url).body.to_s
|
246
|
+
rescue Errors::NotFound
|
247
|
+
nil
|
248
|
+
end
|
249
|
+
|
250
|
+
# Edit the subreddit's stylesheet.
|
251
|
+
# @param text [String] the updated CSS
|
252
|
+
# @param reason [String] the reason for modifying the stylesheet
|
253
|
+
def update_stylesheet(text, reason: nil)
|
254
|
+
params = { op: 'save', stylesheet_contents: text }
|
255
|
+
params[:reason] = reason if reason
|
256
|
+
client.post("/r/#{read_attribute(:display_name)}/api/subreddit_stylesheet", params)
|
257
|
+
end
|
258
|
+
|
259
|
+
# @return [Hash] the subreddit's settings
|
260
|
+
def settings
|
261
|
+
client.get("/r/#{read_attribute(:display_name)}/about/edit").body[:data]
|
262
|
+
end
|
263
|
+
|
264
|
+
# Modify the subreddit's settings.
|
265
|
+
# @param params [Hash] the settings to change
|
266
|
+
# @see https://www.reddit.com/dev/api#POST_api_site_admin
|
267
|
+
def modify_settings(**params)
|
268
|
+
full_params = settings.merge(params)
|
269
|
+
full_params[:sr] = read_attribute(:name)
|
270
|
+
SETTINGS_MAP.each { |src, dest| full_params[dest] = full_params.delete(src) }
|
271
|
+
client.post('/api/site_admin', full_params)
|
272
|
+
end
|
273
|
+
|
274
|
+
# Get the moderation log.
|
275
|
+
# @param params [Hash] a list of params to send with the request
|
276
|
+
# @option params [String] :after return results after the given fullname
|
277
|
+
# @option params [String] :before return results before the given fullname
|
278
|
+
# @option params [Integer] :count the number of items already seen in the listing
|
279
|
+
# @option params [1..100] :limit the maximum number of things to return
|
280
|
+
# @option params [String] :type filter events to a specific type
|
281
|
+
#
|
282
|
+
# @return [Listing<ModAction>]
|
283
|
+
def mod_log(**params)
|
284
|
+
client.model(:get, "/r/#{read_attribute(:display_name)}/about/log", params)
|
285
|
+
end
|
286
|
+
|
287
|
+
# Invite a user to moderate this subreddit.
|
288
|
+
# @param user [User] the user to invite
|
289
|
+
# @param permissions [String] the permission string to invite the user with
|
290
|
+
def invite_moderator(user, permissions: '+all')
|
291
|
+
add_relationship(type: 'moderator_invite', name: user.name, permissions: permissions)
|
292
|
+
end
|
293
|
+
|
294
|
+
# Take back a moderator request.
|
295
|
+
# @param user [User] the requested user
|
296
|
+
def uninvite_moderator(user)
|
297
|
+
remove_relationship(type: 'moderator_invite', name: user.name)
|
298
|
+
end
|
299
|
+
|
300
|
+
# Accept an invite to become a moderator of this subreddit.
|
301
|
+
def accept_moderator_invite
|
302
|
+
client.post("/r/#{read_attribute(:display_name)}/api/accept_moderator_invite")
|
303
|
+
end
|
304
|
+
|
305
|
+
# Dethrone a moderator.
|
306
|
+
# @param user [User] the user to remove
|
307
|
+
def remove_moderator(user)
|
308
|
+
remove_relationship(type: 'moderator', name: user.name)
|
309
|
+
end
|
310
|
+
|
311
|
+
# Leave from being a moderator on a subreddit.
|
312
|
+
def leave_moderator
|
313
|
+
client.post('/api/leavemoderator', id: read_attribute(:name))
|
314
|
+
end
|
315
|
+
|
316
|
+
# Add a contributor to the subreddit.
|
317
|
+
# @param user [User] the user to add
|
318
|
+
def add_contributor(user)
|
319
|
+
add_relationship(type: 'contributor', name: user.name)
|
320
|
+
end
|
321
|
+
|
322
|
+
# Remove a contributor from the subreddit.
|
323
|
+
# @param user [User] the user to remove
|
324
|
+
def remove_contributor(user)
|
325
|
+
remove_relationship(type: 'contributor', name: user.name)
|
326
|
+
end
|
327
|
+
|
328
|
+
# Leave from being a contributor on a subreddit.
|
329
|
+
def leave_contributor
|
330
|
+
client.post('/api/leavecontributor', id: read_attribute(:name))
|
331
|
+
end
|
332
|
+
|
333
|
+
# Ban a user from a subreddit.
|
334
|
+
# @param user [User] the user to ban
|
335
|
+
# @param params [Hash] additional options to supply with the request
|
336
|
+
# @option params [String] :ban_reason the reason for the ban
|
337
|
+
# @option params [String] :ban_message a message sent to the banned user
|
338
|
+
# @option params [String] :note a note that only moderators can see
|
339
|
+
# @option params [Integer] :duration the number of days to ban the user (if temporary)
|
340
|
+
def ban(user, **params)
|
341
|
+
add_relationship(type: 'banned', name: user.name, **params)
|
342
|
+
end
|
343
|
+
|
344
|
+
# Remove a ban on a user.
|
345
|
+
# @param user [User] the user to unban
|
346
|
+
def unban(user)
|
347
|
+
remove_relationship(type: 'banned', name: user.name)
|
348
|
+
end
|
349
|
+
|
350
|
+
# Allow a user to contribute to the wiki.
|
351
|
+
# @param user [User] the user to add
|
352
|
+
def add_wiki_contributor(user)
|
353
|
+
add_relationship(type: 'wikicontributor', name: user.name)
|
354
|
+
end
|
355
|
+
|
356
|
+
# No longer allow a user to contribute to the wiki.
|
357
|
+
# @param user [User] the user to remove
|
358
|
+
def remove_wiki_contributor(user)
|
359
|
+
remove_relationship(type: 'wikicontributor', name: user.name)
|
360
|
+
end
|
361
|
+
|
362
|
+
# Ban a user from contributing to the wiki.
|
363
|
+
# @param user [User] the user to ban
|
364
|
+
# @param params [Hash] additional options to supply with the request
|
365
|
+
# @option params [String] :ban_reason the reason for the ban (not sure this matters)
|
366
|
+
# @option params [String] :note a note that only moderators can see
|
367
|
+
# @option params [Integer] :duration the number of days to ban the user (if temporary)
|
368
|
+
def ban_wiki_contributor(user, **params)
|
369
|
+
add_relationship(type: 'wikibanned', name: user.name, **params)
|
370
|
+
end
|
371
|
+
|
372
|
+
# No longer ban a user from contributing to the wiki.
|
373
|
+
# @param user [User] the user to unban
|
374
|
+
def unban_wiki_contributor(user)
|
375
|
+
remove_relationship(type: 'wikibanned', name: user.name)
|
376
|
+
end
|
377
|
+
|
378
|
+
# Upload a subreddit-specific image.
|
379
|
+
# @param file [String, IO] the image file to upload
|
380
|
+
# @param image_type ['jpg', 'png'] the image type
|
381
|
+
# @param upload_type ['img', 'header', 'icon', 'banner'] where to upload the image
|
382
|
+
# @param image_name [String] the name of the image (if upload_type is 'img')
|
383
|
+
# @return [String] the url of the uploaded file
|
384
|
+
def upload_image(file:, image_type:, upload_type:, image_name: nil)
|
385
|
+
file_data = HTTP::FormData::File.new(file)
|
386
|
+
params = { img_type: image_type, upload_type: upload_type, file: file_data }
|
387
|
+
params[:name] = image_name if upload_type.to_s == 'img'
|
388
|
+
client.post("/r/#{read_attribute(:display_name)}/api/upload_sr_img", params).body[:img_src]
|
389
|
+
end
|
390
|
+
|
391
|
+
# Delete a subreddit-specific image.
|
392
|
+
# @param upload_type ['img', 'header', 'icon', 'banner'] the image to delete
|
393
|
+
# @param image_name [String] the image name (if upload_type is 'img')
|
394
|
+
def delete_image(upload_type:, image_name: nil)
|
395
|
+
unless %w[img header icon banner].include?(upload_type)
|
396
|
+
raise ArgumentError, 'unknown upload_type'
|
397
|
+
end
|
398
|
+
|
399
|
+
params = {}
|
400
|
+
params[:name] = image_name if upload_type.to_s == 'img'
|
401
|
+
client.post("/r/#{read_attribute(:display_name)}/api/delete_sr_#{upload_type}", params)
|
402
|
+
end
|
403
|
+
|
404
|
+
# @!attribute [r] display_name
|
405
|
+
# @return [String] the subreddit's name
|
406
|
+
property :display_name, :required
|
407
|
+
|
408
|
+
# @!attribute [r] id
|
409
|
+
# @return [String] the subreddit's base36 id.
|
410
|
+
property :id
|
411
|
+
|
412
|
+
# @!attribute [r] name
|
413
|
+
# @return [String] the subreddit's t5_ fullname.
|
414
|
+
property :name
|
415
|
+
|
416
|
+
# @!attribute [r] title
|
417
|
+
# @return [String] the subreddit's page title text.
|
418
|
+
property :title
|
419
|
+
|
420
|
+
# @!attribute [r] user_is_contributor?
|
421
|
+
# @return [Boolean] whether the logged-in user is the subreddit's contributor
|
422
|
+
property :user_is_contributor?, from: :user_is_contributor
|
423
|
+
|
424
|
+
# @!attribute [r] banner_image
|
425
|
+
# @return [String] the url to the subreddit's banner image
|
426
|
+
property :banner_image, from: :banner_img
|
427
|
+
|
428
|
+
# @!attribute [r] banner_size
|
429
|
+
# @return [Array<Integer>] the banner dimensions
|
430
|
+
property :banner_size
|
431
|
+
|
432
|
+
# @!attribute [r] user_flair_text
|
433
|
+
# @return [String] the logged-in user's flair text
|
434
|
+
property :user_flair_text
|
435
|
+
|
436
|
+
# @!attribute [r] user_flair_css_class
|
437
|
+
# @return [String] the css class for the user's flair
|
438
|
+
property :user_flair_css_class
|
439
|
+
|
440
|
+
# @!attribute [r] user_is_banned
|
441
|
+
# @return [Boolean] whether the logged-in user is banned from this subreddit
|
442
|
+
property :user_is_banned?, from: :user_is_banned
|
443
|
+
|
444
|
+
# @!attribute [r] user_is_moderator?
|
445
|
+
# @return [Boolean] whether the logged-in user is a moderator of the subreddit
|
446
|
+
property :user_is_moderator?, from: :user_is_moderator
|
447
|
+
|
448
|
+
# @!attribute [r] user_is_muted?
|
449
|
+
# @return [Boolean] whether the logged-in user is muted from the subreddit
|
450
|
+
property :user_is_muted?, from: :user_is_muted
|
451
|
+
|
452
|
+
# @!attribute [r] user_is_subscriber
|
453
|
+
# @return [Boolean] whether the logged-in user is a subscriber to the subreddit
|
454
|
+
property :user_is_subscriber?, from: :user_is_subscriber
|
455
|
+
|
456
|
+
# @!attribute [r] wiki_enabled?
|
457
|
+
# @return [Boolean] whether the wiki is enabled for this subreddit
|
458
|
+
property :wiki_enabled?, from: :wiki_enabled
|
459
|
+
|
460
|
+
# @!attribute [r] show_media?
|
461
|
+
# @return [Boolean] whether media is shown
|
462
|
+
property :show_media?, from: :show_media
|
463
|
+
|
464
|
+
# @!attribute [r] description
|
465
|
+
# @return [String] the subreddit description
|
466
|
+
property :description
|
467
|
+
|
468
|
+
# @!attribute [r] description_html
|
469
|
+
# @return [String] the html-rendered version of the subreddit description
|
470
|
+
property :description_html
|
471
|
+
|
472
|
+
# @!attribute [r] submit_text
|
473
|
+
# @return [String] the submit text
|
474
|
+
property :submit_text
|
475
|
+
|
476
|
+
# @!attribute [r] submit_text_html
|
477
|
+
# @return [String] the submit text html
|
478
|
+
property :submit_text_html
|
479
|
+
|
480
|
+
# @!attribute [r] can_set_flair?
|
481
|
+
# @return [Boolean] whether the user can set the flair in the subreddit
|
482
|
+
property :can_set_flair?, from: :user_can_flair_in_sr
|
483
|
+
|
484
|
+
# @!attribute [r] header_img
|
485
|
+
# @return [String] the url to the header image
|
486
|
+
property :header_image, from: :header_img
|
487
|
+
|
488
|
+
# @!attribute [r] header_size
|
489
|
+
# @return [Array<Integer>] the dimensions of the header image
|
490
|
+
property :header_size
|
491
|
+
|
492
|
+
# @!attribute [r] collapse_deleted_comments?
|
493
|
+
# @return [Boolean] whether deleted comments are collapsed
|
494
|
+
property :collapse_deleted_comments?, from: :collapse_deleted_comments
|
495
|
+
|
496
|
+
# @!attribute [r] user_has_favorited?
|
497
|
+
# @return [Boolean] whether the user has favourited the subreddit
|
498
|
+
property :user_has_favorited?, from: :user_has_favorited
|
499
|
+
|
500
|
+
# @!attribute [r] public_description
|
501
|
+
# @return [String] the public description
|
502
|
+
property :public_description
|
503
|
+
|
504
|
+
# @!attribute [r] public_description_html
|
505
|
+
# @return [String] the html-rendered version of the public description
|
506
|
+
property :public_description_html
|
507
|
+
|
508
|
+
# @!attribute [r] over_18?
|
509
|
+
# @return [Boolean] whether the user is marked as over 18
|
510
|
+
property :over_18?, from: :over18
|
511
|
+
|
512
|
+
# @!attribute [r] spoilers_enabled?
|
513
|
+
# @return [Boolean] whether the subreddit has spoilers enabled
|
514
|
+
property :spoilers_enabled?, from: :spoilers_enabled
|
515
|
+
|
516
|
+
# @!attribute [r] icon_size
|
517
|
+
# @return [Array<Integer>] the subreddit icon size
|
518
|
+
property :icon_size
|
519
|
+
|
520
|
+
# @!attribute [r] audience_target
|
521
|
+
# @return [String] no clue what this means
|
522
|
+
property :audience_target
|
523
|
+
|
524
|
+
# @!attribute [r] suggested_comment_sort
|
525
|
+
# @return [String] the suggested comment sort
|
526
|
+
property :suggested_comment_sort
|
527
|
+
|
528
|
+
# @!attribute [r] active_user_count
|
529
|
+
# @return [Integer] the number of active users
|
530
|
+
property :active_user_count
|
531
|
+
|
532
|
+
# @!attribute [r] accounts_active
|
533
|
+
# @return [Integer] the number of active accounts
|
534
|
+
property :accounts_active
|
535
|
+
|
536
|
+
# @!attribute [r] subscribers
|
537
|
+
# @return [Integer] the subreddit's subscriber count
|
538
|
+
property :subscribers
|
539
|
+
|
540
|
+
# @!attribute [r] icon_image
|
541
|
+
# @return [String] the url to the icon image
|
542
|
+
property :icon_image, from: :icon_img
|
543
|
+
|
544
|
+
# @!attribute [r] header_title
|
545
|
+
# @return [String] the header's "title" attribute (i.e. mouseover text)
|
546
|
+
property :header_title
|
547
|
+
|
548
|
+
# @!attribute [r] display_name_prefixed
|
549
|
+
# @return [String] the display name, prefixed with a "r/".
|
550
|
+
# @deprecated not really deprecated, but prefer just using the display_name directly
|
551
|
+
property :display_name_prefixed, default: -> { "r/#{read_attribute(:display_name)}" }
|
552
|
+
|
553
|
+
# @!attribute [r] submit_link_label
|
554
|
+
# @return [String] the label text on the submit link button
|
555
|
+
property :submit_link_label
|
556
|
+
|
557
|
+
# @!attribute [r] submit_text_label
|
558
|
+
# @return [String] the label text on the submit text button
|
559
|
+
property :submit_text_label
|
560
|
+
|
561
|
+
# @!attribute [r] public_traffic
|
562
|
+
# @return [Boolean] whether the traffic page is public
|
563
|
+
property :public_traffic?, from: :public_traffic
|
564
|
+
|
565
|
+
# @!attribute [r] key_color
|
566
|
+
# @return [String] a hex color code, not sure what this does
|
567
|
+
property :key_color
|
568
|
+
|
569
|
+
# @!attribute [r] user_flair_visible?
|
570
|
+
# @return [Boolean] whether the user's flair is shown to others
|
571
|
+
property :user_flair_visible?, from: :user_sr_flair_enabled
|
572
|
+
|
573
|
+
# @!attribute [r] user_flair_enabled?
|
574
|
+
# @return [Boolean] whether the subreddit allows setting user flairs
|
575
|
+
property :user_flair_enabled?, from: :user_flair_enabled_in_sr
|
576
|
+
|
577
|
+
# @!attribute [r] language
|
578
|
+
# @return [String] the subreddit's language code
|
579
|
+
property :language, from: :lang
|
580
|
+
|
581
|
+
# @!attribute [r] enrolled_in_new_modmail?
|
582
|
+
# @return [Boolean] whether the subreddit is enrolled in the new modmail
|
583
|
+
property :enrolled_in_new_modmail?, from: :is_enrolled_in_new_modmail
|
584
|
+
|
585
|
+
# @!attribute [r] whitelist_status
|
586
|
+
# @return [String] not sure what this does, something to do with ads?
|
587
|
+
property :whitelist_status
|
588
|
+
|
589
|
+
# @!attribute [r] url
|
590
|
+
# @return [String] the subreddit's **relative** url (e.g. /r/Redd/)
|
591
|
+
property :url, default: -> { "/r/#{read_attribute(:display_name)}/" }
|
592
|
+
|
593
|
+
# @!attribute [r] quarantined?
|
594
|
+
# @return [Boolean] whether the subreddit is quarantined
|
595
|
+
property :quarantined?, from: :quarantine
|
596
|
+
|
597
|
+
# @!attribute [r] hide_ads?
|
598
|
+
# @return [Boolean] whether ads are hidden?
|
599
|
+
property :hide_ads?, from: :hide_ads
|
600
|
+
|
601
|
+
# @!attribute [r] created_at
|
602
|
+
# @return [Time] the time the subreddit was created
|
603
|
+
property :created_at, from: :created_utc, with: ->(t) { Time.at(t) }
|
604
|
+
|
605
|
+
# @!attribute [r] accounts_active_is_fuzzed
|
606
|
+
# @return [Boolean] whether active accounts is fuzzed
|
607
|
+
property :accounts_active_is_fuzzed?, from: :accounts_active_is_fuzzed
|
608
|
+
|
609
|
+
# @!attribute [r] advertiser_category
|
610
|
+
# @return [String] the advertiser category
|
611
|
+
property :advertiser_category
|
612
|
+
|
613
|
+
# @!attribute [r] subreddit_theme_enabled?
|
614
|
+
# @return [Boolean] whether the subreddit theme is enabled
|
615
|
+
property :subreddit_theme_enabled?, from: :user_sr_theme_enabled
|
616
|
+
|
617
|
+
# @!attribute [r] link_flair_enabled
|
618
|
+
# @return [Boolean] whether link flairs are enabled
|
619
|
+
property :link_flair_enabled?, from: :link_flair_enabled
|
620
|
+
|
621
|
+
# @!attribute [r] allow_images?
|
622
|
+
# @return [Boolean] whether images are allowed
|
623
|
+
property :allow_images?, from: :allow_images
|
624
|
+
|
625
|
+
# @!attribute [r] show_media_preview
|
626
|
+
# @return [Boolean] whether media previews are shown
|
627
|
+
property :show_media_preview?, from: :show_media_preview
|
628
|
+
|
629
|
+
# @!attribute [r] comment_score_hide_mins
|
630
|
+
# @return [Integer] the number of minutes the comment score is hidden
|
631
|
+
property :comment_score_hide_mins
|
632
|
+
|
633
|
+
# @!attribute [r] subreddit_type
|
634
|
+
# @return [String] whether it's a public, private, or gold-restricted subreddit
|
635
|
+
property :subreddit_type
|
636
|
+
|
637
|
+
# @!attribute [r] submission_type
|
638
|
+
# @return [String] the allowed submission type (?)
|
639
|
+
property :submission_type
|
640
|
+
|
641
|
+
private
|
642
|
+
|
643
|
+
def lazer_reload
|
644
|
+
fully_loaded!
|
645
|
+
exists_locally?(:name) ? load_from_fullname : load_from_display_name
|
646
|
+
end
|
647
|
+
|
648
|
+
# Return the attributes using the display_name (best option).
|
649
|
+
def load_from_display_name
|
650
|
+
client.get("/r/#{read_attribute(:display_name)}/about").body[:data]
|
651
|
+
end
|
652
|
+
|
653
|
+
# Load the attributes using the subreddit fullname (not so best option).
|
654
|
+
def load_from_fullname
|
655
|
+
response = client.get('/api/info', id: read_attribute(:name))
|
656
|
+
raise Errors::NotFound.new(response) if response.body[:data][:children].empty?
|
657
|
+
|
658
|
+
response.body[:data][:children][0][:data]
|
659
|
+
end
|
660
|
+
|
661
|
+
def add_relationship(**params)
|
662
|
+
client.post("/r/#{read_attribute(:display_name)}/api/friend", params)
|
663
|
+
end
|
664
|
+
|
665
|
+
def remove_relationship(**params)
|
666
|
+
client.post("/r/#{read_attribute(:display_name)}/api/unfriend", params)
|
667
|
+
end
|
668
|
+
end
|
669
|
+
end
|
670
|
+
end
|
@@ -0,0 +1,34 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative 'model'
|
4
|
+
|
5
|
+
module Redd
|
6
|
+
module Models
|
7
|
+
# A user trophy.
|
8
|
+
class Trophy < Model
|
9
|
+
# @!attribute [r] icon_70px
|
10
|
+
# @return [String] the url for a 70x70 thumbnail icon
|
11
|
+
property :icon_70px, from: :icon_70
|
12
|
+
|
13
|
+
# @!attribute [r] icon_40px
|
14
|
+
# @return [String] the url for a 40x40 thumbnail icon
|
15
|
+
property :icon_40px, from: :icon_40
|
16
|
+
|
17
|
+
# @!attribute [r] name
|
18
|
+
# @return [String] the name of the trophy
|
19
|
+
property :name
|
20
|
+
|
21
|
+
# @!attribute [r] id
|
22
|
+
# @return [String] the trophy id
|
23
|
+
property :id
|
24
|
+
|
25
|
+
# @!attribute [r] award_id
|
26
|
+
# @return [String]
|
27
|
+
property :award_id
|
28
|
+
|
29
|
+
# @!attribute [r] description
|
30
|
+
# @return [String] the trophy description
|
31
|
+
property :description
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|