Why is my excel add-in getting corrupted? - excel

I have a link to an excel add-in I let users download. I am using flask + mod_wsgi.
#app.route('/link/')
def download_addin():
parent_dir = os.path.dirname(os.path.dirname(os.path.realpath(__file__))) + '/static/'
response = make_response()
response.headers['Cache-Control'] = 'no-cache'
response.headers['Content-Type'] = 'application/vnd.ms-excel.addin.macroEnabled.12'
response.headers['Content-Disposition'] = 'attachment; filename=my_addin.xlam'
return response
I download the file but when I use it in Excel I get a warning "Excel cannot open the file 'my_addin.xlam' because the file format or file extension is not valid...'
Thanks!

You need to return the file as part of the response. Try something like
#app.route('/link/')
def download_addin():
parent_dir = os.path.dirname(os.path.dirname(os.path.realpath(__file__))) + '/static/'
with open(os.path.join(parent_dir, 'my_addin.xlam')) as f:
response = make_response(f.read())
response.headers['Cache-Control'] = 'no-cache'
response.headers['Content-Type'] = 'application/vnd.ms-excel.addin.macroEnabled.12'
response.headers['Content-Disposition'] = 'attachment; filename=my_addin.xlam'
return response
Without doing this you'll download an empty file. That's probably why Excel doesn't like the format.

Related

django download view downloading only .xls instead of file with extension on model

I have my Django view where I upload the file from admin and users download it on the frontend when I download the file on the frontend the download is extension with only .xls i.e when I upload the file with .xlsx extension it is still downloading with .xls instead the file should be downloaded according to the extension either its xls or xlsx.
views.py
class myAPIView(APIView):
def get(self, request):
data = Model.objects.first()
filename = data.file.name
file_extention = filename.split('.')[-1]
response = HttpResponse(
data.file.path,
content_type='application/vnd.openxmlformats-officedocument.spreadsheetml.sheet')
response['Content-Disposition'] = \
'attachment; filename="output_file"'+ file_extention
return response
This is the standard that you can apply(edit the content-type for you.)
class myAPIView(APIView):
def get(self, request):
data = Model.objects.first()
filename = data.file # or data.file.name based on your models.
file_extention = filename.split('.')[-1] # something which is seprated by dot. in the last
response = HttpResponse(
file_path,
content_type='application/vnd.openxmlformats-officedocument.spreadsheetml.sheet')
response['Content-Disposition'] = \
'attachment; filename="output_file"'+ file_extention
return response

How to get dynamic url of file uploaded to sharepoint using python?

My code does following tasks on daily basis:
Create a date folder on sharepoint.DONE
Create a category folder in the date folder of sharepoint. DONE
Upload a file in respective category folder. DONE
4. Find the url of file. PENDING
Send the url on email. DONE
def upload_files(base_url, site, access_token, fileName, filePath, fileFolderUrl):
try:
fileHandle = open(filePath, 'rb')
#fileFolderUrl = f'Shared Documents/Output/{subFolder}'
requestFileUploadUrl = f"{base_url}/{site}/_api/web/GetFolderByServerRelativeUrl('{fileFolderUrl}')/Files/add(url='{fileName}',overwrite=true)"
headers = {
'Accept':'application/json; odata=verbose',
'Content-Type':'application/json; odata=verbose',
'Authorization': 'Bearer {}'.format(access_token)
}
uploadFileResult = requests.post(requestFileUploadUrl, headers=headers, data=fileHandle)
if uploadFileResult.status_code == 200:
return "success"
else:
return "failure"
except Exception as e:
print(f"Error in uploading files to sharepoint:{e}")
return "error"
Can someone please help me understand the process to obtain the url of this file that I am required to upload in dynamically created folders on sharepoint using python3+?
So,the structure is : SharedDocuments/Output/Today's Date/CategoryA/file.xlsx
One solution could be to create the URL manually as you already know the url, the site and the name of the file.
I figure out that you can create the link to share a file with this pattern :
<base_url>/<site>/<FileFolderUrl>/<File>?&web=1
For example : https://company.sharepoint.com/sites/test/Documents%20partages/testing.jpg?&web=1
It works only for people that already have access it.
I have not yet tested in an automatic solution but only by hand in an empirical way
I know it's been a long while but was scrolling through it today and thought of answering it. Hope it can be helpful to someone in the future.
def get_out_file_url(base_url, site, access_token, file_folder, fileName):
"""
These are random examples of file_folder and base_url
file_folder = 'Shared Documents/Output/Dated/Category'
base_url = 'https://company.sharepoint.com'
"""
requestFileGetUrl = f'{base_url}/sites/{site}/_api/web/GetFolderByServerRelativeUrl(\'' + fileUrl + '/'+ '\')/files?$filter'
headers = {
'Accept':'application/json; odata=verbose',
'Content-Type':'application/json; odata=verbose',
'Authorization': 'Bearer {}'.format(access_token)
}
getFileResult = requests.get(requestFileGetUrl, headers=headers)
values = getFileResult.json()
fileData = values['d']['results']
for key in fileData:
if key['Name'] == fileName:
fileURLLink = key['ServerRelativeUrl']
fileCreatedTime = key['TimeCreated']
fileLastModified = key['TimeLastModified']
fileNewUrl = base_url + urllib.parse.quote(fileURLLink)
return fileNewUrl
else:
return file_folder

