Skip to content

Commit

Permalink
Feat:Add post program mentee relationship endpoint
Browse files Browse the repository at this point in the history
  • Loading branch information
decon-harsh committed Feb 12, 2021
1 parent 6f43f59 commit fe9d46f
Show file tree
Hide file tree
Showing 11 changed files with 560 additions and 2 deletions.
3 changes: 3 additions & 0 deletions app/api/bit_extension.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,3 +19,6 @@

from app.api.resources.organizations import organizations_ns as organization_namespace
api.add_namespace(organization_namespace, path="/")

from app.api.resources.mentorship_relation import mentorship_relation_ns as mentorship_relation_namespace
api.add_namespace(mentorship_relation_namespace, path="/")
36 changes: 36 additions & 0 deletions app/api/dao/mentorship_relation_extension.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
import ast
from http import HTTPStatus
from flask import json
from app.database.models.bit_schema.mentorship_relation_extension import MentorshipRelationExtensionModel
from app import messages
from app.api.request_api_utils import AUTH_COOKIE
from app.utils.bitschema_utils import Timezone


class MentorshipRelationExtensionDAO:

"""Data Access Object for Users_Extension functionalities"""

@staticmethod
def createMentorshipRelationExtension(program_id, mentorship_relation_id , mentee_request_date):
"""Creates the extending mentorship relation between organization's program and the user which is logged in.
Arguments:
organization_id: The ID organization, program_id: The ID of program.
Returns:
A dictionary containing "message" which indicates whether or not
the relation was created successfully and "code" for the HTTP response code.
"""

try:
mentorship_relation_extension_object = MentorshipRelationExtensionModel(program_id,mentorship_relation_id)
mentorship_relation_extension_object.mentee_request_date = mentee_request_date
mentorship_relation_extension_object.save_to_db()
return messages.MENTORSHIP_RELATION_WAS_SENT_SUCCESSFULLY, HTTPStatus.CREATED
except:
return messages.INTERNAL_SERVER_ERROR, HTTPStatus.BAD_REQUEST




26 changes: 26 additions & 0 deletions app/api/models/mentorship_relation.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
from flask_restx import fields, Model

from app.utils.enum_utils import MentorshipRelationState


def add_models_to_namespace(api_namespace):
api_namespace.models[send_mentorship_extension_request_body.name] = send_mentorship_extension_request_body


send_mentorship_extension_request_body = Model(
"Send mentorship relation request to organziation model",
{
"mentee_id": fields.Integer(
required=True, description="Mentorship relation mentee ID"
),
"mentee_request_date": fields.Float(
required=True, description="Mentorship relation mentee_request_date in UNIX timestamp format"
),
"end_date": fields.Float(
required=True,
description="Mentorship relation end date in UNIX timestamp format",
),
"notes": fields.String(required=True, description="Mentorship relation notes"),

},
)
31 changes: 31 additions & 0 deletions app/api/request_api_utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,37 @@ def post_request(request_string, data):
return response_message, response_code


def post_request_with_token(request_string, token, data):
request_url = f"{BASE_MS_API_URL}{request_string}"
is_wrong_token = validate_token(token)

if not is_wrong_token:
try:
response = requests.post(
request_url,
json=data,
headers={"Authorization": AUTH_COOKIE["Authorization"].value, "Accept": "application/json"},
)
response.raise_for_status()
response_message = response.json()
response_code = response.status_code
except requests.exceptions.ConnectionError as e:
response_message = messages.INTERNAL_SERVER_ERROR
response_code = json.dumps(HTTPStatus.INTERNAL_SERVER_ERROR)
logging.fatal(f"{e}")
except requests.exceptions.HTTPError as e:
response_message = e.response.json()
response_code = e.response.status_code
except Exception as e:
response_message = messages.INTERNAL_SERVER_ERROR
response_code = json.dumps(HTTPStatus.INTERNAL_SERVER_ERROR)
logging.fatal(f"{e}")
finally:
logging.fatal(f"{response_message}")
return response_message, response_code
return is_wrong_token


