distributed-press-api-client 0.5.0rc3 → 0.5.0rc5

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
  SHA256:
3
- metadata.gz: 5e02ff077d2abf2abdfc55a7d71e425c4b1a951558b036dbb247dfc369518cf1
4
- data.tar.gz: 0ec16a94b2363883abca06b6bdd46d8f593bbc01cc32801c40d8951b0d6815a3
3
+ metadata.gz: 6b468eae410973ff56d5e6eb85e04e9a2bdeb375f274841fff3599a71adf220e
4
+ data.tar.gz: 4bba1c34d1d866264af766c57b3beadcc70a4e064d9b0e50686bf2a2940d4e9c
5
5
  SHA512:
6
- metadata.gz: 4d3e9f5f978c5761c416f9817b598c320c68315609f626cdfccc13c765b5b198d1fd0d0765614ac65db613abc47891209ada12015e9f05bce0f3c37e4c3afaa6
7
- data.tar.gz: 06d08f6ca0419ff3a0b33b682bf8d99e15c0a93cd9e7c49a0df226287040e768d5e020634d35d58bf58090826f6fba903bde17b26c6d805569b1acaa4b0b82c9
6
+ metadata.gz: e90870a42b49134a6a2916f87363a11f35514effc99b72f38044c4a2d5bb1505b2d42c82e4c6f7277fa8ad9f321ef86f867e070e74aff3742826e2a16892ade5
7
+ data.tar.gz: 676e4969b7c5dcbc785157ee38599de7faf823c62659c21b9108dd04ae0cbff6e62e26390bbcc407f9ac76a8566758b646ee36b16baeb235b157c0af290124f1
@@ -7,6 +7,7 @@ require 'time'
7
7
  require 'digest/sha2'
8
8
  require 'uri'
9
9
  require_relative '../../version'
10
+ require_relative '../../../httparty/parser/nokogiri'
10
11
  require_relative 'signed_headers'
11
12
 
12
13
  # Retro-compatibility for URI < 0.12
@@ -0,0 +1,35 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative 'referenced_object'
4
+
5
+ class DistributedPress
6
+ module V1
7
+ module Social
8
+ # A Collection or OrderedCollection is a an object with a list of
9
+ # items. Sometimes, collections are paginated, so we provide
10
+ # methods to traverse them.
11
+ class Collection < ReferencedObject
12
+ include Enumerable
13
+
14
+ RECURSIVE_ATTRIBUTES = %w[items orderedItems first next].freeze
15
+
16
+ # If the Collection has items, yield them and keep processing
17
+ # any pages forward until the end.
18
+ #
19
+ # @todo Use totalItems from the starting object for validation
20
+ # @todo Implement lazy loading
21
+ def each(&block)
22
+ Enumerator.new do |enum|
23
+ RECURSIVE_ATTRIBUTES.each do |attribute|
24
+ next unless object.key?(attribute)
25
+
26
+ object[attribute].each(&block).each do |item|
27
+ enum << item
28
+ end
29
+ end
30
+ end
31
+ end
32
+ end
33
+ end
34
+ end
35
+ end
@@ -3,6 +3,7 @@
3
3
  require 'addressable'
4
4
  require_relative 'reference'
5
5
  require_relative 'referenced_object'
6
+ require_relative 'collection'
6
7
 
7
8
  class DistributedPress
8
9
  module V1
@@ -17,7 +18,7 @@ class DistributedPress
17
18
  def _dump(_)
18
19
  Marshal.dump(client)
19
20
  end
20
-
21
+
21
22
  def self._load(client)
22
23
  new(client: Marshal.load(client))
23
24
  end
@@ -25,22 +26,61 @@ class DistributedPress
25
26
  # @param :client [DistributedPress::V1::Social::Client]
26
27
  def initialize(client:)
27
28
  @client = client
29
+ # @todo Replace with a class
28
30
  @parser =
29
31
  proc do |body, format|
32
+ next HTTParty::Parser.call(body, :html) if body&.starts_with? '<'
30
33
  next HTTParty::Parser.call(body, format || :plain) unless body&.starts_with? '{'
