defmodule Ami.Lesson do # import Ecto.Query use Ecto.Schema alias Ami.{ Tag, Repo, Unit, Quiz, Post, Video, Score, Resource, UserAnswer, UnitLesson, LessonResource, LessonActivity, LessonMainResource, ResourceAttachment } schema "lessons" do field(:title, :string) field(:description, :string) field(:created_at, :utc_datetime) field(:updated_at, :utc_datetime) field(:paid, :boolean) # belongs_to(:unit, Unit) has_many(:unit_lessons, UnitLesson) has_many(:units, through: [:unit_lessons, :unit]) has_one(:main_resource, LessonMainResource) has_one(:main_resource_attachment, through: [:main_resource, :resource_attachment]) has_one(:lesson_activity, LessonActivity) has_one(:lesson_activity_attachment, through: [:lesson_activity, :resource_attachment]) has_many(:lessons_resources, LessonResource) has_many(:resource_attachments, through: [:lessons_resources, :resource_attachment]) many_to_many(:tags, Tag, join_through: "lessons_tags", on_replace: :delete) # In Rails we had a polymorphic association for this which is not implemented in Ecto # Scope is also not possible in Ecto so check function with_preloaded_videos function for more information. has_many(:videos, Video, foreign_key: :videoable_id) # Also a polymorphic association has_many(:resources, Resource, foreign_key: :resourceable_id) has_many(:posts, Post) has_one(:quiz, Quiz) end @doc """ Because of better design patterns implemented by Ecto we cannot return lesson.videos to return correct videos. preload_videos implement a pattern which will return lesson.videos to return only videos with videoable_type == "Lesson" for the given lesson """ def preload_videos(struct), do: Video.preload_videos(struct, "Lesson") @doc """ Pattern to fetch resources as lesson.resources with resourceable_type == "Lesson" """ def preload_resources(struct), do: Resource.preload_resources(struct, "Lesson") @doc """ Check if the lesson is completed or not """ def completed?(lesson, enrollment) do lesson = Repo.preload(lesson, [:quiz]) if lesson.quiz do if !lesson.quiz.is_final do find(Score, lesson.quiz.id, enrollment.course_period_id, enrollment.user_id, enrollment.id) != nil else find(Score, lesson.quiz.id, enrollment.course_period_id, enrollment.user_id, enrollment.id) != nil && enrollment.assignment_status == "accepted" end end end # Helper to find User Answers or Score with smiliar arguments defp find(module, quiz_id, course_period_id, user_id) do Repo.get_by(module, quiz_id: quiz_id, course_period_id: course_period_id, user_id: user_id) end defp find(module, quiz_id, course_period_id, user_id, enrollment_id) do Repo.get_by(module, quiz_id: quiz_id, course_period_id: course_period_id, user_id: user_id, enrollment_id: enrollment_id) end @doc """ Helper checking if a lesson has got an 'Activity' resource """ def has_activity?(lesson) do lesson = Repo.preload(lesson, :lesson_activity) !is_nil(lesson.lesson_activity) end end