Cant't access media_id_string in JS Mastodon-Bot - javascript

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.

Related

why the result of uploader is error but never goes in .catch in requestPromise

this is my test file for upload and i explain it step by step:
I wrote a test to upload the file. the uploader method written with busboy module and it working true
but i have problem in test.
when result of uploader is error, this error never returned in .catch and go in .then.
more explain in code:
const http = require('http');
// const request = require('request');
const rp = require('request-promise');
const fs = require('fs');
const assert = require('chai').assert;
const port = process.env.PORT || 80;
const Q = require('q');
let server;
const options = {
method: 'POST',
uri: 'http://127.0.0.1/upload',
formData: {
name: 'test',
file: {
value: fs.createReadStream('./test/test.jpg'),
options: {
filename: 'test.jpg',
contentType: 'image/jpg'
}
}
},
headers: {
'Connection': 'Keep-Alive',
'content-type': 'multipart/form-data' // Is set automatically
},
json: true,
};
function startServer(port, cb) {
server = http.createServer(function (req, res) {
if (req.method === 'POST') {
if (req.url === '/upload') {
serveRequest(req, res);
}
}
});
server.listen(port, () => {
cb(function stopServer(done) {
setTimeout(function () {
server.close();
done();
}, 20);
});
console.log(`listening on port ${port} ...`);
});
}
function serveRequest(request, response) {
if (request.headers.hasOwnProperty('content-type')
&& request.headers['content-type'].split(';')[0] === 'multipart/form-data') {
serveUpload(request, response);
}
}
function serveUpload(request, response) {
uploader.upload(request, function (error, res) {
if (error) {
response.end();
}
else {
response.write(JSON.stringify(res));
response.end();
}
});
}
// -----------------------
describe('upload', function () {
let stopServer = null;
before('start server', function (done) {
startServer(port, function (stop) {
stopServer = stop;
done();
});
});
it('upload a file - options is true', function (done) {
rp(options)
.then(function (r) {
console.log(r);
})
.catch(function (error) {
console.log(error);
});
});
after('stop server', function (done) {
stopServer(done);
});
});
I make a request to the uploader and the result of my request is returned in the serveUpload() method. The result of serveUpload() is error and error is object like this :
error =
meta: {
code: '',
sourceType: 'module',
sourceName: '',
version: '2.0.4'
},
data: {
message: {
en: 'uploaded data size is out of limit'
}
}
}
this error must returned .catch(e) in the rp(options), but in fact it must go to .then(r) in rp(options)
log r in .then is undefined.
rp(options)
.then(function (r) {
console.log(r); // error always come here But in fact it must go to catch and r is undefined
})
.catch(function (error) {
console.log(error);
});
I don't understand why this is happening, I would be very grateful if anyone could help me.

Get URL of uploaded file to S3 (after the file has been uploaded)

