diff --git a/packages/file-handling/src/dbp-nextcloud-file-picker.js b/packages/file-handling/src/dbp-nextcloud-file-picker.js index f50c9c43d687eeb58c8d61938b7f8a25fdb3e8a0..61d54ad475084f926713eb9011b9f40a2e740c09 100644 --- a/packages/file-handling/src/dbp-nextcloud-file-picker.js +++ b/packages/file-handling/src/dbp-nextcloud-file-picker.js @@ -41,6 +41,8 @@ export class NextcloudFilePicker extends ScopedElementsMixin(DBPLitElement) { this.uploadFileDirectory = null; this.fileList = []; this.fileNameCounter = 0; + this.activeDirectoryRights = 'SGDNVCK'; + this.activeDirectoryACL = ''; } static get scopedElements() { @@ -70,6 +72,8 @@ export class NextcloudFilePicker extends ScopedElementsMixin(DBPLitElement) { replaceFilename: { type: String, attribute: false }, uploadFileObject: { type: Object, attribute: false }, uploadFileDirectory: { type: String, attribute: false }, + activeDirectoryRights: { type: String, attribute: false }, + activeDirectoryACL: { type: String, attribute: false }, }; } @@ -143,7 +147,9 @@ export class NextcloudFilePicker extends ScopedElementsMixin(DBPLitElement) { const hours = ("0" + timestamp.getHours()).slice(-2); const minutes = ("0" + timestamp.getMinutes()).slice(-2); return date + "." + month + "." + year + " " + hours + ":" + minutes; - }} + }}, + {title: "rights", field: "props.permissions"}, + {title: "acl", field: "props.acl-list.acl.acl-permissions"} ], initialSort:[ {column:"basename", dir:"asc"}, @@ -162,6 +168,10 @@ export class NextcloudFilePicker extends ScopedElementsMixin(DBPLitElement) { const data = row.getData(); if (this.directoriesOnly) { + // comment out if you want to navigate through folders with double click + const data = row.getData(); + this.directoryClicked(e, data); + this.folderIsSelected = i18n.t('nextcloud-file-picker.load-in-folder'); } else { @@ -183,10 +193,12 @@ export class NextcloudFilePicker extends ScopedElementsMixin(DBPLitElement) { } }); - if (this.tabulatorTable.browserMobile === false) + + // Strg + click select mode on desktop + /*if (this.tabulatorTable.browserMobile === false) { this.tabulatorTable.options.selectableRangeMode = "click"; - } + }*/ function checkFileType(data, filterParams) { // check if file is allowed if (typeof data.mime === 'undefined') { @@ -237,28 +249,30 @@ export class NextcloudFilePicker extends ScopedElementsMixin(DBPLitElement) { } onReceiveWindowMessage(event) { - const data = event.data; - console.log("data", data); - - if (data.type === "webapppassword") { - if(this.loginWindow !== null) { - this.loginWindow.close(); - } - - const apiUrl = this.webDavUrl + "/" + data.loginName; - console.log("url: ", this.webDavUrl); - // see https://github.com/perry-mitchell/webdav-client/blob/master/API.md#module_WebDAV.createClient + if (this.webDavClient === null) + { + const data = event.data; + console.log("data", data); + console.log("context", this.directoriesOnly); - this.webDavClient = createClient( - apiUrl, - { - username: data.loginName, - password: data.token + if (data.type === "webapppassword") { + if(this.loginWindow !== null) { + this.loginWindow.close(); } - ); - this.loadDirectory(this.directoryPath); + const apiUrl = this.webDavUrl + "/" + data.loginName; + console.log("url: ", this.webDavUrl); + // see https://github.com/perry-mitchell/webdav-client/blob/master/API.md#module_WebDAV.createClient + this.webDavClient = createClient( + apiUrl, + { + username: data.loginName, + password: data.token + } + ); + this.loadDirectory(this.directoryPath); + } } } @@ -274,14 +288,34 @@ export class NextcloudFilePicker extends ScopedElementsMixin(DBPLitElement) { this.directoryPath = path; // see https://github.com/perry-mitchell/webdav-client#getdirectorycontents - + if(typeof this.webDavClient === "undefined" && !this.webDavClient) + { + console.log("no client detected"); + //todo load new client + } this.webDavClient - .getDirectoryContents(path, {details: true}) + .getDirectoryContents(path, {details: true, data: "<?xml version=\"1.0\"?>" + + "<d:propfind xmlns:d=\"DAV:\" xmlns:oc=\"http://owncloud.org/ns\" xmlns:nc=\"http://nextcloud.org/ns\" xmlns:ocs=\"http://open-collaboration-services.org/ns\">" + + " <d:prop>" + + " <d:getlastmodified />" + + " <d:resourcetype />" + + " <d:getcontenttype />" + + " <d:getcontentlength />" + + " <d:getetag />" + + " <oc:permissions />" + + " <nc:acl-list>" + + " <nc:acl>" + + " <nc:acl-permissions />" + + " </nc:acl>" + + " </nc:acl-list>" + + " </d:prop>" + + "</d:propfind>"}) .then(contents => { //console.log("contents", contents); this.loading = false; this.statusText = ""; this.tabulatorTable.setData(contents.data); + console.log("!!!!!!!!!!!!!!!!!!!!!!!!", contents.data) this.isPickerActive = true; }).catch(error => { console.error(error.message); @@ -304,27 +338,18 @@ export class NextcloudFilePicker extends ScopedElementsMixin(DBPLitElement) { this.loading = false; this.statusText = reloadButton; }); - - const contents2 = this.webDavClient.customRequest(path, { - method: "PROPFIND", - headers: { - Accept: "text/plain", - Depth: 0 - }, - data: "<?xml version=\"1.0\"?>\n" + - "<d:propfind xmlns:d=\"DAV:\" xmlns:oc=\"http://owncloud.org/ns\" xmlns:nc=\"http://nextcloud.org/ns\">\n" + - " <d:prop>\n" + - " <oc:permissions />\n" + - " <nc:acl-permissions />\n" + - " </d:prop>\n" + - "</d:propfind>", - responseType: "text" - }); // contents => { //console.log("---------", contents)}); - - } directoryClicked(event, file) { + // save rights of clicked directory + this.activeDirectoryRights = file.props.permissions; + if(typeof file.props['acl-list'] !== "undefined" && + typeof file.props['acl-list']['acl']['acl-permissions'] !== "undefined" && file.props['acl-list']['acl']['acl-permissions']) { + this.activeDirectoryACL = file.props['acl-list']['acl']['acl-permissions']; + } + else { + this.activeDirectoryACL = ''; + } this.loadDirectory(file.filename); event.preventDefault(); } @@ -473,12 +498,111 @@ export class NextcloudFilePicker extends ScopedElementsMixin(DBPLitElement) { this.fileNameCounter = 1; } + checkRights(file) { + // Todo check rights after an conflict and return which should be grayed out (the options rename or replace) + // no rename: if you dont have create permissions + // no replace if you dont have write permissions + + // nextcloud permissions + let perm = 0; + let active_directory_perm = this.activeDirectoryRights; + let rows = this.tabulatorTable.searchRows("basename", "=", this.replaceFilename); + perm = rows[0].getData().props.permissions; + + console.log("RIGHTS IN THIS FOLDER:", this.activeDirectoryRights); + console.log("RIGHT OF FILE:", perm); + + console.log("RIGHTS IN THIS FOLDER:", this.activeDirectoryRights); + console.log("RIGHT OF FILE:", perm); + + // if I'm in an group or external folder take the acl permissions + if(this.activeDirectoryACL !== '') + { + console.log("ACL SET"); + active_directory_perm = this.activeDirectoryACL; + } + + + + // read only directory + if(active_directory_perm === "MG" || active_directory_perm === "SG") + { + console.log("0"); + return 0; + } + + // read only file + if((perm === 'SG' || perm === 'MG') && !active_directory_perm.includes("CK") ) + { + console.log("0"); + return 0; + } + + // read only file + if((perm === 'SG' || perm === 'MG') && active_directory_perm.includes("CK") ) + { + console.log("1"); + return 1; + } + + // only create and no edit + if((active_directory_perm.includes("CK") && !active_directory_perm.includes("NV")) || (active_directory_perm.includes("CK") && !perm.includes("NV"))) { + console.log("1"); + return 1; + } + + // only edit and no create + if(perm.includes("NV") && !active_directory_perm.includes("CK")) { + console.log("2"); + return 2; + } + + console.log("-1"); + return -1; + } + /** * */ replaceModalDialog(file, directory) { this.uploadFileObject = file; this.uploadFileDirectory = directory; + let rights = this.checkRights(file); + if(rights === 0) { + // TODO Übersetzen + this.loading = false; + this.statusText = "readonly: Du darfst in diesem ordner nichts schreiben"; + return; + } + else if(rights === 1) { + this.loading = false; + this.statusText = "Du darfst hier nur erstellen"; + this._("#replace-replace").setAttribute("disabled", "true"); + this._("#replace-new-name").removeAttribute("disabled"); + this._("#replace-replace").checked = false; + this._("#replace-new-name").checked = true; + this.disableInputField(); + this._("#replace-new-name").focus(); + + } + else if(rights === 2) { + this.loading = false; + this.statusText = "Du darfst hier nur bearbeiten"; + this._("#replace-new-name").setAttribute("disabled", "true"); + this._("#replace-replace").removeAttribute("disabled"); + this._("#replace-new-name").checked = false; + this._("#replace-replace").checked = true; + this.disableInputField(); + this._("#replace-replace").focus(); + } + else { + this._("#replace-new-name").removeAttribute("disabled"); + this._("#replace-replace").removeAttribute("disabled"); + this._("#replace-replace").checked = false; + this._("#replace-new-name").checked = true; + this.disableInputField(); + this._("#replace-new-name").focus(); + } MicroModal.show(this._('#replace-modal')); } @@ -538,7 +662,9 @@ export class NextcloudFilePicker extends ScopedElementsMixin(DBPLitElement) { * */ cancelEverything() { - this.fileList = []; + this.statusText = ""; + this.loading = false; + this.fileList = []; } /** @@ -582,7 +708,7 @@ export class NextcloudFilePicker extends ScopedElementsMixin(DBPLitElement) { */ getBreadcrumb() { let htmlpath = []; - htmlpath[0] = html`<a @click="${() => { this.loadDirectory("/"); }}" title="${i18n.t('nextcloud-file-picker.folder-home')}"><dbp-icon name="home"></dbp-icon> </a>`; + htmlpath[0] = html`<span class="breadcrumb"><a @click="${() => { this.loadDirectory("/"); }}" title="${i18n.t('nextcloud-file-picker.folder-home')}"><dbp-icon name="home"></dbp-icon> </a></span>`; const directories = this.directoryPath.split('/'); if (directories[1] === "") { @@ -597,7 +723,7 @@ export class NextcloudFilePicker extends ScopedElementsMixin(DBPLitElement) { path += directories[j]; } - htmlpath[i] = html` › <a @click="${() => { this.loadDirectory(path); }}" title="${i18n.t('nextcloud-file-picker.load-path-link', {path: directories[i]})}">${directories[i]}</a>`; + htmlpath[i] = html`<span class="muted"> › </span><span class="breadcrumb"><a @click="${() => { this.loadDirectory(path); }}" title="${i18n.t('nextcloud-file-picker.load-path-link', {path: directories[i]})}">${directories[i]}</a></span>`; } return htmlpath; @@ -739,17 +865,17 @@ export class NextcloudFilePicker extends ScopedElementsMixin(DBPLitElement) { .tabulator-row, .tabulator-row.tabulator-row-even{ background-color: white; } + + .tabulator-row.tabulator-selectable.tabulator-selectable:hover{ + background-color: var(--dbp-secondary-bg-color); + color: var(--dbp-secondary-text-color); + } - .tabulator-row.tabulator-selected:hover, .tabulator-row.tabulator-selected{ + .tabulator-row.tabulator-selectable.tabulator-selected:hover, .tabulator-row.tabulator-selected{ background-color: var(--dbp-dark); color: var(--dbp-light); } - .tabulator-row.tabulator-selectable:hover{ - background-color: #eee; - color: var(--dbp-dark); - } - .tabulator .tabulator-header .tabulator-col .tabulator-col-content{ display: inline-flex; } @@ -885,6 +1011,18 @@ export class NextcloudFilePicker extends ScopedElementsMixin(DBPLitElement) { padding-bottom: 10px; } + .breadcrumb, .muted{ + color: var(--dbp-muted-text); + } + + .breadcrumb:last-child{ + color: inherit; + } + + input:disabled+label{ + color: #aaa; + } + @media only screen and (orientation: portrait) and (max-device-width: 765px) { @@ -1058,7 +1196,7 @@ export class NextcloudFilePicker extends ScopedElementsMixin(DBPLitElement) { </label> </div> <div> - <input type="radio" class="radio-btn" name="replacement" value="replace" @click="${() => {this.disableInputField();}}"> + <input type="radio" id="replace-replace" class="radio-btn" name="replacement" value="replace" @click="${() => {this.disableInputField();}}"> <label for="replace">${i18n.t('nextcloud-file-picker.replace-replace')}</label> </div> <div> diff --git a/packages/file-handling/src/file-sink.js b/packages/file-handling/src/file-sink.js index e0b890e5af9296d884fbbfc2ffa92ab8929ae3ef..f79667f5d2dda7f4d05f5643f3a7882f270b6bec 100644 --- a/packages/file-handling/src/file-sink.js +++ b/packages/file-handling/src/file-sink.js @@ -67,7 +67,14 @@ export class FileSink extends ScopedElementsMixin(DBPLitElement) { let zip = new JSZip(); let fileNames = []; - // add all signed pdf-files + // download one file not compressed! + if(this.files.length === 1) + { + FileSaver.saveAs(this.files[0], this.files[0].filename); + return; + } + + // download all files compressed this.files.forEach((file) => { let fileName = file.name; @@ -204,12 +211,12 @@ export class FileSink extends ScopedElementsMixin(DBPLitElement) { <div class="source-main ${classMap({"hidden": this.activeDestination !== "local"})}"> <div id="zip-download-block"> <div class="block"> - ${this.text || i18n.t('file-sink.local-intro', {'amount': this.files.length})} + ${this.text || i18n.t('file-sink.local-intro', {'count': this.files.length})} </div> <button class="button is-primary" ?disabled="${this.disabled}" @click="${() => { this.downloadCompressedFiles(); }}"> - ${this.buttonLabel || i18n.t('file-sink.local-button')} + ${this.buttonLabel || i18n.t('file-sink.local-button', {'count': this.files.length})} </button> </div> </div> diff --git a/packages/file-handling/src/i18n/de/translation.json b/packages/file-handling/src/i18n/de/translation.json index 04f4e865125fc4cbe4142f6f2dee45b0d9b951c6..3d5cab737837854452d66b415437e1a3019eea84 100644 --- a/packages/file-handling/src/i18n/de/translation.json +++ b/packages/file-handling/src/i18n/de/translation.json @@ -16,8 +16,10 @@ "nav-local": "Lokaler Computer" }, "file-sink": { - "local-intro": "{{amount}} Datei(en) als ZIP-Datei herunterladen", - "local-button": "ZIP-Datei herunterladen", + "local-intro": "{{count}} Datei herunterladen", + "local-intro_plural": "{{count}} Dateien als ZIP-Datei herunterladen", + "local-button": "Datei herunterladen", + "local-button_plural": "ZIP-Datei herunterladen", "modal-close": "Dialog schließen", "nav-local": "Lokaler Computer", "upload-success-title": "Erfolgreich hochgeladen", diff --git a/packages/file-handling/src/i18n/en/translation.json b/packages/file-handling/src/i18n/en/translation.json index cbb7bd2d4a970d0d4ccdf732d59f41bc723f8bab..f8790698bec1655c01e766f216465cf973d387a8 100644 --- a/packages/file-handling/src/i18n/en/translation.json +++ b/packages/file-handling/src/i18n/en/translation.json @@ -16,8 +16,10 @@ "nav-local": "My device" }, "file-sink": { - "local-intro": "Download {{amount}} file(s) as ZIP-file", - "local-button": "Download ZIP-file", + "local-intro": "Download {{count}} file", + "local-intro_plural": "Download {{count}} files als ZIP", + "local-button": "Download file", + "local-button_plural": "Download ZIP-file", "modal-close": "Close dialog", "nav-local": "My device", "upload-success-title": "Successful uploaded",