Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Dote dev #83

Merged
merged 9 commits into from
Nov 15, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 4 additions & 2 deletions app/configurations/admin.py
Original file line number Diff line number Diff line change
Expand Up @@ -32,11 +32,13 @@ class CourseInformationMappingAdmin(admin.ModelAdmin):
'course_type', 'course_time',
'course_instructor', 'course_deliveryMode',
'course_thumbnail', 'course_derived_from',
'course_competency', 'xds_ui_configuration')
'course_competency', 'course_subject',
'xds_ui_configuration')
fields = ['course_title', 'course_description',
'course_url', 'course_code', 'course_startDate',
'course_endDate', 'course_provider',
'course_type', 'course_time',
'course_instructor', 'course_deliveryMode',
'course_thumbnail', 'course_derived_from',
'course_competency', 'xds_ui_configuration']
'course_competency', 'course_subject',
'xds_ui_configuration']
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
# Generated by Django 4.2.16 on 2024-11-08 18:40

from django.db import migrations, models


class Migration(migrations.Migration):

dependencies = [
('configurations', '0010_merge_20241026_0049'),
]

operations = [
migrations.AlterField(
model_name='courseinformationmapping',
name='course_derived_from',
field=models.CharField(default='P2881-Core.DerivedFrom', help_text='Enter the mapping for the reference to the course derived from found in the elasticsearch', max_length=200),
),
]
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
# Generated by Django 4.2.16 on 2024-11-08 20:05

from django.db import migrations, models


class Migration(migrations.Migration):

dependencies = [
('configurations', '0011_alter_courseinformationmapping_course_derived_from'),
]

operations = [
migrations.AddField(
model_name='courseinformationmapping',
name='course_subject',
field=models.CharField(default='p2881-core.Subject', help_text='Enter the mapping for the course subject', max_length=200),
),
]
7 changes: 6 additions & 1 deletion app/configurations/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -198,7 +198,7 @@ class CourseInformationMapping(TimeStampedModel):
" elasticsearch")

course_derived_from = models.CharField(max_length=200,
default="P2881_Core.DerivedFrom",
default="P2881-Core.DerivedFrom",
help_text="Enter the mapping for "
"the reference to the "
"course derived from found in the"
Expand All @@ -211,6 +211,11 @@ class CourseInformationMapping(TimeStampedModel):
"the reference to the "
"competency taught")

course_subject = models.CharField(max_length=200,
default="p2881-core.Subject",
help_text="Enter the mapping for "
"the course subject")

xds_ui_configuration = models \
.OneToOneField(XDSUIConfiguration,
on_delete=models.CASCADE,
Expand Down
10 changes: 9 additions & 1 deletion app/core/admin.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
from core.models import (CourseDetailHighlight, CourseSpotlight, Experience,
InterestList, SavedFilter, SearchFilter,
SearchSortOption)
SearchSortOption, SearchField)
from django.contrib import admin


Expand All @@ -12,6 +12,14 @@ class SearchFilterAdmin(admin.ModelAdmin):
'filter_type', 'active',)]


@admin.register(SearchField)
class SearchFieldAdmin(admin.ModelAdmin):
list_display = ('display_name', 'field_name', 'xds_ui_configuration',
'active', 'created', 'modified',)
fields = [('display_name', 'field_name', 'xds_ui_configuration',
'active',)]


@admin.register(SearchSortOption)
class SearchSortOptionAdmin(admin.ModelAdmin):
list_display = ('display_name', 'field_name', 'xds_ui_configuration',
Expand Down
32 changes: 32 additions & 0 deletions app/core/migrations/0009_searchfield.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
# Generated by Django 4.2.16 on 2024-11-08 18:40

from django.db import migrations, models
import django.db.models.deletion
import django.utils.timezone
import model_utils.fields


class Migration(migrations.Migration):

dependencies = [
('configurations', '0011_alter_courseinformationmapping_course_derived_from'),
('core', '0008_alter_coursedetailhighlight_rank'),
]

operations = [
migrations.CreateModel(
name='SearchField',
fields=[
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('created', model_utils.fields.AutoCreatedField(default=django.utils.timezone.now, editable=False, verbose_name='created')),
('modified', model_utils.fields.AutoLastModifiedField(default=django.utils.timezone.now, editable=False, verbose_name='modified')),
('display_name', models.CharField(help_text='Enter the display name of the field to search by on', max_length=200)),
('field_name', models.CharField(help_text='Enter the metadata field name as displayed in Elasticsearch e.g. course.title', max_length=200)),
('active', models.BooleanField(default=True)),
('xds_ui_configuration', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='configurations.xdsuiconfiguration')),
],
options={
'abstract': False,
},
),
]
24 changes: 24 additions & 0 deletions app/core/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,30 @@ def __str__(self):
return f'{self.id}'


