Google calendar api - add a file attachment - python-3.x

Using python 3.6, requests==2.22.0
I am using the Google API to create an event: documentation
In the documentation I see:
attachments[].fileUrl string URL link to the attachment.
For adding Google Drive file attachments use the same format as in alternateLink property of the Files resource in the Drive API.
Required when adding an attachment.
writable
Can I insert a file attachment not via a link-url?
Will that require a separate call?
data = {
'summary': 'CALENDAR TESTING',
'location': 'Some fake location',
'description': 'This is a test',
'start': {
'dateTime': 'some iso datetime',
'timeZone': 'some tz',
},
'end': {
'dateTime': 'some iso datetime',
'timeZone': 'some tz',
},
}
url = 'https://www.googleapis.com/calendar/v3/calendars/{}/events'.format(calendar_id)
headers = {
'Authorization': 'Bearer {}'.format(access_token),
'Accept': 'application/json',
'Content-Type': 'application/json',
}
response = requests.post(
url,
data=json.dumps(data),
headers=headers,
)
Example of an attachment-generating-payload sent to an already existing event in Office365:
data = {
"#odata.type": "#microsoft.graph.fileAttachment",
"name": "<String, file name>.pdf",
"contentBytes": <b64 encoded pdf bytes>
}
My goal is to attach a PDF file to the event.
In case I missed a documentation reference please point me to it - otherwise I will appreciate what is necessary to add to the above Google event creation payload to make this happen, or the url + payload schema to attach post-event creation.
Thank you!

Seems like Google does not support events attachments that are not store on Drive.
I am evaluating possible workarounds for the issue.

Related

I am facing issue while reading request body in Azure function node js

In my azure function post call i am passing body like this
{
"license":{
"licensepolicy": "NA",
"metadata":{
"tenantname":"tenantname",
},
"licensetype":"type"
},
"customer":{
"name":"TEst User",
"emailaddress":"email",
"company":"test"
}
}
In my code I am accessing this request body like below
context.log(req.body.license);
Its giving undefined log, I don't know why but its working in normal node js code but in azure function its not working.
Please assist me if I am wrong somewhere
thanks in advance
Make sure to check your post method whether it contains the Header 'Content-Type': 'application/json'
headers: {
'Content-Type': 'application/json'
}
If you are not sending the Json response you have to convert that into Json object in your code to retrieve that information.
# convert request into Json object and access those informations.
const parsedData = JSON.parse(req)
context.log(parsedData.body.license);

Uploading Office Open XML files using API POST method in Python

I am trying to write a script to help me automate some work with our CAT tool (Memsource). To this end, I need to upload some files using API.
I rely on Memsource API documentation available here: https://cloud.memsource.com/web/docs/api#operation/createJob
I wrote a short code to test file uploading before moving to making it async, and I have some serious problem: text files are uploaded correctly, although the body of the text contains some additions after uploading:
--4002a5507da490554ad71ce8591ccf69
Content-Disposition: form-data; name="file"; filename=“test.txt"
I also tried to upload DOCX file, but it cannot be even opened in Memsource online editor — I guess the content is modified along the way, but I am unable to find where...
The code responsible for the upload is as follows:
def test_upload(self):
# Assemble "Memsource" header as mentioned in the API docs
Memsource_header = {
"targetLangs": ["pl"],
}
# Open the file to be uploaded and extract file name
f = open("Own/TMS_CAT/test.txt", "rb")
f_name = os.path.basename(f.name)
# Assemble the request header
header = {
"Memsource": json.dumps(Memsource_header),
"Content-Disposition": f'attachment; filename="{f_name}"',
"Authorization": f"ApiToken {self.authToken}",
"Content-Type": "application/octet-stream; charset=utf-8",
}
# Make POST request and catch results
file = {"file": f}
req = requests.post(
"https://cloud.memsource.com/web/api2/v1/projects/{project-id}/jobs",
headers=header,
files=file,
)
print(req.request.headers)
print(req.json())
The request header:
{
"User-Agent":"python-requests/2.27.1",
"Accept-Encoding":"gzip, deflate",
"Accept":"*/*",
"Connection":"keep-alive",
"Memsource":"{\"targetLangs\": [\"pl\"]}",
"Content-Disposition":"attachment; filename=\"test.txt\"",
"Authorization":"ApiToken {secret}",
"Content-Type":"application/octet-stream; charset=utf-8",
"Content-Length":"2902"
}
And the response from Memsource:
{
"asyncRequest":{
"action":"IMPORT_JOB",
"dateCreated":"2022-02-22T18:36:30+0000",
"id":"{id}"
},
"jobs":[
{
"workflowLevel":1,
"workflowStep":{
"uid":"{uid}",
"order":2,
"id":"{id}",
"name":"Tra"
},
"imported":false,
"dateCreated":"2022-02-22T18:36:30+0000",
"notificationIntervalInMinutes":-1,
"updateSourceDate":"None",
"dateDue":"2022-10-10T12:00:00+0000",
"targetLang":"pl",
"continuous":false,
"jobAssignedEmailTemplate":"None",
"uid":"{id}",
"status":"NEW",
"filename":"test.txt",
"sourceFileUid":"{id}",
"providers":[
]
}
],
"unsupportedFiles":[
]
}
both look okay to me...
I will appreciate any suggestions on how to get this thing working! :-)
I managed to fix this problem — noticed that requests are adding some limited headers to the body of the request, i.e., the content of the file passed in files parameter.
I simply got rid of that and changed the code as follows:
# Open the file to be uploaded and extract file name
with open(
"/file.ext", "rb"
) as f:
f_name = os.path.basename(f.name)
# Assemble the request header
header = {
"Memsource": json.dumps(Memsource_header),
"Content-Disposition": f'attachment; filename="{f_name}"',
"Authorization": f"ApiToken {self.authToken}",
"Content-Type": "application/octet-stream; charset=utf-8",
}
req = requests.post(
"https://cloud.memsource.com/web/api2/v1/projects/{project-id}/jobs",
headers=header,
data=f,
)

