redd 0.8.0.pre.2 → 0.8.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 69d6cf992f71356b1db86a000bdc3be4508e351c
4
- data.tar.gz: 01d0b098fb7c26a91e34ff001310417c93e3bd74
3
+ metadata.gz: ca106c8ea55f1c1278f643802a357163ebca48cc
4
+ data.tar.gz: 38302c79dbc6c94813c182b5b0ec2b0cae02c124
5
5
  SHA512:
6
- metadata.gz: 4019ce12ee1cfac8927642bfdd327e4221835842a230ad73bce35b0ce3e1f0445523bf5a796aeca182b63c7061861ba1a28a587fe8814594d6d89531ece2c3a6
7
- data.tar.gz: 292775ce9121b4de029ee49e451417508b64524940043569ebe53b807387fac0b1539a7cf5e37a13d494c83267421a1789a75e00ec96cadbaa2cf01128c0f9b7
6
+ metadata.gz: c379f17013fbd83957752e7e745b8f55bc37b96f7cb96ad4d08252f1857b57258cf2fe5fcb8a711f65217908ad703b2e4a506720833226fcc89d36fefe2e9f62
7
+ data.tar.gz: a95cee5b5b15124d6867f1a998c9abb21b7aace479d23ff32e85e86b06c6dac129ffa9dedfc169ce6612a1bfe07614b5a79d8b4d1e5fd506b938bc0bd8b4cdfb
data/README.md CHANGED
@@ -40,6 +40,10 @@ end
40
40
  **Yes**, that's all there is to it! You don't need to handle rate-limiting, refresh access tokens
41
41
  or protect against issues on reddit's end (like 5xx errors).
42
42
 
43
+ #### Where can I find the documentation?
44
+
45
+ [**Latest**](www.rubydoc.info/gems/redd) / [**GitHub**](http://www.rubydoc.info/github/avinashbot/redd/master/Redd/Models/Session)
46
+
43
47
  #### How can I contact you?
44
48
  [Reddit](https://www.reddit.com/message/compose/?to=Mustermind) /
45
49
  [GitHub](https://github.com/avinashbot/redd/issues/new) /
@@ -37,7 +37,7 @@ server.mount_proc '/authenticate' do |_, res|
37
37
  state: '0',
38
38
  redirect_uri: 'http://localhost:8000/redirect',
39
39
  'scope': %w(identity read subscribe privatemessages wikiread submit vote edit modposts history
40
- modflair modconfig)
40
+ modflair modconfig modmail livemanage)
41
41
  )
42
42
  )
43
43
  end
@@ -66,7 +66,7 @@ module Redd
66
66
 
67
67
  def model(verb, path, options = {})
68
68
  # XXX: make unmarshal explicit in methods?
69
- unmarshal(request(verb, path, options).body)
69
+ unmarshal(send(verb, path, options).body)
70
70
  end
71
71
 
72
72
  # Makes a request, ensuring not to break the rate limit by sleeping.
@@ -56,6 +56,11 @@ module Redd
56
56
  @attributes
57
57
  end
58
58
 
59
+ # @return [Array<self>] an array representation of self
60
+ def to_ary
61
+ [self]
62
+ end
63
+
59
64
  # Checks whether an attribute is supported by method_missing.
60
65
  # @param method_name [Symbol] the method name or attribute to check
61
66
  # @param include_private [Boolean] whether to also include private methods
