<commit_before>package io.stardog.starwizard.services.stripe;

import com.google.common.base.Preconditions;
import com.google.common.collect.ImmutableMap;
import com.stripe.Stripe;
import com.stripe.exception.SignatureVerificationException;
import com.stripe.exception.StripeException;
import com.stripe.model.*;
import com.stripe.net.RequestOptions;
import com.stripe.net.Webhook;
import io.stardog.starwizard.services.common.AsyncService;
import io.stardog.starwizard.services.stripe.exceptions.UncheckedStripeException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import javax.annotation.Nullable;
import javax.inject.Inject;
import javax.inject.Named;
import javax.inject.Singleton;
import java.math.BigDecimal;
import java.time.Instant;
import java.util.*;

/**
 * StripeService is a wrapper around Stripe's Java API that makes it easier to use in the following ways:
 *   - more mockable/testable, does not rely on static invocations
 *   - wraps checked exceptions and throws UncheckedStripeExceptions instead
 *   - monetary amounts expressed as BigDecimals instead of cents
 *   - checks whether you are using a live stripe key in a non-prod environment, and logs a warning if you are
 */
@Singleton
public class StripeService {
    private final String signingSecret;
    private final Logger LOGGER = LoggerFactory.getLogger(StripeService.class);

    private StripeService(String apiKey, @Nullable String signingSecret) {
        Stripe.apiKey = apiKey;
        Stripe.setAppInfo("starwizard-services", "0.2.1", "https://github.com/stardogventures/starwizard");
        this.signingSecret = signingSecret;
    }

    public static StripeService of(String apiKey) {
        return new StripeService(apiKey, null);
    }

    public static StripeService of(String apiKey, String signingSecret) {
        return new StripeService(apiKey, signingSecret);
    }

    @Inject
    public StripeService(AsyncService asyncService,
                         @Named("stripeSecretKey") String apiKey,
                         @Named("stripeSigningSecret") String signingSecret,
                         @Named("env") String env) {
        this(apiKey, signingSecret);

        // in non-production environment, provide a warning if a live stripe key is in use
        if (!env.equals("prod") && apiKey.startsWith("sk_live_")) {
            asyncService.submit(() -> {
                try {
                    Thread.sleep(5000L);    // sleep long enough to get past normal startup phase, so this message will be visible
                } catch (InterruptedException e) {
                    // okay to swallow this
                }
                LOGGER.warn("***** WARNING: LIVE STRIPE KEY IN USE IN NON-PRODUCTION ENVIRONMENT " + env + " *****");
            });
        }
    }

    /**
     * Creates a new SetupIntent object.
     * @params params   Parameters to pass along to Stripe
     * @return created  Stripe Setup Intent object
     */
    public SetupIntent createSetupIntent(@Nullable Map<String, Object> params) {

        try{
            params = params != null ? params : new HashMap<>();
            return SetupIntent.create(params);
        } catch (StripeException e) {
            throw new UncheckedStripeException(e);
        }

    }


    /**
     * Run a one-off charge, either from a customer or a source token.
     * @param amount    amount of the charge
     * @param currency  currency of the charge
     * @param token token (should either be a source token, or a customer identifier)<commit_msg>Added methods to Stripe Service for retrieving and attaching payment methods.<commit_after>package io.stardog.starwizard.services.stripe;

import com.google.common.base.Preconditions;
import com.google.common.collect.ImmutableMap;
import com.stripe.Stripe;
import com.stripe.exception.SignatureVerificationException;
import com.stripe.exception.StripeException;
import com.stripe.model.*;
import com.stripe.net.RequestOptions;
import com.stripe.net.Webhook;
import io.stardog.starwizard.services.common.AsyncService;
import io.stardog.starwizard.services.stripe.exceptions.UncheckedStripeException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import javax.annotation.Nullable;
import javax.inject.Inject;
import javax.inject.Named;
import javax.inject.Singleton;
import java.math.BigDecimal;
import java.time.Instant;
import java.util.*;

/**
 * StripeService is a wrapper around Stripe's Java API that makes it easier to use in the following ways:
 *   - more mockable/testable, does not rely on static invocations
 *   - wraps checked exceptions and throws UncheckedStripeExceptions instead
 *   - monetary amounts expressed as BigDecimals instead of cents
 *   - checks whether you are using a live stripe key in a non-prod environment, and logs a warning if you are
 */
@Singleton
public class StripeService {
    private final String signingSecret;
    private final Logger LOGGER = LoggerFactory.getLogger(StripeService.class);

