diff --git a/resources/functions/user/check_user.sql b/resources/functions/user/check_user.sql new file mode 100644 index 0000000..4142278 --- /dev/null +++ b/resources/functions/user/check_user.sql @@ -0,0 +1,18 @@ +create or replace function check_user(in username text, in plain_password text, out resource json) language plpgsql as +$$ +declare + _username alias for username; +begin + select + case when count(u) = 1 + then to_json(json_populate_record(null::user_lite, to_json(u))) -- TODO refactor this ! + else null end + into resource + from "user" as u + where u.username = lower(_username) + and u.password = crypt(plain_password, u.password) + group by u; +end; +$$; + +-- drop function if exists check_user(text, text, out json); \ No newline at end of file diff --git a/resources/functions/user/find_user_by_id.sql b/resources/functions/user/find_user_by_id.sql new file mode 100644 index 0000000..7f2e1ca --- /dev/null +++ b/resources/functions/user/find_user_by_id.sql @@ -0,0 +1,12 @@ +create or replace procedure find_user_by_id(in id uuid, inout resource json) language plpgsql as +$$ +declare + _id alias for id; +begin + select to_json(u) into resource + from "user" as u + where u.id = _id; +end; +$$; + +-- drop procedure if exists find_user_by_id(inout json); \ No newline at end of file diff --git a/resources/functions/user/find_user_by_username.sql b/resources/functions/user/find_user_by_username.sql new file mode 100644 index 0000000..c8c6e4b --- /dev/null +++ b/resources/functions/user/find_user_by_username.sql @@ -0,0 +1,12 @@ +create or replace procedure find_user_by_username(in username text, inout resource json) language plpgsql as +$$ +declare + _username alias for username; +begin + select to_json(u) into resource + from "user" as u + where u.username = _username; +end; +$$; + +-- drop procedure if exists find_user_by_username(text, inout json); \ No newline at end of file diff --git a/resources/functions/user/insert_user.sql b/resources/functions/user/insert_user.sql new file mode 100644 index 0000000..803b268 --- /dev/null +++ b/resources/functions/user/insert_user.sql @@ -0,0 +1,20 @@ +create or replace procedure insert_user(inout resource json) language plpgsql as +$$ +declare + new_id uuid; +begin + insert into "user" (username, password, blocked_at) + select + username, + crypt(resource->>'plain_password', gen_salt('bf', 8)), + case when blocked_at is not null then now() else null end + from json_populate_record(null::"user", resource) + returning id into new_id; + + select to_json(u) into resource + from "user" as u + where u.id = new_id; +end; +$$; + +-- drop procedure if exists insert_user(inout json); \ No newline at end of file diff --git a/resources/sql/migrations/0000-init_schema.up.sql b/resources/sql/migrations/0000-init_schema.up.sql index 8ec5264..4f6577b 100644 --- a/resources/sql/migrations/0000-init_schema.up.sql +++ b/resources/sql/migrations/0000-init_schema.up.sql @@ -1,9 +1,5 @@ -- Users create extension if not exists pgcrypto; --- select * --- from "user" --- where username = lower('nick@example.com') --- and password = crypt('12346', password); create table "user" ( diff --git a/resources/sql/migrations/0000-init_view.down.sql b/resources/sql/migrations/0000-init_view.down.sql new file mode 100644 index 0000000..3a46f2f --- /dev/null +++ b/resources/sql/migrations/0000-init_view.down.sql @@ -0,0 +1,2 @@ +-- User +drop view if exists user_lite; \ No newline at end of file diff --git a/resources/sql/migrations/0000-init_view.up.sql b/resources/sql/migrations/0000-init_view.up.sql new file mode 100644 index 0000000..354be37 --- /dev/null +++ b/resources/sql/migrations/0000-init_view.up.sql @@ -0,0 +1,5 @@ +-- User +create or replace view user_lite as +select u.id, u.created_at, u.blocked_at, u.username +from "user" u +where u.blocked_at is null; \ No newline at end of file diff --git a/resources/tests/user.sql b/resources/tests/user.sql new file mode 100644 index 0000000..6db54af --- /dev/null +++ b/resources/tests/user.sql @@ -0,0 +1,31 @@ +do +$$ +declare + created_user json := '{"username": "george", "plain_password": "azerty"}'; + selected_user json; + exist_user json; +begin + call insert_user(created_user); + assert created_user->>'username' = 'george', 'username must be george'; + assert created_user->>'password' is not null, 'password must be generated'; + + call find_user_by_id((created_user->>'id')::uuid, selected_user); + assert selected_user->>'username' = 'george', 'username must be george'; + + call find_user_by_username(created_user->>'username', selected_user); + assert selected_user->>'username' = 'george', 'username must be george'; + + select check_user('george', 'azerty') into exist_user; + assert exist_user is not null, format('the function check_user must be return user object if username and password is correct, %s is return', exist_user::text); + assert exist_user->>'username' = 'george', format('the function check_user must be return user object with username is "george", %s is return', exist_user::text); + assert exist_user->>'password' is null, format('the function check_user must not be return the password, %s is return', exist_user::text); + + delete from "user" where username = 'george'; + + select check_user('george', 'azerty') into exist_user; + assert exist_user is null, format('the function check_user must be return null if user not exist, %s is return', exist_user::text); + + raise notice 'user test pass'; +end; +$$; +