@@ -0,0 +1,82 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative 'lazy_model'
4
+
5
+ module Redd
6
+ module Models
7
+ # Represents a conversation in the new modmail.
8
+ # TODO: add message and modmail-specific user type
9
+ class Conversation < LazyModel
10
+ # Get a Conversation from its id.
11
+ # @option hash [String] :id the base36 id (e.g. abc123)
12
+ # @return [Conversation]
13
+ def self.from_response(client, hash)
14
+ id = hash.fetch(:id)
15
+ new(client) do |c|
16
+ response = c.get("/api/mod/conversations/#{id}").body
17
+ response[:conversation].merge(
18
+ messages: response[:messages],
19
+ user: response[:user],
20
+ mod_actions: response[:modActions]
21
+ )
22
+ end
23
+ end
24
+
25
+ # Get a Conversation from its id.
26
+ # @param id [String] the base36 id (e.g. abc123)
27
+ # @return [Conversation]
28
+ def self.from_id(client, id)
29
+ from_response(client, id: id)
30
+ end
31
+
32
+ # Mark this conversation as read.
33
+ def mark_as_read
34
+ @client.post('/api/mod/conversations/read', conversationIds: [get_attribute(:id)])
35
+ end
36
+
37
+ # Mark this conversation as unread.
38
+ def mark_as_unread
39
+ @client.post('/api/mod/conversations/unread', conversationIds: [get_attribute(:id)])
40
+ end
41
+
42
+ # Mark this conversation as archived.
43
+ def archive
44
+ perform_action(:post, 'archive')
45
+ end
46
+
47
+ # Removed this conversation from archived.
48
+ def unarchive
49
+ perform_action(:post, 'unarchive')
50
+ end
51
+
52
+ # Highlight this conversation.
53
+ def highlight
54
+ perform_action(:post, 'highlight')
55
+ end
56
+
57
+ # Remove the highlight on this conversation.
58
+ def unhighlight
59
+ perform_action(:delete, 'highlight')
60
+ end
61
+
62
+ # Mute this conversation.
63
+ def mute
64
+ perform_action(:post, 'mute')
65
+ end
66
+
67
+ # Unmute this conversation.
68
+ def unmute
69
+ perform_action(:post, 'unmute')
70
+ end
71
+
72
+ private
73
+
74
+ # Perform an action on a conversation.
75
+ # @param method [:post, :delete] the method to use
76
+ # @param action [String] the name of the action
77
+ def perform_action(method, action)
78
+ @client.send(method, "/api/mod/conversations/#{id}/#{action}")
79
+ end
80
+ end
81
+ end
82
+ end
@@ -16,6 +16,11 @@ module Redd
16
16
  new(client, hash)
17
17
  end
18
18
 
19
+ # @return [Array<Comment, Submission, PrivateMessage>] an array representation of self
20
+ def to_ary
21
+ get_attribute(:children)
22
+ end
23
+
19
24
  %i([] each empty? first last).each do |method_name|
20
25
  define_method(method_name) do |*args, &block|
21
26
  get_attribute(:children).public_send(method_name, *args, &block)
