<commit_before>require 'mission_based'
require 'xml'
class Response < ActiveRecord::Base
  include MissionBased

  belongs_to(:form, :inverse_of => :responses, :counter_cache => true)
  has_many(:answers, :include => :questioning, :order => "questionings.rank", 
    :autosave => true, :validate => false, :dependent => :destroy, :inverse_of => :response)
  belongs_to(:user, :inverse_of => :responses)
  
  attr_accessor(:modifier)
  
  # we turn off validate above and do it here so we can control the message and have only one message
  # regardless of how many answer errors there are
  validates(:user, :presence => true)
  validate(:no_missing_answers)

  # only need to validate answers in web mode
  validates_associated(:answers, :message => "are invalid (see below)", :if => Proc.new{|r| r.modifier == "web"})
  
  default_scope(includes({:form => :type}, :user).order("responses.created_at DESC"))
  scope(:unreviewed, where(:reviewed => false))
  scope(:by, lambda{|user| where(:user_id => user.id)})
  
  self.per_page = 20
  
  def self.find_eager(id)
    includes([:form, {:answers => 
      {
        :choices => {:option => :translations},
        :option => :translations, 
        :questioning => [:condition, {:question => [:type, :translations, {:option_set => {:options => :translations}}]}]
      }
    }]).find(id)
  end
  
  def self.for_export(rel)
    find_by_sql(export_sql(rel))
  end
  
  # gets the list of fields to be searched for this class
  # includes whether they should be included in a default, unqualified search
  # and whether they are searchable by a regular expression
  def self.search_qualifiers
    [
      Search::Qualifier.new(:label => "formname", :col => "forms.name", :assoc => :forms),
      Search::Qualifier.new(:label => "formtype", :col => "form_types.name", :assoc => :form_types),
      Search::Qualifier.new(:label => "reviewed", :col => "responses.reviewed", :subst => {"yes" => "1", "no" => "0"}),
      Search::Qualifier.new(:label => "submitter", :col => "users.name", :assoc => :users, :partials => true),
      Search::Qualifier.new(:label => "answer", :col => "answers.value", :assoc => :answers, :partials => true, :default => true),
      Search::Qualifier.new(:label => "source", :col => "responses.source"),
      Search::Qualifier.new(:label => "date", :col => "DATE(CONVERT_TZ(responses.created_at, 'UTC', '#{Time.zone.mysql_name}'))"),

      # this qualifier matches responses that have answers to questions with the given option set
      Search::Qualifier.new(:label => "option-set", :col => "option_sets.name", :assoc => :option_sets),
    ]
  end
  
  def self.search_examples
    ['submitter:"<NAME>"', 'formname:polling', 'reviewed:yes']
  end

  def self.create_from_xml(xml, user, mission)
    # parse xml
    doc = XML::Parser.string(xml).parse
<commit_msg>renamed form, formtype qualifiers, added question-type qualifier<commit_after>require 'mission_based'
require 'xml'
class Response < ActiveRecord::Base
  include MissionBased

  belongs_to(:form, :inverse_of => :responses, :counter_cache => true)
  has_many(:answers, :include => :questioning, :order => "questionings.rank", 
    :autosave => true, :validate => false, :dependent => :destroy, :inverse_of => :response)
  belongs_to(:user, :inverse_of => :responses)
  
  attr_accessor(:modifier)
  
  # we turn off validate above and do it here so we can control the message and have only one message
  # regardless of how many answer errors there are
  validates(:user, :presence => true)
  validate(:no_missing_answers)

  # only need to validate answers in web mode
  validates_associated(:answers, :message => "are invalid (see below)", :if => Proc.new{|r| r.modifier == "web"})
  
  default_scope(includes({:form => :type}, :user).order("responses.created_at DESC"))
  scope(:unreviewed, where(:reviewed => false))
  scope(:by, lambda{|user| where(:user_id => user.id)})
  
  self.per_page = 20
  
  def self.find_eager(id)
    includes([:form, {:answers => 
      {
        :choices => {:option => :translations},
        :option => :translations, 
        :questioning => [:condition, {:question => [:type, :translations, {:option_set => {:options => :translations}}]}]
      }
    }]).find(id)
  end
  
  def self.for_export(rel)
    find_by_sql(export_sql(rel))
  end
  
  # gets the list of fields to be searched for this class
  # includes whether they should be included in a default, unqualified search
  # and whether they are searchable by a regular expression
  def self.search_qualifiers
    [
      Search::Qualifier.new(:label => "form", :col => "forms.name", :assoc => :forms),
      Search::Qualifier.new(:label => "form-type", :col => "form_types.name", :assoc => :form_types),
      Search::Qualifier.new(:label => "reviewed", :col => "responses.reviewed", :subst => {"yes" => "1", "no" => "0"}),
      Search::Qualifier.new(:label => "submitter", :col => "users.name", :assoc => :users, :partials => true),
      Search::Qualifier.new(:label => "answer", :col => "answers.value", :assoc => :answers, :partials => true, :default => true),
      Search::Qualifier.new(:label => "source", :col => "responses.source"),
      Search::Qualifier.new(:label => "date", :col => "DATE(CONVERT_TZ(responses.created_at, 'UTC', '#{Time.zone.mysql_name}'))"),

      # this qualifier matches responses that have answers to questions with the given option set
      Search::Qualifier.new(:label => "option-set", :col => "option_sets.name", :assoc => :option_sets),

      # this qualifier matces responses that have answers to questions with the given type
      Search::Qualifier.new(:label => "question-type", :col => "question_types.long_name", :assoc => :question_types)

    ]
  end
  
  def self.search_examples
    ['submitter:"<NAME>"', 'form:polling', 'reviewed:yes', 'date < 2010-03-15']
  end

  def self.create_from_xml(xml, user, mission)
    # parse xml
    doc = XML::Parser.string(xml).parse

{'fraction_non_alphanumeric': 0.16414904330312186, 'fraction_numerical': 0.002685464921114468, 'mean_word_length': 4.208916083916084, 'pattern_counts': {'":': 0, '<': 8, '<?xml version=': 0, '>': 108, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 10}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '3704744', 'n_tokens_mistral': 1940, 'n_tokens_neox': 1859, 'n_words': 495}