Merge branch '14602_admin_compute_node_paginations'
[arvados.git] / src / common / webdav.ts
1 // Copyright (C) The Arvados Authors. All rights reserved.
2 //
3 // SPDX-License-Identifier: AGPL-3.0
4
5 export class WebDAV {
6
7     defaults: WebDAVDefaults = {
8         baseURL: '',
9         headers: {},
10     };
11
12     constructor(config?: Partial<WebDAVDefaults>, private createRequest = () => new XMLHttpRequest()) {
13         if (config) {
14             this.defaults = { ...this.defaults, ...config };
15         }
16     }
17
18     propfind = (url: string, config: WebDAVRequestConfig = {}) =>
19         this.request({
20             ...config, url,
21             method: 'PROPFIND'
22         })
23
24     put = (url: string, data?: any, config: WebDAVRequestConfig = {}) =>
25         this.request({
26             ...config, url,
27             method: 'PUT',
28             data
29         })
30
31     upload = (url: string, path: string, files: File[], config: WebDAVRequestConfig = {}) => {
32         const fd = new FormData();
33         fd.append('path', path);
34         files.forEach((f, idx) => {
35             fd.append(`file-${idx}`, f);
36         });
37
38         return this.request({
39             ...config, url,
40             method: 'PUT',
41             data: fd
42         });
43     }
44
45     copy = (url: string, destination: string, config: WebDAVRequestConfig = {}) =>
46         this.request({
47             ...config, url,
48             method: 'COPY',
49             headers: { ...config.headers, Destination: this.defaults.baseURL + destination }
50         })
51
52     move = (url: string, destination: string, config: WebDAVRequestConfig = {}) =>
53         this.request({
54             ...config, url,
55             method: 'MOVE',
56             headers: { ...config.headers, Destination: this.defaults.baseURL + destination }
57         })
58
59     delete = (url: string, config: WebDAVRequestConfig = {}) =>
60         this.request({
61             ...config, url,
62             method: 'DELETE'
63         })
64
65     private request = (config: RequestConfig) => {
66         return new Promise<XMLHttpRequest>((resolve, reject) => {
67             const r = this.createRequest();
68             r.open(config.method, this.defaults.baseURL + config.url);
69
70             const headers = { ...this.defaults.headers, ...config.headers };
71             Object
72                 .keys(headers)
73                 .forEach(key => r.setRequestHeader(key, headers[key]));
74
75             if (config.onUploadProgress) {
76                 r.upload.addEventListener('progress', config.onUploadProgress);
77             }
78
79             r.addEventListener('load', () => {
80                 if (r.status === 404) {
81                     return reject(r);
82                 } else {
83                     return resolve(r);
84                 }
85             });
86
87             r.addEventListener('error', () => {
88                 return reject(r);
89             });
90
91             r.upload.addEventListener('error', () => {
92                 return reject(r);
93             });
94
95             r.send(config.data);
96         });
97     }
98 }
99
100 export interface WebDAVRequestConfig {
101     headers?: {
102         [key: string]: string;
103     };
104     onUploadProgress?: (event: ProgressEvent) => void;
105 }
106
107 interface WebDAVDefaults {
108     baseURL: string;
109     headers: { [key: string]: string };
110 }
111
112 interface RequestConfig {
113     method: string;
114     url: string;
115     headers?: { [key: string]: string };
116     data?: any;
117     onUploadProgress?: (event: ProgressEvent) => void;
118 }