Example #1
0
def note(user_id: int):
    act = request.args.get('act') or request.json.get('act')

    user = User.get_or_none(User.id == user_id)
    if user is None:
        return fail(404, f'No such user {user_id}.')

    if act == 'fetch':
        return jsonify(tuple(user.notes().dicts()))

    if not current_user.role.is_manager:
        return fail(403, "You aren't allowed to access this page.")

    if act == 'delete':
        note_id = int(request.args.get('noteId'))
        return try_or_fail(notes.delete, note_id=note_id)

    if act == 'create':
        note_text = request.args.get('note', '')
        note_exercise = request.args.get('exercise', '')
        privacy = request.args.get('privacy', '0')
        return try_or_fail(
            notes.create,
            user=user,
            note_text=note_text,
            note_exercise=note_exercise,
            privacy=privacy,
        )

    return fail(400, f'Unknown or unset act value "{act}".')
Example #2
0
def upload_page():
    user_id = current_user.id
    user = User.get_or_none(User.id == user_id)  # should never happen
    if user is None:
        return fail(404, 'User not found.')
    if request.content_length > MAX_UPLOAD_SIZE:
        return fail(
            413, f'File is too big. {MAX_UPLOAD_SIZE // 1000000}MB allowed.',
        )

    file: Optional[FileStorage] = request.files.get('file')
    if file is None:
        return fail(422, 'No file was given.')

    try:
        matches, misses = upload.new(user, file)
    except UploadError as e:
        log.debug(e)
        return fail(400, str(e))
    except FileSizeError as e:
        log.debug(e)
        return fail(413, str(e))

    return jsonify({
        'exercise_matches': matches,
        'exercise_misses': misses,
    })
Example #3
0
def view(
    solution_id: int, file_id: Optional[int] = None, shared_url: str = '',
):
    solution = Solution.get_or_none(Solution.id == solution_id)
    if solution is None:
        return fail(404, 'Solution does not exist.')

    viewer_is_solver = solution.solver.id == current_user.id
    has_viewer_access = current_user.role.is_viewer
    if not shared_url and not viewer_is_solver and not has_viewer_access:
        return fail(403, 'This user has no permissions to view this page.')

    is_manager = current_user.role.is_manager

    solution_files = tuple(solution.files)
    if not solution_files:
        if not is_manager:
            return fail(404, 'There are no files in this solution.')
        return done_checking(solution.exercise.id, solution.id)

    try:
        view_params = solutions.get_view_parameters(
            solution, file_id, shared_url, is_manager,
            solution_files, viewer_is_solver,
        )
    except LmsError as e:
        error_message, status_code = e.args
        return fail(status_code, error_message)

    return render_template('view.html', **view_params)
Example #4
0
def download(download_id: str):
    """Downloading a zip file of the code files.

    Args:
        download_id (str): Can be on each side of
                           a solution.id and sharedsolution.shared_url.
    """
    solution = Solution.get_or_none(Solution.id == download_id)
    shared_solution = SharedSolution.get_or_none(
        SharedSolution.shared_url == download_id,
    )
    if solution is None and shared_solution is None:
        return fail(404, 'Solution does not exist.')

    if shared_solution is None:
        viewer_is_solver = solution.solver.id == current_user.id
        has_viewer_access = current_user.role.is_viewer
        if not viewer_is_solver and not has_viewer_access:
            return fail(403, 'This user has no permissions to view this page.')
        files = solution.files
        filename = solution.exercise.subject
    else:
        files = shared_solution.solution.files
        filename = shared_solution.solution.exercise.subject

    response = make_response(solutions.create_zip_from_solution(files))
    response.headers.set('Content-Type', 'zip')
    response.headers.set(
        'Content-Disposition', 'attachment',
        filename=f'{filename}.zip',
    )
    return response
