I'm trying to register a customer through Firebase Realtime-Database, but I'm needing help adding a stripeID to the customer reference through a Cloud Function. I can register a customer just fine, but how can I append my Cloud Function when I click the sign up action because I'm not getting anything in the Firebase Function Logs right now? Thank you.
Cloud Function
exports.createStripeCustomer = functions.https.onCall( async (data, context) => {
const email = data.email
const uid = context.auth.uid
console.log(uid)
if (uid === null) {
console.log('Illegal access attempt due to unauthenticated attempt.')
throw new functions.https.HttpsError('internal', 'Illegal access attempt')
}
return stripe.customers
.create({ email: email })
.then((customer) => {
return customer["id"];
})
.then((customerId) => {
admin.database().ref("customers").child(uid).update({
stripeId: customerId,
email: email,
id: uid
})
})
.catch((err) => {
console.log(err);
throw new functions.https.HttpsError(
"internal",
" Unable to create Stripe user : " + err
);
});
})
WelcomeActivity.kt
signUpButton.setOnClickListener {
val registerStub = findViewById<ViewStub>(R.id.registerStub)
registerStub.inflate()
performRegister()
}
private fun performRegister() {
// MARK: - Register ViewStub Properties
val registerViewStubProfileImageButton = findViewById<ImageButton>(R.id.addPhotoImageButton)
val registerViewStubFullnameTextView = findViewById<TextInputEditText>(R.id.fullnameInputTextView)
val registerViewStubUsernameTextView = findViewById<TextInputEditText>(R.id.usernameTextInputView)
val registerViewStubEmailTextView = findViewById<TextInputEditText>(R.id.emailInputTextView)
val registerViewStubPasswordTextView = findViewById<TextInputEditText>(R.id.passwordTextInputView)
val registerViewStubConfirmPasswordTextView = findViewById<TextInputEditText>(R.id.confirmPasswordTextInputView)
val registerViewStubCancelButton = findViewById<Button>(R.id.secondCancelButton)
val registerViewStubSignUpButton = findViewById<Button>(R.id.secondSignUpButton)
val fullnameText = TextUtils.isEmpty(registerViewStubFullnameTextView.text)
val usernameText = TextUtils.isEmpty(registerViewStubUsernameTextView.text)
val emailText = TextUtils.isEmpty(registerViewStubEmailTextView.text)
val passwordText = TextUtils.isEmpty(registerViewStubPasswordTextView.text)
val confirmPasswordText = TextUtils.isEmpty(registerViewStubConfirmPasswordTextView.text)
registerViewStubSignUpButton.setOnClickListener {
FirebaseAuth.getInstance().createUserWithEmailAndPassword(registerViewStubEmailTextView.text.toString(), registerViewStubPasswordTextView.text.toString())
.addOnCompleteListener {
if (!it.isSuccessful) return#addOnCompleteListener
// else if successful
uploadImageToFirebaseStorage()
}
.addOnFailureListener {
Toast.makeText(this, "Failed to create user: ${it.message}", Toast.LENGTH_SHORT).show()
}
}
}
private fun uploadImageToFirebaseStorage() {
if (selectedPhotoUri == null) return
val filename = UUID.randomUUID().toString()
val ref = FirebaseStorage.getInstance().getReference("/customer_profile_images/$filename")
ref.putFile(selectedPhotoUri!!)
.addOnSuccessListener {
ref.downloadUrl.addOnSuccessListener {
saveCustomerToFirebaseDatabase(it.toString())
}
}
}
private fun saveCustomerToFirebaseDatabase(profileImageUrl: String) {
val registerStub = findViewById<ViewStub>(R.id.registerStub)
val registerViewStubFullnameTextView = findViewById<TextInputEditText>(R.id.fullnameInputTextView)
val registerViewStubUsernameTextView = findViewById<TextInputEditText>(R.id.usernameTextInputView)
val registerViewStubEmailTextView = findViewById<TextInputEditText>(R.id.emailInputTextView)
val uid = FirebaseAuth.getInstance().uid ?: ""
val ref = FirebaseDatabase.getInstance().getReference("/customers/$uid")
val customer = Customer(uid, registerViewStubFullnameTextView.text.toString(), registerViewStubUsernameTextView.text.toString(),
registerViewStubEmailTextView.text.toString(), profileImageUrl)
ref.setValue(customer)
.addOnSuccessListener {
uploadStripeCustomer()
registerStub.alpha = 0f
finish()
}
}
private fun uploadStripeCustomer(): Task<String> {
val registerViewStubEmailTextView = findViewById<TextInputEditText>(R.id.emailInputTextView)
val data = hashMapOf(
"email" to registerViewStubEmailTextView
)
return functions
.getHttpsCallable("createStripeCustomer")
.call(data)
.continueWith { task ->
val result = task.result?.data as Map<*, *>
result["createStripeCustomer"] as String
}
}
Related
I am making a user registration with Authentication, but in turn, I insert these registrations in a collection of Firebase Realtime Database.
The structure of the database is as follows:
viewmodel of my register screen:
class RegisterViewModel : ViewModel() {
var email = mutableStateOf("")
var userName = mutableStateOf("")
var password = mutableStateOf("")
var status = mutableStateOf("1")
val state = mutableStateOf(RegisterState())
val user = FirebaseAuth.getInstance().currentUser
val loginPresenter = AuthPresenter()
fun registrar(email: String, password: String) {
viewModelScope.launch {
state.value = state.value.copy(isLoading = true)
if (
Common.isValidString(email.trim()) &&
Common.isValidPassword(password.trim()) &&
Common.isValidName(userName.value.trim()) &&
Common.isValidStatus(status.value)
) {
loginPresenter.signUp(email.trim(), password).addOnSuccessListener {
try {
val empleado = Empleado(
it.user!!.uid,
userName.value.trim(),
it.user!!.email!!,
status.value,
)
loginPresenter.createUserInDb(empleado).addOnSuccessListener {
state.value = state.value.copy(isSuccess = true)
}.addOnFailureListener { exception ->
state.value = state.value.copy(isError = exception.message)
}
} catch (e: Exception) {
state.value = state.value.copy(isError = e.message)
}
}.addOnFailureListener {
state.value = state.value.copy(isLoading = false)
state.value = state.value.copy(isError = it.message)
}
} else {
state.value = state.value.copy(isLoading = false)
state.value = state.value.copy(isError = "Rellena bien los campos")
}
}
}
fun dismiss() {
state.value = state.value.copy(isError = null)
}
And here the calls:
override suspend fun signUp(email: String, password: String): Task<AuthResult> {
return mAuth.createUserWithEmailAndPassword(email, password)
}
override fun createUserInDb(user: Empleado): Task<Void> {
return usersRef.child(user.uid!!).setValue(user.toMap())
}
First of all, the collection is: "employees"
and the document fields are:
.uid
.userName
.e-mail
.status
What I want to do is the following;
If there is no document in the "employees" collection;
The status field of the document to be inserted takes a value of 38. But if a document already exists in the collection, it takes the value of 1
As you can see in the picture, the documents in the person collection refer to the statistics collection.
I can pull this data like this
PersonRepository
override fun getPersonsFromFirestore(): Flow<Response<List<Person>>> = callbackFlow {
val snapshotListener =
personsCollection.addSnapshotListener { snapshot, e ->
val response = if (snapshot != null) {
val personList = snapshot.toObjects(Person::class.java)
Response.Success(personList)
} else {
throw Error(e?.message ?: e.toString())
}
trySend(response).isSuccess
}
awaitClose {
snapshotListener.remove()
}
}
Model
data class Person(
val id: Int=0,
val name: String="",
val surname: String="",
val image_url: String="",
val biography: String="",
val team: String="",
val statistics: DocumentReference? = null,
var personStatistics: PersonStatistics? = null
)
How can I convert Document Reference to object here?
I tried this first
override fun getPersonsFromFirestore(): Flow<Response<List<Person>>> = callbackFlow {
val snapshotListener =
personsCollection.addSnapshotListener { snapshot, e ->
val response = if (snapshot != null) {
val personList = mutableStateListOf<Person>()
snapshot.onEach {
val person = it.toObject(Person::class.java)
person.statistics!!.get().addOnSuccessListener {
val personStatistics = it.toObject(PersonStatistics::class.java)
person.personStatistics = personStatistics
}
personList.add(person)
}
//val personList = snapshot.toObjects(Person::class.java)
Response.Success(personList)
} else {
throw Error(e?.message ?: e.toString())
}
trySend(response).isSuccess
}
awaitClose {
snapshotListener.remove()
}
}
but in this approach Person Statistics comes first as null. It is added later. How can I bring them all at once? Or is there another better way?
Okey, This is how I solved it,
override fun getPersonsFromFirestore(): Flow<Response<List<Person>>> = callbackFlow {
val snapshotListener =
personsCollection.addSnapshotListener { snapshot, e ->
val response = if (snapshot != null) {
val personList = mutableStateListOf<Person>()
snapshot.onEach {
val person = it.toObject(Person::class.java)
val statistics = it.data["statistics"] as DocumentReference
statistics.addSnapshotListener { value, error ->
if (value!=null){
person.personStatistics = value.toObject(PersonStatistics::class.java)
personList.add(person)
}else{
throw Error(error?.message ?: error.toString())
}
}
}
Response.Success(personList)
} else {
throw Error(e?.message ?: e.toString())
}
trySend(response).isSuccess
}
awaitClose {
snapshotListener.remove()
}
}
this is the chat functionality on my app but the messages aren't appearing on my app although it is getting updated in the firebase. when I hardcoded the values it is working. this is the conversation activity. I've used a chat fragment and adapter as well. But the messages are just not getting posted on the app. any alternative solutions or a solution for this would be nice.
private val firebaseDB = FirebaseFirestore.getInstance()
private val userId = FirebaseAuth.getInstance().currentUser?.uid
private val conversationAdapter = ConversationAdapter(arrayListOf(), userId)
private var chatId: String? = null
private var imageUrl: String? = null
private var otherUserId: String? = null
private var chatName: String? = null
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_conversation)
chatId = intent.extras.getString(PARAM_CHAT_ID)
imageUrl = intent.extras.getString(PARAM_IMAGE_URL)
chatName = intent.extras.getString(chatName)
otherUserId = intent.extras.getString(PARAM_OTHER_USER_ID)
if (chatId.isNullOrEmpty() || userId.isNullOrEmpty()) {
Toast.makeText(this, "chat room error", Toast.LENGTH_LONG).show()
finish()
}
topNameTV.text = chatName
populateImage(this, imageUrl, topPhotoIV, R.drawable.default_user)
messagesRV.apply {
setHasFixedSize(false)
layoutManager = LinearLayoutManager(context)
adapter = conversationAdapter
}
firebaseDB.collection(DATA_CHATS)
.document(chatId!!)
.collection(DATA_CHAT_MESSAGES)
.orderBy(DATA_CHAT_MESSAGE_TIME)
.addSnapshotListener{ querySnapshot, firebaseFirestoreException ->
if(firebaseFirestoreException != null){
firebaseFirestoreException.printStackTrace()
return#addSnapshotListener
}else{
if (querySnapshot != null){
for(change in querySnapshot.documentChanges){
when(change.type){
DocumentChange.Type.ADDED -> {
val message = change.document.toObject(Convo::class.java)
if(message != null){
conversationAdapter.addMessage(message)
messagesRV.post {
messagesRV.smoothScrollToPosition(conversationAdapter.itemCount -1)
}
}
}
}
}
}
}
}
}
fun onSend(v: View) {
if (!messageET.text.isNullOrEmpty()){
val message = Convo(userId, messageET.text.toString(), System.currentTimeMillis())
firebaseDB.collection(DATA_CHATS).document(chatId!!)
.collection(DATA_CHAT_MESSAGES)
.document()
.set(message)
messageET.setText("",TextView.BufferType.EDITABLE)
}
}
companion object {
private val PARAM_CHAT_ID = "Chat id"
private val PARAM_IMAGE_URL = "Image url"
private val PARAM_OTHER_USER_ID = "Other user id"
private val PARAM_CHAT_NAME = "Chat name"
fun newIntent(context: Context?, chatId: String?, imageUrl: String?, otherUserId: String?
chatName: String?): Intent{
val intent = Intent(context,ConversationActivity::class.java)
intent.putExtra(PARAM_CHAT_ID,chatId)
intent.putExtra(PARAM_IMAGE_URL, imageUrl)
intent.putExtra(PARAM_OTHER_USER_ID, otherUserId)
intent.putExtra(PARAM_CHAT_NAME, chatName)
return intent
}
}
}
When I created JOIN Action and LOGIN Action on Android app,
Aa problem has occurred.
Working with MVP pattern in LOGIN Action.
But the results on the logins aren't exactly what I want.
I'll show you the code.
class LoginModel {
var TAG = "LoginModel"
private var ID: String
private var PW: String
var resultTxt: String = ""
var auth: FirebaseAuth = FirebaseAuth.getInstance()
constructor(ID: String, PW: String) {
this.ID = ID
this.PW = PW
}
fun login(ID: String, PW: String) : String{
this.ID = ID
this.PW = PW
auth.signInWithEmailAndPassword(ID, PW)
.addOnCompleteListener { task ->
//
if (task.isSuccessful) {
val user = auth.currentUser
resultTxt = "Login Success"
} else {
resultTxt = "Login Failed"
}
}
return resultTxt
// I'd like to process the results based on the return.
// But it doesn't return the way I want it.
// I know it's related to asynchronous processing.
// So where should I put the callback function, and how should I write
// it?
}
}
Add a callback to your login function which get invoked after resultTxt has been set. Something along the following lines should work,
class LoginModel {
var TAG = "LoginModel"
private var ID: String
private var PW: String
var resultTxt: String = ""
var auth: FirebaseAuth = FirebaseAuth.getInstance()
constructor(ID: String, PW: String) {
this.ID = ID
this.PW = PW
}
fun login(ID: String, PW: String, callback: (String)->Unit) {
this.ID = ID
this.PW = PW
auth.signInWithEmailAndPassword(ID, PW)
.addOnCompleteListener { task ->
//
if (task.isSuccessful) {
val user = auth.currentUser
resultTxt = "Login Success"
} else {
resultTxt = "Login Failed"
}
//The callback get's invoked with your expected result value.
callback.invoke(resultTxt)
}
//Don't return here
//return resultTxt
// I'd like to process the results based on the return.
// But it doesn't return the way I want it.
// I know it's related to asynchronous processing.
// So where should I put the callback function, and how should I write
// it?
}
}
You can then call the method using,
login(id,password) { result ->
//Do what you want with the result here
}
fun login(ID: String, PW: String, callback:(String) -> Unit) {
this.ID = ID
this.PW = PW
auth.signInWithEmailAndPassword(ID, PW)
.addOnCompleteListener { task ->
if (task.isSuccessful) {
val user = auth.currentUser
resultTxt = "Login Success"
} else {
resultTxt = "Login Failed"
}
callback.invoke(resultTxt)
}
}
try this as a callback, it will return the value of resultTxt after it has executed.
Then, when you call the login method:
login(ID,PW){ result ->
//here, result is the value of the callback
}
ALTERNATIVELY
You can return the result and user of the call in a callback, like this:
fun login(ID: String, PW: String, callback:(Boolean, User?) -> Unit) {
this.ID = ID
this.PW = PW
auth.signInWithEmailAndPassword(ID, PW)
.addOnCompleteListener { task ->
if (task.isSuccessful) {
callback.invoke(true, auth.currentUser)
} else {
callback.invoke(false, null)
}
}
}
Then you can use it like this :
Login(id, password){ result: Boolean, user: User? ->
if(result){
//the result is successful
user?.let{ authUser ->
//here, authUser is your user
}
} else{
//the result was not successful
}
}
I'm trying to get the user info with this code but is not showing on the activity
The profile picture and the name are not creating a new user on the base
What am I missing?
Does anyone had coded this using Kotlin?
private fun handleFacebookAccessToken(token: AccessToken) {
Log.d(TAG, "handleFacebookAccessToken:" + token)
val credential = FacebookAuthProvider.getCredential(token.token)
App.currentAuth.signInWithCredential(credential)
.addOnCompleteListener(this) { Log.d(TAG, "signInWithCredential:success") }
.addOnSuccessListener(this) { authResult ->
if (authResult != null) {
val firebaseUser = authResult.user
if (App.database_table_users.child(firebaseUser.uid) == null) {
var facebookId = ""
firebaseUser.providerData
.filter { it.providerId == FacebookAuthProvider.PROVIDER_ID }
.forEach { facebookId = it.uid }
val photoUrl = "https://graph.facebook.com/$facebookId/picture?width=1024&height=1024"
App.database_table_users.child(firebaseUser.uid).setValue(
User(firebaseUser.uid,
firebaseUser.email.orEmpty(),
firebaseUser.displayName.orEmpty(),
photoUrl,
false
)
)
}
}
}
.addOnFailureListener(this) { ex ->
if (ex is FirebaseAuthUserCollisionException) {
LoginManager.getInstance().logOut()
val ad = AlertDialog.Builder(this#LoginActivity)
ad.setMessage(getString(R.string.auth_user_collision))
ad.setPositiveButton(getString(R.string.ok), null)
ad.show()
} else {
ex.printStackTrace()
}
}
}
You must use FirebaseAuth.getInstance() instead of App.currentAuth.
For example;
val mAuth = FirebaseAuth.getInstance()
val credential = FacebookAuthProvider.getCredential(token)
mAuth.signInWithCredential(credential)
.addOnCompleteListener(this) { task ->
if (task.isSuccessful) {
val user = mAuth.currentUser
} else {
task.exception?.printStackTrace()
}
}
Try This it's work for me
private fun loginWithFaceBook()
{
LoginManager.getInstance().registerCallback(callbackManager, facebookCallBack)
LoginManager.getInstance().logInWithReadPermissions(this, Arrays.asList("public_profile","email"))
}
private val facebookCallBack = object : FacebookCallback<LoginResult> {
override fun onSuccess(result: LoginResult?) {
val graphRequest = GraphRequest.newMeRequest(result?.accessToken) { _, response ->
val graphObject = response.jsonObject
val id = if(graphObject.has("id")) graphObject.getString("id") else null
val email = if(graphObject.has("email")) graphObject.getString("email") else null
val firstName = if(graphObject.has("first_name")) graphObject.getString("first_name") else null
val lastName = if(graphObject.has("last_name")) graphObject.getString("last_name") else null
val photoUrl = if(graphObject.has("picture")) {
val picture : JSONObject = graphObject.getJSONObject("picture")
if(picture.has("data") && picture.has("url") && picture.getString("url").isNotBlank()) {
picture.getString("url")
}
else
null
}
else
val bundle = Bundle()
bundle.putString("fields", "id,first_name,last_name,name,picture,email,gender,birthday,link")
graphRequest.parameters = bundle
graphRequest.executeAsync()
}
override fun onError(error: FacebookException) {
when{
error.message != null -> showSnackbar(error.message.toString())
}
}
override fun onCancel() {
}
}