diff --git a/lms/lmsdb/models.py b/lms/lmsdb/models.py index 3c08359d..df87b034 100644 --- a/lms/lmsdb/models.py +++ b/lms/lmsdb/models.py @@ -74,6 +74,10 @@ def get_student_role(cls) -> 'Role': def get_staff_role(cls) -> 'Role': return cls.get(Role.name == RoleOptions.STAFF.value) + @classmethod + def get_admin_role(cls) -> 'Role': + return cls.get(Role.name == RoleOptions.ADMINISTRATOR.value) + @classmethod def by_name(cls, name) -> 'Role': if name.startswith('_'): @@ -755,6 +759,7 @@ def _by_file(cls, file_id: int): CommentText.id.alias('comment_id'), CommentText.text, SolutionFile.id.alias('file_id'), User.fullname.alias('author_name'), + User.role.alias('author_role'), ] return ( cls diff --git a/lms/lmsweb/config.py.example b/lms/lmsweb/config.py.example index 5c8973d7..4a55f63d 100644 --- a/lms/lmsweb/config.py.example +++ b/lms/lmsweb/config.py.example @@ -29,6 +29,9 @@ ERRORS_CSV = 'errors.csv' # Shareable option SHAREABLE_SOLUTIONS = True +# Users comments option +USERS_COMMENTS = True + # Babel config LANGUAGES = { 'he': 'Hebrew', diff --git a/lms/lmsweb/views.py b/lms/lmsweb/views.py index 46f89990..f6784a47 100644 --- a/lms/lmsweb/views.py +++ b/lms/lmsweb/views.py @@ -19,7 +19,7 @@ from werkzeug.utils import redirect from lms.lmsdb.models import ( - ALL_MODELS, Comment, CommentText, Exercise, RoleOptions, + ALL_MODELS, Comment, CommentText, Exercise, Role, RoleOptions, SharedSolution, Solution, SolutionFile, User, database, ) from lms.lmsweb import babel, routes, webapp @@ -208,8 +208,8 @@ def _create_comment( return jsonify({ 'success': 'true', 'text': comment_.comment.text, - 'author_name': user.fullname, 'is_auto': False, 'id': comment_.id, - 'line_number': line_number, + 'author_name': user.fullname, 'author_role': user.role.id, + 'is_auto': False, 'id': comment_.id, 'line_number': line_number, }) @@ -274,9 +274,20 @@ def comment(): 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'}) @@ -501,9 +512,17 @@ def _common_comments(exercise_id=None, user_id=None): Most common comments throughout all exercises. Filter by exercise id when specified. """ - query = CommentText.filter(**{ - CommentText.flake8_key.name: None, - }).select(CommentText.id, CommentText.text).join(Comment) + is_moderator_comments = ( + (Comment.commenter.role == Role.get_staff_role().id) + | (Comment.commenter.role == Role.get_admin_role().id), + ) + query = ( + CommentText.select(CommentText.id, CommentText.text) + .join(Comment).join(User).join(Role).where( + CommentText.flake8_key.is_null(True), + is_moderator_comments, + ).switch(Comment) + ) if exercise_id is not None: query = ( diff --git a/lms/static/comments.js b/lms/static/comments.js index ce345809..8bd0f662 100644 --- a/lms/static/comments.js +++ b/lms/static/comments.js @@ -27,9 +27,15 @@ function isUserGrader() { return ['staff', 'administrator'].includes(sessionStorage.getItem('role')); } +function isSolverComment(commentData) { + const authorIsSolver = commentData.author_name === sessionStorage.getItem('solver'); + const allowedComment = sessionStorage.getItem('allowedComment') === 'true'; + return (authorIsSolver && allowedComment); +} + function formatCommentData(commentData) { let changedCommentText = `
${commentData.text}`; - if (isUserGrader()) { + if (isUserGrader() || isSolverComment(commentData)) { const deleteButton = ``; changedCommentText = `${deleteButton} ${changedCommentText}`; } @@ -139,6 +145,8 @@ window.addEventListener('load', () => { window.solutionId = codeElement.id; window.fileId = codeElement.file; sessionStorage.setItem('role', codeElement.role); + sessionStorage.setItem('solver', codeElement.solver); + sessionStorage.setItem('allowedComment', codeElement.allowedComment); addLineSpansToPre(document.getElementsByTagName('code')); pullComments(window.fileId, treatComments); }); diff --git a/lms/templates/view.html b/lms/templates/view.html index d52373b1..6b777e46 100644 --- a/lms/templates/view.html +++ b/lms/templates/view.html @@ -67,7 +67,7 @@{{- current_file.code | trim(chars=' ') | e -}}