<commit_before># frozen_string_literal: true

#
# Copyright (C) 2013 - present Instructure, Inc.
#
# This file is part of Canvas.
#
# Canvas is free software: you can redistribute it and/or modify it under
# the terms of the GNU Affero General Public License as published by the Free
# Software Foundation, version 3 of the License.
#
# Canvas is distributed in the hope that it will be useful, but WITHOUT ANY
# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
# A PARTICULAR PURPOSE. See the GNU Affero General Public License for more
# details.
#
# You should have received a copy of the GNU Affero General Public License along
# with this program. If not, see <http://www.gnu.org/licenses/>.
#

# @API Submission Comments
#
# This API can be used to edit and delete submission comments.
class SubmissionCommentsApiController < ApplicationController
  before_action :require_context

  include Api::V1::Attachment
  include Api::V1::SubmissionComment

  # @API Edit a submission comment
  #
  # Edit the given submission comment.
  #
  # @argument comment [String]
  #   If this argument is present, edit the text of a comment.
  #
  # @returns SubmissionComment
  def update
    submission_comment = SubmissionComment.find(params[:id])
    if authorized_action(submission_comment, @current_user, :update)
      submission_comment.updating_user = @current_user
      submission_comment.reload unless submission_comment.update(submission_comment_params)

      return render json: submission_comment_json(
        submission_comment,
        @current_user
      )
    end
  end

  def submission_comment_params
    params.permit(:comment)
  end

  # @API Delete a submission comment
  #
  # Delete the given submission comment.
  #
  # @example_request
  #     curl https://<canvas>/api/v1/courses/<course_id>/assignments/<assignment_id>/submissions/<user_id>/comments/<id> \
  #          -X DELETE \
  #          -H 'Authorization: Bearer <token>'
  # @returns SubmissionComment
  def destroy
    submission_comment = SubmissionComment.find(params[:id])
    if authorized_action(submission_comment, @current_user, :delete)
      comment_data = anonymous_moderated_submission_comments_json(
        assignment: submission_comment.submission.assignment,
        course: @context,
        current_user: @current_user,
        avatars: service_enabled?(:avatars),
        submission_comments: [submission_comment],
        submissions: [submission_comment.submission]
      )[0]

      submission_comment.updating_user = @current_user
      submission_comment.destroy!

      return render json: comment_data
    end
  end

  # @API Upload a file
  #
  # Upload a file to attach to a submission comment
  #
  # See the {file:file_uploads.html File Upload Documentation} for details on the file upload workflow.
  #
  # The final step of the file upload workflow will return the attachment data,
  # including the new file id. The caller can then PUT the file_id to the
  # submission API to attach it to a comment
  def create_file
    @assignment = api_find(@context.assignments.active, params[:assignment_id])
    @user = api_find(@context.students_visible_to(@current_user, include: :inactive),
                     params[:user_id])

    if authorized_action?(@assignment, @current_user,
                          :attach_submission_comment_files)
      api_attachment_preflight(@assignment, request, check_quota: false)
    end
  end

  # Internal: annotation_notification
  #
  # Send notification of annotation to other users of the submission
  # Must have permission to send_messages on Site Admin account.
  # annotation notifications go to all users on the submission and the observers for those users.
  # annotation notifications also go to the instructors unless it is sent from an instructor.
  # annotation notifications from instructors go to students if assignment is set to post automatically or if the assignment is posted.
  #
  # @argument author_id [Required, String]
  #   The user that created the annotation
  #
  # @example_request
  #    curl https://<canvas>/api/v1/courses/:course_id/assignments/:assignment_id/submissions/:user_id/annotation_notification
  #      -H 'Authorization: Bearer <token>' \
  #      -X POST \
  #      -F "author_id": "1"
  #
  # returns {}, status 200
  def annotation_notification
    GuardRail.activate(:secondary) do
      if authorized_action?(Account.site_admin, @current_user, :send_messages)
        assignment = api_find(@context.assignments.active, params[:assignment_id])
        author = assignment.shard.activate { api_find(User.active, params[:author_id]) }
        user = api_find(@context.all_current_users, params[:user_id])
        submission = assignment.submissions.where(user_id: user).take
        unless submission
          return render json: { error: "Couldn't find Submission for user with API id #{params[:user_id]}" },
                        status: :bad_request
        end

        user.mark_submission_annotations_unread!(submission) unless user == author

        instructors = @context.instructors_in_charge_of(user)

        # If the author is an instructor, check post_policies to see if we should notify others.
        # Don't notify other instructors if author is an instructor
        #
        if author_is_instructor?(author, instructors)
          # author is instructors, so check post_policies, if submission is not posted
          # and not set to automatically post, don't notify anyone.
          if assignment.post_manually? && !submission.posted?
            return render json: {}, status: 200
          end
        else # author is a student or admin
          # always notify instructor
          broadcast_annotation_notification(submission: submission, to_list: instructors, data: broadcast_data(author))
        end

        submissions_by_user_id = if submission.group_id
                                   assignment.submissions.where(user_id: submission.group.users.select(:id)).index_by(&:user_id)
                                 else
                                   # if the user is the author there are no more people to notify.
                                   return render json: {}, status: 200 if author == user

                                   { user.id => submission }<commit_msg>switch to primary to mark submission annotations unread<commit_after># frozen_string_literal: true

