Skip to content

Commit

Permalink
Updated Program APIs for WP
Browse files Browse the repository at this point in the history
  • Loading branch information
abdulmanann committed Nov 14, 2024
1 parent 1cd3fdd commit ab5758a
Show file tree
Hide file tree
Showing 6 changed files with 99 additions and 9 deletions.
27 changes: 21 additions & 6 deletions course_discovery/apps/api/serializers.py
Original file line number Diff line number Diff line change
Expand Up @@ -813,7 +813,8 @@ class Meta:
model = CourseRun
fields = ('key', 'uuid', 'title', 'external_key', 'image', 'short_description', 'marketing_url',
'seats', 'start', 'end', 'go_live_date', 'enrollment_start', 'enrollment_end',
'pacing_type', 'type', 'run_type', 'status', 'is_enrollable', 'is_marketable', 'term', 'subjects',)
'pacing_type', 'type', 'run_type', 'status', 'is_enrollable', 'is_marketable', 'term', 'subjects',
'card_image_url')

def get_marketing_url(self, obj):
include_archived = self.context.get('include_archived')
Expand Down Expand Up @@ -928,7 +929,7 @@ class Meta(MinimalCourseRunSerializer.Meta):
'first_enrollable_paid_seat_price', 'has_ofac_restrictions', 'ofac_comment',
'enrollment_count', 'recent_enrollment_count', 'expected_program_type', 'expected_program_name',
'course_uuid', 'estimated_hours', 'invite_only', 'subjects',
'is_marketing_price_set', 'marketing_price_value', 'is_marketing_price_hidden', 'featured', 'card_image_url',
'is_marketing_price_set', 'marketing_price_value', 'is_marketing_price_hidden', 'featured',
'average_rating', 'total_raters', 'yt_video_url', 'course_duration_override', 'course_difficulty',
'course_job_role', 'course_format', 'course_industry_certified_training', 'course_owner', 'course_language'
)
Expand Down Expand Up @@ -1483,6 +1484,7 @@ class MinimalProgramSerializer(DynamicFieldsMixin, BaseModelSerializer):

authoring_organizations = MinimalOrganizationSerializer(many=True)
banner_image = StdImageSerializerField(allow_null=True, required=False)
card_image = StdImageSerializerField(allow_null=True, required=False)
courses = serializers.SerializerMethodField()
type = serializers.SlugRelatedField(slug_field='slug', queryset=ProgramType.objects.all())
type_attrs = ProgramTypeAttrsSerializer(source='type')
Expand Down Expand Up @@ -1512,8 +1514,8 @@ class Meta:
model = Program
fields = (
'uuid', 'title', 'subtitle', 'type', 'type_attrs', 'status', 'marketing_slug', 'marketing_url',
'banner_image', 'hidden', 'courses', 'authoring_organizations', 'card_image_url',
'is_program_eligible_for_one_click_purchase', 'degree', 'curricula', 'marketing_hook',
'banner_image', 'card_image', 'hidden', 'courses', 'authoring_organizations', 'card_image_url',
'is_program_eligible_for_one_click_purchase', 'degree', 'curricula', 'marketing_hook', 'featured'
)
read_only_fields = ('uuid', 'marketing_url', 'banner_image')

Expand Down Expand Up @@ -1633,6 +1635,7 @@ class ProgramSerializer(MinimalProgramSerializer):
marketing_slug = CharField()
type_attrs = ProgramTypeAttrsSerializer(source='type', required=False)
curricula = CurriculumSerializer(many=True, required=False)
banner_image_url = serializers.URLField(required=False, allow_null=True)

@classmethod
def prefetch_queryset(cls, partner, queryset=None):
Expand Down Expand Up @@ -1678,7 +1681,7 @@ class Meta(MinimalProgramSerializer.Meta):
'faq', 'credit_backing_organizations', 'corporate_endorsements', 'job_outlook_items',
'individual_endorsements', 'languages', 'transcript_languages', 'subjects', 'price_ranges',
'staff', 'credit_redemption_overview', 'applicable_seat_types', 'instructor_ordering',
'enrollment_count', 'recent_enrollment_count', 'topics', 'credit_value',
'enrollment_count', 'recent_enrollment_count', 'topics', 'credit_value', 'banner_image_url'
)

