Handle custom response messages with Parse-server 3.0.0+ - parse-server

I have a project where it uses Parse-server 2.8.1 version. This was previously communicated with mLab and with the current migration to MongoDBAtlas, we have to update the parse-server version to the latest. I have seen there was a migrating doc. But there is a part which I not getting yet. How to set custom response messages. For example
if (users.length > 0){
response.success({
status:false,
message:'Screen name has already been taken.'
});
} else {
response.success({
status:true,
message:'Screen name available.'
});
}
How to convert this to support the parse-server latest version. This is a must since mobile apps are communicating with the server, depending on these status values and the message.

It should be something like this:
Parse.Cloud.define('myFunctionName', async () => {
const query = new Parse.Query(Parse.User);
// add some constraints to query
const users = await query.find({ useMasterKey: true });
if (users.length > 0) {
return {
status: false,
message: 'Screen name has already been taken.'
};
} else {
return {
status:true,
message:'Screen name available.'
};
}
});

Related

Linking.canOpenURL isn't accurate for checking which Maps app is installed choose the correct maps app

I have a button with an address, and when it opens, I want to use the "default" app which is installed. The reason is, for example, many iOS users uninstall Apple Maps app, so they only have Google. Checking if iOS ? 'maps' : 'google' isn't safe because it can't be Platform dependent.
This is using Expo SDK 46.
I then read to try something like:
const openUrl = () => {
const mapNames = ['comgooglemaps', 'maps'];
const hasApp = mapNames.find(async name => {
try {
return await Linking.canOpenURL(
`${name}://?center=${vehicle.coordinates.latitude}, ${vehicle.coordinates.longitude}`,
);
} catch (_e) {
return false;
}
});
openMap({
provider: hasApp,
end: vehicle.streetAddress,
});
};
but this isn't working because Linking.canOpenURL is always returning the first item since it's a "string" and there fore meets the API requirements of "given URL can be handled".
So I tried an alternate option, based on research on other suggestions:
const openUrl = async () => {
let hasGoogleMaps = false;
await Linking.canOpenURL('comgooglemaps').then(canOpen => {
if (canOpen) {
hasGoogleMaps = true;
}
});
openMap({
provider: hasGoogleMaps ? 'google' : 'apple',
end: vehicle.streetAddress,
});
};
This too fails to open Google Maps on iOS.
My question is: how can I for sure know if I have google maps installed and not base it on the Platform.OS itself?
Bonus question: is it true I cannot install Google Maps on a simulator?

Get result of useQuery with Apollo and Nuxt.js

I'm trying to use the useQuery function (from package '#vue/apollo-composable').
This function doesn't return a promise, just refs to result, loading etc. so I can't directly use this data in my store (Pinia).
Currently I have this code:
fetchArticle: function (id: string) {
// check if article is already in cache
const cache = this.articles.find(a => a.id == id);
if (cache && !cache.partial) return cache;
// fetch article from server
const { result: article } = useQuery<{ article: Article }>(GET_ARTICLE, { id });
// update state, but... when `article` contains data?
},
When I'am in a store I don't know how to wait for request end.
I tried to transform useQuery to return promise but that doesn't work, Nuxt.js freeze on server with this code:
fetchArticle: async function (id: string) {
// check if article is already in cache
const cache = this.articles.find(a => a.id == id);
if (cache && !cache.partial) return cache;
// fetch article from server
const { onResult, result } = useQuery<{ article: Article }>(GET_ARTICLE, { id });
const article = result.value?.article || (await new Promise(r => onResult(({ data }) => r(data.article))));
if (!article) return;
const data = { ...article, partial: false };
this.articles = this.articles.map(a => (a.id == id ? data : a)) as Article[];
// return article
return article;
},
Informations
Store: Pinia
Versions: Nuxt 3.1.2; #vue/apollo-composable 4.0.0-beta.2
I use the apollo client like this:
// The creation of the client
// This part is on a base class, that all of my Service extends
this.apolloClient = new ApolloClient({
link: //the link,
cache: new InMemoryCache(),
name: "My APP name",
version: `v${version.toString()}`,
defaultOptions: defaultOptions //some options I customize
});
provideApolloClient(this.apolloClient);
//The query
// This part is on the Service class
return this.apolloClient.query({ query: query, variables: { id: id }}).then((result) => {
return result.data.myData;
});
I always used like this, never used the useQuery. In the link I use a combination of three, one for the Auth, one for Errors and one for the base URL

Web app that runs in Microsoft Teams (personal tab) doesn't always work on Desktop version

