mirror of
https://github.com/alexmickelson/canvasManagement.git
synced 2026-03-25 23:28:33 -06:00
working on code to upload files...
This commit is contained in:
@@ -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
3
nextjs/pnpm-lock.yaml
generated
@@ -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
|
||||||
|
|||||||
96
nextjs/src/services/canvas/files/canvasFileService.ts
Normal file
96
nextjs/src/services/canvas/files/canvasFileService.ts
Normal 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;
|
||||||
|
}
|
||||||
|
};
|
||||||
@@ -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
52
requests/fileUpload.http
Normal 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
BIN
requests/image.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 7.2 KiB |
Reference in New Issue
Block a user