bas 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
|