def programs_page(request): username = current_user(request)['username'] if not username: # redirect users to /login if they are not logged in url = request.url.replace('/programs', '/login') return redirect(url, code=302) from_user = request.args.get('user') or None if from_user and not is_admin(request): if not is_teacher(request): return "unauthorized", 403 students = DATABASE.get_teacher_students(username) if from_user not in students: return "unauthorized", 403 texts = TRANSLATIONS.get_translations(requested_lang(), 'Programs') ui = TRANSLATIONS.get_translations(requested_lang(), 'ui') adventures = load_adventure_for_language(requested_lang())['adventures'] result = DATABASE.programs_for_user(from_user or username) programs = [] now = timems() for item in result: program_age = now - item['date'] if program_age < 1000 * 60 * 60: measure = texts['minutes'] date = round(program_age / (1000 * 60)) elif program_age < 1000 * 60 * 60 * 24: measure = texts['hours'] date = round(program_age / (1000 * 60 * 60)) else: measure = texts['days'] date = round(program_age / (1000 * 60 * 60 * 24)) programs.append({ 'id': item['id'], 'code': item['code'], 'date': texts['ago-1'] + ' ' + str(date) + ' ' + measure + ' ' + texts['ago-2'], 'level': item['level'], 'name': item['name'], 'adventure_name': item.get('adventure_name'), 'public': item.get('public') }) return render_template('programs.html', lang=requested_lang(), menu=render_main_menu('programs'), texts=texts, ui=ui, auth=TRANSLATIONS.get_translations( requested_lang(), 'Auth'), programs=programs, username=username, is_teacher=is_teacher(request), current_page='programs', from_user=from_user, adventures=adventures)
def error(): error_messages = TRANSLATIONS.get_translations(requested_lang(), "ClientErrorMessages") return render_template("error_messages.js", error_messages=json.dumps(error_messages))
def gradual_error(): error_messages = TRANSLATIONS.get_translations(requested_lang(), "GradualFeedback") return render_template("gradual_messages.js", error_messages=json.dumps(error_messages))
def render_code_editor_with_tabs(request, course, level_number, menu, translations, version, loaded_program, adventures, adventure_name): if os.path.isfile( f'coursedata/quiz/quiz_questions_lvl{level_number}.yaml'): quiz_data = utils.load_yaml( f'coursedata/quiz/quiz_questions_lvl{level_number}.yaml') quiz_data_level = quiz_data['level'] else: quiz_data_level = 0 sublevel = None if isinstance(level_number, str) and re.match('\d+-\d+', level_number): sublevel = int(level_number[level_number.index('-') + 1]) level_number = int(level_number[0:level_number.index('-')]) defaults = course.get_default_text(level_number, sublevel) if not defaults: abort(404) if course.custom: adventures = [ x for x in adventures if x['short_name'] in course.adventures ] arguments_dict = {} # Meta stuff arguments_dict['course'] = course arguments_dict['level_nr'] = str(level_number) arguments_dict['sublevel'] = str(sublevel) if (sublevel) else None arguments_dict['lang'] = course.language arguments_dict['level'] = defaults.level arguments_dict['prev_level'] = int(level_number) - 1 if int( level_number) > 1 else None arguments_dict['next_level'] = int(level_number) + 1 if int( level_number) < course.max_level() else None arguments_dict['menu'] = menu arguments_dict['latest'] = version arguments_dict['selected_page'] = 'code' arguments_dict['page_title'] = f'Level {level_number} – Hedy' arguments_dict['auth'] = translations.get_translations( course.language, 'Auth') arguments_dict['username'] = current_user(request)['username'] arguments_dict['is_teacher'] = is_teacher(request) arguments_dict['loaded_program'] = loaded_program arguments_dict['adventures'] = adventures arguments_dict['adventure_name'] = adventure_name arguments_dict['quiz_data_level'] = quiz_data_level arguments_dict[ 'quiz_enabled'] = config['quiz-enabled'] and course.language == 'nl' # Translations arguments_dict.update( **translations.get_translations(course.language, 'ui')) # Actual assignment arguments_dict.update(**attr.asdict(defaults)) return render_template("code-page.html", **arguments_dict)
def adventures_list(): return render_template('adventures.html', lang=lang, adventures=load_adventure_for_language (requested_lang ()), menu=render_main_menu('adventures'), username=current_user(request) ['username'], auth=TRANSLATIONS.data [lang] ['Auth'])
def page_500(page_error=None, ui_message=None, menu=True): return render_template("500.html", menu=menu, page_error=page_error or g.ui_texts.get(ui_message) or ''), 500
def render_assignment_editor(request, course, level_number, assignment_number, menu, translations, version, loaded_program, adventure_assignments, adventure_name): if os.path.isfile( f'coursedata/quiz/quiz_questions_lvl{level_number}.yaml'): quiz_data = utils.load_yaml( f'coursedata/quiz/quiz_questions_lvl{level_number}.yaml') quiz_data_level = quiz_data['level'] else: quiz_data_level = 0 sublevel = None if isinstance(level_number, str) and re.match('\d+-\d+', level_number): sublevel = int(level_number[level_number.index('-') + 1]) level_number = int(level_number[0:level_number.index('-')]) assignment = course.get_assignment(level_number, assignment_number, sublevel) if not assignment: abort(404) arguments_dict = {} # Meta stuff arguments_dict['course'] = course arguments_dict['level_nr'] = str(level_number) arguments_dict['sublevel'] = str(sublevel) if (sublevel) else None arguments_dict[ 'assignment_nr'] = assignment.step # Give this a chance to be 'None' arguments_dict['lang'] = course.language arguments_dict['level'] = assignment.level arguments_dict['prev_level'] = int(level_number) - 1 if int( level_number) > 1 else None arguments_dict['next_level'] = int(level_number) + 1 if int( level_number) < course.max_level() else None arguments_dict['next_assignment'] = int(assignment_number) + 1 if int( assignment_number) < course.max_step(level_number) else None arguments_dict['menu'] = menu arguments_dict['latest'] = version arguments_dict['selected_page'] = 'code' arguments_dict['page_title'] = f'Level {level_number} – Hedy' arguments_dict['docs'] = [attr.asdict(d) for d in assignment.docs] arguments_dict['auth'] = translations.data[course.language]['Auth'] arguments_dict['username'] = current_user(request)['username'] arguments_dict['loaded_program'] = loaded_program arguments_dict['adventure_assignments'] = adventure_assignments arguments_dict['adventure_name'] = adventure_name arguments_dict['quiz_data_level'] = quiz_data_level arguments_dict[ 'quiz_enabled'] = config['quiz-enabled'] and course.language == 'nl' print(course.language == 'nl') # Translations arguments_dict.update( **translations.get_translations(course.language, 'ui')) # Actual assignment arguments_dict.update(**attr.asdict(assignment)) # Add markdowns to docs for doc in arguments_dict['docs']: doc['markdown'] = (course.docs.get(int(level_number), doc['slug']) or { 'markdown': '' }).markdown return render_template("code-page.html", **arguments_dict)
def submit_answer(level_source, question_nr, attempt): if not config.get('quiz-enabled') and g.lang != 'nl': return 'Hedy quiz disabled!', 404 else: # Get the chosen option from the request form with radio buttons option = request.form["radio_option"] # Reading yaml file quiz_data = quiz_data_file_for(level_source) if not quiz_data.exists(): return 'No quiz yaml file found for this level', 404 # Convert question_nr to an integer q_nr = int(question_nr) session['quiz-attempt'] = int(attempt) questionStatus = 'false' if int(attempt) == 1: questionStatus = 'start' # Convert the corresponding chosen option to the index of an option question = quiz_data['questions'][q_nr - 1].get(q_nr) index_option = ord(option.split("-")[1]) - 65 session['chosen_option'] = option.split("-")[1] # If the correct answer is chosen, update the total score and the number of correct answered questions if question['correct_answer'] in option: if session.get('total_score'): session['total_score'] = session.get('total_score') + ( config.get('quiz-max-attempts') - session.get( 'quiz-attempt')) * 0.5 * question['question_score'] else: session['total_score'] = (config.get('quiz-max-attempts') - session.get('quiz-attempt') ) * 0.5 * question['question_score'] if session.get('correct_answer'): session['correct_answer'] = session.get('correct_answer') + 1 else: session['correct_answer'] = 1 # Loop through the questions and check that the loop doesn't reach out of bounds q_nr = int(question_nr) if q_nr <= len(quiz_data['questions']): if question['correct_answer'] in option: return render_template( 'feedback.html', quiz=quiz_data, question=question, questions=quiz_data['questions'], level_source=level_source, question_nr=q_nr, correct=session.get('correct_answer'), option=option, index_option=index_option, menu=render_main_menu('adventures'), lang=lang, username=current_user(request)['username'], auth=TRANSLATIONS.data[requested_lang()]['Auth']) elif session.get('quiz-attempt') <= config.get( 'quiz-max-attempts'): question = quiz_data['questions'][q_nr - 1].get(q_nr) # Convert the indices to the corresponding characters char_array = [] for i in range(len(question['mp_choice_options'])): char_array.append(chr(ord('@') + (i + 1))) return render_template( 'quiz_question.html', quiz=quiz_data, level_source=level_source, questions=quiz_data['questions'], question=quiz_data['questions'][q_nr - 1].get(q_nr), question_nr=q_nr, correct=session.get('correct_answer'), attempt=session.get('quiz-attempt'), questionStatus=questionStatus, chosen_option=session.get('chosen_option'), char_array=char_array, menu=render_main_menu('adventures'), lang=lang, username=current_user(request)['username'], auth=TRANSLATIONS.data[requested_lang()]['Auth']) elif session.get('quiz-attempt') > config.get('quiz-max-attempts'): return render_template( 'feedback.html', quiz=quiz_data, question=question, questions=quiz_data['questions'], level_source=level_source, question_nr=q_nr, correct=session.get('correct_answer'), questionStatus=questionStatus, option=option, index_option=index_option, menu=render_main_menu('adventures'), lang=lang, username=current_user(request)['username'], auth=TRANSLATIONS.data[requested_lang()]['Auth']) else: # show a different page for after the last question return 'No end quiz page!', 404
def get_class(user, class_id): if not is_teacher(request): return 'Only teachers can retrieve classes', 403 Class = DATABASE.get_class(class_id) if not Class or Class['teacher'] != user['username']: return utils.page_404( TRANSLATIONS, render_main_menu('my-profile'), current_user(request)['username'], requested_lang(), TRANSLATIONS.get_translations(requested_lang(), 'ui').get('no_such_class')) students = [] for student_username in Class.get('students', []): student = DATABASE.user_by_username(student_username) programs = DATABASE.programs_for_user(student_username) highest_level = max( program['level'] for program in programs) if len(programs) else 0 sorted_public_programs = list( sorted( [program for program in programs if program.get('public')], key=lambda p: p['date'])) if sorted_public_programs: latest_shared = sorted_public_programs[-1] latest_shared['link'] = os.getenv( 'BASE_URL') + f"/hedy/{latest_shared['id']}/view" else: latest_shared = None students.append({ 'username': student_username, 'last_login': utils.mstoisostring(student['last_login']), 'programs': len(programs), 'highest_level': highest_level, 'latest_shared': latest_shared }) if utils.is_testing_request(request): return jsonify({ 'students': students, 'link': Class['link'], 'name': Class['name'], 'id': Class['id'] }) return render_template( 'class-overview.html', lang=requested_lang(), auth=TRANSLATIONS.get_translations(requested_lang(), 'Auth'), menu=render_main_menu('my-profile'), username=current_user(request)['username'], is_teacher=is_teacher(request), current_page='my-profile', class_info={ 'students': students, 'link': os.getenv('BASE_URL') + '/hedy/l/' + Class['link'], 'name': Class['name'], 'id': Class['id'] })