def get_user(token):
request_url = "/user"
return get_request(request_url, token, params=None)
Expand Down
173 changes: 173 additions & 0 deletions app/api/resources/mentorship_relation.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,173 @@
import ast
import json
from http import HTTPStatus, cookies
from datetime import datetime, timedelta
from flask import request
from flask_restx import Resource, marshal, Namespace
from app import messages
from app.api.request_api_utils import (
post_request,
post_request_with_token,
get_request,
put_request,
http_response_checker,
AUTH_COOKIE,
validate_token)
# Common Resources
from app.api.resources.common import auth_header_parser
# Validations
from app.api.validations.user import *
from app.api.validations.task_comment import (
validate_task_comment_request_data,
COMMENT_MAX_LENGTH,
)
from app.utils.validation_utils import get_length_validation_error_message,expected_fields_validator
from app.utils.ms_constants import DEFAULT_PAGE, DEFAULT_USERS_PER_PAGE
# Namespace Models
from app.api.models.mentorship_relation import *
# Databases Models
from app.database.models.bit_schema.user_extension import UserExtensionModel
from app.database.models.ms_schema.mentorship_relation import MentorshipRelationModel
from app.database.models.bit_schema.organization import OrganizationModel
from app.database.models.bit_schema.program import ProgramModel
# DAOs
from app.api.dao.user_extension import UserExtensionDAO
from app.api.dao.personal_background import PersonalBackgroundDAO
from app.api.dao.mentorship_relation_extension import MentorshipRelationExtensionDAO
from app.api.dao.organization import OrganizationDAO
from app.api.dao.program import ProgramDAO

mentorship_relation_ns = Namespace(
"Mentorship Relation",
description="Operations related to " "mentorship relations " "between users",
)
add_models_to_namespace(mentorship_relation_ns)

mentorshipRelationExtensionDAO = MentorshipRelationExtensionDAO()
userExtensionDAO = UserExtensionDAO()
OrganizationDAO = OrganizationDAO()
ProgramDAO = ProgramDAO()

@mentorship_relation_ns.route("organizations/<int:organization_id>/programs/<int:program_id>/send_request")
class SendRequest(Resource):
@classmethod
@mentorship_relation_ns.doc("send_request")
@mentorship_relation_ns.expect(auth_header_parser, send_mentorship_extension_request_body)
@mentorship_relation_ns.response(
HTTPStatus.CREATED, "%s" % messages.MENTORSHIP_RELATION_WAS_SENT_SUCCESSFULLY
)
@mentorship_relation_ns.response(
HTTPStatus.BAD_REQUEST,
"%s\n%s\n%s\n%s\n%s\n%s\n%s\n%s\n%s\n%s\n%s\n%s\n%s\n%s\n%s"
% (
messages.NO_DATA_WAS_SENT,
messages.MATCH_EITHER_MENTOR_OR_MENTEE,
messages.MENTOR_ID_SAME_AS_MENTEE_ID,
messages.END_TIME_BEFORE_PRESENT,
messages.MENTOR_TIME_GREATER_THAN_MAX_TIME,
messages.MENTOR_TIME_LESS_THAN_MIN_TIME,
messages.MENTOR_NOT_AVAILABLE_TO_MENTOR,
messages.MENTEE_NOT_AVAIL_TO_BE_MENTORED,
messages.MENTOR_ALREADY_IN_A_RELATION,
messages.MENTEE_ALREADY_IN_A_RELATION,
messages.MENTOR_ID_FIELD_IS_MISSING,
messages.MENTEE_ID_FIELD_IS_MISSING,
messages.NOTES_FIELD_IS_MISSING,
messages.ORGANIZATION_DOES_NOT_EXIST,
messages.PROGRAM_DOES_NOT_EXIST,
),
)
@mentorship_relation_ns.response(
HTTPStatus.UNAUTHORIZED,
"%s\n%s\n%s"
% (
messages.TOKEN_HAS_EXPIRED,
messages.TOKEN_IS_INVALID,
messages.AUTHORISATION_TOKEN_IS_MISSING,
),
)
@mentorship_relation_ns.response(
HTTPStatus.NOT_FOUND,
"%s\n%s" % (messages.MENTOR_DOES_NOT_EXIST, messages.MENTEE_DOES_NOT_EXIST),
)
def post(cls,organization_id,program_id):
"""
Creates a new mentorship relation request.
Also, sends an email notification to the recipient about new relation request.
Input:
1. Header: valid access token
2. Body: A dict containing
- mentor_request_date,end_date: UNIX timestamp
- notes: description of relation request
Returns:
Success or failure message. A mentorship request is send to the other
person whose ID is mentioned. The relation appears at /pending endpoint.
"""

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

if not is_wrong_token:
try:
user_json = (AUTH_COOKIE["user"].value)
user = ast.literal_eval(user_json)
data = request.json

if not data:
return messages.NO_DATA_WAS_SENT, HTTPStatus.BAD_REQUEST

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

is_valid = SendRequest.is_valid_data(data)
if is_valid != {}:
return is_valid, HTTPStatus.BAD_REQUEST

