diff --git a/apps/lenra/lib/lenra/guardian/guardian.ex b/apps/lenra/lib/lenra/guardian/guardian.ex index fe0a1d74..579f5d1a 100644 --- a/apps/lenra/lib/lenra/guardian/guardian.ex +++ b/apps/lenra/lib/lenra/guardian/guardian.ex @@ -47,4 +47,13 @@ defmodule Lenra.Guardian do {:ok, claims} end end + + def verify_claims(claims, _options) do + with {:ok, user} <- resource_from_claims(claims), + true <- Lenra.CguService.user_accepted_latest_cgu?(user.id) do + {:ok, claims} + else + _error -> {:error, :did_not_accept_cgu} + end + end end diff --git a/apps/lenra/lib/lenra/services/cgu_services.ex b/apps/lenra/lib/lenra/services/cgu_services.ex index 8f8c1d43..47e86dda 100644 --- a/apps/lenra/lib/lenra/services/cgu_services.ex +++ b/apps/lenra/lib/lenra/services/cgu_services.ex @@ -2,14 +2,34 @@ defmodule Lenra.CguService do @moduledoc """ The service that get the latest CGU. """ + import Ecto.Query, only: [from: 2, select: 3] + alias Lenra.{Cgu, Repo} + defp get_latest_cgu_query do + Ecto.Query.last(Cgu, :inserted_at) + end + def get_latest_cgu do - cgu = Cgu |> Ecto.Query.last(:inserted_at) |> Repo.one() + cgu = get_latest_cgu_query() |> Repo.one() case cgu do nil -> {:error, :error_404} cgu -> {:ok, cgu} end end + + def user_accepted_latest_cgu?(user_id) do + latest_cgu = get_latest_cgu_query() |> select([c], c.id) + + with false <- + Repo.exists?( + from( + u in Lenra.UserAcceptCguVersion, + where: u.user_id == ^user_id and u.cgu_id in subquery(latest_cgu) + ) + ) do + not Repo.exists?(latest_cgu) + end + end end diff --git a/apps/lenra/test/lenra/services/cgu_service_test.exs b/apps/lenra/test/lenra/services/cgu_service_test.exs index 279caea5..dc09910e 100644 --- a/apps/lenra/test/lenra/services/cgu_service_test.exs +++ b/apps/lenra/test/lenra/services/cgu_service_test.exs @@ -53,4 +53,44 @@ defmodule Lenra.CguSerciceTest do assert {:ok, inserted_cgu3} == CguService.get_latest_cgu() end end + + describe "user_accepted_latest_cgu?" do + test "No CGU in database" do + {:ok, %{inserted_user: user}} = UserTestHelper.register_john_doe() + + assert true == Lenra.CguService.user_accepted_latest_cgu?(user.id) + end + + test "User did not accept CGU" do + {:ok, %{inserted_user: user}} = UserTestHelper.register_john_doe() + %{link: "a", version: "1.0.0", hash: "a"} |> Lenra.Cgu.new() |> Repo.insert() + + assert Lenra.Cgu |> Lenra.Repo.all() |> Enum.count() == 1 + assert false == Lenra.CguService.user_accepted_latest_cgu?(user.id) + end + + test "User accepted latest CGU" do + {:ok, %{inserted_user: user}} = UserTestHelper.register_john_doe() + {:ok, cgu} = %{link: "a", version: "1.0.0", hash: "a"} |> Lenra.Cgu.new() |> Repo.insert() + %{user_id: user.id, cgu_id: cgu.id} |> Lenra.UserAcceptCguVersion.new() |> Repo.insert() + + assert true == Lenra.CguService.user_accepted_latest_cgu?(user.id) + end + + test "User accepted CGU but it is not the latest" do + {:ok, %{inserted_user: user}} = UserTestHelper.register_john_doe() + {:ok, cgu} = %{link: "a", version: "1.0.0", hash: "a"} |> Lenra.Cgu.new() |> Repo.insert() + %{user_id: user.id, cgu_id: cgu.id} |> Lenra.UserAcceptCguVersion.new() |> Repo.insert() + date = DateTime.utc_now() |> DateTime.add(4, :second) |> DateTime.truncate(:second) + + {:ok, _cgu} = + %{link: "b", version: "2.0.0", hash: "b"} + |> Lenra.Cgu.new() + |> Ecto.Changeset.put_change(:inserted_at, date) + |> Ecto.Changeset.put_change(:updated_at, date) + |> Repo.insert() + + assert false == Lenra.CguService.user_accepted_latest_cgu?(user.id) + end + end end diff --git a/apps/lenra_web/lib/lenra_web/controllers/user_controller.ex b/apps/lenra_web/lib/lenra_web/controllers/user_controller.ex index 84daec69..07151793 100644 --- a/apps/lenra_web/lib/lenra_web/controllers/user_controller.ex +++ b/apps/lenra_web/lib/lenra_web/controllers/user_controller.ex @@ -24,7 +24,7 @@ defmodule LenraWeb.UserController do end def refresh(conn, _params) do - access_token = + {:ok, access_token} = conn |> Plug.current_token() |> TokenHelper.create_access_token() diff --git a/apps/lenra_web/lib/lenra_web/guardian/error_handler.ex b/apps/lenra_web/lib/lenra_web/guardian/error_handler.ex index e21ec9d8..df08d03a 100644 --- a/apps/lenra_web/lib/lenra_web/guardian/error_handler.ex +++ b/apps/lenra_web/lib/lenra_web/guardian/error_handler.ex @@ -5,6 +5,16 @@ defmodule Lenra.Guardian.ErrorHandler do @behaviour Guardian.Plug.ErrorHandler + @impl Guardian.Plug.ErrorHandler + def auth_error(conn, {:error, :did_not_accept_cgu}, _opts) do + [translated_error] = LenraWeb.ErrorHelpers.translate_error(:did_not_accept_cgu) + + conn + |> Phoenix.Controller.put_view(LenraWeb.ErrorView) + |> Plug.Conn.put_status(403) + |> Phoenix.Controller.render("403.json", error: translated_error) + end + @impl Guardian.Plug.ErrorHandler def auth_error(conn, {type, _reason}, _opts) do message = diff --git a/apps/lenra_web/lib/lenra_web/guardian/token_helper.ex b/apps/lenra_web/lib/lenra_web/guardian/token_helper.ex index 48840c51..873f867c 100644 --- a/apps/lenra_web/lib/lenra_web/guardian/token_helper.ex +++ b/apps/lenra_web/lib/lenra_web/guardian/token_helper.ex @@ -10,7 +10,7 @@ defmodule LenraWeb.TokenHelper do conn = create_refresh_and_store_cookie(conn, user) with {:ok, refresh_token} <- get_cookie_from_resp(conn), - access_token <- create_access_token(refresh_token) do + {:ok, access_token} <- create_access_token(refresh_token) do assign_access_token(conn, access_token) else error -> @@ -34,9 +34,9 @@ defmodule LenraWeb.TokenHelper do end def create_access_token(refresh_token) do - {:ok, _old, {access_token, _new_claims}} = Lenra.Guardian.exchange(refresh_token, "refresh", "access") - - access_token + with {:ok, _old, {access_token, _new_claims}} <- Lenra.Guardian.exchange(refresh_token, "refresh", "access") do + {:ok, access_token} + end end def revoke_current_refresh(conn) do diff --git a/apps/lenra_web/lib/lenra_web/views/error_helpers.ex b/apps/lenra_web/lib/lenra_web/views/error_helpers.ex index a51e465c..c5cf6d25 100644 --- a/apps/lenra_web/lib/lenra_web/views/error_helpers.ex +++ b/apps/lenra_web/lib/lenra_web/views/error_helpers.ex @@ -37,7 +37,8 @@ defmodule LenraWeb.ErrorHelpers do error_404: %{code: 404, message: "Not Found."}, error_500: %{code: 500, message: "Internal server error."}, openfaas_not_reachable: %{code: 1000, message: "Openfaas is not accessible"}, - forbidden: %{code: 403, message: "Forbidden"} + forbidden: %{code: 403, message: "Forbidden"}, + did_not_accept_cgu: %{code: 4031, message: "You must accept the CGU to use Lenra"} ] def translate_errors([]), do: [] diff --git a/apps/lenra_web/lib/lenra_web/views/error_view.ex b/apps/lenra_web/lib/lenra_web/views/error_view.ex index 12905813..c30ede86 100644 --- a/apps/lenra_web/lib/lenra_web/views/error_view.ex +++ b/apps/lenra_web/lib/lenra_web/views/error_view.ex @@ -20,8 +20,8 @@ defmodule LenraWeb.ErrorView do %{"errors" => [%{code: 401, message: "Unauthorized"}], "success" => false} end - def render("403.json", %{message: message}) do - %{"errors" => [%{code: 403, message: message}], "success" => false} + def render("403.json", %{error: error}) do + %{"errors" => [error], "success" => false} end def render("403.json", _assigns) do