Request_BadRequest in O365 - javascript

I am trying to send a email with the help of O365. I have configured everything but I am getting a error
GraphError { statusCode: 405, code: 'Request_BadRequest',
message: 'Specified HTTP method is not allowed for the request
target.', requestId: '34f321-57de-4483-b97d-5957f8786ecb', date:
2019-09-16T00:17:53.000Z, body:
'{"code":"Request_BadRequest","message":"Specified HTTP method is not
allowed for the request
target.","innerError":{"request-id":"34f803b1-57de-4483-b97d-5957f8786ecb","date":"2019-09-16T05:47:51"}}'
}
Code
const APP_ID = "XXXXXXXXXXXXXXXXXX";
const APP_SECERET = "XXXXXXXXXXXXXX";
const TENANT_ID = "XXXXXXXXXXXXXXXX";
const TOKEN_ENDPOINT = "https://login.microsoftonline.com/XXXXXXXXXXXXXXXXXXXXX/oauth2/v2.0/token";
const MS_GRAPH_SCOPE = "https://graph.microsoft.com/.default";
const GRANT_TYPE = "client_credentials";
const graphScopes = ["User.Read", "Mail.Send"]; // An array of graph scopes
const request = require("request");
const endpoint = TOKEN_ENDPOINT;
const requestParams = {
grant_type: GRANT_TYPE,
client_id: APP_ID,
client_secret: APP_SECERET,
scope: MS_GRAPH_SCOPE
};
request.post({
url: endpoint,
form: requestParams
}, function(err, response, body) {
if (err) {
console.log("error");
} else {
// console.log(response);
// console.log("Body=" + body);
let parsedBody = JSON.parse(body);
if (parsedBody.error_description) {
console.log("Error=" + parsedBody.error_description);
} else {
console.log("Access Token=" + parsedBody.access_token);
// testGraphAPI(parsedBody.access_token);
let accessToken = parsedBody.access_token;
getMe(accessToken);
}
}
});
function getMe(accessToken) {
require("isomorphic-fetch");
const fs = require("fs");
const MicrosoftGraph = require("#microsoft/microsoft-graph-client").Client;
const options = {
defaultVersion: "v1.0",
debugLogging: true,
authProvider: (done) => {
done(null, accessToken);
},
};
// https://github.com/microsoftgraph/msgraph-sdk-javascript/blob/dev/samples/node/main.js
// https://learn.microsoft.com/en-us/graph/overview
const client = MicrosoftGraph.init(options);
// send an email
const sendMail = {
message: {
subject: "Test o365 api from node",
body: {
contentType: "Text",
content: "Testing api."
},
toRecipients: [{
emailAddress: {
address: "test#abc.com"
}
}],
ccRecipients: [{
emailAddress: {
address: "test#abc.com"
}
}]
},
saveToSentItems: "false"
};
client.api('/users/test1#abc.onmicrosoft.com ').post(sendMail).then((res) => {
console.log(res);
}).catch((err) => {
console.log(err);
});
}
Can someone tell me where I am going wrong. Please help me out

I had the same error and it was a malformed url when sending to the users.
I think your url should be /users/test1#abc.onmicrosoft.com/sendMail

Related

Amplify lambda function "Not Authorized to access [function] on type [model]"

