JohnCoene / firebase

Google FIrebase for shiny
https://firebase.john-coene.com
GNU Affero General Public License v3.0
170 stars 26 forks source link

Stripe Extension for Firebase #43

Closed paladinic closed 1 year ago

paladinic commented 1 year ago

Hi,

Thanks to your library, I successfully hosted a shiny app in Google Cloud Run, using Firebase for authentication. I am now trying to use the Stripe Extension provided through Firebase. I followed the steps outlined here, adding the javascript functions in the app's .js file, but the app seems to be ignoring this. Any ideas on how the extension could be leveraged with your library?

paladinic commented 1 year ago

So far, to integrate firebase, the R library, and Stripe, the solution I'm using is summarised in the app below. I still need to add the logic of allowing the user to pay for a subscription but I think I will simply use the "payment link"/"billing portal" that stripe provides. I would be very much open to and grateful for suggestions, feedback, etc..

library(shiny)
library(magrittr)
library(firebase)
library(httr)

user_has_plan = function(email){
  res = GET(
    url = 'https://api.stripe.com/v1/customers', 
    query = list(email = email), 
    authenticate(
      user = 'sk_etc...',
      password = '')
    )
  return(content(res)$data %>% length() > 0)
}

ui <- fluidPage(
  useFirebase(),
  firebaseUIContainer(),
  reqSignin(actionButton("signout", "Sign out")),
  uiOutput("msg"),
  numericInput(inputId = 'n',label = 'n',value = 0),
  plotOutput("plot")
)

server <- function(input, output){
  f <- FirebaseUI$
    new("session")$
    set_providers(
      email = TRUE,
      yahoo = TRUE,
      google = TRUE,
      github = TRUE,
      twitter = TRUE,
      facebook = TRUE,
      microsoft = TRUE
    )$
    launch()

  output$plot <- renderPlot({
    f$req_sign_in() # require sign in
    plot(cars)
  })

  output$msg <- renderUI({
    f$req_sign_in() # require sign in
    uiOutput('test')
  })

  output$test = renderUI({
    user <- f$get_signed_in() # get logged in user info
    print(user$response$email)

    if(user_has_plan(user$response$email)){
      h1('User has plan')
    }else{
      h1('User has no plan')
    }
  })

  observeEvent(input$signout, {
    f$sign_out()
  })

}

shinyApp(ui, server)
JohnCoene commented 1 year ago

I have, in the past, done something custom to make the firebase package work with the firebase - stripe integration you discuss. Essentially need to use an old version of this package which you can find on the omics branch.

e.g.:

        db = firebase.firestore();

    db
        .collection('customers')
        .doc(firebase.auth().currentUser.uid)
        .get()
        .then((doc) => {
            let data = {
                href: window.location.href,
                id: doc.data().stripeId
            }
            Shiny.setInputValue(`stripeId`, data);
        });

    db
        .collection('customers')
        .doc(firebase.auth().currentUser.uid)
        .collection('subscriptions')
        .where('status', '==', 'active')
        .onSnapshot(async (snapshot) => {
            const doc = snapshot.docs[0];

            try {
                Shiny.setInputValue(
                    'permissions', 
                    { 
                        success: true,
                        response: doc.data() 
                    },
                    {priority: 'event'}
                );
            } catch (error) {
                Shiny.setInputValue(
                    'permissions', 
                    { 
                        success: false,
                        response: error
                    },
                    {priority: 'event'}
                );
            }
        }, (error) => {
            Shiny.setInputValue(
                'permissions', 
                { 
                    success: false,
                    response: error
                },
                {priority: 'event'}
            );
        });

I had to do something custom because I cannot, for now, properly integrate firestore with shiny in JavaScript. It's not technical difficulties but rather API design problems.

paladinic commented 1 year ago

Thank you @JohnCoene , I think I will stick to using directly the stripe API. I'll share the code if it starts looking good :).