Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
44 changes: 43 additions & 1 deletion lib/cadet/incentives/achievements.ex
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,12 @@ defmodule Cadet.Incentives.Achievements do
"""
use Cadet, [:context, :display]

alias Cadet.Incentives.Achievement
alias Cadet.Incentives.{Achievement, GoalProgress}

import Ecto.Query

require Decimal

@doc """
Returns all achievements.

Expand All @@ -21,6 +23,46 @@ defmodule Cadet.Incentives.Achievements do
|> Repo.all()
end

@doc """
Returns a user's total xp from their completed achievements.
"""
def achievements_total_xp(course_id, course_reg_id) when is_ecto_id(course_id) do
xp =
Achievement
|> 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()

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()}}
@doc """
Inserts a new achievement, or updates it if it already exists.
Expand Down
66 changes: 52 additions & 14 deletions lib/cadet_web/controllers/user_controller.ex
Original file line number Diff line number Diff line change
Expand Up @@ -5,19 +5,20 @@ defmodule CadetWeb.UserController do

use CadetWeb, :controller
use PhoenixSwagger
import Cadet.Assessments
alias Cadet.Accounts
alias Cadet.Incentives.Achievements
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)

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,
Expand Down Expand Up @@ -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,
Expand Down Expand Up @@ -112,8 +113,20 @@ defmodule CadetWeb.UserController do
end
end

def combined_total_xp(conn, _) do
course_id = conn.assigns.course_reg.course_id
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
get("/v2/user")
get("/user")

summary("Get the name, and latest_viewed_course of a user")

Expand All @@ -124,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")

Expand All @@ -135,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")
Expand All @@ -148,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")
Expand All @@ -161,13 +174,13 @@ 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")

parameters do
course_id(:path, :integer, "the user's course id", required: true)
course_id(:path, :integer, "course ID", required: true)

agreedToResearch(
:body,
Expand All @@ -181,6 +194,22 @@ defmodule CadetWeb.UserController do
response(400, "Bad Request")
end

swagger_path :combined_total_xp do
get("/courses/:course_id/user/total_xp")

summary("Get the user's total XP from achievements and assessments")

security([%{JWT: []}])
produces("application/json")

parameters do
course_id(:path, :integer, "course ID", required: true)
end

response(200, "OK", Schema.ref(:TotalXPInfo))
response(401, "Unauthorised")
end

def swagger_definitions do
%{
IndexInfo:
Expand All @@ -202,6 +231,15 @@ defmodule CadetWeb.UserController do
)
end
end,
TotalXPInfo:
swagger_schema do
title("User Total XP")
description("the user's total achievement and assessment XP")

properties do
totalXp(:integer, "total XP")
end
end,
LatestViewedInfo:
swagger_schema do
title("Latest viewed course")
Expand Down
1 change: 1 addition & 0 deletions lib/cadet_web/router.ex
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,7 @@ defmodule CadetWeb.Router do
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)

Expand Down
Loading