bas 1.5.3 → 1.6.1

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 (49) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +6 -0
  3. data/README.md +92 -50
  4. data/lib/bas/bot/base.rb +44 -52
  5. data/lib/bas/shared_storage/base.rb +35 -0
  6. data/lib/bas/shared_storage/default.rb +18 -0
  7. data/lib/bas/shared_storage/postgres.rb +94 -0
  8. data/lib/bas/shared_storage/types/read.rb +22 -0
  9. data/lib/bas/utils/openai/run_assistant.rb +1 -0
  10. data/lib/bas/utils/postgres/request.rb +3 -1
  11. data/lib/bas/version.rb +1 -1
  12. metadata +8 -41
  13. data/lib/bas/bot/compare_wip_limit_count.rb +0 -92
  14. data/lib/bas/bot/create_work_item.rb +0 -142
  15. data/lib/bas/bot/fetch_billing_from_digital_ocean.rb +0 -87
  16. data/lib/bas/bot/fetch_birthdays_from_notion.rb +0 -128
  17. data/lib/bas/bot/fetch_domain_services_from_notion.rb +0 -93
  18. data/lib/bas/bot/fetch_domains_wip_counts_from_notion.rb +0 -121
  19. data/lib/bas/bot/fetch_domains_wip_limit_from_notion.rb +0 -134
  20. data/lib/bas/bot/fetch_emails_from_imap.rb +0 -99
  21. data/lib/bas/bot/fetch_github_issues.rb +0 -147
  22. data/lib/bas/bot/fetch_images_from_discord.rb +0 -78
  23. data/lib/bas/bot/fetch_media_from_notion.rb +0 -186
  24. data/lib/bas/bot/fetch_next_week_birthdays_from_notion.rb +0 -142
  25. data/lib/bas/bot/fetch_next_week_ptos_from_notion.rb +0 -197
  26. data/lib/bas/bot/fetch_ptos_from_notion.rb +0 -160
  27. data/lib/bas/bot/format_birthdays.rb +0 -97
  28. data/lib/bas/bot/format_do_bill_alert.rb +0 -108
  29. data/lib/bas/bot/format_emails.rb +0 -124
  30. data/lib/bas/bot/format_wip_limit_exceeded.rb +0 -97
  31. data/lib/bas/bot/garbage_collector.rb +0 -85
  32. data/lib/bas/bot/humanize_pto.rb +0 -117
  33. data/lib/bas/bot/notify_discord.rb +0 -96
  34. data/lib/bas/bot/notify_do_bill_alert_email.rb +0 -94
  35. data/lib/bas/bot/review_domain_availability.rb +0 -96
  36. data/lib/bas/bot/review_media.rb +0 -139
  37. data/lib/bas/bot/update_review_media_state.rb +0 -102
  38. data/lib/bas/bot/update_work_item.rb +0 -181
  39. data/lib/bas/bot/verify_issue_existance_in_notion.rb +0 -131
  40. data/lib/bas/bot/write_domain_review_requests.rb +0 -104
  41. data/lib/bas/bot/write_media_review_in_discord.rb +0 -98
  42. data/lib/bas/bot/write_media_review_requests.rb +0 -104
  43. data/lib/bas/read/base.rb +0 -30
  44. data/lib/bas/read/default.rb +0 -16
  45. data/lib/bas/read/postgres.rb +0 -44
  46. data/lib/bas/read/types/response.rb +0 -18
  47. data/lib/bas/write/base.rb +0 -31
  48. data/lib/bas/write/postgres.rb +0 -45
  49. data/lib/bas/write/postgres_update.rb +0 -49