How to upload video as a multipart/form body content in Python for Video Indexer API?

I am trying to upload a video file from local machine using VideoIndexer API in Python. I am expected to upload video as a multipart/form body content. Following is my code (Variable values like accountID, name, location are not pasted below),
# Request headers
headers = {
'x-ms-client-request-id': '',
'Content-Type': 'multipart/form-data',
'Ocp-Apim-Subscription-Key': 'xxxxxxxxx',
}
# Request parameters
params = urllib.parse.urlencode({
'privacy': 'Private',
'description': 'testing',
})
try:
conn = http.client.HTTPSConnection('api.videoindexer.ai')
conn.request("POST", "/" + location + "/Accounts/" + accountId + "/Videos?name=" + name + "&accessToken=" + accessToken + "&%s" % params, body = open('TestAudio1.mp4', 'rb').read(), headers = headers)
response = conn.getresponse()
data = response.read()
print(data)
conn.close()
except Exception as e:
print("[Errno {0}] {1}".format(e.errno, e.strerror))
I am getting the following error,
{"ErrorType":"INVALID_INPUT","Message":"Input is invalid. Input must specify either a video url, an asset id or provide a multipart content body."}
How can I fix this issue?

Excel file represented by string in API response: how to download as file with python?

I am calling an API that returns the following object as response:
{
"BrokenRules": [],
"ReturnCode": 0,
"ReturnData": "\"UEsDBBQAAAAIAGJAylC560mkEgIAAM4DAAAPABwAeGwvd29ya2Jvb2sueG1sIKIYACigFAAAAAAAAAAAAAAAAAAAAAAAAAAAAO29B2AcSZYlJi9tynt/SvVK1+B0oQiAYBMk2JBAEOzBiM3mku.....ASAMAABMAAAAAAAAAAAAAAAAA0P8QAFtDb250ZW50X1R5cGVzXS54bWxQSwUGAAAAAAgACAD9AQAAqAERAAAA\""
}
I am supposed to be able to download an excel file (.xlsx) from the ReturnData object. How do I do that with python 3?
Here is what I have tried, but the file is corrupt and is empty. Any ideas ?
filename = "api_output.xlsx"
response = requests.post(URL, headers=headers, json=data)
res = json.loads(response.json()["ReturnData"])
with open(filename, 'w') as file:
print("writing file")
file.write(res)
So I found the answer:
response = requests.post(URL, headers=headers, json=data)
res = json.loads(response.json()["ReturnData"])
data = base64.b64decode(res)
with open(filename, 'wb') as file:
print("writing file")
file.write(data)

Download Zoom Recordings to Local Machine and use Resumable Upload Method to upload the video to Google Drive