I am following the explanations from this website: https://aws.amazon.com/de/getting-started/hands-on/build-flutter-mobile-app-part-two/module-four/
If I start the application, a profile is not created, which should be happening in "custom.js".
const { Sha256 } = require("#aws-crypto/sha256-js");
const { defaultProvider } = require("#aws-sdk/credential-provider-node");
const { SignatureV4 } = require("#aws-sdk/signature-v4");
const { HttpRequest } = require("#aws-sdk/protocol-http");
const { default: fetch, Request } = require("node-fetch");
const GRAPHQL_ENDPOINT = process.env.API_AMPLIFYTRIPSPLANNER_GRAPHQLAPIENDPOINTOUTPUT;
const AWS_REGION = process.env.AWS_REGION || 'us-east-1';
const query = /* GraphQL */ `
mutation createProfile($email: String!,$owner: String!) {
createProfile(input: {
email: $email,
owner: $owner,
}) {
email
}
}
`;
/**
* #type {import('#types/aws-lambda').PostConfirmationTriggerHandler}
*/
exports.handler = async (event) => {
console.log(`EVENT: ${JSON.stringify(event)}`);
const variables = {
email: event.request.userAttributes.email,
owner: `${event.request.userAttributes.sub}::${event.userName}`
};
const endpoint = new URL(GRAPHQL_ENDPOINT);
const signer = new SignatureV4({
credentials: defaultProvider(),
region: AWS_REGION,
service: 'appsync',
sha256: Sha256
});
const requestToBeSigned = new HttpRequest({
method: 'POST',
headers: {
'Content-Type': 'application/json',
host: endpoint.host
},
hostname: endpoint.host,
body: JSON.stringify({ query, variables }),
path: endpoint.pathname
});
const signed = await signer.sign(requestToBeSigned);
const request = new Request(endpoint, signed);
let statusCode = 200;
let body;
let response;
try {
response = await fetch(request);
body = await response.json();
if (body.errors) statusCode = 400;
} catch (error) {
statusCode = 500;
body = {
errors: [
{
message: error.message
}
]
};
}
console.log(`statusCode: ${statusCode}`);
console.log(`body: ${JSON.stringify(body)}`);
return {
statusCode,
body: JSON.stringify(body)
};
};
I was expecting the profile to be created, when I run the application. But there is no profile created.
Cloud watch is providing this error log message:
{
"data": {
"createProfile": null
},
"errors": [
{
"path": [
"createProfile"
],
"data": null,
"errorType": "Unauthorized",
"errorInfo": null,
"locations": [
{
"line": 3,
"column": 6,
"sourceName": null
}
],
"message": "Not Authorized to access createProfile on type Profile"
}
]
}
I am trying to understand the two problems:
The data should not be null
There should not be an authorization problem (which maybe a follow-on from the data issue)
I have not found any useful hints yet.
What needs to be changed?
I now realized my error. I did not follow the instructions to start the second tuturial within a clean directory. The Amplify configuration required a change in the Auth module, that can only be implemented in a new project (you cannot change auth type after deploying an app).

Cant't access media_id_string in JS Mastodon-Bot

I want to write a small bot for Mastodon to toot images.
const Mastodon = require('mastodon-api');
const fs = require('fs');
console.log("Hallo");
const T = new Mastodon({
client_key: 'xxx',
client_secret: 'xxx',
access_token: 'xxx',
timeout_ms: 60*1000,
api_url: 'https://xxx/api/v1/'
})
const params ={
status:"Hallo"
}
var b64content = fs.readFileSync('./xxx.png', { encoding: 'base64' })
T.post('media/upload', { media: b64content }, params, (error, data) => {
if (error) {
console.error(error);
}else{
console.log(data);
}
});
var mediaIdStr = data.media_id_string;
params = { status: 'Hallo', media_ids: [mediaIdStr] }
T.post('statuses/update', params, function (err, data, response) {
console.log(data);
});
But I get the error message:
var mediaIdStr = data.media_id_string;
^
ReferenceError: data is not defined
How can I access media_id_string? Am grateful for any tip.

Firestore getSignedUrl() give The caller does not have permission at Gaxios