def create(self, validated_data):
Expand Down Expand Up @@ -1720,6 +1723,10 @@ def update(self, instance, validated_data):
instance.min_hours_effort_per_week = validated_data.get('min_hours_effort_per_week', instance.min_hours_effort_per_week)
instance.max_hours_effort_per_week = validated_data.get('max_hours_effort_per_week', instance.max_hours_effort_per_week)
instance.marketing_slug = validated_data.get('marketing_slug', instance.marketing_slug)
instance.featured = validated_data.get('featured', instance.featured)
instance.overview = validated_data.get('overview', instance.overview)
instance.card_image = validated_data.get('card_image', instance.card_image)
instance.banner_image_url = validated_data.get('banner_image_url', instance.banner_image_url)

instance.save()

Expand Down Expand Up @@ -2451,7 +2458,15 @@ class Meta:
'subject_uuids',
'weeks_to_complete_max',
'weeks_to_complete_min',
'search_card_display'
'search_card_display',
'num_of_courses',
'featured',
'overview',
'banner_image_url',
'bundle_price',
'bundle_currency',
'created',
'title_override'
)


Expand Down
11 changes: 11 additions & 0 deletions course_discovery/apps/api/v1/views/search.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
from rest_framework.views import APIView

from course_discovery.apps.api import filters, mixins, serializers
from course_discovery.apps.api.utils import get_query_param
from course_discovery.apps.course_metadata.choices import ProgramStatus
from course_discovery.apps.course_metadata.models import Course, CourseRun, Person, Program

Expand Down Expand Up @@ -157,10 +158,20 @@ class ProgramSearchViewSet(BaseHaystackViewSet):
document_uid_field = 'uuid'
lookup_field = 'uuid'
index_models = (Program,)
ordering_fields = ('created', 'start', 'title', 'title_override')
filter_backends = [filters.HaystackFilter, OrderingFilter]
detail_serializer_class = serializers.ProgramSearchModelSerializer
facet_serializer_class = serializers.ProgramFacetSerializer
serializer_class = serializers.ProgramSearchSerializer

def get_serializer_context(self):
context = super().get_serializer_context()
query_params = ['exclude_utm', 'use_full_course_serializer', 'published_course_runs_only',
'marketable_enrollable_course_runs_with_archived']
for query_param in query_params:
context[query_param] = get_query_param(self.request, query_param)
return context


class AggregateSearchViewSet(BaseHaystackViewSet, CatalogDataViewSet):
""" Search all content types. """
Expand Down
4 changes: 2 additions & 2 deletions course_discovery/apps/course_metadata/admin.py
Original file line number Diff line number Diff line change
Expand Up @@ -203,8 +203,8 @@ class ProgramAdmin(admin.ModelAdmin):
'card_image', 'marketing_slug', 'overview', 'credit_redemption_overview', 'video', 'total_hours_of_effort',
'weeks_to_complete', 'min_hours_effort_per_week', 'max_hours_effort_per_week', 'courses',
'order_courses_by_start_date', 'custom_course_runs_display', 'excluded_course_runs', 'authoring_organizations',
'credit_backing_organizations', 'one_click_purchase_enabled', 'hidden', 'corporate_endorsements', 'faq',
'individual_endorsements', 'job_outlook_items', 'expected_learning_items', 'instructor_ordering',
'credit_backing_organizations', 'one_click_purchase_enabled', 'hidden', 'featured', 'corporate_endorsements',
'faq', 'individual_endorsements', 'job_outlook_items', 'expected_learning_items', 'instructor_ordering',
'enrollment_count', 'recent_enrollment_count', 'credit_value',
)

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
# Generated by Django 2.2.24 on 2024-10-31 09:17

from django.db import migrations, models


class Migration(migrations.Migration):

dependencies = [
('course_metadata', '0274_auto_20240911_0805'),
]