@@ -0,0 +1,67 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative 'lazy_model'
4
+
5
+ module Redd
6
+ module Models
7
+ # Represents a live thread.
8
+ class LiveThread < LazyModel
9
+ # Get a Conversation from its id.
10
+ # @option hash [String] :id the base36 id (e.g. abc123)
11
+ # @return [Conversation]
12
+ def self.from_response(client, hash)
13
+ id = hash.fetch(:id)
14
+ new(client, hash) { |c| c.get("/live/#{id}/about").body[:data] }
15
+ end
16
+
17
+ # Get a LiveThread from its id.
18
+ # @param id [String] the id
19
+ # @return [LiveThread]
20
+ def self.from_id(client, id)
21
+ from_response(client, id: id)
22
+ end
23
+
24
+ # Configure the settings of this live thread
25
+ # @param params [Hash] a list of params to send with the request
26
+ # @option params [String] :description the new description
27
+ # @option params [Boolean] :nsfw whether the thread is for users 18 and above
28
+ # @option params [String] :resources the new resources
29
+ # @option params [String] :title the thread title
30
+ def configure(**params)
31
+ @client.post("/api/live/#{get_attribute(:id)}/edit", params)
32
+ end
33
+
34
+ # Add an update to this live event.
35
+ # @param body [String] the update text
36
+ def update(body)
37
+ @client.post("/api/live/#{get_attribute(:id)}/update", body: body)
38
+ end
39
+
40
+ # @return [Array<User>] the contributors to this thread
41
+ def contributors
42
+ @client.get("/live/#{get_attribute(:id)}/contributors").body[0][:data].map do |user|
43
+ User.from_response(@client, user)
44
+ end
45
+ end
46
+
47
+ # @return [Array<User>] users invited to contribute to this thread
48
+ def invited_contributors
49
+ @client.get("/live/#{get_attribute(:id)}/contributors").body[1][:data].map do |user|
50
+ User.from_response(@client, user)
51
+ end
52
+ end
53
+
54
+ # Returns all discussions that link to this live thread.
55
+ # @param params [Hash] a list of params to send with the request
56
+ # @option params [String] :after return results after the given fullname
57
+ # @option params [String] :before return results before the given fullname
58
+ # @option params [Integer] :count the number of items already seen in the listing
59
+ # @option params [1..100] :limit the maximum number of things to return
60
+ #
61
+ # @return [Listing<Submission>]
62
+ def discussions(**params)
63
+ @client.model(:get, "/live/#{get_attribute(:id)}/discussions", params)
64
+ end
65
+ end
66
+ end
67
+ end
@@ -0,0 +1,45 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative 'basic_model'
4
+ require_relative 'subreddit'
5
+ require_relative 'conversation'
6
+
7
+ module Redd
8
+ module Models
9
+ # A container for the new modmail.
10
+ # XXX: Instead of making ModMail a dumb container, could it be a lazy wrapper for #unread_count?
11
+ class ModMail < BasicModel
12
+ # @return [#highlighted, #notifications, #archived, #new, #inprogress, #mod] the number of
13
+ # unread messages in each category
14
+ def unread_count
15
+ BasicModel.new(nil, @client.get('/api/mod/conversations/unread/count').body)
16
+ end
17
+
18
+ # @return [Array<Subreddit>] moderated subreddits that are enrolled in the new modmail
19
+ def enrolled
20
+ @client.get('/api/mod/conversations/subreddits').body[:subreddits].map do |_, s|
21
+ Subreddit.from_response(@client, s.merge(last_updated: s.delete(:lastUpdated)))
22
+ end
23
+ end
24
+
25
+ # Get the conversations
26
+ # @param after [String] base36 modmail conversation id
27
+ # @param subreddits [Subreddit, Array<Subreddit>] the subreddits to limit to
28
+ # @param limit [Integer] an integer (default: 25)
29
+ # @param sort [:recent, :mod, :user, :unread] the sort order
30
+ # @param state [:new, :inprogress, :mod, :notifications, :archived, :highlighted, :all] the
31
+ # state to limit the conversations by
32
+ def conversations(subreddits: nil, **params)
33
+ params[:entity] = Array(subreddits).map(&:display_name).join(',') if subreddits
34
+ @client.get('/api/mod/conversations', **params).body
35
+ end
36
+
37
+ # Get a conversation from its base36 id.
38
+ # @param id [String] the conversation's id
39
+ # @return [Conversation]
40
+ def get(id)
41
+ Conversation.from_id(@client, id)
42
+ end
43
+ end
44
+ end
45
+ end
@@ -19,6 +19,11 @@ module Redd
19
19
  )
20
20
  end
21
21
 
22
+ # @return [Array<String>] an array representation of self
23
+ def to_ary
24
+ get_attribute(:children)
25
+ end
26
+
22
27
  # Keep expanding until all top-level MoreComments are converted to comments
23
28
  def recursive_expand(link:, sort: 'best')
24
29
  # FIXME: this returns a flattened listing of comments and doesn't preserve the structure
@@ -56,6 +56,16 @@ module Redd
56
56
  vote(0)
57
57
  end
58
58
 
59
+ # Send replies to this thing to the user's inbox.
60
+ def enable_inbox_replies
61
+ @client.post('/api/sendreplies', id: get_attribute(:name), state: true)
62
+ end
63
+
64
+ # Stop sending replies to this thing to the user's inbox.
65
+ def disable_inbox_replies
66
+ @client.post('/api/sendreplies', id: get_attribute(:name), state: false)
67
+ end
68
+
59
69
  private
60
70
 
61
71
  # Send a vote.
@@ -9,6 +9,16 @@ module Redd
9
9
  class Session < BasicModel
10
10
  include Searchable
11
11
 
