public async Task <ActionResult <ReviewCommentResponse> > AddExerciseCodeReviewComment([FromRoute] int reviewId, [FromBody] ReviewCreateCommentParameters parameters) { var review = await slideCheckingsRepo.FindExerciseCodeReviewById(reviewId); var submissionUserId = review.ExerciseCheckingId.HasValue ? review.ExerciseChecking.UserId : review.Submission.UserId; var submissionCourseId = review.ExerciseCheckingId.HasValue ? review.ExerciseChecking.CourseId : review.Submission.CourseId; var isInstructor = await courseRolesRepo.HasUserAccessToCourse(UserId, submissionCourseId, CourseRoleType.Instructor); if (submissionUserId != UserId && !isInstructor) { return(StatusCode((int)HttpStatusCode.Forbidden, new ErrorResponse("You can't comment this review"))); } var canReply = isInstructor || !review.Author.IsUlearnBot() || review.NotDeletedComments.Any(c => !c.Author.IsUlearnBot()); if (!canReply) { return(StatusCode((int)HttpStatusCode.Forbidden, new ErrorResponse("You can't reply this review"))); } var comment = await slideCheckingsRepo.AddExerciseCodeReviewComment(UserId, reviewId, parameters.Text); if (review.ExerciseCheckingId.HasValue && review.ExerciseChecking.IsChecked) { var course = await courseManager.FindCourseAsync(submissionCourseId); var slideId = review.ExerciseChecking.SlideId; var unit = course?.FindUnitBySlideId(slideId, isInstructor); if (unit != null && await unitsRepo.IsUnitVisibleForStudents(course, unit.Id)) { await NotifyAboutCodeReviewComment(comment); } } return(ReviewCommentResponse.Build(comment)); }