我有一个使用 Next.js 构建的应用程序,它与 Python Flask API 交互以生成 DOCX 文件并通过 Microsoft Graph API 将其上传到 OneDrive。以下是相关代码的概述:
1.Next.js 代码(TypeScript):
import toPascalCase from "@/libs/toPascalCase";
import axios from "axios";
const DownloadTemplate = async (suratData: any, accessToken: String) => {
try {
const locResponse = await fetch("http://ip-api.com/json/");
const locData = await locResponse.json();
const city = locData.city || "Jakarta"; // Default to Jakarta if city is not found
const requestBody = {
template: "Memo",
kepada:
suratData?.surat?.kepadaId.map((k: any) => k.name).join(", ") || "",
dari: suratData?.surat?.dariId.name || "",
perihal: suratData?.konten?.perihal.name || "",
sifat: suratData?.konten?.sifat.name || "",
lampiran: suratData?.konten?.lampiran?.name || "-",
tgl: suratData?.surat?.tanggal
? new Date(suratData.surat.tanggal).toLocaleDateString("id-ID", {
day: "2-digit",
month: "long",
year: "numeric",
})
: "",
Tempat: city,
jabatan: toPascalCase(suratData?.surat?.dariId?.jabatan || ""),
name: toPascalCase(suratData?.surat?.dariId?.name || ""),
stringforqr: "testing dari front end node",
};
const formData = new FormData();
formData.append("data", JSON.stringify(requestBody));
console.log("Request Body:", requestBody);
const response = await axios.post('http://127.0.0.1:5000/getTemplate', requestBody, {
headers: {
"Authorization": `Bearer ${accessToken}`,
'Content-Type': 'application/json',
},
});
console.log(response.data);
return response.data;
} catch (error) {
console.error("Error downloading template:", error);
}
};
export default DownloadTemplate;
2。 Python Flask 代码:
from flask import Flask, request, send_file
from flask_cors import CORS
from docx import Document
from docx.shared import Inches
import database
from docx2pdf import convert
import os
import tempfile
import pythoncom
import logging
import pythoncom
import qrcode
import requests
import tempfile
import json
from PIL import Image
from flask import request
app = Flask(__name__)
CORS(app)
# app.config['CORS_HEADERS'] = 'Content-Type'
def fill_invitation(template_path, output_path, data, qr_code_path=None):
doc = Document(template_path)
# doc = template_path
# data['tgl'] = datetime.today().strftime("%d %B %Y")
for paragraph in doc.paragraphs:
for key, value in data.items():
if key in paragraph.text:
for index, run in enumerate(paragraph.runs):
newkey = '{{' + key + '}}'
if paragraph.runs[index-1].text == '{{' and run.text == key:
run.text = run.text.replace(key, value)
paragraph.runs[index-1].text = ''
paragraph.runs[index+1].text = ''
elif newkey == run.text:
if newkey == "qr":
run.text
run.text = run.text.replace(newkey, value)
for table in doc.tables:
for row in table.rows:
for cell in row.cells:
for paragraph in cell.paragraphs:
for key, value in data.items():
if key in paragraph.text:
for index, run in enumerate(paragraph.runs):
newkey = '{{' + key + '}}'
if paragraph.runs[index-1].text == '{{' and paragraph.runs[index+1].text == '}}' and run.text == key:
run.text = run.text.replace(key, value)
paragraph.runs[index-1].text = ''
paragraph.runs[index+1].text = ''
elif newkey == run.text:
run.text = run.text.replace(newkey, value)
if qr_code_path:
inserted = False
for paragraph in doc.paragraphs:
if "{{qr}}" in paragraph.text:
logging.debug("QR code placeholder '{{qr}}' found.")
paragraph.text = paragraph.text.replace("{{qr}}", "")
run = paragraph.add_run()
run.add_picture(qr_code_path, width=Inches(1.3))
inserted = True
logging.debug("QR code inserted into paragraph.")
if not inserted:
logging.debug("QR code placeholder '{{qr}}' not found in the document.")
doc.save(output_path)
@app.route('/getTemplate', methods=['POST'])
def docsFilling():
data = request.get_json()
# data = json.loads(request.form.get('data'))
accessToken = request.headers.get('Authorization')
print('data ================================== > ', data)
print('accessToken ================================== > ', accessToken)
templateData = data.get('template')
listTipeSurat = database.getData(templateData)
template = "retrieved_file.docx"
Logo_link = 'Logo_PGASOL.jpg'
stringqr = data['stringforqr']
basewidth = 200
logo = Image.open(Logo_link)
wpercent = (basewidth / float(logo.size[0]))
hsize = int((float(logo.size[1]) * float(wpercent)))
logo = logo.resize((basewidth, hsize))
QRcode = qrcode.QRCode(
error_correction=qrcode.constants.ERROR_CORRECT_H
)
QRcode.add_data(stringqr)
QRcode.make()
QRcolor = 'Black'
QRimg = QRcode.make_image(
fill_color=QRcolor, back_color="white").convert('RGB')
pos = ((QRimg.size[0] - logo.size[0]) // 2,
(QRimg.size[1] - logo.size[1]) // 2)
QRimg.paste(logo, pos)
try:
with tempfile.NamedTemporaryFile(delete=False, suffix='.png', dir='./temp/qr') as temp_qr:
qr_code_path = temp_qr.name
QRimg.save(qr_code_path)
with open(template, "wb") as f:
f.write(listTipeSurat.fileTemplate)
with tempfile.NamedTemporaryFile(delete=False, suffix='.docx', dir='./temp/docs') as temp_docx:
output_path = temp_docx.name
print('output_path =====> ', output_path)
fill_invitation(template, output_path, data, qr_code_path)
with open(output_path, 'rb') as item:
media_content = item.read()
x = requests.put('https://graph.microsoft.com/v1.0/me/drive/special/approot:/test15.docx:/content',
headers={'Authorization': accessToken,
'Content-Type': 'application/vnd.openxmlformats-officedocument.wordprocessingml.document'},
data=media_content)
dataContent = x.json()
return dataContent
except Exception as e:
return str(e), 500
finally:
# Ensure temporary files are cleaned up
try:
if os.path.exists(output_path):
os.remove(output_path)
if os.path.exists(qr_code_path):
os.remove(qr_code_path)
except PermissionError:
pass # Handle the permission error or log it
if __name__ == '__main__':
logging.basicConfig(level=logging.ERROR)
app.run(debug=True)
我的代码的目的是调用python中的端点来使用从下一个js发送到python的ruqest数据,并将它们转换为已自动填充的docx,然后通过microsoft graph api上传到onedrive。
问题:
当我从 Next.js 应用程序调用 Python API 端点时,我从 Microsoft Graph API 收到以下错误:
{
"error": {
"code": "itemNotFound",
"innerError": {
"client-request-id": "4a9e1e4f-1cc0-4725-944e-a95ec0d5e409",
"date": "2024-08-08T13:22:57",
"request-id": "4a9e1e4f-1cc0-4725-944e-a95ec0d5e409"
},
"message": "Item not found"
}
}
但是当我通过 POSTMAN 应用程序测试它时,它运行没有任何问题,文档已创建并上传到我的一个驱动器。
问题:
谢谢您的帮助!
首先,您向
/me/drive/{some-id}/content
提出的请求不存在
对于某个项目的内容,您应该调用其中之一
GET /drives/{drive-id}/items/{item-id}/content
GET /groups/{group-id}/drive/items/{item-id}/content
GET /me/drive/root:/{item-path}:/content
GET /me/drive/items/{item-id}/content
GET /shares/{shareIdOrEncodedSharingUrl}/driveItem/content
GET /sites/{siteId}/drive/items/{item-id}/content
GET /users/{userId}/drive/items/{item-id}/content
也就是说,您提出的请求也只有声明
scp=User.Read profile openid email
,而 Files.Read
是所需的最低许可。
我的建议是首先检查正在调用的 URL,并确保它是 https://learn.microsoft.com/en-us/graph/api/driveitem-get-content?view=graph-rest 中列出的 URL 之一-1.0&tabs=http
然后检查应用程序中的 Files.Read 权限。应将其添加为 Entra Portal 上的委托权限。