Skip to content

Commit

Permalink
Feat: PUT /user/personal_background api endpoint and tests
Browse files Browse the repository at this point in the history
Refactored background enum  logic for update personal background

Add other fields for physical, mental ability and socio economic

Fix: bug on user_id not retrieved error message and setting

Refactor POST PUT update personal background to one api endpoint PUT
  • Loading branch information
mtreacy002 committed Aug 11, 2020
1 parent 44b0e9b commit 8b14e21
Show file tree
Hide file tree
Showing 4 changed files with 536 additions and 1 deletion.
79 changes: 78 additions & 1 deletion app/api/dao/personal_background.py
Original file line number Diff line number Diff line change
Expand Up @@ -46,4 +46,81 @@ def get_user_personal_background_info(user_id):
"highest_education_other": result.others["highest_education_other"],
"is_public": result.is_public
}


@staticmethod
def update_user_personal_background(data):
"""Creates or Updates a personal_background instance.
Arguments:
data: A list containing user's id, and user's background details (gender,
age, ethnicity, sexual_orientation, religion, physical_ability, mental_ability,
socio_economic, highest_education, years_of_experience, others) as well as
whether or not user agrees to make their personal background information
public to other members of BridgeInTech.
Returns:
A dictionary containing "message" which indicates whether or not the user_exension
was created or updated successfully and "code" for the HTTP response code.
"""

try:
user_id = int(AUTH_COOKIE["user_id"].value)
except ValueError:
return messages.USER_ID_IS_NOT_RETRIEVED, HTTPStatus.FORBIDDEN

others_data = {}
try:
others_data["gender_other"] = data["gender_other"]
others_data["ethnicity_other"] = data["ethnicity_other"]
others_data["sexual_orientation_other"] = data["sexual_orientation_other"]
others_data["religion_other"] = data["religion_other"]
others_data["physical_ability_other"] = data["physical_ability_other"]
others_data["mental_ability_other"] = data["mental_ability_other"]
others_data["socio_economic_other"] = data["socio_economic_other"]
others_data["highest_education_other"] = data["highest_education_other"]
except KeyError as e:
return e, HTTPStatus.BAD_REQUEST

existing_personal_background = PersonalBackgroundModel.find_by_user_id(user_id)
if not existing_personal_background:
try:
personal_background = PersonalBackgroundModel(
user_id=user_id,
gender=Gender(data["gender"]).name,
age=Age(data["age"]).name,
ethnicity=Ethnicity(data["ethnicity"]).name,
sexual_orientation=SexualOrientation(data["sexual_orientation"]).name,
religion=Religion(data["religion"]).name,
physical_ability=PhysicalAbility(data["physical_ability"]).name,
mental_ability=MentalAbility(data["mental_ability"]).name,
socio_economic=SocioEconomic(data["socio_economic"]).name,
highest_education=HighestEducation(data["highest_education"]).name,
years_of_experience=YearsOfExperience(data["years_of_experience"]).name,
)
personal_background.others = others_data
personal_background.is_public = data["is_public"]
except KeyError as e:
return e, HTTPStatus.BAD_REQUEST

personal_background.save_to_db()
return messages.PERSONAL_BACKGROUND_SUCCESSFULLY_CREATED, HTTPStatus.CREATED

try:
existing_personal_background.gender = Gender(data["gender"]).name
existing_personal_background.age = Age(data["age"]).name
existing_personal_background.ethnicity = Ethnicity(data["ethnicity"]).name
existing_personal_background.sexual_orientation = SexualOrientation(data["sexual_orientation"]).name
existing_personal_background.religion = Religion(data["religion"]).name
existing_personal_background.physical_ability = PhysicalAbility(data["physical_ability"]).name
existing_personal_background.mental_ability = MentalAbility(data["mental_ability"]).name
existing_personal_background.socio_economic = SocioEconomic(data["socio_economic"]).name
existing_personal_background.highest_education = HighestEducation(data["highest_education"]).name
existing_personal_background.years_of_experience = YearsOfExperience(data["years_of_experience"]).name
existing_personal_background.is_public = data["is_public"]
except KeyError as e:
return e, HTTPStatus.BAD_REQUEST

existing_personal_background.others = others_data
existing_personal_background.save_to_db()

return messages.PERSONAL_BACKGROUND_SUCCESSFULLY_UPDATED, HTTPStatus.OK
50 changes: 50 additions & 0 deletions app/api/resources/users.py
Original file line number Diff line number Diff line change
Expand Up @@ -335,4 +335,54 @@ def get(cls):
return is_wrong_token


