Current user doesn't persist when reloading an app (Ionic2 + Parse Server) - authentication

I'm currently working on Ionic 2 app with Parse Server backend.
I implemented signed up process. No problems here, everything works as expected: new account is created, user is logged in after sign up and current user exists.
Now I want to use current user and bypass sign up/login page next time user opens the app (if the user is already logged in ). The Parse documentation clearly states:
“It would be bothersome if the user had to log in every time they
open your app. You can avoid this by using the cached
current Parse.User object. Whenever you use any signup or login
methods, the user is cached in localStorage.”
In my case, however, I can't manage to make it work. I create current user according to Parse documentation during initialization process of the app:
var currentUser = Parse.User.current();
if (currentUser) {
// do stuff with the user
} else {
// show the signup or login page
}
Every time I open the app after successful sign up the current user is NULL.
Any ideas?

I kinda understand what's going on, but still don't understand why.
During signup or login Parse is supposed to save current user to local storage, but if local storage is not available for some reason, it saves it to memory map. And this is what happens in my case: Parse always saves current user to memory map, which is, of cause, temporary storage. Hence, every time I reload the app, Parse memory map is empty. I don't understand why in my environment Parse decides that local storage is unavailable. I couldn't find in the code where this decision is made. It seems to me that memory map is default (which is probably not true). Could it be that local storage functionality is not implemented yet in the open source version of Parse? Or does it have something to do with Ionic2 implementation?
Is there anybody out there from Parse team who is familiar with this part of Parse code?
Thanks.

Hi I use Local Storage.
import { Component } from '#angular/core';
import { NavController,Alert,Storage,LocalStorage } from 'ionic-angular';
import {HomePage} from'../home/home';
import {UserdetailPage} from'../userdetail/userdetail';
declare var require:any;
var Parse = require('parse/node');
#Component({
templateUrl: 'build/pages/user/user.html',
})
export class UserPage {
public currentUser:any;
public local:any;
username:string="";
password:string="";
repassword: string="";
sign:string = "SIGN IN";
constructor(private nav: NavController) {
Parse.initialize(XXXXX);
Parse.serverURL = 'XXXXXX';
this.local = new Storage(LocalStorage);
this.currentUser = this.local.get('userid');
console.log(this.currentUser);
}
signin(){
console.log("username:"+this.username);
console.log("password:"+this.password);
if(this.username!="" &&this.password!=""){
if(this.repassword!=""){
// Register User Session
this.register();
}
else if(this.repassword==""&&this.username!=""&&this.password!=""){
this.login();
}
}
}
changeSign(s:string){
console.log(s);
if(s!="")
this.sign = "SIGN UP (Register New Account)";
else
this.sign ="SIGN IN";
}
register(){
if(this.repassword==this.password){
var parseuser = new Parse.User();
parseuser.set("username",this.username);
parseuser.set("password",this.password);
parseuser.signUp(null, {
success:user=>this.registerSucessAlert(),
error: error=>this.registerFailAlert("Register Fail, The user name exists or Server is down")
});
}
else{
this.registerFailAlert("Password is not the same");
}
}
login(){
console.log("Login");
Parse.User.logIn(this.username, this.password, {
success:user=>this.loginSucessAlert(),
error:error=>this.loginFailAlert()
});
}
loginSucessAlert(){
this.currentUser = Parse.User.current().id;
this.local.set('userid',this.currentUser);
let alert = Alert.create({
title:'Login',
subTitle:'Hi '+this.username+', Press to Continue.',
buttons:[{text:'OaaaK',
handle:()=>{this.nav.setRoot(UserdetailPage);}}]
});
this.nav.present(alert);
}
loginFailAlert(){
let alert = Alert.create({
title:'Login',
subTitle:'Login Error',
buttons:['OK']
});
this.nav.present(alert);
}
registerSucessAlert(){
this.currentUser = Parse.User.current().id;
this.local.set('userid',this.currentUser);
let alert = Alert.create({
title:'Resgiter',
subTitle:'Thank you'+this.username+' for register, Press to Continue.',
buttons:['OK']
});
this.nav.present(alert);
}
registerFailAlert(err:string){
let alert = Alert.create({
title:'Register Fail',
subTitle:err,
buttons:['OK']
});
this.nav.present(alert);
}
}

