Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add Avenger Backlog Notifications #932

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
52 commits
Select commit Hold shift + click to select a range
fcc4cf5
Create NotificationType Model
Santosh3007 Feb 14, 2023
b429644
Configure Oban and Bamboo for notifications system
Junyi00 Feb 14, 2023
d024a75
Create NotificationConfig Model
Santosh3007 Feb 14, 2023
cd20b4a
Create TimeOption Model
Santosh3007 Feb 14, 2023
a580719
Create NotificationPreference Model
Santosh3007 Feb 14, 2023
877220a
Create SentNotification Model
Santosh3007 Feb 14, 2023
c8ecd5d
Add Email Field to User Model
Junyi00 Feb 15, 2023
6a6cec7
fix: Fix Oban configuration
Junyi00 Feb 15, 2023
1b5ca22
chore: Add dependency on bamboo_phoenix for email template rendering
Junyi00 Feb 15, 2023
39367e4
feat: Implement Oban job for avenger backlog emails
Junyi00 Feb 15, 2023
e6cd06c
chore: Prevent browser from opening automatically when a local email …
Junyi00 Feb 15, 2023
4cc7b7f
Add migrations for notification triggers and avenger backlog
Junyi00 Feb 15, 2023
1802e49
Implement notification configuration checks
Junyi00 Feb 15, 2023
0f7b7e4
Fix formatting errors
Santosh3007 Feb 16, 2023
dd951e8
fix: Fix notifications schema typos
Junyi00 Feb 21, 2023
554054f
fix: Fix test configurations not being applied
Junyi00 Feb 21, 2023
960d75b
chore: remove unused controllers and views
Santosh3007 Feb 27, 2023
851a309
chore: Add tests for notifications
Junyi00 Feb 27, 2023
fa4ea44
chore: Add test for avenger backlog email
Junyi00 Feb 27, 2023
6602170
chore: Resolve style violations
Junyi00 Feb 27, 2023
669ac75
chore: Resolve style violations
Junyi00 Feb 27, 2023
e8bff4c
chore: Resolve style violations
Junyi00 Feb 27, 2023
45bbb34
style: fix formatting
Santosh3007 Feb 27, 2023
f6857b9
fix: Fix bad refactoring
Junyi00 Feb 27, 2023
f709625
fix: Fix testing environment with Oban and Bamboo
Junyi00 Feb 27, 2023
5b43002
test: add tests for notification types
Santosh3007 Feb 28, 2023
b37f4a5
test: add tests for time options
Santosh3007 Feb 28, 2023
b0000c6
chore: Update constraints and changesets for notification models
Junyi00 Feb 28, 2023
7003af5
chore: Update default behaviour for no time_option in user preference
Junyi00 Feb 28, 2023
1f25fc0
style: fix formatting
Santosh3007 Feb 28, 2023
d6d6869
test: add tests for sent notifications
Santosh3007 Mar 1, 2023
fdfd195
Add tests for notifications module
Junyi00 Mar 1, 2023
31c7b5c
Merge branch 'add-avenger-backlog-notification' of https://github.com…
Junyi00 Mar 1, 2023
498ca1b
fix: Fix testing with Oban
Junyi00 Mar 2, 2023
70823a6
Add more tests for notifications module
Junyi00 Mar 2, 2023
cf160f8
test: add tests for NotificationWorker
Santosh3007 Mar 5, 2023
83d4943
style: fix formatting
Santosh3007 Mar 5, 2023
bf362c7
style: fix formatting
Santosh3007 Mar 5, 2023
05aac5c
style: fix formatting
Santosh3007 Mar 6, 2023
3b571ff
Merge branch 'add-avenger-backlog-notification' of https://github.com…
Junyi00 Mar 6, 2023
8f0e982
fix: Fix tests under notification types name constraints
Junyi00 Mar 6, 2023
ba29201
feat: Implement job for assessment submission mail
Santosh3007 Feb 26, 2023
c07f88f
Merge branch 'add-avenger-backlog-notification' of https://github.com…
Junyi00 Mar 9, 2023
4f120ee
fix: Fix assessment submission worker
Junyi00 Mar 10, 2023
0b245a9
chore: Add test for assessment submission
Junyi00 Mar 10, 2023
9600d40
chore: Add migration to populate existing nus users' emails
Junyi00 Mar 11, 2023
22c1391
feat: implement sent_notifications
Santosh3007 Mar 12, 2023
8ef9a59
fix: fix tests
Santosh3007 Mar 12, 2023
a516463
style: fix formatting
Santosh3007 Mar 12, 2023
8994947
fix: fix guard clauses
Santosh3007 Mar 13, 2023
b93cdbd
fix: Fix db triggers not running for assessment submission notifications
Junyi00 Mar 13, 2023
67a56f8
Merge branch 'master' into add-avenger-backlog-notification
martin-henz May 22, 2023
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
23 changes: 19 additions & 4 deletions config/config.exs
Original file line number Diff line number Diff line change
Expand Up @@ -72,10 +72,6 @@ config :sentry,
root_source_code_path: File.cwd!(),
context_lines: 5

