<commit_before>module Spaceship
  # Represents a provisioning profile of the Apple Dev Portal
  class ProvisioningProfile < Base
    # @return (String) The ID generated by the Dev Portal
    #   You'll probably not really need this value
    # @example
    #   "2MAY7NPHAA"
    attr_accessor :id

    # @return (String) The UDID of this provisioning profile
    #   This value is used for example for code signing
    #   It is also contained in the actual profile
    # @example
    #   "23d7df3b-9767-4e85-a1ea-1df4d8f32fec"
    attr_accessor :uuid

    # @return (DateTime) The date and time of when the profile
    #   expires. 
    # @example
    #   #<DateTime: 2015-11-25T22:45:50+00:00 ((2457352j,81950s,0n),+0s,2299161j)>
    attr_accessor :expires

    # @return (String) The profile distribution type. You probably want to 
    #   use the class type to detect the profile type instead of this string.
    # @example AppStore Profile
    #     "store"
    # @example AdHoc Profile
    #     "adhoc"
    # @example Development Profile
    #     "limited"
    attr_accessor :distribution_method

    # @return (String) The name of this profile
    # @example
    #   "com.krausefx.app AppStore"
    attr_accessor :name

    # @return (String) The status of this profile
    # @example Active (profile is fine)
    #   "Active"
    # @example Expired (time ran out)
    #   "Expired"
    # @example Invalid (e.g. code signing identity not available any more)
    #   "Invalid"
    attr_accessor :status

    # @return (String) The type of the profile (development or distribution). 
    #   You'll probably not need this value
    # @example Distribution
    #   "iOS Distribution"
    # @example Development
    #   "iOS Development"
    attr_accessor :type

    # @return (String) This will always be "2"
    # @example
    #   "2"
    attr_accessor :version

    # @return (String) The supported platform for this profile
    # @example
    #   "ios"
    attr_accessor :platform

    # No information about this attribute
    attr_accessor :managing_app

    # A reference to the app this profile is for.
    # You can then easily access the value directly
    # @return (App) The app this profile is for
    # 
    # @example Example Value
    #   <Spaceship::App
    #     @app_id="2UMR2S6PAA"
    #     @name="<NAME>"
    #     @platform="ios"
    #     @prefix="5A997XSAAA"
    #     @bundle_id="com.krausefx.app"
    #     @is_wildcard=false
    #     @dev_push_enabled=false
    #     @prod_push_enabled=false>
    # 
    # @example Usage
    #   profile.app.name
    attr_accessor :app

    # @return (Array) A list of certificates used for this profile
    # @example Example Value
    #  [
    #   <Spaceship::Certificate::Production
    #     @status=nil
    #     @id="XC5PH8D4AA"
    #     @name="iOS Distribution"
    #     @created=nil
    #     @expires=#<DateTime: 2015-11-25T22:45:50+00:00 ((2457352j,81950s,0n),+0s,2299161j)>
    #     @owner_type="team"
    #     @owner_name=nil
    #     @owner_id=nil
    #     @type_display_id="R58UK2EWAA">]
    #  ]
    # 
    # @example Usage
    #   profile.certificates.first.id
    attr_accessor :certificates

    # @return (Array) A list of devices this profile is enabled for.
    #   This will always be [] for AppStore profiles
    # 
    # @example Example Value
    #  <Spaceship::Device
    #    @id="WXQ7V239BE"
    #    @name="Grahams iPhone 4s"
    #    @udid="ba0ac7d70f7a14c6fa02ef0e02f4fe9c5178e2f7"
    #    @platform="ios"
    #    @status="c">]
    # 
    # @example Usage
    #  profile.devices.first.name
    attr_accessor :devices

    attr_mapping({
      'provisioningProfileId' => :id,
      'UUID' => :uuid,
      'dateExpire' => :expires,
      'distributionMethod' => :distribution_method,
      'name' => :name,
      'status' => :status,
      'type' => :type,
      'version' => :version,
      'proProPlatform' => :platform,
      'managingApp' => :managing_app,
      'appId' => :app
    })

    class << self
      # @return (String) The profile type used for web requests to the Dev Portal
      # @example
      #  "limited"
      #  "store"
      #  "adhoc"
      #  "inhouse"
      def type
        raise "You cannot create a ProvisioningProfile without a type. Use a subclass."
      end

      # Create a new object based on a hash.
      # This is used to create a new object based on the server response.
      def factory(attrs)
        # Ad Hoc Profiles look exactly like App Store profiles, but usually include devices
        attrs['distributionMethod'] = 'adhoc' if attrs['distributionMethod'] == 'store' && attrs['devices'].size > 0
        # available values of `distributionMethod` at this point: ['adhoc', 'store', 'limited']

        klass = case attrs['distributionMethod']
        when 'limited'
          Development
        when 'store'
          AppStore
        when 'adhoc'
          AdHoc
        when 'inhouse'
          InHouse
        else
          raise "Can't find class '#{attrs['distributionMethod']}'"
        end

        attrs['appId'] = App.factory(attrs['appId'])
        attrs['devices'].map! { |device| Device.factory(device) }
        attrs['certificates'].map! { |cert| Certificate.factory(cert) }

        klass.client = @client
        klass.new(attrs)
      end

      # @return (String) The human readable name of this profile type.
      # @example
      #  "AppStore"
      #  "AdHoc"
      #  "Development"
      #  "InHouse"
      def pretty_type
        name.split('::').last
      end

      # Create a new provisioning profile
      # @param name (String): The name of the provisioning profile on the Dev Portal
      # @param bundle_id (String): The app identifier, this paramter is required
      # @param certificate (Certificate): The certificate that should be used with this
      #  provisioning profile
      # @param devices (Array) (optional): An array of Device objects that should be used in this profile.
      #  It is recommend to not pass devices as spaceship will automatically add all devices for AdHoc
      #  and Development profiles and add none for AppStore and Enterprise Profiles
      # @return (ProvisioningProfile): The profile that was just created
      def create!(name: nil, bundle_id: nil, certificate: nil, devices: [])
        raise "Missing required parameter 'bundle_id'" if bundle_id.to_s.empty?
        raise "Missing required parameter 'certificate'. e.g. use `Spaceship::Certificate::Production.all.first`" if certificate.to_s.empty?

        app = Spaceship::App.find(bundle_id)
        raise "Could not find app with bundle id '#{bundle_id}'" unless app

        # Fill in sensible default values
        name ||= [bundle_id, self.pretty_type].join(' ')

        devices = [] if self == AppStore # App Store Profiles MUST NOT have devices

        if devices.nil? or devices.count == 0
          if self == Development or self == AdHoc
            # For Development and AdHoc we usually want all devices by default
            devices = Spaceship::Device.all
          end
        end

        profile = client.create_provisioning_profile!(name,
                                              self.type,
                                              app.app_id,
                                              [certificate.id],
                                              devices.map {|d| d.id} )
        self.new(profile)
      end

      # @return (Array) Returns all profiles registered for this account
      #  If you're calling this from a subclass (like AdHoc), this will 
      #  only return the profiles that are of this type
      def all
        profiles = client.provisioning_profiles.map do |profile|
          self.factory(profile)
        end

        # filter out the profiles managed by xcode
        profiles.delete_if do |profile|
          profile.managed_by_xcode?
        end

        return profiles if self == ProvisioningProfile

        # only return the profiles that match the class
        profiles.select do |profile|
          profile.class == self
        end
      end

      # @return (ProvisioningProfile) Find a provisioning based on the
      #  bundle_id (app identifier). This will return nil if it can't be
      #  found.
      def find_by_bundle_id(bundle_id)
        all.find_all do |profile|
          profile.app.bundle_id == bundle_id
        end
      end

    end

    # Represents a Development profile from the Dev Portal
    class Development < ProvisioningProfile
      def self.type
        'limited'
      end
    end

    # Represents an AppStore profile from the Dev Portal
    class AppStore < ProvisioningProfile
      def self.type
        'store'
      end
    end

    # Represents an AdHoc profile from the Dev Portal
    class AdHoc < ProvisioningProfile
      def self.type
        'adhoc'
      end
    end

    # Represents an Enterprise InHouse profile from the Dev Portal
    class InHouse < ProvisioningProfile
      def self.type
        'inhouse'
      end
    end

    # Download the current provisioning profile. This will *not* store
    # the provisioning profile on the file system. Instead this method
    # will return the content of the profile.
    # @return (String) The content of the provisioning profile
    #  You'll probably want to store it on the file system
    # @example
    #  File.write("path.mobileprovision", profile.download)
    def download
      client.download_provisioning_profile(self.id)
    end

    # Delete the provisioning profile
    def delete!
      client.delete_provisioning_profile!(self.id)
    end

    # Repair an existing provisioning profile
    # alias to update!
    def repair!
      update!
    end

    # Updates the provisioning profile from the local data
    # e.g. after you added new devices to the profile
    # This will also update the code signing identity if necessary
    def update!
      unless certificate_valid?
        if self.kind_of?Development
          self.certificates = [Spaceship::Certificate::Development.all.first]
        else
          self.certificates = [Spaceship::Certificate::Production.all.first]
        end
      end

      client.repair_provisioning_profile!(
        self.id,
        self.name,
        self.distribution_method,
        self.app.app_id,
        self.certificates.map { |c| c.id },
        self.devices.map { |d| d.id }
      )
    end

    # Is the certificate of this profile available?
    # @return (Bool) is the certificate valid? 
    def certificate_valid?
      return false if (certificates || []).count == 0
      certificates.each do |c|
        if Spaceship::Certificate.all.collect { |s| s.id }.include?(c.id)
          return true
        end
      end
      return false
    end

    # @return (Bool) Is this profile managed by Xcode?<commit_msg>Added automatic retrieving of new profile after update is called<commit_after>module Spaceship
  # Represents a provisioning profile of the Apple Dev Portal
  class ProvisioningProfile < Base
    # @return (String) The ID generated by the Dev Portal
    #   You'll probably not really need this value
    # @example
    #   "2MAY7NPHAA"
    attr_accessor :id

    # @return (String) The UDID of this provisioning profile
    #   This value is used for example for code signing
    #   It is also contained in the actual profile
    # @example
    #   "23d7df3b-9767-4e85-a1ea-1df4d8f32fec"
    attr_accessor :uuid

    # @return (DateTime) The date and time of when the profile
    #   expires. 
    # @example
    #   #<DateTime: 2015-11-25T22:45:50+00:00 ((2457352j,81950s,0n),+0s,2299161j)>
    attr_accessor :expires

    # @return (String) The profile distribution type. You probably want to 
    #   use the class type to detect the profile type instead of this string.
    # @example AppStore Profile
    #     "store"
    # @example AdHoc Profile
    #     "adhoc"
    # @example Development Profile
    #     "limited"
    attr_accessor :distribution_method

    # @return (String) The name of this profile
    # @example
    #   "com.krausefx.app AppStore"
    attr_accessor :name

    # @return (String) The status of this profile
    # @example Active (profile is fine)
    #   "Active"
    # @example Expired (time ran out)
    #   "Expired"
    # @example Invalid (e.g. code signing identity not available any more)
    #   "Invalid"
    attr_accessor :status

    # @return (String) The type of the profile (development or distribution). 
    #   You'll probably not need this value
    # @example Distribution
    #   "iOS Distribution"
    # @example Development
    #   "iOS Development"
    attr_accessor :type

    # @return (String) This will always be "2"
    # @example
    #   "2"
    attr_accessor :version

    # @return (String) The supported platform for this profile
    # @example
    #   "ios"
    attr_accessor :platform

    # No information about this attribute
    attr_accessor :managing_app

    # A reference to the app this profile is for.
    # You can then easily access the value directly
    # @return (App) The app this profile is for
    # 
    # @example Example Value
    #   <Spaceship::App
    #     @app_id="2UMR2S6PAA"
    #     @name="App Name"
    #     @platform="ios"
    #     @prefix="5A997XSAAA"
    #     @bundle_id="com.krausefx.app"
    #     @is_wildcard=false
    #     @dev_push_enabled=false
    #     @prod_push_enabled=false>
    # 
    # @example Usage
    #   profile.app.name
    attr_accessor :app

    # @return (Array) A list of certificates used for this profile
    # @example Example Value
    #  [
    #   <Spaceship::Certificate::Production
    #     @status=nil
    #     @id="XC5PH8D4AA"
    #     @name="iOS Distribution"
    #     @created=nil
    #     @expires=#<DateTime: 2015-11-25T22:45:50+00:00 ((2457352j,81950s,0n),+0s,2299161j)>
    #     @owner_type="team"
    #     @owner_name=nil
    #     @owner_id=nil
    #     @type_display_id="R58UK2EWAA">]
    #  ]
    # 
    # @example Usage
    #   profile.certificates.first.id
    attr_accessor :certificates

    # @return (Array) A list of devices this profile is enabled for.
    #   This will always be [] for AppStore profiles
    # 
    # @example Example Value
    #  <Spaceship::Device
    #    @id="WXQ7V239BE"
    #    @name="Grahams iPhone 4s"
    #    @udid="ba0ac7d70f7a14c6fa02ef0e02f4fe9c5178e2f7"
    #    @platform="ios"
    #    @status="c">]
    # 
    # @example Usage
    #  profile.devices.first.name
    attr_accessor :devices

    attr_mapping({
      'provisioningProfileId' => :id,
      'UUID' => :uuid,
      'dateExpire' => :expires,
      'distributionMethod' => :distribution_method,
      'name' => :name,
      'status' => :status,
      'type' => :type,
      'version' => :version,
      'proProPlatform' => :platform,
      'managingApp' => :managing_app,
      'appId' => :app
    })

    class << self
      # @return (String) The profile type used for web requests to the Dev Portal
      # @example
      #  "limited"
      #  "store"
      #  "adhoc"
      #  "inhouse"
      def type
        raise "You cannot create a ProvisioningProfile without a type. Use a subclass."
      end

      # Create a new object based on a hash.
      # This is used to create a new object based on the server response.
      def factory(attrs)
        # Ad Hoc Profiles look exactly like App Store profiles, but usually include devices
        attrs['distributionMethod'] = 'adhoc' if attrs['distributionMethod'] == 'store' && attrs['devices'].size > 0
        # available values of `distributionMethod` at this point: ['adhoc', 'store', 'limited']

        klass = case attrs['distributionMethod']
        when 'limited'
          Development
        when 'store'
          AppStore
        when 'adhoc'
          AdHoc
        when 'inhouse'
          InHouse
        else
          raise "Can't find class '#{attrs['distributionMethod']}'"
        end

        attrs['appId'] = App.factory(attrs['appId'])
        attrs['devices'].map! { |device| Device.factory(device) }
        attrs['certificates'].map! { |cert| Certificate.factory(cert) }

        klass.client = @client
        klass.new(attrs)
      end

      # @return (String) The human readable name of this profile type.
      # @example
      #  "AppStore"
      #  "AdHoc"
      #  "Development"
      #  "InHouse"
      def pretty_type
        name.split('::').last
      end

      # Create a new provisioning profile
      # @param name (String): The name of the provisioning profile on the Dev Portal
      # @param bundle_id (String): The app identifier, this paramter is required
      # @param certificate (Certificate): The certificate that should be used with this
      #  provisioning profile
      # @param devices (Array) (optional): An array of Device objects that should be used in this profile.
      #  It is recommend to not pass devices as spaceship will automatically add all devices for AdHoc
      #  and Development profiles and add none for AppStore and Enterprise Profiles
      # @return (ProvisioningProfile): The profile that was just created
      def create!(name: nil, bundle_id: nil, certificate: nil, devices: [])
        raise "Missing required parameter 'bundle_id'" if bundle_id.to_s.empty?
        raise "Missing required parameter 'certificate'. e.g. use `Spaceship::Certificate::Production.all.first`" if certificate.to_s.empty?

        app = Spaceship::App.find(bundle_id)
        raise "Could not find app with bundle id '#{bundle_id}'" unless app

        # Fill in sensible default values
        name ||= [bundle_id, self.pretty_type].join(' ')

        devices = [] if self == AppStore # App Store Profiles MUST NOT have devices

        if devices.nil? or devices.count == 0
          if self == Development or self == AdHoc
            # For Development and AdHoc we usually want all devices by default
            devices = Spaceship::Device.all
          end
        end

        profile = client.create_provisioning_profile!(name,
                                              self.type,
                                              app.app_id,
                                              [certificate.id],
                                              devices.map {|d| d.id} )
        self.new(profile)
      end

      # @return (Array) Returns all profiles registered for this account
      #  If you're calling this from a subclass (like AdHoc), this will 
      #  only return the profiles that are of this type
      def all
        profiles = client.provisioning_profiles.map do |profile|
          self.factory(profile)
        end

        # filter out the profiles managed by xcode
        profiles.delete_if do |profile|
          profile.managed_by_xcode?
        end

        return profiles if self == ProvisioningProfile

        # only return the profiles that match the class
        profiles.select do |profile|
          profile.class == self
        end
      end

      # @return (ProvisioningProfile) Find a provisioning based on the
      #  bundle_id (app identifier). This will return nil if it can't be
      #  found.
      def find_by_bundle_id(bundle_id)
        all.find_all do |profile|
          profile.app.bundle_id == bundle_id
        end
      end

    end

    # Represents a Development profile from the Dev Portal
    class Development < ProvisioningProfile
      def self.type
        'limited'
      end
    end

    # Represents an AppStore profile from the Dev Portal
    class AppStore < ProvisioningProfile
      def self.type
        'store'
      end
    end

    # Represents an AdHoc profile from the Dev Portal
    class AdHoc < ProvisioningProfile
      def self.type
        'adhoc'
      end
    end

    # Represents an Enterprise InHouse profile from the Dev Portal
    class InHouse < ProvisioningProfile
      def self.type
        'inhouse'
      end
    end

    # Download the current provisioning profile. This will *not* store
    # the provisioning profile on the file system. Instead this method
    # will return the content of the profile.
    # @return (String) The content of the provisioning profile
    #  You'll probably want to store it on the file system
    # @example
    #  File.write("path.mobileprovision", profile.download)
    def download
      client.download_provisioning_profile(self.id)
    end

    # Delete the provisioning profile
    def delete!
      client.delete_provisioning_profile!(self.id)
    end

    # Repair an existing provisioning profile
    # alias to update!
    # @return (ProvisioningProfile) A new provisioning profile, as 
    #  the repair method will generate a profile with a new ID
    def repair!
      update!
    end

    # Updates the provisioning profile from the local data
    # e.g. after you added new devices to the profile
    # This will also update the code signing identity if necessary
    # @return (ProvisioningProfile) A new provisioning profile, as 
    #  the repair method will generate a profile with a new ID
    def update!
      unless certificate_valid?
        if self.kind_of?Development
          self.certificates = [Spaceship::Certificate::Development.all.first]
        else
          self.certificates = [Spaceship::Certificate::Production.all.first]
        end
      end

      client.repair_provisioning_profile!(
        self.id,
        self.name,
        self.distribution_method,
        self.app.app_id,
        self.certificates.map { |c| c.id },
        self.devices.map { |d| d.id }
      )

      # We need to fetch the provisioning profile again, as the ID changes
      profile = Spaceship::ProvisioningProfile.all.find do |profile|
        profile.name == self.name # we can use the name as it's valid
      end

      return profile
    end

    # Is the certificate of this profile available?
    # @return (Bool) is the certificate valid? 
    def certificate_valid?
      return false if (certificates || []).count == 0
      certificates.each do |c|
        if Spaceship::Certificate.all.collect { |s| s.id }.include?(c.id)
          return true
        end
      end
      return false
    end

    # @return (Bool) Is this profile managed by Xcode?
{'fraction_non_alphanumeric': 0.08582861253484399, 'fraction_numerical': 0.012678715942810899, 'mean_word_length': 2.2643087760493104, 'pattern_counts': {'":': 0, '<': 28, '<?xml version=': 0, '>': 38, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 48, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '5200657', 'n_tokens_mistral': 6649, 'n_tokens_neox': 6334, 'n_words': 2084}