Related

Cookie values do not get properly updated - Vue cookies

Here's what I want to do:
I am looking to store user preferences (Possibly 2-3 users max) in a cookie so they are readily available.
Upon login, I check if I have an existing 'users' cookie and if not, I create it. If it exists, I check if my current user is inside this cookie. If not, I add him, with empty prefs.
vue: 2.4.16
vue-cookies: 1.7.4
loggedIn (userId) {
this.profile = userId
this.userConnected = true
if (this.$cookies.isKey('users')) {
const userBase = JSON.parse(this.$cookies.get('users'))
const found = userBase.findIndex(user => user.profile === this.profile)
if (found === -1) {
console.log('new user, add to cookie')
const newUser = {
profile: this.profile,
preferences: {
cursor: null,
wallpaper: null,
theme: null
}
}
userBase.push(newUser)
this.$cookies.set('users', JSON.stringify(userBase), 604800)
}
} else {
console.log('no cookie, create users cookie')
const newUsers = [
{
profile: this.profile,
preferences: {
cursor: null,
wallpaper: null,
theme: null
}
}
]
this.$cookies.set('users', JSON.stringify(newUsers), 604800)
}
So far so good. Everything seems to work properly.
I then have my function to update preferences and update the cookie. The problem occurs when I have more than one users in my cookie. The first object in my cookie array will always get modified properly, but any other user in the Array will be ignored completely. This only happens with the cookie, the data that I'm pushing into the cookie is looking good. Here's more details:
updatePreferences (preference, data) {
//- We are getting the Users cookie, and finding the current active user
const globalPreferences = JSON.parse(this.$cookies.get('users'))
const userIndex = globalPreferences.findIndex(user => user.profile === this.$store.state.User.userProfile)
const currentUser = globalPreferences[userIndex]
if (preference === 'wallpaper') {
currentUser.preferences.wallpaper = data
globalPreferences.splice(userIndex, 1, currentUser)
//- globalPreferences is always properly updated. The console log always reflects the changes
const updatedData = JSON.stringify(globalPreferences)
//- The cookie does not properly update. Only the first index ever gets updated, the rest never changes.
this.$cookies.set('users', updatedData, 604800)
}
}
I am definitely lost here. I have tried removing the cookie before updating it again, but without luck either. Any help would be appreciated. Thanks!
First user update - Console log (Works properly)
Second user update - Console log (Cookie does not update value)
The data I was trying to push into the cookie was too big. I'm gonna use localStorage for now as it properly updates my data, and will make sure to clean the unused informations.

Getting requested page route in Nuxt middleware

I have a very simple 'named' Nuxt middleware set up (taken from the docs) which checks in the store to see whether a user is authenticated before they can navigate to certain routes. If the user is not authenticated, they are directed to a straightforward form in which they have to provide an email address to gain access (at http://example.com/access). All of that works fine, after they fulfil the middleware's store.state.authenticated check they can navigate around no problem.
export default function ({ store, redirect }) {
if (!store.state.authenticated) {
return redirect('/access')
}
}
My question is, once the user has entered their email address, I have no way of knowing what route they were initially trying to access. I've looked at other questions here about passing data between routes but because of the way the middleware works these solutions don't seem to be feasible.
I really would rather not set the slug in the vuex state as this will lead to a whole other set of complications – I also don't mind setting the intended slug as a query or a param on the /access url. I have read through the docs for the Nuxt redirect function and realise you can pass a route.query as an argument. So it seems that you could potentially do something like this:
return redirect('/access', intendedSlug)
...or, if using params(?):
return redirect(`/access/${intendedSlug}`)
But I don't know how to pass that intendedSlug value to the middleware in the first place as it's not exposed on the context passed to the function or anywhere else. It seems like this would be a common problem, but I can't find any simple solutions – any help would be really appreciated!
To help #Bodger I'm posting how I resolved this, it may not be perfect and it's working on a slightly older version of Nuxt (I know 😵!) but this is how I resolved the issue.
.../middleware/authenticated.js
export default function (context) {
const path =
context.route.path.length && context.route.path[0] === '/'
? context.route.path.slice(1)
: context.route.path
const pathArray = path.split('/')
if (process.server && !context.store.state.authenticated) {
return context.redirect('/access', pathArray)
} else if (!context.store.state.authenticated) {
return context.redirect('/access', pathArray)
}
}
The pathArray is then accessible in my /access page.
.../pages/access.js
data() {
return {
attemptedRoutePathArray: Object.values(this.$route.query)
...
}
},
...
computed: {
attemptedRouteURL() {
return new URL(
this.attemptedRoutePathArray.join('/'),
process.env.baseUrl
)
},
...
}

how to show agreement Page just one time in ionic 4

I have a problem when working on app.I just want to create agreement page,which will show just one time when the app load first time. After that the page will never show. but in my app that page always showing when the app loaded.Please help me
You could set a boolean variable in storage when the agreement is first displayed, then you check if this variable has been set before showing the agreement.
For example:
import { Storage } from '#ionic/storage';
constructor() {
this.storage.get('agreement_displayed').then(val => {
if (!val) {
this.displayAgreement();
this.storage.set('agreement_displayed', true);
}
});
}

Determine if opened as dialog in prompt

I am developing an aurelia app. I have a component (which is a full-page component and is navigable) and also in another page, I want to use this component as a prompt to let user choose from that page. So I have written the code below to open it as intended:
selectTaskFromTree(callbackOrSuccess, failure) {
const dialog = this.dialogService
.open({ viewModel: PLATFORM.moduleName('features/view/tree/tree'), model: {}, lock: false });
if (callbackOrSuccess) {
if (failure) {
dialog.whenClosed(response => {
if (!response.wasCancelled) {
callbackOrSuccess(response.output);
} else {
failure(response);
}
});
}
else{
dialog.whenClosed(callbackOrSuccess);
}
return;
}
else{
return dialog;
}
}
So the component Tree is now successfully loaded and shown. The problem is now how to determine if the TreeComponent is opened as a dialog or not.
The way I am thinking about is to pass an arbitrary param to it and if the param is true, the status is dialog and otherwise not dialog:
const dialog = this.dialogService
.open({ viewModel: PLATFORM.moduleName('features/view/tree/tree'), model: {isDialog: true}, lock: false });
But I think maybe there is also a better way to do this. For example to ask from DialogService if I am a dialog or not. So what are the other solutions and which one is better?
To determine whether or not you have an open (or active) dialog you can ask DialogService for the relevant fields:
this.dialogService.hasOpenDialog
this.dialogService.hasActiveDialog
Sadly, this cannot tell you which dialog is open. I would argue that your idea of passing a param to the model is an equally valid way of doing it.
I have thought about different solutions and I was seeking for keeping coupling low and preventing define of new param. So I wrote the below code where I want to know if this component is opened as a dialog or not:
attached() {
this._isDialog = Boolean(this.dialogController.settings);
}

Change body class when it has aurelia-app attached

Shortly I have two shells/roots: one for login page and one for the rest of the application and switch between them given the user is logged in or not.
My aurelia-app is attached to body element but I have distinct body classes for login and the rest of the application.
What is the best way to also switch body classes depending on the active shell?
In my opinion, the easiest way is changing the body class in the main.js file. For instance:
let rootComponent = '';
aurelia.start().then(a => {
if (!app.isLoggedIn()) { //<--- example of func to check if the user is logged in
document.body.className = "example-class-1";
rootComponent = 'login/login';
} else {
document.body.className = "example-class-2";
rootComponent = 'app/app';
}
a.setRoot(rootComponent, document.body);
});
Hope this helps!