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
10 changes: 5 additions & 5 deletions lib/code_corps/model/skill.ex
Original file line number Diff line number Diff line change
Expand Up @@ -4,16 +4,16 @@ defmodule CodeCorps.Skill do
@type t :: %__MODULE__{}

schema "skills" do
field :title, :string
field :description, :string
field :original_row, :integer

has_many :role_skills, CodeCorps.RoleSkill
has_many :roles, through: [:role_skills, :role]
field :title, :string

has_many :project_skills, CodeCorps.ProjectSkill
has_many :projects, through: [:project_skills, :project]

has_many :role_skills, CodeCorps.RoleSkill
has_many :roles, through: [:role_skills, :role]

timestamps()
end

Expand All @@ -23,7 +23,7 @@ defmodule CodeCorps.Skill do
@spec changeset(CodeCorps.Skill.t, map) :: Ecto.Changeset.t
def changeset(struct, params \\ %{}) do
struct
|> cast(params, [:title, :description, :original_row])
|> cast(params, [:description, :original_row, :title])
|> validate_required([:title])
|> unique_constraint(:title)
end
Expand Down
38 changes: 38 additions & 0 deletions lib/code_corps/skills/skills.ex
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
defmodule CodeCorps.Skills do
@moduledoc ~S"""
Work with skills.
"""

alias CodeCorps.{
Repo,
Skill,
UserSkill
}

import Ecto.Query

@doc """
Find the most popular skills, in order, with a limit.
"""
@spec popular(map) :: [Skill.t]
def popular(params \\ %{})
def popular(%{"limit" => limit}), do: limit |> Integer.parse() |> apply_limit()
def popular(_), do: do_popular()

defp apply_limit({limit, _rem}) when limit <= 100, do: do_popular(limit)
defp apply_limit(_), do: do_popular()

@spec do_popular(pos_integer) :: [Skill.t]
def do_popular(limit \\ 10) do
query =
from s in Skill,
join: us in UserSkill,
on: s.id == us.skill_id,
group_by: s.id,
order_by: [desc: count(us.skill_id)],
limit: ^limit

query
|> Repo.all()
end
end
11 changes: 8 additions & 3 deletions lib/code_corps_web/controllers/skill_controller.ex
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ defmodule CodeCorpsWeb.SkillController do
@moduledoc false
use CodeCorpsWeb, :controller

alias CodeCorps.{Skill, User, Helpers.Query}
alias CodeCorps.{Helpers.Query, Skill, Skills, User}

action_fallback CodeCorpsWeb.FallbackController
plug CodeCorpsWeb.Plug.DataToAttributes
Expand All @@ -22,7 +22,7 @@ defmodule CodeCorpsWeb.SkillController do
end
end

@spec create(Plug.Conn.t, map) :: Conn.t
@spec create(Conn.t, map) :: Conn.t
def create(%Conn{} = conn, %{} = params) do
with %User{} = current_user <- conn |> CodeCorps.Guardian.Plug.current_resource,
{:ok, :authorized} <- current_user |> Policy.authorize(:create, %Skill{}, params),
Expand All @@ -34,12 +34,17 @@ defmodule CodeCorpsWeb.SkillController do
end

@spec load_skills(map) :: list(Skill.t)
defp load_skills(%{"popular" => "true"} = params) do
params
|> Skills.popular()
|> preload()
end
defp load_skills(%{} = params) do
Skill
|> Query.id_filter(params)
|> Query.title_filter(params)
|> Query.limit_filter(params)
|> Repo.all
|> Repo.all()
end

@preloads [:role_skills]
Expand Down
38 changes: 38 additions & 0 deletions test/lib/code_corps/skills/skills_test.exs
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
defmodule CodeCorps.AccountsTest do
@moduledoc false

use CodeCorps.DbAccessCase

alias CodeCorps.Skills

describe "popular/1" do
test "returns popular skills in order with a limit" do
[least_popular, somewhat_popular, most_popular] = insert_list(3, :skill)
insert_list(3, :user_skill, skill: most_popular)
insert_list(2, :user_skill, skill: somewhat_popular)
insert_list(1, :user_skill, skill: least_popular)

[first_result, last_result] = Skills.popular(%{"limit" => "2"})

assert first_result == most_popular
assert last_result == somewhat_popular
end

test "defaults limit to 10" do
skills = insert_list(11, :skill)
skills |> Enum.each(fn skill -> insert(:user_skill, skill: skill) end)

results = Skills.popular()

assert results |> Enum.count() == 10
end

test "ignores non-number limits" do
insert(:user_skill)

results = Skills.popular(%{"limit" => "apples"})

assert results |> Enum.count() == 1
end
end
end
14 changes: 14 additions & 0 deletions test/lib/code_corps_web/controllers/skill_controller_test.exs
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,20 @@ defmodule CodeCorpsWeb.SkillControllerTest do
returned_skills_length = json["data"] |> length
assert returned_skills_length == 5
end

test "lists popular skills", %{conn: conn} do
[skill_1, skill_2] = insert_pair(:skill)
insert(:user_skill, skill: skill_1)
insert_list(2, :user_skill, skill: skill_2)

params = %{"popular" => "true"}
path = conn |> skill_path(:index, params)

conn
|> get(path)
|> json_response(200)
|> assert_ids_from_response([skill_2.id, skill_1.id])
end
end

describe "show" do
Expand Down