Example #5
0
def view(
    solution_id: int,
    file_id: Optional[int] = None,
    shared_url: str = '',
):
    solution = Solution.get_or_none(Solution.id == solution_id)
    if solution is None:
        return fail(404, 'Solution does not exist.')

    viewer_is_solver = solution.solver.id == current_user.id
    has_viewer_access = current_user.role.is_viewer
    if not shared_url and not viewer_is_solver and not has_viewer_access:
        return fail(403, 'This user has no permissions to view this page.')

    versions = solution.ordered_versions()
    test_results = solution.test_results()
    is_manager = current_user.role.is_manager

    solution_files = tuple(solution.files)
    if not solution_files:
        if not is_manager:
            return fail(404, 'There are no files in this solution.')
        return done_checking(solution.exercise.id, solution.id)

    files = solutions.get_files_tree(solution.files)
    file_id = file_id or files[0]['id']
    file_to_show = next((f for f in solution_files if f.id == file_id), None)
    if file_to_show is None:
        return fail(404, 'File does not exist.')

    view_params = {
        'solution': model_to_dict(solution),
        'files': files,
        'comments': solution.comments_per_file,
        'current_file': file_to_show,
        'is_manager': is_manager,
        'role': current_user.role.name.lower(),
        'versions': versions,
        'test_results': test_results,
        'shared_url': shared_url,
    }

    if is_manager:
        view_params = {
            **view_params,
            'exercise_common_comments':
            _common_comments(exercise_id=solution.exercise),
            'all_common_comments':
            _common_comments(),
            'user_comments':
            _common_comments(user_id=current_user.id),
            'left':
            Solution.left_in_exercise(solution.exercise),
        }

    if viewer_is_solver:
        notifications.read_related(solution_id, current_user.id)

    return render_template('view.html', **view_params)
Example #6
0
def comment():
    act = request.args.get('act') or request.json.get('act')

    if request.method == 'POST':
        file_id = int(request.json.get('fileId', 0))
    else:  # it's a GET
        file_id = int(request.args.get('fileId', 0))

    file = SolutionFile.get_or_none(file_id)
    if file is None:
        return fail(404, f'No such file {file_id}.')

    solver_id = file.solution.solver.id
    if solver_id != current_user.id and not current_user.role.is_manager:
        return fail(403, "You aren't allowed to access this page.")

    if act == 'fetch':
        return jsonify(Comment.by_file(file_id))

    if (
        not webapp.config.get('USERS_COMMENTS', False)
        and not current_user.role.is_manager
    ):
        return fail(403, "You aren't allowed to access this page.")

    if act == 'delete':
        comment_id = int(request.args.get('commentId'))
        comment_ = Comment.get_or_none(Comment.id == comment_id)
        if (
            comment_.commenter.id != current_user.id
            and not current_user.role.is_manager
        ):
            return fail(403, "You aren't allowed to access this page.")
        if comment_ is not None:
            comment_.delete_instance()
        return jsonify({'success': 'true'})

    if act == 'create':
        kind = request.json.get('kind', '')
        comment_id, comment_text = None, None
        try:
            line_number = int(request.json.get('line', 0))
        except ValueError:
            line_number = 0
        if kind.lower() == 'id':
            comment_id = int(request.json.get('comment', 0))
        if kind.lower() == 'text':
            comment_text = request.json.get('comment', '')
        return comments._create_comment(
            current_user.id,
            file,
            kind,
            line_number,
            comment_text,
            comment_id,
        )

    return fail(400, f'Unknown or unset act value "{act}".')
Example #7
0
def change_last_course_viewed(course_id: int):
    course = Course.get_or_none(course_id)
    if course is None:
        return fail(404, f'No such course {course_id}.')
    user = User.get(User.id == current_user.id)
    if not UserCourse.is_user_registered(user.id, course.id):
        return fail(403, "You're not allowed to access this page.")
    user.last_course_viewed = course
    user.save()
    return redirect(url_for('exercises_page'))
Example #8
0
def user(user_id):
    if user_id != current_user.id and not current_user.role.is_manager:
        return fail(403, "You aren't allowed to watch this page.")
    target_user = User.get_or_none(User.id == user_id)
    if target_user is None:
        return fail(404, 'There is no such user.')

    return render_template(
        'user.html',
        solutions=Solution.of_user(target_user.id, with_archived=True),
        user=target_user,
    )