operations = [
migrations.AddField(
model_name='historicalprogram',
name='featured',
field=models.BooleanField(default=False),
),
migrations.AddField(
model_name='program',
name='featured',
field=models.BooleanField(default=False),
),
]
4 changes: 3 additions & 1 deletion course_discovery/apps/course_metadata/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -2162,6 +2162,8 @@ class Program(PkSearchableMixin, TimeStampedModel):
blank=True, default=0, help_text=_(
'Number of credits a learner will earn upon successful completion of the program')
)
featured = models.BooleanField(default=False)

objects = ProgramQuerySet.as_manager()

history = HistoricalRecords()
Expand Down Expand Up @@ -2233,7 +2235,7 @@ def weeks_to_complete_max(self):
@property
def marketing_url(self):
if self.marketing_slug:
path = '{type}/{slug}'.format(type=self.type.slug.lower(), slug=self.marketing_slug)
path = 'program/{slug}'.format(slug=self.marketing_slug)
return urljoin(self.partner.marketing_site_url_root, path)

return None
Expand Down
39 changes: 39 additions & 0 deletions course_discovery/apps/course_metadata/search_indexes.py
Original file line number Diff line number Diff line change
Expand Up @@ -350,6 +350,7 @@ class ProgramIndex(BaseIndex, indexes.Indexable, OrganizationsMixin):

uuid = indexes.CharField(model_attr='uuid')
title = indexes.CharField(model_attr='title', boost=TITLE_FIELD_BOOST)
title_override = indexes.CharField(indexed=False, stored=True)
title_autocomplete = indexes.NgramField(model_attr='title', boost=TITLE_FIELD_BOOST)
subtitle = indexes.CharField(model_attr='subtitle')
type = indexes.CharField(model_attr='type__name_t', faceted=True)
Expand All @@ -375,9 +376,16 @@ class ProgramIndex(BaseIndex, indexes.Indexable, OrganizationsMixin):
weeks_to_complete_max = indexes.IntegerField(model_attr='weeks_to_complete_max', null=True)
language = indexes.MultiValueField(faceted=True)
hidden = indexes.BooleanField(model_attr='hidden', faceted=True)
num_of_courses = indexes.IntegerField(null=True)
featured = indexes.BooleanField(model_attr='featured', faceted=True)
is_program_eligible_for_one_click_purchase = indexes.BooleanField(
model_attr='is_program_eligible_for_one_click_purchase', null=False
)
overview = indexes.CharField(model_attr='overview', null=True)
banner_image_url = indexes.CharField(null=True)
bundle_price = indexes.IntegerField(null=True)
bundle_currency = indexes.CharField(null=True)
created = indexes.DateTimeField(model_attr='created', null=True, faceted=True)

def prepare_aggregation_key(self, obj):
return 'program:{}'.format(obj.uuid)
Expand Down Expand Up @@ -410,6 +418,37 @@ def prepare_search_card_display(self, obj):

return []
return [degree.search_card_ranking, degree.search_card_cost, degree.search_card_courses]

def prepare_num_of_courses(self, obj):
return obj.courses.count()

def prepare_banner_image_url(self, obj):
if obj.banner_image_url:
return obj.banner_image_url
elif obj.banner_image:
return obj.banner_image.url
return None

def prepare_bundle_price(self, obj):
bundle_price = 0
course_runs = list(obj.course_runs)
for course_run in course_runs:
first_enrollable_paid_seat_price = course_run.first_enrollable_paid_seat_price
if first_enrollable_paid_seat_price:
bundle_price += first_enrollable_paid_seat_price
return bundle_price

def prepare_bundle_currency(self, obj):
course_runs = list(obj.course_runs)
if course_runs:
first_course_run = course_runs[0]
first_seat = first_course_run.seats.first()
if first_seat:
return first_seat.currency.code
return None

def prepare_title_override(self, obj):
return obj.title.title()


class PersonIndex(BaseIndex, indexes.Indexable):
Expand Down

0 comments on commit ab5758a

Please sign in to comment.