bas 0.4.0 → 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (99) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +12 -0
  3. data/README.md +68 -147
  4. data/lib/bas/bot/base.rb +74 -0
  5. data/lib/bas/bot/compare_wip_limit_count.rb +92 -0
  6. data/lib/bas/bot/fetch_birthdays_from_notion.rb +128 -0
  7. data/lib/bas/bot/fetch_domains_wip_counts_from_notion.rb +121 -0
  8. data/lib/bas/bot/fetch_domains_wip_limit_from_notion.rb +134 -0
  9. data/lib/bas/bot/fetch_emails_from_imap.rb +99 -0
  10. data/lib/bas/bot/fetch_next_week_birthdays_from_notion.rb +142 -0
  11. data/lib/bas/bot/fetch_next_week_ptos_from_notion.rb +162 -0
  12. data/lib/bas/bot/fetch_ptos_from_notion.rb +138 -0
  13. data/lib/bas/bot/format_birthdays.rb +97 -0
  14. data/lib/bas/bot/format_emails.rb +124 -0
  15. data/lib/bas/bot/format_wip_limit_exceeded.rb +97 -0
  16. data/lib/bas/bot/garbage_collector.rb +85 -0
  17. data/lib/bas/bot/humanize_pto.rb +119 -0
  18. data/lib/bas/bot/notify_discord.rb +96 -0
  19. data/lib/bas/read/base.rb +10 -23
  20. data/lib/bas/read/default.rb +16 -0
  21. data/lib/bas/read/postgres.rb +44 -0
  22. data/lib/bas/read/types/response.rb +18 -0
  23. data/lib/bas/utils/discord/integration.rb +43 -0
  24. data/lib/bas/utils/exceptions/function_not_implemented.rb +16 -0
  25. data/lib/bas/utils/exceptions/invalid_process_response.rb +16 -0
  26. data/lib/bas/utils/imap/request.rb +76 -0
  27. data/lib/bas/utils/notion/request.rb +45 -0
  28. data/lib/bas/utils/openai/run_assistant.rb +99 -0
  29. data/lib/bas/utils/postgres/request.rb +50 -0
  30. data/lib/bas/version.rb +1 -1
  31. data/lib/bas/write/base.rb +12 -17
  32. data/lib/bas/write/postgres.rb +45 -0
  33. data/lib/bas/write/postgres_update.rb +49 -0
  34. data/lib/bas.rb +1 -3
  35. metadata +30 -67
  36. data/lib/bas/domain/birthday.rb +0 -25
  37. data/lib/bas/domain/email.rb +0 -34
  38. data/lib/bas/domain/exceptions/function_not_implemented.rb +0 -18
  39. data/lib/bas/domain/issue.rb +0 -22
  40. data/lib/bas/domain/notification.rb +0 -23
  41. data/lib/bas/domain/pto.rb +0 -69
  42. data/lib/bas/domain/work_items_limit.rb +0 -25
  43. data/lib/bas/formatter/base.rb +0 -53
  44. data/lib/bas/formatter/birthday.rb +0 -38
  45. data/lib/bas/formatter/exceptions/invalid_data.rb +0 -15
  46. data/lib/bas/formatter/notification.rb +0 -34
  47. data/lib/bas/formatter/pto.rb +0 -89
  48. data/lib/bas/formatter/support_emails.rb +0 -73
  49. data/lib/bas/formatter/types/response.rb +0 -16
  50. data/lib/bas/formatter/work_items_limit.rb +0 -68
  51. data/lib/bas/process/base.rb +0 -39
  52. data/lib/bas/process/discord/exceptions/invalid_webhook_token.rb +0 -16
  53. data/lib/bas/process/discord/implementation.rb +0 -71
  54. data/lib/bas/process/discord/types/response.rb +0 -22
  55. data/lib/bas/process/openai/base.rb +0 -72
  56. data/lib/bas/process/openai/helper.rb +0 -19
  57. data/lib/bas/process/openai/types/response.rb +0 -27
  58. data/lib/bas/process/openai/use_case/humanize_pto.rb +0 -53
  59. data/lib/bas/process/slack/exceptions/invalid_webhook_token.rb +0 -16
  60. data/lib/bas/process/slack/implementation.rb +0 -70
  61. data/lib/bas/process/slack/types/response.rb +0 -21
  62. data/lib/bas/process/types/response.rb +0 -16
  63. data/lib/bas/read/github/base.rb +0 -57
  64. data/lib/bas/read/github/types/response.rb +0 -27
  65. data/lib/bas/read/github/use_case/repo_issues.rb +0 -17
  66. data/lib/bas/read/imap/base.rb +0 -70
  67. data/lib/bas/read/imap/types/response.rb +0 -27
  68. data/lib/bas/read/imap/use_case/support_emails.rb +0 -26
  69. data/lib/bas/read/notion/base.rb +0 -52
  70. data/lib/bas/read/notion/exceptions/invalid_api_key.rb +0 -15
  71. data/lib/bas/read/notion/exceptions/invalid_database_id.rb +0 -15
  72. data/lib/bas/read/notion/helper.rb +0 -21
  73. data/lib/bas/read/notion/types/response.rb +0 -26
  74. data/lib/bas/read/notion/use_case/birthday_next_week.rb +0 -41
  75. data/lib/bas/read/notion/use_case/birthday_today.rb +0 -29
  76. data/lib/bas/read/notion/use_case/notification.rb +0 -28
  77. data/lib/bas/read/notion/use_case/pto_next_week.rb +0 -71
  78. data/lib/bas/read/notion/use_case/pto_today.rb +0 -30
  79. data/lib/bas/read/notion/use_case/work_items_limit.rb +0 -37
  80. data/lib/bas/read/postgres/base.rb +0 -46
  81. data/lib/bas/read/postgres/helper.rb +0 -16
  82. data/lib/bas/read/postgres/types/response.rb +0 -42
  83. data/lib/bas/read/postgres/use_case/pto_today.rb +0 -32
  84. data/lib/bas/serialize/base.rb +0 -30
  85. data/lib/bas/serialize/github/issues.rb +0 -57
  86. data/lib/bas/serialize/imap/support_emails.rb +0 -56
  87. data/lib/bas/serialize/notion/birthday_today.rb +0 -68
  88. data/lib/bas/serialize/notion/notification.rb +0 -56
  89. data/lib/bas/serialize/notion/pto_today.rb +0 -75
  90. data/lib/bas/serialize/notion/work_items_limit.rb +0 -65
  91. data/lib/bas/serialize/postgres/pto_today.rb +0 -47
  92. data/lib/bas/use_cases/types/config.rb +0 -20
  93. data/lib/bas/use_cases/use_case.rb +0 -42
  94. data/lib/bas/use_cases/use_cases.rb +0 -465
  95. data/lib/bas/write/logs/base.rb +0 -33
  96. data/lib/bas/write/logs/use_case/console_log.rb +0 -22
  97. data/lib/bas/write/notion/base.rb +0 -36
  98. data/lib/bas/write/notion/use_case/empty_notification.rb +0 -38
  99. 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