<commit_before>module BlueStateDigital
  class SignupFormField < ApiDataModel
    FIELDS = [:id, :format, :label, :description, :is_required, :is_custom_field, :cons_field_id, :create_dt]
    attr_accessor *FIELDS

    # Takes a <signup_form_field> block already processed by Nokogiri
    def self.from_xml(xml_record)
      SignupFormField.new(id: xml_record[:id],
                          format: xml_record.xpath('format').text,
                          label: xml_record.xpath('label').text,
                          description: xml_record.xpath('description').text,
                          is_required: xml_record.xpath('is_required').text == '1',
                          is_custom_field: xml_record.xpath('is_custom_field').text == '1',
                          cons_field_id: xml_record.xpath('cons_field_id').text.to_i,
                          create_dt: xml_record.xpath('create_dt').text)
    end
  end

  class SignupForm < ApiDataModel
    FIELDS = [:id, :name, :slug, :public_title, :create_dt]
    attr_accessor *FIELDS

    def self.clone(options)
      clone_from_id = options[:clone_from_id]
      slug = options[:slug]
      name = options[:name]
      public_title = options[:public_title]
      connection = options[:connection]

      params = {signup_form_id: clone_from_id, title: public_title, signup_form_name: name, slug: slug}
      xml_response = connection.perform_request '/signup/clone_form', {}, 'POST', params

      doc = Nokogiri::XML(xml_response)
      record = doc.xpath('//signup_form').first
      if record
        id = record.xpath('id').text.to_i
        SignupForm.new(id: id, name: name, slug: slug, public_title: public_title, connection: connection)
      else
        raise "Set constituent data failed with message: #{xml_response}"
      end
    end

    # Takes a hash like {field_data: {'field label' => 'field value'}, email_opt_in: false, source: 'foo', subsource: 'bar'}
    def process_signup(data)
      # Construct the XML to send
      field_data = data[:field_data]
      builder = Builder::XmlMarkup.new
      builder.instruct! :xml, version: '1.0', encoding: 'utf-8'
      xml_body = builder.api do |api|
        api.signup_form(id: self.id) do |form|
          form_fields.each do |field|
            form.signup_form_field(field_data[field.label], id: field.id)
          end
          form.email_opt_in(data[:email_opt_in] ? '1' : '0')
          [:source, :subsource].each do |key|
            if data.has_key?(key)
              form.source(data[key])
            end
          end
        end
      end

      # Post it to the endpoint
      begin
        response = connection.perform_request_raw '/signup/process_signup', {}, 'POST', xml_body
        if response.status >= 200 && response.status < 300
          return true
        else
          raise "process signup failed with message: #{response.body}"
        end
      rescue BlueStateDigital::XmlErrorResponse => err
        begin
          errors = {}
          error_xmls = Nokogiri::XML(err.message).xpath('//error')
          error_xmls.each do |error_xml|
            field = form_fields.select{|field| field.id.to_s == error_xml.xpath('signup_form_field_id').text}.first
            errors[field.label] = error_xml.xpath('description').text<commit_msg>don't overwrite source with subsource<commit_after>module BlueStateDigital
  class SignupFormField < ApiDataModel
    FIELDS = [:id, :format, :label, :description, :is_required, :is_custom_field, :cons_field_id, :create_dt]
    attr_accessor *FIELDS

    # Takes a <signup_form_field> block already processed by Nokogiri
    def self.from_xml(xml_record)
      SignupFormField.new(id: xml_record[:id],
                          format: xml_record.xpath('format').text,
                          label: xml_record.xpath('label').text,
                          description: xml_record.xpath('description').text,
                          is_required: xml_record.xpath('is_required').text == '1',
                          is_custom_field: xml_record.xpath('is_custom_field').text == '1',
                          cons_field_id: xml_record.xpath('cons_field_id').text.to_i,
                          create_dt: xml_record.xpath('create_dt').text)
    end
  end

  class SignupForm < ApiDataModel
    FIELDS = [:id, :name, :slug, :public_title, :create_dt]
    attr_accessor *FIELDS

    def self.clone(options)
      clone_from_id = options[:clone_from_id]
      slug = options[:slug]
      name = options[:name]
      public_title = options[:public_title]
      connection = options[:connection]

      params = {signup_form_id: clone_from_id, title: public_title, signup_form_name: name, slug: slug}
      xml_response = connection.perform_request '/signup/clone_form', {}, 'POST', params

      doc = Nokogiri::XML(xml_response)
      record = doc.xpath('//signup_form').first
      if record
        id = record.xpath('id').text.to_i
        SignupForm.new(id: id, name: name, slug: slug, public_title: public_title, connection: connection)
      else
        raise "Set constituent data failed with message: #{xml_response}"
      end
    end

    # Takes a hash like {field_data: {'field label' => 'field value'}, email_opt_in: false, source: 'foo', subsource: 'bar'}
    def process_signup(data)
      # Construct the XML to send
      field_data = data[:field_data]
      builder = Builder::XmlMarkup.new
      builder.instruct! :xml, version: '1.0', encoding: 'utf-8'
      xml_body = builder.api do |api|
        api.signup_form(id: self.id) do |form|
          form_fields.each do |field|
            form.signup_form_field(field_data[field.label], id: field.id)
          end
          form.email_opt_in(data[:email_opt_in] ? '1' : '0')
          form.source(data[:source]) if data.has_key?(:source)
          form.source(data[:subsource]) if data.has_key?(:subsource)
        end
      end

      # Post it to the endpoint
      begin
        response = connection.perform_request_raw '/signup/process_signup', {}, 'POST', xml_body
        if response.status >= 200 && response.status < 300
          return true
        else
          raise "process signup failed with message: #{response.body}"
        end
      rescue BlueStateDigital::XmlErrorResponse => err
        begin
          errors = {}
          error_xmls = Nokogiri::XML(err.message).xpath('//error')
          error_xmls.each do |error_xml|
            field = form_fields.select{|field| field.id.to_s == error_xml.xpath('signup_form_field_id').text}.first
            errors[field.label] = error_xml.xpath('description').text
{'fraction_non_alphanumeric': 0.11513407059536433, 'fraction_numerical': 0.003938797151946675, 'mean_word_length': 2.5667206915180985, 'pattern_counts': {'":': 0, '<': 11, '<?xml version=': 0, '>': 11, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 42}, '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': '1197133', 'n_tokens_mistral': 2055, 'n_tokens_neox': 2020, 'n_words': 432}