<commit_before>require 'mechanize'
require 'set'
require 'httparty'
require 'itc/post_data'
require 'itc/response'
require 'itc/models'

module Itc
  class Agent
    include Itc::PostData
    BASE_URI = 'https://itunesconnect.apple.com'
    IMAGE_BASE_URI = 'https://du-itc.itunes.apple.com'

    def get(url, parameters=[], referer=nil, headers={})
      Response.new(@http_client.get(URI.join(BASE_URI, url), parameters, referer, headers).body)
    end

    def post(url, parameters=[], headers={})
      headers = {'Content-Type' => 'application/json'}.merge(headers)
      Response.new(@http_client.post(URI.join(BASE_URI, url), parameters, headers).body)
    rescue Mechanize::ResponseCodeError => e
      Response.new(e.page.body)
    end

    def post_image(url, body=nil, headers={})
      tries ||= 3
      full_url = URI.join(IMAGE_BASE_URI, url)
      response = HTTParty.post(full_url, body: body, headers: headers, timeout: 60, ssl_version: :TLSv1)
      if response.success?
        return ImageUploadResponse.new(response.body)
      else
        raise "Got error code #{response.code} for #{full_url} -- #{response.body}"
      end
    rescue Timeout::Error
      tries -= 1
      if tries > 0
        retry
      else
        raise
      end
    end

    def initialize(username, password)
      @username = username
      @password = password
      @http_client = Mechanize.new
      @http_client.idle_timeout = 1 # Prevent connection resets from apple
    end

    def login
      # TODO Don't select by name in case apple changes
      login_page = @http_client.get(BASE_URI)
      login_form = login_page.form('appleConnectForm')
      login_form.theAccountName = @username
      login_form.theAccountPW = <PASSWORD>
      response = @http_client.submit(login_form)
      unless response.search('h2:contains("Sign In to iTunes Connect")').empty?
        raise "Failed to sign into iTunes Connect"
      end
      @logged_in = true
    end

    def search_by_sku(sku)
      apps = all_apps
      apps.find { |app| app.sku == sku }
    end

    def all_apps
      login unless @logged_in
      response = get('/WebObjects/iTunesConnect.woa/ra/apps/manageyourapps/summary')
      response.raise_if_errors
      response.data['summaries'].map{ |s| App.new(s) }
    end

    def search_by_app_id(app_id)
      login unless @logged_in
      response = get("/WebObjects/iTunesConnect.woa/ra/apps/detail/#{app_id}")
      unless response.errors
        response.data
      end
    rescue Mechanize::ResponseCodeError => e
      false
    end

    def localization
      login unless @logged_in
      l10n_resp = get("/WebObjects/iTunesConnect.woa/ra/l10n")
      l10n_resp.raise_if_errors
      ref_resp = get("/WebObjects/iTunesConnect.woa/ra/ref")
      ref_resp.raise_if_errors
      Localization.new(l10n_resp.data, ref_resp.data)
    end

    def find_app_store_url(app_id)
      app_info = search_by_app_id(app_id)
      if app_info
        app_info["appPageMoreLinks"].find{ |h| h["text"] == "ITC.apps.versionLinks.AppStore" }["link"]
      end
    end

    def app_details(app_id)
      login unless @logged_in
      response = get("/WebObjects/iTunesConnect.woa/ra/apps/detail/#{app_id}")
      response.raise_if_errors
      response.data
    end

    def can_update_version?(app_details)
      return true if app_details['liveVersion']['state'] == 'prepareForUpload'
    end

    def can_add_version?(app_details)
      return app_details['canAddVersion']
    end

    def add_version(app_id, version)
      login unless @logged_in
      data = {version: version}.to_json
      post_response = post("/WebObjects/iTunesConnect.woa/ra/apps/version/create/#{app_id}", data)
      post_response.raise_if_errors
      post_response
    end

    def create_app(name, version, bundle_id, vendor_id)
      login unless @logged_in
      data = create_app_data(name, version, bundle_id, vendor_id).to_json
      response = post("/WebObjects/iTunesConnect.woa/ra/apps/create/?appType=ios", data)
      response.raise_if_errors
      response.data
    end<commit_msg>add app_version_details<commit_after>require 'mechanize'
require 'set'
require 'httparty'
require 'itc/post_data'
require 'itc/response'
require 'itc/models'

