bas 0.1.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 +7 -0
- data/._.rspec_status +0 -0
- data/.rspec +3 -0
- data/.rubocop.yml +14 -0
- data/CHANGELOG.md +4 -0
- data/CODE_OF_CONDUCT.md +132 -0
- data/CONTRIBUTING.md +66 -0
- data/Gemfile +24 -0
- data/LICENSE +21 -0
- data/README.md +362 -0
- data/Rakefile +12 -0
- data/SECURITY.md +13 -0
- data/lib/bas/dispatcher/base.rb +31 -0
- data/lib/bas/dispatcher/discord/exceptions/invalid_webhook_token.rb +16 -0
- data/lib/bas/dispatcher/discord/implementation.rb +51 -0
- data/lib/bas/dispatcher/discord/types/response.rb +22 -0
- data/lib/bas/dispatcher/slack/exceptions/invalid_webhook_token.rb +16 -0
- data/lib/bas/dispatcher/slack/implementation.rb +51 -0
- data/lib/bas/dispatcher/slack/types/response.rb +21 -0
- data/lib/bas/domain/birthday.rb +25 -0
- data/lib/bas/domain/email.rb +34 -0
- data/lib/bas/domain/exceptions/function_not_implemented.rb +18 -0
- data/lib/bas/domain/pto.rb +28 -0
- data/lib/bas/domain/work_items_limit.rb +25 -0
- data/lib/bas/fetcher/base.rb +43 -0
- data/lib/bas/fetcher/imap/base.rb +70 -0
- data/lib/bas/fetcher/imap/types/response.rb +27 -0
- data/lib/bas/fetcher/imap/use_case/support_emails.rb +26 -0
- data/lib/bas/fetcher/notion/base.rb +52 -0
- data/lib/bas/fetcher/notion/exceptions/invalid_api_key.rb +15 -0
- data/lib/bas/fetcher/notion/exceptions/invalid_database_id.rb +15 -0
- data/lib/bas/fetcher/notion/helper.rb +21 -0
- data/lib/bas/fetcher/notion/types/response.rb +26 -0
- data/lib/bas/fetcher/notion/use_case/birthday_next_week.rb +41 -0
- data/lib/bas/fetcher/notion/use_case/birthday_today.rb +29 -0
- data/lib/bas/fetcher/notion/use_case/pto_next_week.rb +71 -0
- data/lib/bas/fetcher/notion/use_case/pto_today.rb +30 -0
- data/lib/bas/fetcher/notion/use_case/work_items_limit.rb +37 -0
- data/lib/bas/fetcher/postgres/base.rb +46 -0
- data/lib/bas/fetcher/postgres/helper.rb +16 -0
- data/lib/bas/fetcher/postgres/types/response.rb +42 -0
- data/lib/bas/fetcher/postgres/use_case/pto_today.rb +32 -0
- data/lib/bas/formatter/base.rb +53 -0
- data/lib/bas/formatter/birthday.rb +34 -0
- data/lib/bas/formatter/exceptions/invalid_data.rb +15 -0
- data/lib/bas/formatter/pto.rb +88 -0
- data/lib/bas/formatter/support_emails.rb +69 -0
- data/lib/bas/formatter/work_items_limit.rb +64 -0
- data/lib/bas/mapper/base.rb +30 -0
- data/lib/bas/mapper/imap/support_emails.rb +56 -0
- data/lib/bas/mapper/notion/birthday_today.rb +68 -0
- data/lib/bas/mapper/notion/pto_today.rb +70 -0
- data/lib/bas/mapper/notion/work_items_limit.rb +65 -0
- data/lib/bas/mapper/postgres/pto_today.rb +47 -0
- data/lib/bas/use_cases/types/config.rb +19 -0
- data/lib/bas/use_cases/use_case.rb +39 -0
- data/lib/bas/use_cases/use_cases.rb +377 -0
- data/lib/bas/version.rb +6 -0
- data/lib/bas.rb +9 -0
- data/renovate.json +6 -0
- data/sig/business_automation_system.rbs +4 -0
- metadata +107 -0
@@ -0,0 +1,30 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative "../domain/exceptions/function_not_implemented"
|
4
|
+
|
5
|
+
module Mapper
|
6
|
+
##
|
7
|
+
# The Mapper::Base module serves as the foundation for implementing specific data shaping logic within the
|
8
|
+
# Mapper module. Defines essential methods, that provide a blueprint for organizing or shaping data in a manner
|
9
|
+
# suitable for downstream formatting processes.
|
10
|
+
#
|
11
|
+
module Base
|
12
|
+
# An method meant to prepare or organize the data coming from an implementation of the Fetcher::Base interface.
|
13
|
+
# Must be overridden by subclasses, with specific logic based on the use case.
|
14
|
+
#
|
15
|
+
# <br>
|
16
|
+
# <b>Params:</b>
|
17
|
+
# * <tt>Fetcher::Notion::Types::Response</tt> response: Response produced by a fetcher.
|
18
|
+
#
|
19
|
+
# <br>
|
20
|
+
#
|
21
|
+
# <b>raises</b> <tt>Domain::Exceptions::FunctionNotImplemented</tt> when missing implementation.
|
22
|
+
# <br>
|
23
|
+
#
|
24
|
+
# <b>returns</b> <tt>List<Domain::></tt> Mapped list of data, ready to be formatted.
|
25
|
+
#
|
26
|
+
def map(_response)
|
27
|
+
raise Domain::Exceptions::FunctionNotImplemented
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
@@ -0,0 +1,56 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative "../../domain/email"
|
4
|
+
require_relative "../base"
|
5
|
+
|
6
|
+
module Mapper
|
7
|
+
module Imap
|
8
|
+
##
|
9
|
+
# This class implementats the methods of the Mapper::Base module, specifically designed for
|
10
|
+
# preparing or shaping support emails data coming from a Fetcher::Base implementation.
|
11
|
+
class SupportEmails
|
12
|
+
include Base
|
13
|
+
|
14
|
+
# Implements the logic for shaping the results from a fetcher response.
|
15
|
+
#
|
16
|
+
# <br>
|
17
|
+
# <b>Params:</b>
|
18
|
+
# * <tt>Fetcher::Imap::Types::Response</tt> imap_response: Array of imap emails data.
|
19
|
+
#
|
20
|
+
# <br>
|
21
|
+
# <b>return</b> <tt>List<Domain::Email></tt> support_emails_list, mapped support emails to be used by a
|
22
|
+
# Formatter::Base implementation.
|
23
|
+
#
|
24
|
+
def map(imap_response)
|
25
|
+
return [] if imap_response.results.empty?
|
26
|
+
|
27
|
+
normalized_email_data = normalize_response(imap_response.results)
|
28
|
+
|
29
|
+
normalized_email_data.map do |email|
|
30
|
+
Domain::Email.new(email["subject"], email["sender"], email["date"])
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
private
|
35
|
+
|
36
|
+
def normalize_response(results)
|
37
|
+
return [] if results.nil?
|
38
|
+
|
39
|
+
results.map do |value|
|
40
|
+
{
|
41
|
+
"sender" => extract_sender(value),
|
42
|
+
"date" => value.date,
|
43
|
+
"subject" => value.subject
|
44
|
+
}
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
def extract_sender(value)
|
49
|
+
mailbox = value.sender[0]["mailbox"]
|
50
|
+
host = value.sender[0]["host"]
|
51
|
+
|
52
|
+
"#{mailbox}@#{host}"
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
@@ -0,0 +1,68 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative "../../domain/birthday"
|
4
|
+
require_relative "../base"
|
5
|
+
|
6
|
+
module Mapper
|
7
|
+
module Notion
|
8
|
+
##
|
9
|
+
# This class implementats the methods of the Mapper::Base module, specifically designed for preparing or
|
10
|
+
# shaping birthdays data coming from a Fetcher::Base implementation.
|
11
|
+
class BirthdayToday
|
12
|
+
include Base
|
13
|
+
|
14
|
+
BIRTHDAY_PARAMS = ["Complete Name", "BD_this_year"].freeze
|
15
|
+
|
16
|
+
# Implements the logic for shaping the results from a fetcher response.
|
17
|
+
#
|
18
|
+
# <br>
|
19
|
+
# <b>Params:</b>
|
20
|
+
# * <tt>Fetcher::Notion::Types::Response</tt> notion_response: Notion response object.
|
21
|
+
#
|
22
|
+
# <br>
|
23
|
+
# <b>return</b> <tt>List<Domain::Birthday></tt> birthdays_list, mapped birthdays to be used by a
|
24
|
+
# Formatter::Base implementation.
|
25
|
+
#
|
26
|
+
def map(notion_response)
|
27
|
+
return [] if notion_response.results.empty?
|
28
|
+
|
29
|
+
normalized_notion_data = normalize_response(notion_response.results)
|
30
|
+
|
31
|
+
normalized_notion_data.map do |birthday|
|
32
|
+
Domain::Birthday.new(birthday["Complete Name"], birthday["BD_this_year"])
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
private
|
37
|
+
|
38
|
+
def normalize_response(results)
|
39
|
+
return [] if results.nil?
|
40
|
+
|
41
|
+
results.map do |value|
|
42
|
+
birthday_fields = value["properties"].slice(*BIRTHDAY_PARAMS)
|
43
|
+
|
44
|
+
birthday_fields.each do |field, birthday_value|
|
45
|
+
birthday_fields[field] = extract_birthday_value(field, birthday_value)
|
46
|
+
end
|
47
|
+
|
48
|
+
birthday_fields
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
def extract_birthday_value(field, value)
|
53
|
+
case field
|
54
|
+
when "Complete Name" then extract_rich_text_field_value(value)
|
55
|
+
when "BD_this_year" then extract_date_field_value(value)
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
def extract_rich_text_field_value(data)
|
60
|
+
data["rich_text"][0]["plain_text"]
|
61
|
+
end
|
62
|
+
|
63
|
+
def extract_date_field_value(data)
|
64
|
+
data["formula"]["date"]["start"]
|
65
|
+
end
|
66
|
+
end
|
67
|
+
end
|
68
|
+
end
|
@@ -0,0 +1,70 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative "../../domain/pto"
|
4
|
+
require_relative "../base"
|
5
|
+
|
6
|
+
module Mapper
|
7
|
+
module Notion
|
8
|
+
##
|
9
|
+
# This class implementats the methods of the Mapper::Base module, specifically designed for preparing or
|
10
|
+
# shaping PTO's data coming from a Fetcher::Base implementation.
|
11
|
+
#
|
12
|
+
class PtoToday
|
13
|
+
include Base
|
14
|
+
|
15
|
+
PTO_PARAMS = ["Person", "Desde?", "Hasta?"].freeze
|
16
|
+
|
17
|
+
# Implements the logic for shaping the results from a fetcher response.
|
18
|
+
#
|
19
|
+
# <br>
|
20
|
+
# <b>Params:</b>
|
21
|
+
# * <tt>Fetcher::Notion::Types::Response</tt> notion_response: Notion response object.
|
22
|
+
#
|
23
|
+
# <br>
|
24
|
+
# <b>returns</b> <tt>List<Domain::Pto></tt> ptos_list, mapped PTO's to be used by a Formatter::Base
|
25
|
+
# implementation.
|
26
|
+
#
|
27
|
+
def map(notion_response)
|
28
|
+
return [] if notion_response.results.empty?
|
29
|
+
|
30
|
+
normalized_notion_data = normalize_response(notion_response.results)
|
31
|
+
|
32
|
+
normalized_notion_data.map do |pto|
|
33
|
+
Domain::Pto.new(pto["Person"], pto["Desde?"], pto["Hasta?"])
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
private
|
38
|
+
|
39
|
+
def normalize_response(response)
|
40
|
+
return [] if response.nil?
|
41
|
+
|
42
|
+
response.map do |value|
|
43
|
+
pto_fields = value["properties"].slice(*PTO_PARAMS)
|
44
|
+
|
45
|
+
pto_fields.each do |field, pto_value|
|
46
|
+
pto_fields[field] = extract_pto_value(field, pto_value)
|
47
|
+
end
|
48
|
+
|
49
|
+
pto_fields
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
def extract_pto_value(field, value)
|
54
|
+
case field
|
55
|
+
when "Person" then extract_person_field_value(value)
|
56
|
+
when "Desde?" then extract_date_field_value(value)
|
57
|
+
when "Hasta?" then extract_date_field_value(value)
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
def extract_person_field_value(data)
|
62
|
+
data["people"][0]["name"]
|
63
|
+
end
|
64
|
+
|
65
|
+
def extract_date_field_value(data)
|
66
|
+
data["date"]["start"]
|
67
|
+
end
|
68
|
+
end
|
69
|
+
end
|
70
|
+
end
|
@@ -0,0 +1,65 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative "../../domain/work_items_limit"
|
4
|
+
require_relative "../base"
|
5
|
+
|
6
|
+
module Mapper
|
7
|
+
module Notion
|
8
|
+
##
|
9
|
+
# This class implementats the methods of the Mapper::Base module, specifically designed
|
10
|
+
# for preparing or shaping work items data coming from a Fetcher::Base implementation.
|
11
|
+
class WorkItemsLimit
|
12
|
+
include Base
|
13
|
+
|
14
|
+
WORK_ITEM_PARAMS = ["Responsible domain"].freeze
|
15
|
+
|
16
|
+
# Implements the logic for shaping the results from a fetcher response.
|
17
|
+
#
|
18
|
+
# <br>
|
19
|
+
# <b>Params:</b>
|
20
|
+
# * <tt>Fetcher::Notion::Types::Response</tt> notion_response: Notion response object.
|
21
|
+
#
|
22
|
+
# <br>
|
23
|
+
# <b>return</b> <tt>List<Domain::WorkItem></tt> work_items_list, mapped work items to be used by a
|
24
|
+
# Formatter::Base implementation.
|
25
|
+
#
|
26
|
+
def map(notion_response)
|
27
|
+
return [] if notion_response.results.empty?
|
28
|
+
|
29
|
+
normalized_notion_data = normalize_response(notion_response.results)
|
30
|
+
|
31
|
+
domain_items_count = count_domain_items(normalized_notion_data)
|
32
|
+
|
33
|
+
domain_items_count.map do |domain, items_count|
|
34
|
+
Domain::WorkItemsLimit.new(domain, items_count)
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
private
|
39
|
+
|
40
|
+
def normalize_response(results)
|
41
|
+
return [] if results.nil?
|
42
|
+
|
43
|
+
results.map do |value|
|
44
|
+
work_item_fields = value["properties"].slice(*WORK_ITEM_PARAMS)
|
45
|
+
|
46
|
+
work_item_fields.each do |field, work_item_value|
|
47
|
+
work_item_fields[field] = extract_domain_field_value(work_item_value)
|
48
|
+
end
|
49
|
+
|
50
|
+
work_item_fields
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
def extract_domain_field_value(data)
|
55
|
+
data["select"]["name"]
|
56
|
+
end
|
57
|
+
|
58
|
+
def count_domain_items(work_items_list)
|
59
|
+
domain_work_items = work_items_list.group_by { |work_item| work_item["Responsible domain"] }
|
60
|
+
|
61
|
+
domain_work_items.transform_values(&:count)
|
62
|
+
end
|
63
|
+
end
|
64
|
+
end
|
65
|
+
end
|
@@ -0,0 +1,47 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative "../../domain/pto"
|
4
|
+
require_relative "../base"
|
5
|
+
|
6
|
+
module Mapper
|
7
|
+
module Postgres
|
8
|
+
##
|
9
|
+
# This class implementats the methods of the Mapper::Base module, specifically designed for preparing or
|
10
|
+
# shaping PTO's data coming from the Fetcher::Postgres::Pto class.
|
11
|
+
#
|
12
|
+
class PtoToday
|
13
|
+
# Implements the logic for shaping the results from a fetcher response.
|
14
|
+
#
|
15
|
+
# <br>
|
16
|
+
# <b>Params:</b>
|
17
|
+
# * <tt>Fetcher::Postgres::Types::Response</tt> pg_response: Postgres response object.
|
18
|
+
#
|
19
|
+
# <br>
|
20
|
+
# <b>returns</b> <tt>List<Domain::Pto></tt> ptos_list, mapped PTO's to be used by a Formatter::Base
|
21
|
+
# implementation.
|
22
|
+
#
|
23
|
+
def map(pg_response)
|
24
|
+
return [] if pg_response.records.empty?
|
25
|
+
|
26
|
+
ptos = build_map(pg_response)
|
27
|
+
|
28
|
+
ptos.map do |pto|
|
29
|
+
name = pto["name"]
|
30
|
+
start_date = pto["start_date"]
|
31
|
+
end_date = pto["end_date"]
|
32
|
+
|
33
|
+
Domain::Pto.new(name, start_date, end_date)
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
private
|
38
|
+
|
39
|
+
def build_map(pg_response)
|
40
|
+
fields = pg_response.fields
|
41
|
+
values = pg_response.records
|
42
|
+
|
43
|
+
values.map { |value| Hash[fields.zip(value)] }
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module UseCases
|
4
|
+
module Types
|
5
|
+
##
|
6
|
+
# Represents a the configuration composing the initial components required by a UseCases::UseCase implementation.
|
7
|
+
#
|
8
|
+
class Config
|
9
|
+
attr_reader :fetcher, :mapper, :formatter, :dispatcher
|
10
|
+
|
11
|
+
def initialize(fetcher, mapper, formatter, dispatcher)
|
12
|
+
@fetcher = fetcher
|
13
|
+
@mapper = mapper
|
14
|
+
@formatter = formatter
|
15
|
+
@dispatcher = dispatcher
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
@@ -0,0 +1,39 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module UseCases
|
4
|
+
##
|
5
|
+
# The UseCases::UseCase class represents a generic structure for use cases within the system. It encapsulates the
|
6
|
+
# logic flow by coordinating the execution of its components to fulfill a specific use case.
|
7
|
+
#
|
8
|
+
class UseCase
|
9
|
+
attr_reader :fetcher, :mapper, :formatter, :dispatcher
|
10
|
+
|
11
|
+
# Initializes the use case with the necessary components.
|
12
|
+
#
|
13
|
+
# <br>
|
14
|
+
# <b>Params:</b>
|
15
|
+
# * <tt>Usecases::Types::Config</tt> config, The components required to instantiate a use case.
|
16
|
+
#
|
17
|
+
def initialize(config)
|
18
|
+
@fetcher = config.fetcher
|
19
|
+
@mapper = config.mapper
|
20
|
+
@formatter = config.formatter
|
21
|
+
@dispatcher = config.dispatcher
|
22
|
+
end
|
23
|
+
|
24
|
+
# Executes the use case by orchestrating the sequential execution of the fetcher, mapper, formatter, and dispatcher.
|
25
|
+
#
|
26
|
+
# <br>
|
27
|
+
# <b>returns</b> <tt>Dispatcher::Discord::Types::Response</tt>
|
28
|
+
#
|
29
|
+
def perform
|
30
|
+
response = fetcher.fetch
|
31
|
+
|
32
|
+
mappings = mapper.map(response)
|
33
|
+
|
34
|
+
formatted_payload = formatter.format(mappings)
|
35
|
+
|
36
|
+
dispatcher.dispatch(formatted_payload)
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|