# Import environment specific config. This must remain at the bottom
# of this file so it overrides the configuration defined above.
import_config "#{Mix.env()}.exs"

# Configure Phoenix Swagger
config :cadet, :phoenix_swagger,
swagger_files: %{
Expand All @@ -93,3 +89,22 @@ config :guardian, Guardian.DB,
token_types: ["refresh"],
# default: 60 minute
sweep_interval: 180

config :cadet, Oban,
repo: Cadet.Repo,
plugins: [
# keep
{Oban.Plugins.Pruner, max_age: 60},
{Oban.Plugins.Cron,
crontab: [
{"@daily", Cadet.Workers.NotificationWorker,
args: %{"notification_type" => "avenger_backlog"}}
]}
],
queues: [default: 10, notifications: 1]

config :cadet, Cadet.Mailer, adapter: Bamboo.LocalAdapter

# Import environment specific config. This must remain at the bottom
# of this file so it overrides the configuration defined above.
import_config "#{Mix.env()}.exs"
2 changes: 2 additions & 0 deletions config/prod.exs
Original file line number Diff line number Diff line change
Expand Up @@ -44,3 +44,5 @@ config :logger, level: :info
config :ex_aws,
access_key_id: [:instance_role],
secret_access_key: [:instance_role]

config :cadet, Cadet.Mailer, adapter: Bamboo.SesAdapter
6 changes: 6 additions & 0 deletions config/test.exs
Original file line number Diff line number Diff line change
Expand Up @@ -88,3 +88,9 @@ config :arc, storage: Arc.Storage.Local

if "test.secrets.exs" |> Path.expand(__DIR__) |> File.exists?(),
do: import_config("test.secrets.exs")

config :cadet, Oban,
repo: Cadet.Repo,
testing: :manual

config :cadet, Cadet.Mailer, adapter: Bamboo.TestAdapter
26 changes: 26 additions & 0 deletions lib/cadet/accounts/course_registrations.ex
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,13 @@ defmodule Cadet.Accounts.CourseRegistrations do
|> Repo.all()
end

def get_staffs(course_id) do
CourseRegistration
|> where(course_id: ^course_id)
|> where(role: :staff)
|> Repo.all()
end

def get_users(course_id, group_id) when is_ecto_id(group_id) and is_ecto_id(course_id) do
CourseRegistration
|> where([cr], cr.course_id == ^course_id)
Expand Down Expand Up @@ -200,4 +207,23 @@ defmodule Cadet.Accounts.CourseRegistrations do
{:error, changeset} -> {:error, {:bad_request, full_error_messages(changeset)}}
end
end

def get_avenger_of(student_id) when is_ecto_id(student_id) do
CourseRegistration
|> Repo.get_by(id: student_id)
|> Repo.preload(:group)
|> Map.get(:group)
|> case do
nil ->
nil

group ->
avenger_id = Map.get(group, :leader_id)

CourseRegistration
|> where([cr], cr.id == ^avenger_id)
|> preload(:user)
|> Repo.one()
end
end
end
1 change: 1 addition & 0 deletions lib/cadet/accounts/user.ex
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ defmodule Cadet.Accounts.User do
field(:username, :string)
field(:provider, :string)
field(:super_admin, :boolean)
field(:email, :string)

belongs_to(:latest_viewed_course, Course)
has_many(:courses, CourseRegistration)
Expand Down
4 changes: 3 additions & 1 deletion lib/cadet/application.ex
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,9 @@ defmodule Cadet.Application do
# Start the GuardianDB sweeper
worker(Guardian.DB.Token.SweeperServer, []),
# Start the Quantum scheduler
worker(Cadet.Jobs.Scheduler, [])
worker(Cadet.Jobs.Scheduler, []),
# Start the Oban instance
{Oban, Application.fetch_env!(:cadet, Oban)}
]

children =
Expand Down
24 changes: 22 additions & 2 deletions lib/cadet/assessments/assessments.ex
Original file line number Diff line number Diff line change
Expand Up @@ -721,11 +721,24 @@ defmodule Cadet.Assessments do
|> Repo.one()
end

def get_submission_by_id(submission_id) when is_ecto_id(submission_id) do
Submission
|> where(id: ^submission_id)
|> join(:inner, [s], a in assoc(s, :assessment))
|> preload([_, a], assessment: a)
|> Repo.one()
end

