def create_sample_course_framework(self, NC, NU, NL): """ create a user, courses, units, and lessons for the purpose of testing the api NC is the number of courses to create NU is the number of units, NL is the number of lessons """ user = self.create_and_return_local_user() course_id_bank = [] for course in range(NC): course_id = new_course({ 'title': 'Foo Course %s' % course, 'teacher': user.key.id() }) course_id_bank.append(course_id) unit_id_bank = [] for course_id in course_id_bank: for unit in range(NU): unit_id = new_unit({ 'title': 'Foo Unit %s' % unit, 'course': course_id }) unit_id_bank.append(unit_id) for unit_id in unit_id_bank: for lesson in range(NL): new_lesson({ 'title': 'Foo Lesson %s' % lesson, 'unit': unit_id })
def test_new_course_with_bad_user_id(self): """ attempt to create a course with a bad user id should raise an exception """ content = { 'title' : 'foo course', 'body' : 'this course has no owner', 'teacher' : 99999999 } self.assertRaises(Exception, new_course, content) # let's also make sure the error message was passed! try: new_course(content) except Exception as e: self.assertIn("that user does not exist", str(e))
def test_new_unit_creation(self): """ assert that a new unit can be created using the new unit function """ local_user = self.create_and_return_local_user() course_id = new_course({ 'teacher' : local_user.key.id(), 'title' : 'foo course', 'body' : 'hey look mom', }) unit_id = new_unit({ 'course' : course_id, 'title' : 'foo unit', 'body' : 'bla bla unit body', }) unit = ndb.Key('Curriculum', unit_id).get() course = ndb.Key('Curriculum', course_id).get() # check that the correct content properties were set self.assertEqual(unit.content['title'], 'foo unit') self.assertEqual(unit.content['body'], 'bla bla unit body') # check that the correct inferred properties were set self.assertEqual(unit.content['course'], course_id) self.assertEqual(unit.content['teacher'], int(local_user.key.id())) self.assertEqual(unit.content_type, 'unit') # check that the parent course correctly had this new unit id appended self.assertIn(unit_id, course.content['units'])
def test_new_unit_creation(self): """ assert that a new unit can be created using the new unit function """ local_user = self.create_and_return_local_user() course_id = new_course({ 'teacher': local_user.key.id(), 'title': 'foo course', 'body': 'hey look mom', }) unit_id = new_unit({ 'course': course_id, 'title': 'foo unit', 'body': 'bla bla unit body', }) unit = ndb.Key('Curriculum', unit_id).get() course = ndb.Key('Curriculum', course_id).get() # check that the correct content properties were set self.assertEqual(unit.content['title'], 'foo unit') self.assertEqual(unit.content['body'], 'bla bla unit body') # check that the correct inferred properties were set self.assertEqual(unit.content['course'], course_id) self.assertEqual(unit.content['teacher'], int(local_user.key.id())) self.assertEqual(unit.content_type, 'unit') # check that the parent course correctly had this new unit id appended self.assertIn(unit_id, course.content['units'])
def create_sample_course_framework(self,NC,NU,NL): """ create a user, courses, units, and lessons for the purpose of testing the api NC is the number of courses to create NU is the number of units, NL is the number of lessons """ user = self.create_and_return_local_user() course_id_bank = [] for course in range(NC): course_id = new_course({ 'title' : 'Foo Course %s' % course, 'teacher' : user.key.id() }) course_id_bank.append(course_id) unit_id_bank = [] for course_id in course_id_bank: for unit in range(NU): unit_id = new_unit({ 'title' : 'Foo Unit %s' % unit, 'course' : course_id }) unit_id_bank.append(unit_id) for unit_id in unit_id_bank: for lesson in range(NL): new_lesson({ 'title' : 'Foo Lesson %s' % lesson, 'unit' : unit_id })
def test_new_course_with_bad_user_id(self): """ attempt to create a course with a bad user id should raise an exception """ content = { 'title': 'foo course', 'body': 'this course has no owner', 'teacher': 99999999 } self.assertRaises(Exception, new_course, content) # let's also make sure the error message was passed! try: new_course(content) except Exception as e: self.assertIn("that user does not exist", str(e))
def post(self, content_id=None): """ handle the post request for the CurriculumAPI if no content_id then assumption is new entity, else the assumption is to edit an existing entity """ if not users.get_current_user(): return {'error': 'you must be logged in'}, 401 else: parser = reqparse.RequestParser() parser.add_argument('content_type', type=str) parser.add_argument('teacher', type=str) parser.add_argument('title', type=str) parser.add_argument('body', type=str) parser.add_argument('private', type=str) parser.add_argument('course', type=str) parser.add_argument('unit', type=str) args = parser.parse_args() try: content = {} content_type = args['content_type'] if content_type not in ['course', 'unit', 'lesson']: raise TypeError('invalid content type') googleID = users.get_current_user().user_id() content['teacher'] = get_user_by_google_id(googleID).key.id() if content_type == 'lesson': # the first line of the lesson body IS the title title = args['body'].strip().splitlines()[0] content['title'] = re.sub('^#+', '', title) else: content['title'] = args['title'] content['body'] = args['body'] content['private'] = args['private'] if not content_id: if content_type == 'course': content_id = new_course(content) if content_type == 'unit': content['course'] = args['course'] content_id = new_unit(content) if content_type == 'lesson': content['unit'] = args['unit'] content_id = new_lesson(content) else: modify_content(content, content_id) new_content = get_content_by_id(content_id) data = content_to_dict(new_content) except Exception as e: logging.info(e) return {'error' : str(e)}, 500 else: return data
def test_that_new_course_shows_up_in_authors_course_list(self): """ a new course should be appended to the author's course list """ local_user = self.create_and_return_local_user() content = { 'teacher' : int(local_user.key.id()), 'title' : 'foo course', 'body' : 'study hard, learn well, duh', } course_id = new_course(content) self.assertIn(course_id, local_user.courses)
def test_that_new_course_shows_up_in_authors_course_list(self): """ a new course should be appended to the author's course list """ local_user = self.create_and_return_local_user() content = { 'teacher': int(local_user.key.id()), 'title': 'foo course', 'body': 'study hard, learn well, duh', } course_id = new_course(content) self.assertIn(course_id, local_user.courses)
def test_new_course_controller(self): """ test that the new course controller is working property """ local_user = self.create_and_return_local_user() content = { 'teacher': int(local_user.key.id()), 'title': 'foo course', 'body': 'study hard, learn well, duh', } course_id = new_course(content) fetched_course = ndb.Key('Curriculum', course_id).get() self.assertEqual(fetched_course.content['title'], 'foo course')
def test_new_course_controller(self): """ test that the new course controller is working property """ local_user = self.create_and_return_local_user() content = { 'teacher' : int(local_user.key.id()), 'title' : 'foo course', 'body' : 'study hard, learn well, duh', } course_id = new_course(content) fetched_course = ndb.Key('Curriculum', course_id).get() self.assertEqual(fetched_course.content['title'], 'foo course')
def post(self, contentID=None): """ handle the post request for the CurriculumAPI if no contentID then assumption is new entity, else the assumption is to edit an existing entity acceptable params of the data sent in the post request include: 'content_type' : str 'title' : str 'body' : str 'private' : bool """ try: content_type = self.request.POST.get('content_type') if content_type not in ['course', 'unit', 'lesson']: raise TypeError('invalid content type') googleID = users.get_current_user().user_id() content = {} content['teacher'] = get_user_by_google_id(googleID).key.id() if content_type == 'lesson': # the first line of the lesson body IS the title body = self.request.POST.get('body') title = body.splitlines()[0] content['title'] = re.sub('^#+', '', title) else: content['title'] = self.request.POST.get('title') content['body'] = self.request.POST.get('body') content['private'] = self.request.POST.get('private') if contentID is None: if content_type == 'course': contentID = new_course(content) if content_type == 'unit': content['course'] = self.request.POST.get('course') contentID = new_unit(content) if content_type == 'lesson': content['unit'] = self.request.POST.get('unit') contentID = new_lesson(content) else: modify_content(content, contentID) new_content = get_content_by_id(contentID) data = content_to_dict(new_content) except Exception as e: data = {'error' : str(e)} logging.info(data) self.write_json(data)
def post(self, contentID=None): """ handle the post request for the CurriculumAPI if no contentID then assumption is new entity, else the assumption is to edit an existing entity acceptable params of the data sent in the post request include: 'content_type' : str 'title' : str 'body' : str 'private' : bool """ try: content_type = self.request.POST.get('content_type') if content_type not in ['course', 'unit', 'lesson']: raise TypeError('invalid content type') googleID = users.get_current_user().user_id() content = {} content['teacher'] = get_user_by_google_id(googleID).key.id() if content_type == 'lesson': # the first line of the lesson body IS the title body = self.request.POST.get('body') title = body.splitlines()[0] content['title'] = re.sub('^#+', '', title) else: content['title'] = self.request.POST.get('title') content['body'] = self.request.POST.get('body') content['private'] = self.request.POST.get('private') if contentID is None: if content_type == 'course': contentID = new_course(content) if content_type == 'unit': content['course'] = self.request.POST.get('course') contentID = new_unit(content) if content_type == 'lesson': content['unit'] = self.request.POST.get('unit') contentID = new_lesson(content) else: modify_content(content, contentID) new_content = get_content_by_id(contentID) data = content_to_dict(new_content) except Exception as e: data = {'error': str(e)} logging.info(data) self.write_json(data)
def create_new_approval(self): """ a helper class for quickly creating a new approval item """ teacher = self.create_and_return_local_user() course_id = new_course({ 'teacher': teacher.key.id(), 'title': 'foo course', 'body': 'hey look mom', }) new_approval_request(course=get_course_by_id(course_id), googleID='123', formalName='John Doe', email='*****@*****.**')
def test_simple_content_model_conversion(self): """ create a simple model and pass it to the content_to_dict controller """ local_user = self.create_and_return_local_user() course_id = new_course({ 'teacher' : local_user.key.id(), 'title' : 'foo course', 'body' : 'hey look mom', }) course = get_content_by_id(course_id) dict_content = content_to_dict(course) self.assertEqual(dict_content['content_type'], 'course') self.assertEqual(dict_content['content']['title'], 'foo course')
def test_non_authenticated_get_private_course(self): """ attempt to fetch a private course from a non-authenticated user non-authenticated means not logged into google """ author = self.create_and_return_local_user() course_id = new_course({ 'title': 'Foo Course', 'teacher': author.key.id(), 'private': True, }) response = self.testapp.get('/api/curriculum/%s' % course_id, ) data = json.loads(response.body) self.assertIn('error', data)
def create_new_approval(self): """ a helper class for quickly creating a new approval item """ teacher = self.create_and_return_local_user() course_id = new_course({ 'teacher' : teacher.key.id(), 'title' : 'foo course', 'body' : 'hey look mom', }) new_approval_request( course = get_course_by_id(course_id), googleID='123', formalName='John Doe', email='*****@*****.**')
def test_non_authorized_get_private_course(self): """ attempt to fetch a private course from authenticated/non-approved user non-approved means the user has a google account which has not been awarded access by the teacher """ author = self.create_and_return_local_user() course_id = new_course({ 'title': 'Foo Course', 'teacher': author.key.id(), 'private': True, }) self.create_google_user() response = self.testapp.get('/api/curriculum/%s' % course_id, ) data = json.loads(response.body) self.assertIn('error', data)
def test_non_authenticated_get_private_course(self): """ attempt to fetch a private course from a non-authenticated user non-authenticated means not logged into google """ author = self.create_and_return_local_user() course_id = new_course({ 'title' : 'Foo Course', 'teacher' : author.key.id(), 'private' : True, }) response = self.testapp.get( '/api/curriculum/%s' % course_id, ) data = json.loads(response.body) self.assertIn('error', data)
def test_user_with_courses(self): """ create a user + a course and see that the course is actually appended to the user's json object """ teacher = self.create_and_return_local_user(username='******') user_id = teacher.key.id() content = { 'teacher': int(teacher.key.id()), 'title': 'foo course', 'body': 'study hard, learn well, duh', } course_id = new_course(content) response = self.testapp.get('/api/user/%s' % user_id) user_data = json.loads(response.body) user_courses = user_data['courses'] first_course = user_courses[0] self.assertEqual(course_id, first_course['id'])
def test_user_with_courses(self): """ create a user + a course and see that the course is actually appended to the user's json object """ teacher = self.create_and_return_local_user(username='******') user_id = teacher.key.id() content = { 'teacher' : int(teacher.key.id()), 'title' : 'foo course', 'body' : 'study hard, learn well, duh', } course_id = new_course(content) response = self.testapp.get('/api/user/%s' % user_id) user_data = json.loads(response.body) user_courses = user_data['courses'] first_course = user_courses[0] self.assertEqual(course_id, first_course['id'])
def test_non_authorized_get_private_course(self): """ attempt to fetch a private course from authenticated/non-approved user non-approved means the user has a google account which has not been awarded access by the teacher """ author = self.create_and_return_local_user() course_id = new_course({ 'title' : 'Foo Course', 'teacher' : author.key.id(), 'private' : True, }) self.create_google_user() response = self.testapp.get( '/api/curriculum/%s' % course_id, ) data = json.loads(response.body) self.assertIn('error', data)
def create_several_approvals_for_course(self, number_of_courses=1): """ create a course then approve several googleID's to access the course a helper method for the tests in this class; returns the course for which the approvals were generated. If more than 1 course is created, return the user instead of course/ids """ teacher = self.create_and_return_local_user() for N in range(number_of_courses): course_id = new_course({ 'teacher': teacher.key.id(), 'title': 'foo course', 'body': 'hey look mom', }) list_of_ids_to_approve = [1, 2, 3, 4, 5] course = get_course_by_id(course_id) for i in list_of_ids_to_approve: new_approval_request(course=course, googleID=i, formalName='John Doe %s' % i, email='*****@*****.**' % i)
def create_several_approvals_for_course(self, number_of_courses = 1): """ create a course then approve several googleID's to access the course a helper method for the tests in this class; returns the course for which the approvals were generated. If more than 1 course is created, return the user instead of course/ids """ teacher = self.create_and_return_local_user() for N in range(number_of_courses): course_id = new_course({ 'teacher' : teacher.key.id(), 'title' : 'foo course', 'body' : 'hey look mom', }) list_of_ids_to_approve = [1,2,3,4,5] course = get_course_by_id(course_id) for i in list_of_ids_to_approve: new_approval_request( course = course, googleID=i, formalName='John Doe %s' % i, email='*****@*****.**' % i )
def get(self, migration_type=None): current_user = users.get_current_user() if current_user.email() != '*****@*****.**': abort(403) else: if migration_type == 'clear_content': ndb.delete_multi(Curriculum.query().fetch(keys_only=True)) elif migration_type == 'clear_teacher_courses': teachers = User.query() for teacher in teachers: logging.info('clearing courses for %s' % teacher.key.id()) teacher.courses = [] teacher.put() logging.info('Completed clearing courses for %s' % teacher.key.id()) elif migration_type == 'course': courses = Content.query(Content.contentType == 'course') for course in courses: if course.listed != 'done_migrating3': try: logging.info("Begin course migration for %s" % course.key.id()) app_user = course.key.parent().get() teacher = get_user_by_google_id(app_user.googleID) course_data = { 'teacher' : teacher.key.id(), 'title' : course.title, 'body' : course.body } new_course_id = new_course(course_data) logging.info("Saved data for Curriculum ID: %s" % new_course_id) units = Content.query(Content.contentType == 'unit', ancestor=course.key) for unit in units: logging.info("Begin unit migration for %s" % unit.key.id()) unit_data = { 'teacher' : teacher.key.id(), 'course' : new_course_id, 'title' : unit.title, 'body' : unit.body } new_unit_id = new_unit(unit_data) logging.info("Saved data for Unit ID: %s" % new_unit_id) lessons = Content.query(Content.contentType == 'lesson', ancestor=unit.key) for lesson in lessons: logging.info("Begin lesson migration for %s" % lesson.key.id()) lesson_data = { 'teacher' : teacher.key.id(), 'course' : new_course_id, 'unit' : new_unit_id, 'title' : lesson.title, 'body' : lesson.body } lesson_id = new_lesson(lesson_data) logging.info("Saved data for Lesson ID: %s" % lesson_id) course.listed = 'done_migrating3' course.put() logging.info("Finished course migration for %s" % course.key.id()) except Exception as e: logging.info("Error migrating course %s" % course.key.id()) logging.info(str(e)) return render_template( 'migrate.html', status_msg = 'migration complete' )