Compare commits
No commits in common. "main" and "migrations" have entirely different histories.
main
...
migrations
@ -1,3 +0,0 @@
|
|||||||
POSTGRES_USER=postgres
|
|
||||||
POSTGRES_PASSWORD=password
|
|
||||||
POSTGRES_DB=dnim
|
|
@ -1,2 +0,0 @@
|
|||||||
POSTGRES_USER=postgres
|
|
||||||
POSTGRES_PASSWORD=password
|
|
@ -1,23 +0,0 @@
|
|||||||
FROM node:20-bookworm
|
|
||||||
|
|
||||||
ENV PIP_BREAK_SYSTEM_PACKAGES 1
|
|
||||||
|
|
||||||
RUN apt-get update && apt-get upgrade -y
|
|
||||||
RUN DEBIAN_FRONTEND=noninteractive apt-get install -y --no-install-recommends tzdata \
|
|
||||||
&& apt-get install -y curl ca-certificates gnupg postgresql-common \
|
|
||||||
&& YES=y sh /usr/share/postgresql-common/pgdg/apt.postgresql.org.sh \
|
|
||||||
&& apt-get install -y postgresql-15
|
|
||||||
RUN apt-get update \
|
|
||||||
&& install -m 0755 -d /etc/apt/keyrings \
|
|
||||||
&& curl -fsSL https://download.docker.com/linux/debian/gpg | gpg --dearmor -o /etc/apt/keyrings/docker.gpg \
|
|
||||||
&& chmod a+r /etc/apt/keyrings/docker.gpg \
|
|
||||||
&& echo \
|
|
||||||
"deb [arch="$(dpkg --print-architecture)" signed-by=/etc/apt/keyrings/docker.gpg] https://download.docker.com/linux/debian \
|
|
||||||
"$(. /etc/os-release && echo "$VERSION_CODENAME")" stable" | tee /etc/apt/sources.list.d/docker.list > /dev/null \
|
|
||||||
&& apt-get update \
|
|
||||||
&& apt-get install -y docker-ce-cli docker-compose-plugin
|
|
||||||
RUN set -x \
|
|
||||||
&& apt-get install -y python3 python3-pip \
|
|
||||||
&& pip install psycopg2-binary \
|
|
||||||
&& pip install pg8000 \
|
|
||||||
&& pip install migra
|
|
@ -1,44 +0,0 @@
|
|||||||
name: 'gen-migrations'
|
|
||||||
on: { push: { branches: ['main'] } }
|
|
||||||
|
|
||||||
jobs:
|
|
||||||
gen-migrations:
|
|
||||||
if: |
|
|
||||||
!startsWith(gitea.event.head_commit.message, 'chore')
|
|
||||||
container:
|
|
||||||
image: 'git.orionkindel.com/dnim/db-ci-runner:specified-policeman-saw-kindly'
|
|
||||||
volumes:
|
|
||||||
- '/run/user/1001/docker.sock:/run/user/1001/docker.sock'
|
|
||||||
- '/var/run/postgresql:/var/run/postgresql'
|
|
||||||
steps:
|
|
||||||
- uses: 'actions/checkout@v3'
|
|
||||||
with: { fetch-depth: 0, submodules: 'recursive', token: '${{ secrets._GITEA_TOKEN }}' }
|
|
||||||
- name: 'git config'
|
|
||||||
run: |
|
|
||||||
git config --global user.email 'noreply@dnim.org'
|
|
||||||
git config --global user.name '🤖'
|
|
||||||
- name: 'update migrations submodule (and push if needed)'
|
|
||||||
run: |
|
|
||||||
set -ex
|
|
||||||
git fetch --all --recurse-submodules
|
|
||||||
git submodule update --init --remote migrations;
|
|
||||||
git add -A
|
|
||||||
git commit -m 'chore: update migrations' || true
|
|
||||||
git push || true
|
|
||||||
- name: 'gen migrations (and push if needed)'
|
|
||||||
run: |
|
|
||||||
set -ex
|
|
||||||
./scripts/gen_migrations.sh
|
|
||||||
if ! (git diff-index --quiet HEAD --ignore-submodules=none); then
|
|
||||||
cd migrations
|
|
||||||
git switch migrations
|
|
||||||
git add -A
|
|
||||||
git commit -m 'chore: babe wake up new migrations just dropped'
|
|
||||||
git push -u origin migrations
|
|
||||||
cd ../
|
|
||||||
git add -A
|
|
||||||
git commit -m 'chore: update migrations'
|
|
||||||
git push
|
|
||||||
fi
|
|
||||||
env:
|
|
||||||
DOCKER_HOST: 'unix:///run/user/1001/docker.sock' # HACK: rootless docker on gitea action runner
|
|
@ -1,15 +0,0 @@
|
|||||||
name: 'migrate-devel'
|
|
||||||
on: { push: { branches: ['main'], paths: ['migrations'] } }
|
|
||||||
|
|
||||||
jobs:
|
|
||||||
migrate-devel:
|
|
||||||
container:
|
|
||||||
image: 'git.orionkindel.com/dnim/db-ci-runner:specified-policeman-saw-kindly'
|
|
||||||
volumes: ['/run/user/1001/docker.sock:/run/user/1001/docker.sock']
|
|
||||||
steps:
|
|
||||||
- uses: 'actions/checkout@v3'
|
|
||||||
with: { fetch-depth: 0, ref: 'main', submodules: 'recursive' }
|
|
||||||
- run: './scripts/migrate.sh'
|
|
||||||
env:
|
|
||||||
DOCKER_HOST: 'unix:///run/user/1001/docker.sock' # HACK: rootless docker on gitea action runner
|
|
||||||
POSTGRES_URI: '${{ secrets.POSTGRES_DEVEL_URI }}'
|
|
@ -1,15 +0,0 @@
|
|||||||
name: 'migrate-stage'
|
|
||||||
on: { push: { branches: ['main'], paths: ['migrations'] } }
|
|
||||||
|
|
||||||
jobs:
|
|
||||||
migrate-stage:
|
|
||||||
container:
|
|
||||||
image: 'git.orionkindel.com/dnim/db-ci-runner:specified-policeman-saw-kindly'
|
|
||||||
volumes: ['/run/user/1001/docker.sock:/run/user/1001/docker.sock']
|
|
||||||
steps:
|
|
||||||
- uses: 'actions/checkout@v3'
|
|
||||||
with: { fetch-depth: 0, ref: 'main', submodules: 'recursive' }
|
|
||||||
- run: './scripts/migrate.sh'
|
|
||||||
env:
|
|
||||||
DOCKER_HOST: 'unix:///run/user/1001/docker.sock' # HACK: rootless docker on gitea action runner
|
|
||||||
POSTGRES_URI: '${{ secrets.POSTGRES_STAGE_URI }}'
|
|
5
.gitignore
vendored
5
.gitignore
vendored
@ -1,5 +0,0 @@
|
|||||||
.env
|
|
||||||
data
|
|
||||||
tmp
|
|
||||||
head
|
|
||||||
base
|
|
4
.gitmodules
vendored
4
.gitmodules
vendored
@ -1,4 +0,0 @@
|
|||||||
[submodule "migrations"]
|
|
||||||
branch = migrations
|
|
||||||
path = migrations
|
|
||||||
url = git@git.orionkindel.com:dnim/db
|
|
@ -1 +0,0 @@
|
|||||||
postgres 15.3
|
|
1
01ee432_to_658ad01.sql
Normal file
1
01ee432_to_658ad01.sql
Normal file
@ -0,0 +1 @@
|
|||||||
|
|
1
032c1f7_to_3c7189c.sql
Normal file
1
032c1f7_to_3c7189c.sql
Normal file
@ -0,0 +1 @@
|
|||||||
|
|
33
047a51b_to_49bed63.sql
Normal file
33
047a51b_to_49bed63.sql
Normal file
@ -0,0 +1,33 @@
|
|||||||
|
alter type "public"."usr_username" rename attribute "username" to "str" cascade;
|
||||||
|
|
||||||
|
set check_function_bodies = off;
|
||||||
|
|
||||||
|
CREATE OR REPLACE FUNCTION public.create_newtype_text(qualified_name text)
|
||||||
|
RETURNS void
|
||||||
|
LANGUAGE plpgsql
|
||||||
|
AS $function$
|
||||||
|
begin
|
||||||
|
execute concat('create type ', qualified_name, ' as (str text);');
|
||||||
|
execute concat( 'create function '
|
||||||
|
, qualified_name || '_to_string(val ' || qualified_name || ')'
|
||||||
|
, E' returns text language sql as \'select (val.str);\';'
|
||||||
|
);
|
||||||
|
execute concat( 'create function '
|
||||||
|
, qualified_name || '_of_string(val text)'
|
||||||
|
, ' returns ' || qualified_name || E' language sql as \'select row(val);\';'
|
||||||
|
);
|
||||||
|
end;
|
||||||
|
$function$
|
||||||
|
;
|
||||||
|
|
||||||
|
CREATE OR REPLACE FUNCTION public.usr_username_of_string(val text)
|
||||||
|
RETURNS usr_username
|
||||||
|
LANGUAGE sql
|
||||||
|
AS $function$select row(val);$function$
|
||||||
|
;
|
||||||
|
|
||||||
|
CREATE OR REPLACE FUNCTION public.usr_username_to_string(val usr_username)
|
||||||
|
RETURNS text
|
||||||
|
LANGUAGE sql
|
||||||
|
AS $function$select (val.str);$function$
|
||||||
|
;
|
1
04ffd5d_to_d89a4fa.sql
Normal file
1
04ffd5d_to_d89a4fa.sql
Normal file
@ -0,0 +1 @@
|
|||||||
|
|
1
0502154_to_87f7a4d.sql
Normal file
1
0502154_to_87f7a4d.sql
Normal file
@ -0,0 +1 @@
|
|||||||
|
|
1
053511d_to_70a8bca.sql
Normal file
1
053511d_to_70a8bca.sql
Normal file
@ -0,0 +1 @@
|
|||||||
|
|
1
0728ba9_to_442d4e8.sql
Normal file
1
0728ba9_to_442d4e8.sql
Normal file
@ -0,0 +1 @@
|
|||||||
|
|
192
0b9c597_to_0502154.sql
Normal file
192
0b9c597_to_0502154.sql
Normal file
@ -0,0 +1,192 @@
|
|||||||
|
create type "public"."usr_session_device" as enum ('linux', 'macos', 'win', 'android', 'ios', 'other');
|
||||||
|
|
||||||
|
create type "public"."usr_tag_or_email" as ("str" text);
|
||||||
|
|
||||||
|
CREATE OR REPLACE FUNCTION public.usr_tag_or_email_of_string(val text)
|
||||||
|
RETURNS usr_tag_or_email
|
||||||
|
LANGUAGE sql
|
||||||
|
AS $function$select row(val);$function$
|
||||||
|
;
|
||||||
|
|
||||||
|
CREATE OR REPLACE FUNCTION public.usr_tag_or_email_to_email(toe usr_tag_or_email)
|
||||||
|
RETURNS email
|
||||||
|
LANGUAGE plpgsql
|
||||||
|
IMMUTABLE
|
||||||
|
AS $function$
|
||||||
|
begin
|
||||||
|
if position('@' in usr_tag_or_email_to_string(toe)) > 0 then
|
||||||
|
return email_of_string(usr_tag_or_email_to_string(toe));
|
||||||
|
else
|
||||||
|
return null;
|
||||||
|
end if;
|
||||||
|
end;
|
||||||
|
$function$
|
||||||
|
;
|
||||||
|
|
||||||
|
CREATE OR REPLACE FUNCTION public.usr_tag_or_email_to_string(val usr_tag_or_email)
|
||||||
|
RETURNS text
|
||||||
|
LANGUAGE sql
|
||||||
|
AS $function$select (val.str);$function$
|
||||||
|
;
|
||||||
|
|
||||||
|
CREATE OR REPLACE FUNCTION public.usr_tag_or_email_to_tag(toe usr_tag_or_email)
|
||||||
|
RETURNS usr_tag
|
||||||
|
LANGUAGE plpgsql
|
||||||
|
IMMUTABLE
|
||||||
|
AS $function$
|
||||||
|
begin
|
||||||
|
if usr_tag_or_email_to_email(toe) is null then
|
||||||
|
return usr_tag_of_string(usr_tag_or_email_to_string(toe));
|
||||||
|
else
|
||||||
|
return null;
|
||||||
|
end if;
|
||||||
|
end;
|
||||||
|
$function$
|
||||||
|
;
|
||||||
|
|
||||||
|
|
||||||
|
create type "public"."usr_session_key" as ("str" text);
|
||||||
|
|
||||||
|
CREATE OR REPLACE FUNCTION public.usr_session_key_of_string(val text)
|
||||||
|
RETURNS usr_session_key
|
||||||
|
LANGUAGE sql
|
||||||
|
AS $function$select row(val);$function$
|
||||||
|
;
|
||||||
|
|
||||||
|
CREATE OR REPLACE FUNCTION public.usr_session_key_to_string(val usr_session_key)
|
||||||
|
RETURNS text
|
||||||
|
LANGUAGE sql
|
||||||
|
AS $function$select (val.str);$function$
|
||||||
|
;
|
||||||
|
|
||||||
|
CREATE OR REPLACE FUNCTION public.usr_session_key_gen()
|
||||||
|
RETURNS usr_session_key
|
||||||
|
LANGUAGE sql
|
||||||
|
AS $function$
|
||||||
|
select usr_session_key_of_string(
|
||||||
|
md5(extract(epoch from now()) || gen_random_bytes(32) :: text)
|
||||||
|
);
|
||||||
|
$function$
|
||||||
|
;
|
||||||
|
|
||||||
|
|
||||||
|
create table "public"."usr_session" (
|
||||||
|
"id" integer generated always as identity not null,
|
||||||
|
"key" usr_session_key not null default usr_session_key_gen(),
|
||||||
|
"expired" boolean not null default false,
|
||||||
|
"expires_at" timestamp without time zone not null,
|
||||||
|
"usr" integer not null,
|
||||||
|
"location" text,
|
||||||
|
"device" usr_session_device,
|
||||||
|
"ip" inet
|
||||||
|
);
|
||||||
|
|
||||||
|
|
||||||
|
CREATE UNIQUE INDEX usr_session_key_key ON public.usr_session USING btree (key);
|
||||||
|
|
||||||
|
CREATE UNIQUE INDEX usr_session_pkey ON public.usr_session USING btree (id);
|
||||||
|
|
||||||
|
alter table "public"."usr_session" add constraint "usr_session_pkey" PRIMARY KEY using index "usr_session_pkey";
|
||||||
|
|
||||||
|
alter table "public"."usr_session" add constraint "usr_session_key_key" UNIQUE using index "usr_session_key_key";
|
||||||
|
|
||||||
|
alter table "public"."usr_session" add constraint "usr_session_usr_fkey" FOREIGN KEY (usr) REFERENCES usr(id) not valid;
|
||||||
|
|
||||||
|
alter table "public"."usr_session" validate constraint "usr_session_usr_fkey";
|
||||||
|
|
||||||
|
set check_function_bodies = off;
|
||||||
|
|
||||||
|
CREATE OR REPLACE FUNCTION public.do_usr_session_immutable_columns()
|
||||||
|
RETURNS trigger
|
||||||
|
LANGUAGE plpgsql
|
||||||
|
AS $function$
|
||||||
|
begin
|
||||||
|
if OLD.id <> NEW.id then
|
||||||
|
raise exception 'public.usr_session.id is immutable' using errcode = 'restrict_violation';
|
||||||
|
elsif OLD.key <> NEW.key then
|
||||||
|
raise exception 'public.usr_session.key is immutable' using errcode = 'restrict_violation';
|
||||||
|
elsif OLD.expires_at <> NEW.expires_at then
|
||||||
|
raise exception 'public.usr_session.expires_at is immutable' using errcode = 'restrict_violation';
|
||||||
|
elsif OLD.usr <> NEW.usr then
|
||||||
|
raise exception 'public.usr_session.usr is immutable' using errcode = 'restrict_violation';
|
||||||
|
elsif OLD.location <> NEW.location then
|
||||||
|
raise exception 'public.usr_session.location is immutable' using errcode = 'restrict_violation';
|
||||||
|
elsif OLD.device <> NEW.device then
|
||||||
|
raise exception 'public.usr_session.device is immutable' using errcode = 'restrict_violation';
|
||||||
|
elsif OLD.ip <> NEW.ip then
|
||||||
|
raise exception 'public.usr_session.ip is immutable' using errcode = 'restrict_violation';
|
||||||
|
end if;
|
||||||
|
|
||||||
|
return NEW;
|
||||||
|
end;
|
||||||
|
$function$
|
||||||
|
;
|
||||||
|
|
||||||
|
CREATE OR REPLACE FUNCTION public.usr_session_login(tag_or_email usr_tag_or_email, password text, remember boolean DEFAULT false, location text DEFAULT NULL::text, device usr_session_device DEFAULT NULL::usr_session_device, ip inet DEFAULT NULL::inet)
|
||||||
|
RETURNS usr_session_key
|
||||||
|
LANGUAGE plpgsql
|
||||||
|
AS $function$
|
||||||
|
declare
|
||||||
|
usr public.usr;
|
||||||
|
key public.usr_session_key;
|
||||||
|
expires_at timestamp;
|
||||||
|
begin
|
||||||
|
usr := public.usr_session_login_validate(tag_or_email, password);
|
||||||
|
|
||||||
|
if remember then
|
||||||
|
expires_at := now() + interval '1 week';
|
||||||
|
else
|
||||||
|
expires_at := now() + interval '1 hour';
|
||||||
|
end if;
|
||||||
|
|
||||||
|
insert into public.usr_session
|
||||||
|
(expires_at, usr, location, device, ip)
|
||||||
|
values
|
||||||
|
(expires_at, usr.id, location, device, ip)
|
||||||
|
returning usr_session.key
|
||||||
|
into key;
|
||||||
|
|
||||||
|
return key;
|
||||||
|
end;
|
||||||
|
$function$
|
||||||
|
;
|
||||||
|
|
||||||
|
CREATE OR REPLACE FUNCTION public.usr_session_login_validate(tag_or_email usr_tag_or_email, password text)
|
||||||
|
RETURNS usr
|
||||||
|
LANGUAGE plpgsql
|
||||||
|
STABLE
|
||||||
|
AS $function$
|
||||||
|
declare
|
||||||
|
usr_email public.email := public.usr_tag_or_email_to_email(tag_or_email);
|
||||||
|
usr_tag public.usr_tag := public.usr_tag_or_email_to_tag(tag_or_email);
|
||||||
|
usr public.usr;
|
||||||
|
begin
|
||||||
|
select *
|
||||||
|
from public.usr as u
|
||||||
|
where u.email = usr_email
|
||||||
|
or u.tag = usr_tag
|
||||||
|
into usr;
|
||||||
|
|
||||||
|
if usr.id = 1 or usr.tag = usr_tag_of_string('system') then
|
||||||
|
raise notice 'system user may not be logged into';
|
||||||
|
raise exception 'incorrect password for user %', usr_tag_or_email_to_string(tag_or_email);
|
||||||
|
end if;
|
||||||
|
|
||||||
|
if usr is null then
|
||||||
|
-- prevent email guess bruteforces by raising the same exception
|
||||||
|
-- for invalid password and user not found
|
||||||
|
raise notice 'user % not found', usr_tag_or_email_to_string(tag_or_email);
|
||||||
|
raise exception 'incorrect password for user %', usr_tag_or_email_to_string(tag_or_email);
|
||||||
|
end if;
|
||||||
|
|
||||||
|
if not hashed_text_matches(password, usr.password) then
|
||||||
|
raise notice 'password does not match for user %', usr_tag_or_email_to_string(tag_or_email);
|
||||||
|
raise exception 'incorrect password for user %', usr_tag_or_email_to_string(tag_or_email);
|
||||||
|
end if;
|
||||||
|
|
||||||
|
return usr;
|
||||||
|
end;
|
||||||
|
$function$
|
||||||
|
;
|
||||||
|
|
||||||
|
CREATE TRIGGER trigger_usr_session_immutable_columns BEFORE UPDATE ON public.usr_session FOR EACH ROW EXECUTE FUNCTION do_usr_session_immutable_columns();
|
1
0d639e8_to_bfbd8ff.sql
Normal file
1
0d639e8_to_bfbd8ff.sql
Normal file
@ -0,0 +1 @@
|
|||||||
|
|
1
0db5ca4_to_0b9c597.sql
Normal file
1
0db5ca4_to_0b9c597.sql
Normal file
@ -0,0 +1 @@
|
|||||||
|
|
1
0e93478_to_1590c59.sql
Normal file
1
0e93478_to_1590c59.sql
Normal file
@ -0,0 +1 @@
|
|||||||
|
|
1
0eb9b42_to_2c288ef.sql
Normal file
1
0eb9b42_to_2c288ef.sql
Normal file
@ -0,0 +1 @@
|
|||||||
|
|
1
111338a_skipped.sql
Normal file
1
111338a_skipped.sql
Normal file
@ -0,0 +1 @@
|
|||||||
|
|
1
1590c59_to_01ee432.sql
Normal file
1
1590c59_to_01ee432.sql
Normal file
@ -0,0 +1 @@
|
|||||||
|
|
1
1652073_skipped.sql
Normal file
1
1652073_skipped.sql
Normal file
@ -0,0 +1 @@
|
|||||||
|
|
1
16a20c2_to_dcd1193.sql
Normal file
1
16a20c2_to_dcd1193.sql
Normal file
@ -0,0 +1 @@
|
|||||||
|
|
1
19fc181_to_d94188f.sql
Normal file
1
19fc181_to_d94188f.sql
Normal file
@ -0,0 +1 @@
|
|||||||
|
|
91
1bf3d29_to_c83a4ce.sql
Normal file
91
1bf3d29_to_c83a4ce.sql
Normal file
@ -0,0 +1,91 @@
|
|||||||
|
set check_function_bodies = off;
|
||||||
|
|
||||||
|
CREATE OR REPLACE FUNCTION public.grp_admins()
|
||||||
|
RETURNS grp
|
||||||
|
LANGUAGE sql
|
||||||
|
STABLE
|
||||||
|
AS $function$select * from public.grp where tag = public.grp_tag_of_string('admins')$function$
|
||||||
|
;
|
||||||
|
|
||||||
|
CREATE OR REPLACE FUNCTION public.usr_root()
|
||||||
|
RETURNS usr
|
||||||
|
LANGUAGE sql
|
||||||
|
STABLE
|
||||||
|
AS $function$select * from public.usr where tag = public.usr_tag_of_string('root')$function$
|
||||||
|
;
|
||||||
|
|
||||||
|
CREATE OR REPLACE FUNCTION public.do_insert_usr_perm()
|
||||||
|
RETURNS trigger
|
||||||
|
LANGUAGE plpgsql
|
||||||
|
AS $function$
|
||||||
|
declare
|
||||||
|
admins int;
|
||||||
|
begin
|
||||||
|
admins := public.grp_admins();
|
||||||
|
|
||||||
|
insert into public.perm
|
||||||
|
(path, owner_user, owner_group, owner_user_mode, owner_group_mode, everyone_mode)
|
||||||
|
values
|
||||||
|
('/users/' || NEW.id || '/tag', NEW.id, admins, 'w', 'w', 'r')
|
||||||
|
, ('/users/' || NEW.id || '/email', NEW.id, admins, 'w', 'w', '-')
|
||||||
|
, ('/users/' || NEW.id || '/deleted', NEW.id, admins, 'w', 'w', '-')
|
||||||
|
, ('/users/' || NEW.id || '/password', NEW.id, admins, 'w', 'w', '-')
|
||||||
|
;
|
||||||
|
|
||||||
|
return new;
|
||||||
|
end;
|
||||||
|
$function$
|
||||||
|
;
|
||||||
|
|
||||||
|
CREATE OR REPLACE FUNCTION public.do_usr_create_default_grp()
|
||||||
|
RETURNS trigger
|
||||||
|
LANGUAGE plpgsql
|
||||||
|
AS $function$
|
||||||
|
declare
|
||||||
|
new_grp int;
|
||||||
|
begin
|
||||||
|
insert into public.grp (tag)
|
||||||
|
values (grp_tag_of_string('usr_' || new.uid))
|
||||||
|
returning id into new_grp;
|
||||||
|
|
||||||
|
perform public.grp_add_member(to_grp => new_grp, add_usr => new.id);
|
||||||
|
|
||||||
|
update public.perm
|
||||||
|
set owner_user = public.usr_root()
|
||||||
|
, owner_group = public.grp_admins()
|
||||||
|
where path = '/groups/' || new_grp || '/members'
|
||||||
|
or path = '/groups/' || new_grp || '/tag';
|
||||||
|
|
||||||
|
return null;
|
||||||
|
end;
|
||||||
|
$function$
|
||||||
|
;
|
||||||
|
|
||||||
|
CREATE OR REPLACE FUNCTION public.get_acting_usr()
|
||||||
|
RETURNS usr
|
||||||
|
LANGUAGE plpgsql
|
||||||
|
AS $function$
|
||||||
|
declare
|
||||||
|
uid text;
|
||||||
|
acting_usr public.usr;
|
||||||
|
begin
|
||||||
|
if nullif(current_setting('dnim.usr_uid', true), '') is null then
|
||||||
|
acting_usr := public.usr_root();
|
||||||
|
else
|
||||||
|
select u.*
|
||||||
|
from public.usr u
|
||||||
|
where u.uid = current_setting('dnim.usr_uid', true) :: uuid
|
||||||
|
into acting_usr;
|
||||||
|
end if;
|
||||||
|
|
||||||
|
return acting_usr;
|
||||||
|
end;
|
||||||
|
$function$
|
||||||
|
;
|
||||||
|
|
||||||
|
CREATE OR REPLACE FUNCTION public.grp_members_admins()
|
||||||
|
RETURNS SETOF usr
|
||||||
|
LANGUAGE sql
|
||||||
|
STABLE
|
||||||
|
AS $function$select * from public.grp_members((public.grp_admins()).id)$function$
|
||||||
|
;
|
1
1c76bcb_skipped.sql
Normal file
1
1c76bcb_skipped.sql
Normal file
@ -0,0 +1 @@
|
|||||||
|
|
1
1dae8d2_to_e758bc6.sql
Normal file
1
1dae8d2_to_e758bc6.sql
Normal file
@ -0,0 +1 @@
|
|||||||
|
|
440
202de79_to_5f9c3c7.sql
Normal file
440
202de79_to_5f9c3c7.sql
Normal file
@ -0,0 +1,440 @@
|
|||||||
|
alter table "public"."usr_session" drop column "expired";
|
||||||
|
|
||||||
|
alter table "public"."usr_session" add column "remembered" boolean not null default false;
|
||||||
|
|
||||||
|
set check_function_bodies = off;
|
||||||
|
|
||||||
|
CREATE OR REPLACE FUNCTION public.usr_session_touch(session usr_session_key)
|
||||||
|
RETURNS usr
|
||||||
|
LANGUAGE plpgsql
|
||||||
|
AS $function$
|
||||||
|
declare
|
||||||
|
session public.usr_session;
|
||||||
|
session_usr public.usr;
|
||||||
|
new_exp timestamp;
|
||||||
|
begin
|
||||||
|
select s
|
||||||
|
from public.usr_session s
|
||||||
|
where s.key = session
|
||||||
|
into session;
|
||||||
|
|
||||||
|
if session is null then
|
||||||
|
raise exception 'usr_session_invalid';
|
||||||
|
end if;
|
||||||
|
|
||||||
|
if session.expires_at <= now() then
|
||||||
|
raise exception 'usr_session_expired';
|
||||||
|
end if;
|
||||||
|
|
||||||
|
if session.remembered then
|
||||||
|
new_exp := now() + interval '1 week';
|
||||||
|
else
|
||||||
|
new_exp := now() + interval '1 hour';
|
||||||
|
end if;
|
||||||
|
|
||||||
|
update public.usr_session s
|
||||||
|
set s.expires_at = new_exp
|
||||||
|
where s.id = session.id;
|
||||||
|
|
||||||
|
select u.*
|
||||||
|
from public.usr u
|
||||||
|
where u.id = session.usr
|
||||||
|
into session_usr;
|
||||||
|
|
||||||
|
return session_usr;
|
||||||
|
end;
|
||||||
|
$function$
|
||||||
|
;
|
||||||
|
|
||||||
|
CREATE OR REPLACE FUNCTION public.do_check_usr_tag()
|
||||||
|
RETURNS trigger
|
||||||
|
LANGUAGE plpgsql
|
||||||
|
STABLE
|
||||||
|
AS $function$
|
||||||
|
begin
|
||||||
|
if new.tag = usr_tag_of_string('root') then
|
||||||
|
raise exception 'tag_invalid';
|
||||||
|
else
|
||||||
|
return new;
|
||||||
|
end if;
|
||||||
|
end;
|
||||||
|
$function$
|
||||||
|
;
|
||||||
|
|
||||||
|
CREATE OR REPLACE FUNCTION public.do_community_immutable_columns()
|
||||||
|
RETURNS trigger
|
||||||
|
LANGUAGE plpgsql
|
||||||
|
AS $function$
|
||||||
|
begin
|
||||||
|
if OLD.id <> NEW.id then
|
||||||
|
raise exception 'immutable_field'
|
||||||
|
using detail = 'public.community.id is immutable',
|
||||||
|
errcode = 'restrict_violation';
|
||||||
|
elsif OLD.uid <> NEW.uid then
|
||||||
|
raise exception 'immutable_field'
|
||||||
|
using detail = 'public.community.uid is immutable',
|
||||||
|
errcode = 'restrict_violation';
|
||||||
|
end if;
|
||||||
|
|
||||||
|
return NEW;
|
||||||
|
end;
|
||||||
|
$function$
|
||||||
|
;
|
||||||
|
|
||||||
|
CREATE OR REPLACE FUNCTION public.do_grp_immutable_columns()
|
||||||
|
RETURNS trigger
|
||||||
|
LANGUAGE plpgsql
|
||||||
|
AS $function$
|
||||||
|
begin
|
||||||
|
if OLD.id <> NEW.id then
|
||||||
|
raise exception 'immutable_field'
|
||||||
|
using detail = 'public.grp.id is immutable',
|
||||||
|
errcode = 'restrict_violation';
|
||||||
|
elsif OLD.uid <> NEW.uid then
|
||||||
|
raise exception 'immutable_field'
|
||||||
|
using detail = 'public.grp.uid is immutable',
|
||||||
|
errcode = 'restrict_violation';
|
||||||
|
elsif OLD.tag <> NEW.tag then
|
||||||
|
raise exception 'immutable_field'
|
||||||
|
using detail = 'public.grp.tag is immutable',
|
||||||
|
errcode = 'restrict_violation';
|
||||||
|
end if;
|
||||||
|
|
||||||
|
return NEW;
|
||||||
|
end;
|
||||||
|
$function$
|
||||||
|
;
|
||||||
|
|
||||||
|
CREATE OR REPLACE FUNCTION public.do_perm_immutable_columns()
|
||||||
|
RETURNS trigger
|
||||||
|
LANGUAGE plpgsql
|
||||||
|
AS $function$
|
||||||
|
begin
|
||||||
|
if OLD.id <> NEW.id then
|
||||||
|
raise exception 'immutable_field'
|
||||||
|
using detail = 'public.perm.id is immutable',
|
||||||
|
errcode = 'restrict_violation';
|
||||||
|
elsif OLD.uid <> NEW.uid then
|
||||||
|
raise exception 'immutable_field'
|
||||||
|
using detail = 'public.perm.uid is immutable',
|
||||||
|
errcode = 'restrict_violation';
|
||||||
|
elsif OLD.path <> NEW.path then
|
||||||
|
raise exception 'immutable_field'
|
||||||
|
using detail = 'public.perm.path is immutable',
|
||||||
|
errcode = 'restrict_violation';
|
||||||
|
end if;
|
||||||
|
|
||||||
|
return NEW;
|
||||||
|
end;
|
||||||
|
$function$
|
||||||
|
;
|
||||||
|
|
||||||
|
CREATE OR REPLACE FUNCTION public.do_thread_attachment_emoji_immutable_columns()
|
||||||
|
RETURNS trigger
|
||||||
|
LANGUAGE plpgsql
|
||||||
|
AS $function$
|
||||||
|
begin
|
||||||
|
if OLD.id <> NEW.id then
|
||||||
|
raise exception 'immutable_field'
|
||||||
|
using detail = 'public.thread_attachment_emoji.id is immutable',
|
||||||
|
errcode = 'restrict_violation';
|
||||||
|
elsif OLD.uid <> NEW.uid then
|
||||||
|
raise exception 'immutable_field'
|
||||||
|
using detail = 'public.thread_attachment_emoji.uid is immutable',
|
||||||
|
errcode = 'restrict_violation';
|
||||||
|
elsif OLD.thread_attachment <> NEW.thread_attachment then
|
||||||
|
raise exception 'immutable_field'
|
||||||
|
using detail = 'public.thread_attachment_emoji.thread_attachment is immutable',
|
||||||
|
errcode = 'restrict_violation';
|
||||||
|
elsif OLD.emoji <> NEW.emoji then
|
||||||
|
raise exception 'immutable_field'
|
||||||
|
using detail = 'public.thread_attachment_emoji.emoji is immutable',
|
||||||
|
errcode = 'restrict_violation';
|
||||||
|
end if;
|
||||||
|
|
||||||
|
return NEW;
|
||||||
|
end;
|
||||||
|
$function$
|
||||||
|
;
|
||||||
|
|
||||||
|
CREATE OR REPLACE FUNCTION public.do_thread_attachment_immutable_columns()
|
||||||
|
RETURNS trigger
|
||||||
|
LANGUAGE plpgsql
|
||||||
|
AS $function$
|
||||||
|
begin
|
||||||
|
if OLD.id <> NEW.id then
|
||||||
|
raise exception 'immutable_field'
|
||||||
|
using detail = 'public.thread_attachment.id is immutable',
|
||||||
|
errcode = 'restrict_violation';
|
||||||
|
elsif OLD.uid <> NEW.uid then
|
||||||
|
raise exception 'immutable_field'
|
||||||
|
using detail = 'public.thread_attachment.uid is immutable',
|
||||||
|
errcode = 'restrict_violation';
|
||||||
|
elsif OLD.thread <> NEW.thread then
|
||||||
|
raise exception 'immutable_field'
|
||||||
|
using detail = 'public.thread_attachment.thread is immutable',
|
||||||
|
errcode = 'restrict_violation';
|
||||||
|
elsif OLD.kind <> NEW.kind then
|
||||||
|
raise exception 'immutable_field'
|
||||||
|
using detail = 'public.thread_attachment.kind is immutable',
|
||||||
|
errcode = 'restrict_violation';
|
||||||
|
end if;
|
||||||
|
|
||||||
|
return NEW;
|
||||||
|
end;
|
||||||
|
$function$
|
||||||
|
;
|
||||||
|
|
||||||
|
CREATE OR REPLACE FUNCTION public.do_thread_attachment_vote_immutable_columns()
|
||||||
|
RETURNS trigger
|
||||||
|
LANGUAGE plpgsql
|
||||||
|
AS $function$
|
||||||
|
begin
|
||||||
|
if OLD.id <> NEW.id then
|
||||||
|
raise exception 'immutable_field'
|
||||||
|
using detail = 'public.thread_attachment_vote.id is immutable',
|
||||||
|
errcode = 'restrict_violation';
|
||||||
|
elsif OLD.uid <> NEW.uid then
|
||||||
|
raise exception 'immutable_field'
|
||||||
|
using detail = 'public.thread_attachment_vote.uid is immutable',
|
||||||
|
errcode = 'restrict_violation';
|
||||||
|
elsif OLD.thread_attachment <> NEW.thread_attachment then
|
||||||
|
raise exception 'immutable_field'
|
||||||
|
using detail = 'public.thread_attachment_vote.thread_attachment is immutable',
|
||||||
|
errcode = 'restrict_violation';
|
||||||
|
elsif OLD.direction <> NEW.direction then
|
||||||
|
raise exception 'immutable_field'
|
||||||
|
using detail = 'public.thread_attachment_vote.direction is immutable',
|
||||||
|
errcode = 'restrict_violation';
|
||||||
|
end if;
|
||||||
|
|
||||||
|
return NEW;
|
||||||
|
end;
|
||||||
|
$function$
|
||||||
|
;
|
||||||
|
|
||||||
|
CREATE OR REPLACE FUNCTION public.do_thread_feed_immutable_columns()
|
||||||
|
RETURNS trigger
|
||||||
|
LANGUAGE plpgsql
|
||||||
|
AS $function$
|
||||||
|
begin
|
||||||
|
if OLD.id <> NEW.id then
|
||||||
|
raise exception 'immutable_field'
|
||||||
|
using detail = 'public.thread_feed.id is immutable',
|
||||||
|
errcode = 'restrict_violation';
|
||||||
|
elsif OLD.uid <> NEW.uid then
|
||||||
|
raise exception 'immutable_field'
|
||||||
|
using detail = 'public.thread_feed.uid is immutable',
|
||||||
|
errcode = 'restrict_violation';
|
||||||
|
elsif OLD.thread <> NEW.thread then
|
||||||
|
raise exception 'immutable_field'
|
||||||
|
using detail = 'public.thread_feed.thread is immutable',
|
||||||
|
errcode = 'restrict_violation';
|
||||||
|
elsif OLD.community <> NEW.community then
|
||||||
|
raise exception 'immutable_field'
|
||||||
|
using detail = 'public.thread_feed.community is immutable',
|
||||||
|
errcode = 'restrict_violation';
|
||||||
|
end if;
|
||||||
|
|
||||||
|
return NEW;
|
||||||
|
end;
|
||||||
|
$function$
|
||||||
|
;
|
||||||
|
|
||||||
|
CREATE OR REPLACE FUNCTION public.do_thread_immutable_columns()
|
||||||
|
RETURNS trigger
|
||||||
|
LANGUAGE plpgsql
|
||||||
|
AS $function$
|
||||||
|
begin
|
||||||
|
if OLD.id <> NEW.id then
|
||||||
|
raise exception 'immutable_field'
|
||||||
|
using detail = 'public.thread.id is immutable',
|
||||||
|
errcode = 'restrict_violation';
|
||||||
|
elsif OLD.uid <> NEW.uid then
|
||||||
|
raise exception 'immutable_field'
|
||||||
|
using detail = 'public.thread.uid is immutable',
|
||||||
|
errcode = 'restrict_violation';
|
||||||
|
elsif OLD.kind <> NEW.kind then
|
||||||
|
raise exception 'immutable_field'
|
||||||
|
using detail = 'public.thread.kind is immutable',
|
||||||
|
errcode = 'restrict_violation';
|
||||||
|
end if;
|
||||||
|
|
||||||
|
return NEW;
|
||||||
|
end;
|
||||||
|
$function$
|
||||||
|
;
|
||||||
|
|
||||||
|
CREATE OR REPLACE FUNCTION public.do_usr_immutable_columns()
|
||||||
|
RETURNS trigger
|
||||||
|
LANGUAGE plpgsql
|
||||||
|
AS $function$
|
||||||
|
begin
|
||||||
|
if OLD.id <> NEW.id then
|
||||||
|
raise exception 'immutable_field'
|
||||||
|
using detail = 'public.usr.id is immutable',
|
||||||
|
errcode = 'restrict_violation';
|
||||||
|
elsif OLD.uid <> NEW.uid then
|
||||||
|
raise exception 'immutable_field'
|
||||||
|
using detail = 'public.usr.uid is immutable',
|
||||||
|
errcode = 'restrict_violation';
|
||||||
|
end if;
|
||||||
|
|
||||||
|
return NEW;
|
||||||
|
end;
|
||||||
|
$function$
|
||||||
|
;
|
||||||
|
|
||||||
|
CREATE OR REPLACE FUNCTION public.do_usr_session_immutable_columns()
|
||||||
|
RETURNS trigger
|
||||||
|
LANGUAGE plpgsql
|
||||||
|
AS $function$
|
||||||
|
begin
|
||||||
|
if OLD.id <> NEW.id then
|
||||||
|
raise exception 'immutable_field'
|
||||||
|
using detail = 'public.usr_session.id is immutable',
|
||||||
|
errcode = 'restrict_violation';
|
||||||
|
elsif OLD.key <> NEW.key then
|
||||||
|
raise exception 'immutable_field'
|
||||||
|
using detail = 'public.usr_session.key is immutable',
|
||||||
|
errcode = 'restrict_violation';
|
||||||
|
elsif OLD.expires_at <> NEW.expires_at then
|
||||||
|
raise exception 'immutable_field'
|
||||||
|
using detail = 'public.usr_session.expires_at is immutable',
|
||||||
|
errcode = 'restrict_violation';
|
||||||
|
elsif OLD.usr <> NEW.usr then
|
||||||
|
raise exception 'immutable_field'
|
||||||
|
using detail = 'public.usr_session.usr is immutable',
|
||||||
|
errcode = 'restrict_violation';
|
||||||
|
elsif OLD.location <> NEW.location then
|
||||||
|
raise exception 'immutable_field'
|
||||||
|
using detail = 'public.usr_session.location is immutable',
|
||||||
|
errcode = 'restrict_violation';
|
||||||
|
elsif OLD.device <> NEW.device then
|
||||||
|
raise exception 'immutable_field'
|
||||||
|
using detail = 'public.usr_session.device is immutable',
|
||||||
|
errcode = 'restrict_violation';
|
||||||
|
elsif OLD.ip <> NEW.ip then
|
||||||
|
raise exception 'immutable_field'
|
||||||
|
using detail = 'public.usr_session.ip is immutable',
|
||||||
|
errcode = 'restrict_violation';
|
||||||
|
end if;
|
||||||
|
|
||||||
|
return NEW;
|
||||||
|
end;
|
||||||
|
$function$
|
||||||
|
;
|
||||||
|
|
||||||
|
CREATE OR REPLACE FUNCTION public.immutable(schema text, table_ text, columns text[])
|
||||||
|
RETURNS void
|
||||||
|
LANGUAGE plpgsql
|
||||||
|
AS $function$
|
||||||
|
declare
|
||||||
|
col text;
|
||||||
|
qualified_name text := concat(schema, '.', table_);
|
||||||
|
do_table_immutable_columns text := concat('do_', table_, '_immutable_columns');
|
||||||
|
trigger_table_immutable_columns text := concat('trigger_', table_, '_immutable_columns');
|
||||||
|
create_do_table_immutable_columns text;
|
||||||
|
create_trigger_table_immutable_columns text;
|
||||||
|
begin
|
||||||
|
create_do_table_immutable_columns := concat( create_do_table_immutable_columns
|
||||||
|
, 'create function ', schema, '.', do_table_immutable_columns, E'() returns trigger language plpgsql as \$\$\n'
|
||||||
|
, E'begin\n'
|
||||||
|
, ' if OLD.', columns[1], ' <> NEW.', columns[1], E' then\n'
|
||||||
|
, E' raise exception \'immutable_field\'\n'
|
||||||
|
, E' using detail = \'', qualified_name, '.', columns[1], E' is immutable\',\n'
|
||||||
|
, E' errcode = \'restrict_violation\';\n'
|
||||||
|
);
|
||||||
|
foreach col in array columns[2:] loop
|
||||||
|
create_do_table_immutable_columns := concat( create_do_table_immutable_columns
|
||||||
|
, E' elsif OLD.', col, ' <> NEW.', col, E' then\n'
|
||||||
|
, E' raise exception \'immutable_field\'\n'
|
||||||
|
, E' using detail = \'', qualified_name, '.', col, E' is immutable\',\n'
|
||||||
|
, E' errcode = \'restrict_violation\';\n'
|
||||||
|
);
|
||||||
|
end loop;
|
||||||
|
|
||||||
|
create_do_table_immutable_columns := concat( create_do_table_immutable_columns
|
||||||
|
, E' end if;\n'
|
||||||
|
, E'\n'
|
||||||
|
, E' return NEW;\n'
|
||||||
|
, E'end;\n'
|
||||||
|
, E'\$\$;\n'
|
||||||
|
);
|
||||||
|
|
||||||
|
create_trigger_table_immutable_columns := concat( create_trigger_table_immutable_columns
|
||||||
|
, 'create trigger ', trigger_table_immutable_columns, E'\n'
|
||||||
|
, 'before update on ', qualified_name, E'\n'
|
||||||
|
, 'for each row execute function ', do_table_immutable_columns, '();'
|
||||||
|
);
|
||||||
|
|
||||||
|
execute create_do_table_immutable_columns;
|
||||||
|
execute create_trigger_table_immutable_columns;
|
||||||
|
end;
|
||||||
|
$function$
|
||||||
|
;
|
||||||
|
|
||||||
|
CREATE OR REPLACE FUNCTION public.usr_session_login(tag_or_email usr_tag_or_email, password text, remember boolean DEFAULT false, location text DEFAULT NULL::text, device usr_session_device DEFAULT NULL::usr_session_device, ip inet DEFAULT NULL::inet)
|
||||||
|
RETURNS usr_session_key
|
||||||
|
LANGUAGE plpgsql
|
||||||
|
AS $function$
|
||||||
|
declare
|
||||||
|
usr public.usr;
|
||||||
|
key public.usr_session_key := usr_session_key_gen();
|
||||||
|
expires_at timestamp;
|
||||||
|
begin
|
||||||
|
usr := public.usr_session_login_validate(tag_or_email, password);
|
||||||
|
|
||||||
|
if remember then
|
||||||
|
expires_at := now() + interval '1 week';
|
||||||
|
else
|
||||||
|
expires_at := now() + interval '1 hour';
|
||||||
|
end if;
|
||||||
|
|
||||||
|
insert into public.usr_session
|
||||||
|
(key, expires_at, usr, remembered, location, device, ip)
|
||||||
|
values
|
||||||
|
(key, expires_at, usr.id, remember, location, device, ip);
|
||||||
|
|
||||||
|
return key;
|
||||||
|
end;
|
||||||
|
$function$
|
||||||
|
;
|
||||||
|
|
||||||
|
CREATE OR REPLACE FUNCTION public.usr_session_login_validate(tag_or_email usr_tag_or_email, password text)
|
||||||
|
RETURNS usr
|
||||||
|
LANGUAGE plpgsql
|
||||||
|
STABLE
|
||||||
|
AS $function$
|
||||||
|
declare
|
||||||
|
usr_email public.email := public.usr_tag_or_email_to_email(tag_or_email);
|
||||||
|
usr_tag public.usr_tag := public.usr_tag_or_email_to_tag(tag_or_email);
|
||||||
|
usr public.usr;
|
||||||
|
begin
|
||||||
|
select *
|
||||||
|
from public.usr as u
|
||||||
|
where u.email = usr_email
|
||||||
|
or u.tag = usr_tag
|
||||||
|
into usr;
|
||||||
|
|
||||||
|
if usr.id = 1 or usr.tag = usr_tag_of_string('root') then
|
||||||
|
raise notice 'root user may not be logged into';
|
||||||
|
raise exception 'incorrect_password';
|
||||||
|
end if;
|
||||||
|
|
||||||
|
if usr is null then
|
||||||
|
-- prevent email guess bruteforces by raising the same exception
|
||||||
|
-- for invalid password and user not found
|
||||||
|
raise notice 'user % not found', usr_tag_or_email_to_string(tag_or_email);
|
||||||
|
raise exception 'incorrect_password';
|
||||||
|
end if;
|
||||||
|
|
||||||
|
if not hashed_text_matches(password, usr.password) then
|
||||||
|
raise notice 'password does not match for user %', usr_tag_or_email_to_string(tag_or_email);
|
||||||
|
raise exception 'incorrect_password';
|
||||||
|
end if;
|
||||||
|
|
||||||
|
return usr;
|
||||||
|
end;
|
||||||
|
$function$
|
||||||
|
;
|
1
2080a44_to_0e93478.sql
Normal file
1
2080a44_to_0e93478.sql
Normal file
@ -0,0 +1 @@
|
|||||||
|
|
1
21957cf_skipped.sql
Normal file
1
21957cf_skipped.sql
Normal file
@ -0,0 +1 @@
|
|||||||
|
|
1
2345c61_to_8b08d9f.sql
Normal file
1
2345c61_to_8b08d9f.sql
Normal file
@ -0,0 +1 @@
|
|||||||
|
|
1
26c2c9c_to_b9d80dd.sql
Normal file
1
26c2c9c_to_b9d80dd.sql
Normal file
@ -0,0 +1 @@
|
|||||||
|
|
1
2704c5b_skipped.sql
Normal file
1
2704c5b_skipped.sql
Normal file
@ -0,0 +1 @@
|
|||||||
|
|
@ -1,30 +1,19 @@
|
|||||||
create function public.set_acting_usr(uid text)
|
set check_function_bodies = off;
|
||||||
returns void
|
|
||||||
language plpgsql
|
|
||||||
volatile
|
|
||||||
as $$
|
|
||||||
begin
|
|
||||||
if uid is not null and uid != '' then
|
|
||||||
perform set_config('dnim.usr_uid', uid, false);
|
|
||||||
end if;
|
|
||||||
end;
|
|
||||||
$$;
|
|
||||||
|
|
||||||
create function public.unset_acting_usr()
|
CREATE OR REPLACE FUNCTION public.unset_acting_usr()
|
||||||
returns void
|
RETURNS void
|
||||||
language plpgsql
|
LANGUAGE plpgsql
|
||||||
volatile
|
AS $function$
|
||||||
as $$
|
|
||||||
begin
|
begin
|
||||||
perform set_config('dnim.usr_uid', '', false);
|
perform set_config('dnim.usr_uid', '', false);
|
||||||
end;
|
end;
|
||||||
$$;
|
$function$
|
||||||
|
;
|
||||||
|
|
||||||
create function public.get_acting_usr()
|
CREATE OR REPLACE FUNCTION public.get_acting_usr()
|
||||||
returns public.usr
|
RETURNS usr
|
||||||
language plpgsql
|
LANGUAGE plpgsql
|
||||||
volatile
|
AS $function$
|
||||||
as $$
|
|
||||||
declare
|
declare
|
||||||
acting_usr public.usr;
|
acting_usr public.usr;
|
||||||
begin
|
begin
|
||||||
@ -39,4 +28,17 @@ begin
|
|||||||
|
|
||||||
return coalesce(acting_usr, public.usr_root());
|
return coalesce(acting_usr, public.usr_root());
|
||||||
end;
|
end;
|
||||||
$$;
|
$function$
|
||||||
|
;
|
||||||
|
|
||||||
|
CREATE OR REPLACE FUNCTION public.set_acting_usr(uid text)
|
||||||
|
RETURNS void
|
||||||
|
LANGUAGE plpgsql
|
||||||
|
AS $function$
|
||||||
|
begin
|
||||||
|
if uid is not null and uid != '' then
|
||||||
|
perform set_config('dnim.usr_uid', uid, false);
|
||||||
|
end if;
|
||||||
|
end;
|
||||||
|
$function$
|
||||||
|
;
|
1
28b6544_skipped.sql
Normal file
1
28b6544_skipped.sql
Normal file
@ -0,0 +1 @@
|
|||||||
|
|
1
2c288ef_to_5169bcb.sql
Normal file
1
2c288ef_to_5169bcb.sql
Normal file
@ -0,0 +1 @@
|
|||||||
|
|
@ -1,162 +1,311 @@
|
|||||||
create type public.audit_kind as enum
|
alter table "public"."community_audit" drop column "prev_role_nonmember";
|
||||||
( 'modify'
|
|
||||||
, 'delete'
|
|
||||||
, 'create'
|
|
||||||
);
|
|
||||||
|
|
||||||
create type audited_column as (column_ text, type_ text);
|
alter table "public"."community_member" add column "community" integer not null;
|
||||||
|
|
||||||
create function audit(schema text, table_ text, tracked_columns audited_column[], soft_delete boolean)
|
alter table "public"."community_member_role" add column "community" integer not null;
|
||||||
returns void
|
|
||||||
language plpgsql as $$
|
|
||||||
begin
|
|
||||||
if soft_delete then
|
|
||||||
perform setup_audit_and_soft_delete(schema, table_, tracked_columns);
|
|
||||||
else
|
|
||||||
perform setup_audit_and_hard_delete(schema, table_, tracked_columns);
|
|
||||||
end if;
|
|
||||||
end;
|
|
||||||
$$;
|
|
||||||
|
|
||||||
create function setup_audit_and_soft_delete( schema text
|
alter table "public"."community_member" add constraint "community_member_community_fkey" FOREIGN KEY (community) REFERENCES community(id) not valid;
|
||||||
, table_ text
|
|
||||||
, tracked_columns audited_column[]
|
|
||||||
)
|
|
||||||
returns void
|
|
||||||
language plpgsql as $$
|
|
||||||
declare
|
|
||||||
col audited_column;
|
|
||||||
audit_table text := concat(schema, '.', table_, '_audit');
|
|
||||||
do_table_audit text := concat(schema, '.do_', table_, '_audit');
|
|
||||||
do_table_soft_delete text := concat(schema, '.do_', table_, '_soft_delete');
|
|
||||||
create_audit_table text := '';
|
|
||||||
create_do_table_audit text := '';
|
|
||||||
create_do_table_soft_delete text := '';
|
|
||||||
create_trigger_table_audit text := '';
|
|
||||||
create_trigger_table_soft_delete text := '';
|
|
||||||
begin
|
|
||||||
-- create table X_audit() >>>
|
|
||||||
create_audit_table := concat( create_audit_table
|
|
||||||
, 'create table ', audit_table, E'\n'
|
|
||||||
, ' ( ', table_, ' int not null references ', table_, '(id)', E'\n'
|
|
||||||
, ' , kind public.audit_kind not null', E'\n'
|
|
||||||
, ' , actor int not null references public.usr (id)', E'\n'
|
|
||||||
);
|
|
||||||
|
|
||||||
foreach col in array tracked_columns loop
|
alter table "public"."community_member" validate constraint "community_member_community_fkey";
|
||||||
create_audit_table := concat( create_audit_table
|
|
||||||
, E' , prev_', (col.column_), ' ', (col.type_), E' null\n'
|
|
||||||
);
|
|
||||||
end loop;
|
|
||||||
|
|
||||||
create_audit_table := concat( create_audit_table
|
alter table "public"."community_member_role" add constraint "community_member_role_community_fkey" FOREIGN KEY (community) REFERENCES community(id) not valid;
|
||||||
, ' );'
|
|
||||||
);
|
|
||||||
-- <<< create table X_audit()
|
|
||||||
|
|
||||||
-- create function do_X_soft_delete() >>>
|
alter table "public"."community_member_role" validate constraint "community_member_role_community_fkey";
|
||||||
create_do_table_soft_delete := concat( create_do_table_soft_delete
|
|
||||||
, 'create function ', do_table_soft_delete, E'() returns trigger language plpgsql as \$\$\n'
|
|
||||||
, E'begin\n'
|
|
||||||
, E' insert into ', audit_table, E'\n'
|
|
||||||
, E' (', table_, E', kind, actor)\n'
|
|
||||||
, E' values\n'
|
|
||||||
, E' (OLD.id, \'delete\', (select (public.get_acting_usr()).id));\n'
|
|
||||||
, E'\n'
|
|
||||||
, E' update ', schema, '.', table_, E'\n'
|
|
||||||
, E' set deleted = true\n'
|
|
||||||
, E' where id = OLD.id;\n'
|
|
||||||
, E'\n'
|
|
||||||
, E' return null;\n'
|
|
||||||
, E'end;\n'
|
|
||||||
, E'\$\$;'
|
|
||||||
);
|
|
||||||
-- <<< create function do_X_soft_delete()
|
|
||||||
|
|
||||||
-- create function do_X_audit() >>>
|
set check_function_bodies = off;
|
||||||
create_do_table_audit := concat( create_do_table_audit
|
|
||||||
, 'create function ', do_table_audit, E'() returns trigger language plpgsql as \$\$\n'
|
|
||||||
, E'declare\n'
|
|
||||||
, E' audit_kind public.audit_kind;\n'
|
|
||||||
, E' id int;\n'
|
|
||||||
);
|
|
||||||
|
|
||||||
foreach col in array tracked_columns loop
|
CREATE OR REPLACE FUNCTION public.do_community_audit()
|
||||||
create_do_table_audit := concat( create_do_table_audit
|
RETURNS trigger
|
||||||
, 'prev_', (col.column_), ' ', (col.type_), E';\n'
|
LANGUAGE plpgsql
|
||||||
);
|
AS $function$
|
||||||
end loop;
|
declare
|
||||||
|
audit_kind public.audit_kind;
|
||||||
|
id int;
|
||||||
|
prev_tag public.community_tag;
|
||||||
|
begin
|
||||||
|
if (TG_OP = 'INSERT') then
|
||||||
|
id := NEW.id;
|
||||||
|
audit_kind := 'create';
|
||||||
|
elsif (TG_OP = 'UPDATE') then
|
||||||
|
id := OLD.id;
|
||||||
|
audit_kind := 'modify';
|
||||||
|
prev_tag := OLD.tag;
|
||||||
|
end if;
|
||||||
|
insert into public.community_audit
|
||||||
|
(kind, community, actor, prev_tag )
|
||||||
|
values
|
||||||
|
(audit_kind, id, 1, prev_tag);
|
||||||
|
return NEW;
|
||||||
|
end;
|
||||||
|
$function$
|
||||||
|
;
|
||||||
|
|
||||||
create_do_table_audit := concat( create_do_table_audit
|
CREATE OR REPLACE FUNCTION public.do_community_member_audit()
|
||||||
, E'begin\n'
|
RETURNS trigger
|
||||||
, E' if (TG_OP = \'INSERT\') then\n'
|
LANGUAGE plpgsql
|
||||||
, E' id := NEW.id;\n'
|
AS $function$
|
||||||
, E' audit_kind := \'create\';\n'
|
declare
|
||||||
, E' elsif (TG_OP = \'UPDATE\') then\n'
|
audit_kind public.audit_kind;
|
||||||
, E' id := OLD.id;\n'
|
id int;
|
||||||
, E' audit_kind := \'modify\';\n'
|
prev_usr int;
|
||||||
);
|
prev_role_ int;
|
||||||
|
begin
|
||||||
|
if (TG_OP = 'INSERT') then
|
||||||
|
id := NEW.id;
|
||||||
|
audit_kind := 'create';
|
||||||
|
elsif (TG_OP = 'DELETE') then
|
||||||
|
id := OLD.id;
|
||||||
|
audit_kind := 'delete';
|
||||||
|
elsif (TG_OP = 'UPDATE') then
|
||||||
|
id := OLD.id;
|
||||||
|
audit_kind := 'modify';
|
||||||
|
prev_usr := OLD.usr;
|
||||||
|
prev_role_ := OLD.role_;
|
||||||
|
end if;
|
||||||
|
insert into public.community_member_audit
|
||||||
|
(kind, community_member, actor, prev_usr, prev_role_ )
|
||||||
|
values
|
||||||
|
(audit_kind, id, 1, prev_usr, prev_role_);
|
||||||
|
return NEW;
|
||||||
|
end;
|
||||||
|
$function$
|
||||||
|
;
|
||||||
|
|
||||||
foreach col in array tracked_columns loop
|
CREATE OR REPLACE FUNCTION public.do_community_member_role_audit()
|
||||||
create_do_table_audit := concat( create_do_table_audit
|
RETURNS trigger
|
||||||
, ' prev_', (col.column_), ' := OLD.', (col.column_), E';\n'
|
LANGUAGE plpgsql
|
||||||
);
|
AS $function$
|
||||||
end loop;
|
declare
|
||||||
|
audit_kind public.audit_kind;
|
||||||
|
id int;
|
||||||
|
prev_title text;
|
||||||
|
prev_description text;
|
||||||
|
begin
|
||||||
|
if (TG_OP = 'INSERT') then
|
||||||
|
id := NEW.id;
|
||||||
|
audit_kind := 'create';
|
||||||
|
elsif (TG_OP = 'DELETE') then
|
||||||
|
id := OLD.id;
|
||||||
|
audit_kind := 'delete';
|
||||||
|
elsif (TG_OP = 'UPDATE') then
|
||||||
|
id := OLD.id;
|
||||||
|
audit_kind := 'modify';
|
||||||
|
prev_title := OLD.title;
|
||||||
|
prev_description := OLD.description;
|
||||||
|
end if;
|
||||||
|
insert into public.community_member_role_audit
|
||||||
|
(kind, community_member_role, actor, prev_title, prev_description )
|
||||||
|
values
|
||||||
|
(audit_kind, id, 1, prev_title, prev_description);
|
||||||
|
return NEW;
|
||||||
|
end;
|
||||||
|
$function$
|
||||||
|
;
|
||||||
|
|
||||||
create_do_table_audit := concat( create_do_table_audit
|
CREATE OR REPLACE FUNCTION public.do_community_member_role_immutable_columns()
|
||||||
, E' end if;\n'
|
RETURNS trigger
|
||||||
, E' insert into ', audit_table, E'\n'
|
LANGUAGE plpgsql
|
||||||
, ' (kind, ', table_, ', actor'
|
AS $function$
|
||||||
);
|
begin
|
||||||
|
if OLD.id <> NEW.id then
|
||||||
|
raise exception 'public.community_member_role.id is immutable' using errcode = 'restrict_violation';
|
||||||
|
elsif OLD.uid <> NEW.uid then
|
||||||
|
raise exception 'public.community_member_role.uid is immutable' using errcode = 'restrict_violation';
|
||||||
|
elsif OLD.community <> NEW.community then
|
||||||
|
raise exception 'public.community_member_role.community is immutable' using errcode = 'restrict_violation';
|
||||||
|
end if;
|
||||||
|
|
||||||
foreach col in array tracked_columns loop
|
return NEW;
|
||||||
create_do_table_audit := concat( create_do_table_audit
|
end;
|
||||||
, ', prev_', (col.column_)
|
$function$
|
||||||
);
|
;
|
||||||
end loop;
|
|
||||||
|
|
||||||
create_do_table_audit := concat( create_do_table_audit
|
CREATE OR REPLACE FUNCTION public.do_community_member_role_scope_audit()
|
||||||
, E' )\n'
|
RETURNS trigger
|
||||||
, E' values\n'
|
LANGUAGE plpgsql
|
||||||
, E' (audit_kind, id, (public.get_acting_usr()).id'
|
AS $function$
|
||||||
);
|
declare
|
||||||
|
audit_kind public.audit_kind;
|
||||||
|
id int;
|
||||||
|
prev_role_ int;
|
||||||
|
prev_scope public.authz_scope;
|
||||||
|
begin
|
||||||
|
if (TG_OP = 'INSERT') then
|
||||||
|
id := NEW.id;
|
||||||
|
audit_kind := 'create';
|
||||||
|
elsif (TG_OP = 'DELETE') then
|
||||||
|
id := OLD.id;
|
||||||
|
audit_kind := 'delete';
|
||||||
|
elsif (TG_OP = 'UPDATE') then
|
||||||
|
id := OLD.id;
|
||||||
|
audit_kind := 'modify';
|
||||||
|
prev_role_ := OLD.role_;
|
||||||
|
prev_scope := OLD.scope;
|
||||||
|
end if;
|
||||||
|
insert into public.community_member_role_scope_audit
|
||||||
|
(kind, community_member_role_scope, actor, prev_role_, prev_scope )
|
||||||
|
values
|
||||||
|
(audit_kind, id, 1, prev_role_, prev_scope);
|
||||||
|
return NEW;
|
||||||
|
end;
|
||||||
|
$function$
|
||||||
|
;
|
||||||
|
|
||||||
foreach col in array tracked_columns loop
|
CREATE OR REPLACE FUNCTION public.do_community_nonmember_scope_audit()
|
||||||
create_do_table_audit := concat( create_do_table_audit
|
RETURNS trigger
|
||||||
, ', prev_', (col.column_)
|
LANGUAGE plpgsql
|
||||||
);
|
AS $function$
|
||||||
end loop;
|
declare
|
||||||
|
audit_kind public.audit_kind;
|
||||||
|
id int;
|
||||||
|
prev_community int;
|
||||||
|
prev_scope public.authz_scope;
|
||||||
|
begin
|
||||||
|
if (TG_OP = 'INSERT') then
|
||||||
|
id := NEW.id;
|
||||||
|
audit_kind := 'create';
|
||||||
|
elsif (TG_OP = 'DELETE') then
|
||||||
|
id := OLD.id;
|
||||||
|
audit_kind := 'delete';
|
||||||
|
elsif (TG_OP = 'UPDATE') then
|
||||||
|
id := OLD.id;
|
||||||
|
audit_kind := 'modify';
|
||||||
|
prev_community := OLD.community;
|
||||||
|
prev_scope := OLD.scope;
|
||||||
|
end if;
|
||||||
|
insert into public.community_nonmember_scope_audit
|
||||||
|
(kind, community_nonmember_scope, actor, prev_community, prev_scope )
|
||||||
|
values
|
||||||
|
(audit_kind, id, 1, prev_community, prev_scope);
|
||||||
|
return NEW;
|
||||||
|
end;
|
||||||
|
$function$
|
||||||
|
;
|
||||||
|
|
||||||
create_do_table_audit := concat( create_do_table_audit
|
CREATE OR REPLACE FUNCTION public.do_thread_attachment_audit()
|
||||||
, E');\n'
|
RETURNS trigger
|
||||||
, E' return NEW;\n'
|
LANGUAGE plpgsql
|
||||||
, E'end;\n'
|
AS $function$
|
||||||
, E'\$\$;'
|
declare
|
||||||
);
|
audit_kind public.audit_kind;
|
||||||
-- <<< create function do_X_audit()
|
id int;
|
||||||
|
begin
|
||||||
|
if (TG_OP = 'INSERT') then
|
||||||
|
id := NEW.id;
|
||||||
|
audit_kind := 'create';
|
||||||
|
elsif (TG_OP = 'UPDATE') then
|
||||||
|
id := OLD.id;
|
||||||
|
audit_kind := 'modify';
|
||||||
|
end if;
|
||||||
|
insert into public.thread_attachment_audit
|
||||||
|
(kind, thread_attachment, actor )
|
||||||
|
values
|
||||||
|
(audit_kind, id, 1);
|
||||||
|
return NEW;
|
||||||
|
end;
|
||||||
|
$function$
|
||||||
|
;
|
||||||
|
|
||||||
create_trigger_table_audit := concat( 'create trigger trigger_', table_, E'_audit\n'
|
CREATE OR REPLACE FUNCTION public.do_thread_attachment_emoji_audit()
|
||||||
, 'after insert or update on ', schema, '.', table_, E'\n'
|
RETURNS trigger
|
||||||
, 'for each row execute function ', do_table_audit, '();'
|
LANGUAGE plpgsql
|
||||||
);
|
AS $function$
|
||||||
create_trigger_table_soft_delete := concat( 'create trigger trigger_', table_, E'_soft_delete\n'
|
declare
|
||||||
, 'before delete on ', schema, '.', table_, E'\n'
|
audit_kind public.audit_kind;
|
||||||
, 'for each row execute function ', do_table_soft_delete, '();'
|
id int;
|
||||||
);
|
begin
|
||||||
execute create_audit_table;
|
if (TG_OP = 'INSERT') then
|
||||||
execute create_do_table_audit;
|
id := NEW.id;
|
||||||
execute create_do_table_soft_delete;
|
audit_kind := 'create';
|
||||||
execute create_trigger_table_audit;
|
elsif (TG_OP = 'UPDATE') then
|
||||||
execute create_trigger_table_soft_delete;
|
id := OLD.id;
|
||||||
end;
|
audit_kind := 'modify';
|
||||||
$$;
|
end if;
|
||||||
|
insert into public.thread_attachment_emoji_audit
|
||||||
|
(kind, thread_attachment_emoji, actor )
|
||||||
|
values
|
||||||
|
(audit_kind, id, 1);
|
||||||
|
return NEW;
|
||||||
|
end;
|
||||||
|
$function$
|
||||||
|
;
|
||||||
|
|
||||||
create function setup_audit_and_hard_delete( schema text
|
CREATE OR REPLACE FUNCTION public.do_thread_attachment_vote_audit()
|
||||||
, table_ text
|
RETURNS trigger
|
||||||
, tracked_columns audited_column[]
|
LANGUAGE plpgsql
|
||||||
)
|
AS $function$
|
||||||
returns void
|
declare
|
||||||
language plpgsql as $$
|
audit_kind public.audit_kind;
|
||||||
|
id int;
|
||||||
|
begin
|
||||||
|
if (TG_OP = 'INSERT') then
|
||||||
|
id := NEW.id;
|
||||||
|
audit_kind := 'create';
|
||||||
|
elsif (TG_OP = 'UPDATE') then
|
||||||
|
id := OLD.id;
|
||||||
|
audit_kind := 'modify';
|
||||||
|
end if;
|
||||||
|
insert into public.thread_attachment_vote_audit
|
||||||
|
(kind, thread_attachment_vote, actor )
|
||||||
|
values
|
||||||
|
(audit_kind, id, 1);
|
||||||
|
return NEW;
|
||||||
|
end;
|
||||||
|
$function$
|
||||||
|
;
|
||||||
|
|
||||||
|
CREATE OR REPLACE FUNCTION public.do_thread_audit()
|
||||||
|
RETURNS trigger
|
||||||
|
LANGUAGE plpgsql
|
||||||
|
AS $function$
|
||||||
|
declare
|
||||||
|
audit_kind public.audit_kind;
|
||||||
|
id int;
|
||||||
|
begin
|
||||||
|
if (TG_OP = 'INSERT') then
|
||||||
|
id := NEW.id;
|
||||||
|
audit_kind := 'create';
|
||||||
|
elsif (TG_OP = 'UPDATE') then
|
||||||
|
id := OLD.id;
|
||||||
|
audit_kind := 'modify';
|
||||||
|
end if;
|
||||||
|
insert into public.thread_audit
|
||||||
|
(kind, thread, actor )
|
||||||
|
values
|
||||||
|
(audit_kind, id, 1);
|
||||||
|
return NEW;
|
||||||
|
end;
|
||||||
|
$function$
|
||||||
|
;
|
||||||
|
|
||||||
|
CREATE OR REPLACE FUNCTION public.do_thread_feed_audit()
|
||||||
|
RETURNS trigger
|
||||||
|
LANGUAGE plpgsql
|
||||||
|
AS $function$
|
||||||
|
declare
|
||||||
|
audit_kind public.audit_kind;
|
||||||
|
id int;
|
||||||
|
begin
|
||||||
|
if (TG_OP = 'INSERT') then
|
||||||
|
id := NEW.id;
|
||||||
|
audit_kind := 'create';
|
||||||
|
elsif (TG_OP = 'UPDATE') then
|
||||||
|
id := OLD.id;
|
||||||
|
audit_kind := 'modify';
|
||||||
|
end if;
|
||||||
|
insert into public.thread_feed_audit
|
||||||
|
(kind, thread_feed, actor )
|
||||||
|
values
|
||||||
|
(audit_kind, id, 1);
|
||||||
|
return NEW;
|
||||||
|
end;
|
||||||
|
$function$
|
||||||
|
;
|
||||||
|
|
||||||
|
CREATE OR REPLACE FUNCTION public.setup_audit_and_hard_delete(schema text, table_ text, tracked_columns audited_column[])
|
||||||
|
RETURNS void
|
||||||
|
LANGUAGE plpgsql
|
||||||
|
AS $function$
|
||||||
declare
|
declare
|
||||||
col audited_column;
|
col audited_column;
|
||||||
audit_table text := concat(schema, '.', table_, '_audit');
|
audit_table text := concat(schema, '.', table_, '_audit');
|
||||||
@ -235,7 +384,7 @@ create function setup_audit_and_hard_delete( schema text
|
|||||||
create_do_table_audit := concat( create_do_table_audit
|
create_do_table_audit := concat( create_do_table_audit
|
||||||
, E' )\n'
|
, E' )\n'
|
||||||
, E' values\n'
|
, E' values\n'
|
||||||
, E' (audit_kind, id, (public.get_acting_usr()).id'
|
, E' (audit_kind, id, 1'
|
||||||
);
|
);
|
||||||
|
|
||||||
foreach col in array tracked_columns loop
|
foreach col in array tracked_columns loop
|
||||||
@ -262,4 +411,137 @@ create function setup_audit_and_hard_delete( schema text
|
|||||||
execute create_trigger_table_audit;
|
execute create_trigger_table_audit;
|
||||||
execute create_trigger_table_soft_delete;
|
execute create_trigger_table_soft_delete;
|
||||||
end;
|
end;
|
||||||
$$;
|
$function$
|
||||||
|
;
|
||||||
|
|
||||||
|
CREATE OR REPLACE FUNCTION public.setup_audit_and_soft_delete(schema text, table_ text, tracked_columns audited_column[])
|
||||||
|
RETURNS void
|
||||||
|
LANGUAGE plpgsql
|
||||||
|
AS $function$
|
||||||
|
declare
|
||||||
|
col audited_column;
|
||||||
|
audit_table text := concat(schema, '.', table_, '_audit');
|
||||||
|
do_table_audit text := concat(schema, '.do_', table_, '_audit');
|
||||||
|
do_table_soft_delete text := concat(schema, '.do_', table_, '_soft_delete');
|
||||||
|
create_audit_table text := '';
|
||||||
|
create_do_table_audit text := '';
|
||||||
|
create_do_table_soft_delete text := '';
|
||||||
|
create_trigger_table_audit text := '';
|
||||||
|
create_trigger_table_soft_delete text := '';
|
||||||
|
begin
|
||||||
|
-- create table X_audit() >>>
|
||||||
|
create_audit_table := concat( create_audit_table
|
||||||
|
, 'create table ', audit_table, E'\n'
|
||||||
|
, ' ( ', table_, ' int not null references ', table_, '(id)', E'\n'
|
||||||
|
, ' , kind public.audit_kind not null', E'\n'
|
||||||
|
, ' , actor int not null references public.usr (id)', E'\n'
|
||||||
|
);
|
||||||
|
|
||||||
|
foreach col in array tracked_columns loop
|
||||||
|
create_audit_table := concat( create_audit_table
|
||||||
|
, E' , prev_', (col.column_), ' ', (col.type_), E' null\n'
|
||||||
|
);
|
||||||
|
end loop;
|
||||||
|
|
||||||
|
create_audit_table := concat( create_audit_table
|
||||||
|
, ' );'
|
||||||
|
);
|
||||||
|
-- <<< create table X_audit()
|
||||||
|
|
||||||
|
-- create function do_X_soft_delete() >>>
|
||||||
|
create_do_table_soft_delete := concat( create_do_table_soft_delete
|
||||||
|
, 'create function ', do_table_soft_delete, E'() returns trigger language plpgsql as \$\$\n'
|
||||||
|
, E'begin\n'
|
||||||
|
, E' insert into ', audit_table, E'\n'
|
||||||
|
, E' (', table_, E', kind, actor)\n'
|
||||||
|
, E' values\n'
|
||||||
|
, E' (OLD.id, \'delete\', 1);\n'
|
||||||
|
, E'\n'
|
||||||
|
, E' update ', schema, '.', table_, E'\n'
|
||||||
|
, E' set deleted = true\n'
|
||||||
|
, E' where id = OLD.id;\n'
|
||||||
|
, E'\n'
|
||||||
|
, E' return null;\n'
|
||||||
|
, E'end;\n'
|
||||||
|
, E'\$\$;'
|
||||||
|
);
|
||||||
|
-- <<< create function do_X_soft_delete()
|
||||||
|
|
||||||
|
-- create function do_X_audit() >>>
|
||||||
|
create_do_table_audit := concat( create_do_table_audit
|
||||||
|
, 'create function ', do_table_audit, E'() returns trigger language plpgsql as \$\$\n'
|
||||||
|
, E'declare\n'
|
||||||
|
, E' audit_kind public.audit_kind;\n'
|
||||||
|
, E' id int;\n'
|
||||||
|
);
|
||||||
|
|
||||||
|
foreach col in array tracked_columns loop
|
||||||
|
create_do_table_audit := concat( create_do_table_audit
|
||||||
|
, 'prev_', (col.column_), ' ', (col.type_), E';\n'
|
||||||
|
);
|
||||||
|
end loop;
|
||||||
|
|
||||||
|
create_do_table_audit := concat( create_do_table_audit
|
||||||
|
, E'begin\n'
|
||||||
|
, E' if (TG_OP = \'INSERT\') then\n'
|
||||||
|
, E' id := NEW.id;\n'
|
||||||
|
, E' audit_kind := \'create\';\n'
|
||||||
|
, E' elsif (TG_OP = \'UPDATE\') then\n'
|
||||||
|
, E' id := OLD.id;\n'
|
||||||
|
, E' audit_kind := \'modify\';\n'
|
||||||
|
);
|
||||||
|
|
||||||
|
foreach col in array tracked_columns loop
|
||||||
|
create_do_table_audit := concat( create_do_table_audit
|
||||||
|
, ' prev_', (col.column_), ' := OLD.', (col.column_), E';\n'
|
||||||
|
);
|
||||||
|
end loop;
|
||||||
|
|
||||||
|
create_do_table_audit := concat( create_do_table_audit
|
||||||
|
, E' end if;\n'
|
||||||
|
, E' insert into ', audit_table, E'\n'
|
||||||
|
, ' (kind, ', table_, ', actor'
|
||||||
|
);
|
||||||
|
|
||||||
|
foreach col in array tracked_columns loop
|
||||||
|
create_do_table_audit := concat( create_do_table_audit
|
||||||
|
, ', prev_', (col.column_)
|
||||||
|
);
|
||||||
|
end loop;
|
||||||
|
|
||||||
|
create_do_table_audit := concat( create_do_table_audit
|
||||||
|
, E' )\n'
|
||||||
|
, E' values\n'
|
||||||
|
, E' (audit_kind, id, 1'
|
||||||
|
);
|
||||||
|
|
||||||
|
foreach col in array tracked_columns loop
|
||||||
|
create_do_table_audit := concat( create_do_table_audit
|
||||||
|
, ', prev_', (col.column_)
|
||||||
|
);
|
||||||
|
end loop;
|
||||||
|
|
||||||
|
create_do_table_audit := concat( create_do_table_audit
|
||||||
|
, E');\n'
|
||||||
|
, E' return NEW;\n'
|
||||||
|
, E'end;\n'
|
||||||
|
, E'\$\$;'
|
||||||
|
);
|
||||||
|
-- <<< create function do_X_audit()
|
||||||
|
|
||||||
|
create_trigger_table_audit := concat( 'create trigger trigger_', table_, E'_audit\n'
|
||||||
|
, 'after insert or update on ', schema, '.', table_, E'\n'
|
||||||
|
, 'for each row execute function ', do_table_audit, '();'
|
||||||
|
);
|
||||||
|
create_trigger_table_soft_delete := concat( 'create trigger trigger_', table_, E'_soft_delete\n'
|
||||||
|
, 'before delete on ', schema, '.', table_, E'\n'
|
||||||
|
, 'for each row execute function ', do_table_soft_delete, '();'
|
||||||
|
);
|
||||||
|
execute create_audit_table;
|
||||||
|
execute create_do_table_audit;
|
||||||
|
execute create_do_table_soft_delete;
|
||||||
|
execute create_trigger_table_audit;
|
||||||
|
execute create_trigger_table_soft_delete;
|
||||||
|
end;
|
||||||
|
$function$
|
||||||
|
;
|
1
309bbd5_to_0eb9b42.sql
Normal file
1
309bbd5_to_0eb9b42.sql
Normal file
@ -0,0 +1 @@
|
|||||||
|
|
1
3234a35_to_835faa5.sql
Normal file
1
3234a35_to_835faa5.sql
Normal file
@ -0,0 +1 @@
|
|||||||
|
|
35
3712154_to_38893b5.sql
Normal file
35
3712154_to_38893b5.sql
Normal file
@ -0,0 +1,35 @@
|
|||||||
|
set check_function_bodies = off;
|
||||||
|
|
||||||
|
CREATE OR REPLACE FUNCTION public.do_grp_add_admins()
|
||||||
|
RETURNS trigger
|
||||||
|
LANGUAGE plpgsql
|
||||||
|
AS $function$
|
||||||
|
declare
|
||||||
|
admins int[];
|
||||||
|
begin
|
||||||
|
admins := ( select array_agg(usr.id)
|
||||||
|
from public.grp_members_admins() as usr
|
||||||
|
);
|
||||||
|
|
||||||
|
perform public.grp_add_members( to_grp => NEW.id
|
||||||
|
, add_usrs => admins
|
||||||
|
);
|
||||||
|
|
||||||
|
return null;
|
||||||
|
end;
|
||||||
|
$function$
|
||||||
|
;
|
||||||
|
|
||||||
|
CREATE OR REPLACE FUNCTION public.grp_members(of_grp integer)
|
||||||
|
RETURNS SETOF usr
|
||||||
|
LANGUAGE plpgsql
|
||||||
|
STABLE
|
||||||
|
AS $function$
|
||||||
|
begin
|
||||||
|
return query select u.*
|
||||||
|
from public.grp_usr gu
|
||||||
|
inner join public.usr u on gu.usr = u.id
|
||||||
|
where gu.grp = of_grp;
|
||||||
|
end;
|
||||||
|
$function$
|
||||||
|
;
|
1
38893b5_to_fe4288d.sql
Normal file
1
38893b5_to_fe4288d.sql
Normal file
@ -0,0 +1 @@
|
|||||||
|
|
1
3a14f00_to_d0526f0.sql
Normal file
1
3a14f00_to_d0526f0.sql
Normal file
@ -0,0 +1 @@
|
|||||||
|
|
1
3c7189c_to_d5749b0.sql
Normal file
1
3c7189c_to_d5749b0.sql
Normal file
@ -0,0 +1 @@
|
|||||||
|
|
1
3e57563_to_e92e56d.sql
Normal file
1
3e57563_to_e92e56d.sql
Normal file
@ -0,0 +1 @@
|
|||||||
|
|
1
43d2f59_to_c462e62.sql
Normal file
1
43d2f59_to_c462e62.sql
Normal file
@ -0,0 +1 @@
|
|||||||
|
|
1
442d4e8_to_5da43dd.sql
Normal file
1
442d4e8_to_5da43dd.sql
Normal file
@ -0,0 +1 @@
|
|||||||
|
|
1
46b4bc6_to_309bbd5.sql
Normal file
1
46b4bc6_to_309bbd5.sql
Normal file
@ -0,0 +1 @@
|
|||||||
|
|
200
49bed63_to_7a4d728.sql
Normal file
200
49bed63_to_7a4d728.sql
Normal file
@ -0,0 +1,200 @@
|
|||||||
|
alter table "public"."usr" drop constraint "usr_username_key";
|
||||||
|
|
||||||
|
alter table "public"."usr_audit" drop constraint "fk_usr_audit_actor";
|
||||||
|
|
||||||
|
alter table "public"."usr_audit" drop constraint "fk_usr_audit_usr";
|
||||||
|
|
||||||
|
drop index if exists "public"."usr_username_key";
|
||||||
|
|
||||||
|
alter table "public"."usr_audit" add constraint "usr_audit_actor_fkey" FOREIGN KEY (actor) REFERENCES usr(id) not valid;
|
||||||
|
|
||||||
|
alter table "public"."usr_audit" validate constraint "usr_audit_actor_fkey";
|
||||||
|
|
||||||
|
alter table "public"."usr_audit" add constraint "usr_audit_usr_fkey" FOREIGN KEY (usr) REFERENCES usr(id) not valid;
|
||||||
|
|
||||||
|
alter table "public"."usr_audit" validate constraint "usr_audit_usr_fkey";
|
||||||
|
|
||||||
|
set check_function_bodies = off;
|
||||||
|
|
||||||
|
create type "public"."audited_column" as ("column_" text, "type_" text);
|
||||||
|
|
||||||
|
CREATE OR REPLACE FUNCTION public.setup_audit_and_soft_delete(schema text, table_ text, tracked_columns audited_column[])
|
||||||
|
RETURNS void
|
||||||
|
LANGUAGE plpgsql
|
||||||
|
AS $function$
|
||||||
|
declare
|
||||||
|
col audited_column;
|
||||||
|
audit_table text := concat(schema, '.', table_, '_audit');
|
||||||
|
do_table_audit text := concat(schema, '.do_', table_, '_audit');
|
||||||
|
do_table_soft_delete text := concat(schema, '.do_', table_, '_soft_delete');
|
||||||
|
create_audit_table text := '';
|
||||||
|
create_do_table_audit text := '';
|
||||||
|
create_do_table_soft_delete text := '';
|
||||||
|
create_trigger_table_audit text := '';
|
||||||
|
create_trigger_table_soft_delete text := '';
|
||||||
|
begin
|
||||||
|
-- create table X_audit() >>>
|
||||||
|
create_audit_table := concat( create_audit_table
|
||||||
|
, 'create table ', audit_table, E'\n'
|
||||||
|
, ' ( ', table_, ' int not null references ', table_, '(id)', E'\n'
|
||||||
|
, ' , kind public.audit_kind not null', E'\n'
|
||||||
|
, ' , actor int not null references public.usr (id)', E'\n'
|
||||||
|
);
|
||||||
|
|
||||||
|
foreach col in array tracked_columns loop
|
||||||
|
create_audit_table := concat( create_audit_table
|
||||||
|
, E' , prev_', (col.column_), ' ', (col.type_), E' null\n'
|
||||||
|
);
|
||||||
|
end loop;
|
||||||
|
|
||||||
|
create_audit_table := concat( create_audit_table
|
||||||
|
, ' );'
|
||||||
|
);
|
||||||
|
-- <<< create table X_audit()
|
||||||
|
|
||||||
|
-- create function do_X_soft_delete() >>>
|
||||||
|
create_do_table_soft_delete := concat( create_do_table_soft_delete
|
||||||
|
, 'create function ', do_table_soft_delete, E'() returns trigger language plpgsql as \$\$\n'
|
||||||
|
, E'begin\n'
|
||||||
|
, E' insert into ', audit_table, E'\n'
|
||||||
|
, E' (', table_, E', kind, actor)\n'
|
||||||
|
, E' values\n'
|
||||||
|
, E' (OLD.id, \'delete\', 1);\n'
|
||||||
|
, E'\n'
|
||||||
|
, E' update ', schema, '.', table_, E'\n'
|
||||||
|
, E' set deleted = true\n'
|
||||||
|
, E' where id = OLD.id;\n'
|
||||||
|
, E'\n'
|
||||||
|
, E' return null;\n'
|
||||||
|
, E'end;\n'
|
||||||
|
, E'\$\$;'
|
||||||
|
);
|
||||||
|
-- <<< create function do_X_soft_delete()
|
||||||
|
|
||||||
|
-- create function do_X_audit() >>>
|
||||||
|
create_do_table_audit := concat( create_do_table_audit
|
||||||
|
, 'create function ', do_table_audit, E'() returns trigger language plpgsql as \$\$\n'
|
||||||
|
, E'declare\n'
|
||||||
|
, E' audit_kind public.audit_kind;\n'
|
||||||
|
, E' id int;\n'
|
||||||
|
);
|
||||||
|
|
||||||
|
foreach col in array tracked_columns loop
|
||||||
|
create_do_table_audit := concat( create_do_table_audit
|
||||||
|
, 'prev_', (col.column_), ' ', (col.type_), E';\n'
|
||||||
|
);
|
||||||
|
end loop;
|
||||||
|
|
||||||
|
create_do_table_audit := concat( create_do_table_audit
|
||||||
|
, E'begin\n'
|
||||||
|
, E' if (TG_OP = \'INSERT\') then\n'
|
||||||
|
, E' id := NEW.id;\n'
|
||||||
|
, E' audit_kind := \'create\';\n'
|
||||||
|
, E' elsif (TG_OP = \'UPDATE\') then\n'
|
||||||
|
, E' id := OLD.id;\n'
|
||||||
|
, E' audit_kind := \'modify\';\n'
|
||||||
|
);
|
||||||
|
|
||||||
|
foreach col in array tracked_columns loop
|
||||||
|
create_do_table_audit := concat( create_do_table_audit
|
||||||
|
, ' prev_', (col.column_), ' := OLD.', (col.column_), E';\n'
|
||||||
|
);
|
||||||
|
end loop;
|
||||||
|
|
||||||
|
create_do_table_audit := concat( create_do_table_audit
|
||||||
|
, E' end if;\n'
|
||||||
|
, E' insert into public.usr_audit\n'
|
||||||
|
, E' (kind, usr, actor'
|
||||||
|
);
|
||||||
|
|
||||||
|
foreach col in array tracked_columns loop
|
||||||
|
create_do_table_audit := concat( create_do_table_audit
|
||||||
|
, ', prev_', (col.column_)
|
||||||
|
);
|
||||||
|
end loop;
|
||||||
|
|
||||||
|
create_do_table_audit := concat( create_do_table_audit
|
||||||
|
, E' )\n'
|
||||||
|
, E' values\n'
|
||||||
|
, E' (audit_kind, id, 1'
|
||||||
|
);
|
||||||
|
|
||||||
|
foreach col in array tracked_columns loop
|
||||||
|
create_do_table_audit := concat( create_do_table_audit
|
||||||
|
, ', prev_', (col.column_)
|
||||||
|
);
|
||||||
|
end loop;
|
||||||
|
|
||||||
|
create_do_table_audit := concat( create_do_table_audit
|
||||||
|
, E');\n'
|
||||||
|
, E' return NEW;\n'
|
||||||
|
, E'end;\n'
|
||||||
|
, E'\$\$;'
|
||||||
|
);
|
||||||
|
-- <<< create function do_X_audit()
|
||||||
|
|
||||||
|
create_trigger_table_audit := concat( 'create trigger trigger_', table_, E'_audit\n'
|
||||||
|
, 'after insert or update on ', schema, '.', table_, E'\n'
|
||||||
|
, 'for each row execute function ', do_table_audit, '();'
|
||||||
|
);
|
||||||
|
create_trigger_table_soft_delete := concat( 'create trigger trigger_', table_, E'_soft_delete\n'
|
||||||
|
, 'before delete on ', schema, '.', table_, E'\n'
|
||||||
|
, 'for each row execute function ', do_table_soft_delete, '();'
|
||||||
|
);
|
||||||
|
execute create_audit_table;
|
||||||
|
execute create_do_table_audit;
|
||||||
|
execute create_do_table_soft_delete;
|
||||||
|
execute create_trigger_table_audit;
|
||||||
|
execute create_trigger_table_soft_delete;
|
||||||
|
end;
|
||||||
|
$function$
|
||||||
|
;
|
||||||
|
|
||||||
|
CREATE OR REPLACE FUNCTION public.do_usr_audit()
|
||||||
|
RETURNS trigger
|
||||||
|
LANGUAGE plpgsql
|
||||||
|
AS $function$
|
||||||
|
declare
|
||||||
|
audit_kind public.audit_kind;
|
||||||
|
id int;
|
||||||
|
prev_username public.usr_username;
|
||||||
|
prev_password public.hashed_text;
|
||||||
|
prev_email public.email;
|
||||||
|
begin
|
||||||
|
if (TG_OP = 'INSERT') then
|
||||||
|
id := NEW.id;
|
||||||
|
audit_kind := 'create';
|
||||||
|
elsif (TG_OP = 'UPDATE') then
|
||||||
|
id := OLD.id;
|
||||||
|
audit_kind := 'modify';
|
||||||
|
prev_username := OLD.username;
|
||||||
|
prev_password := OLD.password;
|
||||||
|
prev_email := OLD.email;
|
||||||
|
end if;
|
||||||
|
insert into public.usr_audit
|
||||||
|
(kind, usr, actor, prev_username, prev_password, prev_email )
|
||||||
|
values
|
||||||
|
(audit_kind, id, 1, prev_username, prev_password, prev_email);
|
||||||
|
return NEW;
|
||||||
|
end;
|
||||||
|
$function$
|
||||||
|
;
|
||||||
|
|
||||||
|
CREATE OR REPLACE FUNCTION public.do_usr_soft_delete()
|
||||||
|
RETURNS trigger
|
||||||
|
LANGUAGE plpgsql
|
||||||
|
AS $function$
|
||||||
|
begin
|
||||||
|
insert into public.usr_audit
|
||||||
|
(usr, kind, actor)
|
||||||
|
values
|
||||||
|
(OLD.id, 'delete', 1);
|
||||||
|
|
||||||
|
update public.usr
|
||||||
|
set deleted = true
|
||||||
|
where id = OLD.id;
|
||||||
|
|
||||||
|
return null;
|
||||||
|
end;
|
||||||
|
$function$
|
||||||
|
;
|
1
4a81f5f_to_eba0043.sql
Normal file
1
4a81f5f_to_eba0043.sql
Normal file
@ -0,0 +1 @@
|
|||||||
|
|
1
4b9a59a_skipped.sql
Normal file
1
4b9a59a_skipped.sql
Normal file
@ -0,0 +1 @@
|
|||||||
|
|
1
508c1c2_skipped.sql
Normal file
1
508c1c2_skipped.sql
Normal file
@ -0,0 +1 @@
|
|||||||
|
|
1
5105b7f_to_c0d37ca.sql
Normal file
1
5105b7f_to_c0d37ca.sql
Normal file
@ -0,0 +1 @@
|
|||||||
|
|
1
5169bcb_to_6a5d100.sql
Normal file
1
5169bcb_to_6a5d100.sql
Normal file
@ -0,0 +1 @@
|
|||||||
|
|
1
533493e_to_6941558.sql
Normal file
1
533493e_to_6941558.sql
Normal file
@ -0,0 +1 @@
|
|||||||
|
|
1
548f60b_skipped.sql
Normal file
1
548f60b_skipped.sql
Normal file
@ -0,0 +1 @@
|
|||||||
|
|
1
5521049_to_7825f89.sql
Normal file
1
5521049_to_7825f89.sql
Normal file
@ -0,0 +1 @@
|
|||||||
|
|
1
55fca68_skipped.sql
Normal file
1
55fca68_skipped.sql
Normal file
@ -0,0 +1 @@
|
|||||||
|
|
1
56957d3_to_e6a9378.sql
Normal file
1
56957d3_to_e6a9378.sql
Normal file
@ -0,0 +1 @@
|
|||||||
|
|
1
56980bf_to_f84b8ed.sql
Normal file
1
56980bf_to_f84b8ed.sql
Normal file
@ -0,0 +1 @@
|
|||||||
|
|
1
5da43dd_to_0d639e8.sql
Normal file
1
5da43dd_to_0d639e8.sql
Normal file
@ -0,0 +1 @@
|
|||||||
|
|
1
5e39afb_skipped.sql
Normal file
1
5e39afb_skipped.sql
Normal file
@ -0,0 +1 @@
|
|||||||
|
|
1
5f31077_to_be07aca.sql
Normal file
1
5f31077_to_be07aca.sql
Normal file
@ -0,0 +1 @@
|
|||||||
|
|
1
5f9c3c7_to_e4984dd.sql
Normal file
1
5f9c3c7_to_e4984dd.sql
Normal file
@ -0,0 +1 @@
|
|||||||
|
|
1
60a672d_to_f9fa376.sql
Normal file
1
60a672d_to_f9fa376.sql
Normal file
@ -0,0 +1 @@
|
|||||||
|
|
1
629bc32_to_533493e.sql
Normal file
1
629bc32_to_533493e.sql
Normal file
@ -0,0 +1 @@
|
|||||||
|
|
1
658ad01_to_3712154.sql
Normal file
1
658ad01_to_3712154.sql
Normal file
@ -0,0 +1 @@
|
|||||||
|
|
1
65b6f0f_to_0728ba9.sql
Normal file
1
65b6f0f_to_0728ba9.sql
Normal file
@ -0,0 +1 @@
|
|||||||
|
|
1
65f7926_to_885e22c.sql
Normal file
1
65f7926_to_885e22c.sql
Normal file
@ -0,0 +1 @@
|
|||||||
|
|
50
6700413_to_68cd9c5.sql
Normal file
50
6700413_to_68cd9c5.sql
Normal file
@ -0,0 +1,50 @@
|
|||||||
|
set check_function_bodies = off;
|
||||||
|
|
||||||
|
CREATE OR REPLACE FUNCTION public.create_newtype_text(qualified_name text)
|
||||||
|
RETURNS void
|
||||||
|
LANGUAGE plpgsql
|
||||||
|
AS $function$
|
||||||
|
begin
|
||||||
|
execute concat('create type ', qualified_name, ' as (str text);');
|
||||||
|
execute concat( 'create function '
|
||||||
|
, qualified_name || '_to_string(val ' || qualified_name || ')'
|
||||||
|
, E' returns text language sql as \'select (val.str);\';'
|
||||||
|
);
|
||||||
|
execute concat( 'create function '
|
||||||
|
, qualified_name || '_of_string(val text)'
|
||||||
|
, ' returns ' || qualified_name || E' language sql as \'select row(val);\';'
|
||||||
|
);
|
||||||
|
execute concat( 'create cast '
|
||||||
|
, ' (' || qualified_name || ' as text)'
|
||||||
|
, ' with function ' || qualified_name || E'_to_string(' || qualified_name || ')'
|
||||||
|
, ' as assignment;'
|
||||||
|
);
|
||||||
|
execute concat( 'create cast '
|
||||||
|
, ' (text as ' || qualified_name || ')'
|
||||||
|
, ' with function ' || qualified_name || E'_of_string(text)'
|
||||||
|
, ' as assignment;'
|
||||||
|
);
|
||||||
|
end;
|
||||||
|
$function$
|
||||||
|
;
|
||||||
|
|
||||||
|
create cast (public.usr_tag as text) with function public.usr_tag_to_string(public.usr_tag) as assignment;
|
||||||
|
create cast (text as public.usr_tag) with function public.usr_tag_of_string(text) as assignment;
|
||||||
|
|
||||||
|
create cast (public.usr_session_key as text) with function public.usr_session_key_to_string(public.usr_session_key) as assignment;
|
||||||
|
create cast (text as public.usr_session_key) with function public.usr_session_key_of_string(text) as assignment;
|
||||||
|
|
||||||
|
create cast (public.grp_tag as text) with function public.grp_tag_to_string(public.grp_tag) as assignment;
|
||||||
|
create cast (text as public.grp_tag) with function public.grp_tag_of_string(text) as assignment;
|
||||||
|
|
||||||
|
create cast (public.community_tag as text) with function public.community_tag_to_string(public.community_tag) as assignment;
|
||||||
|
create cast (text as public.community_tag) with function public.community_tag_of_string(text) as assignment;
|
||||||
|
|
||||||
|
create cast (public.email as text) with function public.email_to_string(public.email) as assignment;
|
||||||
|
create cast (text as public.email) with function public.email_of_string(text) as assignment;
|
||||||
|
|
||||||
|
create cast (public.hashed_text as text) with function public.hashed_text_to_string(public.hashed_text) as assignment;
|
||||||
|
create cast (text as public.hashed_text) with function public.hashed_text_of_string(text) as assignment;
|
||||||
|
|
||||||
|
create cast (human_uuid.huid as text) with function human_uuid.huid_to_string(human_uuid.huid) as assignment;
|
||||||
|
create cast (text as human_uuid.huid) with function human_uuid.huid_of_string(text) as assignment;
|
1
68cd9c5_to_ee6390d.sql
Normal file
1
68cd9c5_to_ee6390d.sql
Normal file
@ -0,0 +1 @@
|
|||||||
|
|
1
6941558_to_cda6320.sql
Normal file
1
6941558_to_cda6320.sql
Normal file
@ -0,0 +1 @@
|
|||||||
|
|
1
6a5d100_to_b402f08.sql
Normal file
1
6a5d100_to_b402f08.sql
Normal file
@ -0,0 +1 @@
|
|||||||
|
|
1
6b1557a_to_c310921.sql
Normal file
1
6b1557a_to_c310921.sql
Normal file
@ -0,0 +1 @@
|
|||||||
|
|
1
6d10cb3_skipped.sql
Normal file
1
6d10cb3_skipped.sql
Normal file
@ -0,0 +1 @@
|
|||||||
|
|
1
6f08ab4_skipped.sql
Normal file
1
6f08ab4_skipped.sql
Normal file
@ -0,0 +1 @@
|
|||||||
|
|
1
6f52cad_skipped.sql
Normal file
1
6f52cad_skipped.sql
Normal file
@ -0,0 +1 @@
|
|||||||
|
|
1
70a8bca_to_fd395c2.sql
Normal file
1
70a8bca_to_fd395c2.sql
Normal file
@ -0,0 +1 @@
|
|||||||
|
|
1
72e1e0e_to_5521049.sql
Normal file
1
72e1e0e_to_5521049.sql
Normal file
@ -0,0 +1 @@
|
|||||||
|
|
62
7371374_to_94501b7.sql
Normal file
62
7371374_to_94501b7.sql
Normal file
@ -0,0 +1,62 @@
|
|||||||
|
alter table "public"."audit" drop constraint "audit_pkey";
|
||||||
|
|
||||||
|
drop index if exists "public"."audit_pkey";
|
||||||
|
|
||||||
|
drop table "public"."audit";
|
||||||
|
|
||||||
|
set check_function_bodies = off;
|
||||||
|
|
||||||
|
CREATE OR REPLACE FUNCTION public.do_usr_audit()
|
||||||
|
RETURNS trigger
|
||||||
|
LANGUAGE plpgsql
|
||||||
|
AS $function$
|
||||||
|
declare
|
||||||
|
audit_kind public.audit_kind;
|
||||||
|
usr_id int;
|
||||||
|
prev_username public.usr_username := null;
|
||||||
|
prev_password public.hashed_text := null;
|
||||||
|
prev_email public.email := null;
|
||||||
|
begin
|
||||||
|
if (TG_OP = 'UPDATE') then
|
||||||
|
usr_id := OLD.id;
|
||||||
|
audit_kind := 'modify';
|
||||||
|
prev_username := OLD.username;
|
||||||
|
prev_password := OLD.password;
|
||||||
|
prev_email := OLD.email;
|
||||||
|
elsif (TG_OP = 'INSERT') then
|
||||||
|
usr_id := NEW.id;
|
||||||
|
audit_kind := 'create';
|
||||||
|
end if;
|
||||||
|
|
||||||
|
insert into public.usr_audit
|
||||||
|
(kind, usr, actor, prev_username, prev_email, prev_password )
|
||||||
|
values
|
||||||
|
-- TODO actor
|
||||||
|
(audit_kind, usr_id, usr_id, prev_username, prev_email, prev_password );
|
||||||
|
|
||||||
|
return NEW;
|
||||||
|
end;
|
||||||
|
$function$
|
||||||
|
;
|
||||||
|
|
||||||
|
CREATE OR REPLACE FUNCTION public.do_usr_soft_delete()
|
||||||
|
RETURNS trigger
|
||||||
|
LANGUAGE plpgsql
|
||||||
|
AS $function$
|
||||||
|
declare
|
||||||
|
audit_id int;
|
||||||
|
begin
|
||||||
|
insert into public.usr_audit
|
||||||
|
(kind, usr, actor)
|
||||||
|
values
|
||||||
|
-- TODO actor
|
||||||
|
('delete' :: public.audit_kind, OLD.id, OLD.id);
|
||||||
|
|
||||||
|
update public.usr
|
||||||
|
set deleted = true
|
||||||
|
where id = OLD.id;
|
||||||
|
|
||||||
|
return null;
|
||||||
|
end;
|
||||||
|
$function$
|
||||||
|
;
|
1
7613dc8_to_3a14f00.sql
Normal file
1
7613dc8_to_3a14f00.sql
Normal file
@ -0,0 +1 @@
|
|||||||
|
|
1
7825f89_to_994fa9d.sql
Normal file
1
7825f89_to_994fa9d.sql
Normal file
@ -0,0 +1 @@
|
|||||||
|
|
53
7a4d728_to_c19a46b.sql
Normal file
53
7a4d728_to_c19a46b.sql
Normal file
@ -0,0 +1,53 @@
|
|||||||
|
drop function if exists "public"."hashed_text_string"(hashed hashed_text);
|
||||||
|
|
||||||
|
alter type "public"."email" rename attribute "email" to "str";
|
||||||
|
|
||||||
|
alter type "public"."hashed_text" rename attribute "hashed" to "str";
|
||||||
|
|
||||||
|
set check_function_bodies = off;
|
||||||
|
|
||||||
|
CREATE OR REPLACE FUNCTION public.email_of_string(val text)
|
||||||
|
RETURNS email
|
||||||
|
LANGUAGE sql
|
||||||
|
AS $function$select row(val);$function$
|
||||||
|
;
|
||||||
|
|
||||||
|
CREATE OR REPLACE FUNCTION public.email_to_string(val email)
|
||||||
|
RETURNS text
|
||||||
|
LANGUAGE sql
|
||||||
|
AS $function$select (val.str);$function$
|
||||||
|
;
|
||||||
|
|
||||||
|
CREATE OR REPLACE FUNCTION public.hashed_text_of_string(val text)
|
||||||
|
RETURNS hashed_text
|
||||||
|
LANGUAGE sql
|
||||||
|
AS $function$select row(val);$function$
|
||||||
|
;
|
||||||
|
|
||||||
|
CREATE OR REPLACE FUNCTION public.hashed_text_to_string(val hashed_text)
|
||||||
|
RETURNS text
|
||||||
|
LANGUAGE sql
|
||||||
|
AS $function$select (val.str);$function$
|
||||||
|
;
|
||||||
|
|
||||||
|
CREATE OR REPLACE FUNCTION public.hash_text(plain text)
|
||||||
|
RETURNS hashed_text
|
||||||
|
LANGUAGE plpgsql
|
||||||
|
IMMUTABLE
|
||||||
|
AS $function$
|
||||||
|
begin
|
||||||
|
return hashed_text_of_string(crypt(plain, gen_salt('bf')));
|
||||||
|
end;
|
||||||
|
$function$
|
||||||
|
;
|
||||||
|
|
||||||
|
CREATE OR REPLACE FUNCTION public.hashed_text_matches(plain text, hashed hashed_text)
|
||||||
|
RETURNS boolean
|
||||||
|
LANGUAGE plpgsql
|
||||||
|
IMMUTABLE
|
||||||
|
AS $function$
|
||||||
|
begin
|
||||||
|
return hashed_text_to_string(hashed) = crypt(plain, hashed_text_to_string(hashed));
|
||||||
|
end;
|
||||||
|
$function$
|
||||||
|
;
|
1
7cda196_to_1bf3d29.sql
Normal file
1
7cda196_to_1bf3d29.sql
Normal file
@ -0,0 +1 @@
|
|||||||
|
|
1
80d94f9_skipped.sql
Normal file
1
80d94f9_skipped.sql
Normal file
@ -0,0 +1 @@
|
|||||||
|
|
1
835faa5_to_3e57563.sql
Normal file
1
835faa5_to_3e57563.sql
Normal file
@ -0,0 +1 @@
|
|||||||
|
|
1
86bb834_to_1dae8d2.sql
Normal file
1
86bb834_to_1dae8d2.sql
Normal file
@ -0,0 +1 @@
|
|||||||
|
|
30
87f7a4d_to_b3de72d.sql
Normal file
30
87f7a4d_to_b3de72d.sql
Normal file
@ -0,0 +1,30 @@
|
|||||||
|
alter table "public"."usr_session" alter column "key" drop default;
|
||||||
|
|
||||||
|
set check_function_bodies = off;
|
||||||
|
|
||||||
|
CREATE OR REPLACE FUNCTION public.usr_session_login(tag_or_email usr_tag_or_email, password text, remember boolean DEFAULT false, location text DEFAULT NULL::text, device usr_session_device DEFAULT NULL::usr_session_device, ip inet DEFAULT NULL::inet)
|
||||||
|
RETURNS usr_session_key
|
||||||
|
LANGUAGE plpgsql
|
||||||
|
AS $function$
|
||||||
|
declare
|
||||||
|
usr public.usr;
|
||||||
|
key public.usr_session_key := usr_session_key_gen();
|
||||||
|
expires_at timestamp;
|
||||||
|
begin
|
||||||
|
usr := public.usr_session_login_validate(tag_or_email, password);
|
||||||
|
|
||||||
|
if remember then
|
||||||
|
expires_at := now() + interval '1 week';
|
||||||
|
else
|
||||||
|
expires_at := now() + interval '1 hour';
|
||||||
|
end if;
|
||||||
|
|
||||||
|
insert into public.usr_session
|
||||||
|
(key, expires_at, usr, location, device, ip)
|
||||||
|
values
|
||||||
|
(key, expires_at, usr.id, location, device, ip);
|
||||||
|
|
||||||
|
return key;
|
||||||
|
end;
|
||||||
|
$function$
|
||||||
|
;
|
1
885e22c_to_27a69a5.sql
Normal file
1
885e22c_to_27a69a5.sql
Normal file
@ -0,0 +1 @@
|
|||||||
|
|
1
89df399_to_bba7d98.sql
Normal file
1
89df399_to_bba7d98.sql
Normal file
@ -0,0 +1 @@
|
|||||||
|
|
4812
8b08d9f_to_4a81f5f.sql
Normal file
4812
8b08d9f_to_4a81f5f.sql
Normal file
File diff suppressed because it is too large
Load Diff
1
8b648a8_to_89df399.sql
Normal file
1
8b648a8_to_89df399.sql
Normal file
@ -0,0 +1 @@
|
|||||||
|
|
1
9226df1_skipped.sql
Normal file
1
9226df1_skipped.sql
Normal file
@ -0,0 +1 @@
|
|||||||
|
|
1
93e81ad_to_16a20c2.sql
Normal file
1
93e81ad_to_16a20c2.sql
Normal file
@ -0,0 +1 @@
|
|||||||
|
|
32
94501b7_to_047a51b.sql
Normal file
32
94501b7_to_047a51b.sql
Normal file
@ -0,0 +1,32 @@
|
|||||||
|
create extension if not exists "pgcrypto" with schema "public" version '1.3';
|
||||||
|
|
||||||
|
set check_function_bodies = off;
|
||||||
|
|
||||||
|
CREATE OR REPLACE FUNCTION public.hash_text(plain text)
|
||||||
|
RETURNS hashed_text
|
||||||
|
LANGUAGE plpgsql
|
||||||
|
IMMUTABLE
|
||||||
|
AS $function$
|
||||||
|
begin
|
||||||
|
return row(crypt(plain, gen_salt('bf')));
|
||||||
|
end;
|
||||||
|
$function$
|
||||||
|
;
|
||||||
|
|
||||||
|
CREATE OR REPLACE FUNCTION public.hashed_text_matches(plain text, hashed hashed_text)
|
||||||
|
RETURNS boolean
|
||||||
|
LANGUAGE plpgsql
|
||||||
|
IMMUTABLE
|
||||||
|
AS $function$
|
||||||
|
begin
|
||||||
|
return hashed_text_string(hashed) = crypt(plain, hashed_text_string(hashed));
|
||||||
|
end;
|
||||||
|
$function$
|
||||||
|
;
|
||||||
|
|
||||||
|
CREATE OR REPLACE FUNCTION public.hashed_text_string(hashed hashed_text)
|
||||||
|
RETURNS text
|
||||||
|
LANGUAGE sql
|
||||||
|
IMMUTABLE
|
||||||
|
AS $function$select (hashed.hashed);$function$
|
||||||
|
;
|
1
94ab122_to_9abd45a.sql
Normal file
1
94ab122_to_9abd45a.sql
Normal file
@ -0,0 +1 @@
|
|||||||
|
|
1
9569e36_to_da31970.sql
Normal file
1
9569e36_to_da31970.sql
Normal file
@ -0,0 +1 @@
|
|||||||
|
|
1
96937df_skipped.sql
Normal file
1
96937df_skipped.sql
Normal file
@ -0,0 +1 @@
|
|||||||
|
|
1
9929ee9_skipped.sql
Normal file
1
9929ee9_skipped.sql
Normal file
@ -0,0 +1 @@
|
|||||||
|
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user