@classmethod
@users_ns.doc("update_user_personal_background")
@users_ns.response(
HTTPStatus.OK, f"{messages.PERSONAL_BACKGROUND_SUCCESSFULLY_UPDATED}"
)
@users_ns.response(
HTTPStatus.CREATED, f"{messages.PERSONAL_BACKGROUND_SUCCESSFULLY_CREATED}"
)
@users_ns.response(
HTTPStatus.BAD_REQUEST,
f"{messages.USER_ID_IS_NOT_VALID}\n"
f"{messages.PERSONAL_BACKGROUND_DATA_HAS_MISSING_FIELD}\n"
f"{messages.UNEXPECTED_INPUT}"
)
@users_ns.response(
HTTPStatus.INTERNAL_SERVER_ERROR, f"{messages.INTERNAL_SERVER_ERROR}"
)
@users_ns.expect(auth_header_parser, user_personal_background_request_body_model, validate=True)
def put(cls):
"""
Creates or updates user personal background
A user with valid access token can use this endpoint to create or update personal background information to their own data.
The endpoint takes any of the given parameters (gender, age, ethnicity, sexusl_orientation, religion, physical_ability,
mental_ability, socio_economic, highest_education, years_of_experience enums), others (dictionary of any additional
information the user added from any of the background fields) and is_public (boolean value true or false which
indicates whether or not the user agrees to make their personal background information public to other BridgeInTech members).
The response contains a success or error message. This request only accessible once user retrieve their user_id
by sending GET /user/personal_details.
"""

token = request.headers.environ["HTTP_AUTHORIZATION"]
is_wrong_token = validate_token(token)

if not is_wrong_token:
data = request.json
if not data:
return messages.NO_DATA_FOR_UPDATING_PROFILE_WAS_SENT, HTTPStatus.BAD_REQUEST

is_field_valid = expected_fields_validator(data, user_personal_background_request_body_model)
if not is_field_valid.get("is_field_valid"):
return is_field_valid.get("message"), HTTPStatus.BAD_REQUEST

is_not_valid = validate_update_personal_background_info_request(data)
if is_not_valid:
return is_not_valid, HTTPStatus.BAD_REQUEST

return PersonalBackgroundDAO.update_user_personal_background(data)

return is_wrong_token

189 changes: 189 additions & 0 deletions tests/users/test_api_create_personal_background.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,189 @@
import unittest
from http import HTTPStatus, cookies
from unittest.mock import patch, Mock
import requests
from requests.exceptions import HTTPError
from flask import json
from flask_restx import marshal
from app import messages
from tests.base_test_case import BaseTestCase
from app.api.request_api_utils import post_request, get_request, BASE_MS_API_URL, AUTH_COOKIE
from app.api.models.user import full_user_api_model, get_user_personal_background_response_model
from tests.test_data import user1
from app.database.models.ms_schema.user import UserModel
from app.database.models.bit_schema.personal_background import PersonalBackgroundModel


class TestCreatePersonalBackgroundApi(BaseTestCase):

@patch("requests.post")
def setUp(self, mock_login):
super(TestCreatePersonalBackgroundApi, self).setUp()

success_message = {"access_token": "this is fake token", "access_expiry": 1601478236}
success_code = HTTPStatus.OK

mock_login_response = Mock()
mock_login_response.json.return_value = success_message
mock_login_response.status_code = success_code
mock_login.return_value = mock_login_response
mock_login.raise_for_status = json.dumps(success_code)

user_login_success = {
"username": user1.get("username"),
"password": user1.get("password")
}

with self.client:
login_response = self.client.post(
"/login",
data=json.dumps(user_login_success),
follow_redirects=True,
content_type="application/json",
)

test_user = UserModel(
name=user1["name"],
username=user1["username"],
password=user1["password"],
email=user1["email"],
terms_and_conditions_checked=user1["terms_and_conditions_checked"]
)
test_user.need_mentoring = user1["need_mentoring"]
test_user.available_to_mentor = user1["available_to_mentor"]

test_user.save_to_db()

self.test_user_data = UserModel.find_by_email(test_user.email)

AUTH_COOKIE["user_id"] = self.test_user_data.id

self.correct_payload_personal_background = {
"gender": "Female",
"age": "Between 55 to 64 yo",
"ethnicity": "Middle Eastern/North African (MENA)",
"sexual_orientation": "Prefer not to say",
"religion": "Islam",
"physical_ability": "With/had limited physical ability (or with/had some type of physical disability/ies)",
"mental_ability": "With/previously had some type of mental disorders",
"socio_economic": "Lower Middle class (e.g. blue collars in skilled trades/Paralegals/Bank tellers/Sales/Clerical-Admin/other support workers)",
"highest_education": "Prefer not to say",
"years_of_experience": "Prefer not to say",
"gender_other": "They",
"ethnicity_other": "",
"sexual_orientation_other": "",
"religion_other": "Daoism",
"physical_ability_other": "",
"mental_ability_other": "",
"socio_economic_other": "",
"highest_education_other": "",
"is_public": False
}


@patch("requests.put")
def test_api_dao_create_user_personal_background_successfully(self, mock_create_personal_background):
success_message = messages.PERSONAL_BACKGROUND_SUCCESSFULLY_CREATED
success_code = HTTPStatus.CREATED

mock_get_response = Mock()
mock_get_response.json.return_value = success_message
mock_get_response.status_code = success_code

mock_create_personal_background.return_value = mock_get_response
mock_create_personal_background.raise_for_status = json.dumps(success_code)

