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,96 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative 'model'
|
4
|
+
|
5
|
+
module Redd
|
6
|
+
module Models
|
7
|
+
# An object that represents a bunch of comments that need to be expanded.
|
8
|
+
class MoreComments < Model
|
9
|
+
# Expand the object's children into a listing of Comments and MoreComments.
|
10
|
+
# @param link [Submission] the submission the object belongs to
|
11
|
+
# @return [Listing<Comment, MoreComments>] the expanded children
|
12
|
+
def expand(link:)
|
13
|
+
expand_recursive(link: link, lookup: {})
|
14
|
+
end
|
15
|
+
|
16
|
+
# @return [Array<String>] an array representation of self
|
17
|
+
def to_a
|
18
|
+
read_attribute(:children)
|
19
|
+
end
|
20
|
+
alias to_ary to_a
|
21
|
+
|
22
|
+
# @!attribute [r] count
|
23
|
+
# @return [Integer] the comments under this object
|
24
|
+
property :count
|
25
|
+
|
26
|
+
# @!attribute [r] name
|
27
|
+
# @return [String] the object fullname
|
28
|
+
property :name
|
29
|
+
|
30
|
+
# @!attribute [r] id
|
31
|
+
# @return [String] the object id
|
32
|
+
property :id
|
33
|
+
|
34
|
+
# @!attribute [r] parent_id
|
35
|
+
# @return [String] the parent fullname
|
36
|
+
property :parent_id
|
37
|
+
|
38
|
+
# @!attribute [r] depth
|
39
|
+
# @return [Integer] the depth
|
40
|
+
property :depth
|
41
|
+
|
42
|
+
# @!attribute [r] children
|
43
|
+
# @return [Array<String>] the unexpanded comments
|
44
|
+
property :children
|
45
|
+
|
46
|
+
protected
|
47
|
+
|
48
|
+
# Keep expanding until all top-level MoreComments are converted to comments.
|
49
|
+
# @param link [Submission] the object's submission
|
50
|
+
# @param lookup [Hash] a hash of comments to add future replies to
|
51
|
+
# @return [Array<Comment, MoreComments>] the expanded comments or self if past depth
|
52
|
+
def expand_recursive(link:, lookup:) # rubocop:disable Metrics/AbcSize, Metrics/CyclomaticComplexity, Metrics/MethodLength, Metrics/PerceivedComplexity
|
53
|
+
return [self] if depth == 0
|
54
|
+
|
55
|
+
expand_one(link: link).each_with_object([]) do |thing, coll|
|
56
|
+
target =
|
57
|
+
if thing.parent_id == read_attribute(:parent_id)
|
58
|
+
coll
|
59
|
+
elsif lookup.key?(thing.parent_id)
|
60
|
+
lookup[thing.parent_id].replies.children
|
61
|
+
end
|
62
|
+
|
63
|
+
if target.nil?
|
64
|
+
warn "expanding error: orphaned comment #{thing.name}"
|
65
|
+
next
|
66
|
+
end
|
67
|
+
|
68
|
+
if thing.is_a?(Comment)
|
69
|
+
# Add the comment to a lookup hash.
|
70
|
+
lookup[thing.name] = thing
|
71
|
+
# If the parent is not in the lookup hash, add it to the root listing.
|
72
|
+
target.push(thing)
|
73
|
+
elsif thing.is_a?(MoreComments) && thing.count > 0
|
74
|
+
if thing.parent_id == read_attribute(:parent_id)
|
75
|
+
ary = thing.expand_recursive(link: link, lookup: lookup, depth: depth - 1)
|
76
|
+
target.concat(ary)
|
77
|
+
else
|
78
|
+
target.push(thing)
|
79
|
+
end
|
80
|
+
end
|
81
|
+
end
|
82
|
+
end
|
83
|
+
|
84
|
+
private
|
85
|
+
|
86
|
+
# Expand the object's children into a listing of Comments and MoreComments.
|
87
|
+
# @param link [Submission] the submission the object belongs to
|
88
|
+
# @return [Listing<Comment, MoreComments>] the expanded children
|
89
|
+
def expand_one(link:)
|
90
|
+
params = { link_id: link.name, children: read_attribute(:children).join(',') }
|
91
|
+
params[:sort] = link.sort_order if link.sort_order
|
92
|
+
client.model(:post, '/api/morechildren', params)
|
93
|
+
end
|
94
|
+
end
|
95
|
+
end
|
96
|
+
end
|
@@ -0,0 +1,104 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative 'model'
|
4
|
+
|
5
|
+
module Redd
|
6
|
+
module Models
|
7
|
+
# A multi.
|
8
|
+
class Multireddit < Model
|
9
|
+
# Get the appropriate listing.
|
10
|
+
# @param sort [:hot, :new, :top, :controversial, :comments, :rising, :gilded] the type of
|
11
|
+
# listing
|
12
|
+
# @param params [Hash] a list of params to send with the request
|
13
|
+
# @option params [String] :after return results after the given fullname
|
14
|
+
# @option params [String] :before return results before the given fullname
|
15
|
+
# @option params [Integer] :count the number of items already seen in the listing
|
16
|
+
# @option params [1..100] :limit the maximum number of things to return
|
17
|
+
# @option params [:hour, :day, :week, :month, :year, :all] :time the time period to consider
|
18
|
+
# when sorting.
|
19
|
+
#
|
20
|
+
# @note The option :time only applies to the top and controversial sorts.
|
21
|
+
# @return [Listing<Submission>]
|
22
|
+
def listing(sort, **params)
|
23
|
+
params[:t] = params.delete(:time) if params.key?(:time)
|
24
|
+
client.model(:get, "#{read_attribute(:path)}#{sort}", params)
|
25
|
+
end
|
26
|
+
|
27
|
+
# @!method hot(**params)
|
28
|
+
# @!method new(**params)
|
29
|
+
# @!method top(**params)
|
30
|
+
# @!method controversial(**params)
|
31
|
+
# @!method comments(**params)
|
32
|
+
# @!method rising(**params)
|
33
|
+
# @!method gilded(**params)
|
34
|
+
#
|
35
|
+
# @see #listing
|
36
|
+
%i[hot new top controversial comments rising gilded].each do |sort|
|
37
|
+
define_method(sort) { |**params| listing(sort, **params) }
|
38
|
+
end
|
39
|
+
|
40
|
+
# @!attribute [r] can_edit?
|
41
|
+
# @return [Boolean] whether the user can edit the multireddit
|
42
|
+
property :can_edit?, from: :can_edit
|
43
|
+
|
44
|
+
# @!attribute [r] display_name
|
45
|
+
# @return [String] the multi's display name
|
46
|
+
property :display_name
|
47
|
+
|
48
|
+
# @!attribute [r] name
|
49
|
+
# @return [String] the multireddit name
|
50
|
+
property :name
|
51
|
+
|
52
|
+
# @!attribute [r] description_md
|
53
|
+
# @return [String] the markdown verion of the description
|
54
|
+
property :description_md
|
55
|
+
|
56
|
+
# @!attribute [r] description_html
|
57
|
+
# @return [String] the html-rendered description
|
58
|
+
property :description_html
|
59
|
+
|
60
|
+
# @!attribute [r] copied_from
|
61
|
+
# @return [Multireddit, nil] the multi this one was copied from
|
62
|
+
property :copied_from, with: ->(n) { Multireddit.new(client, path: n) if n }
|
63
|
+
|
64
|
+
# @!attribute [r] icon_url
|
65
|
+
# @return [String, nil] the icon url
|
66
|
+
property :icon_url
|
67
|
+
|
68
|
+
# @!attribute [r] subreddits
|
69
|
+
# @return [Array<Subreddit>] the subreddits in this multi
|
70
|
+
property :subreddits,
|
71
|
+
with: ->(a) { a.map { |n| Subreddit.new(client, display_name: n.fetch(:name)) } }
|
72
|
+
|
73
|
+
# @!attribute [r] created_at
|
74
|
+
# @return [Time] the creation time
|
75
|
+
property :created_at, from: :created_utc, with: ->(t) { Time.at(t) }
|
76
|
+
|
77
|
+
# @!attribute [r] key_color
|
78
|
+
# @return [String] a hex color
|
79
|
+
property :key_color
|
80
|
+
|
81
|
+
# @!attribute [r] visibility
|
82
|
+
# @return [String] the multi visibility, either "public" or "private"
|
83
|
+
property :visibility
|
84
|
+
|
85
|
+
# @!attribute [r] icon_name
|
86
|
+
# @return [String] the icon name
|
87
|
+
property :icon_name
|
88
|
+
|
89
|
+
# @!attribute [r] weighting_scheme
|
90
|
+
# @return [String]
|
91
|
+
property :weighting_scheme
|
92
|
+
|
93
|
+
# @!attribute [r] path
|
94
|
+
# @return [String] the multi path
|
95
|
+
property :path, :required
|
96
|
+
|
97
|
+
private
|
98
|
+
|
99
|
+
def lazer_reload
|
100
|
+
client.get("/api/multi#{read_attribute(:path)}").body[:data]
|
101
|
+
end
|
102
|
+
end
|
103
|
+
end
|
104
|
+
end
|
@@ -0,0 +1,124 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative 'model'
|
4
|
+
|
5
|
+
module Redd
|
6
|
+
module Models
|
7
|
+
# An enumerable type that covers listings and expands forwards.
|
8
|
+
#
|
9
|
+
# If you want to use the #[] operator, you'll need to convert the object to an Array. This can
|
10
|
+
# be done with either {Enumerable#first} or {Enumerable#to_a}.
|
11
|
+
class PaginatedListing
|
12
|
+
include Enumerable
|
13
|
+
|
14
|
+
# A simple fixed-size ring buffer.
|
15
|
+
# @api private
|
16
|
+
class RingBuffer
|
17
|
+
def initialize(size)
|
18
|
+
@size = size
|
19
|
+
@backing_array = Array.new(size)
|
20
|
+
@pointer = 0
|
21
|
+
end
|
22
|
+
|
23
|
+
def include?(element)
|
24
|
+
@backing_array.include?(element)
|
25
|
+
end
|
26
|
+
|
27
|
+
def add(element)
|
28
|
+
@backing_array[@pointer] = element
|
29
|
+
@pointer = (@pointer + 1) % @size
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
# Create an expandable listing.
|
34
|
+
# @param client [APIClient] the caller to use for streams
|
35
|
+
# @param options [Hash]
|
36
|
+
# @option options [String] :before the listing's before parameter
|
37
|
+
# @option options [String] :after the listing's after parameter
|
38
|
+
# @option options [Integer] :limit the maximum number of items to fetch
|
39
|
+
# @yieldparam after [String] the fullname of the item to fetch after
|
40
|
+
# @yieldparam limit [Integer] the number of items to fetch (max 100)
|
41
|
+
# @yieldreturn [Listing] the listing to return
|
42
|
+
def initialize(client, **options, &block)
|
43
|
+
raise ArgumentError, 'block must be provided' unless block_given?
|
44
|
+
|
45
|
+
@client = client
|
46
|
+
@caller = block
|
47
|
+
@before = options[:before]
|
48
|
+
@after = options[:after]
|
49
|
+
@limit = options[:limit] || 1000
|
50
|
+
end
|
51
|
+
|
52
|
+
# Go forward through the listing.
|
53
|
+
# @yield [Model] the object returned in the listings
|
54
|
+
# @return [Enumerator] if a block wasn't provided
|
55
|
+
def each(&block)
|
56
|
+
return _each(&block) if block_given?
|
57
|
+
|
58
|
+
enum_for(:_each)
|
59
|
+
end
|
60
|
+
|
61
|
+
# Stream through the listing.
|
62
|
+
# @note If you iterate through the stream, you'll loop forever.
|
63
|
+
# This may or may not be desirable.
|
64
|
+
# @yield [Model] the object returned in the listings
|
65
|
+
# @return [Enumerator] if a block wasn't provided
|
66
|
+
def stream(&block)
|
67
|
+
return _stream(&block) if block_given?
|
68
|
+
|
69
|
+
enum_for(:_stream)
|
70
|
+
end
|
71
|
+
|
72
|
+
private
|
73
|
+
|
74
|
+
# Go backward through the listing.
|
75
|
+
# @yield [Object] the object returned in the listings
|
76
|
+
def _stream # rubocop:disable Metrics/MethodLength
|
77
|
+
buffer = RingBuffer.new(100)
|
78
|
+
remaining = @limit > 0 ? reverse_each.to_a : []
|
79
|
+
|
80
|
+
loop do
|
81
|
+
remaining.push(*fetch_prev_listing)
|
82
|
+
remaining.reverse_each do |o|
|
83
|
+
next if buffer.include?(o.id)
|
84
|
+
|
85
|
+
buffer.add(o.id)
|
86
|
+
yield o
|
87
|
+
end
|
88
|
+
remaining.clear
|
89
|
+
end
|
90
|
+
end
|
91
|
+
|
92
|
+
# Go forward through the listing.
|
93
|
+
# @yield [Object] the object returned in the listings
|
94
|
+
def _each(&block)
|
95
|
+
loop do
|
96
|
+
return if @limit == 0
|
97
|
+
|
98
|
+
remaining = fetch_next_listing
|
99
|
+
return if remaining.children.empty? # if the fetched listing is empty
|
100
|
+
|
101
|
+
remaining.each(&block)
|
102
|
+
return if remaining.after.nil? # if there's no link to the next item
|
103
|
+
end
|
104
|
+
end
|
105
|
+
|
106
|
+
# Fetch the next listing with @caller and update @after and @limit.
|
107
|
+
def fetch_next_listing
|
108
|
+
caller_limit = [@limit, 100].min
|
109
|
+
listing = @caller.call(after: @after, limit: caller_limit)
|
110
|
+
@after = listing.after
|
111
|
+
@limit -= caller_limit
|
112
|
+
listing
|
113
|
+
end
|
114
|
+
|
115
|
+
# Fetch the previous listing with @caller and update @before.
|
116
|
+
def fetch_prev_listing
|
117
|
+
# we're not using the user-provided because a stream isn't supposed to die
|
118
|
+
listing = @caller.call(before: @before, after: nil, limit: 100)
|
119
|
+
@before = listing.empty? ? nil : listing.first.name
|
120
|
+
listing
|
121
|
+
end
|
122
|
+
end
|
123
|
+
end
|
124
|
+
end
|
@@ -0,0 +1,83 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Redd
|
4
|
+
module Models
|
5
|
+
# Methods for user-submitted content, i.e. Submissions and Comments.
|
6
|
+
module Postable
|
7
|
+
# Edit a thing.
|
8
|
+
# @param text [String] The new text.
|
9
|
+
# @return [self] the edited thing
|
10
|
+
def edit(text)
|
11
|
+
client.post('/api/editusertext', thing_id: read_attribute(:name), text: text)
|
12
|
+
self
|
13
|
+
end
|
14
|
+
|
15
|
+
# Delete the thing.
|
16
|
+
def delete
|
17
|
+
client.post('/api/del', id: read_attribute(:name))
|
18
|
+
end
|
19
|
+
|
20
|
+
# @return [Boolean] whether the item is probably deleted
|
21
|
+
def deleted?
|
22
|
+
read_attribute(:author).name == '[deleted]'
|
23
|
+
end
|
24
|
+
|
25
|
+
# Save a link or comment to the user's account.
|
26
|
+
# @param category [String] a category to save to
|
27
|
+
def save(category = nil)
|
28
|
+
params = { id: read_attribute(:name) }
|
29
|
+
params[:category] = category if category
|
30
|
+
client.post('/api/save', params)
|
31
|
+
end
|
32
|
+
|
33
|
+
# Remove the link or comment from the user's saved links.
|
34
|
+
def unsave
|
35
|
+
client.post('/api/unsave', id: read_attribute(:name))
|
36
|
+
end
|
37
|
+
|
38
|
+
# Hide a link from the user.
|
39
|
+
def hide
|
40
|
+
client.post('/api/hide', id: read_attribute(:name))
|
41
|
+
end
|
42
|
+
|
43
|
+
# Unhide a previously hidden link.
|
44
|
+
def unhide
|
45
|
+
client.post('/api/unhide', id: read_attribute(:name))
|
46
|
+
end
|
47
|
+
|
48
|
+
# Upvote the model.
|
49
|
+
def upvote
|
50
|
+
vote(1)
|
51
|
+
end
|
52
|
+
|
53
|
+
# Downvote the model.
|
54
|
+
def downvote
|
55
|
+
vote(-1)
|
56
|
+
end
|
57
|
+
|
58
|
+
# Clear any upvotes or downvotes on the model.
|
59
|
+
def undo_vote
|
60
|
+
vote(0)
|
61
|
+
end
|
62
|
+
|
63
|
+
# Send replies to this thing to the user's inbox.
|
64
|
+
def enable_inbox_replies
|
65
|
+
client.post('/api/sendreplies', id: read_attribute(:name), state: true)
|
66
|
+
end
|
67
|
+
|
68
|
+
# Stop sending replies to this thing to the user's inbox.
|
69
|
+
def disable_inbox_replies
|
70
|
+
client.post('/api/sendreplies', id: read_attribute(:name), state: false)
|
71
|
+
end
|
72
|
+
|
73
|
+
private
|
74
|
+
|
75
|
+
# Send a vote.
|
76
|
+
# @param direction [-1, 0, 1] the direction to vote in
|
77
|
+
def vote(direction)
|
78
|
+
fullname = read_attribute(:name)
|
79
|
+
client.post('/api/vote', id: fullname, dir: direction)
|
80
|
+
end
|
81
|
+
end
|
82
|
+
end
|
83
|
+
end
|
@@ -0,0 +1,105 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative 'model'
|
4
|
+
require_relative 'inboxable'
|
5
|
+
require_relative 'replyable'
|
6
|
+
require_relative 'reportable'
|
7
|
+
|
8
|
+
module Redd
|
9
|
+
module Models
|
10
|
+
# A private message
|
11
|
+
class PrivateMessage < Model
|
12
|
+
include Inboxable
|
13
|
+
include Replyable
|
14
|
+
include Reportable
|
15
|
+
|
16
|
+
# Delete the message from the user's inbox.
|
17
|
+
def delete
|
18
|
+
client.post('/api/del_msg', id: read_attribute(:name))
|
19
|
+
end
|
20
|
+
|
21
|
+
# Mute the author of the message.
|
22
|
+
def mute_author
|
23
|
+
client.post('/api/mute_message_author', id: read_attribute(:name))
|
24
|
+
end
|
25
|
+
|
26
|
+
# Unmute the author of the message.
|
27
|
+
def unmute_author
|
28
|
+
client.post('/api/unmute_message_author', id: read_attribute(:name))
|
29
|
+
end
|
30
|
+
|
31
|
+
# @!attribute [r] first_message
|
32
|
+
# @return [Integer] not sure what this does
|
33
|
+
property :first_message
|
34
|
+
|
35
|
+
# @!attribute [r] first_message_name
|
36
|
+
# @return [String] the fullname of the first message
|
37
|
+
property :first_message_name
|
38
|
+
|
39
|
+
# @!attribute [r] subreddit
|
40
|
+
# @return [Subreddit, nil] the subreddit that sent the message
|
41
|
+
property :subreddit, with: ->(s) { Subreddit.new(client, display_name: s) if s }
|
42
|
+
|
43
|
+
# @!attribute [r] replies
|
44
|
+
# @return [Listing<PrivateMessage>]
|
45
|
+
property :replies, with: ->(l) { Listing.new(client, l[:data]) if l.is_a?(Hash) }
|
46
|
+
|
47
|
+
# @!attribute [r] id
|
48
|
+
# @return [String] the message id
|
49
|
+
property :id
|
50
|
+
|
51
|
+
# @!attribute [r] subject
|
52
|
+
# @return [String] the message subject
|
53
|
+
property :subject
|
54
|
+
|
55
|
+
# @!attribute [r] was_comment?
|
56
|
+
# @return [Boolean]
|
57
|
+
property :was_comment?, from: :was_comment
|
58
|
+
|
59
|
+
# @!attribute [r] author
|
60
|
+
# @return [User] the message author
|
61
|
+
property :author, with: ->(n) { User.new(client, name: n) if n }
|
62
|
+
|
63
|
+
# @!attribute [r] num_comments
|
64
|
+
# @return [Integer] huh?
|
65
|
+
property :num_comments
|
66
|
+
|
67
|
+
# @!attribute [r] parent_id
|
68
|
+
# @return [String, nil] the parent id
|
69
|
+
property :parent_id
|
70
|
+
|
71
|
+
# @!attribute [r] subreddit_name_prefixed
|
72
|
+
# @return [String] the subreddit name, prefixed with "r/"
|
73
|
+
property :subreddit_name_prefixed
|
74
|
+
|
75
|
+
# @!attribute [r] new?
|
76
|
+
# @return [Boolean] whether the message is new
|
77
|
+
property :new?, from: :new
|
78
|
+
|
79
|
+
# @!attribute [r] body
|
80
|
+
# @return [String] the message body
|
81
|
+
property :body
|
82
|
+
|
83
|
+
# @!attribute [r] body_html
|
84
|
+
# @return [String] the html-rendered version of the body
|
85
|
+
property :body_html
|
86
|
+
|
87
|
+
# @!attribute [r] dest
|
88
|
+
# @return [String] the recipient of the message
|
89
|
+
# @todo maybe convert the object to Subreddit/User?
|
90
|
+
property :dest
|
91
|
+
|
92
|
+
# @!attribute [r] name
|
93
|
+
# @return [String] the message fullname
|
94
|
+
property :name
|
95
|
+
|
96
|
+
# @!attribute [r] created
|
97
|
+
# @return [Time] the time the message was created
|
98
|
+
property :created_utc, with: ->(t) { Time.at(t) }
|
99
|
+
|
100
|
+
# @!attribute [r] distinguished
|
101
|
+
# @return [String] the level the message is distinguished
|
102
|
+
property :distinguished
|
103
|
+
end
|
104
|
+
end
|
105
|
+
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Redd
|
4
|
+
module Models
|
5
|
+
# A model that can be commented on or replied to.
|
6
|
+
module Replyable
|
7
|
+
# Add a comment to a link, reply to a comment or reply to a message.
|
8
|
+
# @param text [String] the text to comment
|
9
|
+
# @return [Comment, PrivateMessage] The created reply.
|
10
|
+
def reply(text)
|
11
|
+
fullname = read_attribute(:name)
|
12
|
+
client.model(:post, '/api/comment', text: text, thing_id: fullname).first
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
@@ -0,0 +1,14 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Redd
|
4
|
+
module Models
|
5
|
+
# Things that can be reported (except users).
|
6
|
+
module Reportable
|
7
|
+
# Report the object.
|
8
|
+
# @param reason [String] the report reason
|
9
|
+
def report(reason)
|
10
|
+
client.post('/api/report', thing_id: read_attribute(:name), reason: reason)
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
@@ -0,0 +1,35 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Redd
|
4
|
+
module Models
|
5
|
+
# Applied to {Session} for site-wide and {Subreddit} for subreddit-specific search.
|
6
|
+
module Searchable
|
7
|
+
# Search reddit.
|
8
|
+
# @see https://www.reddit.com/wiki/search
|
9
|
+
#
|
10
|
+
# @param query [String] the search query
|
11
|
+
# @param params [Hash] the search params
|
12
|
+
# @option params [:cloudsearch, :lucene, :plain] :syntax the query's syntax
|
13
|
+
# @option params [String] :after return results after the given fullname
|
14
|
+
# @option params [String] :before return results before the given fullname
|
15
|
+
# @option params [Integer] :count the number of items already seen in the listing
|
16
|
+
# @option params [1..100] :limit the maximum number of things to return
|
17
|
+
# @option params [:hour, :day, :week, :month, :year, :all] :time the time period to restrict
|
18
|
+
# search results by
|
19
|
+
# @option params [:relevance, :hot, :top, :new, :comments] :sort the sort order of results
|
20
|
+
# @option params [String] :restrict_to restrict by subreddit (prefer {Subreddit#search})
|
21
|
+
# @return [Listing<Comment, Submission>] the search results
|
22
|
+
def search(query, **params)
|
23
|
+
params[:q] = query
|
24
|
+
params[:t] = params.delete(:time) if params.key?(:time)
|
25
|
+
if params[:restrict_to]
|
26
|
+
subreddit = params.delete(:restrict_to)
|
27
|
+
params[:restrict_sr] = true
|
28
|
+
client.model(:get, "/r/#{subreddit}/search", params)
|
29
|
+
else
|
30
|
+
client.model(:get, '/search', params)
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative 'user'
|
4
|
+
|
5
|
+
module Redd
|
6
|
+
module Models
|
7
|
+
# The user that the bot is running under.
|
8
|
+
class Self < User
|
9
|
+
private
|
10
|
+
|
11
|
+
def lazer_reload
|
12
|
+
fully_loaded!
|
13
|
+
client.get('/api/v1/me').body
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|