Packages

Package containing all AMI Models shared between micro-services.

Retired package: Deprecated - faulty

Current section

Files

Jump to
ami_models lib ami course.ex
Raw

lib/ami/course.ex

defmodule Ami.Course do
use Ecto.Schema
import Ecto.{
Query
}
alias Ami.{
Tag,
User,
Repo,
Quiz,
Unit,
Score,
Video,
Course,
Answer,
Package,
Resource,
Community,
UnitLesson,
ThumbImage,
TeaserImage,
CoursePeriod,
AffiliateLogo,
CourseResource,
ResourceAttachment,
ThumbImageAttachment,
TeaserImageAttachment,
AffiliateLogoAttachment
}
schema "courses" do
field(:title, :string)
field(:description, :string)
field(:instructor, :string)
field(:image, :string)
# field(:tags, {:array, :string})
field(:created_at, :utc_datetime)
field(:updated_at, :utc_datetime)
field(:sort, :integer)
field(:why_take_course, :string)
field(:components, :string)
field(:total_hours, :integer)
field(:inactive_teaser_link, :string)
field(:subtitle, :string)
field(:acceptance_score, :integer)
field(:free_course, :boolean)
field(:on_air, :boolean)
field(:teaser_description, :string)
field(:teaser_banner_text, :string)
field(:price, :integer)
field(:certificate_price, :boolean)
field(:access_price, :boolean)
field(:price_currency, :string)
field(:slug, :string)
field(:is_featured, :boolean)
field(:marking_guide, :string)
belongs_to(:course_admin, User, foreign_key: :course_admin_id)
# belongs_to(:quiz, Quiz)
belongs_to(:pre_assessment_quiz, Quiz)
# belongs_to(:final_exam, Quiz)
belongs_to(:community, Community)
many_to_many(:instructors, User,
join_through: "courses_users",
join_keys: [course_id: :id, user_id: :id],
on_delete: :delete_all
)
has_many(:course_periods, CoursePeriod)
has_many(:videos, Video, foreign_key: :videoable_id)
has_many(:units, Unit)
has_many(:lessons, through: [:units, :lessons])
has_many(:quizzes, through: [:lessons, :quiz])
# Also a polymorphic association
# has_many(:resources, Resource, foreign_key: :resourceable_id)
# has_many(:teaser_images, TeaserImage, foreign_key: :teaseable_id)
has_many(:teaser_image_attachments, TeaserImageAttachment,
on_delete: :delete_all,
on_replace: :delete
)
has_many(:thumb_image_attachments, ThumbImageAttachment,
on_delete: :delete_all,
on_replace: :delete
)
has_many(:affiliate_logo_attachments, AffiliateLogoAttachment,
on_delete: :delete_all,
on_replace: :delete
)
has_many(:courses_resources, CourseResource)
has_many(:resource_attachments,
through: [:courses_resources, :resource_attachment],
on_delete: :delate_all,
on_replace: :delete
)
# has_many(:affiliate_logos, AffiliateLogo)
many_to_many(:tags, Tag,
join_through: "courses_tags",
on_replace: :delete,
on_delete: :delete_all
)
has_many(:thumb_images, ThumbImage)
# has_many(:affiliate_logos, AffiliateLogo)
# has_many(:scores, Score)
# has_many(:lessons, through: [:units, :lessons])
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, "Course")
@doc """
Pattern to fetch resources as lesson.resources with resourceable_type == "Lesson"
"""
def preload_resources(struct), do: Resource.preload_resources(struct, "Course")
@doc """
Fetch courses to display on the my_courses page tailored for given user
If given user is business member (2), fetch:
- courses with open course periods belonging to the communities the user is member of
- courses with open course periods belonging to the communities the user is moderator of
If given user is member (1), fetch above plus the followings:
- 'on air' featured courses
- 'on air' open public courses
- 'on air' closed public courses
If given user is non-member (0) fetch:
- 'on air' public courses
- 'on air' courses with course periods belonging to communities
- 'on air' courses with course periods belonging to 'Universal' and 'Public' communities
"""
def catalog_for(user_struct) do
case user_struct.status do
0 ->
courses_list = fetch_courses_for_nonmember(user_struct)
packages_list = Package.on_air()
%{courses: courses_list, packages: packages_list}
1 ->
courses_list = fetch_courses_for_member(user_struct)
packages_list = Package.on_air()
%{courses: courses_list, packages: packages_list}
2 ->
%{courses: CoursePeriod.open_community_courses_for(user_struct), packages: []}
end
end
def catalog_for(user_struct, type) do
courses_list =
case type do
"community" ->
CoursePeriod.open_community_courses_for(user_struct)
|> add_universal_public_community_courses(user_struct)
|> Enum.uniq_by(fn %CoursePeriod{} = cp -> cp.course_id end)
"public" ->
CoursePeriod.for_open_on_air_public_courses()
"package" ->
[]
"learning_lab" ->
CoursePeriod.for_learning_lab()
end
packages_list =
case type do
"community" ->
[]
"public" ->
packages_list_for(user_struct)
"package" ->
packages_list_for(user_struct)
"learning_lab" ->
[]
end
%{courses: courses_list, packages: packages_list}
end
def catalog_of_open_public_cp() do
Repo.all(from(c in __MODULE__, where: c.on_air == true))
|> Enum.map(
&(CoursePeriod.fetch_current_public_course_periods_for(&1)
|> List.first())
)
|> Enum.reject(&is_nil(&1))
end
defp add_universal_public_community_courses(cp_list, user_struct) do
if user_struct.status == 0 do
Enum.concat(cp_list, CoursePeriod.for_open_onair_universalpublic_community_courses())
else
cp_list
end
end
defp packages_list_for(user_struct) do
if user_struct.status in [0, 1], do: Package.on_air(), else: []
end
defp fetch_courses_for_nonmember(user_struct) do
CoursePeriod.for_open_on_air_public_courses()
|> Enum.concat(CoursePeriod.open_community_courses_for(user_struct))
|> Enum.concat(CoursePeriod.for_open_onair_universalpublic_community_courses())
|> Enum.uniq_by(fn %CoursePeriod{} = cp -> cp.course_id end)
end
defp fetch_courses_for_member(user_struct) do
CoursePeriod.for_on_air_featured_courses()
|> Enum.concat(CoursePeriod.open_community_courses_for(user_struct))
|> Enum.concat(CoursePeriod.for_open_on_air_public_courses())
|> Enum.uniq_by(fn %CoursePeriod{} = cp -> cp.course_id end)
end
def topics_for(course_struct) do
Repo.preload(course_struct, units: from(u in Unit, order_by: u.id)).units
|> Enum.map(fn u -> u.title end)
|> Enum.drop(-1)
end
def distinct_instructors(course) do
course.instructors |> Enum.dedup_by(fn e -> e.id end)
end
def unit_exams(%Course{} = course) do
query =
from(
q in Quiz,
join: l in assoc(q, :lesson),
join: ul in assoc(l, :unit_lessons),
join: u in assoc(ul, :unit),
join: c in assoc(u, :course),
where: c.id == ^course.id,
where: q.is_graded == true,
where: q.is_final == false
)
Repo.all(query)
end
def graded_exams(%Course{} = course) do
query =
from(
q in Quiz,
join: l in assoc(q, :lesson),
join: ul in assoc(l, :unit_lessons),
join: u in assoc(ul, :unit),
join: c in assoc(u, :course),
where: c.id == ^course.id,
where: q.is_graded == true or q.is_final == true
)
Repo.all(query)
end
def final_exam(course_id) do
query =
from(
q in Quiz,
where: q.is_final == true,
join: l in assoc(q, :lesson),
join: ul in assoc(l, :unit_lessons),
join: u in assoc(ul, :unit),
# join: c in assoc(u, :course),
where: u.course_id == ^course_id
)
Repo.one(query)
end
def pre_assessment_quiz(course) do
Repo.preload(course, [:quizzes]).quizzes
|> Enum.find(fn q -> q.is_pre end)
|> Repo.preload(questions: :answers)
end
def marking_guide_url({id, marking_guide}) do
case marking_guide do
nil ->
""
_ ->
"https://ami-aws-s3.s3.amazonaws.com/uploads/#{marking_guide}"
end
end
def has_intro_activity?(course) do
intro_unit = List.first(course.units)
lesson = List.first(intro_unit.lessons) |> Repo.preload([:lesson_activity])
!is_nil(lesson.lesson_activity)
end
def intro_activity_url(course) do
intro_unit = List.first(course.units)
lesson =
List.first(intro_unit.lessons)
|> Repo.preload([:lesson_activity_attachment])
ResourceAttachment.file_url(
{lesson.lesson_activity_attachment.id, lesson.lesson_activity_attachment.file}
)
end
def unit_for_lesson(course, lesson) do
query =
from(
u in Unit,
join: ul in assoc(u, :unit_lessons),
join: l in assoc(ul, :lesson),
where: u.course_id == ^course.id,
where: l.id == ^lesson.id,
order_by: [asc: ul.position]
)
Repo.one(query)
|> Repo.preload(unit_lessons: {from(ul in UnitLesson, order_by: ul.position), [:lesson]})
|> Repo.preload(:lessons)
end
end