neonredd 0.0.1

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.
Files changed (53) hide show
  1. checksums.yaml +7 -0
  2. data/Gemfile +4 -0
  3. data/LICENSE.md +22 -0
  4. data/README.md +1 -0
  5. data/Rakefile +5 -0
  6. data/Redd.LICENSE.md +22 -0
  7. data/RedditKit.LICENSE.md +9 -0
  8. data/lib/redd/access.rb +76 -0
  9. data/lib/redd/clients/base/account.rb +20 -0
  10. data/lib/redd/clients/base/identity.rb +22 -0
  11. data/lib/redd/clients/base/none.rb +27 -0
  12. data/lib/redd/clients/base/privatemessages.rb +33 -0
  13. data/lib/redd/clients/base/read.rb +114 -0
  14. data/lib/redd/clients/base/stream.rb +82 -0
  15. data/lib/redd/clients/base/submit.rb +19 -0
  16. data/lib/redd/clients/base/utilities.rb +143 -0
  17. data/lib/redd/clients/base/wikiread.rb +33 -0
  18. data/lib/redd/clients/base.rb +181 -0
  19. data/lib/redd/clients/installed.rb +56 -0
  20. data/lib/redd/clients/script.rb +40 -0
  21. data/lib/redd/clients/userless.rb +32 -0
  22. data/lib/redd/clients/web.rb +59 -0
  23. data/lib/redd/error.rb +151 -0
  24. data/lib/redd/objects/base.rb +39 -0
  25. data/lib/redd/objects/comment.rb +22 -0
  26. data/lib/redd/objects/labeled_multi.rb +13 -0
  27. data/lib/redd/objects/listing.rb +29 -0
  28. data/lib/redd/objects/more_comments.rb +10 -0
  29. data/lib/redd/objects/private_message.rb +28 -0
  30. data/lib/redd/objects/submission.rb +140 -0
  31. data/lib/redd/objects/subreddit.rb +329 -0
  32. data/lib/redd/objects/thing/editable.rb +22 -0
  33. data/lib/redd/objects/thing/hideable.rb +18 -0
  34. data/lib/redd/objects/thing/inboxable.rb +25 -0
  35. data/lib/redd/objects/thing/messageable.rb +38 -0
  36. data/lib/redd/objects/thing/moderatable.rb +43 -0
  37. data/lib/redd/objects/thing/refreshable.rb +14 -0
  38. data/lib/redd/objects/thing/saveable.rb +21 -0
  39. data/lib/redd/objects/thing/votable.rb +33 -0
  40. data/lib/redd/objects/thing.rb +26 -0
  41. data/lib/redd/objects/user.rb +52 -0
  42. data/lib/redd/objects/wiki_page.rb +15 -0
  43. data/lib/redd/rate_limit.rb +88 -0
  44. data/lib/redd/response/parse_json.rb +18 -0
  45. data/lib/redd/response/raise_error.rb +16 -0
  46. data/lib/redd/version.rb +4 -0
  47. data/lib/redd.rb +50 -0
  48. data/neonredd.gemspec +33 -0
  49. data/spec/redd/objects/base_spec.rb +1 -0
  50. data/spec/redd/response/raise_error_spec.rb +11 -0
  51. data/spec/redd_spec.rb +5 -0
  52. data/spec/spec_helper.rb +71 -0
  53. metadata +225 -0