Given a link that when the user hits it a PDF is downloaded ,
I want to upload the file to S3 and then get an Amazon S3 URL that would be public (I don't want the user to see the real Link , so that's why I'd rather upload it to S3).
Consider the code :
module.exports = class S3Uploader {
uploadPdfFromURLToS3 = urlToUpload => {
import aws from "aws-sdk";
const request = require("request");
const s3 = new aws.S3();
const config = require("config");
var uuidv4 = require("uuid/v4");
var filename = uuidv4() + ".pdf";
aws.config.update({
accessKeyId: config.get("-------------"),
secretAccessKey: config.get("-----------------")
});
var promise = new Promise((resolve, reject) => {
return request({ url: urlToUpload, encoding: null }, function(
err,
res,
body
) {
if (err) return reject({ status: 500, error: err });
return resolve({ status: 200, body: body });
});
});
promise.then(pdf => {
if (pdf.status == 200) {
s3.putObject(
{
Bucket: "-----Your-Bucket-Name",
Body: pdf.body,
Key: filename,
ACL: "public-read"
},
(err, data) => {
if (err) console.log(err);
else
{
console.log("uploaded");
// Get the S3 Public link ????
}
}
);
}
});
};
};
How can I get the link after the file has been uploaded successfully , in the callback ?
You can build up the url using string concatentation.
https://your-bucket-name.s3-eu-west-1.amazonaws.com/filename
Make sure you are using the correct region.
You can try adding $(data.Location) in your console.log("uploaded") line.
console.log("uploaded. $(data.Location)");
**TRY THIS **The main change is in s3.putObject()
module.exports = class S3Uploader {
uploadPdfFromURLToS3 = urlToUpload => {
import aws from "aws-sdk";
const request = require("request");
const s3 = new aws.S3();
const config = require("config");
var uuidv4 = require("uuid/v4");
var filename = uuidv4() + ".pdf";
aws.config.update({
accessKeyId: config.get("-------------"),
secretAccessKey: config.get("-----------------")
});
var promise = new Promise((resolve, reject) => {
return request({ url: urlToUpload, encoding: null }, function(
err,
res,
body
) {
if (err) return reject({ status: 500, error: err });
return resolve({ status: 200, body: body });
});
});
promise.then(pdf => {
if (pdf.status == 200) {
s3.putObject(
{
Bucket: "-----Your-Bucket-Name",
Body: pdf.body,
Key: filename,
ACL: "public-read"
},async(err,data)=>{if(err){console.log("error")}
else
console.log(data.location) //get pdf url
}
);
}
});
};
};

Request_BadRequest in O365

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

Gmail API using nodejs, asnyc function to get messages

I've been trying to make this work but couldn't figure it out.
I need to retrieve all the mail id's then get those mail messages using their ids. Because it's not async, when exporting the data I get nothing.
function listMessages(auth) {
const gmail = google.gmail({version: 'v1', auth});
let data;
gmail.users.messages.list({
'userId': 'mail address',
'q': 'some query'
}, (err, res) => {
res.data.messages.forEach(element => {
console.log(element);
mails.push(element.id);
});
mails.forEach((id) => {
request = gmail.users.messages.get({
'userId': 'sedatcyalcin#gmail.com',
'id': id
}, (err, res) => {
data = res.data.snippet;
console.log(data);
});
})
});
}
I can export mails but can't export data;
This is how I made it work:
function getRecentEmail(auth) {
const gmail = google.gmail({ version: 'v1', auth });
// Only get the recent email - 'maxResults' parameter
gmail.users.messages.list({ auth: auth, userId: 'me', maxResults: 1, }, function (err, response) {
if (err) {
console.log('The API returned an error: ' + err);
return;
}
// Get the message id which we will need to retreive tha actual message next.
var message_id = response['data']['messages'][0]['id'];
// Retreive the actual message using the message id
gmail.users.messages.get({ auth: auth, userId: 'me', 'id': message_id }, function (err, response) {
if (err) {
console.log('The API returned an error: ' + err);
return;
}
email = response.data
console.log(email)
});
}); }
And I called it in your index.js file below this line:
// Authorize a client with credentials, then call the Gmail API.
authorize(JSON.parse(content), getRecentEmail);
Maybe dividing into 2 functions and if the one returns promise may solve it.
const listMessages = auth => {
return new Promise((resolve , reject)=>{
const gmail = google.gmail({version: 'v1', auth});
let data;
gmail.users.messages.list({
'userId': 'mail address',
'q': 'some query'
}, (err, res) => {
res.data.messages.forEach(element => {
console.log(element);
mails.push(element.id);
resolve(mails)
});
})
})
}
const getMessages = () => {
listMessages().then(mails=>{
mails.forEach((id) => {
request = gmail.users.messages.get({
'userId': 'sedatcyalcin#gmail.com',
'id': id
}, (err, res) => {
data = res.data.snippet;
console.log(data);
});
})
})
}
Birde boyle dene , olmaz ise sorunu daha detaylı anlatırsan yardım etmeye çalışırım.
Here is my TS based solution to list messages.
Note that format: 'raw' returns base64. Remove that line if you just want snippets of each email that matches your query.
const gmail = google.gmail({ version: 'v1', auth });
let data: string | undefined;
const mails: string[] = [];
gmail.users.messages?.list(
{
userId: 'me',
q: 'from: some query',
maxResults: 1,
},
(err, res) => {
if (!res || !res.data || !res.data.messages) {
console.log('No Messages Found');
return;
}
res.data.messages.forEach((message) => {
console.log(`first api call: ${message}`);
mails.push(message.id ?? '');
});
mails.forEach((id) => {
const req = gmail.users.messages.get(
{
userId: 'me',
id,
format: 'raw',
},
(err, res) => {
// data = res?.data.snippet!;
console.log(res?.data);
}
);
});
}
);
};

Testing express middleware

I have following code to test:
const Status = require('http-status-codes');
const passport = require('passport');
const Users = require('../models/users.js');
const authentication = {
// Authenticate User Middleware
authenticateUser: function authenticateUser(req, res, next) {
return passport.authenticate('bearer', { session: false, failWithError: false },
(err, user, info) => {
if (err) {
return res.status(500).json({ message: err });
}
if (user) {
return Users.findOne({ auth_ref: user.auth_ref })
.populate('groups')
.exec((e, doc) => {
if (e) {
return res.status(500).json({ message: e });
}
req.authInfo = info;
req.user = doc;
return next(null, doc, info);
});
}
return res.status(Status.UNAUTHORIZED).json({ message: 'Access denied' });
}
)(req, res, next);
},
};
module.exports = authentication.authenticateUser;
My test file:
const test = require('ava');
const sinon = require('sinon');
const proxyquire = require('proxyquire');
const Util = require('../util');
Util.beforeEach(test, (t) => {
const authenticateStub = sinon.stub();
const passportStub = {
authenticate: authenticateStub,
};
const authenticationMocked = proxyquire('../../../middleware/authentication', { passport: passportStub });
t.context.authenticateStub = authenticateStub;
t.context.authenticationMocked = authenticationMocked;
});
Util.afterEach(test);
Util.after(test);
test('[middleware/authentication] authenticateUser function call succeed', sinon.test(async (t) => {
// given
const func = t.context.authenticationMocked;
t.context.authenticateStub.withArgs(sinon.match.any, sinon.match.any, sinon.match.any).yields('error', { statusCode: 500 }, 'sampleUser');
const nextSpy = sinon.spy();
const fakeReq = { user: { email: '' } };
const res = {
status: () => res,
json: () => res,
};
// when
func(fakeReq, res, nextSpy);
// then
})
My problem is that I somehow can't mock the res parameter in a way so that no error occurs.
This code produces the following error:
Rejected promise returned by test. Reason:
TypeError {
message: 'passport.authenticate(...) is not a function', }
If I remove the res object to {} the error is res.status is not a function
Am I doing something wrong with the initialization or is my res object wrong?
I now found the following solution:
// given
const func = t.context.authenticationMocked;
t.context.authenticateStub.withArgs(sinon.match.any, sinon.match.any, sinon.match.any).yields('error', { statusCode: 500 }, 'sampleUser').returns(() => {});
const nextSpy = sinon.spy();
const fakeReq = { user: { email: '' } };
const rootRouteStub = {
status: sinon.stub(),
json: sinon.spy(),
};
rootRouteStub.status.returns(rootRouteStub);
// when
func(fakeReq, rootRouteStub, nextSpy);

Categories