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

feat: add feature to the List Users API to filter users by skill #1097

Open
wants to merge 18 commits into
base: develop
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 10 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
22 changes: 15 additions & 7 deletions app/api/dao/user.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
from typing import Dict
from flask_restx import marshal
from sqlalchemy import func
from nltk.stem import PorterStemmer

from app import messages
from app.api.email_utils import confirm_token
Expand Down Expand Up @@ -152,6 +153,7 @@ def get_user_by_username(username: str):
def list_users(
user_id: int,
search_query: str = "",
skill: str = "",
page: int = DEFAULT_PAGE,
per_page: int = DEFAULT_USERS_PER_PAGE,
is_verified=None,
Expand All @@ -161,6 +163,7 @@ def list_users(
Arguments:
user_id: The ID of the user to be listed.
search_query: The search query for name of the users to be found.
skill: The skill of the user to be listed.
is_verified: Status of the user's verification; None when provided as an argument.
page: The page of users to be returned
per_page: The number of users to return per page
Expand All @@ -170,14 +173,19 @@ def list_users(

"""

users_list = (
UserModel.query.filter(
UserModel.id != user_id,
not is_verified or UserModel.is_email_verified,
func.lower(UserModel.name).contains(search_query.lower())
| func.lower(UserModel.username).contains(search_query.lower()),
users_list_query = UserModel.query.filter(
UserModel.id != user_id,
not is_verified or UserModel.is_email_verified,
func.lower(UserModel.name).contains(search_query.lower())
| func.lower(UserModel.username).contains(search_query.lower()),
)
if skill:
ps = PorterStemmer()
users_list_query = users_list_query.filter(
func.lower(UserModel.skills).contains(ps.stem(skill.lower()))
battuAshita marked this conversation as resolved.
Show resolved Hide resolved
)
.order_by(UserModel.id)
users_list = (
users_list_query.order_by(UserModel.id)
.paginate(
page=page,
per_page=per_page,
Expand Down
19 changes: 16 additions & 3 deletions app/api/resources/user.py
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ class UserList(Resource):
"list_users",
params={
"search": "Search query",
"skills": "Search based on skill",
"page": "specify page of users (default: 1)",
"per_page": "specify number of users per page (default: 10)",
},
Expand Down Expand Up @@ -75,7 +76,13 @@ def get(cls):
)

user_id = get_jwt_identity()
return DAO.list_users(user_id, request.args.get("search", ""), page, per_page)
return DAO.list_users(
user_id,
request.args.get("search", ""),
request.args.get("skills", None),
page,
per_page,
)


@users_ns.route("users/<int:user_id>")
Expand Down Expand Up @@ -208,7 +215,7 @@ def delete(cls):
class ChangeUserPassword(Resource):
@classmethod
@jwt_required
@users_ns.doc("update_user_password")
@users_ns.doc("updateNone_user_password")
battuAshita marked this conversation as resolved.
Show resolved Hide resolved
@users_ns.expect(
auth_header_parser, change_password_request_data_model, validate=True
)
Expand Down Expand Up @@ -242,6 +249,7 @@ class VerifiedUser(Resource):
"get_verified_users",
params={
"search": "Search query",
"skills": "Search based on skill",
"page": "specify page of users",
"per_page": "specify number of users per page",
},
Expand Down Expand Up @@ -280,7 +288,12 @@ def get(cls):

user_id = get_jwt_identity()
return DAO.list_users(
user_id, request.args.get("search", ""), page, per_page, is_verified=True
user_id,
request.args.get("search", ""),
battuAshita marked this conversation as resolved.
Show resolved Hide resolved
request.args.get("skills", None),
page,
per_page,
is_verified=True,
)


Expand Down
1 change: 1 addition & 0 deletions requirements.txt
Original file line number Diff line number Diff line change
Expand Up @@ -10,3 +10,4 @@ gunicorn==20.0.4
psycopg2-binary==2.8.6
python-dotenv==0.14.0
six==1.11.0
nltk==3.6.2
130 changes: 130 additions & 0 deletions tests/users/test_dao_filter_by_skill.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,130 @@
import unittest

from flask import json
from http import HTTPStatus
from tests.base_test_case import BaseTestCase
from app.database.models.user import UserModel
from app.database.sqlalchemy_extension import db
from tests.test_data import user1, user2, user3, user4
from tests.test_utils import get_test_request_header


class TestFilterUsersBySkill(BaseTestCase):
def insert_entries_in_database(self):

# Insert data of the first entry
self.first_user = UserModel(
name=user1["name"],
battuAshita marked this conversation as resolved.
Show resolved Hide resolved
email=user1["email"],
username=user1["username"],
password=user1["password"],
terms_and_conditions_checked=user1["terms_and_conditions_checked"],
)
battuAshita marked this conversation as resolved.
Show resolved Hide resolved
self.first_user.is_email_verified = True
self.first_user.skills = "Problem Solving"

db.session.add(self.first_user)
db.session.commit()

# Insert data of the second entry
self.second_user = UserModel(
name=user2["name"],
email=user2["email"],
username=user2["username"],
password=user2["password"],
terms_and_conditions_checked=user2["terms_and_conditions_checked"],
)
battuAshita marked this conversation as resolved.
Show resolved Hide resolved
self.second_user.is_email_verified = True
self.second_user.skills = "Problem Solving"

db.session.add(self.second_user)
db.session.commit()

# Insert data of the third entry
self.third_user = UserModel(
name=user3["name"],
email=user3["email"],
username=user3["username"],
password=user3["password"],
terms_and_conditions_checked=user3["terms_and_conditions_checked"],
)
self.third_user.is_email_verified = True
self.third_user.skills = "Critical thinking"

db.session.add(self.third_user)
db.session.commit()

# Insert data of the fourth entry
self.fourth_user = UserModel(
name=user4["name"],
email=user4["email"],
username=user4["username"],
password=user4["password"],
terms_and_conditions_checked=user4["terms_and_conditions_checked"],
)
self.fourth_user.is_email_verified = True
self.fourth_user.skills = "Creativity"

db.session.add(self.fourth_user)
db.session.commit()

def test_filter_users_by_skill_problem_solving(self):
self.insert_entries_in_database()

auth_header = get_test_request_header(self.admin_user.id)
expected_response = {"user1": "Problem Solving", "user2": "Problem Solving"}

actual_response = self.client.get(
"/users/verified?skills=problem solving",
headers=auth_header,
content_type="application/json",
)

self.assertEqual(HTTPStatus.OK, actual_response.status_code)

for data in json.loads(actual_response.data):

if data["username"] in expected_response.keys():
battuAshita marked this conversation as resolved.
Show resolved Hide resolved
self.assertEqual(expected_response[data["username"]], data["skills"])

def test_filter_users_by_skill_critical(self):
self.insert_entries_in_database()

auth_header = get_test_request_header(self.admin_user.id)
expected_response = {"user3": "Critical thinking"}

actual_response = self.client.get(
"/users/verified?skills=Critical",
headers=auth_header,
content_type="application/json",
)

self.assertEqual(HTTPStatus.OK, actual_response.status_code)

for data in json.loads(actual_response.data):

if data["username"] in expected_response.keys():
battuAshita marked this conversation as resolved.
Show resolved Hide resolved
self.assertEqual(expected_response[data["username"]], data["skills"])

def test_filter_users_by_skill_creative(self):
self.insert_entries_in_database()

auth_header = get_test_request_header(self.admin_user.id)
expected_response = {"user4": "Creativity"}

actual_response = self.client.get(
"/users/verified?skills=Creative",
headers=auth_header,
content_type="application/json",
)

self.assertEqual(HTTPStatus.OK, actual_response.status_code)

for data in json.loads(actual_response.data):

if data["username"] in expected_response.keys():
battuAshita marked this conversation as resolved.
Show resolved Hide resolved
self.assertEqual(expected_response[data["username"]], data["skills"])


if __name__ == "__main__":
unittest.main()