<commit_before># coding: utf-8

require "danger/helpers/comments_helper"

module Danger
  module RequestSources
    class BitbucketCloudAPI
      attr_accessor :host, :project, :slug, :pull_request_id

      def initialize(repo_slug, pull_request_id, branch_name, environment)
        @username = environment["DANGER_BITBUCKETCLOUD_USERNAME"]
        @password = environment["<PASSWORD>ER_BITBUCKETCLOUD_PASSWORD"]
        self.project, self.slug = repo_slug.split("/")
        self.pull_request_id = pull_request_id || fetch_pr_from_branch(branch_name)
        self.host = "https://bitbucket.org/"
        @environment = environment
      end

      def inspect
        inspected = super

        if @password
          inspected = inspected.sub! @password, "********".freeze
        end

        inspected
      end

      def credentials_given?
        @username && !@username.empty? && @password && !<PASSWORD>?
      end

      def pull_request(*)
        fetch_pr_json
      end

      def fetch_pr_json
        uri = URI(pr_api_endpoint)
        fetch_json(uri)
      end

      def fetch_last_comments
        uri = URI("#{pr_api_endpoint}/activity?limit=1000")
        fetch_json(uri)[:values].select { |v| v[:comment] }.map { |v| v[:comment] }
      end

      def delete_comment(id)
        uri = URI("#{pr_api_endpoint_v1}/comments/#{id}")
        delete(uri)
      end

      def post_comment(text)
        uri = URI("#{pr_api_endpoint_v1}/comments")
        body = { content: text }.to_json
        post(uri, body)
      end

      private

      def base_url(version)
        "https://api.bitbucket.org/#{version}.0/repositories/#{project}/#{slug}/pullrequests"
      end

      def pr_api_endpoint
        "#{base_url(2)}/#{pull_request_id}"
      end

      def pr_api_endpoint_v1
        "#{base_url(1)}/#{pull_request_id}"
      end

      def prs_api_endpoint(branch_name)
        "#{base_url(2)}?q=source.branch.name=\"#{branch_name}\""
      end

      def fetch_pr_from_branch(branch_name)
        uri = URI(URI.escape(prs_api_endpoint(branch_name)))
        fetch_json(uri)[:values][0][:id]
      end

      def access_token
        return @access_token unless @access_token.nil?
        
        oauth_key = @environment["DANGER_BITBUCKETCLOUD_OAUTH_KEY"]
        oauth_secret = @environment["DANGER_BITBUCKETCLOUD_OAUTH_SECRET"]
        return nil if oauth_key.nil?
        return nil if oauth_secret.nil?
        
        uri = URI.parse("https://bitbucket.org/site/oauth2/access_token")
        req = Net::HTTP::Post.new(uri.request_uri, { "Content-Type" => "application/json" })
        req.basic_auth oauth_key, oauth_secret
        req.set_form_data({'grant_type' => 'client_credentials'})
        res = Net::HTTP.start(uri.hostname, uri.port, use_ssl: true) do |http|
            http.request(req)
        end
    
        access_token = JSON.parse(res.body, symbolize_names: true)[:access_token]
        @access_token ||= access_token
      end

      def fetch_json(uri)
        raise credentials_not_available unless credentials_given?
<commit_msg>Move token generation to initializer<commit_after># coding: utf-8

require "danger/helpers/comments_helper"

module Danger
  module RequestSources
    class BitbucketCloudAPI
      attr_accessor :host, :project, :slug, :access_token, :pull_request_id

      def initialize(repo_slug, pull_request_id, branch_name, environment)
        @username = environment["DANGER_BITBUCKETCLOUD_USERNAME"]
        @password = environment["DANGER_BITBUCKETCLOUD_PASSWORD"]
        self.project, self.slug = repo_slug.split("/")
        self.access_token = fetch_access_token(environment)
        self.pull_request_id = pull_request_id || fetch_pr_from_branch(branch_name)
        self.host = "https://bitbucket.org/"
      end

      def inspect
        inspected = super

        if @password
          inspected = inspected.sub! @password, "********".freeze
        end

        inspected
      end

      def credentials_given?
        @username && !@username.empty? && @password && !@password.empty?
      end

      def pull_request(*)
        fetch_pr_json
      end

      def fetch_pr_json
        uri = URI(pr_api_endpoint)
        fetch_json(uri)
      end

      def fetch_last_comments
        uri = URI("#{pr_api_endpoint}/activity?limit=1000")
        fetch_json(uri)[:values].select { |v| v[:comment] }.map { |v| v[:comment] }
      end

      def delete_comment(id)
        uri = URI("#{pr_api_endpoint_v1}/comments/#{id}")
        delete(uri)
      end

      def post_comment(text)
        uri = URI("#{pr_api_endpoint_v1}/comments")
        body = { content: text }.to_json
        post(uri, body)
      end

      private

      def base_url(version)
        "https://api.bitbucket.org/#{version}.0/repositories/#{project}/#{slug}/pullrequests"
      end

      def pr_api_endpoint
        "#{base_url(2)}/#{pull_request_id}"
      end

      def pr_api_endpoint_v1
        "#{base_url(1)}/#{pull_request_id}"
      end

      def prs_api_endpoint(branch_name)
        "#{base_url(2)}?q=source.branch.name=\"#{branch_name}\""
      end

      def fetch_pr_from_branch(branch_name)
        uri = URI(URI.escape(prs_api_endpoint(branch_name)))
        fetch_json(uri)[:values][0][:id]
      end

      def fetch_access_token(environment)
        oauth_key = environment["DANGER_BITBUCKETCLOUD_OAUTH_KEY"]
        oauth_secret = environment["DANGER_BITBUCKETCLOUD_OAUTH_SECRET"]
        return nil if oauth_key.nil?
        return nil if oauth_secret.nil?
        
        uri = URI.parse("https://bitbucket.org/site/oauth2/access_token")
        req = Net::HTTP::Post.new(uri.request_uri, { "Content-Type" => "application/json" })
        req.basic_auth oauth_key, oauth_secret
        req.set_form_data({'grant_type' => 'client_credentials'})
        res = Net::HTTP.start(uri.hostname, uri.port, use_ssl: true) do |http|
            http.request(req)
        end
    
        JSON.parse(res.body, symbolize_names: true)[:access_token]
      end

      def fetch_json(uri)
        raise credentials_not_available unless credentials_given?

{'fraction_non_alphanumeric': 0.11637016484413253, 'fraction_numerical': 0.004569936347315162, 'mean_word_length': 2.6716596764529656, 'pattern_counts': {'":': 0, '<': 5, '<?xml version=': 0, '>': 9, 'https://': 6, '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': '7143729', 'n_tokens_mistral': 1985, 'n_tokens_neox': 1971, 'n_words': 334}