<commit_before>defmodule CoursePlanner.Terms do
  @moduledoc """
    Handle all interactions with Terms, create, list, fetch, edit, and delete
  """
  alias CoursePlanner.{Repo, OfferedCourse, Notifier}
  alias CoursePlanner.Terms.Term
  alias Ecto.{Changeset, DateTime}
  import Ecto.Query, only: [from: 2]

  def all do
    Repo.all(non_deleted_query())
  end

  def new do
    Term.changeset(%Term{holidays: [], courses: []})
  end

  def create(params) do
    %Term{}
    |> Term.changeset(params)
    |> Changeset.put_assoc(:offered_courses, course_changesets(params))
    |> Repo.insert
  end

  def course_changesets(%{"course_ids" => ids}) do
    Enum.map(ids, &OfferedCourse.add_to_term_changeset/1)
  end
  def course_changesets(_), do: []

  def get(id) do
    non_deleted_query()
    |> Repo.get(id)
    |> Repo.preload(:courses)
  end

  def edit(id) do
    case get(id) do
      nil -> {:error, :not_found}
      term -> {:ok, term, Term.changeset(term)}
    end
  end

  def update(id, params) do
    case get(id) do
      nil -> {:error, :not_found}
      term ->
        params = Map.put_new(params, "holidays", [])
        term
        |> Term.changeset(params)
        |> Changeset.put_assoc(:offered_courses, course_changesets(params))
        |> Repo.update
        |> format_update_error(term)
    end
  end

  defp format_update_error({:ok, _} = result, _), do: result
  defp format_update_error({:error, changeset}, term), do: {:error, term, changeset}

  def delete(id) do
    case get(id) do
      nil -> {:error, :not_found}
      term ->
        term
        |> Term.changeset()
        |> Changeset.put_change(:deleted_at, DateTime.utc())
        |> Repo.update()
    end
  end

  defp non_deleted_query do
    from t in Term, where: is_nil(t.deleted_at)
  end

  def notify_term_users(term, current_user, notification_type) do
    term
    |> get_enrolled_students()
    |> Enum.reject(fn %{id: id} -> id == current_user.id end)
    |> Enum.each(&(Notifier.notify_user(&1, notification_type)))
  end

  defp get_enrolled_students(term) do
    term
    |> Repo.preload([:offered_courses, offered_courses: :students])
    |> Map.get(:offered_courses)
    |> Enum.map(&(Map.get(&1, :students)))
    |> List.flatten()
  end
end
<commit_msg>Notify students, teachers and coordinators.<commit_after>defmodule CoursePlanner.Terms do
  @moduledoc """
    Handle all interactions with Terms, create, list, fetch, edit, and delete
  """
  alias CoursePlanner.{Repo, OfferedCourse, Notifier, Coordinators}
  alias CoursePlanner.Terms.Term
  alias Ecto.{Changeset, DateTime}
  import Ecto.Query, only: [from: 2]

  def all do
    Repo.all(non_deleted_query())
  end

  def new do
    Term.changeset(%Term{holidays: [], courses: []})
  end

  def create(params) do
    %Term{}
    |> Term.changeset(params)
    |> Changeset.put_assoc(:offered_courses, course_changesets(params))
    |> Repo.insert
  end

  def course_changesets(%{"course_ids" => ids}) do
    Enum.map(ids, &OfferedCourse.add_to_term_changeset/1)
  end
  def course_changesets(_), do: []

  def get(id) do
    non_deleted_query()
    |> Repo.get(id)
    |> Repo.preload(:courses)
  end

  def edit(id) do
    case get(id) do
      nil -> {:error, :not_found}
      term -> {:ok, term, Term.changeset(term)}
    end
  end

  def update(id, params) do
    case get(id) do
      nil -> {:error, :not_found}
      term ->
        params = Map.put_new(params, "holidays", [])
        term
        |> Term.changeset(params)
        |> Changeset.put_assoc(:offered_courses, course_changesets(params))
        |> Repo.update
        |> format_update_error(term)
    end
  end

  defp format_update_error({:ok, _} = result, _), do: result
  defp format_update_error({:error, changeset}, term), do: {:error, term, changeset}

  def delete(id) do
    case get(id) do
      nil -> {:error, :not_found}
      term ->
        term
        |> Term.changeset()
        |> Changeset.put_change(:deleted_at, DateTime.utc())
        |> Repo.update()
    end
  end

  defp non_deleted_query do
    from t in Term, where: is_nil(t.deleted_at)
  end

  def notify_term_users(term, current_user, notification_type) do
    term
    |> get_subscribed_users()
    |> Enum.reject(fn %{id: id} -> id == current_user.id end)
    |> Enum.each(&(Notifier.notify_user(&1, notification_type)))
  end

  defp get_subscribed_users(term) do
    offered_courses = term
    |> Repo.preload([:offered_courses, offered_courses: :students, offered_courses: :teachers])
    |> Map.get(:offered_courses)

    students = offered_courses
    |> Enum.flat_map(&(Map.get(&1, :students)))
    |> Enum.uniq_by(fn %{id: id} -> id end)

    teachers = offered_courses
    |> Enum.flat_map(&(Map.get(&1, :teachers)))
    |> Enum.uniq_by(fn %{id: id} -> id end)

    students ++ teachers ++ Coordinators.all()
  end
end

{'fraction_non_alphanumeric': 0.13790970933828076, 'fraction_numerical': 0.0018552875695732839, 'mean_word_length': 3.1612349914236706, 'pattern_counts': {'":': 0, '<': 3, '<?xml version=': 0, '>': 61, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '3264321', 'n_tokens_mistral': 1781, 'n_tokens_neox': 1711, 'n_words': 370}