bns 0.1.1 → 0.2.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/._.rspec_status +0 -0
- data/CHANGELOG.md +9 -0
- data/Gemfile +2 -0
- data/README.md +159 -3
- data/lib/bns/dispatcher/discord/exceptions/invalid_webhook_token.rb +2 -2
- data/lib/bns/dispatcher/discord/implementation.rb +1 -1
- data/lib/bns/dispatcher/slack/exceptions/invalid_webhook_token.rb +16 -0
- data/lib/bns/dispatcher/slack/implementation.rb +51 -0
- data/lib/bns/dispatcher/slack/types/response.rb +21 -0
- data/lib/bns/domain/work_items_limit.rb +39 -0
- data/lib/bns/fetcher/base.rb +13 -0
- data/lib/bns/fetcher/notion/{pto.rb → base.rb} +11 -7
- data/lib/bns/fetcher/notion/types/response.rb +1 -1
- data/lib/bns/fetcher/notion/use_case/birthday_next_week.rb +41 -0
- data/lib/bns/fetcher/notion/use_case/birthday_today.rb +29 -0
- data/lib/bns/fetcher/notion/use_case/pto_next_week.rb +71 -0
- data/lib/bns/fetcher/notion/use_case/pto_today.rb +30 -0
- data/lib/bns/fetcher/notion/use_case/work_items_limit.rb +37 -0
- data/lib/bns/fetcher/postgres/base.rb +46 -0
- data/lib/bns/fetcher/postgres/helper.rb +16 -0
- data/lib/bns/fetcher/postgres/types/response.rb +42 -0
- data/lib/bns/fetcher/postgres/use_case/pto_today.rb +32 -0
- data/lib/bns/formatter/base.rb +11 -8
- data/lib/bns/formatter/birthday.rb +34 -0
- data/lib/bns/formatter/exceptions/invalid_data.rb +15 -0
- data/lib/bns/formatter/pto.rb +76 -0
- data/lib/bns/formatter/work_items_limit.rb +43 -0
- data/lib/bns/mapper/notion/{birthday.rb → birthday_today.rb} +13 -21
- data/lib/bns/mapper/notion/{pto.rb → pto_today.rb} +15 -41
- data/lib/bns/mapper/notion/work_items_limit.rb +65 -0
- data/lib/bns/mapper/postgres/pto_today.rb +47 -0
- data/lib/bns/use_cases/use_cases.rb +227 -49
- data/lib/bns/version.rb +1 -1
- metadata +25 -9
- data/lib/bns/fetcher/notion/birthday.rb +0 -53
- data/lib/bns/formatter/discord/birthday.rb +0 -36
- data/lib/bns/formatter/discord/exceptions/invalid_data.rb +0 -17
- data/lib/bns/formatter/discord/pto.rb +0 -49
@@ -0,0 +1,46 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "pg"
|
4
|
+
|
5
|
+
require_relative "../base"
|
6
|
+
require_relative "./types/response"
|
7
|
+
require_relative "./helper"
|
8
|
+
|
9
|
+
module Fetcher
|
10
|
+
module Postgres
|
11
|
+
##
|
12
|
+
# This class is an implementation of the Fetcher::Base interface, specifically designed
|
13
|
+
# for fetching data from Postgres.
|
14
|
+
#
|
15
|
+
class Base < Fetcher::Base
|
16
|
+
protected
|
17
|
+
|
18
|
+
# Implements the data fetching logic from a Postgres database. It use the PG gem
|
19
|
+
# to request data from a local or external database and returns a validated response.
|
20
|
+
#
|
21
|
+
# Gem: pg (https://rubygems.org/gems/pg)
|
22
|
+
#
|
23
|
+
def execute(query)
|
24
|
+
pg_connection = PG::Connection.new(config[:connection])
|
25
|
+
|
26
|
+
pg_result = execute_query(pg_connection, query)
|
27
|
+
|
28
|
+
postgres_response = Fetcher::Postgres::Types::Response.new(pg_result)
|
29
|
+
|
30
|
+
Fetcher::Postgres::Helper.validate_response(postgres_response)
|
31
|
+
end
|
32
|
+
|
33
|
+
private
|
34
|
+
|
35
|
+
def execute_query(pg_connection, query)
|
36
|
+
if query.is_a? String
|
37
|
+
pg_connection.exec(query)
|
38
|
+
else
|
39
|
+
sentence, params = query
|
40
|
+
|
41
|
+
pg_connection.exec_params(sentence, params)
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Fetcher
|
4
|
+
module Postgres
|
5
|
+
##
|
6
|
+
# Provides common fuctionalities along the Postgres domain.
|
7
|
+
#
|
8
|
+
module Helper
|
9
|
+
def self.validate_response(response)
|
10
|
+
response.response.check_result
|
11
|
+
|
12
|
+
response
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
@@ -0,0 +1,42 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Fetcher
|
4
|
+
module Postgres
|
5
|
+
module Types
|
6
|
+
##
|
7
|
+
# Represents a response received from the Postgres API. It encapsulates essential information about the response,
|
8
|
+
# providing a structured way to handle and analyze it's responses.
|
9
|
+
class Response
|
10
|
+
attr_reader :status, :message, :response, :fields, :records
|
11
|
+
|
12
|
+
SUCCESS_STATUS = "PGRES_TUPLES_OK"
|
13
|
+
|
14
|
+
def initialize(response)
|
15
|
+
if response.res_status == SUCCESS_STATUS
|
16
|
+
success_response(response)
|
17
|
+
else
|
18
|
+
failure_response(response)
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
private
|
23
|
+
|
24
|
+
def success_response(response)
|
25
|
+
@status = response.res_status
|
26
|
+
@message = "success"
|
27
|
+
@response = response
|
28
|
+
@fields = response.fields
|
29
|
+
@records = response.values
|
30
|
+
end
|
31
|
+
|
32
|
+
def failure_response(response)
|
33
|
+
@status = response.res_status
|
34
|
+
@message = response.result_error_message
|
35
|
+
@response = response
|
36
|
+
@fields = nil
|
37
|
+
@records = nil
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
@@ -0,0 +1,32 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative "../base"
|
4
|
+
|
5
|
+
module Fetcher
|
6
|
+
module Postgres
|
7
|
+
##
|
8
|
+
# This class is an implementation of the Fetcher::Postgres::Base interface, specifically designed
|
9
|
+
# for fetching Paid Time Off (PTO) data from a Postgres Database.
|
10
|
+
#
|
11
|
+
class PtoToday < Base
|
12
|
+
# Implements the data fetching query for todays PTO data from a Postgres database.
|
13
|
+
#
|
14
|
+
def fetch
|
15
|
+
execute(build_query)
|
16
|
+
end
|
17
|
+
|
18
|
+
private
|
19
|
+
|
20
|
+
def build_query
|
21
|
+
today = Time.now.utc.strftime("%F").to_s
|
22
|
+
|
23
|
+
start_time = "#{today}T00:00:00"
|
24
|
+
end_time = "#{today}T23:59:59"
|
25
|
+
|
26
|
+
where = "(start_date <= $1 AND end_date >= $1) OR (start_date>= $2 AND end_date <= $3)"
|
27
|
+
|
28
|
+
["SELECT * FROM pto WHERE #{where}", [today, start_time, end_time]]
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
data/lib/bns/formatter/base.rb
CHANGED
@@ -10,8 +10,17 @@ module Formatter
|
|
10
10
|
# formatters tailored to different use cases.
|
11
11
|
#
|
12
12
|
class Base
|
13
|
-
|
14
|
-
|
13
|
+
attr_reader :template
|
14
|
+
|
15
|
+
# Initializes the fetcher with essential configuration parameters.
|
16
|
+
#
|
17
|
+
def initialize(config = {})
|
18
|
+
@config = config
|
19
|
+
@template = config[:template]
|
20
|
+
end
|
21
|
+
|
22
|
+
# This method is designed to provide a specified format for data from any implementation of
|
23
|
+
# the Mapper::Base interface.
|
15
24
|
# Must be overridden by subclasses, with specific logic based on the use case.
|
16
25
|
#
|
17
26
|
# <br>
|
@@ -23,12 +32,6 @@ module Formatter
|
|
23
32
|
#
|
24
33
|
# <b>returns</b> <tt>String</tt> Formatted payload suitable for a Dispatcher::Base implementation.
|
25
34
|
#
|
26
|
-
attr_reader :template
|
27
|
-
|
28
|
-
def initialize(config = {})
|
29
|
-
@template = config[:template]
|
30
|
-
end
|
31
|
-
|
32
35
|
def format(_domain_data)
|
33
36
|
raise Domain::Exceptions::FunctionNotImplemented
|
34
37
|
end
|
@@ -0,0 +1,34 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative "../domain/birthday"
|
4
|
+
require_relative "./exceptions/invalid_data"
|
5
|
+
require_relative "./base"
|
6
|
+
|
7
|
+
module Formatter
|
8
|
+
##
|
9
|
+
# This class implements methods from the Formatter::Base module, tailored to format the
|
10
|
+
# Domain::Birthday structure for a dispatcher.
|
11
|
+
class Birthday < Base
|
12
|
+
# Implements the logic for building a formatted payload with the given template for birthdays.
|
13
|
+
#
|
14
|
+
# <br>
|
15
|
+
# <b>Params:</b>
|
16
|
+
# * <tt>List<Domain::Birthday></tt> birthdays_list: list of mapped birthdays.
|
17
|
+
#
|
18
|
+
# <br>
|
19
|
+
# <b>raises</b> <tt>Formatter::Exceptions::InvalidData</tt> when invalid data is provided.
|
20
|
+
#
|
21
|
+
# <br>
|
22
|
+
# <b>returns</b> <tt>String</tt> payload: formatted payload suitable for a Dispatcher.
|
23
|
+
#
|
24
|
+
def format(birthdays_list)
|
25
|
+
raise Formatter::Exceptions::InvalidData unless birthdays_list.all? do |brithday|
|
26
|
+
brithday.is_a?(Domain::Birthday)
|
27
|
+
end
|
28
|
+
|
29
|
+
birthdays_list.reduce("") do |payload, birthday|
|
30
|
+
payload + build_template(Domain::Birthday::ATTRIBUTES, birthday)
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Formatter
|
4
|
+
module Exceptions
|
5
|
+
##
|
6
|
+
# Provides a domain-specific representation for errors that occurs when trying to process invalid
|
7
|
+
# data on a Fetcher::Base implementation
|
8
|
+
#
|
9
|
+
class InvalidData < StandardError
|
10
|
+
def initialize(message = "")
|
11
|
+
super(message)
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
@@ -0,0 +1,76 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative "../domain/pto"
|
4
|
+
require_relative "./exceptions/invalid_data"
|
5
|
+
require_relative "./base"
|
6
|
+
|
7
|
+
module Formatter
|
8
|
+
##
|
9
|
+
# This class implements methods from the Formatter::Base module, tailored to format the
|
10
|
+
# Domain::Pto structure for a dispatcher.
|
11
|
+
class Pto < Base
|
12
|
+
# Initializes the Slack formatter with essential configuration parameters.
|
13
|
+
#
|
14
|
+
# <b>timezone</b> : expect an string with the time difference relative to the UTC. Example: "-05:00"
|
15
|
+
def initialize(config = {})
|
16
|
+
super(config)
|
17
|
+
|
18
|
+
@timezone = config[:timezone]
|
19
|
+
end
|
20
|
+
|
21
|
+
# Implements the logic for building a formatted payload with the given template for PTO's.
|
22
|
+
#
|
23
|
+
# <br>
|
24
|
+
# <b>Params:</b>
|
25
|
+
# * <tt>List<Domain::Pto></tt> pto_list: List of mapped PTO's.
|
26
|
+
#
|
27
|
+
# <br>
|
28
|
+
# <b>raises</b> <tt>Formatter::Exceptions::InvalidData</tt> when invalid data is provided.
|
29
|
+
#
|
30
|
+
# <br>
|
31
|
+
# <b>returns</b> <tt>String</tt> payload, formatted payload suitable for a Dispatcher.
|
32
|
+
#
|
33
|
+
|
34
|
+
def format(ptos_list)
|
35
|
+
raise Formatter::Exceptions::InvalidData unless ptos_list.all? { |pto| pto.is_a?(Domain::Pto) }
|
36
|
+
|
37
|
+
ptos_list.reduce("") do |payload, pto|
|
38
|
+
built_template = build_template(Domain::Pto::ATTRIBUTES, pto)
|
39
|
+
payload + format_message_by_case(built_template.gsub("\n", ""), pto)
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
private
|
44
|
+
|
45
|
+
def format_message_by_case(built_template, pto)
|
46
|
+
date_start = format_timezone(pto.start_date).strftime("%F")
|
47
|
+
date_end = format_timezone(pto.end_date).strftime("%F")
|
48
|
+
|
49
|
+
if date_start == date_end
|
50
|
+
interval = same_day_interval(pto)
|
51
|
+
day_message = today?(date_start) ? "today" : "the day #{date_start}"
|
52
|
+
|
53
|
+
"#{built_template} #{day_message} #{interval}\n"
|
54
|
+
else
|
55
|
+
"#{built_template} from #{date_start} to #{date_end}\n"
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
def same_day_interval(pto)
|
60
|
+
time_start = format_timezone(pto.start_date).strftime("%I:%M %P")
|
61
|
+
time_end = format_timezone(pto.end_date).strftime("%I:%M %P")
|
62
|
+
|
63
|
+
time_start == time_end ? "all day" : "from #{time_start} to #{time_end}"
|
64
|
+
end
|
65
|
+
|
66
|
+
def format_timezone(date)
|
67
|
+
@timezone.nil? ? Time.new(date) : Time.new(date, in: @timezone)
|
68
|
+
end
|
69
|
+
|
70
|
+
def today?(date)
|
71
|
+
time_now = Time.now.strftime("%F")
|
72
|
+
|
73
|
+
date == format_timezone(time_now).strftime("%F")
|
74
|
+
end
|
75
|
+
end
|
76
|
+
end
|
@@ -0,0 +1,43 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative "../domain/work_items_limit"
|
4
|
+
require_relative "./exceptions/invalid_data"
|
5
|
+
require_relative "./base"
|
6
|
+
|
7
|
+
module Formatter
|
8
|
+
##
|
9
|
+
# This class implements methods from the Formatter::Base module, tailored to format the
|
10
|
+
# Domain::WorkItemsLimit structure for a dispatcher.
|
11
|
+
class WorkItemsLimit < Base
|
12
|
+
attr_reader :limit
|
13
|
+
|
14
|
+
# Implements the logic for building a formatted payload with the given template for wip limits.
|
15
|
+
#
|
16
|
+
# <br>
|
17
|
+
# <b>Params:</b>
|
18
|
+
# * <tt>List<Domain::WorkItemsLimit></tt> work_items_list: List of mapped work items limits.
|
19
|
+
#
|
20
|
+
# <br>
|
21
|
+
# <b>raises</b> <tt>Formatter::Exceptions::InvalidData</tt> when invalid data is provided.
|
22
|
+
#
|
23
|
+
# <br>
|
24
|
+
# <b>returns</b> <tt>String</tt> payload, formatted payload suitable for a Dispatcher.
|
25
|
+
#
|
26
|
+
|
27
|
+
def format(work_items_list)
|
28
|
+
raise Formatter::Exceptions::InvalidData unless work_items_list.all? do |work_item|
|
29
|
+
work_item.is_a?(Domain::WorkItemsLimit)
|
30
|
+
end
|
31
|
+
|
32
|
+
exceeded_domains(work_items_list).reduce("") do |payload, work_items_limit|
|
33
|
+
payload + build_template(Domain::WorkItemsLimit::ATTRIBUTES, work_items_limit)
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
private
|
38
|
+
|
39
|
+
def exceeded_domains(work_items_list)
|
40
|
+
work_items_list.filter { |work_item| work_item.total > work_item.wip_limit }
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
@@ -8,9 +8,11 @@ module Mapper
|
|
8
8
|
##
|
9
9
|
# This class implementats the methods of the Mapper::Base module, specifically designed for preparing or
|
10
10
|
# shaping birthdays data coming from a Fetcher::Base implementation.
|
11
|
-
class
|
11
|
+
class BirthdayToday
|
12
12
|
include Base
|
13
13
|
|
14
|
+
BIRTHDAY_PARAMS = ["Complete Name", "BD_this_year"].freeze
|
15
|
+
|
14
16
|
# Implements the logic for shaping the results from a fetcher response.
|
15
17
|
#
|
16
18
|
# <br>
|
@@ -27,7 +29,7 @@ module Mapper
|
|
27
29
|
normalized_notion_data = normalize_response(notion_response.results)
|
28
30
|
|
29
31
|
normalized_notion_data.map do |birthday|
|
30
|
-
Domain::Birthday.new(birthday["
|
32
|
+
Domain::Birthday.new(birthday["Complete Name"], birthday["BD_this_year"])
|
31
33
|
end
|
32
34
|
end
|
33
35
|
|
@@ -36,32 +38,22 @@ module Mapper
|
|
36
38
|
def normalize_response(results)
|
37
39
|
return [] if results.nil?
|
38
40
|
|
39
|
-
normalized_results = []
|
40
|
-
|
41
41
|
results.map do |value|
|
42
|
-
|
43
|
-
properties.delete("Name")
|
42
|
+
birthday_fields = value["properties"].slice(*BIRTHDAY_PARAMS)
|
44
43
|
|
45
|
-
|
44
|
+
birthday_fields.each do |field, birthday_value|
|
45
|
+
birthday_fields[field] = extract_birthday_value(field, birthday_value)
|
46
|
+
end
|
46
47
|
|
47
|
-
|
48
|
+
birthday_fields
|
48
49
|
end
|
49
|
-
|
50
|
-
normalized_results
|
51
50
|
end
|
52
51
|
|
53
|
-
def
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
if k == "Complete Name"
|
58
|
-
normalized_value["name"] = extract_rich_text_field_value(v)
|
59
|
-
elsif k == "BD_this_year"
|
60
|
-
normalized_value["birth_date"] = extract_date_field_value(v)
|
61
|
-
end
|
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)
|
62
56
|
end
|
63
|
-
|
64
|
-
normalized_value
|
65
57
|
end
|
66
58
|
|
67
59
|
def extract_rich_text_field_value(data)
|
@@ -9,9 +9,11 @@ module Mapper
|
|
9
9
|
# This class implementats the methods of the Mapper::Base module, specifically designed for preparing or
|
10
10
|
# shaping PTO's data coming from a Fetcher::Base implementation.
|
11
11
|
#
|
12
|
-
class
|
12
|
+
class PtoToday
|
13
13
|
include Base
|
14
14
|
|
15
|
+
PTO_PARAMS = ["Person", "Desde?", "Hasta?"].freeze
|
16
|
+
|
15
17
|
# Implements the logic for shaping the results from a fetcher response.
|
16
18
|
#
|
17
19
|
# <br>
|
@@ -26,8 +28,9 @@ module Mapper
|
|
26
28
|
return [] if notion_response.results.empty?
|
27
29
|
|
28
30
|
normalized_notion_data = normalize_response(notion_response.results)
|
31
|
+
|
29
32
|
normalized_notion_data.map do |pto|
|
30
|
-
Domain::Pto.new(pto["
|
33
|
+
Domain::Pto.new(pto["Person"], pto["Desde?"], pto["Hasta?"])
|
31
34
|
end
|
32
35
|
end
|
33
36
|
|
@@ -36,39 +39,22 @@ module Mapper
|
|
36
39
|
def normalize_response(response)
|
37
40
|
return [] if response.nil?
|
38
41
|
|
39
|
-
normalized_response = []
|
40
|
-
|
41
42
|
response.map do |value|
|
42
|
-
|
43
|
-
properties.delete("Name")
|
43
|
+
pto_fields = value["properties"].slice(*PTO_PARAMS)
|
44
44
|
|
45
|
-
|
45
|
+
pto_fields.each do |field, pto_value|
|
46
|
+
pto_fields[field] = extract_pto_value(field, pto_value)
|
47
|
+
end
|
46
48
|
|
47
|
-
|
49
|
+
pto_fields
|
48
50
|
end
|
49
|
-
|
50
|
-
normalized_response
|
51
51
|
end
|
52
52
|
|
53
|
-
def
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
end
|
59
|
-
|
60
|
-
normalized_value
|
61
|
-
end
|
62
|
-
|
63
|
-
def extract_pto_fields(key, value, normalized_value)
|
64
|
-
case key
|
65
|
-
when "Person"
|
66
|
-
user_name = extract_person_field_value(value)
|
67
|
-
normalized_value["name"] = user_name
|
68
|
-
when "Desde?"
|
69
|
-
normalized_value["start"] = extract_date_field_value(value)
|
70
|
-
when "Hasta?"
|
71
|
-
normalized_value["end"] = extract_date_field_value(value)
|
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)
|
72
58
|
end
|
73
59
|
end
|
74
60
|
|
@@ -79,18 +65,6 @@ module Mapper
|
|
79
65
|
def extract_date_field_value(data)
|
80
66
|
data["date"]["start"]
|
81
67
|
end
|
82
|
-
|
83
|
-
def format_date(str_date)
|
84
|
-
return "" if str_date.nil?
|
85
|
-
|
86
|
-
if str_date.include?("T")
|
87
|
-
format = "%Y-%m-%d|%I:%M %p"
|
88
|
-
datetime = Time.new(str_date)
|
89
|
-
datetime.strftime(format)
|
90
|
-
else
|
91
|
-
str_date
|
92
|
-
end
|
93
|
-
end
|
94
68
|
end
|
95
69
|
end
|
96
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
|