Example #9
0
def shared_solution(shared_url: str, file_id: Optional[int] = None):
    if not webapp.config.get('SHAREABLE_SOLUTIONS', False):
        return fail(404, 'Solutions are not shareable.')

    shared_solution = SharedSolution.get_or_none(
        SharedSolution.shared_url == shared_url,
    )
    if shared_solution is None:
        return fail(404, 'The solution does not exist.')

    solution_id = shared_solution.solution.id
    return view(
        solution_id=solution_id, file_id=file_id, shared_url=shared_url,
    )
Example #10
0
def join_public_course(course_id: int):
    course = Course.get_or_none(course_id)
    if course is None:
        return fail(404, 'There is no such course.')
    if not course.is_public:
        return fail(403, "You aren't allowed to do this method.")

    try:
        users.join_public_course(course, current_user)
    except AlreadyExists as e:
        error_message, status_code = e.args
        return fail(status_code, error_message)

    return redirect(url_for('exercises_page'))
Example #11
0
def try_or_fail(callback: Callable, *args: Any, **kwargs: Any):
    try:
        result = callback(*args, **kwargs)
    except LmsError as e:
        error_message, status_code = e.args
        return fail(status_code, error_message)
    return result or jsonify({'success': 'true'})
Example #12
0
def _create_comment(
        user_id: int,
        file: SolutionFile,
        kind: str,
        line_number: int,
        comment_text: Optional[str] = None,  # set when kind == text
        comment_id: Optional[int] = None,  # set when kind == id
):
    user = User.get_or_none(User.id == user_id)
    if user is None:
        # should never happen, we checked session_id == solver_id
        return fail(404, 'No such user.')

    if (not kind) or (kind not in ('id', 'text')):
        return fail(400, 'Invalid kind.')

    if line_number <= 0:
        return fail(422, f'Invalid line number: {line_number}.')

    if kind == 'id':
        new_comment_id = comment_id
    elif kind == 'text':
        if not comment_text:
            return fail(422, 'Empty comments are not allowed.')
        new_comment_id = CommentText.create_comment(text=comment_text).id
    else:
        # should never happend, kind was checked before
        return fail(400, 'Invalid kind.')

    solutions.notify_comment_after_check(user, file.solution)

    comment_ = Comment.create(
        commenter=user,
        line_number=line_number,
        comment=new_comment_id,
        file=file,
    )

    return jsonify({
        'success': 'true',
        'text': comment_.comment.text,
        'author_name': user.fullname,
        'author_role': user.role.id,
        'is_auto': False,
        'id': comment_.id,
        'line_number': line_number,
    })
Example #13
0
File: views.py Project: ry-v1/lms
def comment():
    act = request.args.get('act') or request.json.get('act')

    if request.method == 'POST':
        file_id = int(request.json.get('fileId', 0))
    else:  # it's a GET
        file_id = int(request.args.get('fileId', 0))

    file = SolutionFile.get_or_none(file_id)
    if file is None:
        return fail(404, f'No such file {file_id}.')

    solver_id = file.solution.solver.id
    if solver_id != current_user.id and not current_user.role.is_manager:
        return fail(403, "You aren't allowed to access this page.")

    if act == 'fetch':
        return jsonify(Comment.by_file(file_id))

    if (not webapp.config.get('USERS_COMMENTS', False)
            and not current_user.role.is_manager):
        return fail(403, "You aren't allowed to access this page.")

    if act == 'delete':
        return try_or_fail(comments.delete)

    if act == 'create':
        user = User.get_or_none(User.id == current_user.id)
        try:
            comment_ = comments.create(file=file, user=user)
        except LmsError as e:
            error_message, status_code = e.args
            return fail(status_code, error_message)

        return jsonify({
            'success': 'true',
            'text': comment_.comment.text,
            'is_auto': False,
            'author_name': user.fullname,
            'author_role': user.role.id,
            'id': comment_.id,
            'line_number': comment_.line_number,
        })

    return fail(400, f'Unknown or unset act value "{act}".')