12
+ # @return [ModMail] the new modmail
13
+ def modmail
14
+ ModMail.new(@client)
15
+ end
16
+
17
+ # @return [LiveThread] the live thread
18
+ def live_thread(id)
19
+ LiveThread.from_id(client, id)
20
+ end
21
+
12
22
  # @return [FrontPage] the user's front page
13
23
  def front_page
14
24
  FrontPage.new(@client)
@@ -62,20 +72,14 @@ module Redd
62
72
 
63
73
  # Return a listing of the user's inbox (including comment replies and private messages).
64
74
  #
65
- # @param category ['inbox', 'unread', 'sent'] The category of messages
66
- # to view.
67
- # @param mark [Boolean] Whether to remove the orangered from the
68
- # user's inbox.
69
- # @param params [Hash] A list of optional params to send with the request.
70
- # @option params [String] :after Return results after the given
71
- # fullname.
72
- # @option params [String] :before Return results before the given
73
- # fullname.
74
- # @option params [Integer] :count (0) The number of items already seen
75
- # in the listing.
76
- # @option params [1..100] :limit (25) The maximum number of things to
77
- # return.
78
- # @return [Listing]
75
+ # @param category ['inbox', 'unread', 'sent', 'moderator'] the category of messages to view
76
+ # @param mark [Boolean] whether to remove the orangered from the user's inbox
77
+ # @param params [Hash] a list of optional params to send with the request
78
+ # @option params [String] :after return results after the given fullname
79
+ # @option params [String] :before return results before the given fullname
80
+ # @option params [Integer] :count (0) the number of items already seen in the listing
81
+ # @option params [1..100] :limit (25) the maximum number of things to return
82
+ # @return [Listing<Comment, PrivateMessage>]
79
83
  def my_messages(category: 'inbox', mark: false, **params)
80
84
  @client.model(:get, "/message/#{category}.json", params.merge(mark: mark))
81
85
  end
@@ -84,6 +88,20 @@ module Redd
84
88
  def read_all_messages
85
89
  @client.post('/api/read_all_messages')
86
90
  end
91
+
92
+ # @return [Array<User>] the logged-in user's friends
93
+ def friends
94
+ @client.get('/api/v1/me/friends').body[:data][:children].map do |h|
95
+ User.from_response(@client, name: h[:name], id: h[:id].tr('t2_', ''), since: h[:date])
96
+ end
97
+ end
98
+
99
+ # @return [Array<User>] users blocked by the logged-in user
100
+ def blocked
101
+ @client.get('/prefs/blocked').body[:data][:children].map do |h|
102
+ User.from_response(@client, name: h[:name], id: h[:id].tr('t2_', ''), since: h[:date])
103
+ end
104
+ end
87
105
  end
88
106
  end
89
107
  end
@@ -33,6 +33,17 @@ module Redd
33
33
  end
34
34
  end
35
35
 
36
+ # Get all submissions for the same url.
37
+ # @param params [Hash] A list of optional params to send with the request.
38
+ # @option params [String] :after return results after the given fullname
39
+ # @option params [String] :before return results before the given fullname
40
+ # @option params [Integer] :count (0) the number of items already seen in the listing
41
+ # @option params [1..100] :limit (25) the maximum number of things to return
42
+ # @return [Listing<Submission>]
43
+ def duplicates(**params)
44
+ @client.unmarshal(@client.get("/duplicates/#{get_attribute(:id)}", params).body[1])
45
+ end
46
+
36
47
  # Mark the link as "Not Suitable For Work".
37
48
  def mark_as_nsfw
38
49
  @client.get('/api/marknsfw', id: get_attribute(:name))
@@ -141,6 +141,7 @@ module Redd
141
141
  # @return [Array<Hash>]
142
142
  def relationship_listing(type, **params)
143
143
  # TODO: add methods to determine if a certain user was banned/muted/etc
144
+ # TODO: return User types?
144
145
  user_list = @client.get("/r/#{get_attribute(:display_name)}/about/#{type}", params).body
145
146
  user_list[:data][:children]
146
147
  end
@@ -8,7 +8,7 @@ module Redd
8
8
  class ErrorHandler