I have a Web app built in Vuejs and has SSO authentification using microsoftTeams.authentication.getAuthToken when running in Teams, or microsoftAuthLib when running in the browser.
Inside the company's network or when connected to the VPN everything works absolutely fine.
We recently opened it outside of the VPN and we created a public certificate for it. So when I disconnect the VPN, it works:
In any browser (outside of Teams).
Teams browser version.
Teams on Android/iPhone.
But it doesn't work on Teams Windows Desktop version, it fails with the following error:
Refused to display
'https://login.microsoftonline.com/.../oauth2/authorize?...' in a
frame because it set 'X-Frame-Options' to 'deny'.
Anybody has an idea what could be the issue? And why would it work on the company's VPN but not outside?And only on specific cases? I am lost, any help would be appreciated.
Thank you
*** EDIT / ADDED SSO REDIRECT CODE ***
import * as microsoftTeams from "#microsoft/teams-js";
import * as microsoftAuthLib from "msal";
import settings from './settings.js';
var msalConfig = {
auth: {
clientId: settings.sso.id,
authority: settings.sso.authority
},
cache: {
cacheLocation: "localStorage",
storeAuthStateInCookie: true
}
};
var requestObj = {
scopes: settings.sso.scopes
};
var myMSALObj = new microsoftAuthLib.UserAgentApplication(msalConfig);
myMSALObj.handleRedirectCallback(authRedirectCallBack);
function authRedirectCallBack(error, response) {
if (error) {
console.log(error);
} else {
console.log("token type is:" + response.tokenType);
}
}
function loginRedirect(requestObj) {
let account = myMSALObj.getAccount();
if (!account) {
myMSALObj.loginRedirect(requestObj);
return false;
} else {
return true;
}
}
function acquireMsalToken() {
return new Promise(function (resolve) {
resolve(myMSALObj.acquireTokenSilent(requestObj).then(token => {
return token.accessToken;
}).catch(error => {
acquireMsalTokenRedirect(error);
}));
})
}
function acquireTeamsToken() {
return new Promise((resolve, reject) => {
microsoftTeams.authentication.getAuthToken({
successCallback: (result) => {
resolve(result);
},
failureCallback: (error) => {
reject(error);
}
});
});
}
function acquireMsalTokenRedirect(error) {
if (error.errorCode === "consent_required" ||
error.errorCode === "interaction_required" ||
error.errorCode === "login_required") {
myMSALObj.acquireTokenRedirect(requestObj);
}
}
var msal = {
autoSignIn: function () {
return loginRedirect(requestObj);
},
acquireToken: async function () {
if (settings.sso.inTeams) {
microsoftTeams.initialize();
microsoftTeams.enterFullscreen();
return acquireTeamsToken();
} else {
let signedIn = msal.autoSignIn();
if (signedIn) {
return acquireMsalToken();
}
}
}
}
export default msal
This error means that you are trying to redirect your tab's iframe to the AAD login flow which in turn is unable to silently generate an auth token for you and is attempting to show an interactive flow (e.g. sign in or consent):
Refused to display
'https://login.microsoftonline.com/.../oauth2/authorize?...' in a
frame because it set 'X-Frame-Options' to 'deny'.
To avoid this issue you need to try and acquire a token silently and if that fails use the microsoftTeams.authentication.authenticate API to open a popup window and conduct the AAD login flow there.
Replacing the acquireTeamsToken() function with the following resolved the issue.
function acquireTeamsToken() {
return new Promise((resolve, reject) => {
microsoftTeams.initialize(() => {
microsoftTeams.authentication.authenticate({
url: window.location.origin + "/ms-teams/auth-start",
width: 600,
height: 535,
successCallback: (result) => {
resolve(result);
},
failureCallback: (error) => {
reject(error);
}
});
});
});
}
I found this documentation very helpful on how to create the Authentication pop up and how to create a Callback window with the Token in it.
You might also want to cache the token and only create a popup when it expires.
This might be because you're using the auth popup option instead of the redirect option in whichever auth library you're using (hopefully MSAL 2.0). Teams is a little different because it's actually launching a popup for you when necessary, so although it sounds a bit strange, you actually want to use the redirect option, inside the popup that is launched. What might help is to look at the new SSO Sample app in the Teams PnP samples.
Go to: %APPDATA%\Microsoft\Teams
Open the file hooks.json (if it's not there, create it)
Add the following to it: {"enableSso": false, "enableSsoMac": false}
That's it, now Teams desktop has the same authentication workflow as the browser version. Have a nice day.

How can I use local copy of MongoDB Synced Realm database while completely offline?

I am using MongoDB Realm Sync on my React Native app. When I start my app online and later disconnect internet, my realm works fine. I can see my data and also I can write data which syncs with server when I go back online. But when I start my app completely offline, my app does not show any data. From what I understand, realm is suppose to read local database and return data even when the app starts from complete offline. Isn't it ? How can I access my data when I start my app offline ? Below is my code I've used to sync with server.
const config = {
schema: [sessionSchema],
sync: {
user,
partitionValue: 'Test',
},
};
try {
Realm.open(config)
.then((openedRealm) => {
if (canceled) {
openedRealm.close();
return;
}
realmRef.current = openedRealm;
const syncSessions = openedRealm.objects('session');
openedRealm.addListener('change', () => {
setSessions([...syncSessions]);
});
setSessions([...syncSessions]);
}
} catch (e) {
console.log('ERROR', e);
}
const OpenRealmBehaviorConfiguration = {
type: "openImmediately",
}
const configuration = {
schema: [UserSchema],
sync: {
user: app.currentUser,
partitionValue: "user_1",
// Add this two lines below
newRealmFileBehavior: OpenRealmBehaviorConfiguration,
existingRealmFileBehavior: OpenRealmBehaviorConfiguration,
}
}
I found an answer for similar question here: https://developer.mongodb.com/community/forums/t/open-synced-local-database-when-completely-offline/11169/2
You can do something like:
async function getRealm() {
const app = new Realm.App("your-app-id");
if (app.currentUser) {
// A user had already logged in - open the Realm synchronously
return new Realm(getConfig(app.currentUser));
}
// We don't have a user - login a user and open the realm async
const user = await app.logIn(Realm.Credentials.anonymous());
return await Realm.open(getConfig(user));
}
function getConfig(user) {
return {
sync: {
user,
partitionValue: "my-partition"
}
};
}

Preload / Pre-populate PouchDB in React Native Application

Is it possible to preload / pre-populate a database in my React Native application and then the first time it is run, simply do a sync? I already have most, if not all of the database information before the app is distributed, it would be awesome if it just had to do a quick sync when the app is run. Any ideas how I would go about doing that?
I found this - https://pouchdb.com/2016/04/28/prebuilt-databases-with-pouchdb.html but it doesn't mention React Native
Using:
pouchdb-find: ^7.0.0
pouchdb-react-native: ^6.4.1
react: 16.3.1
react-moment: ^0.7.9
react-native: ~0.55.2
Thanks for any pointers.
Update Here is the code I'm using to try the loading of a dump file. This code exists in /screens/Home.js
The dump file is located in /client/dbfile/database.txt
var db = new PouchDB("cs1");
db.get("_local/initial_load_complete")
.catch(function(err) {
console.log("loading dumpfile");
if (err.status !== 404) {
// 404 means not found
throw err;
}
db.load("/client/dbfile/database.txt").then(function() {
return db.put({ _id: "_local/initial_load_complete" });
});
})
.then(function() {
// at this point, we are sure that
// initial replication is complete
console.log("loading is complete!");
return db.allDocs({ include_docs: true });
})
.then(
function(res) {
// display all docs for debugging purposes (empty)
console.log(res);
});
this.localDB = db;
When this runs my console displays this - showing there have been 0 rows added.
Object {
"offset": 0,
"rows": Array [],
"total_rows": 0,
}
Possible Unhandled Promise Rejection (id: 0):
Object {
"message": undefined,
"name": "unknown",
"status": 0,
}
In my project I have couple of db docs I distribute with app (translations JSON is the one good example).
So at app init I just try to read translations doc from db, if there is none - I import content from js module and store in db.
Then translations changes just being replicated from server to local db.
//transmob.js
const transMobFile = {
//content goes here
);
module.exports = transMobFile
//dbInit.js
import transMobFile from 'data/transMob';
..
PDB.getDoc('TransMob')
.then((doc)=> {
if (!doc) {
global.locales = transMobFile.localesMob; // locales
global.translations = transMobFile.langMob; // translations
return PDB.saveDoc('TransMob', transMobFile)
}
})
You can use react-native-fs to load a file from /android/app/src/main/assets. Just put the file into the assets folder and read it with RNFS.readFileAssets.
import PouchDB from 'pouchdb-core';
PouchDB
.plugin(require('pouchdb-find'))
.plugin(require('pouchdb-load'));
import RNFS from 'react-native-fs';
const localDB = new PouchDB("cs1", {adapter: 'asyncstorage'});
localDB.get("_local/initial_load_complete")
.catch(function(err) {
console.log("loading dumpfile");
if (err.status !== 404) {
// 404 means not found
throw err;
}
RNFS.readFileAssets('yourdb.txt', 'utf8')
.then((contents) => {
localDB.load(contents).then(function() {
return localDB.put({ _id: "_local/initial_load_complete" });
}).then(function() {
// at this point, we are sure that
// initial replication is complete
console.log("loading is complete!");
return localDB.allDocs({ include_docs: true }).then(
function(res) {
// display all docs for debugging purposes (empty)
console.log(res);
});
}, function(err) {
console.log(err);
});
})
})
You'll need to rebuild your project, reloading is not sufficient.
My project crashes when I attempt to load a 30MB file, so I probably will split it into a few smaller files. Check out https://github.com/pouchdb-community/pouchdb-load to see how this works if needed.
I found that the db.load() function from the pouchdb-load module requires a URL. I was pointing it to a file path on the device's filesystem. I placed my database.txt file on my server, changed it to use the url and it worked.
In my mind this isn't ideal because if they install the app and have slow wireless, it still has to pull the file from the server. It is still much faster than performing a full-on replicate when the app opens for the first time however.