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,92 +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::CompareWipLimitCount class serves as a bot implementation to read domains wip limits and
10
- # counts from a PostgresDB database, compare the values to find exceeded counts, and write them on
11
- # 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: "FetchDomainsWipLimitFromNotion"
27
- # },
28
- # write_options: {
29
- # connection: {
30
- # host: "localhost",
31
- # port: 5432,
32
- # dbname: "bas",
33
- # user: "postgres",
34
- # password: "postgres"
35
- # },
36
- # db_table: "use_cases",
37
- # tag: "CompareWipLimitCount"
38
- # }
39
- # }
40
- #
41
- # bot = Bot::CompareWipLimitCount.new(options)
42
- # bot.execute
43
- #
44
- class CompareWipLimitCount < Bot::Base
45
- # read function to execute the PostgresDB Read component
46
- #
47
- def read
48
- reader = Read::Postgres.new(read_options.merge(conditions))
49
-
50
- reader.execute
51
- end
52
-
53
- # Process function to compare the domains wip counts and limits
54
- #
55
- def process
56
- return { success: { exceeded_domain_count: {} } } if unprocessable_response
57
-
58
- domains_limits = read_response.data["domains_limits"]
59
- domain_wip_count = read_response.data["domain_wip_count"]
60
-
61
- exceeded_domain_count = exceedded_counts(domains_limits, domain_wip_count)
62
-
63
- { success: { exceeded_domain_count: } }
64
- end
65
-
66
- # Write function to execute the PostgresDB write component
67
- #
68
- def write
69
- write = Write::Postgres.new(write_options, process_response)
70
-
71
- write.execute
72
- end
73
-
74
- private
75
-
76
- def conditions
77
- {
78
- where: "archived=$1 AND tag=$2 AND stage=$3 ORDER BY inserted_at ASC",
79
- params: [false, read_options[:tag], "unprocessed"]
80
- }
81
- end
82
-
83
- def exceedded_counts(limits, counts)
84
- counts.to_a.map do |domain_wip_count|
85
- domain, count = domain_wip_count
86
- domain_limit = limits[domain]
87
-
88
- { domain:, exceeded: count - domain_limit } if count > domain_limit
89
- end.compact
90
- end
91
- end
92
- end
@@ -1,142 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require "json"
4
-
5
- require_relative "./base"
6
- require_relative "../read/postgres"
7
- require_relative "../utils/notion/request"
8
- require_relative "../utils/notion/types"
9
- require_relative "../write/postgres"
10
-
11
- module Bot
12
- ##
13
- # The Bot::CreateWorkItem class serves as a bot implementation to create "work items" on a
14
- # notion database using information of a GitHub issue.
15
- #
16
- # <br>
17
- # <b>Example</b>
18
- #
19
- # options = {
20
- # read_options: {
21
- # connection: {
22
- # host: "localhost",
23
- # port: 5432,
24
- # dbname: "bas",
25
- # user: "postgres",
26
- # password: "postgres"
27
- # },
28
- # db_table: "github_issues",
29
- # tag: "CreateWorkItemRequest"
30
- # },
31
- # process_options: {
32
- # database_id: "notion database id",
33
- # secret: "notion secret",
34
- # domain: "domain association",
35
- # status: "default status",
36
- # work_item_type: "work_item_type",
37
- # project: "project id"
38
- # },
39
- # write_options: {
40
- # connection: {
41
- # host: "localhost",
42
- # port: 5432,
43
- # dbname: "bas",
44
- # user: "postgres",
45
- # password: "postgres"
46
- # },
47
- # db_table: "github_issues",
48
- # tag: "CreateWorkItem"
49
- # }
50
- # }
51
- #
52
- # bot = Bot::VerifyIssueExistanceInNotion.new(options)
53
- # bot.execute
54
- #
55
- class CreateWorkItem < Bot::Base
56
- include Utils::Notion::Types
57
-
58
- UPDATE_REQUEST = "UpdateWorkItemRequest"
59
- STATUS = "Backlog"
60
-
61
- # read function to execute the PostgresDB Read component
62
- #
63
- def read
64
- reader = Read::Postgres.new(read_options.merge(conditions))
65
-
66
- reader.execute
67
- end
68
-
69
- # process function to execute the Notion utility to create work items on a notion
70
- # database
71
- #
72
- def process
73
- return { success: { created: nil } } if unprocessable_response
74
-
75
- response = Utils::Notion::Request.execute(params)
76
-
77
- if response.code == 200
78
- { success: { issue: read_response.data["issue"], notion_wi: response["id"] } }
79
- else
80
- { error: { message: response.parsed_response, status_code: response.code } }
81
- end
82
- end
83
-
84
- # write function to execute the PostgresDB write component
85
- #
86
- def write
87
- options = write_options.merge({ tag: })
88
-
89
- write = Write::Postgres.new(options, process_response)
90
-
91
- write.execute
92
- end
93
-
94
- private
95
-
96
- def conditions
97
- {
98
- where: "archived=$1 AND tag=$2 AND stage=$3 ORDER BY inserted_at ASC",
99
- params: [false, read_options[:tag], "unprocessed"]
100
- }
101
- end
102
-
103
- def params
104
- {
105
- endpoint: "pages",
106
- secret: process_options[:secret],
107
- method: "post",
108
- body:
109
- }
110
- end
111
-
112
- def body
113
- {
114
- parent: { database_id: process_options[:database_id] },
115
- properties:
116
- }
117
- end
118
-
119
- def properties # rubocop:disable Metrics/AbcSize
120
- {
121
- "Responsible domain": select(read_response.data["domain"]),
122
- "Github Issue Id": rich_text(read_response.data["issue"]["id"].to_s),
123
- "Status": status(STATUS),
124
- "Detail": title(read_response.data["issue"]["title"])
125
- }.merge(work_item_type)
126
- end
127
-
128
- def work_item_type
129
- case read_response.data["work_item_type"]
130
- when "activity" then { "Activity": relation(read_response.data["type_id"]) }
131
- when "project" then { "Project": relation(read_response.data["type_id"]) }
132
- else {}
133
- end
134
- end
135
-
136
- def tag
137
- return write_options[:tag] if process_response[:success].nil? || process_response[:success][:notion_wi].nil?
138
-
139
- UPDATE_REQUEST
140
- end
141
- end
142
- end
@@ -1,87 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require_relative "./base"
4
- require_relative "../read/postgres"
5
- require_relative "../utils/digital_ocean/request"
6
- require_relative "../write/postgres"
7
-
8
- module Bot
9
- ##
10
- # The Bot::FetchBillingFromDigitalOcean class serves as a bot implementation to read digital
11
- # ocean current billing using the DigitalOcean API
12
- #
13
- # <br>
14
- # <b>Example</b>
15
- #
16
- # options = {
17
- # process_options: {
18
- # secret: "digital_ocean_secret_key"
19
- # },
20
- # write_options: {
21
- # connection: {
22
- # host: "host",
23
- # port: 5432,
24
- # dbname: "bas",
25
- # user: "postgres",
26
- # password: "postgres"
27
- # },
28
- # db_table: "use_cases",
29
- # tag: "FetchBillingFromDigitalOcean"
30
- # }
31
- # }
32
- #
33
- # bot = Bot::FetchBillingFromDigitalOcean.new(options)
34
- # bot.execute
35
- #
36
- class FetchBillingFromDigitalOcean < Bot::Base
37
- # Read function to execute the default Read component
38
- #
39
- def read
40
- reader = Read::Postgres.new(read_options.merge(conditions))
41
-
42
- reader.execute
43
- end
44
-
45
- # Process function to execute the DigitalOcean utility to fetch bills
46
- #
47
- def process
48
- response = Utils::DigitalOcean::Request.execute(params)
49
-
50
- if response.code == 200
51
- { success: { billing: response.parsed_response, last_billing: } }
52
- else
53
- { error: { message: response.parsed_response, status_code: response.code } }
54
- end
55
- end
56
-
57
- # Write function to execute the PostgresDB write component
58
- #
59
- def write
60
- write = Write::Postgres.new(write_options, process_response)
61
-
62
- write.execute
63
- end
64
-
65
- private
66
-
67
- def conditions
68
- {
69
- where: "archived=$1 AND tag=$2 ORDER BY inserted_at DESC",
70
- params: [false, read_options[:tag]]
71
- }
72
- end
73
-
74
- def params
75
- {
76
- endpoint: "customers/my/balance",
77
- secret: process_options[:secret],
78
- method: "get",
79
- body: {}
80
- }
81
- end
82
-
83
- def last_billing
84
- read_response.data.nil? ? nil : read_response.data["billing"]
85
- end
86
- end
87
- end
@@ -1,128 +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::FetchBirthdaysFromNotion class serves as a bot implementation to read birthdays from a
11
- # 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: "use_cases",
30
- # tag: "FetchBirthdaysFromNotion"
31
- # }
32
- # }
33
- #
34
- # bot = Bot::FetchBirthdaysFromNotion.new(options)
35
- # bot.execute
36
- #
37
- class FetchBirthdaysFromNotion < Bot::Base
38
- # read function to execute the PostgresDB Read component
39
- #
40
- def read
41
- reader = Read::Postgres.new(read_options.merge(conditions))
42
-
43
- reader.execute
44
- end
45
-
46
- # Process function to execute the Notion utility to fetch birthdays from a notion database
47
- #
48
- def process
49
- response = Utils::Notion::Request.execute(params)
50
-
51
- if response.code == 200
52
- birthdays_list = normalize_response(response.parsed_response["results"])
53
-
54
- { success: { birthdays: birthdays_list } }
55
- else
56
- { error: { message: response.parsed_response, status_code: response.code } }
57
- end
58
- end
59
-
60
- # Write function to execute the PostgresDB write component
61
- #
62
- def write
63
- write = Write::Postgres.new(write_options, process_response)
64
-
65
- write.execute
66
- end
67
-
68
- private
69
-
70
- def conditions
71
- {
72
- where: "archived=$1 AND tag=$2 ORDER BY inserted_at DESC",
73
- params: [false, read_options[:tag]]
74
- }
75
- end
76
-
77
- def params
78
- {
79
- endpoint: "databases/#{process_options[:database_id]}/query",
80
- secret: process_options[:secret],
81
- method: "post",
82
- body:
83
- }
84
- end
85
-
86
- def body
87
- today = Time.now.utc.strftime("%F").to_s
88
-
89
- {
90
- filter: {
91
- and: [{ property: "BD_this_year", date: { equals: today } }] + 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 normalize_response(results)
108
- return [] if results.nil?
109
-
110
- results.map do |value|
111
- birthday_fields = value["properties"]
112
-
113
- {
114
- "name" => extract_rich_text_field_value(birthday_fields["Complete Name"]),
115
- "birthday_date" => extract_date_field_value(birthday_fields["BD_this_year"])
116
- }
117
- end
118
- end
119
-
120
- def extract_rich_text_field_value(data)
121
- data["rich_text"][0]["plain_text"]
122
- end
123
-
124
- def extract_date_field_value(data)
125
- data["formula"]["date"]["start"]
126
- end
127
- end
128
- end
@@ -1,93 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require_relative "./base"
4
- require_relative "../read/default"
5
- require_relative "../utils/notion/request"
6
- require_relative "../write/postgres"
7
-
8
- module Bot
9
- ##
10
- # The Bot::FetchDomainServicesFromNotion class serves as a bot implementation to read
11
- # web domains 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: "localhost",
24
- # port: 5432,
25
- # dbname: "bas",
26
- # user: "postgres",
27
- # password: "postgres"
28
- # },
29
- # db_table: "web_availability",
30
- # tag: "FetchDomainServicesFromNotion"
31
- # }
32
- # }
33
- #
34
- # bot = Bot::FetchDomainServicesFromNotion.new(options)
35
- # bot.execute
36
- #
37
- class FetchDomainServicesFromNotion < Bot::Base
38
- def read
39
- reader = Read::Default.new
40
-
41
- reader.execute
42
- end
43
-
44
- # Process function to execute the Notion utility to fetch web domains from a notion database
45
- #
46
- def process
47
- response = Utils::Notion::Request.execute(params)
48
-
49
- if response.code == 200
50
- urls_list = normalize_response(response.parsed_response["results"])
51
-
52
- { success: { urls: urls_list } }
53
- else
54
- { error: { message: response.parsed_response, status_code: response.code } }
55
- end
56
- end
57
-
58
- # Write function to execute the PostgresDB write component
59
- #
60
- def write
61
- write = Write::Postgres.new(write_options, process_response)
62
-
63
- write.execute
64
- end
65
-
66
- private
67
-
68
- def params
69
- {
70
- endpoint: "databases/#{process_options[:database_id]}/query",
71
- secret: process_options[:secret],
72
- method: "post",
73
- body: {}
74
- }
75
- end
76
-
77
- def normalize_response(results)
78
- return [] if results.nil?
79
-
80
- results.map do |value|
81
- properties = value["properties"]
82
-
83
- {
84
- "url" => extract_rich_text_field_value(properties["domain"])
85
- }
86
- end
87
- end
88
-
89
- def extract_rich_text_field_value(data)
90
- data["rich_text"][0]["plain_text"]
91
- end
92
- end
93
- end
@@ -1,121 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require_relative "./base"
4
- require_relative "../read/default"
5
- require_relative "../utils/notion/request"
6
- require_relative "../write/postgres"
7
-
8
- module Bot
9
- ##
10
- # The Bot::FetchDomainsWipCountsFromNotion class serves as a bot implementation to fetch work items
11
- # in progress or in hold from a Notion database, count how many are by domain, and write them on a
12
- # PostgresDB table with a specific format.
13
- #
14
- # <br>
15
- # <b>Example</b>
16
- #
17
- # options = {
18
- # process_options: {
19
- # database_id: "notion database id",
20
- # secret: "notion secret"
21
- # },
22
- # write_options: {
23
- # connection: {
24
- # host: "host",
25
- # port: 5432,
26
- # dbname: "bas",
27
- # user: "postgres",
28
- # password: "postgres"
29
- # },
30
- # db_table: "use_cases",
31
- # tag: "FetchDomainsWipCountsFromNotion"
32
- # }
33
- # }
34
- #
35
- # bot = Bot::FetchDomainsWipCountsFromNotion.new(options)
36
- # bot.execute
37
- #
38
- class FetchDomainsWipCountsFromNotion < Bot::Base
39
- # Read function to execute the default Read component
40
- #
41
- def read
42
- reader = Read::Default.new
43
-
44
- reader.execute
45
- end
46
-
47
- # Process function to execute the Notion utility to fetch work item from the notion database
48
- #
49
- def process
50
- response = Utils::Notion::Request.execute(params)
51
-
52
- if response.code == 200
53
- work_items_domains = normalize_response(response.parsed_response["results"])
54
- domain_wip_count = count_domain_items(work_items_domains)
55
-
56
- { success: { domain_wip_count: } }
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
- {
83
- filter: {
84
- "and": [
85
- { property: "OK", formula: { string: { contains: "✅" } } },
86
- { "or": status_conditions }
87
- ]
88
- }
89
- }
90
- end
91
-
92
- def status_conditions
93
- [
94
- { property: "Status", status: { equals: "In Progress" } },
95
- { property: "Status", status: { equals: "On Hold" } }
96
- ]
97
- end
98
-
99
- def normalize_response(results)
100
- return [] if results.nil?
101
-
102
- results.map do |pto|
103
- work_item_fields = pto["properties"]
104
-
105
- {
106
- "domain" => extract_domain_field_value(work_item_fields["Responsible domain"])
107
- }
108
- end
109
- end
110
-
111
- def extract_domain_field_value(data)
112
- data["select"]["name"]
113
- end
114
-
115
- def count_domain_items(work_items_list)
116
- domain_work_items = work_items_list.group_by { |work_item| work_item["domain"] }
117
-
118
- domain_work_items.transform_values(&:count)
119
- end
120
- end
121
- end