bns 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 +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,96 @@
|
|
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 Pto
|
13
|
+
include Base
|
14
|
+
|
15
|
+
# Implements the logic for shaping the results from a fetcher response.
|
16
|
+
#
|
17
|
+
# <br>
|
18
|
+
# <b>Params:</b>
|
19
|
+
# * <tt>Fetcher::Notion::Types::Response</tt> notion_response: Notion response object.
|
20
|
+
#
|
21
|
+
# <br>
|
22
|
+
# <b>returns</b> <tt>List<Domain::Pto></tt> ptos_list, mapped PTO's to be used by a Formatter::Base
|
23
|
+
# implementation.
|
24
|
+
#
|
25
|
+
def map(notion_response)
|
26
|
+
return [] if notion_response.results.empty?
|
27
|
+
|
28
|
+
normalized_notion_data = normalize_response(notion_response.results)
|
29
|
+
normalized_notion_data.map do |pto|
|
30
|
+
Domain::Pto.new(pto["name"], format_date(pto["start"]), format_date(pto["end"]))
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
private
|
35
|
+
|
36
|
+
def normalize_response(response)
|
37
|
+
return [] if response.nil?
|
38
|
+
|
39
|
+
normalized_response = []
|
40
|
+
|
41
|
+
response.map do |value|
|
42
|
+
properties = value["properties"]
|
43
|
+
properties.delete("Name")
|
44
|
+
|
45
|
+
normalized_value = normalize(properties)
|
46
|
+
|
47
|
+
normalized_response.append(normalized_value)
|
48
|
+
end
|
49
|
+
|
50
|
+
normalized_response
|
51
|
+
end
|
52
|
+
|
53
|
+
def normalize(properties)
|
54
|
+
normalized_value = {}
|
55
|
+
|
56
|
+
properties.each do |k, v|
|
57
|
+
extract_pto_fields(k, v, normalized_value)
|
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)
|
72
|
+
end
|
73
|
+
end
|
74
|
+
|
75
|
+
def extract_person_field_value(data)
|
76
|
+
data["people"][0]["name"]
|
77
|
+
end
|
78
|
+
|
79
|
+
def extract_date_field_value(data)
|
80
|
+
data["date"]["start"]
|
81
|
+
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
|
+
end
|
95
|
+
end
|
96
|
+
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
|
@@ -0,0 +1,150 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative "../fetcher/notion/birthday"
|
4
|
+
require_relative "../mapper/notion/birthday"
|
5
|
+
require_relative "../formatter/discord/birthday"
|
6
|
+
|
7
|
+
require_relative "../fetcher/notion/pto"
|
8
|
+
require_relative "../mapper/notion/pto"
|
9
|
+
require_relative "../formatter/discord/pto"
|
10
|
+
|
11
|
+
require_relative "../dispatcher/discord/implementation"
|
12
|
+
require_relative "use_case"
|
13
|
+
require_relative "./types/config"
|
14
|
+
|
15
|
+
##
|
16
|
+
# This module provides factory methods for use cases within the system. Each method
|
17
|
+
# represents a use case implementation introduced in the system.
|
18
|
+
#
|
19
|
+
module UseCases
|
20
|
+
# Provides an instance of the Birthdays notifications from Notion to Discord use case implementation.
|
21
|
+
#
|
22
|
+
# <b>Example</b>
|
23
|
+
#
|
24
|
+
# "filter": {
|
25
|
+
# "or": [
|
26
|
+
# {
|
27
|
+
# "property": "BD_this_year",
|
28
|
+
# "date": {
|
29
|
+
# "equals": today
|
30
|
+
# }
|
31
|
+
# }
|
32
|
+
# ]
|
33
|
+
# },
|
34
|
+
# "sorts": []
|
35
|
+
# }
|
36
|
+
#
|
37
|
+
# options = {
|
38
|
+
# fetch_options: {
|
39
|
+
# base_url: "https://api.notion.com",
|
40
|
+
# database_id: NOTION_DATABASE_ID,
|
41
|
+
# secret: NOTION_API_INTEGRATION_SECRET,
|
42
|
+
# filter: filter
|
43
|
+
# },
|
44
|
+
# dispatch_options: {
|
45
|
+
# webhook: "https://discord.com/api/webhooks/1199213527672565760/KmpoIzBet9xYG16oFh8W1RWHbpIqT7UtTBRrhfLcvWZdNiVZCTM-gpil2Qoy4eYEgpdf",
|
46
|
+
# name: "Birthday Bot"
|
47
|
+
# }
|
48
|
+
# }
|
49
|
+
#
|
50
|
+
# use_case = UseCases.notify_birthday_from_notion_to_discord(options)
|
51
|
+
# use_case.perform
|
52
|
+
#
|
53
|
+
# #################################################################################
|
54
|
+
#
|
55
|
+
# Requirements:
|
56
|
+
# * Notion database ID, from a database with the following structure:
|
57
|
+
#
|
58
|
+
# _________________________________________________________________________________
|
59
|
+
# | Complete Name (text) | BD_this_year (formula) | BD (date) |
|
60
|
+
# | -------------------- | --------------------------- | ------------------------ |
|
61
|
+
# | John Doe | January 24, 2024 | January 24, 2000 |
|
62
|
+
# | Jane Doe | June 20, 2024 | June 20, 2000 |
|
63
|
+
# ---------------------------------------------------------------------------------
|
64
|
+
# With the following formula for the BD_this_year column:
|
65
|
+
# dateAdd(prop("BD"), year(now()) - year(prop("BD")), "years")
|
66
|
+
#
|
67
|
+
# * A Notion secret, which can be obtained, by creating an integration here: `https://developers.notion.com/`,
|
68
|
+
# browsing on the <View my integations> option, and selecting the <New Integration> or <Create new>
|
69
|
+
# integration** buttons.
|
70
|
+
# * A webhook key, which can be generated directly on discrod on the desired channel, following this instructions:
|
71
|
+
# https://support.discord.com/hc/en-us/articles/228383668-Intro-to-Webhooks
|
72
|
+
#
|
73
|
+
def self.notify_birthday_from_notion_to_discord(options)
|
74
|
+
fetcher = Fetcher::Notion::Birthday.new(options[:fetch_options])
|
75
|
+
mapper = Mapper::Notion::Birthday.new
|
76
|
+
formatter = Formatter::Discord::Birthday.new
|
77
|
+
dispatcher = Dispatcher::Discord::Implementation.new(options[:dispatch_options])
|
78
|
+
use_case_cofig = UseCases::Types::Config.new(fetcher, mapper, formatter, dispatcher)
|
79
|
+
|
80
|
+
UseCases::UseCase.new(use_case_cofig)
|
81
|
+
end
|
82
|
+
|
83
|
+
# Provides an instance of the PTO notifications from Notion to Discord use case implementation.
|
84
|
+
#
|
85
|
+
# <br>
|
86
|
+
# <b>Example</b>
|
87
|
+
#
|
88
|
+
# "filter": {
|
89
|
+
# "and": [
|
90
|
+
# {
|
91
|
+
# property: "Desde?",
|
92
|
+
# date: {
|
93
|
+
# "on_or_before": today
|
94
|
+
# }
|
95
|
+
# },
|
96
|
+
# {s
|
97
|
+
# property: "Hasta?",
|
98
|
+
# date: {
|
99
|
+
# "on_or_after": today
|
100
|
+
# }
|
101
|
+
# }
|
102
|
+
# ]
|
103
|
+
# },
|
104
|
+
# "sorts": []
|
105
|
+
# }
|
106
|
+
#
|
107
|
+
# options = {
|
108
|
+
# fetch_options: {
|
109
|
+
# base_url: "https://api.notion.com",
|
110
|
+
# database_id: NOTION_DATABASE_ID,
|
111
|
+
# secret: NOTION_API_INTEGRATION_SECRET,
|
112
|
+
# filter: filter
|
113
|
+
# },
|
114
|
+
# dispatch_options: {
|
115
|
+
# webhook: "https://discord.com/api/webhooks/1199213527672565760/KmpoIzBet9xYG16oFh8W1RWHbpIqT7UtTBRrhfLcvWZdNiVZCTM-gpil2Qoy4eYEgpdf",
|
116
|
+
# name: "Pto Bot"
|
117
|
+
# }
|
118
|
+
# }
|
119
|
+
#
|
120
|
+
# use_case = UseCases.notify_pto_from_notion_to_discord(options)
|
121
|
+
# use_case.perform
|
122
|
+
#
|
123
|
+
# #################################################################################
|
124
|
+
#
|
125
|
+
# Requirements:
|
126
|
+
# * Notion database ID, from a database with the following structure:
|
127
|
+
#
|
128
|
+
# ________________________________________________________________________________________________________
|
129
|
+
# | Person (person) | Desde? (date) | Hasta? (date) |
|
130
|
+
# | -------------------- | --------------------------------------- | ------------------------------------ |
|
131
|
+
# | John Doe | January 24, 2024 | January 27, 2024 |
|
132
|
+
# | Jane Doe | November 11, 2024 2:00 PM | November 11, 2024 6:00 PM |
|
133
|
+
# ---------------------------------------------------------------------------------------------------------
|
134
|
+
#
|
135
|
+
# * A Notion secret, which can be obtained, by creating an integration here: `https://developers.notion.com/`,
|
136
|
+
# browsing on the <View my integations> option, and selecting the <New Integration> or <Create new>
|
137
|
+
# integration** buttons.
|
138
|
+
# * A webhook key, which can be generated directly on discrod on the desired channel, following this instructions:
|
139
|
+
# https://support.discord.com/hc/en-us/articles/228383668-Intro-to-Webhooks
|
140
|
+
#
|
141
|
+
def self.notify_pto_from_notion_to_discord(options)
|
142
|
+
fetcher = Fetcher::Notion::Pto.new(options[:fetch_options])
|
143
|
+
mapper = Mapper::Notion::Pto.new
|
144
|
+
formatter = Formatter::Discord::Pto.new
|
145
|
+
dispatcher = Dispatcher::Discord::Implementation.new(options[:dispatch_options])
|
146
|
+
use_case_cofig = UseCases::Types::Config.new(fetcher, mapper, formatter, dispatcher)
|
147
|
+
|
148
|
+
UseCases::UseCase.new(use_case_cofig)
|
149
|
+
end
|
150
|
+
end
|
data/lib/bns/version.rb
ADDED
data/lib/bns.rb
ADDED
metadata
ADDED
@@ -0,0 +1,84 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: bns
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.1.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- kommitters Open Source
|
8
|
+
autorequire:
|
9
|
+
bindir: exe
|
10
|
+
cert_chain: []
|
11
|
+
date: 2024-02-06 00:00:00.000000000 Z
|
12
|
+
dependencies: []
|
13
|
+
description: A versatile business notification system offering key components for
|
14
|
+
building various use cases. It provides an easy-to-use tool for implementing
|
15
|
+
notifications without excessive complexity.
|
16
|
+
email:
|
17
|
+
- oss@kommit.co
|
18
|
+
executables: []
|
19
|
+
extensions: []
|
20
|
+
extra_rdoc_files: []
|
21
|
+
files:
|
22
|
+
- ".rspec"
|
23
|
+
- ".rubocop.yml"
|
24
|
+
- CHANGELOG.md
|
25
|
+
- CODE_OF_CONDUCT.md
|
26
|
+
- CONTRIBUTING.md
|
27
|
+
- Gemfile
|
28
|
+
- Gemfile.lock
|
29
|
+
- LICENSE
|
30
|
+
- README.md
|
31
|
+
- Rakefile
|
32
|
+
- lib/bns.rb
|
33
|
+
- lib/bns/dispatcher/base.rb
|
34
|
+
- lib/bns/dispatcher/discord/exceptions/invalid_webhook_token.rb
|
35
|
+
- lib/bns/dispatcher/discord/implementation.rb
|
36
|
+
- lib/bns/dispatcher/discord/types/response.rb
|
37
|
+
- lib/bns/domain/birthday.rb
|
38
|
+
- lib/bns/domain/exceptions/function_not_implemented.rb
|
39
|
+
- lib/bns/domain/pto.rb
|
40
|
+
- lib/bns/fetcher/base.rb
|
41
|
+
- lib/bns/fetcher/notion/birthday.rb
|
42
|
+
- lib/bns/fetcher/notion/exceptions/invalid_api_key.rb
|
43
|
+
- lib/bns/fetcher/notion/exceptions/invalid_database_id.rb
|
44
|
+
- lib/bns/fetcher/notion/helper.rb
|
45
|
+
- lib/bns/fetcher/notion/pto.rb
|
46
|
+
- lib/bns/fetcher/notion/types/response.rb
|
47
|
+
- lib/bns/formatter/base.rb
|
48
|
+
- lib/bns/formatter/discord/birthday.rb
|
49
|
+
- lib/bns/formatter/discord/exceptions/invalid_data.rb
|
50
|
+
- lib/bns/formatter/discord/pto.rb
|
51
|
+
- lib/bns/mapper/base.rb
|
52
|
+
- lib/bns/mapper/notion/birthday.rb
|
53
|
+
- lib/bns/mapper/notion/pto.rb
|
54
|
+
- lib/bns/use_cases/types/config.rb
|
55
|
+
- lib/bns/use_cases/use_case.rb
|
56
|
+
- lib/bns/use_cases/use_cases.rb
|
57
|
+
- lib/bns/version.rb
|
58
|
+
- sig/business_notification_system.rbs
|
59
|
+
homepage: https://github.com/kommitters/bns
|
60
|
+
licenses:
|
61
|
+
- MIT
|
62
|
+
metadata:
|
63
|
+
homepage_uri: https://github.com/kommitters/bns
|
64
|
+
source_code_uri: https://github.com/kommitters/bns
|
65
|
+
post_install_message:
|
66
|
+
rdoc_options: []
|
67
|
+
require_paths:
|
68
|
+
- lib
|
69
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
70
|
+
requirements:
|
71
|
+
- - ">="
|
72
|
+
- !ruby/object:Gem::Version
|
73
|
+
version: 2.6.0
|
74
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
75
|
+
requirements:
|
76
|
+
- - ">="
|
77
|
+
- !ruby/object:Gem::Version
|
78
|
+
version: '0'
|
79
|
+
requirements: []
|
80
|
+
rubygems_version: 3.5.3
|
81
|
+
signing_key:
|
82
|
+
specification_version: 4
|
83
|
+
summary: BNS - Business notification system
|
84
|
+
test_files: []
|