Sending email notifications for Events via Google Calendar API - javascript

I'm using the calendar.events.insert API to add an Event to my Calendar via the PHP client.
The event is being inserted correctly along with appropriate values as set by the API.
The same however is not able to trigger an email invite to the attendees. I looked around to find that the request needs to set the param sendNotifications as true.
The same doesn't seem to help either.
Here is a sample code:
var request = gapi.client.calendar.events.insert({
"calendarId" : calendarData.id,
"sendNotifications": true,
"end": {
"dateTime": eventData.endTime
},
"start": {
"dateTime": eventData.startTime
},
"summary": eventData.eventName,
"attendees": jQuery.map(eventData.attendees, function(a) {
return {'email' : a};
}),
"reminders": {
"useDefault": false,
"overrides": [
{
"method": "email",
"minutes": 15
},
{
"method": "popup",
"minutes": 15
}
]
}
});
Where eventData and calendarData are appropriate objects.
Although my main problem is with email invites being sent the first time, I also tried (as can be seen above) to set a reminder (using overrides). While the popup works as expected, I didn't receive an email update in this case either.
This makes me wonder whether this may be a permission issue - something which I need to enable for my app perhaps (the user would understandably need to know if my app is sending emails on their behalf)?

In the Google API Documentation for inserting events, the "sendNotifications" option is actually a parameter. You might want to put it in the request parameters instead of the body.
In Meteor
Note: In my Meteor application, I did did the request by hand, and I'm still new to JavaScript. I'm not sure how you would do that in plain JavaScript or with the calendar API, so I'll just put the Meteor code, hope it helps although it's a bit off-topic.
var reqUrl = "https://www.googleapis.com/calendar/v3/calendars/primary/events";
var payload = {
'headers' : {
'Authorization': "Bearer " + token,
'Content-Type': 'application/json'
},
'params': {
'sendNotifications': true
},
'data': {
"summary": summary,
"location": "",
"start": {
"dateTime": start
},
"end": {
"dateTime": end
},
"attendees": [
{
"email": "*********#gmail.com"
}
]
}
};
Meteor.http.post(reqUrl, reqParams, function () {});

#linaa is correct. Just ran into this issue myself.
In JS, this would look like:
var request = gapi.client.calendar.events.insert(
sendNotifications: true,
{
// request body goes here
}
);

For this you should set the "remindOnRespondedEventsOnly" value to "true".
which means, Whether event reminders should be sent only for events with the user’s response status “Yes” and “Maybe”.
You can find this information here.
Hope that helps!

event = service.events().insert(calendarId='primary', body=event, sendUpdates='all').execute()
this will work

Related

Firebase messaging missing Authentication key in MongoDB trigger functions:

Please I need help. I don't know what I am doing wrong. I am trying to send push notification from http request but I keep getting this error:
The request was missing an Authentication Key. Please, refer to section "Authentication" of the FCM documentation, at https://firebase.google.com/docs/cloud-messaging/server.
I am currently doing this:
const response = await context.http.post({
url:"https://fcm.googleapis.com/fcm/send",
header:{"Content-Type": "application/json",
"Authorization":"key= Web Server Key"},
body:{
"to": usersPushToken, // From FirebaseMessaging.instance.getToken();
"notification": {
"title": "Title",
"body": "body",
"clickAction": 'FLUTTER_NOTIFICATION_CLICK',
"sound": 'default',
},
}
},
encodeBodyAsJSON: true,
});
My web server key (Cloud Messaging API (Legacy)) I also tried API key:
This was my fault (headers not header). But I will leave this answer for anyone using Flutter, MongoDB, and Firebase Messaging.
const response = await context.http.post({
url:"https://fcm.googleapis.com/fcm/send",
"headers":{"Content-Type": ["application/json"], //Must be in array
"Authorization":["key= Web Server Key"]}, //Must be in array
"body":{
"to": usersPushToken, // From FirebaseMessaging.instance.getToken();
"notification": {
"title": "Title",
"body": "body",
"clickAction": 'FLUTTER_NOTIFICATION_CLICK',
"sound": 'default',
},
}
},
encodeBodyAsJSON: true,
});

How do I query an index properly with Dynamoose

