# Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. # SPDX-License-Identifier: Apache-2.0 import json import os import boto3 import base64 import datetime import calendar from bs4 import BeautifulSoup from botocore.exceptions import ClientError def get_secret(secrets_name): """ function: get_secret from AWS Secrets Manager This function retrieves the secret string from AWS Secrets Manager. We will retrieve the Canvas API Token using this function. Refer to the readme for more details on how to store secret in AWS Secrets Manager, and configure QnABot with the secret key name. """ region_name = os.environ['AWS_REGION'] # Create a Secrets Manager client session = boto3.session.Session() client = session.client( service_name='secretsmanager', region_name=region_name ) # In this sample we only handle the specific exceptions for the 'GetSecretValue' API. # See https://docs.aws.amazon.com/secretsmanager/latest/apireference/API_GetSecretValue.html # We rethrow the exception by default. try: get_secret_value_response = client.get_secret_value( SecretId=secrets_name ) # Decrypts secret using the associated KMS CMK. # Depending on whether the secret is a string or binary, one of these fields will be populated. if 'SecretString' in get_secret_value_response: secret = get_secret_value_response['SecretString'] secret = json.loads(get_secret_value_response['SecretString'])['API_Token'] else: decoded_binary_secret = base64.b64decode(get_secret_value_response['SecretBinary']) secret = decoded_binary_secret.API_Token except ClientError as e: print ("ERROR: "+ str(e)) #print the exception raise e #return the API token return secret def getCanvasUser (param_canvas, param_user_name): """ function to get Canvas User This function retrieves the Canvas user by using the SIS Login ID """ user = param_canvas.get_user(param_user_name, 'sis_login_id') return user def query_menu (event, student_name): """ function to get menu """ # provide a menu to choose from (announcements, enrollments, syllabus, assignments, grades) choicelist = [{'text':'Announcements','value':"tell me about my announcements"}, {'text':'Course Enrollments','value':"tell me about my enrollments"}, {'text':'Course Syllabus','value':"tell me about my syllabus"}, {'text':'Assignments','value':"tell me about my assignments"}, {'text':'Grades','value':"tell me about my grades"}] genericAttachments = {'version': '1','contentType': 'application/vnd.amazonaws.card.generic','genericAttachments':[{"title":"response buttons","buttons":choicelist}]} event['res']['session']['appContext']['responseCard'] = genericAttachments event['res']['session']['appContext']['altMessages']['markdown'] = "Please select one of the options below:" intCounter = 0 strChoiceList = "" for items in choicelist: if strChoiceList != '': strChoiceList = strChoiceList + ", " strChoiceList = strChoiceList + choicelist[intCounter]['text'] intCounter = intCounter + 1 event['res']['session']['appContext']['altMessages']['ssml'] = get_SSML_output("Please select one of these options: " + strChoiceList) return event def query_enrollments_for_student(event, canvas, student_user_name): """ function: query_enrollments_for_student This function retrieves students' active enrollments """ # Get the user using user_id to match with LMS SIS_ID try: user = getCanvasUser (canvas, student_user_name) except: return user_not_found_error (event) if user: courses = user.get_courses(enrollment_status='active',include=['syllabus_body']) # Loop through the courses. course_names = [course.name for course in courses] result = {"CourseNames": course_names} return_courses = result['CourseNames'] if return_courses: choicelist = [] for i in return_courses: choicelist.append({'text':i,'value':"more information about my {} course".format(i)}) genericAttachments = {'version': '1','contentType': 'application/vnd.amazonaws.card.generic','genericAttachments':[{"title":"response buttons","buttons":choicelist}]} event['res']['session']['appContext']['responseCard'] = genericAttachments event['res']['session']['appContext']['altMessages']['markdown'] = "Please select one of the options below:" intCounter = 0 strChoiceList = "" for items in choicelist: if strChoiceList != '': strChoiceList = strChoiceList + ", " strChoiceList = strChoiceList + choicelist[intCounter]['text'] intCounter = intCounter + 1 event['res']['session']['appContext']['altMessages']['ssml'] = get_SSML_output("Please select one of these options: " + strChoiceList) else: return_message = "You are not currently enrolled in any courses." set_alt_message (event, return_message) return event def query_courses_for_student(event, canvas, student_user_name, course_name_to_filter): """ function: query_courses_for_student This function retrieves course options across all active enrolled courses, or for a particular course, for the student for example: more information about {course name} """ # Get the user using user_id to match with LMS SIS_ID try: user = getCanvasUser (canvas, student_user_name) except: return user_not_found_error (event) blnFoundCourse = False if user: courses = user.get_courses(enrollment_status='active') # Loop through the courses. for course in courses: if course_name_to_filter != '' and course.name.upper().strip() == course_name_to_filter.upper(): result = {"Choice": course.name} blnFoundCourse = True break if blnFoundCourse == False: result = {"Choice": 'N/A'} else: result = {"Choice": 'N/A'} returned_course = result['Choice'] if returned_course == 'N/A': return_message = "Sorry, was unable to find the course you are looking for. Check the course name and try again. You can also ask what courses have i enrolled in, to get a list of enrolled courses." set_alt_message (event, return_message) else: genericattachment = ['assignments','syllabus','grades'] choicelist = [] for i in genericattachment: choicelist.append({'text':'{} {}'.format(returned_course,i),'value':'tell me about my {} {}'.format(returned_course,i)}) genericAttachments = {'version': '1','contentType': 'application/vnd.amazonaws.card.generic','genericAttachments':[{"title":"response buttons","buttons":choicelist}]} event['res']['session']['appContext']['responseCard'] = genericAttachments event['res']['session']['appContext']['altMessages']['markdown'] = "Please select one of the options below:" intCounter = 0 strChoiceList = "" for items in choicelist: if strChoiceList != '': strChoiceList = strChoiceList + ", " strChoiceList = strChoiceList + choicelist[intCounter]['text'] intCounter = intCounter + 1 event['res']['session']['appContext']['altMessages']['ssml'] = get_SSML_output("Please select one of these options: " + strChoiceList) return event def query_course_assignments_for_student(event, canvas, student_user_name, course_name_to_filter): """ function: query_course_assignments_for_student This function retrieves assignment information across all active enrolled courses, or for a particular course, for the student for example: do i have any assignments due or tell me about by {course_name} assignments """ course_assignments = '' blnHasAssignments = False blnFoundMatch = False no_records_message = 'There are no assignments for this course.' # Get the user using user_id to match with LMS SIS_ID try: user = getCanvasUser (canvas, student_user_name) except: return user_not_found_error (event) if user: courses = user.get_courses(enrollment_status='active') for course in courses: blnHasAssignments = False blnFoundMatch = False #check for matching course_name_slot_input with course names if course_name_to_filter != '' and course.name.upper().strip() == course_name_to_filter.upper(): blnFoundMatch = True if blnFoundMatch == True: course_assignments = "" + course.name + ":