bas 1.3.0 → 1.4.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 +4 -0
- data/lib/bas/bot/create_work_item.rb +141 -0
- data/lib/bas/bot/fetch_github_issues.rb +125 -0
- data/lib/bas/bot/fetch_next_week_ptos_from_notion.rb +41 -6
- data/lib/bas/bot/fetch_ptos_from_notion.rb +3 -16
- data/lib/bas/bot/update_work_item.rb +132 -0
- data/lib/bas/bot/verify_issue_existance_in_notion.rb +130 -0
- data/lib/bas/bot/write_github_issue_requests.rb +96 -0
- data/lib/bas/utils/github/octokit_client.rb +54 -0
- data/lib/bas/utils/notion/delete_page_blocks.rb +64 -0
- data/lib/bas/utils/notion/types.rb +39 -0
- data/lib/bas/version.rb +1 -1
- metadata +10 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 4ab201fef0200fb13b92ff49a3925c0fc2a10efd26a473d987cc9eef4ddbeae6
|
4
|
+
data.tar.gz: 93724237d9d6865c369e46f528a2a92dc63b7dd4239d5b0d37725cdb57d96ff9
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: a958b5d144da8fa1e162d5d44a18dd30472d2cd7bbd9c6d3fe6991d860a2b5199b9c68aff3b190fbdc48cc275b686c6707b304b39552a6776945e391b4bcb5b1
|
7
|
+
data.tar.gz: 30d014adce784050342b51663a583ee7474e2f00b28ef60210254c5f3fdf43d614607bff763325d93016d5b6bd320a5cdb9363a86b03082d37e28d896248979a
|
data/CHANGELOG.md
CHANGED
@@ -1,5 +1,9 @@
|
|
1
1
|
# Changelog
|
2
2
|
|
3
|
+
# 1.4.0 (26.07.2024)
|
4
|
+
- [Add bots to synchronize issues with notion work items](https://github.com/kommitters/bas/issues/87)
|
5
|
+
- [Update fetch pto from notion bot](https://github.com/kommitters/bas/issues/75)
|
6
|
+
|
3
7
|
# 1.3.0 (18.07.2024)
|
4
8
|
- [Add bots to check webs availability](https://github.com/kommitters/bas/issues/83)
|
5
9
|
|
@@ -0,0 +1,141 @@
|
|
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
|
+
|
60
|
+
# read function to execute the PostgresDB Read component
|
61
|
+
#
|
62
|
+
def read
|
63
|
+
reader = Read::Postgres.new(read_options.merge(conditions))
|
64
|
+
|
65
|
+
reader.execute
|
66
|
+
end
|
67
|
+
|
68
|
+
# process function to execute the Notion utility to create work items on a notion
|
69
|
+
# database
|
70
|
+
#
|
71
|
+
def process
|
72
|
+
return { success: { created: nil } } if unprocessable_response
|
73
|
+
|
74
|
+
response = Utils::Notion::Request.execute(params)
|
75
|
+
|
76
|
+
if response.code == 200
|
77
|
+
{ success: { issue: read_response.data["issue"], notion_wi: response["id"] } }
|
78
|
+
else
|
79
|
+
{ error: { message: response.parsed_response, status_code: response.code } }
|
80
|
+
end
|
81
|
+
end
|
82
|
+
|
83
|
+
# write function to execute the PostgresDB write component
|
84
|
+
#
|
85
|
+
def write
|
86
|
+
options = write_options.merge({ tag: })
|
87
|
+
|
88
|
+
write = Write::Postgres.new(options, process_response)
|
89
|
+
|
90
|
+
write.execute
|
91
|
+
end
|
92
|
+
|
93
|
+
private
|
94
|
+
|
95
|
+
def conditions
|
96
|
+
{
|
97
|
+
where: "archived=$1 AND tag=$2 AND stage=$3 ORDER BY inserted_at ASC",
|
98
|
+
params: [false, read_options[:tag], "unprocessed"]
|
99
|
+
}
|
100
|
+
end
|
101
|
+
|
102
|
+
def params
|
103
|
+
{
|
104
|
+
endpoint: "pages",
|
105
|
+
secret: process_options[:secret],
|
106
|
+
method: "post",
|
107
|
+
body:
|
108
|
+
}
|
109
|
+
end
|
110
|
+
|
111
|
+
def body
|
112
|
+
{
|
113
|
+
parent: { database_id: process_options[:database_id] },
|
114
|
+
properties:
|
115
|
+
}
|
116
|
+
end
|
117
|
+
|
118
|
+
def properties # rubocop:disable Metrics/AbcSize
|
119
|
+
{
|
120
|
+
"Responsible domain": select(process_options[:domain]),
|
121
|
+
"Github Issue id": rich_text(read_response.data["issue"]["id"].to_s),
|
122
|
+
"Status": status(process_options[:status]),
|
123
|
+
"Detail": title(read_response.data["issue"]["title"])
|
124
|
+
}.merge(work_item_type)
|
125
|
+
end
|
126
|
+
|
127
|
+
def work_item_type
|
128
|
+
case process_options[:work_item_type]
|
129
|
+
when "activity" then { "Activity": relation(process_options[:activity]) }
|
130
|
+
when "project" then { "Project": relation(process_options[:project]) }
|
131
|
+
else {}
|
132
|
+
end
|
133
|
+
end
|
134
|
+
|
135
|
+
def tag
|
136
|
+
return write_options[:tag] if process_response[:success].nil? || process_response[:success][:notion_wi].nil?
|
137
|
+
|
138
|
+
UPDATE_REQUEST
|
139
|
+
end
|
140
|
+
end
|
141
|
+
end
|
@@ -0,0 +1,125 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative "./base"
|
4
|
+
require_relative "../read/default"
|
5
|
+
require_relative "../utils/github/octokit_client"
|
6
|
+
require_relative "../write/postgres"
|
7
|
+
|
8
|
+
module Bot
|
9
|
+
##
|
10
|
+
# The Bot::FetchGithubIssues class serves as a bot implementation to fetch GitHub issues from a
|
11
|
+
# repository and write them 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: "github_issues",
|
26
|
+
# tag: "FetchGithubIssues",
|
27
|
+
# avoid_process: true
|
28
|
+
# },
|
29
|
+
# process_options: {
|
30
|
+
# private_pem: "Github App private token",
|
31
|
+
# app_id: "Github App id",
|
32
|
+
# repo: "repository name",
|
33
|
+
# filters: "hash with filters",
|
34
|
+
# organization: "GitHub organization name"
|
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: "github_issues",
|
45
|
+
# tag: "FetchGithubIssues"
|
46
|
+
# }
|
47
|
+
# }
|
48
|
+
#
|
49
|
+
# bot = Bot::FetchGithubIssues.new(options)
|
50
|
+
# bot.execute
|
51
|
+
#
|
52
|
+
class FetchGithubIssues < Bot::Base
|
53
|
+
ISSUE_PARAMS = %i[id html_url title body labels state created_at updated_at].freeze
|
54
|
+
PER_PAGE = 100
|
55
|
+
|
56
|
+
# read function to execute the PostgresDB Read component
|
57
|
+
#
|
58
|
+
def read
|
59
|
+
reader = Read::Postgres.new(read_options.merge(conditions))
|
60
|
+
|
61
|
+
reader.execute
|
62
|
+
end
|
63
|
+
|
64
|
+
# Process function to request GitHub issues using the octokit utility
|
65
|
+
#
|
66
|
+
def process
|
67
|
+
octokit = Utils::Github::OctokitClient.new(params).execute
|
68
|
+
|
69
|
+
if octokit[:client]
|
70
|
+
repo_issues = octokit[:client].issues(@process_options[:repo], filters)
|
71
|
+
|
72
|
+
issues = normalize_response(repo_issues)
|
73
|
+
|
74
|
+
{ success: { issues: } }
|
75
|
+
else
|
76
|
+
{ error: octokit[:error] }
|
77
|
+
end
|
78
|
+
end
|
79
|
+
|
80
|
+
# Write function to execute the PostgresDB write component
|
81
|
+
#
|
82
|
+
def write
|
83
|
+
write = Write::Postgres.new(write_options, process_response)
|
84
|
+
|
85
|
+
write.execute
|
86
|
+
end
|
87
|
+
|
88
|
+
private
|
89
|
+
|
90
|
+
def conditions
|
91
|
+
{
|
92
|
+
where: "tag=$1 ORDER BY inserted_at DESC",
|
93
|
+
params: [read_options[:tag]]
|
94
|
+
}
|
95
|
+
end
|
96
|
+
|
97
|
+
def params
|
98
|
+
{
|
99
|
+
private_pem: process_options[:private_pem],
|
100
|
+
app_id: process_options[:app_id],
|
101
|
+
method: process_options[:method],
|
102
|
+
method_params: process_options[:method_params],
|
103
|
+
organization: process_options[:organization]
|
104
|
+
}
|
105
|
+
end
|
106
|
+
|
107
|
+
def filters
|
108
|
+
default_filter = { per_page: PER_PAGE }
|
109
|
+
|
110
|
+
filters = @process_options[:filters]
|
111
|
+
filters = filters.merge({ since: read_response.inserted_at }) unless read_response.nil?
|
112
|
+
|
113
|
+
filters.is_a?(Hash) ? default_filter.merge(filters) : default_filter
|
114
|
+
end
|
115
|
+
|
116
|
+
def normalize_response(issues)
|
117
|
+
issues.map do |issue|
|
118
|
+
ISSUE_PARAMS.reduce({}) do |hash, param|
|
119
|
+
hash.merge({ param => issue.send(param) })
|
120
|
+
.merge({ assignees: issue.assignees.map(&:login) })
|
121
|
+
end
|
122
|
+
end
|
123
|
+
end
|
124
|
+
end
|
125
|
+
end
|
@@ -1,5 +1,7 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
+
require "date"
|
4
|
+
|
3
5
|
require_relative "./base"
|
4
6
|
require_relative "../read/default"
|
5
7
|
require_relative "../utils/notion/request"
|
@@ -34,7 +36,7 @@ module Bot
|
|
34
36
|
# bot = Bot::FetchNextWeekPtosFromNotion.new(options)
|
35
37
|
# bot.execute
|
36
38
|
#
|
37
|
-
class FetchNextWeekPtosFromNotion < Bot::Base
|
39
|
+
class FetchNextWeekPtosFromNotion < Bot::Base # rubocop:disable Metrics/ClassLength
|
38
40
|
# Read function to execute the default Read component
|
39
41
|
#
|
40
42
|
def read
|
@@ -130,14 +132,47 @@ module Bot
|
|
130
132
|
results.map do |pto|
|
131
133
|
pto_fields = pto["properties"]
|
132
134
|
|
133
|
-
|
134
|
-
|
135
|
-
|
136
|
-
|
137
|
-
|
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)
|
138
140
|
end
|
139
141
|
end
|
140
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
|
+
|
141
176
|
def extract_description_field_value(data)
|
142
177
|
names = data["title"].map { |name| name["plain_text"] }
|
143
178
|
|
@@ -74,26 +74,13 @@ module Bot
|
|
74
74
|
endpoint: "databases/#{process_options[:database_id]}/query",
|
75
75
|
secret: process_options[:secret],
|
76
76
|
method: "post",
|
77
|
-
body:
|
77
|
+
body: { filter: today_condition }
|
78
78
|
}
|
79
79
|
end
|
80
80
|
|
81
|
-
def body
|
82
|
-
{ filter: { "or": conditions } }
|
83
|
-
end
|
84
|
-
|
85
|
-
def conditions
|
86
|
-
[
|
87
|
-
today_condition,
|
88
|
-
{ property: "StartDateTime", date: { this_week: {} } },
|
89
|
-
{ property: "EndDateTime", date: { this_week: {} } },
|
90
|
-
{ property: "StartDateTime", date: { next_week: {} } },
|
91
|
-
{ property: "EndDateTime", date: { next_week: {} } }
|
92
|
-
]
|
93
|
-
end
|
94
|
-
|
95
81
|
def today_condition
|
96
82
|
today = Time.now.utc.strftime("%F").to_s
|
83
|
+
|
97
84
|
{
|
98
85
|
"and": [
|
99
86
|
{ property: "StartDateTime", date: { on_or_before: today } },
|
@@ -134,7 +121,7 @@ module Bot
|
|
134
121
|
end
|
135
122
|
|
136
123
|
def returns(date)
|
137
|
-
date.include?("
|
124
|
+
date.include?("T12") ? "#{date} in the afternoon" : next_work_day(date)
|
138
125
|
end
|
139
126
|
|
140
127
|
def next_work_day(date)
|
@@ -0,0 +1,132 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "json"
|
4
|
+
require "md_to_notion"
|
5
|
+
|
6
|
+
require_relative "./base"
|
7
|
+
require_relative "../read/postgres"
|
8
|
+
require_relative "../utils/notion/request"
|
9
|
+
require_relative "../utils/notion/types"
|
10
|
+
require_relative "../utils/notion/delete_page_blocks"
|
11
|
+
require_relative "../write/postgres"
|
12
|
+
|
13
|
+
module Bot
|
14
|
+
##
|
15
|
+
# The Bot::UpdateWorkItem class serves as a bot implementation to update "work items" on a
|
16
|
+
# notion database using information of a GitHub issue.
|
17
|
+
#
|
18
|
+
# <br>
|
19
|
+
# <b>Example</b>
|
20
|
+
#
|
21
|
+
# options = {
|
22
|
+
# read_options: {
|
23
|
+
# connection: {
|
24
|
+
# host: "localhost",
|
25
|
+
# port: 5432,
|
26
|
+
# dbname: "bas",
|
27
|
+
# user: "postgres",
|
28
|
+
# password: "postgres"
|
29
|
+
# },
|
30
|
+
# db_table: "github_issues",
|
31
|
+
# tag: "UpdateWorkItemRequest"
|
32
|
+
# },
|
33
|
+
# process_options: {
|
34
|
+
# secret: "notion secret"
|
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: "github_issues",
|
45
|
+
# tag: "UpdateWorkItem"
|
46
|
+
# }
|
47
|
+
# }
|
48
|
+
#
|
49
|
+
# bot = Bot::UpdateWorkItem.new(options)
|
50
|
+
# bot.execute
|
51
|
+
#
|
52
|
+
class UpdateWorkItem < Bot::Base
|
53
|
+
include Utils::Notion::Types
|
54
|
+
|
55
|
+
DESCRIPTION = "Issue Description"
|
56
|
+
|
57
|
+
# read function to execute the PostgresDB Read component
|
58
|
+
#
|
59
|
+
def read
|
60
|
+
reader = Read::Postgres.new(read_options.merge(conditions))
|
61
|
+
|
62
|
+
reader.execute
|
63
|
+
end
|
64
|
+
|
65
|
+
# process function to execute the Notion utility to update work items on a notion
|
66
|
+
# database
|
67
|
+
def process
|
68
|
+
return { success: { updated: nil } } if unprocessable_response
|
69
|
+
|
70
|
+
delete_wi
|
71
|
+
|
72
|
+
response = Utils::Notion::Request.execute(params)
|
73
|
+
|
74
|
+
if response.code == 200
|
75
|
+
{ success: { issue: read_response.data["issue"] } }
|
76
|
+
else
|
77
|
+
{ error: { message: response.parsed_response, status_code: response.code } }
|
78
|
+
end
|
79
|
+
end
|
80
|
+
|
81
|
+
# write function to execute the PostgresDB write component
|
82
|
+
#
|
83
|
+
def write
|
84
|
+
write = Write::Postgres.new(write_options, process_response)
|
85
|
+
|
86
|
+
write.execute
|
87
|
+
end
|
88
|
+
|
89
|
+
private
|
90
|
+
|
91
|
+
def conditions
|
92
|
+
{
|
93
|
+
where: "archived=$1 AND tag=$2 AND stage=$3 ORDER BY inserted_at ASC",
|
94
|
+
params: [false, read_options[:tag], "unprocessed"]
|
95
|
+
}
|
96
|
+
end
|
97
|
+
|
98
|
+
def params
|
99
|
+
{
|
100
|
+
endpoint: "blocks/#{read_response.data["notion_wi"]}/children",
|
101
|
+
secret: process_options[:secret],
|
102
|
+
method: "patch",
|
103
|
+
body:
|
104
|
+
}
|
105
|
+
end
|
106
|
+
|
107
|
+
def body
|
108
|
+
{ children: description + [issue_reference] }
|
109
|
+
end
|
110
|
+
|
111
|
+
def description
|
112
|
+
MdToNotion::Parser.markdown_to_notion_blocks(read_response.data["issue"]["body"])
|
113
|
+
end
|
114
|
+
|
115
|
+
def issue_reference
|
116
|
+
{
|
117
|
+
object: "block",
|
118
|
+
type: "paragraph",
|
119
|
+
paragraph: rich_text("issue", read_response.data["issue"]["html_url"])
|
120
|
+
}
|
121
|
+
end
|
122
|
+
|
123
|
+
def delete_wi
|
124
|
+
params = {
|
125
|
+
page_id: read_response.data["notion_wi"],
|
126
|
+
secret: process_options[:secret]
|
127
|
+
}
|
128
|
+
|
129
|
+
Utils::Notion::DeletePageBlocks.new(params).execute
|
130
|
+
end
|
131
|
+
end
|
132
|
+
end
|
@@ -0,0 +1,130 @@
|
|
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/update_db_state"
|
9
|
+
require_relative "../write/postgres"
|
10
|
+
|
11
|
+
module Bot
|
12
|
+
##
|
13
|
+
# The Bot::VerifyIssueExistanceInNotion class serves as a bot implementation to verify if a
|
14
|
+
# GitHub issue was already created on a notion database base on a column with the issue id.
|
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: "GithubIssueRequest"
|
30
|
+
# },
|
31
|
+
# process_options: {
|
32
|
+
# database_id: "notion database id",
|
33
|
+
# secret: "notion secret"
|
34
|
+
# },
|
35
|
+
# write_options: {
|
36
|
+
# connection: {
|
37
|
+
# host: "localhost",
|
38
|
+
# port: 5432,
|
39
|
+
# dbname: "bas",
|
40
|
+
# user: "postgres",
|
41
|
+
# password: "postgres"
|
42
|
+
# },
|
43
|
+
# db_table: "github_issues",
|
44
|
+
# tag: "VerifyIssueExistanceInNotio"
|
45
|
+
# }
|
46
|
+
# }
|
47
|
+
#
|
48
|
+
# bot = Bot::VerifyIssueExistanceInNotion.new(options)
|
49
|
+
# bot.execute
|
50
|
+
#
|
51
|
+
class VerifyIssueExistanceInNotion < Bot::Base
|
52
|
+
NOT_FOUND = "not found"
|
53
|
+
|
54
|
+
# read function to execute the PostgresDB Read component
|
55
|
+
#
|
56
|
+
def read
|
57
|
+
reader = Read::Postgres.new(read_options.merge(conditions))
|
58
|
+
|
59
|
+
reader.execute
|
60
|
+
end
|
61
|
+
|
62
|
+
# process function to execute the Notion utility to verify GitHub issues existance
|
63
|
+
# on a notion database
|
64
|
+
#
|
65
|
+
def process
|
66
|
+
return { success: { issue: nil } } if unprocessable_response
|
67
|
+
|
68
|
+
response = Utils::Notion::Request.execute(params)
|
69
|
+
|
70
|
+
if response.code == 200
|
71
|
+
result = response.parsed_response["results"].first
|
72
|
+
|
73
|
+
{ success: { issue: read_response.data["request"], notion_wi: notion_wi_id(result) } }
|
74
|
+
else
|
75
|
+
{ error: { message: response.parsed_response, status_code: response.code } }
|
76
|
+
end
|
77
|
+
end
|
78
|
+
|
79
|
+
# write function to execute the PostgresDB write component
|
80
|
+
#
|
81
|
+
def write
|
82
|
+
options = write_options.merge({ tag: })
|
83
|
+
|
84
|
+
write = Write::Postgres.new(options, process_response)
|
85
|
+
|
86
|
+
write.execute
|
87
|
+
end
|
88
|
+
|
89
|
+
private
|
90
|
+
|
91
|
+
def conditions
|
92
|
+
{
|
93
|
+
where: "archived=$1 AND tag=$2 AND stage=$3 ORDER BY inserted_at ASC",
|
94
|
+
params: [false, read_options[:tag], "unprocessed"]
|
95
|
+
}
|
96
|
+
end
|
97
|
+
|
98
|
+
def params
|
99
|
+
{
|
100
|
+
endpoint: "databases/#{process_options[:database_id]}/query",
|
101
|
+
secret: process_options[:secret],
|
102
|
+
method: "post",
|
103
|
+
body:
|
104
|
+
}
|
105
|
+
end
|
106
|
+
|
107
|
+
def body
|
108
|
+
{
|
109
|
+
filter: {
|
110
|
+
property: "Github Issue id",
|
111
|
+
rich_text: { equals: read_response.data["request"]["id"].to_s }
|
112
|
+
}
|
113
|
+
}
|
114
|
+
end
|
115
|
+
|
116
|
+
def notion_wi_id(result)
|
117
|
+
return NOT_FOUND if result.nil?
|
118
|
+
|
119
|
+
result["id"]
|
120
|
+
end
|
121
|
+
|
122
|
+
def tag
|
123
|
+
issue = process_response[:success]
|
124
|
+
|
125
|
+
return write_options[:tag] if issue.nil? || issue[:notion_wi].nil?
|
126
|
+
|
127
|
+
issue[:notion_wi].eql?(NOT_FOUND) ? "CreateWorkItemRequest" : "UpdateWorkItemRequest"
|
128
|
+
end
|
129
|
+
end
|
130
|
+
end
|
@@ -0,0 +1,96 @@
|
|
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::WriteGithubIssueRequests class serves as a bot implementation to write GitHub issues
|
10
|
+
# request to be sent individually.
|
11
|
+
#
|
12
|
+
# <br>
|
13
|
+
# <b>Example</b>
|
14
|
+
#
|
15
|
+
# options = {
|
16
|
+
# read_options: {
|
17
|
+
# connection: {
|
18
|
+
# host: "localhost",
|
19
|
+
# port: 5432,
|
20
|
+
# dbname: "bas",
|
21
|
+
# user: "postgres",
|
22
|
+
# password: "postgres"
|
23
|
+
# },
|
24
|
+
# db_table: "github_issues",
|
25
|
+
# tag: "FetchGithubIssues"
|
26
|
+
# },
|
27
|
+
# process_options: {
|
28
|
+
# connection: {
|
29
|
+
# host: "localhost",
|
30
|
+
# port: 5432,
|
31
|
+
# dbname: "bas",
|
32
|
+
# user: "postgres",
|
33
|
+
# password: "postgres"
|
34
|
+
# },
|
35
|
+
# db_table: "github_issues",
|
36
|
+
# tag: "GithubIssueRequest"
|
37
|
+
# },
|
38
|
+
# write_options: {
|
39
|
+
# connection: {
|
40
|
+
# host: "localhost",
|
41
|
+
# port: 5432,
|
42
|
+
# dbname: "bas",
|
43
|
+
# user: "postgres",
|
44
|
+
# password: "postgres"
|
45
|
+
# },
|
46
|
+
# db_table: "github_issues",
|
47
|
+
# tag: "WriteGithubIssueRequests"
|
48
|
+
# }
|
49
|
+
# }
|
50
|
+
#
|
51
|
+
# bot = Bot::WriteGithubIssueRequests.new(options)
|
52
|
+
# bot.execute
|
53
|
+
#
|
54
|
+
class WriteGithubIssueRequests < Bot::Base
|
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 write GitHub issues requests.
|
64
|
+
#
|
65
|
+
def process
|
66
|
+
return { success: { created: nil } } if unprocessable_response
|
67
|
+
|
68
|
+
read_response.data["issues"].each { |request| create_request(request) }
|
69
|
+
|
70
|
+
{ success: { created: true } }
|
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 create_request(request)
|
91
|
+
write_data = { success: { request: } }
|
92
|
+
|
93
|
+
Write::Postgres.new(process_options, write_data).execute
|
94
|
+
end
|
95
|
+
end
|
96
|
+
end
|
@@ -0,0 +1,54 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "octokit"
|
4
|
+
require "openssl"
|
5
|
+
require "jwt"
|
6
|
+
|
7
|
+
module Utils
|
8
|
+
module Github
|
9
|
+
##
|
10
|
+
# This module is a Github utility for making requests to the Github API using the octokit module
|
11
|
+
#
|
12
|
+
class OctokitClient
|
13
|
+
def initialize(params)
|
14
|
+
@params = params
|
15
|
+
end
|
16
|
+
|
17
|
+
# Build the octokit client using a Github app access token
|
18
|
+
#
|
19
|
+
def execute
|
20
|
+
{ client: octokit }
|
21
|
+
rescue StandardError => e
|
22
|
+
{ error: e.to_s }
|
23
|
+
end
|
24
|
+
|
25
|
+
private
|
26
|
+
|
27
|
+
def octokit
|
28
|
+
Octokit::Client.new(bearer_token: access_token)
|
29
|
+
end
|
30
|
+
|
31
|
+
def access_token
|
32
|
+
app = Octokit::Client.new(client_id: @params[:app_id], bearer_token: jwt)
|
33
|
+
|
34
|
+
installation_id = app.find_organization_installation(@params[:organization]).id
|
35
|
+
|
36
|
+
app.create_app_installation_access_token(installation_id)[:token]
|
37
|
+
end
|
38
|
+
|
39
|
+
def jwt
|
40
|
+
private_key = OpenSSL::PKey::RSA.new(@params[:private_pem])
|
41
|
+
|
42
|
+
JWT.encode(jwt_payload, private_key, "RS256")
|
43
|
+
end
|
44
|
+
|
45
|
+
def jwt_payload
|
46
|
+
{
|
47
|
+
iat: Time.now.to_i - 60,
|
48
|
+
exp: Time.now.to_i + (10 * 60),
|
49
|
+
iss: @params[:app_id]
|
50
|
+
}
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
@@ -0,0 +1,64 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "httparty"
|
4
|
+
require_relative "request"
|
5
|
+
|
6
|
+
module Utils
|
7
|
+
module Notion
|
8
|
+
##
|
9
|
+
# This module is a Notion utility for deleting page blocks.
|
10
|
+
#
|
11
|
+
class DeletePageBlocks
|
12
|
+
# Implements the delete page blocks process logic to Notion.
|
13
|
+
#
|
14
|
+
# <br>
|
15
|
+
# <b>Params:</b>
|
16
|
+
# * <tt>page_id</tt> Id of the notion page.
|
17
|
+
# * <tt>secret</tt> Notion secret.
|
18
|
+
#
|
19
|
+
# <br>
|
20
|
+
# <b>returns</b> <tt>HTTParty::Response</tt>
|
21
|
+
#
|
22
|
+
#
|
23
|
+
def initialize(params)
|
24
|
+
@params = params
|
25
|
+
end
|
26
|
+
|
27
|
+
def execute
|
28
|
+
page_blocks_ids.each { |block_id| delete_block(block_id) }
|
29
|
+
end
|
30
|
+
|
31
|
+
private
|
32
|
+
|
33
|
+
def page_blocks_ids
|
34
|
+
page = Utils::Notion::Request.execute(page_params)
|
35
|
+
|
36
|
+
page.parsed_response["results"].map { |block| block["id"] }
|
37
|
+
end
|
38
|
+
|
39
|
+
def page_params
|
40
|
+
{
|
41
|
+
endpoint: "blocks/#{@params[:page_id]}/children",
|
42
|
+
secret: @params[:secret],
|
43
|
+
method: "get",
|
44
|
+
body: {}
|
45
|
+
}
|
46
|
+
end
|
47
|
+
|
48
|
+
def delete_block(block_id)
|
49
|
+
params = delete_params(block_id)
|
50
|
+
|
51
|
+
Utils::Notion::Request.execute(params)
|
52
|
+
end
|
53
|
+
|
54
|
+
def delete_params(block_id)
|
55
|
+
{
|
56
|
+
endpoint: "blocks/#{block_id}",
|
57
|
+
secret: @params[:secret],
|
58
|
+
method: "delete",
|
59
|
+
body: {}
|
60
|
+
}
|
61
|
+
end
|
62
|
+
end
|
63
|
+
end
|
64
|
+
end
|
@@ -0,0 +1,39 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Utils
|
4
|
+
module Notion
|
5
|
+
##
|
6
|
+
# This module is a Notion utility for formating standard notion types to
|
7
|
+
# filter or create.
|
8
|
+
#
|
9
|
+
module Types
|
10
|
+
def multi_select(name)
|
11
|
+
{ "multi_select" => [{ "name" => name }] }
|
12
|
+
end
|
13
|
+
|
14
|
+
def relation(id)
|
15
|
+
{ relation: [{ id: }] }
|
16
|
+
end
|
17
|
+
|
18
|
+
def select(name)
|
19
|
+
{ select: { name: } }
|
20
|
+
end
|
21
|
+
|
22
|
+
def rich_text(content, url = nil)
|
23
|
+
text = { content: }
|
24
|
+
|
25
|
+
text = text.merge({ link: { url: } }) unless url.nil?
|
26
|
+
|
27
|
+
{ rich_text: [{ text: }] }
|
28
|
+
end
|
29
|
+
|
30
|
+
def status(name)
|
31
|
+
{ status: { name: } }
|
32
|
+
end
|
33
|
+
|
34
|
+
def title(content)
|
35
|
+
{ title: [{ text: { content: } }] }
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
data/lib/bas/version.rb
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: bas
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.
|
4
|
+
version: 1.4.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- kommitters Open Source
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2024-07-
|
11
|
+
date: 2024-07-26 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: gmail_xoauth
|
@@ -187,12 +187,14 @@ files:
|
|
187
187
|
- lib/bas.rb
|
188
188
|
- lib/bas/bot/base.rb
|
189
189
|
- lib/bas/bot/compare_wip_limit_count.rb
|
190
|
+
- lib/bas/bot/create_work_item.rb
|
190
191
|
- lib/bas/bot/fetch_billing_from_digital_ocean.rb
|
191
192
|
- lib/bas/bot/fetch_birthdays_from_notion.rb
|
192
193
|
- lib/bas/bot/fetch_domain_services_from_notion.rb
|
193
194
|
- lib/bas/bot/fetch_domains_wip_counts_from_notion.rb
|
194
195
|
- lib/bas/bot/fetch_domains_wip_limit_from_notion.rb
|
195
196
|
- lib/bas/bot/fetch_emails_from_imap.rb
|
197
|
+
- lib/bas/bot/fetch_github_issues.rb
|
196
198
|
- lib/bas/bot/fetch_media_from_notion.rb
|
197
199
|
- lib/bas/bot/fetch_next_week_birthdays_from_notion.rb
|
198
200
|
- lib/bas/bot/fetch_next_week_ptos_from_notion.rb
|
@@ -208,7 +210,10 @@ files:
|
|
208
210
|
- lib/bas/bot/review_domain_availability.rb
|
209
211
|
- lib/bas/bot/review_media.rb
|
210
212
|
- lib/bas/bot/update_review_media_state.rb
|
213
|
+
- lib/bas/bot/update_work_item.rb
|
214
|
+
- lib/bas/bot/verify_issue_existance_in_notion.rb
|
211
215
|
- lib/bas/bot/write_domain_review_requests.rb
|
216
|
+
- lib/bas/bot/write_github_issue_requests.rb
|
212
217
|
- lib/bas/bot/write_media_review_in_notion.rb
|
213
218
|
- lib/bas/bot/write_media_review_requests.rb
|
214
219
|
- lib/bas/read/base.rb
|
@@ -219,9 +224,12 @@ files:
|
|
219
224
|
- lib/bas/utils/discord/integration.rb
|
220
225
|
- lib/bas/utils/exceptions/function_not_implemented.rb
|
221
226
|
- lib/bas/utils/exceptions/invalid_process_response.rb
|
227
|
+
- lib/bas/utils/github/octokit_client.rb
|
222
228
|
- lib/bas/utils/google/send_email.rb
|
223
229
|
- lib/bas/utils/imap/request.rb
|
230
|
+
- lib/bas/utils/notion/delete_page_blocks.rb
|
224
231
|
- lib/bas/utils/notion/request.rb
|
232
|
+
- lib/bas/utils/notion/types.rb
|
225
233
|
- lib/bas/utils/notion/update_db_state.rb
|
226
234
|
- lib/bas/utils/openai/run_assistant.rb
|
227
235
|
- lib/bas/utils/postgres/request.rb
|