31
34
 
32
- ReferencedObject.new(object: HTTParty::Parser.call(body, :json), dereferencer: self)
35
+ object = HTTParty::Parser.call(body, :json)
36
+
37
+ # @todo Actually validate objects
38
+ case object['type']
39
+ when 'Collection', 'OrderedCollection', 'CollectionPage'
40
+ Collection.new(object: object, dereferencer: self)
41
+ else
42
+ ReferencedObject.new(object: object, dereferencer: self)
43
+ end
33
44
  end
34
45
  end
35
46
 
36
- # Fetch a URI
47
+ # Fetch a URI, if it's an HTML page, look for the alternate
48
+ # version so we always have the correct activity.
37
49
  #
50
+ # @todo Raise an error if the content-type is not supported?
38
51
  # @param :uri [String, Addressable::URI]
39
52
  # @return [HTTParty::Response]
40
53
  def get(uri:)
41
- uri = uris(uri)
54
+ response = nil
55
+
56
+ loop do
57
+ uri = uris(uri)
58
+ client = clients(uri)
59
+ response = client.get(endpoint: uri.path, parser: @parser)
60
+
61
+ # Break the loop if the request failed
62
+ break unless response.success?
63
+ # Or if it's not an HTML document
64
+ break unless response.parsed_response.is_a?(::Nokogiri::HTML5::Document)
65
+
66
+ link = response.parsed_response.css('link[rel=alternate]').find do |link|
67
+ next unless link['type']
68
+ next true if client.class::ACCEPT.include?(link['type'])
69
+
70
+ client.class::ACCEPT.any? do |accept|
71
+ link['type'].start_with? accept
72
+ end
73
+ end
74
+
75
+ break if link.nil?
76
+ break if link['href'].nil?
77
+ break if link['href'].empty?
78
+
79
+ # Start loop again with the new URI
80
+ uri = link['href']
81
+ end
42
82
 
43
- clients(uri).get(endpoint: uri.path, parser: @parser)
83
+ response
44
84
  end
45
85
 
46
86
  # Gets a client for a URI
@@ -25,12 +25,14 @@ class DistributedPress
25
25
  #
26
26
  # @param actor_url [String] The URL where the Actor profile is hosted
27
27
  # @param announce [Boolean] Automatically announce new accounts
28
+ # @param manually_approves_followers [Boolean] Automatically accept follow requests
28
29
  # @return [HTTParty::Response]
