<commit_before>require 'encoding'
require 'auto_complete'
require 'csv_invalid_line_error'

# Manages actions relating to editing and modifying
# groups.
class GroupsController < ApplicationController
  include GroupsHelper
  # Administrator
  before_filter      :authorize_only_for_admin

  auto_complete_for :student, :user_name
  auto_complete_for :assignment, :name

  layout 'assignment_content'

  def note_message
    @assignment = Assignment.find(params[:id])
    if params[:success]
      flash_message(:success, I18n.t('notes.create.success'))
    else
      flash_message(:error, I18n.t('notes.error'))
    end
  end

  # Group administration functions -----------------------------------------
  # Verify that all functions below are included in the authorize filter above

  def new
    assignment = Assignment.find(params[:assignment_id])
    begin
      assignment.add_group(params[:new_group_name])
      flash_now(:success, I18n.t('groups.rename_group.success'))
    rescue Exception => e
      flash[:error] = e.message
    ensure
      head :ok
    end
  end

  def remove_group
    # When a success div exists we can return successfully removed groups
    return unless request.delete?
    grouping = Grouping.find(params[:grouping_id])
    @assignment = grouping.assignment
    @errors = []
    @removed_groupings = []
    students_to_remove = grouping.students.to_a
    grouping.student_memberships.each do |member|
      grouping.remove_member(member.id)
    end
    # TODO: return errors through request
    if grouping.has_submission?
        @errors.push(grouping.group.group_name)
    else
      grouping.delete_grouping
      @removed_groupings.push(grouping)
      flash_message(:success, I18n.t('groups.delete'))
    end
    head :ok
  end

  def rename_group
    @assignment = Assignment.find(params[:assignment_id])
    # group_id is really the grouping_id, this is due to rails routing
    @grouping = Grouping.find(params[:id])
    @group = @grouping.group

    # Checking if a group with this name already exists
    if (@groups = Group.where(group_name: params[:new_groupname]).first)
       existing = true
       groupexist_id = @groups.id
    end

    unless existing
      # We update the group_name
      @group.group_name = params[:new_groupname]
      if @group.save
        flash_message(:success, I18n.t('groups.rename_group.success'))
      end
    else

      # We link the grouping to the group already existing

      # We verify there is no other grouping linked to this group on the
      # same assignement
      params[:groupexist_id] = groupexist_id
      params[:assignment_id] = @assignment.id

      if Grouping.where(assignment_id: @assignment.id, group_id: groupexist_id)
                 .to_a
         flash[:error] = I18n.t('groups.rename_group.already_in_use')
      else
        @grouping.update_attribute(:group_id, groupexist_id)
      end
    end
  end

  def valid_grouping
    assignment = Assignment.find(params[:assignment_id])
    grouping = Grouping.find(params[:grouping_id])
    grouping.validate_grouping
    head :ok
  end

  def invalid_grouping
    assignment = Assignment.find(params[:assignment_id])
    grouping = Grouping.find(params[:grouping_id])
    grouping.invalidate_grouping
    head :ok
  end

  def index
    @assignment = Assignment.find(params[:assignment_id])
    @clone_assignments = Assignment.where(vcs_submit: true)
                                   .where.not(id: @assignment.id)
                                   .order(:id)
  end

  def assign_scans
    @assignment = Assignment.find(params[:assignment_id])
    if params.has_key?(:grouping)
      next_grouping = Grouping.find(params[:grouping])
    else
      next_grouping = Grouping.get_assign_scans_grouping(@assignment)
    end
    if next_grouping.nil?
      redirect_to(:back)
      return
    end
    names = next_grouping.memberships.map do |u|
      u.user.first_name + ' ' + u.user.last_name
    end
    num_valid = @assignment.get_num_valid
    num_total = @assignment.get_num_assigned
    if num_valid == num_total
      flash_message(:success, t('groups.done_assign'))
    end
    @data = {
      group_name: next_grouping.group.group_name,
      grouping_id: next_grouping.id,
      students: names,
      num_total: num_total,
      num_valid: num_valid
    }
    next_file = next_grouping.current_submission_used.submission_files.find_by(filename: 'COVER.pdf')
    unless next_file.nil?
      @data[:filelink] = download_assignment_groups_path(
        select_file_id: next_grouping.current_submission_used.submission_files.find_by(filename: 'COVER.pdf').id,
        show_in_browser: true )
    end
  end

  def get_names
    names = Student
              .select(:id, :id_number, :user_name, "CONCAT(first_name,' ',last_name) AS label, CONCAT(first_name,' ',last_name) AS value")
              .where("(lower(first_name) like ? OR lower(last_name) like ? OR lower(user_name) like ? OR id_number like ?) AND users.id NOT IN (?)",
                     "#{params[:term].downcase}%", "#{params[:term].downcase}%", "#{params[:term].downcase}%", "#{params[:term]}%",
                     Membership.select(:user_id).joins(:grouping).where("groupings.assignment_id = ?", params[:assignment]));
    render json: names
  end

  def assign_student_and_next
    @grouping = Grouping.find(params[:g_id])
    @assignment = @grouping.assignment
    if params[:skip]
      @grouping.validate_grouping
    else
      # if the user has selected a name from the dropdown, s_id is set
      if params[:s_id].present?
        student = Student.find(params[:s_id])
      end
      # if the user has typed in the whole name without select, or if they typed a name different from the select s_id
      if student.nil? || (student.first_name + ' ' + student.last_name) != params[:names]
        student = Student.where('lower(CONCAT(first_name, \' \', last_name)) like ? OR lower(CONCAT(last_name, \' \', first_name)) like ?',
                                 params[:names].downcase, params[:names].downcase).first
      end
      StudentMembership
        .find_or_create_by(user: student, grouping: @grouping, membership_status: StudentMembership::STATUSES[:accepted])
    end
    next_grouping
  end

  def next_grouping
    if params[:a_id].present?
      @assignment = Assignment.find(params[:a_id])
    end
    next_grouping = Grouping.get_assign_scans_grouping(@assignment)
    names = next_grouping.memberships.map do |u|
      u.user.first_name + ' ' + u.user.last_name
    end
    num_valid = @assignment.get_num_valid
    num_total = @assignment.get_num_assigned
    if num_valid == num_total
      flash_message(:success, t('groups.done_assign'))
    end
    if !@grouping.nil? && next_grouping.id == @grouping.id
      render json: {
        grouping_id: next_grouping.id,
        students: names,
        num_total: num_total,
        num_valid: num_valid
      }
    else
      data = {
        group_name: next_grouping.group.group_name,
        grouping_id: next_grouping.id,
        students: names,
        num_total: num_total,
        num_valid: num_valid
      }
      next_file = next_grouping.current_submission_used.submission_files.find_by(filename: 'COVER.pdf')
      unless next_file.nil?
          data[:filelink] = download_assignment_groups_path(
          select_file_id: next_grouping.current_submission_used.submission_files.find_by(filename: 'COVER.pdf').id,
          show_in_browser: true )
      end
      render json: data
    end<commit_msg>Don't permanently skip papers in assign_scans, and display only student memberships<commit_after>require 'encoding'
