forked from Simon-Initiative/oli-torus
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge branch 'Simon-Initiative:master' into master
- Loading branch information
Showing
19 changed files
with
1,256 additions
and
10 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,52 @@ | ||
defmodule Mix.Tasks.CreateContainedObjectives do | ||
@shortdoc "Create contained objectives for all sections that were not migrated" | ||
|
||
use Mix.Task | ||
|
||
alias Oli.Delivery.Sections | ||
alias Oli.Repo | ||
alias Oli.Delivery.Sections.{ContainedObjectivesBuilder, Section} | ||
alias Ecto.Multi | ||
|
||
require Logger | ||
|
||
import Ecto.Query, only: [from: 2] | ||
|
||
@impl Mix.Task | ||
def run(_args) do | ||
Mix.Task.run("app.start") | ||
|
||
run_now() | ||
end | ||
|
||
def run_now() do | ||
Logger.info("Start enqueueing contained objectives creation") | ||
|
||
Multi.new() | ||
|> Multi.run(:sections, &get_not_started_sections(&1, &2)) | ||
|> Oban.insert_all(:jobs, &build_contained_objectives_jobs(&1)) | ||
|> Ecto.Multi.update_all( | ||
:update_all_sections, | ||
fn _ -> from(Section, where: [v25_migration: :not_started]) end, | ||
set: [v25_migration: :pending] | ||
) | ||
|> Repo.transaction() | ||
|> case do | ||
{:ok, %{jobs: jobs}} -> | ||
Logger.info("#{Enum.count(jobs)} jobs enqueued for contained objectives creation") | ||
|
||
:ok | ||
|
||
{:error, _, changeset, _} -> | ||
Logger.error("Error enqueuing jobs: #{inspect(changeset)}") | ||
|
||
:error | ||
end | ||
end | ||
|
||
defp get_not_started_sections(_repo, _changes), | ||
do: {:ok, Sections.get_sections_by([v25_migration: :not_started], [:slug])} | ||
|
||
defp build_contained_objectives_jobs(%{sections: sections}), | ||
do: Enum.map(sections, &ContainedObjectivesBuilder.new(%{section_slug: &1.slug})) | ||
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,39 @@ | ||
defmodule Oli.Delivery.Sections.ContainedObjective do | ||
@moduledoc """ | ||
The ContainedObjective schema represents an association between section containers and objectives linked to the pages within them. | ||
It is created for optimization purposes since it provides a fast way of retrieving the objectives associated to the containers of a section. | ||
Given a section, each objective will have as many entries in the table as containers it is linked to. | ||
There will be always at least one entry per objective with the container_id being nil, which represents the inclusion of the objective in the root container. | ||
""" | ||
|
||
use Ecto.Schema | ||
import Ecto.Changeset | ||
|
||
alias Oli.Delivery.Sections.Section | ||
alias Oli.Resources.Resource | ||
|
||
schema "contained_objectives" do | ||
belongs_to(:section, Section) | ||
belongs_to(:container, Resource) | ||
belongs_to(:objective, Resource) | ||
|
||
timestamps(type: :utc_datetime) | ||
end | ||
|
||
@doc false | ||
def changeset(contained_page, attrs) do | ||
contained_page | ||
|> cast(attrs, [ | ||
:section_id, | ||
:container_id, | ||
:objective_id | ||
]) | ||
|> validate_required([ | ||
:section_id, | ||
:objective_id | ||
]) | ||
|> foreign_key_constraint(:section_id) | ||
|> foreign_key_constraint(:objective_id) | ||
end | ||
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,62 @@ | ||
defmodule Oli.Delivery.Sections.ContainedObjectivesBuilder do | ||
use Oban.Worker, | ||
queue: :objectives, | ||
unique: [keys: [:section_slug]], | ||
max_attempts: 1 | ||
|
||
alias Oli.Delivery.Sections.{ContainedObjective, Section} | ||
alias Oli.Delivery.Sections | ||
alias Oli.Repo | ||
alias Ecto.Multi | ||
|
||
@impl Oban.Worker | ||
def perform(%Oban.Job{args: %{"section_slug" => section_slug}}) do | ||
timestamps = %{ | ||
inserted_at: {:placeholder, :now}, | ||
updated_at: {:placeholder, :now} | ||
} | ||
|
||
placeholders = %{ | ||
now: DateTime.utc_now() |> DateTime.truncate(:second) | ||
} | ||
|
||
Multi.new() | ||
|> Multi.run( | ||
:contained_objectives, | ||
&Sections.build_contained_objectives(&1, &2, section_slug) | ||
) | ||
|> Multi.insert_all( | ||
:inserted_contained_objectives, | ||
ContainedObjective, | ||
&objectives_with_timestamps(&1, timestamps), | ||
placeholders: placeholders | ||
) | ||
|> Multi.run(:section, &find_section_by_slug(&1, &2, section_slug)) | ||
|> Multi.update( | ||
:done_section, | ||
&Section.changeset(&1.section, %{v25_migration: :done}) | ||
) | ||
|> Repo.transaction() | ||
|> case do | ||
{:ok, res} -> | ||
{:ok, res} | ||
|
||
{:error, _, changeset, _} -> | ||
{:error, changeset} | ||
end | ||
end | ||
|
||
defp objectives_with_timestamps(%{contained_objectives: contained_objectives}, timestamps) do | ||
Enum.map(contained_objectives, &Map.merge(&1, timestamps)) | ||
end | ||
|
||
defp find_section_by_slug(repo, _changes, section_slug) do | ||
case repo.get_by(Section, slug: section_slug) do | ||
nil -> | ||
{:error, :section_not_found} | ||
|
||
section -> | ||
{:ok, section} | ||
end | ||
end | ||
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.