29
- def create(actor_url, announce = false)
30
+ def create(actor_url, announce: false, manually_approves_followers: false)
30
31
  inbox_body = {
31
32
  'actorUrl' => actor_url,
32
33
  'publicKeyId' => "#{actor_url}#main-key",
33
34
  'announce' => announce,
35
+ 'manuallyApprovesFollowers' => manually_approves_followers,
34
36
  'keypair' => {
35
37
  'publicKeyPem' => client.public_key.public_to_pem,
36
38
  'privateKeyPem' => client.private_key.export
@@ -8,6 +8,11 @@ class DistributedPress
8
8
  class Reference
9
9
  extend Forwardable
10
10
 
11
+ # Public addressing doesn't lead to an activity
12
+ #
13
+ # @return [String]
14
+ PUBLIC = 'https://www.w3.org/ns/activitystreams#Public'
15
+
11
16
  # @return [String]
12
17
  attr_reader :uri
13
18
 
@@ -28,11 +33,18 @@ class DistributedPress
28
33
  @object ||= dereferencer.get(uri: uri)
29
34
  end
30
35
 
36
+ # Is this a public post?
37
+ #
38
+ # @return [Bool]
39
+ def public?
40
+ [slice(*%w[audience to cc]).values].flatten.include? PUBLIC
41
+ end
42
+
31
43
  def inspect
32
44
  "#{self.class.name}(#{uri})"
33
45
  end
34
46
 
35
- def_delegators :object, :[], :dig, :to_h, :to_json
47
+ def_delegators :object, :[], :dig, :to_h, :to_json, :slice
36
48
  end
37
49
  end
38
50
  end
@@ -18,6 +18,7 @@ class DistributedPress
18
18
  replies
19
19
  to
20
20
  publicKey
21
+ audience
21
22
 
22
23
  alsoKnownAs
23
24
  devices
@@ -73,13 +74,22 @@ class DistributedPress
73
74
  when Hash
74
75
  reference_object!(o)
75
76
  o
76
- when String then dereferencer.references(dereferencer.uris(o))
77
+ when String
78
+ if o == DistributedPress::V1::Social::Reference::PUBLIC
79
+ o
80
+ else
81
+ dereferencer.references(dereferencer.uris(o))
82
+ end
83
+ else
84
+ o
77
85
  end
78
86
  end
79
87
  when Hash
80
88
  reference_object!(object[attribute])
81
89
  when String
82
- object[attribute] = dereferencer.references(dereferencer.uris(object[attribute]))
90
+ unless object[attribute] == DistributedPress::V1::Social::Reference::PUBLIC
91
+ object[attribute] = dereferencer.references(dereferencer.uris(object[attribute]))
92
+ end
83
93
  end
84
94
  end
85
95
  end
@@ -3,5 +3,5 @@
3
3
  # API client
4
4
  class DistributedPress
5
5
  # Version
6
- VERSION = '0.5.0rc3'
6
+ VERSION = '0.5.0rc5'
7
7
  end
@@ -0,0 +1,21 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'httparty/parser'
4
+ require 'nokogiri'
5
+
6
+ module HTTParty
7
+ class Parser
8
+ # Parse HTML as Nokogiri documents
9
+ module Nokogiri
10
+ protected
11
+
12
+ def html
13
+ ::Nokogiri::HTML5(body)
14
+ end
15
+ end
16
+ end
17
+ end
18
+
19
+ HTTParty::Parser.class_eval do
20
+ prepend HTTParty::Parser::Nokogiri
21
+ end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: distributed-press-api-client
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.5.0rc3
4
+ version: 0.5.0rc5
5
5
  platform: ruby
6
6
  authors:
7
7
  - f
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2024-06-17 00:00:00.000000000 Z
11
+ date: 2024-07-18 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: addressable
@@ -120,6 +120,20 @@ dependencies:
120
120
  - - "~>"
121
121
  - !ruby/object:Gem::Version
122
122
  version: 2.6.0
123
+ - !ruby/object:Gem::Dependency
124
+ name: nokogiri
125
+ requirement: !ruby/object:Gem::Requirement
126
+ requirements:
127
+ - - "~>"
128
+ - !ruby/object:Gem::Version
129
+ version: '1.16'
130
+ type: :runtime
131
+ prerelease: false
132
+ version_requirements: !ruby/object:Gem::Requirement
133
+ requirements:
134
+ - - "~>"
135
+ - !ruby/object:Gem::Version
136
+ version: '1.16'
123
137
  - !ruby/object:Gem::Dependency
124
138
  name: activesupport
125
139
  requirement: !ruby/object:Gem::Requirement
@@ -310,6 +324,7 @@ files:
310
324
  - lib/distributed_press/v1/social/allowlist.rb
311
325
  - lib/distributed_press/v1/social/blocklist.rb
312
326
  - lib/distributed_press/v1/social/client.rb
327
+ - lib/distributed_press/v1/social/collection.rb
313
328
  - lib/distributed_press/v1/social/dereferencer.rb
314
329
  - lib/distributed_press/v1/social/followers.rb
315
330
  - lib/distributed_press/v1/social/hook.rb
@@ -324,6 +339,7 @@ files:
324
339
  - lib/distributed_press/version.rb
325
340
  - lib/dry/schema/processor_decorator.rb
326
341
  - lib/dry/schema/result_decorator.rb
342
+ - lib/httparty/parser/nokogiri.rb
327
343
  - lib/jekyll-distributed-press-v0.rb
328
344
  homepage: https://0xacab.org/sutty/distributed-press-api-client
329
345
  licenses: