How to use fetch inside another fetch? - javascript

I have this class which is supposed to authenticate a user (in this case a moderator)
import Cookie from "universal-cookie";
import { promiseNotification, updateNotification } from "./addNotification";
const cookies = new Cookie();
class Authentication {
token;
role;
login = (username, password) => {
const id = promiseNotification("Login...")
fetch("auth/get-token", {
method: "POST",
headers: {'Content-Type': 'application/json'},
body: JSON.stringify({username: username, password: password})
})
.then(res => res.json())
.then(data => {
updateNotification(id, data);
if (data.token) {
cookies.set("token", data.token);
this.setToken();
return this.setRole(); //If I understand correctly this returns a promise
}
}).then(() => window.location.replace("/mod")) //and this handles the setRole promise
.catch((error) => {alert("Error occurred login in"); console.log(error)});
}
setRole = async () => {
return fetch(`/auth/get-role/${this.token}`, {method: 'GET'}).then(res => res.json())
.then(data => this.role = data.role);
}
setToken = () => {
this.token = cookies.get("token") || "";
}
}
export default new Authentication();
When I call the login function the role and token should be set in the class instance and after it finishes it should redirect the user to the mods page. In the mods page I have this logic to prevent non moderators from accessing it.
useEffect(() => {
console.log(JSON.stringify(auth)); //This prints an empty object, meaning that none of the actions that happened in login had any effect
if (!["administrator", "moderator"].includes(auth.role)) {
createNotification("You are not a moderator", "error");
history.push("/admin-login");
}
}, []);
Why aren't any of the properties in the auth object being update?

Related

Cypress: Get the url token, save it to local storage and mock the login data to perform an automatic login

