Storing a data permanent with Flutter - firebase

I am developing an app with Flutter and Firebase.
I want to store the _id with SharedPreferences permanently.
Therefore, i looked after it, but my code doesnt work at all. It always throws the error:
type 'Future' is not a subtype of type 'String'
Here is my code:
class Profile with ChangeNotifier {
String _id;
void setName(String name) {
const url =
'myurl';
http
.post(url, body: json.encode({'name': name, 'description': name}))
.then((response) {
_id = json.decode(response.body)['name'];
});
addID();
}
Future<void> updateName(String name, String id) async {
String url =
'myurl';
await http.patch(url,
body: json.encode({'name': 'Ein Titel', 'description': name}));
}
And here are my methods with the SharedPrefs:
String getID() {
return getIDOffline();
}
addID() async {
SharedPreferences prefs = await SharedPreferences.getInstance();
prefs.setString('id', _id);
}
getIDOffline() async {
SharedPreferences prefs = await SharedPreferences.getInstance();
//Return String
String stringValue = prefs.getString('id');
return stringValue;
}

You have use wrong method for return string so you have to change String getID() to Future<String> getID(). And you can use like this.
getValue()async{
String value = await getID();
}

When you use async always try to add also Future.
like :
Future<returnType> methodName() async { }
In your code try to change
String getID(){ } to Future<String>getID() async{ }

Related

Call to DB gets stuck on await (but works when called from a Blazor component)

When calling the method from the .cs file, the app gets stuck on the await line; but if I call it from the .razor it works flawlessy.
.cs
public AccountService(IUserData userData)
{
_userData = userData;
}
...
public async Task<bool> Validate(string userId, string password)
{
...
try
{
List<UserModel> users = new List<UserModel<();
users = await _userData.GetUsers();
//NEVER GETS HERE
return true;
}
catch (Exception ex)
{
return false;
}
...
}
.razor
#inject IUserData _db;
#code {
private List<UserModel> users;
...
protected override async Task OnInitializedAsync()
{
users = await _db.GetUsers();
}
...
UserData
public class UserData : IUserData
{
private readonly ISqlDataAccess _db;
public UserData(ISqlDataAccess db)
{
_db = db;
}
public Task<List<UserModel>> GetUsers()
{
string sql = "Select *from dbo.Users";
return _db.LoadData<UserModel, dynamic>(sql, new { });
}
...
}
IUserData
public interface IUserData
{
Task<List<UserModel>> GetUsers();
...
}
DBAccess
public async Task<List<T>> LoadData<T, U>(string sql, U parameters)
{
string connectionString = _config.GetConnectionString(ConnectionStringName);
using (IDbConnection connection = new SqlConnection(connectionString))
{
var data = await connection.QueryAsync<T>(sql, parameters); //I GET STUCK HERE
return data.ToList();
}
}
IDBAccess
Task<List<T>> LoadData<T, U>(string sql, U parameters);
PS
I updated this post https://stackoverflow.com/questions/68225154/implementing-an-interface-on-a-class-with-dependency-injection with this question, but sinced I had already marked it as answered I decided to make a new one
Your problem is how your code is calling the asynchronous method:
if (((AccountService)AccountService).Validate(user.UserCredentials, user.Password).Result)
The .Result may seem weird, but otherwise I get an error: can't convert ...Task to bool
The proper solution for this error is to use await, not Result:
if (await ((AccountService)AccountService).Validate(user.UserCredentials, user.Password))
Using Result can cause deadlocks.

I want to get user id in a get function

Future<String> getCurrentUser() async {
final FirebaseUser user = await _auth.currentUser();
final uid = user.uid;
return uid;
}
I want to have user uid in the document but I cant get it .
Stream<List<RezervasyonListesi>> get rezervasonlarlistesi1 {
return rezervasyonCollectionRef
.document() // **In document I want refer to user uid ;**
.collection("rezerve")
.snapshots()
.map(_rezervasyonlistesifromsnap);
}
I tried this but didnt work
Stream<List<RezervasyonListesi>> get rezervasonlarlistesi {
getCurrentUser().then((value) {
return rezervasyonCollectionRef
.document(value)
.collection("rezerve")
.snapshots()
.map(_rezervasyonlistesifromsnap);
});
}
Stream<List< RezervasyonListesi>> is not a type of future because of that I cant use async in that function .Without ascyn how can I get my firebase user uid.
class of RezervasyonListesi
class RezervasyonListesi {
final String name;
final String address;
final String image;
final String rating;
final String description;
RezervasyonListesi(
{this.address, this.description, this.image, this.name, this.rating});
}
Try this.
Stream<List<RezervasyonListesi>> get rezervasonlarlistesi async*{
String currentUser = await getCurrentUser();
yield* rezervasyonCollectionRef.document(currentUser.uid).snapshots().map((snapshot){
return snapshot.data;
});
}

Firestore CollectionReference with dynamic Path doesn't work

i'm trying to query a firestore collection with a dynamic path (user specific), it works hardcoded, but not dynamic with a variable, someone know the issue and can help?
Thanks in advance
final CollectionReference addressCollection =
Firestore.instance.collection('users/r9qClctByGXinYAmB2MqQNctgd53/addresses');
works.
This not:
final CollectionReference addressCollection =
Firestore.instance.collection('users/$userId/addresses');
userId is = r9qClctByGXinYAmB2MqQNctgd53
Full FirestoreDatabase code:
class FirestoreDatabase {
final _service = FirestoreService.instance;
static String userId;
void setUserId(uid) {
userId = uid;
}
final CollectionReference addressCollection =
Firestore.instance.collection('users/$userId/addresses');
// Adresses List Stream
Stream<List<Address>> get addressesStream {
return addressCollection.snapshots().map(_addressListFromSnapshot);
}
List<Address> _addressListFromSnapshot(QuerySnapshot snapshot) {
return snapshot.documents.map((doc) {
return Address.fromMap(doc.data);
}).toList();
}
}

How can I get a value from firebase and and put it in a text in Flutter

I'm having a simple problem which is how to get specific values from database Firebase.
For example, I want to get the value of "name" and put it in text. How can I do that? Can you write a detailed code?
class _HomePageState extends State<HomePage> {
String myuid;
FirebaseUser currentUser;
// To get id
void _loadCurrentUser() {
FirebaseAuth.instance.currentUser().then((FirebaseUser user) {
setState(() { // call setState to rebuild the view
this.currentUser = user;
});
});
}
#override
void initState() {
super.initState();
_loadCurrentUser();
}
#override
Widget build(BuildContext context) {
myuid = currentUser.uid;
var getname;
Future<void> getName() async {
DocumentSnapshot ds =
await Firestore.instance.collection('users').document(myuid).get();
getname = ds.data['name'];
}
Try
String name;
Future<null> getName() async {
DocumentSnapshot document = await Firestore.instance.collection('users').document(FirebaseUser().uid).get();
name = document.data['name']
}
This is how you can get data from the Firestore Database Document once
val docRef = db.collection("users").document("mhPtwy..........")
docRef.get()
.addOnSuccessListener { document ->
if (document != null) {
Log.d(TAG, "DocumentSnapshot data: ${document.data}")
} else {
Log.d(TAG, "No such document")
}
}
.addOnFailureListener { exception ->
Log.d(TAG, "get failed with ", exception)
}
This is a kind of cheeky way to get the data and store it in a variable
var name;
Future<void> getName(){
DocumentSnapshot ds = await
Firestore.instance.collection('users').document(uid).get();
name = ds.data['name']
}
then just throw that in your text field
Text(name);

how to revoke/invalidate/cancel old email confirmation token (identity)

i allow newly created users who know their password and isn't confirmed yet to change their registration email (as long as it's not registered in my database)
the problem is that if they changed the email, i generate new email confirmation token, but the old token could still validate them(the one i issue on registration), which pretty much could mean that people could use their registration mail at first, change it to some other mail they don't have access to, and validate from the old one, which is a big security hole for me to just leave
is there any way to remove/revoke the old token? (technically i could create a new user and delete the old one, the old token wouldn't work on new user, yet i think there should be a better solution for this)
I added the following properties to my ApplicationUser class
public class ApplicationUser : IdentityUser {
public string EmailConfirmationToken { get; set; }
public string ResetPasswordToken { get; set; }
}
This holds on to the confirmation token to be validated against when confirming email token.
I then added the following to my ApplicationUserManager which is a UserManager<ApplicationUser> derived class.
public override async System.Threading.Tasks.Task<string> GenerateEmailConfirmationTokenAsync(string userId) {
/* NOTE:
* The default UserTokenProvider generates tokens based on the users's SecurityStamp, so until that changes
* (like when the user's password changes), the tokens will always be the same, and remain valid.
* So if you want to simply invalidate old tokens, just call manager.UpdateSecurityStampAsync().
*/
//await base.UpdateSecurityStampAsync(userId);
var token = await base.GenerateEmailConfirmationTokenAsync(userId);
if (!string.IsNullOrEmpty(token)) {
var user = await FindByIdAsync(userId);
user.EmailConfirmationToken = token;
user.EmailConfirmed = false;
await UpdateAsync(user);
}
return token;
}
public override async System.Threading.Tasks.Task<string> GeneratePasswordResetTokenAsync(string userId) {
var token = await base.GeneratePasswordResetTokenAsync(userId);
if (!string.IsNullOrEmpty(token)) {
var x = await FindByIdAsync(userId);
x.ResetPasswordToken = token;
await UpdateAsync(x);
}
return token;
}
public override async System.Threading.Tasks.Task<IdentityResult> ConfirmEmailAsync(string userId, string token) {
var result = await base.ConfirmEmailAsync(userId, token);
if (result.Succeeded) {
var x = await FindByIdAsync(userId);
x.EmailConfirmationToken = null;
await UpdateAsync(x);
}
return result;
}
public override async System.Threading.Tasks.Task<IdentityResult> ResetPasswordAsync(string userId, string token, string newPassword) {
var result = await base.ResetPasswordAsync(userId, token, newPassword);
if (result.Succeeded) {
var x = await FindByIdAsync(userId);
x.ResetPasswordToken = null;
await UpdateAsync(x);
}
return result;
}
The following Extensions were added to be able to find the user based on their stored token.
public static class ApplicationUserManagerExtension {
public static Task<string> FindIdByEmailConfirmationTokenAsync(this UserManager<ApplicationUser> manager, string confirmationToken) {
string result = null;
ApplicationUser user = manager.Users.SingleOrDefault(u => u.EmailConfirmationToken != null && u.EmailConfirmationToken == confirmationToken);
if (user != null) {
result = user.Id;
}
return Task.FromResult(result);
}
public static Task<string> FindIdByResetPasswordTokenAsync(this UserManager<ApplicationUser> manager, string token) {
string result = null;
ApplicationUser user = manager.Users.SingleOrDefault(u => u.ResetPasswordToken != null && u.ResetPasswordToken == token);
if (user != null) {
result = user.Id;
}
return Task.FromResult(result);
}
}

Resources