hephaestus 0.7.2 → 0.7.2.2
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 +4 -4
- data/CHANGELOG.md +12 -0
- data/app/controllers/concerns/hephaestus/responses.rb +107 -0
- data/app/controllers/concerns/hephaestus/validates_from_yetto.rb +51 -0
- data/app/controllers/hephaestus/application_controller.rb +42 -0
- data/app/controllers/hephaestus/root_controller.rb +10 -0
- data/app/controllers/hephaestus/settings_controller.rb +20 -0
- data/app/controllers/hephaestus/staff_controller.rb +20 -0
- data/app/jobs/hephaestus/application_job.rb +12 -0
- data/app/jobs/hephaestus/update_yetto_job.rb +39 -0
- data/app/models/hephaestus/application_record.rb +8 -0
- data/app/serializers/hephaestus/error_serializer.rb +18 -0
- data/app/serializers/hephaestus/headers.rb +27 -0
- data/app/services/hephaestus/yetto_service.rb +99 -0
- data/app/views/layouts/staff.html.erb +7 -0
- data/app/views/staff/index.html.erb +1 -0
- data/config/database.yml +49 -0
- data/config/environments/development.rb +89 -0
- data/config/environments/production.rb +96 -0
- data/config/environments/staging.rb +94 -0
- data/config/environments/test.rb +73 -0
- data/config/initializers/application.rb +14 -0
- data/config/initializers/cors.rb +19 -0
- data/config/initializers/environment.rb +92 -0
- data/config/initializers/filter_parameter_logging.rb +23 -0
- data/config/initializers/inflections.rb +21 -0
- data/config/initializers/litestream.rb +36 -0
- data/config/initializers/lograge.rb +27 -0
- data/config/initializers/opentelemetry.rb +40 -0
- data/config/initializers/sidekiq.rb +13 -0
- data/config/initializers/slack_webhook_logger.rb +19 -0
- data/config/litestream.yml +12 -0
- data/config/queue.yml +18 -0
- data/config/recurring.yml +10 -0
- data/config/routes.rb +17 -0
- data/db/queue_schema.rb +129 -0
- data/lib/hephaestus/version.rb +1 -1
- metadata +36 -19
- data/templates/.dockerignore +0 -39
- data/templates/.env.sample +0 -6
- data/templates/.github/dependabot.yml +0 -27
- data/templates/.github/workflows/automerge.yml +0 -17
- data/templates/.github/workflows/deploy.yml +0 -30
- data/templates/.github/workflows/licenses.yml +0 -23
- data/templates/.github/workflows/lint.yml +0 -32
- data/templates/.github/workflows/security.yml +0 -15
- data/templates/.github/workflows/sorbet.yml +0 -19
- data/templates/.github/workflows/test.yml +0 -21
- data/templates/.licensed.yml +0 -43
- data/templates/.rubocop.yml +0 -5
- data/templates/.ruby-version +0 -1
- data/templates/.vscode/extensions.json +0 -9
- data/templates/.vscode/launch.json +0 -13
- data/templates/.vscode/settings.json +0 -52
- data/templates/test/integration/.keep +0 -0
- data/templates/test/mailers/.keep +0 -0
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: aa434c3350cbeb0ba0f33457265f2f191196762b7b29d0857ed974cee9f8c008
|
4
|
+
data.tar.gz: 1ac324371d86e09c465918289d7ab64024d35ab3b3331de831816f37d150c6b8
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 16c8f996fffbbda083c2c399e17691566a3b7a57ae83cf3f2653c7f8b01be60add0da975c47b99d5c7ce0ee3989dc92edab07396b320bf498fb29dc02d5eabb8
|
7
|
+
data.tar.gz: 7fac9568440247732d5c8f946f1992639d428c02424613e84a7be9f5b8f887cc17f6cd0598d1bd406d5fd4331c2078b2a187e7eff3fd6b99463b24565f761f66
|
data/CHANGELOG.md
CHANGED
@@ -1,3 +1,15 @@
|
|
1
|
+
# [v0.7.2.2] - 16-11-2024
|
2
|
+
## What's Changed
|
3
|
+
* is not yet available by @gjtorikian in https://github.com/yettoapp/hephaestus/pull/33
|
4
|
+
|
5
|
+
|
6
|
+
**Full Changelog**: https://github.com/yettoapp/hephaestus/compare/v0.7.2.1...v0.7.2.2
|
7
|
+
# [v0.7.2.1] - 16-11-2024
|
8
|
+
## What's Changed
|
9
|
+
* include all files in the gem by @gjtorikian in https://github.com/yettoapp/hephaestus/pull/31
|
10
|
+
|
11
|
+
|
12
|
+
**Full Changelog**: https://github.com/yettoapp/hephaestus/compare/v0.7.2...v0.7.2.1
|
1
13
|
# [v0.7.2] - 16-11-2024
|
2
14
|
## What's Changed
|
3
15
|
* [skip test] Release v0.7.1 by @github-actions in https://github.com/yettoapp/hephaestus/pull/28
|
@@ -0,0 +1,107 @@
|
|
1
|
+
# typed: false
|
2
|
+
# frozen_string_literal: true
|
3
|
+
|
4
|
+
module Hephaestus
|
5
|
+
module Responses
|
6
|
+
def no_content
|
7
|
+
head(:no_content)
|
8
|
+
end
|
9
|
+
|
10
|
+
def okay
|
11
|
+
render(
|
12
|
+
json: {
|
13
|
+
message: "OK",
|
14
|
+
}.to_json,
|
15
|
+
status: :ok,
|
16
|
+
)
|
17
|
+
end
|
18
|
+
|
19
|
+
def created
|
20
|
+
render(
|
21
|
+
json: {
|
22
|
+
message: "Created",
|
23
|
+
}.to_json,
|
24
|
+
status: :created,
|
25
|
+
)
|
26
|
+
end
|
27
|
+
|
28
|
+
def bad_request
|
29
|
+
render(
|
30
|
+
json: {
|
31
|
+
errors: [
|
32
|
+
{
|
33
|
+
message: "Bad Request",
|
34
|
+
},
|
35
|
+
],
|
36
|
+
}.to_json,
|
37
|
+
status: :bad_request,
|
38
|
+
)
|
39
|
+
end
|
40
|
+
|
41
|
+
def forbidden
|
42
|
+
render(
|
43
|
+
json: {
|
44
|
+
errors: [
|
45
|
+
{
|
46
|
+
message: "Forbidden",
|
47
|
+
},
|
48
|
+
],
|
49
|
+
}.to_json,
|
50
|
+
status: :forbidden,
|
51
|
+
)
|
52
|
+
end
|
53
|
+
|
54
|
+
def not_acceptable
|
55
|
+
render(
|
56
|
+
json: ::Hephaestus::ErrorSerializer.format("Not Acceptable").to_json,
|
57
|
+
status: :not_acceptable,
|
58
|
+
)
|
59
|
+
end
|
60
|
+
|
61
|
+
def not_found
|
62
|
+
render(
|
63
|
+
json: ::Hephaestus::ErrorSerializer.format("Not Found").to_json,
|
64
|
+
status: :not_found,
|
65
|
+
)
|
66
|
+
end
|
67
|
+
|
68
|
+
def service_unavailable(msg)
|
69
|
+
render(
|
70
|
+
json: {
|
71
|
+
errors: [
|
72
|
+
{
|
73
|
+
message: "Service Unavailable: #{msg}",
|
74
|
+
},
|
75
|
+
],
|
76
|
+
}.to_json,
|
77
|
+
status: :service_unavailable,
|
78
|
+
)
|
79
|
+
end
|
80
|
+
|
81
|
+
def bad_gateway
|
82
|
+
render(
|
83
|
+
json: {
|
84
|
+
errors: [
|
85
|
+
{
|
86
|
+
message: "Bad Gateway",
|
87
|
+
},
|
88
|
+
],
|
89
|
+
}.to_json,
|
90
|
+
status: :bad_gateway,
|
91
|
+
)
|
92
|
+
end
|
93
|
+
|
94
|
+
def internal_server_error
|
95
|
+
render(
|
96
|
+
json: {
|
97
|
+
errors: [
|
98
|
+
{
|
99
|
+
message: "Internal Server Error",
|
100
|
+
},
|
101
|
+
],
|
102
|
+
}.to_json,
|
103
|
+
status: :internal_server_error,
|
104
|
+
)
|
105
|
+
end
|
106
|
+
end
|
107
|
+
end
|
@@ -0,0 +1,51 @@
|
|
1
|
+
# typed: false
|
2
|
+
# frozen_string_literal: true
|
3
|
+
|
4
|
+
module Hephaestus
|
5
|
+
module ValidatesFromYetto
|
6
|
+
SHA256_DIGEST = OpenSSL::Digest.new("sha256")
|
7
|
+
|
8
|
+
extend ActiveSupport::Concern
|
9
|
+
|
10
|
+
include Hephaestus::Responses
|
11
|
+
|
12
|
+
included do
|
13
|
+
before_action :from_yetto?
|
14
|
+
end
|
15
|
+
|
16
|
+
def from_yetto?
|
17
|
+
return bad_request if request.headers.blank?
|
18
|
+
|
19
|
+
yetto_signature = request.headers.fetch(Hephaestus::Headers::HEADER_SIGNATURE, "")
|
20
|
+
|
21
|
+
return bad_request unless yetto_signature.start_with?("sha256=")
|
22
|
+
|
23
|
+
hmac_header = yetto_signature.split("sha256=").last
|
24
|
+
body = request.env.fetch("RAW_POST_DATA", "")
|
25
|
+
|
26
|
+
calculated_hmac = OpenSSL::HMAC.hexdigest(SHA256_DIGEST, Hephaestus::YETTO_SIGNING_SECRET, body)
|
27
|
+
|
28
|
+
return true if ActiveSupport::SecurityUtils.secure_compare(calculated_hmac, hmac_header)
|
29
|
+
|
30
|
+
bad_request
|
31
|
+
end
|
32
|
+
|
33
|
+
def from_yetto_inline?
|
34
|
+
return bad_request if request.headers.blank?
|
35
|
+
|
36
|
+
yetto_signature = request.headers.fetch(Hephaestus::Headers::HEADER_SIGNATURE, "")
|
37
|
+
|
38
|
+
return bad_request unless yetto_signature.start_with?("sha256=")
|
39
|
+
|
40
|
+
hmac_header = yetto_signature.split("sha256=").last
|
41
|
+
body = params["encrypted_payload"]
|
42
|
+
|
43
|
+
@payload = T.let(ActiveSupport::MessageEncryptor.new(Hephaestus::YETTO_SIGNING_SECRET, url_safe: true, serializer: :json).decrypt_and_verify(body), T.nilable(String))
|
44
|
+
calculated_hmac = OpenSSL::HMAC.hexdigest(OpenSSL::Digest.new("sha256"), Hephaestus::YETTO_SIGNING_SECRET, @payload)
|
45
|
+
|
46
|
+
return true if ActiveSupport::SecurityUtils.secure_compare(calculated_hmac, hmac_header)
|
47
|
+
|
48
|
+
bad_request
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
@@ -0,0 +1,42 @@
|
|
1
|
+
# typed: false
|
2
|
+
# frozen_string_literal: true
|
3
|
+
|
4
|
+
require "opentelemetry-semantic_conventions"
|
5
|
+
|
6
|
+
module Hephaestus
|
7
|
+
class ApplicationController < ActionController::Base
|
8
|
+
include ActionController::MimeResponds
|
9
|
+
|
10
|
+
include Hephaestus::Headers
|
11
|
+
include Hephaestus::Responses
|
12
|
+
|
13
|
+
rescue_from ActionController::UnknownFormat, with: :not_acceptable
|
14
|
+
protect_from_forgery with: :null_session
|
15
|
+
|
16
|
+
def ensure_json_request
|
17
|
+
return if request.format.json?
|
18
|
+
|
19
|
+
not_acceptable
|
20
|
+
end
|
21
|
+
|
22
|
+
# Yetto sends a unique state parameter as part of the OAuth installation process.
|
23
|
+
# This decodes that into something the plug can use.
|
24
|
+
def parse_state(state)
|
25
|
+
decoded_state = Base64.urlsafe_decode64(state)
|
26
|
+
state = JSON.parse(decoded_state)
|
27
|
+
|
28
|
+
{
|
29
|
+
version: state["version"],
|
30
|
+
salt: state["salt"],
|
31
|
+
nonce: state["nonce"] || "",
|
32
|
+
plug_installation_id: state["plug_installation_id"],
|
33
|
+
membership_id: state["membership_id"], # optional, used for conversation.viewed events
|
34
|
+
redirect_to: state["redirect_to"],
|
35
|
+
}
|
36
|
+
rescue ArgumentError # invalid base64
|
37
|
+
{}
|
38
|
+
rescue JSON::ParserError # invalid JSON
|
39
|
+
{}
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
# typed: false
|
2
|
+
# frozen_string_literal: true
|
3
|
+
|
4
|
+
module Hephaestus
|
5
|
+
class SettingsController < ApplicationController
|
6
|
+
before_action :ensure_json_request
|
7
|
+
|
8
|
+
def new
|
9
|
+
set_step
|
10
|
+
render("settings/new")
|
11
|
+
end
|
12
|
+
|
13
|
+
def edit
|
14
|
+
end
|
15
|
+
|
16
|
+
def set_step
|
17
|
+
@step = params.fetch(:step, 1).to_i || 1
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
# typed: false
|
2
|
+
# frozen_string_literal: true
|
3
|
+
|
4
|
+
module Hephaestus
|
5
|
+
class StaffController < ApplicationController
|
6
|
+
layout "staff"
|
7
|
+
|
8
|
+
class << self
|
9
|
+
def staff_request?(request)
|
10
|
+
return true if Rails.env.development?
|
11
|
+
|
12
|
+
true
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
def index
|
17
|
+
render404 unless StaffController.staff_request?(request)
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
@@ -0,0 +1,12 @@
|
|
1
|
+
# typed: false
|
2
|
+
# frozen_string_literal: true
|
3
|
+
|
4
|
+
module Hephaestus
|
5
|
+
class ApplicationJob < ActiveJob::Base
|
6
|
+
# Automatically retry jobs that encountered a deadlock
|
7
|
+
# retry_on ActiveRecord::Deadlocked
|
8
|
+
|
9
|
+
# Most jobs are safe to ignore if the underlying records are no longer available
|
10
|
+
# discard_on ActiveJob::DeserializationError
|
11
|
+
end
|
12
|
+
end
|
@@ -0,0 +1,39 @@
|
|
1
|
+
# typed: false
|
2
|
+
# frozen_string_literal: true
|
3
|
+
|
4
|
+
# Send updated data to Yetto to store in the database
|
5
|
+
# This can be used to update installation data or message data
|
6
|
+
module Hephaestus
|
7
|
+
class UpdateYettoJob < ApplicationJob
|
8
|
+
queue_as :high_priority_update_yetto
|
9
|
+
|
10
|
+
def perform(params)
|
11
|
+
type = params.delete(:type)
|
12
|
+
params.deep_symbolize_keys!
|
13
|
+
|
14
|
+
inbox_id = params.fetch(:inbox, {}).fetch(:id, nil)
|
15
|
+
plug_installation_id = params.fetch(:plug_installation, {}).fetch(:id, nil)
|
16
|
+
conversation_id = params.fetch(:conversation, {}).fetch(:id, nil)
|
17
|
+
message_id = params.fetch(:message, {}).fetch(:id, nil)
|
18
|
+
|
19
|
+
response = case type
|
20
|
+
when "update_plug_installation"
|
21
|
+
YettoService.update_plug_installation(plug_installation_id, params[:payload])
|
22
|
+
when "create_conversation"
|
23
|
+
YettoService.create_conversation(plug_installation_id, inbox_id, params[:payload])
|
24
|
+
when "add_message_to_conversation"
|
25
|
+
YettoService.add_message_to_conversation(plug_installation_id, conversation_id, params[:payload])
|
26
|
+
when "create_message_reply"
|
27
|
+
YettoService.create_message_reply(plug_installation_id, message_id, params[:payload])
|
28
|
+
when "update_message"
|
29
|
+
YettoService.update_message(plug_installation_id, message_id, params[:payload])
|
30
|
+
end
|
31
|
+
|
32
|
+
response, type = Rails.configuration.enhance_update_yetto_job.call(params, type, response) if Rails.configuration.respond_to?(:enhance_update_yetto_job)
|
33
|
+
|
34
|
+
if response.present? && response.unavailable?
|
35
|
+
logger.error("Could not #{type} for #{plug_installation_id}: #{response.parsed_json_body}")
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
# typed: false
|
2
|
+
# frozen_string_literal: true
|
3
|
+
|
4
|
+
module Hephaestus
|
5
|
+
module Headers
|
6
|
+
YETTO_DELIVERY_ID = "HTTP_X_YETTO_DELIVERY_ID"
|
7
|
+
|
8
|
+
HEADER_EVENT = "HTTP_X_YETTO_EVENT"
|
9
|
+
EVENT_AFTER_CREATE = "created"
|
10
|
+
EVENT_AFTER_UPDATE = "updated"
|
11
|
+
EVENT_AFTER_RENAME = "renamed"
|
12
|
+
EVENT_AFTER_DESTROY = "destroyed"
|
13
|
+
|
14
|
+
# for conversations
|
15
|
+
EVENT_AFTER_VIEW = "viewed"
|
16
|
+
|
17
|
+
HEADER_RECORD_TYPE = "HTTP_X_YETTO_RECORD_TYPE"
|
18
|
+
RECORD_TYPE_PLUG_INSTALLATION = "plug_installation"
|
19
|
+
RECORD_TYPE_MESSAGE = "message"
|
20
|
+
RECORD_TYPE_INBOX = "inbox"
|
21
|
+
RECORD_TYPE_ORGANIZATION = "organization"
|
22
|
+
|
23
|
+
RECORD_TYPE_CONVERSATION = "conversation"
|
24
|
+
|
25
|
+
HEADER_SIGNATURE = "HTTP_X_YETTO_SIGNATURE"
|
26
|
+
end
|
27
|
+
end
|
@@ -0,0 +1,99 @@
|
|
1
|
+
# typed: false
|
2
|
+
# frozen_string_literal: true
|
3
|
+
|
4
|
+
require "jwt"
|
5
|
+
require "openssl"
|
6
|
+
require "httpsensible"
|
7
|
+
|
8
|
+
class Object
|
9
|
+
# Relies on the fix implemented in https://github.com/rails/rails/pull/39966 to ensure
|
10
|
+
# that blank values don't result in queries with empty values, eg. `?filter[metadata]=`, when
|
11
|
+
# we prefer (and accept!) `?filter[metadata]`.
|
12
|
+
def to_query(key)
|
13
|
+
blank? ? CGI.escape(key.to_param).to_s : "#{CGI.escape(key.to_param)}=#{CGI.escape(to_param.to_s)}"
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
module Hephaestus
|
18
|
+
class YettoService
|
19
|
+
# Version is set by the consuming plug
|
20
|
+
YETTO_API_VERSION_TLD = "#{Hephaestus::PROTOCOL}#{Hephaestus::YETTO_API_URL}/#{Rails.configuration.yetto_api_version}"
|
21
|
+
|
22
|
+
class << self
|
23
|
+
def yetto_client
|
24
|
+
@yetto_client ||= Httpsensible::Client.new(user_agent: "#{Rails.application.class.module_parent.name}/#{Hephaestus::Engine::GIT_SHA}")
|
25
|
+
end
|
26
|
+
|
27
|
+
def encoded_jwt
|
28
|
+
Httpsensible::JWT.encode_jwt(Hephaestus::YETTO_PLUG_PEM, Hephaestus::YETTO_PLUG_ID)
|
29
|
+
end
|
30
|
+
|
31
|
+
def perform_token_exchange(plug_installation_id)
|
32
|
+
response = yetto_client.with_headers({ "Authorization" => "Bearer #{encoded_jwt}" }).post("#{YETTO_API_VERSION_TLD}/plug/installations/#{plug_installation_id}/access_tokens")
|
33
|
+
body = response.parsed_json_body
|
34
|
+
body["token"]
|
35
|
+
end
|
36
|
+
|
37
|
+
def get_plug_installation(plug_installation_id)
|
38
|
+
token = perform_token_exchange(plug_installation_id)
|
39
|
+
yetto_client.with_headers({ "Authorization" => "Bearer #{token}" }).get("#{YETTO_API_VERSION_TLD}/installations/#{plug_installation_id}")
|
40
|
+
end
|
41
|
+
|
42
|
+
def update_plug_installation(plug_installation_id, params)
|
43
|
+
plug_installation = {}
|
44
|
+
|
45
|
+
plug_installation[:settings] = params.fetch(:settings, {})
|
46
|
+
plug_installation[:credentials] = params.fetch(:credentials, {})
|
47
|
+
|
48
|
+
token = perform_token_exchange(plug_installation_id)
|
49
|
+
yetto_client.with_headers({ "Authorization" => "Bearer #{token}" }).patch("#{YETTO_API_VERSION_TLD}/installations/#{plug_installation_id}", json: plug_installation)
|
50
|
+
end
|
51
|
+
|
52
|
+
def get_messages_in_inbox(plug_installation_id, inbox_id, filter: {})
|
53
|
+
token = perform_token_exchange(plug_installation_id)
|
54
|
+
|
55
|
+
yetto_client.with_headers({ "Authorization" => "Bearer #{token}" }).get("#{YETTO_API_VERSION_TLD}/inboxes/#{inbox_id}/messages#{to_filter_query(filter)}")
|
56
|
+
end
|
57
|
+
|
58
|
+
def get_messages_in_conversation(plug_installation_id, conversation_id, filter: {})
|
59
|
+
token = perform_token_exchange(plug_installation_id)
|
60
|
+
|
61
|
+
yetto_client.with_headers("Authorization" => "Bearer #{token}").get("#{YETTO_API_VERSION_TLD}/conversations/#{conversation_id}/messages#{to_filter_query(filter)}")
|
62
|
+
end
|
63
|
+
|
64
|
+
def update_message(plug_installation_id, message_id, params)
|
65
|
+
token = perform_token_exchange(plug_installation_id)
|
66
|
+
|
67
|
+
yetto_client.with_headers("Authorization" => "Bearer #{token}").patch("#{YETTO_API_VERSION_TLD}/messages/#{message_id}", json: params)
|
68
|
+
end
|
69
|
+
|
70
|
+
def create_conversation(plug_installation_id, inbox_id, params)
|
71
|
+
token = perform_token_exchange(plug_installation_id)
|
72
|
+
|
73
|
+
yetto_client.with_headers({ "Authorization" => "Bearer #{token}" }).post("#{YETTO_API_VERSION_TLD}/inboxes/#{inbox_id}/conversations", json: params)
|
74
|
+
end
|
75
|
+
|
76
|
+
def create_message_reply(plug_installation_id, message_id, params)
|
77
|
+
token = perform_token_exchange(plug_installation_id)
|
78
|
+
|
79
|
+
yetto_client.with_headers("Authorization" => "Bearer #{token}").post("#{YETTO_API_VERSION_TLD}/messages/#{message_id}/replies", json: params)
|
80
|
+
end
|
81
|
+
|
82
|
+
def add_message_to_conversation(plug_installation_id, conversation_id, params)
|
83
|
+
token = perform_token_exchange(plug_installation_id)
|
84
|
+
|
85
|
+
yetto_client.with_headers({ "Authorization" => "Bearer #{token}" }).post("#{YETTO_API_VERSION_TLD}/conversations/#{conversation_id}/messages", json: params)
|
86
|
+
end
|
87
|
+
|
88
|
+
def get_plug_installations(filter: {})
|
89
|
+
yetto_client.with_headers({ "Authorization" => "Bearer #{encoded_jwt}" }).get("#{YETTO_API_VERSION_TLD}/plug/installations#{to_filter_query(filter)}")
|
90
|
+
end
|
91
|
+
|
92
|
+
private def to_filter_query(hash)
|
93
|
+
return "" if hash.nil?
|
94
|
+
|
95
|
+
"?#{hash.to_query("filter")}"
|
96
|
+
end
|
97
|
+
end
|
98
|
+
end
|
99
|
+
end
|
@@ -0,0 +1 @@
|
|
1
|
+
Hello, staff!
|
data/config/database.yml
ADDED
@@ -0,0 +1,49 @@
|
|
1
|
+
# SQLite. Versions 3.8.0 and up are supported.
|
2
|
+
# gem install sqlite3
|
3
|
+
#
|
4
|
+
# Ensure the SQLite 3 gem is defined in your Gemfile
|
5
|
+
# gem "sqlite3"
|
6
|
+
#
|
7
|
+
default: &default
|
8
|
+
adapter: sqlite3
|
9
|
+
pool: <%= ENV.fetch("RAILS_MAX_THREADS") { 5 } %>
|
10
|
+
timeout: 5000
|
11
|
+
|
12
|
+
development:
|
13
|
+
primary:
|
14
|
+
<<: *default
|
15
|
+
database: storage/development.sqlite3
|
16
|
+
queue:
|
17
|
+
<<: *default
|
18
|
+
database: storage/development_queue.sqlite3
|
19
|
+
migrations_paths: db/queue_migrate
|
20
|
+
|
21
|
+
|
22
|
+
# Warning: The database defined as "test" will be erased and
|
23
|
+
# re-generated from your development database when you run "rake".
|
24
|
+
# Do not set this db to the same as development or production.
|
25
|
+
test:
|
26
|
+
primary:
|
27
|
+
<<: *default
|
28
|
+
database: storage/test.sqlite3
|
29
|
+
queue:
|
30
|
+
<<: *default
|
31
|
+
database: storage/test_queue.sqlite3
|
32
|
+
migrations_paths: db/queue_migrate
|
33
|
+
|
34
|
+
|
35
|
+
|
36
|
+
# SQLite3 write its data on the local filesystem, as such it requires
|
37
|
+
# persistent disks. If you are deploying to a managed service, you should
|
38
|
+
# make sure it provides disk persistence, as many don't.
|
39
|
+
#
|
40
|
+
# Similarly, if you deploy your application as a Docker container, you must
|
41
|
+
# ensure the database is located in a persisted volume.
|
42
|
+
production:
|
43
|
+
primary:
|
44
|
+
<<: *default
|
45
|
+
database: /mnt/data/production.sqlite3
|
46
|
+
queue:
|
47
|
+
<<: *default
|
48
|
+
database: /mnt/data/production_queue.sqlite3
|
49
|
+
migrations_paths: db/queue_migrate
|
@@ -0,0 +1,89 @@
|
|
1
|
+
# typed: false
|
2
|
+
# frozen_string_literal: true
|
3
|
+
|
4
|
+
require "active_support/core_ext/integer/time"
|
5
|
+
|
6
|
+
Rails.application.configure do
|
7
|
+
# Settings specified here will take precedence over those in config/application.rb.
|
8
|
+
|
9
|
+
# In the development environment your application's code is reloaded any time
|
10
|
+
# it changes. This slows down response time but is perfect for development
|
11
|
+
# since you don't have to restart the web server when you make code changes.
|
12
|
+
config.enable_reloading = true
|
13
|
+
|
14
|
+
# Do not eager load code on boot.
|
15
|
+
config.eager_load = false
|
16
|
+
|
17
|
+
# Show full error reports.
|
18
|
+
config.consider_all_requests_local = true
|
19
|
+
|
20
|
+
# Enable server timing.
|
21
|
+
config.server_timing = true
|
22
|
+
|
23
|
+
# Enable/disable caching. By default caching is disabled.
|
24
|
+
# Run rails dev:cache to toggle caching.
|
25
|
+
if Rails.root.join("tmp/caching-dev.txt").exist?
|
26
|
+
config.action_controller.perform_caching = true
|
27
|
+
config.action_controller.enable_fragment_cache_logging = true
|
28
|
+
|
29
|
+
config.cache_store = :memory_store
|
30
|
+
config.public_file_server.headers = { "Cache-Control" => "public, max-age=#{2.days.to_i}" }
|
31
|
+
else
|
32
|
+
config.action_controller.perform_caching = false
|
33
|
+
|
34
|
+
config.cache_store = :null_store
|
35
|
+
end
|
36
|
+
|
37
|
+
if defined?(ActionMailer)
|
38
|
+
# Don't care if the mailer can't send.
|
39
|
+
config.action_mailer.raise_delivery_errors = false
|
40
|
+
|
41
|
+
# Disable caching for Action Mailer templates even if Action Controller
|
42
|
+
# caching is enabled.
|
43
|
+
config.action_mailer.perform_caching = false
|
44
|
+
|
45
|
+
config.action_mailer.default_url_options = { host: "localhost", port: 3000 }
|
46
|
+
end
|
47
|
+
|
48
|
+
# Print deprecation notices to the Rails logger.
|
49
|
+
config.active_support.deprecation = :log
|
50
|
+
|
51
|
+
# Raise exceptions for disallowed deprecations.
|
52
|
+
config.active_support.disallowed_deprecation = :raise
|
53
|
+
|
54
|
+
# Tell Active Support which deprecation messages to disallow.
|
55
|
+
config.active_support.disallowed_deprecation_warnings = []
|
56
|
+
|
57
|
+
# Highlight code that enqueued background job in logs.
|
58
|
+
config.active_job.verbose_enqueue_logs = true
|
59
|
+
|
60
|
+
# Raises error for missing translations.
|
61
|
+
# config.i18n.raise_on_missing_translations = true
|
62
|
+
|
63
|
+
# Annotate rendered view with file names.
|
64
|
+
config.action_view.annotate_rendered_view_with_filenames = true
|
65
|
+
|
66
|
+
# Raise error when a before_action's only/except options reference missing actions.
|
67
|
+
config.action_controller.raise_on_missing_callback_actions = true
|
68
|
+
|
69
|
+
config.active_job.queue_adapter = :solid_queue
|
70
|
+
config.solid_queue.silence_polling = true
|
71
|
+
config.solid_queue.connects_to = { database: { writing: :queue } }
|
72
|
+
|
73
|
+
# Apply autocorrection by RuboCop to files generated by `bin/rails generate`.
|
74
|
+
# config.generators.apply_rubocop_autocorrect_after_generate!
|
75
|
+
|
76
|
+
# establish a DEBUG environment
|
77
|
+
if ENV.fetch("DEBUG", false) && defined?(Rails::Server)
|
78
|
+
require "debug/open_nonstop"
|
79
|
+
end
|
80
|
+
|
81
|
+
# Load dotenv only in development environment
|
82
|
+
Dotenv::Rails.overwrite = true
|
83
|
+
|
84
|
+
# Let dev server run on GitHub Codespaces
|
85
|
+
config.hosts << /[a-z0-9\-]+\.githubpreview\.dev/
|
86
|
+
|
87
|
+
# Let dev server run on ngrok domains
|
88
|
+
config.hosts << /[a-z0-9\-]+\.ngrok\.io/
|
89
|
+
end
|