9
9
  HTTP_ERRORS = {
10
10
  400 => Redd::BadRequest,
11
- 403 => Redd::Forbidden,
11
+ # 403 => Redd::Forbidden,
12
12
  404 => Redd::NotFound,
13
13
  500 => Redd::ServerError,
14
14
  502 => Redd::ServerError,
@@ -23,12 +23,13 @@ module Redd
23
23
 
24
24
  def check_error(response, raw:)
25
25
  # TODO: deal with errors of type { fields:, explanation:, message:, reason: }
26
- if !raw && response.body[:json] && response.body[:json][:errors] &&
27
- !response.body[:json][:errors].empty?
26
+ if !raw && response.body.is_a?(Hash) && response.body[:json] &&
27
+ response.body[:json][:errors] && !response.body[:json][:errors].empty?
28
28
  Redd::APIError.new(response)
29
29
  elsif HTTP_ERRORS.key?(response.code)
30
30
  HTTP_ERRORS[response.code].new(response)
31
- elsif response.code == 401
31
+ elsif response.code == 401 || response.code == 403
32
+ # FIXME: i think insufficient_scope comes with 403 and invalid_token with 401
32
33
  AUTHORIZATION_ERRORS.each do |key, klass|
33
34
  auth_header = response.headers['www-authenticate']
34
35
  return klass.new(response) if auth_header && auth_header.include?(key)
@@ -5,16 +5,18 @@ module Redd
5
5
  # Unmarshals hashes into objects.
6
6
  class Unmarshaller
7
7
  # Contains the mapping from 'kind' strings to classes.
8
+ # TODO: UserList type!
8
9
  MAPPING = {
9
- 't1' => Models::Comment,
10
- 't2' => Models::User,
11
- 't3' => Models::Submission,
12
- 't4' => Models::PrivateMessage,
13
- 't5' => Models::Subreddit,
14
- 'more' => Models::MoreComments,
15
- 'wikipage' => Models::WikiPage,
16
- 'Listing' => Models::Listing,
17
- 'LabeledMulti' => Models::Multireddit
10
+ 't1' => Models::Comment,
11
+ 't2' => Models::User,
12
+ 't3' => Models::Submission,
13
+ 't4' => Models::PrivateMessage,
14
+ 't5' => Models::Subreddit,
15
+ 'more' => Models::MoreComments,
16
+ 'wikipage' => Models::WikiPage,
17
+ 'Listing' => Models::Listing,
18
+ 'LabeledMulti' => Models::Multireddit,
19
+ 'LiveUpdateEvent' => Models::LiveThread
18
20
  }.freeze
19
21
 
20
22
  def initialize(client)
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Redd
4
- VERSION = '0.8.0.pre.2'
4
+ VERSION = '0.8.0'
5
5
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: redd
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.8.0.pre.2
4
+ version: 0.8.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Avinash Dwarapu
@@ -152,11 +152,14 @@ files:
152
152
  - lib/redd/models/access.rb
153
153
  - lib/redd/models/basic_model.rb
154
154
  - lib/redd/models/comment.rb
155
+ - lib/redd/models/conversation.rb
155
156
  - lib/redd/models/front_page.rb
156
157
  - lib/redd/models/inboxable.rb
157
158
  - lib/redd/models/lazy_model.rb
158
159
  - lib/redd/models/listing.rb
160
+ - lib/redd/models/live_thread.rb
159
161
  - lib/redd/models/messageable.rb
162
+ - lib/redd/models/mod_mail.rb
160
163
  - lib/redd/models/moderatable.rb
161
164
  - lib/redd/models/more_comments.rb
162
165
  - lib/redd/models/multireddit.rb
@@ -191,9 +194,9 @@ required_ruby_version: !ruby/object:Gem::Requirement
191
194
  version: '0'
192
195
  required_rubygems_version: !ruby/object:Gem::Requirement
193
196
  requirements:
194
- - - ">"
197
+ - - ">="
195
198
  - !ruby/object:Gem::Version
196
- version: 1.3.1
199
+ version: '0'
197
200
  requirements: []
198
201
  rubyforge_project:
199
202
  rubygems_version: 2.6.8