From 79092a8f356e5fc9866c758edb1209f38f15c2cd Mon Sep 17 00:00:00 2001 From: ShenyiCui Date: Tue, 8 Feb 2022 22:01:04 +0800 Subject: [PATCH 01/25] Add TestApi --- config/dev.exs | 2 +- lib/cadet_web/admin_views/admin_goals_view.ex | 4 ++++ lib/cadet_web/controllers/incentives_controller.ex | 7 +++++++ lib/cadet_web/router.ex | 1 + lib/cadet_web/views/incentives_view.ex | 6 ++++++ 5 files changed, 19 insertions(+), 1 deletion(-) diff --git a/config/dev.exs b/config/dev.exs index 43360b906..aff99e085 100644 --- a/config/dev.exs +++ b/config/dev.exs @@ -52,7 +52,7 @@ config :phoenix, :stacktrace_depth, 20 # Configure your database config :cadet, Cadet.Repo, username: "postgres", - password: "postgres", + password: "root", database: "cadet_dev", hostname: "localhost", pool_size: 10 diff --git a/lib/cadet_web/admin_views/admin_goals_view.ex b/lib/cadet_web/admin_views/admin_goals_view.ex index d41c060e8..7ddcd1157 100644 --- a/lib/cadet_web/admin_views/admin_goals_view.ex +++ b/lib/cadet_web/admin_views/admin_goals_view.ex @@ -10,6 +10,10 @@ defmodule CadetWeb.AdminGoalsView do render_many(goals, CadetWeb.AdminGoalsView, "goal_with_progress.json", as: :goal) end + def render("totalxp.json", %{data: data}) do + %{data: data} + end + def render("goal.json", %{goal: goal}) do transform_map_for_view(goal, %{ uuid: :uuid, diff --git a/lib/cadet_web/controllers/incentives_controller.ex b/lib/cadet_web/controllers/incentives_controller.ex index 2787f8c26..23a419419 100644 --- a/lib/cadet_web/controllers/incentives_controller.ex +++ b/lib/cadet_web/controllers/incentives_controller.ex @@ -16,6 +16,11 @@ defmodule CadetWeb.IncentivesController do ) end + def calculate_totalxp(conn, _) do + # query database + render(conn, "item.json", item: "hello") + end + def update_progress(conn, %{"uuid" => uuid, "progress" => progress}) do course_reg_id = conn.assigns.course_reg.id @@ -25,6 +30,8 @@ defmodule CadetWeb.IncentivesController do |> handle_standard_result(conn) end + + defp json_to_progress(json, uuid, course_reg_id) do json = json diff --git a/lib/cadet_web/router.ex b/lib/cadet_web/router.ex index 2b28492d0..6ffcebe79 100644 --- a/lib/cadet_web/router.ex +++ b/lib/cadet_web/router.ex @@ -79,6 +79,7 @@ defmodule CadetWeb.Router do post("/assessments/question/:questionid/answer", AnswerController, :submit) get("/achievements", IncentivesController, :index_achievements) + get("/achievements/totalxp", IncentivesController, :calculate_totalxp) get("/stories", StoriesController, :index) diff --git a/lib/cadet_web/views/incentives_view.ex b/lib/cadet_web/views/incentives_view.ex index c72e747ea..e038c2de4 100644 --- a/lib/cadet_web/views/incentives_view.ex +++ b/lib/cadet_web/views/incentives_view.ex @@ -33,6 +33,12 @@ defmodule CadetWeb.IncentivesView do render_many(goals, CadetWeb.IncentivesView, "goal_with_progress.json", as: :goal) end + def render("item.json", %{message: message}) do + %{ + message: message, + } + end + def render("goal_with_progress.json", %{goal: goal}) do transform_map_for_view(goal, %{ uuid: :uuid, From 82b2e69b2754cf37d74a22cb0ca652eb8bb1d2a9 Mon Sep 17 00:00:00 2001 From: ShenyiCui Date: Wed, 9 Feb 2022 15:57:52 +0800 Subject: [PATCH 02/25] Update totalXp GetRequest --- lib/cadet_web/controllers/incentives_controller.ex | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/cadet_web/controllers/incentives_controller.ex b/lib/cadet_web/controllers/incentives_controller.ex index 23a419419..421aacc6f 100644 --- a/lib/cadet_web/controllers/incentives_controller.ex +++ b/lib/cadet_web/controllers/incentives_controller.ex @@ -17,10 +17,10 @@ defmodule CadetWeb.IncentivesController do end def calculate_totalxp(conn, _) do - # query database - render(conn, "item.json", item: "hello") + json(conn, %{data: "message"}) end + @spec update_progress(Plug.Conn.t(), map) :: Plug.Conn.t() def update_progress(conn, %{"uuid" => uuid, "progress" => progress}) do course_reg_id = conn.assigns.course_reg.id From d5b083680de6efc4fde0343a098994a0cf9fe92d Mon Sep 17 00:00:00 2001 From: ShenyiCui Date: Tue, 22 Feb 2022 20:45:32 +0800 Subject: [PATCH 03/25] Add total xp logic --- lib/cadet/incentives/achievements.ex | 12 +++++++++++ .../controllers/incentives_controller.ex | 20 ++++++++++++++++++- 2 files changed, 31 insertions(+), 1 deletion(-) diff --git a/lib/cadet/incentives/achievements.ex b/lib/cadet/incentives/achievements.ex index 5fa93c0a4..4d71c4376 100644 --- a/lib/cadet/incentives/achievements.ex +++ b/lib/cadet/incentives/achievements.ex @@ -21,6 +21,18 @@ defmodule Cadet.Incentives.Achievements do |> Repo.all() end + @doc """ + Returns all achievements with goals and progress. + + This returns Achievement structs with prerequisites, goal association and progress maps pre-loaded. + """ + def get_goals_with_progress(course_id) when is_ecto_id(course_id) do + Achievement + |> where(course_id: ^course_id) + |> preload([:prerequisites, goals: [goal: :progress]]) + |> Repo.all() + end + @spec upsert(map()) :: {:ok, %Achievement{}} | {:error, {:bad_request, String.t()}} @doc """ Inserts a new achievement, or updates it if it already exists. diff --git a/lib/cadet_web/controllers/incentives_controller.ex b/lib/cadet_web/controllers/incentives_controller.ex index 421aacc6f..2d477ed65 100644 --- a/lib/cadet_web/controllers/incentives_controller.ex +++ b/lib/cadet_web/controllers/incentives_controller.ex @@ -10,6 +10,7 @@ defmodule CadetWeb.IncentivesController do render(conn, "index_achievements.json", achievements: Achievements.get(course_id)) end + @spec index_goals(Plug.Conn.t(), any) :: Plug.Conn.t() def index_goals(conn, _) do render(conn, "index_goals_with_progress.json", goals: Goals.get_with_progress(conn.assigns.course_reg) @@ -17,7 +18,24 @@ defmodule CadetWeb.IncentivesController do end def calculate_totalxp(conn, _) do - json(conn, %{data: "message"}) + course_id = conn.assigns.course_reg.course_id + achievements = Achievements.get_goals_with_progress(course_id) + + #IO.inspect Enum.at(goals, 0) + #IO.inspect Enum.at(achievements, 0) + total_xp = 0 + Enum.each(achievements, fn achivement_item -> + xp = achivement_item.xp + Enum.each(achivement_item.goals, fn goal_item -> + progress = Enum.at(goal_item.goal.progress, 0) + if (!progress.completed) do + IO.inspect "uncompleted" + xp = 0 + end + end) + total_xp = total_xp + xp + end) + json(conn, %{totalXp: total_xp}) end @spec update_progress(Plug.Conn.t(), map) :: Plug.Conn.t() From a835e67971b387eef164a931dda11c6442985465 Mon Sep 17 00:00:00 2001 From: Richard Qi <55354921+riccqi@users.noreply.github.com> Date: Wed, 23 Feb 2022 02:21:58 +0800 Subject: [PATCH 04/25] move totalxp logic into achievements.ex --- config/dev.exs | 4 +- lib/cadet/incentives/achievements.ex | 20 +++++-- .../controllers/incentives_controller.ex | 34 +++++------ mix.lock | 59 ++++++++++--------- 4 files changed, 64 insertions(+), 53 deletions(-) diff --git a/config/dev.exs b/config/dev.exs index aff99e085..1314c247f 100644 --- a/config/dev.exs +++ b/config/dev.exs @@ -51,8 +51,8 @@ config :phoenix, :stacktrace_depth, 20 # Configure your database config :cadet, Cadet.Repo, - username: "postgres", - password: "root", + username: "richardqi", + password: "", database: "cadet_dev", hostname: "localhost", pool_size: 10 diff --git a/lib/cadet/incentives/achievements.ex b/lib/cadet/incentives/achievements.ex index 4d71c4376..9eb1f0ee6 100644 --- a/lib/cadet/incentives/achievements.ex +++ b/lib/cadet/incentives/achievements.ex @@ -27,10 +27,22 @@ defmodule Cadet.Incentives.Achievements do This returns Achievement structs with prerequisites, goal association and progress maps pre-loaded. """ def get_goals_with_progress(course_id) when is_ecto_id(course_id) do - Achievement - |> where(course_id: ^course_id) - |> preload([:prerequisites, goals: [goal: :progress]]) - |> Repo.all() + achievements = + Achievement + |> where(course_id: ^course_id) + |> preload([:prerequisites, goals: [goal: :progress]]) + |> Repo.all() + + # IO.puts("---------------------------------------") + # IO.inspect(achievements) + + for achievement <- achievements, + goal <- achievement.goals, + Enum.at(goal.goal.progress, 0).completed, + reduce: 0 do + total -> + total + achievement.xp + end end @spec upsert(map()) :: {:ok, %Achievement{}} | {:error, {:bad_request, String.t()}} diff --git a/lib/cadet_web/controllers/incentives_controller.ex b/lib/cadet_web/controllers/incentives_controller.ex index 2d477ed65..569f40137 100644 --- a/lib/cadet_web/controllers/incentives_controller.ex +++ b/lib/cadet_web/controllers/incentives_controller.ex @@ -19,22 +19,22 @@ defmodule CadetWeb.IncentivesController do def calculate_totalxp(conn, _) do course_id = conn.assigns.course_reg.course_id - achievements = Achievements.get_goals_with_progress(course_id) - - #IO.inspect Enum.at(goals, 0) - #IO.inspect Enum.at(achievements, 0) - total_xp = 0 - Enum.each(achievements, fn achivement_item -> - xp = achivement_item.xp - Enum.each(achivement_item.goals, fn goal_item -> - progress = Enum.at(goal_item.goal.progress, 0) - if (!progress.completed) do - IO.inspect "uncompleted" - xp = 0 - end - end) - total_xp = total_xp + xp - end) + total_xp = Achievements.get_goals_with_progress(course_id) + IO.puts(total_xp) + # IO.inspect Enum.at(goals, 0) + # IO.inspect Enum.at(achievements, 0) + # total_xp = 0 + # Enum.each(achievements, fn achivement_item -> + # xp = achivement_item.xp + # Enum.each(achivement_item.goals, fn goal_item -> + # progress = Enum.at(goal_item.goal.progress, 0) + # if (!progress.completed) do + # IO.inspect "uncompleted" + # xp = 0 + # end + # end) + # total_xp = total_xp + xp + # end) json(conn, %{totalXp: total_xp}) end @@ -48,8 +48,6 @@ defmodule CadetWeb.IncentivesController do |> handle_standard_result(conn) end - - defp json_to_progress(json, uuid, course_reg_id) do json = json diff --git a/mix.lock b/mix.lock index 5ad6f0746..8fca438ee 100644 --- a/mix.lock +++ b/mix.lock @@ -5,78 +5,79 @@ "blankable": {:hex, :blankable, "1.0.0", "89ab564a63c55af117e115144e3b3b57eb53ad43ba0f15553357eb283e0ed425", [:mix], [], "hexpm", "7cf11aac0e44f4eedbee0c15c1d37d94c090cb72a8d9fddf9f7aec30f9278899"}, "bunt": {:hex, :bunt, "0.2.0", "951c6e801e8b1d2cbe58ebbd3e616a869061ddadcc4863d0a2182541acae9a38", [:mix], [], "hexpm", "7af5c7e09fe1d40f76c8e4f9dd2be7cebd83909f31fee7cd0e9eadc567da8353"}, "bypass": {:hex, :bypass, "2.1.0", "909782781bf8e20ee86a9cabde36b259d44af8b9f38756173e8f5e2e1fabb9b1", [:mix], [{:plug, "~> 1.7", [hex: :plug, repo: "hexpm", optional: false]}, {:plug_cowboy, "~> 2.0", [hex: :plug_cowboy, repo: "hexpm", optional: false]}, {:ranch, "~> 1.3", [hex: :ranch, repo: "hexpm", optional: false]}], "hexpm", "d9b5df8fa5b7a6efa08384e9bbecfe4ce61c77d28a4282f79e02f1ef78d96b80"}, - "certifi": {:hex, :certifi, "2.6.1", "dbab8e5e155a0763eea978c913ca280a6b544bfa115633fa20249c3d396d9493", [:rebar3], [], "hexpm", "524c97b4991b3849dd5c17a631223896272c6b0af446778ba4675a1dff53bb7e"}, + "certifi": {:hex, :certifi, "2.9.0", "6f2a475689dd47f19fb74334859d460a2dc4e3252a3324bd2111b8f0429e7e21", [:rebar3], [], "hexpm", "266da46bdb06d6c6d35fde799bcb28d36d985d424ad7c08b5bb48f5b5cdd4641"}, "combine": {:hex, :combine, "0.10.0", "eff8224eeb56498a2af13011d142c5e7997a80c8f5b97c499f84c841032e429f", [:mix], [], "hexpm", "1b1dbc1790073076580d0d1d64e42eae2366583e7aecd455d1215b0d16f2451b"}, "configparser_ex": {:hex, :configparser_ex, "4.0.0", "17e2b831cfa33a08c56effc610339b2986f0d82a9caa0ed18880a07658292ab6", [:mix], [], "hexpm", "02e6d1a559361a063cba7b75bc3eb2d6ad7e62730c551cc4703541fd11e65e5b"}, "connection": {:hex, :connection, "1.1.0", "ff2a49c4b75b6fb3e674bfc5536451607270aac754ffd1bdfe175abe4a6d7a68", [:mix], [], "hexpm", "722c1eb0a418fbe91ba7bd59a47e28008a189d47e37e0e7bb85585a016b2869c"}, "corsica": {:hex, :corsica, "1.1.3", "5f1de40bc9285753aa03afbdd10c364dac79b2ddbf2ba9c5c9c47b397ec06f40", [:mix], [{:plug, "~> 1.0", [hex: :plug, repo: "hexpm", optional: false]}], "hexpm", "8156b3a14a114a346262871333a931a1766b2597b56bf994fcfcb65443a348ad"}, "cowboy": {:hex, :cowboy, "2.9.0", "865dd8b6607e14cf03282e10e934023a1bd8be6f6bacf921a7e2a96d800cd452", [:make, :rebar3], [{:cowlib, "2.11.0", [hex: :cowlib, repo: "hexpm", optional: false]}, {:ranch, "1.8.0", [hex: :ranch, repo: "hexpm", optional: false]}], "hexpm", "2c729f934b4e1aa149aff882f57c6372c15399a20d54f65c8d67bef583021bde"}, - "cowboy_telemetry": {:hex, :cowboy_telemetry, "0.3.1", "ebd1a1d7aff97f27c66654e78ece187abdc646992714164380d8a041eda16754", [:rebar3], [{:cowboy, "~> 2.7", [hex: :cowboy, repo: "hexpm", optional: false]}, {:telemetry, "~> 0.4", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "3a6efd3366130eab84ca372cbd4a7d3c3a97bdfcfb4911233b035d117063f0af"}, + "cowboy_telemetry": {:hex, :cowboy_telemetry, "0.4.0", "f239f68b588efa7707abce16a84d0d2acf3a0f50571f8bb7f56a15865aae820c", [:rebar3], [{:cowboy, "~> 2.7", [hex: :cowboy, repo: "hexpm", optional: false]}, {:telemetry, "~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "7d98bac1ee4565d31b62d59f8823dfd8356a169e7fcbb83831b8a5397404c9de"}, "cowlib": {:hex, :cowlib, "2.11.0", "0b9ff9c346629256c42ebe1eeb769a83c6cb771a6ee5960bd110ab0b9b872063", [:make, :rebar3], [], "hexpm", "2b3e9da0b21c4565751a6d4901c20d1b4cc25cbb7fd50d91d2ab6dd287bc86a9"}, - "credo": {:hex, :credo, "1.5.6", "e04cc0fdc236fefbb578e0c04bd01a471081616e741d386909e527ac146016c6", [:mix], [{:bunt, "~> 0.2.0", [hex: :bunt, repo: "hexpm", optional: false]}, {:file_system, "~> 0.2.8", [hex: :file_system, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: false]}], "hexpm", "4b52a3e558bd64e30de62a648518a5ea2b6e3e5d2b164ef5296244753fc7eb17"}, - "crontab": {:hex, :crontab, "1.1.10", "dc9bb1f4299138d47bce38341f5dcbee0aa6c205e864fba7bc847f3b5cb48241", [:mix], [{:ecto, "~> 1.0 or ~> 2.0 or ~> 3.0", [hex: :ecto, repo: "hexpm", optional: true]}], "hexpm", "1347d889d1a0eda997990876b4894359e34bfbbd688acbb0ba28a2795ca40685"}, + "credo": {:hex, :credo, "1.6.3", "0a9f8925dbc8f940031b789f4623fc9a0eea99d3eed600fe831e403eb96c6a83", [:mix], [{:bunt, "~> 0.2.0", [hex: :bunt, repo: "hexpm", optional: false]}, {:file_system, "~> 0.2.8", [hex: :file_system, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: false]}], "hexpm", "1167cde00e6661d740fc54da2ee268e35d3982f027399b64d3e2e83af57a1180"}, + "crontab": {:hex, :crontab, "1.1.11", "4028ced51b813a5061f85b689d4391ef0c27550c8ab09aaf139e4295c3d93ea4", [:mix], [{:ecto, "~> 1.0 or ~> 2.0 or ~> 3.0", [hex: :ecto, repo: "hexpm", optional: true]}], "hexpm", "ecb045f9ac14a3e2990e54368f70cdb6e2f2abafc5bc329d6c31f0c74b653787"}, "csv": {:hex, :csv, "2.4.1", "50e32749953b6bf9818dbfed81cf1190e38cdf24f95891303108087486c5925e", [:mix], [{:parallel_stream, "~> 1.0.4", [hex: :parallel_stream, repo: "hexpm", optional: false]}], "hexpm", "54508938ac67e27966b10ef49606e3ad5995d665d7fc2688efb3eab1307c9079"}, - "db_connection": {:hex, :db_connection, "2.4.0", "d04b1b73795dae60cead94189f1b8a51cc9e1f911c234cc23074017c43c031e5", [:mix], [{:connection, "~> 1.0", [hex: :connection, repo: "hexpm", optional: false]}, {:telemetry, "~> 0.4 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "ad416c21ad9f61b3103d254a71b63696ecadb6a917b36f563921e0de00d7d7c8"}, + "db_connection": {:hex, :db_connection, "2.4.1", "6411f6e23f1a8b68a82fa3a36366d4881f21f47fc79a9efb8c615e62050219da", [:mix], [{:connection, "~> 1.0", [hex: :connection, repo: "hexpm", optional: false]}, {:telemetry, "~> 0.4 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "ea36d226ec5999781a9a8ad64e5d8c4454ecedc7a4d643e4832bf08efca01f00"}, "decimal": {:hex, :decimal, "2.0.0", "a78296e617b0f5dd4c6caf57c714431347912ffb1d0842e998e9792b5642d697", [:mix], [], "hexpm", "34666e9c55dea81013e77d9d87370fe6cb6291d1ef32f46a1600230b1d44f577"}, "dialyxir": {:hex, :dialyxir, "1.1.0", "c5aab0d6e71e5522e77beff7ba9e08f8e02bad90dfbeffae60eaf0cb47e29488", [:mix], [{:erlex, ">= 0.2.6", [hex: :erlex, repo: "hexpm", optional: false]}], "hexpm", "07ea8e49c45f15264ebe6d5b93799d4dd56a44036cf42d0ad9c960bc266c0b9a"}, "distillery": {:hex, :distillery, "2.1.1", "f9332afc2eec8a1a2b86f22429e068ef35f84a93ea1718265e740d90dd367814", [:mix], [{:artificery, "~> 0.2", [hex: :artificery, repo: "hexpm", optional: false]}], "hexpm", "bbc7008b0161a6f130d8d903b5b3232351fccc9c31a991f8fcbf2a12ace22995"}, - "ecto": {:hex, :ecto, "3.6.2", "efdf52acfc4ce29249bab5417415bd50abd62db7b0603b8bab0d7b996548c2bc", [:mix], [{:decimal, "~> 1.6 or ~> 2.0", [hex: :decimal, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}, {:telemetry, "~> 0.4", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "efad6dfb04e6f986b8a3047822b0f826d9affe8e4ebdd2aeedbfcb14fd48884e"}, + "ecto": {:hex, :ecto, "3.7.1", "a20598862351b29f80f285b21ec5297da1181c0442687f9b8329f0445d228892", [:mix], [{:decimal, "~> 1.6 or ~> 2.0", [hex: :decimal, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}, {:telemetry, "~> 0.4 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "d36e5b39fc479e654cffd4dbe1865d9716e4a9b6311faff799b6f90ab81b8638"}, "ecto_enum": {:hex, :ecto_enum, "1.4.0", "d14b00e04b974afc69c251632d1e49594d899067ee2b376277efd8233027aec8", [:mix], [{:ecto, ">= 3.0.0", [hex: :ecto, repo: "hexpm", optional: false]}, {:ecto_sql, "> 3.0.0", [hex: :ecto_sql, repo: "hexpm", optional: false]}, {:mariaex, ">= 0.0.0", [hex: :mariaex, repo: "hexpm", optional: true]}, {:postgrex, ">= 0.0.0", [hex: :postgrex, repo: "hexpm", optional: true]}], "hexpm", "8fb55c087181c2b15eee406519dc22578fa60dd82c088be376d0010172764ee4"}, - "ecto_sql": {:hex, :ecto_sql, "3.6.2", "9526b5f691701a5181427634c30655ac33d11e17e4069eff3ae1176c764e0ba3", [:mix], [{:db_connection, "~> 2.2", [hex: :db_connection, repo: "hexpm", optional: false]}, {:ecto, "~> 3.6.2", [hex: :ecto, repo: "hexpm", optional: false]}, {:myxql, "~> 0.4.0 or ~> 0.5.0", [hex: :myxql, repo: "hexpm", optional: true]}, {:postgrex, "~> 0.15.0 or ~> 1.0", [hex: :postgrex, repo: "hexpm", optional: true]}, {:tds, "~> 2.1.1", [hex: :tds, repo: "hexpm", optional: true]}, {:telemetry, "~> 0.4.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "5ec9d7e6f742ea39b63aceaea9ac1d1773d574ea40df5a53ef8afbd9242fdb6b"}, + "ecto_sql": {:hex, :ecto_sql, "3.7.2", "55c60aa3a06168912abf145c6df38b0295c34118c3624cf7a6977cd6ce043081", [:mix], [{:db_connection, "~> 2.2", [hex: :db_connection, repo: "hexpm", optional: false]}, {:ecto, "~> 3.7.0", [hex: :ecto, repo: "hexpm", optional: false]}, {:myxql, "~> 0.4.0 or ~> 0.5.0 or ~> 0.6.0", [hex: :myxql, repo: "hexpm", optional: true]}, {:postgrex, "~> 0.15.0 or ~> 0.16.0 or ~> 1.0", [hex: :postgrex, repo: "hexpm", optional: true]}, {:tds, "~> 2.1.1 or ~> 2.2", [hex: :tds, repo: "hexpm", optional: true]}, {:telemetry, "~> 0.4.0 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "3c218ea62f305dcaef0b915fb56583195e7b91c91dcfb006ba1f669bfacbff2a"}, "erlex": {:hex, :erlex, "0.2.6", "c7987d15e899c7a2f34f5420d2a2ea0d659682c06ac607572df55a43753aa12e", [:mix], [], "hexpm", "2ed2e25711feb44d52b17d2780eabf998452f6efda104877a3881c2f8c0c0c75"}, - "ex_aws": {:hex, :ex_aws, "2.2.3", "f9bb1b04aaed3270f08c99d0268ff2c6596edb3a4a8792d18ffd37a74dd4810d", [:mix], [{:configparser_ex, "~> 4.0", [hex: :configparser_ex, repo: "hexpm", optional: true]}, {:hackney, "~> 1.16", [hex: :hackney, repo: "hexpm", optional: true]}, {:jason, "~> 1.1", [hex: :jason, repo: "hexpm", optional: true]}, {:jsx, "~> 3.0", [hex: :jsx, repo: "hexpm", optional: true]}, {:sweet_xml, "~> 0.6", [hex: :sweet_xml, repo: "hexpm", optional: true]}, {:telemetry, "~> 0.4", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "8ddf1da94624e5f92afe36d4146086f72d85bb15998cec137c1fd854a3f04bc4"}, + "ex_aws": {:hex, :ex_aws, "2.2.10", "064139724335b00b6665af7277189afc9ed507791b1ccf2698dadc7c8ad892e8", [:mix], [{:configparser_ex, "~> 4.0", [hex: :configparser_ex, repo: "hexpm", optional: true]}, {:hackney, "~> 1.16", [hex: :hackney, repo: "hexpm", optional: true]}, {:jason, "~> 1.1", [hex: :jason, repo: "hexpm", optional: true]}, {:jsx, "~> 2.8 or ~> 3.0", [hex: :jsx, repo: "hexpm", optional: true]}, {:mime, "~> 1.2 or ~> 2.0", [hex: :mime, repo: "hexpm", optional: false]}, {:sweet_xml, "~> 0.7", [hex: :sweet_xml, repo: "hexpm", optional: true]}, {:telemetry, "~> 0.4.3 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "98acb63f74b2f0822be219c5c2f0e8d243c2390f5325ad0557b014d3360da47e"}, "ex_aws_lambda": {:hex, :ex_aws_lambda, "2.0.2", "77c749e4c4c36fb607639519a2e6b2037ec5986be52add632c1f5f5b9932089b", [:mix], [{:ex_aws, "~> 2.0", [hex: :ex_aws, repo: "hexpm", optional: false]}], "hexpm", "4e47a9b0bdd3ec993f812e6ef87ad8d1a652e4ffadb8d7c2632e90bd4a4d1fe2"}, - "ex_aws_s3": {:hex, :ex_aws_s3, "2.3.0", "5dfe50116bad048240bae7cd9418bfe23296542ff72a01b9138113a1cd31451c", [:mix], [{:ex_aws, "~> 2.0", [hex: :ex_aws, repo: "hexpm", optional: false]}, {:sweet_xml, ">= 0.0.0", [hex: :sweet_xml, repo: "hexpm", optional: true]}], "hexpm", "0b13b11478825d62d2f6e57ae763695331be06f2216468f31bb304316758b096"}, + "ex_aws_s3": {:hex, :ex_aws_s3, "2.3.2", "92a63b72d763b488510626d528775b26831f5c82b066a63a3128054b7a09de28", [:mix], [{:ex_aws, "~> 2.0", [hex: :ex_aws, repo: "hexpm", optional: false]}, {:sweet_xml, ">= 0.0.0", [hex: :sweet_xml, repo: "hexpm", optional: true]}], "hexpm", "b235b27131409bcc293c343bf39f1fbdd32892aa237b3f13752e914dc2979960"}, "ex_aws_secretsmanager": {:hex, :ex_aws_secretsmanager, "2.0.0", "deff8c12335f0160882afeb9687e55a97fddcd7d9a82fc3a6fbb270797374773", [:mix], [{:ex_aws, "~> 2.0", [hex: :ex_aws, repo: "hexpm", optional: false]}], "hexpm", "8b2838af536c32263ff797012b29e87bad73ef34f43cfa60ebca8e84576f6d45"}, "ex_aws_sts": {:hex, :ex_aws_sts, "2.3.0", "ce48c4cba7f1595a7d544458d0202ca313124026dba7b1a0021bbb1baa3d66d0", [:mix], [{:ex_aws, "~> 2.2", [hex: :ex_aws, repo: "hexpm", optional: false]}], "hexpm", "f14e4c7da3454514bf253b331e9422d25825485c211896ab3b81d2a4bdbf62f5"}, "ex_json_schema": {:hex, :ex_json_schema, "0.7.4", "09eb5b0c8184e5702bc89625a9d0c05c7a0a845d382e9f6f406a0fc1c9a8cc3f", [:mix], [], "hexpm", "45c67fa840f0d719a2b5578126dc29bcdc1f92499c0f61bcb8a3bcb5935f9684"}, "ex_machina": {:hex, :ex_machina, "2.7.0", "b792cc3127fd0680fecdb6299235b4727a4944a09ff0fa904cc639272cd92dc7", [:mix], [{:ecto, "~> 2.2 or ~> 3.0", [hex: :ecto, repo: "hexpm", optional: true]}, {:ecto_sql, "~> 3.0", [hex: :ecto_sql, repo: "hexpm", optional: true]}], "hexpm", "419aa7a39bde11894c87a615c4ecaa52d8f107bbdd81d810465186f783245bf8"}, "ex_utils": {:hex, :ex_utils, "0.1.7", "2c133e0bcdc49a858cf8dacf893308ebc05bc5fba501dc3d2935e65365ec0bf3", [:mix], [], "hexpm", "66d4fe75285948f2d1e69c2a5ddd651c398c813574f8d36a9eef11dc20356ef6"}, "exactor": {:hex, :exactor, "2.2.4", "5efb4ddeb2c48d9a1d7c9b465a6fffdd82300eb9618ece5d34c3334d5d7245b1", [:mix], [], "hexpm", "1222419f706e01bfa1095aec9acf6421367dcfab798a6f67c54cf784733cd6b5"}, - "excoveralls": {:hex, :excoveralls, "0.14.2", "f9f5fd0004d7bbeaa28ea9606251bb643c313c3d60710bad1f5809c845b748f0", [:mix], [{:hackney, "~> 1.16", [hex: :hackney, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: false]}], "hexpm", "ca6fd358621cb4d29311b29d4732c4d47dac70e622850979bc54ed9a3e50f3e1"}, + "excoveralls": {:hex, :excoveralls, "0.14.4", "295498f1ae47bdc6dce59af9a585c381e1aefc63298d48172efaaa90c3d251db", [:mix], [{:hackney, "~> 1.16", [hex: :hackney, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: false]}], "hexpm", "e3ab02f2df4c1c7a519728a6f0a747e71d7d6e846020aae338173619217931c1"}, "exjsx": {:hex, :exjsx, "4.0.0", "60548841e0212df401e38e63c0078ec57b33e7ea49b032c796ccad8cde794b5c", [:mix], [{:jsx, "~> 2.8.0", [hex: :jsx, repo: "hexpm", optional: false]}], "hexpm", "32e95820a97cffea67830e91514a2ad53b888850442d6d395f53a1ac60c82e07"}, - "exvcr": {:hex, :exvcr, "0.13.2", "e17fd3ee3a341f41a3aa65a3ce73a339759a9d0658f83782492c6e9b6cf9daa4", [:mix], [{:exactor, "~> 2.2", [hex: :exactor, repo: "hexpm", optional: false]}, {:exjsx, "~> 4.0", [hex: :exjsx, repo: "hexpm", optional: false]}, {:finch, "~> 0.8.0", [hex: :finch, repo: "hexpm", optional: true]}, {:httpoison, "~> 1.0", [hex: :httpoison, repo: "hexpm", optional: true]}, {:httpotion, "~> 3.1", [hex: :httpotion, repo: "hexpm", optional: true]}, {:ibrowse, "4.4.0", [hex: :ibrowse, repo: "hexpm", optional: true]}, {:meck, "~> 0.8", [hex: :meck, repo: "hexpm", optional: false]}], "hexpm", "17f41a533d14f582fe6b5f83214f058cf5ba77c6a7bc15bc53a9ea1827d92d96"}, - "faker": {:hex, :faker, "0.16.0", "1e2cf3e8d60d44a30741fb98118fcac18b2020379c7e00d18f1a005841b2f647", [:mix], [], "hexpm", "fbcb9bf1299dff3c9dd7e50f41802bbc472ffbb84e7656394c8aa913ec315141"}, + "exvcr": {:hex, :exvcr, "0.13.3", "fcd5f54ea0ebd41db7fe16701f3c67871d1b51c3c104ab88f11135a173d47134", [:mix], [{:exactor, "~> 2.2", [hex: :exactor, repo: "hexpm", optional: false]}, {:exjsx, "~> 4.0", [hex: :exjsx, repo: "hexpm", optional: false]}, {:finch, "~> 0.8", [hex: :finch, repo: "hexpm", optional: true]}, {:httpoison, "~> 1.0", [hex: :httpoison, repo: "hexpm", optional: true]}, {:httpotion, "~> 3.1", [hex: :httpotion, repo: "hexpm", optional: true]}, {:ibrowse, "4.4.0", [hex: :ibrowse, repo: "hexpm", optional: true]}, {:meck, "~> 0.8", [hex: :meck, repo: "hexpm", optional: false]}], "hexpm", "db61057447388b7adc4443a55047d11d09acc75eeb5548507c775a8402e02689"}, + "faker": {:hex, :faker, "0.17.0", "671019d0652f63aefd8723b72167ecdb284baf7d47ad3a82a15e9b8a6df5d1fa", [:mix], [], "hexpm", "a7d4ad84a93fd25c5f5303510753789fc2433ff241bf3b4144d3f6f291658a6a"}, "file_system": {:hex, :file_system, "0.2.10", "fb082005a9cd1711c05b5248710f8826b02d7d1784e7c3451f9c1231d4fc162d", [:mix], [], "hexpm", "41195edbfb562a593726eda3b3e8b103a309b733ad25f3d642ba49696bf715dc"}, - "gen_stage": {:hex, :gen_stage, "1.1.0", "dd0c0f8d2f3b993fdbd3d58e94abbe65380f4e78bdee3fa93d5618d7d14abe60", [:mix], [], "hexpm", "7f2b36a6d02f7ef2ba410733b540ec423af65ec9c99f3d1083da508aca3b9305"}, - "gettext": {:hex, :gettext, "0.18.2", "7df3ea191bb56c0309c00a783334b288d08a879f53a7014341284635850a6e55", [:mix], [], "hexpm", "f9f537b13d4fdd30f3039d33cb80144c3aa1f8d9698e47d7bcbcc8df93b1f5c5"}, - "git_hooks": {:hex, :git_hooks, "0.6.3", "320aa54e9eeae6f04ceef79f33e426af5ab9618ac160d87b6467afba9ab07eee", [:mix], [{:blankable, "~> 1.0.0", [hex: :blankable, repo: "hexpm", optional: false]}, {:recase, "~> 0.7.0", [hex: :recase, repo: "hexpm", optional: false]}], "hexpm", "573a3e31579853cb898ca7e60524b7b8c0f2aeb7b7af4a906641fd60b1491051"}, - "guardian": {:hex, :guardian, "2.2.0", "0b730e957923ec79547fb8311f1092d2464cb187aebbf1d51f7a3f4dad545583", [:mix], [{:jose, "~> 1.8", [hex: :jose, repo: "hexpm", optional: false]}, {:plug, "~> 1.3.3 or ~> 1.4", [hex: :plug, repo: "hexpm", optional: true]}], "hexpm", "6e3fad1520ece1210372ed9e51bde246cf299b1caf1654663a436ede13d0d822"}, + "gen_stage": {:hex, :gen_stage, "1.1.2", "b1656cd4ba431ed02c5656fe10cb5423820847113a07218da68eae5d6a260c23", [:mix], [], "hexpm", "9e39af23140f704e2b07a3e29d8f05fd21c2aaf4088ff43cb82be4b9e3148d02"}, + "gettext": {:hex, :gettext, "0.19.1", "564953fd21f29358e68b91634799d9d26989f8d039d7512622efb3c3b1c97892", [:mix], [], "hexpm", "10c656c0912b8299adba9b061c06947511e3f109ab0d18b44a866a4498e77222"}, + "git_hooks": {:hex, :git_hooks, "0.7.1", "58ae0e5a0d1443fe7e6ce36ca6b44b2b36bd680bc3d3568321ca057d2eaf9f3c", [:mix], [{:blankable, "~> 1.0.0", [hex: :blankable, repo: "hexpm", optional: false]}, {:recase, "~> 0.7.0", [hex: :recase, repo: "hexpm", optional: false]}], "hexpm", "b06f0166ccd0a4ac56126df294b853aba138400d4b947cc03198481fa49780fe"}, + "guardian": {:hex, :guardian, "2.2.1", "5a4a949fd46eac79ef37f074ada7d1ef82e274bc99e335c286e042f5383f4f80", [:mix], [{:jose, "~> 1.8", [hex: :jose, repo: "hexpm", optional: false]}, {:plug, "~> 1.3.3 or ~> 1.4", [hex: :plug, repo: "hexpm", optional: true]}], "hexpm", "09b5c4d08f18524bd33ffe49617003cbca9f617237e23b5f42223cda61c5f052"}, "guardian_db": {:hex, :guardian_db, "2.1.0", "ec95a9d99cdd1e550555d09a7bb4a340d8887aad0697f594590c2fd74be02426", [:mix], [{:ecto, "~> 3.0", [hex: :ecto, repo: "hexpm", optional: false]}, {:ecto_sql, "~> 3.1", [hex: :ecto_sql, repo: "hexpm", optional: false]}, {:guardian, "~> 1.0 or ~> 2.0", [hex: :guardian, repo: "hexpm", optional: false]}, {:postgrex, "~> 0.13", [hex: :postgrex, repo: "hexpm", optional: true]}], "hexpm", "f8e7d543ac92c395f3a7fd5acbe6829faeade57d688f7562e2f0fca8f94a0d70"}, - "hackney": {:hex, :hackney, "1.17.4", "99da4674592504d3fb0cfef0db84c3ba02b4508bae2dff8c0108baa0d6e0977c", [:rebar3], [{:certifi, "~>2.6.1", [hex: :certifi, repo: "hexpm", optional: false]}, {:idna, "~>6.1.0", [hex: :idna, repo: "hexpm", optional: false]}, {:metrics, "~>1.0.0", [hex: :metrics, repo: "hexpm", optional: false]}, {:mimerl, "~>1.1", [hex: :mimerl, repo: "hexpm", optional: false]}, {:parse_trans, "3.3.1", [hex: :parse_trans, repo: "hexpm", optional: false]}, {:ssl_verify_fun, "~>1.1.0", [hex: :ssl_verify_fun, repo: "hexpm", optional: false]}, {:unicode_util_compat, "~>0.7.0", [hex: :unicode_util_compat, repo: "hexpm", optional: false]}], "hexpm", "de16ff4996556c8548d512f4dbe22dd58a587bf3332e7fd362430a7ef3986b16"}, + "hackney": {:hex, :hackney, "1.18.1", "f48bf88f521f2a229fc7bae88cf4f85adc9cd9bcf23b5dc8eb6a1788c662c4f6", [:rebar3], [{:certifi, "~>2.9.0", [hex: :certifi, repo: "hexpm", optional: false]}, {:idna, "~>6.1.0", [hex: :idna, repo: "hexpm", optional: false]}, {:metrics, "~>1.0.0", [hex: :metrics, repo: "hexpm", optional: false]}, {:mimerl, "~>1.1", [hex: :mimerl, repo: "hexpm", optional: false]}, {:parse_trans, "3.3.1", [hex: :parse_trans, repo: "hexpm", optional: false]}, {:ssl_verify_fun, "~>1.1.0", [hex: :ssl_verify_fun, repo: "hexpm", optional: false]}, {:unicode_util_compat, "~>0.7.0", [hex: :unicode_util_compat, repo: "hexpm", optional: false]}], "hexpm", "a4ecdaff44297e9b5894ae499e9a070ea1888c84afdd1fd9b7b2bc384950128e"}, "httpoison": {:hex, :httpoison, "1.8.0", "6b85dea15820b7804ef607ff78406ab449dd78bed923a49c7160e1886e987a3d", [:mix], [{:hackney, "~> 1.17", [hex: :hackney, repo: "hexpm", optional: false]}], "hexpm", "28089eaa98cf90c66265b6b5ad87c59a3729bea2e74e9d08f9b51eb9729b3c3a"}, "idna": {:hex, :idna, "6.1.1", "8a63070e9f7d0c62eb9d9fcb360a7de382448200fbbd1b106cc96d3d8099df8d", [:rebar3], [{:unicode_util_compat, "~>0.7.0", [hex: :unicode_util_compat, repo: "hexpm", optional: false]}], "hexpm", "92376eb7894412ed19ac475e4a86f7b413c1b9fbb5bd16dccd57934157944cea"}, "inch_ex": {:hex, :inch_ex, "2.1.0-rc.1", "7642a8902c0d2ed5d9b5754b2fc88fedf630500d630fc03db7caca2e92dedb36", [:mix], [{:bunt, "~> 0.2", [hex: :bunt, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: false]}], "hexpm", "4ceee988760f9382d1c1d0b93ea5875727f6071693e89a0a3c49c456ef1be75d"}, - "jason": {:hex, :jason, "1.2.2", "ba43e3f2709fd1aa1dce90aaabfd039d000469c05c56f0b8e31978e03fa39052", [:mix], [{:decimal, "~> 1.0 or ~> 2.0", [hex: :decimal, repo: "hexpm", optional: true]}], "hexpm", "18a228f5f0058ee183f29f9eae0805c6e59d61c3b006760668d8d18ff0d12179"}, + "jason": {:hex, :jason, "1.3.0", "fa6b82a934feb176263ad2df0dbd91bf633d4a46ebfdffea0c8ae82953714946", [:mix], [{:decimal, "~> 1.0 or ~> 2.0", [hex: :decimal, repo: "hexpm", optional: true]}], "hexpm", "53fc1f51255390e0ec7e50f9cb41e751c260d065dcba2bf0d08dc51a4002c2ac"}, "jose": {:hex, :jose, "1.11.2", "f4c018ccf4fdce22c71e44d471f15f723cb3efab5d909ab2ba202b5bf35557b3", [:mix, :rebar3], [], "hexpm", "98143fbc48d55f3a18daba82d34fe48959d44538e9697c08f34200fa5f0947d2"}, "jsx": {:hex, :jsx, "3.1.0", "d12516baa0bb23a59bb35dccaf02a1bd08243fcbb9efe24f2d9d056ccff71268", [:rebar3], [], "hexpm", "0c5cc8fdc11b53cc25cf65ac6705ad39e54ecc56d1c22e4adb8f5a53fb9427f3"}, "meck": {:hex, :meck, "0.9.2", "85ccbab053f1db86c7ca240e9fc718170ee5bda03810a6292b5306bf31bae5f5", [:rebar3], [], "hexpm", "81344f561357dc40a8344afa53767c32669153355b626ea9fcbc8da6b3045826"}, "memento": {:hex, :memento, "0.3.2", "38cfc8ff9bcb1adff7cbd0f3b78a762636b86dff764729d1c82d0464c539bdd0", [:mix], [], "hexpm", "25cf691a98a0cb70262f4a7543c04bab24648cb2041d937eb64154a8d6f8012b"}, "metrics": {:hex, :metrics, "1.0.1", "25f094dea2cda98213cecc3aeff09e940299d950904393b2a29d191c346a8486", [:rebar3], [], "hexpm", "69b09adddc4f74a40716ae54d140f93beb0fb8978d8636eaded0c31b6f099f16"}, - "mime": {:hex, :mime, "1.6.0", "dabde576a497cef4bbdd60aceee8160e02a6c89250d6c0b29e56c0dfb00db3d2", [:mix], [], "hexpm", "31a1a8613f8321143dde1dafc36006a17d28d02bdfecb9e95a880fa7aabd19a7"}, + "mime": {:hex, :mime, "2.0.2", "0b9e1a4c840eafb68d820b0e2158ef5c49385d17fb36855ac6e7e087d4b1dcc5", [:mix], [], "hexpm", "e6a3f76b4c277739e36c2e21a2c640778ba4c3846189d5ab19f97f126df5f9b7"}, "mimerl": {:hex, :mimerl, "1.2.0", "67e2d3f571088d5cfd3e550c383094b47159f3eee8ffa08e64106cdf5e981be3", [:rebar3], [], "hexpm", "f278585650aa581986264638ebf698f8bb19df297f66ad91b18910dfc6e19323"}, "mock": {:hex, :mock, "0.3.7", "75b3bbf1466d7e486ea2052a73c6e062c6256fb429d6797999ab02fa32f29e03", [:mix], [{:meck, "~> 0.9.2", [hex: :meck, repo: "hexpm", optional: false]}], "hexpm", "4da49a4609e41fd99b7836945c26f373623ea968cfb6282742bcb94440cf7e5c"}, "openid_connect": {:hex, :openid_connect, "0.2.2", "c05055363330deab39ffd89e609db6b37752f255a93802006d83b45596189c0b", [:mix], [{:httpoison, "~> 1.2", [hex: :httpoison, repo: "hexpm", optional: false]}, {:jason, ">= 1.0.0", [hex: :jason, repo: "hexpm", optional: false]}, {:jose, "~> 1.8", [hex: :jose, repo: "hexpm", optional: false]}], "hexpm", "735769b6d592124b58edd0582554ce638524c0214cd783d8903d33357d74cc13"}, "parallel_stream": {:hex, :parallel_stream, "1.0.6", "b967be2b23f0f6787fab7ed681b4c45a215a81481fb62b01a5b750fa8f30f76c", [:mix], [], "hexpm", "639b2e8749e11b87b9eb42f2ad325d161c170b39b288ac8d04c4f31f8f0823eb"}, "parse_trans": {:hex, :parse_trans, "3.3.1", "16328ab840cc09919bd10dab29e431da3af9e9e7e7e6f0089dd5a2d2820011d8", [:rebar3], [], "hexpm", "07cd9577885f56362d414e8c4c4e6bdf10d43a8767abb92d24cbe8b24c54888b"}, - "phoenix": {:hex, :phoenix, "1.5.10", "3ee7d5c17ff9626d72d374d8fc8909bf00f4323fd15549fbe3abbbd38b5299c8", [:mix], [{:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}, {:phoenix_html, "~> 2.13 or ~> 3.0", [hex: :phoenix_html, repo: "hexpm", optional: true]}, {:phoenix_pubsub, "~> 2.0", [hex: :phoenix_pubsub, repo: "hexpm", optional: false]}, {:plug, "~> 1.10", [hex: :plug, repo: "hexpm", optional: false]}, {:plug_cowboy, "~> 1.0 or ~> 2.2", [hex: :plug_cowboy, repo: "hexpm", optional: true]}, {:plug_crypto, "~> 1.1.2 or ~> 1.2", [hex: :plug_crypto, repo: "hexpm", optional: false]}, {:telemetry, "~> 0.4", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "f9c2eaa5a8fe5a412610c6aa84ccdb6f3e92f333d4df7fbaeb0d5a157dbfb48d"}, - "phoenix_ecto": {:hex, :phoenix_ecto, "4.3.0", "2c69a452c2e0ee8c93345ae1cdc1696ef4877ff9cbb15c305def41960c3c4ebf", [:mix], [{:ecto, "~> 3.0", [hex: :ecto, repo: "hexpm", optional: false]}, {:phoenix_html, "~> 2.14.2 or ~> 3.0", [hex: :phoenix_html, repo: "hexpm", optional: true]}, {:plug, "~> 1.0", [hex: :plug, repo: "hexpm", optional: false]}], "hexpm", "0ac491924217550c8f42c81c1f390b5d81517d12ceaf9abf3e701156760a848e"}, + "phoenix": {:hex, :phoenix, "1.6.6", "281c8ce8dccc9f60607346b72cdfc597c3dde134dd9df28dff08282f0b751754", [:mix], [{:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}, {:phoenix_pubsub, "~> 2.0", [hex: :phoenix_pubsub, repo: "hexpm", optional: false]}, {:phoenix_view, "~> 1.0", [hex: :phoenix_view, repo: "hexpm", optional: false]}, {:plug, "~> 1.10", [hex: :plug, repo: "hexpm", optional: false]}, {:plug_cowboy, "~> 2.2", [hex: :plug_cowboy, repo: "hexpm", optional: true]}, {:plug_crypto, "~> 1.2", [hex: :plug_crypto, repo: "hexpm", optional: false]}, {:telemetry, "~> 0.4 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "807bd646e64cd9dc83db016199715faba72758e6db1de0707eef0a2da4924364"}, + "phoenix_ecto": {:hex, :phoenix_ecto, "4.4.0", "0672ed4e4808b3fbed494dded89958e22fb882de47a97634c0b13e7b0b5f7720", [:mix], [{:ecto, "~> 3.3", [hex: :ecto, repo: "hexpm", optional: false]}, {:phoenix_html, "~> 2.14.2 or ~> 3.0", [hex: :phoenix_html, repo: "hexpm", optional: true]}, {:plug, "~> 1.9", [hex: :plug, repo: "hexpm", optional: false]}], "hexpm", "09864e558ed31ee00bd48fcc1d4fc58ae9678c9e81649075431e69dbabb43cc1"}, "phoenix_pubsub": {:hex, :phoenix_pubsub, "2.0.0", "a1ae76717bb168cdeb10ec9d92d1480fec99e3080f011402c0a2d68d47395ffb", [:mix], [], "hexpm", "c52d948c4f261577b9c6fa804be91884b381a7f8f18450c5045975435350f771"}, "phoenix_swagger": {:hex, :phoenix_swagger, "0.8.3", "298d6204802409d3b0b4fc1013873839478707cf3a62532a9e10fec0e26d0e37", [:mix], [{:ex_json_schema, "~> 0.7.1", [hex: :ex_json_schema, repo: "hexpm", optional: true]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}, {:plug, "~> 1.11", [hex: :plug, repo: "hexpm", optional: false]}, {:poison, "~> 2.2 or ~> 3.0", [hex: :poison, repo: "hexpm", optional: true]}], "hexpm", "3bc0fa9f5b679b8a61b90a52b2c67dd932320e9a84a6f91a4af872a0ab367337"}, - "plug": {:hex, :plug, "1.12.1", "645678c800601d8d9f27ad1aebba1fdb9ce5b2623ddb961a074da0b96c35187d", [:mix], [{:mime, "~> 1.0 or ~> 2.0", [hex: :mime, repo: "hexpm", optional: false]}, {:plug_crypto, "~> 1.1.1 or ~> 1.2", [hex: :plug_crypto, repo: "hexpm", optional: false]}, {:telemetry, "~> 0.4.3 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "d57e799a777bc20494b784966dc5fbda91eb4a09f571f76545b72a634ce0d30b"}, - "plug_cowboy": {:hex, :plug_cowboy, "2.5.1", "7cc96ff645158a94cf3ec9744464414f02287f832d6847079adfe0b58761cbd0", [:mix], [{:cowboy, "~> 2.7", [hex: :cowboy, repo: "hexpm", optional: false]}, {:cowboy_telemetry, "~> 0.3", [hex: :cowboy_telemetry, repo: "hexpm", optional: false]}, {:plug, "~> 1.7", [hex: :plug, repo: "hexpm", optional: false]}, {:telemetry, "~> 0.4 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "107d0a5865fa92bcb48e631cc0729ae9ccfa0a9f9a1bd8f01acb513abf1c2d64"}, + "phoenix_view": {:hex, :phoenix_view, "1.1.2", "1b82764a065fb41051637872c7bd07ed2fdb6f5c3bd89684d4dca6e10115c95a", [:mix], [{:phoenix_html, "~> 2.14.2 or ~> 3.0", [hex: :phoenix_html, repo: "hexpm", optional: true]}], "hexpm", "7ae90ad27b09091266f6adbb61e1d2516a7c3d7062c6789d46a7554ec40f3a56"}, + "plug": {:hex, :plug, "1.13.3", "93b299039c21a8b82cc904d13812bce4ced45cf69153e8d35ca16ffb3e8c5d98", [:mix], [{:mime, "~> 1.0 or ~> 2.0", [hex: :mime, repo: "hexpm", optional: false]}, {:plug_crypto, "~> 1.1.1 or ~> 1.2", [hex: :plug_crypto, repo: "hexpm", optional: false]}, {:telemetry, "~> 0.4.3 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "98c8003e4faf7b74a9ac41bee99e328b08f069bf932747d4a7532e97ae837a17"}, + "plug_cowboy": {:hex, :plug_cowboy, "2.5.2", "62894ccd601cf9597e2c23911ff12798a8a18d237e9739f58a6b04e4988899fe", [:mix], [{:cowboy, "~> 2.7", [hex: :cowboy, repo: "hexpm", optional: false]}, {:cowboy_telemetry, "~> 0.3", [hex: :cowboy_telemetry, repo: "hexpm", optional: false]}, {:plug, "~> 1.7", [hex: :plug, repo: "hexpm", optional: false]}], "hexpm", "ea6e87f774c8608d60c8d34022a7d073bd7680a0a013f049fc62bf35efea1044"}, "plug_crypto": {:hex, :plug_crypto, "1.2.2", "05654514ac717ff3a1843204b424477d9e60c143406aa94daf2274fdd280794d", [:mix], [], "hexpm", "87631c7ad914a5a445f0a3809f99b079113ae4ed4b867348dd9eec288cecb6db"}, - "postgrex": {:hex, :postgrex, "0.15.10", "2809dee1b1d76f7cbabe570b2a9285c2e7b41be60cf792f5f2804a54b838a067", [:mix], [{:connection, "~> 1.0", [hex: :connection, repo: "hexpm", optional: false]}, {:db_connection, "~> 2.1", [hex: :db_connection, repo: "hexpm", optional: false]}, {:decimal, "~> 1.5 or ~> 2.0", [hex: :decimal, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}], "hexpm", "1560ca427542f6b213f8e281633ae1a3b31cdbcd84ebd7f50628765b8f6132be"}, - "quantum": {:hex, :quantum, "3.3.0", "e8f6b9479728774288c5f426b11a6e3e8f619f3c226163a7e18bccfe543b714d", [:mix], [{:crontab, "~> 1.1", [hex: :crontab, repo: "hexpm", optional: false]}, {:gen_stage, "~> 0.14 or ~> 1.0", [hex: :gen_stage, repo: "hexpm", optional: false]}, {:telemetry, "~> 0.4", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "3b83ef137ab3887e783b013418b5ce3e847d66b71c4ef0f233b0321c84b72f67"}, + "postgrex": {:hex, :postgrex, "0.16.2", "0f83198d0e73a36e8d716b90f45f3bde75b5eebf4ade4f43fa1f88c90a812f74", [:mix], [{:connection, "~> 1.1", [hex: :connection, repo: "hexpm", optional: false]}, {:db_connection, "~> 2.1", [hex: :db_connection, repo: "hexpm", optional: false]}, {:decimal, "~> 1.5 or ~> 2.0", [hex: :decimal, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}], "hexpm", "a9ea589754d9d4d076121090662b7afe155b374897a6550eb288f11d755acfa0"}, + "quantum": {:hex, :quantum, "3.4.0", "5a53c3c52b0d55f2323940232ba6ab4c98e7e14c73dfacbba3a1ed799b037ce5", [:mix], [{:crontab, "~> 1.1", [hex: :crontab, repo: "hexpm", optional: false]}, {:gen_stage, "~> 0.14 or ~> 1.0", [hex: :gen_stage, repo: "hexpm", optional: false]}, {:telemetry, "~> 0.4.3 or ~> 1.0.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "d0eb64957d3dc49c8ed730cc2203108334226496535965b8dfa3f3dbcf430f87"}, "que": {:hex, :que, "0.10.1", "788ed0ec92ed69bdf9cfb29bf41a94ca6355b8d44959bd0669cf706e557ac891", [:mix], [{:ex_utils, "~> 0.1.6", [hex: :ex_utils, repo: "hexpm", optional: false]}, {:memento, "~> 0.3.0", [hex: :memento, repo: "hexpm", optional: false]}], "hexpm", "a737b365253e75dbd24b2d51acc1d851049e87baae08cd0c94e2bc5cd65088d5"}, "ranch": {:hex, :ranch, "1.8.0", "8c7a100a139fd57f17327b6413e4167ac559fbc04ca7448e9be9057311597a1d", [:make, :rebar3], [], "hexpm", "49fbcfd3682fab1f5d109351b61257676da1a2fdbe295904176d5e521a2ddfe5"}, "recase": {:hex, :recase, "0.7.0", "3f2f719f0886c7a3b7fe469058ec539cb7bbe0023604ae3bce920e186305e5ae", [:mix], [], "hexpm", "36f5756a9f552f4a94b54a695870e32f4e72d5fad9c25e61bc4a3151c08a4e0c"}, - "sentry": {:hex, :sentry, "8.0.5", "5ca922b9238a50c7258b52f47364b2d545beda5e436c7a43965b34577f1ef61f", [:mix], [{:hackney, "~> 1.8", [hex: :hackney, repo: "hexpm", optional: true]}, {:jason, "~> 1.1", [hex: :jason, repo: "hexpm", optional: true]}, {:plug, "~> 1.6", [hex: :plug, repo: "hexpm", optional: true]}, {:plug_cowboy, "~> 2.3", [hex: :plug_cowboy, repo: "hexpm", optional: true]}], "hexpm", "4972839fdbf52e886d7b3e694c8adf421f764f2fa79036b88fb4742049bd4b7c"}, + "sentry": {:hex, :sentry, "8.0.6", "c8de1bf0523bc120ec37d596c55260901029ecb0994e7075b0973328779ceef7", [:mix], [{:hackney, "~> 1.8", [hex: :hackney, repo: "hexpm", optional: true]}, {:jason, "~> 1.1", [hex: :jason, repo: "hexpm", optional: true]}, {:plug, "~> 1.6", [hex: :plug, repo: "hexpm", optional: true]}, {:plug_cowboy, "~> 2.3", [hex: :plug_cowboy, repo: "hexpm", optional: true]}], "hexpm", "051a2d0472162f3137787c7c9d6e6e4ef239de9329c8c45b1f1bf1e9379e1883"}, "ssl_verify_fun": {:hex, :ssl_verify_fun, "1.1.6", "cf344f5692c82d2cd7554f5ec8fd961548d4fd09e7d22f5b62482e5aeaebd4b0", [:make, :mix, :rebar3], [], "hexpm", "bdb0d2471f453c88ff3908e7686f86f9be327d065cc1ec16fa4540197ea04680"}, - "sweet_xml": {:hex, :sweet_xml, "0.7.0", "39ca6a53c526a1759672690656d5a787bee1016bfff467310170f9b428a238cb", [:mix], [], "hexpm", "2f18cb07f22b5a0d3e99d8b7e4176020f0051f90e449968821e4fde930edd945"}, - "telemetry": {:hex, :telemetry, "0.4.3", "a06428a514bdbc63293cd9a6263aad00ddeb66f608163bdec7c8995784080818", [:rebar3], [], "hexpm", "eb72b8365ffda5bed68a620d1da88525e326cb82a75ee61354fc24b844768041"}, + "sweet_xml": {:hex, :sweet_xml, "0.7.2", "4729f997286811fabdd8288f8474e0840a76573051062f066c4b597e76f14f9f", [:mix], [], "hexpm", "6894e68a120f454534d99045ea3325f7740ea71260bc315f82e29731d570a6e8"}, + "telemetry": {:hex, :telemetry, "1.0.0", "0f453a102cdf13d506b7c0ab158324c337c41f1cc7548f0bc0e130bbf0ae9452", [:rebar3], [], "hexpm", "73bc09fa59b4a0284efb4624335583c528e07ec9ae76aca96ea0673850aec57a"}, "timex": {:hex, :timex, "3.7.6", "502d2347ec550e77fdf419bc12d15bdccd31266bb7d925b30bf478268098282f", [:mix], [{:combine, "~> 0.10", [hex: :combine, repo: "hexpm", optional: false]}, {:gettext, "~> 0.10", [hex: :gettext, repo: "hexpm", optional: false]}, {:tzdata, "~> 1.0", [hex: :tzdata, repo: "hexpm", optional: false]}], "hexpm", "a296327f79cb1ec795b896698c56e662ed7210cc9eb31f0ab365eb3a62e2c589"}, - "tzdata": {:hex, :tzdata, "1.1.0", "72f5babaa9390d0f131465c8702fa76da0919e37ba32baa90d93c583301a8359", [:mix], [{:hackney, "~> 1.17", [hex: :hackney, repo: "hexpm", optional: false]}], "hexpm", "18f453739b48d3dc5bcf0e8906d2dc112bb40baafe2c707596d89f3c8dd14034"}, + "tzdata": {:hex, :tzdata, "1.1.1", "20c8043476dfda8504952d00adac41c6eda23912278add38edc140ae0c5bcc46", [:mix], [{:hackney, "~> 1.17", [hex: :hackney, repo: "hexpm", optional: false]}], "hexpm", "a69cec8352eafcd2e198dea28a34113b60fdc6cb57eb5ad65c10292a6ba89787"}, "unicode_util_compat": {:hex, :unicode_util_compat, "0.7.0", "bc84380c9ab48177092f43ac89e4dfa2c6d62b40b8bd132b1059ecc7232f9a78", [:rebar3], [], "hexpm", "25eee6d67df61960cf6a794239566599b09e17e668d3700247bc498638152521"}, "xml_builder": {:hex, :xml_builder, "2.2.0", "cc5f1eeefcfcde6e90a9b77fb6c490a20bc1b856a7010ce6396f6da9719cbbab", [:mix], [], "hexpm", "9d66d52fb917565d358166a4314078d39ef04d552904de96f8e73f68f64a62c9"}, } From b042e45e281242b3768c69c9cd101904aa139786 Mon Sep 17 00:00:00 2001 From: Richard Qi <55354921+riccqi@users.noreply.github.com> Date: Wed, 23 Feb 2022 02:26:08 +0800 Subject: [PATCH 05/25] Update achievements.ex --- lib/cadet/incentives/achievements.ex | 1 + 1 file changed, 1 insertion(+) diff --git a/lib/cadet/incentives/achievements.ex b/lib/cadet/incentives/achievements.ex index 9eb1f0ee6..07fa45f5a 100644 --- a/lib/cadet/incentives/achievements.ex +++ b/lib/cadet/incentives/achievements.ex @@ -40,6 +40,7 @@ defmodule Cadet.Incentives.Achievements do goal <- achievement.goals, Enum.at(goal.goal.progress, 0).completed, reduce: 0 do + # contains bug that will add the same achievement xp for each of the goals it has total -> total + achievement.xp end From 2e5bfc0f2d99616d53639e12af55b4e6c1f8694c Mon Sep 17 00:00:00 2001 From: ShenyiCui Date: Wed, 23 Feb 2022 12:44:56 +0800 Subject: [PATCH 06/25] Change Function Name --- config/dev.exs | 4 ++-- lib/cadet/incentives/achievements.ex | 2 +- lib/cadet_web/controllers/incentives_controller.ex | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/config/dev.exs b/config/dev.exs index 1314c247f..aff99e085 100644 --- a/config/dev.exs +++ b/config/dev.exs @@ -51,8 +51,8 @@ config :phoenix, :stacktrace_depth, 20 # Configure your database config :cadet, Cadet.Repo, - username: "richardqi", - password: "", + username: "postgres", + password: "root", database: "cadet_dev", hostname: "localhost", pool_size: 10 diff --git a/lib/cadet/incentives/achievements.ex b/lib/cadet/incentives/achievements.ex index 07fa45f5a..67d8807b6 100644 --- a/lib/cadet/incentives/achievements.ex +++ b/lib/cadet/incentives/achievements.ex @@ -26,7 +26,7 @@ defmodule Cadet.Incentives.Achievements do This returns Achievement structs with prerequisites, goal association and progress maps pre-loaded. """ - def get_goals_with_progress(course_id) when is_ecto_id(course_id) do + def get_total_xp(course_id) when is_ecto_id(course_id) do achievements = Achievement |> where(course_id: ^course_id) diff --git a/lib/cadet_web/controllers/incentives_controller.ex b/lib/cadet_web/controllers/incentives_controller.ex index 569f40137..4ce97992f 100644 --- a/lib/cadet_web/controllers/incentives_controller.ex +++ b/lib/cadet_web/controllers/incentives_controller.ex @@ -19,7 +19,7 @@ defmodule CadetWeb.IncentivesController do def calculate_totalxp(conn, _) do course_id = conn.assigns.course_reg.course_id - total_xp = Achievements.get_goals_with_progress(course_id) + total_xp = Achievements.get_total_xp(course_id) IO.puts(total_xp) # IO.inspect Enum.at(goals, 0) # IO.inspect Enum.at(achievements, 0) From 252bfa1282d2957b1111fa7a98b794c68ca1e8f1 Mon Sep 17 00:00:00 2001 From: ShenyiCui Date: Wed, 2 Mar 2022 00:43:30 +0800 Subject: [PATCH 07/25] Add assessment xp calculation --- config/dev.exs | 6 ++-- lib/cadet/incentives/achievements.ex | 29 +++++++++++------ .../controllers/incentives_controller.ex | 31 +++++++++---------- 3 files changed, 37 insertions(+), 29 deletions(-) diff --git a/config/dev.exs b/config/dev.exs index aff99e085..36ed68b2f 100644 --- a/config/dev.exs +++ b/config/dev.exs @@ -51,9 +51,9 @@ config :phoenix, :stacktrace_depth, 20 # Configure your database config :cadet, Cadet.Repo, - username: "postgres", - password: "root", - database: "cadet_dev", + username: "###", + password: "###", + database: "###", hostname: "localhost", pool_size: 10 diff --git a/lib/cadet/incentives/achievements.ex b/lib/cadet/incentives/achievements.ex index 67d8807b6..f6c98fe3c 100644 --- a/lib/cadet/incentives/achievements.ex +++ b/lib/cadet/incentives/achievements.ex @@ -23,6 +23,8 @@ defmodule Cadet.Incentives.Achievements do @doc """ Returns all achievements with goals and progress. + # To Do + Run elixir tests for edge cases etc. This returns Achievement structs with prerequisites, goal association and progress maps pre-loaded. """ @@ -33,17 +35,26 @@ defmodule Cadet.Incentives.Achievements do |> preload([:prerequisites, goals: [goal: :progress]]) |> Repo.all() - # IO.puts("---------------------------------------") - # IO.inspect(achievements) - for achievement <- achievements, - goal <- achievement.goals, - Enum.at(goal.goal.progress, 0).completed, - reduce: 0 do - # contains bug that will add the same achievement xp for each of the goals it has - total -> - total + achievement.xp + is_goal_completed = fn (goal_item) -> + if (Enum.count(goal_item.goal.progress) != 0), + do: Enum.at(goal_item.goal.progress, 0).completed, + else: false end + + is_all_goal_completed = fn (goal_item, acc) -> + if is_goal_completed.(goal_item), do: {:cont, acc}, else: {:halt, 0} + end + + acc_goals = fn (all_goals) -> + Enum.reduce_while(all_goals, 1, is_all_goal_completed) + end + + acc_achievements = fn (achievement_item, acc) -> + acc + acc_goals.(achievement_item.goals) * achievement_item.xp + end + + Enum.reduce(achievements, 0, acc_achievements) end @spec upsert(map()) :: {:ok, %Achievement{}} | {:error, {:bad_request, String.t()}} diff --git a/lib/cadet_web/controllers/incentives_controller.ex b/lib/cadet_web/controllers/incentives_controller.ex index 4ce97992f..af20ea8a0 100644 --- a/lib/cadet_web/controllers/incentives_controller.ex +++ b/lib/cadet_web/controllers/incentives_controller.ex @@ -2,7 +2,9 @@ defmodule CadetWeb.IncentivesController do use CadetWeb, :controller use PhoenixSwagger + import Cadet.Assessments + alias Cadet.Accounts.CourseRegistrations alias Cadet.Incentives.{Achievements, Goals} def index_achievements(conn, _) do @@ -19,23 +21,18 @@ defmodule CadetWeb.IncentivesController do def calculate_totalxp(conn, _) do course_id = conn.assigns.course_reg.course_id - total_xp = Achievements.get_total_xp(course_id) - IO.puts(total_xp) - # IO.inspect Enum.at(goals, 0) - # IO.inspect Enum.at(achievements, 0) - # total_xp = 0 - # Enum.each(achievements, fn achivement_item -> - # xp = achivement_item.xp - # Enum.each(achivement_item.goals, fn goal_item -> - # progress = Enum.at(goal_item.goal.progress, 0) - # if (!progress.completed) do - # IO.inspect "uncompleted" - # xp = 0 - # end - # end) - # total_xp = total_xp + xp - # end) - json(conn, %{totalXp: total_xp}) + total_achievement_xp = Achievements.get_total_xp(course_id) + user = conn.assigns.current_user + + if user.latest_viewed_course_id do + latest = CourseRegistrations.get_user_course(user.id, user.latest_viewed_course_id) + total_assessment_xp = user_total_xp(latest) + total_xp = total_assessment_xp + total_achievement_xp + json(conn, %{totalXp: total_xp}) + else + json(conn, %{totalXp: total_achievement_xp}) + end + end @spec update_progress(Plug.Conn.t(), map) :: Plug.Conn.t() From 9e7515f344ef3cb6bfd47e15844ba6e703733efb Mon Sep 17 00:00:00 2001 From: ShenyiCui Date: Wed, 2 Mar 2022 01:08:42 +0800 Subject: [PATCH 08/25] Remove redundant code --- lib/cadet_web/admin_views/admin_goals_view.ex | 4 ---- 1 file changed, 4 deletions(-) diff --git a/lib/cadet_web/admin_views/admin_goals_view.ex b/lib/cadet_web/admin_views/admin_goals_view.ex index 7ddcd1157..d41c060e8 100644 --- a/lib/cadet_web/admin_views/admin_goals_view.ex +++ b/lib/cadet_web/admin_views/admin_goals_view.ex @@ -10,10 +10,6 @@ defmodule CadetWeb.AdminGoalsView do render_many(goals, CadetWeb.AdminGoalsView, "goal_with_progress.json", as: :goal) end - def render("totalxp.json", %{data: data}) do - %{data: data} - end - def render("goal.json", %{goal: goal}) do transform_map_for_view(goal, %{ uuid: :uuid, From 84661704017ab8e4b88c7af2a4b1052998c9ac4a Mon Sep 17 00:00:00 2001 From: ShenyiCui Date: Wed, 2 Mar 2022 01:10:48 +0800 Subject: [PATCH 09/25] Update incentives view --- lib/cadet_web/views/incentives_view.ex | 6 ------ 1 file changed, 6 deletions(-) diff --git a/lib/cadet_web/views/incentives_view.ex b/lib/cadet_web/views/incentives_view.ex index e038c2de4..c72e747ea 100644 --- a/lib/cadet_web/views/incentives_view.ex +++ b/lib/cadet_web/views/incentives_view.ex @@ -33,12 +33,6 @@ defmodule CadetWeb.IncentivesView do render_many(goals, CadetWeb.IncentivesView, "goal_with_progress.json", as: :goal) end - def render("item.json", %{message: message}) do - %{ - message: message, - } - end - def render("goal_with_progress.json", %{goal: goal}) do transform_map_for_view(goal, %{ uuid: :uuid, From cff2949d44dc142818dc3aa34b061209c115b346 Mon Sep 17 00:00:00 2001 From: ShenyiCui Date: Wed, 9 Mar 2022 01:20:26 +0800 Subject: [PATCH 10/25] Fix Bugs - xp calc based on user_id - xp calc based on goal count --- lib/cadet/incentives/achievements.ex | 16 ++++++++++------ .../controllers/incentives_controller.ex | 5 +++-- 2 files changed, 13 insertions(+), 8 deletions(-) diff --git a/lib/cadet/incentives/achievements.ex b/lib/cadet/incentives/achievements.ex index dd44f09eb..84c73776c 100644 --- a/lib/cadet/incentives/achievements.ex +++ b/lib/cadet/incentives/achievements.ex @@ -23,22 +23,24 @@ defmodule Cadet.Incentives.Achievements do @doc """ Returns all achievements with goals and progress. - # To Do - Run elixir tests for edge cases etc. This returns Achievement structs with prerequisites, goal association and progress maps pre-loaded. """ - def get_total_xp(course_id) when is_ecto_id(course_id) do + def get_total_xp(course_id, user_id) when is_ecto_id(course_id) do achievements = Achievement |> where(course_id: ^course_id) - |> preload([:prerequisites, goals: [goal: :progress]]) + |> preload([:prerequisites, goals: [goal: [progress: :course_reg]]]) |> Repo.all() + IO.inspect Enum.at(Enum.at(achievements, 2).goals, 0).goal.meta["targetCount"] + is_goal_completed = fn (goal_item) -> if (Enum.count(goal_item.goal.progress) != 0), - do: Enum.at(goal_item.goal.progress, 0).completed, + do: Enum.at(goal_item.goal.progress, 0).completed + and user_id == Enum.at(goal_item.goal.progress, 0).course_reg.user_id + and Enum.at(goal_item.goal.progress, 0).count == goal_item.goal.meta["targetCount"], else: false end @@ -47,7 +49,9 @@ defmodule Cadet.Incentives.Achievements do end acc_goals = fn (all_goals) -> - Enum.reduce_while(all_goals, 1, is_all_goal_completed) + if (Enum.count(all_goals) != 0), + do: Enum.reduce_while(all_goals, 1, is_all_goal_completed), + else: 0 end acc_achievements = fn (achievement_item, acc) -> diff --git a/lib/cadet_web/controllers/incentives_controller.ex b/lib/cadet_web/controllers/incentives_controller.ex index af20ea8a0..e62a1e54c 100644 --- a/lib/cadet_web/controllers/incentives_controller.ex +++ b/lib/cadet_web/controllers/incentives_controller.ex @@ -21,16 +21,17 @@ defmodule CadetWeb.IncentivesController do def calculate_totalxp(conn, _) do course_id = conn.assigns.course_reg.course_id - total_achievement_xp = Achievements.get_total_xp(course_id) user = conn.assigns.current_user if user.latest_viewed_course_id do latest = CourseRegistrations.get_user_course(user.id, user.latest_viewed_course_id) + total_achievement_xp = Achievements.get_total_xp(course_id, user.id) total_assessment_xp = user_total_xp(latest) + total_xp = total_assessment_xp + total_achievement_xp json(conn, %{totalXp: total_xp}) else - json(conn, %{totalXp: total_achievement_xp}) + json(conn, %{totalXp: "an error has occured"}) end end From c8fbea6ffd712393f3f1b7183eec852cbb17b463 Mon Sep 17 00:00:00 2001 From: ShenyiCui Date: Wed, 9 Mar 2022 01:21:38 +0800 Subject: [PATCH 11/25] Refactor Code - run mix format --- lib/cadet/incentives/achievements.ex | 24 +++++++++---------- lib/cadet/jobs/autograder/lambda_worker.ex | 4 +++- .../controllers/incentives_controller.ex | 1 - 3 files changed, 15 insertions(+), 14 deletions(-) diff --git a/lib/cadet/incentives/achievements.ex b/lib/cadet/incentives/achievements.ex index 84c73776c..1d91bea66 100644 --- a/lib/cadet/incentives/achievements.ex +++ b/lib/cadet/incentives/achievements.ex @@ -33,28 +33,28 @@ defmodule Cadet.Incentives.Achievements do |> preload([:prerequisites, goals: [goal: [progress: :course_reg]]]) |> Repo.all() - - IO.inspect Enum.at(Enum.at(achievements, 2).goals, 0).goal.meta["targetCount"] - - is_goal_completed = fn (goal_item) -> - if (Enum.count(goal_item.goal.progress) != 0), - do: Enum.at(goal_item.goal.progress, 0).completed - and user_id == Enum.at(goal_item.goal.progress, 0).course_reg.user_id - and Enum.at(goal_item.goal.progress, 0).count == goal_item.goal.meta["targetCount"], + IO.inspect(Enum.at(Enum.at(achievements, 2).goals, 0).goal.meta["targetCount"]) + + is_goal_completed = fn goal_item -> + if Enum.count(goal_item.goal.progress) != 0, + do: + Enum.at(goal_item.goal.progress, 0).completed and + user_id == Enum.at(goal_item.goal.progress, 0).course_reg.user_id and + Enum.at(goal_item.goal.progress, 0).count == goal_item.goal.meta["targetCount"], else: false end - is_all_goal_completed = fn (goal_item, acc) -> + is_all_goal_completed = fn goal_item, acc -> if is_goal_completed.(goal_item), do: {:cont, acc}, else: {:halt, 0} end - acc_goals = fn (all_goals) -> - if (Enum.count(all_goals) != 0), + acc_goals = fn all_goals -> + if Enum.count(all_goals) != 0, do: Enum.reduce_while(all_goals, 1, is_all_goal_completed), else: 0 end - acc_achievements = fn (achievement_item, acc) -> + acc_achievements = fn achievement_item, acc -> acc + acc_goals.(achievement_item.goals) * achievement_item.xp end diff --git a/lib/cadet/jobs/autograder/lambda_worker.ex b/lib/cadet/jobs/autograder/lambda_worker.ex index a2a6d3f7a..350869896 100644 --- a/lib/cadet/jobs/autograder/lambda_worker.ex +++ b/lib/cadet/jobs/autograder/lambda_worker.ex @@ -44,7 +44,9 @@ defmodule Cadet.Autograder.LambdaWorker do def on_failure(%{answer: answer = %Answer{}, question: %Question{}}, error) do error_message = - "Failed to get autograder result. answer_id: #{answer.id}, error: #{inspect(error, pretty: true)}" + "Failed to get autograder result. answer_id: #{answer.id}, error: #{ + inspect(error, pretty: true) + }" Logger.error(error_message) Sentry.capture_message(error_message) diff --git a/lib/cadet_web/controllers/incentives_controller.ex b/lib/cadet_web/controllers/incentives_controller.ex index e62a1e54c..fff245f48 100644 --- a/lib/cadet_web/controllers/incentives_controller.ex +++ b/lib/cadet_web/controllers/incentives_controller.ex @@ -33,7 +33,6 @@ defmodule CadetWeb.IncentivesController do else json(conn, %{totalXp: "an error has occured"}) end - end @spec update_progress(Plug.Conn.t(), map) :: Plug.Conn.t() From ce58119cb53b091561f73bd5df415086861001fa Mon Sep 17 00:00:00 2001 From: Richard Qi <55354921+riccqi@users.noreply.github.com> Date: Wed, 9 Mar 2022 03:37:25 +0800 Subject: [PATCH 12/25] Code cleanup - Inlined small functions - Changed function naming related to calculating total xp - Moved total_xp endpoint to user route --- config/dev.exs | 6 ++-- lib/cadet/incentives/achievements.ex | 36 +++++++++---------- lib/cadet/jobs/autograder/lambda_worker.ex | 4 +-- .../controllers/incentives_controller.ex | 18 ---------- lib/cadet_web/controllers/user_controller.ex | 31 ++++++++++++---- lib/cadet_web/router.ex | 2 +- 6 files changed, 45 insertions(+), 52 deletions(-) diff --git a/config/dev.exs b/config/dev.exs index 36ed68b2f..43360b906 100644 --- a/config/dev.exs +++ b/config/dev.exs @@ -51,9 +51,9 @@ config :phoenix, :stacktrace_depth, 20 # Configure your database config :cadet, Cadet.Repo, - username: "###", - password: "###", - database: "###", + username: "postgres", + password: "postgres", + database: "cadet_dev", hostname: "localhost", pool_size: 10 diff --git a/lib/cadet/incentives/achievements.ex b/lib/cadet/incentives/achievements.ex index 1d91bea66..ae92a56bf 100644 --- a/lib/cadet/incentives/achievements.ex +++ b/lib/cadet/incentives/achievements.ex @@ -22,19 +22,17 @@ defmodule Cadet.Incentives.Achievements do end @doc """ - Returns all achievements with goals and progress. + Returns a user's total xp from their completed achievements. This returns Achievement structs with prerequisites, goal association and progress maps pre-loaded. """ - def get_total_xp(course_id, user_id) when is_ecto_id(course_id) do + def achievements_total_xp(course_id, user_id) when is_ecto_id(course_id) do achievements = Achievement |> where(course_id: ^course_id) |> preload([:prerequisites, goals: [goal: [progress: :course_reg]]]) |> Repo.all() - IO.inspect(Enum.at(Enum.at(achievements, 2).goals, 0).goal.meta["targetCount"]) - is_goal_completed = fn goal_item -> if Enum.count(goal_item.goal.progress) != 0, do: @@ -44,24 +42,22 @@ defmodule Cadet.Incentives.Achievements do else: false end - is_all_goal_completed = fn goal_item, acc -> - if is_goal_completed.(goal_item), do: {:cont, acc}, else: {:halt, 0} - end - - acc_goals = fn all_goals -> - if Enum.count(all_goals) != 0, - do: Enum.reduce_while(all_goals, 1, is_all_goal_completed), - else: 0 - end - - acc_achievements = fn achievement_item, acc -> - acc + acc_goals.(achievement_item.goals) * achievement_item.xp - end - - Enum.reduce(achievements, 0, acc_achievements) + Enum.reduce(achievements, 0, fn achievement_item, acc -> + completed_goals = + if Enum.count(achievement_item.goals) != 0, + do: + Enum.reduce_while(achievement_item.goals, 1, fn goal_item, acc -> + if is_goal_completed.(goal_item), + do: {:cont, acc}, + else: {:halt, 0} + end), + else: 0 + + acc + completed_goals * achievement_item.xp + end) end - @spec upsert(map()) :: {:ok, %Achievement{}} | {:error, {:bad_request, String.t()}} + @spec upsert(map()) :: {:ok, Achievement.t()} | {:error, {:bad_request, String.t()}} @doc """ Inserts a new achievement, or updates it if it already exists. """ diff --git a/lib/cadet/jobs/autograder/lambda_worker.ex b/lib/cadet/jobs/autograder/lambda_worker.ex index 350869896..a2a6d3f7a 100644 --- a/lib/cadet/jobs/autograder/lambda_worker.ex +++ b/lib/cadet/jobs/autograder/lambda_worker.ex @@ -44,9 +44,7 @@ defmodule Cadet.Autograder.LambdaWorker do def on_failure(%{answer: answer = %Answer{}, question: %Question{}}, error) do error_message = - "Failed to get autograder result. answer_id: #{answer.id}, error: #{ - inspect(error, pretty: true) - }" + "Failed to get autograder result. answer_id: #{answer.id}, error: #{inspect(error, pretty: true)}" Logger.error(error_message) Sentry.capture_message(error_message) diff --git a/lib/cadet_web/controllers/incentives_controller.ex b/lib/cadet_web/controllers/incentives_controller.ex index fff245f48..deac4c999 100644 --- a/lib/cadet_web/controllers/incentives_controller.ex +++ b/lib/cadet_web/controllers/incentives_controller.ex @@ -2,9 +2,7 @@ defmodule CadetWeb.IncentivesController do use CadetWeb, :controller use PhoenixSwagger - import Cadet.Assessments - alias Cadet.Accounts.CourseRegistrations alias Cadet.Incentives.{Achievements, Goals} def index_achievements(conn, _) do @@ -19,22 +17,6 @@ defmodule CadetWeb.IncentivesController do ) end - def calculate_totalxp(conn, _) do - course_id = conn.assigns.course_reg.course_id - user = conn.assigns.current_user - - if user.latest_viewed_course_id do - latest = CourseRegistrations.get_user_course(user.id, user.latest_viewed_course_id) - total_achievement_xp = Achievements.get_total_xp(course_id, user.id) - total_assessment_xp = user_total_xp(latest) - - total_xp = total_assessment_xp + total_achievement_xp - json(conn, %{totalXp: total_xp}) - else - json(conn, %{totalXp: "an error has occured"}) - end - end - @spec update_progress(Plug.Conn.t(), map) :: Plug.Conn.t() def update_progress(conn, %{"uuid" => uuid, "progress" => progress}) do course_reg_id = conn.assigns.course_reg.id diff --git a/lib/cadet_web/controllers/user_controller.ex b/lib/cadet_web/controllers/user_controller.ex index f5bca255c..ca5391c3f 100644 --- a/lib/cadet_web/controllers/user_controller.ex +++ b/lib/cadet_web/controllers/user_controller.ex @@ -5,7 +5,8 @@ defmodule CadetWeb.UserController do use CadetWeb, :controller use PhoenixSwagger - import Cadet.Assessments + alias Cadet.Assessments + alias Cadet.Incentives.Achievements alias Cadet.Accounts alias Cadet.Accounts.CourseRegistrations @@ -15,9 +16,9 @@ defmodule CadetWeb.UserController do if user.latest_viewed_course_id do latest = CourseRegistrations.get_user_course(user.id, user.latest_viewed_course_id) - xp = user_total_xp(latest) - max_xp = user_max_xp(latest) - story = user_current_story(latest) + xp = Assessments.user_total_xp(latest) + max_xp = Assessments.user_max_xp(latest) + story = Assessments.user_current_story(latest) render( conn, @@ -58,9 +59,9 @@ defmodule CadetWeb.UserController do end defp get_course_reg_config(conn, course_reg) do - xp = user_total_xp(course_reg) - max_xp = user_max_xp(course_reg) - story = user_current_story(course_reg) + xp = Assessments.user_total_xp(course_reg) + max_xp = Assessments.user_max_xp(course_reg) + story = Assessments.user_current_story(course_reg) render( conn, @@ -112,6 +113,22 @@ defmodule CadetWeb.UserController do end end + def combined_total_xp(conn, _) do + course_id = conn.assigns.course_reg.course_id + user = conn.assigns.current_user + + if user.latest_viewed_course_id do + latest = CourseRegistrations.get_user_course(user.id, user.latest_viewed_course_id) + total_achievement_xp = Achievements.achievements_total_xp(course_id, user.id) + total_assessment_xp = Assessments.user_total_xp(latest) + + total_xp = total_assessment_xp + total_achievement_xp + json(conn, %{totalXp: total_xp}) + else + json(conn, %{totalXp: "an error has occured"}) + end + end + swagger_path :index do get("/v2/user") diff --git a/lib/cadet_web/router.ex b/lib/cadet_web/router.ex index 6ffcebe79..bbfa468b6 100644 --- a/lib/cadet_web/router.ex +++ b/lib/cadet_web/router.ex @@ -79,13 +79,13 @@ defmodule CadetWeb.Router do post("/assessments/question/:questionid/answer", AnswerController, :submit) get("/achievements", IncentivesController, :index_achievements) - get("/achievements/totalxp", IncentivesController, :calculate_totalxp) get("/stories", StoriesController, :index) get("/notifications", NotificationsController, :index) post("/notifications/acknowledge", NotificationsController, :acknowledge) + get("/user/total_xp", UserController, :combined_total_xp) put("/user/game_states", UserController, :update_game_states) put("/user/research_agreement", UserController, :update_research_agreement) From a81d266cef9766c77dbfff18c0940d8147a3192c Mon Sep 17 00:00:00 2001 From: Richard Qi <55354921+riccqi@users.noreply.github.com> Date: Wed, 9 Mar 2022 09:47:52 +0800 Subject: [PATCH 13/25] Update mix.lock --- mix.lock | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/mix.lock b/mix.lock index 8fca438ee..24b719472 100644 --- a/mix.lock +++ b/mix.lock @@ -5,7 +5,7 @@ "blankable": {:hex, :blankable, "1.0.0", "89ab564a63c55af117e115144e3b3b57eb53ad43ba0f15553357eb283e0ed425", [:mix], [], "hexpm", "7cf11aac0e44f4eedbee0c15c1d37d94c090cb72a8d9fddf9f7aec30f9278899"}, "bunt": {:hex, :bunt, "0.2.0", "951c6e801e8b1d2cbe58ebbd3e616a869061ddadcc4863d0a2182541acae9a38", [:mix], [], "hexpm", "7af5c7e09fe1d40f76c8e4f9dd2be7cebd83909f31fee7cd0e9eadc567da8353"}, "bypass": {:hex, :bypass, "2.1.0", "909782781bf8e20ee86a9cabde36b259d44af8b9f38756173e8f5e2e1fabb9b1", [:mix], [{:plug, "~> 1.7", [hex: :plug, repo: "hexpm", optional: false]}, {:plug_cowboy, "~> 2.0", [hex: :plug_cowboy, repo: "hexpm", optional: false]}, {:ranch, "~> 1.3", [hex: :ranch, repo: "hexpm", optional: false]}], "hexpm", "d9b5df8fa5b7a6efa08384e9bbecfe4ce61c77d28a4282f79e02f1ef78d96b80"}, - "certifi": {:hex, :certifi, "2.9.0", "6f2a475689dd47f19fb74334859d460a2dc4e3252a3324bd2111b8f0429e7e21", [:rebar3], [], "hexpm", "266da46bdb06d6c6d35fde799bcb28d36d985d424ad7c08b5bb48f5b5cdd4641"}, + "certifi": {:hex, :certifi, "2.8.0", "d4fb0a6bb20b7c9c3643e22507e42f356ac090a1dcea9ab99e27e0376d695eba", [:rebar3], [], "hexpm", "6ac7efc1c6f8600b08d625292d4bbf584e14847ce1b6b5c44d983d273e1097ea"}, "combine": {:hex, :combine, "0.10.0", "eff8224eeb56498a2af13011d142c5e7997a80c8f5b97c499f84c841032e429f", [:mix], [], "hexpm", "1b1dbc1790073076580d0d1d64e42eae2366583e7aecd455d1215b0d16f2451b"}, "configparser_ex": {:hex, :configparser_ex, "4.0.0", "17e2b831cfa33a08c56effc610339b2986f0d82a9caa0ed18880a07658292ab6", [:mix], [], "hexpm", "02e6d1a559361a063cba7b75bc3eb2d6ad7e62730c551cc4703541fd11e65e5b"}, "connection": {:hex, :connection, "1.1.0", "ff2a49c4b75b6fb3e674bfc5536451607270aac754ffd1bdfe175abe4a6d7a68", [:mix], [], "hexpm", "722c1eb0a418fbe91ba7bd59a47e28008a189d47e37e0e7bb85585a016b2869c"}, @@ -13,8 +13,8 @@ "cowboy": {:hex, :cowboy, "2.9.0", "865dd8b6607e14cf03282e10e934023a1bd8be6f6bacf921a7e2a96d800cd452", [:make, :rebar3], [{:cowlib, "2.11.0", [hex: :cowlib, repo: "hexpm", optional: false]}, {:ranch, "1.8.0", [hex: :ranch, repo: "hexpm", optional: false]}], "hexpm", "2c729f934b4e1aa149aff882f57c6372c15399a20d54f65c8d67bef583021bde"}, "cowboy_telemetry": {:hex, :cowboy_telemetry, "0.4.0", "f239f68b588efa7707abce16a84d0d2acf3a0f50571f8bb7f56a15865aae820c", [:rebar3], [{:cowboy, "~> 2.7", [hex: :cowboy, repo: "hexpm", optional: false]}, {:telemetry, "~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "7d98bac1ee4565d31b62d59f8823dfd8356a169e7fcbb83831b8a5397404c9de"}, "cowlib": {:hex, :cowlib, "2.11.0", "0b9ff9c346629256c42ebe1eeb769a83c6cb771a6ee5960bd110ab0b9b872063", [:make, :rebar3], [], "hexpm", "2b3e9da0b21c4565751a6d4901c20d1b4cc25cbb7fd50d91d2ab6dd287bc86a9"}, - "credo": {:hex, :credo, "1.6.3", "0a9f8925dbc8f940031b789f4623fc9a0eea99d3eed600fe831e403eb96c6a83", [:mix], [{:bunt, "~> 0.2.0", [hex: :bunt, repo: "hexpm", optional: false]}, {:file_system, "~> 0.2.8", [hex: :file_system, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: false]}], "hexpm", "1167cde00e6661d740fc54da2ee268e35d3982f027399b64d3e2e83af57a1180"}, - "crontab": {:hex, :crontab, "1.1.11", "4028ced51b813a5061f85b689d4391ef0c27550c8ab09aaf139e4295c3d93ea4", [:mix], [{:ecto, "~> 1.0 or ~> 2.0 or ~> 3.0", [hex: :ecto, repo: "hexpm", optional: true]}], "hexpm", "ecb045f9ac14a3e2990e54368f70cdb6e2f2abafc5bc329d6c31f0c74b653787"}, + "credo": {:hex, :credo, "1.6.1", "7dc76dcdb764a4316c1596804c48eada9fff44bd4b733a91ccbf0c0f368be61e", [:mix], [{:bunt, "~> 0.2.0", [hex: :bunt, repo: "hexpm", optional: false]}, {:file_system, "~> 0.2.8", [hex: :file_system, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: false]}], "hexpm", "698607fb5993720c7e93d2d8e76f2175bba024de964e160e2f7151ef3ab82ac5"}, + "crontab": {:hex, :crontab, "1.1.10", "dc9bb1f4299138d47bce38341f5dcbee0aa6c205e864fba7bc847f3b5cb48241", [:mix], [{:ecto, "~> 1.0 or ~> 2.0 or ~> 3.0", [hex: :ecto, repo: "hexpm", optional: true]}], "hexpm", "1347d889d1a0eda997990876b4894359e34bfbbd688acbb0ba28a2795ca40685"}, "csv": {:hex, :csv, "2.4.1", "50e32749953b6bf9818dbfed81cf1190e38cdf24f95891303108087486c5925e", [:mix], [{:parallel_stream, "~> 1.0.4", [hex: :parallel_stream, repo: "hexpm", optional: false]}], "hexpm", "54508938ac67e27966b10ef49606e3ad5995d665d7fc2688efb3eab1307c9079"}, "db_connection": {:hex, :db_connection, "2.4.1", "6411f6e23f1a8b68a82fa3a36366d4881f21f47fc79a9efb8c615e62050219da", [:mix], [{:connection, "~> 1.0", [hex: :connection, repo: "hexpm", optional: false]}, {:telemetry, "~> 0.4 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "ea36d226ec5999781a9a8ad64e5d8c4454ecedc7a4d643e4832bf08efca01f00"}, "decimal": {:hex, :decimal, "2.0.0", "a78296e617b0f5dd4c6caf57c714431347912ffb1d0842e998e9792b5642d697", [:mix], [], "hexpm", "34666e9c55dea81013e77d9d87370fe6cb6291d1ef32f46a1600230b1d44f577"}, @@ -22,9 +22,9 @@ "distillery": {:hex, :distillery, "2.1.1", "f9332afc2eec8a1a2b86f22429e068ef35f84a93ea1718265e740d90dd367814", [:mix], [{:artificery, "~> 0.2", [hex: :artificery, repo: "hexpm", optional: false]}], "hexpm", "bbc7008b0161a6f130d8d903b5b3232351fccc9c31a991f8fcbf2a12ace22995"}, "ecto": {:hex, :ecto, "3.7.1", "a20598862351b29f80f285b21ec5297da1181c0442687f9b8329f0445d228892", [:mix], [{:decimal, "~> 1.6 or ~> 2.0", [hex: :decimal, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}, {:telemetry, "~> 0.4 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "d36e5b39fc479e654cffd4dbe1865d9716e4a9b6311faff799b6f90ab81b8638"}, "ecto_enum": {:hex, :ecto_enum, "1.4.0", "d14b00e04b974afc69c251632d1e49594d899067ee2b376277efd8233027aec8", [:mix], [{:ecto, ">= 3.0.0", [hex: :ecto, repo: "hexpm", optional: false]}, {:ecto_sql, "> 3.0.0", [hex: :ecto_sql, repo: "hexpm", optional: false]}, {:mariaex, ">= 0.0.0", [hex: :mariaex, repo: "hexpm", optional: true]}, {:postgrex, ">= 0.0.0", [hex: :postgrex, repo: "hexpm", optional: true]}], "hexpm", "8fb55c087181c2b15eee406519dc22578fa60dd82c088be376d0010172764ee4"}, - "ecto_sql": {:hex, :ecto_sql, "3.7.2", "55c60aa3a06168912abf145c6df38b0295c34118c3624cf7a6977cd6ce043081", [:mix], [{:db_connection, "~> 2.2", [hex: :db_connection, repo: "hexpm", optional: false]}, {:ecto, "~> 3.7.0", [hex: :ecto, repo: "hexpm", optional: false]}, {:myxql, "~> 0.4.0 or ~> 0.5.0 or ~> 0.6.0", [hex: :myxql, repo: "hexpm", optional: true]}, {:postgrex, "~> 0.15.0 or ~> 0.16.0 or ~> 1.0", [hex: :postgrex, repo: "hexpm", optional: true]}, {:tds, "~> 2.1.1 or ~> 2.2", [hex: :tds, repo: "hexpm", optional: true]}, {:telemetry, "~> 0.4.0 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "3c218ea62f305dcaef0b915fb56583195e7b91c91dcfb006ba1f669bfacbff2a"}, + "ecto_sql": {:hex, :ecto_sql, "3.7.1", "8de624ef50b2a8540252d8c60506379fbbc2707be1606853df371cf53df5d053", [:mix], [{:db_connection, "~> 2.2", [hex: :db_connection, repo: "hexpm", optional: false]}, {:ecto, "~> 3.7.0", [hex: :ecto, repo: "hexpm", optional: false]}, {:myxql, "~> 0.4.0 or ~> 0.5.0", [hex: :myxql, repo: "hexpm", optional: true]}, {:postgrex, "~> 0.15.0 or ~> 1.0", [hex: :postgrex, repo: "hexpm", optional: true]}, {:tds, "~> 2.1.1 or ~> 2.2", [hex: :tds, repo: "hexpm", optional: true]}, {:telemetry, "~> 0.4.0 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "2b42a32e2ce92f64aba5c88617891ab3b0ba34f3f3a503fa20009eae1a401c81"}, "erlex": {:hex, :erlex, "0.2.6", "c7987d15e899c7a2f34f5420d2a2ea0d659682c06ac607572df55a43753aa12e", [:mix], [], "hexpm", "2ed2e25711feb44d52b17d2780eabf998452f6efda104877a3881c2f8c0c0c75"}, - "ex_aws": {:hex, :ex_aws, "2.2.10", "064139724335b00b6665af7277189afc9ed507791b1ccf2698dadc7c8ad892e8", [:mix], [{:configparser_ex, "~> 4.0", [hex: :configparser_ex, repo: "hexpm", optional: true]}, {:hackney, "~> 1.16", [hex: :hackney, repo: "hexpm", optional: true]}, {:jason, "~> 1.1", [hex: :jason, repo: "hexpm", optional: true]}, {:jsx, "~> 2.8 or ~> 3.0", [hex: :jsx, repo: "hexpm", optional: true]}, {:mime, "~> 1.2 or ~> 2.0", [hex: :mime, repo: "hexpm", optional: false]}, {:sweet_xml, "~> 0.7", [hex: :sweet_xml, repo: "hexpm", optional: true]}, {:telemetry, "~> 0.4.3 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "98acb63f74b2f0822be219c5c2f0e8d243c2390f5325ad0557b014d3360da47e"}, + "ex_aws": {:hex, :ex_aws, "2.2.9", "295d2a9939315b2e27c92bde9615e2904d85442e5b59e259c4ee673e8a222c84", [:mix], [{:configparser_ex, "~> 4.0", [hex: :configparser_ex, repo: "hexpm", optional: true]}, {:hackney, "~> 1.16", [hex: :hackney, repo: "hexpm", optional: true]}, {:jason, "~> 1.1", [hex: :jason, repo: "hexpm", optional: true]}, {:jsx, "~> 2.8 or ~> 3.0", [hex: :jsx, repo: "hexpm", optional: true]}, {:mime, "~> 1.2 or ~> 2.0", [hex: :mime, repo: "hexpm", optional: false]}, {:sweet_xml, "~> 0.7", [hex: :sweet_xml, repo: "hexpm", optional: true]}, {:telemetry, "~> 0.4.3 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "f86e62f8c2a35c4536332b678a0edc18a9cd810d839cf1a9086f745ccf1fcc94"}, "ex_aws_lambda": {:hex, :ex_aws_lambda, "2.0.2", "77c749e4c4c36fb607639519a2e6b2037ec5986be52add632c1f5f5b9932089b", [:mix], [{:ex_aws, "~> 2.0", [hex: :ex_aws, repo: "hexpm", optional: false]}], "hexpm", "4e47a9b0bdd3ec993f812e6ef87ad8d1a652e4ffadb8d7c2632e90bd4a4d1fe2"}, "ex_aws_s3": {:hex, :ex_aws_s3, "2.3.2", "92a63b72d763b488510626d528775b26831f5c82b066a63a3128054b7a09de28", [:mix], [{:ex_aws, "~> 2.0", [hex: :ex_aws, repo: "hexpm", optional: false]}, {:sweet_xml, ">= 0.0.0", [hex: :sweet_xml, repo: "hexpm", optional: true]}], "hexpm", "b235b27131409bcc293c343bf39f1fbdd32892aa237b3f13752e914dc2979960"}, "ex_aws_secretsmanager": {:hex, :ex_aws_secretsmanager, "2.0.0", "deff8c12335f0160882afeb9687e55a97fddcd7d9a82fc3a6fbb270797374773", [:mix], [{:ex_aws, "~> 2.0", [hex: :ex_aws, repo: "hexpm", optional: false]}], "hexpm", "8b2838af536c32263ff797012b29e87bad73ef34f43cfa60ebca8e84576f6d45"}, @@ -35,15 +35,15 @@ "exactor": {:hex, :exactor, "2.2.4", "5efb4ddeb2c48d9a1d7c9b465a6fffdd82300eb9618ece5d34c3334d5d7245b1", [:mix], [], "hexpm", "1222419f706e01bfa1095aec9acf6421367dcfab798a6f67c54cf784733cd6b5"}, "excoveralls": {:hex, :excoveralls, "0.14.4", "295498f1ae47bdc6dce59af9a585c381e1aefc63298d48172efaaa90c3d251db", [:mix], [{:hackney, "~> 1.16", [hex: :hackney, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: false]}], "hexpm", "e3ab02f2df4c1c7a519728a6f0a747e71d7d6e846020aae338173619217931c1"}, "exjsx": {:hex, :exjsx, "4.0.0", "60548841e0212df401e38e63c0078ec57b33e7ea49b032c796ccad8cde794b5c", [:mix], [{:jsx, "~> 2.8.0", [hex: :jsx, repo: "hexpm", optional: false]}], "hexpm", "32e95820a97cffea67830e91514a2ad53b888850442d6d395f53a1ac60c82e07"}, - "exvcr": {:hex, :exvcr, "0.13.3", "fcd5f54ea0ebd41db7fe16701f3c67871d1b51c3c104ab88f11135a173d47134", [:mix], [{:exactor, "~> 2.2", [hex: :exactor, repo: "hexpm", optional: false]}, {:exjsx, "~> 4.0", [hex: :exjsx, repo: "hexpm", optional: false]}, {:finch, "~> 0.8", [hex: :finch, repo: "hexpm", optional: true]}, {:httpoison, "~> 1.0", [hex: :httpoison, repo: "hexpm", optional: true]}, {:httpotion, "~> 3.1", [hex: :httpotion, repo: "hexpm", optional: true]}, {:ibrowse, "4.4.0", [hex: :ibrowse, repo: "hexpm", optional: true]}, {:meck, "~> 0.8", [hex: :meck, repo: "hexpm", optional: false]}], "hexpm", "db61057447388b7adc4443a55047d11d09acc75eeb5548507c775a8402e02689"}, + "exvcr": {:hex, :exvcr, "0.13.2", "e17fd3ee3a341f41a3aa65a3ce73a339759a9d0658f83782492c6e9b6cf9daa4", [:mix], [{:exactor, "~> 2.2", [hex: :exactor, repo: "hexpm", optional: false]}, {:exjsx, "~> 4.0", [hex: :exjsx, repo: "hexpm", optional: false]}, {:finch, "~> 0.8.0", [hex: :finch, repo: "hexpm", optional: true]}, {:httpoison, "~> 1.0", [hex: :httpoison, repo: "hexpm", optional: true]}, {:httpotion, "~> 3.1", [hex: :httpotion, repo: "hexpm", optional: true]}, {:ibrowse, "4.4.0", [hex: :ibrowse, repo: "hexpm", optional: true]}, {:meck, "~> 0.8", [hex: :meck, repo: "hexpm", optional: false]}], "hexpm", "17f41a533d14f582fe6b5f83214f058cf5ba77c6a7bc15bc53a9ea1827d92d96"}, "faker": {:hex, :faker, "0.17.0", "671019d0652f63aefd8723b72167ecdb284baf7d47ad3a82a15e9b8a6df5d1fa", [:mix], [], "hexpm", "a7d4ad84a93fd25c5f5303510753789fc2433ff241bf3b4144d3f6f291658a6a"}, "file_system": {:hex, :file_system, "0.2.10", "fb082005a9cd1711c05b5248710f8826b02d7d1784e7c3451f9c1231d4fc162d", [:mix], [], "hexpm", "41195edbfb562a593726eda3b3e8b103a309b733ad25f3d642ba49696bf715dc"}, "gen_stage": {:hex, :gen_stage, "1.1.2", "b1656cd4ba431ed02c5656fe10cb5423820847113a07218da68eae5d6a260c23", [:mix], [], "hexpm", "9e39af23140f704e2b07a3e29d8f05fd21c2aaf4088ff43cb82be4b9e3148d02"}, - "gettext": {:hex, :gettext, "0.19.1", "564953fd21f29358e68b91634799d9d26989f8d039d7512622efb3c3b1c97892", [:mix], [], "hexpm", "10c656c0912b8299adba9b061c06947511e3f109ab0d18b44a866a4498e77222"}, - "git_hooks": {:hex, :git_hooks, "0.7.1", "58ae0e5a0d1443fe7e6ce36ca6b44b2b36bd680bc3d3568321ca057d2eaf9f3c", [:mix], [{:blankable, "~> 1.0.0", [hex: :blankable, repo: "hexpm", optional: false]}, {:recase, "~> 0.7.0", [hex: :recase, repo: "hexpm", optional: false]}], "hexpm", "b06f0166ccd0a4ac56126df294b853aba138400d4b947cc03198481fa49780fe"}, + "gettext": {:hex, :gettext, "0.19.0", "6909d61b38bb33339558f128f8af5913d5d5fe304a770217bf352b1620fb7ec4", [:mix], [], "hexpm", "3f7a274f52ebda9bb6655dfeda3d6b0dc4537ae51ce41dcccc7f73ca7379ad5e"}, + "git_hooks": {:hex, :git_hooks, "0.6.4", "a20757c39b2b9ab75d894fc3eaed8fbb1c45e207fd19f12f45fe9b5327910817", [:mix], [{:blankable, "~> 1.0.0", [hex: :blankable, repo: "hexpm", optional: false]}, {:recase, "~> 0.7.0", [hex: :recase, repo: "hexpm", optional: false]}], "hexpm", "a44c76f3d7bdaf885d6f0bf5b3f3e86922b5edf28ee2e6235aa6e561bf172b1c"}, "guardian": {:hex, :guardian, "2.2.1", "5a4a949fd46eac79ef37f074ada7d1ef82e274bc99e335c286e042f5383f4f80", [:mix], [{:jose, "~> 1.8", [hex: :jose, repo: "hexpm", optional: false]}, {:plug, "~> 1.3.3 or ~> 1.4", [hex: :plug, repo: "hexpm", optional: true]}], "hexpm", "09b5c4d08f18524bd33ffe49617003cbca9f617237e23b5f42223cda61c5f052"}, "guardian_db": {:hex, :guardian_db, "2.1.0", "ec95a9d99cdd1e550555d09a7bb4a340d8887aad0697f594590c2fd74be02426", [:mix], [{:ecto, "~> 3.0", [hex: :ecto, repo: "hexpm", optional: false]}, {:ecto_sql, "~> 3.1", [hex: :ecto_sql, repo: "hexpm", optional: false]}, {:guardian, "~> 1.0 or ~> 2.0", [hex: :guardian, repo: "hexpm", optional: false]}, {:postgrex, "~> 0.13", [hex: :postgrex, repo: "hexpm", optional: true]}], "hexpm", "f8e7d543ac92c395f3a7fd5acbe6829faeade57d688f7562e2f0fca8f94a0d70"}, - "hackney": {:hex, :hackney, "1.18.1", "f48bf88f521f2a229fc7bae88cf4f85adc9cd9bcf23b5dc8eb6a1788c662c4f6", [:rebar3], [{:certifi, "~>2.9.0", [hex: :certifi, repo: "hexpm", optional: false]}, {:idna, "~>6.1.0", [hex: :idna, repo: "hexpm", optional: false]}, {:metrics, "~>1.0.0", [hex: :metrics, repo: "hexpm", optional: false]}, {:mimerl, "~>1.1", [hex: :mimerl, repo: "hexpm", optional: false]}, {:parse_trans, "3.3.1", [hex: :parse_trans, repo: "hexpm", optional: false]}, {:ssl_verify_fun, "~>1.1.0", [hex: :ssl_verify_fun, repo: "hexpm", optional: false]}, {:unicode_util_compat, "~>0.7.0", [hex: :unicode_util_compat, repo: "hexpm", optional: false]}], "hexpm", "a4ecdaff44297e9b5894ae499e9a070ea1888c84afdd1fd9b7b2bc384950128e"}, + "hackney": {:hex, :hackney, "1.18.0", "c4443d960bb9fba6d01161d01cd81173089686717d9490e5d3606644c48d121f", [:rebar3], [{:certifi, "~>2.8.0", [hex: :certifi, repo: "hexpm", optional: false]}, {:idna, "~>6.1.0", [hex: :idna, repo: "hexpm", optional: false]}, {:metrics, "~>1.0.0", [hex: :metrics, repo: "hexpm", optional: false]}, {:mimerl, "~>1.1", [hex: :mimerl, repo: "hexpm", optional: false]}, {:parse_trans, "3.3.1", [hex: :parse_trans, repo: "hexpm", optional: false]}, {:ssl_verify_fun, "~>1.1.0", [hex: :ssl_verify_fun, repo: "hexpm", optional: false]}, {:unicode_util_compat, "~>0.7.0", [hex: :unicode_util_compat, repo: "hexpm", optional: false]}], "hexpm", "9afcda620704d720db8c6a3123e9848d09c87586dc1c10479c42627b905b5c5e"}, "httpoison": {:hex, :httpoison, "1.8.0", "6b85dea15820b7804ef607ff78406ab449dd78bed923a49c7160e1886e987a3d", [:mix], [{:hackney, "~> 1.17", [hex: :hackney, repo: "hexpm", optional: false]}], "hexpm", "28089eaa98cf90c66265b6b5ad87c59a3729bea2e74e9d08f9b51eb9729b3c3a"}, "idna": {:hex, :idna, "6.1.1", "8a63070e9f7d0c62eb9d9fcb360a7de382448200fbbd1b106cc96d3d8099df8d", [:rebar3], [{:unicode_util_compat, "~>0.7.0", [hex: :unicode_util_compat, repo: "hexpm", optional: false]}], "hexpm", "92376eb7894412ed19ac475e4a86f7b413c1b9fbb5bd16dccd57934157944cea"}, "inch_ex": {:hex, :inch_ex, "2.1.0-rc.1", "7642a8902c0d2ed5d9b5754b2fc88fedf630500d630fc03db7caca2e92dedb36", [:mix], [{:bunt, "~> 0.2", [hex: :bunt, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: false]}], "hexpm", "4ceee988760f9382d1c1d0b93ea5875727f6071693e89a0a3c49c456ef1be75d"}, @@ -63,11 +63,11 @@ "phoenix_ecto": {:hex, :phoenix_ecto, "4.4.0", "0672ed4e4808b3fbed494dded89958e22fb882de47a97634c0b13e7b0b5f7720", [:mix], [{:ecto, "~> 3.3", [hex: :ecto, repo: "hexpm", optional: false]}, {:phoenix_html, "~> 2.14.2 or ~> 3.0", [hex: :phoenix_html, repo: "hexpm", optional: true]}, {:plug, "~> 1.9", [hex: :plug, repo: "hexpm", optional: false]}], "hexpm", "09864e558ed31ee00bd48fcc1d4fc58ae9678c9e81649075431e69dbabb43cc1"}, "phoenix_pubsub": {:hex, :phoenix_pubsub, "2.0.0", "a1ae76717bb168cdeb10ec9d92d1480fec99e3080f011402c0a2d68d47395ffb", [:mix], [], "hexpm", "c52d948c4f261577b9c6fa804be91884b381a7f8f18450c5045975435350f771"}, "phoenix_swagger": {:hex, :phoenix_swagger, "0.8.3", "298d6204802409d3b0b4fc1013873839478707cf3a62532a9e10fec0e26d0e37", [:mix], [{:ex_json_schema, "~> 0.7.1", [hex: :ex_json_schema, repo: "hexpm", optional: true]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}, {:plug, "~> 1.11", [hex: :plug, repo: "hexpm", optional: false]}, {:poison, "~> 2.2 or ~> 3.0", [hex: :poison, repo: "hexpm", optional: true]}], "hexpm", "3bc0fa9f5b679b8a61b90a52b2c67dd932320e9a84a6f91a4af872a0ab367337"}, - "phoenix_view": {:hex, :phoenix_view, "1.1.2", "1b82764a065fb41051637872c7bd07ed2fdb6f5c3bd89684d4dca6e10115c95a", [:mix], [{:phoenix_html, "~> 2.14.2 or ~> 3.0", [hex: :phoenix_html, repo: "hexpm", optional: true]}], "hexpm", "7ae90ad27b09091266f6adbb61e1d2516a7c3d7062c6789d46a7554ec40f3a56"}, - "plug": {:hex, :plug, "1.13.3", "93b299039c21a8b82cc904d13812bce4ced45cf69153e8d35ca16ffb3e8c5d98", [:mix], [{:mime, "~> 1.0 or ~> 2.0", [hex: :mime, repo: "hexpm", optional: false]}, {:plug_crypto, "~> 1.1.1 or ~> 1.2", [hex: :plug_crypto, repo: "hexpm", optional: false]}, {:telemetry, "~> 0.4.3 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "98c8003e4faf7b74a9ac41bee99e328b08f069bf932747d4a7532e97ae837a17"}, + "phoenix_view": {:hex, :phoenix_view, "1.1.0", "149f053830ec3c19a2a8a67c208885a26e4c2b92cc4a9d54e03b633d68ef9add", [:mix], [{:phoenix_html, "~> 2.14.2 or ~> 3.0", [hex: :phoenix_html, repo: "hexpm", optional: true]}], "hexpm", "dd219f768b3d97a224ed11e8a83f4fd0f3bd490434d3950d7c51a2e597a762f1"}, + "plug": {:hex, :plug, "1.12.1", "645678c800601d8d9f27ad1aebba1fdb9ce5b2623ddb961a074da0b96c35187d", [:mix], [{:mime, "~> 1.0 or ~> 2.0", [hex: :mime, repo: "hexpm", optional: false]}, {:plug_crypto, "~> 1.1.1 or ~> 1.2", [hex: :plug_crypto, repo: "hexpm", optional: false]}, {:telemetry, "~> 0.4.3 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "d57e799a777bc20494b784966dc5fbda91eb4a09f571f76545b72a634ce0d30b"}, "plug_cowboy": {:hex, :plug_cowboy, "2.5.2", "62894ccd601cf9597e2c23911ff12798a8a18d237e9739f58a6b04e4988899fe", [:mix], [{:cowboy, "~> 2.7", [hex: :cowboy, repo: "hexpm", optional: false]}, {:cowboy_telemetry, "~> 0.3", [hex: :cowboy_telemetry, repo: "hexpm", optional: false]}, {:plug, "~> 1.7", [hex: :plug, repo: "hexpm", optional: false]}], "hexpm", "ea6e87f774c8608d60c8d34022a7d073bd7680a0a013f049fc62bf35efea1044"}, "plug_crypto": {:hex, :plug_crypto, "1.2.2", "05654514ac717ff3a1843204b424477d9e60c143406aa94daf2274fdd280794d", [:mix], [], "hexpm", "87631c7ad914a5a445f0a3809f99b079113ae4ed4b867348dd9eec288cecb6db"}, - "postgrex": {:hex, :postgrex, "0.16.2", "0f83198d0e73a36e8d716b90f45f3bde75b5eebf4ade4f43fa1f88c90a812f74", [:mix], [{:connection, "~> 1.1", [hex: :connection, repo: "hexpm", optional: false]}, {:db_connection, "~> 2.1", [hex: :db_connection, repo: "hexpm", optional: false]}, {:decimal, "~> 1.5 or ~> 2.0", [hex: :decimal, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}], "hexpm", "a9ea589754d9d4d076121090662b7afe155b374897a6550eb288f11d755acfa0"}, + "postgrex": {:hex, :postgrex, "0.15.13", "7794e697481799aee8982688c261901de493eb64451feee6ea58207d7266d54a", [:mix], [{:connection, "~> 1.0", [hex: :connection, repo: "hexpm", optional: false]}, {:db_connection, "~> 2.1", [hex: :db_connection, repo: "hexpm", optional: false]}, {:decimal, "~> 1.5 or ~> 2.0", [hex: :decimal, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}], "hexpm", "3ffb76e1a97cfefe5c6a95632a27ffb67f28871c9741fb585f9d1c3cd2af70f1"}, "quantum": {:hex, :quantum, "3.4.0", "5a53c3c52b0d55f2323940232ba6ab4c98e7e14c73dfacbba3a1ed799b037ce5", [:mix], [{:crontab, "~> 1.1", [hex: :crontab, repo: "hexpm", optional: false]}, {:gen_stage, "~> 0.14 or ~> 1.0", [hex: :gen_stage, repo: "hexpm", optional: false]}, {:telemetry, "~> 0.4.3 or ~> 1.0.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "d0eb64957d3dc49c8ed730cc2203108334226496535965b8dfa3f3dbcf430f87"}, "que": {:hex, :que, "0.10.1", "788ed0ec92ed69bdf9cfb29bf41a94ca6355b8d44959bd0669cf706e557ac891", [:mix], [{:ex_utils, "~> 0.1.6", [hex: :ex_utils, repo: "hexpm", optional: false]}, {:memento, "~> 0.3.0", [hex: :memento, repo: "hexpm", optional: false]}], "hexpm", "a737b365253e75dbd24b2d51acc1d851049e87baae08cd0c94e2bc5cd65088d5"}, "ranch": {:hex, :ranch, "1.8.0", "8c7a100a139fd57f17327b6413e4167ac559fbc04ca7448e9be9057311597a1d", [:make, :rebar3], [], "hexpm", "49fbcfd3682fab1f5d109351b61257676da1a2fdbe295904176d5e521a2ddfe5"}, From ac0376e713b01fc28800fbf18c094ce0cb55df9b Mon Sep 17 00:00:00 2001 From: ShenyiCui Date: Wed, 23 Mar 2022 02:34:39 +0800 Subject: [PATCH 14/25] Fix total_xp query - Calculate total xp through a single query. - Fix variable issues in user_controller --- lib/cadet/incentives/achievements.ex | 63 +++++++++++--------- lib/cadet_web/controllers/user_controller.ex | 20 +++---- 2 files changed, 43 insertions(+), 40 deletions(-) diff --git a/lib/cadet/incentives/achievements.ex b/lib/cadet/incentives/achievements.ex index ae92a56bf..2ec4e732a 100644 --- a/lib/cadet/incentives/achievements.ex +++ b/lib/cadet/incentives/achievements.ex @@ -5,9 +5,12 @@ defmodule Cadet.Incentives.Achievements do use Cadet, [:context, :display] alias Cadet.Incentives.Achievement + alias Cadet.Incentives.GoalProgress import Ecto.Query + require Decimal + @doc """ Returns all achievements. @@ -23,38 +26,42 @@ defmodule Cadet.Incentives.Achievements do @doc """ Returns a user's total xp from their completed achievements. - - This returns Achievement structs with prerequisites, goal association and progress maps pre-loaded. """ - def achievements_total_xp(course_id, user_id) when is_ecto_id(course_id) do - achievements = + def achievements_total_xp(course_id, course_reg_id) when is_ecto_id(course_id) do + xp = Achievement - |> where(course_id: ^course_id) - |> preload([:prerequisites, goals: [goal: [progress: :course_reg]]]) - |> Repo.all() - - is_goal_completed = fn goal_item -> - if Enum.count(goal_item.goal.progress) != 0, - do: - Enum.at(goal_item.goal.progress, 0).completed and - user_id == Enum.at(goal_item.goal.progress, 0).course_reg.user_id and - Enum.at(goal_item.goal.progress, 0).count == goal_item.goal.meta["targetCount"], - else: false - end + |> join(:inner, [a], j in assoc(a, :goals)) + |> join(:inner, [_, j], g in assoc(j, :goal)) + |> join(:left, [_, _, g], p in GoalProgress, + on: p.goal_uuid == g.uuid and p.course_reg_id == ^course_reg_id + ) + |> where([a, j, g, p], a.course_id == ^course_id) + |> group_by([a, j, g, p], a.uuid) + |> having( + [a, j, g, p], + fragment( + "bool_and(?)", + p.completed and p.count == g.target_count and not is_nil(p.course_reg_id) + ) + ) + # this max is a dummy - simply because a.xp is not under the GROUP BY + |> select([a, j, g, p], %{ + xp: fragment("CASE WHEN bool_and(is_variable_xp) THEN SUM(count) ELSE MAX(xp) END") + }) + |> subquery() + |> select([s], sum(s.xp)) + |> Repo.one() + |> decimal_to_integer() - Enum.reduce(achievements, 0, fn achievement_item, acc -> - completed_goals = - if Enum.count(achievement_item.goals) != 0, - do: - Enum.reduce_while(achievement_item.goals, 1, fn goal_item, acc -> - if is_goal_completed.(goal_item), - do: {:cont, acc}, - else: {:halt, 0} - end), - else: 0 + xp + end - acc + completed_goals * achievement_item.xp - end) + defp decimal_to_integer(decimal) do + if Decimal.is_decimal(decimal) do + Decimal.to_integer(decimal) + else + 0 + end end @spec upsert(map()) :: {:ok, Achievement.t()} | {:error, {:bad_request, String.t()}} diff --git a/lib/cadet_web/controllers/user_controller.ex b/lib/cadet_web/controllers/user_controller.ex index ca5391c3f..f7f6bad71 100644 --- a/lib/cadet_web/controllers/user_controller.ex +++ b/lib/cadet_web/controllers/user_controller.ex @@ -115,18 +115,14 @@ defmodule CadetWeb.UserController do def combined_total_xp(conn, _) do course_id = conn.assigns.course_reg.course_id - user = conn.assigns.current_user - - if user.latest_viewed_course_id do - latest = CourseRegistrations.get_user_course(user.id, user.latest_viewed_course_id) - total_achievement_xp = Achievements.achievements_total_xp(course_id, user.id) - total_assessment_xp = Assessments.user_total_xp(latest) - - total_xp = total_assessment_xp + total_achievement_xp - json(conn, %{totalXp: total_xp}) - else - json(conn, %{totalXp: "an error has occured"}) - end + user_id = conn.assigns.course_reg.user_id + course_reg_id = conn.assigns.course_reg.id + user_course = CourseRegistrations.get_user_course(user_id, course_id) + + total_achievement_xp = Achievements.achievements_total_xp(course_id, course_reg_id) + total_assessment_xp = Assessments.user_total_xp(user_course) + total_xp = total_achievement_xp + total_assessment_xp + json(conn, %{totalXp: total_xp}) end swagger_path :index do From a40c88ba26c6013770a3e5d617bf578bfff157c2 Mon Sep 17 00:00:00 2001 From: Richard Qi <55354921+riccqi@users.noreply.github.com> Date: Thu, 24 Mar 2022 01:16:19 +0800 Subject: [PATCH 15/25] Fix credo formatting errors --- lib/cadet/incentives/achievements.ex | 3 +-- lib/cadet_web/controllers/user_controller.ex | 4 ++-- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/lib/cadet/incentives/achievements.ex b/lib/cadet/incentives/achievements.ex index 2ec4e732a..cf7b4ae25 100644 --- a/lib/cadet/incentives/achievements.ex +++ b/lib/cadet/incentives/achievements.ex @@ -4,8 +4,7 @@ defmodule Cadet.Incentives.Achievements do """ use Cadet, [:context, :display] - alias Cadet.Incentives.Achievement - alias Cadet.Incentives.GoalProgress + alias Cadet.Incentives.{Achievement, GoalProgress} import Ecto.Query diff --git a/lib/cadet_web/controllers/user_controller.ex b/lib/cadet_web/controllers/user_controller.ex index f7f6bad71..2a3633d19 100644 --- a/lib/cadet_web/controllers/user_controller.ex +++ b/lib/cadet_web/controllers/user_controller.ex @@ -5,11 +5,11 @@ defmodule CadetWeb.UserController do use CadetWeb, :controller use PhoenixSwagger - alias Cadet.Assessments alias Cadet.Incentives.Achievements - alias Cadet.Accounts alias Cadet.Accounts.CourseRegistrations + alias Cadet.{Accounts, Assessments} + def index(conn, _) do user = conn.assigns.current_user courses = CourseRegistrations.get_courses(conn.assigns.current_user) From 5ed7bdfe8c994360aec60d3c4eb87055689043af Mon Sep 17 00:00:00 2001 From: Richard Qi <55354921+riccqi@users.noreply.github.com> Date: Fri, 25 Mar 2022 01:04:13 +0800 Subject: [PATCH 16/25] Add swagger path for combined_total_xp Fixes some other user route issues --- lib/cadet_web/controllers/user_controller.ex | 35 +++++++++++++++++--- 1 file changed, 30 insertions(+), 5 deletions(-) diff --git a/lib/cadet_web/controllers/user_controller.ex b/lib/cadet_web/controllers/user_controller.ex index 2a3633d19..f366b0d18 100644 --- a/lib/cadet_web/controllers/user_controller.ex +++ b/lib/cadet_web/controllers/user_controller.ex @@ -126,7 +126,7 @@ defmodule CadetWeb.UserController do end swagger_path :index do - get("/v2/user") + get("/user") summary("Get the name, and latest_viewed_course of a user") @@ -137,7 +137,7 @@ defmodule CadetWeb.UserController do end swagger_path :get_latest_viewed do - get("/v2/user/latest_viewed_course") + get("/user/latest_viewed_course") summary("Get the latest_viewed_course of a user") @@ -148,7 +148,7 @@ defmodule CadetWeb.UserController do end swagger_path :update_latest_viewed do - put("/v2/user/latest_viewed_course") + put("/user/latest_viewed_course") summary("Update user's latest viewed course") security([%{JWT: []}]) consumes("application/json") @@ -161,7 +161,7 @@ defmodule CadetWeb.UserController do end swagger_path :update_game_states do - put("/v2/courses/:course_id/user/game_states") + put("/courses/:course_id/user/game_states") summary("Update user's game states") security([%{JWT: []}]) consumes("application/json") @@ -174,7 +174,7 @@ defmodule CadetWeb.UserController do end swagger_path :update_research_agreement do - put("/v2/courses/:course_id/user/research_agreement") + put("/courses/:course_id/user/research_agreement") summary("Update the user's agreement to the anonymized collection of programs for research") security([%{JWT: []}]) consumes("application/json") @@ -194,6 +194,22 @@ defmodule CadetWeb.UserController do response(400, "Bad Request") end + swagger_path :combined_total_xp do + get("/courses/{courseId}/user/total_xp") + + summary("Get the total xp from achievements and assessments of a user in a specific course") + + security([%{JWT: []}]) + produces("application/json") + + parameters do + courseId(:path, :integer, "Course Id", required: true) + end + + response(200, "OK", Schema.ref(:TotalXPInfo)) + response(401, "Unauthorised") + end + def swagger_definitions do %{ IndexInfo: @@ -215,6 +231,15 @@ defmodule CadetWeb.UserController do ) end end, + TotalXPInfo: + swagger_schema do + title("User Total XP") + description("total xp of the user") + + properties do + totalXp(:integer, "total xp") + end + end, LatestViewedInfo: swagger_schema do title("Latest viewed course") From fabbdabc3f593e381008e39b87072d0a1558499d Mon Sep 17 00:00:00 2001 From: Richard Qi <55354921+riccqi@users.noreply.github.com> Date: Thu, 31 Mar 2022 01:55:35 +0800 Subject: [PATCH 17/25] Add normal test for total_xp route Add test --- .../controllers/user_controller_test.exs | 125 ++++++++++++++++++ 1 file changed, 125 insertions(+) diff --git a/test/cadet_web/controllers/user_controller_test.exs b/test/cadet_web/controllers/user_controller_test.exs index 8867ddb76..af5a5cb13 100644 --- a/test/cadet_web/controllers/user_controller_test.exs +++ b/test/cadet_web/controllers/user_controller_test.exs @@ -4,6 +4,7 @@ defmodule CadetWeb.UserControllerTest do import Ecto.Query import Cadet.Factory + import Cadet.TestEntityHelper alias CadetWeb.UserController # alias Cadet.Assessments.{Assessment, Submission} alias Cadet.Accounts.{User, CourseRegistration} @@ -173,6 +174,130 @@ defmodule CadetWeb.UserControllerTest do end end + describe "GET /v2/courses/{course_id}/user/total_xp" do + @tag authenticate: :student, group: true + test "normal addition of completed assessment and achievement with completed goal", %{ + conn: conn + } do + test_cr = conn.assigns.test_cr + course = conn.assigns.test_cr.course + + assessment = insert(:assessment, %{is_published: true, course: course}) + question = insert(:question, %{assessment: assessment}) + + submission = + insert(:submission, %{ + assessment: assessment, + student: test_cr, + status: :submitted, + xp_bonus: 100 + }) + + insert(:answer, %{ + question: question, + submission: submission, + xp: 20, + xp_adjustment: -10 + }) + + goal = + insert( + :goal, + Map.merge( + goal_literal(1), + %{ + course: course, + progress: [ + %{ + count: 1, + completed: true, + course_reg_id: test_cr.id + } + ] + } + ) + ) + + insert(:achievement, %{ + course: course, + title: "Rune Master", + is_task: true, + position: 1, + xp: 100, + card_tile_url: + "https://source-academy-assets.s3-ap-southeast-1.amazonaws.com/achievement/card-tile/rune-master-tile.png", + goals: [ + %{goal_uuid: goal.uuid} + ] + }) + + resp = + conn + |> get("/v2/courses/#{course.id}/user/total_xp") + |> json_response(200) + + assert resp["totalXp"] == 210 + end + + # test "success", %{conn: conn} do + # user = conn.assigns.current_user + # course = user.latest_viewed_course + + # cr = + # CourseRegistration + # |> preload(:group) + # |> Repo.get_by(course_id: course.id, user_id: user.id) + + # another_cr = insert(:course_registration, %{user: user, role: :admin}) + # assessment = insert(:assessment, %{is_published: true, course: course}) + # question = insert(:question, %{assessment: assessment}) + + # submission = + # insert(:submission, %{ + # assessment: assessment, + # student: cr, + # status: :submitted, + # xp_bonus: 100 + # }) + + # insert(:answer, %{ + # question: question, + # submission: submission, + # xp: 20, + # xp_adjustment: -10 + # }) + + # not_submitted_assessment = insert(:assessment, %{is_published: true, course: course}) + # not_submitted_question = insert(:question, assessment: not_submitted_assessment) + + # not_submitted_submission = + # insert(:submission, %{assessment: not_submitted_assessment, student: cr}) + + # insert( + # :answer, + # question: not_submitted_question, + # submission: not_submitted_submission + # ) + + # resp = + # conn + # |> get("/v2/courses/#{course.id}/user/total_xp") + # |> json_response(200) + + # expected = %{ + # "totalXp" => 110 + # } + + # assert expected == resp + # end + + # test "unauthorized", %{conn: conn} do + # conn = get(conn, "/v2/courses/1/user/total_xp", nil) + # assert response(conn, 401) =~ "Unauthorised" + # end + end + + # REFERENCE THIS describe "GET /v2/user/latest_viewed_course" do @tag authenticate: :student, group: true test "success, student non-story fields", %{conn: conn} do From 03c177546e17c99996a24eb8e04957f21ad079bf Mon Sep 17 00:00:00 2001 From: Richard Qi <55354921+riccqi@users.noreply.github.com> Date: Thu, 31 Mar 2022 01:59:36 +0800 Subject: [PATCH 18/25] Update user_controller_test.exs --- test/cadet_web/controllers/user_controller_test.exs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/cadet_web/controllers/user_controller_test.exs b/test/cadet_web/controllers/user_controller_test.exs index af5a5cb13..0743c88ab 100644 --- a/test/cadet_web/controllers/user_controller_test.exs +++ b/test/cadet_web/controllers/user_controller_test.exs @@ -5,8 +5,8 @@ defmodule CadetWeb.UserControllerTest do import Cadet.Factory import Cadet.TestEntityHelper + alias CadetWeb.UserController - # alias Cadet.Assessments.{Assessment, Submission} alias Cadet.Accounts.{User, CourseRegistration} alias Cadet.{Repo, Courses} From 3bfc6ba075239286322945d5f0ebebef29110bcb Mon Sep 17 00:00:00 2001 From: Richard Qi <55354921+riccqi@users.noreply.github.com> Date: Thu, 31 Mar 2022 02:28:05 +0800 Subject: [PATCH 19/25] Fix imports --- test/cadet_web/controllers/user_controller_test.exs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/test/cadet_web/controllers/user_controller_test.exs b/test/cadet_web/controllers/user_controller_test.exs index 0743c88ab..dab1842c8 100644 --- a/test/cadet_web/controllers/user_controller_test.exs +++ b/test/cadet_web/controllers/user_controller_test.exs @@ -2,9 +2,8 @@ defmodule CadetWeb.UserControllerTest do use CadetWeb.ConnCase import Ecto.Query - import Cadet.Factory - import Cadet.TestEntityHelper + import Cadet.{Factory, TestEntityHelper} alias CadetWeb.UserController alias Cadet.Accounts.{User, CourseRegistration} From dc0a36e973550e37e3db8189dfe3c61fd37dea13 Mon Sep 17 00:00:00 2001 From: Richard Qi <55354921+riccqi@users.noreply.github.com> Date: Thu, 31 Mar 2022 23:58:42 +0800 Subject: [PATCH 20/25] Add more tests for total_xp route --- .../controllers/user_controller_test.exs | 346 +++++++++++++++--- 1 file changed, 289 insertions(+), 57 deletions(-) diff --git a/test/cadet_web/controllers/user_controller_test.exs b/test/cadet_web/controllers/user_controller_test.exs index dab1842c8..67c1d012f 100644 --- a/test/cadet_web/controllers/user_controller_test.exs +++ b/test/cadet_web/controllers/user_controller_test.exs @@ -175,7 +175,7 @@ defmodule CadetWeb.UserControllerTest do describe "GET /v2/courses/{course_id}/user/total_xp" do @tag authenticate: :student, group: true - test "normal addition of completed assessment and achievement with completed goal", %{ + test "addition of assessment and achievement with completed goal", %{ conn: conn } do test_cr = conn.assigns.test_cr @@ -221,6 +221,7 @@ defmodule CadetWeb.UserControllerTest do course: course, title: "Rune Master", is_task: true, + is_variable_xp: false, position: 1, xp: 100, card_tile_url: @@ -238,62 +239,293 @@ defmodule CadetWeb.UserControllerTest do assert resp["totalXp"] == 210 end - # test "success", %{conn: conn} do - # user = conn.assigns.current_user - # course = user.latest_viewed_course - - # cr = - # CourseRegistration - # |> preload(:group) - # |> Repo.get_by(course_id: course.id, user_id: user.id) - - # another_cr = insert(:course_registration, %{user: user, role: :admin}) - # assessment = insert(:assessment, %{is_published: true, course: course}) - # question = insert(:question, %{assessment: assessment}) - - # submission = - # insert(:submission, %{ - # assessment: assessment, - # student: cr, - # status: :submitted, - # xp_bonus: 100 - # }) - - # insert(:answer, %{ - # question: question, - # submission: submission, - # xp: 20, - # xp_adjustment: -10 - # }) - - # not_submitted_assessment = insert(:assessment, %{is_published: true, course: course}) - # not_submitted_question = insert(:question, assessment: not_submitted_assessment) - - # not_submitted_submission = - # insert(:submission, %{assessment: not_submitted_assessment, student: cr}) - - # insert( - # :answer, - # question: not_submitted_question, - # submission: not_submitted_submission - # ) - - # resp = - # conn - # |> get("/v2/courses/#{course.id}/user/total_xp") - # |> json_response(200) - - # expected = %{ - # "totalXp" => 110 - # } - - # assert expected == resp - # end - - # test "unauthorized", %{conn: conn} do - # conn = get(conn, "/v2/courses/1/user/total_xp", nil) - # assert response(conn, 401) =~ "Unauthorised" - # end + @tag authenticate: :student, group: true + test "addition of assessment and achievement with incomplete goal", %{ + conn: conn + } do + test_cr = conn.assigns.test_cr + course = conn.assigns.test_cr.course + + assessment = insert(:assessment, %{is_published: true, course: course}) + question = insert(:question, %{assessment: assessment}) + + submission = + insert(:submission, %{ + assessment: assessment, + student: test_cr, + status: :submitted, + xp_bonus: 100 + }) + + insert(:answer, %{ + question: question, + submission: submission, + xp: 20, + xp_adjustment: -10 + }) + + goal = + insert( + :goal, + Map.merge( + goal_literal(1), + %{ + course: course, + progress: [ + %{ + count: 0, + completed: true, + course_reg_id: test_cr.id + } + ] + } + ) + ) + + insert(:achievement, %{ + course: course, + title: "Rune Master", + is_task: true, + is_variable_xp: false, + position: 1, + xp: 100, + card_tile_url: + "https://source-academy-assets.s3-ap-southeast-1.amazonaws.com/achievement/card-tile/rune-master-tile.png", + goals: [ + %{goal_uuid: goal.uuid} + ] + }) + + resp = + conn + |> get("/v2/courses/#{course.id}/user/total_xp") + |> json_response(200) + + assert resp["totalXp"] == 110 + end + + @tag authenticate: :student, group: true + test "addition of assessment and achievement with one completed, one incomplete goal", + %{ + conn: conn + } do + test_cr = conn.assigns.test_cr + course = conn.assigns.test_cr.course + + assessment = insert(:assessment, %{is_published: true, course: course}) + question = insert(:question, %{assessment: assessment}) + + submission = + insert(:submission, %{ + assessment: assessment, + student: test_cr, + status: :submitted, + xp_bonus: 100 + }) + + insert(:answer, %{ + question: question, + submission: submission, + xp: 20, + xp_adjustment: -10 + }) + + goal_complete = + insert( + :goal, + Map.merge( + goal_literal(1), + %{ + course: course, + progress: [ + %{ + count: 1, + completed: true, + course_reg_id: test_cr.id + } + ] + } + ) + ) + + goal_incomplete = + insert( + :goal, + Map.merge( + goal_literal(1), + %{ + course: course, + progress: [ + %{ + count: 0, + completed: true, + course_reg_id: test_cr.id + } + ] + } + ) + ) + + insert(:achievement, %{ + course: course, + title: "Rune Master", + is_task: true, + is_variable_xp: false, + position: 1, + xp: 100, + card_tile_url: + "https://source-academy-assets.s3-ap-southeast-1.amazonaws.com/achievement/card-tile/rune-master-tile.png", + goals: [ + %{goal_uuid: goal_complete.uuid}, + %{goal_uuid: goal_incomplete.uuid} + ] + }) + + resp = + conn + |> get("/v2/courses/#{course.id}/user/total_xp") + |> json_response(200) + + assert resp["totalXp"] == 110 + end + + @tag authenticate: :student, group: true + test "addition of assessment and achievement with goal w/o progress entry", %{ + conn: conn + } do + test_cr = conn.assigns.test_cr + course = conn.assigns.test_cr.course + + assessment = insert(:assessment, %{is_published: true, course: course}) + question = insert(:question, %{assessment: assessment}) + + submission = + insert(:submission, %{ + assessment: assessment, + student: test_cr, + status: :submitted, + xp_bonus: 100 + }) + + insert(:answer, %{ + question: question, + submission: submission, + xp: 20, + xp_adjustment: -10 + }) + + goal = + insert( + :goal, + Map.merge( + goal_literal(1), + %{ + course: course + } + ) + ) + + insert(:achievement, %{ + course: course, + title: "Rune Master", + is_task: true, + is_variable_xp: false, + position: 1, + xp: 100, + card_tile_url: + "https://source-academy-assets.s3-ap-southeast-1.amazonaws.com/achievement/card-tile/rune-master-tile.png", + goals: [ + %{goal_uuid: goal.uuid} + ] + }) + + resp = + conn + |> get("/v2/courses/#{course.id}/user/total_xp") + |> json_response(200) + + assert resp["totalXp"] == 110 + end + + @tag authenticate: :student, group: true + test "addition of no assessments and achievement with completed goal", %{ + conn: conn + } do + test_cr = conn.assigns.test_cr + course = conn.assigns.test_cr.course + + goal = + insert( + :goal, + Map.merge( + goal_literal(1), + %{ + course: course, + progress: [ + %{ + count: 1, + completed: true, + course_reg_id: test_cr.id + } + ] + } + ) + ) + + insert(:achievement, %{ + course: course, + title: "Rune Master", + is_task: true, + is_variable_xp: false, + position: 1, + xp: 100, + card_tile_url: + "https://source-academy-assets.s3-ap-southeast-1.amazonaws.com/achievement/card-tile/rune-master-tile.png", + goals: [ + %{goal_uuid: goal.uuid} + ] + }) + + resp = + conn + |> get("/v2/courses/#{course.id}/user/total_xp") + |> json_response(200) + + assert resp["totalXp"] == 100 + end + + @tag authenticate: :student, group: true + test "addition of assessment and no achievements", %{ + conn: conn + } do + test_cr = conn.assigns.test_cr + course = conn.assigns.test_cr.course + + assessment = insert(:assessment, %{is_published: true, course: course}) + question = insert(:question, %{assessment: assessment}) + + submission = + insert(:submission, %{ + assessment: assessment, + student: test_cr, + status: :submitted, + xp_bonus: 100 + }) + + insert(:answer, %{ + question: question, + submission: submission, + xp: 20, + xp_adjustment: -10 + }) + + resp = + conn + |> get("/v2/courses/#{course.id}/user/total_xp") + |> json_response(200) + + assert resp["totalXp"] == 110 + end end # REFERENCE THIS From c2c4e3fbd0b77ea9f509fa20169f17b817f59bf7 Mon Sep 17 00:00:00 2001 From: Richard Qi <55354921+riccqi@users.noreply.github.com> Date: Fri, 1 Apr 2022 00:13:19 +0800 Subject: [PATCH 21/25] Update test names --- test/cadet_web/controllers/user_controller_test.exs | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/test/cadet_web/controllers/user_controller_test.exs b/test/cadet_web/controllers/user_controller_test.exs index 67c1d012f..13ca18584 100644 --- a/test/cadet_web/controllers/user_controller_test.exs +++ b/test/cadet_web/controllers/user_controller_test.exs @@ -175,7 +175,7 @@ defmodule CadetWeb.UserControllerTest do describe "GET /v2/courses/{course_id}/user/total_xp" do @tag authenticate: :student, group: true - test "addition of assessment and achievement with completed goal", %{ + test "achievement, one completed goal", %{ conn: conn } do test_cr = conn.assigns.test_cr @@ -240,7 +240,7 @@ defmodule CadetWeb.UserControllerTest do end @tag authenticate: :student, group: true - test "addition of assessment and achievement with incomplete goal", %{ + test "achievement, one incomplete goal", %{ conn: conn } do test_cr = conn.assigns.test_cr @@ -305,7 +305,7 @@ defmodule CadetWeb.UserControllerTest do end @tag authenticate: :student, group: true - test "addition of assessment and achievement with one completed, one incomplete goal", + test "achievement, one completed and one incomplete goal", %{ conn: conn } do @@ -390,7 +390,7 @@ defmodule CadetWeb.UserControllerTest do end @tag authenticate: :student, group: true - test "addition of assessment and achievement with goal w/o progress entry", %{ + test "achievement, goal (no progress entry)", %{ conn: conn } do test_cr = conn.assigns.test_cr @@ -448,7 +448,7 @@ defmodule CadetWeb.UserControllerTest do end @tag authenticate: :student, group: true - test "addition of no assessments and achievement with completed goal", %{ + test "no assessments", %{ conn: conn } do test_cr = conn.assigns.test_cr @@ -495,7 +495,7 @@ defmodule CadetWeb.UserControllerTest do end @tag authenticate: :student, group: true - test "addition of assessment and no achievements", %{ + test "no achievements", %{ conn: conn } do test_cr = conn.assigns.test_cr From 013e8a1e381cbee48bcab2b7ccf88d66da40d484 Mon Sep 17 00:00:00 2001 From: Richard Qi <55354921+riccqi@users.noreply.github.com> Date: Fri, 1 Apr 2022 00:21:26 +0800 Subject: [PATCH 22/25] Add is_variable_xp: true tests --- .../controllers/user_controller_test.exs | 383 +++++++++++++++++- 1 file changed, 382 insertions(+), 1 deletion(-) diff --git a/test/cadet_web/controllers/user_controller_test.exs b/test/cadet_web/controllers/user_controller_test.exs index 13ca18584..6491b1cfb 100644 --- a/test/cadet_web/controllers/user_controller_test.exs +++ b/test/cadet_web/controllers/user_controller_test.exs @@ -526,9 +526,390 @@ defmodule CadetWeb.UserControllerTest do assert resp["totalXp"] == 110 end + + @tag authenticate: :student, group: true + test "achievement (is_variable_xp: true), no goals.", %{ + conn: conn + } do + test_cr = conn.assigns.test_cr + course = conn.assigns.test_cr.course + + assessment = insert(:assessment, %{is_published: true, course: course}) + question = insert(:question, %{assessment: assessment}) + + submission = + insert(:submission, %{ + assessment: assessment, + student: test_cr, + status: :submitted, + xp_bonus: 100 + }) + + insert(:answer, %{ + question: question, + submission: submission, + xp: 20, + xp_adjustment: -10 + }) + + insert(:achievement, %{ + course: course, + title: "Rune Master", + is_task: true, + is_variable_xp: true, + position: 1, + xp: 100, + card_tile_url: + "https://source-academy-assets.s3-ap-southeast-1.amazonaws.com/achievement/card-tile/rune-master-tile.png", + goals: [] + }) + + resp = + conn + |> get("/v2/courses/#{course.id}/user/total_xp") + |> json_response(200) + + assert resp["totalXp"] == 110 + end + + @tag authenticate: :student, group: true + test "achievement (is_variable_xp: true), one incomplete goal (no progress entry).", %{ + conn: conn + } do + test_cr = conn.assigns.test_cr + course = conn.assigns.test_cr.course + + assessment = insert(:assessment, %{is_published: true, course: course}) + question = insert(:question, %{assessment: assessment}) + + submission = + insert(:submission, %{ + assessment: assessment, + student: test_cr, + status: :submitted, + xp_bonus: 100 + }) + + insert(:answer, %{ + question: question, + submission: submission, + xp: 20, + xp_adjustment: -10 + }) + + goal = + insert( + :goal, + Map.merge( + goal_literal(1), + %{ + course: course + } + ) + ) + + insert(:achievement, %{ + course: course, + title: "Rune Master", + is_task: true, + is_variable_xp: true, + position: 1, + xp: 100, + card_tile_url: + "https://source-academy-assets.s3-ap-southeast-1.amazonaws.com/achievement/card-tile/rune-master-tile.png", + goals: [ + %{goal_uuid: goal.uuid} + ] + }) + + resp = + conn + |> get("/v2/courses/#{course.id}/user/total_xp") + |> json_response(200) + + assert resp["totalXp"] == 110 + end + + @tag authenticate: :student, group: true + test "achievement (is_variable_xp: true), one incomplete goal (with progress entry).", %{ + conn: conn + } do + test_cr = conn.assigns.test_cr + course = conn.assigns.test_cr.course + + assessment = insert(:assessment, %{is_published: true, course: course}) + question = insert(:question, %{assessment: assessment}) + + submission = + insert(:submission, %{ + assessment: assessment, + student: test_cr, + status: :submitted, + xp_bonus: 100 + }) + + insert(:answer, %{ + question: question, + submission: submission, + xp: 20, + xp_adjustment: -10 + }) + + goal = + insert( + :goal, + Map.merge( + goal_literal(1), + %{ + course: course, + progress: [ + %{ + count: 0, + completed: true, + course_reg_id: test_cr.id + } + ] + } + ) + ) + + insert(:achievement, %{ + course: course, + title: "Rune Master", + is_task: true, + is_variable_xp: true, + position: 1, + xp: 100, + card_tile_url: + "https://source-academy-assets.s3-ap-southeast-1.amazonaws.com/achievement/card-tile/rune-master-tile.png", + goals: [ + %{goal_uuid: goal.uuid} + ] + }) + + resp = + conn + |> get("/v2/courses/#{course.id}/user/total_xp") + |> json_response(200) + + assert resp["totalXp"] == 110 + end + + @tag authenticate: :student, group: true + test "achievement (is_variable_xp: true), one goal completed.", %{ + conn: conn + } do + test_cr = conn.assigns.test_cr + course = conn.assigns.test_cr.course + + assessment = insert(:assessment, %{is_published: true, course: course}) + question = insert(:question, %{assessment: assessment}) + + submission = + insert(:submission, %{ + assessment: assessment, + student: test_cr, + status: :submitted, + xp_bonus: 100 + }) + + insert(:answer, %{ + question: question, + submission: submission, + xp: 20, + xp_adjustment: -10 + }) + + goal = + insert( + :goal, + Map.merge( + goal_literal(1), + %{ + course: course, + progress: [ + %{ + count: 1, + completed: true, + course_reg_id: test_cr.id + } + ] + } + ) + ) + + insert(:achievement, %{ + course: course, + title: "Rune Master", + is_task: true, + is_variable_xp: true, + position: 1, + xp: 100, + card_tile_url: + "https://source-academy-assets.s3-ap-southeast-1.amazonaws.com/achievement/card-tile/rune-master-tile.png", + goals: [ + %{goal_uuid: goal.uuid} + ] + }) + + resp = + conn + |> get("/v2/courses/#{course.id}/user/total_xp") + |> json_response(200) + + assert resp["totalXp"] == 111 + end + + @tag authenticate: :student, group: true + test "achievement (is_variable_xp: true), with one goal completed and one goal incomplete", %{ + conn: conn + } do + test_cr = conn.assigns.test_cr + course = conn.assigns.test_cr.course + + assessment = insert(:assessment, %{is_published: true, course: course}) + question = insert(:question, %{assessment: assessment}) + + submission = + insert(:submission, %{ + assessment: assessment, + student: test_cr, + status: :submitted, + xp_bonus: 100 + }) + + insert(:answer, %{ + question: question, + submission: submission, + xp: 20, + xp_adjustment: -10 + }) + + goal = + insert( + :goal, + Map.merge( + goal_literal(1), + %{ + course: course, + progress: [ + %{ + count: 1, + completed: true, + course_reg_id: test_cr.id + } + ] + } + ) + ) + + goal2 = + insert( + :goal, + Map.merge( + goal_literal(1), + %{ + course: course, + progress: [ + %{ + count: 0, + completed: true, + course_reg_id: test_cr.id + } + ] + } + ) + ) + + insert(:achievement, %{ + course: course, + title: "Rune Master", + is_task: true, + is_variable_xp: true, + position: 1, + xp: 100, + card_tile_url: + "https://source-academy-assets.s3-ap-southeast-1.amazonaws.com/achievement/card-tile/rune-master-tile.png", + goals: [ + %{goal_uuid: goal.uuid}, + %{goal_uuid: goal2.uuid} + ] + }) + + resp = + conn + |> get("/v2/courses/#{course.id}/user/total_xp") + |> json_response(200) + + assert resp["totalXp"] == 110 + end + + @tag authenticate: :student, group: true + test "achievement (is_variable_xp: true), one goal with 0 target_count and 0 count", %{ + conn: conn + } do + test_cr = conn.assigns.test_cr + course = conn.assigns.test_cr.course + + assessment = insert(:assessment, %{is_published: true, course: course}) + question = insert(:question, %{assessment: assessment}) + + submission = + insert(:submission, %{ + assessment: assessment, + student: test_cr, + status: :submitted, + xp_bonus: 100 + }) + + insert(:answer, %{ + question: question, + submission: submission, + xp: 20, + xp_adjustment: -10 + }) + + goal = + insert( + :goal, + Map.merge( + goal_literal(0), + %{ + course: course, + progress: [ + %{ + count: 0, + completed: true, + course_reg_id: test_cr.id + } + ] + } + ) + ) + + insert(:achievement, %{ + course: course, + title: "Rune Master", + is_task: true, + is_variable_xp: true, + position: 1, + xp: 100, + card_tile_url: + "https://source-academy-assets.s3-ap-southeast-1.amazonaws.com/achievement/card-tile/rune-master-tile.png", + goals: [ + %{goal_uuid: goal.uuid} + ] + }) + + resp = + conn + |> get("/v2/courses/#{course.id}/user/total_xp") + |> json_response(200) + + assert resp["totalXp"] == 110 + end end - # REFERENCE THIS describe "GET /v2/user/latest_viewed_course" do @tag authenticate: :student, group: true test "success, student non-story fields", %{conn: conn} do From 1e415d151a9a5f223f72b2934864ed5dd935f362 Mon Sep 17 00:00:00 2001 From: angelsl Date: Fri, 22 Apr 2022 20:21:18 +0800 Subject: [PATCH 23/25] Remove added @spec lines --- lib/cadet_web/controllers/incentives_controller.ex | 2 -- 1 file changed, 2 deletions(-) diff --git a/lib/cadet_web/controllers/incentives_controller.ex b/lib/cadet_web/controllers/incentives_controller.ex index deac4c999..2787f8c26 100644 --- a/lib/cadet_web/controllers/incentives_controller.ex +++ b/lib/cadet_web/controllers/incentives_controller.ex @@ -10,14 +10,12 @@ defmodule CadetWeb.IncentivesController do render(conn, "index_achievements.json", achievements: Achievements.get(course_id)) end - @spec index_goals(Plug.Conn.t(), any) :: Plug.Conn.t() def index_goals(conn, _) do render(conn, "index_goals_with_progress.json", goals: Goals.get_with_progress(conn.assigns.course_reg) ) end - @spec update_progress(Plug.Conn.t(), map) :: Plug.Conn.t() def update_progress(conn, %{"uuid" => uuid, "progress" => progress}) do course_reg_id = conn.assigns.course_reg.id From 0598a6a44928050efc1ce795d75ea907ccd6aa92 Mon Sep 17 00:00:00 2001 From: angelsl Date: Fri, 22 Apr 2022 20:24:27 +0800 Subject: [PATCH 24/25] Tweak documentation --- lib/cadet_web/controllers/user_controller.ex | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/lib/cadet_web/controllers/user_controller.ex b/lib/cadet_web/controllers/user_controller.ex index f366b0d18..ed93e66dc 100644 --- a/lib/cadet_web/controllers/user_controller.ex +++ b/lib/cadet_web/controllers/user_controller.ex @@ -180,7 +180,7 @@ defmodule CadetWeb.UserController do consumes("application/json") parameters do - course_id(:path, :integer, "the user's course id", required: true) + course_id(:path, :integer, "course ID", required: true) agreedToResearch( :body, @@ -195,15 +195,15 @@ defmodule CadetWeb.UserController do end swagger_path :combined_total_xp do - get("/courses/{courseId}/user/total_xp") + get("/courses/:course_id/user/total_xp") - summary("Get the total xp from achievements and assessments of a user in a specific course") + summary("Get the user's total XP from achievements and assessments") security([%{JWT: []}]) produces("application/json") parameters do - courseId(:path, :integer, "Course Id", required: true) + course_id(:path, :integer, "course ID", required: true) end response(200, "OK", Schema.ref(:TotalXPInfo)) @@ -234,10 +234,10 @@ defmodule CadetWeb.UserController do TotalXPInfo: swagger_schema do title("User Total XP") - description("total xp of the user") + description("the user's total achievement and assessment XP") properties do - totalXp(:integer, "total xp") + totalXp(:integer, "total XP") end end, LatestViewedInfo: From 839b45f347b5d9fcc263573ebc2ce258f63075dd Mon Sep 17 00:00:00 2001 From: angelsl Date: Fri, 22 Apr 2022 20:26:40 +0800 Subject: [PATCH 25/25] Call swagger_path combined_total_xp in tests --- test/cadet_web/controllers/user_controller_test.exs | 1 + 1 file changed, 1 insertion(+) diff --git a/test/cadet_web/controllers/user_controller_test.exs b/test/cadet_web/controllers/user_controller_test.exs index 6491b1cfb..ea445fbc5 100644 --- a/test/cadet_web/controllers/user_controller_test.exs +++ b/test/cadet_web/controllers/user_controller_test.exs @@ -16,6 +16,7 @@ defmodule CadetWeb.UserControllerTest do assert is_map(UserController.swagger_path_update_latest_viewed(nil)) assert is_map(UserController.swagger_path_update_game_states(nil)) assert is_map(UserController.swagger_path_update_research_agreement(nil)) + assert is_map(UserController.swagger_path_combined_total_xp(nil)) end describe "GET v2/user" do