I'm using Dynamoose to simplify my interactions with DynamoDB in a node.js application. I'm trying to write a query using Dynamoose's Model.query function that will search a table using an index, but it seems like Dynamoose is not including all of the info required to process the query and I'm not sure what I'm doing wrong.
Here's what the schema looks like:
const UserSchema = new dynamoose.Schema({
"user_id": {
"hashKey": true,
"type": String
},
"email": {
"type": String,
"index": {
"global": true,
"name": "email-index"
}
},
"first_name": {
"type": String,
"index": {
"global": true,
"name": "first_name-index"
}
},
"last_name": {
"type": String,
"index": {
"global": true,
"name": "last_name-index"
}
}
)
module.exports = dynamoose.model(config.usersTable, UserSchema)
I'd like to be able to search for users by their email address, so I'm writing a query that looks like this:
Users.query("email").contains(query.email)
.using("email-index")
.all()
.exec()
.then( results => {
res.status(200).json(results)
}).catch( err => {
res.status(500).send("Error searching for users: " + err)
})
I have a global secondary index defined for the email field:
When I try to execute this query, I'm getting the following error:
Error searching for users: ValidationException: Either the KeyConditions or KeyConditionExpression parameter must be specified in the request.
Using the Dynamoose debugging output, I can see that the query winds up looking like this:
aws:dynamodb:query:request - {
"FilterExpression": "contains (#a0, :v0)",
"ExpressionAttributeNames": {
"#a0": "email"
},
"ExpressionAttributeValues": {
":v0": {
"S": "mel"
}
},
"TableName": "user_qa",
"IndexName": "email-index"
}
I note that the actual query sent to DynamoDB does not contain KeyConditions or KeyConditionExpression, as the error message indicates. What am I doing wrong that prevents this query from being written correctly such that it executes the query against the global secondary index I've added for this table?
As it turns out, calls like .contains(text) are used as filters, not query parameters. DynamoDB can't figure out if the text in the index contains the text I'm searching for without looking at every single record, which is a scan, not a query. So it doesn't make sense to try to use .contains(text) in this context, even though it's possible to call it in a chain like the one I constructed. What I ultimately needed to do to make this work is turn my call into a table scan with the .contains(text) filter:
Users.scan({ email: { contains: query.email }}).all().exec().then( ... )
I am not familiar with Dynamoose too much but the following code below will do an update on a record using node.JS and DynamoDB. See the key parameter I have below; by the error message you got it seems you are missing this.
To my knowledge, you must specify a key for an UPDATE request. You can checks the AWS DynamoDB docs to confirm.
var params = {
TableName: table,
Key: {
"id": customerID,
},
UpdateExpression: "set customer_name= :s, customer_address= :p, customer_phone= :u, end_date = :u",
ExpressionAttributeValues: {
":s": customer_name,
":p": customer_address,
":u": customer_phone
},
ReturnValues: "UPDATED_NEW"
};
await docClient.update(params).promise();

webauthn authentication javascript formatting assistance

I have been trying to figure out how to do 2fa with webauthn and I have the registration part working. The details are really poorly documented, especially all of the encoding payloads in javascript. I am able to register a device to a user, but I am not able to authenticate with that device. For reference, I'm using these resources:
https://github.com/cedarcode/webauthn-ruby
https://www.passwordless.dev/js/mfa.register.js
And specifically, for authentication, I'm trying to mimic this js functionality:
https://www.passwordless.dev/js/mfa.register.js
In my user model, I have a webauthn_id, and several u2f devices, each of which has a public_key and a webauthn_id.
In my Rails app, I do:
options = WebAuthn::Credential.options_for_get(allow: :webauthn_id)
session[:webauthn_options] = options
In my javascript, I try to mimic the js file above and I do (this is embedded ruby):
options = <%= raw #options.as_json.to_json %>
options.challenge = WebAuthnHelpers.coerceToArrayBuffer(options.challenge);
options.allowCredentials = options.allowCredentials.map((c) => {
c.id = WebAuthnHelpers.coerceToArrayBuffer(c.id);
return c;
});
navigator.credentials.get({ "publicKey": options }).then(function (credentialInfoAssertion)
{
// send assertion response back to the server
// to proceed with the control of the credential
alert('here');
}).catch(function (err)
{
debugger
console.error(err); /* THIS IS WHERE THE ERROR IS THROWN */
});
The problem is, I cannot get past navigator.credentials.get, I get this error in the javascript console:
TypeError: CredentialsContainer.get: Element of 'allowCredentials' member of PublicKeyCredentialRequestOptions can't be converted to a dictionary
options at the time navigator.credentials.get is called looks like this:
I've tried every which way to convert my db-stored user and device variables into javascript properly encoded and parsed variables but cannot seem to get it to work. Anything obvious about what I'm doing wrong?
Thanks for any help,
Kevin
UPDATE -
Adding options json generated by the server:
"{\"challenge\":\"SSDYi4I7kRWt5wc5KjuAvgJ3dsQhjy7IPOJ0hvR5tMg\",\"timeout\":120000,\"allowCredentials\":[{\"type\":\"public-key\",\"id\":\"OUckfxGNLGGASUfGiX-1_8FzehlXh3fKvJ98tm59mVukJkKb_CGk1avnorL4sQQASVO9aGqmgn01jf629Jt0Z0SmBpDKd9sL1T5Z9loDrkLTTCIzrIRqhwPC6yrkfBFi\"},{\"type\":\"public-key\",\"id\":\"Fj5T-WPmEMTz139mY-Vo0DTfsNmjwy_mUx6jn5rUEPx-LsY51mxNYidprJ39_cHeAOieg-W12X47iJm42K0Tsixj4_Fl6KjdgYoxQtEYsNF-LPhwtoKwYsy1hZgVojp3\"}]}"
This is an example of the serialised JSON data returned by our implementation:
{
"challenge": "MQ1S8MBSU0M2kiJqJD8wnQ",
"timeout": 60000,
"rpId": "identity.acme.com",
"allowCredentials": [
{
"type": "public-key",
"id": "k5Ti8dLdko1GANsBT-_NZ5L_-8j_8TnoNOYe8mUcs4o",
"transports": [
"internal"
]
},
{
"type": "public-key",
"id": "LAqkKEO99XPCQ7fsUa3stz7K76A_mE5dQwX4S3QS6jdbI9ttSn9Hu37BA31JUGXqgyhTtskL5obe6uZxitbIfA",
"transports": [
"usb"
]
},
{
"type": "public-key",
"id": "nbN3S08Wv2GElRsW9AmK70J1INEpwIywQcOl6rp_DWLm4mcQiH96TmAXSrZRHciZBENVB9rJdE94HPHbeVjtZg",
"transports": [
"usb"
]
}
],
"userVerification": "discouraged",
"extensions": {
"txAuthSimple": "Sign in to your ACME account",
"exts": true,
"uvi": true,
"loc": true,
"uvm": true
}
}
This is parsed to an object and the code used to coerce those base64url encoded values is:
credentialRequestOptions.challenge = WebAuthnHelpers.coerceToArrayBuffer(credentialRequestOptions.challenge);
credentialRequestOptions.allowCredentials = credentialRequestOptions.allowCredentials.map((c) => {
c.id = WebAuthnHelpers.coerceToArrayBuffer(c.id);
return c;
});
Hope that helps. The JSON data is retreived via a fetch() call and the byte[] fields are encoded as base64url on the serverside.

Skip Chromecast selection when sending from Google Chrome

I'm trying to send data to a chromecast, but I would like to send the data to a certain Chromecast directly, without selecting it in the Google Chrome.
I would like to skip the Chromecast selection before sending data.
This is want to avoid.
I dont want to select the cast but directly cast the data to it.
I've been checking the session object that we get from chrome.cast.initialize and it return something like this:
{
"sessionId": "b59f1754-fd13-48cd-b237-4952a69cade4",
"appId": "5B797F56",
"displayName": "url-cast-sender",
"statusText": "URL Cast ready...",
"receiver": {
"label": "rTflOUigItAIYPwoZZ87Uv5oK8yI.",
"friendlyName": "Sala de Juntas",
"capabilities": [
"video_out",
"audio_out"
],
"volume": {
"controlType": "attenuation",
"level": 1,
"muted": false,
"stepInterval": 0.05000000074505806
},
"receiverType": "cast",
"isActiveInput": null,
"displayStatus": null
},
"senderApps": [],
"namespaces": [
{
"name": "urn:x-cast:com.google.cast.debugoverlay"
},
{
"name": "urn:x-cast:com.url.cast"
}
],
"media": [],
"status": "connected",
"transportId": "b59f1754-fd13-48cd-b237-4952a69cade4"
};
As you can see there is label there, I've been trying to work with it but nothing.
The way the page request the connection to a chromecast is the following:
// click handlers
document.getElementById('requestSession').onclick = function () {
chrome.cast.requestSession(sessionListener, onErr);
};
Which seems to be the part that opens the selection alert in Google Chrome.
My work is a fork from url-cast-receiver and you can check a demo here.
Turns out it is not possible from the frontend part.
So I ended up using a library called SharpCaster created by Tapanila, in which there is a controller that allows you to do this kind of stuff, here you can find an example of it.
Had some trouble to make it work and also opened an issue in the repository, but ended up fixing it myself, issue #141.
WebPageCastingTester.cs
using System.Linq;
using System.Threading.Tasks;
using SharpCaster.Controllers;
using SharpCaster.Services;
using Xunit;
namespace SharpCaster.Test
{
public class WebPageCastingTester
{
private ChromecastService _chromecastService;
public WebPageCastingTester()
{
_chromecastService = ChromecastService.Current;
var device = _chromecastService.StartLocatingDevices().Result;
_chromecastService.ConnectToChromecast(device.First()).Wait(2000);
}
[Fact]
public async void TestingLaunchingSharpCasterDemo()
{
var controller = await _chromecastService.ChromeCastClient.LaunchWeb();
await Task.Delay(4000);
Assert.NotNull(_chromecastService.ChromeCastClient.ChromecastStatus.Applications.First(x => x.AppId == WebController.WebAppId));
await controller.LoadUrl("https://www.windytv.com/");
await Task.Delay(4000);
Assert.Equal(_chromecastService.ChromeCastClient.ChromecastStatus.Applications.First(x => x.AppId == WebController.WebAppId).StatusText,
"Now Playing: https://www.windytv.com/");
}
}
}

Google Maps Geo giving JSONP error Unexpected token : or invalid label

We're trying to get information of a user based on the lat longitude.
Our code has been working fine until a couple weeks ago when we started getting this error.
Here is our code:
var reverse_geo_url = "http://maps.google.com/maps/geo?q=" + lat + "," + lng + "&key=[key]&sensor=false"
console.log("Calling " + reverse_geo_url);
new $.ajax(reverse_geo_url, {
dataType: "jsonp",
timeout: 5000,
success: function (data) {
// yay
}
});
Problem is that we all of a sudden are getting
Uncaught SyntaxError: Unexpected token :
Here is an example response from Google's servers (when I go directly to the url)
{
"name": "33.0024912,-88.4218782",
"Status": {
"code": 200,
"request": "geocode"
},
"Placemark": [ {
"id": "p1",
"address": "Paulette Rd, Macon, MS 39341, USA",
"AddressDetails": {
"Accuracy" : 6,
"Country" : {
"AdministrativeArea" : {
"AdministrativeAreaName" : "MS",
"Locality" : {
"LocalityName" : "Macon",
"PostalCode" : {
"PostalCodeNumber" : "39341"
},
"Thoroughfare" : {
"ThoroughfareName" : "Paulette Rd"
}
}
},
"CountryName" : "USA",
"CountryNameCode" : "US"
}
},
"ExtendedData": {
"LatLonBox": {
"north": 32.9994289,
"south": 32.9891822,
"east": -88.4094885,
"west": -88.4393238
}
},
"Point": {
"coordinates": [ -88.4238788, 32.9952338, 0 ]
}
} ]
}
https://developers.google.com/maps/documentation/javascript/geocoding#GeocodingResponses
Accessing the Geocoding service is asynchronous, since the Google Maps
API needs to make a call to an external server. For that reason, you
need to pass a callback method to execute upon completion of the
request. This callback method processes the result(s). Note that the
geocoder may return more than one result.
According to the documentation callback is supposed to be supported. JQuery adds that callback header so I don't get why Google isn't honoring it.
*Edit: For reference, the url that my app tries to call is http://maps.google.com/maps/geo?q=33.8024912,-84.4218782&key=[my key here]&sensor=false&callback=jQuery16409036452900618315_1335293866369&_=1335293866469
Is this something on Google's side? Or is something on our side? Again, this code used to work perfectly.
Other posts that I've seen on StackOverFlow, people are saying that when this error shows up in means that the server doesn't support JSONP... What's confusing to me is that this used to work... Did google change their API?
Out of curiosity, why are you doing ajax calls to do geocoding? You could be using the Google Maps API directly and more simply: https://developers.google.com/maps/documentation/javascript/geocoding
Reading through the docs it seems you don't need to register any more to use this api,
I used this successfully :
var url = string.Format("http://maps.google.com/maps/geo?q={0}&output=xml", encodedPostCode);
Hope this helps

Categories