#
# Copyright (C) 2013 - present Instructure, Inc.
#
# This file is part of Canvas.
#
# Canvas is free software: you can redistribute it and/or modify it under
# the terms of the GNU Affero General Public License as published by the Free
# Software Foundation, version 3 of the License.
#
# Canvas is distributed in the hope that it will be useful, but WITHOUT ANY
# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
# A PARTICULAR PURPOSE. See the GNU Affero General Public License for more
# details.
#
# You should have received a copy of the GNU Affero General Public License along
# with this program. If not, see <http://www.gnu.org/licenses/>.
#

# @API Submission Comments
#
# This API can be used to edit and delete submission comments.
class SubmissionCommentsApiController < ApplicationController
  before_action :require_context

  include Api::V1::Attachment
  include Api::V1::SubmissionComment

  # @API Edit a submission comment
  #
  # Edit the given submission comment.
  #
  # @argument comment [String]
  #   If this argument is present, edit the text of a comment.
  #
  # @returns SubmissionComment
  def update
    submission_comment = SubmissionComment.find(params[:id])
    if authorized_action(submission_comment, @current_user, :update)
      submission_comment.updating_user = @current_user
      submission_comment.reload unless submission_comment.update(submission_comment_params)

      return render json: submission_comment_json(
        submission_comment,
        @current_user
      )
    end
  end

  def submission_comment_params
    params.permit(:comment)
  end

  # @API Delete a submission comment
  #
  # Delete the given submission comment.
  #
  # @example_request
  #     curl https://<canvas>/api/v1/courses/<course_id>/assignments/<assignment_id>/submissions/<user_id>/comments/<id> \
  #          -X DELETE \
  #          -H 'Authorization: Bearer <token>'
  # @returns SubmissionComment
  def destroy
    submission_comment = SubmissionComment.find(params[:id])
    if authorized_action(submission_comment, @current_user, :delete)
      comment_data = anonymous_moderated_submission_comments_json(
        assignment: submission_comment.submission.assignment,
        course: @context,
        current_user: @current_user,
        avatars: service_enabled?(:avatars),
        submission_comments: [submission_comment],
        submissions: [submission_comment.submission]
      )[0]

      submission_comment.updating_user = @current_user
      submission_comment.destroy!

      return render json: comment_data
    end
  end

  # @API Upload a file
  #
  # Upload a file to attach to a submission comment
  #
  # See the {file:file_uploads.html File Upload Documentation} for details on the file upload workflow.
  #
  # The final step of the file upload workflow will return the attachment data,
  # including the new file id. The caller can then PUT the file_id to the
  # submission API to attach it to a comment
  def create_file
    @assignment = api_find(@context.assignments.active, params[:assignment_id])
    @user = api_find(@context.students_visible_to(@current_user, include: :inactive),
                     params[:user_id])

    if authorized_action?(@assignment, @current_user,
                          :attach_submission_comment_files)
      api_attachment_preflight(@assignment, request, check_quota: false)
    end
  end

  # Internal: annotation_notification
  #
  # Send notification of annotation to other users of the submission
  # Must have permission to send_messages on Site Admin account.
  # annotation notifications go to all users on the submission and the observers for those users.
  # annotation notifications also go to the instructors unless it is sent from an instructor.
  # annotation notifications from instructors go to students if assignment is set to post automatically or if the assignment is posted.
  #
  # @argument author_id [Required, String]
  #   The user that created the annotation
  #
  # @example_request
  #    curl https://<canvas>/api/v1/courses/:course_id/assignments/:assignment_id/submissions/:user_id/annotation_notification
  #      -H 'Authorization: Bearer <token>' \
  #      -X POST \
  #      -F "author_id": "1"
  #
  # returns {}, status 200
  def annotation_notification
    GuardRail.activate(:secondary) do
      if authorized_action?(Account.site_admin, @current_user, :send_messages)
        assignment = api_find(@context.assignments.active, params[:assignment_id])
        author = assignment.shard.activate { api_find(User.active, params[:author_id]) }
        user = api_find(@context.all_current_users, params[:user_id])
        submission = assignment.submissions.where(user_id: user).take
        unless submission
          return render json: { error: "Couldn't find Submission for user with API id #{params[:user_id]}" },
                        status: :bad_request
        end

        GuardRail.activate(:primary) { user.mark_submission_annotations_unread!(submission) } unless user == author

        instructors = @context.instructors_in_charge_of(user)

        # If the author is an instructor, check post_policies to see if we should notify others.
        # Don't notify other instructors if author is an instructor
        #
        if author_is_instructor?(author, instructors)
          # author is instructors, so check post_policies, if submission is not posted
          # and not set to automatically post, don't notify anyone.
          if assignment.post_manually? && !submission.posted?
            return render json: {}, status: 200
          end
        else # author is a student or admin
          # always notify instructor
          broadcast_annotation_notification(submission: submission, to_list: instructors, data: broadcast_data(author))
        end

        submissions_by_user_id = if submission.group_id
                                   assignment.submissions.where(user_id: submission.group.users.select(:id)).index_by(&:user_id)
                                 else
                                   # if the user is the author there are no more people to notify.
                                   return render json: {}, status: 200 if author == user

                                   { user.id => submission }
{'fraction_non_alphanumeric': 0.07426556991774383, 'fraction_numerical': 0.003133568350959655, 'mean_word_length': 3.086427656850192, 'pattern_counts': {'":': 2, '<': 23, '<?xml version=': 0, '>': 23, 'https://': 4, 'lorem ipsum': 0, 'www.': 2, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 10, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '3516959', 'n_tokens_mistral': 3456, 'n_tokens_neox': 3363, 'n_words': 1122}