require 'auto_complete'
require 'csv_invalid_line_error'

# Manages actions relating to editing and modifying
# groups.
class GroupsController < ApplicationController
  include GroupsHelper
  # Administrator
  before_filter      :authorize_only_for_admin

  auto_complete_for :student, :user_name
  auto_complete_for :assignment, :name

  layout 'assignment_content'

  def note_message
    @assignment = Assignment.find(params[:id])
    if params[:success]
      flash_message(:success, I18n.t('notes.create.success'))
    else
      flash_message(:error, I18n.t('notes.error'))
    end
  end

  # Group administration functions -----------------------------------------
  # Verify that all functions below are included in the authorize filter above

  def new
    assignment = Assignment.find(params[:assignment_id])
    begin
      assignment.add_group(params[:new_group_name])
      flash_now(:success, I18n.t('groups.rename_group.success'))
    rescue Exception => e
      flash[:error] = e.message
    ensure
      head :ok
    end
  end

  def remove_group
    # When a success div exists we can return successfully removed groups
    return unless request.delete?
    grouping = Grouping.find(params[:grouping_id])
    @assignment = grouping.assignment
    @errors = []
    @removed_groupings = []
    students_to_remove = grouping.students.to_a
    grouping.student_memberships.each do |member|
      grouping.remove_member(member.id)
    end
    # TODO: return errors through request
    if grouping.has_submission?
        @errors.push(grouping.group.group_name)
    else
      grouping.delete_grouping
      @removed_groupings.push(grouping)
      flash_message(:success, I18n.t('groups.delete'))
    end
    head :ok
  end

  def rename_group
    @assignment = Assignment.find(params[:assignment_id])
    # group_id is really the grouping_id, this is due to rails routing
    @grouping = Grouping.find(params[:id])
    @group = @grouping.group

    # Checking if a group with this name already exists
    if (@groups = Group.where(group_name: params[:new_groupname]).first)
       existing = true
       groupexist_id = @groups.id
    end

    unless existing
      # We update the group_name
      @group.group_name = params[:new_groupname]
      if @group.save
        flash_message(:success, I18n.t('groups.rename_group.success'))
      end
    else

      # We link the grouping to the group already existing

      # We verify there is no other grouping linked to this group on the
      # same assignement
      params[:groupexist_id] = groupexist_id
      params[:assignment_id] = @assignment.id

      if Grouping.where(assignment_id: @assignment.id, group_id: groupexist_id)
                 .to_a
         flash[:error] = I18n.t('groups.rename_group.already_in_use')
      else
        @grouping.update_attribute(:group_id, groupexist_id)
      end
    end
  end

  def valid_grouping
    assignment = Assignment.find(params[:assignment_id])
    grouping = Grouping.find(params[:grouping_id])
    grouping.validate_grouping
    head :ok
  end

  def invalid_grouping
    assignment = Assignment.find(params[:assignment_id])
    grouping = Grouping.find(params[:grouping_id])
    grouping.invalidate_grouping
    head :ok
  end

  def index
    @assignment = Assignment.find(params[:assignment_id])
    @clone_assignments = Assignment.where(vcs_submit: true)
                                   .where.not(id: @assignment.id)
                                   .order(:id)
  end

  def assign_scans
    @assignment = Assignment.find(params[:assignment_id])
    if params.has_key?(:grouping)
      next_grouping = Grouping.find(params[:grouping])
    else
      next_grouping = Grouping.get_assign_scans_grouping(@assignment)
    end
    if next_grouping.nil?
      redirect_to(:back)
      return
    end
    names = next_grouping.non_rejected_student_memberships.map do |u|
      u.user.first_name + ' ' + u.user.last_name
    end
    num_valid = @assignment.get_num_valid
    num_total = @assignment.get_num_assigned
    if num_valid == num_total
      flash_message(:success, t('groups.done_assign'))
    end
    @data = {
      group_name: next_grouping.group.group_name,
      grouping_id: next_grouping.id,
      students: names,
      num_total: num_total,
      num_valid: num_valid
    }
    next_file = next_grouping.current_submission_used.submission_files.find_by(filename: 'COVER.pdf')
    unless next_file.nil?
      @data[:filelink] = download_assignment_groups_path(
        select_file_id: next_grouping.current_submission_used.submission_files.find_by(filename: 'COVER.pdf').id,
        show_in_browser: true )
    end
  end

  def get_names
    names = Student
              .select(:id, :id_number, :user_name, "CONCAT(first_name,' ',last_name) AS label, CONCAT(first_name,' ',last_name) AS value")
              .where("(lower(first_name) like ? OR lower(last_name) like ? OR lower(user_name) like ? OR id_number like ?) AND users.id NOT IN (?)",
                     "#{params[:term].downcase}%", "#{params[:term].downcase}%", "#{params[:term].downcase}%", "#{params[:term]}%",
                     Membership.select(:user_id).joins(:grouping).where("groupings.assignment_id = ?", params[:assignment]));
    render json: names
  end

  def assign_student_and_next
    @grouping = Grouping.find(params[:g_id])
    @assignment = @grouping.assignment
    unless params[:skip]
      # if the user has selected a name from the dropdown, s_id is set
      if params[:s_id].present?
        student = Student.find(params[:s_id])
      end
      # if the user has typed in the whole name without select, or if they typed a name different from the select s_id
      if student.nil? || (student.first_name + ' ' + student.last_name) != params[:names]
        student = Student.where('lower(CONCAT(first_name, \' \', last_name)) like ? OR lower(CONCAT(last_name, \' \', first_name)) like ?',
                                 params[:names].downcase, params[:names].downcase).first
      end
      StudentMembership
        .find_or_create_by(user: student, grouping: @grouping, membership_status: StudentMembership::STATUSES[:accepted])
    end
    next_grouping
  end

  def next_grouping
    if params[:a_id].present?
      @assignment = Assignment.find(params[:a_id])
    end
    next_grouping = Grouping.get_assign_scans_grouping(@assignment)
    names = next_grouping.non_rejected_student_memberships.map do |u|
      u.user.first_name + ' ' + u.user.last_name
    end
    num_valid = @assignment.get_num_valid
    num_total = @assignment.get_num_assigned
    if num_valid == num_total
      flash_message(:success, t('groups.done_assign'))
    end
    if !@grouping.nil? && next_grouping.id == @grouping.id
      render json: {
        grouping_id: next_grouping.id,
        students: names,
        num_total: num_total,
        num_valid: num_valid
      }
    else
      data = {
        group_name: next_grouping.group.group_name,
        grouping_id: next_grouping.id,
        students: names,
        num_total: num_total,
        num_valid: num_valid
      }
      next_file = next_grouping.current_submission_used.submission_files.find_by(filename: 'COVER.pdf')
      unless next_file.nil?
          data[:filelink] = download_assignment_groups_path(
          select_file_id: next_grouping.current_submission_used.submission_files.find_by(filename: 'COVER.pdf').id,
          show_in_browser: true )
      end
      render json: data
    end
{'fraction_non_alphanumeric': 0.10346878097125867, 'fraction_numerical': 0.0015857284440039642, 'mean_word_length': 3.0298189563365283, 'pattern_counts': {'":': 0, '<': 5, '<?xml version=': 0, '>': 5, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, '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': '2870575', 'n_tokens_mistral': 4775, 'n_tokens_neox': 4695, 'n_words': 987}