UNPKG

23.6 kBJavaScriptView Raw
1import { __decorate } from "tslib";
2import { body, cancelableScope, CancelAction } from "@pnp/queryable";
3import { getGUID, isFunc, stringIsNullOrEmpty, isUrlAbsolute, combine, noInherit } from "@pnp/core";
4import { _SPCollection, spInvokableFactory, SPInstance, deleteableWithETag, deleteable, } from "../spqueryable.js";
5import { Item } from "../items/index.js";
6import { odataUrlFrom } from "../utils/odata-url-from.js";
7import { defaultPath } from "../decorators.js";
8import { spPost, spGet } from "../operations.js";
9import { extractWebUrl } from "../utils/extract-web-url.js";
10import { toResourcePath } from "../utils/to-resource-path.js";
11import { encodePath } from "../utils/encode-path-str.js";
12import { ReadableFile } from "./readable-file.js";
13import "../context-info/index.js";
14import { BatchNever } from "../batching.js";
15/**
16 * Describes a collection of File objects
17 *
18 */
19let _Files = class _Files extends _SPCollection {
20 /**
21 * Gets a File by filename
22 *
23 * @param name The name of the file, including extension.
24 */
25 getByUrl(name) {
26 if (/%#/.test(name)) {
27 throw Error("For file names containing % or # please use web.getFileByServerRelativePath");
28 }
29 return File(this).concat(`('${encodePath(name)}')`);
30 }
31 /**
32 * Adds a file using the pound percent safe methods
33 *
34 * @param url Encoded url of the file
35 * @param content The file content
36 * @param parameters Additional parameters to control method behavior
37 */
38 async addUsingPath(url, content, parameters = { Overwrite: false }) {
39 const path = [`AddUsingPath(decodedurl='${encodePath(url)}'`];
40 if (parameters) {
41 if (parameters.Overwrite) {
42 path.push(",Overwrite=true");
43 }
44 if (parameters.AutoCheckoutOnInvalidData) {
45 path.push(",AutoCheckoutOnInvalidData=true");
46 }
47 if (!stringIsNullOrEmpty(parameters.XorHash)) {
48 path.push(`,XorHash=${encodePath(parameters.XorHash)}`);
49 }
50 }
51 path.push(")");
52 const resp = await spPost(Files(this, path.join("")), { body: content });
53 return {
54 data: resp,
55 file: fileFromServerRelativePath(this, resp.ServerRelativeUrl),
56 };
57 }
58 /**
59 * Uploads a file. Not supported for batching
60 *
61 * @param url The folder-relative url of the file.
62 * @param content The Blob file content to add
63 * @param progress A callback function which can be used to track the progress of the upload
64 * @param shouldOverWrite Should a file with the same name in the same location be overwritten? (default: true)
65 * @param chunkSize The size of each file slice, in bytes (default: 10485760)
66 * @returns The new File and the raw response.
67 */
68 async addChunked(url, content, progress, shouldOverWrite = true, chunkSize = 10485760) {
69 const response = await spPost(Files(this, `add(overwrite=${shouldOverWrite},url='${encodePath(url)}')`));
70 const file = fileFromServerRelativePath(this, response.ServerRelativeUrl);
71 file.using(CancelAction(() => {
72 return File(file).delete();
73 }));
74 return file.setContentChunked(content, progress, chunkSize);
75 }
76 /**
77 * Adds a ghosted file to an existing list or document library. Not supported for batching.
78 *
79 * @param fileUrl The server-relative url where you want to save the file.
80 * @param templateFileType The type of use to create the file.
81 * @returns The template file that was added and the raw response.
82 */
83 async addTemplateFile(fileUrl, templateFileType) {
84 const response = await spPost(Files(this, `addTemplateFile(urloffile='${encodePath(fileUrl)}',templatefiletype=${templateFileType})`));
85 return {
86 data: response,
87 file: fileFromServerRelativePath(this, response.ServerRelativeUrl),
88 };
89 }
90};
91__decorate([
92 cancelableScope
93], _Files.prototype, "addUsingPath", null);
94__decorate([
95 cancelableScope
96], _Files.prototype, "addChunked", null);
97__decorate([
98 cancelableScope
99], _Files.prototype, "addTemplateFile", null);
100_Files = __decorate([
101 defaultPath("files")
102], _Files);
103export { _Files };
104export const Files = spInvokableFactory(_Files);
105/**
106 * Describes a single File instance
107 *
108 */
109export class _File extends ReadableFile {
110 constructor() {
111 super(...arguments);
112 this.delete = deleteableWithETag();
113 }
114 /**
115 * Gets a value that specifies the list item field values for the list item corresponding to the file.
116 *
117 */
118 get listItemAllFields() {
119 return SPInstance(this, "listItemAllFields");
120 }
121 /**
122 * Gets a collection of versions
123 *
124 */
125 get versions() {
126 return Versions(this);
127 }
128 /**
129 * Gets the current locked by user
130 *
131 */
132 async getLockedByUser() {
133 const u = await spGet(File(this, "lockedByUser"));
134 if (u["odata.null"] === true) {
135 return null;
136 }
137 else {
138 return u;
139 }
140 }
141 /**
142 * Approves the file submitted for content approval with the specified comment.
143 * Only documents in lists that are enabled for content approval can be approved.
144 *
145 * @param comment The comment for the approval.
146 */
147 approve(comment = "") {
148 return spPost(File(this, `approve(comment='${encodePath(comment)}')`));
149 }
150 /**
151 * Stops the chunk upload session without saving the uploaded data. Does not support batching.
152 * If the file doesn’t already exist in the library, the partially uploaded file will be deleted.
153 * Use this in response to user action (as in a request to cancel an upload) or an error or exception.
154 * Use the uploadId value that was passed to the StartUpload method that started the upload session.
155 * This method is currently available only on Office 365.
156 *
157 * @param uploadId The unique identifier of the upload session.
158 */
159 cancelUpload(uploadId) {
160 return spPost(File(this, `cancelUpload(uploadId=guid'${uploadId}')`));
161 }
162 /**
163 * Checks the file in to a document library based on the check-in type.
164 *
165 * @param comment A comment for the check-in. Its length must be <= 1023.
166 * @param checkinType The check-in type for the file.
167 */
168 checkin(comment = "", checkinType = CheckinType.Major) {
169 if (comment.length > 1023) {
170 throw Error("The maximum comment length is 1023 characters.");
171 }
172 return spPost(File(this, `checkin(comment='${encodePath(comment)}',checkintype=${checkinType})`));
173 }
174 /**
175 * Checks out the file from a document library.
176 */
177 checkout() {
178 return spPost(File(this, "checkout"));
179 }
180 /**
181 * Copies the file to the destination url.
182 *
183 * @param url The absolute url or server relative url of the destination file path to copy to.
184 * @param shouldOverWrite Should a file with the same name in the same location be overwritten?
185 */
186 copyTo(url, shouldOverWrite = true) {
187 return spPost(File(this, `copyTo(strnewurl='${encodePath(url)}',boverwrite=${shouldOverWrite})`));
188 }
189 async copyByPath(destUrl, ...rest) {
190 let options = {
191 ShouldBypassSharedLocks: true,
192 ResetAuthorAndCreatedOnCopy: true,
193 KeepBoth: false,
194 };
195 if (rest.length === 2) {
196 if (typeof rest[1] === "boolean") {
197 options.KeepBoth = rest[1];
198 }
199 else if (typeof rest[1] === "object") {
200 options = { ...options, ...rest[1] };
201 }
202 }
203 return this.moveCopyImpl(destUrl, options, rest[0], "CopyFileByPath");
204 }
205 /**
206 * Denies approval for a file that was submitted for content approval.
207 * Only documents in lists that are enabled for content approval can be denied.
208 *
209 * @param comment The comment for the denial.
210 */
211 deny(comment = "") {
212 if (comment.length > 1023) {
213 throw Error("The maximum comment length is 1023 characters.");
214 }
215 return spPost(File(this, `deny(comment='${encodePath(comment)}')`));
216 }
217 async moveByPath(destUrl, ...rest) {
218 let options = {
219 KeepBoth: false,
220 ShouldBypassSharedLocks: true,
221 RetainEditorAndModifiedOnMove: false,
222 };
223 if (rest.length === 2) {
224 if (typeof rest[1] === "boolean") {
225 options.KeepBoth = rest[1];
226 }
227 else if (typeof rest[1] === "object") {
228 options = { ...options, ...rest[1] };
229 }
230 }
231 return this.moveCopyImpl(destUrl, options, rest[0], "MoveFileByPath");
232 }
233 /**
234 * Submits the file for content approval with the specified comment.
235 *
236 * @param comment The comment for the published file. Its length must be <= 1023.
237 */
238 publish(comment = "") {
239 if (comment.length > 1023) {
240 throw Error("The maximum comment length is 1023 characters.");
241 }
242 return spPost(File(this, `publish(comment='${encodePath(comment)}')`));
243 }
244 /**
245 * Moves the file to the Recycle Bin and returns the identifier of the new Recycle Bin item.
246 *
247 * @returns The GUID of the recycled file.
248 */
249 recycle() {
250 return spPost(File(this, "recycle"));
251 }
252 /**
253 * Deletes the file object with options.
254 *
255 * @param parameters Specifies the options to use when deleting a file.
256 */
257 async deleteWithParams(parameters) {
258 return spPost(File(this, "DeleteWithParameters"), body({ parameters }));
259 }
260 /**
261 * Reverts an existing checkout for the file.
262 *
263 */
264 undoCheckout() {
265 return spPost(File(this, "undoCheckout"));
266 }
267 /**
268 * Removes the file from content approval or unpublish a major version.
269 *
270 * @param comment The comment for the unpublish operation. Its length must be <= 1023.
271 */
272 unpublish(comment = "") {
273 if (comment.length > 1023) {
274 throw Error("The maximum comment length is 1023 characters.");
275 }
276 return spPost(File(this, `unpublish(comment='${encodePath(comment)}')`));
277 }
278 /**
279 * Checks to see if the file represented by this object exists
280 *
281 */
282 async exists() {
283 try {
284 const r = await File(this).select("Exists")();
285 return r.Exists;
286 }
287 catch (e) {
288 // this treats any error here as the file not existing, which
289 // might not be true, but is good enough.
290 return false;
291 }
292 }
293 /**
294 * Sets the content of a file, for large files use setContentChunked. Not supported in batching.
295 *
296 * @param content The file content
297 *
298 */
299 async setContent(content) {
300 await spPost(File(this, "$value"), {
301 body: content,
302 headers: {
303 "X-HTTP-Method": "PUT",
304 },
305 });
306 return File(this);
307 }
308 /**
309 * Gets the associated list item for this folder, loading the default properties
310 */
311 async getItem(...selects) {
312 const q = this.listItemAllFields;
313 const d = await q.select(...selects)();
314 return Object.assign(Item([this, odataUrlFrom(d)]), d);
315 }
316 /**
317 * Sets the contents of a file using a chunked upload approach. Not supported in batching.
318 *
319 * @param file The file to upload
320 * @param progress A callback function which can be used to track the progress of the upload
321 * @param chunkSize The size of each file slice, in bytes (default: 10485760)
322 */
323 async setContentChunked(file, progress, chunkSize = 10485760) {
324 if (!isFunc(progress)) {
325 progress = () => null;
326 }
327 const fileSize = (file === null || file === void 0 ? void 0 : file.size) || file.length;
328 const totalBlocks = parseInt((fileSize / chunkSize).toString(), 10) + ((fileSize % chunkSize === 0) ? 1 : 0);
329 const uploadId = getGUID();
330 const fileRef = File(this).using(CancelAction(() => {
331 return File(fileRef).cancelUpload(uploadId);
332 }));
333 // report that we are starting
334 progress({ uploadId, blockNumber: 1, chunkSize, currentPointer: 0, fileSize, stage: "starting", totalBlocks });
335 let currentPointer = await fileRef.startUpload(uploadId, file.slice(0, chunkSize));
336 // skip the first and last blocks
337 for (let i = 2; i < totalBlocks; i++) {
338 progress({ uploadId, blockNumber: i, chunkSize, currentPointer, fileSize, stage: "continue", totalBlocks });
339 currentPointer = await fileRef.continueUpload(uploadId, currentPointer, file.slice(currentPointer, currentPointer + chunkSize));
340 }
341 progress({ uploadId, blockNumber: totalBlocks, chunkSize, currentPointer, fileSize, stage: "finishing", totalBlocks });
342 return fileRef.finishUpload(uploadId, currentPointer, file.slice(currentPointer));
343 }
344 /**
345 * Starts a new chunk upload session and uploads the first fragment.
346 * The current file content is not changed when this method completes.
347 * The method is idempotent (and therefore does not change the result) as long as you use the same values for uploadId and stream.
348 * The upload session ends either when you use the CancelUpload method or when you successfully
349 * complete the upload session by passing the rest of the file contents through the ContinueUpload and FinishUpload methods.
350 * The StartUpload and ContinueUpload methods return the size of the running total of uploaded data in bytes,
351 * so you can pass those return values to subsequent uses of ContinueUpload and FinishUpload.
352 * This method is currently available only on Office 365.
353 *
354 * @param uploadId The unique identifier of the upload session.
355 * @param fragment The file contents.
356 * @returns The size of the total uploaded data in bytes.
357 */
358 async startUpload(uploadId, fragment) {
359 let n = await spPost(File(this, `startUpload(uploadId=guid'${uploadId}')`), { body: fragment });
360 if (typeof n === "object") {
361 // When OData=verbose the payload has the following shape:
362 // { StartUpload: "10485760" }
363 n = n.StartUpload;
364 }
365 return parseFloat(n);
366 }
367 /**
368 * Continues the chunk upload session with an additional fragment.
369 * The current file content is not changed.
370 * Use the uploadId value that was passed to the StartUpload method that started the upload session.
371 * This method is currently available only on Office 365.
372 *
373 * @param uploadId The unique identifier of the upload session.
374 * @param fileOffset The size of the offset into the file where the fragment starts.
375 * @param fragment The file contents.
376 * @returns The size of the total uploaded data in bytes.
377 */
378 async continueUpload(uploadId, fileOffset, fragment) {
379 let n = await spPost(File(this, `continueUpload(uploadId=guid'${uploadId}',fileOffset=${fileOffset})`), { body: fragment });
380 if (typeof n === "object") {
381 // When OData=verbose the payload has the following shape:
382 // { ContinueUpload: "20971520" }
383 n = n.ContinueUpload;
384 }
385 return parseFloat(n);
386 }
387 /**
388 * Uploads the last file fragment and commits the file. The current file content is changed when this method completes.
389 * Use the uploadId value that was passed to the StartUpload method that started the upload session.
390 * This method is currently available only on Office 365.
391 *
392 * @param uploadId The unique identifier of the upload session.
393 * @param fileOffset The size of the offset into the file where the fragment starts.
394 * @param fragment The file contents.
395 * @returns The newly uploaded file.
396 */
397 async finishUpload(uploadId, fileOffset, fragment) {
398 const response = await spPost(File(this, `finishUpload(uploadId=guid'${uploadId}',fileOffset=${fileOffset})`), { body: fragment });
399 return {
400 data: response,
401 file: fileFromServerRelativePath(this, response.ServerRelativeUrl),
402 };
403 }
404 moveCopyImpl(destUrl, options, overwrite, methodName) {
405 // create a timeline we will manipulate for this request
406 const poster = File(this);
407 // add our pre-request actions, this fixes issues with batching hanging #2668
408 poster.on.pre(noInherit(async (url, init, result) => {
409 const { ServerRelativeUrl: srcUrl, ["odata.id"]: absoluteUrl } = await File(this).using(BatchNever()).select("ServerRelativeUrl")();
410 const webBaseUrl = new URL(extractWebUrl(absoluteUrl));
411 url = combine(webBaseUrl.toString(), `/_api/SP.MoveCopyUtil.${methodName}(overwrite=@a1)?@a1=${overwrite}`);
412 init = body({
413 destPath: toResourcePath(isUrlAbsolute(destUrl) ? destUrl : `${webBaseUrl.protocol}//${webBaseUrl.host}${destUrl}`),
414 options,
415 srcPath: toResourcePath(isUrlAbsolute(srcUrl) ? srcUrl : `${webBaseUrl.protocol}//${webBaseUrl.host}${srcUrl}`),
416 }, init);
417 return [url, init, result];
418 }));
419 return spPost(poster).then(() => fileFromPath(this, destUrl));
420 }
421}
422__decorate([
423 cancelableScope
424], _File.prototype, "copyByPath", null);
425__decorate([
426 cancelableScope
427], _File.prototype, "moveByPath", null);
428__decorate([
429 cancelableScope
430], _File.prototype, "setContentChunked", null);
431export const File = spInvokableFactory(_File);
432/**
433 * Creates an IFile instance given a base object and a server relative path
434 *
435 * @param base Valid SPQueryable from which the observers will be used and the web url extracted
436 * @param serverRelativePath The server relative url to the file (ex: '/sites/dev/documents/file.txt')
437 * @returns IFile instance referencing the file described by the supplied parameters
438 */
439export function fileFromServerRelativePath(base, serverRelativePath) {
440 return File([base, extractWebUrl(base.toUrl())], `_api/web/getFileByServerRelativePath(decodedUrl='${encodePath(serverRelativePath)}')`);
441}
442/**
443 * Creates an IFile instance given a base object and an absolute path
444 *
445 * @param base Valid SPQueryable from which the observers will be used
446 * @param serverRelativePath The absolute url to the file (ex: 'https://tenant.sharepoint.com/sites/dev/documents/file.txt')
447 * @returns IFile instance referencing the file described by the supplied parameters
448 */
449export async function fileFromAbsolutePath(base, absoluteFilePath) {
450 const { WebFullUrl } = await File(this).using(BatchNever()).getContextInfo(absoluteFilePath);
451 const { pathname } = new URL(absoluteFilePath);
452 return fileFromServerRelativePath(File([base, combine(WebFullUrl, "_api/web")]), decodeURIComponent(pathname));
453}
454/**
455 * Creates an IFile intance given a base object and either an absolute or server relative path to a file
456 *
457 * @param base Valid SPQueryable from which the observers will be used
458 * @param serverRelativePath server relative or absolute url to the file (ex: 'https://tenant.sharepoint.com/sites/dev/documents/file.txt' or '/sites/dev/documents/file.txt')
459 * @returns IFile instance referencing the file described by the supplied parameters
460 */
461export async function fileFromPath(base, path) {
462 return (isUrlAbsolute(path) ? fileFromAbsolutePath : fileFromServerRelativePath)(base, path);
463}
464/**
465 * Describes a collection of Version objects
466 *
467 */
468let _Versions = class _Versions extends _SPCollection {
469 /**
470 * Gets a version by id
471 *
472 * @param versionId The id of the version to retrieve
473 */
474 getById(versionId) {
475 return Version(this).concat(`(${versionId})`);
476 }
477 /**
478 * Deletes all the file version objects in the collection.
479 *
480 */
481 deleteAll() {
482 return spPost(Versions(this, "deleteAll"));
483 }
484 /**
485 * Deletes the specified version of the file.
486 *
487 * @param versionId The ID of the file version to delete.
488 */
489 deleteById(versionId) {
490 return spPost(Versions(this, `deleteById(vid=${versionId})`));
491 }
492 /**
493 * Recycles the specified version of the file.
494 *
495 * @param versionId The ID of the file version to delete.
496 */
497 recycleByID(versionId) {
498 return spPost(Versions(this, `recycleByID(vid=${versionId})`));
499 }
500 /**
501 * Deletes the file version object with the specified version label.
502 *
503 * @param label The version label of the file version to delete, for example: 1.2
504 */
505 deleteByLabel(label) {
506 return spPost(Versions(this, `deleteByLabel(versionlabel='${encodePath(label)}')`));
507 }
508 /**
509 * Recycles the file version object with the specified version label.
510 *
511 * @param label The version label of the file version to delete, for example: 1.2
512 */
513 recycleByLabel(label) {
514 return spPost(Versions(this, `recycleByLabel(versionlabel='${encodePath(label)}')`));
515 }
516 /**
517 * Creates a new file version from the file specified by the version label.
518 *
519 * @param label The version label of the file version to restore, for example: 1.2
520 */
521 restoreByLabel(label) {
522 return spPost(Versions(this, `restoreByLabel(versionlabel='${encodePath(label)}')`));
523 }
524};
525_Versions = __decorate([
526 defaultPath("versions")
527], _Versions);
528export { _Versions };
529export const Versions = spInvokableFactory(_Versions);
530/**
531 * Describes a single Version instance
532 *
533 */
534export class _Version extends ReadableFile {
535 constructor() {
536 super(...arguments);
537 this.delete = deleteable();
538 }
539}
540export const Version = spInvokableFactory(_Version);
541/**
542 * Types for document check in.
543 * Minor = 0
544 * Major = 1
545 * Overwrite = 2
546 */
547export var CheckinType;
548(function (CheckinType) {
549 CheckinType[CheckinType["Minor"] = 0] = "Minor";
550 CheckinType[CheckinType["Major"] = 1] = "Major";
551 CheckinType[CheckinType["Overwrite"] = 2] = "Overwrite";
552})(CheckinType || (CheckinType = {}));
553/**
554 * File move opertions
555 */
556export var MoveOperations;
557(function (MoveOperations) {
558 /**
559 * Produce an error if a file with the same name exists in the destination
560 */
561 MoveOperations[MoveOperations["None"] = 0] = "None";
562 /**
563 * Overwrite a file with the same name if it exists. Value is 1.
564 */
565 MoveOperations[MoveOperations["Overwrite"] = 1] = "Overwrite";
566 /**
567 * Complete the move operation even if supporting files are separated from the file. Value is 8.
568 */
569 MoveOperations[MoveOperations["AllowBrokenThickets"] = 8] = "AllowBrokenThickets";
570 /**
571 * Boolean specifying whether to retain the source of the move's editor and modified by datetime.
572 */
573 MoveOperations[MoveOperations["RetainEditorAndModifiedOnMove"] = 2048] = "RetainEditorAndModifiedOnMove";
574})(MoveOperations || (MoveOperations = {}));
575export var TemplateFileType;
576(function (TemplateFileType) {
577 TemplateFileType[TemplateFileType["StandardPage"] = 0] = "StandardPage";
578 TemplateFileType[TemplateFileType["WikiPage"] = 1] = "WikiPage";
579 TemplateFileType[TemplateFileType["FormPage"] = 2] = "FormPage";
580 TemplateFileType[TemplateFileType["ClientSidePage"] = 3] = "ClientSidePage";
581})(TemplateFileType || (TemplateFileType = {}));
582//# sourceMappingURL=types.js.map
\No newline at end of file