import * as F from '../api/filesAPITypes'; import {canvas, Match, mkHeader} from '../request/requestBuidler'; import * as ResponseType from '../api/responseTypes'; import {isValidURL} from '../utils'; import fetch from 'node-fetch'; import fs from 'fs'; import {pipeline} from 'stream'; import path from 'path'; import {promisify} from 'util'; import {URLString} from 'src/api/aliases'; const streamPipeline = promisify(pipeline); // Note, `File` is just a object that stores some information about // the actual file. To download the file you need to use the url contained // in `File` object interface FileStream { filename: string, // the information of the file provided by canvas server. meta: ResponseType.File, // the stream body returned from `fetch` stream: NodeJS.ReadableStream, }; /** * store one FileStream at the given baseDir. * @param baseDir where to download the file to. * @param stream the FileStream object generated by one of the file fetching apis. * @returns a flag that indicate if file is successfully written. */ export async function store(baseDir: string, stream: FileStream) { if (!await promisify(fs.exists)(baseDir)) { console.log(`${baseDir} doesn't exist, creating a new one`); await promisify(fs.mkdir)(baseDir); } const filepath = path.join(baseDir, stream.filename); const wstream = fs.createWriteStream(filepath); await streamPipeline(stream.stream, wstream); } /** * @param path the path it store to. * @param stream */ export async function storeByPath(filepath: string, stream: NodeJS.ReadableStream) { const wstream = fs.createWriteStream(filepath); await streamPipeline(stream, wstream); } /** * download a single file * @param * @returns a promise FileStream * * Note the filename received in `File` object will be url encoded. */ export async function fetchFile( file: ResponseType.File): Promise { const {url, filename} = file; const decodedFilename = decodeURIComponent(filename); const response = await fetchFileByUrl(url); return { ...response, filename: decodedFilename, meta: file, } } export async function fetchFileByUrl(url: string) { if (!isValidURL(url)) { throw new Error("" + "file resource url get from canvas api is invalid." + " It's a canvas problem"); } const response = await fetch(url, { method: 'get', headers: {...mkHeader()} }); return { stream: response.body, } } /** * download files from a list of File * @param files A list of files that can come from any File[] return apis. * @return a promise of a list of binary file and there corresponding File. * File can be used to determine what to do with the binary buffer. */ export async function fetchFiles(files: ResponseType.File[]) { return files.map(async file => { return fetchFile(file) }); } /** * download all files from a folder * @param folder * @return */ export async function fetchAllFromAFolder( folder: ResponseType.Folder, config: Match,) { const {id} = folder; const files = await getFilesOfAFolder(id, config); return fetchFiles(files); } export async function getFile( fileId: Match["id"], include: Match["include"]) { return canvas({ uri: "/api/v1/files/:id", uriParams: {id: fileId}, method: "GET", param: {include} }) } export async function getCourseFileQuota( courseId: Match["course_id"], ) { return canvas({ uri: "/api/v1/courses/:course_id/files/quota", uriParams: {course_id: courseId}, method: "GET", param: {} }) } export async function getGroupFileQuota( groupId: Match["group_id"], ) { return canvas({ uri: "/api/v1/groups/:group_id/files/quota", uriParams: {group_id: groupId}, method: "GET", param: {} }) } export async function getUserFileQuota( userId?: Match["user_id"], ) { return canvas({ uri: "/api/v1/users/:user_id/files/quota", uriParams: {user_id: userId ?? "self"}, method: "GET", param: {}, }) } export const getQuota = () => getUserFileQuota("self"); export async function getCourseFiles( courseId: Match["course_id"], config: Match, ) { return canvas({ uri: "/api/v1/courses/:course_id/files", uriParams: {course_id: courseId}, method: "GET", param: config, }); } export async function getUserFiles( userId: Match["user_id"], config: Match, ) { return canvas({ uri: "/api/v1/users/:user_id/files", uriParams: {user_id: userId}, method: "GET", param: config, }); } export const getFiles = (config: Match) => getUserFiles("self", config) export async function getGroupFiles( groupId: Match["group_id"], config: Match, ) { return canvas({ uri: "/api/v1/groups/:group_id/files", uriParams: {group_id: groupId}, method: "GET", param: config, }); } export async function getFilesOfAFolder( folderId: Match["id"], config: Match, ) { return canvas({ uri: "/api/v1/folders/:id/files", uriParams: {id: folderId}, method: "GET", param: config, }); } export async function updateFile( id: Match["id"], config: Match, ) { return canvas({ uri: "/api/v1/files/:id", uriParams: {id}, method: "PUT", param: config, }) } export async function deletFile( id: Match["id"], config: Match, ) { return canvas({ uri: "/api/v1/files/:id", uriParams: {id}, method: "DELETE", param: config, }) } export async function getCourseFolders( courseId: Match["course_id"], ) { return canvas({ uri: "/api/v1/courses/:course_id/folders", uriParams: {course_id: courseId}, method: "GET", param: {}, }) } export async function getUserFolders( userId?: Match["user_id"], ) { return canvas({ uri: "/api/v1/users/:user_id/folders", uriParams: {user_id: userId ?? "self"}, method: "GET", param: {}, }) } export async function getGroupFolders( groupId: Match["group_id"], ) { return canvas({ uri: "/api/v1/groups/:group_id/folders", uriParams: {group_id: groupId}, method: "GET", param: {}, }) } export async function getCourseFoldersByPath( courseId: Match["course_id"], path: string, ) { return canvas({ uri: "/api/v1/courses/:course_id/folders/by_path/*full_path", uriParams: {course_id: courseId, full_path: path}, method: "GET", param: {}, }); } export async function getGroupFoldersByPath( groupId: Match["group_id"], path: string, ) { return canvas({ uri: "/api/v1/groups/:group_id/folders/by_path/*full_path", uriParams: {group_id: groupId, full_path: path}, method: "GET", param: {}, }); } export async function getUserFoldersByPath( userId: Match["user_id"], path: string, ) { return canvas({ uri: "/api/v1/users/:user_id/folders/by_path/*full_path", uriParams: {user_id: userId, full_path: path}, method: "GET", param: {}, }); } export async function getFolderInCourse( courseId: Match["course_id"], folderId: Match["id"], ) { return canvas({ uri: "/api/v1/courses/:course_id/folders/:id", uriParams: {course_id: courseId, id: folderId}, method: "GET", param: {}, }); } export async function getFolderOfUser( userId: Match["user_id"], folderId: Match["id"], ) { return canvas({ uri: "/api/v1/users/:user_id/folders/:id", uriParams: {user_id: userId, id: folderId}, method: "GET", param: {}, }); } export async function getFolderInGroup( groupId: Match["group_id"], folderId: Match["id"], ) { return canvas({ uri: "/api/v1/groups/:group_id/folders/:id", uriParams: {group_id: groupId, id: folderId}, method: "GET", param: {}, }); } export async function getFolder( folderId: Match["id"], ) { return canvas({ uri: "/api/v1/folders/:id", uriParams: {id: folderId}, method: "GET", param: {}, }); } export async function getFolders( folderId: Match["id"], ) { return canvas({ uri: "/api/v1/folders/:id/folders", uriParams: {id: folderId}, method: "GET", param: {}, }); } export async function updateFolder( folderId: Match["id"], config: Match, ) { return canvas({ uri: "/api/v1/folders/:id", uriParams: {id: folderId}, method: "PUT", param: config, }) } export async function createFolderInCourse( courseId: Match["course_id"], config: Match ) { return canvas({ uri: "/api/v1/courses/:course_id/folders", uriParams: {course_id: courseId}, method: "POST", param: config, }); } export async function createFolderOfUser( userId: Match["user_id"], config: Match ) { return canvas({ uri: "/api/v1/users/:user_id/folders", uriParams: {user_id: userId}, method: "POST", param: config, }); } export async function createFolderInGroup( groupId: Match["group_id"], config: Match ) { return canvas({ uri: "/api/v1/groups/:group_id/folders", uriParams: {group_id: groupId}, method: "POST", param: config, }); } export async function createFolder( folderId: Match["folder_id"], config: Match ) { return canvas({ uri: "/api/v1/folders/:folder_id/folders", uriParams: {folder_id: folderId}, method: "POST", param: config, }); } export async function deleteFolder( folderId: Match["id"], config: Match ) { return canvas({ uri: "/api/v1/folders/:id", uriParams: {id: folderId}, method: "DELETE", param: config, }) } // ** Low level file uploading api. This will only create a pending // file on canvas' server. To perform an entire data upload please // use uploadAFile() in `uploadPolily.ts`. export async function uploadAFileENDPOINT( folderId: Match["folder_id"], config: Match ) { return canvas({ uri: "/api/v1/folders/:folder_id/files", uriParams: {folder_id: folderId}, method: "POST", param: config, }); } export async function CopyAFile( destFolderId: Match["dest_folder_id"], config: Match, ) { return canvas({ uri: "/api/v1/folders/:dest_folder_id/copy_file", uriParams: {dest_folder_id: destFolderId}, method: "POST", param: config, }) } export async function CopyAFolder( destFolderId: Match["dest_folder_id"], config: Match, ) { return canvas({ uri: "/api/v1/folders/:dest_folder_id/copy_folder", uriParams: {dest_folder_id: destFolderId}, method: "POST", param: config, }) }