foobara-http-command-connector 0.0.13 → 0.0.15

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: f050dbda61782345868886aeb89b9f79160aafd2ec23ed5c9295c962460360dc
4
- data.tar.gz: 8baa30f94268fecc85e9b9f86676f03a484d5efbc797a5aedd35f62d770f24b0
3
+ metadata.gz: 4a6e931ec6770cb9d080f7881905dfac20b5246a0ca5726e14ce37151edff543
4
+ data.tar.gz: b11048224ade66b0fda7dc73b33ce49f522402e283e8ac10bd776e5548c9b6bd
5
5
  SHA512:
6
- metadata.gz: ea971dd972af3d7845e9a206e4dc956eb1b29f674b34d4389a7f67e360e4559b8dd5cf9cc9e6475ee98aadb63985aff93d9c4b4d75fe9f9cf07e8f2e1054b6cf
7
- data.tar.gz: f8bbcb34388d4042df81fafdd9e286d2b2cca9a560e1dcd541f0fa83e38d7b402858f6c2f0ef48c858386468db1a7c64bcfd7e30df264bdbc10d87ce771dd383
6
+ metadata.gz: 3b4386dd8cbcdccd2b4fe4bc02dde29cae04704fa56e5458dd77d712515518c9e91af64664255679f81539c6b33346b3c8aa91e33cdac95ba98073a5d74359d1
7
+ data.tar.gz: 5fbb2a89db7b9605e0509eaac865feea185dd13ac6067c2ce8166cac87970bcf09ab3e2ba31f02c6cfb4328e86b2bbb304cc32ada10193411bd1f0948e001e15
data/CHANGELOG.md CHANGED
@@ -1,6 +1,11 @@
1
- ## [0.0.13] - 2025-01-30
1
+ ## [0.0.15] - 2025-03-28
2
2
 
3
- - Make sure manifest is ran in detached context
3
+ - Implement MoveAttributeToCookie response mutator
4
+ - Decouple Help command from html serialization
5
+
6
+ ## [0.0.14] - 2025-02-02
7
+
8
+ - Put manifest into detached context by default
4
9
 
5
10
  ## [0.0.12] - 2025-01-28
6
11
 
@@ -3,15 +3,33 @@ module Foobara
3
3
  class Http < Foobara::CommandConnector
4
4
  module Commands
5
5
  class Describe < Foobara::CommandConnector::Commands::Describe
6
+ inputs do
7
+ manifestable :duck
8
+ request :duck
9
+ detached :boolean, default: true
10
+ end
11
+
6
12
  def stamp_request_metadata
7
13
  manifest[:metadata] = super.merge(url: request.url)
8
14
  end
9
15
 
16
+ def in_detached_context(&)
17
+ Thread.foobara_with_var("foobara_manifest_context", detached: true, &)
18
+ end
19
+
10
20
  def build_manifest
11
- Thread.foobara_with_var("foobara_manifest_context", detached: true) do
21
+ if detached_context?
22
+ in_detached_context do
23
+ super
24
+ end
25
+ else
12
26
  super
13
27
  end
14
28
  end
29
+
30
+ def detached_context?
31
+ detached
32
+ end
15
33
  end
16
34
  end
17
35
  end
@@ -0,0 +1,14 @@
1
+ module Foobara
2
+ module CommandConnectors
3
+ class Http < CommandConnector
4
+ module Commands
5
+ class Help < Command
6
+ class Presenter
7
+ class RequestFailed < Presenter
8
+ end
9
+ end
10
+ end
11
+ end
12
+ end
13
+ end
14
+ end
@@ -41,6 +41,8 @@ module Foobara
41
41
  Presenter::Processor
42
42
  when Manifest::ProcessorClass
43
43
  Presenter::ProcessorClass
44
+ when ErrorCollection
45
+ Presenter::RequestFailed
44
46
  else
45
47
  # :nocov:
46
48
  raise "No presenter found for #{manifest.path}"
@@ -171,7 +173,9 @@ module Foobara
171
173
  end
172
174
 
173
175
  def respond_to_missing?(method_name, include_private = false)
176
+ # :nocov:
174
177
  manifest.respond_to?(method_name, include_private)
178
+ # :nocov:
175
179
  end
176
180
  end
177
181
  end
