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.
Files changed (39) hide show
  1. checksums.yaml +7 -0
  2. data/.rspec +3 -0
  3. data/.rubocop.yml +14 -0
  4. data/CHANGELOG.md +11 -0
  5. data/CODE_OF_CONDUCT.md +132 -0
  6. data/CONTRIBUTING.md +66 -0
  7. data/Gemfile +18 -0
  8. data/Gemfile.lock +91 -0
  9. data/LICENSE +21 -0
  10. data/README.md +198 -0
  11. data/Rakefile +12 -0
  12. data/lib/bns/dispatcher/base.rb +31 -0
  13. data/lib/bns/dispatcher/discord/exceptions/invalid_webhook_token.rb +16 -0
  14. data/lib/bns/dispatcher/discord/implementation.rb +51 -0
  15. data/lib/bns/dispatcher/discord/types/response.rb +22 -0
  16. data/lib/bns/domain/birthday.rb +23 -0
  17. data/lib/bns/domain/exceptions/function_not_implemented.rb +18 -0
  18. data/lib/bns/domain/pto.rb +26 -0
  19. data/lib/bns/fetcher/base.rb +30 -0
  20. data/lib/bns/fetcher/notion/birthday.rb +53 -0
  21. data/lib/bns/fetcher/notion/exceptions/invalid_api_key.rb +15 -0
  22. data/lib/bns/fetcher/notion/exceptions/invalid_database_id.rb +15 -0
  23. data/lib/bns/fetcher/notion/helper.rb +21 -0
  24. data/lib/bns/fetcher/notion/pto.rb +48 -0
  25. data/lib/bns/fetcher/notion/types/response.rb +26 -0
  26. data/lib/bns/formatter/base.rb +29 -0
  27. data/lib/bns/formatter/discord/birthday.rb +43 -0
  28. data/lib/bns/formatter/discord/exceptions/invalid_data.rb +17 -0
  29. data/lib/bns/formatter/discord/pto.rb +52 -0
  30. data/lib/bns/mapper/base.rb +30 -0
  31. data/lib/bns/mapper/notion/birthday.rb +76 -0
  32. data/lib/bns/mapper/notion/pto.rb +96 -0
  33. data/lib/bns/use_cases/types/config.rb +19 -0
  34. data/lib/bns/use_cases/use_case.rb +39 -0
  35. data/lib/bns/use_cases/use_cases.rb +150 -0
  36. data/lib/bns/version.rb +6 -0
  37. data/lib/bns.rb +9 -0
  38. data/sig/business_notification_system.rbs +4 -0
  39. 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
@@ -0,0 +1,6 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Bns
4
+ # Gem version
5
+ VERSION = "0.1.0"
6
+ end
data/lib/bns.rb ADDED
@@ -0,0 +1,9 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "bns/version"
4
+ require_relative "bns/use_cases/use_cases"
5
+
6
+ module Bns # rubocop:disable Style/Documentation
7
+ include UseCases
8
+ class Error < StandardError; end
9
+ end
@@ -0,0 +1,4 @@
1
+ module BusinessNotificationSystem
2
+ VERSION: String
3
+ # See the writing guide of rbs: https://github.com/ruby/rbs#guides
4
+ end
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: []