bns 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 +3 -0
- data/.rubocop.yml +14 -0
- data/CHANGELOG.md +11 -0
- data/CODE_OF_CONDUCT.md +132 -0
- data/CONTRIBUTING.md +66 -0
- data/Gemfile +18 -0
- data/Gemfile.lock +91 -0
- data/LICENSE +21 -0
- data/README.md +198 -0
- data/Rakefile +12 -0
- data/lib/bns/dispatcher/base.rb +31 -0
- data/lib/bns/dispatcher/discord/exceptions/invalid_webhook_token.rb +16 -0
- data/lib/bns/dispatcher/discord/implementation.rb +51 -0
- data/lib/bns/dispatcher/discord/types/response.rb +22 -0
- data/lib/bns/domain/birthday.rb +23 -0
- data/lib/bns/domain/exceptions/function_not_implemented.rb +18 -0
- data/lib/bns/domain/pto.rb +26 -0
- data/lib/bns/fetcher/base.rb +30 -0
- data/lib/bns/fetcher/notion/birthday.rb +53 -0
- data/lib/bns/fetcher/notion/exceptions/invalid_api_key.rb +15 -0
- data/lib/bns/fetcher/notion/exceptions/invalid_database_id.rb +15 -0
- data/lib/bns/fetcher/notion/helper.rb +21 -0
- data/lib/bns/fetcher/notion/pto.rb +48 -0
- data/lib/bns/fetcher/notion/types/response.rb +26 -0
- data/lib/bns/formatter/base.rb +29 -0
- data/lib/bns/formatter/discord/birthday.rb +43 -0
- data/lib/bns/formatter/discord/exceptions/invalid_data.rb +17 -0
- data/lib/bns/formatter/discord/pto.rb +52 -0
- data/lib/bns/mapper/base.rb +30 -0
- data/lib/bns/mapper/notion/birthday.rb +76 -0
- data/lib/bns/mapper/notion/pto.rb +96 -0
- data/lib/bns/use_cases/types/config.rb +19 -0
- data/lib/bns/use_cases/use_case.rb +39 -0
- data/lib/bns/use_cases/use_cases.rb +150 -0
- data/lib/bns/version.rb +6 -0
- data/lib/bns.rb +9 -0
- data/sig/business_notification_system.rbs +4 -0
- metadata +84 -0
@@ -0,0 +1,51 @@
|
|
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 Dispatcher
|
8
|
+
module Discord
|
9
|
+
##
|
10
|
+
# This class is an implementation of the Dispatcher::Base interface, specifically designed
|
11
|
+
# for dispatching messages to Discord.
|
12
|
+
#
|
13
|
+
class Implementation < Base
|
14
|
+
# Implements the dispatching logic for the Discord use case. It sends a POST request to
|
15
|
+
# the Discord webhook with the specified payload.
|
16
|
+
#
|
17
|
+
# <br>
|
18
|
+
# <b>Params:</b>
|
19
|
+
# * <tt>String</tt> payload: Payload to be dispatched to discord.
|
20
|
+
# <br>
|
21
|
+
# <b>raises</b> <tt>Exceptions::Discord::InvalidWebookToken</tt> if the provided webhook token is invalid.
|
22
|
+
#
|
23
|
+
# <br>
|
24
|
+
# <b>returns</b> <tt>Dispatcher::Discord::Types::Response</tt>
|
25
|
+
#
|
26
|
+
def dispatch(payload)
|
27
|
+
body = {
|
28
|
+
username: name,
|
29
|
+
avatar_url: "",
|
30
|
+
content: payload
|
31
|
+
}.to_json
|
32
|
+
response = HTTParty.post(webhook, { body: body, headers: { "Content-Type" => "application/json" } })
|
33
|
+
|
34
|
+
discord_response = Dispatcher::Discord::Types::Response.new(response)
|
35
|
+
|
36
|
+
validate_response(discord_response)
|
37
|
+
end
|
38
|
+
|
39
|
+
private
|
40
|
+
|
41
|
+
def validate_response(response)
|
42
|
+
case response.code
|
43
|
+
when 50_027
|
44
|
+
raise Exceptions::Discord::InvalidWebookToken, response.message
|
45
|
+
else
|
46
|
+
response
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Dispatcher
|
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
|
@@ -0,0 +1,23 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Domain
|
4
|
+
##
|
5
|
+
# The Domain::Birthday class provides a domain-specific representation of a Birthday object.
|
6
|
+
# It encapsulates the individual's name and their birthdate, offering a structured way to
|
7
|
+
# handle and manipulate birthday information.
|
8
|
+
class Birthday
|
9
|
+
attr_reader :individual_name, :birth_date
|
10
|
+
|
11
|
+
# Initializes a Domain::Birthday instance with the specified individual name, and date of birth.
|
12
|
+
#
|
13
|
+
# <br>
|
14
|
+
# <b>Params:</b>
|
15
|
+
# * <tt>String</tt> individual_name Name of the individual
|
16
|
+
# * <tt>Date</tt> birth_date Birthdate from the individual
|
17
|
+
#
|
18
|
+
def initialize(individual_name, date)
|
19
|
+
@individual_name = individual_name
|
20
|
+
@birth_date = date
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Domain
|
4
|
+
module Exceptions
|
5
|
+
##
|
6
|
+
# Provides a domain-specific representation for errors that occur when a function has not been implemented yet.
|
7
|
+
# It inherits from StandardError # and allows developers to raise a specific exception when a required function
|
8
|
+
# remains unimplemented in a subclass.
|
9
|
+
#
|
10
|
+
class FunctionNotImplemented < StandardError
|
11
|
+
# Initializes the exception with an optional custom error message.
|
12
|
+
#
|
13
|
+
def initialize(message = "The function haven't been implemented yet.")
|
14
|
+
super(message)
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
@@ -0,0 +1,26 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Domain
|
4
|
+
##
|
5
|
+
# The Domain::Pto class provides a domain-specific representation of a Paid Time Off (PTO) object.
|
6
|
+
# It encapsulates information about an individual's time off, including the individual's name,
|
7
|
+
# the start date, and the end date of the time off period.
|
8
|
+
#
|
9
|
+
class Pto
|
10
|
+
attr_reader :individual_name, :start_date, :end_date
|
11
|
+
|
12
|
+
# Initializes a Domain::Pto instance with the specified individual name, start date, and end date.
|
13
|
+
#
|
14
|
+
# <br>
|
15
|
+
# <b>Params:</b>
|
16
|
+
# * <tt>String</tt> individual_name Name of the individual.
|
17
|
+
# * <tt>DateTime</tt> start_date Start day of the PTO.
|
18
|
+
# * <tt>String</tt> end_date End date of the PTO.
|
19
|
+
#
|
20
|
+
def initialize(individual_name, start_date, end_date)
|
21
|
+
@individual_name = individual_name
|
22
|
+
@start_date = start_date
|
23
|
+
@end_date = end_date
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
@@ -0,0 +1,30 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative "../domain/exceptions/function_not_implemented"
|
4
|
+
|
5
|
+
module Fetcher
|
6
|
+
##
|
7
|
+
# The Fetcher::Base class serves as the foundation for implementing specific data fetchers within the Fetcher module.
|
8
|
+
# Operating as an interface, this class defines essential attributes and methods, providing a blueprint for creating
|
9
|
+
# custom fetchers tailored to different data sources.
|
10
|
+
#
|
11
|
+
class Base
|
12
|
+
attr_reader :config
|
13
|
+
|
14
|
+
# Initializes the fetcher with essential configuration parameters.
|
15
|
+
#
|
16
|
+
def initialize(config)
|
17
|
+
@config = config
|
18
|
+
end
|
19
|
+
|
20
|
+
# A method meant to fetch data from an specific source depending on the implementation.
|
21
|
+
# Must be overridden by subclasses, with specific logic based on the use case.
|
22
|
+
#
|
23
|
+
# <br>
|
24
|
+
# <b>raises</b> <tt>Domain::Exceptions::FunctionNotImplemented</tt> when missing implementation.
|
25
|
+
#
|
26
|
+
def fetch
|
27
|
+
raise Domain::Exceptions::FunctionNotImplemented
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
@@ -0,0 +1,53 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "httparty"
|
4
|
+
require "date"
|
5
|
+
|
6
|
+
require_relative "../base"
|
7
|
+
require_relative "./exceptions/invalid_api_key"
|
8
|
+
require_relative "./exceptions/invalid_database_id"
|
9
|
+
require_relative "./types/response"
|
10
|
+
require_relative "./helper"
|
11
|
+
|
12
|
+
module Fetcher
|
13
|
+
module Notion
|
14
|
+
##
|
15
|
+
# This class is an implementation of the Fetcher::Base interface, specifically designed
|
16
|
+
# for fetching birthday data from Notion.
|
17
|
+
#
|
18
|
+
class Birthday < Base
|
19
|
+
# Implements the data fetching logic for Birthdays data from Notion. It sends a POST
|
20
|
+
# request to the Notion API to query the specified database and returns a validated response.
|
21
|
+
#
|
22
|
+
# <br>
|
23
|
+
# <b>raises</b> <tt>Exceptions::Notion::InvalidApiKey</tt> if the API key provided is incorrect or invalid.
|
24
|
+
#
|
25
|
+
# <b>raises</b> <tt>Exceptions::Notion::InvalidDatabaseId</tt> if the Database id provided is incorrect
|
26
|
+
# or invalid.
|
27
|
+
#
|
28
|
+
def fetch
|
29
|
+
url = build_url(config[:base_url], config[:database_id])
|
30
|
+
|
31
|
+
httparty_response = HTTParty.post(url, { body: config[:filter].to_json, headers: headers })
|
32
|
+
|
33
|
+
notion_response = Fetcher::Notion::Types::Response.new(httparty_response)
|
34
|
+
|
35
|
+
Fetcher::Notion::Helper.validate_response(notion_response)
|
36
|
+
end
|
37
|
+
|
38
|
+
private
|
39
|
+
|
40
|
+
def headers
|
41
|
+
{
|
42
|
+
"Authorization" => "Bearer #{config[:secret]}",
|
43
|
+
"Content-Type" => "application/json",
|
44
|
+
"Notion-Version" => "2022-06-28"
|
45
|
+
}
|
46
|
+
end
|
47
|
+
|
48
|
+
def build_url(base, database_id)
|
49
|
+
"#{base}/v1/databases/#{database_id}/query"
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
@@ -0,0 +1,15 @@
|
|
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
|
@@ -0,0 +1,15 @@
|
|
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
|
@@ -0,0 +1,21 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Fetcher
|
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
|
@@ -0,0 +1,48 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "httparty"
|
4
|
+
require "date"
|
5
|
+
|
6
|
+
require_relative "../base"
|
7
|
+
require_relative "./exceptions/invalid_api_key"
|
8
|
+
require_relative "./exceptions/invalid_database_id"
|
9
|
+
require_relative "./types/response"
|
10
|
+
|
11
|
+
module Fetcher
|
12
|
+
module Notion
|
13
|
+
##
|
14
|
+
# This class is an implementation of the Fetcher::Base interface, specifically designed
|
15
|
+
# for fetching Paid Time Off (PTO) data from Notion.
|
16
|
+
#
|
17
|
+
class Pto < Base
|
18
|
+
# Implements the data fetching logic for PTO's data from Notion. It sends a POST
|
19
|
+
# request to the Notion API to query the specified database and returns a validated response.
|
20
|
+
#
|
21
|
+
# <br>
|
22
|
+
# <b>raises</b> <tt>Exceptions::Notion::InvalidApiKey</tt> if the API key provided is incorrect or invalid.
|
23
|
+
#
|
24
|
+
# <b>raises</b> <tt>Exceptions::Notion::InvalidDatabaseId</tt> if the Database id provided is incorrect
|
25
|
+
# or invalid.
|
26
|
+
#
|
27
|
+
def fetch
|
28
|
+
url = "#{config[:base_url]}/v1/databases/#{config[:database_id]}/query"
|
29
|
+
|
30
|
+
httparty_response = HTTParty.post(url, { body: config[:filter].to_json, headers: headers })
|
31
|
+
|
32
|
+
notion_response = Fetcher::Notion::Types::Response.new(httparty_response)
|
33
|
+
|
34
|
+
Fetcher::Notion::Helper.validate_response(notion_response)
|
35
|
+
end
|
36
|
+
|
37
|
+
private
|
38
|
+
|
39
|
+
def headers
|
40
|
+
{
|
41
|
+
"Authorization" => "Bearer #{config[:secret]}",
|
42
|
+
"Content-Type" => "application/json",
|
43
|
+
"Notion-Version" => "2022-06-28"
|
44
|
+
}
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
@@ -0,0 +1,26 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Fetcher
|
4
|
+
module Notion
|
5
|
+
module Types
|
6
|
+
##
|
7
|
+
# Represents a response received from the Notion 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_code, :message, :results
|
11
|
+
|
12
|
+
def initialize(response)
|
13
|
+
if response["results"].nil?
|
14
|
+
@status_code = response["status"]
|
15
|
+
@message = response["message"]
|
16
|
+
@results = nil
|
17
|
+
else
|
18
|
+
@status_code = 200
|
19
|
+
@message = "success"
|
20
|
+
@results = response["results"]
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
@@ -0,0 +1,29 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative "../domain/exceptions/function_not_implemented"
|
4
|
+
|
5
|
+
module Formatter
|
6
|
+
##
|
7
|
+
# The Formatter::Base module serves as the foundation for implementing specific data presentation logic
|
8
|
+
# within the Formatter module. Defines essential methods, that provide a blueprint for creating custom
|
9
|
+
# formatters tailored to different use cases.
|
10
|
+
#
|
11
|
+
module Base
|
12
|
+
# A method meant to give an specified format depending on the implementation to the data coming from an
|
13
|
+
# implementation of the Mapper::Base interface.
|
14
|
+
# Must be overridden by subclasses, with specific logic based on the use case.
|
15
|
+
#
|
16
|
+
# <br>
|
17
|
+
# <b>Params:</b>
|
18
|
+
# * <tt>List<Domain::></tt> domain_data: List of specific domain objects depending on the use case.
|
19
|
+
#
|
20
|
+
# <br>
|
21
|
+
# <b>raises</b> <tt>Domain::Exceptions::FunctionNotImplemented</tt> when missing implementation.
|
22
|
+
#
|
23
|
+
# <b>returns</b> <tt>String</tt> Formatted payload suitable for a Dispatcher::Base implementation.
|
24
|
+
#
|
25
|
+
def format(_domain_data)
|
26
|
+
raise Domain::Exceptions::FunctionNotImplemented
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
@@ -0,0 +1,43 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative "../../domain/birthday"
|
4
|
+
require_relative "../base"
|
5
|
+
require_relative "./exceptions/invalid_data"
|
6
|
+
|
7
|
+
module Formatter
|
8
|
+
module Discord
|
9
|
+
##
|
10
|
+
# This class implementats the methods of the Formatter::Base module, specifically designed for formatting birthday
|
11
|
+
# data in a way suitable for Discord messages.
|
12
|
+
class Birthday
|
13
|
+
include Base
|
14
|
+
|
15
|
+
# Implements the logic for building a formatted payload with the given template for birthdays.
|
16
|
+
#
|
17
|
+
# <br>
|
18
|
+
# <b>Params:</b>
|
19
|
+
# * <tt>List<Domain::Birthday></tt> birthdays_list: list of mapped birthdays.
|
20
|
+
#
|
21
|
+
# <br>
|
22
|
+
# <b>raises</b> <tt>Formatter::Discord::Exceptions::InvalidData</tt> when invalid data is provided.
|
23
|
+
#
|
24
|
+
# <br>
|
25
|
+
# <b>returns</b> <tt>String</tt> payload: formatted payload suitable for a Discord message.
|
26
|
+
#
|
27
|
+
def format(birthdays_list)
|
28
|
+
raise Formatter::Discord::Exceptions::InvalidData unless birthdays_list.all? do |brithday|
|
29
|
+
brithday.is_a?(Domain::Birthday)
|
30
|
+
end
|
31
|
+
|
32
|
+
template = "NAME, Wishing you a very happy birthday! Enjoy your special day! :birthday: :gift:"
|
33
|
+
payload = ""
|
34
|
+
|
35
|
+
birthdays_list.each do |birthday|
|
36
|
+
payload += "#{template.gsub("NAME", birthday.individual_name)}\n"
|
37
|
+
end
|
38
|
+
|
39
|
+
payload
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Formatter
|
4
|
+
module Discord
|
5
|
+
module Exceptions
|
6
|
+
##
|
7
|
+
# Provides a domain-specific representation for errors that occurs when trying to process invalid
|
8
|
+
# data on a Fetcher::Base implementation
|
9
|
+
#
|
10
|
+
class InvalidData < StandardError
|
11
|
+
def initialize(message = "")
|
12
|
+
super(message)
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
@@ -0,0 +1,52 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative "../../domain/pto"
|
4
|
+
require_relative "../base"
|
5
|
+
|
6
|
+
module Formatter
|
7
|
+
module Discord
|
8
|
+
##
|
9
|
+
# This class is an implementation of the Formatter::Base interface, specifically designed for formatting PTO
|
10
|
+
# data in a way suitable for Discord messages.
|
11
|
+
class Pto
|
12
|
+
include Base
|
13
|
+
|
14
|
+
# Implements the logic for building a formatted payload with the given template for PTO's.
|
15
|
+
#
|
16
|
+
# <br>
|
17
|
+
# <b>Params:</b>
|
18
|
+
# * <tt>List<Domain::Pto></tt> pto_list: List of mapped PTO's.
|
19
|
+
#
|
20
|
+
# <br>
|
21
|
+
# <b>raises</b> <tt>Formatter::Discord::Exceptions::InvalidData</tt> when invalid data is provided.
|
22
|
+
#
|
23
|
+
# <br>
|
24
|
+
# <b>returns</b> <tt>String</tt> payload, formatted payload suitable for a Discord message.
|
25
|
+
#
|
26
|
+
def format(ptos_list)
|
27
|
+
raise Formatter::Discord::Exceptions::InvalidData unless ptos_list.all? { |pto| pto.is_a?(Domain::Pto) }
|
28
|
+
|
29
|
+
template = ":beach: NAME is on PTO"
|
30
|
+
payload = ""
|
31
|
+
|
32
|
+
ptos_list.each do |pto|
|
33
|
+
payload += "#{template.gsub("NAME", pto.individual_name)} #{build_pto_message(pto)}\n"
|
34
|
+
end
|
35
|
+
|
36
|
+
payload
|
37
|
+
end
|
38
|
+
|
39
|
+
private
|
40
|
+
|
41
|
+
def build_pto_message(pto)
|
42
|
+
if pto.start_date.include?("|")
|
43
|
+
start_time = pto.start_date.split("|")
|
44
|
+
end_time = pto.end_date.split("|")
|
45
|
+
"#{start_time[1]} - #{end_time[1]}"
|
46
|
+
else
|
47
|
+
"all day"
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
@@ -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,76 @@
|
|
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 Birthday
|
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::Notion::Types::Response</tt> notion_response: Notion response object.
|
19
|
+
#
|
20
|
+
# <br>
|
21
|
+
# <b>return</b> <tt>List<Domain::Birthday></tt> birthdays_list, mapped birthdays to be used by a
|
22
|
+
# Formatter::Base implementation.
|
23
|
+
#
|
24
|
+
def map(notion_response)
|
25
|
+
return [] if notion_response.results.empty?
|
26
|
+
|
27
|
+
normalized_notion_data = normalize_response(notion_response.results)
|
28
|
+
|
29
|
+
normalized_notion_data.map do |birthday|
|
30
|
+
Domain::Birthday.new(birthday["name"], birthday["birth_date"])
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
private
|
35
|
+
|
36
|
+
def normalize_response(results)
|
37
|
+
return [] if results.nil?
|
38
|
+
|
39
|
+
normalized_results = []
|
40
|
+
|
41
|
+
results.map do |value|
|
42
|
+
properties = value["properties"]
|
43
|
+
properties.delete("Name")
|
44
|
+
|
45
|
+
normalized_value = normalize(properties)
|
46
|
+
|
47
|
+
normalized_results.append(normalized_value)
|
48
|
+
end
|
49
|
+
|
50
|
+
normalized_results
|
51
|
+
end
|
52
|
+
|
53
|
+
def normalize(properties)
|
54
|
+
normalized_value = {}
|
55
|
+
|
56
|
+
properties.each do |k, v|
|
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
|
62
|
+
end
|
63
|
+
|
64
|
+
normalized_value
|
65
|
+
end
|
66
|
+
|
67
|
+
def extract_rich_text_field_value(data)
|
68
|
+
data["rich_text"][0]["plain_text"]
|
69
|
+
end
|
70
|
+
|
71
|
+
def extract_date_field_value(data)
|
72
|
+
data["formula"]["date"]["start"]
|
73
|
+
end
|
74
|
+
end
|
75
|
+
end
|
76
|
+
end
|