@@ -0,0 +1,22 @@
1
+ module Foobara
2
+ module CommandConnectors
3
+ class Http < CommandConnector
4
+ module Commands
5
+ class Help < Command
6
+ class ResultSerializer < Serializer
7
+ def serialize(object_to_help_with)
8
+ presenter = Presenter.for(object_to_help_with)
9
+
10
+ template_path = presenter.template_path
11
+ template_body = File.read(template_path)
12
+ template = ERB.new(template_body)
13
+ template.filename = template_path
14
+
15
+ template.result(presenter.instance_eval { binding })
16
+ end
17
+ end
18
+ end
19
+ end
20
+ end
21
+ end
22
+ end
@@ -0,0 +1 @@
1
+ Request Failed: <%= to_sentence %>
@@ -3,23 +3,20 @@ module Foobara
3
3
  class Http < CommandConnector
4
4
  module Commands
5
5
  class Help < Command
6
- description "Will extract items from the request to help with. Assumes the help is desired in HTML format"
6
+ description "Will extract items from the request to help with"
7
7
  inputs request: Http::Request
8
- result :string
8
+ result :duck
9
9
  possible_error CommandConnector::NotFoundError
10
10
 
11
11
  def execute
12
12
  load_manifest
13
13
  determine_object_to_help_with
14
- build_presenter
15
- load_template
16
- generate_html_from_template
17
- set_header_to_html
14
+ set_manifest_to_help_with
18
15
 
19
- html
16
+ manifest_to_help_with
20
17
  end
21
18
 
22
- attr_accessor :raw_manifest, :root_manifest, :object_to_help_with, :template, :html, :presenter
19
+ attr_accessor :raw_manifest, :root_manifest, :object_to_help_with, :manifest_to_help_with
23
20
 
24
21
  def load_manifest
25
22
  self.raw_manifest = command_connector.foobara_manifest
@@ -35,6 +32,7 @@ module Foobara
35
32
  if result
36
33
  self.object_to_help_with = result
37
34
  else
35
+ # TODO: we should look up from the command connector's namespace instead, right?
38
36
  result = GlobalOrganization.foobara_lookup(arg, mode:)
39
37
 
