bas 1.5.2 → 1.6.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 (50) 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 +37 -54
  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 +95 -0
  8. data/lib/bas/shared_storage/types/read.rb +22 -0
  9. data/lib/bas/utils/discord/request.rb +15 -2
  10. data/lib/bas/utils/openai/run_assistant.rb +1 -0
  11. data/lib/bas/utils/postgres/request.rb +3 -1
  12. data/lib/bas/version.rb +1 -1
  13. metadata +8 -41
  14. data/lib/bas/bot/compare_wip_limit_count.rb +0 -92
  15. data/lib/bas/bot/create_work_item.rb +0 -142
  16. data/lib/bas/bot/fetch_billing_from_digital_ocean.rb +0 -87
  17. data/lib/bas/bot/fetch_birthdays_from_notion.rb +0 -128
  18. data/lib/bas/bot/fetch_domain_services_from_notion.rb +0 -93
  19. data/lib/bas/bot/fetch_domains_wip_counts_from_notion.rb +0 -121
  20. data/lib/bas/bot/fetch_domains_wip_limit_from_notion.rb +0 -134
  21. data/lib/bas/bot/fetch_emails_from_imap.rb +0 -99
  22. data/lib/bas/bot/fetch_github_issues.rb +0 -147
  23. data/lib/bas/bot/fetch_images_from_discord.rb +0 -78
  24. data/lib/bas/bot/fetch_media_from_notion.rb +0 -186
  25. data/lib/bas/bot/fetch_next_week_birthdays_from_notion.rb +0 -142
  26. data/lib/bas/bot/fetch_next_week_ptos_from_notion.rb +0 -197
  27. data/lib/bas/bot/fetch_ptos_from_notion.rb +0 -160
  28. data/lib/bas/bot/format_birthdays.rb +0 -97
  29. data/lib/bas/bot/format_do_bill_alert.rb +0 -108
  30. data/lib/bas/bot/format_emails.rb +0 -124
  31. data/lib/bas/bot/format_wip_limit_exceeded.rb +0 -97
  32. data/lib/bas/bot/garbage_collector.rb +0 -85
  33. data/lib/bas/bot/humanize_pto.rb +0 -117
  34. data/lib/bas/bot/notify_discord.rb +0 -96
  35. data/lib/bas/bot/notify_do_bill_alert_email.rb +0 -94
  36. data/lib/bas/bot/review_domain_availability.rb +0 -96
  37. data/lib/bas/bot/review_media.rb +0 -139
  38. data/lib/bas/bot/update_review_media_state.rb +0 -102
  39. data/lib/bas/bot/update_work_item.rb +0 -181
  40. data/lib/bas/bot/verify_issue_existance_in_notion.rb +0 -131
  41. data/lib/bas/bot/write_domain_review_requests.rb +0 -104
  42. data/lib/bas/bot/write_media_review_in_discord.rb +0 -114
  43. data/lib/bas/bot/write_media_review_requests.rb +0 -104
  44. data/lib/bas/read/base.rb +0 -30
  45. data/lib/bas/read/default.rb +0 -16
  46. data/lib/bas/read/postgres.rb +0 -44
  47. data/lib/bas/read/types/response.rb +0 -18
  48. data/lib/bas/write/base.rb +0 -31
  49. data/lib/bas/write/postgres.rb +0 -45
  50. data/lib/bas/write/postgres_update.rb +0 -49
