bas 0.3.1 → 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/.rubocop.yml +1 -1
- data/CHANGELOG.md +15 -0
- data/CONTRIBUTING.md +9 -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 +31 -57
- 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/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/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/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/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/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 -389
- data/lib/bas/write/logs/base.rb +0 -33
- data/lib/bas/write/logs/use_case/console_log.rb +0 -22
|
@@ -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: 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,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: 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
|
|
@@ -1,27 +0,0 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
|
-
|
|
3
|
-
module Read
|
|
4
|
-
module Github
|
|
5
|
-
module Types
|
|
6
|
-
##
|
|
7
|
-
# Represents a response received from the Octokit Github client. It encapsulates essential
|
|
8
|
-
# information about the response, providing a structured way to handle and analyze
|
|
9
|
-
# it's responses.
|
|
10
|
-
class Response
|
|
11
|
-
attr_reader :status_code, :message, :results
|
|
12
|
-
|
|
13
|
-
def initialize(response)
|
|
14
|
-
if response.empty?
|
|
15
|
-
@status_code = 404
|
|
16
|
-
@message = "no result were found"
|
|
17
|
-
@results = []
|
|
18
|
-
else
|
|
19
|
-
@status_code = 200
|
|
20
|
-
@message = "success"
|
|
21
|
-
@results = response
|
|
22
|
-
end
|
|
23
|
-
end
|
|
24
|
-
end
|
|
25
|
-
end
|
|
26
|
-
end
|
|
27
|
-
end
|
|
@@ -1,17 +0,0 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
|
-
|
|
3
|
-
require_relative "../base"
|
|
4
|
-
|
|
5
|
-
module Read
|
|
6
|
-
module Github
|
|
7
|
-
##
|
|
8
|
-
# This class is an implementation of the Read::Github::Base interface, specifically designed
|
|
9
|
-
# for reading issues from a Github repository.
|
|
10
|
-
#
|
|
11
|
-
class RepoIssues < Github::Base
|
|
12
|
-
def execute
|
|
13
|
-
read("list_issues", config[:repo])
|
|
14
|
-
end
|
|
15
|
-
end
|
|
16
|
-
end
|
|
17
|
-
end
|
data/lib/bas/read/imap/base.rb
DELETED
|
@@ -1,70 +0,0 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
|
-
|
|
3
|
-
require "net/imap"
|
|
4
|
-
require "gmail_xoauth"
|
|
5
|
-
|
|
6
|
-
require_relative "../base"
|
|
7
|
-
require_relative "./types/response"
|
|
8
|
-
|
|
9
|
-
module Read
|
|
10
|
-
module Imap
|
|
11
|
-
##
|
|
12
|
-
# This class is an implementation of the Read::Base interface, specifically designed
|
|
13
|
-
# for reading data from an IMAP server.
|
|
14
|
-
#
|
|
15
|
-
class Base < Read::Base
|
|
16
|
-
protected
|
|
17
|
-
|
|
18
|
-
# Implements the reading logic for emails data from an IMAP server.
|
|
19
|
-
# It connects to an IMAP server inbox, request emails base on a filter,
|
|
20
|
-
# and returns a validated response.
|
|
21
|
-
#
|
|
22
|
-
def read(email_domain, email_port, token_uri, query)
|
|
23
|
-
access_token = refresh_token(token_uri)
|
|
24
|
-
|
|
25
|
-
imap_fetch(email_domain, email_port, query, access_token)
|
|
26
|
-
|
|
27
|
-
Read::Imap::Types::Response.new(@emails)
|
|
28
|
-
end
|
|
29
|
-
|
|
30
|
-
private
|
|
31
|
-
|
|
32
|
-
def imap_fetch(email_domain, email_port, query, access_token)
|
|
33
|
-
imap = Net::IMAP.new(email_domain, port: email_port, ssl: true)
|
|
34
|
-
|
|
35
|
-
imap.authenticate("XOAUTH2", config[:user], access_token)
|
|
36
|
-
|
|
37
|
-
imap.examine(config[:inbox])
|
|
38
|
-
|
|
39
|
-
@emails = fetch_emails(imap, query)
|
|
40
|
-
|
|
41
|
-
imap.logout
|
|
42
|
-
imap.disconnect
|
|
43
|
-
end
|
|
44
|
-
|
|
45
|
-
def fetch_emails(imap, query)
|
|
46
|
-
imap.search(query).map do |message_id|
|
|
47
|
-
imap.fetch(message_id, "ENVELOPE")[0].attr["ENVELOPE"]
|
|
48
|
-
end
|
|
49
|
-
end
|
|
50
|
-
|
|
51
|
-
def refresh_token(token_uri)
|
|
52
|
-
uri = URI.parse(token_uri)
|
|
53
|
-
|
|
54
|
-
response = Net::HTTP.post_form(uri, params)
|
|
55
|
-
token_data = JSON.parse(response.body)
|
|
56
|
-
|
|
57
|
-
token_data["access_token"]
|
|
58
|
-
end
|
|
59
|
-
|
|
60
|
-
def params
|
|
61
|
-
{
|
|
62
|
-
"grant_type" => "refresh_token",
|
|
63
|
-
"refresh_token" => config[:refresh_token],
|
|
64
|
-
"client_id" => config[:client_id],
|
|
65
|
-
"client_secret" => config[:client_secret]
|
|
66
|
-
}
|
|
67
|
-
end
|
|
68
|
-
end
|
|
69
|
-
end
|
|
70
|
-
end
|
|
@@ -1,27 +0,0 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
|
-
|
|
3
|
-
module Read
|
|
4
|
-
module Imap
|
|
5
|
-
module Types
|
|
6
|
-
##
|
|
7
|
-
# Represents a response received from the Imap client. It encapsulates essential
|
|
8
|
-
# information about the response, providing a structured way to handle and analyze
|
|
9
|
-
# it's responses.
|
|
10
|
-
class Response
|
|
11
|
-
attr_reader :status_code, :message, :results
|
|
12
|
-
|
|
13
|
-
def initialize(response)
|
|
14
|
-
if response.empty?
|
|
15
|
-
@status_code = 404
|
|
16
|
-
@message = "no result were found"
|
|
17
|
-
@results = []
|
|
18
|
-
else
|
|
19
|
-
@status_code = 200
|
|
20
|
-
@message = "success"
|
|
21
|
-
@results = response
|
|
22
|
-
end
|
|
23
|
-
end
|
|
24
|
-
end
|
|
25
|
-
end
|
|
26
|
-
end
|
|
27
|
-
end
|
|
@@ -1,26 +0,0 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
|
-
|
|
3
|
-
require_relative "../base"
|
|
4
|
-
|
|
5
|
-
module Read
|
|
6
|
-
module Imap
|
|
7
|
-
##
|
|
8
|
-
# This class is an implementation of the Read::Imap::Base interface, specifically designed
|
|
9
|
-
# for reading support email from a Google Gmail account.
|
|
10
|
-
#
|
|
11
|
-
class SupportEmails < Imap::Base
|
|
12
|
-
TOKEN_URI = "https://oauth2.googleapis.com/token"
|
|
13
|
-
EMAIL_DOMAIN = "imap.gmail.com"
|
|
14
|
-
EMAIL_PORT = 993
|
|
15
|
-
|
|
16
|
-
# Implements the data reading filter for support emails from Google Gmail.
|
|
17
|
-
#
|
|
18
|
-
def execute
|
|
19
|
-
yesterday = (Time.now - (60 * 60 * 24)).strftime("%d-%b-%Y")
|
|
20
|
-
query = ["TO", config[:search_email], "SINCE", yesterday]
|
|
21
|
-
|
|
22
|
-
read(EMAIL_DOMAIN, EMAIL_PORT, TOKEN_URI, query)
|
|
23
|
-
end
|
|
24
|
-
end
|
|
25
|
-
end
|
|
26
|
-
end
|
data/lib/bas/read/notion/base.rb
DELETED
|
@@ -1,52 +0,0 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
|
-
|
|
3
|
-
require "httparty"
|
|
4
|
-
|
|
5
|
-
require_relative "../base"
|
|
6
|
-
require_relative "./exceptions/invalid_api_key"
|
|
7
|
-
require_relative "./exceptions/invalid_database_id"
|
|
8
|
-
require_relative "./types/response"
|
|
9
|
-
require_relative "./helper"
|
|
10
|
-
|
|
11
|
-
module Read
|
|
12
|
-
module Notion
|
|
13
|
-
##
|
|
14
|
-
# This class is an implementation of the Read::Base interface, specifically designed
|
|
15
|
-
# for reading data from Notion.
|
|
16
|
-
#
|
|
17
|
-
class Base < Read::Base
|
|
18
|
-
NOTION_BASE_URL = "https://api.notion.com"
|
|
19
|
-
|
|
20
|
-
protected
|
|
21
|
-
|
|
22
|
-
# Implements the read logic for data from Notion. It sends a POST
|
|
23
|
-
# request to the Notion API to query the specified database and returns a validated response.
|
|
24
|
-
#
|
|
25
|
-
# <br>
|
|
26
|
-
# <b>raises</b> <tt>Exceptions::Notion::InvalidApiKey</tt> if the API key provided is incorrect or invalid.
|
|
27
|
-
#
|
|
28
|
-
# <b>raises</b> <tt>Exceptions::Notion::InvalidDatabaseId</tt> if the Database id provided is incorrect
|
|
29
|
-
# or invalid.
|
|
30
|
-
#
|
|
31
|
-
def read(filter)
|
|
32
|
-
url = "#{NOTION_BASE_URL}/v1/databases/#{config[:database_id]}/query"
|
|
33
|
-
|
|
34
|
-
httparty_response = HTTParty.post(url, { body: filter.to_json, headers: headers })
|
|
35
|
-
|
|
36
|
-
notion_response = Read::Notion::Types::Response.new(httparty_response)
|
|
37
|
-
|
|
38
|
-
Read::Notion::Helper.validate_response(notion_response)
|
|
39
|
-
end
|
|
40
|
-
|
|
41
|
-
private
|
|
42
|
-
|
|
43
|
-
def headers
|
|
44
|
-
{
|
|
45
|
-
"Authorization" => "Bearer #{config[:secret]}",
|
|
46
|
-
"Content-Type" => "application/json",
|
|
47
|
-
"Notion-Version" => "2022-06-28"
|
|
48
|
-
}
|
|
49
|
-
end
|
|
50
|
-
end
|
|
51
|
-
end
|
|
52
|
-
end
|
|
@@ -1,15 +0,0 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
|
-
|
|
3
|
-
module Exceptions
|
|
4
|
-
module Notion
|
|
5
|
-
##
|
|
6
|
-
# Provides a domain-specific representation for errors that occurs when an invalid API key is provided
|
|
7
|
-
# for a Notion-related operation.
|
|
8
|
-
#
|
|
9
|
-
class InvalidApiKey < StandardError
|
|
10
|
-
def initialize(message = "The provided API token is invalid.")
|
|
11
|
-
super(message)
|
|
12
|
-
end
|
|
13
|
-
end
|
|
14
|
-
end
|
|
15
|
-
end
|
|
@@ -1,15 +0,0 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
|
-
|
|
3
|
-
module Exceptions
|
|
4
|
-
module Notion
|
|
5
|
-
##
|
|
6
|
-
# Provides a domain-specific representation for errors that occurs when an invalid database id is provided
|
|
7
|
-
# for a Notion-related operation.
|
|
8
|
-
#
|
|
9
|
-
class InvalidDatabaseId < StandardError
|
|
10
|
-
def initialize(message = "The provided id doesn't match any database.")
|
|
11
|
-
super(message)
|
|
12
|
-
end
|
|
13
|
-
end
|
|
14
|
-
end
|
|
15
|
-
end
|
|
@@ -1,21 +0,0 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
|
-
|
|
3
|
-
module Read
|
|
4
|
-
module Notion
|
|
5
|
-
##
|
|
6
|
-
# Provides common fuctionalities along the Notion domain.
|
|
7
|
-
#
|
|
8
|
-
module Helper
|
|
9
|
-
def self.validate_response(response)
|
|
10
|
-
case response.status_code
|
|
11
|
-
when 401
|
|
12
|
-
raise Exceptions::Notion::InvalidApiKey, response.message
|
|
13
|
-
when 404
|
|
14
|
-
raise Exceptions::Notion::InvalidDatabaseId, response.message
|
|
15
|
-
else
|
|
16
|
-
response
|
|
17
|
-
end
|
|
18
|
-
end
|
|
19
|
-
end
|
|
20
|
-
end
|
|
21
|
-
end
|