diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index e8fdf30..07ddf29 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -200,7 +200,7 @@ jobs: uses: josecfreittas/elixir-coverage-feedback-action@v1 with: github_token: ${{ secrets.GITHUB_TOKEN }} - coverage_threshold: 70 + coverage_threshold: 80 services: pg: image: postgres:16 diff --git a/apps/core/test/core/schema/topic_test.exs b/apps/core/test/core/schema/topic_test.exs index 411737f..84aad30 100644 --- a/apps/core/test/core/schema/topic_test.exs +++ b/apps/core/test/core/schema/topic_test.exs @@ -33,7 +33,10 @@ defmodule Core.TopicTest do describe "find/1" do test "when exist", %{course: course} do - topic = insert!(:topic, course_id: course.uuid) |> Repo.preload(:activities) + topic = + insert!(:topic, course_id: course.uuid) + |> Repo.preload(:course) + |> Repo.preload(:activities) assert Topic.find(topic.uuid) == topic end diff --git a/apps/web/lib/web/controllers/topics/topics_controller.ex b/apps/web/lib/web/controllers/topics/topics_controller.ex index a84dc31..10dfd32 100644 --- a/apps/web/lib/web/controllers/topics/topics_controller.ex +++ b/apps/web/lib/web/controllers/topics/topics_controller.ex @@ -36,7 +36,7 @@ defmodule Web.Topics.TopicsController do end def delete(conn, _params) do - topic = conn.assigns.topic + topic = conn.assigns.object case topic |> Topic.delete() do {:ok, topic} -> diff --git a/apps/web/lib/web/controllers/users/users_json.ex b/apps/web/lib/web/controllers/users/users_json.ex index 1568e7d..bbd0276 100644 --- a/apps/web/lib/web/controllers/users/users_json.ex +++ b/apps/web/lib/web/controllers/users/users_json.ex @@ -25,7 +25,9 @@ defmodule Web.Users.UsersJSON do %{ id: user.uuid, email: user.email, - full_name: user.full_name + role: user.role, + full_name: user.full_name, + inserted_at: user.inserted_at |> to_string() } end end diff --git a/apps/web/mix.exs b/apps/web/mix.exs index ca15316..9d3131d 100644 --- a/apps/web/mix.exs +++ b/apps/web/mix.exs @@ -16,7 +16,7 @@ defmodule Web.MixProject do deps: deps(), test_coverage: [ summary: [ - threshold: 70 + threshold: 80 ] ] ] diff --git a/apps/web/test/web/controllers/topics_controller_test.exs b/apps/web/test/web/controllers/topics_controller_test.exs index 05e5902..1cb8103 100644 --- a/apps/web/test/web/controllers/topics_controller_test.exs +++ b/apps/web/test/web/controllers/topics_controller_test.exs @@ -6,6 +6,8 @@ defmodule Web.TopicsControllerTest do import Web.Auth.Guardian import Core.Factory + alias GoEscuelaLms.Core.Schema.Topic + setup do course = insert!(:course) student = insert!(:user, role: :student) @@ -60,11 +62,11 @@ defmodule Web.TopicsControllerTest do {:ok, token, _} = encode_and_sign(instructor, %{}, token_type: :access) conn = - session_conn() - |> put_session(:user_id, instructor.uuid) - |> put_req_header("accept", "application/json") - |> put_req_header("authorization", "Bearer " <> token) - |> post(~p"/api/courses/#{course.uuid}/topics", %{name: nil}) + session_conn() + |> put_session(:user_id, instructor.uuid) + |> put_req_header("accept", "application/json") + |> put_req_header("authorization", "Bearer " <> token) + |> post(~p"/api/courses/#{course.uuid}/topics", %{name: nil}) assert json_response(conn, 422)["errors"] == %{"detail" => %{"name" => ["is required"]}} end @@ -76,11 +78,11 @@ defmodule Web.TopicsControllerTest do name = Faker.Lorem.word() conn = - session_conn() - |> put_session(:user_id, instructor.uuid) - |> put_req_header("accept", "application/json") - |> put_req_header("authorization", "Bearer " <> token) - |> post(~p"/api/courses/#{course.uuid}/topics", %{name: name}) + session_conn() + |> put_session(:user_id, instructor.uuid) + |> put_req_header("accept", "application/json") + |> put_req_header("authorization", "Bearer " <> token) + |> post(~p"/api/courses/#{course.uuid}/topics", %{name: name}) response = json_response(conn, 200)["data"] @@ -121,6 +123,7 @@ defmodule Web.TopicsControllerTest do test "invalid enrollment", %{instructor: instructor, course: course} do topic = insert!(:topic, course_id: course.uuid) {:ok, token, _} = encode_and_sign(instructor, %{}, token_type: :access) + conn = session_conn() |> put_session(:user_id, instructor.uuid) @@ -137,11 +140,11 @@ defmodule Web.TopicsControllerTest do {:ok, token, _} = encode_and_sign(instructor, %{}, token_type: :access) conn = - session_conn() - |> put_session(:user_id, instructor.uuid) - |> put_req_header("accept", "application/json") - |> put_req_header("authorization", "Bearer " <> token) - |> put(~p"/api/topics/#{topic.uuid}", %{name: nil}) + session_conn() + |> put_session(:user_id, instructor.uuid) + |> put_req_header("accept", "application/json") + |> put_req_header("authorization", "Bearer " <> token) + |> put(~p"/api/topics/#{topic.uuid}", %{name: nil}) assert json_response(conn, 422)["errors"] == %{"detail" => %{"name" => ["is required"]}} end @@ -154,11 +157,11 @@ defmodule Web.TopicsControllerTest do name = Faker.Lorem.word() conn = - session_conn() - |> put_session(:user_id, instructor.uuid) - |> put_req_header("accept", "application/json") - |> put_req_header("authorization", "Bearer " <> token) - |> put(~p"/api/topics/#{topic.uuid}", %{name: name}) + session_conn() + |> put_session(:user_id, instructor.uuid) + |> put_req_header("accept", "application/json") + |> put_req_header("authorization", "Bearer " <> token) + |> put(~p"/api/topics/#{topic.uuid}", %{name: name}) response = json_response(conn, 200)["data"] @@ -167,9 +170,63 @@ defmodule Web.TopicsControllerTest do end end - # describe "delete/2" do - # test "unauthorized", %{user: user} do + describe "delete/2" do + test "unauthorized", %{student: student, course: course} do + topic = insert!(:topic, course_id: course.uuid) + + {:ok, token, _} = encode_and_sign(student, %{}, token_type: :access) + + conn = + session_conn() + |> put_session(:user_id, student.uuid) + |> put_req_header("accept", "application/json") + |> put_req_header("authorization", "Bearer " <> token) + |> delete(~p"/api/topics/#{topic.uuid}", %{}) + + assert json_response(conn, 403)["errors"] == %{"detail" => "Forbidden resource"} + end + + test "invalid topic", %{organizer: organizer} do + {:ok, token, _} = encode_and_sign(organizer, %{}, token_type: :access) + + conn = + session_conn() + |> put_session(:user_id, organizer.uuid) + |> put_req_header("accept", "application/json") + |> put_req_header("authorization", "Bearer " <> token) + |> delete(~p"/api/topics/#{Faker.UUID.v4()}", %{}) + + assert json_response(conn, 422)["errors"] == %{"detail" => "topic is invalid"} + end + + test "invalid enrollment", %{instructor: instructor, course: course} do + topic = insert!(:topic, course_id: course.uuid) + {:ok, token, _} = encode_and_sign(instructor, %{}, token_type: :access) + + conn = + session_conn() + |> put_session(:user_id, instructor.uuid) + |> put_req_header("accept", "application/json") + |> put_req_header("authorization", "Bearer " <> token) + |> delete(~p"/api/topics/#{topic.uuid}", %{}) + + assert json_response(conn, 403)["errors"] == %{"detail" => "Forbidden resource"} + end + + test "valid delete", %{instructor: instructor, course: course} do + topic = insert!(:topic, course_id: course.uuid) + insert!(:enrollment, course_id: course.uuid, user_id: instructor.uuid) + {:ok, token, _} = encode_and_sign(instructor, %{}, token_type: :access) - # end - # end + conn = + session_conn() + |> put_session(:user_id, instructor.uuid) + |> put_req_header("accept", "application/json") + |> put_req_header("authorization", "Bearer " <> token) + |> delete(~p"/api/topics/#{topic.uuid}") + + assert json_response(conn, 200) + assert Topic.find(topic.uuid) == nil + end + end end diff --git a/apps/web/test/web/controllers/users_controller_test.exs b/apps/web/test/web/controllers/users_controller_test.exs new file mode 100644 index 0000000..7c64bdb --- /dev/null +++ b/apps/web/test/web/controllers/users_controller_test.exs @@ -0,0 +1,134 @@ +defmodule Web.UsersControllerTest do + use ExUnit.Case + use Core.DataCase + use Web.ConnCase + + import Web.Auth.Guardian + import Core.Factory + + setup do + instructor = insert!(:user, role: :instructor) + organizer = insert!(:user, role: :organizer) + + {:ok, instructor: instructor, organizer: organizer} + end + + describe "create/2" do + test "unauthorized", %{instructor: instructor} do + {:ok, token, _} = encode_and_sign(instructor, %{}, token_type: :access) + + conn = + session_conn() + |> put_session(:user_id, instructor.uuid) + |> put_req_header("accept", "application/json") + |> put_req_header("authorization", "Bearer " <> token) + |> post(~p"/api/users", %{}) + + assert json_response(conn, 403)["errors"] == %{"detail" => "Forbidden resource"} + end + + test "invalid params", %{organizer: organizer} do + {:ok, token, _} = encode_and_sign(organizer, %{}, token_type: :access) + + conn = + session_conn() + |> put_session(:user_id, organizer.uuid) + |> put_req_header("accept", "application/json") + |> put_req_header("authorization", "Bearer " <> token) + |> post(~p"/api/users", %{}) + + assert json_response(conn, 422)["errors"] == %{ + "detail" => %{ + "email" => ["is required"], + "full_name" => ["is required"], + "password" => ["is required"], + "role" => ["is required"] + } + } + end + + test "valid params", %{organizer: organizer} do + {:ok, token, _} = encode_and_sign(organizer, %{}, token_type: :access) + + user = + build(:user) + |> Map.from_struct() + |> Map.merge(%{role: "student", password: Faker.String.base64(100)}) + + conn = + session_conn() + |> put_session(:user_id, organizer.uuid) + |> put_req_header("accept", "application/json") + |> put_req_header("authorization", "Bearer " <> token) + |> post(~p"/api/users", user) + + response = json_response(conn, 200)["data"] + + assert response["full_name"] == user.full_name + assert response["email"] == user.email + assert response["role"] == user.role + end + end + + describe "index/2" do + test "unauthorized", %{instructor: instructor} do + {:ok, token, _} = encode_and_sign(instructor, %{}, token_type: :access) + + conn = + session_conn() + |> put_session(:user_id, instructor.uuid) + |> put_req_header("accept", "application/json") + |> put_req_header("authorization", "Bearer " <> token) + |> get(~p"/api/users", %{}) + + assert json_response(conn, 403)["errors"] == %{"detail" => "Forbidden resource"} + end + + test "get all users", %{instructor: instructor, organizer: organizer} do + student = insert!(:user, role: :student) + + {:ok, token, _} = encode_and_sign(organizer, %{}, token_type: :access) + + user = + build(:user) + |> Map.from_struct() + |> Map.merge(%{role: "student", password: Faker.String.base64(100)}) + + conn = + session_conn() + |> put_session(:user_id, organizer.uuid) + |> put_req_header("accept", "application/json") + |> put_req_header("authorization", "Bearer " <> token) + |> get(~p"/api/users") + + response = json_response(conn, 200)["data"] + + assert response == [ + %{ + "id" => instructor.uuid, + "full_name" => instructor.full_name, + "email" => instructor.email, + "role" => instructor.role |> to_string(), + "inserted_at" => instructor.inserted_at |> to_string() + }, + %{ + "id" => organizer.uuid, + "full_name" => organizer.full_name, + "email" => organizer.email, + "role" => organizer.role |> to_string(), + "inserted_at" => organizer.inserted_at |> to_string() + }, + %{ + "id" => student.uuid, + "full_name" => student.full_name, + "email" => student.email, + "role" => student.role |> to_string(), + "inserted_at" => student.inserted_at |> to_string() + } + ] + end + end + + # describe "update/2" do + # end +end