    private StripeService(String apiKey, @Nullable String signingSecret) {
        Stripe.apiKey = apiKey;
        Stripe.setAppInfo("starwizard-services", "0.2.1", "https://github.com/stardogventures/starwizard");
        this.signingSecret = signingSecret;
    }

    public static StripeService of(String apiKey) {
        return new StripeService(apiKey, null);
    }

    public static StripeService of(String apiKey, String signingSecret) {
        return new StripeService(apiKey, signingSecret);
    }

    @Inject
    public StripeService(AsyncService asyncService,
                         @Named("stripeSecretKey") String apiKey,
                         @Named("stripeSigningSecret") String signingSecret,
                         @Named("env") String env) {
        this(apiKey, signingSecret);

        // in non-production environment, provide a warning if a live stripe key is in use
        if (!env.equals("prod") && apiKey.startsWith("sk_live_")) {
            asyncService.submit(() -> {
                try {
                    Thread.sleep(5000L);    // sleep long enough to get past normal startup phase, so this message will be visible
                } catch (InterruptedException e) {
                    // okay to swallow this
                }
                LOGGER.warn("***** WARNING: LIVE STRIPE KEY IN USE IN NON-PRODUCTION ENVIRONMENT " + env + " *****");
            });
        }
    }

    /**
     * Creates a new SetupIntent object.
     * @params params   Parameters to pass along to Stripe
     * @return created  Stripe Setup Intent object
     */
    public SetupIntent createSetupIntent(@Nullable Map<String, Object> params) {

        try{
            params = params != null ? params : new HashMap<>();
            return SetupIntent.create(params);
        } catch (StripeException e) {
            throw new UncheckedStripeException(e);
        }

    }

    /**
     * Retrieves a payment method of the given ID. Throws an error if the given ID is not a valid payment method.
     * @return  Payment method object pulled from Stripe.
     */
    public PaymentMethod retrievePaymentMethod(String paymentMethodId) {

        try{
            return PaymentMethod.retrieve(paymentMethodId);
        } catch (StripeException e) {
            throw new UncheckedStripeException(e);
        }

    }

    /**
     * Attaches the given payment method to the given customer.
     * @param paymentMethod     Payment method to attach to the customer
     * @param stripeCustomerId  Stripe ID of the customer to attach the payment method too
     */
    public void attachPaymentMethodToCustomer(PaymentMethod paymentMethod, String stripeCustomerId) {

        Preconditions.checkNotNull(paymentMethod);
        Preconditions.checkNotNull(stripeCustomerId);

        Map<String,Object> params = new HashMap<>();
        params.put("customer", stripeCustomerId);

        try{
            paymentMethod.attach(params);
        } catch (StripeException e) {
            throw new UncheckedStripeException(e);
        }

    }


    /**
     * Run a one-off charge, either from a customer or a source token.
     * @param amount    amount of the charge
     * @param currency  currency of the charge
     * @param token token (should either be a source token, or a customer identifier)
{'fraction_non_alphanumeric': 0.08558721000120206, 'fraction_numerical': 0.002163721601153985, 'mean_word_length': 2.8060384263494966, 'pattern_counts': {'":': 0, '<': 9, '<?xml version=': 0, '>': 11, 'https://': 2, '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': '424067', 'n_tokens_mistral': 2288, 'n_tokens_neox': 2195, 'n_words': 687}