def finalise_submission(submission = %Submission{}) do
with {:status, :attempted} <- {:status, submission.status},
{:ok, updated_submission} <- update_submission_status_and_xp_bonus(submission) do
# Couple with update_submission_status_and_xp_bonus to ensure notification is sent
Notifications.write_notification_when_student_submits(submission)
# Send email notification to avenger
%{notification_type: "assessment_submission", submission_id: updated_submission.id}
|> Cadet.Workers.NotificationWorker.new()
|> Oban.insert()

# Begin autograding job
GradingJob.force_grade_individual_submission(updated_submission)

Expand Down Expand Up @@ -1151,7 +1164,8 @@ defmodule Cadet.Assessments do
{:ok, String.t()}
def all_submissions_by_grader_for_index(
grader = %CourseRegistration{course_id: course_id},
group_only \\ false
group_only \\ false,
ungraded_only \\ false
) do
show_all = not group_only

Expand All @@ -1161,6 +1175,11 @@ defmodule Cadet.Assessments do
else:
"where s.student_id in (select cr.id from course_registrations cr inner join groups g on cr.group_id = g.id where g.leader_id = $2) or s.student_id = $2"

ungraded_where =
if ungraded_only,
do: "where s.\"gradedCount\" < assts.\"questionCount\"",
else: ""

params = if show_all, do: [course_id], else: [course_id, grader.id]

# We bypass Ecto here and use a raw query to generate JSON directly from
Expand Down Expand Up @@ -1200,7 +1219,7 @@ defmodule Cadet.Assessments do
group by s.id) s
inner join
(select
a.id, to_json(a) as jsn
a.id, a."questionCount", to_json(a) as jsn
from
(select
a.id,
Expand Down Expand Up @@ -1240,6 +1259,7 @@ defmodule Cadet.Assessments do
from course_registrations cr
inner join
users u on u.id = cr.user_id) cr) unsubmitters on s.unsubmitted_by_id = unsubmitters.id
#{ungraded_where}
) q
""",
params
Expand Down
10 changes: 8 additions & 2 deletions lib/cadet/courses/courses.ex
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,12 @@ defmodule Cadet.Courses do
end
end

def get_all_course_ids do
Course
|> select([c], c.id)
|> Repo.all()
end

defp retrieve_course(course_id) when is_ecto_id(course_id) do
Course
|> where(id: ^course_id)
Expand Down Expand Up @@ -233,8 +239,8 @@ defmodule Cadet.Courses do
)
|> where(course_id: ^course_id)
|> Repo.one()} do
# It is ok to assume that user course registions already exist, as they would have been created
# in the admin_user_controller before calling this function
# It is ok to assume that user course registions already exist, as they would
# have been created in the admin_user_controller before calling this function
case role do
# If student, update his course registration
:student ->
Expand Down
40 changes: 40 additions & 0 deletions lib/cadet/email.ex
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
defmodule Cadet.Email do
@moduledoc """
Contains methods for sending email notifications.
"""
use Bamboo.Phoenix, view: CadetWeb.EmailView
import Bamboo.Email

def avenger_backlog_email(template_file_name, avenger, ungraded_submissions) do
if is_nil(avenger.email) do
nil
else
base_email()
|> to(avenger.email)
|> assign(:avenger_name, avenger.name)
|> assign(:submissions, ungraded_submissions)
|> subject("Backlog for #{avenger.name}")
|> render("#{template_file_name}.html")
end
end

def assessment_submission_email(template_file_name, avenger, student, submission) do
if is_nil(avenger.email) do
nil
else
base_email()
|> to(avenger.email)
|> assign(:avenger_name, avenger.name)
|> assign(:student_name, student.name)
|> assign(:assessment_title, submission.assessment.title)
|> subject("New submission for #{submission.assessment.title}")
|> render("#{template_file_name}.html")
end
end

defp base_email do
new_email()
|> from("noreply@sourceacademy.org")
|> put_html_layout({CadetWeb.LayoutView, "email.html"})
end
end
3 changes: 3 additions & 0 deletions lib/cadet/jobs/scheduler.ex
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
# credo:disable-for-this-file Credo.Check.Readability.ModuleDoc
# @moduledoc is actually generated by a macro inside Quantum
defmodule Cadet.Jobs.Scheduler do
@moduledoc """
Quantum is used for scheduling jobs with cron jobs.
"""
use Quantum, otp_app: :cadet
end
6 changes: 6 additions & 0 deletions lib/cadet/mailer.ex
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
defmodule Cadet.Mailer do
@moduledoc """
Mailer used to sent notification emails.
"""
use Bamboo.Mailer, otp_app: :cadet
end
Loading