-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathpostgres_ci--0.2--0.3.sql
More file actions
378 lines (323 loc) · 11.5 KB
/
postgres_ci--0.2--0.3.sql
File metadata and controls
378 lines (323 loc) · 11.5 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
create schema notification;
grant usage on schema notification to public;
grant execute on all functions in schema notification to public;
drop index postgres_ci.find_user;
create unlogged table postgres_ci.notification(
build_id int not null references postgres_ci.builds(build_id) primary key,
created_at timestamptz not null default current_timestamp
);
create type postgres_ci.notification_method as enum (
'none',
'email',
'telegram'
);
create table postgres_ci.user_notification_method(
user_id int not null references postgres_ci.users(user_id) primary key,
method postgres_ci.notification_method not null default 'none',
text_id text not null,
int_id bigint not null default 0
);
select pg_catalog.pg_extension_config_dump('postgres_ci.user_notification_method', '');
create unique index unique_user_notification_method
on postgres_ci.user_notification_method (method, lower(text_id))
where method <> 'none' and text_id <> '';
insert into postgres_ci.user_notification_method (user_id, method, text_id)
select user_id, 'email', user_email from postgres_ci.users;
create or replace function notification.fetch() returns table (
build_id int,
build_status postgres_ci.status,
project_id int,
project_name text,
branch text,
build_error text,
build_created_at timestamptz,
build_started_at timestamptz,
build_finished_at timestamptz,
commit_sha text,
commit_message text,
committed_at timestamptz,
committer_name text,
committer_email text,
commit_author_name text,
commit_author_email text,
send_to jsonb
) as $$
declare
_build_id int;
begin
SELECT
N.build_id INTO _build_id
FROM postgres_ci.notification AS N
ORDER BY N.build_id
LIMIT 1
FOR UPDATE SKIP LOCKED;
IF NOT FOUND THEN
return;
END IF;
return query
SELECT
B.build_id,
B.status,
P.project_id,
P.project_name,
BR.branch,
B.error,
B.created_at,
B.started_at,
B.finished_at,
C.commit_sha,
C.commit_message,
C.committed_at,
C.committer_name,
C.committer_email,
C.author_name,
C.author_email,
(
SELECT
COALESCE(array_to_json(array_agg(P.*)), '[]')
FROM (
SELECT
U.user_name,
M.method AS notify_method,
M.text_id AS notify_text_id,
M.int_id AS notify_int_id
FROM postgres_ci.users AS U
JOIN postgres_ci.user_notification_method AS M ON U.user_id = M.user_id
WHERE U.user_id IN (
SELECT
P.project_owner_id
UNION ALL
SELECT
U.user_id
FROM postgres_ci.users AS U
WHERE U.user_email IN (lower(C.author_email), lower(C.committer_email))
) AND M.method <> 'none'
) AS P
)::jsonb
FROM postgres_ci.builds AS B
JOIN postgres_ci.projects AS P ON P.project_id = B.project_id
JOIN postgres_ci.commits AS C ON C.commit_id = B.commit_id
JOIN postgres_ci.branches AS BR ON BR.branch_id = B.branch_id
WHERE B.build_id = _build_id;
DELETE FROM postgres_ci.notification AS N WHERE N.build_id = _build_id;
end;
$$ language plpgsql security definer rows 1;
create or replace function users.add(
_user_login text,
_password text,
_user_name text,
_user_email text,
_is_superuser boolean,
out user_id int
) returns int as $$
declare
_salt text;
_message text;
_column_name text;
_constraint_name text;
_datatype_name text;
_table_name text;
_schema_name text;
begin
_salt = postgres_ci.sha1(gen_salt('md5') || current_timestamp);
BEGIN
INSERT INTO postgres_ci.users (
user_login,
user_name,
user_email,
is_superuser,
hash,
salt
) VALUES (
_user_login,
_user_name,
_user_email,
_is_superuser,
encode(digest(_salt || _password, 'sha1'), 'hex'),
_salt
) RETURNING users.user_id INTO user_id;
INSERT INTO postgres_ci.user_notification_method (user_id, method, text_id) VALUES (add.user_id, 'email', _user_email);
EXCEPTION WHEN OTHERS THEN
GET STACKED DIAGNOSTICS
_column_name = column_name,
_constraint_name = constraint_name,
_datatype_name = pg_datatype_name,
_table_name = table_name,
_schema_name = schema_name;
CASE
WHEN _constraint_name = 'unique_user_login' THEN
_message = 'LOGIN_ALREADY_EXISTS';
WHEN _constraint_name = 'unique_user_email' THEN
_message = 'EMAIL_ALREADY_EXISTS';
WHEN _constraint_name = 'check_user_email' THEN
_message = 'INVALID_EMAIL';
ELSE
_message = SQLERRM;
END CASE;
RAISE EXCEPTION USING
MESSAGE = _message,
ERRCODE = SQLSTATE,
COLUMN = _column_name,
CONSTRAINT = _constraint_name,
DATATYPE = _datatype_name,
TABLE = _table_name,
SCHEMA = _schema_name;
END;
end;
$$ language plpgsql security definer;
create or replace function notification.update_method(
_user_id int,
_method postgres_ci.notification_method,
_text_id text
) returns void as $$
begin
CASE
WHEN _method = 'none' THEN
UPDATE postgres_ci.user_notification_method
SET
method = _method,
text_id = '',
int_id = 0
WHERE user_id = _user_id;
ELSE
UPDATE postgres_ci.user_notification_method
SET
method = _method,
text_id = _text_id,
int_id = 0
WHERE user_id = _user_id AND NOT (
text_id = _text_id AND method = _method
);
END CASE;
end;
$$ language plpgsql security definer;
create or replace function notification.bind_with_telegram(
_user_id int,
_telegram_username text,
_telegram_id bigint
) returns void as $$
begin
UPDATE postgres_ci.user_notification_method
SET
int_id = _telegram_id
WHERE user_id = _user_id
AND method = 'telegram'
AND text_id = _telegram_username;
IF NOT FOUND THEN
RAISE EXCEPTION 'NOT_FOUND' USING ERRCODE = 'no_data_found';
END IF;
end;
$$ language plpgsql security definer;
create or replace function notification.find_user_by_telegram_username(_telegram_username text) returns table (
user_id int,
telegram_id bigint
) as $$
begin
return query
SELECT
N.user_id,
N.int_id
FROM postgres_ci.user_notification_method AS N
WHERE N.method = 'telegram'
AND N.text_id = _telegram_username;
end;
$$ language plpgsql security definer rows 1;
create or replace function build.stop(_build_id int, _config text, _error text) returns void as $$
begin
UPDATE postgres_ci.builds
SET
config = _config,
error = _error,
status = (
CASE
WHEN _error = '' THEN 'success'
ELSE 'failed'
END
)::postgres_ci.status,
finished_at = current_timestamp
WHERE build_id = _build_id
AND status = 'running';
IF NOT FOUND THEN
RAISE EXCEPTION 'NOT_FOUND' USING ERRCODE = 'no_data_found';
END IF;
PERFORM build.notify(_build_id);
IF EXISTS(
SELECT
FROM postgres_ci.parts
WHERE build_id = _build_id
AND success IS False
LIMIT 1
) THEN
UPDATE postgres_ci.builds SET status = 'failed'::postgres_ci.status WHERE build_id = _build_id;
END IF;
end;
$$ language plpgsql security definer;
create or replace function build.gc() returns void as $$
declare
_build_id int;
begin
FOR _build_id IN
SELECT
build_id
FROM postgres_ci.builds
WHERE status IN ('accepted', 'running')
AND created_at < (current_timestamp - '1 hour'::interval)
ORDER BY build_id
LOOP
UPDATE postgres_ci.builds AS B
SET
status = 'failed',
error = 'Execution timeout',
finished_at = current_timestamp
WHERE B.build_id = _build_id;
PERFORM
pg_notify('postgres-ci::stop_container', (
SELECT to_json(T.*) FROM (
SELECT
P.container_id,
current_timestamp AS created_at
) T
)::text
)
FROM postgres_ci.parts AS P
WHERE P.build_id = _build_id;
PERFORM build.notify(_build_id);
END LOOP;
end;
$$ language plpgsql security definer;
create or replace function build.notify(_build_id int) returns boolean as $$
begin
INSERT INTO postgres_ci.notification (build_id) VALUES (_build_id);
PERFORM pg_notify('postgres-ci::notification', (
SELECT to_json(T.*) FROM (
SELECT
_build_id AS build_id,
CURRENT_TIMESTAMP AS created_at
) T
)::text
);
return true;
end;
$$ language plpgsql security definer;
create or replace function notification.get_method(
_user_id int,
out method text,
out text_id text,
out int_id bigint
) returns record as $$
begin
SELECT
M.method,
M.text_id,
M.int_id
INTO
method,
text_id,
int_id
FROM postgres_ci.user_notification_method AS M
WHERE M.user_id = _user_id;
IF NOT FOUND THEN
RAISE EXCEPTION 'NOT_FOUND' USING ERRCODE = 'no_data_found';
END IF;
end;
$$ language plpgsql security definer;