bas 0.4.0 → 1.0.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 +4 -4
- data/CHANGELOG.md +12 -0
- data/README.md +68 -147
- data/lib/bas/bot/base.rb +74 -0
- data/lib/bas/bot/compare_wip_limit_count.rb +92 -0
- data/lib/bas/bot/fetch_birthdays_from_notion.rb +128 -0
- data/lib/bas/bot/fetch_domains_wip_counts_from_notion.rb +121 -0
- data/lib/bas/bot/fetch_domains_wip_limit_from_notion.rb +134 -0
- data/lib/bas/bot/fetch_emails_from_imap.rb +99 -0
- data/lib/bas/bot/fetch_next_week_birthdays_from_notion.rb +142 -0
- data/lib/bas/bot/fetch_next_week_ptos_from_notion.rb +162 -0
- data/lib/bas/bot/fetch_ptos_from_notion.rb +138 -0
- data/lib/bas/bot/format_birthdays.rb +97 -0
- data/lib/bas/bot/format_emails.rb +124 -0
- data/lib/bas/bot/format_wip_limit_exceeded.rb +97 -0
- data/lib/bas/bot/garbage_collector.rb +85 -0
- data/lib/bas/bot/humanize_pto.rb +119 -0
- data/lib/bas/bot/notify_discord.rb +96 -0
- data/lib/bas/read/base.rb +10 -23
- data/lib/bas/read/default.rb +16 -0
- data/lib/bas/read/postgres.rb +44 -0
- data/lib/bas/read/types/response.rb +18 -0
- data/lib/bas/utils/discord/integration.rb +43 -0
- data/lib/bas/utils/exceptions/function_not_implemented.rb +16 -0
- data/lib/bas/utils/exceptions/invalid_process_response.rb +16 -0
- data/lib/bas/utils/imap/request.rb +76 -0
- data/lib/bas/utils/notion/request.rb +45 -0
- data/lib/bas/utils/openai/run_assistant.rb +99 -0
- data/lib/bas/utils/postgres/request.rb +50 -0
- data/lib/bas/version.rb +1 -1
- data/lib/bas/write/base.rb +12 -17
- data/lib/bas/write/postgres.rb +45 -0
- data/lib/bas/write/postgres_update.rb +49 -0
- data/lib/bas.rb +1 -3
- metadata +30 -67
- data/lib/bas/domain/birthday.rb +0 -25
- data/lib/bas/domain/email.rb +0 -34
- data/lib/bas/domain/exceptions/function_not_implemented.rb +0 -18
- data/lib/bas/domain/issue.rb +0 -22
- data/lib/bas/domain/notification.rb +0 -23
- data/lib/bas/domain/pto.rb +0 -69
- data/lib/bas/domain/work_items_limit.rb +0 -25
- data/lib/bas/formatter/base.rb +0 -53
- data/lib/bas/formatter/birthday.rb +0 -38
- data/lib/bas/formatter/exceptions/invalid_data.rb +0 -15
- data/lib/bas/formatter/notification.rb +0 -34
- data/lib/bas/formatter/pto.rb +0 -89
- data/lib/bas/formatter/support_emails.rb +0 -73
- data/lib/bas/formatter/types/response.rb +0 -16
- data/lib/bas/formatter/work_items_limit.rb +0 -68
- data/lib/bas/process/base.rb +0 -39
- data/lib/bas/process/discord/exceptions/invalid_webhook_token.rb +0 -16
- data/lib/bas/process/discord/implementation.rb +0 -71
- data/lib/bas/process/discord/types/response.rb +0 -22
- data/lib/bas/process/openai/base.rb +0 -72
- data/lib/bas/process/openai/helper.rb +0 -19
- data/lib/bas/process/openai/types/response.rb +0 -27
- data/lib/bas/process/openai/use_case/humanize_pto.rb +0 -53
- data/lib/bas/process/slack/exceptions/invalid_webhook_token.rb +0 -16
- data/lib/bas/process/slack/implementation.rb +0 -70
- data/lib/bas/process/slack/types/response.rb +0 -21
- data/lib/bas/process/types/response.rb +0 -16
- data/lib/bas/read/github/base.rb +0 -57
- data/lib/bas/read/github/types/response.rb +0 -27
- data/lib/bas/read/github/use_case/repo_issues.rb +0 -17
- data/lib/bas/read/imap/base.rb +0 -70
- data/lib/bas/read/imap/types/response.rb +0 -27
- data/lib/bas/read/imap/use_case/support_emails.rb +0 -26
- data/lib/bas/read/notion/base.rb +0 -52
- data/lib/bas/read/notion/exceptions/invalid_api_key.rb +0 -15
- data/lib/bas/read/notion/exceptions/invalid_database_id.rb +0 -15
- data/lib/bas/read/notion/helper.rb +0 -21
- data/lib/bas/read/notion/types/response.rb +0 -26
- data/lib/bas/read/notion/use_case/birthday_next_week.rb +0 -41
- data/lib/bas/read/notion/use_case/birthday_today.rb +0 -29
- data/lib/bas/read/notion/use_case/notification.rb +0 -28
- data/lib/bas/read/notion/use_case/pto_next_week.rb +0 -71
- data/lib/bas/read/notion/use_case/pto_today.rb +0 -30
- data/lib/bas/read/notion/use_case/work_items_limit.rb +0 -37
- data/lib/bas/read/postgres/base.rb +0 -46
- data/lib/bas/read/postgres/helper.rb +0 -16
- data/lib/bas/read/postgres/types/response.rb +0 -42
- data/lib/bas/read/postgres/use_case/pto_today.rb +0 -32
- data/lib/bas/serialize/base.rb +0 -30
- data/lib/bas/serialize/github/issues.rb +0 -57
- data/lib/bas/serialize/imap/support_emails.rb +0 -56
- data/lib/bas/serialize/notion/birthday_today.rb +0 -68
- data/lib/bas/serialize/notion/notification.rb +0 -56
- data/lib/bas/serialize/notion/pto_today.rb +0 -75
- data/lib/bas/serialize/notion/work_items_limit.rb +0 -65
- data/lib/bas/serialize/postgres/pto_today.rb +0 -47
- data/lib/bas/use_cases/types/config.rb +0 -20
- data/lib/bas/use_cases/use_case.rb +0 -42
- data/lib/bas/use_cases/use_cases.rb +0 -465
- data/lib/bas/write/logs/base.rb +0 -33
- data/lib/bas/write/logs/use_case/console_log.rb +0 -22
- data/lib/bas/write/notion/base.rb +0 -36
- data/lib/bas/write/notion/use_case/empty_notification.rb +0 -38
- data/lib/bas/write/notion/use_case/notification.rb +0 -38
@@ -1,73 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
require_relative "../domain/email"
|
4
|
-
require_relative "./exceptions/invalid_data"
|
5
|
-
require_relative "./base"
|
6
|
-
require_relative "./types/response"
|
7
|
-
|
8
|
-
module Formatter
|
9
|
-
##
|
10
|
-
# This class implements methods from the Formatter::Base module, tailored to format the
|
11
|
-
# Domain::Email structure for a Process.
|
12
|
-
class SupportEmails < Base
|
13
|
-
DEFAULT_TIME_ZONE = "+00:00"
|
14
|
-
|
15
|
-
# Initializes the formatter with essential configuration parameters.
|
16
|
-
#
|
17
|
-
# <b>timezone</b> : expect an string with the time difference relative to the UTC. Example: "-05:00"
|
18
|
-
def initialize(config = {})
|
19
|
-
super(config)
|
20
|
-
|
21
|
-
@timezone = config[:timezone] || DEFAULT_TIME_ZONE
|
22
|
-
@frecuency = config[:frecuency]
|
23
|
-
end
|
24
|
-
|
25
|
-
# Implements the logic for building a formatted payload with the given template for support emails.
|
26
|
-
#
|
27
|
-
# <br>
|
28
|
-
# <b>Params:</b>
|
29
|
-
# * <tt>List<Domain::Email></tt> support_emails_list: list of support emails.
|
30
|
-
#
|
31
|
-
# <br>
|
32
|
-
# <b>raises</b> <tt>Formatter::Exceptions::InvalidData</tt> when invalid data is provided.
|
33
|
-
#
|
34
|
-
# <br>
|
35
|
-
# <b>returns</b> <tt>Formatter::Types::Response</tt> formatter response: standard output for
|
36
|
-
# the formatted payload suitable for a Process.
|
37
|
-
#
|
38
|
-
def format(support_emails_list)
|
39
|
-
raise Formatter::Exceptions::InvalidData unless support_emails_list.all? do |support_email|
|
40
|
-
support_email.is_a?(Domain::Email)
|
41
|
-
end
|
42
|
-
|
43
|
-
response = process_emails(support_emails_list).reduce("") do |payload, support_email|
|
44
|
-
payload + build_template(Domain::Email::ATTRIBUTES, support_email)
|
45
|
-
end
|
46
|
-
|
47
|
-
Formatter::Types::Response.new(response)
|
48
|
-
end
|
49
|
-
|
50
|
-
private
|
51
|
-
|
52
|
-
def process_emails(emails)
|
53
|
-
emails.each { |email| email.date = at_timezone(email.date) }
|
54
|
-
emails.filter! { |email| email.date > time_window } unless @frecuency.nil?
|
55
|
-
|
56
|
-
format_timestamp(emails)
|
57
|
-
end
|
58
|
-
|
59
|
-
def format_timestamp(emails)
|
60
|
-
emails.each { |email| email.date = email.date.strftime("%F %r") }
|
61
|
-
end
|
62
|
-
|
63
|
-
def time_window
|
64
|
-
date_time = Time.now - (60 * 60 * @frecuency)
|
65
|
-
|
66
|
-
at_timezone(date_time)
|
67
|
-
end
|
68
|
-
|
69
|
-
def at_timezone(date)
|
70
|
-
Time.at(date, in: @timezone)
|
71
|
-
end
|
72
|
-
end
|
73
|
-
end
|
@@ -1,16 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
module Formatter
|
4
|
-
module Types
|
5
|
-
##
|
6
|
-
# Represents a response received from a Formatter. It encapsulates the formatted data to be used by
|
7
|
-
# a Process or a Write component.
|
8
|
-
class Response
|
9
|
-
attr_reader :data
|
10
|
-
|
11
|
-
def initialize(response)
|
12
|
-
@data = response
|
13
|
-
end
|
14
|
-
end
|
15
|
-
end
|
16
|
-
end
|
@@ -1,68 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
require_relative "../domain/work_items_limit"
|
4
|
-
require_relative "./exceptions/invalid_data"
|
5
|
-
require_relative "./base"
|
6
|
-
require_relative "./types/response"
|
7
|
-
|
8
|
-
module Formatter
|
9
|
-
##
|
10
|
-
# This class implements methods from the Formatter::Base module, tailored to format the
|
11
|
-
# Domain::WorkItemsLimit structure for a Process.
|
12
|
-
class WorkItemsLimit < Base
|
13
|
-
DEFAULT_DOMAIN_LIMIT = 6
|
14
|
-
|
15
|
-
# Initializes the formatter with essential configuration parameters.
|
16
|
-
#
|
17
|
-
# <b>limits</b> : expect a map with the wip limits by domain. Example: { "ops": 5 }
|
18
|
-
def initialize(config = {})
|
19
|
-
super(config)
|
20
|
-
|
21
|
-
@limits = config[:limits]
|
22
|
-
end
|
23
|
-
|
24
|
-
# Implements the logic for building a formatted payload with the given template for wip limits.
|
25
|
-
#
|
26
|
-
# <br>
|
27
|
-
# <b>Params:</b>
|
28
|
-
# * <tt>List<Domain::WorkItemsLimit></tt> work_items_list: List of serialized work items limits.
|
29
|
-
#
|
30
|
-
# <br>
|
31
|
-
# <b>raises</b> <tt>Formatter::Exceptions::InvalidData</tt> when invalid data is provided.
|
32
|
-
#
|
33
|
-
# <br>
|
34
|
-
# <b>returns</b> <tt>Formatter::Types::Response</tt> formatter response: standard output for
|
35
|
-
# the formatted payload suitable for a Process.
|
36
|
-
#
|
37
|
-
|
38
|
-
def format(work_items_list)
|
39
|
-
raise Formatter::Exceptions::InvalidData unless work_items_list.all? do |work_item|
|
40
|
-
work_item.is_a?(Domain::WorkItemsLimit)
|
41
|
-
end
|
42
|
-
|
43
|
-
response = exceeded_domains(work_items_list).reduce("") do |payload, work_items_limit|
|
44
|
-
built_template = build_template(Domain::WorkItemsLimit::ATTRIBUTES, work_items_limit)
|
45
|
-
payload + format_message_by_case(built_template.gsub("\n", ""), work_items_limit)
|
46
|
-
end
|
47
|
-
|
48
|
-
Formatter::Types::Response.new(response)
|
49
|
-
end
|
50
|
-
|
51
|
-
private
|
52
|
-
|
53
|
-
def format_message_by_case(template, work_items_limit)
|
54
|
-
total_items = work_items_limit.total
|
55
|
-
limit = domain_limit(work_items_limit.domain)
|
56
|
-
|
57
|
-
template + ", #{total_items} of #{limit}\n"
|
58
|
-
end
|
59
|
-
|
60
|
-
def exceeded_domains(work_items_list)
|
61
|
-
work_items_list.filter { |work_item| work_item.total > domain_limit(work_item.domain) }
|
62
|
-
end
|
63
|
-
|
64
|
-
def domain_limit(domain)
|
65
|
-
@limits[domain.to_sym] || DEFAULT_DOMAIN_LIMIT
|
66
|
-
end
|
67
|
-
end
|
68
|
-
end
|
data/lib/bas/process/base.rb
DELETED
@@ -1,39 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
require_relative "../domain/exceptions/function_not_implemented"
|
4
|
-
require_relative "./types/response"
|
5
|
-
|
6
|
-
module Process
|
7
|
-
##
|
8
|
-
# Serves as a foundational structure for implementing specific process. Acting as an interface,
|
9
|
-
# this class defines essential attributes and methods, providing a blueprint for creating custom
|
10
|
-
# process tailored to different platforms or services.
|
11
|
-
#
|
12
|
-
class Base
|
13
|
-
attr_reader :config
|
14
|
-
|
15
|
-
# Initializes the process with essential configuration parameters.
|
16
|
-
#
|
17
|
-
def initialize(config = {})
|
18
|
-
@config = config
|
19
|
-
end
|
20
|
-
|
21
|
-
# A method meant to send messages to an specific destination depending on the implementation.
|
22
|
-
# Must be overridden by subclasses, with specific logic based on the use case.
|
23
|
-
#
|
24
|
-
# <br>
|
25
|
-
# <b>returns</b> a <tt>Process::Types::Response</tt>: standard output for a process
|
26
|
-
#
|
27
|
-
def execute(format_response)
|
28
|
-
Process::Types::Response.new(format_response.data)
|
29
|
-
end
|
30
|
-
|
31
|
-
protected
|
32
|
-
|
33
|
-
def valid_format_response(format_response)
|
34
|
-
return format_response if format_response.is_a?(Formatter::Types::Response)
|
35
|
-
|
36
|
-
raise Formatter::Exceptions::InvalidData
|
37
|
-
end
|
38
|
-
end
|
39
|
-
end
|
@@ -1,16 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
module Process
|
4
|
-
module Discord
|
5
|
-
module Exceptions
|
6
|
-
##
|
7
|
-
# Domain specific representation when an invalid Discord webhook token is provided to Discord.
|
8
|
-
#
|
9
|
-
class InvalidWebookToken < StandardError
|
10
|
-
def initialize(message = "The provided Webhook token is invalid.")
|
11
|
-
super(message)
|
12
|
-
end
|
13
|
-
end
|
14
|
-
end
|
15
|
-
end
|
16
|
-
end
|
@@ -1,71 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
require_relative "../base"
|
4
|
-
require_relative "./exceptions/invalid_webhook_token"
|
5
|
-
require_relative "./types/response"
|
6
|
-
|
7
|
-
module Process
|
8
|
-
module Discord
|
9
|
-
##
|
10
|
-
# This class is an implementation of the Process::Base interface, specifically designed
|
11
|
-
# for sending messages to Discord.
|
12
|
-
#
|
13
|
-
class Implementation < Base
|
14
|
-
attr_reader :webhook, :name
|
15
|
-
|
16
|
-
# Initializes the process with essential configuration parameters.
|
17
|
-
#
|
18
|
-
def initialize(config = {})
|
19
|
-
super(config)
|
20
|
-
|
21
|
-
@webhook = config[:webhook]
|
22
|
-
@name = config[:name]
|
23
|
-
end
|
24
|
-
|
25
|
-
# Implements the sending process logic for the Discord use case. It sends a POST request to
|
26
|
-
# the Discord webhook with the specified payload.
|
27
|
-
#
|
28
|
-
# <br>
|
29
|
-
# <b>Params:</b>
|
30
|
-
# * <tt>Formatter::Types::Response</tt> formatter response: standard formatter response
|
31
|
-
# with the Payload to be send to discord.
|
32
|
-
# <br>
|
33
|
-
# <b>raises</b> <tt>Exceptions::Discord::InvalidWebookToken</tt> if the provided webhook
|
34
|
-
# token is invalid.
|
35
|
-
#
|
36
|
-
# <br>
|
37
|
-
# <b>returns</b> <tt>Process::Types::Response</tt>
|
38
|
-
#
|
39
|
-
def execute(format_response)
|
40
|
-
response = valid_format_response(format_response)
|
41
|
-
|
42
|
-
body = post_body(response.data)
|
43
|
-
|
44
|
-
response = HTTParty.post(webhook, { body:, headers: { "Content-Type" => "application/json" } })
|
45
|
-
|
46
|
-
discord_response = Process::Discord::Types::Response.new(response)
|
47
|
-
|
48
|
-
validate_response(discord_response)
|
49
|
-
end
|
50
|
-
|
51
|
-
private
|
52
|
-
|
53
|
-
def post_body(payload)
|
54
|
-
{
|
55
|
-
username: name,
|
56
|
-
avatar_url: "",
|
57
|
-
content: payload
|
58
|
-
}.to_json
|
59
|
-
end
|
60
|
-
|
61
|
-
def validate_response(response)
|
62
|
-
case response.code
|
63
|
-
when 50_027
|
64
|
-
raise Discord::Exceptions::InvalidWebookToken, response.message
|
65
|
-
else
|
66
|
-
Process::Types::Response.new(response)
|
67
|
-
end
|
68
|
-
end
|
69
|
-
end
|
70
|
-
end
|
71
|
-
end
|
@@ -1,22 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
module Process
|
4
|
-
module Discord
|
5
|
-
module Types
|
6
|
-
##
|
7
|
-
# Represents a response received from Discord. It encapsulates essential information about the response,
|
8
|
-
# providing a structured way to handle and analyze Discord server responses.
|
9
|
-
#
|
10
|
-
class Response
|
11
|
-
attr_reader :code, :http_code, :message, :response
|
12
|
-
|
13
|
-
def initialize(response)
|
14
|
-
@http_code = response.code
|
15
|
-
@code = response["code"]
|
16
|
-
@message = response.message
|
17
|
-
@response = response.response
|
18
|
-
end
|
19
|
-
end
|
20
|
-
end
|
21
|
-
end
|
22
|
-
end
|
@@ -1,72 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
require "httparty"
|
4
|
-
|
5
|
-
require_relative "../base"
|
6
|
-
require_relative "./types/response"
|
7
|
-
require_relative "./helper"
|
8
|
-
|
9
|
-
module Process
|
10
|
-
module OpenAI
|
11
|
-
##
|
12
|
-
# This class is an implementation of the Process::Base interface, specifically designed
|
13
|
-
# for requesting to the OpenAI API for chat completion.
|
14
|
-
#
|
15
|
-
class Base < Process::Base
|
16
|
-
OPENAI_BASE_URL = "https://api.openai.com"
|
17
|
-
DEFAULT_N_CHOICES = 1
|
18
|
-
|
19
|
-
# Initializes the process with essential configuration parameters.
|
20
|
-
#
|
21
|
-
def initialize(config = {})
|
22
|
-
super(config)
|
23
|
-
|
24
|
-
@n_choices = config[:n_choices] || DEFAULT_N_CHOICES
|
25
|
-
end
|
26
|
-
|
27
|
-
protected
|
28
|
-
|
29
|
-
# Implements the sending process logic for the OpenAI API. It sends a
|
30
|
-
# POST request to the OpenAI API for chat completion with the specified payload.
|
31
|
-
#
|
32
|
-
# <br>
|
33
|
-
# <b>Params:</b>
|
34
|
-
# * <tt>Formatter::Types::Response</tt> formatter response: standard formatter response
|
35
|
-
# with the data to be send to OpenAI.
|
36
|
-
# <br>
|
37
|
-
# <b>raises</b> <tt>StandardError</tt> if the API returns an error response
|
38
|
-
#
|
39
|
-
# <br>
|
40
|
-
# <b>returns</b> <tt>Process::Types::Response</tt>
|
41
|
-
#
|
42
|
-
def process(messages)
|
43
|
-
url = "#{OPENAI_BASE_URL}/v1/chat/completions"
|
44
|
-
|
45
|
-
httparty_response = HTTParty.post(url, { body: body(messages).to_json, headers: })
|
46
|
-
|
47
|
-
openai_response = Process::OpenAI::Types::Response.new(httparty_response)
|
48
|
-
|
49
|
-
response = Process::OpenAI::Helper.validate_response(openai_response)
|
50
|
-
|
51
|
-
Process::Types::Response.new(response)
|
52
|
-
end
|
53
|
-
|
54
|
-
private
|
55
|
-
|
56
|
-
def body(messages)
|
57
|
-
{
|
58
|
-
"model": config[:model],
|
59
|
-
"n": @n_choices,
|
60
|
-
"messages": messages
|
61
|
-
}
|
62
|
-
end
|
63
|
-
|
64
|
-
def headers
|
65
|
-
{
|
66
|
-
"Authorization" => "Bearer #{config[:secret]}",
|
67
|
-
"Content-Type" => "application/json"
|
68
|
-
}
|
69
|
-
end
|
70
|
-
end
|
71
|
-
end
|
72
|
-
end
|
@@ -1,19 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
module Process
|
4
|
-
module OpenAI
|
5
|
-
##
|
6
|
-
# Provides common fuctionalities along the Process::OpenAI domain.
|
7
|
-
#
|
8
|
-
module Helper
|
9
|
-
def self.validate_response(response)
|
10
|
-
case response.status_code
|
11
|
-
when 200
|
12
|
-
response
|
13
|
-
else
|
14
|
-
raise StandardError, response.message
|
15
|
-
end
|
16
|
-
end
|
17
|
-
end
|
18
|
-
end
|
19
|
-
end
|
@@ -1,27 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
module Process
|
4
|
-
module OpenAI
|
5
|
-
module Types
|
6
|
-
##
|
7
|
-
# Represents a response received from the OpenAI chat completion service API. It encapsulates
|
8
|
-
# essential information about the response, providing a structured way to handle and analyze
|
9
|
-
# its responses.
|
10
|
-
class Response
|
11
|
-
attr_reader :status_code, :message, :choices
|
12
|
-
|
13
|
-
def initialize(response)
|
14
|
-
if response["error"]
|
15
|
-
@status_code = response.code
|
16
|
-
@message = response["error"]
|
17
|
-
@choices = []
|
18
|
-
else
|
19
|
-
@status_code = 200
|
20
|
-
@message = "success"
|
21
|
-
@choices = response["choices"]
|
22
|
-
end
|
23
|
-
end
|
24
|
-
end
|
25
|
-
end
|
26
|
-
end
|
27
|
-
end
|
@@ -1,53 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
require_relative "../base"
|
4
|
-
|
5
|
-
module Process
|
6
|
-
module OpenAI
|
7
|
-
##
|
8
|
-
# This class is an implementation of the Process::OpenAI::Base interface, specifically designed
|
9
|
-
# to humanize formatted PTO messages for better understanding.
|
10
|
-
#
|
11
|
-
class HumanizePto < OpenAI::Base
|
12
|
-
# Implements the data process to humanize formatted PTO messages.
|
13
|
-
#
|
14
|
-
def execute(format_response)
|
15
|
-
messages = [
|
16
|
-
{
|
17
|
-
"role": "user",
|
18
|
-
"content": content(format_response.data)
|
19
|
-
}
|
20
|
-
]
|
21
|
-
|
22
|
-
process(messages)
|
23
|
-
end
|
24
|
-
|
25
|
-
private
|
26
|
-
|
27
|
-
def content(data)
|
28
|
-
<<~MESSAGE
|
29
|
-
The following message is too complex for a human to read since it has specific dates formatted as YYYY-MM-DD:
|
30
|
-
|
31
|
-
\"#{data}\"
|
32
|
-
|
33
|
-
Create a text that gives the same message in a more human-readable and context-valuable fashion for a human.
|
34
|
-
Use the current date (#{current_date}) to provide context.
|
35
|
-
Try grouping information and using bullet points to make it easier to read the information at a quick glance.
|
36
|
-
Additionally, keep in mind that we work from Monday to Friday - not weekends.
|
37
|
-
Please, just give the PTOs message and avoid the intro message such as \"Here is a reader-friendly message\".
|
38
|
-
Add emojis for a cool message, but keep it seriously.
|
39
|
-
|
40
|
-
For example:
|
41
|
-
The input "Jane Doe is on PTO from 2024-04-08 to 2024-04-26", means that Jane will be on PTO starting at 2024-04-08
|
42
|
-
and ending at 2024-04-26, i.e, she will be back the next work-day which is 2024-04-29.
|
43
|
-
MESSAGE
|
44
|
-
end
|
45
|
-
|
46
|
-
def current_date
|
47
|
-
utc_today = Time.now.utc
|
48
|
-
|
49
|
-
Time.at(utc_today, in: config[:timezone]).strftime("%A, %F").to_s
|
50
|
-
end
|
51
|
-
end
|
52
|
-
end
|
53
|
-
end
|
@@ -1,16 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
module Process
|
4
|
-
module Slack
|
5
|
-
module Exceptions
|
6
|
-
##
|
7
|
-
# Domain specific representation when an invalid webhook token is provided to Slack.
|
8
|
-
#
|
9
|
-
class InvalidWebookToken < StandardError
|
10
|
-
def initialize(message = "The provided Webhook token is invalid.")
|
11
|
-
super(message)
|
12
|
-
end
|
13
|
-
end
|
14
|
-
end
|
15
|
-
end
|
16
|
-
end
|
@@ -1,70 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
require_relative "../base"
|
4
|
-
require_relative "./exceptions/invalid_webhook_token"
|
5
|
-
require_relative "./types/response"
|
6
|
-
|
7
|
-
module Process
|
8
|
-
module Slack
|
9
|
-
##
|
10
|
-
# This class is an implementation of the Process::Base interface, specifically designed
|
11
|
-
# for sending messages to Slack.
|
12
|
-
#
|
13
|
-
class Implementation < Base
|
14
|
-
attr_reader :webhook, :name
|
15
|
-
|
16
|
-
# Initializes the process with essential configuration parameters.
|
17
|
-
#
|
18
|
-
def initialize(config = {})
|
19
|
-
super(config)
|
20
|
-
|
21
|
-
@webhook = config[:webhook]
|
22
|
-
@name = config[:name]
|
23
|
-
end
|
24
|
-
|
25
|
-
# Implements the sending process logic for the Slack use case. It sends a POST request to
|
26
|
-
# the Slack webhook with the specified payload.
|
27
|
-
#
|
28
|
-
# <br>
|
29
|
-
# <b>Params:</b>
|
30
|
-
# * <tt>Formatter::Types::Response</tt> formatter response: standard formatter response
|
31
|
-
# with the Payload to be send to slack.
|
32
|
-
# <br>
|
33
|
-
# <b>raises</b> <tt>Exceptions::Slack::InvalidWebookToken</tt> if the provided webhook
|
34
|
-
# token is invalid.
|
35
|
-
#
|
36
|
-
# <br>
|
37
|
-
# <b>returns</b> <tt>Process::Types::Response</tt>
|
38
|
-
#
|
39
|
-
def execute(format_response)
|
40
|
-
response = valid_format_response(format_response)
|
41
|
-
|
42
|
-
body = post_body(response.data)
|
43
|
-
|
44
|
-
response = HTTParty.post(webhook, { body:, headers: { "Content-Type" => "application/json" } })
|
45
|
-
|
46
|
-
slack_response = Process::Discord::Types::Response.new(response)
|
47
|
-
|
48
|
-
validate_response(slack_response)
|
49
|
-
end
|
50
|
-
|
51
|
-
private
|
52
|
-
|
53
|
-
def post_body(payload)
|
54
|
-
{
|
55
|
-
username: name,
|
56
|
-
text: payload
|
57
|
-
}.to_json
|
58
|
-
end
|
59
|
-
|
60
|
-
def validate_response(response)
|
61
|
-
case response.http_code
|
62
|
-
when 403
|
63
|
-
raise Process::Slack::Exceptions::InvalidWebookToken, response.message
|
64
|
-
else
|
65
|
-
Process::Types::Response.new(response)
|
66
|
-
end
|
67
|
-
end
|
68
|
-
end
|
69
|
-
end
|
70
|
-
end
|
@@ -1,21 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
module Process
|
4
|
-
module Slack
|
5
|
-
module Types
|
6
|
-
##
|
7
|
-
# Represents a response received from Slack. It encapsulates essential information about the response,
|
8
|
-
# providing a structured way to handle and analyze Slack server responses.
|
9
|
-
#
|
10
|
-
class Response
|
11
|
-
attr_reader :body, :http_code, :message
|
12
|
-
|
13
|
-
def initialize(response)
|
14
|
-
@http_code = response.code
|
15
|
-
@message = response.message
|
16
|
-
@body = response.body
|
17
|
-
end
|
18
|
-
end
|
19
|
-
end
|
20
|
-
end
|
21
|
-
end
|
@@ -1,16 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
module Process
|
4
|
-
module Types
|
5
|
-
##
|
6
|
-
# Represents a response received from a Process. It encapsulates the formatted data to be used by
|
7
|
-
# a Write component.
|
8
|
-
class Response
|
9
|
-
attr_reader :data
|
10
|
-
|
11
|
-
def initialize(response)
|
12
|
-
@data = response
|
13
|
-
end
|
14
|
-
end
|
15
|
-
end
|
16
|
-
end
|
data/lib/bas/read/github/base.rb
DELETED
@@ -1,57 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
require "octokit"
|
4
|
-
require "openssl"
|
5
|
-
require "jwt"
|
6
|
-
|
7
|
-
require_relative "../base"
|
8
|
-
require_relative "./types/response"
|
9
|
-
|
10
|
-
module Read
|
11
|
-
module Github
|
12
|
-
##
|
13
|
-
# This class is an implementation of the Read::Base interface, specifically designed
|
14
|
-
# for reading data from a GitHub repository.
|
15
|
-
#
|
16
|
-
class Base < Read::Base
|
17
|
-
protected
|
18
|
-
|
19
|
-
# Implements the data reading logic to get data from a Github repository.
|
20
|
-
# It connects to Github using the octokit gem, authenticates with a github app,
|
21
|
-
# request the data and returns a validated response.
|
22
|
-
#
|
23
|
-
def read(method, *filter)
|
24
|
-
octokit_response = octokit.public_send(method, *filter)
|
25
|
-
|
26
|
-
Read::Github::Types::Response.new(octokit_response)
|
27
|
-
end
|
28
|
-
|
29
|
-
private
|
30
|
-
|
31
|
-
def octokit
|
32
|
-
Octokit::Client.new(bearer_token: access_token)
|
33
|
-
end
|
34
|
-
|
35
|
-
def access_token
|
36
|
-
app = Octokit::Client.new(client_id: config[:app_id], bearer_token: jwt)
|
37
|
-
|
38
|
-
app.create_app_installation_access_token(config[:installation_id])[:token]
|
39
|
-
end
|
40
|
-
|
41
|
-
def jwt
|
42
|
-
private_pem = File.read(config[:secret_path])
|
43
|
-
private_key = OpenSSL::PKey::RSA.new(private_pem)
|
44
|
-
|
45
|
-
JWT.encode(jwt_payload, private_key, "RS256")
|
46
|
-
end
|
47
|
-
|
48
|
-
def jwt_payload
|
49
|
-
{
|
50
|
-
iat: Time.now.to_i - 60,
|
51
|
-
exp: Time.now.to_i + (10 * 60),
|
52
|
-
iss: config[:app_id]
|
53
|
-
}
|
54
|
-
end
|
55
|
-
end
|
56
|
-
end
|
57
|
-
end
|