I need to login without going through the login screen, that is, with mocked data, because when testing the login directly on the login screen, when authenticating I am redirected to the home screen, where in addition to not being the screen I want to test ends up breaking the test due to a problem with the iframe. Until then I already have the custom command to get the token and save it, I need to hit the url, and with the mocked data automatically log in, and with that redirect to the screen I want to test.
Here's what I have so far:
Commands.js
import 'cypress-iframe';
import 'cypress-dotenv';
import 'cypress-file-upload';
import 'cypress-localstorage-commands';
const defaultUsername = Cypress.env('user')
const defaultPassword = Cypress.env('password')
Cypress.Commands.add('getToken', (username = defaultUsername, password = defaultPassword) => {
cy.request({
method: 'POST',
url: 'https://testedt04.qa.directtalk.com.br/adminuiservices/api/Login',
headers: {
Authorization: `Basic ${window.btoa(`${username}:${password}`)}`,
},
}).then((res) => {
if (res.status === 200) {
cy.setLocalStorage('dt.admin.token', res.body.token)
cy.setLocalStorage('dt.admin.siteId', res.body.SiteId)
cy.setLocalStorage('dt.admin.agentId', res.body.AgentId)
cy.setLocalStorage('dt.admin.tenantId', res.body.tenantId)
cy.setLocalStorage('dt.admin.departments', JSON.stringify(res.body.departments))
cy.setLocalStorage('dt.admin.mnemonic', res.body.mnemonic)
cy.setLocalStorage('dt.admin.megaMenu', res.body.MegaMenu)
cy.setLocalStorage('dt.admin.siteName', res.body.siteName)
cy.setLocalStorage('dt.admin.agentUserName', res.body.agentUserName)
cy.setLocalStorage('dt.admin.agentName', res.body.agentName)
}
})
}
Login.spec.js
/// <reference types="cypress"/>
import signin from '../pages/SigninPage'
describe("Get Token And Save", () => {
before(() => {
cy.getToken();
cy.saveLocalStorage()
})
beforeEach(() => {
cy.restoreLocalStorage()
})
it("Should Exist Token in localStorage", () => {
cy.getLocalStorage("dt.admin.token").should("exist")
cy.getLocalStorage("dt.admin.token").then(token => {
cy.log('Token generated: ' + token)
})
})
})
describe('When I login in supervisor', () => {
before(() => {
signin.go()
cy.getToken()
signin.noException()
cy.saveLocalStorage()
})
beforeEach(() => {
cy.reload()
cy.restoreLocalStorage()
})
it("Sould Still Exist Token in localStorage", () => {
cy.getLocalStorage("dt.admin.token").should("exist")
cy.getLocalStorage("dt.admin.token").then(token => {
cy.log('Token generated: ' + token)
})
})
it('With CORRECTLY credentials', () => {
signin.login(Cypress.env('user'),Cypress.env('password'))
signin.verifyLogin(Cypress.env('site'),Cypress.env('agent'))
})
it('With WRONG credentials', () => {
signin.login('não existe','erro')
signin.verifyErrorLoginMessage(403, 'Credencias informadas invalidas')
})
it('With NOT FOUND response request', () => {
signin.interceptLogin(404)
signin.login('SEM','erro')
signin.verifyErrorLoginMessage(404, 'Operação não encontrada')
})
it('With SERVER ERROR response request', () => {
signin.interceptLogin(500)
signin.login('SEM','erro')
signin.verifyErrorLoginMessage(500, 'Erro interno no servidor')
})
})
SigninPage.js
class SigninPage {
go(){
cy.visit('/login.html')
}
login(user, pass){
this.go()
cy.get('#login').type(user)
cy.get('#password').type(pass)
cy.get('[ng-show="SHOW_INPUTS"] > .form-wrapper > .form-horizontal > .buttons-wrapper > #loginButton').click()
}
verifyLogin(site, agent){
cy.get('.site-name').should('have.text', site)
cy.get('.agent-name').should('have.text', agent)
}
interceptLogin(code){
cy.intercept('POST', '/adminuiservices/api/Login', {
statusCode: code,
body: {},
},)
}
verifyErrorLoginMessage(code, message){
cy.get(`[ng-show="hasError(${code})"]`)
.should('have.text', message)
}
noException(){
Cypress.on('uncaught:exception', (err, runnable) => {
return false
})
}
}
export default new SigninPage;

How to adjust the order of events occurring in async Javascript?

I am working on authentication for my react native app.
The problem I am having is that the signInUser function seems to be executing in the wrong order. I want the signIn function to fully execute before moving on.
However, that doesn't seem to be happening as I am getting this response in my console, with the "undefined" coming from console.log(response) in the SignInScreen.
Here is the console:
undefined
16d0707a3508a9b43b8c36c8574ca73d8b4b26af
I have this function in the SignInScreen.js
import { signIn } from "../services/authService";
import { useAuthDispatch } from "../contexts/authContext";
const SignInScreen = ({ navigation }) => {
const dispatch = useAuthDispatch();
const [signInLoading, setSignInLoading] = useState(false);
const signInUser = async (values) => {
const { email, password } = values;
setSignInLoading(true);
signIn(email, password)
.then((response) => {
console.log(response);
dispatch({
type: "SIGN_IN",
token: response,
});
})
.catch((e) => {
console.log(e);
})
.finally(() => setSignInLoading(false));
};
And this is my authService.js:
import axios from "axios";
const signIn = async (email, password) => {
axios
.post("http://127.0.0.1:8000/rest-auth/login/", {
username: email,
email: email,
password: password,
})
.then((response) => {
console.log(response.data.key);
return response.data.key;
})
.catch((error) => {
return error;
});
};
How can I fix this?

Dispatch in Redux-Thunk

Uncaught (in promise) Error: Request failed with status code 400
I need to make a page request to the database for logging into the system, but I'm already too confused and don't know how to remove this error.
Before that there was the error "Actions must be plain objects. Use custom middleware for async actions."
After that I connected Redux-Thunk and the current error appeared.
Actions
export const auth = (email, password, isLogin) => {
return async(dispatch) => {
dispatch(authData())
let url = 'https://identitytoolkit.googleapis.com/v1/accounts:signUp?key=AIzaSyAU8gNE0fGG8z9zqUyh68Inw9_RzljhCCs'
if (isLogin) {
url = 'https://identitytoolkit.googleapis.com/v1/accounts:signInWithPassword?key=AIzaSyAU8gNE0fGG8z9zqUyh68Inw9_RzljhCCs'
}
const response = await axios.post(url, authData)
console.log(response.data)
}
}
const authData = (email, password, returnSecureToken = true) => ({
type: 'LOGIN',
email,
password,
returnSecureToken
})
Component
loginHandler = () => {
this.props.auth(
this.props.AuthMail,
this.props.AuthPass,
true
)
}
registerHandler = () => {
this.props.auth(
this.props.AuthRegMail,
this.props.AuthRegPass,
false
)
}
const mapDispatchToProps = dispatch => {
return {
auth: (email, password, isLogin) => dispatch(auth(email, password, isLogin))
}
}
// You forgot to add the arguments to authData function
dispatch(authData())
// Here you are passing in a function as the second argument
const response = await axios.post(url, authData)
Should probably be something like this:
export const auth = (email, password, isLogin) => {
return async (dispatch) => {
const url = isLogin ? 'example.com/login' : 'example.com/signup';
const response = await axios.post(url, {
email,
password,
returnSecureToken: true,
});
console.log(response.data);
// Handle this action somewhere to store the signed in user data in redux
dispatch({
type: "LOGIN",
payload: response.data
})
}
}

Express/React promise stalled

I have an Express backend server on port 5000 and react front end running on port 3000. I am trying to fetch some data from express post route and return it to front end but my Promise never resolves. It always ends up as "stalled".
util.inspect(messageList) shows my array on server console but my Promise on the front end never resolves.
I'm fetching some data server side on ComponentDidMount like below:
class Conversation extends React.Component {
state = {
conversations: [],
messages: [],
error: null,
loading: true,
input: '',
owner: 'Unassigned'
}
componentDidMount() {
const { match } = this.props
const { conversationId } = match.params
// Make a POST request to our server and pass the conversationId
this.getMessages(conversationId)
}
getMessages(conversationId) {
return fetch('/search-conversation', {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify({ conversation: conversationId })
})
.then(res => res.json())
.then((messages) => this.setState({ messages }))
}
Server Side:
app.post('/search-conversation', (req, res) => {
conversationId = req.body.conversation
if (!conversationId) {
res.send('/error');
} else {
console.log(`Success, conv id is ${conversationId}`);
}
// call function to go get messages from API
console.log(`fetching messages for ${conversationId}`)
return fetch(endpoint)
.then((res) => res.json())
.then(({ data }) => data)
.then((data) => {
const messageList = data[0].messages.data
return messageList
})
.then((messageList) => console.log(util.inspect(messageList)))
.catch(error => console.error(`Error: ${error}`))
});
Any ideas are appreciated, thanks in advance.
You are missing res.json() call on the server side that will send response to the client:
app.post('/search-conversation', (req, res) => {
conversationId = req.body.conversation
if (!conversationId) {
res.send('/error');
} else {
console.log(`Success, conv id is ${conversationId}`);
}
// call function to go get messages from API
console.log(`fetching messages for ${conversationId}`)
return fetch(endpoint)
.then((res) => res.json())
.then(({ data }) => data)
.then((data) => {
const messageList = data[0].messages.data
res.json(messageList) // <-- sending response
})
.catch(error => console.error(`Error: ${error}`))
});

How can I update a user AFTER they have logged out of my app, then sign back in

I am currently developing an app that requires login/logout. I am using google-login-react (Google OAuth2) to handle most of the signing in heavy work. From there, I am posting the google access token along with some other stuff (id, email, last login, etc..) to my RESTful API. After the user is authenticated, they are redirected to a dashboard. From there, the user can sign out of the application.
What I am having difficulty with is UPDATING the user and the user object after the user signs back in. Right now, every time the user logs back in, it is posting a new object (and thus a new user) to my API. I'm looking to simply just show the updated LAST LOGIN and to store the existing user in the ID they had already been assigned upon initial log in.
Right now, this is what I have thus far:
PostData.js
export function PostData(type, userData) {
let BaseURL = 'https://app.someApp.com/';
return new Promise((resolve, reject) =>{
fetch(BaseURL+type, {
headers:{
"Accept": "application/json",
"Content-Type": "application/json"},
'Access-Control-Allow-Origin':'*',
'Content-Security-Policy':'upgrade-insecure-requests',
method: 'POST',
mode: 'cors',
body: JSON.stringify(userData)
})
.then((response) => response.json())
.then((res) => {
resolve(res);
})
.catch((error) => {
reject(error);
});
});
}
Login.js
class Login extends Component {
constructor(props) {
super(props);
this.state = {
loginError: false,
redirect: false
};
this.signup = this.signup.bind(this);
}
signup(res, type) {
let postData;
var currentTime = new Date();
if (type === 'google' && res.profileObj.email) {
postData = {
email: res.profileObj.email,
realname: res.profileObj.name,
googleId: res.profileObj.googleId,
googleAccessToken: res.Zi.access_token,
googleImageURL: res.profileObj.imageUrl,
lastLogin: currentTime
};
}
if (postData) {
PostData('api/v1/appUsers', postData).then((result) => {
let responseJson = result;
localStorage.setItem("userData", JSON.stringify(responseJson));
this.setState({redirect: true});
});
} else {}
};
render() {
if (this.state.redirect || localStorage.getItem('userData')) {
return (<Redirect to={'/'}/>)
}
const responseGoogle = (response) => {
let isSignedIn = true;
console.log("google console");
console.log(response);
console.log(isSignedIn);
this.signup(response, 'google');
return isSignedIn;
}
Home.js
signOut(e) {
e.preventDefault()
if (localStorage.getItem('userData')) {
localStorage.removeItem('userData');
this.props.history.push('/login')
console.log('shit works');
}
}
constructor(props){
super(props);
this.state = {
name:'',
redirect: false,
};
}
componentDidMount() {
let data = JSON.parse(localStorage.getItem('userData'));
console.log(data);
}
render() {
if(!localStorage.getItem('userData') || this.state.redirect){
return (<Redirect to={'/login'}/>)
}
**I'm mainly looking for a syntax solution as opposed to the logic solution as I am aware of the logic behind this

Categories