module Itc
  class Agent
    include Itc::PostData
    BASE_URI = 'https://itunesconnect.apple.com'
    IMAGE_BASE_URI = 'https://du-itc.itunes.apple.com'

    def get(url, parameters=[], referer=nil, headers={})
      Response.new(@http_client.get(URI.join(BASE_URI, url), parameters, referer, headers).body)
    end

    def post(url, parameters=[], headers={})
      headers = {'Content-Type' => 'application/json'}.merge(headers)
      Response.new(@http_client.post(URI.join(BASE_URI, url), parameters, headers).body)
    rescue Mechanize::ResponseCodeError => e
      Response.new(e.page.body)
    end

    def post_image(url, body=nil, headers={})
      tries ||= 3
      full_url = URI.join(IMAGE_BASE_URI, url)
      response = HTTParty.post(full_url, body: body, headers: headers, timeout: 60, ssl_version: :TLSv1)
      if response.success?
        return ImageUploadResponse.new(response.body)
      else
        raise "Got error code #{response.code} for #{full_url} -- #{response.body}"
      end
    rescue Timeout::Error
      tries -= 1
      if tries > 0
        retry
      else
        raise
      end
    end

    def initialize(username, password)
      @username = username
      @password = password
      @http_client = Mechanize.new
      @http_client.idle_timeout = 1 # Prevent connection resets from apple
    end

    def login
      # TODO Don't select by name in case apple changes
      login_page = @http_client.get(BASE_URI)
      login_form = login_page.form('appleConnectForm')
      login_form.theAccountName = @username
      login_form.theAccountPW = <PASSWORD>
      response = @http_client.submit(login_form)
      unless response.search('h2:contains("Sign In to iTunes Connect")').empty?
        raise "Failed to sign into iTunes Connect"
      end
      @logged_in = true
    end

    def search_by_sku(sku)
      apps = all_apps
      apps.find { |app| app.sku == sku }
    end

    def all_apps
      login unless @logged_in
      response = get('/WebObjects/iTunesConnect.woa/ra/apps/manageyourapps/summary')
      response.raise_if_errors
      response.data['summaries'].map{ |s| App.new(s) }
    end

    def search_by_app_id(app_id)
      login unless @logged_in
      response = get("/WebObjects/iTunesConnect.woa/ra/apps/detail/#{app_id}")
      unless response.errors
        response.data
      end
    rescue Mechanize::ResponseCodeError => e
      false
    end

    def localization
      login unless @logged_in
      l10n_resp = get("/WebObjects/iTunesConnect.woa/ra/l10n")
      l10n_resp.raise_if_errors
      ref_resp = get("/WebObjects/iTunesConnect.woa/ra/ref")
      ref_resp.raise_if_errors
      Localization.new(l10n_resp.data, ref_resp.data)
    end

    def find_app_store_url(app_id)
      app_info = search_by_app_id(app_id)
      if app_info
        app_info["appPageMoreLinks"].find{ |h| h["text"] == "ITC.apps.versionLinks.AppStore" }["link"]
      end
    end

    def app_details(app_id)
      login unless @logged_in
      response = get("/WebObjects/iTunesConnect.woa/ra/apps/detail/#{app_id}")
      response.raise_if_errors
      response.data
    end

    def app_version_details(app_id)
      login unless @logged_in
      response = get("/WebObjects/iTunesConnect.woa/ra/apps/version/#{app_id}")
      response.raise_if_errors
      response.data
    end

    def can_update_version?(app_details)
      return true if app_details['liveVersion']['state'] == 'prepareForUpload'
    end

    def can_add_version?(app_details)
      return app_details['canAddVersion']
    end

    def add_version(app_id, version)
      login unless @logged_in
      data = {version: version}.to_json
      post_response = post("/WebObjects/iTunesConnect.woa/ra/apps/version/create/#{app_id}", data)
      post_response.raise_if_errors
      post_response
    end

    def create_app(name, version, bundle_id, vendor_id)
      login unless @logged_in
      data = create_app_data(name, version, bundle_id, vendor_id).to_json
      response = post("/WebObjects/iTunesConnect.woa/ra/apps/create/?appType=ios", data)
      response.raise_if_errors
      response.data
    end
{'fraction_non_alphanumeric': 0.10771435395271077, 'fraction_numerical': 0.0038213518032003822, 'mean_word_length': 2.989995235826584, 'pattern_counts': {'":': 0, '<': 5, '<?xml version=': 0, '>': 13, 'https://': 4, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, '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': '1305676', 'n_tokens_mistral': 2760, 'n_tokens_neox': 2705, 'n_words': 550}