def copy_course_background_task()

in microservices/lms/src/services/section_service.py [0:0]


def copy_course_background_task(course_template_details,
                                sections_details,
                                cohort_details,
                                lms_job_id,current_course,
                                message=""):
  """Create section  Background Task to copy course and updated database
  for newly created section
  Args:
    course_template_details (template object): course template object which
    will referenced in section
    sections_details (str):Input section details provided by user in API
    cohort_details(str):course template object which will
    referenced in section
    headers(str):Authentications headers
  Raises:
    HTTPException: 500 Internal Server Error if something fails

  Returns:
    True : (bool) on success
  """
  lms_job = LmsJob.find_by_id(lms_job_id)
  logs = lms_job.logs
  Logger.info(current_course)
  try:
    # Create a new course
    info_msg = f"Background Task started for the cohort id {cohort_details.id}\
                course template {course_template_details.id} \
                with section name{sections_details.name}"

    logs["info"].append(info_msg)
    Logger.info(info_msg)

    new_course = classroom_crud.create_course(course_template_details.name,
                                              sections_details.description,
                                              sections_details.name, "me")

    lms_job.classroom_id = new_course["id"]
    lms_job.start_time = datetime.datetime.utcnow()
    lms_job.status = "running"
    lms_job.update()

    # Create section with the required fields
    section = Section()
    section.name = course_template_details.name
    section.section = sections_details.name
    section.description = sections_details.description
    section.max_students = sections_details.max_students
    # Reference document can be get using get() method
    section.course_template = course_template_details
    section.cohort = cohort_details
    section.classroom_id = new_course["id"]
    section.classroom_code = new_course["enrollmentCode"]
    section.classroom_url = new_course["alternateLink"]
    section.enrolled_students_count = 0
    section.status = "PROVISIONING"
    section_id = section.save().id
    classroom_id = new_course["id"]

    lms_job.section_id = section_id
    lms_job.update()

    error_flag = False
    target_folder_id = new_course["teacherFolder"]["id"]
    logs["info"].append(
        f"ID of target drive folder for section {target_folder_id}")
    Logger.info(f"ID of target drive folder for section {target_folder_id}")

    # Get topics of current course
    topics = classroom_crud.get_topics(course_template_details.classroom_id)
    # add new_course to pubsub topic for both course work and roaster changes
    classroom_crud.enable_notifications(new_course["id"], "COURSE_WORK_CHANGES")
    classroom_crud.enable_notifications(new_course["id"],
                                        "COURSE_ROSTER_CHANGES")
    # add instructional designer
    list_course_template_enrollment_mapping = CourseTemplateEnrollmentMapping\
      .fetch_all_by_course_template(course_template_details.key)
    if list_course_template_enrollment_mapping:
      for course_template_mapping in list_course_template_enrollment_mapping:
        try:
          add_instructional_designer_into_section(section,
                                                  course_template_mapping)
        except Exception as error:
          error = traceback.format_exc().replace("\n", " ")
          Logger.error(f"Create teacher failed for \
              for {course_template_details.instructional_designer}")
          Logger.error(error)

    #If topics are present in course create topics returns a dict
    # with keys a current topicID and new topic id as values
    if topics is not None:
      topic_id_map = classroom_crud.create_topics(new_course["id"], topics)
    # Calling function to get edit_url and view url of
    # google form which returns
    # a dictionary of view_links as keys and edit
    #  links/  and file_id as values for all drive files
    # url_mapping = classroom_crud.get_edit_url_and_view_url_mapping_of_folder(
    #   current_course["teacherFolder"]["id"])

    # Get coursework of current course and create a new course
    coursework_list = classroom_crud.get_coursework_list(
        course_template_details.classroom_id)

    # final_coursewok=[]
    for coursework in coursework_list:
      coursework_lti_assignment_ids = []
      try:
        #Check if a coursework is linked to a topic if yes then
        # replace the old topic id to new topic id using topic_id_map

        lti_assignment_details = {
            "section_id": section_id,
            "source_context_id": course_template_details.id,
            "coursework_title": coursework["title"],
            "start_date": None,
            "end_date": None,
            "due_date": None
        }

        # Update the due date of the course work if exists
        if coursework.get("dueDate"):
          coursework_due_date = coursework.get("dueDate")

          if coursework.get("dueTime"):
            coursework_due_time = coursework.get("dueTime")
            coursework_due_datetime = datetime.datetime(
                coursework_due_date.get("year"),
                coursework_due_date.get("month"),
                coursework_due_date.get("day"),
                coursework_due_time.get("hours", 0),
                coursework_due_time.get("minutes", 0))
          else:
            coursework_due_datetime = datetime.datetime(
                coursework_due_date.get("year"),
                coursework_due_date.get("month"),
                coursework_due_date.get("day"))

          curr_utc_timestamp = datetime.datetime.utcnow()
          lti_assignment_details["start_date"] = (
              cohort_details.start_date).strftime("%Y-%m-%dT%H:%M:%S%z")

          if coursework_due_datetime < curr_utc_timestamp:
            # Commented for now as the due dates are supposed to be updated by the user before
            # starting the copy course process

            # coursework["dueDate"] = {
            #   "year": cohort_details.end_date.year,
            #   "month": cohort_details.end_date.month,
            #   "day": cohort_details.end_date.day
            # }
            # coursework["dueTime"] = {
            #   "hours": cohort_details.end_date.hour,
            #   "minutes": cohort_details.end_date.minute
            # }

            lti_assignment_details["end_date"] = lti_assignment_details[
                "due_date"] = (
                    cohort_details.end_date).strftime("%Y-%m-%dT%H:%M:%S%z")

          else:
            lti_assignment_details["end_date"] = lti_assignment_details[
                "due_date"] = coursework_due_datetime.strftime(
                    "%Y-%m-%dT%H:%M:%S%z")

        if "topicId" in coursework.keys():
          coursework["topicId"] = topic_id_map[coursework["topicId"]]
        #Check if a material is present in coursework
        if "materials" in coursework.keys():
          coursework_update_output = update_coursework_material(
              materials=coursework["materials"],
              target_folder_id=target_folder_id,
              error_flag=error_flag,
              lti_assignment_details=lti_assignment_details,
              logs=logs)
          coursework["materials"] = coursework_update_output["material"]
          error_flag = coursework_update_output["error_flag"]
          coursework_lti_assignment_ids.extend(
              coursework_update_output["lti_assignment_ids"])
        # final_coursewok.append(coursework)

        coursework_data = classroom_crud.create_coursework(
            new_course["id"], coursework)

        for assignment_id in coursework_lti_assignment_ids:
          coursework_id = coursework_data.get("id")
          input_json = {"course_work_id": coursework_id}
          # update assignment with new coursework id
          lti_assignment_req = requests.patch(
              f"http://classroom-shim/classroom-shim/api/v1/lti-assignment/{assignment_id}",
              headers={
                  "Authorization": f"Bearer {auth_client.get_id_token()}"
              },
              json=input_json,
              timeout=60)

          if lti_assignment_req.status_code != 200:
            error_flag = True
            error_msg = f"Failed to update assignment {assignment_id} with course work id \
                          {coursework_id} due to error - {lti_assignment_req.text} with \
                            status code - {lti_assignment_req.status_code} for course work"

            logs["errors"].append(error_msg)
            Logger.error(error_msg)

          logs["info"].append(
              f"Updated the course work id for new LTI assignment - {assignment_id}"
          )
          Logger.info(
              f"Updated the course work id for new LTI assignment - {assignment_id}"
          )

      except Exception as error:
        title = coursework["title"]
        error_flag = True
        logs["errors"].append(f"Error - {error} for '{title}'")
        logs["errors"].append(f"Copy coursework failed for \
              course_id {course_template_details.classroom_id} for '{title}'")
        Logger.error(f"Copy coursework failed for \
              course_id {course_template_details.classroom_id} for '{title}'")
        error = traceback.format_exc().replace("\n", " ")
        Logger.error(error)
        continue

    # # Create coursework in new course
    # # return final_coursewok
    # if final_coursewok is not None:
    #   classroom_crud.create_coursework(new_course["id"],final_coursewok)
    # Get the list of courseworkMaterial
    # final_coursewok_material = []
    coursework_material_list = classroom_crud.get_coursework_material_list(
        course_template_details.classroom_id)
    for coursework_material in coursework_material_list:
      coursework_material_lti_assignment_ids = []
      try:
        #Check if a coursework material is linked to a topic if yes then
        # replace the old topic id to new topic id using topic_id_map

        lti_assignment_details = {
            "section_id": section_id,
            "source_context_id": course_template_details.id,
            "coursework_title": coursework_material["title"],
            "start_date": None,
            "end_date": None,
            "due_date": None
        }

        if "topicId" in coursework_material.keys():
          coursework_material["topicId"] = topic_id_map[
              coursework_material["topicId"]]
        #Check if a material is present in coursework
        if "materials" in coursework_material.keys():

          coursework_material_update_output = update_coursework_material(
              materials=coursework_material["materials"],
              target_folder_id=target_folder_id,
              error_flag=error_flag,
              lti_assignment_details=lti_assignment_details,
              logs=logs)

          coursework_material["materials"] = coursework_material_update_output[
              "material"]
          error_flag = coursework_update_output["error_flag"]
          coursework_material_lti_assignment_ids.extend(
              coursework_update_output["lti_assignment_ids"])
          print("Updated coursework material attached")

        coursework_material_data = classroom_crud.create_coursework_material(new_course["id"],
                                                coursework_material)

        for assignment_id in coursework_material_lti_assignment_ids:
          coursework_id = coursework_material_data.get("id")
          input_json = {"course_work_id": coursework_id}
          # update assignment with new coursework id
          lti_assignment_req = requests.patch(
              f"http://classroom-shim/classroom-shim/api/v1/lti-assignment/{assignment_id}",
              headers={
                  "Authorization": f"Bearer {auth_client.get_id_token()}"
              },
              json=input_json,
              timeout=60)

          if lti_assignment_req.status_code != 200:
            error_flag = True
            error_msg = f"Failed to update assignment {assignment_id} with course work id \
                          {coursework_id} due to error - {lti_assignment_req.text} with \
                            status code - {lti_assignment_req.status_code} for course work material"

            logs["errors"].append(error_msg)
            Logger.error(error_msg)

          logs["info"].append(
              f"Updated the id for course work material for new LTI assignment - {assignment_id}"
          )
          Logger.info(
              f"Updated the id course work material for new LTI assignment - {assignment_id}"
          )

        # final_coursewok_material.append(coursework_material)
      except Exception as error:
        title = coursework_material["title"]
        error_flag = True
        Logger.error(f"Get coursework material failed for\
        course_id {course_template_details.classroom_id} for {title}")

        logs["errors"].append(f"Error - {error}")
        logs["errors"].append(f"Get coursework material failed for\
        course_id {course_template_details.classroom_id} for {title}")
        error = traceback.format_exc().replace("\n", " ")
        Logger.error(error)
        continue

    # # Create coursework in new course
    # if final_coursewok_material is not None:
    #   classroom_crud.create_coursework_material(new_course["id"],
    #                                             final_coursewok_material)

    # Classroom copy is successful then the section status is changed to active
    if error_flag:
      section.status = "FAILED_TO_PROVISION"
    else:
      section.status = "ACTIVE"
    section.update()

    rows=[{
      "sectionId":section_id,\
      "courseId":new_course["id"],\
      "classroomUrl":new_course["alternateLink"],\
        "name":new_course["section"],\
        "description":new_course["description"],\
          "cohortId":cohort_details.id,\
        "courseTemplateId":course_template_details.id,\
          "status":section.status,\
        "enrollmentStatus": section.enrollment_status,
        "maxStudents": section.max_students,
          "timestamp":datetime.datetime.utcnow()
    }]
    insert_rows_to_bq(
        rows=rows,
        dataset=BQ_DATASET,
        table_name=BQ_TABLE_DICT["BQ_COLL_SECTION_TABLE"])
    Logger.info(message)
    Logger.info(f"Background Task Completed for section Creation for cohort\
                {cohort_details.id}")
    Logger.info(f"Section Details are section id {section_id},\
                classroom id {classroom_id}")

    logs["info"].append(
        f"Background Task Completed for section Creation for cohort\
                {cohort_details.id}")
    logs["info"].append(f"Section Details are section id {section_id},\
                classroom id {classroom_id}")

    lms_job.logs = logs
    if error_flag:
      lms_job.status = "failed"
    else:
      lms_job.status = "success"
    lms_job.end_time = datetime.datetime.utcnow()
    lms_job.update()

    return True
  except Exception as e:
    error = traceback.format_exc().replace("\n", " ")
    Logger.error(error)
    Logger.error(e)

    logs["errors"].append(str(e))
    lms_job.logs = logs
    lms_job.end_time = datetime.datetime.utcnow()
    lms_job.status = "failed"
    lms_job.update()

    raise InternalServerError(str(e)) from e