Ограничить удаление пользователя из набора изменений в веб-приложении Elixir и Phoenix - PullRequest
0 голосов
/ 12 апреля 2020

Можем ли мы ограничить удаление пользователя из базы данных на основе его адреса электронной почты в состоянии Repo.delete! (Changeset) в веб-разработке elixir и phoenix

Сейчас это код, который я использую. Я хочу ограничить удаление двух пользователей из базы данных во время удаления: -

def delete(conn, _params, current_admin) do

    changeset = AdminUser.common_changeset(conn.assigns.admin_user, %{}, whodoneit(current_admin))

    Repo.delete!(changeset)

    msg = gettext("%{name} deleted successfully", name: gettext("Administrator"))

    conn
    |> put_flash(:success, msg)
    |> redirect(to: Routes.admin_admin_user_path(conn, :index))

end

1 Ответ

2 голосов
/ 13 апреля 2020

Хотя правильным способом предотвращения действий с некоторыми «записями флешки» было бы изменение базы данных для отклонения таких изменений (см. Ниже), все же можно достичь этого результата с помощью Ecto.Changeset.validate_change/3, и его больше прибитого родного брата Ecto.Changeset.validate_exclusion/4. В приведенном здесь примере показано, как предотвратить проверку некоторых наборов изменений на основе значений.

Более общий способ заключается в реализации Ecto.Repo.delete/2Ecto.Repo.delete!/2) обратные вызовы для проверки значений перед делегированием по умолчанию Ecto.Repo.Schema.delete/4

@impl Ecto.Repo
def delete(struct, opts \\ []) do
  # check the record and execute the code below
  #   if and only if the check passed
  Ecto.Repo.Schema.delete(
    __MODULE__,
    get_dynamic_repo(),
    struct,
    with_default_options(:delete, opts)
  )
end

Это все еще очень подвержено ошибкам, потому что можно просто выполнить необработанный запрос через Ecto.Adapters.SQL.query/4

Ecto.Adapters.SQL.query(MyRepo, "DELETE FROM users WHERE email = ", [admin_email])

Кроме того, можно изменить электронное письмо, и в таком случае вы захотите вместо этого защитить UPDATE.


Тем не менее, единственный правильный способ go состоит в том, чтобы полагаться на БД для отклонения таких удалений. Это можно сделать с помощью TRIGGER или RULE в PostgreSQL. Вот пример триггера.

CREATE OR REPLACE FUNCTION prevent_email_hacks()
  RETURNS "trigger" AS
'
BEGIN
  IF OLD.email = "admin@foo.bar" THEN
    RAISE EXCEPTION \'This email is locked\';
  END IF;
  RETURN NEW;
END;
'
LANGUAGE 'plpgsql' VOLATILE;

CREATE TRIGGER protect_admin
  BEFORE INSERT OR UPDATE OR DELETE
  ON users
  FOR EACH ROW
  EXECUTE PROCEDURE prevent_email_hacks();
...