feat!: remove skill_levels API (#35863)

Resolves issue #35302 (https://github.com/openedx/edx-platform/issues/35302).
This commit is contained in:
Justin Hynes
2024-11-15 09:37:37 -05:00
committed by GitHub
parent ec68ee4a91
commit 7adecb4c6c
11 changed files with 0 additions and 819 deletions

View File

@@ -9291,21 +9291,6 @@ paths:
in: path
required: true
type: string
/user/v1/skill_level/{job_id}/:
get:
operationId: user_v1_skill_level_read
description: GET /api/user/v1/skill_level/{job_id}/
parameters: []
responses:
'200':
description: ''
tags:
- user
parameters:
- name: job_id
in: path
required: true
type: string
/user/v1/user_prefs/:
get:
operationId: user_v1_user_prefs_list

View File

@@ -1,31 +0,0 @@
"""
APIs for learner skill levels.
"""
from .utils import get_skills_score, calculate_user_skill_score, generate_skill_score_mapping
def get_learner_skill_levels(user, top_categories):
"""
Evaluates learner's skill levels in the given job category. Only considers skills for the categories
and not their sub-categories.
Params:
user: user for each score is being calculated.
top_categories (List, string): A list of fields (as strings) of job categories and their skills.
Returns:
top_categories: Categories with scores appended to skills.
"""
# get a skill to score mapping for every course user has passed
skill_score_mapping = generate_skill_score_mapping(user)
for skill_category in top_categories:
category_skills = skill_category['skills']
get_skills_score(category_skills, skill_score_mapping)
skill_category['user_score'] = calculate_user_skill_score(category_skills)
skill_category['edx_average_score'] = None
sub_categories = skill_category['skills_subcategories']
for sub_category in sub_categories:
subcategory_skills = sub_category['skills']
get_skills_score(subcategory_skills, skill_score_mapping)
return top_categories

View File

@@ -1,8 +0,0 @@
"""
Constants for learner skill levels app.
"""
LEVEL_TYPE_SCORE_MAPPING = {
'Introductory': 1,
'Intermediate': 2,
'Advanced': 3
}

View File

@@ -1,219 +0,0 @@
""" Unit tests for Learner Skill Levels utilities. """
import ddt
from collections import defaultdict
from unittest import mock
from rest_framework.test import APIClient
from common.djangoapps.student.tests.factories import UserFactory
from openedx.core.djangoapps.catalog.tests.mixins import CatalogIntegrationMixin
from openedx.core.djangoapps.user_api.learner_skill_levels.utils import (
calculate_user_skill_score,
generate_skill_score_mapping,
get_base_url,
get_job_holder_usernames,
get_skills_score,
get_top_skill_categories_for_job,
update_category_user_scores_map,
update_edx_average_score,
)
from xmodule.modulestore.tests.django_utils import SharedModuleStoreTestCase
from .testutils import (
DUMMY_CATEGORIES_RESPONSE,
DUMMY_CATEGORIES_WITH_SCORES,
DUMMY_USERNAMES_RESPONSE,
DUMMY_COURSE_DATA_RESPONSE,
DUMMY_USER_SCORES_MAP,
)
@ddt.ddt
class LearnerSkillLevelsUtilsTests(SharedModuleStoreTestCase, CatalogIntegrationMixin):
"""
Test LearnerSkillLevel utilities.
"""
SERVICE_USERNAME = 'catalog_service_username'
def setUp(self):
"""
Unit tests setup.
"""
super().setUp()
self.client = APIClient()
self.service_user = UserFactory(username=self.SERVICE_USERNAME)
self.catalog_integration = self.create_catalog_integration()
@mock.patch('openedx.core.djangoapps.user_api.learner_skill_levels.utils.get_course_run_ids')
@mock.patch('openedx.core.djangoapps.user_api.learner_skill_levels.utils.get_course_run_data')
@mock.patch('openedx.core.djangoapps.user_api.learner_skill_levels.utils.get_course_data')
def test_generate_skill_score_mapping(
self,
mock_get_course_data,
mock_get_course_run_data,
mock_get_course_run_ids,
):
"""
Test that skill-score mapping is returned in correct format.
"""
user = UserFactory(username='edX')
mock_get_course_run_ids.return_value = ['course-v1:AWS+OTP-AWSD12']
mock_get_course_run_data.return_value = {'course': 'AWS+OTP'}
mock_get_course_data.return_value = DUMMY_COURSE_DATA_RESPONSE
result = generate_skill_score_mapping(user)
expected_response = {"python": 3, "MongoDB": 3, "Data Science": 3}
assert result == expected_response
@ddt.data(
([], 0.0),
(
[
{"id": 1, "name": "Financial Management", "score": None},
{"id": 2, "name": "Fintech", "score": None},
], 0.0
),
(
[
{"id": 1, "name": "Financial Management", "score": None},
{"id": 2, "name": "Fintech", "score": None},
], 0.0
),
(
[
{"id": 1, "name": "Financial Management", "score": 3},
{"id": 2, "name": "Fintech", "score": 2},
], 0.8
),
)
@ddt.unpack
def test_calculate_user_skill_score(self, skills_with_score, expected):
"""
Test that skill-score mapping is returned in correct format.
"""
result = calculate_user_skill_score(skills_with_score)
assert result == expected
@ddt.data(
([], {"Financial Management": 1, "Fintech": 3}, []),
(
[
{"id": 1, "name": "Financial Management"},
{"id": 2, "name": "Fintech"},
],
{
"Financial Management": 1,
"Fintech": 3
},
[
{"id": 1, "name": "Financial Management", "score": 1},
{"id": 2, "name": "Fintech", "score": 3},
],
),
(
[
{"id": 1, "name": "Financial Management"},
{"id": 2, "name": "Fintech"},
],
{},
[
{"id": 1, "name": "Financial Management", "score": None},
{"id": 2, "name": "Fintech", "score": None},
],
),
(
[
{"id": 1, "name": "Financial Management"},
{"id": 2, "name": "Fintech"},
],
{
"Python": 1,
"AI": 3
},
[
{"id": 1, "name": "Financial Management", "score": None},
{"id": 2, "name": "Fintech", "score": None},
],
),
)
@ddt.unpack
def test_get_skills_score(self, skills, learner_skill_score, expected):
"""
Test that skill-score mapping is returned in correct format.
"""
get_skills_score(skills, learner_skill_score)
assert skills == expected
def test_update_category_user_scores_map(self):
"""
Test that skill-score mapping is returned in correct format.
"""
category_user_scores_map = defaultdict(list)
update_category_user_scores_map(DUMMY_CATEGORIES_WITH_SCORES["skill_categories"], category_user_scores_map)
expected = {"Information Technology": [0.8], "Finance": [0.3]}
assert category_user_scores_map == expected
def test_update_edx_average_score(self):
"""
Test that skill-score mapping is returned in correct format.
"""
update_edx_average_score(DUMMY_CATEGORIES_WITH_SCORES["skill_categories"], DUMMY_USER_SCORES_MAP)
assert DUMMY_CATEGORIES_WITH_SCORES["skill_categories"][0]["edx_average_score"] == 0.4
assert DUMMY_CATEGORIES_WITH_SCORES["skill_categories"][1]["edx_average_score"] == 0.5
@ddt.data(
("http://localhost:18000/api/", "http://localhost:18000"),
("http://localhost:18000/", "http://localhost:18000"),
)
@ddt.unpack
def test_get_base_url(self, source_url, expected):
"""
Test that base url is returned correctly.
"""
actual = get_base_url(source_url)
assert actual == expected
@mock.patch('openedx.core.djangoapps.user_api.learner_skill_levels.utils.get_catalog_api_client')
@mock.patch('openedx.core.djangoapps.user_api.learner_skill_levels.utils.get_catalog_api_base_url')
@mock.patch('openedx.core.djangoapps.user_api.learner_skill_levels.utils.get_api_data')
@mock.patch('openedx.core.djangoapps.user_api.learner_skill_levels.utils.check_catalog_integration_and_get_user')
def test_get_top_skill_categories_for_job(
self,
mock_check_catalog_integration_and_get_user,
mock_get_api_data,
mock_get_catalog_api_base_url,
mock_get_catalog_api_client
):
"""
Test that get_top_skill_categories_for_job returns jobs categories.
"""
mock_check_catalog_integration_and_get_user.return_value = self.service_user, self.catalog_integration
mock_get_api_data.return_value = DUMMY_CATEGORIES_RESPONSE
mock_get_catalog_api_base_url.return_value = 'localhost:18381/api'
mock_get_catalog_api_client.return_value = self.client
result = get_top_skill_categories_for_job(1)
assert result == DUMMY_CATEGORIES_RESPONSE
@mock.patch('openedx.core.djangoapps.user_api.learner_skill_levels.utils.get_catalog_api_client')
@mock.patch('openedx.core.djangoapps.user_api.learner_skill_levels.utils.get_catalog_api_base_url')
@mock.patch('openedx.core.djangoapps.user_api.learner_skill_levels.utils.get_api_data')
@mock.patch('openedx.core.djangoapps.user_api.learner_skill_levels.utils.check_catalog_integration_and_get_user')
def test_get_job_holder_usernames(
self,
mock_check_catalog_integration_and_get_user,
mock_get_api_data,
mock_get_catalog_api_base_url,
mock_get_catalog_api_client
):
"""
Test that test_get_job_holder_usernames returns usernames.
"""
mock_check_catalog_integration_and_get_user.return_value = self.service_user, self.catalog_integration
mock_get_api_data.return_value = DUMMY_USERNAMES_RESPONSE
mock_get_catalog_api_base_url.return_value = 'localhost:18381/api'
mock_get_catalog_api_client.return_value = self.client
result = get_job_holder_usernames(1)
assert result == DUMMY_USERNAMES_RESPONSE

View File

@@ -1,119 +0,0 @@
"""
Test cases for LearnerSkillLevelsView.
"""
from unittest import mock
from django.urls import reverse
from rest_framework.test import APIClient, APITestCase
from common.djangoapps.student.tests.factories import TEST_PASSWORD, UserFactory
from .testutils import DUMMY_CATEGORIES_RESPONSE, DUMMY_USERNAMES_RESPONSE
class LearnerSkillLevelsViewTests(APITestCase):
"""
The tests for LearnerSkillLevelsView.
"""
def setUp(self):
super().setUp()
self.client = APIClient()
self.user = UserFactory.create(password=TEST_PASSWORD)
self.url = reverse('learner_skill_level', kwargs={'job_id': '1'})
for username in DUMMY_USERNAMES_RESPONSE['usernames']:
UserFactory(username=username)
def test_unauthorized_get_endpoint(self):
"""
Test that endpoint is only accessible to authorized user.
"""
response = self.client.get(self.url)
assert response.status_code == 401
@mock.patch('openedx.core.djangoapps.user_api.learner_skill_levels.views.get_top_skill_categories_for_job')
@mock.patch('openedx.core.djangoapps.user_api.learner_skill_levels.views.get_job_holder_usernames')
@mock.patch('openedx.core.djangoapps.user_api.learner_skill_levels.api.generate_skill_score_mapping')
def test_get_endpoint(
self,
mock_generate_skill_score_mapping,
mock_get_job_holder_usernames,
mock_get_top_skill_categories_for_job
):
"""
Test that response if returned with correct scores appended.
"""
mock_get_top_skill_categories_for_job.return_value = DUMMY_CATEGORIES_RESPONSE
mock_get_job_holder_usernames.return_value = DUMMY_USERNAMES_RESPONSE
mock_generate_skill_score_mapping.return_value = {'Technology Roadmap': 2, 'Python': 3}
self.client.login(username=self.user.username, password=TEST_PASSWORD)
response = self.client.get(self.url)
assert response.status_code == 200
# check if the response is mutated and scores are appended for skills
# for when some skills are learned by user in a category, check if user_score and avg score is appended
assert response.data['skill_categories'][0]['user_score'] == 0.8
assert response.data['skill_categories'][0]['edx_average_score'] == 0.8
# for when no skill is learned by user in a category, check if user_score and avg score is appended
assert response.data['skill_categories'][1]['user_score'] == 0.0
assert response.data['skill_categories'][1]['edx_average_score'] == 0.0
@mock.patch('openedx.core.djangoapps.user_api.learner_skill_levels.views.get_top_skill_categories_for_job')
@mock.patch('openedx.core.djangoapps.user_api.learner_skill_levels.views.get_job_holder_usernames')
@mock.patch('openedx.core.djangoapps.user_api.learner_skill_levels.api.generate_skill_score_mapping')
def test_get_with_less_than_5_users(
self,
mock_generate_skill_score_mapping,
mock_get_job_holder_usernames,
mock_get_top_skill_categories_for_job
):
"""
Test that average value is None when users are less than 5.
"""
mock_get_top_skill_categories_for_job.return_value = DUMMY_CATEGORIES_RESPONSE
mock_get_job_holder_usernames.return_value = {"usernames": ['user1', 'user2']}
mock_generate_skill_score_mapping.return_value = {'Technology Roadmap': 2, 'Python': 3}
self.client.login(username=self.user.username, password=TEST_PASSWORD)
response = self.client.get(self.url)
assert response.status_code == 200
# check if the response is mutated and scores are appended for skills
# for when some skills are learned by user in a category, check if user_score and avg score is appended
assert response.data['skill_categories'][0]['user_score'] == 0.8
assert response.data['skill_categories'][0]['edx_average_score'] is None
# for when no skill is learned by user in a category, check if user_score and avg score is appended
assert response.data['skill_categories'][1]['user_score'] == 0.0
assert response.data['skill_categories'][1]['edx_average_score'] is None
@mock.patch('openedx.core.djangoapps.user_api.learner_skill_levels.views.get_top_skill_categories_for_job')
@mock.patch('openedx.core.djangoapps.user_api.learner_skill_levels.views.get_job_holder_usernames')
@mock.patch('openedx.core.djangoapps.user_api.learner_skill_levels.api.generate_skill_score_mapping')
def test_get_no_skills_learned(
self,
mock_generate_skill_score_mapping,
mock_get_job_holder_usernames,
mock_get_top_skill_categories_for_job
):
"""
Test that score is 0.0 when no skills are learned by a user.
"""
mock_get_top_skill_categories_for_job.return_value = DUMMY_CATEGORIES_RESPONSE
mock_get_job_holder_usernames.return_value = DUMMY_USERNAMES_RESPONSE
mock_generate_skill_score_mapping.return_value = {}
self.client.login(username=self.user.username, password=TEST_PASSWORD)
response = self.client.get(self.url)
assert response.status_code == 200
# check if the response is mutated and scores are appended for skills
# for when some skills are learned by user in a category, check if user_score and avg score is appended
assert response.data['skill_categories'][0]['user_score'] == 0.0
assert response.data['skill_categories'][0]['edx_average_score'] == 0.0
# for when no skill is learned by user in a category, check if user_score and avg score is appended
assert response.data['skill_categories'][1]['user_score'] == 0.0
assert response.data['skill_categories'][1]['edx_average_score'] == 0.0

View File

@@ -1,110 +0,0 @@
"""
Utilities for unit tests of learner skill levels.
"""
DUMMY_CATEGORIES_RESPONSE = {
"job": "Digital Product Manager",
"skill_categories": [
{
"name": "Information Technology",
"id": 1,
"skills": [
{"id": 3, "name": "Technology Roadmap"},
{"id": 12, "name": "Python"},
{"id": 2, "name": "MongoDB"}
],
"skills_subcategories": [
{
"id": 1,
"name": "Databases",
"skills": [
{"id": 1, "name": "Query Languages"},
{"id": 2, "name": "MongoDB"},
]
},
{
"id": 2,
"name": "IT Management",
"skills": [
{"id": 3, "name": "Technology Roadmap"},
]
},
]
},
{
"name": "Finance",
"id": 2,
"skills": [
{"id": 4, "name": "Accounting"},
{"id": 5, "name": "TQM"},
],
"skills_subcategories": [
{
"id": 3,
"name": "Auditing",
"skills": [
{"id": 4, "name": "Accounting"},
{"id": 5, "name": "TQM"},
]
},
{
"id": 4,
"name": "Management",
"skills": [
{"id": 6, "name": "Financial Management"},
]
},
]
},
]
}
DUMMY_CATEGORIES_WITH_SCORES = {
"job": "Digital Product Manager",
"skill_categories": [
{
"name": "Information Technology",
"id": 1,
"skills": [
{"id": 3, "name": "Technology Roadmap", "score": 1},
{"id": 12, "name": "Python", "score": 2},
{"id": 2, "name": "MongoDB", "score": 3}
],
"user_score": 0.8,
},
{
"name": "Finance",
"id": 2,
"skills": [
{"id": 1, "name": "Query Languages", "score": 1},
{"id": 4, "name": "System Design", "score": 2},
],
"user_score": 0.3,
},
]
}
DUMMY_USER_SCORES_MAP = {
"Information Technology": [0.1, 0.3, 0.5, 0.7],
"Finance": [0.2, 0.4, 0.6, 0.8]
}
DUMMY_USERNAMES_RESPONSE = {
"usernames": [
'test_user_1',
'test_user_2',
'test_user_3',
'test_user_4',
'test_user_5',
'test_user_6',
]
}
DUMMY_COURSE_DATA_RESPONSE = {
"key": "AWS+OTP",
"uuid": "fe1a9ad4-a452-45cd-80e5-9babd3d43f96",
"title": "Demonstration Course",
"level_type": 'Advanced',
"skill_names": ["python", "MongoDB", "Data Science"]
}

View File

@@ -1,182 +0,0 @@
"""
Utilities for learner_skill_levels.
"""
from logging import getLogger
from urllib.parse import urlparse
from lms.djangoapps.grades.models import PersistentCourseGrade # lint-amnesty, pylint: disable=unused-import
from openedx.core.djangoapps.catalog.utils import (
get_catalog_api_client,
check_catalog_integration_and_get_user,
get_catalog_api_base_url,
)
from openedx.core.djangoapps.catalog.utils import get_course_data, get_course_run_data
from openedx.core.lib.edx_api_utils import get_api_data
from .constants import LEVEL_TYPE_SCORE_MAPPING
LOGGER = getLogger(__name__) # pylint: disable=invalid-name
def get_course_run_ids(user):
"""
Returns all the course run ids of the courses that user has passed from PersistentCourseGrade model.
"""
return list(
PersistentCourseGrade.objects.filter(
user_id=user.id,
passed_timestamp__isnull=False
).values_list('course_id', flat=True)
)
def generate_skill_score_mapping(user):
"""
Generates a skill to score mapping for all the skills user has learner so far in passed courses.
"""
# get course_run_ids of all courses the user has passed
course_run_ids = get_course_run_ids(user)
skill_score_mapping = {}
for course_run_id in course_run_ids:
# fetch course details from course run id to get course key
course_run_data = get_course_run_data(course_run_id, ['course'])
if course_run_data:
# fetch course details to get level type and skills
course_data = get_course_data(course_run_data['course'], ['skill_names', 'level_type'])
skill_names = course_data['skill_names']
level_type = course_data['level_type']
# if a level_type is None for a course, we should skip that course.
if level_type:
score = LEVEL_TYPE_SCORE_MAPPING[level_type.capitalize()]
for skill in skill_names:
if skill in skill_score_mapping:
# assign scores b/w 1-3 based on level type
# assign the larger score if skill is repeated in 2 courses
skill_score_mapping[skill] = max(score, skill_score_mapping[skill])
else:
skill_score_mapping.update({skill: score})
LOGGER.info(
"Could not find course_key for course run id [%s].", course_run_id
)
return skill_score_mapping
def calculate_user_skill_score(skills_with_score):
"""
Calculates user skill score to see where the user falls in a certain job category.
"""
# generate a dict with skill name as key and score as value
# take only those skills that user has learned.
if not skills_with_score:
return 0.0
skills_score_dict = {
item['name']: item['score']
for item in skills_with_score
if item['score'] is not None
}
sum_of_skills = sum(skills_score_dict.values())
skills_count = len(skills_score_dict)
if not skills_count:
return 0.0
# sum of skills score in the category/ 3*no. of skills in category
return round(sum_of_skills / (3 * skills_count), 1)
def get_skills_score(skills, learner_skill_score):
"""
Takes each skill item in list and appends its score to it.
For a skill that doesn't exist in learner's skills set, appends None as score.
"""
for skill in skills:
skill['score'] = learner_skill_score.get(skill['name'])
def update_category_user_scores_map(categories, category_user_scores_map):
"""
Appends user's scores for each category in the dict.
"""
for category in categories:
category_user_scores_map[category['name']].append(category['user_score'])
def update_edx_average_score(categories, user_score_mapping):
"""
Calculates average score for each category and appends it.
"""
for category in categories:
category_scores = user_score_mapping[category['name']]
sum_score = sum(category_scores, 0.0)
average_score = round(sum_score / len(category_scores), 1)
category['edx_average_score'] = average_score
def get_base_url(url):
"""
Returns the base url for any given url.
"""
if url:
parsed = urlparse(url)
return f'{parsed.scheme}://{parsed.netloc}'
def get_top_skill_categories_for_job(job_id):
"""
Retrieve top categories for the job with the given job_id.
Arguments:
job_id (int): id of the job about which we are retrieving information.
Returns:
dict with top 5 categories of specified job.
"""
user, catalog_integration = check_catalog_integration_and_get_user(error_message_field='Skill Categories')
if user:
api_client = get_catalog_api_client(user)
root_url = get_catalog_api_base_url()
base_api_url = get_base_url(root_url)
resource = '/taxonomy/api/v1/job-top-subcategories'
cache_key = f'{catalog_integration.CACHE_KEY}.job-categories.{job_id}'
data = get_api_data(
catalog_integration,
resource=resource,
resource_id=job_id,
api_client=api_client,
base_api_url=base_api_url,
cache_key=cache_key if catalog_integration.is_cache_enabled else None,
)
if data:
return data
def get_job_holder_usernames(job_id):
"""
Retrieve usernames of users who have the same job as given job_id.
Arguments:
job_id (int): id of the job for which we are retrieving usernames.
Returns:
list with oldest 100 users' usernames that exist in our system.
"""
user, catalog_integration = check_catalog_integration_and_get_user(error_message_field='Job Holder Usernames')
if user:
api_client = get_catalog_api_client(user)
root_url = get_catalog_api_base_url()
base_api_url = get_base_url(root_url)
resource = '/taxonomy/api/v1/job-holder-usernames'
cache_key = f'{catalog_integration.CACHE_KEY}.job-holder-usernames.{job_id}'
data = get_api_data(
catalog_integration,
resource=resource,
resource_id=job_id,
api_client=api_client,
base_api_url=base_api_url,
cache_key=cache_key if catalog_integration.is_cache_enabled else None,
)
if data:
return data

View File

@@ -1,129 +0,0 @@
"""
Views for learner_skill_levels.
"""
from collections import defaultdict
from copy import deepcopy
from django.contrib.auth.models import User # lint-amnesty, pylint: disable=imported-auth-user
from rest_framework import permissions, status
from rest_framework.response import Response
from rest_framework.views import APIView
from edx_rest_framework_extensions.auth.jwt.authentication import JwtAuthentication
from edx_rest_framework_extensions.auth.session.authentication import SessionAuthenticationAllowInactiveUser
from openedx.core.lib.api.authentication import BearerAuthenticationAllowInactiveUser
from .api import get_learner_skill_levels
from .utils import get_top_skill_categories_for_job, get_job_holder_usernames, update_category_user_scores_map, \
update_edx_average_score
class LearnerSkillLevelsView(APIView):
"""
**Use Cases**
Returns top 5 job categories for the given job. Checks which skill the user has learned via courses
and assign scores to each skill in category. Also takes first 100 users in our system to calculate
average score for each category.
**Request format**
GET /api/user/v1/skill_level/{job_id}/
**Response Values for GET**
If the specified job_id doesn't exist, an HTTP
404 "Not Found" response is returned.
If a logged in user makes a request with an existing job, an HTTP 200
"OK" response is returned that contains a JSON string.
**Example Request**
GET /api/user/v1/skill_level/1/
**Example Response**
{
"job": "Digital Product Manager",
"skill_categories": [
{
"name": "Information Technology",
"id": 1,
"skills": [
{"id": 2, "name": "Query Languages", "score": 1},
{"id": 3, "name": "MongoDB", "score": 3},
]
"user_score": 0.4, // request user's score
"edx_average_score": 0.7,
"skills_subcategories": [
{
"id": 1,
"name": "Databases",
"skills": [
{"id": 2, "name": "Query Languages", "score": 1},
{"id": 3, "name": "MongoDB", "score": None},
]
},
{
"id": 2,
"name": "IT Management",
"skills": [
{"id": 1, "name": "Technology Roadmap", "score": 2},
]
},
// here remaining job related skills subcategories
]
},
// Here more 4 skill categories
]
}
"""
authentication_classes = (
JwtAuthentication,
BearerAuthenticationAllowInactiveUser,
SessionAuthenticationAllowInactiveUser
)
permission_classes = (permissions.IsAuthenticated, )
def get(self, request, job_id):
"""
GET /api/user/v1/skill_level/{job_id}/
"""
# get top categories for the given job
job_skill_categories = get_top_skill_categories_for_job(job_id)
if not job_skill_categories:
return Response(
status=status.HTTP_404_NOT_FOUND,
data={'message': "The job id doesn't exist, enter a valid job id."}
)
# assign scores for every skill request user has learned
top_categories = deepcopy(job_skill_categories['skill_categories'])
user_category_scores = get_learner_skill_levels(
user=request.user,
top_categories=top_categories,
)
# repeat the same logic for 100 job holder users in our system
job_holder_usernames = get_job_holder_usernames(job_id)
users = User.objects.filter(username__in=job_holder_usernames['usernames'])
# edx_avg_score should only be calculated if users count is greater than 5, else skip it.
if len(users) > 5:
# To save all the users' scores against every category to calculate average score
category_user_scores_map = defaultdict(list)
for user in users:
categories = deepcopy(job_skill_categories['skill_categories'])
categories_with_scores = get_learner_skill_levels(
user=user,
top_categories=categories,
)
update_category_user_scores_map(categories_with_scores, category_user_scores_map)
update_edx_average_score(user_category_scores, category_user_scores_map)
job_skill_categories['skill_categories'] = user_category_scores
return Response(job_skill_categories)

View File

@@ -19,7 +19,6 @@ from .accounts.views import (
NameChangeView,
UsernameReplacementView, CancelAccountRetirementStatusView
)
from .learner_skill_levels.views import LearnerSkillLevelsView
from . import views as user_api_views
from .models import UserPreference
from .preferences.views import PreferencesDetailView, PreferencesView
@@ -191,11 +190,6 @@ urlpatterns = [
PreferencesDetailView.as_view(),
name='preferences_detail_api'
),
re_path(
r'^v1/skill_level/(?P<job_id>[0-9]+)/$',
LearnerSkillLevelsView.as_view(),
name="learner_skill_level"
),
# Moved from user_api/legacy_urls.py
path('v1/', include(USER_API_ROUTER.urls)),