139 lines
3.8 KiB
Erlang
139 lines
3.8 KiB
Erlang
-module(core_user).
|
|
-include("records.hrl").
|
|
|
|
-export([create/2, get_by_id/1, get_by_email/1, update/2, delete/1]).
|
|
-export([email_exists/1]).
|
|
-export([generate_id/0]).
|
|
-export([list_users/0]).
|
|
-export([block/1, unblock/1]).
|
|
|
|
%% Создание пользователя
|
|
create(Email, Password) ->
|
|
% Проверяем, существует ли email
|
|
case email_exists(Email) of
|
|
true ->
|
|
{error, email_exists};
|
|
false ->
|
|
Id = generate_id(),
|
|
{ok, PasswordHash} = logic_auth:hash_password(Password),
|
|
|
|
% Определяем роль: первый пользователь становится админом
|
|
Role = case mnesia:dirty_match_object(#user{_ = '_'}) of
|
|
[] -> admin;
|
|
_ -> user
|
|
end,
|
|
|
|
User = #user{
|
|
id = Id,
|
|
email = Email,
|
|
password_hash = PasswordHash,
|
|
role = Role,
|
|
status = active,
|
|
created_at = calendar:universal_time(),
|
|
updated_at = calendar:universal_time()
|
|
},
|
|
|
|
F = fun() ->
|
|
mnesia:write(User),
|
|
{ok, User}
|
|
end,
|
|
|
|
case mnesia:transaction(F) of
|
|
{atomic, Result} -> Result;
|
|
{aborted, Reason} -> {error, Reason}
|
|
end
|
|
end.
|
|
|
|
%% Получение пользователя по ID
|
|
get_by_id(Id) ->
|
|
case mnesia:dirty_read(user, Id) of
|
|
[] -> {error, not_found};
|
|
[User] -> {ok, User}
|
|
end.
|
|
|
|
%% Получение пользователя по email
|
|
get_by_email(Email) ->
|
|
Match = #user{email = Email, _ = '_'},
|
|
case mnesia:dirty_match_object(Match) of
|
|
[] -> {error, not_found};
|
|
[User] -> {ok, User}
|
|
end.
|
|
|
|
%% Проверка существования email
|
|
email_exists(Email) ->
|
|
case get_by_email(Email) of
|
|
{ok, _} -> true;
|
|
{error, _} -> false
|
|
end.
|
|
|
|
%% Обновление пользователя
|
|
update(Id, Updates) ->
|
|
F = fun() ->
|
|
case mnesia:read(user, Id) of
|
|
[] ->
|
|
{error, not_found};
|
|
[User] ->
|
|
UpdatedUser = apply_updates(User, Updates),
|
|
mnesia:write(UpdatedUser),
|
|
{ok, UpdatedUser}
|
|
end
|
|
end,
|
|
|
|
case mnesia:transaction(F) of
|
|
{atomic, Result} -> Result;
|
|
{aborted, Reason} -> {error, Reason}
|
|
end.
|
|
|
|
%% Удаление пользователя (soft delete)
|
|
delete(Id) ->
|
|
update(Id, [{status, deleted}]).
|
|
|
|
list_users() ->
|
|
Users = mnesia:dirty_match_object(#user{_ = '_'}),
|
|
ActiveUsers = [U || U <- Users, U#user.status =/= deleted],
|
|
{ok, [user_to_map(U) || U <- ActiveUsers]}.
|
|
|
|
user_to_map(User) ->
|
|
#{
|
|
id => User#user.id,
|
|
email => User#user.email,
|
|
password_hash => User#user.password_hash,
|
|
role => User#user.role,
|
|
status => User#user.status,
|
|
created_at => User#user.created_at,
|
|
updated_at => User#user.updated_at
|
|
}.
|
|
|
|
block(Id) ->
|
|
case get_by_id(Id) of
|
|
{ok, User} ->
|
|
Updated = User#user{status = blocked, updated_at = calendar:universal_time()},
|
|
mnesia:dirty_write(Updated),
|
|
{ok, Updated};
|
|
Error -> Error
|
|
end.
|
|
|
|
unblock(Id) ->
|
|
case get_by_id(Id) of
|
|
{ok, User} ->
|
|
Updated = User#user{status = active, updated_at = calendar:universal_time()},
|
|
mnesia:dirty_write(Updated),
|
|
{ok, Updated};
|
|
Error -> Error
|
|
end.
|
|
|
|
%% Внутренние функции
|
|
generate_id() ->
|
|
base64:encode(crypto:strong_rand_bytes(16), #{mode => urlsafe, padding => false}).
|
|
|
|
apply_updates(User, Updates) ->
|
|
Updated = lists:foldl(fun({Field, Value}, U) ->
|
|
set_field(Field, Value, U)
|
|
end, User, Updates),
|
|
Updated#user{updated_at = calendar:universal_time()}.
|
|
|
|
set_field(email, Value, U) -> U#user{email = Value};
|
|
set_field(password_hash, Value, U) -> U#user{password_hash = Value};
|
|
set_field(role, Value, U) when Value =:= user; Value =:= admin -> U#user{role = Value};
|
|
set_field(status, Value, U) when Value =:= active; Value =:= frozen; Value =:= deleted -> U#user{status = Value};
|
|
set_field(_, _, U) -> U. |