Send multipart gmail email which is huge attachments

I am trying to send an email which has attachments in it, using Gmail APIs, I am using NodeJS, I have read this document
https://developers.google.com/gmail/api/guides/uploads#multipart
But I am not sure what I am missing in headers, the following is the code
I have to send an email which has an attachment which is more than 25 MB so for that, I am using multipart of Gmail, following is the code
const options = {
uri: 'https://www.googleapis.com/upload/gmail/v1/users/xyz#gmail.com/messages/send?uploadType=multipart',
method: apiConfig.method,
media: {mimeType: 'message/rfc822', body: requestParameter.dataObj.raw},
headers: {
Authorization: 'Bearer ' + token,
'Content-type': 'message/rfc822'
},
json: true
}
According to the Send attachments with your Gmail documentation:
You can send up to 25 MB in attachments. If you have more than one attachment, they can't add up to more than 25 MB.
If your file is greater than 25 MB, Gmail automatically adds a Google Drive link in the email instead of including it as an attachment.
But the last sentence refers to the Gmail UI, and not if you are using the API.
So essentially you cannot upload directly the attachment to the Gmail - you will have to upload it to Google Drive first and afterwards send it in the e-mail.
A possible solution:
Upload the file which you want to send to Google Drive by using the Google Drive API v3. Since you want to upload a file bigger than 25 mb you should use the resumable upload. The resumable upload is a more reliable type of transfer and especially important with large files.
var options = {
url: 'https://www.googleapis.com/upload/drive/v3/files?uploadType=resumable',
headers: {
'Authorization': 'Bearer ' + token,
'Content-Type': 'application/json',
},
//other options
}
Retrieve the file from Drive by using the Drive API and set the permissions necessary to be able to share the file. Afterwards you have to use the NPM module async to synchronize the changes in the permissions.
var fileId = 'ID_OF_THE_FILE';
var permissions = [
{
'type': 'user',
'role': 'writer',
'emailAddress': 'user#example.com'
}, {
'type': 'domain',
'role': 'writer',
'domain': 'example.com'
}
];
Send the e-mail with the link for the file wanted in the body.
Note: you also have to authorize the necessary scopes both for Drive and Gmail.
Moreover, I suggest you check the following links since they might be of help:
NodeJS Quickstart Drive API;
Upload files to Drive;
Drive Permissions;
OAuth 2.0 Scopes for Google APIs.

Getting JSON Data into image format

I have this GET request I built to call Google APIS dot com to get an image of a house at a given address. It's all working fine. In Postman it displays the image from the body of the request. All good!
I converted the code to NodeJS REQUEST. Put that code into my project. It all works though the data returned is all �����JFIF������ like this in the BODY returned.
Can you point me to some resources or can you tell me in NODEJS how I get that into a Image type variable. I want to then display it using JSON code into Messenger Bot. I have the JSON code to send a IMAGE type back to Messenger - I just need to get the results of the GET above into a format in NODEJS that will work - like a PNG or JPG format.
This is the code I used from Postman CODE:
var options = { method: 'GET',
url: 'https://maps.googleapis.com/maps/api/streetview',
qs:
{ size: '450x450',
location: 'N108W15303%20Bel%20Aire%20Ln%2053022',
fov: '90',
heading: '235',
pitch: '10',
key: 'xxx' },
headers:
{ 'Postman-Token': 'xxx',
'Cache-Control': 'no-cache',
Accept: 'application/json' } };
requestGoogle(options, function (error, response, body) {
if (error) throw new Error(error);
console.log(body);
});
The BODY var is is all ����JFIF��C
It displays great in the Postman App. so you are somehow converting it to display it - what I am looking for.
Any help would be appreciated - or direct me to a resource that can help that would be great.

