From the two same lines, one is generating an error relative to FutureOrNull - dart

Thos are the two function from the same class I wrote: The first has the error:
A value of type 'Future<String?>' can't be returned by the 'onError' handler because it must be assignable to 'FutureOr'.
while the second is OK and I don't understand why.
Can you tell me please?
/// Creates or update the User collection
Future<String?> _createOrUpdateUser(User user) {
final email = user.email;
final nameFromEmail =
email!.substring(0, email.indexOf('#')).replaceAll(".", " ").trim();
return FirebaseFirestore.instance.collection('users').doc(user.uid).set({
'id': user.uid,
'screenName': '',
'displayName': user.displayName ?? nameFromEmail,
'photoUrl': user.photoURL,
'bio': '',
'darkMode': false,
'email': user.email,
}).then((_) {
debugPrint("User ${user.displayName} is created");
return null;
}).catchError((e) {
debugPrint(e.toString());
return Future<String?>.error(e); // <<<<< Error here: A value of type 'Future<String?>' can't be returned by the 'onError' handler because it must be assignable to 'FutureOr<Null>'.
});
}
Future<String?> _authUser(BuildContext context, LoginData data) {
debugPrint('Name: ${data.name}, Password: ${data.password}');
return auth
.signInWithEmailAndPassword(email: data.name, password: data.password)
.then((credential) {
try {
final user = credential.user;
if (user == null) {
return 'Password does not match';
} else {
_createOrUpdateUser(user);
// == Tell the app we just signed in
Provider.of<StateModel>(context, listen: false).signedIn = user;
return null;
}
} catch (e) {
return 'User not exists';
}
}).catchError((e) {
if (e.code == 'weak-password') {
debugPrint('The password provided is too weak.');
} else if (e.code == 'email-already-in-use') {
debugPrint('The account already exists for that email.');
} else {
debugPrint(e.toString());
}
return Future<String?>.error(e); // <<<<< No problem here
});
}

Related

Rxjs BehaviorSubject error handling when used with mergemap

I have the following code
#Injectable()
export class ReceptionService {
private generalInfoDataSrc$ = new BehaviorSubject<any>(null);
public generalInfoData = this.generalInfoDataSrc$.asObservable();
setGeneralInfo(dataSrc: GeneralInfoMModal) {
this.generalInfoDataSrc$.next(dataSrc);
}
}
From my component1 I will set the above as
OnSelect(patient: any) {
let generalInfo = new GeneralInfoMModal();
generalInfo.id = patient.id;
// some other code here
// this.recepService.setGeneralInfo(generalInfo);
}
// from component2
//
ngOnInit() { getPatientDetails() }
getPatientDetails() {
this.receptionService.generalInfoData.pipe(mergeMap(response => {
if (response && response.id) {
this.loading = true;
return this.receptionService.get('User/Get' + response.id, this.sourceobj);
} else {
return of(null);
}
}), takeUntil(this.unsubscribe$)).subscribe(response => {
this.patient = response;
this.loading = false;
}, error => {
this.loading = false;
// this.utility.showMsg('An error occurred while getting user.')
}, () => {
})
}
Every things works well. I keep on selecting a user thereby calling the User/Get api. But if in case if the api returns an error then error part is executed after which when there is a change in behaviorsubject(user is selected) it doesn't call the User/Get. Is there other way of handling errors with behaviorsubject or any other approach to handle the idea. How a behaviorsubject should be used in such a case.
If you are using the same behavior subject over and over again, and if there is an error, you need to set the behavior subject back to null, so that when the next user is set, it will get the latest value.
Try something like this:
getPatientDetails() {
this.receptionService.generalInfoData.pipe(mergeMap(response => {
if (response && response.id) {
this.loading = true;
return this.receptionService.get('User/Get' + response.id, this.sourceobj);
} else {
return of(null);
}
}), takeUntil(this.unsubscribe$)).subscribe(response => {
this.patient = response;
this.loading = false;
}, error => {
this.loading = false;
///////////////////////////////// ADD THIS LINE ///////////////////////
this.recepService.setGeneralInfo(null);
// this.utility.showMsg('An error occurred while getting user.')
}, () => {
})

Netlify functions with axios

I want to make my form submission happen server-side in order to not expose my API key. I plan to do this with netlify functions however I don't know how that would look with Axios. I've looked for examples on how to do this but I don't seem to find any. Could some help me I'm stuck as to what to put inside my the Netlify function? If anyone has worked with these two programs and could provide a hand that would be helpful here is my javascript with my submission function.
var form = document.querySelector("#user_form");
let reqHeaders = {
headers: {
Authorization: "Bearer",
}
}
let url = ""
let reqData = {
records: [
{
fields: null
}
]
}
let formData = {
firstName: "",
lastName: "",
email: ""
}
function logData(id, dataObj, value) {
dataObj[id] = value;
console.log(value)
}
function formMessg (id) {
document.querySelector(id).style.display = "block";
setTimeout(function(){
document.querySelector(id).style.display = "none";
form.reset();
}, 2500)
}
form.addEventListener("submit", function (e) {
e.preventDefault();
let spam = document.getElementById('spam').value;
try {
for(const data in formData){
if(formData[data] === "" || spam.length !== 0){
const error = new Error();
error.notVaild = true;
throw error;
}
}
reqData.records[0].fields = formData;
console.log(reqData);
axios.post(url, reqData, reqHeaders).then((res) => {
formMessg ('.success-messg');
form.style.display = "none";
})
.catch ((err) => {
throw err;
});
} catch (err){
if (err.reponse){
formMessg ('.fail-messg');
} else if (err.request) {
formMessg ('.fail-messg');
} else if ("Notvalid") {
formMessg ('.fill-messg');
}else {
console.log(err);
}
}
});

How to handle user cancel for OAUTH2 request in Teams messaging extension

The cancellation response from token.botframework.com is currently being displayed to screen like this:
{
"error": {
"code": "ServiceError",
"message": "Missing required query string parameter: code. Url = https://token.botframework.com/.auth/web/redirect?state=d48fb60ae4834fd8adabfe054a5eff74&error_description=The+user+chose+not+to+give+your+app+access+to+their+Dropbox+account.&error=access_denied"
}
}
How can I, instead, handle the cancellation gracefully? If the user cancels like this, I'd like to just have the auth-card-popup window close automatically.
This is for an action-type messaging extension app that I'm building. The sign-in process begins with an auth card. The bot is pointed at a Dropbox OAUTH2 connection. Here the relevant code that brings up the card:
const { TeamsActivityHandler, CardFactory } = require('botbuilder');
class MsgExtActionBot extends TeamsActivityHandler {
constructor() {
super();
this.connectionName = 'oauth2-provider';
}
async handleTeamsMessagingExtensionFetchTask(context, action) {
if (!await this.isAuthenticated(context)) {
return this.getSignInResponse(context);
}
}
async isAuthenticated(context) {
let tokenResponse = await context.adapter.getUserToken(
context,
this.connectionName
);
if (tokenResponse && tokenResponse.token) {
return true;
}
if (!context.activity.value.state) {
return false;
}
tokenResponse = await context.adapter.getUserToken(
context,
this.connectionName,
context.activity.value.state
);
if (tokenResponse && tokenResponse.token) {
return true;
}
return false;
}
async getSignInResponse(context) {
const signInLink = await context.adapter.getSignInLink(context, this.connectionName);
return {
composeExtension: {
type: 'auth',
suggestedActions: {
actions: [{
type: 'openUrl',
value: signInLink,
title: 'Please sign in'
}]
},
}
};
}
}

Receiving returned data from firebase callable functions

I'm playing with Callable HTTPS-functions in iOS. I've created and deployed the following function:
export const generateLoginToken = functions.https.onCall((data, context) => {
const uid = data.user_id
if (!(typeof uid === 'string') || uid.length === 0) {
throw new functions.https.HttpsError('invalid-argument', 'The function must be called with one argument "user_id" ');
}
admin.auth().createCustomToken(uid)
.then((token) => {
console.log("Did create custom token:", token)
return { text: "some_data" };
}).catch((error) => {
console.log("Error creating custom token:", error)
throw new functions.https.HttpsError('internal', 'createCustomToken(uid) has failed for some reason')
})
})
Then I call the function from my iOS-app like this:
let callParameters = ["user_id": userId]
self?.functions.httpsCallable("generateLoginToken").call(callParameters) { [weak self] (result, error) in
if let localError = self?.makeCallableFunctionError(error) {
single(SingleEvent.error(localError))
} else {
print("Result", result)
print("data", result?.data)
if let text = (result?.data as? [String: Any])?["text"] as? String {
single(SingleEvent.success(text))
} else {
let error = NSError.init(domain: "CallableFunctionError", code: 3, userInfo: ["info": "didn't find custom access token in the returned result"])
single(SingleEvent.error(error))
}
}
}
I can see on the logs that the function is invoked on the server with the right parameters, but I can't seem to the get data that is being returned from the function back into the app. It seems that the result.data value is nilfor some reason, even though I return {text: "some_data"} from the cloud function. How come?
Yikes! The issue was that I forgot to return the actual promise from the cloud function. This function is working:
export const generateLoginToken = functions.https.onCall((data, context) => {
const uid = data.user_id
if (!(typeof uid === 'string') || uid.length === 0) {
throw new functions.https.HttpsError('invalid-argument', 'The function must be called with one argument "user_id" ');
}
return admin.auth().createCustomToken(uid)
.then((token) => {
console.log("Did create custom token:", token)
return { text: "some_data" };
}).catch((error) => {
console.log("Error creating custom token:", error)
throw new functions.https.HttpsError('internal', 'createCustomToken(uid) has failed for some reason')
})
})

Pass over throwned error with completeError

I try to write an application that insert record into mongodb.
First look at my test:
test('Password test failed, not strong enough.', () {
Account.create({'name': 'eric', 'email': 'koston#mail.com', 'password': 'Test'})
.catchError((err) {
expect(err, throwsA(new isInstanceOf<DuplicateError>()));
});
});
This test should be failed, because the password is not strong enough. And the code, that try to insert record.
static Future<String> create(Map account) {
var completer = new Completer();
String hashed_password;
var self = new Account();
if(self._signUpKeys.length != account.length) {
return completer.completeError(new LengthError(I18n.instance.getTextByMap('TEXT1')));
}
for(var singUpKey in self._signUpKeys) {
if (!account.containsKey(singUpKey)) {
return completer.completeError(new ArgumentError(I18n.instance.getTextByMap('TEXT1')));
}
}
// Try to find duplication
Future.wait([findAccountByField('name', account['name']),
findAccountByField('email', account['email'])])
.then((Iterable<Map<String, String>> lists) {
// Check of any duplications
lists.forEach((value){
value.forEach((String key, String value) {
switch(key) {
case('name'):
return completer.completeError(new DuplicateError(
I18n.instance.getTextWithMarker('TEXT2', {'&1': value})));
case('email'):
return completer.completeError(new DuplicateError(
I18n.instance.getTextWithMarker('TEXT3', {'&1': value})));
}
});
hashed_password = Account.generateHashPassword(account['password']);
self._insert(self._fillDbFields(name: account['name'], email: account['email'], hashed_password: hashed_password,
created_at: new DateTime.now(), activated: false))
.then((result) => completer.complete(result));
});
})
.catchError((err) {
completer.completeError(err);
});
return completer.future;
}
this allocation will thrown an error, because the password is not according to security requirement.
hashed_password = Account.generateHashPassword(account['password']);
and this part should catch error and complete it.
.catchError((err) {
completer.completeError(err);
});
but in the test, I've got NoSuchMethodError. Why here, the error object is not pass over to test? What i do here wrong?
I think you should check what value lists has here
Future.wait([findAccountByField('name', account['name']),
findAccountByField('email', account['email'])])
.then((Iterable<Map<String, String>> lists) {
if it is null you can't call forEach on it

Resources