why can't create user using stream chat api in flutter? - flutter

I'm trying to create a chat screen in my flutter application using Stream chat API. the problem is when I try to create a channel with two users it shows that the users are not created even though I have created them:
E/flutter ( 4695): [ERROR:flutter/lib/ui/ui_dart_state.cc(209)] Unhandled Exception:
StreamChatNetworkError(code: 4, message: GetOrCreateChannel failed with error: "The following
users are involved in channel create operation, but don't exist: [hasan11 mohammed11]. Please
create the user objects before setting up the channel.", statusCode: 400, data:
ErrorResponse(code: 4, message: GetOrCreateChannel failed with error: "The following users are
involved in channel create operation, but don't exist: [hasan11 mohammed11]. Please create the
user objects before setting up the channel.", statusCode: 400, moreInfo:
https://getstream.io/chat/docs/api_errors_response))
here is my dart code for initializing the channel and the users:
onPressed () {
await streamAPI.initUser(client,
username: 'hasan',
id: Config.hasanID,
token: Config.hasanToken);
final channel = await streamAPI.createChannel(
client, 'messaging', 'sample', [Config.hasanID, Config.mohammedID]);
Navigator.of(context).push(
MaterialPageRoute(
builder: (context) =>
chat(client: client, channel: channel)));
}
StreamAPI.dart code:
import 'package:flutter/cupertino.dart';
import 'package:stream_chat_flutter/stream_chat_flutter.dart';
class streamAPI {
static Future initUser(
StreamChatClient client, {
#required String username,
#required String id,
#required String token
}) async {
final user = User(
id: id,
extraData: {
'name': username
}
);
await client.connectUser(user, token);
}
static Future<Channel> createChannel(
StreamChatClient client,
#required String type,
#required String id,
List<String> idMembers
) async {
final channel = client.channel(type, id: id, extraData: {
'name': 'channel1',
'members': idMembers
});
await channel.create();
channel.watch();
return channel;
}
}
Can anyone help me please?

Make sure that these users are created on the Stream backend. In your Stream dashboard, go to the Explorer -> users section, and you should see a list of all your users. Ensure the IDs match what you have in your code.
Stream Dashboard Example
Take note you don't need to call both create and watch, as watch will automatically create the channel.
If you're using the Stream Chat UI or Core components, you don't even need to call watch yourself, then you only need to call create.
I recommend taking a look at the Flutter tutorial page if you're still stuck: https://getstream.io/chat/flutter/tutorial/
Or the Stream Flutter YouTube Playlist: https://www.youtube.com/watch?v=pO_MOJRqYlk&list=PLNBhvhkAJG6t-BxkRAnSqa67lm5C1mpKk

Related

How to use Flutter Reactive BLE to send a UUID to a Bluetooth device and save response to string

I have been trying to figure out the Flutter Reactive BLE dart library. I have went through the Github example app and got when I want to work. I am wondering if there is an easier way to do what I am doing.
I have tried messing around with the readCharacterisitc but I have had no luck. I don't think I am connecting to the device properly.
final characteristic = QualifiedCharacteristic(serviceId: serviceUuid, characteristicId: characteristicUuid, deviceId: foundDeviceId);
final response = await flutterReactiveBle.readCharacteristic(characteristic);
The goal would be to have all relevant functions and variables to connect to the BLE device in one file so all I have to do is 1 line and get my response for my different UUIDs.
I am also very new to flutter and dart so if I am going about this wrong please let me know.
You will need to know the service UUIDs and characteristic UUIDs of that device.
First perform a scan and save the device id.
String? deviceId;
final flutterReactiveBle = FlutterReactiveBle();
flutterReactiveBle.scanForDevices(withServices: [serviceId], scanMode: ScanMode.lowLatency).listen((device) {
//save the device id to a variable
deviceId = device.id;
}, onError: () {
//code for handling error
});
Then use this device id to connect to that device.
You need to know the service ids and characteristic ids of that device.
flutterReactiveBle.connectToDevice(
id: deviceId,
servicesWithCharacteristicsToDiscover: {serviceId: [charId1, charId2]},
connectionTimeout: const Duration(seconds: 2),
).listen((connectionState) {
if (connectionState.connectionState == DeviceConnectionState.connected) {
// send the data
final characteristic = QualifiedCharacteristic(serviceId: serviceUuid,
characteristicId: charId1, deviceId: deviceId);
var response = await flutterReactiveBle.writeCharacteristicWithResponse(characteristic, value: [0x00]);
}
}, onError: (Object error) {
// Handle a possible error
});
Please note that in many cases, you will get the response on another characteristic UUID. So you will have to listen to that characteristic UUID to get the response.

How to set user Id and propeties in Firebase Analytics - Flutter

Goal : To save user ID and their properties, as he/she interacts with the flutter application.
Problem : Events are getting logged but i cant see user id and properties. I noticed it initially (that user id and properties arre not being logged) while working in debug mode, and then I also waited for 24-48 hours to check in the dashboard but no details for userId.
Documentation link : https://firebase.google.com/docs/analytics/userid#dart
and Yes the properties that I am trying to save in analytics, I have defined them in Custom definitions under User scope.
Code :
import 'package:firebase_analytics/firebase_analytics.dart';
class AnalyticsClass {
static final AnalyticsClass _singleton = AnalyticsClass._internal();
late FirebaseAnalytics fa = FirebaseAnalytics.instance;
factory AnalyticsClass() {
return _singleton;
}
AnalyticsClass._internal();
buttonTap(id, name) async {
await fa.logEvent(name: 'button_tap');
}
setUser(String id, name) async {
await fa.setUserId(id: id);
await fa.setUserProperty(name: 'referral', value: "test new : $name");
}
resetUser() async {
await fa.setUserId(id: null);
await fa.setUserProperty(name: 'referral', value: null);
}
}
If you're using the setUserId() in Firebase, this does not show up in the Analytics reports due to privacy concerns. What you can do is to export your data to BigQuery. This will allow you to query your raw data as well as build custom reports via Data Studio. You may also consider using the User explorer in Google Analytics Dashboard which will help you gain more insight on the behavior of your individual users.

Flutter authentication with email and password without using Firebase

Is it possible to achive authentication with email and password in flutter without using firebase? I have searched around Stackoverflow and internet in general and found nothing about this.
I am creating a simple authentication class this is what I have done at the moment:
class User {
bool isAuthenticated = false;
late String userid;
late String username;
late String email;
late DateTime expireDate; // this variable is used to make the user re-authenticate when today is expireDate
User(bool isAuthenticated, String userid, String username, String email) {
this.isAuthenticated = isAuthenticated;
this.userid = userid;
this.username = username;
this.email = email;
this.expireDate = new DateTime.now().add(new Duration(days: 30));
}
}
class Authentication {
Future<User> signin(String email, String password) {}
void signup(String username, String email, String password) {}
}
EDIT #1: I know how to setup a cookie/token based authentication server I have my own repos on that topic: cookie authentication, token authentication but I don't know how to handle the tokens/cookies in flutter.
This answer is based of #edit1. Since you mentioned that you already know how to set up tokens on the server side you're half way done. Here's a few assumptions I'm making, you already know js/php and worked with JSON output, The database already has a column and table that keeps track of sessions and user_id.
Since you know how Cookies are built this should be relatively easy cause i built it around similar architecture. We has to use the local memory that app's provide access to. There are two packages in flutter that allow u to do this, you can use either:
shared_preferences package link
flutter_secure_storage package link
The main difference is if you want to store 'tokens' or data you want secure you would obviously use flutter_secure_storage. I'm going to use this for code example. And yes the data is saved even after the app is closed.
Setting up Tokens(flutter):
Setting up User Class
When using firebase we generally take for granted the user class that comes with flutter_auth but that is basically what we have to build. A user class with all the data u want to store and then a function called authenticate.
class AppUser{
final _storage = new FlutterSecureStorage();
//below class is mentioned in the next part
AuthApi api = new AuthApi();
//constructor
AppUser(){
//ur data;
};
Future<bool> authenticate(email, password) async {
//this is the api mentioned in next part
http.Response res = await api.login(email, password);
Map<String, dynamic> jsonRes = jsonDecode(res.body);
if (jsonRes["error"]) {
return false;
}
_setToken(jsonRes["token"]);
_setUID(jsonRes["user-id"].toString());
_setAuthState(true);
return true;
}
Future<void> _setToken(String val) async {
//how to write to safe_storage
await _storage.write(key: 'token', value: val);
}
Future<void> _setUID(String val) async {
await _storage.write(key: 'user_id', value: val);
}
//you can stream this or use it in a wrapper to help navigate
Future<bool> isAuthenticated() async {
bool authState = await _getAuthState();
return authState;
}
Future<void> _getAuthState() async {
//how to read from safe_storage u can use the same to read token later just replace 'state' with 'token'
String myState = (await _storage.read(key: 'state')).toString();
//returns boolean true or false
return myState.toLowerCase() == 'true';
}
Future<void> _setAuthState(bool liveAuthState) async {
await _storage.write(key: 'state', value: liveAuthState.toString());
}
}
and assuming ur going to authenticate on a button press so it would look like
onPressed(){
AuthUser user = new AuthUser();
if(user.authenticate(email, password)){
//if logged in. Prolly call Navigator.
}else{
//handle error
}
}
Setting up api calls
Oka so this is calling a Node express API, and the json output looks like
//if successful
{"status":200, "error": false, "token": "sha256token", "user-id": "uid"}
we need to create a class that will give us an output for making this call hence the AuthApi class
class AuthApi {
//this is the login api and it returns the above JSON
Future<http.Response> login(String email, String password){
return http.post(
Uri.parse(ip + '/api/auth/login'),
headers: <String, String>{
'Content-Type': 'application/json',
},
body: jsonEncode(<String, String>{
"email": email,
"password": password,
}),
);
}
}
Thank you for clarifying what u needed, it helped answer better.
You can use Nodejs & express to create your own API and MongoDB or any other DB to act as a persistent DB. I am attaching my github repo link which has minimum code required to setup a email/password auth in mongodb
Github
EDIT :
I have little to no idea about sessions but for tokens there are packages in pub.dev which lets you decode the tokens. jwt-decoder.
You can check the expiry time of the token using this package and for storing them you can use secure_storage
I had a look at your token authentication repo. I would suggest you to verify the token when you get them and not just blindly trust them.
Yes it is Totally possible to create Authentication without Firebase, but it becomes a-lot more difficult and there are multiple solutions.
What firebase provides:
Server space with no down time
Complete set of Api's including authentication with various methods
Strong security(built by google)
Ease of use and setup with great documentation
The reason I bring these up is cause the alternative ur looking for is very difficult for a programer who's relatively new and can feel like you are building multiple applications at a time. It's definitely a learning curve. Also I'm assuming u don't just want local authentication cause thats kinda pointless.
Creating ur own backend involves:
Setting up a server(usually ubuntu)(and either on a raspi or a host like amazon, digital ocean, etc)
Setting up a database with tables(mysql, sql, mongoDB)
Creating communication API's (php, Node.js)
So here's what i'd recommend for getting into backend dev,
use LAMP architecture : Linux, Apache, MySQL, PHP
Setting up Lamp isn't too hard heres a link i followed:
https://www.digitalocean.com/community/tutorials/how-to-install-linux-apache-mysql-php-lamp-stack-on-ubuntu-16-04
After u set up ur back end, then u have to create api calls from flutter.
The call (if u created an auth.php where people can login) would look something like:
http://ip:8080/auth.php?email="example#gmail.com"&pass="123456"
I understand why you feel like you didn't find solutions, i was there too but there are tons,LAMP is one of the more easier ones. If u are still interested i'd recommend checking out System Design courses.

image picker path for stripe readfilesync Flutter Web

I'm using the file_picker package for flutter https://pub.dev/packages/file_picker
I have read many times that because you can’t access paths on web browsers, you need to use the bytes property, e.g.
FilePickerResult result = await FilePicker.platform.pickFiles();
if(result != null) {
var path = print(result.files.single.path); // this will return null
var bytes = print(result.files.singe.bytes); // this will return a Uint8List of bytes
} else {
// User canceled the picker
}
But I have to upload the images my users select from their devices via the web (so for all types of devices) to my Stripe Connect API in order for them to have a validated identity_document when they register. The bytes Uint8List will throw an error from firebase, here is my code:
export const uploadIdentityFront = async (uid: any, identityFront: any) => {
const fp = fs.readFileSync(identityFront);
const frontIdentity = await stripe.files.create({
file: {
data: fp,
name: 'identityFront.jpg',
type: 'application/octet-stream',
},
purpose: 'identity_document',
});
await updateId(uid, { frontIdentityFileId: frontIdentity.id })
return frontIdentity;
}
The error thrown:
[firebase_functions/unknown] TypeError [ERR_INVALID_ARG_TYPE]: The "path" argument must be of type string or an instance of Buffer or URL. Received an instance of Array
I will need to send stripe an image document via the file system's readFileSync property in order to do this, but with Flutter Web not being able to print the path for the image chosen by the user, I am stuck on how to resolve this issue
I use this code to send bytes to my server, which uses stream to send. You can use http package to send streams.
var request = http.MultipartRequest(
'POST',
Uri.parse('_url'),
);
request.files.add(
http.MultipartFile.fromBytes(
'identityFront', //name of field which you receive in api
bytes, // bytes
filename: 'identityFront.jpg', // optional name
//contentType: content, optional media Type
));
request.fields.addEntries([
MapEntry('uid', 'uid_value_in_String_Type'),
]);
await request.send();
I finally solved it. For anyone trying to upload a file to Stripe via flutter web, don't create a fs.readFileSync in your backend server side code. Instead, remove it and upload a file like this:
export const uploadIdentityFront = async (uid: any, identityFront: any) => {
const frontIdentity = await stripe.files.create({
file: {
data: identityFront,
name: 'identityFront.jpg',
type: 'image/jpg',
},
purpose: 'identity_document',
});
await updateId(uid, { frontIdentityFileId: frontIdentity.id })
return frontIdentity;
}
This way, you can upload the file via the file_picker package and uploading it as a picker.file.first.bytes. But don't wrap it in a string - send it just like this as a callable function in firebase functions:
await uploadFrontPassport.call(
<dynamic, dynamic>{'identityFront':picked.files.first.bytes}
);

App login with google account and firebase integration

I'm developping a crowfunding application with flutter.
The first step I've done (after firebase integration to my app) is the login page (login with google) and it works correctly.
In the firebase dashboard I can see the number of users logged and their activity, but I can't see their details (eg. their name, surname and google mail).
Is it possibile to track these data in firebase dashboard? If it is yes, how can I do it?
Thanks
To save other details, for example: name, age, gender.
First you need to create a Model for this User.
In the sign up process, you need to save this information using Firestore.
I will put below a code for example:
In the example, it is an Uber style app and I want to retrieve the user's name mainly and I want to know its type, whether it is a driver or a passenger.
Sign up Screen
I am using the form of registration only with email / password, but it makes no difference, after registering, see the code below, in the ".then", is where the data is passed to the Firestore
void cadastrarUser(Usuario usuario) {
FirebaseAuth auth = FirebaseAuth.instance;
FirebaseFirestore db = FirebaseFirestore.instance;
auth
.createUserWithEmailAndPassword(
email: usuario.email, password: usuario.senha)
.then((firebaseUser) {
db.collection("usuarios").doc(firebaseUser.user.uid).set(usuario.toMap());
switch (usuario.typeUser) {
case "motorista":
Get.toNamed("/painel-motorista");
break;
case "passageiro":
Get.toNamed("/painel-passageiro");
break;
}
}).catchError((error) {
errorMessage =
"Erro ao cadastrar usuário, verifique os campos e tente novamnte!";
});
This method receives a User instance, to transfer this data from the User instance, you need to convert this object into a "map".
In the model, you need create a method for this conversion, see the example below:
class Usuario {
String _idUser;
String _nome;
String _email;
String _senha;
String _typeUser;
Usuario();
String checkTypeUser(bool typeUser) {
return typeUser ? "motorista" : "passageiro";
}
Map<String, dynamic> toMap() {
Map<String, dynamic> map = {
"nome": this.nome,
"email": this.email,
"typeUser": this.typeUser
};
return map;
}