Terminal showing ReSubScription:{} when using LiveQuery in parse_server_sdk_flutter - flutter

I followed all steps in documentation, but this function never gets called:
subscription.on(LiveQueryEvent.create,
(value) {});
All I receive in terminal is this: "ReSubScription:{}".
I am trying to capture the event when one of my classes in the database gets a new record/entry.
If requested, I can arrange a demo codebase, but please help me get through this.
PS: I am calling this subscription.on() method in initState() method of a stateful widget, not in main().
UPDATE
I am sharing link of git repo of a minimal app to demonstrate what I did. Here is the link
Please see what have I done incorrect with livequery. Would be grateful for any pointers/guidance.
UPDATE 2nd
Please note, I've hardcoded adminId (objectId of admin logged in). Check TODO plz.
My Testing procedure:
Create a user from backend database manually using Parse Dashboard. Plz Keep username = email.
Open app. Click admin button. Go to AdminLogin page and enter your email and password.
If you are successful, app will navigate to next white screen. This confirms that auth was done successfully.
Open the app again. Click user button. Go to UserForm.
Enter name and hit subscriber button. This will create a new class in Database by the name "Subscribers" and add columns "adminId" and "name"
(plz hardcode the adminId in code bcoz you already know it)
Now open the app again and go to admin and login again to move to control panel (white screen).
Wait for the back4app to send trigger/callback. (which shows ReSubScription:{}).

The problem is related to the code below:
final ParseObject object = ParseObject('Subscribers');
final response = await object.create();
if (response.success && response.count > 0) {
final ParseObject record = response.results[0];
record.set('name', name);
record.set('adminId', adminId);
await record.save();
}
Note that first you create the object with no adminId and that's why your event is not triggered. You then set the adminId and update the object. In that moment, your enter event should be triggered. Please listen to all different events (create, enter, update, leave, delete) and you will see it happening.

Related

Flutter oAuth : how to get started with OAuth and Stripe connect

