def test_no_modification_on_event_has_no_effect_on_disk(self): course = MoodleCourse(self.tmp_path) quiz = course.get_activity_by_type_and_num(MoodleQuiz, 1) before_modification_dt = os.path.getmtime(quiz.path) quiz.write() self.assertTrue(before_modification_dt == os.path.getmtime(quiz.path))
def test_sort_activity_type(self): course = MoodleCourse(self.tmp_path) activities = course._load_activites()[MoodleQuiz] activities = course._sort_activity_type(activities) for i, x in enumerate([146935, 146936, 146939]): self.assertEqual(x, activities[i]['moduleid'])
def test_get_data_from_event(self): course = MoodleCourse(self.tmp_path) quiz = course.get_activity_by_type_and_num(MoodleQuiz, 1) self.assertEqual('test de remise', quiz['name']) self.assertEqual('1451709900', quiz['timeopen']) self.assertEqual('1454301900', quiz['timeclose'])
def download_planning(uuid): try: planning = _get_planning(uuid, g.user_id) except CAPException as e: return e.res moodle_archive_path = planning.mbz_fullpath planning_txt = planning.planning_txt if not planning_txt: return _bad_request() # Make tmp directory for MBZ extraction and ics download with tempfile.TemporaryDirectory() as tmp_path: # Download calendar to tmp folder calendar = CalendarReader(planning.ics_fullpath) calendar_meetings = calendar.get_all_meetings() # Extract Moodle course to tmp folder with tarfile.open(moodle_archive_path) as tar_file: tar_file.extractall(tmp_path) course = MoodleCourse(tmp_path) interpreter = Interpreter(calendar_meetings, course) for line in planning_txt.split('\n'): event = interpreter.get_new_event_from_string(line) course.replace_event(event) folder = os.path.join(app.config['UPLOAD_FOLDER'], uuid) latest_mbz_path = os.path.join(folder, 'latest.mbz') course.write(latest_mbz_path) return send_from_directory( folder, 'latest.mbz', as_attachment=True)
def download_planning(uuid): planning = _get_planning(uuid) if not planning: return jsonify({"message": 'Planning with uuid "%s" not found' % uuid}), 404 moodle_archive_path = planning.mbz_fullpath planning_txt = planning.planning_txt if not planning_txt: return _bad_request() # Make tmp directory for MBZ extraction and ics download with tempfile.TemporaryDirectory() as tmp_path: # Download calendar to tmp folder calendar_path = _dl_and_save_ics_file(planning.ics_url, tmp_path) calendar = CalendarReader(calendar_path) calendar_meetings = calendar.get_all_meetings() # Extract Moodle course to tmp folder with tarfile.open(moodle_archive_path) as tar_file: tar_file.extractall(tmp_path) course = MoodleCourse(tmp_path) interpreter = Interpreter(calendar_meetings, course) for line in planning_txt.split("\n"): event = interpreter.get_new_event_from_string(line) course.replace_event(event) folder = os.path.join(app.config["UPLOAD_FOLDER"], uuid) latest_mbz_path = os.path.join(folder, "latest.mbz") course.write(latest_mbz_path) return send_from_directory(folder, "latest.mbz", as_attachment=True)
def test_archive_is_repacked(self): course = MoodleCourse(self.tmp_path) quiz = course.get_activity_by_type_and_num(MoodleQuiz, 1) quiz.set_start_datetime(arrow.get( 2001, 1, 1, 1, 1, 1, tzinfo=tz.gettz('America/Montreal')).datetime) course.write(self.tmp_output_archive) self.assertTrue(os.path.isfile(self.tmp_output_archive))
def test_archive_is_repacked(self): course = MoodleCourse(self.tmp_path) quiz = course.get_activity_by_type_and_num(MoodleQuiz, 1) quiz.set_start_datetime( arrow.get(2001, 1, 1, 1, 1, 1, tzinfo=tz.gettz('America/Montreal')).datetime) course.write(self.tmp_output_archive) self.assertTrue(os.path.isfile(self.tmp_output_archive))
def test_get_event_end_date(self): course = MoodleCourse(self.tmp_path) quiz = course.get_activity_by_type_and_num(MoodleQuiz, 1) quiz['timeclose'] = 1389027600 dt = arrow.get(2014, 1, 6, 12, tzinfo=tz.gettz('America/Montreal')).datetime self.assertEqual(dt, quiz.get_end_datetime())
def test_set_event_start_date(self): course = MoodleCourse(self.tmp_path) quiz = course.get_activity_by_type_and_num(MoodleQuiz, 1) dt = arrow.get(2014, 1, 6, 12, tzinfo=tz.gettz('America/Montreal')).datetime quiz.set_start_datetime(dt) self.assertEqual('1389027600', quiz['timeopen'])
def test_get_event_end_date(self): course = MoodleCourse(self.tmp_path) quiz = course.get_activity_by_type_and_num(MoodleQuiz, 1) quiz['timeclose'] = 1389027600 dt = arrow.get( 2014, 1, 6, 12, tzinfo=tz.gettz('America/Montreal')).datetime self.assertEqual(dt, quiz.get_end_datetime())
def test_set_event_start_date(self): course = MoodleCourse(self.tmp_path) quiz = course.get_activity_by_type_and_num(MoodleQuiz, 1) dt = arrow.get( 2014, 1, 6, 12, tzinfo=tz.gettz('America/Montreal')).datetime quiz.set_start_datetime(dt) self.assertEqual('1389027600', quiz['timeopen'])
def test_set_invalid_key_raises_exception(self): course = MoodleCourse(self.tmp_path) quiz = course.get_activity_by_type_and_num(MoodleQuiz, 1) with self.assertRaises(Exception): quiz['invalid_key'] = 'some data' with self.assertRaises(Exception): quiz['id'] = 'some data' with self.assertRaises(Exception): quiz['moduleid'] = 'some data'
def test_get_activity_by_relative_num(self): course = MoodleCourse(self.tmp_path) actual = course.get_activity_by_type_and_num(MoodleQuiz, 1)['id'] self.assertEqual('4271', actual) actual = course.get_activity_by_type_and_num(MoodleQuiz, 2)['id'] self.assertEqual('4272', actual) actual = course.get_activity_by_type_and_num(MoodleQuiz, 3)['id'] self.assertEqual('4273', actual) actual = course.get_activity_by_type_and_num(MoodleHomework, 1)['id'] self.assertEqual('5588', actual)
def test_new_mbz_archive(self): course_activity_planner._generate_planning_uuid = \ MagicMock(return_value='uuid') # Ignore mbz in request and link to local mbz file course_activity_planner._save_mbz_file = \ MagicMock(return_value=self.local_mbz_path) res = self.client.post( '/api/planning', data=dict( mbz_file=(io.BytesIO(b'this is a test'), 'test.mbz'), ics_url=self.cal_url), headers=[('Authorization', "Bearer %s" % self.token)]) res = self.client.put( '/api/planning/uuid', data=json.dumps({'planning': 'MQ1 S1F S2\nE1 S1F S2'}), headers=[('Content-Type', 'application/json'), ('Authorization', "Bearer %s" % self.token)]) res = self.client.get( '/api/planning/uuid/mbz', headers=[('Authorization', "Bearer %s" % self.token)]) self.assertEqual(200, res._status_code) new_mbz_path = os.path.join(self.app.config['UPLOAD_FOLDER'], 'downloaded.mbz') encoded = json.loads(res.data.decode('utf8'))['mbz_64'] with open(new_mbz_path, 'wb') as f: f.write(base64.b64decode(encoded)) print(os.path.exists(new_mbz_path)) tmp_archive = os.path.join(self.app.config['UPLOAD_FOLDER'], 'extracted') with tarfile.open(new_mbz_path) as tar_file: tar_file.extractall(tmp_archive) course = MoodleCourse(tmp_archive) quiz = course.get_activity_by_type_and_num(MoodleQuiz, 1) expected_s = 1389013200 expected_e = 1389614400 actual_s = quiz.get_start_timestamp() actual_e = quiz.get_end_timestamp() self.assertEqual(expected_s, actual_s) self.assertEqual(expected_e, actual_e)
def get_interpreter_and_planning_from(uuid): planning = _get_planning(uuid, g.user_id) moodle_archive_path = planning.mbz_fullpath try: calendar = CalendarReader(planning.ics_fullpath) calendar_meetings = calendar.get_all_meetings() except CAPException as e: raise e except Exception as e: raise CAPException({'type': 'danger', 'msg': str(e)}, 400) if not moodle_archive_path: return Interpreter(calendar_meetings, None), planning # Make tmp directory for MBZ extraction with tempfile.TemporaryDirectory() as tmp_path: # Extract Moodle course to tmp folder try: with tarfile.open(moodle_archive_path) as tar_file: tar_file.extractall(tmp_path) course = MoodleCourse(tmp_path) except Exception: _bad_mbz() return Interpreter(calendar_meetings, course), planning
def test_new_mbz_archive(self): course_activity_planner._generate_planning_uuid = \ MagicMock(return_value='uuid') # Ignore mbz in request and link to local mbz file course_activity_planner._save_mbz_file = \ MagicMock(return_value=self.local_mbz_path) res = self.client.post( '/api/planning', data=dict( mbz_file=(io.BytesIO(b'this is a test'), 'test.mbz'), ics_url=self.cal_url), headers=[('Authorization', "Bearer %s" % self.token)]) res = self.client.put( '/api/planning/uuid', data=json.dumps({'planning': 'Q1 S1F S2'}), headers=[('Content-Type', 'application/json'), ('Authorization', "Bearer %s" % self.token)]) res = self.client.get( '/api/planning/uuid/mbz', headers=[('Authorization', "Bearer %s" % self.token)]) self.assertEqual(200, res._status_code) new_mbz_path = os.path.join(self.app.config['UPLOAD_FOLDER'], 'downloaded.mbz') with open(new_mbz_path, 'wb') as f: f.write(res.data) tmp_archive = os.path.join(self.app.config['UPLOAD_FOLDER'], 'extracted') with tarfile.open(new_mbz_path) as tar_file: tar_file.extractall(tmp_archive) course = MoodleCourse(tmp_archive) quiz = course.get_activity_by_type_and_num(MoodleQuiz, 1) expected_s = 1389013200 expected_e = 1389614400 actual_s = quiz.get_start_timestamp() actual_e = quiz.get_end_timestamp() self.assertEqual(expected_s, actual_s) self.assertEqual(expected_e, actual_e)
def test_modification_of_event_has_effect_on_disk(self): course = MoodleCourse(self.tmp_path) quiz = course.get_activity_by_type_and_num(MoodleQuiz, 1) quiz.set_start_datetime(arrow.get( 2001, 1, 1, 1, 1, 1, tzinfo=tz.gettz('America/Montreal')).datetime) before_modification_dt = os.path.getmtime(quiz.path) quiz.write() self.assertFalse(before_modification_dt == os.path.getmtime(quiz.path)) # Check data is updated on disk course_after = MoodleCourse(self.tmp_path) quiz_after = course_after.get_activity_by_type_and_num(MoodleQuiz, 1) self.assertEqual(arrow.get( 2001, 1, 1, 1, 1, 1, tzinfo=tz.gettz('America/Montreal')).datetime, quiz_after.get_start_datetime() )
def test_write_activities_to_disk_saves_io(self): course = MoodleCourse(self.tmp_path) # quiz 1 is not modified q1 = course.get_activity_by_type_and_num(MoodleQuiz, 1) q1_before_modification_dt = os.path.getmtime(q1.path) # quiz 2 is modified q2 = course.get_activity_by_type_and_num(MoodleQuiz, 2) q2.set_start_datetime( arrow.get(2001, 1, 1, 1, 1, 1, tzinfo=tz.gettz('America/Montreal')).datetime) q2_before_modification_dt = os.path.getmtime(q2.path) # Homework 1 is modified h1 = course.get_activity_by_type_and_num(MoodleHomework, 1) h1.set_start_datetime( arrow.get(2001, 1, 1, 1, 1, 1, tzinfo=tz.gettz('America/Montreal')).datetime) h1_before_modification_dt = os.path.getmtime(h1.path) course._write_activities_to_disk() # Only quiz 2 was written on disk self.assertTrue(q1_before_modification_dt == os.path.getmtime(q1.path)) self.assertFalse( q2_before_modification_dt == os.path.getmtime(q2.path)) self.assertFalse( h1_before_modification_dt == os.path.getmtime(h1.path))
def download_planning(uuid): try: planning = _get_planning(uuid, g.user_id) except CAPException as e: return e.res moodle_archive_path = planning.mbz_fullpath planning_txt = planning.planning_txt if not planning_txt: return _bad_request() # Make tmp directory for MBZ extraction and ics download with tempfile.TemporaryDirectory() as tmp_path: # Download calendar to tmp folder calendar = CalendarReader(planning.ics_fullpath) calendar_meetings = calendar.get_all_meetings() # Extract Moodle course to tmp folder with tarfile.open(moodle_archive_path) as tar_file: tar_file.extractall(tmp_path) course = MoodleCourse(tmp_path) interpreter = Interpreter(calendar_meetings, course) for line in planning_txt.split('\n'): event = interpreter.get_new_event_from_string(line) course.replace_event(event) folder = os.path.join(app.config['UPLOAD_FOLDER'], uuid) latest_mbz_path = os.path.join(folder, 'latest.mbz') course.write(latest_mbz_path) return send_from_directory(folder, 'latest.mbz', as_attachment=True)
def setUp(self): # Setup calendar calendar = CalendarReader(self.calendar_path) self.calendar_meetings = calendar.get_all_meetings() # Setup Moodle course self.tmp_path = tempfile.mkdtemp() with tarfile.open(self.moodle_archive_path) as tar_file: tar_file.extractall(self.tmp_path) self.course = MoodleCourse(self.tmp_path) self.interpreter = Interpreter(self.calendar_meetings, self.course)
def preview_planning(uuid): try: planning = _get_planning(uuid, g.user_id) except CAPException as e: return e.res moodle_archive_path = planning.mbz_fullpath planning_txt = planning.planning_txt # Make tmp directory for MBZ extraction with tempfile.TemporaryDirectory() as tmp_path: try: calendar = CalendarReader(planning.ics_fullpath) calendar_meetings = calendar.get_all_meetings() except Exception as e: _bad_cal() # Extract Moodle course to tmp folder course = None if moodle_archive_path: try: with tarfile.open(moodle_archive_path) as tar_file: tar_file.extractall(tmp_path) course = MoodleCourse(tmp_path) except Exception as e: return jsonify(alerts=[{ 'type': 'danger', 'msg': 'MBZ file could not be read.' }]), 400 alerts = [] preview = None inventory = None try: interpreter = Interpreter(calendar_meetings, course) inventory = _build_inventory(interpreter, planning_txt) preview = _build_preview(interpreter, planning_txt) alerts = _build_alerts_for_preview(interpreter) except InvalidSyntaxException as e: alerts.append({'type': 'danger', 'msg': e.message}) return jsonify({ 'preview': preview, 'inventory': inventory, 'alerts': alerts }), 200
def test_load_activities(self): course = MoodleCourse(self.tmp_path) actual = course._load_activites()[MoodleQuiz] self.assertEqual(3, len(actual)) actual = course._load_activites()[MoodleHomework] self.assertEqual(1, len(actual)) actual = course._load_activites()[MoodleLesson] self.assertEqual(1, len(actual)) actual = course._load_activites()[MoodleFeedback] self.assertEqual(1, len(actual)) actual = course._load_activites()[MoodleChoice] self.assertEqual(1, len(actual))
def test_modification_of_event_has_effect_on_disk(self): course = MoodleCourse(self.tmp_path) quiz = course.get_activity_by_type_and_num(MoodleQuiz, 1) quiz.set_start_datetime( arrow.get(2001, 1, 1, 1, 1, 1, tzinfo=tz.gettz('America/Montreal')).datetime) before_modification_dt = os.path.getmtime(quiz.path) quiz.write() self.assertFalse(before_modification_dt == os.path.getmtime(quiz.path)) self.assertFalse( before_modification_dt == os.path.getmtime(quiz.global_path + '/calendar.xml')) # Check data is updated on disk course_after = MoodleCourse(self.tmp_path) quiz_after = course_after.get_activity_by_type_and_num(MoodleQuiz, 1) self.assertEqual( arrow.get(2001, 1, 1, 1, 1, 1, tzinfo=tz.gettz('America/Montreal')).datetime, quiz_after.get_start_datetime())
def test_write_activities_to_disk_saves_io(self): course = MoodleCourse(self.tmp_path) # quiz 1 is not modified q1 = course.get_activity_by_type_and_num(MoodleQuiz, 1) q1_before_modification_dt = os.path.getmtime(q1.path) # quiz 2 is modified q2 = course.get_activity_by_type_and_num(MoodleQuiz, 2) q2.set_start_datetime(arrow.get( 2001, 1, 1, 1, 1, 1, tzinfo=tz.gettz('America/Montreal')).datetime) q2_before_modification_dt = os.path.getmtime(q2.path) # Homework 1 is modified h1 = course.get_activity_by_type_and_num(MoodleHomework, 1) h1.set_start_datetime(arrow.get( 2001, 1, 1, 1, 1, 1, tzinfo=tz.gettz('America/Montreal')).datetime) h1_before_modification_dt = os.path.getmtime(h1.path) course._write_activities_to_disk() # Only quiz 2 was written on disk self.assertTrue(q1_before_modification_dt == os.path.getmtime(q1.path)) self.assertFalse(q2_before_modification_dt == os.path.getmtime(q2.path)) self.assertFalse(h1_before_modification_dt == os.path.getmtime(h1.path))
def test_load_activity_sequence(self): course = MoodleCourse(self.tmp_path) actual = course._load_activity_sequence() self.assertEqual([175721, 175723, 175724, 175720, 175722, 176000], actual)
def test_load_activities(self): course = MoodleCourse(self.tmp_path) actual = course._load_activites()[MoodleQuiz] self.assertEqual(4, len(actual)) actual = course._load_activites()[MoodleHomework] self.assertEqual(1, len(actual))
def test_load_activity_sequence(self): course = MoodleCourse(self.tmp_path) actual = course._load_activity_sequence() self.assertEqual([146934, 146935, 146936, 146937, 146939], actual)
def test_invisible_activities_are_not_loaded(self): course = MoodleCourse(self.tmp_path) actual = course._load_activites()[MoodleQuiz] self.assertEqual(2, len(actual))
def test_activities_are_sorted(self): course = MoodleCourse(self.tmp_path) for i, x in enumerate([146935, 146936, 146939]): self.assertEqual(x, course.activities[MoodleQuiz][i]['moduleid'])