Skip to content

Conversation

@indocomsoft
Copy link
Member

Fixes #67

@indocomsoft indocomsoft self-assigned this Jul 8, 2018
@indocomsoft indocomsoft added this to the Sprint 4 milestone Jul 8, 2018
@coveralls
Copy link

coveralls commented Jul 8, 2018

Pull Request Test Coverage Report for Build 844

  • 83 of 83 (100.0%) changed or added relevant lines in 8 files are covered.
  • No unchanged relevant lines lost coverage.
  • Overall coverage increased (+1.08%) to 98.34%

Totals Coverage Status
Change from base Build 830: 1.08%
Covered Lines: 474
Relevant Lines: 482

💛 - Coveralls

@indocomsoft indocomsoft force-pushed the add-grading-controller branch 2 times, most recently from 6c29b6e to 56d3e90 Compare July 10, 2018 17:00
@indocomsoft indocomsoft changed the title Add grading controller WIP: Add grading controller Jul 11, 2018
@indocomsoft indocomsoft force-pushed the add-grading-controller branch 2 times, most recently from 4ef1062 to 9c12d80 Compare July 12, 2018 15:47
@indocomsoft indocomsoft requested review from ning-y and tuesmiddt July 13, 2018 04:32
@indocomsoft indocomsoft changed the title WIP: Add grading controller Add grading controller Jul 13, 2018
Copy link
Contributor

@tuesmiddt tuesmiddt left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks good overall. Minor issues only. Haven't looked at the tests in detail yet.

Lets agree to not change past migrations after the 3 controllers are shipped.

@spec students_of(User.t()) :: User.t()
def students_of(%User{id: id, role: :staff}) do
User
|> join(:inner, [u], g in Group, u.group_id == g.id and g.leader_id == ^id)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think it's clearer to move the leader_id check into a separate line. Cursory googling suggest both will be optimised to the same query.

User
|> join(:inner, [u], g in assoc(u, :group)
|> where([_, g], g.leader_id == ^id)

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah they both are optimised to the same query

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done

s.assessment_id == a.id
)
|> select([s, x, st, a], %Submission{s | xp: x.xp, student: st, assessment: a})
|> join(:inner, [s], t in subquery(students), s.student_id == t.id)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can replace join(:inner, [s], st in assoc(s, :student)) with this directly.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done

|> join(:inner, [a], s in Submission, a.submission_id == s.id)
|> join(:inner, [a, s], t in subquery(students), t.id == s.student_id)
|> join(:inner, [a], q in assoc(a, :question))
|> preload([a, _, _, q], question: q)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Use preload([a, ..., q], question: q) instead

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ooh, I didn't know about this syntax. Cool!

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done

answer =
Answer
|> where([a], a.submission_id == ^submission_id and a.question_id == ^question_id)
|> join(:inner, [a], s in Submission, a.submission_id == s.id)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I prefer assoc joins to be written with the asssoc syntax: (join(:inner, [a], s in assoc(a, :submission))) but I get it also causes some inconsistency in syntax because it doesn't work with subqueries. What are your thoughts?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah I think I prefer the assoc syntax too. It's an oversight on my part.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done

|> join(:inner, [a, s], t in subquery(students), t.id == s.student_id)
|> Repo.one()

if answer do
Copy link
Contributor

@tuesmiddt tuesmiddt Jul 13, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could consider replacing this block with:

with {:answer_found?, answer = %Answer{}} <- {:answer_found?, answer},
# or with {:answer_found?, true} <- {:answer_found?, is_map(answer)},
      {:valid, changeset = %Ecto.Changeset{valid?: true}} <-
        {:valid, Answer.grading_changeset(answer, attrs)},
      {:ok, _} <- Repo.update(changeset) do
  {:ok, nil}
else
  {:answer_found?, _} ->
    {:error, {:bad_request, "Answer not found or user not permitted to grade."}}

  {:valid, changeset} ->
    {:error, {:bad_request, full_error_messages(changeset.errors)}}

  {:error, _} ->
    {:error, {:internal_server_error, "Please try again later."}}
end

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done.

%{
content: sequence("ProgrammingQuestion"),
solution_template: "f => f(f);",
solution: "(f => f(f))(f => f(f));"
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🙃

end
end

defmacro is_ecto_id(id) do
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Created #113


@spec full_error_messages(keyword({String.t(), term()})) :: String.t()
def full_error_messages(errors) do
for {key, {message, _}} <- errors do
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I personally prefer:

    to_error_string = fn {key, {message, _}} -> "#{key} #{message}" end

    errors
    |> Enum.map(to_error_string)
    |> Enum.join(", ")

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think in this case Enum makes more sense than list comprehension.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done

@indocomsoft
Copy link
Member Author

@tuesmiddt Fixed my code according to your code review. I also re-wrote seeds.exs and seed_db/1 in my test to use list comprehension for better readibility

@indocomsoft indocomsoft merged commit ddc0618 into master Jul 14, 2018
@indocomsoft indocomsoft deleted the add-grading-controller branch July 14, 2018 04:02
indocomsoft added a commit that referenced this pull request Aug 17, 2018
* Add factories and seeds

* Update api spec according to changes from Vignesh

* Implement index

* Hotfix tests

* Implement show sans test

* Add tests

* Update context and model in preparation of implementing update

* Fix duplicate factory

* Implement update sans test

* Add typespec and is_ecto_id macro guard clause

* Add and refactor tests

* Fix according to code review

* Change to list comprehension for readability
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants