I am completely at a loss here. I have been struggling with this for several hours now trying multiple different approaches and none are getting me anywhere. My problem is I cannot seem to figure out how it the new Password is meant to be retrieved from the user within the newPasswordRequired callback after an authentication request to Cognito. Here is my code in its current state. Please don't hesitate to tell me what I can do better, as I am fairly new to Angular and completely new to using Cognito authentication.
public login(email: string, password: string): Observable<UserModel> {
const cognitoUser = new CognitoUser(this.getUserData(email));
cognitoUser.setAuthenticationFlowType('USER_PASSWORD_AUTH');
const authenticationDetails = new AuthenticationDetails(CognitoUtils.getAuthDetails(email, password));
const self = this;
return Observable.create((obs: Observer<UserModel>) => {
cognitoUser.authenticateUser(authenticationDetails, {
onSuccess: result => {
this.session = result;
const token = result.getIdToken();
const accessToken = result.getAccessToken();
this.localStorage.setToken(token);
this.localStorage.setAccessToken(accessToken);
obs.complete();
},
onFailure: err => {
obs.error(err);
},
newPasswordRequired: (userAttributes, requiredAttributes) => {
let dialogRef: MatDialogRef<NewPasswordComponent>;
const config = new MatDialogConfig();;
config.role = 'dialog';
config.width = '40%';
config.data = { newPass: self.newPass };
dialogRef = self.dialog.open(NewPasswordComponent, config);
dialogRef.afterClosed().subscribe(result => {
self.newPass = result;
cognitoUser.completeNewPasswordChallenge(self.newPass, userAttributes, {
onSuccess: result => {
obs.complete();
},
onFailure: err => {
obs.error(err);
}
});
});
}
});
});
}
Based on what you have provided, it looks like the issue is when you respond with completeNewPasswordChallenge you're passing in userAttributes which is returned from the newPasswordRequired callback and won't work.
Instead, you need to see what attributes are required (i.e. requiredAttributes) and pass them in as an object. For example, if "name" is the required attribute, then pass in the following way:
dialogRef.afterClosed().subscribe(result => {
self.newPass = result;
cognitoUser.completeNewPasswordChallenge(self.newPass, {"name":"John Doe"}, {
onSuccess: result => {
obs.complete();
},
onFailure: err => {
obs.error(err);
}
});
Hope this helps!
Related
I am trying to send a notification whenever a new update to my database takes place. I have the onUpdate side working but I am new to FCM and I am stuck at the sending the notification.
The structure of the devices collection is:
+devices/
+tokenId/
-tokenId:njurhvnlkdnvlksnvlñaksnvlkak
-userId:nkjnjfnwjfnwlknlkdwqkwdkqwdd
The function that I have right now that gets stuck with an empty value of token is:
const functions = require('firebase-functions');
const admin = require("firebase-admin");
admin.initializeApp();
const db = admin.firestore();
const settings = { timestampsInSnapshots: true };
db.settings(settings);
.....
exports.fcmSend = functions.firestore
.document(`chats/{chatId}`).onUpdate((change, context) => {
const messageArray = change.after.data().messages;
const message = messageArray[(messageArray.length-1)].content
if (!change.after.data()) {
return console.log('nothing new');
}
const payload = {
notification: {
title: "nuevo co-lab",
body: message,
}
};
return admin.database().ref(`/devices`)
.once('value')
.then(token => token.val())
.then(userFcmToken => {
console.log("Sending...", userFcmToken);
return admin.messaging().sendToDevice(userFcmToken, payload)
})
.then(res => {
console.log("Sent Successfully", res);
})
.catch(err => {
console.log("Error: ", err);
});
});
I am not able to get the token from the database. It is null or undefined. Can anyone help me with this second part of the function?
Thanks a lot in advance!
Thanks Frank for the tip!
I managed to solve the problem with this code in case anybody needs it:
const payload = {
notification: {
title: "nuevo mensaje de co-lab",
body: message,
}
};
// Get the list of device tokens.
const allTokens = await admin.firestore().collection('devices').get();
const tokens = [];
allTokens.forEach((tokenDoc) => {
tokens.push(tokenDoc.id);
});
if (tokens.length > 0) {
// Send notifications to all tokens.
return await admin.messaging().sendToDevice(tokens, payload);
}else {
return null;
}
consider a function
exports.projectNotifyLaunch = (admin, functions) => {
return functions.database.ref("/projects/{pid}").onCreate(snap => {
const { title } = snap.val();
const notification = {
title: `${title} just launched!`,
body: `We just heard about a new cryptocurrency project called ${title}`
};
return admin.messaging().sendToTopic("premium", { notification });
});
};
How should I mock deeply nested functions such as
functions.database.ref("/projects/{pid}").onCreate(snap => {});
or
admin.messaging().sendToTopic("premium", { notification });
in Jest? I want to fire off the snap=>{} callback and assert against the value of notification.
I was able to make this work
This works but it's quite verbose. I'm wondering if there is a better way, or a type of testing I'm not aware of with Jest.
describe("send notification to premium users on new project", () => {
// INPUTS
const snap = {
val: () => ({
title: "Test Title"
})
};
const functions = {
database: {
ref: () => ({
onCreate: callback => callback(snap)
})
}
};
// outputs
let topicStub = null;
let notificationStub = null;
const admin = {
messaging: () => ({
sendToTopic: (topic, notification) => {
topicStub = topic;
notificationStub = notification;
}
})
};
projectNotifyLaunch(admin, functions);
test("title is correct", () => {
expect(notificationStub.notification.title).toBe(
"Test Title just launched!"
);
});
test("topic is premium", () => {
expect(topicStub).toBe("premium");
});
});
I not undestand everything with javascript etc, I want to get my data returned by ma action redux but i'have a problem with my code.
const mapStateToProps = state => {
const group = state.groupReducer.group ? state.groupReducer.group : [ ]
return {
group
}
how i can get my data ?
When I try with that:
const mapStateToProps = state => {
const group = state.groupReducer.group.data.data[0] ? state.groupReducer.group.data.data[0] : [ ]
return {
group
}
And my goal is map around group
renderGroup = group => {
return group.map((groups => {
<div key={groups.data.data.id}>
//
</div>
}))
}
Sagas.js
export function* loadApiDataGroup() {
try {
// API
const response = yield
call(axios.get,'http://localhost:8000/api/group');
yield put(loadGroup(response))
} catch (e) {
console.log('REQUEST FAILED! Could not get group.')
console.log(e)
}
}
Action.js
export function loadGroup(data){ return { type: LOAD_GROUP, data }};
export function creatGroup(data){ return { type: CREATE_GROUP, data}};
// reducer
export default function groupReducer( state= {}, action = {}){
switch (action.type){
case LOAD_GROUP:
return {
...state,
group: action.data
}
case CREATE_GROUP:
return {
...state
}
default:
return state
}
thank you to help me
Try
const mapStateToProps = state => ({
group: state.groupReducer.group || []
});
Then you can use this.props.group in the component. Even though you might only want one thing in mapStateToProps, it's usually not directly returned like that.
If group is the response of an API request, you need to unpack data first, this is done in your async action creator (you will want to use redux-thunk or something similar):
const getGroup = () => async (dispatch) => {
dispatch({ type: 'GET_GROUP_REQUEST' });
try {
const { data } = await axios.get('/some/url');
dispatch({ type: 'GET_GROUP_SUCCESS', payload: data });
} catch (error) {
dispatch({ type: 'GET_GROUP_FAILURE', payload: error });
}
};
I'm trying to make an HTTP POST and then check the response to see if it fails or succeeds.
The HTTP call looks like this :
doLogin(credentials) {
var header = new Headers();
header.append('Content-Type', 'application/x-www-form-urlencoded');
var body = 'username=' + credentials.username + '&password=' + credentials.password;
return new Promise((resolve, reject) => {
this.http.post(this.url, body, {
headers: header
})
.subscribe(
data => {
resolve(data.json());
},
error => {
resolve(error.json());
}
);
});
}
And the call of this function is the following :
data: Object;
errorMessage: Object;
login($event, username, password) {
this.credentials = {
username: username,
password: password
};
this._loginService.doLogin(this.credentials).then(
result => {
this.data = result;
console.log(this.data);
},
error => {
this.errorMessage = <any>error;
console.log(this.errorMessage);
});
}
On Chrome console, the data is the following :
Object {status: "Login success", token: "eyJhbGciOiJIUzUxMiJ9.eyJzdWIiOiJjcmlzdGkiLCJ1c2VyS…blf1AzZ6KzRWQFNGXCrIeUHRG3Wrk7ZfCou135WmbVa15iYTA"}
How can I access the status in Angular 2? Because if I'm trying to access this.data.status, it's not working.
Should I create a class with the status and token properties?
To answer your question, you can use the response.okboolean that's available in the subscription of the observable from the http.
So based on your code you could pass the data object straight to the promise and inspect data.ok before parsing the data.json.
//...
return new Promise((resolve, reject) => {
this.http.post(this.url, body, {
headers: header
})
.subscribe(resolve,
error => {
reject(error.json());
}
);
});
// then you would have something like this:
this._loginService.doLogin(this.credentials).then(
result => {
if (result.ok) {
this.data = result;
console.log(this.data);
}
},
error => {
this.errorMessage = <any>error;
console.log(this.errorMessage);
})
SUGGESTION
Now, I would recommend getting rid of the promise, as I believe you don't really need it. whoever is consuming your service can just subscribe to the observable returned by the http post, like so:
doLogin(credentials) {
let header = new Headers();
header.append('Content-Type', 'application/x-www-form-urlencoded');
var body = 'username='+credentials.username+'&password='+credentials.password;
return this.http.post(this.url, body, { headers: header });
}
Then, when logging in:
login($event, username, password) {
this.credentials = {
username: username,
password: password
};
this._loginService.doLogin(this.credentials).subscribe(response => {
if (response.ok) { // <== CHECK Response status
this.data = response.json();
console.log(this.data);
} else {
// handle bad request
}
},
error => {
this.errorMessage = <any>error;
console.log(this.errorMessage);
});
}
Hope this helps!
You could do it like this:
data: Object;
errorMessage: Object;
login($event, username, password) {
this.credentials = {
username: username,
password: password
};
this._loginService.doLogin(this.credentials).then(
(result: any) => {
this.data = result;
console.log(this.data);
console.log(this.data.status);
},
error => {
this.errorMessage = <any>error;
console.log(this.errorMessage);
});
}
Set the result to type any. That way you'll be able to access the status, however you could create a class and use rxjs/map within your service to populate the class if you so desire.
My application code to test:
create(params) {
let result = {};
try {
result = await this.db.query('/* some query */');
} catch (e) {
throw new Error('Error creating User', e);
}
return this._getById(result.insertId);
}
I have the _getById method in the same class which does exactly what it says...
And my current test (running through Ava):
test('it should create a user', async t => {
const db = mock({
query: () => {
},
});
const userObj = {
// some params
};
const user = new Users({
db: db.object,
});
const call = {
request: userObj,
};
const result = await user.create(call);
// test?
});
If I try and test anything based off of the result variable, ie. the newly created User, I receive the error "Cannot read property 'insertId' of undefined". What is my best option with Sinon to test that this create method will return a newly created "user"?
I think that you have the "Cannot read property 'insertId' of undefined" because the following mock doesn't return something
const db = mock({
query: () => {
},
});
If you return something like that
const db = mock({
query: () => {
return {
username: "username"
}
},
});
and in the test the result will have the value and you should be able to use expect to check if you have the expected result:
{
username: "username"
}
The problem in this specific test starts when the mock does not return something and also calling mock overrode the value that you assigned here
let result = {};