# Checking whether organization exists
organization = OrganizationModel.query.filter_by(id=organization_id).first()
if not organization:
return messages.ORGANIZATION_DOES_NOT_EXIST, HTTPStatus.NOT_FOUND

# Checking whether program exists
program = ProgramModel.find_by_id(program_id)
if not program or (program.organization_id != organization_id):
return messages.PROGRAM_DOES_NOT_EXIST, HTTPStatus.NOT_FOUND

mentor_id = organization.rep_id
mentee_id = data['mentee_id']

mentorship_relation_data={}
mentorship_relation_data['mentee_id'] = mentee_id
mentorship_relation_data['mentor_id'] = int(mentor_id)
mentorship_relation_data['end_date'] = data['end_date']
mentorship_relation_data['notes'] = data['notes']

response = http_response_checker(post_request_with_token("/mentorship_relation/send_request",token, mentorship_relation_data))
if response.status_code == 201:
mentorshipRelationId = MentorshipRelationModel.query.filter_by(mentor_id=mentor_id).filter_by(mentee_id=mentee_id).first().id
return MentorshipRelationExtensionDAO.createMentorshipRelationExtension(program_id, mentorshipRelationId ,data['mentee_request_date'])
else:
return response.message, HTTPStatus.BAD_REQUEST
except ValueError as e:
return e, HTTPStatus.BAD_REQUEST

return is_wrong_token


@staticmethod
def is_valid_data(data):

# Verify if request body has required fields
if "mentee_id" not in data:
return messages.MENTEE_ID_FIELD_IS_MISSING
if "end_date" not in data:
return messages.END_DATE_FIELD_IS_MISSING
if "notes" not in data:
return messages.NOTES_FIELD_IS_MISSING
if "mentee_request_date" not in data:
return messages.MENTEE_REQUEST_DATE_FIELD_IS_MISSING
return {}
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,15 @@ def find_by_id(cls, _id) -> "MentorshipRelationExtensionModel":
_id: The id of a mentorship_relations_extension.
"""
return cls.query.filter_by(id=_id).first()

@classmethod
def find_by_program_id(cls, _id) -> "MentorshipRelationExtensionModel":

"""Returns the mentorship_relations_extension that has the passed program id.
Args:
_id: The id of a program.
"""
return cls.query.filter_by(program_id=_id).first()

def save_to_db(self) -> None:
"""Saves the model to the database."""
Expand Down
2 changes: 1 addition & 1 deletion app/database/models/bit_schema/program.py
Original file line number Diff line number Diff line change
Expand Up @@ -116,7 +116,7 @@ def json(self):
def __repr__(self):
"""Returns the program name, creation/start/end date and organization id."""
return (
f"Program id is {self.program.id}\n"
f"Program id is {self.id}\n"
f"Program name is {self.program_name}.\n"
f"Organization's id is {self.organization_id}.\n"
f"Program start date is {self.start_date}\n"
Expand Down
4 changes: 4 additions & 0 deletions app/messages.py
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,7 @@
MENTOR_ID_FIELD_IS_MISSING = {"message": "Mentor ID field is missing."}
MENTEE_ID_FIELD_IS_MISSING = {"message": "Mentee ID field is missing."}
END_DATE_FIELD_IS_MISSING = {"message": "End date field is missing."}
MENTEE_REQUEST_DATE_FIELD_IS_MISSING = {"message": "Mentee request date field is missing."}
NOTES_FIELD_IS_MISSING = {"message": "Notes field is missing."}
USERNAME_FIELD_IS_MISSING = {"message": "The field username is missing."}
PASSWORD_FIELD_IS_MISSING = {"message": "Password field is missing."}
Expand Down Expand Up @@ -137,6 +138,9 @@
NO_DATA_FOR_UPDATING_PROFILE_WAS_SENT = {
"message": "No data for updating profile was sent."
}
NO_DATA_WAS_SENT = {
"message": "No data was sent."
}
ADDITIONAL_INFORMATION_DOES_NOT_EXIST = {
"message": "No additional information found with your data. Please provide them now."
}
Expand Down
2 changes: 1 addition & 1 deletion requirements.txt
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
APScheduler==3.6.3
Flask==1.1.2
Flask-Cors==3.0.9
Flask-JWT-Extended==3.24.1
Flask-JWT-Extended==3.25.0
Flask-Mail==0.9.1
Flask-Migrate==2.5.3
flask-restx==0.2.0
Expand Down
Empty file.
Loading

0 comments on commit fe9d46f

Please sign in to comment.