microservices/lms/src/services/student_service.py (125 lines of code) (raw):
"""Student API services"""
import requests
import traceback
import datetime
from config import USER_MANAGEMENT_BASE_URL,BQ_TABLE_DICT,BQ_DATASET
from services.section_service import insert_section_enrollment_to_bq
from common.utils import classroom_crud
from common.utils.bq_helper import insert_rows_to_bq
from common.utils.logging_handler import Logger
from common.models import CourseEnrollmentMapping, User
from common.utils.errors import (ResourceNotFoundException,
UserManagementServiceError)
from common.utils.http_exceptions import (Conflict, InternalServerError)
def get_section_with_minimum_student(sections):
"""Get section with minimum count of students
Args:
sections :list of section objects with same cohort
Returns: sections object with minimum count of studnet
returns none if max student count is reached in all sections
"""
min_sections_count_mapping = None
min_student = 0
for section in sections:
if min_sections_count_mapping is None:
if section.enrolled_students_count < section.max_students and\
section.status =="ACTIVE" and section.enrollment_status=="OPEN":
min_sections_count_mapping = section
min_student = section.enrolled_students_count
else:
if section.enrolled_students_count < min_student and\
section.enrolled_students_count < section.max_students and\
section.status =="ACTIVE" and section.enrollment_status=="OPEN":
min_student = section.enrolled_students_count
min_sections_count_mapping = section
return min_sections_count_mapping
def check_student_can_enroll_in_cohort(email, headers, sections):
"""
Args:
sections :list of section objects with from same cohort
email : student email
headers : Authentication headers
Returns: boolean value
True : Student can be enroll
"""
try:
student_details = classroom_crud.get_user_details_by_email(
user_email=email, headers=headers)
except ResourceNotFoundException as rte:
err = traceback.format_exc().replace("\n", " ")
Logger.error(err)
Logger.error(rte)
Logger.info("Student is not present in database")
return True
if student_details["data"] != []:
user_id = student_details["data"][0]["user_id"]
for section in sections:
result = CourseEnrollmentMapping.check_enrollment_exists_section(
section_key=section.key, user_id=user_id)
if result is not None:
Logger.error(f"Student {email} is present in section_id {section.id}\
enrollment_id {result.id}")
return False
return True
def insert_failure_log(email:str, section_id:str, cohort_id:str,
err:str, error_type:str):
"""
Insert enrollment error logs to BQ
"""
rows = [{
"email": email,
"error_type": error_type,
"traceback": err,
"log_time": datetime.datetime.utcnow(),
"section_id": section_id,
"cohort_id": cohort_id
}]
insert_rows_to_bq(rows=rows,
dataset=BQ_DATASET,
table_name=BQ_TABLE_DICT["BQ_ENROLLMENT_FAILURE_LOGS"])
def invite_student(section, student_email, headers):
"""
Args:
section :section
student_email : student email to be invited
headers : Authentication headers
Returns: dictionary with course_enrollment_id,user_id,invitation_id,
cohort_id,section_id,classroom_id,classroom_url
"""
searched_student = classroom_crud.\
get_user_details_by_email(user_email=student_email,headers=headers)
# If the response is success check if student is inactive i.e raise error
searched_student = searched_student["data"]
if searched_student == []:
Logger.info(f"User {student_email} is not present in database")
# User does not exist in db call create User API
body = {
"first_name": "first_name",
"last_name": "last_name",
"email": student_email,
"user_type": "learner",
"user_groups": [],
"status": "active",
"is_registered": True,
"failed_login_attempts_count": 0,
"access_api_docs": False
}
create_user_response = requests.post(f"{USER_MANAGEMENT_BASE_URL}/user",
json=body,
headers=headers)
Logger.info(create_user_response.json())
if create_user_response.status_code != 200:
raise UserManagementServiceError(
f"Create User API Error {create_user_response.status_code}")
user_id = create_user_response.json()["data"]["user_id"]
else:
if searched_student[0]["status"] == "inactive":
raise InternalServerError("Student inactive in \
database. Please update\
the student status")
else:
user_id = searched_student[0]["user_id"]
check_already_invited = CourseEnrollmentMapping.\
check_enrollment_exists_section(
section_key=section.key,user_id=user_id)
if check_already_invited:
Logger.error(
f"User {student_email} is already invited or "
+ f"enrolled in this section as {check_already_invited.role}")
raise Conflict(
f"User {student_email} is invited or enrolled "
+ f"in this section as {check_already_invited.role}")
invitation = classroom_crud.invite_user(course_id=section.classroom_id,
email=student_email,
role="STUDENT")
Logger.info(
f"User with Email {student_email} present with user_id {user_id}")
course_enrollment_mapping = CourseEnrollmentMapping()
course_enrollment_mapping.section = section
course_enrollment_mapping.user = User.find_by_user_id(user_id)
course_enrollment_mapping.status = "invited"
course_enrollment_mapping.role = "learner"
course_enrollment_mapping.invitation_id = invitation["id"]
course_enrollment_id = course_enrollment_mapping.save().id
insert_section_enrollment_to_bq(course_enrollment_mapping,section)
return {
"invitation_id": invitation["id"],
"course_enrollment_id": course_enrollment_id,
"user_id": user_id,
"section_id": section.id,
"cohort_id": section.cohort.key,
"classroom_id": section.classroom_id,
"classroom_url": section.classroom_url
}