Offline data retrieval in a Cordova Windows project - visual-studio

I am having difficulties using the Kapsel OData plugin to retrieve data from a store when the device is offline.
Here is the situation :
Cordova application for Windows platform
When the app opens, I start by opening a store against my OData service (similar to the Northwind service)
The store is created and opened. I then try and retrieve data from the store using OData.read or by setting a model and then calling read() on it.
The store will successfully open. However, my call to read the data will succeed when the device is online, and fail when it is offline, no matter which of the two previous methods I use.
Here is my code :
function openStore() {
var properties = {
"name": "Emergency",
"host": applicationContext.registrationContext.serverHost,
"port": applicationContext.registrationContext.serverPort,
"https": applicationContext.registrationContext.https,
"serviceRoot": appId,
"definingRequests": {
"Products": "/Products"
}
};
store = sap.OData.createOfflineStore(properties);
store.open(openStoreSuccessCallback, errorCallback);
}
function openStoreSuccessCallback() {
sap.OData.applyHttpClient();
retrieveWithModel();//retrieveWithOData();
}
function retrieveWithModel() {
var uri = applicationContext.applicationEndpointURL;
var user = applicationContext.registrationContext.user;
var password = applicationContext.registrationContext.password;
var headers = { "X-SMP-APPCID": applicationContext.applicationConnectionId };
var oModel = new sap.ui.model.odata.ODataModel(uri, {
json: "true",
user: user,
password: password,
headers: headers
});
sap.ui.getCore().setModel(oModel);
oModel.read("/Products", {
success: function (oEvent) {
var msg = new Windows.UI.Popups.MessageDialog("Success");
msg.showAsync();
},
error: function (err) {
console.log("you have failed");
var msg = new Windows.UI.Popups.MessageDialog("Fail");
msg.showAsync();
}
});
}
function retrieveWithOData() {
var sURL = applicationContext.applicationEndpointURL + "/Products";
var oHeaders = {};
oHeaders['Authorization'] = authStr;
oHeaders['X-SMP-APPCID'] = applicationContext.applicationConnectionId;
//oHeaders['Content-Type'] = "application/json";
//oHeaders['X-CSRF-Token'] = "FETCH";
var request = {
headers: oHeaders,
requestUri: sURL,
method: "GET"
};
OData.read(request,
function (data, response) {
console.log('Success');
},
function (err) {
console.log('Fail');
}
);
}
Kapsel SDK version is 3.8.0
SMP SDK is SP08
Cordova version 5.3.3
I am wondering if this is an issue with the way the app is launched. I need a way to open the same instance of the application every time, so the offline store will be kept with all its data. Because Cordova-generated Visual Studio projects do not generate an .exe file (only .appx files which would need to be signed and sideloaded to be used), the way I proceed is : I run the application in online mode from Visual Studio, then pin it to the taskbar or start menu, close it and switch the device to offline mode, and reopen it from the task bar.
However, more and more it seems like this method does not work as expected.
Can anyone confirm that a Visual Studio project, opened from the taskbar, should run the same way as when it is run from VS, with the same dependencies, libraries etc? If such is the case (and I can't really imagine why it wouldn't be), does anyone have any experience with these technologies and see what a potential issue could be?
Any help would be greatly appreciated.
Thanks!

Ok I found the solution to my problem. In case anyone ever encounters the same issue, the problem was that my offline store was not being used (you can see with Fiddler that there are outbound requests to the backend system even in offline mode).
The Visual studio project does keep the store from one build or launch to the next.

Related

handleMessageError when registering Teams connector