Getting 401 uploading file into a table with a service account

I am using nodejs and the REST API to interact with bigquery. I am using the google-oauth-jwt module for JWT signing.
I granted a service account write permission. So far I can list projects, list datasets, create a table and delete a table. But when it comes to upload a file via multipart POST, I ran into two problems:
gzipped json file doesn't work, I get an error saying "end boundary missing"
when I use uncompressed json file, I get a 401 unauthorized error
I don't think this is related to my machine's time being out of sync since other REST api calls worked as expected.
var url = 'https://www.googleapis.com/upload/bigquery/v2/projects/' + projectId + '/jobs';
var request = googleOauthJWT.requestWithJWT();
var jobResource = {
jobReference: {
projectId: projectId,
jobId: jobId
},
configuration: {
load: {
sourceFormat: 'NEWLINE_DELIMITED_JSON',
destinationTable: {
projectId: projectId,
datasetId: datasetId,
tableId: tableId
},
createDisposition: '',
writeDisposition: ''
}
}
};
request(
{
url: url,
method: 'POST',
jwt: jwtParams,
headers: {
'Content-Type': 'multipart/related'
},
qs: {
uploadType: 'multipart'
},
multipart: [
{
'Content-Type':'application/json; charset=UTF-8',
body: JSON.stringify(jobResource)
},
{
'Content-Type':'application/octet-stream',
body: fileBuffer.toString()
}
]
},
function(err, response, body) {
console.log(JSON.parse(body).selfLink);
}
);
Can anyone shine some light on this?
P.S. the documentation on bigquery REST api is not up to date on many things, wish the google guys can keep it updated
Update 1:
Here is the full HTTP request:
POST /upload/bigquery/v2/projects/239525534299/jobs?uploadType=multipart HTTP/1.1
content-type: multipart/related; boundary=71e00bd1-1c17-4892-8784-2facc6998699
authorization: Bearer ya29.AHES6ZRYyfSUpQz7xt-xwEgUfelmCvwi0RL3ztHDwC4vnBI
host: www.googleapis.com
content-length: 876
Connection: keep-alive
--71e00bd1-1c17-4892-8784-2facc6998699
Content-Type: application/json
{"jobReference":{"projectId":"239525534299","jobId":"test-upload-2013-08-07_2300"},"configuration":{"load":{"sourceFormat":"NEWLINE_DELIMITED_JSON","destinationTable":{"projectId":"239525534299","datasetId":"performance","tableId":"test_table"},"createDisposition":"CREATE_NEVER","writeDisposition":"WRITE_APPEND"}}}
--71e00bd1-1c17-4892-8784-2facc6998699
Content-Type: application/octet-stream
{"practiceId":2,"fanCount":5,"mvp":"Hello"}
{"practiceId":3,"fanCount":33,"mvp":"Hello"}
{"practiceId":4,"fanCount":71,"mvp":"Hello"}
{"practiceId":5,"fanCount":93,"mvp":"Hello"}
{"practiceId":6,"fanCount":92,"mvp":"Hello"}
{"practiceId":7,"fanCount":74,"mvp":"Hello"}
{"practiceId":8,"fanCount":100,"mvp":"Hello"}
{"practiceId":9,"fanCount":27,"mvp":"Hello"}
--71e00bd1-1c17-4892-8784-2facc6998699--
You are most likely sending duplicate content-type headers to the Google API.
I don't have the capability to effortlessly make a request to Google BigQuery to test, but I'd start with removing the headers property of your options object to request().
Remove this:
headers: {
'Content-Type': 'multipart/related'
},
The Node.js request module automatically detects that you have passed in a multipart array, and it adds the appropriate content-type header. If you provide your own content-type header, you most likely end up with a "duplicate" one, which does not contain the multipart boundary.
If you modify your code slightly to print out the actual headers sent:
var req = request({...}, function(..) {...});
console.log(req.headers);
You should see something like this for your original code above (I'm using the Node REPL):
> req.headers
{ 'Content-Type': 'multipart/related',
'content-type': 'multipart/related; boundary=af5ed508-5655-48e4-b43c-ae5be91b5ae9',
'content-length': 271 }
And the following if you remove the explicit headers option:
> req.headers
{ 'content-type': 'multipart/related; boundary=49d2371f-1baf-4526-b140-0d4d3f80bb75',
'content-length': 271 }
Some servers don't deal well with multiple headers having the same name. Hopefully this solves the end boundary missing error from the API!
I figured this out myself. This is one of those silly mistakes that would have you stuck for the whole day and at the end when you found the solution you would really knock on your own head.
I got the 401 by typing the selfLink URL in the browser. Of course it's not authorized.

Resources