class SearchField(TimeStampedModel):
"""Model to add aditional fields to search by"""
display_name = models.CharField(
max_length=200,
help_text='Enter the display name of the field to search by on')
field_name = models.CharField(
max_length=200,
help_text='Enter the metadata field name as displayed in Elasticsearch'
' e.g. course.title'
)
xds_ui_configuration = models.ForeignKey(XDSUIConfiguration,
on_delete=models.CASCADE)

active = models.BooleanField(default=True)

def get_absolute_url(self):
""" URL for displaying individual model records."""
return reverse('Configuration-detail', args=[str(self.id)])

def __str__(self):
"""String for representing the Model object."""
return f'{self.id}'


class SearchSortOption(TimeStampedModel):
"""Model to contain options for sorting search results"""

Expand Down
2 changes: 2 additions & 0 deletions app/es_api/urls.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,4 +15,6 @@
name='search-derived'),
path('teaches/', views.SearchCompetencyView.as_view(),
name='search-competency'),
path('similar-courses/<str:key>/', views.GetSimilarCoursesView.
as_view(), name='get-similar-courses')
]
37 changes: 34 additions & 3 deletions app/es_api/utils/queries.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,8 @@
import logging

from configurations.models import CourseInformationMapping, XDSConfiguration
from core.models import CourseSpotlight, SearchFilter, SearchSortOption
from core.models import (CourseSpotlight, SearchFilter,
SearchSortOption, SearchField)
from django.core.exceptions import ObjectDoesNotExist
from elasticsearch_dsl import A, Document, Q
from elasticsearch_dsl.query import MoreLikeThis
Expand Down Expand Up @@ -85,8 +86,9 @@ def search_by_keyword(self, keyword="", filters={}):
course_mapping.course_code, course_mapping.course_provider,
course_mapping.course_instructor,
course_mapping.course_deliveryMode,
'Course.CourseTitle', 'Course.ShortDescription',
'Course.CourseCode', 'Course.CourseProviderName'
course_mapping.course_competency,
*SearchField.objects.filter(
active=True).values_list('field_name', flat=True)
]

q = Q("multi_match",
Expand Down Expand Up @@ -211,6 +213,35 @@ def more_like_this(self, doc_id):

return response

def similar_courses(self, keyword=""):
"""This method takes in a keyword and queries the elasticsearch index
for 4 courses with similar competencies or subjects"""

course_mapping = CourseInformationMapping.objects.first()
fields = [
course_mapping.course_competency,
course_mapping.course_subject
]

# We're going to match based only on two fields
q = Q("multi_match",
query=keyword,
fields=fields)

# setting up the search object
self.search = self.search.query(q)

self.user_organization_filtering()

# sending back 4 responses
self.search = self.search[0:4]

# call to elasticsearch to execute the query
response = self.search.execute()
logger.info(self.search.to_dict())

return response

def spotlight_courses(self):
"""This method queries elasticsearch for courses with ids matching the
ids of stored CourseSpotlight objects that are active"""
Expand Down
46 changes: 45 additions & 1 deletion app/es_api/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -208,7 +208,8 @@ def get(self, request):

class GetMoreLikeThisView(APIView):
"""This method defines an API for fetching results using the
more_like_this feature from elasticsearch. """
more_like_this feature from elasticsearch for
more like this courses section of UI. """

def get(self, request, doc_id):
results = []
Expand Down Expand Up @@ -239,6 +240,49 @@ def get(self, request, doc_id):
return HttpResponse(results, content_type="application/json")


class GetSimilarCoursesView(APIView):
"""This method defines an API for fetching results by sending key words
to elasticsearch and looking for similar courses. """

def get(self, request, key):
results = []

if key != '':
errorMsg = {
"message": "error executing ElasticSearch query; " +
"Please contact an administrator"
}
errorMsgJSON = json.dumps(errorMsg)

try:

queries = XSEQueries(
XDSConfiguration.objects.first().target_xse_host,
XDSConfiguration.objects.first().target_xse_index,
user=request.user)
response = queries.similar_courses(
keyword=key)
results = queries.get_results(response)
except HTTPError as http_err:
logger.error(http_err)
return HttpResponseServerError(errorMsgJSON,
content_type="application/json")
except Exception as err:
logger.error(err)
return HttpResponseServerError(errorMsgJSON,
content_type="application/json")
else:
logger.info(results)
return HttpResponse(results, content_type="application/json")
else:
error = {
"message": "Request is missing 'key' query paramater"
}
errorJson = json.dumps(error)
return HttpResponseBadRequest(errorJson,
content_type="application/json")


class FiltersView(APIView):
"""This method defines an API for performing a filter search"""

Expand Down
Loading