Skip to content

Commit

Permalink
skills list api
Browse files Browse the repository at this point in the history
ENT-4239
  • Loading branch information
muhammad-ammar committed Mar 5, 2021
1 parent 433b3ef commit 52df616
Show file tree
Hide file tree
Showing 11 changed files with 171 additions and 1 deletion.
Empty file added taxonomy/api/__init__.py
Empty file.
Empty file added taxonomy/api/v1/__init__.py
Empty file.
10 changes: 10 additions & 0 deletions taxonomy/api/v1/serializers.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
from rest_framework import serializers
from taxonomy.models import Skill


class SkillSerializer(serializers.ModelSerializer):
""" Skill Searlizer """

class Meta:
model = Skill
fields = ('name', 'description')
6 changes: 6 additions & 0 deletions taxonomy/api/v1/urls.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
from django.urls import path
from taxonomy.api.v1.views import SkillsView

urlpatterns = [
path('api/v1/skills/', SkillsView.as_view(), name='skill_list')
]
19 changes: 19 additions & 0 deletions taxonomy/api/v1/views.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
from rest_framework.generics import ListAPIView
from rest_framework.permissions import IsAuthenticated
from taxonomy.models import Skill
from taxonomy.api.v1.serializers import SkillSerializer


class SkillsView(ListAPIView):
""" List view for Skills """
permission_classes = [IsAuthenticated]
serializer_class = SkillSerializer

def get_queryset(self):
search = self.request.query_params.get('search')

queryset = Skill.objects.exclude(courseskills__is_blacklisted=True)
if search:
queryset = queryset.filter(name__icontains=search)

return queryset
18 changes: 18 additions & 0 deletions taxonomy/migrations/0010_auto_20210305_0914.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
# Generated by Django 2.2.17 on 2021-03-05 09:14

from django.db import migrations, models


class Migration(migrations.Migration):

dependencies = [
('taxonomy', '0009_skill_description'),
]

