bas 0.4.0 → 1.0.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 +4 -4
- data/CHANGELOG.md +12 -0
- data/README.md +68 -147
- data/lib/bas/bot/base.rb +74 -0
- data/lib/bas/bot/compare_wip_limit_count.rb +92 -0
- data/lib/bas/bot/fetch_birthdays_from_notion.rb +128 -0
- data/lib/bas/bot/fetch_domains_wip_counts_from_notion.rb +121 -0
- data/lib/bas/bot/fetch_domains_wip_limit_from_notion.rb +134 -0
- data/lib/bas/bot/fetch_emails_from_imap.rb +99 -0
- data/lib/bas/bot/fetch_next_week_birthdays_from_notion.rb +142 -0
- data/lib/bas/bot/fetch_next_week_ptos_from_notion.rb +162 -0
- data/lib/bas/bot/fetch_ptos_from_notion.rb +138 -0
- data/lib/bas/bot/format_birthdays.rb +97 -0
- data/lib/bas/bot/format_emails.rb +124 -0
- data/lib/bas/bot/format_wip_limit_exceeded.rb +97 -0
- data/lib/bas/bot/garbage_collector.rb +85 -0
- data/lib/bas/bot/humanize_pto.rb +119 -0
- data/lib/bas/bot/notify_discord.rb +96 -0
- data/lib/bas/read/base.rb +10 -23
- data/lib/bas/read/default.rb +16 -0
- data/lib/bas/read/postgres.rb +44 -0
- data/lib/bas/read/types/response.rb +18 -0
- data/lib/bas/utils/discord/integration.rb +43 -0
- data/lib/bas/utils/exceptions/function_not_implemented.rb +16 -0
- data/lib/bas/utils/exceptions/invalid_process_response.rb +16 -0
- data/lib/bas/utils/imap/request.rb +76 -0
- data/lib/bas/utils/notion/request.rb +45 -0
- data/lib/bas/utils/openai/run_assistant.rb +99 -0
- data/lib/bas/utils/postgres/request.rb +50 -0
- data/lib/bas/version.rb +1 -1
- data/lib/bas/write/base.rb +12 -17
- data/lib/bas/write/postgres.rb +45 -0
- data/lib/bas/write/postgres_update.rb +49 -0
- data/lib/bas.rb +1 -3
- metadata +30 -67
- data/lib/bas/domain/birthday.rb +0 -25
- data/lib/bas/domain/email.rb +0 -34
- data/lib/bas/domain/exceptions/function_not_implemented.rb +0 -18
- data/lib/bas/domain/issue.rb +0 -22
- data/lib/bas/domain/notification.rb +0 -23
- data/lib/bas/domain/pto.rb +0 -69
- data/lib/bas/domain/work_items_limit.rb +0 -25
- data/lib/bas/formatter/base.rb +0 -53
- data/lib/bas/formatter/birthday.rb +0 -38
- data/lib/bas/formatter/exceptions/invalid_data.rb +0 -15
- data/lib/bas/formatter/notification.rb +0 -34
- data/lib/bas/formatter/pto.rb +0 -89
- data/lib/bas/formatter/support_emails.rb +0 -73
- data/lib/bas/formatter/types/response.rb +0 -16
- data/lib/bas/formatter/work_items_limit.rb +0 -68
- data/lib/bas/process/base.rb +0 -39
- data/lib/bas/process/discord/exceptions/invalid_webhook_token.rb +0 -16
- data/lib/bas/process/discord/implementation.rb +0 -71
- data/lib/bas/process/discord/types/response.rb +0 -22
- data/lib/bas/process/openai/base.rb +0 -72
- data/lib/bas/process/openai/helper.rb +0 -19
- data/lib/bas/process/openai/types/response.rb +0 -27
- data/lib/bas/process/openai/use_case/humanize_pto.rb +0 -53
- data/lib/bas/process/slack/exceptions/invalid_webhook_token.rb +0 -16
- data/lib/bas/process/slack/implementation.rb +0 -70
- data/lib/bas/process/slack/types/response.rb +0 -21
- data/lib/bas/process/types/response.rb +0 -16
- data/lib/bas/read/github/base.rb +0 -57
- data/lib/bas/read/github/types/response.rb +0 -27
- data/lib/bas/read/github/use_case/repo_issues.rb +0 -17
- data/lib/bas/read/imap/base.rb +0 -70
- data/lib/bas/read/imap/types/response.rb +0 -27
- data/lib/bas/read/imap/use_case/support_emails.rb +0 -26
- data/lib/bas/read/notion/base.rb +0 -52
- data/lib/bas/read/notion/exceptions/invalid_api_key.rb +0 -15
- data/lib/bas/read/notion/exceptions/invalid_database_id.rb +0 -15
- data/lib/bas/read/notion/helper.rb +0 -21
- data/lib/bas/read/notion/types/response.rb +0 -26
- data/lib/bas/read/notion/use_case/birthday_next_week.rb +0 -41
- data/lib/bas/read/notion/use_case/birthday_today.rb +0 -29
- data/lib/bas/read/notion/use_case/notification.rb +0 -28
- data/lib/bas/read/notion/use_case/pto_next_week.rb +0 -71
- data/lib/bas/read/notion/use_case/pto_today.rb +0 -30
- data/lib/bas/read/notion/use_case/work_items_limit.rb +0 -37
- data/lib/bas/read/postgres/base.rb +0 -46
- data/lib/bas/read/postgres/helper.rb +0 -16
- data/lib/bas/read/postgres/types/response.rb +0 -42
- data/lib/bas/read/postgres/use_case/pto_today.rb +0 -32
- data/lib/bas/serialize/base.rb +0 -30
- data/lib/bas/serialize/github/issues.rb +0 -57
- data/lib/bas/serialize/imap/support_emails.rb +0 -56
- data/lib/bas/serialize/notion/birthday_today.rb +0 -68
- data/lib/bas/serialize/notion/notification.rb +0 -56
- data/lib/bas/serialize/notion/pto_today.rb +0 -75
- data/lib/bas/serialize/notion/work_items_limit.rb +0 -65
- data/lib/bas/serialize/postgres/pto_today.rb +0 -47
- data/lib/bas/use_cases/types/config.rb +0 -20
- data/lib/bas/use_cases/use_case.rb +0 -42
- data/lib/bas/use_cases/use_cases.rb +0 -465
- data/lib/bas/write/logs/base.rb +0 -33
- data/lib/bas/write/logs/use_case/console_log.rb +0 -22
- data/lib/bas/write/notion/base.rb +0 -36
- data/lib/bas/write/notion/use_case/empty_notification.rb +0 -38
- data/lib/bas/write/notion/use_case/notification.rb +0 -38
@@ -0,0 +1,138 @@
|
|
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::FetchPtosFromNotion class serves as a bot implementation to read PTO's 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: "pto",
|
30
|
+
# tag: "FetchPtosFromNotion"
|
31
|
+
# }
|
32
|
+
# }
|
33
|
+
#
|
34
|
+
# bot = Bot::FetchPtosFromNotion.new(options)
|
35
|
+
# bot.execute
|
36
|
+
#
|
37
|
+
class FetchPtosFromNotion < Bot::Base
|
38
|
+
# Read function to execute the default Read component
|
39
|
+
#
|
40
|
+
def read
|
41
|
+
reader = Read::Default.new
|
42
|
+
|
43
|
+
reader.execute
|
44
|
+
end
|
45
|
+
|
46
|
+
# Process function to execute the Notion utility to fetch PTO's from the notion database
|
47
|
+
#
|
48
|
+
def process
|
49
|
+
response = Utils::Notion::Request.execute(params)
|
50
|
+
|
51
|
+
if response.code == 200
|
52
|
+
ptos_list = normalize_response(response.parsed_response["results"])
|
53
|
+
|
54
|
+
{ success: { ptos: ptos_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 params
|
71
|
+
{
|
72
|
+
endpoint: "databases/#{process_options[:database_id]}/query",
|
73
|
+
secret: process_options[:secret],
|
74
|
+
method: "post",
|
75
|
+
body:
|
76
|
+
}
|
77
|
+
end
|
78
|
+
|
79
|
+
def body
|
80
|
+
{ filter: { "or": conditions } }
|
81
|
+
end
|
82
|
+
|
83
|
+
def conditions
|
84
|
+
[
|
85
|
+
today_condition,
|
86
|
+
{ property: "StartDateTime", date: { this_week: {} } },
|
87
|
+
{ property: "EndDateTime", date: { this_week: {} } },
|
88
|
+
{ property: "StartDateTime", date: { next_week: {} } },
|
89
|
+
{ property: "EndDateTime", date: { next_week: {} } }
|
90
|
+
]
|
91
|
+
end
|
92
|
+
|
93
|
+
def today_condition
|
94
|
+
today = Time.now.utc.strftime("%F").to_s
|
95
|
+
{
|
96
|
+
"and": [
|
97
|
+
{ property: "StartDateTime", date: { on_or_before: today } },
|
98
|
+
{ property: "EndDateTime", date: { on_or_after: today } }
|
99
|
+
]
|
100
|
+
}
|
101
|
+
end
|
102
|
+
|
103
|
+
def normalize_response(results)
|
104
|
+
return [] if results.nil?
|
105
|
+
|
106
|
+
results.map do |pto|
|
107
|
+
pto_fields = pto["properties"]
|
108
|
+
|
109
|
+
{
|
110
|
+
"Name" => extract_description_field_value(pto_fields["Description"]),
|
111
|
+
"StartDateTime" => extract_date_field_value(pto_fields["StartDateTime"]),
|
112
|
+
"EndDateTime" => extract_date_field_value(pto_fields["EndDateTime"])
|
113
|
+
}
|
114
|
+
end
|
115
|
+
end
|
116
|
+
|
117
|
+
def extract_description_field_value(data)
|
118
|
+
names = data["title"].map { |name| name["plain_text"] }
|
119
|
+
|
120
|
+
names.join(" ")
|
121
|
+
end
|
122
|
+
|
123
|
+
def extract_date_field_value(date)
|
124
|
+
{
|
125
|
+
from: extract_start_date(date),
|
126
|
+
to: extract_end_date(date)
|
127
|
+
}
|
128
|
+
end
|
129
|
+
|
130
|
+
def extract_start_date(data)
|
131
|
+
data["date"]["start"]
|
132
|
+
end
|
133
|
+
|
134
|
+
def extract_end_date(data)
|
135
|
+
data["date"]["end"]
|
136
|
+
end
|
137
|
+
end
|
138
|
+
end
|
@@ -0,0 +1,97 @@
|
|
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
|
@@ -0,0 +1,124 @@
|
|
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
|
@@ -0,0 +1,97 @@
|
|
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
|
@@ -0,0 +1,85 @@
|
|
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
|
@@ -0,0 +1,119 @@
|
|
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.map do |pto|
|
105
|
+
"#{pto["Name"]} is PTO from StartDateTime: #{pto["StartDateTime"]} to EndDateTime: #{pto["EndDateTime"]}"
|
106
|
+
end.join("\n")
|
107
|
+
|
108
|
+
prompt.gsub("{data}", ptos_list_formatted_string)
|
109
|
+
end
|
110
|
+
|
111
|
+
def sucess_response(response)
|
112
|
+
{ success: { notification: response.parsed_response["data"].first["content"].first["text"]["value"] } }
|
113
|
+
end
|
114
|
+
|
115
|
+
def error_response(response)
|
116
|
+
{ error: { message: response.parsed_response, status_code: response.code } }
|
117
|
+
end
|
118
|
+
end
|
119
|
+
end
|