working on code to upload files...

This commit is contained in:
2024-11-20 09:14:11 -07:00
parent e47810a741
commit 9cba83e51c
6 changed files with 154 additions and 2 deletions

View File

@@ -20,6 +20,7 @@
"@types/ws": "^8.5.13", "@types/ws": "^8.5.13",
"chokidar": "^4.0.1", "chokidar": "^4.0.1",
"dotenv": "^16.4.5", "dotenv": "^16.4.5",
"form-data": "^4.0.1",
"jsdom": "^25.0.0", "jsdom": "^25.0.0",
"next": "^15.0.2", "next": "^15.0.2",
"react": "^18", "react": "^18",

3
nextjs/pnpm-lock.yaml generated
View File

@@ -32,6 +32,9 @@ importers:
dotenv: dotenv:
specifier: ^16.4.5 specifier: ^16.4.5
version: 16.4.5 version: 16.4.5
form-data:
specifier: ^4.0.1
version: 4.0.1
jsdom: jsdom:
specifier: ^25.0.0 specifier: ^25.0.0
version: 25.0.1 version: 25.0.1

View File

@@ -0,0 +1,96 @@
import fs from "fs/promises";
import path from "path";
import axios from "axios";
import { canvasApi } from "../canvasServiceUtils";
import { axiosClient } from "@/services/axiosUtils";
import FormData from "form-data";
export const downloadUrlToTempDirectory = async (
sourceUrl: string
): Promise<string> => {
try {
const fileName =
path.basename(new URL(sourceUrl).pathname) || `tempfile-${Date.now()}`;
const tempFilePath = path.join("/tmp", fileName);
const response = await axios.get(sourceUrl, {
responseType: "arraybuffer",
});
await fs.writeFile(tempFilePath, response.data);
return tempFilePath;
} catch (error) {
console.error("Error downloading or saving the file:", error);
throw error;
}
};
const getFileSize = async (pathToFile: string): Promise<number> => {
try {
const stats = await fs.stat(pathToFile);
return stats.size;
} catch (error) {
console.error("Error reading file size:", error);
throw error;
}
};
export const uploadToCanvasPart1 = async (
pathToUpload: string,
canvasCourseId: string
) => {
try {
const url = `${canvasApi}/courses/${canvasCourseId}/assignment_groups`;
const formData = new FormData();
formData.append("name", path.basename(pathToUpload));
formData.append("size", (await getFileSize(pathToUpload)).toString());
const response = await axiosClient.post(url, formData);
const upload_url = response.data.upload_url;
const upload_params = response.data.upload_params;
return { upload_url, upload_params };
} catch (error) {
console.error("Error uploading file to Canvas part 1:", error);
throw error;
}
};
export const uploadToCanvasPart2 = async (
pathToUpload: string,
upload_url: string,
upload_params: { [key: string]: string }
) => {
try {
const formData = new FormData();
Object.keys(formData).forEach((key) => {
formData.append(key, upload_params[key]);
});
const fileBuffer = await fs.readFile(pathToUpload);
const fileName = path.basename(pathToUpload);
formData.append("file", fileBuffer, fileName);
const response = await axiosClient.post(upload_url, formData, {
headers: formData.getHeaders(),
validateStatus: (status) => status < 500,
});
if (response.status === 301) {
const redirectUrl = response.headers.location;
if (!redirectUrl) {
throw new Error(
"Redirect URL not provided in the Location header on redirect from second part of canvas file upload"
);
}
const redirectResponse = await axiosClient.get(redirectUrl);
console.log("redirect response", redirectResponse.data);
}
} catch (error) {
console.error("Error uploading file to Canvas part 1:", error);
throw error;
}
};

View File

@@ -44,8 +44,8 @@ export function markdownToHTMLSafe(
const clean = DOMPurify.sanitize( const clean = DOMPurify.sanitize(
marked.parse(markdownString, { async: false, pedantic: false, gfm: true }) marked.parse(markdownString, { async: false, pedantic: false, gfm: true })
); );
return convertImagesToCanvasImages(clean, settings); // return convertImagesToCanvasImages(clean, settings);
// return clean; return clean;
} }
export function markdownToHtmlNoImages(markdownString: string) { export function markdownToHtmlNoImages(markdownString: string) {

52
requests/fileUpload.http Normal file
View File

@@ -0,0 +1,52 @@
# https://canvas.instructure.com/doc/api/file.file_uploads.html
###
GET https://snow.instructure.com/api/v1/courses
Authorization: Bearer {{$dotenv CANVAS_TOKEN}}
### 1st request
# @name createFile
POST https://snow.instructure.com/api/v1/courses/1014748/files
Authorization: Bearer {{$dotenv CANVAS_TOKEN}}
name=image.png&size=7339
### 2nd request based on the results of the first
### all upload_params need to be sent in the form
# @name uploadFile
POST {{createFile.response.body.$.upload_url}}
Content-Type: multipart/form-data; boundary=boundary
--boundary
Content-Disposition: form-data; name="file"; filename="image.png"
Content-Type: image/png
< ./image.png
--boundary
Content-Disposition: form-data; name="filename"
image.png
--boundary
Content-Disposition: form-data; name="content_type"
image/png
--boundary--
### if second request is a 301, you must follow the redirect with a get request and authorization
### mine seems to be a 201, which means i am done
### alternatively, you can just give canvas the public URL
### requires polling a status url afterwards to know when complete, yuck
POST https://snow.instructure.com/api/v1/courses/1014748/files
Authorization: Bearer {{$dotenv CANVAS_TOKEN}}
url=http://example.com/my_pic.jpg&name=profile_pic.jpg
###
GET https://snow.instructure.com/api/v1/courses/1014748/files/170618085
Authorization: Bearer {{$dotenv CANVAS_TOKEN}}
# file links can be reset with <https://canvas.instructure.com/doc/api/files.html#method.files.reset_verifier>

BIN
requests/image.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.2 KiB