I'm developing a Microsoft Teams custom app that can add connectors to Teams channels.
My connector has been working fine for a few months now, but a few weeks ago, the ability to register new connectors has stopped working:
After clicking “Save” on the connector configuration page, “loading” shows up until it times out (see the console screenshot below).
When I look in the browser console, I see that the outbound request was actually successful and notifySuccess() was called on the save event, but Teams does not register it (see full JS code below).
Also, a handleMessageError message is emitted, but I could not figure out what the issue is.
I tried this in the native app and in Chrome, and a client tried it in another instance of Teams as well.
Is this a bug or a (undocumented?) change in the Teams API?
Console / UI screenshot
JSON Error Message:
{
"seq": 1615787354693,
"timestamp": 1615793440583,
"flightSettings": {
"Name": "ConnectorFrontEndSettings",
"AriaSDKToken": "d127f72a3abd41c9b9dd94faca947689-d58285e6-3a68-4cab-a458-37b9d9761d35-7033",
"SPAEnabled": true,
"ClassificationFilterEnabled": true,
"ClientRoutingEnabled": true,
"EnableYammerGroupOption": true,
"EnableFadeMessage": false,
"EnableDomainBasedOwaConnectorList": false,
"EnableDomainBasedTeamsConnectorList": false,
"DevPortalSPAEnabled": true,
"ShowHomeNavigationButtonOnConfigurationPage": false,
"DisableConnectToO365InlineDeleteFeedbackPage": true
},
"status": 500,
"clientType": "SkypeSpaces",
"connectorType": "fc0ee140-b62a-4947-9af1-d19a66a00af8",
"name": "handleMessageError"
}
JS code that runs on the connector's configuration page:
const XHR = new XMLHttpRequest();
const subscriptionApiUrl = "https://XYZ.execute-api.us-east-1.amazonaws.com/Prod/subscriptions/";
const channelsApiBaseURL = "https://www.example.com/api/library/v2/channels/";
const defaultChannelParameters = "sorting=latest&language=en&excludeReviews=true";
const url = new URL(window.location.href);
const clientId = url.searchParams.get("clientid");
const clientSecret = url.searchParams.get("clientsecret");
const teamsSettings = {
entityId: "Example",
contentUrl: "https://www.example.com/xyz",
configName: "Example"
};
var saveEvent;
console.log("Example Connector initializing");
microsoftTeams.initialize();
microsoftTeams.settings.setValidityState(true); // make Save button enabled
microsoftTeams.settings.registerOnSaveHandler(handleSaveEvent);
function handleSaveEvent(e) {
saveEvent = e;
microsoftTeams.settings.setSettings(teamsSettings);
microsoftTeams.settings.getSettings(storeSettings);
}
function storeSettings(settings) {
XHR.addEventListener("load", reportSuccess);
XHR.addEventListener("error", reportFailure);
XHR.open("POST", subscriptionApiUrl);
XHR.setRequestHeader("Content-Type", "application/json");
XHR.send(composePayload(settings.webhookUrl));
console.log("Request to store Example Connector sent");
}
function composePayload(webhookUrl) {
return JSON.stringify({
webhookUrl: webhookUrl,
gaChannelUrl: channelsApiBaseURL + document.getElementById("ga-channel-id").value + "/items?" + defaultChannelParameters,
gaClientId: clientId,
gaClientSecret: clientSecret,
cronSchedule: "0 " + document.getElementById("time").value + " * * " + document.getElementById("frequency"),
postNow: document.getElementById("post-now").checked ? true : false
});
}
function reportSuccess(e) {
console.log("Example Connector registered!");
saveEvent.notifySuccess();
}
function reportFailure(e) {
let msg = "Could not connect to subscription API.";
console.log(msg);
saveEvent.notifyFailure(msg);
}
I got the same error. I registered the connector and downloaded the generated manifest.json then packaged (with icons) and tried to sideload the zip. I got the same error when trying to "Save".
I then tried to edit the generated manifest using the App Studio (App Studio -> Import an existing app) and this time I got a meaningful error saying the property needsIdentity is not valid according the schema from the manifest (https://developer.microsoft.com/en-us/json-schemas/teams/v1.3/MicrosoftTeams.schema.json)
Removing this property fixed the issue and I was able to save the connector configuration.
I could not find any documentation about this property. I checked the last version of the schema by now (1.8) and it's not there !!
I created an issue : https://github.com/MicrosoftDocs/msteams-docs/issues/2949

Is there a way to tell if your app is running in Microsoft Teams

I have a web app that needs to execute specific code if it is running in Microsoft Teams, however I haven't yet figured out if there is any way to tell if your app is running in teams. Any ideas or insight?
edit:
for anyone wondering we ended up using a combination of the two answers below, on app start it will check the url of the app to see if it contains "/teams". The teams app is told specifically to point to {app_name}/teams, if this case is true it will run the following code block:
import * as microsoftTeams from '#microsoft/teams-js';
if (window.location.pathname.includes('teams')) {
microsoftTeams.initialize(() => {
microsoftTeams.getContext(context => {
store.dispatch(teamsDetected(context.hostClientType!));
try {
microsoftTeams.settings.registerOnSaveHandler(saveEvent => {
microsoftTeams.settings.setSettings({
websiteUrl: window.location.href,
contentUrl: `${window.location.href}&teams`,
entityId: context.entityId,
suggestedDisplayName: document.title
});
saveEvent.notifySuccess();
});
microsoftTeams.settings.setValidityState(true);
} catch (err) {
console.error('failed to set teams settings')
}
});
});
}
As you have probably experienced, a call to microsoftTeams.getContext(...) never returns if you are not in Teams.
So I have a flag that I monitor with a setInterval and if this._teamsContext is truthy, and has sane values; and only if if has this._hasAttemptedConnection
It is a bit of a round-a-bout way.
Another mechanism I implemented a little later was passing in a flag with the URL entrypoint (in our case: this is a Teams Tab) https://<oururl>?context=teams and only using the Teams codepath when in Teams.
I have seen requests in the Microsoft Teams .js github to return a failure from the microsoftTeams.getContext(...) refer: is there any API to detect running in Teams or not?
Prior to the flag, I had some Typescript code that looks like
WireTeams(): Promise<boolean> {
this._hasAttemptedConnection = false
return new Promise<boolean>((resolve, reject) => {
microsoftTeams.initialize()
microsoftTeams.getContext((context) => {
if (context === null || context === undefined) {
resolve(false)
}
this._teamsContext = context
})
})
this._hasAttemptedConnection = true
}
As of 2022, Microsoft released version 2.0 of teams-js library. You can check https://www.npmjs.com/package/#microsoft/teams-js. You can now use the app module to check whether it is initialized.
import { app } from '#microsoft/teams-js';
bool initialized = app.isInitialized()

After updating nativescript folder and files are not creating in my android phone

I'm able to create a folder if it not exists and save a newly written file in that folder previously. but after updating to latest nativescript the same code was not working and not give error properly.
and also I'm getting an error
Error: android.util.AndroidRuntimeException: Calling startActivity() from >outside of an Activity context requires the FLAG_ACTIVITY_NEW_TASK flag. >Is this really what you want?
const fileSystemModule = require("tns-core-modules/file-system");
const documents = fileSystemModule.knownFolders.documents();
documents._path = "/storage/emulated/0/";
const folder = documents.getFolder('Reports/sample/');
const file = folder.getFile('fileName.xlsx');
file.writeText(viewModel.get("fileTextContent") || html_content)
.then((result) => {
return file.readText()
.then((res) => {
var toast = Toast.makeText("Exported to Excel Succesfully");
toast.show();
return res;
});
}).then((result) => {
console.log("---result---");
console.log(result); // im getting result, a html string
var intent = new android.content.Intent(android.content.Intent.ACTION_VIEW);
intent.setDataAndType(android.net.Uri.fromFile(new java.io.File(file._path)), "application/vnd.ms-excel");
application.android.context.startActivity(android.content.Intent.createChooser(intent, "Open Excel..."));
}).catch((err) => {
console.log(err);
});
before updating it was working fine. but now I don't know what happened to this.
It's a new requirement from Android itself. You must add FLAG_ACTIVITY_NEW_TASK flag to your intent.
With Android 9, you cannot start an activity from a non-activity context unless you pass the intent flag FLAG_ACTIVITY_NEW_TASK. If you attempt to start an activity without passing this flag, the activity does not start, and the system prints a message to the log.
intent.addFlags(android.content.Intent.FLAG_ACTIVITY_NEW_TASK);

How to update an User with useMasterKey in Parse

Issue Description
I'm trying to update an User when another user click on my Xamarin button.
Then, I used Cloud Code to perform this but it doesnt work
My Code
Here is my complete JS code :
Parse.Cloud.beforeSave("Archive", function(request, response) {
Parse.serverURL = 'https://pg-app-0brffxkawi8lqvf2eyc2isqrs66zsu.scalabl.cloud/1/';
var status = request.object.get("status");
if (status == "validated") {
var event = request.object.get("event");
event.fetch({
success: function(myEvent) {
var coinsEvent = myEvent.get("coins");
var user = request.object.get("user");
user.fetch({
success: function(myUser, coinsEvent, user) {
var email = myUser.get("email");
var coinsUser = myUser.get("coins");
myUser.set("coins", coinsUser + coinsEvent);
return myUser.save(null, {useMasterKey:true});
}
});
}
});
}
response.success();
});
I think myUser.save(null, {useMasterKey:true}); should work
I actually have that error :
Dec 24, 2017, 12:27 GMT+1 - ERRORError generating response for [PUT] /1/classes/_User/1GPcqmn6Hd
"Cannot modify user 1GPcqmn6Hd."
{
"coins": 250
}
Environment Setup
Server
parse-server version : v2.3.3
Server: Sashido
Your success branch never calls response.success() which is a problem... though maybe not THE problem.
You are also doing 2 fetches inside a 'beforeSave' function which is not recommended. 'BeforeSave' must happen very quickly and fetches take time. I would consider thinking through other options.
If you really need to do it this way, consider doing a Parse.Query("event") with an include("user") and trigger the query with query.first({useMasterKey:true}).
Are you sure coinsEvent is what you think it is? Fetch only returns the object fetched... not sure that you can curry in other parameters. I would change your final success routine to (double checking that coinsEvent is valid):
success: function(myUser) {
var coinsUser = myUser.get("coins");
myUser.set("coins", coinsUser + coinsEvent);
return myUser.save(null, {useMasterKey:true}).then(_ => response.success());
}

Node.js Express mongoose query find

I have a little problem with Express and mongoose using Node.js . I pasted the code in pastebin, for a better visibility.
Here is the app.js: http://pastebin.com/FRAFzvjR
Here is the routes/index.js: http://pastebin.com/gDgBXSy6
Since the db.js isn't big, I post it here:
var mongoose = require('mongoose'),
Schema = mongoose.Schema;
module.exports = function () {
mongoose.connect('mongodb://localhost/test',
function(err) {
if (err) { throw err; }
}
);
};
var User = new Schema({
username: {type: String, index: { unique: true }},
mdp: String
});
module.exports = mongoose.model('User', User);
As you can see, I used the console.log to debug my app, and I found that, in routes/index.js, only the a appeared. That's weird, it's as if the script stopped (or continue without any response) when
userModel.findOne({username: req.body.username}, function(err, data)
is tried.
Any idea?
You never connect to your database. Your connect method is within the db.export, but that is never called as a function from your app.
Also, you are overwriting your module.exports - if you want multiple functions/classes to be exported, you must add them as different properties of the module.export object. ie.:
module.export.truthy = function() { return true; }
module.export.falsy = function() { return false; }
When you then require that module, you must call the function (trueFalse.truthy();) in order to get the value. Since you never execute the function to connect to your database, you are not recieveing any data.
A couple of things real quick.
Make sure you're on the latest mongoose (2.5.3). Update your package.json and run npm update.
Try doing a console.log(augments) before your if (err). It's possible that an error is happening.
Are you sure you're really connecting to the database? Try explicitly connecting at the top of your file (just for testing) mongoose.connect('mongodb://localhost/my_database');
I'll update if I get any other ideas.

Resources