I have built a function in Python3 that will retrieve the data from a Google Spreadsheet. The data will contain the Recording's Download_URL and other information.
The function will download the Recording and store it in the local machine. Once the video is saved, the function will upload it to Google Drive using the Resumable Upload method.
Even though the response from the Resumable Upload method is 200 and it also gives me the Id of the file, I can't seem to find the file anywhere in my Google Drive. Below is my code.
import os
import requests
import json
import gspread
from oauth2client.service_account import ServiceAccountCredentials
DOWNLOAD_DIRECTORY = 'Parent_Folder'
def upload_recording(file_location,file_name):
filesize = os.path.getsize(file_location)
# Retrieve session for resumable upload.
headers = {"Authorization": "Bearer " + access_token, "Content-Type": "application/json"}
params = {
"name": file_name,
"mimeType": "video/mp4"
}
r = requests.post(
"https://www.googleapis.com/upload/drive/v3/files?uploadType=resumable",
headers=headers,
data=json.dumps(params)
)
print(r)
location = r.headers['Location']
# Upload the file.
headers = {"Content-Range": "bytes 0-" + str(filesize - 1) + "/" + str(filesize)}
r = requests.put(
location,
headers=headers,
data=open(file_location, 'rb')
)
print(r.text)
return True
def download_recording(download_url, foldername, filename):
upload_success = False
dl_dir = os.sep.join([DOWNLOAD_DIRECTORY, foldername])
full_filename = os.sep.join([dl_dir, filename])
os.makedirs(dl_dir, exist_ok=True)
response = requests.get(download_url, stream=True)
try:
with open(full_filename, 'wb') as fd:
for chunk in response.iter_content(chunk_size=512 * 1024):
fd.write(chunk)
upload_success = upload_recording(full_filename,filename)
return upload_success
except Exception as e:
# if there was some exception, print the error and return False
print(e)
return upload_success
def main():
scope = ["https://spreadsheets.google.com/feeds", "https://www.googleapis.com/auth/spreadsheets",
"https://www.googleapis.com/auth/drive.file", "https://www.googleapis.com/auth/drive"]
creds = ServiceAccountCredentials.from_json_keyfile_name('creds.json', scope)
client = gspread.authorize(creds)
sheet = client.open("Zoom Recordings Data").sheet1
data = sheet.get_all_records()
# Get the Recordings information that are needed to download
for index in range(len(sheet.col_values(9))+1 ,len(data)+2):
success = False
getRow = sheet.row_values(index)
session_name = getRow[0]
topic = getRow[1]
topic = topic.replace('/', '')
topic = topic.replace(':', '')
account_name = getRow[2]
start_date = getRow[3]
file_size = getRow[4]
file_type = getRow[5]
url_token = getRow[6] + '?access_token=' + getRow[7]
file_name = start_date + ' - ' + topic + '.' + file_type.lower()
file_destination = session_name + '/' + account_name + '/' + topic
success |= download_recording(url_token, file_destination, file_name)
# Update status on Google Sheet
if success:
cell = 'I' + str(index)
sheet.update_acell(cell,'success')
if __name__ == "__main__":
credentials = ServiceAccountCredentials.from_json_keyfile_name(
'creds.json',
scopes='https://www.googleapis.com/auth/drive'
)
delegated_credentials = credentials.create_delegated('Service_Account_client_email')
access_token = delegated_credentials.get_access_token().access_token
main()
I'm still trying to figure out how to upload the video to the folder that it needs to be. I'm very new to Python and the Drive API. I would very appreciate if you can give me some suggestions.
How about this answer?
Issue and solution:
Even though the response from the Resumable Upload method is 200 and it also gives me the Id of the file, I can't seem to find the file anywhere in my Google Drive. Below is my code.
I think that your script is correct for the resumable upload. From your above situation and from your script, I understood that your script worked, and the file has been able to be uploaded to Google Drive with the resumable upload.
And, when I saw your issue of I can't seem to find the file anywhere in my Google Drive and your script, I noticed that you are uploading the file using the access token retrieved by the service account. In this case, the uploaded file is put to the Drive of the service account. Your Google Drive is different from the Drive of the service account. By this, you cannot see the uploaded file using the browser. In this case, I would like to propose the following 2 methods.
Pattern 1:
The owner of the uploaded file is the service account. In this pattern, share the uploaded file with your Google account. The function upload_recording is modified as follows. And please set your email address of Google account to emailAddress.
Modified script:
def upload_recording(file_location, file_name):
filesize = os.path.getsize(file_location)
# Retrieve session for resumable upload.
headers1 = {"Authorization": "Bearer " + access_token, "Content-Type": "application/json"} # Modified
params = {
"name": file_name,
"mimeType": "video/mp4"
}
r = requests.post(
"https://www.googleapis.com/upload/drive/v3/files?uploadType=resumable",
headers=headers1, # Modified
data=json.dumps(params)
)
print(r)
location = r.headers['Location']
# Upload the file.
headers2 = {"Content-Range": "bytes 0-" + str(filesize - 1) + "/" + str(filesize)} # Modified
r = requests.put(
location,
headers=headers2, # Modified
data=open(file_location, 'rb')
)
# I added below script.
fileId = r.json()['id']
permissions = {
"role": "writer",
"type": "user",
"emailAddress": "###" # <--- Please set your email address of your Google account.
}
r2 = requests.post(
"https://www.googleapis.com/drive/v3/files/" + fileId + "/permissions",
headers=headers1,
data=json.dumps(permissions)
)
print(r2.text)
return True
When you run above modified script, you can see the uploaded file at "Shared with me" of your Google Drive.
Pattern 2:
In this pattern, the file is uploaded to the shared folder using the resumable upload with the service account. So at first, please prepare a folder in your Google Drive and share the folder with the email of the service account.
Modified script:
Please modify the function upload_recording as follows. And please set the folder ID you shared with the service account.
From:
params = {
"name": file_name,
"mimeType": "video/mp4"
}
To:
params = {
"name": file_name,
"mimeType": "video/mp4",
"parents": ["###"] # <--- Please set the folder ID you shared with the service account.
}
When you run above modified script, you can see the uploaded file at the shared folder of your Google Drive.
Note:
In this case, the owner is the service account. Of course, the owner can be also changed.
Reference:
Permissions: create

Resources