Upload attachment in JIRA using MS bot Framework - postman

I'm trying to upload an attachment for Jira ticket using Microsoft Bot framework in Nodejs.
I'm calling the attachment Api in Jira using below code snippet:
const axios = require('axios');
const dotenv = require('dotenv');
const fs = require('fs');
const FormData = require('form-data')
dotenv.config();
class attachmentAPI {
constructor() {
}
async uploadJIRAImage(key) {
let urlString = `https://{jira-site-name}.atlassian.net/rest/api/2/issue/${key}/attachments`;
console.log(urlString);
const credentials = process.env.JiraUsername + ":" + process.env.JiraPassword;
const hash = Buffer.from(credentials).toString('base64');
const Basic = 'Basic ' + hash;
let formData = new FormData();
//Here I want to upload image url from emulator
**let stream = fs.createReadStream("Image.png");**
formData.append('file', stream);
let formHeaders = formData.getHeaders();
let res = await axios.post(urlString, formData, {
headers: {
'Accept': 'application/json',
'Authorization': Basic,
'X-Atlassian-Token': 'nocheck',
...formHeaders
}
});
console.log("Api-Result: ",res)
}
}
exports.attachmentAPI = attachmentAPI;
In this way I can now able to upload the image. As it is located in the same folder locally. But I want to upload an image url from emulator, that need to be attached to JIRA ticket.
emulator image uploaded content is in this format:
{
name: 'SAP-Logo.png',
contentType: 'image/png',
contentUrl: 'http://localhost:12345/v3/attachments/1b864600-fe77-11eb-bc85-b3c9f4256d99/views/original'
}
How do I successfully send the image Url/path in the above code as formdata that attach the image to Jira ticket?
Thanks in advance.

Related

How to upload several photos using aw3?

I use react native and backend was built with Prisma and GraphQL (Apollo Server).
I don't store image data to Prisma but to aw3.
The problem is I want to upload several images at once to my app. So I make image column of Prisma Array [], not String.
But as using aw3, I can upload only one image at once. So even if I make image column as Array, I can't upload several images at once as Array using aw3.
When I searched people suggest 3 options in order to upload multiple files by aw3.
multi-thread
multi-processing
zip upload (amazon-lambda)
In my case(to upload files as Array),
which option is most advisable?
And can you teach me the way of doing that?
My backend code:
export const uploadToS3 = async (file, userId, folderName) => {
const { filename, createReadStream } = await file;
const readStream = createReadStream();
const objectName = `${folderName}/${userId}-${Date.now()}-${filename}`;
const { Location } = await new AWS.S3()
.upload({
Bucket: "chungchunonuploads",
Key: objectName,
ACL: "public-read",
Body: readStream,
})
.promise();
return Location;
};
We need to resolve multiple file upload promises with Promise.all. Let us refactor our code and split it into 2 functions.
// Assume that we have list of all files to upload
const filesToUpload = [file1, file2, file3, fileN];
export const uploadSingleFileToS3 = async (file, userId, folderName) => {
const { filename, createReadStream } = await file;
const readStream = createReadStream();
const objectName = `${folderName}/${userId}-${Date.now()}-${filename}`;
const response = await new AWS.S3().upload({
Bucket: "chungchunonuploads",
Key: objectName,
ACL: "public-read",
Body: readStream,
});
return response;
};
const uploadMultipleFilesToS3 = async (filesToUpload, userId, folderName) => {
const uploadPromises = filesToUpload.map((file) => {
return uploadSingleFileToS3(file, userId, folderName);
});
// Array containing all uploaded files data
const uploadResult = await Promise.all(uploadPromises);
// Add logic here to update the database with Prisma ORM
};
// Call uploadMultipleFilesToS3 with all required parameters

Forward uploaded file from a service to another service

I'm trying to create a REST API with ExpressJS that accept an image and pass it to another service (with a POST request) which is in charge to perform some operations (resize, etc..) and store into an AWS S3. I know that the same solution can be easily done with a Lambda Function directly but I have a K8s and I want to make worth it.
All components are already working with the exception of the service that forward the image to the second service.
The idea that I've found on internet is using a stream, but I got the exception Error: Expected a stream at Object.getStream [as default]
How can I solve that? Is the right practice or there is a better solution to achieve the same result?
const headers = req.headers;
const files: any = req.files
const filename = files[0].originalname;
const buffer = await getStream(files[0].stream)
const formFile = new FormData();
formFile.append('image', buffer, filename);
headers['Content-Type'] = 'multipart/form-data';
axios.post("http://localhost:1401/content/image/test/upload/", formFile, {
headers: headers,
})
.catch((error) => {
const { status, data } = error.response;
res.status(status).send(data);
})
I've found a solution that I post here for those who'll have the same problem.
Install form-data on node:
yarn add form-data
Then in your controller:
const headers = req.headers;
const files: any = req.files
const formFile = new FormData();
files.forEach((file: any) => {
const filename = file.originalname;
const buffer = file.buffer
formFile.append('image', buffer, filename);
})
// set the correct header otherwise it won't work
headers["content-type"] = `multipart/form-data; boundary=${formFile.getBoundary()}`
// now you can send the image to the second service
axios.post("http://localhost:1401/content/image/test/upload/", formFile, {
headers: headers,
})
.then((r : any) => {
res.sendStatus(r.status).end()
})
.catch((error) => {
const { status, data } = error.response;
res.status(status).send(data);
})

Flutter sending a post request to a Django API with a file as the body