operations = [
migrations.AlterField(
model_name='skill',
name='name',
field=models.CharField(blank=True, db_index=True, help_text='The name of the skill.', max_length=255),
),
]
1 change: 1 addition & 0 deletions taxonomy/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ class Skill(TimeStampedModel):
name = models.CharField(
max_length=255,
blank=True,
db_index=True,
help_text=_(
'The name of the skill.'
)
Expand Down
6 changes: 5 additions & 1 deletion taxonomy/urls.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,16 @@
Taxonomy Connector URL Configuration.
"""

from django.urls import re_path
from django.urls import re_path, include

from taxonomy import views
from taxonomy.api.v1.urls import urlpatterns as api_v1_urlpatterns


urlpatterns = [
re_path(
r"^admin/taxonomy/refresh_course_skills/$", views.RefreshCourseSkills.as_view(), name="refresh_course_skills"
),
]

urlpatterns += api_v1_urlpatterns
18 changes: 18 additions & 0 deletions test_settings.py
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,18 @@ def root(*args):
'django.contrib.sessions',
'django.contrib.messages',
'taxonomy',
'rest_framework'
)

MIDDLEWARE = (
'django.contrib.sessions.middleware.SessionMiddleware',
'django.middleware.locale.LocaleMiddleware',
'django.middleware.common.CommonMiddleware',
'django.middleware.csrf.CsrfViewMiddleware',
'django.contrib.auth.middleware.AuthenticationMiddleware',
'django.contrib.messages.middleware.MessageMiddleware',
'django.contrib.sites.middleware.CurrentSiteMiddleware',
'django.middleware.clickjacking.XFrameOptionsMiddleware',
)

LOCALE_PATHS = [
Expand Down Expand Up @@ -69,3 +81,9 @@ def root(*args):
CELERY_BROKER_URL = 'memory://localhost/'

### END CELERY

REST_FRAMEWORK = {
'DEFAULT_AUTHENTICATION_CLASSES': (
'rest_framework.authentication.SessionAuthentication',
),
}
19 changes: 19 additions & 0 deletions test_utils/factories.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@
import factory
from faker import Factory as FakerFactory

from django.contrib.auth.models import User

from taxonomy.models import CourseSkills, Job, JobPostings, JobSkills, Skill

FAKER = FakerFactory.create()
Expand Down Expand Up @@ -94,3 +96,20 @@ class Meta:
median_posting_duration = factory.LazyAttribute(lambda x: FAKER.pyint(min_value=0, max_value=100000000))
unique_postings = factory.LazyAttribute(lambda x: FAKER.pyint(min_value=0, max_value=100000000))
unique_companies = factory.LazyAttribute(lambda x: FAKER.pyint(min_value=0, max_value=100000000))


class UserFactory(factory.django.DjangoModelFactory):
"""
Factory for User model.
"""

class Meta:
model = User

email = factory.LazyAttribute(lambda x: FAKER.email())
username = factory.LazyAttribute(lambda x: FAKER.user_name())
first_name = factory.LazyAttribute(lambda x: FAKER.first_name())
last_name = factory.LazyAttribute(lambda x: FAKER.last_name())
is_superuser = False
is_staff = False
is_active = True
75 changes: 75 additions & 0 deletions tests/test_api_v1.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
from pytest import mark
from django.urls import reverse

from rest_framework.test import APITestCase
from rest_framework import status
from test_utils import factories


TEST_USERNAME = 'taxonomy_user'
TEST_EMAIL = '[email protected]'
TEST_PASSWORD = 'password'


@mark.django_db
class TestSkillsView(APITestCase):
def setUp(self):
"""
Perform operations common to all tests.
"""
super().setUp()
self.user = self.create_user(username=TEST_USERNAME, email=TEST_EMAIL, password=TEST_PASSWORD)

self.url = reverse('skill_list')

self.whitelisted_skills = [
'C Plus Plus', 'Command Line Interface', 'Data Structures', 'Biochemistry',
'Animations', 'Algorithms', 'Data Science', 'Data Wrangling', 'Databases'
]
self.blacklisted_skills = ['Visual Basic', 'Oracle']

for skill_name in self.whitelisted_skills:
skill = factories.SkillFactory(name=skill_name)
factories.CourseSkillsFactory(skill=skill)

for skill_name in self.blacklisted_skills:
skill = factories.SkillFactory(name=skill_name)
factories.CourseSkillsFactory(skill=skill, is_blacklisted=True)

self.client.login(username=TEST_USERNAME, password=TEST_PASSWORD)

def create_user(self, username=TEST_USERNAME, password=TEST_PASSWORD, **kwargs):
"""
Create a test user and set its password.
"""
user = factories.UserFactory(username=username, **kwargs)
user.set_password(password) # pylint: disable=no-member
user.save() # pylint: disable=no-member
return user

def test_search(self):
"""
Verify that skills endppoint return all skills when `search` query param is not given
"""
response = self.client.get(path=self.url)
assert response.status_code == status.HTTP_200_OK
skill_names = [skill['name'] for skill in response.json()]
assert sorted(skill_names) == sorted(self.whitelisted_skills)

def test_search_with_query_param(self):
"""
Verify that skills endppoint return filtered skills according to the `search` query param
"""
response = self.client.get(path=self.url + '?search=data')
assert response.status_code == status.HTTP_200_OK
skill_names = [skill['name'] for skill in response.json()]
assert skill_names == ['Data Structures', 'Data Science', 'Data Wrangling', 'Databases' ]

def test_search_with_blacklisted_skill(self):
"""
Verify that skills endppoint does not return blacklised skills.
"""
response = self.client.get(path=self.url + '?search=Oracle')
assert response.status_code == status.HTTP_200_OK
skill_names = [skill['name'] for skill in response.json()]
assert skill_names == []

0 comments on commit 52df616

Please sign in to comment.