I am trying to implement stripe connect in my flutter app. Here are the steps I need to implement. Can anyone please navigate me on how I could achieve this in Flutter?
I am able to create a button with the endpointUrl but that's all..
Thanks
I found out this myself using firebase cloud functions:
first you create an https function in the firebase cloud function
then you add the link created by the function to your stripe dashboard
then you write the following logic to your function
obtain the the authorisation code
fetch data from stripe
save the response somewhere (in my case in realtime database)
Here is the function
exports.connectStripeStandardAccount = functions.https.onRequest((req, res) => {
let authCode = req.query.code;
return stripe.oauth.token({
grant_type: 'authorization_code',
code: authCode,
}).then(async response => {
await admin.database()
.ref(`/accounts/${authCode}`)
.set(response);
return res.send("Well done, account integration is completed. You can now close the window and go back to the app");
});
});
The answer selected is not completely correct:
If you dont assign the account_id to a user then it's of no use.
The only way to pass the user_id (fUser.uid) is to pass it using the state parameter.
exports.StripePI = functions.https.onRequest(async (req, res) => {
// console.log('accountIdq ' + req.query.error);
// console.log('accountIdq ' + req.query.state);
// return;
// if(!req.query.code)
// return res.send("An Error has occured please try again");
const response = await stripe.oauth.token({
grant_type: 'authorization_code',
code: req.query.code,
}).then(async response => {
var connected_account_id = response.stripe_user_id;
await admin.firestore().collection('Registration').doc(req.query.state)
.update({customer_id : connected_account_id});
return res.send("Well done, account integration is completed. You can now close the window and go back to the app");
});
});
If you want to create an in-app stripe connect account registration with flutter you will need these:
A server or service to complete the OAuth like Firebase Functions or Integromat (I used Integromat)
A link that will redirect to your app (I used Firebase Dynamic Link)
STEPS TO CREATE THE REGISTRATION FLOW
INTEGROMAT/FIREBASE FUNCTIONS SETUP
I decided to use Integromat instead of Firebase Functions because is easier to set up, doesn't need any code, and decreases my server load.
If you want to create it on Firebase Functions you will need to have a Blaze Plan
If you don't know it, Integromat will automate processes that you currently handle manually, via webhooks. It is not only capable of connecting apps (like GoogleCloud, Facebook, AWS...) but can also transfer and transform data.
Create a new scenario and add a Custom Webhook. Click on it and click on add, name it, and save it. It will now create a custom link to your webhook.
Close and click on the semi-sphere next to the webhook, to add the new module.
Select HTTP and Make a Request.
In the URL section insert https://connect.stripe.com/oauth/token.
Method POST.
Body Type Application/x-www-form-urlencoded.
Create now those fields :
Key client_secret - value your stripe client secret You can find it on your stripe dashboard. I advise you to first use the test mode and after that, change the value to the live key.
Key grant_type - value authorization_code
Key code - leave the value blank. We will add it later.
Save and close
For Firebase Functions you can create a new HTTPS function (I didn't test this)
var stripe = require("stripe")(*your stripe client secret*);
exports.connectStripeStandardAccount = functions.https.onRequest((req, res) =>{
let authCode = req.query.code;
return stripe.oauth.token({
grant_type: 'authorization_code',
code: authCode,
});
});
Remember to install stripe package npm install stripe
STRIPE SETUP
If you are in the test mode go to this link
If you are in the live mode go to this link
Go on the bottom and activate oAuth for standard accounts or for Express Account.
Click on Add URI and add the webhook link of Integromat that you created or the link related to your Firebase function.
If you used Firebase add this link https://us-central1-<project-id>.cloudfunctions.net/connectStripeStandardAccount
For Integromat you will need to create the structure. To do this click on Test OAuth, copy the link, and open it in incognito mode. Open your Integromat scenario and click on your webhook. Now click on Re-determine data structure.
Return to your stripe registration page and click on Ignore account form at the top.
Return on Integromat and select the HTTPS request, modify the field code, and insert the variable code (will open a dialog with all queries from the webhook). Confirm and save.
Now click on the play button and reopen the stripe registration link in incognito mode and click on Ignore account form. Return in Integromat and add a JSON module after the HTTPS request. In the JSON string insert the Data variable and save. Create a Webhook Response module after the JSON module.
In the status put 301, then click on Ok.
DEEP LINK SETUP
It's time to set up the redirect link that will return the user to our flutter app or on our website if the user hasn't it installed.
I used Firebase Dynamic Link You can follow this tutorial for set up.
Go to the dashboard and create a new Link prefix and a new dynamic link, remember to select to redirect your users to the right app.
Click on the three dots in your dynamic link row and click on Link Details. Copy the extended link.
Open Integromat and select the last module you created (Webhook Response). Click on Show advanced settings and on the Header add :
Key Location - value the extended dynamic link that you copied.
If you want your app to elaborate data from the stripe OAuth response you can modify the extended dynamic link by adding ? on the link parameter: link=https://test.page.link?stripe_user_id={{14.stripe_user_id}}
And select the variable parsed from the JSON module. Remember to click on the save icon to save your scenario.
On Firebase Functions you can do this when the function stripe.oauth.token finish (I didn't test it):
res.setHeader('Location', your dynamic link);
res.status(301).send();
Remember to deploy it.
FLUTTER APP SETUP
The code here is very simple. To initialize the connect account registration you only need to set up a button that will launch the stripe connect URL. You can use launch(url);
You can find that URL here. Remember to be logged in to your stripe account to get the right stripe client id. You can easily get it in the same section you added the webhook link in your stripe connect settings.
Delete &redirect_uri=https://sub2.example.com on the URL.
Now you can test your app and will see that when you complete your stripe connect registration/login you will be redirected to your app.
If you want to have an in-app web view you can use this package
To handle the response, you need to have installed the package firebase_dynamic_links
Set your Main widget Stateful and on the initState run the method getDynamic() :
void getDynamic() {
FirebaseDynamicLinks.instance.getInitialLink().then((value) {
if (value != null) {
_connect(value);
}
});
FirebaseDynamicLinks.instance.onLink(onSuccess: (value) async {
if (value != null) {
_connect(value);
}
}, onError: (error) async {
debugPrint('DynamicLinks onError $error');
});
}
void _connect(value) {
Uri deepLink = value.link;
print("Link :" + deepLink.path);
print("Query :" + deepLink.queryParameters.toString());
String stripeUserId = deepLink.queryParameters["stripe_user_id"];
}
You need to have both of them to handle dynamic links when your app is running and when it's closed.

PWA home screen "uninstall" DOM event

I am trying to keep track of whether a web app has been installed to the user's home-screen using a value in localStorage.
I know there is DOM event that fires when a web app has been installed into a user's home-screen, but is there an event for when it has been uninstalled?
The type of event I have in mind would ideally be scheduled in a manner similar to (and behave in a manner similar to) onunload. (ie. an uncancellable event that allows me to schedule some last bit of work before the app is destroyed)
eg:
window.addEventListener('appinstalled', function(e) {
console.log('onappinstalled', e)
localStorage.setItem('APP_INSTALLED', '1')
})
// given the above, is anything like the following possible?
window.addEventListener('appuninstalled', function(e) {
console.log('onappuninstalled', e)
localStorage.setItem('APP_INSTALLED', '0')
})
I realised that once a user has uninstalled the app from their home-screen, the browser will begin prompting to install the app to the home-screen, again, provided you have met the criteria.
So by using the onbeforeinstallprompt event, there is an opportunity to clear the 'APP_INSTALLED' key from localStorage, and perform other arbitrary work.
eg:
window.addEventListener('beforeinstallprompt', function(e) {
localStorage.removeItem('APP_INSTALLED')
})
Moreover, this localStorage key may have already been cleared if the user elected to delete all data associated with the app when uninstalling the app from their home-screen.

Firebase Auth: user profile changes are not synced to other devices?

Scenario:
I am logged in with Firebase Auth, using the email provider. I change my user's photoURL and displayName using this Swift code:
let changeRequest = Auth.auth().currentUser?.createProfileChangeRequest()
changeRequest?.photoURL = someURL
changeRequest?.displayName = someName
changeRequest?.commitChanges { (error) in
// ...
}
From then on, when I use Auth.auth().currentUser.photoURL and Auth.auth().currentUser.displayName to render the user's name and avatar, it all works as expected. No problem at all.
However, I was also logged in on another device, before I made the changes to photoURL and displayName. And on that device, the old user information is shown, even when killing and restarting the app. All of that while I am using the Auth.auth().addStateDidChangeListener API as well.
Only when I logout and log back in, is the user info refreshed. I guess it's using the locally cached data, but it's not fetching the fresh user info from the server or something?
Am I doing something wrong? Do I need to force a refresh when the app starts up or something?
Edit: I've tried again a few times and yeah it's 100% reproducible.
Log in on two devices. Output Auth.auth().currentUser.displayName somewhere on screen (or to the console).
On device A, change the displayName. When I refresh the UI, the new name is shown. When I restart the app, the new name is shown.
On device B, the old name is still shown, even after killing and restarting the app. Only when I logout and back in, is the new name finally shown.
In the end I created a new top level Users collection, where I am now storing the user profile data. And with a snapshot listener, updating info on one device also updates it on the others. Too bad this was necessary, but it works.

How to handle changes made from other devices logged in on the same account?

Let's say that the user is logged in on two phones.
On phone1, he goes to his profile page and changes setting1 but doesn't press 'Save', yet.
Meanhwile, the same user, on phone2, changes another setting, setting2 and saves.
During the call made to the database made on phone2, he presses the Save button on phone1.
Since phone1 doesn't know about the new changes made from phone2, if setting1 is dependent on setting2, it will mess things up.
How should one handle this scenario?
You need to fetch user record with help of FIRDataEventTypeChildChanged.
Whenever the change occur on firebase databases your block/closure for observer will be called and you can change that particular values.
For e.g.:
// Listen for change comments in the Firebase database
yourRef.observe(.childChanged, with: { (snapshot) -> Void in
<update your values>
})

Meteor keep track of user sign ins

I would like to keep track of the amount of times that a user has logged into the application to either:
Remind them on their first visit to complete their profile
If profile is not complete, every X amount of visits remind user to complete
I'm not sure if the proper way to do this would be adding a key value to the users collection, or tie login to a new collection which counts up one each time a login occurs.
Is there a built in method to keep track of login successes?
Yup. You can even keep track of login failures.
From http://docs.meteor.com/#/full/accounts_onlogin:
Accounts.onLogin(function() {
// track successful login here. You can just use Meteor.user() to find out which user.
});
Accounts.onLoginFailure(function() {
// track failed login here.
});
There is even a "validate login attempt" method where you could potentially screen your users:
Accounts.validateLoginAttempt(func):
Accounts.validateLoginAttempt(function(loginInfo) {
// loginInfo.user returns a valid user object, if logged in successfully. Maybe tie this one to a collection, and do some checks etc.
// you can even use loginInfo.connection to see where the user has connected from (e.g. IP address.. perhaps)
return true; // return false if you want to 'bounce' this user.
});
Note: These can be done server-side only.