40
38
  if result && root_manifest.contains?(result.foobara_manifest_reference,
@@ -54,38 +52,12 @@ module Foobara
54
52
  end
55
53
  end
56
54
 
57
- def build_presenter
58
- self.presenter = Help::Presenter.for(manifest_to_help_with)
59
- end
60
-
61
- def template_path
62
- presenter.template_path
63
- end
64
-
65
- def load_template
66
- template_body = File.read(template_path)
67
-
68
- erb = ERB.new(template_body)
69
- erb.filename = template_path
70
-
71
- self.template = erb
72
- end
73
-
74
- def generate_html_from_template
75
- self.html = template.result(presenter.instance_eval { binding })
76
- end
77
-
78
- def set_header_to_html
79
- request.response_headers ||= {}
80
- request.response_headers = request.response_headers.merge("content-type" => "text/html")
81
- end
82
-
83
- def manifest_to_help_with
84
- @manifest_to_help_with ||= if object_to_help_with.is_a?(Manifest::BaseManifest)
85
- object_to_help_with
86
- else
87
- root_manifest.lookup(object_to_help_with.foobara_manifest_reference)
88
- end
55
+ def set_manifest_to_help_with
56
+ self.manifest_to_help_with = if object_to_help_with.is_a?(Manifest::BaseManifest)
57
+ object_to_help_with
58
+ else
59
+ root_manifest.lookup(object_to_help_with.foobara_manifest_reference)
60
+ end
89
61
  end
90
62
 
91
63
  def command_connector
@@ -0,0 +1,31 @@
1
+ module Foobara
2
+ module CommandConnectors
3
+ class Http < CommandConnector
4
+ class Cookie
5
+ attr_accessor :name, :value, :opts
6
+
7
+ ALLOWED_OPTIONS = %i[path httponly secure same_site domain expires max_age].freeze
8
+
9
+ def initialize(name, value, **opts)
10
+ invalid_options = opts.keys - ALLOWED_OPTIONS
11
+
12
+ unless invalid_options.empty?
13
+ # :nocov:
14
+ raise ArgumentError, "Invalid options #{invalid_options.inspect} expected only #{ALLOWED_OPTIONS.inspect}"
15
+ # :nocov:
16
+ end
17
+
18
+ self.name = name
19
+ self.value = value
20
+ self.opts = opts.transform_keys(&:to_sym)
21
+ end
22
+
23
+ ALLOWED_OPTIONS.each do |option|
24
+ define_method option do
25
+ opts[option]
26
+ end
27
+ end
28
+ end
29
+ end
30
+ end
31
+ end
data/src/http/response.rb CHANGED
@@ -3,11 +3,22 @@ module Foobara
3
3
  class Http < CommandConnector
4
4
  class Response < CommandConnector::Response
5
5
  attr_accessor :headers
6
+ attr_writer :cookies
6
7
 
7
- def initialize(headers:, **)
8
+ def initialize(headers: nil, cookies: nil, **)
8
9
  self.headers = headers
10
+ self.cookies = cookies
11
+
9
12
  super(**)
10
13
  end
14
+
15
+ def cookies
16
+ @cookies ||= []
17
+ end
18
+
19
+ def add_cookie(cookie_name, cookie_value, cookie_opts)
20
+ cookies << Cookie.new(cookie_name, cookie_value, **cookie_opts)
21
+ end
11
22
  end
12
23
  end
13
24
  end
@@ -0,0 +1,47 @@
1
+ module Foobara
2
+ module CommandConnectors
3
+ class Http < CommandConnector
4
+ class MoveAttributeToCookie < ResponseMutator
5
+ class << self
6
+ attr_accessor :attribute_name, :cookie_name, :cookie_opts
7
+
8
+ def for(attribute_name, cookie_name = attribute_name, **cookie_opts)
9
+ subclass = Class.new(self)
10
+
11
+ subclass.attribute_name = attribute_name
12
+ subclass.cookie_name = cookie_name
13
+ subclass.cookie_opts = cookie_opts
14
+
15
+ subclass
16
+ end
17
+ end
18
+
19
+ attr_writer :attribute_name, :cookie_name, :cookie_opts
20
+
21
+ def result_type_from(result_type)
22
+ AttributesTransformers.reject(result_type.declaration_data)
23
+ new_declaration = TypeDeclarations::Attributes.reject(result_type.declaration_data, attribute_name)
24
+
25
+ Domain.current.foobara_type_from_declaration(new_declaration)
26
+ end
27
+
28
+ def mutate(response)
29
+ cookie_value = response.body.delete(attribute_name)
30
+ response.add_cookie(cookie_name, cookie_value, cookie_opts)
31
+ end
32
+
33
+ def attribute_name
34
+ @attribute_name ||= self.class.attribute_name
35
+ end
36
+
37
+ def cookie_name
38
+ @cookie_name ||= self.class.cookie_name
39
+ end
40
+
41
+ def cookie_opts
42
+ @cookie_opts ||= self.class.cookie_opts
43
+ end
44
+ end
45
+ end
46
+ end
47
+ end
data/src/http.rb CHANGED
@@ -58,57 +58,59 @@ module Foobara
58
58
  super(*, prefix:, **)
59
59
  end
60
60
 
61
- def request_to_command(context)
62
- if context.method == "OPTIONS"
61
+ def request_to_command(request)
62
+ if request.method == "OPTIONS"
63
63
  # TODO: this feels a bit hacky and like overkill...
64
64
  return Foobara::CommandConnectors::Http::Commands::GetOptions.new
65
65
  end
66
66
 
67
67
  command = super
68
68
 
69
- if context.action == "help"
70
- # Let's unwrap the transformed command to avoid serialization
71
- # TODO: maybe instead register Help without serializers?
72
- command = command.command
69
+ # TODO: We should kill these case statements and require connecting these commands
70
+ if request.action == "help"
71
+ command.class.serializers = [Commands::Help::ResultSerializer]
73
72
  end
74
73
 
75
74
  command
76
75
  end
77
76
 
78
- def request_to_response(request)
79
- command = request.command
77
+ def set_response_status(response)
78
+ command = response.command
80
79
  outcome = command.outcome
81
80
 
82
- # TODO: feels awkward to call this here... Maybe use result/errors transformers instead??
83
- # Or call the serializer here??
84
- body = command.respond_to?(:serialize_result) ? command.serialize_result : outcome.result
85
-
86
- status = if outcome.success?
87
- 200
88
- else
89
- errors = outcome.errors
90
-
91
- if errors.size == 1
92
- error = errors.first
93
-
94
- case error
95
- when CommandConnector::UnknownError
96
- 500
97
- when CommandConnector::NotFoundError, Foobara::Entity::NotFoundError
98
- # TODO: we should not be coupled to Entities here...
99
- body ||= "Not found"
100
- 404
101
- when CommandConnector::UnauthenticatedError
102
- 401
103
- when CommandConnector::NotAllowedError
104
- 403
105
- end
106
- end || 422
107
- end
108
-
109
- headers = headers_for(request)
110
-
111
- Response.new(status:, headers:, body:, request:)
81
+ response.status = if outcome.success?
82
+ 200
83
+ else
84
+ errors = outcome.errors
85
+
86
+ if errors.size == 1
87
+ error = errors.first
88
+
89
+ case error
90
+ when CommandConnector::UnknownError
91
+ 500
92
+ when CommandConnector::NotFoundError, Foobara::Entity::NotFoundError
93
+ # TODO: we should not be coupled to Entities here...
94
+ 404
95
+ when CommandConnector::UnauthenticatedError
96
+ 401
97
+ when CommandConnector::NotAllowedError
98
+ 403
99
+ end
100
+ end || 422
101
+ end
102
+ end
103
+
104
+ def mutate_response(response)
105
+ super
106
+
107
+ headers = headers_for(response.request)
108
+
109
+ if headers&.any?
110
+ response.headers = (response.headers || {}).merge(headers)
111
+ else
112
+ response.headers ||= {}
113
+ end
112
114
  end
113
115
 
114
116
  def headers_for(request)
metadata CHANGED
@@ -1,28 +1,28 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: foobara-http-command-connector
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.13
4
+ version: 0.0.15
5
5
  platform: ruby
6
6
  authors:
7
7
  - Miles Georgi
8
8
  bindir: bin
9
9
  cert_chain: []
10
- date: 2025-01-31 00:00:00.000000000 Z
10
+ date: 2025-03-28 00:00:00.000000000 Z
11
11
  dependencies:
12
12
  - !ruby/object:Gem::Dependency
13
13
  name: foobara
14
14
  requirement: !ruby/object:Gem::Requirement
15
15
  requirements:
16
- - - ">="
16
+ - - "~>"
17
17
  - !ruby/object:Gem::Version
18
- version: '0'
18
+ version: 0.0.88
19
19
  type: :runtime
20
20
  prerelease: false
21
21
  version_requirements: !ruby/object:Gem::Requirement
22
22
  requirements:
23
- - - ">="
23
+ - - "~>"
24
24
  - !ruby/object:Gem::Version
25
- version: '0'
25
+ version: 0.0.88
26
26
  email:
27
27
  - azimux@gmail.com
28
28
  executables: []
@@ -48,8 +48,10 @@ files:
48
48
  - src/http/commands/help/presenter/organization.rb
49
49
  - src/http/commands/help/presenter/processor.rb
50
50
  - src/http/commands/help/presenter/processor_class.rb
51
+ - src/http/commands/help/presenter/request_failed.rb
51
52
  - src/http/commands/help/presenter/root.rb
52
53
  - src/http/commands/help/presenter/type.rb
54
+ - src/http/commands/help/result_serializer.rb
53
55
  - src/http/commands/help/templates/command.html.erb
54
56
  - src/http/commands/help/templates/domain.html.erb
55
57
  - src/http/commands/help/templates/entity.html.erb
@@ -58,10 +60,13 @@ files:
58
60
  - src/http/commands/help/templates/organization.html.erb
59
61
  - src/http/commands/help/templates/processor.html.erb
60
62
  - src/http/commands/help/templates/processor_class.html.erb
63
+ - src/http/commands/help/templates/request_failed.html.erb
61
64
  - src/http/commands/help/templates/root.html.erb
62
65
  - src/http/commands/help/templates/type.html.erb
66
+ - src/http/cookie.rb
63
67
  - src/http/request.rb
64
68
  - src/http/response.rb
69
+ - src/http/response_mutators/move_attribute_to_cookie.rb
65
70
  homepage: https://github.com/foobara/http-command-connector
66
71
  licenses:
67
72
  - Apache-2.0
@@ -85,7 +90,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
85
90
  - !ruby/object:Gem::Version
86
91
  version: '0'
87
92
  requirements: []
88
- rubygems_version: 3.6.3
93
+ rubygems_version: 3.6.6
89
94
  specification_version: 4
90
95
  summary: No description. Add one.
91
96
  test_files: []