I got following error at file.getSignedUrl. I have other function to copy the file and create new file on Cloud Storage. Why this function need permission and where do I need to set?
Error: The caller does not have permission at Gaxios._request (/layers/google.nodejs.yarn/yarn_modules/node_modules/gaxios/build/src/gaxios.js:129:23) at runMicrotasks () at processTicksAndRejections (node:internal/process/task_queues:96:5) at async Compute.requestAsync (/layers/google.nodejs.yarn/yarn_modules/node_modules/google-auth-library/build/src/auth/oauth2client.js:368:18) at async GoogleAuth.signBlob (/layers/google.nodejs.yarn/yarn_modules/node_modules/google-auth-library/build/src/auth/googleauth.js:662:21) at async sign (/layers/google.nodejs.yarn/yarn_modules/node_modules/#google-cloud/storage/build/src/signer.js:103:35) { name: 'SigningError' }
const functions = require("firebase-functions");
const axios = require("axios");
const { Storage } = require("#google-cloud/storage");
const storage = new Storage();
// Don't forget to replace with your bucket name
const bucket = storage.bucket("projectid.appspot.com");
async function getAlbums() {
const endpoint = "https://api.mydomain.com/graphql";
const headers = {
"content-type": "application/json",
};
const graphqlQuery = {
query: `query Albums {
albums {
id
album_cover
}
}`,
};
const response = await axios({
url: endpoint,
method: "post",
headers: headers,
data: graphqlQuery,
});
if (response.errors) {
functions.logger.error("API ERROR : ", response.errors); // errors if any
} else {
return response.data.data.albums;
}
}
async function updateUrl(id, url) {
const endpoint = "https://api.mydomain.com/graphql";
const headers = {
"content-type": "application/json",
};
const graphqlQuery = {
query: `mutation UpdateAlbum($data: AlbumUpdateInput!, $where:
AlbumWhereUniqueInput!) {
updateAlbum(data: $data, where: $where) {
id
}
}`,
variables: {
data: {
album_cover: {
set: url,
},
},
where: {
id: id,
},
},
};
const response = await axios({
url: endpoint,
method: "post",
headers: headers,
data: graphqlQuery,
});
if (response.errors) {
functions.logger.error("API ERROR : ", response.errors); // errors if any
} else {
return response.data.data.album;
}
}
const triggerBucketEvent = async () => {
const config = {
action: "read",
expires: "03-17-2025",
};
const albums = await getAlbums();
albums.map((album) => {
const resizedFileName = album.id + "_300x200.webp";
const filePath = "images/albums/thumbs/" + resizedFileName;
const file = bucket.file(filePath);
functions.logger.info(file.name);
file.getSignedUrl(config, function (err, url) {
if (err) {
functions.logger.error(err);
return;
} else {
functions.logger.info(
`The signed url for ${resizedFileName} is ${url}.`
);
updateUrl(album.id, url);
}
} );
});
};
exports.updateResizedImageUrl = functions.https.onRequest(async () => {
await triggerBucketEvent();
});
I need to add Service Account Token Creator role for App Engine default service account.

In azure functions (js) POST request after async/await call does not work

I am currently working with azure functions in javascript. In my function, I am first getting a specific element from my CosmoDB (this is the async/await part). I get a result and then I want to do an https POST request. However, my problem is, that it never finished the HTTPs request and I don't really know why. What am I doing wrong?
(As you can see I tried 2 different ways of doing the request, once with the standard https function and the commented out the part with npm request package. However, both ways won't work).
Here is my code:
const CosmosClient = require('#azure/cosmos').CosmosClient;
var https = require('https');
var http = require('http');
var request = require('request');
const endpoint = "someEndpoint";
const masterKey = "anymasterkey";
const database = {
"id": "Database"
};
const container = {
"id": "Container1"
};
const databaseId = database.id;
const containerId = container.id;
const client = new CosmosClient({
endpoint: endpoint,
auth: {
masterKey: masterKey
}
});
module.exports = function (context, req) {
const country = "de";
const bban = 12345678;
const querySpec = {
query: "SELECT * FROM Container1 f WHERE f.country = #country AND f.bban = #bban",
parameters: [{
name: "#country",
value: country
},
{
name: "#bban",
value: bban
}
]
};
getContainers(querySpec).then((results) => {
const result = results[0];
context.log('here before request');
var options = {
host: 'example.com',
port: '80',
path: '/test',
method: 'POST'
};
// Set up the request
var req = http.request(options, (res) => {
var body = "";
context.log('request');
res.on("data", (chunk) => {
body += chunk;
});
res.on("end", () => {
context.res = body;
context.done();
});
}).on("error", (error) => {
context.log('error');
context.res = {
status: 500,
body: error
};
context.done();
});
req.end();
// request({
// baseUrl: 'someURL',
// port: 443,
// uri: 'someuri',
// method: 'POST',
// headers: {
// 'Content-Type': 'text/xml;charset=UTF-8',
// 'SOAPAction': 'someaction'
// },
// function (error, response, body) {
// context.log('inside request')
// if (error) {
// context.log('error', error);
// } else {
// context.log('response');
// }
// }
// })
})
};
async function getContainers(querySpec) {
const {container, database} = await init();
return new Promise(async (resolve, reject) => {
const {
result: results
} = await container.items.query(querySpec).toArray();
resolve(results);
})
}
async function init() {
const {
database
} = await client.databases.createIfNotExists({
id: databaseId
});
const {
container
} = await database.containers.createIfNotExists({
id: containerId
});
return {
database,
container
};
}
The last thing that happens is the print of "here before request". After that the function just does nothing until it timesout. So what am I doing wrong? Can't I just this combination of await/async and requests?
As commented you are not sending any data to the POST call. You need to have a req.write before the req.end
req.write(data);
req.end();
That is why the POST call is failing for you. After this fix, it should work

Firebase Function:Function returned undefined, expected Promise or value

I have written a firebase function to send notification whenever a like occurs in my android app. The notification functionality works good most of the times but sometimes does not work.
I receive this error always ( whether it is working or not):
Function returned undefined, expected Promise or value
Here's the code of my like function:
exports.sendactorLikeNotification = functions.database.ref('/Likes/{post_id}/{user_id}')
.onWrite(event => {
if (event.data.exists())
{
const message = event.data.val();
const userUid = event.params.user_id;
const ownerUid = message.owner_id;
console.log("Owner id", ownerUid);
const userPic = message.thumb_image;
const userName = message.name;
const post_key = event.params.post_id;
const timestamp = admin.database.ServerValue.TIMESTAMP;
if(ownerUid == userUid){return null;}
const Promise1= admin.database().ref(`/notifs/${ownerUid}`).push({
thumb_image: userPic,
name: userName,
user_id: userUid,
post_id: post_key,
text: "liked your post",
type: "Like",
read: "false",
time: timestamp
});
const Promise2=admin.database().ref(`/Users/${ownerUid}/device_token`).once('value');
const Promise3= Promise2.then(function(snapshot) {
const getrealDeviceTokensPromise = snapshot.val();
console.log("Device Token", getrealDeviceTokensPromise);
// Notification details.
const payload = {
notification: {
title: 'Appname',
body: userName + ' has liked your post.',
icon: "default",
sound: "default",
click_action: "OPEN_ACTIVITY_1"
}
};
const Promise4= admin.messaging().sendToDevice(getrealDeviceTokensPromise, payload)
.then(function (response) {
console.log("Successfully sent message:", response);
return Promise.all([Promise1,Promise3,Promise4]);
})
.catch(function (error) {
console.log("Error sending message:", error);
return null;
});
}, function(error) {
// The Promise was rejected.
console.error(error);
return null;
});
}
else
{
return null;
}
});
I don't understand where I am going wrong. Please help!
exports.sendactorLikeNotification = functions.database.ref('/Likes/{post_id}/{user_id}').onWrite(event => {
if (event.data.exists()) {
const promises=[];
const message = event.data.val();
const userUid = event.params.user_id;
const ownerUid = message.owner_id;
console.log("Owner id", ownerUid);
const userPic = message.thumb_image;
const userName = message.name;
const post_key = event.params.post_id;
const timestamp = admin.database.ServerValue.TIMESTAMP;
if(ownerUid == userUid){return null;}
const a1=admin.database().ref(`/notifs/${ownerUid}`).push({
thumb_image: userPic,
name: userName,
user_id: userUid,
post_id: post_key,
text: "liked your post",
type: "Like",
read: "false",
time: timestamp
});
promises.push(a1);
const a2= admin.database().ref(`/Users/${ownerUid}/device_token`).once('value').then(function(snapshot) {
const getrealDeviceTokensPromise = snapshot.val();
console.log("Device Token", getrealDeviceTokensPromise);
// Notification details.
const payload = {
notification: {
title: 'Appname',
body: userName + ' has liked your post.',
icon: "default",
sound: "default",
click_action: "OPEN_ACTIVITY_1"
}
};
const a3=admin.messaging().sendToDevice(getrealDeviceTokensPromise, payload)
.then(function (response) {
console.log("Successfully sent message:", response);
})
.catch(function (error) {
console.log("Error sending message:", error);
});
promises.push(a3);
}, function(error) {
console.error(error);
});
promises.push(a1);
return Promise.all(promises);
}
else
{
return null;
}
});
This code solved the problem for me!
You're returning undefined when:
event.data.exists() returns false
ownerUid == userUid
You're also not dealing with the promise returned by sendToDevice().then().catch(). The function needs to wait until that work is done before terminating.
Please test the following changes and let me know, also I recommend updating the firebase-functions SDK:
exports.sendactorLikeNotification = functions.database.ref('/Likes/{post_id}/{user_id}')
.onWrite(event => {
if (event.data.exists()) {
const promises = [];
const message = event.data.val();
const userUid = event.params.user_id;
const ownerUid = message.owner_id;
const userPic = message.thumb_image;
const userName = message.name;
const post_key = event.params.post_id;
const timestamp = admin.database.ServerValue.TIMESTAMP;
if (ownerUid === userUid) return null;
return Promise.all([admin.database().ref(`/Users/${ownerUid}/device_token`).once('value')]).then(r => {
const cO = r[0];
const aP = admin.database().ref(`/notifs/${ownerUid}`).push({
thumb_image: userPic,
name: userName,
user_id: userUid,
post_id: post_key,
text: "liked your post",
type: "Like",
read: "false",
time: timestamp
});
promises.push(aP);
const payload = {
notification: {
title: 'Appname',
body: userName + ' has liked your post.',
icon: "default",
sound: "default",
click_action: "OPEN_ACTIVITY_1"
}
};
const tokensList = Object.keys(cO.val());
promises.push(admin.messaging().sendToDevice(tokensList, payload));
return Promise.all(promises);
});
}
return null;
});

Categories