@@ -1,142 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require_relative "./base"
4
- require_relative "../read/postgres"
5
- require_relative "../utils/notion/request"
6
- require_relative "../write/postgres"
7
-
8
- module Bot
9
- ##
10
- # The Bot::FetchNextWeekBirthdaysFromNotion class serves as a bot implementation to read next
11
- # week birthdays from a notion database and write them on a PostgresDB table with a specific format.
12
- #
13
- # <br>
14
- # <b>Example</b>
15
- #
16
- # options = {
17
- # process_options: {
18
- # database_id: "notion database id",
19
- # secret: "notion secret"
20
- # },
21
- # write_options: {
22
- # connection: {
23
- # host: "host",
24
- # port: 5432,
25
- # dbname: "bas",
26
- # user: "postgres",
27
- # password: "postgres"
28
- # },
29
- # db_table: "birthdays",
30
- # tag: "FetchNextWeekBirthdaysFromNotion"
31
- # }
32
- # }
33
- #
34
- # bot = Bot::FetchNextWeekBirthdaysFromNotion.new(options)
35
- # bot.execute
36
- #
37
- class FetchNextWeekBirthdaysFromNotion < Bot::Base
38
- DAYS_BEFORE = 7
39
-
40
- # read function to execute the PostgresDB Read component
41
- #
42
- def read
43
- reader = Read::Postgres.new(read_options.merge(conditions))
44
-
45
- reader.execute
46
- end
47
-
48
- # Process function to execute the Notion utility to fetch PTO's from the notion database
49
- #
50
- def process
51
- response = Utils::Notion::Request.execute(params)
52
-
53
- if response.code == 200
54
- birthdays_list = normalize_response(response.parsed_response["results"])
55
-
56
- { success: { birthdays: birthdays_list } }
57
- else
58
- { error: { message: response.parsed_response, status_code: response.code } }
59
- end
60
- end
61
-
62
- # Write function to execute the PostgresDB write component
63
- #
64
- def write
65
- write = Write::Postgres.new(write_options, process_response)
66
-
67
- write.execute
68
- end
69
-
70
- private
71
-
72
- def conditions
73
- {
74
- where: "archived=$1 AND tag=$2 AND stage=$3 ORDER BY inserted_at ASC",
75
- params: [false, read_options[:tag], "unprocessed"]
76
- }
77
- end
78
-
79
- def params
80
- {
81
- endpoint: "databases/#{process_options[:database_id]}/query",
82
- secret: process_options[:secret],
83
- method: "post",
84
- body:
85
- }
86
- end
87
-
88
- def body
89
- {
90
- filter: {
91
- and: [{ property: "BD_this_year", date: { equals: n_days_from_now } }] + last_edited_condition
92
- }
93
- }
94
- end
95
-
96
- def last_edited_condition
97
- return [] if read_response.inserted_at.nil?
98
-
99
- [
100
- {
101
- timestamp: "last_edited_time",
102
- last_edited_time: { on_or_after: read_response.inserted_at }
103
- }
104
- ]
105
- end
106
-
107
- def n_days_from_now
108
- date = Time.now.utc + days_in_second(days_before)
109
-
110
- date.utc.strftime("%F").to_s
111
- end
112
-
113
- def days_before
114
- process_options[:days_before] || DAYS_BEFORE
115
- end
116
-
117
- def days_in_second(days)
118
- days * 24 * 60 * 60
119
- end
120
-
121
- def normalize_response(results)
122
- return [] if results.nil?
123
-
124
- results.map do |value|
125
- birthday_fields = value["properties"]
126
-
127
- {
128
- "name" => extract_rich_text_field_value(birthday_fields["Complete Name"]),
129
- "birthday_date" => extract_date_field_value(birthday_fields["BD_this_year"])
130
- }
131
- end
132
- end
133
-
134
- def extract_rich_text_field_value(data)
135
- data["rich_text"][0]["plain_text"]
136
- end
137
-
138
- def extract_date_field_value(data)
139
- data["formula"]["date"]["start"]
140
- end
141
- end
142
- end
@@ -1,197 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require "date"
4
-
5
- require_relative "./base"
6
- require_relative "../read/default"
7
- require_relative "../utils/notion/request"
8
- require_relative "../write/postgres"
9
-
10
- module Bot
11
- ##
12
- # The Bot::FetchNextWeekPtosFromNotion class serves as a bot implementation to read next week
13
- # PTO's from a notion database and write them on a PostgresDB table with a specific format.
14
- #
15
- # <br>
16
- # <b>Example</b>
17
- #
18
- # options = {
19
- # process_options: {
20
- # database_id: "notion database id",
21
- # secret: "notion secret"
22
- # },
23
- # write_options: {
24
- # connection: {
25
- # host: "host",
26
- # port: 5432,
27
- # dbname: "bas",
28
- # user: "postgres",
29
- # password: "postgres"
30
- # },
31
- # db_table: "pto",
32
- # tag: "FetchNextWeekPtosFromNotion"
33
- # }
34
- # }
35
- #
36
- # bot = Bot::FetchNextWeekPtosFromNotion.new(options)
37
- # bot.execute
38
- #
39
- class FetchNextWeekPtosFromNotion < Bot::Base # rubocop:disable Metrics/ClassLength
40
- # Read function to execute the default Read component
41
- #
42
- def read
43
- reader = Read::Default.new
44
-
45
- reader.execute
46
- end
47
-
48
- # Process function to execute the Notion utility to fetch next week PTO's from the notion database
49
- #
50
- def process
51
- response = Utils::Notion::Request.execute(params)
52
-
53
- if response.code == 200
54
- ptos_list = normalize_response(response.parsed_response["results"])
55
-
56
- { success: { ptos: ptos_list } }
57
- else
58
- { error: { message: response.parsed_response, status_code: response.code } }
59
- end
60
- end
61
-
62
- # Write function to execute the PostgresDB write component
63
- #
64
- def write
65
- write = Write::Postgres.new(write_options, process_response)
66
-
67
- write.execute
68
- end
69
-
70
- private
71
-
72
- def params
73
- {
74
- endpoint: "databases/#{process_options[:database_id]}/query",
75
- secret: process_options[:secret],
76
- method: "post",
77
- body:
78
- }
79
- end
80
-
81
- def body
82
- monday, sunday = next_week_dates
83
-
84
- {
85
- filter: {
86
- or: [
87
- belong_next_week("StartDateTime", monday, sunday),
88
- belong_next_week("EndDateTime", monday, sunday),
89
- cover_next_week(monday, sunday)
90
- ]
91
- }
92
- }
93
- end
94
-
95
- def next_week_dates
96
- monday = next_week_monday
97
- sunday = monday + 6
98
-
99
- [monday, sunday]
100
- end
101
-
102
- def next_week_monday
103
- today = Date.today
104
- week_day = today.wday
105
-
106
- days = week_day.zero? ? 1 : 8 - week_day
107
-
108
- today + days
109
- end
110
-
111
- def belong_next_week(property, after_day, before_day)
112
- {
113
- and: [
114
- { property:, date: { on_or_after: after_day } },
115
- { property:, date: { on_or_before: before_day } }
116
- ]
117
- }
118
- end
119
-
120
- def cover_next_week(monday, sunday)
121
- {
122
- and: [
123
- { property: "EndDateTime", date: { on_or_after: sunday } },
124
- { property: "StartDateTime", date: { on_or_before: monday } }
125
- ]
126
- }
127
- end
128
-
129
- def normalize_response(results)
130
- return [] if results.nil?
131
-
132
- results.map do |pto|
133
- pto_fields = pto["properties"]
134
-
135
- name = extract_description_field_value(pto_fields["Description"])
136
- start_date = extract_date_field_value(pto_fields["StartDateTime"])
137
- end_date = extract_date_field_value(pto_fields["EndDateTime"])
138
-
139
- description(name, start_date, end_date)
140
- end
141
- end
142
-
143
- def description(name, start_date, end_date)
144
- start = start_description(start_date)
145
- finish = end_description(end_date)
146
-
147
- "#{name} will not be working between #{start} and #{finish}. And returns the #{returns(finish)}"
148
- end
149
-
150
- def start_description(date)
151
- date[:from]
152
- end
153
-
154
- def end_description(date)
155
- return date[:from] if date[:to].nil?
156
-
157
- date[:to]
158
- end
159
-
160
- def returns(date)
161
- date.include?("T12") ? "#{date} in the afternoon" : next_work_day(date)
162
- end
163
-
164
- def next_work_day(date)
165
- datetime = DateTime.parse(date)
166
-
167
- return_day = case datetime.wday
168
- when 5 then datetime + 3
169
- when 6 then datetime + 2
170
- else datetime + 1
171
- end
172
-
173
- return_day.strftime("%A %B %d of %Y").to_s
174
- end
175
-
176
- def extract_description_field_value(data)
177
- names = data["title"].map { |name| name["plain_text"] }
178
-
179
- names.join(" ")
180
- end
181
-
182
- def extract_date_field_value(date)
183
- {
184
- from: extract_start_date(date),
185
- to: extract_end_date(date)
186
- }
187
- end
188
-
189
- def extract_start_date(data)
190
- data["date"]["start"]
191
- end
192
-
193
- def extract_end_date(data)
194
- data["date"]["end"]
195
- end
196
- end
197
- end
@@ -1,160 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require "date"
4
-
5
- require_relative "./base"
6
- require_relative "../read/default"
7
- require_relative "../utils/notion/request"
8
- require_relative "../write/postgres"
9
-
10
- module Bot
11
- ##
12
- # The Bot::FetchPtosFromNotion class serves as a bot implementation to read PTO's from a
13
- # notion database and write them on a PostgresDB table with a specific format.
14
- #
15
- # <br>
16
- # <b>Example</b>
17
- #
18
- # options = {
19
- # process_options: {
20
- # database_id: "notion database id",
21
- # secret: "notion secret"
22
- # },
23
- # write_options: {
24
- # connection: {
25
- # host: "host",
26
- # port: 5432,
27
- # dbname: "bas",
28
- # user: "postgres",
29
- # password: "postgres"
30
- # },
31
- # db_table: "pto",
32
- # tag: "FetchPtosFromNotion"
33
- # }
34
- # }
35
- #
36
- # bot = Bot::FetchPtosFromNotion.new(options)
37
- # bot.execute
38
- #
39
- class FetchPtosFromNotion < Bot::Base
40
- # Read function to execute the default Read component
41
- #
42
- def read
43
- reader = Read::Default.new
44
-
45
- reader.execute
46
- end
47
-
48
- # Process function to execute the Notion utility to fetch PTO's from the notion database
49
- #
50
- def process
51
- response = Utils::Notion::Request.execute(params)
52
-
53
- if response.code == 200
54
- ptos_list = normalize_response(response.parsed_response["results"])
55
-
56
- { success: { ptos: ptos_list } }
57
- else
58
- { error: { message: response.parsed_response, status_code: response.code } }
59
- end
60
- end
61
-
62
- # Write function to execute the PostgresDB write component
63
- #
64
- def write
65
- write = Write::Postgres.new(write_options, process_response)
66
-
67
- write.execute
68
- end
69
-
70
- private
71
-
72
- def params
73
- {
74
- endpoint: "databases/#{process_options[:database_id]}/query",
75
- secret: process_options[:secret],
76
- method: "post",
77
- body: { filter: today_condition }
78
- }
79
- end
80
-
81
- def today_condition
82
- today = Time.now.utc.strftime("%F").to_s
83
-
84
- {
85
- "and": [
86
- { property: "StartDateTime", date: { on_or_before: today } },
87
- { property: "EndDateTime", date: { on_or_after: today } }
88
- ]
89
- }
90
- end
91
-
92
- def normalize_response(results)
93
- return [] if results.nil?
94
-
95
- results.map do |pto|
96
- pto_fields = pto["properties"]
97
-
98
- name = extract_description_field_value(pto_fields["Description"])
99
- start_date = extract_date_field_value(pto_fields["StartDateTime"])
100
- end_date = extract_date_field_value(pto_fields["EndDateTime"])
101
-
102
- description(name, start_date, end_date)
103
- end
104
- end
105
-
106
- def description(name, start_date, end_date)
107
- start = start_description(start_date)
108
- finish = end_description(end_date)
109
-
110
- "#{name} will not be working between #{start} and #{finish}. And returns the #{returns(finish)}"
111
- end
112
-
113
- def start_description(date)
114
- date[:from]
115
- end
116
-
117
- def end_description(date)
118
- return date[:from] if date[:to].nil?
119
-
120
- date[:to]
121
- end
122
-
123
- def returns(date)
124
- date.include?("T12") ? "#{date} in the afternoon" : next_work_day(date)
125
- end
126
-
127
- def next_work_day(date)
128
- datetime = DateTime.parse(date)
129
-
130
- return_day = case datetime.wday
131
- when 5 then datetime + 3
132
- when 6 then datetime + 2
133
- else datetime + 1
134
- end
135
-
136
- return_day.strftime("%A %B %d of %Y").to_s
137
- end
138
-
139
- def extract_description_field_value(data)
140
- names = data["title"].map { |name| name["plain_text"] }
141
-
142
- names.join(" ")
143
- end
144
-
145
- def extract_date_field_value(date)
146
- {
147
- from: extract_start_date(date),
148
- to: extract_end_date(date)
149
- }
150
- end
151
-
152
- def extract_start_date(data)
153
- data["date"]["start"]
154
- end
155
-
156
- def extract_end_date(data)
157
- data["date"]["end"]
158
- end
159
- end
160
- end
@@ -1,97 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require_relative "./base"
4
- require_relative "../read/postgres"
5
- require_relative "../write/postgres"
6
-
7
- module Bot
8
- ##
9
- # The Bot::FormatBirthdays class serves as a bot implementation to read birthdays from a
10
- # PostgresDB database, format them with a specific template, and write them on a PostgresDB
11
- # table with a specific format.
12
- #
13
- # <br>
14
- # <b>Example</b>
15
- #
16
- # options = {
17
- # read_options: {
18
- # connection: {
19
- # host: "localhost",
20
- # port: 5432,
21
- # dbname: "bas",
22
- # user: "postgres",
23
- # password: "postgres"
24
- # },
25
- # db_table: "use_cases",
26
- # tag: "FetchBirthdaysFromNotion"
27
- # },
28
- # process_options: {
29
- # template: "birthday template message"
30
- # },
31
- # write_options: {
32
- # connection: {
33
- # host: "localhost",
34
- # port: 5432,
35
- # dbname: "bas",
36
- # user: "postgres",
37
- # password: "postgres"
38
- # },
39
- # db_table: "use_cases",
40
- # tag: "FormatBirthdays"
41
- # }
42
- # }
43
- #
44
- # bot = Bot::FormatBirthdays.new(options)
45
- # bot.execute
46
- #
47
- class FormatBirthdays < Bot::Base
48
- BIRTHDAY_ATTRIBUTES = %w[name birthday_date].freeze
49
-
50
- # read function to execute the PostgresDB Read component
51
- #
52
- def read
53
- reader = Read::Postgres.new(read_options.merge(conditions))
54
-
55
- reader.execute
56
- end
57
-
58
- # Process function to format the notification using a template
59
- #
60
- def process
61
- return { success: { notification: "" } } if unprocessable_response
62
-
63
- birthdays_list = read_response.data["birthdays"]
64
-
65
- notification = birthdays_list.reduce("") do |payload, birthday|
66
- "#{payload} #{build_template(BIRTHDAY_ATTRIBUTES, birthday)} \n"
67
- end
68
-
69
- { success: { notification: } }
70
- end
71
-
72
- # Write function to execute the PostgresDB write component
73
- #
74
- def write
75
- write = Write::Postgres.new(write_options, process_response)
76
-
77
- write.execute
78
- end
79
-
80
- private
81
-
82
- def conditions
83
- {
84
- where: "archived=$1 AND tag=$2 AND stage=$3 ORDER BY inserted_at ASC",
85
- params: [false, read_options[:tag], "unprocessed"]
86
- }
87
- end
88
-
89
- def build_template(attributes, instance)
90
- template = process_options[:template]
91
-
92
- attributes.reduce(template) do |formated_template, attribute|
93
- formated_template.gsub("<#{attribute}>", instance[attribute].to_s)
94
- end
95
- end
96
- end
97
- end
@@ -1,108 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require_relative "./base"
4
- require_relative "../read/postgres"
5
- require_relative "../write/postgres"
6
-
7
- module Bot
8
- ##
9
- # The Bot::FormatDoBillAlert class serves as a bot implementation to format DigitalOcean bill
10
- # alerts from a PostgresDB database, format them with a specific template, and write them on a
11
- # PostgresDB table with a specific format.
12
- #
13
- # <br>
14
- # <b>Example</b>
15
- #
16
- # options = {
17
- # read_options: {
18
- # connection: {
19
- # host: "localhost",
20
- # port: 5432,
21
- # dbname: "bas",
22
- # user: "postgres",
23
- # password: "postgres"
24
- # },
25
- # db_table: "do_billing",
26
- # tag: "FetchBillingFromDigitalOcean"
27
- # },
28
- # process_options: {
29
- # threshold: 7
30
- # },
31
- # write_options: {
32
- # connection: {
33
- # host: "localhost",
34
- # port: 5432,
35
- # dbname: "bas",
36
- # user: "postgres",
37
- # password: "postgres"
38
- # },
39
- # db_table: "do_billing",
40
- # tag: "FormatDoBillAlert"
41
- # }
42
- # }
43
- #
44
- # bot = Bot::FormatDoBillAlert.new(options)
45
- # bot.execute
46
- #
47
- class FormatDoBillAlert < Bot::Base
48
- # read function to execute the PostgresDB Read component
49
- #
50
- def read
51
- reader = Read::Postgres.new(read_options.merge(conditions))
52
-
53
- reader.execute
54
- end
55
-
56
- # Process function to format the notification using a template
57
- #
58
- def process
59
- return { success: { notification: "" } } if unprocessable_response || !threshold_exceeded
60
-
61
- { success: { notification: message } }
62
- end
63
-
64
- # Write function to execute the PostgresDB write component
65
- #
66
- def write
67
- write = Write::Postgres.new(write_options, process_response)
68
-
69
- write.execute
70
- end
71
-
72
- private
73
-
74
- def conditions
75
- {
76
- where: "archived=$1 AND tag=$2 AND stage=$3 ORDER BY inserted_at ASC",
77
- params: [false, read_options[:tag], "unprocessed"]
78
- }
79
- end
80
-
81
- def threshold_exceeded
82
- return false if billing.zero?
83
-
84
- usage > process_options[:threshold]
85
- end
86
-
87
- def usage
88
- billing - last_billing
89
- end
90
-
91
- def billing
92
- read_response.data["billing"]["month_to_date_balance"].to_f
93
- end
94
-
95
- def last_billing
96
- read_response.data["last_billing"]["month_to_date_balance"].to_f
97
- end
98
-
99
- def message
100
- balance = billing
101
- threshold = process_options[:threshold]
102
-
103
- ":warning: The **DigitalOcean** daily usage was exceeded. \
104
- Current balance: #{balance}, Threshold: #{threshold}, \
105
- Current daily usage: #{usage.round(3)}"
106
- end
107
- end
108
- end