@@ -0,0 +1,140 @@
1
+ require_relative 'thing'
2
+
3
+ module Redd
4
+ module Objects
5
+ # A submission made in a subreddit.
6
+ class Submission < Thing
7
+ include Thing::Editable
8
+ include Thing::Hideable
9
+ include Thing::Moderatable
10
+ include Thing::Refreshable
11
+ include Thing::Saveable
12
+ include Thing::Votable
13
+
14
+ alias_property :nsfw?, :over_18
15
+ alias_property :self?, :is_self
16
+ alias_property :comments_count, :num_comments
17
+
18
+ # The shorter url for sharing.
19
+ def short_url
20
+ "http://redd.it/#{self[:id]}"
21
+ end
22
+
23
+ # Whether the comment was gilded.
24
+ def gilded?
25
+ self[:gilded] > 0
26
+ end
27
+
28
+ # Mark the thing as Not Suitable For Work.
29
+ def mark_as_nsfw
30
+ get('/api/marknsfw', id: fullname)
31
+ self[:over_18] = true
32
+ end
33
+
34
+ # No longer mark the thing as Not Suitable For Work.
35
+ def unmark_as_nsfw
36
+ get('/api/unmarknsfw', id: fullname)
37
+ self[:over_18] = false
38
+ end
39
+ alias mark_as_safe unmark_as_nsfw
40
+
41
+ # Reply to the thing.
42
+ # @param text [String] The text to comment.
43
+ # @return [Objects::Comment] The reply.
44
+ def add_comment(text)
45
+ client.add_comment(self, text)
46
+ end
47
+
48
+ # Set the submission to "contest mode" (comments are randomly sorted)
49
+ def set_contest_mode
50
+ post('/api/set_contest_mode', id: fullname, state: true)
51
+ end
52
+
53
+ # Unset the "contest mode".
54
+ def unset_contest_mode
55
+ post('/api/set_contest_mode', id: fullname, state: false)
56
+ end
57
+
58
+ # Set the submission as the sticky post of the subreddit
59
+ def set_sticky
60
+ post('/api/set_subreddit_sticky', id: fullname, state: true)
61
+ self[:stickied] = true
62
+ end
63
+
64
+ # Unsticky the post from the subreddit
65
+ def unset_sticky
66
+ post('/api/set_subreddit_sticky', id: fullname, state: false)
67
+ self[:stickied] = false
68
+ end
69
+
70
+ # @return [Listing] The submission's comments.
71
+ # @todo Allow for various depths and contexts and what not. Maybe a
72
+ # get_comment method?
73
+ def comments
74
+ refresh! unless @comments
75
+ @comments
76
+ end
77
+ alias replies comments
78
+
79
+ # Refresh the submission AND its comments.
80
+ # @return [Submission] The updated submission.
81
+ def refresh!
82
+ body = get("/comments/#{id}.json").body
83
+ @comments = client.object_from_body(body[1])
84
+ deep_merge!(body[0])
85
+ end
86
+
87
+ # Take a MoreComments and return a listing of comments.
88
+ # @param [MoreComments] more The object to expand.
89
+ # @return [Listing] A listing of the expanded comments.
90
+ # rubocop:disable Metrics/MethodLength
91
+ def expand_more(more)
92
+ response = client.get(
93
+ '/api/morechildren',
94
+ children: more.join(','),
95
+ link_id: fullname
96
+ )
97
+
98
+ client.object_from_body(
99
+ kind: 'Listing',
100
+ data: {
101
+ before: '', after: '',
102
+ children: response.body[:json][:data][:things]
103
+ }
104
+ )
105
+ end
106
+
107
+ # Get the related articles.
108
+ # @param [Hash] params A list of params to send with the request.
109
+ # @option params [String] :after Return results after the given
110
+ # fullname.
111
+ # @option params [String] :before Return results before the given
112
+ # fullname.
113
+ # @option params [Integer] :count The number of items already seen
114
+ # in the listing.
115
+ # @option params [1..100] :limit The maximum number of things to
116
+ # return.
117
+ # @return [Objects::Listing<Objects::Thing>]
118
+ def get_related(**params)
119
+ related = get("/related/#{id}.json", params).body[1]
120
+ client.object_from_body(related)
121
+ end
122
+
123
+ # Get other articles with the same URL.
124
+ # @param [Hash] params A list of params to send with the request.
125
+ # @option params [String] :after Return results after the given
126
+ # fullname.
127
+ # @option params [String] :before Return results before the given
128
+ # fullname.
129
+ # @option params [Integer] :count The number of items already seen
130
+ # in the listing.
131
+ # @option params [1..100] :limit The maximum number of things to
132
+ # return.
133
+ # @return [Objects::Listing<Objects::Submission>]
134
+ def get_duplicates(**params)
135
+ duplicates = get("/duplicates/#{id}.json", params).body[1]
136
+ client.object_from_body(duplicates)
137
+ end
138
+ end
139
+ end
140
+ end
@@ -0,0 +1,329 @@
1
+ require 'fastimage'
2
+ require_relative 'thing'
3
+ # rubocop:disable Metrics/ClassLength, Metrics/ParameterLists
4
+ # rubocop:disable Metrics/MethodLength, Metrics/AbcSize
5
+ module Redd
6
+ module Objects
7
+ # A comment made on links.
8
+ # @todo #subscribe! and #unsubscribe!
9
+ class Subreddit < Thing
10
+ include Thing::Messageable
11
+ include Thing::Refreshable
12
+
13
+ alias_property :header_image, :header_img
14
+ alias_property :nsfw?, :over18
15
+ alias_property :users_online, :accounts_active
16
+ alias_property :type, :subreddit_type
17
+ alias_property :times_gilded, :gilded
18
+
19
+ # @!group Submissions
20
+
21
+ # Submit a link or a text post to the subreddit.
22
+ #
23
+ # @param [String] title The title of the submission.
24
+ # @param [String] captcha A possible captcha result to send if one
25
+ # is required.
26
+ # @param [String] identifier The identifier for the captcha if one
27
+ # is required.
28
+ # @param [String] text The text of the self-post.
29
+ # @param [String] url The URL of the link.
30
+ # @param [Boolean] resubmit Whether to post a link to the subreddit
31
+ # despite it having been posted there before (you monster).
32
+ # @param [Boolean] sendreplies Whether to send the replies to your
33
+ # inbox.
34
+ # @return [Objects::Thing] The returned result (url, id and name).
35
+ def submit(
36
+ title, captcha = nil, identifier = nil, text: nil, url: nil,
37
+ resubmit: false, sendreplies: true
38
+ )
39
+
40
+ params = {
41
+ extension: 'json', title: title, sr: display_name,
42
+ resubmit: resubmit, sendreplies: sendreplies
43
+ }
44
+
45
+ if captcha
46
+ params[:captcha] = captcha
47
+ params[:iden] = identifier
48
+ end
49
+ if text
50
+ params[:kind] = :self
51
+ params[:text] = text
52
+ end
53
+ if url
54
+ params[:kind] = :link
55
+ params[:url] = url
56
+ end
57
+
58
+ response = post('/api/submit', params)
59
+ Objects::Thing.new(self, response.body[:json][:data])
60
+ end
61
+
62
+ # Add a comment to the submission.
63
+ # @param text [String] The text to comment.
64
+ # @return [Objects::Comment] The reply.
65
+ def add_comment(text)
66
+ client.add_comment(self, text)
67
+ end
68
+
69
+ # @!endgroup
70
+
71
+ # @!group Stylesheets
72
+
73
+ # @return [String] The url for the subreddit's stylesheet.
74
+ def stylesheet_url
75
+ get("/r/#{display_name}/stylesheet").headers['location']
76
+ end
77
+
78
+ # @return [String] The css for the subreddit.
79
+ def stylesheet
80
+ Faraday.get(stylesheet_url).body
81
+ end
82
+
83
+ # Edit the subreddit's stylesheet
84
+ #
85
+ # @param [String] contents The new CSS.
86
+ # @param [String] reason Why you modified the stylesheet.
87
+ # @author Takashi M (@beatak) and Avinash Dwarapu (@avidw)
88
+ # @note https://www.reddit.com/r/naut/about/stylesheet/ is a good place
89
+ # to test if you have an error.
90
+ def edit_stylesheet(contents, reason = nil)
91
+ params = { op: 'save', stylesheet_contents: contents }
92
+ params[:reason] = reason if reason
93
+ post("/r/#{display_name}/api/subreddit_stylesheet", params)
94
+ end
95
+
96
+ # @!endgroup
97
+
98
+ # @!group Invites
99
+
100
+ # Accept a moderator invite from a subreddit.
101
+ def accept_moderator_invite!
102
+ post("/r/#{display_name}/api/accept_moderator_invite")
103
+ end
104
+
105
+ # Stop being a contributor of the subreddit.
106
+ def leave_contributor_status!
107
+ post('/api/leavecontributor', id: fullname)
108
+ end
109
+
110
+ # Stop being a moderator of the subreddit.
111
+ def leave_moderator_status!
112
+ post('/api/leavemoderator', id: fullname)
113
+ end
114
+
115
+ # @!endgroup
116
+
117
+ # @!group Flairs
118
+
119
+ # Get a list of everbody on the subreddit with a user flair.
120
+ #
121
+ # @param [Hash] params A list of params to send with the request.
122
+ # @option params [String] :after Return results after the given
123
+ # fullname.
124
+ # @option params [String] :before Return results before the given
125
+ # fullname.
126
+ # @option params [Integer] :count The number of items already seen in the
127
+ # listing.
128
+ # @option params [1..1000] :limit The maximum number of things to
129
+ # return.
130
+ # @option params [String] :name The username when getting the flair of
131
+ # just one user.
132
+ # @return [Objects::Listing<Hash>] A listing of flair hashes.
133
+ def get_flairlist(**params)
134
+ body = get("/r/#{display_name}/api/flairlist.json", params).body
135
+ client.object_from_body(
136
+ kind: 'Listing',
137
+ data: {
138
+ children: body[:users],
139
+ before: body[:prev],
140
+ after: body[:next]
141
+ }
142
+ )
143
+ end
144
+
145
+ # Get the flair of a user.
146
+ #
147
+ # @param [Objects::User, String] user The user to find.
148
+ # @return [Hash, nil] Flair info about the user or nil if nobody was
149
+ # found.
150
+ def get_flair(user)
151
+ username = client.property(user, :name)
152
+ flair = get_flairlist(user: username).first
153
+ flair if flair[:user].casecmp(username) == 0
154
+ end
155
+
156
+ # Set the flair of a user or link.
157
+ # @param [Objects::Subreddit, Objects::User] thing The user or link to
158
+ # set the flair to.
159
+ # @param [:user, :link] type The type of thing.
160
+ # @param [String] text The text to set the flair to.
161
+ # @param [String] css_class The css_class of the flair.
162
+ def set_flair(thing, type = nil, text = nil, css_class = nil)
163
+ params = { text: text, css_class: css_class }
164
+ if thing.is_a?(Objects::User) || type == :user
165
+ params[:name] = client.property(thing, :name)
166
+ elsif thing.is_a?(Objects::Submission) || type == :link
167
+ params[:link] = client.property(thing, :fullname)
168
+ else
169
+ fail 'You should provide a proper type.'
170
+ end
171
+
172
+ post("/r/#{display_name}/api/flair", params)
173
+ end
174
+
175
+ # @!endgroup
176
+
177
+ # @!group Listings
178
+
179
+ # @!method get_hot(**params)
180
+ # @!method get_new(**params)
181
+ # @!method get_top(**params)
182
+ # @!method get_controversial(**params)
183
+ # @!method get_comments(**params)
184
+ #
185
+ # Get the appropriate listing.
186
+ # @param params [Hash] A list of params to send with the request.
187
+ # @option params [String] :after Return results after the given
188
+ # fullname.
189
+ # @option params [String :before Return results before the given
190
+ # fullname.
191
+ # @option params [Integer] :count (0) The number of items already seen
192
+ # in the listing.
193
+ # @option params [1..100] :limit (25) The maximum number of things to
194
+ # return.
195
+ # @option params [:hour, :day, :week, :month, :year, :all] :t The
196
+ # time period to consider when sorting.
197
+ #
198
+ # @note The option :t only applies to the top and controversial sorts.
199
+ # @return [Objects::Listing<Objects::Thing>]
200
+ %w(hot new top controversial comments).each do |sort|
201
+ define_method :"get_#{sort}" do |**params|
202
+ client.send(:"get_#{sort}", self, **params)
203
+ end
204
+ end
205
+
206
+ # Search.
207
+ # @param query [String] The query string.
208
+ # @param params [Hash] A list of params to send with the request.
209
+ # @option params [String] :after Return results after the given
210
+ # fullname.
211
+ # @option params [String :before Return results before the given
212
+ # fullname.
213
+ # @option params [Integer] :count The number of items already seen in
214
+ # the listing.
215
+ # @option params [1..100] :limit The maximum number of things to
216
+ # return.
217
+ # @option params [:cloudsearch, :lucene, :plain] :syntax The type of
218
+ # syntax to use.
219
+ # @option params [:relevance, :new, :hot, :top, :comments] :sort The
220
+ # way to sort the results.
221
+ # @option params [:hour, :day, :week, :month, :year, :all] :t The
222
+ # time period to consider when sorting.
223
+ #
224
+ # @note The option :t only applies to the top and controversial sorts.
225
+ # @return [Objects::Listing<Objects::Thing>]
226
+ def search(query, **params)
227
+ client.search(query, self, **params)
228
+ end
229
+
230
+ # @!endgroup
231
+
232
+ # @!group Moderation
233
+
234
+ # @!method get_reports(**params)
235
+ # @!method get_spam(**params)
236
+ # @!method get_modqueue(**params)
237
+ # @!method get_unmoderated(**params)
238
+ # @!method get_edited(**params)
239
+ #
240
+ # Get the appropriate moderator listing.
241
+ # @param [Hash] params A list of params to send with the request.
242
+ # @option params [String] :after Return results after the given
243
+ # fullname.
244
+ # @option params [String] :before Return results before the given
245
+ # fullname.
246
+ # @option params [Integer] :count The number of items already seen
247
+ # in the listing.
248
+ # @option params [1..100] :limit The maximum number of things to
249
+ # return.
250
+ # @option params :location No idea what this does.
251
+ # @option params [:links, :comments] :only The type of things to show.
252
+ #
253
+ # @return [Objects::Listing<Objects::Thing>]
254
+ # @see https://www.reddit.com/dev/api#GET_about_{location}
255
+ %w(reports spam modqueue unmoderated edited).each do |sort|
256
+ define_method :"get_#{sort}" do |**params|
257
+ client.request_object(
258
+ :get, "/r/#{display_name}/about/#{sort}", params
259
+ )
260
+ end
261
+ end
262
+
263
+ # @return [Objects::Base] The current settings of a subreddit.
264
+ def admin_about
265
+ client.request_object(:get, "/r/#{display_name}/about/edit.json")
266
+ end
267
+
268
+ # Edit the subreddit's settings
269
+ # @param [Hash] attributes The subreddit's new settings.
270
+ # @note This method may make additional requests if not all of the
271
+ # required attributes are provided. Take a look at the source for the
272
+ # required attributes required to avoid making the additional request.
273
+ # @see https://github.com/alaycock/MeetCal-bot/blob/master/serverInfo.conf
274
+ def admin_edit(attributes)
275
+ params = {
276
+ # Subreddit name
277
+ sr: fullname,
278
+ # Apparently useless options
279
+ show_cname_sidebar: true,
280
+ :"header-title" => title
281
+ }
282
+
283
+ required = %i(
284
+ allow_top collapse_deleted_comments comment_score_hide_mins
285
+ css_on_cname description exclude_banned_modqueue lang link_type name
286
+ over_18 public_description public_traffic show_media spam_comments
287
+ spam_links spam_selfposts submit_link_label submit_text
288
+ submit_text_label title type wiki_edit_age wiki_edit_karma wikimode
289
+ )
290
+
291
+ if required.all? { |key| attributes.key?(key) }
292
+ params.merge!(attributes)
293
+ else
294
+ about = admin_about
295
+ final = about
296
+ .select { |k, _| required.include?(k) }
297
+ .merge(
298
+ name: display_name,
299
+ type: about[:subreddit_type],
300
+ lang: about[:language],
301
+ link_type: about[:content_options],
302
+ allow_top: true,
303
+ css_on_cname: true
304
+ )
305
+ .merge(attributes)
306
+ params.merge!(final)
307
+ end
308
+
309
+ post('/api/site_admin', params)
310
+ end
311
+
312
+ # Add or replace the subreddit image or header logo.
313
+ # @param [String, IO] file The path/url to the file or the file itself.
314
+ # @param [String] name The name of the uploaded file.
315
+ # @return [String] The url of the image on reddit's CDN.
316
+ def upload_image(file, name = nil)
317
+ io = (file.is_a?(IO) ? file : File.open(file, 'r'))
318
+ type = FastImage.type(io)
319
+ payload = Faraday::UploadIO.new(io, "image/#{type}")
320
+
321
+ params = { file: payload, header: (name ? 0 : 1), img_type: type }
322
+ params[:name] = name if name
323
+ post("/r/#{display_name}/api/upload_sr_img", params).body[:img_src]
324
+ end
325
+
326
+ # @!endgroup
327
+ end
328
+ end
329
+ end
@@ -0,0 +1,22 @@
1
+ module Redd
2
+ module Objects
3
+ class Thing
4
+ # Things that can be edited and deleted.
5
+ module Editable
6
+ # Edit a thing.
7
+ # @param text [String] The new text.
8
+ # @return [Thing] The edited thing.
9
+ def edit(text)
10
+ post('/api/editusertext', thing_id: fullname, text: text)
11
+ self[(is_a?(Submission) ? :selftext : :body)] = text
12
+ self
13
+ end
14
+
15
+ # Delete the thing
16
+ def delete!
17
+ post('/api/del', id: fullname)
18
+ end
19
+ end
20
+ end
21
+ end
22
+ end
@@ -0,0 +1,18 @@
1
+ module Redd
2
+ module Objects
3
+ class Thing
4
+ # Things that can be hidden from the user.
5
+ module Hideable
6
+ # Hide a link from the user.
7
+ def hide
8
+ post('/api/hide', id: fullname)
9
+ end
10
+
11
+ # Unhide a previously hidden link.
12
+ def unhide
13
+ post('/api/unhide', id: fullname)
14
+ end
15
+ end
16
+ end
17
+ end
18
+ end
@@ -0,0 +1,25 @@
1
+ module Redd
2
+ module Objects
3
+ class Thing
4
+ # Things that can be sent to a user's inbox.
5
+ module Inboxable
6
+ # Mark this thing as read.
7
+ def mark_as_read
8
+ post('/api/read_message', id: fullname)
9
+ end
10
+
11
+ # Mark one or more messages as unread.
12
+ def mark_as_unread
13
+ post('/api/unread_message', id: fullname)
14
+ end
15
+
16
+ # Reply to the thing.
17
+ # @param text [String] The text to comment.
18
+ # @return [Objects::Comment, Objects::PrivateMessage] The reply.
19
+ def reply(text)
20
+ client.add_comment(self, text)
21
+ end
22
+ end
23
+ end
24
+ end
25
+ end
@@ -0,0 +1,38 @@
1
+ module Redd
2
+ module Objects
3
+ class Thing
4
+ # Things that can be sent a message.
5
+ module Messageable
6
+ # Compose a message to a person or the moderators of a subreddit.
7
+ #
8
+ # @param [String] subject The subject of the message.
9
+ # @param [String] text The message text.
10
+ # @param [String] from_sr The subreddit to send the message on behalf
11
+ # of or nil if from the user.
12
+ # @param [String] captcha A possible captcha result to send if one
13
+ # is required.
14
+ # @param [String] identifier The identifier for the captcha if one
15
+ # is required.
16
+ # rubocop:disable Metrics/MethodLength
17
+ def send_message(
18
+ subject, text, from_sr = nil, captcha = nil, identifier = nil
19
+ )
20
+ params = { subject: subject, text: text }
21
+ if captcha
22
+ params[:captcha] = captcha
23
+ params[:iden] = identifier
24
+ end
25
+ params[:from_sr] = client.property(from_sr, :display_name) if from_sr
26
+ params[:to] =
27
+ if respond_to?(:display_name)
28
+ "/r/#{self[:display_name]}"
29
+ else
30
+ self[:name]
31
+ end
32
+
33
+ post('/api/compose', params)
34
+ end
35
+ end
36
+ end
37
+ end
38
+ end
@@ -0,0 +1,43 @@
1
+ module Redd
2
+ module Objects
3
+ class Thing
4
+ # Things that a moderator can manage.
5
+ module Moderatable
6
+ # Approve a submission.
7
+ def approve!
8
+ post('/api/approve', id: fullname)
9
+ end
10
+
11
+ # Remove a submission.
12
+ # @param [Boolean] spam Whether or not this item is removed due to it
13
+ # being spam.
14
+ def remove!(spam = false)
15
+ post('/api/remove', id: fullname, spam: spam)
16
+ end
17
+
18
+ # Distinguish a link or comment with a sigil to show that it has
19
+ # been created by a moderator.
20
+ # @param [:yes, :no, :admin, :special] how How to distinguish the
21
+ # thing.
22
+ def distinguish(how = :yes)
23
+ post('/api/distinguish', id: fullname, how: how)
24
+ end
25
+
26
+ # Remove the sigil that shows a thing was created by a moderator.
27
+ def undistinguish
28
+ distinguish(:no)
29
+ end
30
+
31
+ # Stop getting any moderator-related reports on the thing.
32
+ def ignore_reports
33
+ post('/api/ignore_reports', id: fullname)
34
+ end
35
+
36
+ # Start getting moderator-related reports on the thing again.
37
+ def unignore_reports
38
+ post('/api/unignore_reports', id: fullname)
39
+ end
40
+ end
41
+ end
42
+ end
43
+ end
@@ -0,0 +1,14 @@
1
+ module Redd
2
+ module Objects
3
+ class Thing
4
+ # Things that can be refreshed with the current data.
5
+ module Refreshable
6
+ # Refresh the thing.
7
+ def refresh!
8
+ body = get('/api/info', id: fullname).body[:data][:children][0]
9
+ deep_merge!(body[:data])
10
+ end
11
+ end
12
+ end
13
+ end
14
+ end
@@ -0,0 +1,21 @@
1
+ module Redd
2
+ module Objects
3
+ class Thing
4
+ # Things that can be saved to a user's account.
5
+ module Saveable
6
+ # Save a link or comment (if gilded) to the user's account.
7
+ # @param [String] category A category to save to (if gilded).
8
+ def save(category = nil)
9
+ params = { id: fullname }
10
+ params[:category] = category if category
11
+ post('/api/save', params)
12
+ end
13
+
14
+ # Remove the link or comment from the user's saved links.
15
+ def unsave
16
+ post('/api/unsave', id: fullname)
17
+ end
18
+ end
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,33 @@
1
+ module Redd
2
+ module Objects
3
+ class Thing
4
+ # Things that can be voted upon.
5
+ module Votable
6
+ # Upvote the thing.
7
+ def upvote
8
+ vote(1)
9
+ end
10
+
11
+ # Downvote the thing.
12
+ def downvote
13
+ vote(-1)
14
+ end
15
+
16
+ # Remove your vote on the thing.
17
+ def clear_vote
18
+ vote(0)
19
+ end
20
+ alias unvote clear_vote
21
+
22
+ private
23
+
24
+ # Send a vote.
25
+ # @param [-1, 0, 1] direction The direction to vote in.
26
+ def vote(direction)
27
+ post('/api/vote', id: fullname, dir: direction)
28
+ self[:ups] += direction
29
+ end
30
+ end
31
+ end
32
+ end
33
+ end