@@ -1,124 +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::FormatEmails class serves as a bot implementation to read emails 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: "FetchEmailsFromImap"
27
- # },
28
- # process_options: {
29
- # template: "emails 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: "FormatEmails"
41
- # }
42
- # }
43
- #
44
- # bot = Bot::FormatEmails.new(options)
45
- # bot.execute
46
- #
47
- class FormatEmails < Bot::Base
48
- EMAIL_ATTRIBUTES = %w[subject sender date].freeze
49
- DEFAULT_TIME_ZONE = "+00:00"
50
-
51
- # read function to execute the PostgresDB Read component
52
- #
53
- def read
54
- reader = Read::Postgres.new(read_options.merge(conditions))
55
-
56
- reader.execute
57
- end
58
-
59
- # Process function to format the notification using a template
60
- #
61
- def process
62
- return { success: { notification: "" } } if unprocessable_response
63
-
64
- emails_list = read_response.data["emails"]
65
-
66
- notification = process_emails(emails_list).reduce("") do |payload, email|
67
- "#{payload} #{build_template(EMAIL_ATTRIBUTES, email)} \n"
68
- end
69
-
70
- { success: { notification: } }
71
- end
72
-
73
- # Write function to execute the PostgresDB write component
74
- #
75
- def write
76
- write = Write::Postgres.new(write_options, process_response)
77
-
78
- write.execute
79
- end
80
-
81
- private
82
-
83
- def conditions
84
- {
85
- where: "archived=$1 AND tag=$2 AND stage=$3 ORDER BY inserted_at ASC",
86
- params: [false, read_options[:tag], "unprocessed"]
87
- }
88
- end
89
-
90
- def process_emails(emails)
91
- emails.each do |email|
92
- date = DateTime.parse(email["date"]).to_time
93
- email["date"] = at_timezone(date)
94
- end
95
- emails.filter! { |email| email["date"] > time_window } unless process_options[:frequency].nil?
96
-
97
- format_timestamp(emails)
98
- end
99
-
100
- def format_timestamp(emails)
101
- emails.each { |email| email["date"] = email["date"].strftime("%F %r") }
102
- end
103
-
104
- def time_window
105
- date_time = Time.now - (60 * 60 * process_options[:frequency])
106
-
107
- at_timezone(date_time)
108
- end
109
-
110
- def at_timezone(date)
111
- timezone = process_options[:timezone] || DEFAULT_TIME_ZONE
112
-
113
- Time.at(date, in: timezone)
114
- end
115
-
116
- def build_template(attributes, instance)
117
- template = process_options[:template]
118
-
119
- attributes.reduce(template) do |formated_template, attribute|
120
- formated_template.gsub("<#{attribute}>", instance[attribute].to_s)
121
- end
122
- end
123
- end
124
- 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::FormatWipLimitExceeded class serves as a bot implementation to read exceeded domain wip
10
- # counts by limits from a PostgresDB database, format them with a specific template, and write them
11
- # on a 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: "use_cases",
26
- # tag: "CompareWipLimitCount"
27
- # },
28
- # process_options: {
29
- # template: "exceeded wip limit 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: "FormatWipLimitExceeded"
41
- # }
42
- # }
43
- #
44
- # bot = Bot::FormatWipLimitExceeded.new(options)
45
- # bot.execute
46
- #
47
- class FormatWipLimitExceeded < Bot::Base
48
- WIP_LIMIT_ATTRIBUTES = %w[domain exceeded].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
- exceedded_limits_list = read_response.data["exceeded_domain_count"]
64
-
65
- notification = exceedded_limits_list.reduce("") do |payload, exceedded_limit|
66
- "#{payload} #{build_template(WIP_LIMIT_ATTRIBUTES, exceedded_limit)} \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,85 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require_relative "./base"
4
- require_relative "../read/default"
5
- require_relative "../write/postgres"
6
-
7
- module Bot
8
- ##
9
- # The Bot::GarbageCollector class serves as a bot implementation to archive bot records from a
10
- # PostgresDB database table and write a response on a PostgresDB table with a specific format.
11
- #
12
- # <br>
13
- # <b>Example</b>
14
- #
15
- # options = {
16
- # process_options: {
17
- # connection: {
18
- # host: "localhost",
19
- # port: 5432,
20
- # dbname: "bas",
21
- # user: "postgres",
22
- # password: "postgres"
23
- # },
24
- # db_table: "use_cases"
25
- # },
26
- # write_options: {
27
- # connection: {
28
- # host: "localhost",
29
- # port: 5432,
30
- # dbname: "bas",
31
- # user: "postgres",
32
- # password: "postgres"
33
- # },
34
- # db_table: "use_cases"
35
- # }
36
- # }
37
- #
38
- # bot = Bot::GarbageCollector.new(options)
39
- # bot.execute
40
- #
41
- class GarbageCollector < Bot::Base
42
- SUCCESS_STATUS = "PGRES_COMMAND_OK"
43
-
44
- # Read function to execute the default Read component
45
- #
46
- def read
47
- reader = Read::Default.new
48
-
49
- reader.execute
50
- end
51
-
52
- # Process function to update records in a PostgresDB database table
53
- #
54
- def process
55
- response = Utils::Postgres::Request.execute(params)
56
-
57
- if response.res_status == SUCCESS_STATUS
58
- { success: { archived: true } }
59
- else
60
- { error: { message: response.result_error_message, status_code: response.res_status } }
61
- end
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 params
75
- {
76
- connection: process_options[:connection],
77
- query:
78
- }
79
- end
80
-
81
- def query
82
- "UPDATE #{process_options[:db_table]} SET archived=true WHERE archived=false"
83
- end
84
- end
85
- end
@@ -1,117 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require_relative "./base"
4
- require_relative "../read/postgres"
5
- require_relative "../write/postgres"
6
- require_relative "../utils/openai/run_assistant"
7
-
8
- module Bot
9
- ##
10
- # The Bot::HumanizePto class serves as a bot implementation to read PTO's from a
11
- # PostgresDb table, format them using an OpenAI Assistant with the OpenAI API, and
12
- # write the response as a notification on a PostgresDB table.
13
- #
14
- # <br>
15
- # <b>Example</b>
16
- #
17
- # options = {
18
- # read_options: {
19
- # connection: {
20
- # host: "host",
21
- # port: 5432,
22
- # dbname: "bas",
23
- # user: "postgres",
24
- # password: "postgres"
25
- # },
26
- # db_table: "pto",
27
- # tag: "FetchPtosFromNotion"
28
- # },
29
- # process_options: {
30
- # secret: "openai secret key",
31
- # assistant_id: "assistant_id",
32
- # prompt: "optional additional prompt"
33
- # },
34
- # write_options: {
35
- # connection: {
36
- # host: "host",
37
- # port: 5432,
38
- # dbname: "bas",
39
- # user: "postgres",
40
- # password: "postgres"
41
- # },
42
- # db_table: "pto",
43
- # tag: "HumanizePto"
44
- # }
45
- # }
46
- #
47
- # bot = Bot::HumanizePto.new(options)
48
- # bot.execute
49
- #
50
- class HumanizePto < Bot::Base
51
- DEFAULT_PROMPT = "{data}"
52
-
53
- # read function to execute the PostgresDB Read component
54
- #
55
- def read
56
- reader = Read::Postgres.new(read_options.merge(conditions))
57
-
58
- reader.execute
59
- end
60
-
61
- # process function to execute the OpenaAI utility to process the PTO's
62
- #
63
- def process
64
- return { success: { notification: "" } } if unprocessable_response
65
-
66
- response = Utils::OpenAI::RunAssitant.execute(params)
67
-
68
- if response.code != 200 || (!response["status"].nil? && response["status"] != "completed")
69
- return error_response(response)
70
- end
71
-
72
- sucess_response(response)
73
- end
74
-
75
- # write function to execute the PostgresDB write component
76
- #
77
- def write
78
- write = Write::Postgres.new(write_options, process_response)
79
-
80
- write.execute
81
- end
82
-
83
- private
84
-
85
- def conditions
86
- {
87
- where: "archived=$1 AND tag=$2 AND stage=$3 ORDER BY inserted_at ASC",
88
- params: [false, read_options[:tag], "unprocessed"]
89
- }
90
- end
91
-
92
- def params
93
- {
94
- assistant_id: process_options[:assistant_id],
95
- secret: process_options[:secret],
96
- prompt: build_prompt
97
- }
98
- end
99
-
100
- def build_prompt
101
- prompt = process_options[:prompt] || DEFAULT_PROMPT
102
- ptos_list = read_response.data["ptos"]
103
-
104
- ptos_list_formatted_string = ptos_list.join("\n")
105
-
106
- prompt.gsub("{data}", ptos_list_formatted_string)
107
- end
108
-
109
- def sucess_response(response)
110
- { success: { notification: response.parsed_response["data"].first["content"].first["text"]["value"] } }
111
- end
112
-
113
- def error_response(response)
114
- { error: { message: response.parsed_response, status_code: response.code } }
115
- end
116
- end
117
- end
@@ -1,96 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require_relative "./base"
4
- require_relative "../read/postgres"
5
- require_relative "../write/postgres"
6
- require_relative "../utils/discord/integration"
7
-
8
- module Bot
9
- ##
10
- # The Bot::NotifyDiscord class serves as a bot implementation to send messages to a
11
- # Discord readed from a PostgresDB table.
12
- #
13
- # <br>
14
- # <b>Example</b>
15
- #
16
- # options = {
17
- # read_options: {
18
- # connection: {
19
- # host: "host",
20
- # port: 5432,
21
- # dbname: "bas",
22
- # user: "postgres",
23
- # password: "postgres"
24
- # },
25
- # db_table: "pto",
26
- # tag: "HumanizePto"
27
- # },
28
- # process_options: {
29
- # name: "bot name to be shown on discord",
30
- # webhook: "discord webhook"
31
- # },
32
- # write_options: {
33
- # connection: {
34
- # host: "host",
35
- # port: 5432,
36
- # dbname: "bas",
37
- # user: "postgres",
38
- # password: "postgres"
39
- # },
40
- # db_table: "pto",
41
- # tag: "NotifyDiscord"
42
- # }
43
- # }
44
- #
45
- # bot = Bot::NotifyDiscord.new(options)
46
- # bot.execute
47
- #
48
- class NotifyDiscord < Bot::Base
49
- # read function to execute the PostgresDB Read component
50
- #
51
- def read
52
- reader = Read::Postgres.new(read_options.merge(conditions))
53
-
54
- reader.execute
55
- end
56
-
57
- # process function to execute the Discord utility to send the PTO's notification
58
- #
59
- def process
60
- return { success: {} } if unprocessable_response
61
-
62
- response = Utils::Discord::Integration.execute(params)
63
-
64
- if response.code == 204
65
- { success: {} }
66
- else
67
- { error: { message: response.parsed_response, status_code: response.code } }
68
- end
69
- end
70
-
71
- # write function to execute the PostgresDB write component
72
- #
73
- def write
74
- write = Write::Postgres.new(write_options, process_response)
75
-
76
- write.execute
77
- end
78
-
79
- private
80
-
81
- def conditions
82
- {
83
- where: "archived=$1 AND tag=$2 AND stage=$3 ORDER BY inserted_at ASC",
84
- params: [false, read_options[:tag], "unprocessed"]
85
- }
86
- end
87
-
88
- def params
89
- {
90
- name: process_options[:name],
91
- notification: read_response.data["notification"],
92
- webhook: process_options[:webhook]
93
- }
94
- end
95
- end
96
- end
@@ -1,94 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require_relative "./base"
4
- require_relative "../read/postgres"
5
- require_relative "../write/postgres"
6
- require_relative "../utils/google/send_email"
7
-
8
- module Bot
9
- ##
10
- # The Bot::NotifyDoBillAlertEmail class serves as a bot implementation to send digital
11
- # ocean daily bill exceeded alert emails to a recipient using a google account
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
- # refresh_token: "email server refresh token",
30
- # client_id: "email server client it",
31
- # client_secret: "email server client secret",
32
- # user_email: "sender@mail.com",
33
- # recipient_email: "recipient@mail.com",
34
- # threshold: "THRESHOLD"
35
- # },
36
- # write_options: {
37
- # connection: {
38
- # host: "localhost",
39
- # port: 5432,
40
- # dbname: "bas",
41
- # user: "postgres",
42
- # password: "postgres"
43
- # },
44
- # db_table: "do_billing",
45
- # tag: "NotifyDoBillAlertEmail"
46
- # }
47
- # }
48
- #
49
- # bot = Bot::NotifyDoBillAlertEmail.new(options)
50
- # bot.execute
51
- #
52
- class NotifyDoBillAlertEmail < Bot::Base
53
- SUBJECT = "Digital Ocean Daily Threshold Alert"
54
-
55
- # read function to execute the PostgresDB Read component
56
- #
57
- def read
58
- reader = Read::Postgres.new(read_options.merge(conditions))
59
-
60
- reader.execute
61
- end
62
-
63
- # process function to execute the Google send email utility
64
- #
65
- def process
66
- return { success: {} } if unprocessable_response
67
-
68
- response = Utils::GoogleService::SendEmail.new(params).execute
69
-
70
- response[:error].nil? ? { success: {} } : { error: response }
71
- end
72
-
73
- # write function to execute the PostgresDB write component
74
- #
75
- def write
76
- write = Write::Postgres.new(write_options, process_response)
77
-
78
- write.execute
79
- end
80
-
81
- private
82
-
83
- def conditions
84
- {
85
- where: "archived=$1 AND tag=$2 AND stage=$3 ORDER BY inserted_at ASC",
86
- params: [false, read_options[:tag], "unprocessed"]
87
- }
88
- end
89
-
90
- def params
91
- process_options.merge({ subject: SUBJECT, message: read_response.data["notification"] })
92
- end
93
- end
94
- end
@@ -1,96 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require "httparty"
4
-
5
- require_relative "./base"
6
- require_relative "../read/postgres"
7
- require_relative "../write/postgres"
8
- require_relative "../utils/openai/run_assistant"
9
-
10
- module Bot
11
- ##
12
- # The Bot::ReviewDomainAvailability class serves as a bot implementation to read from a postgres
13
- # shared storage a domain requests and review its availability.
14
- #
15
- # <br>
16
- # <b>Example</b>
17
- #
18
- # options = {
19
- # read_options: {
20
- # connection: {
21
- # host: "localhost",
22
- # port: 5432,
23
- # dbname: "bas",
24
- # user: "postgres",
25
- # password: "postgres"
26
- # },
27
- # db_table: "web_availability",
28
- # tag: "ReviewDomainRequest"
29
- # },
30
- # write_options: {
31
- # connection: {
32
- # host: "localhost",
33
- # port: 5432,
34
- # dbname: "bas",
35
- # user: "postgres",
36
- # password: "postgres"
37
- # },
38
- # db_table: "web_availability",
39
- # tag: "ReviewDomainAvailability"
40
- # }
41
- # }
42
- #
43
- # bot = Bot::ReviewDomainAvailability.new(options)
44
- # bot.execute
45
- #
46
- class ReviewDomainAvailability < Bot::Base
47
- # read function to execute the PostgresDB Read component
48
- #
49
- def read
50
- reader = Read::Postgres.new(read_options.merge(conditions))
51
-
52
- reader.execute
53
- end
54
-
55
- # process function to make a http request to the domain and check the status
56
- #
57
- def process
58
- return { success: { review: nil } } if unprocessable_response
59
-
60
- response = availability
61
-
62
- if response.code == 200
63
- { success: { review: nil } }
64
- else
65
- { success: { notification: notification(response) } }
66
- end
67
- end
68
-
69
- # write function to execute the PostgresDB write component
70
- #
71
- def write
72
- write = Write::Postgres.new(write_options, process_response)
73
-
74
- write.execute
75
- end
76
-
77
- private
78
-
79
- def conditions
80
- {
81
- where: "archived=$1 AND tag=$2 AND stage=$3 ORDER BY inserted_at ASC",
82
- params: [false, read_options[:tag], "unprocessed"]
83
- }
84
- end
85
-
86
- def availability
87
- url = read_response.data["url"]
88
-
89
- HTTParty.get(url, {})
90
- end
91
-
92
- def notification(response)
93
- ":warning: The Domain #{read_response.data["url"]} is down with an error code of #{response.code}"
94
- end
95
- end
96
- end