Example #14
0
def user(user_id):
    if user_id != current_user.id and not current_user.role.is_manager:
        return fail(403, "You aren't allowed to watch this page.")
    target_user = User.get_or_none(User.id == user_id)
    if target_user is None:
        return fail(404, 'There is no such user.')

    is_manager = current_user.role.is_manager

    return render_template(
        'user.html',
        solutions=Solution.of_user(
            target_user.id, with_archived=True, from_all_courses=True,
        ),
        user=target_user,
        is_manager=is_manager,
        notes_options=Note.get_note_options(),
        public_course_exists=Course.public_course_exists(),
    )
Example #15
0
def recover_password(user_id: int, token: str):
    user = User.get_or_none(User.id == user_id)
    if user is None:
        return fail(404, 'The authentication code is invalid.')

    try:
        SERIALIZER.loads(
            token, salt=retrieve_salt(user), max_age=CONFIRMATION_TIME,
        )

    except SignatureExpired:
        return redirect(url_for(
            'login', login_message=(
                _('Reset password link is expired'),
            ),
        ))
    except BadSignature:
        return fail(404, 'The authentication code is invalid.')

    else:
        return recover_password_check(user, token)
Example #16
0
def confirm_email(user_id: int, token: str):
    user = User.get_or_none(User.id == user_id)
    if user is None:
        return fail(404, 'The authentication code is invalid.')

    if not user.role.is_unverified:
        return fail(403, 'User has been already confirmed.')

    try:
        SERIALIZER.loads(
            token, salt=retrieve_salt(user), max_age=CONFIRMATION_TIME,
        )

    except SignatureExpired:
        send_confirmation_mail(user)
        return redirect(url_for(
            'login', login_message=(
                _(
                    'The confirmation link is expired, new link has been '
                    'sent to your email',
                ),
            ),
        ))
    except BadSignature:
        return fail(404, 'The authentication code is invalid.')

    else:
        update = User.update(
            role=Role.get_student_role(),
        ).where(User.username == user.username)
        update.execute()
        return redirect(url_for(
            'login', login_message=(
                _(
                    'Your user has been successfully confirmed, '
                    'you can now login',
                ),
            ),
        ))
Example #17
0
def share():
    act = request.json.get('act')
    solution_id = int(request.json.get('solutionId', 0))

    try:
        shared_solution = share_link.get(solution_id)
    except LmsError as e:
        error_message, status_code = e.args
        return fail(status_code, error_message)

    if act == 'get':
        return jsonify({
            'success': 'true',
            'share_link': shared_solution.shared_url,
        })
    elif act == 'delete':
        shared_solution.delete_instance()
        return jsonify({
            'success': 'true',
            'share_link': 'false',
        })

    return fail(400, f'Unknown or unset act value "{act}".')
Example #18
0
def download(download_id: str):
    """Downloading a zip file of the code files.

    Args:
        download_id (str): Can be on each side of
                           a solution.id and sharedsolution.shared_url.
    """
    try:
        files, filename = solutions.get_download_data(download_id)
    except LmsError as e:
        error_message, status_code = e.args
        return fail(status_code, error_message)

    response = make_response(solutions.create_zip_from_solution(files))
    response.headers.set('Content-Type', 'zip')
    response.headers.set(
        'Content-Disposition', 'attachment',
        filename=f'{filename}.zip'.encode('utf-8'),
    )
    return response
Example #19
0
File: admin.py Project: ry-v1/lms
 def wrapper(*args, **kwargs):
     if not current_user.role.is_manager:
         return fail(403, 'This user has no permissions to view this page.')
     else:
         return func(*args, **kwargs)
Example #20
0
def send(course_id: int, _exercise_number: Optional[int]):
    if not UserCourse.is_user_registered(current_user.id, course_id):
        return fail(403, "You aren't allowed to watch this page.")
    return render_template('upload.html', course_id=course_id)
Example #21
0
def send_(course_id: int):
    if not UserCourse.is_user_registered(current_user.id, course_id):
        return fail(403, "You aren't allowed to watch this page.")
    return render_template('upload.html', course_id=course_id)
Example #22
0
def get_next_url(url_next_param: Optional[str]):
    next_url = url_next_param if url_next_param else None
    if not is_safe_url(next_url):
        return fail(400, "The URL isn't safe.")
    return redirect(next_url or url_for('main'))