with self.client:
response = self.client.put(
"/user/personal_background",
headers={"Authorization": AUTH_COOKIE["Authorization"].value},
data=json.dumps(
dict(self.correct_payload_personal_background)
),
follow_redirects=True,
content_type="application/json",
)

test_user_personal_background_data = PersonalBackgroundModel.query.filter_by(user_id=self.test_user_data.id).first()
self.assertEqual(str(test_user_personal_background_data.user_id), AUTH_COOKIE["user_id"].value)
self.assertEqual(test_user_personal_background_data.gender.value, self.correct_payload_personal_background["gender"])
self.assertEqual(test_user_personal_background_data.age.value, self.correct_payload_personal_background["age"])
self.assertEqual(test_user_personal_background_data.ethnicity.value, self.correct_payload_personal_background["ethnicity"])
self.assertEqual(test_user_personal_background_data.sexual_orientation.value, self.correct_payload_personal_background["sexual_orientation"])
self.assertEqual(test_user_personal_background_data.religion.value, self.correct_payload_personal_background["religion"])
self.assertEqual(test_user_personal_background_data.physical_ability.value, self.correct_payload_personal_background["physical_ability"])
self.assertEqual(test_user_personal_background_data.mental_ability.value, self.correct_payload_personal_background["mental_ability"])
self.assertEqual(test_user_personal_background_data.socio_economic.value, self.correct_payload_personal_background["socio_economic"])
self.assertEqual(test_user_personal_background_data.highest_education.value, self.correct_payload_personal_background["highest_education"])
self.assertEqual(test_user_personal_background_data.years_of_experience.value, self.correct_payload_personal_background["years_of_experience"])
self.assertEqual(test_user_personal_background_data.others["gender_other"], self.correct_payload_personal_background["gender_other"])
self.assertEqual(test_user_personal_background_data.others["ethnicity_other"], self.correct_payload_personal_background["ethnicity_other"])
self.assertEqual(test_user_personal_background_data.others["sexual_orientation_other"], self.correct_payload_personal_background["sexual_orientation_other"])
self.assertEqual(test_user_personal_background_data.others["religion_other"], self.correct_payload_personal_background["religion_other"])
self.assertEqual(test_user_personal_background_data.others["physical_ability_other"], self.correct_payload_personal_background["physical_ability_other"])
self.assertEqual(test_user_personal_background_data.others["mental_ability_other"], self.correct_payload_personal_background["mental_ability_other"])
self.assertEqual(test_user_personal_background_data.others["socio_economic_other"], self.correct_payload_personal_background["socio_economic_other"])
self.assertEqual(test_user_personal_background_data.others["highest_education_other"], self.correct_payload_personal_background["highest_education_other"])
self.assertEqual(test_user_personal_background_data.is_public, self.correct_payload_personal_background["is_public"])
self.assertEqual(response.json, success_message)
self.assertEqual(response.status_code, success_code)


@patch("requests.put")
def test_api_dao_create_user_personal_background_invalid_payload(self, mock_create_personal_background):
error_message = messages.PERSONAL_BACKGROUND_IS_INVALID
error_code = HTTPStatus.BAD_REQUEST

mock_response = Mock()
http_error = requests.exceptions.HTTPError()
mock_response.raise_for_status.side_effect = http_error
mock_create_personal_background.return_value = mock_response

mock_error = Mock()
mock_error.json.return_value = error_message
mock_error.status_code = error_code
mock_create_personal_background.side_effect = requests.exceptions.HTTPError(response=mock_error)

test_user_personal_background = {
"gender": "Some random value",
"age": "Between 55 to 64 yo",
"ethnicity": "Middle Eastern/North African (MENA)",
"sexual_orientation": "Prefer not to say",
"religion": "Islam",
"physical_ability": "With/had limited physical ability (or with/had some type of physical disability/ies)",
"mental_ability": "With/previously had some type of mental disorders",
"socio_economic": "Lower Middle class (e.g. blue collars in skilled trades/Paralegals/Bank tellers/Sales/Clerical-Admin/other support workers)",
"highest_education": "Prefer not to say",
"years_of_experience": "Prefer not to say",
"gender_other": "They",
"ethnicity_other": "",
"sexual_orientation_other": "",
"religion_other": "Daoism",
"physical_ability_other": "",
"mental_ability_other": "",
"socio_economic_other": "",
"highest_education_other": "",
"is_public": False
}

with self.client:
response = self.client.put(
"/user/personal_background",
headers={"Authorization": AUTH_COOKIE["Authorization"].value},
data=json.dumps(
dict(test_user_personal_background)
),
follow_redirects=True,
content_type="application/json",
)

test_user_personal_background_data = PersonalBackgroundModel.query.filter_by(user_id=self.test_user_data.id).first()
self.assertEqual(test_user_personal_background_data, None)
self.assertEqual(response.json, error_message)
self.assertEqual(response.status_code, error_code)


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


Loading

0 comments on commit 8b14e21

Please sign in to comment.