I have a Django API where a user is able to upload a file through a post request with the following body:
{
"file": *attached file*
}
In Django, the file is gathered from the request with request.FILES['file']
The request has to be sent from flutter (dart) code. I have tried a few ways, this is the function from my latest attempt which shows an error - because the "file" is not in the correct format.
static void uploadProfilePhoto(File file, String fileId) async {
Uint8List fileBytes = file.readAsBytesSync();
var response = http.post(
globals.baseURL() + "/upload/",
//headers: {"Content-Type": "application/json"},
body: {
"file":base64Encode(fileBytes)
}
).then((v)=>print("v: "+v.body));
}
Any idea in what format the "file" should be sent from flutter? Else is there any other method which might work? Thank you in advance.
in flutter use
import 'dart:convert' as convert;
import 'dart:io';
import 'package:http/http.dart' as http;
#override
Future<Map<String, dynamic>> sendFiletodjango(
{File file,
}) async {
var endPoint = url;
Map data = {};
String base64file = base64Encode(file.readAsBytesSync());
String fileName = file.path.split("/").last;
data['name']=fileName;
data['file']= base64file;
try {
var response = await http.post(endPoint,headers: yourRequestHeaders, body:convert.json.encode(data));
} catch (e) {
throw (e.toString());
}
}
in python django use
from django.core.files.base import ContentFile
file = response.data.get("file")
name = response.data.get("name")
your_file = ContentFile(base64.b64decode(file),name)
model.fileField = your_file
model.save()
You can try multipart/form-data to upload files from Flutter to the Django server using HTTP post request.
From flutter, you can send multipart/form-data request in the below shown way.
Future<Response> uploadFile(File file) async {
Response response;
var uri = Uri.parse(url);
var request = http.MultipartRequest('POST', uri);
request.files.add(await http.MultipartFile.fromPath('file', file.path));
var response = await request.send();
if (response.statusCode == 200 || response.statusCode == 201) {
print('Uploaded!');
}
return response;
}
You can find more about it here Dart MultipartRequest.

Connecting to Google API with Service Account and OAuth

I'm using an environment that doesn't have native support for a GCP client library. So I'm trying to figure out how to authenticate directly using manually crafted JWT token.
I've adapted the tasks from here Using nodeJS test environment, with jwa to implement the algorithm.
https://developers.google.com/identity/protocols/OAuth2ServiceAccount
The private key is taken from a JSON version of the service account file.
When the test runs, it catches a very basic 400 error, that just says "invalid request". I'm not sure how to troubleshoot it.
Could someone please help identify what I'm doing wrong?
var assert = require('assert');
const jwa = require('jwa');
const request = require('request-promise');
const pk = require('../auth/tradestate-2-tw').private_key;
const authEndpoint = 'https://www.googleapis.com/oauth2/v4/token';
describe('Connecting to Google API', function() {
it('should be able to get an auth token for Google Access', async () => {
assert(pk && pk.length, 'PK exists');
const header = { alg: "RS256", typ: "JWT" };
const body = {
"iss":"salesforce-treasury-wine#tradestate-2.iam.gserviceaccount.com",
"scope":"https://www.googleapis.com/auth/devstorage.readonly",
"aud":"https://www.googleapis.com/oauth2/v4/token",
"exp": new Date().getTime() + 3600 * 1000,
"iat": new Date().getTime()
};
console.log(JSON.stringify(body, null, 2));
const encodedHeader = Buffer.from(JSON.toString(header)).toString('base64')
const encodedBody = Buffer.from(JSON.toString(body)).toString('base64');
const cryptoString = `${encodedHeader}.${encodedBody}`;
const algo = jwa('RS256');
const signature = algo.sign(cryptoString, pk);
const jwt = `${encodedHeader}.${encodedBody}.${signature}`;
console.log('jwt', jwt);
const headers = {'Content-Type': 'application/x-www-form-urlencoded'};
const form = {
grant_type: 'urn:ietf:params:oauth:grant-type:jwt-bearer',
assertion: jwt
};
try {
const result = await request.post({url: authEndpoint, form, headers});
assert(result, 'Reached result');
console.log('Got result', JSON.stringify(result, null, 2));
} catch (err) {
console.log(JSON.stringify(err, null, 2));
throw (err);
}
});
});
Use JSON.stringify instead of JSON.toString. From the link in your question:
{"alg":"RS256","typ":"JWT"}
The Base64url representation of this is as follows:
eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9
When using JSON.toString() and then base64 encoding, you would get W29iamVjdCBKU09OXQ== which explains the 400 for an invalid request as it can't decrypt anything you're sending it.

Zip File downloaded from ReactJs/Axios is corrupted

I'm trying to download a zip file from a Django api and have the user download it. There are two .csv files in the zip.
I am able to download a single .csv files individually, but when I try to download the zip and unzip, I get errors that the zip is corrupted. For sanity check, I am able to send the request via Postman. I am able to successfully download and unzip the file using that.
Here is my code fragment:
axios
.post('http://0.0.0.0:8000/sheets/', data,
{
headers: {
'Content-Type': 'multipart/form-data',
'responseType': 'arraybuffer'
}
})
.then(res => {
console.log(res.data)
const disposition = res.request.getResponseHeader('Content-Disposition')
var fileName = "";
var filenameRegex = /filename[^;=\n]*=((['"]).*?\2|[^;\n]*)/;
var matches = filenameRegex.exec(disposition);
if (matches != null && matches[1]) {
fileName = matches[1].replace(/['"]/g, '');
}
let blob = new Blob([res.data], { type: 'application/zip' })
const downloadUrl = URL.createObjectURL(blob)
let a = document.createElement("a");
a.href = downloadUrl;
a.download = fileName;
document.body.appendChild(a);
a.click();
To add to btbam91's reply: responseType has to be part of the config. In the above example:
axios
.post('http://0.0.0.0:8000/sheets/', data,
{
responseType: 'arraybuffer',
headers: {
'Content-Type': 'multipart/form-data',
}
})
The problem was that 'responseType': 'arraybuffer' should not be in "headers."