diff --git a/.eslintrc.js b/.eslintrc.js index 471030c9..9e01ab3f 100644 --- a/.eslintrc.js +++ b/.eslintrc.js @@ -23,9 +23,10 @@ module.exports = { ], "parser": "@typescript-eslint/parser", "parserOptions": { - "project": "tsconfig.json", + "project": ["./tsconfig.json"], "sourceType": "module" }, + "files": ["*.ts"], "plugins": [ "@typescript-eslint", "jsdoc", @@ -68,7 +69,7 @@ module.exports = { ], "@typescript-eslint/consistent-type-assertions": "error", "@typescript-eslint/dot-notation": "error", - "@typescript-eslint/explicit-module-boundary-types": "warn", + "@typescript-eslint/explicit-module-boundary-types": "off", "@typescript-eslint/naming-convention": "error", "@typescript-eslint/no-array-constructor": "error", "@typescript-eslint/no-empty-function": "error", @@ -88,10 +89,11 @@ module.exports = { "@typescript-eslint/no-parameter-properties": "off", "@typescript-eslint/no-this-alias": "error", "@typescript-eslint/no-unnecessary-type-assertion": "error", - "@typescript-eslint/no-unsafe-assignment": "error", + "@typescript-eslint/no-unsafe-argument": "off", + "@typescript-eslint/no-unsafe-assignment": "off", "@typescript-eslint/no-unsafe-call": "error", - "@typescript-eslint/no-unsafe-member-access": "error", - "@typescript-eslint/no-unsafe-return": "error", + "@typescript-eslint/no-unsafe-member-access": "off", + "@typescript-eslint/no-unsafe-return": "off", "@typescript-eslint/no-unused-expressions": "error", "@typescript-eslint/no-unused-vars": "warn", "@typescript-eslint/no-use-before-define": "off", @@ -136,7 +138,7 @@ module.exports = { "id-match": "error", "jsdoc/check-alignment": "error", "jsdoc/check-indentation": "error", - "jsdoc/newline-after-description": "error", + "jsdoc/newline-after-description": "off", "max-classes-per-file": [ "error", 1 diff --git a/.gitignore b/.gitignore index 62641d9e..73ac59bf 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,5 @@ +docs + # exclude local environment definition .en .env diff --git a/docs/_config.yml b/docs/_config.yml deleted file mode 100644 index 46b4d992..00000000 --- a/docs/_config.yml +++ /dev/null @@ -1,4 +0,0 @@ -theme: jekyll-theme-minimal -include: - - "_*_.html" - - "_*_.*.html" \ No newline at end of file diff --git a/docs/api/assets/css/main.css b/docs/api/assets/css/main.css deleted file mode 100644 index 959edd73..00000000 --- a/docs/api/assets/css/main.css +++ /dev/null @@ -1,2679 +0,0 @@ -/*! normalize.css v1.1.3 | MIT License | git.io/normalize */ -/* ========================================================================== - * * HTML5 display definitions - * * ========================================================================== */ -/** - * * Correct `block` display not defined in IE 6/7/8/9 and Firefox 3. */ -article, aside, details, figcaption, figure, footer, header, hgroup, main, nav, section, summary { - display: block; -} - -/** - * * Correct `inline-block` display not defined in IE 6/7/8/9 and Firefox 3. */ -audio, canvas, video { - display: inline-block; - *display: inline; - *zoom: 1; -} - -/** - * * Prevent modern browsers from displaying `audio` without controls. - * * Remove excess height in iOS 5 devices. */ -audio:not([controls]) { - display: none; - height: 0; -} - -/** - * * Address styling not present in IE 7/8/9, Firefox 3, and Safari 4. - * * Known issue: no IE 6 support. */ -[hidden] { - display: none; -} - -/* ========================================================================== - * * Base - * * ========================================================================== */ -/** - * * 1. Correct text resizing oddly in IE 6/7 when body `font-size` is set using - * * `em` units. - * * 2. Prevent iOS text size adjust after orientation change, without disabling - * * user zoom. */ -html { - font-size: 100%; - /* 1 */ - -ms-text-size-adjust: 100%; - /* 2 */ - -webkit-text-size-adjust: 100%; - /* 2 */ - font-family: sans-serif; -} - -/** - * * Address `font-family` inconsistency between `textarea` and other form - * * elements. */ -button, input, select, textarea { - font-family: sans-serif; -} - -/** - * * Address margins handled incorrectly in IE 6/7. */ -body { - margin: 0; -} - -/* ========================================================================== - * * Links - * * ========================================================================== */ -/** - * * Address `outline` inconsistency between Chrome and other browsers. */ -a:focus { - outline: thin dotted; -} -a:active, a:hover { - outline: 0; -} - -/** - * * Improve readability when focused and also mouse hovered in all browsers. */ -/* ========================================================================== - * * Typography - * * ========================================================================== */ -/** - * * Address font sizes and margins set differently in IE 6/7. - * * Address font sizes within `section` and `article` in Firefox 4+, Safari 5, - * * and Chrome. */ -h1 { - font-size: 2em; - margin: 0.67em 0; -} - -h2 { - font-size: 1.5em; - margin: 0.83em 0; -} - -h3 { - font-size: 1.17em; - margin: 1em 0; -} - -h4, .tsd-index-panel h3 { - font-size: 1em; - margin: 1.33em 0; -} - -h5 { - font-size: 0.83em; - margin: 1.67em 0; -} - -h6 { - font-size: 0.67em; - margin: 2.33em 0; -} - -/** - * * Address styling not present in IE 7/8/9, Safari 5, and Chrome. */ -abbr[title] { - border-bottom: 1px dotted; -} - -/** - * * Address style set to `bolder` in Firefox 3+, Safari 4/5, and Chrome. */ -b, strong { - font-weight: bold; -} - -blockquote { - margin: 1em 40px; -} - -/** - * * Address styling not present in Safari 5 and Chrome. */ -dfn { - font-style: italic; -} - -/** - * * Address differences between Firefox and other browsers. - * * Known issue: no IE 6/7 normalization. */ -hr { - box-sizing: content-box; - height: 0; -} - -/** - * * Address styling not present in IE 6/7/8/9. */ -mark { - background: #ff0; - color: #000; -} - -/** - * * Address margins set differently in IE 6/7. */ -p, pre { - margin: 1em 0; -} - -/** - * * Correct font family set oddly in IE 6, Safari 4/5, and Chrome. */ -code, kbd, pre, samp { - font-family: monospace, serif; - _font-family: "courier new", monospace; - font-size: 1em; -} - -/** - * * Improve readability of pre-formatted text in all browsers. */ -pre { - white-space: pre; - white-space: pre-wrap; - word-wrap: break-word; -} - -/** - * * Address CSS quotes not supported in IE 6/7. */ -q { - quotes: none; -} -q:before, q:after { - content: ""; - content: none; -} - -/** - * * Address `quotes` property not supported in Safari 4. */ -/** - * * Address inconsistent and variable font size in all browsers. */ -small { - font-size: 80%; -} - -/** - * * Prevent `sub` and `sup` affecting `line-height` in all browsers. */ -sub { - font-size: 75%; - line-height: 0; - position: relative; - vertical-align: baseline; -} - -sup { - font-size: 75%; - line-height: 0; - position: relative; - vertical-align: baseline; - top: -0.5em; -} - -sub { - bottom: -0.25em; -} - -/* ========================================================================== - * * Lists - * * ========================================================================== */ -/** - * * Address margins set differently in IE 6/7. */ -dl, menu, ol, ul { - margin: 1em 0; -} - -dd { - margin: 0 0 0 40px; -} - -/** - * * Address paddings set differently in IE 6/7. */ -menu, ol, ul { - padding: 0 0 0 40px; -} - -/** - * * Correct list images handled incorrectly in IE 7. */ -nav ul, nav ol { - list-style: none; - list-style-image: none; -} - -/* ========================================================================== - * * Embedded content - * * ========================================================================== */ -/** - * * 1. Remove border when inside `a` element in IE 6/7/8/9 and Firefox 3. - * * 2. Improve image quality when scaled in IE 7. */ -img { - border: 0; - /* 1 */ - -ms-interpolation-mode: bicubic; -} - -/* 2 */ -/** - * * Correct overflow displayed oddly in IE 9. */ -svg:not(:root) { - overflow: hidden; -} - -/* ========================================================================== - * * Figures - * * ========================================================================== */ -/** - * * Address margin not present in IE 6/7/8/9, Safari 5, and Opera 11. */ -figure, form { - margin: 0; -} - -/* ========================================================================== - * * Forms - * * ========================================================================== */ -/** - * * Correct margin displayed oddly in IE 6/7. */ -/** - * * Define consistent border, margin, and padding. */ -fieldset { - border: 1px solid #c0c0c0; - margin: 0 2px; - padding: 0.35em 0.625em 0.75em; -} - -/** - * * 1. Correct color not being inherited in IE 6/7/8/9. - * * 2. Correct text not wrapping in Firefox 3. - * * 3. Correct alignment displayed oddly in IE 6/7. */ -legend { - border: 0; - /* 1 */ - padding: 0; - white-space: normal; - /* 2 */ - *margin-left: -7px; -} - -/* 3 */ -/** - * * 1. Correct font size not being inherited in all browsers. - * * 2. Address margins set differently in IE 6/7, Firefox 3+, Safari 5, - * * and Chrome. - * * 3. Improve appearance and consistency in all browsers. */ -button, input, select, textarea { - font-size: 100%; - /* 1 */ - margin: 0; - /* 2 */ - vertical-align: baseline; - /* 3 */ - *vertical-align: middle; -} - -/* 3 */ -/** - * * Address Firefox 3+ setting `line-height` on `input` using `!important` in - * * the UA stylesheet. */ -button, input { - line-height: normal; -} - -/** - * * Address inconsistent `text-transform` inheritance for `button` and `select`. - * * All other form control elements do not inherit `text-transform` values. - * * Correct `button` style inheritance in Chrome, Safari 5+, and IE 6+. - * * Correct `select` style inheritance in Firefox 4+ and Opera. */ -button, select { - text-transform: none; -} - -/** - * * 1. Avoid the WebKit bug in Android 4.0.* where (2) destroys native `audio` - * * and `video` controls. - * * 2. Correct inability to style clickable `input` types in iOS. - * * 3. Improve usability and consistency of cursor style between image-type - * * `input` and others. - * * 4. Remove inner spacing in IE 7 without affecting normal text inputs. - * * Known issue: inner spacing remains in IE 6. */ -button, html input[type=button] { - -webkit-appearance: button; - /* 2 */ - cursor: pointer; - /* 3 */ - *overflow: visible; -} - -/* 4 */ -input[type=reset], input[type=submit] { - -webkit-appearance: button; - /* 2 */ - cursor: pointer; - /* 3 */ - *overflow: visible; -} - -/* 4 */ -/** - * * Re-set default cursor for disabled elements. */ -button[disabled], html input[disabled] { - cursor: default; -} - -/** - * * 1. Address box sizing set to content-box in IE 8/9. - * * 2. Remove excess padding in IE 8/9. - * * 3. Remove excess padding in IE 7. - * * Known issue: excess padding remains in IE 6. */ -input { - /* 3 */ -} -input[type=checkbox], input[type=radio] { - box-sizing: border-box; - /* 1 */ - padding: 0; - /* 2 */ - *height: 13px; - /* 3 */ - *width: 13px; -} -input[type=search] { - -webkit-appearance: textfield; - /* 1 */ - /* 2 */ - box-sizing: content-box; -} -input[type=search]::-webkit-search-cancel-button, input[type=search]::-webkit-search-decoration { - -webkit-appearance: none; -} - -/** - * * 1. Address `appearance` set to `searchfield` in Safari 5 and Chrome. - * * 2. Address `box-sizing` set to `border-box` in Safari 5 and Chrome - * * (include `-moz` to future-proof). */ -/** - * * Remove inner padding and search cancel button in Safari 5 and Chrome - * * on OS X. */ -/** - * * Remove inner padding and border in Firefox 3+. */ -button::-moz-focus-inner, input::-moz-focus-inner { - border: 0; - padding: 0; -} - -/** - * * 1. Remove default vertical scrollbar in IE 6/7/8/9. - * * 2. Improve readability and alignment in all browsers. */ -textarea { - overflow: auto; - /* 1 */ - vertical-align: top; -} - -/* 2 */ -/* ========================================================================== - * * Tables - * * ========================================================================== */ -/** - * * Remove most spacing between table cells. */ -table { - border-collapse: collapse; - border-spacing: 0; -} - -/* * - * *Visual Studio-like style based on original C# coloring by Jason Diamond */ -.hljs { - display: inline-block; - padding: 0.5em; - background: white; - color: black; -} - -.hljs-comment, .hljs-annotation, .hljs-template_comment, .diff .hljs-header, .hljs-chunk, .apache .hljs-cbracket { - color: #008000; -} - -.hljs-keyword, .hljs-id, .hljs-built_in, .css .smalltalk .hljs-class, .hljs-winutils, .bash .hljs-variable, .tex .hljs-command, .hljs-request, .hljs-status, .nginx .hljs-title { - color: #00f; -} - -.xml .hljs-tag { - color: #00f; -} -.xml .hljs-tag .hljs-value { - color: #00f; -} - -.hljs-string, .hljs-title, .hljs-parent, .hljs-tag .hljs-value, .hljs-rules .hljs-value { - color: #a31515; -} - -.ruby .hljs-symbol { - color: #a31515; -} -.ruby .hljs-symbol .hljs-string { - color: #a31515; -} - -.hljs-template_tag, .django .hljs-variable, .hljs-addition, .hljs-flow, .hljs-stream, .apache .hljs-tag, .hljs-date, .tex .hljs-formula, .coffeescript .hljs-attribute { - color: #a31515; -} - -.ruby .hljs-string, .hljs-decorator, .hljs-filter .hljs-argument, .hljs-localvars, .hljs-array, .hljs-attr_selector, .hljs-pseudo, .hljs-pi, .hljs-doctype, .hljs-deletion, .hljs-envvar, .hljs-shebang, .hljs-preprocessor, .hljs-pragma, .userType, .apache .hljs-sqbracket, .nginx .hljs-built_in, .tex .hljs-special, .hljs-prompt { - color: #2b91af; -} - -.hljs-phpdoc, .hljs-javadoc, .hljs-xmlDocTag { - color: #808080; -} - -.vhdl .hljs-typename { - font-weight: bold; -} -.vhdl .hljs-string { - color: #666666; -} -.vhdl .hljs-literal { - color: #a31515; -} -.vhdl .hljs-attribute { - color: #00b0e8; -} - -.xml .hljs-attribute { - color: #f00; -} - -ul.tsd-descriptions > li > :first-child, .tsd-panel > :first-child, .col > :first-child, .col-11 > :first-child, .col-10 > :first-child, .col-9 > :first-child, .col-8 > :first-child, .col-7 > :first-child, .col-6 > :first-child, .col-5 > :first-child, .col-4 > :first-child, .col-3 > :first-child, .col-2 > :first-child, .col-1 > :first-child, -ul.tsd-descriptions > li > :first-child > :first-child, -.tsd-panel > :first-child > :first-child, -.col > :first-child > :first-child, -.col-11 > :first-child > :first-child, -.col-10 > :first-child > :first-child, -.col-9 > :first-child > :first-child, -.col-8 > :first-child > :first-child, -.col-7 > :first-child > :first-child, -.col-6 > :first-child > :first-child, -.col-5 > :first-child > :first-child, -.col-4 > :first-child > :first-child, -.col-3 > :first-child > :first-child, -.col-2 > :first-child > :first-child, -.col-1 > :first-child > :first-child, -ul.tsd-descriptions > li > :first-child > :first-child > :first-child, -.tsd-panel > :first-child > :first-child > :first-child, -.col > :first-child > :first-child > :first-child, -.col-11 > :first-child > :first-child > :first-child, -.col-10 > :first-child > :first-child > :first-child, -.col-9 > :first-child > :first-child > :first-child, -.col-8 > :first-child > :first-child > :first-child, -.col-7 > :first-child > :first-child > :first-child, -.col-6 > :first-child > :first-child > :first-child, -.col-5 > :first-child > :first-child > :first-child, -.col-4 > :first-child > :first-child > :first-child, -.col-3 > :first-child > :first-child > :first-child, -.col-2 > :first-child > :first-child > :first-child, -.col-1 > :first-child > :first-child > :first-child { - margin-top: 0; -} -ul.tsd-descriptions > li > :last-child, .tsd-panel > :last-child, .col > :last-child, .col-11 > :last-child, .col-10 > :last-child, .col-9 > :last-child, .col-8 > :last-child, .col-7 > :last-child, .col-6 > :last-child, .col-5 > :last-child, .col-4 > :last-child, .col-3 > :last-child, .col-2 > :last-child, .col-1 > :last-child, -ul.tsd-descriptions > li > :last-child > :last-child, -.tsd-panel > :last-child > :last-child, -.col > :last-child > :last-child, -.col-11 > :last-child > :last-child, -.col-10 > :last-child > :last-child, -.col-9 > :last-child > :last-child, -.col-8 > :last-child > :last-child, -.col-7 > :last-child > :last-child, -.col-6 > :last-child > :last-child, -.col-5 > :last-child > :last-child, -.col-4 > :last-child > :last-child, -.col-3 > :last-child > :last-child, -.col-2 > :last-child > :last-child, -.col-1 > :last-child > :last-child, -ul.tsd-descriptions > li > :last-child > :last-child > :last-child, -.tsd-panel > :last-child > :last-child > :last-child, -.col > :last-child > :last-child > :last-child, -.col-11 > :last-child > :last-child > :last-child, -.col-10 > :last-child > :last-child > :last-child, -.col-9 > :last-child > :last-child > :last-child, -.col-8 > :last-child > :last-child > :last-child, -.col-7 > :last-child > :last-child > :last-child, -.col-6 > :last-child > :last-child > :last-child, -.col-5 > :last-child > :last-child > :last-child, -.col-4 > :last-child > :last-child > :last-child, -.col-3 > :last-child > :last-child > :last-child, -.col-2 > :last-child > :last-child > :last-child, -.col-1 > :last-child > :last-child > :last-child { - margin-bottom: 0; -} - -.container { - max-width: 1200px; - margin: 0 auto; - padding: 0 40px; -} -@media (max-width: 640px) { - .container { - padding: 0 20px; - } -} - -.container-main { - padding-bottom: 200px; -} - -.row { - display: -ms-flexbox; - display: flex; - position: relative; - margin: 0 -10px; -} -.row:after { - visibility: hidden; - display: block; - content: ""; - clear: both; - height: 0; -} - -.col, .col-11, .col-10, .col-9, .col-8, .col-7, .col-6, .col-5, .col-4, .col-3, .col-2, .col-1 { - box-sizing: border-box; - float: left; - padding: 0 10px; -} - -.col-1 { - width: 8.3333333333%; -} - -.offset-1 { - margin-left: 8.3333333333%; -} - -.col-2 { - width: 16.6666666667%; -} - -.offset-2 { - margin-left: 16.6666666667%; -} - -.col-3 { - width: 25%; -} - -.offset-3 { - margin-left: 25%; -} - -.col-4 { - width: 33.3333333333%; -} - -.offset-4 { - margin-left: 33.3333333333%; -} - -.col-5 { - width: 41.6666666667%; -} - -.offset-5 { - margin-left: 41.6666666667%; -} - -.col-6 { - width: 50%; -} - -.offset-6 { - margin-left: 50%; -} - -.col-7 { - width: 58.3333333333%; -} - -.offset-7 { - margin-left: 58.3333333333%; -} - -.col-8 { - width: 66.6666666667%; -} - -.offset-8 { - margin-left: 66.6666666667%; -} - -.col-9 { - width: 75%; -} - -.offset-9 { - margin-left: 75%; -} - -.col-10 { - width: 83.3333333333%; -} - -.offset-10 { - margin-left: 83.3333333333%; -} - -.col-11 { - width: 91.6666666667%; -} - -.offset-11 { - margin-left: 91.6666666667%; -} - -.tsd-kind-icon { - display: block; - position: relative; - padding-left: 20px; - text-indent: -20px; -} -.tsd-kind-icon:before { - content: ""; - display: inline-block; - vertical-align: middle; - width: 17px; - height: 17px; - margin: 0 3px 2px 0; - background-image: url(../images/icons.png); -} -@media (-webkit-min-device-pixel-ratio: 1.5), (min-resolution: 144dpi) { - .tsd-kind-icon:before { - background-image: url(../images/icons@2x.png); - background-size: 238px 204px; - } -} - -.tsd-signature.tsd-kind-icon:before { - background-position: 0 -153px; -} - -.tsd-kind-object-literal > .tsd-kind-icon:before { - background-position: 0px -17px; -} -.tsd-kind-object-literal.tsd-is-protected > .tsd-kind-icon:before { - background-position: -17px -17px; -} -.tsd-kind-object-literal.tsd-is-private > .tsd-kind-icon:before { - background-position: -34px -17px; -} - -.tsd-kind-class > .tsd-kind-icon:before { - background-position: 0px -34px; -} -.tsd-kind-class.tsd-is-protected > .tsd-kind-icon:before { - background-position: -17px -34px; -} -.tsd-kind-class.tsd-is-private > .tsd-kind-icon:before { - background-position: -34px -34px; -} - -.tsd-kind-class.tsd-has-type-parameter > .tsd-kind-icon:before { - background-position: 0px -51px; -} -.tsd-kind-class.tsd-has-type-parameter.tsd-is-protected > .tsd-kind-icon:before { - background-position: -17px -51px; -} -.tsd-kind-class.tsd-has-type-parameter.tsd-is-private > .tsd-kind-icon:before { - background-position: -34px -51px; -} - -.tsd-kind-interface > .tsd-kind-icon:before { - background-position: 0px -68px; -} -.tsd-kind-interface.tsd-is-protected > .tsd-kind-icon:before { - background-position: -17px -68px; -} -.tsd-kind-interface.tsd-is-private > .tsd-kind-icon:before { - background-position: -34px -68px; -} - -.tsd-kind-interface.tsd-has-type-parameter > .tsd-kind-icon:before { - background-position: 0px -85px; -} -.tsd-kind-interface.tsd-has-type-parameter.tsd-is-protected > .tsd-kind-icon:before { - background-position: -17px -85px; -} -.tsd-kind-interface.tsd-has-type-parameter.tsd-is-private > .tsd-kind-icon:before { - background-position: -34px -85px; -} - -.tsd-kind-namespace > .tsd-kind-icon:before { - background-position: 0px -102px; -} -.tsd-kind-namespace.tsd-is-protected > .tsd-kind-icon:before { - background-position: -17px -102px; -} -.tsd-kind-namespace.tsd-is-private > .tsd-kind-icon:before { - background-position: -34px -102px; -} - -.tsd-kind-module > .tsd-kind-icon:before { - background-position: 0px -102px; -} -.tsd-kind-module.tsd-is-protected > .tsd-kind-icon:before { - background-position: -17px -102px; -} -.tsd-kind-module.tsd-is-private > .tsd-kind-icon:before { - background-position: -34px -102px; -} - -.tsd-kind-enum > .tsd-kind-icon:before { - background-position: 0px -119px; -} -.tsd-kind-enum.tsd-is-protected > .tsd-kind-icon:before { - background-position: -17px -119px; -} -.tsd-kind-enum.tsd-is-private > .tsd-kind-icon:before { - background-position: -34px -119px; -} - -.tsd-kind-enum-member > .tsd-kind-icon:before { - background-position: 0px -136px; -} -.tsd-kind-enum-member.tsd-is-protected > .tsd-kind-icon:before { - background-position: -17px -136px; -} -.tsd-kind-enum-member.tsd-is-private > .tsd-kind-icon:before { - background-position: -34px -136px; -} - -.tsd-kind-signature > .tsd-kind-icon:before { - background-position: 0px -153px; -} -.tsd-kind-signature.tsd-is-protected > .tsd-kind-icon:before { - background-position: -17px -153px; -} -.tsd-kind-signature.tsd-is-private > .tsd-kind-icon:before { - background-position: -34px -153px; -} - -.tsd-kind-type-alias > .tsd-kind-icon:before { - background-position: 0px -170px; -} -.tsd-kind-type-alias.tsd-is-protected > .tsd-kind-icon:before { - background-position: -17px -170px; -} -.tsd-kind-type-alias.tsd-is-private > .tsd-kind-icon:before { - background-position: -34px -170px; -} - -.tsd-kind-type-alias.tsd-has-type-parameter > .tsd-kind-icon:before { - background-position: 0px -187px; -} -.tsd-kind-type-alias.tsd-has-type-parameter.tsd-is-protected > .tsd-kind-icon:before { - background-position: -17px -187px; -} -.tsd-kind-type-alias.tsd-has-type-parameter.tsd-is-private > .tsd-kind-icon:before { - background-position: -34px -187px; -} - -.tsd-kind-variable > .tsd-kind-icon:before { - background-position: -136px -0px; -} -.tsd-kind-variable.tsd-is-protected > .tsd-kind-icon:before { - background-position: -153px -0px; -} -.tsd-kind-variable.tsd-is-private > .tsd-kind-icon:before { - background-position: -119px -0px; -} -.tsd-kind-variable.tsd-parent-kind-class > .tsd-kind-icon:before { - background-position: -51px -0px; -} -.tsd-kind-variable.tsd-parent-kind-class.tsd-is-inherited > .tsd-kind-icon:before { - background-position: -68px -0px; -} -.tsd-kind-variable.tsd-parent-kind-class.tsd-is-protected > .tsd-kind-icon:before { - background-position: -85px -0px; -} -.tsd-kind-variable.tsd-parent-kind-class.tsd-is-protected.tsd-is-inherited > .tsd-kind-icon:before { - background-position: -102px -0px; -} -.tsd-kind-variable.tsd-parent-kind-class.tsd-is-private > .tsd-kind-icon:before { - background-position: -119px -0px; -} -.tsd-kind-variable.tsd-parent-kind-enum > .tsd-kind-icon:before { - background-position: -170px -0px; -} -.tsd-kind-variable.tsd-parent-kind-enum.tsd-is-protected > .tsd-kind-icon:before { - background-position: -187px -0px; -} -.tsd-kind-variable.tsd-parent-kind-enum.tsd-is-private > .tsd-kind-icon:before { - background-position: -119px -0px; -} -.tsd-kind-variable.tsd-parent-kind-interface > .tsd-kind-icon:before { - background-position: -204px -0px; -} -.tsd-kind-variable.tsd-parent-kind-interface.tsd-is-inherited > .tsd-kind-icon:before { - background-position: -221px -0px; -} - -.tsd-kind-property > .tsd-kind-icon:before { - background-position: -136px -0px; -} -.tsd-kind-property.tsd-is-protected > .tsd-kind-icon:before { - background-position: -153px -0px; -} -.tsd-kind-property.tsd-is-private > .tsd-kind-icon:before { - background-position: -119px -0px; -} -.tsd-kind-property.tsd-parent-kind-class > .tsd-kind-icon:before { - background-position: -51px -0px; -} -.tsd-kind-property.tsd-parent-kind-class.tsd-is-inherited > .tsd-kind-icon:before { - background-position: -68px -0px; -} -.tsd-kind-property.tsd-parent-kind-class.tsd-is-protected > .tsd-kind-icon:before { - background-position: -85px -0px; -} -.tsd-kind-property.tsd-parent-kind-class.tsd-is-protected.tsd-is-inherited > .tsd-kind-icon:before { - background-position: -102px -0px; -} -.tsd-kind-property.tsd-parent-kind-class.tsd-is-private > .tsd-kind-icon:before { - background-position: -119px -0px; -} -.tsd-kind-property.tsd-parent-kind-enum > .tsd-kind-icon:before { - background-position: -170px -0px; -} -.tsd-kind-property.tsd-parent-kind-enum.tsd-is-protected > .tsd-kind-icon:before { - background-position: -187px -0px; -} -.tsd-kind-property.tsd-parent-kind-enum.tsd-is-private > .tsd-kind-icon:before { - background-position: -119px -0px; -} -.tsd-kind-property.tsd-parent-kind-interface > .tsd-kind-icon:before { - background-position: -204px -0px; -} -.tsd-kind-property.tsd-parent-kind-interface.tsd-is-inherited > .tsd-kind-icon:before { - background-position: -221px -0px; -} - -.tsd-kind-get-signature > .tsd-kind-icon:before { - background-position: -136px -17px; -} -.tsd-kind-get-signature.tsd-is-protected > .tsd-kind-icon:before { - background-position: -153px -17px; -} -.tsd-kind-get-signature.tsd-is-private > .tsd-kind-icon:before { - background-position: -119px -17px; -} -.tsd-kind-get-signature.tsd-parent-kind-class > .tsd-kind-icon:before { - background-position: -51px -17px; -} -.tsd-kind-get-signature.tsd-parent-kind-class.tsd-is-inherited > .tsd-kind-icon:before { - background-position: -68px -17px; -} -.tsd-kind-get-signature.tsd-parent-kind-class.tsd-is-protected > .tsd-kind-icon:before { - background-position: -85px -17px; -} -.tsd-kind-get-signature.tsd-parent-kind-class.tsd-is-protected.tsd-is-inherited > .tsd-kind-icon:before { - background-position: -102px -17px; -} -.tsd-kind-get-signature.tsd-parent-kind-class.tsd-is-private > .tsd-kind-icon:before { - background-position: -119px -17px; -} -.tsd-kind-get-signature.tsd-parent-kind-enum > .tsd-kind-icon:before { - background-position: -170px -17px; -} -.tsd-kind-get-signature.tsd-parent-kind-enum.tsd-is-protected > .tsd-kind-icon:before { - background-position: -187px -17px; -} -.tsd-kind-get-signature.tsd-parent-kind-enum.tsd-is-private > .tsd-kind-icon:before { - background-position: -119px -17px; -} -.tsd-kind-get-signature.tsd-parent-kind-interface > .tsd-kind-icon:before { - background-position: -204px -17px; -} -.tsd-kind-get-signature.tsd-parent-kind-interface.tsd-is-inherited > .tsd-kind-icon:before { - background-position: -221px -17px; -} - -.tsd-kind-set-signature > .tsd-kind-icon:before { - background-position: -136px -34px; -} -.tsd-kind-set-signature.tsd-is-protected > .tsd-kind-icon:before { - background-position: -153px -34px; -} -.tsd-kind-set-signature.tsd-is-private > .tsd-kind-icon:before { - background-position: -119px -34px; -} -.tsd-kind-set-signature.tsd-parent-kind-class > .tsd-kind-icon:before { - background-position: -51px -34px; -} -.tsd-kind-set-signature.tsd-parent-kind-class.tsd-is-inherited > .tsd-kind-icon:before { - background-position: -68px -34px; -} -.tsd-kind-set-signature.tsd-parent-kind-class.tsd-is-protected > .tsd-kind-icon:before { - background-position: -85px -34px; -} -.tsd-kind-set-signature.tsd-parent-kind-class.tsd-is-protected.tsd-is-inherited > .tsd-kind-icon:before { - background-position: -102px -34px; -} -.tsd-kind-set-signature.tsd-parent-kind-class.tsd-is-private > .tsd-kind-icon:before { - background-position: -119px -34px; -} -.tsd-kind-set-signature.tsd-parent-kind-enum > .tsd-kind-icon:before { - background-position: -170px -34px; -} -.tsd-kind-set-signature.tsd-parent-kind-enum.tsd-is-protected > .tsd-kind-icon:before { - background-position: -187px -34px; -} -.tsd-kind-set-signature.tsd-parent-kind-enum.tsd-is-private > .tsd-kind-icon:before { - background-position: -119px -34px; -} -.tsd-kind-set-signature.tsd-parent-kind-interface > .tsd-kind-icon:before { - background-position: -204px -34px; -} -.tsd-kind-set-signature.tsd-parent-kind-interface.tsd-is-inherited > .tsd-kind-icon:before { - background-position: -221px -34px; -} - -.tsd-kind-accessor > .tsd-kind-icon:before { - background-position: -136px -51px; -} -.tsd-kind-accessor.tsd-is-protected > .tsd-kind-icon:before { - background-position: -153px -51px; -} -.tsd-kind-accessor.tsd-is-private > .tsd-kind-icon:before { - background-position: -119px -51px; -} -.tsd-kind-accessor.tsd-parent-kind-class > .tsd-kind-icon:before { - background-position: -51px -51px; -} -.tsd-kind-accessor.tsd-parent-kind-class.tsd-is-inherited > .tsd-kind-icon:before { - background-position: -68px -51px; -} -.tsd-kind-accessor.tsd-parent-kind-class.tsd-is-protected > .tsd-kind-icon:before { - background-position: -85px -51px; -} -.tsd-kind-accessor.tsd-parent-kind-class.tsd-is-protected.tsd-is-inherited > .tsd-kind-icon:before { - background-position: -102px -51px; -} -.tsd-kind-accessor.tsd-parent-kind-class.tsd-is-private > .tsd-kind-icon:before { - background-position: -119px -51px; -} -.tsd-kind-accessor.tsd-parent-kind-enum > .tsd-kind-icon:before { - background-position: -170px -51px; -} -.tsd-kind-accessor.tsd-parent-kind-enum.tsd-is-protected > .tsd-kind-icon:before { - background-position: -187px -51px; -} -.tsd-kind-accessor.tsd-parent-kind-enum.tsd-is-private > .tsd-kind-icon:before { - background-position: -119px -51px; -} -.tsd-kind-accessor.tsd-parent-kind-interface > .tsd-kind-icon:before { - background-position: -204px -51px; -} -.tsd-kind-accessor.tsd-parent-kind-interface.tsd-is-inherited > .tsd-kind-icon:before { - background-position: -221px -51px; -} - -.tsd-kind-function > .tsd-kind-icon:before { - background-position: -136px -68px; -} -.tsd-kind-function.tsd-is-protected > .tsd-kind-icon:before { - background-position: -153px -68px; -} -.tsd-kind-function.tsd-is-private > .tsd-kind-icon:before { - background-position: -119px -68px; -} -.tsd-kind-function.tsd-parent-kind-class > .tsd-kind-icon:before { - background-position: -51px -68px; -} -.tsd-kind-function.tsd-parent-kind-class.tsd-is-inherited > .tsd-kind-icon:before { - background-position: -68px -68px; -} -.tsd-kind-function.tsd-parent-kind-class.tsd-is-protected > .tsd-kind-icon:before { - background-position: -85px -68px; -} -.tsd-kind-function.tsd-parent-kind-class.tsd-is-protected.tsd-is-inherited > .tsd-kind-icon:before { - background-position: -102px -68px; -} -.tsd-kind-function.tsd-parent-kind-class.tsd-is-private > .tsd-kind-icon:before { - background-position: -119px -68px; -} -.tsd-kind-function.tsd-parent-kind-enum > .tsd-kind-icon:before { - background-position: -170px -68px; -} -.tsd-kind-function.tsd-parent-kind-enum.tsd-is-protected > .tsd-kind-icon:before { - background-position: -187px -68px; -} -.tsd-kind-function.tsd-parent-kind-enum.tsd-is-private > .tsd-kind-icon:before { - background-position: -119px -68px; -} -.tsd-kind-function.tsd-parent-kind-interface > .tsd-kind-icon:before { - background-position: -204px -68px; -} -.tsd-kind-function.tsd-parent-kind-interface.tsd-is-inherited > .tsd-kind-icon:before { - background-position: -221px -68px; -} - -.tsd-kind-method > .tsd-kind-icon:before { - background-position: -136px -68px; -} -.tsd-kind-method.tsd-is-protected > .tsd-kind-icon:before { - background-position: -153px -68px; -} -.tsd-kind-method.tsd-is-private > .tsd-kind-icon:before { - background-position: -119px -68px; -} -.tsd-kind-method.tsd-parent-kind-class > .tsd-kind-icon:before { - background-position: -51px -68px; -} -.tsd-kind-method.tsd-parent-kind-class.tsd-is-inherited > .tsd-kind-icon:before { - background-position: -68px -68px; -} -.tsd-kind-method.tsd-parent-kind-class.tsd-is-protected > .tsd-kind-icon:before { - background-position: -85px -68px; -} -.tsd-kind-method.tsd-parent-kind-class.tsd-is-protected.tsd-is-inherited > .tsd-kind-icon:before { - background-position: -102px -68px; -} -.tsd-kind-method.tsd-parent-kind-class.tsd-is-private > .tsd-kind-icon:before { - background-position: -119px -68px; -} -.tsd-kind-method.tsd-parent-kind-enum > .tsd-kind-icon:before { - background-position: -170px -68px; -} -.tsd-kind-method.tsd-parent-kind-enum.tsd-is-protected > .tsd-kind-icon:before { - background-position: -187px -68px; -} -.tsd-kind-method.tsd-parent-kind-enum.tsd-is-private > .tsd-kind-icon:before { - background-position: -119px -68px; -} -.tsd-kind-method.tsd-parent-kind-interface > .tsd-kind-icon:before { - background-position: -204px -68px; -} -.tsd-kind-method.tsd-parent-kind-interface.tsd-is-inherited > .tsd-kind-icon:before { - background-position: -221px -68px; -} - -.tsd-kind-call-signature > .tsd-kind-icon:before { - background-position: -136px -68px; -} -.tsd-kind-call-signature.tsd-is-protected > .tsd-kind-icon:before { - background-position: -153px -68px; -} -.tsd-kind-call-signature.tsd-is-private > .tsd-kind-icon:before { - background-position: -119px -68px; -} -.tsd-kind-call-signature.tsd-parent-kind-class > .tsd-kind-icon:before { - background-position: -51px -68px; -} -.tsd-kind-call-signature.tsd-parent-kind-class.tsd-is-inherited > .tsd-kind-icon:before { - background-position: -68px -68px; -} -.tsd-kind-call-signature.tsd-parent-kind-class.tsd-is-protected > .tsd-kind-icon:before { - background-position: -85px -68px; -} -.tsd-kind-call-signature.tsd-parent-kind-class.tsd-is-protected.tsd-is-inherited > .tsd-kind-icon:before { - background-position: -102px -68px; -} -.tsd-kind-call-signature.tsd-parent-kind-class.tsd-is-private > .tsd-kind-icon:before { - background-position: -119px -68px; -} -.tsd-kind-call-signature.tsd-parent-kind-enum > .tsd-kind-icon:before { - background-position: -170px -68px; -} -.tsd-kind-call-signature.tsd-parent-kind-enum.tsd-is-protected > .tsd-kind-icon:before { - background-position: -187px -68px; -} -.tsd-kind-call-signature.tsd-parent-kind-enum.tsd-is-private > .tsd-kind-icon:before { - background-position: -119px -68px; -} -.tsd-kind-call-signature.tsd-parent-kind-interface > .tsd-kind-icon:before { - background-position: -204px -68px; -} -.tsd-kind-call-signature.tsd-parent-kind-interface.tsd-is-inherited > .tsd-kind-icon:before { - background-position: -221px -68px; -} - -.tsd-kind-function.tsd-has-type-parameter > .tsd-kind-icon:before { - background-position: -136px -85px; -} -.tsd-kind-function.tsd-has-type-parameter.tsd-is-protected > .tsd-kind-icon:before { - background-position: -153px -85px; -} -.tsd-kind-function.tsd-has-type-parameter.tsd-is-private > .tsd-kind-icon:before { - background-position: -119px -85px; -} -.tsd-kind-function.tsd-has-type-parameter.tsd-parent-kind-class > .tsd-kind-icon:before { - background-position: -51px -85px; -} -.tsd-kind-function.tsd-has-type-parameter.tsd-parent-kind-class.tsd-is-inherited > .tsd-kind-icon:before { - background-position: -68px -85px; -} -.tsd-kind-function.tsd-has-type-parameter.tsd-parent-kind-class.tsd-is-protected > .tsd-kind-icon:before { - background-position: -85px -85px; -} -.tsd-kind-function.tsd-has-type-parameter.tsd-parent-kind-class.tsd-is-protected.tsd-is-inherited > .tsd-kind-icon:before { - background-position: -102px -85px; -} -.tsd-kind-function.tsd-has-type-parameter.tsd-parent-kind-class.tsd-is-private > .tsd-kind-icon:before { - background-position: -119px -85px; -} -.tsd-kind-function.tsd-has-type-parameter.tsd-parent-kind-enum > .tsd-kind-icon:before { - background-position: -170px -85px; -} -.tsd-kind-function.tsd-has-type-parameter.tsd-parent-kind-enum.tsd-is-protected > .tsd-kind-icon:before { - background-position: -187px -85px; -} -.tsd-kind-function.tsd-has-type-parameter.tsd-parent-kind-enum.tsd-is-private > .tsd-kind-icon:before { - background-position: -119px -85px; -} -.tsd-kind-function.tsd-has-type-parameter.tsd-parent-kind-interface > .tsd-kind-icon:before { - background-position: -204px -85px; -} -.tsd-kind-function.tsd-has-type-parameter.tsd-parent-kind-interface.tsd-is-inherited > .tsd-kind-icon:before { - background-position: -221px -85px; -} - -.tsd-kind-method.tsd-has-type-parameter > .tsd-kind-icon:before { - background-position: -136px -85px; -} -.tsd-kind-method.tsd-has-type-parameter.tsd-is-protected > .tsd-kind-icon:before { - background-position: -153px -85px; -} -.tsd-kind-method.tsd-has-type-parameter.tsd-is-private > .tsd-kind-icon:before { - background-position: -119px -85px; -} -.tsd-kind-method.tsd-has-type-parameter.tsd-parent-kind-class > .tsd-kind-icon:before { - background-position: -51px -85px; -} -.tsd-kind-method.tsd-has-type-parameter.tsd-parent-kind-class.tsd-is-inherited > .tsd-kind-icon:before { - background-position: -68px -85px; -} -.tsd-kind-method.tsd-has-type-parameter.tsd-parent-kind-class.tsd-is-protected > .tsd-kind-icon:before { - background-position: -85px -85px; -} -.tsd-kind-method.tsd-has-type-parameter.tsd-parent-kind-class.tsd-is-protected.tsd-is-inherited > .tsd-kind-icon:before { - background-position: -102px -85px; -} -.tsd-kind-method.tsd-has-type-parameter.tsd-parent-kind-class.tsd-is-private > .tsd-kind-icon:before { - background-position: -119px -85px; -} -.tsd-kind-method.tsd-has-type-parameter.tsd-parent-kind-enum > .tsd-kind-icon:before { - background-position: -170px -85px; -} -.tsd-kind-method.tsd-has-type-parameter.tsd-parent-kind-enum.tsd-is-protected > .tsd-kind-icon:before { - background-position: -187px -85px; -} -.tsd-kind-method.tsd-has-type-parameter.tsd-parent-kind-enum.tsd-is-private > .tsd-kind-icon:before { - background-position: -119px -85px; -} -.tsd-kind-method.tsd-has-type-parameter.tsd-parent-kind-interface > .tsd-kind-icon:before { - background-position: -204px -85px; -} -.tsd-kind-method.tsd-has-type-parameter.tsd-parent-kind-interface.tsd-is-inherited > .tsd-kind-icon:before { - background-position: -221px -85px; -} - -.tsd-kind-constructor > .tsd-kind-icon:before { - background-position: -136px -102px; -} -.tsd-kind-constructor.tsd-is-protected > .tsd-kind-icon:before { - background-position: -153px -102px; -} -.tsd-kind-constructor.tsd-is-private > .tsd-kind-icon:before { - background-position: -119px -102px; -} -.tsd-kind-constructor.tsd-parent-kind-class > .tsd-kind-icon:before { - background-position: -51px -102px; -} -.tsd-kind-constructor.tsd-parent-kind-class.tsd-is-inherited > .tsd-kind-icon:before { - background-position: -68px -102px; -} -.tsd-kind-constructor.tsd-parent-kind-class.tsd-is-protected > .tsd-kind-icon:before { - background-position: -85px -102px; -} -.tsd-kind-constructor.tsd-parent-kind-class.tsd-is-protected.tsd-is-inherited > .tsd-kind-icon:before { - background-position: -102px -102px; -} -.tsd-kind-constructor.tsd-parent-kind-class.tsd-is-private > .tsd-kind-icon:before { - background-position: -119px -102px; -} -.tsd-kind-constructor.tsd-parent-kind-enum > .tsd-kind-icon:before { - background-position: -170px -102px; -} -.tsd-kind-constructor.tsd-parent-kind-enum.tsd-is-protected > .tsd-kind-icon:before { - background-position: -187px -102px; -} -.tsd-kind-constructor.tsd-parent-kind-enum.tsd-is-private > .tsd-kind-icon:before { - background-position: -119px -102px; -} -.tsd-kind-constructor.tsd-parent-kind-interface > .tsd-kind-icon:before { - background-position: -204px -102px; -} -.tsd-kind-constructor.tsd-parent-kind-interface.tsd-is-inherited > .tsd-kind-icon:before { - background-position: -221px -102px; -} - -.tsd-kind-constructor-signature > .tsd-kind-icon:before { - background-position: -136px -102px; -} -.tsd-kind-constructor-signature.tsd-is-protected > .tsd-kind-icon:before { - background-position: -153px -102px; -} -.tsd-kind-constructor-signature.tsd-is-private > .tsd-kind-icon:before { - background-position: -119px -102px; -} -.tsd-kind-constructor-signature.tsd-parent-kind-class > .tsd-kind-icon:before { - background-position: -51px -102px; -} -.tsd-kind-constructor-signature.tsd-parent-kind-class.tsd-is-inherited > .tsd-kind-icon:before { - background-position: -68px -102px; -} -.tsd-kind-constructor-signature.tsd-parent-kind-class.tsd-is-protected > .tsd-kind-icon:before { - background-position: -85px -102px; -} -.tsd-kind-constructor-signature.tsd-parent-kind-class.tsd-is-protected.tsd-is-inherited > .tsd-kind-icon:before { - background-position: -102px -102px; -} -.tsd-kind-constructor-signature.tsd-parent-kind-class.tsd-is-private > .tsd-kind-icon:before { - background-position: -119px -102px; -} -.tsd-kind-constructor-signature.tsd-parent-kind-enum > .tsd-kind-icon:before { - background-position: -170px -102px; -} -.tsd-kind-constructor-signature.tsd-parent-kind-enum.tsd-is-protected > .tsd-kind-icon:before { - background-position: -187px -102px; -} -.tsd-kind-constructor-signature.tsd-parent-kind-enum.tsd-is-private > .tsd-kind-icon:before { - background-position: -119px -102px; -} -.tsd-kind-constructor-signature.tsd-parent-kind-interface > .tsd-kind-icon:before { - background-position: -204px -102px; -} -.tsd-kind-constructor-signature.tsd-parent-kind-interface.tsd-is-inherited > .tsd-kind-icon:before { - background-position: -221px -102px; -} - -.tsd-kind-index-signature > .tsd-kind-icon:before { - background-position: -136px -119px; -} -.tsd-kind-index-signature.tsd-is-protected > .tsd-kind-icon:before { - background-position: -153px -119px; -} -.tsd-kind-index-signature.tsd-is-private > .tsd-kind-icon:before { - background-position: -119px -119px; -} -.tsd-kind-index-signature.tsd-parent-kind-class > .tsd-kind-icon:before { - background-position: -51px -119px; -} -.tsd-kind-index-signature.tsd-parent-kind-class.tsd-is-inherited > .tsd-kind-icon:before { - background-position: -68px -119px; -} -.tsd-kind-index-signature.tsd-parent-kind-class.tsd-is-protected > .tsd-kind-icon:before { - background-position: -85px -119px; -} -.tsd-kind-index-signature.tsd-parent-kind-class.tsd-is-protected.tsd-is-inherited > .tsd-kind-icon:before { - background-position: -102px -119px; -} -.tsd-kind-index-signature.tsd-parent-kind-class.tsd-is-private > .tsd-kind-icon:before { - background-position: -119px -119px; -} -.tsd-kind-index-signature.tsd-parent-kind-enum > .tsd-kind-icon:before { - background-position: -170px -119px; -} -.tsd-kind-index-signature.tsd-parent-kind-enum.tsd-is-protected > .tsd-kind-icon:before { - background-position: -187px -119px; -} -.tsd-kind-index-signature.tsd-parent-kind-enum.tsd-is-private > .tsd-kind-icon:before { - background-position: -119px -119px; -} -.tsd-kind-index-signature.tsd-parent-kind-interface > .tsd-kind-icon:before { - background-position: -204px -119px; -} -.tsd-kind-index-signature.tsd-parent-kind-interface.tsd-is-inherited > .tsd-kind-icon:before { - background-position: -221px -119px; -} - -.tsd-kind-event > .tsd-kind-icon:before { - background-position: -136px -136px; -} -.tsd-kind-event.tsd-is-protected > .tsd-kind-icon:before { - background-position: -153px -136px; -} -.tsd-kind-event.tsd-is-private > .tsd-kind-icon:before { - background-position: -119px -136px; -} -.tsd-kind-event.tsd-parent-kind-class > .tsd-kind-icon:before { - background-position: -51px -136px; -} -.tsd-kind-event.tsd-parent-kind-class.tsd-is-inherited > .tsd-kind-icon:before { - background-position: -68px -136px; -} -.tsd-kind-event.tsd-parent-kind-class.tsd-is-protected > .tsd-kind-icon:before { - background-position: -85px -136px; -} -.tsd-kind-event.tsd-parent-kind-class.tsd-is-protected.tsd-is-inherited > .tsd-kind-icon:before { - background-position: -102px -136px; -} -.tsd-kind-event.tsd-parent-kind-class.tsd-is-private > .tsd-kind-icon:before { - background-position: -119px -136px; -} -.tsd-kind-event.tsd-parent-kind-enum > .tsd-kind-icon:before { - background-position: -170px -136px; -} -.tsd-kind-event.tsd-parent-kind-enum.tsd-is-protected > .tsd-kind-icon:before { - background-position: -187px -136px; -} -.tsd-kind-event.tsd-parent-kind-enum.tsd-is-private > .tsd-kind-icon:before { - background-position: -119px -136px; -} -.tsd-kind-event.tsd-parent-kind-interface > .tsd-kind-icon:before { - background-position: -204px -136px; -} -.tsd-kind-event.tsd-parent-kind-interface.tsd-is-inherited > .tsd-kind-icon:before { - background-position: -221px -136px; -} - -.tsd-is-static > .tsd-kind-icon:before { - background-position: -136px -153px; -} -.tsd-is-static.tsd-is-protected > .tsd-kind-icon:before { - background-position: -153px -153px; -} -.tsd-is-static.tsd-is-private > .tsd-kind-icon:before { - background-position: -119px -153px; -} -.tsd-is-static.tsd-parent-kind-class > .tsd-kind-icon:before { - background-position: -51px -153px; -} -.tsd-is-static.tsd-parent-kind-class.tsd-is-inherited > .tsd-kind-icon:before { - background-position: -68px -153px; -} -.tsd-is-static.tsd-parent-kind-class.tsd-is-protected > .tsd-kind-icon:before { - background-position: -85px -153px; -} -.tsd-is-static.tsd-parent-kind-class.tsd-is-protected.tsd-is-inherited > .tsd-kind-icon:before { - background-position: -102px -153px; -} -.tsd-is-static.tsd-parent-kind-class.tsd-is-private > .tsd-kind-icon:before { - background-position: -119px -153px; -} -.tsd-is-static.tsd-parent-kind-enum > .tsd-kind-icon:before { - background-position: -170px -153px; -} -.tsd-is-static.tsd-parent-kind-enum.tsd-is-protected > .tsd-kind-icon:before { - background-position: -187px -153px; -} -.tsd-is-static.tsd-parent-kind-enum.tsd-is-private > .tsd-kind-icon:before { - background-position: -119px -153px; -} -.tsd-is-static.tsd-parent-kind-interface > .tsd-kind-icon:before { - background-position: -204px -153px; -} -.tsd-is-static.tsd-parent-kind-interface.tsd-is-inherited > .tsd-kind-icon:before { - background-position: -221px -153px; -} - -.tsd-is-static.tsd-kind-function > .tsd-kind-icon:before { - background-position: -136px -170px; -} -.tsd-is-static.tsd-kind-function.tsd-is-protected > .tsd-kind-icon:before { - background-position: -153px -170px; -} -.tsd-is-static.tsd-kind-function.tsd-is-private > .tsd-kind-icon:before { - background-position: -119px -170px; -} -.tsd-is-static.tsd-kind-function.tsd-parent-kind-class > .tsd-kind-icon:before { - background-position: -51px -170px; -} -.tsd-is-static.tsd-kind-function.tsd-parent-kind-class.tsd-is-inherited > .tsd-kind-icon:before { - background-position: -68px -170px; -} -.tsd-is-static.tsd-kind-function.tsd-parent-kind-class.tsd-is-protected > .tsd-kind-icon:before { - background-position: -85px -170px; -} -.tsd-is-static.tsd-kind-function.tsd-parent-kind-class.tsd-is-protected.tsd-is-inherited > .tsd-kind-icon:before { - background-position: -102px -170px; -} -.tsd-is-static.tsd-kind-function.tsd-parent-kind-class.tsd-is-private > .tsd-kind-icon:before { - background-position: -119px -170px; -} -.tsd-is-static.tsd-kind-function.tsd-parent-kind-enum > .tsd-kind-icon:before { - background-position: -170px -170px; -} -.tsd-is-static.tsd-kind-function.tsd-parent-kind-enum.tsd-is-protected > .tsd-kind-icon:before { - background-position: -187px -170px; -} -.tsd-is-static.tsd-kind-function.tsd-parent-kind-enum.tsd-is-private > .tsd-kind-icon:before { - background-position: -119px -170px; -} -.tsd-is-static.tsd-kind-function.tsd-parent-kind-interface > .tsd-kind-icon:before { - background-position: -204px -170px; -} -.tsd-is-static.tsd-kind-function.tsd-parent-kind-interface.tsd-is-inherited > .tsd-kind-icon:before { - background-position: -221px -170px; -} - -.tsd-is-static.tsd-kind-method > .tsd-kind-icon:before { - background-position: -136px -170px; -} -.tsd-is-static.tsd-kind-method.tsd-is-protected > .tsd-kind-icon:before { - background-position: -153px -170px; -} -.tsd-is-static.tsd-kind-method.tsd-is-private > .tsd-kind-icon:before { - background-position: -119px -170px; -} -.tsd-is-static.tsd-kind-method.tsd-parent-kind-class > .tsd-kind-icon:before { - background-position: -51px -170px; -} -.tsd-is-static.tsd-kind-method.tsd-parent-kind-class.tsd-is-inherited > .tsd-kind-icon:before { - background-position: -68px -170px; -} -.tsd-is-static.tsd-kind-method.tsd-parent-kind-class.tsd-is-protected > .tsd-kind-icon:before { - background-position: -85px -170px; -} -.tsd-is-static.tsd-kind-method.tsd-parent-kind-class.tsd-is-protected.tsd-is-inherited > .tsd-kind-icon:before { - background-position: -102px -170px; -} -.tsd-is-static.tsd-kind-method.tsd-parent-kind-class.tsd-is-private > .tsd-kind-icon:before { - background-position: -119px -170px; -} -.tsd-is-static.tsd-kind-method.tsd-parent-kind-enum > .tsd-kind-icon:before { - background-position: -170px -170px; -} -.tsd-is-static.tsd-kind-method.tsd-parent-kind-enum.tsd-is-protected > .tsd-kind-icon:before { - background-position: -187px -170px; -} -.tsd-is-static.tsd-kind-method.tsd-parent-kind-enum.tsd-is-private > .tsd-kind-icon:before { - background-position: -119px -170px; -} -.tsd-is-static.tsd-kind-method.tsd-parent-kind-interface > .tsd-kind-icon:before { - background-position: -204px -170px; -} -.tsd-is-static.tsd-kind-method.tsd-parent-kind-interface.tsd-is-inherited > .tsd-kind-icon:before { - background-position: -221px -170px; -} - -.tsd-is-static.tsd-kind-call-signature > .tsd-kind-icon:before { - background-position: -136px -170px; -} -.tsd-is-static.tsd-kind-call-signature.tsd-is-protected > .tsd-kind-icon:before { - background-position: -153px -170px; -} -.tsd-is-static.tsd-kind-call-signature.tsd-is-private > .tsd-kind-icon:before { - background-position: -119px -170px; -} -.tsd-is-static.tsd-kind-call-signature.tsd-parent-kind-class > .tsd-kind-icon:before { - background-position: -51px -170px; -} -.tsd-is-static.tsd-kind-call-signature.tsd-parent-kind-class.tsd-is-inherited > .tsd-kind-icon:before { - background-position: -68px -170px; -} -.tsd-is-static.tsd-kind-call-signature.tsd-parent-kind-class.tsd-is-protected > .tsd-kind-icon:before { - background-position: -85px -170px; -} -.tsd-is-static.tsd-kind-call-signature.tsd-parent-kind-class.tsd-is-protected.tsd-is-inherited > .tsd-kind-icon:before { - background-position: -102px -170px; -} -.tsd-is-static.tsd-kind-call-signature.tsd-parent-kind-class.tsd-is-private > .tsd-kind-icon:before { - background-position: -119px -170px; -} -.tsd-is-static.tsd-kind-call-signature.tsd-parent-kind-enum > .tsd-kind-icon:before { - background-position: -170px -170px; -} -.tsd-is-static.tsd-kind-call-signature.tsd-parent-kind-enum.tsd-is-protected > .tsd-kind-icon:before { - background-position: -187px -170px; -} -.tsd-is-static.tsd-kind-call-signature.tsd-parent-kind-enum.tsd-is-private > .tsd-kind-icon:before { - background-position: -119px -170px; -} -.tsd-is-static.tsd-kind-call-signature.tsd-parent-kind-interface > .tsd-kind-icon:before { - background-position: -204px -170px; -} -.tsd-is-static.tsd-kind-call-signature.tsd-parent-kind-interface.tsd-is-inherited > .tsd-kind-icon:before { - background-position: -221px -170px; -} - -.tsd-is-static.tsd-kind-event > .tsd-kind-icon:before { - background-position: -136px -187px; -} -.tsd-is-static.tsd-kind-event.tsd-is-protected > .tsd-kind-icon:before { - background-position: -153px -187px; -} -.tsd-is-static.tsd-kind-event.tsd-is-private > .tsd-kind-icon:before { - background-position: -119px -187px; -} -.tsd-is-static.tsd-kind-event.tsd-parent-kind-class > .tsd-kind-icon:before { - background-position: -51px -187px; -} -.tsd-is-static.tsd-kind-event.tsd-parent-kind-class.tsd-is-inherited > .tsd-kind-icon:before { - background-position: -68px -187px; -} -.tsd-is-static.tsd-kind-event.tsd-parent-kind-class.tsd-is-protected > .tsd-kind-icon:before { - background-position: -85px -187px; -} -.tsd-is-static.tsd-kind-event.tsd-parent-kind-class.tsd-is-protected.tsd-is-inherited > .tsd-kind-icon:before { - background-position: -102px -187px; -} -.tsd-is-static.tsd-kind-event.tsd-parent-kind-class.tsd-is-private > .tsd-kind-icon:before { - background-position: -119px -187px; -} -.tsd-is-static.tsd-kind-event.tsd-parent-kind-enum > .tsd-kind-icon:before { - background-position: -170px -187px; -} -.tsd-is-static.tsd-kind-event.tsd-parent-kind-enum.tsd-is-protected > .tsd-kind-icon:before { - background-position: -187px -187px; -} -.tsd-is-static.tsd-kind-event.tsd-parent-kind-enum.tsd-is-private > .tsd-kind-icon:before { - background-position: -119px -187px; -} -.tsd-is-static.tsd-kind-event.tsd-parent-kind-interface > .tsd-kind-icon:before { - background-position: -204px -187px; -} -.tsd-is-static.tsd-kind-event.tsd-parent-kind-interface.tsd-is-inherited > .tsd-kind-icon:before { - background-position: -221px -187px; -} - -@keyframes fade-in { - from { - opacity: 0; - } - to { - opacity: 1; - } -} -@keyframes fade-out { - from { - opacity: 1; - visibility: visible; - } - to { - opacity: 0; - } -} -@keyframes fade-in-delayed { - 0% { - opacity: 0; - } - 33% { - opacity: 0; - } - 100% { - opacity: 1; - } -} -@keyframes fade-out-delayed { - 0% { - opacity: 1; - visibility: visible; - } - 66% { - opacity: 0; - } - 100% { - opacity: 0; - } -} -@keyframes shift-to-left { - from { - transform: translate(0, 0); - } - to { - transform: translate(-25%, 0); - } -} -@keyframes unshift-to-left { - from { - transform: translate(-25%, 0); - } - to { - transform: translate(0, 0); - } -} -@keyframes pop-in-from-right { - from { - transform: translate(100%, 0); - } - to { - transform: translate(0, 0); - } -} -@keyframes pop-out-to-right { - from { - transform: translate(0, 0); - visibility: visible; - } - to { - transform: translate(100%, 0); - } -} -body { - background: #fdfdfd; - font-family: "Segoe UI", sans-serif; - font-size: 16px; - color: #222; -} - -a { - color: #4da6ff; - text-decoration: none; -} -a:hover { - text-decoration: underline; -} - -code, pre { - font-family: Menlo, Monaco, Consolas, "Courier New", monospace; - padding: 0.2em; - margin: 0; - font-size: 14px; - background-color: rgba(0, 0, 0, 0.04); -} - -pre { - padding: 10px; -} -pre code { - padding: 0; - font-size: 100%; - background-color: transparent; -} - -.tsd-typography { - line-height: 1.333em; -} -.tsd-typography ul { - list-style: square; - padding: 0 0 0 20px; - margin: 0; -} -.tsd-typography h4, .tsd-typography .tsd-index-panel h3, .tsd-index-panel .tsd-typography h3, .tsd-typography h5, .tsd-typography h6 { - font-size: 1em; - margin: 0; -} -.tsd-typography h5, .tsd-typography h6 { - font-weight: normal; -} -.tsd-typography p, .tsd-typography ul, .tsd-typography ol { - margin: 1em 0; -} - -@media (min-width: 901px) and (max-width: 1024px) { - html.default .col-content { - width: 72%; - } - html.default .col-menu { - width: 28%; - } - html.default .tsd-navigation { - padding-left: 10px; - } -} -@media (max-width: 900px) { - html.default .col-content { - float: none; - width: 100%; - } - html.default .col-menu { - position: fixed !important; - overflow: auto; - -webkit-overflow-scrolling: touch; - z-index: 1024; - top: 0 !important; - bottom: 0 !important; - left: auto !important; - right: 0 !important; - width: 100%; - padding: 20px 20px 0 0; - max-width: 450px; - visibility: hidden; - background-color: #fff; - transform: translate(100%, 0); - } - html.default .col-menu > *:last-child { - padding-bottom: 20px; - } - html.default .overlay { - content: ""; - display: block; - position: fixed; - z-index: 1023; - top: 0; - left: 0; - right: 0; - bottom: 0; - background-color: rgba(0, 0, 0, 0.75); - visibility: hidden; - } - html.default.to-has-menu .overlay { - animation: fade-in 0.4s; - } - html.default.to-has-menu header, -html.default.to-has-menu footer, -html.default.to-has-menu .col-content { - animation: shift-to-left 0.4s; - } - html.default.to-has-menu .col-menu { - animation: pop-in-from-right 0.4s; - } - html.default.from-has-menu .overlay { - animation: fade-out 0.4s; - } - html.default.from-has-menu header, -html.default.from-has-menu footer, -html.default.from-has-menu .col-content { - animation: unshift-to-left 0.4s; - } - html.default.from-has-menu .col-menu { - animation: pop-out-to-right 0.4s; - } - html.default.has-menu body { - overflow: hidden; - } - html.default.has-menu .overlay { - visibility: visible; - } - html.default.has-menu header, -html.default.has-menu footer, -html.default.has-menu .col-content { - transform: translate(-25%, 0); - } - html.default.has-menu .col-menu { - visibility: visible; - transform: translate(0, 0); - } -} - -.tsd-page-title { - padding: 70px 0 20px 0; - margin: 0 0 40px 0; - background: #fff; - box-shadow: 0 0 5px rgba(0, 0, 0, 0.35); -} -.tsd-page-title h1 { - margin: 0; -} - -.tsd-breadcrumb { - margin: 0; - padding: 0; - color: #808080; -} -.tsd-breadcrumb a { - color: #808080; - text-decoration: none; -} -.tsd-breadcrumb a:hover { - text-decoration: underline; -} -.tsd-breadcrumb li { - display: inline; -} -.tsd-breadcrumb li:after { - content: " / "; -} - -html.minimal .container { - margin: 0; -} -html.minimal .container-main { - padding-top: 50px; - padding-bottom: 0; -} -html.minimal .content-wrap { - padding-left: 300px; -} -html.minimal .tsd-navigation { - position: fixed !important; - overflow: auto; - -webkit-overflow-scrolling: touch; - box-sizing: border-box; - z-index: 1; - left: 0; - top: 40px; - bottom: 0; - width: 300px; - padding: 20px; - margin: 0; -} -html.minimal .tsd-member .tsd-member { - margin-left: 0; -} -html.minimal .tsd-page-toolbar { - position: fixed; - z-index: 2; -} -html.minimal #tsd-filter .tsd-filter-group { - right: 0; - transform: none; -} -html.minimal footer { - background-color: transparent; -} -html.minimal footer .container { - padding: 0; -} -html.minimal .tsd-generator { - padding: 0; -} -@media (max-width: 900px) { - html.minimal .tsd-navigation { - display: none; - } - html.minimal .content-wrap { - padding-left: 0; - } -} - -dl.tsd-comment-tags { - overflow: hidden; -} -dl.tsd-comment-tags dt { - float: left; - padding: 1px 5px; - margin: 0 10px 0 0; - border-radius: 4px; - border: 1px solid #808080; - color: #808080; - font-size: 0.8em; - font-weight: normal; -} -dl.tsd-comment-tags dd { - margin: 0 0 10px 0; -} -dl.tsd-comment-tags dd:before, dl.tsd-comment-tags dd:after { - display: table; - content: " "; -} -dl.tsd-comment-tags dd pre, dl.tsd-comment-tags dd:after { - clear: both; -} -dl.tsd-comment-tags p { - margin: 0; -} - -.tsd-panel.tsd-comment .lead { - font-size: 1.1em; - line-height: 1.333em; - margin-bottom: 2em; -} -.tsd-panel.tsd-comment .lead:last-child { - margin-bottom: 0; -} - -.toggle-protected .tsd-is-private { - display: none; -} - -.toggle-public .tsd-is-private, -.toggle-public .tsd-is-protected, -.toggle-public .tsd-is-private-protected { - display: none; -} - -.toggle-inherited .tsd-is-inherited { - display: none; -} - -.toggle-only-exported .tsd-is-not-exported { - display: none; -} - -.toggle-externals .tsd-is-external { - display: none; -} - -#tsd-filter { - position: relative; - display: inline-block; - height: 40px; - vertical-align: bottom; -} -.no-filter #tsd-filter { - display: none; -} -#tsd-filter .tsd-filter-group { - display: inline-block; - height: 40px; - vertical-align: bottom; - white-space: nowrap; -} -#tsd-filter input { - display: none; -} -@media (max-width: 900px) { - #tsd-filter .tsd-filter-group { - display: block; - position: absolute; - top: 40px; - right: 20px; - height: auto; - background-color: #fff; - visibility: hidden; - transform: translate(50%, 0); - box-shadow: 0 0 4px rgba(0, 0, 0, 0.25); - } - .has-options #tsd-filter .tsd-filter-group { - visibility: visible; - } - .to-has-options #tsd-filter .tsd-filter-group { - animation: fade-in 0.2s; - } - .from-has-options #tsd-filter .tsd-filter-group { - animation: fade-out 0.2s; - } - #tsd-filter label, -#tsd-filter .tsd-select { - display: block; - padding-right: 20px; - } -} - -footer { - border-top: 1px solid #eee; - background-color: #fff; -} -footer.with-border-bottom { - border-bottom: 1px solid #eee; -} -footer .tsd-legend-group { - font-size: 0; -} -footer .tsd-legend { - display: inline-block; - width: 25%; - padding: 0; - font-size: 16px; - list-style: none; - line-height: 1.333em; - vertical-align: top; -} -@media (max-width: 900px) { - footer .tsd-legend { - width: 50%; - } -} - -.tsd-hierarchy { - list-style: square; - padding: 0 0 0 20px; - margin: 0; -} -.tsd-hierarchy .target { - font-weight: bold; -} - -.tsd-index-panel .tsd-index-content { - margin-bottom: -30px !important; -} -.tsd-index-panel .tsd-index-section { - margin-bottom: 30px !important; -} -.tsd-index-panel h3 { - margin: 0 -20px 10px -20px; - padding: 0 20px 10px 20px; - border-bottom: 1px solid #eee; -} -.tsd-index-panel ul.tsd-index-list { - -moz-column-count: 3; - -ms-column-count: 3; - -o-column-count: 3; - column-count: 3; - -moz-column-gap: 20px; - -ms-column-gap: 20px; - -o-column-gap: 20px; - column-gap: 20px; - padding: 0; - list-style: none; - line-height: 1.333em; -} -@media (max-width: 900px) { - .tsd-index-panel ul.tsd-index-list { - -moz-column-count: 1; - -ms-column-count: 1; - -o-column-count: 1; - column-count: 1; - } -} -@media (min-width: 901px) and (max-width: 1024px) { - .tsd-index-panel ul.tsd-index-list { - -moz-column-count: 2; - -ms-column-count: 2; - -o-column-count: 2; - column-count: 2; - } -} -.tsd-index-panel ul.tsd-index-list li { - -webkit-page-break-inside: avoid; - -moz-page-break-inside: avoid; - -ms-page-break-inside: avoid; - -o-page-break-inside: avoid; - page-break-inside: avoid; -} -.tsd-index-panel a, -.tsd-index-panel .tsd-parent-kind-module a { - color: #9600ff; -} -.tsd-index-panel .tsd-parent-kind-interface a { - color: #7da01f; -} -.tsd-index-panel .tsd-parent-kind-enum a { - color: #cc9900; -} -.tsd-index-panel .tsd-parent-kind-class a { - color: #4da6ff; -} -.tsd-index-panel .tsd-kind-module a { - color: #9600ff; -} -.tsd-index-panel .tsd-kind-interface a { - color: #7da01f; -} -.tsd-index-panel .tsd-kind-enum a { - color: #cc9900; -} -.tsd-index-panel .tsd-kind-class a { - color: #4da6ff; -} -.tsd-index-panel .tsd-is-private a { - color: #808080; -} - -.tsd-flag { - display: inline-block; - padding: 1px 5px; - border-radius: 4px; - color: #fff; - background-color: #808080; - text-indent: 0; - font-size: 14px; - font-weight: normal; -} - -.tsd-anchor { - position: absolute; - top: -100px; -} - -.tsd-member { - position: relative; -} -.tsd-member .tsd-anchor + h3 { - margin-top: 0; - margin-bottom: 0; - border-bottom: none; -} - -.tsd-navigation { - margin: 0 0 0 40px; -} -.tsd-navigation a { - display: block; - padding-top: 2px; - padding-bottom: 2px; - border-left: 2px solid transparent; - color: #222; - text-decoration: none; - transition: border-left-color 0.1s; -} -.tsd-navigation a:hover { - text-decoration: underline; -} -.tsd-navigation ul { - margin: 0; - padding: 0; - list-style: none; -} -.tsd-navigation li { - padding: 0; -} - -.tsd-navigation.primary { - padding-bottom: 40px; -} -.tsd-navigation.primary a { - display: block; - padding-top: 6px; - padding-bottom: 6px; -} -.tsd-navigation.primary ul li a { - padding-left: 5px; -} -.tsd-navigation.primary ul li li a { - padding-left: 25px; -} -.tsd-navigation.primary ul li li li a { - padding-left: 45px; -} -.tsd-navigation.primary ul li li li li a { - padding-left: 65px; -} -.tsd-navigation.primary ul li li li li li a { - padding-left: 85px; -} -.tsd-navigation.primary ul li li li li li li a { - padding-left: 105px; -} -.tsd-navigation.primary > ul { - border-bottom: 1px solid #eee; -} -.tsd-navigation.primary li { - border-top: 1px solid #eee; -} -.tsd-navigation.primary li.current > a { - font-weight: bold; -} -.tsd-navigation.primary li.label span { - display: block; - padding: 20px 0 6px 5px; - color: #808080; -} -.tsd-navigation.primary li.globals + li > span, .tsd-navigation.primary li.globals + li > a { - padding-top: 20px; -} - -.tsd-navigation.secondary { - max-height: calc(100vh - 1rem - 40px); - overflow: auto; - position: -webkit-sticky; - position: sticky; - top: calc(.5rem + 40px); - transition: 0.3s; -} -.tsd-navigation.secondary.tsd-navigation--toolbar-hide { - max-height: calc(100vh - 1rem); - top: 0.5rem; -} -.tsd-navigation.secondary ul { - transition: opacity 0.2s; -} -.tsd-navigation.secondary ul li a { - padding-left: 25px; -} -.tsd-navigation.secondary ul li li a { - padding-left: 45px; -} -.tsd-navigation.secondary ul li li li a { - padding-left: 65px; -} -.tsd-navigation.secondary ul li li li li a { - padding-left: 85px; -} -.tsd-navigation.secondary ul li li li li li a { - padding-left: 105px; -} -.tsd-navigation.secondary ul li li li li li li a { - padding-left: 125px; -} -.tsd-navigation.secondary ul.current a { - border-left-color: #eee; -} -.tsd-navigation.secondary li.focus > a, -.tsd-navigation.secondary ul.current li.focus > a { - border-left-color: #000; -} -.tsd-navigation.secondary li.current { - margin-top: 20px; - margin-bottom: 20px; - border-left-color: #eee; -} -.tsd-navigation.secondary li.current > a { - font-weight: bold; -} - -@media (min-width: 901px) { - .menu-sticky-wrap { - position: static; - } -} - -.tsd-panel { - margin: 20px 0; - padding: 20px; - background-color: #fff; - box-shadow: 0 0 4px rgba(0, 0, 0, 0.25); -} -.tsd-panel:empty { - display: none; -} -.tsd-panel > h1, .tsd-panel > h2, .tsd-panel > h3 { - margin: 1.5em -20px 10px -20px; - padding: 0 20px 10px 20px; - border-bottom: 1px solid #eee; -} -.tsd-panel > h1.tsd-before-signature, .tsd-panel > h2.tsd-before-signature, .tsd-panel > h3.tsd-before-signature { - margin-bottom: 0; - border-bottom: 0; -} -.tsd-panel table { - display: block; - width: 100%; - overflow: auto; - margin-top: 10px; - word-break: normal; - word-break: keep-all; -} -.tsd-panel table th { - font-weight: bold; -} -.tsd-panel table th, .tsd-panel table td { - padding: 6px 13px; - border: 1px solid #ddd; -} -.tsd-panel table tr { - background-color: #fff; - border-top: 1px solid #ccc; -} -.tsd-panel table tr:nth-child(2n) { - background-color: #f8f8f8; -} - -.tsd-panel-group { - margin: 60px 0; -} -.tsd-panel-group > h1, .tsd-panel-group > h2, .tsd-panel-group > h3 { - padding-left: 20px; - padding-right: 20px; -} - -#tsd-search { - transition: background-color 0.2s; -} -#tsd-search .title { - position: relative; - z-index: 2; -} -#tsd-search .field { - position: absolute; - left: 0; - top: 0; - right: 40px; - height: 40px; -} -#tsd-search .field input { - box-sizing: border-box; - position: relative; - top: -50px; - z-index: 1; - width: 100%; - padding: 0 10px; - opacity: 0; - outline: 0; - border: 0; - background: transparent; - color: #222; -} -#tsd-search .field label { - position: absolute; - overflow: hidden; - right: -40px; -} -#tsd-search .field input, -#tsd-search .title { - transition: opacity 0.2s; -} -#tsd-search .results { - position: absolute; - visibility: hidden; - top: 40px; - width: 100%; - margin: 0; - padding: 0; - list-style: none; - box-shadow: 0 0 4px rgba(0, 0, 0, 0.25); -} -#tsd-search .results li { - padding: 0 10px; - background-color: #fdfdfd; -} -#tsd-search .results li:nth-child(even) { - background-color: #fff; -} -#tsd-search .results li.state { - display: none; -} -#tsd-search .results li.current, -#tsd-search .results li:hover { - background-color: #eee; -} -#tsd-search .results a { - display: block; -} -#tsd-search .results a:before { - top: 10px; -} -#tsd-search .results span.parent { - color: #808080; - font-weight: normal; -} -#tsd-search.has-focus { - background-color: #eee; -} -#tsd-search.has-focus .field input { - top: 0; - opacity: 1; -} -#tsd-search.has-focus .title { - z-index: 0; - opacity: 0; -} -#tsd-search.has-focus .results { - visibility: visible; -} -#tsd-search.loading .results li.state.loading { - display: block; -} -#tsd-search.failure .results li.state.failure { - display: block; -} - -.tsd-signature { - margin: 0 0 1em 0; - padding: 10px; - border: 1px solid #eee; - font-family: Menlo, Monaco, Consolas, "Courier New", monospace; - font-size: 14px; - overflow-x: auto; -} -.tsd-signature.tsd-kind-icon { - padding-left: 30px; -} -.tsd-signature.tsd-kind-icon:before { - top: 10px; - left: 10px; -} -.tsd-panel > .tsd-signature { - margin-left: -20px; - margin-right: -20px; - border-width: 1px 0; -} -.tsd-panel > .tsd-signature.tsd-kind-icon { - padding-left: 40px; -} -.tsd-panel > .tsd-signature.tsd-kind-icon:before { - left: 20px; -} - -.tsd-signature-symbol { - color: #808080; - font-weight: normal; -} - -.tsd-signature-type { - font-style: italic; - font-weight: normal; -} - -.tsd-signatures { - padding: 0; - margin: 0 0 1em 0; - border: 1px solid #eee; -} -.tsd-signatures .tsd-signature { - margin: 0; - border-width: 1px 0 0 0; - transition: background-color 0.1s; -} -.tsd-signatures .tsd-signature:first-child { - border-top-width: 0; -} -.tsd-signatures .tsd-signature.current { - background-color: #eee; -} -.tsd-signatures.active > .tsd-signature { - cursor: pointer; -} -.tsd-panel > .tsd-signatures { - margin-left: -20px; - margin-right: -20px; - border-width: 1px 0; -} -.tsd-panel > .tsd-signatures .tsd-signature.tsd-kind-icon { - padding-left: 40px; -} -.tsd-panel > .tsd-signatures .tsd-signature.tsd-kind-icon:before { - left: 20px; -} -.tsd-panel > a.anchor + .tsd-signatures { - border-top-width: 0; - margin-top: -20px; -} - -ul.tsd-descriptions { - position: relative; - overflow: hidden; - padding: 0; - list-style: none; -} -ul.tsd-descriptions.active > .tsd-description { - display: none; -} -ul.tsd-descriptions.active > .tsd-description.current { - display: block; -} -ul.tsd-descriptions.active > .tsd-description.fade-in { - animation: fade-in-delayed 0.3s; -} -ul.tsd-descriptions.active > .tsd-description.fade-out { - animation: fade-out-delayed 0.3s; - position: absolute; - display: block; - top: 0; - left: 0; - right: 0; - opacity: 0; - visibility: hidden; -} -ul.tsd-descriptions h4, ul.tsd-descriptions .tsd-index-panel h3, .tsd-index-panel ul.tsd-descriptions h3 { - font-size: 16px; - margin: 1em 0 0.5em 0; -} - -ul.tsd-parameters, -ul.tsd-type-parameters { - list-style: square; - margin: 0; - padding-left: 20px; -} -ul.tsd-parameters > li.tsd-parameter-signature, -ul.tsd-type-parameters > li.tsd-parameter-signature { - list-style: none; - margin-left: -20px; -} -ul.tsd-parameters h5, -ul.tsd-type-parameters h5 { - font-size: 16px; - margin: 1em 0 0.5em 0; -} -ul.tsd-parameters .tsd-comment, -ul.tsd-type-parameters .tsd-comment { - margin-top: -0.5em; -} - -.tsd-sources { - font-size: 14px; - color: #808080; - margin: 0 0 1em 0; -} -.tsd-sources a { - color: #808080; - text-decoration: underline; -} -.tsd-sources ul, .tsd-sources p { - margin: 0 !important; -} -.tsd-sources ul { - list-style: none; - padding: 0; -} - -.tsd-page-toolbar { - position: fixed; - z-index: 1; - top: 0; - left: 0; - width: 100%; - height: 40px; - color: #333; - background: #fff; - border-bottom: 1px solid #eee; - transition: transform 0.3s linear; -} -.tsd-page-toolbar a { - color: #333; - text-decoration: none; -} -.tsd-page-toolbar a.title { - font-weight: bold; -} -.tsd-page-toolbar a.title:hover { - text-decoration: underline; -} -.tsd-page-toolbar .table-wrap { - display: table; - width: 100%; - height: 40px; -} -.tsd-page-toolbar .table-cell { - display: table-cell; - position: relative; - white-space: nowrap; - line-height: 40px; -} -.tsd-page-toolbar .table-cell:first-child { - width: 100%; -} - -.tsd-page-toolbar--hide { - transform: translateY(-100%); -} - -.tsd-select .tsd-select-list li:before, .tsd-select .tsd-select-label:before, .tsd-widget:before { - content: ""; - display: inline-block; - width: 40px; - height: 40px; - margin: 0 -8px 0 0; - background-image: url(../images/widgets.png); - background-repeat: no-repeat; - text-indent: -1024px; - vertical-align: bottom; -} -@media (-webkit-min-device-pixel-ratio: 1.5), (min-resolution: 144dpi) { - .tsd-select .tsd-select-list li:before, .tsd-select .tsd-select-label:before, .tsd-widget:before { - background-image: url(../images/widgets@2x.png); - background-size: 320px 40px; - } -} - -.tsd-widget { - display: inline-block; - overflow: hidden; - opacity: 0.6; - height: 40px; - transition: opacity 0.1s, background-color 0.2s; - vertical-align: bottom; - cursor: pointer; -} -.tsd-widget:hover { - opacity: 0.8; -} -.tsd-widget.active { - opacity: 1; - background-color: #eee; -} -.tsd-widget.no-caption { - width: 40px; -} -.tsd-widget.no-caption:before { - margin: 0; -} -.tsd-widget.search:before { - background-position: 0 0; -} -.tsd-widget.menu:before { - background-position: -40px 0; -} -.tsd-widget.options:before { - background-position: -80px 0; -} -.tsd-widget.options, .tsd-widget.menu { - display: none; -} -@media (max-width: 900px) { - .tsd-widget.options, .tsd-widget.menu { - display: inline-block; - } -} -input[type=checkbox] + .tsd-widget:before { - background-position: -120px 0; -} -input[type=checkbox]:checked + .tsd-widget:before { - background-position: -160px 0; -} - -.tsd-select { - position: relative; - display: inline-block; - height: 40px; - transition: opacity 0.1s, background-color 0.2s; - vertical-align: bottom; - cursor: pointer; -} -.tsd-select .tsd-select-label { - opacity: 0.6; - transition: opacity 0.2s; -} -.tsd-select .tsd-select-label:before { - background-position: -240px 0; -} -.tsd-select.active .tsd-select-label { - opacity: 0.8; -} -.tsd-select.active .tsd-select-list { - visibility: visible; - opacity: 1; - transition-delay: 0s; -} -.tsd-select .tsd-select-list { - position: absolute; - visibility: hidden; - top: 40px; - left: 0; - margin: 0; - padding: 0; - opacity: 0; - list-style: none; - box-shadow: 0 0 4px rgba(0, 0, 0, 0.25); - transition: visibility 0s 0.2s, opacity 0.2s; -} -.tsd-select .tsd-select-list li { - padding: 0 20px 0 0; - background-color: #fdfdfd; -} -.tsd-select .tsd-select-list li:before { - background-position: 40px 0; -} -.tsd-select .tsd-select-list li:nth-child(even) { - background-color: #fff; -} -.tsd-select .tsd-select-list li:hover { - background-color: #eee; -} -.tsd-select .tsd-select-list li.selected:before { - background-position: -200px 0; -} -@media (max-width: 900px) { - .tsd-select .tsd-select-list { - top: 0; - left: auto; - right: 100%; - margin-right: -5px; - } - .tsd-select .tsd-select-label:before { - background-position: -280px 0; - } -} - -img { - max-width: 100%; -} \ No newline at end of file diff --git a/docs/api/assets/images/icons.png b/docs/api/assets/images/icons.png deleted file mode 100644 index 3836d5fe..00000000 Binary files a/docs/api/assets/images/icons.png and /dev/null differ diff --git a/docs/api/assets/images/icons@2x.png b/docs/api/assets/images/icons@2x.png deleted file mode 100644 index 5a209e2f..00000000 Binary files a/docs/api/assets/images/icons@2x.png and /dev/null differ diff --git a/docs/api/assets/images/widgets.png b/docs/api/assets/images/widgets.png deleted file mode 100644 index c7380532..00000000 Binary files a/docs/api/assets/images/widgets.png and /dev/null differ diff --git a/docs/api/assets/images/widgets@2x.png b/docs/api/assets/images/widgets@2x.png deleted file mode 100644 index 4bbbd572..00000000 Binary files a/docs/api/assets/images/widgets@2x.png and /dev/null differ diff --git a/docs/api/assets/js/main.js b/docs/api/assets/js/main.js deleted file mode 100644 index 39a80669..00000000 --- a/docs/api/assets/js/main.js +++ /dev/null @@ -1 +0,0 @@ -!function(){var e=function(t){var r=new e.Builder;return r.pipeline.add(e.trimmer,e.stopWordFilter,e.stemmer),r.searchPipeline.add(e.stemmer),t.call(r,r),r.build()};e.version="2.3.7",e.utils={},e.utils.warn=function(e){return function(t){e.console&&console.warn&&console.warn(t)}}(this),e.utils.asString=function(e){return null==e?"":e.toString()},e.utils.clone=function(e){if(null==e)return e;for(var t=Object.create(null),r=Object.keys(e),i=0;i=this.length)return e.QueryLexer.EOS;var t=this.str.charAt(this.pos);return this.pos+=1,t},e.QueryLexer.prototype.width=function(){return this.pos-this.start},e.QueryLexer.prototype.ignore=function(){this.start==this.pos&&(this.pos+=1),this.start=this.pos},e.QueryLexer.prototype.backup=function(){this.pos-=1},e.QueryLexer.prototype.acceptDigitRun=function(){for(var t,r;47<(r=(t=this.next()).charCodeAt(0))&&r<58;);t!=e.QueryLexer.EOS&&this.backup()},e.QueryLexer.prototype.more=function(){return this.pos=this.scrollTop||0===this.scrollTop,isShown!==this.showToolbar&&(this.toolbar.classList.toggle("tsd-page-toolbar--hide"),this.secondaryNav.classList.toggle("tsd-navigation--toolbar-hide")),this.lastY=this.scrollTop},Viewport}(typedoc.EventTarget);typedoc.Viewport=Viewport,typedoc.registerService(Viewport,"viewport")}(typedoc||(typedoc={})),function(typedoc){function Component(options){this.el=options.el}typedoc.Component=Component}(typedoc||(typedoc={})),function(typedoc){typedoc.pointerDown="mousedown",typedoc.pointerMove="mousemove",typedoc.pointerUp="mouseup",typedoc.pointerDownPosition={x:0,y:0},typedoc.preventNextClick=!1,typedoc.isPointerDown=!1,typedoc.isPointerTouch=!1,typedoc.hasPointerMoved=!1,typedoc.isMobile=/Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(navigator.userAgent),document.documentElement.classList.add(typedoc.isMobile?"is-mobile":"not-mobile"),typedoc.isMobile&&"ontouchstart"in document.documentElement&&(typedoc.isPointerTouch=!0,typedoc.pointerDown="touchstart",typedoc.pointerMove="touchmove",typedoc.pointerUp="touchend"),document.addEventListener(typedoc.pointerDown,function(e){typedoc.isPointerDown=!0,typedoc.hasPointerMoved=!1;var t="touchstart"==typedoc.pointerDown?e.targetTouches[0]:e;typedoc.pointerDownPosition.y=t.pageY||0,typedoc.pointerDownPosition.x=t.pageX||0}),document.addEventListener(typedoc.pointerMove,function(e){if(typedoc.isPointerDown&&!typedoc.hasPointerMoved){var t="touchstart"==typedoc.pointerDown?e.targetTouches[0]:e,x=typedoc.pointerDownPosition.x-(t.pageX||0),y=typedoc.pointerDownPosition.y-(t.pageY||0);typedoc.hasPointerMoved=10scrollTop;)index-=1;for(;index"+match+""}),parent=row.parent||"";(parent=parent.replace(new RegExp(this.query,"i"),function(match){return""+match+""}))&&(name=''+parent+"."+name);var item=document.createElement("li");item.classList.value=row.classes,item.innerHTML='\n '+name+"\n ",this.results.appendChild(item)}}},Search.prototype.setLoadingState=function(value){this.loadingState!=value&&(this.el.classList.remove(SearchLoadingState[this.loadingState].toLowerCase()),this.loadingState=value,this.el.classList.add(SearchLoadingState[this.loadingState].toLowerCase()),this.updateResults())},Search.prototype.setHasFocus=function(value){this.hasFocus!=value&&(this.hasFocus=value,this.el.classList.toggle("has-focus"),value?(this.setQuery(""),this.field.value=""):this.field.value=this.query)},Search.prototype.setQuery=function(value){this.query=value.trim(),this.updateResults()},Search.prototype.setCurrentResult=function(dir){var current=this.results.querySelector(".current");if(current){var rel=1==dir?current.nextElementSibling:current.previousElementSibling;rel&&(current.classList.remove("current"),rel.classList.add("current"))}else(current=this.results.querySelector(1==dir?"li:first-child":"li:last-child"))&¤t.classList.add("current")},Search.prototype.gotoCurrentResult=function(){var current=this.results.querySelector(".current");if(current||(current=this.results.querySelector("li:first-child")),current){var link=current.querySelector("a");link&&(window.location.href=link.href),this.field.blur()}},Search.prototype.bindEvents=function(){var _this=this;this.results.addEventListener("mousedown",function(){_this.resultClicked=!0}),this.results.addEventListener("mouseup",function(){_this.resultClicked=!1,_this.setHasFocus(!1)}),this.field.addEventListener("focusin",function(){_this.setHasFocus(!0),_this.loadIndex()}),this.field.addEventListener("focusout",function(){_this.resultClicked?_this.resultClicked=!1:setTimeout(function(){return _this.setHasFocus(!1)},100)}),this.field.addEventListener("input",function(){_this.setQuery(_this.field.value)}),this.field.addEventListener("keydown",function(e){13==e.keyCode||27==e.keyCode||38==e.keyCode||40==e.keyCode?(_this.preventPress=!0,e.preventDefault(),13==e.keyCode?_this.gotoCurrentResult():27==e.keyCode?_this.field.blur():38==e.keyCode?_this.setCurrentResult(-1):40==e.keyCode&&_this.setCurrentResult(1)):_this.preventPress=!1}),this.field.addEventListener("keypress",function(e){_this.preventPress&&e.preventDefault()}),document.body.addEventListener("keydown",function(e){e.altKey||e.ctrlKey||e.metaKey||!_this.hasFocus&&47this.groups.length-1&&(index=this.groups.length-1),this.index!=index){var to=this.groups[index];if(-1 - - - - - BaseError | nextcloud-node-client - - - - - -
-
-
-
- -
-
- Options -
-
- All -
    -
  • Public
  • -
  • Public/Protected
  • -
  • All
  • -
-
- - -
-
- Menu -
-
-
-
-
-
- -

Class BaseError

-
-
-
-
-
-
-
-

Hierarchy

- -
-
-

Index

-
-
-
-

Constructors

- -
-
-

Properties

- -
-
-
-
-
-

Constructors

-
- -

constructor

-
    -
  • new BaseError(m: string, context?: any): BaseError
  • -
-
    -
  • - -

    Parameters

    -
      -
    • -
      m: string
      -
    • -
    • -
      Optional context: any
      -
    • -
    -

    Returns BaseError

    -
  • -
-
-
-
-

Properties

-
- -

message

-
message: string
- -
-
- -

name

-
name: string
- -
-
- -

Optional stack

-
stack: undefined | string
- -
-
- -

Static Error

-
Error: ErrorConstructor
- -
-
-
- -
-
-
-
-

Legend

-
-
    -
  • Constructor
  • -
  • Property
  • -
  • Method
  • -
-
    -
  • Inherited constructor
  • -
  • Inherited property
  • -
  • Inherited method
  • -
-
    -
  • Protected property
  • -
  • Protected method
  • -
-
    -
  • Static property
  • -
  • Static method
  • -
-
    -
  • Property
  • -
-
-
-
-
-

Generated using TypeDoc

-
-
- - - \ No newline at end of file diff --git a/docs/api/classes/client.html b/docs/api/classes/client.html deleted file mode 100644 index b1a29588..00000000 --- a/docs/api/classes/client.html +++ /dev/null @@ -1,2614 +0,0 @@ - - - - - - Client | nextcloud-node-client - - - - - -
-
-
-
- -
-
- Options -
-
- All -
    -
  • Public
  • -
  • Public/Protected
  • -
  • All
  • -
-
- - -
-
- Menu -
-
-
-
-
-
- -

Class Client

-
-
-
-
-
-
-
-
-
-

The nextcloud client is the root object to access the remote api of the nextcloud server.

-
-
-
-
-

Hierarchy

-
    -
  • - Client -
  • -
-
-
-

Index

-
- -
-
-
-

Constructors

-
- -

constructor

- -
    -
  • - -
    -
    -

    Creates a new instance of a nextcloud client.
    - Use the server to provide server connectivity information to the client.
    - (The FakeServer is only used for testing and code coverage)

    - If the server is not provided the client tries to find the connectivity information - in the environment.
    - If a VCAP_SERVICES environment variable is available, the client tries to find - a service with the name "nextcloud" in the user-provides-services section.
    - If no VCAP_SERVICES are available, the client uses the following variables - from the envirnonment for the connectivity:

    -
      -
    • NEXTCLOUD_URL - the url of the nextcloud server
    • -
    • NEXTCLOUD_USERNAME - the user name
    • -
    • NEXTCLOUD_PASSWORD - the application password
    • -
    -
    -
    -

    Parameters

    -
      -
    • -
      Optional server: Server | FakeServer
      -
      -
      -

      optional server information to connection to a nextcloud server

      -
      -
      -
    • -
    -

    Returns Client

    -
  • -
-
-
-
-

Properties

-
- -

Static webDavUrlPath

-
webDavUrlPath: string = "/remote.php/webdav"
- -
-
-
-

Methods

-
- -

addCommentToFile

-
    -
  • addCommentToFile(fileId: number, comment: string): Promise<void>
  • -
-
    -
  • - -
    -
    -

    adds a comment to a file

    -
    -
    -

    Parameters

    -
      -
    • -
      fileId: number
      -
      -

      the id of the file

      -
      -
    • -
    • -
      comment: string
      -
      -

      the comment to be added to the file

      -
      -
    • -
    -

    Returns Promise<void>

    -
  • -
-
-
- -

addTagToFile

-
    -
  • addTagToFile(fileId: number, tagName: string): Promise<void>
  • -
-
    -
  • - -
    -
    -

    adds a tag to a file or folder - if the tag does not exist, it is automatically created - if the tag is created, the user must have damin privileges

    -
    -
    -
    throws
    -

    Error

    -
    -
    -
    -

    Parameters

    -
      -
    • -
      fileId: number
      -
      -

      the id of the file

      -
      -
    • -
    • -
      tagName: string
      -
      -

      the name of the tag

      -
      -
    • -
    -

    Returns Promise<void>

    -

    nothing

    -
  • -
-
-
- -

addUserToMemberUserGroup

-
    -
  • addUserToMemberUserGroup(id: string, userGroupId: string): Promise<void>
  • -
-
    -
  • - -
    -
    -

    adds a user to a group as member

    -
    -
    -
    throws
    -

    {UserNotFoundError}

    -
    -
    throws
    -

    {UserGroupDoesNotExistError}

    -
    -
    throws
    -

    {InsufficientPrivilegesError}

    -
    -
    throws
    -

    {OperationFailedError}

    -
    -
    -
    -

    Parameters

    -
      -
    • -
      id: string
      -
      -

      string the user id

      -
      -
    • -
    • -
      userGroupId: string
      -
      -

      string the user group id

      -
      -
    • -
    -

    Returns Promise<void>

    -
  • -
-
-
- -

createFile

-
    -
  • createFile(fileName: string, data: Buffer | ReadableStream): Promise<File>
  • -
-
    -
  • - -
    -
    -

    create a new file of overwrites an existing file

    -
    -
    -

    Parameters

    -
      -
    • -
      fileName: string
      -
      -

      the file name /folder1/folder2/filename.txt

      -
      -
    • -
    • -
      data: Buffer | ReadableStream
      -
      -

      the buffer object

      -
      -
    • -
    -

    Returns Promise<File>

    -
  • -
-
-
- -

createFolder

-
    -
  • createFolder(folderName: string): Promise<Folder>
  • -
-
    -
  • - -
    -
    -

    creates a folder and all parent folders in the path if they do not exist

    -
    -
    -

    Parameters

    -
      -
    • -
      folderName: string
      -
      -

      name of the folder /folder/subfolder/subfolder

      -
      -
    • -
    -

    Returns Promise<Folder>

    -

    a folder object

    -
  • -
-
-
- -

createShare

- - -
-
- -

createTag

-
    -
  • createTag(tagName: string): Promise<Tag>
  • -
-
    -
  • - -
    -
    -

    creates a new tag, if not already existing - this function will fail with http 403 if the user does not have admin privileges

    -
    -
    -

    Parameters

    -
      -
    • -
      tagName: string
      -
      -

      the name of the tag

      -
      -
    • -
    -

    Returns Promise<Tag>

    -

    tagId

    -
  • -
-
-
- -

createUser

-
    -
  • createUser(options: { email?: undefined | string; id: string; password?: undefined | string }): Promise<User>
  • -
-
    -
  • - -
    -
    -

    creates a new user with email or password

    -
    -
    -
    throws
    -

    UserAlreadyExistsError

    -
    -
    throws
    -

    {UserNotFoundError}

    -
    -
    throws
    -

    UserUpdateError

    -
    -
    -
    -

    Parameters

    -
      -
    • -
      options: { email?: undefined | string; id: string; password?: undefined | string }
      -
        -
      • -
        Optional email?: undefined | string
        -
      • -
      • -
        id: string
        -
      • -
      • -
        Optional password?: undefined | string
        -
      • -
      -
    • -
    -

    Returns Promise<User>

    -

    User

    -
  • -
-
-
- -

createUserGroup

-
    -
  • createUserGroup(id: string): Promise<UserGroup>
  • -
-
    -
  • - -
    -
    -

    create a new user group

    -
    -
    -
    async
    -
    -
    throws
    -

    {UserGroupAlreadyExistsError}

    -
    -
    -
    -

    Parameters

    -
      -
    • -
      id: string
      -
      -

      user group id

      -
      -
    • -
    -

    Returns Promise<UserGroup>

    -
  • -
-
-
- -

deleteAllTags

-
    -
  • deleteAllTags(): Promise<void>
  • -
-
    -
  • - -
    -
    -

    deletes all visible assignable tags

    -
    -
    -
    throws
    -

    Error

    -
    -
    -
    -

    Returns Promise<void>

    -
  • -
-
-
- -

deleteFile

-
    -
  • deleteFile(fileName: string): Promise<void>
  • -
-
    -
  • - -
    -
    -

    deletes a file

    -
    -
    -

    Parameters

    -
      -
    • -
      fileName: string
      -
      -

      name of folder "/f1/f2/f3/x.txt"

      -
      -
    • -
    -

    Returns Promise<void>

    -
  • -
-
-
- -

deleteFolder

-
    -
  • deleteFolder(folderName: string): Promise<void>
  • -
-
    -
  • - -
    -
    -

    deletes a folder

    -
    -
    -

    Parameters

    -
      -
    • -
      folderName: string
      -
      -

      name of folder "/f1/f2/f3"

      -
      -
    • -
    -

    Returns Promise<void>

    -
  • -
-
-
- -

deleteShare

-
    -
  • deleteShare(shareId: string): Promise<any>
  • -
-
    -
  • - -
    -
    -

    get share information

    -
    -
    -

    Parameters

    -
      -
    • -
      shareId: string
      -
      -
      -
    • -
    -

    Returns Promise<any>

    -
  • -
-
-
- -

deleteTag

-
    -
  • deleteTag(tagId: number): Promise<void>
  • -
-
    -
  • - -
    -
    -

    deletes the tag by id - this function will fail with http 403 if the user does not have admin privileges

    -
    -
    -

    Parameters

    -
      -
    • -
      tagId: number
      -
      -

      the id of the tag like "/remote.php/dav/systemtags/234"

      -
      -
    • -
    -

    Returns Promise<void>

    -
  • -
-
-
- -

deleteUser

-
    -
  • deleteUser(id: string): Promise<void>
  • -
-
    -
  • - -
    -
    -

    deletes the user

    -
    -
    -
    throws
    -

    {UserNotFoundError}

    -
    -
    -
    -

    Parameters

    -
      -
    • -
      id: string
      -
      -

      string the user id

      -
      -
    • -
    -

    Returns Promise<void>

    -
  • -
-
-
- -

deleteUserGroup

-
    -
  • deleteUserGroup(id: string): Promise<void>
  • -
-
    -
  • - -
    -
    -

    deletes an existing user group

    -
    -
    -
    throws
    -

    {UserGroupDowsNotExistError}

    -
    -
    throws
    -

    {UserGroupDeletionFailedError}

    -
    -
    -
    -

    Parameters

    -
      -
    • -
      id: string
      -
      -

      string

      -
      -
    • -
    -

    Returns Promise<void>

    -
  • -
-
-
- -

demoteUserFromSubadminUserGroup

-
    -
  • demoteUserFromSubadminUserGroup(id: string, userGroupId: string): Promise<void>
  • -
-
    -
  • - -
    -
    -

    Removes the subadmin rights for the user specified from the group specified

    -
    -
    -
    throws
    -

    {InsufficientPrivilegesError}

    -
    -
    throws
    -

    {OperationFailedError}

    -
    -
    -
    -

    Parameters

    -
      -
    • -
      id: string
      -
      -

      string the user id

      -
      -
    • -
    • -
      userGroupId: string
      -
      -

      string the user group id

      -
      -
    • -
    -

    Returns Promise<void>

    -
  • -
-
-
- -

disableUser

-
    -
  • disableUser(id: string): Promise<void>
  • -
-
    -
  • - -
    -
    -

    disables the user

    -
    -
    -
    throws
    -

    {UserNotFoundError}

    -
    -
    -
    -

    Parameters

    -
      -
    • -
      id: string
      -
      -

      string the user id

      -
      -
    • -
    -

    Returns Promise<void>

    -
  • -
-
-
- -

enableUser

-
    -
  • enableUser(id: string): Promise<void>
  • -
-
    -
  • - -
    -
    -

    enables the user

    -
    -
    -
    throws
    -

    {UserNotFoundError}

    -
    -
    -
    -

    Parameters

    -
      -
    • -
      id: string
      -
      -

      string the user id

      -
      -
    • -
    -

    Returns Promise<void>

    -
  • -
-
-
- -

getAppInfos

-
    -
  • getAppInfos(appName: string): Promise<object>
  • -
-
    -
  • - -

    Parameters

    -
      -
    • -
      appName: string
      -
    • -
    -

    Returns Promise<object>

    -
  • -
-
-
- -

getApps

-
    -
  • getApps(): Promise<string[]>
  • -
-
    -
  • - -
    -
    -

    returns apps

    -
    -
    -

    Returns Promise<string[]>

    -
  • -
-
-
- -

getContent

-
    -
  • getContent(fileName: string): Promise<Buffer>
  • -
-
    -
  • - -
    -
    -

    returns the content of a file

    -
    -
    -

    Parameters

    -
      -
    • -
      fileName: string
      -
      -

      name of the file /d1/file1.txt

      -
      -
    • -
    -

    Returns Promise<Buffer>

    -

    Buffer with file content

    -
  • -
-
-
- -

getFile

-
    -
  • getFile(fileName: string): Promise<File | null>
  • -
-
    -
  • - -
    -
    -

    returns a nextcloud file object

    -
    -
    -

    Parameters

    -
      -
    • -
      fileName: string
      -
      -

      the full file name /folder1/folder2/file.pdf

      -
      -
    • -
    -

    Returns Promise<File | null>

    -
  • -
-
-
- -

getFileComments

-
    -
  • getFileComments(fileId: number, top?: undefined | number, skip?: undefined | number): Promise<string[]>
  • -
-
    -
  • - -
    -
    -

    returns comments of a file / folder

    -
    -
    -
    throws
    -

    Exception

    -
    -
    -
    -

    Parameters

    -
      -
    • -
      fileId: number
      -
      -

      the id of the file / folder

      -
      -
    • -
    • -
      Optional top: undefined | number
      -
      -

      number of comments to return

      -
      -
    • -
    • -
      Optional skip: undefined | number
      -
      -

      the offset

      -
      -
    • -
    -

    Returns Promise<string[]>

    -

    array of comment strings

    -
  • -
-
-
- -

getFileId

-
    -
  • getFileId(fileUrl: string): Promise<number>
  • -
-
    -
  • - -
    -
    -

    returns the id of the file or -1 of not found

    -
    -
    -

    Parameters

    -
      -
    • -
      fileUrl: string
      -
    • -
    -

    Returns Promise<number>

    -

    id of the file or -1 if not found

    -
  • -
-
-
- -

getFileSystemElementByTags

- -
    -
  • - -
    -
    -

    returns an array of file system objects that have all given tags assigned (AND)

    -
    -
    -
    async
    -
    -
    -
    -

    Parameters

    -
      -
    • -
      tags: Tag[]
      -
      -

      array of tags

      -
      -
    • -
    -

    Returns Promise<FileSystemElement[]>

    -

    returns an array of file system objects

    -
  • -
-
-
- -

getFiles

- -
    -
  • - -
    -
    -

    get files of a folder

    -
    -
    -

    Parameters

    -
      -
    • -
      folderName: string
      -
      -

      Name of the folder like "/company/branches/germany"

      -
      -
    • -
    • -
      Optional options: FolderGetFilesOptions
      -
      -

      options for filtering and paging

      -
      -
    • -
    -

    Returns Promise<File[]>

    -

    array of file objects

    -
  • -
-
-
- -

getFolder

-
    -
  • getFolder(folderName: string): Promise<Folder | null>
  • -
-
    -
  • - -
    -
    -

    get a folder object from a path string

    -
    -
    -

    Parameters

    -
      -
    • -
      folderName: string
      -
      -

      Name of the folder like "/company/branches/germany"

      -
      -
    • -
    -

    Returns Promise<Folder | null>

    -

    null if the folder does not exist or an folder object

    -
  • -
-
-
- -

getFolderContents

-
    -
  • getFolderContents(folderName: string): Promise<any[]>
  • -
-
    -
  • - -

    Parameters

    -
      -
    • -
      folderName: string
      -
    • -
    -

    Returns Promise<any[]>

    -
  • -
-
-
- -

getLink

-
    -
  • getLink(fileName: string): string
  • -
-
    -
  • - -
    -
    -

    returns the link to a file for downloading

    -
    -
    -

    Parameters

    -
      -
    • -
      fileName: string
      -
      -

      name of the file /folder1/folder1.txt

      -
      -
    • -
    -

    Returns string

    -

    url

    -
  • -
-
-
- -

getNotifications

-
    -
  • getNotifications(): Promise<object[]>
  • -
-
    -
  • - -
    -
    -

    Returns Promise<object[]>

    -

    array of notification objects

    -
  • -
-
-
- -

getQuota

-
    -
  • getQuota(): Promise<IQuota>
  • -
-
    -
  • - -
    -
    -

    returns the used and free quota of the nextcloud account

    -
    -
    -

    Returns Promise<IQuota>

    -
  • -
-
-
- -

getRootFolder

- -
    -
  • - -
    -
    -

    get the root folder object

    -
    -
    -

    Returns Folder

    -

    the root folder

    -
  • -
-
-
- -

getShare

-
    -
  • getShare(shareId: string): Promise<any>
  • -
-
    -
  • - -
    -
    -

    get share information

    -
    -
    -

    Parameters

    -
      -
    • -
      shareId: string
      -
      -
      -
    • -
    -

    Returns Promise<any>

    -
  • -
-
-
- -

getSubFolders

-
    -
  • getSubFolders(folderName: string): Promise<Folder[]>
  • -
-
    -
  • - -
    -
    -

    get a array of folders from a folder path string

    -
    -
    -

    Parameters

    -
      -
    • -
      folderName: string
      -
      -

      Name of the folder like "/company/branches/germany"

      -
      -
    • -
    -

    Returns Promise<Folder[]>

    -

    array of folder objects

    -
  • -
-
-
- -

getSystemBasicData

- - -
-
- -

getSystemInfo

- -
    -
  • - -
    -
    -

    returns system information about the nextcloud server and the nextcloud client

    -
    -
    -

    Returns Promise<ISystemInfo>

    -
  • -
-
-
- -

getTagById

-
    -
  • getTagById(tagId: number): Promise<Tag | null>
  • -
-
    -
  • - -
    -
    -

    returns a tag identified by the id or null if not found

    -
    -
    -

    Parameters

    -
      -
    • -
      tagId: number
      -
      -

      the id of the tag

      -
      -
    • -
    -

    Returns Promise<Tag | null>

    -

    tag or null

    -
  • -
-
-
- -

getTagByName

-
    -
  • getTagByName(tagName: string): Promise<Tag | null>
  • -
-
    -
  • - -
    -
    -

    returns a tag identified by the name or null if not found

    -
    -
    -

    Parameters

    -
      -
    • -
      tagName: string
      -
      -

      the name of the tag

      -
      -
    • -
    -

    Returns Promise<Tag | null>

    -

    tag or null

    -
  • -
-
-
- -

getTags

-
    -
  • getTags(): Promise<Tag[]>
  • -
-
    -
  • - -
    -
    -

    returns a list of tags

    -
    -
    -

    Returns Promise<Tag[]>

    -

    array of tags

    -
  • -
-
-
- -

getTagsOfFile

-
    -
  • getTagsOfFile(fileId: number): Promise<Map<string, number>>
  • -
-
    -
  • - -
    -
    -

    returns the list of tag names and the tag ids

    -
    -
    -

    Parameters

    -
      -
    • -
      fileId: number
      -
      -

      the id of the file

      -
      -
    • -
    -

    Returns Promise<Map<string, number>>

    -
  • -
-
-
- -

getUILink

-
    -
  • getUILink(fileId: number): string
  • -
-
    -
  • - -
    -
    -

    returns the url to the file in the nextcloud UI

    -
    -
    -

    Parameters

    -
      -
    • -
      fileId: number
      -
      -

      the id of the file

      -
      -
    • -
    -

    Returns string

    -
  • -
-
-
- -

getUpdateNotifications

-
    -
  • getUpdateNotifications(version: string): Promise<object>
  • -
-
    -
  • - -

    Parameters

    -
      -
    • -
      version: string
      -
    • -
    -

    Returns Promise<object>

    -
  • -
-
-
- -

getUser

-
    -
  • getUser(id: string): Promise<User | null>
  • -
-
    -
  • - -
    -
    -

    returns a user or null if not found

    -
    -
    -

    Parameters

    -
      -
    • -
      id: string
      -
      -

      string

      -
      -
    • -
    -

    Returns Promise<User | null>

    -

    User | null

    -
  • -
-
-
- -

getUserData

- -
    -
  • - -
    -
    -

    returns user data

    -
    -
    -
    throws
    -

    {UserNotFoundError}

    -
    -
    -
    -

    Parameters

    -
      -
    • -
      id: string
      -
      -

      string the user id

      -
      -
    • -
    -

    Returns Promise<IUserOptions>

    -

    Promise user data

    -
  • -
-
-
- -

getUserGroup

-
    -
  • getUserGroup(id: string): Promise<UserGroup | null>
  • -
-
    -
  • - -
    -
    -

    get user group

    -
    -
    -

    Parameters

    -
      -
    • -
      id: string
      -
      -

      string

      -
      -
    • -
    -

    Returns Promise<UserGroup | null>

    -

    Promise<UserGroup|null>

    -
  • -
-
-
- -

getUserGroupIds

-
    -
  • getUserGroupIds(search?: undefined | string, limit?: undefined | number, offset?: undefined | number): Promise<string[]>
  • -
-
    -
  • - -
    -
    -

    returns a list of user groups

    -
    -
    -
    throws
    -

    QueryLimitError

    -
    -
    throws
    -

    QueryOffsetError

    -
    -
    -
    -

    Parameters

    -
      -
    • -
      Optional search: undefined | string
      -
      -

      string

      -
      -
    • -
    • -
      Optional limit: undefined | number
      -
      -

      number

      -
      -
    • -
    • -
      Optional offset: undefined | number
      -
      -

      number

      -
      -
    • -
    -

    Returns Promise<string[]>

    -

    list of user groups

    -
  • -
-
-
- -

getUserGroupMembers

-
    -
  • getUserGroupMembers(id: string): Promise<string[]>
  • -
-
    -
  • - -
    -
    -

    returns a list of user ids that are members of the user group

    -
    -
    -
    throws
    -

    [UserGroupDoesNotExistError}

    -
    -
    -
    -

    Parameters

    -
      -
    • -
      id: string
      -
      -

      string

      -
      -
    • -
    -

    Returns Promise<string[]>

    -

    list of member user ids

    -
  • -
-
-
- -

getUserGroupSubadmins

-
    -
  • getUserGroupSubadmins(id: string): Promise<string[]>
  • -
-
    -
  • - -
    -
    -

    returns a list of user ids that are subadmins of the user group

    -
    -
    -
    throws
    -

    [UserGroupDoesNotExistError}

    -
    -
    -
    -

    Parameters

    -
      -
    • -
      id: string
      -
      -

      string

      -
      -
    • -
    -

    Returns Promise<string[]>

    -

    list of subadmin user ids

    -
  • -
-
-
- -

getUserGroups

-
    -
  • getUserGroups(search?: undefined | string, limit?: undefined | number, offset?: undefined | number): Promise<UserGroup[]>
  • -
-
    -
  • - -
    -
    -

    returns a list of user groups

    -
    -
    -
    throws
    -

    QueryLimitError

    -
    -
    throws
    -

    QueryOffsetError

    -
    -
    -
    -

    Parameters

    -
      -
    • -
      Optional search: undefined | string
      -
      -

      string

      -
      -
    • -
    • -
      Optional limit: undefined | number
      -
      -

      number

      -
      -
    • -
    • -
      Optional offset: undefined | number
      -
      -

      number

      -
      -
    • -
    -

    Returns Promise<UserGroup[]>

    -

    list of user groups

    -
  • -
-
-
- -

getUsers

-
    -
  • getUsers(search?: undefined | string, limit?: undefined | number, offset?: undefined | number): Promise<User[]>
  • -
- -
-
- -

moveFile

-
    -
  • moveFile(sourceFileName: string, targetFileName: string): Promise<File>
  • -
-
    -
  • - -
    -
    -

    renames the file or moves it to an other location

    -
    -
    -

    Parameters

    -
      -
    • -
      sourceFileName: string
      -
      -

      source file name

      -
      -
    • -
    • -
      targetFileName: string
      -
      -

      target file name

      -
      -
    • -
    -

    Returns Promise<File>

    -
  • -
-
-
- -

moveFolder

-
    -
  • moveFolder(sourceFolderName: string, tarName: string): Promise<Folder>
  • -
-
    -
  • - -
    -
    -

    renames the folder or moves it to an other location

    -
    -
    -

    Parameters

    -
      -
    • -
      sourceFolderName: string
      -
      -

      source folder name

      -
      -
    • -
    • -
      tarName: string
      -
      -

      target folder name

      -
      -
    • -
    -

    Returns Promise<Folder>

    -
  • -
-
-
- -

pipeContentStream

-
    -
  • pipeContentStream(fileName: string, destination: WritableStream): Promise<void>
  • -
-
    -
  • - -
    -
    -

    returns the content of a file

    -
    -
    -

    Parameters

    -
      -
    • -
      fileName: string
      -
      -

      name of the file /d1/file1.txt

      -
      -
    • -
    • -
      destination: WritableStream
      -
    • -
    -

    Returns Promise<void>

    -

    Buffer with file content

    -
  • -
-
-
- -

promoteUserToUserGroupSubadmin

-
    -
  • promoteUserToUserGroupSubadmin(id: string, userGroupId: string): Promise<void>
  • -
-
    -
  • - -
    -
    -

    promotes a user to a user group subadmin

    -
    -
    -
    throws
    -

    {UserNotFoundError}

    -
    -
    throws
    -

    {UserGroupDoesNotExistError}

    -
    -
    throws
    -

    {InsufficientPrivilegesError}

    -
    -
    throws
    -

    {OperationFailedError}

    -
    -
    -
    -

    Parameters

    -
      -
    • -
      id: string
      -
      -

      string the user id

      -
      -
    • -
    • -
      userGroupId: string
      -
      -

      string the user group id

      -
      -
    • -
    -

    Returns Promise<void>

    -
  • -
-
-
- -

removeTagOfFile

-
    -
  • removeTagOfFile(fileId: number, tagId: number): Promise<void>
  • -
-
    -
  • - -
    -
    -

    removes the tag from the file

    -
    -
    -

    Parameters

    -
      -
    • -
      fileId: number
      -
      -

      the file id

      -
      -
    • -
    • -
      tagId: number
      -
      -

      the tag id

      -
      -
    • -
    -

    Returns Promise<void>

    -
  • -
-
-
- -

removeUserFromMemberUserGroup

-
    -
  • removeUserFromMemberUserGroup(id: string, userGroupId: string): Promise<void>
  • -
-
    -
  • - -
    -
    -

    removes a user from a group as member

    -
    -
    -
    throws
    -

    {UserNotFoundError}

    -
    -
    throws
    -

    {UserGroupDoesNotExistError}

    -
    -
    throws
    -

    {InsufficientPrivilegesError}

    -
    -
    throws
    -

    {OperationFailedError}

    -
    -
    -
    -

    Parameters

    -
      -
    • -
      id: string
      -
      -

      string the user id

      -
      -
    • -
    • -
      userGroupId: string
      -
      -

      string the user group id

      -
      -
    • -
    -

    Returns Promise<void>

    -
  • -
-
-
- -

resendWelcomeEmail

-
    -
  • resendWelcomeEmail(id: string): Promise<void>
  • -
-
    -
  • - -
    -
    -

    resend the welcome email

    -
    -
    -
    throws
    -

    {UserResendWelcomeEmailError}

    -
    -
    -
    -

    Parameters

    -
      -
    • -
      id: string
      -
      -

      user id

      -
      -
    • -
    -

    Returns Promise<void>

    -
  • -
-
-
- -

sendNotificationToUser

-
    -
  • sendNotificationToUser(userId: string, shortMessage: string, longMessage?: undefined | string): Promise<void>
  • -
-
    -
  • - -

    Parameters

    -
      -
    • -
      userId: string
      -
    • -
    • -
      shortMessage: string
      -
    • -
    • -
      Optional longMessage: undefined | string
      -
    • -
    -

    Returns Promise<void>

    -
  • -
-
-
- -

updateShare

-
    -
  • updateShare(shareId: string, body: { password: string } | { expireDate: string } | { note: string }): Promise<void>
  • -
-
    -
  • - -
    -
    -

    update a new share

    -
    -
    -

    Parameters

    -
      -
    • -
      shareId: string
      -
    • -
    • -
      body: { password: string } | { expireDate: string } | { note: string }
      -
    • -
    -

    Returns Promise<void>

    -
  • -
-
-
- -

updateUserProperty

-
    -
  • updateUserProperty(id: string, property: UserProperty, value: string): Promise<void>
  • -
-
    -
  • - -
    -
    -

    updates a user property

    -
    -
    -
    async
    -
    -
    throws
    -

    {UserNotFoundError}

    -
    -
    throws
    -

    {UserUpdateError}

    -
    -
    -
    -

    Parameters

    -
      -
    • -
      id: string
      -
      -

      user id

      -
      -
    • -
    • -
      property: UserProperty
      -
      -

      property name

      -
      -
    • -
    • -
      value: string
      -
      -

      property value

      -
      -
    • -
    -

    Returns Promise<void>

    -
  • -
-
-
- -

upsertUsers

- - -
-
-
- -
-
-
-
-

Legend

-
-
    -
  • Constructor
  • -
  • Property
  • -
  • Method
  • -
-
    -
  • Inherited constructor
  • -
  • Inherited property
  • -
  • Inherited method
  • -
-
    -
  • Protected property
  • -
  • Protected method
  • -
-
    -
  • Static property
  • -
  • Static method
  • -
-
    -
  • Property
  • -
-
-
-
-
-

Generated using TypeDoc

-
-
- - - \ No newline at end of file diff --git a/docs/api/classes/clienterror.html b/docs/api/classes/clienterror.html deleted file mode 100644 index ea00f9f5..00000000 --- a/docs/api/classes/clienterror.html +++ /dev/null @@ -1,266 +0,0 @@ - - - - - - ClientError | nextcloud-node-client - - - - - -
-
-
-
- -
-
- Options -
-
- All -
    -
  • Public
  • -
  • Public/Protected
  • -
  • All
  • -
-
- - -
-
- Menu -
-
-
-
-
-
- -

Class ClientError

-
-
-
-
-
-
-
-

Hierarchy

-
    -
  • - Error -
      -
    • - ClientError -
    • -
    -
  • -
-
-
-

Index

-
-
-
-

Constructors

- -
-
-

Properties

- -
-
-
-
-
-

Constructors

-
- -

constructor

-
    -
  • new ClientError(m: string, code: string, context?: any): ClientError
  • -
-
    -
  • - -

    Parameters

    -
      -
    • -
      m: string
      -
    • -
    • -
      code: string
      -
    • -
    • -
      Optional context: any
      -
    • -
    -

    Returns ClientError

    -
  • -
-
-
-
-

Properties

-
- -

code

-
code: string
- -
-
- -

message

-
message: string
- -
-
- -

name

-
name: string
- -
-
- -

Optional stack

-
stack: undefined | string
- -
-
- -

Static Error

-
Error: ErrorConstructor
- -
-
-
- -
-
-
-
-

Legend

-
-
    -
  • Constructor
  • -
  • Property
  • -
  • Method
  • -
-
    -
  • Inherited constructor
  • -
  • Inherited property
  • -
  • Inherited method
  • -
-
    -
  • Protected property
  • -
  • Protected method
  • -
-
    -
  • Static property
  • -
  • Static method
  • -
-
    -
  • Property
  • -
-
-
-
-
-

Generated using TypeDoc

-
-
- - - \ No newline at end of file diff --git a/docs/api/classes/command.html b/docs/api/classes/command.html deleted file mode 100644 index 99f1c19c..00000000 --- a/docs/api/classes/command.html +++ /dev/null @@ -1,438 +0,0 @@ - - - - - - Command | nextcloud-node-client - - - - - -
-
-
-
- -
-
- Options -
-
- All -
    -
  • Public
  • -
  • Public/Protected
  • -
  • All
  • -
-
- - -
-
- Menu -
-
-
-
-
-
- -

Class Command

-
-
-
-
-
-
-
-
-
-

The command class represents a potential long running activity. - This activity has been wrapped into an object to ease the tracking of the processing state. - Create a command with receiver information, execute the command and check the status and progress. - Check the result when finsished.

-
-
-
-
-

Hierarchy

- -
-
-

Index

-
-
-
-

Constructors

- -
-
-

Properties

- -
-
-

Methods

- -
-
-
-
-
-

Constructors

-
- -

constructor

- - -
-
-
-

Properties

-
- -

Protected client

-
client: Client
- -
-
- -

Protected percentCompleted

-
percentCompleted: number
- -
-
- -

Protected resultMetaData

-
resultMetaData: CommandResultMetaData
- -
-
- -

Protected status

- - -
-
-
-

Methods

-
- -

execute

-
    -
  • execute(): Promise<void>
  • -
-
    -
  • - -
    -
    -

    final execute the command

    -
    -
    -
    async
    -
    -
    final
    -
    -
    -
    -

    Returns Promise<void>

    -
  • -
-
-
- -

getPercentCompleted

-
    -
  • getPercentCompleted(): number
  • -
-
    -
  • - -
    -
    -

    returns the completion percentage of the command

    -
    -
    -

    Returns number

    -

    percentage of completion

    -
  • -
-
-
- -

getResultMetaData

- - -
-
- -

getStatus

- - -
-
- -

isFinished

-
    -
  • isFinished(): boolean
  • -
-
    -
  • - -
    -
    -

    returns true, if the command has been finished

    -
    -
    -

    Returns boolean

    -
  • -
-
-
- -

Protected Abstract onExecute

-
    -
  • onExecute(): Promise<void>
  • -
- -
-
-
- -
-
-
-
-

Legend

-
-
    -
  • Constructor
  • -
  • Property
  • -
  • Method
  • -
-
    -
  • Inherited constructor
  • -
  • Inherited property
  • -
  • Inherited method
  • -
-
    -
  • Protected property
  • -
  • Protected method
  • -
-
    -
  • Static property
  • -
  • Static method
  • -
-
    -
  • Property
  • -
-
-
-
-
-

Generated using TypeDoc

-
-
- - - \ No newline at end of file diff --git a/docs/api/classes/commandalreadyexecutederror.html b/docs/api/classes/commandalreadyexecutederror.html deleted file mode 100644 index 53f72fe4..00000000 --- a/docs/api/classes/commandalreadyexecutederror.html +++ /dev/null @@ -1,243 +0,0 @@ - - - - - - CommandAlreadyExecutedError | nextcloud-node-client - - - - - -
-
-
-
- -
-
- Options -
-
- All -
    -
  • Public
  • -
  • Public/Protected
  • -
  • All
  • -
-
- - -
-
- Menu -
-
-
-
-
-
- -

Class CommandAlreadyExecutedError

-
-
-
-
-
-
-
-
-
-

the command is already executed

-
-
-
-
-

Hierarchy

-
    -
  • - BaseError -
      -
    • - CommandAlreadyExecutedError -
    • -
    -
  • -
-
-
-

Index

-
-
-
-

Constructors

- -
-
-

Properties

- -
-
-
-
-
-

Constructors

-
- -

constructor

- - -
-
-
-

Properties

-
- -

message

-
message: string
- -
-
- -

name

-
name: string
- -
-
- -

Optional stack

-
stack: undefined | string
- -
-
-
- -
-
-
-
-

Legend

-
-
    -
  • Constructor
  • -
  • Property
  • -
  • Method
  • -
-
    -
  • Inherited constructor
  • -
  • Inherited property
  • -
  • Inherited method
  • -
-
    -
  • Protected property
  • -
  • Protected method
  • -
-
    -
  • Static property
  • -
  • Static method
  • -
-
    -
  • Property
  • -
-
-
-
-
-

Generated using TypeDoc

-
-
- - - \ No newline at end of file diff --git a/docs/api/classes/downloadfoldercommand.html b/docs/api/classes/downloadfoldercommand.html deleted file mode 100644 index c4cca1e6..00000000 --- a/docs/api/classes/downloadfoldercommand.html +++ /dev/null @@ -1,473 +0,0 @@ - - - - - - DownloadFolderCommand | nextcloud-node-client - - - - - -
-
-
-
- -
-
- Options -
-
- All -
    -
  • Public
  • -
  • Public/Protected
  • -
  • All
  • -
-
- - -
-
- Menu -
-
-
-
-
-
- -

Class DownloadFolderCommand

-
-
-
-
-
-
-
-
-
-

Command to download the contents of a folder from nextcloud to local file system recursively

-
-
-
-
-

Hierarchy

-
    -
  • - Command -
      -
    • - DownloadFolderCommand -
    • -
    -
  • -
-
-
-

Index

-
-
-
-

Constructors

- -
-
-

Properties

- -
-
-

Methods

- -
-
-
-
-
-

Constructors

-
- -

constructor

- - -
-
-
-

Properties

-
- -

Protected client

-
client: Client
- -
-
- -

Protected percentCompleted

-
percentCompleted: number
- -
-
- -

Protected resultMetaData

-
resultMetaData: CommandResultMetaData
- -
-
- -

Protected status

- - -
-
-
-

Methods

-
- -

execute

-
    -
  • execute(): Promise<void>
  • -
- -
-
- -

getBytesDownloaded

-
    -
  • getBytesDownloaded(): number
  • -
- -
-
- -

getPercentCompleted

-
    -
  • getPercentCompleted(): number
  • -
- -
-
- -

getResultMetaData

- - -
-
- -

getStatus

- - -
-
- -

isFinished

-
    -
  • isFinished(): boolean
  • -
- -
-
- -

Protected onExecute

-
    -
  • onExecute(): Promise<void>
  • -
- -
-
-
- -
-
-
-
-

Legend

-
-
    -
  • Constructor
  • -
  • Property
  • -
  • Method
  • -
-
    -
  • Inherited constructor
  • -
  • Inherited property
  • -
  • Inherited method
  • -
-
    -
  • Protected property
  • -
  • Protected method
  • -
-
    -
  • Static property
  • -
  • Static method
  • -
-
    -
  • Property
  • -
-
-
-
-
-

Generated using TypeDoc

-
-
- - - \ No newline at end of file diff --git a/docs/api/classes/environment.html b/docs/api/classes/environment.html deleted file mode 100644 index 4ea1dd7f..00000000 --- a/docs/api/classes/environment.html +++ /dev/null @@ -1,252 +0,0 @@ - - - - - - Environment | nextcloud-node-client - - - - - -
-
-
-
- -
-
- Options -
-
- All -
    -
  • Public
  • -
  • Public/Protected
  • -
  • All
  • -
-
- - -
-
- Menu -
-
-
-
-
-
- -

Class Environment

-
-
-
-
-
-
-
-

Hierarchy

-
    -
  • - Environment -
  • -
-
-
-

Index

-
- -
-
-
-

Methods

-
- -

Static getMinLogLevel

-
    -
  • getMinLogLevel(): string
  • -
- -
-
- -

Static getNextcloudUrl

-
    -
  • getNextcloudUrl(): string
  • -
- -
-
- -

Static getPassword

-
    -
  • getPassword(): string
  • -
- -
-
- -

Static getRecordingActiveIndicator

-
    -
  • getRecordingActiveIndicator(): boolean
  • -
- -
-
- -

Static getUserName

-
    -
  • getUserName(): string
  • -
- -
-
-
- -
-
-
-
-

Legend

-
-
    -
  • Constructor
  • -
  • Property
  • -
  • Method
  • -
-
    -
  • Inherited constructor
  • -
  • Inherited property
  • -
  • Inherited method
  • -
-
    -
  • Protected property
  • -
  • Protected method
  • -
-
    -
  • Static property
  • -
  • Static method
  • -
-
    -
  • Property
  • -
-
-
-
-
-

Generated using TypeDoc

-
-
- - - \ No newline at end of file diff --git a/docs/api/classes/environmentvcapservices.html b/docs/api/classes/environmentvcapservices.html deleted file mode 100644 index 8c79e848..00000000 --- a/docs/api/classes/environmentvcapservices.html +++ /dev/null @@ -1,269 +0,0 @@ - - - - - - EnvironmentVcapServices | nextcloud-node-client - - - - - -
-
-
-
- -
-
- Options -
-
- All -
    -
  • Public
  • -
  • Public/Protected
  • -
  • All
  • -
-
- - -
-
- Menu -
-
-
-
-
-
- -

Class EnvironmentVcapServices

-
-
-
-
-
-
-
-
-
-

returns the nextcloud credentials that is defined in the - "user-provided" service section of the VCAP_SERVICES environment - instanceName: the name of the nextcloud user provided service instance

-
-
-
-
-

Hierarchy

-
    -
  • - EnvironmentVcapServices -
  • -
-
-
-

Index

-
-
-
-

Constructors

- -
-
-

Properties

- -
-
-

Methods

- -
-
-
-
-
-

Constructors

-
- -

constructor

- - -
-
-
-

Properties

-
- -

Readonly password

-
password: string
- -
-
- -

Readonly url

-
url: string
- -
-
- -

Readonly userName

-
userName: string
- -
-
-
-

Methods

-
- -

getServer

- -
    -
  • - -
    -
    -

    returns the nextcloud credentials that is defined in the - "user-provided" service section of the VCAP_SERVICES environment

    -
    -
    -

    Returns Server

    -

    credentials from the VCAP_SERVICES environment (user provided service)

    -
  • -
-
-
-
- -
-
-
-
-

Legend

-
-
    -
  • Constructor
  • -
  • Property
  • -
  • Method
  • -
-
    -
  • Inherited constructor
  • -
  • Inherited property
  • -
  • Inherited method
  • -
-
    -
  • Protected property
  • -
  • Protected method
  • -
-
    -
  • Static property
  • -
  • Static method
  • -
-
    -
  • Property
  • -
-
-
-
-
-

Generated using TypeDoc

-
-
- - - \ No newline at end of file diff --git a/docs/api/classes/fakeserver.html b/docs/api/classes/fakeserver.html deleted file mode 100644 index bf185d1d..00000000 --- a/docs/api/classes/fakeserver.html +++ /dev/null @@ -1,240 +0,0 @@ - - - - - - FakeServer | nextcloud-node-client - - - - - -
-
-
-
- -
-
- Options -
-
- All -
    -
  • Public
  • -
  • Public/Protected
  • -
  • All
  • -
-
- - -
-
- Menu -
-
-
-
-
-
- -

Class FakeServer

-
-
-
-
-
-
-
-

Hierarchy

-
    -
  • - FakeServer -
  • -
-
-
-

Index

-
-
-
-

Constructors

- -
-
-

Properties

- -
-
-

Methods

- -
-
-
-
-
-

Constructors

-
- -

constructor

- - -
-
-
-

Properties

-
- -

fakeResponses

-
fakeResponses: RequestResponseLogEntry[] = []
- -
-
-
-

Methods

-
- -

getFakeHttpResponse

-
    -
  • getFakeHttpResponse(url: string, requestInit: RequestInit, expectedHttpStatusCode: number[], context: IRequestContext): Promise<Response>
  • -
-
    -
  • - -

    Parameters

    -
      -
    • -
      url: string
      -
    • -
    • -
      requestInit: RequestInit
      -
    • -
    • -
      expectedHttpStatusCode: number[]
      -
    • -
    • -
      context: IRequestContext
      -
    • -
    -

    Returns Promise<Response>

    -
  • -
-
-
-
- -
-
-
-
-

Legend

-
-
    -
  • Constructor
  • -
  • Property
  • -
  • Method
  • -
-
    -
  • Inherited constructor
  • -
  • Inherited property
  • -
  • Inherited method
  • -
-
    -
  • Protected property
  • -
  • Protected method
  • -
-
    -
  • Static property
  • -
  • Static method
  • -
-
    -
  • Property
  • -
-
-
-
-
-

Generated using TypeDoc

-
-
- - - \ No newline at end of file diff --git a/docs/api/classes/file.html b/docs/api/classes/file.html deleted file mode 100644 index ba92c73c..00000000 --- a/docs/api/classes/file.html +++ /dev/null @@ -1,752 +0,0 @@ - - - - - - File | nextcloud-node-client - - - - - -
-
-
-
- -
-
- Options -
-
- All -
    -
  • Public
  • -
  • Public/Protected
  • -
  • All
  • -
-
- - -
-
- Menu -
-
-
-
-
-
- -

Class File

-
-
-
-
-
-
-
-
-
-

The file class represents a file in nextcloud. - It exposes file properties and content handling, commenting and tagging

-
-
-
-
-

Hierarchy

-
    -
  • - File -
  • -
-
-
-

Implements

- -
-
-

Index

-
-
-
-

Constructors

- -
-
-

Accessors

- -
-
-

Methods

- -
-
-
-
-
-

Constructors

-
- -

constructor

-
    -
  • new File(client: Client, name: string, baseName: string, lastmod: string, size: number, mime: string, id: number): File
  • -
-
    -
  • - -

    Parameters

    -
      -
    • -
      client: Client
      -
    • -
    • -
      name: string
      -
    • -
    • -
      baseName: string
      -
    • -
    • -
      lastmod: string
      -
    • -
    • -
      size: number
      -
    • -
    • -
      mime: string
      -
    • -
    • -
      id: number
      -
    • -
    -

    Returns File

    -
  • -
-
-
-
-

Accessors

-
- -

baseName

-
    -
  • get baseName(): string
  • -
-
    -
  • - -
    -
    -

    The base name of the file (file name without path) - The base name is readonly

    -
    -
    -

    Returns string

    -
  • -
-
-
- -

id

-
    -
  • get id(): number
  • -
-
    -
  • - -
    -
    -

    The unique id of the file.

    -
    -
    -

    Returns number

    -
  • -
-
-
- -

lastmod

-
    -
  • get lastmod(): Date
  • -
-
    -
  • - -
    -
    -

    The timestamp of the last file change - readonly

    -
    -
    -

    Returns Date

    -
  • -
-
-
- -

mime

-
    -
  • get mime(): string
  • -
-
    -
  • - -
    -
    -

    The mime type (content type) of the file

    -
    -
    -

    Returns string

    -
  • -
-
-
- -

name

-
    -
  • get name(): string
  • -
-
    -
  • - -
    -
    -

    The name of the file including the path - The name is readonly

    -
    -
    -

    Returns string

    -
  • -
-
-
- -

size

-
    -
  • get size(): number
  • -
-
    -
  • - -
    -
    -

    The file size in bytes - readonly

    -
    -
    -

    Returns number

    -
  • -
-
-
-
-

Methods

-
- -

addComment

-
    -
  • addComment(comment: string): Promise<void>
  • -
-
    -
  • - -
    -
    -

    add comment to file

    -
    -
    -

    Parameters

    -
      -
    • -
      comment: string
      -
      -

      the comment

      -
      -
    • -
    -

    Returns Promise<void>

    -
  • -
-
-
- -

addTag

-
    -
  • addTag(tagName: string): Promise<void>
  • -
-
    -
  • - -
    -
    -

    adds a tag name to the file

    -
    -
    -

    Parameters

    -
      -
    • -
      tagName: string
      -
      -

      name of the tag

      -
      -
    • -
    -

    Returns Promise<void>

    -
  • -
-
-
- -

delete

-
    -
  • delete(): Promise<void>
  • -
-
    -
  • - -
    -
    -

    deletes a file

    -
    -
    -
    throws
    -

    Error

    -
    -
    -
    -

    Returns Promise<void>

    -
  • -
-
-
- -

getComments

-
    -
  • getComments(top?: undefined | number, skip?: undefined | number): Promise<string[]>
  • -
-
    -
  • - -
    -
    -

    get list of comments of file

    -
    -
    -
    throws
    -

    Exception

    -
    -
    -
    -

    Parameters

    -
      -
    • -
      Optional top: undefined | number
      -
      -

      number of comments to return

      -
      -
    • -
    • -
      Optional skip: undefined | number
      -
      -

      the offset

      -
      -
    • -
    -

    Returns Promise<string[]>

    -

    array of comment strings

    -
  • -
-
-
- -

getContent

-
    -
  • getContent(): Promise<Buffer>
  • -
-
    -
  • - -
    -
    -
    throws
    -

    Error

    -
    -
    -
    -

    Returns Promise<Buffer>

    -

    the buffer of the file content

    -
  • -
-
-
- -

getFolder

-
    -
  • getFolder(): Promise<Folder>
  • -
-
    -
  • - -
    -
    -

    get folder of the file

    -
    -
    -
    throws
    -

    ClientError

    -
    -
    -
    -

    Returns Promise<Folder>

    -

    the parent folder

    -
  • -
-
-
- -

getTags

-
    -
  • getTags(): Promise<string[]>
  • -
-
    -
  • - -
    -
    -

    get tag names

    -
    -
    -

    Returns Promise<string[]>

    -

    array of tag names

    -
  • -
-
-
- -

getUIUrl

-
    -
  • getUIUrl(): string
  • -
-
    -
  • - -
    -
    -
    throws
    -

    Error

    -
    -
    -
    -

    Returns string

    -

    the url of the file in the UI

    -
  • -
-
-
- -

getUrl

-
    -
  • getUrl(): string
  • -
-
    -
  • - -
    -
    -
    throws
    -

    Error

    -
    -
    -
    -

    Returns string

    -

    the url of the file

    -
  • -
-
-
- -

move

-
    -
  • move(targetFileName: string): Promise<File>
  • -
-
    -
  • - -
    -
    -

    moves or renames the current file to the new location - target folder must exists

    -
    -
    -
    throws
    -

    Error

    -
    -
    -
    -

    Parameters

    -
      -
    • -
      targetFileName: string
      -
      -

      the name of the target file /f1/f2/myfile.txt

      -
      -
    • -
    -

    Returns Promise<File>

    -
  • -
-
-
- -

removeTag

-
    -
  • removeTag(tagName: string): Promise<void>
  • -
-
    -
  • - -
    -
    -

    removes a tag of the file

    -
    -
    -

    Parameters

    -
      -
    • -
      tagName: string
      -
      -

      the name of the tag

      -
      -
    • -
    -

    Returns Promise<void>

    -
  • -
-
-
-
- -
-
-
-
-

Legend

-
-
    -
  • Constructor
  • -
  • Property
  • -
  • Method
  • -
-
    -
  • Inherited constructor
  • -
  • Inherited property
  • -
  • Inherited method
  • -
-
    -
  • Protected property
  • -
  • Protected method
  • -
-
    -
  • Static property
  • -
  • Static method
  • -
-
    -
  • Property
  • -
-
-
-
-
-

Generated using TypeDoc

-
-
- - - \ No newline at end of file diff --git a/docs/api/classes/filesizeformatter.html b/docs/api/classes/filesizeformatter.html deleted file mode 100644 index 941e18a7..00000000 --- a/docs/api/classes/filesizeformatter.html +++ /dev/null @@ -1,203 +0,0 @@ - - - - - - FileSizeFormatter | nextcloud-node-client - - - - - -
-
-
-
- -
-
- Options -
-
- All -
    -
  • Public
  • -
  • Public/Protected
  • -
  • All
  • -
-
- - -
-
- Menu -
-
-
-
-
-
- -

Class FileSizeFormatter

-
-
-
-
-
-
-
-

Hierarchy

-
    -
  • - FileSizeFormatter -
  • -
-
-
-

Index

-
-
-
-

Constructors

- -
-
-

Methods

- -
-
-
-
-
-

Constructors

-
- -

constructor

- - -
-
-
-

Methods

-
- -

getUserFriendlyFileSize

-
    -
  • getUserFriendlyFileSize(): string
  • -
- -
-
-
- -
-
-
-
-

Legend

-
-
    -
  • Constructor
  • -
  • Property
  • -
  • Method
  • -
-
    -
  • Inherited constructor
  • -
  • Inherited property
  • -
  • Inherited method
  • -
-
    -
  • Protected property
  • -
  • Protected method
  • -
-
    -
  • Static property
  • -
  • Static method
  • -
-
    -
  • Property
  • -
-
-
-
-
-

Generated using TypeDoc

-
-
- - - \ No newline at end of file diff --git a/docs/api/classes/filesystemelement.html b/docs/api/classes/filesystemelement.html deleted file mode 100644 index 00f06829..00000000 --- a/docs/api/classes/filesystemelement.html +++ /dev/null @@ -1,583 +0,0 @@ - - - - - - FileSystemElement | nextcloud-node-client - - - - - -
-
-
-
- -
-
- Options -
-
- All -
    -
  • Public
  • -
  • Public/Protected
  • -
  • All
  • -
-
- - -
-
- Menu -
-
-
-
-
-
- -

Class FileSystemElement

-
-
-
-
-
-
-
-
-
-

The file class represents a file in nextcloud. - It exposes file properties and content handling, commenting and tagging

-
-
-
-
-

Hierarchy

-
    -
  • - FileSystemElement -
  • -
-
-
-

Implemented by

- -
-
-

Index

-
-
-
-

Accessors

- -
-
-

Methods

- -
-
-
-
-
-

Accessors

-
- -

baseName

-
    -
  • get baseName(): string
  • -
-
    -
  • - -
    -
    -

    The base name of the file system element (name without path) - The base name is readonly

    -
    -
    -

    Returns string

    -
  • -
-
-
- -

id

-
    -
  • get id(): number
  • -
- -
-
- -

lastmod

-
    -
  • get lastmod(): Date
  • -
-
    -
  • - -
    -
    -

    The timestamp of the last file system element change - readonly

    -
    -
    -

    Returns Date

    -
  • -
-
-
- -

name

-
    -
  • get name(): string
  • -
-
    -
  • - -
    -
    -

    The name of the file system element including the path - The name is readonly

    -
    -
    -

    Returns string

    -
  • -
-
-
-
-

Methods

-
- -

Abstract addComment

-
    -
  • addComment(comment: string): Promise<void>
  • -
-
    -
  • - -
    -
    -

    add comment to file

    -
    -
    -

    Parameters

    -
      -
    • -
      comment: string
      -
      -

      the comment

      -
      -
    • -
    -

    Returns Promise<void>

    -
  • -
-
-
- -

Abstract addTag

-
    -
  • addTag(tagName: string): Promise<void>
  • -
-
    -
  • - -
    -
    -

    adds a tag name to the file system element

    -
    -
    -

    Parameters

    -
      -
    • -
      tagName: string
      -
      -

      name of the tag

      -
      -
    • -
    -

    Returns Promise<void>

    -
  • -
-
-
- -

Abstract delete

-
    -
  • delete(): Promise<void>
  • -
-
    -
  • - -
    -
    -

    deletes a file system element

    -
    -
    -
    throws
    -

    Error

    -
    -
    -
    -

    Returns Promise<void>

    -
  • -
-
-
- -

Abstract getComments

-
    -
  • getComments(top?: undefined | number, skip?: undefined | number): Promise<string[]>
  • -
-
    -
  • - -
    -
    -

    get list of comments of file

    -
    -
    -
    throws
    -

    Exception

    -
    -
    -
    -

    Parameters

    -
      -
    • -
      Optional top: undefined | number
      -
      -

      number of comments to return

      -
      -
    • -
    • -
      Optional skip: undefined | number
      -
      -

      the offset

      -
      -
    • -
    -

    Returns Promise<string[]>

    -

    array of comment strings

    -
  • -
-
-
- -

Abstract getTags

-
    -
  • getTags(): Promise<string[]>
  • -
- -
-
- -

Abstract getUIUrl

-
    -
  • getUIUrl(): string
  • -
-
    -
  • - -
    -
    -
    throws
    -

    Error

    -
    -
    -
    -

    Returns string

    -

    the url of the file system element in the UI

    -
  • -
-
-
- -

Abstract getUrl

-
    -
  • getUrl(): string
  • -
-
    -
  • - -
    -
    -
    throws
    -

    Error

    -
    -
    -
    -

    Returns string

    -

    the url of the file sytsem element

    -
  • -
-
-
- -

Abstract move

- -
    -
  • - -
    -
    -

    moves or renames the current file system element to the new location - target folder must exists

    -
    -
    -
    throws
    -

    Error

    -
    -
    -
    -

    Parameters

    -
      -
    • -
      targetName: string
      -
    • -
    -

    Returns Promise<FileSystemElement>

    -
  • -
-
-
- -

Abstract removeTag

-
    -
  • removeTag(tagName: string): Promise<void>
  • -
-
    -
  • - -
    -
    -

    removes a tag of the file system element

    -
    -
    -

    Parameters

    -
      -
    • -
      tagName: string
      -
      -

      the name of the tag

      -
      -
    • -
    -

    Returns Promise<void>

    -
  • -
-
-
-
- -
-
-
-
-

Legend

-
-
    -
  • Constructor
  • -
  • Property
  • -
  • Method
  • -
-
    -
  • Inherited constructor
  • -
  • Inherited property
  • -
  • Inherited method
  • -
-
    -
  • Protected property
  • -
  • Protected method
  • -
-
    -
  • Static property
  • -
  • Static method
  • -
-
    -
  • Property
  • -
-
-
-
-
-

Generated using TypeDoc

-
-
- - - \ No newline at end of file diff --git a/docs/api/classes/filesystemfolder.html b/docs/api/classes/filesystemfolder.html deleted file mode 100644 index 9c759e42..00000000 --- a/docs/api/classes/filesystemfolder.html +++ /dev/null @@ -1,224 +0,0 @@ - - - - - - FileSystemFolder | nextcloud-node-client - - - - - -
-
-
-
- -
-
- Options -
-
- All -
    -
  • Public
  • -
  • Public/Protected
  • -
  • All
  • -
-
- - -
-
- Menu -
-
-
-
-
-
- -

Class FileSystemFolder

-
-
-
-
-
-
-
-

Hierarchy

-
    -
  • - FileSystemFolder -
  • -
-
-
-

Index

-
-
-
-

Constructors

- -
-
-

Methods

- -
-
-
-
-
-

Constructors

-
- -

constructor

- - -
-
-
-

Methods

-
- -

getFileNames

- - -
-
- -

getName

- - -
-
-
- -
-
-
-
-

Legend

-
-
    -
  • Constructor
  • -
  • Property
  • -
  • Method
  • -
-
    -
  • Inherited constructor
  • -
  • Inherited property
  • -
  • Inherited method
  • -
-
    -
  • Protected property
  • -
  • Protected method
  • -
-
    -
  • Static property
  • -
  • Static method
  • -
-
    -
  • Property
  • -
-
-
-
-
-

Generated using TypeDoc

-
-
- - - \ No newline at end of file diff --git a/docs/api/classes/folder.html b/docs/api/classes/folder.html deleted file mode 100644 index 576a4269..00000000 --- a/docs/api/classes/folder.html +++ /dev/null @@ -1,856 +0,0 @@ - - - - - - Folder | nextcloud-node-client - - - - - -
-
-
-
- -
-
- Options -
-
- All -
    -
  • Public
  • -
  • Public/Protected
  • -
  • All
  • -
-
- - -
-
- Menu -
-
-
-
-
-
- -

Class Folder

-
-
-
-
-
-
-
-

Hierarchy

-
    -
  • - Folder -
  • -
-
-
-

Implements

- -
-
-

Index

-
-
-
-

Constructors

- -
-
-

Accessors

- -
-
-

Methods

- -
-
-
-
-
-

Constructors

-
- -

constructor

-
    -
  • new Folder(client: Client, name: string, baseName: string, lastmod: string, id?: number): Folder
  • -
-
    -
  • - -

    Parameters

    -
      -
    • -
      client: Client
      -
    • -
    • -
      name: string
      -
    • -
    • -
      baseName: string
      -
    • -
    • -
      lastmod: string
      -
    • -
    • -
      Default value id: number = -1
      -
    • -
    -

    Returns Folder

    -
  • -
-
-
-
-

Accessors

-
- -

baseName

-
    -
  • get baseName(): string
  • -
- -
-
- -

id

-
    -
  • get id(): number
  • -
- -
-
- -

lastmod

-
    -
  • get lastmod(): Date
  • -
- -
-
- -

name

-
    -
  • get name(): string
  • -
- -
-
-
-

Methods

-
- -

addComment

-
    -
  • addComment(comment: string): Promise<void>
  • -
-
    -
  • - -
    -
    -

    add comment to folder

    -
    -
    -

    Parameters

    -
      -
    • -
      comment: string
      -
      -

      the comment

      -
      -
    • -
    -

    Returns Promise<void>

    -
  • -
-
-
- -

addTag

-
    -
  • addTag(tagName: string): Promise<void>
  • -
-
    -
  • - -
    -
    -

    adds a tag name to the folder

    -
    -
    -

    Parameters

    -
      -
    • -
      tagName: string
      -
      -

      name of the tag

      -
      -
    • -
    -

    Returns Promise<void>

    -
  • -
-
-
- -

containsFile

-
    -
  • containsFile(fileBaseName: string): Promise<boolean>
  • -
-
    -
  • - -
    -
    -
    throws
    -

    Error

    -
    -
    -
    -

    Parameters

    -
      -
    • -
      fileBaseName: string
      -
      -

      file basename

      -
      -
    • -
    -

    Returns Promise<boolean>

    -

    true if the folder contains a file with the given basename

    -
  • -
-
-
- -

createFile

-
    -
  • createFile(fileBaseName: string, data: Buffer | ReadableStream): Promise<File>
  • -
-
    -
  • - -
    -
    -

    creates a file in the folder

    -
    -
    -
    throws
    -

    Error

    -
    -
    -
    -

    Parameters

    -
      -
    • -
      fileBaseName: string
      -
      -

      the base name of the file

      -
      -
    • -
    • -
      data: Buffer | ReadableStream
      -
      -

      the buffer or stream with file content

      -
      -
    • -
    -

    Returns Promise<File>

    -

    the new file or null

    -
  • -
-
-
- -

createSubFolder

-
    -
  • createSubFolder(subFolderBaseName: string): Promise<Folder>
  • -
-
    -
  • - -
    -
    -

    creates a subfolder

    -
    -
    -

    Parameters

    -
      -
    • -
      subFolderBaseName: string
      -
      -

      name of the subfolder basename

      -
      -
    • -
    -

    Returns Promise<Folder>

    -
  • -
-
-
- -

delete

-
    -
  • delete(): Promise<void>
  • -
-
    -
  • - -
    -
    -

    deletes the folder and the contained files

    -
    -
    -
    throws
    -

    Error

    -
    -
    -
    -

    Returns Promise<void>

    -
  • -
-
-
- -

getComments

-
    -
  • getComments(top?: undefined | number, skip?: undefined | number): Promise<string[]>
  • -
-
    -
  • - -
    -
    -

    get list of comments of folder

    -
    -
    -
    throws
    -

    Exception

    -
    -
    -
    -

    Parameters

    -
      -
    • -
      Optional top: undefined | number
      -
      -

      number of comments to return

      -
      -
    • -
    • -
      Optional skip: undefined | number
      -
      -

      the offset

      -
      -
    • -
    -

    Returns Promise<string[]>

    -

    array of comment strings

    -
  • -
-
-
- -

getFile

-
    -
  • getFile(fileBaseName: string): Promise<File | null>
  • -
-
    -
  • - -
    -
    -

    get a file by basename

    -
    -
    -
    throws
    -

    Error

    -
    -
    -
    -

    Parameters

    -
      -
    • -
      fileBaseName: string
      -
      -

      the base name of the file

      -
      -
    • -
    -

    Returns Promise<File | null>

    -

    the file of null

    -
  • -
-
-
- -

getFiles

- - -
-
- -

getSubFolders

-
    -
  • getSubFolders(): Promise<Folder[]>
  • -
-
    -
  • - -
    -
    -
    throws
    -

    Error

    -
    -
    -
    -

    Returns Promise<Folder[]>

    -

    an array of subfolders

    -
  • -
-
-
- -

getTags

-
    -
  • getTags(): Promise<string[]>
  • -
-
    -
  • - -
    -
    -

    get tag names

    -
    -
    -

    Returns Promise<string[]>

    -

    array of tag names

    -
  • -
-
-
- -

getUIUrl

-
    -
  • getUIUrl(): string
  • -
-
    -
  • - -
    -
    -
    throws
    -

    Error

    -
    -
    -
    -

    Returns string

    -

    the url of the folder in the UI

    -
  • -
-
-
- -

getUrl

-
    -
  • getUrl(): string
  • -
-
    -
  • - -
    -
    -
    throws
    -

    Error

    -
    -
    -
    -

    Returns string

    -

    the url of the folder

    -
  • -
-
-
- -

hasSubFolder

-
    -
  • hasSubFolder(subFolderBaseName: string): Promise<boolean>
  • -
-
    -
  • - -
    -
    -

    returns true if the current folder has a subfolder with the given base name

    -
    -
    -

    Parameters

    -
      -
    • -
      subFolderBaseName: string
      -
      -

      the base name of the subfolder like "products"

      -
      -
    • -
    -

    Returns Promise<boolean>

    -
  • -
-
-
- -

move

-
    -
  • move(targetFolderName: string): Promise<Folder>
  • -
-
    -
  • - -
    -
    -

    renames or moves the current folder to the new location - target folder must exists

    -
    -
    -
    throws
    -

    Error

    -
    -
    -
    -

    Parameters

    -
      -
    • -
      targetFolderName: string
      -
      -

      the name of the target folder /f1/f2/target

      -
      -
    • -
    -

    Returns Promise<Folder>

    -
  • -
-
-
- -

removeTag

-
    -
  • removeTag(tagName: string): Promise<void>
  • -
-
    -
  • - -
    -
    -

    removes a tag of the file

    -
    -
    -

    Parameters

    -
      -
    • -
      tagName: string
      -
      -

      the name of the tag

      -
      -
    • -
    -

    Returns Promise<void>

    -
  • -
-
-
-
- -
-
-
-
-

Legend

-
-
    -
  • Constructor
  • -
  • Property
  • -
  • Method
  • -
-
    -
  • Inherited constructor
  • -
  • Inherited property
  • -
  • Inherited method
  • -
-
    -
  • Protected property
  • -
  • Protected method
  • -
-
    -
  • Static property
  • -
  • Static method
  • -
-
    -
  • Property
  • -
-
-
-
-
-

Generated using TypeDoc

-
-
- - - \ No newline at end of file diff --git a/docs/api/classes/getfilesrecursivelycommand.html b/docs/api/classes/getfilesrecursivelycommand.html deleted file mode 100644 index 6dd70a15..00000000 --- a/docs/api/classes/getfilesrecursivelycommand.html +++ /dev/null @@ -1,468 +0,0 @@ - - - - - - GetFilesRecursivelyCommand | nextcloud-node-client - - - - - -
-
-
-
- -
-
- Options -
-
- All -
    -
  • Public
  • -
  • Public/Protected
  • -
  • All
  • -
-
- - -
-
- Menu -
-
-
-
-
-
- -

Class GetFilesRecursivelyCommand

-
-
-
-
-
-
-
-
-
-

Command to get all files of a nextcloud folder recursively

-
-
-
-
-

Hierarchy

-
    -
  • - Command -
      -
    • - GetFilesRecursivelyCommand -
    • -
    -
  • -
-
-
-

Index

-
-
-
-

Constructors

- -
-
-

Properties

- -
-
-

Methods

- -
-
-
-
-
-

Constructors

-
- -

constructor

- - -
-
-
-

Properties

-
- -

Protected client

-
client: Client
- -
-
- -

Protected percentCompleted

-
percentCompleted: number
- -
-
- -

Protected resultMetaData

-
resultMetaData: CommandResultMetaData
- -
-
- -

Protected status

- - -
-
-
-

Methods

-
- -

execute

-
    -
  • execute(): Promise<void>
  • -
- -
-
- -

getFiles

-
    -
  • getFiles(): File[]
  • -
- -
-
- -

getPercentCompleted

-
    -
  • getPercentCompleted(): number
  • -
- -
-
- -

getResultMetaData

- - -
-
- -

getStatus

- - -
-
- -

isFinished

-
    -
  • isFinished(): boolean
  • -
- -
-
- -

Protected onExecute

-
    -
  • onExecute(): Promise<void>
  • -
- -
-
-
- -
-
-
-
-

Legend

-
-
    -
  • Constructor
  • -
  • Property
  • -
  • Method
  • -
-
    -
  • Inherited constructor
  • -
  • Inherited property
  • -
  • Inherited method
  • -
-
    -
  • Protected property
  • -
  • Protected method
  • -
-
    -
  • Static property
  • -
  • Static method
  • -
-
    -
  • Property
  • -
-
-
-
-
-

Generated using TypeDoc

-
-
- - - \ No newline at end of file diff --git a/docs/api/classes/httpclient.html b/docs/api/classes/httpclient.html deleted file mode 100644 index f0000455..00000000 --- a/docs/api/classes/httpclient.html +++ /dev/null @@ -1,218 +0,0 @@ - - - - - - HttpClient | nextcloud-node-client - - - - - -
-
-
-
- -
-
- Options -
-
- All -
    -
  • Public
  • -
  • Public/Protected
  • -
  • All
  • -
-
- - -
-
- Menu -
-
-
-
-
-
- -

Class HttpClient

-
-
-
-
-
-
-
-

Hierarchy

-
    -
  • - HttpClient -
  • -
-
-
-

Index

-
-
-
-

Constructors

- -
-
-

Methods

- -
-
-
-
-
-

Constructors

-
- -

constructor

- - -
-
-
-

Methods

-
- -

getHttpResponse

-
    -
  • getHttpResponse(url: string, requestInit: RequestInit, expectedHttpStatusCode: number[], context: IRequestContext): Promise<Response>
  • -
-
    -
  • - -

    Parameters

    -
      -
    • -
      url: string
      -
    • -
    • -
      requestInit: RequestInit
      -
    • -
    • -
      expectedHttpStatusCode: number[]
      -
    • -
    • -
      context: IRequestContext
      -
    • -
    -

    Returns Promise<Response>

    -
  • -
-
-
-
- -
-
-
-
-

Legend

-
-
    -
  • Constructor
  • -
  • Property
  • -
  • Method
  • -
-
    -
  • Inherited constructor
  • -
  • Inherited property
  • -
  • Inherited method
  • -
-
    -
  • Protected property
  • -
  • Protected method
  • -
-
    -
  • Static property
  • -
  • Static method
  • -
-
    -
  • Property
  • -
-
-
-
-
-

Generated using TypeDoc

-
-
- - - \ No newline at end of file diff --git a/docs/api/classes/insufficientprivilegeserror.html b/docs/api/classes/insufficientprivilegeserror.html deleted file mode 100644 index ad70bcd3..00000000 --- a/docs/api/classes/insufficientprivilegeserror.html +++ /dev/null @@ -1,243 +0,0 @@ - - - - - - InsufficientPrivilegesError | nextcloud-node-client - - - - - -
-
-
-
- -
-
- Options -
-
- All -
    -
  • Public
  • -
  • Public/Protected
  • -
  • All
  • -
-
- - -
-
- Menu -
-
-
-
-
-
- -

Class InsufficientPrivilegesError

-
-
-
-
-
-
-
-
-
-

the service response is invalid

-
-
-
-
-

Hierarchy

-
    -
  • - BaseError -
      -
    • - InsufficientPrivilegesError -
    • -
    -
  • -
-
-
-

Index

-
-
-
-

Constructors

- -
-
-

Properties

- -
-
-
-
-
-

Constructors

-
- -

constructor

- - -
-
-
-

Properties

-
- -

message

-
message: string
- -
-
- -

name

-
name: string
- -
-
- -

Optional stack

-
stack: undefined | string
- -
-
-
- -
-
-
-
-

Legend

-
-
    -
  • Constructor
  • -
  • Property
  • -
  • Method
  • -
-
    -
  • Inherited constructor
  • -
  • Inherited property
  • -
  • Inherited method
  • -
-
    -
  • Protected property
  • -
  • Protected method
  • -
-
    -
  • Static property
  • -
  • Static method
  • -
-
    -
  • Property
  • -
-
-
-
-
-

Generated using TypeDoc

-
-
- - - \ No newline at end of file diff --git a/docs/api/classes/invalidserviceresponseformaterror.html b/docs/api/classes/invalidserviceresponseformaterror.html deleted file mode 100644 index dcce11ba..00000000 --- a/docs/api/classes/invalidserviceresponseformaterror.html +++ /dev/null @@ -1,243 +0,0 @@ - - - - - - InvalidServiceResponseFormatError | nextcloud-node-client - - - - - -
-
-
-
- -
-
- Options -
-
- All -
    -
  • Public
  • -
  • Public/Protected
  • -
  • All
  • -
-
- - -
-
- Menu -
-
-
-
-
-
- -

Class InvalidServiceResponseFormatError

-
-
-
-
-
-
-
-
-
-

the service response is invalid

-
-
-
-
-

Hierarchy

-
    -
  • - BaseError -
      -
    • - InvalidServiceResponseFormatError -
    • -
    -
  • -
-
-
-

Index

-
-
-
-

Constructors

- -
-
-

Properties

- -
-
-
-
-
-

Constructors

-
- -

constructor

- - -
-
-
-

Properties

-
- -

message

-
message: string
- -
-
- -

name

-
name: string
- -
-
- -

Optional stack

-
stack: undefined | string
- -
-
-
- -
-
-
-
-

Legend

-
-
    -
  • Constructor
  • -
  • Property
  • -
  • Method
  • -
-
    -
  • Inherited constructor
  • -
  • Inherited property
  • -
  • Inherited method
  • -
-
    -
  • Protected property
  • -
  • Protected method
  • -
-
    -
  • Static property
  • -
  • Static method
  • -
-
    -
  • Property
  • -
-
-
-
-
-

Generated using TypeDoc

-
-
- - - \ No newline at end of file diff --git a/docs/api/classes/logger.html b/docs/api/classes/logger.html deleted file mode 100644 index 249494d5..00000000 --- a/docs/api/classes/logger.html +++ /dev/null @@ -1,421 +0,0 @@ - - - - - - Logger | nextcloud-node-client - - - - - -
-
-
-
- -
-
- Options -
-
- All -
    -
  • Public
  • -
  • Public/Protected
  • -
  • All
  • -
-
- - -
-
- Menu -
-
-
-
-
-
- -

Class Logger

-
-
-
-
-
-
-
-

Hierarchy

-
    -
  • - Logger -
  • -
-
-
-

Index

-
-
-
-

Constructors

- -
-
-

Methods

- -
-
-
-
-
-

Constructors

-
- -

constructor

- - -
-
-
-

Methods

-
- -

debug

-
    -
  • debug(...args: unknown[]): LogObject
  • -
-
    -
  • - -
    -
    -

    Logs a debug message.

    -
    -
    -

    Parameters

    -
      -
    • -
      Rest ...args: unknown[]
      -
      -

      Multiple log attributes that should be logged out.

      -
      -
    • -
    -

    Returns LogObject

    -
  • -
-
-
- -

error

-
    -
  • error(...args: unknown[]): LogObject
  • -
-
    -
  • - -
    -
    -

    Logs a error message.

    -
    -
    -

    Parameters

    -
      -
    • -
      Rest ...args: unknown[]
      -
      -

      Multiple log attributes that should be logged out.

      -
      -
    • -
    -

    Returns LogObject

    -
  • -
-
-
- -

fatal

-
    -
  • fatal(...args: unknown[]): LogObject
  • -
-
    -
  • - -
    -
    -

    Logs a fatal message.

    -
    -
    -

    Parameters

    -
      -
    • -
      Rest ...args: unknown[]
      -
      -

      Multiple log attributes that should be logged out.

      -
      -
    • -
    -

    Returns LogObject

    -
  • -
-
-
- -

info

-
    -
  • info(...args: unknown[]): LogObject
  • -
-
    -
  • - -
    -
    -

    Logs a info message.

    -
    -
    -

    Parameters

    -
      -
    • -
      Rest ...args: unknown[]
      -
      -

      Multiple log attributes that should be logged out.

      -
      -
    • -
    -

    Returns LogObject

    -
  • -
-
-
- -

silly

-
    -
  • silly(...args: unknown[]): LogObject
  • -
-
    -
  • - -
    -
    -

    Logs a silly message.

    -
    -
    -

    Parameters

    -
      -
    • -
      Rest ...args: unknown[]
      -
      -

      Multiple log attributes that should be logged out.

      -
      -
    • -
    -

    Returns LogObject

    -
  • -
-
-
- -

trace

-
    -
  • trace(...args: unknown[]): LogObject
  • -
-
    -
  • - -
    -
    -

    Logs a trace message.

    -
    -
    -

    Parameters

    -
      -
    • -
      Rest ...args: unknown[]
      -
      -

      Multiple log attributes that should be logged out.

      -
      -
    • -
    -

    Returns LogObject

    -
  • -
-
-
- -

warn

-
    -
  • warn(...args: unknown[]): LogObject
  • -
-
    -
  • - -
    -
    -

    Logs a warn message.

    -
    -
    -

    Parameters

    -
      -
    • -
      Rest ...args: unknown[]
      -
      -

      Multiple log attributes that should be logged out.

      -
      -
    • -
    -

    Returns LogObject

    -
  • -
-
-
-
- -
-
-
-
-

Legend

-
-
    -
  • Constructor
  • -
  • Property
  • -
  • Method
  • -
-
    -
  • Inherited constructor
  • -
  • Inherited property
  • -
  • Inherited method
  • -
-
    -
  • Protected property
  • -
  • Protected method
  • -
-
    -
  • Static property
  • -
  • Static method
  • -
-
    -
  • Property
  • -
-
-
-
-
-

Generated using TypeDoc

-
-
- - - \ No newline at end of file diff --git a/docs/api/classes/operationfailederror.html b/docs/api/classes/operationfailederror.html deleted file mode 100644 index 46fab1ea..00000000 --- a/docs/api/classes/operationfailederror.html +++ /dev/null @@ -1,243 +0,0 @@ - - - - - - OperationFailedError | nextcloud-node-client - - - - - -
-
-
-
- -
-
- Options -
-
- All -
    -
  • Public
  • -
  • Public/Protected
  • -
  • All
  • -
-
- - -
-
- Menu -
-
-
-
-
-
- -

Class OperationFailedError

-
-
-
-
-
-
-
-
-
-

operation failed

-
-
-
-
-

Hierarchy

-
    -
  • - BaseError -
      -
    • - OperationFailedError -
    • -
    -
  • -
-
-
-

Index

-
-
-
-

Constructors

- -
-
-

Properties

- -
-
-
-
-
-

Constructors

-
- -

constructor

- - -
-
-
-

Properties

-
- -

message

-
message: string
- -
-
- -

name

-
name: string
- -
-
- -

Optional stack

-
stack: undefined | string
- -
-
-
- -
-
-
-
-

Legend

-
-
    -
  • Constructor
  • -
  • Property
  • -
  • Method
  • -
-
    -
  • Inherited constructor
  • -
  • Inherited property
  • -
  • Inherited method
  • -
-
    -
  • Protected property
  • -
  • Protected method
  • -
-
    -
  • Static property
  • -
  • Static method
  • -
-
    -
  • Property
  • -
-
-
-
-
-

Generated using TypeDoc

-
-
- - - \ No newline at end of file diff --git a/docs/api/classes/querylimiterror.html b/docs/api/classes/querylimiterror.html deleted file mode 100644 index 38f420db..00000000 --- a/docs/api/classes/querylimiterror.html +++ /dev/null @@ -1,243 +0,0 @@ - - - - - - QueryLimitError | nextcloud-node-client - - - - - -
-
-
-
- -
-
- Options -
-
- All -
    -
  • Public
  • -
  • Public/Protected
  • -
  • All
  • -
-
- - -
-
- Menu -
-
-
-
-
-
- -

Class QueryLimitError

-
-
-
-
-
-
-
-
-
-

the query limit parameter must be a number larger than 0

-
-
-
-
-

Hierarchy

-
    -
  • - BaseError -
      -
    • - QueryLimitError -
    • -
    -
  • -
-
-
-

Index

-
-
-
-

Constructors

- -
-
-

Properties

- -
-
-
-
-
-

Constructors

-
- -

constructor

- - -
-
-
-

Properties

-
- -

message

-
message: string
- -
-
- -

name

-
name: string
- -
-
- -

Optional stack

-
stack: undefined | string
- -
-
-
- -
-
-
-
-

Legend

-
-
    -
  • Constructor
  • -
  • Property
  • -
  • Method
  • -
-
    -
  • Inherited constructor
  • -
  • Inherited property
  • -
  • Inherited method
  • -
-
    -
  • Protected property
  • -
  • Protected method
  • -
-
    -
  • Static property
  • -
  • Static method
  • -
-
    -
  • Property
  • -
-
-
-
-
-

Generated using TypeDoc

-
-
- - - \ No newline at end of file diff --git a/docs/api/classes/queryoffseterror.html b/docs/api/classes/queryoffseterror.html deleted file mode 100644 index dda70f8f..00000000 --- a/docs/api/classes/queryoffseterror.html +++ /dev/null @@ -1,243 +0,0 @@ - - - - - - QueryOffsetError | nextcloud-node-client - - - - - -
-
-
-
- -
-
- Options -
-
- All -
    -
  • Public
  • -
  • Public/Protected
  • -
  • All
  • -
-
- - -
-
- Menu -
-
-
-
-
-
- -

Class QueryOffsetError

-
-
-
-
-
-
-
-
-
-

the query offset parameter must be a number larger than 0

-
-
-
-
-

Hierarchy

-
    -
  • - BaseError -
      -
    • - QueryOffsetError -
    • -
    -
  • -
-
-
-

Index

-
-
-
-

Constructors

- -
-
-

Properties

- -
-
-
-
-
-

Constructors

-
- -

constructor

- - -
-
-
-

Properties

-
- -

message

-
message: string
- -
-
- -

name

-
name: string
- -
-
- -

Optional stack

-
stack: undefined | string
- -
-
-
- -
-
-
-
-

Legend

-
-
    -
  • Constructor
  • -
  • Property
  • -
  • Method
  • -
-
    -
  • Inherited constructor
  • -
  • Inherited property
  • -
  • Inherited method
  • -
-
    -
  • Protected property
  • -
  • Protected method
  • -
-
    -
  • Static property
  • -
  • Static method
  • -
-
    -
  • Property
  • -
-
-
-
-
-

Generated using TypeDoc

-
-
- - - \ No newline at end of file diff --git a/docs/api/classes/requestlogentry.html b/docs/api/classes/requestlogentry.html deleted file mode 100644 index 8aeb4cc1..00000000 --- a/docs/api/classes/requestlogentry.html +++ /dev/null @@ -1,261 +0,0 @@ - - - - - - RequestLogEntry | nextcloud-node-client - - - - - -
-
-
-
- -
-
- Options -
-
- All -
    -
  • Public
  • -
  • Public/Protected
  • -
  • All
  • -
-
- - -
-
- Menu -
-
-
-
-
-
- -

Class RequestLogEntry

-
-
-
-
-
-
-
-

Hierarchy

-
    -
  • - RequestLogEntry -
  • -
-
-
-

Index

-
-
-
-

Constructors

- -
-
-

Properties

- -
-
-
-
-
-

Constructors

-
- -

constructor

-
    -
  • new RequestLogEntry(url: string, method: string, description: string, body?: undefined | string): RequestLogEntry
  • -
- -
-
-
-

Properties

-
- -

Optional body

-
body: undefined | string
- -
-
- -

description

-
description: string
- -
-
- -

Optional jsonBody

-
jsonBody: any
- -
-
- -

method

-
method: string
- -
-
- -

url

-
url: string
- -
-
-
- -
-
-
-
-

Legend

-
-
    -
  • Constructor
  • -
  • Property
  • -
  • Method
  • -
-
    -
  • Inherited constructor
  • -
  • Inherited property
  • -
  • Inherited method
  • -
-
    -
  • Protected property
  • -
  • Protected method
  • -
-
    -
  • Static property
  • -
  • Static method
  • -
-
    -
  • Property
  • -
-
-
-
-
-

Generated using TypeDoc

-
-
- - - \ No newline at end of file diff --git a/docs/api/classes/requestresponselog.html b/docs/api/classes/requestresponselog.html deleted file mode 100644 index acf1ad0d..00000000 --- a/docs/api/classes/requestresponselog.html +++ /dev/null @@ -1,321 +0,0 @@ - - - - - - RequestResponseLog | nextcloud-node-client - - - - - -
-
-
-
- -
-
- Options -
-
- All -
    -
  • Public
  • -
  • Public/Protected
  • -
  • All
  • -
-
- - -
-
- Menu -
-
-
-
-
-
- -

Class RequestResponseLog

-
-
-
-
-
-
-
-

Hierarchy

-
    -
  • - RequestResponseLog -
  • -
-
-
-

Index

-
-
-
-

Properties

- -
-
-

Methods

- -
-
-
-
-
-

Properties

-
- -

baseDirectory

-
baseDirectory: string = RequestResponseLog.defaultLogDirectory
- -
-
- -

Static Readonly defaultLogDirectory

-
defaultLogDirectory: string = "RequestResponseLog/"
- -
-
-
-

Methods

-
- -

addEntry

-
    -
  • addEntry(logEntry: requestResponseLogEntry): Promise<void>
  • -
- -
-
- -

getEntries

-
    -
  • getEntries(): Promise<requestResponseLogEntry[]>
  • -
- -
-
- -

getFileName

-
    -
  • getFileName(): string
  • -
- -
-
- -

setContext

-
    -
  • setContext(context: string): Promise<void>
  • -
- -
-
- -

Static deleteInstance

-
    -
  • deleteInstance(): void
  • -
- -
-
- -

Static getInstance

- - -
-
-
- -
-
-
-
-

Legend

-
-
    -
  • Constructor
  • -
  • Property
  • -
  • Method
  • -
-
    -
  • Inherited constructor
  • -
  • Inherited property
  • -
  • Inherited method
  • -
-
    -
  • Protected property
  • -
  • Protected method
  • -
-
    -
  • Static property
  • -
  • Static method
  • -
-
    -
  • Property
  • -
-
-
-
-
-

Generated using TypeDoc

-
-
- - - \ No newline at end of file diff --git a/docs/api/classes/requestresponselogentry.html b/docs/api/classes/requestresponselogentry.html deleted file mode 100644 index 85bd37dc..00000000 --- a/docs/api/classes/requestresponselogentry.html +++ /dev/null @@ -1,213 +0,0 @@ - - - - - - RequestResponseLogEntry | nextcloud-node-client - - - - - -
-
-
-
- -
-
- Options -
-
- All -
    -
  • Public
  • -
  • Public/Protected
  • -
  • All
  • -
-
- - -
-
- Menu -
-
-
-
-
-
- -

Class RequestResponseLogEntry

-
-
-
-
-
-
-
-

Hierarchy

-
    -
  • - RequestResponseLogEntry -
  • -
-
-
-

Index

-
-
-
-

Constructors

- -
-
-

Properties

- -
-
-
-
-
-

Constructors

-
- -

constructor

- - -
-
-
-

Properties

-
- -

request

- - -
-
- -

response

- - -
-
-
- -
-
-
-
-

Legend

-
-
    -
  • Constructor
  • -
  • Property
  • -
  • Method
  • -
-
    -
  • Inherited constructor
  • -
  • Inherited property
  • -
  • Inherited method
  • -
-
    -
  • Protected property
  • -
  • Protected method
  • -
-
    -
  • Static property
  • -
  • Static method
  • -
-
    -
  • Property
  • -
-
-
-
-
-

Generated using TypeDoc

-
-
- - - \ No newline at end of file diff --git a/docs/api/classes/responselogentry.html b/docs/api/classes/responselogentry.html deleted file mode 100644 index d9098f4a..00000000 --- a/docs/api/classes/responselogentry.html +++ /dev/null @@ -1,261 +0,0 @@ - - - - - - ResponseLogEntry | nextcloud-node-client - - - - - -
-
-
-
- -
-
- Options -
-
- All -
    -
  • Public
  • -
  • Public/Protected
  • -
  • All
  • -
-
- - -
-
- Menu -
-
-
-
-
-
- -

Class ResponseLogEntry

-
-
-
-
-
-
-
-

Hierarchy

-
    -
  • - ResponseLogEntry -
  • -
-
-
-

Index

-
-
-
-

Constructors

- -
-
-

Properties

- -
-
-
-
-
-

Constructors

-
- -

constructor

-
    -
  • new ResponseLogEntry(status: number, body?: undefined | string, contentType?: undefined | string, contentLocation?: undefined | string): ResponseLogEntry
  • -
-
    -
  • - -

    Parameters

    -
      -
    • -
      status: number
      -
    • -
    • -
      Optional body: undefined | string
      -
    • -
    • -
      Optional contentType: undefined | string
      -
    • -
    • -
      Optional contentLocation: undefined | string
      -
    • -
    -

    Returns ResponseLogEntry

    -
  • -
-
-
-
-

Properties

-
- -

Optional body

-
body: undefined | string
- -
-
- -

Optional contentLocation

-
contentLocation: undefined | string
- -
-
- -

Optional contentType

-
contentType: undefined | string
- -
-
- -

Optional jsonBody

-
jsonBody: any
- -
-
- -

status

-
status: number
- -
-
-
- -
-
-
-
-

Legend

-
-
    -
  • Constructor
  • -
  • Property
  • -
  • Method
  • -
-
    -
  • Inherited constructor
  • -
  • Inherited property
  • -
  • Inherited method
  • -
-
    -
  • Protected property
  • -
  • Protected method
  • -
-
    -
  • Static property
  • -
  • Static method
  • -
-
    -
  • Property
  • -
-
-
-
-
-

Generated using TypeDoc

-
-
- - - \ No newline at end of file diff --git a/docs/api/classes/server.html b/docs/api/classes/server.html deleted file mode 100644 index 814e9056..00000000 --- a/docs/api/classes/server.html +++ /dev/null @@ -1,238 +0,0 @@ - - - - - - Server | nextcloud-node-client - - - - - -
-
-
-
- -
-
- Options -
-
- All -
    -
  • Public
  • -
  • Public/Protected
  • -
  • All
  • -
-
- - -
-
- Menu -
-
-
-
-
-
- -

Class Server

-
-
-
-
-
-
-
-

Hierarchy

-
    -
  • - Server -
  • -
-
-
-

Index

-
-
-
-

Constructors

- -
-
-

Properties

- -
-
-
-
-
-

Constructors

-
- -

constructor

- - -
-
-
-

Properties

-
- -

basicAuth

-
basicAuth: IBasicAuth
- -
-
- -

logRequestResponse

-
logRequestResponse: boolean
- -
-
- -

Optional proxy

-
proxy: IProxy
- -
-
- -

url

-
url: string
- -
-
-
- -
-
-
-
-

Legend

-
-
    -
  • Constructor
  • -
  • Property
  • -
  • Method
  • -
-
    -
  • Inherited constructor
  • -
  • Inherited property
  • -
  • Inherited method
  • -
-
    -
  • Protected property
  • -
  • Protected method
  • -
-
    -
  • Static property
  • -
  • Static method
  • -
-
    -
  • Property
  • -
-
-
-
-
-

Generated using TypeDoc

-
-
- - - \ No newline at end of file diff --git a/docs/api/classes/share.html b/docs/api/classes/share.html deleted file mode 100644 index 426dcb74..00000000 --- a/docs/api/classes/share.html +++ /dev/null @@ -1,456 +0,0 @@ - - - - - - Share | nextcloud-node-client - - - - - -
-
-
-
- -
-
- Options -
-
- All -
    -
  • Public
  • -
  • Public/Protected
  • -
  • All
  • -
-
- - -
-
- Menu -
-
-
-
-
-
- -

Class Share

-
-
-
-
-
-
-
-

Hierarchy

-
    -
  • - Share -
  • -
-
-
-

Index

-
-
-
-

Accessors

- -
-
-

Methods

- -
-
-
-
-
-

Accessors

-
- -

expiration

-
    -
  • get expiration(): Date | null
  • -
-
    -
  • - -
    -
    -

    expiration - The expiration is readonly

    -
    -
    -

    Returns Date | null

    -
  • -
-
-
- -

id

-
    -
  • get id(): string
  • -
-
    -
  • - -
    -
    -

    id - The id is readonly

    -
    -
    -

    Returns string

    -
  • -
-
-
- -

note

-
    -
  • get note(): string
  • -
-
    -
  • - -
    -
    -

    note - The note is readonly

    -
    -
    -

    Returns string

    -
  • -
-
-
- -

token

-
    -
  • get token(): string
  • -
-
    -
  • - -
    -
    -

    token - The token is readonly

    -
    -
    -

    Returns string

    -
  • -
-
-
- -

url

-
    -
  • get url(): string
  • -
-
    -
  • - -
    -
    -

    share url - The share url is readonly

    -
    -
    -

    Returns string

    -
  • -
-
-
-
-

Methods

-
- -

delete

-
    -
  • delete(): Promise<void>
  • -
- -
-
- -

setExpiration

-
    -
  • setExpiration(expiration: Date): Promise<void>
  • -
-
    -
  • - -

    Parameters

    -
      -
    • -
      expiration: Date
      -
    • -
    -

    Returns Promise<void>

    -
  • -
-
-
- -

setNote

-
    -
  • setNote(note: string): Promise<void>
  • -
-
    -
  • - -

    Parameters

    -
      -
    • -
      note: string
      -
    • -
    -

    Returns Promise<void>

    -
  • -
-
-
- -

setPassword

-
    -
  • setPassword(password: string): Promise<void>
  • -
-
    -
  • - -
    -
    -

    set a new password

    -
    -
    -

    Parameters

    -
      -
    • -
      password: string
      -
      -
      -
    • -
    -

    Returns Promise<void>

    -
  • -
-
-
- -

Static createShareRequestBody

-
    -
  • createShareRequestBody(createShare: ICreateShare): string
  • -
- -
-
- -

Static getShare

-
    -
  • getShare(client: Client, id: string): Promise<Share>
  • -
- -
-
-
- -
-
-
-
-

Legend

-
-
    -
  • Constructor
  • -
  • Property
  • -
  • Method
  • -
-
    -
  • Inherited constructor
  • -
  • Inherited property
  • -
  • Inherited method
  • -
-
    -
  • Protected property
  • -
  • Protected method
  • -
-
    -
  • Static property
  • -
  • Static method
  • -
-
    -
  • Property
  • -
-
-
-
-
-

Generated using TypeDoc

-
-
- - - \ No newline at end of file diff --git a/docs/api/classes/tag.html b/docs/api/classes/tag.html deleted file mode 100644 index 663c76ce..00000000 --- a/docs/api/classes/tag.html +++ /dev/null @@ -1,317 +0,0 @@ - - - - - - Tag | nextcloud-node-client - - - - - -
-
-
-
- -
-
- Options -
-
- All -
    -
  • Public
  • -
  • Public/Protected
  • -
  • All
  • -
-
- - -
-
- Menu -
-
-
-
-
-
- -

Class Tag

-
-
-
-
-
-
-
-

Hierarchy

-
    -
  • - Tag -
  • -
-
-
-

Index

-
-
-
-

Constructors

- -
-
-

Properties

- -
-
-

Methods

- -
-
-
-
-
-

Constructors

-
- -

constructor

-
    -
  • new Tag(client: Client, id: number, name: string, visible: boolean, assignable: boolean, canAssign: boolean): Tag
  • -
-
    -
  • - -

    Parameters

    -
      -
    • -
      client: Client
      -
    • -
    • -
      id: number
      -
    • -
    • -
      name: string
      -
    • -
    • -
      visible: boolean
      -
    • -
    • -
      assignable: boolean
      -
    • -
    • -
      canAssign: boolean
      -
    • -
    -

    Returns Tag

    -
  • -
-
-
-
-

Properties

-
- -

Readonly assignable

-
assignable: boolean
- -
-
- -

Readonly canAssign

-
canAssign: boolean
- -
-
- -

Readonly id

-
id: number
- -
-
- -

Readonly name

-
name: string
- -
-
- -

Readonly visible

-
visible: boolean
- -
-
-
-

Methods

-
- -

delete

-
    -
  • delete(): Promise<void>
  • -
-
    -
  • - -

    Returns Promise<void>

    -
  • -
-
-
- -

toString

-
    -
  • toString(): string
  • -
- -
-
-
- -
-
-
-
-

Legend

-
-
    -
  • Constructor
  • -
  • Property
  • -
  • Method
  • -
-
    -
  • Inherited constructor
  • -
  • Inherited property
  • -
  • Inherited method
  • -
-
    -
  • Protected property
  • -
  • Protected method
  • -
-
    -
  • Static property
  • -
  • Static method
  • -
-
    -
  • Property
  • -
-
-
-
-
-

Generated using TypeDoc

-
-
- - - \ No newline at end of file diff --git a/docs/api/classes/uploadfilescommand.html b/docs/api/classes/uploadfilescommand.html deleted file mode 100644 index e47c2982..00000000 --- a/docs/api/classes/uploadfilescommand.html +++ /dev/null @@ -1,468 +0,0 @@ - - - - - - UploadFilesCommand | nextcloud-node-client - - - - - -
-
-
-
- -
-
- Options -
-
- All -
    -
  • Public
  • -
  • Public/Protected
  • -
  • All
  • -
-
- - -
-
- Menu -
-
-
-
-
-
- -

Class UploadFilesCommand

-
-
-
-
-
-
-
-
-
-

Command to upload a set or files from local file system to nextcloud

-
-
-
-
-

Hierarchy

-
    -
  • - Command -
      -
    • - UploadFilesCommand -
    • -
    -
  • -
-
-
-

Index

-
-
-
-

Constructors

- -
-
-

Properties

- -
-
-

Methods

- -
-
-
-
-
-

Constructors

-
- -

constructor

- - -
-
-
-

Properties

-
- -

Protected client

-
client: Client
- -
-
- -

Protected percentCompleted

-
percentCompleted: number
- -
-
- -

Protected resultMetaData

-
resultMetaData: CommandResultMetaData
- -
-
- -

Protected status

- - -
-
-
-

Methods

-
- -

execute

-
    -
  • execute(): Promise<void>
  • -
- -
-
- -

getBytesUploaded

-
    -
  • getBytesUploaded(): number
  • -
- -
-
- -

getPercentCompleted

-
    -
  • getPercentCompleted(): number
  • -
- -
-
- -

getResultMetaData

- - -
-
- -

getStatus

- - -
-
- -

isFinished

-
    -
  • isFinished(): boolean
  • -
- -
-
- -

Protected onExecute

-
    -
  • onExecute(): Promise<void>
  • -
- -
-
-
- -
-
-
-
-

Legend

-
-
    -
  • Constructor
  • -
  • Property
  • -
  • Method
  • -
-
    -
  • Inherited constructor
  • -
  • Inherited property
  • -
  • Inherited method
  • -
-
    -
  • Protected property
  • -
  • Protected method
  • -
-
    -
  • Static property
  • -
  • Static method
  • -
-
    -
  • Property
  • -
-
-
-
-
-

Generated using TypeDoc

-
-
- - - \ No newline at end of file diff --git a/docs/api/classes/uploadfoldercommand.html b/docs/api/classes/uploadfoldercommand.html deleted file mode 100644 index 3ad081ed..00000000 --- a/docs/api/classes/uploadfoldercommand.html +++ /dev/null @@ -1,468 +0,0 @@ - - - - - - UploadFolderCommand | nextcloud-node-client - - - - - -
-
-
-
- -
-
- Options -
-
- All -
    -
  • Public
  • -
  • Public/Protected
  • -
  • All
  • -
-
- - -
-
- Menu -
-
-
-
-
-
- -

Class UploadFolderCommand

-
-
-
-
-
-
-
-
-
-

Command to upload the contents of a folder from local file system to nextcloud recursively

-
-
-
-
-

Hierarchy

-
    -
  • - Command -
      -
    • - UploadFolderCommand -
    • -
    -
  • -
-
-
-

Index

-
-
-
-

Constructors

- -
-
-

Properties

- -
-
-

Methods

- -
-
-
-
-
-

Constructors

-
- -

constructor

- - -
-
-
-

Properties

-
- -

Protected client

-
client: Client
- -
-
- -

Protected percentCompleted

-
percentCompleted: number
- -
-
- -

Protected resultMetaData

-
resultMetaData: CommandResultMetaData
- -
-
- -

Protected status

- - -
-
-
-

Methods

-
- -

execute

-
    -
  • execute(): Promise<void>
  • -
- -
-
- -

getBytesUploaded

-
    -
  • getBytesUploaded(): number
  • -
- -
-
- -

getPercentCompleted

-
    -
  • getPercentCompleted(): number
  • -
- -
-
- -

getResultMetaData

- - -
-
- -

getStatus

- - -
-
- -

isFinished

-
    -
  • isFinished(): boolean
  • -
- -
-
- -

Protected onExecute

-
    -
  • onExecute(): Promise<void>
  • -
- -
-
-
- -
-
-
-
-

Legend

-
-
    -
  • Constructor
  • -
  • Property
  • -
  • Method
  • -
-
    -
  • Inherited constructor
  • -
  • Inherited property
  • -
  • Inherited method
  • -
-
    -
  • Protected property
  • -
  • Protected method
  • -
-
    -
  • Static property
  • -
  • Static method
  • -
-
    -
  • Property
  • -
-
-
-
-
-

Generated using TypeDoc

-
-
- - - \ No newline at end of file diff --git a/docs/api/classes/user.html b/docs/api/classes/user.html deleted file mode 100644 index 9ac2bf0c..00000000 --- a/docs/api/classes/user.html +++ /dev/null @@ -1,1685 +0,0 @@ - - - - - - User | nextcloud-node-client - - - - - -
-
-
-
- -
-
- Options -
-
- All -
    -
  • Public
  • -
  • Public/Protected
  • -
  • All
  • -
-
- - -
-
- Menu -
-
-
-
-
-
- -

Class User

-
-
-
-
-
-
-
-
-
-

The user class represents a user in nextcloud. - async getGroups - async isDisabled - async getLastLogin - async getEmail - getId - async getDisplayName

-
-
-
-
-

Hierarchy

-
    -
  • - User -
  • -
-
-
-

Index

-
- -
-
-
-

Constructors

-
- -

constructor

- -
    -
  • - -
    -
    -

    the conscructor of the user - should only me invoked by the Client

    -
    -
    -

    Parameters

    -
      -
    • -
      client: Client
      -
    • -
    • -
      id: string
      -
      -
      -

      the user id

      -
      -
      -
    • -
    • -
      Optional options: IUserOptions
      -
      -
      -

      optional options

      -
      -
      -
    • -
    -

    Returns User

    -
  • -
-
-
-
-

Properties

-
- -

Readonly id

-
id: string
- -
-
-
-

Methods

-
- -

addToMemberUserGroup

-
    -
  • addToMemberUserGroup(userGroup: UserGroup): Promise<void>
  • -
-
    -
  • - -
    -
    -

    adds the user to a user group as member

    -
    -
    -
    async
    -
    -
    throws
    -

    {UserNotFoundError}

    -
    -
    throws
    -

    {UserGroupDoesNotExistError}

    -
    -
    throws
    -

    {InsufficientPrivilegesError}

    -
    -
    throws
    -

    {OperationFailedError}

    -
    -
    -
    -

    Parameters

    -
      -
    • -
      userGroup: UserGroup
      -
      -

      the user group

      -
      -
    • -
    -

    Returns Promise<void>

    -
  • -
-
-
- -

delete

-
    -
  • delete(): Promise<void>
  • -
-
    -
  • - -
    -
    -

    deletes a user

    -
    -
    -
    async
    -
    -
    throws
    -

    {UserNotFoundError}

    -
    -
    -
    -

    Returns Promise<void>

    -
  • -
-
-
- -

demoteFromSubadminUserGroup

-
    -
  • demoteFromSubadminUserGroup(userGroup: UserGroup): Promise<void>
  • -
-
    -
  • - -
    -
    -

    demote the user from beeing a subadmin of the user group

    -
    -
    -
    async
    -
    -
    throws
    -

    {UserNotFoundError}

    -
    -
    throws
    -

    {UserGroupDoesNotExistError}

    -
    -
    throws
    -

    {InsufficientPrivilegesError}

    -
    -
    throws
    -

    {OperationFailedError}

    -
    -
    -
    -

    Parameters

    -
      -
    • -
      userGroup: UserGroup
      -
      -

      the user group

      -
      -
    • -
    -

    Returns Promise<void>

    -
  • -
-
-
- -

demoteFromSuperAdmin

-
    -
  • demoteFromSuperAdmin(): Promise<void>
  • -
-
    -
  • - -
    -
    -

    demote user from being a super admin

    -
    -
    -
    async
    -
    -
    throws
    -

    {UserNotFoundError}

    -
    -
    throws
    -

    {UserGroupDoesNotExistError}

    -
    -
    throws
    -

    {InsufficientPrivilegesError}

    -
    -
    throws
    -

    {OperationFailedError}

    -
    -
    -
    -

    Returns Promise<void>

    -
  • -
-
-
- -

disable

-
    -
  • disable(): Promise<void>
  • -
-
    -
  • - -
    -
    -

    disables the user

    -
    -
    -
    async
    -
    -
    throws
    -

    {UserNotFoundError}

    -
    -
    -
    -

    Returns Promise<void>

    -
  • -
-
-
- -

enable

-
    -
  • enable(): Promise<void>
  • -
-
    -
  • - -
    -
    -

    enables the user

    -
    -
    -
    async
    -
    -
    throws
    -

    {UserNotFoundError}

    -
    -
    -
    -

    Returns Promise<void>

    -
  • -
-
-
- -

getAddress

-
    -
  • getAddress(): Promise<string>
  • -
-
    -
  • - -
    -
    -

    returns the phone number

    -
    -
    -
    async
    -
    -
    throws
    -

    {UserNotFoundError}

    -
    -
    -
    -

    Returns Promise<string>

    -

    address

    -
  • -
-
-
- -

getDisplayName

-
    -
  • getDisplayName(): Promise<string>
  • -
-
    -
  • - -
    -
    -

    returns the display name

    -
    -
    -
    async
    -
    -
    throws
    -

    {UserNotFoundError}

    -
    -
    -
    -

    Returns Promise<string>

    -

    display name

    -
  • -
-
-
- -

getEmail

-
    -
  • getEmail(): Promise<string>
  • -
-
    -
  • - -
    -
    -

    returns the email address

    -
    -
    -
    async
    -
    -
    throws
    -

    {UserNotFoundError}

    -
    -
    -
    -

    Returns Promise<string>

    -

    email adress

    -
  • -
-
-
- -

getLanguage

-
    -
  • getLanguage(): Promise<string>
  • -
-
    -
  • - -
    -
    -

    returns the langauge code

    -
    -
    -
    async
    -
    -
    throws
    -

    {UserNotFoundError}

    -
    -
    -
    -

    Returns Promise<string>

    -

    language code

    -
  • -
-
-
- -

getLastLogin

-
    -
  • getLastLogin(): Promise<Date | null>
  • -
-
    -
  • - -
    -
    -

    get the last login date or null if the user has not been logged in yet

    -
    -
    -
    async
    -
    -
    throws
    -

    {UserNotFoundError}

    -
    -
    -
    -

    Returns Promise<Date | null>

    -

    last login date or null if the user has not been logged in yet

    -
  • -
-
-
- -

getLocale

-
    -
  • getLocale(): Promise<string>
  • -
-
    -
  • - -
    -
    -

    returns the locale

    -
    -
    -
    async
    -
    -
    throws
    -

    {UserNotFoundError}

    -
    -
    -
    -

    Returns Promise<string>

    -

    locale

    -
  • -
-
-
- -

getMemberUserGroupIds

-
    -
  • getMemberUserGroupIds(): Promise<string[]>
  • -
-
    -
  • - -
    -
    -

    returns a list of user group ids where the user is member

    -
    -
    -
    async
    -
    -
    throws
    -

    {UserNotFoundError}

    -
    -
    -
    -

    Returns Promise<string[]>

    -

    a list of user group ids where the user is member

    -
  • -
-
-
- -

getMemberUserGroups

-
    -
  • getMemberUserGroups(): Promise<UserGroup[]>
  • -
-
    -
  • - -
    -
    -

    returns a list of user groups where the user is member

    -
    -
    -
    async
    -
    -
    throws
    -

    {UserNotFoundError}

    -
    -
    -
    -

    Returns Promise<UserGroup[]>

    -

    a list of user groups where the user is member

    -
  • -
-
-
- -

getPhone

-
    -
  • getPhone(): Promise<string>
  • -
-
    -
  • - -
    -
    -

    returns the phone number

    -
    -
    -
    async
    -
    -
    throws
    -

    {UserNotFoundError}

    -
    -
    -
    -

    Returns Promise<string>

    -

    phone number

    -
  • -
-
-
- -

getQuota

- -
    -
  • - -
    -
    -

    returns information on quota, usage and available space

    -
    -
    -
    async
    -
    -
    throws
    -

    {UserNotFoundError}

    -
    -
    -
    -

    Returns Promise<IUserOptionsQuota>

    -
  • -
-
-
- -

getQuotaUserFriendly

- -
    -
  • - -
    -
    -

    returns information on quota, usage and available space in a user friendly format

    -
    -
    -
    async
    -
    -
    throws
    -

    {UserNotFoundError}

    -
    -
    -
    -

    Returns Promise<IUserQuotaUserFriendly>

    -
  • -
-
-
- -

getSubadminUserGroupIds

-
    -
  • getSubadminUserGroupIds(): Promise<string[]>
  • -
-
    -
  • - -
    -
    -

    returns a list of user group ids where the user is subadmin

    -
    -
    -
    async
    -
    -
    throws
    -

    {UserNotFoundError}

    -
    -
    -
    -

    Returns Promise<string[]>

    -

    a list of user group ids where the user is subadmin

    -
  • -
-
-
- -

getSubadminUserGroups

-
    -
  • getSubadminUserGroups(): Promise<UserGroup[]>
  • -
-
    -
  • - -
    -
    -

    returns a list of user groups where the user is subadmin

    -
    -
    -
    async
    -
    -
    throws
    -

    {UserNotFoundError}

    -
    -
    -
    -

    Returns Promise<UserGroup[]>

    -

    a list of user groups where the user is subadmin

    -
  • -
-
-
- -

getTwitter

-
    -
  • getTwitter(): Promise<string>
  • -
-
    -
  • - -
    -
    -

    returns the twitter handle

    -
    -
    -
    async
    -
    -
    throws
    -

    {UserNotFoundError}

    -
    -
    -
    -

    Returns Promise<string>

    -

    twitter handle

    -
  • -
-
-
- -

getWebsite

-
    -
  • getWebsite(): Promise<string>
  • -
-
    -
  • - -
    -
    -

    returns the website

    -
    -
    -
    async
    -
    -
    throws
    -

    {UserNotFoundError}

    -
    -
    -
    -

    Returns Promise<string>

    -

    website

    -
  • -
-
-
- -

isEnabled

-
    -
  • isEnabled(): Promise<boolean>
  • -
-
    -
  • - -
    -
    -

    returns true if the user is enabled

    -
    -
    -
    async
    -
    -
    throws
    -

    {UserNotFoundError}

    -
    -
    -
    -

    Returns Promise<boolean>

    -

    true if the user is enabled

    -
  • -
-
-
- -

isSuperAdmin

-
    -
  • isSuperAdmin(): Promise<boolean>
  • -
-
    -
  • - -
    -
    -

    true if the user is a superadmin

    -
    -
    -
    async
    -
    -
    throws
    -

    {UserNotFoundError}

    -
    -
    -
    -

    Returns Promise<boolean>

    -

    true if the user is a superadmin

    -
  • -
-
-
- -

promoteToSuperAdmin

-
    -
  • promoteToSuperAdmin(): Promise<void>
  • -
-
    -
  • - -
    -
    -

    promote user to super admin

    -
    -
    -
    async
    -
    -
    throws
    -

    {UserNotFoundError}

    -
    -
    throws
    -

    {UserGroupDoesNotExistError}

    -
    -
    throws
    -

    {InsufficientPrivilegesError}

    -
    -
    throws
    -

    {OperationFailedError}

    -
    -
    -
    -

    Returns Promise<void>

    -
  • -
-
-
- -

promoteToUserGroupSubadmin

-
    -
  • promoteToUserGroupSubadmin(userGroup: UserGroup): Promise<void>
  • -
-
    -
  • - -
    -
    -

    promote the user to be a subadmin of the user group

    -
    -
    -
    async
    -
    -
    throws
    -

    {UserNotFoundError}

    -
    -
    throws
    -

    {UserGroupDoesNotExistError}

    -
    -
    throws
    -

    {InsufficientPrivilegesError}

    -
    -
    throws
    -

    {OperationFailedError}

    -
    -
    -
    -

    Parameters

    -
      -
    • -
      userGroup: UserGroup
      -
      -

      the user group

      -
      -
    • -
    -

    Returns Promise<void>

    -
  • -
-
-
- -

removeFromMemberUserGroup

-
    -
  • removeFromMemberUserGroup(userGroup: UserGroup): Promise<void>
  • -
-
    -
  • - -
    -
    -

    remove the user from a user group as member

    -
    -
    -
    async
    -
    -
    throws
    -

    {UserNotFoundError}

    -
    -
    throws
    -

    {UserGroupDoesNotExistError}

    -
    -
    throws
    -

    {InsufficientPrivilegesError}

    -
    -
    throws
    -

    {OperationFailedError}

    -
    -
    -
    -

    Parameters

    -
      -
    • -
      userGroup: UserGroup
      -
      -

      the user group

      -
      -
    • -
    -

    Returns Promise<void>

    -
  • -
-
-
- -

resendWelcomeEmail

-
    -
  • resendWelcomeEmail(): Promise<void>
  • -
-
    -
  • - -
    -
    -

    resends the welcome email

    -
    -
    -
    async
    -
    -
    throws
    -

    {UserResendWelcomeEmailError}

    -
    -
    -
    -

    Returns Promise<void>

    -
  • -
-
-
- -

setAddress

-
    -
  • setAddress(value: string): Promise<void>
  • -
-
    -
  • - -
    -
    -

    set the address

    -
    -
    -
    async
    -
    -
    throws
    -

    {UserNotFoundError}

    -
    -
    throws
    -

    {UserUpdateError}

    -
    -
    -
    -

    Parameters

    -
      -
    • -
      value: string
      -
      -

      the address

      -
      -
    • -
    -

    Returns Promise<void>

    -
  • -
-
-
- -

setDisplayName

-
    -
  • setDisplayName(value: string): Promise<void>
  • -
-
    -
  • - -
    -
    -

    set the display name

    -
    -
    -
    async
    -
    -
    throws
    -

    {UserNotFoundError}

    -
    -
    throws
    -

    {UserUpdateError}

    -
    -
    -
    -

    Parameters

    -
      -
    • -
      value: string
      -
      -

      the display name

      -
      -
    • -
    -

    Returns Promise<void>

    -
  • -
-
-
- -

setEmail

-
    -
  • setEmail(value: string): Promise<void>
  • -
-
    -
  • - -
    -
    -

    set the email address

    -
    -
    -
    async
    -
    -
    throws
    -

    {UserNotFoundError}

    -
    -
    throws
    -

    {UserUpdateError}

    -
    -
    -
    -

    Parameters

    -
      -
    • -
      value: string
      -
      -

      the email address

      -
      -
    • -
    -

    Returns Promise<void>

    -
  • -
-
-
- -

setLanguage

-
    -
  • setLanguage(value: string): Promise<void>
  • -
-
    -
  • - -
    -
    -

    set the language code like EN, DE, FR...

    -
    -
    -
    async
    -
    -
    throws
    -

    {UserNotFoundError}

    -
    -
    throws
    -

    {UserUpdateError}

    -
    -
    -
    -

    Parameters

    -
      -
    • -
      value: string
      -
      -

      the language code

      -
      -
    • -
    -

    Returns Promise<void>

    -
  • -
-
-
- -

setLocale

-
    -
  • setLocale(value: string): Promise<void>
  • -
-
    -
  • - -
    -
    -

    set the locale like EN, DE, FR...

    -
    -
    -
    async
    -
    -
    throws
    -

    {UserNotFoundError}

    -
    -
    throws
    -

    {UserUpdateError}

    -
    -
    -
    -

    Parameters

    -
      -
    • -
      value: string
      -
      -

      the locale

      -
      -
    • -
    -

    Returns Promise<void>

    -
  • -
-
-
- -

setPassword

-
    -
  • setPassword(value: string): Promise<void>
  • -
-
    -
  • - -
    -
    -

    set the password

    -
    -
    -
    async
    -
    -
    throws
    -

    {UserNotFoundError}

    -
    -
    throws
    -

    {UserUpdateError}

    -
    -
    -
    -

    Parameters

    -
      -
    • -
      value: string
      -
      -

      the password

      -
      -
    • -
    -

    Returns Promise<void>

    -
  • -
-
-
- -

setPhone

-
    -
  • setPhone(value: string): Promise<void>
  • -
-
    -
  • - -
    -
    -

    set phone number

    -
    -
    -
    async
    -
    -
    throws
    -

    {UserNotFoundError}

    -
    -
    throws
    -

    {UserUpdateError}

    -
    -
    -
    -

    Parameters

    -
      -
    • -
      value: string
      -
      -

      the phone number

      -
      -
    • -
    -

    Returns Promise<void>

    -
  • -
-
-
- -

setQuota

-
    -
  • setQuota(value: string): Promise<void>
  • -
-
    -
  • - -
    -
    -

    sets the quota limit of the user

    -
    -
    -
    async
    -
    -
    throws
    -

    {UserNotFoundError}

    -
    -
    throws
    -

    {UserUpdateError}

    -
    -
    -
    -

    Parameters

    -
      -
    • -
      value: string
      -
      -

      the quota string like "1 GB", "100 MB"

      -
      -
    • -
    -

    Returns Promise<void>

    -
  • -
-
-
- -

setTwitter

-
    -
  • setTwitter(value: string): Promise<void>
  • -
-
    -
  • - -
    -
    -

    set the twitter handle

    -
    -
    -
    async
    -
    -
    throws
    -

    {UserNotFoundError}

    -
    -
    throws
    -

    {UserUpdateError}

    -
    -
    -
    -

    Parameters

    -
      -
    • -
      value: string
      -
      -

      the twitter handle

      -
      -
    • -
    -

    Returns Promise<void>

    -
  • -
-
-
- -

setWebsite

-
    -
  • setWebsite(value: string): Promise<void>
  • -
-
    -
  • - -
    -
    -

    set the website

    -
    -
    -
    async
    -
    -
    throws
    -

    {UserNotFoundError}

    -
    -
    throws
    -

    {UserUpdateError}

    -
    -
    -
    -

    Parameters

    -
      -
    • -
      value: string
      -
      -

      the website

      -
      -
    • -
    -

    Returns Promise<void>

    -
  • -
-
-
-
- -
-
-
-
-

Legend

-
-
    -
  • Constructor
  • -
  • Property
  • -
  • Method
  • -
-
    -
  • Inherited constructor
  • -
  • Inherited property
  • -
  • Inherited method
  • -
-
    -
  • Protected property
  • -
  • Protected method
  • -
-
    -
  • Static property
  • -
  • Static method
  • -
-
    -
  • Property
  • -
-
-
-
-
-

Generated using TypeDoc

-
-
- - - \ No newline at end of file diff --git a/docs/api/classes/useralreadyexistserror.html b/docs/api/classes/useralreadyexistserror.html deleted file mode 100644 index 1531b834..00000000 --- a/docs/api/classes/useralreadyexistserror.html +++ /dev/null @@ -1,243 +0,0 @@ - - - - - - UserAlreadyExistsError | nextcloud-node-client - - - - - -
-
-
-
- -
-
- Options -
-
- All -
    -
  • Public
  • -
  • Public/Protected
  • -
  • All
  • -
-
- - -
-
- Menu -
-
-
-
-
-
- -

Class UserAlreadyExistsError

-
-
-
-
-
-
-
-
-
-

user already exists

-
-
-
-
-

Hierarchy

-
    -
  • - BaseError -
      -
    • - UserAlreadyExistsError -
    • -
    -
  • -
-
-
-

Index

-
-
-
-

Constructors

- -
-
-

Properties

- -
-
-
-
-
-

Constructors

-
- -

constructor

- - -
-
-
-

Properties

-
- -

message

-
message: string
- -
-
- -

name

-
name: string
- -
-
- -

Optional stack

-
stack: undefined | string
- -
-
-
- -
-
-
-
-

Legend

-
-
    -
  • Constructor
  • -
  • Property
  • -
  • Method
  • -
-
    -
  • Inherited constructor
  • -
  • Inherited property
  • -
  • Inherited method
  • -
-
    -
  • Protected property
  • -
  • Protected method
  • -
-
    -
  • Static property
  • -
  • Static method
  • -
-
    -
  • Property
  • -
-
-
-
-
-

Generated using TypeDoc

-
-
- - - \ No newline at end of file diff --git a/docs/api/classes/usercreateerror.html b/docs/api/classes/usercreateerror.html deleted file mode 100644 index 7344dd9c..00000000 --- a/docs/api/classes/usercreateerror.html +++ /dev/null @@ -1,243 +0,0 @@ - - - - - - UserCreateError | nextcloud-node-client - - - - - -
-
-
-
- -
-
- Options -
-
- All -
    -
  • Public
  • -
  • Public/Protected
  • -
  • All
  • -
-
- - -
-
- Menu -
-
-
-
-
-
- -

Class UserCreateError

-
-
-
-
-
-
-
-
-
-

error creating user

-
-
-
-
-

Hierarchy

-
    -
  • - BaseError -
      -
    • - UserCreateError -
    • -
    -
  • -
-
-
-

Index

-
-
-
-

Constructors

- -
-
-

Properties

- -
-
-
-
-
-

Constructors

-
- -

constructor

- - -
-
-
-

Properties

-
- -

message

-
message: string
- -
-
- -

name

-
name: string
- -
-
- -

Optional stack

-
stack: undefined | string
- -
-
-
- -
-
-
-
-

Legend

-
-
    -
  • Constructor
  • -
  • Property
  • -
  • Method
  • -
-
    -
  • Inherited constructor
  • -
  • Inherited property
  • -
  • Inherited method
  • -
-
    -
  • Protected property
  • -
  • Protected method
  • -
-
    -
  • Static property
  • -
  • Static method
  • -
-
    -
  • Property
  • -
-
-
-
-
-

Generated using TypeDoc

-
-
- - - \ No newline at end of file diff --git a/docs/api/classes/usergroup.html b/docs/api/classes/usergroup.html deleted file mode 100644 index 80ef0bf1..00000000 --- a/docs/api/classes/usergroup.html +++ /dev/null @@ -1,291 +0,0 @@ - - - - - - UserGroup | nextcloud-node-client - - - - - -
-
-
-
- -
-
- Options -
-
- All -
    -
  • Public
  • -
  • Public/Protected
  • -
  • All
  • -
-
- - -
-
- Menu -
-
-
-
-
-
- -

Class UserGroup

-
-
-
-
-
-
-
-
-
-

The user group class represents a user user in nextcloud. - spec: https://docs.nextcloud.com/server/latest/admin_manual/configuration_user/instruction_set_for_groups.html - id - getSubAdmins - getMembers

-
-
-
-
-

Hierarchy

-
    -
  • - UserGroup -
  • -
-
-
-

Index

-
-
-
-

Constructors

- -
-
-

Properties

- -
-
-

Methods

- -
-
-
-
-
-

Constructors

-
- -

constructor

- - -
-
-
-

Properties

-
- -

Readonly id

-
id: string
- -
-
-
-

Methods

-
- -

delete

-
    -
  • delete(): Promise<void>
  • -
-
    -
  • - -
    -
    -

    deletes the user group

    -
    -
    -
    throws
    -

    UserGroupDeletionFailedError

    -
    -
    -
    -

    Returns Promise<void>

    -
  • -
-
-
- -

getMemberUserIds

-
    -
  • getMemberUserIds(): Promise<string[]>
  • -
- -
-
- -

getSubadminUserIds

-
    -
  • getSubadminUserIds(): Promise<string[]>
  • -
- -
-
-
- -
-
-
-
-

Legend

-
-
    -
  • Constructor
  • -
  • Property
  • -
  • Method
  • -
-
    -
  • Inherited constructor
  • -
  • Inherited property
  • -
  • Inherited method
  • -
-
    -
  • Protected property
  • -
  • Protected method
  • -
-
    -
  • Static property
  • -
  • Static method
  • -
-
    -
  • Property
  • -
-
-
-
-
-

Generated using TypeDoc

-
-
- - - \ No newline at end of file diff --git a/docs/api/classes/usergroupalreadyexistserror.html b/docs/api/classes/usergroupalreadyexistserror.html deleted file mode 100644 index 08e5bae6..00000000 --- a/docs/api/classes/usergroupalreadyexistserror.html +++ /dev/null @@ -1,243 +0,0 @@ - - - - - - UserGroupAlreadyExistsError | nextcloud-node-client - - - - - -
-
-
-
- -
-
- Options -
-
- All -
    -
  • Public
  • -
  • Public/Protected
  • -
  • All
  • -
-
- - -
-
- Menu -
-
-
-
-
-
- -

Class UserGroupAlreadyExistsError

-
-
-
-
-
-
-
-
-
-

user group already exists

-
-
-
-
-

Hierarchy

-
    -
  • - BaseError -
      -
    • - UserGroupAlreadyExistsError -
    • -
    -
  • -
-
-
-

Index

-
-
-
-

Constructors

- -
-
-

Properties

- -
-
-
-
-
-

Constructors

-
- -

constructor

- - -
-
-
-

Properties

-
- -

message

-
message: string
- -
-
- -

name

-
name: string
- -
-
- -

Optional stack

-
stack: undefined | string
- -
-
-
- -
-
-
-
-

Legend

-
-
    -
  • Constructor
  • -
  • Property
  • -
  • Method
  • -
-
    -
  • Inherited constructor
  • -
  • Inherited property
  • -
  • Inherited method
  • -
-
    -
  • Protected property
  • -
  • Protected method
  • -
-
    -
  • Static property
  • -
  • Static method
  • -
-
    -
  • Property
  • -
-
-
-
-
-

Generated using TypeDoc

-
-
- - - \ No newline at end of file diff --git a/docs/api/classes/usergroupdeletionfailederror.html b/docs/api/classes/usergroupdeletionfailederror.html deleted file mode 100644 index 13203418..00000000 --- a/docs/api/classes/usergroupdeletionfailederror.html +++ /dev/null @@ -1,243 +0,0 @@ - - - - - - UserGroupDeletionFailedError | nextcloud-node-client - - - - - -
-
-
-
- -
-
- Options -
-
- All -
    -
  • Public
  • -
  • Public/Protected
  • -
  • All
  • -
-
- - -
-
- Menu -
-
-
-
-
-
- -

Class UserGroupDeletionFailedError

-
-
-
-
-
-
-
-
-
-

user group cloud not be deleted

-
-
-
-
-

Hierarchy

-
    -
  • - BaseError -
      -
    • - UserGroupDeletionFailedError -
    • -
    -
  • -
-
-
-

Index

-
-
-
-

Constructors

- -
-
-

Properties

- -
-
-
-
-
-

Constructors

-
- -

constructor

- - -
-
-
-

Properties

-
- -

message

-
message: string
- -
-
- -

name

-
name: string
- -
-
- -

Optional stack

-
stack: undefined | string
- -
-
-
- -
-
-
-
-

Legend

-
-
    -
  • Constructor
  • -
  • Property
  • -
  • Method
  • -
-
    -
  • Inherited constructor
  • -
  • Inherited property
  • -
  • Inherited method
  • -
-
    -
  • Protected property
  • -
  • Protected method
  • -
-
    -
  • Static property
  • -
  • Static method
  • -
-
    -
  • Property
  • -
-
-
-
-
-

Generated using TypeDoc

-
-
- - - \ No newline at end of file diff --git a/docs/api/classes/usergroupdoesnotexisterror.html b/docs/api/classes/usergroupdoesnotexisterror.html deleted file mode 100644 index 36d1f560..00000000 --- a/docs/api/classes/usergroupdoesnotexisterror.html +++ /dev/null @@ -1,243 +0,0 @@ - - - - - - UserGroupDoesNotExistError | nextcloud-node-client - - - - - -
-
-
-
- -
-
- Options -
-
- All -
    -
  • Public
  • -
  • Public/Protected
  • -
  • All
  • -
-
- - -
-
- Menu -
-
-
-
-
-
- -

Class UserGroupDoesNotExistError

-
-
-
-
-
-
-
-
-
-

user group does not exist

-
-
-
-
-

Hierarchy

-
    -
  • - BaseError -
      -
    • - UserGroupDoesNotExistError -
    • -
    -
  • -
-
-
-

Index

-
-
-
-

Constructors

- -
-
-

Properties

- -
-
-
-
-
-

Constructors

-
- -

constructor

- - -
-
-
-

Properties

-
- -

message

-
message: string
- -
-
- -

name

-
name: string
- -
-
- -

Optional stack

-
stack: undefined | string
- -
-
-
- -
-
-
-
-

Legend

-
-
    -
  • Constructor
  • -
  • Property
  • -
  • Method
  • -
-
    -
  • Inherited constructor
  • -
  • Inherited property
  • -
  • Inherited method
  • -
-
    -
  • Protected property
  • -
  • Protected method
  • -
-
    -
  • Static property
  • -
  • Static method
  • -
-
    -
  • Property
  • -
-
-
-
-
-

Generated using TypeDoc

-
-
- - - \ No newline at end of file diff --git a/docs/api/classes/usernotfounderror.html b/docs/api/classes/usernotfounderror.html deleted file mode 100644 index aa1cd959..00000000 --- a/docs/api/classes/usernotfounderror.html +++ /dev/null @@ -1,243 +0,0 @@ - - - - - - UserNotFoundError | nextcloud-node-client - - - - - -
-
-
-
- -
-
- Options -
-
- All -
    -
  • Public
  • -
  • Public/Protected
  • -
  • All
  • -
-
- - -
-
- Menu -
-
-
-
-
-
- -

Class UserNotFoundError

-
-
-
-
-
-
-
-
-
-

user not found

-
-
-
-
-

Hierarchy

-
    -
  • - BaseError -
      -
    • - UserNotFoundError -
    • -
    -
  • -
-
-
-

Index

-
-
-
-

Constructors

- -
-
-

Properties

- -
-
-
-
-
-

Constructors

-
- -

constructor

- - -
-
-
-

Properties

-
- -

message

-
message: string
- -
-
- -

name

-
name: string
- -
-
- -

Optional stack

-
stack: undefined | string
- -
-
-
- -
-
-
-
-

Legend

-
-
    -
  • Constructor
  • -
  • Property
  • -
  • Method
  • -
-
    -
  • Inherited constructor
  • -
  • Inherited property
  • -
  • Inherited method
  • -
-
    -
  • Protected property
  • -
  • Protected method
  • -
-
    -
  • Static property
  • -
  • Static method
  • -
-
    -
  • Property
  • -
-
-
-
-
-

Generated using TypeDoc

-
-
- - - \ No newline at end of file diff --git a/docs/api/classes/userresendwelcomeemailerror.html b/docs/api/classes/userresendwelcomeemailerror.html deleted file mode 100644 index 146e06b0..00000000 --- a/docs/api/classes/userresendwelcomeemailerror.html +++ /dev/null @@ -1,243 +0,0 @@ - - - - - - UserResendWelcomeEmailError | nextcloud-node-client - - - - - -
-
-
-
- -
-
- Options -
-
- All -
    -
  • Public
  • -
  • Public/Protected
  • -
  • All
  • -
-
- - -
-
- Menu -
-
-
-
-
-
- -

Class UserResendWelcomeEmailError

-
-
-
-
-
-
-
-
-
-

Error sending user welcome email

-
-
-
-
-

Hierarchy

-
    -
  • - BaseError -
      -
    • - UserResendWelcomeEmailError -
    • -
    -
  • -
-
-
-

Index

-
-
-
-

Constructors

- -
-
-

Properties

- -
-
-
-
-
-

Constructors

-
- -

constructor

- - -
-
-
-

Properties

-
- -

message

-
message: string
- -
-
- -

name

-
name: string
- -
-
- -

Optional stack

-
stack: undefined | string
- -
-
-
- -
-
-
-
-

Legend

-
-
    -
  • Constructor
  • -
  • Property
  • -
  • Method
  • -
-
    -
  • Inherited constructor
  • -
  • Inherited property
  • -
  • Inherited method
  • -
-
    -
  • Protected property
  • -
  • Protected method
  • -
-
    -
  • Static property
  • -
  • Static method
  • -
-
    -
  • Property
  • -
-
-
-
-
-

Generated using TypeDoc

-
-
- - - \ No newline at end of file diff --git a/docs/api/classes/userupdateerror.html b/docs/api/classes/userupdateerror.html deleted file mode 100644 index 269147c5..00000000 --- a/docs/api/classes/userupdateerror.html +++ /dev/null @@ -1,243 +0,0 @@ - - - - - - UserUpdateError | nextcloud-node-client - - - - - -
-
-
-
- -
-
- Options -
-
- All -
    -
  • Public
  • -
  • Public/Protected
  • -
  • All
  • -
-
- - -
-
- Menu -
-
-
-
-
-
- -

Class UserUpdateError

-
-
-
-
-
-
-
-
-
-

error updating user

-
-
-
-
-

Hierarchy

-
    -
  • - BaseError -
      -
    • - UserUpdateError -
    • -
    -
  • -
-
-
-

Index

-
-
-
-

Constructors

- -
-
-

Properties

- -
-
-
-
-
-

Constructors

-
- -

constructor

- - -
-
-
-

Properties

-
- -

message

-
message: string
- -
-
- -

name

-
name: string
- -
-
- -

Optional stack

-
stack: undefined | string
- -
-
-
- -
-
-
-
-

Legend

-
-
    -
  • Constructor
  • -
  • Property
  • -
  • Method
  • -
-
    -
  • Inherited constructor
  • -
  • Inherited property
  • -
  • Inherited method
  • -
-
    -
  • Protected property
  • -
  • Protected method
  • -
-
    -
  • Static property
  • -
  • Static method
  • -
-
    -
  • Property
  • -
-
-
-
-
-

Generated using TypeDoc

-
-
- - - \ No newline at end of file diff --git a/docs/api/enums/commandstatus.html b/docs/api/enums/commandstatus.html deleted file mode 100644 index 21990f92..00000000 --- a/docs/api/enums/commandstatus.html +++ /dev/null @@ -1,225 +0,0 @@ - - - - - - CommandStatus | nextcloud-node-client - - - - - -
-
-
-
- -
-
- Options -
-
- All -
    -
  • Public
  • -
  • Public/Protected
  • -
  • All
  • -
-
- - -
-
- Menu -
-
-
-
-
-
- -

Enumeration CommandStatus

-
-
-
-
-
-
-
-
-
-

The potential states that a command can have. - When a command is created, the state is "initial" - When the execution has started, the status is "running" - When the execution has finsihed, the status can be "succes" or "failed"

-
-
-
-
-

Index

-
-
-
-

Enumeration members

- -
-
-
-
-
-

Enumeration members

-
- -

failed

-
failed: = "failed"
- -
-
-

After unsuccessfull execution of the command, the status is "failed"

-
-
-
-
- -

initial

-
initial: = "initial"
- -
-
-

When a command is created, the state is "initial"

-
-
-
-
- -

running

-
running: = "running"
- -
-
-

When the execution has started, the status is "running"

-
-
-
-
- -

success

-
success: = "success"
- -
-
-

After successful execution of the command, the status is "success"

-
-
-
-
-
- -
-
-
-
-

Legend

-
-
    -
  • Constructor
  • -
  • Property
  • -
  • Method
  • -
-
    -
  • Inherited constructor
  • -
  • Inherited property
  • -
  • Inherited method
  • -
-
    -
  • Protected property
  • -
  • Protected method
  • -
-
    -
  • Static property
  • -
  • Static method
  • -
-
    -
  • Property
  • -
-
-
-
-
-

Generated using TypeDoc

-
-
- - - \ No newline at end of file diff --git a/docs/api/enums/shareitemtype.html b/docs/api/enums/shareitemtype.html deleted file mode 100644 index c58e92e4..00000000 --- a/docs/api/enums/shareitemtype.html +++ /dev/null @@ -1,167 +0,0 @@ - - - - - - ShareItemType | nextcloud-node-client - - - - - -
-
-
-
- -
-
- Options -
-
- All -
    -
  • Public
  • -
  • Public/Protected
  • -
  • All
  • -
-
- - -
-
- Menu -
-
-
-
-
-
- -

Enumeration ShareItemType

-
-
-
-
-
-
-
-

Index

-
-
-
-

Enumeration members

- -
-
-
-
-
-

Enumeration members

-
- -

file

-
file: = "file"
- -
-
- -

folder

-
folder: = "folder"
- -
-
-
- -
-
-
-
-

Legend

-
-
    -
  • Constructor
  • -
  • Property
  • -
  • Method
  • -
-
    -
  • Inherited constructor
  • -
  • Inherited property
  • -
  • Inherited method
  • -
-
    -
  • Protected property
  • -
  • Protected method
  • -
-
    -
  • Static property
  • -
  • Static method
  • -
-
    -
  • Property
  • -
-
-
-
-
-

Generated using TypeDoc

-
-
- - - \ No newline at end of file diff --git a/docs/api/enums/sharepermission.html b/docs/api/enums/sharepermission.html deleted file mode 100644 index 8a2b0cbb..00000000 --- a/docs/api/enums/sharepermission.html +++ /dev/null @@ -1,223 +0,0 @@ - - - - - - SharePermission | nextcloud-node-client - - - - - -
-
-
-
- -
-
- Options -
-
- All -
    -
  • Public
  • -
  • Public/Protected
  • -
  • All
  • -
-
- - -
-
- Menu -
-
-
-
-
-
- -

Enumeration SharePermission

-
-
-
-
-
-
-
-

Index

-
-
-
-

Enumeration members

- -
-
-
-
-
-

Enumeration members

-
- -

all

-
all: = 31
- -
-
- -

create

-
create: = 4
- -
-
- -

delete

-
delete: = 8
- -
-
- -

read

-
read: = 1
- -
-
- -

share

-
share: = 16
- -
-
- -

update

-
update: = 2
- -
-
-
- -
-
-
-
-

Legend

-
-
    -
  • Constructor
  • -
  • Property
  • -
  • Method
  • -
-
    -
  • Inherited constructor
  • -
  • Inherited property
  • -
  • Inherited method
  • -
-
    -
  • Protected property
  • -
  • Protected method
  • -
-
    -
  • Static property
  • -
  • Static method
  • -
-
    -
  • Property
  • -
-
-
-
-
-

Generated using TypeDoc

-
-
- - - \ No newline at end of file diff --git a/docs/api/enums/sharetype.html b/docs/api/enums/sharetype.html deleted file mode 100644 index 17adefb6..00000000 --- a/docs/api/enums/sharetype.html +++ /dev/null @@ -1,195 +0,0 @@ - - - - - - ShareType | nextcloud-node-client - - - - - -
-
-
-
- -
-
- Options -
-
- All -
    -
  • Public
  • -
  • Public/Protected
  • -
  • All
  • -
-
- - -
-
- Menu -
-
-
-
-
-
- -

Enumeration ShareType

-
-
-
-
-
-
-
-

Index

-
-
-
-

Enumeration members

- -
-
-
-
-
-

Enumeration members

-
- -

email

-
email: = 4
- -
-
- -

group

-
group: = 1
- -
-
- -

publicLink

-
publicLink: = 3
- -
-
- -

user

-
user: = 0
- -
-
-
- -
-
-
-
-

Legend

-
-
    -
  • Constructor
  • -
  • Property
  • -
  • Method
  • -
-
    -
  • Inherited constructor
  • -
  • Inherited property
  • -
  • Inherited method
  • -
-
    -
  • Protected property
  • -
  • Protected method
  • -
-
    -
  • Static property
  • -
  • Static method
  • -
-
    -
  • Property
  • -
-
-
-
-
-

Generated using TypeDoc

-
-
- - - \ No newline at end of file diff --git a/docs/api/enums/userproperty.html b/docs/api/enums/userproperty.html deleted file mode 100644 index 7d242f00..00000000 --- a/docs/api/enums/userproperty.html +++ /dev/null @@ -1,279 +0,0 @@ - - - - - - UserProperty | nextcloud-node-client - - - - - -
-
-
-
- -
-
- Options -
-
- All -
    -
  • Public
  • -
  • Public/Protected
  • -
  • All
  • -
-
- - -
-
- Menu -
-
-
-
-
-
- -

Enumeration UserProperty

-
-
-
-
-
-
-
-

Index

-
-
-
-

Enumeration members

- -
-
-
-
-
-

Enumeration members

-
- -

address

-
address: = "address"
- -
-
- -

displayName

-
displayName: = "displayname"
- -
-
- -

email

-
email: = "email"
- -
-
- -

language

-
language: = "language"
- -
-
- -

locale

-
locale: = "locale"
- -
-
- -

password

-
password: = "password"
- -
-
- -

phone

-
phone: = "phone"
- -
-
- -

quota

-
quota: = "quota"
- -
-
- -

twitter

-
twitter: = "twitter"
- -
-
- -

website

-
website: = "website"
- -
-
-
- -
-
-
-
-

Legend

-
-
    -
  • Constructor
  • -
  • Property
  • -
  • Method
  • -
-
    -
  • Inherited constructor
  • -
  • Inherited property
  • -
  • Inherited method
  • -
-
    -
  • Protected property
  • -
  • Protected method
  • -
-
    -
  • Static property
  • -
  • Static method
  • -
-
    -
  • Property
  • -
-
-
-
-
-

Generated using TypeDoc

-
-
- - - \ No newline at end of file diff --git a/docs/api/globals.html b/docs/api/globals.html deleted file mode 100644 index 6a53d61d..00000000 --- a/docs/api/globals.html +++ /dev/null @@ -1,591 +0,0 @@ - - - - - - nextcloud-node-client - - - - - -
-
-
-
- -
-
- Options -
-
- All -
    -
  • Public
  • -
  • Public/Protected
  • -
  • All
  • -
-
- - -
-
- Menu -
-
-
-
-
-
- -

nextcloud-node-client

-
-
-
-
-
-
-
-

Index

-
-
-
-

Enumerations

- -
-
-

Classes

- -
-
-

Interfaces

- -
-
-

Variables

- -
-
-

Functions

- -
-
-
-
-
-

Variables

-
- -

Const HttpProxyAgent

-
HttpProxyAgent: any = require('http-proxy-agent')
- -
-
- -

Let client

-
client: Client
- -
-
- -

Const debug

-
debug: any = require("debug").debug("DownloadFilesCommand")
- -
-
- -

Const log

-
log: Logger = new Logger()
- -
-
- -

Const readdir

-
readdir: __promisify__ = util.promisify(fs.readdir)
- -
-
- -

Const stat

-
stat: __promisify__ = util.promisify(fs.stat)
- -
-
-
-

Functions

-
- -

Const getNextcloudClient

-
    -
  • getNextcloudClient(context: string): Promise<Client>
  • -
- -
-
- -

Const recordingModeActive

-
    -
  • recordingModeActive(): boolean
  • -
- -
-
-
- -
-
-
-
-

Legend

-
-
    -
  • Constructor
  • -
  • Property
  • -
  • Method
  • -
-
    -
  • Inherited constructor
  • -
  • Inherited property
  • -
  • Inherited method
  • -
-
    -
  • Protected property
  • -
  • Protected method
  • -
-
    -
  • Static property
  • -
  • Static method
  • -
-
    -
  • Property
  • -
-
-
-
-
-

Generated using TypeDoc

-
-
- - - \ No newline at end of file diff --git a/docs/api/index.html b/docs/api/index.html deleted file mode 100644 index 02d67118..00000000 --- a/docs/api/index.html +++ /dev/null @@ -1,904 +0,0 @@ - - - - - - nextcloud-node-client - - - - - -
-
-
-
- -
-
- Options -
-
- All -
    -
  • Public
  • -
  • Public/Protected
  • -
  • All
  • -
-
- - -
-
- Menu -
-
-
-
-
-
- -

nextcloud-node-client

-
-
-
-
-
-
-
- -

nextcloud-node-client

-
- -

Access nextcloud remotely from node.js applications with a rich and simple TypeScript / JavaScript API.

-

lang: Typescript - - NPM Downloads - Dependency Status - Coverage Status - Install Size - documentation

-
    -
  • upload and download files
  • -
  • create files and folder structures
  • -
  • all user management functions
  • -
  • create shares
  • -
  • tagging and commenting
  • -
-

The nextcloud node client is used to automate access to nextcloud servers from node.js apppliactions.

- -

Example

-
-
// typescript
-import Client, { File, Folder, Tag, Share } from "nextcloud-node-client";
-
-(async () => {
-    try {
-        // create a new client using connectivity information from environment 
-        const client = new Client();
-        // create a folder structure if not available
-        const folder: Folder = await client.createFolder("folder/subfolder");
-        // create file within the folder
-        const file: File = await folder.createFile("myFile.txt", Buffer.from("My file content"));
-        // add a tag to the file and create the tag if not existing
-        await file.addTag("MyTag");
-        // add a comment to the file
-        await file.addComment("myComment");
-        // get the file content
-        const content: Buffer = await file.getContent();
-        // share the file publicly with password and note
-        const share: Share = await client.createShare({ fileSystemElement: file });
-        await share.setPassword("some password");
-        await share.setNote("some note\nnew line");
-        // use the url to access the share 
-        const shareLink:string = share.url;
-        // delete the folder including the file and share
-        await folder.delete();
-    } catch (e) {
-        // some error handling   
-        console.log(e);
-    }
-})();
- -

Documentation

-
- - -

Installation

-
-

npm install nextcloud-node-client

- -

Security and access management

-
-

The client requires the url of the nextcloud server and the credentials.

-

Use an app specific password generated in the security - devices & sessions section of the nextcloud settings.

- -

Environment

-
-

Credentials can be specified in the environment:

-
NEXTCLOUD_USERNAME= "<your user name>"
-NEXTCLOUD_PASSWORD = "<your password>"
-NEXTCLOUD_URL= "https://<your nextcloud host>"

The cloud service configuration VCAP_SERVICES can be used alternativley (refer to the Cloud Foundry documentation for details).

-

The nextcloud credentials are stored in the section for user provided services user-provided. - The client is able to access the service credentials by providing the instance name.

-
{
-    "user-provided": [
-        {
-            "credentials": {
-                "password": "<your password>",
-                "url": "https://<your nextcloud host>",
-                "username": "<your user name>"
-            },
-            "name": "<your service instance name>"
-        }
-    ]
-}
- -

Creating a client

-
-

Creating a nextcloud client

-
  // uses the environment to initialize
-  import Client from "nextcloud-node-client";
-  const client = new Client();
-
  // uses explicite credentials
-  import Client, { Server } from "nextcloud-node-client";
-  const server: Server = new Server(
-            { basicAuth:
-                { password: "<your password>",
-                  username: "<your user name>",
-                },
-                url: "https://<your nextcloud host>",
-            });
-
-  const client = new Client(server);
- -

Concepts and Philosophy

-
-

The nextcloud-node-client provids a object oriented API in TypeScript. The focus is to provide a simple access to the nextcloud resources rather than a full functional coverage.

-

nextcloud node client object model

-

The client comes with an object oriented API to access the APIs of nextcloud. The following object types are supported:

- -

Client

-
-

The client is the root object and represents the connection to the nextcloud server. The client is used to get access to the root folder and the tag repository.

- -

Folder

-
-

The folder is the representation of a nextcloud folder. It may contain many files. All files of a folder are deleted, if the folder is deleted.

- -

File

-
-

The file is the representation of a nextcloud file. Every file is contained in a folder.

- -

Tag

-
-

Tags are used to filter for file and folders. Tags can be created and assigned to files or folders.

- -

Share

-
-

Files and folders can be shared with user, user groups or publicly. The share can be password protected and an exiration date can be applied.

- -

API

-
-

This is an overview of the client API. - Details can be found in the API docs

- -

Client

-
-
    -
  • factory method for client
  • -
  • create folder
  • -
  • get folder, get root folder
  • -
  • create file
  • -
  • get file
  • -
  • create tag*
  • -
  • get tags, by name, by id
  • -
  • get quota
  • -
  • find users, get user by id
  • -
  • create user
  • -
  • mass creations and changes of users
  • -
  • get user groups, by id
  • -
  • create user group - -

    Folder

    -
    -
  • -
  • get name, id, base name, urls
  • -
  • delete
  • -
  • create sub folders
  • -
  • get sub folder
  • -
  • create file
  • -
  • get files
  • -
  • get tags, add tag, remove tag
  • -
  • add comment
  • -
  • get comments
  • -
  • move/rename - -

    File

    -
    -
  • -
  • get name, id, base name, urls, content type
  • -
  • get content
  • -
  • delete
  • -
  • get tags, add tag, remove tag
  • -
  • add comment
  • -
  • get comments
  • -
  • get folder
  • -
  • move/rename - -

    Tag

    -
    -
  • -
  • get name, id
  • -
  • delete* - -

    Share

    -
    -
  • -
  • create, update, delete - -

    User Group

    -
    -
  • -
  • delete
  • -
  • get members, get subadmins - -

    User

    -
    -
  • -
  • delete
  • -
  • get properties (display name, email, quota and usage, language, last login, ...)
  • -
  • change properties (display name, email, quota, language, password, ...)
  • -
  • send welcome email
  • -
  • enable / disable
  • -
  • promote to super admin / demote from super admin
  • -
  • get member groups, get subadmin groups
  • -
  • add to user group as member / remove from member user group
  • -
  • promote as subadmin for user group / demote from subadmin user group
  • -
-

* admin permissions required

- -

API Examples

-
- -

Quota

-
-
    const q: IQuota = await client.getQuota();
-    // { used: 479244777, available: 10278950773 }
- -

Sytem information

-
-
    const si: ISystemInfo = await client.getSystemInfo();  
- -

Create folder

-
-
    // create folder
-    const folder: Folder = await client.createFolder("/products/brooms");
-    // create subfolder
-    const subfolder: Folder = await folder.createSubFolder("soft brooms");
-    // "/products/brooms/soft brooms"
-
- -

Get folder(s)

-
-
    // get folder
-    const folder: Folder = await client.getFolder("/products");
-    // get subfolders
-    const subfolders: Folder[] = await folder.getSubFolders();    
- -

Delete folder

-
-
    // get folder
-    const folder: Folder = await client.getFolder("/products");
-    await folder.delete();
- -

Create file

-
-
    const folder = await client.getFolder("/products");
-    const file = folder.createFile("MyFile.txt", new Buffer("My new file"));
- -

Get file

-
-
    const file = await client.getFile("/products/MyFile.txt");
-    // or
-    const folder = await client.getFolder("/products");
-    const file = await folder.getFile("MyFile.txt");
-    // file: name, baseName, lastmod, size, mime
- -

Get file content

-
-
    const file = await client.getFile("/products/MyFile.txt");
-    const buffer = await file.getContent();
- -

Get file Url

-
-
    const file = await client.getFile("/products/MyFile.txt");
-    const url = await file.getUrl();
- -

Add tag to file

-
-
    const file = await client.getFile("/products/MyFile.txt");
-    await file.addTag("myTag");
- -

Delete file

-
-
    const file = await client.getFile("/products/MyFile.txt");
-    await file.delete();
- -

Get files

-
-
    const folder = await client.getFolder("/products");
-    const files = await folder.getFiles();
- -

Move and/or rename file

-
-
    const file = await client.getFile("/products/MyFile.txt");
-    await file.move("/products/brooms/MyFileRenamed.txt");
- -

Create, change and delete a share

-
-
    const file = await client.getFile("/products/MyFile.txt");
-    // share the file (works also for folder)
-    const createShare: ICreateShare = { fileSystemElement: file };
-    const share: Share = await client.createShare(createShare);
-    // change share settings
-    await share.setPassword("some password");
-    await share.setNote("some note\nnew line");
-    await share.setExpiration(new Date(2020, 11, 5));  
-    // use the url to access the share 
-    const shareLink:string = share.url;
-    // delete share, if not required anymore
-    await share.delete();
- -

Architecture

-
-

The nextcloud node client can be used by node applications to extend the nextcloud functionality remotely. The client uses only HTTP apis of nextcloud for access.

-

nextcloud node client component architecture

- -

Examples

-
- -

User management

-
-
// typescript
-import Client, { User, UserGroup } from "nextcloud-node-client";
-
-(async () => {
-    try {
-        // create a new client using connectivity 
-        // information from environment
-        const client = new Client();
-        // create a new user group
-        const group: UserGroup = await client.createUserGroup("MyGroup");
-        // create a new user with a email or password
-        const user: User = await client.createUser({ id: "MyUserId", email: "mail@example.com" });
-        // set some properties 
-        // ... password, phone, website, twitter, address, email, locale
-        await user.setDisplayName("My Display Name");
-        await user.setQuota("5 GB");
-        await user.setLanguage("en");
-        // get properties 
-        // ... quota, user friendly quota, phone, website, twitter, address, locale
-        const email = await user.getEmail();
-        // disable user
-        await user.disable();
-        // enable user
-        await user.enable();
-        // promote to super administrator
-        await user.promoteToSuperAdmin();
-        // demote from super administrator
-        await user.demoteFromSuperAdmin();
-        // resend welcome email to user
-        await user.resendWelcomeEmail();
-        // add to user group as member
-        await user.addToMemberUserGroup(group);
-        // get member user groups
-        const memberGroups: UserGroup[] = await user.getMemberUserGroups();
-        // get user ids of memembers
-        await group.getMemberUserIds();
-        // remove user from member group
-        await user.removeFromMemberUserGroup(group);
-        // promote user as subadmin for user group
-        await user.promoteToUserGroupSubadmin(group);
-        // get user groups where the user is subadmin
-        const subadminGroups: UserGroup[] = await user.getSubadminUserGroups();
-        // get user ids of subadmins
-        await group.getSubadminUserIds();
-        // demote user from being subadmin for user group
-        await user.demoteFromSubadminUserGroup(group);
-        // delete the user
-        await user.delete();
-        // delete the user group
-        await group.delete();
-        // mass creations / updates of users
-        // groups are created on the fly
-        await client.upsertUsers([
-            { id: "myUser1", email: "myUser1@example.com", enabled: false, memberGroups: ["group1", "group2"] },
-            { id: "myUser2", password: "mySecurePassword", displayName: "My Name", superAdmin: true, quota: "2 GB" },
-            // ...
-        ]);
-    } catch (e) {
-        // use specific exception *error classes 
-        // for error handling documented in @throws
-    }
-})();
- -

Tagging

-
-
// typescript
-import Client, { File, Folder, Share, Tag, FileSystemElement } from "nextcloud-node-client";
-
-(async () => {
-    try {
-        // create a new client using connectivity information from environment
-        const client = new Client();
-        // create a folder structure if not available
-        const folder: Folder = await client.createFolder("folder/subfolder");
-        // create file within the folder
-        const file: File = await folder.createFile("myFile.txt", Buffer.from("My file content"));
-        // create two tags
-        const tag1: Tag = await client.createTag("tag 1");
-        const tag2: Tag = await client.createTag("tag 2");
-        // assign tag to folder
-        folder.addTag(tag1.name);
-        // assign tag to files
-        file.addTag(tag1.name);
-        file.addTag(tag2.name);
-
-        // get list of file system elements with the tag1 assigned
-        let fse: FileSystemElement[] = await client.getFileSystemElementByTags([tag1]);
-        // print names of folder and file
-        console.log(fse[0].name);
-        console.log(fse[1].name);
-
-        // get list of file system elements with the tag1 and tag2
-        fse = await client.getFileSystemElementByTags([tag1, tag2]);
-        // print name of file
-        console.log(fse[0].name);
-
-        // delete the tags
-        await tag1.delete();
-        await tag2.delete();
-        // delete the folder including the file and share
-        await folder.delete();
-    } catch (e) {
-        // some error handling
-        console.log(e);
-    }
-})();
- -

Quality

-
-

Tested with nextcloud 17.0.1, 18.0.0

-

A code coverage of 100% is aspired

- -

Todo list

-
- -

Sharing

-
-

Share with

-
    -
  • user
  • -
  • usergroup
  • -
  • email-address
  • -
- -

Search

-
-
    -
  • Search for files api
  • -
  • client in github actions - upload files
  • -
- -

Server API

-
-
    -
  • support also the nextcloud server url instead of the WebDAV url only
  • -
- -

Download

-
-
    -
  • download folder contents example
  • -
  • download folder contents to disk recursively
  • -
- -

Upload

-
-
    -
  • upload local file on disk to nextcloud
  • -
  • upload local folder on disk to nextcloud recursively
  • -
- -

Get Files recursively

-
-
    -
  • command get files recurively
  • -
  • filter get files recurively
  • -
  • example get files recurively
  • -
- -

Access using tags

-
-

* Get files and folders by tags client.getFileSystemObjectByTags

- -

User management

-
-

User:

-
    -
  • get
  • -
  • getIds limit, offset, search
  • -
  • create
  • -
  • update
  • -
  • delete
  • -
  • deactivate
  • -
  • add/remove group member
  • -
  • add/remove group subadmin
  • -
  • example in readme
  • -
  • send notification
  • -
-

User group:

-
    -
  • get
  • -
  • create
  • -
  • delete
  • -
- -

Streams

-
-

Create file and get file using streams

- -

Eventing

-
-
    -
  • create event objects
  • -
  • start observer
  • -
  • subscribe to events and register handler functions
  • -
  • telegram support
  • -
- -

notifications

-
-

basic methods are available since 1.2.0 without strong typing

-
    -
  • notification object
  • -
- -

Refactoring

-
-
    -
  • Introduction of exception classes instead of error codes (breaking change)
  • -
  • Move from codecov to coveralls
  • -
  • move to eslint instead of using tslint
  • -
  • remove "I" from all interfaces - (breaking change)
  • -
- -

Search

-
-
    -
  • Search for files api
  • -
  • client in github actions - upload files
  • -
- -

License

-
-

Apache

-
-
- -
-
-
-
-

Legend

-
-
    -
  • Constructor
  • -
  • Property
  • -
  • Method
  • -
-
    -
  • Inherited constructor
  • -
  • Inherited property
  • -
  • Inherited method
  • -
-
    -
  • Protected property
  • -
  • Protected method
  • -
-
    -
  • Static property
  • -
  • Static method
  • -
-
    -
  • Property
  • -
-
-
-
-
-

Generated using TypeDoc

-
-
- - - \ No newline at end of file diff --git a/docs/api/interfaces/commandresultmetadata.html b/docs/api/interfaces/commandresultmetadata.html deleted file mode 100644 index 9dc56e58..00000000 --- a/docs/api/interfaces/commandresultmetadata.html +++ /dev/null @@ -1,196 +0,0 @@ - - - - - - CommandResultMetaData | nextcloud-node-client - - - - - -
-
-
-
- -
-
- Options -
-
- All -
    -
  • Public
  • -
  • Public/Protected
  • -
  • All
  • -
-
- - -
-
- Menu -
-
-
-
-
-
- -

Interface CommandResultMetaData

-
-
-
-
-
-
-
-
-
-

when the command has finished, the client can get the result of the command execution

-
-
-
-
-

Hierarchy

-
    -
  • - CommandResultMetaData -
  • -
-
-
-

Index

-
-
-
-

Properties

- -
-
-
-
-
-

Properties

-
- -

errors

-
errors: string[]
- -
-
- -

messages

-
messages: string[]
- -
-
- -

timeElapsed

-
timeElapsed: number
- -
-
-
- -
-
-
-
-

Legend

-
-
    -
  • Constructor
  • -
  • Property
  • -
  • Method
  • -
-
    -
  • Inherited constructor
  • -
  • Inherited property
  • -
  • Inherited method
  • -
-
    -
  • Protected property
  • -
  • Protected method
  • -
-
    -
  • Static property
  • -
  • Static method
  • -
-
    -
  • Property
  • -
-
-
-
-
-

Generated using TypeDoc

-
-
- - - \ No newline at end of file diff --git a/docs/api/interfaces/downloadfoldercommandoptions.html b/docs/api/interfaces/downloadfoldercommandoptions.html deleted file mode 100644 index ae9f378e..00000000 --- a/docs/api/interfaces/downloadfoldercommandoptions.html +++ /dev/null @@ -1,238 +0,0 @@ - - - - - - DownloadFolderCommandOptions | nextcloud-node-client - - - - - -
-
-
-
- -
-
- Options -
-
- All -
    -
  • Public
  • -
  • Public/Protected
  • -
  • All
  • -
-
- - -
-
- Menu -
-
-
-
-
-
- -

Interface DownloadFolderCommandOptions

-
-
-
-
-
-
-
-
-
-

options to create a download folder command

-
-
-
-
-

Hierarchy

-
    -
  • - DownloadFolderCommandOptions -
  • -
-
-
-

Index

-
- -
-
-
-

Properties

-
- -

Optional filterFile

-
filterFile: undefined | ((file: File) => File | null)
- -
-
-

function to filter files

-
-
-
-
- -

getTargetFileNameBeforeDownload

-
getTargetFileNameBeforeDownload: (fileNames: SourceTargetFileNames) => string
- -
-
-

the function to determine the target file name having the sourece file name. - If the file should not be downloaded, return an empty string

-
-
-
param
-

source and target file names

-
-
-
-
-

Type declaration

- -
-
-
- -

sourceFolder

-
sourceFolder: Folder
- -
-
-

The source folder with the file structure to be downloaded

-
-
-
-
-
- -
-
-
-
-

Legend

-
-
    -
  • Constructor
  • -
  • Property
  • -
  • Method
  • -
-
    -
  • Inherited constructor
  • -
  • Inherited property
  • -
  • Inherited method
  • -
-
    -
  • Protected property
  • -
  • Protected method
  • -
-
    -
  • Static property
  • -
  • Static method
  • -
-
    -
  • Property
  • -
-
-
-
-
-

Generated using TypeDoc

-
-
- - - \ No newline at end of file diff --git a/docs/api/interfaces/foldergetfilesoptions.html b/docs/api/interfaces/foldergetfilesoptions.html deleted file mode 100644 index 63559dc1..00000000 --- a/docs/api/interfaces/foldergetfilesoptions.html +++ /dev/null @@ -1,166 +0,0 @@ - - - - - - FolderGetFilesOptions | nextcloud-node-client - - - - - -
-
-
-
- -
-
- Options -
-
- All -
    -
  • Public
  • -
  • Public/Protected
  • -
  • All
  • -
-
- - -
-
- Menu -
-
-
-
-
-
- -

Interface FolderGetFilesOptions

-
-
-
-
-
-
-
-

Hierarchy

-
    -
  • - FolderGetFilesOptions -
  • -
-
-
-

Index

-
-
-
-

Properties

- -
-
-
-
-
-

Properties

-
- -

Optional filterFile

-
filterFile: undefined | ((file: File) => File | null)
- -
-
-

callback function to filter files

-
-
-
-
-
- -
-
-
-
-

Legend

-
-
    -
  • Constructor
  • -
  • Property
  • -
  • Method
  • -
-
    -
  • Inherited constructor
  • -
  • Inherited property
  • -
  • Inherited method
  • -
-
    -
  • Protected property
  • -
  • Protected method
  • -
-
    -
  • Static property
  • -
  • Static method
  • -
-
    -
  • Property
  • -
-
-
-
-
-

Generated using TypeDoc

-
-
- - - \ No newline at end of file diff --git a/docs/api/interfaces/getfilesrecursivelycommandoptions.html b/docs/api/interfaces/getfilesrecursivelycommandoptions.html deleted file mode 100644 index b3dccbdd..00000000 --- a/docs/api/interfaces/getfilesrecursivelycommandoptions.html +++ /dev/null @@ -1,185 +0,0 @@ - - - - - - GetFilesRecursivelyCommandOptions | nextcloud-node-client - - - - - -
-
-
-
- -
-
- Options -
-
- All -
    -
  • Public
  • -
  • Public/Protected
  • -
  • All
  • -
-
- - -
-
- Menu -
-
-
-
-
-
- -

Interface GetFilesRecursivelyCommandOptions

-
-
-
-
-
-
-
-

Hierarchy

-
    -
  • - GetFilesRecursivelyCommandOptions -
  • -
-
-
-

Index

-
-
-
-

Properties

- -
-
-
-
-
-

Properties

-
- -

Optional filterFile

-
filterFile: undefined | ((file: File) => File | null)
- -
-
-

function to filter files

-
-
-
-
- -

sourceFolder

-
sourceFolder: Folder
- -
-
-

the source nextcloud folder to start listing the files

-
-
-
-
-
- -
-
-
-
-

Legend

-
-
    -
  • Constructor
  • -
  • Property
  • -
  • Method
  • -
-
    -
  • Inherited constructor
  • -
  • Inherited property
  • -
  • Inherited method
  • -
-
    -
  • Protected property
  • -
  • Protected method
  • -
-
    -
  • Static property
  • -
  • Static method
  • -
-
    -
  • Property
  • -
-
-
-
-
-

Generated using TypeDoc

-
-
- - - \ No newline at end of file diff --git a/docs/api/interfaces/ibasicauth.html b/docs/api/interfaces/ibasicauth.html deleted file mode 100644 index 4c04cf15..00000000 --- a/docs/api/interfaces/ibasicauth.html +++ /dev/null @@ -1,175 +0,0 @@ - - - - - - IBasicAuth | nextcloud-node-client - - - - - -
-
-
-
- -
-
- Options -
-
- All -
    -
  • Public
  • -
  • Public/Protected
  • -
  • All
  • -
-
- - -
-
- Menu -
-
-
-
-
-
- -

Interface IBasicAuth

-
-
-
-
-
-
-
-

Hierarchy

-
    -
  • - IBasicAuth -
  • -
-
-
-

Index

-
-
-
-

Properties

- -
-
-
-
-
-

Properties

-
- -

password

-
password: string
- -
-
- -

username

-
username: string
- -
-
-
- -
-
-
-
-

Legend

-
-
    -
  • Constructor
  • -
  • Property
  • -
  • Method
  • -
-
    -
  • Inherited constructor
  • -
  • Inherited property
  • -
  • Inherited method
  • -
-
    -
  • Protected property
  • -
  • Protected method
  • -
-
    -
  • Static property
  • -
  • Static method
  • -
-
    -
  • Property
  • -
-
-
-
-
-

Generated using TypeDoc

-
-
- - - \ No newline at end of file diff --git a/docs/api/interfaces/icreateshare.html b/docs/api/interfaces/icreateshare.html deleted file mode 100644 index 9330a383..00000000 --- a/docs/api/interfaces/icreateshare.html +++ /dev/null @@ -1,189 +0,0 @@ - - - - - - ICreateShare | nextcloud-node-client - - - - - -
-
-
-
- -
-
- Options -
-
- All -
    -
  • Public
  • -
  • Public/Protected
  • -
  • All
  • -
-
- - -
-
- Menu -
-
-
-
-
-
- -

Interface ICreateShare

-
-
-
-
-
-
-
-

Hierarchy

-
    -
  • - ICreateShare -
  • -
-
-
-

Index

-
-
-
-

Properties

- -
-
-
-
-
-

Properties

-
- -

fileSystemElement

-
fileSystemElement: FileSystemElement
- -
-
- -

Optional password

-
password: undefined | string
- -
-
- -

Optional publicUpload

-
publicUpload: undefined | false | true
- -
-
-
- -
-
-
-
-

Legend

-
-
    -
  • Constructor
  • -
  • Property
  • -
  • Method
  • -
-
    -
  • Inherited constructor
  • -
  • Inherited property
  • -
  • Inherited method
  • -
-
    -
  • Protected property
  • -
  • Protected method
  • -
-
    -
  • Static property
  • -
  • Static method
  • -
-
    -
  • Property
  • -
-
-
-
-
-

Generated using TypeDoc

-
-
- - - \ No newline at end of file diff --git a/docs/api/interfaces/ifilenameformats.html b/docs/api/interfaces/ifilenameformats.html deleted file mode 100644 index fc771864..00000000 --- a/docs/api/interfaces/ifilenameformats.html +++ /dev/null @@ -1,175 +0,0 @@ - - - - - - IFileNameFormats | nextcloud-node-client - - - - - -
-
-
-
- -
-
- Options -
-
- All -
    -
  • Public
  • -
  • Public/Protected
  • -
  • All
  • -
-
- - -
-
- Menu -
-
-
-
-
-
- -

Interface IFileNameFormats

-
-
-
-
-
-
-
-

Hierarchy

-
    -
  • - IFileNameFormats -
  • -
-
-
-

Index

-
-
-
-

Properties

- -
-
-
-
-
-

Properties

-
- -

absolute

-
absolute: string
- -
-
- -

relative

-
relative: string
- -
-
-
- -
-
-
-
-

Legend

-
-
    -
  • Constructor
  • -
  • Property
  • -
  • Method
  • -
-
    -
  • Inherited constructor
  • -
  • Inherited property
  • -
  • Inherited method
  • -
-
    -
  • Protected property
  • -
  • Protected method
  • -
-
    -
  • Static property
  • -
  • Static method
  • -
-
    -
  • Property
  • -
-
-
-
-
-

Generated using TypeDoc

-
-
- - - \ No newline at end of file diff --git a/docs/api/interfaces/ihttpclientoptions.html b/docs/api/interfaces/ihttpclientoptions.html deleted file mode 100644 index 6ce446ab..00000000 --- a/docs/api/interfaces/ihttpclientoptions.html +++ /dev/null @@ -1,203 +0,0 @@ - - - - - - IHttpClientOptions | nextcloud-node-client - - - - - -
-
-
-
- -
-
- Options -
-
- All -
    -
  • Public
  • -
  • Public/Protected
  • -
  • All
  • -
-
- - -
-
- Menu -
-
-
-
-
-
- -

Interface IHttpClientOptions

-
-
-
-
-
-
-
-

Hierarchy

-
    -
  • - IHttpClientOptions -
  • -
-
-
-

Index

-
-
-
-

Properties

- -
-
-
-
-
-

Properties

-
- -

Optional authorizationHeader

-
authorizationHeader: undefined | string
- -
-
- -

Optional logRequestResponse

-
logRequestResponse: undefined | false | true
- -
-
- -

Optional origin

-
origin: undefined | string
- -
-
- -

Optional proxy

-
proxy: IProxy
- -
-
-
- -
-
-
-
-

Legend

-
-
    -
  • Constructor
  • -
  • Property
  • -
  • Method
  • -
-
    -
  • Inherited constructor
  • -
  • Inherited property
  • -
  • Inherited method
  • -
-
    -
  • Protected property
  • -
  • Protected method
  • -
-
    -
  • Static property
  • -
  • Static method
  • -
-
    -
  • Property
  • -
-
-
-
-
-

Generated using TypeDoc

-
-
- - - \ No newline at end of file diff --git a/docs/api/interfaces/iproxy.html b/docs/api/interfaces/iproxy.html deleted file mode 100644 index d0690bd6..00000000 --- a/docs/api/interfaces/iproxy.html +++ /dev/null @@ -1,217 +0,0 @@ - - - - - - IProxy | nextcloud-node-client - - - - - -
-
-
-
- -
-
- Options -
-
- All -
    -
  • Public
  • -
  • Public/Protected
  • -
  • All
  • -
-
- - -
-
- Menu -
-
-
-
-
-
- -

Interface IProxy

-
-
-
-
-
-
-
-

Hierarchy

-
    -
  • - IProxy -
  • -
-
-
-

Index

-
-
-
-

Properties

- -
-
-
-
-
-

Properties

-
- -

host

-
host: string
- -
-
- -

port

-
port: string
- -
-
- -

protocol

-
protocol: string
- -
-
- -

Optional proxyAuthorizationHeader

-
proxyAuthorizationHeader: undefined | string
- -
-
- -

secureProxy

-
secureProxy: boolean
- -
-
-
- -
-
-
-
-

Legend

-
-
    -
  • Constructor
  • -
  • Property
  • -
  • Method
  • -
-
    -
  • Inherited constructor
  • -
  • Inherited property
  • -
  • Inherited method
  • -
-
    -
  • Protected property
  • -
  • Protected method
  • -
-
    -
  • Static property
  • -
  • Static method
  • -
-
    -
  • Property
  • -
-
-
-
-
-

Generated using TypeDoc

-
-
- - - \ No newline at end of file diff --git a/docs/api/interfaces/iquota.html b/docs/api/interfaces/iquota.html deleted file mode 100644 index e613eb6b..00000000 --- a/docs/api/interfaces/iquota.html +++ /dev/null @@ -1,175 +0,0 @@ - - - - - - IQuota | nextcloud-node-client - - - - - -
-
-
-
- -
-
- Options -
-
- All -
    -
  • Public
  • -
  • Public/Protected
  • -
  • All
  • -
-
- - -
-
- Menu -
-
-
-
-
-
- -

Interface IQuota

-
-
-
-
-
-
-
-

Hierarchy

-
    -
  • - IQuota -
  • -
-
-
-

Index

-
-
-
-

Properties

- -
-
-
-
-
-

Properties

-
- -

available

-
available: number | string
- -
-
- -

used

-
used: number
- -
-
-
- -
-
-
-
-

Legend

-
-
    -
  • Constructor
  • -
  • Property
  • -
  • Method
  • -
-
    -
  • Inherited constructor
  • -
  • Inherited property
  • -
  • Inherited method
  • -
-
    -
  • Protected property
  • -
  • Protected method
  • -
-
    -
  • Static property
  • -
  • Static method
  • -
-
    -
  • Property
  • -
-
-
-
-
-

Generated using TypeDoc

-
-
- - - \ No newline at end of file diff --git a/docs/api/interfaces/irequestcontext.html b/docs/api/interfaces/irequestcontext.html deleted file mode 100644 index 2abefc1e..00000000 --- a/docs/api/interfaces/irequestcontext.html +++ /dev/null @@ -1,161 +0,0 @@ - - - - - - IRequestContext | nextcloud-node-client - - - - - -
-
-
-
- -
-
- Options -
-
- All -
    -
  • Public
  • -
  • Public/Protected
  • -
  • All
  • -
-
- - -
-
- Menu -
-
-
-
-
-
- -

Interface IRequestContext

-
-
-
-
-
-
-
-

Hierarchy

-
    -
  • - IRequestContext -
  • -
-
-
-

Index

-
-
-
-

Properties

- -
-
-
-
-
-

Properties

-
- -

Optional description

-
description: undefined | string
- -
-
-
- -
-
-
-
-

Legend

-
-
    -
  • Constructor
  • -
  • Property
  • -
  • Method
  • -
-
    -
  • Inherited constructor
  • -
  • Inherited property
  • -
  • Inherited method
  • -
-
    -
  • Protected property
  • -
  • Protected method
  • -
-
    -
  • Static property
  • -
  • Static method
  • -
-
    -
  • Property
  • -
-
-
-
-
-

Generated using TypeDoc

-
-
- - - \ No newline at end of file diff --git a/docs/api/interfaces/iserveroptions.html b/docs/api/interfaces/iserveroptions.html deleted file mode 100644 index 7cdcd5e5..00000000 --- a/docs/api/interfaces/iserveroptions.html +++ /dev/null @@ -1,220 +0,0 @@ - - - - - - IServerOptions | nextcloud-node-client - - - - - -
-
-
-
- -
-
- Options -
-
- All -
    -
  • Public
  • -
  • Public/Protected
  • -
  • All
  • -
-
- - -
-
- Menu -
-
-
-
-
-
- -

Interface IServerOptions

-
-
-
-
-
-
-
-
-
-

The options of a server constructor

-
-
-
-
-

Hierarchy

-
    -
  • - IServerOptions -
  • -
-
-
-

Index

-
-
-
-

Properties

- -
-
-
-
-
-

Properties

-
- -

basicAuth

-
basicAuth: IBasicAuth
- -
-
-

basic authentication informatin to access the nextcloud server

-
-
-
-
- -

Optional logRequestResponse

-
logRequestResponse: undefined | false | true
- -
-
- -

Optional proxy

-
proxy: IProxy
- -
-
- -

url

-
url: string
- -
-
-

the url of the nextcloud server like https://nextcloud.mydomain.com

-
-
-
-
-
- -
-
-
-
-

Legend

-
-
    -
  • Constructor
  • -
  • Property
  • -
  • Method
  • -
-
    -
  • Inherited constructor
  • -
  • Inherited property
  • -
  • Inherited method
  • -
-
    -
  • Protected property
  • -
  • Protected method
  • -
-
    -
  • Static property
  • -
  • Static method
  • -
-
    -
  • Property
  • -
-
-
-
-
-

Generated using TypeDoc

-
-
- - - \ No newline at end of file diff --git a/docs/api/interfaces/istat.html b/docs/api/interfaces/istat.html deleted file mode 100644 index 37960a3d..00000000 --- a/docs/api/interfaces/istat.html +++ /dev/null @@ -1,245 +0,0 @@ - - - - - - IStat | nextcloud-node-client - - - - - -
-
-
-
- -
-
- Options -
-
- All -
    -
  • Public
  • -
  • Public/Protected
  • -
  • All
  • -
-
- - -
-
- Menu -
-
-
-
-
-
- -

Interface IStat

-
-
-
-
-
-
-
-

Hierarchy

-
    -
  • - IStat -
  • -
-
-
-

Index

-
-
-
-

Properties

- -
-
-
-
-
-

Properties

-
- -

basename

-
basename: string
- -
-
- -

Optional fileid

-
fileid: undefined | number
- -
-
- -

filename

-
filename: string
- -
-
- -

lastmod

-
lastmod: string
- -
-
- -

Optional mime

-
mime: undefined | string
- -
-
- -

Optional size

-
size: undefined | number
- -
-
- -

type

-
type: string
- -
-
-
- -
-
-
-
-

Legend

-
-
    -
  • Constructor
  • -
  • Property
  • -
  • Method
  • -
-
    -
  • Inherited constructor
  • -
  • Inherited property
  • -
  • Inherited method
  • -
-
    -
  • Protected property
  • -
  • Protected method
  • -
-
    -
  • Static property
  • -
  • Static method
  • -
-
    -
  • Property
  • -
-
-
-
-
-

Generated using TypeDoc

-
-
- - - \ No newline at end of file diff --git a/docs/api/interfaces/isysbasicdata.html b/docs/api/interfaces/isysbasicdata.html deleted file mode 100644 index acc5c8cc..00000000 --- a/docs/api/interfaces/isysbasicdata.html +++ /dev/null @@ -1,189 +0,0 @@ - - - - - - ISysBasicData | nextcloud-node-client - - - - - -
-
-
-
- -
-
- Options -
-
- All -
    -
  • Public
  • -
  • Public/Protected
  • -
  • All
  • -
-
- - -
-
- Menu -
-
-
-
-
-
- -

Interface ISysBasicData

-
-
-
-
-
-
-
-

Hierarchy

-
    -
  • - ISysBasicData -
  • -
-
-
-

Index

-
-
-
-

Properties

- -
-
-
-
-
-

Properties

-
- -

serverTimeString

-
serverTimeString: string
- -
-
- -

timeServersString

-
timeServersString: string
- -
-
- -

uptimeString

-
uptimeString: string
- -
-
-
- -
-
-
-
-

Legend

-
-
    -
  • Constructor
  • -
  • Property
  • -
  • Method
  • -
-
    -
  • Inherited constructor
  • -
  • Inherited property
  • -
  • Inherited method
  • -
-
    -
  • Protected property
  • -
  • Protected method
  • -
-
    -
  • Static property
  • -
  • Static method
  • -
-
    -
  • Property
  • -
-
-
-
-
-

Generated using TypeDoc

-
-
- - - \ No newline at end of file diff --git a/docs/api/interfaces/isysinfonextcloud.html b/docs/api/interfaces/isysinfonextcloud.html deleted file mode 100644 index cc89b8e3..00000000 --- a/docs/api/interfaces/isysinfonextcloud.html +++ /dev/null @@ -1,189 +0,0 @@ - - - - - - ISysInfoNextcloud | nextcloud-node-client - - - - - -
-
-
-
- -
-
- Options -
-
- All -
    -
  • Public
  • -
  • Public/Protected
  • -
  • All
  • -
-
- - -
-
- Menu -
-
-
-
-
-
- -

Interface ISysInfoNextcloud

-
-
-
-
-
-
-
-

Hierarchy

-
    -
  • - ISysInfoNextcloud -
  • -
-
-
-

Index

-
-
-
-

Properties

- -
-
-
-
-
-

Properties

-
- -

shares

-
shares: object
- -
-
- -

storage

-
storage: object
- -
-
- -

system

-
system: object
- -
-
-
- -
-
-
-
-

Legend

-
-
    -
  • Constructor
  • -
  • Property
  • -
  • Method
  • -
-
    -
  • Inherited constructor
  • -
  • Inherited property
  • -
  • Inherited method
  • -
-
    -
  • Protected property
  • -
  • Protected method
  • -
-
    -
  • Static property
  • -
  • Static method
  • -
-
    -
  • Property
  • -
-
-
-
-
-

Generated using TypeDoc

-
-
- - - \ No newline at end of file diff --git a/docs/api/interfaces/isysinfonextcloudclient.html b/docs/api/interfaces/isysinfonextcloudclient.html deleted file mode 100644 index b7a11dbd..00000000 --- a/docs/api/interfaces/isysinfonextcloudclient.html +++ /dev/null @@ -1,161 +0,0 @@ - - - - - - ISysInfoNextcloudClient | nextcloud-node-client - - - - - -
-
-
-
- -
-
- Options -
-
- All -
    -
  • Public
  • -
  • Public/Protected
  • -
  • All
  • -
-
- - -
-
- Menu -
-
-
-
-
-
- -

Interface ISysInfoNextcloudClient

-
-
-
-
-
-
-
-

Hierarchy

-
    -
  • - ISysInfoNextcloudClient -
  • -
-
-
-

Index

-
-
-
-

Properties

- -
-
-
-
-
-

Properties

-
- -

version

-
version: string
- -
-
-
- -
-
-
-
-

Legend

-
-
    -
  • Constructor
  • -
  • Property
  • -
  • Method
  • -
-
    -
  • Inherited constructor
  • -
  • Inherited property
  • -
  • Inherited method
  • -
-
    -
  • Protected property
  • -
  • Protected method
  • -
-
    -
  • Static property
  • -
  • Static method
  • -
-
    -
  • Property
  • -
-
-
-
-
-

Generated using TypeDoc

-
-
- - - \ No newline at end of file diff --git a/docs/api/interfaces/isysteminfo.html b/docs/api/interfaces/isysteminfo.html deleted file mode 100644 index d9c46ce8..00000000 --- a/docs/api/interfaces/isysteminfo.html +++ /dev/null @@ -1,203 +0,0 @@ - - - - - - ISystemInfo | nextcloud-node-client - - - - - -
-
-
-
- -
-
- Options -
-
- All -
    -
  • Public
  • -
  • Public/Protected
  • -
  • All
  • -
-
- - -
-
- Menu -
-
-
-
-
-
- -

Interface ISystemInfo

-
-
-
-
-
-
-
-

Hierarchy

-
    -
  • - ISystemInfo -
  • -
-
-
-

Index

-
-
-
-

Properties

- -
-
-
-
-
-

Properties

-
- -

activeUsers

-
activeUsers: object
- -
-
- -

nextcloud

- - -
-
- -

nextcloudClient

-
nextcloudClient: ISysInfoNextcloudClient
- -
-
- -

server

-
server: object
- -
-
-
- -
-
-
-
-

Legend

-
-
    -
  • Constructor
  • -
  • Property
  • -
  • Method
  • -
-
    -
  • Inherited constructor
  • -
  • Inherited property
  • -
  • Inherited method
  • -
-
    -
  • Protected property
  • -
  • Protected method
  • -
-
    -
  • Static property
  • -
  • Static method
  • -
-
    -
  • Property
  • -
-
-
-
-
-

Generated using TypeDoc

-
-
- - - \ No newline at end of file diff --git a/docs/api/interfaces/iupsertuseroptions.html b/docs/api/interfaces/iupsertuseroptions.html deleted file mode 100644 index bdb87f8a..00000000 --- a/docs/api/interfaces/iupsertuseroptions.html +++ /dev/null @@ -1,371 +0,0 @@ - - - - - - IUpsertUserOptions | nextcloud-node-client - - - - - -
-
-
-
- -
-
- Options -
-
- All -
    -
  • Public
  • -
  • Public/Protected
  • -
  • All
  • -
-
- - -
-
- Menu -
-
-
-
-
-
- -

Interface IUpsertUserOptions

-
-
-
-
-
-
-
-

Hierarchy

-
    -
  • - IUpsertUserOptions -
  • -
-
-
-

Index

-
- -
-
-
-

Properties

-
- -

Optional address

-
address: undefined | string
- -
-
- -

Optional displayName

-
displayName: undefined | string
- -
-
- -

Optional email

-
email: undefined | string
- -
-
- -

Optional enabled

-
enabled: undefined | false | true
- -
-
- -

id

-
id: string
- -
-
- -

Optional language

-
language: undefined | string
- -
-
- -

Optional locale

-
locale: undefined | string
- -
-
- -

Optional memberGroups

-
memberGroups: string[]
- -
-
- -

Optional password

-
password: undefined | string
- -
-
- -

Optional phone

-
phone: undefined | string
- -
-
- -

Optional quota

-
quota: undefined | string
- -
-
- -

Optional resendWelcomeEmail

-
resendWelcomeEmail: undefined | false | true
- -
-
- -

Optional subadminGroups

-
subadminGroups: string[]
- -
-
- -

Optional superAdmin

-
superAdmin: undefined | false | true
- -
-
- -

Optional twitter

-
twitter: undefined | string
- -
-
- -

Optional website

-
website: undefined | string
- -
-
-
- -
-
-
-
-

Legend

-
-
    -
  • Constructor
  • -
  • Property
  • -
  • Method
  • -
-
    -
  • Inherited constructor
  • -
  • Inherited property
  • -
  • Inherited method
  • -
-
    -
  • Protected property
  • -
  • Protected method
  • -
-
    -
  • Static property
  • -
  • Static method
  • -
-
    -
  • Property
  • -
-
-
-
-
-

Generated using TypeDoc

-
-
- - - \ No newline at end of file diff --git a/docs/api/interfaces/iupsertuserreport.html b/docs/api/interfaces/iupsertuserreport.html deleted file mode 100644 index a6b28b0a..00000000 --- a/docs/api/interfaces/iupsertuserreport.html +++ /dev/null @@ -1,189 +0,0 @@ - - - - - - IUpsertUserReport | nextcloud-node-client - - - - - -
-
-
-
- -
-
- Options -
-
- All -
    -
  • Public
  • -
  • Public/Protected
  • -
  • All
  • -
-
- - -
-
- Menu -
-
-
-
-
-
- -

Interface IUpsertUserReport

-
-
-
-
-
-
-
-

Hierarchy

-
    -
  • - IUpsertUserReport -
  • -
-
-
-

Index

-
-
-
-

Properties

- -
-
-
-
-
-

Properties

-
- -

changes

- - -
-
- -

id

-
id: string
- -
-
- -

message

-
message: string
- -
-
-
- -
-
-
-
-

Legend

-
-
    -
  • Constructor
  • -
  • Property
  • -
  • Method
  • -
-
    -
  • Inherited constructor
  • -
  • Inherited property
  • -
  • Inherited method
  • -
-
    -
  • Protected property
  • -
  • Protected method
  • -
-
    -
  • Static property
  • -
  • Static method
  • -
-
    -
  • Property
  • -
-
-
-
-
-

Generated using TypeDoc

-
-
- - - \ No newline at end of file diff --git a/docs/api/interfaces/iuseroptions.html b/docs/api/interfaces/iuseroptions.html deleted file mode 100644 index dfd47175..00000000 --- a/docs/api/interfaces/iuseroptions.html +++ /dev/null @@ -1,329 +0,0 @@ - - - - - - IUserOptions | nextcloud-node-client - - - - - -
-
-
-
- -
-
- Options -
-
- All -
    -
  • Public
  • -
  • Public/Protected
  • -
  • All
  • -
-
- - -
-
- Menu -
-
-
-
-
-
- -

Interface IUserOptions

-
-
-
-
-
-
-
-

Hierarchy

-
    -
  • - IUserOptions -
  • -
-
-
-

Index

-
- -
-
-
-

Properties

-
- -

address

-
address: string
- -
-
- -

displayName

-
displayName: string
- -
-
- -

email

-
email: string
- -
-
- -

enabled

-
enabled: boolean
- -
-
- -

language

-
language: string
- -
-
- -

Optional lastLogin

-
lastLogin: Date
- -
-
- -

locale

-
locale: string
- -
-
- -

memberGroups

-
memberGroups: string[]
- -
-
- -

phone

-
phone: string
- -
-
- -

quota

- - -
-
- -

subadminGroups

-
subadminGroups: string[]
- -
-
- -

twitter

-
twitter: string
- -
-
- -

website

-
website: string
- -
-
-
- -
-
-
-
-

Legend

-
-
    -
  • Constructor
  • -
  • Property
  • -
  • Method
  • -
-
    -
  • Inherited constructor
  • -
  • Inherited property
  • -
  • Inherited method
  • -
-
    -
  • Protected property
  • -
  • Protected method
  • -
-
    -
  • Static property
  • -
  • Static method
  • -
-
    -
  • Property
  • -
-
-
-
-
-

Generated using TypeDoc

-
-
- - - \ No newline at end of file diff --git a/docs/api/interfaces/iuseroptionsquota.html b/docs/api/interfaces/iuseroptionsquota.html deleted file mode 100644 index a4261fc0..00000000 --- a/docs/api/interfaces/iuseroptionsquota.html +++ /dev/null @@ -1,217 +0,0 @@ - - - - - - IUserOptionsQuota | nextcloud-node-client - - - - - -
-
-
-
- -
-
- Options -
-
- All -
    -
  • Public
  • -
  • Public/Protected
  • -
  • All
  • -
-
- - -
-
- Menu -
-
-
-
-
-
- -

Interface IUserOptionsQuota

-
-
-
-
-
-
-
-

Hierarchy

-
    -
  • - IUserOptionsQuota -
  • -
-
-
-

Index

-
-
-
-

Properties

- -
-
-
-
-
-

Properties

-
- -

Optional free

-
free: undefined | number
- -
-
- -

quota

-
quota: number
- -
-
- -

relative

-
relative: number
- -
-
- -

Optional total

-
total: undefined | number
- -
-
- -

used

-
used: number
- -
-
-
- -
-
-
-
-

Legend

-
-
    -
  • Constructor
  • -
  • Property
  • -
  • Method
  • -
-
    -
  • Inherited constructor
  • -
  • Inherited property
  • -
  • Inherited method
  • -
-
    -
  • Protected property
  • -
  • Protected method
  • -
-
    -
  • Static property
  • -
  • Static method
  • -
-
    -
  • Property
  • -
-
-
-
-
-

Generated using TypeDoc

-
-
- - - \ No newline at end of file diff --git a/docs/api/interfaces/iuserpropertychange.html b/docs/api/interfaces/iuserpropertychange.html deleted file mode 100644 index 9163a9d5..00000000 --- a/docs/api/interfaces/iuserpropertychange.html +++ /dev/null @@ -1,203 +0,0 @@ - - - - - - IUserPropertyChange | nextcloud-node-client - - - - - -
-
-
-
- -
-
- Options -
-
- All -
    -
  • Public
  • -
  • Public/Protected
  • -
  • All
  • -
-
- - -
-
- Menu -
-
-
-
-
-
- -

Interface IUserPropertyChange

-
-
-
-
-
-
-
-

Hierarchy

-
    -
  • - IUserPropertyChange -
  • -
-
-
-

Index

-
-
-
-

Properties

- -
-
-
-
-
-

Properties

-
- -

Optional error

-
error: undefined | string
- -
-
- -

newValue

-
newValue: string
- -
-
- -

previousValue

-
previousValue: string
- -
-
- -

property

-
property: string
- -
-
-
- -
-
-
-
-

Legend

-
-
    -
  • Constructor
  • -
  • Property
  • -
  • Method
  • -
-
    -
  • Inherited constructor
  • -
  • Inherited property
  • -
  • Inherited method
  • -
-
    -
  • Protected property
  • -
  • Protected method
  • -
-
    -
  • Static property
  • -
  • Static method
  • -
-
    -
  • Property
  • -
-
-
-
-
-

Generated using TypeDoc

-
-
- - - \ No newline at end of file diff --git a/docs/api/interfaces/iuserquotauserfriendly.html b/docs/api/interfaces/iuserquotauserfriendly.html deleted file mode 100644 index a40698c8..00000000 --- a/docs/api/interfaces/iuserquotauserfriendly.html +++ /dev/null @@ -1,217 +0,0 @@ - - - - - - IUserQuotaUserFriendly | nextcloud-node-client - - - - - -
-
-
-
- -
-
- Options -
-
- All -
    -
  • Public
  • -
  • Public/Protected
  • -
  • All
  • -
-
- - -
-
- Menu -
-
-
-
-
-
- -

Interface IUserQuotaUserFriendly

-
-
-
-
-
-
-
-

Hierarchy

-
    -
  • - IUserQuotaUserFriendly -
  • -
-
-
-

Index

-
-
-
-

Properties

- -
-
-
-
-
-

Properties

-
- -

Optional free

-
free: undefined | string
- -
-
- -

quota

-
quota: string
- -
-
- -

relative

-
relative: string
- -
-
- -

Optional total

-
total: undefined | string
- -
-
- -

used

-
used: string
- -
-
-
- -
-
-
-
-

Legend

-
-
    -
  • Constructor
  • -
  • Property
  • -
  • Method
  • -
-
    -
  • Inherited constructor
  • -
  • Inherited property
  • -
  • Inherited method
  • -
-
    -
  • Protected property
  • -
  • Protected method
  • -
-
    -
  • Static property
  • -
  • Static method
  • -
-
    -
  • Property
  • -
-
-
-
-
-

Generated using TypeDoc

-
-
- - - \ No newline at end of file diff --git a/docs/api/interfaces/sourcetargetfilenames.html b/docs/api/interfaces/sourcetargetfilenames.html deleted file mode 100644 index e8dc5d0a..00000000 --- a/docs/api/interfaces/sourcetargetfilenames.html +++ /dev/null @@ -1,175 +0,0 @@ - - - - - - SourceTargetFileNames | nextcloud-node-client - - - - - -
-
-
-
- -
-
- Options -
-
- All -
    -
  • Public
  • -
  • Public/Protected
  • -
  • All
  • -
-
- - -
-
- Menu -
-
-
-
-
-
- -

Interface SourceTargetFileNames

-
-
-
-
-
-
-
-

Hierarchy

-
    -
  • - SourceTargetFileNames -
  • -
-
-
-

Index

-
-
-
-

Properties

- -
-
-
-
-
-

Properties

-
- -

sourceFileName

-
sourceFileName: string
- -
-
- -

targetFileName

-
targetFileName: string
- -
-
-
- -
-
-
-
-

Legend

-
-
    -
  • Constructor
  • -
  • Property
  • -
  • Method
  • -
-
    -
  • Inherited constructor
  • -
  • Inherited property
  • -
  • Inherited method
  • -
-
    -
  • Protected property
  • -
  • Protected method
  • -
-
    -
  • Static property
  • -
  • Static method
  • -
-
    -
  • Property
  • -
-
-
-
-
-

Generated using TypeDoc

-
-
- - - \ No newline at end of file diff --git a/docs/api/interfaces/uploadfilescommandoptions.html b/docs/api/interfaces/uploadfilescommandoptions.html deleted file mode 100644 index 4a373600..00000000 --- a/docs/api/interfaces/uploadfilescommandoptions.html +++ /dev/null @@ -1,175 +0,0 @@ - - - - - - UploadFilesCommandOptions | nextcloud-node-client - - - - - -
-
-
-
- -
-
- Options -
-
- All -
    -
  • Public
  • -
  • Public/Protected
  • -
  • All
  • -
-
- - -
-
- Menu -
-
-
-
-
-
- -

Interface UploadFilesCommandOptions

-
-
-
-
-
-
-
-

Hierarchy

-
    -
  • - UploadFilesCommandOptions -
  • -
-
-
-

Index

-
-
-
-

Properties

- -
-
-
-
-
-

Properties

-
- -

files

- - -
-
- -

Optional processFileAfterUpload

-
processFileAfterUpload: undefined | ((file: File) => Promise<void>)
- -
-
-
- -
-
-
-
-

Legend

-
-
    -
  • Constructor
  • -
  • Property
  • -
  • Method
  • -
-
    -
  • Inherited constructor
  • -
  • Inherited property
  • -
  • Inherited method
  • -
-
    -
  • Protected property
  • -
  • Protected method
  • -
-
    -
  • Static property
  • -
  • Static method
  • -
-
    -
  • Property
  • -
-
-
-
-
-

Generated using TypeDoc

-
-
- - - \ No newline at end of file diff --git a/docs/api/interfaces/uploadfoldercommandoptions.html b/docs/api/interfaces/uploadfoldercommandoptions.html deleted file mode 100644 index 088d4915..00000000 --- a/docs/api/interfaces/uploadfoldercommandoptions.html +++ /dev/null @@ -1,211 +0,0 @@ - - - - - - UploadFolderCommandOptions | nextcloud-node-client - - - - - -
-
-
-
- -
-
- Options -
-
- All -
    -
  • Public
  • -
  • Public/Protected
  • -
  • All
  • -
-
- - -
-
- Menu -
-
-
-
-
-
- -

Interface UploadFolderCommandOptions

-
-
-
-
-
-
-
-
-
-

options to create a upload folder command

-
-
-
-
-

Hierarchy

-
    -
  • - UploadFolderCommandOptions -
  • -
-
-
-

Index

-
- -
-
-
-

Properties

-
- -

folderName

-
folderName: string
- -
-
-

The name of the source folder with the file structure to be uploaded

-
-
-
-
- -

Optional getTargetFileNameBeforeUpload

-
getTargetFileNameBeforeUpload: undefined | ((fileNames: SourceTargetFileNames) => string)
- -
-
-

the function to determine the target file name having the sourece file name. - If the file should not be uploaded, return an empty string

-
-
-
param
-
-
-
-
-
- -

Optional processFileAfterUpload

-
processFileAfterUpload: undefined | ((file: File) => Promise<void>)
- -
-
-
- -
-
-
-
-

Legend

-
-
    -
  • Constructor
  • -
  • Property
  • -
  • Method
  • -
-
    -
  • Inherited constructor
  • -
  • Inherited property
  • -
  • Inherited method
  • -
-
    -
  • Protected property
  • -
  • Protected method
  • -
-
    -
  • Static property
  • -
  • Static method
  • -
-
    -
  • Property
  • -
-
-
-
-
-

Generated using TypeDoc

-
-
- - - \ No newline at end of file diff --git a/docs/coverage/base.css b/docs/coverage/base.css deleted file mode 100644 index f418035b..00000000 --- a/docs/coverage/base.css +++ /dev/null @@ -1,224 +0,0 @@ -body, html { - margin:0; padding: 0; - height: 100%; -} -body { - font-family: Helvetica Neue, Helvetica, Arial; - font-size: 14px; - color:#333; -} -.small { font-size: 12px; } -*, *:after, *:before { - -webkit-box-sizing:border-box; - -moz-box-sizing:border-box; - box-sizing:border-box; - } -h1 { font-size: 20px; margin: 0;} -h2 { font-size: 14px; } -pre { - font: 12px/1.4 Consolas, "Liberation Mono", Menlo, Courier, monospace; - margin: 0; - padding: 0; - -moz-tab-size: 2; - -o-tab-size: 2; - tab-size: 2; -} -a { color:#0074D9; text-decoration:none; } -a:hover { text-decoration:underline; } -.strong { font-weight: bold; } -.space-top1 { padding: 10px 0 0 0; } -.pad2y { padding: 20px 0; } -.pad1y { padding: 10px 0; } -.pad2x { padding: 0 20px; } -.pad2 { padding: 20px; } -.pad1 { padding: 10px; } -.space-left2 { padding-left:55px; } -.space-right2 { padding-right:20px; } -.center { text-align:center; } -.clearfix { display:block; } -.clearfix:after { - content:''; - display:block; - height:0; - clear:both; - visibility:hidden; - } -.fl { float: left; } -@media only screen and (max-width:640px) { - .col3 { width:100%; max-width:100%; } - .hide-mobile { display:none!important; } -} - -.quiet { - color: #7f7f7f; - color: rgba(0,0,0,0.5); -} -.quiet a { opacity: 0.7; } - -.fraction { - font-family: Consolas, 'Liberation Mono', Menlo, Courier, monospace; - font-size: 10px; - color: #555; - background: #E8E8E8; - padding: 4px 5px; - border-radius: 3px; - vertical-align: middle; -} - -div.path a:link, div.path a:visited { color: #333; } -table.coverage { - border-collapse: collapse; - margin: 10px 0 0 0; - padding: 0; -} - -table.coverage td { - margin: 0; - padding: 0; - vertical-align: top; -} -table.coverage td.line-count { - text-align: right; - padding: 0 5px 0 20px; -} -table.coverage td.line-coverage { - text-align: right; - padding-right: 10px; - min-width:20px; -} - -table.coverage td span.cline-any { - display: inline-block; - padding: 0 5px; - width: 100%; -} -.missing-if-branch { - display: inline-block; - margin-right: 5px; - border-radius: 3px; - position: relative; - padding: 0 4px; - background: #333; - color: yellow; -} - -.skip-if-branch { - display: none; - margin-right: 10px; - position: relative; - padding: 0 4px; - background: #ccc; - color: white; -} -.missing-if-branch .typ, .skip-if-branch .typ { - color: inherit !important; -} -.coverage-summary { - border-collapse: collapse; - width: 100%; -} -.coverage-summary tr { border-bottom: 1px solid #bbb; } -.keyline-all { border: 1px solid #ddd; } -.coverage-summary td, .coverage-summary th { padding: 10px; } -.coverage-summary tbody { border: 1px solid #bbb; } -.coverage-summary td { border-right: 1px solid #bbb; } -.coverage-summary td:last-child { border-right: none; } -.coverage-summary th { - text-align: left; - font-weight: normal; - white-space: nowrap; -} -.coverage-summary th.file { border-right: none !important; } -.coverage-summary th.pct { } -.coverage-summary th.pic, -.coverage-summary th.abs, -.coverage-summary td.pct, -.coverage-summary td.abs { text-align: right; } -.coverage-summary td.file { white-space: nowrap; } -.coverage-summary td.pic { min-width: 120px !important; } -.coverage-summary tfoot td { } - -.coverage-summary .sorter { - height: 10px; - width: 7px; - display: inline-block; - margin-left: 0.5em; - background: url(sort-arrow-sprite.png) no-repeat scroll 0 0 transparent; -} -.coverage-summary .sorted .sorter { - background-position: 0 -20px; -} -.coverage-summary .sorted-desc .sorter { - background-position: 0 -10px; -} -.status-line { height: 10px; } -/* yellow */ -.cbranch-no { background: yellow !important; color: #111; } -/* dark red */ -.red.solid, .status-line.low, .low .cover-fill { background:#C21F39 } -.low .chart { border:1px solid #C21F39 } -.highlighted, -.highlighted .cstat-no, .highlighted .fstat-no, .highlighted .cbranch-no{ - background: #C21F39 !important; -} -/* medium red */ -.cstat-no, .fstat-no, .cbranch-no, .cbranch-no { background:#F6C6CE } -/* light red */ -.low, .cline-no { background:#FCE1E5 } -/* light green */ -.high, .cline-yes { background:rgb(230,245,208) } -/* medium green */ -.cstat-yes { background:rgb(161,215,106) } -/* dark green */ -.status-line.high, .high .cover-fill { background:rgb(77,146,33) } -.high .chart { border:1px solid rgb(77,146,33) } -/* dark yellow (gold) */ -.status-line.medium, .medium .cover-fill { background: #f9cd0b; } -.medium .chart { border:1px solid #f9cd0b; } -/* light yellow */ -.medium { background: #fff4c2; } - -.cstat-skip { background: #ddd; color: #111; } -.fstat-skip { background: #ddd; color: #111 !important; } -.cbranch-skip { background: #ddd !important; color: #111; } - -span.cline-neutral { background: #eaeaea; } - -.coverage-summary td.empty { - opacity: .5; - padding-top: 4px; - padding-bottom: 4px; - line-height: 1; - color: #888; -} - -.cover-fill, .cover-empty { - display:inline-block; - height: 12px; -} -.chart { - line-height: 0; -} -.cover-empty { - background: white; -} -.cover-full { - border-right: none !important; -} -pre.prettyprint { - border: none !important; - padding: 0 !important; - margin: 0 !important; -} -.com { color: #999 !important; } -.ignore-none { color: #999; font-weight: normal; } - -.wrapper { - min-height: 100%; - height: auto !important; - height: 100%; - margin: 0 auto -48px; -} -.footer, .push { - height: 48px; -} diff --git a/docs/coverage/block-navigation.js b/docs/coverage/block-navigation.js deleted file mode 100644 index c7ff5a5c..00000000 --- a/docs/coverage/block-navigation.js +++ /dev/null @@ -1,79 +0,0 @@ -/* eslint-disable */ -var jumpToCode = (function init() { - // Classes of code we would like to highlight in the file view - var missingCoverageClasses = ['.cbranch-no', '.cstat-no', '.fstat-no']; - - // Elements to highlight in the file listing view - var fileListingElements = ['td.pct.low']; - - // We don't want to select elements that are direct descendants of another match - var notSelector = ':not(' + missingCoverageClasses.join('):not(') + ') > '; // becomes `:not(a):not(b) > ` - - // Selecter that finds elements on the page to which we can jump - var selector = - fileListingElements.join(', ') + - ', ' + - notSelector + - missingCoverageClasses.join(', ' + notSelector); // becomes `:not(a):not(b) > a, :not(a):not(b) > b` - - // The NodeList of matching elements - var missingCoverageElements = document.querySelectorAll(selector); - - var currentIndex; - - function toggleClass(index) { - missingCoverageElements - .item(currentIndex) - .classList.remove('highlighted'); - missingCoverageElements.item(index).classList.add('highlighted'); - } - - function makeCurrent(index) { - toggleClass(index); - currentIndex = index; - missingCoverageElements.item(index).scrollIntoView({ - behavior: 'smooth', - block: 'center', - inline: 'center' - }); - } - - function goToPrevious() { - var nextIndex = 0; - if (typeof currentIndex !== 'number' || currentIndex === 0) { - nextIndex = missingCoverageElements.length - 1; - } else if (missingCoverageElements.length > 1) { - nextIndex = currentIndex - 1; - } - - makeCurrent(nextIndex); - } - - function goToNext() { - var nextIndex = 0; - - if ( - typeof currentIndex === 'number' && - currentIndex < missingCoverageElements.length - 1 - ) { - nextIndex = currentIndex + 1; - } - - makeCurrent(nextIndex); - } - - return function jump(event) { - switch (event.which) { - case 78: // n - case 74: // j - goToNext(); - break; - case 66: // b - case 75: // k - case 80: // p - goToPrevious(); - break; - } - }; -})(); -window.addEventListener('keydown', jumpToCode); diff --git a/docs/coverage/client.ts.html b/docs/coverage/client.ts.html deleted file mode 100644 index af0ec936..00000000 --- a/docs/coverage/client.ts.html +++ /dev/null @@ -1,9659 +0,0 @@ - - - - - - Code coverage report for client.ts - - - - - - - - - -
-
-

All files client.ts

-
- -
- 95.87% - Statements - 1022/1066 -
- - -
- 95.02% - Branches - 382/402 -
- - -
- 93.9% - Functions - 77/82 -
- - -
- 95.86% - Lines - 1018/1062 -
- - -
-

- Press n or j to go to the next uncovered block, b, p or k for the previous block. -

-
-
-

-
1 -2 -3 -4 -5 -6 -7 -8 -9 -10 -11 -12 -13 -14 -15 -16 -17 -18 -19 -20 -21 -22 -23 -24 -25 -26 -27 -28 -29 -30 -31 -32 -33 -34 -35 -36 -37 -38 -39 -40 -41 -42 -43 -44 -45 -46 -47 -48 -49 -50 -51 -52 -53 -54 -55 -56 -57 -58 -59 -60 -61 -62 -63 -64 -65 -66 -67 -68 -69 -70 -71 -72 -73 -74 -75 -76 -77 -78 -79 -80 -81 -82 -83 -84 -85 -86 -87 -88 -89 -90 -91 -92 -93 -94 -95 -96 -97 -98 -99 -100 -101 -102 -103 -104 -105 -106 -107 -108 -109 -110 -111 -112 -113 -114 -115 -116 -117 -118 -119 -120 -121 -122 -123 -124 -125 -126 -127 -128 -129 -130 -131 -132 -133 -134 -135 -136 -137 -138 -139 -140 -141 -142 -143 -144 -145 -146 -147 -148 -149 -150 -151 -152 -153 -154 -155 -156 -157 -158 -159 -160 -161 -162 -163 -164 -165 -166 -167 -168 -169 -170 -171 -172 -173 -174 -175 -176 -177 -178 -179 -180 -181 -182 -183 -184 -185 -186 -187 -188 -189 -190 -191 -192 -193 -194 -195 -196 -197 -198 -199 -200 -201 -202 -203 -204 -205 -206 -207 -208 -209 -210 -211 -212 -213 -214 -215 -216 -217 -218 -219 -220 -221 -222 -223 -224 -225 -226 -227 -228 -229 -230 -231 -232 -233 -234 -235 -236 -237 -238 -239 -240 -241 -242 -243 -244 -245 -246 -247 -248 -249 -250 -251 -252 -253 -254 -255 -256 -257 -258 -259 -260 -261 -262 -263 -264 -265 -266 -267 -268 -269 -270 -271 -272 -273 -274 -275 -276 -277 -278 -279 -280 -281 -282 -283 -284 -285 -286 -287 -288 -289 -290 -291 -292 -293 -294 -295 -296 -297 -298 -299 -300 -301 -302 -303 -304 -305 -306 -307 -308 -309 -310 -311 -312 -313 -314 -315 -316 -317 -318 -319 -320 -321 -322 -323 -324 -325 -326 -327 -328 -329 -330 -331 -332 -333 -334 -335 -336 -337 -338 -339 -340 -341 -342 -343 -344 -345 -346 -347 -348 -349 -350 -351 -352 -353 -354 -355 -356 -357 -358 -359 -360 -361 -362 -363 -364 -365 -366 -367 -368 -369 -370 -371 -372 -373 -374 -375 -376 -377 -378 -379 -380 -381 -382 -383 -384 -385 -386 -387 -388 -389 -390 -391 -392 -393 -394 -395 -396 -397 -398 -399 -400 -401 -402 -403 -404 -405 -406 -407 -408 -409 -410 -411 -412 -413 -414 -415 -416 -417 -418 -419 -420 -421 -422 -423 -424 -425 -426 -427 -428 -429 -430 -431 -432 -433 -434 -435 -436 -437 -438 -439 -440 -441 -442 -443 -444 -445 -446 -447 -448 -449 -450 -451 -452 -453 -454 -455 -456 -457 -458 -459 -460 -461 -462 -463 -464 -465 -466 -467 -468 -469 -470 -471 -472 -473 -474 -475 -476 -477 -478 -479 -480 -481 -482 -483 -484 -485 -486 -487 -488 -489 -490 -491 -492 -493 -494 -495 -496 -497 -498 -499 -500 -501 -502 -503 -504 -505 -506 -507 -508 -509 -510 -511 -512 -513 -514 -515 -516 -517 -518 -519 -520 -521 -522 -523 -524 -525 -526 -527 -528 -529 -530 -531 -532 -533 -534 -535 -536 -537 -538 -539 -540 -541 -542 -543 -544 -545 -546 -547 -548 -549 -550 -551 -552 -553 -554 -555 -556 -557 -558 -559 -560 -561 -562 -563 -564 -565 -566 -567 -568 -569 -570 -571 -572 -573 -574 -575 -576 -577 -578 -579 -580 -581 -582 -583 -584 -585 -586 -587 -588 -589 -590 -591 -592 -593 -594 -595 -596 -597 -598 -599 -600 -601 -602 -603 -604 -605 -606 -607 -608 -609 -610 -611 -612 -613 -614 -615 -616 -617 -618 -619 -620 -621 -622 -623 -624 -625 -626 -627 -628 -629 -630 -631 -632 -633 -634 -635 -636 -637 -638 -639 -640 -641 -642 -643 -644 -645 -646 -647 -648 -649 -650 -651 -652 -653 -654 -655 -656 -657 -658 -659 -660 -661 -662 -663 -664 -665 -666 -667 -668 -669 -670 -671 -672 -673 -674 -675 -676 -677 -678 -679 -680 -681 -682 -683 -684 -685 -686 -687 -688 -689 -690 -691 -692 -693 -694 -695 -696 -697 -698 -699 -700 -701 -702 -703 -704 -705 -706 -707 -708 -709 -710 -711 -712 -713 -714 -715 -716 -717 -718 -719 -720 -721 -722 -723 -724 -725 -726 -727 -728 -729 -730 -731 -732 -733 -734 -735 -736 -737 -738 -739 -740 -741 -742 -743 -744 -745 -746 -747 -748 -749 -750 -751 -752 -753 -754 -755 -756 -757 -758 -759 -760 -761 -762 -763 -764 -765 -766 -767 -768 -769 -770 -771 -772 -773 -774 -775 -776 -777 -778 -779 -780 -781 -782 -783 -784 -785 -786 -787 -788 -789 -790 -791 -792 -793 -794 -795 -796 -797 -798 -799 -800 -801 -802 -803 -804 -805 -806 -807 -808 -809 -810 -811 -812 -813 -814 -815 -816 -817 -818 -819 -820 -821 -822 -823 -824 -825 -826 -827 -828 -829 -830 -831 -832 -833 -834 -835 -836 -837 -838 -839 -840 -841 -842 -843 -844 -845 -846 -847 -848 -849 -850 -851 -852 -853 -854 -855 -856 -857 -858 -859 -860 -861 -862 -863 -864 -865 -866 -867 -868 -869 -870 -871 -872 -873 -874 -875 -876 -877 -878 -879 -880 -881 -882 -883 -884 -885 -886 -887 -888 -889 -890 -891 -892 -893 -894 -895 -896 -897 -898 -899 -900 -901 -902 -903 -904 -905 -906 -907 -908 -909 -910 -911 -912 -913 -914 -915 -916 -917 -918 -919 -920 -921 -922 -923 -924 -925 -926 -927 -928 -929 -930 -931 -932 -933 -934 -935 -936 -937 -938 -939 -940 -941 -942 -943 -944 -945 -946 -947 -948 -949 -950 -951 -952 -953 -954 -955 -956 -957 -958 -959 -960 -961 -962 -963 -964 -965 -966 -967 -968 -969 -970 -971 -972 -973 -974 -975 -976 -977 -978 -979 -980 -981 -982 -983 -984 -985 -986 -987 -988 -989 -990 -991 -992 -993 -994 -995 -996 -997 -998 -999 -1000 -1001 -1002 -1003 -1004 -1005 -1006 -1007 -1008 -1009 -1010 -1011 -1012 -1013 -1014 -1015 -1016 -1017 -1018 -1019 -1020 -1021 -1022 -1023 -1024 -1025 -1026 -1027 -1028 -1029 -1030 -1031 -1032 -1033 -1034 -1035 -1036 -1037 -1038 -1039 -1040 -1041 -1042 -1043 -1044 -1045 -1046 -1047 -1048 -1049 -1050 -1051 -1052 -1053 -1054 -1055 -1056 -1057 -1058 -1059 -1060 -1061 -1062 -1063 -1064 -1065 -1066 -1067 -1068 -1069 -1070 -1071 -1072 -1073 -1074 -1075 -1076 -1077 -1078 -1079 -1080 -1081 -1082 -1083 -1084 -1085 -1086 -1087 -1088 -1089 -1090 -1091 -1092 -1093 -1094 -1095 -1096 -1097 -1098 -1099 -1100 -1101 -1102 -1103 -1104 -1105 -1106 -1107 -1108 -1109 -1110 -1111 -1112 -1113 -1114 -1115 -1116 -1117 -1118 -1119 -1120 -1121 -1122 -1123 -1124 -1125 -1126 -1127 -1128 -1129 -1130 -1131 -1132 -1133 -1134 -1135 -1136 -1137 -1138 -1139 -1140 -1141 -1142 -1143 -1144 -1145 -1146 -1147 -1148 -1149 -1150 -1151 -1152 -1153 -1154 -1155 -1156 -1157 -1158 -1159 -1160 -1161 -1162 -1163 -1164 -1165 -1166 -1167 -1168 -1169 -1170 -1171 -1172 -1173 -1174 -1175 -1176 -1177 -1178 -1179 -1180 -1181 -1182 -1183 -1184 -1185 -1186 -1187 -1188 -1189 -1190 -1191 -1192 -1193 -1194 -1195 -1196 -1197 -1198 -1199 -1200 -1201 -1202 -1203 -1204 -1205 -1206 -1207 -1208 -1209 -1210 -1211 -1212 -1213 -1214 -1215 -1216 -1217 -1218 -1219 -1220 -1221 -1222 -1223 -1224 -1225 -1226 -1227 -1228 -1229 -1230 -1231 -1232 -1233 -1234 -1235 -1236 -1237 -1238 -1239 -1240 -1241 -1242 -1243 -1244 -1245 -1246 -1247 -1248 -1249 -1250 -1251 -1252 -1253 -1254 -1255 -1256 -1257 -1258 -1259 -1260 -1261 -1262 -1263 -1264 -1265 -1266 -1267 -1268 -1269 -1270 -1271 -1272 -1273 -1274 -1275 -1276 -1277 -1278 -1279 -1280 -1281 -1282 -1283 -1284 -1285 -1286 -1287 -1288 -1289 -1290 -1291 -1292 -1293 -1294 -1295 -1296 -1297 -1298 -1299 -1300 -1301 -1302 -1303 -1304 -1305 -1306 -1307 -1308 -1309 -1310 -1311 -1312 -1313 -1314 -1315 -1316 -1317 -1318 -1319 -1320 -1321 -1322 -1323 -1324 -1325 -1326 -1327 -1328 -1329 -1330 -1331 -1332 -1333 -1334 -1335 -1336 -1337 -1338 -1339 -1340 -1341 -1342 -1343 -1344 -1345 -1346 -1347 -1348 -1349 -1350 -1351 -1352 -1353 -1354 -1355 -1356 -1357 -1358 -1359 -1360 -1361 -1362 -1363 -1364 -1365 -1366 -1367 -1368 -1369 -1370 -1371 -1372 -1373 -1374 -1375 -1376 -1377 -1378 -1379 -1380 -1381 -1382 -1383 -1384 -1385 -1386 -1387 -1388 -1389 -1390 -1391 -1392 -1393 -1394 -1395 -1396 -1397 -1398 -1399 -1400 -1401 -1402 -1403 -1404 -1405 -1406 -1407 -1408 -1409 -1410 -1411 -1412 -1413 -1414 -1415 -1416 -1417 -1418 -1419 -1420 -1421 -1422 -1423 -1424 -1425 -1426 -1427 -1428 -1429 -1430 -1431 -1432 -1433 -1434 -1435 -1436 -1437 -1438 -1439 -1440 -1441 -1442 -1443 -1444 -1445 -1446 -1447 -1448 -1449 -1450 -1451 -1452 -1453 -1454 -1455 -1456 -1457 -1458 -1459 -1460 -1461 -1462 -1463 -1464 -1465 -1466 -1467 -1468 -1469 -1470 -1471 -1472 -1473 -1474 -1475 -1476 -1477 -1478 -1479 -1480 -1481 -1482 -1483 -1484 -1485 -1486 -1487 -1488 -1489 -1490 -1491 -1492 -1493 -1494 -1495 -1496 -1497 -1498 -1499 -1500 -1501 -1502 -1503 -1504 -1505 -1506 -1507 -1508 -1509 -1510 -1511 -1512 -1513 -1514 -1515 -1516 -1517 -1518 -1519 -1520 -1521 -1522 -1523 -1524 -1525 -1526 -1527 -1528 -1529 -1530 -1531 -1532 -1533 -1534 -1535 -1536 -1537 -1538 -1539 -1540 -1541 -1542 -1543 -1544 -1545 -1546 -1547 -1548 -1549 -1550 -1551 -1552 -1553 -1554 -1555 -1556 -1557 -1558 -1559 -1560 -1561 -1562 -1563 -1564 -1565 -1566 -1567 -1568 -1569 -1570 -1571 -1572 -1573 -1574 -1575 -1576 -1577 -1578 -1579 -1580 -1581 -1582 -1583 -1584 -1585 -1586 -1587 -1588 -1589 -1590 -1591 -1592 -1593 -1594 -1595 -1596 -1597 -1598 -1599 -1600 -1601 -1602 -1603 -1604 -1605 -1606 -1607 -1608 -1609 -1610 -1611 -1612 -1613 -1614 -1615 -1616 -1617 -1618 -1619 -1620 -1621 -1622 -1623 -1624 -1625 -1626 -1627 -1628 -1629 -1630 -1631 -1632 -1633 -1634 -1635 -1636 -1637 -1638 -1639 -1640 -1641 -1642 -1643 -1644 -1645 -1646 -1647 -1648 -1649 -1650 -1651 -1652 -1653 -1654 -1655 -1656 -1657 -1658 -1659 -1660 -1661 -1662 -1663 -1664 -1665 -1666 -1667 -1668 -1669 -1670 -1671 -1672 -1673 -1674 -1675 -1676 -1677 -1678 -1679 -1680 -1681 -1682 -1683 -1684 -1685 -1686 -1687 -1688 -1689 -1690 -1691 -1692 -1693 -1694 -1695 -1696 -1697 -1698 -1699 -1700 -1701 -1702 -1703 -1704 -1705 -1706 -1707 -1708 -1709 -1710 -1711 -1712 -1713 -1714 -1715 -1716 -1717 -1718 -1719 -1720 -1721 -1722 -1723 -1724 -1725 -1726 -1727 -1728 -1729 -1730 -1731 -1732 -1733 -1734 -1735 -1736 -1737 -1738 -1739 -1740 -1741 -1742 -1743 -1744 -1745 -1746 -1747 -1748 -1749 -1750 -1751 -1752 -1753 -1754 -1755 -1756 -1757 -1758 -1759 -1760 -1761 -1762 -1763 -1764 -1765 -1766 -1767 -1768 -1769 -1770 -1771 -1772 -1773 -1774 -1775 -1776 -1777 -1778 -1779 -1780 -1781 -1782 -1783 -1784 -1785 -1786 -1787 -1788 -1789 -1790 -1791 -1792 -1793 -1794 -1795 -1796 -1797 -1798 -1799 -1800 -1801 -1802 -1803 -1804 -1805 -1806 -1807 -1808 -1809 -1810 -1811 -1812 -1813 -1814 -1815 -1816 -1817 -1818 -1819 -1820 -1821 -1822 -1823 -1824 -1825 -1826 -1827 -1828 -1829 -1830 -1831 -1832 -1833 -1834 -1835 -1836 -1837 -1838 -1839 -1840 -1841 -1842 -1843 -1844 -1845 -1846 -1847 -1848 -1849 -1850 -1851 -1852 -1853 -1854 -1855 -1856 -1857 -1858 -1859 -1860 -1861 -1862 -1863 -1864 -1865 -1866 -1867 -1868 -1869 -1870 -1871 -1872 -1873 -1874 -1875 -1876 -1877 -1878 -1879 -1880 -1881 -1882 -1883 -1884 -1885 -1886 -1887 -1888 -1889 -1890 -1891 -1892 -1893 -1894 -1895 -1896 -1897 -1898 -1899 -1900 -1901 -1902 -1903 -1904 -1905 -1906 -1907 -1908 -1909 -1910 -1911 -1912 -1913 -1914 -1915 -1916 -1917 -1918 -1919 -1920 -1921 -1922 -1923 -1924 -1925 -1926 -1927 -1928 -1929 -1930 -1931 -1932 -1933 -1934 -1935 -1936 -1937 -1938 -1939 -1940 -1941 -1942 -1943 -1944 -1945 -1946 -1947 -1948 -1949 -1950 -1951 -1952 -1953 -1954 -1955 -1956 -1957 -1958 -1959 -1960 -1961 -1962 -1963 -1964 -1965 -1966 -1967 -1968 -1969 -1970 -1971 -1972 -1973 -1974 -1975 -1976 -1977 -1978 -1979 -1980 -1981 -1982 -1983 -1984 -1985 -1986 -1987 -1988 -1989 -1990 -1991 -1992 -1993 -1994 -1995 -1996 -1997 -1998 -1999 -2000 -2001 -2002 -2003 -2004 -2005 -2006 -2007 -2008 -2009 -2010 -2011 -2012 -2013 -2014 -2015 -2016 -2017 -2018 -2019 -2020 -2021 -2022 -2023 -2024 -2025 -2026 -2027 -2028 -2029 -2030 -2031 -2032 -2033 -2034 -2035 -2036 -2037 -2038 -2039 -2040 -2041 -2042 -2043 -2044 -2045 -2046 -2047 -2048 -2049 -2050 -2051 -2052 -2053 -2054 -2055 -2056 -2057 -2058 -2059 -2060 -2061 -2062 -2063 -2064 -2065 -2066 -2067 -2068 -2069 -2070 -2071 -2072 -2073 -2074 -2075 -2076 -2077 -2078 -2079 -2080 -2081 -2082 -2083 -2084 -2085 -2086 -2087 -2088 -2089 -2090 -2091 -2092 -2093 -2094 -2095 -2096 -2097 -2098 -2099 -2100 -2101 -2102 -2103 -2104 -2105 -2106 -2107 -2108 -2109 -2110 -2111 -2112 -2113 -2114 -2115 -2116 -2117 -2118 -2119 -2120 -2121 -2122 -2123 -2124 -2125 -2126 -2127 -2128 -2129 -2130 -2131 -2132 -2133 -2134 -2135 -2136 -2137 -2138 -2139 -2140 -2141 -2142 -2143 -2144 -2145 -2146 -2147 -2148 -2149 -2150 -2151 -2152 -2153 -2154 -2155 -2156 -2157 -2158 -2159 -2160 -2161 -2162 -2163 -2164 -2165 -2166 -2167 -2168 -2169 -2170 -2171 -2172 -2173 -2174 -2175 -2176 -2177 -2178 -2179 -2180 -2181 -2182 -2183 -2184 -2185 -2186 -2187 -2188 -2189 -2190 -2191 -2192 -2193 -2194 -2195 -2196 -2197 -2198 -2199 -2200 -2201 -2202 -2203 -2204 -2205 -2206 -2207 -2208 -2209 -2210 -2211 -2212 -2213 -2214 -2215 -2216 -2217 -2218 -2219 -2220 -2221 -2222 -2223 -2224 -2225 -2226 -2227 -2228 -2229 -2230 -2231 -2232 -2233 -2234 -2235 -2236 -2237 -2238 -2239 -2240 -2241 -2242 -2243 -2244 -2245 -2246 -2247 -2248 -2249 -2250 -2251 -2252 -2253 -2254 -2255 -2256 -2257 -2258 -2259 -2260 -2261 -2262 -2263 -2264 -2265 -2266 -2267 -2268 -2269 -2270 -2271 -2272 -2273 -2274 -2275 -2276 -2277 -2278 -2279 -2280 -2281 -2282 -2283 -2284 -2285 -2286 -2287 -2288 -2289 -2290 -2291 -2292 -2293 -2294 -2295 -2296 -2297 -2298 -2299 -2300 -2301 -2302 -2303 -2304 -2305 -2306 -2307 -2308 -2309 -2310 -2311 -2312 -2313 -2314 -2315 -2316 -2317 -2318 -2319 -2320 -2321 -2322 -2323 -2324 -2325 -2326 -2327 -2328 -2329 -2330 -2331 -2332 -2333 -2334 -2335 -2336 -2337 -2338 -2339 -2340 -2341 -2342 -2343 -2344 -2345 -2346 -2347 -2348 -2349 -2350 -2351 -2352 -2353 -2354 -2355 -2356 -2357 -2358 -2359 -2360 -2361 -2362 -2363 -2364 -2365 -2366 -2367 -2368 -2369 -2370 -2371 -2372 -2373 -2374 -2375 -2376 -2377 -2378 -2379 -2380 -2381 -2382 -2383 -2384 -2385 -2386 -2387 -2388 -2389 -2390 -2391 -2392 -2393 -2394 -2395 -2396 -2397 -2398 -2399 -2400 -2401 -2402 -2403 -2404 -2405 -2406 -2407 -2408 -2409 -2410 -2411 -2412 -2413 -2414 -2415 -2416 -2417 -2418 -2419 -2420 -2421 -2422 -2423 -2424 -2425 -2426 -2427 -2428 -2429 -2430 -2431 -2432 -2433 -2434 -2435 -2436 -2437 -2438 -2439 -2440 -2441 -2442 -2443 -2444 -2445 -2446 -2447 -2448 -2449 -2450 -2451 -2452 -2453 -2454 -2455 -2456 -2457 -2458 -2459 -2460 -2461 -2462 -2463 -2464 -2465 -2466 -2467 -2468 -2469 -2470 -2471 -2472 -2473 -2474 -2475 -2476 -2477 -2478 -2479 -2480 -2481 -2482 -2483 -2484 -2485 -2486 -2487 -2488 -2489 -2490 -2491 -2492 -2493 -2494 -2495 -2496 -2497 -2498 -2499 -2500 -2501 -2502 -2503 -2504 -2505 -2506 -2507 -2508 -2509 -2510 -2511 -2512 -2513 -2514 -2515 -2516 -2517 -2518 -2519 -2520 -2521 -2522 -2523 -2524 -2525 -2526 -2527 -2528 -2529 -2530 -2531 -2532 -2533 -2534 -2535 -2536 -2537 -2538 -2539 -2540 -2541 -2542 -2543 -2544 -2545 -2546 -2547 -2548 -2549 -2550 -2551 -2552 -2553 -2554 -2555 -2556 -2557 -2558 -2559 -2560 -2561 -2562 -2563 -2564 -2565 -2566 -2567 -2568 -2569 -2570 -2571 -2572 -2573 -2574 -2575 -2576 -2577 -2578 -2579 -2580 -2581 -2582 -2583 -2584 -2585 -2586 -2587 -2588 -2589 -2590 -2591 -2592 -2593 -2594 -2595 -2596 -2597 -2598 -2599 -2600 -2601 -2602 -2603 -2604 -2605 -2606 -2607 -2608 -2609 -2610 -2611 -2612 -2613 -2614 -2615 -2616 -2617 -2618 -2619 -2620 -2621 -2622 -2623 -2624 -2625 -2626 -2627 -2628 -2629 -2630 -2631 -2632 -2633 -2634 -2635 -2636 -2637 -2638 -2639 -2640 -2641 -2642 -2643 -2644 -2645 -2646 -2647 -2648 -2649 -2650 -2651 -2652 -2653 -2654 -2655 -2656 -2657 -2658 -2659 -2660 -2661 -2662 -2663 -2664 -2665 -2666 -2667 -2668 -2669 -2670 -2671 -2672 -2673 -2674 -2675 -2676 -2677 -2678 -2679 -2680 -2681 -2682 -2683 -2684 -2685 -2686 -2687 -2688 -2689 -2690 -2691 -2692 -2693 -2694 -2695 -2696 -2697 -2698 -2699 -2700 -2701 -2702 -2703 -2704 -2705 -2706 -2707 -2708 -2709 -2710 -2711 -2712 -2713 -2714 -2715 -2716 -2717 -2718 -2719 -2720 -2721 -2722 -2723 -2724 -2725 -2726 -2727 -2728 -2729 -2730 -2731 -2732 -2733 -2734 -2735 -2736 -2737 -2738 -2739 -2740 -2741 -2742 -2743 -2744 -2745 -2746 -2747 -2748 -2749 -2750 -2751 -2752 -2753 -2754 -2755 -2756 -2757 -2758 -2759 -2760 -2761 -2762 -2763 -2764 -2765 -2766 -2767 -2768 -2769 -2770 -2771 -2772 -2773 -2774 -2775 -2776 -2777 -2778 -2779 -2780 -2781 -2782 -2783 -2784 -2785 -2786 -2787 -2788 -2789 -2790 -2791 -2792 -2793 -2794 -2795 -2796 -2797 -2798 -2799 -2800 -2801 -2802 -2803 -2804 -2805 -2806 -2807 -2808 -2809 -2810 -2811 -2812 -2813 -2814 -2815 -2816 -2817 -2818 -2819 -2820 -2821 -2822 -2823 -2824 -2825 -2826 -2827 -2828 -2829 -2830 -2831 -2832 -2833 -2834 -2835 -2836 -2837 -2838 -2839 -2840 -2841 -2842 -2843 -2844 -2845 -2846 -2847 -2848 -2849 -2850 -2851 -2852 -2853 -2854 -2855 -2856 -2857 -2858 -2859 -2860 -2861 -2862 -2863 -2864 -2865 -2866 -2867 -2868 -2869 -2870 -2871 -2872 -2873 -2874 -2875 -2876 -2877 -2878 -2879 -2880 -2881 -2882 -2883 -2884 -2885 -2886 -2887 -2888 -2889 -2890 -2891 -2892 -2893 -2894 -2895 -2896 -2897 -2898 -2899 -2900 -2901 -2902 -2903 -2904 -2905 -2906 -2907 -2908 -2909 -2910 -2911 -2912 -2913 -2914 -2915 -2916 -2917 -2918 -2919 -2920 -2921 -2922 -2923 -2924 -2925 -2926 -2927 -2928 -2929 -2930 -2931 -2932 -2933 -2934 -2935 -2936 -2937 -2938 -2939 -2940 -2941 -2942 -2943 -2944 -2945 -2946 -2947 -2948 -2949 -2950 -2951 -2952 -2953 -2954 -2955 -2956 -2957 -2958 -2959 -2960 -2961 -2962 -2963 -2964 -2965 -2966 -2967 -2968 -2969 -2970 -2971 -2972 -2973 -2974 -2975 -2976 -2977 -2978 -2979 -2980 -2981 -2982 -2983 -2984 -2985 -2986 -2987 -2988 -2989 -2990 -2991 -2992 -2993 -2994 -2995 -2996 -2997 -2998 -2999 -3000 -3001 -3002 -3003 -3004 -3005 -3006 -3007 -3008 -3009 -3010 -3011 -3012 -3013 -3014 -3015 -3016 -3017 -3018 -3019 -3020 -3021 -3022 -3023 -3024 -3025 -3026 -3027 -3028 -3029 -3030 -3031 -3032 -3033 -3034 -3035 -3036 -3037 -3038 -3039 -3040 -3041 -3042 -3043 -3044 -3045 -3046 -3047 -3048 -3049 -3050 -3051 -3052 -3053 -3054 -3055 -3056 -3057 -3058 -3059 -3060 -3061 -3062 -3063 -3064 -3065 -3066 -3067 -3068 -3069 -3070 -3071 -3072 -3073 -3074 -3075 -3076 -3077 -3078 -3079 -3080 -3081 -3082 -3083 -3084 -3085 -3086 -3087 -3088 -3089 -3090 -3091 -3092 -3093 -3094 -3095 -3096 -3097 -3098 -3099 -3100 -3101 -3102 -3103 -3104 -3105 -3106 -3107 -3108 -3109 -3110 -3111 -3112 -3113 -3114 -3115 -3116 -3117 -3118 -3119 -3120 -3121 -3122 -3123 -3124 -3125 -3126 -3127 -3128 -3129 -3130 -3131 -3132 -3133 -3134 -3135 -3136 -3137 -3138 -3139 -3140 -3141 -3142 -3143 -3144 -3145 -3146 -3147 -3148 -3149 -3150 -3151 -3152 -3153 -3154 -3155 -3156 -3157 -3158 -3159 -3160 -3161 -3162 -3163 -3164 -3165 -3166 -3167 -3168 -3169 -3170 -3171 -3172 -3173 -3174 -3175 -3176 -3177 -3178 -3179 -3180 -3181 -3182 -3183 -3184 -3185 -3186 -3187 -3188 -3189 -3190 -3191 -3192 -3193 -3194  -1x -1x -  -1x -1x -1x -1x -1x -1x -1x -  -  -  -  -1x -1x -1x -1x -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -1x -1x -1x -1x -1x -1x -1x -1x -1x -1x -1x -1x -1x -  -  -  -1x -1x -1x -1x -1x -1x -1x -1x -1x -1x -1x -1x -1x -1x -  -  -  -1x -1x -1x -1x -1x -1x -  -  -1x -1x -1x -1x -1x -1x -1x -1x -1x -1x -  -  -  -  -  -  -  -1x -  -1x -  -1x -  -  -1x -  -1x -  -  -1x -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -1x -  -1x -  -  -  -  -  -  -  -219x -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -219x -219x -219x -219x -219x -219x -  -  -  -219x -2x -2x -1x -  -1x -1x -  -  -  -218x -  -4x -  -4x -  -4x -  -1x -  -  -3x -  -3x -3x -3x -3x -3x -1x -  -2x -  -  -3x -  -3x -  -  -  -  -  -  -3x -  -  -217x -214x -214x -  -  -  -  -  -  -  -12x -12x -  -  -  -12x -  -  -  -  -  -12x -  -4x -4x -17x -8x -  -  -  -8x -2x -  -  -  -  -4x -1x -1x -  -3x -3x -  -  -  -  -  -  -  -  -  -  -  -  -  -  -36x -  -  -36x -36x -14x -  -  -  -22x -  -  -  -  -  -22x -  -  -  -  -  -22x -22x -22x -1x -  -  -  -21x -  -21x -21x -  -  -  -  -  -  -  -  -  -50x -  -50x -50x -80x -26x -  -  -24x -  -  -  -  -  -  -  -  -  -2x -  -2x -2x -4x -1x -  -  -1x -  -  -  -  -  -  -  -  -  -22x -  -22x -  -  -  -22x -  -  -  -  -  -  -  -  -  -  -  -  -1x -  -1x -  -1x -  -2x -  -  -  -  -  -  -  -  -54x -54x -  -  -  -  -  -  -  -  -  -  -  -  -  -54x -  -54x -  -  -  -  -  -54x -54x -  -54x -124x -  -  -  -  -  -  -  -54x -  -  -  -  -  -  -  -9x -  -9x -  -  -  -  -  -  -  -  -  -  -  -  -  -9x -9x -  -  -  -  -  -9x -9x -  -9x -16x -  -  -9x -9x -  -  -  -  -  -  -  -  -2x -  -2x -  -  -  -2x -  -  -  -  -2x -  -  -  -  -  -  -  -2x -  -2x -  -  -  -  -  -  -  -  -  -2x -  -  -  -  -  -2x -  -2x -2x -1x -  -  -  -1x -1x -  -  -  -37x -  -37x -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -37x -37x -  -  -  -  -36x -  -  -36x -36x -  -  -  -  -  -36x -126x -126x -68x -  -126x -36x -  -90x -90x -90x -90x -90x -90x -58x -58x -58x -  -32x -  -90x -90x -  -  -  -  -  -36x -  -  -  -  -  -  -  -  -138x -138x -  -138x -138x -538x -2x -  -  -  -  -  -136x -136x -69x -69x -  -  -67x -67x -67x -  -  -11x -11x -11x -11x -  -11x -  -38x -38x -38x -  -38x -27x -  -  -27x -27x -  -11x -  -  -  -  -  -67x -67x -66x -66x -  -1x -  -  -  -  -  -  -  -  -  -  -  -41x -41x -  -41x -  -  -41x -41x -  -  -  -  -  -  -  -1x -1x -  -  -  -  -  -  -  -  -30x -30x -  -30x -  -30x -28x -  -  -  -  -  -  -  -  -4x -  -  -  -  -  -  -  -  -  -5x -5x -  -5x -7x -  -5x -5x -5x -  -  -  -  -  -  -  -  -  -5x -  -  -  -  -  -5x -5x -  -  -  -  -  -  -  -1x -1x -  -4x -  -4x -4x -4x -  -1x -  -  -3x -12x -12x -  -  -12x -12x -12x -12x -  -12x -6x -  -6x -  -  -12x -  -  -3x -  -  -  -  -  -  -  -  -294x -294x -  -  -294x -4x -  -  -290x -290x -185x -185x -184x -  -  -  -  -  -1x -1x -  -  -105x -105x -  -  -  -  -  -  -  -  -  -19x -19x -19x -  -19x -  -19x -18x -18x -  -  -  -  -  -  -19x -  -  -  -  -  -  -  -  -  -18x -18x -18x -  -18x -  -18x -30x -  -30x -  -  -  -  -  -  -  -30x -14x -  -30x -19x -  -  -  -18x -  -  -  -  -  -  -  -  -  -87x -1x -  -  -87x -87x -  -87x -  -  -87x -86x -  -  -86x -  -86x -1x -  -85x -  -  -  -  -  -  -  -110x -  -110x -110x -105x -105x -104x -  -  -  -  -  -  -  -1x -1x -  -  -5x -5x -  -  -  -  -  -  -  -  -  -  -3x -3x -  -3x -  -3x -  -  -  -3x -3x -  -  -  -  -  -  -  -1x -1x -  -  -2x -2x -1x -  -  -1x -  -  -  -  -  -  -  -  -  -3x -3x -  -3x -  -3x -  -  -  -3x -3x -  -  -  -  -  -  -  -1x -1x -  -  -2x -2x -1x -  -  -1x -  -  -  -  -  -  -  -  -2x -2x -2x -  -  -  -2x -2x -  -  -  -  -  -1x -1x -  -  -1x -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -5x -5x -  -  -  -  -  -  -  -2x -2x -  -  -  -  -  -  -  -  -  -  -  -  -24x -24x -  -24x -1x -  -  -23x -  -  -  -  -  -  -  -23x -  -  -  -  -  -23x -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -8x -  -8x -  -  -  -  -  -  -8x -  -  -  -  -  -8x -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -3x -3x -1x -  -  -3x -1x -  -  -3x -  -  -  -  -  -  -  -  -3x -  -  -  -  -  -3x -3x -3x -6x -  -  -3x -  -  -  -  -  -  -8x -  -  -  -  -8x -  -  -  -  -  -8x -  -8x -8x -8x -8x -8x -  -8x -7x -6x -5x -  -1x -  -  -5x -4x -  -1x -  -  -4x -3x -  -1x -  -  -1x -  -  -3x -2x -  -1x -  -  -2x -1x -  -1x -  -  -  -1x -  -  -1x -  -  -  -  -  -  -  -  -  -  -  -  -  -1x -  -  -  -4x -  -  -  -  -4x -  -  -  -  -  -4x -  -  -  -4x -  -  -  -  -  -1x -  -  -  -  -  -3x -  -  -1x -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -29x -  -29x -27x -27x -17x -  -27x -  -  -  -  -  -  -  -  -  -  -  -  -29x -29x -  -  -  -  -29x -29x -29x -25x -  -29x -2x -1x -  -1x -  -28x -2x -1x -  -1x -  -27x -25x -  -27x -  -27x -  -  -  -  -27x -  -  -  -  -  -  -  -  -  -  -  -  -  -  -27x -  -27x -  -  -26x -26x -  -17x -  -  -27x -  -  -  -  -  -  -  -  -24x -24x -14x -  -10x -  -  -  -  -  -  -  -  -  -4x -4x -  -  -  -  -4x -4x -  -4x -  -  -  -  -4x -4x -  -4x -1x -  -  -3x -  -  -2x -2x -4x -  -  -  -3x -  -  -  -  -  -  -  -  -  -5x -5x -  -  -  -  -5x -5x -  -5x -  -  -  -  -5x -5x -  -5x -1x -  -  -4x -  -3x -3x -1x -  -  -  -4x -  -  -  -  -  -  -  -  -  -  -18x -18x -  -  -  -  -18x -18x -  -  -  -  -18x -  -18x -1x -  -  -17x -14x -  -3x -  -  -  -  -  -  -  -  -  -  -23x -23x -  -  -  -23x -23x -  -  -  -  -23x -  -23x -8x -  -  -15x -1x -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -47x -47x -  -  -  -  -47x -47x -47x -46x -  -47x -4x -1x -  -3x -  -46x -2x -1x -  -1x -  -45x -44x -  -45x -  -45x -  -  -  -  -45x -  -  -  -  -  -  -  -  -  -  -  -  -  -  -45x -  -45x -  -  -44x -44x -43x -  -  -  -45x -  -  -  -  -  -  -  -  -  -72x -72x -  -  -  -  -72x -72x -  -72x -  -  -  -  -72x -  -72x -1x -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -71x -71x -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -71x -35x -  -36x -35x -  -36x -36x -1x -  -36x -1x -  -  -71x -  -  -  -  -  -  -  -  -  -4x -4x -  -  -  -  -4x -4x -  -4x -  -  -  -  -4x -  -4x -2x -  -2x -  -  -  -  -  -  -  -  -  -5x -5x -  -  -  -  -5x -5x -  -5x -  -  -  -  -5x -  -5x -3x -  -2x -  -  -  -  -  -  -  -  -  -36x -36x -  -  -  -  -36x -36x -  -36x -  -  -  -  -36x -  -36x -18x -  -18x -  -  -  -  -  -  -  -  -41x -41x -41x -35x -  -6x -  -  -  -  -  -  -  -  -  -  -  -23x -23x -23x -4x -3x -  -1x -  -  -22x -19x -  -  -22x -  -  -  -  -22x -22x -  -  -  -  -22x -  -22x -1x -  -  -21x -21x -18x -  -  -3x -  -  -  -  -  -  -  -  -  -  -  -  -  -51x -51x -  -51x -  -  -  -  -51x -51x -51x -  -  -  -  -51x -  -  -  -  -  -  -  -  -  -  -51x -1x -  -  -50x -32x -  -  -18x -3x -  -  -18x -  -  -  -  -  -  -  -  -5x -  -5x -  -  -  -5x -5x -5x -  -  -  -  -5x -  -5x -1x -  -  -4x -2x -  -2x -  -  -  -  -  -  -  -  -  -  -  -  -  -16x -  -16x -16x -  -  -  -  -  -16x -16x -  -16x -  -  -  -  -16x -  -16x -9x -  -  -6x -1x -  -  -5x -1x -  -  -4x -1x -  -  -3x -  -  -  -  -  -  -  -  -  -  -  -  -  -14x -  -14x -14x -  -  -  -  -  -14x -14x -  -14x -  -  -  -  -12x -  -12x -7x -  -  -5x -1x -  -  -4x -1x -  -  -3x -1x -  -  -2x -  -  -  -  -  -  -  -  -  -  -  -  -  -13x -  -13x -13x -  -  -  -  -  -13x -13x -  -13x -  -  -  -  -13x -  -13x -8x -  -  -5x -1x -  -  -4x -1x -  -  -3x -1x -  -  -2x -  -  -  -  -  -  -  -  -  -  -  -10x -  -10x -10x -  -  -  -  -  -10x -10x -  -10x -  -  -  -  -10x -  -10x -4x -  -  -  -  -  -  -  -  -  -  -  -  -  -6x -1x -  -  -5x -  -  -  -  -  -  -  -  -  -12x -12x -18x -18x -  -  -18x -2x -2x -1x -  -1x -1x -1x -  -  -16x -  -  -17x -17x -17x -  -  -  -  -17x -7x -3x -3x -2x -  -1x -  -  -  -7x -2x -2x -1x -  -1x -  -  -  -  -  -  -  -17x -6x -3x -3x -2x -  -1x -  -  -  -6x -2x -2x -1x -  -1x -  -  -  -  -  -  -  -17x -8x -8x -8x -4x -2x -1x -  -  -  -13x -10x -  -8x -8x -8x -8x -8x -5x -5x -  -2x -2x -  -  -6x -6x -  -1x -1x -  -  -  -8x -5x -5x -  -2x -2x -  -  -8x -3x -  -5x -5x -  -  -  -  -  -  -  -  -17x -8x -8x -10x -8x -  -8x -8x -8x -7x -7x -2x -2x -  -1x -1x -  -  -6x -6x -  -1x -1x -  -  -  -8x -4x -4x -  -1x -1x -  -  -8x -3x -  -5x -  -  -  -  -  -  -  -17x -6x -6x -6x -6x -4x -4x -3x -  -1x -  -  -  -  -  -  -  -17x -6x -6x -6x -6x -3x -3x -2x -  -1x -  -  -  -  -  -  -  -17x -5x -5x -5x -5x -3x -3x -1x -  -2x -  -  -  -  -  -  -  -17x -5x -5x -5x -5x -3x -3x -1x -  -2x -  -  -  -  -  -  -  -17x -6x -6x -6x -6x -3x -3x -2x -  -1x -  -  -  -  -  -  -  -17x -6x -6x -6x -6x -4x -4x -3x -  -1x -  -  -  -  -  -  -  -17x -5x -5x -5x -5x -5x -3x -  -2x -  -  -  -  -  -  -17x -6x -6x -6x -6x -3x -3x -2x -  -1x -  -  -  -  -  -  -  -17x -6x -6x -6x -6x -3x -3x -2x -  -1x -  -  -  -  -  -  -  -17x -5x -5x -5x -5x -3x -3x -1x -  -2x -  -  -  -  -  -  -  -17x -6x -6x -6x -6x -2x -2x -1x -  -1x -  -  -  -  -17x -1x -  -17x -  -12x -  -  -  -  -  -  -  -  -  -  -  -  -2x -2x -  -2x -  -  -  -  -2x -  -  -2x -  -  -  -  -  -2x -2x -2x -  -  -  -  -  -  -  -  -  -  -  -  -  -  -3x -  -3x -  -  -  -  -3x -  -3x -  -  -  -  -  -  -  -  -  -  -  -  -  -10x -  -  -  -10x -  -10x -  -  -  -  -  -10x -10x -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -1x -  -  -  -1x -  -1x -  -  -  -  -  -  -  -  -  -  -  -  -  -  -3x -  -  -  -  -3x -  -  -  -  -  -  -3x -1x -  -  -2x -  -2x -  -2x -1x -  -1x -  -  -1x -1x -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -411x -  -411x -1x -  -  -410x -1x -  -  -409x -  -409x -1x -  -408x -  -  -408x -  -  -408x -2x -  -  -  -406x -309x -  -  -  -  -  -  -406x -406x -  -661x -1x -  -  -660x -1x -  -659x -  -  -659x -329x -  -  -659x -989x -1x -  -988x -594x -1x -  -593x -593x -593x -  -  -  -  -402x -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -1229x -369x -  -  -  -1229x -1229x -  -  -  -  -  -  -  -  -  -  -  -  -37x -37x -37x -37x -  -37x -19x -  -18x -  -37x -37x -  -  -  -  -  -36x -90x -32x -18x -  -  -58x -30x -30x -  -  -  -  -1x -  -  -37x -  -  -  -536x -4x -  -  -536x -536x -7x -  -  -536x -  -  -  -145x -  -  -  -  -94x -94x -  -94x -  -  -94x -94x -  -  -  -  -  -  -  -11x -11x -  -  -  -  -  -400x -400x -  -400x -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -400x -400x -  -  -  -  -  -  -  -109x -109x -  -  -291x -291x -  -291x -290x -  -  -  -  -  -  -  -290x -105x -  -185x -  -  -290x -104x -  -  -  -291x -1x -1x -  -  -290x -  -  -  -  -397x -397x -  -  -396x -396x -334x -  -396x -  -1x -  -  -  -405x -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -374x -  -  -  -  -86x -86x -  -86x -  -  -  -  -86x -86x -86x -  -  -  -86x -  -  -  -  -  -  -86x -  -  -  - 
// this must be the first
-import { config } from "dotenv";
-config();
- 
-import UploadFilesCommand, { UploadFilesCommandOptions, SourceTargetFileNames } from "./uploadFilesCommand";
-import UploadFolderCommand, { UploadFolderCommandOptions } from "./uploadFolderCommand";
-import GetFilesRecursivelyCommand, { GetFilesRecursivelyCommandOptions } from "./getFilesRecursivelyCommand";
-import { CommandStatus, CommandResultMetaData } from "./command";
-import debugFactory from "debug";
-import parser from "fast-xml-parser";
-import {
-    Headers,
-    RequestInit,
-    Response,
-} from "node-fetch";
-import path, { basename } from "path";
-import Environment from "./environment";
-import EnvironmentVcapServices from "./environmentVcapServices";
-import ClientError, {
-    CommandAlreadyExecutedError,
-    QueryLimitError,
-    QueryOffsetError,
-    InsufficientPrivilegesError,
-    InvalidServiceResponseFormatError,
-    OperationFailedError,
-    UserGroupAlreadyExistsError,
-    UserGroupDeletionFailedError,
-    UserResendWelcomeEmailError,
-    UserGroupDoesNotExistError,
-    UserNotFoundError,
-    UserAlreadyExistsError,
-    UserCreateError,
-    UserUpdateError,
-} from "./error";
-import FakeServer from "./fakeServer";
-import File from "./file";
-import FileSystemElement from "./fileSystemElement";
-import FileSystemFolder, { IFileNameFormats } from "./fileSystemFolder";
-import Folder, { FolderGetFilesOptions } from "./folder";
-import { HttpClient, IHttpClientOptions, IProxy, IRequestContext } from "./httpClient";
-import RequestResponseLog from "./requestResponseLog";
-import RequestResponseLogEntry from "./requestResponseLogEntry";
-import Server, { IServerOptions } from "./server";
-import Share, { ICreateShare, SharePermission } from "./share";
-import Tag from "./tag";
-import UserGroup from "./userGroup";
-import User, { IUserOptions, IUserOptionsQuota, IUserQuotaUserFriendly, UserProperty } from "./user";
- 
-export {
-    FolderGetFilesOptions,
-    CommandAlreadyExecutedError,
-    InvalidServiceResponseFormatError,
-    InsufficientPrivilegesError,
-    OperationFailedError,
-    QueryLimitError,
-    QueryOffsetError,
-    UserNotFoundError,
-    UserAlreadyExistsError,
-    UserCreateError,
-    UserResendWelcomeEmailError,
-    UserUpdateError,
-    UserGroupAlreadyExistsError,
-    UserGroupDeletionFailedError,
-    UserGroupDoesNotExistError,
-}
- 
-export {
-    Client,
-    ClientError,
-    Environment,
-    Folder,
-    File,
-    FileSystemElement,
-    ICreateShare,
-    IServerOptions,
-    Tag,
-    FakeServer,
-    Server,
-    Share,
-    SharePermission,
-    RequestResponseLog,
-    RequestResponseLogEntry,
-    User,
-    UserGroup,
-    UserProperty,
-    IUserOptionsQuota,
-    IUserQuotaUserFriendly,
-};
- 
-// command object for upload
-export {
-    CommandResultMetaData,
-    GetFilesRecursivelyCommand,
-    GetFilesRecursivelyCommandOptions,
-    UploadFilesCommand,
-    UploadFilesCommandOptions,
-    UploadFolderCommand,
-    UploadFolderCommandOptions,
-    SourceTargetFileNames,
-    FileSystemFolder,
-    IFileNameFormats,
-    CommandStatus,
-}
- 
-const debug = debugFactory("NCClient");
-// const debug = console.log;
- 
-interface IStat {
-    "type": string;
-    "filename": string;
-    "basename": string;
-    "lastmod": string;
-    "size"?: number;
-    "mime"?: string;
-    "fileid"?: number;
-}
- 
-export interface IUpsertUserOptions {
-    "id": string;
-    "enabled"?: boolean;
-    "subadminGroups"?: string[],
-    "memberGroups"?: string[],
-    "quota"?: string,
-    "email"?: string,
-    "displayName"?: string,
-    "password"?: string,
-    "phone"?: string,
-    "address"?: string,
-    "website"?: string,
-    "twitter"?: string,
-    "language"?: string
-    "locale"?: string,
-    "superAdmin"?: boolean,
-    "resendWelcomeEmail"?: boolean,
-}
- 
-export interface IUserPropertyChange {
-    "property": string;
-    "previousValue": string;
-    "newValue": string;
-    "error"?: string;
-}
- 
-export interface IUpsertUserReport {
-    "id": string;
-    "message": string;
-    "changes": IUserPropertyChange[];
-}
- 
-export interface ISysInfoNextcloudClient {
-    "version": string;
-}
- 
-export interface ISysInfoNextcloud {
-    "system": object;
-    "storage": object;
-    "shares": object;
-}
- 
-export interface ISysBasicData {
-    "serverTimeString": string;
-    "uptimeString": string;
-    "timeServersString": string;
-}
- 
-export interface ISystemInfo {
-    "nextcloud": ISysInfoNextcloud;
-    // @todo change object to something strongly typed
-    "server": object;
-    // @todo change object to something strongly typed
-    "activeUsers": object;
-    "nextcloudClient": ISysInfoNextcloudClient;
-}
- 
-export interface IQuota {
-    used: number;
-    available: number | string;
-}
- 
-/**
- * The nextcloud client is the root object to access the remote api of the nextcloud server.<br>
- */
-export default class Client {
- 
-    public static webDavUrlPath: string = "/remote.php/webdav";
- 
-    private nextcloudOrigin: string;
-    private nextcloudAuthHeader: string;
-    private nextcloudRequestToken: string;
-    private webDAVUrl: string;
-    private proxy?: IProxy;
-    private fakeServer?: FakeServer;
-    private logRequestResponse: boolean = false;
-    private httpClient?: HttpClient;
-    private userId: string;
- 
-    /**
-     * Creates a new instance of a nextcloud client.<br/>
-     * Use the server to provide server connectivity information to the client.<br/>
-     * (The FakeServer is only used for testing and code coverage)<br/><br/>
-     * If the server is not provided the client tries to find the connectivity information
-     * in the environment.<br/>
-     * If a <b>VCAP_SERVICES</b> environment variable is available, the client tries to find
-     * a service with the name <b>"nextcloud"</b> in the user-provides-services section.<br/>
-     * If no VCAP_SERVICES are available, the client uses the following variables
-     * from the envirnonment for the connectivity:<br/>
-     * <ul>
-     * <li>NEXTCLOUD_URL - the WebDAV url of the nextcloud server</li>
-     * <li>NEXTCLOUD_USERNAME - the user name</li>
-     * <li>NEXTCLOUD_PASSWORD - the application password</li>
-     * </ul>
-     * @param server optional server information to connection to a nextcloud server
-     * @constructor
-     */
-    public constructor(server?: Server | FakeServer) {
-        debug("constructor");
-        this.nextcloudOrigin = "";
-        this.nextcloudAuthHeader = "";
-        this.nextcloudRequestToken = "";
-        this.webDAVUrl = "";
-        this.userId = "";
- 
-        // if no server is provided, try to get a server from VCAP_S environment "nextcloud" instance
-        // If no VCAP_S environment exists try from environment
-        if (!server) {
-            try {
-                const env: EnvironmentVcapServices = new EnvironmentVcapServices("nextcloud");
-                server = env.getServer();
-            } catch (e) {
-                const env: Environment = new Environment();
-                server = env.getServer();
-            }
-        }
- 
-        if (server instanceof Server) {
- 
-            this.proxy = server.proxy;
- 
-            debug("constructor: webdav url %s", server.url);
- 
-            if (server.url.indexOf(Client.webDavUrlPath) === -1) {
-                // not a valid nextcloud url
-                throw new ClientError(`The provided nextcloud url "${server.url}" does not comply to the nextcloud url standard, "${Client.webDavUrlPath}" is missing`,
-                    "ERR_INVALID_NEXTCLOUD_WEBDAV_URL");
-            }
-            this.nextcloudOrigin = server.url.substr(0, server.url.indexOf(Client.webDavUrlPath));
- 
-            debug("constructor: nextcloud url %s", this.nextcloudOrigin);
-            this.userId = server.basicAuth.username;
-            this.nextcloudAuthHeader = "Basic " + Buffer.from(server.basicAuth.username + ":" + server.basicAuth.password).toString("base64");
-            this.nextcloudRequestToken = "";
-            if (server.url.slice(-1) === "/") {
-                this.webDAVUrl = server.url.slice(0, -1);
-            } else {
-                this.webDAVUrl = server.url;
-            }
- 
-            this.logRequestResponse = server.logRequestResponse;
- 
-            const options: IHttpClientOptions = {
-                authorizationHeader: this.nextcloudAuthHeader,
-                logRequestResponse: this.logRequestResponse,
-                origin: this.nextcloudOrigin,
-                proxy: this.proxy,
-            };
- 
-            this.httpClient = new HttpClient(options);
-        }
- 
-        if (server instanceof FakeServer) {
-            this.fakeServer = server;
-            this.webDAVUrl = "https://fake.server" + Client.webDavUrlPath;
-        }
-    }
- 
-    /**
-     * returns the used and free quota of the nextcloud account
-     */
-    public async getQuota(): Promise<IQuota> {
-        debug("getQuota");
-        const requestInit: RequestInit = {
-            method: "PROPFIND",
-        };
- 
-        const response: Response = await this.getHttpResponse(
-            this.webDAVUrl + "/",
-            requestInit,
-            [207],
-            { description: "Client get quota" });
- 
-        const properties: any[] = await this.getPropertiesFromWebDAVMultistatusResponse(response, Client.webDavUrlPath + "/");
- 
-        let quota: IQuota | null = null;
-        for (const prop of properties) {
-            if (prop["quota-available-bytes"]) {
-                quota = {
-                    available: "unlimited",
-                    used: prop["quota-used-bytes"],
-                };
-                if (prop["quota-available-bytes"] > 0) {
-                    quota.available = prop["quota-available-bytes"];
-                }
-            }
-        }
- 
-        if (!quota) {
-            debug("Error, quota not available: %s ", JSON.stringify(properties, null, 4));
-            throw new ClientError(`Error, quota not available`, "ERR_QUOTA_NOT_AVAILABLE");
-        }
-        debug("getQuota = %O", quota);
-        return quota;
-    }
- 
-    // ***************************************************************************************
-    // tags
-    // ***************************************************************************************
- 
-    /**
-     * creates a new tag, if not already existing
-     * this function will fail with http 403 if the user does not have admin privileges
-     * @param tagName the name of the tag
-     * @returns tagId
-     */
-    public async createTag(tagName: string): Promise<Tag> {
- 
-        debug("createTag");
-        let tag: Tag | null;
-        // is the tag already existing?
-        tag = await this.getTagByName(tagName);
-        if (tag) {
-            return tag;
-        }
-        // tag does not exist, create tag
- 
-        const requestInit: RequestInit = {
-            body: `{ "name": "${tagName}", "userVisible": true, "userAssignable": true, "canAssign": true }`,
-            headers: new Headers({ "Content-Type": "application/json" }),
-            method: "POST",
-        };
- 
-        const response: Response = await this.getHttpResponse(
-            this.nextcloudOrigin + "/remote.php/dav/systemtags/",
-            requestInit,
-            [201],
-            { description: "Tag create" },
-        );
-        const tagString: string | null = response.headers.get("Content-Location");
-        debug("createTag new tagId %s, tagName %s", tagString, tagName);
-        if (tagString === "" || tagString === null) {
-            throw new ClientError(`Error, tag with name '${tagName}' could not be created`, "ERR_TAG_CREATE_FAILED");
-        }
- 
-        // the number id of the tag is the last element in the id (path)
-        const tagId: number = this.getTagIdFromHref(tagString);
- 
-        tag = new Tag(this, tagId, tagName, true, true, true);
-        return tag;
-    }
- 
-    /**
-     * returns a tag identified by the name or null if not found
-     * @param tagName the name of the tag
-     * @returns tag or null
-     */
-    public async getTagByName(tagName: string): Promise<Tag | null> {
- 
-        debug("getTag");
- 
-        const tags: Tag[] = await this.getTags();
-        for (const tag of tags) {
-            if (tag.name === tagName) {
-                return tag;
-            }
-        }
-        return null;
-    }
- 
-    /**
-     * returns a tag identified by the id or null if not found
-     * @param tagId the id of the tag
-     * @returns tag or null
-     */
-    public async getTagById(tagId: number): Promise<Tag | null> {
- 
-        debug("getTagById");
- 
-        const tags: Tag[] = await this.getTags();
-        for (const tag of tags) {
-            if (tag.id === tagId) {
-                return tag;
-            }
-        }
-        return null;
-    }
- 
-    /**
-     * deletes the tag by id
-     * this function will fail with http 403 if the user does not have admin privileges
-     * @param tagId the id of the tag like "/remote.php/dav/systemtags/234"
-     */
-    public async deleteTag(tagId: number): Promise<void> {
- 
-        debug("deleteTag tagId: $s", tagId);
- 
-        const requestInit: RequestInit = {
-            method: "DELETE",
-        };
- 
-        const response: Response = await this.getHttpResponse(
-            `${this.nextcloudOrigin}/remote.php/dav/systemtags/${tagId}`,
-            requestInit,
-            [204, 404],
-            { description: "Tag delete" });
-    }
- 
-    /**
-     * deletes all visible assignable tags
-     * @throws Error
-     */
-    public async deleteAllTags(): Promise<void> {
- 
-        debug("deleteAllTags");
- 
-        const tags: Tag[] = await this.getTags();
- 
-        for (const tag of tags) {
-            // debug("deleteAllTags tag: %O", tag);
-            await tag.delete();
-        }
-    }
- 
-    /**
-     * returns a list of tags
-     * @returns array of tags
-     */
-    public async getTags(): Promise<Tag[]> {
-        debug("getTags PROPFIND %s", this.nextcloudOrigin + "/remote.php/dav/systemtags/");
-        const requestInit: RequestInit = {
-            body: `<?xml version="1.0"?>
-            <d:propfind  xmlns:d="DAV:" xmlns:oc="http://owncloud.org/ns">
-              <d:prop>
-                <oc:id />
-                <oc:display-name />
-                <oc:user-visible />
-                <oc:user-assignable />
-                <oc:can-assign />
-              </d:prop>
-            </d:propfind>`,
-            method: "PROPFIND",
-        };
- 
-        const relUrl = `/remote.php/dav/systemtags/`;
- 
-        const response: Response = await this.getHttpResponse(
-            this.nextcloudOrigin + relUrl,
-            requestInit,
-            [207],
-            { description: "Tags get" });
- 
-        const properties: any[] = await this.getPropertiesFromWebDAVMultistatusResponse(response, relUrl + "/*");
-        const tags: Tag[] = [];
- 
-        for (const prop of properties) {
-            tags.push(new Tag(this,
-                this.getTagIdFromHref(prop._href),
-                prop["display-name"],
-                prop["user-visible"],
-                prop["user-assignable"],
-                prop["can-assign"]));
-        }
- 
-        return tags;
-    }
- 
-    /**
-     * returns the list of tag names and the tag ids
-     * @param fileId the id of the file
-     */
-    public async getTagsOfFile(fileId: number): Promise<Map<string, number>> {
-        debug("getTagsOfFile");
- 
-        const requestInit: RequestInit = {
-            body: `<?xml version="1.0"?>
-            <d:propfind  xmlns:d="DAV:" xmlns:oc="http://owncloud.org/ns">
-              <d:prop>
-                <oc:id />
-                <oc:display-name />
-                <oc:user-visible />
-                <oc:user-assignable />
-                <oc:can-assign />
-              </d:prop>
-            </d:propfind>`,
-            method: "PROPFIND",
-        };
- 
-        const relUrl = `/remote.php/dav/systemtags-relations/files/${fileId}`;
-        const response: Response = await this.getHttpResponse(
-            `${this.nextcloudOrigin}${relUrl}`,
-            requestInit,
-            [207],
-            { description: "File get tags" });
- 
-        const properties: any[] = await this.getPropertiesFromWebDAVMultistatusResponse(response, relUrl + "/*");
-        const tagMap: Map<string, number> = new Map();
- 
-        for (const prop of properties) {
-            tagMap.set(prop["display-name"], prop.id);
-        }
- 
-        debug("tags of file %O", tagMap);
-        return tagMap;
-    }
- 
-    /**
-     * removes the tag from the file
-     * @param fileId the file id
-     * @param tagId the tag id
-     */
-    public async removeTagOfFile(fileId: number, tagId: number): Promise<void> {
-        debug("removeTagOfFile tagId: $s fileId:", tagId, fileId);
- 
-        const requestInit: RequestInit = {
-            method: "DELETE",
-        };
- 
-        const response: Response = await this.getHttpResponse(
-            `${this.nextcloudOrigin}/remote.php/dav/systemtags-relations/files/${fileId}/${tagId}`,
-            requestInit,
-            [204, 404],
-            { description: "File remove tag" });
-        return;
-    }
- 
-    /**
-     * returns the id of the file or -1 of not found
-     * @returns id of the file or -1 if not found
-     */
-    public async getFileId(fileUrl: string): Promise<number> {
-        debug("getFileId");
- 
-        const requestInit: RequestInit = {
-            body: `
-            <d:propfind  xmlns:d="DAV:" xmlns:oc="http://owncloud.org/ns" xmlns:nc="http://nextcloud.org/ns">
-              <d:prop>
-                  <oc:fileid />
-              </d:prop>
-            </d:propfind>`,
-            method: "PROPFIND",
-        };
- 
-        const response: Response = await this.getHttpResponse(
-            fileUrl,
-            requestInit,
-            [207],
-            { description: "File get id" });
- 
-        const properties: any[] = await this.getPropertiesFromWebDAVMultistatusResponse(response, "");
- 
-        for (const prop of properties) {
-            if (prop.fileid) {
-                return prop.fileid;
-            }
-        }
- 
-        debug("getFileId no file id found for %s", fileUrl);
-        return -1;
-    }
- 
-    public async getFolderContents(folderName: string): Promise<any[]> {
-        debug("getFolderContents");
- 
-        const requestInit: RequestInit = {
-            body: `<?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:getetag />
-                <d:getcontenttype />
-                <d:resourcetype />
-                <oc:fileid />
-                <oc:permissions />
-                <oc:size />
-                <d:getcontentlength />
-                <nc:has-preview />
-                <nc:mount-type />
-                <nc:is-encrypted />
-                <ocs:share-permissions />
-                <oc:tags />
-                <oc:favorite />
-                <oc:comments-unread />
-                <oc:owner-id />
-                <oc:owner-display-name />
-                <oc:share-types />
-              </d:prop>
-            </d:propfind>`,
-            method: "PROPFIND",
-        };
-        const url = `${this.webDAVUrl}${folderName}`;
-        const response: Response = await this.getHttpResponse(
-            url,
-            requestInit,
-            [207],
-            { description: "Folder get contents" });
-        const folderContents: any[] = [];
- 
-        let properties: any[];
-        try {
-            properties = await this.getPropertiesFromWebDAVMultistatusResponse(response, "");
-        } catch (e) {
-            return folderContents;
-        }
- 
-        // tslint:disable-next-line:no-empty
-        for (const prop of properties) {
-            let fileName = decodeURI(prop._href.substr(prop._href.indexOf(Client.webDavUrlPath) + 18));
-            if (fileName.endsWith("/")) {
-                fileName = fileName.slice(0, -1);
-            }
-            if ((url + "/").endsWith(decodeURI(prop._href))) {
-                continue;
-            }
-            const folderContentsEntry: any = {};
-            folderContentsEntry.lastmod = prop.getlastmodified;
-            folderContentsEntry.fileid = prop.fileid;
-            folderContentsEntry.basename = fileName.split("/").reverse()[0];
-            folderContentsEntry.filename = fileName;
-            if (prop.getcontenttype) {
-                folderContentsEntry.mime = prop.getcontenttype;
-                folderContentsEntry.size = prop.getcontentlength;
-                folderContentsEntry.type = "file";
-            } else {
-                folderContentsEntry.type = "directory";
-            }
-            Eif (folderContentsEntry.basename !== "") {
-                folderContents.push(folderContentsEntry);
-            }
- 
-        }
- 
-        // debug("folderContentsEntry $s", JSON.stringify(folderContents, null, 4));
-        return folderContents;
-    }
- 
-    /**
-     * creates a folder and all parent folders in the path if they do not exist
-     * @param folderName name of the folder /folder/subfolder/subfolder
-     * @returns a folder object
-     */
-    public async createFolder(folderName: string): Promise<Folder> {
-        folderName = this.sanitizeFolderName(folderName);
-        debug("createFolder: folderName=%s", folderName);
- 
-        const parts1: string[] = folderName.split("/");
-        for (const p of parts1) {
-            if ((p) === "." || p === "..") {
-                throw new ClientError(`Error creating folder, folder name "${folderName}" invalid`, "ERR_CREATE_FOLDER_INVALID_FOLDER_NAME");
-            }
-        }
- 
-        let folder: Folder | null;
- 
-        folder = await this.getFolder(folderName);
-        if (folder) {
-            debug("createFolder: folder already available %O", folder.name);
-            return folder;
-        } else {
-            // try to do a simple create with the complete path
-            try {
-                debug("createFolder: folder = %s", folderName);
-                await this.createFolderInternal(folderName);
-            } catch (e) {
-                // create all folders in the path
-                const parts: string[] = folderName.split("/");
-                parts.shift();
-                let folderPath: string = "";
-                debug("createFolder: parts = %O", parts);
- 
-                for (const part of parts) {
- 
-                    debug("createFolder: part = %O", part);
-                    folderPath += "/" + part;
-                    folder = await this.getFolder(folderPath);
- 
-                    if (folder === null) {
-                        debug("createFolder: folder not available");
-                        // folder not  available
- 
-                        debug("createFolder: folder = %s", folderPath);
-                        await this.createFolderInternal(folderPath);
-                    } else {
-                        debug("createFolder: folder already available %s", folderPath);
-                    }
-                }
-            }
-        }
- 
-        folder = await this.getFolder(folderName);
-        if (folder) {
-            debug("createFolder: new folder %O", folder.name);
-            return folder;
-        } else {
-            throw new ClientError(`Error creating folder, folder name "${folderName}"
-            `, "ERR_CREATE_FOLDER_FAILED");
-        }
- 
-    }
- 
-    /**
-     * deletes a file
-     * @param fileName name of folder "/f1/f2/f3/x.txt"
-     */
-    public async deleteFile(fileName: string): Promise<void> {
- 
-        const url: string = this.webDAVUrl + fileName;
-        debug("deleteFile %s", url);
- 
-        const requestInit: RequestInit = {
-            method: "DELETE",
-        };
-        try {
-            await this.getHttpResponse(
-                url,
-                requestInit,
-                [204],
-                { description: "File delete" },
-            );
- 
-        } catch (err) {
-            debug("Error in deleteFile %s %s %s", err.message, requestInit.method, url);
-            throw err;
-        }
-    }
- 
-    /**
-     * deletes a folder
-     * @param folderName name of folder "/f1/f2/f3"
-     */
-    public async deleteFolder(folderName: string): Promise<void> {
-        folderName = this.sanitizeFolderName(folderName);
-        debug("deleteFolder:");
- 
-        const folder: Folder | null = await this.getFolder(folderName);
- 
-        if (folder) {
-            await this.deleteFile(folderName);
-        }
-    }
- 
-    /**
-     * get the root folder object
-     * @returns {Promise<Folder>} the root folder
-     */
-    public getRootFolder(): Folder {
-        return new Folder(this, "/", "", "");
-    }
- 
-    /**
-     * returns an array of file system objects that have all given tags assigned (AND)
-     * @param {Tag[]} tags array of tags
-     * @async
-     * @returns {Promise<FileSystemElement[]>} returns an array of file system objects
-     */
-    public async getFileSystemElementByTags(tags: Tag[]): Promise<FileSystemElement[]> {
-        debug("getFileSystemElementByTags %s", tags.join(", "));
-        let filterRule: string = "";
- 
-        for (const tag of tags) {
-            filterRule += `<oc:systemtag>${tag.id}</oc:systemtag>`;
-        }
-        const urlSuffix = `/remote.php/dav/files/`;
-        const url = `${this.nextcloudOrigin}${urlSuffix}${this.userId}`;
-        const body = `<?xml version="1.0"?>
-        <oc:filter-files  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:getcontenttype />
-              <oc:fileid />
-           </d:prop>
-           <oc:filter-rules>
-                ${filterRule}
-           </oc:filter-rules>
-        </oc:filter-files>`;
-        const requestInit: RequestInit = {
-            body,
-            // headers: new Headers({ Depth: "0" }),
-            method: "REPORT",
-        };
-        let response: Response;
-        try {
-            response = await this.getHttpResponse(
-                url,
-                requestInit,
-                [207],
-                { description: "Get FileSystemElements by tags" },
-            );
- 
-        } catch (err) {
-            debug("Error in stat %s %s %s %s", err.message, requestInit.method, url);
-            throw err;
-        }
-        const result: FileSystemElement[] = [];
- 
-        let properties: any[] = [];
-        try {
-            properties = await this.getPropertiesFromWebDAVMultistatusResponse(response, "");
-        } catch (e) {
-            return result
-        }
- 
-        for (const prop of properties) {
-            let fse: FileSystemElement | null = null;
-            let name: string = prop._href;
- 
-            // remove the first two elements from the path
-            name = name.replace(urlSuffix, "");
-            const a: string[] = name.split("/")
-            a.shift();
-            name = "/" + a.join("/");
-            // console.log(name);
-            if (prop.getcontenttype) {
-                fse = await this.getFile(name);
-            } else {
-                fse = await this.getFolder(name);
-            }
- 
-            result.push(fse!);
- 
-        }
-        return result;
-    }
- 
-    /**
-     * get a folder object from a path string
-     * @param {string} folderName Name of the folder like "/company/branches/germany"
-     * @returns {Promise<Folder | null>} null if the folder does not exist or an folder object
-     */
-    public async getFolder(folderName: string): Promise<Folder | null> {
-        folderName = this.sanitizeFolderName(folderName);
-        debug("getFolder %s", folderName);
- 
-        // return root folder
-        if (folderName === "/" || folderName === "") {
-            return this.getRootFolder();
-        }
- 
-        try {
-            const stat: IStat = await this.stat(folderName);
-            debug(": SUCCESS!!");
-            if (stat.type !== "file") {
-                return new Folder(this,
-                    stat.filename.replace(/\\/g, "/"),
-                    stat.basename,
-                    stat.lastmod,
-                    stat.fileid);
-            } else {
-                debug("getFolder: found object is file not a folder");
-                return null;
-            }
-        } catch (e) {
-            debug("getFolder: exception occurred calling stat %O", e.message);
-            return null;
-        }
-    }
- 
-    /**
-     * get a array of folders from a folder path string
-     * @param folderName Name of the folder like "/company/branches/germany"
-     * @returns array of folder objects
-     */
-    public async getSubFolders(folderName: string): Promise<Folder[]> {
-        debug("getSubFolders: folder %s", folderName);
-        const folders: Folder[] = [];
-        folderName = this.sanitizeFolderName(folderName);
- 
-        const folderElements: any[] = await this.Contents(folderName, true);
- 
-        for (const folderElement of folderElements) {
-            debug("getSubFolders: adding subfolders %s", folderElement.filename);
-            folders.push(new Folder(this,
-                folderElement.filename.replace(/\\/g, "/"),
-                folderElement.basename,
-                folderElement.lastmod,
-                folderElement.fileid));
-        }
- 
-        return folders;
-    }
- 
-    /**
-     * get files of a folder
-     * @param {string} folderName Name of the folder like "/company/branches/germany"
-     * @param {FolderGetFilesOptions} options options for filtering and paging
-     * @returns array of file objects
-     */
-    public async getFiles(folderName: string, options?: FolderGetFilesOptions): Promise<File[]> {
-        debug("getFiles: folder %s", folderName);
-        const files: File[] = [];
-        folderName = this.sanitizeFolderName(folderName);
- 
-        const fileElements: any[] = await this.Contents(folderName, false);
- 
-        for (const folderElement of fileElements) {
-            debug("getFiles: adding file %s", folderElement.filename);
-            // debug("getFiles: adding file %O", folderElement);
-            let file: File | null = new File(this,
-                folderElement.filename.replace(/\\/g, "/"),
-                folderElement.basename,
-                folderElement.lastmod,
-                folderElement.size,
-                folderElement.mime,
-                folderElement.fileid);
- 
-            if (options && options.filterFile) {
-                file = options.filterFile(file);
-            }
-            if (file) {
-                files.push(file);
-            }
-        }
- 
-        return files;
-    }
- 
-    /**
-     * create a new file of overwrites an existing file
-     * @param fileName the file name /folder1/folder2/filename.txt
-     * @param data the buffer object
-     */
-    public async createFile(fileName: string, data: Buffer | NodeJS.ReadableStream): Promise<File> {
- 
-        if (fileName.startsWith("./")) {
-            fileName = fileName.replace("./", "/");
-        }
- 
-        const baseName: string = path.basename(fileName);
-        const folderName: string = path.dirname(fileName);
- 
-        debug("createFile folder name %s base name %s", folderName, baseName);
- 
-        // ensure that we have a folder
-        await this.createFolder(folderName);
-        await this.putFileContents(fileName, data);
- 
-        let file: File | null;
-        file = await this.getFile(fileName);
- 
-        if (!file) {
-            throw new ClientError(`Error creating file, file name "${fileName}"`, "ERR_CREATE_FILE_FAILED");
-        }
-        return file;
-    }
- 
-    /**
-     * returns a nextcloud file object
-     * @param fileName the full file name /folder1/folder2/file.pdf
-     */
-    public async getFile(fileName: string): Promise<File | null> {
-        debug("getFile fileName = %s", fileName);
- 
-        try {
-            const stat: IStat = await this.stat(fileName);
-            debug(": SUCCESS!!");
-            if (stat.type === "file") {
-                return new File(this,
-                    stat.filename.replace(/\\/g, "/"),
-                    stat.basename,
-                    stat.lastmod,
-                    stat.size!,
-                    stat.mime || "",
-                    stat.fileid || -1);
-            } else {
-                debug("getFile: found object is a folder not a file");
-                return null;
-            }
-        } catch (e) {
-            debug("getFile: exception occurred calling stat %O", e.message);
-            return null;
-        }
-    }
- 
-    /**
-     * renames the file or moves it to an other location
-     * @param sourceFileName source file name
-     * @param targetFileName target file name
-     */
-    public async moveFile(sourceFileName: string, targetFileName: string): Promise<File> {
- 
-        const url: string = this.webDAVUrl + sourceFileName;
-        const destinationUrl: string = this.webDAVUrl + targetFileName;
- 
-        debug("moveFile from '%s' to '%s'", url, destinationUrl);
- 
-        const requestInit: RequestInit = {
-            headers: new Headers({ Destination: destinationUrl }),
-            method: "MOVE",
-        };
-        try {
-            await this.getHttpResponse(
-                url,
-                requestInit,
-                [201],
-                { description: "File move" },
-            );
- 
-        } catch (err) {
-            debug("Error in move file %s %s source: %s destination: %s", err.message, requestInit.method, url, destinationUrl);
-            throw new ClientError("Error: moving file failed: source=" + sourceFileName + " target=" + targetFileName + " - " + err.message, "ERR_FILE_MOVE_FAILED");
-        }
- 
-        const targetFile: File | null = await this.getFile(targetFileName);
-        if (!targetFile) {
-            throw new ClientError("Error: moving file failed: source=" + sourceFileName + " target=" + targetFileName, "ERR_FILE_MOVE_FAILED");
-        }
- 
-        return targetFile;
-    }
- 
-    /**
-     * renames the folder or moves it to an other location
-     * @param sourceFolderName source folder name
-     * @param tarName target folder name
-     */
-    public async moveFolder(sourceFolderName: string, tarName: string): Promise<Folder> {
- 
-        const url: string = this.webDAVUrl + sourceFolderName;
-        const destinationUrl: string = this.webDAVUrl + tarName;
- 
-        debug("moveFolder from '%s' to '%s'", url, destinationUrl);
- 
-        const requestInit: RequestInit = {
-            headers: new Headers({ Destination: destinationUrl }),
-            method: "MOVE",
-        };
-        try {
-            await this.getHttpResponse(
-                url,
-                requestInit,
-                [201],
-                { description: "Folder move" },
-            );
- 
-        } catch (err) {
-            debug("Error in move folder %s %s source: %s destination: %s", err.message, requestInit.method, url, destinationUrl);
-            throw new ClientError("Error: moving folder failed: source=" + sourceFolderName + " target=" + tarName + " - " + err.message, "ERR_FOLDER_MOVE_FAILED");
-        }
- 
-        const tar: Folder | null = await this.getFolder(tarName);
-        if (!tar) {
-            throw new ClientError("Error: moving folder failed: source=" + sourceFolderName + " target=" + tarName, "ERR_FOLDER_MOVE_FAILED");
-        }
- 
-        return tar;
-    }
- 
-    /**
-     * returns the content of a file
-     * @param fileName name of the file /d1/file1.txt
-     * @returns Buffer with file content
-     */
-    public async getContent(fileName: string): Promise<Buffer> {
-        const url = this.webDAVUrl + fileName;
-        debug("getContent GET %s", url);
-        const requestInit: RequestInit = {
-            method: "GET",
-        };
-        let response: Response;
-        try {
-            response = await this.getHttpResponse(
-                url,
-                requestInit,
-                [200],
-                { description: "File get content" });
-        } catch (err) {
-            debug("Error getContent %s - error %s", url, err.message);
-            throw err;
-        }
- 
-        return Buffer.from(await response.buffer());
-    }
- 
-    /**
-     * returns the content of a file
-     * @param fileName name of the file /d1/file1.txt
-     * @returns Buffer with file content
-     */
-    public async pipeContentStream(fileName: string, destination: NodeJS.WritableStream): Promise<void> {
-        const url = this.webDAVUrl + fileName;
-        debug("getContent GET %s", url);
-        const requestInit: RequestInit = {
-            method: "GET",
-        };
-        let response: Response;
-        try {
-            response = await this.getHttpResponse(
-                url,
-                requestInit,
-                [200],
-                { description: "File pipe content stream" });
-        } catch (err) {
-            debug("Error getContent %s - error %s", url, err.message);
-            throw err;
-        }
-        response.body.pipe(destination);
-    }
- 
-    /**
-     * returns the link to a file for downloading
-     * @param fileName name of the file /folder1/folder1.txt
-     * @returns url
-     */
-    public getLink(fileName: string): string {
-        debug("getLink of %s", fileName);
-        return this.webDAVUrl + fileName;
-    }
- 
-    /**
-     * returns the url to the file in the nextcloud UI
-     * @param fileId the id of the file
-     */
-    public getUILink(fileId: number): string {
-        debug("getUILink of %s", fileId);
-        return `${this.nextcloudOrigin}/apps/files/?fileid=${fileId}`;
-    }
- 
-    /**
-     * adds a tag to a file or folder
-     * if the tag does not exist, it is automatically created
-     * if the tag is created, the user must have damin privileges
-     * @param fileId the id of the file
-     * @param tagName the name of the tag
-     * @returns nothing
-     * @throws Error
-     */
-    public async addTagToFile(fileId: number, tagName: string): Promise<void> {
-        debug("addTagToFile file:%s tag:%s", fileId, tagName);
-        const tag: Tag = await this.createTag(tagName);
- 
-        if (!tag.canAssign) {
-            throw new ClientError(`Error: No permission to assign tag "${tagName}" to file. Tag is not assignable`, "ERR_TAG_NOT_ASSIGNABLE");
-        }
- 
-        const addTagBody: any = {
-            canAssign: tag.canAssign,
-            id: tag.id,
-            name: tag.name,
-            userAssignable: tag.assignable,
-            userVisible: tag.visible,
-        };
- 
-        const requestInit: RequestInit = {
-            body: JSON.stringify(addTagBody, null, 4),
-            headers: new Headers({ "Content-Type": "application/json" }),
-            method: "PUT",
-        };
- 
-        await this.getHttpResponse(
-            `${this.nextcloudOrigin}/remote.php/dav/systemtags-relations/files/${fileId}/${tag.id}`,
-            requestInit,
-            [201, 409],
-            { description: "File add tag" }); // created or conflict
-    }
- 
-    // ***************************************************************************************
-    // activity
-    // ***************************************************************************************
-    /*
-    @todo to be refactored to eventing
- 
-    public async getActivities(): Promise<string[]> {
-        const result: string[] = [];
-        const requestInit: RequestInit = {
-            headers: new Headers({ "ocs-apirequest": "true" }),
-            method: "GET",
-        };
- 
-        const response: Response = await this.getHttpResponse(
-            this.nextcloudOrigin + "/ocs/v2.php/apps/activity/api/v2/activity/files?format=json&previews=false&since=97533",
-            requestInit,
-            [200],
-            { description: "Activities get" });
- 
-        const responseObject: any = await response.json();
-        // @todo
- 
-        for (const res of responseObject.ocs.data) {
-            debug(JSON.stringify({
-                acivityId: res.activity_id,
-                objects: res.objects,
-                type: res.type,
-            }, null, 4));
-        }
- 
-        // debug("getActivities: responseObject %s", JSON.stringify(responseObject, null, 4));
- 
-        return result;
-    }
-*/
-    // ***************************************************************************************
-    // comments
-    // ***************************************************************************************
- 
-    /**
-     * adds a comment to a file
-     * @param fileId the id of the file
-     * @param comment the comment to be added to the file
-     */
-    public async addCommentToFile(fileId: number, comment: string): Promise<void> {
-        debug("addCommentToFile file:%s comment:%s", fileId, comment);
- 
-        const addCommentBody: any = {
-            actorType: "users",
-            message: comment,
-            objectType: "files",
-            verb: "comment",
-        };
- 
-        const requestInit: RequestInit = {
-            body: JSON.stringify(addCommentBody, null, 4),
-            headers: new Headers({ "Content-Type": "application/json" }),
-            method: "POST",
-        };
- 
-        await this.getHttpResponse(
-            `${this.nextcloudOrigin}/remote.php/dav/comments/files/${fileId}`,
-            requestInit,
-            [201],
-            { description: "File add comment" }); // created
-    }
- 
-    /**
-     * returns comments of a file / folder
-     * @param fileId the id of the file / folder
-     * @param top number of comments to return
-     * @param skip the offset
-     * @returns array of comment strings
-     * @throws Exception
-     */
-    public async getFileComments(fileId: number, top?: number, skip?: number): Promise<string[]> {
-        debug("getFileComments fileId:%s", fileId);
-        if (!top) {
-            top = 30;
-        }
- 
-        if (!skip) {
-            skip = 0;
-        }
- 
-        const requestInit: RequestInit = {
-            body: `<?xml version="1.0" encoding="utf-8" ?>
-                    <oc:filter-comments xmlns:D="DAV:" xmlns:oc="http://owncloud.org/ns">
-                        <oc:limit>${top}</oc:limit>
-                        <oc:offset>${skip}</oc:offset>
-                    </oc:filter-comments>`,
-            method: "REPORT",
-        };
- 
-        const response: Response = await this.getHttpResponse(
-            `${this.nextcloudOrigin}/remote.php/dav/comments/files/${fileId}`,
-            requestInit,
-            [207],
-            { description: "File get comments" });
- 
-        const properties: any[] = await this.getPropertiesFromWebDAVMultistatusResponse(response, "");
-        const comments: string[] = [];
-        for (const prop of properties) {
-            comments.push(prop.message);
-        }
- 
-        return comments;
-    }
- 
-    /**
-     * returns system information about the nextcloud server and the nextcloud client
-     */
-    public async getSystemInfo(): Promise<ISystemInfo> {
-        const requestInit: RequestInit = {
-            headers: this.getOcsHeaders(),
-            method: "GET",
-        };
- 
-        const response: Response = await this.getHttpResponse(
-            this.nextcloudOrigin + "/ocs/v2.php/apps/serverinfo/api/v1/info",
-            requestInit,
-            [200],
-            { description: "SystemInfo get" });
- 
-        const rawResult: any = await response.json();
-        // validate the raw result
-        let system = {};
-        let storage = {};
-        let shares = {};
-        let server = {};
-        let activeUsers = {};
- 
-        if (rawResult && rawResult.ocs && rawResult.ocs.data) {
-            if (rawResult.ocs.data.nextcloud) {
-                if (rawResult.ocs.data.nextcloud.system) {
-                    system = rawResult.ocs.data.nextcloud.system;
-                } else {
-                    throw new ClientError("Fatal Error: nextcloud data.nextcloud.system missing", "ERR_SYSTEM_INFO_MISSING_DATA");
-                }
- 
-                if (rawResult.ocs.data.nextcloud.storage) {
-                    storage = rawResult.ocs.data.nextcloud.storage;
-                } else {
-                    throw new ClientError("Fatal Error: nextcloud data.nextcloud.storage missing", "ERR_SYSTEM_INFO_MISSING_DATA");
-                }
- 
-                if (rawResult.ocs.data.nextcloud.shares) {
-                    shares = rawResult.ocs.data.nextcloud.shares;
-                } else {
-                    throw new ClientError("Fatal Error: nextcloud data.nextcloud.shares missing", "ERR_SYSTEM_INFO_MISSING_DATA");
-                }
-            } else {
-                throw new ClientError("Fatal Error: nextcloud data.nextcloud missing", "ERR_SYSTEM_INFO_MISSING_DATA");
-            }
- 
-            if (rawResult.ocs.data.server) {
-                server = rawResult.ocs.data.server;
-            } else {
-                throw new ClientError("Fatal Error: nextcloud data.server missing", "ERR_SYSTEM_INFO_MISSING_DATA");
-            }
- 
-            if (rawResult.ocs.data.activeUsers) {
-                activeUsers = rawResult.ocs.data.activeUsers;
-            } else {
-                throw new ClientError("Fatal Error: nextcloud data.activeUsers missing", "ERR_SYSTEM_INFO_MISSING_DATA");
-            }
- 
-        } else {
-            throw new ClientError("Fatal Error: nextcloud system data missing", "ERR_SYSTEM_INFO_MISSING_DATA");
-        }
- 
-        const result: ISystemInfo = {
-            activeUsers,
-            nextcloud:
-            {
-                shares,
-                storage,
-                system,
-            },
-            nextcloudClient:
-            {
-                version: require("../package.json").version,
-            },
-            server,
-        };
-        return result;
-    }
- 
-    public async getSystemBasicData(): Promise<ISysBasicData> {
-        const requestInit: RequestInit = {
-            headers: this.getOcsHeaders(),
-            method: "GET",
-        };
- 
-        const response: Response = await this.getHttpResponse(
-            this.nextcloudOrigin + "/ocs/v2.php/apps/serverinfo/api/v1/basicdata",
-            requestInit,
-            [200],
-            { description: "System Basic Data get" });
- 
-        const rawResult: any = await response.json();
-        // console.log("Basic Data\n", JSON.stringify(rawResult));
-        let result: ISysBasicData;
- 
-        if (rawResult &&
-            rawResult.ocs &&
-            rawResult.ocs.data &&
-            rawResult.ocs.data.servertime &&
-            rawResult.ocs.data.uptime &&
-            rawResult.ocs.data.timeservers) {
-            result = {
-                serverTimeString: rawResult.ocs.data.servertime.replace("\n", ""),
-                uptimeString: rawResult.ocs.data.uptime.replace("\n", ""),
-                timeServersString: rawResult.ocs.data.timeservers.trim(),
-            }
-        } else {
-            throw new ClientError("Fatal Error: nextcloud basic data missing", "ERR_SYSTEM_INFO_MISSING_DATA");
-        }
- 
-        return result;
-    }
- 
-    // ***************************************************************************************
-    // user management
-    // ***************************************************************************************
- 
-    // ***************************************************************************************
-    // user group
-    // spec: https://docs.nextcloud.com/server/latest/admin_manual/configuration_user/instruction_set_for_groups.html
-    // ***************************************************************************************
- 
-    /**
-     * returns a list of user groups
-     * @param search string
-     * @param limit number
-     * @param offset number
-     * @returns list of user groups
-     * @throws QueryLimitError
-     * @throws QueryOffsetError
-     */
-    public async getUserGroups(search?: string, limit?: number, offset?: number): Promise<UserGroup[]> {
-        debug("getUserGroups");
- 
-        const userGroupIds: string[] = await this.getUserGroupIds(search, limit, offset);
-        const userGroups: UserGroup[] = [];
-        for (const userGroupId of userGroupIds) {
-            userGroups.push(new UserGroup(this, userGroupId));
-        }
-        return userGroups;
-    }
- 
-    /**
-     * returns a list of user groups
-     * @param search string
-     * @param limit number
-     * @param offset number
-     * @returns list of user groups
-     * @throws QueryLimitError
-     * @throws QueryOffsetError
-     */
-    public async getUserGroupIds(search?: string, limit?: number, offset?: number): Promise<string[]> {
-        debug("getUserGroupIds");
-        const requestInit: RequestInit = {
-            headers: this.getOcsHeaders(),
-            method: "GET",
-        };
- 
-        let url = this.getOcsUrl(`/groups`);
-        const queryParameter: string[] = [];
-        if (search) {
-            queryParameter.push(`search=${search}`);
-        }
-        if (limit) {
-            if (limit < 1) {
-                throw new QueryLimitError("The limit must be larger than 0");
-            }
-            queryParameter.push(`limit=${limit}`);
-        }
-        if (offset) {
-            if (offset < 1) {
-                throw new QueryOffsetError("The offset must be larger than 0");
-            }
-            queryParameter.push(`offset=${offset}`);
-        }
-        if (queryParameter.join("&").length > 1) {
-            url += "?" + queryParameter.join("&");
-        }
-        debug("url ", url)
- 
-        const response: Response = await this.getHttpResponse(
-            url,
-            requestInit,
-            [200],
-            { description: "User Groups get" });
-        const rawResult: any = await response.json();
-        /*
-        {
-          ocs: {
-            meta: {
-              status: 'ok',
-              statuscode: 100,
-              message: 'OK',
-              totalitems: '',
-              itemsperpage: ''
-            },
-            data: { groups: ["g1", "g2"] }
-          }
-        }
-        */
-        const userGroups: string[] = [];
- 
-        if (rawResult.ocs &&
-            rawResult.ocs.data &&
-            rawResult.ocs.data.groups) {
-            debug("groups", rawResult.ocs.data.groups);
-            rawResult.ocs.data.groups.forEach((value: string) => {
-                // userGroups.push(new UserGroup(this, value));
-                userGroups.push(value);
-            });
-        }
-        return userGroups;
-    }
- 
-    /**
-     * get user group
-     * @param id string
-     * @returns Promise<UserGroup|null>
-     */
-    public async getUserGroup(id: string): Promise<UserGroup | null> {
-        const userGroups: UserGroup[] = await this.getUserGroups(id);
-        if (userGroups[0]) {
-            return userGroups[0];
-        }
-        return null
-    }
- 
-    /**
-     * returns a list of user ids that are members of the user group
-     * @param id string
-     * @returns list of member user ids
-     * @throws [UserGroupDoesNotExistError}
-     */
-    public async getUserGroupMembers(id: string): Promise<string[]> {
-        debug("getUserGroupMembers");
-        const requestInit: RequestInit = {
-            headers: this.getOcsHeaders(),
-            method: "GET",
-        };
- 
-        const url = this.getOcsUrl(`/groups/${id}`);
-        debug("url ", url)
- 
-        const response: Response = await this.getHttpResponse(
-            url,
-            requestInit,
-            [200],
-            { description: "User group get members" });
-        const rawResult: any = await response.json();
-        const userIds: string[] = [];
- 
-        if (this.getOcsMetaStatus(rawResult).code === 404) {
-            throw new UserGroupDoesNotExistError(`User Group ${id} does not exist`);
-        }
- 
-        if (rawResult.ocs &&
-            rawResult.ocs.data &&
-            rawResult.ocs.data.users) {
-            debug("members", rawResult.ocs.data.users);
-            rawResult.ocs.data.users.forEach((value: string) => {
-                userIds.push(value);
-            });
-        }
- 
-        return userIds;
-    }
- 
-    /**
-     * returns a list of user ids that are subadmins of the user group
-     * @param id string
-     * @returns list of subadmin user ids
-     * @throws [UserGroupDoesNotExistError}
-     */
-    public async getUserGroupSubadmins(id: string): Promise<string[]> {
-        debug("getUserGroupsubadmins");
-        const requestInit: RequestInit = {
-            headers: this.getOcsHeaders(),
-            method: "GET",
-        };
- 
-        const url = this.getOcsUrl(`/groups/${id}/subadmins`);
-        debug("url ", url)
- 
-        const response: Response = await this.getHttpResponse(
-            url,
-            requestInit,
-            [200],
-            { description: "User group get subadmins" });
-        const rawResult: any = await response.json();
-        const userIds: string[] = [];
- 
-        if (this.getOcsMetaStatus(rawResult).code === 101) {
-            throw new UserGroupDoesNotExistError(`User Group ${id} does not exist`);
-        }
- 
-        if (rawResult.ocs &&
-            rawResult.ocs.data) {
-            debug("subadmins", rawResult.ocs.data);
-            rawResult.ocs.data.forEach((value: string) => {
-                userIds.push(value);
-            });
-        }
- 
-        return userIds;
-    }
- 
-    /**
-     * create a new user group
-     * @async
-     * @param {string} id user group id
-     * @returns {Promise<UserGroup>}
-     * @throws {UserGroupAlreadyExistsError}
-     */
-    public async createUserGroup(id: string): Promise<UserGroup> {
-        debug("createUserGroup id=", id);
-        const requestInit: RequestInit = {
-            body: JSON.stringify({ groupid: id }),
-            headers: this.getOcsHeaders(),
-            method: "POST",
-        };
-        debug("request body: ", requestInit.body);
-        const response: Response = await this.getHttpResponse(
-            this.getOcsUrl(`/groups`),
-            requestInit,
-            [200],
-            { description: "UserGroup create" });
-        const rawResult: any = await response.json();
- 
-        if (this.getOcsMetaStatus(rawResult).code === 102) {
-            throw new UserGroupAlreadyExistsError(`User Group ${id} already exists`);
-        }
- 
-        if (this.getOcsMetaStatus(rawResult).code === 100) {
-            return new UserGroup(this, id);
-        }
-        throw new OperationFailedError(`User group ${id} could not be created: ${this.getOcsMetaStatus(rawResult).message}`);
-    }
- 
-    /**
-     * deletes an existing user group
-     * @param id string
-     * @returns {Promise<void>}
-     * @throws {UserGroupDowsNotExistError}
-     * @throws {UserGroupDeletionFailedError}
-     */
-    public async deleteUserGroup(id: string): Promise<void> {
-        debug("deleteUserGroup id=", id);
-        const requestInit: RequestInit = {
-            headers: this.getOcsHeaders(),
-            method: "DELETE",
-        };
-        debug("request body: ", requestInit.body);
-        const response: Response = await this.getHttpResponse(
-            this.getOcsUrl(`/groups/${id}`),
-            requestInit,
-            [200],
-            { description: "UserGroup delete" });
-        const rawResult: any = await response.json();
- 
-        if (this.getOcsMetaStatus(rawResult).code === 101) {
-            throw new UserGroupDoesNotExistError(`User Group ${id} does not exists`);
-        }
- 
-        if (this.getOcsMetaStatus(rawResult).code === 102) {
-            throw new UserGroupDeletionFailedError(`User Group ${id} could not be deleted`);
-        }
-    }
- 
-    // ***************************************************************************************
-    // user
-    // spec: https://docs.nextcloud.com/server/latest/admin_manual/configuration_user/instruction_set_for_users.html
-    // ***************************************************************************************
- 
-    /**
-     * returns a list of users
-     * https://docs.nextcloud.com/server/latest/admin_manual/configuration_user/instruction_set_for_users.html#search-get-users
-     * @param search string
-     * @param limit number
-     * @param offset number
-     */
-    public async getUsers(search?: string, limit?: number, offset?: number): Promise<User[]> {
-        debug("getUsers");
-        const requestInit: RequestInit = {
-            headers: this.getOcsHeaders(),
-            method: "GET",
-        };
- 
-        let url = this.getOcsUrl(`/users`);
-        const queryParameter: string[] = [];
-        if (search) {
-            queryParameter.push(`search=${search}`);
-        }
-        if (limit) {
-            if (limit < 1) {
-                throw new QueryLimitError("The limit must be larger than 0");
-            }
-            queryParameter.push(`limit=${limit}`);
-        }
-        if (offset) {
-            if (offset < 1) {
-                throw new QueryOffsetError("The offset must be larger than 0");
-            }
-            queryParameter.push(`offset=${offset}`);
-        }
-        if (queryParameter.join("&").length > 1) {
-            url += "?" + queryParameter.join("&");
-        }
-        debug("url ", url)
- 
-        const response: Response = await this.getHttpResponse(
-            url,
-            requestInit,
-            [200],
-            { description: "Users get" });
-        const rawResult: any = await response.json();
-        /*
-        {
-          ocs: {
-            meta: {
-              status: 'ok',
-              statuscode: 100,
-              message: 'OK',
-              totalitems: '',
-              itemsperpage: ''
-            },
-            data: { users: ["u1", "u2"] }
-          }
-        }
-        */
-        const users: User[] = [];
- 
-        if (rawResult.ocs &&
-            rawResult.ocs.data &&
-            rawResult.ocs.data.users) {
-            debug("user ids", rawResult.ocs.data.users);
-            rawResult.ocs.data.users.forEach((value: string) => {
-                users.push(new User(this, value));
-            });
-        }
- 
-        return users;
-    }
- 
-    /**
-     * returns user data
-     * @param id string the user id
-     * @returns Promise<IUserOptions> user data
-     * @throws {UserNotFoundError}
-     */
-    public async getUserData(id: string): Promise<IUserOptions> {
-        debug("getUserData");
-        const requestInit: RequestInit = {
-            headers: this.getOcsHeaders(),
-            method: "GET",
-        };
- 
-        const url = this.getOcsUrl(`/users/${id}`);
-        debug("url ", url)
- 
-        const response: Response = await this.getHttpResponse(
-            url,
-            requestInit,
-            [200],
-            { description: `User ${id} get` });
-        const rawResult: any = await response.json();
- 
-        if (this.getOcsMetaStatus(rawResult).code === 404) {
-            throw new UserNotFoundError(`User '${id}' not found`);
-        }
-        /*
-        {
-          ocs: {
-            meta: {
-              status: 'ok',
-              statuscode: 100,
-              message: 'OK',
-              totalitems: '',
-              itemsperpage: ''
-            },
-            data: { ... }
-          }
-        }
-        */
- 
-        let userData: IUserOptions;
-        debug("user data", rawResult.ocs.data);
-        userData = {
-            enabled: rawResult.ocs.data.enabled,
-            lastLogin: rawResult.ocs.data.lastLogin === 0 ? undefined : new Date(rawResult.ocs.data.lastLogin),
-            subadminGroups: rawResult.ocs.data.subadmin,
-            memberGroups: rawResult.ocs.data.groups,
-            quota: {
-                free: 0,
-                used: 0,
-                total: 0,
-                relative: 0,
-                quota: 0
-            },
-            email: rawResult.ocs.data.email,
-            displayName: rawResult.ocs.data.displayname,
-            phone: rawResult.ocs.data.phone,
-            address: rawResult.ocs.data.address,
-            website: rawResult.ocs.data.website,
-            twitter: rawResult.ocs.data.twitter,
-            language: rawResult.ocs.data.language,
-            locale: rawResult.ocs.data.locale,
-        };
-        if (rawResult.ocs.data.quota.quota === 'none') {
-            userData.quota = { quota: 0, relative: 0, used: 0 };
-        } else {
-            if (!rawResult.ocs.data.quota.relative) {
-                rawResult.ocs.data.quota.relative = 0;
-            }
-            userData.quota = { quota: rawResult.ocs.data.quota.quota, relative: rawResult.ocs.data.quota.relative, used: rawResult.ocs.data.quota.used };
-            if (rawResult.ocs.data.quota.free) {
-                userData.quota.free = rawResult.ocs.data.quota.free;
-            }
-            if (rawResult.ocs.data.quota.total) {
-                userData.quota.total = rawResult.ocs.data.quota.total;
-            }
-        }
-        return userData;
-    }
- 
-    /**
-     * enables the user
-     * @param id string the user id
-     * @returns {Promise<void>}
-     * @throws {UserNotFoundError}
-     */
-    public async enableUser(id: string): Promise<void> {
-        debug("enableUser");
-        const requestInit: RequestInit = {
-            headers: this.getOcsHeaders(),
-            method: "PUT",
-        };
- 
-        const url = this.getOcsUrl(`/users/${id}/enable`);
-        debug("url ", url)
- 
-        const response: Response = await this.getHttpResponse(
-            url,
-            requestInit,
-            [200],
-            { description: `User ${id} enable` });
-        const rawResult: any = await response.json();
- 
-        if (this.getOcsMetaStatus(rawResult).code === 100) {
-            return
-        }
-        throw new UserNotFoundError(`User '${id}' not found`);
-    }
- 
-    /**
-     * disables the user
-     * @param id string the user id
-     * @returns {Promise<void>}
-     * @throws {UserNotFoundError}
-     */
-    public async disableUser(id: string): Promise<void> {
-        debug("disableUser");
-        const requestInit: RequestInit = {
-            headers: this.getOcsHeaders(),
-            method: "PUT",
-        };
- 
-        const url = this.getOcsUrl(`/users/${id}/disable`);
-        debug("url ", url)
- 
-        const response: Response = await this.getHttpResponse(
-            url,
-            requestInit,
-            [200],
-            { description: `User ${id} disable` });
-        const rawResult: any = await response.json();
- 
-        if (this.getOcsMetaStatus(rawResult).code === 100) {
-            return
-        }
-        throw new UserNotFoundError(`User '${id}' not found`);
-    }
- 
-    /**
-     * deletes the user
-     * @param id string the user id
-     * @returns {Promise<void>}
-     * @throws {UserNotFoundError}
-     */
-    public async deleteUser(id: string): Promise<void> {
-        debug("deleteUser");
-        const requestInit: RequestInit = {
-            headers: this.getOcsHeaders(),
-            method: "DELETE",
-        };
- 
-        const url = this.getOcsUrl(`/users/${id}`);
-        debug("url ", url)
- 
-        const response: Response = await this.getHttpResponse(
-            url,
-            requestInit,
-            [200],
-            { description: `User ${id} delete` });
-        const rawResult: any = await response.json();
- 
-        if (this.getOcsMetaStatus(rawResult).code === 100) {
-            return
-        }
-        throw new UserNotFoundError(`User '${id}' not found`);
-    }
- 
-    /**
-     * returns a user or null if not found
-     * @param id string
-     * @returns User | null
-     */
-    public async getUser(id: string): Promise<User | null> {
-        debug("getUser");
-        const users: User[] = await this.getUsers(id);
-        if (users[0]) {
-            return users[0];
-        }
-        return null;
-    }
- 
-    /**
-     * creates a new user with email or password
-     * @param options
-     * @returns User
-     * @throws UserAlreadyExistsError
-     * @throws {UserNotFoundError}
-     * @throws UserUpdateError
-     */
-    public async createUser(options: { id: string, email?: string, password?: string }): Promise<User> {
-        debug("createUser");
-        const createUserBody: { userid: string, password?: string, email?: string } = { userid: options.id };
-        if (options.email) {
-            if (/^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(options.email)) {
-                createUserBody.email = options.email;
-            } else {
-                throw new UserCreateError(`Error creating user '${options.id}' - invalid email address '${options.email}'`);
-            }
-        }
-        if (options.password) {
-            createUserBody.password = options.password;
-        }
- 
-        const requestInit: RequestInit = {
-            body: JSON.stringify(createUserBody, null, 4),
-            headers: this.getOcsHeaders(),
-            method: "POST",
-        };
-        debug("request body: ", requestInit.body);
-        const response: Response = await this.getHttpResponse(
-            this.getOcsUrl(`/users`),
-            requestInit,
-            [200],
-            { description: `User ${options.id} create` });
-        const rawResult: any = await response.json();
- 
-        if (this.getOcsMetaStatus(rawResult).code === 102) {
-            throw new UserAlreadyExistsError(`User with id '${options.id}' already exists`);
-        }
- 
-        const user: User | null = await this.getUser(options.id);
-        if (user) {
-            return user;
-        }
- 
-        throw new UserCreateError(`Error creating user '${options.id}' - ${this.getOcsMetaStatus(rawResult).message} (${this.getOcsMetaStatus(rawResult).code})`);
-    }
- 
-    /**
-     * updates a user property
-     * @async
-     * @param {string} id user id
-     * @param {UserProperty} property property name
-     * @param {string} value property value
-     * @returns {Promise<void>}
-     * @throws  {UserNotFoundError}
-     * @throws  {UserUpdateError}
-     */
-    public async updateUserProperty(id: string, property: UserProperty, value: string): Promise<void> {
-        debug("updateUserProperty");
-        const body: { key: string, value: string } = { key: property, value };
- 
-        const requestInit: RequestInit = {
-            body: JSON.stringify(body, null, 4),
-            headers: this.getOcsHeaders(),
-            method: "PUT",
-        };
-        const url = this.getOcsUrl(`/users/${id}`);
-        debug("request body: ", requestInit.body);
-        const response: Response = await this.getHttpResponse(
-            url,
-            requestInit,
-            [200, 401],
-            { description: `User ${id} update ${property}=${value}` });
-        const rawResult: any = await response.json();
- 
-        // This service operation returns a 401, if the user does not exist - very strange...
-        // spec says to return 200 and status code 101
-        /*
-        if (this.getOcsMetaStatus(rawResult).code === 101) {
-            throw new UserNotFoundError(`User with id '${id}' not found`);
-        }
-        */
-        // maybe this is due to a nextcloud api error
-        // it is not possible to distiguish beteen authentication error and user not found :-(
-        if (response.status === 401) {
-            throw new UserNotFoundError(`User with id '${id}' not found`);
-        }
- 
-        if (this.getOcsMetaStatus(rawResult).code === 100) {
-            return;
-        }
- 
-        if (property === UserProperty.password) {
-            value = "********";
-        }
-        // code 102 or 103
-        throw new UserUpdateError(`User with id '${id}' could not be updated - ${property}=${value}. ${rawResult.ocs.meta.message}`);
-    }
- 
-    /**
-     * resend the welcome email
-     * @param id user id
-     * @throws  {UserResendWelcomeEmailError}
-     */
-    public async resendWelcomeEmail(id: string,): Promise<void> {
-        debug("resendWelcomeEmail");
- 
-        const requestInit: RequestInit = {
-            headers: this.getOcsHeaders(),
-            method: "POST",
-        };
-        const url = this.getOcsUrl(`/users/${id}/welcome`);
-        debug("request body: ", requestInit.body);
-        const response: Response = await this.getHttpResponse(
-            url,
-            requestInit,
-            [200],
-            { description: `Resend welcome email for user ${id}` });
-        const rawResult: any = await response.json();
- 
-        if (this.getOcsMetaStatus(rawResult).code === 101) {
-            throw new UserResendWelcomeEmailError(`Error sending welcome email for '${id}': Email address not available`);
-        }
- 
-        if (this.getOcsMetaStatus(rawResult).code === 100) {
-            return;
-        }
-        throw new UserResendWelcomeEmailError(`Error sending welcome email for '${id}' failed`);
-    }
- 
-    /**
-     * adds a user to a group as member
-     * @param id string the user id
-     * @param userGroupId string the user group id
-     * @returns {Promise<void>}
-     * @throws {UserNotFoundError}
-     * @throws {UserGroupDoesNotExistError}
-     * @throws {InsufficientPrivilegesError}
-     * @throws {OperationFailedError}
-     */
-    public async addUserToMemberUserGroup(id: string, userGroupId: string): Promise<void> {
-        debug("addUserToUserGroup");
- 
-        const body: { groupid: string } = { groupid: userGroupId };
-        const requestInit: RequestInit = {
-            body: JSON.stringify(body, null, 4),
-            headers: this.getOcsHeaders(),
-            method: "POST",
-        };
- 
-        const url = this.getOcsUrl(`/users/${id}/groups`);
-        debug("url ", url)
- 
-        const response: Response = await this.getHttpResponse(
-            url,
-            requestInit,
-            [200],
-            { description: `Add user ${id} to user group ${userGroupId}` });
-        const rawResult: any = await response.json();
- 
-        if (this.getOcsMetaStatus(rawResult).code === 100) {
-            return
-        }
- 
-        if (this.getOcsMetaStatus(rawResult).code === 102) {
-            throw new UserGroupDoesNotExistError(`User group ${userGroupId} does not exist`)
-        }
- 
-        if (this.getOcsMetaStatus(rawResult).code === 103) {
-            throw new UserNotFoundError(`User ${id} does not exist`)
-        }
- 
-        if (this.getOcsMetaStatus(rawResult).code === 104) {
-            throw new InsufficientPrivilegesError(`Insufficient privileges to add a user to a group`);
-        }
- 
-        throw new OperationFailedError(`User ${id} could not be added to user group ${userGroupId}: ${this.getOcsMetaStatus(rawResult).message}`);
-    }
- 
-    /**
-     * removes a user from a group as member
-     * @param id string the user id
-     * @param userGroupId string the user group id
-     * @returns {Promise<void>}
-     * @throws {UserNotFoundError}
-     * @throws {UserGroupDoesNotExistError}
-     * @throws {InsufficientPrivilegesError}
-     * @throws {OperationFailedError}
-     */
-    public async removeUserFromMemberUserGroup(id: string, userGroupId: string): Promise<void> {
-        debug("removeUserFromMemberUserGroup");
- 
-        const body: { groupid: string } = { groupid: userGroupId };
-        const requestInit: RequestInit = {
-            body: JSON.stringify(body, null, 4),
-            headers: this.getOcsHeaders(),
-            method: "DELETE",
-        };
- 
-        const url = this.getOcsUrl(`/users/${id}/groups`);
-        debug("url ", url)
- 
-        const response: Response = await this.getHttpResponse(
-            url,
-            requestInit,
-            [200],
-            { description: `Remove user ${id} from user group ${userGroupId}` });
-        const rawResult: any = await response.json();
- 
-        if (this.getOcsMetaStatus(rawResult).code === 100) {
-            return
-        }
- 
-        if (this.getOcsMetaStatus(rawResult).code === 102) {
-            throw new UserGroupDoesNotExistError(`User group ${userGroupId} does not exist`)
-        }
- 
-        if (this.getOcsMetaStatus(rawResult).code === 103) {
-            throw new UserNotFoundError(`User ${id} does not exist`)
-        }
- 
-        if (this.getOcsMetaStatus(rawResult).code === 104) {
-            throw new InsufficientPrivilegesError(`Insufficient privileges to add a user to a group`);
-        }
- 
-        throw new OperationFailedError(`User ${id} could not be added to user group ${userGroupId}: ${this.getOcsMetaStatus(rawResult).message}`);
-    }
- 
-    /**
-     * promotes a user to a user group subadmin
-     * @param id string the user id
-     * @param userGroupId string the user group id
-     * @returns {Promise<void>}
-     * @throws {UserNotFoundError}
-     * @throws {UserGroupDoesNotExistError}
-     * @throws {InsufficientPrivilegesError}
-     * @throws {OperationFailedError}
-     */
-    public async promoteUserToUserGroupSubadmin(id: string, userGroupId: string): Promise<void> {
-        debug("promoteUserToUserGroupSubadmin");
- 
-        const body: { groupid: string } = { groupid: userGroupId };
-        const requestInit: RequestInit = {
-            body: JSON.stringify(body, null, 4),
-            headers: this.getOcsHeaders(),
-            method: "POST",
-        };
- 
-        const url = this.getOcsUrl(`/users/${id}/subadmins`);
-        debug("url ", url)
- 
-        const response: Response = await this.getHttpResponse(
-            url,
-            requestInit,
-            [200],
-            { description: `Promote User ${id} to user group subadmin ${userGroupId}` });
-        const rawResult: any = await response.json();
- 
-        if (this.getOcsMetaStatus(rawResult).code === 100) {
-            return
-        }
- 
-        if (this.getOcsMetaStatus(rawResult).code === 102) {
-            throw new UserGroupDoesNotExistError(`User group ${userGroupId} does not exist`)
-        }
- 
-        if (this.getOcsMetaStatus(rawResult).code === 101) {
-            throw new UserNotFoundError(`User ${id} does not exist`)
-        }
- 
-        if (this.getOcsMetaStatus(rawResult).code === 104) {
-            throw new InsufficientPrivilegesError(`Insufficient privileges to add a user to a group`);
-        }
- 
-        throw new OperationFailedError(`User ${id} could not be removed from user group ${userGroupId}: ${this.getOcsMetaStatus(rawResult).message}`);
-    }
- 
-    /**
-     * Removes the subadmin rights for the user specified from the group specified
-     * @param id string the user id
-     * @param userGroupId string the user group id
-     * @returns {Promise<void>}
-     * @throws {InsufficientPrivilegesError}
-     * @throws {OperationFailedError}
-     */
-    public async demoteUserFromSubadminUserGroup(id: string, userGroupId: string): Promise<void> {
-        debug("demoteUserFromSubadminUserGroup");
- 
-        const body: { groupid: string } = { groupid: userGroupId };
-        const requestInit: RequestInit = {
-            body: JSON.stringify(body, null, 4),
-            headers: this.getOcsHeaders(),
-            method: "DELETE",
-        };
- 
-        const url = this.getOcsUrl(`/users/${id}/subadmins`);
-        debug("url ", url)
- 
-        const response: Response = await this.getHttpResponse(
-            url,
-            requestInit,
-            [200],
-            { description: `Demotes user ${id} from subadmin user group ${userGroupId}` });
-        const rawResult: any = await response.json();
- 
-        if (this.getOcsMetaStatus(rawResult).code === 100) {
-            return
-        }
- 
-        // this API does not work like remove from group :-(
-        // 101 is for user group not found and user not found
-        /*
-            if (this.getOcsMetaStatus(rawResult).code === 101) {
-                throw new UserGroupDoesNotExistError(`User group ${userGroupId} does not exist`)
-            }
- 
-            if (this.getOcsMetaStatus(rawResult).code === 101) {
-                throw new UserNotFoundError(`User ${id} does not exist`)
-            }
-        */
-        if (this.getOcsMetaStatus(rawResult).code === 104) {
-            throw new InsufficientPrivilegesError(`Insufficient privileges to add a user to a group`);
-        }
- 
-        throw new OperationFailedError(`User ${id} could not be demoted from subadmin user group ${userGroupId}: ${this.getOcsMetaStatus(rawResult).message}`);
-    }
- 
- 
-    /**
-     * insert or update complete user data
-     * @param options IUpsertUserOptions[]
-     * @returns Promise<IUpsertUserReport[]
-     */
-    public async upsertUsers(options: IUpsertUserOptions[]): Promise<IUpsertUserReport[]> {
-        const report: IUpsertUserReport[] = [];
-        for (const option of options) {
-            const userReport: IUpsertUserReport = { id: option.id, message: "", changes: [] };
-            let user: User | null = await this.getUser(option.id);
-            // create or update user?
- 
-            if (!user) {
-                try {
-                    user = await this.createUser({ id: option.id, email: option.email, password: option.password })
-                    userReport.message = `User ${option.id} created`;
-                } catch (e) {
-                    userReport.message = `Create user ${option.id} failed ${e.message}`;
-                    report.push(userReport);
-                    continue;
-                }
-            } else {
-                userReport.message = `User ${option.id} changed`;
-            }
- 
-            let previousValue: string = "";
-            let newValue: string = "";
-            let property: string = "";
- 
-            // ************************
-            // enabled
-            // ************************
-            if (option.enabled !== undefined) {
-                if (await user.isEnabled() && option.enabled === false) {
-                    try {
-                        await user.disable();
-                        userReport.changes.push({ property: "enabled", previousValue: "true", newValue: "false" });
-                    } catch (e) {
-                        userReport.changes.push({ property: "enabled", previousValue: "true", newValue: "true", error: e.message });
-                    }
-                }
- 
-                if (await user.isEnabled() === false && option.enabled === true) {
-                    try {
-                        await user.enable();
-                        userReport.changes.push({ property: "enabled", previousValue: "false", newValue: "true" });
-                    } catch (e) {
-                        userReport.changes.push({ property: "enabled", previousValue: "false", newValue: "false", error: e.message });
-                    }
-                }
-            }
- 
-            // ************************
-            // super admin
-            // ************************
-            if (option.superAdmin !== undefined) {
-                if (await user.isSuperAdmin() && option.superAdmin === false) {
-                    try {
-                        await user.demoteFromSuperAdmin();
-                        userReport.changes.push({ property: "superAdmin", previousValue: "true", newValue: "false" });
-                    } catch (e) {
-                        userReport.changes.push({ property: "superAdmin", previousValue: "true", newValue: "true", error: e.message });
-                    }
-                }
- 
-                if (await user.isSuperAdmin() === false && option.superAdmin === true) {
-                    try {
-                        await user.promoteToSuperAdmin();
-                        userReport.changes.push({ property: "superAdmin", previousValue: "false", newValue: "true" });
-                    } catch (e) {
-                        userReport.changes.push({ property: "superAdmin", previousValue: "false", newValue: "false", error: e.message });
-                    }
-                }
-            }
- 
-            // ************************
-            // member groups
-            // ************************
-            if (option.memberGroups !== undefined) {
-                const previousGroups: string[] = await user.getMemberUserGroupIds()
-                const newGroups: string[] = option.memberGroups;
-                if (option.superAdmin !== undefined) {
-                    if (option.superAdmin === true) {
-                        if (newGroups.indexOf("admin") === -1) {
-                            newGroups.push("admin");
-                        }
-                    }
-                }
-                const groupsToAdd: string[] = newGroups.filter(x => !previousGroups.includes(x));
-                const groupsToRemove: string[] = previousGroups.filter(x => !newGroups.includes(x));
-                let userGroup: UserGroup | null;
-                property = "memberGroups";
-                let error: Error | null = null;
-                for (const groupId of groupsToAdd) {
-                    userGroup = await this.getUserGroup(groupId)
-                    if (!userGroup) {
-                        try {
-                            userGroup = await this.createUserGroup(groupId)
-                        } catch (e) {
-                            error = e;
-                            break;
-                        }
-                    }
-                    try {
-                        await user.addToMemberUserGroup(userGroup);
-                    } catch (e) {
-                        error = e;
-                        break;
-                    }
-                }
- 
-                for (const groupId of groupsToRemove) {
-                    try {
-                        await user.removeFromMemberUserGroup(new UserGroup(this, groupId));
-                    } catch (e) {
-                        error = e;
-                        break;
-                    }
-                }
-                if (error) {
-                    userReport.changes.push({ property, previousValue: previousGroups.join(", "), newValue: previousGroups.join(", "), error: error.message });
-                } else {
-                    Eif (groupsToAdd.length > 0 || groupsToRemove.length > 0) {
-                        userReport.changes.push({ property, previousValue: previousGroups.join(", "), newValue: newGroups.join(", ") });
-                    }
-                }
- 
-            }
- 
-            // ************************
-            // subadmin groups
-            // ************************
-            if (option.subadminGroups !== undefined) {
-                const previousGroups: string[] = await user.getSubadminUserGroupIds()
-                const newGroups: string[] = option.subadminGroups;
-                const groupsToAdd: string[] = newGroups.filter(x => !previousGroups.includes(x));
-                const groupsToRemove: string[] = previousGroups.filter(x => !newGroups.includes(x));
-                let userGroup: UserGroup | null;
-                property = "subadminGroups";
-                let error: Error | null = null;
-                for (const groupId of groupsToAdd) {
-                    userGroup = await this.getUserGroup(groupId)
-                    if (!userGroup) {
-                        try {
-                            userGroup = await this.createUserGroup(groupId)
-                        } catch (e) {
-                            error = e;
-                            break;
-                        }
-                    }
-                    try {
-                        await user.promoteToUserGroupSubadmin(userGroup);
-                    } catch (e) {
-                        error = e;
-                        break;
-                    }
-                }
- 
-                for (const groupId of groupsToRemove) {
-                    try {
-                        await user.demoteFromSubadminUserGroup(new UserGroup(this, groupId));
-                    } catch (e) {
-                        error = e;
-                        break;
-                    }
-                }
-                if (error) {
-                    userReport.changes.push({ property, previousValue: previousGroups.join(", "), newValue: previousGroups.join(", "), error: error.message });
-                } else {
-                    userReport.changes.push({ property, previousValue: previousGroups.join(", "), newValue: newGroups.join(", ") });
-                }
- 
-            }
- 
-            // ************************
-            // display name
-            // ************************
-            if (option.displayName !== undefined) {
-                previousValue = await user.getDisplayName();
-                newValue = option.displayName
-                property = "displayName";
-                if (previousValue !== newValue) {
-                    try {
-                        await user.setDisplayName(option.displayName);
-                        userReport.changes.push({ property, previousValue, newValue });
-                    } catch (e) {
-                        userReport.changes.push({ property, previousValue, newValue: previousValue, error: e.message });
-                    }
-                }
-            }
- 
-            // ************************
-            // email
-            // ************************
-            if (option.email !== undefined) {
-                previousValue = await user.getEmail();
-                newValue = option.email;
-                property = "email";
-                if (previousValue !== newValue) {
-                    try {
-                        await user.setEmail(option.email);
-                        userReport.changes.push({ property, previousValue, newValue });
-                    } catch (e) {
-                        userReport.changes.push({ property, previousValue, newValue: previousValue, error: e.message });
-                    }
-                }
-            }
- 
-            // ************************
-            // language
-            // ************************
-            if (option.language !== undefined) {
-                previousValue = await user.getLanguage();
-                newValue = option.language;
-                property = "language";
-                if (previousValue !== newValue) {
-                    try {
-                        await user.setLanguage(option.language);
-                        userReport.changes.push({ property, previousValue, newValue });
-                    } catch (e) {
-                        userReport.changes.push({ property, previousValue, newValue: previousValue, error: e.message });
-                    }
-                }
-            }
- 
-            // ************************
-            // locale
-            // ************************
-            if (option.locale !== undefined) {
-                previousValue = await user.getLocale();
-                newValue = option.locale;
-                property = "locale";
-                if (previousValue !== newValue) {
-                    try {
-                        await user.setLocale(option.locale);
-                        userReport.changes.push({ property, previousValue, newValue });
-                    } catch (e) {
-                        userReport.changes.push({ property, previousValue, newValue: previousValue, error: e.message });
-                    }
-                }
-            }
- 
-            // ************************
-            // twitter
-            // ************************
-            if (option.twitter !== undefined) {
-                previousValue = await user.getTwitter();
-                newValue = option.twitter;
-                property = "twitter";
-                if (previousValue !== newValue) {
-                    try {
-                        await user.setTwitter(option.twitter);
-                        userReport.changes.push({ property, previousValue, newValue });
-                    } catch (e) {
-                        userReport.changes.push({ property, previousValue, newValue: previousValue, error: e.message });
-                    }
-                }
-            }
- 
-            // ************************
-            // phone
-            // ************************
-            if (option.phone !== undefined) {
-                previousValue = await user.getPhone();
-                newValue = option.phone;
-                property = "phone";
-                if (previousValue !== newValue) {
-                    try {
-                        await user.setPhone(option.phone);
-                        userReport.changes.push({ property, previousValue, newValue });
-                    } catch (e) {
-                        userReport.changes.push({ property, previousValue, newValue: previousValue, error: e.message });
-                    }
-                }
-            }
- 
-            // ************************
-            // password
-            // ************************
-            if (option.password !== undefined) {
-                previousValue = "********";
-                newValue = option.password;
-                property = "password";
-                try {
-                    await user.setPassword(option.password);
-                    userReport.changes.push({ property, previousValue, newValue: previousValue });
-                } catch (e) {
-                    userReport.changes.push({ property, previousValue, newValue: previousValue, error: e.message });
-                }
-            }
- 
-            // ************************
-            // address
-            // ************************
-            if (option.address !== undefined) {
-                previousValue = await user.getAddress();
-                newValue = option.address;
-                property = "address";
-                if (previousValue !== newValue) {
-                    try {
-                        await user.setAddress(option.address);
-                        userReport.changes.push({ property, previousValue, newValue });
-                    } catch (e) {
-                        userReport.changes.push({ property, previousValue, newValue: previousValue, error: e.message });
-                    }
-                }
-            }
- 
-            // ************************
-            // website
-            // ************************
-            if (option.website !== undefined) {
-                previousValue = await user.getWebsite();
-                newValue = option.website;
-                property = "website";
-                if (previousValue !== newValue) {
-                    try {
-                        await user.setWebsite(option.website);
-                        userReport.changes.push({ property, previousValue, newValue });
-                    } catch (e) {
-                        userReport.changes.push({ property, previousValue, newValue: previousValue, error: e.message });
-                    }
-                }
-            }
- 
-            // ************************
-            // quota
-            // ************************
-            if (option.quota !== undefined) {
-                previousValue = await (await user.getQuotaUserFriendly()).quota;
-                newValue = option.quota;
-                property = "quota";
-                if (previousValue !== newValue) {
-                    try {
-                        await user.setQuota(option.quota);
-                        userReport.changes.push({ property, previousValue, newValue });
-                    } catch (e) {
-                        userReport.changes.push({ property, previousValue, newValue: previousValue, error: e.message });
-                    }
-                }
-            }
- 
-            // ************************
-            // resend welcome email
-            // ************************
-            if (option.resendWelcomeEmail !== undefined) {
-                previousValue = "not sent";
-                newValue = "sent";
-                property = "resendWelcomeEmail";
-                if (option.resendWelcomeEmail) {
-                    try {
-                        await user.resendWelcomeEmail();
-                        userReport.changes.push({ property, previousValue, newValue });
-                    } catch (e) {
-                        userReport.changes.push({ property, previousValue, newValue: previousValue, error: e.message });
-                    }
-                }
-            }
- 
-            if (userReport.changes.length === 0) {
-                userReport.message = `User ${option.id} not changed`;
-            }
-            report.push(userReport);
-        }
-        return report;
-    }
- 
-    // ***************************************************************************************
-    // shares
-    // https://docs.nextcloud.com/server/latest/developer_manual/client_apis/OCS/ocs-share-api.html
-    // ***************************************************************************************
- 
-    /**
-     * create a new share
-     */
-    public async createShare(options: ICreateShare): Promise<Share> {
- 
-        const shareRequest = Share.createShareRequestBody(options);
-        debug(shareRequest);
- 
-        const requestInit: RequestInit = {
-            body: shareRequest,
-            headers: this.getOcsHeaders(),
-            method: "POST",
-        };
-        const url = this.nextcloudOrigin + "/ocs/v2.php/apps/files_sharing/api/v1/shares";
- 
-        // try {
-        const response: Response = await this.getHttpResponse(
-            url,
-            requestInit,
-            [200],
-            { description: "Share create" });
- 
-        const rawResult: any = await response.json();
-        debug(rawResult);
-        return Share.getShare(this, rawResult.ocs.data.id);
-        /* } catch (e) {
-            debug("result " + e.message);
-            debug("requestInit ", JSON.stringify(requestInit, null, 4));
-            debug("headers " + JSON.stringify(headers, null, 4));
-            debug("url ", url);
-            throw e;
-        } */
-    }
- 
-    /**
-     * update a new share
-     */
-    public async updateShare(shareId: string, body: { password: string } | { expireDate: string } | { note: string }): Promise<void> {
- 
-        debug("updateShare body ", body);
- 
-        const requestInit: RequestInit = {
-            body: JSON.stringify(body, null, 4),
-            headers: this.getOcsHeaders(),
-            method: "PUT",
-        };
-        const url = this.nextcloudOrigin + "/ocs/v2.php/apps/files_sharing/api/v1/shares/" + shareId;
- 
-        await this.getHttpResponse(
-            url,
-            requestInit,
-            [200],
-            { description: "Share update" });
- 
-    }
- 
-    /**
-     * get share information
-     * @param shareId
-     */
-    public async getShare(shareId: string): Promise<any> {
- 
-        const requestInit: RequestInit = {
-            headers: this.getOcsHeaders(),
-            method: "GET",
-        };
-        const url = this.nextcloudOrigin + "/ocs/v2.php/apps/files_sharing/api/v1/shares/" + shareId;
- 
-        const response: Response = await this.getHttpResponse(
-            url,
-            requestInit,
-            [200],
-            { description: "Share get" });
- 
-        const rawResult: any = await response.json();
-        return rawResult;
-        /*
-    } catch (e) {
-        debug("result " + e.message);
-        debug("requestInit ", JSON.stringify(requestInit, null, 4));
-        debug("headers " + JSON.stringify(headers, null, 4));
-        debug("url ", url);
-        throw e;
-    }
-    */
-    }
- 
-    /**
-     * get share information
-     * @param shareId
-     */
-    public async deleteShare(shareId: string): Promise<any> {
- 
-        const requestInit: RequestInit = {
-            headers: this.getOcsHeaders(),
-            method: "DELETE",
-        };
-        const url = this.nextcloudOrigin + "/ocs/v2.php/apps/files_sharing/api/v1/shares/" + shareId;
- 
-        const response: Response = await this.getHttpResponse(
-            url,
-            requestInit,
-            [200],
-            { description: "Share delete" });
- 
-    }
- 
-    // ***************************************************************************************
-    // notfication management
-    // ***************************************************************************************
-    /**
-     * @returns array of notification objects
-     */
-    public async getNotifications(): Promise<object[]> {
-        const requestInit: RequestInit = {
-            headers: this.getOcsHeaders(),
-            method: "GET",
-        };
- 
-        const response: Response = await this.getHttpResponse(
-            this.nextcloudOrigin + "/ocs/v2.php/apps/notifications/api/v2/notifications",
-            requestInit,
-            [200, 404],
-            { description: "Notifications get" });
- 
-        // no notification found
-        if (response.status === 404) {
-            return [];
-        }
- 
-        const rawResult: any = await response.json();
- 
-        let notifications = [];
- 
-        if (rawResult && rawResult.ocs && rawResult.ocs.data) {
-            notifications = rawResult.ocs.data;
-        } else {
-            throw new ClientError("Fatal Error: nextcloud notifications data missing", "ERR_SYSTEM_INFO_MISSING_DATA"); // @todo wrong error message
-        }
- 
-        const result: object[] = notifications;
-        return result;
-    }
- 
-    public async getUpdateNotifications(version: string): Promise<object> {
- 
-        // @todo refactoring... /ocs/v2.php/apps/notifications/api/v2/notifications/<id>   (GET/DELETE)
- 
-        const requestInit: RequestInit = {
-            headers: this.getOcsHeaders(),
-            method: "GET",
-        };
- 
-        const response: Response = await this.getHttpResponse(
-            this.nextcloudOrigin + `/ocs/v2.php/apps/updatenotification/api/v1/applist/${version}`,
-            requestInit,
-            [200],
-            { description: "UpdateNotifications get" });
- 
-        const rawResult: any = await response.json();
- 
-        let updateNotification = {};
- 
-        if (rawResult && rawResult.ocs && rawResult.ocs.data) {
-            updateNotification = rawResult.ocs.data;
-        } else {
-            throw new ClientError("Fatal Error: nextcloud notifications data missing", "ERR_SYSTEM_INFO_MISSING_DATA");
-        }
- 
-        const result: object = updateNotification;
-        return result;
-    }
- 
-    // @todo to be refactored to user
-    public async sendNotificationToUser(userId: string, shortMessage: string, longMessage?: string): Promise<void> {
-        const requestInit: RequestInit = {
-            headers: new Headers({
-                "Accept": "application/json",
-                "Content-Type": "application/x-www-form-urlencoded",
-                "OCS-APIRequest": "true",
-            }),
-            method: "POST",
-        };
- 
-        if (!longMessage) {
-            longMessage = "";
-        }
-        longMessage = `&longMessage=${encodeURIComponent(longMessage)}`;
-        const queryString = `${encodeURIComponent(userId)}?shortMessage=${encodeURIComponent(shortMessage)}${longMessage}`;
-        const response: Response = await this.getHttpResponse(
-            this.nextcloudOrigin + `/ocs/v2.php/apps/admin_notifications/api/v1/notifications/${queryString}`,
-            requestInit,
-            [200],
-            { description: "User create" });
-        const rawResult: any = await response.json();
-        //        console.log(rawResult);
-    }
- 
-    // ***************************************************************************************
-    // apps management
-    // ***************************************************************************************
-    /**
-     * returns apps
-     */
-    public async getApps(): Promise<string[]> {
-        const requestInit: RequestInit = {
-            headers: this.getOcsHeaders(),
-            method: "GET",
-        };
- 
-        const response: Response = await this.getHttpResponse(
-            this.getOcsUrl(`/apps`),
-            requestInit,
-            [200],
-            { description: "Apps get" });
- 
-        const rawResult: any = await response.json();
- 
-        let apps = [];
- 
-        if (rawResult && rawResult.ocs && rawResult.ocs.data) {
-            apps = rawResult.ocs.data;
-        } else {
-            throw new ClientError("Fatal Error: nextcloud apps data missing", "ERR_SYSTEM_INFO_MISSING_DATA");
-        }
- 
-        const result: string[] = apps;
- 
-        return result;
-    }
-    public async getAppInfos(appName: string): Promise<object> {
-        const requestInit: RequestInit = {
-            headers: this.getOcsHeaders(),
-            method: "GET",
-        };
- 
-        const response: Response = await this.getHttpResponse(
-            this.getOcsUrl(`/apps/${appName}`),
-            requestInit,
-            [200],
-            { description: "App Infos get" });
- 
-        const rawResult: any = await response.json();
- 
-        let appInfo = {};
- 
-        if (rawResult && rawResult.ocs && rawResult.ocs.data) {
-            appInfo = rawResult.ocs.data;
-        } else {
-            throw new ClientError("Fatal Error: nextcloud apps data missing", "ERR_SYSTEM_INFO_MISSING_DATA");
-        }
- 
-        const result: object = appInfo;
- 
-        return result;
-    }
- 
-    // ***************************************************************************************
-    // private methods
-    // ***************************************************************************************
- 
-    /**
-     * asserts valid xml
-     * asserts multistatus response
-     * asserts that a href is available in the multistatus response
-     * asserts propstats and prop
-     * @param response the http response
-     * @param href get only properties that match the href
-     * @returns array of properties
-     * @throws GeneralError
-     */
-    private async getPropertiesFromWebDAVMultistatusResponse(response: Response, href: string): Promise<any[]> {
-        const responseContentType: string | null = response.headers.get("Content-Type");
- 
-        if (!responseContentType) {
-            throw new ClientError("Response content type expected", "ERR_RESPONSE_WITHOUT_CONTENT_TYPE_HEADER");
-        }
- 
-        if (responseContentType.indexOf("application/xml") === -1) {
-            throw new ClientError("XML response content type expected", "ERR_XML_RESPONSE_CONTENT_TYPE_EXPECTED");
-        }
- 
-        const xmlBody: string = await response.text();
- 
-        if (parser.validate(xmlBody) !== true) {
-            throw new ClientError(`The response is not valid XML: ${xmlBody}`, "ERR_RESPONSE_NOT_INVALID_XML");
-        }
-        const options: any = {
-            ignoreNameSpace: true,
-        };
-        const body: any = parser.parse(xmlBody, options);
- 
-        // ensure that we have a multistatus response
-        if (!body.multistatus || !body.multistatus.response) {
-            throw new ClientError(`The response is is not a WebDAV multistatus response`, "ERR_RESPONSE_NO_MULTISTATUS_XML");
-        }
- 
-        // ensure that response is always an array
-        if (body.multistatus.response.href || body.multistatus.response.propstat) {
-            body.multistatus.response = new Array(body.multistatus.response);
-        }
-        /*
-                if (body.multistatus.response.propstat) {
-                    body.multistatus.response = [body.multistatus.response];
-                }
-        */
-        const responseProperties: any[] = [];
-        for (const res of body.multistatus.response) {
- 
-            if (!res.href) {
-                throw new ClientError(`The mulitstatus response must have a href`, "ERR_RESPONSE_MISSING_HREF_MULTISTATUS");
-            }
- 
-            if (!res.propstat) {
-                throw new ClientError(`The mulitstatus response must have a "propstat" container`, "ERR_RESPONSE_MISSING_PROPSTAT");
-            }
-            let propStats = res.propstat;
- 
-            // ensure an array
-            if (res.propstat.status || res.propstat.prop) {
-                propStats = [res.propstat];
-            }
- 
-            for (const propStat of propStats) {
-                if (!propStat.status) {
-                    throw new ClientError(`The propstat must have a "status"`, "ERR_RESPONSE_MISSING_PROPSTAT_STATUS");
-                }
-                if (propStat.status === "HTTP/1.1 200 OK") {
-                    if (!propStat.prop) {
-                        throw new ClientError(`The propstat must have a "prop"`, "ERR_RESPONSE_MISSING_PROPSTAT_PROP");
-                    }
-                    const property: any = propStat.prop;
-                    property._href = res.href;
-                    responseProperties.push(property);
-                }
-            }
-            //            }
-        }
-        return responseProperties;
-    }
- 
-    /**
-     * nextcloud creates a csrf token and stores it in the html header attribute
-     * data-requesttoken
-     * this function is currently not used
-     * @returns the csrf token / requesttoken
-     */
-    /*
-        private async getCSRFToken(): Promise<string> {
- 
-            const requestInit: RequestInit = {
-                method: "GET",
-            };
- 
-            const response: Response = await this.getHttpResponse(
-                this.nextcloudOrigin,
-                requestInit,
-                [200],
-                { description: "CSER token get" });
- 
-            const html = await response.text();
- 
-            const requestToken: string = html.substr(html.indexOf("data-requesttoken=") + 19, 89);
-            debug("getCSRFToken  %s", requestToken);
-            return requestToken;
-        }
-    */
- 
-    private async getHttpResponse(url: string, requestInit: RequestInit, expectedHttpStatusCode: number[], context: IRequestContext): Promise<Response> {
- 
-        if (!requestInit.headers) {
-            requestInit.headers = new Headers();
-        }
- 
-        /* istanbul ignore else */
-        if (this.fakeServer) {
-            return await this.fakeServer.getFakeHttpResponse(url, requestInit, expectedHttpStatusCode, context);
-        } else {
-            return await this.httpClient!.getHttpResponse(url, requestInit, expectedHttpStatusCode, context);
-        }
-    }
- 
-    /**
-     * get contents array of a folder
-     * @param folderName Name of the folder like "/company/branches/germany"
-     * @param folderIndicator true if folders are requested otherwise files
-     * @returns array of folder contents meta data
-     */
-    private async Contents(folderName: string, folderIndicator: boolean): Promise<any[]> {
-        debug("Contents: folder %s", folderName);
-        const folders: Folder[] = [];
-        folderName = this.sanitizeFolderName(folderName);
-        const resultArray: any[] = [];
- 
-        if (folderIndicator === true) {
-            debug("Contents: get folders");
-        } else {
-            debug("Contents: get files");
-        }
-        try {
-            const folderContentsArray = await this.getFolderContents(folderName);
- 
-            // debug("###########################");
-            // debug("$s", JSON.stringify(folderContentsArray, null, 4));
-            // debug("###########################");
- 
-            for (const folderElement of folderContentsArray) {
-                if (folderElement.type === "directory") {
-                    if (folderIndicator === true) {
-                        resultArray.push(folderElement);
-                    }
-                } else {
-                    if (folderIndicator === false) {
-                        debug("Contents folder element file %O ", folderElement);
-                        resultArray.push(folderElement);
-                    }
-                }
-            }
-        } catch (e) {
-            debug("Contents: exception occurred %s", e.message);
-        }
- 
-        return resultArray;
-    }
- 
-    private sanitizeFolderName(folderName: string): string {
-        if (folderName[0] !== "/") {
-            folderName = "/" + folderName;
-        }
-        // remove trailing "/" es
-        folderName = folderName.replace(/\/+$/, "");
-        if (folderName === "") {
-            folderName = "/";
-        }
- 
-        return folderName;
-    }
- 
-    private getTagIdFromHref(href: string): number {
-        return parseInt(href.split("/")[href.split("/").length - 1], 10);
-    }
- 
-    private async createFolderInternal(folderName: string): Promise<void> {
- 
-        const url: string = this.webDAVUrl + folderName;
-        debug("createFolderInternal %s", url);
- 
-        const requestInit: RequestInit = {
-            method: "MKCOL",
-        };
-        try {
-            await this.getHttpResponse(
-                url,
-                requestInit,
-                [201],
-                { description: "Folder create" },
-            );
- 
-        } catch (err) {
-            debug("Error in createFolderInternal %s %s %s %s", err.message, requestInit.method, url);
-            throw err;
-        }
-    }
- 
-    private async stat(fileName: string): Promise<IStat> {
- 
-        const url: string = this.webDAVUrl + fileName;
-        debug("stat %s", url);
- 
-        const requestInit: RequestInit = {
-            body: `<?xml version="1.0"?>
-            <d:propfind  xmlns:d="DAV:" xmlns:oc="http://owncloud.org/ns" xmlns:nc="http://nextcloud.org/ns">
-            <d:prop>
-                  <d:getlastmodified />
-                  <d:getetag />
-                  <d:getcontenttype />
-                  <d:resourcetype />
-                  <oc:fileid />
-                  <oc:permissions />
-                  <oc:size />
-                  <d:getcontentlength />
-                  <nc:has-preview />
-                  <oc:favorite />
-                  <oc:comments-unread />
-                  <oc:owner-display-name />
-                  <oc:share-types />
-            </d:prop>
-          </d:propfind>`,
-            headers: new Headers({ Depth: "0" }),
-            method: "PROPFIND",
-        };
-        let response: Response;
-        try {
-            response = await this.getHttpResponse(
-                url,
-                requestInit,
-                [207],
-                { description: "File/Folder get details" },
-            );
- 
-        } catch (err) {
-            debug("Error in stat %s %s %s %s", err.message, requestInit.method, url);
-            throw err;
-        }
- 
-        const properties: any[] = await this.getPropertiesFromWebDAVMultistatusResponse(response, "");
-        let resultStat: IStat | null = null;
- 
-        for (const prop of properties) {
-            resultStat = {
-                basename: basename(fileName),
-                fileid: prop.fileid,
-                filename: fileName,
-                lastmod: prop.getlastmodified,
-                type: "file",
-            };
- 
-            if (prop.getcontentlength) {
-                resultStat.size = prop.getcontentlength;
-            } else {
-                resultStat.type = "directory";
-            }
- 
-            if (prop.getcontenttype) {
-                resultStat.mime = prop.getcontenttype;
-            }
-        }
- 
-        if (!resultStat) {
-            debug("Error: response %s", JSON.stringify(properties, null, 4));
-            throw new ClientError("Error getting status information from : " + url,
-                "ERR_STAT");
-        }
-        return resultStat;
-    }
- 
-    private getOcsMetaStatus(input: any): { code: number, message: string } {
-        let code: number;
-        let message: string = "";
-        if (input.ocs &&
-            input.ocs.meta &&
-            input.ocs.meta.statuscode) {
-            code = input.ocs.meta.statuscode;
-            if (input.ocs.meta.message) {
-                message = input.ocs.meta.message;
-            }
-            return { code, message }
-        }
-        throw new InvalidServiceResponseFormatError("Fatal Error: The OCS meta status could not be retrieved from OCS response");
-    }
- 
-    private getOcsHeaders(): Headers {
-        return new Headers({
-            "OCS-APIRequest": "true",
-            "Content-Type": "application/json",
-            "Accept": "application/json"
-        });
-    }
- 
-    private getOcsUrl(suffix: string): string {
-        /*
-        if (!suffix) {
-            suffix = "";
-        }
-        if (!suffix.startsWith("/")) {
-            suffix = `/${suffix}`
-        }
-        */
-        return `${this.nextcloudOrigin}/ocs/v1.php/cloud${suffix}`;
-    }
- 
-    private async putFileContents(fileName: string, data: Buffer | NodeJS.ReadableStream): Promise<Response> {
- 
-        const url: string = this.webDAVUrl + fileName;
-        debug("putFileContents %s", url);
- 
-        const requestInit: RequestInit = {
-            body: data,
-            method: "PUT",
-        };
-        let response: Response;
-        let description = "File save content ";
-        Eif (data instanceof Buffer) {
-            description += "from buffer";
-        } else {
-            description += "from stream";
-        }
-        response = await this.getHttpResponse(
-            url,
-            requestInit,
-            [201, 204],
-            { description },
-        );
- 
-        return response;
-    }
- 
-}
- 
- -
-
- - - - - - - - - \ No newline at end of file diff --git a/docs/coverage/command.ts.html b/docs/coverage/command.ts.html deleted file mode 100644 index 36e74341..00000000 --- a/docs/coverage/command.ts.html +++ /dev/null @@ -1,440 +0,0 @@ - - - - - - Code coverage report for command.ts - - - - - - - - - -
-
-

All files command.ts

-
- -
- 100% - Statements - 23/23 -
- - -
- 100% - Branches - 10/10 -
- - -
- 100% - Functions - 7/7 -
- - -
- 100% - Lines - 23/23 -
- - -
-

- Press n or j to go to the next uncovered block, b, p or k for the previous block. -

-
-
-

-
1 -2 -3 -4 -5 -6 -7 -8 -9 -10 -11 -12 -13 -14 -15 -16 -17 -18 -19 -20 -21 -22 -23 -24 -25 -26 -27 -28 -29 -30 -31 -32 -33 -34 -35 -36 -37 -38 -39 -40 -41 -42 -43 -44 -45 -46 -47 -48 -49 -50 -51 -52 -53 -54 -55 -56 -57 -58 -59 -60 -61 -62 -63 -64 -65 -66 -67 -68 -69 -70 -71 -72 -73 -74 -75 -76 -77 -78 -79 -80 -81 -82 -83 -84 -85 -86 -87 -88 -89 -90 -91 -92 -93 -94 -95 -96 -97 -98 -99 -100 -101 -102 -103 -104 -105 -106 -107 -108 -109 -110 -111 -112 -113 -114 -115 -116 -117 -118 -119 -120 -121  -1x -  -1x -  -  -  -  -  -  -  -  -  -1x -  -  -  -1x -  -  -  -1x -  -  -  -1x -  -  -  -1x -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -1x -  -  -  -  -  -  -17x -17x -17x -17x -  -  -  -  -  -  -  -  -  -19x -19x -1x -  -18x -17x -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -65x -15x -  -50x -  -  -  -  -  -  -  -18x -  -  -  -  -  -  -  -7x -  -  -  -  -  -  -  -27x -  -  -  - 
// tslint:disable-next-line:no-var-requires
-const debug = require("debug").debug("Command");
- 
-import Client, {
-    CommandAlreadyExecutedError,
-} from "./client";
- 
-/**
- * The potential states that a command can have.
- * When a command is created, the state is "initial"
- * When the execution has started, the status is "running"
- * When the execution has finsihed, the status can be "succes" or "failed"
- */
-export enum CommandStatus {
-    /**
-     * When a command is created, the state is "initial"
-     */
-    initial = "initial",
-    /**
-     * When the execution has started, the status is "running"
-     */
-    running = "running",
-    /**
-     * After successful  execution of the command, the status is "success"
-     */
-    success = "success",
-    /**
-     * After unsuccessfull execution of the command, the status is "failed"
-     */
-    failed = "failed",
-}
- 
-/**
- * when the command has finished, the client can get the result of the command execution
- */
-export interface CommandResultMetaData {
-    errors: string[],
-    messages: string[],
-    timeElapsed: number,
-}
- 
-/**
- * The command class represents a potential long running activity.
- * This activity has been wrapped into an object to ease the tracking of the processing state.
- * Create a command with  receiver information, execute the command and check the status and progress.
- * Check the result when finsished.
- */
-export default abstract class Command {
-    protected client: Client;
-    protected status: CommandStatus;
-    protected percentCompleted: number;
-    protected resultMetaData: CommandResultMetaData;
- 
-    constructor(client: Client) {
-        this.client = client;
-        this.status = CommandStatus.initial;
-        this.percentCompleted = 0;
-        this.resultMetaData = { messages: [], errors: [], timeElapsed: 0 };
-    }
- 
-    /**
-     * final execute the command
-     * @async
-     * @final
-     * @returns {Promise<void>}
-     */
-    public async execute(): Promise<void> {
-        debug("execute Command = " + this.constructor.name, this.status);
-        if (this.isFinished()) {
-            throw new CommandAlreadyExecutedError("Error: Command has already been executed. Command = " + this.constructor.name);
-        }
-        if (this.status === CommandStatus.initial) {
-            await this.onExecute();
-        }
-        // do nothing if already running
-    }
- 
-    /**
-     * execute the command
-     * @async
-     * @returns {Promise<void>}
-     */
-    protected abstract async onExecute(): Promise<void>;
- 
-    /**
-     * returns true, if the command has been finished
-     * @returns {boolean}
-     */
-    public isFinished(): boolean {
-        if (this.status === CommandStatus.failed || this.status === CommandStatus.success) {
-            return true;
-        }
-        return false;
-    }
- 
-    /**
-     * returns the status of the command
-     * @returns {CommandStatus}
-     */
-    public getStatus(): CommandStatus {
-        return this.status;
-    }
- 
-    /**
-     * returns the completion percentage of the command
-     * @returns {number} percentage of completion
-     */
-    public getPercentCompleted(): number {
-        return this.percentCompleted;
-    }
- 
-    /**
-     * returns the result meta data of the command
-     * @returns {null|any} the result of the command
-     */
-    public getResultMetaData(): CommandResultMetaData {
-        return this.resultMetaData;
-    }
- 
-}
- 
- -
-
- - - - - - - - - \ No newline at end of file diff --git a/docs/coverage/environment.ts.html b/docs/coverage/environment.ts.html deleted file mode 100644 index ea7913e9..00000000 --- a/docs/coverage/environment.ts.html +++ /dev/null @@ -1,260 +0,0 @@ - - - - - - Code coverage report for environment.ts - - - - - - - - - -
-
-

All files environment.ts

-
- -
- 100% - Statements - 18/18 -
- - -
- 100% - Branches - 13/13 -
- - -
- 100% - Functions - 2/2 -
- - -
- 100% - Lines - 18/18 -
- - -
-

- Press n or j to go to the next uncovered block, b, p or k for the previous block. -

-
-
-

-
1 -2 -3 -4 -5 -6 -7 -8 -9 -10 -11 -12 -13 -14 -15 -16 -17 -18 -19 -20 -21 -22 -23 -24 -25 -26 -27 -28 -29 -30 -31 -32 -33 -34 -35 -36 -37 -38 -39 -40 -41 -42 -43 -44 -45 -46 -47 -48 -49 -50 -51 -52 -53 -54 -55 -56 -57 -58 -59 -60 -611x -1x -1x -  -1x -  -1x -  -  -  -  -  -  -9x -9x -9x -9x -  -  -8x -  -1x -  -  -  -  -  -  -  -  -  -  -  -9x -2x -  -  -  -7x -1x -  -  -  -6x -1x -  -  -  -5x -  -  -  -  -  -  -  -  -  -  -  - 
import debugFactory from "debug";
-import ClientError from "./error";
-import Server from "./server";
- 
-const debug = debugFactory("NCEnvironment");
- 
-export default class Environment {
-    public readonly url?: string;
-    public readonly userName?: string;
-    public readonly password?: string;
-    public readonly recordingActive: boolean;
- 
-    public constructor() {
-        this.url = process.env.NEXTCLOUD_URL;
-        this.userName = process.env.NEXTCLOUD_USERNAME;
-        this.password = process.env.NEXTCLOUD_PASSWORD;
-        if ((process.env.TEST_RECORDING_ACTIVE &&
-            (process.env.TEST_RECORDING_ACTIVE === "0" || process.env.TEST_RECORDING_ACTIVE === "false" || process.env.TEST_RECORDING_ACTIVE === "inactive")) ||
-            !process.env.TEST_RECORDING_ACTIVE) {
-            this.recordingActive = false;
-        } else {
-            this.recordingActive = true;
-        }
-    }
- 
-    /**
-     * returns the nextcloud credentials that is defined in the
-     * "user-provided" service section of the VCAP_SERVICES environment
-     * @param instanceName the name of the nextcloud user provided service instance
-     * @returns credentials from the VCAP_SERVICES environment (user provided service)
-     */
-    public getServer(): Server {
- 
-        if (!this.url) {
-            throw new ClientError("NCEnvironment: NEXTCLOUD_URL not defined in environment"
-                , "ERR_NEXTCLOUD_URL_NOT_DEFINED");
-        }
- 
-        if (!this.userName) {
-            throw new ClientError("NCEnvironment: NEXTCLOUD_USERNAME not defined in environment"
-                , "ERR_NEXTCLOUD_USERNAME_NOT_DEFINED");
-        }
- 
-        if (!this.password) {
-            throw new ClientError("NCEnvironment: NEXTCLOUD_PASSWORD not defined in environment"
-                , "ERR_NEXTCLOUD_PASSWORD_NOT_DEFINED");
-        }
- 
-        return new Server({
-            basicAuth: {
-                password: this.password,
-                username: this.userName,
-            },
-            logRequestResponse: this.recordingActive,
-            url: this.url,
-        });
- 
-    }
- 
-}
- 
- -
-
- - - - - - - - - \ No newline at end of file diff --git a/docs/coverage/environmentVcapServices.ts.html b/docs/coverage/environmentVcapServices.ts.html deleted file mode 100644 index d18b2442..00000000 --- a/docs/coverage/environmentVcapServices.ts.html +++ /dev/null @@ -1,299 +0,0 @@ - - - - - - Code coverage report for environmentVcapServices.ts - - - - - - - - - -
-
-

All files environmentVcapServices.ts

-
- -
- 100% - Statements - 24/24 -
- - -
- 100% - Branches - 15/15 -
- - -
- 100% - Functions - 2/2 -
- - -
- 100% - Lines - 24/24 -
- - -
-

- Press n or j to go to the next uncovered block, b, p or k for the previous block. -

-
-
-

-
1 -2 -3 -4 -5 -6 -7 -8 -9 -10 -11 -12 -13 -14 -15 -16 -17 -18 -19 -20 -21 -22 -23 -24 -25 -26 -27 -28 -29 -30 -31 -32 -33 -34 -35 -36 -37 -38 -39 -40 -41 -42 -43 -44 -45 -46 -47 -48 -49 -50 -51 -52 -53 -54 -55 -56 -57 -58 -59 -60 -61 -62 -63 -64 -65 -66 -67 -68 -69 -70 -71 -72 -73 -74  -1x -  -1x -1x -1x -1x -  -1x -  -  -  -  -  -  -1x -  -  -  -  -  -  -8x -2x -  -  -6x -6x -  -6x -1x -1x -  -  -5x -1x -  -  -  -  -4x -1x -  -  -  -  -3x -1x -  -  -  -  -2x -2x -2x -  -  -  -  -  -  -  -  -  -2x -  -  -  -  -  -  -  -  - 
// tslint:disable-next-line:no-var-requires
-require("dotenv").config();
- 
-import debugFactory from "debug";
-import ClientError from "./error";
-import Server from "./server";
-export { Server };
- 
-const debug = debugFactory("NCEnvironmentVcapServices");
- 
-/**
- * returns the nextcloud credentials that is defined in the
- * "user-provided" service section of the VCAP_SERVICES environment
- * instanceName: the name of the nextcloud user provided service instance
- */
-export default class EnvironmentVcapServices {
-    public readonly url: string;
-    public readonly userName: string;
-    public readonly password: string;
- 
-    public constructor(instanceName: string) {
- 
-        if (!process.env.VCAP_SERVICES) {
-            throw new ClientError("NCEnvironmentVcapServices: environment VCAP_SERVICES not found", "ERR_VCAP_SERVICES_NOT_FOUND");
-        }
- 
-        const vcapServices = require("vcap_services");
-        const cred = vcapServices.getCredentials("user-provided", undefined, instanceName);
- 
-        if (!cred || cred === undefined || (!cred.url && !cred.username && !cred.password)) {
-            debug("NCEnvironmentVcapServices: error credentials not found or not fully specified %O", cred);
-            throw new ClientError(`NCEnvironmentVcapServices: nextcloud credentials not found in environment VCAP_SERVICES. Service section: "user-provided", service instance name: "${instanceName}" `, "ERR_VCAP_SERVICES_NOT_FOUND");
-        }
- 
-        if (!cred.url) {
-            throw new ClientError("NCEnvironmentVcapServices: VCAP_SERVICES url not defined in user provided services for nextcloud"
-                , "ERR_VCAP_SERVICES_URL_NOT_DEFINED",
-                { credentials: cred });
-        }
- 
-        if (!cred.password) {
-            throw new ClientError("NCEnvironmentVcapServices: VCAP_SERVICES password not defined in user provided services for nextcloud",
-                "ERR_VCAP_SERVICES_PASSWORD_NOT_DEFINED",
-                { credentials: cred });
-        }
- 
-        if (!cred.username) {
-            throw new ClientError("NCEnvironmentVcapServices: VCAP_SERVICES username not defined in user provided services for nextcloud",
-                "ERR_VCAP_SERVICES_USERNAME_NOT_DEFINED",
-                { credentials: cred });
-        }
- 
-        this.url = cred.url as string;
-        this.userName = cred.username as string;
-        this.password = cred.password as string;
-    }
- 
-    /**
-     * returns the nextcloud credentials that is defined in the
-     * "user-provided" service section of the VCAP_SERVICES environment
-     * @param instanceName the name of the nextcloud user provided service instance
-     * @returns credentials from the VCAP_SERVICES environment (user provided service)
-     */
-    public getServer(): Server {
-        return new Server({
-            basicAuth: {
-                password: this.password,
-                username: this.userName,
-            },
-            url: this.url,
-        });
-    }
-}
- 
- -
-
- - - - - - - - - \ No newline at end of file diff --git a/docs/coverage/error.ts.html b/docs/coverage/error.ts.html deleted file mode 100644 index 9084e91a..00000000 --- a/docs/coverage/error.ts.html +++ /dev/null @@ -1,362 +0,0 @@ - - - - - - Code coverage report for error.ts - - - - - - - - - -
-
-

All files error.ts

-
- -
- 100% - Statements - 22/22 -
- - -
- 100% - Branches - 0/0 -
- - -
- 100% - Functions - 2/2 -
- - -
- 100% - Lines - 22/22 -
- - -
-

- Press n or j to go to the next uncovered block, b, p or k for the previous block. -

-
-
-

-
1 -2 -3 -4 -5 -6 -7 -8 -9 -10 -11 -12 -13 -14 -15 -16 -17 -18 -19 -20 -21 -22 -23 -24 -25 -26 -27 -28 -29 -30 -31 -32 -33 -34 -35 -36 -37 -38 -39 -40 -41 -42 -43 -44 -45 -46 -47 -48 -49 -50 -51 -52 -53 -54 -55 -56 -57 -58 -59 -60 -61 -62 -63 -64 -65 -66 -67 -68 -69 -70 -71 -72 -73 -74 -75 -76 -77 -78 -79 -80 -81 -82 -83 -84 -85 -86 -87 -88 -89 -90 -91 -92 -93 -94 -95  -  -1x -  -1x -  -  -  -  -63x -63x -63x -  -  -  -  -1x -  -  -  -93x -93x -  -  -  -  -  -  -  -1x -  -  -  -  -1x -  -  -  -  -1x -  -  -  -  -1x -  -  -  -  -1x -  -  -  -  -1x -  -  -  -  -1x -  -  -  -  -1x -  -  -  -  -1x -  -  -  -  -1x -  -  -  -  -1x -  -  -  -  -1x -  -  -  -  -1x -  -  -  -  -1x
// tslint:disable:max-classes-per-file
-// tslint:disable-next-line:no-var-requires
-const debug = require("debug").debug("ClientError");
- 
-export default class ClientError extends Error {
-    public code: string;
-    private context?: any;
- 
-    constructor(m: string, code: string, context?: any) {
-        super(m);
-        this.code = code;
-        this.context = context;
-    }
-}
- 
-// tslint:disable-next-line:max-classes-per-file
-export class BaseError extends Error {
-    private context?: any;
- 
-    constructor(m: string, context?: any) {
-        super(m);
-        this.context = context;
-    }
-}
- 
- 
-/**
- * the query limit parameter must be a number larger than 0
- */
-export class QueryLimitError extends BaseError { };
- 
-/**
- * the query offset parameter must be a number larger than 0
- */
-export class QueryOffsetError extends BaseError { };
- 
-/**
- * user group already exists
- */
-export class UserGroupAlreadyExistsError extends BaseError { };
- 
-/**
- * user group does not exist
- */
-export class UserGroupDoesNotExistError extends BaseError { };
- 
-/**
- * user group cloud not be deleted
- */
-export class UserGroupDeletionFailedError extends BaseError { };
- 
-/**
- * user not found
- */
-export class UserNotFoundError extends BaseError { };
- 
-/**
- * user already exists
- */
-export class UserAlreadyExistsError extends BaseError { };
- 
-/**
- * error creating user
- */
-export class UserCreateError extends BaseError { };
- 
-/**
- * error updating user
- */
-export class UserUpdateError extends BaseError { };
- 
-/**
- * Error sending user welcome email
- */
-export class UserResendWelcomeEmailError extends BaseError { };
- 
-/**
- * the service response is invalid
- */
-export class InvalidServiceResponseFormatError extends BaseError { };
- 
-/**
- * the service response is invalid
- */
-export class InsufficientPrivilegesError extends BaseError { };
- 
-/**
- * operation failed
- */
-export class OperationFailedError extends BaseError { };
- 
-/**
- * the command is already executed
- */
-export class CommandAlreadyExecutedError extends BaseError { };
- -
-
- - - - - - - - - \ No newline at end of file diff --git a/docs/coverage/fakeServer.ts.html b/docs/coverage/fakeServer.ts.html deleted file mode 100644 index 56f2f401..00000000 --- a/docs/coverage/fakeServer.ts.html +++ /dev/null @@ -1,236 +0,0 @@ - - - - - - Code coverage report for fakeServer.ts - - - - - - - - - -
-
-

All files fakeServer.ts

-
- -
- 100% - Statements - 27/27 -
- - -
- 100% - Branches - 10/10 -
- - -
- 100% - Functions - 2/2 -
- - -
- 100% - Lines - 27/27 -
- - -
-

- Press n or j to go to the next uncovered block, b, p or k for the previous block. -

-
-
-

-
1 -2 -3 -4 -5 -6 -7 -8 -9 -10 -11 -12 -13 -14 -15 -16 -17 -18 -19 -20 -21 -22 -23 -24 -25 -26 -27 -28 -29 -30 -31 -32 -33 -34 -35 -36 -37 -38 -39 -40 -41 -42 -43 -44 -45 -46 -47 -48 -49 -50 -51 -52 -531x -1x -  -  -  -  -  -  -  -1x -  -1x -216x -  -216x -  -  -1231x -1231x -2x -  -  -1231x -1231x -3x -  -1228x -  -  -  -1228x -  -1228x -1226x -  -  -1228x -29x -  -  -1228x -126x -126x -126x -126x -126x -126x -126x -  -1102x -  -  - 
import debugFactory from "debug";
-import {
-    RequestInit,
-    Response,
-    ResponseInit,
-} from "node-fetch";
-import { IRequestContext } from "./httpClient";
-import RequestResponseLogEntry from "./requestResponseLogEntry";
- 
-const debug = debugFactory("NCFakeServer");
- 
-export default class FakeServer {
-    public fakeResponses: RequestResponseLogEntry[] = [];
-    public constructor(fakeResponses: RequestResponseLogEntry[]) {
-        this.fakeResponses = fakeResponses;
-    }
-    public async getFakeHttpResponse(url: string, requestInit: RequestInit, expectedHttpStatusCode: number[], context: IRequestContext): Promise<Response> {
-        debug("getFakeHttpResponse");
-        if (!requestInit.method) {
-            requestInit.method = "UNDEFINED";
-        }
- 
-        const rrEntry: RequestResponseLogEntry | undefined = this.fakeResponses.shift();
-        if (!rrEntry) {
-            throw new Error(`error providing fake http response. No fake response available`);
-        }
-        const responseInit: ResponseInit = {
-            status: rrEntry.response.status,
-        };
- 
-        const response: Response = new Response(rrEntry.response.body, responseInit);
- 
-        if (rrEntry.response.contentType) {
-            response.headers.append("Content-Type", rrEntry.response.contentType);
-        }
- 
-        if (rrEntry.response.contentLocation) {
-            response.headers.append("Content-Location", rrEntry.response.contentLocation);
-        }
- 
-        if (expectedHttpStatusCode.indexOf(response.status) === -1) {
-            debug("getHttpResponse unexpected status response %s", response.status + " " + response.statusText);
-            debug("getHttpResponse description %s", context.description);
-            debug("getHttpResponse expected %s", expectedHttpStatusCode.join(","));
-            debug("getHttpResponse headers %s", JSON.stringify(response.headers, null, 4));
-            debug("getHttpResponse request body %s", requestInit.body);
-            debug("getHttpResponse text %s", await response.text());
-            throw new Error(`HTTP response status ${response.status} not expected. Expected status: ${expectedHttpStatusCode.join(",")} - status text: ${response.statusText}`);
-        }
-        return response;
-    }
-}
- 
- -
-
- - - - - - - - - \ No newline at end of file diff --git a/docs/coverage/favicon.png b/docs/coverage/favicon.png deleted file mode 100644 index 66918178..00000000 Binary files a/docs/coverage/favicon.png and /dev/null differ diff --git a/docs/coverage/file.ts.html b/docs/coverage/file.ts.html deleted file mode 100644 index cf26910b..00000000 --- a/docs/coverage/file.ts.html +++ /dev/null @@ -1,728 +0,0 @@ - - - - - - Code coverage report for file.ts - - - - - - - - - -
-
-

All files file.ts

-
- -
- 100% - Statements - 57/57 -
- - -
- 100% - Branches - 6/6 -
- - -
- 100% - Functions - 19/19 -
- - -
- 100% - Lines - 57/57 -
- - -
-

- Press n or j to go to the next uncovered block, b, p or k for the previous block. -

-
-
-

-
1 -2 -3 -4 -5 -6 -7 -8 -9 -10 -11 -12 -13 -14 -15 -16 -17 -18 -19 -20 -21 -22 -23 -24 -25 -26 -27 -28 -29 -30 -31 -32 -33 -34 -35 -36 -37 -38 -39 -40 -41 -42 -43 -44 -45 -46 -47 -48 -49 -50 -51 -52 -53 -54 -55 -56 -57 -58 -59 -60 -61 -62 -63 -64 -65 -66 -67 -68 -69 -70 -71 -72 -73 -74 -75 -76 -77 -78 -79 -80 -81 -82 -83 -84 -85 -86 -87 -88 -89 -90 -91 -92 -93 -94 -95 -96 -97 -98 -99 -100 -101 -102 -103 -104 -105 -106 -107 -108 -109 -110 -111 -112 -113 -114 -115 -116 -117 -118 -119 -120 -121 -122 -123 -124 -125 -126 -127 -128 -129 -130 -131 -132 -133 -134 -135 -136 -137 -138 -139 -140 -141 -142 -143 -144 -145 -146 -147 -148 -149 -150 -151 -152 -153 -154 -155 -156 -157 -158 -159 -160 -161 -162 -163 -164 -165 -166 -167 -168 -169 -170 -171 -172 -173 -174 -175 -176 -177 -178 -179 -180 -181 -182 -183 -184 -185 -186 -187 -188 -189 -190 -191 -192 -193 -194 -195 -196 -197 -198 -199 -200 -201 -202 -203 -204 -205 -206 -207 -208 -209 -210 -211 -212 -213 -214 -215 -216 -2171x -1x -  -  -  -  -  -  -  -1x -  -  -  -  -  -  -  -  -  -  -  -134x -  -  -  -  -  -  -  -  -134x -  -  -  -  -  -  -24x -23x -  -  -  -  -  -  -  -3x -2x -  -  -  -  -  -  -  -2x -1x -  -  -  -  -  -  -  -2x -1x -  -  -  -  -  -  -28x -27x -  -  -  -  -  -  -33x -31x -  -  -  -  -  -  -  -12x -12x -  -  -  -  -  -  -  -  -2x -2x -  -2x -1x -  -1x -  -  -  -  -  -  -  -  -  -2x -1x -1x -1x -1x -1x -1x -1x -  -  -  -  -  -  -  -2x -2x -  -  -  -  -  -  -  -3x -3x -  -  -  -  -  -  -  -1x -1x -  -  -  -  -  -  -  -14x -14x -  -  -  -  -  -  -  -3x -3x -3x -3x -5x -  -3x -  -  -  -  -  -  -  -2x -2x -  -2x -2x -1x -  -  -  -  -  -  -  -  -4x -4x -  -  -  -  -  -  -  -  -  -  -1x -1x -  -  -  -126x -8x -  -  -  - 
import path from "path";
-import Client, { ClientError } from "./client";
-import FileSystemElement from "./fileSystemElement";
-import Folder from "./folder";
- 
-/**
- * The file class represents a file in nextcloud.
- * It exposes file properties and content handling, commenting and tagging
- */
-export default class File implements FileSystemElement {
-    private memento: {
-        baseName: string,
-        id: number,
-        deleted: boolean,
-        lastmod: Date,
-        mime: string,
-        name: string,
-        size: number,
-    };
-    private client: Client;
-    constructor(client: Client, name: string, baseName: string, lastmod: string, size: number, mime: string, id: number) {
-        this.memento = {
-            baseName,
-            deleted: false,
-            id,
-            lastmod: new Date(lastmod),
-            mime,
-            name,
-            size,
-        };
-        this.client = client;
-    }
-    /**
-     * The name of the file including the path
-     * The name is readonly
-     */
-    get name(): string {
-        this.assertExistence();
-        return this.memento.name;
-    }
- 
-    /**
-     * The base name of the file (file name without path)
-     * The base name is readonly
-     */
-    get baseName(): string {
-        this.assertExistence();
-        return this.memento.baseName;
-    }
- 
-    /**
-     * The timestamp of the last file change
-     * readonly
-     */
-    get lastmod(): Date {
-        this.assertExistence();
-        return this.memento.lastmod;
-    }
- 
-    /**
-     * The file size in bytes
-     * readonly
-     */
-    get size(): number {
-        this.assertExistence();
-        return this.memento.size;
-    }
- 
-    /**
-     * The mime type (content type) of the file
-     */
-    get mime(): string {
-        this.assertExistence();
-        return this.memento.mime;
-    }
- 
-    /**
-     * The unique id of the file.
-     */
-    get id(): number {
-        this.assertExistence();
-        return this.memento.id;
-    }
- 
-    /**
-     * deletes a file
-     * @throws Error
-     */
-    public async delete(): Promise<void> {
-        this.memento.deleted = true;
-        return await this.client.deleteFile(this.memento.name);
-    }
- 
-    /**
-     * get folder of the file
-     * @throws ClientError
-     * @returns the parent folder
-     */
-    public async getFolder(): Promise<Folder> {
-        this.assertExistence();
-        const folder: Folder | null = await this.client.getFolder(path.dirname((this.memento.name)));
- 
-        if (folder) {
-            return folder;
-        }
-        throw new ClientError("Error, the folder of the file does not exist anymore", "ERR_FILE_FOLDER_DOES_NOT_EXIST");
-    }
- 
-    /**
-     * moves or renames the current file to the new location
-     * target folder must exists
-     * @param targetFileName the name of the target file /f1/f2/myfile.txt
-     * @throws Error
-     */
-    public async move(targetFileName: string): Promise<File> {
-        this.assertExistence();
-        const file: File = await this.client.moveFile(this.name, targetFileName);
-        this.memento.name = file.name;
-        this.memento.baseName = file.baseName;
-        this.memento.lastmod = file.lastmod;
-        this.memento.mime = file.mime;
-        this.memento.size = file.size;
-        return this;
-    }
- 
-    /**
-     * @returns the buffer of the file content
-     * @throws Error
-     */
-    public async getContent(): Promise<Buffer> {
-        this.assertExistence();
-        return this.client.getContent(this.name);
-    }
- 
-    /**
-     * @returns the url of the file
-     * @throws Error
-     */
-    public getUrl(): string {
-        this.assertExistence();
-        return this.client.getLink(this.name);
-    }
- 
-    /**
-     * @returns the url of the file in the UI
-     * @throws Error
-     */
-    public getUIUrl(): string {
-        this.assertExistence();
-        return this.client.getUILink(this.id);
-    }
- 
-    /**
-     * adds a tag name to the file
-     * @param tagName name of the tag
-     */
-    public async addTag(tagName: string): Promise<void> {
-        this.assertExistence();
-        return this.client.addTagToFile(this.id, tagName);
-    }
- 
-    /**
-     * get tag names
-     * @returns array of tag names
-     */
-    public async getTags(): Promise<string[]> {
-        this.assertExistence();
-        const map: Map<string, number> = await this.client.getTagsOfFile(this.id);
-        const tagNames: string[] = [];
-        for (const tagName of map) {
-            tagNames.push(tagName[0]);
-        }
-        return tagNames;
-    }
- 
-    /**
-     * removes a tag of the file
-     * @param tagName the name of the tag
-     */
-    public async removeTag(tagName: string): Promise<void> {
-        this.assertExistence();
-        const map: Map<string, number> = await this.client.getTagsOfFile(this.id);
- 
-        const tagId: number | undefined = map.get(tagName);
-        if (tagId) {
-            await this.client.removeTagOfFile(this.id, tagId);
-        }
-    }
- 
-    /**
-     * add comment to file
-     * @param comment the comment
-     */
-    public async addComment(comment: string): Promise<void> {
-        this.assertExistence();
-        return await this.client.addCommentToFile(this.id, comment);
-    }
- 
-    /**
-     * get list of comments of file
-     * @param top number of comments to return
-     * @param skip the offset
-     * @returns array of comment strings
-     * @throws Exception
-     */
-    public async getComments(top?: number, skip?: number): Promise<string[]> {
-        this.assertExistence();
-        return await this.client.getFileComments(this.id, top, skip);
-    }
- 
-    private assertExistence(): void {
-        if (this.memento.deleted) {
-            throw new ClientError("File does not exist", "ERR_FILE_NOT_EXISTING");
-        }
-    }
-}
- 
- -
-
- - - - - - - - - \ No newline at end of file diff --git a/docs/coverage/fileSizeFormatter.ts.html b/docs/coverage/fileSizeFormatter.ts.html deleted file mode 100644 index 81034f2c..00000000 --- a/docs/coverage/fileSizeFormatter.ts.html +++ /dev/null @@ -1,179 +0,0 @@ - - - - - - Code coverage report for fileSizeFormatter.ts - - - - - - - - - -
-
-

All files fileSizeFormatter.ts

-
- -
- 100% - Statements - 18/18 -
- - -
- 100% - Branches - 6/6 -
- - -
- 100% - Functions - 2/2 -
- - -
- 100% - Lines - 18/18 -
- - -
-

- Press n or j to go to the next uncovered block, b, p or k for the previous block. -

-
-
-

-
1 -2 -3 -4 -5 -6 -7 -8 -9 -10 -11 -12 -13 -14 -15 -16 -17 -18 -19 -20 -21 -22 -23 -24 -25 -26 -27 -28 -29 -30 -31 -32 -33 -34  -1x -  -20x -20x -20x -  -  -20x -  -  -  -20x -20x -5x -5x -  -15x -6x -6x -  -9x -1x -1x -  -  -8x -  -20x -20x -  -  -  - 
 
-export default class FileSizeFormatter {
-    private bytes: number;
-    private oneKiloByte = 1024;
-    private oneMegaByte = this.oneKiloByte * 1024;
-    private oneGigaByte = this.oneMegaByte * 1024;
- 
-    constructor(bytes: number) {
-        this.bytes = bytes;
-    }
-    public getUserFriendlyFileSize(): string {
-        let suffix: string;
-        let size = this.bytes;
-        if (size > this.oneGigaByte) {
-            size /= this.oneGigaByte;
-            suffix = " GB";
-        }
-        else if (this.bytes > this.oneMegaByte) {
-            size /= this.oneMegaByte;
-            suffix = " MB";
-        }
-        else if (this.bytes > this.oneKiloByte) {
-            size /= this.oneKiloByte;
-            suffix = " kB";
-        }
-        else {
-            suffix = " B";
-        }
-        size = Math.round(size);
-        return size + suffix;
-    }
- 
-}
- 
- -
-
- - - - - - - - - \ No newline at end of file diff --git a/docs/coverage/fileSystemElement.ts.html b/docs/coverage/fileSystemElement.ts.html deleted file mode 100644 index d6e5379d..00000000 --- a/docs/coverage/fileSystemElement.ts.html +++ /dev/null @@ -1,350 +0,0 @@ - - - - - - Code coverage report for fileSystemElement.ts - - - - - - - - - -
-
-

All files fileSystemElement.ts

-
- -
- 100% - Statements - 1/1 -
- - -
- 100% - Branches - 0/0 -
- - -
- 100% - Functions - 0/0 -
- - -
- 100% - Lines - 1/1 -
- - -
-

- Press n or j to go to the next uncovered block, b, p or k for the previous block. -

-
-
-

-
1 -2 -3 -4 -5 -6 -7 -8 -9 -10 -11 -12 -13 -14 -15 -16 -17 -18 -19 -20 -21 -22 -23 -24 -25 -26 -27 -28 -29 -30 -31 -32 -33 -34 -35 -36 -37 -38 -39 -40 -41 -42 -43 -44 -45 -46 -47 -48 -49 -50 -51 -52 -53 -54 -55 -56 -57 -58 -59 -60 -61 -62 -63 -64 -65 -66 -67 -68 -69 -70 -71 -72 -73 -74 -75 -76 -77 -78 -79 -80 -81 -82 -83 -84 -85 -86 -87 -88 -89 -90 -91  -  -  -  -  -  -1x -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  - 
import Client, { ClientError } from "./client";
- 
-/**
- * The file class represents a file in nextcloud.
- * It exposes file properties and content handling, commenting and tagging
- */
-export default abstract class FileSystemElement {
- 
-    /**
-     * The name of the file system element including the path
-     * The name is readonly
-     */
-    abstract get name(): string;
- 
-    /**
-     * The base name of the file system element (name without path)
-     * The base name is readonly
-     */
-    abstract get baseName(): string;
- 
-    /**
-     * The timestamp of the last file system element change
-     * readonly
-     */
-    abstract get lastmod(): Date;
- 
-    /**
-     * The unique id of the file system element.
-     */
-    abstract get id(): number;
- 
-    /**
-     * deletes a file system element
-     * @throws Error
-     */
-    public abstract async delete(): Promise<void>;
- 
-    /**
-     * moves or renames the current file system element to the new location
-     * target folder must exists
-     * @param targetFileName the name of the target file /f1/f2/myfile.txt
-     * @throws Error
-     */
-    public abstract async move(targetName: string): Promise<FileSystemElement>;
- 
-    /**
-     * @returns the url of the file sytsem element
-     * @throws Error
-     */
-    public abstract getUrl(): string;
- 
-    /**
-     * @returns the url of the file system element in the UI
-     * @throws Error
-     */
-    public abstract getUIUrl(): string;
- 
-    /**
-     * adds a tag name to the file system element
-     * @param tagName name of the tag
-     */
-    public abstract async addTag(tagName: string): Promise<void>;
- 
-    /**
-     * get tag names
-     * @returns array of tag names
-     */
-    public abstract async getTags(): Promise<string[]>;
- 
-    /**
-     * removes a tag of the file system element
-     * @param tagName the name of the tag
-     */
-    public abstract async removeTag(tagName: string): Promise<void>;
- 
-    /**
-     * add comment to file
-     * @param comment the comment
-     */
-    public abstract async addComment(comment: string): Promise<void>;
- 
-    /**
-     * get list of comments of file
-     * @param top number of comments to return
-     * @param skip the offset
-     * @returns array of comment strings
-     * @throws Exception
-     */
-    public abstract async getComments(top?: number, skip?: number): Promise<string[]>;
-}
- 
- -
-
- - - - - - - - - \ No newline at end of file diff --git a/docs/coverage/fileSystemFolder.ts.html b/docs/coverage/fileSystemFolder.ts.html deleted file mode 100644 index 61614ccb..00000000 --- a/docs/coverage/fileSystemFolder.ts.html +++ /dev/null @@ -1,218 +0,0 @@ - - - - - - Code coverage report for fileSystemFolder.ts - - - - - - - - - -
-
-

All files fileSystemFolder.ts

-
- -
- 100% - Statements - 20/20 -
- - -
- 100% - Branches - 2/2 -
- - -
- 100% - Functions - 7/7 -
- - -
- 100% - Lines - 18/18 -
- - -
-

- Press n or j to go to the next uncovered block, b, p or k for the previous block. -

-
-
-

-
1 -2 -3 -4 -5 -6 -7 -8 -9 -10 -11 -12 -13 -14 -15 -16 -17 -18 -19 -20 -21 -22 -23 -24 -25 -26 -27 -28 -29 -30 -31 -32 -33 -34 -35 -36 -37 -38 -39 -40 -41 -42 -43 -44 -45 -46 -47  -1x -  -1x -1x -1x -  -1x -1x -  -  -  -  -  -  -1x -  -  -10x -  -  -  -271x -  -  -  -10x -  -10x -270x -  -9x -  -  -  -  -89x -349x -349x -349x -  -349x -  -  -  -  - 
// tslint:disable-next-line:no-var-requires
-const debug = require("debug").debug("FileSystemFolder");
- 
-import util from "util";
-import fs from "fs";
-import path from "path";
- 
-const readdir = util.promisify(fs.readdir);
-const stat = util.promisify(fs.stat);
- 
-export interface IFileNameFormats {
-    absolute: string;
-    relative: string;
-}
- 
-export default class FileSystemFolder {
-    private name: string;
-    constructor(name: string) {
-        this.name = name;
-    }
- 
-    public getName(): IFileNameFormats {
-        return { relative: this.name, absolute: path.resolve(this.name) };
-    }
- 
-    public async getFileNames(): Promise<IFileNameFormats[]> {
-        const fileNames: IFileNameFormats[] = [];
- 
-        for (const absoluteFileName of await this.getFileNamesRecursively(this.name)) {
-            fileNames.push({ absolute: absoluteFileName, relative: absoluteFileName.replace(path.resolve(this.getName().absolute), "").replace(/\\/g, "/") })
-        }
-        return (fileNames);
-    };
- 
-    private async getFileNamesRecursively(name: string): Promise<string[]> {
- 
-        const subdirs: string[] = await readdir(name);
-        const files = await Promise.all(subdirs.map(async (subdir: string) => {
-            const res: string = path.resolve(name, subdir);
-            return (await stat(res)).isDirectory() ? this.getFileNamesRecursively(res) : res;
-        }));
-        return files.reduce((a: any, f: any) => a.concat(f), []);
-    }
- 
- 
-}
- 
- -
-
- - - - - - - - - \ No newline at end of file diff --git a/docs/coverage/folder.ts.html b/docs/coverage/folder.ts.html deleted file mode 100644 index f6614167..00000000 --- a/docs/coverage/folder.ts.html +++ /dev/null @@ -1,842 +0,0 @@ - - - - - - Code coverage report for folder.ts - - - - - - - - - -
-
-

All files folder.ts

-
- -
- 100% - Statements - 70/70 -
- - -
- 100% - Branches - 11/11 -
- - -
- 100% - Functions - 22/22 -
- - -
- 100% - Lines - 70/70 -
- - -
-

- Press n or j to go to the next uncovered block, b, p or k for the previous block. -

-
-
-

-
1 -2 -3 -4 -5 -6 -7 -8 -9 -10 -11 -12 -13 -14 -15 -16 -17 -18 -19 -20 -21 -22 -23 -24 -25 -26 -27 -28 -29 -30 -31 -32 -33 -34 -35 -36 -37 -38 -39 -40 -41 -42 -43 -44 -45 -46 -47 -48 -49 -50 -51 -52 -53 -54 -55 -56 -57 -58 -59 -60 -61 -62 -63 -64 -65 -66 -67 -68 -69 -70 -71 -72 -73 -74 -75 -76 -77 -78 -79 -80 -81 -82 -83 -84 -85 -86 -87 -88 -89 -90 -91 -92 -93 -94 -95 -96 -97 -98 -99 -100 -101 -102 -103 -104 -105 -106 -107 -108 -109 -110 -111 -112 -113 -114 -115 -116 -117 -118 -119 -120 -121 -122 -123 -124 -125 -126 -127 -128 -129 -130 -131 -132 -133 -134 -135 -136 -137 -138 -139 -140 -141 -142 -143 -144 -145 -146 -147 -148 -149 -150 -151 -152 -153 -154 -155 -156 -157 -158 -159 -160 -161 -162 -163 -164 -165 -166 -167 -168 -169 -170 -171 -172 -173 -174 -175 -176 -177 -178 -179 -180 -181 -182 -183 -184 -185 -186 -187 -188 -189 -190 -191 -192 -193 -194 -195 -196 -197 -198 -199 -200 -201 -202 -203 -204 -205 -206 -207 -208 -209 -210 -211 -212 -213 -214 -215 -216 -217 -218 -219 -220 -221 -222 -223 -224 -225 -226 -227 -228 -229 -230 -231 -232 -233 -234 -235 -236 -237 -238 -239 -240 -241 -242 -243 -244 -245 -246 -247 -248 -249 -250 -251 -252 -253 -254 -255  -1x -  -  -1x -  -  -  -  -  -  -  -  -  -  -1x -  -  -  -  -  -  -  -  -  -  -206x -206x -  -  -  -  -  -  -  -  -  -216x -215x -  -  -  -3x -2x -  -  -  -2x -1x -  -  -  -24x -22x -  -  -  -  -  -  -  -17x -17x -  -  -  -  -  -  -  -2x -2x -2x -1x -  -1x -  -  -  -  -  -  -18x -18x -  -  -  -  -  -  -  -1x -1x -  -  -  -  -  -  -  -  -  -4x -4x -  -  -  -  -  -  -  -  -  -  -21x -  -21x -21x -  -  -21x -162x -1x -  -  -  -  -  -20x -  -  -  -  -  -  -  -28x -28x -28x -  -  -  -  -  -  -  -  -  -1x -1x -1x -1x -1x -1x -  -  -  -  -  -  -  -1x -1x -  -  -  -  -  -  -  -1x -1x -  -  -  -  -  -  -  -  -2x -  -2x -2x -1x -  -1x -  -  -  -  -  -  -  -9x -  -  -  -  -  -  -  -2x -2x -2x -2x -5x -  -2x -  -  -  -  -  -  -  -2x -2x -2x -  -2x -2x -1x -  -  -  -  -  -  -  -  -4x -4x -  -  -  -  -  -  -  -  -  -  -2x -2x -  -  -  -323x -5x -  -  -  -  - 
// tslint:disable-next-line:no-var-requires
-const debug = require("debug").debug("Folder");
- 
-import Client from "./client";
-import ClientError from "./error";
-import File from "./file";
-import FileSystemElement from "./fileSystemElement";
- 
-export interface FolderGetFilesOptions {
-    /**
-     * callback function to filter files
-     */
-    filterFile?: (file: File) => File | null;
-}
- 
-export default class Folder implements FileSystemElement {
-    private client: Client;
-    private memento: {
-        baseName: string,
-        id: number,
-        deleted: boolean,
-        lastmod: Date,
-        name: string,
-    };
-    constructor(client: Client, name: string, baseName: string, lastmod: string, id: number = -1) {
- 
-        this.client = client;
-        this.memento = {
-            baseName,
-            deleted: false,
-            id,
-            lastmod: new Date(lastmod),
-            name,
-        };
-    }
- 
-    get name(): string {
-        this.assertExistence();
-        return this.memento.name;
-    }
- 
-    get baseName(): string {
-        this.assertExistence();
-        return this.memento.baseName;
-    }
- 
-    get lastmod(): Date {
-        this.assertExistence();
-        return this.memento.lastmod;
-    }
- 
-    get id(): number {
-        this.assertExistence();
-        return this.memento.id;
-    }
- 
-    /**
-     * @returns an array of subfolders
-     * @throws Error
-     */
-    public async getSubFolders(): Promise<Folder[]> {
-        this.assertExistence();
-        return await this.client.getSubFolders(this.name);
-    }
- 
-    /**
-     * returns true if the current folder has a subfolder with the given base name
-     * @param subFolderBaseName the base name of the subfolder like "products"
-     */
-    public async hasSubFolder(subFolderBaseName: string): Promise<boolean> {
-        this.assertExistence();
-        const subFolder: Folder | null = await this.client.getFolder(this.name + "/" + subFolderBaseName);
-        if (subFolder) {
-            return true;
-        }
-        return false;
-    }
- 
-    /**
-     * @returns all files of the folder
-     */
-    public async getFiles(options?: FolderGetFilesOptions): Promise<File[]> {
-        this.assertExistence();
-        return await this.client.getFiles(this.name, options);
-    }
- 
-    /**
-     * creates a subfolder
-     * @param subFolderBaseName  name of the subfolder basename
-     */
-    public async createSubFolder(subFolderBaseName: string): Promise<Folder> {
-        this.assertExistence();
-        return await this.client.createFolder(this.name + "/" + subFolderBaseName);
-    }
- 
-    /**
-     * get a file by basename
-     * @param fileBaseName the base name of the file
-     * @returns the file of null
-     * @throws Error
-     */
-    public async getFile(fileBaseName: string): Promise<File | null> {
-        this.assertExistence();
-        return this.client.getFile(this.name + "/" + fileBaseName);
-    }
- 
-    /**
-     * creates a file in the folder
-     * @param fileBaseName the base name of the file
-     * @param data the buffer or stream with file content
-     * @returns the new file or null
-     * @throws Error
-     */
-    public async createFile(fileBaseName: string, data: Buffer | NodeJS.ReadableStream): Promise<File> {
-        this.assertExistence();
-        // must not contain :/\*"<>?
-        debug("createFile fileBaseName = %s", fileBaseName);
-        const invalidChars: string[] = [":", "*", "/", "\\", "\"", "?", "<", ">"];
-        // debug("createFile invalidChars = %O", invalidChars);
- 
-        for (const invalidChar of invalidChars) {
-            if (fileBaseName.indexOf(invalidChar) !== -1) {
-                throw new ClientError("Filename contains an invalid character '" + invalidChar + "'",
-                    "ERR_INVALID_CHAR_IN_FILE_NAME",
-                    { fileBaseName });
-            }
-        }
- 
-        return this.client.createFile(this.name + "/" + fileBaseName.replace(/^\/+/g, ""), data);
-    }
- 
-    /**
-     * deletes the folder and the contained files
-     * @throws Error
-     */
-    public async delete(): Promise<void> {
-        debug("delete");
-        this.memento.deleted = true;
-        return await this.client.deleteFolder(this.memento.name);
-    }
- 
-    /**
-     * renames or moves the current folder to the new location
-     * target folder must exists
-     * @param targetFolderName the name of the target folder /f1/f2/target
-     * @throws Error
-     */
-    public async move(targetFolderName: string): Promise<Folder> {
-        this.assertExistence();
-        const folder: Folder = await this.client.moveFolder(this.name, targetFolderName);
-        this.memento.name = folder.name;
-        this.memento.baseName = folder.baseName;
-        this.memento.lastmod = folder.lastmod;
-        return this;
-    }
- 
-    /**
-     * @returns the url of the folder
-     * @throws Error
-     */
-    public getUrl(): string {
-        this.assertExistence();
-        return this.client.getLink(this.name);
-    }
- 
-    /**
-     * @returns the url of the folder in the UI
-     * @throws Error
-     */
-    public getUIUrl(): string {
-        this.assertExistence();
-        return this.client.getUILink(this.id);
-    }
- 
-    /**
-     * @returns true if the folder contains a file with the given basename
-     * @param fileBaseName file basename
-     * @throws Error
-     */
-    public async containsFile(fileBaseName: string): Promise<boolean> {
-        this.assertExistence();
-        let file: File | null;
-        file = await this.getFile(fileBaseName);
-        if (file) {
-            return true;
-        }
-        return false;
-    }
- 
-    /**
-     * adds a tag name to the folder
-     * @param tagName name of the tag
-     */
-    public async addTag(tagName: string): Promise<void> {
-        return await this.client.addTagToFile(this.id, tagName);
-    }
- 
-    /**
-     * get tag names
-     * @returns array of tag names
-     */
-    public async getTags(): Promise<string[]> {
-        this.assertExistence();
-        const map: Map<string, number> = await this.client.getTagsOfFile(this.id);
-        const tagNames: string[] = [];
-        for (const tagName of map) {
-            tagNames.push(tagName[0]);
-        }
-        return tagNames;
-    }
- 
-    /**
-     * removes a tag of the file
-     * @param tagName the name of the tag
-     */
-    public async removeTag(tagName: string): Promise<void> {
-        this.assertExistence();
-        const map: Map<string, number> = await this.client.getTagsOfFile(this.id);
-        const tagNames: string[] = [];
- 
-        const tagId: number | undefined = map.get(tagName);
-        if (tagId) {
-            await this.client.removeTagOfFile(this.id, tagId);
-        }
-    }
- 
-    /**
-     * add comment to folder
-     * @param comment the comment
-     */
-    public async addComment(comment: string): Promise<void> {
-        this.assertExistence();
-        return await this.client.addCommentToFile(this.id, comment);
-    }
- 
-    /**
-     * get list of comments of folder
-     * @param top number of comments to return
-     * @param skip the offset
-     * @returns array of comment strings
-     * @throws Exception
-     */
-    public async getComments(top?: number, skip?: number): Promise<string[]> {
-        this.assertExistence();
-        return await this.client.getFileComments(this.id, top, skip);
-    }
- 
-    private assertExistence(): void {
-        if (this.memento.deleted) {
-            throw new ClientError("Folder does not exist", "ERR_FOLDER_NOT_EXISTING");
-        }
-    }
- 
-}
- 
- -
-
- - - - - - - - - \ No newline at end of file diff --git a/docs/coverage/getFilesRecursivelyCommand.ts.html b/docs/coverage/getFilesRecursivelyCommand.ts.html deleted file mode 100644 index bbafb6f8..00000000 --- a/docs/coverage/getFilesRecursivelyCommand.ts.html +++ /dev/null @@ -1,368 +0,0 @@ - - - - - - Code coverage report for getFilesRecursivelyCommand.ts - - - - - - - - - -
-
-

All files getFilesRecursivelyCommand.ts

-
- -
- 100% - Statements - 32/32 -
- - -
- 100% - Branches - 4/4 -
- - -
- 100% - Functions - 4/4 -
- - -
- 100% - Lines - 32/32 -
- - -
-

- Press n or j to go to the next uncovered block, b, p or k for the previous block. -

-
-
-

-
1 -2 -3 -4 -5 -6 -7 -8 -9 -10 -11 -12 -13 -14 -15 -16 -17 -18 -19 -20 -21 -22 -23 -24 -25 -26 -27 -28 -29 -30 -31 -32 -33 -34 -35 -36 -37 -38 -39 -40 -41 -42 -43 -44 -45 -46 -47 -48 -49 -50 -51 -52 -53 -54 -55 -56 -57 -58 -59 -60 -61 -62 -63 -64 -65 -66 -67 -68 -69 -70 -71 -72 -73 -74 -75 -76 -77 -78 -79 -80 -81 -82 -83 -84 -85 -86 -87 -88 -89 -90 -91 -92 -93 -94 -95 -96 -97  -1x -  -  -1x -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -1x -  -  -  -  -  -  -  -  -  -  -3x -3x -3x -3x -  -  -  -  -  -  -  -  -3x -3x -3x -3x -3x -  -2x -  -1x -1x -  -  -3x -3x -1x -  -2x -  -3x -3x -  -  -  -  -2x -  -  -  -  -  -  -  -  -  -  -  -17x -17x -16x -17x -  -  -16x -16x -14x -  -16x -  -14x -  -16x -  -  - 
// tslint:disable-next-line:no-var-requires
-const debug = require("debug").debug("GetFilesRecursivelyCommand");
- 
-import Client, { File, Folder, FolderGetFilesOptions } from "./client";
-import Command, { CommandStatus } from "./command";
- 
-export interface GetFilesRecursivelyCommandOptions {
-    /**
-     * the source nextcloud folder to start listing the files
-     */
-    sourceFolder: Folder;
-    /**
-     * function to filter files
-     */
-    filterFile?: (file: File) => File | null;
-}
- 
-/**
- * Command to get all files of a nextcloud folder recursively
- */
-export default class GetFilesRecursivelyCommand extends Command {
-    private sourceFolder: Folder;
-    private filterFile?: (file: File) => File | null;
-    private files: File[];
- 
-    /**
-     * @param {Client} client the client
-     * @param {SourceTargetFileNames[]} files the files to be uploaded
-     * @param {(file: File) => void} processAfterUpload callback function to process the uploaded file
-     */
-    constructor(client: Client, options: GetFilesRecursivelyCommandOptions) {
-        super(client);
-        this.sourceFolder = options.sourceFolder;
-        this.filterFile = options.filterFile;
-        this.files = [];
-    }
- 
-    /**
-     * execute the command
-     * @async
-     * @returns {Promise<void>}
-     */
-    protected async onExecute(): Promise<void> {
-        this.status = CommandStatus.running;
-        const startTime = new Date();
-        try {
-            this.percentCompleted = 0;
-            await this.processFolder(this.sourceFolder, 100);
-            // console.log("file count", this.files.length);
-            this.resultMetaData.messages.push(`${this.files.length} files found`);
-        } catch (e) {
-            debug(e.message);
-            this.resultMetaData.errors.push(e.message);
-        }
- 
-        this.percentCompleted = 100;
-        if (this.resultMetaData.errors.length > 0) {
-            this.status = CommandStatus.failed;
-        } else {
-            this.status = CommandStatus.success;
-        }
-        this.resultMetaData.timeElapsed = new Date().getTime() - startTime.getTime();
-        return;
-    };
- 
- 
-    public getFiles(): File[] {
-        return this.files;
-    }
- 
-    /**
-     * adds files of folder and processes subordinated folders
-     * @param {Folder} folder the folder to process
-     * @param {number} percentagethe percentage that is finished, when the function returns
-     */
-    private async processFolder(folder: Folder, percentage: number): Promise<void> {
-        // tslint:disable-next-line:no-console
-        // console.log(folder.name);
- 
-        const options: FolderGetFilesOptions = { filterFile: this.filterFile }
-        const folderFiles: File[] = await folder.getFiles(options);
-        for (const fi of folderFiles) {
-            this.files.push(fi);
-        }
- 
-        const subFolders: Folder[] = await folder.getSubFolders();
-        if (subFolders.length === 0) {
-            this.percentCompleted += percentage;
-        }
-        for (const subFolder of subFolders) {
-            // console.log("folder", subFolder.name);
-            await this.processFolder(subFolder, percentage / subFolders.length);
-        }
-        return;
-    }
-}
- 
- -
-
- - - - - - - - - \ No newline at end of file diff --git a/docs/coverage/httpClient.ts.html b/docs/coverage/httpClient.ts.html deleted file mode 100644 index f3311a09..00000000 --- a/docs/coverage/httpClient.ts.html +++ /dev/null @@ -1,539 +0,0 @@ - - - - - - Code coverage report for httpClient.ts - - - - - - - - - -
-
-

All files httpClient.ts

-
- -
- 95.31% - Statements - 61/64 -
- - -
- 89.29% - Branches - 25/28 -
- - -
- 88.89% - Functions - 8/9 -
- - -
- 95.08% - Lines - 58/61 -
- - -
-

- Press n or j to go to the next uncovered block, b, p or k for the previous block. -

-
-
-

-
1 -2 -3 -4 -5 -6 -7 -8 -9 -10 -11 -12 -13 -14 -15 -16 -17 -18 -19 -20 -21 -22 -23 -24 -25 -26 -27 -28 -29 -30 -31 -32 -33 -34 -35 -36 -37 -38 -39 -40 -41 -42 -43 -44 -45 -46 -47 -48 -49 -50 -51 -52 -53 -54 -55 -56 -57 -58 -59 -60 -61 -62 -63 -64 -65 -66 -67 -68 -69 -70 -71 -72 -73 -74 -75 -76 -77 -78 -79 -80 -81 -82 -83 -84 -85 -86 -87 -88 -89 -90 -91 -92 -93 -94 -95 -96 -97 -98 -99 -100 -101 -102 -103 -104 -105 -106 -107 -108 -109 -110 -111 -112 -113 -114 -115 -116 -117 -118 -119 -120 -121 -122 -123 -124 -125 -126 -127 -128 -129 -130 -131 -132 -133 -134 -135 -136 -137 -138 -139 -140 -141 -142 -143 -144 -145 -146 -147 -148 -149 -150 -151 -152 -153 -154  -1x -  -1x -  -1x -1x -  -  -  -  -1x -1x -1x -  -1x -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -1x -  -  -  -  -  -  -9x -9x -9x -9x -9x -  -  -  -6x -5x -  -  -6x -1x -  -  -6x -1x -  -  -6x -3x -  -6x -  -  -6x -2x -2x -  -  -  -  -  -2x -  -2x -1x -  -  -  -6x -6x -  -6x -  -3x -1x -  -  -2x -2x -  -  -1x -  -  -  -1x -1x -  -  -1x -1x -  -  -1x -1x -  -  -  -1x -  -  -  -  -1x -  -  -  -  -1x -  -  -  -  -1x -1x -  -  -3x -  -3x -1x -1x -1x -1x -1x -1x -1x -  -  -  -  -  -  -  -2x -  -  -  - 
// tslint:disable-next-line:no-var-requires
-const HttpProxyAgent = require('http-proxy-agent');
- 
-import debugFactory from "debug";
-import { HttpProxyAgentOptions } from "http-proxy-agent";
-import fetch from "node-fetch";
-import {
-    Headers,
-    RequestInit,
-    Response,
-} from "node-fetch";
-import ClientError from "./error";
-import RequestResponseLog from "./requestResponseLog";
-import RequestResponseLogEntry, { RequestLogEntry, ResponseLogEntry } from "./requestResponseLogEntry";
- 
-const debug = debugFactory("HttpClient");
- 
-export interface IRequestContext {
-    "description"?: string;
-}
- 
-export interface IProxy {
-    "host": string;
-    "port": string;
-    "protocol": string;
-    "secureProxy": boolean;
-    "proxyAuthorizationHeader"?: string;
-}
- 
-export interface IHttpClientOptions {
-    "authorizationHeader"?: string;
-    "logRequestResponse"?: boolean;
-    "proxy"?: IProxy;
-    "origin"?: string;
-}
-export class HttpClient {
-    private proxy?: IProxy;
-    private authorizationHeader?: string;
-    private logRequestResponse: boolean;
-    private origin: string;
- 
-    public constructor(options: IHttpClientOptions) {
-        debug("constructor");
-        this.authorizationHeader = options.authorizationHeader;
-        this.proxy = options.proxy;
-        this.logRequestResponse = options.logRequestResponse || false;
-        this.origin = options.origin || "";
-    }
-    public async getHttpResponse(url: string, requestInit: RequestInit, expectedHttpStatusCode: number[], context: IRequestContext): Promise<Response> {
- 
-        if (!requestInit.headers) {
-            requestInit.headers = new Headers();
-        }
- 
-        if (!requestInit.method) {
-            requestInit.method = "UNDEFINED";
-        }
- 
-        if (!context.description) {
-            context.description = "";
-        }
- 
-        if (this.authorizationHeader) {
-            (requestInit.headers as Headers).append("Authorization", this.authorizationHeader);
-        }
-        (requestInit.headers as Headers).append("User-Agent", "nextcloud-node-client");
- 
-        // set the proxy
-        if (this.proxy) {
-            debug("proxy agent used");
-            const options: HttpProxyAgentOptions = {
-                host: this.proxy.host,
-                port: this.proxy.port,
-                protocol: this.proxy.protocol,
-            };
- 
-            requestInit.agent = new HttpProxyAgent(options);
- 
-            if (this.proxy.proxyAuthorizationHeader) {
-                (requestInit.headers as Headers).append("Proxy-Authorization", this.proxy.proxyAuthorizationHeader);
-            }
-        }
- 
-        debug("getHttpResponse request header %O", requestInit.headers);
-        debug("getHttpResponse url:%s, %O", url, requestInit);
- 
-        const response: Response = await fetch(url, requestInit);
- 
-        if (this.logRequestResponse) {
-            const responseText = await response.text();
- 
-            // overwrite response functions as the body uses a stearm object...
-            response.text = async () => {
-                return responseText;
-            };
- 
-            response.body.pipe = (destination: NodeJS.WritableStream, options?: { end?: boolean; }): any => {
-                destination.write(responseText);
-            };
- 
-            response.json = async () => {
-                return JSON.parse(responseText);
-            };
- 
-            response.buffer = async () => {
-                return Buffer.from(responseText);
-            };
- 
-            let body: string = `<Body is ${typeof requestInit.body}>`;
-            Iif (requestInit.body && requestInit.body instanceof Buffer) {
-                body = `<Body is Buffer ${requestInit.body.length}>`;
-            }
- 
-            Iif (typeof requestInit.body === "string") {
-                body = requestInit.body;
-            }
- 
-            const reqLogEntry: RequestLogEntry =
-                new RequestLogEntry(url.replace(this.origin, ""),
-                    requestInit.method, context.description,
-                    body);
- 
-            const resLogEntry: ResponseLogEntry =
-                new ResponseLogEntry(response.status,
-                    await response.text(),
-                    response.headers.get("Content-Type") as string,
-                    response.headers.get("Content-Location") || "");
- 
-            const rrLog: RequestResponseLog = RequestResponseLog.getInstance();
-            await rrLog.addEntry(new RequestResponseLogEntry(reqLogEntry, resLogEntry));
-        }
- 
-        const responseContentType: string | null = response.headers.get("content-type");
- 
-        if (expectedHttpStatusCode.indexOf(response.status) === -1) {
-            debug("getHttpResponse unexpected status response %s", response.status + " " + response.statusText);
-            debug("getHttpResponse description %s", context.description);
-            debug("getHttpResponse expected %s", expectedHttpStatusCode.join(","));
-            debug("getHttpResponse headers %s", JSON.stringify(response.headers, null, 4));
-            debug("getHttpResponse request body %s", requestInit.body);
-            debug("getHttpResponse text %s", await response.text());
-            throw new ClientError(`HTTP response status ${response.status} not expected. Expected status: ${expectedHttpStatusCode.join(",")} - status text: ${response.statusText}`,
-                "ERR_UNEXPECTED_HTTP_STATUS",
-                {
-                    expectedHttpStatusCodes: expectedHttpStatusCode,
-                    responseStatus: response.status,
-                    responseStatusText: response.statusText,
-                });
-        }
-        return response;
-    }
- 
-}
- 
- -
-
- - - - - - - - - \ No newline at end of file diff --git a/docs/coverage/index.html b/docs/coverage/index.html deleted file mode 100644 index a61a6d8f..00000000 --- a/docs/coverage/index.html +++ /dev/null @@ -1,126 +0,0 @@ - - - - - - Code coverage report for All files - - - - - - - - - -
-
-

All files

-
- -
- 93.95% - Statements - 1786/1901 -
- - -
- 89.91% - Branches - 570/634 -
- - -
- 92.25% - Functions - 262/284 -
- - -
- 93.9% - Lines - 1770/1885 -
- - -
-

- Press n or j to go to the next uncovered block, b, p or k for the previous block. -

-
-
-
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
FileStatementsBranchesFunctionsLines
src -
-
94.16%1611/171189.93%545/60691.83%236/25794.12%1602/1702
src/command -
-
92.11%175/19089.29%25/2896.3%26/2791.8%168/183
-
-
-
- - - - - - - - - \ No newline at end of file diff --git a/docs/coverage/lcov-report/base.css b/docs/coverage/lcov-report/base.css deleted file mode 100644 index f418035b..00000000 --- a/docs/coverage/lcov-report/base.css +++ /dev/null @@ -1,224 +0,0 @@ -body, html { - margin:0; padding: 0; - height: 100%; -} -body { - font-family: Helvetica Neue, Helvetica, Arial; - font-size: 14px; - color:#333; -} -.small { font-size: 12px; } -*, *:after, *:before { - -webkit-box-sizing:border-box; - -moz-box-sizing:border-box; - box-sizing:border-box; - } -h1 { font-size: 20px; margin: 0;} -h2 { font-size: 14px; } -pre { - font: 12px/1.4 Consolas, "Liberation Mono", Menlo, Courier, monospace; - margin: 0; - padding: 0; - -moz-tab-size: 2; - -o-tab-size: 2; - tab-size: 2; -} -a { color:#0074D9; text-decoration:none; } -a:hover { text-decoration:underline; } -.strong { font-weight: bold; } -.space-top1 { padding: 10px 0 0 0; } -.pad2y { padding: 20px 0; } -.pad1y { padding: 10px 0; } -.pad2x { padding: 0 20px; } -.pad2 { padding: 20px; } -.pad1 { padding: 10px; } -.space-left2 { padding-left:55px; } -.space-right2 { padding-right:20px; } -.center { text-align:center; } -.clearfix { display:block; } -.clearfix:after { - content:''; - display:block; - height:0; - clear:both; - visibility:hidden; - } -.fl { float: left; } -@media only screen and (max-width:640px) { - .col3 { width:100%; max-width:100%; } - .hide-mobile { display:none!important; } -} - -.quiet { - color: #7f7f7f; - color: rgba(0,0,0,0.5); -} -.quiet a { opacity: 0.7; } - -.fraction { - font-family: Consolas, 'Liberation Mono', Menlo, Courier, monospace; - font-size: 10px; - color: #555; - background: #E8E8E8; - padding: 4px 5px; - border-radius: 3px; - vertical-align: middle; -} - -div.path a:link, div.path a:visited { color: #333; } -table.coverage { - border-collapse: collapse; - margin: 10px 0 0 0; - padding: 0; -} - -table.coverage td { - margin: 0; - padding: 0; - vertical-align: top; -} -table.coverage td.line-count { - text-align: right; - padding: 0 5px 0 20px; -} -table.coverage td.line-coverage { - text-align: right; - padding-right: 10px; - min-width:20px; -} - -table.coverage td span.cline-any { - display: inline-block; - padding: 0 5px; - width: 100%; -} -.missing-if-branch { - display: inline-block; - margin-right: 5px; - border-radius: 3px; - position: relative; - padding: 0 4px; - background: #333; - color: yellow; -} - -.skip-if-branch { - display: none; - margin-right: 10px; - position: relative; - padding: 0 4px; - background: #ccc; - color: white; -} -.missing-if-branch .typ, .skip-if-branch .typ { - color: inherit !important; -} -.coverage-summary { - border-collapse: collapse; - width: 100%; -} -.coverage-summary tr { border-bottom: 1px solid #bbb; } -.keyline-all { border: 1px solid #ddd; } -.coverage-summary td, .coverage-summary th { padding: 10px; } -.coverage-summary tbody { border: 1px solid #bbb; } -.coverage-summary td { border-right: 1px solid #bbb; } -.coverage-summary td:last-child { border-right: none; } -.coverage-summary th { - text-align: left; - font-weight: normal; - white-space: nowrap; -} -.coverage-summary th.file { border-right: none !important; } -.coverage-summary th.pct { } -.coverage-summary th.pic, -.coverage-summary th.abs, -.coverage-summary td.pct, -.coverage-summary td.abs { text-align: right; } -.coverage-summary td.file { white-space: nowrap; } -.coverage-summary td.pic { min-width: 120px !important; } -.coverage-summary tfoot td { } - -.coverage-summary .sorter { - height: 10px; - width: 7px; - display: inline-block; - margin-left: 0.5em; - background: url(sort-arrow-sprite.png) no-repeat scroll 0 0 transparent; -} -.coverage-summary .sorted .sorter { - background-position: 0 -20px; -} -.coverage-summary .sorted-desc .sorter { - background-position: 0 -10px; -} -.status-line { height: 10px; } -/* yellow */ -.cbranch-no { background: yellow !important; color: #111; } -/* dark red */ -.red.solid, .status-line.low, .low .cover-fill { background:#C21F39 } -.low .chart { border:1px solid #C21F39 } -.highlighted, -.highlighted .cstat-no, .highlighted .fstat-no, .highlighted .cbranch-no{ - background: #C21F39 !important; -} -/* medium red */ -.cstat-no, .fstat-no, .cbranch-no, .cbranch-no { background:#F6C6CE } -/* light red */ -.low, .cline-no { background:#FCE1E5 } -/* light green */ -.high, .cline-yes { background:rgb(230,245,208) } -/* medium green */ -.cstat-yes { background:rgb(161,215,106) } -/* dark green */ -.status-line.high, .high .cover-fill { background:rgb(77,146,33) } -.high .chart { border:1px solid rgb(77,146,33) } -/* dark yellow (gold) */ -.status-line.medium, .medium .cover-fill { background: #f9cd0b; } -.medium .chart { border:1px solid #f9cd0b; } -/* light yellow */ -.medium { background: #fff4c2; } - -.cstat-skip { background: #ddd; color: #111; } -.fstat-skip { background: #ddd; color: #111 !important; } -.cbranch-skip { background: #ddd !important; color: #111; } - -span.cline-neutral { background: #eaeaea; } - -.coverage-summary td.empty { - opacity: .5; - padding-top: 4px; - padding-bottom: 4px; - line-height: 1; - color: #888; -} - -.cover-fill, .cover-empty { - display:inline-block; - height: 12px; -} -.chart { - line-height: 0; -} -.cover-empty { - background: white; -} -.cover-full { - border-right: none !important; -} -pre.prettyprint { - border: none !important; - padding: 0 !important; - margin: 0 !important; -} -.com { color: #999 !important; } -.ignore-none { color: #999; font-weight: normal; } - -.wrapper { - min-height: 100%; - height: auto !important; - height: 100%; - margin: 0 auto -48px; -} -.footer, .push { - height: 48px; -} diff --git a/docs/coverage/lcov-report/block-navigation.js b/docs/coverage/lcov-report/block-navigation.js deleted file mode 100644 index c7ff5a5c..00000000 --- a/docs/coverage/lcov-report/block-navigation.js +++ /dev/null @@ -1,79 +0,0 @@ -/* eslint-disable */ -var jumpToCode = (function init() { - // Classes of code we would like to highlight in the file view - var missingCoverageClasses = ['.cbranch-no', '.cstat-no', '.fstat-no']; - - // Elements to highlight in the file listing view - var fileListingElements = ['td.pct.low']; - - // We don't want to select elements that are direct descendants of another match - var notSelector = ':not(' + missingCoverageClasses.join('):not(') + ') > '; // becomes `:not(a):not(b) > ` - - // Selecter that finds elements on the page to which we can jump - var selector = - fileListingElements.join(', ') + - ', ' + - notSelector + - missingCoverageClasses.join(', ' + notSelector); // becomes `:not(a):not(b) > a, :not(a):not(b) > b` - - // The NodeList of matching elements - var missingCoverageElements = document.querySelectorAll(selector); - - var currentIndex; - - function toggleClass(index) { - missingCoverageElements - .item(currentIndex) - .classList.remove('highlighted'); - missingCoverageElements.item(index).classList.add('highlighted'); - } - - function makeCurrent(index) { - toggleClass(index); - currentIndex = index; - missingCoverageElements.item(index).scrollIntoView({ - behavior: 'smooth', - block: 'center', - inline: 'center' - }); - } - - function goToPrevious() { - var nextIndex = 0; - if (typeof currentIndex !== 'number' || currentIndex === 0) { - nextIndex = missingCoverageElements.length - 1; - } else if (missingCoverageElements.length > 1) { - nextIndex = currentIndex - 1; - } - - makeCurrent(nextIndex); - } - - function goToNext() { - var nextIndex = 0; - - if ( - typeof currentIndex === 'number' && - currentIndex < missingCoverageElements.length - 1 - ) { - nextIndex = currentIndex + 1; - } - - makeCurrent(nextIndex); - } - - return function jump(event) { - switch (event.which) { - case 78: // n - case 74: // j - goToNext(); - break; - case 66: // b - case 75: // k - case 80: // p - goToPrevious(); - break; - } - }; -})(); -window.addEventListener('keydown', jumpToCode); diff --git a/docs/coverage/lcov-report/client.ts.html b/docs/coverage/lcov-report/client.ts.html deleted file mode 100644 index af0ec936..00000000 --- a/docs/coverage/lcov-report/client.ts.html +++ /dev/null @@ -1,9659 +0,0 @@ - - - - - - Code coverage report for client.ts - - - - - - - - - -
-
-

All files client.ts

-
- -
- 95.87% - Statements - 1022/1066 -
- - -
- 95.02% - Branches - 382/402 -
- - -
- 93.9% - Functions - 77/82 -
- - -
- 95.86% - Lines - 1018/1062 -
- - -
-

- Press n or j to go to the next uncovered block, b, p or k for the previous block. -

-
-
-

-
1 -2 -3 -4 -5 -6 -7 -8 -9 -10 -11 -12 -13 -14 -15 -16 -17 -18 -19 -20 -21 -22 -23 -24 -25 -26 -27 -28 -29 -30 -31 -32 -33 -34 -35 -36 -37 -38 -39 -40 -41 -42 -43 -44 -45 -46 -47 -48 -49 -50 -51 -52 -53 -54 -55 -56 -57 -58 -59 -60 -61 -62 -63 -64 -65 -66 -67 -68 -69 -70 -71 -72 -73 -74 -75 -76 -77 -78 -79 -80 -81 -82 -83 -84 -85 -86 -87 -88 -89 -90 -91 -92 -93 -94 -95 -96 -97 -98 -99 -100 -101 -102 -103 -104 -105 -106 -107 -108 -109 -110 -111 -112 -113 -114 -115 -116 -117 -118 -119 -120 -121 -122 -123 -124 -125 -126 -127 -128 -129 -130 -131 -132 -133 -134 -135 -136 -137 -138 -139 -140 -141 -142 -143 -144 -145 -146 -147 -148 -149 -150 -151 -152 -153 -154 -155 -156 -157 -158 -159 -160 -161 -162 -163 -164 -165 -166 -167 -168 -169 -170 -171 -172 -173 -174 -175 -176 -177 -178 -179 -180 -181 -182 -183 -184 -185 -186 -187 -188 -189 -190 -191 -192 -193 -194 -195 -196 -197 -198 -199 -200 -201 -202 -203 -204 -205 -206 -207 -208 -209 -210 -211 -212 -213 -214 -215 -216 -217 -218 -219 -220 -221 -222 -223 -224 -225 -226 -227 -228 -229 -230 -231 -232 -233 -234 -235 -236 -237 -238 -239 -240 -241 -242 -243 -244 -245 -246 -247 -248 -249 -250 -251 -252 -253 -254 -255 -256 -257 -258 -259 -260 -261 -262 -263 -264 -265 -266 -267 -268 -269 -270 -271 -272 -273 -274 -275 -276 -277 -278 -279 -280 -281 -282 -283 -284 -285 -286 -287 -288 -289 -290 -291 -292 -293 -294 -295 -296 -297 -298 -299 -300 -301 -302 -303 -304 -305 -306 -307 -308 -309 -310 -311 -312 -313 -314 -315 -316 -317 -318 -319 -320 -321 -322 -323 -324 -325 -326 -327 -328 -329 -330 -331 -332 -333 -334 -335 -336 -337 -338 -339 -340 -341 -342 -343 -344 -345 -346 -347 -348 -349 -350 -351 -352 -353 -354 -355 -356 -357 -358 -359 -360 -361 -362 -363 -364 -365 -366 -367 -368 -369 -370 -371 -372 -373 -374 -375 -376 -377 -378 -379 -380 -381 -382 -383 -384 -385 -386 -387 -388 -389 -390 -391 -392 -393 -394 -395 -396 -397 -398 -399 -400 -401 -402 -403 -404 -405 -406 -407 -408 -409 -410 -411 -412 -413 -414 -415 -416 -417 -418 -419 -420 -421 -422 -423 -424 -425 -426 -427 -428 -429 -430 -431 -432 -433 -434 -435 -436 -437 -438 -439 -440 -441 -442 -443 -444 -445 -446 -447 -448 -449 -450 -451 -452 -453 -454 -455 -456 -457 -458 -459 -460 -461 -462 -463 -464 -465 -466 -467 -468 -469 -470 -471 -472 -473 -474 -475 -476 -477 -478 -479 -480 -481 -482 -483 -484 -485 -486 -487 -488 -489 -490 -491 -492 -493 -494 -495 -496 -497 -498 -499 -500 -501 -502 -503 -504 -505 -506 -507 -508 -509 -510 -511 -512 -513 -514 -515 -516 -517 -518 -519 -520 -521 -522 -523 -524 -525 -526 -527 -528 -529 -530 -531 -532 -533 -534 -535 -536 -537 -538 -539 -540 -541 -542 -543 -544 -545 -546 -547 -548 -549 -550 -551 -552 -553 -554 -555 -556 -557 -558 -559 -560 -561 -562 -563 -564 -565 -566 -567 -568 -569 -570 -571 -572 -573 -574 -575 -576 -577 -578 -579 -580 -581 -582 -583 -584 -585 -586 -587 -588 -589 -590 -591 -592 -593 -594 -595 -596 -597 -598 -599 -600 -601 -602 -603 -604 -605 -606 -607 -608 -609 -610 -611 -612 -613 -614 -615 -616 -617 -618 -619 -620 -621 -622 -623 -624 -625 -626 -627 -628 -629 -630 -631 -632 -633 -634 -635 -636 -637 -638 -639 -640 -641 -642 -643 -644 -645 -646 -647 -648 -649 -650 -651 -652 -653 -654 -655 -656 -657 -658 -659 -660 -661 -662 -663 -664 -665 -666 -667 -668 -669 -670 -671 -672 -673 -674 -675 -676 -677 -678 -679 -680 -681 -682 -683 -684 -685 -686 -687 -688 -689 -690 -691 -692 -693 -694 -695 -696 -697 -698 -699 -700 -701 -702 -703 -704 -705 -706 -707 -708 -709 -710 -711 -712 -713 -714 -715 -716 -717 -718 -719 -720 -721 -722 -723 -724 -725 -726 -727 -728 -729 -730 -731 -732 -733 -734 -735 -736 -737 -738 -739 -740 -741 -742 -743 -744 -745 -746 -747 -748 -749 -750 -751 -752 -753 -754 -755 -756 -757 -758 -759 -760 -761 -762 -763 -764 -765 -766 -767 -768 -769 -770 -771 -772 -773 -774 -775 -776 -777 -778 -779 -780 -781 -782 -783 -784 -785 -786 -787 -788 -789 -790 -791 -792 -793 -794 -795 -796 -797 -798 -799 -800 -801 -802 -803 -804 -805 -806 -807 -808 -809 -810 -811 -812 -813 -814 -815 -816 -817 -818 -819 -820 -821 -822 -823 -824 -825 -826 -827 -828 -829 -830 -831 -832 -833 -834 -835 -836 -837 -838 -839 -840 -841 -842 -843 -844 -845 -846 -847 -848 -849 -850 -851 -852 -853 -854 -855 -856 -857 -858 -859 -860 -861 -862 -863 -864 -865 -866 -867 -868 -869 -870 -871 -872 -873 -874 -875 -876 -877 -878 -879 -880 -881 -882 -883 -884 -885 -886 -887 -888 -889 -890 -891 -892 -893 -894 -895 -896 -897 -898 -899 -900 -901 -902 -903 -904 -905 -906 -907 -908 -909 -910 -911 -912 -913 -914 -915 -916 -917 -918 -919 -920 -921 -922 -923 -924 -925 -926 -927 -928 -929 -930 -931 -932 -933 -934 -935 -936 -937 -938 -939 -940 -941 -942 -943 -944 -945 -946 -947 -948 -949 -950 -951 -952 -953 -954 -955 -956 -957 -958 -959 -960 -961 -962 -963 -964 -965 -966 -967 -968 -969 -970 -971 -972 -973 -974 -975 -976 -977 -978 -979 -980 -981 -982 -983 -984 -985 -986 -987 -988 -989 -990 -991 -992 -993 -994 -995 -996 -997 -998 -999 -1000 -1001 -1002 -1003 -1004 -1005 -1006 -1007 -1008 -1009 -1010 -1011 -1012 -1013 -1014 -1015 -1016 -1017 -1018 -1019 -1020 -1021 -1022 -1023 -1024 -1025 -1026 -1027 -1028 -1029 -1030 -1031 -1032 -1033 -1034 -1035 -1036 -1037 -1038 -1039 -1040 -1041 -1042 -1043 -1044 -1045 -1046 -1047 -1048 -1049 -1050 -1051 -1052 -1053 -1054 -1055 -1056 -1057 -1058 -1059 -1060 -1061 -1062 -1063 -1064 -1065 -1066 -1067 -1068 -1069 -1070 -1071 -1072 -1073 -1074 -1075 -1076 -1077 -1078 -1079 -1080 -1081 -1082 -1083 -1084 -1085 -1086 -1087 -1088 -1089 -1090 -1091 -1092 -1093 -1094 -1095 -1096 -1097 -1098 -1099 -1100 -1101 -1102 -1103 -1104 -1105 -1106 -1107 -1108 -1109 -1110 -1111 -1112 -1113 -1114 -1115 -1116 -1117 -1118 -1119 -1120 -1121 -1122 -1123 -1124 -1125 -1126 -1127 -1128 -1129 -1130 -1131 -1132 -1133 -1134 -1135 -1136 -1137 -1138 -1139 -1140 -1141 -1142 -1143 -1144 -1145 -1146 -1147 -1148 -1149 -1150 -1151 -1152 -1153 -1154 -1155 -1156 -1157 -1158 -1159 -1160 -1161 -1162 -1163 -1164 -1165 -1166 -1167 -1168 -1169 -1170 -1171 -1172 -1173 -1174 -1175 -1176 -1177 -1178 -1179 -1180 -1181 -1182 -1183 -1184 -1185 -1186 -1187 -1188 -1189 -1190 -1191 -1192 -1193 -1194 -1195 -1196 -1197 -1198 -1199 -1200 -1201 -1202 -1203 -1204 -1205 -1206 -1207 -1208 -1209 -1210 -1211 -1212 -1213 -1214 -1215 -1216 -1217 -1218 -1219 -1220 -1221 -1222 -1223 -1224 -1225 -1226 -1227 -1228 -1229 -1230 -1231 -1232 -1233 -1234 -1235 -1236 -1237 -1238 -1239 -1240 -1241 -1242 -1243 -1244 -1245 -1246 -1247 -1248 -1249 -1250 -1251 -1252 -1253 -1254 -1255 -1256 -1257 -1258 -1259 -1260 -1261 -1262 -1263 -1264 -1265 -1266 -1267 -1268 -1269 -1270 -1271 -1272 -1273 -1274 -1275 -1276 -1277 -1278 -1279 -1280 -1281 -1282 -1283 -1284 -1285 -1286 -1287 -1288 -1289 -1290 -1291 -1292 -1293 -1294 -1295 -1296 -1297 -1298 -1299 -1300 -1301 -1302 -1303 -1304 -1305 -1306 -1307 -1308 -1309 -1310 -1311 -1312 -1313 -1314 -1315 -1316 -1317 -1318 -1319 -1320 -1321 -1322 -1323 -1324 -1325 -1326 -1327 -1328 -1329 -1330 -1331 -1332 -1333 -1334 -1335 -1336 -1337 -1338 -1339 -1340 -1341 -1342 -1343 -1344 -1345 -1346 -1347 -1348 -1349 -1350 -1351 -1352 -1353 -1354 -1355 -1356 -1357 -1358 -1359 -1360 -1361 -1362 -1363 -1364 -1365 -1366 -1367 -1368 -1369 -1370 -1371 -1372 -1373 -1374 -1375 -1376 -1377 -1378 -1379 -1380 -1381 -1382 -1383 -1384 -1385 -1386 -1387 -1388 -1389 -1390 -1391 -1392 -1393 -1394 -1395 -1396 -1397 -1398 -1399 -1400 -1401 -1402 -1403 -1404 -1405 -1406 -1407 -1408 -1409 -1410 -1411 -1412 -1413 -1414 -1415 -1416 -1417 -1418 -1419 -1420 -1421 -1422 -1423 -1424 -1425 -1426 -1427 -1428 -1429 -1430 -1431 -1432 -1433 -1434 -1435 -1436 -1437 -1438 -1439 -1440 -1441 -1442 -1443 -1444 -1445 -1446 -1447 -1448 -1449 -1450 -1451 -1452 -1453 -1454 -1455 -1456 -1457 -1458 -1459 -1460 -1461 -1462 -1463 -1464 -1465 -1466 -1467 -1468 -1469 -1470 -1471 -1472 -1473 -1474 -1475 -1476 -1477 -1478 -1479 -1480 -1481 -1482 -1483 -1484 -1485 -1486 -1487 -1488 -1489 -1490 -1491 -1492 -1493 -1494 -1495 -1496 -1497 -1498 -1499 -1500 -1501 -1502 -1503 -1504 -1505 -1506 -1507 -1508 -1509 -1510 -1511 -1512 -1513 -1514 -1515 -1516 -1517 -1518 -1519 -1520 -1521 -1522 -1523 -1524 -1525 -1526 -1527 -1528 -1529 -1530 -1531 -1532 -1533 -1534 -1535 -1536 -1537 -1538 -1539 -1540 -1541 -1542 -1543 -1544 -1545 -1546 -1547 -1548 -1549 -1550 -1551 -1552 -1553 -1554 -1555 -1556 -1557 -1558 -1559 -1560 -1561 -1562 -1563 -1564 -1565 -1566 -1567 -1568 -1569 -1570 -1571 -1572 -1573 -1574 -1575 -1576 -1577 -1578 -1579 -1580 -1581 -1582 -1583 -1584 -1585 -1586 -1587 -1588 -1589 -1590 -1591 -1592 -1593 -1594 -1595 -1596 -1597 -1598 -1599 -1600 -1601 -1602 -1603 -1604 -1605 -1606 -1607 -1608 -1609 -1610 -1611 -1612 -1613 -1614 -1615 -1616 -1617 -1618 -1619 -1620 -1621 -1622 -1623 -1624 -1625 -1626 -1627 -1628 -1629 -1630 -1631 -1632 -1633 -1634 -1635 -1636 -1637 -1638 -1639 -1640 -1641 -1642 -1643 -1644 -1645 -1646 -1647 -1648 -1649 -1650 -1651 -1652 -1653 -1654 -1655 -1656 -1657 -1658 -1659 -1660 -1661 -1662 -1663 -1664 -1665 -1666 -1667 -1668 -1669 -1670 -1671 -1672 -1673 -1674 -1675 -1676 -1677 -1678 -1679 -1680 -1681 -1682 -1683 -1684 -1685 -1686 -1687 -1688 -1689 -1690 -1691 -1692 -1693 -1694 -1695 -1696 -1697 -1698 -1699 -1700 -1701 -1702 -1703 -1704 -1705 -1706 -1707 -1708 -1709 -1710 -1711 -1712 -1713 -1714 -1715 -1716 -1717 -1718 -1719 -1720 -1721 -1722 -1723 -1724 -1725 -1726 -1727 -1728 -1729 -1730 -1731 -1732 -1733 -1734 -1735 -1736 -1737 -1738 -1739 -1740 -1741 -1742 -1743 -1744 -1745 -1746 -1747 -1748 -1749 -1750 -1751 -1752 -1753 -1754 -1755 -1756 -1757 -1758 -1759 -1760 -1761 -1762 -1763 -1764 -1765 -1766 -1767 -1768 -1769 -1770 -1771 -1772 -1773 -1774 -1775 -1776 -1777 -1778 -1779 -1780 -1781 -1782 -1783 -1784 -1785 -1786 -1787 -1788 -1789 -1790 -1791 -1792 -1793 -1794 -1795 -1796 -1797 -1798 -1799 -1800 -1801 -1802 -1803 -1804 -1805 -1806 -1807 -1808 -1809 -1810 -1811 -1812 -1813 -1814 -1815 -1816 -1817 -1818 -1819 -1820 -1821 -1822 -1823 -1824 -1825 -1826 -1827 -1828 -1829 -1830 -1831 -1832 -1833 -1834 -1835 -1836 -1837 -1838 -1839 -1840 -1841 -1842 -1843 -1844 -1845 -1846 -1847 -1848 -1849 -1850 -1851 -1852 -1853 -1854 -1855 -1856 -1857 -1858 -1859 -1860 -1861 -1862 -1863 -1864 -1865 -1866 -1867 -1868 -1869 -1870 -1871 -1872 -1873 -1874 -1875 -1876 -1877 -1878 -1879 -1880 -1881 -1882 -1883 -1884 -1885 -1886 -1887 -1888 -1889 -1890 -1891 -1892 -1893 -1894 -1895 -1896 -1897 -1898 -1899 -1900 -1901 -1902 -1903 -1904 -1905 -1906 -1907 -1908 -1909 -1910 -1911 -1912 -1913 -1914 -1915 -1916 -1917 -1918 -1919 -1920 -1921 -1922 -1923 -1924 -1925 -1926 -1927 -1928 -1929 -1930 -1931 -1932 -1933 -1934 -1935 -1936 -1937 -1938 -1939 -1940 -1941 -1942 -1943 -1944 -1945 -1946 -1947 -1948 -1949 -1950 -1951 -1952 -1953 -1954 -1955 -1956 -1957 -1958 -1959 -1960 -1961 -1962 -1963 -1964 -1965 -1966 -1967 -1968 -1969 -1970 -1971 -1972 -1973 -1974 -1975 -1976 -1977 -1978 -1979 -1980 -1981 -1982 -1983 -1984 -1985 -1986 -1987 -1988 -1989 -1990 -1991 -1992 -1993 -1994 -1995 -1996 -1997 -1998 -1999 -2000 -2001 -2002 -2003 -2004 -2005 -2006 -2007 -2008 -2009 -2010 -2011 -2012 -2013 -2014 -2015 -2016 -2017 -2018 -2019 -2020 -2021 -2022 -2023 -2024 -2025 -2026 -2027 -2028 -2029 -2030 -2031 -2032 -2033 -2034 -2035 -2036 -2037 -2038 -2039 -2040 -2041 -2042 -2043 -2044 -2045 -2046 -2047 -2048 -2049 -2050 -2051 -2052 -2053 -2054 -2055 -2056 -2057 -2058 -2059 -2060 -2061 -2062 -2063 -2064 -2065 -2066 -2067 -2068 -2069 -2070 -2071 -2072 -2073 -2074 -2075 -2076 -2077 -2078 -2079 -2080 -2081 -2082 -2083 -2084 -2085 -2086 -2087 -2088 -2089 -2090 -2091 -2092 -2093 -2094 -2095 -2096 -2097 -2098 -2099 -2100 -2101 -2102 -2103 -2104 -2105 -2106 -2107 -2108 -2109 -2110 -2111 -2112 -2113 -2114 -2115 -2116 -2117 -2118 -2119 -2120 -2121 -2122 -2123 -2124 -2125 -2126 -2127 -2128 -2129 -2130 -2131 -2132 -2133 -2134 -2135 -2136 -2137 -2138 -2139 -2140 -2141 -2142 -2143 -2144 -2145 -2146 -2147 -2148 -2149 -2150 -2151 -2152 -2153 -2154 -2155 -2156 -2157 -2158 -2159 -2160 -2161 -2162 -2163 -2164 -2165 -2166 -2167 -2168 -2169 -2170 -2171 -2172 -2173 -2174 -2175 -2176 -2177 -2178 -2179 -2180 -2181 -2182 -2183 -2184 -2185 -2186 -2187 -2188 -2189 -2190 -2191 -2192 -2193 -2194 -2195 -2196 -2197 -2198 -2199 -2200 -2201 -2202 -2203 -2204 -2205 -2206 -2207 -2208 -2209 -2210 -2211 -2212 -2213 -2214 -2215 -2216 -2217 -2218 -2219 -2220 -2221 -2222 -2223 -2224 -2225 -2226 -2227 -2228 -2229 -2230 -2231 -2232 -2233 -2234 -2235 -2236 -2237 -2238 -2239 -2240 -2241 -2242 -2243 -2244 -2245 -2246 -2247 -2248 -2249 -2250 -2251 -2252 -2253 -2254 -2255 -2256 -2257 -2258 -2259 -2260 -2261 -2262 -2263 -2264 -2265 -2266 -2267 -2268 -2269 -2270 -2271 -2272 -2273 -2274 -2275 -2276 -2277 -2278 -2279 -2280 -2281 -2282 -2283 -2284 -2285 -2286 -2287 -2288 -2289 -2290 -2291 -2292 -2293 -2294 -2295 -2296 -2297 -2298 -2299 -2300 -2301 -2302 -2303 -2304 -2305 -2306 -2307 -2308 -2309 -2310 -2311 -2312 -2313 -2314 -2315 -2316 -2317 -2318 -2319 -2320 -2321 -2322 -2323 -2324 -2325 -2326 -2327 -2328 -2329 -2330 -2331 -2332 -2333 -2334 -2335 -2336 -2337 -2338 -2339 -2340 -2341 -2342 -2343 -2344 -2345 -2346 -2347 -2348 -2349 -2350 -2351 -2352 -2353 -2354 -2355 -2356 -2357 -2358 -2359 -2360 -2361 -2362 -2363 -2364 -2365 -2366 -2367 -2368 -2369 -2370 -2371 -2372 -2373 -2374 -2375 -2376 -2377 -2378 -2379 -2380 -2381 -2382 -2383 -2384 -2385 -2386 -2387 -2388 -2389 -2390 -2391 -2392 -2393 -2394 -2395 -2396 -2397 -2398 -2399 -2400 -2401 -2402 -2403 -2404 -2405 -2406 -2407 -2408 -2409 -2410 -2411 -2412 -2413 -2414 -2415 -2416 -2417 -2418 -2419 -2420 -2421 -2422 -2423 -2424 -2425 -2426 -2427 -2428 -2429 -2430 -2431 -2432 -2433 -2434 -2435 -2436 -2437 -2438 -2439 -2440 -2441 -2442 -2443 -2444 -2445 -2446 -2447 -2448 -2449 -2450 -2451 -2452 -2453 -2454 -2455 -2456 -2457 -2458 -2459 -2460 -2461 -2462 -2463 -2464 -2465 -2466 -2467 -2468 -2469 -2470 -2471 -2472 -2473 -2474 -2475 -2476 -2477 -2478 -2479 -2480 -2481 -2482 -2483 -2484 -2485 -2486 -2487 -2488 -2489 -2490 -2491 -2492 -2493 -2494 -2495 -2496 -2497 -2498 -2499 -2500 -2501 -2502 -2503 -2504 -2505 -2506 -2507 -2508 -2509 -2510 -2511 -2512 -2513 -2514 -2515 -2516 -2517 -2518 -2519 -2520 -2521 -2522 -2523 -2524 -2525 -2526 -2527 -2528 -2529 -2530 -2531 -2532 -2533 -2534 -2535 -2536 -2537 -2538 -2539 -2540 -2541 -2542 -2543 -2544 -2545 -2546 -2547 -2548 -2549 -2550 -2551 -2552 -2553 -2554 -2555 -2556 -2557 -2558 -2559 -2560 -2561 -2562 -2563 -2564 -2565 -2566 -2567 -2568 -2569 -2570 -2571 -2572 -2573 -2574 -2575 -2576 -2577 -2578 -2579 -2580 -2581 -2582 -2583 -2584 -2585 -2586 -2587 -2588 -2589 -2590 -2591 -2592 -2593 -2594 -2595 -2596 -2597 -2598 -2599 -2600 -2601 -2602 -2603 -2604 -2605 -2606 -2607 -2608 -2609 -2610 -2611 -2612 -2613 -2614 -2615 -2616 -2617 -2618 -2619 -2620 -2621 -2622 -2623 -2624 -2625 -2626 -2627 -2628 -2629 -2630 -2631 -2632 -2633 -2634 -2635 -2636 -2637 -2638 -2639 -2640 -2641 -2642 -2643 -2644 -2645 -2646 -2647 -2648 -2649 -2650 -2651 -2652 -2653 -2654 -2655 -2656 -2657 -2658 -2659 -2660 -2661 -2662 -2663 -2664 -2665 -2666 -2667 -2668 -2669 -2670 -2671 -2672 -2673 -2674 -2675 -2676 -2677 -2678 -2679 -2680 -2681 -2682 -2683 -2684 -2685 -2686 -2687 -2688 -2689 -2690 -2691 -2692 -2693 -2694 -2695 -2696 -2697 -2698 -2699 -2700 -2701 -2702 -2703 -2704 -2705 -2706 -2707 -2708 -2709 -2710 -2711 -2712 -2713 -2714 -2715 -2716 -2717 -2718 -2719 -2720 -2721 -2722 -2723 -2724 -2725 -2726 -2727 -2728 -2729 -2730 -2731 -2732 -2733 -2734 -2735 -2736 -2737 -2738 -2739 -2740 -2741 -2742 -2743 -2744 -2745 -2746 -2747 -2748 -2749 -2750 -2751 -2752 -2753 -2754 -2755 -2756 -2757 -2758 -2759 -2760 -2761 -2762 -2763 -2764 -2765 -2766 -2767 -2768 -2769 -2770 -2771 -2772 -2773 -2774 -2775 -2776 -2777 -2778 -2779 -2780 -2781 -2782 -2783 -2784 -2785 -2786 -2787 -2788 -2789 -2790 -2791 -2792 -2793 -2794 -2795 -2796 -2797 -2798 -2799 -2800 -2801 -2802 -2803 -2804 -2805 -2806 -2807 -2808 -2809 -2810 -2811 -2812 -2813 -2814 -2815 -2816 -2817 -2818 -2819 -2820 -2821 -2822 -2823 -2824 -2825 -2826 -2827 -2828 -2829 -2830 -2831 -2832 -2833 -2834 -2835 -2836 -2837 -2838 -2839 -2840 -2841 -2842 -2843 -2844 -2845 -2846 -2847 -2848 -2849 -2850 -2851 -2852 -2853 -2854 -2855 -2856 -2857 -2858 -2859 -2860 -2861 -2862 -2863 -2864 -2865 -2866 -2867 -2868 -2869 -2870 -2871 -2872 -2873 -2874 -2875 -2876 -2877 -2878 -2879 -2880 -2881 -2882 -2883 -2884 -2885 -2886 -2887 -2888 -2889 -2890 -2891 -2892 -2893 -2894 -2895 -2896 -2897 -2898 -2899 -2900 -2901 -2902 -2903 -2904 -2905 -2906 -2907 -2908 -2909 -2910 -2911 -2912 -2913 -2914 -2915 -2916 -2917 -2918 -2919 -2920 -2921 -2922 -2923 -2924 -2925 -2926 -2927 -2928 -2929 -2930 -2931 -2932 -2933 -2934 -2935 -2936 -2937 -2938 -2939 -2940 -2941 -2942 -2943 -2944 -2945 -2946 -2947 -2948 -2949 -2950 -2951 -2952 -2953 -2954 -2955 -2956 -2957 -2958 -2959 -2960 -2961 -2962 -2963 -2964 -2965 -2966 -2967 -2968 -2969 -2970 -2971 -2972 -2973 -2974 -2975 -2976 -2977 -2978 -2979 -2980 -2981 -2982 -2983 -2984 -2985 -2986 -2987 -2988 -2989 -2990 -2991 -2992 -2993 -2994 -2995 -2996 -2997 -2998 -2999 -3000 -3001 -3002 -3003 -3004 -3005 -3006 -3007 -3008 -3009 -3010 -3011 -3012 -3013 -3014 -3015 -3016 -3017 -3018 -3019 -3020 -3021 -3022 -3023 -3024 -3025 -3026 -3027 -3028 -3029 -3030 -3031 -3032 -3033 -3034 -3035 -3036 -3037 -3038 -3039 -3040 -3041 -3042 -3043 -3044 -3045 -3046 -3047 -3048 -3049 -3050 -3051 -3052 -3053 -3054 -3055 -3056 -3057 -3058 -3059 -3060 -3061 -3062 -3063 -3064 -3065 -3066 -3067 -3068 -3069 -3070 -3071 -3072 -3073 -3074 -3075 -3076 -3077 -3078 -3079 -3080 -3081 -3082 -3083 -3084 -3085 -3086 -3087 -3088 -3089 -3090 -3091 -3092 -3093 -3094 -3095 -3096 -3097 -3098 -3099 -3100 -3101 -3102 -3103 -3104 -3105 -3106 -3107 -3108 -3109 -3110 -3111 -3112 -3113 -3114 -3115 -3116 -3117 -3118 -3119 -3120 -3121 -3122 -3123 -3124 -3125 -3126 -3127 -3128 -3129 -3130 -3131 -3132 -3133 -3134 -3135 -3136 -3137 -3138 -3139 -3140 -3141 -3142 -3143 -3144 -3145 -3146 -3147 -3148 -3149 -3150 -3151 -3152 -3153 -3154 -3155 -3156 -3157 -3158 -3159 -3160 -3161 -3162 -3163 -3164 -3165 -3166 -3167 -3168 -3169 -3170 -3171 -3172 -3173 -3174 -3175 -3176 -3177 -3178 -3179 -3180 -3181 -3182 -3183 -3184 -3185 -3186 -3187 -3188 -3189 -3190 -3191 -3192 -3193 -3194  -1x -1x -  -1x -1x -1x -1x -1x -1x -1x -  -  -  -  -1x -1x -1x -1x -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -1x -1x -1x -1x -1x -1x -1x -1x -1x -1x -1x -1x -1x -  -  -  -1x -1x -1x -1x -1x -1x -1x -1x -1x -1x -1x -1x -1x -1x -  -  -  -1x -1x -1x -1x -1x -1x -  -  -1x -1x -1x -1x -1x -1x -1x -1x -1x -1x -  -  -  -  -  -  -  -1x -  -1x -  -1x -  -  -1x -  -1x -  -  -1x -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -1x -  -1x -  -  -  -  -  -  -  -219x -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -219x -219x -219x -219x -219x -219x -  -  -  -219x -2x -2x -1x -  -1x -1x -  -  -  -218x -  -4x -  -4x -  -4x -  -1x -  -  -3x -  -3x -3x -3x -3x -3x -1x -  -2x -  -  -3x -  -3x -  -  -  -  -  -  -3x -  -  -217x -214x -214x -  -  -  -  -  -  -  -12x -12x -  -  -  -12x -  -  -  -  -  -12x -  -4x -4x -17x -8x -  -  -  -8x -2x -  -  -  -  -4x -1x -1x -  -3x -3x -  -  -  -  -  -  -  -  -  -  -  -  -  -  -36x -  -  -36x -36x -14x -  -  -  -22x -  -  -  -  -  -22x -  -  -  -  -  -22x -22x -22x -1x -  -  -  -21x -  -21x -21x -  -  -  -  -  -  -  -  -  -50x -  -50x -50x -80x -26x -  -  -24x -  -  -  -  -  -  -  -  -  -2x -  -2x -2x -4x -1x -  -  -1x -  -  -  -  -  -  -  -  -  -22x -  -22x -  -  -  -22x -  -  -  -  -  -  -  -  -  -  -  -  -1x -  -1x -  -1x -  -2x -  -  -  -  -  -  -  -  -54x -54x -  -  -  -  -  -  -  -  -  -  -  -  -  -54x -  -54x -  -  -  -  -  -54x -54x -  -54x -124x -  -  -  -  -  -  -  -54x -  -  -  -  -  -  -  -9x -  -9x -  -  -  -  -  -  -  -  -  -  -  -  -  -9x -9x -  -  -  -  -  -9x -9x -  -9x -16x -  -  -9x -9x -  -  -  -  -  -  -  -  -2x -  -2x -  -  -  -2x -  -  -  -  -2x -  -  -  -  -  -  -  -2x -  -2x -  -  -  -  -  -  -  -  -  -2x -  -  -  -  -  -2x -  -2x -2x -1x -  -  -  -1x -1x -  -  -  -37x -  -37x -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -37x -37x -  -  -  -  -36x -  -  -36x -36x -  -  -  -  -  -36x -126x -126x -68x -  -126x -36x -  -90x -90x -90x -90x -90x -90x -58x -58x -58x -  -32x -  -90x -90x -  -  -  -  -  -36x -  -  -  -  -  -  -  -  -138x -138x -  -138x -138x -538x -2x -  -  -  -  -  -136x -136x -69x -69x -  -  -67x -67x -67x -  -  -11x -11x -11x -11x -  -11x -  -38x -38x -38x -  -38x -27x -  -  -27x -27x -  -11x -  -  -  -  -  -67x -67x -66x -66x -  -1x -  -  -  -  -  -  -  -  -  -  -  -41x -41x -  -41x -  -  -41x -41x -  -  -  -  -  -  -  -1x -1x -  -  -  -  -  -  -  -  -30x -30x -  -30x -  -30x -28x -  -  -  -  -  -  -  -  -4x -  -  -  -  -  -  -  -  -  -5x -5x -  -5x -7x -  -5x -5x -5x -  -  -  -  -  -  -  -  -  -5x -  -  -  -  -  -5x -5x -  -  -  -  -  -  -  -1x -1x -  -4x -  -4x -4x -4x -  -1x -  -  -3x -12x -12x -  -  -12x -12x -12x -12x -  -12x -6x -  -6x -  -  -12x -  -  -3x -  -  -  -  -  -  -  -  -294x -294x -  -  -294x -4x -  -  -290x -290x -185x -185x -184x -  -  -  -  -  -1x -1x -  -  -105x -105x -  -  -  -  -  -  -  -  -  -19x -19x -19x -  -19x -  -19x -18x -18x -  -  -  -  -  -  -19x -  -  -  -  -  -  -  -  -  -18x -18x -18x -  -18x -  -18x -30x -  -30x -  -  -  -  -  -  -  -30x -14x -  -30x -19x -  -  -  -18x -  -  -  -  -  -  -  -  -  -87x -1x -  -  -87x -87x -  -87x -  -  -87x -86x -  -  -86x -  -86x -1x -  -85x -  -  -  -  -  -  -  -110x -  -110x -110x -105x -105x -104x -  -  -  -  -  -  -  -1x -1x -  -  -5x -5x -  -  -  -  -  -  -  -  -  -  -3x -3x -  -3x -  -3x -  -  -  -3x -3x -  -  -  -  -  -  -  -1x -1x -  -  -2x -2x -1x -  -  -1x -  -  -  -  -  -  -  -  -  -3x -3x -  -3x -  -3x -  -  -  -3x -3x -  -  -  -  -  -  -  -1x -1x -  -  -2x -2x -1x -  -  -1x -  -  -  -  -  -  -  -  -2x -2x -2x -  -  -  -2x -2x -  -  -  -  -  -1x -1x -  -  -1x -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -5x -5x -  -  -  -  -  -  -  -2x -2x -  -  -  -  -  -  -  -  -  -  -  -  -24x -24x -  -24x -1x -  -  -23x -  -  -  -  -  -  -  -23x -  -  -  -  -  -23x -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -8x -  -8x -  -  -  -  -  -  -8x -  -  -  -  -  -8x -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -3x -3x -1x -  -  -3x -1x -  -  -3x -  -  -  -  -  -  -  -  -3x -  -  -  -  -  -3x -3x -3x -6x -  -  -3x -  -  -  -  -  -  -8x -  -  -  -  -8x -  -  -  -  -  -8x -  -8x -8x -8x -8x -8x -  -8x -7x -6x -5x -  -1x -  -  -5x -4x -  -1x -  -  -4x -3x -  -1x -  -  -1x -  -  -3x -2x -  -1x -  -  -2x -1x -  -1x -  -  -  -1x -  -  -1x -  -  -  -  -  -  -  -  -  -  -  -  -  -1x -  -  -  -4x -  -  -  -  -4x -  -  -  -  -  -4x -  -  -  -4x -  -  -  -  -  -1x -  -  -  -  -  -3x -  -  -1x -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -29x -  -29x -27x -27x -17x -  -27x -  -  -  -  -  -  -  -  -  -  -  -  -29x -29x -  -  -  -  -29x -29x -29x -25x -  -29x -2x -1x -  -1x -  -28x -2x -1x -  -1x -  -27x -25x -  -27x -  -27x -  -  -  -  -27x -  -  -  -  -  -  -  -  -  -  -  -  -  -  -27x -  -27x -  -  -26x -26x -  -17x -  -  -27x -  -  -  -  -  -  -  -  -24x -24x -14x -  -10x -  -  -  -  -  -  -  -  -  -4x -4x -  -  -  -  -4x -4x -  -4x -  -  -  -  -4x -4x -  -4x -1x -  -  -3x -  -  -2x -2x -4x -  -  -  -3x -  -  -  -  -  -  -  -  -  -5x -5x -  -  -  -  -5x -5x -  -5x -  -  -  -  -5x -5x -  -5x -1x -  -  -4x -  -3x -3x -1x -  -  -  -4x -  -  -  -  -  -  -  -  -  -  -18x -18x -  -  -  -  -18x -18x -  -  -  -  -18x -  -18x -1x -  -  -17x -14x -  -3x -  -  -  -  -  -  -  -  -  -  -23x -23x -  -  -  -23x -23x -  -  -  -  -23x -  -23x -8x -  -  -15x -1x -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -47x -47x -  -  -  -  -47x -47x -47x -46x -  -47x -4x -1x -  -3x -  -46x -2x -1x -  -1x -  -45x -44x -  -45x -  -45x -  -  -  -  -45x -  -  -  -  -  -  -  -  -  -  -  -  -  -  -45x -  -45x -  -  -44x -44x -43x -  -  -  -45x -  -  -  -  -  -  -  -  -  -72x -72x -  -  -  -  -72x -72x -  -72x -  -  -  -  -72x -  -72x -1x -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -71x -71x -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -71x -35x -  -36x -35x -  -36x -36x -1x -  -36x -1x -  -  -71x -  -  -  -  -  -  -  -  -  -4x -4x -  -  -  -  -4x -4x -  -4x -  -  -  -  -4x -  -4x -2x -  -2x -  -  -  -  -  -  -  -  -  -5x -5x -  -  -  -  -5x -5x -  -5x -  -  -  -  -5x -  -5x -3x -  -2x -  -  -  -  -  -  -  -  -  -36x -36x -  -  -  -  -36x -36x -  -36x -  -  -  -  -36x -  -36x -18x -  -18x -  -  -  -  -  -  -  -  -41x -41x -41x -35x -  -6x -  -  -  -  -  -  -  -  -  -  -  -23x -23x -23x -4x -3x -  -1x -  -  -22x -19x -  -  -22x -  -  -  -  -22x -22x -  -  -  -  -22x -  -22x -1x -  -  -21x -21x -18x -  -  -3x -  -  -  -  -  -  -  -  -  -  -  -  -  -51x -51x -  -51x -  -  -  -  -51x -51x -51x -  -  -  -  -51x -  -  -  -  -  -  -  -  -  -  -51x -1x -  -  -50x -32x -  -  -18x -3x -  -  -18x -  -  -  -  -  -  -  -  -5x -  -5x -  -  -  -5x -5x -5x -  -  -  -  -5x -  -5x -1x -  -  -4x -2x -  -2x -  -  -  -  -  -  -  -  -  -  -  -  -  -16x -  -16x -16x -  -  -  -  -  -16x -16x -  -16x -  -  -  -  -16x -  -16x -9x -  -  -6x -1x -  -  -5x -1x -  -  -4x -1x -  -  -3x -  -  -  -  -  -  -  -  -  -  -  -  -  -14x -  -14x -14x -  -  -  -  -  -14x -14x -  -14x -  -  -  -  -12x -  -12x -7x -  -  -5x -1x -  -  -4x -1x -  -  -3x -1x -  -  -2x -  -  -  -  -  -  -  -  -  -  -  -  -  -13x -  -13x -13x -  -  -  -  -  -13x -13x -  -13x -  -  -  -  -13x -  -13x -8x -  -  -5x -1x -  -  -4x -1x -  -  -3x -1x -  -  -2x -  -  -  -  -  -  -  -  -  -  -  -10x -  -10x -10x -  -  -  -  -  -10x -10x -  -10x -  -  -  -  -10x -  -10x -4x -  -  -  -  -  -  -  -  -  -  -  -  -  -6x -1x -  -  -5x -  -  -  -  -  -  -  -  -  -12x -12x -18x -18x -  -  -18x -2x -2x -1x -  -1x -1x -1x -  -  -16x -  -  -17x -17x -17x -  -  -  -  -17x -7x -3x -3x -2x -  -1x -  -  -  -7x -2x -2x -1x -  -1x -  -  -  -  -  -  -  -17x -6x -3x -3x -2x -  -1x -  -  -  -6x -2x -2x -1x -  -1x -  -  -  -  -  -  -  -17x -8x -8x -8x -4x -2x -1x -  -  -  -13x -10x -  -8x -8x -8x -8x -8x -5x -5x -  -2x -2x -  -  -6x -6x -  -1x -1x -  -  -  -8x -5x -5x -  -2x -2x -  -  -8x -3x -  -5x -5x -  -  -  -  -  -  -  -  -17x -8x -8x -10x -8x -  -8x -8x -8x -7x -7x -2x -2x -  -1x -1x -  -  -6x -6x -  -1x -1x -  -  -  -8x -4x -4x -  -1x -1x -  -  -8x -3x -  -5x -  -  -  -  -  -  -  -17x -6x -6x -6x -6x -4x -4x -3x -  -1x -  -  -  -  -  -  -  -17x -6x -6x -6x -6x -3x -3x -2x -  -1x -  -  -  -  -  -  -  -17x -5x -5x -5x -5x -3x -3x -1x -  -2x -  -  -  -  -  -  -  -17x -5x -5x -5x -5x -3x -3x -1x -  -2x -  -  -  -  -  -  -  -17x -6x -6x -6x -6x -3x -3x -2x -  -1x -  -  -  -  -  -  -  -17x -6x -6x -6x -6x -4x -4x -3x -  -1x -  -  -  -  -  -  -  -17x -5x -5x -5x -5x -5x -3x -  -2x -  -  -  -  -  -  -17x -6x -6x -6x -6x -3x -3x -2x -  -1x -  -  -  -  -  -  -  -17x -6x -6x -6x -6x -3x -3x -2x -  -1x -  -  -  -  -  -  -  -17x -5x -5x -5x -5x -3x -3x -1x -  -2x -  -  -  -  -  -  -  -17x -6x -6x -6x -6x -2x -2x -1x -  -1x -  -  -  -  -17x -1x -  -17x -  -12x -  -  -  -  -  -  -  -  -  -  -  -  -2x -2x -  -2x -  -  -  -  -2x -  -  -2x -  -  -  -  -  -2x -2x -2x -  -  -  -  -  -  -  -  -  -  -  -  -  -  -3x -  -3x -  -  -  -  -3x -  -3x -  -  -  -  -  -  -  -  -  -  -  -  -  -10x -  -  -  -10x -  -10x -  -  -  -  -  -10x -10x -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -1x -  -  -  -1x -  -1x -  -  -  -  -  -  -  -  -  -  -  -  -  -  -3x -  -  -  -  -3x -  -  -  -  -  -  -3x -1x -  -  -2x -  -2x -  -2x -1x -  -1x -  -  -1x -1x -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -411x -  -411x -1x -  -  -410x -1x -  -  -409x -  -409x -1x -  -408x -  -  -408x -  -  -408x -2x -  -  -  -406x -309x -  -  -  -  -  -  -406x -406x -  -661x -1x -  -  -660x -1x -  -659x -  -  -659x -329x -  -  -659x -989x -1x -  -988x -594x -1x -  -593x -593x -593x -  -  -  -  -402x -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -1229x -369x -  -  -  -1229x -1229x -  -  -  -  -  -  -  -  -  -  -  -  -37x -37x -37x -37x -  -37x -19x -  -18x -  -37x -37x -  -  -  -  -  -36x -90x -32x -18x -  -  -58x -30x -30x -  -  -  -  -1x -  -  -37x -  -  -  -536x -4x -  -  -536x -536x -7x -  -  -536x -  -  -  -145x -  -  -  -  -94x -94x -  -94x -  -  -94x -94x -  -  -  -  -  -  -  -11x -11x -  -  -  -  -  -400x -400x -  -400x -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -400x -400x -  -  -  -  -  -  -  -109x -109x -  -  -291x -291x -  -291x -290x -  -  -  -  -  -  -  -290x -105x -  -185x -  -  -290x -104x -  -  -  -291x -1x -1x -  -  -290x -  -  -  -  -397x -397x -  -  -396x -396x -334x -  -396x -  -1x -  -  -  -405x -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -374x -  -  -  -  -86x -86x -  -86x -  -  -  -  -86x -86x -86x -  -  -  -86x -  -  -  -  -  -  -86x -  -  -  - 
// this must be the first
-import { config } from "dotenv";
-config();
- 
-import UploadFilesCommand, { UploadFilesCommandOptions, SourceTargetFileNames } from "./uploadFilesCommand";
-import UploadFolderCommand, { UploadFolderCommandOptions } from "./uploadFolderCommand";
-import GetFilesRecursivelyCommand, { GetFilesRecursivelyCommandOptions } from "./getFilesRecursivelyCommand";
-import { CommandStatus, CommandResultMetaData } from "./command";
-import debugFactory from "debug";
-import parser from "fast-xml-parser";
-import {
-    Headers,
-    RequestInit,
-    Response,
-} from "node-fetch";
-import path, { basename } from "path";
-import Environment from "./environment";
-import EnvironmentVcapServices from "./environmentVcapServices";
-import ClientError, {
-    CommandAlreadyExecutedError,
-    QueryLimitError,
-    QueryOffsetError,
-    InsufficientPrivilegesError,
-    InvalidServiceResponseFormatError,
-    OperationFailedError,
-    UserGroupAlreadyExistsError,
-    UserGroupDeletionFailedError,
-    UserResendWelcomeEmailError,
-    UserGroupDoesNotExistError,
-    UserNotFoundError,
-    UserAlreadyExistsError,
-    UserCreateError,
-    UserUpdateError,
-} from "./error";
-import FakeServer from "./fakeServer";
-import File from "./file";
-import FileSystemElement from "./fileSystemElement";
-import FileSystemFolder, { IFileNameFormats } from "./fileSystemFolder";
-import Folder, { FolderGetFilesOptions } from "./folder";
-import { HttpClient, IHttpClientOptions, IProxy, IRequestContext } from "./httpClient";
-import RequestResponseLog from "./requestResponseLog";
-import RequestResponseLogEntry from "./requestResponseLogEntry";
-import Server, { IServerOptions } from "./server";
-import Share, { ICreateShare, SharePermission } from "./share";
-import Tag from "./tag";
-import UserGroup from "./userGroup";
-import User, { IUserOptions, IUserOptionsQuota, IUserQuotaUserFriendly, UserProperty } from "./user";
- 
-export {
-    FolderGetFilesOptions,
-    CommandAlreadyExecutedError,
-    InvalidServiceResponseFormatError,
-    InsufficientPrivilegesError,
-    OperationFailedError,
-    QueryLimitError,
-    QueryOffsetError,
-    UserNotFoundError,
-    UserAlreadyExistsError,
-    UserCreateError,
-    UserResendWelcomeEmailError,
-    UserUpdateError,
-    UserGroupAlreadyExistsError,
-    UserGroupDeletionFailedError,
-    UserGroupDoesNotExistError,
-}
- 
-export {
-    Client,
-    ClientError,
-    Environment,
-    Folder,
-    File,
-    FileSystemElement,
-    ICreateShare,
-    IServerOptions,
-    Tag,
-    FakeServer,
-    Server,
-    Share,
-    SharePermission,
-    RequestResponseLog,
-    RequestResponseLogEntry,
-    User,
-    UserGroup,
-    UserProperty,
-    IUserOptionsQuota,
-    IUserQuotaUserFriendly,
-};
- 
-// command object for upload
-export {
-    CommandResultMetaData,
-    GetFilesRecursivelyCommand,
-    GetFilesRecursivelyCommandOptions,
-    UploadFilesCommand,
-    UploadFilesCommandOptions,
-    UploadFolderCommand,
-    UploadFolderCommandOptions,
-    SourceTargetFileNames,
-    FileSystemFolder,
-    IFileNameFormats,
-    CommandStatus,
-}
- 
-const debug = debugFactory("NCClient");
-// const debug = console.log;
- 
-interface IStat {
-    "type": string;
-    "filename": string;
-    "basename": string;
-    "lastmod": string;
-    "size"?: number;
-    "mime"?: string;
-    "fileid"?: number;
-}
- 
-export interface IUpsertUserOptions {
-    "id": string;
-    "enabled"?: boolean;
-    "subadminGroups"?: string[],
-    "memberGroups"?: string[],
-    "quota"?: string,
-    "email"?: string,
-    "displayName"?: string,
-    "password"?: string,
-    "phone"?: string,
-    "address"?: string,
-    "website"?: string,
-    "twitter"?: string,
-    "language"?: string
-    "locale"?: string,
-    "superAdmin"?: boolean,
-    "resendWelcomeEmail"?: boolean,
-}
- 
-export interface IUserPropertyChange {
-    "property": string;
-    "previousValue": string;
-    "newValue": string;
-    "error"?: string;
-}
- 
-export interface IUpsertUserReport {
-    "id": string;
-    "message": string;
-    "changes": IUserPropertyChange[];
-}
- 
-export interface ISysInfoNextcloudClient {
-    "version": string;
-}
- 
-export interface ISysInfoNextcloud {
-    "system": object;
-    "storage": object;
-    "shares": object;
-}
- 
-export interface ISysBasicData {
-    "serverTimeString": string;
-    "uptimeString": string;
-    "timeServersString": string;
-}
- 
-export interface ISystemInfo {
-    "nextcloud": ISysInfoNextcloud;
-    // @todo change object to something strongly typed
-    "server": object;
-    // @todo change object to something strongly typed
-    "activeUsers": object;
-    "nextcloudClient": ISysInfoNextcloudClient;
-}
- 
-export interface IQuota {
-    used: number;
-    available: number | string;
-}
- 
-/**
- * The nextcloud client is the root object to access the remote api of the nextcloud server.<br>
- */
-export default class Client {
- 
-    public static webDavUrlPath: string = "/remote.php/webdav";
- 
-    private nextcloudOrigin: string;
-    private nextcloudAuthHeader: string;
-    private nextcloudRequestToken: string;
-    private webDAVUrl: string;
-    private proxy?: IProxy;
-    private fakeServer?: FakeServer;
-    private logRequestResponse: boolean = false;
-    private httpClient?: HttpClient;
-    private userId: string;
- 
-    /**
-     * Creates a new instance of a nextcloud client.<br/>
-     * Use the server to provide server connectivity information to the client.<br/>
-     * (The FakeServer is only used for testing and code coverage)<br/><br/>
-     * If the server is not provided the client tries to find the connectivity information
-     * in the environment.<br/>
-     * If a <b>VCAP_SERVICES</b> environment variable is available, the client tries to find
-     * a service with the name <b>"nextcloud"</b> in the user-provides-services section.<br/>
-     * If no VCAP_SERVICES are available, the client uses the following variables
-     * from the envirnonment for the connectivity:<br/>
-     * <ul>
-     * <li>NEXTCLOUD_URL - the WebDAV url of the nextcloud server</li>
-     * <li>NEXTCLOUD_USERNAME - the user name</li>
-     * <li>NEXTCLOUD_PASSWORD - the application password</li>
-     * </ul>
-     * @param server optional server information to connection to a nextcloud server
-     * @constructor
-     */
-    public constructor(server?: Server | FakeServer) {
-        debug("constructor");
-        this.nextcloudOrigin = "";
-        this.nextcloudAuthHeader = "";
-        this.nextcloudRequestToken = "";
-        this.webDAVUrl = "";
-        this.userId = "";
- 
-        // if no server is provided, try to get a server from VCAP_S environment "nextcloud" instance
-        // If no VCAP_S environment exists try from environment
-        if (!server) {
-            try {
-                const env: EnvironmentVcapServices = new EnvironmentVcapServices("nextcloud");
-                server = env.getServer();
-            } catch (e) {
-                const env: Environment = new Environment();
-                server = env.getServer();
-            }
-        }
- 
-        if (server instanceof Server) {
- 
-            this.proxy = server.proxy;
- 
-            debug("constructor: webdav url %s", server.url);
- 
-            if (server.url.indexOf(Client.webDavUrlPath) === -1) {
-                // not a valid nextcloud url
-                throw new ClientError(`The provided nextcloud url "${server.url}" does not comply to the nextcloud url standard, "${Client.webDavUrlPath}" is missing`,
-                    "ERR_INVALID_NEXTCLOUD_WEBDAV_URL");
-            }
-            this.nextcloudOrigin = server.url.substr(0, server.url.indexOf(Client.webDavUrlPath));
- 
-            debug("constructor: nextcloud url %s", this.nextcloudOrigin);
-            this.userId = server.basicAuth.username;
-            this.nextcloudAuthHeader = "Basic " + Buffer.from(server.basicAuth.username + ":" + server.basicAuth.password).toString("base64");
-            this.nextcloudRequestToken = "";
-            if (server.url.slice(-1) === "/") {
-                this.webDAVUrl = server.url.slice(0, -1);
-            } else {
-                this.webDAVUrl = server.url;
-            }
- 
-            this.logRequestResponse = server.logRequestResponse;
- 
-            const options: IHttpClientOptions = {
-                authorizationHeader: this.nextcloudAuthHeader,
-                logRequestResponse: this.logRequestResponse,
-                origin: this.nextcloudOrigin,
-                proxy: this.proxy,
-            };
- 
-            this.httpClient = new HttpClient(options);
-        }
- 
-        if (server instanceof FakeServer) {
-            this.fakeServer = server;
-            this.webDAVUrl = "https://fake.server" + Client.webDavUrlPath;
-        }
-    }
- 
-    /**
-     * returns the used and free quota of the nextcloud account
-     */
-    public async getQuota(): Promise<IQuota> {
-        debug("getQuota");
-        const requestInit: RequestInit = {
-            method: "PROPFIND",
-        };
- 
-        const response: Response = await this.getHttpResponse(
-            this.webDAVUrl + "/",
-            requestInit,
-            [207],
-            { description: "Client get quota" });
- 
-        const properties: any[] = await this.getPropertiesFromWebDAVMultistatusResponse(response, Client.webDavUrlPath + "/");
- 
-        let quota: IQuota | null = null;
-        for (const prop of properties) {
-            if (prop["quota-available-bytes"]) {
-                quota = {
-                    available: "unlimited",
-                    used: prop["quota-used-bytes"],
-                };
-                if (prop["quota-available-bytes"] > 0) {
-                    quota.available = prop["quota-available-bytes"];
-                }
-            }
-        }
- 
-        if (!quota) {
-            debug("Error, quota not available: %s ", JSON.stringify(properties, null, 4));
-            throw new ClientError(`Error, quota not available`, "ERR_QUOTA_NOT_AVAILABLE");
-        }
-        debug("getQuota = %O", quota);
-        return quota;
-    }
- 
-    // ***************************************************************************************
-    // tags
-    // ***************************************************************************************
- 
-    /**
-     * creates a new tag, if not already existing
-     * this function will fail with http 403 if the user does not have admin privileges
-     * @param tagName the name of the tag
-     * @returns tagId
-     */
-    public async createTag(tagName: string): Promise<Tag> {
- 
-        debug("createTag");
-        let tag: Tag | null;
-        // is the tag already existing?
-        tag = await this.getTagByName(tagName);
-        if (tag) {
-            return tag;
-        }
-        // tag does not exist, create tag
- 
-        const requestInit: RequestInit = {
-            body: `{ "name": "${tagName}", "userVisible": true, "userAssignable": true, "canAssign": true }`,
-            headers: new Headers({ "Content-Type": "application/json" }),
-            method: "POST",
-        };
- 
-        const response: Response = await this.getHttpResponse(
-            this.nextcloudOrigin + "/remote.php/dav/systemtags/",
-            requestInit,
-            [201],
-            { description: "Tag create" },
-        );
-        const tagString: string | null = response.headers.get("Content-Location");
-        debug("createTag new tagId %s, tagName %s", tagString, tagName);
-        if (tagString === "" || tagString === null) {
-            throw new ClientError(`Error, tag with name '${tagName}' could not be created`, "ERR_TAG_CREATE_FAILED");
-        }
- 
-        // the number id of the tag is the last element in the id (path)
-        const tagId: number = this.getTagIdFromHref(tagString);
- 
-        tag = new Tag(this, tagId, tagName, true, true, true);
-        return tag;
-    }
- 
-    /**
-     * returns a tag identified by the name or null if not found
-     * @param tagName the name of the tag
-     * @returns tag or null
-     */
-    public async getTagByName(tagName: string): Promise<Tag | null> {
- 
-        debug("getTag");
- 
-        const tags: Tag[] = await this.getTags();
-        for (const tag of tags) {
-            if (tag.name === tagName) {
-                return tag;
-            }
-        }
-        return null;
-    }
- 
-    /**
-     * returns a tag identified by the id or null if not found
-     * @param tagId the id of the tag
-     * @returns tag or null
-     */
-    public async getTagById(tagId: number): Promise<Tag | null> {
- 
-        debug("getTagById");
- 
-        const tags: Tag[] = await this.getTags();
-        for (const tag of tags) {
-            if (tag.id === tagId) {
-                return tag;
-            }
-        }
-        return null;
-    }
- 
-    /**
-     * deletes the tag by id
-     * this function will fail with http 403 if the user does not have admin privileges
-     * @param tagId the id of the tag like "/remote.php/dav/systemtags/234"
-     */
-    public async deleteTag(tagId: number): Promise<void> {
- 
-        debug("deleteTag tagId: $s", tagId);
- 
-        const requestInit: RequestInit = {
-            method: "DELETE",
-        };
- 
-        const response: Response = await this.getHttpResponse(
-            `${this.nextcloudOrigin}/remote.php/dav/systemtags/${tagId}`,
-            requestInit,
-            [204, 404],
-            { description: "Tag delete" });
-    }
- 
-    /**
-     * deletes all visible assignable tags
-     * @throws Error
-     */
-    public async deleteAllTags(): Promise<void> {
- 
-        debug("deleteAllTags");
- 
-        const tags: Tag[] = await this.getTags();
- 
-        for (const tag of tags) {
-            // debug("deleteAllTags tag: %O", tag);
-            await tag.delete();
-        }
-    }
- 
-    /**
-     * returns a list of tags
-     * @returns array of tags
-     */
-    public async getTags(): Promise<Tag[]> {
-        debug("getTags PROPFIND %s", this.nextcloudOrigin + "/remote.php/dav/systemtags/");
-        const requestInit: RequestInit = {
-            body: `<?xml version="1.0"?>
-            <d:propfind  xmlns:d="DAV:" xmlns:oc="http://owncloud.org/ns">
-              <d:prop>
-                <oc:id />
-                <oc:display-name />
-                <oc:user-visible />
-                <oc:user-assignable />
-                <oc:can-assign />
-              </d:prop>
-            </d:propfind>`,
-            method: "PROPFIND",
-        };
- 
-        const relUrl = `/remote.php/dav/systemtags/`;
- 
-        const response: Response = await this.getHttpResponse(
-            this.nextcloudOrigin + relUrl,
-            requestInit,
-            [207],
-            { description: "Tags get" });
- 
-        const properties: any[] = await this.getPropertiesFromWebDAVMultistatusResponse(response, relUrl + "/*");
-        const tags: Tag[] = [];
- 
-        for (const prop of properties) {
-            tags.push(new Tag(this,
-                this.getTagIdFromHref(prop._href),
-                prop["display-name"],
-                prop["user-visible"],
-                prop["user-assignable"],
-                prop["can-assign"]));
-        }
- 
-        return tags;
-    }
- 
-    /**
-     * returns the list of tag names and the tag ids
-     * @param fileId the id of the file
-     */
-    public async getTagsOfFile(fileId: number): Promise<Map<string, number>> {
-        debug("getTagsOfFile");
- 
-        const requestInit: RequestInit = {
-            body: `<?xml version="1.0"?>
-            <d:propfind  xmlns:d="DAV:" xmlns:oc="http://owncloud.org/ns">
-              <d:prop>
-                <oc:id />
-                <oc:display-name />
-                <oc:user-visible />
-                <oc:user-assignable />
-                <oc:can-assign />
-              </d:prop>
-            </d:propfind>`,
-            method: "PROPFIND",
-        };
- 
-        const relUrl = `/remote.php/dav/systemtags-relations/files/${fileId}`;
-        const response: Response = await this.getHttpResponse(
-            `${this.nextcloudOrigin}${relUrl}`,
-            requestInit,
-            [207],
-            { description: "File get tags" });
- 
-        const properties: any[] = await this.getPropertiesFromWebDAVMultistatusResponse(response, relUrl + "/*");
-        const tagMap: Map<string, number> = new Map();
- 
-        for (const prop of properties) {
-            tagMap.set(prop["display-name"], prop.id);
-        }
- 
-        debug("tags of file %O", tagMap);
-        return tagMap;
-    }
- 
-    /**
-     * removes the tag from the file
-     * @param fileId the file id
-     * @param tagId the tag id
-     */
-    public async removeTagOfFile(fileId: number, tagId: number): Promise<void> {
-        debug("removeTagOfFile tagId: $s fileId:", tagId, fileId);
- 
-        const requestInit: RequestInit = {
-            method: "DELETE",
-        };
- 
-        const response: Response = await this.getHttpResponse(
-            `${this.nextcloudOrigin}/remote.php/dav/systemtags-relations/files/${fileId}/${tagId}`,
-            requestInit,
-            [204, 404],
-            { description: "File remove tag" });
-        return;
-    }
- 
-    /**
-     * returns the id of the file or -1 of not found
-     * @returns id of the file or -1 if not found
-     */
-    public async getFileId(fileUrl: string): Promise<number> {
-        debug("getFileId");
- 
-        const requestInit: RequestInit = {
-            body: `
-            <d:propfind  xmlns:d="DAV:" xmlns:oc="http://owncloud.org/ns" xmlns:nc="http://nextcloud.org/ns">
-              <d:prop>
-                  <oc:fileid />
-              </d:prop>
-            </d:propfind>`,
-            method: "PROPFIND",
-        };
- 
-        const response: Response = await this.getHttpResponse(
-            fileUrl,
-            requestInit,
-            [207],
-            { description: "File get id" });
- 
-        const properties: any[] = await this.getPropertiesFromWebDAVMultistatusResponse(response, "");
- 
-        for (const prop of properties) {
-            if (prop.fileid) {
-                return prop.fileid;
-            }
-        }
- 
-        debug("getFileId no file id found for %s", fileUrl);
-        return -1;
-    }
- 
-    public async getFolderContents(folderName: string): Promise<any[]> {
-        debug("getFolderContents");
- 
-        const requestInit: RequestInit = {
-            body: `<?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:getetag />
-                <d:getcontenttype />
-                <d:resourcetype />
-                <oc:fileid />
-                <oc:permissions />
-                <oc:size />
-                <d:getcontentlength />
-                <nc:has-preview />
-                <nc:mount-type />
-                <nc:is-encrypted />
-                <ocs:share-permissions />
-                <oc:tags />
-                <oc:favorite />
-                <oc:comments-unread />
-                <oc:owner-id />
-                <oc:owner-display-name />
-                <oc:share-types />
-              </d:prop>
-            </d:propfind>`,
-            method: "PROPFIND",
-        };
-        const url = `${this.webDAVUrl}${folderName}`;
-        const response: Response = await this.getHttpResponse(
-            url,
-            requestInit,
-            [207],
-            { description: "Folder get contents" });
-        const folderContents: any[] = [];
- 
-        let properties: any[];
-        try {
-            properties = await this.getPropertiesFromWebDAVMultistatusResponse(response, "");
-        } catch (e) {
-            return folderContents;
-        }
- 
-        // tslint:disable-next-line:no-empty
-        for (const prop of properties) {
-            let fileName = decodeURI(prop._href.substr(prop._href.indexOf(Client.webDavUrlPath) + 18));
-            if (fileName.endsWith("/")) {
-                fileName = fileName.slice(0, -1);
-            }
-            if ((url + "/").endsWith(decodeURI(prop._href))) {
-                continue;
-            }
-            const folderContentsEntry: any = {};
-            folderContentsEntry.lastmod = prop.getlastmodified;
-            folderContentsEntry.fileid = prop.fileid;
-            folderContentsEntry.basename = fileName.split("/").reverse()[0];
-            folderContentsEntry.filename = fileName;
-            if (prop.getcontenttype) {
-                folderContentsEntry.mime = prop.getcontenttype;
-                folderContentsEntry.size = prop.getcontentlength;
-                folderContentsEntry.type = "file";
-            } else {
-                folderContentsEntry.type = "directory";
-            }
-            Eif (folderContentsEntry.basename !== "") {
-                folderContents.push(folderContentsEntry);
-            }
- 
-        }
- 
-        // debug("folderContentsEntry $s", JSON.stringify(folderContents, null, 4));
-        return folderContents;
-    }
- 
-    /**
-     * creates a folder and all parent folders in the path if they do not exist
-     * @param folderName name of the folder /folder/subfolder/subfolder
-     * @returns a folder object
-     */
-    public async createFolder(folderName: string): Promise<Folder> {
-        folderName = this.sanitizeFolderName(folderName);
-        debug("createFolder: folderName=%s", folderName);
- 
-        const parts1: string[] = folderName.split("/");
-        for (const p of parts1) {
-            if ((p) === "." || p === "..") {
-                throw new ClientError(`Error creating folder, folder name "${folderName}" invalid`, "ERR_CREATE_FOLDER_INVALID_FOLDER_NAME");
-            }
-        }
- 
-        let folder: Folder | null;
- 
-        folder = await this.getFolder(folderName);
-        if (folder) {
-            debug("createFolder: folder already available %O", folder.name);
-            return folder;
-        } else {
-            // try to do a simple create with the complete path
-            try {
-                debug("createFolder: folder = %s", folderName);
-                await this.createFolderInternal(folderName);
-            } catch (e) {
-                // create all folders in the path
-                const parts: string[] = folderName.split("/");
-                parts.shift();
-                let folderPath: string = "";
-                debug("createFolder: parts = %O", parts);
- 
-                for (const part of parts) {
- 
-                    debug("createFolder: part = %O", part);
-                    folderPath += "/" + part;
-                    folder = await this.getFolder(folderPath);
- 
-                    if (folder === null) {
-                        debug("createFolder: folder not available");
-                        // folder not  available
- 
-                        debug("createFolder: folder = %s", folderPath);
-                        await this.createFolderInternal(folderPath);
-                    } else {
-                        debug("createFolder: folder already available %s", folderPath);
-                    }
-                }
-            }
-        }
- 
-        folder = await this.getFolder(folderName);
-        if (folder) {
-            debug("createFolder: new folder %O", folder.name);
-            return folder;
-        } else {
-            throw new ClientError(`Error creating folder, folder name "${folderName}"
-            `, "ERR_CREATE_FOLDER_FAILED");
-        }
- 
-    }
- 
-    /**
-     * deletes a file
-     * @param fileName name of folder "/f1/f2/f3/x.txt"
-     */
-    public async deleteFile(fileName: string): Promise<void> {
- 
-        const url: string = this.webDAVUrl + fileName;
-        debug("deleteFile %s", url);
- 
-        const requestInit: RequestInit = {
-            method: "DELETE",
-        };
-        try {
-            await this.getHttpResponse(
-                url,
-                requestInit,
-                [204],
-                { description: "File delete" },
-            );
- 
-        } catch (err) {
-            debug("Error in deleteFile %s %s %s", err.message, requestInit.method, url);
-            throw err;
-        }
-    }
- 
-    /**
-     * deletes a folder
-     * @param folderName name of folder "/f1/f2/f3"
-     */
-    public async deleteFolder(folderName: string): Promise<void> {
-        folderName = this.sanitizeFolderName(folderName);
-        debug("deleteFolder:");
- 
-        const folder: Folder | null = await this.getFolder(folderName);
- 
-        if (folder) {
-            await this.deleteFile(folderName);
-        }
-    }
- 
-    /**
-     * get the root folder object
-     * @returns {Promise<Folder>} the root folder
-     */
-    public getRootFolder(): Folder {
-        return new Folder(this, "/", "", "");
-    }
- 
-    /**
-     * returns an array of file system objects that have all given tags assigned (AND)
-     * @param {Tag[]} tags array of tags
-     * @async
-     * @returns {Promise<FileSystemElement[]>} returns an array of file system objects
-     */
-    public async getFileSystemElementByTags(tags: Tag[]): Promise<FileSystemElement[]> {
-        debug("getFileSystemElementByTags %s", tags.join(", "));
-        let filterRule: string = "";
- 
-        for (const tag of tags) {
-            filterRule += `<oc:systemtag>${tag.id}</oc:systemtag>`;
-        }
-        const urlSuffix = `/remote.php/dav/files/`;
-        const url = `${this.nextcloudOrigin}${urlSuffix}${this.userId}`;
-        const body = `<?xml version="1.0"?>
-        <oc:filter-files  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:getcontenttype />
-              <oc:fileid />
-           </d:prop>
-           <oc:filter-rules>
-                ${filterRule}
-           </oc:filter-rules>
-        </oc:filter-files>`;
-        const requestInit: RequestInit = {
-            body,
-            // headers: new Headers({ Depth: "0" }),
-            method: "REPORT",
-        };
-        let response: Response;
-        try {
-            response = await this.getHttpResponse(
-                url,
-                requestInit,
-                [207],
-                { description: "Get FileSystemElements by tags" },
-            );
- 
-        } catch (err) {
-            debug("Error in stat %s %s %s %s", err.message, requestInit.method, url);
-            throw err;
-        }
-        const result: FileSystemElement[] = [];
- 
-        let properties: any[] = [];
-        try {
-            properties = await this.getPropertiesFromWebDAVMultistatusResponse(response, "");
-        } catch (e) {
-            return result
-        }
- 
-        for (const prop of properties) {
-            let fse: FileSystemElement | null = null;
-            let name: string = prop._href;
- 
-            // remove the first two elements from the path
-            name = name.replace(urlSuffix, "");
-            const a: string[] = name.split("/")
-            a.shift();
-            name = "/" + a.join("/");
-            // console.log(name);
-            if (prop.getcontenttype) {
-                fse = await this.getFile(name);
-            } else {
-                fse = await this.getFolder(name);
-            }
- 
-            result.push(fse!);
- 
-        }
-        return result;
-    }
- 
-    /**
-     * get a folder object from a path string
-     * @param {string} folderName Name of the folder like "/company/branches/germany"
-     * @returns {Promise<Folder | null>} null if the folder does not exist or an folder object
-     */
-    public async getFolder(folderName: string): Promise<Folder | null> {
-        folderName = this.sanitizeFolderName(folderName);
-        debug("getFolder %s", folderName);
- 
-        // return root folder
-        if (folderName === "/" || folderName === "") {
-            return this.getRootFolder();
-        }
- 
-        try {
-            const stat: IStat = await this.stat(folderName);
-            debug(": SUCCESS!!");
-            if (stat.type !== "file") {
-                return new Folder(this,
-                    stat.filename.replace(/\\/g, "/"),
-                    stat.basename,
-                    stat.lastmod,
-                    stat.fileid);
-            } else {
-                debug("getFolder: found object is file not a folder");
-                return null;
-            }
-        } catch (e) {
-            debug("getFolder: exception occurred calling stat %O", e.message);
-            return null;
-        }
-    }
- 
-    /**
-     * get a array of folders from a folder path string
-     * @param folderName Name of the folder like "/company/branches/germany"
-     * @returns array of folder objects
-     */
-    public async getSubFolders(folderName: string): Promise<Folder[]> {
-        debug("getSubFolders: folder %s", folderName);
-        const folders: Folder[] = [];
-        folderName = this.sanitizeFolderName(folderName);
- 
-        const folderElements: any[] = await this.Contents(folderName, true);
- 
-        for (const folderElement of folderElements) {
-            debug("getSubFolders: adding subfolders %s", folderElement.filename);
-            folders.push(new Folder(this,
-                folderElement.filename.replace(/\\/g, "/"),
-                folderElement.basename,
-                folderElement.lastmod,
-                folderElement.fileid));
-        }
- 
-        return folders;
-    }
- 
-    /**
-     * get files of a folder
-     * @param {string} folderName Name of the folder like "/company/branches/germany"
-     * @param {FolderGetFilesOptions} options options for filtering and paging
-     * @returns array of file objects
-     */
-    public async getFiles(folderName: string, options?: FolderGetFilesOptions): Promise<File[]> {
-        debug("getFiles: folder %s", folderName);
-        const files: File[] = [];
-        folderName = this.sanitizeFolderName(folderName);
- 
-        const fileElements: any[] = await this.Contents(folderName, false);
- 
-        for (const folderElement of fileElements) {
-            debug("getFiles: adding file %s", folderElement.filename);
-            // debug("getFiles: adding file %O", folderElement);
-            let file: File | null = new File(this,
-                folderElement.filename.replace(/\\/g, "/"),
-                folderElement.basename,
-                folderElement.lastmod,
-                folderElement.size,
-                folderElement.mime,
-                folderElement.fileid);
- 
-            if (options && options.filterFile) {
-                file = options.filterFile(file);
-            }
-            if (file) {
-                files.push(file);
-            }
-        }
- 
-        return files;
-    }
- 
-    /**
-     * create a new file of overwrites an existing file
-     * @param fileName the file name /folder1/folder2/filename.txt
-     * @param data the buffer object
-     */
-    public async createFile(fileName: string, data: Buffer | NodeJS.ReadableStream): Promise<File> {
- 
-        if (fileName.startsWith("./")) {
-            fileName = fileName.replace("./", "/");
-        }
- 
-        const baseName: string = path.basename(fileName);
-        const folderName: string = path.dirname(fileName);
- 
-        debug("createFile folder name %s base name %s", folderName, baseName);
- 
-        // ensure that we have a folder
-        await this.createFolder(folderName);
-        await this.putFileContents(fileName, data);
- 
-        let file: File | null;
-        file = await this.getFile(fileName);
- 
-        if (!file) {
-            throw new ClientError(`Error creating file, file name "${fileName}"`, "ERR_CREATE_FILE_FAILED");
-        }
-        return file;
-    }
- 
-    /**
-     * returns a nextcloud file object
-     * @param fileName the full file name /folder1/folder2/file.pdf
-     */
-    public async getFile(fileName: string): Promise<File | null> {
-        debug("getFile fileName = %s", fileName);
- 
-        try {
-            const stat: IStat = await this.stat(fileName);
-            debug(": SUCCESS!!");
-            if (stat.type === "file") {
-                return new File(this,
-                    stat.filename.replace(/\\/g, "/"),
-                    stat.basename,
-                    stat.lastmod,
-                    stat.size!,
-                    stat.mime || "",
-                    stat.fileid || -1);
-            } else {
-                debug("getFile: found object is a folder not a file");
-                return null;
-            }
-        } catch (e) {
-            debug("getFile: exception occurred calling stat %O", e.message);
-            return null;
-        }
-    }
- 
-    /**
-     * renames the file or moves it to an other location
-     * @param sourceFileName source file name
-     * @param targetFileName target file name
-     */
-    public async moveFile(sourceFileName: string, targetFileName: string): Promise<File> {
- 
-        const url: string = this.webDAVUrl + sourceFileName;
-        const destinationUrl: string = this.webDAVUrl + targetFileName;
- 
-        debug("moveFile from '%s' to '%s'", url, destinationUrl);
- 
-        const requestInit: RequestInit = {
-            headers: new Headers({ Destination: destinationUrl }),
-            method: "MOVE",
-        };
-        try {
-            await this.getHttpResponse(
-                url,
-                requestInit,
-                [201],
-                { description: "File move" },
-            );
- 
-        } catch (err) {
-            debug("Error in move file %s %s source: %s destination: %s", err.message, requestInit.method, url, destinationUrl);
-            throw new ClientError("Error: moving file failed: source=" + sourceFileName + " target=" + targetFileName + " - " + err.message, "ERR_FILE_MOVE_FAILED");
-        }
- 
-        const targetFile: File | null = await this.getFile(targetFileName);
-        if (!targetFile) {
-            throw new ClientError("Error: moving file failed: source=" + sourceFileName + " target=" + targetFileName, "ERR_FILE_MOVE_FAILED");
-        }
- 
-        return targetFile;
-    }
- 
-    /**
-     * renames the folder or moves it to an other location
-     * @param sourceFolderName source folder name
-     * @param tarName target folder name
-     */
-    public async moveFolder(sourceFolderName: string, tarName: string): Promise<Folder> {
- 
-        const url: string = this.webDAVUrl + sourceFolderName;
-        const destinationUrl: string = this.webDAVUrl + tarName;
- 
-        debug("moveFolder from '%s' to '%s'", url, destinationUrl);
- 
-        const requestInit: RequestInit = {
-            headers: new Headers({ Destination: destinationUrl }),
-            method: "MOVE",
-        };
-        try {
-            await this.getHttpResponse(
-                url,
-                requestInit,
-                [201],
-                { description: "Folder move" },
-            );
- 
-        } catch (err) {
-            debug("Error in move folder %s %s source: %s destination: %s", err.message, requestInit.method, url, destinationUrl);
-            throw new ClientError("Error: moving folder failed: source=" + sourceFolderName + " target=" + tarName + " - " + err.message, "ERR_FOLDER_MOVE_FAILED");
-        }
- 
-        const tar: Folder | null = await this.getFolder(tarName);
-        if (!tar) {
-            throw new ClientError("Error: moving folder failed: source=" + sourceFolderName + " target=" + tarName, "ERR_FOLDER_MOVE_FAILED");
-        }
- 
-        return tar;
-    }
- 
-    /**
-     * returns the content of a file
-     * @param fileName name of the file /d1/file1.txt
-     * @returns Buffer with file content
-     */
-    public async getContent(fileName: string): Promise<Buffer> {
-        const url = this.webDAVUrl + fileName;
-        debug("getContent GET %s", url);
-        const requestInit: RequestInit = {
-            method: "GET",
-        };
-        let response: Response;
-        try {
-            response = await this.getHttpResponse(
-                url,
-                requestInit,
-                [200],
-                { description: "File get content" });
-        } catch (err) {
-            debug("Error getContent %s - error %s", url, err.message);
-            throw err;
-        }
- 
-        return Buffer.from(await response.buffer());
-    }
- 
-    /**
-     * returns the content of a file
-     * @param fileName name of the file /d1/file1.txt
-     * @returns Buffer with file content
-     */
-    public async pipeContentStream(fileName: string, destination: NodeJS.WritableStream): Promise<void> {
-        const url = this.webDAVUrl + fileName;
-        debug("getContent GET %s", url);
-        const requestInit: RequestInit = {
-            method: "GET",
-        };
-        let response: Response;
-        try {
-            response = await this.getHttpResponse(
-                url,
-                requestInit,
-                [200],
-                { description: "File pipe content stream" });
-        } catch (err) {
-            debug("Error getContent %s - error %s", url, err.message);
-            throw err;
-        }
-        response.body.pipe(destination);
-    }
- 
-    /**
-     * returns the link to a file for downloading
-     * @param fileName name of the file /folder1/folder1.txt
-     * @returns url
-     */
-    public getLink(fileName: string): string {
-        debug("getLink of %s", fileName);
-        return this.webDAVUrl + fileName;
-    }
- 
-    /**
-     * returns the url to the file in the nextcloud UI
-     * @param fileId the id of the file
-     */
-    public getUILink(fileId: number): string {
-        debug("getUILink of %s", fileId);
-        return `${this.nextcloudOrigin}/apps/files/?fileid=${fileId}`;
-    }
- 
-    /**
-     * adds a tag to a file or folder
-     * if the tag does not exist, it is automatically created
-     * if the tag is created, the user must have damin privileges
-     * @param fileId the id of the file
-     * @param tagName the name of the tag
-     * @returns nothing
-     * @throws Error
-     */
-    public async addTagToFile(fileId: number, tagName: string): Promise<void> {
-        debug("addTagToFile file:%s tag:%s", fileId, tagName);
-        const tag: Tag = await this.createTag(tagName);
- 
-        if (!tag.canAssign) {
-            throw new ClientError(`Error: No permission to assign tag "${tagName}" to file. Tag is not assignable`, "ERR_TAG_NOT_ASSIGNABLE");
-        }
- 
-        const addTagBody: any = {
-            canAssign: tag.canAssign,
-            id: tag.id,
-            name: tag.name,
-            userAssignable: tag.assignable,
-            userVisible: tag.visible,
-        };
- 
-        const requestInit: RequestInit = {
-            body: JSON.stringify(addTagBody, null, 4),
-            headers: new Headers({ "Content-Type": "application/json" }),
-            method: "PUT",
-        };
- 
-        await this.getHttpResponse(
-            `${this.nextcloudOrigin}/remote.php/dav/systemtags-relations/files/${fileId}/${tag.id}`,
-            requestInit,
-            [201, 409],
-            { description: "File add tag" }); // created or conflict
-    }
- 
-    // ***************************************************************************************
-    // activity
-    // ***************************************************************************************
-    /*
-    @todo to be refactored to eventing
- 
-    public async getActivities(): Promise<string[]> {
-        const result: string[] = [];
-        const requestInit: RequestInit = {
-            headers: new Headers({ "ocs-apirequest": "true" }),
-            method: "GET",
-        };
- 
-        const response: Response = await this.getHttpResponse(
-            this.nextcloudOrigin + "/ocs/v2.php/apps/activity/api/v2/activity/files?format=json&previews=false&since=97533",
-            requestInit,
-            [200],
-            { description: "Activities get" });
- 
-        const responseObject: any = await response.json();
-        // @todo
- 
-        for (const res of responseObject.ocs.data) {
-            debug(JSON.stringify({
-                acivityId: res.activity_id,
-                objects: res.objects,
-                type: res.type,
-            }, null, 4));
-        }
- 
-        // debug("getActivities: responseObject %s", JSON.stringify(responseObject, null, 4));
- 
-        return result;
-    }
-*/
-    // ***************************************************************************************
-    // comments
-    // ***************************************************************************************
- 
-    /**
-     * adds a comment to a file
-     * @param fileId the id of the file
-     * @param comment the comment to be added to the file
-     */
-    public async addCommentToFile(fileId: number, comment: string): Promise<void> {
-        debug("addCommentToFile file:%s comment:%s", fileId, comment);
- 
-        const addCommentBody: any = {
-            actorType: "users",
-            message: comment,
-            objectType: "files",
-            verb: "comment",
-        };
- 
-        const requestInit: RequestInit = {
-            body: JSON.stringify(addCommentBody, null, 4),
-            headers: new Headers({ "Content-Type": "application/json" }),
-            method: "POST",
-        };
- 
-        await this.getHttpResponse(
-            `${this.nextcloudOrigin}/remote.php/dav/comments/files/${fileId}`,
-            requestInit,
-            [201],
-            { description: "File add comment" }); // created
-    }
- 
-    /**
-     * returns comments of a file / folder
-     * @param fileId the id of the file / folder
-     * @param top number of comments to return
-     * @param skip the offset
-     * @returns array of comment strings
-     * @throws Exception
-     */
-    public async getFileComments(fileId: number, top?: number, skip?: number): Promise<string[]> {
-        debug("getFileComments fileId:%s", fileId);
-        if (!top) {
-            top = 30;
-        }
- 
-        if (!skip) {
-            skip = 0;
-        }
- 
-        const requestInit: RequestInit = {
-            body: `<?xml version="1.0" encoding="utf-8" ?>
-                    <oc:filter-comments xmlns:D="DAV:" xmlns:oc="http://owncloud.org/ns">
-                        <oc:limit>${top}</oc:limit>
-                        <oc:offset>${skip}</oc:offset>
-                    </oc:filter-comments>`,
-            method: "REPORT",
-        };
- 
-        const response: Response = await this.getHttpResponse(
-            `${this.nextcloudOrigin}/remote.php/dav/comments/files/${fileId}`,
-            requestInit,
-            [207],
-            { description: "File get comments" });
- 
-        const properties: any[] = await this.getPropertiesFromWebDAVMultistatusResponse(response, "");
-        const comments: string[] = [];
-        for (const prop of properties) {
-            comments.push(prop.message);
-        }
- 
-        return comments;
-    }
- 
-    /**
-     * returns system information about the nextcloud server and the nextcloud client
-     */
-    public async getSystemInfo(): Promise<ISystemInfo> {
-        const requestInit: RequestInit = {
-            headers: this.getOcsHeaders(),
-            method: "GET",
-        };
- 
-        const response: Response = await this.getHttpResponse(
-            this.nextcloudOrigin + "/ocs/v2.php/apps/serverinfo/api/v1/info",
-            requestInit,
-            [200],
-            { description: "SystemInfo get" });
- 
-        const rawResult: any = await response.json();
-        // validate the raw result
-        let system = {};
-        let storage = {};
-        let shares = {};
-        let server = {};
-        let activeUsers = {};
- 
-        if (rawResult && rawResult.ocs && rawResult.ocs.data) {
-            if (rawResult.ocs.data.nextcloud) {
-                if (rawResult.ocs.data.nextcloud.system) {
-                    system = rawResult.ocs.data.nextcloud.system;
-                } else {
-                    throw new ClientError("Fatal Error: nextcloud data.nextcloud.system missing", "ERR_SYSTEM_INFO_MISSING_DATA");
-                }
- 
-                if (rawResult.ocs.data.nextcloud.storage) {
-                    storage = rawResult.ocs.data.nextcloud.storage;
-                } else {
-                    throw new ClientError("Fatal Error: nextcloud data.nextcloud.storage missing", "ERR_SYSTEM_INFO_MISSING_DATA");
-                }
- 
-                if (rawResult.ocs.data.nextcloud.shares) {
-                    shares = rawResult.ocs.data.nextcloud.shares;
-                } else {
-                    throw new ClientError("Fatal Error: nextcloud data.nextcloud.shares missing", "ERR_SYSTEM_INFO_MISSING_DATA");
-                }
-            } else {
-                throw new ClientError("Fatal Error: nextcloud data.nextcloud missing", "ERR_SYSTEM_INFO_MISSING_DATA");
-            }
- 
-            if (rawResult.ocs.data.server) {
-                server = rawResult.ocs.data.server;
-            } else {
-                throw new ClientError("Fatal Error: nextcloud data.server missing", "ERR_SYSTEM_INFO_MISSING_DATA");
-            }
- 
-            if (rawResult.ocs.data.activeUsers) {
-                activeUsers = rawResult.ocs.data.activeUsers;
-            } else {
-                throw new ClientError("Fatal Error: nextcloud data.activeUsers missing", "ERR_SYSTEM_INFO_MISSING_DATA");
-            }
- 
-        } else {
-            throw new ClientError("Fatal Error: nextcloud system data missing", "ERR_SYSTEM_INFO_MISSING_DATA");
-        }
- 
-        const result: ISystemInfo = {
-            activeUsers,
-            nextcloud:
-            {
-                shares,
-                storage,
-                system,
-            },
-            nextcloudClient:
-            {
-                version: require("../package.json").version,
-            },
-            server,
-        };
-        return result;
-    }
- 
-    public async getSystemBasicData(): Promise<ISysBasicData> {
-        const requestInit: RequestInit = {
-            headers: this.getOcsHeaders(),
-            method: "GET",
-        };
- 
-        const response: Response = await this.getHttpResponse(
-            this.nextcloudOrigin + "/ocs/v2.php/apps/serverinfo/api/v1/basicdata",
-            requestInit,
-            [200],
-            { description: "System Basic Data get" });
- 
-        const rawResult: any = await response.json();
-        // console.log("Basic Data\n", JSON.stringify(rawResult));
-        let result: ISysBasicData;
- 
-        if (rawResult &&
-            rawResult.ocs &&
-            rawResult.ocs.data &&
-            rawResult.ocs.data.servertime &&
-            rawResult.ocs.data.uptime &&
-            rawResult.ocs.data.timeservers) {
-            result = {
-                serverTimeString: rawResult.ocs.data.servertime.replace("\n", ""),
-                uptimeString: rawResult.ocs.data.uptime.replace("\n", ""),
-                timeServersString: rawResult.ocs.data.timeservers.trim(),
-            }
-        } else {
-            throw new ClientError("Fatal Error: nextcloud basic data missing", "ERR_SYSTEM_INFO_MISSING_DATA");
-        }
- 
-        return result;
-    }
- 
-    // ***************************************************************************************
-    // user management
-    // ***************************************************************************************
- 
-    // ***************************************************************************************
-    // user group
-    // spec: https://docs.nextcloud.com/server/latest/admin_manual/configuration_user/instruction_set_for_groups.html
-    // ***************************************************************************************
- 
-    /**
-     * returns a list of user groups
-     * @param search string
-     * @param limit number
-     * @param offset number
-     * @returns list of user groups
-     * @throws QueryLimitError
-     * @throws QueryOffsetError
-     */
-    public async getUserGroups(search?: string, limit?: number, offset?: number): Promise<UserGroup[]> {
-        debug("getUserGroups");
- 
-        const userGroupIds: string[] = await this.getUserGroupIds(search, limit, offset);
-        const userGroups: UserGroup[] = [];
-        for (const userGroupId of userGroupIds) {
-            userGroups.push(new UserGroup(this, userGroupId));
-        }
-        return userGroups;
-    }
- 
-    /**
-     * returns a list of user groups
-     * @param search string
-     * @param limit number
-     * @param offset number
-     * @returns list of user groups
-     * @throws QueryLimitError
-     * @throws QueryOffsetError
-     */
-    public async getUserGroupIds(search?: string, limit?: number, offset?: number): Promise<string[]> {
-        debug("getUserGroupIds");
-        const requestInit: RequestInit = {
-            headers: this.getOcsHeaders(),
-            method: "GET",
-        };
- 
-        let url = this.getOcsUrl(`/groups`);
-        const queryParameter: string[] = [];
-        if (search) {
-            queryParameter.push(`search=${search}`);
-        }
-        if (limit) {
-            if (limit < 1) {
-                throw new QueryLimitError("The limit must be larger than 0");
-            }
-            queryParameter.push(`limit=${limit}`);
-        }
-        if (offset) {
-            if (offset < 1) {
-                throw new QueryOffsetError("The offset must be larger than 0");
-            }
-            queryParameter.push(`offset=${offset}`);
-        }
-        if (queryParameter.join("&").length > 1) {
-            url += "?" + queryParameter.join("&");
-        }
-        debug("url ", url)
- 
-        const response: Response = await this.getHttpResponse(
-            url,
-            requestInit,
-            [200],
-            { description: "User Groups get" });
-        const rawResult: any = await response.json();
-        /*
-        {
-          ocs: {
-            meta: {
-              status: 'ok',
-              statuscode: 100,
-              message: 'OK',
-              totalitems: '',
-              itemsperpage: ''
-            },
-            data: { groups: ["g1", "g2"] }
-          }
-        }
-        */
-        const userGroups: string[] = [];
- 
-        if (rawResult.ocs &&
-            rawResult.ocs.data &&
-            rawResult.ocs.data.groups) {
-            debug("groups", rawResult.ocs.data.groups);
-            rawResult.ocs.data.groups.forEach((value: string) => {
-                // userGroups.push(new UserGroup(this, value));
-                userGroups.push(value);
-            });
-        }
-        return userGroups;
-    }
- 
-    /**
-     * get user group
-     * @param id string
-     * @returns Promise<UserGroup|null>
-     */
-    public async getUserGroup(id: string): Promise<UserGroup | null> {
-        const userGroups: UserGroup[] = await this.getUserGroups(id);
-        if (userGroups[0]) {
-            return userGroups[0];
-        }
-        return null
-    }
- 
-    /**
-     * returns a list of user ids that are members of the user group
-     * @param id string
-     * @returns list of member user ids
-     * @throws [UserGroupDoesNotExistError}
-     */
-    public async getUserGroupMembers(id: string): Promise<string[]> {
-        debug("getUserGroupMembers");
-        const requestInit: RequestInit = {
-            headers: this.getOcsHeaders(),
-            method: "GET",
-        };
- 
-        const url = this.getOcsUrl(`/groups/${id}`);
-        debug("url ", url)
- 
-        const response: Response = await this.getHttpResponse(
-            url,
-            requestInit,
-            [200],
-            { description: "User group get members" });
-        const rawResult: any = await response.json();
-        const userIds: string[] = [];
- 
-        if (this.getOcsMetaStatus(rawResult).code === 404) {
-            throw new UserGroupDoesNotExistError(`User Group ${id} does not exist`);
-        }
- 
-        if (rawResult.ocs &&
-            rawResult.ocs.data &&
-            rawResult.ocs.data.users) {
-            debug("members", rawResult.ocs.data.users);
-            rawResult.ocs.data.users.forEach((value: string) => {
-                userIds.push(value);
-            });
-        }
- 
-        return userIds;
-    }
- 
-    /**
-     * returns a list of user ids that are subadmins of the user group
-     * @param id string
-     * @returns list of subadmin user ids
-     * @throws [UserGroupDoesNotExistError}
-     */
-    public async getUserGroupSubadmins(id: string): Promise<string[]> {
-        debug("getUserGroupsubadmins");
-        const requestInit: RequestInit = {
-            headers: this.getOcsHeaders(),
-            method: "GET",
-        };
- 
-        const url = this.getOcsUrl(`/groups/${id}/subadmins`);
-        debug("url ", url)
- 
-        const response: Response = await this.getHttpResponse(
-            url,
-            requestInit,
-            [200],
-            { description: "User group get subadmins" });
-        const rawResult: any = await response.json();
-        const userIds: string[] = [];
- 
-        if (this.getOcsMetaStatus(rawResult).code === 101) {
-            throw new UserGroupDoesNotExistError(`User Group ${id} does not exist`);
-        }
- 
-        if (rawResult.ocs &&
-            rawResult.ocs.data) {
-            debug("subadmins", rawResult.ocs.data);
-            rawResult.ocs.data.forEach((value: string) => {
-                userIds.push(value);
-            });
-        }
- 
-        return userIds;
-    }
- 
-    /**
-     * create a new user group
-     * @async
-     * @param {string} id user group id
-     * @returns {Promise<UserGroup>}
-     * @throws {UserGroupAlreadyExistsError}
-     */
-    public async createUserGroup(id: string): Promise<UserGroup> {
-        debug("createUserGroup id=", id);
-        const requestInit: RequestInit = {
-            body: JSON.stringify({ groupid: id }),
-            headers: this.getOcsHeaders(),
-            method: "POST",
-        };
-        debug("request body: ", requestInit.body);
-        const response: Response = await this.getHttpResponse(
-            this.getOcsUrl(`/groups`),
-            requestInit,
-            [200],
-            { description: "UserGroup create" });
-        const rawResult: any = await response.json();
- 
-        if (this.getOcsMetaStatus(rawResult).code === 102) {
-            throw new UserGroupAlreadyExistsError(`User Group ${id} already exists`);
-        }
- 
-        if (this.getOcsMetaStatus(rawResult).code === 100) {
-            return new UserGroup(this, id);
-        }
-        throw new OperationFailedError(`User group ${id} could not be created: ${this.getOcsMetaStatus(rawResult).message}`);
-    }
- 
-    /**
-     * deletes an existing user group
-     * @param id string
-     * @returns {Promise<void>}
-     * @throws {UserGroupDowsNotExistError}
-     * @throws {UserGroupDeletionFailedError}
-     */
-    public async deleteUserGroup(id: string): Promise<void> {
-        debug("deleteUserGroup id=", id);
-        const requestInit: RequestInit = {
-            headers: this.getOcsHeaders(),
-            method: "DELETE",
-        };
-        debug("request body: ", requestInit.body);
-        const response: Response = await this.getHttpResponse(
-            this.getOcsUrl(`/groups/${id}`),
-            requestInit,
-            [200],
-            { description: "UserGroup delete" });
-        const rawResult: any = await response.json();
- 
-        if (this.getOcsMetaStatus(rawResult).code === 101) {
-            throw new UserGroupDoesNotExistError(`User Group ${id} does not exists`);
-        }
- 
-        if (this.getOcsMetaStatus(rawResult).code === 102) {
-            throw new UserGroupDeletionFailedError(`User Group ${id} could not be deleted`);
-        }
-    }
- 
-    // ***************************************************************************************
-    // user
-    // spec: https://docs.nextcloud.com/server/latest/admin_manual/configuration_user/instruction_set_for_users.html
-    // ***************************************************************************************
- 
-    /**
-     * returns a list of users
-     * https://docs.nextcloud.com/server/latest/admin_manual/configuration_user/instruction_set_for_users.html#search-get-users
-     * @param search string
-     * @param limit number
-     * @param offset number
-     */
-    public async getUsers(search?: string, limit?: number, offset?: number): Promise<User[]> {
-        debug("getUsers");
-        const requestInit: RequestInit = {
-            headers: this.getOcsHeaders(),
-            method: "GET",
-        };
- 
-        let url = this.getOcsUrl(`/users`);
-        const queryParameter: string[] = [];
-        if (search) {
-            queryParameter.push(`search=${search}`);
-        }
-        if (limit) {
-            if (limit < 1) {
-                throw new QueryLimitError("The limit must be larger than 0");
-            }
-            queryParameter.push(`limit=${limit}`);
-        }
-        if (offset) {
-            if (offset < 1) {
-                throw new QueryOffsetError("The offset must be larger than 0");
-            }
-            queryParameter.push(`offset=${offset}`);
-        }
-        if (queryParameter.join("&").length > 1) {
-            url += "?" + queryParameter.join("&");
-        }
-        debug("url ", url)
- 
-        const response: Response = await this.getHttpResponse(
-            url,
-            requestInit,
-            [200],
-            { description: "Users get" });
-        const rawResult: any = await response.json();
-        /*
-        {
-          ocs: {
-            meta: {
-              status: 'ok',
-              statuscode: 100,
-              message: 'OK',
-              totalitems: '',
-              itemsperpage: ''
-            },
-            data: { users: ["u1", "u2"] }
-          }
-        }
-        */
-        const users: User[] = [];
- 
-        if (rawResult.ocs &&
-            rawResult.ocs.data &&
-            rawResult.ocs.data.users) {
-            debug("user ids", rawResult.ocs.data.users);
-            rawResult.ocs.data.users.forEach((value: string) => {
-                users.push(new User(this, value));
-            });
-        }
- 
-        return users;
-    }
- 
-    /**
-     * returns user data
-     * @param id string the user id
-     * @returns Promise<IUserOptions> user data
-     * @throws {UserNotFoundError}
-     */
-    public async getUserData(id: string): Promise<IUserOptions> {
-        debug("getUserData");
-        const requestInit: RequestInit = {
-            headers: this.getOcsHeaders(),
-            method: "GET",
-        };
- 
-        const url = this.getOcsUrl(`/users/${id}`);
-        debug("url ", url)
- 
-        const response: Response = await this.getHttpResponse(
-            url,
-            requestInit,
-            [200],
-            { description: `User ${id} get` });
-        const rawResult: any = await response.json();
- 
-        if (this.getOcsMetaStatus(rawResult).code === 404) {
-            throw new UserNotFoundError(`User '${id}' not found`);
-        }
-        /*
-        {
-          ocs: {
-            meta: {
-              status: 'ok',
-              statuscode: 100,
-              message: 'OK',
-              totalitems: '',
-              itemsperpage: ''
-            },
-            data: { ... }
-          }
-        }
-        */
- 
-        let userData: IUserOptions;
-        debug("user data", rawResult.ocs.data);
-        userData = {
-            enabled: rawResult.ocs.data.enabled,
-            lastLogin: rawResult.ocs.data.lastLogin === 0 ? undefined : new Date(rawResult.ocs.data.lastLogin),
-            subadminGroups: rawResult.ocs.data.subadmin,
-            memberGroups: rawResult.ocs.data.groups,
-            quota: {
-                free: 0,
-                used: 0,
-                total: 0,
-                relative: 0,
-                quota: 0
-            },
-            email: rawResult.ocs.data.email,
-            displayName: rawResult.ocs.data.displayname,
-            phone: rawResult.ocs.data.phone,
-            address: rawResult.ocs.data.address,
-            website: rawResult.ocs.data.website,
-            twitter: rawResult.ocs.data.twitter,
-            language: rawResult.ocs.data.language,
-            locale: rawResult.ocs.data.locale,
-        };
-        if (rawResult.ocs.data.quota.quota === 'none') {
-            userData.quota = { quota: 0, relative: 0, used: 0 };
-        } else {
-            if (!rawResult.ocs.data.quota.relative) {
-                rawResult.ocs.data.quota.relative = 0;
-            }
-            userData.quota = { quota: rawResult.ocs.data.quota.quota, relative: rawResult.ocs.data.quota.relative, used: rawResult.ocs.data.quota.used };
-            if (rawResult.ocs.data.quota.free) {
-                userData.quota.free = rawResult.ocs.data.quota.free;
-            }
-            if (rawResult.ocs.data.quota.total) {
-                userData.quota.total = rawResult.ocs.data.quota.total;
-            }
-        }
-        return userData;
-    }
- 
-    /**
-     * enables the user
-     * @param id string the user id
-     * @returns {Promise<void>}
-     * @throws {UserNotFoundError}
-     */
-    public async enableUser(id: string): Promise<void> {
-        debug("enableUser");
-        const requestInit: RequestInit = {
-            headers: this.getOcsHeaders(),
-            method: "PUT",
-        };
- 
-        const url = this.getOcsUrl(`/users/${id}/enable`);
-        debug("url ", url)
- 
-        const response: Response = await this.getHttpResponse(
-            url,
-            requestInit,
-            [200],
-            { description: `User ${id} enable` });
-        const rawResult: any = await response.json();
- 
-        if (this.getOcsMetaStatus(rawResult).code === 100) {
-            return
-        }
-        throw new UserNotFoundError(`User '${id}' not found`);
-    }
- 
-    /**
-     * disables the user
-     * @param id string the user id
-     * @returns {Promise<void>}
-     * @throws {UserNotFoundError}
-     */
-    public async disableUser(id: string): Promise<void> {
-        debug("disableUser");
-        const requestInit: RequestInit = {
-            headers: this.getOcsHeaders(),
-            method: "PUT",
-        };
- 
-        const url = this.getOcsUrl(`/users/${id}/disable`);
-        debug("url ", url)
- 
-        const response: Response = await this.getHttpResponse(
-            url,
-            requestInit,
-            [200],
-            { description: `User ${id} disable` });
-        const rawResult: any = await response.json();
- 
-        if (this.getOcsMetaStatus(rawResult).code === 100) {
-            return
-        }
-        throw new UserNotFoundError(`User '${id}' not found`);
-    }
- 
-    /**
-     * deletes the user
-     * @param id string the user id
-     * @returns {Promise<void>}
-     * @throws {UserNotFoundError}
-     */
-    public async deleteUser(id: string): Promise<void> {
-        debug("deleteUser");
-        const requestInit: RequestInit = {
-            headers: this.getOcsHeaders(),
-            method: "DELETE",
-        };
- 
-        const url = this.getOcsUrl(`/users/${id}`);
-        debug("url ", url)
- 
-        const response: Response = await this.getHttpResponse(
-            url,
-            requestInit,
-            [200],
-            { description: `User ${id} delete` });
-        const rawResult: any = await response.json();
- 
-        if (this.getOcsMetaStatus(rawResult).code === 100) {
-            return
-        }
-        throw new UserNotFoundError(`User '${id}' not found`);
-    }
- 
-    /**
-     * returns a user or null if not found
-     * @param id string
-     * @returns User | null
-     */
-    public async getUser(id: string): Promise<User | null> {
-        debug("getUser");
-        const users: User[] = await this.getUsers(id);
-        if (users[0]) {
-            return users[0];
-        }
-        return null;
-    }
- 
-    /**
-     * creates a new user with email or password
-     * @param options
-     * @returns User
-     * @throws UserAlreadyExistsError
-     * @throws {UserNotFoundError}
-     * @throws UserUpdateError
-     */
-    public async createUser(options: { id: string, email?: string, password?: string }): Promise<User> {
-        debug("createUser");
-        const createUserBody: { userid: string, password?: string, email?: string } = { userid: options.id };
-        if (options.email) {
-            if (/^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(options.email)) {
-                createUserBody.email = options.email;
-            } else {
-                throw new UserCreateError(`Error creating user '${options.id}' - invalid email address '${options.email}'`);
-            }
-        }
-        if (options.password) {
-            createUserBody.password = options.password;
-        }
- 
-        const requestInit: RequestInit = {
-            body: JSON.stringify(createUserBody, null, 4),
-            headers: this.getOcsHeaders(),
-            method: "POST",
-        };
-        debug("request body: ", requestInit.body);
-        const response: Response = await this.getHttpResponse(
-            this.getOcsUrl(`/users`),
-            requestInit,
-            [200],
-            { description: `User ${options.id} create` });
-        const rawResult: any = await response.json();
- 
-        if (this.getOcsMetaStatus(rawResult).code === 102) {
-            throw new UserAlreadyExistsError(`User with id '${options.id}' already exists`);
-        }
- 
-        const user: User | null = await this.getUser(options.id);
-        if (user) {
-            return user;
-        }
- 
-        throw new UserCreateError(`Error creating user '${options.id}' - ${this.getOcsMetaStatus(rawResult).message} (${this.getOcsMetaStatus(rawResult).code})`);
-    }
- 
-    /**
-     * updates a user property
-     * @async
-     * @param {string} id user id
-     * @param {UserProperty} property property name
-     * @param {string} value property value
-     * @returns {Promise<void>}
-     * @throws  {UserNotFoundError}
-     * @throws  {UserUpdateError}
-     */
-    public async updateUserProperty(id: string, property: UserProperty, value: string): Promise<void> {
-        debug("updateUserProperty");
-        const body: { key: string, value: string } = { key: property, value };
- 
-        const requestInit: RequestInit = {
-            body: JSON.stringify(body, null, 4),
-            headers: this.getOcsHeaders(),
-            method: "PUT",
-        };
-        const url = this.getOcsUrl(`/users/${id}`);
-        debug("request body: ", requestInit.body);
-        const response: Response = await this.getHttpResponse(
-            url,
-            requestInit,
-            [200, 401],
-            { description: `User ${id} update ${property}=${value}` });
-        const rawResult: any = await response.json();
- 
-        // This service operation returns a 401, if the user does not exist - very strange...
-        // spec says to return 200 and status code 101
-        /*
-        if (this.getOcsMetaStatus(rawResult).code === 101) {
-            throw new UserNotFoundError(`User with id '${id}' not found`);
-        }
-        */
-        // maybe this is due to a nextcloud api error
-        // it is not possible to distiguish beteen authentication error and user not found :-(
-        if (response.status === 401) {
-            throw new UserNotFoundError(`User with id '${id}' not found`);
-        }
- 
-        if (this.getOcsMetaStatus(rawResult).code === 100) {
-            return;
-        }
- 
-        if (property === UserProperty.password) {
-            value = "********";
-        }
-        // code 102 or 103
-        throw new UserUpdateError(`User with id '${id}' could not be updated - ${property}=${value}. ${rawResult.ocs.meta.message}`);
-    }
- 
-    /**
-     * resend the welcome email
-     * @param id user id
-     * @throws  {UserResendWelcomeEmailError}
-     */
-    public async resendWelcomeEmail(id: string,): Promise<void> {
-        debug("resendWelcomeEmail");
- 
-        const requestInit: RequestInit = {
-            headers: this.getOcsHeaders(),
-            method: "POST",
-        };
-        const url = this.getOcsUrl(`/users/${id}/welcome`);
-        debug("request body: ", requestInit.body);
-        const response: Response = await this.getHttpResponse(
-            url,
-            requestInit,
-            [200],
-            { description: `Resend welcome email for user ${id}` });
-        const rawResult: any = await response.json();
- 
-        if (this.getOcsMetaStatus(rawResult).code === 101) {
-            throw new UserResendWelcomeEmailError(`Error sending welcome email for '${id}': Email address not available`);
-        }
- 
-        if (this.getOcsMetaStatus(rawResult).code === 100) {
-            return;
-        }
-        throw new UserResendWelcomeEmailError(`Error sending welcome email for '${id}' failed`);
-    }
- 
-    /**
-     * adds a user to a group as member
-     * @param id string the user id
-     * @param userGroupId string the user group id
-     * @returns {Promise<void>}
-     * @throws {UserNotFoundError}
-     * @throws {UserGroupDoesNotExistError}
-     * @throws {InsufficientPrivilegesError}
-     * @throws {OperationFailedError}
-     */
-    public async addUserToMemberUserGroup(id: string, userGroupId: string): Promise<void> {
-        debug("addUserToUserGroup");
- 
-        const body: { groupid: string } = { groupid: userGroupId };
-        const requestInit: RequestInit = {
-            body: JSON.stringify(body, null, 4),
-            headers: this.getOcsHeaders(),
-            method: "POST",
-        };
- 
-        const url = this.getOcsUrl(`/users/${id}/groups`);
-        debug("url ", url)
- 
-        const response: Response = await this.getHttpResponse(
-            url,
-            requestInit,
-            [200],
-            { description: `Add user ${id} to user group ${userGroupId}` });
-        const rawResult: any = await response.json();
- 
-        if (this.getOcsMetaStatus(rawResult).code === 100) {
-            return
-        }
- 
-        if (this.getOcsMetaStatus(rawResult).code === 102) {
-            throw new UserGroupDoesNotExistError(`User group ${userGroupId} does not exist`)
-        }
- 
-        if (this.getOcsMetaStatus(rawResult).code === 103) {
-            throw new UserNotFoundError(`User ${id} does not exist`)
-        }
- 
-        if (this.getOcsMetaStatus(rawResult).code === 104) {
-            throw new InsufficientPrivilegesError(`Insufficient privileges to add a user to a group`);
-        }
- 
-        throw new OperationFailedError(`User ${id} could not be added to user group ${userGroupId}: ${this.getOcsMetaStatus(rawResult).message}`);
-    }
- 
-    /**
-     * removes a user from a group as member
-     * @param id string the user id
-     * @param userGroupId string the user group id
-     * @returns {Promise<void>}
-     * @throws {UserNotFoundError}
-     * @throws {UserGroupDoesNotExistError}
-     * @throws {InsufficientPrivilegesError}
-     * @throws {OperationFailedError}
-     */
-    public async removeUserFromMemberUserGroup(id: string, userGroupId: string): Promise<void> {
-        debug("removeUserFromMemberUserGroup");
- 
-        const body: { groupid: string } = { groupid: userGroupId };
-        const requestInit: RequestInit = {
-            body: JSON.stringify(body, null, 4),
-            headers: this.getOcsHeaders(),
-            method: "DELETE",
-        };
- 
-        const url = this.getOcsUrl(`/users/${id}/groups`);
-        debug("url ", url)
- 
-        const response: Response = await this.getHttpResponse(
-            url,
-            requestInit,
-            [200],
-            { description: `Remove user ${id} from user group ${userGroupId}` });
-        const rawResult: any = await response.json();
- 
-        if (this.getOcsMetaStatus(rawResult).code === 100) {
-            return
-        }
- 
-        if (this.getOcsMetaStatus(rawResult).code === 102) {
-            throw new UserGroupDoesNotExistError(`User group ${userGroupId} does not exist`)
-        }
- 
-        if (this.getOcsMetaStatus(rawResult).code === 103) {
-            throw new UserNotFoundError(`User ${id} does not exist`)
-        }
- 
-        if (this.getOcsMetaStatus(rawResult).code === 104) {
-            throw new InsufficientPrivilegesError(`Insufficient privileges to add a user to a group`);
-        }
- 
-        throw new OperationFailedError(`User ${id} could not be added to user group ${userGroupId}: ${this.getOcsMetaStatus(rawResult).message}`);
-    }
- 
-    /**
-     * promotes a user to a user group subadmin
-     * @param id string the user id
-     * @param userGroupId string the user group id
-     * @returns {Promise<void>}
-     * @throws {UserNotFoundError}
-     * @throws {UserGroupDoesNotExistError}
-     * @throws {InsufficientPrivilegesError}
-     * @throws {OperationFailedError}
-     */
-    public async promoteUserToUserGroupSubadmin(id: string, userGroupId: string): Promise<void> {
-        debug("promoteUserToUserGroupSubadmin");
- 
-        const body: { groupid: string } = { groupid: userGroupId };
-        const requestInit: RequestInit = {
-            body: JSON.stringify(body, null, 4),
-            headers: this.getOcsHeaders(),
-            method: "POST",
-        };
- 
-        const url = this.getOcsUrl(`/users/${id}/subadmins`);
-        debug("url ", url)
- 
-        const response: Response = await this.getHttpResponse(
-            url,
-            requestInit,
-            [200],
-            { description: `Promote User ${id} to user group subadmin ${userGroupId}` });
-        const rawResult: any = await response.json();
- 
-        if (this.getOcsMetaStatus(rawResult).code === 100) {
-            return
-        }
- 
-        if (this.getOcsMetaStatus(rawResult).code === 102) {
-            throw new UserGroupDoesNotExistError(`User group ${userGroupId} does not exist`)
-        }
- 
-        if (this.getOcsMetaStatus(rawResult).code === 101) {
-            throw new UserNotFoundError(`User ${id} does not exist`)
-        }
- 
-        if (this.getOcsMetaStatus(rawResult).code === 104) {
-            throw new InsufficientPrivilegesError(`Insufficient privileges to add a user to a group`);
-        }
- 
-        throw new OperationFailedError(`User ${id} could not be removed from user group ${userGroupId}: ${this.getOcsMetaStatus(rawResult).message}`);
-    }
- 
-    /**
-     * Removes the subadmin rights for the user specified from the group specified
-     * @param id string the user id
-     * @param userGroupId string the user group id
-     * @returns {Promise<void>}
-     * @throws {InsufficientPrivilegesError}
-     * @throws {OperationFailedError}
-     */
-    public async demoteUserFromSubadminUserGroup(id: string, userGroupId: string): Promise<void> {
-        debug("demoteUserFromSubadminUserGroup");
- 
-        const body: { groupid: string } = { groupid: userGroupId };
-        const requestInit: RequestInit = {
-            body: JSON.stringify(body, null, 4),
-            headers: this.getOcsHeaders(),
-            method: "DELETE",
-        };
- 
-        const url = this.getOcsUrl(`/users/${id}/subadmins`);
-        debug("url ", url)
- 
-        const response: Response = await this.getHttpResponse(
-            url,
-            requestInit,
-            [200],
-            { description: `Demotes user ${id} from subadmin user group ${userGroupId}` });
-        const rawResult: any = await response.json();
- 
-        if (this.getOcsMetaStatus(rawResult).code === 100) {
-            return
-        }
- 
-        // this API does not work like remove from group :-(
-        // 101 is for user group not found and user not found
-        /*
-            if (this.getOcsMetaStatus(rawResult).code === 101) {
-                throw new UserGroupDoesNotExistError(`User group ${userGroupId} does not exist`)
-            }
- 
-            if (this.getOcsMetaStatus(rawResult).code === 101) {
-                throw new UserNotFoundError(`User ${id} does not exist`)
-            }
-        */
-        if (this.getOcsMetaStatus(rawResult).code === 104) {
-            throw new InsufficientPrivilegesError(`Insufficient privileges to add a user to a group`);
-        }
- 
-        throw new OperationFailedError(`User ${id} could not be demoted from subadmin user group ${userGroupId}: ${this.getOcsMetaStatus(rawResult).message}`);
-    }
- 
- 
-    /**
-     * insert or update complete user data
-     * @param options IUpsertUserOptions[]
-     * @returns Promise<IUpsertUserReport[]
-     */
-    public async upsertUsers(options: IUpsertUserOptions[]): Promise<IUpsertUserReport[]> {
-        const report: IUpsertUserReport[] = [];
-        for (const option of options) {
-            const userReport: IUpsertUserReport = { id: option.id, message: "", changes: [] };
-            let user: User | null = await this.getUser(option.id);
-            // create or update user?
- 
-            if (!user) {
-                try {
-                    user = await this.createUser({ id: option.id, email: option.email, password: option.password })
-                    userReport.message = `User ${option.id} created`;
-                } catch (e) {
-                    userReport.message = `Create user ${option.id} failed ${e.message}`;
-                    report.push(userReport);
-                    continue;
-                }
-            } else {
-                userReport.message = `User ${option.id} changed`;
-            }
- 
-            let previousValue: string = "";
-            let newValue: string = "";
-            let property: string = "";
- 
-            // ************************
-            // enabled
-            // ************************
-            if (option.enabled !== undefined) {
-                if (await user.isEnabled() && option.enabled === false) {
-                    try {
-                        await user.disable();
-                        userReport.changes.push({ property: "enabled", previousValue: "true", newValue: "false" });
-                    } catch (e) {
-                        userReport.changes.push({ property: "enabled", previousValue: "true", newValue: "true", error: e.message });
-                    }
-                }
- 
-                if (await user.isEnabled() === false && option.enabled === true) {
-                    try {
-                        await user.enable();
-                        userReport.changes.push({ property: "enabled", previousValue: "false", newValue: "true" });
-                    } catch (e) {
-                        userReport.changes.push({ property: "enabled", previousValue: "false", newValue: "false", error: e.message });
-                    }
-                }
-            }
- 
-            // ************************
-            // super admin
-            // ************************
-            if (option.superAdmin !== undefined) {
-                if (await user.isSuperAdmin() && option.superAdmin === false) {
-                    try {
-                        await user.demoteFromSuperAdmin();
-                        userReport.changes.push({ property: "superAdmin", previousValue: "true", newValue: "false" });
-                    } catch (e) {
-                        userReport.changes.push({ property: "superAdmin", previousValue: "true", newValue: "true", error: e.message });
-                    }
-                }
- 
-                if (await user.isSuperAdmin() === false && option.superAdmin === true) {
-                    try {
-                        await user.promoteToSuperAdmin();
-                        userReport.changes.push({ property: "superAdmin", previousValue: "false", newValue: "true" });
-                    } catch (e) {
-                        userReport.changes.push({ property: "superAdmin", previousValue: "false", newValue: "false", error: e.message });
-                    }
-                }
-            }
- 
-            // ************************
-            // member groups
-            // ************************
-            if (option.memberGroups !== undefined) {
-                const previousGroups: string[] = await user.getMemberUserGroupIds()
-                const newGroups: string[] = option.memberGroups;
-                if (option.superAdmin !== undefined) {
-                    if (option.superAdmin === true) {
-                        if (newGroups.indexOf("admin") === -1) {
-                            newGroups.push("admin");
-                        }
-                    }
-                }
-                const groupsToAdd: string[] = newGroups.filter(x => !previousGroups.includes(x));
-                const groupsToRemove: string[] = previousGroups.filter(x => !newGroups.includes(x));
-                let userGroup: UserGroup | null;
-                property = "memberGroups";
-                let error: Error | null = null;
-                for (const groupId of groupsToAdd) {
-                    userGroup = await this.getUserGroup(groupId)
-                    if (!userGroup) {
-                        try {
-                            userGroup = await this.createUserGroup(groupId)
-                        } catch (e) {
-                            error = e;
-                            break;
-                        }
-                    }
-                    try {
-                        await user.addToMemberUserGroup(userGroup);
-                    } catch (e) {
-                        error = e;
-                        break;
-                    }
-                }
- 
-                for (const groupId of groupsToRemove) {
-                    try {
-                        await user.removeFromMemberUserGroup(new UserGroup(this, groupId));
-                    } catch (e) {
-                        error = e;
-                        break;
-                    }
-                }
-                if (error) {
-                    userReport.changes.push({ property, previousValue: previousGroups.join(", "), newValue: previousGroups.join(", "), error: error.message });
-                } else {
-                    Eif (groupsToAdd.length > 0 || groupsToRemove.length > 0) {
-                        userReport.changes.push({ property, previousValue: previousGroups.join(", "), newValue: newGroups.join(", ") });
-                    }
-                }
- 
-            }
- 
-            // ************************
-            // subadmin groups
-            // ************************
-            if (option.subadminGroups !== undefined) {
-                const previousGroups: string[] = await user.getSubadminUserGroupIds()
-                const newGroups: string[] = option.subadminGroups;
-                const groupsToAdd: string[] = newGroups.filter(x => !previousGroups.includes(x));
-                const groupsToRemove: string[] = previousGroups.filter(x => !newGroups.includes(x));
-                let userGroup: UserGroup | null;
-                property = "subadminGroups";
-                let error: Error | null = null;
-                for (const groupId of groupsToAdd) {
-                    userGroup = await this.getUserGroup(groupId)
-                    if (!userGroup) {
-                        try {
-                            userGroup = await this.createUserGroup(groupId)
-                        } catch (e) {
-                            error = e;
-                            break;
-                        }
-                    }
-                    try {
-                        await user.promoteToUserGroupSubadmin(userGroup);
-                    } catch (e) {
-                        error = e;
-                        break;
-                    }
-                }
- 
-                for (const groupId of groupsToRemove) {
-                    try {
-                        await user.demoteFromSubadminUserGroup(new UserGroup(this, groupId));
-                    } catch (e) {
-                        error = e;
-                        break;
-                    }
-                }
-                if (error) {
-                    userReport.changes.push({ property, previousValue: previousGroups.join(", "), newValue: previousGroups.join(", "), error: error.message });
-                } else {
-                    userReport.changes.push({ property, previousValue: previousGroups.join(", "), newValue: newGroups.join(", ") });
-                }
- 
-            }
- 
-            // ************************
-            // display name
-            // ************************
-            if (option.displayName !== undefined) {
-                previousValue = await user.getDisplayName();
-                newValue = option.displayName
-                property = "displayName";
-                if (previousValue !== newValue) {
-                    try {
-                        await user.setDisplayName(option.displayName);
-                        userReport.changes.push({ property, previousValue, newValue });
-                    } catch (e) {
-                        userReport.changes.push({ property, previousValue, newValue: previousValue, error: e.message });
-                    }
-                }
-            }
- 
-            // ************************
-            // email
-            // ************************
-            if (option.email !== undefined) {
-                previousValue = await user.getEmail();
-                newValue = option.email;
-                property = "email";
-                if (previousValue !== newValue) {
-                    try {
-                        await user.setEmail(option.email);
-                        userReport.changes.push({ property, previousValue, newValue });
-                    } catch (e) {
-                        userReport.changes.push({ property, previousValue, newValue: previousValue, error: e.message });
-                    }
-                }
-            }
- 
-            // ************************
-            // language
-            // ************************
-            if (option.language !== undefined) {
-                previousValue = await user.getLanguage();
-                newValue = option.language;
-                property = "language";
-                if (previousValue !== newValue) {
-                    try {
-                        await user.setLanguage(option.language);
-                        userReport.changes.push({ property, previousValue, newValue });
-                    } catch (e) {
-                        userReport.changes.push({ property, previousValue, newValue: previousValue, error: e.message });
-                    }
-                }
-            }
- 
-            // ************************
-            // locale
-            // ************************
-            if (option.locale !== undefined) {
-                previousValue = await user.getLocale();
-                newValue = option.locale;
-                property = "locale";
-                if (previousValue !== newValue) {
-                    try {
-                        await user.setLocale(option.locale);
-                        userReport.changes.push({ property, previousValue, newValue });
-                    } catch (e) {
-                        userReport.changes.push({ property, previousValue, newValue: previousValue, error: e.message });
-                    }
-                }
-            }
- 
-            // ************************
-            // twitter
-            // ************************
-            if (option.twitter !== undefined) {
-                previousValue = await user.getTwitter();
-                newValue = option.twitter;
-                property = "twitter";
-                if (previousValue !== newValue) {
-                    try {
-                        await user.setTwitter(option.twitter);
-                        userReport.changes.push({ property, previousValue, newValue });
-                    } catch (e) {
-                        userReport.changes.push({ property, previousValue, newValue: previousValue, error: e.message });
-                    }
-                }
-            }
- 
-            // ************************
-            // phone
-            // ************************
-            if (option.phone !== undefined) {
-                previousValue = await user.getPhone();
-                newValue = option.phone;
-                property = "phone";
-                if (previousValue !== newValue) {
-                    try {
-                        await user.setPhone(option.phone);
-                        userReport.changes.push({ property, previousValue, newValue });
-                    } catch (e) {
-                        userReport.changes.push({ property, previousValue, newValue: previousValue, error: e.message });
-                    }
-                }
-            }
- 
-            // ************************
-            // password
-            // ************************
-            if (option.password !== undefined) {
-                previousValue = "********";
-                newValue = option.password;
-                property = "password";
-                try {
-                    await user.setPassword(option.password);
-                    userReport.changes.push({ property, previousValue, newValue: previousValue });
-                } catch (e) {
-                    userReport.changes.push({ property, previousValue, newValue: previousValue, error: e.message });
-                }
-            }
- 
-            // ************************
-            // address
-            // ************************
-            if (option.address !== undefined) {
-                previousValue = await user.getAddress();
-                newValue = option.address;
-                property = "address";
-                if (previousValue !== newValue) {
-                    try {
-                        await user.setAddress(option.address);
-                        userReport.changes.push({ property, previousValue, newValue });
-                    } catch (e) {
-                        userReport.changes.push({ property, previousValue, newValue: previousValue, error: e.message });
-                    }
-                }
-            }
- 
-            // ************************
-            // website
-            // ************************
-            if (option.website !== undefined) {
-                previousValue = await user.getWebsite();
-                newValue = option.website;
-                property = "website";
-                if (previousValue !== newValue) {
-                    try {
-                        await user.setWebsite(option.website);
-                        userReport.changes.push({ property, previousValue, newValue });
-                    } catch (e) {
-                        userReport.changes.push({ property, previousValue, newValue: previousValue, error: e.message });
-                    }
-                }
-            }
- 
-            // ************************
-            // quota
-            // ************************
-            if (option.quota !== undefined) {
-                previousValue = await (await user.getQuotaUserFriendly()).quota;
-                newValue = option.quota;
-                property = "quota";
-                if (previousValue !== newValue) {
-                    try {
-                        await user.setQuota(option.quota);
-                        userReport.changes.push({ property, previousValue, newValue });
-                    } catch (e) {
-                        userReport.changes.push({ property, previousValue, newValue: previousValue, error: e.message });
-                    }
-                }
-            }
- 
-            // ************************
-            // resend welcome email
-            // ************************
-            if (option.resendWelcomeEmail !== undefined) {
-                previousValue = "not sent";
-                newValue = "sent";
-                property = "resendWelcomeEmail";
-                if (option.resendWelcomeEmail) {
-                    try {
-                        await user.resendWelcomeEmail();
-                        userReport.changes.push({ property, previousValue, newValue });
-                    } catch (e) {
-                        userReport.changes.push({ property, previousValue, newValue: previousValue, error: e.message });
-                    }
-                }
-            }
- 
-            if (userReport.changes.length === 0) {
-                userReport.message = `User ${option.id} not changed`;
-            }
-            report.push(userReport);
-        }
-        return report;
-    }
- 
-    // ***************************************************************************************
-    // shares
-    // https://docs.nextcloud.com/server/latest/developer_manual/client_apis/OCS/ocs-share-api.html
-    // ***************************************************************************************
- 
-    /**
-     * create a new share
-     */
-    public async createShare(options: ICreateShare): Promise<Share> {
- 
-        const shareRequest = Share.createShareRequestBody(options);
-        debug(shareRequest);
- 
-        const requestInit: RequestInit = {
-            body: shareRequest,
-            headers: this.getOcsHeaders(),
-            method: "POST",
-        };
-        const url = this.nextcloudOrigin + "/ocs/v2.php/apps/files_sharing/api/v1/shares";
- 
-        // try {
-        const response: Response = await this.getHttpResponse(
-            url,
-            requestInit,
-            [200],
-            { description: "Share create" });
- 
-        const rawResult: any = await response.json();
-        debug(rawResult);
-        return Share.getShare(this, rawResult.ocs.data.id);
-        /* } catch (e) {
-            debug("result " + e.message);
-            debug("requestInit ", JSON.stringify(requestInit, null, 4));
-            debug("headers " + JSON.stringify(headers, null, 4));
-            debug("url ", url);
-            throw e;
-        } */
-    }
- 
-    /**
-     * update a new share
-     */
-    public async updateShare(shareId: string, body: { password: string } | { expireDate: string } | { note: string }): Promise<void> {
- 
-        debug("updateShare body ", body);
- 
-        const requestInit: RequestInit = {
-            body: JSON.stringify(body, null, 4),
-            headers: this.getOcsHeaders(),
-            method: "PUT",
-        };
-        const url = this.nextcloudOrigin + "/ocs/v2.php/apps/files_sharing/api/v1/shares/" + shareId;
- 
-        await this.getHttpResponse(
-            url,
-            requestInit,
-            [200],
-            { description: "Share update" });
- 
-    }
- 
-    /**
-     * get share information
-     * @param shareId
-     */
-    public async getShare(shareId: string): Promise<any> {
- 
-        const requestInit: RequestInit = {
-            headers: this.getOcsHeaders(),
-            method: "GET",
-        };
-        const url = this.nextcloudOrigin + "/ocs/v2.php/apps/files_sharing/api/v1/shares/" + shareId;
- 
-        const response: Response = await this.getHttpResponse(
-            url,
-            requestInit,
-            [200],
-            { description: "Share get" });
- 
-        const rawResult: any = await response.json();
-        return rawResult;
-        /*
-    } catch (e) {
-        debug("result " + e.message);
-        debug("requestInit ", JSON.stringify(requestInit, null, 4));
-        debug("headers " + JSON.stringify(headers, null, 4));
-        debug("url ", url);
-        throw e;
-    }
-    */
-    }
- 
-    /**
-     * get share information
-     * @param shareId
-     */
-    public async deleteShare(shareId: string): Promise<any> {
- 
-        const requestInit: RequestInit = {
-            headers: this.getOcsHeaders(),
-            method: "DELETE",
-        };
-        const url = this.nextcloudOrigin + "/ocs/v2.php/apps/files_sharing/api/v1/shares/" + shareId;
- 
-        const response: Response = await this.getHttpResponse(
-            url,
-            requestInit,
-            [200],
-            { description: "Share delete" });
- 
-    }
- 
-    // ***************************************************************************************
-    // notfication management
-    // ***************************************************************************************
-    /**
-     * @returns array of notification objects
-     */
-    public async getNotifications(): Promise<object[]> {
-        const requestInit: RequestInit = {
-            headers: this.getOcsHeaders(),
-            method: "GET",
-        };
- 
-        const response: Response = await this.getHttpResponse(
-            this.nextcloudOrigin + "/ocs/v2.php/apps/notifications/api/v2/notifications",
-            requestInit,
-            [200, 404],
-            { description: "Notifications get" });
- 
-        // no notification found
-        if (response.status === 404) {
-            return [];
-        }
- 
-        const rawResult: any = await response.json();
- 
-        let notifications = [];
- 
-        if (rawResult && rawResult.ocs && rawResult.ocs.data) {
-            notifications = rawResult.ocs.data;
-        } else {
-            throw new ClientError("Fatal Error: nextcloud notifications data missing", "ERR_SYSTEM_INFO_MISSING_DATA"); // @todo wrong error message
-        }
- 
-        const result: object[] = notifications;
-        return result;
-    }
- 
-    public async getUpdateNotifications(version: string): Promise<object> {
- 
-        // @todo refactoring... /ocs/v2.php/apps/notifications/api/v2/notifications/<id>   (GET/DELETE)
- 
-        const requestInit: RequestInit = {
-            headers: this.getOcsHeaders(),
-            method: "GET",
-        };
- 
-        const response: Response = await this.getHttpResponse(
-            this.nextcloudOrigin + `/ocs/v2.php/apps/updatenotification/api/v1/applist/${version}`,
-            requestInit,
-            [200],
-            { description: "UpdateNotifications get" });
- 
-        const rawResult: any = await response.json();
- 
-        let updateNotification = {};
- 
-        if (rawResult && rawResult.ocs && rawResult.ocs.data) {
-            updateNotification = rawResult.ocs.data;
-        } else {
-            throw new ClientError("Fatal Error: nextcloud notifications data missing", "ERR_SYSTEM_INFO_MISSING_DATA");
-        }
- 
-        const result: object = updateNotification;
-        return result;
-    }
- 
-    // @todo to be refactored to user
-    public async sendNotificationToUser(userId: string, shortMessage: string, longMessage?: string): Promise<void> {
-        const requestInit: RequestInit = {
-            headers: new Headers({
-                "Accept": "application/json",
-                "Content-Type": "application/x-www-form-urlencoded",
-                "OCS-APIRequest": "true",
-            }),
-            method: "POST",
-        };
- 
-        if (!longMessage) {
-            longMessage = "";
-        }
-        longMessage = `&longMessage=${encodeURIComponent(longMessage)}`;
-        const queryString = `${encodeURIComponent(userId)}?shortMessage=${encodeURIComponent(shortMessage)}${longMessage}`;
-        const response: Response = await this.getHttpResponse(
-            this.nextcloudOrigin + `/ocs/v2.php/apps/admin_notifications/api/v1/notifications/${queryString}`,
-            requestInit,
-            [200],
-            { description: "User create" });
-        const rawResult: any = await response.json();
-        //        console.log(rawResult);
-    }
- 
-    // ***************************************************************************************
-    // apps management
-    // ***************************************************************************************
-    /**
-     * returns apps
-     */
-    public async getApps(): Promise<string[]> {
-        const requestInit: RequestInit = {
-            headers: this.getOcsHeaders(),
-            method: "GET",
-        };
- 
-        const response: Response = await this.getHttpResponse(
-            this.getOcsUrl(`/apps`),
-            requestInit,
-            [200],
-            { description: "Apps get" });
- 
-        const rawResult: any = await response.json();
- 
-        let apps = [];
- 
-        if (rawResult && rawResult.ocs && rawResult.ocs.data) {
-            apps = rawResult.ocs.data;
-        } else {
-            throw new ClientError("Fatal Error: nextcloud apps data missing", "ERR_SYSTEM_INFO_MISSING_DATA");
-        }
- 
-        const result: string[] = apps;
- 
-        return result;
-    }
-    public async getAppInfos(appName: string): Promise<object> {
-        const requestInit: RequestInit = {
-            headers: this.getOcsHeaders(),
-            method: "GET",
-        };
- 
-        const response: Response = await this.getHttpResponse(
-            this.getOcsUrl(`/apps/${appName}`),
-            requestInit,
-            [200],
-            { description: "App Infos get" });
- 
-        const rawResult: any = await response.json();
- 
-        let appInfo = {};
- 
-        if (rawResult && rawResult.ocs && rawResult.ocs.data) {
-            appInfo = rawResult.ocs.data;
-        } else {
-            throw new ClientError("Fatal Error: nextcloud apps data missing", "ERR_SYSTEM_INFO_MISSING_DATA");
-        }
- 
-        const result: object = appInfo;
- 
-        return result;
-    }
- 
-    // ***************************************************************************************
-    // private methods
-    // ***************************************************************************************
- 
-    /**
-     * asserts valid xml
-     * asserts multistatus response
-     * asserts that a href is available in the multistatus response
-     * asserts propstats and prop
-     * @param response the http response
-     * @param href get only properties that match the href
-     * @returns array of properties
-     * @throws GeneralError
-     */
-    private async getPropertiesFromWebDAVMultistatusResponse(response: Response, href: string): Promise<any[]> {
-        const responseContentType: string | null = response.headers.get("Content-Type");
- 
-        if (!responseContentType) {
-            throw new ClientError("Response content type expected", "ERR_RESPONSE_WITHOUT_CONTENT_TYPE_HEADER");
-        }
- 
-        if (responseContentType.indexOf("application/xml") === -1) {
-            throw new ClientError("XML response content type expected", "ERR_XML_RESPONSE_CONTENT_TYPE_EXPECTED");
-        }
- 
-        const xmlBody: string = await response.text();
- 
-        if (parser.validate(xmlBody) !== true) {
-            throw new ClientError(`The response is not valid XML: ${xmlBody}`, "ERR_RESPONSE_NOT_INVALID_XML");
-        }
-        const options: any = {
-            ignoreNameSpace: true,
-        };
-        const body: any = parser.parse(xmlBody, options);
- 
-        // ensure that we have a multistatus response
-        if (!body.multistatus || !body.multistatus.response) {
-            throw new ClientError(`The response is is not a WebDAV multistatus response`, "ERR_RESPONSE_NO_MULTISTATUS_XML");
-        }
- 
-        // ensure that response is always an array
-        if (body.multistatus.response.href || body.multistatus.response.propstat) {
-            body.multistatus.response = new Array(body.multistatus.response);
-        }
-        /*
-                if (body.multistatus.response.propstat) {
-                    body.multistatus.response = [body.multistatus.response];
-                }
-        */
-        const responseProperties: any[] = [];
-        for (const res of body.multistatus.response) {
- 
-            if (!res.href) {
-                throw new ClientError(`The mulitstatus response must have a href`, "ERR_RESPONSE_MISSING_HREF_MULTISTATUS");
-            }
- 
-            if (!res.propstat) {
-                throw new ClientError(`The mulitstatus response must have a "propstat" container`, "ERR_RESPONSE_MISSING_PROPSTAT");
-            }
-            let propStats = res.propstat;
- 
-            // ensure an array
-            if (res.propstat.status || res.propstat.prop) {
-                propStats = [res.propstat];
-            }
- 
-            for (const propStat of propStats) {
-                if (!propStat.status) {
-                    throw new ClientError(`The propstat must have a "status"`, "ERR_RESPONSE_MISSING_PROPSTAT_STATUS");
-                }
-                if (propStat.status === "HTTP/1.1 200 OK") {
-                    if (!propStat.prop) {
-                        throw new ClientError(`The propstat must have a "prop"`, "ERR_RESPONSE_MISSING_PROPSTAT_PROP");
-                    }
-                    const property: any = propStat.prop;
-                    property._href = res.href;
-                    responseProperties.push(property);
-                }
-            }
-            //            }
-        }
-        return responseProperties;
-    }
- 
-    /**
-     * nextcloud creates a csrf token and stores it in the html header attribute
-     * data-requesttoken
-     * this function is currently not used
-     * @returns the csrf token / requesttoken
-     */
-    /*
-        private async getCSRFToken(): Promise<string> {
- 
-            const requestInit: RequestInit = {
-                method: "GET",
-            };
- 
-            const response: Response = await this.getHttpResponse(
-                this.nextcloudOrigin,
-                requestInit,
-                [200],
-                { description: "CSER token get" });
- 
-            const html = await response.text();
- 
-            const requestToken: string = html.substr(html.indexOf("data-requesttoken=") + 19, 89);
-            debug("getCSRFToken  %s", requestToken);
-            return requestToken;
-        }
-    */
- 
-    private async getHttpResponse(url: string, requestInit: RequestInit, expectedHttpStatusCode: number[], context: IRequestContext): Promise<Response> {
- 
-        if (!requestInit.headers) {
-            requestInit.headers = new Headers();
-        }
- 
-        /* istanbul ignore else */
-        if (this.fakeServer) {
-            return await this.fakeServer.getFakeHttpResponse(url, requestInit, expectedHttpStatusCode, context);
-        } else {
-            return await this.httpClient!.getHttpResponse(url, requestInit, expectedHttpStatusCode, context);
-        }
-    }
- 
-    /**
-     * get contents array of a folder
-     * @param folderName Name of the folder like "/company/branches/germany"
-     * @param folderIndicator true if folders are requested otherwise files
-     * @returns array of folder contents meta data
-     */
-    private async Contents(folderName: string, folderIndicator: boolean): Promise<any[]> {
-        debug("Contents: folder %s", folderName);
-        const folders: Folder[] = [];
-        folderName = this.sanitizeFolderName(folderName);
-        const resultArray: any[] = [];
- 
-        if (folderIndicator === true) {
-            debug("Contents: get folders");
-        } else {
-            debug("Contents: get files");
-        }
-        try {
-            const folderContentsArray = await this.getFolderContents(folderName);
- 
-            // debug("###########################");
-            // debug("$s", JSON.stringify(folderContentsArray, null, 4));
-            // debug("###########################");
- 
-            for (const folderElement of folderContentsArray) {
-                if (folderElement.type === "directory") {
-                    if (folderIndicator === true) {
-                        resultArray.push(folderElement);
-                    }
-                } else {
-                    if (folderIndicator === false) {
-                        debug("Contents folder element file %O ", folderElement);
-                        resultArray.push(folderElement);
-                    }
-                }
-            }
-        } catch (e) {
-            debug("Contents: exception occurred %s", e.message);
-        }
- 
-        return resultArray;
-    }
- 
-    private sanitizeFolderName(folderName: string): string {
-        if (folderName[0] !== "/") {
-            folderName = "/" + folderName;
-        }
-        // remove trailing "/" es
-        folderName = folderName.replace(/\/+$/, "");
-        if (folderName === "") {
-            folderName = "/";
-        }
- 
-        return folderName;
-    }
- 
-    private getTagIdFromHref(href: string): number {
-        return parseInt(href.split("/")[href.split("/").length - 1], 10);
-    }
- 
-    private async createFolderInternal(folderName: string): Promise<void> {
- 
-        const url: string = this.webDAVUrl + folderName;
-        debug("createFolderInternal %s", url);
- 
-        const requestInit: RequestInit = {
-            method: "MKCOL",
-        };
-        try {
-            await this.getHttpResponse(
-                url,
-                requestInit,
-                [201],
-                { description: "Folder create" },
-            );
- 
-        } catch (err) {
-            debug("Error in createFolderInternal %s %s %s %s", err.message, requestInit.method, url);
-            throw err;
-        }
-    }
- 
-    private async stat(fileName: string): Promise<IStat> {
- 
-        const url: string = this.webDAVUrl + fileName;
-        debug("stat %s", url);
- 
-        const requestInit: RequestInit = {
-            body: `<?xml version="1.0"?>
-            <d:propfind  xmlns:d="DAV:" xmlns:oc="http://owncloud.org/ns" xmlns:nc="http://nextcloud.org/ns">
-            <d:prop>
-                  <d:getlastmodified />
-                  <d:getetag />
-                  <d:getcontenttype />
-                  <d:resourcetype />
-                  <oc:fileid />
-                  <oc:permissions />
-                  <oc:size />
-                  <d:getcontentlength />
-                  <nc:has-preview />
-                  <oc:favorite />
-                  <oc:comments-unread />
-                  <oc:owner-display-name />
-                  <oc:share-types />
-            </d:prop>
-          </d:propfind>`,
-            headers: new Headers({ Depth: "0" }),
-            method: "PROPFIND",
-        };
-        let response: Response;
-        try {
-            response = await this.getHttpResponse(
-                url,
-                requestInit,
-                [207],
-                { description: "File/Folder get details" },
-            );
- 
-        } catch (err) {
-            debug("Error in stat %s %s %s %s", err.message, requestInit.method, url);
-            throw err;
-        }
- 
-        const properties: any[] = await this.getPropertiesFromWebDAVMultistatusResponse(response, "");
-        let resultStat: IStat | null = null;
- 
-        for (const prop of properties) {
-            resultStat = {
-                basename: basename(fileName),
-                fileid: prop.fileid,
-                filename: fileName,
-                lastmod: prop.getlastmodified,
-                type: "file",
-            };
- 
-            if (prop.getcontentlength) {
-                resultStat.size = prop.getcontentlength;
-            } else {
-                resultStat.type = "directory";
-            }
- 
-            if (prop.getcontenttype) {
-                resultStat.mime = prop.getcontenttype;
-            }
-        }
- 
-        if (!resultStat) {
-            debug("Error: response %s", JSON.stringify(properties, null, 4));
-            throw new ClientError("Error getting status information from : " + url,
-                "ERR_STAT");
-        }
-        return resultStat;
-    }
- 
-    private getOcsMetaStatus(input: any): { code: number, message: string } {
-        let code: number;
-        let message: string = "";
-        if (input.ocs &&
-            input.ocs.meta &&
-            input.ocs.meta.statuscode) {
-            code = input.ocs.meta.statuscode;
-            if (input.ocs.meta.message) {
-                message = input.ocs.meta.message;
-            }
-            return { code, message }
-        }
-        throw new InvalidServiceResponseFormatError("Fatal Error: The OCS meta status could not be retrieved from OCS response");
-    }
- 
-    private getOcsHeaders(): Headers {
-        return new Headers({
-            "OCS-APIRequest": "true",
-            "Content-Type": "application/json",
-            "Accept": "application/json"
-        });
-    }
- 
-    private getOcsUrl(suffix: string): string {
-        /*
-        if (!suffix) {
-            suffix = "";
-        }
-        if (!suffix.startsWith("/")) {
-            suffix = `/${suffix}`
-        }
-        */
-        return `${this.nextcloudOrigin}/ocs/v1.php/cloud${suffix}`;
-    }
- 
-    private async putFileContents(fileName: string, data: Buffer | NodeJS.ReadableStream): Promise<Response> {
- 
-        const url: string = this.webDAVUrl + fileName;
-        debug("putFileContents %s", url);
- 
-        const requestInit: RequestInit = {
-            body: data,
-            method: "PUT",
-        };
-        let response: Response;
-        let description = "File save content ";
-        Eif (data instanceof Buffer) {
-            description += "from buffer";
-        } else {
-            description += "from stream";
-        }
-        response = await this.getHttpResponse(
-            url,
-            requestInit,
-            [201, 204],
-            { description },
-        );
- 
-        return response;
-    }
- 
-}
- 
- -
-
- - - - - - - - - \ No newline at end of file diff --git a/docs/coverage/lcov-report/command.ts.html b/docs/coverage/lcov-report/command.ts.html deleted file mode 100644 index 36e74341..00000000 --- a/docs/coverage/lcov-report/command.ts.html +++ /dev/null @@ -1,440 +0,0 @@ - - - - - - Code coverage report for command.ts - - - - - - - - - -
-
-

All files command.ts

-
- -
- 100% - Statements - 23/23 -
- - -
- 100% - Branches - 10/10 -
- - -
- 100% - Functions - 7/7 -
- - -
- 100% - Lines - 23/23 -
- - -
-

- Press n or j to go to the next uncovered block, b, p or k for the previous block. -

-
-
-

-
1 -2 -3 -4 -5 -6 -7 -8 -9 -10 -11 -12 -13 -14 -15 -16 -17 -18 -19 -20 -21 -22 -23 -24 -25 -26 -27 -28 -29 -30 -31 -32 -33 -34 -35 -36 -37 -38 -39 -40 -41 -42 -43 -44 -45 -46 -47 -48 -49 -50 -51 -52 -53 -54 -55 -56 -57 -58 -59 -60 -61 -62 -63 -64 -65 -66 -67 -68 -69 -70 -71 -72 -73 -74 -75 -76 -77 -78 -79 -80 -81 -82 -83 -84 -85 -86 -87 -88 -89 -90 -91 -92 -93 -94 -95 -96 -97 -98 -99 -100 -101 -102 -103 -104 -105 -106 -107 -108 -109 -110 -111 -112 -113 -114 -115 -116 -117 -118 -119 -120 -121  -1x -  -1x -  -  -  -  -  -  -  -  -  -1x -  -  -  -1x -  -  -  -1x -  -  -  -1x -  -  -  -1x -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -1x -  -  -  -  -  -  -17x -17x -17x -17x -  -  -  -  -  -  -  -  -  -19x -19x -1x -  -18x -17x -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -65x -15x -  -50x -  -  -  -  -  -  -  -18x -  -  -  -  -  -  -  -7x -  -  -  -  -  -  -  -27x -  -  -  - 
// tslint:disable-next-line:no-var-requires
-const debug = require("debug").debug("Command");
- 
-import Client, {
-    CommandAlreadyExecutedError,
-} from "./client";
- 
-/**
- * The potential states that a command can have.
- * When a command is created, the state is "initial"
- * When the execution has started, the status is "running"
- * When the execution has finsihed, the status can be "succes" or "failed"
- */
-export enum CommandStatus {
-    /**
-     * When a command is created, the state is "initial"
-     */
-    initial = "initial",
-    /**
-     * When the execution has started, the status is "running"
-     */
-    running = "running",
-    /**
-     * After successful  execution of the command, the status is "success"
-     */
-    success = "success",
-    /**
-     * After unsuccessfull execution of the command, the status is "failed"
-     */
-    failed = "failed",
-}
- 
-/**
- * when the command has finished, the client can get the result of the command execution
- */
-export interface CommandResultMetaData {
-    errors: string[],
-    messages: string[],
-    timeElapsed: number,
-}
- 
-/**
- * The command class represents a potential long running activity.
- * This activity has been wrapped into an object to ease the tracking of the processing state.
- * Create a command with  receiver information, execute the command and check the status and progress.
- * Check the result when finsished.
- */
-export default abstract class Command {
-    protected client: Client;
-    protected status: CommandStatus;
-    protected percentCompleted: number;
-    protected resultMetaData: CommandResultMetaData;
- 
-    constructor(client: Client) {
-        this.client = client;
-        this.status = CommandStatus.initial;
-        this.percentCompleted = 0;
-        this.resultMetaData = { messages: [], errors: [], timeElapsed: 0 };
-    }
- 
-    /**
-     * final execute the command
-     * @async
-     * @final
-     * @returns {Promise<void>}
-     */
-    public async execute(): Promise<void> {
-        debug("execute Command = " + this.constructor.name, this.status);
-        if (this.isFinished()) {
-            throw new CommandAlreadyExecutedError("Error: Command has already been executed. Command = " + this.constructor.name);
-        }
-        if (this.status === CommandStatus.initial) {
-            await this.onExecute();
-        }
-        // do nothing if already running
-    }
- 
-    /**
-     * execute the command
-     * @async
-     * @returns {Promise<void>}
-     */
-    protected abstract async onExecute(): Promise<void>;
- 
-    /**
-     * returns true, if the command has been finished
-     * @returns {boolean}
-     */
-    public isFinished(): boolean {
-        if (this.status === CommandStatus.failed || this.status === CommandStatus.success) {
-            return true;
-        }
-        return false;
-    }
- 
-    /**
-     * returns the status of the command
-     * @returns {CommandStatus}
-     */
-    public getStatus(): CommandStatus {
-        return this.status;
-    }
- 
-    /**
-     * returns the completion percentage of the command
-     * @returns {number} percentage of completion
-     */
-    public getPercentCompleted(): number {
-        return this.percentCompleted;
-    }
- 
-    /**
-     * returns the result meta data of the command
-     * @returns {null|any} the result of the command
-     */
-    public getResultMetaData(): CommandResultMetaData {
-        return this.resultMetaData;
-    }
- 
-}
- 
- -
-
- - - - - - - - - \ No newline at end of file diff --git a/docs/coverage/lcov-report/environment.ts.html b/docs/coverage/lcov-report/environment.ts.html deleted file mode 100644 index ea7913e9..00000000 --- a/docs/coverage/lcov-report/environment.ts.html +++ /dev/null @@ -1,260 +0,0 @@ - - - - - - Code coverage report for environment.ts - - - - - - - - - -
-
-

All files environment.ts

-
- -
- 100% - Statements - 18/18 -
- - -
- 100% - Branches - 13/13 -
- - -
- 100% - Functions - 2/2 -
- - -
- 100% - Lines - 18/18 -
- - -
-

- Press n or j to go to the next uncovered block, b, p or k for the previous block. -

-
-
-

-
1 -2 -3 -4 -5 -6 -7 -8 -9 -10 -11 -12 -13 -14 -15 -16 -17 -18 -19 -20 -21 -22 -23 -24 -25 -26 -27 -28 -29 -30 -31 -32 -33 -34 -35 -36 -37 -38 -39 -40 -41 -42 -43 -44 -45 -46 -47 -48 -49 -50 -51 -52 -53 -54 -55 -56 -57 -58 -59 -60 -611x -1x -1x -  -1x -  -1x -  -  -  -  -  -  -9x -9x -9x -9x -  -  -8x -  -1x -  -  -  -  -  -  -  -  -  -  -  -9x -2x -  -  -  -7x -1x -  -  -  -6x -1x -  -  -  -5x -  -  -  -  -  -  -  -  -  -  -  - 
import debugFactory from "debug";
-import ClientError from "./error";
-import Server from "./server";
- 
-const debug = debugFactory("NCEnvironment");
- 
-export default class Environment {
-    public readonly url?: string;
-    public readonly userName?: string;
-    public readonly password?: string;
-    public readonly recordingActive: boolean;
- 
-    public constructor() {
-        this.url = process.env.NEXTCLOUD_URL;
-        this.userName = process.env.NEXTCLOUD_USERNAME;
-        this.password = process.env.NEXTCLOUD_PASSWORD;
-        if ((process.env.TEST_RECORDING_ACTIVE &&
-            (process.env.TEST_RECORDING_ACTIVE === "0" || process.env.TEST_RECORDING_ACTIVE === "false" || process.env.TEST_RECORDING_ACTIVE === "inactive")) ||
-            !process.env.TEST_RECORDING_ACTIVE) {
-            this.recordingActive = false;
-        } else {
-            this.recordingActive = true;
-        }
-    }
- 
-    /**
-     * returns the nextcloud credentials that is defined in the
-     * "user-provided" service section of the VCAP_SERVICES environment
-     * @param instanceName the name of the nextcloud user provided service instance
-     * @returns credentials from the VCAP_SERVICES environment (user provided service)
-     */
-    public getServer(): Server {
- 
-        if (!this.url) {
-            throw new ClientError("NCEnvironment: NEXTCLOUD_URL not defined in environment"
-                , "ERR_NEXTCLOUD_URL_NOT_DEFINED");
-        }
- 
-        if (!this.userName) {
-            throw new ClientError("NCEnvironment: NEXTCLOUD_USERNAME not defined in environment"
-                , "ERR_NEXTCLOUD_USERNAME_NOT_DEFINED");
-        }
- 
-        if (!this.password) {
-            throw new ClientError("NCEnvironment: NEXTCLOUD_PASSWORD not defined in environment"
-                , "ERR_NEXTCLOUD_PASSWORD_NOT_DEFINED");
-        }
- 
-        return new Server({
-            basicAuth: {
-                password: this.password,
-                username: this.userName,
-            },
-            logRequestResponse: this.recordingActive,
-            url: this.url,
-        });
- 
-    }
- 
-}
- 
- -
-
- - - - - - - - - \ No newline at end of file diff --git a/docs/coverage/lcov-report/environmentVcapServices.ts.html b/docs/coverage/lcov-report/environmentVcapServices.ts.html deleted file mode 100644 index d18b2442..00000000 --- a/docs/coverage/lcov-report/environmentVcapServices.ts.html +++ /dev/null @@ -1,299 +0,0 @@ - - - - - - Code coverage report for environmentVcapServices.ts - - - - - - - - - -
-
-

All files environmentVcapServices.ts

-
- -
- 100% - Statements - 24/24 -
- - -
- 100% - Branches - 15/15 -
- - -
- 100% - Functions - 2/2 -
- - -
- 100% - Lines - 24/24 -
- - -
-

- Press n or j to go to the next uncovered block, b, p or k for the previous block. -

-
-
-

-
1 -2 -3 -4 -5 -6 -7 -8 -9 -10 -11 -12 -13 -14 -15 -16 -17 -18 -19 -20 -21 -22 -23 -24 -25 -26 -27 -28 -29 -30 -31 -32 -33 -34 -35 -36 -37 -38 -39 -40 -41 -42 -43 -44 -45 -46 -47 -48 -49 -50 -51 -52 -53 -54 -55 -56 -57 -58 -59 -60 -61 -62 -63 -64 -65 -66 -67 -68 -69 -70 -71 -72 -73 -74  -1x -  -1x -1x -1x -1x -  -1x -  -  -  -  -  -  -1x -  -  -  -  -  -  -8x -2x -  -  -6x -6x -  -6x -1x -1x -  -  -5x -1x -  -  -  -  -4x -1x -  -  -  -  -3x -1x -  -  -  -  -2x -2x -2x -  -  -  -  -  -  -  -  -  -2x -  -  -  -  -  -  -  -  - 
// tslint:disable-next-line:no-var-requires
-require("dotenv").config();
- 
-import debugFactory from "debug";
-import ClientError from "./error";
-import Server from "./server";
-export { Server };
- 
-const debug = debugFactory("NCEnvironmentVcapServices");
- 
-/**
- * returns the nextcloud credentials that is defined in the
- * "user-provided" service section of the VCAP_SERVICES environment
- * instanceName: the name of the nextcloud user provided service instance
- */
-export default class EnvironmentVcapServices {
-    public readonly url: string;
-    public readonly userName: string;
-    public readonly password: string;
- 
-    public constructor(instanceName: string) {
- 
-        if (!process.env.VCAP_SERVICES) {
-            throw new ClientError("NCEnvironmentVcapServices: environment VCAP_SERVICES not found", "ERR_VCAP_SERVICES_NOT_FOUND");
-        }
- 
-        const vcapServices = require("vcap_services");
-        const cred = vcapServices.getCredentials("user-provided", undefined, instanceName);
- 
-        if (!cred || cred === undefined || (!cred.url && !cred.username && !cred.password)) {
-            debug("NCEnvironmentVcapServices: error credentials not found or not fully specified %O", cred);
-            throw new ClientError(`NCEnvironmentVcapServices: nextcloud credentials not found in environment VCAP_SERVICES. Service section: "user-provided", service instance name: "${instanceName}" `, "ERR_VCAP_SERVICES_NOT_FOUND");
-        }
- 
-        if (!cred.url) {
-            throw new ClientError("NCEnvironmentVcapServices: VCAP_SERVICES url not defined in user provided services for nextcloud"
-                , "ERR_VCAP_SERVICES_URL_NOT_DEFINED",
-                { credentials: cred });
-        }
- 
-        if (!cred.password) {
-            throw new ClientError("NCEnvironmentVcapServices: VCAP_SERVICES password not defined in user provided services for nextcloud",
-                "ERR_VCAP_SERVICES_PASSWORD_NOT_DEFINED",
-                { credentials: cred });
-        }
- 
-        if (!cred.username) {
-            throw new ClientError("NCEnvironmentVcapServices: VCAP_SERVICES username not defined in user provided services for nextcloud",
-                "ERR_VCAP_SERVICES_USERNAME_NOT_DEFINED",
-                { credentials: cred });
-        }
- 
-        this.url = cred.url as string;
-        this.userName = cred.username as string;
-        this.password = cred.password as string;
-    }
- 
-    /**
-     * returns the nextcloud credentials that is defined in the
-     * "user-provided" service section of the VCAP_SERVICES environment
-     * @param instanceName the name of the nextcloud user provided service instance
-     * @returns credentials from the VCAP_SERVICES environment (user provided service)
-     */
-    public getServer(): Server {
-        return new Server({
-            basicAuth: {
-                password: this.password,
-                username: this.userName,
-            },
-            url: this.url,
-        });
-    }
-}
- 
- -
-
- - - - - - - - - \ No newline at end of file diff --git a/docs/coverage/lcov-report/error.ts.html b/docs/coverage/lcov-report/error.ts.html deleted file mode 100644 index 9084e91a..00000000 --- a/docs/coverage/lcov-report/error.ts.html +++ /dev/null @@ -1,362 +0,0 @@ - - - - - - Code coverage report for error.ts - - - - - - - - - -
-
-

All files error.ts

-
- -
- 100% - Statements - 22/22 -
- - -
- 100% - Branches - 0/0 -
- - -
- 100% - Functions - 2/2 -
- - -
- 100% - Lines - 22/22 -
- - -
-

- Press n or j to go to the next uncovered block, b, p or k for the previous block. -

-
-
-

-
1 -2 -3 -4 -5 -6 -7 -8 -9 -10 -11 -12 -13 -14 -15 -16 -17 -18 -19 -20 -21 -22 -23 -24 -25 -26 -27 -28 -29 -30 -31 -32 -33 -34 -35 -36 -37 -38 -39 -40 -41 -42 -43 -44 -45 -46 -47 -48 -49 -50 -51 -52 -53 -54 -55 -56 -57 -58 -59 -60 -61 -62 -63 -64 -65 -66 -67 -68 -69 -70 -71 -72 -73 -74 -75 -76 -77 -78 -79 -80 -81 -82 -83 -84 -85 -86 -87 -88 -89 -90 -91 -92 -93 -94 -95  -  -1x -  -1x -  -  -  -  -63x -63x -63x -  -  -  -  -1x -  -  -  -93x -93x -  -  -  -  -  -  -  -1x -  -  -  -  -1x -  -  -  -  -1x -  -  -  -  -1x -  -  -  -  -1x -  -  -  -  -1x -  -  -  -  -1x -  -  -  -  -1x -  -  -  -  -1x -  -  -  -  -1x -  -  -  -  -1x -  -  -  -  -1x -  -  -  -  -1x -  -  -  -  -1x
// tslint:disable:max-classes-per-file
-// tslint:disable-next-line:no-var-requires
-const debug = require("debug").debug("ClientError");
- 
-export default class ClientError extends Error {
-    public code: string;
-    private context?: any;
- 
-    constructor(m: string, code: string, context?: any) {
-        super(m);
-        this.code = code;
-        this.context = context;
-    }
-}
- 
-// tslint:disable-next-line:max-classes-per-file
-export class BaseError extends Error {
-    private context?: any;
- 
-    constructor(m: string, context?: any) {
-        super(m);
-        this.context = context;
-    }
-}
- 
- 
-/**
- * the query limit parameter must be a number larger than 0
- */
-export class QueryLimitError extends BaseError { };
- 
-/**
- * the query offset parameter must be a number larger than 0
- */
-export class QueryOffsetError extends BaseError { };
- 
-/**
- * user group already exists
- */
-export class UserGroupAlreadyExistsError extends BaseError { };
- 
-/**
- * user group does not exist
- */
-export class UserGroupDoesNotExistError extends BaseError { };
- 
-/**
- * user group cloud not be deleted
- */
-export class UserGroupDeletionFailedError extends BaseError { };
- 
-/**
- * user not found
- */
-export class UserNotFoundError extends BaseError { };
- 
-/**
- * user already exists
- */
-export class UserAlreadyExistsError extends BaseError { };
- 
-/**
- * error creating user
- */
-export class UserCreateError extends BaseError { };
- 
-/**
- * error updating user
- */
-export class UserUpdateError extends BaseError { };
- 
-/**
- * Error sending user welcome email
- */
-export class UserResendWelcomeEmailError extends BaseError { };
- 
-/**
- * the service response is invalid
- */
-export class InvalidServiceResponseFormatError extends BaseError { };
- 
-/**
- * the service response is invalid
- */
-export class InsufficientPrivilegesError extends BaseError { };
- 
-/**
- * operation failed
- */
-export class OperationFailedError extends BaseError { };
- 
-/**
- * the command is already executed
- */
-export class CommandAlreadyExecutedError extends BaseError { };
- -
-
- - - - - - - - - \ No newline at end of file diff --git a/docs/coverage/lcov-report/fakeServer.ts.html b/docs/coverage/lcov-report/fakeServer.ts.html deleted file mode 100644 index 56f2f401..00000000 --- a/docs/coverage/lcov-report/fakeServer.ts.html +++ /dev/null @@ -1,236 +0,0 @@ - - - - - - Code coverage report for fakeServer.ts - - - - - - - - - -
-
-

All files fakeServer.ts

-
- -
- 100% - Statements - 27/27 -
- - -
- 100% - Branches - 10/10 -
- - -
- 100% - Functions - 2/2 -
- - -
- 100% - Lines - 27/27 -
- - -
-

- Press n or j to go to the next uncovered block, b, p or k for the previous block. -

-
-
-

-
1 -2 -3 -4 -5 -6 -7 -8 -9 -10 -11 -12 -13 -14 -15 -16 -17 -18 -19 -20 -21 -22 -23 -24 -25 -26 -27 -28 -29 -30 -31 -32 -33 -34 -35 -36 -37 -38 -39 -40 -41 -42 -43 -44 -45 -46 -47 -48 -49 -50 -51 -52 -531x -1x -  -  -  -  -  -  -  -1x -  -1x -216x -  -216x -  -  -1231x -1231x -2x -  -  -1231x -1231x -3x -  -1228x -  -  -  -1228x -  -1228x -1226x -  -  -1228x -29x -  -  -1228x -126x -126x -126x -126x -126x -126x -126x -  -1102x -  -  - 
import debugFactory from "debug";
-import {
-    RequestInit,
-    Response,
-    ResponseInit,
-} from "node-fetch";
-import { IRequestContext } from "./httpClient";
-import RequestResponseLogEntry from "./requestResponseLogEntry";
- 
-const debug = debugFactory("NCFakeServer");
- 
-export default class FakeServer {
-    public fakeResponses: RequestResponseLogEntry[] = [];
-    public constructor(fakeResponses: RequestResponseLogEntry[]) {
-        this.fakeResponses = fakeResponses;
-    }
-    public async getFakeHttpResponse(url: string, requestInit: RequestInit, expectedHttpStatusCode: number[], context: IRequestContext): Promise<Response> {
-        debug("getFakeHttpResponse");
-        if (!requestInit.method) {
-            requestInit.method = "UNDEFINED";
-        }
- 
-        const rrEntry: RequestResponseLogEntry | undefined = this.fakeResponses.shift();
-        if (!rrEntry) {
-            throw new Error(`error providing fake http response. No fake response available`);
-        }
-        const responseInit: ResponseInit = {
-            status: rrEntry.response.status,
-        };
- 
-        const response: Response = new Response(rrEntry.response.body, responseInit);
- 
-        if (rrEntry.response.contentType) {
-            response.headers.append("Content-Type", rrEntry.response.contentType);
-        }
- 
-        if (rrEntry.response.contentLocation) {
-            response.headers.append("Content-Location", rrEntry.response.contentLocation);
-        }
- 
-        if (expectedHttpStatusCode.indexOf(response.status) === -1) {
-            debug("getHttpResponse unexpected status response %s", response.status + " " + response.statusText);
-            debug("getHttpResponse description %s", context.description);
-            debug("getHttpResponse expected %s", expectedHttpStatusCode.join(","));
-            debug("getHttpResponse headers %s", JSON.stringify(response.headers, null, 4));
-            debug("getHttpResponse request body %s", requestInit.body);
-            debug("getHttpResponse text %s", await response.text());
-            throw new Error(`HTTP response status ${response.status} not expected. Expected status: ${expectedHttpStatusCode.join(",")} - status text: ${response.statusText}`);
-        }
-        return response;
-    }
-}
- 
- -
-
- - - - - - - - - \ No newline at end of file diff --git a/docs/coverage/lcov-report/favicon.png b/docs/coverage/lcov-report/favicon.png deleted file mode 100644 index 66918178..00000000 Binary files a/docs/coverage/lcov-report/favicon.png and /dev/null differ diff --git a/docs/coverage/lcov-report/file.ts.html b/docs/coverage/lcov-report/file.ts.html deleted file mode 100644 index cf26910b..00000000 --- a/docs/coverage/lcov-report/file.ts.html +++ /dev/null @@ -1,728 +0,0 @@ - - - - - - Code coverage report for file.ts - - - - - - - - - -
-
-

All files file.ts

-
- -
- 100% - Statements - 57/57 -
- - -
- 100% - Branches - 6/6 -
- - -
- 100% - Functions - 19/19 -
- - -
- 100% - Lines - 57/57 -
- - -
-

- Press n or j to go to the next uncovered block, b, p or k for the previous block. -

-
-
-

-
1 -2 -3 -4 -5 -6 -7 -8 -9 -10 -11 -12 -13 -14 -15 -16 -17 -18 -19 -20 -21 -22 -23 -24 -25 -26 -27 -28 -29 -30 -31 -32 -33 -34 -35 -36 -37 -38 -39 -40 -41 -42 -43 -44 -45 -46 -47 -48 -49 -50 -51 -52 -53 -54 -55 -56 -57 -58 -59 -60 -61 -62 -63 -64 -65 -66 -67 -68 -69 -70 -71 -72 -73 -74 -75 -76 -77 -78 -79 -80 -81 -82 -83 -84 -85 -86 -87 -88 -89 -90 -91 -92 -93 -94 -95 -96 -97 -98 -99 -100 -101 -102 -103 -104 -105 -106 -107 -108 -109 -110 -111 -112 -113 -114 -115 -116 -117 -118 -119 -120 -121 -122 -123 -124 -125 -126 -127 -128 -129 -130 -131 -132 -133 -134 -135 -136 -137 -138 -139 -140 -141 -142 -143 -144 -145 -146 -147 -148 -149 -150 -151 -152 -153 -154 -155 -156 -157 -158 -159 -160 -161 -162 -163 -164 -165 -166 -167 -168 -169 -170 -171 -172 -173 -174 -175 -176 -177 -178 -179 -180 -181 -182 -183 -184 -185 -186 -187 -188 -189 -190 -191 -192 -193 -194 -195 -196 -197 -198 -199 -200 -201 -202 -203 -204 -205 -206 -207 -208 -209 -210 -211 -212 -213 -214 -215 -216 -2171x -1x -  -  -  -  -  -  -  -1x -  -  -  -  -  -  -  -  -  -  -  -134x -  -  -  -  -  -  -  -  -134x -  -  -  -  -  -  -24x -23x -  -  -  -  -  -  -  -3x -2x -  -  -  -  -  -  -  -2x -1x -  -  -  -  -  -  -  -2x -1x -  -  -  -  -  -  -28x -27x -  -  -  -  -  -  -33x -31x -  -  -  -  -  -  -  -12x -12x -  -  -  -  -  -  -  -  -2x -2x -  -2x -1x -  -1x -  -  -  -  -  -  -  -  -  -2x -1x -1x -1x -1x -1x -1x -1x -  -  -  -  -  -  -  -2x -2x -  -  -  -  -  -  -  -3x -3x -  -  -  -  -  -  -  -1x -1x -  -  -  -  -  -  -  -14x -14x -  -  -  -  -  -  -  -3x -3x -3x -3x -5x -  -3x -  -  -  -  -  -  -  -2x -2x -  -2x -2x -1x -  -  -  -  -  -  -  -  -4x -4x -  -  -  -  -  -  -  -  -  -  -1x -1x -  -  -  -126x -8x -  -  -  - 
import path from "path";
-import Client, { ClientError } from "./client";
-import FileSystemElement from "./fileSystemElement";
-import Folder from "./folder";
- 
-/**
- * The file class represents a file in nextcloud.
- * It exposes file properties and content handling, commenting and tagging
- */
-export default class File implements FileSystemElement {
-    private memento: {
-        baseName: string,
-        id: number,
-        deleted: boolean,
-        lastmod: Date,
-        mime: string,
-        name: string,
-        size: number,
-    };
-    private client: Client;
-    constructor(client: Client, name: string, baseName: string, lastmod: string, size: number, mime: string, id: number) {
-        this.memento = {
-            baseName,
-            deleted: false,
-            id,
-            lastmod: new Date(lastmod),
-            mime,
-            name,
-            size,
-        };
-        this.client = client;
-    }
-    /**
-     * The name of the file including the path
-     * The name is readonly
-     */
-    get name(): string {
-        this.assertExistence();
-        return this.memento.name;
-    }
- 
-    /**
-     * The base name of the file (file name without path)
-     * The base name is readonly
-     */
-    get baseName(): string {
-        this.assertExistence();
-        return this.memento.baseName;
-    }
- 
-    /**
-     * The timestamp of the last file change
-     * readonly
-     */
-    get lastmod(): Date {
-        this.assertExistence();
-        return this.memento.lastmod;
-    }
- 
-    /**
-     * The file size in bytes
-     * readonly
-     */
-    get size(): number {
-        this.assertExistence();
-        return this.memento.size;
-    }
- 
-    /**
-     * The mime type (content type) of the file
-     */
-    get mime(): string {
-        this.assertExistence();
-        return this.memento.mime;
-    }
- 
-    /**
-     * The unique id of the file.
-     */
-    get id(): number {
-        this.assertExistence();
-        return this.memento.id;
-    }
- 
-    /**
-     * deletes a file
-     * @throws Error
-     */
-    public async delete(): Promise<void> {
-        this.memento.deleted = true;
-        return await this.client.deleteFile(this.memento.name);
-    }
- 
-    /**
-     * get folder of the file
-     * @throws ClientError
-     * @returns the parent folder
-     */
-    public async getFolder(): Promise<Folder> {
-        this.assertExistence();
-        const folder: Folder | null = await this.client.getFolder(path.dirname((this.memento.name)));
- 
-        if (folder) {
-            return folder;
-        }
-        throw new ClientError("Error, the folder of the file does not exist anymore", "ERR_FILE_FOLDER_DOES_NOT_EXIST");
-    }
- 
-    /**
-     * moves or renames the current file to the new location
-     * target folder must exists
-     * @param targetFileName the name of the target file /f1/f2/myfile.txt
-     * @throws Error
-     */
-    public async move(targetFileName: string): Promise<File> {
-        this.assertExistence();
-        const file: File = await this.client.moveFile(this.name, targetFileName);
-        this.memento.name = file.name;
-        this.memento.baseName = file.baseName;
-        this.memento.lastmod = file.lastmod;
-        this.memento.mime = file.mime;
-        this.memento.size = file.size;
-        return this;
-    }
- 
-    /**
-     * @returns the buffer of the file content
-     * @throws Error
-     */
-    public async getContent(): Promise<Buffer> {
-        this.assertExistence();
-        return this.client.getContent(this.name);
-    }
- 
-    /**
-     * @returns the url of the file
-     * @throws Error
-     */
-    public getUrl(): string {
-        this.assertExistence();
-        return this.client.getLink(this.name);
-    }
- 
-    /**
-     * @returns the url of the file in the UI
-     * @throws Error
-     */
-    public getUIUrl(): string {
-        this.assertExistence();
-        return this.client.getUILink(this.id);
-    }
- 
-    /**
-     * adds a tag name to the file
-     * @param tagName name of the tag
-     */
-    public async addTag(tagName: string): Promise<void> {
-        this.assertExistence();
-        return this.client.addTagToFile(this.id, tagName);
-    }
- 
-    /**
-     * get tag names
-     * @returns array of tag names
-     */
-    public async getTags(): Promise<string[]> {
-        this.assertExistence();
-        const map: Map<string, number> = await this.client.getTagsOfFile(this.id);
-        const tagNames: string[] = [];
-        for (const tagName of map) {
-            tagNames.push(tagName[0]);
-        }
-        return tagNames;
-    }
- 
-    /**
-     * removes a tag of the file
-     * @param tagName the name of the tag
-     */
-    public async removeTag(tagName: string): Promise<void> {
-        this.assertExistence();
-        const map: Map<string, number> = await this.client.getTagsOfFile(this.id);
- 
-        const tagId: number | undefined = map.get(tagName);
-        if (tagId) {
-            await this.client.removeTagOfFile(this.id, tagId);
-        }
-    }
- 
-    /**
-     * add comment to file
-     * @param comment the comment
-     */
-    public async addComment(comment: string): Promise<void> {
-        this.assertExistence();
-        return await this.client.addCommentToFile(this.id, comment);
-    }
- 
-    /**
-     * get list of comments of file
-     * @param top number of comments to return
-     * @param skip the offset
-     * @returns array of comment strings
-     * @throws Exception
-     */
-    public async getComments(top?: number, skip?: number): Promise<string[]> {
-        this.assertExistence();
-        return await this.client.getFileComments(this.id, top, skip);
-    }
- 
-    private assertExistence(): void {
-        if (this.memento.deleted) {
-            throw new ClientError("File does not exist", "ERR_FILE_NOT_EXISTING");
-        }
-    }
-}
- 
- -
-
- - - - - - - - - \ No newline at end of file diff --git a/docs/coverage/lcov-report/fileSizeFormatter.ts.html b/docs/coverage/lcov-report/fileSizeFormatter.ts.html deleted file mode 100644 index 81034f2c..00000000 --- a/docs/coverage/lcov-report/fileSizeFormatter.ts.html +++ /dev/null @@ -1,179 +0,0 @@ - - - - - - Code coverage report for fileSizeFormatter.ts - - - - - - - - - -
-
-

All files fileSizeFormatter.ts

-
- -
- 100% - Statements - 18/18 -
- - -
- 100% - Branches - 6/6 -
- - -
- 100% - Functions - 2/2 -
- - -
- 100% - Lines - 18/18 -
- - -
-

- Press n or j to go to the next uncovered block, b, p or k for the previous block. -

-
-
-

-
1 -2 -3 -4 -5 -6 -7 -8 -9 -10 -11 -12 -13 -14 -15 -16 -17 -18 -19 -20 -21 -22 -23 -24 -25 -26 -27 -28 -29 -30 -31 -32 -33 -34  -1x -  -20x -20x -20x -  -  -20x -  -  -  -20x -20x -5x -5x -  -15x -6x -6x -  -9x -1x -1x -  -  -8x -  -20x -20x -  -  -  - 
 
-export default class FileSizeFormatter {
-    private bytes: number;
-    private oneKiloByte = 1024;
-    private oneMegaByte = this.oneKiloByte * 1024;
-    private oneGigaByte = this.oneMegaByte * 1024;
- 
-    constructor(bytes: number) {
-        this.bytes = bytes;
-    }
-    public getUserFriendlyFileSize(): string {
-        let suffix: string;
-        let size = this.bytes;
-        if (size > this.oneGigaByte) {
-            size /= this.oneGigaByte;
-            suffix = " GB";
-        }
-        else if (this.bytes > this.oneMegaByte) {
-            size /= this.oneMegaByte;
-            suffix = " MB";
-        }
-        else if (this.bytes > this.oneKiloByte) {
-            size /= this.oneKiloByte;
-            suffix = " kB";
-        }
-        else {
-            suffix = " B";
-        }
-        size = Math.round(size);
-        return size + suffix;
-    }
- 
-}
- 
- -
-
- - - - - - - - - \ No newline at end of file diff --git a/docs/coverage/lcov-report/fileSystemElement.ts.html b/docs/coverage/lcov-report/fileSystemElement.ts.html deleted file mode 100644 index d6e5379d..00000000 --- a/docs/coverage/lcov-report/fileSystemElement.ts.html +++ /dev/null @@ -1,350 +0,0 @@ - - - - - - Code coverage report for fileSystemElement.ts - - - - - - - - - -
-
-

All files fileSystemElement.ts

-
- -
- 100% - Statements - 1/1 -
- - -
- 100% - Branches - 0/0 -
- - -
- 100% - Functions - 0/0 -
- - -
- 100% - Lines - 1/1 -
- - -
-

- Press n or j to go to the next uncovered block, b, p or k for the previous block. -

-
-
-

-
1 -2 -3 -4 -5 -6 -7 -8 -9 -10 -11 -12 -13 -14 -15 -16 -17 -18 -19 -20 -21 -22 -23 -24 -25 -26 -27 -28 -29 -30 -31 -32 -33 -34 -35 -36 -37 -38 -39 -40 -41 -42 -43 -44 -45 -46 -47 -48 -49 -50 -51 -52 -53 -54 -55 -56 -57 -58 -59 -60 -61 -62 -63 -64 -65 -66 -67 -68 -69 -70 -71 -72 -73 -74 -75 -76 -77 -78 -79 -80 -81 -82 -83 -84 -85 -86 -87 -88 -89 -90 -91  -  -  -  -  -  -1x -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  - 
import Client, { ClientError } from "./client";
- 
-/**
- * The file class represents a file in nextcloud.
- * It exposes file properties and content handling, commenting and tagging
- */
-export default abstract class FileSystemElement {
- 
-    /**
-     * The name of the file system element including the path
-     * The name is readonly
-     */
-    abstract get name(): string;
- 
-    /**
-     * The base name of the file system element (name without path)
-     * The base name is readonly
-     */
-    abstract get baseName(): string;
- 
-    /**
-     * The timestamp of the last file system element change
-     * readonly
-     */
-    abstract get lastmod(): Date;
- 
-    /**
-     * The unique id of the file system element.
-     */
-    abstract get id(): number;
- 
-    /**
-     * deletes a file system element
-     * @throws Error
-     */
-    public abstract async delete(): Promise<void>;
- 
-    /**
-     * moves or renames the current file system element to the new location
-     * target folder must exists
-     * @param targetFileName the name of the target file /f1/f2/myfile.txt
-     * @throws Error
-     */
-    public abstract async move(targetName: string): Promise<FileSystemElement>;
- 
-    /**
-     * @returns the url of the file sytsem element
-     * @throws Error
-     */
-    public abstract getUrl(): string;
- 
-    /**
-     * @returns the url of the file system element in the UI
-     * @throws Error
-     */
-    public abstract getUIUrl(): string;
- 
-    /**
-     * adds a tag name to the file system element
-     * @param tagName name of the tag
-     */
-    public abstract async addTag(tagName: string): Promise<void>;
- 
-    /**
-     * get tag names
-     * @returns array of tag names
-     */
-    public abstract async getTags(): Promise<string[]>;
- 
-    /**
-     * removes a tag of the file system element
-     * @param tagName the name of the tag
-     */
-    public abstract async removeTag(tagName: string): Promise<void>;
- 
-    /**
-     * add comment to file
-     * @param comment the comment
-     */
-    public abstract async addComment(comment: string): Promise<void>;
- 
-    /**
-     * get list of comments of file
-     * @param top number of comments to return
-     * @param skip the offset
-     * @returns array of comment strings
-     * @throws Exception
-     */
-    public abstract async getComments(top?: number, skip?: number): Promise<string[]>;
-}
- 
- -
-
- - - - - - - - - \ No newline at end of file diff --git a/docs/coverage/lcov-report/fileSystemFolder.ts.html b/docs/coverage/lcov-report/fileSystemFolder.ts.html deleted file mode 100644 index 61614ccb..00000000 --- a/docs/coverage/lcov-report/fileSystemFolder.ts.html +++ /dev/null @@ -1,218 +0,0 @@ - - - - - - Code coverage report for fileSystemFolder.ts - - - - - - - - - -
-
-

All files fileSystemFolder.ts

-
- -
- 100% - Statements - 20/20 -
- - -
- 100% - Branches - 2/2 -
- - -
- 100% - Functions - 7/7 -
- - -
- 100% - Lines - 18/18 -
- - -
-

- Press n or j to go to the next uncovered block, b, p or k for the previous block. -

-
-
-

-
1 -2 -3 -4 -5 -6 -7 -8 -9 -10 -11 -12 -13 -14 -15 -16 -17 -18 -19 -20 -21 -22 -23 -24 -25 -26 -27 -28 -29 -30 -31 -32 -33 -34 -35 -36 -37 -38 -39 -40 -41 -42 -43 -44 -45 -46 -47  -1x -  -1x -1x -1x -  -1x -1x -  -  -  -  -  -  -1x -  -  -10x -  -  -  -271x -  -  -  -10x -  -10x -270x -  -9x -  -  -  -  -89x -349x -349x -349x -  -349x -  -  -  -  - 
// tslint:disable-next-line:no-var-requires
-const debug = require("debug").debug("FileSystemFolder");
- 
-import util from "util";
-import fs from "fs";
-import path from "path";
- 
-const readdir = util.promisify(fs.readdir);
-const stat = util.promisify(fs.stat);
- 
-export interface IFileNameFormats {
-    absolute: string;
-    relative: string;
-}
- 
-export default class FileSystemFolder {
-    private name: string;
-    constructor(name: string) {
-        this.name = name;
-    }
- 
-    public getName(): IFileNameFormats {
-        return { relative: this.name, absolute: path.resolve(this.name) };
-    }
- 
-    public async getFileNames(): Promise<IFileNameFormats[]> {
-        const fileNames: IFileNameFormats[] = [];
- 
-        for (const absoluteFileName of await this.getFileNamesRecursively(this.name)) {
-            fileNames.push({ absolute: absoluteFileName, relative: absoluteFileName.replace(path.resolve(this.getName().absolute), "").replace(/\\/g, "/") })
-        }
-        return (fileNames);
-    };
- 
-    private async getFileNamesRecursively(name: string): Promise<string[]> {
- 
-        const subdirs: string[] = await readdir(name);
-        const files = await Promise.all(subdirs.map(async (subdir: string) => {
-            const res: string = path.resolve(name, subdir);
-            return (await stat(res)).isDirectory() ? this.getFileNamesRecursively(res) : res;
-        }));
-        return files.reduce((a: any, f: any) => a.concat(f), []);
-    }
- 
- 
-}
- 
- -
-
- - - - - - - - - \ No newline at end of file diff --git a/docs/coverage/lcov-report/folder.ts.html b/docs/coverage/lcov-report/folder.ts.html deleted file mode 100644 index f6614167..00000000 --- a/docs/coverage/lcov-report/folder.ts.html +++ /dev/null @@ -1,842 +0,0 @@ - - - - - - Code coverage report for folder.ts - - - - - - - - - -
-
-

All files folder.ts

-
- -
- 100% - Statements - 70/70 -
- - -
- 100% - Branches - 11/11 -
- - -
- 100% - Functions - 22/22 -
- - -
- 100% - Lines - 70/70 -
- - -
-

- Press n or j to go to the next uncovered block, b, p or k for the previous block. -

-
-
-

-
1 -2 -3 -4 -5 -6 -7 -8 -9 -10 -11 -12 -13 -14 -15 -16 -17 -18 -19 -20 -21 -22 -23 -24 -25 -26 -27 -28 -29 -30 -31 -32 -33 -34 -35 -36 -37 -38 -39 -40 -41 -42 -43 -44 -45 -46 -47 -48 -49 -50 -51 -52 -53 -54 -55 -56 -57 -58 -59 -60 -61 -62 -63 -64 -65 -66 -67 -68 -69 -70 -71 -72 -73 -74 -75 -76 -77 -78 -79 -80 -81 -82 -83 -84 -85 -86 -87 -88 -89 -90 -91 -92 -93 -94 -95 -96 -97 -98 -99 -100 -101 -102 -103 -104 -105 -106 -107 -108 -109 -110 -111 -112 -113 -114 -115 -116 -117 -118 -119 -120 -121 -122 -123 -124 -125 -126 -127 -128 -129 -130 -131 -132 -133 -134 -135 -136 -137 -138 -139 -140 -141 -142 -143 -144 -145 -146 -147 -148 -149 -150 -151 -152 -153 -154 -155 -156 -157 -158 -159 -160 -161 -162 -163 -164 -165 -166 -167 -168 -169 -170 -171 -172 -173 -174 -175 -176 -177 -178 -179 -180 -181 -182 -183 -184 -185 -186 -187 -188 -189 -190 -191 -192 -193 -194 -195 -196 -197 -198 -199 -200 -201 -202 -203 -204 -205 -206 -207 -208 -209 -210 -211 -212 -213 -214 -215 -216 -217 -218 -219 -220 -221 -222 -223 -224 -225 -226 -227 -228 -229 -230 -231 -232 -233 -234 -235 -236 -237 -238 -239 -240 -241 -242 -243 -244 -245 -246 -247 -248 -249 -250 -251 -252 -253 -254 -255  -1x -  -  -1x -  -  -  -  -  -  -  -  -  -  -1x -  -  -  -  -  -  -  -  -  -  -206x -206x -  -  -  -  -  -  -  -  -  -216x -215x -  -  -  -3x -2x -  -  -  -2x -1x -  -  -  -24x -22x -  -  -  -  -  -  -  -17x -17x -  -  -  -  -  -  -  -2x -2x -2x -1x -  -1x -  -  -  -  -  -  -18x -18x -  -  -  -  -  -  -  -1x -1x -  -  -  -  -  -  -  -  -  -4x -4x -  -  -  -  -  -  -  -  -  -  -21x -  -21x -21x -  -  -21x -162x -1x -  -  -  -  -  -20x -  -  -  -  -  -  -  -28x -28x -28x -  -  -  -  -  -  -  -  -  -1x -1x -1x -1x -1x -1x -  -  -  -  -  -  -  -1x -1x -  -  -  -  -  -  -  -1x -1x -  -  -  -  -  -  -  -  -2x -  -2x -2x -1x -  -1x -  -  -  -  -  -  -  -9x -  -  -  -  -  -  -  -2x -2x -2x -2x -5x -  -2x -  -  -  -  -  -  -  -2x -2x -2x -  -2x -2x -1x -  -  -  -  -  -  -  -  -4x -4x -  -  -  -  -  -  -  -  -  -  -2x -2x -  -  -  -323x -5x -  -  -  -  - 
// tslint:disable-next-line:no-var-requires
-const debug = require("debug").debug("Folder");
- 
-import Client from "./client";
-import ClientError from "./error";
-import File from "./file";
-import FileSystemElement from "./fileSystemElement";
- 
-export interface FolderGetFilesOptions {
-    /**
-     * callback function to filter files
-     */
-    filterFile?: (file: File) => File | null;
-}
- 
-export default class Folder implements FileSystemElement {
-    private client: Client;
-    private memento: {
-        baseName: string,
-        id: number,
-        deleted: boolean,
-        lastmod: Date,
-        name: string,
-    };
-    constructor(client: Client, name: string, baseName: string, lastmod: string, id: number = -1) {
- 
-        this.client = client;
-        this.memento = {
-            baseName,
-            deleted: false,
-            id,
-            lastmod: new Date(lastmod),
-            name,
-        };
-    }
- 
-    get name(): string {
-        this.assertExistence();
-        return this.memento.name;
-    }
- 
-    get baseName(): string {
-        this.assertExistence();
-        return this.memento.baseName;
-    }
- 
-    get lastmod(): Date {
-        this.assertExistence();
-        return this.memento.lastmod;
-    }
- 
-    get id(): number {
-        this.assertExistence();
-        return this.memento.id;
-    }
- 
-    /**
-     * @returns an array of subfolders
-     * @throws Error
-     */
-    public async getSubFolders(): Promise<Folder[]> {
-        this.assertExistence();
-        return await this.client.getSubFolders(this.name);
-    }
- 
-    /**
-     * returns true if the current folder has a subfolder with the given base name
-     * @param subFolderBaseName the base name of the subfolder like "products"
-     */
-    public async hasSubFolder(subFolderBaseName: string): Promise<boolean> {
-        this.assertExistence();
-        const subFolder: Folder | null = await this.client.getFolder(this.name + "/" + subFolderBaseName);
-        if (subFolder) {
-            return true;
-        }
-        return false;
-    }
- 
-    /**
-     * @returns all files of the folder
-     */
-    public async getFiles(options?: FolderGetFilesOptions): Promise<File[]> {
-        this.assertExistence();
-        return await this.client.getFiles(this.name, options);
-    }
- 
-    /**
-     * creates a subfolder
-     * @param subFolderBaseName  name of the subfolder basename
-     */
-    public async createSubFolder(subFolderBaseName: string): Promise<Folder> {
-        this.assertExistence();
-        return await this.client.createFolder(this.name + "/" + subFolderBaseName);
-    }
- 
-    /**
-     * get a file by basename
-     * @param fileBaseName the base name of the file
-     * @returns the file of null
-     * @throws Error
-     */
-    public async getFile(fileBaseName: string): Promise<File | null> {
-        this.assertExistence();
-        return this.client.getFile(this.name + "/" + fileBaseName);
-    }
- 
-    /**
-     * creates a file in the folder
-     * @param fileBaseName the base name of the file
-     * @param data the buffer or stream with file content
-     * @returns the new file or null
-     * @throws Error
-     */
-    public async createFile(fileBaseName: string, data: Buffer | NodeJS.ReadableStream): Promise<File> {
-        this.assertExistence();
-        // must not contain :/\*"<>?
-        debug("createFile fileBaseName = %s", fileBaseName);
-        const invalidChars: string[] = [":", "*", "/", "\\", "\"", "?", "<", ">"];
-        // debug("createFile invalidChars = %O", invalidChars);
- 
-        for (const invalidChar of invalidChars) {
-            if (fileBaseName.indexOf(invalidChar) !== -1) {
-                throw new ClientError("Filename contains an invalid character '" + invalidChar + "'",
-                    "ERR_INVALID_CHAR_IN_FILE_NAME",
-                    { fileBaseName });
-            }
-        }
- 
-        return this.client.createFile(this.name + "/" + fileBaseName.replace(/^\/+/g, ""), data);
-    }
- 
-    /**
-     * deletes the folder and the contained files
-     * @throws Error
-     */
-    public async delete(): Promise<void> {
-        debug("delete");
-        this.memento.deleted = true;
-        return await this.client.deleteFolder(this.memento.name);
-    }
- 
-    /**
-     * renames or moves the current folder to the new location
-     * target folder must exists
-     * @param targetFolderName the name of the target folder /f1/f2/target
-     * @throws Error
-     */
-    public async move(targetFolderName: string): Promise<Folder> {
-        this.assertExistence();
-        const folder: Folder = await this.client.moveFolder(this.name, targetFolderName);
-        this.memento.name = folder.name;
-        this.memento.baseName = folder.baseName;
-        this.memento.lastmod = folder.lastmod;
-        return this;
-    }
- 
-    /**
-     * @returns the url of the folder
-     * @throws Error
-     */
-    public getUrl(): string {
-        this.assertExistence();
-        return this.client.getLink(this.name);
-    }
- 
-    /**
-     * @returns the url of the folder in the UI
-     * @throws Error
-     */
-    public getUIUrl(): string {
-        this.assertExistence();
-        return this.client.getUILink(this.id);
-    }
- 
-    /**
-     * @returns true if the folder contains a file with the given basename
-     * @param fileBaseName file basename
-     * @throws Error
-     */
-    public async containsFile(fileBaseName: string): Promise<boolean> {
-        this.assertExistence();
-        let file: File | null;
-        file = await this.getFile(fileBaseName);
-        if (file) {
-            return true;
-        }
-        return false;
-    }
- 
-    /**
-     * adds a tag name to the folder
-     * @param tagName name of the tag
-     */
-    public async addTag(tagName: string): Promise<void> {
-        return await this.client.addTagToFile(this.id, tagName);
-    }
- 
-    /**
-     * get tag names
-     * @returns array of tag names
-     */
-    public async getTags(): Promise<string[]> {
-        this.assertExistence();
-        const map: Map<string, number> = await this.client.getTagsOfFile(this.id);
-        const tagNames: string[] = [];
-        for (const tagName of map) {
-            tagNames.push(tagName[0]);
-        }
-        return tagNames;
-    }
- 
-    /**
-     * removes a tag of the file
-     * @param tagName the name of the tag
-     */
-    public async removeTag(tagName: string): Promise<void> {
-        this.assertExistence();
-        const map: Map<string, number> = await this.client.getTagsOfFile(this.id);
-        const tagNames: string[] = [];
- 
-        const tagId: number | undefined = map.get(tagName);
-        if (tagId) {
-            await this.client.removeTagOfFile(this.id, tagId);
-        }
-    }
- 
-    /**
-     * add comment to folder
-     * @param comment the comment
-     */
-    public async addComment(comment: string): Promise<void> {
-        this.assertExistence();
-        return await this.client.addCommentToFile(this.id, comment);
-    }
- 
-    /**
-     * get list of comments of folder
-     * @param top number of comments to return
-     * @param skip the offset
-     * @returns array of comment strings
-     * @throws Exception
-     */
-    public async getComments(top?: number, skip?: number): Promise<string[]> {
-        this.assertExistence();
-        return await this.client.getFileComments(this.id, top, skip);
-    }
- 
-    private assertExistence(): void {
-        if (this.memento.deleted) {
-            throw new ClientError("Folder does not exist", "ERR_FOLDER_NOT_EXISTING");
-        }
-    }
- 
-}
- 
- -
-
- - - - - - - - - \ No newline at end of file diff --git a/docs/coverage/lcov-report/getFilesRecursivelyCommand.ts.html b/docs/coverage/lcov-report/getFilesRecursivelyCommand.ts.html deleted file mode 100644 index bbafb6f8..00000000 --- a/docs/coverage/lcov-report/getFilesRecursivelyCommand.ts.html +++ /dev/null @@ -1,368 +0,0 @@ - - - - - - Code coverage report for getFilesRecursivelyCommand.ts - - - - - - - - - -
-
-

All files getFilesRecursivelyCommand.ts

-
- -
- 100% - Statements - 32/32 -
- - -
- 100% - Branches - 4/4 -
- - -
- 100% - Functions - 4/4 -
- - -
- 100% - Lines - 32/32 -
- - -
-

- Press n or j to go to the next uncovered block, b, p or k for the previous block. -

-
-
-

-
1 -2 -3 -4 -5 -6 -7 -8 -9 -10 -11 -12 -13 -14 -15 -16 -17 -18 -19 -20 -21 -22 -23 -24 -25 -26 -27 -28 -29 -30 -31 -32 -33 -34 -35 -36 -37 -38 -39 -40 -41 -42 -43 -44 -45 -46 -47 -48 -49 -50 -51 -52 -53 -54 -55 -56 -57 -58 -59 -60 -61 -62 -63 -64 -65 -66 -67 -68 -69 -70 -71 -72 -73 -74 -75 -76 -77 -78 -79 -80 -81 -82 -83 -84 -85 -86 -87 -88 -89 -90 -91 -92 -93 -94 -95 -96 -97  -1x -  -  -1x -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -1x -  -  -  -  -  -  -  -  -  -  -3x -3x -3x -3x -  -  -  -  -  -  -  -  -3x -3x -3x -3x -3x -  -2x -  -1x -1x -  -  -3x -3x -1x -  -2x -  -3x -3x -  -  -  -  -2x -  -  -  -  -  -  -  -  -  -  -  -17x -17x -16x -17x -  -  -16x -16x -14x -  -16x -  -14x -  -16x -  -  - 
// tslint:disable-next-line:no-var-requires
-const debug = require("debug").debug("GetFilesRecursivelyCommand");
- 
-import Client, { File, Folder, FolderGetFilesOptions } from "./client";
-import Command, { CommandStatus } from "./command";
- 
-export interface GetFilesRecursivelyCommandOptions {
-    /**
-     * the source nextcloud folder to start listing the files
-     */
-    sourceFolder: Folder;
-    /**
-     * function to filter files
-     */
-    filterFile?: (file: File) => File | null;
-}
- 
-/**
- * Command to get all files of a nextcloud folder recursively
- */
-export default class GetFilesRecursivelyCommand extends Command {
-    private sourceFolder: Folder;
-    private filterFile?: (file: File) => File | null;
-    private files: File[];
- 
-    /**
-     * @param {Client} client the client
-     * @param {SourceTargetFileNames[]} files the files to be uploaded
-     * @param {(file: File) => void} processAfterUpload callback function to process the uploaded file
-     */
-    constructor(client: Client, options: GetFilesRecursivelyCommandOptions) {
-        super(client);
-        this.sourceFolder = options.sourceFolder;
-        this.filterFile = options.filterFile;
-        this.files = [];
-    }
- 
-    /**
-     * execute the command
-     * @async
-     * @returns {Promise<void>}
-     */
-    protected async onExecute(): Promise<void> {
-        this.status = CommandStatus.running;
-        const startTime = new Date();
-        try {
-            this.percentCompleted = 0;
-            await this.processFolder(this.sourceFolder, 100);
-            // console.log("file count", this.files.length);
-            this.resultMetaData.messages.push(`${this.files.length} files found`);
-        } catch (e) {
-            debug(e.message);
-            this.resultMetaData.errors.push(e.message);
-        }
- 
-        this.percentCompleted = 100;
-        if (this.resultMetaData.errors.length > 0) {
-            this.status = CommandStatus.failed;
-        } else {
-            this.status = CommandStatus.success;
-        }
-        this.resultMetaData.timeElapsed = new Date().getTime() - startTime.getTime();
-        return;
-    };
- 
- 
-    public getFiles(): File[] {
-        return this.files;
-    }
- 
-    /**
-     * adds files of folder and processes subordinated folders
-     * @param {Folder} folder the folder to process
-     * @param {number} percentagethe percentage that is finished, when the function returns
-     */
-    private async processFolder(folder: Folder, percentage: number): Promise<void> {
-        // tslint:disable-next-line:no-console
-        // console.log(folder.name);
- 
-        const options: FolderGetFilesOptions = { filterFile: this.filterFile }
-        const folderFiles: File[] = await folder.getFiles(options);
-        for (const fi of folderFiles) {
-            this.files.push(fi);
-        }
- 
-        const subFolders: Folder[] = await folder.getSubFolders();
-        if (subFolders.length === 0) {
-            this.percentCompleted += percentage;
-        }
-        for (const subFolder of subFolders) {
-            // console.log("folder", subFolder.name);
-            await this.processFolder(subFolder, percentage / subFolders.length);
-        }
-        return;
-    }
-}
- 
- -
-
- - - - - - - - - \ No newline at end of file diff --git a/docs/coverage/lcov-report/httpClient.ts.html b/docs/coverage/lcov-report/httpClient.ts.html deleted file mode 100644 index f3311a09..00000000 --- a/docs/coverage/lcov-report/httpClient.ts.html +++ /dev/null @@ -1,539 +0,0 @@ - - - - - - Code coverage report for httpClient.ts - - - - - - - - - -
-
-

All files httpClient.ts

-
- -
- 95.31% - Statements - 61/64 -
- - -
- 89.29% - Branches - 25/28 -
- - -
- 88.89% - Functions - 8/9 -
- - -
- 95.08% - Lines - 58/61 -
- - -
-

- Press n or j to go to the next uncovered block, b, p or k for the previous block. -

-
-
-

-
1 -2 -3 -4 -5 -6 -7 -8 -9 -10 -11 -12 -13 -14 -15 -16 -17 -18 -19 -20 -21 -22 -23 -24 -25 -26 -27 -28 -29 -30 -31 -32 -33 -34 -35 -36 -37 -38 -39 -40 -41 -42 -43 -44 -45 -46 -47 -48 -49 -50 -51 -52 -53 -54 -55 -56 -57 -58 -59 -60 -61 -62 -63 -64 -65 -66 -67 -68 -69 -70 -71 -72 -73 -74 -75 -76 -77 -78 -79 -80 -81 -82 -83 -84 -85 -86 -87 -88 -89 -90 -91 -92 -93 -94 -95 -96 -97 -98 -99 -100 -101 -102 -103 -104 -105 -106 -107 -108 -109 -110 -111 -112 -113 -114 -115 -116 -117 -118 -119 -120 -121 -122 -123 -124 -125 -126 -127 -128 -129 -130 -131 -132 -133 -134 -135 -136 -137 -138 -139 -140 -141 -142 -143 -144 -145 -146 -147 -148 -149 -150 -151 -152 -153 -154  -1x -  -1x -  -1x -1x -  -  -  -  -1x -1x -1x -  -1x -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -1x -  -  -  -  -  -  -9x -9x -9x -9x -9x -  -  -  -6x -5x -  -  -6x -1x -  -  -6x -1x -  -  -6x -3x -  -6x -  -  -6x -2x -2x -  -  -  -  -  -2x -  -2x -1x -  -  -  -6x -6x -  -6x -  -3x -1x -  -  -2x -2x -  -  -1x -  -  -  -1x -1x -  -  -1x -1x -  -  -1x -1x -  -  -  -1x -  -  -  -  -1x -  -  -  -  -1x -  -  -  -  -1x -1x -  -  -3x -  -3x -1x -1x -1x -1x -1x -1x -1x -  -  -  -  -  -  -  -2x -  -  -  - 
// tslint:disable-next-line:no-var-requires
-const HttpProxyAgent = require('http-proxy-agent');
- 
-import debugFactory from "debug";
-import { HttpProxyAgentOptions } from "http-proxy-agent";
-import fetch from "node-fetch";
-import {
-    Headers,
-    RequestInit,
-    Response,
-} from "node-fetch";
-import ClientError from "./error";
-import RequestResponseLog from "./requestResponseLog";
-import RequestResponseLogEntry, { RequestLogEntry, ResponseLogEntry } from "./requestResponseLogEntry";
- 
-const debug = debugFactory("HttpClient");
- 
-export interface IRequestContext {
-    "description"?: string;
-}
- 
-export interface IProxy {
-    "host": string;
-    "port": string;
-    "protocol": string;
-    "secureProxy": boolean;
-    "proxyAuthorizationHeader"?: string;
-}
- 
-export interface IHttpClientOptions {
-    "authorizationHeader"?: string;
-    "logRequestResponse"?: boolean;
-    "proxy"?: IProxy;
-    "origin"?: string;
-}
-export class HttpClient {
-    private proxy?: IProxy;
-    private authorizationHeader?: string;
-    private logRequestResponse: boolean;
-    private origin: string;
- 
-    public constructor(options: IHttpClientOptions) {
-        debug("constructor");
-        this.authorizationHeader = options.authorizationHeader;
-        this.proxy = options.proxy;
-        this.logRequestResponse = options.logRequestResponse || false;
-        this.origin = options.origin || "";
-    }
-    public async getHttpResponse(url: string, requestInit: RequestInit, expectedHttpStatusCode: number[], context: IRequestContext): Promise<Response> {
- 
-        if (!requestInit.headers) {
-            requestInit.headers = new Headers();
-        }
- 
-        if (!requestInit.method) {
-            requestInit.method = "UNDEFINED";
-        }
- 
-        if (!context.description) {
-            context.description = "";
-        }
- 
-        if (this.authorizationHeader) {
-            (requestInit.headers as Headers).append("Authorization", this.authorizationHeader);
-        }
-        (requestInit.headers as Headers).append("User-Agent", "nextcloud-node-client");
- 
-        // set the proxy
-        if (this.proxy) {
-            debug("proxy agent used");
-            const options: HttpProxyAgentOptions = {
-                host: this.proxy.host,
-                port: this.proxy.port,
-                protocol: this.proxy.protocol,
-            };
- 
-            requestInit.agent = new HttpProxyAgent(options);
- 
-            if (this.proxy.proxyAuthorizationHeader) {
-                (requestInit.headers as Headers).append("Proxy-Authorization", this.proxy.proxyAuthorizationHeader);
-            }
-        }
- 
-        debug("getHttpResponse request header %O", requestInit.headers);
-        debug("getHttpResponse url:%s, %O", url, requestInit);
- 
-        const response: Response = await fetch(url, requestInit);
- 
-        if (this.logRequestResponse) {
-            const responseText = await response.text();
- 
-            // overwrite response functions as the body uses a stearm object...
-            response.text = async () => {
-                return responseText;
-            };
- 
-            response.body.pipe = (destination: NodeJS.WritableStream, options?: { end?: boolean; }): any => {
-                destination.write(responseText);
-            };
- 
-            response.json = async () => {
-                return JSON.parse(responseText);
-            };
- 
-            response.buffer = async () => {
-                return Buffer.from(responseText);
-            };
- 
-            let body: string = `<Body is ${typeof requestInit.body}>`;
-            Iif (requestInit.body && requestInit.body instanceof Buffer) {
-                body = `<Body is Buffer ${requestInit.body.length}>`;
-            }
- 
-            Iif (typeof requestInit.body === "string") {
-                body = requestInit.body;
-            }
- 
-            const reqLogEntry: RequestLogEntry =
-                new RequestLogEntry(url.replace(this.origin, ""),
-                    requestInit.method, context.description,
-                    body);
- 
-            const resLogEntry: ResponseLogEntry =
-                new ResponseLogEntry(response.status,
-                    await response.text(),
-                    response.headers.get("Content-Type") as string,
-                    response.headers.get("Content-Location") || "");
- 
-            const rrLog: RequestResponseLog = RequestResponseLog.getInstance();
-            await rrLog.addEntry(new RequestResponseLogEntry(reqLogEntry, resLogEntry));
-        }
- 
-        const responseContentType: string | null = response.headers.get("content-type");
- 
-        if (expectedHttpStatusCode.indexOf(response.status) === -1) {
-            debug("getHttpResponse unexpected status response %s", response.status + " " + response.statusText);
-            debug("getHttpResponse description %s", context.description);
-            debug("getHttpResponse expected %s", expectedHttpStatusCode.join(","));
-            debug("getHttpResponse headers %s", JSON.stringify(response.headers, null, 4));
-            debug("getHttpResponse request body %s", requestInit.body);
-            debug("getHttpResponse text %s", await response.text());
-            throw new ClientError(`HTTP response status ${response.status} not expected. Expected status: ${expectedHttpStatusCode.join(",")} - status text: ${response.statusText}`,
-                "ERR_UNEXPECTED_HTTP_STATUS",
-                {
-                    expectedHttpStatusCodes: expectedHttpStatusCode,
-                    responseStatus: response.status,
-                    responseStatusText: response.statusText,
-                });
-        }
-        return response;
-    }
- 
-}
- 
- -
-
- - - - - - - - - \ No newline at end of file diff --git a/docs/coverage/lcov-report/index.html b/docs/coverage/lcov-report/index.html deleted file mode 100644 index a61a6d8f..00000000 --- a/docs/coverage/lcov-report/index.html +++ /dev/null @@ -1,126 +0,0 @@ - - - - - - Code coverage report for All files - - - - - - - - - -
-
-

All files

-
- -
- 93.95% - Statements - 1786/1901 -
- - -
- 89.91% - Branches - 570/634 -
- - -
- 92.25% - Functions - 262/284 -
- - -
- 93.9% - Lines - 1770/1885 -
- - -
-

- Press n or j to go to the next uncovered block, b, p or k for the previous block. -

-
-
-
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
FileStatementsBranchesFunctionsLines
src -
-
94.16%1611/171189.93%545/60691.83%236/25794.12%1602/1702
src/command -
-
92.11%175/19089.29%25/2896.3%26/2791.8%168/183
-
-
-
- - - - - - - - - \ No newline at end of file diff --git a/docs/coverage/lcov-report/prettify.css b/docs/coverage/lcov-report/prettify.css deleted file mode 100644 index b317a7cd..00000000 --- a/docs/coverage/lcov-report/prettify.css +++ /dev/null @@ -1 +0,0 @@ -.pln{color:#000}@media screen{.str{color:#080}.kwd{color:#008}.com{color:#800}.typ{color:#606}.lit{color:#066}.pun,.opn,.clo{color:#660}.tag{color:#008}.atn{color:#606}.atv{color:#080}.dec,.var{color:#606}.fun{color:red}}@media print,projection{.str{color:#060}.kwd{color:#006;font-weight:bold}.com{color:#600;font-style:italic}.typ{color:#404;font-weight:bold}.lit{color:#044}.pun,.opn,.clo{color:#440}.tag{color:#006;font-weight:bold}.atn{color:#404}.atv{color:#060}}pre.prettyprint{padding:2px;border:1px solid #888}ol.linenums{margin-top:0;margin-bottom:0}li.L0,li.L1,li.L2,li.L3,li.L5,li.L6,li.L7,li.L8{list-style-type:none}li.L1,li.L3,li.L5,li.L7,li.L9{background:#eee} diff --git a/docs/coverage/lcov-report/prettify.js b/docs/coverage/lcov-report/prettify.js deleted file mode 100644 index b3225238..00000000 --- a/docs/coverage/lcov-report/prettify.js +++ /dev/null @@ -1,2 +0,0 @@ -/* eslint-disable */ -window.PR_SHOULD_USE_CONTINUATION=true;(function(){var h=["break,continue,do,else,for,if,return,while"];var u=[h,"auto,case,char,const,default,double,enum,extern,float,goto,int,long,register,short,signed,sizeof,static,struct,switch,typedef,union,unsigned,void,volatile"];var p=[u,"catch,class,delete,false,import,new,operator,private,protected,public,this,throw,true,try,typeof"];var l=[p,"alignof,align_union,asm,axiom,bool,concept,concept_map,const_cast,constexpr,decltype,dynamic_cast,explicit,export,friend,inline,late_check,mutable,namespace,nullptr,reinterpret_cast,static_assert,static_cast,template,typeid,typename,using,virtual,where"];var x=[p,"abstract,boolean,byte,extends,final,finally,implements,import,instanceof,null,native,package,strictfp,super,synchronized,throws,transient"];var R=[x,"as,base,by,checked,decimal,delegate,descending,dynamic,event,fixed,foreach,from,group,implicit,in,interface,internal,into,is,lock,object,out,override,orderby,params,partial,readonly,ref,sbyte,sealed,stackalloc,string,select,uint,ulong,unchecked,unsafe,ushort,var"];var r="all,and,by,catch,class,else,extends,false,finally,for,if,in,is,isnt,loop,new,no,not,null,of,off,on,or,return,super,then,true,try,unless,until,when,while,yes";var w=[p,"debugger,eval,export,function,get,null,set,undefined,var,with,Infinity,NaN"];var s="caller,delete,die,do,dump,elsif,eval,exit,foreach,for,goto,if,import,last,local,my,next,no,our,print,package,redo,require,sub,undef,unless,until,use,wantarray,while,BEGIN,END";var I=[h,"and,as,assert,class,def,del,elif,except,exec,finally,from,global,import,in,is,lambda,nonlocal,not,or,pass,print,raise,try,with,yield,False,True,None"];var f=[h,"alias,and,begin,case,class,def,defined,elsif,end,ensure,false,in,module,next,nil,not,or,redo,rescue,retry,self,super,then,true,undef,unless,until,when,yield,BEGIN,END"];var H=[h,"case,done,elif,esac,eval,fi,function,in,local,set,then,until"];var A=[l,R,w,s+I,f,H];var e=/^(DIR|FILE|vector|(de|priority_)?queue|list|stack|(const_)?iterator|(multi)?(set|map)|bitset|u?(int|float)\d*)/;var C="str";var z="kwd";var j="com";var O="typ";var G="lit";var L="pun";var F="pln";var m="tag";var E="dec";var J="src";var P="atn";var n="atv";var N="nocode";var M="(?:^^\\.?|[+-]|\\!|\\!=|\\!==|\\#|\\%|\\%=|&|&&|&&=|&=|\\(|\\*|\\*=|\\+=|\\,|\\-=|\\->|\\/|\\/=|:|::|\\;|<|<<|<<=|<=|=|==|===|>|>=|>>|>>=|>>>|>>>=|\\?|\\@|\\[|\\^|\\^=|\\^\\^|\\^\\^=|\\{|\\||\\|=|\\|\\||\\|\\|=|\\~|break|case|continue|delete|do|else|finally|instanceof|return|throw|try|typeof)\\s*";function k(Z){var ad=0;var S=false;var ac=false;for(var V=0,U=Z.length;V122)){if(!(al<65||ag>90)){af.push([Math.max(65,ag)|32,Math.min(al,90)|32])}if(!(al<97||ag>122)){af.push([Math.max(97,ag)&~32,Math.min(al,122)&~32])}}}}af.sort(function(av,au){return(av[0]-au[0])||(au[1]-av[1])});var ai=[];var ap=[NaN,NaN];for(var ar=0;arat[0]){if(at[1]+1>at[0]){an.push("-")}an.push(T(at[1]))}}an.push("]");return an.join("")}function W(al){var aj=al.source.match(new RegExp("(?:\\[(?:[^\\x5C\\x5D]|\\\\[\\s\\S])*\\]|\\\\u[A-Fa-f0-9]{4}|\\\\x[A-Fa-f0-9]{2}|\\\\[0-9]+|\\\\[^ux0-9]|\\(\\?[:!=]|[\\(\\)\\^]|[^\\x5B\\x5C\\(\\)\\^]+)","g"));var ah=aj.length;var an=[];for(var ak=0,am=0;ak=2&&ai==="["){aj[ak]=X(ag)}else{if(ai!=="\\"){aj[ak]=ag.replace(/[a-zA-Z]/g,function(ao){var ap=ao.charCodeAt(0);return"["+String.fromCharCode(ap&~32,ap|32)+"]"})}}}}return aj.join("")}var aa=[];for(var V=0,U=Z.length;V=0;){S[ac.charAt(ae)]=Y}}var af=Y[1];var aa=""+af;if(!ag.hasOwnProperty(aa)){ah.push(af);ag[aa]=null}}ah.push(/[\0-\uffff]/);V=k(ah)})();var X=T.length;var W=function(ah){var Z=ah.sourceCode,Y=ah.basePos;var ad=[Y,F];var af=0;var an=Z.match(V)||[];var aj={};for(var ae=0,aq=an.length;ae=5&&"lang-"===ap.substring(0,5);if(am&&!(ai&&typeof ai[1]==="string")){am=false;ap=J}if(!am){aj[ag]=ap}}var ab=af;af+=ag.length;if(!am){ad.push(Y+ab,ap)}else{var al=ai[1];var ak=ag.indexOf(al);var ac=ak+al.length;if(ai[2]){ac=ag.length-ai[2].length;ak=ac-al.length}var ar=ap.substring(5);B(Y+ab,ag.substring(0,ak),W,ad);B(Y+ab+ak,al,q(ar,al),ad);B(Y+ab+ac,ag.substring(ac),W,ad)}}ah.decorations=ad};return W}function i(T){var W=[],S=[];if(T.tripleQuotedStrings){W.push([C,/^(?:\'\'\'(?:[^\'\\]|\\[\s\S]|\'{1,2}(?=[^\']))*(?:\'\'\'|$)|\"\"\"(?:[^\"\\]|\\[\s\S]|\"{1,2}(?=[^\"]))*(?:\"\"\"|$)|\'(?:[^\\\']|\\[\s\S])*(?:\'|$)|\"(?:[^\\\"]|\\[\s\S])*(?:\"|$))/,null,"'\""])}else{if(T.multiLineStrings){W.push([C,/^(?:\'(?:[^\\\']|\\[\s\S])*(?:\'|$)|\"(?:[^\\\"]|\\[\s\S])*(?:\"|$)|\`(?:[^\\\`]|\\[\s\S])*(?:\`|$))/,null,"'\"`"])}else{W.push([C,/^(?:\'(?:[^\\\'\r\n]|\\.)*(?:\'|$)|\"(?:[^\\\"\r\n]|\\.)*(?:\"|$))/,null,"\"'"])}}if(T.verbatimStrings){S.push([C,/^@\"(?:[^\"]|\"\")*(?:\"|$)/,null])}var Y=T.hashComments;if(Y){if(T.cStyleComments){if(Y>1){W.push([j,/^#(?:##(?:[^#]|#(?!##))*(?:###|$)|.*)/,null,"#"])}else{W.push([j,/^#(?:(?:define|elif|else|endif|error|ifdef|include|ifndef|line|pragma|undef|warning)\b|[^\r\n]*)/,null,"#"])}S.push([C,/^<(?:(?:(?:\.\.\/)*|\/?)(?:[\w-]+(?:\/[\w-]+)+)?[\w-]+\.h|[a-z]\w*)>/,null])}else{W.push([j,/^#[^\r\n]*/,null,"#"])}}if(T.cStyleComments){S.push([j,/^\/\/[^\r\n]*/,null]);S.push([j,/^\/\*[\s\S]*?(?:\*\/|$)/,null])}if(T.regexLiterals){var X=("/(?=[^/*])(?:[^/\\x5B\\x5C]|\\x5C[\\s\\S]|\\x5B(?:[^\\x5C\\x5D]|\\x5C[\\s\\S])*(?:\\x5D|$))+/");S.push(["lang-regex",new RegExp("^"+M+"("+X+")")])}var V=T.types;if(V){S.push([O,V])}var U=(""+T.keywords).replace(/^ | $/g,"");if(U.length){S.push([z,new RegExp("^(?:"+U.replace(/[\s,]+/g,"|")+")\\b"),null])}W.push([F,/^\s+/,null," \r\n\t\xA0"]);S.push([G,/^@[a-z_$][a-z_$@0-9]*/i,null],[O,/^(?:[@_]?[A-Z]+[a-z][A-Za-z_$@0-9]*|\w+_t\b)/,null],[F,/^[a-z_$][a-z_$@0-9]*/i,null],[G,new RegExp("^(?:0x[a-f0-9]+|(?:\\d(?:_\\d+)*\\d*(?:\\.\\d*)?|\\.\\d\\+)(?:e[+\\-]?\\d+)?)[a-z]*","i"),null,"0123456789"],[F,/^\\[\s\S]?/,null],[L,/^.[^\s\w\.$@\'\"\`\/\#\\]*/,null]);return g(W,S)}var K=i({keywords:A,hashComments:true,cStyleComments:true,multiLineStrings:true,regexLiterals:true});function Q(V,ag){var U=/(?:^|\s)nocode(?:\s|$)/;var ab=/\r\n?|\n/;var ac=V.ownerDocument;var S;if(V.currentStyle){S=V.currentStyle.whiteSpace}else{if(window.getComputedStyle){S=ac.defaultView.getComputedStyle(V,null).getPropertyValue("white-space")}}var Z=S&&"pre"===S.substring(0,3);var af=ac.createElement("LI");while(V.firstChild){af.appendChild(V.firstChild)}var W=[af];function ae(al){switch(al.nodeType){case 1:if(U.test(al.className)){break}if("BR"===al.nodeName){ad(al);if(al.parentNode){al.parentNode.removeChild(al)}}else{for(var an=al.firstChild;an;an=an.nextSibling){ae(an)}}break;case 3:case 4:if(Z){var am=al.nodeValue;var aj=am.match(ab);if(aj){var ai=am.substring(0,aj.index);al.nodeValue=ai;var ah=am.substring(aj.index+aj[0].length);if(ah){var ak=al.parentNode;ak.insertBefore(ac.createTextNode(ah),al.nextSibling)}ad(al);if(!ai){al.parentNode.removeChild(al)}}}break}}function ad(ak){while(!ak.nextSibling){ak=ak.parentNode;if(!ak){return}}function ai(al,ar){var aq=ar?al.cloneNode(false):al;var ao=al.parentNode;if(ao){var ap=ai(ao,1);var an=al.nextSibling;ap.appendChild(aq);for(var am=an;am;am=an){an=am.nextSibling;ap.appendChild(am)}}return aq}var ah=ai(ak.nextSibling,0);for(var aj;(aj=ah.parentNode)&&aj.nodeType===1;){ah=aj}W.push(ah)}for(var Y=0;Y=S){ah+=2}if(V>=ap){Z+=2}}}var t={};function c(U,V){for(var S=V.length;--S>=0;){var T=V[S];if(!t.hasOwnProperty(T)){t[T]=U}else{if(window.console){console.warn("cannot override language handler %s",T)}}}}function q(T,S){if(!(T&&t.hasOwnProperty(T))){T=/^\s*]*(?:>|$)/],[j,/^<\!--[\s\S]*?(?:-\->|$)/],["lang-",/^<\?([\s\S]+?)(?:\?>|$)/],["lang-",/^<%([\s\S]+?)(?:%>|$)/],[L,/^(?:<[%?]|[%?]>)/],["lang-",/^]*>([\s\S]+?)<\/xmp\b[^>]*>/i],["lang-js",/^]*>([\s\S]*?)(<\/script\b[^>]*>)/i],["lang-css",/^]*>([\s\S]*?)(<\/style\b[^>]*>)/i],["lang-in.tag",/^(<\/?[a-z][^<>]*>)/i]]),["default-markup","htm","html","mxml","xhtml","xml","xsl"]);c(g([[F,/^[\s]+/,null," \t\r\n"],[n,/^(?:\"[^\"]*\"?|\'[^\']*\'?)/,null,"\"'"]],[[m,/^^<\/?[a-z](?:[\w.:-]*\w)?|\/?>$/i],[P,/^(?!style[\s=]|on)[a-z](?:[\w:-]*\w)?/i],["lang-uq.val",/^=\s*([^>\'\"\s]*(?:[^>\'\"\s\/]|\/(?=\s)))/],[L,/^[=<>\/]+/],["lang-js",/^on\w+\s*=\s*\"([^\"]+)\"/i],["lang-js",/^on\w+\s*=\s*\'([^\']+)\'/i],["lang-js",/^on\w+\s*=\s*([^\"\'>\s]+)/i],["lang-css",/^style\s*=\s*\"([^\"]+)\"/i],["lang-css",/^style\s*=\s*\'([^\']+)\'/i],["lang-css",/^style\s*=\s*([^\"\'>\s]+)/i]]),["in.tag"]);c(g([],[[n,/^[\s\S]+/]]),["uq.val"]);c(i({keywords:l,hashComments:true,cStyleComments:true,types:e}),["c","cc","cpp","cxx","cyc","m"]);c(i({keywords:"null,true,false"}),["json"]);c(i({keywords:R,hashComments:true,cStyleComments:true,verbatimStrings:true,types:e}),["cs"]);c(i({keywords:x,cStyleComments:true}),["java"]);c(i({keywords:H,hashComments:true,multiLineStrings:true}),["bsh","csh","sh"]);c(i({keywords:I,hashComments:true,multiLineStrings:true,tripleQuotedStrings:true}),["cv","py"]);c(i({keywords:s,hashComments:true,multiLineStrings:true,regexLiterals:true}),["perl","pl","pm"]);c(i({keywords:f,hashComments:true,multiLineStrings:true,regexLiterals:true}),["rb"]);c(i({keywords:w,cStyleComments:true,regexLiterals:true}),["js"]);c(i({keywords:r,hashComments:3,cStyleComments:true,multilineStrings:true,tripleQuotedStrings:true,regexLiterals:true}),["coffee"]);c(g([],[[C,/^[\s\S]+/]]),["regex"]);function d(V){var U=V.langExtension;try{var S=a(V.sourceNode);var T=S.sourceCode;V.sourceCode=T;V.spans=S.spans;V.basePos=0;q(U,T)(V);D(V)}catch(W){if("console" in window){console.log(W&&W.stack?W.stack:W)}}}function y(W,V,U){var S=document.createElement("PRE");S.innerHTML=W;if(U){Q(S,U)}var T={langExtension:V,numberLines:U,sourceNode:S};d(T);return S.innerHTML}function b(ad){function Y(af){return document.getElementsByTagName(af)}var ac=[Y("pre"),Y("code"),Y("xmp")];var T=[];for(var aa=0;aa=0){var ah=ai.match(ab);var am;if(!ah&&(am=o(aj))&&"CODE"===am.tagName){ah=am.className.match(ab)}if(ah){ah=ah[1]}var al=false;for(var ak=aj.parentNode;ak;ak=ak.parentNode){if((ak.tagName==="pre"||ak.tagName==="code"||ak.tagName==="xmp")&&ak.className&&ak.className.indexOf("prettyprint")>=0){al=true;break}}if(!al){var af=aj.className.match(/\blinenums\b(?::(\d+))?/);af=af?af[1]&&af[1].length?+af[1]:true:false;if(af){Q(aj,af)}S={langExtension:ah,sourceNode:aj,numberLines:af};d(S)}}}if(X]*(?:>|$)/],[PR.PR_COMMENT,/^<\!--[\s\S]*?(?:-\->|$)/],[PR.PR_PUNCTUATION,/^(?:<[%?]|[%?]>)/],["lang-",/^<\?([\s\S]+?)(?:\?>|$)/],["lang-",/^<%([\s\S]+?)(?:%>|$)/],["lang-",/^]*>([\s\S]+?)<\/xmp\b[^>]*>/i],["lang-handlebars",/^]*type\s*=\s*['"]?text\/x-handlebars-template['"]?\b[^>]*>([\s\S]*?)(<\/script\b[^>]*>)/i],["lang-js",/^]*>([\s\S]*?)(<\/script\b[^>]*>)/i],["lang-css",/^]*>([\s\S]*?)(<\/style\b[^>]*>)/i],["lang-in.tag",/^(<\/?[a-z][^<>]*>)/i],[PR.PR_DECLARATION,/^{{[#^>/]?\s*[\w.][^}]*}}/],[PR.PR_DECLARATION,/^{{&?\s*[\w.][^}]*}}/],[PR.PR_DECLARATION,/^{{{>?\s*[\w.][^}]*}}}/],[PR.PR_COMMENT,/^{{![^}]*}}/]]),["handlebars","hbs"]);PR.registerLangHandler(PR.createSimpleLexer([[PR.PR_PLAIN,/^[ \t\r\n\f]+/,null," \t\r\n\f"]],[[PR.PR_STRING,/^\"(?:[^\n\r\f\\\"]|\\(?:\r\n?|\n|\f)|\\[\s\S])*\"/,null],[PR.PR_STRING,/^\'(?:[^\n\r\f\\\']|\\(?:\r\n?|\n|\f)|\\[\s\S])*\'/,null],["lang-css-str",/^url\(([^\)\"\']*)\)/i],[PR.PR_KEYWORD,/^(?:url|rgb|\!important|@import|@page|@media|@charset|inherit)(?=[^\-\w]|$)/i,null],["lang-css-kw",/^(-?(?:[_a-z]|(?:\\[0-9a-f]+ ?))(?:[_a-z0-9\-]|\\(?:\\[0-9a-f]+ ?))*)\s*:/i],[PR.PR_COMMENT,/^\/\*[^*]*\*+(?:[^\/*][^*]*\*+)*\//],[PR.PR_COMMENT,/^(?:)/],[PR.PR_LITERAL,/^(?:\d+|\d*\.\d+)(?:%|[a-z]+)?/i],[PR.PR_LITERAL,/^#(?:[0-9a-f]{3}){1,2}/i],[PR.PR_PLAIN,/^-?(?:[_a-z]|(?:\\[\da-f]+ ?))(?:[_a-z\d\-]|\\(?:\\[\da-f]+ ?))*/i],[PR.PR_PUNCTUATION,/^[^\s\w\'\"]+/]]),["css"]);PR.registerLangHandler(PR.createSimpleLexer([],[[PR.PR_KEYWORD,/^-?(?:[_a-z]|(?:\\[\da-f]+ ?))(?:[_a-z\d\-]|\\(?:\\[\da-f]+ ?))*/i]]),["css-kw"]);PR.registerLangHandler(PR.createSimpleLexer([],[[PR.PR_STRING,/^[^\)\"\']+/]]),["css-str"]); diff --git a/docs/coverage/lcov-report/requestResponseLog.ts.html b/docs/coverage/lcov-report/requestResponseLog.ts.html deleted file mode 100644 index 723228f6..00000000 --- a/docs/coverage/lcov-report/requestResponseLog.ts.html +++ /dev/null @@ -1,419 +0,0 @@ - - - - - - Code coverage report for requestResponseLog.ts - - - - - - - - - -
-
-

All files requestResponseLog.ts

-
- -
- 100% - Statements - 54/54 -
- - -
- 100% - Branches - 24/24 -
- - -
- 100% - Functions - 9/9 -
- - -
- 100% - Lines - 54/54 -
- - -
-

- Press n or j to go to the next uncovered block, b, p or k for the previous block. -

-
-
-

-
1 -2 -3 -4 -5 -6 -7 -8 -9 -10 -11 -12 -13 -14 -15 -16 -17 -18 -19 -20 -21 -22 -23 -24 -25 -26 -27 -28 -29 -30 -31 -32 -33 -34 -35 -36 -37 -38 -39 -40 -41 -42 -43 -44 -45 -46 -47 -48 -49 -50 -51 -52 -53 -54 -55 -56 -57 -58 -59 -60 -61 -62 -63 -64 -65 -66 -67 -68 -69 -70 -71 -72 -73 -74 -75 -76 -77 -78 -79 -80 -81 -82 -83 -84 -85 -86 -87 -88 -89 -90 -91 -92 -93 -94 -95 -96 -97 -98 -99 -100 -101 -102 -103 -104 -105 -106 -107 -108 -109 -110 -111 -112 -113 -114  -1x -1x -1x -1x -  -  -1x -  -1x -1x -  -  -8x -  -  -166x -9x -  -166x -  -1x -  -9x -  -9x -  -9x -9x -  -  -  -11x -11x -1x -1x -  -  -10x -8x -4x -  -8x -1x -  -  -  -10x -8x -4x -  -  -  -10x -10x -  -  -  -160x -160x -1x -1x -  -  -159x -96x -  -  -  -162x -162x -  -162x -162x -  -  -162x -  -  -  -331x -  -  -  -8x -6x -  -2x -  -  -  -162x -162x -162x -  -162x -646x -162x -  -484x -  -  -646x -646x -  -  -  -  -  -  -  -  -  - 
 
-import debugFactory from "debug";
-import parser from "fast-xml-parser";
-import { promises as fsPromises } from "fs";
-import path from "path";
-import requestResponseLogEntry from "./requestResponseLogEntry";
- 
-const debug = debugFactory("RequestResponseLog");
- 
-export default class RequestResponseLog {
-    public static readonly defaultLogDirectory: string = "RequestResponseLog/";
- 
-    public static deleteInstance(): void {
-        RequestResponseLog.log = null;
-    }
-    public static getInstance(): RequestResponseLog {
-        if (!RequestResponseLog.log) {
-            RequestResponseLog.log = new RequestResponseLog();
-        }
-        return RequestResponseLog.log;
-    }
-    private static log: RequestResponseLog | null = null;
- 
-    public baseDirectory: string = RequestResponseLog.defaultLogDirectory;
-    private context: string;
-    private entries: requestResponseLogEntry[] = [];
-    private constructor() {
-        this.baseDirectory = RequestResponseLog.defaultLogDirectory;
-        this.context = "";
-    }
- 
-    public async addEntry(logEntry: requestResponseLogEntry) {
-        debug("addEntry");
-        if (!this.context) {
-            debug("Error while recording, context not set");
-            throw new Error("Error while recording, context not set");
-        }
- 
-        if (logEntry.response.body && logEntry.response.contentType) {
-            if (logEntry.response.contentType.indexOf("application/xml") !== -1) {
-                logEntry.response.jsonBody = this.xmlToJson(logEntry.response.body);
-            }
-            if (logEntry.response.contentType.indexOf("application/json") !== -1) {
-                logEntry.response.jsonBody = JSON.parse(logEntry.response.body);
-            }
-        }
- 
-        if (logEntry.request.body) {
-            if (logEntry.request.body.indexOf && logEntry.request.body.indexOf("<?xml version") !== -1) {
-                logEntry.request.jsonBody = this.xmlToJson(logEntry.request.body);
-            }
-        }
- 
-        this.entries.push(logEntry);
-        await fsPromises.writeFile(this.getFileName(), JSON.stringify(this.entries, null, 4));
-    }
- 
-    public async getEntries(): Promise<requestResponseLogEntry[]> {
-        debug("getEntries");
-        if (!this.context) {
-            debug("Error while getting recording request, context not set");
-            throw new Error("Error while getting recording request, context not set");
-        }
- 
-        const entries: string = await fsPromises.readFile(this.getFileName(), { encoding: "utf8" });
-        return JSON.parse(entries);
-    }
- 
-    public async setContext(context: string) {
-        debug("setContext");
-        const newContext: string = context.replace(/ |:|\./g, "_");
-        // if (this.context !== newContext) {
-        this.context = newContext;
-        this.entries = [];
-        // }
-        // create the directory
-        await this.assertDirectory(this.getFileName());
-    }
- 
-    public getFileName(): string {
-        return `${this.baseDirectory}${this.context}.json`;
-    }
- 
-    private xmlToJson(xml: string): any {
-        if (parser.validate(xml) === true) {
-            return parser.parse(xml, { ignoreNameSpace: true });
-        }
-        return { info: "invalid xml" };
-    }
- 
-    private async assertDirectory(filename: string): Promise<void> {
-        const directory = path.dirname(filename);
-        const pathArray: string[] = directory.split("/");
-        let p: string = "";
- 
-        for (const dir of pathArray) {
-            if (p === "") {
-                p = dir;
-            } else {
-                p = p + "/" + dir;
-            }
- 
-            try {
-                await fsPromises.mkdir(p);
-                  /* istanbul ignore next */
-                debug(`directory "${p}" created`);
-            } catch (e) {
-                  /* istanbul ignore next */                
-                debug(`directory "${p}" already exists`);
-            }
-        }
-    }
-}
- 
- -
-
- - - - - - - - - \ No newline at end of file diff --git a/docs/coverage/lcov-report/requestResponseLogEntry.ts.html b/docs/coverage/lcov-report/requestResponseLogEntry.ts.html deleted file mode 100644 index b2ccd29b..00000000 --- a/docs/coverage/lcov-report/requestResponseLogEntry.ts.html +++ /dev/null @@ -1,197 +0,0 @@ - - - - - - Code coverage report for requestResponseLogEntry.ts - - - - - - - - - -
-
-

All files requestResponseLogEntry.ts

-
- -
- 100% - Statements - 13/13 -
- - -
- 100% - Branches - 0/0 -
- - -
- 100% - Functions - 3/3 -
- - -
- 100% - Lines - 13/13 -
- - -
-

- Press n or j to go to the next uncovered block, b, p or k for the previous block. -

-
-
-

-
1 -2 -3 -4 -5 -6 -7 -8 -9 -10 -11 -12 -13 -14 -15 -16 -17 -18 -19 -20 -21 -22 -23 -24 -25 -26 -27 -28 -29 -30 -31 -32 -33 -34 -35 -36 -37 -38 -39 -40  -1x -  -  -  -  -  -  -7x -7x -7x -7x -  -  -  -  -1x -  -  -  -  -  -  -7x -7x -7x -7x -  -  -  -  -1x -  -  -  -11x -11x -  -  - 
 
-export class RequestLogEntry {
-    public body?: string;
-    public description: string;
-    public jsonBody?: any;
-    public method: string;
-    public url: string;
-    public constructor(url: string, method: string, description: string, body?: string) {
-        this.url = url;
-        this.method = method;
-        this.description = description;
-        this.body = body;
-    }
-}
- 
-// tslint:disable-next-line:max-classes-per-file
-export class ResponseLogEntry {
-    public body?: string;
-    public contentType?: string;
-    public contentLocation?: string;
-    public jsonBody?: any;
-    public status: number;
-    public constructor(status: number, body?: string, contentType?: string, contentLocation?: string) {
-        this.status = status;
-        this.body = body;
-        this.contentType = contentType;
-        this.contentLocation = contentLocation;
-    }
-}
- 
-// tslint:disable-next-line:max-classes-per-file
-export default class RequestResponseLogEntry {
-    public request: RequestLogEntry;
-    public response: ResponseLogEntry;
-    public constructor(request: RequestLogEntry, response: ResponseLogEntry) {
-        this.request = request;
-        this.response = response;
-    }
-}
- 
- -
-
- - - - - - - - - \ No newline at end of file diff --git a/docs/coverage/lcov-report/server.ts.html b/docs/coverage/lcov-report/server.ts.html deleted file mode 100644 index 4d1a9369..00000000 --- a/docs/coverage/lcov-report/server.ts.html +++ /dev/null @@ -1,188 +0,0 @@ - - - - - - Code coverage report for server.ts - - - - - - - - - -
-
-

All files server.ts

-
- -
- 100% - Statements - 10/10 -
- - -
- 100% - Branches - 2/2 -
- - -
- 100% - Functions - 1/1 -
- - -
- 100% - Lines - 10/10 -
- - -
-

- Press n or j to go to the next uncovered block, b, p or k for the previous block. -

-
-
-

-
1 -2 -3 -4 -5 -6 -7 -8 -9 -10 -11 -12 -13 -14 -15 -16 -17 -18 -19 -20 -21 -22 -23 -24 -25 -26 -27 -28 -29 -30 -31 -32 -33 -34 -35 -36 -371x -  -  -1x -  -  -  -  -  -  -  -  -  -  -  -  -  -  -1x -  -  -  -  -  -  -9x -9x -9x -9x -9x -1x -  -8x -  -  -  - 
import debugFactory from "debug";
-import { IProxy } from "./httpClient";
- 
-const debug = debugFactory("NCServer");
- 
-export interface IBasicAuth {
-    "username": string;
-    "password": string;
-}
- 
-export interface IServerOptions {
-    "url": string;
-    "basicAuth": IBasicAuth;
-    "proxy"?: IProxy;
-    "logRequestResponse"?: boolean;
-}
- 
-// tslint:disable-next-line: max-classes-per-file
-export default class Server {
-    public url: string;
-    public basicAuth: IBasicAuth;
-    public proxy?: IProxy;
-    public logRequestResponse: boolean;
-    //    public constructor(url: string, basicAuth: IBasicAuth, proxy?: IProxy, logRequestResponse: boolean = false) {
-    public constructor(options: IServerOptions) {
-        debug("constructor");
-        this.url = options.url;
-        this.basicAuth = options.basicAuth;
-        this.proxy = options.proxy;
-        if (options.logRequestResponse) {
-            this.logRequestResponse = true;
-        } else {
-            this.logRequestResponse = false;
-        }
-    }
-}
- 
- -
-
- - - - - - - - - \ No newline at end of file diff --git a/docs/coverage/lcov-report/share.ts.html b/docs/coverage/lcov-report/share.ts.html deleted file mode 100644 index 68a7136a..00000000 --- a/docs/coverage/lcov-report/share.ts.html +++ /dev/null @@ -1,704 +0,0 @@ - - - - - - Code coverage report for share.ts - - - - - - - - - -
-
-

All files share.ts

-
- -
- 100% - Statements - 59/59 -
- - -
- 100% - Branches - 28/28 -
- - -
- 100% - Functions - 16/16 -
- - -
- 100% - Lines - 59/59 -
- - -
-

- Press n or j to go to the next uncovered block, b, p or k for the previous block. -

-
-
-

-
1 -2 -3 -4 -5 -6 -7 -8 -9 -10 -11 -12 -13 -14 -15 -16 -17 -18 -19 -20 -21 -22 -23 -24 -25 -26 -27 -28 -29 -30 -31 -32 -33 -34 -35 -36 -37 -38 -39 -40 -41 -42 -43 -44 -45 -46 -47 -48 -49 -50 -51 -52 -53 -54 -55 -56 -57 -58 -59 -60 -61 -62 -63 -64 -65 -66 -67 -68 -69 -70 -71 -72 -73 -74 -75 -76 -77 -78 -79 -80 -81 -82 -83 -84 -85 -86 -87 -88 -89 -90 -91 -92 -93 -94 -95 -96 -97 -98 -99 -100 -101 -102 -103 -104 -105 -106 -107 -108 -109 -110 -111 -112 -113 -114 -115 -116 -117 -118 -119 -120 -121 -122 -123 -124 -125 -126 -127 -128 -129 -130 -131 -132 -133 -134 -135 -136 -137 -138 -139 -140 -141 -142 -143 -144 -145 -146 -147 -148 -149 -150 -151 -152 -153 -154 -155 -156 -157 -158 -159 -160 -161 -162 -163 -164 -165 -166 -167 -168 -169 -170 -171 -172 -173 -174 -175 -176 -177 -178 -179 -180 -181 -182 -183 -184 -185 -186 -187 -188 -189 -190 -191 -192 -193 -194 -195 -196 -197 -198 -199 -200 -201 -202 -203 -204 -205 -206 -207 -208 -2091x -  -  -  -  -1x -1x -1x -1x -1x -1x -1x -  -  -1x -1x -1x -1x -1x -  -  -  -  -  -  -  -  -  -1x -1x -1x -  -1x -  -  -10x -10x -6x -  -  -  -2x -  -  -  -  -  -  -  -2x -  -  -  -  -  -2x -1x -  -1x -  -  -2x -1x -  -  -2x -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -10x -10x -  -  -  -  -  -  -  -  -  -  -1x -  -  -  -1x -1x -  -  -  -  -  -  -  -1x -  -  -  -1x -1x -  -  -  -10x -  -10x -1x -  -  -9x -1x -  -8x -  -8x -1x -  -7x -  -7x -1x -  -  -6x -5x -  -1x -  -6x -2x -  -  -6x -1x -  -  -  -  -  -  -  -  -  -  -  -2x -  -  -  -  -  -  -  -2x -  -  -  -  -  -  -  -1x -  -  -  -  -  -  -  -2x -  -  -  -  -  -  -  -2x -  -  -  - 
import Client, { ClientError } from "./client";
-import File from "./file";
-import FileSystemElement from "./fileSystemElement";
-import Folder from "./folder";
- 
-export enum SharePermission {
-    all = 31,
-    read = 1,
-    update = 2,
-    create = 4,
-    delete = 8,
-    share = 16,
-}
- 
-enum ShareType {
-    user = 0,
-    group = 1,
-    publicLink = 3,
-    email = 4,
-}
- 
-export interface ICreateShare {
-    "fileSystemElement": FileSystemElement;
-    // @todo "shareWith"?: User | UserGroup | EMail;
-    "publicUpload"?: boolean;
-    "password"?: string;
-}
- 
-enum ShareItemType {
-    file = "file",
-    folder = "folder",
-}
-export default class Share {
- 
-    public static async getShare(client: Client, id: string): Promise<Share> {
-        const share: Share = new Share(client, id);
-        await share.initialize();
-        return share;
-    }
- 
-    public static createShareRequestBody(createShare: ICreateShare): string {
-        const shareType: ShareType = ShareType.publicLink;
- 
-        const shareRequest: {
-            path: string,
-            shareType: number,
-            // @todo   permissions: number | number[]
-            password?: string,
-            publicUpload?: string,
-        } = {
-            path: createShare.fileSystemElement.name,
-            //  @todo    permissions: 1,
-            shareType,
-        };
- 
-        if (createShare.publicUpload && createShare.publicUpload === true) {
-            shareRequest.publicUpload = "enable";
-        } else {
-            shareRequest.publicUpload = "disable";
-        }
- 
-        if (createShare.password) {
-            shareRequest.password = createShare.password;
-        }
- 
-        return JSON.stringify(shareRequest, null, 4);
-    }
- 
-    private client: Client;
-    private memento: {
-        expiration: Date | null,
-        id: string;
-        itemType: ShareItemType,
-        note: string,
-        token: string,
-        url: string,
-        // share_type: number,
-        // "uid_owner": string,
-        // "displayname_owner": string,
-        // "permissions": SharePermission,
-        // "can_edit": boolean,
-        // "can_delete": boolean,
-        // "stime": Date,
-        // "parent"?: Share,
-        // "uid_file_owner": string,
-        // "label"?: string,
-        // "displayname_file_owner": string,
-        // "path": string,
-        // "mimetype"?: string,
-        // "share_with"?: string,
-        // "share_with_displayname"?: string,
-        // "mail_send": boolean,
-        // "hide_download": boolean,
-    };
- 
-    private constructor(client: Client, id: string) {
-        this.client = client;
-        this.memento = {
-            expiration: null,
-            id,
-            itemType: ShareItemType.file,
-            note: "",
-            token: "",
-            url: "",
-        };
-    }
- 
-    public async delete(): Promise<void> {
-        await this.client.deleteShare(this.memento.id);
-    }
- 
-    public async setExpiration(expiration: Date): Promise<void> {
-        this.memento.expiration = expiration;
-        await this.client.updateShare(this.memento.id, { expireDate: expiration.toISOString().split("T")[0] });
-    }
- 
-    /**
-     * set a new password
-     * @param password
-     */
-    public async setPassword(password: string): Promise<void> {
-        await this.client.updateShare(this.memento.id, { password });
-    }
- 
-    public async setNote(note: string): Promise<void> {
-        this.memento.note = note;
-        await this.client.updateShare(this.memento.id, { note });
-    }
- 
-    private async initialize(): Promise<void> {
-        const rawShareData = await this.client.getShare(this.memento.id);
- 
-        if (!rawShareData.ocs || !rawShareData.ocs.data[0]) {
-            throw new ClientError(`Error invalid share data received "ocs.data" missing`, "ERR_INVALID_SHARE_RESPONSE");
-        }
- 
-        if (!rawShareData.ocs.data[0].url) {
-            throw new ClientError(`Error invalid share data received "url" missing`, "ERR_INVALID_SHARE_RESPONSE");
-        }
-        this.memento.url = rawShareData.ocs.data[0].url;
- 
-        if (!rawShareData.ocs.data[0].token) {
-            throw new ClientError(`Error invalid share data received "token" missing`, "ERR_INVALID_SHARE_RESPONSE");
-        }
-        this.memento.token = rawShareData.ocs.data[0].token;
- 
-        if (!rawShareData.ocs.data[0].item_type) {
-            throw new ClientError(`Error invalid share data received "item_type" missing`, "ERR_INVALID_SHARE_RESPONSE");
-        }
- 
-        if (rawShareData.ocs.data[0].item_type === "file") {
-            this.memento.itemType = ShareItemType.file;
-        } else {
-            this.memento.itemType = ShareItemType.folder;
-        }
-        if (rawShareData.ocs.data[0].expiration) {
-            this.memento.expiration = new Date(rawShareData.ocs.data[0].expiration);
-        }
- 
-        if (rawShareData.ocs.data[0].note) {
-            this.memento.note = rawShareData.ocs.data[0].note;
-        }
- 
-        // console.log(JSON.stringify(rawShareData, null, 4));
-        // console.log(JSON.stringify(this, null, 4));
-    }
- 
-    /**
-     * token
-     * The token is readonly
-     */
-    public get token(): string {
-        return this.memento.token;
-    }
- 
-    /**
-     * share url
-     * The share url is readonly
-     */
-    public get url(): string {
-        return this.memento.url;
-    }
- 
-    /**
-     * expiration
-     * The expiration is readonly
-     */
-    public get expiration(): Date | null {
-        return this.memento.expiration;
-    }
- 
-    /**
-     * note
-     * The note is readonly
-     */
-    public get note(): string {
-        return this.memento.note;
-    }
- 
-    /**
-     * id
-     * The id is readonly
-     */
-    public get id(): string {
-        return this.memento.id;
-    }
- 
-}
- 
- -
-
- - - - - - - - - \ No newline at end of file diff --git a/docs/coverage/lcov-report/sort-arrow-sprite.png b/docs/coverage/lcov-report/sort-arrow-sprite.png deleted file mode 100644 index 03f704a6..00000000 Binary files a/docs/coverage/lcov-report/sort-arrow-sprite.png and /dev/null differ diff --git a/docs/coverage/lcov-report/sorter.js b/docs/coverage/lcov-report/sorter.js deleted file mode 100644 index 16de10c4..00000000 --- a/docs/coverage/lcov-report/sorter.js +++ /dev/null @@ -1,170 +0,0 @@ -/* eslint-disable */ -var addSorting = (function() { - 'use strict'; - var cols, - currentSort = { - index: 0, - desc: false - }; - - // returns the summary table element - function getTable() { - return document.querySelector('.coverage-summary'); - } - // returns the thead element of the summary table - function getTableHeader() { - return getTable().querySelector('thead tr'); - } - // returns the tbody element of the summary table - function getTableBody() { - return getTable().querySelector('tbody'); - } - // returns the th element for nth column - function getNthColumn(n) { - return getTableHeader().querySelectorAll('th')[n]; - } - - // loads all columns - function loadColumns() { - var colNodes = getTableHeader().querySelectorAll('th'), - colNode, - cols = [], - col, - i; - - for (i = 0; i < colNodes.length; i += 1) { - colNode = colNodes[i]; - col = { - key: colNode.getAttribute('data-col'), - sortable: !colNode.getAttribute('data-nosort'), - type: colNode.getAttribute('data-type') || 'string' - }; - cols.push(col); - if (col.sortable) { - col.defaultDescSort = col.type === 'number'; - colNode.innerHTML = - colNode.innerHTML + ''; - } - } - return cols; - } - // attaches a data attribute to every tr element with an object - // of data values keyed by column name - function loadRowData(tableRow) { - var tableCols = tableRow.querySelectorAll('td'), - colNode, - col, - data = {}, - i, - val; - for (i = 0; i < tableCols.length; i += 1) { - colNode = tableCols[i]; - col = cols[i]; - val = colNode.getAttribute('data-value'); - if (col.type === 'number') { - val = Number(val); - } - data[col.key] = val; - } - return data; - } - // loads all row data - function loadData() { - var rows = getTableBody().querySelectorAll('tr'), - i; - - for (i = 0; i < rows.length; i += 1) { - rows[i].data = loadRowData(rows[i]); - } - } - // sorts the table using the data for the ith column - function sortByIndex(index, desc) { - var key = cols[index].key, - sorter = function(a, b) { - a = a.data[key]; - b = b.data[key]; - return a < b ? -1 : a > b ? 1 : 0; - }, - finalSorter = sorter, - tableBody = document.querySelector('.coverage-summary tbody'), - rowNodes = tableBody.querySelectorAll('tr'), - rows = [], - i; - - if (desc) { - finalSorter = function(a, b) { - return -1 * sorter(a, b); - }; - } - - for (i = 0; i < rowNodes.length; i += 1) { - rows.push(rowNodes[i]); - tableBody.removeChild(rowNodes[i]); - } - - rows.sort(finalSorter); - - for (i = 0; i < rows.length; i += 1) { - tableBody.appendChild(rows[i]); - } - } - // removes sort indicators for current column being sorted - function removeSortIndicators() { - var col = getNthColumn(currentSort.index), - cls = col.className; - - cls = cls.replace(/ sorted$/, '').replace(/ sorted-desc$/, ''); - col.className = cls; - } - // adds sort indicators for current column being sorted - function addSortIndicators() { - getNthColumn(currentSort.index).className += currentSort.desc - ? ' sorted-desc' - : ' sorted'; - } - // adds event listeners for all sorter widgets - function enableUI() { - var i, - el, - ithSorter = function ithSorter(i) { - var col = cols[i]; - - return function() { - var desc = col.defaultDescSort; - - if (currentSort.index === i) { - desc = !currentSort.desc; - } - sortByIndex(i, desc); - removeSortIndicators(); - currentSort.index = i; - currentSort.desc = desc; - addSortIndicators(); - }; - }; - for (i = 0; i < cols.length; i += 1) { - if (cols[i].sortable) { - // add the click event handler on the th so users - // dont have to click on those tiny arrows - el = getNthColumn(i).querySelector('.sorter').parentElement; - if (el.addEventListener) { - el.addEventListener('click', ithSorter(i)); - } else { - el.attachEvent('onclick', ithSorter(i)); - } - } - } - } - // adds sorting functionality to the UI - return function() { - if (!getTable()) { - return; - } - cols = loadColumns(); - loadData(); - addSortIndicators(); - enableUI(); - }; -})(); - -window.addEventListener('load', addSorting); diff --git a/docs/coverage/lcov-report/src/client.ts.html b/docs/coverage/lcov-report/src/client.ts.html deleted file mode 100644 index 71ec7a95..00000000 --- a/docs/coverage/lcov-report/src/client.ts.html +++ /dev/null @@ -1,9203 +0,0 @@ - - - - - - Code coverage report for src/client.ts - - - - - - - - - -
-
-

All files / src client.ts

-
- -
- 92.97% - Statements - 1031/1109 -
- - -
- 87.44% - Branches - 383/438 -
- - -
- 92% - Functions - 92/100 -
- - -
- 92.94% - Lines - 1027/1105 -
- - -
-

- Press n or j to go to the next uncovered block, b, p or k for the previous block. -

-
-
-

-
1 -2 -3 -4 -5 -6 -7 -8 -9 -10 -11 -12 -13 -14 -15 -16 -17 -18 -19 -20 -21 -22 -23 -24 -25 -26 -27 -28 -29 -30 -31 -32 -33 -34 -35 -36 -37 -38 -39 -40 -41 -42 -43 -44 -45 -46 -47 -48 -49 -50 -51 -52 -53 -54 -55 -56 -57 -58 -59 -60 -61 -62 -63 -64 -65 -66 -67 -68 -69 -70 -71 -72 -73 -74 -75 -76 -77 -78 -79 -80 -81 -82 -83 -84 -85 -86 -87 -88 -89 -90 -91 -92 -93 -94 -95 -96 -97 -98 -99 -100 -101 -102 -103 -104 -105 -106 -107 -108 -109 -110 -111 -112 -113 -114 -115 -116 -117 -118 -119 -120 -121 -122 -123 -124 -125 -126 -127 -128 -129 -130 -131 -132 -133 -134 -135 -136 -137 -138 -139 -140 -141 -142 -143 -144 -145 -146 -147 -148 -149 -150 -151 -152 -153 -154 -155 -156 -157 -158 -159 -160 -161 -162 -163 -164 -165 -166 -167 -168 -169 -170 -171 -172 -173 -174 -175 -176 -177 -178 -179 -180 -181 -182 -183 -184 -185 -186 -187 -188 -189 -190 -191 -192 -193 -194 -195 -196 -197 -198 -199 -200 -201 -202 -203 -204 -205 -206 -207 -208 -209 -210 -211 -212 -213 -214 -215 -216 -217 -218 -219 -220 -221 -222 -223 -224 -225 -226 -227 -228 -229 -230 -231 -232 -233 -234 -235 -236 -237 -238 -239 -240 -241 -242 -243 -244 -245 -246 -247 -248 -249 -250 -251 -252 -253 -254 -255 -256 -257 -258 -259 -260 -261 -262 -263 -264 -265 -266 -267 -268 -269 -270 -271 -272 -273 -274 -275 -276 -277 -278 -279 -280 -281 -282 -283 -284 -285 -286 -287 -288 -289 -290 -291 -292 -293 -294 -295 -296 -297 -298 -299 -300 -301 -302 -303 -304 -305 -306 -307 -308 -309 -310 -311 -312 -313 -314 -315 -316 -317 -318 -319 -320 -321 -322 -323 -324 -325 -326 -327 -328 -329 -330 -331 -332 -333 -334 -335 -336 -337 -338 -339 -340 -341 -342 -343 -344 -345 -346 -347 -348 -349 -350 -351 -352 -353 -354 -355 -356 -357 -358 -359 -360 -361 -362 -363 -364 -365 -366 -367 -368 -369 -370 -371 -372 -373 -374 -375 -376 -377 -378 -379 -380 -381 -382 -383 -384 -385 -386 -387 -388 -389 -390 -391 -392 -393 -394 -395 -396 -397 -398 -399 -400 -401 -402 -403 -404 -405 -406 -407 -408 -409 -410 -411 -412 -413 -414 -415 -416 -417 -418 -419 -420 -421 -422 -423 -424 -425 -426 -427 -428 -429 -430 -431 -432 -433 -434 -435 -436 -437 -438 -439 -440 -441 -442 -443 -444 -445 -446 -447 -448 -449 -450 -451 -452 -453 -454 -455 -456 -457 -458 -459 -460 -461 -462 -463 -464 -465 -466 -467 -468 -469 -470 -471 -472 -473 -474 -475 -476 -477 -478 -479 -480 -481 -482 -483 -484 -485 -486 -487 -488 -489 -490 -491 -492 -493 -494 -495 -496 -497 -498 -499 -500 -501 -502 -503 -504 -505 -506 -507 -508 -509 -510 -511 -512 -513 -514 -515 -516 -517 -518 -519 -520 -521 -522 -523 -524 -525 -526 -527 -528 -529 -530 -531 -532 -533 -534 -535 -536 -537 -538 -539 -540 -541 -542 -543 -544 -545 -546 -547 -548 -549 -550 -551 -552 -553 -554 -555 -556 -557 -558 -559 -560 -561 -562 -563 -564 -565 -566 -567 -568 -569 -570 -571 -572 -573 -574 -575 -576 -577 -578 -579 -580 -581 -582 -583 -584 -585 -586 -587 -588 -589 -590 -591 -592 -593 -594 -595 -596 -597 -598 -599 -600 -601 -602 -603 -604 -605 -606 -607 -608 -609 -610 -611 -612 -613 -614 -615 -616 -617 -618 -619 -620 -621 -622 -623 -624 -625 -626 -627 -628 -629 -630 -631 -632 -633 -634 -635 -636 -637 -638 -639 -640 -641 -642 -643 -644 -645 -646 -647 -648 -649 -650 -651 -652 -653 -654 -655 -656 -657 -658 -659 -660 -661 -662 -663 -664 -665 -666 -667 -668 -669 -670 -671 -672 -673 -674 -675 -676 -677 -678 -679 -680 -681 -682 -683 -684 -685 -686 -687 -688 -689 -690 -691 -692 -693 -694 -695 -696 -697 -698 -699 -700 -701 -702 -703 -704 -705 -706 -707 -708 -709 -710 -711 -712 -713 -714 -715 -716 -717 -718 -719 -720 -721 -722 -723 -724 -725 -726 -727 -728 -729 -730 -731 -732 -733 -734 -735 -736 -737 -738 -739 -740 -741 -742 -743 -744 -745 -746 -747 -748 -749 -750 -751 -752 -753 -754 -755 -756 -757 -758 -759 -760 -761 -762 -763 -764 -765 -766 -767 -768 -769 -770 -771 -772 -773 -774 -775 -776 -777 -778 -779 -780 -781 -782 -783 -784 -785 -786 -787 -788 -789 -790 -791 -792 -793 -794 -795 -796 -797 -798 -799 -800 -801 -802 -803 -804 -805 -806 -807 -808 -809 -810 -811 -812 -813 -814 -815 -816 -817 -818 -819 -820 -821 -822 -823 -824 -825 -826 -827 -828 -829 -830 -831 -832 -833 -834 -835 -836 -837 -838 -839 -840 -841 -842 -843 -844 -845 -846 -847 -848 -849 -850 -851 -852 -853 -854 -855 -856 -857 -858 -859 -860 -861 -862 -863 -864 -865 -866 -867 -868 -869 -870 -871 -872 -873 -874 -875 -876 -877 -878 -879 -880 -881 -882 -883 -884 -885 -886 -887 -888 -889 -890 -891 -892 -893 -894 -895 -896 -897 -898 -899 -900 -901 -902 -903 -904 -905 -906 -907 -908 -909 -910 -911 -912 -913 -914 -915 -916 -917 -918 -919 -920 -921 -922 -923 -924 -925 -926 -927 -928 -929 -930 -931 -932 -933 -934 -935 -936 -937 -938 -939 -940 -941 -942 -943 -944 -945 -946 -947 -948 -949 -950 -951 -952 -953 -954 -955 -956 -957 -958 -959 -960 -961 -962 -963 -964 -965 -966 -967 -968 -969 -970 -971 -972 -973 -974 -975 -976 -977 -978 -979 -980 -981 -982 -983 -984 -985 -986 -987 -988 -989 -990 -991 -992 -993 -994 -995 -996 -997 -998 -999 -1000 -1001 -1002 -1003 -1004 -1005 -1006 -1007 -1008 -1009 -1010 -1011 -1012 -1013 -1014 -1015 -1016 -1017 -1018 -1019 -1020 -1021 -1022 -1023 -1024 -1025 -1026 -1027 -1028 -1029 -1030 -1031 -1032 -1033 -1034 -1035 -1036 -1037 -1038 -1039 -1040 -1041 -1042 -1043 -1044 -1045 -1046 -1047 -1048 -1049 -1050 -1051 -1052 -1053 -1054 -1055 -1056 -1057 -1058 -1059 -1060 -1061 -1062 -1063 -1064 -1065 -1066 -1067 -1068 -1069 -1070 -1071 -1072 -1073 -1074 -1075 -1076 -1077 -1078 -1079 -1080 -1081 -1082 -1083 -1084 -1085 -1086 -1087 -1088 -1089 -1090 -1091 -1092 -1093 -1094 -1095 -1096 -1097 -1098 -1099 -1100 -1101 -1102 -1103 -1104 -1105 -1106 -1107 -1108 -1109 -1110 -1111 -1112 -1113 -1114 -1115 -1116 -1117 -1118 -1119 -1120 -1121 -1122 -1123 -1124 -1125 -1126 -1127 -1128 -1129 -1130 -1131 -1132 -1133 -1134 -1135 -1136 -1137 -1138 -1139 -1140 -1141 -1142 -1143 -1144 -1145 -1146 -1147 -1148 -1149 -1150 -1151 -1152 -1153 -1154 -1155 -1156 -1157 -1158 -1159 -1160 -1161 -1162 -1163 -1164 -1165 -1166 -1167 -1168 -1169 -1170 -1171 -1172 -1173 -1174 -1175 -1176 -1177 -1178 -1179 -1180 -1181 -1182 -1183 -1184 -1185 -1186 -1187 -1188 -1189 -1190 -1191 -1192 -1193 -1194 -1195 -1196 -1197 -1198 -1199 -1200 -1201 -1202 -1203 -1204 -1205 -1206 -1207 -1208 -1209 -1210 -1211 -1212 -1213 -1214 -1215 -1216 -1217 -1218 -1219 -1220 -1221 -1222 -1223 -1224 -1225 -1226 -1227 -1228 -1229 -1230 -1231 -1232 -1233 -1234 -1235 -1236 -1237 -1238 -1239 -1240 -1241 -1242 -1243 -1244 -1245 -1246 -1247 -1248 -1249 -1250 -1251 -1252 -1253 -1254 -1255 -1256 -1257 -1258 -1259 -1260 -1261 -1262 -1263 -1264 -1265 -1266 -1267 -1268 -1269 -1270 -1271 -1272 -1273 -1274 -1275 -1276 -1277 -1278 -1279 -1280 -1281 -1282 -1283 -1284 -1285 -1286 -1287 -1288 -1289 -1290 -1291 -1292 -1293 -1294 -1295 -1296 -1297 -1298 -1299 -1300 -1301 -1302 -1303 -1304 -1305 -1306 -1307 -1308 -1309 -1310 -1311 -1312 -1313 -1314 -1315 -1316 -1317 -1318 -1319 -1320 -1321 -1322 -1323 -1324 -1325 -1326 -1327 -1328 -1329 -1330 -1331 -1332 -1333 -1334 -1335 -1336 -1337 -1338 -1339 -1340 -1341 -1342 -1343 -1344 -1345 -1346 -1347 -1348 -1349 -1350 -1351 -1352 -1353 -1354 -1355 -1356 -1357 -1358 -1359 -1360 -1361 -1362 -1363 -1364 -1365 -1366 -1367 -1368 -1369 -1370 -1371 -1372 -1373 -1374 -1375 -1376 -1377 -1378 -1379 -1380 -1381 -1382 -1383 -1384 -1385 -1386 -1387 -1388 -1389 -1390 -1391 -1392 -1393 -1394 -1395 -1396 -1397 -1398 -1399 -1400 -1401 -1402 -1403 -1404 -1405 -1406 -1407 -1408 -1409 -1410 -1411 -1412 -1413 -1414 -1415 -1416 -1417 -1418 -1419 -1420 -1421 -1422 -1423 -1424 -1425 -1426 -1427 -1428 -1429 -1430 -1431 -1432 -1433 -1434 -1435 -1436 -1437 -1438 -1439 -1440 -1441 -1442 -1443 -1444 -1445 -1446 -1447 -1448 -1449 -1450 -1451 -1452 -1453 -1454 -1455 -1456 -1457 -1458 -1459 -1460 -1461 -1462 -1463 -1464 -1465 -1466 -1467 -1468 -1469 -1470 -1471 -1472 -1473 -1474 -1475 -1476 -1477 -1478 -1479 -1480 -1481 -1482 -1483 -1484 -1485 -1486 -1487 -1488 -1489 -1490 -1491 -1492 -1493 -1494 -1495 -1496 -1497 -1498 -1499 -1500 -1501 -1502 -1503 -1504 -1505 -1506 -1507 -1508 -1509 -1510 -1511 -1512 -1513 -1514 -1515 -1516 -1517 -1518 -1519 -1520 -1521 -1522 -1523 -1524 -1525 -1526 -1527 -1528 -1529 -1530 -1531 -1532 -1533 -1534 -1535 -1536 -1537 -1538 -1539 -1540 -1541 -1542 -1543 -1544 -1545 -1546 -1547 -1548 -1549 -1550 -1551 -1552 -1553 -1554 -1555 -1556 -1557 -1558 -1559 -1560 -1561 -1562 -1563 -1564 -1565 -1566 -1567 -1568 -1569 -1570 -1571 -1572 -1573 -1574 -1575 -1576 -1577 -1578 -1579 -1580 -1581 -1582 -1583 -1584 -1585 -1586 -1587 -1588 -1589 -1590 -1591 -1592 -1593 -1594 -1595 -1596 -1597 -1598 -1599 -1600 -1601 -1602 -1603 -1604 -1605 -1606 -1607 -1608 -1609 -1610 -1611 -1612 -1613 -1614 -1615 -1616 -1617 -1618 -1619 -1620 -1621 -1622 -1623 -1624 -1625 -1626 -1627 -1628 -1629 -1630 -1631 -1632 -1633 -1634 -1635 -1636 -1637 -1638 -1639 -1640 -1641 -1642 -1643 -1644 -1645 -1646 -1647 -1648 -1649 -1650 -1651 -1652 -1653 -1654 -1655 -1656 -1657 -1658 -1659 -1660 -1661 -1662 -1663 -1664 -1665 -1666 -1667 -1668 -1669 -1670 -1671 -1672 -1673 -1674 -1675 -1676 -1677 -1678 -1679 -1680 -1681 -1682 -1683 -1684 -1685 -1686 -1687 -1688 -1689 -1690 -1691 -1692 -1693 -1694 -1695 -1696 -1697 -1698 -1699 -1700 -1701 -1702 -1703 -1704 -1705 -1706 -1707 -1708 -1709 -1710 -1711 -1712 -1713 -1714 -1715 -1716 -1717 -1718 -1719 -1720 -1721 -1722 -1723 -1724 -1725 -1726 -1727 -1728 -1729 -1730 -1731 -1732 -1733 -1734 -1735 -1736 -1737 -1738 -1739 -1740 -1741 -1742 -1743 -1744 -1745 -1746 -1747 -1748 -1749 -1750 -1751 -1752 -1753 -1754 -1755 -1756 -1757 -1758 -1759 -1760 -1761 -1762 -1763 -1764 -1765 -1766 -1767 -1768 -1769 -1770 -1771 -1772 -1773 -1774 -1775 -1776 -1777 -1778 -1779 -1780 -1781 -1782 -1783 -1784 -1785 -1786 -1787 -1788 -1789 -1790 -1791 -1792 -1793 -1794 -1795 -1796 -1797 -1798 -1799 -1800 -1801 -1802 -1803 -1804 -1805 -1806 -1807 -1808 -1809 -1810 -1811 -1812 -1813 -1814 -1815 -1816 -1817 -1818 -1819 -1820 -1821 -1822 -1823 -1824 -1825 -1826 -1827 -1828 -1829 -1830 -1831 -1832 -1833 -1834 -1835 -1836 -1837 -1838 -1839 -1840 -1841 -1842 -1843 -1844 -1845 -1846 -1847 -1848 -1849 -1850 -1851 -1852 -1853 -1854 -1855 -1856 -1857 -1858 -1859 -1860 -1861 -1862 -1863 -1864 -1865 -1866 -1867 -1868 -1869 -1870 -1871 -1872 -1873 -1874 -1875 -1876 -1877 -1878 -1879 -1880 -1881 -1882 -1883 -1884 -1885 -1886 -1887 -1888 -1889 -1890 -1891 -1892 -1893 -1894 -1895 -1896 -1897 -1898 -1899 -1900 -1901 -1902 -1903 -1904 -1905 -1906 -1907 -1908 -1909 -1910 -1911 -1912 -1913 -1914 -1915 -1916 -1917 -1918 -1919 -1920 -1921 -1922 -1923 -1924 -1925 -1926 -1927 -1928 -1929 -1930 -1931 -1932 -1933 -1934 -1935 -1936 -1937 -1938 -1939 -1940 -1941 -1942 -1943 -1944 -1945 -1946 -1947 -1948 -1949 -1950 -1951 -1952 -1953 -1954 -1955 -1956 -1957 -1958 -1959 -1960 -1961 -1962 -1963 -1964 -1965 -1966 -1967 -1968 -1969 -1970 -1971 -1972 -1973 -1974 -1975 -1976 -1977 -1978 -1979 -1980 -1981 -1982 -1983 -1984 -1985 -1986 -1987 -1988 -1989 -1990 -1991 -1992 -1993 -1994 -1995 -1996 -1997 -1998 -1999 -2000 -2001 -2002 -2003 -2004 -2005 -2006 -2007 -2008 -2009 -2010 -2011 -2012 -2013 -2014 -2015 -2016 -2017 -2018 -2019 -2020 -2021 -2022 -2023 -2024 -2025 -2026 -2027 -2028 -2029 -2030 -2031 -2032 -2033 -2034 -2035 -2036 -2037 -2038 -2039 -2040 -2041 -2042 -2043 -2044 -2045 -2046 -2047 -2048 -2049 -2050 -2051 -2052 -2053 -2054 -2055 -2056 -2057 -2058 -2059 -2060 -2061 -2062 -2063 -2064 -2065 -2066 -2067 -2068 -2069 -2070 -2071 -2072 -2073 -2074 -2075 -2076 -2077 -2078 -2079 -2080 -2081 -2082 -2083 -2084 -2085 -2086 -2087 -2088 -2089 -2090 -2091 -2092 -2093 -2094 -2095 -2096 -2097 -2098 -2099 -2100 -2101 -2102 -2103 -2104 -2105 -2106 -2107 -2108 -2109 -2110 -2111 -2112 -2113 -2114 -2115 -2116 -2117 -2118 -2119 -2120 -2121 -2122 -2123 -2124 -2125 -2126 -2127 -2128 -2129 -2130 -2131 -2132 -2133 -2134 -2135 -2136 -2137 -2138 -2139 -2140 -2141 -2142 -2143 -2144 -2145 -2146 -2147 -2148 -2149 -2150 -2151 -2152 -2153 -2154 -2155 -2156 -2157 -2158 -2159 -2160 -2161 -2162 -2163 -2164 -2165 -2166 -2167 -2168 -2169 -2170 -2171 -2172 -2173 -2174 -2175 -2176 -2177 -2178 -2179 -2180 -2181 -2182 -2183 -2184 -2185 -2186 -2187 -2188 -2189 -2190 -2191 -2192 -2193 -2194 -2195 -2196 -2197 -2198 -2199 -2200 -2201 -2202 -2203 -2204 -2205 -2206 -2207 -2208 -2209 -2210 -2211 -2212 -2213 -2214 -2215 -2216 -2217 -2218 -2219 -2220 -2221 -2222 -2223 -2224 -2225 -2226 -2227 -2228 -2229 -2230 -2231 -2232 -2233 -2234 -2235 -2236 -2237 -2238 -2239 -2240 -2241 -2242 -2243 -2244 -2245 -2246 -2247 -2248 -2249 -2250 -2251 -2252 -2253 -2254 -2255 -2256 -2257 -2258 -2259 -2260 -2261 -2262 -2263 -2264 -2265 -2266 -2267 -2268 -2269 -2270 -2271 -2272 -2273 -2274 -2275 -2276 -2277 -2278 -2279 -2280 -2281 -2282 -2283 -2284 -2285 -2286 -2287 -2288 -2289 -2290 -2291 -2292 -2293 -2294 -2295 -2296 -2297 -2298 -2299 -2300 -2301 -2302 -2303 -2304 -2305 -2306 -2307 -2308 -2309 -2310 -2311 -2312 -2313 -2314 -2315 -2316 -2317 -2318 -2319 -2320 -2321 -2322 -2323 -2324 -2325 -2326 -2327 -2328 -2329 -2330 -2331 -2332 -2333 -2334 -2335 -2336 -2337 -2338 -2339 -2340 -2341 -2342 -2343 -2344 -2345 -2346 -2347 -2348 -2349 -2350 -2351 -2352 -2353 -2354 -2355 -2356 -2357 -2358 -2359 -2360 -2361 -2362 -2363 -2364 -2365 -2366 -2367 -2368 -2369 -2370 -2371 -2372 -2373 -2374 -2375 -2376 -2377 -2378 -2379 -2380 -2381 -2382 -2383 -2384 -2385 -2386 -2387 -2388 -2389 -2390 -2391 -2392 -2393 -2394 -2395 -2396 -2397 -2398 -2399 -2400 -2401 -2402 -2403 -2404 -2405 -2406 -2407 -2408 -2409 -2410 -2411 -2412 -2413 -2414 -2415 -2416 -2417 -2418 -2419 -2420 -2421 -2422 -2423 -2424 -2425 -2426 -2427 -2428 -2429 -2430 -2431 -2432 -2433 -2434 -2435 -2436 -2437 -2438 -2439 -2440 -2441 -2442 -2443 -2444 -2445 -2446 -2447 -2448 -2449 -2450 -2451 -2452 -2453 -2454 -2455 -2456 -2457 -2458 -2459 -2460 -2461 -2462 -2463 -2464 -2465 -2466 -2467 -2468 -2469 -2470 -2471 -2472 -2473 -2474 -2475 -2476 -2477 -2478 -2479 -2480 -2481 -2482 -2483 -2484 -2485 -2486 -2487 -2488 -2489 -2490 -2491 -2492 -2493 -2494 -2495 -2496 -2497 -2498 -2499 -2500 -2501 -2502 -2503 -2504 -2505 -2506 -2507 -2508 -2509 -2510 -2511 -2512 -2513 -2514 -2515 -2516 -2517 -2518 -2519 -2520 -2521 -2522 -2523 -2524 -2525 -2526 -2527 -2528 -2529 -2530 -2531 -2532 -2533 -2534 -2535 -2536 -2537 -2538 -2539 -2540 -2541 -2542 -2543 -2544 -2545 -2546 -2547 -2548 -2549 -2550 -2551 -2552 -2553 -2554 -2555 -2556 -2557 -2558 -2559 -2560 -2561 -2562 -2563 -2564 -2565 -2566 -2567 -2568 -2569 -2570 -2571 -2572 -2573 -2574 -2575 -2576 -2577 -2578 -2579 -2580 -2581 -2582 -2583 -2584 -2585 -2586 -2587 -2588 -2589 -2590 -2591 -2592 -2593 -2594 -2595 -2596 -2597 -2598 -2599 -2600 -2601 -2602 -2603 -2604 -2605 -2606 -2607 -2608 -2609 -2610 -2611 -2612 -2613 -2614 -2615 -2616 -2617 -2618 -2619 -2620 -2621 -2622 -2623 -2624 -2625 -2626 -2627 -2628 -2629 -2630 -2631 -2632 -2633 -2634 -2635 -2636 -2637 -2638 -2639 -2640 -2641 -2642 -2643 -2644 -2645 -2646 -2647 -2648 -2649 -2650 -2651 -2652 -2653 -2654 -2655 -2656 -2657 -2658 -2659 -2660 -2661 -2662 -2663 -2664 -2665 -2666 -2667 -2668 -2669 -2670 -2671 -2672 -2673 -2674 -2675 -2676 -2677 -2678 -2679 -2680 -2681 -2682 -2683 -2684 -2685 -2686 -2687 -2688 -2689 -2690 -2691 -2692 -2693 -2694 -2695 -2696 -2697 -2698 -2699 -2700 -2701 -2702 -2703 -2704 -2705 -2706 -2707 -2708 -2709 -2710 -2711 -2712 -2713 -2714 -2715 -2716 -2717 -2718 -2719 -2720 -2721 -2722 -2723 -2724 -2725 -2726 -2727 -2728 -2729 -2730 -2731 -2732 -2733 -2734 -2735 -2736 -2737 -2738 -2739 -2740 -2741 -2742 -2743 -2744 -2745 -2746 -2747 -2748 -2749 -2750 -2751 -2752 -2753 -2754 -2755 -2756 -2757 -2758 -2759 -2760 -2761 -2762 -2763 -2764 -2765 -2766 -2767 -2768 -2769 -2770 -2771 -2772 -2773 -2774 -2775 -2776 -2777 -2778 -2779 -2780 -2781 -2782 -2783 -2784 -2785 -2786 -2787 -2788 -2789 -2790 -2791 -2792 -2793 -2794 -2795 -2796 -2797 -2798 -2799 -2800 -2801 -2802 -2803 -2804 -2805 -2806 -2807 -2808 -2809 -2810 -2811 -2812 -2813 -2814 -2815 -2816 -2817 -2818 -2819 -2820 -2821 -2822 -2823 -2824 -2825 -2826 -2827 -2828 -2829 -2830 -2831 -2832 -2833 -2834 -2835 -2836 -2837 -2838 -2839 -2840 -2841 -2842 -2843 -2844 -2845 -2846 -2847 -2848 -2849 -2850 -2851 -2852 -2853 -2854 -2855 -2856 -2857 -2858 -2859 -2860 -2861 -2862 -2863 -2864 -2865 -2866 -2867 -2868 -2869 -2870 -2871 -2872 -2873 -2874 -2875 -2876 -2877 -2878 -2879 -2880 -2881 -2882 -2883 -2884 -2885 -2886 -2887 -2888 -2889 -2890 -2891 -2892 -2893 -2894 -2895 -2896 -2897 -2898 -2899 -2900 -2901 -2902 -2903 -2904 -2905 -2906 -2907 -2908 -2909 -2910 -2911 -2912 -2913 -2914 -2915 -2916 -2917 -2918 -2919 -2920 -2921 -2922 -2923 -2924 -2925 -2926 -2927 -2928 -2929 -2930 -2931 -2932 -2933 -2934 -2935 -2936 -2937 -2938 -2939 -2940 -2941 -2942 -2943 -2944 -2945 -2946 -2947 -2948 -2949 -2950 -2951 -2952 -2953 -2954 -2955 -2956 -2957 -2958 -2959 -2960 -2961 -2962 -2963 -2964 -2965 -2966 -2967 -2968 -2969 -2970 -2971 -2972 -2973 -2974 -2975 -2976 -2977 -2978 -2979 -2980 -2981 -2982 -2983 -2984 -2985 -2986 -2987 -2988 -2989 -2990 -2991 -2992 -2993 -2994 -2995 -2996 -2997 -2998 -2999 -3000 -3001 -3002 -3003 -3004 -3005 -3006 -3007 -3008 -3009 -3010 -3011 -3012 -3013 -3014 -3015 -3016 -3017 -3018 -3019 -3020 -3021 -3022 -3023 -3024 -3025 -3026 -3027 -3028 -3029 -3030 -3031 -3032 -3033 -3034 -3035 -3036 -3037 -3038 -3039 -3040 -3041 -3042  -  -1x -1x -1x -  -1x -1x -1x -1x -1x -1x -1x -1x -1x -1x -1x -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -1x -1x -1x -1x -1x -1x -1x -1x -1x -1x -1x -1x -1x -1x -  -1x -  -  -  -1x -2x -5x -8x -3x -3x -9x -2x -4x -3x -5x -2x -2x -8x -  -  -  -1x -1x -1x -1x -1x -1x -  -  -1x -1x -1x -1x -1x -1x -1x -1x -1x -2x -  -  -1x -  -  -  -  -  -1x -  -1x -  -1x -  -1x -  -  -1x -  -12x -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -1x -1x -  -  -  -  -  -  -  -230x -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -230x -230x -230x -230x -230x -230x -  -  -  -230x -6x -6x -1x -  -5x -  -  -  -  -  -  -  -  -4x -  -  -  -229x -169x -  -169x -  -169x -3x -1x -  -3x -  -  -169x -  -169x -169x -169x -169x -169x -2x -  -167x -  -  -169x -  -169x -  -  -  -  -  -  -169x -  -  -229x -60x -60x -  -  -  -  -  -  -  -13x -13x -  -  -  -13x -  -13x -  -5x -5x -25x -13x -  -  -  -13x -7x -  -  -  -  -5x -1x -1x -  -4x -4x -  -  -  -  -  -  -  -  -  -  -  -  -  -30x -  -  -30x -30x -14x -  -  -  -16x -  -  -  -  -  -  -16x -16x -  -16x -1x -1x -  -15x -  -  -15x -  -15x -15x -  -  -  -  -  -  -  -  -38x -  -38x -38x -56x -20x -  -  -18x -  -  -  -  -  -  -  -  -2x -  -2x -2x -4x -1x -  -  -1x -  -  -  -  -  -  -  -  -16x -  -16x -  -  -  -16x -  -  -  -  -  -  -  -1x -  -1x -  -1x -  -2x -  -  -  -  -  -  -  -  -42x -42x -  -  -  -  -  -  -  -  -  -  -  -  -  -42x -  -42x -  -42x -42x -  -42x -  -94x -  -  -42x -  -  -  -  -  -  -  -4x -  -4x -  -  -  -  -  -  -  -  -  -  -  -  -  -4x -4x -  -4x -  -4x -  -4x -8x -  -  -4x -4x -  -  -  -  -  -  -  -  -1x -  -1x -  -  -  -1x -1x -  -  -  -  -  -  -  -2x -  -2x -  -  -  -  -  -  -  -  -  -2x -  -2x -  -2x -2x -1x -1x -  -  -  -  -  -  -1x -1x -  -  -  -8x -  -8x -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -8x -8x -7x -  -7x -  -  -  -  -  -  -  -7x -  -  -7x -7x -7x -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -149x -149x -  -149x -149x -615x -2x -  -  -  -  -  -147x -147x -25x -25x -  -  -122x -122x -122x -  -  -63x -63x -63x -63x -  -63x -245x -245x -245x -  -245x -85x -  -  -85x -85x -  -160x -  -  -  -  -  -72x -72x -71x -71x -  -1x -  -  -  -  -  -  -  -  -  -  -  -  -25x -25x -  -25x -  -  -25x -25x -  -1x -1x -  -  -  -  -  -  -  -  -22x -22x -  -22x -  -22x -16x -  -  -  -  -  -  -  -  -4x -  -  -  -  -  -  -  -  -  -5x -5x -  -5x -7x -  -5x -5x -5x -  -  -  -  -  -  -  -  -  -5x -  -  -  -  -  -5x -5x -  -1x -1x -  -4x -  -4x -4x -4x -  -1x -  -  -3x -12x -  -12x -  -  -12x -12x -12x -12x -  -12x -6x -  -6x -  -  -12x -  -3x -  -  -  -  -  -  -  -  -510x -510x -  -  -510x -4x -  -  -506x -506x -387x -387x -281x -  -106x -106x -  -  -119x -119x -  -  -  -  -  -  -  -  -  -5x -5x -5x -  -5x -  -5x -  -  -  -  -  -5x -  -  -  -  -  -  -  -  -  -3x -3x -3x -  -3x -  -3x -  -  -  -  -  -  -  -  -  -  -  -  -  -3x -  -  -  -  -  -  -  -  -97x -1x -  -  -97x -97x -  -97x -  -  -97x -53x -  -53x -  -53x -1x -  -52x -  -  -  -  -  -  -  -75x -  -75x -75x -70x -70x -70x -  -  -  -  -  -5x -5x -  -  -  -  -  -  -  -  -  -3x -3x -  -3x -  -3x -  -  -  -  -3x -3x -  -1x -1x -  -  -2x -2x -1x -  -  -1x -  -  -  -  -  -  -  -  -3x -3x -  -3x -  -3x -  -  -  -  -3x -3x -  -1x -1x -  -  -2x -2x -1x -  -  -1x -  -  -  -  -  -  -  -  -2x -2x -2x -  -  -  -2x -2x -  -1x -1x -  -  -1x -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -3x -3x -  -  -  -  -  -  -  -1x -1x -  -  -  -  -  -  -  -  -  -  -  -  -18x -18x -  -18x -1x -  -  -17x -  -  -  -  -  -  -  -17x -  -  -  -  -  -  -17x -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -8x -  -8x -  -  -  -  -  -  -8x -  -  -  -  -  -  -8x -  -  -  -  -  -  -  -  -  -  -  -3x -3x -1x -  -  -3x -1x -  -  -3x -  -  -  -  -  -  -  -  -3x -  -3x -3x -3x -6x -  -  -3x -  -  -  -  -  -  -8x -  -  -  -  -8x -  -8x -  -8x -8x -8x -8x -8x -  -8x -7x -6x -5x -  -1x -  -  -5x -4x -  -1x -  -  -4x -3x -  -1x -  -  -1x -  -  -3x -2x -  -1x -  -  -2x -1x -  -1x -  -  -1x -  -  -1x -  -  -  -  -  -  -  -  -  -  -  -  -1x -  -  -  -4x -  -  -  -  -4x -  -4x -  -  -  -4x -1x -  -  -  -  -  -  -  -  -3x -  -  -1x -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -29x -  -29x -27x -27x -17x -  -27x -  -  -  -  -  -  -  -  -  -  -  -  -29x -29x -  -  -  -  -29x -29x -29x -25x -  -29x -2x -1x -  -1x -  -28x -2x -1x -  -1x -  -27x -25x -  -27x -  -27x -27x -  -  -  -  -  -  -  -  -  -  -  -  -  -  -27x -  -27x -26x -  -26x -  -17x -  -  -27x -  -  -  -  -  -  -  -  -24x -24x -14x -  -10x -  -  -  -  -  -  -  -  -  -4x -4x -  -  -  -  -4x -4x -  -4x -4x -4x -  -4x -1x -  -  -3x -2x -  -2x -4x -  -  -  -3x -  -  -  -  -  -  -  -  -  -5x -5x -  -  -  -  -5x -5x -  -5x -5x -5x -  -5x -1x -  -  -4x -3x -  -3x -1x -  -  -  -4x -  -  -  -  -  -  -  -  -  -  -18x -18x -  -  -  -  -18x -18x -18x -  -18x -1x -  -  -17x -14x -  -3x -  -  -  -  -  -  -  -  -  -  -23x -23x -  -  -  -23x -23x -23x -  -23x -8x -  -  -15x -1x -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -47x -47x -  -  -  -  -47x -47x -47x -46x -  -47x -4x -1x -  -3x -  -46x -2x -1x -  -1x -  -45x -44x -  -45x -  -45x -45x -  -  -  -  -  -  -  -  -  -  -  -  -  -  -45x -  -45x -44x -  -44x -43x -  -  -  -45x -  -  -  -  -  -  -  -  -  -72x -72x -  -  -  -  -72x -72x -  -72x -72x -  -72x -1x -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -71x -71x -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -71x -35x -  -36x -35x -  -36x -36x -1x -  -36x -1x -  -  -71x -  -  -  -  -  -  -  -  -  -4x -4x -  -  -  -  -4x -4x -  -4x -4x -  -4x -2x -  -2x -  -  -  -  -  -  -  -  -  -5x -5x -  -  -  -  -5x -5x -  -5x -5x -  -5x -3x -  -2x -  -  -  -  -  -  -  -  -  -36x -36x -  -  -  -  -36x -36x -  -36x -36x -  -36x -18x -  -18x -  -  -  -  -  -  -  -  -41x -41x -41x -35x -  -6x -  -  -  -  -  -  -  -  -  -  -  -23x -23x -23x -4x -3x -  -1x -  -  -22x -19x -  -  -22x -  -  -  -  -22x -22x -22x -  -22x -1x -  -  -21x -21x -18x -  -  -3x -  -  -  -  -  -  -  -  -  -  -  -  -  -51x -51x -  -51x -  -  -  -  -51x -51x -51x -51x -  -  -  -  -  -  -  -  -  -  -51x -1x -  -  -50x -32x -  -  -18x -3x -  -  -18x -  -  -  -  -  -  -  -  -5x -  -5x -  -  -  -5x -5x -5x -5x -  -5x -1x -  -  -4x -2x -  -2x -  -  -  -  -  -  -  -  -  -  -  -  -  -16x -  -16x -16x -  -  -  -  -  -16x -16x -  -16x -16x -  -16x -9x -  -  -6x -1x -  -  -5x -1x -  -  -4x -1x -  -  -3x -  -  -  -  -  -  -  -  -  -  -  -  -  -14x -  -14x -14x -  -  -  -  -  -14x -14x -  -14x -12x -  -12x -7x -  -  -5x -1x -  -  -4x -1x -  -  -3x -1x -  -  -2x -  -  -  -  -  -  -  -  -  -  -  -  -  -13x -  -13x -13x -  -  -  -  -  -13x -13x -  -13x -13x -  -13x -8x -  -  -5x -1x -  -  -4x -1x -  -  -3x -1x -  -  -2x -  -  -  -  -  -  -  -  -  -  -  -10x -  -10x -10x -  -  -  -  -  -10x -10x -  -10x -10x -  -10x -4x -  -  -  -  -  -  -  -  -  -  -  -  -  -6x -1x -  -  -5x -  -  -  -  -  -  -  -  -12x -12x -18x -18x -  -  -18x -2x -2x -1x -  -1x -1x -1x -  -  -16x -  -  -17x -17x -17x -  -  -  -  -17x -7x -3x -3x -2x -  -1x -  -  -  -7x -2x -2x -1x -  -1x -  -  -  -  -  -  -  -17x -6x -3x -3x -2x -  -1x -  -  -  -6x -2x -2x -1x -  -1x -  -  -  -  -  -  -  -17x -8x -8x -8x -4x -2x -1x -  -  -  -13x -10x -  -8x -8x -8x -8x -8x -5x -5x -  -2x -2x -  -  -6x -6x -  -1x -1x -  -  -  -8x -5x -5x -  -2x -2x -  -  -8x -3x -  -5x -5x -  -  -  -  -  -  -  -17x -8x -8x -10x -8x -  -8x -8x -8x -7x -7x -2x -2x -  -1x -1x -  -  -6x -6x -  -1x -1x -  -  -  -8x -4x -4x -  -1x -1x -  -  -8x -3x -  -5x -  -  -  -  -  -  -17x -6x -6x -6x -6x -4x -4x -3x -  -1x -1x -1x -  -1x -  -  -  -  -  -  -  -17x -6x -6x -6x -6x -3x -3x -2x -  -1x -1x -1x -  -1x -  -  -  -  -  -  -  -17x -5x -5x -5x -5x -3x -3x -1x -  -2x -2x -2x -  -2x -  -  -  -  -  -  -  -17x -5x -5x -5x -5x -3x -3x -1x -  -2x -2x -2x -  -2x -  -  -  -  -  -  -  -17x -6x -6x -6x -6x -3x -3x -2x -  -1x -1x -1x -  -1x -  -  -  -  -  -  -  -17x -6x -6x -6x -6x -4x -4x -3x -  -1x -1x -1x -  -  -1x -  -  -  -  -  -  -  -17x -5x -5x -5x -5x -5x -3x -  -2x -2x -2x -  -2x -  -  -  -  -  -  -17x -6x -6x -6x -6x -3x -3x -2x -  -1x -1x -1x -  -1x -  -  -  -  -  -  -  -17x -6x -6x -6x -6x -3x -3x -2x -  -1x -1x -1x -  -1x -  -  -  -  -  -  -  -17x -5x -5x -5x -5x -3x -3x -1x -  -2x -2x -2x -  -  -2x -  -  -  -  -  -  -  -17x -6x -6x -6x -6x -2x -2x -1x -  -1x -1x -1x -  -  -1x -  -  -  -  -17x -1x -  -17x -  -12x -  -  -  -  -  -  -  -  -  -  -  -3x -3x -  -3x -  -  -  -  -3x -  -  -3x -  -3x -  -3x -  -3x -  -3x -2x -  -  -3x -  -  -  -  -  -  -  -  -  -  -  -  -  -  -4x -  -4x -  -  -  -  -4x -  -4x -  -  -  -  -  -  -  -11x -  -  -  -11x -  -11x -  -  -11x -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -1x -  -  -  -1x -  -1x -  -  -  -  -  -  -  -  -  -  -3x -  -  -  -  -3x -  -  -3x -1x -  -  -2x -  -2x -  -2x -1x -  -1x -  -  -  -1x -1x -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -533x -  -533x -1x -  -  -532x -1x -  -  -531x -  -531x -1x -  -530x -  -  -530x -  -  -530x -2x -  -  -  -528x -196x -  -  -  -  -  -  -528x -528x -1275x -1x -  -  -1274x -1x -  -1273x -  -  -1273x -352x -  -  -1273x -2194x -1x -  -2193x -1225x -1x -  -1224x -  -1224x -1224x -  -  -  -  -  -524x -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -1413x -381x -  -  -  -1413x -109x -  -  -  -  -  -  -  -  -  -  -  -  -8x -8x -8x -8x -  -8x -5x -  -3x -  -8x -8x -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -8x -  -  -  -8x -  -  -  -697x -4x -  -  -697x -697x -7x -  -  -697x -  -  -  -109x -  -  -  -207x -207x -  -207x -  -  -207x -207x -  -113x -113x -  -  -  -  -581x -581x -  -581x -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -581x -581x -  -123x -123x -  -  -458x -458x -  -458x -1038x -  -  -  -  -  -  -  -1038x -182x -  -856x -  -  -1038x -181x -  -  -  -458x -1x -1x -  -457x -  -  -  -  -397x -397x -396x -396x -334x -  -396x -  -1x -  -  -  -408x -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -374x -  -  -  -53x -53x -  -53x -  -  -  -  -53x -53x -53x -  -  -  -53x -  -  - 
/* eslint-disable @typescript-eslint/no-unsafe-assignment, @typescript-eslint/no-unsafe-member-access */
- 
-import { config } from "dotenv";
-config();
-import Joi from "joi";
- 
-import UploadFilesCommand, { UploadFilesCommandOptions, SourceTargetFileNames } from "./command/uploadFilesCommand";
-import UploadFolderCommand, { UploadFolderCommandOptions } from "./command/uploadFolderCommand";
-import GetFilesRecursivelyCommand, { GetFilesRecursivelyCommandOptions } from "./command/getFilesRecursivelyCommand";
-import DownloadFolderCommand, { DownloadFolderCommandOptions } from "./command/downloadFolderCommand";
-import { CommandStatus, CommandResultMetaData } from "./command/command";
-import parser from "fast-xml-parser";
-import { Headers, RequestInit, Response } from "node-fetch";
-import path, { basename } from "path";
-import Environment from "./environment";
-import EnvironmentVcapServices from "./environmentVcapServices";
-import ClientError, {
-  CommandAlreadyExecutedError,
-  QueryLimitError,
-  QueryOffsetError,
-  InsufficientPrivilegesError,
-  InvalidServiceResponseFormatError,
-  OperationFailedError,
-  UserGroupAlreadyExistsError,
-  UserGroupDeletionFailedError,
-  UserResendWelcomeEmailError,
-  UserGroupDoesNotExistError,
-  UserNotFoundError,
-  UserAlreadyExistsError,
-  UserCreateError,
-  UserUpdateError,
-} from "./error";
-import FakeServer from "./fakeServer";
-import File from "./file";
-import FileSystemElement from "./fileSystemElement";
-import FileSystemFolder, { IFileNameFormats } from "./fileSystemFolder";
-import Folder, { FolderGetFilesOptions } from "./folder";
-import { HttpClient, IHttpClientOptions, IProxy, IRequestContext } from "./httpClient";
-import RequestResponseLog from "./requestResponseLog";
-import RequestResponseLogEntry from "./requestResponseLogEntry";
-import Server, { IServerOptions } from "./server";
-import Share, { ICreateShare, SharePermission, ShareItemType } from "./share";
-import Tag from "./tag";
-import UserGroup from "./userGroup";
-import User, { IUserOptions, IUserOptionsQuota, IUserQuotaUserFriendly, UserProperty } from "./user";
-import Logger from "./logger";
-import { isNumber } from "util";
-const log: Logger = new Logger();
- 
-export {
-  FolderGetFilesOptions,
-  CommandAlreadyExecutedError,
-  InvalidServiceResponseFormatError,
-  InsufficientPrivilegesError,
-  OperationFailedError,
-  QueryLimitError,
-  QueryOffsetError,
-  UserNotFoundError,
-  UserAlreadyExistsError,
-  UserCreateError,
-  UserResendWelcomeEmailError,
-  UserUpdateError,
-  UserGroupAlreadyExistsError,
-  UserGroupDeletionFailedError,
-  UserGroupDoesNotExistError,
-};
- 
-export {
-  Client,
-  ClientError,
-  Environment,
-  Folder,
-  File,
-  FileSystemElement,
-  ICreateShare,
-  IServerOptions,
-  Tag,
-  FakeServer,
-  Server,
-  Share,
-  SharePermission,
-  RequestResponseLog,
-  RequestResponseLogEntry,
-  User,
-  UserGroup,
-  UserProperty,
-  IUserOptionsQuota,
-  IUserQuotaUserFriendly,
-  ShareItemType,
-};
- 
-// command object for upload
-export {
-  CommandResultMetaData,
-  DownloadFolderCommand,
-  DownloadFolderCommandOptions,
-  GetFilesRecursivelyCommand,
-  GetFilesRecursivelyCommandOptions,
-  UploadFilesCommand,
-  UploadFilesCommandOptions,
-  UploadFolderCommand,
-  UploadFolderCommandOptions,
-  SourceTargetFileNames,
-  FileSystemFolder,
-  IFileNameFormats,
-  CommandStatus,
-};
- 
-interface IStat {
-  type: string;
-  filename: string;
-  basename: string;
-  lastmod: string;
-  size?: number;
-  mime?: string;
-  fileid?: number;
-}
- 
-export interface IUpsertUserOptions {
-  id: string;
-  enabled?: boolean;
-  subadminGroups?: string[];
-  memberGroups?: string[];
-  quota?: string;
-  email?: string;
-  displayName?: string;
-  password?: string;
-  phone?: string;
-  address?: string;
-  website?: string;
-  twitter?: string;
-  language?: string;
-  locale?: string;
-  superAdmin?: boolean;
-  resendWelcomeEmail?: boolean;
-}
- 
-export interface IUserPropertyChange {
-  property: string;
-  previousValue: string;
-  newValue: string;
-  error?: string;
-}
- 
-export interface IUpsertUserReport {
-  id: string;
-  message: string;
-  changes: IUserPropertyChange[];
-}
- 
-export interface ISysInfoNextcloudClient {
-  version: string;
-}
- 
-// @todo refactoring of type
-export interface ISysInfoNextcloud {
-  system: any;
-  storage: any;
-  shares: any;
-}
- 
-export interface ISysBasicData {
-  serverTimeString: string;
-  uptimeString: string;
-  timeServersString: string;
-}
- 
-// @todo refactoring of type
-export interface ISystemInfo {
-  nextcloud: ISysInfoNextcloud;
-  // @todo change object to something strongly typed
-  server: any;
-  // @todo change object to something strongly typed
-  activeUsers: any;
-  nextcloudClient: ISysInfoNextcloudClient;
-}
- 
-export interface IQuota {
-  used: number;
-  available: number | string;
-}
- 
-/**
- * The nextcloud client is the root object to access the remote api of the nextcloud server.<br>
- */
-export default class Client {
-  public static webDavUrlPath: string = "/remote.php/webdav";
- 
-  private nextcloudOrigin: string;
-  private nextcloudAuthHeader: string;
-  private nextcloudRequestToken: string;
-  private webDAVUrl: string;
-  private proxy?: IProxy;
-  private fakeServer?: FakeServer;
-  private logRequestResponse: boolean = false;
-  private httpClient?: HttpClient;
-  private userId: string;
- 
-  /**
-   * Creates a new instance of a nextcloud client.<br/>
-   * Use the server to provide server connectivity information to the client.<br/>
-   * (The FakeServer is only used for testing and code coverage)<br/><br/>
-   * If the server is not provided the client tries to find the connectivity information
-   * in the environment.<br/>
-   * If a <b>VCAP_SERVICES</b> environment variable is available, the client tries to find
-   * a service with the name <b>"nextcloud"</b> in the user-provides-services section.<br/>
-   * If no VCAP_SERVICES are available, the client uses the following variables
-   * from the envirnonment for the connectivity:<br/>
-   * <ul>
-   * <li>NEXTCLOUD_URL - the url of the nextcloud server</li>
-   * <li>NEXTCLOUD_USERNAME - the user name</li>
-   * <li>NEXTCLOUD_PASSWORD - the application password</li>
-   * </ul>
-   * @param server optional server information to connection to a nextcloud server
-   * @constructor
-   */
-  public constructor(server?: Server | FakeServer) {
-    log.debug("constructor");
-    this.nextcloudOrigin = "";
-    this.nextcloudAuthHeader = "";
-    this.nextcloudRequestToken = "";
-    this.webDAVUrl = "";
-    this.userId = "";
- 
-    // if no server is provided, try to get a server from VCAP_S environment "nextcloud" instance
-    // If no VCAP_S environment exists try from environment
-    if (!server) {
-      try {
-        const env: EnvironmentVcapServices = new EnvironmentVcapServices("nextcloud");
-        server = env.getServer();
-      } catch (e) {
-        const serverOptions: IServerOptions = {
-          url: Environment.getNextcloudUrl(),
-          basicAuth: {
-            username: Environment.getUserName(),
-            password: Environment.getPassword(),
-          },
-          logRequestResponse: Environment.getRecordingActiveIndicator(),
-        };
- 
-        server = new Server(serverOptions);
-      }
-    }
- 
-    if (server instanceof Server) {
-      this.proxy = server.proxy;
- 
-      log.debug("constructor: url ", server.url);
- 
-      if (server.url.indexOf(Client.webDavUrlPath) === -1) {
-        if (server.url.slice(-1) === "/") {
-          server.url = server.url.slice(0, -1);
-        }
-        server.url = server.url + Client.webDavUrlPath;
-      }
- 
-      this.nextcloudOrigin = server.url.substr(0, server.url.indexOf(Client.webDavUrlPath));
- 
-      log.debug("constructor: nextcloud url ", this.nextcloudOrigin);
-      this.userId = server.basicAuth.username;
-      this.nextcloudAuthHeader = "Basic " + Buffer.from(server.basicAuth.username + ":" + server.basicAuth.password).toString("base64");
-      this.nextcloudRequestToken = "";
-      if (server.url.slice(-1) === "/") {
-        this.webDAVUrl = server.url.slice(0, -1);
-      } else {
-        this.webDAVUrl = server.url;
-      }
- 
-      this.logRequestResponse = server.logRequestResponse;
- 
-      const options: IHttpClientOptions = {
-        authorizationHeader: this.nextcloudAuthHeader,
-        logRequestResponse: this.logRequestResponse,
-        origin: this.nextcloudOrigin,
-        proxy: this.proxy,
-      };
- 
-      this.httpClient = new HttpClient(options);
-    }
- 
-    if (server instanceof FakeServer) {
-      this.fakeServer = server;
-      this.webDAVUrl = "https://fake.server" + Client.webDavUrlPath;
-    }
-  }
- 
-  /**
-   * returns the used and free quota of the nextcloud account
-   */
-  public async getQuota(): Promise<IQuota> {
-    log.debug("getQuota");
-    const requestInit: RequestInit = {
-      method: "PROPFIND",
-    };
- 
-    const response: Response = await this.getHttpResponse(this.webDAVUrl + "/", requestInit, [207], { description: "Client get quota" });
- 
-    const properties: any[] = await this.getPropertiesFromWebDAVMultistatusResponse(response, Client.webDavUrlPath + "/");
- 
-    let quota: IQuota | null = null;
-    for (const prop of properties) {
-      if (prop["quota-available-bytes"]) {
-        quota = {
-          available: "unlimited",
-          used: prop["quota-used-bytes"],
-        };
-        if (prop["quota-available-bytes"] > 0) {
-          quota.available = prop["quota-available-bytes"];
-        }
-      }
-    }
- 
-    if (!quota) {
-      log.debug("Error, quota not available: ", JSON.stringify(properties, null, 4));
-      throw new ClientError(`Error, quota not available`, "ERR_QUOTA_NOT_AVAILABLE");
-    }
-    log.debug("getQuota =", quota);
-    return quota;
-  }
- 
-  // ***************************************************************************************
-  // tags
-  // ***************************************************************************************
- 
-  /**
-   * creates a new tag, if not already existing
-   * this function will fail with http 403 if the user does not have admin privileges
-   * @param tagName the name of the tag
-   * @returns tagId
-   */
-  public async createTag(tagName: string): Promise<Tag> {
-    log.debug("createTag");
-    let tag: Tag | null;
-    // is the tag already existing?
-    tag = await this.getTagByName(tagName);
-    if (tag) {
-      return tag;
-    }
-    // tag does not exist, create tag
- 
-    const requestInit: RequestInit = {
-      body: `{ "name": "${tagName}", "userVisible": true, "userAssignable": true, "canAssign": true }`,
-      // eslint-disable-next-line @typescript-eslint/naming-convention
-      headers: new Headers({ "Content-Type": "application/json" }),
-      method: "POST",
-    };
- 
-    const response: Response = await this.getHttpResponse(this.nextcloudOrigin + "/remote.php/dav/systemtags/", requestInit, [201], { description: "Tag create" });
-    const tagString: string | null = response.headers.get("Content-Location");
- 
-    if (tagString === "" || tagString === null) {
-      log.error(`createTag 'tagName' ${tagName}`);
-      throw new ClientError(`Error, tag with name '${tagName}' could not be created`, "ERR_TAG_CREATE_FAILED");
-    }
-    log.debug(`createTag new tagId ${tagString} tagName ${tagName}`);
- 
-    // the number id of the tag is the last element in the id (path)
-    const tagId: number = this.getTagIdFromHref(tagString);
- 
-    tag = new Tag(this, tagId, tagName, true, true, true);
-    return tag;
-  }
- 
-  /**
-   * returns a tag identified by the name or null if not found
-   * @param tagName the name of the tag
-   * @returns tag or null
-   */
-  public async getTagByName(tagName: string): Promise<Tag | null> {
-    log.debug("getTag");
- 
-    const tags: Tag[] = await this.getTags();
-    for (const tag of tags) {
-      if (tag.name === tagName) {
-        return tag;
-      }
-    }
-    return null;
-  }
- 
-  /**
-   * returns a tag identified by the id or null if not found
-   * @param tagId the id of the tag
-   * @returns tag or null
-   */
-  public async getTagById(tagId: number): Promise<Tag | null> {
-    log.debug("getTagById");
- 
-    const tags: Tag[] = await this.getTags();
-    for (const tag of tags) {
-      if (tag.id === tagId) {
-        return tag;
-      }
-    }
-    return null;
-  }
- 
-  /**
-   * deletes the tag by id
-   * this function will fail with http 403 if the user does not have admin privileges
-   * @param tagId the id of the tag like "/remote.php/dav/systemtags/234"
-   */
-  public async deleteTag(tagId: number): Promise<void> {
-    log.debug("deleteTag tagId: ", tagId);
- 
-    const requestInit: RequestInit = {
-      method: "DELETE",
-    };
- 
-    const response: Response = await this.getHttpResponse(`${this.nextcloudOrigin}/remote.php/dav/systemtags/${tagId}`, requestInit, [204, 404], { description: "Tag delete" });
-  }
- 
-  /**
-   * deletes all visible assignable tags
-   * @throws Error
-   */
-  public async deleteAllTags(): Promise<void> {
-    log.debug("deleteAllTags");
- 
-    const tags: Tag[] = await this.getTags();
- 
-    for (const tag of tags) {
-      // log.debug("deleteAllTags tag: ", tag);
-      await tag.delete();
-    }
-  }
- 
-  /**
-   * returns a list of tags
-   * @returns array of tags
-   */
-  public async getTags(): Promise<Tag[]> {
-    log.debug("getTags PROPFIND " + this.nextcloudOrigin + "/remote.php/dav/systemtags/");
-    const requestInit: RequestInit = {
-      body: `<?xml version="1.0"?>
-            <d:propfind  xmlns:d="DAV:" xmlns:oc="http://owncloud.org/ns">
-              <d:prop>
-                <oc:id />
-                <oc:display-name />
-                <oc:user-visible />
-                <oc:user-assignable />
-                <oc:can-assign />
-              </d:prop>
-            </d:propfind>`,
-      method: "PROPFIND",
-    };
- 
-    const relUrl = `/remote.php/dav/systemtags/`;
- 
-    const response: Response = await this.getHttpResponse(this.nextcloudOrigin + relUrl, requestInit, [207], { description: "Tags get" });
- 
-    const properties: any[] = await this.getPropertiesFromWebDAVMultistatusResponse(response, relUrl + "/*");
-    const tags: Tag[] = [];
- 
-    for (const prop of properties) {
-      // eslint-disable-next-line no-underscore-dangle
-      tags.push(new Tag(this, this.getTagIdFromHref(prop._href), prop["display-name"], prop["user-visible"], prop["user-assignable"], prop["can-assign"]));
-    }
- 
-    return tags;
-  }
- 
-  /**
-   * returns the list of tag names and the tag ids
-   * @param fileId the id of the file
-   */
-  public async getTagsOfFile(fileId: number): Promise<Map<string, number>> {
-    log.debug("getTagsOfFile");
- 
-    const requestInit: RequestInit = {
-      body: `<?xml version="1.0"?>
-            <d:propfind  xmlns:d="DAV:" xmlns:oc="http://owncloud.org/ns">
-              <d:prop>
-                <oc:id />
-                <oc:display-name />
-                <oc:user-visible />
-                <oc:user-assignable />
-                <oc:can-assign />
-              </d:prop>
-            </d:propfind>`,
-      method: "PROPFIND",
-    };
- 
-    const relUrl = `/remote.php/dav/systemtags-relations/files/${fileId}`;
-    const response: Response = await this.getHttpResponse(`${this.nextcloudOrigin}${relUrl}`, requestInit, [207], { description: "File get tags" });
- 
-    const properties: any[] = await this.getPropertiesFromWebDAVMultistatusResponse(response, relUrl + "/*");
-    // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
-    const tagMap: Map<string, number> = new Map();
- 
-    for (const prop of properties) {
-      tagMap.set(prop["display-name"], prop.id);
-    }
- 
-    log.debug("tags of file ", tagMap);
-    return tagMap;
-  }
- 
-  /**
-   * removes the tag from the file
-   * @param fileId the file id
-   * @param tagId the tag id
-   */
-  public async removeTagOfFile(fileId: number, tagId: number): Promise<void> {
-    log.debug(`removeTagOfFile tagId: ${tagId} fileId:${fileId}`);
- 
-    const requestInit: RequestInit = {
-      method: "DELETE",
-    };
- 
-    await this.getHttpResponse(`${this.nextcloudOrigin}/remote.php/dav/systemtags-relations/files/${fileId}/${tagId}`, requestInit, [204, 404], { description: "File remove tag" });
-    return;
-  }
- 
-  /**
-   * returns the id of the file or -1 of not found
-   * @returns id of the file or -1 if not found
-   */
-  public async getFileId(fileUrl: string): Promise<number> {
-    log.debug("getFileId");
- 
-    const requestInit: RequestInit = {
-      body: `
-            <d:propfind  xmlns:d="DAV:" xmlns:oc="http://owncloud.org/ns" xmlns:nc="http://nextcloud.org/ns">
-              <d:prop>
-                  <oc:fileid />
-              </d:prop>
-            </d:propfind>`,
-      method: "PROPFIND",
-    };
- 
-    const response: Response = await this.getHttpResponse(fileUrl, requestInit, [207], { description: "File get id" });
- 
-    const properties: any[] = await this.getPropertiesFromWebDAVMultistatusResponse(response, "");
- 
-    for (const prop of properties) {
-      if (prop.fileid !== undefined) {
-        Eif (typeof prop.fileid === "number") {
-          return prop.fileid as number;
-        } else {
-          return -1;
-        }
-      }
-    }
- 
-    log.debug("getFileId no file id found for " + fileUrl);
-    return -1;
-  }
- 
-  public async getFolderContents(folderName: string): Promise<any[]> {
-    log.debug("getFolderContents");
- 
-    const requestInit: RequestInit = {
-      body: `<?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:getetag />
-                <d:getcontenttype />
-                <d:resourcetype />
-                <oc:fileid />
-                <oc:permissions />
-                <oc:size />
-                <d:getcontentlength />
-                <nc:has-preview />
-                <nc:mount-type />
-                <nc:is-encrypted />
-                <ocs:share-permissions />
-                <oc:tags />
-                <oc:favorite />
-                <oc:comments-unread />
-                <oc:owner-id />
-                <oc:owner-display-name />
-                <oc:share-types />
-              </d:prop>
-            </d:propfind>`,
-      method: "PROPFIND",
-    };
-    const url = `${this.webDAVUrl}${folderName}`;
-    const response: Response = await this.getHttpResponse(url, requestInit, [207], { description: "Folder get contents" });
-    const folderContents: any[] = [];
- 
-    const schema: Joi.ObjectSchema = Joi.object({
-      _href: Joi.string().required(),
-      getlastmodified: Joi.string().required(),
-      fileid: Joi.number().integer().required(),
-      getcontenttype: Joi.string(),
-      getcontentlength: Joi.number().integer(),
-    });
- 
-    const properties: any[] = await this.getPropertiesFromWebDAVMultistatusResponse(response, "");
- 
-    // validate the properties
-    const { error, value } = schema.validate(properties);
-    Eif (error) {
-      throw new ClientError(`Error get folder contents - folder name "${folderName}" error ${error.message};`, "INVALID");
-    }
- 
-    for (const prop of properties) {
-      // eslint-disable-next-line @typescript-eslint/no-unsafe-call, no-underscore-dangle, @typescript-eslint/restrict-plus-operands
-      let fileName = decodeURI(prop._href.substr(prop._href.indexOf(Client.webDavUrlPath) + 18));
-      if (fileName.endsWith("/")) {
-        fileName = fileName.slice(0, -1);
-      }
-      // eslint-disable-next-line no-underscore-dangle
-      if ((url + "/").endsWith(decodeURI(prop._href))) {
-        continue;
-      }
-      const folderContentsEntry: any = {};
-      folderContentsEntry.lastmod = prop.getlastmodified;
-      folderContentsEntry.fileid = prop.fileid;
-      folderContentsEntry.basename = fileName.split("/").reverse()[0];
-      folderContentsEntry.filename = fileName;
-      if (prop.getcontenttype) {
-        folderContentsEntry.mime = prop.getcontenttype;
-        folderContentsEntry.size = prop.getcontentlength;
-        folderContentsEntry.type = "file";
-      } else {
-        folderContentsEntry.type = "directory";
-      }
-      // if (folderContentsEntry.basename !== "") {
-      folderContents.push(folderContentsEntry);
-      // }
-    }
- 
-    // log.debug("folderContentsEntry ", JSON.stringify(folderContents, null, 4));
-    // eslint-disable-next-line @typescript-eslint/no-unsafe-return
-    return folderContents;
-  }
- 
-  /**
-   * creates a folder and all parent folders in the path if they do not exist
-   * @param folderName name of the folder /folder/subfolder/subfolder
-   * @returns a folder object
-   */
-  public async createFolder(folderName: string): Promise<Folder> {
-    folderName = this.sanitizeFolderName(folderName);
-    log.debug("createFolder: folderName=", folderName);
- 
-    const parts1: string[] = folderName.split("/");
-    for (const p of parts1) {
-      if (p === "." || p === "..") {
-        throw new ClientError(`Error creating folder, folder name "${folderName}" invalid`, "ERR_CREATE_FOLDER_INVALID_FOLDER_NAME");
-      }
-    }
- 
-    let folder: Folder | null;
- 
-    folder = await this.getFolder(folderName);
-    if (folder) {
-      log.debug("createFolder: folder already available ", folder.name);
-      return folder;
-    } else {
-      // try to do a simple create with the complete path
-      try {
-        log.debug("createFolder: folder = ", folderName);
-        await this.createFolderInternal(folderName);
-      } catch (e) {
-        // create all folders in the path
-        const parts: string[] = folderName.split("/");
-        parts.shift();
-        let folderPath: string = "";
-        log.debug("createFolder: parts = ", parts);
- 
-        for (const part of parts) {
-          log.debug("createFolder: part = ", part);
-          folderPath += "/" + part;
-          folder = await this.getFolder(folderPath);
- 
-          if (folder === null) {
-            log.debug("createFolder: folder not available");
-            // folder not  available
- 
-            log.debug("createFolder: folder = ", folderPath);
-            await this.createFolderInternal(folderPath);
-          } else {
-            log.debug("createFolder: folder already available ", folderPath);
-          }
-        }
-      }
-    }
- 
-    folder = await this.getFolder(folderName);
-    if (folder) {
-      log.debug("createFolder: new folder ", folder.name);
-      return folder;
-    } else {
-      throw new ClientError(
-        `Error creating folder, folder name "${folderName}"
-            `,
-        "ERR_CREATE_FOLDER_FAILED"
-      );
-    }
-  }
- 
-  /**
-   * deletes a file
-   * @param fileName name of folder "/f1/f2/f3/x.txt"
-   */
-  public async deleteFile(fileName: string): Promise<void> {
-    const url: string = this.webDAVUrl + fileName;
-    log.debug("deleteFile ", url);
- 
-    const requestInit: RequestInit = {
-      method: "DELETE",
-    };
-    try {
-      await this.getHttpResponse(url, requestInit, [204], { description: "File delete" });
-    } catch (err) {
-      log.debug("Error in deleteFile ", err.message, requestInit.method, url);
-      throw err;
-    }
-  }
- 
-  /**
-   * deletes a folder
-   * @param folderName name of folder "/f1/f2/f3"
-   */
-  public async deleteFolder(folderName: string): Promise<void> {
-    folderName = this.sanitizeFolderName(folderName);
-    log.debug("deleteFolder:");
- 
-    const folder: Folder | null = await this.getFolder(folderName);
- 
-    if (folder) {
-      await this.deleteFile(folderName);
-    }
-  }
- 
-  /**
-   * get the root folder object
-   * @returns {Promise<Folder>} the root folder
-   */
-  public getRootFolder(): Folder {
-    return new Folder(this, "/", "", "");
-  }
- 
-  /**
-   * returns an array of file system objects that have all given tags assigned (AND)
-   * @param {Tag[]} tags array of tags
-   * @async
-   * @returns {Promise<FileSystemElement[]>} returns an array of file system objects
-   */
-  public async getFileSystemElementByTags(tags: Tag[]): Promise<FileSystemElement[]> {
-    log.debug("getFileSystemElementByTags ", tags.join(", "));
-    let filterRule: string = "";
- 
-    for (const tag of tags) {
-      filterRule += `<oc:systemtag>${tag.id}</oc:systemtag>`;
-    }
-    const urlSuffix = `/remote.php/dav/files/`;
-    const url = `${this.nextcloudOrigin}${urlSuffix}${this.userId}`;
-    const body = `<?xml version="1.0"?>
-        <oc:filter-files  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:getcontenttype />
-              <oc:fileid />
-           </d:prop>
-           <oc:filter-rules>
-                ${filterRule}
-           </oc:filter-rules>
-        </oc:filter-files>`;
-    const requestInit: RequestInit = {
-      body,
-      // headers: new Headers({ Depth: "0" }),
-      method: "REPORT",
-    };
-    let response: Response;
-    try {
-      response = await this.getHttpResponse(url, requestInit, [207], { description: "Get FileSystemElements by tags" });
-    } catch (err) {
-      log.debug("Error in stat ", err.message, requestInit.method, url);
-      throw err;
-    }
-    const result: FileSystemElement[] = [];
- 
-    let properties: any[] = [];
-    try {
-      properties = await this.getPropertiesFromWebDAVMultistatusResponse(response, "");
-    } catch (e) {
-      return result;
-    }
- 
-    for (const prop of properties) {
-      let fse: FileSystemElement | null = null;
-      // eslint-disable-next-line no-underscore-dangle
-      let name: string = prop._href;
- 
-      // remove the first two elements from the path
-      name = name.replace(urlSuffix, "");
-      const a: string[] = name.split("/");
-      a.shift();
-      name = "/" + a.join("/");
-      // console.log(name);
-      if (prop.getcontenttype) {
-        fse = await this.getFile(name);
-      } else {
-        fse = await this.getFolder(name);
-      }
- 
-      result.push(fse!);
-    }
-    return result;
-  }
- 
-  /**
-   * get a folder object from a path string
-   * @param {string} folderName Name of the folder like "/company/branches/germany"
-   * @returns {Promise<Folder | null>} null if the folder does not exist or an folder object
-   */
-  public async getFolder(folderName: string): Promise<Folder | null> {
-    folderName = this.sanitizeFolderName(folderName);
-    log.debug("getFolder", folderName);
- 
-    // return root folder
-    if (folderName === "/" || folderName === "") {
-      return this.getRootFolder();
-    }
- 
-    try {
-      const stat: IStat = await this.stat(folderName);
-      log.debug(": SUCCESS!!");
-      if (stat.type !== "file") {
-        return new Folder(this, stat.filename.replace(/\\/g, "/"), stat.basename, stat.lastmod, stat.fileid);
-      } else {
-        log.debug("getFolder: found object is file not a folder");
-        return null;
-      }
-    } catch (e) {
-      log.debug("getFolder: exception occurred calling stat ", e.message);
-      return null;
-    }
-  }
- 
-  /**
-   * get a array of folders from a folder path string
-   * @param folderName Name of the folder like "/company/branches/germany"
-   * @returns array of folder objects
-   */
-  public async getSubFolders(folderName: string): Promise<Folder[]> {
-    log.debug("getSubFolders: folder ", folderName);
-    const folders: Folder[] = [];
-    folderName = this.sanitizeFolderName(folderName);
- 
-    const folderElements: any[] = await this.contents(folderName, true);
- 
-    for (const folderElement of folderElements) {
-      log.debug("getSubFolders: adding subfolders ", folderElement.filename);
-      // eslint-disable-next-line @typescript-eslint/no-unsafe-call
-      folders.push(new Folder(this, folderElement.filename.replace(/\\/g, "/"), folderElement.basename, folderElement.lastmod, folderElement.fileid));
-    }
- 
-    return folders;
-  }
- 
-  /**
-   * get files of a folder
-   * @param {string} folderName Name of the folder like "/company/branches/germany"
-   * @param {FolderGetFilesOptions} options options for filtering and paging
-   * @returns array of file objects
-   */
-  public async getFiles(folderName: string, options?: FolderGetFilesOptions): Promise<File[]> {
-    log.debug("getFiles: folder ", folderName);
-    const files: File[] = [];
-    folderName = this.sanitizeFolderName(folderName);
- 
-    const fileElements: any[] = await this.contents(folderName, false);
- 
-    for (const folderElement of fileElements) {
-      log.debug("getFiles: adding file ", folderElement.filename);
-      // log.debug("getFiles: adding file ", folderElement);
-      // eslint-disable-next-line @typescript-eslint/no-unsafe-call
-      let file: File | null = new File(this, folderElement.filename.replace(/\\/g, "/"), folderElement.basename, folderElement.lastmod, folderElement.size, folderElement.mime, folderElement.fileid);
- 
-      if (options && options.filterFile) {
-        file = options.filterFile(file);
-      }
-      if (file) {
-        files.push(file);
-      }
-    }
- 
-    return files;
-  }
- 
-  /**
-   * create a new file of overwrites an existing file
-   * @param fileName the file name /folder1/folder2/filename.txt
-   * @param data the buffer object
-   */
-  public async createFile(fileName: string, data: Buffer | NodeJS.ReadableStream): Promise<File> {
-    if (fileName.startsWith("./")) {
-      fileName = fileName.replace("./", "/");
-    }
- 
-    const baseName: string = path.basename(fileName);
-    const folderName: string = path.dirname(fileName);
- 
-    log.debug(`createFile folder name ${folderName} base name ${baseName}`);
- 
-    // ensure that we have a folder
-    await this.createFolder(folderName);
-    await this.putFileContents(fileName, data);
- 
-    const file: File | null = await this.getFile(fileName);
- 
-    if (!file) {
-      throw new ClientError(`Error creating file, file name "${fileName}"`, "ERR_CREATE_FILE_FAILED");
-    }
-    return file;
-  }
- 
-  /**
-   * returns a nextcloud file object
-   * @param fileName the full file name /folder1/folder2/file.pdf
-   */
-  public async getFile(fileName: string): Promise<File | null> {
-    log.debug("getFile fileName = ", fileName);
- 
-    try {
-      const stat: IStat = await this.stat(fileName);
-      log.debug(": SUCCESS!!");
-      Eif (stat.type === "file") {
-        return new File(this, stat.filename.replace(/\\/g, "/"), stat.basename, stat.lastmod, stat.size!, stat.mime || "", stat.fileid || -1);
-      } else {
-        log.debug("getFile: found object is a folder not a file");
-        return null;
-      }
-    } catch (e) {
-      log.debug("getFile: exception occurred calling stat ", e.message);
-      return null;
-    }
-  }
- 
-  /**
-   * renames the file or moves it to an other location
-   * @param sourceFileName source file name
-   * @param targetFileName target file name
-   */
-  public async moveFile(sourceFileName: string, targetFileName: string): Promise<File> {
-    const url: string = this.webDAVUrl + sourceFileName;
-    const destinationUrl: string = this.webDAVUrl + targetFileName;
- 
-    log.debug("moveFile from '" + url + "' to '" + destinationUrl + "'");
- 
-    const requestInit: RequestInit = {
-      // eslint-disable-next-line @typescript-eslint/naming-convention
-      headers: new Headers({ Destination: destinationUrl }),
-      method: "MOVE",
-    };
-    try {
-      await this.getHttpResponse(url, requestInit, [201], { description: "File move" });
-    } catch (err) {
-      log.debug(`Error in move file ${err.message as string} ${requestInit.method || ""} source: ${url} destination: ${destinationUrl}`);
-      throw new ClientError(`Error: moving file failed: source=" ${sourceFileName} target= ${targetFileName} - ${err.message as string}`, "ERR_FILE_MOVE_FAILED");
-    }
- 
-    const targetFile: File | null = await this.getFile(targetFileName);
-    if (!targetFile) {
-      throw new ClientError("Error: moving file failed: source=" + sourceFileName + " target=" + targetFileName, "ERR_FILE_MOVE_FAILED");
-    }
- 
-    return targetFile;
-  }
- 
-  /**
-   * renames the folder or moves it to an other location
-   * @param sourceFolderName source folder name
-   * @param tarName target folder name
-   */
-  public async moveFolder(sourceFolderName: string, tarName: string): Promise<Folder> {
-    const url: string = this.webDAVUrl + sourceFolderName;
-    const destinationUrl: string = this.webDAVUrl + tarName;
- 
-    log.debug(`moveFolder from '${url}' to '${destinationUrl}'`);
- 
-    const requestInit: RequestInit = {
-      // eslint-disable-next-line @typescript-eslint/naming-convention
-      headers: new Headers({ Destination: destinationUrl }),
-      method: "MOVE",
-    };
-    try {
-      await this.getHttpResponse(url, requestInit, [201], { description: "Folder move" });
-    } catch (err) {
-      log.debug(`Error in move folder ${err.message as string} ${requestInit.method || ""} source: ${url} destination: ${destinationUrl}`);
-      throw new ClientError(`Error: moving folder failed: source=${sourceFolderName} target=${tarName} - ${err.message as string}`, "ERR_FOLDER_MOVE_FAILED");
-    }
- 
-    const tar: Folder | null = await this.getFolder(tarName);
-    if (!tar) {
-      throw new ClientError("Error: moving folder failed: source=" + sourceFolderName + " target=" + tarName, "ERR_FOLDER_MOVE_FAILED");
-    }
- 
-    return tar;
-  }
- 
-  /**
-   * returns the content of a file
-   * @param fileName name of the file /d1/file1.txt
-   * @returns Buffer with file content
-   */
-  public async getContent(fileName: string): Promise<Buffer> {
-    const url = this.webDAVUrl + fileName;
-    log.debug("getContent GET ", url);
-    const requestInit: RequestInit = {
-      method: "GET",
-    };
-    let response: Response;
-    try {
-      response = await this.getHttpResponse(url, requestInit, [200], { description: "File get content" });
-    } catch (err) {
-      log.debug(`Error getContent ${url} - error ${err.message as string}`);
-      throw err;
-    }
- 
-    return Buffer.from(await response.buffer());
-  }
- 
-  /**
-   * returns the content of a file
-   * @param fileName name of the file /d1/file1.txt
-   * @returns Buffer with file content
-   */
-  public async pipeContentStream(fileName: string, destination: NodeJS.WritableStream): Promise<void> {
-    const url = this.webDAVUrl + fileName;
-    log.debug("getContent GET ", url);
-    const requestInit: RequestInit = {
-      method: "GET",
-    };
-    let response: Response;
-    try {
-      response = await this.getHttpResponse(url, requestInit, [200], { description: "File pipe content stream" });
-    } catch (err) {
-      log.debug(`Error getContent ${url} - error ${err.message as string}`);
-      throw err;
-    }
-    response.body.pipe(destination);
-  }
- 
-  /**
-   * returns the link to a file for downloading
-   * @param fileName name of the file /folder1/folder1.txt
-   * @returns url
-   */
-  public getLink(fileName: string): string {
-    log.debug("getLink of ", fileName);
-    return this.webDAVUrl + fileName;
-  }
- 
-  /**
-   * returns the url to the file in the nextcloud UI
-   * @param fileId the id of the file
-   */
-  public getUILink(fileId: number): string {
-    log.debug("getUILink of ", fileId);
-    return `${this.nextcloudOrigin}/apps/files/?fileid=${fileId}`;
-  }
- 
-  /**
-   * adds a tag to a file or folder
-   * if the tag does not exist, it is automatically created
-   * if the tag is created, the user must have damin privileges
-   * @param fileId the id of the file
-   * @param tagName the name of the tag
-   * @returns nothing
-   * @throws Error
-   */
-  public async addTagToFile(fileId: number, tagName: string): Promise<void> {
-    log.debug(`addTagToFile file: "${fileId}" tag: "${tagName}"`);
-    const tag: Tag = await this.createTag(tagName);
- 
-    if (!tag.canAssign) {
-      throw new ClientError(`Error: No permission to assign tag "${tagName}" to file. Tag is not assignable`, "ERR_TAG_NOT_ASSIGNABLE");
-    }
- 
-    const addTagBody: any = {
-      canAssign: tag.canAssign,
-      id: tag.id,
-      name: tag.name,
-      userAssignable: tag.assignable,
-      userVisible: tag.visible,
-    };
- 
-    const requestInit: RequestInit = {
-      body: JSON.stringify(addTagBody, null, 4),
-      // eslint-disable-next-line @typescript-eslint/naming-convention
-      headers: new Headers({ "Content-Type": "application/json" }),
-      method: "PUT",
-    };
- 
-    await this.getHttpResponse(`${this.nextcloudOrigin}/remote.php/dav/systemtags-relations/files/${fileId}/${tag.id}`, requestInit, [201, 409], { description: "File add tag" }); // created or conflict
-  }
- 
-  // ***************************************************************************************
-  // activity
-  // ***************************************************************************************
-  /*
-    @todo to be refactored to eventing
- 
-    public async getActivities(): Promise<string[]> {
-        const result: string[] = [];
-        const requestInit: RequestInit = {
-            headers: new Headers({ "ocs-apirequest": "true" }),
-            method: "GET",
-        };
- 
-        const response: Response = await this.getHttpResponse(
-            this.nextcloudOrigin + "/ocs/v2.php/apps/activity/api/v2/activity/files?format=json&previews=false&since=97533",
-            requestInit,
-            [200],
-            { description: "Activities get" });
- 
-        const responseObject: any = await response.json();
-        // @todo
- 
-        for (const res of responseObject.ocs.data) {
-            log.debug(JSON.stringify({
-                acivityId: res.activity_id,
-                objects: res.objects,
-                type: res.type,
-            }, null, 4));
-        }
- 
-        // log.debug("getActivities: responseObject ", JSON.stringify(responseObject, null, 4));
- 
-        return result;
-    }
-*/
-  // ***************************************************************************************
-  // comments
-  // ***************************************************************************************
- 
-  /**
-   * adds a comment to a file
-   * @param fileId the id of the file
-   * @param comment the comment to be added to the file
-   */
-  public async addCommentToFile(fileId: number, comment: string): Promise<void> {
-    log.debug(`addCommentToFile file:"${fileId}" comment:"${comment}"`);
- 
-    const addCommentBody: any = {
-      actorType: "users",
-      message: comment,
-      objectType: "files",
-      verb: "comment",
-    };
- 
-    const requestInit: RequestInit = {
-      body: JSON.stringify(addCommentBody, null, 4),
-      // eslint-disable-next-line @typescript-eslint/naming-convention
-      headers: new Headers({ "Content-Type": "application/json" }),
-      method: "POST",
-    };
- 
-    await this.getHttpResponse(`${this.nextcloudOrigin}/remote.php/dav/comments/files/${fileId}`, requestInit, [201], { description: "File add comment" }); // created
-  }
- 
-  /**
-   * returns comments of a file / folder
-   * @param fileId the id of the file / folder
-   * @param top number of comments to return
-   * @param skip the offset
-   * @returns array of comment strings
-   * @throws Exception
-   */
-  public async getFileComments(fileId: number, top?: number, skip?: number): Promise<string[]> {
-    log.debug("getFileComments fileId: ", fileId);
-    if (!top) {
-      top = 30;
-    }
- 
-    if (!skip) {
-      skip = 0;
-    }
- 
-    const requestInit: RequestInit = {
-      body: `<?xml version="1.0" encoding="utf-8" ?>
-                    <oc:filter-comments xmlns:D="DAV:" xmlns:oc="http://owncloud.org/ns">
-                        <oc:limit>${top}</oc:limit>
-                        <oc:offset>${skip}</oc:offset>
-                    </oc:filter-comments>`,
-      method: "REPORT",
-    };
- 
-    const response: Response = await this.getHttpResponse(`${this.nextcloudOrigin}/remote.php/dav/comments/files/${fileId}`, requestInit, [207], { description: "File get comments" });
- 
-    const properties: any[] = await this.getPropertiesFromWebDAVMultistatusResponse(response, "");
-    const comments: string[] = [];
-    for (const prop of properties) {
-      comments.push(prop.message);
-    }
- 
-    return comments;
-  }
- 
-  /**
-   * returns system information about the nextcloud server and the nextcloud client
-   */
-  public async getSystemInfo(): Promise<ISystemInfo> {
-    const requestInit: RequestInit = {
-      headers: this.getOcsHeaders(),
-      method: "GET",
-    };
- 
-    const response: Response = await this.getHttpResponse(this.nextcloudOrigin + "/ocs/v2.php/apps/serverinfo/api/v1/info", requestInit, [200], { description: "SystemInfo get" });
- 
-    const rawResult: any = await response.json();
-    // validate the raw result
-    let system = {};
-    let storage = {};
-    let shares = {};
-    let server = {};
-    let activeUsers = {};
- 
-    if (rawResult && rawResult.ocs && rawResult.ocs.data) {
-      if (rawResult.ocs.data.nextcloud) {
-        if (rawResult.ocs.data.nextcloud.system) {
-          system = rawResult.ocs.data.nextcloud.system;
-        } else {
-          throw new ClientError("Fatal Error: nextcloud data.nextcloud.system missing", "ERR_SYSTEM_INFO_MISSING_DATA");
-        }
- 
-        if (rawResult.ocs.data.nextcloud.storage) {
-          storage = rawResult.ocs.data.nextcloud.storage;
-        } else {
-          throw new ClientError("Fatal Error: nextcloud data.nextcloud.storage missing", "ERR_SYSTEM_INFO_MISSING_DATA");
-        }
- 
-        if (rawResult.ocs.data.nextcloud.shares) {
-          shares = rawResult.ocs.data.nextcloud.shares;
-        } else {
-          throw new ClientError("Fatal Error: nextcloud data.nextcloud.shares missing", "ERR_SYSTEM_INFO_MISSING_DATA");
-        }
-      } else {
-        throw new ClientError("Fatal Error: nextcloud data.nextcloud missing", "ERR_SYSTEM_INFO_MISSING_DATA");
-      }
- 
-      if (rawResult.ocs.data.server) {
-        server = rawResult.ocs.data.server;
-      } else {
-        throw new ClientError("Fatal Error: nextcloud data.server missing", "ERR_SYSTEM_INFO_MISSING_DATA");
-      }
- 
-      if (rawResult.ocs.data.activeUsers) {
-        activeUsers = rawResult.ocs.data.activeUsers;
-      } else {
-        throw new ClientError("Fatal Error: nextcloud data.activeUsers missing", "ERR_SYSTEM_INFO_MISSING_DATA");
-      }
-    } else {
-      throw new ClientError("Fatal Error: nextcloud system data missing", "ERR_SYSTEM_INFO_MISSING_DATA");
-    }
- 
-    const result: ISystemInfo = {
-      activeUsers,
-      nextcloud: {
-        shares,
-        storage,
-        system,
-      },
-      nextcloudClient: {
-        // eslint-disable-next-line @typescript-eslint/no-var-requires
-        version: require("../package.json").version,
-      },
-      server,
-    };
-    return result;
-  }
- 
-  public async getSystemBasicData(): Promise<ISysBasicData> {
-    const requestInit: RequestInit = {
-      headers: this.getOcsHeaders(),
-      method: "GET",
-    };
- 
-    const response: Response = await this.getHttpResponse(this.nextcloudOrigin + "/ocs/v2.php/apps/serverinfo/api/v1/basicdata", requestInit, [200], { description: "System Basic Data get" });
- 
-    const rawResult: any = await response.json();
-    // console.log("Basic Data\n", JSON.stringify(rawResult));
-    let result: ISysBasicData;
- 
-    if (rawResult && rawResult.ocs && rawResult.ocs.data && rawResult.ocs.data.servertime && rawResult.ocs.data.uptime && rawResult.ocs.data.timeservers) {
-      result = {
-        // eslint-disable-next-line @typescript-eslint/no-unsafe-call
-        serverTimeString: rawResult.ocs.data.servertime.replace("\n", ""),
-        // eslint-disable-next-line @typescript-eslint/no-unsafe-call
-        uptimeString: rawResult.ocs.data.uptime.replace("\n", ""),
-        // eslint-disable-next-line @typescript-eslint/no-unsafe-call
-        timeServersString: rawResult.ocs.data.timeservers.trim(),
-      };
-    } else {
-      throw new ClientError("Fatal Error: nextcloud basic data missing", "ERR_SYSTEM_INFO_MISSING_DATA");
-    }
- 
-    return result;
-  }
- 
-  // ***************************************************************************************
-  // user management
-  // ***************************************************************************************
- 
-  // ***************************************************************************************
-  // user group
-  // spec: https://docs.nextcloud.com/server/latest/admin_manual/configuration_user/instruction_set_for_groups.html
-  // ***************************************************************************************
- 
-  /**
-   * returns a list of user groups
-   * @param search string
-   * @param limit number
-   * @param offset number
-   * @returns list of user groups
-   * @throws QueryLimitError
-   * @throws QueryOffsetError
-   */
-  public async getUserGroups(search?: string, limit?: number, offset?: number): Promise<UserGroup[]> {
-    log.debug("getUserGroups");
- 
-    const userGroupIds: string[] = await this.getUserGroupIds(search, limit, offset);
-    const userGroups: UserGroup[] = [];
-    for (const userGroupId of userGroupIds) {
-      userGroups.push(new UserGroup(this, userGroupId));
-    }
-    return userGroups;
-  }
- 
-  /**
-   * returns a list of user groups
-   * @param search string
-   * @param limit number
-   * @param offset number
-   * @returns list of user groups
-   * @throws QueryLimitError
-   * @throws QueryOffsetError
-   */
-  public async getUserGroupIds(search?: string, limit?: number, offset?: number): Promise<string[]> {
-    log.debug("getUserGroupIds");
-    const requestInit: RequestInit = {
-      headers: this.getOcsHeaders(),
-      method: "GET",
-    };
- 
-    let url = this.getOcsUrl(`/groups`);
-    const queryParameter: string[] = [];
-    if (search) {
-      queryParameter.push(`search=${search}`);
-    }
-    if (limit) {
-      if (limit < 1) {
-        throw new QueryLimitError("The limit must be larger than 0");
-      }
-      queryParameter.push(`limit=${limit}`);
-    }
-    if (offset) {
-      if (offset < 1) {
-        throw new QueryOffsetError("The offset must be larger than 0");
-      }
-      queryParameter.push(`offset=${offset}`);
-    }
-    if (queryParameter.join("&").length > 1) {
-      url += "?" + queryParameter.join("&");
-    }
-    log.debug("url ", url);
- 
-    const response: Response = await this.getHttpResponse(url, requestInit, [200], { description: "User Groups get" });
-    const rawResult: any = await response.json();
-    /*
-        {
-          ocs: {
-            meta: {
-              status: 'ok',
-              statuscode: 100,
-              message: 'OK',
-              totalitems: '',
-              itemsperpage: ''
-            },
-            data: { groups: ["g1", "g2"] }
-          }
-        }
-        */
-    const userGroups: string[] = [];
- 
-    if (rawResult.ocs && rawResult.ocs.data && rawResult.ocs.data.groups) {
-      log.debug("groups", rawResult.ocs.data.groups);
-      // eslint-disable-next-line @typescript-eslint/no-unsafe-call
-      rawResult.ocs.data.groups.forEach((value: string) => {
-        // userGroups.push(new UserGroup(this, value));
-        userGroups.push(value);
-      });
-    }
-    return userGroups;
-  }
- 
-  /**
-   * get user group
-   * @param id string
-   * @returns Promise<UserGroup|null>
-   */
-  public async getUserGroup(id: string): Promise<UserGroup | null> {
-    const userGroups: UserGroup[] = await this.getUserGroups(id);
-    if (userGroups[0]) {
-      return userGroups[0];
-    }
-    return null;
-  }
- 
-  /**
-   * returns a list of user ids that are members of the user group
-   * @param id string
-   * @returns list of member user ids
-   * @throws [UserGroupDoesNotExistError}
-   */
-  public async getUserGroupMembers(id: string): Promise<string[]> {
-    log.debug("getUserGroupMembers");
-    const requestInit: RequestInit = {
-      headers: this.getOcsHeaders(),
-      method: "GET",
-    };
- 
-    const url = this.getOcsUrl(`/groups/${id}`);
-    log.debug("url ", url);
- 
-    const response: Response = await this.getHttpResponse(url, requestInit, [200], { description: "User group get members" });
-    const rawResult: any = await response.json();
-    const userIds: string[] = [];
- 
-    if (this.getOcsMetaStatus(rawResult).code === 404) {
-      throw new UserGroupDoesNotExistError(`User Group ${id} does not exist`);
-    }
- 
-    if (rawResult.ocs && rawResult.ocs.data && rawResult.ocs.data.users) {
-      log.debug("members", rawResult.ocs.data.users);
-      // eslint-disable-next-line @typescript-eslint/no-unsafe-call
-      rawResult.ocs.data.users.forEach((value: string) => {
-        userIds.push(value);
-      });
-    }
- 
-    return userIds;
-  }
- 
-  /**
-   * returns a list of user ids that are subadmins of the user group
-   * @param id string
-   * @returns list of subadmin user ids
-   * @throws [UserGroupDoesNotExistError}
-   */
-  public async getUserGroupSubadmins(id: string): Promise<string[]> {
-    log.debug("getUserGroupsubadmins");
-    const requestInit: RequestInit = {
-      headers: this.getOcsHeaders(),
-      method: "GET",
-    };
- 
-    const url = this.getOcsUrl(`/groups/${id}/subadmins`);
-    log.debug("url ", url);
- 
-    const response: Response = await this.getHttpResponse(url, requestInit, [200], { description: "User group get subadmins" });
-    const rawResult: any = await response.json();
-    const userIds: string[] = [];
- 
-    if (this.getOcsMetaStatus(rawResult).code === 101) {
-      throw new UserGroupDoesNotExistError(`User Group ${id} does not exist`);
-    }
- 
-    if (rawResult.ocs && rawResult.ocs.data) {
-      log.debug("subadmins", rawResult.ocs.data);
-      // eslint-disable-next-line @typescript-eslint/no-unsafe-call
-      rawResult.ocs.data.forEach((value: string) => {
-        userIds.push(value);
-      });
-    }
- 
-    return userIds;
-  }
- 
-  /**
-   * create a new user group
-   * @async
-   * @param {string} id user group id
-   * @returns {Promise<UserGroup>}
-   * @throws {UserGroupAlreadyExistsError}
-   */
-  public async createUserGroup(id: string): Promise<UserGroup> {
-    log.debug("createUserGroup id=", id);
-    const requestInit: RequestInit = {
-      body: JSON.stringify({ groupid: id }),
-      headers: this.getOcsHeaders(),
-      method: "POST",
-    };
-    log.debug("request body: ", requestInit.body);
-    const response: Response = await this.getHttpResponse(this.getOcsUrl(`/groups`), requestInit, [200], { description: "UserGroup create" });
-    const rawResult: any = await response.json();
- 
-    if (this.getOcsMetaStatus(rawResult).code === 102) {
-      throw new UserGroupAlreadyExistsError(`User Group ${id} already exists`);
-    }
- 
-    if (this.getOcsMetaStatus(rawResult).code === 100) {
-      return new UserGroup(this, id);
-    }
-    throw new OperationFailedError(`User group ${id} could not be created: ${this.getOcsMetaStatus(rawResult).message}`);
-  }
- 
-  /**
-   * deletes an existing user group
-   * @param id string
-   * @returns {Promise<void>}
-   * @throws {UserGroupDowsNotExistError}
-   * @throws {UserGroupDeletionFailedError}
-   */
-  public async deleteUserGroup(id: string): Promise<void> {
-    log.debug("deleteUserGroup id=", id);
-    const requestInit: RequestInit = {
-      headers: this.getOcsHeaders(),
-      method: "DELETE",
-    };
-    log.debug("request body: ", requestInit.body);
-    const response: Response = await this.getHttpResponse(this.getOcsUrl(`/groups/${id}`), requestInit, [200], { description: "UserGroup delete" });
-    const rawResult: any = await response.json();
- 
-    if (this.getOcsMetaStatus(rawResult).code === 101) {
-      throw new UserGroupDoesNotExistError(`User Group ${id} does not exists`);
-    }
- 
-    if (this.getOcsMetaStatus(rawResult).code === 102) {
-      throw new UserGroupDeletionFailedError(`User Group ${id} could not be deleted`);
-    }
-  }
- 
-  // ***************************************************************************************
-  // user
-  // spec: https://docs.nextcloud.com/server/latest/admin_manual/configuration_user/instruction_set_for_users.html
-  // ***************************************************************************************
- 
-  /**
-   * returns a list of users
-   * https://docs.nextcloud.com/server/latest/admin_manual/configuration_user/instruction_set_for_users.html#search-get-users
-   * @param search string
-   * @param limit number
-   * @param offset number
-   */
-  public async getUsers(search?: string, limit?: number, offset?: number): Promise<User[]> {
-    log.debug("getUsers");
-    const requestInit: RequestInit = {
-      headers: this.getOcsHeaders(),
-      method: "GET",
-    };
- 
-    let url = this.getOcsUrl(`/users`);
-    const queryParameter: string[] = [];
-    if (search) {
-      queryParameter.push(`search=${search}`);
-    }
-    if (limit) {
-      if (limit < 1) {
-        throw new QueryLimitError("The limit must be larger than 0");
-      }
-      queryParameter.push(`limit=${limit}`);
-    }
-    if (offset) {
-      if (offset < 1) {
-        throw new QueryOffsetError("The offset must be larger than 0");
-      }
-      queryParameter.push(`offset=${offset}`);
-    }
-    if (queryParameter.join("&").length > 1) {
-      url += "?" + queryParameter.join("&");
-    }
-    log.debug("url ", url);
- 
-    const response: Response = await this.getHttpResponse(url, requestInit, [200], { description: "Users get" });
-    const rawResult: any = await response.json();
-    /*
-        {
-          ocs: {
-            meta: {
-              status: 'ok',
-              statuscode: 100,
-              message: 'OK',
-              totalitems: '',
-              itemsperpage: ''
-            },
-            data: { users: ["u1", "u2"] }
-          }
-        }
-        */
-    const users: User[] = [];
- 
-    if (rawResult.ocs && rawResult.ocs.data && rawResult.ocs.data.users) {
-      log.debug("user ids", rawResult.ocs.data.users);
-      // eslint-disable-next-line @typescript-eslint/no-unsafe-call
-      rawResult.ocs.data.users.forEach((value: string) => {
-        users.push(new User(this, value));
-      });
-    }
- 
-    return users;
-  }
- 
-  /**
-   * returns user data
-   * @param id string the user id
-   * @returns Promise<IUserOptions> user data
-   * @throws {UserNotFoundError}
-   */
-  public async getUserData(id: string): Promise<IUserOptions> {
-    log.debug("getUserData");
-    const requestInit: RequestInit = {
-      headers: this.getOcsHeaders(),
-      method: "GET",
-    };
- 
-    const url = this.getOcsUrl(`/users/${id}`);
-    log.debug("url ", url);
- 
-    const response: Response = await this.getHttpResponse(url, requestInit, [200], { description: `User ${id} get` });
-    const rawResult: any = await response.json();
- 
-    if (this.getOcsMetaStatus(rawResult).code === 404) {
-      throw new UserNotFoundError(`User '${id}' not found`);
-    }
-    /*
-        {
-          ocs: {
-            meta: {
-              status: 'ok',
-              statuscode: 100,
-              message: 'OK',
-              totalitems: '',
-              itemsperpage: ''
-            },
-            data: { ... }
-          }
-        }
-        */
- 
-    log.debug("user data", rawResult.ocs.data);
-    const userData: IUserOptions = {
-      enabled: rawResult.ocs.data.enabled,
-      lastLogin: rawResult.ocs.data.lastLogin === 0 ? undefined : new Date(rawResult.ocs.data.lastLogin),
-      subadminGroups: rawResult.ocs.data.subadmin,
-      memberGroups: rawResult.ocs.data.groups,
-      quota: {
-        free: 0,
-        used: 0,
-        total: 0,
-        relative: 0,
-        quota: 0,
-      },
-      email: rawResult.ocs.data.email,
-      displayName: rawResult.ocs.data.displayname,
-      phone: rawResult.ocs.data.phone,
-      address: rawResult.ocs.data.address,
-      website: rawResult.ocs.data.website,
-      twitter: rawResult.ocs.data.twitter,
-      language: rawResult.ocs.data.language,
-      locale: rawResult.ocs.data.locale,
-    };
-    if (rawResult.ocs.data.quota.quota === "none") {
-      userData.quota = { quota: 0, relative: 0, used: 0 };
-    } else {
-      if (!rawResult.ocs.data.quota.relative) {
-        rawResult.ocs.data.quota.relative = 0;
-      }
-      userData.quota = { quota: rawResult.ocs.data.quota.quota, relative: rawResult.ocs.data.quota.relative, used: rawResult.ocs.data.quota.used };
-      if (rawResult.ocs.data.quota.free) {
-        userData.quota.free = rawResult.ocs.data.quota.free;
-      }
-      if (rawResult.ocs.data.quota.total) {
-        userData.quota.total = rawResult.ocs.data.quota.total;
-      }
-    }
-    return userData;
-  }
- 
-  /**
-   * enables the user
-   * @param id string the user id
-   * @returns {Promise<void>}
-   * @throws {UserNotFoundError}
-   */
-  public async enableUser(id: string): Promise<void> {
-    log.debug("enableUser");
-    const requestInit: RequestInit = {
-      headers: this.getOcsHeaders(),
-      method: "PUT",
-    };
- 
-    const url = this.getOcsUrl(`/users/${id}/enable`);
-    log.debug("url ", url);
- 
-    const response: Response = await this.getHttpResponse(url, requestInit, [200], { description: `User ${id} enable` });
-    const rawResult: any = await response.json();
- 
-    if (this.getOcsMetaStatus(rawResult).code === 100) {
-      return;
-    }
-    throw new UserNotFoundError(`User '${id}' not found`);
-  }
- 
-  /**
-   * disables the user
-   * @param id string the user id
-   * @returns {Promise<void>}
-   * @throws {UserNotFoundError}
-   */
-  public async disableUser(id: string): Promise<void> {
-    log.debug("disableUser");
-    const requestInit: RequestInit = {
-      headers: this.getOcsHeaders(),
-      method: "PUT",
-    };
- 
-    const url = this.getOcsUrl(`/users/${id}/disable`);
-    log.debug("url ", url);
- 
-    const response: Response = await this.getHttpResponse(url, requestInit, [200], { description: `User ${id} disable` });
-    const rawResult: any = await response.json();
- 
-    if (this.getOcsMetaStatus(rawResult).code === 100) {
-      return;
-    }
-    throw new UserNotFoundError(`User '${id}' not found`);
-  }
- 
-  /**
-   * deletes the user
-   * @param id string the user id
-   * @returns {Promise<void>}
-   * @throws {UserNotFoundError}
-   */
-  public async deleteUser(id: string): Promise<void> {
-    log.debug("deleteUser");
-    const requestInit: RequestInit = {
-      headers: this.getOcsHeaders(),
-      method: "DELETE",
-    };
- 
-    const url = this.getOcsUrl(`/users/${id}`);
-    log.debug("url ", url);
- 
-    const response: Response = await this.getHttpResponse(url, requestInit, [200], { description: `User ${id} delete` });
-    const rawResult: any = await response.json();
- 
-    if (this.getOcsMetaStatus(rawResult).code === 100) {
-      return;
-    }
-    throw new UserNotFoundError(`User '${id}' not found`);
-  }
- 
-  /**
-   * returns a user or null if not found
-   * @param id string
-   * @returns User | null
-   */
-  public async getUser(id: string): Promise<User | null> {
-    log.debug("getUser");
-    const users: User[] = await this.getUsers(id);
-    if (users[0]) {
-      return users[0];
-    }
-    return null;
-  }
- 
-  /**
-   * creates a new user with email or password
-   * @param options
-   * @returns User
-   * @throws UserAlreadyExistsError
-   * @throws {UserNotFoundError}
-   * @throws UserUpdateError
-   */
-  public async createUser(options: { id: string; email?: string; password?: string }): Promise<User> {
-    log.debug("createUser");
-    const createUserBody: { userid: string; password?: string; email?: string } = { userid: options.id };
-    if (options.email) {
-      if (/^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(options.email)) {
-        createUserBody.email = options.email;
-      } else {
-        throw new UserCreateError(`Error creating user '${options.id}' - invalid email address '${options.email}'`);
-      }
-    }
-    if (options.password) {
-      createUserBody.password = options.password;
-    }
- 
-    const requestInit: RequestInit = {
-      body: JSON.stringify(createUserBody, null, 4),
-      headers: this.getOcsHeaders(),
-      method: "POST",
-    };
-    log.debug("request body: ", requestInit.body);
-    const response: Response = await this.getHttpResponse(this.getOcsUrl(`/users`), requestInit, [200], { description: `User ${options.id} create` });
-    const rawResult: any = await response.json();
- 
-    if (this.getOcsMetaStatus(rawResult).code === 102) {
-      throw new UserAlreadyExistsError(`User with id '${options.id}' already exists`);
-    }
- 
-    const user: User | null = await this.getUser(options.id);
-    if (user) {
-      return user;
-    }
- 
-    throw new UserCreateError(`Error creating user '${options.id}' - ${this.getOcsMetaStatus(rawResult).message} (${this.getOcsMetaStatus(rawResult).code})`);
-  }
- 
-  /**
-   * updates a user property
-   * @async
-   * @param {string} id user id
-   * @param {UserProperty} property property name
-   * @param {string} value property value
-   * @returns {Promise<void>}
-   * @throws  {UserNotFoundError}
-   * @throws  {UserUpdateError}
-   */
-  public async updateUserProperty(id: string, property: UserProperty, value: string): Promise<void> {
-    log.debug("updateUserProperty");
-    const body: { key: string; value: string } = { key: property, value };
- 
-    const requestInit: RequestInit = {
-      body: JSON.stringify(body, null, 4),
-      headers: this.getOcsHeaders(),
-      method: "PUT",
-    };
-    const url = this.getOcsUrl(`/users/${id}`);
-    log.debug("request body: ", requestInit.body);
-    const response: Response = await this.getHttpResponse(url, requestInit, [200, 401], { description: `User ${id} update ${property}=${value}` });
-    const rawResult: any = await response.json();
- 
-    // This service operation returns a 401, if the user does not exist - very strange...
-    // spec says to return 200 and status code 101
-    /*
-        if (this.getOcsMetaStatus(rawResult).code === 101) {
-            throw new UserNotFoundError(`User with id '${id}' not found`);
-        }
-        */
-    // maybe this is due to a nextcloud api error
-    // it is not possible to distiguish beteen authentication error and user not found :-(
-    if (response.status === 401) {
-      throw new UserNotFoundError(`User with id '${id}' not found`);
-    }
- 
-    if (this.getOcsMetaStatus(rawResult).code === 100) {
-      return;
-    }
- 
-    if (property === UserProperty.password) {
-      value = "********";
-    }
-    // code 102 or 103
-    throw new UserUpdateError(`User with id '${id}' could not be updated - ${property}=${value}. ${rawResult.ocs.meta.message as string}`);
-  }
- 
-  /**
-   * resend the welcome email
-   * @param id user id
-   * @throws  {UserResendWelcomeEmailError}
-   */
-  public async resendWelcomeEmail(id: string): Promise<void> {
-    log.debug("resendWelcomeEmail");
- 
-    const requestInit: RequestInit = {
-      headers: this.getOcsHeaders(),
-      method: "POST",
-    };
-    const url = this.getOcsUrl(`/users/${id}/welcome`);
-    log.debug("request body: ", requestInit.body);
-    const response: Response = await this.getHttpResponse(url, requestInit, [200], { description: `Resend welcome email for user ${id}` });
-    const rawResult: any = await response.json();
- 
-    if (this.getOcsMetaStatus(rawResult).code === 101) {
-      throw new UserResendWelcomeEmailError(`Error sending welcome email for '${id}': Email address not available`);
-    }
- 
-    if (this.getOcsMetaStatus(rawResult).code === 100) {
-      return;
-    }
-    throw new UserResendWelcomeEmailError(`Error sending welcome email for '${id}' failed`);
-  }
- 
-  /**
-   * adds a user to a group as member
-   * @param id string the user id
-   * @param userGroupId string the user group id
-   * @returns {Promise<void>}
-   * @throws {UserNotFoundError}
-   * @throws {UserGroupDoesNotExistError}
-   * @throws {InsufficientPrivilegesError}
-   * @throws {OperationFailedError}
-   */
-  public async addUserToMemberUserGroup(id: string, userGroupId: string): Promise<void> {
-    log.debug("addUserToUserGroup");
- 
-    const body: { groupid: string } = { groupid: userGroupId };
-    const requestInit: RequestInit = {
-      body: JSON.stringify(body, null, 4),
-      headers: this.getOcsHeaders(),
-      method: "POST",
-    };
- 
-    const url = this.getOcsUrl(`/users/${id}/groups`);
-    log.debug("url ", url);
- 
-    const response: Response = await this.getHttpResponse(url, requestInit, [200], { description: `Add user ${id} to user group ${userGroupId}` });
-    const rawResult: any = await response.json();
- 
-    if (this.getOcsMetaStatus(rawResult).code === 100) {
-      return;
-    }
- 
-    if (this.getOcsMetaStatus(rawResult).code === 102) {
-      throw new UserGroupDoesNotExistError(`User group ${userGroupId} does not exist`);
-    }
- 
-    if (this.getOcsMetaStatus(rawResult).code === 103) {
-      throw new UserNotFoundError(`User ${id} does not exist`);
-    }
- 
-    if (this.getOcsMetaStatus(rawResult).code === 104) {
-      throw new InsufficientPrivilegesError(`Insufficient privileges to add a user to a group`);
-    }
- 
-    throw new OperationFailedError(`User ${id} could not be added to user group ${userGroupId}: ${this.getOcsMetaStatus(rawResult).message}`);
-  }
- 
-  /**
-   * removes a user from a group as member
-   * @param id string the user id
-   * @param userGroupId string the user group id
-   * @returns {Promise<void>}
-   * @throws {UserNotFoundError}
-   * @throws {UserGroupDoesNotExistError}
-   * @throws {InsufficientPrivilegesError}
-   * @throws {OperationFailedError}
-   */
-  public async removeUserFromMemberUserGroup(id: string, userGroupId: string): Promise<void> {
-    log.debug("removeUserFromMemberUserGroup");
- 
-    const body: { groupid: string } = { groupid: userGroupId };
-    const requestInit: RequestInit = {
-      body: JSON.stringify(body, null, 4),
-      headers: this.getOcsHeaders(),
-      method: "DELETE",
-    };
- 
-    const url = this.getOcsUrl(`/users/${id}/groups`);
-    log.debug("url ", url);
- 
-    const response: Response = await this.getHttpResponse(url, requestInit, [200], { description: `Remove user ${id} from user group ${userGroupId}` });
-    const rawResult: any = await response.json();
- 
-    if (this.getOcsMetaStatus(rawResult).code === 100) {
-      return;
-    }
- 
-    if (this.getOcsMetaStatus(rawResult).code === 102) {
-      throw new UserGroupDoesNotExistError(`User group ${userGroupId} does not exist`);
-    }
- 
-    if (this.getOcsMetaStatus(rawResult).code === 103) {
-      throw new UserNotFoundError(`User ${id} does not exist`);
-    }
- 
-    if (this.getOcsMetaStatus(rawResult).code === 104) {
-      throw new InsufficientPrivilegesError(`Insufficient privileges to add a user to a group`);
-    }
- 
-    throw new OperationFailedError(`User ${id} could not be added to user group ${userGroupId}: ${this.getOcsMetaStatus(rawResult).message}`);
-  }
- 
-  /**
-   * promotes a user to a user group subadmin
-   * @param id string the user id
-   * @param userGroupId string the user group id
-   * @returns {Promise<void>}
-   * @throws {UserNotFoundError}
-   * @throws {UserGroupDoesNotExistError}
-   * @throws {InsufficientPrivilegesError}
-   * @throws {OperationFailedError}
-   */
-  public async promoteUserToUserGroupSubadmin(id: string, userGroupId: string): Promise<void> {
-    log.debug("promoteUserToUserGroupSubadmin");
- 
-    const body: { groupid: string } = { groupid: userGroupId };
-    const requestInit: RequestInit = {
-      body: JSON.stringify(body, null, 4),
-      headers: this.getOcsHeaders(),
-      method: "POST",
-    };
- 
-    const url = this.getOcsUrl(`/users/${id}/subadmins`);
-    log.debug("url ", url);
- 
-    const response: Response = await this.getHttpResponse(url, requestInit, [200], { description: `Promote User ${id} to user group subadmin ${userGroupId}` });
-    const rawResult: any = await response.json();
- 
-    if (this.getOcsMetaStatus(rawResult).code === 100) {
-      return;
-    }
- 
-    if (this.getOcsMetaStatus(rawResult).code === 102) {
-      throw new UserGroupDoesNotExistError(`User group ${userGroupId} does not exist`);
-    }
- 
-    if (this.getOcsMetaStatus(rawResult).code === 101) {
-      throw new UserNotFoundError(`User ${id} does not exist`);
-    }
- 
-    if (this.getOcsMetaStatus(rawResult).code === 104) {
-      throw new InsufficientPrivilegesError(`Insufficient privileges to add a user to a group`);
-    }
- 
-    throw new OperationFailedError(`User ${id} could not be removed from user group ${userGroupId}: ${this.getOcsMetaStatus(rawResult).message}`);
-  }
- 
-  /**
-   * Removes the subadmin rights for the user specified from the group specified
-   * @param id string the user id
-   * @param userGroupId string the user group id
-   * @returns {Promise<void>}
-   * @throws {InsufficientPrivilegesError}
-   * @throws {OperationFailedError}
-   */
-  public async demoteUserFromSubadminUserGroup(id: string, userGroupId: string): Promise<void> {
-    log.debug("demoteUserFromSubadminUserGroup");
- 
-    const body: { groupid: string } = { groupid: userGroupId };
-    const requestInit: RequestInit = {
-      body: JSON.stringify(body, null, 4),
-      headers: this.getOcsHeaders(),
-      method: "DELETE",
-    };
- 
-    const url = this.getOcsUrl(`/users/${id}/subadmins`);
-    log.debug("url ", url);
- 
-    const response: Response = await this.getHttpResponse(url, requestInit, [200], { description: `Demotes user ${id} from subadmin user group ${userGroupId}` });
-    const rawResult: any = await response.json();
- 
-    if (this.getOcsMetaStatus(rawResult).code === 100) {
-      return;
-    }
- 
-    // this API does not work like remove from group :-(
-    // 101 is for user group not found and user not found
-    /*
-            if (this.getOcsMetaStatus(rawResult).code === 101) {
-                throw new UserGroupDoesNotExistError(`User group ${userGroupId} does not exist`)
-            }
- 
-            if (this.getOcsMetaStatus(rawResult).code === 101) {
-                throw new UserNotFoundError(`User ${id} does not exist`)
-            }
-        */
-    if (this.getOcsMetaStatus(rawResult).code === 104) {
-      throw new InsufficientPrivilegesError(`Insufficient privileges to add a user to a group`);
-    }
- 
-    throw new OperationFailedError(`User ${id} could not be demoted from subadmin user group ${userGroupId}: ${this.getOcsMetaStatus(rawResult).message}`);
-  }
- 
-  /**
-   * insert or update complete user data
-   * @param options IUpsertUserOptions[]
-   * @returns Promise<IUpsertUserReport[]
-   */
-  public async upsertUsers(options: IUpsertUserOptions[]): Promise<IUpsertUserReport[]> {
-    const report: IUpsertUserReport[] = [];
-    for (const option of options) {
-      const userReport: IUpsertUserReport = { id: option.id, message: "", changes: [] };
-      let user: User | null = await this.getUser(option.id);
-      // create or update user?
- 
-      if (!user) {
-        try {
-          user = await this.createUser({ id: option.id, email: option.email, password: option.password });
-          userReport.message = `User ${option.id} created`;
-        } catch (e) {
-          userReport.message = `Create user ${option.id} failed ${e.message as string}`;
-          report.push(userReport);
-          continue;
-        }
-      } else {
-        userReport.message = `User ${option.id} changed`;
-      }
- 
-      let previousValue: string = "";
-      let newValue: string = "";
-      let property: string = "";
- 
-      // ************************
-      // enabled
-      // ************************
-      if (option.enabled !== undefined) {
-        if ((await user.isEnabled()) && option.enabled === false) {
-          try {
-            await user.disable();
-            userReport.changes.push({ property: "enabled", previousValue: "true", newValue: "false" });
-          } catch (e) {
-            userReport.changes.push({ property: "enabled", previousValue: "true", newValue: "true", error: e.message });
-          }
-        }
- 
-        if ((await user.isEnabled()) === false && option.enabled === true) {
-          try {
-            await user.enable();
-            userReport.changes.push({ property: "enabled", previousValue: "false", newValue: "true" });
-          } catch (e) {
-            userReport.changes.push({ property: "enabled", previousValue: "false", newValue: "false", error: e.message });
-          }
-        }
-      }
- 
-      // ************************
-      // super admin
-      // ************************
-      if (option.superAdmin !== undefined) {
-        if ((await user.isSuperAdmin()) && option.superAdmin === false) {
-          try {
-            await user.demoteFromSuperAdmin();
-            userReport.changes.push({ property: "superAdmin", previousValue: "true", newValue: "false" });
-          } catch (e) {
-            userReport.changes.push({ property: "superAdmin", previousValue: "true", newValue: "true", error: e.message });
-          }
-        }
- 
-        if ((await user.isSuperAdmin()) === false && option.superAdmin === true) {
-          try {
-            await user.promoteToSuperAdmin();
-            userReport.changes.push({ property: "superAdmin", previousValue: "false", newValue: "true" });
-          } catch (e) {
-            userReport.changes.push({ property: "superAdmin", previousValue: "false", newValue: "false", error: e.message });
-          }
-        }
-      }
- 
-      // ************************
-      // member groups
-      // ************************
-      if (option.memberGroups !== undefined) {
-        const previousGroups: string[] = await user.getMemberUserGroupIds();
-        const newGroups: string[] = option.memberGroups;
-        if (option.superAdmin !== undefined) {
-          if (option.superAdmin === true) {
-            if (newGroups.indexOf("admin") === -1) {
-              newGroups.push("admin");
-            }
-          }
-        }
-        const groupsToAdd: string[] = newGroups.filter((x) => !previousGroups.includes(x));
-        const groupsToRemove: string[] = previousGroups.filter((x) => !newGroups.includes(x));
-        let userGroup: UserGroup | null;
-        property = "memberGroups";
-        let error: Error | null = null;
-        for (const groupId of groupsToAdd) {
-          userGroup = await this.getUserGroup(groupId);
-          if (!userGroup) {
-            try {
-              userGroup = await this.createUserGroup(groupId);
-            } catch (e) {
-              error = e as Error;
-              break;
-            }
-          }
-          try {
-            await user.addToMemberUserGroup(userGroup);
-          } catch (e) {
-            error = e as Error;
-            break;
-          }
-        }
- 
-        for (const groupId of groupsToRemove) {
-          try {
-            await user.removeFromMemberUserGroup(new UserGroup(this, groupId));
-          } catch (e) {
-            error = e as Error;
-            break;
-          }
-        }
-        if (error) {
-          userReport.changes.push({ property, previousValue: previousGroups.join(", "), newValue: previousGroups.join(", "), error: error.message });
-        } else {
-          Eif (groupsToAdd.length > 0 || groupsToRemove.length > 0) {
-            userReport.changes.push({ property, previousValue: previousGroups.join(", "), newValue: newGroups.join(", ") });
-          }
-        }
-      }
- 
-      // ************************
-      // subadmin groups
-      // ************************
-      if (option.subadminGroups !== undefined) {
-        const previousGroups: string[] = await user.getSubadminUserGroupIds();
-        const newGroups: string[] = option.subadminGroups;
-        const groupsToAdd: string[] = newGroups.filter((x) => !previousGroups.includes(x));
-        const groupsToRemove: string[] = previousGroups.filter((x) => !newGroups.includes(x));
-        let userGroup: UserGroup | null;
-        property = "subadminGroups";
-        let error: Error | null = null;
-        for (const groupId of groupsToAdd) {
-          userGroup = await this.getUserGroup(groupId);
-          if (!userGroup) {
-            try {
-              userGroup = await this.createUserGroup(groupId);
-            } catch (e) {
-              error = e as Error;
-              break;
-            }
-          }
-          try {
-            await user.promoteToUserGroupSubadmin(userGroup);
-          } catch (e) {
-            error = e as Error;
-            break;
-          }
-        }
- 
-        for (const groupId of groupsToRemove) {
-          try {
-            await user.demoteFromSubadminUserGroup(new UserGroup(this, groupId));
-          } catch (e) {
-            error = e as Error;
-            break;
-          }
-        }
-        if (error) {
-          userReport.changes.push({ property, previousValue: previousGroups.join(", "), newValue: previousGroups.join(", "), error: error.message });
-        } else {
-          userReport.changes.push({ property, previousValue: previousGroups.join(", "), newValue: newGroups.join(", ") });
-        }
-      }
- 
-      // ************************
-      // display name
-      // ************************
-      if (option.displayName !== undefined) {
-        previousValue = await user.getDisplayName();
-        newValue = option.displayName;
-        property = "displayName";
-        if (previousValue !== newValue) {
-          try {
-            await user.setDisplayName(option.displayName);
-            userReport.changes.push({ property, previousValue, newValue });
-          } catch (e) {
-            let message = "";
-            Eif (e instanceof Error) {
-              message = e.message;
-            }
-            userReport.changes.push({ property, previousValue, newValue: previousValue, error: message });
-          }
-        }
-      }
- 
-      // ************************
-      // email
-      // ************************
-      if (option.email !== undefined) {
-        previousValue = await user.getEmail();
-        newValue = option.email;
-        property = "email";
-        if (previousValue !== newValue) {
-          try {
-            await user.setEmail(option.email);
-            userReport.changes.push({ property, previousValue, newValue });
-          } catch (e) {
-            let message = "";
-            Eif (e instanceof Error) {
-              message = e.message;
-            }
-            userReport.changes.push({ property, previousValue, newValue: previousValue, error: message });
-          }
-        }
-      }
- 
-      // ************************
-      // language
-      // ************************
-      if (option.language !== undefined) {
-        previousValue = await user.getLanguage();
-        newValue = option.language;
-        property = "language";
-        if (previousValue !== newValue) {
-          try {
-            await user.setLanguage(option.language);
-            userReport.changes.push({ property, previousValue, newValue });
-          } catch (e) {
-            let message = "";
-            Eif (e instanceof Error) {
-              message = e.message;
-            }
-            userReport.changes.push({ property, previousValue, newValue: previousValue, error: message });
-          }
-        }
-      }
- 
-      // ************************
-      // locale
-      // ************************
-      if (option.locale !== undefined) {
-        previousValue = await user.getLocale();
-        newValue = option.locale;
-        property = "locale";
-        if (previousValue !== newValue) {
-          try {
-            await user.setLocale(option.locale);
-            userReport.changes.push({ property, previousValue, newValue });
-          } catch (e) {
-            let message = "";
-            Eif (e instanceof Error) {
-              message = e.message;
-            }
-            userReport.changes.push({ property, previousValue, newValue: previousValue, error: message });
-          }
-        }
-      }
- 
-      // ************************
-      // twitter
-      // ************************
-      if (option.twitter !== undefined) {
-        previousValue = await user.getTwitter();
-        newValue = option.twitter;
-        property = "twitter";
-        if (previousValue !== newValue) {
-          try {
-            await user.setTwitter(option.twitter);
-            userReport.changes.push({ property, previousValue, newValue });
-          } catch (e) {
-            let message = "";
-            Eif (e instanceof Error) {
-              message = e.message;
-            }
-            userReport.changes.push({ property, previousValue, newValue: previousValue, error: message });
-          }
-        }
-      }
- 
-      // ************************
-      // phone
-      // ************************
-      if (option.phone !== undefined) {
-        previousValue = await user.getPhone();
-        newValue = option.phone;
-        property = "phone";
-        if (previousValue !== newValue) {
-          try {
-            await user.setPhone(option.phone);
-            userReport.changes.push({ property, previousValue, newValue });
-          } catch (e) {
-            let message = "";
-            Eif (e instanceof Error) {
-              message = e.message;
-            }
- 
-            userReport.changes.push({ property, previousValue, newValue: previousValue, error: message });
-          }
-        }
-      }
- 
-      // ************************
-      // password
-      // ************************
-      if (option.password !== undefined) {
-        previousValue = "********";
-        newValue = option.password;
-        property = "password";
-        try {
-          await user.setPassword(option.password);
-          userReport.changes.push({ property, previousValue, newValue: previousValue });
-        } catch (e) {
-          let message = "";
-          Eif (e instanceof Error) {
-            message = e.message;
-          }
-          userReport.changes.push({ property, previousValue, newValue: previousValue, error: message });
-        }
-      }
- 
-      // ************************
-      // address
-      // ************************
-      if (option.address !== undefined) {
-        previousValue = await user.getAddress();
-        newValue = option.address;
-        property = "address";
-        if (previousValue !== newValue) {
-          try {
-            await user.setAddress(option.address);
-            userReport.changes.push({ property, previousValue, newValue });
-          } catch (e) {
-            let message = "";
-            Eif (e instanceof Error) {
-              message = e.message;
-            }
-            userReport.changes.push({ property, previousValue, newValue: previousValue, error: message });
-          }
-        }
-      }
- 
-      // ************************
-      // website
-      // ************************
-      if (option.website !== undefined) {
-        previousValue = await user.getWebsite();
-        newValue = option.website;
-        property = "website";
-        if (previousValue !== newValue) {
-          try {
-            await user.setWebsite(option.website);
-            userReport.changes.push({ property, previousValue, newValue });
-          } catch (e) {
-            let message = "";
-            Eif (e instanceof Error) {
-              message = e.message;
-            }
-            userReport.changes.push({ property, previousValue, newValue: previousValue, error: message });
-          }
-        }
-      }
- 
-      // ************************
-      // quota
-      // ************************
-      if (option.quota !== undefined) {
-        previousValue = (await user.getQuotaUserFriendly()).quota;
-        newValue = option.quota;
-        property = "quota";
-        if (previousValue !== newValue) {
-          try {
-            await user.setQuota(option.quota);
-            userReport.changes.push({ property, previousValue, newValue });
-          } catch (e) {
-            let message = "";
-            Eif (e instanceof Error) {
-              message = e.message;
-            }
- 
-            userReport.changes.push({ property, previousValue, newValue: previousValue, error: message });
-          }
-        }
-      }
- 
-      // ************************
-      // resend welcome email
-      // ************************
-      if (option.resendWelcomeEmail !== undefined) {
-        previousValue = "not sent";
-        newValue = "sent";
-        property = "resendWelcomeEmail";
-        if (option.resendWelcomeEmail) {
-          try {
-            await user.resendWelcomeEmail();
-            userReport.changes.push({ property, previousValue, newValue });
-          } catch (e) {
-            let message = "";
-            Eif (e instanceof Error) {
-              message = e.message;
-            }
- 
-            userReport.changes.push({ property, previousValue, newValue: previousValue, error: message });
-          }
-        }
-      }
- 
-      if (userReport.changes.length === 0) {
-        userReport.message = `User ${option.id} not changed`;
-      }
-      report.push(userReport);
-    }
-    return report;
-  }
- 
-  // ***************************************************************************************
-  // shares
-  // https://docs.nextcloud.com/server/latest/developer_manual/client_apis/OCS/ocs-share-api.html
-  // ***************************************************************************************
- 
-  /**
-   * create a new share
-   */
-  public async createShare(options: ICreateShare): Promise<Share> {
-    const shareRequest = Share.createShareRequestBody(options);
-    log.debug(shareRequest);
- 
-    const requestInit: RequestInit = {
-      body: shareRequest,
-      headers: this.getOcsHeaders(),
-      method: "POST",
-    };
-    const url = this.nextcloudOrigin + "/ocs/v2.php/apps/files_sharing/api/v1/shares";
- 
-    // try {
-    const response: Response = await this.getHttpResponse(url, requestInit, [200, 204], { description: "Share create" });
- 
-    const rawResult: { ocs: { data: { id: string } } } = (await response.json()) as { ocs: { data: { id: string } } };
- 
-    log.debug(rawResult);
- 
-    const share: Share = await Share.getShare(this, rawResult.ocs.data.id);
- 
-    if (options.publicUpload) {
-      await share.setPublicUpload();
-    }
- 
-    return share;
- 
-    /* } catch (e) {
-            log.debug("result " + e.message);
-            log.debug("requestInit ", JSON.stringify(requestInit, null, 4));
-            log.debug("headers " + JSON.stringify(headers, null, 4));
-            log.debug("url ", url);
-            throw e;
-        } */
-  }
- 
-  /**
-   * update a new share
-   */
-  public async updateShare(shareId: string, body: { password: string } | { expireDate: string } | { note: string } | { permissions: number }): Promise<void> {
-    log.debug("updateShare body ", body);
- 
-    const requestInit: RequestInit = {
-      body: JSON.stringify(body, null, 4),
-      headers: this.getOcsHeaders(),
-      method: "PUT",
-    };
-    const url = this.nextcloudOrigin + "/ocs/v2.php/apps/files_sharing/api/v1/shares/" + shareId;
- 
-    await this.getHttpResponse(url, requestInit, [200], { description: "Share update" });
-  }
- 
-  /**
-   * get share information
-   * @param shareId
-   */
-  public async getShare(shareId: string): Promise<any> {
-    const requestInit: RequestInit = {
-      headers: this.getOcsHeaders(),
-      method: "GET",
-    };
-    const url = this.nextcloudOrigin + "/ocs/v2.php/apps/files_sharing/api/v1/shares/" + shareId;
- 
-    const response: Response = await this.getHttpResponse(url, requestInit, [200], { description: "Share get" });
- 
-    // eslint-disable-next-line @typescript-eslint/no-unsafe-return
-    return await response.json();
- 
-    /*
-    } catch (e) {
-        log.debug("result " + e.message);
-        log.debug("requestInit ", JSON.stringify(requestInit, null, 4));
-        log.debug("headers " + JSON.stringify(headers, null, 4));
-        log.debug("url ", url);
-        throw e;
-    }
-    */
-  }
- 
-  /**
-   * get share information
-   * @param shareId
-   */
-  public async deleteShare(shareId: string): Promise<any> {
-    const requestInit: RequestInit = {
-      headers: this.getOcsHeaders(),
-      method: "DELETE",
-    };
-    const url = this.nextcloudOrigin + "/ocs/v2.php/apps/files_sharing/api/v1/shares/" + shareId;
- 
-    const response: Response = await this.getHttpResponse(url, requestInit, [200], { description: "Share delete" });
-  }
- 
-  // ***************************************************************************************
-  // notfication management
-  // ***************************************************************************************
-  /**
-   * @returns array of notification objects
-   */
-  // eslint-disable-next-line @typescript-eslint/ban-types
-  public async getNotifications(): Promise<object[]> {
-    const requestInit: RequestInit = {
-      headers: this.getOcsHeaders(),
-      method: "GET",
-    };
- 
-    const response: Response = await this.getHttpResponse(this.nextcloudOrigin + "/ocs/v2.php/apps/notifications/api/v2/notifications", requestInit, [200, 404], { description: "Notifications get" });
- 
-    // no notification found
-    if (response.status === 404) {
-      return [];
-    }
- 
-    const rawResult: any = await response.json();
- 
-    let notifications = [];
- 
-    if (rawResult && rawResult.ocs && rawResult.ocs.data) {
-      notifications = rawResult.ocs.data;
-    } else {
-      throw new ClientError("Fatal Error: nextcloud notifications data missing", "ERR_SYSTEM_INFO_MISSING_DATA"); // @todo wrong error message
-    }
- 
-    // eslint-disable-next-line @typescript-eslint/ban-types
-    const result: object[] = notifications;
-    return result;
-  }
- 
-  // eslint-disable-next-line @typescript-eslint/ban-types
-  public async getUpdateNotifications(version: string): Promise<object> {
-    // @todo refactoring... /ocs/v2.php/apps/notifications/api/v2/notifications/<id>   (GET/DELETE)
- 
-    const requestInit: RequestInit = {
-      headers: this.getOcsHeaders(),
-      method: "GET",
-    };
- 
-    const response: Response = await this.getHttpResponse(this.nextcloudOrigin + `/ocs/v2.php/apps/updatenotification/api/v1/applist/${version}`, requestInit, [200], { description: "UpdateNotifications get" });
- 
-    // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
-    const rawResult: any = await response.json();
- 
-    let updateNotification = {};
- 
-    // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access
-    if (rawResult && rawResult.ocs && rawResult.ocs.data) {
-      updateNotification = rawResult.ocs.data;
-    } else {
-      throw new ClientError("Fatal Error: nextcloud notifications data missing", "ERR_SYSTEM_INFO_MISSING_DATA");
-    }
- 
-    // eslint-disable-next-line @typescript-eslint/ban-types
-    const result: object = updateNotification;
-    return result;
-  }
- 
-  // @todo to be refactored to user
-  public async sendNotificationToUser(userId: string, shortMessage: string, longMessage?: string): Promise<void> {
-    const requestInit: RequestInit = {
-      headers: new Headers({
-        // eslint-disable-next-line @typescript-eslint/naming-convention
-        Accept: "application/json",
-        // eslint-disable-next-line @typescript-eslint/naming-convention
-        "Content-Type": "application/x-www-form-urlencoded",
-        // eslint-disable-next-line @typescript-eslint/naming-convention
-        "OCS-APIRequest": "true",
-      }),
-      method: "POST",
-    };
- 
-    if (!longMessage) {
-      longMessage = "";
-    }
-    longMessage = `&longMessage=${encodeURIComponent(longMessage)}`;
-    const queryString = `${encodeURIComponent(userId)}?shortMessage=${encodeURIComponent(shortMessage)}${longMessage}`;
-    await this.getHttpResponse(this.nextcloudOrigin + `/ocs/v2.php/apps/admin_notifications/api/v1/notifications/${queryString}`, requestInit, [200], { description: "User create" });    
-    // const response: Response = await this.getHttpResponse(this.nextcloudOrigin + `/ocs/v2.php/apps/admin_notifications/api/v1/notifications/${queryString}`, requestInit, [200], { description: "User create" });
-    // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
-    // const rawResult: any = await response.json();
-    //        console.log(rawResult);
-  }
- 
-  // ***************************************************************************************
-  // apps management
-  // ***************************************************************************************
-  /**
-   * returns apps
-   */
-  public async getApps(): Promise<string[]> {
-    const requestInit: RequestInit = {
-      headers: this.getOcsHeaders(),
-      method: "GET",
-    };
- 
-    const response: Response = await this.getHttpResponse(this.getOcsUrl(`/apps`), requestInit, [200], { description: "Apps get" });
- 
-    // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
-    const rawResult: any = await response.json();
- 
-    let apps = [];
- 
-    // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access
-    if (rawResult && rawResult.ocs && rawResult.ocs.data) {
-      apps = rawResult.ocs.data;
-    } else {
-      throw new ClientError("Fatal Error: nextcloud apps data missing", "ERR_SYSTEM_INFO_MISSING_DATA");
-    }
- 
-    const result: string[] = apps;
- 
-    return result;
-  }
-  // eslint-disable-next-line @typescript-eslint/ban-types
-  public async getAppInfos(appName: string): Promise<object> {
-    const requestInit: RequestInit = {
-      headers: this.getOcsHeaders(),
-      method: "GET",
-    };
- 
-    const response: Response = await this.getHttpResponse(this.getOcsUrl(`/apps/${appName}`), requestInit, [200], { description: "App Infos get" });
- 
-    // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
-    const rawResult: any = await response.json();
- 
-    let appInfo = {};
- 
-    // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access
-    if (rawResult && rawResult.ocs && rawResult.ocs.data) {
-      appInfo = rawResult.ocs.data;
-    } else {
-      throw new ClientError("Fatal Error: nextcloud apps data missing", "ERR_SYSTEM_INFO_MISSING_DATA");
-    }
- 
-    // eslint-disable-next-line @typescript-eslint/ban-types
-    const result: object = appInfo;
- 
-    return result;
-  }
- 
-  // ***************************************************************************************
-  // private methods
-  // ***************************************************************************************
- 
-  /**
-   * asserts valid xml
-   * asserts multistatus response
-   * asserts that a href is available in the multistatus response
-   * asserts propstats and prop
-   * @param response the http response
-   * @param href get only properties that match the href
-   * @returns array of properties
-   * @throws GeneralError
-   */
-  private async getPropertiesFromWebDAVMultistatusResponse(response: Response, href: string): Promise<any[]> {
-    const responseContentType: string | null = response.headers.get("Content-Type");
- 
-    if (!responseContentType) {
-      throw new ClientError("Response content type expected", "ERR_RESPONSE_WITHOUT_CONTENT_TYPE_HEADER");
-    }
- 
-    if (responseContentType.indexOf("application/xml") === -1) {
-      throw new ClientError("XML response content type expected", "ERR_XML_RESPONSE_CONTENT_TYPE_EXPECTED");
-    }
- 
-    const xmlBody: string = await response.text();
- 
-    if (parser.validate(xmlBody) !== true) {
-      throw new ClientError(`The response is not valid XML: ${xmlBody}`, "ERR_RESPONSE_NOT_INVALID_XML");
-    }
-    const options: any = {
-      ignoreNameSpace: true,
-    };
-    const body: any = parser.parse(xmlBody, options);
- 
-    // ensure that we have a multistatus response
-    if (!body.multistatus || !body.multistatus.response) {
-      throw new ClientError(`The response is is not a WebDAV multistatus response`, "ERR_RESPONSE_NO_MULTISTATUS_XML");
-    }
- 
-    // ensure that response is always an array
-    if (body.multistatus.response.href || body.multistatus.response.propstat) {
-      body.multistatus.response = new Array(body.multistatus.response);
-    }
-    /*
-                if (body.multistatus.response.propstat) {
-                    body.multistatus.response = [body.multistatus.response];
-                }
-        */
-    const responseProperties: any[] = [];
-    for (const res of body.multistatus.response) {
-      if (!res.href) {
-        throw new ClientError(`The mulitstatus response must have a href`, "ERR_RESPONSE_MISSING_HREF_MULTISTATUS");
-      }
- 
-      if (!res.propstat) {
-        throw new ClientError(`The mulitstatus response must have a "propstat" container`, "ERR_RESPONSE_MISSING_PROPSTAT");
-      }
-      let propStats = res.propstat;
- 
-      // ensure an array
-      if (res.propstat.status || res.propstat.prop) {
-        propStats = [res.propstat];
-      }
- 
-      for (const propStat of propStats) {
-        if (!propStat.status) {
-          throw new ClientError(`The propstat must have a "status"`, "ERR_RESPONSE_MISSING_PROPSTAT_STATUS");
-        }
-        if (propStat.status === "HTTP/1.1 200 OK") {
-          if (!propStat.prop) {
-            throw new ClientError(`The propstat must have a "prop"`, "ERR_RESPONSE_MISSING_PROPSTAT_PROP");
-          }
-          const property: any = propStat.prop;
-          // eslint-disable-next-line no-underscore-dangle
-          property._href = res.href;
-          responseProperties.push(property);
-        }
-      }
-      //            }
-    }
-    // eslint-disable-next-line @typescript-eslint/no-unsafe-return
-    return responseProperties;
-  }
- 
-  /**
-   * nextcloud creates a csrf token and stores it in the html header attribute
-   * data-requesttoken
-   * this function is currently not used
-   * @returns the csrf token / requesttoken
-   */
-  /*
-        private async getCSRFToken(): Promise<string> {
- 
-            const requestInit: RequestInit = {
-                method: "GET",
-            };
- 
-            const response: Response = await this.getHttpResponse(
-                this.nextcloudOrigin,
-                requestInit,
-                [200],
-                { description: "CSER token get" });
- 
-            const html = await response.text();
- 
-            const requestToken: string = html.substr(html.indexOf("data-requesttoken=") + 19, 89);
-            log.debug("getCSRFToken ", requestToken);
-            return requestToken;
-        }
-    */
- 
-  private async getHttpResponse(url: string, requestInit: RequestInit, expectedHttpStatusCode: number[], context: IRequestContext): Promise<Response> {
-    if (!requestInit.headers) {
-      requestInit.headers = new Headers();
-    }
- 
-    /* istanbul ignore else */
-    if (this.fakeServer) {
-      return await this.fakeServer.getFakeHttpResponse(url, requestInit, expectedHttpStatusCode, context);
-    } else {
-      return await this.httpClient!.getHttpResponse(url, requestInit, expectedHttpStatusCode, context);
-    }
-  }
- 
-  /**
-   * get contents array of a folder
-   * @param folderName Name of the folder like "/company/branches/germany"
-   * @param folderIndicator true if folders are requested otherwise files
-   * @returns array of folder contents meta data
-   */
-  private async contents(folderName: string, folderIndicator: boolean): Promise<any[]> {
-    log.debug("Contents: folder ", folderName);
-    const folders: Folder[] = [];
-    folderName = this.sanitizeFolderName(folderName);
-    const resultArray: any[] = [];
- 
-    if (folderIndicator === true) {
-      log.debug("Contents: get folders");
-    } else {
-      log.debug("Contents: get files");
-    }
-    try {
-      const folderContentsArray = await this.getFolderContents(folderName);
- 
-      // log.debug("###########################");
-      // log.debug("$s", JSON.stringify(folderContentsArray, null, 4));
-      // log.debug("###########################");
- 
-      for (const folderElement of folderContentsArray) {
-        if (folderElement.type === "directory") {
-          if (folderIndicator === true) {
-            resultArray.push(folderElement);
-          }
-        } else {
-          if (folderIndicator === false) {
-            log.debug("Contents folder element file ", folderElement);
-            resultArray.push(folderElement);
-          }
-        }
-      }
-    } catch (e) {
-      log.debug("Contents: exception occurred ", e.message);
-    }
- 
-    // eslint-disable-next-line @typescript-eslint/no-unsafe-return
-    return resultArray;
-  }
- 
-  private sanitizeFolderName(folderName: string): string {
-    if (folderName[0] !== "/") {
-      folderName = "/" + folderName;
-    }
-    // remove trailing "/" es
-    folderName = folderName.replace(/\/+$/, "");
-    if (folderName === "") {
-      folderName = "/";
-    }
- 
-    return folderName;
-  }
- 
-  private getTagIdFromHref(href: string): number {
-    return parseInt(href.split("/")[href.split("/").length - 1], 10);
-  }
- 
-  private async createFolderInternal(folderName: string): Promise<void> {
-    const url: string = this.webDAVUrl + folderName;
-    log.debug("createFolderInternal ", url);
- 
-    const requestInit: RequestInit = {
-      method: "MKCOL",
-    };
-    try {
-      await this.getHttpResponse(url, requestInit, [201], { description: "Folder create" });
-    } catch (err) {
-      log.debug(`Error in createFolderInternal ${err.message as string} ${requestInit.method || ""} ${url}`);
-      throw err;
-    }
-  }
- 
-  private async stat(fileName: string): Promise<IStat> {
-    const url: string = this.webDAVUrl + fileName;
-    log.debug("stat ", url);
- 
-    const requestInit: RequestInit = {
-      body: `<?xml version="1.0"?>
-            <d:propfind  xmlns:d="DAV:" xmlns:oc="http://owncloud.org/ns" xmlns:nc="http://nextcloud.org/ns">
-            <d:prop>
-                  <d:getlastmodified />
-                  <d:getetag />
-                  <d:getcontenttype />
-                  <d:resourcetype />
-                  <oc:fileid />
-                  <oc:permissions />
-                  <oc:size />
-                  <d:getcontentlength />
-                  <nc:has-preview />
-                  <oc:favorite />
-                  <oc:comments-unread />
-                  <oc:owner-display-name />
-                  <oc:share-types />
-            </d:prop>
-          </d:propfind>`,
-      // headers: new Headers({ Depth: "0" }),
-      headers: new Headers(),
-      method: "PROPFIND",
-    };
-    let response: Response;
-    try {
-      response = await this.getHttpResponse(url, requestInit, [207], { description: "File/Folder get details" });
-    } catch (err) {
-      log.debug(`Error in stat ${err.message as string} ${requestInit.method || ""} ${url}`);
-      throw err;
-    }
- 
-    const properties: any[] = await this.getPropertiesFromWebDAVMultistatusResponse(response, "");
-    let resultStat: IStat | null = null;
- 
-    for (const prop of properties) {
-      resultStat = {
-        basename: basename(fileName),
-        fileid: prop.fileid,
-        filename: fileName,
-        lastmod: prop.getlastmodified,
-        type: "file",
-      };
- 
-      if (prop.getcontentlength) {
-        resultStat.size = prop.getcontentlength;
-      } else {
-        resultStat.type = "directory";
-      }
- 
-      if (prop.getcontenttype) {
-        resultStat.mime = prop.getcontenttype;
-      }
-    }
- 
-    if (!resultStat) {
-      log.debug("Error: response ", JSON.stringify(properties, null, 4));
-      throw new ClientError("Error getting status information from : " + url, "ERR_STAT");
-    }
-    return resultStat;
-  }
- 
-  private getOcsMetaStatus(input: any): { code: number; message: string } {
-    let code: number;
-    let message: string = "";
-    if (input.ocs && input.ocs.meta && input.ocs.meta.statuscode) {
-      code = input.ocs.meta.statuscode;
-      if (input.ocs.meta.message) {
-        message = input.ocs.meta.message;
-      }
-      return { code, message };
-    }
-    throw new InvalidServiceResponseFormatError("Fatal Error: The OCS meta status could not be retrieved from OCS response");
-  }
- 
-  private getOcsHeaders(): Headers {
-    return new Headers({
-      // eslint-disable-next-line @typescript-eslint/naming-convention
-      "OCS-APIRequest": "true",
-      // eslint-disable-next-line @typescript-eslint/naming-convention
-      "Content-Type": "application/json",
-      // eslint-disable-next-line @typescript-eslint/naming-convention
-      Accept: "application/json",
-    });
-  }
- 
-  private getOcsUrl(suffix: string): string {
-    /*
-        if (!suffix) {
-            suffix = "";
-        }
-        if (!suffix.startsWith("/")) {
-            suffix = `/${suffix}`
-        }
-        */
-    return `${this.nextcloudOrigin}/ocs/v1.php/cloud${suffix}`;
-  }
- 
-  private async putFileContents(fileName: string, data: Buffer | NodeJS.ReadableStream): Promise<Response> {
-    const url: string = this.webDAVUrl + fileName;
-    log.debug("putFileContents ", url);
- 
-    const requestInit: RequestInit = {
-      body: data,
-      method: "PUT",
-    };
- 
-    let description = "File save content ";
-    Eif (data instanceof Buffer) {
-      description += "from buffer";
-    } else {
-      description += "from stream";
-    }
-    return await this.getHttpResponse(url, requestInit, [201, 204], { description });
-  }
-}
- 
- -
-
- - - - - - - - - \ No newline at end of file diff --git a/docs/coverage/lcov-report/src/command.ts.html b/docs/coverage/lcov-report/src/command.ts.html deleted file mode 100644 index 9bd48521..00000000 --- a/docs/coverage/lcov-report/src/command.ts.html +++ /dev/null @@ -1,446 +0,0 @@ - - - - - - Code coverage report for src/command.ts - - - - - - - - - -
-
-

All files / src command.ts

-
- -
- 96% - Statements - 24/25 -
- - -
- 80% - Branches - 8/10 -
- - -
- 100% - Functions - 7/7 -
- - -
- 96% - Lines - 24/25 -
- - -
-

- Press n or j to go to the next uncovered block, b, p or k for the previous block. -

-
-
-

-
1 -2 -3 -4 -5 -6 -7 -8 -9 -10 -11 -12 -13 -14 -15 -16 -17 -18 -19 -20 -21 -22 -23 -24 -25 -26 -27 -28 -29 -30 -31 -32 -33 -34 -35 -36 -37 -38 -39 -40 -41 -42 -43 -44 -45 -46 -47 -48 -49 -50 -51 -52 -53 -54 -55 -56 -57 -58 -59 -60 -61 -62 -63 -64 -65 -66 -67 -68 -69 -70 -71 -72 -73 -74 -75 -76 -77 -78 -79 -80 -81 -82 -83 -84 -85 -86 -87 -88 -89 -90 -91 -92 -93 -94 -95 -96 -97 -98 -99 -100 -101 -102 -103 -104 -105 -106 -107 -108 -109 -110 -111 -112 -113 -114 -115 -116 -117 -118 -119 -120 -121 -122 -123  -1x -  -1x -  -  -  -  -  -  -  -  -  -1x -  -  -  -1x -  -  -  -1x -  -  -  -1x -  -  -  -1x -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -1x -  -  -  -  -  -  -4x -4x -4x -4x -  -  -  -  -  -  -  -  -  -4x -4x -  -  -4x -4x -4x -4x -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -233x -3x -  -230x -  -  -  -  -  -  -  -39x -  -  -  -  -  -  -  -227x -  -  -  -  -  -  -  -42x -  -  -  - 
// tslint:disable-next-line:no-var-requires
-const debug = require("debug").debug("Command");
- 
-import Client, {
-    CommandAlreadyExecutedError,
-} from "./client";
- 
-/**
- * The potential states that a command can have.
- * When a command is created, the state is "initial"
- * When the execution has started, the status is "running"
- * When the execution has finsihed, the status can be "succes" or "failed"
- */
-export enum CommandStatus {
-    /**
-     * When a command is created, the state is "initial"
-     */
-    initial = "initial",
-    /**
-     * When the execution has started, the status is "running"
-     */
-    running = "running",
-    /**
-     * After successful  execution of the command, the status is "success"
-     */
-    success = "success",
-    /**
-     * After unsuccessfull execution of the command, the status is "failed"
-     */
-    failed = "failed",
-}
- 
-/**
- * when the command has finished, the client can get the result of the command execution
- */
-export interface CommandResultMetaData {
-    errors: string[],
-    messages: string[],
-    timeElapsed: number,
-}
- 
-/**
- * The command class represents a potential long running activity.
- * This activity has been wrapped into an object to ease the tracking of the processing state.
- * Create a command with  receiver information, execute the command and check the status and progress.
- * Check the result when finsished.
- */
-export default abstract class Command {
-    protected client: Client;
-    protected status: CommandStatus;
-    protected percentCompleted: number;
-    protected resultMetaData: CommandResultMetaData;
- 
-    constructor(client: Client) {
-        this.client = client;
-        this.status = CommandStatus.initial;
-        this.percentCompleted = 0;
-        this.resultMetaData = { messages: [], errors: [], timeElapsed: 0 };
-    }
- 
-    /**
-     * final execute the command
-     * @async
-     * @final
-     * @returns {Promise<void>}
-     */
-    public async execute(): Promise<void> {
-        debug("execute Command = " + this.constructor.name, this.status);
-        Iif (this.isFinished()) {
-            throw new CommandAlreadyExecutedError("Error: Command has already been executed. Command = " + this.constructor.name);
-        }
-        Eif (this.status === CommandStatus.initial) {
-            const startTime = new Date();
-            await this.onExecute();
-            this.resultMetaData.timeElapsed = new Date().getTime() - startTime.getTime();
-        }
-        // do nothing if already running
-    }
- 
-    /**
-     * execute the command
-     * @async
-     * @returns {Promise<void>}
-     */
-    protected abstract async onExecute(): Promise<void>;
- 
-    /**
-     * returns true, if the command has been finished
-     * @returns {boolean}
-     */
-    public isFinished(): boolean {
-        if (this.status === CommandStatus.failed || this.status === CommandStatus.success) {
-            return true;
-        }
-        return false;
-    }
- 
-    /**
-     * returns the status of the command
-     * @returns {CommandStatus}
-     */
-    public getStatus(): CommandStatus {
-        return this.status;
-    }
- 
-    /**
-     * returns the completion percentage of the command
-     * @returns {number} percentage of completion
-     */
-    public getPercentCompleted(): number {
-        return this.percentCompleted;
-    }
- 
-    /**
-     * returns the result meta data of the command
-     * @returns {null|any} the result of the command
-     */
-    public getResultMetaData(): CommandResultMetaData {
-        return this.resultMetaData;
-    }
- 
-}
- 
- -
-
- - - - - - - - - \ No newline at end of file diff --git a/docs/coverage/lcov-report/src/command/command.ts.html b/docs/coverage/lcov-report/src/command/command.ts.html deleted file mode 100644 index e6f87c8c..00000000 --- a/docs/coverage/lcov-report/src/command/command.ts.html +++ /dev/null @@ -1,446 +0,0 @@ - - - - - - Code coverage report for src/command/command.ts - - - - - - - - - -
-
-

All files / src/command command.ts

-
- -
- 96% - Statements - 24/25 -
- - -
- 90% - Branches - 9/10 -
- - -
- 100% - Functions - 7/7 -
- - -
- 96% - Lines - 24/25 -
- - -
-

- Press n or j to go to the next uncovered block, b, p or k for the previous block. -

-
-
-

-
1 -2 -3 -4 -5 -6 -7 -8 -9 -10 -11 -12 -13 -14 -15 -16 -17 -18 -19 -20 -21 -22 -23 -24 -25 -26 -27 -28 -29 -30 -31 -32 -33 -34 -35 -36 -37 -38 -39 -40 -41 -42 -43 -44 -45 -46 -47 -48 -49 -50 -51 -52 -53 -54 -55 -56 -57 -58 -59 -60 -61 -62 -63 -64 -65 -66 -67 -68 -69 -70 -71 -72 -73 -74 -75 -76 -77 -78 -79 -80 -81 -82 -83 -84 -85 -86 -87 -88 -89 -90 -91 -92 -93 -94 -95 -96 -97 -98 -99 -100 -101 -102 -103 -104 -105 -106 -107 -108 -109 -110 -111 -112 -113 -114 -115 -116 -117 -118 -119 -120 -121 -122 -123  -1x -  -1x -  -  -  -  -  -  -  -  -  -1x -  -  -  -1x -  -  -  -1x -  -  -  -1x -  -  -  -1x -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -1x -  -  -  -  -  -  -20x -20x -20x -20x -  -  -  -  -  -  -  -  -  -21x -21x -  -  -21x -20x -20x -20x -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -640x -17x -  -623x -  -  -  -  -  -  -  -79x -  -  -  -  -  -  -  -74x -  -  -  -  -  -  -  -91x -  -  -  - 
// tslint:disable-next-line:no-var-requires
-const debug = require("debug").debug("Command");
- 
-import Client, {
-    CommandAlreadyExecutedError,
-} from "../client";
- 
-/**
- * The potential states that a command can have.
- * When a command is created, the state is "initial"
- * When the execution has started, the status is "running"
- * When the execution has finsihed, the status can be "succes" or "failed"
- */
-export enum CommandStatus {
-    /**
-     * When a command is created, the state is "initial"
-     */
-    initial = "initial",
-    /**
-     * When the execution has started, the status is "running"
-     */
-    running = "running",
-    /**
-     * After successful  execution of the command, the status is "success"
-     */
-    success = "success",
-    /**
-     * After unsuccessfull execution of the command, the status is "failed"
-     */
-    failed = "failed",
-}
- 
-/**
- * when the command has finished, the client can get the result of the command execution
- */
-export interface CommandResultMetaData {
-    errors: string[],
-    messages: string[],
-    timeElapsed: number,
-}
- 
-/**
- * The command class represents a potential long running activity.
- * This activity has been wrapped into an object to ease the tracking of the processing state.
- * Create a command with  receiver information, execute the command and check the status and progress.
- * Check the result when finsished.
- */
-export default abstract class Command {
-    protected client: Client;
-    protected status: CommandStatus;
-    protected percentCompleted: number;
-    protected resultMetaData: CommandResultMetaData;
- 
-    constructor(client: Client) {
-        this.client = client;
-        this.status = CommandStatus.initial;
-        this.percentCompleted = 0;
-        this.resultMetaData = { messages: [], errors: [], timeElapsed: 0 };
-    }
- 
-    /**
-     * final execute the command
-     * @async
-     * @final
-     * @returns {Promise<void>}
-     */
-    public async execute(): Promise<void> {
-        debug("execute Command = " + this.constructor.name, this.status);
-        Iif (this.isFinished()) {
-            throw new CommandAlreadyExecutedError("Error: Command has already been executed. Command = " + this.constructor.name);
-        }
-        if (this.status === CommandStatus.initial) {
-            const startTime = new Date();
-            await this.onExecute();
-            this.resultMetaData.timeElapsed = new Date().getTime() - startTime.getTime();
-        }
-        // do nothing if already running
-    }
- 
-    /**
-     * execute the command
-     * @async
-     * @returns {Promise<void>}
-     */
-    protected abstract async onExecute(): Promise<void>;
- 
-    /**
-     * returns true, if the command has been finished
-     * @returns {boolean}
-     */
-    public isFinished(): boolean {
-        if (this.status === CommandStatus.failed || this.status === CommandStatus.success) {
-            return true;
-        }
-        return false;
-    }
- 
-    /**
-     * returns the status of the command
-     * @returns {CommandStatus}
-     */
-    public getStatus(): CommandStatus {
-        return this.status;
-    }
- 
-    /**
-     * returns the completion percentage of the command
-     * @returns {number} percentage of completion
-     */
-    public getPercentCompleted(): number {
-        return this.percentCompleted;
-    }
- 
-    /**
-     * returns the result meta data of the command
-     * @returns {null|any} the result of the command
-     */
-    public getResultMetaData(): CommandResultMetaData {
-        return this.resultMetaData;
-    }
- 
-}
- 
- -
-
- - - - - - - - - \ No newline at end of file diff --git a/docs/coverage/lcov-report/src/command/downloadFolderCommand.ts.html b/docs/coverage/lcov-report/src/command/downloadFolderCommand.ts.html deleted file mode 100644 index 777bbff3..00000000 --- a/docs/coverage/lcov-report/src/command/downloadFolderCommand.ts.html +++ /dev/null @@ -1,428 +0,0 @@ - - - - - - Code coverage report for src/command/downloadFolderCommand.ts - - - - - - - - - -
-
-

All files / src/command downloadFolderCommand.ts

-
- -
- 76.09% - Statements - 35/46 -
- - -
- 50% - Branches - 1/2 -
- - -
- 100% - Functions - 6/6 -
- - -
- 74.42% - Lines - 32/43 -
- - -
-

- Press n or j to go to the next uncovered block, b, p or k for the previous block. -

-
-
-

-
1 -2 -3 -4 -5 -6 -7 -8 -9 -10 -11 -12 -13 -14 -15 -16 -17 -18 -19 -20 -21 -22 -23 -24 -25 -26 -27 -28 -29 -30 -31 -32 -33 -34 -35 -36 -37 -38 -39 -40 -41 -42 -43 -44 -45 -46 -47 -48 -49 -50 -51 -52 -53 -54 -55 -56 -57 -58 -59 -60 -61 -62 -63 -64 -65 -66 -67 -68 -69 -70 -71 -72 -73 -74 -75 -76 -77 -78 -79 -80 -81 -82 -83 -84 -85 -86 -87 -88 -89 -90 -91 -92 -93 -94 -95 -96 -97 -98 -99 -100 -101 -102 -103 -104 -105 -106 -107 -108 -109 -110 -111 -112 -113 -114 -115 -116 -117  -1x -  -1x -  -  -  -  -  -  -  -1x -1x -1x -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -1x -  -  -  -  -  -  -  -  -  -  -1x -1x -1x -1x -1x -  -  -  -  -  -  -  -  -1x -1x -1x -1x -  -  -  -  -1x -  -1x -  -  -1x -  -4x -4x -  -1x -1x -  -1x -1x -1x -  -  -1x -  -  -  -  -  -  -  -  -1x -  -  -  -  -  -1x -1x -  -  -1x -  -1x -  -  -  -1x -  -  -  - 
// tslint:disable-next-line:no-var-requires
-const debug = require("debug").debug("DownloadFilesCommand");
- 
-import Client,
-{
-    File,
-    Folder,
-    SourceTargetFileNames,
-    CommandStatus,
-    GetFilesRecursivelyCommand,
-} from "../client";
-import util from "util";
-import fs from "fs";
-import Command from "./command";
-/**
- * options to create a download folder command
- */
-export interface DownloadFolderCommandOptions {
-    /**
-     * The source folder with the file structure to be downloaded
-     */
-    sourceFolder: Folder;
-    /**
-     * function to filter files
-     */
-    filterFile?: (file: File) => File | null;
-    /**
-     * the function to determine the target file name having the sourece file name.
-     * If the file should not be downloaded, return an empty string
-     * @param {SourceTargetFileNames} fileNames source and target file names
-     */
-    getTargetFileNameBeforeDownload: (fileNames: SourceTargetFileNames) => string;
-}
- 
-/**
- * Command to download the contents of a folder from nextcloud to local file system recursively
- */
-export default class DownloadFolderCommand extends Command {
-    private sourceFolder: Folder;
-    private getTargetFileNameBeforeDownload: (fileNames: SourceTargetFileNames) => string;
-    private bytesDownloaded: number;
-    private filterFile?: (file: File) => File | null;
- 
-    /**
-     * @param {Client} client the client
-     * @param {DownloadFolderCommandOptions} options constructor options
-     */
-    constructor(client: Client, options: DownloadFolderCommandOptions) {
-        super(client);
-        this.sourceFolder = options.sourceFolder;
-        this.getTargetFileNameBeforeDownload = options.getTargetFileNameBeforeDownload;
-        this.filterFile = options.filterFile;
-        this.bytesDownloaded = 0;
-    }
- 
-    /**
-     * execute the command
-     * @async
-     * @returns {Promise<void>}
-     */
-    protected async onExecute(): Promise<void> {
-        this.status = CommandStatus.running;
-        const writeFile = util.promisify(fs.writeFile);
-        const mkdir = util.promisify(fs.mkdir);
-        try {
- 
-            // determine all files to download
-            // it is assumed that this command will use 20% of the time
-            const command: GetFilesRecursivelyCommand =
-                new GetFilesRecursivelyCommand(this.client,
-                    { sourceFolder: this.sourceFolder, filterFile: this.filterFile });
-            command.execute();
- 
-            // check the processing status as long as the command is running
-            while (command.isFinished() !== true) {
-                // wait a bit
-                this.percentCompleted = command.getPercentCompleted() / 5;  // 20%
-                await (async () => { return new Promise(resolve => setTimeout(resolve, 100)) })();
-            }
-            this.resultMetaData.messages.concat(command.getResultMetaData().messages);
-            this.resultMetaData.errors.concat(command.getResultMetaData().errors);
- 
-            const files: File[] = command.getFiles();
-            let bytesToDownload: number = 0;
-            for (const file of files) {
-                bytesToDownload += file.size;
-            }
-            for (const file of files) {
-                const targetFileName = this.getTargetFileNameBeforeDownload({ sourceFileName: file.name, targetFileName: "." + file.name });
-                const content: Buffer = await file.getContent();
-                const path: string = targetFileName.substring(0, targetFileName.lastIndexOf("/"));
-                await mkdir(path, { recursive: true });
-                await writeFile(targetFileName, content);
-                this.bytesDownloaded += file.size;
-                this.percentCompleted = (this.bytesDownloaded / bytesToDownload * 80) + 20;
-            }
-            this.resultMetaData.messages.push(files.length + " files downloaded");
- 
-        } catch (e) {
-            debug(e.message);
-            this.resultMetaData.errors.push(e.message);
-        }
-        this.percentCompleted = 100;
-        Iif (this.resultMetaData.errors.length > 0) {
-            this.status = CommandStatus.failed;
-        } else {
-            this.status = CommandStatus.success;
-        }
-        return;
-    };
- 
-    public getBytesDownloaded(): number {
-        return this.bytesDownloaded;
-    }
- 
-}
- 
- -
-
- - - - - - - - - \ No newline at end of file diff --git a/docs/coverage/lcov-report/src/command/getFilesRecursivelyCommand.ts.html b/docs/coverage/lcov-report/src/command/getFilesRecursivelyCommand.ts.html deleted file mode 100644 index 877bf5ad..00000000 --- a/docs/coverage/lcov-report/src/command/getFilesRecursivelyCommand.ts.html +++ /dev/null @@ -1,368 +0,0 @@ - - - - - - Code coverage report for src/command/getFilesRecursivelyCommand.ts - - - - - - - - - -
-
-

All files / src/command getFilesRecursivelyCommand.ts

-
- -
- 93.75% - Statements - 30/32 -
- - -
- 75% - Branches - 3/4 -
- - -
- 100% - Functions - 4/4 -
- - -
- 93.75% - Lines - 30/32 -
- - -
-

- Press n or j to go to the next uncovered block, b, p or k for the previous block. -

-
-
-

-
1 -2 -3 -4 -5 -6 -7 -8 -9 -10 -11 -12 -13 -14 -15 -16 -17 -18 -19 -20 -21 -22 -23 -24 -25 -26 -27 -28 -29 -30 -31 -32 -33 -34 -35 -36 -37 -38 -39 -40 -41 -42 -43 -44 -45 -46 -47 -48 -49 -50 -51 -52 -53 -54 -55 -56 -57 -58 -59 -60 -61 -62 -63 -64 -65 -66 -67 -68 -69 -70 -71 -72 -73 -74 -75 -76 -77 -78 -79 -80 -81 -82 -83 -84 -85 -86 -87 -88 -89 -90 -91 -92 -93 -94 -95 -96 -97  -1x -  -  -1x -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -1x -  -  -  -  -  -  -  -  -  -  -3x -3x -3x -3x -  -  -  -  -  -  -  -  -3x -3x -3x -3x -3x -  -2x -  -1x -1x -  -  -3x -3x -1x -  -2x -  -3x -3x -  -  -  -  -2x -  -  -  -  -  -  -  -  -  -  -  -3x -3x -2x -  -  -  -2x -2x -2x -  -2x -  -  -  -2x -  -  - 
// tslint:disable-next-line:no-var-requires
-const debug = require("debug").debug("GetFilesRecursivelyCommand");
- 
-import Client, { File, Folder, FolderGetFilesOptions } from "../client";
-import Command, { CommandStatus } from "./command";
- 
-export interface GetFilesRecursivelyCommandOptions {
-    /**
-     * the source nextcloud folder to start listing the files
-     */
-    sourceFolder: Folder;
-    /**
-     * function to filter files
-     */
-    filterFile?: (file: File) => File | null;
-}
- 
-/**
- * Command to get all files of a nextcloud folder recursively
- */
-export default class GetFilesRecursivelyCommand extends Command {
-    private sourceFolder: Folder;
-    private filterFile?: (file: File) => File | null;
-    private files: File[];
- 
-    /**
-     * @param {Client} client the client
-     * @param {SourceTargetFileNames[]} files the files to be uploaded
-     * @param {(file: File) => void} processAfterUpload callback function to process the uploaded file
-     */
-    constructor(client: Client, options: GetFilesRecursivelyCommandOptions) {
-        super(client);
-        this.sourceFolder = options.sourceFolder;
-        this.filterFile = options.filterFile;
-        this.files = [];
-    }
- 
-    /**
-     * execute the command
-     * @async
-     * @returns {Promise<void>}
-     */
-    protected async onExecute(): Promise<void> {
-        this.status = CommandStatus.running;
-        const startTime = new Date();
-        try {
-            this.percentCompleted = 0;
-            await this.processFolder(this.sourceFolder, 100);
-            // console.log("file count", this.files.length);
-            this.resultMetaData.messages.push(`${this.files.length} files found`);
-        } catch (e) {
-            debug(e.message);
-            this.resultMetaData.errors.push(e.message);
-        }
- 
-        this.percentCompleted = 100;
-        if (this.resultMetaData.errors.length > 0) {
-            this.status = CommandStatus.failed;
-        } else {
-            this.status = CommandStatus.success;
-        }
-        this.resultMetaData.timeElapsed = new Date().getTime() - startTime.getTime();
-        return;
-    };
- 
- 
-    public getFiles(): File[] {
-        return this.files;
-    }
- 
-    /**
-     * adds files of folder and processes subordinated folders
-     * @param {Folder} folder the folder to process
-     * @param {number} percentagethe percentage that is finished, when the function returns
-     */
-    private async processFolder(folder: Folder, percentage: number): Promise<void> {
-        // tslint:disable-next-line:no-console
-        // console.log(folder.name);
- 
-        const options: FolderGetFilesOptions = { filterFile: this.filterFile }
-        const folderFiles: File[] = await folder.getFiles(options);
-        for (const fi of folderFiles) {
-            this.files.push(fi);
-        }
- 
-        const subFolders: Folder[] = await folder.getSubFolders();
-        Eif (subFolders.length === 0) {
-            this.percentCompleted += percentage;
-        }
-        for (const subFolder of subFolders) {
-            // console.log("folder", subFolder.name);
-            await this.processFolder(subFolder, percentage / subFolders.length);
-        }
-        return;
-    }
-}
- 
- -
-
- - - - - - - - - \ No newline at end of file diff --git a/docs/coverage/lcov-report/src/command/index.html b/docs/coverage/lcov-report/src/command/index.html deleted file mode 100644 index b60acb85..00000000 --- a/docs/coverage/lcov-report/src/command/index.html +++ /dev/null @@ -1,171 +0,0 @@ - - - - - - Code coverage report for src/command - - - - - - - - - -
-
-

All files src/command

-
- -
- 92.11% - Statements - 175/190 -
- - -
- 89.29% - Branches - 25/28 -
- - -
- 96.3% - Functions - 26/27 -
- - -
- 91.8% - Lines - 168/183 -
- - -
-

- Press n or j to go to the next uncovered block, b, p or k for the previous block. -

-
-
-
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
FileStatementsBranchesFunctionsLines
command.ts -
-
96%24/2590%9/10100%7/796%24/25
downloadFolderCommand.ts -
-
76.09%35/4650%1/2100%6/674.42%32/43
getFilesRecursivelyCommand.ts -
-
93.75%30/3275%3/4100%4/493.75%30/32
uploadFilesCommand.ts -
-
100%41/41100%8/8100%3/3100%41/41
uploadFolderCommand.ts -
-
97.83%45/46100%4/485.71%6/797.62%41/42
-
-
-
- - - - - - - - - \ No newline at end of file diff --git a/docs/coverage/lcov-report/src/command/uploadFilesCommand.ts.html b/docs/coverage/lcov-report/src/command/uploadFilesCommand.ts.html deleted file mode 100644 index cd91fcae..00000000 --- a/docs/coverage/lcov-report/src/command/uploadFilesCommand.ts.html +++ /dev/null @@ -1,389 +0,0 @@ - - - - - - Code coverage report for src/command/uploadFilesCommand.ts - - - - - - - - - -
-
-

All files / src/command uploadFilesCommand.ts

-
- -
- 100% - Statements - 41/41 -
- - -
- 100% - Branches - 8/8 -
- - -
- 100% - Functions - 3/3 -
- - -
- 100% - Lines - 41/41 -
- - -
-

- Press n or j to go to the next uncovered block, b, p or k for the previous block. -

-
-
-

-
1 -2 -3 -4 -5 -6 -7 -8 -9 -10 -11 -12 -13 -14 -15 -16 -17 -18 -19 -20 -21 -22 -23 -24 -25 -26 -27 -28 -29 -30 -31 -32 -33 -34 -35 -36 -37 -38 -39 -40 -41 -42 -43 -44 -45 -46 -47 -48 -49 -50 -51 -52 -53 -54 -55 -56 -57 -58 -59 -60 -61 -62 -63 -64 -65 -66 -67 -68 -69 -70 -71 -72 -73 -74 -75 -76 -77 -78 -79 -80 -81 -82 -83 -84 -85 -86 -87 -88 -89 -90 -91 -92 -93 -94 -95 -96 -97 -98 -99 -100 -101 -102 -103 -104  -1x -  -  -1x -1x -1x -  -  -  -  -  -  -  -  -  -  -  -  -  -  -1x -  -  -  -  -  -  -  -  -  -  -10x -10x -10x -10x -  -  -  -  -  -  -  -  -10x -10x -10x -10x -  -10x -10x -1x -  -  -  -  -10x -  -74x -74x -74x -73x -73x -30x -30x -  -43x -43x -  -  -1x -  -  -74x -74x -74x -  -74x -2x -  -  -  -  -1x -1x -1x -  -10x -8x -  -2x -  -  -10x -  -10x -  -  -  -70x -  -  -  - 
// tslint:disable-next-line:no-var-requires
-const debug = require("debug").debug("UploadFilesCommand");
- 
-import Client, { File } from "../client";
-import Command, { CommandStatus } from "./command";
-import util from "util";
-import fs from "fs";
- 
-export interface SourceTargetFileNames {
-    sourceFileName: string;
-    targetFileName: string;
-}
- 
-export interface UploadFilesCommandOptions {
-    files: SourceTargetFileNames[];
-    processFileAfterUpload?: (file: File) => Promise<void>;
-}
- 
-/**
- * Command to upload a set or files from local file system to nextcloud
- */
-export default class UploadFilesCommand extends Command {
-    private files: SourceTargetFileNames[];
-    private processFileAfterUpload?: (file: File) => Promise<void>;
-    private bytesUploaded: number;
- 
-    /**
-     * @param {Client} client the client
-     * @param {SourceTargetFileNames[]} files the files to be uploaded
-     * @param {(file: File) => void} processAfterUpload callback function to process the uploaded file
-     */
-    constructor(client: Client, options: UploadFilesCommandOptions) {
-        super(client);
-        this.files = options.files;
-        this.bytesUploaded = 0;
-        this.processFileAfterUpload = options.processFileAfterUpload;
-    }
- 
-    /**
-     * execute the command
-     * @async
-     * @returns {Promise<void>}
-     */
-    protected async onExecute(): Promise<void> {
-        this.status = CommandStatus.running;
-        try {
-            const readfile = util.promisify(fs.readFile);
-            let countCompleted = 0;
- 
-            this.percentCompleted = 0;
-            if (this.files.length === 0) {
-                this.percentCompleted = 100;
-            }
- 
-            let newFile: File | null;
- 
-            for (const file of this.files) {
-                let data: Buffer;
-                newFile = null;
-                try {
-                    data = await readfile(file.sourceFileName);
-                    try {
-                        newFile = await this.client.createFile(file.targetFileName, data);
-                        this.resultMetaData.messages.push(`${file.targetFileName}`);
-                        this.bytesUploaded += data.length;
-                    } catch (e) {
-                        this.resultMetaData.errors.push(`${file.targetFileName}: ${e.message}`);
-                        debug(file.targetFileName, e);
-                    }
-                } catch (e) {
-                    this.resultMetaData.errors.push(`${file.targetFileName}: ${e.message}`);
-                }
- 
-                countCompleted++;
-                this.percentCompleted = Math.round(countCompleted / this.files.length * 100);
-                debug(" completed:" + this.percentCompleted + "%");
- 
-                if (newFile && this.processFileAfterUpload) {
-                    await this.processFileAfterUpload(newFile);
-                }
-            }
- 
-        } catch (e) {
-            debug(e.message);
-            this.resultMetaData.errors.push(e.message);
-            this.percentCompleted = 100;
-        }
-        if (this.resultMetaData.errors.length > 0) {
-            this.status = CommandStatus.failed;
-        } else {
-            this.status = CommandStatus.success;
-        }
- 
-        debug("execute finished", this.percentCompleted, this.status);
- 
-        return;
-    };
- 
-    public getBytesUploaded(): number {
-        return this.bytesUploaded;
-    }
- 
-}
- 
- -
-
- - - - - - - - - \ No newline at end of file diff --git a/docs/coverage/lcov-report/src/command/uploadFolderCommand.ts.html b/docs/coverage/lcov-report/src/command/uploadFolderCommand.ts.html deleted file mode 100644 index 5a943605..00000000 --- a/docs/coverage/lcov-report/src/command/uploadFolderCommand.ts.html +++ /dev/null @@ -1,413 +0,0 @@ - - - - - - Code coverage report for src/command/uploadFolderCommand.ts - - - - - - - - - -
-
-

All files / src/command uploadFolderCommand.ts

-
- -
- 97.83% - Statements - 45/46 -
- - -
- 100% - Branches - 4/4 -
- - -
- 85.71% - Functions - 6/7 -
- - -
- 97.62% - Lines - 41/42 -
- - -
-

- Press n or j to go to the next uncovered block, b, p or k for the previous block. -

-
-
-

-
1 -2 -3 -4 -5 -6 -7 -8 -9 -10 -11 -12 -13 -14 -15 -16 -17 -18 -19 -20 -21 -22 -23 -24 -25 -26 -27 -28 -29 -30 -31 -32 -33 -34 -35 -36 -37 -38 -39 -40 -41 -42 -43 -44 -45 -46 -47 -48 -49 -50 -51 -52 -53 -54 -55 -56 -57 -58 -59 -60 -61 -62 -63 -64 -65 -66 -67 -68 -69 -70 -71 -72 -73 -74 -75 -76 -77 -78 -79 -80 -81 -82 -83 -84 -85 -86 -87 -88 -89 -90 -91 -92 -93 -94 -95 -96 -97 -98 -99 -100 -101 -102 -103 -104 -105 -106 -107 -108 -109 -110 -111 -112  -1x -  -1x -  -  -  -  -  -  -  -  -1x -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -1x -  -  -  -  -  -  -  -  -  -  -  -6x -6x -6x -6x -4x -  -14x -  -6x -  -  -  -  -  -  -  -  -6x -6x -6x -6x -6x -  -1x -1x -1x -1x -1x -1x -  -  -5x -5x -70x -  -70x -56x -  -  -  -5x -5x -5x -  -  -5x -65x -65x -65x -65x -  -65x -  -  -5x -5x -5x -5x -5x -  -  -  -  -  -  - 
// tslint:disable-next-line:no-var-requires
-const debug = require("debug").debug("UploadFolderCommand");
- 
-import Client,
-{
-    File,
-    FileSystemFolder,
-    IFileNameFormats,
-    UploadFilesCommand,
-    UploadFilesCommandOptions,
-    SourceTargetFileNames,
-} from "../client";
-import Command, { CommandStatus } from "./command";
- 
-/**
- * options to create a upload folder command
- */
-export interface UploadFolderCommandOptions {
-    /**
-     * The name of the source folder with the file structure to be uploaded
-     */
-    folderName: string;
-    /**
-     * the function to determine the target file name having the sourece file name.
-     * If the file should not be uploaded, return an empty string
-     * @param {SourceTargetFileNames} fileNames
-     */
-    getTargetFileNameBeforeUpload?: (fileNames: SourceTargetFileNames) => string;
-    processFileAfterUpload?: (file: File) => Promise<void>;
-}
- 
-/**
- * Command to upload the contents of a folder from local file system to nextcloud recursively
- */
-export default class UploadFolderCommand extends Command {
-    private folderName: string;
-    private processFileAfterUpload?: (file: File) => Promise<void>;
-    private getTargetFileNameBeforeUpload: (fileNames: SourceTargetFileNames) => string;
-    private bytesUploaded: number;
- 
-    /**
-     * @param {Client} client the client
-     * @param {ISourceTargetFileNames[]} files the files to be uploaded
-     * @param {(file: File) => void} processAfterUpload callback function to process the uploaded file
-     */
-    constructor(client: Client, options: UploadFolderCommandOptions) {
-        super(client);
-        this.folderName = options.folderName;
-        this.processFileAfterUpload = options.processFileAfterUpload;
-        if (options.getTargetFileNameBeforeUpload) {
-            this.getTargetFileNameBeforeUpload = options.getTargetFileNameBeforeUpload;
-        } else {
-            this.getTargetFileNameBeforeUpload = (fileNames: SourceTargetFileNames): string => { return fileNames.targetFileName };
-        }
-        this.bytesUploaded = 0;
-    }
- 
-    /**
-     * execute the command
-     * @async
-     * @returns {Promise<void>}
-     */
-    protected async onExecute(): Promise<void> {
-        this.status = CommandStatus.running;
-        let fileNames: IFileNameFormats[] = [];
-        const fsf: FileSystemFolder = new FileSystemFolder(this.folderName);
-        try {
-            fileNames = await fsf.getFileNames();
-        } catch (e) {
-            this.resultMetaData.errors.push(e);
-            this.status = CommandStatus.failed;
-            this.percentCompleted = 100;
-            this.bytesUploaded = 0;
-            this.resultMetaData.timeElapsed = 0;
-            return;
-        }
- 
-        const files: SourceTargetFileNames[] = [];
-        for (const fileNameFormat of fileNames) {
-            const targetFileName = this.getTargetFileNameBeforeUpload({ sourceFileName: fileNameFormat.absolute, targetFileName: fileNameFormat.relative });
-            // add only files with a target name
-            if (targetFileName !== "") {
-                files.push({ sourceFileName: fileNameFormat.absolute, targetFileName });
-            }
-        }
- 
-        const options: UploadFilesCommandOptions = { files, processFileAfterUpload: this.processFileAfterUpload };
-        const uc: UploadFilesCommand = new UploadFilesCommand(this.client, options);
-        uc.execute();
- 
-        // check the processing status
-        while (uc.isFinished() !== true) {
-            this.status = uc.getStatus();
-            this.percentCompleted = uc.getPercentCompleted();
-            this.resultMetaData = uc.getResultMetaData();
-            this.bytesUploaded = uc.getBytesUploaded();
-            // wait one second
-            await (async () => { return new Promise(resolve => setTimeout(resolve, 1000)) })();
-        }
- 
-        this.status = uc.getStatus();
-        this.percentCompleted = uc.getPercentCompleted();
-        this.resultMetaData = uc.getResultMetaData();
-        this.bytesUploaded = uc.getBytesUploaded();
-        return;
-    };
-    public getBytesUploaded(): number {
-        return this.bytesUploaded;
-    }
- 
-}
- 
- -
-
- - - - - - - - - \ No newline at end of file diff --git a/docs/coverage/lcov-report/src/environment.ts.html b/docs/coverage/lcov-report/src/environment.ts.html deleted file mode 100644 index c03ff06b..00000000 --- a/docs/coverage/lcov-report/src/environment.ts.html +++ /dev/null @@ -1,206 +0,0 @@ - - - - - - Code coverage report for src/environment.ts - - - - - - - - - -
-
-

All files / src environment.ts

-
- -
- 100% - Statements - 15/15 -
- - -
- 100% - Branches - 15/15 -
- - -
- 100% - Functions - 5/5 -
- - -
- 100% - Lines - 15/15 -
- - -
-

- Press n or j to go to the next uncovered block, b, p or k for the previous block. -

-
-
-

-
1 -2 -3 -4 -5 -6 -7 -8 -9 -10 -11 -12 -13 -14 -15 -16 -17 -18 -19 -20 -21 -22 -23 -24 -25 -26 -27 -28 -29 -30 -31 -32 -33 -34 -35 -36 -37 -38 -39 -40 -41 -42 -431x -  -1x -  -  -17x -  -  -  -172x -2x -  -  -170x -  -  -  -171x -1x -  -  -170x -  -  -  -171x -1x -  -  -170x -  -  -  -169x -  -  -168x -  -1x -  -  -  - 
import ClientError from "./error";
- 
-export default class Environment {
- 
-    public static getMinLogLevel(): string {
-        return process.env.MIN_LOG_LEVEL || "error";
-    }
- 
-    public static getNextcloudUrl(): string {
-        if (!process.env.NEXTCLOUD_URL) {
-            throw new ClientError("NCEnvironment: NEXTCLOUD_URL not defined in environment"
-                , "ERR_NEXTCLOUD_URL_NOT_DEFINED");
-        }
-        return process.env.NEXTCLOUD_URL;
-    }
- 
-    public static getUserName(): string {
-        if (!process.env.NEXTCLOUD_USERNAME) {
-            throw new ClientError("NCEnvironment: NEXTCLOUD_USERNAME not defined in environment"
-                , "ERR_NEXTCLOUD_USERNAME_NOT_DEFINED");
-        }
-        return process.env.NEXTCLOUD_USERNAME;
-    }
- 
-    public static getPassword(): string {
-        if (!process.env.NEXTCLOUD_PASSWORD) {
-            throw new ClientError("NCEnvironment: NEXTCLOUD_PASSWORD not defined in environment"
-                , "ERR_NEXTCLOUD_PASSWORD_NOT_DEFINED");
-        }
-        return process.env.NEXTCLOUD_PASSWORD;
-    }
- 
-    public static getRecordingActiveIndicator(): boolean {
-        if ((process.env.TEST_RECORDING_ACTIVE &&
-            (process.env.TEST_RECORDING_ACTIVE === "0" || process.env.TEST_RECORDING_ACTIVE === "false" || process.env.TEST_RECORDING_ACTIVE === "inactive")) ||
-            !process.env.TEST_RECORDING_ACTIVE) {
-            return false;
-        } else {
-            return true;
-        }
-    }
-}
- 
- -
-
- - - - - - - - - \ No newline at end of file diff --git a/docs/coverage/lcov-report/src/environmentVcapServices.ts.html b/docs/coverage/lcov-report/src/environmentVcapServices.ts.html deleted file mode 100644 index c26abfa3..00000000 --- a/docs/coverage/lcov-report/src/environmentVcapServices.ts.html +++ /dev/null @@ -1,302 +0,0 @@ - - - - - - Code coverage report for src/environmentVcapServices.ts - - - - - - - - - -
-
-

All files / src environmentVcapServices.ts

-
- -
- 100% - Statements - 24/24 -
- - -
- 100% - Branches - 15/15 -
- - -
- 100% - Functions - 2/2 -
- - -
- 100% - Lines - 24/24 -
- - -
-

- Press n or j to go to the next uncovered block, b, p or k for the previous block. -

-
-
-

-
1 -2 -3 -4 -5 -6 -7 -8 -9 -10 -11 -12 -13 -14 -15 -16 -17 -18 -19 -20 -21 -22 -23 -24 -25 -26 -27 -28 -29 -30 -31 -32 -33 -34 -35 -36 -37 -38 -39 -40 -41 -42 -43 -44 -45 -46 -47 -48 -49 -50 -51 -52 -53 -54 -55 -56 -57 -58 -59 -60 -61 -62 -63 -64 -65 -66 -67 -68 -69 -70 -71 -72 -73 -74 -75  -1x -  -1x -1x -1x -  -1x -1x -  -  -  -  -  -  -  -1x -  -  -  -  -  -  -12x -2x -  -  -10x -10x -  -10x -5x -5x -  -  -5x -1x -  -  -  -  -4x -1x -  -  -  -  -3x -1x -  -  -  -  -2x -2x -2x -  -  -  -  -  -  -  -  -  -2x -  -  -  -  -  -  -  -  - 
// tslint:disable-next-line:no-var-requires
-require("dotenv").config();
- 
-import ClientError from "./error";
-import Server from "./server";
-export { Server };
- 
-import Logger from "./logger";
-const log: Logger = new Logger();
- 
- 
-/**
- * returns the nextcloud credentials that is defined in the
- * "user-provided" service section of the VCAP_SERVICES environment
- * instanceName: the name of the nextcloud user provided service instance
- */
-export default class EnvironmentVcapServices {
-    public readonly url: string;
-    public readonly userName: string;
-    public readonly password: string;
- 
-    public constructor(instanceName: string) {
- 
-        if (!process.env.VCAP_SERVICES) {
-            throw new ClientError("NCEnvironmentVcapServices: environment VCAP_SERVICES not found", "ERR_VCAP_SERVICES_NOT_FOUND");
-        }
- 
-        const vcapServices = require("vcap_services");
-        const cred = vcapServices.getCredentials("user-provided", undefined, instanceName);
- 
-        if (!cred || cred === undefined || (!cred.url && !cred.username && !cred.password)) {
-            log.error("NCEnvironmentVcapServices: error credentials not found or not fully specified ", cred);
-            throw new ClientError(`NCEnvironmentVcapServices: nextcloud credentials not found in environment VCAP_SERVICES. Service section: "user-provided", service instance name: "${instanceName}" `, "ERR_VCAP_SERVICES_NOT_FOUND");
-        }
- 
-        if (!cred.url) {
-            throw new ClientError("NCEnvironmentVcapServices: VCAP_SERVICES url not defined in user provided services for nextcloud"
-                , "ERR_VCAP_SERVICES_URL_NOT_DEFINED",
-                { credentials: cred });
-        }
- 
-        if (!cred.password) {
-            throw new ClientError("NCEnvironmentVcapServices: VCAP_SERVICES password not defined in user provided services for nextcloud",
-                "ERR_VCAP_SERVICES_PASSWORD_NOT_DEFINED",
-                { credentials: cred });
-        }
- 
-        if (!cred.username) {
-            throw new ClientError("NCEnvironmentVcapServices: VCAP_SERVICES username not defined in user provided services for nextcloud",
-                "ERR_VCAP_SERVICES_USERNAME_NOT_DEFINED",
-                { credentials: cred });
-        }
- 
-        this.url = cred.url as string;
-        this.userName = cred.username as string;
-        this.password = cred.password as string;
-    }
- 
-    /**
-     * returns the nextcloud credentials that is defined in the
-     * "user-provided" service section of the VCAP_SERVICES environment
-     * @param instanceName the name of the nextcloud user provided service instance
-     * @returns credentials from the VCAP_SERVICES environment (user provided service)
-     */
-    public getServer(): Server {
-        return new Server({
-            basicAuth: {
-                password: this.password,
-                username: this.userName,
-            },
-            url: this.url,
-        });
-    }
-}
- 
- -
-
- - - - - - - - - \ No newline at end of file diff --git a/docs/coverage/lcov-report/src/error.ts.html b/docs/coverage/lcov-report/src/error.ts.html deleted file mode 100644 index d864e539..00000000 --- a/docs/coverage/lcov-report/src/error.ts.html +++ /dev/null @@ -1,353 +0,0 @@ - - - - - - Code coverage report for src/error.ts - - - - - - - - - -
-
-

All files / src error.ts

-
- -
- 100% - Statements - 21/21 -
- - -
- 100% - Branches - 0/0 -
- - -
- 100% - Functions - 2/2 -
- - -
- 100% - Lines - 21/21 -
- - -
-

- Press n or j to go to the next uncovered block, b, p or k for the previous block. -

-
-
-

-
1 -2 -3 -4 -5 -6 -7 -8 -9 -10 -11 -12 -13 -14 -15 -16 -17 -18 -19 -20 -21 -22 -23 -24 -25 -26 -27 -28 -29 -30 -31 -32 -33 -34 -35 -36 -37 -38 -39 -40 -41 -42 -43 -44 -45 -46 -47 -48 -49 -50 -51 -52 -53 -54 -55 -56 -57 -58 -59 -60 -61 -62 -63 -64 -65 -66 -67 -68 -69 -70 -71 -72 -73 -74 -75 -76 -77 -78 -79 -80 -81 -82 -83 -84 -85 -86 -87 -88 -89 -90 -91 -92  -1x -  -  -  -  -306x -306x -306x -  -  -  -  -1x -  -  -  -92x -92x -  -  -  -  -  -  -  -1x -  -  -  -  -1x -  -  -  -  -1x -  -  -  -  -1x -  -  -  -  -1x -  -  -  -  -1x -  -  -  -  -1x -  -  -  -  -1x -  -  -  -  -1x -  -  -  -  -1x -  -  -  -  -1x -  -  -  -  -1x -  -  -  -  -1x -  -  -  -  -1x
// tslint:disable:max-classes-per-file
-export default class ClientError extends Error {
-    public code: string;
-    private context?: any;
- 
-    constructor(m: string, code: string, context?: any) {
-        super(m);
-        this.code = code;
-        this.context = context;
-    }
-}
- 
-// tslint:disable-next-line:max-classes-per-file
-export class BaseError extends Error {
-    private context?: any;
- 
-    constructor(m: string, context?: any) {
-        super(m);
-        this.context = context;
-    }
-}
- 
- 
-/**
- * the query limit parameter must be a number larger than 0
- */
-export class QueryLimitError extends BaseError { };
- 
-/**
- * the query offset parameter must be a number larger than 0
- */
-export class QueryOffsetError extends BaseError { };
- 
-/**
- * user group already exists
- */
-export class UserGroupAlreadyExistsError extends BaseError { };
- 
-/**
- * user group does not exist
- */
-export class UserGroupDoesNotExistError extends BaseError { };
- 
-/**
- * user group cloud not be deleted
- */
-export class UserGroupDeletionFailedError extends BaseError { };
- 
-/**
- * user not found
- */
-export class UserNotFoundError extends BaseError { };
- 
-/**
- * user already exists
- */
-export class UserAlreadyExistsError extends BaseError { };
- 
-/**
- * error creating user
- */
-export class UserCreateError extends BaseError { };
- 
-/**
- * error updating user
- */
-export class UserUpdateError extends BaseError { };
- 
-/**
- * Error sending user welcome email
- */
-export class UserResendWelcomeEmailError extends BaseError { };
- 
-/**
- * the service response is invalid
- */
-export class InvalidServiceResponseFormatError extends BaseError { };
- 
-/**
- * the service response is invalid
- */
-export class InsufficientPrivilegesError extends BaseError { };
- 
-/**
- * operation failed
- */
-export class OperationFailedError extends BaseError { };
- 
-/**
- * the command is already executed
- */
-export class CommandAlreadyExecutedError extends BaseError { };
- -
-
- - - - - - - - - \ No newline at end of file diff --git a/docs/coverage/lcov-report/src/fakeServer.ts.html b/docs/coverage/lcov-report/src/fakeServer.ts.html deleted file mode 100644 index 6d51bfa1..00000000 --- a/docs/coverage/lcov-report/src/fakeServer.ts.html +++ /dev/null @@ -1,233 +0,0 @@ - - - - - - Code coverage report for src/fakeServer.ts - - - - - - - - - -
-
-

All files / src fakeServer.ts

-
- -
- 96.3% - Statements - 26/27 -
- - -
- 90% - Branches - 9/10 -
- - -
- 100% - Functions - 2/2 -
- - -
- 96.3% - Lines - 26/27 -
- - -
-

- Press n or j to go to the next uncovered block, b, p or k for the previous block. -

-
-
-

-
1 -2 -3 -4 -5 -6 -7 -8 -9 -10 -11 -12 -13 -14 -15 -16 -17 -18 -19 -20 -21 -22 -23 -24 -25 -26 -27 -28 -29 -30 -31 -32 -33 -34 -35 -36 -37 -38 -39 -40 -41 -42 -43 -44 -45 -46 -47 -48 -49 -50 -51 -521x -  -  -  -  -  -  -1x -1x -  -1x -62x -  -62x -  -  -111x -111x -2x -  -  -111x -111x -3x -  -108x -  -  -  -108x -  -108x -106x -  -  -108x -  -  -  -108x -7x -7x -7x -7x -7x -7x -7x -  -101x -  -  - 
import {
-    RequestInit,
-    Response,
-    ResponseInit,
-} from "node-fetch";
-import { IRequestContext } from "./httpClient";
-import RequestResponseLogEntry from "./requestResponseLogEntry";
-import Logger from "./logger";
-const log: Logger = new Logger();
- 
-export default class FakeServer {
-    public fakeResponses: RequestResponseLogEntry[] = [];
-    public constructor(fakeResponses: RequestResponseLogEntry[]) {
-        this.fakeResponses = fakeResponses;
-    }
-    public async getFakeHttpResponse(url: string, requestInit: RequestInit, expectedHttpStatusCode: number[], context: IRequestContext): Promise<Response> {
-        log.debug("getFakeHttpResponse");
-        if (!requestInit.method) {
-            requestInit.method = "UNDEFINED";
-        }
- 
-        const rrEntry: RequestResponseLogEntry | undefined = this.fakeResponses.shift();
-        if (!rrEntry) {
-            throw new Error(`error providing fake http response. No fake response available`);
-        }
-        const responseInit: ResponseInit = {
-            status: rrEntry.response.status,
-        };
- 
-        const response: Response = new Response(rrEntry.response.body, responseInit);
- 
-        if (rrEntry.response.contentType) {
-            response.headers.append("Content-Type", rrEntry.response.contentType);
-        }
- 
-        Iif (rrEntry.response.contentLocation) {
-            response.headers.append("Content-Location", rrEntry.response.contentLocation);
-        }
- 
-        if (expectedHttpStatusCode.indexOf(response.status) === -1) {
-            log.debug("getHttpResponse unexpected status response ", response.status + " " + response.statusText);
-            log.debug("getHttpResponse description ", context.description);
-            log.debug("getHttpResponse expected ", expectedHttpStatusCode.join(","));
-            log.debug("getHttpResponse headers ", JSON.stringify(response.headers, null, 4));
-            log.debug("getHttpResponse request body ", requestInit.body);
-            log.debug("getHttpResponse text ", await response.text());
-            throw new Error(`HTTP response status ${response.status} not expected. Expected status: ${expectedHttpStatusCode.join(",")} - status text: ${response.statusText}`);
-        }
-        return response;
-    }
-}
- 
- -
-
- - - - - - - - - \ No newline at end of file diff --git a/docs/coverage/lcov-report/src/file.ts.html b/docs/coverage/lcov-report/src/file.ts.html deleted file mode 100644 index 4516e7ce..00000000 --- a/docs/coverage/lcov-report/src/file.ts.html +++ /dev/null @@ -1,728 +0,0 @@ - - - - - - Code coverage report for src/file.ts - - - - - - - - - -
-
-

All files / src file.ts

-
- -
- 78.95% - Statements - 45/57 -
- - -
- 50% - Branches - 3/6 -
- - -
- 89.47% - Functions - 17/19 -
- - -
- 78.95% - Lines - 45/57 -
- - -
-

- Press n or j to go to the next uncovered block, b, p or k for the previous block. -

-
-
-

-
1 -2 -3 -4 -5 -6 -7 -8 -9 -10 -11 -12 -13 -14 -15 -16 -17 -18 -19 -20 -21 -22 -23 -24 -25 -26 -27 -28 -29 -30 -31 -32 -33 -34 -35 -36 -37 -38 -39 -40 -41 -42 -43 -44 -45 -46 -47 -48 -49 -50 -51 -52 -53 -54 -55 -56 -57 -58 -59 -60 -61 -62 -63 -64 -65 -66 -67 -68 -69 -70 -71 -72 -73 -74 -75 -76 -77 -78 -79 -80 -81 -82 -83 -84 -85 -86 -87 -88 -89 -90 -91 -92 -93 -94 -95 -96 -97 -98 -99 -100 -101 -102 -103 -104 -105 -106 -107 -108 -109 -110 -111 -112 -113 -114 -115 -116 -117 -118 -119 -120 -121 -122 -123 -124 -125 -126 -127 -128 -129 -130 -131 -132 -133 -134 -135 -136 -137 -138 -139 -140 -141 -142 -143 -144 -145 -146 -147 -148 -149 -150 -151 -152 -153 -154 -155 -156 -157 -158 -159 -160 -161 -162 -163 -164 -165 -166 -167 -168 -169 -170 -171 -172 -173 -174 -175 -176 -177 -178 -179 -180 -181 -182 -183 -184 -185 -186 -187 -188 -189 -190 -191 -192 -193 -194 -195 -196 -197 -198 -199 -200 -201 -202 -203 -204 -205 -206 -207 -208 -209 -210 -211 -212 -213 -214 -215 -216 -2171x -1x -  -  -  -  -  -  -  -1x -  -  -  -  -  -  -  -  -  -  -  -70x -  -  -  -  -  -  -  -  -70x -  -  -  -  -  -  -24x -23x -  -  -  -  -  -  -  -3x -2x -  -  -  -  -  -  -  -2x -1x -  -  -  -  -  -  -  -2x -1x -  -  -  -  -  -  -2x -1x -  -  -  -  -  -  -19x -17x -  -  -  -  -  -  -  -8x -8x -  -  -  -  -  -  -  -  -1x -1x -  -1x -  -  -1x -  -  -  -  -  -  -  -  -  -2x -1x -1x -1x -1x -1x -1x -1x -  -  -  -  -  -  -  -2x -2x -  -  -  -  -  -  -  -3x -3x -  -  -  -  -  -  -  -1x -1x -  -  -  -  -  -  -  -8x -8x -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -4x -4x -  -  -  -  -  -  -  -  -  -  -1x -1x -  -  -  -74x -8x -  -  -  - 
import path from "path";
-import Client, { ClientError } from "./client";
-import FileSystemElement from "./fileSystemElement";
-import Folder from "./folder";
- 
-/**
- * The file class represents a file in nextcloud.
- * It exposes file properties and content handling, commenting and tagging
- */
-export default class File implements FileSystemElement {
-    private memento: {
-        baseName: string,
-        id: number,
-        deleted: boolean,
-        lastmod: Date,
-        mime: string,
-        name: string,
-        size: number,
-    };
-    private client: Client;
-    constructor(client: Client, name: string, baseName: string, lastmod: string, size: number, mime: string, id: number) {
-        this.memento = {
-            baseName,
-            deleted: false,
-            id,
-            lastmod: new Date(lastmod),
-            mime,
-            name,
-            size,
-        };
-        this.client = client;
-    }
-    /**
-     * The name of the file including the path
-     * The name is readonly
-     */
-    get name(): string {
-        this.assertExistence();
-        return this.memento.name;
-    }
- 
-    /**
-     * The base name of the file (file name without path)
-     * The base name is readonly
-     */
-    get baseName(): string {
-        this.assertExistence();
-        return this.memento.baseName;
-    }
- 
-    /**
-     * The timestamp of the last file change
-     * readonly
-     */
-    get lastmod(): Date {
-        this.assertExistence();
-        return this.memento.lastmod;
-    }
- 
-    /**
-     * The file size in bytes
-     * readonly
-     */
-    get size(): number {
-        this.assertExistence();
-        return this.memento.size;
-    }
- 
-    /**
-     * The mime type (content type) of the file
-     */
-    get mime(): string {
-        this.assertExistence();
-        return this.memento.mime;
-    }
- 
-    /**
-     * The unique id of the file.
-     */
-    get id(): number {
-        this.assertExistence();
-        return this.memento.id;
-    }
- 
-    /**
-     * deletes a file
-     * @throws Error
-     */
-    public async delete(): Promise<void> {
-        this.memento.deleted = true;
-        return await this.client.deleteFile(this.memento.name);
-    }
- 
-    /**
-     * get folder of the file
-     * @throws ClientError
-     * @returns the parent folder
-     */
-    public async getFolder(): Promise<Folder> {
-        this.assertExistence();
-        const folder: Folder | null = await this.client.getFolder(path.dirname((this.memento.name)));
- 
-        Iif (folder) {
-            return folder;
-        }
-        throw new ClientError("Error, the folder of the file does not exist anymore", "ERR_FILE_FOLDER_DOES_NOT_EXIST");
-    }
- 
-    /**
-     * moves or renames the current file to the new location
-     * target folder must exists
-     * @param targetFileName the name of the target file /f1/f2/myfile.txt
-     * @throws Error
-     */
-    public async move(targetFileName: string): Promise<File> {
-        this.assertExistence();
-        const file: File = await this.client.moveFile(this.name, targetFileName);
-        this.memento.name = file.name;
-        this.memento.baseName = file.baseName;
-        this.memento.lastmod = file.lastmod;
-        this.memento.mime = file.mime;
-        this.memento.size = file.size;
-        return this;
-    }
- 
-    /**
-     * @returns the buffer of the file content
-     * @throws Error
-     */
-    public async getContent(): Promise<Buffer> {
-        this.assertExistence();
-        return this.client.getContent(this.name);
-    }
- 
-    /**
-     * @returns the url of the file
-     * @throws Error
-     */
-    public getUrl(): string {
-        this.assertExistence();
-        return this.client.getLink(this.name);
-    }
- 
-    /**
-     * @returns the url of the file in the UI
-     * @throws Error
-     */
-    public getUIUrl(): string {
-        this.assertExistence();
-        return this.client.getUILink(this.id);
-    }
- 
-    /**
-     * adds a tag name to the file
-     * @param tagName name of the tag
-     */
-    public async addTag(tagName: string): Promise<void> {
-        this.assertExistence();
-        return this.client.addTagToFile(this.id, tagName);
-    }
- 
-    /**
-     * get tag names
-     * @returns array of tag names
-     */
-    public async getTags(): Promise<string[]> {
-        this.assertExistence();
-        const map: Map<string, number> = await this.client.getTagsOfFile(this.id);
-        const tagNames: string[] = [];
-        for (const tagName of map) {
-            tagNames.push(tagName[0]);
-        }
-        return tagNames;
-    }
- 
-    /**
-     * removes a tag of the file
-     * @param tagName the name of the tag
-     */
-    public async removeTag(tagName: string): Promise<void> {
-        this.assertExistence();
-        const map: Map<string, number> = await this.client.getTagsOfFile(this.id);
- 
-        const tagId: number | undefined = map.get(tagName);
-        if (tagId) {
-            await this.client.removeTagOfFile(this.id, tagId);
-        }
-    }
- 
-    /**
-     * add comment to file
-     * @param comment the comment
-     */
-    public async addComment(comment: string): Promise<void> {
-        this.assertExistence();
-        return await this.client.addCommentToFile(this.id, comment);
-    }
- 
-    /**
-     * get list of comments of file
-     * @param top number of comments to return
-     * @param skip the offset
-     * @returns array of comment strings
-     * @throws Exception
-     */
-    public async getComments(top?: number, skip?: number): Promise<string[]> {
-        this.assertExistence();
-        return await this.client.getFileComments(this.id, top, skip);
-    }
- 
-    private assertExistence(): void {
-        if (this.memento.deleted) {
-            throw new ClientError("File does not exist", "ERR_FILE_NOT_EXISTING");
-        }
-    }
-}
- 
- -
-
- - - - - - - - - \ No newline at end of file diff --git a/docs/coverage/lcov-report/src/fileSizeFormatter.ts.html b/docs/coverage/lcov-report/src/fileSizeFormatter.ts.html deleted file mode 100644 index f9940f36..00000000 --- a/docs/coverage/lcov-report/src/fileSizeFormatter.ts.html +++ /dev/null @@ -1,179 +0,0 @@ - - - - - - Code coverage report for src/fileSizeFormatter.ts - - - - - - - - - -
-
-

All files / src fileSizeFormatter.ts

-
- -
- 100% - Statements - 18/18 -
- - -
- 100% - Branches - 6/6 -
- - -
- 100% - Functions - 2/2 -
- - -
- 100% - Lines - 18/18 -
- - -
-

- Press n or j to go to the next uncovered block, b, p or k for the previous block. -

-
-
-

-
1 -2 -3 -4 -5 -6 -7 -8 -9 -10 -11 -12 -13 -14 -15 -16 -17 -18 -19 -20 -21 -22 -23 -24 -25 -26 -27 -28 -29 -30 -31 -32 -33 -34  -1x -  -20x -20x -20x -  -  -20x -  -  -  -20x -20x -5x -5x -  -15x -6x -6x -  -9x -1x -1x -  -  -8x -  -20x -20x -  -  -  - 
 
-export default class FileSizeFormatter {
-    private bytes: number;
-    private oneKiloByte = 1024;
-    private oneMegaByte = this.oneKiloByte * 1024;
-    private oneGigaByte = this.oneMegaByte * 1024;
- 
-    constructor(bytes: number) {
-        this.bytes = bytes;
-    }
-    public getUserFriendlyFileSize(): string {
-        let suffix: string;
-        let size = this.bytes;
-        if (size > this.oneGigaByte) {
-            size /= this.oneGigaByte;
-            suffix = " GB";
-        }
-        else if (this.bytes > this.oneMegaByte) {
-            size /= this.oneMegaByte;
-            suffix = " MB";
-        }
-        else if (this.bytes > this.oneKiloByte) {
-            size /= this.oneKiloByte;
-            suffix = " kB";
-        }
-        else {
-            suffix = " B";
-        }
-        size = Math.round(size);
-        return size + suffix;
-    }
- 
-}
- 
- -
-
- - - - - - - - - \ No newline at end of file diff --git a/docs/coverage/lcov-report/src/fileSystemElement.ts.html b/docs/coverage/lcov-report/src/fileSystemElement.ts.html deleted file mode 100644 index d7d76fdb..00000000 --- a/docs/coverage/lcov-report/src/fileSystemElement.ts.html +++ /dev/null @@ -1,350 +0,0 @@ - - - - - - Code coverage report for src/fileSystemElement.ts - - - - - - - - - -
-
-

All files / src fileSystemElement.ts

-
- -
- 100% - Statements - 1/1 -
- - -
- 100% - Branches - 0/0 -
- - -
- 100% - Functions - 0/0 -
- - -
- 100% - Lines - 1/1 -
- - -
-

- Press n or j to go to the next uncovered block, b, p or k for the previous block. -

-
-
-

-
1 -2 -3 -4 -5 -6 -7 -8 -9 -10 -11 -12 -13 -14 -15 -16 -17 -18 -19 -20 -21 -22 -23 -24 -25 -26 -27 -28 -29 -30 -31 -32 -33 -34 -35 -36 -37 -38 -39 -40 -41 -42 -43 -44 -45 -46 -47 -48 -49 -50 -51 -52 -53 -54 -55 -56 -57 -58 -59 -60 -61 -62 -63 -64 -65 -66 -67 -68 -69 -70 -71 -72 -73 -74 -75 -76 -77 -78 -79 -80 -81 -82 -83 -84 -85 -86 -87 -88 -89 -90 -91  -  -  -  -  -  -1x -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  - 
import Client, { ClientError } from "./client";
- 
-/**
- * The file class represents a file in nextcloud.
- * It exposes file properties and content handling, commenting and tagging
- */
-export default abstract class FileSystemElement {
- 
-    /**
-     * The name of the file system element including the path
-     * The name is readonly
-     */
-    abstract get name(): string;
- 
-    /**
-     * The base name of the file system element (name without path)
-     * The base name is readonly
-     */
-    abstract get baseName(): string;
- 
-    /**
-     * The timestamp of the last file system element change
-     * readonly
-     */
-    abstract get lastmod(): Date;
- 
-    /**
-     * The unique id of the file system element.
-     */
-    abstract get id(): number;
- 
-    /**
-     * deletes a file system element
-     * @throws Error
-     */
-    public abstract async delete(): Promise<void>;
- 
-    /**
-     * moves or renames the current file system element to the new location
-     * target folder must exists
-     * @param targetFileName the name of the target file /f1/f2/myfile.txt
-     * @throws Error
-     */
-    public abstract async move(targetName: string): Promise<FileSystemElement>;
- 
-    /**
-     * @returns the url of the file sytsem element
-     * @throws Error
-     */
-    public abstract getUrl(): string;
- 
-    /**
-     * @returns the url of the file system element in the UI
-     * @throws Error
-     */
-    public abstract getUIUrl(): string;
- 
-    /**
-     * adds a tag name to the file system element
-     * @param tagName name of the tag
-     */
-    public abstract async addTag(tagName: string): Promise<void>;
- 
-    /**
-     * get tag names
-     * @returns array of tag names
-     */
-    public abstract async getTags(): Promise<string[]>;
- 
-    /**
-     * removes a tag of the file system element
-     * @param tagName the name of the tag
-     */
-    public abstract async removeTag(tagName: string): Promise<void>;
- 
-    /**
-     * add comment to file
-     * @param comment the comment
-     */
-    public abstract async addComment(comment: string): Promise<void>;
- 
-    /**
-     * get list of comments of file
-     * @param top number of comments to return
-     * @param skip the offset
-     * @returns array of comment strings
-     * @throws Exception
-     */
-    public abstract async getComments(top?: number, skip?: number): Promise<string[]>;
-}
- 
- -
-
- - - - - - - - - \ No newline at end of file diff --git a/docs/coverage/lcov-report/src/fileSystemFolder.ts.html b/docs/coverage/lcov-report/src/fileSystemFolder.ts.html deleted file mode 100644 index c0276fbb..00000000 --- a/docs/coverage/lcov-report/src/fileSystemFolder.ts.html +++ /dev/null @@ -1,209 +0,0 @@ - - - - - - Code coverage report for src/fileSystemFolder.ts - - - - - - - - - -
-
-

All files / src fileSystemFolder.ts

-
- -
- 100% - Statements - 19/19 -
- - -
- 100% - Branches - 2/2 -
- - -
- 100% - Functions - 7/7 -
- - -
- 100% - Lines - 17/17 -
- - -
-

- Press n or j to go to the next uncovered block, b, p or k for the previous block. -

-
-
-

-
1 -2 -3 -4 -5 -6 -7 -8 -9 -10 -11 -12 -13 -14 -15 -16 -17 -18 -19 -20 -21 -22 -23 -24 -25 -26 -27 -28 -29 -30 -31 -32 -33 -34 -35 -36 -37 -38 -39 -40 -41 -42 -43 -441x -1x -1x -  -1x -1x -  -  -  -  -  -  -1x -  -  -11x -  -  -  -290x -  -  -  -11x -  -11x -289x -  -10x -  -  -  -  -97x -375x -375x -375x -  -375x -  -  -  -  - 
import util from "util";
-import fs from "fs";
-import path from "path";
- 
-const readdir = util.promisify(fs.readdir);
-const stat = util.promisify(fs.stat);
- 
-export interface IFileNameFormats {
-    absolute: string;
-    relative: string;
-}
- 
-export default class FileSystemFolder {
-    private name: string;
-    constructor(name: string) {
-        this.name = name;
-    }
- 
-    public getName(): IFileNameFormats {
-        return { relative: this.name, absolute: path.resolve(this.name) };
-    }
- 
-    public async getFileNames(): Promise<IFileNameFormats[]> {
-        const fileNames: IFileNameFormats[] = [];
- 
-        for (const absoluteFileName of await this.getFileNamesRecursively(this.name)) {
-            fileNames.push({ absolute: absoluteFileName, relative: absoluteFileName.replace(path.resolve(this.getName().absolute), "").replace(/\\/g, "/") })
-        }
-        return (fileNames);
-    };
- 
-    private async getFileNamesRecursively(name: string): Promise<string[]> {
- 
-        const subdirs: string[] = await readdir(name);
-        const files = await Promise.all(subdirs.map(async (subdir: string) => {
-            const res: string = path.resolve(name, subdir);
-            return (await stat(res)).isDirectory() ? this.getFileNamesRecursively(res) : res;
-        }));
-        return files.reduce((a: any, f: any) => a.concat(f), []);
-    }
- 
- 
-}
- 
- -
-
- - - - - - - - - \ No newline at end of file diff --git a/docs/coverage/lcov-report/src/folder.ts.html b/docs/coverage/lcov-report/src/folder.ts.html deleted file mode 100644 index fc19fef4..00000000 --- a/docs/coverage/lcov-report/src/folder.ts.html +++ /dev/null @@ -1,839 +0,0 @@ - - - - - - Code coverage report for src/folder.ts - - - - - - - - - -
-
-

All files / src folder.ts

-
- -
- 92.96% - Statements - 66/71 -
- - -
- 90.91% - Branches - 10/11 -
- - -
- 90.91% - Functions - 20/22 -
- - -
- 92.96% - Lines - 66/71 -
- - -
-

- Press n or j to go to the next uncovered block, b, p or k for the previous block. -

-
-
-

-
1 -2 -3 -4 -5 -6 -7 -8 -9 -10 -11 -12 -13 -14 -15 -16 -17 -18 -19 -20 -21 -22 -23 -24 -25 -26 -27 -28 -29 -30 -31 -32 -33 -34 -35 -36 -37 -38 -39 -40 -41 -42 -43 -44 -45 -46 -47 -48 -49 -50 -51 -52 -53 -54 -55 -56 -57 -58 -59 -60 -61 -62 -63 -64 -65 -66 -67 -68 -69 -70 -71 -72 -73 -74 -75 -76 -77 -78 -79 -80 -81 -82 -83 -84 -85 -86 -87 -88 -89 -90 -91 -92 -93 -94 -95 -96 -97 -98 -99 -100 -101 -102 -103 -104 -105 -106 -107 -108 -109 -110 -111 -112 -113 -114 -115 -116 -117 -118 -119 -120 -121 -122 -123 -124 -125 -126 -127 -128 -129 -130 -131 -132 -133 -134 -135 -136 -137 -138 -139 -140 -141 -142 -143 -144 -145 -146 -147 -148 -149 -150 -151 -152 -153 -154 -155 -156 -157 -158 -159 -160 -161 -162 -163 -164 -165 -166 -167 -168 -169 -170 -171 -172 -173 -174 -175 -176 -177 -178 -179 -180 -181 -182 -183 -184 -185 -186 -187 -188 -189 -190 -191 -192 -193 -194 -195 -196 -197 -198 -199 -200 -201 -202 -203 -204 -205 -206 -207 -208 -209 -210 -211 -212 -213 -214 -215 -216 -217 -218 -219 -220 -221 -222 -223 -224 -225 -226 -227 -228 -229 -230 -231 -232 -233 -234 -235 -236 -237 -238 -239 -240 -241 -242 -243 -244 -245 -246 -247 -248 -249 -250 -251 -252 -253 -254  -1x -  -  -1x -1x -  -  -  -  -  -  -  -  -1x -  -  -  -  -  -  -  -  -  -  -285x -285x -  -  -  -  -  -  -  -  -  -144x -143x -  -  -  -2x -1x -  -  -  -2x -1x -  -  -  -22x -21x -  -  -  -  -  -  -  -3x -3x -  -  -  -  -  -  -  -2x -2x -2x -1x -  -1x -  -  -  -  -  -  -3x -3x -  -  -  -  -  -  -  -1x -1x -  -  -  -  -  -  -  -  -  -4x -4x -  -  -  -  -  -  -  -  -  -  -16x -  -16x -16x -  -  -16x -128x -  -  -  -  -  -  -16x -  -  -  -  -  -  -  -20x -20x -20x -  -  -  -  -  -  -  -  -  -1x -1x -1x -1x -1x -1x -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -2x -  -2x -2x -1x -  -1x -  -  -  -  -  -  -  -9x -  -  -  -  -  -  -  -2x -2x -2x -2x -5x -  -2x -  -  -  -  -  -  -  -2x -2x -2x -  -2x -2x -1x -  -  -  -  -  -  -  -  -4x -4x -  -  -  -  -  -  -  -  -  -  -2x -2x -  -  -  -212x -4x -  -  -  -  - 
import Client from "./client";
-import ClientError from "./error";
-import File from "./file";
-import FileSystemElement from "./fileSystemElement";
-import Logger from "./logger";
-const log: Logger = new Logger();
- 
-export interface FolderGetFilesOptions {
-    /**
-     * callback function to filter files
-     */
-    filterFile?: (file: File) => File | null;
-}
- 
-export default class Folder implements FileSystemElement {
-    private client: Client;
-    private memento: {
-        baseName: string,
-        id: number,
-        deleted: boolean,
-        lastmod: Date,
-        name: string,
-    };
-    constructor(client: Client, name: string, baseName: string, lastmod: string, id: number = -1) {
- 
-        this.client = client;
-        this.memento = {
-            baseName,
-            deleted: false,
-            id,
-            lastmod: new Date(lastmod),
-            name,
-        };
-    }
- 
-    get name(): string {
-        this.assertExistence();
-        return this.memento.name;
-    }
- 
-    get baseName(): string {
-        this.assertExistence();
-        return this.memento.baseName;
-    }
- 
-    get lastmod(): Date {
-        this.assertExistence();
-        return this.memento.lastmod;
-    }
- 
-    get id(): number {
-        this.assertExistence();
-        return this.memento.id;
-    }
- 
-    /**
-     * @returns an array of subfolders
-     * @throws Error
-     */
-    public async getSubFolders(): Promise<Folder[]> {
-        this.assertExistence();
-        return await this.client.getSubFolders(this.name);
-    }
- 
-    /**
-     * returns true if the current folder has a subfolder with the given base name
-     * @param subFolderBaseName the base name of the subfolder like "products"
-     */
-    public async hasSubFolder(subFolderBaseName: string): Promise<boolean> {
-        this.assertExistence();
-        const subFolder: Folder | null = await this.client.getFolder(this.name + "/" + subFolderBaseName);
-        if (subFolder) {
-            return true;
-        }
-        return false;
-    }
- 
-    /**
-     * @returns all files of the folder
-     */
-    public async getFiles(options?: FolderGetFilesOptions): Promise<File[]> {
-        this.assertExistence();
-        return await this.client.getFiles(this.name, options);
-    }
- 
-    /**
-     * creates a subfolder
-     * @param subFolderBaseName  name of the subfolder basename
-     */
-    public async createSubFolder(subFolderBaseName: string): Promise<Folder> {
-        this.assertExistence();
-        return await this.client.createFolder(this.name + "/" + subFolderBaseName);
-    }
- 
-    /**
-     * get a file by basename
-     * @param fileBaseName the base name of the file
-     * @returns the file of null
-     * @throws Error
-     */
-    public async getFile(fileBaseName: string): Promise<File | null> {
-        this.assertExistence();
-        return this.client.getFile(this.name + "/" + fileBaseName);
-    }
- 
-    /**
-     * creates a file in the folder
-     * @param fileBaseName the base name of the file
-     * @param data the buffer or stream with file content
-     * @returns the new file or null
-     * @throws Error
-     */
-    public async createFile(fileBaseName: string, data: Buffer | NodeJS.ReadableStream): Promise<File> {
-        this.assertExistence();
-        // must not contain :/\*"<>?
-        log.debug("createFile fileBaseName = ", fileBaseName);
-        const invalidChars: string[] = [":", "*", "/", "\\", "\"", "?", "<", ">"];
-        // log.debug("createFile invalidChars = ", invalidChars);
- 
-        for (const invalidChar of invalidChars) {
-            Iif (fileBaseName.indexOf(invalidChar) !== -1) {
-                throw new ClientError("Filename contains an invalid character '" + invalidChar + "'",
-                    "ERR_INVALID_CHAR_IN_FILE_NAME",
-                    { fileBaseName });
-            }
-        }
- 
-        return this.client.createFile(this.name + "/" + fileBaseName.replace(/^\/+/g, ""), data);
-    }
- 
-    /**
-     * deletes the folder and the contained files
-     * @throws Error
-     */
-    public async delete(): Promise<void> {
-        log.debug("delete");
-        this.memento.deleted = true;
-        return await this.client.deleteFolder(this.memento.name);
-    }
- 
-    /**
-     * renames or moves the current folder to the new location
-     * target folder must exists
-     * @param targetFolderName the name of the target folder /f1/f2/target
-     * @throws Error
-     */
-    public async move(targetFolderName: string): Promise<Folder> {
-        this.assertExistence();
-        const folder: Folder = await this.client.moveFolder(this.name, targetFolderName);
-        this.memento.name = folder.name;
-        this.memento.baseName = folder.baseName;
-        this.memento.lastmod = folder.lastmod;
-        return this;
-    }
- 
-    /**
-     * @returns the url of the folder
-     * @throws Error
-     */
-    public getUrl(): string {
-        this.assertExistence();
-        return this.client.getLink(this.name);
-    }
- 
-    /**
-     * @returns the url of the folder in the UI
-     * @throws Error
-     */
-    public getUIUrl(): string {
-        this.assertExistence();
-        return this.client.getUILink(this.id);
-    }
- 
-    /**
-     * @returns true if the folder contains a file with the given basename
-     * @param fileBaseName file basename
-     * @throws Error
-     */
-    public async containsFile(fileBaseName: string): Promise<boolean> {
-        this.assertExistence();
-        let file: File | null;
-        file = await this.getFile(fileBaseName);
-        if (file) {
-            return true;
-        }
-        return false;
-    }
- 
-    /**
-     * adds a tag name to the folder
-     * @param tagName name of the tag
-     */
-    public async addTag(tagName: string): Promise<void> {
-        return await this.client.addTagToFile(this.id, tagName);
-    }
- 
-    /**
-     * get tag names
-     * @returns array of tag names
-     */
-    public async getTags(): Promise<string[]> {
-        this.assertExistence();
-        const map: Map<string, number> = await this.client.getTagsOfFile(this.id);
-        const tagNames: string[] = [];
-        for (const tagName of map) {
-            tagNames.push(tagName[0]);
-        }
-        return tagNames;
-    }
- 
-    /**
-     * removes a tag of the file
-     * @param tagName the name of the tag
-     */
-    public async removeTag(tagName: string): Promise<void> {
-        this.assertExistence();
-        const map: Map<string, number> = await this.client.getTagsOfFile(this.id);
-        const tagNames: string[] = [];
- 
-        const tagId: number | undefined = map.get(tagName);
-        if (tagId) {
-            await this.client.removeTagOfFile(this.id, tagId);
-        }
-    }
- 
-    /**
-     * add comment to folder
-     * @param comment the comment
-     */
-    public async addComment(comment: string): Promise<void> {
-        this.assertExistence();
-        return await this.client.addCommentToFile(this.id, comment);
-    }
- 
-    /**
-     * get list of comments of folder
-     * @param top number of comments to return
-     * @param skip the offset
-     * @returns array of comment strings
-     * @throws Exception
-     */
-    public async getComments(top?: number, skip?: number): Promise<string[]> {
-        this.assertExistence();
-        return await this.client.getFileComments(this.id, top, skip);
-    }
- 
-    private assertExistence(): void {
-        if (this.memento.deleted) {
-            throw new ClientError("Folder does not exist", "ERR_FOLDER_NOT_EXISTING");
-        }
-    }
- 
-}
- 
- -
-
- - - - - - - - - \ No newline at end of file diff --git a/docs/coverage/lcov-report/src/getFilesRecursivelyCommand.ts.html b/docs/coverage/lcov-report/src/getFilesRecursivelyCommand.ts.html deleted file mode 100644 index 91b3a524..00000000 --- a/docs/coverage/lcov-report/src/getFilesRecursivelyCommand.ts.html +++ /dev/null @@ -1,368 +0,0 @@ - - - - - - Code coverage report for src/getFilesRecursivelyCommand.ts - - - - - - - - - -
-
-

All files / src getFilesRecursivelyCommand.ts

-
- -
- 90.63% - Statements - 29/32 -
- - -
- 75% - Branches - 3/4 -
- - -
- 100% - Functions - 4/4 -
- - -
- 90.63% - Lines - 29/32 -
- - -
-

- Press n or j to go to the next uncovered block, b, p or k for the previous block. -

-
-
-

-
1 -2 -3 -4 -5 -6 -7 -8 -9 -10 -11 -12 -13 -14 -15 -16 -17 -18 -19 -20 -21 -22 -23 -24 -25 -26 -27 -28 -29 -30 -31 -32 -33 -34 -35 -36 -37 -38 -39 -40 -41 -42 -43 -44 -45 -46 -47 -48 -49 -50 -51 -52 -53 -54 -55 -56 -57 -58 -59 -60 -61 -62 -63 -64 -65 -66 -67 -68 -69 -70 -71 -72 -73 -74 -75 -76 -77 -78 -79 -80 -81 -82 -83 -84 -85 -86 -87 -88 -89 -90 -91 -92 -93 -94 -95 -96 -97  -1x -  -  -1x -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -1x -  -  -  -  -  -  -  -  -  -  -1x -1x -1x -1x -  -  -  -  -  -  -  -  -1x -1x -1x -1x -1x -  -1x -  -  -  -  -  -1x -1x -  -  -1x -  -1x -1x -  -  -  -  -1x -  -  -  -  -  -  -  -  -  -  -  -8x -8x -8x -3x -  -  -8x -8x -7x -  -8x -  -7x -  -8x -  -  - 
// tslint:disable-next-line:no-var-requires
-const debug = require("debug").debug("GetFilesRecursivelyCommand");
- 
-import Client, { File, Folder, FolderGetFilesOptions } from "./client";
-import Command, { CommandStatus } from "./command";
- 
-export interface GetFilesRecursivelyCommandOptions {
-    /**
-     * the source nextcloud folder to start listing the files
-     */
-    sourceFolder: Folder;
-    /**
-     * function to filter files
-     */
-    filterFile?: (file: File) => File | null;
-}
- 
-/**
- * Command to get all files of a nextcloud folder recursively
- */
-export default class GetFilesRecursivelyCommand extends Command {
-    private sourceFolder: Folder;
-    private filterFile?: (file: File) => File | null;
-    private files: File[];
- 
-    /**
-     * @param {Client} client the client
-     * @param {SourceTargetFileNames[]} files the files to be uploaded
-     * @param {(file: File) => void} processAfterUpload callback function to process the uploaded file
-     */
-    constructor(client: Client, options: GetFilesRecursivelyCommandOptions) {
-        super(client);
-        this.sourceFolder = options.sourceFolder;
-        this.filterFile = options.filterFile;
-        this.files = [];
-    }
- 
-    /**
-     * execute the command
-     * @async
-     * @returns {Promise<void>}
-     */
-    protected async onExecute(): Promise<void> {
-        this.status = CommandStatus.running;
-        const startTime = new Date();
-        try {
-            this.percentCompleted = 0;
-            await this.processFolder(this.sourceFolder, 100);
-            // console.log("file count", this.files.length);
-            this.resultMetaData.messages.push(`${this.files.length} files found`);
-        } catch (e) {
-            debug(e.message);
-            this.resultMetaData.errors.push(e.message);
-        }
- 
-        this.percentCompleted = 100;
-        Iif (this.resultMetaData.errors.length > 0) {
-            this.status = CommandStatus.failed;
-        } else {
-            this.status = CommandStatus.success;
-        }
-        this.resultMetaData.timeElapsed = new Date().getTime() - startTime.getTime();
-        return;
-    };
- 
- 
-    public getFiles(): File[] {
-        return this.files;
-    }
- 
-    /**
-     * adds files of folder and processes subordinated folders
-     * @param {Folder} folder the folder to process
-     * @param {number} percentagethe percentage that is finished, when the function returns
-     */
-    private async processFolder(folder: Folder, percentage: number): Promise<void> {
-        // tslint:disable-next-line:no-console
-        // console.log(folder.name);
- 
-        const options: FolderGetFilesOptions = { filterFile: this.filterFile }
-        const folderFiles: File[] = await folder.getFiles(options);
-        for (const fi of folderFiles) {
-            this.files.push(fi);
-        }
- 
-        const subFolders: Folder[] = await folder.getSubFolders();
-        if (subFolders.length === 0) {
-            this.percentCompleted += percentage;
-        }
-        for (const subFolder of subFolders) {
-            // console.log("folder", subFolder.name);
-            await this.processFolder(subFolder, percentage / subFolders.length);
-        }
-        return;
-    }
-}
- 
- -
-
- - - - - - - - - \ No newline at end of file diff --git a/docs/coverage/lcov-report/src/httpClient.ts.html b/docs/coverage/lcov-report/src/httpClient.ts.html deleted file mode 100644 index b4f8bbd8..00000000 --- a/docs/coverage/lcov-report/src/httpClient.ts.html +++ /dev/null @@ -1,536 +0,0 @@ - - - - - - Code coverage report for src/httpClient.ts - - - - - - - - - -
-
-

All files / src httpClient.ts

-
- -
- 98.44% - Statements - 63/64 -
- - -
- 100% - Branches - 28/28 -
- - -
- 88.89% - Functions - 8/9 -
- - -
- 98.36% - Lines - 60/61 -
- - -
-

- Press n or j to go to the next uncovered block, b, p or k for the previous block. -

-
-
-

-
1 -2 -3 -4 -5 -6 -7 -8 -9 -10 -11 -12 -13 -14 -15 -16 -17 -18 -19 -20 -21 -22 -23 -24 -25 -26 -27 -28 -29 -30 -31 -32 -33 -34 -35 -36 -37 -38 -39 -40 -41 -42 -43 -44 -45 -46 -47 -48 -49 -50 -51 -52 -53 -54 -55 -56 -57 -58 -59 -60 -61 -62 -63 -64 -65 -66 -67 -68 -69 -70 -71 -72 -73 -74 -75 -76 -77 -78 -79 -80 -81 -82 -83 -84 -85 -86 -87 -88 -89 -90 -91 -92 -93 -94 -95 -96 -97 -98 -99 -100 -101 -102 -103 -104 -105 -106 -107 -108 -109 -110 -111 -112 -113 -114 -115 -116 -117 -118 -119 -120 -121 -122 -123 -124 -125 -126 -127 -128 -129 -130 -131 -132 -133 -134 -135 -136 -137 -138 -139 -140 -141 -142 -143 -144 -145 -146 -147 -148 -149 -150 -151 -152 -153  -1x -  -  -1x -1x -  -  -  -  -1x -1x -1x -1x -1x -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -1x -  -  -  -  -  -  -175x -175x -175x -175x -175x -  -  -  -1310x -5x -  -  -1310x -1x -  -  -1310x -1x -  -  -1310x -1307x -  -1310x -  -  -1310x -2x -2x -  -  -  -  -  -2x -  -2x -1x -  -  -  -1310x -1310x -  -1310x -  -1307x -1304x -  -  -2056x -2056x -  -  -1304x -  -  -  -1304x -319x -  -  -1304x -2x -  -  -1304x -1304x -52x -  -  -1304x -801x -  -  -  -1304x -  -  -  -  -1304x -  -  -  -  -1304x -1304x -  -  -1307x -  -1307x -236x -236x -236x -236x -236x -236x -236x -  -  -  -  -  -  -  -1071x -  -  -  - 
// tslint:disable-next-line:no-var-requires
-const HttpProxyAgent = require('http-proxy-agent');
- 
-import { HttpProxyAgentOptions } from "http-proxy-agent";
-import fetch from "node-fetch";
-import {
-    Headers,
-    RequestInit,
-    Response,
-} from "node-fetch";
-import ClientError from "./error";
-import RequestResponseLog from "./requestResponseLog";
-import RequestResponseLogEntry, { RequestLogEntry, ResponseLogEntry } from "./requestResponseLogEntry";
-import Logger from "./logger";
-const log: Logger = new Logger();
- 
-export interface IRequestContext {
-    "description"?: string;
-}
- 
-export interface IProxy {
-    "host": string;
-    "port": string;
-    "protocol": string;
-    "secureProxy": boolean;
-    "proxyAuthorizationHeader"?: string;
-}
- 
-export interface IHttpClientOptions {
-    "authorizationHeader"?: string;
-    "logRequestResponse"?: boolean;
-    "proxy"?: IProxy;
-    "origin"?: string;
-}
-export class HttpClient {
-    private proxy?: IProxy;
-    private authorizationHeader?: string;
-    private logRequestResponse: boolean;
-    private origin: string;
- 
-    public constructor(options: IHttpClientOptions) {
-        log.debug("constructor");
-        this.authorizationHeader = options.authorizationHeader;
-        this.proxy = options.proxy;
-        this.logRequestResponse = options.logRequestResponse || false;
-        this.origin = options.origin || "";
-    }
-    public async getHttpResponse(url: string, requestInit: RequestInit, expectedHttpStatusCode: number[], context: IRequestContext): Promise<Response> {
- 
-        if (!requestInit.headers) {
-            requestInit.headers = new Headers();
-        }
- 
-        if (!requestInit.method) {
-            requestInit.method = "UNDEFINED";
-        }
- 
-        if (!context.description) {
-            context.description = "";
-        }
- 
-        if (this.authorizationHeader) {
-            (requestInit.headers as Headers).append("Authorization", this.authorizationHeader);
-        }
-        (requestInit.headers as Headers).append("User-Agent", "nextcloud-node-client");
- 
-        // set the proxy
-        if (this.proxy) {
-            log.debug("proxy agent used");
-            const options: HttpProxyAgentOptions = {
-                host: this.proxy.host,
-                port: this.proxy.port,
-                protocol: this.proxy.protocol,
-            };
- 
-            requestInit.agent = new HttpProxyAgent(options);
- 
-            if (this.proxy.proxyAuthorizationHeader) {
-                (requestInit.headers as Headers).append("Proxy-Authorization", this.proxy.proxyAuthorizationHeader);
-            }
-        }
- 
-        log.debug("getHttpResponse request header:", requestInit.headers);
-        log.debug("getHttpResponse url", url, requestInit);
- 
-        const response: Response = await fetch(url, requestInit);
- 
-        if (this.logRequestResponse) {
-            const responseText = await response.text();
- 
-            // overwrite response functions as the body uses a stearm object...
-            response.text = async () => {
-                return responseText;
-            };
- 
-            response.body.pipe = (destination: NodeJS.WritableStream, options?: { end?: boolean; }): any => {
-                destination.write(responseText);
-            };
- 
-            response.json = async () => {
-                return JSON.parse(responseText);
-            };
- 
-            response.buffer = async () => {
-                return Buffer.from(responseText);
-            };
- 
-            let body: string = `<Body is ${typeof requestInit.body}>`;
-            if (requestInit.body && requestInit.body instanceof Buffer) {
-                body = `<Body is Buffer ${requestInit.body.length}>`;
-            }
- 
-            if (typeof requestInit.body === "string") {
-                body = requestInit.body;
-            }
- 
-            const reqLogEntry: RequestLogEntry =
-                new RequestLogEntry(url.replace(this.origin, ""),
-                    requestInit.method, context.description,
-                    body);
- 
-            const resLogEntry: ResponseLogEntry =
-                new ResponseLogEntry(response.status,
-                    await response.text(),
-                    response.headers.get("Content-Type") as string,
-                    response.headers.get("Content-Location") || "");
- 
-            const rrLog: RequestResponseLog = RequestResponseLog.getInstance();
-            await rrLog.addEntry(new RequestResponseLogEntry(reqLogEntry, resLogEntry));
-        }
- 
-        const responseContentType: string | null = response.headers.get("content-type");
- 
-        if (expectedHttpStatusCode.indexOf(response.status) === -1) {
-            log.debug("getHttpResponse unexpected status response "+ response.status + " " + response.statusText);
-            log.debug("getHttpResponse description "+ context.description);
-            log.debug("getHttpResponse expected "+ expectedHttpStatusCode.join(","));
-            log.debug("getHttpResponse headers ", JSON.stringify(response.headers, null, 4));
-            log.debug("getHttpResponse request body ", requestInit.body);
-            log.debug("getHttpResponse text:", await response.text());
-            throw new ClientError(`HTTP response status ${response.status} not expected. Expected status: ${expectedHttpStatusCode.join(",")} - status text: ${response.statusText}`,
-                "ERR_UNEXPECTED_HTTP_STATUS",
-                {
-                    expectedHttpStatusCodes: expectedHttpStatusCode,
-                    responseStatus: response.status,
-                    responseStatusText: response.statusText,
-                });
-        }
-        return response;
-    }
- 
-}
- 
- -
-
- - - - - - - - - \ No newline at end of file diff --git a/docs/coverage/lcov-report/src/index.html b/docs/coverage/lcov-report/src/index.html deleted file mode 100644 index c2d5609d..00000000 --- a/docs/coverage/lcov-report/src/index.html +++ /dev/null @@ -1,381 +0,0 @@ - - - - - - Code coverage report for src - - - - - - - - - -
-
-

All files src

-
- -
- 94.16% - Statements - 1611/1711 -
- - -
- 89.93% - Branches - 545/606 -
- - -
- 91.83% - Functions - 236/257 -
- - -
- 94.12% - Lines - 1602/1702 -
- - -
-

- Press n or j to go to the next uncovered block, b, p or k for the previous block. -

-
-
-
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
FileStatementsBranchesFunctionsLines
client.ts -
-
92.97%1031/110987.44%383/43892%92/10092.94%1027/1105
environment.ts -
-
100%15/15100%15/15100%5/5100%15/15
environmentVcapServices.ts -
-
100%24/24100%15/15100%2/2100%24/24
error.ts -
-
100%21/21100%0/0100%2/2100%21/21
fakeServer.ts -
-
96.3%26/2790%9/10100%2/296.3%26/27
file.ts -
-
78.95%45/5750%3/689.47%17/1978.95%45/57
fileSizeFormatter.ts -
-
100%18/18100%6/6100%2/2100%18/18
fileSystemElement.ts -
-
100%1/1100%0/0100%0/0100%1/1
fileSystemFolder.ts -
-
100%19/19100%2/2100%7/7100%17/17
folder.ts -
-
92.96%66/7190.91%10/1190.91%20/2292.96%66/71
httpClient.ts -
-
98.44%63/64100%28/2888.89%8/998.36%60/61
logger.ts -
-
96.55%28/29100%8/812.5%1/896.55%28/29
requestResponseLog.ts -
-
100%54/54100%24/24100%9/9100%54/54
requestResponseLogEntry.ts -
-
100%13/13100%0/0100%3/3100%13/13
server.ts -
-
90%9/1050%1/2100%1/190%9/10
share.ts -
-
98.36%60/61100%26/2694.74%18/1998.36%60/61
tag.ts -
-
100%9/9100%0/0100%3/3100%9/9
user.ts -
-
100%98/98100%13/13100%40/40100%98/98
userGroup.ts -
-
100%11/11100%2/2100%4/4100%11/11
-
-
-
- - - - - - - - - \ No newline at end of file diff --git a/docs/coverage/lcov-report/src/logger.ts.html b/docs/coverage/lcov-report/src/logger.ts.html deleted file mode 100644 index 37195619..00000000 --- a/docs/coverage/lcov-report/src/logger.ts.html +++ /dev/null @@ -1,419 +0,0 @@ - - - - - - Code coverage report for src/logger.ts - - - - - - - - - -
-
-

All files / src logger.ts

-
- -
- 96.55% - Statements - 28/29 -
- - -
- 100% - Branches - 8/8 -
- - -
- 12.5% - Functions - 1/8 -
- - -
- 96.55% - Lines - 28/29 -
- - -
-

- Press n or j to go to the next uncovered block, b, p or k for the previous block. -

-
-
-

-
1 -2 -3 -4 -5 -6 -7 -8 -9 -10 -11 -12 -13 -14 -15 -16 -17 -18 -19 -20 -21 -22 -23 -24 -25 -26 -27 -28 -29 -30 -31 -32 -33 -34 -35 -36 -37 -38 -39 -40 -41 -42 -43 -44 -45 -46 -47 -48 -49 -50 -51 -52 -53 -54 -55 -56 -57 -58 -59 -60 -61 -62 -63 -64 -65 -66 -67 -68 -69 -70 -71 -72 -73 -74 -75 -76 -77 -78 -79 -80 -81 -82 -83 -84 -85 -86 -87 -88 -89 -90 -91 -92 -93 -94 -95 -96 -97 -98 -99 -100 -101 -102 -103 -104 -105 -106 -107 -108 -109 -110 -111 -112 -113 -1141x -1x -  -  -  -  -  -1x -  -  -  -  -  -17x -  -1x -1x -  -1x -1x -  -1x -1x -  -1x -1x -  -1x -1x -  -10x -10x -  -1x -1x -  -1x -  -  -17x -17x -  -17x -17x -17x -17x -17x -17x -17x -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  - 
import Environment from "./environment";
-import {
-    Logger as TSLogLogger,
-    ILogObject as LogObject,
-    TLogLevelName
-} from "tslog";
- 
-export default class Logger {
-    private logger: TSLogLogger;
- 
-    public constructor() {
-        let minLevel: TLogLevelName;
- 
-        switch (Environment.getMinLogLevel()) {
-            case "silly":
-                minLevel = "silly"
-                break;
-            case "trace":
-                minLevel = "trace"
-                break;
-            case "debug":
-                minLevel = "debug"
-                break;
-            case "info":
-                minLevel = "info"
-                break;
-            case "warn":
-                minLevel = "warn"
-                break;
-            case "error":
-                minLevel = "error"
-                break;
-            case "fatal":
-                minLevel = "fatal"
-                break;
-            default:
-                minLevel = "error";
-        }
- 
-        minLevel = "error";
-        this.logger = new TSLogLogger({ minLevel });
-        // overload is required to get the real position for logging
-        this.silly = this.logger.silly.bind(this.logger);
-        this.trace = this.logger.trace.bind(this.logger);
-        this.debug = this.logger.debug.bind(this.logger);
-        this.info = this.logger.info.bind(this.logger);
-        this.warn = this.logger.warn.bind(this.logger);
-        this.error = this.logger.error.bind(this.logger);
-        this.fatal = this.logger.fatal.bind(this.logger);
-    }
- 
-    /**
-     * Logs a silly message.
-     * @param args  - Multiple log attributes that should be logged out.
-     */
-    public silly(...args: unknown[]): LogObject {
-        /* istanbul ignore next */
-        return this.logger.silly(...args);
-    }
- 
-    /**
-     * Logs a trace message.
-     * @param args  - Multiple log attributes that should be logged out.
-     */
-    public trace(...args: unknown[]): LogObject {
-        /* istanbul ignore next */
-        return this.logger.trace(...args);
-    }
- 
-    /**
-     * Logs a debug message.
-     * @param args  - Multiple log attributes that should be logged out.
-     */
-    public debug(...args: unknown[]): LogObject {
-        return this.logger.debug(...args);
-    }
- 
-    /**
-     * Logs a info message.
-     * @param args  - Multiple log attributes that should be logged out.
-     */
-    public info(...args: unknown[]): LogObject {
-        /* istanbul ignore next */
-        return this.logger.info(...args);
-    }
- 
-    /**
-     * Logs a warn message.
-     * @param args  - Multiple log attributes that should be logged out.
-     */
-    public warn(...args: unknown[]): LogObject {
-        /* istanbul ignore next */
-        return this.logger.warn(...args);
-    }
- 
-    /**
-     * Logs a error message.
-     * @param args  - Multiple log attributes that should be logged out.
-     */
-    public error(...args: unknown[]): LogObject {
-        /* istanbul ignore next */
-        return this.logger.error(...args);
-    }
- 
-    /**
-     * Logs a fatal message.
-     * @param args  - Multiple log attributes that should be logged out.
-     */
-    public fatal(...args: unknown[]): LogObject {
-        /* istanbul ignore next */
-        return this.logger.fatal(...args);
-    }
-}
- 
- -
-
- - - - - - - - - \ No newline at end of file diff --git a/docs/coverage/lcov-report/src/requestResponseLog.ts.html b/docs/coverage/lcov-report/src/requestResponseLog.ts.html deleted file mode 100644 index 308bfb85..00000000 --- a/docs/coverage/lcov-report/src/requestResponseLog.ts.html +++ /dev/null @@ -1,416 +0,0 @@ - - - - - - Code coverage report for src/requestResponseLog.ts - - - - - - - - - -
-
-

All files / src requestResponseLog.ts

-
- -
- 100% - Statements - 54/54 -
- - -
- 100% - Branches - 24/24 -
- - -
- 100% - Functions - 9/9 -
- - -
- 100% - Lines - 54/54 -
- - -
-

- Press n or j to go to the next uncovered block, b, p or k for the previous block. -

-
-
-

-
1 -2 -3 -4 -5 -6 -7 -8 -9 -10 -11 -12 -13 -14 -15 -16 -17 -18 -19 -20 -21 -22 -23 -24 -25 -26 -27 -28 -29 -30 -31 -32 -33 -34 -35 -36 -37 -38 -39 -40 -41 -42 -43 -44 -45 -46 -47 -48 -49 -50 -51 -52 -53 -54 -55 -56 -57 -58 -59 -60 -61 -62 -63 -64 -65 -66 -67 -68 -69 -70 -71 -72 -73 -74 -75 -76 -77 -78 -79 -80 -81 -82 -83 -84 -85 -86 -87 -88 -89 -90 -91 -92 -93 -94 -95 -96 -97 -98 -99 -100 -101 -102 -103 -104 -105 -106 -107 -108 -109 -110 -111 -112 -113  -1x -1x -1x -  -1x -1x -  -1x -1x -  -  -8x -  -  -1475x -9x -  -1475x -  -1x -  -9x -  -9x -  -9x -9x -  -  -  -1314x -1314x -1x -1x -  -  -1313x -1084x -755x -  -1084x -324x -  -  -  -1313x -1311x -638x -  -  -  -1313x -1313x -  -  -  -6x -6x -1x -1x -  -  -5x -5x -  -  -  -168x -168x -  -168x -168x -  -  -168x -  -  -  -1646x -  -  -  -1393x -1391x -  -2x -  -  -  -168x -168x -168x -  -168x -670x -168x -  -502x -  -  -670x -670x -  -  -  -  -  -  -  -  -  - 
 
-import parser from "fast-xml-parser";
-import { promises as fsPromises } from "fs";
-import path from "path";
-import requestResponseLogEntry from "./requestResponseLogEntry";
-import Logger from "./logger";
-const log: Logger = new Logger();
- 
-export default class RequestResponseLog {
-    public static readonly defaultLogDirectory: string = "RequestResponseLog/";
- 
-    public static deleteInstance(): void {
-        RequestResponseLog.log = null;
-    }
-    public static getInstance(): RequestResponseLog {
-        if (!RequestResponseLog.log) {
-            RequestResponseLog.log = new RequestResponseLog();
-        }
-        return RequestResponseLog.log;
-    }
-    private static log: RequestResponseLog | null = null;
- 
-    public baseDirectory: string = RequestResponseLog.defaultLogDirectory;
-    private context: string;
-    private entries: requestResponseLogEntry[] = [];
-    private constructor() {
-        this.baseDirectory = RequestResponseLog.defaultLogDirectory;
-        this.context = "";
-    }
- 
-    public async addEntry(logEntry: requestResponseLogEntry) {
-        log.debug("addEntry");
-        if (!this.context) {
-            log.debug("Error while recording, context not set");
-            throw new Error("Error while recording, context not set");
-        }
- 
-        if (logEntry.response.body && logEntry.response.contentType) {
-            if (logEntry.response.contentType.indexOf("application/xml") !== -1) {
-                logEntry.response.jsonBody = this.xmlToJson(logEntry.response.body);
-            }
-            if (logEntry.response.contentType.indexOf("application/json") !== -1) {
-                logEntry.response.jsonBody = JSON.parse(logEntry.response.body);
-            }
-        }
- 
-        if (logEntry.request.body) {
-            if (logEntry.request.body.indexOf && logEntry.request.body.indexOf("<?xml version") !== -1) {
-                logEntry.request.jsonBody = this.xmlToJson(logEntry.request.body);
-            }
-        }
- 
-        this.entries.push(logEntry);
-        await fsPromises.writeFile(this.getFileName(), JSON.stringify(this.entries, null, 4));
-    }
- 
-    public async getEntries(): Promise<requestResponseLogEntry[]> {
-        log.debug("getEntries");
-        if (!this.context) {
-            log.debug("Error while getting recording request, context not set");
-            throw new Error("Error while getting recording request, context not set");
-        }
- 
-        const entries: string = await fsPromises.readFile(this.getFileName(), { encoding: "utf8" });
-        return JSON.parse(entries);
-    }
- 
-    public async setContext(context: string) {
-        log.debug("setContext");
-        const newContext: string = context.replace(/ |:|\./g, "_");
-        // if (this.context !== newContext) {
-        this.context = newContext;
-        this.entries = [];
-        // }
-        // create the directory
-        await this.assertDirectory(this.getFileName());
-    }
- 
-    public getFileName(): string {
-        return `${this.baseDirectory}${this.context}.json`;
-    }
- 
-    private xmlToJson(xml: string): any {
-        if (parser.validate(xml) === true) {
-            return parser.parse(xml, { ignoreNameSpace: true });
-        }
-        return { info: "invalid xml" };
-    }
- 
-    private async assertDirectory(filename: string): Promise<void> {
-        const directory = path.dirname(filename);
-        const pathArray: string[] = directory.split("/");
-        let p: string = "";
- 
-        for (const dir of pathArray) {
-            if (p === "") {
-                p = dir;
-            } else {
-                p = p + "/" + dir;
-            }
- 
-            try {
-                await fsPromises.mkdir(p);
-                  /* istanbul ignore next */
-                  log.debug(`directory "${p}" created`);
-            } catch (e) {
-                  /* istanbul ignore next */
-                  log.debug(`directory "${p}" already exists`);
-            }
-        }
-    }
-}
- 
- -
-
- - - - - - - - - \ No newline at end of file diff --git a/docs/coverage/lcov-report/src/requestResponseLogEntry.ts.html b/docs/coverage/lcov-report/src/requestResponseLogEntry.ts.html deleted file mode 100644 index caf871ab..00000000 --- a/docs/coverage/lcov-report/src/requestResponseLogEntry.ts.html +++ /dev/null @@ -1,194 +0,0 @@ - - - - - - Code coverage report for src/requestResponseLogEntry.ts - - - - - - - - - -
-
-

All files / src requestResponseLogEntry.ts

-
- -
- 100% - Statements - 13/13 -
- - -
- 100% - Branches - 0/0 -
- - -
- 100% - Functions - 3/3 -
- - -
- 100% - Lines - 13/13 -
- - -
-

- Press n or j to go to the next uncovered block, b, p or k for the previous block. -

-
-
-

-
1 -2 -3 -4 -5 -6 -7 -8 -9 -10 -11 -12 -13 -14 -15 -16 -17 -18 -19 -20 -21 -22 -23 -24 -25 -26 -27 -28 -29 -30 -31 -32 -33 -34 -35 -36 -37 -38 -391x -  -  -  -  -  -  -1310x -1310x -1310x -1310x -  -  -  -  -1x -  -  -  -  -  -  -1310x -1310x -1310x -1310x -  -  -  -  -1x -  -  -  -1314x -1314x -  -  - 
export class RequestLogEntry {
-    public body?: string;
-    public description: string;
-    public jsonBody?: any;
-    public method: string;
-    public url: string;
-    public constructor(url: string, method: string, description: string, body?: string) {
-        this.url = url;
-        this.method = method;
-        this.description = description;
-        this.body = body;
-    }
-}
- 
-// tslint:disable-next-line:max-classes-per-file
-export class ResponseLogEntry {
-    public body?: string;
-    public contentType?: string;
-    public contentLocation?: string;
-    public jsonBody?: any;
-    public status: number;
-    public constructor(status: number, body?: string, contentType?: string, contentLocation?: string) {
-        this.status = status;
-        this.body = body;
-        this.contentType = contentType;
-        this.contentLocation = contentLocation;
-    }
-}
- 
-// tslint:disable-next-line:max-classes-per-file
-export default class RequestResponseLogEntry {
-    public request: RequestLogEntry;
-    public response: ResponseLogEntry;
-    public constructor(request: RequestLogEntry, response: ResponseLogEntry) {
-        this.request = request;
-        this.response = response;
-    }
-}
- 
- -
-
- - - - - - - - - \ No newline at end of file diff --git a/docs/coverage/lcov-report/src/server.ts.html b/docs/coverage/lcov-report/src/server.ts.html deleted file mode 100644 index 1dab6501..00000000 --- a/docs/coverage/lcov-report/src/server.ts.html +++ /dev/null @@ -1,212 +0,0 @@ - - - - - - Code coverage report for src/server.ts - - - - - - - - - -
-
-

All files / src server.ts

-
- -
- 90% - Statements - 9/10 -
- - -
- 50% - Branches - 1/2 -
- - -
- 100% - Functions - 1/1 -
- - -
- 90% - Lines - 9/10 -
- - -
-

- Press n or j to go to the next uncovered block, b, p or k for the previous block. -

-
-
-

-
1 -2 -3 -4 -5 -6 -7 -8 -9 -10 -11 -12 -13 -14 -15 -16 -17 -18 -19 -20 -21 -22 -23 -24 -25 -26 -27 -28 -29 -30 -31 -32 -33 -34 -35 -36 -37 -38 -39 -40 -41 -42 -43 -44 -45  -1x -1x -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -1x -  -  -  -  -  -  -169x -169x -169x -169x -169x -  -  -169x -  -  -  - 
import { IProxy } from "./httpClient";
-import Logger from "./logger";
-const log: Logger = new Logger();
- 
-export interface IBasicAuth {
-    "username": string;
-    "password": string;
-}
- 
-/**
- * The options of a server constructor
- */
-export interface IServerOptions {
-    /**
-     * the url of the nextcloud server like https://nextcloud.mydomain.com
-     */
-    "url": string;
-    /**
-     * basic authentication informatin to access the nextcloud server
-     */
-    "basicAuth": IBasicAuth;
-    "proxy"?: IProxy;
-    "logRequestResponse"?: boolean;
-}
- 
-// tslint:disable-next-line: max-classes-per-file
-export default class Server {
-    public url: string;
-    public basicAuth: IBasicAuth;
-    public proxy?: IProxy;
-    public logRequestResponse: boolean;
-    //    public constructor(url: string, basicAuth: IBasicAuth, proxy?: IProxy, logRequestResponse: boolean = false) {
-    public constructor(options: IServerOptions) {
-        log.debug("constructor");
-        this.url = options.url;
-        this.basicAuth = options.basicAuth;
-        this.proxy = options.proxy;
-        Iif (options.logRequestResponse) {
-            this.logRequestResponse = true;
-        } else {
-            this.logRequestResponse = false;
-        }
-    }
-}
- 
- -
-
- - - - - - - - - \ No newline at end of file diff --git a/docs/coverage/lcov-report/src/share.ts.html b/docs/coverage/lcov-report/src/share.ts.html deleted file mode 100644 index 20582e05..00000000 --- a/docs/coverage/lcov-report/src/share.ts.html +++ /dev/null @@ -1,755 +0,0 @@ - - - - - - Code coverage report for src/share.ts - - - - - - - - - -
-
-

All files / src share.ts

-
- -
- 98.36% - Statements - 60/61 -
- - -
- 100% - Branches - 26/26 -
- - -
- 94.74% - Functions - 18/19 -
- - -
- 98.36% - Lines - 60/61 -
- - -
-

- Press n or j to go to the next uncovered block, b, p or k for the previous block. -

-
-
-

-
1 -2 -3 -4 -5 -6 -7 -8 -9 -10 -11 -12 -13 -14 -15 -16 -17 -18 -19 -20 -21 -22 -23 -24 -25 -26 -27 -28 -29 -30 -31 -32 -33 -34 -35 -36 -37 -38 -39 -40 -41 -42 -43 -44 -45 -46 -47 -48 -49 -50 -51 -52 -53 -54 -55 -56 -57 -58 -59 -60 -61 -62 -63 -64 -65 -66 -67 -68 -69 -70 -71 -72 -73 -74 -75 -76 -77 -78 -79 -80 -81 -82 -83 -84 -85 -86 -87 -88 -89 -90 -91 -92 -93 -94 -95 -96 -97 -98 -99 -100 -101 -102 -103 -104 -105 -106 -107 -108 -109 -110 -111 -112 -113 -114 -115 -116 -117 -118 -119 -120 -121 -122 -123 -124 -125 -126 -127 -128 -129 -130 -131 -132 -133 -134 -135 -136 -137 -138 -139 -140 -141 -142 -143 -144 -145 -146 -147 -148 -149 -150 -151 -152 -153 -154 -155 -156 -157 -158 -159 -160 -161 -162 -163 -164 -165 -166 -167 -168 -169 -170 -171 -172 -173 -174 -175 -176 -177 -178 -179 -180 -181 -182 -183 -184 -185 -186 -187 -188 -189 -190 -191 -192 -193 -194 -195 -196 -197 -198 -199 -200 -201 -202 -203 -204 -205 -206 -207 -208 -209 -210 -211 -212 -213 -214 -215 -216 -217 -218 -219 -220 -221 -222 -223 -224 -225 -2261x -  -  -  -  -1x -1x -1x -1x -1x -1x -1x -  -  -1x -1x -1x -1x -1x -  -  -  -  -  -  -  -  -  -1x -1x -1x -  -1x -  -  -11x -11x -7x -  -  -  -3x -  -  -  -  -  -  -3x -  -  -  -  -  -3x -1x -  -  -3x -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -11x -11x -  -  -  -  -  -  -  -  -  -  -  -1x -  -  -  -1x -1x -  -  -  -  -  -  -  -1x -  -  -  -2x -1x -1x -  -  -  -  -1x -1x -  -  -  -11x -  -11x -1x -  -  -10x -1x -  -9x -  -9x -1x -  -8x -  -8x -1x -  -  -7x -5x -  -2x -  -7x -2x -  -  -7x -1x -  -  -  -  -  -  -  -  -  -  -  -2x -  -  -  -  -  -  -  -2x -  -  -  -  -  -  -  -1x -  -  -  -  -  -  -  -2x -  -  -  -  -  -  -  -2x -  -  -  -  -  -  -1x -  -  -  -  -  -  -  -  -  -  -  - 
import Client, { ClientError } from "./client";
-import File from "./file";
-import FileSystemElement from "./fileSystemElement";
-import Folder from "./folder";
- 
-export enum SharePermission {
-    all = 31,
-    read = 1,
-    update = 2,
-    create = 4,
-    delete = 8,
-    share = 16,
-}
- 
-enum ShareType {
-    user = 0,
-    group = 1,
-    publicLink = 3,
-    email = 4,
-}
- 
-export interface ICreateShare {
-    "fileSystemElement": FileSystemElement;
-    // @todo "shareWith"?: User | UserGroup | EMail;
-    "publicUpload"?: boolean;
-    "password"?: string;
-}
- 
-export enum ShareItemType {
-    file = "file",
-    folder = "folder",
-}
-export default class Share {
- 
-    public static async getShare(client: Client, id: string): Promise<Share> {
-        const share: Share = new Share(client, id);
-        await share.initialize();
-        return share;
-    }
- 
-    public static createShareRequestBody(createShare: ICreateShare): string {
-        const shareType: ShareType = ShareType.publicLink;
- 
-        const shareRequest: {
-            path: string,
-            shareType: number,
-            // @todo   permissions: number | number[]
-            password?: string,
-        } = {
-            path: createShare.fileSystemElement.name,
-            //  @todo    permissions: 1,
-            shareType,
-        };
- 
-        if (createShare.password) {
-            shareRequest.password = createShare.password;
-        }
- 
-        return JSON.stringify(shareRequest, null, 4);
-    }
- 
-    private client: Client;
-    private memento: {
-        expiration: Date | null,
-        id: string;
-        itemType: ShareItemType,
-        note: string,
-        token: string,
-        url: string,
-        publicUpload: boolean,
-        // share_type: number,
-        // "uid_owner": string,
-        // "displayname_owner": string,
-        // "permissions": SharePermission,
-        // "can_edit": boolean,
-        // "can_delete": boolean,
-        // "stime": Date,
-        // "parent"?: Share,
-        // "uid_file_owner": string,
-        // "label"?: string,
-        // "displayname_file_owner": string,
-        // "path": string,
-        // "mimetype"?: string,
-        // "share_with"?: string,
-        // "share_with_displayname"?: string,
-        // "mail_send": boolean,
-        // "hide_download": boolean,
-    };
- 
-    private constructor(client: Client, id: string) {
-        this.client = client;
-        this.memento = {
-            expiration: null,
-            id,
-            itemType: ShareItemType.file,
-            note: "",
-            token: "",
-            url: "",
-            publicUpload: false,
-        };
-    }
- 
-    public async delete(): Promise<void> {
-        await this.client.deleteShare(this.memento.id);
-    }
- 
-    public async setExpiration(expiration: Date): Promise<void> {
-        this.memento.expiration = expiration;
-        await this.client.updateShare(this.memento.id, { expireDate: expiration.toISOString().split("T")[0] });
-    }
- 
-    /**
-     * set a new password
-     * @param password
-     */
-    public async setPassword(password: string): Promise<void> {
-        await this.client.updateShare(this.memento.id, { password });
-    }
- 
-    public async setPublicUpload(): Promise<void> {
-        if (this.memento.itemType === ShareItemType.folder) {
-            this.memento.publicUpload = true;
-            await this.client.updateShare(this.memento.id, { permissions: 15 });
-        }
-    }
- 
-    public async setNote(note: string): Promise<void> {
-        this.memento.note = note;
-        await this.client.updateShare(this.memento.id, { note });
-    }
- 
-    private async initialize(): Promise<void> {
-        const rawShareData = await this.client.getShare(this.memento.id);
- 
-        if (!rawShareData.ocs || !rawShareData.ocs.data[0]) {
-            throw new ClientError(`Error invalid share data received "ocs.data" missing`, "ERR_INVALID_SHARE_RESPONSE");
-        }
- 
-        if (!rawShareData.ocs.data[0].url) {
-            throw new ClientError(`Error invalid share data received "url" missing`, "ERR_INVALID_SHARE_RESPONSE");
-        }
-        this.memento.url = rawShareData.ocs.data[0].url;
- 
-        if (!rawShareData.ocs.data[0].token) {
-            throw new ClientError(`Error invalid share data received "token" missing`, "ERR_INVALID_SHARE_RESPONSE");
-        }
-        this.memento.token = rawShareData.ocs.data[0].token;
- 
-        if (!rawShareData.ocs.data[0].item_type) {
-            throw new ClientError(`Error invalid share data received "item_type" missing`, "ERR_INVALID_SHARE_RESPONSE");
-        }
- 
-        if (rawShareData.ocs.data[0].item_type === "file") {
-            this.memento.itemType = ShareItemType.file;
-        } else {
-            this.memento.itemType = ShareItemType.folder;
-        }
-        if (rawShareData.ocs.data[0].expiration) {
-            this.memento.expiration = new Date(rawShareData.ocs.data[0].expiration);
-        }
- 
-        if (rawShareData.ocs.data[0].note) {
-            this.memento.note = rawShareData.ocs.data[0].note;
-        }
- 
-        // console.log(JSON.stringify(rawShareData, null, 4));
-        // console.log(JSON.stringify(this, null, 4));
-    }
- 
-    /**
-     * token
-     * The token is readonly
-     */
-    public get token(): string {
-        return this.memento.token;
-    }
- 
-    /**
-     * share url
-     * The share url is readonly
-     */
-    public get url(): string {
-        return this.memento.url;
-    }
- 
-    /**
-     * expiration
-     * The expiration is readonly
-     */
-    public get expiration(): Date | null {
-        return this.memento.expiration;
-    }
- 
-    /**
-     * note
-     * The note is readonly
-     */
-    public get note(): string {
-        return this.memento.note;
-    }
- 
-    /**
-     * id
-     * The id is readonly
-     */
-    public get id(): string {
-        return this.memento.id;
-    }
- 
-    /**
-     * returns true if the share akkows upload
-     */
-    public get publicUpload(): boolean {
-        return this.memento.publicUpload;
-    }
- 
-    /**
-     * item type
-     * The type of the share item file or folder
-     */
-    public get itemType(): ShareItemType {
-        return this.memento.itemType;
-    }
- 
-}
- 
- -
-
- - - - - - - - - \ No newline at end of file diff --git a/docs/coverage/lcov-report/src/tag.ts.html b/docs/coverage/lcov-report/src/tag.ts.html deleted file mode 100644 index 24281225..00000000 --- a/docs/coverage/lcov-report/src/tag.ts.html +++ /dev/null @@ -1,158 +0,0 @@ - - - - - - Code coverage report for src/tag.ts - - - - - - - - - -
-
-

All files / src tag.ts

-
- -
- 100% - Statements - 9/9 -
- - -
- 100% - Branches - 0/0 -
- - -
- 100% - Functions - 3/3 -
- - -
- 100% - Lines - 9/9 -
- - -
-

- Press n or j to go to the next uncovered block, b, p or k for the previous block. -

-
-
-

-
1 -2 -3 -4 -5 -6 -7 -8 -9 -10 -11 -12 -13 -14 -15 -16 -17 -18 -19 -20 -21 -22 -23 -24 -25 -26 -27  -  -  -1x -  -  -  -  -  -  -  -109x -109x -109x -109x -109x -109x -  -  -16x -  -  -8x -  -  -  - 
 
-import Client from "./client";
- 
-export default class Tag {
-    public readonly id: number;
-    public readonly name: string;
-    public readonly visible: boolean;
-    public readonly assignable: boolean;
-    public readonly canAssign: boolean;
-    private client: Client;
-    constructor(client: Client, id: number, name: string, visible: boolean, assignable: boolean, canAssign: boolean) {
-        this.client = client;
-        this.name = name;
-        this.visible = visible;
-        this.assignable = assignable;
-        this.canAssign = canAssign;
-        this.id = id;
-    }
-    public async delete(): Promise<void> {
-        return await this.client.deleteTag(this.id);
-    }
-    public toString(): string {
-        return "id:" + this.id + " name:" + this.name;
-    }
- 
-}
- 
- -
-
- - - - - - - - - \ No newline at end of file diff --git a/docs/coverage/lcov-report/src/uploadFilesCommand.ts.html b/docs/coverage/lcov-report/src/uploadFilesCommand.ts.html deleted file mode 100644 index 49b8cf88..00000000 --- a/docs/coverage/lcov-report/src/uploadFilesCommand.ts.html +++ /dev/null @@ -1,389 +0,0 @@ - - - - - - Code coverage report for src/uploadFilesCommand.ts - - - - - - - - - -
-
-

All files / src uploadFilesCommand.ts

-
- -
- 78.05% - Statements - 32/41 -
- - -
- 62.5% - Branches - 5/8 -
- - -
- 100% - Functions - 3/3 -
- - -
- 78.05% - Lines - 32/41 -
- - -
-

- Press n or j to go to the next uncovered block, b, p or k for the previous block. -

-
-
-

-
1 -2 -3 -4 -5 -6 -7 -8 -9 -10 -11 -12 -13 -14 -15 -16 -17 -18 -19 -20 -21 -22 -23 -24 -25 -26 -27 -28 -29 -30 -31 -32 -33 -34 -35 -36 -37 -38 -39 -40 -41 -42 -43 -44 -45 -46 -47 -48 -49 -50 -51 -52 -53 -54 -55 -56 -57 -58 -59 -60 -61 -62 -63 -64 -65 -66 -67 -68 -69 -70 -71 -72 -73 -74 -75 -76 -77 -78 -79 -80 -81 -82 -83 -84 -85 -86 -87 -88 -89 -90 -91 -92 -93 -94 -95 -96 -97 -98 -99 -100 -101 -102 -103 -104  -1x -  -  -1x -1x -1x -  -  -  -  -  -  -  -  -  -  -  -  -  -  -1x -  -  -  -  -  -  -  -  -  -  -1x -1x -1x -1x -  -  -  -  -  -  -  -  -1x -1x -1x -1x -  -1x -1x -  -  -  -  -  -1x -  -14x -14x -14x -14x -14x -14x -14x -  -  -  -  -  -  -  -  -14x -14x -14x -  -14x -  -  -  -  -  -  -  -  -  -1x -  -  -1x -  -  -1x -  -1x -  -  -  -37x -  -  -  - 
// tslint:disable-next-line:no-var-requires
-const debug = require("debug").debug("UploadFilesCommand");
- 
-import Client, { File } from "./client";
-import Command, { CommandStatus } from "./command";
-import util from "util";
-import fs from "fs";
- 
-export interface SourceTargetFileNames {
-    sourceFileName: string;
-    targetFileName: string;
-}
- 
-export interface UploadFilesCommandOptions {
-    files: SourceTargetFileNames[];
-    processFileAfterUpload?: (file: File) => Promise<void>;
-}
- 
-/**
- * Command to upload a set or files from local file system to nextcloud
- */
-export default class UploadFilesCommand extends Command {
-    private files: SourceTargetFileNames[];
-    private processFileAfterUpload?: (file: File) => Promise<void>;
-    private bytesUploaded: number;
- 
-    /**
-     * @param {Client} client the client
-     * @param {SourceTargetFileNames[]} files the files to be uploaded
-     * @param {(file: File) => void} processAfterUpload callback function to process the uploaded file
-     */
-    constructor(client: Client, options: UploadFilesCommandOptions) {
-        super(client);
-        this.files = options.files;
-        this.bytesUploaded = 0;
-        this.processFileAfterUpload = options.processFileAfterUpload;
-    }
- 
-    /**
-     * execute the command
-     * @async
-     * @returns {Promise<void>}
-     */
-    protected async onExecute(): Promise<void> {
-        this.status = CommandStatus.running;
-        try {
-            const readfile = util.promisify(fs.readFile);
-            let countCompleted = 0;
- 
-            this.percentCompleted = 0;
-            Iif (this.files.length === 0) {
-                this.percentCompleted = 100;
-            }
- 
-            let newFile: File | null;
- 
-            for (const file of this.files) {
-                let data: Buffer;
-                newFile = null;
-                try {
-                    data = await readfile(file.sourceFileName);
-                    try {
-                        newFile = await this.client.createFile(file.targetFileName, data);
-                        this.resultMetaData.messages.push(`${file.targetFileName}`);
-                        this.bytesUploaded += data.length;
-                    } catch (e) {
-                        this.resultMetaData.errors.push(`${file.targetFileName}: ${e.message}`);
-                        debug(file.targetFileName, e);
-                    }
-                } catch (e) {
-                    this.resultMetaData.errors.push(`${file.targetFileName}: ${e.message}`);
-                }
- 
-                countCompleted++;
-                this.percentCompleted = Math.round(countCompleted / this.files.length * 100);
-                debug(" completed:" + this.percentCompleted + "%");
- 
-                Iif (newFile && this.processFileAfterUpload) {
-                    await this.processFileAfterUpload(newFile);
-                }
-            }
- 
-        } catch (e) {
-            debug(e.message);
-            this.resultMetaData.errors.push(e.message);
-            this.percentCompleted = 100;
-        }
-        Iif (this.resultMetaData.errors.length > 0) {
-            this.status = CommandStatus.failed;
-        } else {
-            this.status = CommandStatus.success;
-        }
- 
-        debug("execute finished", this.percentCompleted, this.status);
- 
-        return;
-    };
- 
-    public getBytesUploaded(): number {
-        return this.bytesUploaded;
-    }
- 
-}
- 
- -
-
- - - - - - - - - \ No newline at end of file diff --git a/docs/coverage/lcov-report/src/uploadFolderCommand.ts.html b/docs/coverage/lcov-report/src/uploadFolderCommand.ts.html deleted file mode 100644 index ef121057..00000000 --- a/docs/coverage/lcov-report/src/uploadFolderCommand.ts.html +++ /dev/null @@ -1,413 +0,0 @@ - - - - - - Code coverage report for src/uploadFolderCommand.ts - - - - - - - - - -
-
-

All files / src uploadFolderCommand.ts

-
- -
- 80.43% - Statements - 37/46 -
- - -
- 50% - Branches - 2/4 -
- - -
- 71.43% - Functions - 5/7 -
- - -
- 80.95% - Lines - 34/42 -
- - -
-

- Press n or j to go to the next uncovered block, b, p or k for the previous block. -

-
-
-

-
1 -2 -3 -4 -5 -6 -7 -8 -9 -10 -11 -12 -13 -14 -15 -16 -17 -18 -19 -20 -21 -22 -23 -24 -25 -26 -27 -28 -29 -30 -31 -32 -33 -34 -35 -36 -37 -38 -39 -40 -41 -42 -43 -44 -45 -46 -47 -48 -49 -50 -51 -52 -53 -54 -55 -56 -57 -58 -59 -60 -61 -62 -63 -64 -65 -66 -67 -68 -69 -70 -71 -72 -73 -74 -75 -76 -77 -78 -79 -80 -81 -82 -83 -84 -85 -86 -87 -88 -89 -90 -91 -92 -93 -94 -95 -96 -97 -98 -99 -100 -101 -102 -103 -104 -105 -106 -107 -108 -109 -110 -111 -112  -1x -  -1x -  -  -  -  -  -  -  -  -1x -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -1x -  -  -  -  -  -  -  -  -  -  -  -1x -1x -1x -1x -1x -  -  -  -1x -  -  -  -  -  -  -  -  -1x -1x -1x -1x -1x -  -  -  -  -  -  -  -  -  -1x -1x -14x -  -14x -14x -  -  -  -1x -1x -1x -  -  -1x -36x -36x -36x -36x -  -36x -  -  -1x -1x -1x -1x -1x -  -  -  -  -  -  - 
// tslint:disable-next-line:no-var-requires
-const debug = require("debug").debug("UploadFolderCommand");
- 
-import Client,
-{
-    File,
-    FileSystemFolder,
-    IFileNameFormats,
-    UploadFilesCommand,
-    UploadFilesCommandOptions,
-    SourceTargetFileNames,
-} from "./client";
-import Command, { CommandStatus } from "./command";
- 
-/**
- * options to create a upload folder command
- */
-export interface UploadFolderCommandOptions {
-    /**
-     * The name of the source folder with the file structure to be uploaded
-     */
-    folderName: string;
-    /**
-     * the function to determine the target file name having the sourece file name.
-     * If the file should not be uploaded, return an empty string
-     * @param {SourceTargetFileNames} fileNames
-     */
-    getTargetFileNameBeforeUpload?: (fileNames: SourceTargetFileNames) => string;
-    processFileAfterUpload?: (file: File) => Promise<void>;
-}
- 
-/**
- * Command to upload the contents of a folder from local file system to nextcloud recursively
- */
-export default class UploadFolderCommand extends Command {
-    private folderName: string;
-    private processFileAfterUpload?: (file: File) => Promise<void>;
-    private getTargetFileNameBeforeUpload: (fileNames: SourceTargetFileNames) => string;
-    private bytesUploaded: number;
- 
-    /**
-     * @param {Client} client the client
-     * @param {ISourceTargetFileNames[]} files the files to be uploaded
-     * @param {(file: File) => void} processAfterUpload callback function to process the uploaded file
-     */
-    constructor(client: Client, options: UploadFolderCommandOptions) {
-        super(client);
-        this.folderName = options.folderName;
-        this.processFileAfterUpload = options.processFileAfterUpload;
-        Eif (options.getTargetFileNameBeforeUpload) {
-            this.getTargetFileNameBeforeUpload = options.getTargetFileNameBeforeUpload;
-        } else {
-            this.getTargetFileNameBeforeUpload = (fileNames: SourceTargetFileNames): string => { return fileNames.targetFileName };
-        }
-        this.bytesUploaded = 0;
-    }
- 
-    /**
-     * execute the command
-     * @async
-     * @returns {Promise<void>}
-     */
-    protected async onExecute(): Promise<void> {
-        this.status = CommandStatus.running;
-        let fileNames: IFileNameFormats[] = [];
-        const fsf: FileSystemFolder = new FileSystemFolder(this.folderName);
-        try {
-            fileNames = await fsf.getFileNames();
-        } catch (e) {
-            this.resultMetaData.errors.push(e);
-            this.status = CommandStatus.failed;
-            this.percentCompleted = 100;
-            this.bytesUploaded = 0;
-            this.resultMetaData.timeElapsed = 0;
-            return;
-        }
- 
-        const files: SourceTargetFileNames[] = [];
-        for (const fileNameFormat of fileNames) {
-            const targetFileName = this.getTargetFileNameBeforeUpload({ sourceFileName: fileNameFormat.absolute, targetFileName: fileNameFormat.relative });
-            // add only files with a target name
-            Eif (targetFileName !== "") {
-                files.push({ sourceFileName: fileNameFormat.absolute, targetFileName });
-            }
-        }
- 
-        const options: UploadFilesCommandOptions = { files, processFileAfterUpload: this.processFileAfterUpload };
-        const uc: UploadFilesCommand = new UploadFilesCommand(this.client, options);
-        uc.execute();
- 
-        // check the processing status
-        while (uc.isFinished() !== true) {
-            this.status = uc.getStatus();
-            this.percentCompleted = uc.getPercentCompleted();
-            this.resultMetaData = uc.getResultMetaData();
-            this.bytesUploaded = uc.getBytesUploaded();
-            // wait one second
-            await (async () => { return new Promise(resolve => setTimeout(resolve, 1000)) })();
-        }
- 
-        this.status = uc.getStatus();
-        this.percentCompleted = uc.getPercentCompleted();
-        this.resultMetaData = uc.getResultMetaData();
-        this.bytesUploaded = uc.getBytesUploaded();
-        return;
-    };
-    public getBytesUploaded(): number {
-        return this.bytesUploaded;
-    }
- 
-}
- 
- -
-
- - - - - - - - - \ No newline at end of file diff --git a/docs/coverage/lcov-report/src/user.ts.html b/docs/coverage/lcov-report/src/user.ts.html deleted file mode 100644 index 8549b58d..00000000 --- a/docs/coverage/lcov-report/src/user.ts.html +++ /dev/null @@ -1,1880 +0,0 @@ - - - - - - Code coverage report for src/user.ts - - - - - - - - - -
-
-

All files / src user.ts

-
- -
- 100% - Statements - 98/98 -
- - -
- 100% - Branches - 13/13 -
- - -
- 100% - Functions - 40/40 -
- - -
- 100% - Lines - 98/98 -
- - -
-

- Press n or j to go to the next uncovered block, b, p or k for the previous block. -

-
-
-

-
1 -2 -3 -4 -5 -6 -7 -8 -9 -10 -11 -12 -13 -14 -15 -16 -17 -18 -19 -20 -21 -22 -23 -24 -25 -26 -27 -28 -29 -30 -31 -32 -33 -34 -35 -36 -37 -38 -39 -40 -41 -42 -43 -44 -45 -46 -47 -48 -49 -50 -51 -52 -53 -54 -55 -56 -57 -58 -59 -60 -61 -62 -63 -64 -65 -66 -67 -68 -69 -70 -71 -72 -73 -74 -75 -76 -77 -78 -79 -80 -81 -82 -83 -84 -85 -86 -87 -88 -89 -90 -91 -92 -93 -94 -95 -96 -97 -98 -99 -100 -101 -102 -103 -104 -105 -106 -107 -108 -109 -110 -111 -112 -113 -114 -115 -116 -117 -118 -119 -120 -121 -122 -123 -124 -125 -126 -127 -128 -129 -130 -131 -132 -133 -134 -135 -136 -137 -138 -139 -140 -141 -142 -143 -144 -145 -146 -147 -148 -149 -150 -151 -152 -153 -154 -155 -156 -157 -158 -159 -160 -161 -162 -163 -164 -165 -166 -167 -168 -169 -170 -171 -172 -173 -174 -175 -176 -177 -178 -179 -180 -181 -182 -183 -184 -185 -186 -187 -188 -189 -190 -191 -192 -193 -194 -195 -196 -197 -198 -199 -200 -201 -202 -203 -204 -205 -206 -207 -208 -209 -210 -211 -212 -213 -214 -215 -216 -217 -218 -219 -220 -221 -222 -223 -224 -225 -226 -227 -228 -229 -230 -231 -232 -233 -234 -235 -236 -237 -238 -239 -240 -241 -242 -243 -244 -245 -246 -247 -248 -249 -250 -251 -252 -253 -254 -255 -256 -257 -258 -259 -260 -261 -262 -263 -264 -265 -266 -267 -268 -269 -270 -271 -272 -273 -274 -275 -276 -277 -278 -279 -280 -281 -282 -283 -284 -285 -286 -287 -288 -289 -290 -291 -292 -293 -294 -295 -296 -297 -298 -299 -300 -301 -302 -303 -304 -305 -306 -307 -308 -309 -310 -311 -312 -313 -314 -315 -316 -317 -318 -319 -320 -321 -322 -323 -324 -325 -326 -327 -328 -329 -330 -331 -332 -333 -334 -335 -336 -337 -338 -339 -340 -341 -342 -343 -344 -345 -346 -347 -348 -349 -350 -351 -352 -353 -354 -355 -356 -357 -358 -359 -360 -361 -362 -363 -364 -365 -366 -367 -368 -369 -370 -371 -372 -373 -374 -375 -376 -377 -378 -379 -380 -381 -382 -383 -384 -385 -386 -387 -388 -389 -390 -391 -392 -393 -394 -395 -396 -397 -398 -399 -400 -401 -402 -403 -404 -405 -406 -407 -408 -409 -410 -411 -412 -413 -414 -415 -416 -417 -418 -419 -420 -421 -422 -423 -424 -425 -426 -427 -428 -429 -430 -431 -432 -433 -434 -435 -436 -437 -438 -439 -440 -441 -442 -443 -444 -445 -446 -447 -448 -449 -450 -451 -452 -453 -454 -455 -456 -457 -458 -459 -460 -461 -462 -463 -464 -465 -466 -467 -468 -469 -470 -471 -472 -473 -474 -475 -476 -477 -478 -479 -480 -481 -482 -483 -484 -485 -486 -487 -488 -489 -490 -491 -492 -493 -494 -495 -496 -497 -498 -499 -500 -501 -502 -503 -504 -505 -506 -507 -508 -509 -510 -511 -512 -513 -514 -515 -516 -517 -518 -519 -520 -521 -522 -523 -524 -525 -526 -527 -528 -529 -530 -531 -532 -533 -534 -535 -536 -537 -538 -539 -540 -541 -542 -543 -544 -545 -546 -547 -548 -549 -550 -551 -552 -553 -554 -555 -556 -557 -558 -559 -560 -561 -562 -563 -564 -565 -566 -567 -568 -569 -570 -571 -572 -573 -574 -575 -576 -577 -578 -579 -580 -581 -582 -583 -584 -585 -586 -587 -588 -589 -590 -591 -592 -593 -594 -595 -596 -597 -598 -599 -600 -6011x -1x -  -1x -1x -1x -1x -1x -1x -1x -1x -1x -1x -1x -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -1x -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -43x -43x -43x -  -  -  -  -  -  -  -  -  -  -  -  -  -17x -  -  -  -  -  -  -  -  -  -4x -4x -  -  -  -  -  -  -  -  -  -3x -3x -  -  -  -  -  -  -  -  -  -2x -2x -1x -  -1x -  -  -  -  -  -  -  -  -  -7x -  -  -  -  -  -  -  -  -  -  -  -5x -4x -  -  -  -  -  -  -  -  -  -6x -  -  -  -  -  -  -  -  -  -7x -  -7x -  -  -  -  -7x -1x -  -  -7x -1x -  -7x -  -  -  -  -  -  -  -  -  -  -  -6x -4x -  -  -  -  -  -  -  -  -  -7x -  -  -  -  -  -  -  -  -  -  -  -5x -3x -  -  -  -  -  -  -  -  -  -  -  -  -7x -  -  -  -  -  -  -  -  -  -  -  -5x -4x -  -  -  -  -  -  -  -  -  -  -  -  -7x -  -  -  -  -  -  -  -  -  -  -  -4x -3x -  -  -  -  -  -  -  -  -  -  -  -  -  -7x -  -  -  -  -  -  -  -  -  -  -  -4x -3x -  -  -  -  -  -  -  -  -  -  -  -  -  -7x -  -  -  -  -  -  -  -  -  -  -  -4x -3x -  -  -  -  -  -  -  -  -  -  -  -  -  -6x -  -  -  -  -  -  -  -  -  -  -  -5x -2x -  -  -  -  -  -  -  -  -  -  -  -  -  -6x -  -  -  -  -  -  -  -  -  -  -  -5x -2x -  -  -  -  -  -  -  -  -  -  -  -7x -  -  -  -  -  -  -  -  -  -  -  -  -  -4x -  -  -  -  -  -  -  -  -  -  -  -  -  -3x -3x -3x -3x -  -3x -  -  -  -  -  -  -  -  -  -8x -  -  -  -  -  -  -  -  -  -  -  -  -  -11x -9x -9x -  -  -  -  -  -  -  -  -  -  -  -  -  -10x -7x -7x -  -  -  -  -  -  -  -  -  -  -  -  -  -15x -  -  -  -  -  -  -  -  -  -  -  -  -2x -1x -1x -  -  -  -  -  -  -  -  -  -  -  -  -  -3x -3x -2x -  -2x -  -  -  -  -  -  -  -  -  -  -  -  -  -3x -3x -3x -3x -  -3x -  -  -  -  -  -  -  -  -  -8x -  -  -  -  -  -  -  -  -  -  -  -  -  -9x -8x -8x -  -  -  -  -  -  -  -  -  -  -  -  -  -6x -4x -4x -  -  -  -  -  -  -  -  -  -9x -  -  -  -  -  -  -  -  -  -123x -71x -  -123x -  -  -  - 
import Client, { ClientError, IQuota, UserGroup, UserGroupDoesNotExistError } from "./client";
-import FileSizeFormatter from "./fileSizeFormatter";
- 
-export enum UserProperty {
-    email = "email",
-    quota = "quota",
-    displayName = "displayname",
-    phone = "phone",
-    address = "address",
-    website = "website",
-    twitter = "twitter",
-    password = "password",
-    language = "language",
-    locale = "locale",
-}
- 
-export interface IUserOptionsQuota {
-    "free"?: number,
-    "used": number,
-    "total"?: number,
-    "relative": number,
-    "quota": number
-}
- 
-export interface IUserQuotaUserFriendly {
-    "free"?: string,
-    "used": string,
-    "total"?: string,
-    "quota": string,
-    "relative": string
-}
- 
-export interface IUserOptions {
-    "enabled": boolean;
-    "lastLogin"?: Date,
-    "subadminGroups": string[],
-    "memberGroups": string[],
-    "quota": IUserOptionsQuota,
-    "email": string,
-    "displayName": string,
-    "phone": string,
-    "address": string,
-    "website": string,
-    "twitter": string,
-    "language": string
-    "locale": string,
-}
- 
-/**
- * The user class represents a user in nextcloud.
- * async getGroups
- * async isDisabled
- * async getLastLogin
- * async getEmail
- * getId
- * async getDisplayName
- */
-export default class User {
-    // https://docs.nextcloud.com/server/latest/admin_manual/configuration_user/user_provisioning_api.html
- 
-    private memento?: IUserOptions;
-    private client: Client;
-    readonly id: string;
- 
-    /**
-     * the conscructor of the user
-     * should only me invoked by the Client
-     * @constructor
-     * @param {Client} client
-     * @param {string} id the user id
-     * @param {IUserOptions} options optional options
-     */
-    constructor(client: Client, id: string, options?: IUserOptions) {
-        this.id = id;
-        this.client = client;
-        this.memento = options;
-    }
- 
-    // **********************************
-    // enable disable
-    // **********************************
- 
-    /**
-     * returns true if the user is enabled
-     * @async
-     * @returns {Promise<boolean>} true if the user is enabled
-     * @throws {UserNotFoundError}
-     */
-    async isEnabled(): Promise<boolean> {
-        return (await this.getUserData()).enabled;
-    }
- 
-    /**
-     * disables the user
-     * @async
-     * @returns {Promise<void>}
-     * @throws {UserNotFoundError}
-     */
-    async disable(): Promise<void> {
-        delete this.memento;
-        return await this.client.disableUser(this.id);
-    }
- 
-    /**
-     * enables the user
-     * @async
-     * @returns {Promise<void>}
-     * @throws {UserNotFoundError}
-     */
-    async enable(): Promise<void> {
-        delete this.memento;
-        return await this.client.enableUser(this.id);
-    }
- 
-    /**
-     * get the last login date or null if the user has not been logged in yet
-     * @async
-     * @returns {Promise<Date | null>} last login date or null if the user has not been logged in yet
-     * @throws {UserNotFoundError}
-     */
-    async getLastLogin(): Promise<Date | null> {
-        const data: IUserOptions = await this.getUserData();
-        if (data.lastLogin) {
-            return data.lastLogin;
-        }
-        return null;
-    }
- 
-    /**
-     * returns the display name
-     * @async
-     * @returns {Promise<string>} display name
-     * @throws {UserNotFoundError}
-     */
-    async getDisplayName(): Promise<string> {
-        return (await this.getUserData()).displayName;
-    }
- 
-    /**
-     * set the display name
-     * @async
-     * @param {string} value the display name
-     * @returns {Promise<void>}
-     * @throws {UserNotFoundError}
-     * @throws {UserUpdateError}
-     */
-    async setDisplayName(value: string): Promise<void> {
-        await this.client.updateUserProperty(this.id, UserProperty.displayName, value);
-        delete this.memento;
-    }
- 
-    /**
-     * returns information on quota, usage and available space
-     * @async
-     * @returns {Promise<IUserOptionsQuota>}
-     * @throws {UserNotFoundError}
-     */
-    async getQuota(): Promise<IUserOptionsQuota> {
-        return (await this.getUserData()).quota;
-    }
- 
-    /**
-     * returns information on quota, usage and available space in a user friendly format
-     * @async
-     * @returns {Promise<IUserQuotaUserFriendly>}
-     * @throws {UserNotFoundError}
-     */
-    async getQuotaUserFriendly(): Promise<IUserQuotaUserFriendly> {
-        const q: IUserOptionsQuota = (await this.getUserData()).quota;
- 
-        const qUF: IUserQuotaUserFriendly = {
-            used: new FileSizeFormatter(q.used).getUserFriendlyFileSize(),
-            quota: new FileSizeFormatter(q.quota).getUserFriendlyFileSize(),
-            relative: Math.round(q.relative) + " %"
-        }
-        if (q.total) {
-            qUF.total = new FileSizeFormatter(q.total).getUserFriendlyFileSize();
-        }
- 
-        if (q.free) {
-            qUF.free = new FileSizeFormatter(q.free).getUserFriendlyFileSize();
-        }
-        return qUF;
-    }
- 
-    /**
-     * sets the quota limit of the user
-     * @async
-     * @param {string} value the quota string like "1 GB", "100 MB"
-     * @returns {Promise<void>}
-     * @throws {UserNotFoundError}
-     * @throws {UserUpdateError}
-     */
-    async setQuota(value: string): Promise<void> {
-        await this.client.updateUserProperty(this.id, UserProperty.quota, value);
-        delete this.memento;
-    }
- 
-    /**
-     * returns the email address
-     * @async
-     * @returns {Promise<string>} email adress
-     * @throws {UserNotFoundError}
-     */
-    async getEmail(): Promise<string> {
-        return (await this.getUserData()).email;
-    }
- 
-    /**
-     * set the email address
-     * @async
-     * @param {string} value the email address
-     * @returns {Promise<void>}
-     * @throws {UserNotFoundError}
-     * @throws {UserUpdateError}
-     */
-    async setEmail(value: string): Promise<void> {
-        await this.client.updateUserProperty(this.id, UserProperty.email, value);
-        delete this.memento;
-    }
- 
-    // **********************************
-    // phone
-    // **********************************
-    /**
-     * returns the phone number
-     * @async
-     * @returns {Promise<string>} phone number
-     * @throws {UserNotFoundError}
-     */
-    async getPhone(): Promise<string> {
-        return (await this.getUserData()).phone;
-    }
- 
-    /**
-     * set phone number
-     * @async
-     * @param {string} value the phone number
-     * @returns {Promise<void>}
-     * @throws {UserNotFoundError}
-     * @throws {UserUpdateError}
-     */
-    async setPhone(value: string): Promise<void> {
-        await this.client.updateUserProperty(this.id, UserProperty.phone, value);
-        delete this.memento;
-    }
- 
-    // **********************************
-    // address
-    // **********************************
-    /**
-     * returns the phone number
-     * @async
-     * @returns {Promise<string>} address
-     * @throws {UserNotFoundError}
-     */
-    async getAddress(): Promise<string> {
-        return (await this.getUserData()).address;
-    }
- 
-    /**
-     * set the address
-     * @async
-     * @param {string} value the address
-     * @returns {Promise<void>}
-     * @throws {UserNotFoundError}
-     * @throws {UserUpdateError}
-     */
-    async setAddress(value: string): Promise<void> {
-        await this.client.updateUserProperty(this.id, UserProperty.address, value);
-        delete this.memento;
-    }
- 
-    // **********************************
-    // website
-    // **********************************
- 
-    /**
-     * returns the website
-     * @async
-     * @returns {Promise<string>} website
-     * @throws {UserNotFoundError}
-     */
-    async getWebsite(): Promise<string> {
-        return (await this.getUserData()).website;
-    }
- 
-    /**
-     * set the website
-     * @async
-     * @param {string} value the website
-     * @returns {Promise<void>}
-     * @throws {UserNotFoundError}
-     * @throws {UserUpdateError}
-     */
-    async setWebsite(value: string): Promise<void> {
-        await this.client.updateUserProperty(this.id, UserProperty.website, value);
-        delete this.memento;
-    }
- 
-    // **********************************
-    // twitter
-    // **********************************
- 
-    /**
-     * returns the twitter handle
-     * @async
-     * @returns {Promise<string>} twitter handle
-     * @throws {UserNotFoundError}
-     */
-    async getTwitter(): Promise<string> {
-        return (await this.getUserData()).twitter;
-    }
- 
-    /**
-     * set the twitter handle
-     * @async
-     * @param {string} value the twitter handle
-     * @returns {Promise<void>}
-     * @throws {UserNotFoundError}
-     * @throws {UserUpdateError}
-     */
-    async setTwitter(value: string): Promise<void> {
-        await this.client.updateUserProperty(this.id, UserProperty.twitter, value);
-        delete this.memento;
-    }
- 
-    // **********************************
-    // language
-    // **********************************
- 
-    /**
-     * returns the langauge code
-     * @async
-     * @returns {Promise<string>} language code
-     * @throws {UserNotFoundError}
-     */
-    async getLanguage(): Promise<string> {
-        return (await this.getUserData()).language;
-    }
- 
-    /**
-     * set the language code like EN, DE, FR...
-     * @async
-     * @param {string} value the language code
-     * @returns {Promise<void>}
-     * @throws {UserNotFoundError}
-     * @throws {UserUpdateError}
-     */
-    async setLanguage(value: string): Promise<void> {
-        await this.client.updateUserProperty(this.id, UserProperty.language, value);
-        delete this.memento;
-    }
- 
-    // **********************************
-    // locale
-    // **********************************
- 
-    /**
-     * returns the locale
-     * @async
-     * @returns {Promise<string>} locale
-     * @throws {UserNotFoundError}
-     */
-    async getLocale(): Promise<string> {
-        return (await this.getUserData()).locale;
-    }
- 
-    /**
-     * set the locale like EN, DE, FR...
-     * @async
-     * @param {string} value the locale
-     * @returns {Promise<void>}
-     * @throws {UserNotFoundError}
-     * @throws {UserUpdateError}
-     */
-    async setLocale(value: string): Promise<void> {
-        await this.client.updateUserProperty(this.id, UserProperty.locale, value);
-        delete this.memento;
-    }
- 
-    /**
-     * set the password
-     * @async
-     * @param {string} value the password
-     * @returns {Promise<void>}
-     * @throws {UserNotFoundError}
-     * @throws {UserUpdateError}
-     */
-    async setPassword(value: string): Promise<void> {
-        await this.client.updateUserProperty(this.id, UserProperty.password, value);
-    }
- 
-    // **********************************
-    // Resend the welcome email
-    // **********************************
- 
-    /**
-     * resends the welcome email
-     * @async
-     * @returns {Promise<void>}
-     * @throws  {UserResendWelcomeEmailError}
-     */
-    async resendWelcomeEmail(): Promise<void> {
-        await this.client.resendWelcomeEmail(this.id);
-    }
- 
-    // **********************************
-    // user group member
-    // **********************************
- 
-    /**
-     * returns a list of user groups where the user is member
-     * @async
-     * @returns {Promise<UserGroup[]} a list of user groups where the user is member
-     * @throws {UserNotFoundError}
-     */
-    async getMemberUserGroups(): Promise<UserGroup[]> {
-        const groupIds: string[] = (await this.getUserData()).memberGroups;
-        const result: UserGroup[] = [];
-        for (const groupId of groupIds) {
-            result.push(new UserGroup(this.client, groupId));
-        }
-        return result;
-    }
- 
-    /**
-     * returns a list of user group ids where the user is member
-     * @async
-     * @returns {Promise<string[]} a list of user group ids where the user is member
-     * @throws {UserNotFoundError}
-     */
-    async getMemberUserGroupIds(): Promise<string[]> {
-        return (await this.getUserData()).memberGroups;
-    }
- 
-    /**
-     * adds the user to a user group as member
-     * @async
-     * @param {UserGroup} userGroup the user group
-     * @returns {Promise<void>}
-     * @throws {UserNotFoundError}
-     * @throws {UserGroupDoesNotExistError}
-     * @throws {InsufficientPrivilegesError}
-     * @throws {OperationFailedError}
-     */
-    async addToMemberUserGroup(userGroup: UserGroup): Promise<void> {
-        await this.client.addUserToMemberUserGroup(this.id, userGroup.id);
-        delete this.memento;
-        return;
-    }
- 
-    /**
-     * remove the user from a user group as member
-     * @async
-     * @param {UserGroup} userGroup the user group
-     * @returns {Promise<void>}
-     * @throws {UserNotFoundError}
-     * @throws {UserGroupDoesNotExistError}
-     * @throws {InsufficientPrivilegesError}
-     * @throws {OperationFailedError}
-     */
-    async removeFromMemberUserGroup(userGroup: UserGroup): Promise<void> {
-        await this.client.removeUserFromMemberUserGroup(this.id, userGroup.id);
-        delete this.memento;
-        return
-    }
- 
-    // **********************************
-    // user superadmin
-    // **********************************
- 
-    /**
-     * true if the user is a superadmin
-     * @async
-     * @returns {Promise<boolean>} true if the user is a superadmin
-     * @throws {UserNotFoundError}
-     */
-    async isSuperAdmin(): Promise<boolean> {
-        return (await this.getUserData()).memberGroups.indexOf("admin") === -1 ? false : true;
-    }
- 
-    /**
-     * promote user to super admin
-     * @async
-     * @returns {Promise<void>}
-     * @throws {UserNotFoundError}
-     * @throws {UserGroupDoesNotExistError}
-     * @throws {InsufficientPrivilegesError}
-     * @throws {OperationFailedError}
-     */
-    async promoteToSuperAdmin(): Promise<void> {
-        await this.addToMemberUserGroup(new UserGroup(this.client, "admin"));
-        delete this.memento;
-        return;
-    }
- 
-    /**
-     * demote user from being a super admin
-     * @async
-     * @returns {Promise<void>}
-     * @throws {UserNotFoundError}
-     * @throws {UserGroupDoesNotExistError}
-     * @throws {InsufficientPrivilegesError}
-     * @throws {OperationFailedError}
-     */
-    async demoteFromSuperAdmin(): Promise<void> {
-        /* istanbul ignore else */
-        if (await this.isSuperAdmin()) {
-            await this.removeFromMemberUserGroup(new UserGroup(this.client, "admin"));
-            delete this.memento;
-        }
-        return;
-    }
- 
-    // **********************************
-    // user group subadmin
-    // **********************************
- 
-    /**
-     * returns a list of user groups where the user is subadmin
-     * @async
-     * @returns {Promise<UserGroup[]} a list of user groups where the user is subadmin
-     * @throws {UserNotFoundError}
-     */
-    async getSubadminUserGroups(): Promise<UserGroup[]> {
-        const groupIds: string[] = (await this.getUserData()).subadminGroups;
-        const result: UserGroup[] = [];
-        for (const groupId of groupIds) {
-            result.push(new UserGroup(this.client, groupId));
-        }
-        return result;
-    }
- 
-    /**
-     * returns a list of user group ids where the user is subadmin
-     * @async
-     * @returns {Promise<string[]} a list of user group ids where the user is subadmin
-     * @throws {UserNotFoundError}
-     */
-    async getSubadminUserGroupIds(): Promise<string[]> {
-        return (await this.getUserData()).subadminGroups;
-    }
- 
-    /**
-     * promote the user to be a subadmin of the user group
-     * @async
-     * @param {UserGroup} userGroup the user group
-     * @returns {Promise<void>}
-     * @throws {UserNotFoundError}
-     * @throws {UserGroupDoesNotExistError}
-     * @throws {InsufficientPrivilegesError}
-     * @throws {OperationFailedError}
-     */
-    async promoteToUserGroupSubadmin(userGroup: UserGroup): Promise<void> {
-        await this.client.promoteUserToUserGroupSubadmin(this.id, userGroup.id);
-        delete this.memento;
-        return
-    }
- 
-    /**
-     * demote the user from beeing a subadmin of the user group
-     * @async
-     * @param {UserGroup} userGroup the user group
-     * @returns {Promise<void>}
-     * @throws {UserNotFoundError}
-     * @throws {UserGroupDoesNotExistError}
-     * @throws {InsufficientPrivilegesError}
-     * @throws {OperationFailedError}
-     */
-    async demoteFromSubadminUserGroup(userGroup: UserGroup): Promise<void> {
-        await this.client.demoteUserFromSubadminUserGroup(this.id, userGroup.id);
-        delete this.memento;
-        return
-    }
- 
-    /**
-     * deletes a user
-     * @async
-     * @returns {Promise<void>}
-     * @throws {UserNotFoundError}
-     */
-    async delete(): Promise<void> {
-        return await this.client.deleteUser(this.id);
-    }
- 
-    /**
-     * returns the user data
-     * @async
-     * @returns {Promise<IUserOptions>}
-     * @throws {UserNotFoundError}
-     */
-    private async getUserData(): Promise<IUserOptions> {
-        if (!this.memento) {
-            this.memento = await this.client.getUserData(this.id);
-        }
-        return this.memento;
-    }
- 
-}
- 
- -
-
- - - - - - - - - \ No newline at end of file diff --git a/docs/coverage/lcov-report/src/userGroup.ts.html b/docs/coverage/lcov-report/src/userGroup.ts.html deleted file mode 100644 index 6054fcd6..00000000 --- a/docs/coverage/lcov-report/src/userGroup.ts.html +++ /dev/null @@ -1,203 +0,0 @@ - - - - - - Code coverage report for src/userGroup.ts - - - - - - - - - -
-
-

All files / src userGroup.ts

-
- -
- 100% - Statements - 11/11 -
- - -
- 100% - Branches - 2/2 -
- - -
- 100% - Functions - 4/4 -
- - -
- 100% - Lines - 11/11 -
- - -
-

- Press n or j to go to the next uncovered block, b, p or k for the previous block. -

-
-
-

-
1 -2 -3 -4 -5 -6 -7 -8 -9 -10 -11 -12 -13 -14 -15 -16 -17 -18 -19 -20 -21 -22 -23 -24 -25 -26 -27 -28 -29 -30 -31 -32 -33 -34 -35 -36 -37 -38 -39 -40 -41 -421x -  -  -  -  -  -  -  -  -1x -  -  -  -52x -52x -  -  -  -  -  -  -  -  -4x -4x -  -2x -1x -  -1x -  -  -  -  -1x -  -  -  -1x -  -  - 
import Client, { UserGroupDeletionFailedError, UserGroupDoesNotExistError } from "./client";
- 
-/**
- * The user group class represents a user user in nextcloud.
- * spec: https://docs.nextcloud.com/server/latest/admin_manual/configuration_user/instruction_set_for_groups.html
- * id
- * getSubAdmins
- * getMembers
- */
-export default class UserGroup {
-    readonly id: string;
-    private client: Client;
-    constructor(client: Client, id: string) {
-        this.id = id;
-        this.client = client;
-    }
- 
-    /**
-     * deletes the user group
-     * @throws UserGroupDeletionFailedError
-     */
-    public async delete(): Promise<void> {
- 
-        try {
-            return await this.client.deleteUserGroup(this.id);
-        } catch (e) {
-            if (e instanceof UserGroupDoesNotExistError) {
-                return;
-            }
-            throw e;
-        }
-    }
- 
-    public async getMemberUserIds(): Promise<string[]> {
-        return await this.client.getUserGroupMembers(this.id);
-    }
- 
-    public async getSubadminUserIds(): Promise<string[]> {
-        return await this.client.getUserGroupSubadmins(this.id);
-    }
-}
- 
- -
-
- - - - - - - - - \ No newline at end of file diff --git a/docs/coverage/lcov-report/tag.ts.html b/docs/coverage/lcov-report/tag.ts.html deleted file mode 100644 index 88577822..00000000 --- a/docs/coverage/lcov-report/tag.ts.html +++ /dev/null @@ -1,158 +0,0 @@ - - - - - - Code coverage report for tag.ts - - - - - - - - - -
-
-

All files tag.ts

-
- -
- 100% - Statements - 9/9 -
- - -
- 100% - Branches - 0/0 -
- - -
- 100% - Functions - 3/3 -
- - -
- 100% - Lines - 9/9 -
- - -
-

- Press n or j to go to the next uncovered block, b, p or k for the previous block. -

-
-
-

-
1 -2 -3 -4 -5 -6 -7 -8 -9 -10 -11 -12 -13 -14 -15 -16 -17 -18 -19 -20 -21 -22 -23 -24 -25 -26 -27  -  -  -1x -  -  -  -  -  -  -  -145x -145x -145x -145x -145x -145x -  -  -22x -  -  -8x -  -  -  - 
 
-import Client from "./client";
- 
-export default class Tag {
-    public readonly id: number;
-    public readonly name: string;
-    public readonly visible: boolean;
-    public readonly assignable: boolean;
-    public readonly canAssign: boolean;
-    private client: Client;
-    constructor(client: Client, id: number, name: string, visible: boolean, assignable: boolean, canAssign: boolean) {
-        this.client = client;
-        this.name = name;
-        this.visible = visible;
-        this.assignable = assignable;
-        this.canAssign = canAssign;
-        this.id = id;
-    }
-    public async delete(): Promise<void> {
-        return await this.client.deleteTag(this.id);
-    }
-    public toString(): string {
-        return "id:" + this.id + " name:" + this.name;
-    }
- 
-}
- 
- -
-
- - - - - - - - - \ No newline at end of file diff --git a/docs/coverage/lcov-report/uploadFilesCommand.ts.html b/docs/coverage/lcov-report/uploadFilesCommand.ts.html deleted file mode 100644 index 38b29ab8..00000000 --- a/docs/coverage/lcov-report/uploadFilesCommand.ts.html +++ /dev/null @@ -1,395 +0,0 @@ - - - - - - Code coverage report for uploadFilesCommand.ts - - - - - - - - - -
-
-

All files uploadFilesCommand.ts

-
- -
- 100% - Statements - 43/43 -
- - -
- 100% - Branches - 8/8 -
- - -
- 100% - Functions - 3/3 -
- - -
- 100% - Lines - 43/43 -
- - -
-

- Press n or j to go to the next uncovered block, b, p or k for the previous block. -

-
-
-

-
1 -2 -3 -4 -5 -6 -7 -8 -9 -10 -11 -12 -13 -14 -15 -16 -17 -18 -19 -20 -21 -22 -23 -24 -25 -26 -27 -28 -29 -30 -31 -32 -33 -34 -35 -36 -37 -38 -39 -40 -41 -42 -43 -44 -45 -46 -47 -48 -49 -50 -51 -52 -53 -54 -55 -56 -57 -58 -59 -60 -61 -62 -63 -64 -65 -66 -67 -68 -69 -70 -71 -72 -73 -74 -75 -76 -77 -78 -79 -80 -81 -82 -83 -84 -85 -86 -87 -88 -89 -90 -91 -92 -93 -94 -95 -96 -97 -98 -99 -100 -101 -102 -103 -104 -105 -106  -1x -  -  -1x -1x -1x -  -  -  -  -  -  -  -  -  -  -  -  -  -  -1x -  -  -  -  -  -  -  -  -  -  -9x -9x -9x -9x -  -  -  -  -  -  -  -  -9x -9x -9x -9x -9x -  -9x -9x -1x -  -  -  -  -9x -  -60x -60x -60x -59x -59x -58x -58x -  -1x -1x -  -  -1x -  -  -60x -60x -60x -  -60x -2x -  -  -  -  -1x -1x -1x -  -9x -3x -  -6x -  -9x -  -9x -  -9x -  -  -  -7x -  -  -  - 
// tslint:disable-next-line:no-var-requires
-const debug = require("debug").debug("UploadFilesCommand");
- 
-import Client, { File } from "./client";
-import Command, { CommandStatus } from "./command";
-import util from "util";
-import fs from "fs";
- 
-export interface SourceTargetFileNames {
-    sourceFileName: string;
-    targetFileName: string;
-}
- 
-export interface UploadFilesCommandOptions {
-    files: SourceTargetFileNames[];
-    processFileAfterUpload?: (file: File) => Promise<void>;
-}
- 
-/**
- * Command to upload a set or files from local file system to nextcloud
- */
-export default class UploadFilesCommand extends Command {
-    private files: SourceTargetFileNames[];
-    private processFileAfterUpload?: (file: File) => Promise<void>;
-    private bytesUploaded: number;
- 
-    /**
-     * @param {Client} client the client
-     * @param {SourceTargetFileNames[]} files the files to be uploaded
-     * @param {(file: File) => void} processAfterUpload callback function to process the uploaded file
-     */
-    constructor(client: Client, options: UploadFilesCommandOptions) {
-        super(client);
-        this.files = options.files;
-        this.bytesUploaded = 0;
-        this.processFileAfterUpload = options.processFileAfterUpload;
-    }
- 
-    /**
-     * execute the command
-     * @async
-     * @returns {Promise<void>}
-     */
-    protected async onExecute(): Promise<void> {
-        this.status = CommandStatus.running;
-        const startTime = new Date();
-        try {
-            const readfile = util.promisify(fs.readFile);
-            let countCompleted = 0;
- 
-            this.percentCompleted = 0;
-            if (this.files.length === 0) {
-                this.percentCompleted = 100;
-            }
- 
-            let newFile: File | null;
- 
-            for (const file of this.files) {
-                let data: Buffer;
-                newFile = null;
-                try {
-                    data = await readfile(file.sourceFileName);
-                    try {
-                        newFile = await this.client.createFile(file.targetFileName, data);
-                        this.resultMetaData.messages.push(`${file.targetFileName}`);
-                        this.bytesUploaded += data.length;
-                    } catch (e) {
-                        this.resultMetaData.errors.push(`${file.targetFileName}: ${e.message}`);
-                        debug(file.targetFileName, e);
-                    }
-                } catch (e) {
-                    this.resultMetaData.errors.push(`${file.targetFileName}: ${e.message}`);
-                }
- 
-                countCompleted++;
-                this.percentCompleted = Math.round(countCompleted / this.files.length * 100);
-                debug(" completed:" + this.percentCompleted + "%");
- 
-                if (newFile && this.processFileAfterUpload) {
-                    await this.processFileAfterUpload(newFile);
-                }
-            }
- 
-        } catch (e) {
-            debug(e.message);
-            this.resultMetaData.errors.push(e.message);
-            this.percentCompleted = 100;
-        }
-        if (this.resultMetaData.errors.length > 0) {
-            this.status = CommandStatus.failed;
-        } else {
-            this.status = CommandStatus.success;
-        }
-        this.resultMetaData.timeElapsed = new Date().getTime() - startTime.getTime();
- 
-        debug("execute finished", this.percentCompleted, this.status);
- 
-        return;
-    };
- 
-    public getBytesUploaded(): number {
-        return this.bytesUploaded;
-    }
- 
-}
- 
- -
-
- - - - - - - - - \ No newline at end of file diff --git a/docs/coverage/lcov-report/uploadFolderCommand.ts.html b/docs/coverage/lcov-report/uploadFolderCommand.ts.html deleted file mode 100644 index 6d3d5228..00000000 --- a/docs/coverage/lcov-report/uploadFolderCommand.ts.html +++ /dev/null @@ -1,413 +0,0 @@ - - - - - - Code coverage report for uploadFolderCommand.ts - - - - - - - - - -
-
-

All files uploadFolderCommand.ts

-
- -
- 100% - Statements - 46/46 -
- - -
- 100% - Branches - 4/4 -
- - -
- 100% - Functions - 7/7 -
- - -
- 100% - Lines - 42/42 -
- - -
-

- Press n or j to go to the next uncovered block, b, p or k for the previous block. -

-
-
-

-
1 -2 -3 -4 -5 -6 -7 -8 -9 -10 -11 -12 -13 -14 -15 -16 -17 -18 -19 -20 -21 -22 -23 -24 -25 -26 -27 -28 -29 -30 -31 -32 -33 -34 -35 -36 -37 -38 -39 -40 -41 -42 -43 -44 -45 -46 -47 -48 -49 -50 -51 -52 -53 -54 -55 -56 -57 -58 -59 -60 -61 -62 -63 -64 -65 -66 -67 -68 -69 -70 -71 -72 -73 -74 -75 -76 -77 -78 -79 -80 -81 -82 -83 -84 -85 -86 -87 -88 -89 -90 -91 -92 -93 -94 -95 -96 -97 -98 -99 -100 -101 -102 -103 -104 -105 -106 -107 -108 -109 -110 -111 -112  -1x -  -1x -  -  -  -  -  -  -  -  -1x -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -1x -  -  -  -  -  -  -  -  -  -  -  -5x -5x -5x -5x -3x -  -14x -  -5x -  -  -  -  -  -  -  -  -5x -5x -5x -5x -5x -  -1x -1x -1x -1x -1x -1x -  -  -4x -4x -56x -  -56x -42x -  -  -  -4x -4x -4x -  -  -4x -3x -3x -3x -3x -  -3x -  -  -4x -4x -4x -4x -4x -  -  -1x -  -  -  - 
// tslint:disable-next-line:no-var-requires
-const debug = require("debug").debug("UploadFolderCommand");
- 
-import Client,
-{
-    File,
-    FileSystemFolder,
-    IFileNameFormats,
-    UploadFilesCommand,
-    UploadFilesCommandOptions,
-    SourceTargetFileNames,
-} from "./client";
-import Command, { CommandStatus } from "./command";
- 
-/**
- * options to create a upload folder command
- */
-export interface UploadFolderCommandOptions {
-    /**
-     * The name of the source folder with the file structure to be uploaded
-     */
-    folderName: string;
-    /**
-     * the function to determine the target file name having the sourece file name.
-     * If the file should not be uploaded, return an empty string
-     * @param {SourceTargetFileNames} fileNames
-     */
-    getTargetFileNameBeforeUpload?: (fileNames: SourceTargetFileNames) => string;
-    processFileAfterUpload?: (file: File) => Promise<void>;
-}
- 
-/**
- * Command to upload the contents of a folder from local file system to nextcloud recursively
- */
-export default class UploadFolderCommand extends Command {
-    private folderName: string;
-    private processFileAfterUpload?: (file: File) => Promise<void>;
-    private getTargetFileNameBeforeUpload: (fileNames: SourceTargetFileNames) => string;
-    private bytesUploaded: number;
- 
-    /**
-     * @param {Client} client the client
-     * @param {ISourceTargetFileNames[]} files the files to be uploaded
-     * @param {(file: File) => void} processAfterUpload callback function to process the uploaded file
-     */
-    constructor(client: Client, options: UploadFolderCommandOptions) {
-        super(client);
-        this.folderName = options.folderName;
-        this.processFileAfterUpload = options.processFileAfterUpload;
-        if (options.getTargetFileNameBeforeUpload) {
-            this.getTargetFileNameBeforeUpload = options.getTargetFileNameBeforeUpload;
-        } else {
-            this.getTargetFileNameBeforeUpload = (fileNames: SourceTargetFileNames): string => { return fileNames.targetFileName };
-        }
-        this.bytesUploaded = 0;
-    }
- 
-    /**
-     * execute the command
-     * @async
-     * @returns {Promise<void>}
-     */
-    protected async onExecute(): Promise<void> {
-        this.status = CommandStatus.running;
-        let fileNames: IFileNameFormats[] = [];
-        const fsf: FileSystemFolder = new FileSystemFolder(this.folderName);
-        try {
-            fileNames = await fsf.getFileNames();
-        } catch (e) {
-            this.resultMetaData.errors.push(e);
-            this.status = CommandStatus.failed;
-            this.percentCompleted = 100;
-            this.bytesUploaded = 0;
-            this.resultMetaData.timeElapsed = 0;
-            return;
-        }
- 
-        const files: SourceTargetFileNames[] = [];
-        for (const fileNameFormat of fileNames) {
-            const targetFileName = this.getTargetFileNameBeforeUpload({ sourceFileName: fileNameFormat.absolute, targetFileName: fileNameFormat.relative });
-            // add only files with a target name
-            if (targetFileName !== "") {
-                files.push({ sourceFileName: fileNameFormat.absolute, targetFileName });
-            }
-        }
- 
-        const options: UploadFilesCommandOptions = { files, processFileAfterUpload: this.processFileAfterUpload };
-        const uc: UploadFilesCommand = new UploadFilesCommand(this.client, options);
-        uc.execute();
- 
-        // check the processing status
-        while (uc.isFinished() !== true) {
-            this.status = uc.getStatus();
-            this.percentCompleted = uc.getPercentCompleted();
-            this.resultMetaData = uc.getResultMetaData();
-            this.bytesUploaded = uc.getBytesUploaded();
-            // wait one second
-            await (async () => { return new Promise(resolve => setTimeout(resolve, 1000)) })();
-        }
- 
-        this.status = uc.getStatus();
-        this.percentCompleted = uc.getPercentCompleted();
-        this.resultMetaData = uc.getResultMetaData();
-        this.bytesUploaded = uc.getBytesUploaded();
-        return;
-    };
-    public getBytesUploaded(): number {
-        return this.bytesUploaded;
-    }
- 
-}
- 
- -
-
- - - - - - - - - \ No newline at end of file diff --git a/docs/coverage/lcov-report/user.ts.html b/docs/coverage/lcov-report/user.ts.html deleted file mode 100644 index 7ac0f967..00000000 --- a/docs/coverage/lcov-report/user.ts.html +++ /dev/null @@ -1,1880 +0,0 @@ - - - - - - Code coverage report for user.ts - - - - - - - - - -
-
-

All files user.ts

-
- -
- 100% - Statements - 98/98 -
- - -
- 100% - Branches - 13/13 -
- - -
- 100% - Functions - 40/40 -
- - -
- 100% - Lines - 98/98 -
- - -
-

- Press n or j to go to the next uncovered block, b, p or k for the previous block. -

-
-
-

-
1 -2 -3 -4 -5 -6 -7 -8 -9 -10 -11 -12 -13 -14 -15 -16 -17 -18 -19 -20 -21 -22 -23 -24 -25 -26 -27 -28 -29 -30 -31 -32 -33 -34 -35 -36 -37 -38 -39 -40 -41 -42 -43 -44 -45 -46 -47 -48 -49 -50 -51 -52 -53 -54 -55 -56 -57 -58 -59 -60 -61 -62 -63 -64 -65 -66 -67 -68 -69 -70 -71 -72 -73 -74 -75 -76 -77 -78 -79 -80 -81 -82 -83 -84 -85 -86 -87 -88 -89 -90 -91 -92 -93 -94 -95 -96 -97 -98 -99 -100 -101 -102 -103 -104 -105 -106 -107 -108 -109 -110 -111 -112 -113 -114 -115 -116 -117 -118 -119 -120 -121 -122 -123 -124 -125 -126 -127 -128 -129 -130 -131 -132 -133 -134 -135 -136 -137 -138 -139 -140 -141 -142 -143 -144 -145 -146 -147 -148 -149 -150 -151 -152 -153 -154 -155 -156 -157 -158 -159 -160 -161 -162 -163 -164 -165 -166 -167 -168 -169 -170 -171 -172 -173 -174 -175 -176 -177 -178 -179 -180 -181 -182 -183 -184 -185 -186 -187 -188 -189 -190 -191 -192 -193 -194 -195 -196 -197 -198 -199 -200 -201 -202 -203 -204 -205 -206 -207 -208 -209 -210 -211 -212 -213 -214 -215 -216 -217 -218 -219 -220 -221 -222 -223 -224 -225 -226 -227 -228 -229 -230 -231 -232 -233 -234 -235 -236 -237 -238 -239 -240 -241 -242 -243 -244 -245 -246 -247 -248 -249 -250 -251 -252 -253 -254 -255 -256 -257 -258 -259 -260 -261 -262 -263 -264 -265 -266 -267 -268 -269 -270 -271 -272 -273 -274 -275 -276 -277 -278 -279 -280 -281 -282 -283 -284 -285 -286 -287 -288 -289 -290 -291 -292 -293 -294 -295 -296 -297 -298 -299 -300 -301 -302 -303 -304 -305 -306 -307 -308 -309 -310 -311 -312 -313 -314 -315 -316 -317 -318 -319 -320 -321 -322 -323 -324 -325 -326 -327 -328 -329 -330 -331 -332 -333 -334 -335 -336 -337 -338 -339 -340 -341 -342 -343 -344 -345 -346 -347 -348 -349 -350 -351 -352 -353 -354 -355 -356 -357 -358 -359 -360 -361 -362 -363 -364 -365 -366 -367 -368 -369 -370 -371 -372 -373 -374 -375 -376 -377 -378 -379 -380 -381 -382 -383 -384 -385 -386 -387 -388 -389 -390 -391 -392 -393 -394 -395 -396 -397 -398 -399 -400 -401 -402 -403 -404 -405 -406 -407 -408 -409 -410 -411 -412 -413 -414 -415 -416 -417 -418 -419 -420 -421 -422 -423 -424 -425 -426 -427 -428 -429 -430 -431 -432 -433 -434 -435 -436 -437 -438 -439 -440 -441 -442 -443 -444 -445 -446 -447 -448 -449 -450 -451 -452 -453 -454 -455 -456 -457 -458 -459 -460 -461 -462 -463 -464 -465 -466 -467 -468 -469 -470 -471 -472 -473 -474 -475 -476 -477 -478 -479 -480 -481 -482 -483 -484 -485 -486 -487 -488 -489 -490 -491 -492 -493 -494 -495 -496 -497 -498 -499 -500 -501 -502 -503 -504 -505 -506 -507 -508 -509 -510 -511 -512 -513 -514 -515 -516 -517 -518 -519 -520 -521 -522 -523 -524 -525 -526 -527 -528 -529 -530 -531 -532 -533 -534 -535 -536 -537 -538 -539 -540 -541 -542 -543 -544 -545 -546 -547 -548 -549 -550 -551 -552 -553 -554 -555 -556 -557 -558 -559 -560 -561 -562 -563 -564 -565 -566 -567 -568 -569 -570 -571 -572 -573 -574 -575 -576 -577 -578 -579 -580 -581 -582 -583 -584 -585 -586 -587 -588 -589 -590 -591 -592 -593 -594 -595 -596 -597 -598 -599 -600 -6011x -1x -  -1x -1x -1x -1x -1x -1x -1x -1x -1x -1x -1x -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -1x -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -43x -43x -43x -  -  -  -  -  -  -  -  -  -  -  -  -  -17x -  -  -  -  -  -  -  -  -  -4x -4x -  -  -  -  -  -  -  -  -  -3x -3x -  -  -  -  -  -  -  -  -  -2x -2x -1x -  -1x -  -  -  -  -  -  -  -  -  -7x -  -  -  -  -  -  -  -  -  -  -  -5x -4x -  -  -  -  -  -  -  -  -  -6x -  -  -  -  -  -  -  -  -  -7x -  -7x -  -  -  -  -7x -1x -  -  -7x -1x -  -7x -  -  -  -  -  -  -  -  -  -  -  -6x -4x -  -  -  -  -  -  -  -  -  -7x -  -  -  -  -  -  -  -  -  -  -  -5x -3x -  -  -  -  -  -  -  -  -  -  -  -  -7x -  -  -  -  -  -  -  -  -  -  -  -5x -4x -  -  -  -  -  -  -  -  -  -  -  -  -7x -  -  -  -  -  -  -  -  -  -  -  -4x -3x -  -  -  -  -  -  -  -  -  -  -  -  -  -7x -  -  -  -  -  -  -  -  -  -  -  -4x -3x -  -  -  -  -  -  -  -  -  -  -  -  -  -7x -  -  -  -  -  -  -  -  -  -  -  -4x -3x -  -  -  -  -  -  -  -  -  -  -  -  -  -6x -  -  -  -  -  -  -  -  -  -  -  -5x -2x -  -  -  -  -  -  -  -  -  -  -  -  -  -6x -  -  -  -  -  -  -  -  -  -  -  -5x -2x -  -  -  -  -  -  -  -  -  -  -  -7x -  -  -  -  -  -  -  -  -  -  -  -  -  -4x -  -  -  -  -  -  -  -  -  -  -  -  -  -3x -3x -3x -3x -  -3x -  -  -  -  -  -  -  -  -  -8x -  -  -  -  -  -  -  -  -  -  -  -  -  -11x -9x -9x -  -  -  -  -  -  -  -  -  -  -  -  -  -10x -7x -7x -  -  -  -  -  -  -  -  -  -  -  -  -  -15x -  -  -  -  -  -  -  -  -  -  -  -  -2x -1x -1x -  -  -  -  -  -  -  -  -  -  -  -  -  -3x -3x -2x -  -2x -  -  -  -  -  -  -  -  -  -  -  -  -  -3x -3x -3x -3x -  -3x -  -  -  -  -  -  -  -  -  -8x -  -  -  -  -  -  -  -  -  -  -  -  -  -9x -8x -8x -  -  -  -  -  -  -  -  -  -  -  -  -  -6x -4x -4x -  -  -  -  -  -  -  -  -  -9x -  -  -  -  -  -  -  -  -  -123x -71x -  -123x -  -  -  - 
import Client, { ClientError, IQuota, UserGroup, UserGroupDoesNotExistError } from "./client";
-import FileSizeFormatter from "./fileSizeFormatter";
- 
-export enum UserProperty {
-    email = "email",
-    quota = "quota",
-    displayName = "displayname",
-    phone = "phone",
-    address = "address",
-    website = "website",
-    twitter = "twitter",
-    password = "password",
-    language = "language",
-    locale = "locale",
-}
- 
-export interface IUserOptionsQuota {
-    "free"?: number,
-    "used": number,
-    "total"?: number,
-    "relative": number,
-    "quota": number
-}
- 
-export interface IUserQuotaUserFriendly {
-    "free"?: string,
-    "used": string,
-    "total"?: string,
-    "quota": string,
-    "relative": string
-}
- 
-export interface IUserOptions {
-    "enabled": boolean;
-    "lastLogin"?: Date,
-    "subadminGroups": string[],
-    "memberGroups": string[],
-    "quota": IUserOptionsQuota,
-    "email": string,
-    "displayName": string,
-    "phone": string,
-    "address": string,
-    "website": string,
-    "twitter": string,
-    "language": string
-    "locale": string,
-}
- 
-/**
- * The user class represents a user in nextcloud.
- * async getGroups
- * async isDisabled
- * async getLastLogin
- * async getEmail
- * getId
- * async getDisplayName
- */
-export default class User {
-    // https://docs.nextcloud.com/server/latest/admin_manual/configuration_user/user_provisioning_api.html
- 
-    private memento?: IUserOptions;
-    private client: Client;
-    readonly id: string;
- 
-    /**
-     * the conscructor of the user
-     * should only me invoked by the Client
-     * @constructor
-     * @param {Client} client
-     * @param {string} id the user id
-     * @param {IUserOptions} options optional options
-     */
-    constructor(client: Client, id: string, options?: IUserOptions) {
-        this.id = id;
-        this.client = client;
-        this.memento = options;
-    }
- 
-    // **********************************
-    // enable disable
-    // **********************************
- 
-    /**
-     * returns true if the user is enabled
-     * @async
-     * @returns {Promise<boolean>} true if the user is enabled
-     * @throws {UserNotFoundError}
-     */
-    async isEnabled(): Promise<boolean> {
-        return (await this.getUserData()).enabled;
-    }
- 
-    /**
-     * disables the user
-     * @async
-     * @returns {Promise<void>}
-     * @throws {UserNotFoundError}
-     */
-    async disable(): Promise<void> {
-        delete this.memento;
-        return await this.client.disableUser(this.id);
-    }
- 
-    /**
-     * enables the user
-     * @async
-     * @returns {Promise<void>}
-     * @throws {UserNotFoundError}
-     */
-    async enable(): Promise<void> {
-        delete this.memento;
-        return await this.client.enableUser(this.id);
-    }
- 
-    /**
-     * get the last login date or null if the user has not been logged in yet
-     * @async
-     * @returns {Promise<Date | null>} last login date or null if the user has not been logged in yet
-     * @throws {UserNotFoundError}
-     */
-    async getLastLogin(): Promise<Date | null> {
-        const data: IUserOptions = await this.getUserData();
-        if (data.lastLogin) {
-            return data.lastLogin;
-        }
-        return null;
-    }
- 
-    /**
-     * returns the display name
-     * @async
-     * @returns {Promise<string>} display name
-     * @throws {UserNotFoundError}
-     */
-    async getDisplayName(): Promise<string> {
-        return (await this.getUserData()).displayName;
-    }
- 
-    /**
-     * set the display name
-     * @async
-     * @param {string} value the display name
-     * @returns {Promise<void>}
-     * @throws {UserNotFoundError}
-     * @throws {UserUpdateError}
-     */
-    async setDisplayName(value: string): Promise<void> {
-        await this.client.updateUserProperty(this.id, UserProperty.displayName, value);
-        delete this.memento;
-    }
- 
-    /**
-     * returns information on quota, usage and available space
-     * @async
-     * @returns {Promise<IUserOptionsQuota>}
-     * @throws {UserNotFoundError}
-     */
-    async getQuota(): Promise<IUserOptionsQuota> {
-        return (await this.getUserData()).quota;
-    }
- 
-    /**
-     * returns information on quota, usage and available space in a user friendly format
-     * @async
-     * @returns {Promise<IUserQuotaUserFriendly>}
-     * @throws {UserNotFoundError}
-     */
-    async getQuotaUserFriendly(): Promise<IUserQuotaUserFriendly> {
-        const q: IUserOptionsQuota = (await this.getUserData()).quota;
- 
-        const qUF: IUserQuotaUserFriendly = {
-            used: new FileSizeFormatter(q.used).getUserFriendlyFileSize(),
-            quota: new FileSizeFormatter(q.quota).getUserFriendlyFileSize(),
-            relative: Math.round(q.relative) + " %"
-        }
-        if (q.total) {
-            qUF.total = new FileSizeFormatter(q.total).getUserFriendlyFileSize();
-        }
- 
-        if (q.free) {
-            qUF.free = new FileSizeFormatter(q.free).getUserFriendlyFileSize();
-        }
-        return qUF;
-    }
- 
-    /**
-     * sets the quota limit of the user
-     * @async
-     * @param {string} value the quota string like "1 GB", "100 MB"
-     * @returns {Promise<void>}
-     * @throws {UserNotFoundError}
-     * @throws {UserUpdateError}
-     */
-    async setQuota(value: string): Promise<void> {
-        await this.client.updateUserProperty(this.id, UserProperty.quota, value);
-        delete this.memento;
-    }
- 
-    /**
-     * returns the email address
-     * @async
-     * @returns {Promise<string>} email adress
-     * @throws {UserNotFoundError}
-     */
-    async getEmail(): Promise<string> {
-        return (await this.getUserData()).email;
-    }
- 
-    /**
-     * set the email address
-     * @async
-     * @param {string} value the email address
-     * @returns {Promise<void>}
-     * @throws {UserNotFoundError}
-     * @throws {UserUpdateError}
-     */
-    async setEmail(value: string): Promise<void> {
-        await this.client.updateUserProperty(this.id, UserProperty.email, value);
-        delete this.memento;
-    }
- 
-    // **********************************
-    // phone
-    // **********************************
-    /**
-     * returns the phone number
-     * @async
-     * @returns {Promise<string>} phone number
-     * @throws {UserNotFoundError}
-     */
-    async getPhone(): Promise<string> {
-        return (await this.getUserData()).phone;
-    }
- 
-    /**
-     * set phone number
-     * @async
-     * @param {string} value the phone number
-     * @returns {Promise<void>}
-     * @throws {UserNotFoundError}
-     * @throws {UserUpdateError}
-     */
-    async setPhone(value: string): Promise<void> {
-        await this.client.updateUserProperty(this.id, UserProperty.phone, value);
-        delete this.memento;
-    }
- 
-    // **********************************
-    // address
-    // **********************************
-    /**
-     * returns the phone number
-     * @async
-     * @returns {Promise<string>} address
-     * @throws {UserNotFoundError}
-     */
-    async getAddress(): Promise<string> {
-        return (await this.getUserData()).address;
-    }
- 
-    /**
-     * set the address
-     * @async
-     * @param {string} value the address
-     * @returns {Promise<void>}
-     * @throws {UserNotFoundError}
-     * @throws {UserUpdateError}
-     */
-    async setAddress(value: string): Promise<void> {
-        await this.client.updateUserProperty(this.id, UserProperty.address, value);
-        delete this.memento;
-    }
- 
-    // **********************************
-    // website
-    // **********************************
- 
-    /**
-     * returns the website
-     * @async
-     * @returns {Promise<string>} website
-     * @throws {UserNotFoundError}
-     */
-    async getWebsite(): Promise<string> {
-        return (await this.getUserData()).website;
-    }
- 
-    /**
-     * set the website
-     * @async
-     * @param {string} value the website
-     * @returns {Promise<void>}
-     * @throws {UserNotFoundError}
-     * @throws {UserUpdateError}
-     */
-    async setWebsite(value: string): Promise<void> {
-        await this.client.updateUserProperty(this.id, UserProperty.website, value);
-        delete this.memento;
-    }
- 
-    // **********************************
-    // twitter
-    // **********************************
- 
-    /**
-     * returns the twitter handle
-     * @async
-     * @returns {Promise<string>} twitter handle
-     * @throws {UserNotFoundError}
-     */
-    async getTwitter(): Promise<string> {
-        return (await this.getUserData()).twitter;
-    }
- 
-    /**
-     * set the twitter handle
-     * @async
-     * @param {string} value the twitter handle
-     * @returns {Promise<void>}
-     * @throws {UserNotFoundError}
-     * @throws {UserUpdateError}
-     */
-    async setTwitter(value: string): Promise<void> {
-        await this.client.updateUserProperty(this.id, UserProperty.twitter, value);
-        delete this.memento;
-    }
- 
-    // **********************************
-    // language
-    // **********************************
- 
-    /**
-     * returns the langauge code
-     * @async
-     * @returns {Promise<string>} language code
-     * @throws {UserNotFoundError}
-     */
-    async getLanguage(): Promise<string> {
-        return (await this.getUserData()).language;
-    }
- 
-    /**
-     * set the language code like EN, DE, FR...
-     * @async
-     * @param {string} value the language code
-     * @returns {Promise<void>}
-     * @throws {UserNotFoundError}
-     * @throws {UserUpdateError}
-     */
-    async setLanguage(value: string): Promise<void> {
-        await this.client.updateUserProperty(this.id, UserProperty.language, value);
-        delete this.memento;
-    }
- 
-    // **********************************
-    // locale
-    // **********************************
- 
-    /**
-     * returns the locale
-     * @async
-     * @returns {Promise<string>} locale
-     * @throws {UserNotFoundError}
-     */
-    async getLocale(): Promise<string> {
-        return (await this.getUserData()).locale;
-    }
- 
-    /**
-     * set the locale like EN, DE, FR...
-     * @async
-     * @param {string} value the locale
-     * @returns {Promise<void>}
-     * @throws {UserNotFoundError}
-     * @throws {UserUpdateError}
-     */
-    async setLocale(value: string): Promise<void> {
-        await this.client.updateUserProperty(this.id, UserProperty.locale, value);
-        delete this.memento;
-    }
- 
-    /**
-     * set the password
-     * @async
-     * @param {string} value the password
-     * @returns {Promise<void>}
-     * @throws {UserNotFoundError}
-     * @throws {UserUpdateError}
-     */
-    async setPassword(value: string): Promise<void> {
-        await this.client.updateUserProperty(this.id, UserProperty.password, value);
-    }
- 
-    // **********************************
-    // Resend the welcome email
-    // **********************************
- 
-    /**
-     * resends the welcome email
-     * @async
-     * @returns {Promise<void>}
-     * @throws  {UserResendWelcomeEmailError}
-     */
-    async resendWelcomeEmail(): Promise<void> {
-        await this.client.resendWelcomeEmail(this.id);
-    }
- 
-    // **********************************
-    // user group member
-    // **********************************
- 
-    /**
-     * returns a list of user groups where the user is member
-     * @async
-     * @returns {Promise<UserGroup[]} a list of user groups where the user is member
-     * @throws {UserNotFoundError}
-     */
-    async getMemberUserGroups(): Promise<UserGroup[]> {
-        const groupIds: string[] = (await this.getUserData()).memberGroups;
-        const result: UserGroup[] = [];
-        for (const groupId of groupIds) {
-            result.push(new UserGroup(this.client, groupId));
-        }
-        return result;
-    }
- 
-    /**
-     * returns a list of user group ids where the user is member
-     * @async
-     * @returns {Promise<string[]} a list of user group ids where the user is member
-     * @throws {UserNotFoundError}
-     */
-    async getMemberUserGroupIds(): Promise<string[]> {
-        return (await this.getUserData()).memberGroups;
-    }
- 
-    /**
-     * adds the user to a user group as member
-     * @async
-     * @param {UserGroup} userGroup the user group
-     * @returns {Promise<void>}
-     * @throws {UserNotFoundError}
-     * @throws {UserGroupDoesNotExistError}
-     * @throws {InsufficientPrivilegesError}
-     * @throws {OperationFailedError}
-     */
-    async addToMemberUserGroup(userGroup: UserGroup): Promise<void> {
-        await this.client.addUserToMemberUserGroup(this.id, userGroup.id);
-        delete this.memento;
-        return;
-    }
- 
-    /**
-     * remove the user from a user group as member
-     * @async
-     * @param {UserGroup} userGroup the user group
-     * @returns {Promise<void>}
-     * @throws {UserNotFoundError}
-     * @throws {UserGroupDoesNotExistError}
-     * @throws {InsufficientPrivilegesError}
-     * @throws {OperationFailedError}
-     */
-    async removeFromMemberUserGroup(userGroup: UserGroup): Promise<void> {
-        await this.client.removeUserFromMemberUserGroup(this.id, userGroup.id);
-        delete this.memento;
-        return
-    }
- 
-    // **********************************
-    // user superadmin
-    // **********************************
- 
-    /**
-     * true if the user is a superadmin
-     * @async
-     * @returns {Promise<boolean>} true if the user is a superadmin
-     * @throws {UserNotFoundError}
-     */
-    async isSuperAdmin(): Promise<boolean> {
-        return (await this.getUserData()).memberGroups.indexOf("admin") === -1 ? false : true;
-    }
- 
-    /**
-     * promote user to super admin
-     * @async
-     * @returns {Promise<void>}
-     * @throws {UserNotFoundError}
-     * @throws {UserGroupDoesNotExistError}
-     * @throws {InsufficientPrivilegesError}
-     * @throws {OperationFailedError}
-     */
-    async promoteToSuperAdmin(): Promise<void> {
-        await this.addToMemberUserGroup(new UserGroup(this.client, "admin"));
-        delete this.memento;
-        return;
-    }
- 
-    /**
-     * demote user from being a super admin
-     * @async
-     * @returns {Promise<void>}
-     * @throws {UserNotFoundError}
-     * @throws {UserGroupDoesNotExistError}
-     * @throws {InsufficientPrivilegesError}
-     * @throws {OperationFailedError}
-     */
-    async demoteFromSuperAdmin(): Promise<void> {
-        /* istanbul ignore else */
-        if (await this.isSuperAdmin()) {
-            await this.removeFromMemberUserGroup(new UserGroup(this.client, "admin"));
-            delete this.memento;
-        }
-        return;
-    }
- 
-    // **********************************
-    // user group subadmin
-    // **********************************
- 
-    /**
-     * returns a list of user groups where the user is subadmin
-     * @async
-     * @returns {Promise<UserGroup[]} a list of user groups where the user is subadmin
-     * @throws {UserNotFoundError}
-     */
-    async getSubadminUserGroups(): Promise<UserGroup[]> {
-        const groupIds: string[] = (await this.getUserData()).subadminGroups;
-        const result: UserGroup[] = [];
-        for (const groupId of groupIds) {
-            result.push(new UserGroup(this.client, groupId));
-        }
-        return result;
-    }
- 
-    /**
-     * returns a list of user group ids where the user is subadmin
-     * @async
-     * @returns {Promise<string[]} a list of user group ids where the user is subadmin
-     * @throws {UserNotFoundError}
-     */
-    async getSubadminUserGroupIds(): Promise<string[]> {
-        return (await this.getUserData()).subadminGroups;
-    }
- 
-    /**
-     * promote the user to be a subadmin of the user group
-     * @async
-     * @param {UserGroup} userGroup the user group
-     * @returns {Promise<void>}
-     * @throws {UserNotFoundError}
-     * @throws {UserGroupDoesNotExistError}
-     * @throws {InsufficientPrivilegesError}
-     * @throws {OperationFailedError}
-     */
-    async promoteToUserGroupSubadmin(userGroup: UserGroup): Promise<void> {
-        await this.client.promoteUserToUserGroupSubadmin(this.id, userGroup.id);
-        delete this.memento;
-        return
-    }
- 
-    /**
-     * demote the user from beeing a subadmin of the user group
-     * @async
-     * @param {UserGroup} userGroup the user group
-     * @returns {Promise<void>}
-     * @throws {UserNotFoundError}
-     * @throws {UserGroupDoesNotExistError}
-     * @throws {InsufficientPrivilegesError}
-     * @throws {OperationFailedError}
-     */
-    async demoteFromSubadminUserGroup(userGroup: UserGroup): Promise<void> {
-        await this.client.demoteUserFromSubadminUserGroup(this.id, userGroup.id);
-        delete this.memento;
-        return
-    }
- 
-    /**
-     * deletes a user
-     * @async
-     * @returns {Promise<void>}
-     * @throws {UserNotFoundError}
-     */
-    async delete(): Promise<void> {
-        return await this.client.deleteUser(this.id);
-    }
- 
-    /**
-     * returns the user data
-     * @async
-     * @returns {Promise<IUserOptions>}
-     * @throws {UserNotFoundError}
-     */
-    private async getUserData(): Promise<IUserOptions> {
-        if (!this.memento) {
-            this.memento = await this.client.getUserData(this.id);
-        }
-        return this.memento;
-    }
- 
-}
- 
- -
-
- - - - - - - - - \ No newline at end of file diff --git a/docs/coverage/lcov-report/userGroup.ts.html b/docs/coverage/lcov-report/userGroup.ts.html deleted file mode 100644 index e762b487..00000000 --- a/docs/coverage/lcov-report/userGroup.ts.html +++ /dev/null @@ -1,203 +0,0 @@ - - - - - - Code coverage report for userGroup.ts - - - - - - - - - -
-
-

All files userGroup.ts

-
- -
- 100% - Statements - 11/11 -
- - -
- 100% - Branches - 2/2 -
- - -
- 100% - Functions - 4/4 -
- - -
- 100% - Lines - 11/11 -
- - -
-

- Press n or j to go to the next uncovered block, b, p or k for the previous block. -

-
-
-

-
1 -2 -3 -4 -5 -6 -7 -8 -9 -10 -11 -12 -13 -14 -15 -16 -17 -18 -19 -20 -21 -22 -23 -24 -25 -26 -27 -28 -29 -30 -31 -32 -33 -34 -35 -36 -37 -38 -39 -40 -41 -421x -  -  -  -  -  -  -  -  -1x -  -  -  -52x -52x -  -  -  -  -  -  -  -  -4x -4x -  -2x -1x -  -1x -  -  -  -  -1x -  -  -  -1x -  -  - 
import Client, { UserGroupDeletionFailedError, UserGroupDoesNotExistError } from "./client";
- 
-/**
- * The user group class represents a user user in nextcloud.
- * spec: https://docs.nextcloud.com/server/latest/admin_manual/configuration_user/instruction_set_for_groups.html
- * id
- * getSubAdmins
- * getMembers
- */
-export default class UserGroup {
-    readonly id: string;
-    private client: Client;
-    constructor(client: Client, id: string) {
-        this.id = id;
-        this.client = client;
-    }
- 
-    /**
-     * deletes the user group
-     * @throws UserGroupDeletionFailedError
-     */
-    public async delete(): Promise<void> {
- 
-        try {
-            return await this.client.deleteUserGroup(this.id);
-        } catch (e) {
-            if (e instanceof UserGroupDoesNotExistError) {
-                return;
-            }
-            throw e;
-        }
-    }
- 
-    public async getMemberUserIds(): Promise<string[]> {
-        return await this.client.getUserGroupMembers(this.id);
-    }
- 
-    public async getSubadminUserIds(): Promise<string[]> {
-        return await this.client.getUserGroupSubadmins(this.id);
-    }
-}
- 
- -
-
- - - - - - - - - \ No newline at end of file diff --git a/docs/coverage/lcov.info b/docs/coverage/lcov.info deleted file mode 100644 index 89cf60f7..00000000 --- a/docs/coverage/lcov.info +++ /dev/null @@ -1,3303 +0,0 @@ -TN: -SF:src\client.ts -FN:106,(anonymous_14) -FN:52,(anonymous_15) -FN:56,(anonymous_16) -FN:57,(anonymous_17) -FN:54,(anonymous_18) -FN:53,(anonymous_19) -FN:55,(anonymous_20) -FN:63,(anonymous_21) -FN:64,(anonymous_22) -FN:61,(anonymous_23) -FN:65,(anonymous_24) -FN:58,(anonymous_25) -FN:59,(anonymous_26) -FN:60,(anonymous_27) -FN:62,(anonymous_28) -FN:81,(anonymous_29) -FN:89,(anonymous_30) -FN:86,(anonymous_31) -FN:217,(anonymous_32) -FN:290,(anonymous_33) -FN:331,(anonymous_35) -FN:369,(anonymous_37) -FN:386,(anonymous_39) -FN:403,(anonymous_41) -FN:417,(anonymous_43) -FN:432,(anonymous_45) -FN:467,(anonymous_47) -FN:504,(anonymous_49) -FN:519,(anonymous_51) -FN:550,(anonymous_53) -FN:636,(anonymous_55) -FN:700,(anonymous_57) -FN:719,(anonymous_59) -FN:734,(anonymous_61) -FN:744,(anonymous_62) -FN:811,(anonymous_64) -FN:840,(anonymous_66) -FN:862,(anonymous_68) -FN:891,(anonymous_70) -FN:917,(anonymous_72) -FN:940,(anonymous_74) -FN:971,(anonymous_76) -FN:1002,(anonymous_78) -FN:1024,(anonymous_80) -FN:1045,(anonymous_82) -FN:1054,(anonymous_83) -FN:1068,(anonymous_84) -FN:1138,(anonymous_86) -FN:1166,(anonymous_88) -FN:1199,(anonymous_90) -FN:1269,(anonymous_92) -FN:1315,(anonymous_94) -FN:1335,(anonymous_96) -FN:1385,(anonymous_98) -FN:1398,(anonymous_99) -FN:1412,(anonymous_101) -FN:1433,(anonymous_103) -FN:1447,(anonymous_104) -FN:1468,(anonymous_106) -FN:1483,(anonymous_107) -FN:1511,(anonymous_109) -FN:1542,(anonymous_111) -FN:1592,(anonymous_113) -FN:1606,(anonymous_114) -FN:1682,(anonymous_116) -FN:1707,(anonymous_118) -FN:1732,(anonymous_120) -FN:1756,(anonymous_122) -FN:1773,(anonymous_124) -FN:1818,(anonymous_126) -FN:1861,(anonymous_128) -FN:1893,(anonymous_130) -FN:1938,(anonymous_132) -FN:1983,(anonymous_134) -FN:2026,(anonymous_136) -FN:2069,(anonymous_138) -FN:2152,(anonymous_140) -FN:2153,(anonymous_141) -FN:2198,(anonymous_142) -FN:2199,(anonymous_143) -FN:2484,(anonymous_144) -FN:2522,(anonymous_146) -FN:2539,(anonymous_148) -FN:2566,(anonymous_150) -FN:2583,(anonymous_152) -FN:2612,(anonymous_154) -FN:2640,(anonymous_156) -FN:2671,(anonymous_158) -FN:2696,(anonymous_160) -FN:2736,(anonymous_162) -FN:2834,(anonymous_164) -FN:2853,(anonymous_166) -FN:2891,(anonymous_168) -FN:2904,(anonymous_169) -FN:2908,(anonymous_170) -FN:2923,(anonymous_172) -FN:2988,(anonymous_174) -FN:3001,(anonymous_175) -FN:3012,(anonymous_176) -FN:3024,(anonymous_177) -FNF:100 -FNH:92 -FNDA:11,(anonymous_14) -FNDA:0,(anonymous_15) -FNDA:2,(anonymous_16) -FNDA:2,(anonymous_17) -FNDA:4,(anonymous_18) -FNDA:1,(anonymous_19) -FNDA:7,(anonymous_20) -FNDA:1,(anonymous_21) -FNDA:1,(anonymous_22) -FNDA:2,(anonymous_23) -FNDA:7,(anonymous_24) -FNDA:8,(anonymous_25) -FNDA:1,(anonymous_26) -FNDA:3,(anonymous_27) -FNDA:4,(anonymous_28) -FNDA:0,(anonymous_29) -FNDA:0,(anonymous_30) -FNDA:1,(anonymous_31) -FNDA:230,(anonymous_32) -FNDA:13,(anonymous_33) -FNDA:30,(anonymous_35) -FNDA:38,(anonymous_37) -FNDA:2,(anonymous_39) -FNDA:16,(anonymous_41) -FNDA:1,(anonymous_43) -FNDA:42,(anonymous_45) -FNDA:4,(anonymous_47) -FNDA:1,(anonymous_49) -FNDA:2,(anonymous_51) -FNDA:8,(anonymous_53) -FNDA:149,(anonymous_55) -FNDA:25,(anonymous_57) -FNDA:22,(anonymous_59) -FNDA:4,(anonymous_61) -FNDA:5,(anonymous_62) -FNDA:510,(anonymous_64) -FNDA:5,(anonymous_66) -FNDA:3,(anonymous_68) -FNDA:97,(anonymous_70) -FNDA:75,(anonymous_72) -FNDA:3,(anonymous_74) -FNDA:3,(anonymous_76) -FNDA:2,(anonymous_78) -FNDA:0,(anonymous_80) -FNDA:3,(anonymous_82) -FNDA:1,(anonymous_83) -FNDA:18,(anonymous_84) -FNDA:8,(anonymous_86) -FNDA:3,(anonymous_88) -FNDA:8,(anonymous_90) -FNDA:4,(anonymous_92) -FNDA:29,(anonymous_94) -FNDA:29,(anonymous_96) -FNDA:17,(anonymous_98) -FNDA:24,(anonymous_99) -FNDA:4,(anonymous_101) -FNDA:4,(anonymous_103) -FNDA:5,(anonymous_104) -FNDA:1,(anonymous_106) -FNDA:18,(anonymous_107) -FNDA:23,(anonymous_109) -FNDA:47,(anonymous_111) -FNDA:43,(anonymous_113) -FNDA:72,(anonymous_114) -FNDA:4,(anonymous_116) -FNDA:5,(anonymous_118) -FNDA:36,(anonymous_120) -FNDA:41,(anonymous_122) -FNDA:23,(anonymous_124) -FNDA:51,(anonymous_126) -FNDA:5,(anonymous_128) -FNDA:16,(anonymous_130) -FNDA:14,(anonymous_132) -FNDA:13,(anonymous_134) -FNDA:10,(anonymous_136) -FNDA:12,(anonymous_138) -FNDA:13,(anonymous_140) -FNDA:10,(anonymous_141) -FNDA:10,(anonymous_142) -FNDA:7,(anonymous_143) -FNDA:3,(anonymous_144) -FNDA:4,(anonymous_146) -FNDA:11,(anonymous_148) -FNDA:1,(anonymous_150) -FNDA:3,(anonymous_152) -FNDA:0,(anonymous_154) -FNDA:0,(anonymous_156) -FNDA:0,(anonymous_158) -FNDA:0,(anonymous_160) -FNDA:533,(anonymous_162) -FNDA:1413,(anonymous_164) -FNDA:8,(anonymous_166) -FNDA:697,(anonymous_168) -FNDA:109,(anonymous_169) -FNDA:207,(anonymous_170) -FNDA:581,(anonymous_172) -FNDA:397,(anonymous_174) -FNDA:408,(anonymous_175) -FNDA:374,(anonymous_176) -FNDA:53,(anonymous_177) -DA:3,1 -DA:4,1 -DA:5,1 -DA:7,1 -DA:8,1 -DA:9,1 -DA:10,1 -DA:11,1 -DA:12,1 -DA:13,1 -DA:14,1 -DA:15,1 -DA:16,1 -DA:17,1 -DA:33,1 -DA:34,1 -DA:35,1 -DA:36,1 -DA:37,1 -DA:38,1 -DA:39,1 -DA:40,1 -DA:41,1 -DA:42,1 -DA:43,1 -DA:44,1 -DA:45,1 -DA:46,1 -DA:48,1 -DA:52,1 -DA:53,2 -DA:54,5 -DA:55,8 -DA:56,3 -DA:57,3 -DA:58,9 -DA:59,2 -DA:60,4 -DA:61,3 -DA:62,5 -DA:63,2 -DA:64,2 -DA:65,8 -DA:69,1 -DA:70,1 -DA:71,1 -DA:72,1 -DA:73,1 -DA:74,1 -DA:77,1 -DA:78,1 -DA:79,1 -DA:80,1 -DA:81,1 -DA:82,1 -DA:83,1 -DA:84,1 -DA:85,1 -DA:86,2 -DA:89,1 -DA:95,1 -DA:97,1 -DA:99,1 -DA:101,1 -DA:104,1 -DA:106,12 -DA:186,1 -DA:187,1 -DA:195,230 -DA:218,230 -DA:219,230 -DA:220,230 -DA:221,230 -DA:222,230 -DA:223,230 -DA:227,230 -DA:228,6 -DA:229,6 -DA:230,1 -DA:232,5 -DA:241,4 -DA:245,229 -DA:246,169 -DA:248,169 -DA:250,169 -DA:251,3 -DA:252,1 -DA:254,3 -DA:257,169 -DA:259,169 -DA:260,169 -DA:261,169 -DA:262,169 -DA:263,169 -DA:264,2 -DA:266,167 -DA:269,169 -DA:271,169 -DA:278,169 -DA:281,229 -DA:282,60 -DA:283,60 -DA:291,13 -DA:292,13 -DA:296,13 -DA:298,13 -DA:300,5 -DA:301,5 -DA:302,25 -DA:303,13 -DA:307,13 -DA:308,7 -DA:313,5 -DA:314,1 -DA:315,1 -DA:317,4 -DA:318,4 -DA:332,30 -DA:335,30 -DA:336,30 -DA:337,14 -DA:341,16 -DA:348,16 -DA:349,16 -DA:351,16 -DA:352,1 -DA:353,1 -DA:355,15 -DA:358,15 -DA:360,15 -DA:361,15 -DA:370,38 -DA:372,38 -DA:373,38 -DA:374,56 -DA:375,20 -DA:378,18 -DA:387,2 -DA:389,2 -DA:390,2 -DA:391,4 -DA:392,1 -DA:395,1 -DA:404,16 -DA:406,16 -DA:410,16 -DA:418,1 -DA:420,1 -DA:422,1 -DA:424,2 -DA:433,42 -DA:434,42 -DA:448,42 -DA:450,42 -DA:452,42 -DA:453,42 -DA:455,42 -DA:457,94 -DA:460,42 -DA:468,4 -DA:470,4 -DA:484,4 -DA:485,4 -DA:487,4 -DA:489,4 -DA:491,4 -DA:492,8 -DA:495,4 -DA:496,4 -DA:505,1 -DA:507,1 -DA:511,1 -DA:512,1 -DA:520,2 -DA:522,2 -DA:532,2 -DA:534,2 -DA:536,2 -DA:537,2 -DA:538,1 -DA:539,1 -DA:541,0 -DA:546,1 -DA:547,1 -DA:551,8 -DA:553,8 -DA:579,8 -DA:580,8 -DA:581,7 -DA:583,7 -DA:591,7 -DA:594,7 -DA:595,7 -DA:596,7 -DA:599,0 -DA:601,0 -DA:602,0 -DA:603,0 -DA:606,0 -DA:607,0 -DA:609,0 -DA:610,0 -DA:611,0 -DA:612,0 -DA:613,0 -DA:614,0 -DA:615,0 -DA:616,0 -DA:617,0 -DA:619,0 -DA:622,0 -DA:628,0 -DA:637,149 -DA:638,149 -DA:640,149 -DA:641,149 -DA:642,615 -DA:643,2 -DA:649,147 -DA:650,147 -DA:651,25 -DA:652,25 -DA:655,122 -DA:656,122 -DA:657,122 -DA:660,63 -DA:661,63 -DA:662,63 -DA:663,63 -DA:665,63 -DA:666,245 -DA:667,245 -DA:668,245 -DA:670,245 -DA:671,85 -DA:674,85 -DA:675,85 -DA:677,160 -DA:683,72 -DA:684,72 -DA:685,71 -DA:686,71 -DA:688,1 -DA:701,25 -DA:702,25 -DA:704,25 -DA:707,25 -DA:708,25 -DA:710,1 -DA:711,1 -DA:720,22 -DA:721,22 -DA:723,22 -DA:725,22 -DA:726,16 -DA:735,4 -DA:745,5 -DA:746,5 -DA:748,5 -DA:749,7 -DA:751,5 -DA:752,5 -DA:753,5 -DA:763,5 -DA:769,5 -DA:770,5 -DA:772,1 -DA:773,1 -DA:775,4 -DA:777,4 -DA:778,4 -DA:779,4 -DA:781,1 -DA:784,3 -DA:785,12 -DA:787,12 -DA:790,12 -DA:791,12 -DA:792,12 -DA:793,12 -DA:795,12 -DA:796,6 -DA:798,6 -DA:801,12 -DA:803,3 -DA:812,510 -DA:813,510 -DA:816,510 -DA:817,4 -DA:820,506 -DA:821,506 -DA:822,387 -DA:823,387 -DA:824,281 -DA:826,106 -DA:827,106 -DA:830,119 -DA:831,119 -DA:841,5 -DA:842,5 -DA:843,5 -DA:845,5 -DA:847,5 -DA:848,0 -DA:850,0 -DA:853,5 -DA:863,3 -DA:864,3 -DA:865,3 -DA:867,3 -DA:869,3 -DA:870,0 -DA:873,0 -DA:875,0 -DA:876,0 -DA:878,0 -DA:879,0 -DA:883,3 -DA:892,97 -DA:893,1 -DA:896,97 -DA:897,97 -DA:899,97 -DA:902,97 -DA:903,53 -DA:905,53 -DA:907,53 -DA:908,1 -DA:910,52 -DA:918,75 -DA:920,75 -DA:921,75 -DA:922,70 -DA:923,70 -DA:924,70 -DA:926,0 -DA:927,0 -DA:930,5 -DA:931,5 -DA:941,3 -DA:942,3 -DA:944,3 -DA:946,3 -DA:951,3 -DA:952,3 -DA:954,1 -DA:955,1 -DA:958,2 -DA:959,2 -DA:960,1 -DA:963,1 -DA:972,3 -DA:973,3 -DA:975,3 -DA:977,3 -DA:982,3 -DA:983,3 -DA:985,1 -DA:986,1 -DA:989,2 -DA:990,2 -DA:991,1 -DA:994,1 -DA:1003,2 -DA:1004,2 -DA:1005,2 -DA:1009,2 -DA:1010,2 -DA:1012,1 -DA:1013,1 -DA:1016,1 -DA:1025,0 -DA:1026,0 -DA:1027,0 -DA:1031,0 -DA:1032,0 -DA:1034,0 -DA:1035,0 -DA:1037,0 -DA:1046,3 -DA:1047,3 -DA:1055,1 -DA:1056,1 -DA:1069,18 -DA:1070,18 -DA:1072,18 -DA:1073,1 -DA:1076,17 -DA:1084,17 -DA:1091,17 -DA:1139,8 -DA:1141,8 -DA:1148,8 -DA:1155,8 -DA:1167,3 -DA:1168,3 -DA:1169,1 -DA:1172,3 -DA:1173,1 -DA:1176,3 -DA:1185,3 -DA:1187,3 -DA:1188,3 -DA:1189,3 -DA:1190,6 -DA:1193,3 -DA:1200,8 -DA:1205,8 -DA:1207,8 -DA:1209,8 -DA:1210,8 -DA:1211,8 -DA:1212,8 -DA:1213,8 -DA:1215,8 -DA:1216,7 -DA:1217,6 -DA:1218,5 -DA:1220,1 -DA:1223,5 -DA:1224,4 -DA:1226,1 -DA:1229,4 -DA:1230,3 -DA:1232,1 -DA:1235,1 -DA:1238,3 -DA:1239,2 -DA:1241,1 -DA:1244,2 -DA:1245,1 -DA:1247,1 -DA:1250,1 -DA:1253,1 -DA:1266,1 -DA:1270,4 -DA:1275,4 -DA:1277,4 -DA:1281,4 -DA:1282,1 -DA:1291,3 -DA:1294,1 -DA:1316,29 -DA:1318,29 -DA:1319,27 -DA:1320,27 -DA:1321,17 -DA:1323,27 -DA:1336,29 -DA:1337,29 -DA:1342,29 -DA:1343,29 -DA:1344,29 -DA:1345,25 -DA:1347,29 -DA:1348,2 -DA:1349,1 -DA:1351,1 -DA:1353,28 -DA:1354,2 -DA:1355,1 -DA:1357,1 -DA:1359,27 -DA:1360,25 -DA:1362,27 -DA:1364,27 -DA:1365,27 -DA:1380,27 -DA:1382,27 -DA:1383,26 -DA:1385,26 -DA:1387,17 -DA:1390,27 -DA:1399,24 -DA:1400,24 -DA:1401,14 -DA:1403,10 -DA:1413,4 -DA:1414,4 -DA:1419,4 -DA:1420,4 -DA:1422,4 -DA:1423,4 -DA:1424,4 -DA:1426,4 -DA:1427,1 -DA:1430,3 -DA:1431,2 -DA:1433,2 -DA:1434,4 -DA:1438,3 -DA:1448,5 -DA:1449,5 -DA:1454,5 -DA:1455,5 -DA:1457,5 -DA:1458,5 -DA:1459,5 -DA:1461,5 -DA:1462,1 -DA:1465,4 -DA:1466,3 -DA:1468,3 -DA:1469,1 -DA:1473,4 -DA:1484,18 -DA:1485,18 -DA:1490,18 -DA:1491,18 -DA:1492,18 -DA:1494,18 -DA:1495,1 -DA:1498,17 -DA:1499,14 -DA:1501,3 -DA:1512,23 -DA:1513,23 -DA:1517,23 -DA:1518,23 -DA:1519,23 -DA:1521,23 -DA:1522,8 -DA:1525,15 -DA:1526,1 -DA:1543,47 -DA:1544,47 -DA:1549,47 -DA:1550,47 -DA:1551,47 -DA:1552,46 -DA:1554,47 -DA:1555,4 -DA:1556,1 -DA:1558,3 -DA:1560,46 -DA:1561,2 -DA:1562,1 -DA:1564,1 -DA:1566,45 -DA:1567,44 -DA:1569,45 -DA:1571,45 -DA:1572,45 -DA:1587,45 -DA:1589,45 -DA:1590,44 -DA:1592,44 -DA:1593,43 -DA:1597,45 -DA:1607,72 -DA:1608,72 -DA:1613,72 -DA:1614,72 -DA:1616,72 -DA:1617,72 -DA:1619,72 -DA:1620,1 -DA:1637,71 -DA:1638,71 -DA:1659,71 -DA:1660,35 -DA:1662,36 -DA:1663,35 -DA:1665,36 -DA:1666,36 -DA:1667,1 -DA:1669,36 -DA:1670,1 -DA:1673,71 -DA:1683,4 -DA:1684,4 -DA:1689,4 -DA:1690,4 -DA:1692,4 -DA:1693,4 -DA:1695,4 -DA:1696,2 -DA:1698,2 -DA:1708,5 -DA:1709,5 -DA:1714,5 -DA:1715,5 -DA:1717,5 -DA:1718,5 -DA:1720,5 -DA:1721,3 -DA:1723,2 -DA:1733,36 -DA:1734,36 -DA:1739,36 -DA:1740,36 -DA:1742,36 -DA:1743,36 -DA:1745,36 -DA:1746,18 -DA:1748,18 -DA:1757,41 -DA:1758,41 -DA:1759,41 -DA:1760,35 -DA:1762,6 -DA:1774,23 -DA:1775,23 -DA:1776,23 -DA:1777,4 -DA:1778,3 -DA:1780,1 -DA:1783,22 -DA:1784,19 -DA:1787,22 -DA:1792,22 -DA:1793,22 -DA:1794,22 -DA:1796,22 -DA:1797,1 -DA:1800,21 -DA:1801,21 -DA:1802,18 -DA:1805,3 -DA:1819,51 -DA:1820,51 -DA:1822,51 -DA:1827,51 -DA:1828,51 -DA:1829,51 -DA:1830,51 -DA:1841,51 -DA:1842,1 -DA:1845,50 -DA:1846,32 -DA:1849,18 -DA:1850,3 -DA:1853,18 -DA:1862,5 -DA:1864,5 -DA:1868,5 -DA:1869,5 -DA:1870,5 -DA:1871,5 -DA:1873,5 -DA:1874,1 -DA:1877,4 -DA:1878,2 -DA:1880,2 -DA:1894,16 -DA:1896,16 -DA:1897,16 -DA:1903,16 -DA:1904,16 -DA:1906,16 -DA:1907,16 -DA:1909,16 -DA:1910,9 -DA:1913,6 -DA:1914,1 -DA:1917,5 -DA:1918,1 -DA:1921,4 -DA:1922,1 -DA:1925,3 -DA:1939,14 -DA:1941,14 -DA:1942,14 -DA:1948,14 -DA:1949,14 -DA:1951,14 -DA:1952,12 -DA:1954,12 -DA:1955,7 -DA:1958,5 -DA:1959,1 -DA:1962,4 -DA:1963,1 -DA:1966,3 -DA:1967,1 -DA:1970,2 -DA:1984,13 -DA:1986,13 -DA:1987,13 -DA:1993,13 -DA:1994,13 -DA:1996,13 -DA:1997,13 -DA:1999,13 -DA:2000,8 -DA:2003,5 -DA:2004,1 -DA:2007,4 -DA:2008,1 -DA:2011,3 -DA:2012,1 -DA:2015,2 -DA:2027,10 -DA:2029,10 -DA:2030,10 -DA:2036,10 -DA:2037,10 -DA:2039,10 -DA:2040,10 -DA:2042,10 -DA:2043,4 -DA:2057,6 -DA:2058,1 -DA:2061,5 -DA:2070,12 -DA:2071,12 -DA:2072,18 -DA:2073,18 -DA:2076,18 -DA:2077,2 -DA:2078,2 -DA:2079,1 -DA:2081,1 -DA:2082,1 -DA:2083,1 -DA:2086,16 -DA:2089,17 -DA:2090,17 -DA:2091,17 -DA:2096,17 -DA:2097,7 -DA:2098,3 -DA:2099,3 -DA:2100,2 -DA:2102,1 -DA:2106,7 -DA:2107,2 -DA:2108,2 -DA:2109,1 -DA:2111,1 -DA:2119,17 -DA:2120,6 -DA:2121,3 -DA:2122,3 -DA:2123,2 -DA:2125,1 -DA:2129,6 -DA:2130,2 -DA:2131,2 -DA:2132,1 -DA:2134,1 -DA:2142,17 -DA:2143,8 -DA:2144,8 -DA:2145,8 -DA:2146,4 -DA:2147,2 -DA:2148,1 -DA:2152,13 -DA:2153,10 -DA:2155,8 -DA:2156,8 -DA:2157,8 -DA:2158,8 -DA:2159,8 -DA:2160,5 -DA:2161,5 -DA:2163,2 -DA:2164,2 -DA:2167,6 -DA:2168,6 -DA:2170,1 -DA:2171,1 -DA:2175,8 -DA:2176,5 -DA:2177,5 -DA:2179,2 -DA:2180,2 -DA:2183,8 -DA:2184,3 -DA:2186,5 -DA:2187,5 -DA:2195,17 -DA:2196,8 -DA:2197,8 -DA:2198,10 -DA:2199,8 -DA:2201,8 -DA:2202,8 -DA:2203,8 -DA:2204,7 -DA:2205,7 -DA:2206,2 -DA:2207,2 -DA:2209,1 -DA:2210,1 -DA:2213,6 -DA:2214,6 -DA:2216,1 -DA:2217,1 -DA:2221,8 -DA:2222,4 -DA:2223,4 -DA:2225,1 -DA:2226,1 -DA:2229,8 -DA:2230,3 -DA:2232,5 -DA:2239,17 -DA:2240,6 -DA:2241,6 -DA:2242,6 -DA:2243,6 -DA:2244,4 -DA:2245,4 -DA:2246,3 -DA:2248,1 -DA:2249,1 -DA:2250,1 -DA:2252,1 -DA:2260,17 -DA:2261,6 -DA:2262,6 -DA:2263,6 -DA:2264,6 -DA:2265,3 -DA:2266,3 -DA:2267,2 -DA:2269,1 -DA:2270,1 -DA:2271,1 -DA:2273,1 -DA:2281,17 -DA:2282,5 -DA:2283,5 -DA:2284,5 -DA:2285,5 -DA:2286,3 -DA:2287,3 -DA:2288,1 -DA:2290,2 -DA:2291,2 -DA:2292,2 -DA:2294,2 -DA:2302,17 -DA:2303,5 -DA:2304,5 -DA:2305,5 -DA:2306,5 -DA:2307,3 -DA:2308,3 -DA:2309,1 -DA:2311,2 -DA:2312,2 -DA:2313,2 -DA:2315,2 -DA:2323,17 -DA:2324,6 -DA:2325,6 -DA:2326,6 -DA:2327,6 -DA:2328,3 -DA:2329,3 -DA:2330,2 -DA:2332,1 -DA:2333,1 -DA:2334,1 -DA:2336,1 -DA:2344,17 -DA:2345,6 -DA:2346,6 -DA:2347,6 -DA:2348,6 -DA:2349,4 -DA:2350,4 -DA:2351,3 -DA:2353,1 -DA:2354,1 -DA:2355,1 -DA:2358,1 -DA:2366,17 -DA:2367,5 -DA:2368,5 -DA:2369,5 -DA:2370,5 -DA:2371,5 -DA:2372,3 -DA:2374,2 -DA:2375,2 -DA:2376,2 -DA:2378,2 -DA:2385,17 -DA:2386,6 -DA:2387,6 -DA:2388,6 -DA:2389,6 -DA:2390,3 -DA:2391,3 -DA:2392,2 -DA:2394,1 -DA:2395,1 -DA:2396,1 -DA:2398,1 -DA:2406,17 -DA:2407,6 -DA:2408,6 -DA:2409,6 -DA:2410,6 -DA:2411,3 -DA:2412,3 -DA:2413,2 -DA:2415,1 -DA:2416,1 -DA:2417,1 -DA:2419,1 -DA:2427,17 -DA:2428,5 -DA:2429,5 -DA:2430,5 -DA:2431,5 -DA:2432,3 -DA:2433,3 -DA:2434,1 -DA:2436,2 -DA:2437,2 -DA:2438,2 -DA:2441,2 -DA:2449,17 -DA:2450,6 -DA:2451,6 -DA:2452,6 -DA:2453,6 -DA:2454,2 -DA:2455,2 -DA:2456,1 -DA:2458,1 -DA:2459,1 -DA:2460,1 -DA:2463,1 -DA:2468,17 -DA:2469,1 -DA:2471,17 -DA:2473,12 -DA:2485,3 -DA:2486,3 -DA:2488,3 -DA:2493,3 -DA:2496,3 -DA:2498,3 -DA:2500,3 -DA:2502,3 -DA:2504,3 -DA:2505,2 -DA:2508,3 -DA:2523,4 -DA:2525,4 -DA:2530,4 -DA:2532,4 -DA:2540,11 -DA:2544,11 -DA:2546,11 -DA:2549,11 -DA:2567,1 -DA:2571,1 -DA:2573,1 -DA:2584,3 -DA:2589,3 -DA:2592,3 -DA:2593,1 -DA:2596,2 -DA:2598,2 -DA:2600,2 -DA:2601,1 -DA:2603,1 -DA:2607,1 -DA:2608,1 -DA:2615,0 -DA:2620,0 -DA:2623,0 -DA:2625,0 -DA:2628,0 -DA:2629,0 -DA:2631,0 -DA:2635,0 -DA:2636,0 -DA:2641,0 -DA:2653,0 -DA:2654,0 -DA:2656,0 -DA:2657,0 -DA:2658,0 -DA:2672,0 -DA:2677,0 -DA:2680,0 -DA:2682,0 -DA:2685,0 -DA:2686,0 -DA:2688,0 -DA:2691,0 -DA:2693,0 -DA:2697,0 -DA:2702,0 -DA:2705,0 -DA:2707,0 -DA:2710,0 -DA:2711,0 -DA:2713,0 -DA:2717,0 -DA:2719,0 -DA:2737,533 -DA:2739,533 -DA:2740,1 -DA:2743,532 -DA:2744,1 -DA:2747,531 -DA:2749,531 -DA:2750,1 -DA:2752,530 -DA:2755,530 -DA:2758,530 -DA:2759,2 -DA:2763,528 -DA:2764,196 -DA:2771,528 -DA:2772,528 -DA:2773,1275 -DA:2774,1 -DA:2777,1274 -DA:2778,1 -DA:2780,1273 -DA:2783,1273 -DA:2784,352 -DA:2787,1273 -DA:2788,2194 -DA:2789,1 -DA:2791,2193 -DA:2792,1225 -DA:2793,1 -DA:2795,1224 -DA:2797,1224 -DA:2798,1224 -DA:2804,524 -DA:2835,1413 -DA:2836,381 -DA:2840,1413 -DA:2841,109 -DA:2854,8 -DA:2855,8 -DA:2856,8 -DA:2857,8 -DA:2859,8 -DA:2860,5 -DA:2862,3 -DA:2864,8 -DA:2865,8 -DA:2871,0 -DA:2872,0 -DA:2873,0 -DA:2874,0 -DA:2877,0 -DA:2878,0 -DA:2879,0 -DA:2884,8 -DA:2888,8 -DA:2892,697 -DA:2893,4 -DA:2896,697 -DA:2897,697 -DA:2898,7 -DA:2901,697 -DA:2905,109 -DA:2909,207 -DA:2910,207 -DA:2912,207 -DA:2915,207 -DA:2916,207 -DA:2918,113 -DA:2919,113 -DA:2924,581 -DA:2925,581 -DA:2927,581 -DA:2951,581 -DA:2952,581 -DA:2954,123 -DA:2955,123 -DA:2958,458 -DA:2959,458 -DA:2961,458 -DA:2962,1038 -DA:2970,1038 -DA:2971,182 -DA:2973,856 -DA:2976,1038 -DA:2977,181 -DA:2981,458 -DA:2982,1 -DA:2983,1 -DA:2985,457 -DA:2990,397 -DA:2991,397 -DA:2992,396 -DA:2993,396 -DA:2994,334 -DA:2996,396 -DA:2998,1 -DA:3002,408 -DA:3021,374 -DA:3025,53 -DA:3026,53 -DA:3028,53 -DA:3033,53 -DA:3034,53 -DA:3035,53 -DA:3037,0 -DA:3039,53 -LF:1105 -LH:1027 -BRDA:227,0,0,6 -BRDA:227,0,1,224 -BRDA:245,1,0,169 -BRDA:245,1,1,60 -BRDA:250,2,0,3 -BRDA:250,2,1,166 -BRDA:251,3,0,1 -BRDA:251,3,1,2 -BRDA:263,4,0,2 -BRDA:263,4,1,167 -BRDA:281,5,0,60 -BRDA:281,5,1,169 -BRDA:302,6,0,13 -BRDA:302,6,1,12 -BRDA:307,7,0,7 -BRDA:307,7,1,6 -BRDA:313,8,0,1 -BRDA:313,8,1,4 -BRDA:336,9,0,14 -BRDA:336,9,1,16 -BRDA:351,10,0,1 -BRDA:351,10,1,15 -BRDA:351,11,0,16 -BRDA:351,11,1,16 -BRDA:374,12,0,20 -BRDA:374,12,1,36 -BRDA:391,13,0,1 -BRDA:391,13,1,3 -BRDA:537,14,0,1 -BRDA:537,14,1,1 -BRDA:538,15,0,1 -BRDA:538,15,1,0 -BRDA:595,16,0,7 -BRDA:595,16,1,0 -BRDA:602,17,0,0 -BRDA:602,17,1,0 -BRDA:606,18,0,0 -BRDA:606,18,1,0 -BRDA:614,19,0,0 -BRDA:614,19,1,0 -BRDA:642,20,0,2 -BRDA:642,20,1,613 -BRDA:642,21,0,615 -BRDA:642,21,1,614 -BRDA:650,22,0,25 -BRDA:650,22,1,122 -BRDA:670,23,0,85 -BRDA:670,23,1,160 -BRDA:684,24,0,71 -BRDA:684,24,1,1 -BRDA:725,25,0,16 -BRDA:725,25,1,6 -BRDA:795,26,0,6 -BRDA:795,26,1,6 -BRDA:816,27,0,4 -BRDA:816,27,1,506 -BRDA:816,28,0,510 -BRDA:816,28,1,506 -BRDA:823,29,0,281 -BRDA:823,29,1,106 -BRDA:875,30,0,0 -BRDA:875,30,1,0 -BRDA:875,31,0,0 -BRDA:875,31,1,0 -BRDA:878,32,0,0 -BRDA:878,32,1,0 -BRDA:892,33,0,1 -BRDA:892,33,1,96 -BRDA:907,34,0,1 -BRDA:907,34,1,52 -BRDA:923,35,0,70 -BRDA:923,35,1,0 -BRDA:924,36,0,70 -BRDA:924,36,1,1 -BRDA:924,37,0,70 -BRDA:924,37,1,1 -BRDA:954,38,0,1 -BRDA:954,38,1,0 -BRDA:959,39,0,1 -BRDA:959,39,1,1 -BRDA:985,40,0,1 -BRDA:985,40,1,0 -BRDA:990,41,0,1 -BRDA:990,41,1,1 -BRDA:1072,42,0,1 -BRDA:1072,42,1,17 -BRDA:1168,43,0,1 -BRDA:1168,43,1,2 -BRDA:1172,44,0,1 -BRDA:1172,44,1,2 -BRDA:1215,45,0,7 -BRDA:1215,45,1,1 -BRDA:1215,46,0,8 -BRDA:1215,46,1,8 -BRDA:1215,46,2,7 -BRDA:1216,47,0,6 -BRDA:1216,47,1,1 -BRDA:1217,48,0,5 -BRDA:1217,48,1,1 -BRDA:1223,49,0,4 -BRDA:1223,49,1,1 -BRDA:1229,50,0,3 -BRDA:1229,50,1,1 -BRDA:1238,51,0,2 -BRDA:1238,51,1,1 -BRDA:1244,52,0,1 -BRDA:1244,52,1,1 -BRDA:1281,53,0,1 -BRDA:1281,53,1,3 -BRDA:1281,54,0,4 -BRDA:1281,54,1,4 -BRDA:1281,54,2,4 -BRDA:1281,54,3,4 -BRDA:1281,54,4,3 -BRDA:1281,54,5,2 -BRDA:1344,55,0,25 -BRDA:1344,55,1,4 -BRDA:1347,56,0,2 -BRDA:1347,56,1,27 -BRDA:1348,57,0,1 -BRDA:1348,57,1,1 -BRDA:1353,58,0,2 -BRDA:1353,58,1,26 -BRDA:1354,59,0,1 -BRDA:1354,59,1,1 -BRDA:1359,60,0,25 -BRDA:1359,60,1,2 -BRDA:1382,61,0,26 -BRDA:1382,61,1,1 -BRDA:1382,62,0,27 -BRDA:1382,62,1,27 -BRDA:1382,62,2,27 -BRDA:1400,63,0,14 -BRDA:1400,63,1,10 -BRDA:1426,64,0,1 -BRDA:1426,64,1,3 -BRDA:1430,65,0,2 -BRDA:1430,65,1,1 -BRDA:1430,66,0,3 -BRDA:1430,66,1,3 -BRDA:1430,66,2,3 -BRDA:1461,67,0,1 -BRDA:1461,67,1,4 -BRDA:1465,68,0,3 -BRDA:1465,68,1,1 -BRDA:1465,69,0,4 -BRDA:1465,69,1,4 -BRDA:1494,70,0,1 -BRDA:1494,70,1,17 -BRDA:1498,71,0,14 -BRDA:1498,71,1,3 -BRDA:1521,72,0,8 -BRDA:1521,72,1,15 -BRDA:1525,73,0,1 -BRDA:1525,73,1,14 -BRDA:1551,74,0,46 -BRDA:1551,74,1,1 -BRDA:1554,75,0,4 -BRDA:1554,75,1,43 -BRDA:1555,76,0,1 -BRDA:1555,76,1,3 -BRDA:1560,77,0,2 -BRDA:1560,77,1,44 -BRDA:1561,78,0,1 -BRDA:1561,78,1,1 -BRDA:1566,79,0,44 -BRDA:1566,79,1,1 -BRDA:1589,80,0,44 -BRDA:1589,80,1,1 -BRDA:1589,81,0,45 -BRDA:1589,81,1,45 -BRDA:1589,81,2,45 -BRDA:1619,82,0,1 -BRDA:1619,82,1,71 -BRDA:1640,83,0,70 -BRDA:1640,83,1,1 -BRDA:1659,84,0,35 -BRDA:1659,84,1,36 -BRDA:1662,85,0,35 -BRDA:1662,85,1,1 -BRDA:1666,86,0,1 -BRDA:1666,86,1,35 -BRDA:1669,87,0,1 -BRDA:1669,87,1,35 -BRDA:1695,88,0,2 -BRDA:1695,88,1,2 -BRDA:1720,89,0,3 -BRDA:1720,89,1,2 -BRDA:1745,90,0,18 -BRDA:1745,90,1,18 -BRDA:1759,91,0,35 -BRDA:1759,91,1,6 -BRDA:1776,92,0,4 -BRDA:1776,92,1,19 -BRDA:1777,93,0,3 -BRDA:1777,93,1,1 -BRDA:1783,94,0,19 -BRDA:1783,94,1,3 -BRDA:1796,95,0,1 -BRDA:1796,95,1,21 -BRDA:1801,96,0,18 -BRDA:1801,96,1,3 -BRDA:1841,97,0,1 -BRDA:1841,97,1,50 -BRDA:1845,98,0,32 -BRDA:1845,98,1,18 -BRDA:1849,99,0,3 -BRDA:1849,99,1,15 -BRDA:1873,100,0,1 -BRDA:1873,100,1,4 -BRDA:1877,101,0,2 -BRDA:1877,101,1,2 -BRDA:1909,102,0,9 -BRDA:1909,102,1,6 -BRDA:1913,103,0,1 -BRDA:1913,103,1,5 -BRDA:1917,104,0,1 -BRDA:1917,104,1,4 -BRDA:1921,105,0,1 -BRDA:1921,105,1,3 -BRDA:1954,106,0,7 -BRDA:1954,106,1,5 -BRDA:1958,107,0,1 -BRDA:1958,107,1,4 -BRDA:1962,108,0,1 -BRDA:1962,108,1,3 -BRDA:1966,109,0,1 -BRDA:1966,109,1,2 -BRDA:1999,110,0,8 -BRDA:1999,110,1,5 -BRDA:2003,111,0,1 -BRDA:2003,111,1,4 -BRDA:2007,112,0,1 -BRDA:2007,112,1,3 -BRDA:2011,113,0,1 -BRDA:2011,113,1,2 -BRDA:2042,114,0,4 -BRDA:2042,114,1,6 -BRDA:2057,115,0,1 -BRDA:2057,115,1,5 -BRDA:2076,116,0,2 -BRDA:2076,116,1,16 -BRDA:2096,117,0,7 -BRDA:2096,117,1,10 -BRDA:2097,118,0,3 -BRDA:2097,118,1,4 -BRDA:2097,119,0,7 -BRDA:2097,119,1,3 -BRDA:2106,120,0,2 -BRDA:2106,120,1,5 -BRDA:2106,121,0,7 -BRDA:2106,121,1,6 -BRDA:2119,122,0,6 -BRDA:2119,122,1,11 -BRDA:2120,123,0,3 -BRDA:2120,123,1,3 -BRDA:2120,124,0,6 -BRDA:2120,124,1,4 -BRDA:2129,125,0,2 -BRDA:2129,125,1,4 -BRDA:2129,126,0,6 -BRDA:2129,126,1,4 -BRDA:2142,127,0,8 -BRDA:2142,127,1,9 -BRDA:2145,128,0,4 -BRDA:2145,128,1,4 -BRDA:2146,129,0,2 -BRDA:2146,129,1,2 -BRDA:2147,130,0,1 -BRDA:2147,130,1,1 -BRDA:2159,131,0,5 -BRDA:2159,131,1,3 -BRDA:2183,132,0,3 -BRDA:2183,132,1,5 -BRDA:2186,133,0,5 -BRDA:2186,133,1,0 -BRDA:2186,134,0,5 -BRDA:2186,134,1,1 -BRDA:2195,135,0,8 -BRDA:2195,135,1,9 -BRDA:2205,136,0,2 -BRDA:2205,136,1,5 -BRDA:2229,137,0,3 -BRDA:2229,137,1,5 -BRDA:2239,138,0,6 -BRDA:2239,138,1,11 -BRDA:2243,139,0,4 -BRDA:2243,139,1,2 -BRDA:2249,140,0,1 -BRDA:2249,140,1,0 -BRDA:2260,141,0,6 -BRDA:2260,141,1,11 -BRDA:2264,142,0,3 -BRDA:2264,142,1,3 -BRDA:2270,143,0,1 -BRDA:2270,143,1,0 -BRDA:2281,144,0,5 -BRDA:2281,144,1,12 -BRDA:2285,145,0,3 -BRDA:2285,145,1,2 -BRDA:2291,146,0,2 -BRDA:2291,146,1,0 -BRDA:2302,147,0,5 -BRDA:2302,147,1,12 -BRDA:2306,148,0,3 -BRDA:2306,148,1,2 -BRDA:2312,149,0,2 -BRDA:2312,149,1,0 -BRDA:2323,150,0,6 -BRDA:2323,150,1,11 -BRDA:2327,151,0,3 -BRDA:2327,151,1,3 -BRDA:2333,152,0,1 -BRDA:2333,152,1,0 -BRDA:2344,153,0,6 -BRDA:2344,153,1,11 -BRDA:2348,154,0,4 -BRDA:2348,154,1,2 -BRDA:2354,155,0,1 -BRDA:2354,155,1,0 -BRDA:2366,156,0,5 -BRDA:2366,156,1,12 -BRDA:2375,157,0,2 -BRDA:2375,157,1,0 -BRDA:2385,158,0,6 -BRDA:2385,158,1,11 -BRDA:2389,159,0,3 -BRDA:2389,159,1,3 -BRDA:2395,160,0,1 -BRDA:2395,160,1,0 -BRDA:2406,161,0,6 -BRDA:2406,161,1,11 -BRDA:2410,162,0,3 -BRDA:2410,162,1,3 -BRDA:2416,163,0,1 -BRDA:2416,163,1,0 -BRDA:2427,164,0,5 -BRDA:2427,164,1,12 -BRDA:2431,165,0,3 -BRDA:2431,165,1,2 -BRDA:2437,166,0,2 -BRDA:2437,166,1,0 -BRDA:2449,167,0,6 -BRDA:2449,167,1,11 -BRDA:2453,168,0,2 -BRDA:2453,168,1,4 -BRDA:2459,169,0,1 -BRDA:2459,169,1,0 -BRDA:2468,170,0,1 -BRDA:2468,170,1,16 -BRDA:2504,171,0,2 -BRDA:2504,171,1,1 -BRDA:2592,172,0,1 -BRDA:2592,172,1,2 -BRDA:2600,173,0,1 -BRDA:2600,173,1,1 -BRDA:2600,174,0,2 -BRDA:2600,174,1,2 -BRDA:2600,174,2,2 -BRDA:2628,175,0,0 -BRDA:2628,175,1,0 -BRDA:2628,176,0,0 -BRDA:2628,176,1,0 -BRDA:2628,176,2,0 -BRDA:2653,177,0,0 -BRDA:2653,177,1,0 -BRDA:2685,178,0,0 -BRDA:2685,178,1,0 -BRDA:2685,179,0,0 -BRDA:2685,179,1,0 -BRDA:2685,179,2,0 -BRDA:2710,180,0,0 -BRDA:2710,180,1,0 -BRDA:2710,181,0,0 -BRDA:2710,181,1,0 -BRDA:2710,181,2,0 -BRDA:2739,182,0,1 -BRDA:2739,182,1,532 -BRDA:2743,183,0,1 -BRDA:2743,183,1,531 -BRDA:2749,184,0,1 -BRDA:2749,184,1,530 -BRDA:2758,185,0,2 -BRDA:2758,185,1,528 -BRDA:2758,186,0,530 -BRDA:2758,186,1,528 -BRDA:2763,187,0,196 -BRDA:2763,187,1,332 -BRDA:2763,188,0,528 -BRDA:2763,188,1,333 -BRDA:2773,189,0,1 -BRDA:2773,189,1,1274 -BRDA:2777,190,0,1 -BRDA:2777,190,1,1273 -BRDA:2783,191,0,352 -BRDA:2783,191,1,921 -BRDA:2783,192,0,1273 -BRDA:2783,192,1,922 -BRDA:2788,193,0,1 -BRDA:2788,193,1,2193 -BRDA:2791,194,0,1225 -BRDA:2791,194,1,968 -BRDA:2792,195,0,1 -BRDA:2792,195,1,1224 -BRDA:2835,196,0,381 -BRDA:2835,196,1,1032 -BRDA:2840,197,0,109 -BRDA:2859,198,0,5 -BRDA:2859,198,1,3 -BRDA:2872,199,0,0 -BRDA:2872,199,1,0 -BRDA:2873,200,0,0 -BRDA:2873,200,1,0 -BRDA:2877,201,0,0 -BRDA:2877,201,1,0 -BRDA:2892,202,0,4 -BRDA:2892,202,1,693 -BRDA:2897,203,0,7 -BRDA:2897,203,1,690 -BRDA:2918,204,0,113 -BRDA:2918,204,1,0 -BRDA:2954,205,0,123 -BRDA:2954,205,1,0 -BRDA:2970,206,0,182 -BRDA:2970,206,1,856 -BRDA:2976,207,0,181 -BRDA:2976,207,1,857 -BRDA:2981,208,0,1 -BRDA:2981,208,1,457 -BRDA:2991,209,0,396 -BRDA:2991,209,1,1 -BRDA:2991,210,0,397 -BRDA:2991,210,1,397 -BRDA:2991,210,2,397 -BRDA:2993,211,0,334 -BRDA:2993,211,1,62 -BRDA:3034,212,0,53 -BRDA:3034,212,1,0 -BRF:438 -BRH:383 -end_of_record -TN: -SF:src\environment.ts -FN:5,(anonymous_1) -FN:9,(anonymous_2) -FN:17,(anonymous_3) -FN:25,(anonymous_4) -FN:33,(anonymous_5) -FNF:5 -FNH:5 -FNDA:17,(anonymous_1) -FNDA:172,(anonymous_2) -FNDA:171,(anonymous_3) -FNDA:171,(anonymous_4) -FNDA:169,(anonymous_5) -DA:1,1 -DA:3,1 -DA:6,17 -DA:10,172 -DA:11,2 -DA:14,170 -DA:18,171 -DA:19,1 -DA:22,170 -DA:26,171 -DA:27,1 -DA:30,170 -DA:34,169 -DA:37,168 -DA:39,1 -LF:15 -LH:15 -BRDA:6,0,0,17 -BRDA:6,0,1,9 -BRDA:10,1,0,2 -BRDA:10,1,1,170 -BRDA:18,2,0,1 -BRDA:18,2,1,170 -BRDA:26,3,0,1 -BRDA:26,3,1,170 -BRDA:34,4,0,168 -BRDA:34,4,1,1 -BRDA:34,5,0,169 -BRDA:34,5,1,4 -BRDA:34,5,2,3 -BRDA:34,5,3,2 -BRDA:34,5,4,166 -BRF:15 -BRH:15 -end_of_record -TN: -SF:src\environmentVcapServices.ts -FN:22,(anonymous_1) -FN:65,(anonymous_2) -FNF:2 -FNH:2 -FNDA:12,(anonymous_1) -FNDA:2,(anonymous_2) -DA:2,1 -DA:4,1 -DA:5,1 -DA:6,1 -DA:8,1 -DA:9,1 -DA:17,1 -DA:24,12 -DA:25,2 -DA:28,10 -DA:29,10 -DA:31,10 -DA:32,5 -DA:33,5 -DA:36,5 -DA:37,1 -DA:42,4 -DA:43,1 -DA:48,3 -DA:49,1 -DA:54,2 -DA:55,2 -DA:56,2 -DA:66,2 -LF:24 -LH:24 -BRDA:24,0,0,2 -BRDA:24,0,1,10 -BRDA:31,1,0,5 -BRDA:31,1,1,5 -BRDA:31,2,0,10 -BRDA:31,2,1,10 -BRDA:31,2,2,10 -BRDA:31,2,3,6 -BRDA:31,2,4,5 -BRDA:36,3,0,1 -BRDA:36,3,1,4 -BRDA:42,4,0,1 -BRDA:42,4,1,3 -BRDA:48,5,0,1 -BRDA:48,5,1,2 -BRF:15 -BRH:15 -end_of_record -TN: -SF:src\error.ts -FN:6,(anonymous_0) -FN:17,(anonymous_1) -FNF:2 -FNH:2 -FNDA:306,(anonymous_0) -FNDA:92,(anonymous_1) -DA:2,1 -DA:7,306 -DA:8,306 -DA:9,306 -DA:14,1 -DA:18,92 -DA:19,92 -DA:27,1 -DA:32,1 -DA:37,1 -DA:42,1 -DA:47,1 -DA:52,1 -DA:57,1 -DA:62,1 -DA:67,1 -DA:72,1 -DA:77,1 -DA:82,1 -DA:87,1 -DA:92,1 -LF:21 -LH:21 -BRF:0 -BRH:0 -end_of_record -TN: -SF:src\fakeServer.ts -FN:13,(anonymous_8) -FN:16,(anonymous_9) -FNF:2 -FNH:2 -FNDA:62,(anonymous_8) -FNDA:111,(anonymous_9) -DA:1,1 -DA:8,1 -DA:9,1 -DA:11,1 -DA:12,62 -DA:14,62 -DA:17,111 -DA:18,111 -DA:19,2 -DA:22,111 -DA:23,111 -DA:24,3 -DA:26,108 -DA:30,108 -DA:32,108 -DA:33,106 -DA:36,108 -DA:37,0 -DA:40,108 -DA:41,7 -DA:42,7 -DA:43,7 -DA:44,7 -DA:45,7 -DA:46,7 -DA:47,7 -DA:49,101 -LF:27 -LH:26 -BRDA:18,0,0,2 -BRDA:18,0,1,109 -BRDA:23,1,0,3 -BRDA:23,1,1,108 -BRDA:32,2,0,106 -BRDA:32,2,1,2 -BRDA:36,3,0,0 -BRDA:36,3,1,108 -BRDA:40,4,0,7 -BRDA:40,4,1,101 -BRF:10 -BRH:9 -end_of_record -TN: -SF:src\file.ts -FN:21,(anonymous_8) -FN:37,(anonymous_9) -FN:46,(anonymous_10) -FN:55,(anonymous_11) -FN:64,(anonymous_12) -FN:72,(anonymous_13) -FN:80,(anonymous_14) -FN:89,(anonymous_15) -FN:99,(anonymous_17) -FN:115,(anonymous_19) -FN:130,(anonymous_21) -FN:139,(anonymous_23) -FN:148,(anonymous_24) -FN:157,(anonymous_25) -FN:166,(anonymous_27) -FN:180,(anonymous_29) -FN:194,(anonymous_31) -FN:206,(anonymous_33) -FN:211,(anonymous_35) -FNF:19 -FNH:17 -FNDA:70,(anonymous_8) -FNDA:24,(anonymous_9) -FNDA:3,(anonymous_10) -FNDA:2,(anonymous_11) -FNDA:2,(anonymous_12) -FNDA:2,(anonymous_13) -FNDA:19,(anonymous_14) -FNDA:8,(anonymous_15) -FNDA:1,(anonymous_17) -FNDA:2,(anonymous_19) -FNDA:2,(anonymous_21) -FNDA:3,(anonymous_23) -FNDA:1,(anonymous_24) -FNDA:8,(anonymous_25) -FNDA:0,(anonymous_27) -FNDA:0,(anonymous_29) -FNDA:4,(anonymous_31) -FNDA:1,(anonymous_33) -FNDA:74,(anonymous_35) -DA:1,1 -DA:2,1 -DA:10,1 -DA:22,70 -DA:31,70 -DA:38,24 -DA:39,23 -DA:47,3 -DA:48,2 -DA:56,2 -DA:57,1 -DA:65,2 -DA:66,1 -DA:73,2 -DA:74,1 -DA:81,19 -DA:82,17 -DA:90,8 -DA:91,8 -DA:100,1 -DA:101,1 -DA:103,1 -DA:104,0 -DA:106,1 -DA:116,2 -DA:117,1 -DA:118,1 -DA:119,1 -DA:120,1 -DA:121,1 -DA:122,1 -DA:123,1 -DA:131,2 -DA:132,2 -DA:140,3 -DA:141,3 -DA:149,1 -DA:150,1 -DA:158,8 -DA:159,8 -DA:167,0 -DA:168,0 -DA:169,0 -DA:170,0 -DA:171,0 -DA:173,0 -DA:181,0 -DA:182,0 -DA:184,0 -DA:185,0 -DA:186,0 -DA:195,4 -DA:196,4 -DA:207,1 -DA:208,1 -DA:212,74 -DA:213,8 -LF:57 -LH:45 -BRDA:103,0,0,0 -BRDA:103,0,1,1 -BRDA:185,1,0,0 -BRDA:185,1,1,0 -BRDA:212,2,0,8 -BRDA:212,2,1,66 -BRF:6 -BRH:3 -end_of_record -TN: -SF:src\fileSizeFormatter.ts -FN:8,(anonymous_0) -FN:11,(anonymous_1) -FNF:2 -FNH:2 -FNDA:20,(anonymous_0) -FNDA:20,(anonymous_1) -DA:2,1 -DA:4,20 -DA:5,20 -DA:6,20 -DA:9,20 -DA:13,20 -DA:14,20 -DA:15,5 -DA:16,5 -DA:18,15 -DA:19,6 -DA:20,6 -DA:22,9 -DA:23,1 -DA:24,1 -DA:27,8 -DA:29,20 -DA:30,20 -LF:18 -LH:18 -BRDA:14,0,0,5 -BRDA:14,0,1,15 -BRDA:18,1,0,6 -BRDA:18,1,1,9 -BRDA:22,2,0,1 -BRDA:22,2,1,8 -BRF:6 -BRH:6 -end_of_record -TN: -SF:src\fileSystemElement.ts -FNF:0 -FNH:0 -DA:7,1 -LF:1 -LH:1 -BRF:0 -BRH:0 -end_of_record -TN: -SF:src\fileSystemFolder.ts -FN:15,(anonymous_8) -FN:19,(anonymous_9) -FN:23,(anonymous_10) -FN:32,(anonymous_12) -FN:35,(anonymous_14) -FN:35,(anonymous_15) -FN:39,(anonymous_16) -FNF:7 -FNH:7 -FNDA:11,(anonymous_8) -FNDA:290,(anonymous_9) -FNDA:11,(anonymous_10) -FNDA:97,(anonymous_12) -FNDA:375,(anonymous_14) -FNDA:375,(anonymous_15) -FNDA:375,(anonymous_16) -DA:1,1 -DA:2,1 -DA:3,1 -DA:5,1 -DA:6,1 -DA:13,1 -DA:16,11 -DA:20,290 -DA:24,11 -DA:26,11 -DA:27,289 -DA:29,10 -DA:34,97 -DA:35,375 -DA:36,375 -DA:37,375 -DA:39,375 -LF:17 -LH:17 -BRDA:37,0,0,86 -BRDA:37,0,1,289 -BRF:2 -BRH:2 -end_of_record -TN: -SF:src\folder.ts -FN:24,(anonymous_8) -FN:36,(anonymous_9) -FN:41,(anonymous_10) -FN:46,(anonymous_11) -FN:51,(anonymous_12) -FN:60,(anonymous_13) -FN:69,(anonymous_15) -FN:81,(anonymous_17) -FN:90,(anonymous_19) -FN:101,(anonymous_21) -FN:113,(anonymous_23) -FN:135,(anonymous_25) -FN:147,(anonymous_27) -FN:160,(anonymous_29) -FN:169,(anonymous_30) -FN:179,(anonymous_31) -FN:193,(anonymous_33) -FN:201,(anonymous_35) -FN:215,(anonymous_37) -FN:230,(anonymous_39) -FN:242,(anonymous_41) -FN:247,(anonymous_43) -FNF:22 -FNH:20 -FNDA:285,(anonymous_8) -FNDA:144,(anonymous_9) -FNDA:2,(anonymous_10) -FNDA:2,(anonymous_11) -FNDA:22,(anonymous_12) -FNDA:3,(anonymous_13) -FNDA:2,(anonymous_15) -FNDA:3,(anonymous_17) -FNDA:1,(anonymous_19) -FNDA:4,(anonymous_21) -FNDA:16,(anonymous_23) -FNDA:20,(anonymous_25) -FNDA:1,(anonymous_27) -FNDA:0,(anonymous_29) -FNDA:0,(anonymous_30) -FNDA:2,(anonymous_31) -FNDA:9,(anonymous_33) -FNDA:2,(anonymous_35) -FNDA:2,(anonymous_37) -FNDA:4,(anonymous_39) -FNDA:2,(anonymous_41) -FNDA:212,(anonymous_43) -DA:2,1 -DA:5,1 -DA:6,1 -DA:15,1 -DA:26,285 -DA:27,285 -DA:37,144 -DA:38,143 -DA:42,2 -DA:43,1 -DA:47,2 -DA:48,1 -DA:52,22 -DA:53,21 -DA:61,3 -DA:62,3 -DA:70,2 -DA:71,2 -DA:72,2 -DA:73,1 -DA:75,1 -DA:82,3 -DA:83,3 -DA:91,1 -DA:92,1 -DA:102,4 -DA:103,4 -DA:114,16 -DA:116,16 -DA:117,16 -DA:120,16 -DA:121,128 -DA:122,0 -DA:128,16 -DA:136,20 -DA:137,20 -DA:138,20 -DA:148,1 -DA:149,1 -DA:150,1 -DA:151,1 -DA:152,1 -DA:153,1 -DA:161,0 -DA:162,0 -DA:170,0 -DA:171,0 -DA:180,2 -DA:182,2 -DA:183,2 -DA:184,1 -DA:186,1 -DA:194,9 -DA:202,2 -DA:203,2 -DA:204,2 -DA:205,2 -DA:206,5 -DA:208,2 -DA:216,2 -DA:217,2 -DA:218,2 -DA:220,2 -DA:221,2 -DA:222,1 -DA:231,4 -DA:232,4 -DA:243,2 -DA:244,2 -DA:248,212 -DA:249,4 -LF:71 -LH:66 -BRDA:24,0,0,4 -BRDA:72,1,0,1 -BRDA:72,1,1,1 -BRDA:121,2,0,0 -BRDA:121,2,1,128 -BRDA:183,3,0,1 -BRDA:183,3,1,1 -BRDA:221,4,0,1 -BRDA:221,4,1,1 -BRDA:248,5,0,4 -BRDA:248,5,1,208 -BRF:11 -BRH:10 -end_of_record -TN: -SF:src\httpClient.ts -FN:41,(anonymous_14) -FN:48,(anonymous_15) -FN:92,(anonymous_17) -FN:92,(anonymous_18) -FN:96,(anonymous_19) -FN:100,(anonymous_20) -FN:100,(anonymous_21) -FN:104,(anonymous_22) -FN:104,(anonymous_23) -FNF:9 -FNH:8 -FNDA:175,(anonymous_14) -FNDA:1310,(anonymous_15) -FNDA:2056,(anonymous_17) -FNDA:2056,(anonymous_18) -FNDA:0,(anonymous_19) -FNDA:319,(anonymous_20) -FNDA:319,(anonymous_21) -FNDA:2,(anonymous_22) -FNDA:2,(anonymous_23) -DA:2,1 -DA:5,1 -DA:6,1 -DA:11,1 -DA:12,1 -DA:13,1 -DA:14,1 -DA:15,1 -DA:35,1 -DA:42,175 -DA:43,175 -DA:44,175 -DA:45,175 -DA:46,175 -DA:50,1310 -DA:51,5 -DA:54,1310 -DA:55,1 -DA:58,1310 -DA:59,1 -DA:62,1310 -DA:63,1307 -DA:65,1310 -DA:68,1310 -DA:69,2 -DA:70,2 -DA:76,2 -DA:78,2 -DA:79,1 -DA:83,1310 -DA:84,1310 -DA:86,1310 -DA:88,1307 -DA:89,1304 -DA:92,2056 -DA:93,2056 -DA:96,1304 -DA:97,0 -DA:100,1304 -DA:101,319 -DA:104,1304 -DA:105,2 -DA:108,1304 -DA:109,1304 -DA:110,52 -DA:113,1304 -DA:114,801 -DA:118,1304 -DA:123,1304 -DA:128,1304 -DA:129,1304 -DA:132,1307 -DA:134,1307 -DA:135,236 -DA:136,236 -DA:137,236 -DA:138,236 -DA:139,236 -DA:140,236 -DA:141,236 -DA:149,1071 -LF:61 -LH:60 -BRDA:45,0,0,175 -BRDA:45,0,1,11 -BRDA:46,1,0,175 -BRDA:46,1,1,1 -BRDA:50,2,0,5 -BRDA:50,2,1,1305 -BRDA:54,3,0,1 -BRDA:54,3,1,1309 -BRDA:58,4,0,1 -BRDA:58,4,1,1309 -BRDA:62,5,0,1307 -BRDA:62,5,1,3 -BRDA:68,6,0,2 -BRDA:68,6,1,1308 -BRDA:78,7,0,1 -BRDA:78,7,1,1 -BRDA:88,8,0,1304 -BRDA:88,8,1,3 -BRDA:109,9,0,52 -BRDA:109,9,1,1252 -BRDA:109,10,0,1304 -BRDA:109,10,1,853 -BRDA:113,11,0,801 -BRDA:113,11,1,503 -BRDA:126,12,0,1304 -BRDA:126,12,1,1281 -BRDA:134,13,0,236 -BRDA:134,13,1,1071 -BRF:28 -BRH:28 -end_of_record -TN: -SF:src\logger.ts -FN:11,(anonymous_1) -FN:56,(anonymous_2) -FN:65,(anonymous_3) -FN:74,(anonymous_4) -FN:82,(anonymous_5) -FN:91,(anonymous_6) -FN:100,(anonymous_7) -FN:109,(anonymous_8) -FNF:8 -FNH:1 -FNDA:17,(anonymous_1) -FNDA:0,(anonymous_2) -FNDA:0,(anonymous_3) -FNDA:0,(anonymous_4) -FNDA:0,(anonymous_5) -FNDA:0,(anonymous_6) -FNDA:0,(anonymous_7) -FNDA:0,(anonymous_8) -DA:1,1 -DA:2,1 -DA:8,1 -DA:14,17 -DA:16,1 -DA:17,1 -DA:19,1 -DA:20,1 -DA:22,1 -DA:23,1 -DA:25,1 -DA:26,1 -DA:28,1 -DA:29,1 -DA:31,10 -DA:32,10 -DA:34,1 -DA:35,1 -DA:37,1 -DA:40,17 -DA:41,17 -DA:43,17 -DA:44,17 -DA:45,17 -DA:46,17 -DA:47,17 -DA:48,17 -DA:49,17 -DA:75,0 -LF:29 -LH:28 -BRDA:15,0,0,1 -BRDA:15,0,1,1 -BRDA:15,0,2,1 -BRDA:15,0,3,1 -BRDA:15,0,4,1 -BRDA:15,0,5,10 -BRDA:15,0,6,1 -BRDA:15,0,7,1 -BRF:8 -BRH:8 -end_of_record -TN: -SF:src\requestResponseLog.ts -FN:26,(anonymous_8) -FN:12,(anonymous_9) -FN:15,(anonymous_10) -FN:31,(anonymous_11) -FN:57,(anonymous_13) -FN:68,(anonymous_15) -FN:79,(anonymous_17) -FN:83,(anonymous_18) -FN:90,(anonymous_19) -FNF:9 -FNH:9 -FNDA:9,(anonymous_8) -FNDA:8,(anonymous_9) -FNDA:1475,(anonymous_10) -FNDA:1314,(anonymous_11) -FNDA:6,(anonymous_13) -FNDA:168,(anonymous_15) -FNDA:1646,(anonymous_17) -FNDA:1393,(anonymous_18) -FNDA:168,(anonymous_19) -DA:2,1 -DA:3,1 -DA:4,1 -DA:6,1 -DA:7,1 -DA:9,1 -DA:10,1 -DA:13,8 -DA:16,1475 -DA:17,9 -DA:19,1475 -DA:21,1 -DA:23,9 -DA:25,9 -DA:27,9 -DA:28,9 -DA:32,1314 -DA:33,1314 -DA:34,1 -DA:35,1 -DA:38,1313 -DA:39,1084 -DA:40,755 -DA:42,1084 -DA:43,324 -DA:47,1313 -DA:48,1311 -DA:49,638 -DA:53,1313 -DA:54,1313 -DA:58,6 -DA:59,6 -DA:60,1 -DA:61,1 -DA:64,5 -DA:65,5 -DA:69,168 -DA:70,168 -DA:72,168 -DA:73,168 -DA:76,168 -DA:80,1646 -DA:84,1393 -DA:85,1391 -DA:87,2 -DA:91,168 -DA:92,168 -DA:93,168 -DA:95,168 -DA:96,670 -DA:97,168 -DA:99,502 -DA:102,670 -DA:103,670 -LF:54 -LH:54 -BRDA:16,0,0,9 -BRDA:16,0,1,1466 -BRDA:33,1,0,1 -BRDA:33,1,1,1313 -BRDA:38,2,0,1084 -BRDA:38,2,1,229 -BRDA:38,3,0,1313 -BRDA:38,3,1,1084 -BRDA:39,4,0,755 -BRDA:39,4,1,329 -BRDA:42,5,0,324 -BRDA:42,5,1,760 -BRDA:47,6,0,1311 -BRDA:47,6,1,2 -BRDA:48,7,0,638 -BRDA:48,7,1,673 -BRDA:48,8,0,1311 -BRDA:48,8,1,1311 -BRDA:59,9,0,1 -BRDA:59,9,1,5 -BRDA:84,10,0,1391 -BRDA:84,10,1,2 -BRDA:96,11,0,168 -BRDA:96,11,1,502 -BRF:24 -BRH:24 -end_of_record -TN: -SF:src\requestResponseLogEntry.ts -FN:7,(anonymous_0) -FN:22,(anonymous_1) -FN:34,(anonymous_2) -FNF:3 -FNH:3 -FNDA:1310,(anonymous_0) -FNDA:1310,(anonymous_1) -FNDA:1314,(anonymous_2) -DA:1,1 -DA:8,1310 -DA:9,1310 -DA:10,1310 -DA:11,1310 -DA:16,1 -DA:23,1310 -DA:24,1310 -DA:25,1310 -DA:26,1310 -DA:31,1 -DA:35,1314 -DA:36,1314 -LF:13 -LH:13 -BRF:0 -BRH:0 -end_of_record -TN: -SF:src\server.ts -FN:33,(anonymous_1) -FNF:1 -FNH:1 -FNDA:169,(anonymous_1) -DA:2,1 -DA:3,1 -DA:27,1 -DA:34,169 -DA:35,169 -DA:36,169 -DA:37,169 -DA:38,169 -DA:39,0 -DA:41,169 -LF:10 -LH:9 -BRDA:38,0,0,0 -BRDA:38,0,1,169 -BRF:2 -BRH:1 -end_of_record -TN: -SF:src\share.ts -FN:6,(anonymous_7) -FN:15,(anonymous_8) -FN:29,(anonymous_9) -FN:90,(anonymous_10) -FN:35,(anonymous_11) -FN:41,(anonymous_13) -FN:103,(anonymous_14) -FN:107,(anonymous_16) -FN:116,(anonymous_18) -FN:120,(anonymous_20) -FN:127,(anonymous_22) -FN:132,(anonymous_24) -FN:174,(anonymous_26) -FN:182,(anonymous_27) -FN:190,(anonymous_28) -FN:198,(anonymous_29) -FN:206,(anonymous_30) -FN:213,(anonymous_31) -FN:221,(anonymous_32) -FNF:19 -FNH:18 -FNDA:1,(anonymous_7) -FNDA:1,(anonymous_8) -FNDA:1,(anonymous_9) -FNDA:11,(anonymous_10) -FNDA:11,(anonymous_11) -FNDA:3,(anonymous_13) -FNDA:1,(anonymous_14) -FNDA:1,(anonymous_16) -FNDA:1,(anonymous_18) -FNDA:2,(anonymous_20) -FNDA:1,(anonymous_22) -FNDA:11,(anonymous_24) -FNDA:2,(anonymous_26) -FNDA:2,(anonymous_27) -FNDA:1,(anonymous_28) -FNDA:2,(anonymous_29) -FNDA:2,(anonymous_30) -FNDA:1,(anonymous_31) -FNDA:0,(anonymous_32) -DA:1,1 -DA:6,1 -DA:7,1 -DA:8,1 -DA:9,1 -DA:10,1 -DA:11,1 -DA:12,1 -DA:15,1 -DA:16,1 -DA:17,1 -DA:18,1 -DA:19,1 -DA:29,1 -DA:30,1 -DA:31,1 -DA:33,1 -DA:36,11 -DA:37,11 -DA:38,7 -DA:42,3 -DA:49,3 -DA:55,3 -DA:56,1 -DA:59,3 -DA:91,11 -DA:92,11 -DA:104,1 -DA:108,1 -DA:109,1 -DA:117,1 -DA:121,2 -DA:122,1 -DA:123,1 -DA:128,1 -DA:129,1 -DA:133,11 -DA:135,11 -DA:136,1 -DA:139,10 -DA:140,1 -DA:142,9 -DA:144,9 -DA:145,1 -DA:147,8 -DA:149,8 -DA:150,1 -DA:153,7 -DA:154,5 -DA:156,2 -DA:158,7 -DA:159,2 -DA:162,7 -DA:163,1 -DA:175,2 -DA:183,2 -DA:191,1 -DA:199,2 -DA:207,2 -DA:214,1 -DA:222,0 -LF:61 -LH:60 -BRDA:6,0,0,1 -BRDA:6,0,1,1 -BRDA:15,1,0,1 -BRDA:15,1,1,1 -BRDA:29,2,0,1 -BRDA:29,2,1,1 -BRDA:55,3,0,1 -BRDA:55,3,1,2 -BRDA:121,4,0,1 -BRDA:121,4,1,1 -BRDA:135,5,0,1 -BRDA:135,5,1,10 -BRDA:135,6,0,11 -BRDA:135,6,1,10 -BRDA:139,7,0,1 -BRDA:139,7,1,9 -BRDA:144,8,0,1 -BRDA:144,8,1,8 -BRDA:149,9,0,1 -BRDA:149,9,1,7 -BRDA:153,10,0,5 -BRDA:153,10,1,2 -BRDA:158,11,0,2 -BRDA:158,11,1,5 -BRDA:162,12,0,1 -BRDA:162,12,1,6 -BRF:26 -BRH:26 -end_of_record -TN: -SF:src\tag.ts -FN:11,(anonymous_7) -FN:19,(anonymous_8) -FN:22,(anonymous_10) -FNF:3 -FNH:3 -FNDA:109,(anonymous_7) -FNDA:16,(anonymous_8) -FNDA:8,(anonymous_10) -DA:4,1 -DA:12,109 -DA:13,109 -DA:14,109 -DA:15,109 -DA:16,109 -DA:17,109 -DA:20,16 -DA:23,8 -LF:9 -LH:9 -BRF:0 -BRH:0 -end_of_record -TN: -SF:src\user.ts -FN:4,(anonymous_8) -FN:73,(anonymous_9) -FN:89,(anonymous_10) -FN:99,(anonymous_12) -FN:110,(anonymous_14) -FN:121,(anonymous_16) -FN:135,(anonymous_18) -FN:147,(anonymous_20) -FN:158,(anonymous_22) -FN:168,(anonymous_24) -FN:194,(anonymous_26) -FN:205,(anonymous_28) -FN:217,(anonymous_30) -FN:231,(anonymous_32) -FN:243,(anonymous_34) -FN:257,(anonymous_36) -FN:269,(anonymous_38) -FN:284,(anonymous_40) -FN:296,(anonymous_42) -FN:311,(anonymous_44) -FN:323,(anonymous_46) -FN:338,(anonymous_48) -FN:350,(anonymous_50) -FN:365,(anonymous_52) -FN:377,(anonymous_54) -FN:390,(anonymous_56) -FN:404,(anonymous_58) -FN:418,(anonymous_60) -FN:433,(anonymous_62) -FN:447,(anonymous_64) -FN:463,(anonymous_66) -FN:479,(anonymous_68) -FN:492,(anonymous_70) -FN:507,(anonymous_72) -FN:526,(anonymous_74) -FN:541,(anonymous_76) -FN:555,(anonymous_78) -FN:571,(anonymous_80) -FN:583,(anonymous_82) -FN:593,(anonymous_84) -FNF:40 -FNH:40 -FNDA:1,(anonymous_8) -FNDA:43,(anonymous_9) -FNDA:17,(anonymous_10) -FNDA:4,(anonymous_12) -FNDA:3,(anonymous_14) -FNDA:2,(anonymous_16) -FNDA:7,(anonymous_18) -FNDA:5,(anonymous_20) -FNDA:6,(anonymous_22) -FNDA:7,(anonymous_24) -FNDA:6,(anonymous_26) -FNDA:7,(anonymous_28) -FNDA:5,(anonymous_30) -FNDA:7,(anonymous_32) -FNDA:5,(anonymous_34) -FNDA:7,(anonymous_36) -FNDA:4,(anonymous_38) -FNDA:7,(anonymous_40) -FNDA:4,(anonymous_42) -FNDA:7,(anonymous_44) -FNDA:4,(anonymous_46) -FNDA:6,(anonymous_48) -FNDA:5,(anonymous_50) -FNDA:6,(anonymous_52) -FNDA:5,(anonymous_54) -FNDA:7,(anonymous_56) -FNDA:4,(anonymous_58) -FNDA:3,(anonymous_60) -FNDA:8,(anonymous_62) -FNDA:11,(anonymous_64) -FNDA:10,(anonymous_66) -FNDA:15,(anonymous_68) -FNDA:2,(anonymous_70) -FNDA:3,(anonymous_72) -FNDA:3,(anonymous_74) -FNDA:8,(anonymous_76) -FNDA:9,(anonymous_78) -FNDA:6,(anonymous_80) -FNDA:9,(anonymous_82) -FNDA:123,(anonymous_84) -DA:1,1 -DA:2,1 -DA:4,1 -DA:5,1 -DA:6,1 -DA:7,1 -DA:8,1 -DA:9,1 -DA:10,1 -DA:11,1 -DA:12,1 -DA:13,1 -DA:14,1 -DA:58,1 -DA:74,43 -DA:75,43 -DA:76,43 -DA:90,17 -DA:100,4 -DA:101,4 -DA:111,3 -DA:112,3 -DA:122,2 -DA:123,2 -DA:124,1 -DA:126,1 -DA:136,7 -DA:148,5 -DA:149,4 -DA:159,6 -DA:169,7 -DA:171,7 -DA:176,7 -DA:177,1 -DA:180,7 -DA:181,1 -DA:183,7 -DA:195,6 -DA:196,4 -DA:206,7 -DA:218,5 -DA:219,3 -DA:232,7 -DA:244,5 -DA:245,4 -DA:258,7 -DA:270,4 -DA:271,3 -DA:285,7 -DA:297,4 -DA:298,3 -DA:312,7 -DA:324,4 -DA:325,3 -DA:339,6 -DA:351,5 -DA:352,2 -DA:366,6 -DA:378,5 -DA:379,2 -DA:391,7 -DA:405,4 -DA:419,3 -DA:420,3 -DA:421,3 -DA:422,3 -DA:424,3 -DA:434,8 -DA:448,11 -DA:449,9 -DA:450,9 -DA:464,10 -DA:465,7 -DA:466,7 -DA:480,15 -DA:493,2 -DA:494,1 -DA:495,1 -DA:509,3 -DA:510,3 -DA:511,2 -DA:513,2 -DA:527,3 -DA:528,3 -DA:529,3 -DA:530,3 -DA:532,3 -DA:542,8 -DA:556,9 -DA:557,8 -DA:558,8 -DA:572,6 -DA:573,4 -DA:574,4 -DA:584,9 -DA:594,123 -DA:595,71 -DA:597,123 -LF:98 -LH:98 -BRDA:4,0,0,1 -BRDA:4,0,1,1 -BRDA:123,1,0,1 -BRDA:123,1,1,1 -BRDA:176,2,0,1 -BRDA:176,2,1,6 -BRDA:180,3,0,1 -BRDA:180,3,1,6 -BRDA:480,4,0,6 -BRDA:480,4,1,9 -BRDA:509,5,0,3 -BRDA:594,6,0,71 -BRDA:594,6,1,52 -BRF:13 -BRH:13 -end_of_record -TN: -SF:src\userGroup.ts -FN:13,(anonymous_7) -FN:22,(anonymous_8) -FN:34,(anonymous_10) -FN:38,(anonymous_12) -FNF:4 -FNH:4 -FNDA:52,(anonymous_7) -FNDA:4,(anonymous_8) -FNDA:1,(anonymous_10) -FNDA:1,(anonymous_12) -DA:1,1 -DA:10,1 -DA:14,52 -DA:15,52 -DA:24,4 -DA:25,4 -DA:27,2 -DA:28,1 -DA:30,1 -DA:35,1 -DA:39,1 -LF:11 -LH:11 -BRDA:27,0,0,1 -BRDA:27,0,1,1 -BRF:2 -BRH:2 -end_of_record -TN: -SF:src\command\command.ts -FN:14,(anonymous_7) -FN:54,(anonymous_8) -FN:67,(anonymous_9) -FN:91,(anonymous_11) -FN:102,(anonymous_12) -FN:110,(anonymous_13) -FN:118,(anonymous_14) -FNF:7 -FNH:7 -FNDA:1,(anonymous_7) -FNDA:20,(anonymous_8) -FNDA:21,(anonymous_9) -FNDA:640,(anonymous_11) -FNDA:79,(anonymous_12) -FNDA:74,(anonymous_13) -FNDA:91,(anonymous_14) -DA:2,1 -DA:4,1 -DA:14,1 -DA:18,1 -DA:22,1 -DA:26,1 -DA:30,1 -DA:48,1 -DA:55,20 -DA:56,20 -DA:57,20 -DA:58,20 -DA:68,21 -DA:69,21 -DA:70,0 -DA:72,21 -DA:73,20 -DA:74,20 -DA:75,20 -DA:92,640 -DA:93,17 -DA:95,623 -DA:103,79 -DA:111,74 -DA:119,91 -LF:25 -LH:24 -BRDA:14,0,0,1 -BRDA:14,0,1,1 -BRDA:69,1,0,0 -BRDA:69,1,1,21 -BRDA:72,2,0,20 -BRDA:72,2,1,1 -BRDA:92,3,0,17 -BRDA:92,3,1,623 -BRDA:92,4,0,640 -BRDA:92,4,1,629 -BRF:10 -BRH:9 -end_of_record -TN: -SF:src\command\downloadFolderCommand.ts -FN:48,(anonymous_8) -FN:61,(anonymous_9) -FN:78,(anonymous_11) -FN:78,(anonymous_12) -FN:78,(anonymous_13) -FN:112,(anonymous_14) -FNF:6 -FNH:6 -FNDA:1,(anonymous_8) -FNDA:1,(anonymous_9) -FNDA:4,(anonymous_11) -FNDA:4,(anonymous_12) -FNDA:4,(anonymous_13) -FNDA:1,(anonymous_14) -DA:2,1 -DA:4,1 -DA:12,1 -DA:13,1 -DA:14,1 -DA:38,1 -DA:49,1 -DA:50,1 -DA:51,1 -DA:52,1 -DA:53,1 -DA:62,1 -DA:63,1 -DA:64,1 -DA:65,1 -DA:70,1 -DA:72,1 -DA:75,1 -DA:77,4 -DA:78,4 -DA:80,1 -DA:81,1 -DA:83,1 -DA:84,1 -DA:85,1 -DA:86,0 -DA:88,1 -DA:89,0 -DA:90,0 -DA:91,0 -DA:92,0 -DA:93,0 -DA:94,0 -DA:95,0 -DA:97,1 -DA:100,0 -DA:101,0 -DA:103,1 -DA:104,1 -DA:105,0 -DA:107,1 -DA:109,1 -DA:113,1 -LF:43 -LH:32 -BRDA:104,0,0,0 -BRDA:104,0,1,1 -BRF:2 -BRH:1 -end_of_record -TN: -SF:src\command\getFilesRecursivelyCommand.ts -FN:31,(anonymous_13) -FN:43,(anonymous_14) -FN:67,(anonymous_16) -FN:76,(anonymous_17) -FNF:4 -FNH:4 -FNDA:3,(anonymous_13) -FNDA:3,(anonymous_14) -FNDA:2,(anonymous_16) -FNDA:3,(anonymous_17) -DA:2,1 -DA:5,1 -DA:21,1 -DA:32,3 -DA:33,3 -DA:34,3 -DA:35,3 -DA:44,3 -DA:45,3 -DA:46,3 -DA:47,3 -DA:48,3 -DA:50,2 -DA:52,1 -DA:53,1 -DA:56,3 -DA:57,3 -DA:58,1 -DA:60,2 -DA:62,3 -DA:63,3 -DA:68,2 -DA:80,3 -DA:81,3 -DA:82,2 -DA:83,0 -DA:86,2 -DA:87,2 -DA:88,2 -DA:90,2 -DA:92,0 -DA:94,2 -LF:32 -LH:30 -BRDA:57,0,0,1 -BRDA:57,0,1,2 -BRDA:87,1,0,2 -BRDA:87,1,1,0 -BRF:4 -BRH:3 -end_of_record -TN: -SF:src\command\uploadFilesCommand.ts -FN:32,(anonymous_14) -FN:44,(anonymous_15) -FN:99,(anonymous_17) -FNF:3 -FNH:3 -FNDA:10,(anonymous_14) -FNDA:10,(anonymous_15) -FNDA:70,(anonymous_17) -DA:2,1 -DA:5,1 -DA:6,1 -DA:7,1 -DA:22,1 -DA:33,10 -DA:34,10 -DA:35,10 -DA:36,10 -DA:45,10 -DA:46,10 -DA:47,10 -DA:48,10 -DA:50,10 -DA:51,10 -DA:52,1 -DA:57,10 -DA:59,74 -DA:60,74 -DA:61,74 -DA:62,73 -DA:63,73 -DA:64,30 -DA:65,30 -DA:67,43 -DA:68,43 -DA:71,1 -DA:74,74 -DA:75,74 -DA:76,74 -DA:78,74 -DA:79,2 -DA:84,1 -DA:85,1 -DA:86,1 -DA:88,10 -DA:89,8 -DA:91,2 -DA:94,10 -DA:96,10 -DA:100,70 -LF:41 -LH:41 -BRDA:51,0,0,1 -BRDA:51,0,1,9 -BRDA:78,1,0,2 -BRDA:78,1,1,72 -BRDA:78,2,0,74 -BRDA:78,2,1,30 -BRDA:88,3,0,8 -BRDA:88,3,1,2 -BRF:8 -BRH:8 -end_of_record -TN: -SF:src\command\uploadFolderCommand.ts -FN:46,(anonymous_13) -FN:53,(anonymous_14) -FN:63,(anonymous_15) -FN:98,(anonymous_17) -FN:98,(anonymous_18) -FN:98,(anonymous_19) -FN:107,(anonymous_20) -FNF:7 -FNH:6 -FNDA:6,(anonymous_13) -FNDA:14,(anonymous_14) -FNDA:6,(anonymous_15) -FNDA:65,(anonymous_17) -FNDA:65,(anonymous_18) -FNDA:65,(anonymous_19) -FNDA:0,(anonymous_20) -DA:2,1 -DA:4,1 -DA:13,1 -DA:35,1 -DA:47,6 -DA:48,6 -DA:49,6 -DA:50,6 -DA:51,4 -DA:53,14 -DA:55,6 -DA:64,6 -DA:65,6 -DA:66,6 -DA:67,6 -DA:68,6 -DA:70,1 -DA:71,1 -DA:72,1 -DA:73,1 -DA:74,1 -DA:75,1 -DA:78,5 -DA:79,5 -DA:80,70 -DA:82,70 -DA:83,56 -DA:87,5 -DA:88,5 -DA:89,5 -DA:92,5 -DA:93,65 -DA:94,65 -DA:95,65 -DA:96,65 -DA:98,65 -DA:101,5 -DA:102,5 -DA:103,5 -DA:104,5 -DA:105,5 -DA:108,0 -LF:42 -LH:41 -BRDA:50,0,0,4 -BRDA:50,0,1,2 -BRDA:82,1,0,56 -BRDA:82,1,1,14 -BRF:4 -BRH:4 -end_of_record diff --git a/docs/coverage/prettify.css b/docs/coverage/prettify.css deleted file mode 100644 index b317a7cd..00000000 --- a/docs/coverage/prettify.css +++ /dev/null @@ -1 +0,0 @@ -.pln{color:#000}@media screen{.str{color:#080}.kwd{color:#008}.com{color:#800}.typ{color:#606}.lit{color:#066}.pun,.opn,.clo{color:#660}.tag{color:#008}.atn{color:#606}.atv{color:#080}.dec,.var{color:#606}.fun{color:red}}@media print,projection{.str{color:#060}.kwd{color:#006;font-weight:bold}.com{color:#600;font-style:italic}.typ{color:#404;font-weight:bold}.lit{color:#044}.pun,.opn,.clo{color:#440}.tag{color:#006;font-weight:bold}.atn{color:#404}.atv{color:#060}}pre.prettyprint{padding:2px;border:1px solid #888}ol.linenums{margin-top:0;margin-bottom:0}li.L0,li.L1,li.L2,li.L3,li.L5,li.L6,li.L7,li.L8{list-style-type:none}li.L1,li.L3,li.L5,li.L7,li.L9{background:#eee} diff --git a/docs/coverage/prettify.js b/docs/coverage/prettify.js deleted file mode 100644 index b3225238..00000000 --- a/docs/coverage/prettify.js +++ /dev/null @@ -1,2 +0,0 @@ -/* eslint-disable */ -window.PR_SHOULD_USE_CONTINUATION=true;(function(){var h=["break,continue,do,else,for,if,return,while"];var u=[h,"auto,case,char,const,default,double,enum,extern,float,goto,int,long,register,short,signed,sizeof,static,struct,switch,typedef,union,unsigned,void,volatile"];var p=[u,"catch,class,delete,false,import,new,operator,private,protected,public,this,throw,true,try,typeof"];var l=[p,"alignof,align_union,asm,axiom,bool,concept,concept_map,const_cast,constexpr,decltype,dynamic_cast,explicit,export,friend,inline,late_check,mutable,namespace,nullptr,reinterpret_cast,static_assert,static_cast,template,typeid,typename,using,virtual,where"];var x=[p,"abstract,boolean,byte,extends,final,finally,implements,import,instanceof,null,native,package,strictfp,super,synchronized,throws,transient"];var R=[x,"as,base,by,checked,decimal,delegate,descending,dynamic,event,fixed,foreach,from,group,implicit,in,interface,internal,into,is,lock,object,out,override,orderby,params,partial,readonly,ref,sbyte,sealed,stackalloc,string,select,uint,ulong,unchecked,unsafe,ushort,var"];var r="all,and,by,catch,class,else,extends,false,finally,for,if,in,is,isnt,loop,new,no,not,null,of,off,on,or,return,super,then,true,try,unless,until,when,while,yes";var w=[p,"debugger,eval,export,function,get,null,set,undefined,var,with,Infinity,NaN"];var s="caller,delete,die,do,dump,elsif,eval,exit,foreach,for,goto,if,import,last,local,my,next,no,our,print,package,redo,require,sub,undef,unless,until,use,wantarray,while,BEGIN,END";var I=[h,"and,as,assert,class,def,del,elif,except,exec,finally,from,global,import,in,is,lambda,nonlocal,not,or,pass,print,raise,try,with,yield,False,True,None"];var f=[h,"alias,and,begin,case,class,def,defined,elsif,end,ensure,false,in,module,next,nil,not,or,redo,rescue,retry,self,super,then,true,undef,unless,until,when,yield,BEGIN,END"];var H=[h,"case,done,elif,esac,eval,fi,function,in,local,set,then,until"];var A=[l,R,w,s+I,f,H];var e=/^(DIR|FILE|vector|(de|priority_)?queue|list|stack|(const_)?iterator|(multi)?(set|map)|bitset|u?(int|float)\d*)/;var C="str";var z="kwd";var j="com";var O="typ";var G="lit";var L="pun";var F="pln";var m="tag";var E="dec";var J="src";var P="atn";var n="atv";var N="nocode";var M="(?:^^\\.?|[+-]|\\!|\\!=|\\!==|\\#|\\%|\\%=|&|&&|&&=|&=|\\(|\\*|\\*=|\\+=|\\,|\\-=|\\->|\\/|\\/=|:|::|\\;|<|<<|<<=|<=|=|==|===|>|>=|>>|>>=|>>>|>>>=|\\?|\\@|\\[|\\^|\\^=|\\^\\^|\\^\\^=|\\{|\\||\\|=|\\|\\||\\|\\|=|\\~|break|case|continue|delete|do|else|finally|instanceof|return|throw|try|typeof)\\s*";function k(Z){var ad=0;var S=false;var ac=false;for(var V=0,U=Z.length;V122)){if(!(al<65||ag>90)){af.push([Math.max(65,ag)|32,Math.min(al,90)|32])}if(!(al<97||ag>122)){af.push([Math.max(97,ag)&~32,Math.min(al,122)&~32])}}}}af.sort(function(av,au){return(av[0]-au[0])||(au[1]-av[1])});var ai=[];var ap=[NaN,NaN];for(var ar=0;arat[0]){if(at[1]+1>at[0]){an.push("-")}an.push(T(at[1]))}}an.push("]");return an.join("")}function W(al){var aj=al.source.match(new RegExp("(?:\\[(?:[^\\x5C\\x5D]|\\\\[\\s\\S])*\\]|\\\\u[A-Fa-f0-9]{4}|\\\\x[A-Fa-f0-9]{2}|\\\\[0-9]+|\\\\[^ux0-9]|\\(\\?[:!=]|[\\(\\)\\^]|[^\\x5B\\x5C\\(\\)\\^]+)","g"));var ah=aj.length;var an=[];for(var ak=0,am=0;ak=2&&ai==="["){aj[ak]=X(ag)}else{if(ai!=="\\"){aj[ak]=ag.replace(/[a-zA-Z]/g,function(ao){var ap=ao.charCodeAt(0);return"["+String.fromCharCode(ap&~32,ap|32)+"]"})}}}}return aj.join("")}var aa=[];for(var V=0,U=Z.length;V=0;){S[ac.charAt(ae)]=Y}}var af=Y[1];var aa=""+af;if(!ag.hasOwnProperty(aa)){ah.push(af);ag[aa]=null}}ah.push(/[\0-\uffff]/);V=k(ah)})();var X=T.length;var W=function(ah){var Z=ah.sourceCode,Y=ah.basePos;var ad=[Y,F];var af=0;var an=Z.match(V)||[];var aj={};for(var ae=0,aq=an.length;ae=5&&"lang-"===ap.substring(0,5);if(am&&!(ai&&typeof ai[1]==="string")){am=false;ap=J}if(!am){aj[ag]=ap}}var ab=af;af+=ag.length;if(!am){ad.push(Y+ab,ap)}else{var al=ai[1];var ak=ag.indexOf(al);var ac=ak+al.length;if(ai[2]){ac=ag.length-ai[2].length;ak=ac-al.length}var ar=ap.substring(5);B(Y+ab,ag.substring(0,ak),W,ad);B(Y+ab+ak,al,q(ar,al),ad);B(Y+ab+ac,ag.substring(ac),W,ad)}}ah.decorations=ad};return W}function i(T){var W=[],S=[];if(T.tripleQuotedStrings){W.push([C,/^(?:\'\'\'(?:[^\'\\]|\\[\s\S]|\'{1,2}(?=[^\']))*(?:\'\'\'|$)|\"\"\"(?:[^\"\\]|\\[\s\S]|\"{1,2}(?=[^\"]))*(?:\"\"\"|$)|\'(?:[^\\\']|\\[\s\S])*(?:\'|$)|\"(?:[^\\\"]|\\[\s\S])*(?:\"|$))/,null,"'\""])}else{if(T.multiLineStrings){W.push([C,/^(?:\'(?:[^\\\']|\\[\s\S])*(?:\'|$)|\"(?:[^\\\"]|\\[\s\S])*(?:\"|$)|\`(?:[^\\\`]|\\[\s\S])*(?:\`|$))/,null,"'\"`"])}else{W.push([C,/^(?:\'(?:[^\\\'\r\n]|\\.)*(?:\'|$)|\"(?:[^\\\"\r\n]|\\.)*(?:\"|$))/,null,"\"'"])}}if(T.verbatimStrings){S.push([C,/^@\"(?:[^\"]|\"\")*(?:\"|$)/,null])}var Y=T.hashComments;if(Y){if(T.cStyleComments){if(Y>1){W.push([j,/^#(?:##(?:[^#]|#(?!##))*(?:###|$)|.*)/,null,"#"])}else{W.push([j,/^#(?:(?:define|elif|else|endif|error|ifdef|include|ifndef|line|pragma|undef|warning)\b|[^\r\n]*)/,null,"#"])}S.push([C,/^<(?:(?:(?:\.\.\/)*|\/?)(?:[\w-]+(?:\/[\w-]+)+)?[\w-]+\.h|[a-z]\w*)>/,null])}else{W.push([j,/^#[^\r\n]*/,null,"#"])}}if(T.cStyleComments){S.push([j,/^\/\/[^\r\n]*/,null]);S.push([j,/^\/\*[\s\S]*?(?:\*\/|$)/,null])}if(T.regexLiterals){var X=("/(?=[^/*])(?:[^/\\x5B\\x5C]|\\x5C[\\s\\S]|\\x5B(?:[^\\x5C\\x5D]|\\x5C[\\s\\S])*(?:\\x5D|$))+/");S.push(["lang-regex",new RegExp("^"+M+"("+X+")")])}var V=T.types;if(V){S.push([O,V])}var U=(""+T.keywords).replace(/^ | $/g,"");if(U.length){S.push([z,new RegExp("^(?:"+U.replace(/[\s,]+/g,"|")+")\\b"),null])}W.push([F,/^\s+/,null," \r\n\t\xA0"]);S.push([G,/^@[a-z_$][a-z_$@0-9]*/i,null],[O,/^(?:[@_]?[A-Z]+[a-z][A-Za-z_$@0-9]*|\w+_t\b)/,null],[F,/^[a-z_$][a-z_$@0-9]*/i,null],[G,new RegExp("^(?:0x[a-f0-9]+|(?:\\d(?:_\\d+)*\\d*(?:\\.\\d*)?|\\.\\d\\+)(?:e[+\\-]?\\d+)?)[a-z]*","i"),null,"0123456789"],[F,/^\\[\s\S]?/,null],[L,/^.[^\s\w\.$@\'\"\`\/\#\\]*/,null]);return g(W,S)}var K=i({keywords:A,hashComments:true,cStyleComments:true,multiLineStrings:true,regexLiterals:true});function Q(V,ag){var U=/(?:^|\s)nocode(?:\s|$)/;var ab=/\r\n?|\n/;var ac=V.ownerDocument;var S;if(V.currentStyle){S=V.currentStyle.whiteSpace}else{if(window.getComputedStyle){S=ac.defaultView.getComputedStyle(V,null).getPropertyValue("white-space")}}var Z=S&&"pre"===S.substring(0,3);var af=ac.createElement("LI");while(V.firstChild){af.appendChild(V.firstChild)}var W=[af];function ae(al){switch(al.nodeType){case 1:if(U.test(al.className)){break}if("BR"===al.nodeName){ad(al);if(al.parentNode){al.parentNode.removeChild(al)}}else{for(var an=al.firstChild;an;an=an.nextSibling){ae(an)}}break;case 3:case 4:if(Z){var am=al.nodeValue;var aj=am.match(ab);if(aj){var ai=am.substring(0,aj.index);al.nodeValue=ai;var ah=am.substring(aj.index+aj[0].length);if(ah){var ak=al.parentNode;ak.insertBefore(ac.createTextNode(ah),al.nextSibling)}ad(al);if(!ai){al.parentNode.removeChild(al)}}}break}}function ad(ak){while(!ak.nextSibling){ak=ak.parentNode;if(!ak){return}}function ai(al,ar){var aq=ar?al.cloneNode(false):al;var ao=al.parentNode;if(ao){var ap=ai(ao,1);var an=al.nextSibling;ap.appendChild(aq);for(var am=an;am;am=an){an=am.nextSibling;ap.appendChild(am)}}return aq}var ah=ai(ak.nextSibling,0);for(var aj;(aj=ah.parentNode)&&aj.nodeType===1;){ah=aj}W.push(ah)}for(var Y=0;Y=S){ah+=2}if(V>=ap){Z+=2}}}var t={};function c(U,V){for(var S=V.length;--S>=0;){var T=V[S];if(!t.hasOwnProperty(T)){t[T]=U}else{if(window.console){console.warn("cannot override language handler %s",T)}}}}function q(T,S){if(!(T&&t.hasOwnProperty(T))){T=/^\s*]*(?:>|$)/],[j,/^<\!--[\s\S]*?(?:-\->|$)/],["lang-",/^<\?([\s\S]+?)(?:\?>|$)/],["lang-",/^<%([\s\S]+?)(?:%>|$)/],[L,/^(?:<[%?]|[%?]>)/],["lang-",/^]*>([\s\S]+?)<\/xmp\b[^>]*>/i],["lang-js",/^]*>([\s\S]*?)(<\/script\b[^>]*>)/i],["lang-css",/^]*>([\s\S]*?)(<\/style\b[^>]*>)/i],["lang-in.tag",/^(<\/?[a-z][^<>]*>)/i]]),["default-markup","htm","html","mxml","xhtml","xml","xsl"]);c(g([[F,/^[\s]+/,null," \t\r\n"],[n,/^(?:\"[^\"]*\"?|\'[^\']*\'?)/,null,"\"'"]],[[m,/^^<\/?[a-z](?:[\w.:-]*\w)?|\/?>$/i],[P,/^(?!style[\s=]|on)[a-z](?:[\w:-]*\w)?/i],["lang-uq.val",/^=\s*([^>\'\"\s]*(?:[^>\'\"\s\/]|\/(?=\s)))/],[L,/^[=<>\/]+/],["lang-js",/^on\w+\s*=\s*\"([^\"]+)\"/i],["lang-js",/^on\w+\s*=\s*\'([^\']+)\'/i],["lang-js",/^on\w+\s*=\s*([^\"\'>\s]+)/i],["lang-css",/^style\s*=\s*\"([^\"]+)\"/i],["lang-css",/^style\s*=\s*\'([^\']+)\'/i],["lang-css",/^style\s*=\s*([^\"\'>\s]+)/i]]),["in.tag"]);c(g([],[[n,/^[\s\S]+/]]),["uq.val"]);c(i({keywords:l,hashComments:true,cStyleComments:true,types:e}),["c","cc","cpp","cxx","cyc","m"]);c(i({keywords:"null,true,false"}),["json"]);c(i({keywords:R,hashComments:true,cStyleComments:true,verbatimStrings:true,types:e}),["cs"]);c(i({keywords:x,cStyleComments:true}),["java"]);c(i({keywords:H,hashComments:true,multiLineStrings:true}),["bsh","csh","sh"]);c(i({keywords:I,hashComments:true,multiLineStrings:true,tripleQuotedStrings:true}),["cv","py"]);c(i({keywords:s,hashComments:true,multiLineStrings:true,regexLiterals:true}),["perl","pl","pm"]);c(i({keywords:f,hashComments:true,multiLineStrings:true,regexLiterals:true}),["rb"]);c(i({keywords:w,cStyleComments:true,regexLiterals:true}),["js"]);c(i({keywords:r,hashComments:3,cStyleComments:true,multilineStrings:true,tripleQuotedStrings:true,regexLiterals:true}),["coffee"]);c(g([],[[C,/^[\s\S]+/]]),["regex"]);function d(V){var U=V.langExtension;try{var S=a(V.sourceNode);var T=S.sourceCode;V.sourceCode=T;V.spans=S.spans;V.basePos=0;q(U,T)(V);D(V)}catch(W){if("console" in window){console.log(W&&W.stack?W.stack:W)}}}function y(W,V,U){var S=document.createElement("PRE");S.innerHTML=W;if(U){Q(S,U)}var T={langExtension:V,numberLines:U,sourceNode:S};d(T);return S.innerHTML}function b(ad){function Y(af){return document.getElementsByTagName(af)}var ac=[Y("pre"),Y("code"),Y("xmp")];var T=[];for(var aa=0;aa=0){var ah=ai.match(ab);var am;if(!ah&&(am=o(aj))&&"CODE"===am.tagName){ah=am.className.match(ab)}if(ah){ah=ah[1]}var al=false;for(var ak=aj.parentNode;ak;ak=ak.parentNode){if((ak.tagName==="pre"||ak.tagName==="code"||ak.tagName==="xmp")&&ak.className&&ak.className.indexOf("prettyprint")>=0){al=true;break}}if(!al){var af=aj.className.match(/\blinenums\b(?::(\d+))?/);af=af?af[1]&&af[1].length?+af[1]:true:false;if(af){Q(aj,af)}S={langExtension:ah,sourceNode:aj,numberLines:af};d(S)}}}if(X]*(?:>|$)/],[PR.PR_COMMENT,/^<\!--[\s\S]*?(?:-\->|$)/],[PR.PR_PUNCTUATION,/^(?:<[%?]|[%?]>)/],["lang-",/^<\?([\s\S]+?)(?:\?>|$)/],["lang-",/^<%([\s\S]+?)(?:%>|$)/],["lang-",/^]*>([\s\S]+?)<\/xmp\b[^>]*>/i],["lang-handlebars",/^]*type\s*=\s*['"]?text\/x-handlebars-template['"]?\b[^>]*>([\s\S]*?)(<\/script\b[^>]*>)/i],["lang-js",/^]*>([\s\S]*?)(<\/script\b[^>]*>)/i],["lang-css",/^]*>([\s\S]*?)(<\/style\b[^>]*>)/i],["lang-in.tag",/^(<\/?[a-z][^<>]*>)/i],[PR.PR_DECLARATION,/^{{[#^>/]?\s*[\w.][^}]*}}/],[PR.PR_DECLARATION,/^{{&?\s*[\w.][^}]*}}/],[PR.PR_DECLARATION,/^{{{>?\s*[\w.][^}]*}}}/],[PR.PR_COMMENT,/^{{![^}]*}}/]]),["handlebars","hbs"]);PR.registerLangHandler(PR.createSimpleLexer([[PR.PR_PLAIN,/^[ \t\r\n\f]+/,null," \t\r\n\f"]],[[PR.PR_STRING,/^\"(?:[^\n\r\f\\\"]|\\(?:\r\n?|\n|\f)|\\[\s\S])*\"/,null],[PR.PR_STRING,/^\'(?:[^\n\r\f\\\']|\\(?:\r\n?|\n|\f)|\\[\s\S])*\'/,null],["lang-css-str",/^url\(([^\)\"\']*)\)/i],[PR.PR_KEYWORD,/^(?:url|rgb|\!important|@import|@page|@media|@charset|inherit)(?=[^\-\w]|$)/i,null],["lang-css-kw",/^(-?(?:[_a-z]|(?:\\[0-9a-f]+ ?))(?:[_a-z0-9\-]|\\(?:\\[0-9a-f]+ ?))*)\s*:/i],[PR.PR_COMMENT,/^\/\*[^*]*\*+(?:[^\/*][^*]*\*+)*\//],[PR.PR_COMMENT,/^(?:)/],[PR.PR_LITERAL,/^(?:\d+|\d*\.\d+)(?:%|[a-z]+)?/i],[PR.PR_LITERAL,/^#(?:[0-9a-f]{3}){1,2}/i],[PR.PR_PLAIN,/^-?(?:[_a-z]|(?:\\[\da-f]+ ?))(?:[_a-z\d\-]|\\(?:\\[\da-f]+ ?))*/i],[PR.PR_PUNCTUATION,/^[^\s\w\'\"]+/]]),["css"]);PR.registerLangHandler(PR.createSimpleLexer([],[[PR.PR_KEYWORD,/^-?(?:[_a-z]|(?:\\[\da-f]+ ?))(?:[_a-z\d\-]|\\(?:\\[\da-f]+ ?))*/i]]),["css-kw"]);PR.registerLangHandler(PR.createSimpleLexer([],[[PR.PR_STRING,/^[^\)\"\']+/]]),["css-str"]); diff --git a/docs/coverage/requestResponseLog.ts.html b/docs/coverage/requestResponseLog.ts.html deleted file mode 100644 index 723228f6..00000000 --- a/docs/coverage/requestResponseLog.ts.html +++ /dev/null @@ -1,419 +0,0 @@ - - - - - - Code coverage report for requestResponseLog.ts - - - - - - - - - -
-
-

All files requestResponseLog.ts

-
- -
- 100% - Statements - 54/54 -
- - -
- 100% - Branches - 24/24 -
- - -
- 100% - Functions - 9/9 -
- - -
- 100% - Lines - 54/54 -
- - -
-

- Press n or j to go to the next uncovered block, b, p or k for the previous block. -

-
-
-

-
1 -2 -3 -4 -5 -6 -7 -8 -9 -10 -11 -12 -13 -14 -15 -16 -17 -18 -19 -20 -21 -22 -23 -24 -25 -26 -27 -28 -29 -30 -31 -32 -33 -34 -35 -36 -37 -38 -39 -40 -41 -42 -43 -44 -45 -46 -47 -48 -49 -50 -51 -52 -53 -54 -55 -56 -57 -58 -59 -60 -61 -62 -63 -64 -65 -66 -67 -68 -69 -70 -71 -72 -73 -74 -75 -76 -77 -78 -79 -80 -81 -82 -83 -84 -85 -86 -87 -88 -89 -90 -91 -92 -93 -94 -95 -96 -97 -98 -99 -100 -101 -102 -103 -104 -105 -106 -107 -108 -109 -110 -111 -112 -113 -114  -1x -1x -1x -1x -  -  -1x -  -1x -1x -  -  -8x -  -  -166x -9x -  -166x -  -1x -  -9x -  -9x -  -9x -9x -  -  -  -11x -11x -1x -1x -  -  -10x -8x -4x -  -8x -1x -  -  -  -10x -8x -4x -  -  -  -10x -10x -  -  -  -160x -160x -1x -1x -  -  -159x -96x -  -  -  -162x -162x -  -162x -162x -  -  -162x -  -  -  -331x -  -  -  -8x -6x -  -2x -  -  -  -162x -162x -162x -  -162x -646x -162x -  -484x -  -  -646x -646x -  -  -  -  -  -  -  -  -  - 
 
-import debugFactory from "debug";
-import parser from "fast-xml-parser";
-import { promises as fsPromises } from "fs";
-import path from "path";
-import requestResponseLogEntry from "./requestResponseLogEntry";
- 
-const debug = debugFactory("RequestResponseLog");
- 
-export default class RequestResponseLog {
-    public static readonly defaultLogDirectory: string = "RequestResponseLog/";
- 
-    public static deleteInstance(): void {
-        RequestResponseLog.log = null;
-    }
-    public static getInstance(): RequestResponseLog {
-        if (!RequestResponseLog.log) {
-            RequestResponseLog.log = new RequestResponseLog();
-        }
-        return RequestResponseLog.log;
-    }
-    private static log: RequestResponseLog | null = null;
- 
-    public baseDirectory: string = RequestResponseLog.defaultLogDirectory;
-    private context: string;
-    private entries: requestResponseLogEntry[] = [];
-    private constructor() {
-        this.baseDirectory = RequestResponseLog.defaultLogDirectory;
-        this.context = "";
-    }
- 
-    public async addEntry(logEntry: requestResponseLogEntry) {
-        debug("addEntry");
-        if (!this.context) {
-            debug("Error while recording, context not set");
-            throw new Error("Error while recording, context not set");
-        }
- 
-        if (logEntry.response.body && logEntry.response.contentType) {
-            if (logEntry.response.contentType.indexOf("application/xml") !== -1) {
-                logEntry.response.jsonBody = this.xmlToJson(logEntry.response.body);
-            }
-            if (logEntry.response.contentType.indexOf("application/json") !== -1) {
-                logEntry.response.jsonBody = JSON.parse(logEntry.response.body);
-            }
-        }
- 
-        if (logEntry.request.body) {
-            if (logEntry.request.body.indexOf && logEntry.request.body.indexOf("<?xml version") !== -1) {
-                logEntry.request.jsonBody = this.xmlToJson(logEntry.request.body);
-            }
-        }
- 
-        this.entries.push(logEntry);
-        await fsPromises.writeFile(this.getFileName(), JSON.stringify(this.entries, null, 4));
-    }
- 
-    public async getEntries(): Promise<requestResponseLogEntry[]> {
-        debug("getEntries");
-        if (!this.context) {
-            debug("Error while getting recording request, context not set");
-            throw new Error("Error while getting recording request, context not set");
-        }
- 
-        const entries: string = await fsPromises.readFile(this.getFileName(), { encoding: "utf8" });
-        return JSON.parse(entries);
-    }
- 
-    public async setContext(context: string) {
-        debug("setContext");
-        const newContext: string = context.replace(/ |:|\./g, "_");
-        // if (this.context !== newContext) {
-        this.context = newContext;
-        this.entries = [];
-        // }
-        // create the directory
-        await this.assertDirectory(this.getFileName());
-    }
- 
-    public getFileName(): string {
-        return `${this.baseDirectory}${this.context}.json`;
-    }
- 
-    private xmlToJson(xml: string): any {
-        if (parser.validate(xml) === true) {
-            return parser.parse(xml, { ignoreNameSpace: true });
-        }
-        return { info: "invalid xml" };
-    }
- 
-    private async assertDirectory(filename: string): Promise<void> {
-        const directory = path.dirname(filename);
-        const pathArray: string[] = directory.split("/");
-        let p: string = "";
- 
-        for (const dir of pathArray) {
-            if (p === "") {
-                p = dir;
-            } else {
-                p = p + "/" + dir;
-            }
- 
-            try {
-                await fsPromises.mkdir(p);
-                  /* istanbul ignore next */
-                debug(`directory "${p}" created`);
-            } catch (e) {
-                  /* istanbul ignore next */                
-                debug(`directory "${p}" already exists`);
-            }
-        }
-    }
-}
- 
- -
-
- - - - - - - - - \ No newline at end of file diff --git a/docs/coverage/requestResponseLogEntry.ts.html b/docs/coverage/requestResponseLogEntry.ts.html deleted file mode 100644 index b2ccd29b..00000000 --- a/docs/coverage/requestResponseLogEntry.ts.html +++ /dev/null @@ -1,197 +0,0 @@ - - - - - - Code coverage report for requestResponseLogEntry.ts - - - - - - - - - -
-
-

All files requestResponseLogEntry.ts

-
- -
- 100% - Statements - 13/13 -
- - -
- 100% - Branches - 0/0 -
- - -
- 100% - Functions - 3/3 -
- - -
- 100% - Lines - 13/13 -
- - -
-

- Press n or j to go to the next uncovered block, b, p or k for the previous block. -

-
-
-

-
1 -2 -3 -4 -5 -6 -7 -8 -9 -10 -11 -12 -13 -14 -15 -16 -17 -18 -19 -20 -21 -22 -23 -24 -25 -26 -27 -28 -29 -30 -31 -32 -33 -34 -35 -36 -37 -38 -39 -40  -1x -  -  -  -  -  -  -7x -7x -7x -7x -  -  -  -  -1x -  -  -  -  -  -  -7x -7x -7x -7x -  -  -  -  -1x -  -  -  -11x -11x -  -  - 
 
-export class RequestLogEntry {
-    public body?: string;
-    public description: string;
-    public jsonBody?: any;
-    public method: string;
-    public url: string;
-    public constructor(url: string, method: string, description: string, body?: string) {
-        this.url = url;
-        this.method = method;
-        this.description = description;
-        this.body = body;
-    }
-}
- 
-// tslint:disable-next-line:max-classes-per-file
-export class ResponseLogEntry {
-    public body?: string;
-    public contentType?: string;
-    public contentLocation?: string;
-    public jsonBody?: any;
-    public status: number;
-    public constructor(status: number, body?: string, contentType?: string, contentLocation?: string) {
-        this.status = status;
-        this.body = body;
-        this.contentType = contentType;
-        this.contentLocation = contentLocation;
-    }
-}
- 
-// tslint:disable-next-line:max-classes-per-file
-export default class RequestResponseLogEntry {
-    public request: RequestLogEntry;
-    public response: ResponseLogEntry;
-    public constructor(request: RequestLogEntry, response: ResponseLogEntry) {
-        this.request = request;
-        this.response = response;
-    }
-}
- 
- -
-
- - - - - - - - - \ No newline at end of file diff --git a/docs/coverage/server.ts.html b/docs/coverage/server.ts.html deleted file mode 100644 index 4d1a9369..00000000 --- a/docs/coverage/server.ts.html +++ /dev/null @@ -1,188 +0,0 @@ - - - - - - Code coverage report for server.ts - - - - - - - - - -
-
-

All files server.ts

-
- -
- 100% - Statements - 10/10 -
- - -
- 100% - Branches - 2/2 -
- - -
- 100% - Functions - 1/1 -
- - -
- 100% - Lines - 10/10 -
- - -
-

- Press n or j to go to the next uncovered block, b, p or k for the previous block. -

-
-
-

-
1 -2 -3 -4 -5 -6 -7 -8 -9 -10 -11 -12 -13 -14 -15 -16 -17 -18 -19 -20 -21 -22 -23 -24 -25 -26 -27 -28 -29 -30 -31 -32 -33 -34 -35 -36 -371x -  -  -1x -  -  -  -  -  -  -  -  -  -  -  -  -  -  -1x -  -  -  -  -  -  -9x -9x -9x -9x -9x -1x -  -8x -  -  -  - 
import debugFactory from "debug";
-import { IProxy } from "./httpClient";
- 
-const debug = debugFactory("NCServer");
- 
-export interface IBasicAuth {
-    "username": string;
-    "password": string;
-}
- 
-export interface IServerOptions {
-    "url": string;
-    "basicAuth": IBasicAuth;
-    "proxy"?: IProxy;
-    "logRequestResponse"?: boolean;
-}
- 
-// tslint:disable-next-line: max-classes-per-file
-export default class Server {
-    public url: string;
-    public basicAuth: IBasicAuth;
-    public proxy?: IProxy;
-    public logRequestResponse: boolean;
-    //    public constructor(url: string, basicAuth: IBasicAuth, proxy?: IProxy, logRequestResponse: boolean = false) {
-    public constructor(options: IServerOptions) {
-        debug("constructor");
-        this.url = options.url;
-        this.basicAuth = options.basicAuth;
-        this.proxy = options.proxy;
-        if (options.logRequestResponse) {
-            this.logRequestResponse = true;
-        } else {
-            this.logRequestResponse = false;
-        }
-    }
-}
- 
- -
-
- - - - - - - - - \ No newline at end of file diff --git a/docs/coverage/share.ts.html b/docs/coverage/share.ts.html deleted file mode 100644 index 68a7136a..00000000 --- a/docs/coverage/share.ts.html +++ /dev/null @@ -1,704 +0,0 @@ - - - - - - Code coverage report for share.ts - - - - - - - - - -
-
-

All files share.ts

-
- -
- 100% - Statements - 59/59 -
- - -
- 100% - Branches - 28/28 -
- - -
- 100% - Functions - 16/16 -
- - -
- 100% - Lines - 59/59 -
- - -
-

- Press n or j to go to the next uncovered block, b, p or k for the previous block. -

-
-
-

-
1 -2 -3 -4 -5 -6 -7 -8 -9 -10 -11 -12 -13 -14 -15 -16 -17 -18 -19 -20 -21 -22 -23 -24 -25 -26 -27 -28 -29 -30 -31 -32 -33 -34 -35 -36 -37 -38 -39 -40 -41 -42 -43 -44 -45 -46 -47 -48 -49 -50 -51 -52 -53 -54 -55 -56 -57 -58 -59 -60 -61 -62 -63 -64 -65 -66 -67 -68 -69 -70 -71 -72 -73 -74 -75 -76 -77 -78 -79 -80 -81 -82 -83 -84 -85 -86 -87 -88 -89 -90 -91 -92 -93 -94 -95 -96 -97 -98 -99 -100 -101 -102 -103 -104 -105 -106 -107 -108 -109 -110 -111 -112 -113 -114 -115 -116 -117 -118 -119 -120 -121 -122 -123 -124 -125 -126 -127 -128 -129 -130 -131 -132 -133 -134 -135 -136 -137 -138 -139 -140 -141 -142 -143 -144 -145 -146 -147 -148 -149 -150 -151 -152 -153 -154 -155 -156 -157 -158 -159 -160 -161 -162 -163 -164 -165 -166 -167 -168 -169 -170 -171 -172 -173 -174 -175 -176 -177 -178 -179 -180 -181 -182 -183 -184 -185 -186 -187 -188 -189 -190 -191 -192 -193 -194 -195 -196 -197 -198 -199 -200 -201 -202 -203 -204 -205 -206 -207 -208 -2091x -  -  -  -  -1x -1x -1x -1x -1x -1x -1x -  -  -1x -1x -1x -1x -1x -  -  -  -  -  -  -  -  -  -1x -1x -1x -  -1x -  -  -10x -10x -6x -  -  -  -2x -  -  -  -  -  -  -  -2x -  -  -  -  -  -2x -1x -  -1x -  -  -2x -1x -  -  -2x -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -10x -10x -  -  -  -  -  -  -  -  -  -  -1x -  -  -  -1x -1x -  -  -  -  -  -  -  -1x -  -  -  -1x -1x -  -  -  -10x -  -10x -1x -  -  -9x -1x -  -8x -  -8x -1x -  -7x -  -7x -1x -  -  -6x -5x -  -1x -  -6x -2x -  -  -6x -1x -  -  -  -  -  -  -  -  -  -  -  -2x -  -  -  -  -  -  -  -2x -  -  -  -  -  -  -  -1x -  -  -  -  -  -  -  -2x -  -  -  -  -  -  -  -2x -  -  -  - 
import Client, { ClientError } from "./client";
-import File from "./file";
-import FileSystemElement from "./fileSystemElement";
-import Folder from "./folder";
- 
-export enum SharePermission {
-    all = 31,
-    read = 1,
-    update = 2,
-    create = 4,
-    delete = 8,
-    share = 16,
-}
- 
-enum ShareType {
-    user = 0,
-    group = 1,
-    publicLink = 3,
-    email = 4,
-}
- 
-export interface ICreateShare {
-    "fileSystemElement": FileSystemElement;
-    // @todo "shareWith"?: User | UserGroup | EMail;
-    "publicUpload"?: boolean;
-    "password"?: string;
-}
- 
-enum ShareItemType {
-    file = "file",
-    folder = "folder",
-}
-export default class Share {
- 
-    public static async getShare(client: Client, id: string): Promise<Share> {
-        const share: Share = new Share(client, id);
-        await share.initialize();
-        return share;
-    }
- 
-    public static createShareRequestBody(createShare: ICreateShare): string {
-        const shareType: ShareType = ShareType.publicLink;
- 
-        const shareRequest: {
-            path: string,
-            shareType: number,
-            // @todo   permissions: number | number[]
-            password?: string,
-            publicUpload?: string,
-        } = {
-            path: createShare.fileSystemElement.name,
-            //  @todo    permissions: 1,
-            shareType,
-        };
- 
-        if (createShare.publicUpload && createShare.publicUpload === true) {
-            shareRequest.publicUpload = "enable";
-        } else {
-            shareRequest.publicUpload = "disable";
-        }
- 
-        if (createShare.password) {
-            shareRequest.password = createShare.password;
-        }
- 
-        return JSON.stringify(shareRequest, null, 4);
-    }
- 
-    private client: Client;
-    private memento: {
-        expiration: Date | null,
-        id: string;
-        itemType: ShareItemType,
-        note: string,
-        token: string,
-        url: string,
-        // share_type: number,
-        // "uid_owner": string,
-        // "displayname_owner": string,
-        // "permissions": SharePermission,
-        // "can_edit": boolean,
-        // "can_delete": boolean,
-        // "stime": Date,
-        // "parent"?: Share,
-        // "uid_file_owner": string,
-        // "label"?: string,
-        // "displayname_file_owner": string,
-        // "path": string,
-        // "mimetype"?: string,
-        // "share_with"?: string,
-        // "share_with_displayname"?: string,
-        // "mail_send": boolean,
-        // "hide_download": boolean,
-    };
- 
-    private constructor(client: Client, id: string) {
-        this.client = client;
-        this.memento = {
-            expiration: null,
-            id,
-            itemType: ShareItemType.file,
-            note: "",
-            token: "",
-            url: "",
-        };
-    }
- 
-    public async delete(): Promise<void> {
-        await this.client.deleteShare(this.memento.id);
-    }
- 
-    public async setExpiration(expiration: Date): Promise<void> {
-        this.memento.expiration = expiration;
-        await this.client.updateShare(this.memento.id, { expireDate: expiration.toISOString().split("T")[0] });
-    }
- 
-    /**
-     * set a new password
-     * @param password
-     */
-    public async setPassword(password: string): Promise<void> {
-        await this.client.updateShare(this.memento.id, { password });
-    }
- 
-    public async setNote(note: string): Promise<void> {
-        this.memento.note = note;
-        await this.client.updateShare(this.memento.id, { note });
-    }
- 
-    private async initialize(): Promise<void> {
-        const rawShareData = await this.client.getShare(this.memento.id);
- 
-        if (!rawShareData.ocs || !rawShareData.ocs.data[0]) {
-            throw new ClientError(`Error invalid share data received "ocs.data" missing`, "ERR_INVALID_SHARE_RESPONSE");
-        }
- 
-        if (!rawShareData.ocs.data[0].url) {
-            throw new ClientError(`Error invalid share data received "url" missing`, "ERR_INVALID_SHARE_RESPONSE");
-        }
-        this.memento.url = rawShareData.ocs.data[0].url;
- 
-        if (!rawShareData.ocs.data[0].token) {
-            throw new ClientError(`Error invalid share data received "token" missing`, "ERR_INVALID_SHARE_RESPONSE");
-        }
-        this.memento.token = rawShareData.ocs.data[0].token;
- 
-        if (!rawShareData.ocs.data[0].item_type) {
-            throw new ClientError(`Error invalid share data received "item_type" missing`, "ERR_INVALID_SHARE_RESPONSE");
-        }
- 
-        if (rawShareData.ocs.data[0].item_type === "file") {
-            this.memento.itemType = ShareItemType.file;
-        } else {
-            this.memento.itemType = ShareItemType.folder;
-        }
-        if (rawShareData.ocs.data[0].expiration) {
-            this.memento.expiration = new Date(rawShareData.ocs.data[0].expiration);
-        }
- 
-        if (rawShareData.ocs.data[0].note) {
-            this.memento.note = rawShareData.ocs.data[0].note;
-        }
- 
-        // console.log(JSON.stringify(rawShareData, null, 4));
-        // console.log(JSON.stringify(this, null, 4));
-    }
- 
-    /**
-     * token
-     * The token is readonly
-     */
-    public get token(): string {
-        return this.memento.token;
-    }
- 
-    /**
-     * share url
-     * The share url is readonly
-     */
-    public get url(): string {
-        return this.memento.url;
-    }
- 
-    /**
-     * expiration
-     * The expiration is readonly
-     */
-    public get expiration(): Date | null {
-        return this.memento.expiration;
-    }
- 
-    /**
-     * note
-     * The note is readonly
-     */
-    public get note(): string {
-        return this.memento.note;
-    }
- 
-    /**
-     * id
-     * The id is readonly
-     */
-    public get id(): string {
-        return this.memento.id;
-    }
- 
-}
- 
- -
-
- - - - - - - - - \ No newline at end of file diff --git a/docs/coverage/sort-arrow-sprite.png b/docs/coverage/sort-arrow-sprite.png deleted file mode 100644 index 03f704a6..00000000 Binary files a/docs/coverage/sort-arrow-sprite.png and /dev/null differ diff --git a/docs/coverage/sorter.js b/docs/coverage/sorter.js deleted file mode 100644 index 16de10c4..00000000 --- a/docs/coverage/sorter.js +++ /dev/null @@ -1,170 +0,0 @@ -/* eslint-disable */ -var addSorting = (function() { - 'use strict'; - var cols, - currentSort = { - index: 0, - desc: false - }; - - // returns the summary table element - function getTable() { - return document.querySelector('.coverage-summary'); - } - // returns the thead element of the summary table - function getTableHeader() { - return getTable().querySelector('thead tr'); - } - // returns the tbody element of the summary table - function getTableBody() { - return getTable().querySelector('tbody'); - } - // returns the th element for nth column - function getNthColumn(n) { - return getTableHeader().querySelectorAll('th')[n]; - } - - // loads all columns - function loadColumns() { - var colNodes = getTableHeader().querySelectorAll('th'), - colNode, - cols = [], - col, - i; - - for (i = 0; i < colNodes.length; i += 1) { - colNode = colNodes[i]; - col = { - key: colNode.getAttribute('data-col'), - sortable: !colNode.getAttribute('data-nosort'), - type: colNode.getAttribute('data-type') || 'string' - }; - cols.push(col); - if (col.sortable) { - col.defaultDescSort = col.type === 'number'; - colNode.innerHTML = - colNode.innerHTML + ''; - } - } - return cols; - } - // attaches a data attribute to every tr element with an object - // of data values keyed by column name - function loadRowData(tableRow) { - var tableCols = tableRow.querySelectorAll('td'), - colNode, - col, - data = {}, - i, - val; - for (i = 0; i < tableCols.length; i += 1) { - colNode = tableCols[i]; - col = cols[i]; - val = colNode.getAttribute('data-value'); - if (col.type === 'number') { - val = Number(val); - } - data[col.key] = val; - } - return data; - } - // loads all row data - function loadData() { - var rows = getTableBody().querySelectorAll('tr'), - i; - - for (i = 0; i < rows.length; i += 1) { - rows[i].data = loadRowData(rows[i]); - } - } - // sorts the table using the data for the ith column - function sortByIndex(index, desc) { - var key = cols[index].key, - sorter = function(a, b) { - a = a.data[key]; - b = b.data[key]; - return a < b ? -1 : a > b ? 1 : 0; - }, - finalSorter = sorter, - tableBody = document.querySelector('.coverage-summary tbody'), - rowNodes = tableBody.querySelectorAll('tr'), - rows = [], - i; - - if (desc) { - finalSorter = function(a, b) { - return -1 * sorter(a, b); - }; - } - - for (i = 0; i < rowNodes.length; i += 1) { - rows.push(rowNodes[i]); - tableBody.removeChild(rowNodes[i]); - } - - rows.sort(finalSorter); - - for (i = 0; i < rows.length; i += 1) { - tableBody.appendChild(rows[i]); - } - } - // removes sort indicators for current column being sorted - function removeSortIndicators() { - var col = getNthColumn(currentSort.index), - cls = col.className; - - cls = cls.replace(/ sorted$/, '').replace(/ sorted-desc$/, ''); - col.className = cls; - } - // adds sort indicators for current column being sorted - function addSortIndicators() { - getNthColumn(currentSort.index).className += currentSort.desc - ? ' sorted-desc' - : ' sorted'; - } - // adds event listeners for all sorter widgets - function enableUI() { - var i, - el, - ithSorter = function ithSorter(i) { - var col = cols[i]; - - return function() { - var desc = col.defaultDescSort; - - if (currentSort.index === i) { - desc = !currentSort.desc; - } - sortByIndex(i, desc); - removeSortIndicators(); - currentSort.index = i; - currentSort.desc = desc; - addSortIndicators(); - }; - }; - for (i = 0; i < cols.length; i += 1) { - if (cols[i].sortable) { - // add the click event handler on the th so users - // dont have to click on those tiny arrows - el = getNthColumn(i).querySelector('.sorter').parentElement; - if (el.addEventListener) { - el.addEventListener('click', ithSorter(i)); - } else { - el.attachEvent('onclick', ithSorter(i)); - } - } - } - } - // adds sorting functionality to the UI - return function() { - if (!getTable()) { - return; - } - cols = loadColumns(); - loadData(); - addSortIndicators(); - enableUI(); - }; -})(); - -window.addEventListener('load', addSorting); diff --git a/docs/coverage/src/client.ts.html b/docs/coverage/src/client.ts.html deleted file mode 100644 index 71ec7a95..00000000 --- a/docs/coverage/src/client.ts.html +++ /dev/null @@ -1,9203 +0,0 @@ - - - - - - Code coverage report for src/client.ts - - - - - - - - - -
-
-

All files / src client.ts

-
- -
- 92.97% - Statements - 1031/1109 -
- - -
- 87.44% - Branches - 383/438 -
- - -
- 92% - Functions - 92/100 -
- - -
- 92.94% - Lines - 1027/1105 -
- - -
-

- Press n or j to go to the next uncovered block, b, p or k for the previous block. -

-
-
-

-
1 -2 -3 -4 -5 -6 -7 -8 -9 -10 -11 -12 -13 -14 -15 -16 -17 -18 -19 -20 -21 -22 -23 -24 -25 -26 -27 -28 -29 -30 -31 -32 -33 -34 -35 -36 -37 -38 -39 -40 -41 -42 -43 -44 -45 -46 -47 -48 -49 -50 -51 -52 -53 -54 -55 -56 -57 -58 -59 -60 -61 -62 -63 -64 -65 -66 -67 -68 -69 -70 -71 -72 -73 -74 -75 -76 -77 -78 -79 -80 -81 -82 -83 -84 -85 -86 -87 -88 -89 -90 -91 -92 -93 -94 -95 -96 -97 -98 -99 -100 -101 -102 -103 -104 -105 -106 -107 -108 -109 -110 -111 -112 -113 -114 -115 -116 -117 -118 -119 -120 -121 -122 -123 -124 -125 -126 -127 -128 -129 -130 -131 -132 -133 -134 -135 -136 -137 -138 -139 -140 -141 -142 -143 -144 -145 -146 -147 -148 -149 -150 -151 -152 -153 -154 -155 -156 -157 -158 -159 -160 -161 -162 -163 -164 -165 -166 -167 -168 -169 -170 -171 -172 -173 -174 -175 -176 -177 -178 -179 -180 -181 -182 -183 -184 -185 -186 -187 -188 -189 -190 -191 -192 -193 -194 -195 -196 -197 -198 -199 -200 -201 -202 -203 -204 -205 -206 -207 -208 -209 -210 -211 -212 -213 -214 -215 -216 -217 -218 -219 -220 -221 -222 -223 -224 -225 -226 -227 -228 -229 -230 -231 -232 -233 -234 -235 -236 -237 -238 -239 -240 -241 -242 -243 -244 -245 -246 -247 -248 -249 -250 -251 -252 -253 -254 -255 -256 -257 -258 -259 -260 -261 -262 -263 -264 -265 -266 -267 -268 -269 -270 -271 -272 -273 -274 -275 -276 -277 -278 -279 -280 -281 -282 -283 -284 -285 -286 -287 -288 -289 -290 -291 -292 -293 -294 -295 -296 -297 -298 -299 -300 -301 -302 -303 -304 -305 -306 -307 -308 -309 -310 -311 -312 -313 -314 -315 -316 -317 -318 -319 -320 -321 -322 -323 -324 -325 -326 -327 -328 -329 -330 -331 -332 -333 -334 -335 -336 -337 -338 -339 -340 -341 -342 -343 -344 -345 -346 -347 -348 -349 -350 -351 -352 -353 -354 -355 -356 -357 -358 -359 -360 -361 -362 -363 -364 -365 -366 -367 -368 -369 -370 -371 -372 -373 -374 -375 -376 -377 -378 -379 -380 -381 -382 -383 -384 -385 -386 -387 -388 -389 -390 -391 -392 -393 -394 -395 -396 -397 -398 -399 -400 -401 -402 -403 -404 -405 -406 -407 -408 -409 -410 -411 -412 -413 -414 -415 -416 -417 -418 -419 -420 -421 -422 -423 -424 -425 -426 -427 -428 -429 -430 -431 -432 -433 -434 -435 -436 -437 -438 -439 -440 -441 -442 -443 -444 -445 -446 -447 -448 -449 -450 -451 -452 -453 -454 -455 -456 -457 -458 -459 -460 -461 -462 -463 -464 -465 -466 -467 -468 -469 -470 -471 -472 -473 -474 -475 -476 -477 -478 -479 -480 -481 -482 -483 -484 -485 -486 -487 -488 -489 -490 -491 -492 -493 -494 -495 -496 -497 -498 -499 -500 -501 -502 -503 -504 -505 -506 -507 -508 -509 -510 -511 -512 -513 -514 -515 -516 -517 -518 -519 -520 -521 -522 -523 -524 -525 -526 -527 -528 -529 -530 -531 -532 -533 -534 -535 -536 -537 -538 -539 -540 -541 -542 -543 -544 -545 -546 -547 -548 -549 -550 -551 -552 -553 -554 -555 -556 -557 -558 -559 -560 -561 -562 -563 -564 -565 -566 -567 -568 -569 -570 -571 -572 -573 -574 -575 -576 -577 -578 -579 -580 -581 -582 -583 -584 -585 -586 -587 -588 -589 -590 -591 -592 -593 -594 -595 -596 -597 -598 -599 -600 -601 -602 -603 -604 -605 -606 -607 -608 -609 -610 -611 -612 -613 -614 -615 -616 -617 -618 -619 -620 -621 -622 -623 -624 -625 -626 -627 -628 -629 -630 -631 -632 -633 -634 -635 -636 -637 -638 -639 -640 -641 -642 -643 -644 -645 -646 -647 -648 -649 -650 -651 -652 -653 -654 -655 -656 -657 -658 -659 -660 -661 -662 -663 -664 -665 -666 -667 -668 -669 -670 -671 -672 -673 -674 -675 -676 -677 -678 -679 -680 -681 -682 -683 -684 -685 -686 -687 -688 -689 -690 -691 -692 -693 -694 -695 -696 -697 -698 -699 -700 -701 -702 -703 -704 -705 -706 -707 -708 -709 -710 -711 -712 -713 -714 -715 -716 -717 -718 -719 -720 -721 -722 -723 -724 -725 -726 -727 -728 -729 -730 -731 -732 -733 -734 -735 -736 -737 -738 -739 -740 -741 -742 -743 -744 -745 -746 -747 -748 -749 -750 -751 -752 -753 -754 -755 -756 -757 -758 -759 -760 -761 -762 -763 -764 -765 -766 -767 -768 -769 -770 -771 -772 -773 -774 -775 -776 -777 -778 -779 -780 -781 -782 -783 -784 -785 -786 -787 -788 -789 -790 -791 -792 -793 -794 -795 -796 -797 -798 -799 -800 -801 -802 -803 -804 -805 -806 -807 -808 -809 -810 -811 -812 -813 -814 -815 -816 -817 -818 -819 -820 -821 -822 -823 -824 -825 -826 -827 -828 -829 -830 -831 -832 -833 -834 -835 -836 -837 -838 -839 -840 -841 -842 -843 -844 -845 -846 -847 -848 -849 -850 -851 -852 -853 -854 -855 -856 -857 -858 -859 -860 -861 -862 -863 -864 -865 -866 -867 -868 -869 -870 -871 -872 -873 -874 -875 -876 -877 -878 -879 -880 -881 -882 -883 -884 -885 -886 -887 -888 -889 -890 -891 -892 -893 -894 -895 -896 -897 -898 -899 -900 -901 -902 -903 -904 -905 -906 -907 -908 -909 -910 -911 -912 -913 -914 -915 -916 -917 -918 -919 -920 -921 -922 -923 -924 -925 -926 -927 -928 -929 -930 -931 -932 -933 -934 -935 -936 -937 -938 -939 -940 -941 -942 -943 -944 -945 -946 -947 -948 -949 -950 -951 -952 -953 -954 -955 -956 -957 -958 -959 -960 -961 -962 -963 -964 -965 -966 -967 -968 -969 -970 -971 -972 -973 -974 -975 -976 -977 -978 -979 -980 -981 -982 -983 -984 -985 -986 -987 -988 -989 -990 -991 -992 -993 -994 -995 -996 -997 -998 -999 -1000 -1001 -1002 -1003 -1004 -1005 -1006 -1007 -1008 -1009 -1010 -1011 -1012 -1013 -1014 -1015 -1016 -1017 -1018 -1019 -1020 -1021 -1022 -1023 -1024 -1025 -1026 -1027 -1028 -1029 -1030 -1031 -1032 -1033 -1034 -1035 -1036 -1037 -1038 -1039 -1040 -1041 -1042 -1043 -1044 -1045 -1046 -1047 -1048 -1049 -1050 -1051 -1052 -1053 -1054 -1055 -1056 -1057 -1058 -1059 -1060 -1061 -1062 -1063 -1064 -1065 -1066 -1067 -1068 -1069 -1070 -1071 -1072 -1073 -1074 -1075 -1076 -1077 -1078 -1079 -1080 -1081 -1082 -1083 -1084 -1085 -1086 -1087 -1088 -1089 -1090 -1091 -1092 -1093 -1094 -1095 -1096 -1097 -1098 -1099 -1100 -1101 -1102 -1103 -1104 -1105 -1106 -1107 -1108 -1109 -1110 -1111 -1112 -1113 -1114 -1115 -1116 -1117 -1118 -1119 -1120 -1121 -1122 -1123 -1124 -1125 -1126 -1127 -1128 -1129 -1130 -1131 -1132 -1133 -1134 -1135 -1136 -1137 -1138 -1139 -1140 -1141 -1142 -1143 -1144 -1145 -1146 -1147 -1148 -1149 -1150 -1151 -1152 -1153 -1154 -1155 -1156 -1157 -1158 -1159 -1160 -1161 -1162 -1163 -1164 -1165 -1166 -1167 -1168 -1169 -1170 -1171 -1172 -1173 -1174 -1175 -1176 -1177 -1178 -1179 -1180 -1181 -1182 -1183 -1184 -1185 -1186 -1187 -1188 -1189 -1190 -1191 -1192 -1193 -1194 -1195 -1196 -1197 -1198 -1199 -1200 -1201 -1202 -1203 -1204 -1205 -1206 -1207 -1208 -1209 -1210 -1211 -1212 -1213 -1214 -1215 -1216 -1217 -1218 -1219 -1220 -1221 -1222 -1223 -1224 -1225 -1226 -1227 -1228 -1229 -1230 -1231 -1232 -1233 -1234 -1235 -1236 -1237 -1238 -1239 -1240 -1241 -1242 -1243 -1244 -1245 -1246 -1247 -1248 -1249 -1250 -1251 -1252 -1253 -1254 -1255 -1256 -1257 -1258 -1259 -1260 -1261 -1262 -1263 -1264 -1265 -1266 -1267 -1268 -1269 -1270 -1271 -1272 -1273 -1274 -1275 -1276 -1277 -1278 -1279 -1280 -1281 -1282 -1283 -1284 -1285 -1286 -1287 -1288 -1289 -1290 -1291 -1292 -1293 -1294 -1295 -1296 -1297 -1298 -1299 -1300 -1301 -1302 -1303 -1304 -1305 -1306 -1307 -1308 -1309 -1310 -1311 -1312 -1313 -1314 -1315 -1316 -1317 -1318 -1319 -1320 -1321 -1322 -1323 -1324 -1325 -1326 -1327 -1328 -1329 -1330 -1331 -1332 -1333 -1334 -1335 -1336 -1337 -1338 -1339 -1340 -1341 -1342 -1343 -1344 -1345 -1346 -1347 -1348 -1349 -1350 -1351 -1352 -1353 -1354 -1355 -1356 -1357 -1358 -1359 -1360 -1361 -1362 -1363 -1364 -1365 -1366 -1367 -1368 -1369 -1370 -1371 -1372 -1373 -1374 -1375 -1376 -1377 -1378 -1379 -1380 -1381 -1382 -1383 -1384 -1385 -1386 -1387 -1388 -1389 -1390 -1391 -1392 -1393 -1394 -1395 -1396 -1397 -1398 -1399 -1400 -1401 -1402 -1403 -1404 -1405 -1406 -1407 -1408 -1409 -1410 -1411 -1412 -1413 -1414 -1415 -1416 -1417 -1418 -1419 -1420 -1421 -1422 -1423 -1424 -1425 -1426 -1427 -1428 -1429 -1430 -1431 -1432 -1433 -1434 -1435 -1436 -1437 -1438 -1439 -1440 -1441 -1442 -1443 -1444 -1445 -1446 -1447 -1448 -1449 -1450 -1451 -1452 -1453 -1454 -1455 -1456 -1457 -1458 -1459 -1460 -1461 -1462 -1463 -1464 -1465 -1466 -1467 -1468 -1469 -1470 -1471 -1472 -1473 -1474 -1475 -1476 -1477 -1478 -1479 -1480 -1481 -1482 -1483 -1484 -1485 -1486 -1487 -1488 -1489 -1490 -1491 -1492 -1493 -1494 -1495 -1496 -1497 -1498 -1499 -1500 -1501 -1502 -1503 -1504 -1505 -1506 -1507 -1508 -1509 -1510 -1511 -1512 -1513 -1514 -1515 -1516 -1517 -1518 -1519 -1520 -1521 -1522 -1523 -1524 -1525 -1526 -1527 -1528 -1529 -1530 -1531 -1532 -1533 -1534 -1535 -1536 -1537 -1538 -1539 -1540 -1541 -1542 -1543 -1544 -1545 -1546 -1547 -1548 -1549 -1550 -1551 -1552 -1553 -1554 -1555 -1556 -1557 -1558 -1559 -1560 -1561 -1562 -1563 -1564 -1565 -1566 -1567 -1568 -1569 -1570 -1571 -1572 -1573 -1574 -1575 -1576 -1577 -1578 -1579 -1580 -1581 -1582 -1583 -1584 -1585 -1586 -1587 -1588 -1589 -1590 -1591 -1592 -1593 -1594 -1595 -1596 -1597 -1598 -1599 -1600 -1601 -1602 -1603 -1604 -1605 -1606 -1607 -1608 -1609 -1610 -1611 -1612 -1613 -1614 -1615 -1616 -1617 -1618 -1619 -1620 -1621 -1622 -1623 -1624 -1625 -1626 -1627 -1628 -1629 -1630 -1631 -1632 -1633 -1634 -1635 -1636 -1637 -1638 -1639 -1640 -1641 -1642 -1643 -1644 -1645 -1646 -1647 -1648 -1649 -1650 -1651 -1652 -1653 -1654 -1655 -1656 -1657 -1658 -1659 -1660 -1661 -1662 -1663 -1664 -1665 -1666 -1667 -1668 -1669 -1670 -1671 -1672 -1673 -1674 -1675 -1676 -1677 -1678 -1679 -1680 -1681 -1682 -1683 -1684 -1685 -1686 -1687 -1688 -1689 -1690 -1691 -1692 -1693 -1694 -1695 -1696 -1697 -1698 -1699 -1700 -1701 -1702 -1703 -1704 -1705 -1706 -1707 -1708 -1709 -1710 -1711 -1712 -1713 -1714 -1715 -1716 -1717 -1718 -1719 -1720 -1721 -1722 -1723 -1724 -1725 -1726 -1727 -1728 -1729 -1730 -1731 -1732 -1733 -1734 -1735 -1736 -1737 -1738 -1739 -1740 -1741 -1742 -1743 -1744 -1745 -1746 -1747 -1748 -1749 -1750 -1751 -1752 -1753 -1754 -1755 -1756 -1757 -1758 -1759 -1760 -1761 -1762 -1763 -1764 -1765 -1766 -1767 -1768 -1769 -1770 -1771 -1772 -1773 -1774 -1775 -1776 -1777 -1778 -1779 -1780 -1781 -1782 -1783 -1784 -1785 -1786 -1787 -1788 -1789 -1790 -1791 -1792 -1793 -1794 -1795 -1796 -1797 -1798 -1799 -1800 -1801 -1802 -1803 -1804 -1805 -1806 -1807 -1808 -1809 -1810 -1811 -1812 -1813 -1814 -1815 -1816 -1817 -1818 -1819 -1820 -1821 -1822 -1823 -1824 -1825 -1826 -1827 -1828 -1829 -1830 -1831 -1832 -1833 -1834 -1835 -1836 -1837 -1838 -1839 -1840 -1841 -1842 -1843 -1844 -1845 -1846 -1847 -1848 -1849 -1850 -1851 -1852 -1853 -1854 -1855 -1856 -1857 -1858 -1859 -1860 -1861 -1862 -1863 -1864 -1865 -1866 -1867 -1868 -1869 -1870 -1871 -1872 -1873 -1874 -1875 -1876 -1877 -1878 -1879 -1880 -1881 -1882 -1883 -1884 -1885 -1886 -1887 -1888 -1889 -1890 -1891 -1892 -1893 -1894 -1895 -1896 -1897 -1898 -1899 -1900 -1901 -1902 -1903 -1904 -1905 -1906 -1907 -1908 -1909 -1910 -1911 -1912 -1913 -1914 -1915 -1916 -1917 -1918 -1919 -1920 -1921 -1922 -1923 -1924 -1925 -1926 -1927 -1928 -1929 -1930 -1931 -1932 -1933 -1934 -1935 -1936 -1937 -1938 -1939 -1940 -1941 -1942 -1943 -1944 -1945 -1946 -1947 -1948 -1949 -1950 -1951 -1952 -1953 -1954 -1955 -1956 -1957 -1958 -1959 -1960 -1961 -1962 -1963 -1964 -1965 -1966 -1967 -1968 -1969 -1970 -1971 -1972 -1973 -1974 -1975 -1976 -1977 -1978 -1979 -1980 -1981 -1982 -1983 -1984 -1985 -1986 -1987 -1988 -1989 -1990 -1991 -1992 -1993 -1994 -1995 -1996 -1997 -1998 -1999 -2000 -2001 -2002 -2003 -2004 -2005 -2006 -2007 -2008 -2009 -2010 -2011 -2012 -2013 -2014 -2015 -2016 -2017 -2018 -2019 -2020 -2021 -2022 -2023 -2024 -2025 -2026 -2027 -2028 -2029 -2030 -2031 -2032 -2033 -2034 -2035 -2036 -2037 -2038 -2039 -2040 -2041 -2042 -2043 -2044 -2045 -2046 -2047 -2048 -2049 -2050 -2051 -2052 -2053 -2054 -2055 -2056 -2057 -2058 -2059 -2060 -2061 -2062 -2063 -2064 -2065 -2066 -2067 -2068 -2069 -2070 -2071 -2072 -2073 -2074 -2075 -2076 -2077 -2078 -2079 -2080 -2081 -2082 -2083 -2084 -2085 -2086 -2087 -2088 -2089 -2090 -2091 -2092 -2093 -2094 -2095 -2096 -2097 -2098 -2099 -2100 -2101 -2102 -2103 -2104 -2105 -2106 -2107 -2108 -2109 -2110 -2111 -2112 -2113 -2114 -2115 -2116 -2117 -2118 -2119 -2120 -2121 -2122 -2123 -2124 -2125 -2126 -2127 -2128 -2129 -2130 -2131 -2132 -2133 -2134 -2135 -2136 -2137 -2138 -2139 -2140 -2141 -2142 -2143 -2144 -2145 -2146 -2147 -2148 -2149 -2150 -2151 -2152 -2153 -2154 -2155 -2156 -2157 -2158 -2159 -2160 -2161 -2162 -2163 -2164 -2165 -2166 -2167 -2168 -2169 -2170 -2171 -2172 -2173 -2174 -2175 -2176 -2177 -2178 -2179 -2180 -2181 -2182 -2183 -2184 -2185 -2186 -2187 -2188 -2189 -2190 -2191 -2192 -2193 -2194 -2195 -2196 -2197 -2198 -2199 -2200 -2201 -2202 -2203 -2204 -2205 -2206 -2207 -2208 -2209 -2210 -2211 -2212 -2213 -2214 -2215 -2216 -2217 -2218 -2219 -2220 -2221 -2222 -2223 -2224 -2225 -2226 -2227 -2228 -2229 -2230 -2231 -2232 -2233 -2234 -2235 -2236 -2237 -2238 -2239 -2240 -2241 -2242 -2243 -2244 -2245 -2246 -2247 -2248 -2249 -2250 -2251 -2252 -2253 -2254 -2255 -2256 -2257 -2258 -2259 -2260 -2261 -2262 -2263 -2264 -2265 -2266 -2267 -2268 -2269 -2270 -2271 -2272 -2273 -2274 -2275 -2276 -2277 -2278 -2279 -2280 -2281 -2282 -2283 -2284 -2285 -2286 -2287 -2288 -2289 -2290 -2291 -2292 -2293 -2294 -2295 -2296 -2297 -2298 -2299 -2300 -2301 -2302 -2303 -2304 -2305 -2306 -2307 -2308 -2309 -2310 -2311 -2312 -2313 -2314 -2315 -2316 -2317 -2318 -2319 -2320 -2321 -2322 -2323 -2324 -2325 -2326 -2327 -2328 -2329 -2330 -2331 -2332 -2333 -2334 -2335 -2336 -2337 -2338 -2339 -2340 -2341 -2342 -2343 -2344 -2345 -2346 -2347 -2348 -2349 -2350 -2351 -2352 -2353 -2354 -2355 -2356 -2357 -2358 -2359 -2360 -2361 -2362 -2363 -2364 -2365 -2366 -2367 -2368 -2369 -2370 -2371 -2372 -2373 -2374 -2375 -2376 -2377 -2378 -2379 -2380 -2381 -2382 -2383 -2384 -2385 -2386 -2387 -2388 -2389 -2390 -2391 -2392 -2393 -2394 -2395 -2396 -2397 -2398 -2399 -2400 -2401 -2402 -2403 -2404 -2405 -2406 -2407 -2408 -2409 -2410 -2411 -2412 -2413 -2414 -2415 -2416 -2417 -2418 -2419 -2420 -2421 -2422 -2423 -2424 -2425 -2426 -2427 -2428 -2429 -2430 -2431 -2432 -2433 -2434 -2435 -2436 -2437 -2438 -2439 -2440 -2441 -2442 -2443 -2444 -2445 -2446 -2447 -2448 -2449 -2450 -2451 -2452 -2453 -2454 -2455 -2456 -2457 -2458 -2459 -2460 -2461 -2462 -2463 -2464 -2465 -2466 -2467 -2468 -2469 -2470 -2471 -2472 -2473 -2474 -2475 -2476 -2477 -2478 -2479 -2480 -2481 -2482 -2483 -2484 -2485 -2486 -2487 -2488 -2489 -2490 -2491 -2492 -2493 -2494 -2495 -2496 -2497 -2498 -2499 -2500 -2501 -2502 -2503 -2504 -2505 -2506 -2507 -2508 -2509 -2510 -2511 -2512 -2513 -2514 -2515 -2516 -2517 -2518 -2519 -2520 -2521 -2522 -2523 -2524 -2525 -2526 -2527 -2528 -2529 -2530 -2531 -2532 -2533 -2534 -2535 -2536 -2537 -2538 -2539 -2540 -2541 -2542 -2543 -2544 -2545 -2546 -2547 -2548 -2549 -2550 -2551 -2552 -2553 -2554 -2555 -2556 -2557 -2558 -2559 -2560 -2561 -2562 -2563 -2564 -2565 -2566 -2567 -2568 -2569 -2570 -2571 -2572 -2573 -2574 -2575 -2576 -2577 -2578 -2579 -2580 -2581 -2582 -2583 -2584 -2585 -2586 -2587 -2588 -2589 -2590 -2591 -2592 -2593 -2594 -2595 -2596 -2597 -2598 -2599 -2600 -2601 -2602 -2603 -2604 -2605 -2606 -2607 -2608 -2609 -2610 -2611 -2612 -2613 -2614 -2615 -2616 -2617 -2618 -2619 -2620 -2621 -2622 -2623 -2624 -2625 -2626 -2627 -2628 -2629 -2630 -2631 -2632 -2633 -2634 -2635 -2636 -2637 -2638 -2639 -2640 -2641 -2642 -2643 -2644 -2645 -2646 -2647 -2648 -2649 -2650 -2651 -2652 -2653 -2654 -2655 -2656 -2657 -2658 -2659 -2660 -2661 -2662 -2663 -2664 -2665 -2666 -2667 -2668 -2669 -2670 -2671 -2672 -2673 -2674 -2675 -2676 -2677 -2678 -2679 -2680 -2681 -2682 -2683 -2684 -2685 -2686 -2687 -2688 -2689 -2690 -2691 -2692 -2693 -2694 -2695 -2696 -2697 -2698 -2699 -2700 -2701 -2702 -2703 -2704 -2705 -2706 -2707 -2708 -2709 -2710 -2711 -2712 -2713 -2714 -2715 -2716 -2717 -2718 -2719 -2720 -2721 -2722 -2723 -2724 -2725 -2726 -2727 -2728 -2729 -2730 -2731 -2732 -2733 -2734 -2735 -2736 -2737 -2738 -2739 -2740 -2741 -2742 -2743 -2744 -2745 -2746 -2747 -2748 -2749 -2750 -2751 -2752 -2753 -2754 -2755 -2756 -2757 -2758 -2759 -2760 -2761 -2762 -2763 -2764 -2765 -2766 -2767 -2768 -2769 -2770 -2771 -2772 -2773 -2774 -2775 -2776 -2777 -2778 -2779 -2780 -2781 -2782 -2783 -2784 -2785 -2786 -2787 -2788 -2789 -2790 -2791 -2792 -2793 -2794 -2795 -2796 -2797 -2798 -2799 -2800 -2801 -2802 -2803 -2804 -2805 -2806 -2807 -2808 -2809 -2810 -2811 -2812 -2813 -2814 -2815 -2816 -2817 -2818 -2819 -2820 -2821 -2822 -2823 -2824 -2825 -2826 -2827 -2828 -2829 -2830 -2831 -2832 -2833 -2834 -2835 -2836 -2837 -2838 -2839 -2840 -2841 -2842 -2843 -2844 -2845 -2846 -2847 -2848 -2849 -2850 -2851 -2852 -2853 -2854 -2855 -2856 -2857 -2858 -2859 -2860 -2861 -2862 -2863 -2864 -2865 -2866 -2867 -2868 -2869 -2870 -2871 -2872 -2873 -2874 -2875 -2876 -2877 -2878 -2879 -2880 -2881 -2882 -2883 -2884 -2885 -2886 -2887 -2888 -2889 -2890 -2891 -2892 -2893 -2894 -2895 -2896 -2897 -2898 -2899 -2900 -2901 -2902 -2903 -2904 -2905 -2906 -2907 -2908 -2909 -2910 -2911 -2912 -2913 -2914 -2915 -2916 -2917 -2918 -2919 -2920 -2921 -2922 -2923 -2924 -2925 -2926 -2927 -2928 -2929 -2930 -2931 -2932 -2933 -2934 -2935 -2936 -2937 -2938 -2939 -2940 -2941 -2942 -2943 -2944 -2945 -2946 -2947 -2948 -2949 -2950 -2951 -2952 -2953 -2954 -2955 -2956 -2957 -2958 -2959 -2960 -2961 -2962 -2963 -2964 -2965 -2966 -2967 -2968 -2969 -2970 -2971 -2972 -2973 -2974 -2975 -2976 -2977 -2978 -2979 -2980 -2981 -2982 -2983 -2984 -2985 -2986 -2987 -2988 -2989 -2990 -2991 -2992 -2993 -2994 -2995 -2996 -2997 -2998 -2999 -3000 -3001 -3002 -3003 -3004 -3005 -3006 -3007 -3008 -3009 -3010 -3011 -3012 -3013 -3014 -3015 -3016 -3017 -3018 -3019 -3020 -3021 -3022 -3023 -3024 -3025 -3026 -3027 -3028 -3029 -3030 -3031 -3032 -3033 -3034 -3035 -3036 -3037 -3038 -3039 -3040 -3041 -3042  -  -1x -1x -1x -  -1x -1x -1x -1x -1x -1x -1x -1x -1x -1x -1x -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -1x -1x -1x -1x -1x -1x -1x -1x -1x -1x -1x -1x -1x -1x -  -1x -  -  -  -1x -2x -5x -8x -3x -3x -9x -2x -4x -3x -5x -2x -2x -8x -  -  -  -1x -1x -1x -1x -1x -1x -  -  -1x -1x -1x -1x -1x -1x -1x -1x -1x -2x -  -  -1x -  -  -  -  -  -1x -  -1x -  -1x -  -1x -  -  -1x -  -12x -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -1x -1x -  -  -  -  -  -  -  -230x -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -230x -230x -230x -230x -230x -230x -  -  -  -230x -6x -6x -1x -  -5x -  -  -  -  -  -  -  -  -4x -  -  -  -229x -169x -  -169x -  -169x -3x -1x -  -3x -  -  -169x -  -169x -169x -169x -169x -169x -2x -  -167x -  -  -169x -  -169x -  -  -  -  -  -  -169x -  -  -229x -60x -60x -  -  -  -  -  -  -  -13x -13x -  -  -  -13x -  -13x -  -5x -5x -25x -13x -  -  -  -13x -7x -  -  -  -  -5x -1x -1x -  -4x -4x -  -  -  -  -  -  -  -  -  -  -  -  -  -30x -  -  -30x -30x -14x -  -  -  -16x -  -  -  -  -  -  -16x -16x -  -16x -1x -1x -  -15x -  -  -15x -  -15x -15x -  -  -  -  -  -  -  -  -38x -  -38x -38x -56x -20x -  -  -18x -  -  -  -  -  -  -  -  -2x -  -2x -2x -4x -1x -  -  -1x -  -  -  -  -  -  -  -  -16x -  -16x -  -  -  -16x -  -  -  -  -  -  -  -1x -  -1x -  -1x -  -2x -  -  -  -  -  -  -  -  -42x -42x -  -  -  -  -  -  -  -  -  -  -  -  -  -42x -  -42x -  -42x -42x -  -42x -  -94x -  -  -42x -  -  -  -  -  -  -  -4x -  -4x -  -  -  -  -  -  -  -  -  -  -  -  -  -4x -4x -  -4x -  -4x -  -4x -8x -  -  -4x -4x -  -  -  -  -  -  -  -  -1x -  -1x -  -  -  -1x -1x -  -  -  -  -  -  -  -2x -  -2x -  -  -  -  -  -  -  -  -  -2x -  -2x -  -2x -2x -1x -1x -  -  -  -  -  -  -1x -1x -  -  -  -8x -  -8x -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -8x -8x -7x -  -7x -  -  -  -  -  -  -  -7x -  -  -7x -7x -7x -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -149x -149x -  -149x -149x -615x -2x -  -  -  -  -  -147x -147x -25x -25x -  -  -122x -122x -122x -  -  -63x -63x -63x -63x -  -63x -245x -245x -245x -  -245x -85x -  -  -85x -85x -  -160x -  -  -  -  -  -72x -72x -71x -71x -  -1x -  -  -  -  -  -  -  -  -  -  -  -  -25x -25x -  -25x -  -  -25x -25x -  -1x -1x -  -  -  -  -  -  -  -  -22x -22x -  -22x -  -22x -16x -  -  -  -  -  -  -  -  -4x -  -  -  -  -  -  -  -  -  -5x -5x -  -5x -7x -  -5x -5x -5x -  -  -  -  -  -  -  -  -  -5x -  -  -  -  -  -5x -5x -  -1x -1x -  -4x -  -4x -4x -4x -  -1x -  -  -3x -12x -  -12x -  -  -12x -12x -12x -12x -  -12x -6x -  -6x -  -  -12x -  -3x -  -  -  -  -  -  -  -  -510x -510x -  -  -510x -4x -  -  -506x -506x -387x -387x -281x -  -106x -106x -  -  -119x -119x -  -  -  -  -  -  -  -  -  -5x -5x -5x -  -5x -  -5x -  -  -  -  -  -5x -  -  -  -  -  -  -  -  -  -3x -3x -3x -  -3x -  -3x -  -  -  -  -  -  -  -  -  -  -  -  -  -3x -  -  -  -  -  -  -  -  -97x -1x -  -  -97x -97x -  -97x -  -  -97x -53x -  -53x -  -53x -1x -  -52x -  -  -  -  -  -  -  -75x -  -75x -75x -70x -70x -70x -  -  -  -  -  -5x -5x -  -  -  -  -  -  -  -  -  -3x -3x -  -3x -  -3x -  -  -  -  -3x -3x -  -1x -1x -  -  -2x -2x -1x -  -  -1x -  -  -  -  -  -  -  -  -3x -3x -  -3x -  -3x -  -  -  -  -3x -3x -  -1x -1x -  -  -2x -2x -1x -  -  -1x -  -  -  -  -  -  -  -  -2x -2x -2x -  -  -  -2x -2x -  -1x -1x -  -  -1x -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -3x -3x -  -  -  -  -  -  -  -1x -1x -  -  -  -  -  -  -  -  -  -  -  -  -18x -18x -  -18x -1x -  -  -17x -  -  -  -  -  -  -  -17x -  -  -  -  -  -  -17x -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -8x -  -8x -  -  -  -  -  -  -8x -  -  -  -  -  -  -8x -  -  -  -  -  -  -  -  -  -  -  -3x -3x -1x -  -  -3x -1x -  -  -3x -  -  -  -  -  -  -  -  -3x -  -3x -3x -3x -6x -  -  -3x -  -  -  -  -  -  -8x -  -  -  -  -8x -  -8x -  -8x -8x -8x -8x -8x -  -8x -7x -6x -5x -  -1x -  -  -5x -4x -  -1x -  -  -4x -3x -  -1x -  -  -1x -  -  -3x -2x -  -1x -  -  -2x -1x -  -1x -  -  -1x -  -  -1x -  -  -  -  -  -  -  -  -  -  -  -  -1x -  -  -  -4x -  -  -  -  -4x -  -4x -  -  -  -4x -1x -  -  -  -  -  -  -  -  -3x -  -  -1x -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -29x -  -29x -27x -27x -17x -  -27x -  -  -  -  -  -  -  -  -  -  -  -  -29x -29x -  -  -  -  -29x -29x -29x -25x -  -29x -2x -1x -  -1x -  -28x -2x -1x -  -1x -  -27x -25x -  -27x -  -27x -27x -  -  -  -  -  -  -  -  -  -  -  -  -  -  -27x -  -27x -26x -  -26x -  -17x -  -  -27x -  -  -  -  -  -  -  -  -24x -24x -14x -  -10x -  -  -  -  -  -  -  -  -  -4x -4x -  -  -  -  -4x -4x -  -4x -4x -4x -  -4x -1x -  -  -3x -2x -  -2x -4x -  -  -  -3x -  -  -  -  -  -  -  -  -  -5x -5x -  -  -  -  -5x -5x -  -5x -5x -5x -  -5x -1x -  -  -4x -3x -  -3x -1x -  -  -  -4x -  -  -  -  -  -  -  -  -  -  -18x -18x -  -  -  -  -18x -18x -18x -  -18x -1x -  -  -17x -14x -  -3x -  -  -  -  -  -  -  -  -  -  -23x -23x -  -  -  -23x -23x -23x -  -23x -8x -  -  -15x -1x -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -47x -47x -  -  -  -  -47x -47x -47x -46x -  -47x -4x -1x -  -3x -  -46x -2x -1x -  -1x -  -45x -44x -  -45x -  -45x -45x -  -  -  -  -  -  -  -  -  -  -  -  -  -  -45x -  -45x -44x -  -44x -43x -  -  -  -45x -  -  -  -  -  -  -  -  -  -72x -72x -  -  -  -  -72x -72x -  -72x -72x -  -72x -1x -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -71x -71x -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -71x -35x -  -36x -35x -  -36x -36x -1x -  -36x -1x -  -  -71x -  -  -  -  -  -  -  -  -  -4x -4x -  -  -  -  -4x -4x -  -4x -4x -  -4x -2x -  -2x -  -  -  -  -  -  -  -  -  -5x -5x -  -  -  -  -5x -5x -  -5x -5x -  -5x -3x -  -2x -  -  -  -  -  -  -  -  -  -36x -36x -  -  -  -  -36x -36x -  -36x -36x -  -36x -18x -  -18x -  -  -  -  -  -  -  -  -41x -41x -41x -35x -  -6x -  -  -  -  -  -  -  -  -  -  -  -23x -23x -23x -4x -3x -  -1x -  -  -22x -19x -  -  -22x -  -  -  -  -22x -22x -22x -  -22x -1x -  -  -21x -21x -18x -  -  -3x -  -  -  -  -  -  -  -  -  -  -  -  -  -51x -51x -  -51x -  -  -  -  -51x -51x -51x -51x -  -  -  -  -  -  -  -  -  -  -51x -1x -  -  -50x -32x -  -  -18x -3x -  -  -18x -  -  -  -  -  -  -  -  -5x -  -5x -  -  -  -5x -5x -5x -5x -  -5x -1x -  -  -4x -2x -  -2x -  -  -  -  -  -  -  -  -  -  -  -  -  -16x -  -16x -16x -  -  -  -  -  -16x -16x -  -16x -16x -  -16x -9x -  -  -6x -1x -  -  -5x -1x -  -  -4x -1x -  -  -3x -  -  -  -  -  -  -  -  -  -  -  -  -  -14x -  -14x -14x -  -  -  -  -  -14x -14x -  -14x -12x -  -12x -7x -  -  -5x -1x -  -  -4x -1x -  -  -3x -1x -  -  -2x -  -  -  -  -  -  -  -  -  -  -  -  -  -13x -  -13x -13x -  -  -  -  -  -13x -13x -  -13x -13x -  -13x -8x -  -  -5x -1x -  -  -4x -1x -  -  -3x -1x -  -  -2x -  -  -  -  -  -  -  -  -  -  -  -10x -  -10x -10x -  -  -  -  -  -10x -10x -  -10x -10x -  -10x -4x -  -  -  -  -  -  -  -  -  -  -  -  -  -6x -1x -  -  -5x -  -  -  -  -  -  -  -  -12x -12x -18x -18x -  -  -18x -2x -2x -1x -  -1x -1x -1x -  -  -16x -  -  -17x -17x -17x -  -  -  -  -17x -7x -3x -3x -2x -  -1x -  -  -  -7x -2x -2x -1x -  -1x -  -  -  -  -  -  -  -17x -6x -3x -3x -2x -  -1x -  -  -  -6x -2x -2x -1x -  -1x -  -  -  -  -  -  -  -17x -8x -8x -8x -4x -2x -1x -  -  -  -13x -10x -  -8x -8x -8x -8x -8x -5x -5x -  -2x -2x -  -  -6x -6x -  -1x -1x -  -  -  -8x -5x -5x -  -2x -2x -  -  -8x -3x -  -5x -5x -  -  -  -  -  -  -  -17x -8x -8x -10x -8x -  -8x -8x -8x -7x -7x -2x -2x -  -1x -1x -  -  -6x -6x -  -1x -1x -  -  -  -8x -4x -4x -  -1x -1x -  -  -8x -3x -  -5x -  -  -  -  -  -  -17x -6x -6x -6x -6x -4x -4x -3x -  -1x -1x -1x -  -1x -  -  -  -  -  -  -  -17x -6x -6x -6x -6x -3x -3x -2x -  -1x -1x -1x -  -1x -  -  -  -  -  -  -  -17x -5x -5x -5x -5x -3x -3x -1x -  -2x -2x -2x -  -2x -  -  -  -  -  -  -  -17x -5x -5x -5x -5x -3x -3x -1x -  -2x -2x -2x -  -2x -  -  -  -  -  -  -  -17x -6x -6x -6x -6x -3x -3x -2x -  -1x -1x -1x -  -1x -  -  -  -  -  -  -  -17x -6x -6x -6x -6x -4x -4x -3x -  -1x -1x -1x -  -  -1x -  -  -  -  -  -  -  -17x -5x -5x -5x -5x -5x -3x -  -2x -2x -2x -  -2x -  -  -  -  -  -  -17x -6x -6x -6x -6x -3x -3x -2x -  -1x -1x -1x -  -1x -  -  -  -  -  -  -  -17x -6x -6x -6x -6x -3x -3x -2x -  -1x -1x -1x -  -1x -  -  -  -  -  -  -  -17x -5x -5x -5x -5x -3x -3x -1x -  -2x -2x -2x -  -  -2x -  -  -  -  -  -  -  -17x -6x -6x -6x -6x -2x -2x -1x -  -1x -1x -1x -  -  -1x -  -  -  -  -17x -1x -  -17x -  -12x -  -  -  -  -  -  -  -  -  -  -  -3x -3x -  -3x -  -  -  -  -3x -  -  -3x -  -3x -  -3x -  -3x -  -3x -2x -  -  -3x -  -  -  -  -  -  -  -  -  -  -  -  -  -  -4x -  -4x -  -  -  -  -4x -  -4x -  -  -  -  -  -  -  -11x -  -  -  -11x -  -11x -  -  -11x -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -1x -  -  -  -1x -  -1x -  -  -  -  -  -  -  -  -  -  -3x -  -  -  -  -3x -  -  -3x -1x -  -  -2x -  -2x -  -2x -1x -  -1x -  -  -  -1x -1x -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -533x -  -533x -1x -  -  -532x -1x -  -  -531x -  -531x -1x -  -530x -  -  -530x -  -  -530x -2x -  -  -  -528x -196x -  -  -  -  -  -  -528x -528x -1275x -1x -  -  -1274x -1x -  -1273x -  -  -1273x -352x -  -  -1273x -2194x -1x -  -2193x -1225x -1x -  -1224x -  -1224x -1224x -  -  -  -  -  -524x -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -1413x -381x -  -  -  -1413x -109x -  -  -  -  -  -  -  -  -  -  -  -  -8x -8x -8x -8x -  -8x -5x -  -3x -  -8x -8x -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -8x -  -  -  -8x -  -  -  -697x -4x -  -  -697x -697x -7x -  -  -697x -  -  -  -109x -  -  -  -207x -207x -  -207x -  -  -207x -207x -  -113x -113x -  -  -  -  -581x -581x -  -581x -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -581x -581x -  -123x -123x -  -  -458x -458x -  -458x -1038x -  -  -  -  -  -  -  -1038x -182x -  -856x -  -  -1038x -181x -  -  -  -458x -1x -1x -  -457x -  -  -  -  -397x -397x -396x -396x -334x -  -396x -  -1x -  -  -  -408x -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -374x -  -  -  -53x -53x -  -53x -  -  -  -  -53x -53x -53x -  -  -  -53x -  -  - 
/* eslint-disable @typescript-eslint/no-unsafe-assignment, @typescript-eslint/no-unsafe-member-access */
- 
-import { config } from "dotenv";
-config();
-import Joi from "joi";
- 
-import UploadFilesCommand, { UploadFilesCommandOptions, SourceTargetFileNames } from "./command/uploadFilesCommand";
-import UploadFolderCommand, { UploadFolderCommandOptions } from "./command/uploadFolderCommand";
-import GetFilesRecursivelyCommand, { GetFilesRecursivelyCommandOptions } from "./command/getFilesRecursivelyCommand";
-import DownloadFolderCommand, { DownloadFolderCommandOptions } from "./command/downloadFolderCommand";
-import { CommandStatus, CommandResultMetaData } from "./command/command";
-import parser from "fast-xml-parser";
-import { Headers, RequestInit, Response } from "node-fetch";
-import path, { basename } from "path";
-import Environment from "./environment";
-import EnvironmentVcapServices from "./environmentVcapServices";
-import ClientError, {
-  CommandAlreadyExecutedError,
-  QueryLimitError,
-  QueryOffsetError,
-  InsufficientPrivilegesError,
-  InvalidServiceResponseFormatError,
-  OperationFailedError,
-  UserGroupAlreadyExistsError,
-  UserGroupDeletionFailedError,
-  UserResendWelcomeEmailError,
-  UserGroupDoesNotExistError,
-  UserNotFoundError,
-  UserAlreadyExistsError,
-  UserCreateError,
-  UserUpdateError,
-} from "./error";
-import FakeServer from "./fakeServer";
-import File from "./file";
-import FileSystemElement from "./fileSystemElement";
-import FileSystemFolder, { IFileNameFormats } from "./fileSystemFolder";
-import Folder, { FolderGetFilesOptions } from "./folder";
-import { HttpClient, IHttpClientOptions, IProxy, IRequestContext } from "./httpClient";
-import RequestResponseLog from "./requestResponseLog";
-import RequestResponseLogEntry from "./requestResponseLogEntry";
-import Server, { IServerOptions } from "./server";
-import Share, { ICreateShare, SharePermission, ShareItemType } from "./share";
-import Tag from "./tag";
-import UserGroup from "./userGroup";
-import User, { IUserOptions, IUserOptionsQuota, IUserQuotaUserFriendly, UserProperty } from "./user";
-import Logger from "./logger";
-import { isNumber } from "util";
-const log: Logger = new Logger();
- 
-export {
-  FolderGetFilesOptions,
-  CommandAlreadyExecutedError,
-  InvalidServiceResponseFormatError,
-  InsufficientPrivilegesError,
-  OperationFailedError,
-  QueryLimitError,
-  QueryOffsetError,
-  UserNotFoundError,
-  UserAlreadyExistsError,
-  UserCreateError,
-  UserResendWelcomeEmailError,
-  UserUpdateError,
-  UserGroupAlreadyExistsError,
-  UserGroupDeletionFailedError,
-  UserGroupDoesNotExistError,
-};
- 
-export {
-  Client,
-  ClientError,
-  Environment,
-  Folder,
-  File,
-  FileSystemElement,
-  ICreateShare,
-  IServerOptions,
-  Tag,
-  FakeServer,
-  Server,
-  Share,
-  SharePermission,
-  RequestResponseLog,
-  RequestResponseLogEntry,
-  User,
-  UserGroup,
-  UserProperty,
-  IUserOptionsQuota,
-  IUserQuotaUserFriendly,
-  ShareItemType,
-};
- 
-// command object for upload
-export {
-  CommandResultMetaData,
-  DownloadFolderCommand,
-  DownloadFolderCommandOptions,
-  GetFilesRecursivelyCommand,
-  GetFilesRecursivelyCommandOptions,
-  UploadFilesCommand,
-  UploadFilesCommandOptions,
-  UploadFolderCommand,
-  UploadFolderCommandOptions,
-  SourceTargetFileNames,
-  FileSystemFolder,
-  IFileNameFormats,
-  CommandStatus,
-};
- 
-interface IStat {
-  type: string;
-  filename: string;
-  basename: string;
-  lastmod: string;
-  size?: number;
-  mime?: string;
-  fileid?: number;
-}
- 
-export interface IUpsertUserOptions {
-  id: string;
-  enabled?: boolean;
-  subadminGroups?: string[];
-  memberGroups?: string[];
-  quota?: string;
-  email?: string;
-  displayName?: string;
-  password?: string;
-  phone?: string;
-  address?: string;
-  website?: string;
-  twitter?: string;
-  language?: string;
-  locale?: string;
-  superAdmin?: boolean;
-  resendWelcomeEmail?: boolean;
-}
- 
-export interface IUserPropertyChange {
-  property: string;
-  previousValue: string;
-  newValue: string;
-  error?: string;
-}
- 
-export interface IUpsertUserReport {
-  id: string;
-  message: string;
-  changes: IUserPropertyChange[];
-}
- 
-export interface ISysInfoNextcloudClient {
-  version: string;
-}
- 
-// @todo refactoring of type
-export interface ISysInfoNextcloud {
-  system: any;
-  storage: any;
-  shares: any;
-}
- 
-export interface ISysBasicData {
-  serverTimeString: string;
-  uptimeString: string;
-  timeServersString: string;
-}
- 
-// @todo refactoring of type
-export interface ISystemInfo {
-  nextcloud: ISysInfoNextcloud;
-  // @todo change object to something strongly typed
-  server: any;
-  // @todo change object to something strongly typed
-  activeUsers: any;
-  nextcloudClient: ISysInfoNextcloudClient;
-}
- 
-export interface IQuota {
-  used: number;
-  available: number | string;
-}
- 
-/**
- * The nextcloud client is the root object to access the remote api of the nextcloud server.<br>
- */
-export default class Client {
-  public static webDavUrlPath: string = "/remote.php/webdav";
- 
-  private nextcloudOrigin: string;
-  private nextcloudAuthHeader: string;
-  private nextcloudRequestToken: string;
-  private webDAVUrl: string;
-  private proxy?: IProxy;
-  private fakeServer?: FakeServer;
-  private logRequestResponse: boolean = false;
-  private httpClient?: HttpClient;
-  private userId: string;
- 
-  /**
-   * Creates a new instance of a nextcloud client.<br/>
-   * Use the server to provide server connectivity information to the client.<br/>
-   * (The FakeServer is only used for testing and code coverage)<br/><br/>
-   * If the server is not provided the client tries to find the connectivity information
-   * in the environment.<br/>
-   * If a <b>VCAP_SERVICES</b> environment variable is available, the client tries to find
-   * a service with the name <b>"nextcloud"</b> in the user-provides-services section.<br/>
-   * If no VCAP_SERVICES are available, the client uses the following variables
-   * from the envirnonment for the connectivity:<br/>
-   * <ul>
-   * <li>NEXTCLOUD_URL - the url of the nextcloud server</li>
-   * <li>NEXTCLOUD_USERNAME - the user name</li>
-   * <li>NEXTCLOUD_PASSWORD - the application password</li>
-   * </ul>
-   * @param server optional server information to connection to a nextcloud server
-   * @constructor
-   */
-  public constructor(server?: Server | FakeServer) {
-    log.debug("constructor");
-    this.nextcloudOrigin = "";
-    this.nextcloudAuthHeader = "";
-    this.nextcloudRequestToken = "";
-    this.webDAVUrl = "";
-    this.userId = "";
- 
-    // if no server is provided, try to get a server from VCAP_S environment "nextcloud" instance
-    // If no VCAP_S environment exists try from environment
-    if (!server) {
-      try {
-        const env: EnvironmentVcapServices = new EnvironmentVcapServices("nextcloud");
-        server = env.getServer();
-      } catch (e) {
-        const serverOptions: IServerOptions = {
-          url: Environment.getNextcloudUrl(),
-          basicAuth: {
-            username: Environment.getUserName(),
-            password: Environment.getPassword(),
-          },
-          logRequestResponse: Environment.getRecordingActiveIndicator(),
-        };
- 
-        server = new Server(serverOptions);
-      }
-    }
- 
-    if (server instanceof Server) {
-      this.proxy = server.proxy;
- 
-      log.debug("constructor: url ", server.url);
- 
-      if (server.url.indexOf(Client.webDavUrlPath) === -1) {
-        if (server.url.slice(-1) === "/") {
-          server.url = server.url.slice(0, -1);
-        }
-        server.url = server.url + Client.webDavUrlPath;
-      }
- 
-      this.nextcloudOrigin = server.url.substr(0, server.url.indexOf(Client.webDavUrlPath));
- 
-      log.debug("constructor: nextcloud url ", this.nextcloudOrigin);
-      this.userId = server.basicAuth.username;
-      this.nextcloudAuthHeader = "Basic " + Buffer.from(server.basicAuth.username + ":" + server.basicAuth.password).toString("base64");
-      this.nextcloudRequestToken = "";
-      if (server.url.slice(-1) === "/") {
-        this.webDAVUrl = server.url.slice(0, -1);
-      } else {
-        this.webDAVUrl = server.url;
-      }
- 
-      this.logRequestResponse = server.logRequestResponse;
- 
-      const options: IHttpClientOptions = {
-        authorizationHeader: this.nextcloudAuthHeader,
-        logRequestResponse: this.logRequestResponse,
-        origin: this.nextcloudOrigin,
-        proxy: this.proxy,
-      };
- 
-      this.httpClient = new HttpClient(options);
-    }
- 
-    if (server instanceof FakeServer) {
-      this.fakeServer = server;
-      this.webDAVUrl = "https://fake.server" + Client.webDavUrlPath;
-    }
-  }
- 
-  /**
-   * returns the used and free quota of the nextcloud account
-   */
-  public async getQuota(): Promise<IQuota> {
-    log.debug("getQuota");
-    const requestInit: RequestInit = {
-      method: "PROPFIND",
-    };
- 
-    const response: Response = await this.getHttpResponse(this.webDAVUrl + "/", requestInit, [207], { description: "Client get quota" });
- 
-    const properties: any[] = await this.getPropertiesFromWebDAVMultistatusResponse(response, Client.webDavUrlPath + "/");
- 
-    let quota: IQuota | null = null;
-    for (const prop of properties) {
-      if (prop["quota-available-bytes"]) {
-        quota = {
-          available: "unlimited",
-          used: prop["quota-used-bytes"],
-        };
-        if (prop["quota-available-bytes"] > 0) {
-          quota.available = prop["quota-available-bytes"];
-        }
-      }
-    }
- 
-    if (!quota) {
-      log.debug("Error, quota not available: ", JSON.stringify(properties, null, 4));
-      throw new ClientError(`Error, quota not available`, "ERR_QUOTA_NOT_AVAILABLE");
-    }
-    log.debug("getQuota =", quota);
-    return quota;
-  }
- 
-  // ***************************************************************************************
-  // tags
-  // ***************************************************************************************
- 
-  /**
-   * creates a new tag, if not already existing
-   * this function will fail with http 403 if the user does not have admin privileges
-   * @param tagName the name of the tag
-   * @returns tagId
-   */
-  public async createTag(tagName: string): Promise<Tag> {
-    log.debug("createTag");
-    let tag: Tag | null;
-    // is the tag already existing?
-    tag = await this.getTagByName(tagName);
-    if (tag) {
-      return tag;
-    }
-    // tag does not exist, create tag
- 
-    const requestInit: RequestInit = {
-      body: `{ "name": "${tagName}", "userVisible": true, "userAssignable": true, "canAssign": true }`,
-      // eslint-disable-next-line @typescript-eslint/naming-convention
-      headers: new Headers({ "Content-Type": "application/json" }),
-      method: "POST",
-    };
- 
-    const response: Response = await this.getHttpResponse(this.nextcloudOrigin + "/remote.php/dav/systemtags/", requestInit, [201], { description: "Tag create" });
-    const tagString: string | null = response.headers.get("Content-Location");
- 
-    if (tagString === "" || tagString === null) {
-      log.error(`createTag 'tagName' ${tagName}`);
-      throw new ClientError(`Error, tag with name '${tagName}' could not be created`, "ERR_TAG_CREATE_FAILED");
-    }
-    log.debug(`createTag new tagId ${tagString} tagName ${tagName}`);
- 
-    // the number id of the tag is the last element in the id (path)
-    const tagId: number = this.getTagIdFromHref(tagString);
- 
-    tag = new Tag(this, tagId, tagName, true, true, true);
-    return tag;
-  }
- 
-  /**
-   * returns a tag identified by the name or null if not found
-   * @param tagName the name of the tag
-   * @returns tag or null
-   */
-  public async getTagByName(tagName: string): Promise<Tag | null> {
-    log.debug("getTag");
- 
-    const tags: Tag[] = await this.getTags();
-    for (const tag of tags) {
-      if (tag.name === tagName) {
-        return tag;
-      }
-    }
-    return null;
-  }
- 
-  /**
-   * returns a tag identified by the id or null if not found
-   * @param tagId the id of the tag
-   * @returns tag or null
-   */
-  public async getTagById(tagId: number): Promise<Tag | null> {
-    log.debug("getTagById");
- 
-    const tags: Tag[] = await this.getTags();
-    for (const tag of tags) {
-      if (tag.id === tagId) {
-        return tag;
-      }
-    }
-    return null;
-  }
- 
-  /**
-   * deletes the tag by id
-   * this function will fail with http 403 if the user does not have admin privileges
-   * @param tagId the id of the tag like "/remote.php/dav/systemtags/234"
-   */
-  public async deleteTag(tagId: number): Promise<void> {
-    log.debug("deleteTag tagId: ", tagId);
- 
-    const requestInit: RequestInit = {
-      method: "DELETE",
-    };
- 
-    const response: Response = await this.getHttpResponse(`${this.nextcloudOrigin}/remote.php/dav/systemtags/${tagId}`, requestInit, [204, 404], { description: "Tag delete" });
-  }
- 
-  /**
-   * deletes all visible assignable tags
-   * @throws Error
-   */
-  public async deleteAllTags(): Promise<void> {
-    log.debug("deleteAllTags");
- 
-    const tags: Tag[] = await this.getTags();
- 
-    for (const tag of tags) {
-      // log.debug("deleteAllTags tag: ", tag);
-      await tag.delete();
-    }
-  }
- 
-  /**
-   * returns a list of tags
-   * @returns array of tags
-   */
-  public async getTags(): Promise<Tag[]> {
-    log.debug("getTags PROPFIND " + this.nextcloudOrigin + "/remote.php/dav/systemtags/");
-    const requestInit: RequestInit = {
-      body: `<?xml version="1.0"?>
-            <d:propfind  xmlns:d="DAV:" xmlns:oc="http://owncloud.org/ns">
-              <d:prop>
-                <oc:id />
-                <oc:display-name />
-                <oc:user-visible />
-                <oc:user-assignable />
-                <oc:can-assign />
-              </d:prop>
-            </d:propfind>`,
-      method: "PROPFIND",
-    };
- 
-    const relUrl = `/remote.php/dav/systemtags/`;
- 
-    const response: Response = await this.getHttpResponse(this.nextcloudOrigin + relUrl, requestInit, [207], { description: "Tags get" });
- 
-    const properties: any[] = await this.getPropertiesFromWebDAVMultistatusResponse(response, relUrl + "/*");
-    const tags: Tag[] = [];
- 
-    for (const prop of properties) {
-      // eslint-disable-next-line no-underscore-dangle
-      tags.push(new Tag(this, this.getTagIdFromHref(prop._href), prop["display-name"], prop["user-visible"], prop["user-assignable"], prop["can-assign"]));
-    }
- 
-    return tags;
-  }
- 
-  /**
-   * returns the list of tag names and the tag ids
-   * @param fileId the id of the file
-   */
-  public async getTagsOfFile(fileId: number): Promise<Map<string, number>> {
-    log.debug("getTagsOfFile");
- 
-    const requestInit: RequestInit = {
-      body: `<?xml version="1.0"?>
-            <d:propfind  xmlns:d="DAV:" xmlns:oc="http://owncloud.org/ns">
-              <d:prop>
-                <oc:id />
-                <oc:display-name />
-                <oc:user-visible />
-                <oc:user-assignable />
-                <oc:can-assign />
-              </d:prop>
-            </d:propfind>`,
-      method: "PROPFIND",
-    };
- 
-    const relUrl = `/remote.php/dav/systemtags-relations/files/${fileId}`;
-    const response: Response = await this.getHttpResponse(`${this.nextcloudOrigin}${relUrl}`, requestInit, [207], { description: "File get tags" });
- 
-    const properties: any[] = await this.getPropertiesFromWebDAVMultistatusResponse(response, relUrl + "/*");
-    // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
-    const tagMap: Map<string, number> = new Map();
- 
-    for (const prop of properties) {
-      tagMap.set(prop["display-name"], prop.id);
-    }
- 
-    log.debug("tags of file ", tagMap);
-    return tagMap;
-  }
- 
-  /**
-   * removes the tag from the file
-   * @param fileId the file id
-   * @param tagId the tag id
-   */
-  public async removeTagOfFile(fileId: number, tagId: number): Promise<void> {
-    log.debug(`removeTagOfFile tagId: ${tagId} fileId:${fileId}`);
- 
-    const requestInit: RequestInit = {
-      method: "DELETE",
-    };
- 
-    await this.getHttpResponse(`${this.nextcloudOrigin}/remote.php/dav/systemtags-relations/files/${fileId}/${tagId}`, requestInit, [204, 404], { description: "File remove tag" });
-    return;
-  }
- 
-  /**
-   * returns the id of the file or -1 of not found
-   * @returns id of the file or -1 if not found
-   */
-  public async getFileId(fileUrl: string): Promise<number> {
-    log.debug("getFileId");
- 
-    const requestInit: RequestInit = {
-      body: `
-            <d:propfind  xmlns:d="DAV:" xmlns:oc="http://owncloud.org/ns" xmlns:nc="http://nextcloud.org/ns">
-              <d:prop>
-                  <oc:fileid />
-              </d:prop>
-            </d:propfind>`,
-      method: "PROPFIND",
-    };
- 
-    const response: Response = await this.getHttpResponse(fileUrl, requestInit, [207], { description: "File get id" });
- 
-    const properties: any[] = await this.getPropertiesFromWebDAVMultistatusResponse(response, "");
- 
-    for (const prop of properties) {
-      if (prop.fileid !== undefined) {
-        Eif (typeof prop.fileid === "number") {
-          return prop.fileid as number;
-        } else {
-          return -1;
-        }
-      }
-    }
- 
-    log.debug("getFileId no file id found for " + fileUrl);
-    return -1;
-  }
- 
-  public async getFolderContents(folderName: string): Promise<any[]> {
-    log.debug("getFolderContents");
- 
-    const requestInit: RequestInit = {
-      body: `<?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:getetag />
-                <d:getcontenttype />
-                <d:resourcetype />
-                <oc:fileid />
-                <oc:permissions />
-                <oc:size />
-                <d:getcontentlength />
-                <nc:has-preview />
-                <nc:mount-type />
-                <nc:is-encrypted />
-                <ocs:share-permissions />
-                <oc:tags />
-                <oc:favorite />
-                <oc:comments-unread />
-                <oc:owner-id />
-                <oc:owner-display-name />
-                <oc:share-types />
-              </d:prop>
-            </d:propfind>`,
-      method: "PROPFIND",
-    };
-    const url = `${this.webDAVUrl}${folderName}`;
-    const response: Response = await this.getHttpResponse(url, requestInit, [207], { description: "Folder get contents" });
-    const folderContents: any[] = [];
- 
-    const schema: Joi.ObjectSchema = Joi.object({
-      _href: Joi.string().required(),
-      getlastmodified: Joi.string().required(),
-      fileid: Joi.number().integer().required(),
-      getcontenttype: Joi.string(),
-      getcontentlength: Joi.number().integer(),
-    });
- 
-    const properties: any[] = await this.getPropertiesFromWebDAVMultistatusResponse(response, "");
- 
-    // validate the properties
-    const { error, value } = schema.validate(properties);
-    Eif (error) {
-      throw new ClientError(`Error get folder contents - folder name "${folderName}" error ${error.message};`, "INVALID");
-    }
- 
-    for (const prop of properties) {
-      // eslint-disable-next-line @typescript-eslint/no-unsafe-call, no-underscore-dangle, @typescript-eslint/restrict-plus-operands
-      let fileName = decodeURI(prop._href.substr(prop._href.indexOf(Client.webDavUrlPath) + 18));
-      if (fileName.endsWith("/")) {
-        fileName = fileName.slice(0, -1);
-      }
-      // eslint-disable-next-line no-underscore-dangle
-      if ((url + "/").endsWith(decodeURI(prop._href))) {
-        continue;
-      }
-      const folderContentsEntry: any = {};
-      folderContentsEntry.lastmod = prop.getlastmodified;
-      folderContentsEntry.fileid = prop.fileid;
-      folderContentsEntry.basename = fileName.split("/").reverse()[0];
-      folderContentsEntry.filename = fileName;
-      if (prop.getcontenttype) {
-        folderContentsEntry.mime = prop.getcontenttype;
-        folderContentsEntry.size = prop.getcontentlength;
-        folderContentsEntry.type = "file";
-      } else {
-        folderContentsEntry.type = "directory";
-      }
-      // if (folderContentsEntry.basename !== "") {
-      folderContents.push(folderContentsEntry);
-      // }
-    }
- 
-    // log.debug("folderContentsEntry ", JSON.stringify(folderContents, null, 4));
-    // eslint-disable-next-line @typescript-eslint/no-unsafe-return
-    return folderContents;
-  }
- 
-  /**
-   * creates a folder and all parent folders in the path if they do not exist
-   * @param folderName name of the folder /folder/subfolder/subfolder
-   * @returns a folder object
-   */
-  public async createFolder(folderName: string): Promise<Folder> {
-    folderName = this.sanitizeFolderName(folderName);
-    log.debug("createFolder: folderName=", folderName);
- 
-    const parts1: string[] = folderName.split("/");
-    for (const p of parts1) {
-      if (p === "." || p === "..") {
-        throw new ClientError(`Error creating folder, folder name "${folderName}" invalid`, "ERR_CREATE_FOLDER_INVALID_FOLDER_NAME");
-      }
-    }
- 
-    let folder: Folder | null;
- 
-    folder = await this.getFolder(folderName);
-    if (folder) {
-      log.debug("createFolder: folder already available ", folder.name);
-      return folder;
-    } else {
-      // try to do a simple create with the complete path
-      try {
-        log.debug("createFolder: folder = ", folderName);
-        await this.createFolderInternal(folderName);
-      } catch (e) {
-        // create all folders in the path
-        const parts: string[] = folderName.split("/");
-        parts.shift();
-        let folderPath: string = "";
-        log.debug("createFolder: parts = ", parts);
- 
-        for (const part of parts) {
-          log.debug("createFolder: part = ", part);
-          folderPath += "/" + part;
-          folder = await this.getFolder(folderPath);
- 
-          if (folder === null) {
-            log.debug("createFolder: folder not available");
-            // folder not  available
- 
-            log.debug("createFolder: folder = ", folderPath);
-            await this.createFolderInternal(folderPath);
-          } else {
-            log.debug("createFolder: folder already available ", folderPath);
-          }
-        }
-      }
-    }
- 
-    folder = await this.getFolder(folderName);
-    if (folder) {
-      log.debug("createFolder: new folder ", folder.name);
-      return folder;
-    } else {
-      throw new ClientError(
-        `Error creating folder, folder name "${folderName}"
-            `,
-        "ERR_CREATE_FOLDER_FAILED"
-      );
-    }
-  }
- 
-  /**
-   * deletes a file
-   * @param fileName name of folder "/f1/f2/f3/x.txt"
-   */
-  public async deleteFile(fileName: string): Promise<void> {
-    const url: string = this.webDAVUrl + fileName;
-    log.debug("deleteFile ", url);
- 
-    const requestInit: RequestInit = {
-      method: "DELETE",
-    };
-    try {
-      await this.getHttpResponse(url, requestInit, [204], { description: "File delete" });
-    } catch (err) {
-      log.debug("Error in deleteFile ", err.message, requestInit.method, url);
-      throw err;
-    }
-  }
- 
-  /**
-   * deletes a folder
-   * @param folderName name of folder "/f1/f2/f3"
-   */
-  public async deleteFolder(folderName: string): Promise<void> {
-    folderName = this.sanitizeFolderName(folderName);
-    log.debug("deleteFolder:");
- 
-    const folder: Folder | null = await this.getFolder(folderName);
- 
-    if (folder) {
-      await this.deleteFile(folderName);
-    }
-  }
- 
-  /**
-   * get the root folder object
-   * @returns {Promise<Folder>} the root folder
-   */
-  public getRootFolder(): Folder {
-    return new Folder(this, "/", "", "");
-  }
- 
-  /**
-   * returns an array of file system objects that have all given tags assigned (AND)
-   * @param {Tag[]} tags array of tags
-   * @async
-   * @returns {Promise<FileSystemElement[]>} returns an array of file system objects
-   */
-  public async getFileSystemElementByTags(tags: Tag[]): Promise<FileSystemElement[]> {
-    log.debug("getFileSystemElementByTags ", tags.join(", "));
-    let filterRule: string = "";
- 
-    for (const tag of tags) {
-      filterRule += `<oc:systemtag>${tag.id}</oc:systemtag>`;
-    }
-    const urlSuffix = `/remote.php/dav/files/`;
-    const url = `${this.nextcloudOrigin}${urlSuffix}${this.userId}`;
-    const body = `<?xml version="1.0"?>
-        <oc:filter-files  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:getcontenttype />
-              <oc:fileid />
-           </d:prop>
-           <oc:filter-rules>
-                ${filterRule}
-           </oc:filter-rules>
-        </oc:filter-files>`;
-    const requestInit: RequestInit = {
-      body,
-      // headers: new Headers({ Depth: "0" }),
-      method: "REPORT",
-    };
-    let response: Response;
-    try {
-      response = await this.getHttpResponse(url, requestInit, [207], { description: "Get FileSystemElements by tags" });
-    } catch (err) {
-      log.debug("Error in stat ", err.message, requestInit.method, url);
-      throw err;
-    }
-    const result: FileSystemElement[] = [];
- 
-    let properties: any[] = [];
-    try {
-      properties = await this.getPropertiesFromWebDAVMultistatusResponse(response, "");
-    } catch (e) {
-      return result;
-    }
- 
-    for (const prop of properties) {
-      let fse: FileSystemElement | null = null;
-      // eslint-disable-next-line no-underscore-dangle
-      let name: string = prop._href;
- 
-      // remove the first two elements from the path
-      name = name.replace(urlSuffix, "");
-      const a: string[] = name.split("/");
-      a.shift();
-      name = "/" + a.join("/");
-      // console.log(name);
-      if (prop.getcontenttype) {
-        fse = await this.getFile(name);
-      } else {
-        fse = await this.getFolder(name);
-      }
- 
-      result.push(fse!);
-    }
-    return result;
-  }
- 
-  /**
-   * get a folder object from a path string
-   * @param {string} folderName Name of the folder like "/company/branches/germany"
-   * @returns {Promise<Folder | null>} null if the folder does not exist or an folder object
-   */
-  public async getFolder(folderName: string): Promise<Folder | null> {
-    folderName = this.sanitizeFolderName(folderName);
-    log.debug("getFolder", folderName);
- 
-    // return root folder
-    if (folderName === "/" || folderName === "") {
-      return this.getRootFolder();
-    }
- 
-    try {
-      const stat: IStat = await this.stat(folderName);
-      log.debug(": SUCCESS!!");
-      if (stat.type !== "file") {
-        return new Folder(this, stat.filename.replace(/\\/g, "/"), stat.basename, stat.lastmod, stat.fileid);
-      } else {
-        log.debug("getFolder: found object is file not a folder");
-        return null;
-      }
-    } catch (e) {
-      log.debug("getFolder: exception occurred calling stat ", e.message);
-      return null;
-    }
-  }
- 
-  /**
-   * get a array of folders from a folder path string
-   * @param folderName Name of the folder like "/company/branches/germany"
-   * @returns array of folder objects
-   */
-  public async getSubFolders(folderName: string): Promise<Folder[]> {
-    log.debug("getSubFolders: folder ", folderName);
-    const folders: Folder[] = [];
-    folderName = this.sanitizeFolderName(folderName);
- 
-    const folderElements: any[] = await this.contents(folderName, true);
- 
-    for (const folderElement of folderElements) {
-      log.debug("getSubFolders: adding subfolders ", folderElement.filename);
-      // eslint-disable-next-line @typescript-eslint/no-unsafe-call
-      folders.push(new Folder(this, folderElement.filename.replace(/\\/g, "/"), folderElement.basename, folderElement.lastmod, folderElement.fileid));
-    }
- 
-    return folders;
-  }
- 
-  /**
-   * get files of a folder
-   * @param {string} folderName Name of the folder like "/company/branches/germany"
-   * @param {FolderGetFilesOptions} options options for filtering and paging
-   * @returns array of file objects
-   */
-  public async getFiles(folderName: string, options?: FolderGetFilesOptions): Promise<File[]> {
-    log.debug("getFiles: folder ", folderName);
-    const files: File[] = [];
-    folderName = this.sanitizeFolderName(folderName);
- 
-    const fileElements: any[] = await this.contents(folderName, false);
- 
-    for (const folderElement of fileElements) {
-      log.debug("getFiles: adding file ", folderElement.filename);
-      // log.debug("getFiles: adding file ", folderElement);
-      // eslint-disable-next-line @typescript-eslint/no-unsafe-call
-      let file: File | null = new File(this, folderElement.filename.replace(/\\/g, "/"), folderElement.basename, folderElement.lastmod, folderElement.size, folderElement.mime, folderElement.fileid);
- 
-      if (options && options.filterFile) {
-        file = options.filterFile(file);
-      }
-      if (file) {
-        files.push(file);
-      }
-    }
- 
-    return files;
-  }
- 
-  /**
-   * create a new file of overwrites an existing file
-   * @param fileName the file name /folder1/folder2/filename.txt
-   * @param data the buffer object
-   */
-  public async createFile(fileName: string, data: Buffer | NodeJS.ReadableStream): Promise<File> {
-    if (fileName.startsWith("./")) {
-      fileName = fileName.replace("./", "/");
-    }
- 
-    const baseName: string = path.basename(fileName);
-    const folderName: string = path.dirname(fileName);
- 
-    log.debug(`createFile folder name ${folderName} base name ${baseName}`);
- 
-    // ensure that we have a folder
-    await this.createFolder(folderName);
-    await this.putFileContents(fileName, data);
- 
-    const file: File | null = await this.getFile(fileName);
- 
-    if (!file) {
-      throw new ClientError(`Error creating file, file name "${fileName}"`, "ERR_CREATE_FILE_FAILED");
-    }
-    return file;
-  }
- 
-  /**
-   * returns a nextcloud file object
-   * @param fileName the full file name /folder1/folder2/file.pdf
-   */
-  public async getFile(fileName: string): Promise<File | null> {
-    log.debug("getFile fileName = ", fileName);
- 
-    try {
-      const stat: IStat = await this.stat(fileName);
-      log.debug(": SUCCESS!!");
-      Eif (stat.type === "file") {
-        return new File(this, stat.filename.replace(/\\/g, "/"), stat.basename, stat.lastmod, stat.size!, stat.mime || "", stat.fileid || -1);
-      } else {
-        log.debug("getFile: found object is a folder not a file");
-        return null;
-      }
-    } catch (e) {
-      log.debug("getFile: exception occurred calling stat ", e.message);
-      return null;
-    }
-  }
- 
-  /**
-   * renames the file or moves it to an other location
-   * @param sourceFileName source file name
-   * @param targetFileName target file name
-   */
-  public async moveFile(sourceFileName: string, targetFileName: string): Promise<File> {
-    const url: string = this.webDAVUrl + sourceFileName;
-    const destinationUrl: string = this.webDAVUrl + targetFileName;
- 
-    log.debug("moveFile from '" + url + "' to '" + destinationUrl + "'");
- 
-    const requestInit: RequestInit = {
-      // eslint-disable-next-line @typescript-eslint/naming-convention
-      headers: new Headers({ Destination: destinationUrl }),
-      method: "MOVE",
-    };
-    try {
-      await this.getHttpResponse(url, requestInit, [201], { description: "File move" });
-    } catch (err) {
-      log.debug(`Error in move file ${err.message as string} ${requestInit.method || ""} source: ${url} destination: ${destinationUrl}`);
-      throw new ClientError(`Error: moving file failed: source=" ${sourceFileName} target= ${targetFileName} - ${err.message as string}`, "ERR_FILE_MOVE_FAILED");
-    }
- 
-    const targetFile: File | null = await this.getFile(targetFileName);
-    if (!targetFile) {
-      throw new ClientError("Error: moving file failed: source=" + sourceFileName + " target=" + targetFileName, "ERR_FILE_MOVE_FAILED");
-    }
- 
-    return targetFile;
-  }
- 
-  /**
-   * renames the folder or moves it to an other location
-   * @param sourceFolderName source folder name
-   * @param tarName target folder name
-   */
-  public async moveFolder(sourceFolderName: string, tarName: string): Promise<Folder> {
-    const url: string = this.webDAVUrl + sourceFolderName;
-    const destinationUrl: string = this.webDAVUrl + tarName;
- 
-    log.debug(`moveFolder from '${url}' to '${destinationUrl}'`);
- 
-    const requestInit: RequestInit = {
-      // eslint-disable-next-line @typescript-eslint/naming-convention
-      headers: new Headers({ Destination: destinationUrl }),
-      method: "MOVE",
-    };
-    try {
-      await this.getHttpResponse(url, requestInit, [201], { description: "Folder move" });
-    } catch (err) {
-      log.debug(`Error in move folder ${err.message as string} ${requestInit.method || ""} source: ${url} destination: ${destinationUrl}`);
-      throw new ClientError(`Error: moving folder failed: source=${sourceFolderName} target=${tarName} - ${err.message as string}`, "ERR_FOLDER_MOVE_FAILED");
-    }
- 
-    const tar: Folder | null = await this.getFolder(tarName);
-    if (!tar) {
-      throw new ClientError("Error: moving folder failed: source=" + sourceFolderName + " target=" + tarName, "ERR_FOLDER_MOVE_FAILED");
-    }
- 
-    return tar;
-  }
- 
-  /**
-   * returns the content of a file
-   * @param fileName name of the file /d1/file1.txt
-   * @returns Buffer with file content
-   */
-  public async getContent(fileName: string): Promise<Buffer> {
-    const url = this.webDAVUrl + fileName;
-    log.debug("getContent GET ", url);
-    const requestInit: RequestInit = {
-      method: "GET",
-    };
-    let response: Response;
-    try {
-      response = await this.getHttpResponse(url, requestInit, [200], { description: "File get content" });
-    } catch (err) {
-      log.debug(`Error getContent ${url} - error ${err.message as string}`);
-      throw err;
-    }
- 
-    return Buffer.from(await response.buffer());
-  }
- 
-  /**
-   * returns the content of a file
-   * @param fileName name of the file /d1/file1.txt
-   * @returns Buffer with file content
-   */
-  public async pipeContentStream(fileName: string, destination: NodeJS.WritableStream): Promise<void> {
-    const url = this.webDAVUrl + fileName;
-    log.debug("getContent GET ", url);
-    const requestInit: RequestInit = {
-      method: "GET",
-    };
-    let response: Response;
-    try {
-      response = await this.getHttpResponse(url, requestInit, [200], { description: "File pipe content stream" });
-    } catch (err) {
-      log.debug(`Error getContent ${url} - error ${err.message as string}`);
-      throw err;
-    }
-    response.body.pipe(destination);
-  }
- 
-  /**
-   * returns the link to a file for downloading
-   * @param fileName name of the file /folder1/folder1.txt
-   * @returns url
-   */
-  public getLink(fileName: string): string {
-    log.debug("getLink of ", fileName);
-    return this.webDAVUrl + fileName;
-  }
- 
-  /**
-   * returns the url to the file in the nextcloud UI
-   * @param fileId the id of the file
-   */
-  public getUILink(fileId: number): string {
-    log.debug("getUILink of ", fileId);
-    return `${this.nextcloudOrigin}/apps/files/?fileid=${fileId}`;
-  }
- 
-  /**
-   * adds a tag to a file or folder
-   * if the tag does not exist, it is automatically created
-   * if the tag is created, the user must have damin privileges
-   * @param fileId the id of the file
-   * @param tagName the name of the tag
-   * @returns nothing
-   * @throws Error
-   */
-  public async addTagToFile(fileId: number, tagName: string): Promise<void> {
-    log.debug(`addTagToFile file: "${fileId}" tag: "${tagName}"`);
-    const tag: Tag = await this.createTag(tagName);
- 
-    if (!tag.canAssign) {
-      throw new ClientError(`Error: No permission to assign tag "${tagName}" to file. Tag is not assignable`, "ERR_TAG_NOT_ASSIGNABLE");
-    }
- 
-    const addTagBody: any = {
-      canAssign: tag.canAssign,
-      id: tag.id,
-      name: tag.name,
-      userAssignable: tag.assignable,
-      userVisible: tag.visible,
-    };
- 
-    const requestInit: RequestInit = {
-      body: JSON.stringify(addTagBody, null, 4),
-      // eslint-disable-next-line @typescript-eslint/naming-convention
-      headers: new Headers({ "Content-Type": "application/json" }),
-      method: "PUT",
-    };
- 
-    await this.getHttpResponse(`${this.nextcloudOrigin}/remote.php/dav/systemtags-relations/files/${fileId}/${tag.id}`, requestInit, [201, 409], { description: "File add tag" }); // created or conflict
-  }
- 
-  // ***************************************************************************************
-  // activity
-  // ***************************************************************************************
-  /*
-    @todo to be refactored to eventing
- 
-    public async getActivities(): Promise<string[]> {
-        const result: string[] = [];
-        const requestInit: RequestInit = {
-            headers: new Headers({ "ocs-apirequest": "true" }),
-            method: "GET",
-        };
- 
-        const response: Response = await this.getHttpResponse(
-            this.nextcloudOrigin + "/ocs/v2.php/apps/activity/api/v2/activity/files?format=json&previews=false&since=97533",
-            requestInit,
-            [200],
-            { description: "Activities get" });
- 
-        const responseObject: any = await response.json();
-        // @todo
- 
-        for (const res of responseObject.ocs.data) {
-            log.debug(JSON.stringify({
-                acivityId: res.activity_id,
-                objects: res.objects,
-                type: res.type,
-            }, null, 4));
-        }
- 
-        // log.debug("getActivities: responseObject ", JSON.stringify(responseObject, null, 4));
- 
-        return result;
-    }
-*/
-  // ***************************************************************************************
-  // comments
-  // ***************************************************************************************
- 
-  /**
-   * adds a comment to a file
-   * @param fileId the id of the file
-   * @param comment the comment to be added to the file
-   */
-  public async addCommentToFile(fileId: number, comment: string): Promise<void> {
-    log.debug(`addCommentToFile file:"${fileId}" comment:"${comment}"`);
- 
-    const addCommentBody: any = {
-      actorType: "users",
-      message: comment,
-      objectType: "files",
-      verb: "comment",
-    };
- 
-    const requestInit: RequestInit = {
-      body: JSON.stringify(addCommentBody, null, 4),
-      // eslint-disable-next-line @typescript-eslint/naming-convention
-      headers: new Headers({ "Content-Type": "application/json" }),
-      method: "POST",
-    };
- 
-    await this.getHttpResponse(`${this.nextcloudOrigin}/remote.php/dav/comments/files/${fileId}`, requestInit, [201], { description: "File add comment" }); // created
-  }
- 
-  /**
-   * returns comments of a file / folder
-   * @param fileId the id of the file / folder
-   * @param top number of comments to return
-   * @param skip the offset
-   * @returns array of comment strings
-   * @throws Exception
-   */
-  public async getFileComments(fileId: number, top?: number, skip?: number): Promise<string[]> {
-    log.debug("getFileComments fileId: ", fileId);
-    if (!top) {
-      top = 30;
-    }
- 
-    if (!skip) {
-      skip = 0;
-    }
- 
-    const requestInit: RequestInit = {
-      body: `<?xml version="1.0" encoding="utf-8" ?>
-                    <oc:filter-comments xmlns:D="DAV:" xmlns:oc="http://owncloud.org/ns">
-                        <oc:limit>${top}</oc:limit>
-                        <oc:offset>${skip}</oc:offset>
-                    </oc:filter-comments>`,
-      method: "REPORT",
-    };
- 
-    const response: Response = await this.getHttpResponse(`${this.nextcloudOrigin}/remote.php/dav/comments/files/${fileId}`, requestInit, [207], { description: "File get comments" });
- 
-    const properties: any[] = await this.getPropertiesFromWebDAVMultistatusResponse(response, "");
-    const comments: string[] = [];
-    for (const prop of properties) {
-      comments.push(prop.message);
-    }
- 
-    return comments;
-  }
- 
-  /**
-   * returns system information about the nextcloud server and the nextcloud client
-   */
-  public async getSystemInfo(): Promise<ISystemInfo> {
-    const requestInit: RequestInit = {
-      headers: this.getOcsHeaders(),
-      method: "GET",
-    };
- 
-    const response: Response = await this.getHttpResponse(this.nextcloudOrigin + "/ocs/v2.php/apps/serverinfo/api/v1/info", requestInit, [200], { description: "SystemInfo get" });
- 
-    const rawResult: any = await response.json();
-    // validate the raw result
-    let system = {};
-    let storage = {};
-    let shares = {};
-    let server = {};
-    let activeUsers = {};
- 
-    if (rawResult && rawResult.ocs && rawResult.ocs.data) {
-      if (rawResult.ocs.data.nextcloud) {
-        if (rawResult.ocs.data.nextcloud.system) {
-          system = rawResult.ocs.data.nextcloud.system;
-        } else {
-          throw new ClientError("Fatal Error: nextcloud data.nextcloud.system missing", "ERR_SYSTEM_INFO_MISSING_DATA");
-        }
- 
-        if (rawResult.ocs.data.nextcloud.storage) {
-          storage = rawResult.ocs.data.nextcloud.storage;
-        } else {
-          throw new ClientError("Fatal Error: nextcloud data.nextcloud.storage missing", "ERR_SYSTEM_INFO_MISSING_DATA");
-        }
- 
-        if (rawResult.ocs.data.nextcloud.shares) {
-          shares = rawResult.ocs.data.nextcloud.shares;
-        } else {
-          throw new ClientError("Fatal Error: nextcloud data.nextcloud.shares missing", "ERR_SYSTEM_INFO_MISSING_DATA");
-        }
-      } else {
-        throw new ClientError("Fatal Error: nextcloud data.nextcloud missing", "ERR_SYSTEM_INFO_MISSING_DATA");
-      }
- 
-      if (rawResult.ocs.data.server) {
-        server = rawResult.ocs.data.server;
-      } else {
-        throw new ClientError("Fatal Error: nextcloud data.server missing", "ERR_SYSTEM_INFO_MISSING_DATA");
-      }
- 
-      if (rawResult.ocs.data.activeUsers) {
-        activeUsers = rawResult.ocs.data.activeUsers;
-      } else {
-        throw new ClientError("Fatal Error: nextcloud data.activeUsers missing", "ERR_SYSTEM_INFO_MISSING_DATA");
-      }
-    } else {
-      throw new ClientError("Fatal Error: nextcloud system data missing", "ERR_SYSTEM_INFO_MISSING_DATA");
-    }
- 
-    const result: ISystemInfo = {
-      activeUsers,
-      nextcloud: {
-        shares,
-        storage,
-        system,
-      },
-      nextcloudClient: {
-        // eslint-disable-next-line @typescript-eslint/no-var-requires
-        version: require("../package.json").version,
-      },
-      server,
-    };
-    return result;
-  }
- 
-  public async getSystemBasicData(): Promise<ISysBasicData> {
-    const requestInit: RequestInit = {
-      headers: this.getOcsHeaders(),
-      method: "GET",
-    };
- 
-    const response: Response = await this.getHttpResponse(this.nextcloudOrigin + "/ocs/v2.php/apps/serverinfo/api/v1/basicdata", requestInit, [200], { description: "System Basic Data get" });
- 
-    const rawResult: any = await response.json();
-    // console.log("Basic Data\n", JSON.stringify(rawResult));
-    let result: ISysBasicData;
- 
-    if (rawResult && rawResult.ocs && rawResult.ocs.data && rawResult.ocs.data.servertime && rawResult.ocs.data.uptime && rawResult.ocs.data.timeservers) {
-      result = {
-        // eslint-disable-next-line @typescript-eslint/no-unsafe-call
-        serverTimeString: rawResult.ocs.data.servertime.replace("\n", ""),
-        // eslint-disable-next-line @typescript-eslint/no-unsafe-call
-        uptimeString: rawResult.ocs.data.uptime.replace("\n", ""),
-        // eslint-disable-next-line @typescript-eslint/no-unsafe-call
-        timeServersString: rawResult.ocs.data.timeservers.trim(),
-      };
-    } else {
-      throw new ClientError("Fatal Error: nextcloud basic data missing", "ERR_SYSTEM_INFO_MISSING_DATA");
-    }
- 
-    return result;
-  }
- 
-  // ***************************************************************************************
-  // user management
-  // ***************************************************************************************
- 
-  // ***************************************************************************************
-  // user group
-  // spec: https://docs.nextcloud.com/server/latest/admin_manual/configuration_user/instruction_set_for_groups.html
-  // ***************************************************************************************
- 
-  /**
-   * returns a list of user groups
-   * @param search string
-   * @param limit number
-   * @param offset number
-   * @returns list of user groups
-   * @throws QueryLimitError
-   * @throws QueryOffsetError
-   */
-  public async getUserGroups(search?: string, limit?: number, offset?: number): Promise<UserGroup[]> {
-    log.debug("getUserGroups");
- 
-    const userGroupIds: string[] = await this.getUserGroupIds(search, limit, offset);
-    const userGroups: UserGroup[] = [];
-    for (const userGroupId of userGroupIds) {
-      userGroups.push(new UserGroup(this, userGroupId));
-    }
-    return userGroups;
-  }
- 
-  /**
-   * returns a list of user groups
-   * @param search string
-   * @param limit number
-   * @param offset number
-   * @returns list of user groups
-   * @throws QueryLimitError
-   * @throws QueryOffsetError
-   */
-  public async getUserGroupIds(search?: string, limit?: number, offset?: number): Promise<string[]> {
-    log.debug("getUserGroupIds");
-    const requestInit: RequestInit = {
-      headers: this.getOcsHeaders(),
-      method: "GET",
-    };
- 
-    let url = this.getOcsUrl(`/groups`);
-    const queryParameter: string[] = [];
-    if (search) {
-      queryParameter.push(`search=${search}`);
-    }
-    if (limit) {
-      if (limit < 1) {
-        throw new QueryLimitError("The limit must be larger than 0");
-      }
-      queryParameter.push(`limit=${limit}`);
-    }
-    if (offset) {
-      if (offset < 1) {
-        throw new QueryOffsetError("The offset must be larger than 0");
-      }
-      queryParameter.push(`offset=${offset}`);
-    }
-    if (queryParameter.join("&").length > 1) {
-      url += "?" + queryParameter.join("&");
-    }
-    log.debug("url ", url);
- 
-    const response: Response = await this.getHttpResponse(url, requestInit, [200], { description: "User Groups get" });
-    const rawResult: any = await response.json();
-    /*
-        {
-          ocs: {
-            meta: {
-              status: 'ok',
-              statuscode: 100,
-              message: 'OK',
-              totalitems: '',
-              itemsperpage: ''
-            },
-            data: { groups: ["g1", "g2"] }
-          }
-        }
-        */
-    const userGroups: string[] = [];
- 
-    if (rawResult.ocs && rawResult.ocs.data && rawResult.ocs.data.groups) {
-      log.debug("groups", rawResult.ocs.data.groups);
-      // eslint-disable-next-line @typescript-eslint/no-unsafe-call
-      rawResult.ocs.data.groups.forEach((value: string) => {
-        // userGroups.push(new UserGroup(this, value));
-        userGroups.push(value);
-      });
-    }
-    return userGroups;
-  }
- 
-  /**
-   * get user group
-   * @param id string
-   * @returns Promise<UserGroup|null>
-   */
-  public async getUserGroup(id: string): Promise<UserGroup | null> {
-    const userGroups: UserGroup[] = await this.getUserGroups(id);
-    if (userGroups[0]) {
-      return userGroups[0];
-    }
-    return null;
-  }
- 
-  /**
-   * returns a list of user ids that are members of the user group
-   * @param id string
-   * @returns list of member user ids
-   * @throws [UserGroupDoesNotExistError}
-   */
-  public async getUserGroupMembers(id: string): Promise<string[]> {
-    log.debug("getUserGroupMembers");
-    const requestInit: RequestInit = {
-      headers: this.getOcsHeaders(),
-      method: "GET",
-    };
- 
-    const url = this.getOcsUrl(`/groups/${id}`);
-    log.debug("url ", url);
- 
-    const response: Response = await this.getHttpResponse(url, requestInit, [200], { description: "User group get members" });
-    const rawResult: any = await response.json();
-    const userIds: string[] = [];
- 
-    if (this.getOcsMetaStatus(rawResult).code === 404) {
-      throw new UserGroupDoesNotExistError(`User Group ${id} does not exist`);
-    }
- 
-    if (rawResult.ocs && rawResult.ocs.data && rawResult.ocs.data.users) {
-      log.debug("members", rawResult.ocs.data.users);
-      // eslint-disable-next-line @typescript-eslint/no-unsafe-call
-      rawResult.ocs.data.users.forEach((value: string) => {
-        userIds.push(value);
-      });
-    }
- 
-    return userIds;
-  }
- 
-  /**
-   * returns a list of user ids that are subadmins of the user group
-   * @param id string
-   * @returns list of subadmin user ids
-   * @throws [UserGroupDoesNotExistError}
-   */
-  public async getUserGroupSubadmins(id: string): Promise<string[]> {
-    log.debug("getUserGroupsubadmins");
-    const requestInit: RequestInit = {
-      headers: this.getOcsHeaders(),
-      method: "GET",
-    };
- 
-    const url = this.getOcsUrl(`/groups/${id}/subadmins`);
-    log.debug("url ", url);
- 
-    const response: Response = await this.getHttpResponse(url, requestInit, [200], { description: "User group get subadmins" });
-    const rawResult: any = await response.json();
-    const userIds: string[] = [];
- 
-    if (this.getOcsMetaStatus(rawResult).code === 101) {
-      throw new UserGroupDoesNotExistError(`User Group ${id} does not exist`);
-    }
- 
-    if (rawResult.ocs && rawResult.ocs.data) {
-      log.debug("subadmins", rawResult.ocs.data);
-      // eslint-disable-next-line @typescript-eslint/no-unsafe-call
-      rawResult.ocs.data.forEach((value: string) => {
-        userIds.push(value);
-      });
-    }
- 
-    return userIds;
-  }
- 
-  /**
-   * create a new user group
-   * @async
-   * @param {string} id user group id
-   * @returns {Promise<UserGroup>}
-   * @throws {UserGroupAlreadyExistsError}
-   */
-  public async createUserGroup(id: string): Promise<UserGroup> {
-    log.debug("createUserGroup id=", id);
-    const requestInit: RequestInit = {
-      body: JSON.stringify({ groupid: id }),
-      headers: this.getOcsHeaders(),
-      method: "POST",
-    };
-    log.debug("request body: ", requestInit.body);
-    const response: Response = await this.getHttpResponse(this.getOcsUrl(`/groups`), requestInit, [200], { description: "UserGroup create" });
-    const rawResult: any = await response.json();
- 
-    if (this.getOcsMetaStatus(rawResult).code === 102) {
-      throw new UserGroupAlreadyExistsError(`User Group ${id} already exists`);
-    }
- 
-    if (this.getOcsMetaStatus(rawResult).code === 100) {
-      return new UserGroup(this, id);
-    }
-    throw new OperationFailedError(`User group ${id} could not be created: ${this.getOcsMetaStatus(rawResult).message}`);
-  }
- 
-  /**
-   * deletes an existing user group
-   * @param id string
-   * @returns {Promise<void>}
-   * @throws {UserGroupDowsNotExistError}
-   * @throws {UserGroupDeletionFailedError}
-   */
-  public async deleteUserGroup(id: string): Promise<void> {
-    log.debug("deleteUserGroup id=", id);
-    const requestInit: RequestInit = {
-      headers: this.getOcsHeaders(),
-      method: "DELETE",
-    };
-    log.debug("request body: ", requestInit.body);
-    const response: Response = await this.getHttpResponse(this.getOcsUrl(`/groups/${id}`), requestInit, [200], { description: "UserGroup delete" });
-    const rawResult: any = await response.json();
- 
-    if (this.getOcsMetaStatus(rawResult).code === 101) {
-      throw new UserGroupDoesNotExistError(`User Group ${id} does not exists`);
-    }
- 
-    if (this.getOcsMetaStatus(rawResult).code === 102) {
-      throw new UserGroupDeletionFailedError(`User Group ${id} could not be deleted`);
-    }
-  }
- 
-  // ***************************************************************************************
-  // user
-  // spec: https://docs.nextcloud.com/server/latest/admin_manual/configuration_user/instruction_set_for_users.html
-  // ***************************************************************************************
- 
-  /**
-   * returns a list of users
-   * https://docs.nextcloud.com/server/latest/admin_manual/configuration_user/instruction_set_for_users.html#search-get-users
-   * @param search string
-   * @param limit number
-   * @param offset number
-   */
-  public async getUsers(search?: string, limit?: number, offset?: number): Promise<User[]> {
-    log.debug("getUsers");
-    const requestInit: RequestInit = {
-      headers: this.getOcsHeaders(),
-      method: "GET",
-    };
- 
-    let url = this.getOcsUrl(`/users`);
-    const queryParameter: string[] = [];
-    if (search) {
-      queryParameter.push(`search=${search}`);
-    }
-    if (limit) {
-      if (limit < 1) {
-        throw new QueryLimitError("The limit must be larger than 0");
-      }
-      queryParameter.push(`limit=${limit}`);
-    }
-    if (offset) {
-      if (offset < 1) {
-        throw new QueryOffsetError("The offset must be larger than 0");
-      }
-      queryParameter.push(`offset=${offset}`);
-    }
-    if (queryParameter.join("&").length > 1) {
-      url += "?" + queryParameter.join("&");
-    }
-    log.debug("url ", url);
- 
-    const response: Response = await this.getHttpResponse(url, requestInit, [200], { description: "Users get" });
-    const rawResult: any = await response.json();
-    /*
-        {
-          ocs: {
-            meta: {
-              status: 'ok',
-              statuscode: 100,
-              message: 'OK',
-              totalitems: '',
-              itemsperpage: ''
-            },
-            data: { users: ["u1", "u2"] }
-          }
-        }
-        */
-    const users: User[] = [];
- 
-    if (rawResult.ocs && rawResult.ocs.data && rawResult.ocs.data.users) {
-      log.debug("user ids", rawResult.ocs.data.users);
-      // eslint-disable-next-line @typescript-eslint/no-unsafe-call
-      rawResult.ocs.data.users.forEach((value: string) => {
-        users.push(new User(this, value));
-      });
-    }
- 
-    return users;
-  }
- 
-  /**
-   * returns user data
-   * @param id string the user id
-   * @returns Promise<IUserOptions> user data
-   * @throws {UserNotFoundError}
-   */
-  public async getUserData(id: string): Promise<IUserOptions> {
-    log.debug("getUserData");
-    const requestInit: RequestInit = {
-      headers: this.getOcsHeaders(),
-      method: "GET",
-    };
- 
-    const url = this.getOcsUrl(`/users/${id}`);
-    log.debug("url ", url);
- 
-    const response: Response = await this.getHttpResponse(url, requestInit, [200], { description: `User ${id} get` });
-    const rawResult: any = await response.json();
- 
-    if (this.getOcsMetaStatus(rawResult).code === 404) {
-      throw new UserNotFoundError(`User '${id}' not found`);
-    }
-    /*
-        {
-          ocs: {
-            meta: {
-              status: 'ok',
-              statuscode: 100,
-              message: 'OK',
-              totalitems: '',
-              itemsperpage: ''
-            },
-            data: { ... }
-          }
-        }
-        */
- 
-    log.debug("user data", rawResult.ocs.data);
-    const userData: IUserOptions = {
-      enabled: rawResult.ocs.data.enabled,
-      lastLogin: rawResult.ocs.data.lastLogin === 0 ? undefined : new Date(rawResult.ocs.data.lastLogin),
-      subadminGroups: rawResult.ocs.data.subadmin,
-      memberGroups: rawResult.ocs.data.groups,
-      quota: {
-        free: 0,
-        used: 0,
-        total: 0,
-        relative: 0,
-        quota: 0,
-      },
-      email: rawResult.ocs.data.email,
-      displayName: rawResult.ocs.data.displayname,
-      phone: rawResult.ocs.data.phone,
-      address: rawResult.ocs.data.address,
-      website: rawResult.ocs.data.website,
-      twitter: rawResult.ocs.data.twitter,
-      language: rawResult.ocs.data.language,
-      locale: rawResult.ocs.data.locale,
-    };
-    if (rawResult.ocs.data.quota.quota === "none") {
-      userData.quota = { quota: 0, relative: 0, used: 0 };
-    } else {
-      if (!rawResult.ocs.data.quota.relative) {
-        rawResult.ocs.data.quota.relative = 0;
-      }
-      userData.quota = { quota: rawResult.ocs.data.quota.quota, relative: rawResult.ocs.data.quota.relative, used: rawResult.ocs.data.quota.used };
-      if (rawResult.ocs.data.quota.free) {
-        userData.quota.free = rawResult.ocs.data.quota.free;
-      }
-      if (rawResult.ocs.data.quota.total) {
-        userData.quota.total = rawResult.ocs.data.quota.total;
-      }
-    }
-    return userData;
-  }
- 
-  /**
-   * enables the user
-   * @param id string the user id
-   * @returns {Promise<void>}
-   * @throws {UserNotFoundError}
-   */
-  public async enableUser(id: string): Promise<void> {
-    log.debug("enableUser");
-    const requestInit: RequestInit = {
-      headers: this.getOcsHeaders(),
-      method: "PUT",
-    };
- 
-    const url = this.getOcsUrl(`/users/${id}/enable`);
-    log.debug("url ", url);
- 
-    const response: Response = await this.getHttpResponse(url, requestInit, [200], { description: `User ${id} enable` });
-    const rawResult: any = await response.json();
- 
-    if (this.getOcsMetaStatus(rawResult).code === 100) {
-      return;
-    }
-    throw new UserNotFoundError(`User '${id}' not found`);
-  }
- 
-  /**
-   * disables the user
-   * @param id string the user id
-   * @returns {Promise<void>}
-   * @throws {UserNotFoundError}
-   */
-  public async disableUser(id: string): Promise<void> {
-    log.debug("disableUser");
-    const requestInit: RequestInit = {
-      headers: this.getOcsHeaders(),
-      method: "PUT",
-    };
- 
-    const url = this.getOcsUrl(`/users/${id}/disable`);
-    log.debug("url ", url);
- 
-    const response: Response = await this.getHttpResponse(url, requestInit, [200], { description: `User ${id} disable` });
-    const rawResult: any = await response.json();
- 
-    if (this.getOcsMetaStatus(rawResult).code === 100) {
-      return;
-    }
-    throw new UserNotFoundError(`User '${id}' not found`);
-  }
- 
-  /**
-   * deletes the user
-   * @param id string the user id
-   * @returns {Promise<void>}
-   * @throws {UserNotFoundError}
-   */
-  public async deleteUser(id: string): Promise<void> {
-    log.debug("deleteUser");
-    const requestInit: RequestInit = {
-      headers: this.getOcsHeaders(),
-      method: "DELETE",
-    };
- 
-    const url = this.getOcsUrl(`/users/${id}`);
-    log.debug("url ", url);
- 
-    const response: Response = await this.getHttpResponse(url, requestInit, [200], { description: `User ${id} delete` });
-    const rawResult: any = await response.json();
- 
-    if (this.getOcsMetaStatus(rawResult).code === 100) {
-      return;
-    }
-    throw new UserNotFoundError(`User '${id}' not found`);
-  }
- 
-  /**
-   * returns a user or null if not found
-   * @param id string
-   * @returns User | null
-   */
-  public async getUser(id: string): Promise<User | null> {
-    log.debug("getUser");
-    const users: User[] = await this.getUsers(id);
-    if (users[0]) {
-      return users[0];
-    }
-    return null;
-  }
- 
-  /**
-   * creates a new user with email or password
-   * @param options
-   * @returns User
-   * @throws UserAlreadyExistsError
-   * @throws {UserNotFoundError}
-   * @throws UserUpdateError
-   */
-  public async createUser(options: { id: string; email?: string; password?: string }): Promise<User> {
-    log.debug("createUser");
-    const createUserBody: { userid: string; password?: string; email?: string } = { userid: options.id };
-    if (options.email) {
-      if (/^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(options.email)) {
-        createUserBody.email = options.email;
-      } else {
-        throw new UserCreateError(`Error creating user '${options.id}' - invalid email address '${options.email}'`);
-      }
-    }
-    if (options.password) {
-      createUserBody.password = options.password;
-    }
- 
-    const requestInit: RequestInit = {
-      body: JSON.stringify(createUserBody, null, 4),
-      headers: this.getOcsHeaders(),
-      method: "POST",
-    };
-    log.debug("request body: ", requestInit.body);
-    const response: Response = await this.getHttpResponse(this.getOcsUrl(`/users`), requestInit, [200], { description: `User ${options.id} create` });
-    const rawResult: any = await response.json();
- 
-    if (this.getOcsMetaStatus(rawResult).code === 102) {
-      throw new UserAlreadyExistsError(`User with id '${options.id}' already exists`);
-    }
- 
-    const user: User | null = await this.getUser(options.id);
-    if (user) {
-      return user;
-    }
- 
-    throw new UserCreateError(`Error creating user '${options.id}' - ${this.getOcsMetaStatus(rawResult).message} (${this.getOcsMetaStatus(rawResult).code})`);
-  }
- 
-  /**
-   * updates a user property
-   * @async
-   * @param {string} id user id
-   * @param {UserProperty} property property name
-   * @param {string} value property value
-   * @returns {Promise<void>}
-   * @throws  {UserNotFoundError}
-   * @throws  {UserUpdateError}
-   */
-  public async updateUserProperty(id: string, property: UserProperty, value: string): Promise<void> {
-    log.debug("updateUserProperty");
-    const body: { key: string; value: string } = { key: property, value };
- 
-    const requestInit: RequestInit = {
-      body: JSON.stringify(body, null, 4),
-      headers: this.getOcsHeaders(),
-      method: "PUT",
-    };
-    const url = this.getOcsUrl(`/users/${id}`);
-    log.debug("request body: ", requestInit.body);
-    const response: Response = await this.getHttpResponse(url, requestInit, [200, 401], { description: `User ${id} update ${property}=${value}` });
-    const rawResult: any = await response.json();
- 
-    // This service operation returns a 401, if the user does not exist - very strange...
-    // spec says to return 200 and status code 101
-    /*
-        if (this.getOcsMetaStatus(rawResult).code === 101) {
-            throw new UserNotFoundError(`User with id '${id}' not found`);
-        }
-        */
-    // maybe this is due to a nextcloud api error
-    // it is not possible to distiguish beteen authentication error and user not found :-(
-    if (response.status === 401) {
-      throw new UserNotFoundError(`User with id '${id}' not found`);
-    }
- 
-    if (this.getOcsMetaStatus(rawResult).code === 100) {
-      return;
-    }
- 
-    if (property === UserProperty.password) {
-      value = "********";
-    }
-    // code 102 or 103
-    throw new UserUpdateError(`User with id '${id}' could not be updated - ${property}=${value}. ${rawResult.ocs.meta.message as string}`);
-  }
- 
-  /**
-   * resend the welcome email
-   * @param id user id
-   * @throws  {UserResendWelcomeEmailError}
-   */
-  public async resendWelcomeEmail(id: string): Promise<void> {
-    log.debug("resendWelcomeEmail");
- 
-    const requestInit: RequestInit = {
-      headers: this.getOcsHeaders(),
-      method: "POST",
-    };
-    const url = this.getOcsUrl(`/users/${id}/welcome`);
-    log.debug("request body: ", requestInit.body);
-    const response: Response = await this.getHttpResponse(url, requestInit, [200], { description: `Resend welcome email for user ${id}` });
-    const rawResult: any = await response.json();
- 
-    if (this.getOcsMetaStatus(rawResult).code === 101) {
-      throw new UserResendWelcomeEmailError(`Error sending welcome email for '${id}': Email address not available`);
-    }
- 
-    if (this.getOcsMetaStatus(rawResult).code === 100) {
-      return;
-    }
-    throw new UserResendWelcomeEmailError(`Error sending welcome email for '${id}' failed`);
-  }
- 
-  /**
-   * adds a user to a group as member
-   * @param id string the user id
-   * @param userGroupId string the user group id
-   * @returns {Promise<void>}
-   * @throws {UserNotFoundError}
-   * @throws {UserGroupDoesNotExistError}
-   * @throws {InsufficientPrivilegesError}
-   * @throws {OperationFailedError}
-   */
-  public async addUserToMemberUserGroup(id: string, userGroupId: string): Promise<void> {
-    log.debug("addUserToUserGroup");
- 
-    const body: { groupid: string } = { groupid: userGroupId };
-    const requestInit: RequestInit = {
-      body: JSON.stringify(body, null, 4),
-      headers: this.getOcsHeaders(),
-      method: "POST",
-    };
- 
-    const url = this.getOcsUrl(`/users/${id}/groups`);
-    log.debug("url ", url);
- 
-    const response: Response = await this.getHttpResponse(url, requestInit, [200], { description: `Add user ${id} to user group ${userGroupId}` });
-    const rawResult: any = await response.json();
- 
-    if (this.getOcsMetaStatus(rawResult).code === 100) {
-      return;
-    }
- 
-    if (this.getOcsMetaStatus(rawResult).code === 102) {
-      throw new UserGroupDoesNotExistError(`User group ${userGroupId} does not exist`);
-    }
- 
-    if (this.getOcsMetaStatus(rawResult).code === 103) {
-      throw new UserNotFoundError(`User ${id} does not exist`);
-    }
- 
-    if (this.getOcsMetaStatus(rawResult).code === 104) {
-      throw new InsufficientPrivilegesError(`Insufficient privileges to add a user to a group`);
-    }
- 
-    throw new OperationFailedError(`User ${id} could not be added to user group ${userGroupId}: ${this.getOcsMetaStatus(rawResult).message}`);
-  }
- 
-  /**
-   * removes a user from a group as member
-   * @param id string the user id
-   * @param userGroupId string the user group id
-   * @returns {Promise<void>}
-   * @throws {UserNotFoundError}
-   * @throws {UserGroupDoesNotExistError}
-   * @throws {InsufficientPrivilegesError}
-   * @throws {OperationFailedError}
-   */
-  public async removeUserFromMemberUserGroup(id: string, userGroupId: string): Promise<void> {
-    log.debug("removeUserFromMemberUserGroup");
- 
-    const body: { groupid: string } = { groupid: userGroupId };
-    const requestInit: RequestInit = {
-      body: JSON.stringify(body, null, 4),
-      headers: this.getOcsHeaders(),
-      method: "DELETE",
-    };
- 
-    const url = this.getOcsUrl(`/users/${id}/groups`);
-    log.debug("url ", url);
- 
-    const response: Response = await this.getHttpResponse(url, requestInit, [200], { description: `Remove user ${id} from user group ${userGroupId}` });
-    const rawResult: any = await response.json();
- 
-    if (this.getOcsMetaStatus(rawResult).code === 100) {
-      return;
-    }
- 
-    if (this.getOcsMetaStatus(rawResult).code === 102) {
-      throw new UserGroupDoesNotExistError(`User group ${userGroupId} does not exist`);
-    }
- 
-    if (this.getOcsMetaStatus(rawResult).code === 103) {
-      throw new UserNotFoundError(`User ${id} does not exist`);
-    }
- 
-    if (this.getOcsMetaStatus(rawResult).code === 104) {
-      throw new InsufficientPrivilegesError(`Insufficient privileges to add a user to a group`);
-    }
- 
-    throw new OperationFailedError(`User ${id} could not be added to user group ${userGroupId}: ${this.getOcsMetaStatus(rawResult).message}`);
-  }
- 
-  /**
-   * promotes a user to a user group subadmin
-   * @param id string the user id
-   * @param userGroupId string the user group id
-   * @returns {Promise<void>}
-   * @throws {UserNotFoundError}
-   * @throws {UserGroupDoesNotExistError}
-   * @throws {InsufficientPrivilegesError}
-   * @throws {OperationFailedError}
-   */
-  public async promoteUserToUserGroupSubadmin(id: string, userGroupId: string): Promise<void> {
-    log.debug("promoteUserToUserGroupSubadmin");
- 
-    const body: { groupid: string } = { groupid: userGroupId };
-    const requestInit: RequestInit = {
-      body: JSON.stringify(body, null, 4),
-      headers: this.getOcsHeaders(),
-      method: "POST",
-    };
- 
-    const url = this.getOcsUrl(`/users/${id}/subadmins`);
-    log.debug("url ", url);
- 
-    const response: Response = await this.getHttpResponse(url, requestInit, [200], { description: `Promote User ${id} to user group subadmin ${userGroupId}` });
-    const rawResult: any = await response.json();
- 
-    if (this.getOcsMetaStatus(rawResult).code === 100) {
-      return;
-    }
- 
-    if (this.getOcsMetaStatus(rawResult).code === 102) {
-      throw new UserGroupDoesNotExistError(`User group ${userGroupId} does not exist`);
-    }
- 
-    if (this.getOcsMetaStatus(rawResult).code === 101) {
-      throw new UserNotFoundError(`User ${id} does not exist`);
-    }
- 
-    if (this.getOcsMetaStatus(rawResult).code === 104) {
-      throw new InsufficientPrivilegesError(`Insufficient privileges to add a user to a group`);
-    }
- 
-    throw new OperationFailedError(`User ${id} could not be removed from user group ${userGroupId}: ${this.getOcsMetaStatus(rawResult).message}`);
-  }
- 
-  /**
-   * Removes the subadmin rights for the user specified from the group specified
-   * @param id string the user id
-   * @param userGroupId string the user group id
-   * @returns {Promise<void>}
-   * @throws {InsufficientPrivilegesError}
-   * @throws {OperationFailedError}
-   */
-  public async demoteUserFromSubadminUserGroup(id: string, userGroupId: string): Promise<void> {
-    log.debug("demoteUserFromSubadminUserGroup");
- 
-    const body: { groupid: string } = { groupid: userGroupId };
-    const requestInit: RequestInit = {
-      body: JSON.stringify(body, null, 4),
-      headers: this.getOcsHeaders(),
-      method: "DELETE",
-    };
- 
-    const url = this.getOcsUrl(`/users/${id}/subadmins`);
-    log.debug("url ", url);
- 
-    const response: Response = await this.getHttpResponse(url, requestInit, [200], { description: `Demotes user ${id} from subadmin user group ${userGroupId}` });
-    const rawResult: any = await response.json();
- 
-    if (this.getOcsMetaStatus(rawResult).code === 100) {
-      return;
-    }
- 
-    // this API does not work like remove from group :-(
-    // 101 is for user group not found and user not found
-    /*
-            if (this.getOcsMetaStatus(rawResult).code === 101) {
-                throw new UserGroupDoesNotExistError(`User group ${userGroupId} does not exist`)
-            }
- 
-            if (this.getOcsMetaStatus(rawResult).code === 101) {
-                throw new UserNotFoundError(`User ${id} does not exist`)
-            }
-        */
-    if (this.getOcsMetaStatus(rawResult).code === 104) {
-      throw new InsufficientPrivilegesError(`Insufficient privileges to add a user to a group`);
-    }
- 
-    throw new OperationFailedError(`User ${id} could not be demoted from subadmin user group ${userGroupId}: ${this.getOcsMetaStatus(rawResult).message}`);
-  }
- 
-  /**
-   * insert or update complete user data
-   * @param options IUpsertUserOptions[]
-   * @returns Promise<IUpsertUserReport[]
-   */
-  public async upsertUsers(options: IUpsertUserOptions[]): Promise<IUpsertUserReport[]> {
-    const report: IUpsertUserReport[] = [];
-    for (const option of options) {
-      const userReport: IUpsertUserReport = { id: option.id, message: "", changes: [] };
-      let user: User | null = await this.getUser(option.id);
-      // create or update user?
- 
-      if (!user) {
-        try {
-          user = await this.createUser({ id: option.id, email: option.email, password: option.password });
-          userReport.message = `User ${option.id} created`;
-        } catch (e) {
-          userReport.message = `Create user ${option.id} failed ${e.message as string}`;
-          report.push(userReport);
-          continue;
-        }
-      } else {
-        userReport.message = `User ${option.id} changed`;
-      }
- 
-      let previousValue: string = "";
-      let newValue: string = "";
-      let property: string = "";
- 
-      // ************************
-      // enabled
-      // ************************
-      if (option.enabled !== undefined) {
-        if ((await user.isEnabled()) && option.enabled === false) {
-          try {
-            await user.disable();
-            userReport.changes.push({ property: "enabled", previousValue: "true", newValue: "false" });
-          } catch (e) {
-            userReport.changes.push({ property: "enabled", previousValue: "true", newValue: "true", error: e.message });
-          }
-        }
- 
-        if ((await user.isEnabled()) === false && option.enabled === true) {
-          try {
-            await user.enable();
-            userReport.changes.push({ property: "enabled", previousValue: "false", newValue: "true" });
-          } catch (e) {
-            userReport.changes.push({ property: "enabled", previousValue: "false", newValue: "false", error: e.message });
-          }
-        }
-      }
- 
-      // ************************
-      // super admin
-      // ************************
-      if (option.superAdmin !== undefined) {
-        if ((await user.isSuperAdmin()) && option.superAdmin === false) {
-          try {
-            await user.demoteFromSuperAdmin();
-            userReport.changes.push({ property: "superAdmin", previousValue: "true", newValue: "false" });
-          } catch (e) {
-            userReport.changes.push({ property: "superAdmin", previousValue: "true", newValue: "true", error: e.message });
-          }
-        }
- 
-        if ((await user.isSuperAdmin()) === false && option.superAdmin === true) {
-          try {
-            await user.promoteToSuperAdmin();
-            userReport.changes.push({ property: "superAdmin", previousValue: "false", newValue: "true" });
-          } catch (e) {
-            userReport.changes.push({ property: "superAdmin", previousValue: "false", newValue: "false", error: e.message });
-          }
-        }
-      }
- 
-      // ************************
-      // member groups
-      // ************************
-      if (option.memberGroups !== undefined) {
-        const previousGroups: string[] = await user.getMemberUserGroupIds();
-        const newGroups: string[] = option.memberGroups;
-        if (option.superAdmin !== undefined) {
-          if (option.superAdmin === true) {
-            if (newGroups.indexOf("admin") === -1) {
-              newGroups.push("admin");
-            }
-          }
-        }
-        const groupsToAdd: string[] = newGroups.filter((x) => !previousGroups.includes(x));
-        const groupsToRemove: string[] = previousGroups.filter((x) => !newGroups.includes(x));
-        let userGroup: UserGroup | null;
-        property = "memberGroups";
-        let error: Error | null = null;
-        for (const groupId of groupsToAdd) {
-          userGroup = await this.getUserGroup(groupId);
-          if (!userGroup) {
-            try {
-              userGroup = await this.createUserGroup(groupId);
-            } catch (e) {
-              error = e as Error;
-              break;
-            }
-          }
-          try {
-            await user.addToMemberUserGroup(userGroup);
-          } catch (e) {
-            error = e as Error;
-            break;
-          }
-        }
- 
-        for (const groupId of groupsToRemove) {
-          try {
-            await user.removeFromMemberUserGroup(new UserGroup(this, groupId));
-          } catch (e) {
-            error = e as Error;
-            break;
-          }
-        }
-        if (error) {
-          userReport.changes.push({ property, previousValue: previousGroups.join(", "), newValue: previousGroups.join(", "), error: error.message });
-        } else {
-          Eif (groupsToAdd.length > 0 || groupsToRemove.length > 0) {
-            userReport.changes.push({ property, previousValue: previousGroups.join(", "), newValue: newGroups.join(", ") });
-          }
-        }
-      }
- 
-      // ************************
-      // subadmin groups
-      // ************************
-      if (option.subadminGroups !== undefined) {
-        const previousGroups: string[] = await user.getSubadminUserGroupIds();
-        const newGroups: string[] = option.subadminGroups;
-        const groupsToAdd: string[] = newGroups.filter((x) => !previousGroups.includes(x));
-        const groupsToRemove: string[] = previousGroups.filter((x) => !newGroups.includes(x));
-        let userGroup: UserGroup | null;
-        property = "subadminGroups";
-        let error: Error | null = null;
-        for (const groupId of groupsToAdd) {
-          userGroup = await this.getUserGroup(groupId);
-          if (!userGroup) {
-            try {
-              userGroup = await this.createUserGroup(groupId);
-            } catch (e) {
-              error = e as Error;
-              break;
-            }
-          }
-          try {
-            await user.promoteToUserGroupSubadmin(userGroup);
-          } catch (e) {
-            error = e as Error;
-            break;
-          }
-        }
- 
-        for (const groupId of groupsToRemove) {
-          try {
-            await user.demoteFromSubadminUserGroup(new UserGroup(this, groupId));
-          } catch (e) {
-            error = e as Error;
-            break;
-          }
-        }
-        if (error) {
-          userReport.changes.push({ property, previousValue: previousGroups.join(", "), newValue: previousGroups.join(", "), error: error.message });
-        } else {
-          userReport.changes.push({ property, previousValue: previousGroups.join(", "), newValue: newGroups.join(", ") });
-        }
-      }
- 
-      // ************************
-      // display name
-      // ************************
-      if (option.displayName !== undefined) {
-        previousValue = await user.getDisplayName();
-        newValue = option.displayName;
-        property = "displayName";
-        if (previousValue !== newValue) {
-          try {
-            await user.setDisplayName(option.displayName);
-            userReport.changes.push({ property, previousValue, newValue });
-          } catch (e) {
-            let message = "";
-            Eif (e instanceof Error) {
-              message = e.message;
-            }
-            userReport.changes.push({ property, previousValue, newValue: previousValue, error: message });
-          }
-        }
-      }
- 
-      // ************************
-      // email
-      // ************************
-      if (option.email !== undefined) {
-        previousValue = await user.getEmail();
-        newValue = option.email;
-        property = "email";
-        if (previousValue !== newValue) {
-          try {
-            await user.setEmail(option.email);
-            userReport.changes.push({ property, previousValue, newValue });
-          } catch (e) {
-            let message = "";
-            Eif (e instanceof Error) {
-              message = e.message;
-            }
-            userReport.changes.push({ property, previousValue, newValue: previousValue, error: message });
-          }
-        }
-      }
- 
-      // ************************
-      // language
-      // ************************
-      if (option.language !== undefined) {
-        previousValue = await user.getLanguage();
-        newValue = option.language;
-        property = "language";
-        if (previousValue !== newValue) {
-          try {
-            await user.setLanguage(option.language);
-            userReport.changes.push({ property, previousValue, newValue });
-          } catch (e) {
-            let message = "";
-            Eif (e instanceof Error) {
-              message = e.message;
-            }
-            userReport.changes.push({ property, previousValue, newValue: previousValue, error: message });
-          }
-        }
-      }
- 
-      // ************************
-      // locale
-      // ************************
-      if (option.locale !== undefined) {
-        previousValue = await user.getLocale();
-        newValue = option.locale;
-        property = "locale";
-        if (previousValue !== newValue) {
-          try {
-            await user.setLocale(option.locale);
-            userReport.changes.push({ property, previousValue, newValue });
-          } catch (e) {
-            let message = "";
-            Eif (e instanceof Error) {
-              message = e.message;
-            }
-            userReport.changes.push({ property, previousValue, newValue: previousValue, error: message });
-          }
-        }
-      }
- 
-      // ************************
-      // twitter
-      // ************************
-      if (option.twitter !== undefined) {
-        previousValue = await user.getTwitter();
-        newValue = option.twitter;
-        property = "twitter";
-        if (previousValue !== newValue) {
-          try {
-            await user.setTwitter(option.twitter);
-            userReport.changes.push({ property, previousValue, newValue });
-          } catch (e) {
-            let message = "";
-            Eif (e instanceof Error) {
-              message = e.message;
-            }
-            userReport.changes.push({ property, previousValue, newValue: previousValue, error: message });
-          }
-        }
-      }
- 
-      // ************************
-      // phone
-      // ************************
-      if (option.phone !== undefined) {
-        previousValue = await user.getPhone();
-        newValue = option.phone;
-        property = "phone";
-        if (previousValue !== newValue) {
-          try {
-            await user.setPhone(option.phone);
-            userReport.changes.push({ property, previousValue, newValue });
-          } catch (e) {
-            let message = "";
-            Eif (e instanceof Error) {
-              message = e.message;
-            }
- 
-            userReport.changes.push({ property, previousValue, newValue: previousValue, error: message });
-          }
-        }
-      }
- 
-      // ************************
-      // password
-      // ************************
-      if (option.password !== undefined) {
-        previousValue = "********";
-        newValue = option.password;
-        property = "password";
-        try {
-          await user.setPassword(option.password);
-          userReport.changes.push({ property, previousValue, newValue: previousValue });
-        } catch (e) {
-          let message = "";
-          Eif (e instanceof Error) {
-            message = e.message;
-          }
-          userReport.changes.push({ property, previousValue, newValue: previousValue, error: message });
-        }
-      }
- 
-      // ************************
-      // address
-      // ************************
-      if (option.address !== undefined) {
-        previousValue = await user.getAddress();
-        newValue = option.address;
-        property = "address";
-        if (previousValue !== newValue) {
-          try {
-            await user.setAddress(option.address);
-            userReport.changes.push({ property, previousValue, newValue });
-          } catch (e) {
-            let message = "";
-            Eif (e instanceof Error) {
-              message = e.message;
-            }
-            userReport.changes.push({ property, previousValue, newValue: previousValue, error: message });
-          }
-        }
-      }
- 
-      // ************************
-      // website
-      // ************************
-      if (option.website !== undefined) {
-        previousValue = await user.getWebsite();
-        newValue = option.website;
-        property = "website";
-        if (previousValue !== newValue) {
-          try {
-            await user.setWebsite(option.website);
-            userReport.changes.push({ property, previousValue, newValue });
-          } catch (e) {
-            let message = "";
-            Eif (e instanceof Error) {
-              message = e.message;
-            }
-            userReport.changes.push({ property, previousValue, newValue: previousValue, error: message });
-          }
-        }
-      }
- 
-      // ************************
-      // quota
-      // ************************
-      if (option.quota !== undefined) {
-        previousValue = (await user.getQuotaUserFriendly()).quota;
-        newValue = option.quota;
-        property = "quota";
-        if (previousValue !== newValue) {
-          try {
-            await user.setQuota(option.quota);
-            userReport.changes.push({ property, previousValue, newValue });
-          } catch (e) {
-            let message = "";
-            Eif (e instanceof Error) {
-              message = e.message;
-            }
- 
-            userReport.changes.push({ property, previousValue, newValue: previousValue, error: message });
-          }
-        }
-      }
- 
-      // ************************
-      // resend welcome email
-      // ************************
-      if (option.resendWelcomeEmail !== undefined) {
-        previousValue = "not sent";
-        newValue = "sent";
-        property = "resendWelcomeEmail";
-        if (option.resendWelcomeEmail) {
-          try {
-            await user.resendWelcomeEmail();
-            userReport.changes.push({ property, previousValue, newValue });
-          } catch (e) {
-            let message = "";
-            Eif (e instanceof Error) {
-              message = e.message;
-            }
- 
-            userReport.changes.push({ property, previousValue, newValue: previousValue, error: message });
-          }
-        }
-      }
- 
-      if (userReport.changes.length === 0) {
-        userReport.message = `User ${option.id} not changed`;
-      }
-      report.push(userReport);
-    }
-    return report;
-  }
- 
-  // ***************************************************************************************
-  // shares
-  // https://docs.nextcloud.com/server/latest/developer_manual/client_apis/OCS/ocs-share-api.html
-  // ***************************************************************************************
- 
-  /**
-   * create a new share
-   */
-  public async createShare(options: ICreateShare): Promise<Share> {
-    const shareRequest = Share.createShareRequestBody(options);
-    log.debug(shareRequest);
- 
-    const requestInit: RequestInit = {
-      body: shareRequest,
-      headers: this.getOcsHeaders(),
-      method: "POST",
-    };
-    const url = this.nextcloudOrigin + "/ocs/v2.php/apps/files_sharing/api/v1/shares";
- 
-    // try {
-    const response: Response = await this.getHttpResponse(url, requestInit, [200, 204], { description: "Share create" });
- 
-    const rawResult: { ocs: { data: { id: string } } } = (await response.json()) as { ocs: { data: { id: string } } };
- 
-    log.debug(rawResult);
- 
-    const share: Share = await Share.getShare(this, rawResult.ocs.data.id);
- 
-    if (options.publicUpload) {
-      await share.setPublicUpload();
-    }
- 
-    return share;
- 
-    /* } catch (e) {
-            log.debug("result " + e.message);
-            log.debug("requestInit ", JSON.stringify(requestInit, null, 4));
-            log.debug("headers " + JSON.stringify(headers, null, 4));
-            log.debug("url ", url);
-            throw e;
-        } */
-  }
- 
-  /**
-   * update a new share
-   */
-  public async updateShare(shareId: string, body: { password: string } | { expireDate: string } | { note: string } | { permissions: number }): Promise<void> {
-    log.debug("updateShare body ", body);
- 
-    const requestInit: RequestInit = {
-      body: JSON.stringify(body, null, 4),
-      headers: this.getOcsHeaders(),
-      method: "PUT",
-    };
-    const url = this.nextcloudOrigin + "/ocs/v2.php/apps/files_sharing/api/v1/shares/" + shareId;
- 
-    await this.getHttpResponse(url, requestInit, [200], { description: "Share update" });
-  }
- 
-  /**
-   * get share information
-   * @param shareId
-   */
-  public async getShare(shareId: string): Promise<any> {
-    const requestInit: RequestInit = {
-      headers: this.getOcsHeaders(),
-      method: "GET",
-    };
-    const url = this.nextcloudOrigin + "/ocs/v2.php/apps/files_sharing/api/v1/shares/" + shareId;
- 
-    const response: Response = await this.getHttpResponse(url, requestInit, [200], { description: "Share get" });
- 
-    // eslint-disable-next-line @typescript-eslint/no-unsafe-return
-    return await response.json();
- 
-    /*
-    } catch (e) {
-        log.debug("result " + e.message);
-        log.debug("requestInit ", JSON.stringify(requestInit, null, 4));
-        log.debug("headers " + JSON.stringify(headers, null, 4));
-        log.debug("url ", url);
-        throw e;
-    }
-    */
-  }
- 
-  /**
-   * get share information
-   * @param shareId
-   */
-  public async deleteShare(shareId: string): Promise<any> {
-    const requestInit: RequestInit = {
-      headers: this.getOcsHeaders(),
-      method: "DELETE",
-    };
-    const url = this.nextcloudOrigin + "/ocs/v2.php/apps/files_sharing/api/v1/shares/" + shareId;
- 
-    const response: Response = await this.getHttpResponse(url, requestInit, [200], { description: "Share delete" });
-  }
- 
-  // ***************************************************************************************
-  // notfication management
-  // ***************************************************************************************
-  /**
-   * @returns array of notification objects
-   */
-  // eslint-disable-next-line @typescript-eslint/ban-types
-  public async getNotifications(): Promise<object[]> {
-    const requestInit: RequestInit = {
-      headers: this.getOcsHeaders(),
-      method: "GET",
-    };
- 
-    const response: Response = await this.getHttpResponse(this.nextcloudOrigin + "/ocs/v2.php/apps/notifications/api/v2/notifications", requestInit, [200, 404], { description: "Notifications get" });
- 
-    // no notification found
-    if (response.status === 404) {
-      return [];
-    }
- 
-    const rawResult: any = await response.json();
- 
-    let notifications = [];
- 
-    if (rawResult && rawResult.ocs && rawResult.ocs.data) {
-      notifications = rawResult.ocs.data;
-    } else {
-      throw new ClientError("Fatal Error: nextcloud notifications data missing", "ERR_SYSTEM_INFO_MISSING_DATA"); // @todo wrong error message
-    }
- 
-    // eslint-disable-next-line @typescript-eslint/ban-types
-    const result: object[] = notifications;
-    return result;
-  }
- 
-  // eslint-disable-next-line @typescript-eslint/ban-types
-  public async getUpdateNotifications(version: string): Promise<object> {
-    // @todo refactoring... /ocs/v2.php/apps/notifications/api/v2/notifications/<id>   (GET/DELETE)
- 
-    const requestInit: RequestInit = {
-      headers: this.getOcsHeaders(),
-      method: "GET",
-    };
- 
-    const response: Response = await this.getHttpResponse(this.nextcloudOrigin + `/ocs/v2.php/apps/updatenotification/api/v1/applist/${version}`, requestInit, [200], { description: "UpdateNotifications get" });
- 
-    // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
-    const rawResult: any = await response.json();
- 
-    let updateNotification = {};
- 
-    // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access
-    if (rawResult && rawResult.ocs && rawResult.ocs.data) {
-      updateNotification = rawResult.ocs.data;
-    } else {
-      throw new ClientError("Fatal Error: nextcloud notifications data missing", "ERR_SYSTEM_INFO_MISSING_DATA");
-    }
- 
-    // eslint-disable-next-line @typescript-eslint/ban-types
-    const result: object = updateNotification;
-    return result;
-  }
- 
-  // @todo to be refactored to user
-  public async sendNotificationToUser(userId: string, shortMessage: string, longMessage?: string): Promise<void> {
-    const requestInit: RequestInit = {
-      headers: new Headers({
-        // eslint-disable-next-line @typescript-eslint/naming-convention
-        Accept: "application/json",
-        // eslint-disable-next-line @typescript-eslint/naming-convention
-        "Content-Type": "application/x-www-form-urlencoded",
-        // eslint-disable-next-line @typescript-eslint/naming-convention
-        "OCS-APIRequest": "true",
-      }),
-      method: "POST",
-    };
- 
-    if (!longMessage) {
-      longMessage = "";
-    }
-    longMessage = `&longMessage=${encodeURIComponent(longMessage)}`;
-    const queryString = `${encodeURIComponent(userId)}?shortMessage=${encodeURIComponent(shortMessage)}${longMessage}`;
-    await this.getHttpResponse(this.nextcloudOrigin + `/ocs/v2.php/apps/admin_notifications/api/v1/notifications/${queryString}`, requestInit, [200], { description: "User create" });    
-    // const response: Response = await this.getHttpResponse(this.nextcloudOrigin + `/ocs/v2.php/apps/admin_notifications/api/v1/notifications/${queryString}`, requestInit, [200], { description: "User create" });
-    // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
-    // const rawResult: any = await response.json();
-    //        console.log(rawResult);
-  }
- 
-  // ***************************************************************************************
-  // apps management
-  // ***************************************************************************************
-  /**
-   * returns apps
-   */
-  public async getApps(): Promise<string[]> {
-    const requestInit: RequestInit = {
-      headers: this.getOcsHeaders(),
-      method: "GET",
-    };
- 
-    const response: Response = await this.getHttpResponse(this.getOcsUrl(`/apps`), requestInit, [200], { description: "Apps get" });
- 
-    // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
-    const rawResult: any = await response.json();
- 
-    let apps = [];
- 
-    // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access
-    if (rawResult && rawResult.ocs && rawResult.ocs.data) {
-      apps = rawResult.ocs.data;
-    } else {
-      throw new ClientError("Fatal Error: nextcloud apps data missing", "ERR_SYSTEM_INFO_MISSING_DATA");
-    }
- 
-    const result: string[] = apps;
- 
-    return result;
-  }
-  // eslint-disable-next-line @typescript-eslint/ban-types
-  public async getAppInfos(appName: string): Promise<object> {
-    const requestInit: RequestInit = {
-      headers: this.getOcsHeaders(),
-      method: "GET",
-    };
- 
-    const response: Response = await this.getHttpResponse(this.getOcsUrl(`/apps/${appName}`), requestInit, [200], { description: "App Infos get" });
- 
-    // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
-    const rawResult: any = await response.json();
- 
-    let appInfo = {};
- 
-    // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access
-    if (rawResult && rawResult.ocs && rawResult.ocs.data) {
-      appInfo = rawResult.ocs.data;
-    } else {
-      throw new ClientError("Fatal Error: nextcloud apps data missing", "ERR_SYSTEM_INFO_MISSING_DATA");
-    }
- 
-    // eslint-disable-next-line @typescript-eslint/ban-types
-    const result: object = appInfo;
- 
-    return result;
-  }
- 
-  // ***************************************************************************************
-  // private methods
-  // ***************************************************************************************
- 
-  /**
-   * asserts valid xml
-   * asserts multistatus response
-   * asserts that a href is available in the multistatus response
-   * asserts propstats and prop
-   * @param response the http response
-   * @param href get only properties that match the href
-   * @returns array of properties
-   * @throws GeneralError
-   */
-  private async getPropertiesFromWebDAVMultistatusResponse(response: Response, href: string): Promise<any[]> {
-    const responseContentType: string | null = response.headers.get("Content-Type");
- 
-    if (!responseContentType) {
-      throw new ClientError("Response content type expected", "ERR_RESPONSE_WITHOUT_CONTENT_TYPE_HEADER");
-    }
- 
-    if (responseContentType.indexOf("application/xml") === -1) {
-      throw new ClientError("XML response content type expected", "ERR_XML_RESPONSE_CONTENT_TYPE_EXPECTED");
-    }
- 
-    const xmlBody: string = await response.text();
- 
-    if (parser.validate(xmlBody) !== true) {
-      throw new ClientError(`The response is not valid XML: ${xmlBody}`, "ERR_RESPONSE_NOT_INVALID_XML");
-    }
-    const options: any = {
-      ignoreNameSpace: true,
-    };
-    const body: any = parser.parse(xmlBody, options);
- 
-    // ensure that we have a multistatus response
-    if (!body.multistatus || !body.multistatus.response) {
-      throw new ClientError(`The response is is not a WebDAV multistatus response`, "ERR_RESPONSE_NO_MULTISTATUS_XML");
-    }
- 
-    // ensure that response is always an array
-    if (body.multistatus.response.href || body.multistatus.response.propstat) {
-      body.multistatus.response = new Array(body.multistatus.response);
-    }
-    /*
-                if (body.multistatus.response.propstat) {
-                    body.multistatus.response = [body.multistatus.response];
-                }
-        */
-    const responseProperties: any[] = [];
-    for (const res of body.multistatus.response) {
-      if (!res.href) {
-        throw new ClientError(`The mulitstatus response must have a href`, "ERR_RESPONSE_MISSING_HREF_MULTISTATUS");
-      }
- 
-      if (!res.propstat) {
-        throw new ClientError(`The mulitstatus response must have a "propstat" container`, "ERR_RESPONSE_MISSING_PROPSTAT");
-      }
-      let propStats = res.propstat;
- 
-      // ensure an array
-      if (res.propstat.status || res.propstat.prop) {
-        propStats = [res.propstat];
-      }
- 
-      for (const propStat of propStats) {
-        if (!propStat.status) {
-          throw new ClientError(`The propstat must have a "status"`, "ERR_RESPONSE_MISSING_PROPSTAT_STATUS");
-        }
-        if (propStat.status === "HTTP/1.1 200 OK") {
-          if (!propStat.prop) {
-            throw new ClientError(`The propstat must have a "prop"`, "ERR_RESPONSE_MISSING_PROPSTAT_PROP");
-          }
-          const property: any = propStat.prop;
-          // eslint-disable-next-line no-underscore-dangle
-          property._href = res.href;
-          responseProperties.push(property);
-        }
-      }
-      //            }
-    }
-    // eslint-disable-next-line @typescript-eslint/no-unsafe-return
-    return responseProperties;
-  }
- 
-  /**
-   * nextcloud creates a csrf token and stores it in the html header attribute
-   * data-requesttoken
-   * this function is currently not used
-   * @returns the csrf token / requesttoken
-   */
-  /*
-        private async getCSRFToken(): Promise<string> {
- 
-            const requestInit: RequestInit = {
-                method: "GET",
-            };
- 
-            const response: Response = await this.getHttpResponse(
-                this.nextcloudOrigin,
-                requestInit,
-                [200],
-                { description: "CSER token get" });
- 
-            const html = await response.text();
- 
-            const requestToken: string = html.substr(html.indexOf("data-requesttoken=") + 19, 89);
-            log.debug("getCSRFToken ", requestToken);
-            return requestToken;
-        }
-    */
- 
-  private async getHttpResponse(url: string, requestInit: RequestInit, expectedHttpStatusCode: number[], context: IRequestContext): Promise<Response> {
-    if (!requestInit.headers) {
-      requestInit.headers = new Headers();
-    }
- 
-    /* istanbul ignore else */
-    if (this.fakeServer) {
-      return await this.fakeServer.getFakeHttpResponse(url, requestInit, expectedHttpStatusCode, context);
-    } else {
-      return await this.httpClient!.getHttpResponse(url, requestInit, expectedHttpStatusCode, context);
-    }
-  }
- 
-  /**
-   * get contents array of a folder
-   * @param folderName Name of the folder like "/company/branches/germany"
-   * @param folderIndicator true if folders are requested otherwise files
-   * @returns array of folder contents meta data
-   */
-  private async contents(folderName: string, folderIndicator: boolean): Promise<any[]> {
-    log.debug("Contents: folder ", folderName);
-    const folders: Folder[] = [];
-    folderName = this.sanitizeFolderName(folderName);
-    const resultArray: any[] = [];
- 
-    if (folderIndicator === true) {
-      log.debug("Contents: get folders");
-    } else {
-      log.debug("Contents: get files");
-    }
-    try {
-      const folderContentsArray = await this.getFolderContents(folderName);
- 
-      // log.debug("###########################");
-      // log.debug("$s", JSON.stringify(folderContentsArray, null, 4));
-      // log.debug("###########################");
- 
-      for (const folderElement of folderContentsArray) {
-        if (folderElement.type === "directory") {
-          if (folderIndicator === true) {
-            resultArray.push(folderElement);
-          }
-        } else {
-          if (folderIndicator === false) {
-            log.debug("Contents folder element file ", folderElement);
-            resultArray.push(folderElement);
-          }
-        }
-      }
-    } catch (e) {
-      log.debug("Contents: exception occurred ", e.message);
-    }
- 
-    // eslint-disable-next-line @typescript-eslint/no-unsafe-return
-    return resultArray;
-  }
- 
-  private sanitizeFolderName(folderName: string): string {
-    if (folderName[0] !== "/") {
-      folderName = "/" + folderName;
-    }
-    // remove trailing "/" es
-    folderName = folderName.replace(/\/+$/, "");
-    if (folderName === "") {
-      folderName = "/";
-    }
- 
-    return folderName;
-  }
- 
-  private getTagIdFromHref(href: string): number {
-    return parseInt(href.split("/")[href.split("/").length - 1], 10);
-  }
- 
-  private async createFolderInternal(folderName: string): Promise<void> {
-    const url: string = this.webDAVUrl + folderName;
-    log.debug("createFolderInternal ", url);
- 
-    const requestInit: RequestInit = {
-      method: "MKCOL",
-    };
-    try {
-      await this.getHttpResponse(url, requestInit, [201], { description: "Folder create" });
-    } catch (err) {
-      log.debug(`Error in createFolderInternal ${err.message as string} ${requestInit.method || ""} ${url}`);
-      throw err;
-    }
-  }
- 
-  private async stat(fileName: string): Promise<IStat> {
-    const url: string = this.webDAVUrl + fileName;
-    log.debug("stat ", url);
- 
-    const requestInit: RequestInit = {
-      body: `<?xml version="1.0"?>
-            <d:propfind  xmlns:d="DAV:" xmlns:oc="http://owncloud.org/ns" xmlns:nc="http://nextcloud.org/ns">
-            <d:prop>
-                  <d:getlastmodified />
-                  <d:getetag />
-                  <d:getcontenttype />
-                  <d:resourcetype />
-                  <oc:fileid />
-                  <oc:permissions />
-                  <oc:size />
-                  <d:getcontentlength />
-                  <nc:has-preview />
-                  <oc:favorite />
-                  <oc:comments-unread />
-                  <oc:owner-display-name />
-                  <oc:share-types />
-            </d:prop>
-          </d:propfind>`,
-      // headers: new Headers({ Depth: "0" }),
-      headers: new Headers(),
-      method: "PROPFIND",
-    };
-    let response: Response;
-    try {
-      response = await this.getHttpResponse(url, requestInit, [207], { description: "File/Folder get details" });
-    } catch (err) {
-      log.debug(`Error in stat ${err.message as string} ${requestInit.method || ""} ${url}`);
-      throw err;
-    }
- 
-    const properties: any[] = await this.getPropertiesFromWebDAVMultistatusResponse(response, "");
-    let resultStat: IStat | null = null;
- 
-    for (const prop of properties) {
-      resultStat = {
-        basename: basename(fileName),
-        fileid: prop.fileid,
-        filename: fileName,
-        lastmod: prop.getlastmodified,
-        type: "file",
-      };
- 
-      if (prop.getcontentlength) {
-        resultStat.size = prop.getcontentlength;
-      } else {
-        resultStat.type = "directory";
-      }
- 
-      if (prop.getcontenttype) {
-        resultStat.mime = prop.getcontenttype;
-      }
-    }
- 
-    if (!resultStat) {
-      log.debug("Error: response ", JSON.stringify(properties, null, 4));
-      throw new ClientError("Error getting status information from : " + url, "ERR_STAT");
-    }
-    return resultStat;
-  }
- 
-  private getOcsMetaStatus(input: any): { code: number; message: string } {
-    let code: number;
-    let message: string = "";
-    if (input.ocs && input.ocs.meta && input.ocs.meta.statuscode) {
-      code = input.ocs.meta.statuscode;
-      if (input.ocs.meta.message) {
-        message = input.ocs.meta.message;
-      }
-      return { code, message };
-    }
-    throw new InvalidServiceResponseFormatError("Fatal Error: The OCS meta status could not be retrieved from OCS response");
-  }
- 
-  private getOcsHeaders(): Headers {
-    return new Headers({
-      // eslint-disable-next-line @typescript-eslint/naming-convention
-      "OCS-APIRequest": "true",
-      // eslint-disable-next-line @typescript-eslint/naming-convention
-      "Content-Type": "application/json",
-      // eslint-disable-next-line @typescript-eslint/naming-convention
-      Accept: "application/json",
-    });
-  }
- 
-  private getOcsUrl(suffix: string): string {
-    /*
-        if (!suffix) {
-            suffix = "";
-        }
-        if (!suffix.startsWith("/")) {
-            suffix = `/${suffix}`
-        }
-        */
-    return `${this.nextcloudOrigin}/ocs/v1.php/cloud${suffix}`;
-  }
- 
-  private async putFileContents(fileName: string, data: Buffer | NodeJS.ReadableStream): Promise<Response> {
-    const url: string = this.webDAVUrl + fileName;
-    log.debug("putFileContents ", url);
- 
-    const requestInit: RequestInit = {
-      body: data,
-      method: "PUT",
-    };
- 
-    let description = "File save content ";
-    Eif (data instanceof Buffer) {
-      description += "from buffer";
-    } else {
-      description += "from stream";
-    }
-    return await this.getHttpResponse(url, requestInit, [201, 204], { description });
-  }
-}
- 
- -
-
- - - - - - - - - \ No newline at end of file diff --git a/docs/coverage/src/command.ts.html b/docs/coverage/src/command.ts.html deleted file mode 100644 index 9bd48521..00000000 --- a/docs/coverage/src/command.ts.html +++ /dev/null @@ -1,446 +0,0 @@ - - - - - - Code coverage report for src/command.ts - - - - - - - - - -
-
-

All files / src command.ts

-
- -
- 96% - Statements - 24/25 -
- - -
- 80% - Branches - 8/10 -
- - -
- 100% - Functions - 7/7 -
- - -
- 96% - Lines - 24/25 -
- - -
-

- Press n or j to go to the next uncovered block, b, p or k for the previous block. -

-
-
-

-
1 -2 -3 -4 -5 -6 -7 -8 -9 -10 -11 -12 -13 -14 -15 -16 -17 -18 -19 -20 -21 -22 -23 -24 -25 -26 -27 -28 -29 -30 -31 -32 -33 -34 -35 -36 -37 -38 -39 -40 -41 -42 -43 -44 -45 -46 -47 -48 -49 -50 -51 -52 -53 -54 -55 -56 -57 -58 -59 -60 -61 -62 -63 -64 -65 -66 -67 -68 -69 -70 -71 -72 -73 -74 -75 -76 -77 -78 -79 -80 -81 -82 -83 -84 -85 -86 -87 -88 -89 -90 -91 -92 -93 -94 -95 -96 -97 -98 -99 -100 -101 -102 -103 -104 -105 -106 -107 -108 -109 -110 -111 -112 -113 -114 -115 -116 -117 -118 -119 -120 -121 -122 -123  -1x -  -1x -  -  -  -  -  -  -  -  -  -1x -  -  -  -1x -  -  -  -1x -  -  -  -1x -  -  -  -1x -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -1x -  -  -  -  -  -  -4x -4x -4x -4x -  -  -  -  -  -  -  -  -  -4x -4x -  -  -4x -4x -4x -4x -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -233x -3x -  -230x -  -  -  -  -  -  -  -39x -  -  -  -  -  -  -  -227x -  -  -  -  -  -  -  -42x -  -  -  - 
// tslint:disable-next-line:no-var-requires
-const debug = require("debug").debug("Command");
- 
-import Client, {
-    CommandAlreadyExecutedError,
-} from "./client";
- 
-/**
- * The potential states that a command can have.
- * When a command is created, the state is "initial"
- * When the execution has started, the status is "running"
- * When the execution has finsihed, the status can be "succes" or "failed"
- */
-export enum CommandStatus {
-    /**
-     * When a command is created, the state is "initial"
-     */
-    initial = "initial",
-    /**
-     * When the execution has started, the status is "running"
-     */
-    running = "running",
-    /**
-     * After successful  execution of the command, the status is "success"
-     */
-    success = "success",
-    /**
-     * After unsuccessfull execution of the command, the status is "failed"
-     */
-    failed = "failed",
-}
- 
-/**
- * when the command has finished, the client can get the result of the command execution
- */
-export interface CommandResultMetaData {
-    errors: string[],
-    messages: string[],
-    timeElapsed: number,
-}
- 
-/**
- * The command class represents a potential long running activity.
- * This activity has been wrapped into an object to ease the tracking of the processing state.
- * Create a command with  receiver information, execute the command and check the status and progress.
- * Check the result when finsished.
- */
-export default abstract class Command {
-    protected client: Client;
-    protected status: CommandStatus;
-    protected percentCompleted: number;
-    protected resultMetaData: CommandResultMetaData;
- 
-    constructor(client: Client) {
-        this.client = client;
-        this.status = CommandStatus.initial;
-        this.percentCompleted = 0;
-        this.resultMetaData = { messages: [], errors: [], timeElapsed: 0 };
-    }
- 
-    /**
-     * final execute the command
-     * @async
-     * @final
-     * @returns {Promise<void>}
-     */
-    public async execute(): Promise<void> {
-        debug("execute Command = " + this.constructor.name, this.status);
-        Iif (this.isFinished()) {
-            throw new CommandAlreadyExecutedError("Error: Command has already been executed. Command = " + this.constructor.name);
-        }
-        Eif (this.status === CommandStatus.initial) {
-            const startTime = new Date();
-            await this.onExecute();
-            this.resultMetaData.timeElapsed = new Date().getTime() - startTime.getTime();
-        }
-        // do nothing if already running
-    }
- 
-    /**
-     * execute the command
-     * @async
-     * @returns {Promise<void>}
-     */
-    protected abstract async onExecute(): Promise<void>;
- 
-    /**
-     * returns true, if the command has been finished
-     * @returns {boolean}
-     */
-    public isFinished(): boolean {
-        if (this.status === CommandStatus.failed || this.status === CommandStatus.success) {
-            return true;
-        }
-        return false;
-    }
- 
-    /**
-     * returns the status of the command
-     * @returns {CommandStatus}
-     */
-    public getStatus(): CommandStatus {
-        return this.status;
-    }
- 
-    /**
-     * returns the completion percentage of the command
-     * @returns {number} percentage of completion
-     */
-    public getPercentCompleted(): number {
-        return this.percentCompleted;
-    }
- 
-    /**
-     * returns the result meta data of the command
-     * @returns {null|any} the result of the command
-     */
-    public getResultMetaData(): CommandResultMetaData {
-        return this.resultMetaData;
-    }
- 
-}
- 
- -
-
- - - - - - - - - \ No newline at end of file diff --git a/docs/coverage/src/command/command.ts.html b/docs/coverage/src/command/command.ts.html deleted file mode 100644 index e6f87c8c..00000000 --- a/docs/coverage/src/command/command.ts.html +++ /dev/null @@ -1,446 +0,0 @@ - - - - - - Code coverage report for src/command/command.ts - - - - - - - - - -
-
-

All files / src/command command.ts

-
- -
- 96% - Statements - 24/25 -
- - -
- 90% - Branches - 9/10 -
- - -
- 100% - Functions - 7/7 -
- - -
- 96% - Lines - 24/25 -
- - -
-

- Press n or j to go to the next uncovered block, b, p or k for the previous block. -

-
-
-

-
1 -2 -3 -4 -5 -6 -7 -8 -9 -10 -11 -12 -13 -14 -15 -16 -17 -18 -19 -20 -21 -22 -23 -24 -25 -26 -27 -28 -29 -30 -31 -32 -33 -34 -35 -36 -37 -38 -39 -40 -41 -42 -43 -44 -45 -46 -47 -48 -49 -50 -51 -52 -53 -54 -55 -56 -57 -58 -59 -60 -61 -62 -63 -64 -65 -66 -67 -68 -69 -70 -71 -72 -73 -74 -75 -76 -77 -78 -79 -80 -81 -82 -83 -84 -85 -86 -87 -88 -89 -90 -91 -92 -93 -94 -95 -96 -97 -98 -99 -100 -101 -102 -103 -104 -105 -106 -107 -108 -109 -110 -111 -112 -113 -114 -115 -116 -117 -118 -119 -120 -121 -122 -123  -1x -  -1x -  -  -  -  -  -  -  -  -  -1x -  -  -  -1x -  -  -  -1x -  -  -  -1x -  -  -  -1x -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -1x -  -  -  -  -  -  -20x -20x -20x -20x -  -  -  -  -  -  -  -  -  -21x -21x -  -  -21x -20x -20x -20x -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -640x -17x -  -623x -  -  -  -  -  -  -  -79x -  -  -  -  -  -  -  -74x -  -  -  -  -  -  -  -91x -  -  -  - 
// tslint:disable-next-line:no-var-requires
-const debug = require("debug").debug("Command");
- 
-import Client, {
-    CommandAlreadyExecutedError,
-} from "../client";
- 
-/**
- * The potential states that a command can have.
- * When a command is created, the state is "initial"
- * When the execution has started, the status is "running"
- * When the execution has finsihed, the status can be "succes" or "failed"
- */
-export enum CommandStatus {
-    /**
-     * When a command is created, the state is "initial"
-     */
-    initial = "initial",
-    /**
-     * When the execution has started, the status is "running"
-     */
-    running = "running",
-    /**
-     * After successful  execution of the command, the status is "success"
-     */
-    success = "success",
-    /**
-     * After unsuccessfull execution of the command, the status is "failed"
-     */
-    failed = "failed",
-}
- 
-/**
- * when the command has finished, the client can get the result of the command execution
- */
-export interface CommandResultMetaData {
-    errors: string[],
-    messages: string[],
-    timeElapsed: number,
-}
- 
-/**
- * The command class represents a potential long running activity.
- * This activity has been wrapped into an object to ease the tracking of the processing state.
- * Create a command with  receiver information, execute the command and check the status and progress.
- * Check the result when finsished.
- */
-export default abstract class Command {
-    protected client: Client;
-    protected status: CommandStatus;
-    protected percentCompleted: number;
-    protected resultMetaData: CommandResultMetaData;
- 
-    constructor(client: Client) {
-        this.client = client;
-        this.status = CommandStatus.initial;
-        this.percentCompleted = 0;
-        this.resultMetaData = { messages: [], errors: [], timeElapsed: 0 };
-    }
- 
-    /**
-     * final execute the command
-     * @async
-     * @final
-     * @returns {Promise<void>}
-     */
-    public async execute(): Promise<void> {
-        debug("execute Command = " + this.constructor.name, this.status);
-        Iif (this.isFinished()) {
-            throw new CommandAlreadyExecutedError("Error: Command has already been executed. Command = " + this.constructor.name);
-        }
-        if (this.status === CommandStatus.initial) {
-            const startTime = new Date();
-            await this.onExecute();
-            this.resultMetaData.timeElapsed = new Date().getTime() - startTime.getTime();
-        }
-        // do nothing if already running
-    }
- 
-    /**
-     * execute the command
-     * @async
-     * @returns {Promise<void>}
-     */
-    protected abstract async onExecute(): Promise<void>;
- 
-    /**
-     * returns true, if the command has been finished
-     * @returns {boolean}
-     */
-    public isFinished(): boolean {
-        if (this.status === CommandStatus.failed || this.status === CommandStatus.success) {
-            return true;
-        }
-        return false;
-    }
- 
-    /**
-     * returns the status of the command
-     * @returns {CommandStatus}
-     */
-    public getStatus(): CommandStatus {
-        return this.status;
-    }
- 
-    /**
-     * returns the completion percentage of the command
-     * @returns {number} percentage of completion
-     */
-    public getPercentCompleted(): number {
-        return this.percentCompleted;
-    }
- 
-    /**
-     * returns the result meta data of the command
-     * @returns {null|any} the result of the command
-     */
-    public getResultMetaData(): CommandResultMetaData {
-        return this.resultMetaData;
-    }
- 
-}
- 
- -
-
- - - - - - - - - \ No newline at end of file diff --git a/docs/coverage/src/command/downloadFolderCommand.ts.html b/docs/coverage/src/command/downloadFolderCommand.ts.html deleted file mode 100644 index 777bbff3..00000000 --- a/docs/coverage/src/command/downloadFolderCommand.ts.html +++ /dev/null @@ -1,428 +0,0 @@ - - - - - - Code coverage report for src/command/downloadFolderCommand.ts - - - - - - - - - -
-
-

All files / src/command downloadFolderCommand.ts

-
- -
- 76.09% - Statements - 35/46 -
- - -
- 50% - Branches - 1/2 -
- - -
- 100% - Functions - 6/6 -
- - -
- 74.42% - Lines - 32/43 -
- - -
-

- Press n or j to go to the next uncovered block, b, p or k for the previous block. -

-
-
-

-
1 -2 -3 -4 -5 -6 -7 -8 -9 -10 -11 -12 -13 -14 -15 -16 -17 -18 -19 -20 -21 -22 -23 -24 -25 -26 -27 -28 -29 -30 -31 -32 -33 -34 -35 -36 -37 -38 -39 -40 -41 -42 -43 -44 -45 -46 -47 -48 -49 -50 -51 -52 -53 -54 -55 -56 -57 -58 -59 -60 -61 -62 -63 -64 -65 -66 -67 -68 -69 -70 -71 -72 -73 -74 -75 -76 -77 -78 -79 -80 -81 -82 -83 -84 -85 -86 -87 -88 -89 -90 -91 -92 -93 -94 -95 -96 -97 -98 -99 -100 -101 -102 -103 -104 -105 -106 -107 -108 -109 -110 -111 -112 -113 -114 -115 -116 -117  -1x -  -1x -  -  -  -  -  -  -  -1x -1x -1x -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -1x -  -  -  -  -  -  -  -  -  -  -1x -1x -1x -1x -1x -  -  -  -  -  -  -  -  -1x -1x -1x -1x -  -  -  -  -1x -  -1x -  -  -1x -  -4x -4x -  -1x -1x -  -1x -1x -1x -  -  -1x -  -  -  -  -  -  -  -  -1x -  -  -  -  -  -1x -1x -  -  -1x -  -1x -  -  -  -1x -  -  -  - 
// tslint:disable-next-line:no-var-requires
-const debug = require("debug").debug("DownloadFilesCommand");
- 
-import Client,
-{
-    File,
-    Folder,
-    SourceTargetFileNames,
-    CommandStatus,
-    GetFilesRecursivelyCommand,
-} from "../client";
-import util from "util";
-import fs from "fs";
-import Command from "./command";
-/**
- * options to create a download folder command
- */
-export interface DownloadFolderCommandOptions {
-    /**
-     * The source folder with the file structure to be downloaded
-     */
-    sourceFolder: Folder;
-    /**
-     * function to filter files
-     */
-    filterFile?: (file: File) => File | null;
-    /**
-     * the function to determine the target file name having the sourece file name.
-     * If the file should not be downloaded, return an empty string
-     * @param {SourceTargetFileNames} fileNames source and target file names
-     */
-    getTargetFileNameBeforeDownload: (fileNames: SourceTargetFileNames) => string;
-}
- 
-/**
- * Command to download the contents of a folder from nextcloud to local file system recursively
- */
-export default class DownloadFolderCommand extends Command {
-    private sourceFolder: Folder;
-    private getTargetFileNameBeforeDownload: (fileNames: SourceTargetFileNames) => string;
-    private bytesDownloaded: number;
-    private filterFile?: (file: File) => File | null;
- 
-    /**
-     * @param {Client} client the client
-     * @param {DownloadFolderCommandOptions} options constructor options
-     */
-    constructor(client: Client, options: DownloadFolderCommandOptions) {
-        super(client);
-        this.sourceFolder = options.sourceFolder;
-        this.getTargetFileNameBeforeDownload = options.getTargetFileNameBeforeDownload;
-        this.filterFile = options.filterFile;
-        this.bytesDownloaded = 0;
-    }
- 
-    /**
-     * execute the command
-     * @async
-     * @returns {Promise<void>}
-     */
-    protected async onExecute(): Promise<void> {
-        this.status = CommandStatus.running;
-        const writeFile = util.promisify(fs.writeFile);
-        const mkdir = util.promisify(fs.mkdir);
-        try {
- 
-            // determine all files to download
-            // it is assumed that this command will use 20% of the time
-            const command: GetFilesRecursivelyCommand =
-                new GetFilesRecursivelyCommand(this.client,
-                    { sourceFolder: this.sourceFolder, filterFile: this.filterFile });
-            command.execute();
- 
-            // check the processing status as long as the command is running
-            while (command.isFinished() !== true) {
-                // wait a bit
-                this.percentCompleted = command.getPercentCompleted() / 5;  // 20%
-                await (async () => { return new Promise(resolve => setTimeout(resolve, 100)) })();
-            }
-            this.resultMetaData.messages.concat(command.getResultMetaData().messages);
-            this.resultMetaData.errors.concat(command.getResultMetaData().errors);
- 
-            const files: File[] = command.getFiles();
-            let bytesToDownload: number = 0;
-            for (const file of files) {
-                bytesToDownload += file.size;
-            }
-            for (const file of files) {
-                const targetFileName = this.getTargetFileNameBeforeDownload({ sourceFileName: file.name, targetFileName: "." + file.name });
-                const content: Buffer = await file.getContent();
-                const path: string = targetFileName.substring(0, targetFileName.lastIndexOf("/"));
-                await mkdir(path, { recursive: true });
-                await writeFile(targetFileName, content);
-                this.bytesDownloaded += file.size;
-                this.percentCompleted = (this.bytesDownloaded / bytesToDownload * 80) + 20;
-            }
-            this.resultMetaData.messages.push(files.length + " files downloaded");
- 
-        } catch (e) {
-            debug(e.message);
-            this.resultMetaData.errors.push(e.message);
-        }
-        this.percentCompleted = 100;
-        Iif (this.resultMetaData.errors.length > 0) {
-            this.status = CommandStatus.failed;
-        } else {
-            this.status = CommandStatus.success;
-        }
-        return;
-    };
- 
-    public getBytesDownloaded(): number {
-        return this.bytesDownloaded;
-    }
- 
-}
- 
- -
-
- - - - - - - - - \ No newline at end of file diff --git a/docs/coverage/src/command/getFilesRecursivelyCommand.ts.html b/docs/coverage/src/command/getFilesRecursivelyCommand.ts.html deleted file mode 100644 index 877bf5ad..00000000 --- a/docs/coverage/src/command/getFilesRecursivelyCommand.ts.html +++ /dev/null @@ -1,368 +0,0 @@ - - - - - - Code coverage report for src/command/getFilesRecursivelyCommand.ts - - - - - - - - - -
-
-

All files / src/command getFilesRecursivelyCommand.ts

-
- -
- 93.75% - Statements - 30/32 -
- - -
- 75% - Branches - 3/4 -
- - -
- 100% - Functions - 4/4 -
- - -
- 93.75% - Lines - 30/32 -
- - -
-

- Press n or j to go to the next uncovered block, b, p or k for the previous block. -

-
-
-

-
1 -2 -3 -4 -5 -6 -7 -8 -9 -10 -11 -12 -13 -14 -15 -16 -17 -18 -19 -20 -21 -22 -23 -24 -25 -26 -27 -28 -29 -30 -31 -32 -33 -34 -35 -36 -37 -38 -39 -40 -41 -42 -43 -44 -45 -46 -47 -48 -49 -50 -51 -52 -53 -54 -55 -56 -57 -58 -59 -60 -61 -62 -63 -64 -65 -66 -67 -68 -69 -70 -71 -72 -73 -74 -75 -76 -77 -78 -79 -80 -81 -82 -83 -84 -85 -86 -87 -88 -89 -90 -91 -92 -93 -94 -95 -96 -97  -1x -  -  -1x -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -1x -  -  -  -  -  -  -  -  -  -  -3x -3x -3x -3x -  -  -  -  -  -  -  -  -3x -3x -3x -3x -3x -  -2x -  -1x -1x -  -  -3x -3x -1x -  -2x -  -3x -3x -  -  -  -  -2x -  -  -  -  -  -  -  -  -  -  -  -3x -3x -2x -  -  -  -2x -2x -2x -  -2x -  -  -  -2x -  -  - 
// tslint:disable-next-line:no-var-requires
-const debug = require("debug").debug("GetFilesRecursivelyCommand");
- 
-import Client, { File, Folder, FolderGetFilesOptions } from "../client";
-import Command, { CommandStatus } from "./command";
- 
-export interface GetFilesRecursivelyCommandOptions {
-    /**
-     * the source nextcloud folder to start listing the files
-     */
-    sourceFolder: Folder;
-    /**
-     * function to filter files
-     */
-    filterFile?: (file: File) => File | null;
-}
- 
-/**
- * Command to get all files of a nextcloud folder recursively
- */
-export default class GetFilesRecursivelyCommand extends Command {
-    private sourceFolder: Folder;
-    private filterFile?: (file: File) => File | null;
-    private files: File[];
- 
-    /**
-     * @param {Client} client the client
-     * @param {SourceTargetFileNames[]} files the files to be uploaded
-     * @param {(file: File) => void} processAfterUpload callback function to process the uploaded file
-     */
-    constructor(client: Client, options: GetFilesRecursivelyCommandOptions) {
-        super(client);
-        this.sourceFolder = options.sourceFolder;
-        this.filterFile = options.filterFile;
-        this.files = [];
-    }
- 
-    /**
-     * execute the command
-     * @async
-     * @returns {Promise<void>}
-     */
-    protected async onExecute(): Promise<void> {
-        this.status = CommandStatus.running;
-        const startTime = new Date();
-        try {
-            this.percentCompleted = 0;
-            await this.processFolder(this.sourceFolder, 100);
-            // console.log("file count", this.files.length);
-            this.resultMetaData.messages.push(`${this.files.length} files found`);
-        } catch (e) {
-            debug(e.message);
-            this.resultMetaData.errors.push(e.message);
-        }
- 
-        this.percentCompleted = 100;
-        if (this.resultMetaData.errors.length > 0) {
-            this.status = CommandStatus.failed;
-        } else {
-            this.status = CommandStatus.success;
-        }
-        this.resultMetaData.timeElapsed = new Date().getTime() - startTime.getTime();
-        return;
-    };
- 
- 
-    public getFiles(): File[] {
-        return this.files;
-    }
- 
-    /**
-     * adds files of folder and processes subordinated folders
-     * @param {Folder} folder the folder to process
-     * @param {number} percentagethe percentage that is finished, when the function returns
-     */
-    private async processFolder(folder: Folder, percentage: number): Promise<void> {
-        // tslint:disable-next-line:no-console
-        // console.log(folder.name);
- 
-        const options: FolderGetFilesOptions = { filterFile: this.filterFile }
-        const folderFiles: File[] = await folder.getFiles(options);
-        for (const fi of folderFiles) {
-            this.files.push(fi);
-        }
- 
-        const subFolders: Folder[] = await folder.getSubFolders();
-        Eif (subFolders.length === 0) {
-            this.percentCompleted += percentage;
-        }
-        for (const subFolder of subFolders) {
-            // console.log("folder", subFolder.name);
-            await this.processFolder(subFolder, percentage / subFolders.length);
-        }
-        return;
-    }
-}
- 
- -
-
- - - - - - - - - \ No newline at end of file diff --git a/docs/coverage/src/command/index.html b/docs/coverage/src/command/index.html deleted file mode 100644 index b60acb85..00000000 --- a/docs/coverage/src/command/index.html +++ /dev/null @@ -1,171 +0,0 @@ - - - - - - Code coverage report for src/command - - - - - - - - - -
-
-

All files src/command

-
- -
- 92.11% - Statements - 175/190 -
- - -
- 89.29% - Branches - 25/28 -
- - -
- 96.3% - Functions - 26/27 -
- - -
- 91.8% - Lines - 168/183 -
- - -
-

- Press n or j to go to the next uncovered block, b, p or k for the previous block. -

-
-
-
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
FileStatementsBranchesFunctionsLines
command.ts -
-
96%24/2590%9/10100%7/796%24/25
downloadFolderCommand.ts -
-
76.09%35/4650%1/2100%6/674.42%32/43
getFilesRecursivelyCommand.ts -
-
93.75%30/3275%3/4100%4/493.75%30/32
uploadFilesCommand.ts -
-
100%41/41100%8/8100%3/3100%41/41
uploadFolderCommand.ts -
-
97.83%45/46100%4/485.71%6/797.62%41/42
-
-
-
- - - - - - - - - \ No newline at end of file diff --git a/docs/coverage/src/command/uploadFilesCommand.ts.html b/docs/coverage/src/command/uploadFilesCommand.ts.html deleted file mode 100644 index cd91fcae..00000000 --- a/docs/coverage/src/command/uploadFilesCommand.ts.html +++ /dev/null @@ -1,389 +0,0 @@ - - - - - - Code coverage report for src/command/uploadFilesCommand.ts - - - - - - - - - -
-
-

All files / src/command uploadFilesCommand.ts

-
- -
- 100% - Statements - 41/41 -
- - -
- 100% - Branches - 8/8 -
- - -
- 100% - Functions - 3/3 -
- - -
- 100% - Lines - 41/41 -
- - -
-

- Press n or j to go to the next uncovered block, b, p or k for the previous block. -

-
-
-

-
1 -2 -3 -4 -5 -6 -7 -8 -9 -10 -11 -12 -13 -14 -15 -16 -17 -18 -19 -20 -21 -22 -23 -24 -25 -26 -27 -28 -29 -30 -31 -32 -33 -34 -35 -36 -37 -38 -39 -40 -41 -42 -43 -44 -45 -46 -47 -48 -49 -50 -51 -52 -53 -54 -55 -56 -57 -58 -59 -60 -61 -62 -63 -64 -65 -66 -67 -68 -69 -70 -71 -72 -73 -74 -75 -76 -77 -78 -79 -80 -81 -82 -83 -84 -85 -86 -87 -88 -89 -90 -91 -92 -93 -94 -95 -96 -97 -98 -99 -100 -101 -102 -103 -104  -1x -  -  -1x -1x -1x -  -  -  -  -  -  -  -  -  -  -  -  -  -  -1x -  -  -  -  -  -  -  -  -  -  -10x -10x -10x -10x -  -  -  -  -  -  -  -  -10x -10x -10x -10x -  -10x -10x -1x -  -  -  -  -10x -  -74x -74x -74x -73x -73x -30x -30x -  -43x -43x -  -  -1x -  -  -74x -74x -74x -  -74x -2x -  -  -  -  -1x -1x -1x -  -10x -8x -  -2x -  -  -10x -  -10x -  -  -  -70x -  -  -  - 
// tslint:disable-next-line:no-var-requires
-const debug = require("debug").debug("UploadFilesCommand");
- 
-import Client, { File } from "../client";
-import Command, { CommandStatus } from "./command";
-import util from "util";
-import fs from "fs";
- 
-export interface SourceTargetFileNames {
-    sourceFileName: string;
-    targetFileName: string;
-}
- 
-export interface UploadFilesCommandOptions {
-    files: SourceTargetFileNames[];
-    processFileAfterUpload?: (file: File) => Promise<void>;
-}
- 
-/**
- * Command to upload a set or files from local file system to nextcloud
- */
-export default class UploadFilesCommand extends Command {
-    private files: SourceTargetFileNames[];
-    private processFileAfterUpload?: (file: File) => Promise<void>;
-    private bytesUploaded: number;
- 
-    /**
-     * @param {Client} client the client
-     * @param {SourceTargetFileNames[]} files the files to be uploaded
-     * @param {(file: File) => void} processAfterUpload callback function to process the uploaded file
-     */
-    constructor(client: Client, options: UploadFilesCommandOptions) {
-        super(client);
-        this.files = options.files;
-        this.bytesUploaded = 0;
-        this.processFileAfterUpload = options.processFileAfterUpload;
-    }
- 
-    /**
-     * execute the command
-     * @async
-     * @returns {Promise<void>}
-     */
-    protected async onExecute(): Promise<void> {
-        this.status = CommandStatus.running;
-        try {
-            const readfile = util.promisify(fs.readFile);
-            let countCompleted = 0;
- 
-            this.percentCompleted = 0;
-            if (this.files.length === 0) {
-                this.percentCompleted = 100;
-            }
- 
-            let newFile: File | null;
- 
-            for (const file of this.files) {
-                let data: Buffer;
-                newFile = null;
-                try {
-                    data = await readfile(file.sourceFileName);
-                    try {
-                        newFile = await this.client.createFile(file.targetFileName, data);
-                        this.resultMetaData.messages.push(`${file.targetFileName}`);
-                        this.bytesUploaded += data.length;
-                    } catch (e) {
-                        this.resultMetaData.errors.push(`${file.targetFileName}: ${e.message}`);
-                        debug(file.targetFileName, e);
-                    }
-                } catch (e) {
-                    this.resultMetaData.errors.push(`${file.targetFileName}: ${e.message}`);
-                }
- 
-                countCompleted++;
-                this.percentCompleted = Math.round(countCompleted / this.files.length * 100);
-                debug(" completed:" + this.percentCompleted + "%");
- 
-                if (newFile && this.processFileAfterUpload) {
-                    await this.processFileAfterUpload(newFile);
-                }
-            }
- 
-        } catch (e) {
-            debug(e.message);
-            this.resultMetaData.errors.push(e.message);
-            this.percentCompleted = 100;
-        }
-        if (this.resultMetaData.errors.length > 0) {
-            this.status = CommandStatus.failed;
-        } else {
-            this.status = CommandStatus.success;
-        }
- 
-        debug("execute finished", this.percentCompleted, this.status);
- 
-        return;
-    };
- 
-    public getBytesUploaded(): number {
-        return this.bytesUploaded;
-    }
- 
-}
- 
- -
-
- - - - - - - - - \ No newline at end of file diff --git a/docs/coverage/src/command/uploadFolderCommand.ts.html b/docs/coverage/src/command/uploadFolderCommand.ts.html deleted file mode 100644 index 5a943605..00000000 --- a/docs/coverage/src/command/uploadFolderCommand.ts.html +++ /dev/null @@ -1,413 +0,0 @@ - - - - - - Code coverage report for src/command/uploadFolderCommand.ts - - - - - - - - - -
-
-

All files / src/command uploadFolderCommand.ts

-
- -
- 97.83% - Statements - 45/46 -
- - -
- 100% - Branches - 4/4 -
- - -
- 85.71% - Functions - 6/7 -
- - -
- 97.62% - Lines - 41/42 -
- - -
-

- Press n or j to go to the next uncovered block, b, p or k for the previous block. -

-
-
-

-
1 -2 -3 -4 -5 -6 -7 -8 -9 -10 -11 -12 -13 -14 -15 -16 -17 -18 -19 -20 -21 -22 -23 -24 -25 -26 -27 -28 -29 -30 -31 -32 -33 -34 -35 -36 -37 -38 -39 -40 -41 -42 -43 -44 -45 -46 -47 -48 -49 -50 -51 -52 -53 -54 -55 -56 -57 -58 -59 -60 -61 -62 -63 -64 -65 -66 -67 -68 -69 -70 -71 -72 -73 -74 -75 -76 -77 -78 -79 -80 -81 -82 -83 -84 -85 -86 -87 -88 -89 -90 -91 -92 -93 -94 -95 -96 -97 -98 -99 -100 -101 -102 -103 -104 -105 -106 -107 -108 -109 -110 -111 -112  -1x -  -1x -  -  -  -  -  -  -  -  -1x -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -1x -  -  -  -  -  -  -  -  -  -  -  -6x -6x -6x -6x -4x -  -14x -  -6x -  -  -  -  -  -  -  -  -6x -6x -6x -6x -6x -  -1x -1x -1x -1x -1x -1x -  -  -5x -5x -70x -  -70x -56x -  -  -  -5x -5x -5x -  -  -5x -65x -65x -65x -65x -  -65x -  -  -5x -5x -5x -5x -5x -  -  -  -  -  -  - 
// tslint:disable-next-line:no-var-requires
-const debug = require("debug").debug("UploadFolderCommand");
- 
-import Client,
-{
-    File,
-    FileSystemFolder,
-    IFileNameFormats,
-    UploadFilesCommand,
-    UploadFilesCommandOptions,
-    SourceTargetFileNames,
-} from "../client";
-import Command, { CommandStatus } from "./command";
- 
-/**
- * options to create a upload folder command
- */
-export interface UploadFolderCommandOptions {
-    /**
-     * The name of the source folder with the file structure to be uploaded
-     */
-    folderName: string;
-    /**
-     * the function to determine the target file name having the sourece file name.
-     * If the file should not be uploaded, return an empty string
-     * @param {SourceTargetFileNames} fileNames
-     */
-    getTargetFileNameBeforeUpload?: (fileNames: SourceTargetFileNames) => string;
-    processFileAfterUpload?: (file: File) => Promise<void>;
-}
- 
-/**
- * Command to upload the contents of a folder from local file system to nextcloud recursively
- */
-export default class UploadFolderCommand extends Command {
-    private folderName: string;
-    private processFileAfterUpload?: (file: File) => Promise<void>;
-    private getTargetFileNameBeforeUpload: (fileNames: SourceTargetFileNames) => string;
-    private bytesUploaded: number;
- 
-    /**
-     * @param {Client} client the client
-     * @param {ISourceTargetFileNames[]} files the files to be uploaded
-     * @param {(file: File) => void} processAfterUpload callback function to process the uploaded file
-     */
-    constructor(client: Client, options: UploadFolderCommandOptions) {
-        super(client);
-        this.folderName = options.folderName;
-        this.processFileAfterUpload = options.processFileAfterUpload;
-        if (options.getTargetFileNameBeforeUpload) {
-            this.getTargetFileNameBeforeUpload = options.getTargetFileNameBeforeUpload;
-        } else {
-            this.getTargetFileNameBeforeUpload = (fileNames: SourceTargetFileNames): string => { return fileNames.targetFileName };
-        }
-        this.bytesUploaded = 0;
-    }
- 
-    /**
-     * execute the command
-     * @async
-     * @returns {Promise<void>}
-     */
-    protected async onExecute(): Promise<void> {
-        this.status = CommandStatus.running;
-        let fileNames: IFileNameFormats[] = [];
-        const fsf: FileSystemFolder = new FileSystemFolder(this.folderName);
-        try {
-            fileNames = await fsf.getFileNames();
-        } catch (e) {
-            this.resultMetaData.errors.push(e);
-            this.status = CommandStatus.failed;
-            this.percentCompleted = 100;
-            this.bytesUploaded = 0;
-            this.resultMetaData.timeElapsed = 0;
-            return;
-        }
- 
-        const files: SourceTargetFileNames[] = [];
-        for (const fileNameFormat of fileNames) {
-            const targetFileName = this.getTargetFileNameBeforeUpload({ sourceFileName: fileNameFormat.absolute, targetFileName: fileNameFormat.relative });
-            // add only files with a target name
-            if (targetFileName !== "") {
-                files.push({ sourceFileName: fileNameFormat.absolute, targetFileName });
-            }
-        }
- 
-        const options: UploadFilesCommandOptions = { files, processFileAfterUpload: this.processFileAfterUpload };
-        const uc: UploadFilesCommand = new UploadFilesCommand(this.client, options);
-        uc.execute();
- 
-        // check the processing status
-        while (uc.isFinished() !== true) {
-            this.status = uc.getStatus();
-            this.percentCompleted = uc.getPercentCompleted();
-            this.resultMetaData = uc.getResultMetaData();
-            this.bytesUploaded = uc.getBytesUploaded();
-            // wait one second
-            await (async () => { return new Promise(resolve => setTimeout(resolve, 1000)) })();
-        }
- 
-        this.status = uc.getStatus();
-        this.percentCompleted = uc.getPercentCompleted();
-        this.resultMetaData = uc.getResultMetaData();
-        this.bytesUploaded = uc.getBytesUploaded();
-        return;
-    };
-    public getBytesUploaded(): number {
-        return this.bytesUploaded;
-    }
- 
-}
- 
- -
-
- - - - - - - - - \ No newline at end of file diff --git a/docs/coverage/src/environment.ts.html b/docs/coverage/src/environment.ts.html deleted file mode 100644 index c03ff06b..00000000 --- a/docs/coverage/src/environment.ts.html +++ /dev/null @@ -1,206 +0,0 @@ - - - - - - Code coverage report for src/environment.ts - - - - - - - - - -
-
-

All files / src environment.ts

-
- -
- 100% - Statements - 15/15 -
- - -
- 100% - Branches - 15/15 -
- - -
- 100% - Functions - 5/5 -
- - -
- 100% - Lines - 15/15 -
- - -
-

- Press n or j to go to the next uncovered block, b, p or k for the previous block. -

-
-
-

-
1 -2 -3 -4 -5 -6 -7 -8 -9 -10 -11 -12 -13 -14 -15 -16 -17 -18 -19 -20 -21 -22 -23 -24 -25 -26 -27 -28 -29 -30 -31 -32 -33 -34 -35 -36 -37 -38 -39 -40 -41 -42 -431x -  -1x -  -  -17x -  -  -  -172x -2x -  -  -170x -  -  -  -171x -1x -  -  -170x -  -  -  -171x -1x -  -  -170x -  -  -  -169x -  -  -168x -  -1x -  -  -  - 
import ClientError from "./error";
- 
-export default class Environment {
- 
-    public static getMinLogLevel(): string {
-        return process.env.MIN_LOG_LEVEL || "error";
-    }
- 
-    public static getNextcloudUrl(): string {
-        if (!process.env.NEXTCLOUD_URL) {
-            throw new ClientError("NCEnvironment: NEXTCLOUD_URL not defined in environment"
-                , "ERR_NEXTCLOUD_URL_NOT_DEFINED");
-        }
-        return process.env.NEXTCLOUD_URL;
-    }
- 
-    public static getUserName(): string {
-        if (!process.env.NEXTCLOUD_USERNAME) {
-            throw new ClientError("NCEnvironment: NEXTCLOUD_USERNAME not defined in environment"
-                , "ERR_NEXTCLOUD_USERNAME_NOT_DEFINED");
-        }
-        return process.env.NEXTCLOUD_USERNAME;
-    }
- 
-    public static getPassword(): string {
-        if (!process.env.NEXTCLOUD_PASSWORD) {
-            throw new ClientError("NCEnvironment: NEXTCLOUD_PASSWORD not defined in environment"
-                , "ERR_NEXTCLOUD_PASSWORD_NOT_DEFINED");
-        }
-        return process.env.NEXTCLOUD_PASSWORD;
-    }
- 
-    public static getRecordingActiveIndicator(): boolean {
-        if ((process.env.TEST_RECORDING_ACTIVE &&
-            (process.env.TEST_RECORDING_ACTIVE === "0" || process.env.TEST_RECORDING_ACTIVE === "false" || process.env.TEST_RECORDING_ACTIVE === "inactive")) ||
-            !process.env.TEST_RECORDING_ACTIVE) {
-            return false;
-        } else {
-            return true;
-        }
-    }
-}
- 
- -
-
- - - - - - - - - \ No newline at end of file diff --git a/docs/coverage/src/environmentVcapServices.ts.html b/docs/coverage/src/environmentVcapServices.ts.html deleted file mode 100644 index c26abfa3..00000000 --- a/docs/coverage/src/environmentVcapServices.ts.html +++ /dev/null @@ -1,302 +0,0 @@ - - - - - - Code coverage report for src/environmentVcapServices.ts - - - - - - - - - -
-
-

All files / src environmentVcapServices.ts

-
- -
- 100% - Statements - 24/24 -
- - -
- 100% - Branches - 15/15 -
- - -
- 100% - Functions - 2/2 -
- - -
- 100% - Lines - 24/24 -
- - -
-

- Press n or j to go to the next uncovered block, b, p or k for the previous block. -

-
-
-

-
1 -2 -3 -4 -5 -6 -7 -8 -9 -10 -11 -12 -13 -14 -15 -16 -17 -18 -19 -20 -21 -22 -23 -24 -25 -26 -27 -28 -29 -30 -31 -32 -33 -34 -35 -36 -37 -38 -39 -40 -41 -42 -43 -44 -45 -46 -47 -48 -49 -50 -51 -52 -53 -54 -55 -56 -57 -58 -59 -60 -61 -62 -63 -64 -65 -66 -67 -68 -69 -70 -71 -72 -73 -74 -75  -1x -  -1x -1x -1x -  -1x -1x -  -  -  -  -  -  -  -1x -  -  -  -  -  -  -12x -2x -  -  -10x -10x -  -10x -5x -5x -  -  -5x -1x -  -  -  -  -4x -1x -  -  -  -  -3x -1x -  -  -  -  -2x -2x -2x -  -  -  -  -  -  -  -  -  -2x -  -  -  -  -  -  -  -  - 
// tslint:disable-next-line:no-var-requires
-require("dotenv").config();
- 
-import ClientError from "./error";
-import Server from "./server";
-export { Server };
- 
-import Logger from "./logger";
-const log: Logger = new Logger();
- 
- 
-/**
- * returns the nextcloud credentials that is defined in the
- * "user-provided" service section of the VCAP_SERVICES environment
- * instanceName: the name of the nextcloud user provided service instance
- */
-export default class EnvironmentVcapServices {
-    public readonly url: string;
-    public readonly userName: string;
-    public readonly password: string;
- 
-    public constructor(instanceName: string) {
- 
-        if (!process.env.VCAP_SERVICES) {
-            throw new ClientError("NCEnvironmentVcapServices: environment VCAP_SERVICES not found", "ERR_VCAP_SERVICES_NOT_FOUND");
-        }
- 
-        const vcapServices = require("vcap_services");
-        const cred = vcapServices.getCredentials("user-provided", undefined, instanceName);
- 
-        if (!cred || cred === undefined || (!cred.url && !cred.username && !cred.password)) {
-            log.error("NCEnvironmentVcapServices: error credentials not found or not fully specified ", cred);
-            throw new ClientError(`NCEnvironmentVcapServices: nextcloud credentials not found in environment VCAP_SERVICES. Service section: "user-provided", service instance name: "${instanceName}" `, "ERR_VCAP_SERVICES_NOT_FOUND");
-        }
- 
-        if (!cred.url) {
-            throw new ClientError("NCEnvironmentVcapServices: VCAP_SERVICES url not defined in user provided services for nextcloud"
-                , "ERR_VCAP_SERVICES_URL_NOT_DEFINED",
-                { credentials: cred });
-        }
- 
-        if (!cred.password) {
-            throw new ClientError("NCEnvironmentVcapServices: VCAP_SERVICES password not defined in user provided services for nextcloud",
-                "ERR_VCAP_SERVICES_PASSWORD_NOT_DEFINED",
-                { credentials: cred });
-        }
- 
-        if (!cred.username) {
-            throw new ClientError("NCEnvironmentVcapServices: VCAP_SERVICES username not defined in user provided services for nextcloud",
-                "ERR_VCAP_SERVICES_USERNAME_NOT_DEFINED",
-                { credentials: cred });
-        }
- 
-        this.url = cred.url as string;
-        this.userName = cred.username as string;
-        this.password = cred.password as string;
-    }
- 
-    /**
-     * returns the nextcloud credentials that is defined in the
-     * "user-provided" service section of the VCAP_SERVICES environment
-     * @param instanceName the name of the nextcloud user provided service instance
-     * @returns credentials from the VCAP_SERVICES environment (user provided service)
-     */
-    public getServer(): Server {
-        return new Server({
-            basicAuth: {
-                password: this.password,
-                username: this.userName,
-            },
-            url: this.url,
-        });
-    }
-}
- 
- -
-
- - - - - - - - - \ No newline at end of file diff --git a/docs/coverage/src/error.ts.html b/docs/coverage/src/error.ts.html deleted file mode 100644 index d864e539..00000000 --- a/docs/coverage/src/error.ts.html +++ /dev/null @@ -1,353 +0,0 @@ - - - - - - Code coverage report for src/error.ts - - - - - - - - - -
-
-

All files / src error.ts

-
- -
- 100% - Statements - 21/21 -
- - -
- 100% - Branches - 0/0 -
- - -
- 100% - Functions - 2/2 -
- - -
- 100% - Lines - 21/21 -
- - -
-

- Press n or j to go to the next uncovered block, b, p or k for the previous block. -

-
-
-

-
1 -2 -3 -4 -5 -6 -7 -8 -9 -10 -11 -12 -13 -14 -15 -16 -17 -18 -19 -20 -21 -22 -23 -24 -25 -26 -27 -28 -29 -30 -31 -32 -33 -34 -35 -36 -37 -38 -39 -40 -41 -42 -43 -44 -45 -46 -47 -48 -49 -50 -51 -52 -53 -54 -55 -56 -57 -58 -59 -60 -61 -62 -63 -64 -65 -66 -67 -68 -69 -70 -71 -72 -73 -74 -75 -76 -77 -78 -79 -80 -81 -82 -83 -84 -85 -86 -87 -88 -89 -90 -91 -92  -1x -  -  -  -  -306x -306x -306x -  -  -  -  -1x -  -  -  -92x -92x -  -  -  -  -  -  -  -1x -  -  -  -  -1x -  -  -  -  -1x -  -  -  -  -1x -  -  -  -  -1x -  -  -  -  -1x -  -  -  -  -1x -  -  -  -  -1x -  -  -  -  -1x -  -  -  -  -1x -  -  -  -  -1x -  -  -  -  -1x -  -  -  -  -1x -  -  -  -  -1x
// tslint:disable:max-classes-per-file
-export default class ClientError extends Error {
-    public code: string;
-    private context?: any;
- 
-    constructor(m: string, code: string, context?: any) {
-        super(m);
-        this.code = code;
-        this.context = context;
-    }
-}
- 
-// tslint:disable-next-line:max-classes-per-file
-export class BaseError extends Error {
-    private context?: any;
- 
-    constructor(m: string, context?: any) {
-        super(m);
-        this.context = context;
-    }
-}
- 
- 
-/**
- * the query limit parameter must be a number larger than 0
- */
-export class QueryLimitError extends BaseError { };
- 
-/**
- * the query offset parameter must be a number larger than 0
- */
-export class QueryOffsetError extends BaseError { };
- 
-/**
- * user group already exists
- */
-export class UserGroupAlreadyExistsError extends BaseError { };
- 
-/**
- * user group does not exist
- */
-export class UserGroupDoesNotExistError extends BaseError { };
- 
-/**
- * user group cloud not be deleted
- */
-export class UserGroupDeletionFailedError extends BaseError { };
- 
-/**
- * user not found
- */
-export class UserNotFoundError extends BaseError { };
- 
-/**
- * user already exists
- */
-export class UserAlreadyExistsError extends BaseError { };
- 
-/**
- * error creating user
- */
-export class UserCreateError extends BaseError { };
- 
-/**
- * error updating user
- */
-export class UserUpdateError extends BaseError { };
- 
-/**
- * Error sending user welcome email
- */
-export class UserResendWelcomeEmailError extends BaseError { };
- 
-/**
- * the service response is invalid
- */
-export class InvalidServiceResponseFormatError extends BaseError { };
- 
-/**
- * the service response is invalid
- */
-export class InsufficientPrivilegesError extends BaseError { };
- 
-/**
- * operation failed
- */
-export class OperationFailedError extends BaseError { };
- 
-/**
- * the command is already executed
- */
-export class CommandAlreadyExecutedError extends BaseError { };
- -
-
- - - - - - - - - \ No newline at end of file diff --git a/docs/coverage/src/fakeServer.ts.html b/docs/coverage/src/fakeServer.ts.html deleted file mode 100644 index 6d51bfa1..00000000 --- a/docs/coverage/src/fakeServer.ts.html +++ /dev/null @@ -1,233 +0,0 @@ - - - - - - Code coverage report for src/fakeServer.ts - - - - - - - - - -
-
-

All files / src fakeServer.ts

-
- -
- 96.3% - Statements - 26/27 -
- - -
- 90% - Branches - 9/10 -
- - -
- 100% - Functions - 2/2 -
- - -
- 96.3% - Lines - 26/27 -
- - -
-

- Press n or j to go to the next uncovered block, b, p or k for the previous block. -

-
-
-

-
1 -2 -3 -4 -5 -6 -7 -8 -9 -10 -11 -12 -13 -14 -15 -16 -17 -18 -19 -20 -21 -22 -23 -24 -25 -26 -27 -28 -29 -30 -31 -32 -33 -34 -35 -36 -37 -38 -39 -40 -41 -42 -43 -44 -45 -46 -47 -48 -49 -50 -51 -521x -  -  -  -  -  -  -1x -1x -  -1x -62x -  -62x -  -  -111x -111x -2x -  -  -111x -111x -3x -  -108x -  -  -  -108x -  -108x -106x -  -  -108x -  -  -  -108x -7x -7x -7x -7x -7x -7x -7x -  -101x -  -  - 
import {
-    RequestInit,
-    Response,
-    ResponseInit,
-} from "node-fetch";
-import { IRequestContext } from "./httpClient";
-import RequestResponseLogEntry from "./requestResponseLogEntry";
-import Logger from "./logger";
-const log: Logger = new Logger();
- 
-export default class FakeServer {
-    public fakeResponses: RequestResponseLogEntry[] = [];
-    public constructor(fakeResponses: RequestResponseLogEntry[]) {
-        this.fakeResponses = fakeResponses;
-    }
-    public async getFakeHttpResponse(url: string, requestInit: RequestInit, expectedHttpStatusCode: number[], context: IRequestContext): Promise<Response> {
-        log.debug("getFakeHttpResponse");
-        if (!requestInit.method) {
-            requestInit.method = "UNDEFINED";
-        }
- 
-        const rrEntry: RequestResponseLogEntry | undefined = this.fakeResponses.shift();
-        if (!rrEntry) {
-            throw new Error(`error providing fake http response. No fake response available`);
-        }
-        const responseInit: ResponseInit = {
-            status: rrEntry.response.status,
-        };
- 
-        const response: Response = new Response(rrEntry.response.body, responseInit);
- 
-        if (rrEntry.response.contentType) {
-            response.headers.append("Content-Type", rrEntry.response.contentType);
-        }
- 
-        Iif (rrEntry.response.contentLocation) {
-            response.headers.append("Content-Location", rrEntry.response.contentLocation);
-        }
- 
-        if (expectedHttpStatusCode.indexOf(response.status) === -1) {
-            log.debug("getHttpResponse unexpected status response ", response.status + " " + response.statusText);
-            log.debug("getHttpResponse description ", context.description);
-            log.debug("getHttpResponse expected ", expectedHttpStatusCode.join(","));
-            log.debug("getHttpResponse headers ", JSON.stringify(response.headers, null, 4));
-            log.debug("getHttpResponse request body ", requestInit.body);
-            log.debug("getHttpResponse text ", await response.text());
-            throw new Error(`HTTP response status ${response.status} not expected. Expected status: ${expectedHttpStatusCode.join(",")} - status text: ${response.statusText}`);
-        }
-        return response;
-    }
-}
- 
- -
-
- - - - - - - - - \ No newline at end of file diff --git a/docs/coverage/src/file.ts.html b/docs/coverage/src/file.ts.html deleted file mode 100644 index 4516e7ce..00000000 --- a/docs/coverage/src/file.ts.html +++ /dev/null @@ -1,728 +0,0 @@ - - - - - - Code coverage report for src/file.ts - - - - - - - - - -
-
-

All files / src file.ts

-
- -
- 78.95% - Statements - 45/57 -
- - -
- 50% - Branches - 3/6 -
- - -
- 89.47% - Functions - 17/19 -
- - -
- 78.95% - Lines - 45/57 -
- - -
-

- Press n or j to go to the next uncovered block, b, p or k for the previous block. -

-
-
-

-
1 -2 -3 -4 -5 -6 -7 -8 -9 -10 -11 -12 -13 -14 -15 -16 -17 -18 -19 -20 -21 -22 -23 -24 -25 -26 -27 -28 -29 -30 -31 -32 -33 -34 -35 -36 -37 -38 -39 -40 -41 -42 -43 -44 -45 -46 -47 -48 -49 -50 -51 -52 -53 -54 -55 -56 -57 -58 -59 -60 -61 -62 -63 -64 -65 -66 -67 -68 -69 -70 -71 -72 -73 -74 -75 -76 -77 -78 -79 -80 -81 -82 -83 -84 -85 -86 -87 -88 -89 -90 -91 -92 -93 -94 -95 -96 -97 -98 -99 -100 -101 -102 -103 -104 -105 -106 -107 -108 -109 -110 -111 -112 -113 -114 -115 -116 -117 -118 -119 -120 -121 -122 -123 -124 -125 -126 -127 -128 -129 -130 -131 -132 -133 -134 -135 -136 -137 -138 -139 -140 -141 -142 -143 -144 -145 -146 -147 -148 -149 -150 -151 -152 -153 -154 -155 -156 -157 -158 -159 -160 -161 -162 -163 -164 -165 -166 -167 -168 -169 -170 -171 -172 -173 -174 -175 -176 -177 -178 -179 -180 -181 -182 -183 -184 -185 -186 -187 -188 -189 -190 -191 -192 -193 -194 -195 -196 -197 -198 -199 -200 -201 -202 -203 -204 -205 -206 -207 -208 -209 -210 -211 -212 -213 -214 -215 -216 -2171x -1x -  -  -  -  -  -  -  -1x -  -  -  -  -  -  -  -  -  -  -  -70x -  -  -  -  -  -  -  -  -70x -  -  -  -  -  -  -24x -23x -  -  -  -  -  -  -  -3x -2x -  -  -  -  -  -  -  -2x -1x -  -  -  -  -  -  -  -2x -1x -  -  -  -  -  -  -2x -1x -  -  -  -  -  -  -19x -17x -  -  -  -  -  -  -  -8x -8x -  -  -  -  -  -  -  -  -1x -1x -  -1x -  -  -1x -  -  -  -  -  -  -  -  -  -2x -1x -1x -1x -1x -1x -1x -1x -  -  -  -  -  -  -  -2x -2x -  -  -  -  -  -  -  -3x -3x -  -  -  -  -  -  -  -1x -1x -  -  -  -  -  -  -  -8x -8x -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -4x -4x -  -  -  -  -  -  -  -  -  -  -1x -1x -  -  -  -74x -8x -  -  -  - 
import path from "path";
-import Client, { ClientError } from "./client";
-import FileSystemElement from "./fileSystemElement";
-import Folder from "./folder";
- 
-/**
- * The file class represents a file in nextcloud.
- * It exposes file properties and content handling, commenting and tagging
- */
-export default class File implements FileSystemElement {
-    private memento: {
-        baseName: string,
-        id: number,
-        deleted: boolean,
-        lastmod: Date,
-        mime: string,
-        name: string,
-        size: number,
-    };
-    private client: Client;
-    constructor(client: Client, name: string, baseName: string, lastmod: string, size: number, mime: string, id: number) {
-        this.memento = {
-            baseName,
-            deleted: false,
-            id,
-            lastmod: new Date(lastmod),
-            mime,
-            name,
-            size,
-        };
-        this.client = client;
-    }
-    /**
-     * The name of the file including the path
-     * The name is readonly
-     */
-    get name(): string {
-        this.assertExistence();
-        return this.memento.name;
-    }
- 
-    /**
-     * The base name of the file (file name without path)
-     * The base name is readonly
-     */
-    get baseName(): string {
-        this.assertExistence();
-        return this.memento.baseName;
-    }
- 
-    /**
-     * The timestamp of the last file change
-     * readonly
-     */
-    get lastmod(): Date {
-        this.assertExistence();
-        return this.memento.lastmod;
-    }
- 
-    /**
-     * The file size in bytes
-     * readonly
-     */
-    get size(): number {
-        this.assertExistence();
-        return this.memento.size;
-    }
- 
-    /**
-     * The mime type (content type) of the file
-     */
-    get mime(): string {
-        this.assertExistence();
-        return this.memento.mime;
-    }
- 
-    /**
-     * The unique id of the file.
-     */
-    get id(): number {
-        this.assertExistence();
-        return this.memento.id;
-    }
- 
-    /**
-     * deletes a file
-     * @throws Error
-     */
-    public async delete(): Promise<void> {
-        this.memento.deleted = true;
-        return await this.client.deleteFile(this.memento.name);
-    }
- 
-    /**
-     * get folder of the file
-     * @throws ClientError
-     * @returns the parent folder
-     */
-    public async getFolder(): Promise<Folder> {
-        this.assertExistence();
-        const folder: Folder | null = await this.client.getFolder(path.dirname((this.memento.name)));
- 
-        Iif (folder) {
-            return folder;
-        }
-        throw new ClientError("Error, the folder of the file does not exist anymore", "ERR_FILE_FOLDER_DOES_NOT_EXIST");
-    }
- 
-    /**
-     * moves or renames the current file to the new location
-     * target folder must exists
-     * @param targetFileName the name of the target file /f1/f2/myfile.txt
-     * @throws Error
-     */
-    public async move(targetFileName: string): Promise<File> {
-        this.assertExistence();
-        const file: File = await this.client.moveFile(this.name, targetFileName);
-        this.memento.name = file.name;
-        this.memento.baseName = file.baseName;
-        this.memento.lastmod = file.lastmod;
-        this.memento.mime = file.mime;
-        this.memento.size = file.size;
-        return this;
-    }
- 
-    /**
-     * @returns the buffer of the file content
-     * @throws Error
-     */
-    public async getContent(): Promise<Buffer> {
-        this.assertExistence();
-        return this.client.getContent(this.name);
-    }
- 
-    /**
-     * @returns the url of the file
-     * @throws Error
-     */
-    public getUrl(): string {
-        this.assertExistence();
-        return this.client.getLink(this.name);
-    }
- 
-    /**
-     * @returns the url of the file in the UI
-     * @throws Error
-     */
-    public getUIUrl(): string {
-        this.assertExistence();
-        return this.client.getUILink(this.id);
-    }
- 
-    /**
-     * adds a tag name to the file
-     * @param tagName name of the tag
-     */
-    public async addTag(tagName: string): Promise<void> {
-        this.assertExistence();
-        return this.client.addTagToFile(this.id, tagName);
-    }
- 
-    /**
-     * get tag names
-     * @returns array of tag names
-     */
-    public async getTags(): Promise<string[]> {
-        this.assertExistence();
-        const map: Map<string, number> = await this.client.getTagsOfFile(this.id);
-        const tagNames: string[] = [];
-        for (const tagName of map) {
-            tagNames.push(tagName[0]);
-        }
-        return tagNames;
-    }
- 
-    /**
-     * removes a tag of the file
-     * @param tagName the name of the tag
-     */
-    public async removeTag(tagName: string): Promise<void> {
-        this.assertExistence();
-        const map: Map<string, number> = await this.client.getTagsOfFile(this.id);
- 
-        const tagId: number | undefined = map.get(tagName);
-        if (tagId) {
-            await this.client.removeTagOfFile(this.id, tagId);
-        }
-    }
- 
-    /**
-     * add comment to file
-     * @param comment the comment
-     */
-    public async addComment(comment: string): Promise<void> {
-        this.assertExistence();
-        return await this.client.addCommentToFile(this.id, comment);
-    }
- 
-    /**
-     * get list of comments of file
-     * @param top number of comments to return
-     * @param skip the offset
-     * @returns array of comment strings
-     * @throws Exception
-     */
-    public async getComments(top?: number, skip?: number): Promise<string[]> {
-        this.assertExistence();
-        return await this.client.getFileComments(this.id, top, skip);
-    }
- 
-    private assertExistence(): void {
-        if (this.memento.deleted) {
-            throw new ClientError("File does not exist", "ERR_FILE_NOT_EXISTING");
-        }
-    }
-}
- 
- -
-
- - - - - - - - - \ No newline at end of file diff --git a/docs/coverage/src/fileSizeFormatter.ts.html b/docs/coverage/src/fileSizeFormatter.ts.html deleted file mode 100644 index f9940f36..00000000 --- a/docs/coverage/src/fileSizeFormatter.ts.html +++ /dev/null @@ -1,179 +0,0 @@ - - - - - - Code coverage report for src/fileSizeFormatter.ts - - - - - - - - - -
-
-

All files / src fileSizeFormatter.ts

-
- -
- 100% - Statements - 18/18 -
- - -
- 100% - Branches - 6/6 -
- - -
- 100% - Functions - 2/2 -
- - -
- 100% - Lines - 18/18 -
- - -
-

- Press n or j to go to the next uncovered block, b, p or k for the previous block. -

-
-
-

-
1 -2 -3 -4 -5 -6 -7 -8 -9 -10 -11 -12 -13 -14 -15 -16 -17 -18 -19 -20 -21 -22 -23 -24 -25 -26 -27 -28 -29 -30 -31 -32 -33 -34  -1x -  -20x -20x -20x -  -  -20x -  -  -  -20x -20x -5x -5x -  -15x -6x -6x -  -9x -1x -1x -  -  -8x -  -20x -20x -  -  -  - 
 
-export default class FileSizeFormatter {
-    private bytes: number;
-    private oneKiloByte = 1024;
-    private oneMegaByte = this.oneKiloByte * 1024;
-    private oneGigaByte = this.oneMegaByte * 1024;
- 
-    constructor(bytes: number) {
-        this.bytes = bytes;
-    }
-    public getUserFriendlyFileSize(): string {
-        let suffix: string;
-        let size = this.bytes;
-        if (size > this.oneGigaByte) {
-            size /= this.oneGigaByte;
-            suffix = " GB";
-        }
-        else if (this.bytes > this.oneMegaByte) {
-            size /= this.oneMegaByte;
-            suffix = " MB";
-        }
-        else if (this.bytes > this.oneKiloByte) {
-            size /= this.oneKiloByte;
-            suffix = " kB";
-        }
-        else {
-            suffix = " B";
-        }
-        size = Math.round(size);
-        return size + suffix;
-    }
- 
-}
- 
- -
-
- - - - - - - - - \ No newline at end of file diff --git a/docs/coverage/src/fileSystemElement.ts.html b/docs/coverage/src/fileSystemElement.ts.html deleted file mode 100644 index d7d76fdb..00000000 --- a/docs/coverage/src/fileSystemElement.ts.html +++ /dev/null @@ -1,350 +0,0 @@ - - - - - - Code coverage report for src/fileSystemElement.ts - - - - - - - - - -
-
-

All files / src fileSystemElement.ts

-
- -
- 100% - Statements - 1/1 -
- - -
- 100% - Branches - 0/0 -
- - -
- 100% - Functions - 0/0 -
- - -
- 100% - Lines - 1/1 -
- - -
-

- Press n or j to go to the next uncovered block, b, p or k for the previous block. -

-
-
-

-
1 -2 -3 -4 -5 -6 -7 -8 -9 -10 -11 -12 -13 -14 -15 -16 -17 -18 -19 -20 -21 -22 -23 -24 -25 -26 -27 -28 -29 -30 -31 -32 -33 -34 -35 -36 -37 -38 -39 -40 -41 -42 -43 -44 -45 -46 -47 -48 -49 -50 -51 -52 -53 -54 -55 -56 -57 -58 -59 -60 -61 -62 -63 -64 -65 -66 -67 -68 -69 -70 -71 -72 -73 -74 -75 -76 -77 -78 -79 -80 -81 -82 -83 -84 -85 -86 -87 -88 -89 -90 -91  -  -  -  -  -  -1x -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  - 
import Client, { ClientError } from "./client";
- 
-/**
- * The file class represents a file in nextcloud.
- * It exposes file properties and content handling, commenting and tagging
- */
-export default abstract class FileSystemElement {
- 
-    /**
-     * The name of the file system element including the path
-     * The name is readonly
-     */
-    abstract get name(): string;
- 
-    /**
-     * The base name of the file system element (name without path)
-     * The base name is readonly
-     */
-    abstract get baseName(): string;
- 
-    /**
-     * The timestamp of the last file system element change
-     * readonly
-     */
-    abstract get lastmod(): Date;
- 
-    /**
-     * The unique id of the file system element.
-     */
-    abstract get id(): number;
- 
-    /**
-     * deletes a file system element
-     * @throws Error
-     */
-    public abstract async delete(): Promise<void>;
- 
-    /**
-     * moves or renames the current file system element to the new location
-     * target folder must exists
-     * @param targetFileName the name of the target file /f1/f2/myfile.txt
-     * @throws Error
-     */
-    public abstract async move(targetName: string): Promise<FileSystemElement>;
- 
-    /**
-     * @returns the url of the file sytsem element
-     * @throws Error
-     */
-    public abstract getUrl(): string;
- 
-    /**
-     * @returns the url of the file system element in the UI
-     * @throws Error
-     */
-    public abstract getUIUrl(): string;
- 
-    /**
-     * adds a tag name to the file system element
-     * @param tagName name of the tag
-     */
-    public abstract async addTag(tagName: string): Promise<void>;
- 
-    /**
-     * get tag names
-     * @returns array of tag names
-     */
-    public abstract async getTags(): Promise<string[]>;
- 
-    /**
-     * removes a tag of the file system element
-     * @param tagName the name of the tag
-     */
-    public abstract async removeTag(tagName: string): Promise<void>;
- 
-    /**
-     * add comment to file
-     * @param comment the comment
-     */
-    public abstract async addComment(comment: string): Promise<void>;
- 
-    /**
-     * get list of comments of file
-     * @param top number of comments to return
-     * @param skip the offset
-     * @returns array of comment strings
-     * @throws Exception
-     */
-    public abstract async getComments(top?: number, skip?: number): Promise<string[]>;
-}
- 
- -
-
- - - - - - - - - \ No newline at end of file diff --git a/docs/coverage/src/fileSystemFolder.ts.html b/docs/coverage/src/fileSystemFolder.ts.html deleted file mode 100644 index c0276fbb..00000000 --- a/docs/coverage/src/fileSystemFolder.ts.html +++ /dev/null @@ -1,209 +0,0 @@ - - - - - - Code coverage report for src/fileSystemFolder.ts - - - - - - - - - -
-
-

All files / src fileSystemFolder.ts

-
- -
- 100% - Statements - 19/19 -
- - -
- 100% - Branches - 2/2 -
- - -
- 100% - Functions - 7/7 -
- - -
- 100% - Lines - 17/17 -
- - -
-

- Press n or j to go to the next uncovered block, b, p or k for the previous block. -

-
-
-

-
1 -2 -3 -4 -5 -6 -7 -8 -9 -10 -11 -12 -13 -14 -15 -16 -17 -18 -19 -20 -21 -22 -23 -24 -25 -26 -27 -28 -29 -30 -31 -32 -33 -34 -35 -36 -37 -38 -39 -40 -41 -42 -43 -441x -1x -1x -  -1x -1x -  -  -  -  -  -  -1x -  -  -11x -  -  -  -290x -  -  -  -11x -  -11x -289x -  -10x -  -  -  -  -97x -375x -375x -375x -  -375x -  -  -  -  - 
import util from "util";
-import fs from "fs";
-import path from "path";
- 
-const readdir = util.promisify(fs.readdir);
-const stat = util.promisify(fs.stat);
- 
-export interface IFileNameFormats {
-    absolute: string;
-    relative: string;
-}
- 
-export default class FileSystemFolder {
-    private name: string;
-    constructor(name: string) {
-        this.name = name;
-    }
- 
-    public getName(): IFileNameFormats {
-        return { relative: this.name, absolute: path.resolve(this.name) };
-    }
- 
-    public async getFileNames(): Promise<IFileNameFormats[]> {
-        const fileNames: IFileNameFormats[] = [];
- 
-        for (const absoluteFileName of await this.getFileNamesRecursively(this.name)) {
-            fileNames.push({ absolute: absoluteFileName, relative: absoluteFileName.replace(path.resolve(this.getName().absolute), "").replace(/\\/g, "/") })
-        }
-        return (fileNames);
-    };
- 
-    private async getFileNamesRecursively(name: string): Promise<string[]> {
- 
-        const subdirs: string[] = await readdir(name);
-        const files = await Promise.all(subdirs.map(async (subdir: string) => {
-            const res: string = path.resolve(name, subdir);
-            return (await stat(res)).isDirectory() ? this.getFileNamesRecursively(res) : res;
-        }));
-        return files.reduce((a: any, f: any) => a.concat(f), []);
-    }
- 
- 
-}
- 
- -
-
- - - - - - - - - \ No newline at end of file diff --git a/docs/coverage/src/folder.ts.html b/docs/coverage/src/folder.ts.html deleted file mode 100644 index fc19fef4..00000000 --- a/docs/coverage/src/folder.ts.html +++ /dev/null @@ -1,839 +0,0 @@ - - - - - - Code coverage report for src/folder.ts - - - - - - - - - -
-
-

All files / src folder.ts

-
- -
- 92.96% - Statements - 66/71 -
- - -
- 90.91% - Branches - 10/11 -
- - -
- 90.91% - Functions - 20/22 -
- - -
- 92.96% - Lines - 66/71 -
- - -
-

- Press n or j to go to the next uncovered block, b, p or k for the previous block. -

-
-
-

-
1 -2 -3 -4 -5 -6 -7 -8 -9 -10 -11 -12 -13 -14 -15 -16 -17 -18 -19 -20 -21 -22 -23 -24 -25 -26 -27 -28 -29 -30 -31 -32 -33 -34 -35 -36 -37 -38 -39 -40 -41 -42 -43 -44 -45 -46 -47 -48 -49 -50 -51 -52 -53 -54 -55 -56 -57 -58 -59 -60 -61 -62 -63 -64 -65 -66 -67 -68 -69 -70 -71 -72 -73 -74 -75 -76 -77 -78 -79 -80 -81 -82 -83 -84 -85 -86 -87 -88 -89 -90 -91 -92 -93 -94 -95 -96 -97 -98 -99 -100 -101 -102 -103 -104 -105 -106 -107 -108 -109 -110 -111 -112 -113 -114 -115 -116 -117 -118 -119 -120 -121 -122 -123 -124 -125 -126 -127 -128 -129 -130 -131 -132 -133 -134 -135 -136 -137 -138 -139 -140 -141 -142 -143 -144 -145 -146 -147 -148 -149 -150 -151 -152 -153 -154 -155 -156 -157 -158 -159 -160 -161 -162 -163 -164 -165 -166 -167 -168 -169 -170 -171 -172 -173 -174 -175 -176 -177 -178 -179 -180 -181 -182 -183 -184 -185 -186 -187 -188 -189 -190 -191 -192 -193 -194 -195 -196 -197 -198 -199 -200 -201 -202 -203 -204 -205 -206 -207 -208 -209 -210 -211 -212 -213 -214 -215 -216 -217 -218 -219 -220 -221 -222 -223 -224 -225 -226 -227 -228 -229 -230 -231 -232 -233 -234 -235 -236 -237 -238 -239 -240 -241 -242 -243 -244 -245 -246 -247 -248 -249 -250 -251 -252 -253 -254  -1x -  -  -1x -1x -  -  -  -  -  -  -  -  -1x -  -  -  -  -  -  -  -  -  -  -285x -285x -  -  -  -  -  -  -  -  -  -144x -143x -  -  -  -2x -1x -  -  -  -2x -1x -  -  -  -22x -21x -  -  -  -  -  -  -  -3x -3x -  -  -  -  -  -  -  -2x -2x -2x -1x -  -1x -  -  -  -  -  -  -3x -3x -  -  -  -  -  -  -  -1x -1x -  -  -  -  -  -  -  -  -  -4x -4x -  -  -  -  -  -  -  -  -  -  -16x -  -16x -16x -  -  -16x -128x -  -  -  -  -  -  -16x -  -  -  -  -  -  -  -20x -20x -20x -  -  -  -  -  -  -  -  -  -1x -1x -1x -1x -1x -1x -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -2x -  -2x -2x -1x -  -1x -  -  -  -  -  -  -  -9x -  -  -  -  -  -  -  -2x -2x -2x -2x -5x -  -2x -  -  -  -  -  -  -  -2x -2x -2x -  -2x -2x -1x -  -  -  -  -  -  -  -  -4x -4x -  -  -  -  -  -  -  -  -  -  -2x -2x -  -  -  -212x -4x -  -  -  -  - 
import Client from "./client";
-import ClientError from "./error";
-import File from "./file";
-import FileSystemElement from "./fileSystemElement";
-import Logger from "./logger";
-const log: Logger = new Logger();
- 
-export interface FolderGetFilesOptions {
-    /**
-     * callback function to filter files
-     */
-    filterFile?: (file: File) => File | null;
-}
- 
-export default class Folder implements FileSystemElement {
-    private client: Client;
-    private memento: {
-        baseName: string,
-        id: number,
-        deleted: boolean,
-        lastmod: Date,
-        name: string,
-    };
-    constructor(client: Client, name: string, baseName: string, lastmod: string, id: number = -1) {
- 
-        this.client = client;
-        this.memento = {
-            baseName,
-            deleted: false,
-            id,
-            lastmod: new Date(lastmod),
-            name,
-        };
-    }
- 
-    get name(): string {
-        this.assertExistence();
-        return this.memento.name;
-    }
- 
-    get baseName(): string {
-        this.assertExistence();
-        return this.memento.baseName;
-    }
- 
-    get lastmod(): Date {
-        this.assertExistence();
-        return this.memento.lastmod;
-    }
- 
-    get id(): number {
-        this.assertExistence();
-        return this.memento.id;
-    }
- 
-    /**
-     * @returns an array of subfolders
-     * @throws Error
-     */
-    public async getSubFolders(): Promise<Folder[]> {
-        this.assertExistence();
-        return await this.client.getSubFolders(this.name);
-    }
- 
-    /**
-     * returns true if the current folder has a subfolder with the given base name
-     * @param subFolderBaseName the base name of the subfolder like "products"
-     */
-    public async hasSubFolder(subFolderBaseName: string): Promise<boolean> {
-        this.assertExistence();
-        const subFolder: Folder | null = await this.client.getFolder(this.name + "/" + subFolderBaseName);
-        if (subFolder) {
-            return true;
-        }
-        return false;
-    }
- 
-    /**
-     * @returns all files of the folder
-     */
-    public async getFiles(options?: FolderGetFilesOptions): Promise<File[]> {
-        this.assertExistence();
-        return await this.client.getFiles(this.name, options);
-    }
- 
-    /**
-     * creates a subfolder
-     * @param subFolderBaseName  name of the subfolder basename
-     */
-    public async createSubFolder(subFolderBaseName: string): Promise<Folder> {
-        this.assertExistence();
-        return await this.client.createFolder(this.name + "/" + subFolderBaseName);
-    }
- 
-    /**
-     * get a file by basename
-     * @param fileBaseName the base name of the file
-     * @returns the file of null
-     * @throws Error
-     */
-    public async getFile(fileBaseName: string): Promise<File | null> {
-        this.assertExistence();
-        return this.client.getFile(this.name + "/" + fileBaseName);
-    }
- 
-    /**
-     * creates a file in the folder
-     * @param fileBaseName the base name of the file
-     * @param data the buffer or stream with file content
-     * @returns the new file or null
-     * @throws Error
-     */
-    public async createFile(fileBaseName: string, data: Buffer | NodeJS.ReadableStream): Promise<File> {
-        this.assertExistence();
-        // must not contain :/\*"<>?
-        log.debug("createFile fileBaseName = ", fileBaseName);
-        const invalidChars: string[] = [":", "*", "/", "\\", "\"", "?", "<", ">"];
-        // log.debug("createFile invalidChars = ", invalidChars);
- 
-        for (const invalidChar of invalidChars) {
-            Iif (fileBaseName.indexOf(invalidChar) !== -1) {
-                throw new ClientError("Filename contains an invalid character '" + invalidChar + "'",
-                    "ERR_INVALID_CHAR_IN_FILE_NAME",
-                    { fileBaseName });
-            }
-        }
- 
-        return this.client.createFile(this.name + "/" + fileBaseName.replace(/^\/+/g, ""), data);
-    }
- 
-    /**
-     * deletes the folder and the contained files
-     * @throws Error
-     */
-    public async delete(): Promise<void> {
-        log.debug("delete");
-        this.memento.deleted = true;
-        return await this.client.deleteFolder(this.memento.name);
-    }
- 
-    /**
-     * renames or moves the current folder to the new location
-     * target folder must exists
-     * @param targetFolderName the name of the target folder /f1/f2/target
-     * @throws Error
-     */
-    public async move(targetFolderName: string): Promise<Folder> {
-        this.assertExistence();
-        const folder: Folder = await this.client.moveFolder(this.name, targetFolderName);
-        this.memento.name = folder.name;
-        this.memento.baseName = folder.baseName;
-        this.memento.lastmod = folder.lastmod;
-        return this;
-    }
- 
-    /**
-     * @returns the url of the folder
-     * @throws Error
-     */
-    public getUrl(): string {
-        this.assertExistence();
-        return this.client.getLink(this.name);
-    }
- 
-    /**
-     * @returns the url of the folder in the UI
-     * @throws Error
-     */
-    public getUIUrl(): string {
-        this.assertExistence();
-        return this.client.getUILink(this.id);
-    }
- 
-    /**
-     * @returns true if the folder contains a file with the given basename
-     * @param fileBaseName file basename
-     * @throws Error
-     */
-    public async containsFile(fileBaseName: string): Promise<boolean> {
-        this.assertExistence();
-        let file: File | null;
-        file = await this.getFile(fileBaseName);
-        if (file) {
-            return true;
-        }
-        return false;
-    }
- 
-    /**
-     * adds a tag name to the folder
-     * @param tagName name of the tag
-     */
-    public async addTag(tagName: string): Promise<void> {
-        return await this.client.addTagToFile(this.id, tagName);
-    }
- 
-    /**
-     * get tag names
-     * @returns array of tag names
-     */
-    public async getTags(): Promise<string[]> {
-        this.assertExistence();
-        const map: Map<string, number> = await this.client.getTagsOfFile(this.id);
-        const tagNames: string[] = [];
-        for (const tagName of map) {
-            tagNames.push(tagName[0]);
-        }
-        return tagNames;
-    }
- 
-    /**
-     * removes a tag of the file
-     * @param tagName the name of the tag
-     */
-    public async removeTag(tagName: string): Promise<void> {
-        this.assertExistence();
-        const map: Map<string, number> = await this.client.getTagsOfFile(this.id);
-        const tagNames: string[] = [];
- 
-        const tagId: number | undefined = map.get(tagName);
-        if (tagId) {
-            await this.client.removeTagOfFile(this.id, tagId);
-        }
-    }
- 
-    /**
-     * add comment to folder
-     * @param comment the comment
-     */
-    public async addComment(comment: string): Promise<void> {
-        this.assertExistence();
-        return await this.client.addCommentToFile(this.id, comment);
-    }
- 
-    /**
-     * get list of comments of folder
-     * @param top number of comments to return
-     * @param skip the offset
-     * @returns array of comment strings
-     * @throws Exception
-     */
-    public async getComments(top?: number, skip?: number): Promise<string[]> {
-        this.assertExistence();
-        return await this.client.getFileComments(this.id, top, skip);
-    }
- 
-    private assertExistence(): void {
-        if (this.memento.deleted) {
-            throw new ClientError("Folder does not exist", "ERR_FOLDER_NOT_EXISTING");
-        }
-    }
- 
-}
- 
- -
-
- - - - - - - - - \ No newline at end of file diff --git a/docs/coverage/src/getFilesRecursivelyCommand.ts.html b/docs/coverage/src/getFilesRecursivelyCommand.ts.html deleted file mode 100644 index 91b3a524..00000000 --- a/docs/coverage/src/getFilesRecursivelyCommand.ts.html +++ /dev/null @@ -1,368 +0,0 @@ - - - - - - Code coverage report for src/getFilesRecursivelyCommand.ts - - - - - - - - - -
-
-

All files / src getFilesRecursivelyCommand.ts

-
- -
- 90.63% - Statements - 29/32 -
- - -
- 75% - Branches - 3/4 -
- - -
- 100% - Functions - 4/4 -
- - -
- 90.63% - Lines - 29/32 -
- - -
-

- Press n or j to go to the next uncovered block, b, p or k for the previous block. -

-
-
-

-
1 -2 -3 -4 -5 -6 -7 -8 -9 -10 -11 -12 -13 -14 -15 -16 -17 -18 -19 -20 -21 -22 -23 -24 -25 -26 -27 -28 -29 -30 -31 -32 -33 -34 -35 -36 -37 -38 -39 -40 -41 -42 -43 -44 -45 -46 -47 -48 -49 -50 -51 -52 -53 -54 -55 -56 -57 -58 -59 -60 -61 -62 -63 -64 -65 -66 -67 -68 -69 -70 -71 -72 -73 -74 -75 -76 -77 -78 -79 -80 -81 -82 -83 -84 -85 -86 -87 -88 -89 -90 -91 -92 -93 -94 -95 -96 -97  -1x -  -  -1x -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -1x -  -  -  -  -  -  -  -  -  -  -1x -1x -1x -1x -  -  -  -  -  -  -  -  -1x -1x -1x -1x -1x -  -1x -  -  -  -  -  -1x -1x -  -  -1x -  -1x -1x -  -  -  -  -1x -  -  -  -  -  -  -  -  -  -  -  -8x -8x -8x -3x -  -  -8x -8x -7x -  -8x -  -7x -  -8x -  -  - 
// tslint:disable-next-line:no-var-requires
-const debug = require("debug").debug("GetFilesRecursivelyCommand");
- 
-import Client, { File, Folder, FolderGetFilesOptions } from "./client";
-import Command, { CommandStatus } from "./command";
- 
-export interface GetFilesRecursivelyCommandOptions {
-    /**
-     * the source nextcloud folder to start listing the files
-     */
-    sourceFolder: Folder;
-    /**
-     * function to filter files
-     */
-    filterFile?: (file: File) => File | null;
-}
- 
-/**
- * Command to get all files of a nextcloud folder recursively
- */
-export default class GetFilesRecursivelyCommand extends Command {
-    private sourceFolder: Folder;
-    private filterFile?: (file: File) => File | null;
-    private files: File[];
- 
-    /**
-     * @param {Client} client the client
-     * @param {SourceTargetFileNames[]} files the files to be uploaded
-     * @param {(file: File) => void} processAfterUpload callback function to process the uploaded file
-     */
-    constructor(client: Client, options: GetFilesRecursivelyCommandOptions) {
-        super(client);
-        this.sourceFolder = options.sourceFolder;
-        this.filterFile = options.filterFile;
-        this.files = [];
-    }
- 
-    /**
-     * execute the command
-     * @async
-     * @returns {Promise<void>}
-     */
-    protected async onExecute(): Promise<void> {
-        this.status = CommandStatus.running;
-        const startTime = new Date();
-        try {
-            this.percentCompleted = 0;
-            await this.processFolder(this.sourceFolder, 100);
-            // console.log("file count", this.files.length);
-            this.resultMetaData.messages.push(`${this.files.length} files found`);
-        } catch (e) {
-            debug(e.message);
-            this.resultMetaData.errors.push(e.message);
-        }
- 
-        this.percentCompleted = 100;
-        Iif (this.resultMetaData.errors.length > 0) {
-            this.status = CommandStatus.failed;
-        } else {
-            this.status = CommandStatus.success;
-        }
-        this.resultMetaData.timeElapsed = new Date().getTime() - startTime.getTime();
-        return;
-    };
- 
- 
-    public getFiles(): File[] {
-        return this.files;
-    }
- 
-    /**
-     * adds files of folder and processes subordinated folders
-     * @param {Folder} folder the folder to process
-     * @param {number} percentagethe percentage that is finished, when the function returns
-     */
-    private async processFolder(folder: Folder, percentage: number): Promise<void> {
-        // tslint:disable-next-line:no-console
-        // console.log(folder.name);
- 
-        const options: FolderGetFilesOptions = { filterFile: this.filterFile }
-        const folderFiles: File[] = await folder.getFiles(options);
-        for (const fi of folderFiles) {
-            this.files.push(fi);
-        }
- 
-        const subFolders: Folder[] = await folder.getSubFolders();
-        if (subFolders.length === 0) {
-            this.percentCompleted += percentage;
-        }
-        for (const subFolder of subFolders) {
-            // console.log("folder", subFolder.name);
-            await this.processFolder(subFolder, percentage / subFolders.length);
-        }
-        return;
-    }
-}
- 
- -
-
- - - - - - - - - \ No newline at end of file diff --git a/docs/coverage/src/httpClient.ts.html b/docs/coverage/src/httpClient.ts.html deleted file mode 100644 index b4f8bbd8..00000000 --- a/docs/coverage/src/httpClient.ts.html +++ /dev/null @@ -1,536 +0,0 @@ - - - - - - Code coverage report for src/httpClient.ts - - - - - - - - - -
-
-

All files / src httpClient.ts

-
- -
- 98.44% - Statements - 63/64 -
- - -
- 100% - Branches - 28/28 -
- - -
- 88.89% - Functions - 8/9 -
- - -
- 98.36% - Lines - 60/61 -
- - -
-

- Press n or j to go to the next uncovered block, b, p or k for the previous block. -

-
-
-

-
1 -2 -3 -4 -5 -6 -7 -8 -9 -10 -11 -12 -13 -14 -15 -16 -17 -18 -19 -20 -21 -22 -23 -24 -25 -26 -27 -28 -29 -30 -31 -32 -33 -34 -35 -36 -37 -38 -39 -40 -41 -42 -43 -44 -45 -46 -47 -48 -49 -50 -51 -52 -53 -54 -55 -56 -57 -58 -59 -60 -61 -62 -63 -64 -65 -66 -67 -68 -69 -70 -71 -72 -73 -74 -75 -76 -77 -78 -79 -80 -81 -82 -83 -84 -85 -86 -87 -88 -89 -90 -91 -92 -93 -94 -95 -96 -97 -98 -99 -100 -101 -102 -103 -104 -105 -106 -107 -108 -109 -110 -111 -112 -113 -114 -115 -116 -117 -118 -119 -120 -121 -122 -123 -124 -125 -126 -127 -128 -129 -130 -131 -132 -133 -134 -135 -136 -137 -138 -139 -140 -141 -142 -143 -144 -145 -146 -147 -148 -149 -150 -151 -152 -153  -1x -  -  -1x -1x -  -  -  -  -1x -1x -1x -1x -1x -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -1x -  -  -  -  -  -  -175x -175x -175x -175x -175x -  -  -  -1310x -5x -  -  -1310x -1x -  -  -1310x -1x -  -  -1310x -1307x -  -1310x -  -  -1310x -2x -2x -  -  -  -  -  -2x -  -2x -1x -  -  -  -1310x -1310x -  -1310x -  -1307x -1304x -  -  -2056x -2056x -  -  -1304x -  -  -  -1304x -319x -  -  -1304x -2x -  -  -1304x -1304x -52x -  -  -1304x -801x -  -  -  -1304x -  -  -  -  -1304x -  -  -  -  -1304x -1304x -  -  -1307x -  -1307x -236x -236x -236x -236x -236x -236x -236x -  -  -  -  -  -  -  -1071x -  -  -  - 
// tslint:disable-next-line:no-var-requires
-const HttpProxyAgent = require('http-proxy-agent');
- 
-import { HttpProxyAgentOptions } from "http-proxy-agent";
-import fetch from "node-fetch";
-import {
-    Headers,
-    RequestInit,
-    Response,
-} from "node-fetch";
-import ClientError from "./error";
-import RequestResponseLog from "./requestResponseLog";
-import RequestResponseLogEntry, { RequestLogEntry, ResponseLogEntry } from "./requestResponseLogEntry";
-import Logger from "./logger";
-const log: Logger = new Logger();
- 
-export interface IRequestContext {
-    "description"?: string;
-}
- 
-export interface IProxy {
-    "host": string;
-    "port": string;
-    "protocol": string;
-    "secureProxy": boolean;
-    "proxyAuthorizationHeader"?: string;
-}
- 
-export interface IHttpClientOptions {
-    "authorizationHeader"?: string;
-    "logRequestResponse"?: boolean;
-    "proxy"?: IProxy;
-    "origin"?: string;
-}
-export class HttpClient {
-    private proxy?: IProxy;
-    private authorizationHeader?: string;
-    private logRequestResponse: boolean;
-    private origin: string;
- 
-    public constructor(options: IHttpClientOptions) {
-        log.debug("constructor");
-        this.authorizationHeader = options.authorizationHeader;
-        this.proxy = options.proxy;
-        this.logRequestResponse = options.logRequestResponse || false;
-        this.origin = options.origin || "";
-    }
-    public async getHttpResponse(url: string, requestInit: RequestInit, expectedHttpStatusCode: number[], context: IRequestContext): Promise<Response> {
- 
-        if (!requestInit.headers) {
-            requestInit.headers = new Headers();
-        }
- 
-        if (!requestInit.method) {
-            requestInit.method = "UNDEFINED";
-        }
- 
-        if (!context.description) {
-            context.description = "";
-        }
- 
-        if (this.authorizationHeader) {
-            (requestInit.headers as Headers).append("Authorization", this.authorizationHeader);
-        }
-        (requestInit.headers as Headers).append("User-Agent", "nextcloud-node-client");
- 
-        // set the proxy
-        if (this.proxy) {
-            log.debug("proxy agent used");
-            const options: HttpProxyAgentOptions = {
-                host: this.proxy.host,
-                port: this.proxy.port,
-                protocol: this.proxy.protocol,
-            };
- 
-            requestInit.agent = new HttpProxyAgent(options);
- 
-            if (this.proxy.proxyAuthorizationHeader) {
-                (requestInit.headers as Headers).append("Proxy-Authorization", this.proxy.proxyAuthorizationHeader);
-            }
-        }
- 
-        log.debug("getHttpResponse request header:", requestInit.headers);
-        log.debug("getHttpResponse url", url, requestInit);
- 
-        const response: Response = await fetch(url, requestInit);
- 
-        if (this.logRequestResponse) {
-            const responseText = await response.text();
- 
-            // overwrite response functions as the body uses a stearm object...
-            response.text = async () => {
-                return responseText;
-            };
- 
-            response.body.pipe = (destination: NodeJS.WritableStream, options?: { end?: boolean; }): any => {
-                destination.write(responseText);
-            };
- 
-            response.json = async () => {
-                return JSON.parse(responseText);
-            };
- 
-            response.buffer = async () => {
-                return Buffer.from(responseText);
-            };
- 
-            let body: string = `<Body is ${typeof requestInit.body}>`;
-            if (requestInit.body && requestInit.body instanceof Buffer) {
-                body = `<Body is Buffer ${requestInit.body.length}>`;
-            }
- 
-            if (typeof requestInit.body === "string") {
-                body = requestInit.body;
-            }
- 
-            const reqLogEntry: RequestLogEntry =
-                new RequestLogEntry(url.replace(this.origin, ""),
-                    requestInit.method, context.description,
-                    body);
- 
-            const resLogEntry: ResponseLogEntry =
-                new ResponseLogEntry(response.status,
-                    await response.text(),
-                    response.headers.get("Content-Type") as string,
-                    response.headers.get("Content-Location") || "");
- 
-            const rrLog: RequestResponseLog = RequestResponseLog.getInstance();
-            await rrLog.addEntry(new RequestResponseLogEntry(reqLogEntry, resLogEntry));
-        }
- 
-        const responseContentType: string | null = response.headers.get("content-type");
- 
-        if (expectedHttpStatusCode.indexOf(response.status) === -1) {
-            log.debug("getHttpResponse unexpected status response "+ response.status + " " + response.statusText);
-            log.debug("getHttpResponse description "+ context.description);
-            log.debug("getHttpResponse expected "+ expectedHttpStatusCode.join(","));
-            log.debug("getHttpResponse headers ", JSON.stringify(response.headers, null, 4));
-            log.debug("getHttpResponse request body ", requestInit.body);
-            log.debug("getHttpResponse text:", await response.text());
-            throw new ClientError(`HTTP response status ${response.status} not expected. Expected status: ${expectedHttpStatusCode.join(",")} - status text: ${response.statusText}`,
-                "ERR_UNEXPECTED_HTTP_STATUS",
-                {
-                    expectedHttpStatusCodes: expectedHttpStatusCode,
-                    responseStatus: response.status,
-                    responseStatusText: response.statusText,
-                });
-        }
-        return response;
-    }
- 
-}
- 
- -
-
- - - - - - - - - \ No newline at end of file diff --git a/docs/coverage/src/index.html b/docs/coverage/src/index.html deleted file mode 100644 index c2d5609d..00000000 --- a/docs/coverage/src/index.html +++ /dev/null @@ -1,381 +0,0 @@ - - - - - - Code coverage report for src - - - - - - - - - -
-
-

All files src

-
- -
- 94.16% - Statements - 1611/1711 -
- - -
- 89.93% - Branches - 545/606 -
- - -
- 91.83% - Functions - 236/257 -
- - -
- 94.12% - Lines - 1602/1702 -
- - -
-

- Press n or j to go to the next uncovered block, b, p or k for the previous block. -

-
-
-
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
FileStatementsBranchesFunctionsLines
client.ts -
-
92.97%1031/110987.44%383/43892%92/10092.94%1027/1105
environment.ts -
-
100%15/15100%15/15100%5/5100%15/15
environmentVcapServices.ts -
-
100%24/24100%15/15100%2/2100%24/24
error.ts -
-
100%21/21100%0/0100%2/2100%21/21
fakeServer.ts -
-
96.3%26/2790%9/10100%2/296.3%26/27
file.ts -
-
78.95%45/5750%3/689.47%17/1978.95%45/57
fileSizeFormatter.ts -
-
100%18/18100%6/6100%2/2100%18/18
fileSystemElement.ts -
-
100%1/1100%0/0100%0/0100%1/1
fileSystemFolder.ts -
-
100%19/19100%2/2100%7/7100%17/17
folder.ts -
-
92.96%66/7190.91%10/1190.91%20/2292.96%66/71
httpClient.ts -
-
98.44%63/64100%28/2888.89%8/998.36%60/61
logger.ts -
-
96.55%28/29100%8/812.5%1/896.55%28/29
requestResponseLog.ts -
-
100%54/54100%24/24100%9/9100%54/54
requestResponseLogEntry.ts -
-
100%13/13100%0/0100%3/3100%13/13
server.ts -
-
90%9/1050%1/2100%1/190%9/10
share.ts -
-
98.36%60/61100%26/2694.74%18/1998.36%60/61
tag.ts -
-
100%9/9100%0/0100%3/3100%9/9
user.ts -
-
100%98/98100%13/13100%40/40100%98/98
userGroup.ts -
-
100%11/11100%2/2100%4/4100%11/11
-
-
-
- - - - - - - - - \ No newline at end of file diff --git a/docs/coverage/src/logger.ts.html b/docs/coverage/src/logger.ts.html deleted file mode 100644 index 37195619..00000000 --- a/docs/coverage/src/logger.ts.html +++ /dev/null @@ -1,419 +0,0 @@ - - - - - - Code coverage report for src/logger.ts - - - - - - - - - -
-
-

All files / src logger.ts

-
- -
- 96.55% - Statements - 28/29 -
- - -
- 100% - Branches - 8/8 -
- - -
- 12.5% - Functions - 1/8 -
- - -
- 96.55% - Lines - 28/29 -
- - -
-

- Press n or j to go to the next uncovered block, b, p or k for the previous block. -

-
-
-

-
1 -2 -3 -4 -5 -6 -7 -8 -9 -10 -11 -12 -13 -14 -15 -16 -17 -18 -19 -20 -21 -22 -23 -24 -25 -26 -27 -28 -29 -30 -31 -32 -33 -34 -35 -36 -37 -38 -39 -40 -41 -42 -43 -44 -45 -46 -47 -48 -49 -50 -51 -52 -53 -54 -55 -56 -57 -58 -59 -60 -61 -62 -63 -64 -65 -66 -67 -68 -69 -70 -71 -72 -73 -74 -75 -76 -77 -78 -79 -80 -81 -82 -83 -84 -85 -86 -87 -88 -89 -90 -91 -92 -93 -94 -95 -96 -97 -98 -99 -100 -101 -102 -103 -104 -105 -106 -107 -108 -109 -110 -111 -112 -113 -1141x -1x -  -  -  -  -  -1x -  -  -  -  -  -17x -  -1x -1x -  -1x -1x -  -1x -1x -  -1x -1x -  -1x -1x -  -10x -10x -  -1x -1x -  -1x -  -  -17x -17x -  -17x -17x -17x -17x -17x -17x -17x -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  - 
import Environment from "./environment";
-import {
-    Logger as TSLogLogger,
-    ILogObject as LogObject,
-    TLogLevelName
-} from "tslog";
- 
-export default class Logger {
-    private logger: TSLogLogger;
- 
-    public constructor() {
-        let minLevel: TLogLevelName;
- 
-        switch (Environment.getMinLogLevel()) {
-            case "silly":
-                minLevel = "silly"
-                break;
-            case "trace":
-                minLevel = "trace"
-                break;
-            case "debug":
-                minLevel = "debug"
-                break;
-            case "info":
-                minLevel = "info"
-                break;
-            case "warn":
-                minLevel = "warn"
-                break;
-            case "error":
-                minLevel = "error"
-                break;
-            case "fatal":
-                minLevel = "fatal"
-                break;
-            default:
-                minLevel = "error";
-        }
- 
-        minLevel = "error";
-        this.logger = new TSLogLogger({ minLevel });
-        // overload is required to get the real position for logging
-        this.silly = this.logger.silly.bind(this.logger);
-        this.trace = this.logger.trace.bind(this.logger);
-        this.debug = this.logger.debug.bind(this.logger);
-        this.info = this.logger.info.bind(this.logger);
-        this.warn = this.logger.warn.bind(this.logger);
-        this.error = this.logger.error.bind(this.logger);
-        this.fatal = this.logger.fatal.bind(this.logger);
-    }
- 
-    /**
-     * Logs a silly message.
-     * @param args  - Multiple log attributes that should be logged out.
-     */
-    public silly(...args: unknown[]): LogObject {
-        /* istanbul ignore next */
-        return this.logger.silly(...args);
-    }
- 
-    /**
-     * Logs a trace message.
-     * @param args  - Multiple log attributes that should be logged out.
-     */
-    public trace(...args: unknown[]): LogObject {
-        /* istanbul ignore next */
-        return this.logger.trace(...args);
-    }
- 
-    /**
-     * Logs a debug message.
-     * @param args  - Multiple log attributes that should be logged out.
-     */
-    public debug(...args: unknown[]): LogObject {
-        return this.logger.debug(...args);
-    }
- 
-    /**
-     * Logs a info message.
-     * @param args  - Multiple log attributes that should be logged out.
-     */
-    public info(...args: unknown[]): LogObject {
-        /* istanbul ignore next */
-        return this.logger.info(...args);
-    }
- 
-    /**
-     * Logs a warn message.
-     * @param args  - Multiple log attributes that should be logged out.
-     */
-    public warn(...args: unknown[]): LogObject {
-        /* istanbul ignore next */
-        return this.logger.warn(...args);
-    }
- 
-    /**
-     * Logs a error message.
-     * @param args  - Multiple log attributes that should be logged out.
-     */
-    public error(...args: unknown[]): LogObject {
-        /* istanbul ignore next */
-        return this.logger.error(...args);
-    }
- 
-    /**
-     * Logs a fatal message.
-     * @param args  - Multiple log attributes that should be logged out.
-     */
-    public fatal(...args: unknown[]): LogObject {
-        /* istanbul ignore next */
-        return this.logger.fatal(...args);
-    }
-}
- 
- -
-
- - - - - - - - - \ No newline at end of file diff --git a/docs/coverage/src/requestResponseLog.ts.html b/docs/coverage/src/requestResponseLog.ts.html deleted file mode 100644 index 308bfb85..00000000 --- a/docs/coverage/src/requestResponseLog.ts.html +++ /dev/null @@ -1,416 +0,0 @@ - - - - - - Code coverage report for src/requestResponseLog.ts - - - - - - - - - -
-
-

All files / src requestResponseLog.ts

-
- -
- 100% - Statements - 54/54 -
- - -
- 100% - Branches - 24/24 -
- - -
- 100% - Functions - 9/9 -
- - -
- 100% - Lines - 54/54 -
- - -
-

- Press n or j to go to the next uncovered block, b, p or k for the previous block. -

-
-
-

-
1 -2 -3 -4 -5 -6 -7 -8 -9 -10 -11 -12 -13 -14 -15 -16 -17 -18 -19 -20 -21 -22 -23 -24 -25 -26 -27 -28 -29 -30 -31 -32 -33 -34 -35 -36 -37 -38 -39 -40 -41 -42 -43 -44 -45 -46 -47 -48 -49 -50 -51 -52 -53 -54 -55 -56 -57 -58 -59 -60 -61 -62 -63 -64 -65 -66 -67 -68 -69 -70 -71 -72 -73 -74 -75 -76 -77 -78 -79 -80 -81 -82 -83 -84 -85 -86 -87 -88 -89 -90 -91 -92 -93 -94 -95 -96 -97 -98 -99 -100 -101 -102 -103 -104 -105 -106 -107 -108 -109 -110 -111 -112 -113  -1x -1x -1x -  -1x -1x -  -1x -1x -  -  -8x -  -  -1475x -9x -  -1475x -  -1x -  -9x -  -9x -  -9x -9x -  -  -  -1314x -1314x -1x -1x -  -  -1313x -1084x -755x -  -1084x -324x -  -  -  -1313x -1311x -638x -  -  -  -1313x -1313x -  -  -  -6x -6x -1x -1x -  -  -5x -5x -  -  -  -168x -168x -  -168x -168x -  -  -168x -  -  -  -1646x -  -  -  -1393x -1391x -  -2x -  -  -  -168x -168x -168x -  -168x -670x -168x -  -502x -  -  -670x -670x -  -  -  -  -  -  -  -  -  - 
 
-import parser from "fast-xml-parser";
-import { promises as fsPromises } from "fs";
-import path from "path";
-import requestResponseLogEntry from "./requestResponseLogEntry";
-import Logger from "./logger";
-const log: Logger = new Logger();
- 
-export default class RequestResponseLog {
-    public static readonly defaultLogDirectory: string = "RequestResponseLog/";
- 
-    public static deleteInstance(): void {
-        RequestResponseLog.log = null;
-    }
-    public static getInstance(): RequestResponseLog {
-        if (!RequestResponseLog.log) {
-            RequestResponseLog.log = new RequestResponseLog();
-        }
-        return RequestResponseLog.log;
-    }
-    private static log: RequestResponseLog | null = null;
- 
-    public baseDirectory: string = RequestResponseLog.defaultLogDirectory;
-    private context: string;
-    private entries: requestResponseLogEntry[] = [];
-    private constructor() {
-        this.baseDirectory = RequestResponseLog.defaultLogDirectory;
-        this.context = "";
-    }
- 
-    public async addEntry(logEntry: requestResponseLogEntry) {
-        log.debug("addEntry");
-        if (!this.context) {
-            log.debug("Error while recording, context not set");
-            throw new Error("Error while recording, context not set");
-        }
- 
-        if (logEntry.response.body && logEntry.response.contentType) {
-            if (logEntry.response.contentType.indexOf("application/xml") !== -1) {
-                logEntry.response.jsonBody = this.xmlToJson(logEntry.response.body);
-            }
-            if (logEntry.response.contentType.indexOf("application/json") !== -1) {
-                logEntry.response.jsonBody = JSON.parse(logEntry.response.body);
-            }
-        }
- 
-        if (logEntry.request.body) {
-            if (logEntry.request.body.indexOf && logEntry.request.body.indexOf("<?xml version") !== -1) {
-                logEntry.request.jsonBody = this.xmlToJson(logEntry.request.body);
-            }
-        }
- 
-        this.entries.push(logEntry);
-        await fsPromises.writeFile(this.getFileName(), JSON.stringify(this.entries, null, 4));
-    }
- 
-    public async getEntries(): Promise<requestResponseLogEntry[]> {
-        log.debug("getEntries");
-        if (!this.context) {
-            log.debug("Error while getting recording request, context not set");
-            throw new Error("Error while getting recording request, context not set");
-        }
- 
-        const entries: string = await fsPromises.readFile(this.getFileName(), { encoding: "utf8" });
-        return JSON.parse(entries);
-    }
- 
-    public async setContext(context: string) {
-        log.debug("setContext");
-        const newContext: string = context.replace(/ |:|\./g, "_");
-        // if (this.context !== newContext) {
-        this.context = newContext;
-        this.entries = [];
-        // }
-        // create the directory
-        await this.assertDirectory(this.getFileName());
-    }
- 
-    public getFileName(): string {
-        return `${this.baseDirectory}${this.context}.json`;
-    }
- 
-    private xmlToJson(xml: string): any {
-        if (parser.validate(xml) === true) {
-            return parser.parse(xml, { ignoreNameSpace: true });
-        }
-        return { info: "invalid xml" };
-    }
- 
-    private async assertDirectory(filename: string): Promise<void> {
-        const directory = path.dirname(filename);
-        const pathArray: string[] = directory.split("/");
-        let p: string = "";
- 
-        for (const dir of pathArray) {
-            if (p === "") {
-                p = dir;
-            } else {
-                p = p + "/" + dir;
-            }
- 
-            try {
-                await fsPromises.mkdir(p);
-                  /* istanbul ignore next */
-                  log.debug(`directory "${p}" created`);
-            } catch (e) {
-                  /* istanbul ignore next */
-                  log.debug(`directory "${p}" already exists`);
-            }
-        }
-    }
-}
- 
- -
-
- - - - - - - - - \ No newline at end of file diff --git a/docs/coverage/src/requestResponseLogEntry.ts.html b/docs/coverage/src/requestResponseLogEntry.ts.html deleted file mode 100644 index caf871ab..00000000 --- a/docs/coverage/src/requestResponseLogEntry.ts.html +++ /dev/null @@ -1,194 +0,0 @@ - - - - - - Code coverage report for src/requestResponseLogEntry.ts - - - - - - - - - -
-
-

All files / src requestResponseLogEntry.ts

-
- -
- 100% - Statements - 13/13 -
- - -
- 100% - Branches - 0/0 -
- - -
- 100% - Functions - 3/3 -
- - -
- 100% - Lines - 13/13 -
- - -
-

- Press n or j to go to the next uncovered block, b, p or k for the previous block. -

-
-
-

-
1 -2 -3 -4 -5 -6 -7 -8 -9 -10 -11 -12 -13 -14 -15 -16 -17 -18 -19 -20 -21 -22 -23 -24 -25 -26 -27 -28 -29 -30 -31 -32 -33 -34 -35 -36 -37 -38 -391x -  -  -  -  -  -  -1310x -1310x -1310x -1310x -  -  -  -  -1x -  -  -  -  -  -  -1310x -1310x -1310x -1310x -  -  -  -  -1x -  -  -  -1314x -1314x -  -  - 
export class RequestLogEntry {
-    public body?: string;
-    public description: string;
-    public jsonBody?: any;
-    public method: string;
-    public url: string;
-    public constructor(url: string, method: string, description: string, body?: string) {
-        this.url = url;
-        this.method = method;
-        this.description = description;
-        this.body = body;
-    }
-}
- 
-// tslint:disable-next-line:max-classes-per-file
-export class ResponseLogEntry {
-    public body?: string;
-    public contentType?: string;
-    public contentLocation?: string;
-    public jsonBody?: any;
-    public status: number;
-    public constructor(status: number, body?: string, contentType?: string, contentLocation?: string) {
-        this.status = status;
-        this.body = body;
-        this.contentType = contentType;
-        this.contentLocation = contentLocation;
-    }
-}
- 
-// tslint:disable-next-line:max-classes-per-file
-export default class RequestResponseLogEntry {
-    public request: RequestLogEntry;
-    public response: ResponseLogEntry;
-    public constructor(request: RequestLogEntry, response: ResponseLogEntry) {
-        this.request = request;
-        this.response = response;
-    }
-}
- 
- -
-
- - - - - - - - - \ No newline at end of file diff --git a/docs/coverage/src/server.ts.html b/docs/coverage/src/server.ts.html deleted file mode 100644 index 1dab6501..00000000 --- a/docs/coverage/src/server.ts.html +++ /dev/null @@ -1,212 +0,0 @@ - - - - - - Code coverage report for src/server.ts - - - - - - - - - -
-
-

All files / src server.ts

-
- -
- 90% - Statements - 9/10 -
- - -
- 50% - Branches - 1/2 -
- - -
- 100% - Functions - 1/1 -
- - -
- 90% - Lines - 9/10 -
- - -
-

- Press n or j to go to the next uncovered block, b, p or k for the previous block. -

-
-
-

-
1 -2 -3 -4 -5 -6 -7 -8 -9 -10 -11 -12 -13 -14 -15 -16 -17 -18 -19 -20 -21 -22 -23 -24 -25 -26 -27 -28 -29 -30 -31 -32 -33 -34 -35 -36 -37 -38 -39 -40 -41 -42 -43 -44 -45  -1x -1x -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -1x -  -  -  -  -  -  -169x -169x -169x -169x -169x -  -  -169x -  -  -  - 
import { IProxy } from "./httpClient";
-import Logger from "./logger";
-const log: Logger = new Logger();
- 
-export interface IBasicAuth {
-    "username": string;
-    "password": string;
-}
- 
-/**
- * The options of a server constructor
- */
-export interface IServerOptions {
-    /**
-     * the url of the nextcloud server like https://nextcloud.mydomain.com
-     */
-    "url": string;
-    /**
-     * basic authentication informatin to access the nextcloud server
-     */
-    "basicAuth": IBasicAuth;
-    "proxy"?: IProxy;
-    "logRequestResponse"?: boolean;
-}
- 
-// tslint:disable-next-line: max-classes-per-file
-export default class Server {
-    public url: string;
-    public basicAuth: IBasicAuth;
-    public proxy?: IProxy;
-    public logRequestResponse: boolean;
-    //    public constructor(url: string, basicAuth: IBasicAuth, proxy?: IProxy, logRequestResponse: boolean = false) {
-    public constructor(options: IServerOptions) {
-        log.debug("constructor");
-        this.url = options.url;
-        this.basicAuth = options.basicAuth;
-        this.proxy = options.proxy;
-        Iif (options.logRequestResponse) {
-            this.logRequestResponse = true;
-        } else {
-            this.logRequestResponse = false;
-        }
-    }
-}
- 
- -
-
- - - - - - - - - \ No newline at end of file diff --git a/docs/coverage/src/share.ts.html b/docs/coverage/src/share.ts.html deleted file mode 100644 index 20582e05..00000000 --- a/docs/coverage/src/share.ts.html +++ /dev/null @@ -1,755 +0,0 @@ - - - - - - Code coverage report for src/share.ts - - - - - - - - - -
-
-

All files / src share.ts

-
- -
- 98.36% - Statements - 60/61 -
- - -
- 100% - Branches - 26/26 -
- - -
- 94.74% - Functions - 18/19 -
- - -
- 98.36% - Lines - 60/61 -
- - -
-

- Press n or j to go to the next uncovered block, b, p or k for the previous block. -

-
-
-

-
1 -2 -3 -4 -5 -6 -7 -8 -9 -10 -11 -12 -13 -14 -15 -16 -17 -18 -19 -20 -21 -22 -23 -24 -25 -26 -27 -28 -29 -30 -31 -32 -33 -34 -35 -36 -37 -38 -39 -40 -41 -42 -43 -44 -45 -46 -47 -48 -49 -50 -51 -52 -53 -54 -55 -56 -57 -58 -59 -60 -61 -62 -63 -64 -65 -66 -67 -68 -69 -70 -71 -72 -73 -74 -75 -76 -77 -78 -79 -80 -81 -82 -83 -84 -85 -86 -87 -88 -89 -90 -91 -92 -93 -94 -95 -96 -97 -98 -99 -100 -101 -102 -103 -104 -105 -106 -107 -108 -109 -110 -111 -112 -113 -114 -115 -116 -117 -118 -119 -120 -121 -122 -123 -124 -125 -126 -127 -128 -129 -130 -131 -132 -133 -134 -135 -136 -137 -138 -139 -140 -141 -142 -143 -144 -145 -146 -147 -148 -149 -150 -151 -152 -153 -154 -155 -156 -157 -158 -159 -160 -161 -162 -163 -164 -165 -166 -167 -168 -169 -170 -171 -172 -173 -174 -175 -176 -177 -178 -179 -180 -181 -182 -183 -184 -185 -186 -187 -188 -189 -190 -191 -192 -193 -194 -195 -196 -197 -198 -199 -200 -201 -202 -203 -204 -205 -206 -207 -208 -209 -210 -211 -212 -213 -214 -215 -216 -217 -218 -219 -220 -221 -222 -223 -224 -225 -2261x -  -  -  -  -1x -1x -1x -1x -1x -1x -1x -  -  -1x -1x -1x -1x -1x -  -  -  -  -  -  -  -  -  -1x -1x -1x -  -1x -  -  -11x -11x -7x -  -  -  -3x -  -  -  -  -  -  -3x -  -  -  -  -  -3x -1x -  -  -3x -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -11x -11x -  -  -  -  -  -  -  -  -  -  -  -1x -  -  -  -1x -1x -  -  -  -  -  -  -  -1x -  -  -  -2x -1x -1x -  -  -  -  -1x -1x -  -  -  -11x -  -11x -1x -  -  -10x -1x -  -9x -  -9x -1x -  -8x -  -8x -1x -  -  -7x -5x -  -2x -  -7x -2x -  -  -7x -1x -  -  -  -  -  -  -  -  -  -  -  -2x -  -  -  -  -  -  -  -2x -  -  -  -  -  -  -  -1x -  -  -  -  -  -  -  -2x -  -  -  -  -  -  -  -2x -  -  -  -  -  -  -1x -  -  -  -  -  -  -  -  -  -  -  - 
import Client, { ClientError } from "./client";
-import File from "./file";
-import FileSystemElement from "./fileSystemElement";
-import Folder from "./folder";
- 
-export enum SharePermission {
-    all = 31,
-    read = 1,
-    update = 2,
-    create = 4,
-    delete = 8,
-    share = 16,
-}
- 
-enum ShareType {
-    user = 0,
-    group = 1,
-    publicLink = 3,
-    email = 4,
-}
- 
-export interface ICreateShare {
-    "fileSystemElement": FileSystemElement;
-    // @todo "shareWith"?: User | UserGroup | EMail;
-    "publicUpload"?: boolean;
-    "password"?: string;
-}
- 
-export enum ShareItemType {
-    file = "file",
-    folder = "folder",
-}
-export default class Share {
- 
-    public static async getShare(client: Client, id: string): Promise<Share> {
-        const share: Share = new Share(client, id);
-        await share.initialize();
-        return share;
-    }
- 
-    public static createShareRequestBody(createShare: ICreateShare): string {
-        const shareType: ShareType = ShareType.publicLink;
- 
-        const shareRequest: {
-            path: string,
-            shareType: number,
-            // @todo   permissions: number | number[]
-            password?: string,
-        } = {
-            path: createShare.fileSystemElement.name,
-            //  @todo    permissions: 1,
-            shareType,
-        };
- 
-        if (createShare.password) {
-            shareRequest.password = createShare.password;
-        }
- 
-        return JSON.stringify(shareRequest, null, 4);
-    }
- 
-    private client: Client;
-    private memento: {
-        expiration: Date | null,
-        id: string;
-        itemType: ShareItemType,
-        note: string,
-        token: string,
-        url: string,
-        publicUpload: boolean,
-        // share_type: number,
-        // "uid_owner": string,
-        // "displayname_owner": string,
-        // "permissions": SharePermission,
-        // "can_edit": boolean,
-        // "can_delete": boolean,
-        // "stime": Date,
-        // "parent"?: Share,
-        // "uid_file_owner": string,
-        // "label"?: string,
-        // "displayname_file_owner": string,
-        // "path": string,
-        // "mimetype"?: string,
-        // "share_with"?: string,
-        // "share_with_displayname"?: string,
-        // "mail_send": boolean,
-        // "hide_download": boolean,
-    };
- 
-    private constructor(client: Client, id: string) {
-        this.client = client;
-        this.memento = {
-            expiration: null,
-            id,
-            itemType: ShareItemType.file,
-            note: "",
-            token: "",
-            url: "",
-            publicUpload: false,
-        };
-    }
- 
-    public async delete(): Promise<void> {
-        await this.client.deleteShare(this.memento.id);
-    }
- 
-    public async setExpiration(expiration: Date): Promise<void> {
-        this.memento.expiration = expiration;
-        await this.client.updateShare(this.memento.id, { expireDate: expiration.toISOString().split("T")[0] });
-    }
- 
-    /**
-     * set a new password
-     * @param password
-     */
-    public async setPassword(password: string): Promise<void> {
-        await this.client.updateShare(this.memento.id, { password });
-    }
- 
-    public async setPublicUpload(): Promise<void> {
-        if (this.memento.itemType === ShareItemType.folder) {
-            this.memento.publicUpload = true;
-            await this.client.updateShare(this.memento.id, { permissions: 15 });
-        }
-    }
- 
-    public async setNote(note: string): Promise<void> {
-        this.memento.note = note;
-        await this.client.updateShare(this.memento.id, { note });
-    }
- 
-    private async initialize(): Promise<void> {
-        const rawShareData = await this.client.getShare(this.memento.id);
- 
-        if (!rawShareData.ocs || !rawShareData.ocs.data[0]) {
-            throw new ClientError(`Error invalid share data received "ocs.data" missing`, "ERR_INVALID_SHARE_RESPONSE");
-        }
- 
-        if (!rawShareData.ocs.data[0].url) {
-            throw new ClientError(`Error invalid share data received "url" missing`, "ERR_INVALID_SHARE_RESPONSE");
-        }
-        this.memento.url = rawShareData.ocs.data[0].url;
- 
-        if (!rawShareData.ocs.data[0].token) {
-            throw new ClientError(`Error invalid share data received "token" missing`, "ERR_INVALID_SHARE_RESPONSE");
-        }
-        this.memento.token = rawShareData.ocs.data[0].token;
- 
-        if (!rawShareData.ocs.data[0].item_type) {
-            throw new ClientError(`Error invalid share data received "item_type" missing`, "ERR_INVALID_SHARE_RESPONSE");
-        }
- 
-        if (rawShareData.ocs.data[0].item_type === "file") {
-            this.memento.itemType = ShareItemType.file;
-        } else {
-            this.memento.itemType = ShareItemType.folder;
-        }
-        if (rawShareData.ocs.data[0].expiration) {
-            this.memento.expiration = new Date(rawShareData.ocs.data[0].expiration);
-        }
- 
-        if (rawShareData.ocs.data[0].note) {
-            this.memento.note = rawShareData.ocs.data[0].note;
-        }
- 
-        // console.log(JSON.stringify(rawShareData, null, 4));
-        // console.log(JSON.stringify(this, null, 4));
-    }
- 
-    /**
-     * token
-     * The token is readonly
-     */
-    public get token(): string {
-        return this.memento.token;
-    }
- 
-    /**
-     * share url
-     * The share url is readonly
-     */
-    public get url(): string {
-        return this.memento.url;
-    }
- 
-    /**
-     * expiration
-     * The expiration is readonly
-     */
-    public get expiration(): Date | null {
-        return this.memento.expiration;
-    }
- 
-    /**
-     * note
-     * The note is readonly
-     */
-    public get note(): string {
-        return this.memento.note;
-    }
- 
-    /**
-     * id
-     * The id is readonly
-     */
-    public get id(): string {
-        return this.memento.id;
-    }
- 
-    /**
-     * returns true if the share akkows upload
-     */
-    public get publicUpload(): boolean {
-        return this.memento.publicUpload;
-    }
- 
-    /**
-     * item type
-     * The type of the share item file or folder
-     */
-    public get itemType(): ShareItemType {
-        return this.memento.itemType;
-    }
- 
-}
- 
- -
-
- - - - - - - - - \ No newline at end of file diff --git a/docs/coverage/src/tag.ts.html b/docs/coverage/src/tag.ts.html deleted file mode 100644 index 24281225..00000000 --- a/docs/coverage/src/tag.ts.html +++ /dev/null @@ -1,158 +0,0 @@ - - - - - - Code coverage report for src/tag.ts - - - - - - - - - -
-
-

All files / src tag.ts

-
- -
- 100% - Statements - 9/9 -
- - -
- 100% - Branches - 0/0 -
- - -
- 100% - Functions - 3/3 -
- - -
- 100% - Lines - 9/9 -
- - -
-

- Press n or j to go to the next uncovered block, b, p or k for the previous block. -

-
-
-

-
1 -2 -3 -4 -5 -6 -7 -8 -9 -10 -11 -12 -13 -14 -15 -16 -17 -18 -19 -20 -21 -22 -23 -24 -25 -26 -27  -  -  -1x -  -  -  -  -  -  -  -109x -109x -109x -109x -109x -109x -  -  -16x -  -  -8x -  -  -  - 
 
-import Client from "./client";
- 
-export default class Tag {
-    public readonly id: number;
-    public readonly name: string;
-    public readonly visible: boolean;
-    public readonly assignable: boolean;
-    public readonly canAssign: boolean;
-    private client: Client;
-    constructor(client: Client, id: number, name: string, visible: boolean, assignable: boolean, canAssign: boolean) {
-        this.client = client;
-        this.name = name;
-        this.visible = visible;
-        this.assignable = assignable;
-        this.canAssign = canAssign;
-        this.id = id;
-    }
-    public async delete(): Promise<void> {
-        return await this.client.deleteTag(this.id);
-    }
-    public toString(): string {
-        return "id:" + this.id + " name:" + this.name;
-    }
- 
-}
- 
- -
-
- - - - - - - - - \ No newline at end of file diff --git a/docs/coverage/src/uploadFilesCommand.ts.html b/docs/coverage/src/uploadFilesCommand.ts.html deleted file mode 100644 index 49b8cf88..00000000 --- a/docs/coverage/src/uploadFilesCommand.ts.html +++ /dev/null @@ -1,389 +0,0 @@ - - - - - - Code coverage report for src/uploadFilesCommand.ts - - - - - - - - - -
-
-

All files / src uploadFilesCommand.ts

-
- -
- 78.05% - Statements - 32/41 -
- - -
- 62.5% - Branches - 5/8 -
- - -
- 100% - Functions - 3/3 -
- - -
- 78.05% - Lines - 32/41 -
- - -
-

- Press n or j to go to the next uncovered block, b, p or k for the previous block. -

-
-
-

-
1 -2 -3 -4 -5 -6 -7 -8 -9 -10 -11 -12 -13 -14 -15 -16 -17 -18 -19 -20 -21 -22 -23 -24 -25 -26 -27 -28 -29 -30 -31 -32 -33 -34 -35 -36 -37 -38 -39 -40 -41 -42 -43 -44 -45 -46 -47 -48 -49 -50 -51 -52 -53 -54 -55 -56 -57 -58 -59 -60 -61 -62 -63 -64 -65 -66 -67 -68 -69 -70 -71 -72 -73 -74 -75 -76 -77 -78 -79 -80 -81 -82 -83 -84 -85 -86 -87 -88 -89 -90 -91 -92 -93 -94 -95 -96 -97 -98 -99 -100 -101 -102 -103 -104  -1x -  -  -1x -1x -1x -  -  -  -  -  -  -  -  -  -  -  -  -  -  -1x -  -  -  -  -  -  -  -  -  -  -1x -1x -1x -1x -  -  -  -  -  -  -  -  -1x -1x -1x -1x -  -1x -1x -  -  -  -  -  -1x -  -14x -14x -14x -14x -14x -14x -14x -  -  -  -  -  -  -  -  -14x -14x -14x -  -14x -  -  -  -  -  -  -  -  -  -1x -  -  -1x -  -  -1x -  -1x -  -  -  -37x -  -  -  - 
// tslint:disable-next-line:no-var-requires
-const debug = require("debug").debug("UploadFilesCommand");
- 
-import Client, { File } from "./client";
-import Command, { CommandStatus } from "./command";
-import util from "util";
-import fs from "fs";
- 
-export interface SourceTargetFileNames {
-    sourceFileName: string;
-    targetFileName: string;
-}
- 
-export interface UploadFilesCommandOptions {
-    files: SourceTargetFileNames[];
-    processFileAfterUpload?: (file: File) => Promise<void>;
-}
- 
-/**
- * Command to upload a set or files from local file system to nextcloud
- */
-export default class UploadFilesCommand extends Command {
-    private files: SourceTargetFileNames[];
-    private processFileAfterUpload?: (file: File) => Promise<void>;
-    private bytesUploaded: number;
- 
-    /**
-     * @param {Client} client the client
-     * @param {SourceTargetFileNames[]} files the files to be uploaded
-     * @param {(file: File) => void} processAfterUpload callback function to process the uploaded file
-     */
-    constructor(client: Client, options: UploadFilesCommandOptions) {
-        super(client);
-        this.files = options.files;
-        this.bytesUploaded = 0;
-        this.processFileAfterUpload = options.processFileAfterUpload;
-    }
- 
-    /**
-     * execute the command
-     * @async
-     * @returns {Promise<void>}
-     */
-    protected async onExecute(): Promise<void> {
-        this.status = CommandStatus.running;
-        try {
-            const readfile = util.promisify(fs.readFile);
-            let countCompleted = 0;
- 
-            this.percentCompleted = 0;
-            Iif (this.files.length === 0) {
-                this.percentCompleted = 100;
-            }
- 
-            let newFile: File | null;
- 
-            for (const file of this.files) {
-                let data: Buffer;
-                newFile = null;
-                try {
-                    data = await readfile(file.sourceFileName);
-                    try {
-                        newFile = await this.client.createFile(file.targetFileName, data);
-                        this.resultMetaData.messages.push(`${file.targetFileName}`);
-                        this.bytesUploaded += data.length;
-                    } catch (e) {
-                        this.resultMetaData.errors.push(`${file.targetFileName}: ${e.message}`);
-                        debug(file.targetFileName, e);
-                    }
-                } catch (e) {
-                    this.resultMetaData.errors.push(`${file.targetFileName}: ${e.message}`);
-                }
- 
-                countCompleted++;
-                this.percentCompleted = Math.round(countCompleted / this.files.length * 100);
-                debug(" completed:" + this.percentCompleted + "%");
- 
-                Iif (newFile && this.processFileAfterUpload) {
-                    await this.processFileAfterUpload(newFile);
-                }
-            }
- 
-        } catch (e) {
-            debug(e.message);
-            this.resultMetaData.errors.push(e.message);
-            this.percentCompleted = 100;
-        }
-        Iif (this.resultMetaData.errors.length > 0) {
-            this.status = CommandStatus.failed;
-        } else {
-            this.status = CommandStatus.success;
-        }
- 
-        debug("execute finished", this.percentCompleted, this.status);
- 
-        return;
-    };
- 
-    public getBytesUploaded(): number {
-        return this.bytesUploaded;
-    }
- 
-}
- 
- -
-
- - - - - - - - - \ No newline at end of file diff --git a/docs/coverage/src/uploadFolderCommand.ts.html b/docs/coverage/src/uploadFolderCommand.ts.html deleted file mode 100644 index ef121057..00000000 --- a/docs/coverage/src/uploadFolderCommand.ts.html +++ /dev/null @@ -1,413 +0,0 @@ - - - - - - Code coverage report for src/uploadFolderCommand.ts - - - - - - - - - -
-
-

All files / src uploadFolderCommand.ts

-
- -
- 80.43% - Statements - 37/46 -
- - -
- 50% - Branches - 2/4 -
- - -
- 71.43% - Functions - 5/7 -
- - -
- 80.95% - Lines - 34/42 -
- - -
-

- Press n or j to go to the next uncovered block, b, p or k for the previous block. -

-
-
-

-
1 -2 -3 -4 -5 -6 -7 -8 -9 -10 -11 -12 -13 -14 -15 -16 -17 -18 -19 -20 -21 -22 -23 -24 -25 -26 -27 -28 -29 -30 -31 -32 -33 -34 -35 -36 -37 -38 -39 -40 -41 -42 -43 -44 -45 -46 -47 -48 -49 -50 -51 -52 -53 -54 -55 -56 -57 -58 -59 -60 -61 -62 -63 -64 -65 -66 -67 -68 -69 -70 -71 -72 -73 -74 -75 -76 -77 -78 -79 -80 -81 -82 -83 -84 -85 -86 -87 -88 -89 -90 -91 -92 -93 -94 -95 -96 -97 -98 -99 -100 -101 -102 -103 -104 -105 -106 -107 -108 -109 -110 -111 -112  -1x -  -1x -  -  -  -  -  -  -  -  -1x -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -1x -  -  -  -  -  -  -  -  -  -  -  -1x -1x -1x -1x -1x -  -  -  -1x -  -  -  -  -  -  -  -  -1x -1x -1x -1x -1x -  -  -  -  -  -  -  -  -  -1x -1x -14x -  -14x -14x -  -  -  -1x -1x -1x -  -  -1x -36x -36x -36x -36x -  -36x -  -  -1x -1x -1x -1x -1x -  -  -  -  -  -  - 
// tslint:disable-next-line:no-var-requires
-const debug = require("debug").debug("UploadFolderCommand");
- 
-import Client,
-{
-    File,
-    FileSystemFolder,
-    IFileNameFormats,
-    UploadFilesCommand,
-    UploadFilesCommandOptions,
-    SourceTargetFileNames,
-} from "./client";
-import Command, { CommandStatus } from "./command";
- 
-/**
- * options to create a upload folder command
- */
-export interface UploadFolderCommandOptions {
-    /**
-     * The name of the source folder with the file structure to be uploaded
-     */
-    folderName: string;
-    /**
-     * the function to determine the target file name having the sourece file name.
-     * If the file should not be uploaded, return an empty string
-     * @param {SourceTargetFileNames} fileNames
-     */
-    getTargetFileNameBeforeUpload?: (fileNames: SourceTargetFileNames) => string;
-    processFileAfterUpload?: (file: File) => Promise<void>;
-}
- 
-/**
- * Command to upload the contents of a folder from local file system to nextcloud recursively
- */
-export default class UploadFolderCommand extends Command {
-    private folderName: string;
-    private processFileAfterUpload?: (file: File) => Promise<void>;
-    private getTargetFileNameBeforeUpload: (fileNames: SourceTargetFileNames) => string;
-    private bytesUploaded: number;
- 
-    /**
-     * @param {Client} client the client
-     * @param {ISourceTargetFileNames[]} files the files to be uploaded
-     * @param {(file: File) => void} processAfterUpload callback function to process the uploaded file
-     */
-    constructor(client: Client, options: UploadFolderCommandOptions) {
-        super(client);
-        this.folderName = options.folderName;
-        this.processFileAfterUpload = options.processFileAfterUpload;
-        Eif (options.getTargetFileNameBeforeUpload) {
-            this.getTargetFileNameBeforeUpload = options.getTargetFileNameBeforeUpload;
-        } else {
-            this.getTargetFileNameBeforeUpload = (fileNames: SourceTargetFileNames): string => { return fileNames.targetFileName };
-        }
-        this.bytesUploaded = 0;
-    }
- 
-    /**
-     * execute the command
-     * @async
-     * @returns {Promise<void>}
-     */
-    protected async onExecute(): Promise<void> {
-        this.status = CommandStatus.running;
-        let fileNames: IFileNameFormats[] = [];
-        const fsf: FileSystemFolder = new FileSystemFolder(this.folderName);
-        try {
-            fileNames = await fsf.getFileNames();
-        } catch (e) {
-            this.resultMetaData.errors.push(e);
-            this.status = CommandStatus.failed;
-            this.percentCompleted = 100;
-            this.bytesUploaded = 0;
-            this.resultMetaData.timeElapsed = 0;
-            return;
-        }
- 
-        const files: SourceTargetFileNames[] = [];
-        for (const fileNameFormat of fileNames) {
-            const targetFileName = this.getTargetFileNameBeforeUpload({ sourceFileName: fileNameFormat.absolute, targetFileName: fileNameFormat.relative });
-            // add only files with a target name
-            Eif (targetFileName !== "") {
-                files.push({ sourceFileName: fileNameFormat.absolute, targetFileName });
-            }
-        }
- 
-        const options: UploadFilesCommandOptions = { files, processFileAfterUpload: this.processFileAfterUpload };
-        const uc: UploadFilesCommand = new UploadFilesCommand(this.client, options);
-        uc.execute();
- 
-        // check the processing status
-        while (uc.isFinished() !== true) {
-            this.status = uc.getStatus();
-            this.percentCompleted = uc.getPercentCompleted();
-            this.resultMetaData = uc.getResultMetaData();
-            this.bytesUploaded = uc.getBytesUploaded();
-            // wait one second
-            await (async () => { return new Promise(resolve => setTimeout(resolve, 1000)) })();
-        }
- 
-        this.status = uc.getStatus();
-        this.percentCompleted = uc.getPercentCompleted();
-        this.resultMetaData = uc.getResultMetaData();
-        this.bytesUploaded = uc.getBytesUploaded();
-        return;
-    };
-    public getBytesUploaded(): number {
-        return this.bytesUploaded;
-    }
- 
-}
- 
- -
-
- - - - - - - - - \ No newline at end of file diff --git a/docs/coverage/src/user.ts.html b/docs/coverage/src/user.ts.html deleted file mode 100644 index 8549b58d..00000000 --- a/docs/coverage/src/user.ts.html +++ /dev/null @@ -1,1880 +0,0 @@ - - - - - - Code coverage report for src/user.ts - - - - - - - - - -
-
-

All files / src user.ts

-
- -
- 100% - Statements - 98/98 -
- - -
- 100% - Branches - 13/13 -
- - -
- 100% - Functions - 40/40 -
- - -
- 100% - Lines - 98/98 -
- - -
-

- Press n or j to go to the next uncovered block, b, p or k for the previous block. -

-
-
-

-
1 -2 -3 -4 -5 -6 -7 -8 -9 -10 -11 -12 -13 -14 -15 -16 -17 -18 -19 -20 -21 -22 -23 -24 -25 -26 -27 -28 -29 -30 -31 -32 -33 -34 -35 -36 -37 -38 -39 -40 -41 -42 -43 -44 -45 -46 -47 -48 -49 -50 -51 -52 -53 -54 -55 -56 -57 -58 -59 -60 -61 -62 -63 -64 -65 -66 -67 -68 -69 -70 -71 -72 -73 -74 -75 -76 -77 -78 -79 -80 -81 -82 -83 -84 -85 -86 -87 -88 -89 -90 -91 -92 -93 -94 -95 -96 -97 -98 -99 -100 -101 -102 -103 -104 -105 -106 -107 -108 -109 -110 -111 -112 -113 -114 -115 -116 -117 -118 -119 -120 -121 -122 -123 -124 -125 -126 -127 -128 -129 -130 -131 -132 -133 -134 -135 -136 -137 -138 -139 -140 -141 -142 -143 -144 -145 -146 -147 -148 -149 -150 -151 -152 -153 -154 -155 -156 -157 -158 -159 -160 -161 -162 -163 -164 -165 -166 -167 -168 -169 -170 -171 -172 -173 -174 -175 -176 -177 -178 -179 -180 -181 -182 -183 -184 -185 -186 -187 -188 -189 -190 -191 -192 -193 -194 -195 -196 -197 -198 -199 -200 -201 -202 -203 -204 -205 -206 -207 -208 -209 -210 -211 -212 -213 -214 -215 -216 -217 -218 -219 -220 -221 -222 -223 -224 -225 -226 -227 -228 -229 -230 -231 -232 -233 -234 -235 -236 -237 -238 -239 -240 -241 -242 -243 -244 -245 -246 -247 -248 -249 -250 -251 -252 -253 -254 -255 -256 -257 -258 -259 -260 -261 -262 -263 -264 -265 -266 -267 -268 -269 -270 -271 -272 -273 -274 -275 -276 -277 -278 -279 -280 -281 -282 -283 -284 -285 -286 -287 -288 -289 -290 -291 -292 -293 -294 -295 -296 -297 -298 -299 -300 -301 -302 -303 -304 -305 -306 -307 -308 -309 -310 -311 -312 -313 -314 -315 -316 -317 -318 -319 -320 -321 -322 -323 -324 -325 -326 -327 -328 -329 -330 -331 -332 -333 -334 -335 -336 -337 -338 -339 -340 -341 -342 -343 -344 -345 -346 -347 -348 -349 -350 -351 -352 -353 -354 -355 -356 -357 -358 -359 -360 -361 -362 -363 -364 -365 -366 -367 -368 -369 -370 -371 -372 -373 -374 -375 -376 -377 -378 -379 -380 -381 -382 -383 -384 -385 -386 -387 -388 -389 -390 -391 -392 -393 -394 -395 -396 -397 -398 -399 -400 -401 -402 -403 -404 -405 -406 -407 -408 -409 -410 -411 -412 -413 -414 -415 -416 -417 -418 -419 -420 -421 -422 -423 -424 -425 -426 -427 -428 -429 -430 -431 -432 -433 -434 -435 -436 -437 -438 -439 -440 -441 -442 -443 -444 -445 -446 -447 -448 -449 -450 -451 -452 -453 -454 -455 -456 -457 -458 -459 -460 -461 -462 -463 -464 -465 -466 -467 -468 -469 -470 -471 -472 -473 -474 -475 -476 -477 -478 -479 -480 -481 -482 -483 -484 -485 -486 -487 -488 -489 -490 -491 -492 -493 -494 -495 -496 -497 -498 -499 -500 -501 -502 -503 -504 -505 -506 -507 -508 -509 -510 -511 -512 -513 -514 -515 -516 -517 -518 -519 -520 -521 -522 -523 -524 -525 -526 -527 -528 -529 -530 -531 -532 -533 -534 -535 -536 -537 -538 -539 -540 -541 -542 -543 -544 -545 -546 -547 -548 -549 -550 -551 -552 -553 -554 -555 -556 -557 -558 -559 -560 -561 -562 -563 -564 -565 -566 -567 -568 -569 -570 -571 -572 -573 -574 -575 -576 -577 -578 -579 -580 -581 -582 -583 -584 -585 -586 -587 -588 -589 -590 -591 -592 -593 -594 -595 -596 -597 -598 -599 -600 -6011x -1x -  -1x -1x -1x -1x -1x -1x -1x -1x -1x -1x -1x -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -1x -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -43x -43x -43x -  -  -  -  -  -  -  -  -  -  -  -  -  -17x -  -  -  -  -  -  -  -  -  -4x -4x -  -  -  -  -  -  -  -  -  -3x -3x -  -  -  -  -  -  -  -  -  -2x -2x -1x -  -1x -  -  -  -  -  -  -  -  -  -7x -  -  -  -  -  -  -  -  -  -  -  -5x -4x -  -  -  -  -  -  -  -  -  -6x -  -  -  -  -  -  -  -  -  -7x -  -7x -  -  -  -  -7x -1x -  -  -7x -1x -  -7x -  -  -  -  -  -  -  -  -  -  -  -6x -4x -  -  -  -  -  -  -  -  -  -7x -  -  -  -  -  -  -  -  -  -  -  -5x -3x -  -  -  -  -  -  -  -  -  -  -  -  -7x -  -  -  -  -  -  -  -  -  -  -  -5x -4x -  -  -  -  -  -  -  -  -  -  -  -  -7x -  -  -  -  -  -  -  -  -  -  -  -4x -3x -  -  -  -  -  -  -  -  -  -  -  -  -  -7x -  -  -  -  -  -  -  -  -  -  -  -4x -3x -  -  -  -  -  -  -  -  -  -  -  -  -  -7x -  -  -  -  -  -  -  -  -  -  -  -4x -3x -  -  -  -  -  -  -  -  -  -  -  -  -  -6x -  -  -  -  -  -  -  -  -  -  -  -5x -2x -  -  -  -  -  -  -  -  -  -  -  -  -  -6x -  -  -  -  -  -  -  -  -  -  -  -5x -2x -  -  -  -  -  -  -  -  -  -  -  -7x -  -  -  -  -  -  -  -  -  -  -  -  -  -4x -  -  -  -  -  -  -  -  -  -  -  -  -  -3x -3x -3x -3x -  -3x -  -  -  -  -  -  -  -  -  -8x -  -  -  -  -  -  -  -  -  -  -  -  -  -11x -9x -9x -  -  -  -  -  -  -  -  -  -  -  -  -  -10x -7x -7x -  -  -  -  -  -  -  -  -  -  -  -  -  -15x -  -  -  -  -  -  -  -  -  -  -  -  -2x -1x -1x -  -  -  -  -  -  -  -  -  -  -  -  -  -3x -3x -2x -  -2x -  -  -  -  -  -  -  -  -  -  -  -  -  -3x -3x -3x -3x -  -3x -  -  -  -  -  -  -  -  -  -8x -  -  -  -  -  -  -  -  -  -  -  -  -  -9x -8x -8x -  -  -  -  -  -  -  -  -  -  -  -  -  -6x -4x -4x -  -  -  -  -  -  -  -  -  -9x -  -  -  -  -  -  -  -  -  -123x -71x -  -123x -  -  -  - 
import Client, { ClientError, IQuota, UserGroup, UserGroupDoesNotExistError } from "./client";
-import FileSizeFormatter from "./fileSizeFormatter";
- 
-export enum UserProperty {
-    email = "email",
-    quota = "quota",
-    displayName = "displayname",
-    phone = "phone",
-    address = "address",
-    website = "website",
-    twitter = "twitter",
-    password = "password",
-    language = "language",
-    locale = "locale",
-}
- 
-export interface IUserOptionsQuota {
-    "free"?: number,
-    "used": number,
-    "total"?: number,
-    "relative": number,
-    "quota": number
-}
- 
-export interface IUserQuotaUserFriendly {
-    "free"?: string,
-    "used": string,
-    "total"?: string,
-    "quota": string,
-    "relative": string
-}
- 
-export interface IUserOptions {
-    "enabled": boolean;
-    "lastLogin"?: Date,
-    "subadminGroups": string[],
-    "memberGroups": string[],
-    "quota": IUserOptionsQuota,
-    "email": string,
-    "displayName": string,
-    "phone": string,
-    "address": string,
-    "website": string,
-    "twitter": string,
-    "language": string
-    "locale": string,
-}
- 
-/**
- * The user class represents a user in nextcloud.
- * async getGroups
- * async isDisabled
- * async getLastLogin
- * async getEmail
- * getId
- * async getDisplayName
- */
-export default class User {
-    // https://docs.nextcloud.com/server/latest/admin_manual/configuration_user/user_provisioning_api.html
- 
-    private memento?: IUserOptions;
-    private client: Client;
-    readonly id: string;
- 
-    /**
-     * the conscructor of the user
-     * should only me invoked by the Client
-     * @constructor
-     * @param {Client} client
-     * @param {string} id the user id
-     * @param {IUserOptions} options optional options
-     */
-    constructor(client: Client, id: string, options?: IUserOptions) {
-        this.id = id;
-        this.client = client;
-        this.memento = options;
-    }
- 
-    // **********************************
-    // enable disable
-    // **********************************
- 
-    /**
-     * returns true if the user is enabled
-     * @async
-     * @returns {Promise<boolean>} true if the user is enabled
-     * @throws {UserNotFoundError}
-     */
-    async isEnabled(): Promise<boolean> {
-        return (await this.getUserData()).enabled;
-    }
- 
-    /**
-     * disables the user
-     * @async
-     * @returns {Promise<void>}
-     * @throws {UserNotFoundError}
-     */
-    async disable(): Promise<void> {
-        delete this.memento;
-        return await this.client.disableUser(this.id);
-    }
- 
-    /**
-     * enables the user
-     * @async
-     * @returns {Promise<void>}
-     * @throws {UserNotFoundError}
-     */
-    async enable(): Promise<void> {
-        delete this.memento;
-        return await this.client.enableUser(this.id);
-    }
- 
-    /**
-     * get the last login date or null if the user has not been logged in yet
-     * @async
-     * @returns {Promise<Date | null>} last login date or null if the user has not been logged in yet
-     * @throws {UserNotFoundError}
-     */
-    async getLastLogin(): Promise<Date | null> {
-        const data: IUserOptions = await this.getUserData();
-        if (data.lastLogin) {
-            return data.lastLogin;
-        }
-        return null;
-    }
- 
-    /**
-     * returns the display name
-     * @async
-     * @returns {Promise<string>} display name
-     * @throws {UserNotFoundError}
-     */
-    async getDisplayName(): Promise<string> {
-        return (await this.getUserData()).displayName;
-    }
- 
-    /**
-     * set the display name
-     * @async
-     * @param {string} value the display name
-     * @returns {Promise<void>}
-     * @throws {UserNotFoundError}
-     * @throws {UserUpdateError}
-     */
-    async setDisplayName(value: string): Promise<void> {
-        await this.client.updateUserProperty(this.id, UserProperty.displayName, value);
-        delete this.memento;
-    }
- 
-    /**
-     * returns information on quota, usage and available space
-     * @async
-     * @returns {Promise<IUserOptionsQuota>}
-     * @throws {UserNotFoundError}
-     */
-    async getQuota(): Promise<IUserOptionsQuota> {
-        return (await this.getUserData()).quota;
-    }
- 
-    /**
-     * returns information on quota, usage and available space in a user friendly format
-     * @async
-     * @returns {Promise<IUserQuotaUserFriendly>}
-     * @throws {UserNotFoundError}
-     */
-    async getQuotaUserFriendly(): Promise<IUserQuotaUserFriendly> {
-        const q: IUserOptionsQuota = (await this.getUserData()).quota;
- 
-        const qUF: IUserQuotaUserFriendly = {
-            used: new FileSizeFormatter(q.used).getUserFriendlyFileSize(),
-            quota: new FileSizeFormatter(q.quota).getUserFriendlyFileSize(),
-            relative: Math.round(q.relative) + " %"
-        }
-        if (q.total) {
-            qUF.total = new FileSizeFormatter(q.total).getUserFriendlyFileSize();
-        }
- 
-        if (q.free) {
-            qUF.free = new FileSizeFormatter(q.free).getUserFriendlyFileSize();
-        }
-        return qUF;
-    }
- 
-    /**
-     * sets the quota limit of the user
-     * @async
-     * @param {string} value the quota string like "1 GB", "100 MB"
-     * @returns {Promise<void>}
-     * @throws {UserNotFoundError}
-     * @throws {UserUpdateError}
-     */
-    async setQuota(value: string): Promise<void> {
-        await this.client.updateUserProperty(this.id, UserProperty.quota, value);
-        delete this.memento;
-    }
- 
-    /**
-     * returns the email address
-     * @async
-     * @returns {Promise<string>} email adress
-     * @throws {UserNotFoundError}
-     */
-    async getEmail(): Promise<string> {
-        return (await this.getUserData()).email;
-    }
- 
-    /**
-     * set the email address
-     * @async
-     * @param {string} value the email address
-     * @returns {Promise<void>}
-     * @throws {UserNotFoundError}
-     * @throws {UserUpdateError}
-     */
-    async setEmail(value: string): Promise<void> {
-        await this.client.updateUserProperty(this.id, UserProperty.email, value);
-        delete this.memento;
-    }
- 
-    // **********************************
-    // phone
-    // **********************************
-    /**
-     * returns the phone number
-     * @async
-     * @returns {Promise<string>} phone number
-     * @throws {UserNotFoundError}
-     */
-    async getPhone(): Promise<string> {
-        return (await this.getUserData()).phone;
-    }
- 
-    /**
-     * set phone number
-     * @async
-     * @param {string} value the phone number
-     * @returns {Promise<void>}
-     * @throws {UserNotFoundError}
-     * @throws {UserUpdateError}
-     */
-    async setPhone(value: string): Promise<void> {
-        await this.client.updateUserProperty(this.id, UserProperty.phone, value);
-        delete this.memento;
-    }
- 
-    // **********************************
-    // address
-    // **********************************
-    /**
-     * returns the phone number
-     * @async
-     * @returns {Promise<string>} address
-     * @throws {UserNotFoundError}
-     */
-    async getAddress(): Promise<string> {
-        return (await this.getUserData()).address;
-    }
- 
-    /**
-     * set the address
-     * @async
-     * @param {string} value the address
-     * @returns {Promise<void>}
-     * @throws {UserNotFoundError}
-     * @throws {UserUpdateError}
-     */
-    async setAddress(value: string): Promise<void> {
-        await this.client.updateUserProperty(this.id, UserProperty.address, value);
-        delete this.memento;
-    }
- 
-    // **********************************
-    // website
-    // **********************************
- 
-    /**
-     * returns the website
-     * @async
-     * @returns {Promise<string>} website
-     * @throws {UserNotFoundError}
-     */
-    async getWebsite(): Promise<string> {
-        return (await this.getUserData()).website;
-    }
- 
-    /**
-     * set the website
-     * @async
-     * @param {string} value the website
-     * @returns {Promise<void>}
-     * @throws {UserNotFoundError}
-     * @throws {UserUpdateError}
-     */
-    async setWebsite(value: string): Promise<void> {
-        await this.client.updateUserProperty(this.id, UserProperty.website, value);
-        delete this.memento;
-    }
- 
-    // **********************************
-    // twitter
-    // **********************************
- 
-    /**
-     * returns the twitter handle
-     * @async
-     * @returns {Promise<string>} twitter handle
-     * @throws {UserNotFoundError}
-     */
-    async getTwitter(): Promise<string> {
-        return (await this.getUserData()).twitter;
-    }
- 
-    /**
-     * set the twitter handle
-     * @async
-     * @param {string} value the twitter handle
-     * @returns {Promise<void>}
-     * @throws {UserNotFoundError}
-     * @throws {UserUpdateError}
-     */
-    async setTwitter(value: string): Promise<void> {
-        await this.client.updateUserProperty(this.id, UserProperty.twitter, value);
-        delete this.memento;
-    }
- 
-    // **********************************
-    // language
-    // **********************************
- 
-    /**
-     * returns the langauge code
-     * @async
-     * @returns {Promise<string>} language code
-     * @throws {UserNotFoundError}
-     */
-    async getLanguage(): Promise<string> {
-        return (await this.getUserData()).language;
-    }
- 
-    /**
-     * set the language code like EN, DE, FR...
-     * @async
-     * @param {string} value the language code
-     * @returns {Promise<void>}
-     * @throws {UserNotFoundError}
-     * @throws {UserUpdateError}
-     */
-    async setLanguage(value: string): Promise<void> {
-        await this.client.updateUserProperty(this.id, UserProperty.language, value);
-        delete this.memento;
-    }
- 
-    // **********************************
-    // locale
-    // **********************************
- 
-    /**
-     * returns the locale
-     * @async
-     * @returns {Promise<string>} locale
-     * @throws {UserNotFoundError}
-     */
-    async getLocale(): Promise<string> {
-        return (await this.getUserData()).locale;
-    }
- 
-    /**
-     * set the locale like EN, DE, FR...
-     * @async
-     * @param {string} value the locale
-     * @returns {Promise<void>}
-     * @throws {UserNotFoundError}
-     * @throws {UserUpdateError}
-     */
-    async setLocale(value: string): Promise<void> {
-        await this.client.updateUserProperty(this.id, UserProperty.locale, value);
-        delete this.memento;
-    }
- 
-    /**
-     * set the password
-     * @async
-     * @param {string} value the password
-     * @returns {Promise<void>}
-     * @throws {UserNotFoundError}
-     * @throws {UserUpdateError}
-     */
-    async setPassword(value: string): Promise<void> {
-        await this.client.updateUserProperty(this.id, UserProperty.password, value);
-    }
- 
-    // **********************************
-    // Resend the welcome email
-    // **********************************
- 
-    /**
-     * resends the welcome email
-     * @async
-     * @returns {Promise<void>}
-     * @throws  {UserResendWelcomeEmailError}
-     */
-    async resendWelcomeEmail(): Promise<void> {
-        await this.client.resendWelcomeEmail(this.id);
-    }
- 
-    // **********************************
-    // user group member
-    // **********************************
- 
-    /**
-     * returns a list of user groups where the user is member
-     * @async
-     * @returns {Promise<UserGroup[]} a list of user groups where the user is member
-     * @throws {UserNotFoundError}
-     */
-    async getMemberUserGroups(): Promise<UserGroup[]> {
-        const groupIds: string[] = (await this.getUserData()).memberGroups;
-        const result: UserGroup[] = [];
-        for (const groupId of groupIds) {
-            result.push(new UserGroup(this.client, groupId));
-        }
-        return result;
-    }
- 
-    /**
-     * returns a list of user group ids where the user is member
-     * @async
-     * @returns {Promise<string[]} a list of user group ids where the user is member
-     * @throws {UserNotFoundError}
-     */
-    async getMemberUserGroupIds(): Promise<string[]> {
-        return (await this.getUserData()).memberGroups;
-    }
- 
-    /**
-     * adds the user to a user group as member
-     * @async
-     * @param {UserGroup} userGroup the user group
-     * @returns {Promise<void>}
-     * @throws {UserNotFoundError}
-     * @throws {UserGroupDoesNotExistError}
-     * @throws {InsufficientPrivilegesError}
-     * @throws {OperationFailedError}
-     */
-    async addToMemberUserGroup(userGroup: UserGroup): Promise<void> {
-        await this.client.addUserToMemberUserGroup(this.id, userGroup.id);
-        delete this.memento;
-        return;
-    }
- 
-    /**
-     * remove the user from a user group as member
-     * @async
-     * @param {UserGroup} userGroup the user group
-     * @returns {Promise<void>}
-     * @throws {UserNotFoundError}
-     * @throws {UserGroupDoesNotExistError}
-     * @throws {InsufficientPrivilegesError}
-     * @throws {OperationFailedError}
-     */
-    async removeFromMemberUserGroup(userGroup: UserGroup): Promise<void> {
-        await this.client.removeUserFromMemberUserGroup(this.id, userGroup.id);
-        delete this.memento;
-        return
-    }
- 
-    // **********************************
-    // user superadmin
-    // **********************************
- 
-    /**
-     * true if the user is a superadmin
-     * @async
-     * @returns {Promise<boolean>} true if the user is a superadmin
-     * @throws {UserNotFoundError}
-     */
-    async isSuperAdmin(): Promise<boolean> {
-        return (await this.getUserData()).memberGroups.indexOf("admin") === -1 ? false : true;
-    }
- 
-    /**
-     * promote user to super admin
-     * @async
-     * @returns {Promise<void>}
-     * @throws {UserNotFoundError}
-     * @throws {UserGroupDoesNotExistError}
-     * @throws {InsufficientPrivilegesError}
-     * @throws {OperationFailedError}
-     */
-    async promoteToSuperAdmin(): Promise<void> {
-        await this.addToMemberUserGroup(new UserGroup(this.client, "admin"));
-        delete this.memento;
-        return;
-    }
- 
-    /**
-     * demote user from being a super admin
-     * @async
-     * @returns {Promise<void>}
-     * @throws {UserNotFoundError}
-     * @throws {UserGroupDoesNotExistError}
-     * @throws {InsufficientPrivilegesError}
-     * @throws {OperationFailedError}
-     */
-    async demoteFromSuperAdmin(): Promise<void> {
-        /* istanbul ignore else */
-        if (await this.isSuperAdmin()) {
-            await this.removeFromMemberUserGroup(new UserGroup(this.client, "admin"));
-            delete this.memento;
-        }
-        return;
-    }
- 
-    // **********************************
-    // user group subadmin
-    // **********************************
- 
-    /**
-     * returns a list of user groups where the user is subadmin
-     * @async
-     * @returns {Promise<UserGroup[]} a list of user groups where the user is subadmin
-     * @throws {UserNotFoundError}
-     */
-    async getSubadminUserGroups(): Promise<UserGroup[]> {
-        const groupIds: string[] = (await this.getUserData()).subadminGroups;
-        const result: UserGroup[] = [];
-        for (const groupId of groupIds) {
-            result.push(new UserGroup(this.client, groupId));
-        }
-        return result;
-    }
- 
-    /**
-     * returns a list of user group ids where the user is subadmin
-     * @async
-     * @returns {Promise<string[]} a list of user group ids where the user is subadmin
-     * @throws {UserNotFoundError}
-     */
-    async getSubadminUserGroupIds(): Promise<string[]> {
-        return (await this.getUserData()).subadminGroups;
-    }
- 
-    /**
-     * promote the user to be a subadmin of the user group
-     * @async
-     * @param {UserGroup} userGroup the user group
-     * @returns {Promise<void>}
-     * @throws {UserNotFoundError}
-     * @throws {UserGroupDoesNotExistError}
-     * @throws {InsufficientPrivilegesError}
-     * @throws {OperationFailedError}
-     */
-    async promoteToUserGroupSubadmin(userGroup: UserGroup): Promise<void> {
-        await this.client.promoteUserToUserGroupSubadmin(this.id, userGroup.id);
-        delete this.memento;
-        return
-    }
- 
-    /**
-     * demote the user from beeing a subadmin of the user group
-     * @async
-     * @param {UserGroup} userGroup the user group
-     * @returns {Promise<void>}
-     * @throws {UserNotFoundError}
-     * @throws {UserGroupDoesNotExistError}
-     * @throws {InsufficientPrivilegesError}
-     * @throws {OperationFailedError}
-     */
-    async demoteFromSubadminUserGroup(userGroup: UserGroup): Promise<void> {
-        await this.client.demoteUserFromSubadminUserGroup(this.id, userGroup.id);
-        delete this.memento;
-        return
-    }
- 
-    /**
-     * deletes a user
-     * @async
-     * @returns {Promise<void>}
-     * @throws {UserNotFoundError}
-     */
-    async delete(): Promise<void> {
-        return await this.client.deleteUser(this.id);
-    }
- 
-    /**
-     * returns the user data
-     * @async
-     * @returns {Promise<IUserOptions>}
-     * @throws {UserNotFoundError}
-     */
-    private async getUserData(): Promise<IUserOptions> {
-        if (!this.memento) {
-            this.memento = await this.client.getUserData(this.id);
-        }
-        return this.memento;
-    }
- 
-}
- 
- -
-
- - - - - - - - - \ No newline at end of file diff --git a/docs/coverage/src/userGroup.ts.html b/docs/coverage/src/userGroup.ts.html deleted file mode 100644 index 6054fcd6..00000000 --- a/docs/coverage/src/userGroup.ts.html +++ /dev/null @@ -1,203 +0,0 @@ - - - - - - Code coverage report for src/userGroup.ts - - - - - - - - - -
-
-

All files / src userGroup.ts

-
- -
- 100% - Statements - 11/11 -
- - -
- 100% - Branches - 2/2 -
- - -
- 100% - Functions - 4/4 -
- - -
- 100% - Lines - 11/11 -
- - -
-

- Press n or j to go to the next uncovered block, b, p or k for the previous block. -

-
-
-

-
1 -2 -3 -4 -5 -6 -7 -8 -9 -10 -11 -12 -13 -14 -15 -16 -17 -18 -19 -20 -21 -22 -23 -24 -25 -26 -27 -28 -29 -30 -31 -32 -33 -34 -35 -36 -37 -38 -39 -40 -41 -421x -  -  -  -  -  -  -  -  -1x -  -  -  -52x -52x -  -  -  -  -  -  -  -  -4x -4x -  -2x -1x -  -1x -  -  -  -  -1x -  -  -  -1x -  -  - 
import Client, { UserGroupDeletionFailedError, UserGroupDoesNotExistError } from "./client";
- 
-/**
- * The user group class represents a user user in nextcloud.
- * spec: https://docs.nextcloud.com/server/latest/admin_manual/configuration_user/instruction_set_for_groups.html
- * id
- * getSubAdmins
- * getMembers
- */
-export default class UserGroup {
-    readonly id: string;
-    private client: Client;
-    constructor(client: Client, id: string) {
-        this.id = id;
-        this.client = client;
-    }
- 
-    /**
-     * deletes the user group
-     * @throws UserGroupDeletionFailedError
-     */
-    public async delete(): Promise<void> {
- 
-        try {
-            return await this.client.deleteUserGroup(this.id);
-        } catch (e) {
-            if (e instanceof UserGroupDoesNotExistError) {
-                return;
-            }
-            throw e;
-        }
-    }
- 
-    public async getMemberUserIds(): Promise<string[]> {
-        return await this.client.getUserGroupMembers(this.id);
-    }
- 
-    public async getSubadminUserIds(): Promise<string[]> {
-        return await this.client.getUserGroupSubadmins(this.id);
-    }
-}
- 
- -
-
- - - - - - - - - \ No newline at end of file diff --git a/docs/coverage/tag.ts.html b/docs/coverage/tag.ts.html deleted file mode 100644 index 88577822..00000000 --- a/docs/coverage/tag.ts.html +++ /dev/null @@ -1,158 +0,0 @@ - - - - - - Code coverage report for tag.ts - - - - - - - - - -
-
-

All files tag.ts

-
- -
- 100% - Statements - 9/9 -
- - -
- 100% - Branches - 0/0 -
- - -
- 100% - Functions - 3/3 -
- - -
- 100% - Lines - 9/9 -
- - -
-

- Press n or j to go to the next uncovered block, b, p or k for the previous block. -

-
-
-

-
1 -2 -3 -4 -5 -6 -7 -8 -9 -10 -11 -12 -13 -14 -15 -16 -17 -18 -19 -20 -21 -22 -23 -24 -25 -26 -27  -  -  -1x -  -  -  -  -  -  -  -145x -145x -145x -145x -145x -145x -  -  -22x -  -  -8x -  -  -  - 
 
-import Client from "./client";
- 
-export default class Tag {
-    public readonly id: number;
-    public readonly name: string;
-    public readonly visible: boolean;
-    public readonly assignable: boolean;
-    public readonly canAssign: boolean;
-    private client: Client;
-    constructor(client: Client, id: number, name: string, visible: boolean, assignable: boolean, canAssign: boolean) {
-        this.client = client;
-        this.name = name;
-        this.visible = visible;
-        this.assignable = assignable;
-        this.canAssign = canAssign;
-        this.id = id;
-    }
-    public async delete(): Promise<void> {
-        return await this.client.deleteTag(this.id);
-    }
-    public toString(): string {
-        return "id:" + this.id + " name:" + this.name;
-    }
- 
-}
- 
- -
-
- - - - - - - - - \ No newline at end of file diff --git a/docs/coverage/uploadFilesCommand.ts.html b/docs/coverage/uploadFilesCommand.ts.html deleted file mode 100644 index 38b29ab8..00000000 --- a/docs/coverage/uploadFilesCommand.ts.html +++ /dev/null @@ -1,395 +0,0 @@ - - - - - - Code coverage report for uploadFilesCommand.ts - - - - - - - - - -
-
-

All files uploadFilesCommand.ts

-
- -
- 100% - Statements - 43/43 -
- - -
- 100% - Branches - 8/8 -
- - -
- 100% - Functions - 3/3 -
- - -
- 100% - Lines - 43/43 -
- - -
-

- Press n or j to go to the next uncovered block, b, p or k for the previous block. -

-
-
-

-
1 -2 -3 -4 -5 -6 -7 -8 -9 -10 -11 -12 -13 -14 -15 -16 -17 -18 -19 -20 -21 -22 -23 -24 -25 -26 -27 -28 -29 -30 -31 -32 -33 -34 -35 -36 -37 -38 -39 -40 -41 -42 -43 -44 -45 -46 -47 -48 -49 -50 -51 -52 -53 -54 -55 -56 -57 -58 -59 -60 -61 -62 -63 -64 -65 -66 -67 -68 -69 -70 -71 -72 -73 -74 -75 -76 -77 -78 -79 -80 -81 -82 -83 -84 -85 -86 -87 -88 -89 -90 -91 -92 -93 -94 -95 -96 -97 -98 -99 -100 -101 -102 -103 -104 -105 -106  -1x -  -  -1x -1x -1x -  -  -  -  -  -  -  -  -  -  -  -  -  -  -1x -  -  -  -  -  -  -  -  -  -  -9x -9x -9x -9x -  -  -  -  -  -  -  -  -9x -9x -9x -9x -9x -  -9x -9x -1x -  -  -  -  -9x -  -60x -60x -60x -59x -59x -58x -58x -  -1x -1x -  -  -1x -  -  -60x -60x -60x -  -60x -2x -  -  -  -  -1x -1x -1x -  -9x -3x -  -6x -  -9x -  -9x -  -9x -  -  -  -7x -  -  -  - 
// tslint:disable-next-line:no-var-requires
-const debug = require("debug").debug("UploadFilesCommand");
- 
-import Client, { File } from "./client";
-import Command, { CommandStatus } from "./command";
-import util from "util";
-import fs from "fs";
- 
-export interface SourceTargetFileNames {
-    sourceFileName: string;
-    targetFileName: string;
-}
- 
-export interface UploadFilesCommandOptions {
-    files: SourceTargetFileNames[];
-    processFileAfterUpload?: (file: File) => Promise<void>;
-}
- 
-/**
- * Command to upload a set or files from local file system to nextcloud
- */
-export default class UploadFilesCommand extends Command {
-    private files: SourceTargetFileNames[];
-    private processFileAfterUpload?: (file: File) => Promise<void>;
-    private bytesUploaded: number;
- 
-    /**
-     * @param {Client} client the client
-     * @param {SourceTargetFileNames[]} files the files to be uploaded
-     * @param {(file: File) => void} processAfterUpload callback function to process the uploaded file
-     */
-    constructor(client: Client, options: UploadFilesCommandOptions) {
-        super(client);
-        this.files = options.files;
-        this.bytesUploaded = 0;
-        this.processFileAfterUpload = options.processFileAfterUpload;
-    }
- 
-    /**
-     * execute the command
-     * @async
-     * @returns {Promise<void>}
-     */
-    protected async onExecute(): Promise<void> {
-        this.status = CommandStatus.running;
-        const startTime = new Date();
-        try {
-            const readfile = util.promisify(fs.readFile);
-            let countCompleted = 0;
- 
-            this.percentCompleted = 0;
-            if (this.files.length === 0) {
-                this.percentCompleted = 100;
-            }
- 
-            let newFile: File | null;
- 
-            for (const file of this.files) {
-                let data: Buffer;
-                newFile = null;
-                try {
-                    data = await readfile(file.sourceFileName);
-                    try {
-                        newFile = await this.client.createFile(file.targetFileName, data);
-                        this.resultMetaData.messages.push(`${file.targetFileName}`);
-                        this.bytesUploaded += data.length;
-                    } catch (e) {
-                        this.resultMetaData.errors.push(`${file.targetFileName}: ${e.message}`);
-                        debug(file.targetFileName, e);
-                    }
-                } catch (e) {
-                    this.resultMetaData.errors.push(`${file.targetFileName}: ${e.message}`);
-                }
- 
-                countCompleted++;
-                this.percentCompleted = Math.round(countCompleted / this.files.length * 100);
-                debug(" completed:" + this.percentCompleted + "%");
- 
-                if (newFile && this.processFileAfterUpload) {
-                    await this.processFileAfterUpload(newFile);
-                }
-            }
- 
-        } catch (e) {
-            debug(e.message);
-            this.resultMetaData.errors.push(e.message);
-            this.percentCompleted = 100;
-        }
-        if (this.resultMetaData.errors.length > 0) {
-            this.status = CommandStatus.failed;
-        } else {
-            this.status = CommandStatus.success;
-        }
-        this.resultMetaData.timeElapsed = new Date().getTime() - startTime.getTime();
- 
-        debug("execute finished", this.percentCompleted, this.status);
- 
-        return;
-    };
- 
-    public getBytesUploaded(): number {
-        return this.bytesUploaded;
-    }
- 
-}
- 
- -
-
- - - - - - - - - \ No newline at end of file diff --git a/docs/coverage/uploadFolderCommand.ts.html b/docs/coverage/uploadFolderCommand.ts.html deleted file mode 100644 index 6d3d5228..00000000 --- a/docs/coverage/uploadFolderCommand.ts.html +++ /dev/null @@ -1,413 +0,0 @@ - - - - - - Code coverage report for uploadFolderCommand.ts - - - - - - - - - -
-
-

All files uploadFolderCommand.ts

-
- -
- 100% - Statements - 46/46 -
- - -
- 100% - Branches - 4/4 -
- - -
- 100% - Functions - 7/7 -
- - -
- 100% - Lines - 42/42 -
- - -
-

- Press n or j to go to the next uncovered block, b, p or k for the previous block. -

-
-
-

-
1 -2 -3 -4 -5 -6 -7 -8 -9 -10 -11 -12 -13 -14 -15 -16 -17 -18 -19 -20 -21 -22 -23 -24 -25 -26 -27 -28 -29 -30 -31 -32 -33 -34 -35 -36 -37 -38 -39 -40 -41 -42 -43 -44 -45 -46 -47 -48 -49 -50 -51 -52 -53 -54 -55 -56 -57 -58 -59 -60 -61 -62 -63 -64 -65 -66 -67 -68 -69 -70 -71 -72 -73 -74 -75 -76 -77 -78 -79 -80 -81 -82 -83 -84 -85 -86 -87 -88 -89 -90 -91 -92 -93 -94 -95 -96 -97 -98 -99 -100 -101 -102 -103 -104 -105 -106 -107 -108 -109 -110 -111 -112  -1x -  -1x -  -  -  -  -  -  -  -  -1x -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -1x -  -  -  -  -  -  -  -  -  -  -  -5x -5x -5x -5x -3x -  -14x -  -5x -  -  -  -  -  -  -  -  -5x -5x -5x -5x -5x -  -1x -1x -1x -1x -1x -1x -  -  -4x -4x -56x -  -56x -42x -  -  -  -4x -4x -4x -  -  -4x -3x -3x -3x -3x -  -3x -  -  -4x -4x -4x -4x -4x -  -  -1x -  -  -  - 
// tslint:disable-next-line:no-var-requires
-const debug = require("debug").debug("UploadFolderCommand");
- 
-import Client,
-{
-    File,
-    FileSystemFolder,
-    IFileNameFormats,
-    UploadFilesCommand,
-    UploadFilesCommandOptions,
-    SourceTargetFileNames,
-} from "./client";
-import Command, { CommandStatus } from "./command";
- 
-/**
- * options to create a upload folder command
- */
-export interface UploadFolderCommandOptions {
-    /**
-     * The name of the source folder with the file structure to be uploaded
-     */
-    folderName: string;
-    /**
-     * the function to determine the target file name having the sourece file name.
-     * If the file should not be uploaded, return an empty string
-     * @param {SourceTargetFileNames} fileNames
-     */
-    getTargetFileNameBeforeUpload?: (fileNames: SourceTargetFileNames) => string;
-    processFileAfterUpload?: (file: File) => Promise<void>;
-}
- 
-/**
- * Command to upload the contents of a folder from local file system to nextcloud recursively
- */
-export default class UploadFolderCommand extends Command {
-    private folderName: string;
-    private processFileAfterUpload?: (file: File) => Promise<void>;
-    private getTargetFileNameBeforeUpload: (fileNames: SourceTargetFileNames) => string;
-    private bytesUploaded: number;
- 
-    /**
-     * @param {Client} client the client
-     * @param {ISourceTargetFileNames[]} files the files to be uploaded
-     * @param {(file: File) => void} processAfterUpload callback function to process the uploaded file
-     */
-    constructor(client: Client, options: UploadFolderCommandOptions) {
-        super(client);
-        this.folderName = options.folderName;
-        this.processFileAfterUpload = options.processFileAfterUpload;
-        if (options.getTargetFileNameBeforeUpload) {
-            this.getTargetFileNameBeforeUpload = options.getTargetFileNameBeforeUpload;
-        } else {
-            this.getTargetFileNameBeforeUpload = (fileNames: SourceTargetFileNames): string => { return fileNames.targetFileName };
-        }
-        this.bytesUploaded = 0;
-    }
- 
-    /**
-     * execute the command
-     * @async
-     * @returns {Promise<void>}
-     */
-    protected async onExecute(): Promise<void> {
-        this.status = CommandStatus.running;
-        let fileNames: IFileNameFormats[] = [];
-        const fsf: FileSystemFolder = new FileSystemFolder(this.folderName);
-        try {
-            fileNames = await fsf.getFileNames();
-        } catch (e) {
-            this.resultMetaData.errors.push(e);
-            this.status = CommandStatus.failed;
-            this.percentCompleted = 100;
-            this.bytesUploaded = 0;
-            this.resultMetaData.timeElapsed = 0;
-            return;
-        }
- 
-        const files: SourceTargetFileNames[] = [];
-        for (const fileNameFormat of fileNames) {
-            const targetFileName = this.getTargetFileNameBeforeUpload({ sourceFileName: fileNameFormat.absolute, targetFileName: fileNameFormat.relative });
-            // add only files with a target name
-            if (targetFileName !== "") {
-                files.push({ sourceFileName: fileNameFormat.absolute, targetFileName });
-            }
-        }
- 
-        const options: UploadFilesCommandOptions = { files, processFileAfterUpload: this.processFileAfterUpload };
-        const uc: UploadFilesCommand = new UploadFilesCommand(this.client, options);
-        uc.execute();
- 
-        // check the processing status
-        while (uc.isFinished() !== true) {
-            this.status = uc.getStatus();
-            this.percentCompleted = uc.getPercentCompleted();
-            this.resultMetaData = uc.getResultMetaData();
-            this.bytesUploaded = uc.getBytesUploaded();
-            // wait one second
-            await (async () => { return new Promise(resolve => setTimeout(resolve, 1000)) })();
-        }
- 
-        this.status = uc.getStatus();
-        this.percentCompleted = uc.getPercentCompleted();
-        this.resultMetaData = uc.getResultMetaData();
-        this.bytesUploaded = uc.getBytesUploaded();
-        return;
-    };
-    public getBytesUploaded(): number {
-        return this.bytesUploaded;
-    }
- 
-}
- 
- -
-
- - - - - - - - - \ No newline at end of file diff --git a/docs/coverage/user.ts.html b/docs/coverage/user.ts.html deleted file mode 100644 index 7ac0f967..00000000 --- a/docs/coverage/user.ts.html +++ /dev/null @@ -1,1880 +0,0 @@ - - - - - - Code coverage report for user.ts - - - - - - - - - -
-
-

All files user.ts

-
- -
- 100% - Statements - 98/98 -
- - -
- 100% - Branches - 13/13 -
- - -
- 100% - Functions - 40/40 -
- - -
- 100% - Lines - 98/98 -
- - -
-

- Press n or j to go to the next uncovered block, b, p or k for the previous block. -

-
-
-

-
1 -2 -3 -4 -5 -6 -7 -8 -9 -10 -11 -12 -13 -14 -15 -16 -17 -18 -19 -20 -21 -22 -23 -24 -25 -26 -27 -28 -29 -30 -31 -32 -33 -34 -35 -36 -37 -38 -39 -40 -41 -42 -43 -44 -45 -46 -47 -48 -49 -50 -51 -52 -53 -54 -55 -56 -57 -58 -59 -60 -61 -62 -63 -64 -65 -66 -67 -68 -69 -70 -71 -72 -73 -74 -75 -76 -77 -78 -79 -80 -81 -82 -83 -84 -85 -86 -87 -88 -89 -90 -91 -92 -93 -94 -95 -96 -97 -98 -99 -100 -101 -102 -103 -104 -105 -106 -107 -108 -109 -110 -111 -112 -113 -114 -115 -116 -117 -118 -119 -120 -121 -122 -123 -124 -125 -126 -127 -128 -129 -130 -131 -132 -133 -134 -135 -136 -137 -138 -139 -140 -141 -142 -143 -144 -145 -146 -147 -148 -149 -150 -151 -152 -153 -154 -155 -156 -157 -158 -159 -160 -161 -162 -163 -164 -165 -166 -167 -168 -169 -170 -171 -172 -173 -174 -175 -176 -177 -178 -179 -180 -181 -182 -183 -184 -185 -186 -187 -188 -189 -190 -191 -192 -193 -194 -195 -196 -197 -198 -199 -200 -201 -202 -203 -204 -205 -206 -207 -208 -209 -210 -211 -212 -213 -214 -215 -216 -217 -218 -219 -220 -221 -222 -223 -224 -225 -226 -227 -228 -229 -230 -231 -232 -233 -234 -235 -236 -237 -238 -239 -240 -241 -242 -243 -244 -245 -246 -247 -248 -249 -250 -251 -252 -253 -254 -255 -256 -257 -258 -259 -260 -261 -262 -263 -264 -265 -266 -267 -268 -269 -270 -271 -272 -273 -274 -275 -276 -277 -278 -279 -280 -281 -282 -283 -284 -285 -286 -287 -288 -289 -290 -291 -292 -293 -294 -295 -296 -297 -298 -299 -300 -301 -302 -303 -304 -305 -306 -307 -308 -309 -310 -311 -312 -313 -314 -315 -316 -317 -318 -319 -320 -321 -322 -323 -324 -325 -326 -327 -328 -329 -330 -331 -332 -333 -334 -335 -336 -337 -338 -339 -340 -341 -342 -343 -344 -345 -346 -347 -348 -349 -350 -351 -352 -353 -354 -355 -356 -357 -358 -359 -360 -361 -362 -363 -364 -365 -366 -367 -368 -369 -370 -371 -372 -373 -374 -375 -376 -377 -378 -379 -380 -381 -382 -383 -384 -385 -386 -387 -388 -389 -390 -391 -392 -393 -394 -395 -396 -397 -398 -399 -400 -401 -402 -403 -404 -405 -406 -407 -408 -409 -410 -411 -412 -413 -414 -415 -416 -417 -418 -419 -420 -421 -422 -423 -424 -425 -426 -427 -428 -429 -430 -431 -432 -433 -434 -435 -436 -437 -438 -439 -440 -441 -442 -443 -444 -445 -446 -447 -448 -449 -450 -451 -452 -453 -454 -455 -456 -457 -458 -459 -460 -461 -462 -463 -464 -465 -466 -467 -468 -469 -470 -471 -472 -473 -474 -475 -476 -477 -478 -479 -480 -481 -482 -483 -484 -485 -486 -487 -488 -489 -490 -491 -492 -493 -494 -495 -496 -497 -498 -499 -500 -501 -502 -503 -504 -505 -506 -507 -508 -509 -510 -511 -512 -513 -514 -515 -516 -517 -518 -519 -520 -521 -522 -523 -524 -525 -526 -527 -528 -529 -530 -531 -532 -533 -534 -535 -536 -537 -538 -539 -540 -541 -542 -543 -544 -545 -546 -547 -548 -549 -550 -551 -552 -553 -554 -555 -556 -557 -558 -559 -560 -561 -562 -563 -564 -565 -566 -567 -568 -569 -570 -571 -572 -573 -574 -575 -576 -577 -578 -579 -580 -581 -582 -583 -584 -585 -586 -587 -588 -589 -590 -591 -592 -593 -594 -595 -596 -597 -598 -599 -600 -6011x -1x -  -1x -1x -1x -1x -1x -1x -1x -1x -1x -1x -1x -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -1x -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -43x -43x -43x -  -  -  -  -  -  -  -  -  -  -  -  -  -17x -  -  -  -  -  -  -  -  -  -4x -4x -  -  -  -  -  -  -  -  -  -3x -3x -  -  -  -  -  -  -  -  -  -2x -2x -1x -  -1x -  -  -  -  -  -  -  -  -  -7x -  -  -  -  -  -  -  -  -  -  -  -5x -4x -  -  -  -  -  -  -  -  -  -6x -  -  -  -  -  -  -  -  -  -7x -  -7x -  -  -  -  -7x -1x -  -  -7x -1x -  -7x -  -  -  -  -  -  -  -  -  -  -  -6x -4x -  -  -  -  -  -  -  -  -  -7x -  -  -  -  -  -  -  -  -  -  -  -5x -3x -  -  -  -  -  -  -  -  -  -  -  -  -7x -  -  -  -  -  -  -  -  -  -  -  -5x -4x -  -  -  -  -  -  -  -  -  -  -  -  -7x -  -  -  -  -  -  -  -  -  -  -  -4x -3x -  -  -  -  -  -  -  -  -  -  -  -  -  -7x -  -  -  -  -  -  -  -  -  -  -  -4x -3x -  -  -  -  -  -  -  -  -  -  -  -  -  -7x -  -  -  -  -  -  -  -  -  -  -  -4x -3x -  -  -  -  -  -  -  -  -  -  -  -  -  -6x -  -  -  -  -  -  -  -  -  -  -  -5x -2x -  -  -  -  -  -  -  -  -  -  -  -  -  -6x -  -  -  -  -  -  -  -  -  -  -  -5x -2x -  -  -  -  -  -  -  -  -  -  -  -7x -  -  -  -  -  -  -  -  -  -  -  -  -  -4x -  -  -  -  -  -  -  -  -  -  -  -  -  -3x -3x -3x -3x -  -3x -  -  -  -  -  -  -  -  -  -8x -  -  -  -  -  -  -  -  -  -  -  -  -  -11x -9x -9x -  -  -  -  -  -  -  -  -  -  -  -  -  -10x -7x -7x -  -  -  -  -  -  -  -  -  -  -  -  -  -15x -  -  -  -  -  -  -  -  -  -  -  -  -2x -1x -1x -  -  -  -  -  -  -  -  -  -  -  -  -  -3x -3x -2x -  -2x -  -  -  -  -  -  -  -  -  -  -  -  -  -3x -3x -3x -3x -  -3x -  -  -  -  -  -  -  -  -  -8x -  -  -  -  -  -  -  -  -  -  -  -  -  -9x -8x -8x -  -  -  -  -  -  -  -  -  -  -  -  -  -6x -4x -4x -  -  -  -  -  -  -  -  -  -9x -  -  -  -  -  -  -  -  -  -123x -71x -  -123x -  -  -  - 
import Client, { ClientError, IQuota, UserGroup, UserGroupDoesNotExistError } from "./client";
-import FileSizeFormatter from "./fileSizeFormatter";
- 
-export enum UserProperty {
-    email = "email",
-    quota = "quota",
-    displayName = "displayname",
-    phone = "phone",
-    address = "address",
-    website = "website",
-    twitter = "twitter",
-    password = "password",
-    language = "language",
-    locale = "locale",
-}
- 
-export interface IUserOptionsQuota {
-    "free"?: number,
-    "used": number,
-    "total"?: number,
-    "relative": number,
-    "quota": number
-}
- 
-export interface IUserQuotaUserFriendly {
-    "free"?: string,
-    "used": string,
-    "total"?: string,
-    "quota": string,
-    "relative": string
-}
- 
-export interface IUserOptions {
-    "enabled": boolean;
-    "lastLogin"?: Date,
-    "subadminGroups": string[],
-    "memberGroups": string[],
-    "quota": IUserOptionsQuota,
-    "email": string,
-    "displayName": string,
-    "phone": string,
-    "address": string,
-    "website": string,
-    "twitter": string,
-    "language": string
-    "locale": string,
-}
- 
-/**
- * The user class represents a user in nextcloud.
- * async getGroups
- * async isDisabled
- * async getLastLogin
- * async getEmail
- * getId
- * async getDisplayName
- */
-export default class User {
-    // https://docs.nextcloud.com/server/latest/admin_manual/configuration_user/user_provisioning_api.html
- 
-    private memento?: IUserOptions;
-    private client: Client;
-    readonly id: string;
- 
-    /**
-     * the conscructor of the user
-     * should only me invoked by the Client
-     * @constructor
-     * @param {Client} client
-     * @param {string} id the user id
-     * @param {IUserOptions} options optional options
-     */
-    constructor(client: Client, id: string, options?: IUserOptions) {
-        this.id = id;
-        this.client = client;
-        this.memento = options;
-    }
- 
-    // **********************************
-    // enable disable
-    // **********************************
- 
-    /**
-     * returns true if the user is enabled
-     * @async
-     * @returns {Promise<boolean>} true if the user is enabled
-     * @throws {UserNotFoundError}
-     */
-    async isEnabled(): Promise<boolean> {
-        return (await this.getUserData()).enabled;
-    }
- 
-    /**
-     * disables the user
-     * @async
-     * @returns {Promise<void>}
-     * @throws {UserNotFoundError}
-     */
-    async disable(): Promise<void> {
-        delete this.memento;
-        return await this.client.disableUser(this.id);
-    }
- 
-    /**
-     * enables the user
-     * @async
-     * @returns {Promise<void>}
-     * @throws {UserNotFoundError}
-     */
-    async enable(): Promise<void> {
-        delete this.memento;
-        return await this.client.enableUser(this.id);
-    }
- 
-    /**
-     * get the last login date or null if the user has not been logged in yet
-     * @async
-     * @returns {Promise<Date | null>} last login date or null if the user has not been logged in yet
-     * @throws {UserNotFoundError}
-     */
-    async getLastLogin(): Promise<Date | null> {
-        const data: IUserOptions = await this.getUserData();
-        if (data.lastLogin) {
-            return data.lastLogin;
-        }
-        return null;
-    }
- 
-    /**
-     * returns the display name
-     * @async
-     * @returns {Promise<string>} display name
-     * @throws {UserNotFoundError}
-     */
-    async getDisplayName(): Promise<string> {
-        return (await this.getUserData()).displayName;
-    }
- 
-    /**
-     * set the display name
-     * @async
-     * @param {string} value the display name
-     * @returns {Promise<void>}
-     * @throws {UserNotFoundError}
-     * @throws {UserUpdateError}
-     */
-    async setDisplayName(value: string): Promise<void> {
-        await this.client.updateUserProperty(this.id, UserProperty.displayName, value);
-        delete this.memento;
-    }
- 
-    /**
-     * returns information on quota, usage and available space
-     * @async
-     * @returns {Promise<IUserOptionsQuota>}
-     * @throws {UserNotFoundError}
-     */
-    async getQuota(): Promise<IUserOptionsQuota> {
-        return (await this.getUserData()).quota;
-    }
- 
-    /**
-     * returns information on quota, usage and available space in a user friendly format
-     * @async
-     * @returns {Promise<IUserQuotaUserFriendly>}
-     * @throws {UserNotFoundError}
-     */
-    async getQuotaUserFriendly(): Promise<IUserQuotaUserFriendly> {
-        const q: IUserOptionsQuota = (await this.getUserData()).quota;
- 
-        const qUF: IUserQuotaUserFriendly = {
-            used: new FileSizeFormatter(q.used).getUserFriendlyFileSize(),
-            quota: new FileSizeFormatter(q.quota).getUserFriendlyFileSize(),
-            relative: Math.round(q.relative) + " %"
-        }
-        if (q.total) {
-            qUF.total = new FileSizeFormatter(q.total).getUserFriendlyFileSize();
-        }
- 
-        if (q.free) {
-            qUF.free = new FileSizeFormatter(q.free).getUserFriendlyFileSize();
-        }
-        return qUF;
-    }
- 
-    /**
-     * sets the quota limit of the user
-     * @async
-     * @param {string} value the quota string like "1 GB", "100 MB"
-     * @returns {Promise<void>}
-     * @throws {UserNotFoundError}
-     * @throws {UserUpdateError}
-     */
-    async setQuota(value: string): Promise<void> {
-        await this.client.updateUserProperty(this.id, UserProperty.quota, value);
-        delete this.memento;
-    }
- 
-    /**
-     * returns the email address
-     * @async
-     * @returns {Promise<string>} email adress
-     * @throws {UserNotFoundError}
-     */
-    async getEmail(): Promise<string> {
-        return (await this.getUserData()).email;
-    }
- 
-    /**
-     * set the email address
-     * @async
-     * @param {string} value the email address
-     * @returns {Promise<void>}
-     * @throws {UserNotFoundError}
-     * @throws {UserUpdateError}
-     */
-    async setEmail(value: string): Promise<void> {
-        await this.client.updateUserProperty(this.id, UserProperty.email, value);
-        delete this.memento;
-    }
- 
-    // **********************************
-    // phone
-    // **********************************
-    /**
-     * returns the phone number
-     * @async
-     * @returns {Promise<string>} phone number
-     * @throws {UserNotFoundError}
-     */
-    async getPhone(): Promise<string> {
-        return (await this.getUserData()).phone;
-    }
- 
-    /**
-     * set phone number
-     * @async
-     * @param {string} value the phone number
-     * @returns {Promise<void>}
-     * @throws {UserNotFoundError}
-     * @throws {UserUpdateError}
-     */
-    async setPhone(value: string): Promise<void> {
-        await this.client.updateUserProperty(this.id, UserProperty.phone, value);
-        delete this.memento;
-    }
- 
-    // **********************************
-    // address
-    // **********************************
-    /**
-     * returns the phone number
-     * @async
-     * @returns {Promise<string>} address
-     * @throws {UserNotFoundError}
-     */
-    async getAddress(): Promise<string> {
-        return (await this.getUserData()).address;
-    }
- 
-    /**
-     * set the address
-     * @async
-     * @param {string} value the address
-     * @returns {Promise<void>}
-     * @throws {UserNotFoundError}
-     * @throws {UserUpdateError}
-     */
-    async setAddress(value: string): Promise<void> {
-        await this.client.updateUserProperty(this.id, UserProperty.address, value);
-        delete this.memento;
-    }
- 
-    // **********************************
-    // website
-    // **********************************
- 
-    /**
-     * returns the website
-     * @async
-     * @returns {Promise<string>} website
-     * @throws {UserNotFoundError}
-     */
-    async getWebsite(): Promise<string> {
-        return (await this.getUserData()).website;
-    }
- 
-    /**
-     * set the website
-     * @async
-     * @param {string} value the website
-     * @returns {Promise<void>}
-     * @throws {UserNotFoundError}
-     * @throws {UserUpdateError}
-     */
-    async setWebsite(value: string): Promise<void> {
-        await this.client.updateUserProperty(this.id, UserProperty.website, value);
-        delete this.memento;
-    }
- 
-    // **********************************
-    // twitter
-    // **********************************
- 
-    /**
-     * returns the twitter handle
-     * @async
-     * @returns {Promise<string>} twitter handle
-     * @throws {UserNotFoundError}
-     */
-    async getTwitter(): Promise<string> {
-        return (await this.getUserData()).twitter;
-    }
- 
-    /**
-     * set the twitter handle
-     * @async
-     * @param {string} value the twitter handle
-     * @returns {Promise<void>}
-     * @throws {UserNotFoundError}
-     * @throws {UserUpdateError}
-     */
-    async setTwitter(value: string): Promise<void> {
-        await this.client.updateUserProperty(this.id, UserProperty.twitter, value);
-        delete this.memento;
-    }
- 
-    // **********************************
-    // language
-    // **********************************
- 
-    /**
-     * returns the langauge code
-     * @async
-     * @returns {Promise<string>} language code
-     * @throws {UserNotFoundError}
-     */
-    async getLanguage(): Promise<string> {
-        return (await this.getUserData()).language;
-    }
- 
-    /**
-     * set the language code like EN, DE, FR...
-     * @async
-     * @param {string} value the language code
-     * @returns {Promise<void>}
-     * @throws {UserNotFoundError}
-     * @throws {UserUpdateError}
-     */
-    async setLanguage(value: string): Promise<void> {
-        await this.client.updateUserProperty(this.id, UserProperty.language, value);
-        delete this.memento;
-    }
- 
-    // **********************************
-    // locale
-    // **********************************
- 
-    /**
-     * returns the locale
-     * @async
-     * @returns {Promise<string>} locale
-     * @throws {UserNotFoundError}
-     */
-    async getLocale(): Promise<string> {
-        return (await this.getUserData()).locale;
-    }
- 
-    /**
-     * set the locale like EN, DE, FR...
-     * @async
-     * @param {string} value the locale
-     * @returns {Promise<void>}
-     * @throws {UserNotFoundError}
-     * @throws {UserUpdateError}
-     */
-    async setLocale(value: string): Promise<void> {
-        await this.client.updateUserProperty(this.id, UserProperty.locale, value);
-        delete this.memento;
-    }
- 
-    /**
-     * set the password
-     * @async
-     * @param {string} value the password
-     * @returns {Promise<void>}
-     * @throws {UserNotFoundError}
-     * @throws {UserUpdateError}
-     */
-    async setPassword(value: string): Promise<void> {
-        await this.client.updateUserProperty(this.id, UserProperty.password, value);
-    }
- 
-    // **********************************
-    // Resend the welcome email
-    // **********************************
- 
-    /**
-     * resends the welcome email
-     * @async
-     * @returns {Promise<void>}
-     * @throws  {UserResendWelcomeEmailError}
-     */
-    async resendWelcomeEmail(): Promise<void> {
-        await this.client.resendWelcomeEmail(this.id);
-    }
- 
-    // **********************************
-    // user group member
-    // **********************************
- 
-    /**
-     * returns a list of user groups where the user is member
-     * @async
-     * @returns {Promise<UserGroup[]} a list of user groups where the user is member
-     * @throws {UserNotFoundError}
-     */
-    async getMemberUserGroups(): Promise<UserGroup[]> {
-        const groupIds: string[] = (await this.getUserData()).memberGroups;
-        const result: UserGroup[] = [];
-        for (const groupId of groupIds) {
-            result.push(new UserGroup(this.client, groupId));
-        }
-        return result;
-    }
- 
-    /**
-     * returns a list of user group ids where the user is member
-     * @async
-     * @returns {Promise<string[]} a list of user group ids where the user is member
-     * @throws {UserNotFoundError}
-     */
-    async getMemberUserGroupIds(): Promise<string[]> {
-        return (await this.getUserData()).memberGroups;
-    }
- 
-    /**
-     * adds the user to a user group as member
-     * @async
-     * @param {UserGroup} userGroup the user group
-     * @returns {Promise<void>}
-     * @throws {UserNotFoundError}
-     * @throws {UserGroupDoesNotExistError}
-     * @throws {InsufficientPrivilegesError}
-     * @throws {OperationFailedError}
-     */
-    async addToMemberUserGroup(userGroup: UserGroup): Promise<void> {
-        await this.client.addUserToMemberUserGroup(this.id, userGroup.id);
-        delete this.memento;
-        return;
-    }
- 
-    /**
-     * remove the user from a user group as member
-     * @async
-     * @param {UserGroup} userGroup the user group
-     * @returns {Promise<void>}
-     * @throws {UserNotFoundError}
-     * @throws {UserGroupDoesNotExistError}
-     * @throws {InsufficientPrivilegesError}
-     * @throws {OperationFailedError}
-     */
-    async removeFromMemberUserGroup(userGroup: UserGroup): Promise<void> {
-        await this.client.removeUserFromMemberUserGroup(this.id, userGroup.id);
-        delete this.memento;
-        return
-    }
- 
-    // **********************************
-    // user superadmin
-    // **********************************
- 
-    /**
-     * true if the user is a superadmin
-     * @async
-     * @returns {Promise<boolean>} true if the user is a superadmin
-     * @throws {UserNotFoundError}
-     */
-    async isSuperAdmin(): Promise<boolean> {
-        return (await this.getUserData()).memberGroups.indexOf("admin") === -1 ? false : true;
-    }
- 
-    /**
-     * promote user to super admin
-     * @async
-     * @returns {Promise<void>}
-     * @throws {UserNotFoundError}
-     * @throws {UserGroupDoesNotExistError}
-     * @throws {InsufficientPrivilegesError}
-     * @throws {OperationFailedError}
-     */
-    async promoteToSuperAdmin(): Promise<void> {
-        await this.addToMemberUserGroup(new UserGroup(this.client, "admin"));
-        delete this.memento;
-        return;
-    }
- 
-    /**
-     * demote user from being a super admin
-     * @async
-     * @returns {Promise<void>}
-     * @throws {UserNotFoundError}
-     * @throws {UserGroupDoesNotExistError}
-     * @throws {InsufficientPrivilegesError}
-     * @throws {OperationFailedError}
-     */
-    async demoteFromSuperAdmin(): Promise<void> {
-        /* istanbul ignore else */
-        if (await this.isSuperAdmin()) {
-            await this.removeFromMemberUserGroup(new UserGroup(this.client, "admin"));
-            delete this.memento;
-        }
-        return;
-    }
- 
-    // **********************************
-    // user group subadmin
-    // **********************************
- 
-    /**
-     * returns a list of user groups where the user is subadmin
-     * @async
-     * @returns {Promise<UserGroup[]} a list of user groups where the user is subadmin
-     * @throws {UserNotFoundError}
-     */
-    async getSubadminUserGroups(): Promise<UserGroup[]> {
-        const groupIds: string[] = (await this.getUserData()).subadminGroups;
-        const result: UserGroup[] = [];
-        for (const groupId of groupIds) {
-            result.push(new UserGroup(this.client, groupId));
-        }
-        return result;
-    }
- 
-    /**
-     * returns a list of user group ids where the user is subadmin
-     * @async
-     * @returns {Promise<string[]} a list of user group ids where the user is subadmin
-     * @throws {UserNotFoundError}
-     */
-    async getSubadminUserGroupIds(): Promise<string[]> {
-        return (await this.getUserData()).subadminGroups;
-    }
- 
-    /**
-     * promote the user to be a subadmin of the user group
-     * @async
-     * @param {UserGroup} userGroup the user group
-     * @returns {Promise<void>}
-     * @throws {UserNotFoundError}
-     * @throws {UserGroupDoesNotExistError}
-     * @throws {InsufficientPrivilegesError}
-     * @throws {OperationFailedError}
-     */
-    async promoteToUserGroupSubadmin(userGroup: UserGroup): Promise<void> {
-        await this.client.promoteUserToUserGroupSubadmin(this.id, userGroup.id);
-        delete this.memento;
-        return
-    }
- 
-    /**
-     * demote the user from beeing a subadmin of the user group
-     * @async
-     * @param {UserGroup} userGroup the user group
-     * @returns {Promise<void>}
-     * @throws {UserNotFoundError}
-     * @throws {UserGroupDoesNotExistError}
-     * @throws {InsufficientPrivilegesError}
-     * @throws {OperationFailedError}
-     */
-    async demoteFromSubadminUserGroup(userGroup: UserGroup): Promise<void> {
-        await this.client.demoteUserFromSubadminUserGroup(this.id, userGroup.id);
-        delete this.memento;
-        return
-    }
- 
-    /**
-     * deletes a user
-     * @async
-     * @returns {Promise<void>}
-     * @throws {UserNotFoundError}
-     */
-    async delete(): Promise<void> {
-        return await this.client.deleteUser(this.id);
-    }
- 
-    /**
-     * returns the user data
-     * @async
-     * @returns {Promise<IUserOptions>}
-     * @throws {UserNotFoundError}
-     */
-    private async getUserData(): Promise<IUserOptions> {
-        if (!this.memento) {
-            this.memento = await this.client.getUserData(this.id);
-        }
-        return this.memento;
-    }
- 
-}
- 
- -
-
- - - - - - - - - \ No newline at end of file diff --git a/docs/coverage/userGroup.ts.html b/docs/coverage/userGroup.ts.html deleted file mode 100644 index e762b487..00000000 --- a/docs/coverage/userGroup.ts.html +++ /dev/null @@ -1,203 +0,0 @@ - - - - - - Code coverage report for userGroup.ts - - - - - - - - - -
-
-

All files userGroup.ts

-
- -
- 100% - Statements - 11/11 -
- - -
- 100% - Branches - 2/2 -
- - -
- 100% - Functions - 4/4 -
- - -
- 100% - Lines - 11/11 -
- - -
-

- Press n or j to go to the next uncovered block, b, p or k for the previous block. -

-
-
-

-
1 -2 -3 -4 -5 -6 -7 -8 -9 -10 -11 -12 -13 -14 -15 -16 -17 -18 -19 -20 -21 -22 -23 -24 -25 -26 -27 -28 -29 -30 -31 -32 -33 -34 -35 -36 -37 -38 -39 -40 -41 -421x -  -  -  -  -  -  -  -  -1x -  -  -  -52x -52x -  -  -  -  -  -  -  -  -4x -4x -  -2x -1x -  -1x -  -  -  -  -1x -  -  -  -1x -  -  - 
import Client, { UserGroupDeletionFailedError, UserGroupDoesNotExistError } from "./client";
- 
-/**
- * The user group class represents a user user in nextcloud.
- * spec: https://docs.nextcloud.com/server/latest/admin_manual/configuration_user/instruction_set_for_groups.html
- * id
- * getSubAdmins
- * getMembers
- */
-export default class UserGroup {
-    readonly id: string;
-    private client: Client;
-    constructor(client: Client, id: string) {
-        this.id = id;
-        this.client = client;
-    }
- 
-    /**
-     * deletes the user group
-     * @throws UserGroupDeletionFailedError
-     */
-    public async delete(): Promise<void> {
- 
-        try {
-            return await this.client.deleteUserGroup(this.id);
-        } catch (e) {
-            if (e instanceof UserGroupDoesNotExistError) {
-                return;
-            }
-            throw e;
-        }
-    }
- 
-    public async getMemberUserIds(): Promise<string[]> {
-        return await this.client.getUserGroupMembers(this.id);
-    }
- 
-    public async getSubadminUserIds(): Promise<string[]> {
-        return await this.client.getUserGroupSubadmins(this.id);
-    }
-}
- 
- -
-
- - - - - - - - - \ No newline at end of file diff --git a/docs/download.md b/docs/download.md deleted file mode 100644 index 17b9d85b..00000000 --- a/docs/download.md +++ /dev/null @@ -1,62 +0,0 @@ -## Download -Copy files from the Nextcloud to the file system. -Download files of a Nextcloud folder structure recursively to the file system with a single command. -As this process might take some time, the nextcloud-node-client supports also asynchronous processing. -Just create a download command, execute the it and get the result, when the command has finsished. - -The command is used, to keep track of the download process. The current processing state can be queried. Callback functions are supported to filter files before downloading and changing the target file names. - -### Download files of a folder command - -Example: Download files of a folder asynchronously and apply filter -```typescript -// typescript -// download folder structure asynchronously -import Client, { - File, Folder, - DownloadFolderCommand, DownloadFolderCommandOptions, - SourceTargetFileNames, - CommandStatus, CommandResultMetaData, -} from "nextcloud-node-client"; - -(async () => { - const client = new Client(); - const sourceFolder: Folder | null = await client.getFolder("Borstenson/Company"); - - const options: DownloadFolderCommandOptions = - { - sourceFolder: sourceFolder!, - filterFile: (file: File): File | null => { - // download only PDFs - if (file.mime === "application/pdf") { - return file; - } - return null; - }, - getTargetFileNameBeforeDownload: - (fileNames: SourceTargetFileNames): string => { return "./tmp/" + fileNames.targetFileName } - }; - const command: DownloadFolderCommand = new DownloadFolderCommand(client, options); - command.execute(); - - while (command.isFinished() !== true) { - console.log(command.getPercentCompleted() + " %"); - // wait a second - await (async () => { return new Promise(resolve => setTimeout(resolve, 1000)) })(); - } - - // use the result to do the needful - const uploadResult: CommandResultMetaData = command.getResultMetaData(); - - if (command.getStatus() === CommandStatus.success) { - console.log(uploadResult.messages); - console.log(command.getBytesDownloaded()); - } else { - console.log(uploadResult.errors); - } - -})(); - -``` - - diff --git a/docs/favicon.ico b/docs/favicon.ico deleted file mode 100644 index 4edd08a4..00000000 Binary files a/docs/favicon.ico and /dev/null differ diff --git a/docs/getFiles.md b/docs/getFiles.md deleted file mode 100644 index 9f895622..00000000 --- a/docs/getFiles.md +++ /dev/null @@ -1,65 +0,0 @@ -## Get files of a folder recursively -List all files of a given source folder including the complete subfolder structure. -The command is used, to keep track of the file listing process as this can be a long running process. - -### Example -Get all files of a source folder and filter only PDFs and JPGs. -This example shows asynchronous processing. Use await with the execute method for synchronous processing. - -```typescript -// typescript -// get files recursively -import Client, { - File, Folder, - CommandResultMetaData, CommandStatus, - GetFilesRecursivelyCommand, - GetFilesRecursivelyCommandOptions, -} from "nextcloud-node-client"; - -(async () => { - const client = new Client(); - - const sourceFolder: Folder | null = await client.getFolder("/Borstenson/Company Information"); - if (!sourceFolder) { - console.log("source folder not found"); - process.exit(1); - } - - // only pdfs and jpg should be listed - const fileFilterFunction = (file: File): File | null => { - if (file.mime === "application/pdf" || file.mime === "image/jpeg") { - return file; - } - return null; - } - - const options: GetFilesRecursivelyCommandOptions = { - sourceFolder, - filterFile: fileFilterFunction, - }; - - const command: GetFilesRecursivelyCommand = new GetFilesRecursivelyCommand(client, options); - // get files asynchronously (will not throw exceptions!) - command.execute(); - - // check the processing status as long as the command is running - while (command.isFinished() !== true) { - // wait one second - await (async () => { return new Promise(resolve => setTimeout(resolve, 1000)) })(); - console.log(command.getPercentCompleted() + "%"); - } - - // use the result to do the needful - const uploadResult: CommandResultMetaData = command.getResultMetaData(); - - if (command.getStatus() === CommandStatus.success) { - console.log(uploadResult.messages); - for (const file of command.getFiles()) { - console.log(file.name); - } - } else { - console.log(uploadResult.errors); - } - -})(); -``` diff --git a/docs/index.html b/docs/index.html deleted file mode 100644 index 4fc10ef0..00000000 --- a/docs/index.html +++ /dev/null @@ -1,49 +0,0 @@ - - - - - - - nextcloud-node-client - - - - - -
- -

Access nextcloud remotely from node.js applications with a rich and simple TypeScript/JavaScript API.

- - - - - - - -
-
- API Documentation -

- API -
-
- NPM -

- npm -
- GitHub -
- GitHub -
- - Code coverage -
- Code Coverage -
- - - \ No newline at end of file diff --git a/docs/ncnc-logo-banner.png b/docs/ncnc-logo-banner.png deleted file mode 100644 index 6e8e6925..00000000 Binary files a/docs/ncnc-logo-banner.png and /dev/null differ diff --git a/docs/tagging.md b/docs/tagging.md deleted file mode 100644 index 40650983..00000000 --- a/docs/tagging.md +++ /dev/null @@ -1,49 +0,0 @@ -## Tagging -The nextcloud-node-client provides the maintenance of system tags (create and delete). The user must be superadmin to perform this tasks (member of admin user group). -Assigning and removing tags from files and folders is supported. -It is also possible to get a list of all files and folders with specific tag. - -### Example: -```typescript -// typescript -import Client, { File, Folder, Share, Tag, FileSystemElement } from "nextcloud-node-client"; - -(async () => { - try { - // create a new client using connectivity information from environment - const client = new Client(); - // create a folder structure if not available - const folder: Folder = await client.createFolder("folder/subfolder"); - // create file within the folder - const file: File = await folder.createFile("myFile.txt", Buffer.from("My file content")); - // create two tags - const tag1: Tag = await client.createTag("tag 1"); - const tag2: Tag = await client.createTag("tag 2"); - // assign tag to folder - folder.addTag(tag1.name); - // assign tag to files - file.addTag(tag1.name); - file.addTag(tag2.name); - - // get list of file system elements with the tag1 assigned - let fse: FileSystemElement[] = await client.getFileSystemElementByTags([tag1]); - // print names of folder and file - console.log(fse[0].name); - console.log(fse[1].name); - - // get list of file system elements with the tag1 and tag2 - fse = await client.getFileSystemElementByTags([tag1, tag2]); - // print name of file - console.log(fse[0].name); - - // delete the tags - await tag1.delete(); - await tag2.delete(); - // delete the folder including the file and share - await folder.delete(); - } catch (e) { - // some error handling - console.log(e); - } -})(); -``` diff --git a/docs/upload.md b/docs/upload.md deleted file mode 100644 index 702101ce..00000000 --- a/docs/upload.md +++ /dev/null @@ -1,208 +0,0 @@ -## Upload -Copy files from the file system to Nextcloud. -Upload multiple files or complete folders structures recursively to Nextcloud with a single command. -As this process might take some time, the nextcloud-node-client supports also asynchronous processing. -Just create an upload command, execute the it and get the result, when the command has finsished. - -The command is used, to keep track of the upload process. The current processing state can be queried. Callback functions are supported to process the file after upload and to filter files before processing or to define the target file name. - -Check the examples and the class documentation (UploadFilesCommand and UploadFolderCommand). - -### Upload Files Command -Copy files from the file system to Nextcloud. -Provide a list of source and traget file names and optionally a callback function to process the file after successful upload. - -Example: Upload files synchronously -```typescript -// typescript -// upload files synchronously -import Client, { - CommandResultMetaData, CommandStatus, - UploadFilesCommand, SourceTargetFileNames, -} from "nextcloud-node-client"; - -(async () => { - const client = new Client(); - - // create a list of files to upload - const files: SourceTargetFileNames[] = [ - { - sourceFileName: "C:\\Users\\horst\\Documents\\Borstenson Company Profile.pdf", - targetFileName: "/Company Info/Borstenson Company Profile.pdf" - }, - // add even more files ... - ]; - - // create the command object - const uc: UploadFilesCommand = new UploadFilesCommand(client, { files }); - - // start the upload synchronously - await uc.execute(); - - // use the result to do the needful - const uploadResult: CommandResultMetaData = uc.getResultMetaData(); - - if (uc.getStatus() === CommandStatus.success) { - console.log(uploadResult.messages); - console.log(uc.getBytesUploaded()); - } else { - console.log(uploadResult.errors); - } - -})(); -``` - -Example: Upload files asynchronously and process file after upload -```typescript -// typescript -import Client, { - File, CommandResultMetaData, - CommandStatus, UploadFilesCommand, - SourceTargetFileNames, -} from "nextcloud-node-client"; - -(async () => { - const client = new Client(); - - // create a list of files to upload - const files: SourceTargetFileNames[] = [ - { - sourceFileName: "C:\\Users\\horst\\Documents\\Borstenson Company Profile.pdf", - targetFileName: "/Company Info/Borstenson Company Profile.pdf" - }, - // add even more files ... - ]; - // define a callback to process the uploaded file optionally - const processFileAfterUpload = async (file: File): Promise => { - // set a tag and a comment - await file.addTag("Company"); - await file.addComment(`Hello ${file.baseName} your mime type is ${file.mime}`); - // do even more fancy stuff ... - return; - }; - - // create the command object - const uc: UploadFilesCommand = - new UploadFilesCommand(client, { files, processFileAfterUpload }); - - // start the upload asynchronously (will not throw exceptions!) - uc.execute(); - - // check the processing status as long as the command is running - while (uc.isFinished() !== true) { - // wait one second - await (async () => { return new Promise(resolve => setTimeout(resolve, 1000)) })(); - console.log(uc.getPercentCompleted() + "%"); - } - - // use the result to do the needful - const uploadResult: CommandResultMetaData = uc.getResultMetaData(); - - if (uc.getStatus() === CommandStatus.success) { - console.log(uploadResult.messages); - console.log(uc.getBytesUploaded()); - } else { - console.log(uploadResult.errors); - } - -})(); -``` - -### Upload Folder Command -Copy all files of a folder structure from the file system to Nextcloud. - -Example: Upload all files of a folder recursively and synchronously. -```typescript -// typescript -import Client, { - CommandResultMetaData, CommandStatus, UploadFolderCommand, -} from "nextcloud-node-client"; - -(async () => { - const client = new Client(); - - // define a source folder - const folderName: string = "c:\\Users\\horst\\Company"; - - // create the command object - const uc: UploadFolderCommand = new UploadFolderCommand(client, { folderName } - ); - - // start the upload synchronously - await uc.execute(); - - // use the result to do the needful - const uploadResult: CommandResultMetaData = uc.getResultMetaData(); - - if (uc.getStatus() === CommandStatus.success) { - console.log(uploadResult.messages); - } else { - console.log(uploadResult.errors); - } - -})(); -``` - -Example: Upload all files of a folder recursively and ignore "*.tmp" files. Add a tag and comment after successful file upload. -```typescript -// typescript -import Client, { - File, - CommandResultMetaData, - CommandStatus, - UploadFolderCommand, - SourceTargetFileNames, -} from "nextcloud-node-client"; - -(async () => { - const client = new Client(); - - // define a source folder - const folderName: string = "c:\\Users\\horst\\Company"; - - // define a callback to process the uploaded file optionally - const processFileAfterUpload = async (file: File): Promise => { - // set a tag and a comment - await file.addTag("Company"); - await file.addComment(`Hello ${file.baseName} your mime type is ${file.mime}`); - // do even more fancy stuff ... - return; - }; - - // define a callback to determine the target file name - // or to filter out files - const getTargetFileNameBeforeUpload = (fileNames: SourceTargetFileNames): string => { - // do not copy *.tmp files - if (fileNames.sourceFileName.endsWith(".tmp")) { - return ""; - } - return `/Company Information${fileNames.targetFileName}`; - }; - - // create the command object - const uc: UploadFolderCommand = new UploadFolderCommand( - client, { folderName, getTargetFileNameBeforeUpload, processFileAfterUpload } - ); - - // start the upload asynchronously (will not throw exceptions!) - uc.execute(); - - // check the processing status as long as the command is running - while (uc.isFinished() !== true) { - // wait one second - await (async () => { return new Promise(resolve => setTimeout(resolve, 1000)) })(); - console.log(uc.getPercentCompleted() + "%"); - } - - // use the result to do the needful - const uploadResult: CommandResultMetaData = uc.getResultMetaData(); - - if (uc.getStatus() === CommandStatus.success) { - console.log(uploadResult.messages); - console.log(uc.getBytesUploaded()); - } else { - console.log(uploadResult.errors); - } - -})(); -``` diff --git a/docs/userManagement.md b/docs/userManagement.md deleted file mode 100644 index c7323136..00000000 --- a/docs/userManagement.md +++ /dev/null @@ -1,69 +0,0 @@ -## User Management -The nextcloud-node-client provides the complete set of nextcloud user management funtions in node.js to automate user management tasks. -Create, update or delete user information or bulk operations are supported. - -Example: -```typescript -// typescript -import Client, { User, UserGroup } from "nextcloud-node-client"; - -(async () => { - try { - // create a new client using connectivity - // information from environment - const client = new Client(); - // create a new user group - const group: UserGroup = await client.createUserGroup("MyGroup"); - // create a new user with a email or password - const user: User = await client.createUser({ id: "MyUserId", email: "mail@example.com" }); - // set some properties - // ... password, phone, website, twitter, address, email, locale - await user.setDisplayName("My Display Name"); - await user.setQuota("5 GB"); - await user.setLanguage("en"); - // get properties - // ... quota, user friendly quota, phone, website, twitter, address, locale - const email = await user.getEmail(); - // disable user - await user.disable(); - // enable user - await user.enable(); - // promote to super administrator - await user.promoteToSuperAdmin(); - // demote from super administrator - await user.demoteFromSuperAdmin(); - // resend welcome email to user - await user.resendWelcomeEmail(); - // add to user group as member - await user.addToMemberUserGroup(group); - // get member user groups - const memberGroups: UserGroup[] = await user.getMemberUserGroups(); - // get user ids of memembers - await group.getMemberUserIds(); - // remove user from member group - await user.removeFromMemberUserGroup(group); - // promote user as subadmin for user group - await user.promoteToUserGroupSubadmin(group); - // get user groups where the user is subadmin - const subadminGroups: UserGroup[] = await user.getSubadminUserGroups(); - // get user ids of subadmins - await group.getSubadminUserIds(); - // demote user from being subadmin for user group - await user.demoteFromSubadminUserGroup(group); - // delete the user - await user.delete(); - // delete the user group - await group.delete(); - // mass creations / updates of users - // groups are created on the fly - await client.upsertUsers([ - { id: "myUser1", email: "myUser1@example.com", enabled: false, memberGroups: ["group1", "group2"] }, - { id: "myUser2", password: "mySecurePassword", displayName: "My Name", superAdmin: true, quota: "2 GB" }, - // ... - ]); - } catch (e) { - // use specific exception *error classes - // for error handling documented in @throws - } -})(); -``` \ No newline at end of file diff --git a/package.json b/package.json index 7f65c507..d0975c5a 100644 --- a/package.json +++ b/package.json @@ -9,14 +9,15 @@ "url": "git+https://github.com/hobigo/nextcloud-node-client.git" }, "scripts": { - "build-watch": "node ./node_modules/typescript/bin/tsc -w", - "build": "node ./node_modules/typescript/bin/tsc", - "build-release": "node ./node_modules/typescript/bin/tsc && typedoc --out ./docs/ ./src/client.ts", + "prepublishOnly": "npm run build-release", + "build-watch": "tsc --watch", + "build": "tsc", + "build-release": "npm run build && npm run typedoc", "test": "mocha -r ts-node/register src/test/*test.ts", "cover": "nyc mocha -r ts-node/register src/test/*test.ts && nyc report --reporter=text-lcov > coverage.lcov", "record": "nyc mocha -r ts-node/register src/test/*test.ts --record", - "documentation": "typedoc", - "create-lcov": "./node_modules/.bin/codecov -t ", + "typedoc": "typedoc --out ./docs/ ./src/client.ts", + "create-lcov": "codecov -t ", "eslint": "npx eslint" }, "nyc": { @@ -53,41 +54,39 @@ ], "license": "Apache-2.0", "dependencies": { - "@hapi/joi": "^17.1.1", "debug": "^4.1.0", - "dotenv": "^8.2.0", - "fast-xml-parser": "^3.17.4", - "http-proxy-agent": "^4.0.1", + "dotenv": "^11.0.0", + "fast-xml-parser": "^4.0.1", + "form-data": "^4.0.0", + "http-proxy-agent": "^5.0.0", "joi": "^17.2.1", - "node-fetch": "^2.6.0", - "tslog": "^2.6.2", + "node-fetch": "2.6.6", + "tslog": "^3.3.1", "vcap_services": "^0.7.1" }, "devDependencies": { - "@types/chai": "^4.2.12", - "@types/debug": "^4.1.5", - "@types/http-proxy-agent": "^2.0.2", - "@types/joi": "^14.3.4", - "@types/mocha": "^8.0.0", + "@types/chai": "^4.3.0", + "@types/debug": "^4.1.7", + "@types/form-data": "^2.5.0", + "@types/mocha": "^9.0.0", "@types/node": "^14.0.27", - "@types/node-fetch": "^2.5.7", - "@typescript-eslint/eslint-plugin": "^4.0.0", - "@typescript-eslint/parser": "^4.2.0", - "chai": "^4.2.0", - "codecov": "^3.7.2", - "eslint": "^7.5.0", - "eslint-config-prettier": "^6.11.0", - "eslint-plugin-jsdoc": "^30.3.0", - "eslint-plugin-prefer-arrow": "^1.2.2", - "eslint-plugin-prettier": "^3.1.4", - "mocha": "^8.1.3", - "mocked-env": "^1.3.2", + "@types/node-fetch": "^2.5.12", + "@typescript-eslint/eslint-plugin": "^5.9.1", + "@typescript-eslint/parser": "^5.9.1", + "chai": "^4.3.4", + "codecov": "^3.8.3", + "eslint": "^8.6.0", + "eslint-config-prettier": "^8.3.0", + "eslint-plugin-jsdoc": "^37.6.1", + "eslint-plugin-prefer-arrow": "^1.2.3", + "eslint-plugin-prettier": "^4.0.0", + "mocha": "^9.1.3", + "mocked-env": "^1.3.5", "nyc": "^15.1.0", - "prettier": "^2.0.5", - "ts-loader": "^8.0.0", - "ts-node": "^9.0.0", - "typedoc": "^0.19.2", - "typescript": "^4.0.3" + "prettier": "^2.5.1", + "ts-node": "^10.4.0", + "typedoc": "^0.22.10", + "typescript": "^4.5.4" }, "bugs": { "url": "https://github.com/hobigo/nextcloud-node-client/issues" diff --git a/src/client.ts b/src/client.ts index 148fb326..cc284d2b 100644 --- a/src/client.ts +++ b/src/client.ts @@ -1,18 +1,26 @@ -/* eslint-disable @typescript-eslint/no-unsafe-assignment, @typescript-eslint/no-unsafe-member-access */ - import { config } from "dotenv"; config(); import Joi from "joi"; -import UploadFilesCommand, { UploadFilesCommandOptions, SourceTargetFileNames } from "./command/uploadFilesCommand"; -import UploadFolderCommand, { UploadFolderCommandOptions } from "./command/uploadFolderCommand"; -import GetFilesRecursivelyCommand, { GetFilesRecursivelyCommandOptions } from "./command/getFilesRecursivelyCommand"; -import DownloadFolderCommand, { DownloadFolderCommandOptions } from "./command/downloadFolderCommand"; +import UploadFilesCommand, { + UploadFilesCommandOptions, + SourceTargetFileNames +} from "./command/uploadFilesCommand"; +import UploadFolderCommand, { + UploadFolderCommandOptions +} from "./command/uploadFolderCommand"; +import GetFilesRecursivelyCommand, { + GetFilesRecursivelyCommandOptions +} from "./command/getFilesRecursivelyCommand"; +import DownloadFolderCommand, { + DownloadFolderCommandOptions +} from "./command/downloadFolderCommand"; import { CommandStatus, CommandResultMetaData } from "./command/command"; -import parser from "fast-xml-parser"; -import { Headers, RequestInit, Response } from "node-fetch"; +import { XMLParser, XMLValidator } from "fast-xml-parser"; +import { BodyInit, Headers, RequestInit, Response } from "node-fetch"; import path, { basename } from "path"; import Environment from "./environment"; import EnvironmentVcapServices from "./environmentVcapServices"; + import ClientError, { CommandAlreadyExecutedError, QueryLimitError, @@ -27,21 +35,31 @@ import ClientError, { UserNotFoundError, UserAlreadyExistsError, UserCreateError, - UserUpdateError, + UserUpdateError } from "./error"; import FakeServer from "./fakeServer"; import File from "./file"; import FileSystemElement from "./fileSystemElement"; import FileSystemFolder, { IFileNameFormats } from "./fileSystemFolder"; import Folder, { FolderGetFilesOptions } from "./folder"; -import { HttpClient, IHttpClientOptions, IProxy, IRequestContext } from "./httpClient"; +import { + HttpClient, + IHttpClientOptions, + IProxy, + IRequestContext +} from "./httpClient"; import RequestResponseLog from "./requestResponseLog"; import RequestResponseLogEntry from "./requestResponseLogEntry"; import Server, { IServerOptions } from "./server"; import Share, { ICreateShare, SharePermission, ShareItemType } from "./share"; import Tag from "./tag"; import UserGroup from "./userGroup"; -import User, { IUserOptions, IUserOptionsQuota, IUserQuotaUserFriendly, UserProperty } from "./user"; +import User, { + IUserOptions, + IUserOptionsQuota, + IUserQuotaUserFriendly, + UserProperty +} from "./user"; import Logger from "./logger"; import { isNumber } from "util"; const log: Logger = new Logger(); @@ -61,7 +79,7 @@ export { UserUpdateError, UserGroupAlreadyExistsError, UserGroupDeletionFailedError, - UserGroupDoesNotExistError, + UserGroupDoesNotExistError }; export { @@ -85,7 +103,7 @@ export { UserProperty, IUserOptionsQuota, IUserQuotaUserFriendly, - ShareItemType, + ShareItemType }; // command object for upload @@ -102,7 +120,7 @@ export { SourceTargetFileNames, FileSystemFolder, IFileNameFormats, - CommandStatus, + CommandStatus }; interface IStat { @@ -226,16 +244,18 @@ export default class Client { // If no VCAP_S environment exists try from environment if (!server) { try { - const env: EnvironmentVcapServices = new EnvironmentVcapServices("nextcloud"); + const env: EnvironmentVcapServices = new EnvironmentVcapServices( + "nextcloud" + ); server = env.getServer(); } catch (e) { const serverOptions: IServerOptions = { url: Environment.getNextcloudUrl(), basicAuth: { username: Environment.getUserName(), - password: Environment.getPassword(), + password: Environment.getPassword() }, - logRequestResponse: Environment.getRecordingActiveIndicator(), + logRequestResponse: Environment.getRecordingActiveIndicator() }; server = new Server(serverOptions); @@ -254,11 +274,18 @@ export default class Client { server.url = server.url + Client.webDavUrlPath; } - this.nextcloudOrigin = server.url.substr(0, server.url.indexOf(Client.webDavUrlPath)); + this.nextcloudOrigin = server.url.substr( + 0, + server.url.indexOf(Client.webDavUrlPath) + ); log.debug("constructor: nextcloud url ", this.nextcloudOrigin); this.userId = server.basicAuth.username; - this.nextcloudAuthHeader = "Basic " + Buffer.from(server.basicAuth.username + ":" + server.basicAuth.password).toString("base64"); + this.nextcloudAuthHeader = + "Basic " + + Buffer.from( + server.basicAuth.username + ":" + server.basicAuth.password + ).toString("base64"); this.nextcloudRequestToken = ""; if (server.url.slice(-1) === "/") { this.webDAVUrl = server.url.slice(0, -1); @@ -272,7 +299,7 @@ export default class Client { authorizationHeader: this.nextcloudAuthHeader, logRequestResponse: this.logRequestResponse, origin: this.nextcloudOrigin, - proxy: this.proxy, + proxy: this.proxy }; this.httpClient = new HttpClient(options); @@ -290,19 +317,30 @@ export default class Client { public async getQuota(): Promise { log.debug("getQuota"); const requestInit: RequestInit = { - method: "PROPFIND", + method: "PROPFIND" }; - const response: Response = await this.getHttpResponse(this.webDAVUrl + "/", requestInit, [207], { description: "Client get quota" }); + const response: Response = await this.getHttpResponse( + this.webDAVUrl + "/", + requestInit, + [207], + { + description: "Client get quota" + } + ); - const properties: any[] = await this.getPropertiesFromWebDAVMultistatusResponse(response, Client.webDavUrlPath + "/"); + const properties: any[] = + await this.getPropertiesFromWebDAVMultistatusResponse( + response, + Client.webDavUrlPath + "/" + ); let quota: IQuota | null = null; for (const prop of properties) { if (prop["quota-available-bytes"]) { quota = { available: "unlimited", - used: prop["quota-used-bytes"], + used: prop["quota-used-bytes"] }; if (prop["quota-available-bytes"] > 0) { quota.available = prop["quota-available-bytes"]; @@ -311,8 +349,14 @@ export default class Client { } if (!quota) { - log.debug("Error, quota not available: ", JSON.stringify(properties, null, 4)); - throw new ClientError(`Error, quota not available`, "ERR_QUOTA_NOT_AVAILABLE"); + log.debug( + "Error, quota not available: ", + JSON.stringify(properties, null, 4) + ); + throw new ClientError( + `Error, quota not available`, + "ERR_QUOTA_NOT_AVAILABLE" + ); } log.debug("getQuota =", quota); return quota; @@ -343,15 +387,23 @@ export default class Client { body: `{ "name": "${tagName}", "userVisible": true, "userAssignable": true, "canAssign": true }`, // eslint-disable-next-line @typescript-eslint/naming-convention headers: new Headers({ "Content-Type": "application/json" }), - method: "POST", + method: "POST" }; - const response: Response = await this.getHttpResponse(this.nextcloudOrigin + "/remote.php/dav/systemtags/", requestInit, [201], { description: "Tag create" }); + const response: Response = await this.getHttpResponse( + this.nextcloudOrigin + "/remote.php/dav/systemtags/", + requestInit, + [201], + { description: "Tag create" } + ); const tagString: string | null = response.headers.get("Content-Location"); if (tagString === "" || tagString === null) { log.error(`createTag 'tagName' ${tagName}`); - throw new ClientError(`Error, tag with name '${tagName}' could not be created`, "ERR_TAG_CREATE_FAILED"); + throw new ClientError( + `Error, tag with name '${tagName}' could not be created`, + "ERR_TAG_CREATE_FAILED" + ); } log.debug(`createTag new tagId ${tagString} tagName ${tagName}`); @@ -408,10 +460,15 @@ export default class Client { log.debug("deleteTag tagId: ", tagId); const requestInit: RequestInit = { - method: "DELETE", + method: "DELETE" }; - const response: Response = await this.getHttpResponse(`${this.nextcloudOrigin}/remote.php/dav/systemtags/${tagId}`, requestInit, [204, 404], { description: "Tag delete" }); + const response: Response = await this.getHttpResponse( + `${this.nextcloudOrigin}/remote.php/dav/systemtags/${tagId}`, + requestInit, + [204, 404], + { description: "Tag delete" } + ); } /** @@ -436,7 +493,9 @@ export default class Client { * @returns array of tags */ public async getTags(): Promise { - log.debug("getTags PROPFIND " + this.nextcloudOrigin + "/remote.php/dav/systemtags/"); + log.debug( + "getTags PROPFIND " + this.nextcloudOrigin + "/remote.php/dav/systemtags/" + ); const requestInit: RequestInit = { body: ` @@ -448,19 +507,39 @@ export default class Client { `, - method: "PROPFIND", + method: "PROPFIND" }; const relUrl = `/remote.php/dav/systemtags/`; - const response: Response = await this.getHttpResponse(this.nextcloudOrigin + relUrl, requestInit, [207], { description: "Tags get" }); + const response: Response = await this.getHttpResponse( + this.nextcloudOrigin + relUrl, + requestInit, + [207], + { + description: "Tags get" + } + ); - const properties: any[] = await this.getPropertiesFromWebDAVMultistatusResponse(response, relUrl + "/*"); + const properties: any[] = + await this.getPropertiesFromWebDAVMultistatusResponse( + response, + relUrl + "/*" + ); const tags: Tag[] = []; for (const prop of properties) { // eslint-disable-next-line no-underscore-dangle - tags.push(new Tag(this, this.getTagIdFromHref(prop._href), prop["display-name"], prop["user-visible"], prop["user-assignable"], prop["can-assign"])); + tags.push( + new Tag( + this, + this.getTagIdFromHref(prop._href), + prop["display-name"], + prop["user-visible"], + prop["user-assignable"], + prop["can-assign"] + ) + ); } return tags; @@ -485,13 +564,22 @@ export default class Client { `, - method: "PROPFIND", + method: "PROPFIND" }; const relUrl = `/remote.php/dav/systemtags-relations/files/${fileId}`; - const response: Response = await this.getHttpResponse(`${this.nextcloudOrigin}${relUrl}`, requestInit, [207], { description: "File get tags" }); - - const properties: any[] = await this.getPropertiesFromWebDAVMultistatusResponse(response, relUrl + "/*"); + const response: Response = await this.getHttpResponse( + `${this.nextcloudOrigin}${relUrl}`, + requestInit, + [207], + { description: "File get tags" } + ); + + const properties: any[] = + await this.getPropertiesFromWebDAVMultistatusResponse( + response, + relUrl + "/*" + ); // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment const tagMap: Map = new Map(); @@ -513,10 +601,15 @@ export default class Client { log.debug(`removeTagOfFile tagId: ${tagId} fileId:${fileId}`); const requestInit: RequestInit = { - method: "DELETE", + method: "DELETE" }; - await this.getHttpResponse(`${this.nextcloudOrigin}/remote.php/dav/systemtags-relations/files/${fileId}/${tagId}`, requestInit, [204, 404], { description: "File remove tag" }); + await this.getHttpResponse( + `${this.nextcloudOrigin}/remote.php/dav/systemtags-relations/files/${fileId}/${tagId}`, + requestInit, + [204, 404], + { description: "File remove tag" } + ); return; } @@ -535,12 +628,20 @@ export default class Client { `, - method: "PROPFIND", + method: "PROPFIND" }; - const response: Response = await this.getHttpResponse(fileUrl, requestInit, [207], { description: "File get id" }); + const response: Response = await this.getHttpResponse( + fileUrl, + requestInit, + [207], + { + description: "File get id" + } + ); - const properties: any[] = await this.getPropertiesFromWebDAVMultistatusResponse(response, ""); + const properties: any[] = + await this.getPropertiesFromWebDAVMultistatusResponse(response, ""); for (const prop of properties) { if (prop.fileid !== undefined) { @@ -583,10 +684,17 @@ export default class Client { `, - method: "PROPFIND", + method: "PROPFIND" }; const url = `${this.webDAVUrl}${folderName}`; - const response: Response = await this.getHttpResponse(url, requestInit, [207], { description: "Folder get contents" }); + const response: Response = await this.getHttpResponse( + url, + requestInit, + [207], + { + description: "Folder get contents" + } + ); const folderContents: any[] = []; const schema: Joi.ObjectSchema = Joi.object({ @@ -594,20 +702,26 @@ export default class Client { getlastmodified: Joi.string().required(), fileid: Joi.number().integer().required(), getcontenttype: Joi.string(), - getcontentlength: Joi.number().integer(), + getcontentlength: Joi.number().integer() }); - const properties: any[] = await this.getPropertiesFromWebDAVMultistatusResponse(response, ""); + const properties: any[] = + await this.getPropertiesFromWebDAVMultistatusResponse(response, ""); // validate the properties const { error, value } = schema.validate(properties); if (error) { - throw new ClientError(`Error get folder contents - folder name "${folderName}" error ${error.message};`, "INVALID"); + throw new ClientError( + `Error get folder contents - folder name "${folderName}" error ${error.message};`, + "INVALID" + ); } for (const prop of properties) { // eslint-disable-next-line @typescript-eslint/no-unsafe-call, no-underscore-dangle, @typescript-eslint/restrict-plus-operands - let fileName = decodeURI(prop._href.substr(prop._href.indexOf(Client.webDavUrlPath) + 18)); + let fileName = decodeURI( + prop._href.substr(prop._href.indexOf(Client.webDavUrlPath) + 18) + ); if (fileName.endsWith("/")) { fileName = fileName.slice(0, -1); } @@ -650,7 +764,10 @@ export default class Client { const parts1: string[] = folderName.split("/"); for (const p of parts1) { if (p === "." || p === "..") { - throw new ClientError(`Error creating folder, folder name "${folderName}" invalid`, "ERR_CREATE_FOLDER_INVALID_FOLDER_NAME"); + throw new ClientError( + `Error creating folder, folder name "${folderName}" invalid`, + "ERR_CREATE_FOLDER_INVALID_FOLDER_NAME" + ); } } @@ -713,10 +830,12 @@ export default class Client { log.debug("deleteFile ", url); const requestInit: RequestInit = { - method: "DELETE", + method: "DELETE" }; try { - await this.getHttpResponse(url, requestInit, [204], { description: "File delete" }); + await this.getHttpResponse(url, requestInit, [204], { + description: "File delete" + }); } catch (err) { log.debug("Error in deleteFile ", err.message, requestInit.method, url); throw err; @@ -755,7 +874,9 @@ export default class Client { * @async * @returns {Promise} returns an array of file system objects */ - public async getFileSystemElementByTags(tags: Tag[]): Promise { + public async getFileSystemElementByTags( + tags: Tag[] + ): Promise { log.debug("getFileSystemElementByTags ", tags.join(", ")); let filterRule: string = ""; @@ -777,11 +898,13 @@ export default class Client { const requestInit: RequestInit = { body, // headers: new Headers({ Depth: "0" }), - method: "REPORT", + method: "REPORT" }; let response: Response; try { - response = await this.getHttpResponse(url, requestInit, [207], { description: "Get FileSystemElements by tags" }); + response = await this.getHttpResponse(url, requestInit, [207], { + description: "Get FileSystemElements by tags" + }); } catch (err) { log.debug("Error in stat ", err.message, requestInit.method, url); throw err; @@ -790,7 +913,10 @@ export default class Client { let properties: any[] = []; try { - properties = await this.getPropertiesFromWebDAVMultistatusResponse(response, ""); + properties = await this.getPropertiesFromWebDAVMultistatusResponse( + response, + "" + ); } catch (e) { return result; } @@ -833,10 +959,16 @@ export default class Client { } try { - const stat: IStat = await this.stat(folderName); + const stat: IStat = await this.statForDirectory(folderName); log.debug(": SUCCESS!!"); if (stat.type !== "file") { - return new Folder(this, stat.filename.replace(/\\/g, "/"), stat.basename, stat.lastmod, stat.fileid); + return new Folder( + this, + stat.filename.replace(/\\/g, "/"), + stat.basename, + stat.lastmod, + stat.fileid + ); } else { log.debug("getFolder: found object is file not a folder"); return null; @@ -863,7 +995,15 @@ export default class Client { for (const folderElement of folderElements) { log.debug("getSubFolders: adding subfolders ", folderElement.filename); // eslint-disable-next-line @typescript-eslint/no-unsafe-call - folders.push(new Folder(this, folderElement.filename.replace(/\\/g, "/"), folderElement.basename, folderElement.lastmod, folderElement.fileid)); + folders.push( + new Folder( + this, + folderElement.filename.replace(/\\/g, "/"), + folderElement.basename, + folderElement.lastmod, + folderElement.fileid + ) + ); } return folders; @@ -876,7 +1016,10 @@ export default class Client { * @param {FolderGetFilesOptions} options options for filtering and paging * @returns array of file objects */ - public async getFiles(folderName: string, options?: FolderGetFilesOptions): Promise { + public async getFiles( + folderName: string, + options?: FolderGetFilesOptions + ): Promise { log.debug("getFiles: folder ", folderName); const files: File[] = []; folderName = this.sanitizeFolderName(folderName); @@ -887,7 +1030,15 @@ export default class Client { log.debug("getFiles: adding file ", folderElement.filename); // log.debug("getFiles: adding file ", folderElement); // eslint-disable-next-line @typescript-eslint/no-unsafe-call - let file: File | null = new File(this, folderElement.filename.replace(/\\/g, "/"), folderElement.basename, folderElement.lastmod, folderElement.size, folderElement.mime, folderElement.fileid); + let file: File | null = new File( + this, + folderElement.filename.replace(/\\/g, "/"), + folderElement.basename, + folderElement.lastmod, + folderElement.size, + folderElement.mime, + folderElement.fileid + ); if (options && options.filterFile) { file = options.filterFile(file); @@ -906,7 +1057,10 @@ export default class Client { * @param fileName the file name /folder1/folder2/filename.txt * @param data the buffer object */ - public async createFile(fileName: string, data: Buffer | NodeJS.ReadableStream): Promise { + public async createFile( + fileName: string, + data: Buffer | NodeJS.ReadableStream + ): Promise { if (fileName.startsWith("./")) { fileName = fileName.replace("./", "/"); } @@ -923,7 +1077,10 @@ export default class Client { const file: File | null = await this.getFile(fileName); if (!file) { - throw new ClientError(`Error creating file, file name "${fileName}"`, "ERR_CREATE_FILE_FAILED"); + throw new ClientError( + `Error creating file, file name "${fileName}"`, + "ERR_CREATE_FILE_FAILED" + ); } return file; } @@ -940,7 +1097,15 @@ export default class Client { const stat: IStat = await this.stat(fileName); log.debug(": SUCCESS!!"); if (stat.type === "file") { - return new File(this, stat.filename.replace(/\\/g, "/"), stat.basename, stat.lastmod, stat.size!, stat.mime || "", stat.fileid || -1); + return new File( + this, + stat.filename.replace(/\\/g, "/"), + stat.basename, + stat.lastmod, + stat.size!, + stat.mime || "", + stat.fileid || -1 + ); } else { log.debug("getFile: found object is a folder not a file"); return null; @@ -957,7 +1122,10 @@ export default class Client { * @param sourceFileName source file name * @param targetFileName target file name */ - public async moveFile(sourceFileName: string, targetFileName: string): Promise { + public async moveFile( + sourceFileName: string, + targetFileName: string + ): Promise { const url: string = this.webDAVUrl + sourceFileName; const destinationUrl: string = this.webDAVUrl + targetFileName; @@ -966,18 +1134,35 @@ export default class Client { const requestInit: RequestInit = { // eslint-disable-next-line @typescript-eslint/naming-convention headers: new Headers({ Destination: destinationUrl }), - method: "MOVE", + method: "MOVE" }; try { - await this.getHttpResponse(url, requestInit, [201], { description: "File move" }); + await this.getHttpResponse(url, requestInit, [201], { + description: "File move" + }); } catch (err) { - log.debug(`Error in move file ${err.message as string} ${requestInit.method || ""} source: ${url} destination: ${destinationUrl}`); - throw new ClientError(`Error: moving file failed: source=" ${sourceFileName} target= ${targetFileName} - ${err.message as string}`, "ERR_FILE_MOVE_FAILED"); + log.debug( + `Error in move file ${err.message as string} ${ + requestInit.method || "" + } source: ${url} destination: ${destinationUrl}` + ); + throw new ClientError( + `Error: moving file failed: source=" ${sourceFileName} target= ${targetFileName} - ${ + err.message as string + }`, + "ERR_FILE_MOVE_FAILED" + ); } const targetFile: File | null = await this.getFile(targetFileName); if (!targetFile) { - throw new ClientError("Error: moving file failed: source=" + sourceFileName + " target=" + targetFileName, "ERR_FILE_MOVE_FAILED"); + throw new ClientError( + "Error: moving file failed: source=" + + sourceFileName + + " target=" + + targetFileName, + "ERR_FILE_MOVE_FAILED" + ); } return targetFile; @@ -989,7 +1174,10 @@ export default class Client { * @param sourceFolderName source folder name * @param tarName target folder name */ - public async moveFolder(sourceFolderName: string, tarName: string): Promise { + public async moveFolder( + sourceFolderName: string, + tarName: string + ): Promise { const url: string = this.webDAVUrl + sourceFolderName; const destinationUrl: string = this.webDAVUrl + tarName; @@ -998,18 +1186,35 @@ export default class Client { const requestInit: RequestInit = { // eslint-disable-next-line @typescript-eslint/naming-convention headers: new Headers({ Destination: destinationUrl }), - method: "MOVE", + method: "MOVE" }; try { - await this.getHttpResponse(url, requestInit, [201], { description: "Folder move" }); + await this.getHttpResponse(url, requestInit, [201], { + description: "Folder move" + }); } catch (err) { - log.debug(`Error in move folder ${err.message as string} ${requestInit.method || ""} source: ${url} destination: ${destinationUrl}`); - throw new ClientError(`Error: moving folder failed: source=${sourceFolderName} target=${tarName} - ${err.message as string}`, "ERR_FOLDER_MOVE_FAILED"); + log.debug( + `Error in move folder ${err.message as string} ${ + requestInit.method || "" + } source: ${url} destination: ${destinationUrl}` + ); + throw new ClientError( + `Error: moving folder failed: source=${sourceFolderName} target=${tarName} - ${ + err.message as string + }`, + "ERR_FOLDER_MOVE_FAILED" + ); } const tar: Folder | null = await this.getFolder(tarName); if (!tar) { - throw new ClientError("Error: moving folder failed: source=" + sourceFolderName + " target=" + tarName, "ERR_FOLDER_MOVE_FAILED"); + throw new ClientError( + "Error: moving folder failed: source=" + + sourceFolderName + + " target=" + + tarName, + "ERR_FOLDER_MOVE_FAILED" + ); } return tar; @@ -1025,11 +1230,13 @@ export default class Client { const url = this.webDAVUrl + fileName; log.debug("getContent GET ", url); const requestInit: RequestInit = { - method: "GET", + method: "GET" }; let response: Response; try { - response = await this.getHttpResponse(url, requestInit, [200], { description: "File get content" }); + response = await this.getHttpResponse(url, requestInit, [200], { + description: "File get content" + }); } catch (err) { log.debug(`Error getContent ${url} - error ${err.message as string}`); throw err; @@ -1044,20 +1251,25 @@ export default class Client { * @param fileName name of the file /d1/file1.txt * @returns Buffer with file content */ - public async pipeContentStream(fileName: string, destination: NodeJS.WritableStream): Promise { + public async pipeContentStream( + fileName: string, + destination: NodeJS.WritableStream + ): Promise { const url = this.webDAVUrl + fileName; log.debug("getContent GET ", url); const requestInit: RequestInit = { - method: "GET", + method: "GET" }; let response: Response; try { - response = await this.getHttpResponse(url, requestInit, [200], { description: "File pipe content stream" }); + response = await this.getHttpResponse(url, requestInit, [200], { + description: "File pipe content stream" + }); } catch (err) { log.debug(`Error getContent ${url} - error ${err.message as string}`); throw err; } - response.body.pipe(destination); + response.body?.pipe(destination); } /** @@ -1096,7 +1308,10 @@ export default class Client { const tag: Tag = await this.createTag(tagName); if (!tag.canAssign) { - throw new ClientError(`Error: No permission to assign tag "${tagName}" to file. Tag is not assignable`, "ERR_TAG_NOT_ASSIGNABLE"); + throw new ClientError( + `Error: No permission to assign tag "${tagName}" to file. Tag is not assignable`, + "ERR_TAG_NOT_ASSIGNABLE" + ); } const addTagBody: any = { @@ -1104,17 +1319,22 @@ export default class Client { id: tag.id, name: tag.name, userAssignable: tag.assignable, - userVisible: tag.visible, + userVisible: tag.visible }; const requestInit: RequestInit = { body: JSON.stringify(addTagBody, null, 4), // eslint-disable-next-line @typescript-eslint/naming-convention headers: new Headers({ "Content-Type": "application/json" }), - method: "PUT", + method: "PUT" }; - await this.getHttpResponse(`${this.nextcloudOrigin}/remote.php/dav/systemtags-relations/files/${fileId}/${tag.id}`, requestInit, [201, 409], { description: "File add tag" }); // created or conflict + await this.getHttpResponse( + `${this.nextcloudOrigin}/remote.php/dav/systemtags-relations/files/${fileId}/${tag.id}`, + requestInit, + [201, 409], + { description: "File add tag" } + ); // created or conflict } // *************************************************************************************** @@ -1162,24 +1382,32 @@ export default class Client { * @param fileId the id of the file * @param comment the comment to be added to the file */ - public async addCommentToFile(fileId: number, comment: string): Promise { + public async addCommentToFile( + fileId: number, + comment: string + ): Promise { log.debug(`addCommentToFile file:"${fileId}" comment:"${comment}"`); const addCommentBody: any = { actorType: "users", message: comment, objectType: "files", - verb: "comment", + verb: "comment" }; const requestInit: RequestInit = { body: JSON.stringify(addCommentBody, null, 4), // eslint-disable-next-line @typescript-eslint/naming-convention headers: new Headers({ "Content-Type": "application/json" }), - method: "POST", + method: "POST" }; - await this.getHttpResponse(`${this.nextcloudOrigin}/remote.php/dav/comments/files/${fileId}`, requestInit, [201], { description: "File add comment" }); // created + await this.getHttpResponse( + `${this.nextcloudOrigin}/remote.php/dav/comments/files/${fileId}`, + requestInit, + [201], + { description: "File add comment" } + ); // created } /** @@ -1191,7 +1419,11 @@ export default class Client { * @returns array of comment strings * @throws Exception */ - public async getFileComments(fileId: number, top?: number, skip?: number): Promise { + public async getFileComments( + fileId: number, + top?: number, + skip?: number + ): Promise { log.debug("getFileComments fileId: ", fileId); if (!top) { top = 30; @@ -1207,12 +1439,18 @@ export default class Client { ${top} ${skip} `, - method: "REPORT", + method: "REPORT" }; - const response: Response = await this.getHttpResponse(`${this.nextcloudOrigin}/remote.php/dav/comments/files/${fileId}`, requestInit, [207], { description: "File get comments" }); + const response: Response = await this.getHttpResponse( + `${this.nextcloudOrigin}/remote.php/dav/comments/files/${fileId}`, + requestInit, + [207], + { description: "File get comments" } + ); - const properties: any[] = await this.getPropertiesFromWebDAVMultistatusResponse(response, ""); + const properties: any[] = + await this.getPropertiesFromWebDAVMultistatusResponse(response, ""); const comments: string[] = []; for (const prop of properties) { comments.push(prop.message); @@ -1227,10 +1465,15 @@ export default class Client { public async getSystemInfo(): Promise { const requestInit: RequestInit = { headers: this.getOcsHeaders(), - method: "GET", + method: "GET" }; - const response: Response = await this.getHttpResponse(this.nextcloudOrigin + "/ocs/v2.php/apps/serverinfo/api/v1/info", requestInit, [200], { description: "SystemInfo get" }); + const response: Response = await this.getHttpResponse( + this.nextcloudOrigin + "/ocs/v2.php/apps/serverinfo/api/v1/info", + requestInit, + [200], + { description: "SystemInfo get" } + ); const rawResult: any = await response.json(); // validate the raw result @@ -1245,37 +1488,58 @@ export default class Client { if (rawResult.ocs.data.nextcloud.system) { system = rawResult.ocs.data.nextcloud.system; } else { - throw new ClientError("Fatal Error: nextcloud data.nextcloud.system missing", "ERR_SYSTEM_INFO_MISSING_DATA"); + throw new ClientError( + "Fatal Error: nextcloud data.nextcloud.system missing", + "ERR_SYSTEM_INFO_MISSING_DATA" + ); } if (rawResult.ocs.data.nextcloud.storage) { storage = rawResult.ocs.data.nextcloud.storage; } else { - throw new ClientError("Fatal Error: nextcloud data.nextcloud.storage missing", "ERR_SYSTEM_INFO_MISSING_DATA"); + throw new ClientError( + "Fatal Error: nextcloud data.nextcloud.storage missing", + "ERR_SYSTEM_INFO_MISSING_DATA" + ); } if (rawResult.ocs.data.nextcloud.shares) { shares = rawResult.ocs.data.nextcloud.shares; } else { - throw new ClientError("Fatal Error: nextcloud data.nextcloud.shares missing", "ERR_SYSTEM_INFO_MISSING_DATA"); + throw new ClientError( + "Fatal Error: nextcloud data.nextcloud.shares missing", + "ERR_SYSTEM_INFO_MISSING_DATA" + ); } } else { - throw new ClientError("Fatal Error: nextcloud data.nextcloud missing", "ERR_SYSTEM_INFO_MISSING_DATA"); + throw new ClientError( + "Fatal Error: nextcloud data.nextcloud missing", + "ERR_SYSTEM_INFO_MISSING_DATA" + ); } if (rawResult.ocs.data.server) { server = rawResult.ocs.data.server; } else { - throw new ClientError("Fatal Error: nextcloud data.server missing", "ERR_SYSTEM_INFO_MISSING_DATA"); + throw new ClientError( + "Fatal Error: nextcloud data.server missing", + "ERR_SYSTEM_INFO_MISSING_DATA" + ); } if (rawResult.ocs.data.activeUsers) { activeUsers = rawResult.ocs.data.activeUsers; } else { - throw new ClientError("Fatal Error: nextcloud data.activeUsers missing", "ERR_SYSTEM_INFO_MISSING_DATA"); + throw new ClientError( + "Fatal Error: nextcloud data.activeUsers missing", + "ERR_SYSTEM_INFO_MISSING_DATA" + ); } } else { - throw new ClientError("Fatal Error: nextcloud system data missing", "ERR_SYSTEM_INFO_MISSING_DATA"); + throw new ClientError( + "Fatal Error: nextcloud system data missing", + "ERR_SYSTEM_INFO_MISSING_DATA" + ); } const result: ISystemInfo = { @@ -1283,13 +1547,13 @@ export default class Client { nextcloud: { shares, storage, - system, + system }, nextcloudClient: { // eslint-disable-next-line @typescript-eslint/no-var-requires - version: require("../package.json").version, + version: require("../package.json").version }, - server, + server }; return result; } @@ -1297,26 +1561,41 @@ export default class Client { public async getSystemBasicData(): Promise { const requestInit: RequestInit = { headers: this.getOcsHeaders(), - method: "GET", + method: "GET" }; - const response: Response = await this.getHttpResponse(this.nextcloudOrigin + "/ocs/v2.php/apps/serverinfo/api/v1/basicdata", requestInit, [200], { description: "System Basic Data get" }); + const response: Response = await this.getHttpResponse( + this.nextcloudOrigin + "/ocs/v2.php/apps/serverinfo/api/v1/basicdata", + requestInit, + [200], + { description: "System Basic Data get" } + ); const rawResult: any = await response.json(); // console.log("Basic Data\n", JSON.stringify(rawResult)); let result: ISysBasicData; - if (rawResult && rawResult.ocs && rawResult.ocs.data && rawResult.ocs.data.servertime && rawResult.ocs.data.uptime && rawResult.ocs.data.timeservers) { + if ( + rawResult && + rawResult.ocs && + rawResult.ocs.data && + rawResult.ocs.data.servertime && + rawResult.ocs.data.uptime && + rawResult.ocs.data.timeservers + ) { result = { // eslint-disable-next-line @typescript-eslint/no-unsafe-call serverTimeString: rawResult.ocs.data.servertime.replace("\n", ""), // eslint-disable-next-line @typescript-eslint/no-unsafe-call uptimeString: rawResult.ocs.data.uptime.replace("\n", ""), // eslint-disable-next-line @typescript-eslint/no-unsafe-call - timeServersString: rawResult.ocs.data.timeservers.trim(), + timeServersString: rawResult.ocs.data.timeservers.trim() }; } else { - throw new ClientError("Fatal Error: nextcloud basic data missing", "ERR_SYSTEM_INFO_MISSING_DATA"); + throw new ClientError( + "Fatal Error: nextcloud basic data missing", + "ERR_SYSTEM_INFO_MISSING_DATA" + ); } return result; @@ -1341,10 +1620,18 @@ export default class Client { * @throws QueryLimitError * @throws QueryOffsetError */ - public async getUserGroups(search?: string, limit?: number, offset?: number): Promise { + public async getUserGroups( + search?: string, + limit?: number, + offset?: number + ): Promise { log.debug("getUserGroups"); - const userGroupIds: string[] = await this.getUserGroupIds(search, limit, offset); + const userGroupIds: string[] = await this.getUserGroupIds( + search, + limit, + offset + ); const userGroups: UserGroup[] = []; for (const userGroupId of userGroupIds) { userGroups.push(new UserGroup(this, userGroupId)); @@ -1362,11 +1649,15 @@ export default class Client { * @throws QueryLimitError * @throws QueryOffsetError */ - public async getUserGroupIds(search?: string, limit?: number, offset?: number): Promise { + public async getUserGroupIds( + search?: string, + limit?: number, + offset?: number + ): Promise { log.debug("getUserGroupIds"); const requestInit: RequestInit = { headers: this.getOcsHeaders(), - method: "GET", + method: "GET" }; let url = this.getOcsUrl(`/groups`); @@ -1391,7 +1682,14 @@ export default class Client { } log.debug("url ", url); - const response: Response = await this.getHttpResponse(url, requestInit, [200], { description: "User Groups get" }); + const response: Response = await this.getHttpResponse( + url, + requestInit, + [200], + { + description: "User Groups get" + } + ); const rawResult: any = await response.json(); /* { @@ -1446,13 +1744,20 @@ export default class Client { log.debug("getUserGroupMembers"); const requestInit: RequestInit = { headers: this.getOcsHeaders(), - method: "GET", + method: "GET" }; const url = this.getOcsUrl(`/groups/${id}`); log.debug("url ", url); - const response: Response = await this.getHttpResponse(url, requestInit, [200], { description: "User group get members" }); + const response: Response = await this.getHttpResponse( + url, + requestInit, + [200], + { + description: "User group get members" + } + ); const rawResult: any = await response.json(); const userIds: string[] = []; @@ -1482,13 +1787,20 @@ export default class Client { log.debug("getUserGroupsubadmins"); const requestInit: RequestInit = { headers: this.getOcsHeaders(), - method: "GET", + method: "GET" }; const url = this.getOcsUrl(`/groups/${id}/subadmins`); log.debug("url ", url); - const response: Response = await this.getHttpResponse(url, requestInit, [200], { description: "User group get subadmins" }); + const response: Response = await this.getHttpResponse( + url, + requestInit, + [200], + { + description: "User group get subadmins" + } + ); const rawResult: any = await response.json(); const userIds: string[] = []; @@ -1520,10 +1832,17 @@ export default class Client { const requestInit: RequestInit = { body: JSON.stringify({ groupid: id }), headers: this.getOcsHeaders(), - method: "POST", + method: "POST" }; log.debug("request body: ", requestInit.body); - const response: Response = await this.getHttpResponse(this.getOcsUrl(`/groups`), requestInit, [200], { description: "UserGroup create" }); + const response: Response = await this.getHttpResponse( + this.getOcsUrl(`/groups`), + requestInit, + [200], + { + description: "UserGroup create" + } + ); const rawResult: any = await response.json(); if (this.getOcsMetaStatus(rawResult).code === 102) { @@ -1533,7 +1852,11 @@ export default class Client { if (this.getOcsMetaStatus(rawResult).code === 100) { return new UserGroup(this, id); } - throw new OperationFailedError(`User group ${id} could not be created: ${this.getOcsMetaStatus(rawResult).message}`); + throw new OperationFailedError( + `User group ${id} could not be created: ${ + this.getOcsMetaStatus(rawResult).message + }` + ); } /** @@ -1548,10 +1871,15 @@ export default class Client { log.debug("deleteUserGroup id=", id); const requestInit: RequestInit = { headers: this.getOcsHeaders(), - method: "DELETE", + method: "DELETE" }; log.debug("request body: ", requestInit.body); - const response: Response = await this.getHttpResponse(this.getOcsUrl(`/groups/${id}`), requestInit, [200], { description: "UserGroup delete" }); + const response: Response = await this.getHttpResponse( + this.getOcsUrl(`/groups/${id}`), + requestInit, + [200], + { description: "UserGroup delete" } + ); const rawResult: any = await response.json(); if (this.getOcsMetaStatus(rawResult).code === 101) { @@ -1559,7 +1887,9 @@ export default class Client { } if (this.getOcsMetaStatus(rawResult).code === 102) { - throw new UserGroupDeletionFailedError(`User Group ${id} could not be deleted`); + throw new UserGroupDeletionFailedError( + `User Group ${id} could not be deleted` + ); } } @@ -1576,11 +1906,15 @@ export default class Client { * @param limit number * @param offset number */ - public async getUsers(search?: string, limit?: number, offset?: number): Promise { + public async getUsers( + search?: string, + limit?: number, + offset?: number + ): Promise { log.debug("getUsers"); const requestInit: RequestInit = { headers: this.getOcsHeaders(), - method: "GET", + method: "GET" }; let url = this.getOcsUrl(`/users`); @@ -1605,7 +1939,14 @@ export default class Client { } log.debug("url ", url); - const response: Response = await this.getHttpResponse(url, requestInit, [200], { description: "Users get" }); + const response: Response = await this.getHttpResponse( + url, + requestInit, + [200], + { + description: "Users get" + } + ); const rawResult: any = await response.json(); /* { @@ -1645,13 +1986,20 @@ export default class Client { log.debug("getUserData"); const requestInit: RequestInit = { headers: this.getOcsHeaders(), - method: "GET", + method: "GET" }; const url = this.getOcsUrl(`/users/${id}`); log.debug("url ", url); - const response: Response = await this.getHttpResponse(url, requestInit, [200], { description: `User ${id} get` }); + const response: Response = await this.getHttpResponse( + url, + requestInit, + [200], + { + description: `User ${id} get` + } + ); const rawResult: any = await response.json(); if (this.getOcsMetaStatus(rawResult).code === 404) { @@ -1675,7 +2023,10 @@ export default class Client { log.debug("user data", rawResult.ocs.data); const userData: IUserOptions = { enabled: rawResult.ocs.data.enabled, - lastLogin: rawResult.ocs.data.lastLogin === 0 ? undefined : new Date(rawResult.ocs.data.lastLogin), + lastLogin: + rawResult.ocs.data.lastLogin === 0 + ? undefined + : new Date(rawResult.ocs.data.lastLogin), subadminGroups: rawResult.ocs.data.subadmin, memberGroups: rawResult.ocs.data.groups, quota: { @@ -1683,7 +2034,7 @@ export default class Client { used: 0, total: 0, relative: 0, - quota: 0, + quota: 0 }, email: rawResult.ocs.data.email, displayName: rawResult.ocs.data.displayname, @@ -1692,7 +2043,7 @@ export default class Client { website: rawResult.ocs.data.website, twitter: rawResult.ocs.data.twitter, language: rawResult.ocs.data.language, - locale: rawResult.ocs.data.locale, + locale: rawResult.ocs.data.locale }; if (rawResult.ocs.data.quota.quota === "none") { userData.quota = { quota: 0, relative: 0, used: 0 }; @@ -1700,7 +2051,11 @@ export default class Client { if (!rawResult.ocs.data.quota.relative) { rawResult.ocs.data.quota.relative = 0; } - userData.quota = { quota: rawResult.ocs.data.quota.quota, relative: rawResult.ocs.data.quota.relative, used: rawResult.ocs.data.quota.used }; + userData.quota = { + quota: rawResult.ocs.data.quota.quota, + relative: rawResult.ocs.data.quota.relative, + used: rawResult.ocs.data.quota.used + }; if (rawResult.ocs.data.quota.free) { userData.quota.free = rawResult.ocs.data.quota.free; } @@ -1722,13 +2077,20 @@ export default class Client { log.debug("enableUser"); const requestInit: RequestInit = { headers: this.getOcsHeaders(), - method: "PUT", + method: "PUT" }; const url = this.getOcsUrl(`/users/${id}/enable`); log.debug("url ", url); - const response: Response = await this.getHttpResponse(url, requestInit, [200], { description: `User ${id} enable` }); + const response: Response = await this.getHttpResponse( + url, + requestInit, + [200], + { + description: `User ${id} enable` + } + ); const rawResult: any = await response.json(); if (this.getOcsMetaStatus(rawResult).code === 100) { @@ -1748,13 +2110,20 @@ export default class Client { log.debug("disableUser"); const requestInit: RequestInit = { headers: this.getOcsHeaders(), - method: "PUT", + method: "PUT" }; const url = this.getOcsUrl(`/users/${id}/disable`); log.debug("url ", url); - const response: Response = await this.getHttpResponse(url, requestInit, [200], { description: `User ${id} disable` }); + const response: Response = await this.getHttpResponse( + url, + requestInit, + [200], + { + description: `User ${id} disable` + } + ); const rawResult: any = await response.json(); if (this.getOcsMetaStatus(rawResult).code === 100) { @@ -1774,13 +2143,20 @@ export default class Client { log.debug("deleteUser"); const requestInit: RequestInit = { headers: this.getOcsHeaders(), - method: "DELETE", + method: "DELETE" }; const url = this.getOcsUrl(`/users/${id}`); log.debug("url ", url); - const response: Response = await this.getHttpResponse(url, requestInit, [200], { description: `User ${id} delete` }); + const response: Response = await this.getHttpResponse( + url, + requestInit, + [200], + { + description: `User ${id} delete` + } + ); const rawResult: any = await response.json(); if (this.getOcsMetaStatus(rawResult).code === 100) { @@ -1813,14 +2189,24 @@ export default class Client { * @throws {UserNotFoundError} * @throws UserUpdateError */ - public async createUser(options: { id: string; email?: string; password?: string }): Promise { + public async createUser(options: { + id: string; + email?: string; + password?: string; + }): Promise { log.debug("createUser"); - const createUserBody: { userid: string; password?: string; email?: string } = { userid: options.id }; + const createUserBody: { + userid: string; + password?: string; + email?: string; + } = { userid: options.id }; if (options.email) { if (/^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(options.email)) { createUserBody.email = options.email; } else { - throw new UserCreateError(`Error creating user '${options.id}' - invalid email address '${options.email}'`); + throw new UserCreateError( + `Error creating user '${options.id}' - invalid email address '${options.email}'` + ); } } if (options.password) { @@ -1830,14 +2216,23 @@ export default class Client { const requestInit: RequestInit = { body: JSON.stringify(createUserBody, null, 4), headers: this.getOcsHeaders(), - method: "POST", + method: "POST" }; log.debug("request body: ", requestInit.body); - const response: Response = await this.getHttpResponse(this.getOcsUrl(`/users`), requestInit, [200], { description: `User ${options.id} create` }); + const response: Response = await this.getHttpResponse( + this.getOcsUrl(`/users`), + requestInit, + [200], + { + description: `User ${options.id} create` + } + ); const rawResult: any = await response.json(); if (this.getOcsMetaStatus(rawResult).code === 102) { - throw new UserAlreadyExistsError(`User with id '${options.id}' already exists`); + throw new UserAlreadyExistsError( + `User with id '${options.id}' already exists` + ); } const user: User | null = await this.getUser(options.id); @@ -1845,7 +2240,11 @@ export default class Client { return user; } - throw new UserCreateError(`Error creating user '${options.id}' - ${this.getOcsMetaStatus(rawResult).message} (${this.getOcsMetaStatus(rawResult).code})`); + throw new UserCreateError( + `Error creating user '${options.id}' - ${ + this.getOcsMetaStatus(rawResult).message + } (${this.getOcsMetaStatus(rawResult).code})` + ); } /** @@ -1859,18 +2258,29 @@ export default class Client { * @throws {UserNotFoundError} * @throws {UserUpdateError} */ - public async updateUserProperty(id: string, property: UserProperty, value: string): Promise { + public async updateUserProperty( + id: string, + property: UserProperty, + value: string + ): Promise { log.debug("updateUserProperty"); const body: { key: string; value: string } = { key: property, value }; const requestInit: RequestInit = { body: JSON.stringify(body, null, 4), headers: this.getOcsHeaders(), - method: "PUT", + method: "PUT" }; const url = this.getOcsUrl(`/users/${id}`); log.debug("request body: ", requestInit.body); - const response: Response = await this.getHttpResponse(url, requestInit, [200, 401], { description: `User ${id} update ${property}=${value}` }); + const response: Response = await this.getHttpResponse( + url, + requestInit, + [200, 401], + { + description: `User ${id} update ${property}=${value}` + } + ); const rawResult: any = await response.json(); // This service operation returns a 401, if the user does not exist - very strange... @@ -1894,7 +2304,11 @@ export default class Client { value = "********"; } // code 102 or 103 - throw new UserUpdateError(`User with id '${id}' could not be updated - ${property}=${value}. ${rawResult.ocs.meta.message as string}`); + throw new UserUpdateError( + `User with id '${id}' could not be updated - ${property}=${value}. ${ + rawResult.ocs.meta.message as string + }` + ); } /** @@ -1908,21 +2322,32 @@ export default class Client { const requestInit: RequestInit = { headers: this.getOcsHeaders(), - method: "POST", + method: "POST" }; const url = this.getOcsUrl(`/users/${id}/welcome`); log.debug("request body: ", requestInit.body); - const response: Response = await this.getHttpResponse(url, requestInit, [200], { description: `Resend welcome email for user ${id}` }); + const response: Response = await this.getHttpResponse( + url, + requestInit, + [200], + { + description: `Resend welcome email for user ${id}` + } + ); const rawResult: any = await response.json(); if (this.getOcsMetaStatus(rawResult).code === 101) { - throw new UserResendWelcomeEmailError(`Error sending welcome email for '${id}': Email address not available`); + throw new UserResendWelcomeEmailError( + `Error sending welcome email for '${id}': Email address not available` + ); } if (this.getOcsMetaStatus(rawResult).code === 100) { return; } - throw new UserResendWelcomeEmailError(`Error sending welcome email for '${id}' failed`); + throw new UserResendWelcomeEmailError( + `Error sending welcome email for '${id}' failed` + ); } /** @@ -1936,20 +2361,30 @@ export default class Client { * @throws {InsufficientPrivilegesError} * @throws {OperationFailedError} */ - public async addUserToMemberUserGroup(id: string, userGroupId: string): Promise { + public async addUserToMemberUserGroup( + id: string, + userGroupId: string + ): Promise { log.debug("addUserToUserGroup"); const body: { groupid: string } = { groupid: userGroupId }; const requestInit: RequestInit = { body: JSON.stringify(body, null, 4), headers: this.getOcsHeaders(), - method: "POST", + method: "POST" }; const url = this.getOcsUrl(`/users/${id}/groups`); log.debug("url ", url); - const response: Response = await this.getHttpResponse(url, requestInit, [200], { description: `Add user ${id} to user group ${userGroupId}` }); + const response: Response = await this.getHttpResponse( + url, + requestInit, + [200], + { + description: `Add user ${id} to user group ${userGroupId}` + } + ); const rawResult: any = await response.json(); if (this.getOcsMetaStatus(rawResult).code === 100) { @@ -1957,7 +2392,9 @@ export default class Client { } if (this.getOcsMetaStatus(rawResult).code === 102) { - throw new UserGroupDoesNotExistError(`User group ${userGroupId} does not exist`); + throw new UserGroupDoesNotExistError( + `User group ${userGroupId} does not exist` + ); } if (this.getOcsMetaStatus(rawResult).code === 103) { @@ -1965,10 +2402,16 @@ export default class Client { } if (this.getOcsMetaStatus(rawResult).code === 104) { - throw new InsufficientPrivilegesError(`Insufficient privileges to add a user to a group`); + throw new InsufficientPrivilegesError( + `Insufficient privileges to add a user to a group` + ); } - throw new OperationFailedError(`User ${id} could not be added to user group ${userGroupId}: ${this.getOcsMetaStatus(rawResult).message}`); + throw new OperationFailedError( + `User ${id} could not be added to user group ${userGroupId}: ${ + this.getOcsMetaStatus(rawResult).message + }` + ); } /** @@ -1982,20 +2425,30 @@ export default class Client { * @throws {InsufficientPrivilegesError} * @throws {OperationFailedError} */ - public async removeUserFromMemberUserGroup(id: string, userGroupId: string): Promise { + public async removeUserFromMemberUserGroup( + id: string, + userGroupId: string + ): Promise { log.debug("removeUserFromMemberUserGroup"); const body: { groupid: string } = { groupid: userGroupId }; const requestInit: RequestInit = { body: JSON.stringify(body, null, 4), headers: this.getOcsHeaders(), - method: "DELETE", + method: "DELETE" }; const url = this.getOcsUrl(`/users/${id}/groups`); log.debug("url ", url); - const response: Response = await this.getHttpResponse(url, requestInit, [200], { description: `Remove user ${id} from user group ${userGroupId}` }); + const response: Response = await this.getHttpResponse( + url, + requestInit, + [200], + { + description: `Remove user ${id} from user group ${userGroupId}` + } + ); const rawResult: any = await response.json(); if (this.getOcsMetaStatus(rawResult).code === 100) { @@ -2003,7 +2456,9 @@ export default class Client { } if (this.getOcsMetaStatus(rawResult).code === 102) { - throw new UserGroupDoesNotExistError(`User group ${userGroupId} does not exist`); + throw new UserGroupDoesNotExistError( + `User group ${userGroupId} does not exist` + ); } if (this.getOcsMetaStatus(rawResult).code === 103) { @@ -2011,10 +2466,16 @@ export default class Client { } if (this.getOcsMetaStatus(rawResult).code === 104) { - throw new InsufficientPrivilegesError(`Insufficient privileges to add a user to a group`); + throw new InsufficientPrivilegesError( + `Insufficient privileges to add a user to a group` + ); } - throw new OperationFailedError(`User ${id} could not be added to user group ${userGroupId}: ${this.getOcsMetaStatus(rawResult).message}`); + throw new OperationFailedError( + `User ${id} could not be added to user group ${userGroupId}: ${ + this.getOcsMetaStatus(rawResult).message + }` + ); } /** @@ -2028,20 +2489,30 @@ export default class Client { * @throws {InsufficientPrivilegesError} * @throws {OperationFailedError} */ - public async promoteUserToUserGroupSubadmin(id: string, userGroupId: string): Promise { + public async promoteUserToUserGroupSubadmin( + id: string, + userGroupId: string + ): Promise { log.debug("promoteUserToUserGroupSubadmin"); const body: { groupid: string } = { groupid: userGroupId }; const requestInit: RequestInit = { body: JSON.stringify(body, null, 4), headers: this.getOcsHeaders(), - method: "POST", + method: "POST" }; const url = this.getOcsUrl(`/users/${id}/subadmins`); log.debug("url ", url); - const response: Response = await this.getHttpResponse(url, requestInit, [200], { description: `Promote User ${id} to user group subadmin ${userGroupId}` }); + const response: Response = await this.getHttpResponse( + url, + requestInit, + [200], + { + description: `Promote User ${id} to user group subadmin ${userGroupId}` + } + ); const rawResult: any = await response.json(); if (this.getOcsMetaStatus(rawResult).code === 100) { @@ -2049,7 +2520,9 @@ export default class Client { } if (this.getOcsMetaStatus(rawResult).code === 102) { - throw new UserGroupDoesNotExistError(`User group ${userGroupId} does not exist`); + throw new UserGroupDoesNotExistError( + `User group ${userGroupId} does not exist` + ); } if (this.getOcsMetaStatus(rawResult).code === 101) { @@ -2057,10 +2530,16 @@ export default class Client { } if (this.getOcsMetaStatus(rawResult).code === 104) { - throw new InsufficientPrivilegesError(`Insufficient privileges to add a user to a group`); + throw new InsufficientPrivilegesError( + `Insufficient privileges to add a user to a group` + ); } - throw new OperationFailedError(`User ${id} could not be removed from user group ${userGroupId}: ${this.getOcsMetaStatus(rawResult).message}`); + throw new OperationFailedError( + `User ${id} could not be removed from user group ${userGroupId}: ${ + this.getOcsMetaStatus(rawResult).message + }` + ); } /** @@ -2072,20 +2551,30 @@ export default class Client { * @throws {InsufficientPrivilegesError} * @throws {OperationFailedError} */ - public async demoteUserFromSubadminUserGroup(id: string, userGroupId: string): Promise { + public async demoteUserFromSubadminUserGroup( + id: string, + userGroupId: string + ): Promise { log.debug("demoteUserFromSubadminUserGroup"); const body: { groupid: string } = { groupid: userGroupId }; const requestInit: RequestInit = { body: JSON.stringify(body, null, 4), headers: this.getOcsHeaders(), - method: "DELETE", + method: "DELETE" }; const url = this.getOcsUrl(`/users/${id}/subadmins`); log.debug("url ", url); - const response: Response = await this.getHttpResponse(url, requestInit, [200], { description: `Demotes user ${id} from subadmin user group ${userGroupId}` }); + const response: Response = await this.getHttpResponse( + url, + requestInit, + [200], + { + description: `Demotes user ${id} from subadmin user group ${userGroupId}` + } + ); const rawResult: any = await response.json(); if (this.getOcsMetaStatus(rawResult).code === 100) { @@ -2104,10 +2593,16 @@ export default class Client { } */ if (this.getOcsMetaStatus(rawResult).code === 104) { - throw new InsufficientPrivilegesError(`Insufficient privileges to add a user to a group`); + throw new InsufficientPrivilegesError( + `Insufficient privileges to add a user to a group` + ); } - throw new OperationFailedError(`User ${id} could not be demoted from subadmin user group ${userGroupId}: ${this.getOcsMetaStatus(rawResult).message}`); + throw new OperationFailedError( + `User ${id} could not be demoted from subadmin user group ${userGroupId}: ${ + this.getOcsMetaStatus(rawResult).message + }` + ); } /** @@ -2116,19 +2611,31 @@ export default class Client { * @param options IUpsertUserOptions[] * @returns Promise { + public async upsertUsers( + options: IUpsertUserOptions[] + ): Promise { const report: IUpsertUserReport[] = []; for (const option of options) { - const userReport: IUpsertUserReport = { id: option.id, message: "", changes: [] }; + const userReport: IUpsertUserReport = { + id: option.id, + message: "", + changes: [] + }; let user: User | null = await this.getUser(option.id); // create or update user? if (!user) { try { - user = await this.createUser({ id: option.id, email: option.email, password: option.password }); + user = await this.createUser({ + id: option.id, + email: option.email, + password: option.password + }); userReport.message = `User ${option.id} created`; } catch (e) { - userReport.message = `Create user ${option.id} failed ${e.message as string}`; + userReport.message = `Create user ${option.id} failed ${ + e.message as string + }`; report.push(userReport); continue; } @@ -2147,18 +2654,36 @@ export default class Client { if ((await user.isEnabled()) && option.enabled === false) { try { await user.disable(); - userReport.changes.push({ property: "enabled", previousValue: "true", newValue: "false" }); + userReport.changes.push({ + property: "enabled", + previousValue: "true", + newValue: "false" + }); } catch (e) { - userReport.changes.push({ property: "enabled", previousValue: "true", newValue: "true", error: e.message }); + userReport.changes.push({ + property: "enabled", + previousValue: "true", + newValue: "true", + error: e.message + }); } } if ((await user.isEnabled()) === false && option.enabled === true) { try { await user.enable(); - userReport.changes.push({ property: "enabled", previousValue: "false", newValue: "true" }); + userReport.changes.push({ + property: "enabled", + previousValue: "false", + newValue: "true" + }); } catch (e) { - userReport.changes.push({ property: "enabled", previousValue: "false", newValue: "false", error: e.message }); + userReport.changes.push({ + property: "enabled", + previousValue: "false", + newValue: "false", + error: e.message + }); } } } @@ -2170,18 +2695,39 @@ export default class Client { if ((await user.isSuperAdmin()) && option.superAdmin === false) { try { await user.demoteFromSuperAdmin(); - userReport.changes.push({ property: "superAdmin", previousValue: "true", newValue: "false" }); + userReport.changes.push({ + property: "superAdmin", + previousValue: "true", + newValue: "false" + }); } catch (e) { - userReport.changes.push({ property: "superAdmin", previousValue: "true", newValue: "true", error: e.message }); + userReport.changes.push({ + property: "superAdmin", + previousValue: "true", + newValue: "true", + error: e.message + }); } } - if ((await user.isSuperAdmin()) === false && option.superAdmin === true) { + if ( + (await user.isSuperAdmin()) === false && + option.superAdmin === true + ) { try { await user.promoteToSuperAdmin(); - userReport.changes.push({ property: "superAdmin", previousValue: "false", newValue: "true" }); + userReport.changes.push({ + property: "superAdmin", + previousValue: "false", + newValue: "true" + }); } catch (e) { - userReport.changes.push({ property: "superAdmin", previousValue: "false", newValue: "false", error: e.message }); + userReport.changes.push({ + property: "superAdmin", + previousValue: "false", + newValue: "false", + error: e.message + }); } } } @@ -2199,8 +2745,12 @@ export default class Client { } } } - const groupsToAdd: string[] = newGroups.filter((x) => !previousGroups.includes(x)); - const groupsToRemove: string[] = previousGroups.filter((x) => !newGroups.includes(x)); + const groupsToAdd: string[] = newGroups.filter( + x => !previousGroups.includes(x) + ); + const groupsToRemove: string[] = previousGroups.filter( + x => !newGroups.includes(x) + ); let userGroup: UserGroup | null; property = "memberGroups"; let error: Error | null = null; @@ -2231,10 +2781,19 @@ export default class Client { } } if (error) { - userReport.changes.push({ property, previousValue: previousGroups.join(", "), newValue: previousGroups.join(", "), error: error.message }); + userReport.changes.push({ + property, + previousValue: previousGroups.join(", "), + newValue: previousGroups.join(", "), + error: error.message + }); } else { if (groupsToAdd.length > 0 || groupsToRemove.length > 0) { - userReport.changes.push({ property, previousValue: previousGroups.join(", "), newValue: newGroups.join(", ") }); + userReport.changes.push({ + property, + previousValue: previousGroups.join(", "), + newValue: newGroups.join(", ") + }); } } } @@ -2245,8 +2804,12 @@ export default class Client { if (option.subadminGroups !== undefined) { const previousGroups: string[] = await user.getSubadminUserGroupIds(); const newGroups: string[] = option.subadminGroups; - const groupsToAdd: string[] = newGroups.filter((x) => !previousGroups.includes(x)); - const groupsToRemove: string[] = previousGroups.filter((x) => !newGroups.includes(x)); + const groupsToAdd: string[] = newGroups.filter( + x => !previousGroups.includes(x) + ); + const groupsToRemove: string[] = previousGroups.filter( + x => !newGroups.includes(x) + ); let userGroup: UserGroup | null; property = "subadminGroups"; let error: Error | null = null; @@ -2270,16 +2833,27 @@ export default class Client { for (const groupId of groupsToRemove) { try { - await user.demoteFromSubadminUserGroup(new UserGroup(this, groupId)); + await user.demoteFromSubadminUserGroup( + new UserGroup(this, groupId) + ); } catch (e) { error = e as Error; break; } } if (error) { - userReport.changes.push({ property, previousValue: previousGroups.join(", "), newValue: previousGroups.join(", "), error: error.message }); + userReport.changes.push({ + property, + previousValue: previousGroups.join(", "), + newValue: previousGroups.join(", "), + error: error.message + }); } else { - userReport.changes.push({ property, previousValue: previousGroups.join(", "), newValue: newGroups.join(", ") }); + userReport.changes.push({ + property, + previousValue: previousGroups.join(", "), + newValue: newGroups.join(", ") + }); } } @@ -2299,7 +2873,12 @@ export default class Client { if (e instanceof Error) { message = e.message; } - userReport.changes.push({ property, previousValue, newValue: previousValue, error: message }); + userReport.changes.push({ + property, + previousValue, + newValue: previousValue, + error: message + }); } } } @@ -2320,7 +2899,12 @@ export default class Client { if (e instanceof Error) { message = e.message; } - userReport.changes.push({ property, previousValue, newValue: previousValue, error: message }); + userReport.changes.push({ + property, + previousValue, + newValue: previousValue, + error: message + }); } } } @@ -2341,7 +2925,12 @@ export default class Client { if (e instanceof Error) { message = e.message; } - userReport.changes.push({ property, previousValue, newValue: previousValue, error: message }); + userReport.changes.push({ + property, + previousValue, + newValue: previousValue, + error: message + }); } } } @@ -2362,7 +2951,12 @@ export default class Client { if (e instanceof Error) { message = e.message; } - userReport.changes.push({ property, previousValue, newValue: previousValue, error: message }); + userReport.changes.push({ + property, + previousValue, + newValue: previousValue, + error: message + }); } } } @@ -2383,7 +2977,12 @@ export default class Client { if (e instanceof Error) { message = e.message; } - userReport.changes.push({ property, previousValue, newValue: previousValue, error: message }); + userReport.changes.push({ + property, + previousValue, + newValue: previousValue, + error: message + }); } } } @@ -2405,7 +3004,12 @@ export default class Client { message = e.message; } - userReport.changes.push({ property, previousValue, newValue: previousValue, error: message }); + userReport.changes.push({ + property, + previousValue, + newValue: previousValue, + error: message + }); } } } @@ -2419,13 +3023,22 @@ export default class Client { property = "password"; try { await user.setPassword(option.password); - userReport.changes.push({ property, previousValue, newValue: previousValue }); + userReport.changes.push({ + property, + previousValue, + newValue: previousValue + }); } catch (e) { let message = ""; if (e instanceof Error) { message = e.message; } - userReport.changes.push({ property, previousValue, newValue: previousValue, error: message }); + userReport.changes.push({ + property, + previousValue, + newValue: previousValue, + error: message + }); } } @@ -2445,7 +3058,12 @@ export default class Client { if (e instanceof Error) { message = e.message; } - userReport.changes.push({ property, previousValue, newValue: previousValue, error: message }); + userReport.changes.push({ + property, + previousValue, + newValue: previousValue, + error: message + }); } } } @@ -2466,7 +3084,12 @@ export default class Client { if (e instanceof Error) { message = e.message; } - userReport.changes.push({ property, previousValue, newValue: previousValue, error: message }); + userReport.changes.push({ + property, + previousValue, + newValue: previousValue, + error: message + }); } } } @@ -2488,7 +3111,12 @@ export default class Client { message = e.message; } - userReport.changes.push({ property, previousValue, newValue: previousValue, error: message }); + userReport.changes.push({ + property, + previousValue, + newValue: previousValue, + error: message + }); } } } @@ -2510,7 +3138,12 @@ export default class Client { message = e.message; } - userReport.changes.push({ property, previousValue, newValue: previousValue, error: message }); + userReport.changes.push({ + property, + previousValue, + newValue: previousValue, + error: message + }); } } } @@ -2535,21 +3168,45 @@ export default class Client { const shareRequest = Share.createShareRequestBody(options); log.debug(shareRequest); + const headers = this.getOcsHeaders(); + + headers.set( + "Content-Type", + "multipart/form-data;boundary=" + shareRequest.getBoundary() + ); + const requestInit: RequestInit = { body: shareRequest, - headers: this.getOcsHeaders(), - method: "POST", + headers, + method: "POST" }; - const url = this.nextcloudOrigin + "/ocs/v2.php/apps/files_sharing/api/v1/shares"; + + const url = + this.nextcloudOrigin + "/ocs/v2.php/apps/files_sharing/api/v1/shares"; // try { - const response: Response = await this.getHttpResponse(url, requestInit, [200, 204], { description: "Share create" }); + const response: Response = await this.getHttpResponse( + url, + requestInit, + [200, 204], + { + description: "Share create" + } + ); - const rawResult: { ocs: { data: { id: string } } } = (await response.json()) as { ocs: { data: { id: string } } }; + const rawResult: { ocs: { data: { id: string } } } = + (await response.json()) as { + ocs: { data: { id: string } }; + }; log.debug(rawResult); - const share: Share = await Share.getShare(this, rawResult.ocs.data.id); + const share: Share = await Share.getShare( + this, + options.shareType, + options.permissions, + rawResult.ocs.data.id + ); if (options.publicUpload) { await share.setPublicUpload(); @@ -2569,17 +3226,29 @@ export default class Client { /** * update a new share */ - public async updateShare(shareId: string, body: { password: string } | { expireDate: string } | { note: string } | { permissions: number }): Promise { + public async updateShare( + shareId: string, + body: + | { password: string } + | { expireDate: string } + | { note: string } + | { permissions: number } + ): Promise { log.debug("updateShare body ", body); const requestInit: RequestInit = { body: JSON.stringify(body, null, 4), headers: this.getOcsHeaders(), - method: "PUT", + method: "PUT" }; - const url = this.nextcloudOrigin + "/ocs/v2.php/apps/files_sharing/api/v1/shares/" + shareId; + const url = + this.nextcloudOrigin + + "/ocs/v2.php/apps/files_sharing/api/v1/shares/" + + shareId; - await this.getHttpResponse(url, requestInit, [200], { description: "Share update" }); + await this.getHttpResponse(url, requestInit, [200], { + description: "Share update" + }); } /** @@ -2590,11 +3259,21 @@ export default class Client { public async getShare(shareId: string): Promise { const requestInit: RequestInit = { headers: this.getOcsHeaders(), - method: "GET", + method: "GET" }; - const url = this.nextcloudOrigin + "/ocs/v2.php/apps/files_sharing/api/v1/shares/" + shareId; - - const response: Response = await this.getHttpResponse(url, requestInit, [200], { description: "Share get" }); + const url = + this.nextcloudOrigin + + "/ocs/v2.php/apps/files_sharing/api/v1/shares/" + + shareId; + + const response: Response = await this.getHttpResponse( + url, + requestInit, + [200], + { + description: "Share get" + } + ); // eslint-disable-next-line @typescript-eslint/no-unsafe-return return await response.json(); @@ -2618,11 +3297,21 @@ export default class Client { public async deleteShare(shareId: string): Promise { const requestInit: RequestInit = { headers: this.getOcsHeaders(), - method: "DELETE", + method: "DELETE" }; - const url = this.nextcloudOrigin + "/ocs/v2.php/apps/files_sharing/api/v1/shares/" + shareId; - - const response: Response = await this.getHttpResponse(url, requestInit, [200], { description: "Share delete" }); + const url = + this.nextcloudOrigin + + "/ocs/v2.php/apps/files_sharing/api/v1/shares/" + + shareId; + + const response: Response = await this.getHttpResponse( + url, + requestInit, + [200], + { + description: "Share delete" + } + ); } // *************************************************************************************** @@ -2635,10 +3324,16 @@ export default class Client { public async getNotifications(): Promise { const requestInit: RequestInit = { headers: this.getOcsHeaders(), - method: "GET", + method: "GET" }; - const response: Response = await this.getHttpResponse(this.nextcloudOrigin + "/ocs/v2.php/apps/notifications/api/v2/notifications", requestInit, [200, 404], { description: "Notifications get" }); + const response: Response = await this.getHttpResponse( + this.nextcloudOrigin + + "/ocs/v2.php/apps/notifications/api/v2/notifications", + requestInit, + [200, 404], + { description: "Notifications get" } + ); // no notification found if (response.status === 404) { @@ -2652,7 +3347,10 @@ export default class Client { if (rawResult && rawResult.ocs && rawResult.ocs.data) { notifications = rawResult.ocs.data; } else { - throw new ClientError("Fatal Error: nextcloud notifications data missing", "ERR_SYSTEM_INFO_MISSING_DATA"); // @todo wrong error message + throw new ClientError( + "Fatal Error: nextcloud notifications data missing", + "ERR_SYSTEM_INFO_MISSING_DATA" + ); // @todo wrong error message } // eslint-disable-next-line @typescript-eslint/ban-types @@ -2666,10 +3364,16 @@ export default class Client { const requestInit: RequestInit = { headers: this.getOcsHeaders(), - method: "GET", + method: "GET" }; - const response: Response = await this.getHttpResponse(this.nextcloudOrigin + `/ocs/v2.php/apps/updatenotification/api/v1/applist/${version}`, requestInit, [200], { description: "UpdateNotifications get" }); + const response: Response = await this.getHttpResponse( + this.nextcloudOrigin + + `/ocs/v2.php/apps/updatenotification/api/v1/applist/${version}`, + requestInit, + [200], + { description: "UpdateNotifications get" } + ); // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment const rawResult: any = await response.json(); @@ -2680,7 +3384,10 @@ export default class Client { if (rawResult && rawResult.ocs && rawResult.ocs.data) { updateNotification = rawResult.ocs.data; } else { - throw new ClientError("Fatal Error: nextcloud notifications data missing", "ERR_SYSTEM_INFO_MISSING_DATA"); + throw new ClientError( + "Fatal Error: nextcloud notifications data missing", + "ERR_SYSTEM_INFO_MISSING_DATA" + ); } // eslint-disable-next-line @typescript-eslint/ban-types @@ -2689,7 +3396,11 @@ export default class Client { } // @todo to be refactored to user - public async sendNotificationToUser(userId: string, shortMessage: string, longMessage?: string): Promise { + public async sendNotificationToUser( + userId: string, + shortMessage: string, + longMessage?: string + ): Promise { const requestInit: RequestInit = { headers: new Headers({ // eslint-disable-next-line @typescript-eslint/naming-convention @@ -2697,17 +3408,25 @@ export default class Client { // eslint-disable-next-line @typescript-eslint/naming-convention "Content-Type": "application/x-www-form-urlencoded", // eslint-disable-next-line @typescript-eslint/naming-convention - "OCS-APIRequest": "true", + "OCS-APIRequest": "true" }), - method: "POST", + method: "POST" }; if (!longMessage) { longMessage = ""; } longMessage = `&longMessage=${encodeURIComponent(longMessage)}`; - const queryString = `${encodeURIComponent(userId)}?shortMessage=${encodeURIComponent(shortMessage)}${longMessage}`; - await this.getHttpResponse(this.nextcloudOrigin + `/ocs/v2.php/apps/admin_notifications/api/v1/notifications/${queryString}`, requestInit, [200], { description: "User create" }); + const queryString = `${encodeURIComponent( + userId + )}?shortMessage=${encodeURIComponent(shortMessage)}${longMessage}`; + await this.getHttpResponse( + this.nextcloudOrigin + + `/ocs/v2.php/apps/admin_notifications/api/v1/notifications/${queryString}`, + requestInit, + [200], + { description: "User create" } + ); // const response: Response = await this.getHttpResponse(this.nextcloudOrigin + `/ocs/v2.php/apps/admin_notifications/api/v1/notifications/${queryString}`, requestInit, [200], { description: "User create" }); // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment // const rawResult: any = await response.json(); @@ -2723,10 +3442,17 @@ export default class Client { public async getApps(): Promise { const requestInit: RequestInit = { headers: this.getOcsHeaders(), - method: "GET", + method: "GET" }; - const response: Response = await this.getHttpResponse(this.getOcsUrl(`/apps`), requestInit, [200], { description: "Apps get" }); + const response: Response = await this.getHttpResponse( + this.getOcsUrl(`/apps`), + requestInit, + [200], + { + description: "Apps get" + } + ); // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment const rawResult: any = await response.json(); @@ -2737,7 +3463,10 @@ export default class Client { if (rawResult && rawResult.ocs && rawResult.ocs.data) { apps = rawResult.ocs.data; } else { - throw new ClientError("Fatal Error: nextcloud apps data missing", "ERR_SYSTEM_INFO_MISSING_DATA"); + throw new ClientError( + "Fatal Error: nextcloud apps data missing", + "ERR_SYSTEM_INFO_MISSING_DATA" + ); } const result: string[] = apps; @@ -2748,10 +3477,15 @@ export default class Client { public async getAppInfos(appName: string): Promise { const requestInit: RequestInit = { headers: this.getOcsHeaders(), - method: "GET", + method: "GET" }; - const response: Response = await this.getHttpResponse(this.getOcsUrl(`/apps/${appName}`), requestInit, [200], { description: "App Infos get" }); + const response: Response = await this.getHttpResponse( + this.getOcsUrl(`/apps/${appName}`), + requestInit, + [200], + { description: "App Infos get" } + ); // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment const rawResult: any = await response.json(); @@ -2762,7 +3496,10 @@ export default class Client { if (rawResult && rawResult.ocs && rawResult.ocs.data) { appInfo = rawResult.ocs.data; } else { - throw new ClientError("Fatal Error: nextcloud apps data missing", "ERR_SYSTEM_INFO_MISSING_DATA"); + throw new ClientError( + "Fatal Error: nextcloud apps data missing", + "ERR_SYSTEM_INFO_MISSING_DATA" + ); } // eslint-disable-next-line @typescript-eslint/ban-types @@ -2786,30 +3523,44 @@ export default class Client { * @returns array of properties * @throws GeneralError */ - private async getPropertiesFromWebDAVMultistatusResponse(response: Response, href: string): Promise { - const responseContentType: string | null = response.headers.get("Content-Type"); + private async getPropertiesFromWebDAVMultistatusResponse( + response: Response, + href: string + ): Promise { + const responseContentType: string | null = + response.headers.get("Content-Type"); if (!responseContentType) { - throw new ClientError("Response content type expected", "ERR_RESPONSE_WITHOUT_CONTENT_TYPE_HEADER"); + throw new ClientError( + "Response content type expected", + "ERR_RESPONSE_WITHOUT_CONTENT_TYPE_HEADER" + ); } if (responseContentType.indexOf("application/xml") === -1) { - throw new ClientError("XML response content type expected", "ERR_XML_RESPONSE_CONTENT_TYPE_EXPECTED"); + throw new ClientError( + "XML response content type expected", + "ERR_XML_RESPONSE_CONTENT_TYPE_EXPECTED" + ); } const xmlBody: string = await response.text(); - if (parser.validate(xmlBody) !== true) { - throw new ClientError(`The response is not valid XML: ${xmlBody}`, "ERR_RESPONSE_NOT_INVALID_XML"); + if (XMLValidator.validate(xmlBody) !== true) { + throw new ClientError( + `The response is not valid XML: ${xmlBody}`, + "ERR_RESPONSE_NOT_INVALID_XML" + ); } - const options: any = { - ignoreNameSpace: true, - }; - const body: any = parser.parse(xmlBody, options); + const parser = new XMLParser({ removeNSPrefix: true }); + const body: any = parser.parse(xmlBody); // ensure that we have a multistatus response if (!body.multistatus || !body.multistatus.response) { - throw new ClientError(`The response is is not a WebDAV multistatus response`, "ERR_RESPONSE_NO_MULTISTATUS_XML"); + throw new ClientError( + `The response is is not a WebDAV multistatus response`, + "ERR_RESPONSE_NO_MULTISTATUS_XML" + ); } // ensure that response is always an array @@ -2824,11 +3575,17 @@ export default class Client { const responseProperties: any[] = []; for (const res of body.multistatus.response) { if (!res.href) { - throw new ClientError(`The mulitstatus response must have a href`, "ERR_RESPONSE_MISSING_HREF_MULTISTATUS"); + throw new ClientError( + `The mulitstatus response must have a href`, + "ERR_RESPONSE_MISSING_HREF_MULTISTATUS" + ); } if (!res.propstat) { - throw new ClientError(`The mulitstatus response must have a "propstat" container`, "ERR_RESPONSE_MISSING_PROPSTAT"); + throw new ClientError( + `The mulitstatus response must have a "propstat" container`, + "ERR_RESPONSE_MISSING_PROPSTAT" + ); } let propStats = res.propstat; @@ -2839,11 +3596,17 @@ export default class Client { for (const propStat of propStats) { if (!propStat.status) { - throw new ClientError(`The propstat must have a "status"`, "ERR_RESPONSE_MISSING_PROPSTAT_STATUS"); + throw new ClientError( + `The propstat must have a "status"`, + "ERR_RESPONSE_MISSING_PROPSTAT_STATUS" + ); } if (propStat.status === "HTTP/1.1 200 OK") { if (!propStat.prop) { - throw new ClientError(`The propstat must have a "prop"`, "ERR_RESPONSE_MISSING_PROPSTAT_PROP"); + throw new ClientError( + `The propstat must have a "prop"`, + "ERR_RESPONSE_MISSING_PROPSTAT_PROP" + ); } const property: any = propStat.prop; // eslint-disable-next-line no-underscore-dangle @@ -2885,16 +3648,31 @@ export default class Client { } */ - private async getHttpResponse(url: string, requestInit: RequestInit, expectedHttpStatusCode: number[], context: IRequestContext): Promise { + private async getHttpResponse( + url: string, + requestInit: RequestInit, + expectedHttpStatusCode: number[], + context: IRequestContext + ): Promise { if (!requestInit.headers) { requestInit.headers = new Headers(); } /* istanbul ignore else */ if (this.fakeServer) { - return await this.fakeServer.getFakeHttpResponse(url, requestInit, expectedHttpStatusCode, context); + return await this.fakeServer.getFakeHttpResponse( + url, + requestInit, + expectedHttpStatusCode, + context + ); } else { - return await this.httpClient!.getHttpResponse(url, requestInit, expectedHttpStatusCode, context); + return await this.httpClient!.getHttpResponse( + url, + requestInit, + expectedHttpStatusCode, + context + ); } } @@ -2905,7 +3683,10 @@ export default class Client { * @param folderIndicator true if folders are requested otherwise files * @returns array of folder contents meta data */ - private async contents(folderName: string, folderIndicator: boolean): Promise { + private async contents( + folderName: string, + folderIndicator: boolean + ): Promise { log.debug("Contents: folder ", folderName); const folders: Folder[] = []; folderName = this.sanitizeFolderName(folderName); @@ -2965,12 +3746,18 @@ export default class Client { log.debug("createFolderInternal ", url); const requestInit: RequestInit = { - method: "MKCOL", + method: "MKCOL" }; try { - await this.getHttpResponse(url, requestInit, [201], { description: "Folder create" }); + await this.getHttpResponse(url, requestInit, [201], { + description: "Folder create" + }); } catch (err) { - log.debug(`Error in createFolderInternal ${err.message as string} ${requestInit.method || ""} ${url}`); + log.debug( + `Error in createFolderInternal ${err.message as string} ${ + requestInit.method || "" + } ${url}` + ); throw err; } } @@ -3000,17 +3787,25 @@ export default class Client { `, // headers: new Headers({ Depth: "0" }), headers: new Headers(), - method: "PROPFIND", + method: "PROPFIND" }; let response: Response; try { - response = await this.getHttpResponse(url, requestInit, [207], { description: "File/Folder get details" }); + response = await this.getHttpResponse(url, requestInit, [207], { + description: "File/Folder get details" + }); } catch (err) { - log.debug(`Error in stat ${err.message as string} ${requestInit.method || ""} ${url}`); + log.debug( + `Error in stat ${err.message as string} ${ + requestInit.method || "" + } ${url}` + ); throw err; } - const properties: any[] = await this.getPropertiesFromWebDAVMultistatusResponse(response, ""); + const properties: any[] = + await this.getPropertiesFromWebDAVMultistatusResponse(response, ""); + let resultStat: IStat | null = null; for (const prop of properties) { @@ -3019,7 +3814,83 @@ export default class Client { fileid: prop.fileid, filename: fileName, lastmod: prop.getlastmodified, - type: "file", + type: "file" + }; + + if (prop.getcontentlength) { + resultStat.size = prop.getcontentlength; + } else { + resultStat.type = "directory"; + } + + if (prop.getcontenttype) { + resultStat.mime = prop.getcontenttype; + } + } + + if (!resultStat) { + log.debug("Error: response ", JSON.stringify(properties, null, 4)); + throw new ClientError( + "Error getting status information from : " + url, + "ERR_STAT" + ); + } + return resultStat; + } + + private async statForDirectory(fileName: string): Promise { + const url: string = this.webDAVUrl + fileName; + log.debug("stat ", url); + + const requestInit: RequestInit = { + body: ` + + + + + + + + + + + + + + + + + `, + // headers: new Headers({ Depth: "0" }), + headers: new Headers(), + method: "PROPFIND" + }; + let response: Response; + try { + response = await this.getHttpResponse(url, requestInit, [207], { + description: "File/Folder get details" + }); + } catch (err) { + log.debug( + `Error in stat ${err.message as string} ${ + requestInit.method || "" + } ${url}` + ); + throw err; + } + + const properties: any[] = + await this.getPropertiesFromWebDAVMultistatusResponse(response, ""); + + let resultStat: IStat | null = null; + + for (const prop of [properties[0]]) { + resultStat = { + basename: basename(fileName), + fileid: prop.fileid, + filename: fileName, + lastmod: prop.getlastmodified, + type: "file" }; if (prop.getcontentlength) { @@ -3035,7 +3906,10 @@ export default class Client { if (!resultStat) { log.debug("Error: response ", JSON.stringify(properties, null, 4)); - throw new ClientError("Error getting status information from : " + url, "ERR_STAT"); + throw new ClientError( + "Error getting status information from : " + url, + "ERR_STAT" + ); } return resultStat; } @@ -3050,7 +3924,9 @@ export default class Client { } return { code, message }; } - throw new InvalidServiceResponseFormatError("Fatal Error: The OCS meta status could not be retrieved from OCS response"); + throw new InvalidServiceResponseFormatError( + "Fatal Error: The OCS meta status could not be retrieved from OCS response" + ); } private getOcsHeaders(): Headers { @@ -3060,7 +3936,7 @@ export default class Client { // eslint-disable-next-line @typescript-eslint/naming-convention "Content-Type": "application/json", // eslint-disable-next-line @typescript-eslint/naming-convention - Accept: "application/json", + Accept: "application/json" }); } @@ -3076,13 +3952,16 @@ export default class Client { return `${this.nextcloudOrigin}/ocs/v1.php/cloud${suffix}`; } - private async putFileContents(fileName: string, data: Buffer | NodeJS.ReadableStream): Promise { + private async putFileContents( + fileName: string, + data: Buffer | NodeJS.ReadableStream + ): Promise { const url: string = this.webDAVUrl + fileName; log.debug("putFileContents ", url); const requestInit: RequestInit = { body: data, - method: "PUT", + method: "PUT" }; let description = "File save content "; @@ -3091,6 +3970,8 @@ export default class Client { } else { description += "from stream"; } - return await this.getHttpResponse(url, requestInit, [201, 204], { description }); + return await this.getHttpResponse(url, requestInit, [201, 204], { + description + }); } } diff --git a/src/command/command.ts b/src/command/command.ts index fa5f4fad..b88d3972 100644 --- a/src/command/command.ts +++ b/src/command/command.ts @@ -1,9 +1,6 @@ -// tslint:disable-next-line:no-var-requires const debug = require("debug").debug("Command"); -import Client, { - CommandAlreadyExecutedError, -} from "../client"; +import Client, { CommandAlreadyExecutedError } from "../client"; /** * The potential states that a command can have. @@ -12,31 +9,31 @@ import Client, { * When the execution has finsihed, the status can be "succes" or "failed" */ export enum CommandStatus { - /** - * When a command is created, the state is "initial" - */ - initial = "initial", - /** - * When the execution has started, the status is "running" - */ - running = "running", - /** - * After successful execution of the command, the status is "success" - */ - success = "success", - /** - * After unsuccessfull execution of the command, the status is "failed" - */ - failed = "failed", + /** + * When a command is created, the state is "initial" + */ + initial = "initial", + /** + * When the execution has started, the status is "running" + */ + running = "running", + /** + * After successful execution of the command, the status is "success" + */ + success = "success", + /** + * After unsuccessfull execution of the command, the status is "failed" + */ + failed = "failed" } /** * when the command has finished, the client can get the result of the command execution */ export interface CommandResultMetaData { - errors: string[], - messages: string[], - timeElapsed: number, + errors: string[]; + messages: string[]; + timeElapsed: number; } /** @@ -46,77 +43,83 @@ export interface CommandResultMetaData { * Check the result when finsished. */ export default abstract class Command { - protected client: Client; - protected status: CommandStatus; - protected percentCompleted: number; - protected resultMetaData: CommandResultMetaData; + protected client: Client; + protected status: CommandStatus; + protected percentCompleted: number; + protected resultMetaData: CommandResultMetaData; - constructor(client: Client) { - this.client = client; - this.status = CommandStatus.initial; - this.percentCompleted = 0; - this.resultMetaData = { messages: [], errors: [], timeElapsed: 0 }; - } + constructor(client: Client) { + this.client = client; + this.status = CommandStatus.initial; + this.percentCompleted = 0; + this.resultMetaData = { messages: [], errors: [], timeElapsed: 0 }; + } - /** - * final execute the command - * @async - * @final - * @returns {Promise} - */ - public async execute(): Promise { - debug("execute Command = " + this.constructor.name, this.status); - if (this.isFinished()) { - throw new CommandAlreadyExecutedError("Error: Command has already been executed. Command = " + this.constructor.name); - } - if (this.status === CommandStatus.initial) { - const startTime = new Date(); - await this.onExecute(); - this.resultMetaData.timeElapsed = new Date().getTime() - startTime.getTime(); - } - // do nothing if already running + /** + * final execute the command + * @async + * @final + * @returns {Promise} + */ + public async execute(): Promise { + debug("execute Command = " + this.constructor.name, this.status); + if (this.isFinished()) { + throw new CommandAlreadyExecutedError( + "Error: Command has already been executed. Command = " + + this.constructor.name + ); } - - /** - * execute the command - * @async - * @returns {Promise} - */ - protected abstract async onExecute(): Promise; - - /** - * returns true, if the command has been finished - * @returns {boolean} - */ - public isFinished(): boolean { - if (this.status === CommandStatus.failed || this.status === CommandStatus.success) { - return true; - } - return false; + if (this.status === CommandStatus.initial) { + const startTime = new Date(); + await this.onExecute(); + this.resultMetaData.timeElapsed = + new Date().getTime() - startTime.getTime(); } + // do nothing if already running + } - /** - * returns the status of the command - * @returns {CommandStatus} - */ - public getStatus(): CommandStatus { - return this.status; - } + /** + * execute the command + * @async + * @returns {Promise} + */ + protected abstract onExecute(): Promise; - /** - * returns the completion percentage of the command - * @returns {number} percentage of completion - */ - public getPercentCompleted(): number { - return this.percentCompleted; + /** + * returns true, if the command has been finished + * @returns {boolean} + */ + public isFinished(): boolean { + if ( + this.status === CommandStatus.failed || + this.status === CommandStatus.success + ) { + return true; } + return false; + } - /** - * returns the result meta data of the command - * @returns {null|any} the result of the command - */ - public getResultMetaData(): CommandResultMetaData { - return this.resultMetaData; - } + /** + * returns the status of the command + * @returns {CommandStatus} + */ + public getStatus(): CommandStatus { + return this.status; + } + + /** + * returns the completion percentage of the command + * @returns {number} percentage of completion + */ + public getPercentCompleted(): number { + return this.percentCompleted; + } + /** + * returns the result meta data of the command + * @returns {null|any} the result of the command + */ + public getResultMetaData(): CommandResultMetaData { + return this.resultMetaData; + } } diff --git a/src/environment.ts b/src/environment.ts index dc856708..804e1673 100644 --- a/src/environment.ts +++ b/src/environment.ts @@ -1,42 +1,52 @@ import ClientError from "./error"; export default class Environment { + public static getMinLogLevel(): string { + return process.env.MIN_LOG_LEVEL || "error"; + // return "debug"; + } - public static getMinLogLevel(): string { - return process.env.MIN_LOG_LEVEL || "error"; + public static getNextcloudUrl(): string { + if (!process.env.NEXTCLOUD_URL) { + throw new ClientError( + "NCEnvironment: NEXTCLOUD_URL not defined in environment", + "ERR_NEXTCLOUD_URL_NOT_DEFINED", + ); } + return process.env.NEXTCLOUD_URL; + } - public static getNextcloudUrl(): string { - if (!process.env.NEXTCLOUD_URL) { - throw new ClientError("NCEnvironment: NEXTCLOUD_URL not defined in environment" - , "ERR_NEXTCLOUD_URL_NOT_DEFINED"); - } - return process.env.NEXTCLOUD_URL; + public static getUserName(): string { + if (!process.env.NEXTCLOUD_USERNAME) { + throw new ClientError( + "NCEnvironment: NEXTCLOUD_USERNAME not defined in environment", + "ERR_NEXTCLOUD_USERNAME_NOT_DEFINED", + ); } + return process.env.NEXTCLOUD_USERNAME; + } - public static getUserName(): string { - if (!process.env.NEXTCLOUD_USERNAME) { - throw new ClientError("NCEnvironment: NEXTCLOUD_USERNAME not defined in environment" - , "ERR_NEXTCLOUD_USERNAME_NOT_DEFINED"); - } - return process.env.NEXTCLOUD_USERNAME; + public static getPassword(): string { + if (!process.env.NEXTCLOUD_PASSWORD) { + throw new ClientError( + "NCEnvironment: NEXTCLOUD_PASSWORD not defined in environment", + "ERR_NEXTCLOUD_PASSWORD_NOT_DEFINED", + ); } + return process.env.NEXTCLOUD_PASSWORD; + } - public static getPassword(): string { - if (!process.env.NEXTCLOUD_PASSWORD) { - throw new ClientError("NCEnvironment: NEXTCLOUD_PASSWORD not defined in environment" - , "ERR_NEXTCLOUD_PASSWORD_NOT_DEFINED"); - } - return process.env.NEXTCLOUD_PASSWORD; - } - - public static getRecordingActiveIndicator(): boolean { - if ((process.env.TEST_RECORDING_ACTIVE && - (process.env.TEST_RECORDING_ACTIVE === "0" || process.env.TEST_RECORDING_ACTIVE === "false" || process.env.TEST_RECORDING_ACTIVE === "inactive")) || - !process.env.TEST_RECORDING_ACTIVE) { - return false; - } else { - return true; - } + public static getRecordingActiveIndicator(): boolean { + if ( + (process.env.TEST_RECORDING_ACTIVE && + (process.env.TEST_RECORDING_ACTIVE === "0" || + process.env.TEST_RECORDING_ACTIVE === "false" || + process.env.TEST_RECORDING_ACTIVE === "inactive")) || + !process.env.TEST_RECORDING_ACTIVE + ) { + return false; + } else { + return true; } + } } diff --git a/src/examples/basic.ts b/src/examples/basic.ts index aade381f..9daf88b3 100644 --- a/src/examples/basic.ts +++ b/src/examples/basic.ts @@ -1,30 +1,37 @@ -// typescript -import Client, { File, Folder, Share } from "./../client"; +import { ShareType } from "../share"; +import Client, { File, Folder, Share, SharePermission } from "./../client"; (async () => { - try { - // create a new client using connectivity information from environment - const client = new Client(); - // create a folder structure if not available - const folder: Folder = await client.createFolder("folder/subfolder"); - // create file within the folder - const file: File = await folder.createFile("myFile.txt", Buffer.from("My file content")); - // add a tag to the file and create the tag if not existing - await file.addTag("MyTag"); - // add a comment to the file - await file.addComment("myComment"); - // get the file content - const content: Buffer = await file.getContent(); - // share the file publicly with password and note - const share: Share = await client.createShare({ fileSystemElement: file }); - await share.setPassword("some password"); - await share.setNote("some note\nnew line"); - // use the url to access the share - const shareLink: string = share.url; - // delete the folder including the file and share - await folder.delete(); - } catch (e) { - // some error handling - console.log(e); - } -})(); \ No newline at end of file + try { + // create a new client using connectivity information from environment + const client = new Client(); + // create a folder structure if not available + const folder: Folder = await client.createFolder("folder/subfolder"); + // create file within the folder + const file: File = await folder.createFile( + "myFile.txt", + Buffer.from("My file content") + ); + // add a tag to the file and create the tag if not existing + await file.addTag("MyTag"); + // add a comment to the file + await file.addComment("myComment"); + // get the file content + const content: Buffer = await file.getContent(); + // share the file publicly with password and note + const share: Share = await client.createShare({ + fileSystemElement: file, + permissions: SharePermission.all, + shareType: ShareType.publicLink + }); + await share.setPassword("some password"); + await share.setNote("some note\nnew line"); + // use the url to access the share + const shareLink: string | null = share.url; + // delete the folder including the file and share + await folder.delete(); + } catch (e) { + // some error handling + console.log(e); + } +})(); diff --git a/src/fileSystemElement.ts b/src/fileSystemElement.ts index 5205115c..5899ed6f 100644 --- a/src/fileSystemElement.ts +++ b/src/fileSystemElement.ts @@ -5,86 +5,85 @@ import Client, { ClientError } from "./client"; * It exposes file properties and content handling, commenting and tagging */ export default abstract class FileSystemElement { + /** + * The name of the file system element including the path + * The name is readonly + */ + abstract get name(): string; - /** - * The name of the file system element including the path - * The name is readonly - */ - abstract get name(): string; + /** + * The base name of the file system element (name without path) + * The base name is readonly + */ + abstract get baseName(): string; - /** - * The base name of the file system element (name without path) - * The base name is readonly - */ - abstract get baseName(): string; + /** + * The timestamp of the last file system element change + * readonly + */ + abstract get lastmod(): Date; - /** - * The timestamp of the last file system element change - * readonly - */ - abstract get lastmod(): Date; + /** + * The unique id of the file system element. + */ + abstract get id(): number; - /** - * The unique id of the file system element. - */ - abstract get id(): number; + /** + * deletes a file system element + * @throws Error + */ + public abstract delete(): Promise; - /** - * deletes a file system element - * @throws Error - */ - public abstract async delete(): Promise; + /** + * moves or renames the current file system element to the new location + * target folder must exists + * @param targetFileName the name of the target file /f1/f2/myfile.txt + * @throws Error + */ + public abstract move(targetName: string): Promise; - /** - * moves or renames the current file system element to the new location - * target folder must exists - * @param targetFileName the name of the target file /f1/f2/myfile.txt - * @throws Error - */ - public abstract async move(targetName: string): Promise; + /** + * @returns the url of the file sytsem element + * @throws Error + */ + public abstract getUrl(): string; - /** - * @returns the url of the file sytsem element - * @throws Error - */ - public abstract getUrl(): string; + /** + * @returns the url of the file system element in the UI + * @throws Error + */ + public abstract getUIUrl(): string; - /** - * @returns the url of the file system element in the UI - * @throws Error - */ - public abstract getUIUrl(): string; + /** + * adds a tag name to the file system element + * @param tagName name of the tag + */ + public abstract addTag(tagName: string): Promise; - /** - * adds a tag name to the file system element - * @param tagName name of the tag - */ - public abstract async addTag(tagName: string): Promise; + /** + * get tag names + * @returns array of tag names + */ + public abstract getTags(): Promise; - /** - * get tag names - * @returns array of tag names - */ - public abstract async getTags(): Promise; + /** + * removes a tag of the file system element + * @param tagName the name of the tag + */ + public abstract removeTag(tagName: string): Promise; - /** - * removes a tag of the file system element - * @param tagName the name of the tag - */ - public abstract async removeTag(tagName: string): Promise; + /** + * add comment to file + * @param comment the comment + */ + public abstract addComment(comment: string): Promise; - /** - * add comment to file - * @param comment the comment - */ - public abstract async addComment(comment: string): Promise; - - /** - * get list of comments of file - * @param top number of comments to return - * @param skip the offset - * @returns array of comment strings - * @throws Exception - */ - public abstract async getComments(top?: number, skip?: number): Promise; + /** + * get list of comments of file + * @param top number of comments to return + * @param skip the offset + * @returns array of comment strings + * @throws Exception + */ + public abstract getComments(top?: number, skip?: number): Promise; } diff --git a/src/httpClient.ts b/src/httpClient.ts index 688ea91d..81e111cd 100644 --- a/src/httpClient.ts +++ b/src/httpClient.ts @@ -1,152 +1,182 @@ -// tslint:disable-next-line:no-var-requires -const HttpProxyAgent = require('http-proxy-agent'); - +import httpProxyAgent from "http-proxy-agent"; import { HttpProxyAgentOptions } from "http-proxy-agent"; import fetch from "node-fetch"; -import { - Headers, - RequestInit, - Response, -} from "node-fetch"; +import { Headers, RequestInit, Response } from "node-fetch"; import ClientError from "./error"; import RequestResponseLog from "./requestResponseLog"; -import RequestResponseLogEntry, { RequestLogEntry, ResponseLogEntry } from "./requestResponseLogEntry"; +import RequestResponseLogEntry, { + RequestLogEntry, + ResponseLogEntry +} from "./requestResponseLogEntry"; import Logger from "./logger"; const log: Logger = new Logger(); export interface IRequestContext { - "description"?: string; + description?: string; } export interface IProxy { - "host": string; - "port": string; - "protocol": string; - "secureProxy": boolean; - "proxyAuthorizationHeader"?: string; + host: string; + port: string; + protocol: string; + secureProxy: boolean; + proxyAuthorizationHeader?: string; } export interface IHttpClientOptions { - "authorizationHeader"?: string; - "logRequestResponse"?: boolean; - "proxy"?: IProxy; - "origin"?: string; + authorizationHeader?: string; + logRequestResponse?: boolean; + proxy?: IProxy; + origin?: string; } export class HttpClient { - private proxy?: IProxy; - private authorizationHeader?: string; - private logRequestResponse: boolean; - private origin: string; - - public constructor(options: IHttpClientOptions) { - log.debug("constructor"); - this.authorizationHeader = options.authorizationHeader; - this.proxy = options.proxy; - this.logRequestResponse = options.logRequestResponse || false; - this.origin = options.origin || ""; + private proxy?: IProxy; + private authorizationHeader?: string; + private logRequestResponse: boolean; + private origin: string; + + public constructor(options: IHttpClientOptions) { + log.debug("constructor"); + this.authorizationHeader = options.authorizationHeader; + this.proxy = options.proxy; + this.logRequestResponse = options.logRequestResponse || false; + this.origin = options.origin || ""; + } + public async getHttpResponse( + url: string, + requestInit: RequestInit, + expectedHttpStatusCode: number[], + context: IRequestContext + ): Promise { + if (!requestInit.headers) { + requestInit.headers = new Headers(); } - public async getHttpResponse(url: string, requestInit: RequestInit, expectedHttpStatusCode: number[], context: IRequestContext): Promise { - - if (!requestInit.headers) { - requestInit.headers = new Headers(); - } - - if (!requestInit.method) { - requestInit.method = "UNDEFINED"; - } - - if (!context.description) { - context.description = ""; - } - - if (this.authorizationHeader) { - (requestInit.headers as Headers).append("Authorization", this.authorizationHeader); - } - (requestInit.headers as Headers).append("User-Agent", "nextcloud-node-client"); - - // set the proxy - if (this.proxy) { - log.debug("proxy agent used"); - const options: HttpProxyAgentOptions = { - host: this.proxy.host, - port: this.proxy.port, - protocol: this.proxy.protocol, - }; - - requestInit.agent = new HttpProxyAgent(options); - - if (this.proxy.proxyAuthorizationHeader) { - (requestInit.headers as Headers).append("Proxy-Authorization", this.proxy.proxyAuthorizationHeader); - } - } - - log.debug("getHttpResponse request header:", requestInit.headers); - log.debug("getHttpResponse url", url, requestInit); - - const response: Response = await fetch(url, requestInit); - - if (this.logRequestResponse) { - const responseText = await response.text(); - // overwrite response functions as the body uses a stearm object... - response.text = async () => { - return responseText; - }; - - response.body.pipe = (destination: NodeJS.WritableStream, options?: { end?: boolean; }): any => { - destination.write(responseText); - }; - - response.json = async () => { - return JSON.parse(responseText); - }; - - response.buffer = async () => { - return Buffer.from(responseText); - }; - - let body: string = ``; - if (requestInit.body && requestInit.body instanceof Buffer) { - body = ``; - } - - if (typeof requestInit.body === "string") { - body = requestInit.body; - } + if (!requestInit.method) { + requestInit.method = "UNDEFINED"; + } - const reqLogEntry: RequestLogEntry = - new RequestLogEntry(url.replace(this.origin, ""), - requestInit.method, context.description, - body); + if (!context.description) { + context.description = ""; + } - const resLogEntry: ResponseLogEntry = - new ResponseLogEntry(response.status, - await response.text(), - response.headers.get("Content-Type") as string, - response.headers.get("Content-Location") || ""); + if (this.authorizationHeader) { + (requestInit.headers as Headers).append( + "Authorization", + this.authorizationHeader + ); + } + (requestInit.headers as Headers).append( + "User-Agent", + "nextcloud-node-client" + ); + + // set the proxy + if (this.proxy) { + log.debug("proxy agent used"); + const options: HttpProxyAgentOptions = { + host: this.proxy.host, + port: this.proxy.port, + protocol: this.proxy.protocol + }; + + requestInit.agent = httpProxyAgent(options); + + if (this.proxy.proxyAuthorizationHeader) { + (requestInit.headers as Headers).append( + "Proxy-Authorization", + this.proxy.proxyAuthorizationHeader + ); + } + } - const rrLog: RequestResponseLog = RequestResponseLog.getInstance(); - await rrLog.addEntry(new RequestResponseLogEntry(reqLogEntry, resLogEntry)); - } + log.debug("getHttpResponse request header:", requestInit.headers); + log.debug("getHttpResponse url", url, requestInit); + + const response: Response = await fetch(url, requestInit); + + if (this.logRequestResponse) { + const responseText = await response.text(); + + // overwrite response functions as the body uses a stearm object... + response.text = () => { + return Promise.resolve(responseText); + }; + + if (response.body) { + response.body.pipe = ( + destination: NodeJS.WritableStream, + options?: { end?: boolean } + ): any => { + destination.write(responseText); + }; + } + + response.json = () => { + return Promise.resolve(JSON.parse(responseText)); + }; + + response.arrayBuffer = () => { + return Promise.resolve(Buffer.from(responseText)); + }; + + let body = ``; + if (requestInit.body && requestInit.body instanceof Buffer) { + body = ``; + } + + if (typeof requestInit.body === "string") { + body = requestInit.body; + } + + const reqLogEntry: RequestLogEntry = new RequestLogEntry( + url.replace(this.origin, ""), + requestInit.method, + context.description, + body + ); + + const resLogEntry: ResponseLogEntry = new ResponseLogEntry( + response.status, + await response.text(), + response.headers.get("Content-Type") as string, + response.headers.get("Content-Location") || "" + ); + + const rrLog: RequestResponseLog = RequestResponseLog.getInstance(); + await rrLog.addEntry( + new RequestResponseLogEntry(reqLogEntry, resLogEntry) + ); + } - const responseContentType: string | null = response.headers.get("content-type"); - - if (expectedHttpStatusCode.indexOf(response.status) === -1) { - log.debug("getHttpResponse unexpected status response "+ response.status + " " + response.statusText); - log.debug("getHttpResponse description "+ context.description); - log.debug("getHttpResponse expected "+ expectedHttpStatusCode.join(",")); - log.debug("getHttpResponse headers ", JSON.stringify(response.headers, null, 4)); - log.debug("getHttpResponse request body ", requestInit.body); - log.debug("getHttpResponse text:", await response.text()); - throw new ClientError(`HTTP response status ${response.status} not expected. Expected status: ${expectedHttpStatusCode.join(",")} - status text: ${response.statusText}`, - "ERR_UNEXPECTED_HTTP_STATUS", - { - expectedHttpStatusCodes: expectedHttpStatusCode, - responseStatus: response.status, - responseStatusText: response.statusText, - }); + // const responseContentType: string | null = response.headers.get("content-type"); + + if (expectedHttpStatusCode.indexOf(response.status) === -1) { + log.debug( + `getHttpResponse unexpected status response ${response.status} ${response.statusText}` + ); + log.debug("getHttpResponse description " + context.description); + log.debug("getHttpResponse expected " + expectedHttpStatusCode.join(",")); + log.debug( + "getHttpResponse headers ", + JSON.stringify(response.headers, null, 4) + ); + log.debug("getHttpResponse request body ", requestInit.body); + log.debug("getHttpResponse text:", await response.text()); + throw new ClientError( + `HTTP response status ${ + response.status + } not expected. Expected status: ${expectedHttpStatusCode.join( + "," + )} - status text: ${response.statusText}`, + "ERR_UNEXPECTED_HTTP_STATUS", + { + expectedHttpStatusCodes: expectedHttpStatusCode, + responseStatus: response.status, + responseStatusText: response.statusText } - return response; + ); } - + return response; + } } diff --git a/src/logger.ts b/src/logger.ts index e5ba3bbd..708dee0e 100644 --- a/src/logger.ts +++ b/src/logger.ts @@ -1,113 +1,109 @@ import Environment from "./environment"; -import { - Logger as TSLogLogger, - ILogObject as LogObject, - TLogLevelName -} from "tslog"; +import { Logger as TSLogLogger, ILogObject as LogObject, TLogLevelName } from "tslog"; export default class Logger { - private logger: TSLogLogger; + private logger: TSLogLogger; - public constructor() { - let minLevel: TLogLevelName; - - switch (Environment.getMinLogLevel()) { - case "silly": - minLevel = "silly" - break; - case "trace": - minLevel = "trace" - break; - case "debug": - minLevel = "debug" - break; - case "info": - minLevel = "info" - break; - case "warn": - minLevel = "warn" - break; - case "error": - minLevel = "error" - break; - case "fatal": - minLevel = "fatal" - break; - default: - minLevel = "error"; - } + public constructor() { + let minLevel: TLogLevelName; + switch (Environment.getMinLogLevel()) { + case "silly": + minLevel = "silly"; + break; + case "trace": + minLevel = "trace"; + break; + case "debug": + minLevel = "debug"; + break; + case "info": + minLevel = "info"; + break; + case "warn": + minLevel = "warn"; + break; + case "error": + minLevel = "error"; + break; + case "fatal": + minLevel = "fatal"; + break; + default: minLevel = "error"; - this.logger = new TSLogLogger({ minLevel }); - // overload is required to get the real position for logging - this.silly = this.logger.silly.bind(this.logger); - this.trace = this.logger.trace.bind(this.logger); - this.debug = this.logger.debug.bind(this.logger); - this.info = this.logger.info.bind(this.logger); - this.warn = this.logger.warn.bind(this.logger); - this.error = this.logger.error.bind(this.logger); - this.fatal = this.logger.fatal.bind(this.logger); } - /** - * Logs a silly message. - * @param args - Multiple log attributes that should be logged out. - */ - public silly(...args: unknown[]): LogObject { - /* istanbul ignore next */ - return this.logger.silly(...args); - } + // minLevel = "error"; + this.logger = new TSLogLogger({ minLevel }); + // overload is required to get the real position for logging + this.silly = this.logger.silly.bind(this.logger); + this.trace = this.logger.trace.bind(this.logger); + this.debug = this.logger.debug.bind(this.logger); + this.info = this.logger.info.bind(this.logger); + this.warn = this.logger.warn.bind(this.logger); + this.error = this.logger.error.bind(this.logger); + this.fatal = this.logger.fatal.bind(this.logger); + } - /** - * Logs a trace message. - * @param args - Multiple log attributes that should be logged out. - */ - public trace(...args: unknown[]): LogObject { - /* istanbul ignore next */ - return this.logger.trace(...args); - } + /** + * Logs a silly message. + * @param args - Multiple log attributes that should be logged out. + */ + public silly(...args: unknown[]): LogObject { + /* istanbul ignore next */ + return this.logger.silly(...args); + } - /** - * Logs a debug message. - * @param args - Multiple log attributes that should be logged out. - */ - public debug(...args: unknown[]): LogObject { - return this.logger.debug(...args); - } + /** + * Logs a trace message. + * @param args - Multiple log attributes that should be logged out. + */ + public trace(...args: unknown[]): LogObject { + /* istanbul ignore next */ + return this.logger.trace(...args); + } - /** - * Logs a info message. - * @param args - Multiple log attributes that should be logged out. - */ - public info(...args: unknown[]): LogObject { - /* istanbul ignore next */ - return this.logger.info(...args); - } + /** + * Logs a debug message. + * @param args - Multiple log attributes that should be logged out. + */ + public debug(...args: unknown[]): LogObject { + return this.logger.debug(...args); + } - /** - * Logs a warn message. - * @param args - Multiple log attributes that should be logged out. - */ - public warn(...args: unknown[]): LogObject { - /* istanbul ignore next */ - return this.logger.warn(...args); - } + /** + * Logs a info message. + * @param args - Multiple log attributes that should be logged out. + */ + public info(...args: unknown[]): LogObject { + /* istanbul ignore next */ + return this.logger.info(...args); + } - /** - * Logs a error message. - * @param args - Multiple log attributes that should be logged out. - */ - public error(...args: unknown[]): LogObject { - /* istanbul ignore next */ - return this.logger.error(...args); - } + /** + * Logs a warn message. + * @param args - Multiple log attributes that should be logged out. + */ + public warn(...args: unknown[]): LogObject { + /* istanbul ignore next */ + return this.logger.warn(...args); + } - /** - * Logs a fatal message. - * @param args - Multiple log attributes that should be logged out. - */ - public fatal(...args: unknown[]): LogObject { - /* istanbul ignore next */ - return this.logger.fatal(...args); - } + /** + * Logs a error message. + * @param args - Multiple log attributes that should be logged out. + */ + public error(...args: unknown[]): LogObject { + /* istanbul ignore next */ + return this.logger.error(...args); + } + + /** + * Logs a fatal message. + * @param args - Multiple log attributes that should be logged out. + */ + public fatal(...args: unknown[]): LogObject { + /* istanbul ignore next */ + return this.logger.fatal(...args); + } } diff --git a/src/requestResponseLog.ts b/src/requestResponseLog.ts index f3d69a08..30585fdd 100644 --- a/src/requestResponseLog.ts +++ b/src/requestResponseLog.ts @@ -1,5 +1,4 @@ - -import parser from "fast-xml-parser"; +import { XMLParser, XMLValidator } from "fast-xml-parser"; import { promises as fsPromises } from "fs"; import path from "path"; import requestResponseLogEntry from "./requestResponseLogEntry"; @@ -7,106 +6,115 @@ import Logger from "./logger"; const log: Logger = new Logger(); export default class RequestResponseLog { - public static readonly defaultLogDirectory: string = "RequestResponseLog/"; - - public static deleteInstance(): void { - RequestResponseLog.log = null; + public static readonly defaultLogDirectory: string = "RequestResponseLog/"; + + public static deleteInstance(): void { + RequestResponseLog.log = null; + } + public static getInstance(): RequestResponseLog { + if (!RequestResponseLog.log) { + RequestResponseLog.log = new RequestResponseLog(); } - public static getInstance(): RequestResponseLog { - if (!RequestResponseLog.log) { - RequestResponseLog.log = new RequestResponseLog(); - } - return RequestResponseLog.log; + return RequestResponseLog.log; + } + private static log: RequestResponseLog | null = null; + + public baseDirectory: string = RequestResponseLog.defaultLogDirectory; + private context: string; + private entries: requestResponseLogEntry[] = []; + private constructor() { + this.baseDirectory = RequestResponseLog.defaultLogDirectory; + this.context = ""; + } + + public async addEntry(logEntry: requestResponseLogEntry) { + log.debug("addEntry"); + if (!this.context) { + log.debug("Error while recording, context not set"); + throw new Error("Error while recording, context not set"); } - private static log: RequestResponseLog | null = null; - public baseDirectory: string = RequestResponseLog.defaultLogDirectory; - private context: string; - private entries: requestResponseLogEntry[] = []; - private constructor() { - this.baseDirectory = RequestResponseLog.defaultLogDirectory; - this.context = ""; + if (logEntry.response.body && logEntry.response.contentType) { + if (logEntry.response.contentType.indexOf("application/xml") !== -1) { + logEntry.response.jsonBody = this.xmlToJson(logEntry.response.body); + } + if (logEntry.response.contentType.indexOf("application/json") !== -1) { + logEntry.response.jsonBody = JSON.parse(logEntry.response.body); + } } - public async addEntry(logEntry: requestResponseLogEntry) { - log.debug("addEntry"); - if (!this.context) { - log.debug("Error while recording, context not set"); - throw new Error("Error while recording, context not set"); - } - - if (logEntry.response.body && logEntry.response.contentType) { - if (logEntry.response.contentType.indexOf("application/xml") !== -1) { - logEntry.response.jsonBody = this.xmlToJson(logEntry.response.body); - } - if (logEntry.response.contentType.indexOf("application/json") !== -1) { - logEntry.response.jsonBody = JSON.parse(logEntry.response.body); - } - } - - if (logEntry.request.body) { - if (logEntry.request.body.indexOf && logEntry.request.body.indexOf(" { - log.debug("getEntries"); - if (!this.context) { - log.debug("Error while getting recording request, context not set"); - throw new Error("Error while getting recording request, context not set"); - } - - const entries: string = await fsPromises.readFile(this.getFileName(), { encoding: "utf8" }); - return JSON.parse(entries); + this.entries.push(logEntry); + await fsPromises.writeFile( + this.getFileName(), + JSON.stringify(this.entries, null, 4) + ); + } + + public async getEntries(): Promise { + log.debug("getEntries"); + if (!this.context) { + log.debug("Error while getting recording request, context not set"); + throw new Error("Error while getting recording request, context not set"); } - public async setContext(context: string) { - log.debug("setContext"); - const newContext: string = context.replace(/ |:|\./g, "_"); - // if (this.context !== newContext) { - this.context = newContext; - this.entries = []; - // } - // create the directory - await this.assertDirectory(this.getFileName()); + const entries: string = await fsPromises.readFile(this.getFileName(), { + encoding: "utf8" + }); + return JSON.parse(entries); + } + + public async setContext(context: string) { + log.debug("setContext"); + const newContext: string = context.replace(/ |:|\./g, "_"); + // if (this.context !== newContext) { + this.context = newContext; + this.entries = []; + // } + // create the directory + await this.assertDirectory(this.getFileName()); + } + + public getFileName(): string { + return `${this.baseDirectory}${this.context}.json`; + } + + private xmlToJson(xml: string): any { + if (XMLValidator.validate(xml) === true) { + const parser = new XMLParser({ removeNSPrefix: true }); + return parser.parse(xml); } - - public getFileName(): string { - return `${this.baseDirectory}${this.context}.json`; - } - - private xmlToJson(xml: string): any { - if (parser.validate(xml) === true) { - return parser.parse(xml, { ignoreNameSpace: true }); - } - return { info: "invalid xml" }; - } - - private async assertDirectory(filename: string): Promise { - const directory = path.dirname(filename); - const pathArray: string[] = directory.split("/"); - let p: string = ""; - - for (const dir of pathArray) { - if (p === "") { - p = dir; - } else { - p = p + "/" + dir; - } - - try { - await fsPromises.mkdir(p); - /* istanbul ignore next */ - log.debug(`directory "${p}" created`); - } catch (e) { - /* istanbul ignore next */ - log.debug(`directory "${p}" already exists`); - } - } + return { info: "invalid xml" }; + } + + private async assertDirectory(filename: string): Promise { + const directory = path.dirname(filename); + const pathArray: string[] = directory.split("/"); + let p: string = ""; + + for (const dir of pathArray) { + if (p === "") { + p = dir; + } else { + p = p + "/" + dir; + } + + try { + await fsPromises.mkdir(p); + /* istanbul ignore next */ + log.debug(`directory "${p}" created`); + } catch (e) { + /* istanbul ignore next */ + log.debug(`directory "${p}" already exists`); + } } + } } diff --git a/src/share.ts b/src/share.ts index 7c41b396..0ed94c62 100644 --- a/src/share.ts +++ b/src/share.ts @@ -1,225 +1,323 @@ import Client, { ClientError } from "./client"; -import File from "./file"; import FileSystemElement from "./fileSystemElement"; -import Folder from "./folder"; +import UserGroup from "./userGroup"; +import User from "./user"; +import FormData from "form-data"; +import { format } from "path"; export enum SharePermission { - all = 31, - read = 1, - update = 2, - create = 4, - delete = 8, - share = 16, + all = 31, + read = 1, + update = 2, + create = 4, + delete = 8, + share = 16, } -enum ShareType { - user = 0, - group = 1, - publicLink = 3, - email = 4, +export enum ShareType { + user = 0, + group = 1, + publicLink = 3, + email = 4, } export interface ICreateShare { - "fileSystemElement": FileSystemElement; - // @todo "shareWith"?: User | UserGroup | EMail; - "publicUpload"?: boolean; - "password"?: string; + fileSystemElement: FileSystemElement; + publicUpload?: boolean; + password?: string; + shareType: ShareType; + shareWith?: User | UserGroup; + permissions: SharePermission; } export enum ShareItemType { - file = "file", - folder = "folder", + file = "file", + folder = "folder", } export default class Share { - - public static async getShare(client: Client, id: string): Promise { - const share: Share = new Share(client, id); - await share.initialize(); - return share; - } - - public static createShareRequestBody(createShare: ICreateShare): string { - const shareType: ShareType = ShareType.publicLink; - - const shareRequest: { - path: string, - shareType: number, - // @todo permissions: number | number[] - password?: string, - } = { - path: createShare.fileSystemElement.name, - // @todo permissions: 1, - shareType, - }; - - if (createShare.password) { - shareRequest.password = createShare.password; - } - - return JSON.stringify(shareRequest, null, 4); + public static async getShare( + client: Client, + shareType: ShareType, + permissions: SharePermission, + id: string, + user?: User | null, + ): Promise { + const share: Share = new Share(client, shareType, permissions, id, user ?? null); + await share.initialize(); + return share; + } + + public static createShareRequestBody(createShare: ICreateShare): any { + // for backwards compatibility, default sharetype is public link + const shareType: ShareType = createShare.shareType == null ? ShareType.publicLink : createShare.shareType; + if (shareType === ShareType.user || shareType === ShareType.group) { + if (createShare.shareWith == null) { + throw new ClientError( + "Error, when using ShareType user or usergroup, you need to specify shareWith", + "ERR_SHARETYPE_USER_GROUP_WITHOUT_SHAREWITH", + ); + } } - private client: Client; - private memento: { - expiration: Date | null, - id: string; - itemType: ShareItemType, - note: string, - token: string, - url: string, - publicUpload: boolean, - // share_type: number, - // "uid_owner": string, - // "displayname_owner": string, - // "permissions": SharePermission, - // "can_edit": boolean, - // "can_delete": boolean, - // "stime": Date, - // "parent"?: Share, - // "uid_file_owner": string, - // "label"?: string, - // "displayname_file_owner": string, - // "path": string, - // "mimetype"?: string, - // "share_with"?: string, - // "share_with_displayname"?: string, - // "mail_send": boolean, - // "hide_download": boolean, + const shareRequest: { + path: string; + shareType: number; + shareWith?: string; + // @todo permissions: number | number[] + permissions: number; + password?: string; + } = { + path: createShare.fileSystemElement.name, + // @todo permissions: 1, + shareType, + permissions: createShare.permissions, }; - private constructor(client: Client, id: string) { - this.client = client; - this.memento = { - expiration: null, - id, - itemType: ShareItemType.file, - note: "", - token: "", - url: "", - publicUpload: false, - }; - } - - public async delete(): Promise { - await this.client.deleteShare(this.memento.id); + if (createShare.shareWith) { + shareRequest.shareWith = createShare.shareWith.id; } - public async setExpiration(expiration: Date): Promise { - this.memento.expiration = expiration; - await this.client.updateShare(this.memento.id, { expireDate: expiration.toISOString().split("T")[0] }); + if (createShare.password) { + shareRequest.password = createShare.password; } - /** - * set a new password - * @param password - */ - public async setPassword(password: string): Promise { - await this.client.updateShare(this.memento.id, { password }); - } + const theFormData = new FormData(); - public async setPublicUpload(): Promise { - if (this.memento.itemType === ShareItemType.folder) { - this.memento.publicUpload = true; - await this.client.updateShare(this.memento.id, { permissions: 15 }); - } + for (const key of Object.keys(shareRequest)) { + theFormData.append(key, shareRequest[key as keyof typeof shareRequest] as string); } - public async setNote(note: string): Promise { - this.memento.note = note; - await this.client.updateShare(this.memento.id, { note }); + return theFormData; + + // return JSON.stringify(shareRequest, null, 4); + } + + private client: Client; + private memento: { + expiration: Date | null; + id: string; + itemType: ShareItemType; + note: string; + token: string | null; + url: string | null; + publicUpload: boolean; + shareType: number; + // "uid_owner": string, + // "displayname_owner": string, + permissions: SharePermission; + // "can_edit": boolean, + // "can_delete": boolean, + // "stime": Date, + // "parent"?: Share, + // "uid_file_owner": string, + // "label"?: string, + // "displayname_file_owner": string, + // "path": string, + // "mimetype"?: string, + shareWith: User | UserGroup | null; + // "share_with_displayname"?: string, + // "mail_send": boolean, + // "hide_download": boolean, + }; + + private constructor( + client: Client, + shareType: ShareType, + permissions: SharePermission, + id: string, + user: User | null, + ) { + this.client = client; + this.memento = { + expiration: null, + id, + itemType: ShareItemType.file, + note: "", + token: null, + url: null, + publicUpload: false, + shareType: shareType, + shareWith: user, + permissions, + }; + } + + public async delete(): Promise { + await this.client.deleteShare(this.memento.id); + } + + public async setExpiration(expiration: Date): Promise { + this.memento.expiration = expiration; + await this.client.updateShare(this.memento.id, { expireDate: expiration.toISOString().split("T")[0] }); + } + + /** + * set a new password + * + * @param password + */ + public async setPassword(password: string): Promise { + await this.client.updateShare(this.memento.id, { password }); + } + + public async setPublicUpload(): Promise { + if (this.memento.itemType === ShareItemType.folder) { + this.memento.publicUpload = true; + await this.client.updateShare(this.memento.id, { permissions: 15 }); } + } - private async initialize(): Promise { - const rawShareData = await this.client.getShare(this.memento.id); - - if (!rawShareData.ocs || !rawShareData.ocs.data[0]) { - throw new ClientError(`Error invalid share data received "ocs.data" missing`, "ERR_INVALID_SHARE_RESPONSE"); - } - - if (!rawShareData.ocs.data[0].url) { - throw new ClientError(`Error invalid share data received "url" missing`, "ERR_INVALID_SHARE_RESPONSE"); - } - this.memento.url = rawShareData.ocs.data[0].url; - - if (!rawShareData.ocs.data[0].token) { - throw new ClientError(`Error invalid share data received "token" missing`, "ERR_INVALID_SHARE_RESPONSE"); - } - this.memento.token = rawShareData.ocs.data[0].token; - - if (!rawShareData.ocs.data[0].item_type) { - throw new ClientError(`Error invalid share data received "item_type" missing`, "ERR_INVALID_SHARE_RESPONSE"); - } - - if (rawShareData.ocs.data[0].item_type === "file") { - this.memento.itemType = ShareItemType.file; - } else { - this.memento.itemType = ShareItemType.folder; - } - if (rawShareData.ocs.data[0].expiration) { - this.memento.expiration = new Date(rawShareData.ocs.data[0].expiration); - } - - if (rawShareData.ocs.data[0].note) { - this.memento.note = rawShareData.ocs.data[0].note; - } - - // console.log(JSON.stringify(rawShareData, null, 4)); - // console.log(JSON.stringify(this, null, 4)); - } + public async setNote(note: string): Promise { + this.memento.note = note; + await this.client.updateShare(this.memento.id, { note }); + } - /** - * token - * The token is readonly - */ - public get token(): string { - return this.memento.token; - } + private async initialize(): Promise { + const rawShareData = await this.client.getShare(this.memento.id); - /** - * share url - * The share url is readonly - */ - public get url(): string { - return this.memento.url; + if (!rawShareData.ocs || !rawShareData.ocs.data[0]) { + throw new ClientError( + `Error invalid share data received "ocs.data" missing`, + "ERR_INVALID_SHARE_RESPONSE", + ); } - /** - * expiration - * The expiration is readonly - */ - public get expiration(): Date | null { - return this.memento.expiration; + if (!rawShareData.ocs.data[0].item_type) { + throw new ClientError( + `Error invalid share data received "item_type" missing`, + "ERR_INVALID_SHARE_RESPONSE", + ); } - /** - * note - * The note is readonly - */ - public get note(): string { - return this.memento.note; + if (rawShareData.ocs.data[0].item_type === "file") { + this.memento.itemType = ShareItemType.file; + } else { + this.memento.itemType = ShareItemType.folder; } - - /** - * id - * The id is readonly - */ - public get id(): string { - return this.memento.id; + if (rawShareData.ocs.data[0].expiration) { + this.memento.expiration = new Date(rawShareData.ocs.data[0].expiration); } - /** - * returns true if the share akkows upload - */ - public get publicUpload(): boolean { - return this.memento.publicUpload; + if (rawShareData.ocs.data[0].note) { + this.memento.note = rawShareData.ocs.data[0].note; } - /** - * item type - * The type of the share item file or folder - */ - public get itemType(): ShareItemType { - return this.memento.itemType; + if (rawShareData.ocs.data[0].share_type) { + switch (rawShareData.ocs.data[0].share_type) { + case ShareType.user.valueOf(): + this.memento.shareType = ShareType.user; + if (rawShareData.ocs.data[0].share_with) { + this.memento.shareWith = new User(this.client, rawShareData.ocs.data[0].share_with); + } else { + throw new ClientError(`Error user share without target user`, "ERR_USER_SHARE_NO_USER"); + } + break; + case ShareType.group.valueOf(): + this.memento.shareType = ShareType.group; + if (rawShareData.ocs.data[0].share_with) { + this.memento.shareWith = new UserGroup(this.client, rawShareData.ocs.data[0].share_with); + } else { + throw new ClientError( + `Error usergroup share without target usergroup`, + "ERR_USERGROUP_SHARE_NO_USERGROUP", + ); + } + break; + case ShareType.publicLink.valueOf(): + this.memento.shareType = ShareType.publicLink; + if (!rawShareData.ocs.data[0].url) { + throw new ClientError( + `Error invalid share data received "url" missing`, + "ERR_INVALID_SHARE_RESPONSE", + ); + } + this.memento.url = rawShareData.ocs.data[0].url; + if (!rawShareData.ocs.data[0].token) { + throw new ClientError( + `Error invalid share data received "token" missing`, + "ERR_INVALID_SHARE_RESPONSE", + ); + } + this.memento.token = rawShareData.ocs.data[0].token; + + break; + default: + throw new ClientError(`Error unsupported share type`, "ERR_UNSUPPORTED_SHARE_TYPE"); + } } + // console.log(JSON.stringify(rawShareData, null, 4)); + // console.log(JSON.stringify(this, null, 4)); + } + + /** + * token + * The token is readonly + */ + public get token(): string | null { + return this.memento.token; + } + + /** + * share url + * The share url is readonly + */ + public get url(): string | null { + return this.memento.url; + } + + /** + * expiration + * The expiration is readonly + */ + public get expiration(): Date | null { + return this.memento.expiration; + } + + /** + * note + * The note is readonly + */ + public get note(): string { + return this.memento.note; + } + + /** + * id + * The id is readonly + */ + public get id(): string { + return this.memento.id; + } + + /** + * returns true if the share akkows upload + */ + public get publicUpload(): boolean { + return this.memento.publicUpload; + } + + /** + * item type + * The type of the share item file or folder + */ + public get itemType(): ShareItemType { + return this.memento.itemType; + } + + /** + * share type + * The type of the share + */ + public get shareType(): ShareType { + return this.memento.shareType; + } + + /** + * share with + * The entity the share is shared with + */ + public get shareWith(): User | UserGroup | null { + return this.memento.shareWith; + } } diff --git a/src/test/01.nextcloudClient.test.d.ts b/src/test/01.nextcloudClient.test.d.ts new file mode 100644 index 00000000..87ad0c95 --- /dev/null +++ b/src/test/01.nextcloudClient.test.d.ts @@ -0,0 +1 @@ +import "mocha"; diff --git a/src/test/01.nextcloudClient.test.js b/src/test/01.nextcloudClient.test.js new file mode 100644 index 00000000..d5696b89 --- /dev/null +++ b/src/test/01.nextcloudClient.test.js @@ -0,0 +1,1462 @@ +"use strict"; +var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { + function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } + return new (P || (P = Promise))(function (resolve, reject) { + function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } + function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } + function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } + step((generator = generator.apply(thisArg, _arguments || [])).next()); + }); +}; +var __importDefault = (this && this.__importDefault) || function (mod) { + return (mod && mod.__esModule) ? mod : { "default": mod }; +}; +Object.defineProperty(exports, "__esModule", { value: true }); +// this must be the first +const dotenv_1 = require("dotenv"); +(0, dotenv_1.config)(); +const chai_1 = require("chai"); +// if you used the '@types/mocha' method to install mocha type definitions, uncomment the following line +require("mocha"); +const mocked_env_1 = __importDefault(require("mocked-env")); +const client_1 = require("../client"); +const environment_1 = __importDefault(require("../environment")); +const environmentVcapServices_1 = __importDefault(require("../environmentVcapServices")); +const server_1 = __importDefault(require("../server")); +const testUtils_1 = require("./testUtils"); +let client; +// tslint:disable-next-line:only-arrow-functions +// tslint:disable-next-line:space-before-function-paren +describe("01-NEXCLOUD-NODE-CLIENT", function () { + // tslint:disable-next-line:space-before-function-paren + beforeEach(function () { + return __awaiter(this, void 0, void 0, function* () { + if (this.currentTest && this.currentTest.parent) { + client = yield (0, testUtils_1.getNextcloudClient)(this.currentTest.parent.title + "/" + this.currentTest.title); + } + }); + }); + this.timeout(1 * 60 * 1000); + it("01 create client fails", () => __awaiter(this, void 0, void 0, function* () { + const restore = (0, mocked_env_1.default)({ + NEXTCLOUD_URL: undefined, + VCAP_SERVICES: undefined, + }); + try { + // tslint:disable-next-line:no-unused-expression + new client_1.Client(); + (0, chai_1.expect)(false, "expect an exception").to.be.equal(true); + } + catch (e) { + // should fail, if env is not set correctly + (0, chai_1.expect)(e).to.have.property("message"); + (0, chai_1.expect)(e).to.have.property("code"); + (0, chai_1.expect)(e.code).to.be.equal("ERR_NEXTCLOUD_URL_NOT_DEFINED"); + } + finally { + restore(); + } + })); + it("02 create client success", () => __awaiter(this, void 0, void 0, function* () { + const restore = (0, mocked_env_1.default)({ + NEXTCLOUD_URL: undefined, + VCAP_SERVICES: JSON.stringify({ + "user-provided": [{ + credentials: { + password: "somePassword", + url: "https://some.host-name.com/remote.php/webdav", + username: "someUserName", + }, + name: "nextcloud", + }], + }), + }); + try { + // tslint:disable-next-line:no-unused-expression + new client_1.Client(); + } + catch (e) { + (0, chai_1.expect)(e.message, "expect an exception").to.be.equal("expect no exception"); + } + finally { + restore(); + } + })); + it("03 get and create folder", () => __awaiter(this, void 0, void 0, function* () { + let errorOccurred; + let folder = null; + const dirName = "/test/a/b/c/d/xx"; + folder = yield client.createFolder(dirName); + try { + folder = yield client.getFolder(dirName); + errorOccurred = false; + } + catch (e) { + errorOccurred = true; + } + (0, chai_1.expect)(folder, "expect folder to a object").to.be.a("object"); + (0, chai_1.expect)(folder, "expect folder to be a Folder").to.be.instanceOf(client_1.Folder); + })); + it("04 delete folder", () => __awaiter(this, void 0, void 0, function* () { + let errorOccurred; + let folder = null; + const dirName = "/test/deleteme"; + try { + folder = yield client.createFolder(dirName); + errorOccurred = false; + } + catch (e) { + errorOccurred = true; + } + (0, chai_1.expect)(folder, "expect folder to an object").to.be.a("object"); + (0, chai_1.expect)(folder, "expect folder to be a Folder").to.be.instanceOf(client_1.Folder); + try { + folder = yield client.getFolder(dirName); + errorOccurred = false; + } + catch (e) { + errorOccurred = true; + } + (0, chai_1.expect)(folder, "expect folder to an object").to.be.a("object"); + (0, chai_1.expect)(folder, "expect folder to be a Folder").to.be.instanceOf(client_1.Folder); + let deleteResponse; + try { + deleteResponse = yield client.deleteFolder(dirName); + errorOccurred = false; + } + catch (e) { + errorOccurred = true; + } + try { + folder = yield client.getFolder(dirName); + errorOccurred = false; + } + catch (e) { + errorOccurred = true; + } + (0, chai_1.expect)(folder, "expect folder to null").to.be.equal(null); + })); + it("05 get root folder", () => __awaiter(this, void 0, void 0, function* () { + let errorOccurred; + let folder = null; + const dirName = ""; + folder = yield client.createFolder(dirName); + try { + folder = yield client.getFolder(dirName); + errorOccurred = false; + } + catch (e) { + errorOccurred = true; + } + (0, chai_1.expect)(folder, "expect folder to a object").to.be.a("object"); + (0, chai_1.expect)(folder, "expect folder to be a Folder").to.be.instanceOf(client_1.Folder); + })); + it("06 create . folder", () => __awaiter(this, void 0, void 0, function* () { + let errorOccurred; + let folder = null; + const dirName = "/test/aa/.."; + try { + folder = yield client.createFolder(dirName); + errorOccurred = false; + } + catch (e) { + errorOccurred = true; + } + (0, chai_1.expect)(folder, "expect folder to a null").to.be.equal(null); + })); + it("07 create file", () => __awaiter(this, void 0, void 0, function* () { + let errorOccurred; + const fileName = "/test/test07/file1.txt"; + let file = null; + try { + file = yield client.createFile(fileName, Buffer.from("this is a test text")); + errorOccurred = false; + } + catch (e) { + errorOccurred = true; + } + (0, chai_1.expect)(errorOccurred, "expect no exception").to.be.equal(false); + (0, chai_1.expect)(file, "expect file to a object").to.be.a("object").that.is.instanceOf(client_1.File); + // expect(file, "expect file to be a Folder").to.be.instanceOf(File); + (0, chai_1.expect)(file, "expect file to a object").to.be.a("object"); + (0, chai_1.expect)(file, "expect file to be a Folder").to.be.instanceOf(client_1.File); + const folder = yield file.getFolder(); + (0, chai_1.expect)(folder.baseName, "base name of the file folder is 'test07'").to.be.equal("test07"); + yield folder.delete(); + try { + yield file.getFolder(); + } + catch (e) { + (0, chai_1.expect)(e.message, "expect an exception").to.be.equal("Error, the folder of the file does not exist anymore"); + } + })); + it("08 get sub directories of non existsing folder", () => __awaiter(this, void 0, void 0, function* () { + const directories = yield client.getSubFolders("/non/existing/folder"); + (0, chai_1.expect)(directories, "expect directories to be an array").to.be.a("array"); + (0, chai_1.expect)(directories.length, "expect directories to be empty").to.be.equal(0); + })); + it("09 get sub directories", () => __awaiter(this, void 0, void 0, function* () { + const baseName = "/test/base09"; + const subDirName1 = "subdir1"; + const subDirName2 = "subdir2"; + const baseDir = yield client.createFolder(baseName); + yield client.createFolder(baseName + "/" + subDirName1); + yield client.createFolder(baseName + "/" + subDirName2); + const directories = yield client.getSubFolders(baseName); + (0, chai_1.expect)(directories, "expect directories to be an array").to.be.a("array"); + (0, chai_1.expect)(directories.length, "expect 2 directories:" + JSON.stringify(directories)).to.be.equal(2); + yield baseDir.delete(); + })); + it("10 get sub directories with folder object", () => __awaiter(this, void 0, void 0, function* () { + const baseName = "/test/base10"; + const subDirName1 = "subdir1"; + const subDirName2 = "subdir2"; + const baseDir = yield client.createFolder(baseName); + yield client.createFolder(baseName + "/" + subDirName1); + yield client.createFolder(baseName + "/" + subDirName2); + const directories = yield baseDir.getSubFolders(); + (0, chai_1.expect)(directories, "expect directories to be an array").to.be.a("array"); + (0, chai_1.expect)(directories.length, "expect directories to have 2 sub directories").to.be.equal(2); + yield baseDir.delete(); + })); + it("11 get files of an empty folder", () => __awaiter(this, void 0, void 0, function* () { + const dirName = "/test/files/empty"; + const baseDir = yield client.createFolder(dirName); + const files = yield baseDir.getFiles(); + (0, chai_1.expect)(files, "expect files to be an array").to.be.a("array"); + (0, chai_1.expect)(files.length, "expect files to be empty").to.be.equal(0); + yield baseDir.delete(); + })); + it("12 get files of a folder", () => __awaiter(this, void 0, void 0, function* () { + const dirName = "/test/files"; + const fileName1 = "file1.txt"; + const fileName2 = "file2.txt"; + const baseDir = yield client.createFolder(dirName); + yield baseDir.createFile(fileName1, Buffer.from("File 1")); + yield baseDir.createFile(fileName2, Buffer.from("File 2")); + const files = yield baseDir.getFiles(); + (0, chai_1.expect)(files, "expect files to be an array").to.be.a("array"); + (0, chai_1.expect)(files.length, "expect files to be empty").to.be.equal(2); + yield baseDir.delete(); + })); + it("13 get file content", () => __awaiter(this, void 0, void 0, function* () { + const dirName = "/test/fileContent"; + const fileName1 = "file1.txt"; + const baseDir = yield client.createFolder(dirName); + yield baseDir.createFile(fileName1, Buffer.from("File 1")); + const file = yield client.getFile(dirName + "/" + fileName1); + (0, chai_1.expect)(file, "expect file to a object").to.be.a("object").that.is.instanceOf(client_1.File); + const content = yield file.getContent(); + (0, chai_1.expect)(content.toString(), "expect file content to be 'File 1'").to.be.equal("File 1"); + yield baseDir.delete(); + })); + it("14 delete file", () => __awaiter(this, void 0, void 0, function* () { + const dirName = "/test/fileDelete"; + const fileName1 = "file1.txt"; + const baseDir = yield client.createFolder(dirName); + yield baseDir.createFile(fileName1, Buffer.from("File 1")); + let file = yield client.getFile(dirName + "/" + fileName1); + (0, chai_1.expect)(file, "expect file to a object").to.be.a("object").that.is.instanceOf(client_1.File); + yield file.delete(); + file = yield baseDir.getFile(fileName1); + (0, chai_1.expect)(file, "expect file to be null").to.be.equal(null); + yield baseDir.delete(); + })); + it("15 get link of file", () => __awaiter(this, void 0, void 0, function* () { + const dirName = "/test/fileLink"; + const fileName1 = "file1.txt"; + const baseDir = yield client.createFolder(dirName); + yield baseDir.createFile(fileName1, Buffer.from("File 1")); + const file = yield client.getFile(dirName + "/" + fileName1); + (0, chai_1.expect)(file, "expect file to a object").to.be.a("object").that.is.instanceOf(client_1.File); + (0, chai_1.expect)(file, "expect file not to be null").to.be.not.equal(null); + const url = file.getUrl(); + (0, chai_1.expect)(url, "expect url to be a string").to.be.a("string"); + (0, chai_1.expect)(url, "expect url to be available").to.be.not.equal(""); + })); + it("16 get link of folder", () => __awaiter(this, void 0, void 0, function* () { + const dirName = "/test/fileLink"; + yield client.createFolder(dirName); + const url = client.getLink(dirName); + (0, chai_1.expect)(url, "expect url to be a string").to.be.a("string"); + (0, chai_1.expect)(url, "expect url to be available").to.be.not.equal(""); + })); + it("17 move folder", () => __awaiter(this, void 0, void 0, function* () { + const sourceDirName = "/test/sourcefolder"; + const targetDirName = "/test/targetFolder"; + const sourceDir = yield client.createFolder(sourceDirName); + yield sourceDir.move(targetDirName); + (0, chai_1.expect)(sourceDir.name, "expect that the dirname has changed to the target name").to.be.equal(targetDirName); + })); + it("18 move file", () => __awaiter(this, void 0, void 0, function* () { + const dirName = "/test/renameFile"; + const sourceFileName = "sourceFile.txt"; + const targetFileName = dirName + "/targetFile.txt"; + const baseDir = yield client.createFolder(dirName); + const file = yield baseDir.createFile(sourceFileName, Buffer.from("File")); + yield file.move(targetFileName); + (0, chai_1.expect)(file.name, "expect that the filename has changed to the target name").to.be.equal(targetFileName); + })); + it("19 get non existing file", () => __awaiter(this, void 0, void 0, function* () { + const fileName = "/test/doesNotExist.txt"; + const file = yield client.getFile(fileName); + (0, chai_1.expect)(file, "expect file to be null").to.be.equal(null); + })); + it("20 get file id", () => __awaiter(this, void 0, void 0, function* () { + const dirName = "/test/getFileId"; + const fileName1 = "file1.txt"; + const baseDir = yield client.createFolder(dirName); + yield baseDir.createFile(fileName1, Buffer.from("File 1")); + const file = yield client.getFile(dirName + "/" + fileName1); + (0, chai_1.expect)(file, "expect file to a object").to.be.a("object").that.is.instanceOf(client_1.File); + (0, chai_1.expect)(file, "expect file not to be null").to.be.not.equal(null); + const id = yield file.id; + (0, chai_1.expect)(id, "expect id to be a number").to.be.a("number"); + (0, chai_1.expect)(id, "expect id to be not -1").to.be.not.equal(-1); + })); + it("21 get folder id", () => __awaiter(this, void 0, void 0, function* () { + const dirName = "/test/getFolderId"; + const baseDir = yield client.createFolder(dirName); + const id = yield baseDir.id; + (0, chai_1.expect)(id, "expect id to be a number").to.be.a("number"); + (0, chai_1.expect)(id, "expect id to be not -1").to.be.not.equal(-1); + })); + it("22 has subfolders", () => __awaiter(this, void 0, void 0, function* () { + const parentFolderName = "/test/folderWithSubfolder"; + let subFolderName = "subFolder"; + const parentFolder = yield client.createFolder(parentFolderName); + const subFolder = yield client.createFolder(parentFolderName + "/" + subFolderName); + (0, chai_1.expect)(yield parentFolder.hasSubFolder(subFolderName), `Folder should have the subfolder with the name ${subFolderName}`).to.be.equal(true); + subFolderName = "notASubFolder"; + (0, chai_1.expect)(yield parentFolder.hasSubFolder(subFolderName), `Folder should not have the subfolder with the name ${subFolderName}`).to.be.equal(false); + })); + it("23 create client with wrong webdav url", () => __awaiter(this, void 0, void 0, function* () { + const ncserver = new server_1.default({ + basicAuth: { + password: "some password", + username: "some user name", + }, + url: "https://someServer.com:123", + }); + try { + // tslint:disable-next-line:no-unused-expression + new client_1.Client(ncserver); + } + catch (e) { + (0, chai_1.expect)(e).to.have.property("message"); + (0, chai_1.expect)(e).to.have.property("code"); + (0, chai_1.expect)(e.code).to.be.equal("ERR_INVALID_NEXTCLOUD_WEBDAV_URL"); + } + })); + it("24 create a client with url ", () => __awaiter(this, void 0, void 0, function* () { + const ncserver = new server_1.default({ + basicAuth: { + password: "some password", + username: "some user name", + }, + url: "https://someServer.com:123/remote.php/webdav", + }); + try { + // tslint:disable-next-line:no-unused-expression + new client_1.Client(ncserver); + } + catch (e) { + (0, chai_1.expect)(e, "No exception expected").to.be.equal(""); + } + ncserver.url += "/"; + try { + // tslint:disable-next-line:no-unused-expression + new client_1.Client(ncserver); + } + catch (e) { + (0, chai_1.expect)(e, "No exception expected").to.be.equal(""); + } + })); + it("25 get file id", () => __awaiter(this, void 0, void 0, function* () { + const dirName = "/test/fileId"; + const fileName1 = "file1.txt"; + const baseDir = yield client.createFolder(dirName); + const file = yield baseDir.createFile(fileName1, Buffer.from("File 1")); + (0, chai_1.expect)(file, "expect file not to be null").to.be.not.equal(null); + if (file) { + const fileId = yield file.id; + (0, chai_1.expect)(fileId, "expect fileid to a number").to.be.a("number"); + (0, chai_1.expect)(fileId).not.to.be.equal(-1); + const url = file.getUrl(); + const fileId2 = yield client.getFileId(url); + (0, chai_1.expect)(fileId2, "expect fileid to a number").to.be.a("number"); + (0, chai_1.expect)(fileId2).not.to.be.equal(-1); + yield file.delete(); + } + })); + it("26 delete a non existing file by name", () => __awaiter(this, void 0, void 0, function* () { + try { + yield client.deleteFile("fileDoesNotExist.txt"); + } + catch (e) { + (0, chai_1.expect)(e, "exception expected").not.to.be.equal(""); + } + })); + it("27 try to get a folder with a file name", () => __awaiter(this, void 0, void 0, function* () { + const dirName = "/test/getFolder"; + const fileName1 = "file1.txt"; + const baseDir = yield client.createFolder(dirName); + const file = yield baseDir.createFile(fileName1, Buffer.from("File 1")); + (0, chai_1.expect)(file, "expect file not to be null").to.be.not.equal(null); + if (file) { + const folder = yield client.getFolder(file.name); + (0, chai_1.expect)(folder, "expect folder to be null").to.be.equal(null); + } + })); + it("28 create folder with '.'", () => __awaiter(this, void 0, void 0, function* () { + const dirName = "./"; + const fileName1 = "file1.txt"; + const file = yield client.createFile(dirName + fileName1, Buffer.from("File 1")); + (0, chai_1.expect)(file, "expect file not to be null").to.be.not.equal(null); + if (file) { + yield file.delete(); + } + })); + it("29 create invalid file", () => __awaiter(this, void 0, void 0, function* () { + const dirName = "/test/getFolder"; + const fileName1 = "fil*e1.txt"; + const baseDir = yield client.createFolder(dirName); + try { + // tslint:disable-next-line:no-unused-expression + yield baseDir.createFile(fileName1, Buffer.from("File 1")); + } + catch (e) { + (0, chai_1.expect)(e).to.have.property("message"); + (0, chai_1.expect)(e).to.have.property("code"); + (0, chai_1.expect)(e.code).to.be.equal("ERR_INVALID_CHAR_IN_FILE_NAME"); + } + })); + it("30 get folder url, UIUrl and id", () => __awaiter(this, void 0, void 0, function* () { + const dirName = "/test/getFolder"; + const baseDir = yield client.createFolder(dirName); + const url = baseDir.getUrl(); + (0, chai_1.expect)(url).to.be.an("string"); + (0, chai_1.expect)(url).not.to.be.equal(""); + const uiUrl = yield baseDir.getUIUrl(); + (0, chai_1.expect)(uiUrl).to.be.an("string"); + (0, chai_1.expect)(uiUrl).not.to.be.equal(""); + yield baseDir.delete(); + try { + // tslint:disable-next-line:no-unused-expression + yield baseDir.id; + } + catch (e) { + (0, chai_1.expect)(e).to.have.property("message"); + (0, chai_1.expect)(e).to.have.property("code"); + (0, chai_1.expect)(e.code).to.be.equal("ERR_FOLDER_NOT_EXISTING"); + } + })); + it("31 folder contains file test", () => __awaiter(this, void 0, void 0, function* () { + const dirName = "/test/containsFileFolder"; + const fileName1 = "file31.txt"; + const baseDir = yield client.createFolder(dirName); + const file = yield baseDir.createFile(fileName1, Buffer.from("File 1")); + (0, chai_1.expect)(file, "expect file not to be null").to.be.not.equal(null); + (0, chai_1.expect)(yield baseDir.containsFile(fileName1)).to.be.equal(true); + (0, chai_1.expect)(yield baseDir.containsFile("nonExistingFile.txt")).to.be.equal(false); + yield baseDir.delete(); + })); + it("32 file get urls", () => __awaiter(this, void 0, void 0, function* () { + const dirName = "/test/fileGetUrl"; + const fileName1 = "file32.txt"; + const baseDir = yield client.createFolder(dirName); + const file = yield baseDir.createFile(fileName1, Buffer.from("File 1")); + (0, chai_1.expect)(file, "expect file not to be null").to.be.not.equal(null); + if (file) { + const url = file.getUrl(); + (0, chai_1.expect)(url).to.be.an("string"); + (0, chai_1.expect)(url).not.to.be.equal(""); + const uiUrl = yield file.getUIUrl(); + (0, chai_1.expect)(uiUrl).to.be.an("string"); + (0, chai_1.expect)(uiUrl).not.to.be.equal(""); + yield file.delete(); + try { + // tslint:disable-next-line:no-unused-expression + file.id; + } + catch (e) { + (0, chai_1.expect)(e).to.have.property("message"); + (0, chai_1.expect)(e).to.have.property("code"); + (0, chai_1.expect)(e.code).to.be.equal("ERR_FILE_NOT_EXISTING"); + } + } + yield baseDir.delete(); + })); + it("33 create subfolder", () => __awaiter(this, void 0, void 0, function* () { + const dirName = "/test/subfolderTest"; + const baseDir = yield client.createFolder(dirName); + const subfolderName = "subFolder"; + const subfolder = yield baseDir.createSubFolder("subsubfolder"); + (0, chai_1.expect)(subfolder.name).not.to.be.equal(baseDir.name + "/" + subfolderName); + })); + it("34 Get credentials from non existing VCAP_SERVICES environment", () => __awaiter(this, void 0, void 0, function* () { + let restore = (0, mocked_env_1.default)({ + VCAP_SERVICES: undefined, + }); + try { + new environmentVcapServices_1.default("").getServer(); + (0, chai_1.expect)(true, "expect no exception").to.be.equal(false); + } + catch (e) { + (0, chai_1.expect)(e).to.have.property("message"); + (0, chai_1.expect)(e).to.have.property("code"); + (0, chai_1.expect)(e.code).to.be.equal("ERR_VCAP_SERVICES_NOT_FOUND"); + } + finally { + restore(); + } + restore = (0, mocked_env_1.default)({ + VCAP_SERVICES: JSON.stringify({ + "user-provided": [{ + credentials: {}, + name: "test", + }], + }), + }); + try { + new environmentVcapServices_1.default("").getServer(); + (0, chai_1.expect)(true, "expect no exception").to.be.equal(false); + } + catch (e) { + (0, chai_1.expect)(e).to.have.property("message"); + (0, chai_1.expect)(e).to.have.property("code"); + (0, chai_1.expect)(e.code).to.be.equal("ERR_VCAP_SERVICES_NOT_FOUND"); + } + finally { + restore(); + } + restore = (0, mocked_env_1.default)({ + VCAP_SERVICES: JSON.stringify({ + "user-provided": [{ + credentials: { + url: "https://some.host-name.com/remote.php/webdav", + username: "someUserName", + }, + name: "test", + }], + }), + }); + try { + new environmentVcapServices_1.default("").getServer(); + (0, chai_1.expect)(true, "expect no exception").to.be.equal(false); + } + catch (e) { + (0, chai_1.expect)(e).to.have.property("message"); + (0, chai_1.expect)(e).to.have.property("code"); + (0, chai_1.expect)(e.code).to.be.equal("ERR_VCAP_SERVICES_PASSWORD_NOT_DEFINED"); + } + finally { + restore(); + } + restore = (0, mocked_env_1.default)({ + VCAP_SERVICES: JSON.stringify({ + "user-provided": [{ + credentials: { + password: "somePassword", + url: "https://some.host-name.com/remote.php/webdav", + }, + name: "test", + }], + }), + }); + try { + new environmentVcapServices_1.default("").getServer(); + (0, chai_1.expect)(true, "expect no exception").to.be.equal(false); + } + catch (e) { + (0, chai_1.expect)(e).to.have.property("message"); + (0, chai_1.expect)(e).to.have.property("code"); + (0, chai_1.expect)(e.code).to.be.equal("ERR_VCAP_SERVICES_USERNAME_NOT_DEFINED"); + } + finally { + restore(); + } + restore = (0, mocked_env_1.default)({ + VCAP_SERVICES: JSON.stringify({ + "user-provided": [{ + credentials: { + password: "somePassword", + url: "https://some.host-name.com/remote.php/webdav", + username: "someUserName", + }, + name: "test", + }], + }), + }); + try { + new environmentVcapServices_1.default("").getServer(); + } + catch (e) { + (0, chai_1.expect)(false, "expect no exception: " + e.message).to.be.equal(true); + } + finally { + restore(); + } + restore = (0, mocked_env_1.default)({ + VCAP_SERVICES: JSON.stringify({ + "user-provided": [{ + credentials: { + password: "somePassword", + username: "someUserName", + }, + name: "test", + }], + }), + }); + try { + new environmentVcapServices_1.default("").getServer(); + } + catch (e) { + (0, chai_1.expect)(e).to.have.property("message"); + (0, chai_1.expect)(e).to.have.property("code"); + (0, chai_1.expect)(e.code).to.be.equal("ERR_VCAP_SERVICES_URL_NOT_DEFINED"); + } + finally { + restore(); + } + })); + it("35 Get credentials from non existing environment", () => __awaiter(this, void 0, void 0, function* () { + let restore = (0, mocked_env_1.default)({ + NEXTCLOUD_PASSWORD: "SomePassword", + NEXTCLOUD_URL: undefined, + NEXTCLOUD_USERNAME: "SomeUser", + }); + try { + environment_1.default.getNextcloudUrl(); + } + catch (e) { + (0, chai_1.expect)(e).to.have.property("message"); + (0, chai_1.expect)(e).to.have.property("code"); + (0, chai_1.expect)(e.code).to.be.equal("ERR_NEXTCLOUD_URL_NOT_DEFINED"); + } + finally { + restore(); + } + restore = (0, mocked_env_1.default)({ + NEXTCLOUD_PASSWORD: "SomePassword", + NEXTCLOUD_URL: "someUrl", + NEXTCLOUD_USERNAME: undefined, + }); + try { + environment_1.default.getUserName(); + } + catch (e) { + (0, chai_1.expect)(e).to.have.property("message"); + (0, chai_1.expect)(e).to.have.property("code"); + (0, chai_1.expect)(e.code).to.be.equal("ERR_NEXTCLOUD_USERNAME_NOT_DEFINED"); + } + finally { + restore(); + } + restore = (0, mocked_env_1.default)({ + NEXTCLOUD_PASSWORD: undefined, + NEXTCLOUD_URL: "someUrl", + NEXTCLOUD_USERNAME: "SomeUser", + }); + try { + environment_1.default.getPassword(); + } + catch (e) { + (0, chai_1.expect)(e).to.have.property("message"); + (0, chai_1.expect)(e).to.have.property("code"); + (0, chai_1.expect)(e.code).to.be.equal("ERR_NEXTCLOUD_PASSWORD_NOT_DEFINED"); + } + finally { + restore(); + } + restore = (0, mocked_env_1.default)({ + NEXTCLOUD_PASSWORD: "SomePassword", + NEXTCLOUD_URL: "someUrl", + NEXTCLOUD_USERNAME: "SomeUser", + }); + try { + environment_1.default.getNextcloudUrl(); + environment_1.default.getPassword(); + environment_1.default.getUserName(); + } + catch (e) { + (0, chai_1.expect)(false, "do not expect an exception " + e.message).to.be.equal(true); + } + finally { + restore(); + } + restore = (0, mocked_env_1.default)({ + NEXTCLOUD_PASSWORD: "SomePassword", + NEXTCLOUD_URL: "someUrl", + NEXTCLOUD_USERNAME: "SomeUser", + TEST_RECORDING_ACTIVE: "X", + }); + try { + environment_1.default.getNextcloudUrl(); + environment_1.default.getPassword(); + environment_1.default.getUserName(); + environment_1.default.getRecordingActiveIndicator(); + } + catch (e) { + (0, chai_1.expect)(false, "do not expect an exception " + e.message).to.be.equal(true); + } + finally { + restore(); + } + restore = (0, mocked_env_1.default)({ + NEXTCLOUD_PASSWORD: "SomePassword", + NEXTCLOUD_URL: "someUrl", + NEXTCLOUD_USERNAME: "SomeUser", + TEST_RECORDING_ACTIVE: "false", + }); + try { + environment_1.default.getNextcloudUrl(); + environment_1.default.getPassword(); + environment_1.default.getUserName(); + environment_1.default.getRecordingActiveIndicator(); + } + catch (e) { + (0, chai_1.expect)(false, "do not expect an exception " + e.message).to.be.equal(true); + } + finally { + restore(); + } + restore = (0, mocked_env_1.default)({ + NEXTCLOUD_PASSWORD: "SomePassword", + NEXTCLOUD_URL: "someUrl", + NEXTCLOUD_USERNAME: "SomeUser", + TEST_RECORDING_ACTIVE: "0", + }); + try { + environment_1.default.getNextcloudUrl(); + environment_1.default.getPassword(); + environment_1.default.getUserName(); + environment_1.default.getRecordingActiveIndicator(); + } + catch (e) { + (0, chai_1.expect)(false, "do not expect an exception " + e.message).to.be.equal(true); + } + finally { + restore(); + } + restore = (0, mocked_env_1.default)({ + NEXTCLOUD_PASSWORD: "SomePassword", + NEXTCLOUD_URL: "someUrl", + NEXTCLOUD_USERNAME: "SomeUser", + TEST_RECORDING_ACTIVE: "inactive", + }); + try { + environment_1.default.getNextcloudUrl(); + environment_1.default.getPassword(); + environment_1.default.getUserName(); + environment_1.default.getRecordingActiveIndicator(); + } + catch (e) { + (0, chai_1.expect)(false, "do not expect an exception " + e.message).to.be.equal(true); + } + finally { + restore(); + } + })); + it("36 get file with folder name", () => __awaiter(this, void 0, void 0, function* () { + const dirName = "/test/folder36"; + const fileName1 = "file1.txt"; + const baseDir = yield client.createFolder(dirName); + yield baseDir.createFile(fileName1, Buffer.from("File 1")); + const file = yield client.getFile(dirName + "/" + fileName1); + (0, chai_1.expect)(file, "expect file to a object").to.be.a("object").that.is.instanceOf(client_1.File); + // returns null only for coverage + yield client.getFile(dirName); + yield baseDir.delete(); + })); + it("37 get file with incomplete server response", () => __awaiter(this, void 0, void 0, function* () { + const entries = []; + entries.push({ + request: { + description: "File/Folder get details", + method: "PROPFIND", + url: "/remote.php/webdav/test/folder37", + }, + response: { + body: "\n/remote.php/webdav/test/files/file1.txtWed, 18 Dec 2019 17:38:35 GMT"75087567dd1ebe3c04d134837063aeca"text/plain78891RGDNVW66true00Horst-Thorsten BorstensonHTTP/1.1 200 OK", + contentType: "application/xml; charset=utf-8", + status: 207, + }, + }); + const lclient = new client_1.Client(new client_1.FakeServer(entries)); + // console.log(JSON.stringify(this.tests[0].title, null, 4)); + let q; + try { + q = yield lclient.getFile("some dummy name"); + // expect(true, "expect an exception").to.be.equal(false); + } + catch (e) { + (0, chai_1.expect)(true, "expect an exception").to.be.equal(e.message); + } + })); + it("38 delete non existing folder", () => __awaiter(this, void 0, void 0, function* () { + const dirName = "/test/deletemeNonExistingFolder"; + try { + yield client.deleteFolder(dirName); + } + catch (e) { + (0, chai_1.expect)(true, "expect folder no exception").to.be.equal(false); + } + })); + it("39 move folder fails", () => __awaiter(this, void 0, void 0, function* () { + const entries = []; + entries.push({ + request: { + description: "Folder move", + method: "MOVE", + url: "/remote.php/webdav/test/source", + }, + response: { + body: "", + contentType: "text/html; charset=UTF-8", + status: 500, + }, + }); + const sourceDirName = "/test/sourcefolder"; + const targetDirName = "/test/targetFolder"; + const lclient = new client_1.Client(new client_1.FakeServer(entries)); + let folder; + try { + folder = yield lclient.moveFolder(sourceDirName, targetDirName); + } + catch (e) { + (0, chai_1.expect)(true, "expect an exception").to.be.equal(true); + } + (0, chai_1.expect)(folder, "expect an folder to be undefined").to.be.equal(undefined); + })); + it("40 move folder fails - target folder missing", () => __awaiter(this, void 0, void 0, function* () { + const entries = []; + entries.push({ + request: { + description: "Folder move", + method: "MOVE", + url: "/remote.php/webdav/test/source", + }, + response: { + body: "", + contentType: "text/html; charset=UTF-8", + status: 201, + }, + }); + entries.push({ + request: { + description: "File/Folder get details", + method: "PROPFIND", + url: "/remote.php/webdav/test/target", + }, + response: { + body: "", + contentType: "text/html; charset=UTF-8", + status: 404, + }, + }); + const sourceDirName = "/test/sourcefolder"; + const targetDirName = "/test/targetFolder"; + const lclient = new client_1.Client(new client_1.FakeServer(entries)); + let folder; + try { + folder = yield lclient.moveFolder(sourceDirName, targetDirName); + } + catch (e) { + (0, chai_1.expect)(true, "expect an exception").to.be.equal(true); + } + (0, chai_1.expect)(folder, "expect an folder to be undefined").to.be.equal(undefined); + })); + it("41 get file content should fail", () => __awaiter(this, void 0, void 0, function* () { + const dirName = "/test/folder41"; + const fileName1 = "file1.txt"; + const baseDir = yield client.createFolder(dirName); + const file1 = yield baseDir.createFile(fileName1, Buffer.from("File 1")); + const file2 = yield baseDir.getFile(fileName1); + yield file1.delete(); + try { + yield (file2 === null || file2 === void 0 ? void 0 : file2.getContent()); + } + catch (e) { + (0, chai_1.expect)(e.message, "expect an exception").to.be.equal("HTTP response status 404 not expected. Expected status: 200 - status text: Not Found"); + } + yield baseDir.delete(); + })); + it("50 fake server without responses and request without method", () => __awaiter(this, void 0, void 0, function* () { + const requestInit = {}; + const fs = new client_1.FakeServer([]); + try { + yield fs.getFakeHttpResponse("", requestInit, [201], { description: "get response without method" }); + (0, chai_1.expect)(true, "expect an exception").to.be.equal(false); + } + catch (e) { + (0, chai_1.expect)(e.message).to.be.equal("error providing fake http response. No fake response available"); + } + })); + it("51 fake server without response content type", () => __awaiter(this, void 0, void 0, function* () { + const requestInit = {}; + const fs = new client_1.FakeServer([ + { + request: { + description: "description", + method: "method", + url: "url", + }, response: { status: 201, body: "body" }, + }, + ]); + try { + yield fs.getFakeHttpResponse("", requestInit, [201], { description: "get response without method" }); + } + catch (e) { + (0, chai_1.expect)(true, "expect no exception").to.be.equal(e.message); + } + })); + it("60 get file id with missing fileId", () => __awaiter(this, void 0, void 0, function* () { + const entries = []; + entries.push({ + request: { + description: "File get id", + method: "PROPFIND", + url: "/remote.php/webdav/test/fileId/file1.txt", + }, + response: { + body: "\n/remote.php/webdav/test/fileId/file1.txt78843HTTP/1.1 200 OK", + contentType: "application/xml; charset=utf-8", + status: 207, + }, + }); + const lclient = new client_1.Client(new client_1.FakeServer(entries)); + try { + yield lclient.getFileId("some/url"); + (0, chai_1.expect)(true, "expect an exception").to.be.equal(false); + } + catch (e) { + (0, chai_1.expect)(true, "expect an exception").to.be.equal(true); + } + })); + it("61 create folder error handling", () => __awaiter(this, void 0, void 0, function* () { + const entries = []; + entries.push({ + request: { + description: "File/Folder get details", + method: "PROPFIND", + url: "/remote.php/webdav/x", + }, + response: { + body: "", + contentType: "text/html; charset=UTF-8", + status: 404, + }, + }); + entries.push({ + request: { + description: "Folder create", + method: "MKCOL", + url: "/remote.php/webdav/x", + }, + response: { + body: "", + contentType: "text/html; charset=UTF-8", + status: 201, + }, + }); + entries.push({ + request: { + description: "File/Folder get details", + method: "PROPFIND", + url: "/remote.php/webdav/x", + }, + response: { + body: "", + contentType: "text/html; charset=UTF-8", + status: 404, // this should cause the error + }, + }); + const lclient = new client_1.Client(new client_1.FakeServer(entries)); + try { + yield lclient.createFolder("/x"); + (0, chai_1.expect)(true, "expect an exception").to.be.equal(false); + } + catch (e) { + (0, chai_1.expect)(true, "expect an exception").to.be.equal(true); + } + })); + it("62 move file that does not exist", () => __awaiter(this, void 0, void 0, function* () { + const dirName = "/test/renameFile62"; + const sourceFileName = "sourceFile.txt"; + const targetFileName = dirName + "/targetFile.txt"; + const baseDir = yield client.createFolder(dirName); + const file = yield baseDir.createFile(sourceFileName, Buffer.from("File")); + yield file.delete(); + try { + yield file.move(targetFileName); + (0, chai_1.expect)(true, "expect an exception").to.be.equal(false); + } + catch (e) { + (0, chai_1.expect)(true, "expect an exception").to.be.equal(true); + } + yield baseDir.delete(); + })); + it("63 move file to an unexisting folder", () => __awaiter(this, void 0, void 0, function* () { + const entries = []; + entries.push({ + request: { + description: "File move", + method: "MOVE", + url: "/remote.php/webdav/test/renameFile63/sourceFile.txt", + }, + response: { + contentType: "text/html; charset=UTF-8", + status: 201, + }, + }); + entries.push({ + request: { + description: "File/Folder get details", + method: "PROPFIND", + url: "/remote.php/webdav/test/renameFile63", + }, + response: { + contentType: "text/html; charset=UTF-8", + status: 404, + }, + }); + const lclient = new client_1.Client(new client_1.FakeServer(entries)); + // console.log(JSON.stringify(this.tests[0].title, null, 4)); + let q; + try { + q = yield lclient.moveFile("from", "to"); + } + catch (e) { + (0, chai_1.expect)(true, "expect an exception").to.be.equal(true); + } + (0, chai_1.expect)(q).to.be.equal(undefined); + })); + it("64 response without content type and body", () => __awaiter(this, void 0, void 0, function* () { + const entries = []; + entries.push({ + request: { + description: "", + method: "", + url: "", + }, + response: { + status: 207, + }, + }); + const lclient = new client_1.Client(new client_1.FakeServer(entries)); + try { + yield lclient.getQuota(); + (0, chai_1.expect)(true, "expect an exception").to.be.equal(false); + } + catch (e) { + (0, chai_1.expect)(e.message, "expect an exception").to.be.equal("Response content type expected"); + } + })); + it("65 expect xml content type", () => __awaiter(this, void 0, void 0, function* () { + const entries = []; + entries.push({ + request: { + description: "", + method: "", + url: "", + }, + response: { + body: "body", + contentType: "text/plain", + status: 207, + }, + }); + const lclient = new client_1.Client(new client_1.FakeServer(entries)); + try { + yield lclient.getQuota(); + (0, chai_1.expect)(true, "expect an exception").to.be.equal(false); + } + catch (e) { + (0, chai_1.expect)(e.message, "expect an exception").to.be.equal("XML response content type expected"); + } + })); + it("66 invalid xml response", () => __awaiter(this, void 0, void 0, function* () { + const entries = []; + entries.push({ + request: { + description: "", + method: "", + url: "", + }, + response: { + body: "NO XML", + contentType: "application/xml; charset=utf-8", + status: 207, + }, + }); + const lclient = new client_1.Client(new client_1.FakeServer(entries)); + try { + yield lclient.getQuota(); + (0, chai_1.expect)(true, "expect an exception").to.be.equal(false); + } + catch (e) { + (0, chai_1.expect)(e.message, "expect an exception").to.be.equal("The response is not valid XML: NO XML"); + } + })); + it("67 multistatus response without href", () => __awaiter(this, void 0, void 0, function* () { + const entries = []; + entries.push({ + request: { + description: "", + method: "", + url: "", + }, + response: { + body: "\n /remote.php/webdav/ Sat, 28 Dec 2019 18:31:47 GMT 5030985306 -3 "5e079f93da21b" HTTP/1.1 200 OK ", + contentType: "application/xml; charset=utf-8", + status: 207, + }, + }); + const lclient = new client_1.Client(new client_1.FakeServer(entries)); + try { + yield lclient.getQuota(); + (0, chai_1.expect)(true, "expect an exception").to.be.equal(false); + } + catch (e) { + (0, chai_1.expect)(e.message, "expect an exception").to.be.equal("The mulitstatus response must have a href"); + } + })); + it("68 multistatus response without prostat", () => __awaiter(this, void 0, void 0, function* () { + const entries = []; + entries.push({ + request: { + description: "", + method: "", + url: "", + }, + response: { + body: "\n /remote.php/webdav/ Sat, 28 Dec 2019 18:31:47 GMT 5030985306 -3 "5e079f93da21b" HTTP/1.1 200 OK ", + contentType: "application/xml; charset=utf-8", + status: 207, + }, + }); + const lclient = new client_1.Client(new client_1.FakeServer(entries)); + try { + yield lclient.getQuota(); + (0, chai_1.expect)(true, "expect an exception").to.be.equal(false); + } + catch (e) { + (0, chai_1.expect)(e.message, "expect an exception").to.be.equal(`The mulitstatus response must have a "propstat" container`); + } + })); + it("69 multistatus response without prostat status", () => __awaiter(this, void 0, void 0, function* () { + const entries = []; + entries.push({ + request: { + description: "", + method: "", + url: "", + }, + response: { + body: "\n /remote.php/webdav/ Sat, 28 Dec 2019 18:31:47 GMT 5030985306 -3 "5e079f93da21b" HTTP/1.1 200 OK ", + contentType: "application/xml; charset=utf-8", + status: 207, + }, + }); + const lclient = new client_1.Client(new client_1.FakeServer(entries)); + try { + yield lclient.getQuota(); + (0, chai_1.expect)(true, "expect an exception").to.be.equal(false); + } + catch (e) { + (0, chai_1.expect)(e.message, "expect an exception").to.be.equal(`The propstat must have a "status"`); + } + })); + it("70 multistatus response without prostat property", () => __awaiter(this, void 0, void 0, function* () { + const entries = []; + entries.push({ + request: { + description: "", + method: "", + url: "", + }, + response: { + body: "\n /remote.php/webdav/ Sat, 28 Dec 2019 18:31:47 GMT 5030985306 -3 "5e079f93da21b" HTTP/1.1 200 OK ", + contentType: "application/xml; charset=utf-8", + status: 207, + }, + }); + const lclient = new client_1.Client(new client_1.FakeServer(entries)); + try { + yield lclient.getQuota(); + (0, chai_1.expect)(true, "expect an exception").to.be.equal(false); + } + catch (e) { + (0, chai_1.expect)(e.message, "expect an exception").to.be.equal(`The propstat must have a "prop"`); + } + })); + it("71 propfind without properties", () => __awaiter(this, void 0, void 0, function* () { + const entries = []; + entries.push({ + request: { + description: "", + method: "", + url: "", + }, + response: { + // body has no properties + body: "\n /remote.php/webdav/ Sat, 28 Dec 2019 18:31:47 GMT 5030985306 -3 "5e079f93da21b" NOHTTP/1.1 200 OK ", + contentType: "application/xml; charset=utf-8", + status: 207, + }, + }); + const lclient = new client_1.Client(new client_1.FakeServer(entries)); + try { + yield lclient.getFolder("ThisFolderDoesNotExists"); + // returns null + } + catch (e) { + (0, chai_1.expect)(e.message, "expect no exception").to.be.equal(`no exception expected"`); + } + })); + it("72 create file fails", () => __awaiter(this, void 0, void 0, function* () { + const entries = []; + // save content + entries.push({ + request: { + description: "File save content", + method: "PUT", + url: "/remote.php/webdav/file72.txt", + }, + response: { + contentType: "text/html; charset=UTF-8", + status: 201, + }, + }); + // file not available + entries.push({ + request: { + description: "File/Folder get details", + method: "PROPFIND", + url: "/remote.php/webdav/file72.txt", + }, + response: { + contentType: "text/html; charset=UTF-8", + status: 404, + }, + }); + let errorOccurred; + const fileName = "/file72.txt"; + let file = null; + const lclient = new client_1.Client(new client_1.FakeServer(entries)); + try { + file = yield lclient.createFile(fileName, Buffer.from("this is a test text")); + errorOccurred = false; + } + catch (e) { + errorOccurred = true; + (0, chai_1.expect)(e.message, "expect no exception").to.be.equal(`Error creating file, file name "/file72.txt"`); + } + // expect(errorOccurred, "expect no exception").to.be.equal(false); + })); + it("73 access propertries of a deleted file should fail", () => __awaiter(this, void 0, void 0, function* () { + const dirName = "/test/fileDelete73"; + const fileName1 = "file1.txt"; + const baseDir = yield client.createFolder(dirName); + yield baseDir.createFile(fileName1, Buffer.from("File 1")); + const file = yield client.getFile(dirName + "/" + fileName1); + (0, chai_1.expect)(file, "expect file to a object").to.be.a("object").that.is.instanceOf(client_1.File); + yield file.delete(); + const arr = []; + try { + // tslint:disable-next-line:no-unused-expression + arr.push(file.baseName); + // tslint:disable-next-line:no-empty + } + catch (e) { } + try { + // tslint:disable-next-line:no-unused-expression + arr.push(file.name); + // tslint:disable-next-line:no-empty + } + catch (e) { } + try { + // tslint:disable-next-line:no-unused-expression + arr.push(file.id); + // tslint:disable-next-line:no-empty + } + catch (e) { } + try { + // tslint:disable-next-line:no-unused-expression + arr.push(file.lastmod); + // tslint:disable-next-line:no-empty + } + catch (e) { } + try { + // tslint:disable-next-line:no-unused-expression + arr.push(file.mime); + // tslint:disable-next-line:no-empty + } + catch (e) { } + try { + // tslint:disable-next-line:no-unused-expression + arr.push(file.size); + // tslint:disable-next-line:no-empty + } + catch (e) { } + (0, chai_1.expect)(arr.length, "expect that no property is accessible").to.be.equal(0); + yield baseDir.delete(); + })); + it("74 access propertries of a deleted folder should fail", () => __awaiter(this, void 0, void 0, function* () { + const dirName = "/test/fileDelete74"; + const baseDir = yield client.createFolder(dirName); + yield baseDir.delete(); + const arr = []; + try { + // tslint:disable-next-line:no-unused-expression + arr.push(baseDir.baseName); + // tslint:disable-next-line:no-empty + } + catch (e) { } + try { + // tslint:disable-next-line:no-unused-expression + arr.push(baseDir.name); + // tslint:disable-next-line:no-empty + } + catch (e) { } + try { + // tslint:disable-next-line:no-unused-expression + arr.push(baseDir.id); + // tslint:disable-next-line:no-empty + } + catch (e) { } + try { + // tslint:disable-next-line:no-unused-expression + arr.push(baseDir.lastmod); + // tslint:disable-next-line:no-empty + } + catch (e) { } + (0, chai_1.expect)(arr.length, "expect that no property is accessible").to.be.equal(0); + yield baseDir.delete(); + })); + it("75 move file fails", () => __awaiter(this, void 0, void 0, function* () { + const entries = []; + entries.push({ + request: { + description: "File move", + method: "MOVE", + url: "/remote.php/webdav/test/renameFile75/sourceFile.txt", + }, + response: { + contentType: "text/html; charset=UTF-8", + status: 500, + }, + }); + const lclient = new client_1.Client(new client_1.FakeServer(entries)); + let q; + try { + q = yield lclient.moveFile("from", "to"); + } + catch (e) { + (0, chai_1.expect)(true, "expect an exception").to.be.equal(true); + } + (0, chai_1.expect)(q).to.be.equal(undefined); + })); + it("76 create client with url ending with slash", () => __awaiter(this, void 0, void 0, function* () { + const restore = (0, mocked_env_1.default)({ + NEXTCLOUD_URL: "https://server.com/", + NEXTCLOUD_PASSWORD: "SomePassword", + NEXTCLOUD_USERNAME: "SomeUser", + }); + let error = null; + let o; + try { + // tslint:disable-next-line:no-unused-expression + const c = new client_1.Client(); + o = JSON.parse(JSON.stringify(c)); + // console.log(o); + } + catch (e) { + error = e; + } + finally { + restore(); + } + (0, chai_1.expect)(error).to.be.equal(null); + (0, chai_1.expect)(o.nextcloudOrigin).to.be.equal("https://server.com"); + })); + it("77 create client with url not ending with slash", () => __awaiter(this, void 0, void 0, function* () { + const restore = (0, mocked_env_1.default)({ + NEXTCLOUD_URL: "https://server.com", + NEXTCLOUD_PASSWORD: "SomePassword", + NEXTCLOUD_USERNAME: "SomeUser", + }); + let error = null; + let o; + try { + // tslint:disable-next-line:no-unused-expression + const c = new client_1.Client(); + o = JSON.parse(JSON.stringify(c)); + // console.log(o); + } + catch (e) { + error = e; + } + finally { + restore(); + } + (0, chai_1.expect)(error).to.be.equal(null); + (0, chai_1.expect)(o.nextcloudOrigin).to.be.equal("https://server.com"); + })); + it("78 create client with WebDAV url not ending with slash", () => __awaiter(this, void 0, void 0, function* () { + const restore = (0, mocked_env_1.default)({ + NEXTCLOUD_URL: "https://server.com/remote.php/webdav", + NEXTCLOUD_PASSWORD: "SomePassword", + NEXTCLOUD_USERNAME: "SomeUser", + }); + let error = null; + let o; + try { + // tslint:disable-next-line:no-unused-expression + const c = new client_1.Client(); + o = JSON.parse(JSON.stringify(c)); + // console.log(o); + } + catch (e) { + error = e; + } + finally { + restore(); + } + (0, chai_1.expect)(error).to.be.equal(null); + (0, chai_1.expect)(o.nextcloudOrigin).to.be.equal("https://server.com"); + })); + it("79 create client with WebDAV url ending with slash", () => __awaiter(this, void 0, void 0, function* () { + const restore = (0, mocked_env_1.default)({ + NEXTCLOUD_URL: "https://server.com/remote.php/webdav/", + NEXTCLOUD_PASSWORD: "SomePassword", + NEXTCLOUD_USERNAME: "SomeUser", + }); + let error = null; + let o; + try { + // tslint:disable-next-line:no-unused-expression + const c = new client_1.Client(); + o = JSON.parse(JSON.stringify(c)); + // console.log(o); + } + catch (e) { + error = e; + } + finally { + restore(); + } + (0, chai_1.expect)(error).to.be.equal(null); + (0, chai_1.expect)(o.nextcloudOrigin).to.be.equal("https://server.com"); + })); + it("99 delete folder", () => __awaiter(this, void 0, void 0, function* () { + const dirName = "/test"; + let baseDir = yield client.createFolder(dirName); + if (baseDir) { + yield baseDir.delete(); + } + baseDir = yield client.getFolder(dirName); + (0, chai_1.expect)(baseDir, "expect folder to be null").to.be.equal(null); + })); +}); diff --git a/src/test/02.tag.test.d.ts b/src/test/02.tag.test.d.ts new file mode 100644 index 00000000..87ad0c95 --- /dev/null +++ b/src/test/02.tag.test.d.ts @@ -0,0 +1 @@ +import "mocha"; diff --git a/src/test/02.tag.test.js b/src/test/02.tag.test.js new file mode 100644 index 00000000..043e0057 --- /dev/null +++ b/src/test/02.tag.test.js @@ -0,0 +1,360 @@ +"use strict"; +var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { + function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } + return new (P || (P = Promise))(function (resolve, reject) { + function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } + function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } + function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } + step((generator = generator.apply(thisArg, _arguments || [])).next()); + }); +}; +Object.defineProperty(exports, "__esModule", { value: true }); +const chai_1 = require("chai"); +// if you used the '@types/mocha' method to install mocha type definitions, uncomment the following line +require("mocha"); +const client_1 = require("../client"); +const testUtils_1 = require("./testUtils"); +let client; +// tslint:disable-next-line:only-arrow-functions +// tslint:disable-next-line:space-before-function-paren +describe("02-NEXCLOUD-NODE-CLIENT-TAG", function () { + this.timeout(1 * 60 * 1000); + // tslint:disable-next-line:space-before-function-paren + beforeEach(function () { + return __awaiter(this, void 0, void 0, function* () { + if (this.currentTest && this.currentTest.parent) { + client = yield (0, testUtils_1.getNextcloudClient)(this.currentTest.parent.title + "/" + this.currentTest.title); + } + }); + }); + it("01 get tags", () => __awaiter(this, void 0, void 0, function* () { + const tags = yield client.getTags(); + for (const x of tags) { + // tslint:disable-next-line:no-console + // console.log("--- " + x); + } + (0, chai_1.expect)(tags, "expect tags to be an array").to.be.a("array"); + })); + it("02 create tag", () => __awaiter(this, void 0, void 0, function* () { + const tagName = "Tag1"; + const tag = yield client.createTag(tagName); + (0, chai_1.expect)(tag, "expect tag to be an object").to.be.a("object"); + (0, chai_1.expect)(tag.name).to.be.equal(tagName); + // await client.deleteTag("/remote.php/dav/systemtags/11"); + })); + it("03 delete tag", () => __awaiter(this, void 0, void 0, function* () { + const tagName = "Tag-to-be-deleted"; + const tag = yield client.createTag(tagName); + (0, chai_1.expect)(tag, "expect tag to be an object").to.be.a("object"); + (0, chai_1.expect)(tag.name).to.be.equal(tagName); + yield tag.delete(); + const deletedTag = yield client.getTagByName(tagName); + (0, chai_1.expect)(deletedTag).to.be.equal(null); + })); + it("04 get tag by name", () => __awaiter(this, void 0, void 0, function* () { + const tagName = "get-Tag-by-name"; + const tag = yield client.createTag(tagName); + (0, chai_1.expect)(tag, "expect tag to be an object").to.be.a("object"); + (0, chai_1.expect)(tag.name).to.be.equal(tagName); + const getTag = yield client.getTagByName(tagName); + (0, chai_1.expect)(getTag).not.to.be.equal(null); + (0, chai_1.expect)(getTag.name).to.be.equal(tagName); + if (getTag) { + const str = getTag.toString(); + (0, chai_1.expect)(str).to.be.a("string"); + } + yield tag.delete(); + })); + it("05 get tag by id", () => __awaiter(this, void 0, void 0, function* () { + const tagName = "get-Tag-by-id"; + const tag = yield client.createTag(tagName); + (0, chai_1.expect)(tag, "expect tag to be an object").to.be.a("object"); + (0, chai_1.expect)(tag.name).to.be.equal(tagName); + const getTag = yield client.getTagById(tag.id); + (0, chai_1.expect)(getTag).not.to.be.equal(null); + (0, chai_1.expect)(getTag.name).to.be.equal(tagName); + const getTag2 = yield client.getTagById(11223344); + (0, chai_1.expect)(getTag2).to.be.equal(null); + yield tag.delete(); + })); + it("06 add tag to file", () => __awaiter(this, void 0, void 0, function* () { + const dirName = "/test/fileTagging"; + const fileName1 = "file1.txt"; + const baseDir = yield client.createFolder(dirName); + yield baseDir.createFile(fileName1, Buffer.from("File 1")); + const file = yield client.getFile(dirName + "/" + fileName1); + (0, chai_1.expect)(file, "expect file to a object").to.be.a("object").that.is.instanceOf(client_1.File); + (0, chai_1.expect)(file, "expect file not to be null").to.be.not.equal(null); + const id = yield file.id; + (0, chai_1.expect)(id, "expect id to be a number").to.be.a("number"); + (0, chai_1.expect)(id, "expect id to be not -1").to.be.not.equal(-1); + try { + yield file.addTag(`tag-61`); + yield file.addTag(`tag-62`); + } + catch (e) { + (0, chai_1.expect)(true, "we do not expect an exception adding tags").to.be.equal(false); + } + let tag = yield client.getTagByName(`tag-61`); + if (tag) { + yield tag.delete(); + } + tag = yield client.getTagByName(`tag-62`); + if (tag) { + yield tag.delete(); + } + yield baseDir.delete(); + })); + it("07 get tags of file", () => __awaiter(this, void 0, void 0, function* () { + const dirName = "/test/fileTagging"; + const fileName1 = "fileWith3Tags1.txt"; + const baseDir = yield client.createFolder(dirName); + yield baseDir.createFile(fileName1, Buffer.from("File 1")); + const file = yield client.getFile(dirName + "/" + fileName1); + (0, chai_1.expect)(file, "expect file to a object").to.be.a("object").that.is.instanceOf(client_1.File); + (0, chai_1.expect)(file, "expect file not to be null").to.be.not.equal(null); + const id = yield file.id; + (0, chai_1.expect)(id, "expect id to be a number").to.be.a("number"); + (0, chai_1.expect)(id, "expect id to be not -1").to.be.not.equal(-1); + const tagsCreated = [`tag-71`, `tag-72`, `tag-73`]; + try { + for (const tagName of tagsCreated) { + yield file.addTag(tagName); + } + } + catch (e) { + (0, chai_1.expect)(true, "we do not expect an exception adding tags").to.be.equal(false); + } + const tagNames = yield file.getTags(); + tagNames.sort(); + tagsCreated.sort(); + // expect(tagNames, "Tag has value").to.be.equal(tagsCreated); + (0, chai_1.expect)(tagNames[0], "Tag has value").to.be.equal(tagsCreated[0]); + (0, chai_1.expect)(tagNames[1], "Tag has value").to.be.equal(tagsCreated[1]); + (0, chai_1.expect)(tagNames[2], "Tag has value").to.be.equal(tagsCreated[2]); + yield file.delete(); + let tag = yield client.getTagByName(tagsCreated[0]); + if (tag) { + yield tag.delete(); + } + tag = yield client.getTagByName(tagsCreated[1]); + if (tag) { + yield tag.delete(); + } + tag = yield client.getTagByName(tagsCreated[2]); + if (tag) { + yield tag.delete(); + } + yield baseDir.delete(); + })); + it("08 folder tags", () => __awaiter(this, void 0, void 0, function* () { + const dirName = "/test/folderTagging"; + const folder = yield client.createFolder(dirName); + const tagsCreated = [`tag-81`, `tag-82`, `tag-83`]; + try { + for (const tagName of tagsCreated) { + yield folder.addTag(tagName); + } + } + catch (e) { + (0, chai_1.expect)(true, "we do not expect an exception adding tags").to.be.equal(false); + } + const tagNames = yield folder.getTags(); + tagNames.sort(); + tagsCreated.sort(); + // expect(tagNames, "Tag has value").to.be.equal(tagsCreated); + (0, chai_1.expect)(tagNames[0], "Tag has value").to.be.equal(tagsCreated[0]); + (0, chai_1.expect)(tagNames[1], "Tag has value").to.be.equal(tagsCreated[1]); + (0, chai_1.expect)(tagNames[2], "Tag has value").to.be.equal(tagsCreated[2]); + // remove a tag + yield folder.removeTag(tagNames[0]); + const tagNames2 = yield folder.getTags(); + (0, chai_1.expect)(tagNames2.length).to.be.equal(2); + yield folder.delete(); + let tag = yield client.getTagByName(tagsCreated[0]); + if (tag) { + yield tag.delete(); + } + tag = yield client.getTagByName(tagsCreated[1]); + if (tag) { + yield tag.delete(); + } + tag = yield client.getTagByName(tagsCreated[2]); + if (tag) { + yield tag.delete(); + } + })); + it("09 remove tag of file", () => __awaiter(this, void 0, void 0, function* () { + const dirName = "/test/fileTagging"; + const fileName1 = "removeTagOfFile.txt"; + const baseDir = yield client.createFolder(dirName); + yield baseDir.createFile(fileName1, Buffer.from("File 1")); + const file = yield client.getFile(dirName + "/" + fileName1); + (0, chai_1.expect)(file, "expect file to a object").to.be.a("object").that.is.instanceOf(client_1.File); + (0, chai_1.expect)(file, "expect file not to be null").to.be.not.equal(null); + const id = yield file.id; + (0, chai_1.expect)(id, "expect id to be a number").to.be.a("number"); + (0, chai_1.expect)(id, "expect id to be not -1").to.be.not.equal(-1); + const tagsCreated = [`tag-91`, `tag-92`, `tag-93`]; + try { + for (const tagName of tagsCreated) { + yield file.addTag(tagName); + } + } + catch (e) { + (0, chai_1.expect)(true, "we do not expect an exception adding tags").to.be.equal(false); + } + tagsCreated.sort(); + yield file.removeTag(tagsCreated[0]); + const tagNames = yield file.getTags(); + (0, chai_1.expect)(tagNames.length, "only two tags should exist").to.be.equal(2); + yield file.delete(); + let tag = yield client.getTagByName(tagsCreated[0]); + if (tag) { + yield tag.delete(); + } + tag = yield client.getTagByName(tagsCreated[1]); + if (tag) { + yield tag.delete(); + } + tag = yield client.getTagByName(tagsCreated[2]); + if (tag) { + yield tag.delete(); + } + yield baseDir.delete(); + })); + it("10 create a tag twice", () => __awaiter(this, void 0, void 0, function* () { + const tagName = "Tag10"; + const tag = yield client.createTag(tagName); + (0, chai_1.expect)(tag, "expect tag to be an object").to.be.a("object"); + (0, chai_1.expect)(tag.name).to.be.equal(tagName); + // the second tag should be like the first tag + const tag2 = yield client.createTag(tagName); + (0, chai_1.expect)(tag2, "expect tag to be an object").to.be.a("object"); + (0, chai_1.expect)(tag2.name).to.be.equal(tagName); + yield tag.delete(); + yield tag2.delete(); + })); + it("11 remove non existing file tag should not cause an error", () => __awaiter(this, void 0, void 0, function* () { + const tagName = "Tag-non-existing"; + const dirName = "/test/fileTagging"; + const fileName1 = "fileWithoutTags.txt"; + const baseDir = yield client.createFolder(dirName); + const file1 = yield baseDir.createFile(fileName1, Buffer.from("File 1")); + (0, chai_1.expect)(file1, "Expect that the file cloud be created").not.to.be.equal(null); + if (file1) { + try { + // tslint:disable-next-line:no-unused-expression + yield file1.removeTag(tagName); + } + catch (e) { + (0, chai_1.expect)(false, "Expect no exception when removing a non existing tag from a file").to.be.equal(true); + } + finally { + yield file1.delete(); + } + } + })); + it("12 remove non existing folder tag should not cause an error", () => __awaiter(this, void 0, void 0, function* () { + const tagName = "Tag-non-existing"; + const dirName = "/test/folderTagging"; + const baseDir = yield client.createFolder(dirName); + try { + // tslint:disable-next-line:no-unused-expression + yield baseDir.removeTag(tagName); + } + catch (e) { + (0, chai_1.expect)(false, "Expect no exception when removing a non existing tag from a folder").to.be.equal(true); + } + finally { + yield baseDir.delete(); + } + })); + it("13 get tags of a new file and expect none", () => __awaiter(this, void 0, void 0, function* () { + const dirName = "/test/fileTagging"; + const fileName1 = "fileWithoutTags2.txt"; + const baseDir = yield client.createFolder(dirName); + const file1 = yield baseDir.createFile(fileName1, Buffer.from("File 1")); + (0, chai_1.expect)(file1, "Expect that the file cloud be created").not.to.be.equal(null); + if (file1) { + const tags = yield file1.getTags(); + (0, chai_1.expect)(tags.length, "Expect new file not to have any tags").to.be.equal(0); + yield file1.delete(); + } + })); + it("14 create tag returning no content location", () => __awaiter(this, void 0, void 0, function* () { + const entries = []; + entries.push({ + request: { + description: "Tags get", + method: "PROPFIND", + url: "/remote.php/dav/systemtags/", + }, + response: { + body: "\n/remote.php/dav/systemtags/HTTP/1.1 404 Not Found", + contentType: "application/xml; charset=utf-8", + status: 207, + }, + }); + entries.push({ + request: { + description: "Tag Create", + method: "POST", + url: "/remote.php/dav/systemtags/", + }, + response: { + contentType: "text/html; charset=UTF-8", + // no content location! + status: 201, + }, + }); + const lclient = new client_1.Client(new client_1.FakeServer(entries)); + const tagName = "tag-14"; + try { + const tag = yield lclient.createTag(tagName); + (0, chai_1.expect)(true, "expect an exception").to.be.equal(false); + } + catch (e) { + (0, chai_1.expect)(true, "expect an exception").to.be.equal(true); + } + })); + it("15 add tag to file permission fails", () => __awaiter(this, void 0, void 0, function* () { + const entries = []; + entries.push({ + request: { + description: "Tags get", + method: "PROPFIND", + url: "/remote.php/dav/systemtags/", + }, + response: { + body: "\n/remote.php/dav/systemtags/HTTP/1.1 404 Not Found/remote.php/dav/systemtags/644644tag-15truefalsefalseHTTP/1.1 200 OK", + contentType: "application/xml; charset=utf-8", + status: 207, + }, + }); + const lclient = new client_1.Client(new client_1.FakeServer(entries)); + const tagName = "tag-15"; + try { + yield lclient.addTagToFile(123, tagName); + } + catch (e) { + (0, chai_1.expect)(e.message, "expect no exception").to.be.equal('Error: No permission to assign tag "tag-15" to file. Tag is not assignable'); + } + })); + it("98 delete all tags", () => __awaiter(this, void 0, void 0, function* () { + const tagName = "TagToBeDelete"; + yield client.createTag(tagName); + yield client.deleteAllTags(); + const tag = yield client.getTagByName(tagName); + (0, chai_1.expect)(tag).to.be.equal(null); + })); + it("99 delete directory", () => __awaiter(this, void 0, void 0, function* () { + const dirName = "/test"; + let baseDir = yield client.createFolder(dirName); + if (baseDir) { + yield baseDir.delete(); + } + baseDir = yield client.getFolder(dirName); + (0, chai_1.expect)(baseDir, "expect directory to be null").to.be.equal(null); + })); +}); diff --git a/src/test/03.comment.test.d.ts b/src/test/03.comment.test.d.ts new file mode 100644 index 00000000..87ad0c95 --- /dev/null +++ b/src/test/03.comment.test.d.ts @@ -0,0 +1 @@ +import "mocha"; diff --git a/src/test/03.comment.test.js b/src/test/03.comment.test.js new file mode 100644 index 00000000..94971439 --- /dev/null +++ b/src/test/03.comment.test.js @@ -0,0 +1,111 @@ +"use strict"; +var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { + function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } + return new (P || (P = Promise))(function (resolve, reject) { + function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } + function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } + function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } + step((generator = generator.apply(thisArg, _arguments || [])).next()); + }); +}; +Object.defineProperty(exports, "__esModule", { value: true }); +const chai_1 = require("chai"); +// if you used the '@types/mocha' method to install mocha type definitions, uncomment the following line +require("mocha"); +const client_1 = require("../client"); +const testUtils_1 = require("./testUtils"); +let client; +// tslint:disable-next-line:only-arrow-functions +// tslint:disable-next-line:space-before-function-paren +describe("03-NEXCLOUD-NODE-CLIENT-COMMENT", function () { + this.timeout(1 * 60 * 1000); + // tslint:disable-next-line:space-before-function-paren + beforeEach(function () { + return __awaiter(this, void 0, void 0, function* () { + if (this.currentTest && this.currentTest.parent) { + client = yield (0, testUtils_1.getNextcloudClient)(this.currentTest.parent.title + "/" + this.currentTest.title); + } + }); + }); + it("01 add comment to file", () => __awaiter(this, void 0, void 0, function* () { + let errorOccurred; + const fileName = "/test/comments/fileComments.txt"; + let file = null; + try { + file = yield client.createFile(fileName, Buffer.from("file with comments")); + errorOccurred = false; + } + catch (e) { + errorOccurred = true; + } + (0, chai_1.expect)(errorOccurred, "expect no exception").to.be.equal(false); + (0, chai_1.expect)(file, "expect file to a object").to.be.a("object").that.is.instanceOf(client_1.File); + if (file) { + try { + yield file.addComment("C1"); + yield file.addComment("C2"); + yield file.addComment("C3"); + yield file.addComment("C4"); + } + catch (e) { + (0, chai_1.expect)(e.message, "expect no exception").to.be.equal(""); + } + try { + const comments = yield file.getComments(1, 1); + (0, chai_1.expect)(comments[0]).to.be.equal("C3"); + } + catch (e) { + (0, chai_1.expect)(e.message, "expect no exception").to.be.equal(""); + } + } + })); + it("02 add comment to folder", () => __awaiter(this, void 0, void 0, function* () { + let errorOccurred; + const folderName = "/test/folder/comments"; + let folder = null; + try { + folder = yield client.createFolder(folderName); + errorOccurred = false; + } + catch (e) { + errorOccurred = true; + } + (0, chai_1.expect)(errorOccurred, "expect no exception").to.be.equal(false); + (0, chai_1.expect)(folder, "expect file to a object").to.be.a("object").that.is.instanceOf(client_1.Folder); + if (folder) { + try { + yield folder.addComment("C1"); + yield folder.addComment("C2"); + yield folder.addComment("C3"); + yield folder.addComment("C4"); + } + catch (e) { + (0, chai_1.expect)(e.message, "expect no exception").to.be.equal(""); + } + try { + const comments = yield folder.getComments(1, 1); + (0, chai_1.expect)(comments[0]).to.be.equal("C3"); + } + catch (e) { + (0, chai_1.expect)(e.message, "expect no exception").to.be.equal(""); + } + try { + const comments = yield folder.getComments(); + (0, chai_1.expect)(comments[0]).to.be.equal("C4"); + } + catch (e) { + (0, chai_1.expect)(e.message, "expect no exception").to.be.equal(""); + } + yield folder.delete(); + } + })); + it("99 delete directory", () => __awaiter(this, void 0, void 0, function* () { + const dirName = "/test"; + let baseDir = yield client.createFolder(dirName); + if (baseDir) { + yield baseDir.delete(); + } + baseDir = yield client.getFolder(dirName); + (0, chai_1.expect)(baseDir, "expect directory to be null").to.be.equal(null); + })); +}); diff --git a/src/test/04.activity.test.d.ts b/src/test/04.activity.test.d.ts new file mode 100644 index 00000000..e69de29b diff --git a/src/test/04.activity.test.js b/src/test/04.activity.test.js new file mode 100644 index 00000000..696eee5e --- /dev/null +++ b/src/test/04.activity.test.js @@ -0,0 +1,44 @@ +"use strict"; +/* +import { expect } from "chai"; +// if you used the '@types/mocha' method to install mocha type definitions, uncomment the following line +import "mocha"; +import { +NCClient, +} from "../ncClient"; + +import { debug, getNextcloudClient } from "./testUtils"; + +let client: NCClient; + +// tslint:disable-next-line:only-arrow-functions +describe("04-NEXCLOUD-NODE-CLIENT-ACTIVITY", function () { + + this.timeout(1 * 60 * 1000); + + beforeEach(async function() { + if (this.currentTest && this.currentTest.parent) { + client = await getNextcloudClient(this.currentTest.parent.title + "/" + this.currentTest.title); + } + }); + + it.skip("01 get activity", async () => { + + const activities = client.getActivities(); + expect(activities, "expect no exception").to.be.equal(false); + + }); + + it("99 delete directory", async () => { + + const dirName = "/test"; + + let baseDir: NCFolder | null = await client.createFolder(dirName); + if (baseDir) { + await baseDir.delete(); + } + baseDir = await client.getFolder(dirName); + expect(baseDir, "expect directory to be null").to.be.equal(null); + }); +}); + */ diff --git a/src/test/05.readme.test.d.ts b/src/test/05.readme.test.d.ts new file mode 100644 index 00000000..87ad0c95 --- /dev/null +++ b/src/test/05.readme.test.d.ts @@ -0,0 +1 @@ +import "mocha"; diff --git a/src/test/05.readme.test.js b/src/test/05.readme.test.js new file mode 100644 index 00000000..d8494a86 --- /dev/null +++ b/src/test/05.readme.test.js @@ -0,0 +1,39 @@ +"use strict"; +var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { + function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } + return new (P || (P = Promise))(function (resolve, reject) { + function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } + function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } + function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } + step((generator = generator.apply(thisArg, _arguments || [])).next()); + }); +}; +var __importDefault = (this && this.__importDefault) || function (mod) { + return (mod && mod.__esModule) ? mod : { "default": mod }; +}; +Object.defineProperty(exports, "__esModule", { value: true }); +// if you used the '@types/mocha' method to install mocha type definitions, uncomment the following line +require("mocha"); +const client_1 = require("../client"); +const server_1 = __importDefault(require("../server")); +// tslint:disable-next-line:only-arrow-functions +// tslint:disable-next-line:space-before-function-paren +describe("05-NEXCLOUD-NODE-CLIENT-README", function () { + this.timeout(1 * 60 * 1000); + it.skip("01 readme", () => __awaiter(this, void 0, void 0, function* () { + // service instance name from VCAP_SERVICES environment - "user-provided" section + try { + const server = new server_1.default({ url: "http:/test.test", basicAuth: { username: "user", password: "password" } }); + const client = new client_1.Client(server); + const folder = yield client.createFolder("test"); + const file = yield folder.createFile("myFile.txt", Buffer.from("My file content")); + yield file.addTag("MyTag"); + yield file.addTag("myComment"); + yield folder.delete(); + const content = yield file.getContent(); + } + catch (e) { + // some error handling + } + })); +}); diff --git a/src/test/05.requestResponseLog.test.d.ts b/src/test/05.requestResponseLog.test.d.ts new file mode 100644 index 00000000..87ad0c95 --- /dev/null +++ b/src/test/05.requestResponseLog.test.d.ts @@ -0,0 +1 @@ +import "mocha"; diff --git a/src/test/05.requestResponseLog.test.js b/src/test/05.requestResponseLog.test.js new file mode 100644 index 00000000..71515741 --- /dev/null +++ b/src/test/05.requestResponseLog.test.js @@ -0,0 +1,239 @@ +"use strict"; +var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) { + if (k2 === undefined) k2 = k; + Object.defineProperty(o, k2, { enumerable: true, get: function() { return m[k]; } }); +}) : (function(o, m, k, k2) { + if (k2 === undefined) k2 = k; + o[k2] = m[k]; +})); +var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) { + Object.defineProperty(o, "default", { enumerable: true, value: v }); +}) : function(o, v) { + o["default"] = v; +}); +var __importStar = (this && this.__importStar) || function (mod) { + if (mod && mod.__esModule) return mod; + var result = {}; + if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k); + __setModuleDefault(result, mod); + return result; +}; +var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { + function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } + return new (P || (P = Promise))(function (resolve, reject) { + function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } + function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } + function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } + step((generator = generator.apply(thisArg, _arguments || [])).next()); + }); +}; +var __importDefault = (this && this.__importDefault) || function (mod) { + return (mod && mod.__esModule) ? mod : { "default": mod }; +}; +Object.defineProperty(exports, "__esModule", { value: true }); +const chai_1 = require("chai"); +const fs_1 = require("fs"); +require("mocha"); +const requestResponseLog_1 = __importDefault(require("../requestResponseLog")); +const requestResponseLogEntry_1 = __importStar(require("../requestResponseLogEntry")); +// tslint:disable-next-line:only-arrow-functions +// tslint:disable-next-line:space-before-function-paren +describe("05-NEXCLOUD-NODE-CLIENT-REQUEST-RESPONSE-LOG", function () { + this.timeout(1 * 60 * 1000); + const baseDirName = "tmp/testresults/"; + const testContextName = "requestResponseLogTest/d1/d2"; + afterEach(() => __awaiter(this, void 0, void 0, function* () { + try { + yield fs_1.promises.rmdir(baseDirName, { recursive: true }); + // tslint:disable-next-line:no-empty + } + catch (e) { } + })); + it("01 get request response log instance", () => __awaiter(this, void 0, void 0, function* () { + const rrLog = requestResponseLog_1.default.getInstance(); + (0, chai_1.expect)(rrLog, "expect request response log to a object").to.be.a("object").that.is.instanceOf(requestResponseLog_1.default); + // get the recorder a second time + const rrLog2 = requestResponseLog_1.default.getInstance(); + (0, chai_1.expect)(rrLog2, "expect request response log to a object").to.be.a("object").that.is.instanceOf(requestResponseLog_1.default); + requestResponseLog_1.default.deleteInstance(); + })); + it("02 set request response log context", () => __awaiter(this, void 0, void 0, function* () { + const rrLog = requestResponseLog_1.default.getInstance(); + rrLog.baseDirectory = baseDirName; + try { + yield rrLog.setContext(testContextName); + (0, chai_1.expect)(true, "expect no exception").to.be.equal(true); + } + catch (e) { + (0, chai_1.expect)(e.message, "expect no exception").to.be.equal("no exception"); + } + requestResponseLog_1.default.deleteInstance(); + })); + it("03 request response logging", () => __awaiter(this, void 0, void 0, function* () { + const rrLog = requestResponseLog_1.default.getInstance(); + rrLog.baseDirectory = baseDirName; + const requestLogEntry = new requestResponseLogEntry_1.RequestLogEntry("https://my.url.com", "method", "This is a description", "This is a xml request body"); + const responseLogEntry = new requestResponseLogEntry_1.ResponseLogEntry(200, "This is a xml response body", "application/xml; charset=utf-8", "location header"); + try { + yield rrLog.setContext(testContextName); + (0, chai_1.expect)(true, "expect no exception").to.be.equal(true); + } + catch (e) { + (0, chai_1.expect)(e.message, "expect no exception").to.be.equal("no exception"); + } + try { + yield rrLog.addEntry(new requestResponseLogEntry_1.default(requestLogEntry, responseLogEntry)); + } + catch (e) { + (0, chai_1.expect)(e.message, "expect no exception").to.be.equal("expect no exception"); + } + try { + yield rrLog.addEntry(new requestResponseLogEntry_1.default(requestLogEntry, responseLogEntry)); + } + catch (e) { + (0, chai_1.expect)(e.message, "expect no exception").to.be.equal("expect no exception"); + } + const rrLogEntries = yield rrLog.getEntries(); + (0, chai_1.expect)(rrLogEntries).to.be.an("Array"); + (0, chai_1.expect)(rrLogEntries.length).to.be.equal(2); + requestResponseLog_1.default.deleteInstance(); + })); + it("04 request response logging without context", () => __awaiter(this, void 0, void 0, function* () { + const rrLog = requestResponseLog_1.default.getInstance(); + rrLog.baseDirectory = baseDirName; + const requestLogEntry = new requestResponseLogEntry_1.RequestLogEntry("https://my.url.com", "method", "This is a description", "test request body"); + const responseLogEntry = new requestResponseLogEntry_1.ResponseLogEntry(200, "some response text", "content type", "location header"); + try { + yield rrLog.addEntry(new requestResponseLogEntry_1.default(requestLogEntry, responseLogEntry)); + (0, chai_1.expect)(true, "expect an exception when adding an entry without context").to.be.equal(false); + } + catch (e) { + (0, chai_1.expect)(e.message, "expect exception").to.be.equal("Error while recording, context not set"); + } + try { + const rrLogEntries = yield rrLog.getEntries(); + (0, chai_1.expect)(true, "expect an exception when getting the entries without context").to.be.equal(false); + } + catch (e) { + (0, chai_1.expect)(e.message, "expect exception").to.be.equal("Error while getting recording request, context not set"); + } + requestResponseLog_1.default.deleteInstance(); + })); + it("05 invalid xml body", () => __awaiter(this, void 0, void 0, function* () { + const rrLog = requestResponseLog_1.default.getInstance(); + rrLog.baseDirectory = baseDirName; + const requestLogEntry = new requestResponseLogEntry_1.RequestLogEntry("https://my.url.com", "method", "This is a description", "This is invalid xml request body"); + const responseLogEntry = new requestResponseLogEntry_1.ResponseLogEntry(200, "This is a xml response body", "application/xml; charset=utf-8", "location header"); + try { + yield rrLog.setContext(testContextName); + (0, chai_1.expect)(true, "expect no exception").to.be.equal(true); + } + catch (e) { + (0, chai_1.expect)(e.message, "expect no exception").to.be.equal("no exception"); + } + try { + yield rrLog.addEntry(new requestResponseLogEntry_1.default(requestLogEntry, responseLogEntry)); + } + catch (e) { + (0, chai_1.expect)(e.message, "expect no exception").to.be.equal("expect no exception"); + } + try { + yield rrLog.addEntry(new requestResponseLogEntry_1.default(requestLogEntry, responseLogEntry)); + } + catch (e) { + (0, chai_1.expect)(e.message, "expect no exception").to.be.equal("expect no exception"); + } + const rrLogEntries = yield rrLog.getEntries(); + (0, chai_1.expect)(rrLogEntries).to.be.an("Array"); + (0, chai_1.expect)(rrLogEntries.length).to.be.equal(2); + requestResponseLog_1.default.deleteInstance(); + })); + it("06 no body in request and response", () => __awaiter(this, void 0, void 0, function* () { + const rrLog = requestResponseLog_1.default.getInstance(); + rrLog.baseDirectory = baseDirName; + const requestLogEntry = new requestResponseLogEntry_1.RequestLogEntry("https://my.url.com", "method", "This is a description"); + const responseLogEntry = new requestResponseLogEntry_1.ResponseLogEntry(200, undefined, "application/xml; charset=utf-8", "location header"); + try { + yield rrLog.setContext(testContextName); + (0, chai_1.expect)(true, "expect no exception").to.be.equal(true); + } + catch (e) { + (0, chai_1.expect)(e.message, "expect no exception").to.be.equal("no exception"); + } + try { + yield rrLog.addEntry(new requestResponseLogEntry_1.default(requestLogEntry, responseLogEntry)); + } + catch (e) { + (0, chai_1.expect)(e.message, "expect no exception").to.be.equal("expect no exception"); + } + try { + yield rrLog.addEntry(new requestResponseLogEntry_1.default(requestLogEntry, responseLogEntry)); + } + catch (e) { + (0, chai_1.expect)(e.message, "expect no exception").to.be.equal("expect no exception"); + } + const rrLogEntries = yield rrLog.getEntries(); + (0, chai_1.expect)(rrLogEntries).to.be.an("Array"); + (0, chai_1.expect)(rrLogEntries.length).to.be.equal(2); + requestResponseLog_1.default.deleteInstance(); + })); + it("07 response content type not xml", () => __awaiter(this, void 0, void 0, function* () { + const rrLog = requestResponseLog_1.default.getInstance(); + rrLog.baseDirectory = baseDirName; + const requestLogEntry = new requestResponseLogEntry_1.RequestLogEntry("https://my.url.com", "method", "This is a description", "text request body"); + const responseLogEntry = new requestResponseLogEntry_1.ResponseLogEntry(200, "plain text body response", "text/plain", "location header"); + try { + yield rrLog.setContext(testContextName); + (0, chai_1.expect)(true, "expect no exception").to.be.equal(true); + } + catch (e) { + (0, chai_1.expect)(e.message, "expect no exception").to.be.equal("no exception"); + } + try { + yield rrLog.addEntry(new requestResponseLogEntry_1.default(requestLogEntry, responseLogEntry)); + } + catch (e) { + (0, chai_1.expect)(e.message, "expect no exception").to.be.equal("expect no exception"); + } + try { + yield rrLog.addEntry(new requestResponseLogEntry_1.default(requestLogEntry, responseLogEntry)); + } + catch (e) { + (0, chai_1.expect)(e.message, "expect no exception").to.be.equal("expect no exception"); + } + const rrLogEntries = yield rrLog.getEntries(); + (0, chai_1.expect)(rrLogEntries).to.be.an("Array"); + (0, chai_1.expect)(rrLogEntries.length).to.be.equal(2); + requestResponseLog_1.default.deleteInstance(); + })); + it("08 response content type json", () => __awaiter(this, void 0, void 0, function* () { + // add a json response to the json body + const rrLog = requestResponseLog_1.default.getInstance(); + rrLog.baseDirectory = baseDirName; + const requestLogEntry = new requestResponseLogEntry_1.RequestLogEntry("https://my.url.com", "method", "This is a description", "text request body"); + const responseLogEntry = new requestResponseLogEntry_1.ResponseLogEntry(200, "{\"jsonProperty\":42}", "application/json", "location header"); + try { + yield rrLog.setContext(testContextName); + (0, chai_1.expect)(true, "expect no exception").to.be.equal(true); + } + catch (e) { + (0, chai_1.expect)(e.message, "expect no exception").to.be.equal("no exception"); + } + try { + yield rrLog.addEntry(new requestResponseLogEntry_1.default(requestLogEntry, responseLogEntry)); + } + catch (e) { + (0, chai_1.expect)(e.message, "expect no exception").to.be.equal("expect no exception"); + } + const rrLogEntries = yield rrLog.getEntries(); + (0, chai_1.expect)(rrLogEntries).to.be.an("Array"); + (0, chai_1.expect)(rrLogEntries.length).to.be.equal(1); + (0, chai_1.expect)(rrLogEntries[0]).to.have.property("response"); + (0, chai_1.expect)(rrLogEntries[0].response).to.have.property("jsonBody"); + // console.log(rrLogEntries[0].response.jsonBody); + (0, chai_1.expect)(rrLogEntries[0].response.jsonBody).to.be.an("object"); + (0, chai_1.expect)(rrLogEntries[0].response.jsonBody).to.have.property("jsonProperty"); + (0, chai_1.expect)(rrLogEntries[0].response.jsonBody.jsonProperty).to.be.equal(42); + requestResponseLog_1.default.deleteInstance(); + })); +}); diff --git a/src/test/10.quota.test.d.ts b/src/test/10.quota.test.d.ts new file mode 100644 index 00000000..87ad0c95 --- /dev/null +++ b/src/test/10.quota.test.d.ts @@ -0,0 +1 @@ +import "mocha"; diff --git a/src/test/10.quota.test.js b/src/test/10.quota.test.js new file mode 100644 index 00000000..9b37ca2c --- /dev/null +++ b/src/test/10.quota.test.js @@ -0,0 +1,144 @@ +"use strict"; +var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { + function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } + return new (P || (P = Promise))(function (resolve, reject) { + function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } + function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } + function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } + step((generator = generator.apply(thisArg, _arguments || [])).next()); + }); +}; +var __importDefault = (this && this.__importDefault) || function (mod) { + return (mod && mod.__esModule) ? mod : { "default": mod }; +}; +Object.defineProperty(exports, "__esModule", { value: true }); +const chai_1 = require("chai"); +// if you used the '@types/mocha' method to install mocha type definitions, uncomment the following line +require("mocha"); +const client_1 = require("../client"); +const fakeServer_1 = __importDefault(require("../fakeServer")); +const testUtils_1 = require("./testUtils"); +let client; +// tslint:disable-next-line:only-arrow-functions +// tslint:disable-next-line:space-before-function-paren +describe("10-NEXCLOUD-NODE-CLIENT-QUOTA", function () { + // tslint:disable-next-line:space-before-function-paren + beforeEach(function () { + return __awaiter(this, void 0, void 0, function* () { + if (this.currentTest && this.currentTest.parent) { + client = yield (0, testUtils_1.getNextcloudClient)(this.currentTest.parent.title + "/" + this.currentTest.title); + } + }); + }); + this.timeout(1 * 60 * 1000); + it("01 get quota", () => __awaiter(this, void 0, void 0, function* () { + // console.log(JSON.stringify(this.tests[0].title, null, 4)); + let q; + try { + q = yield client.getQuota(); + } + catch (e) { + (0, chai_1.expect)(e, "expect no exception").to.be.equal(null); + } + (0, chai_1.expect)(q, "quota to have property used").to.have.property("used"); + (0, chai_1.expect)(q, "quota to have property available").to.have.property("available"); + })); + it("02 get quota with wrong xml response - no multistatus", () => __awaiter(this, void 0, void 0, function* () { + const entries = []; + entries.push({ + request: { + description: "Client get quota", + method: "PROPFIND", + url: "/remote.php/webdav/", + }, + response: { + body: "\n/remote.php/webdav/Tue, 17 Dec 2019 23:21:39 GMT4710416497-3"5df9630302376"HTTP/1.1 200 OK/remote.php/webdav/Donnerwetter.mdMon, 25 Nov 2019 07:56:30 GMT99"200fe307b08fcbedb5606bba4ba5354d"text/markdownHTTP/1.1 200 OKHTTP/1.1 404 Not Found/remote.php/webdav/SofortUpload/Sun, 15 Dec 2019 13:39:03 GMT476863281-3"5df637777669d"HTTP/1.1 200 OKHTTP/1.1 404 Not Found/remote.php/webdav/bestellung%20buch%20caro.pdfWed, 11 Dec 2019 07:55:54 GMT63320"cbb8508498c886ff53e4e0f378f9bc49"application/pdfHTTP/1.1 200 OKHTTP/1.1 404 Not Found/remote.php/webdav/katze/Tue, 03 Dec 2019 17:19:49 GMT4233489797-3"5de69935b3309"HTTP/1.1 200 OKHTTP/1.1 404 Not Found", + contentType: "application/xml; charset=utf-8", + status: 207, + }, + }); + const lclient = new client_1.Client(new fakeServer_1.default(entries)); + // console.log(JSON.stringify(this.tests[0].title, null, 4)); + let q; + try { + q = yield lclient.getQuota(); + (0, chai_1.expect)(true, "expect an exception").to.be.equal(false); + } + catch (e) { + (0, chai_1.expect)(true, "expect an exception").to.be.equal(true); + } + })); + it("03 get quota with wrong xml response - no quota-used-bytes", () => __awaiter(this, void 0, void 0, function* () { + const entries = []; + entries.push({ + request: { + description: "Client get quota", + method: "PROPFIND", + url: "/remote.php/webdav/", + }, + response: { + body: "\n/remote.php/webdav/Wed, 18 Dec 2019 07:11:01 GMT4710416532-3"5df9d1058812d"HTTP/1.1 200 OK/remote.php/webdav/Donnerwetter.mdMon, 25 Nov 2019 07:56:30 GMT99"200fe307b08fcbedb5606bba4ba5354d"text/markdownHTTP/1.1 200 OKHTTP/1.1 404 Not Found/remote.php/webdav/SofortUpload/Sun, 15 Dec 2019 13:39:03 GMT476863281-3"5df637777669d"HTTP/1.1 200 OKHTTP/1.1 404 Not Found/remote.php/webdav/bestellung%20buch%20caro.pdfWed, 11 Dec 2019 07:55:54 GMT63320"cbb8508498c886ff53e4e0f378f9bc49"application/pdfHTTP/1.1 200 OKHTTP/1.1 404 Not Found/remote.php/webdav/katze/Tue, 03 Dec 2019 17:19:49 GMT4233489797-3"5de69935b3309"HTTP/1.1 200 OKHTTP/1.1 404 Not Found/remote.php/webdav/test/Wed, 18 Dec 2019 07:11:01 GMT35-3"5df9d1058812d"HTTP/1.1 200 OKHTTP/1.1 404 Not Found", + contentType: "application/xml; charset=utf-8", + status: 207, + }, + }); + const lclient = new client_1.Client(new fakeServer_1.default(entries)); + let q; + try { + q = yield lclient.getQuota(); + (0, chai_1.expect)(true, "expect an exception").to.be.equal(false); + } + catch (e) { + (0, chai_1.expect)(true, "expect an exception").to.be.equal(true); + } + })); + it("04 get quota quota-available-bytes > 0", () => __awaiter(this, void 0, void 0, function* () { + const entries = []; + entries.push({ + request: { + description: "Client get quota", + method: "PROPFIND", + url: "/remote.php/webdav/", + }, + response: { + body: "\n/remote.php/webdav/Tue, 17 Dec 2019 23:21:39 GMT471041649742"5df9630302376"HTTP/1.1 200 OK/remote.php/webdav/Donnerwetter.mdMon, 25 Nov 2019 07:56:30 GMT99"200fe307b08fcbedb5606bba4ba5354d"text/markdownHTTP/1.1 200 OKHTTP/1.1 404 Not Found/remote.php/webdav/SofortUpload/Sun, 15 Dec 2019 13:39:03 GMT476863281-3"5df637777669d"HTTP/1.1 200 OKHTTP/1.1 404 Not Found/remote.php/webdav/bestellung%20buch%20caro.pdfWed, 11 Dec 2019 07:55:54 GMT63320"cbb8508498c886ff53e4e0f378f9bc49"application/pdfHTTP/1.1 200 OKHTTP/1.1 404 Not Found/remote.php/webdav/katze/Tue, 03 Dec 2019 17:19:49 GMT4233489797-3"5de69935b3309"HTTP/1.1 200 OKHTTP/1.1 404 Not Found", + contentType: "application/xml; charset=utf-8", + status: 207, + }, + }); + const lclient = new client_1.Client(new fakeServer_1.default(entries)); + // console.log(JSON.stringify(this.tests[0].title, null, 4)); + let q; + try { + q = yield lclient.getQuota(); + } + catch (e) { + (0, chai_1.expect)(true, "expect no exception").to.be.equal(e.message); + } + })); + it("05 get quota missing quota-available-bytes", () => __awaiter(this, void 0, void 0, function* () { + const entries = []; + entries.push({ + request: { + description: "Client get quota", + method: "PROPFIND", + url: "/remote.php/webdav/", + }, + response: { + body: "\n/remote.php/webdav/Tue, 17 Dec 2019 23:21:39 GMT471041649742"5df9630302376"HTTP/1.1 200 OK/remote.php/webdav/Donnerwetter.mdMon, 25 Nov 2019 07:56:30 GMT99"200fe307b08fcbedb5606bba4ba5354d"text/markdownHTTP/1.1 200 OKHTTP/1.1 404 Not Found/remote.php/webdav/SofortUpload/Sun, 15 Dec 2019 13:39:03 GMT476863281-3"5df637777669d"HTTP/1.1 200 OKHTTP/1.1 404 Not Found/remote.php/webdav/bestellung%20buch%20caro.pdfWed, 11 Dec 2019 07:55:54 GMT63320"cbb8508498c886ff53e4e0f378f9bc49"application/pdfHTTP/1.1 200 OKHTTP/1.1 404 Not Found/remote.php/webdav/katze/Tue, 03 Dec 2019 17:19:49 GMT4233489797-3"5de69935b3309"HTTP/1.1 200 OKHTTP/1.1 404 Not Found", + contentType: "application/xml; charset=utf-8", + status: 207, + }, + }); + const lclient = new client_1.Client(new fakeServer_1.default(entries)); + // console.log(JSON.stringify(this.tests[0].title, null, 4)); + let q; + try { + q = yield lclient.getQuota(); + (0, chai_1.expect)(true, "expect an exception").to.be.equal(false); + } + catch (e) { + (0, chai_1.expect)(true, "expect an exception").to.be.equal(true); + } + })); +}); diff --git a/src/test/11.systemInfo.test.d.ts b/src/test/11.systemInfo.test.d.ts new file mode 100644 index 00000000..87ad0c95 --- /dev/null +++ b/src/test/11.systemInfo.test.d.ts @@ -0,0 +1 @@ +import "mocha"; diff --git a/src/test/11.systemInfo.test.js b/src/test/11.systemInfo.test.js new file mode 100644 index 00000000..8b018073 --- /dev/null +++ b/src/test/11.systemInfo.test.js @@ -0,0 +1,312 @@ +"use strict"; +var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { + function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } + return new (P || (P = Promise))(function (resolve, reject) { + function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } + function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } + function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } + step((generator = generator.apply(thisArg, _arguments || [])).next()); + }); +}; +var __importDefault = (this && this.__importDefault) || function (mod) { + return (mod && mod.__esModule) ? mod : { "default": mod }; +}; +Object.defineProperty(exports, "__esModule", { value: true }); +const chai_1 = require("chai"); +// if you used the '@types/mocha' method to install mocha type definitions, uncomment the following line +require("mocha"); +const client_1 = require("../client"); +const fakeServer_1 = __importDefault(require("../fakeServer")); +const testUtils_1 = require("./testUtils"); +let client; +// tslint:disable-next-line:only-arrow-functions +// tslint:disable-next-line:space-before-function-paren +describe("11-NEXCLOUD-NODE-CLIENT-SYSTEM-INFO", function () { + // tslint:disable-next-line:space-before-function-paren + beforeEach(function () { + return __awaiter(this, void 0, void 0, function* () { + if (this.currentTest && this.currentTest.parent) { + client = yield (0, testUtils_1.getNextcloudClient)(this.currentTest.parent.title + "/" + this.currentTest.title); + } + }); + }); + this.timeout(1 * 60 * 1000); + it("01 get system info", () => __awaiter(this, void 0, void 0, function* () { + let sysInfo; + try { + sysInfo = yield client.getSystemInfo(); + (0, chai_1.expect)(sysInfo).to.have.property("nextcloud"); + (0, chai_1.expect)(sysInfo.nextcloud).to.have.property("system"); + (0, chai_1.expect)(sysInfo.nextcloud.system).to.be.a("object"); + (0, chai_1.expect)(sysInfo.nextcloud).to.have.property("storage"); + (0, chai_1.expect)(sysInfo.nextcloud.storage).to.be.a("object"); + (0, chai_1.expect)(sysInfo.nextcloud).to.have.property("shares"); + (0, chai_1.expect)(sysInfo.nextcloud.shares).to.be.a("object"); + (0, chai_1.expect)(sysInfo).to.have.property("server"); + (0, chai_1.expect)(sysInfo.server).to.be.a("object"); + (0, chai_1.expect)(sysInfo).to.have.property("activeUsers"); + (0, chai_1.expect)(sysInfo.activeUsers).to.be.a("object"); + (0, chai_1.expect)(sysInfo).to.have.property("nextcloudClient"); + (0, chai_1.expect)(sysInfo.nextcloudClient).to.have.property("version"); + (0, chai_1.expect)(sysInfo.nextcloudClient.version).to.be.a("string"); + } + catch (e) { + (0, chai_1.expect)(e, "expect no exception").to.be.equal(null); + } + })); + it("02 get system info fails", () => __awaiter(this, void 0, void 0, function* () { + const entries = []; + entries.push({ + request: { + description: "SystemInfo get", + method: "GET", + url: "/ocs/v2.php/apps/serverinfo/api/v1/info?format=json", + }, + response: { + body: "{\"NOTFOUNDocs\":{\"meta\":{\"status\":\"ok\",\"statuscode\":200,\"message\":\"OK\"},\"data\":{\"nextcloud\":{\"system\":{\"version\":\"18.0.0.10\",\"theme\":\"\",\"enable_avatars\":\"yes\",\"enable_previews\":\"yes\",\"memcache.local\":\"\\\\OC\\\\Memcache\\\\APCu\",\"memcache.distributed\":\"none\",\"filelocking.enabled\":\"yes\",\"memcache.locking\":\"\\\\OC\\\\Memcache\\\\Redis\",\"debug\":\"no\",\"freespace\":248184516608,\"cpuload\":[0.42,0.16,0.1],\"mem_total\":4039484,\"mem_free\":2845664,\"swap_total\":2097148,\"swap_free\":2072428,\"apps\":{\"num_installed\":48,\"num_updates_available\":0,\"app_updates\":[]}},\"storage\":{\"num_users\":2,\"num_files\":103909,\"num_storages\":4,\"num_storages_local\":2,\"num_storages_home\":2,\"num_storages_other\":0},\"shares\":{\"num_shares\":2,\"num_shares_user\":0,\"num_shares_groups\":0,\"num_shares_link\":2,\"num_shares_mail\":0,\"num_shares_room\":0,\"num_shares_link_no_password\":2,\"num_fed_shares_sent\":0,\"num_fed_shares_received\":0,\"permissions_3_1\":\"2\"}},\"server\":{\"webserver\":\"nginx\\/1.14.0\",\"php\":{\"version\":\"7.2.24\",\"memory_limit\":536870912,\"max_execution_time\":3600,\"upload_max_filesize\":2097152},\"database\":{\"type\":\"mysql\",\"version\":\"10.1.43\",\"size\":92266496}},\"activeUsers\":{\"last5minutes\":1,\"last1hour\":1,\"last24hours\":2}}}}", + contentType: "application/json; charset=utf-8", + status: 200, + }, + }); + const lclient = new client_1.Client(new fakeServer_1.default(entries)); + let errorCode = ""; + try { + yield lclient.getSystemInfo(); + } + catch (e) { + errorCode = e.code || e.message; + } + (0, chai_1.expect)(errorCode, "expect an exception with the code").to.be.equal("ERR_SYSTEM_INFO_MISSING_DATA"); + })); + it("03 get system info fails - nextcloud-system missing", () => __awaiter(this, void 0, void 0, function* () { + const entries = []; + entries.push({ + request: { + description: "SystemInfo get", + method: "GET", + url: "/ocs/v2.php/apps/serverinfo/api/v1/info?format=json", + }, + response: { + body: "{\"ocs\":{\"meta\":{\"status\":\"ok\",\"statuscode\":200,\"message\":\"OK\"},\"data\":{\"nextcloud\":{\"NOTFOUND-system\":{\"version\":\"18.0.0.10\",\"theme\":\"\",\"enable_avatars\":\"yes\",\"enable_previews\":\"yes\",\"memcache.local\":\"\\\\OC\\\\Memcache\\\\APCu\",\"memcache.distributed\":\"none\",\"filelocking.enabled\":\"yes\",\"memcache.locking\":\"\\\\OC\\\\Memcache\\\\Redis\",\"debug\":\"no\",\"freespace\":248184516608,\"cpuload\":[0.42,0.16,0.1],\"mem_total\":4039484,\"mem_free\":2845664,\"swap_total\":2097148,\"swap_free\":2072428,\"apps\":{\"num_installed\":48,\"num_updates_available\":0,\"app_updates\":[]}},\"storage\":{\"num_users\":2,\"num_files\":103909,\"num_storages\":4,\"num_storages_local\":2,\"num_storages_home\":2,\"num_storages_other\":0},\"shares\":{\"num_shares\":2,\"num_shares_user\":0,\"num_shares_groups\":0,\"num_shares_link\":2,\"num_shares_mail\":0,\"num_shares_room\":0,\"num_shares_link_no_password\":2,\"num_fed_shares_sent\":0,\"num_fed_shares_received\":0,\"permissions_3_1\":\"2\"}},\"server\":{\"webserver\":\"nginx\\/1.14.0\",\"php\":{\"version\":\"7.2.24\",\"memory_limit\":536870912,\"max_execution_time\":3600,\"upload_max_filesize\":2097152},\"database\":{\"type\":\"mysql\",\"version\":\"10.1.43\",\"size\":92266496}},\"activeUsers\":{\"last5minutes\":1,\"last1hour\":1,\"last24hours\":2}}}}", + contentType: "application/json; charset=utf-8", + status: 200, + }, + }); + const lclient = new client_1.Client(new fakeServer_1.default(entries)); + let errorCode = ""; + try { + yield lclient.getSystemInfo(); + } + catch (e) { + errorCode = e.code || e.message; + } + (0, chai_1.expect)(errorCode, "expect an exception with the code").to.be.equal("ERR_SYSTEM_INFO_MISSING_DATA"); + })); + it("04 get system info fails - nextcloud-storage missing", () => __awaiter(this, void 0, void 0, function* () { + const entries = []; + entries.push({ + request: { + description: "SystemInfo get", + method: "GET", + url: "/ocs/v2.php/apps/serverinfo/api/v1/info?format=json", + }, + response: { + body: "{\"ocs\":{\"meta\":{\"status\":\"ok\",\"statuscode\":200,\"message\":\"OK\"},\"data\":{\"nextcloud\":{\"system\":{\"version\":\"18.0.0.10\",\"theme\":\"\",\"enable_avatars\":\"yes\",\"enable_previews\":\"yes\",\"memcache.local\":\"\\\\OC\\\\Memcache\\\\APCu\",\"memcache.distributed\":\"none\",\"filelocking.enabled\":\"yes\",\"memcache.locking\":\"\\\\OC\\\\Memcache\\\\Redis\",\"debug\":\"no\",\"freespace\":248184516608,\"cpuload\":[0.42,0.16,0.1],\"mem_total\":4039484,\"mem_free\":2845664,\"swap_total\":2097148,\"swap_free\":2072428,\"apps\":{\"num_installed\":48,\"num_updates_available\":0,\"app_updates\":[]}},\"NOTFOUND-storage\":{\"num_users\":2,\"num_files\":103909,\"num_storages\":4,\"num_storages_local\":2,\"num_storages_home\":2,\"num_storages_other\":0},\"shares\":{\"num_shares\":2,\"num_shares_user\":0,\"num_shares_groups\":0,\"num_shares_link\":2,\"num_shares_mail\":0,\"num_shares_room\":0,\"num_shares_link_no_password\":2,\"num_fed_shares_sent\":0,\"num_fed_shares_received\":0,\"permissions_3_1\":\"2\"}},\"server\":{\"webserver\":\"nginx\\/1.14.0\",\"php\":{\"version\":\"7.2.24\",\"memory_limit\":536870912,\"max_execution_time\":3600,\"upload_max_filesize\":2097152},\"database\":{\"type\":\"mysql\",\"version\":\"10.1.43\",\"size\":92266496}},\"activeUsers\":{\"last5minutes\":1,\"last1hour\":1,\"last24hours\":2}}}}", + contentType: "application/json; charset=utf-8", + status: 200, + }, + }); + const lclient = new client_1.Client(new fakeServer_1.default(entries)); + let errorCode = ""; + try { + yield lclient.getSystemInfo(); + } + catch (e) { + errorCode = e.code || e.message; + } + (0, chai_1.expect)(errorCode, "expect an exception with the code").to.be.equal("ERR_SYSTEM_INFO_MISSING_DATA"); + })); + it("05 get system info fails - nextcloud-shares missing", () => __awaiter(this, void 0, void 0, function* () { + const entries = []; + entries.push({ + request: { + description: "SystemInfo get", + method: "GET", + url: "/ocs/v2.php/apps/serverinfo/api/v1/info?format=json", + }, + response: { + body: "{\"ocs\":{\"meta\":{\"status\":\"ok\",\"statuscode\":200,\"message\":\"OK\"},\"data\":{\"nextcloud\":{\"system\":{\"version\":\"18.0.0.10\",\"theme\":\"\",\"enable_avatars\":\"yes\",\"enable_previews\":\"yes\",\"memcache.local\":\"\\\\OC\\\\Memcache\\\\APCu\",\"memcache.distributed\":\"none\",\"filelocking.enabled\":\"yes\",\"memcache.locking\":\"\\\\OC\\\\Memcache\\\\Redis\",\"debug\":\"no\",\"freespace\":248184516608,\"cpuload\":[0.42,0.16,0.1],\"mem_total\":4039484,\"mem_free\":2845664,\"swap_total\":2097148,\"swap_free\":2072428,\"apps\":{\"num_installed\":48,\"num_updates_available\":0,\"app_updates\":[]}},\"storage\":{\"num_users\":2,\"num_files\":103909,\"num_storages\":4,\"num_storages_local\":2,\"num_storages_home\":2,\"num_storages_other\":0},\"NOTFOUND-shares\":{\"num_shares\":2,\"num_shares_user\":0,\"num_shares_groups\":0,\"num_shares_link\":2,\"num_shares_mail\":0,\"num_shares_room\":0,\"num_shares_link_no_password\":2,\"num_fed_shares_sent\":0,\"num_fed_shares_received\":0,\"permissions_3_1\":\"2\"}},\"server\":{\"webserver\":\"nginx\\/1.14.0\",\"php\":{\"version\":\"7.2.24\",\"memory_limit\":536870912,\"max_execution_time\":3600,\"upload_max_filesize\":2097152},\"database\":{\"type\":\"mysql\",\"version\":\"10.1.43\",\"size\":92266496}},\"activeUsers\":{\"last5minutes\":1,\"last1hour\":1,\"last24hours\":2}}}}", + contentType: "application/json; charset=utf-8", + status: 200, + }, + }); + const lclient = new client_1.Client(new fakeServer_1.default(entries)); + let errorCode = ""; + try { + yield lclient.getSystemInfo(); + } + catch (e) { + errorCode = e.code || e.message; + } + (0, chai_1.expect)(errorCode, "expect an exception with the code").to.be.equal("ERR_SYSTEM_INFO_MISSING_DATA"); + })); + it("06 get system info fails - nextcloud-data-server missing", () => __awaiter(this, void 0, void 0, function* () { + const entries = []; + entries.push({ + request: { + description: "SystemInfo get", + method: "GET", + url: "/ocs/v2.php/apps/serverinfo/api/v1/info?format=json", + }, + response: { + body: "{\"ocs\":{\"meta\":{\"status\":\"ok\",\"statuscode\":200,\"message\":\"OK\"},\"data\":{\"nextcloud\":{\"system\":{\"version\":\"18.0.0.10\",\"theme\":\"\",\"enable_avatars\":\"yes\",\"enable_previews\":\"yes\",\"memcache.local\":\"\\\\OC\\\\Memcache\\\\APCu\",\"memcache.distributed\":\"none\",\"filelocking.enabled\":\"yes\",\"memcache.locking\":\"\\\\OC\\\\Memcache\\\\Redis\",\"debug\":\"no\",\"freespace\":248184516608,\"cpuload\":[0.42,0.16,0.1],\"mem_total\":4039484,\"mem_free\":2845664,\"swap_total\":2097148,\"swap_free\":2072428,\"apps\":{\"num_installed\":48,\"num_updates_available\":0,\"app_updates\":[]}},\"storage\":{\"num_users\":2,\"num_files\":103909,\"num_storages\":4,\"num_storages_local\":2,\"num_storages_home\":2,\"num_storages_other\":0},\"shares\":{\"num_shares\":2,\"num_shares_user\":0,\"num_shares_groups\":0,\"num_shares_link\":2,\"num_shares_mail\":0,\"num_shares_room\":0,\"num_shares_link_no_password\":2,\"num_fed_shares_sent\":0,\"num_fed_shares_received\":0,\"permissions_3_1\":\"2\"}},\"NOTFOUND-server\":{\"webserver\":\"nginx\\/1.14.0\",\"php\":{\"version\":\"7.2.24\",\"memory_limit\":536870912,\"max_execution_time\":3600,\"upload_max_filesize\":2097152},\"database\":{\"type\":\"mysql\",\"version\":\"10.1.43\",\"size\":92266496}},\"activeUsers\":{\"last5minutes\":1,\"last1hour\":1,\"last24hours\":2}}}}", + contentType: "application/json; charset=utf-8", + status: 200, + }, + }); + const lclient = new client_1.Client(new fakeServer_1.default(entries)); + let errorCode = ""; + try { + yield lclient.getSystemInfo(); + } + catch (e) { + errorCode = e.code || e.message; + } + (0, chai_1.expect)(errorCode, "expect an exception with the code").to.be.equal("ERR_SYSTEM_INFO_MISSING_DATA"); + })); + it("07 get system info fails - data-activeUsers missing", () => __awaiter(this, void 0, void 0, function* () { + const entries = []; + entries.push({ + request: { + description: "SystemInfo get", + method: "GET", + url: "/ocs/v2.php/apps/serverinfo/api/v1/info?format=json", + }, + response: { + body: "{\"ocs\":{\"meta\":{\"status\":\"ok\",\"statuscode\":200,\"message\":\"OK\"},\"data\":{\"nextcloud\":{\"system\":{\"version\":\"18.0.0.10\",\"theme\":\"\",\"enable_avatars\":\"yes\",\"enable_previews\":\"yes\",\"memcache.local\":\"\\\\OC\\\\Memcache\\\\APCu\",\"memcache.distributed\":\"none\",\"filelocking.enabled\":\"yes\",\"memcache.locking\":\"\\\\OC\\\\Memcache\\\\Redis\",\"debug\":\"no\",\"freespace\":248184516608,\"cpuload\":[0.42,0.16,0.1],\"mem_total\":4039484,\"mem_free\":2845664,\"swap_total\":2097148,\"swap_free\":2072428,\"apps\":{\"num_installed\":48,\"num_updates_available\":0,\"app_updates\":[]}},\"storage\":{\"num_users\":2,\"num_files\":103909,\"num_storages\":4,\"num_storages_local\":2,\"num_storages_home\":2,\"num_storages_other\":0},\"shares\":{\"num_shares\":2,\"num_shares_user\":0,\"num_shares_groups\":0,\"num_shares_link\":2,\"num_shares_mail\":0,\"num_shares_room\":0,\"num_shares_link_no_password\":2,\"num_fed_shares_sent\":0,\"num_fed_shares_received\":0,\"permissions_3_1\":\"2\"}},\"server\":{\"webserver\":\"nginx\\/1.14.0\",\"php\":{\"version\":\"7.2.24\",\"memory_limit\":536870912,\"max_execution_time\":3600,\"upload_max_filesize\":2097152},\"database\":{\"type\":\"mysql\",\"version\":\"10.1.43\",\"size\":92266496}},\"NOTFOUND-activeUsers\":{\"last5minutes\":1,\"last1hour\":1,\"last24hours\":2}}}}", + contentType: "application/json; charset=utf-8", + status: 200, + }, + }); + const lclient = new client_1.Client(new fakeServer_1.default(entries)); + let errorCode = ""; + try { + yield lclient.getSystemInfo(); + } + catch (e) { + errorCode = e.code || e.message; + } + (0, chai_1.expect)(errorCode, "expect an exception with the code").to.be.equal("ERR_SYSTEM_INFO_MISSING_DATA"); + })); + it("08 get system info fails - data-nextcloud missing", () => __awaiter(this, void 0, void 0, function* () { + const entries = []; + entries.push({ + request: { + description: "SystemInfo get", + method: "GET", + url: "/ocs/v2.php/apps/serverinfo/api/v1/info?format=json", + }, + response: { + body: "{\"ocs\":{\"meta\":{\"status\":\"ok\",\"statuscode\":200,\"message\":\"OK\"},\"data\":{\"NOTFOUND-nextcloud\":{\"system\":{\"version\":\"18.0.0.10\",\"theme\":\"\",\"enable_avatars\":\"yes\",\"enable_previews\":\"yes\",\"memcache.local\":\"\\\\OC\\\\Memcache\\\\APCu\",\"memcache.distributed\":\"none\",\"filelocking.enabled\":\"yes\",\"memcache.locking\":\"\\\\OC\\\\Memcache\\\\Redis\",\"debug\":\"no\",\"freespace\":248184516608,\"cpuload\":[0.42,0.16,0.1],\"mem_total\":4039484,\"mem_free\":2845664,\"swap_total\":2097148,\"swap_free\":2072428,\"apps\":{\"num_installed\":48,\"num_updates_available\":0,\"app_updates\":[]}},\"storage\":{\"num_users\":2,\"num_files\":103909,\"num_storages\":4,\"num_storages_local\":2,\"num_storages_home\":2,\"num_storages_other\":0},\"shares\":{\"num_shares\":2,\"num_shares_user\":0,\"num_shares_groups\":0,\"num_shares_link\":2,\"num_shares_mail\":0,\"num_shares_room\":0,\"num_shares_link_no_password\":2,\"num_fed_shares_sent\":0,\"num_fed_shares_received\":0,\"permissions_3_1\":\"2\"}},\"server\":{\"webserver\":\"nginx\\/1.14.0\",\"php\":{\"version\":\"7.2.24\",\"memory_limit\":536870912,\"max_execution_time\":3600,\"upload_max_filesize\":2097152},\"database\":{\"type\":\"mysql\",\"version\":\"10.1.43\",\"size\":92266496}},\"activeUsers\":{\"last5minutes\":1,\"last1hour\":1,\"last24hours\":2}}}}", + contentType: "application/json; charset=utf-8", + status: 200, + }, + }); + const lclient = new client_1.Client(new fakeServer_1.default(entries)); + let errorCode = ""; + try { + yield lclient.getSystemInfo(); + } + catch (e) { + errorCode = e.code || e.message; + } + (0, chai_1.expect)(errorCode, "expect an exception with the code").to.be.equal("ERR_SYSTEM_INFO_MISSING_DATA"); + })); + it("10 get system basic data", () => __awaiter(this, void 0, void 0, function* () { + let sysInfo; + try { + sysInfo = yield client.getSystemBasicData(); + (0, chai_1.expect)(sysInfo).to.have.property("serverTimeString"); + (0, chai_1.expect)(sysInfo.serverTimeString).to.be.a("string"); + (0, chai_1.expect)(sysInfo).to.have.property("uptimeString"); + (0, chai_1.expect)(sysInfo.uptimeString).to.be.a("string"); + (0, chai_1.expect)(sysInfo).to.have.property("timeServersString"); + (0, chai_1.expect)(sysInfo.timeServersString).to.be.a("string"); + } + catch (e) { + (0, chai_1.expect)(e, "expect no exception").to.be.equal(null); + } + })); + it("11 get system basic data fails - servertime", () => __awaiter(this, void 0, void 0, function* () { + const entries = []; + entries.push({ + request: { + description: "SystemInfo get", + method: "GET", + url: "/ocs/v2.php/apps/serverinfo/api/v1/basicdata", + }, + response: { + body: "{\"ocs\":{\"meta\":{\"status\":\"ok\",\"statuscode\":200,\"message\":\"OK\"},\"data\":{\"NOTFOUND-servertime\":\"Tue Apr 14 12:45:28 CEST 2020\\n\",\"uptime\":\"up 9 weeks, 5 days, 23 hours, 41 minutes\\n\",\"timeservers\":\" \"}}}", + contentType: "application/json; charset=utf-8", + status: 200, + }, + }); + const lclient = new client_1.Client(new fakeServer_1.default(entries)); + let errorCode = ""; + try { + yield lclient.getSystemBasicData(); + } + catch (e) { + errorCode = e.code || e.message; + } + (0, chai_1.expect)(errorCode, "expect an exception with the code").to.be.equal("ERR_SYSTEM_INFO_MISSING_DATA"); + })); + it("12 get system basic data fails - uptime", () => __awaiter(this, void 0, void 0, function* () { + const entries = []; + entries.push({ + request: { + description: "SystemInfo get", + method: "GET", + url: "/ocs/v2.php/apps/serverinfo/api/v1/basicdata", + }, + response: { + body: "{\"ocs\":{\"meta\":{\"status\":\"ok\",\"statuscode\":200,\"message\":\"OK\"},\"data\":{\"servertime\":\"Tue Apr 14 12:45:28 CEST 2020\\n\",\"NOTFOUND-uptime\":\"up 9 weeks, 5 days, 23 hours, 41 minutes\\n\",\"timeservers\":\" \"}}}", + contentType: "application/json; charset=utf-8", + status: 200, + }, + }); + const lclient = new client_1.Client(new fakeServer_1.default(entries)); + let errorCode = ""; + try { + yield lclient.getSystemBasicData(); + } + catch (e) { + errorCode = e.code || e.message; + } + (0, chai_1.expect)(errorCode, "expect an exception with the code").to.be.equal("ERR_SYSTEM_INFO_MISSING_DATA"); + })); + it("13 get system basic data fails - timeservers", () => __awaiter(this, void 0, void 0, function* () { + const entries = []; + entries.push({ + request: { + description: "SystemInfo get", + method: "GET", + url: "/ocs/v2.php/apps/serverinfo/api/v1/basicdata", + }, + response: { + body: "{\"ocs\":{\"meta\":{\"status\":\"ok\",\"statuscode\":200,\"message\":\"OK\"},\"data\":{\"servertime\":\"Tue Apr 14 12:45:28 CEST 2020\\n\",\"uptime\":\"up 9 weeks, 5 days, 23 hours, 41 minutes\\n\",\"NOTFOUND-timeservers\":\" \"}}}", + contentType: "application/json; charset=utf-8", + status: 200, + }, + }); + const lclient = new client_1.Client(new fakeServer_1.default(entries)); + let errorCode = ""; + try { + yield lclient.getSystemBasicData(); + } + catch (e) { + errorCode = e.code || e.message; + } + (0, chai_1.expect)(errorCode, "expect an exception with the code").to.be.equal("ERR_SYSTEM_INFO_MISSING_DATA"); + })); +}); diff --git a/src/test/12.userManagement.test.d.ts b/src/test/12.userManagement.test.d.ts new file mode 100644 index 00000000..87ad0c95 --- /dev/null +++ b/src/test/12.userManagement.test.d.ts @@ -0,0 +1 @@ +import "mocha"; diff --git a/src/test/12.userManagement.test.js b/src/test/12.userManagement.test.js new file mode 100644 index 00000000..5ffd1190 --- /dev/null +++ b/src/test/12.userManagement.test.js @@ -0,0 +1,2739 @@ +"use strict"; +var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { + function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } + return new (P || (P = Promise))(function (resolve, reject) { + function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } + function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } + function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } + step((generator = generator.apply(thisArg, _arguments || [])).next()); + }); +}; +var __importDefault = (this && this.__importDefault) || function (mod) { + return (mod && mod.__esModule) ? mod : { "default": mod }; +}; +Object.defineProperty(exports, "__esModule", { value: true }); +const chai_1 = require("chai"); +// if you used the '@types/mocha' method to install mocha type definitions, uncomment the following line +require("mocha"); +const client_1 = require("../client"); +const fakeServer_1 = __importDefault(require("../fakeServer")); +const testUtils_1 = require("./testUtils"); +const environment_1 = __importDefault(require("../environment")); +let client; +// tslint:disable-next-line:only-arrow-functions +// tslint:disable-next-line:space-before-function-paren +describe("12-NEXCLOUD-NODE-CLIENT-USER-MANAGEMENT", function () { + // tslint:disable-next-line:space-before-function-paren + beforeEach(function () { + return __awaiter(this, void 0, void 0, function* () { + if (this.currentTest && this.currentTest.parent) { + client = yield (0, testUtils_1.getNextcloudClient)(this.currentTest.parent.title + "/" + this.currentTest.title); + } + }); + }); + this.timeout(1 * 60 * 1000); + it("01 delete non existing user", () => __awaiter(this, void 0, void 0, function* () { + const userId = "testUser01"; + let error = null; + try { + yield client.deleteUser(userId); + } + catch (e) { + error = e; + } + (0, chai_1.expect)(error).to.be.instanceOf(client_1.UserNotFoundError); + })); + it("02 get non existing user", () => __awaiter(this, void 0, void 0, function* () { + const userId = "testUser02"; + let error = null; + let user = null; + try { + user = yield client.getUser(userId); + } + catch (e) { + error = e; + } + (0, chai_1.expect)(error).to.be.equal(null); + (0, chai_1.expect)(user).to.be.equal(null); + })); + it("03 enable non existing user", () => __awaiter(this, void 0, void 0, function* () { + const userId = "testUser03"; + let error = null; + try { + yield client.enableUser(userId); + } + catch (e) { + error = e; + } + (0, chai_1.expect)(error).to.be.instanceOf(client_1.UserNotFoundError); + })); + it("04 disable non existing user", () => __awaiter(this, void 0, void 0, function* () { + const userId = "testUser04"; + let error = null; + try { + yield client.disableUser(userId); + } + catch (e) { + error = e; + } + (0, chai_1.expect)(error).to.be.instanceOf(client_1.UserNotFoundError); + })); + it("05 get user data of non existing user", () => __awaiter(this, void 0, void 0, function* () { + const userId = "testUser05"; + let error = null; + try { + yield client.getUserData(userId); + } + catch (e) { + error = e; + } + (0, chai_1.expect)(error).to.be.instanceOf(client_1.UserNotFoundError); + })); + it("06 create user with errors should fail", () => __awaiter(this, void 0, void 0, function* () { + const userId = "testUser06"; + let error = null; + let user = null; + // ensure that the user is not available + try { + yield client.deleteUser(userId); + } + catch (e) { + // nop + } + try { + user = yield client.createUser({ id: userId, password: "123456" }); + } + catch (e) { + error = e; + } + // password is under the most common ones + (0, chai_1.expect)(error).to.be.instanceOf(client_1.UserCreateError); + try { + user = yield client.createUser({ id: userId }); + } + catch (e) { + error = e; + } + // email address is missing + (0, chai_1.expect)(error).to.be.instanceOf(client_1.UserCreateError); + try { + user = yield client.createUser({ id: userId, email: "This in an invalid @email.address" }); + } + catch (e) { + error = e; + } + // wrong email address + (0, chai_1.expect)(error).to.be.instanceOf(client_1.UserCreateError); + error = null; + try { + user = yield client.createUser({ id: userId, password: "This is a test password" }); + } + catch (e) { + error = e; + } + // user should be created successfully + (0, chai_1.expect)(error).to.be.equal(null); + (0, chai_1.expect)(user).not.to.be.equal(null); + let user2 = null; + try { + user2 = yield client.createUser({ id: userId, password: "This is a test password 1" }); + } + catch (e) { + error = e; + } + // user already exists + (0, chai_1.expect)(error).to.be.instanceOf(client_1.UserAlreadyExistsError); + (0, chai_1.expect)(user2).to.be.equal(null); + try { + yield user.delete(); + } + catch (e) { + // nop + } + })); + it("07 create user successfully", () => __awaiter(this, void 0, void 0, function* () { + const userId = "testUser07"; + let error = null; + let user = null; + // ensure that the user is not available + try { + yield client.deleteUser(userId); + } + catch (e) { + // nop + } + // create user with email address + try { + user = yield client.createUser({ id: userId, email: "h.t.borstenson@gmail.com" }); + } + catch (e) { + error = e; + } + // user should be created successfully + (0, chai_1.expect)(error).to.be.equal(null); + (0, chai_1.expect)(user).not.to.be.equal(null); + try { + yield client.deleteUser(userId); + } + catch (e) { + error = e; + } + (0, chai_1.expect)(error).to.be.equal(null); + // create user with email address and password + error = null; + try { + user = yield client.createUser({ id: userId, email: "h.t.borstenson@gmail.com", password: "this is a secure password" }); + } + catch (e) { + error = e; + } + // user should be created successfully + (0, chai_1.expect)(error).to.be.equal(null); + (0, chai_1.expect)(user).not.to.be.equal(null); + // ensure that the user is not available + try { + yield client.deleteUser(userId); + } + catch (e) { + // nop + } + })); + it("08 enable disable user", () => __awaiter(this, void 0, void 0, function* () { + const userId = "testUser08"; + let error = null; + let user = null; + // ensure that the user is not available + try { + yield client.deleteUser(userId); + } + catch (e) { + // nop + } + // create user with password + try { + user = yield client.createUser({ id: userId, password: "this is a secure password" }); + } + catch (e) { + error = e; + } + // user should be created successfully + (0, chai_1.expect)(error).to.be.equal(null); + (0, chai_1.expect)(user).not.to.be.equal(null); + let isEnabled = false; + isEnabled = yield user.isEnabled(); + (0, chai_1.expect)(isEnabled).to.be.equal(true); + // disable user + try { + yield (user === null || user === void 0 ? void 0 : user.disable()); + } + catch (e) { + error = e; + } + (0, chai_1.expect)(error).to.be.equal(null); + isEnabled = true; + isEnabled = yield user.isEnabled(); + (0, chai_1.expect)(isEnabled).to.be.equal(false); + // enable user + try { + yield (user === null || user === void 0 ? void 0 : user.enable()); + } + catch (e) { + error = e; + } + (0, chai_1.expect)(error).to.be.equal(null); + isEnabled = false; + isEnabled = yield user.isEnabled(); + (0, chai_1.expect)(isEnabled).to.be.equal(true); + // ensure that the user is not available + try { + yield client.deleteUser(userId); + } + catch (e) { + // nop + } + })); + it("09 get users", () => __awaiter(this, void 0, void 0, function* () { + let error = null; + const userCount = 5; + const userIdPrefix = "testUser09-"; + const users = []; + for (let i = 0; i < userCount; i++) { + users.push({ id: userIdPrefix + (i + 1), user: null }); + } + // delete the users first + for (let i = 0; i < userCount; i++) { + error = null; + // delete user + try { + yield client.deleteUser(users[i].id); + } + catch (e) { + // nop + } + } + for (let i = 0; i < userCount; i++) { + error = null; + // create user with password + try { + users[i].user = yield client.createUser({ id: users[i].id, password: "this is a secure password" }); + } + catch (e) { + error = e; + } + (0, chai_1.expect)(error).to.be.equal(null); + (0, chai_1.expect)(users[i].user).not.to.be.equal(null); + } + error = null; + let result = []; + // get users + try { + result = yield client.getUsers(userIdPrefix); + } + catch (e) { + error = e; + } + (0, chai_1.expect)(error).to.be.equal(null); + (0, chai_1.expect)(result.length).to.be.equal(userCount); + error = null; + result = []; + // get users + try { + result = yield client.getUsers(userIdPrefix, 2); + } + catch (e) { + error = e; + } + (0, chai_1.expect)(error).to.be.equal(null); + (0, chai_1.expect)(result.length).to.be.equal(2); + error = null; + result = []; + // get users + try { + result = yield client.getUsers(userIdPrefix, 2, userCount - 1); + } + catch (e) { + error = e; + } + (0, chai_1.expect)(error).to.be.equal(null); + (0, chai_1.expect)(result.length).to.be.equal(1); + // get users with wrong limit + try { + yield client.getUsers(userIdPrefix, -2); + } + catch (e) { + error = e; + } + (0, chai_1.expect)(error).to.be.instanceOf(client_1.QueryLimitError); + // get users with wrong offset + error = null; + try { + yield client.getUsers(userIdPrefix, 1, -1); + } + catch (e) { + error = e; + } + (0, chai_1.expect)(error).to.be.instanceOf(client_1.QueryOffsetError); + for (let i = 0; i < userCount; i++) { + error = null; + // delete user + try { + yield client.deleteUser(users[i].id); + } + catch (e) { + // nop + } + } + })); + it("10 get and update user", () => __awaiter(this, void 0, void 0, function* () { + const userId = "testUser10"; + let error = null; + let user = null; + // ensure that the user is not available + try { + yield client.deleteUser(userId); + } + catch (e) { + // nop + } + // create user with password + try { + user = yield client.createUser({ id: userId, password: "this is a secure password" }); + } + catch (e) { + error = e; + } + // user should be created successfully + (0, chai_1.expect)(error).to.be.equal(null); + (0, chai_1.expect)(user).not.to.be.equal(null); + // *********************** + // quota + // *********************** + let quota; + try { + quota = yield user.getQuota(); + } + catch (e) { + error = e; + } + (0, chai_1.expect)(error, "User getQuota expect no error").to.be.equal(null); + (0, chai_1.expect)(quota.quota).to.be.equal(0); + (0, chai_1.expect)(quota.relative).to.be.equal(0); + (0, chai_1.expect)(quota.used).to.be.equal(0); + let setValue = "1GB"; + error = null; + try { + yield user.setQuota(setValue); + } + catch (e) { + error = e; + } + (0, chai_1.expect)(error).to.be.equal(null); + try { + quota = yield user.getQuota(); + } + catch (e) { + error = e; + } + (0, chai_1.expect)(error, "User getQuota expect no error").to.be.equal(null); + (0, chai_1.expect)(quota.quota).to.be.equal(1024 * 1024 * 1024); + setValue = "100MB"; + error = null; + try { + yield user.setQuota(setValue); + } + catch (e) { + error = e; + } + (0, chai_1.expect)(error).to.be.equal(null); + try { + quota = yield user.getQuota(); + } + catch (e) { + error = e; + } + (0, chai_1.expect)(error, "User getQuota expect no error").to.be.equal(null); + (0, chai_1.expect)(quota.quota).to.be.equal(1024 * 1024 * 100); + let quotaUF; + try { + quotaUF = yield user.getQuotaUserFriendly(); + // console.log(JSON.stringify(quotaUF, null, 4)); + } + catch (e) { + error = e; + } + (0, chai_1.expect)(error, "get getQuotaUserFriendly expect no error").to.be.equal(null); + (0, chai_1.expect)(quotaUF.quota).to.be.equal("100 MB"); + // *********************** + // last login + // *********************** + let lastlogin = null; + try { + lastlogin = yield user.getLastLogin(); + } + catch (e) { + error = e; + } + (0, chai_1.expect)(error, "User getLastLogin expect no error").to.be.equal(null); + (0, chai_1.expect)(lastlogin).to.be.equal(null); + // *********************** + // display name + // *********************** + setValue = "Horst-Thorsten Borstenson"; + let value = ""; + error = null; + try { + yield user.setDisplayName(setValue); + } + catch (e) { + error = e; + } + (0, chai_1.expect)(error).to.be.equal(null); + try { + value = yield user.getDisplayName(); + } + catch (e) { + error = e; + } + (0, chai_1.expect)(error, "User getDisplayName expect no error").to.be.equal(null); + (0, chai_1.expect)(value).to.be.equal(setValue); + // *********************** + // phone + // *********************** + setValue = "+49 1234 567"; + value = ""; + error = null; + try { + yield user.setPhone(setValue); + } + catch (e) { + error = e; + } + (0, chai_1.expect)(error).to.be.equal(null); + try { + value = yield user.getPhone(); + } + catch (e) { + error = e; + } + (0, chai_1.expect)(error, "User getPhone expect no error").to.be.equal(null); + (0, chai_1.expect)(value).to.be.equal(setValue); + // *********************** + // website + // *********************** + setValue = "http://borstenson.com"; + value = ""; + error = null; + try { + yield user.setWebsite(setValue); + } + catch (e) { + error = e; + } + (0, chai_1.expect)(error).to.be.equal(null); + try { + value = yield user.getWebsite(); + } + catch (e) { + error = e; + } + (0, chai_1.expect)(error, "User getWebsite expect no error").to.be.equal(null); + (0, chai_1.expect)(value).to.be.equal(setValue); + // *********************** + // twitter + // *********************** + setValue = "@real.h.t.borstenson"; + value = ""; + error = null; + try { + yield user.setTwitter(setValue); + } + catch (e) { + error = e; + } + (0, chai_1.expect)(error).to.be.equal(null); + try { + value = yield user.getTwitter(); + } + catch (e) { + error = e; + } + (0, chai_1.expect)(error, "User getTwitter expect no error").to.be.equal(null); + (0, chai_1.expect)(value).to.be.equal(setValue); + // *********************** + // address + // *********************** + setValue = "Fürst-Franz-Josef-Strasse 398\n9490 Vaduz\nLiechtenstein"; + value = ""; + error = null; + try { + yield user.setAddress(setValue); + } + catch (e) { + error = e; + } + (0, chai_1.expect)(error).to.be.equal(null); + try { + value = yield user.getAddress(); + } + catch (e) { + error = e; + } + (0, chai_1.expect)(error, "User getAddress expect no error").to.be.equal(null); + (0, chai_1.expect)(value).to.be.equal(setValue); + // *********************** + // language + // *********************** + setValue = "de"; + value = ""; + error = null; + try { + yield user.setLanguage(setValue); + } + catch (e) { + error = e; + } + (0, chai_1.expect)(error).to.be.equal(null); + try { + value = yield user.getLanguage(); + } + catch (e) { + error = e; + } + (0, chai_1.expect)(error, "User getLanguage expect no error").to.be.equal(null); + (0, chai_1.expect)(value).to.be.equal(setValue); + // invalid language + error = null; + try { + yield user.setLanguage("This Language is invalid"); + } + catch (e) { + error = e; + } + (0, chai_1.expect)(error).to.be.instanceOf(client_1.UserUpdateError); + // *********************** + // locale + // *********************** + setValue = "de"; + value = ""; + error = null; + try { + yield user.setLocale(setValue); + } + catch (e) { + error = e; + } + (0, chai_1.expect)(error).to.be.equal(null); + try { + value = yield user.getLocale(); + } + catch (e) { + error = e; + } + (0, chai_1.expect)(error, "User getLocale expect no error").to.be.equal(null); + (0, chai_1.expect)(value).to.be.equal(setValue); + // invalid locale + error = null; + try { + yield user.setLocale("This locale is invalid"); + } + catch (e) { + error = e; + } + (0, chai_1.expect)(error).to.be.instanceOf(client_1.UserUpdateError); + // *********************** + // password + // *********************** + setValue = "This is a secure password 1#99#!man1"; + value = ""; + error = null; + try { + yield user.setPassword(setValue); + } + catch (e) { + error = e; + } + (0, chai_1.expect)(error).to.be.equal(null); + setValue = "xx"; + value = ""; + error = null; + try { + yield user.setPassword(setValue); + } + catch (e) { + error = e; + } + (0, chai_1.expect)(error).to.be.instanceOf(client_1.UserUpdateError); + // *********************** + // resend welcome email should fail + // *********************** + error = null; + try { + yield user.resendWelcomeEmail(); + } + catch (e) { + error = e; + } + (0, chai_1.expect)(error).to.be.instanceOf(client_1.UserResendWelcomeEmailError); + // *********************** + // email + // *********************** + setValue = "h.t.borstenson@gmail.com"; + value = ""; + error = null; + try { + yield user.setEmail(setValue); + } + catch (e) { + error = e; + } + (0, chai_1.expect)(error).to.be.equal(null); + try { + value = yield user.getEmail(); + } + catch (e) { + error = e; + } + (0, chai_1.expect)(error, "User getEmail expect no error").to.be.equal(null); + (0, chai_1.expect)(value).to.be.equal(setValue); + // invalid email address + setValue = "invaid email address"; + value = ""; + try { + yield user.setEmail(setValue); + } + catch (e) { + error = e; + } + (0, chai_1.expect)(error).to.be.instanceOf(client_1.UserUpdateError); + // *********************** + // resend welcome email + // *********************** + error = null; + try { + yield user.resendWelcomeEmail(); + } + catch (e) { + error = e; + } + (0, chai_1.expect)(error).to.be.equal(null); + // clean up user + try { + yield user.delete(); + } + catch (e) { + // nop + } + })); + it("11 get users with wrong response", () => __awaiter(this, void 0, void 0, function* () { + const entries = []; + entries.push({ + request: { + description: "Users get", + method: "GET", + url: "/ocs/v1.php/cloud/users", + }, + response: { + body: "{\"ocs\":{\"meta\":{\"status\":\"ok\",\"statuscode\":100,\"message\":\"OK\",\"totalitems\":\"\",\"itemsperpage\":\"\"},\"data\":{\"usersXXX\":[\"holger\",\"htborstenson\"]}}}", + contentType: "application/json; charset=utf-8", + status: 200, + }, + }); + const lclient = new client_1.Client(new fakeServer_1.default(entries)); + let users; + try { + users = yield lclient.getUsers(); + } + catch (e) { + (0, chai_1.expect)(e.message, "expect no exception").to.be.equal(null); + } + (0, chai_1.expect)(users).to.be.a("array"); + if (users) { + (0, chai_1.expect)(users.length, "expect an empty user list").to.be.equal(0); + } + })); + it("12 update non existing user", () => __awaiter(this, void 0, void 0, function* () { + const userId = "testUser12"; + let error = null; + try { + yield client.updateUserProperty(userId, client_1.UserProperty.displayName, "Some Display Name"); + } + catch (e) { + error = e; + } + (0, chai_1.expect)(error).to.be.instanceOf(client_1.UserNotFoundError); + })); + it("13 login with new user", () => __awaiter(this, void 0, void 0, function* () { + const userId = "testUser13"; + const password = "testUser13-password"; + let error = null; + let user = null; + // ensure that the user is not available + try { + yield client.deleteUser(userId); + } + catch (e) { + // nop + } + // create user with password + try { + user = yield client.createUser({ id: userId, password }); + } + catch (e) { + error = e; + } + // user should be created successfully + (0, chai_1.expect)(error).to.be.equal(null); + (0, chai_1.expect)(user).not.to.be.equal(null); + let quota = yield user.getQuota(); + // console.log(quota); + (0, chai_1.expect)(quota.quota).to.be.equal(0); + (0, chai_1.expect)(quota.relative).to.be.equal(0); + (0, chai_1.expect)(quota.used).to.be.equal(0); + try { + yield user.setQuota("100MB"); + } + catch (e) { + error = e; + } + (0, chai_1.expect)(error).to.be.equal(null); + quota = yield user.getQuota(); + // console.log(quota); + (0, chai_1.expect)(quota.quota).to.be.equal(1024 * 1024 * 100); + (0, chai_1.expect)(quota.relative).to.be.equal(0); + (0, chai_1.expect)(quota.used).to.be.equal(0); + if ((0, testUtils_1.recordingModeActive)()) { + const serverOptions = { + url: environment_1.default.getNextcloudUrl(), + basicAuth: { + username: environment_1.default.getUserName(), + password: environment_1.default.getPassword(), + }, + logRequestResponse: environment_1.default.getRecordingActiveIndicator(), + }; + const ncserver = new client_1.Server(serverOptions); + ncserver.basicAuth.username = userId; + ncserver.basicAuth.password = password; + // login with the new user + const newUserClient = new client_1.Client(ncserver); + // this will issue the first login + try { + yield newUserClient.getQuota(); + // console.log(await newUserClient.getQuota()); + } + catch (e) { + error = e; + } + (0, chai_1.expect)(error).to.be.equal(null); + } + // the quota values change after the first login + user = yield client.getUser(userId); + quota = yield user.getQuota(); + // console.log(quota); + (0, chai_1.expect)(quota.quota).to.be.equal(1024 * 1024 * 100); + (0, chai_1.expect)(quota.relative).to.be.greaterThan(0); + (0, chai_1.expect)(quota.used).to.be.greaterThan(0); + (0, chai_1.expect)(quota.free).to.be.greaterThan(0); + (0, chai_1.expect)(quota.total).to.be.greaterThan(0); + // for code coverage + yield user.getQuotaUserFriendly(); + const lastLogin = yield user.getLastLogin(); + // console.log(lastLogin); + (0, chai_1.expect)(lastLogin).not.to.be.equal(null); + // clean up user + try { + yield user.delete(); + } + catch (e) { + // nop + } + })); + it("14 resend welcome email to non existing user", () => __awaiter(this, void 0, void 0, function* () { + const userId = "testUser04"; + let error = null; + try { + yield client.resendWelcomeEmail(userId); + } + catch (e) { + error = e; + } + (0, chai_1.expect)(error).to.be.instanceOf(client_1.UserResendWelcomeEmailError); + })); + it("20 get user groups", () => __awaiter(this, void 0, void 0, function* () { + let exception; + try { + yield client.getUserGroups("", -10); + } + catch (e) { + exception = e; + } + (0, chai_1.expect)(exception).to.be.instanceOf(client_1.QueryLimitError); + try { + yield client.getUserGroups("", 10, -1); + } + catch (e) { + exception = e; + } + (0, chai_1.expect)(exception).to.be.instanceOf(client_1.QueryOffsetError); + exception = null; + let userGroups; + try { + userGroups = yield client.getUserGroups("no group should ever match this string", 0, 1); + } + catch (e) { + exception = e; + } + (0, chai_1.expect)(exception).to.be.equal(null); + (0, chai_1.expect)(userGroups).not.to.be.equal(undefined); + (0, chai_1.expect)(userGroups.length).to.be.equal(0); + try { + userGroups = yield client.getUserGroups(); + } + catch (e) { + exception = e; + } + (0, chai_1.expect)(exception).to.be.equal(null); + (0, chai_1.expect)(userGroups).not.to.be.equal(undefined); + })); + it("21 get create delete user group", () => __awaiter(this, void 0, void 0, function* () { + const userGroupId = "test 11"; + let userGroup = null; + let exception = null; + try { + userGroup = yield client.getUserGroup(userGroupId); + } + catch (e) { + exception = e; + } + (0, chai_1.expect)(exception, "get user group should not raise an exception").to.be.equal(null); + if (userGroup) { + try { + yield userGroup.delete(); + } + catch (e) { + exception = e; + } + } + (0, chai_1.expect)(exception, "delete user should not raise an exception").to.be.equal(null); + // now the user group is deleted + try { + yield client.createUserGroup(userGroupId); + } + catch (e) { + exception = e; + } + (0, chai_1.expect)(exception).to.be.equal(null); + try { + yield client.createUserGroup(userGroupId); + } + catch (e) { + exception = e; + } + (0, chai_1.expect)(exception).to.be.instanceOf(client_1.UserGroupAlreadyExistsError); + exception = null; + try { + userGroup = yield client.getUserGroup(userGroupId + " this group should never exist"); + } + catch (e) { + exception = e; + } + (0, chai_1.expect)(exception).to.be.equal(null); + (0, chai_1.expect)(userGroup).to.be.equal(null); + try { + userGroup = yield client.getUserGroup(userGroupId); + } + catch (e) { + exception = e; + } + (0, chai_1.expect)(exception, "get user group should not raise an exception").to.be.equal(null); + (0, chai_1.expect)(userGroup).not.to.be.equal(null); + try { + yield userGroup.delete(); + } + catch (e) { + exception = e; + } + (0, chai_1.expect)(exception, "delete user should not raise an exception").to.be.equal(null); + })); + it("22 delete admin user group fails", () => __awaiter(this, void 0, void 0, function* () { + const userGroupId = "admin"; + let userGroup = null; + let exception = null; + try { + userGroup = yield client.getUserGroup(userGroupId); + } + catch (e) { + exception = e; + } + (0, chai_1.expect)(exception, "get user group should not raise an exception").to.be.equal(null); + if (userGroup) { + try { + yield userGroup.delete(); + } + catch (e) { + exception = e; + } + } + (0, chai_1.expect)(exception).to.be.instanceOf(client_1.UserGroupDeletionFailedError); + })); + it("23 get members of user group", () => __awaiter(this, void 0, void 0, function* () { + const userGroupId = "admin"; + let userGroupMembers = []; + let exception = null; + try { + userGroupMembers = yield client.getUserGroupMembers(userGroupId); + } + catch (e) { + exception = e; + } + (0, chai_1.expect)(exception, "get user group should not raise an exception").to.be.equal(null); + (0, chai_1.expect)(userGroupMembers.length).to.be.greaterThan(0); + try { + yield client.getUserGroupMembers(userGroupId + " this group should never exist"); + } + catch (e) { + exception = e; + } + (0, chai_1.expect)(exception).to.be.instanceOf(client_1.UserGroupDoesNotExistError); + let userGroup = null; + exception = null; + try { + userGroup = yield client.getUserGroup(userGroupId); + } + catch (e) { + exception = e; + } + (0, chai_1.expect)(exception, "get user group should not raise an exception").to.be.equal(null); + (0, chai_1.expect)(userGroup, "get user group admin is always there").not.to.be.equal(null); + try { + yield userGroup.getMemberUserIds(); + } + catch (e) { + exception = e; + } + (0, chai_1.expect)(exception).to.be.equal(null); + })); + it("24 get subadmins of user group", () => __awaiter(this, void 0, void 0, function* () { + const userGroupId = "admin"; + let userGroupSubadamins = []; + let exception = null; + try { + userGroupSubadamins = yield client.getUserGroupSubadmins(userGroupId); + } + catch (e) { + exception = e; + } + (0, chai_1.expect)(exception, "get user group should not raise an exception").to.be.equal(null); + (0, chai_1.expect)(userGroupSubadamins.length).to.be.greaterThan(-1); + try { + yield client.getUserGroupSubadmins(userGroupId + " this group should never exist"); + } + catch (e) { + exception = e; + } + (0, chai_1.expect)(exception).to.be.instanceOf(client_1.UserGroupDoesNotExistError); + let userGroup = null; + exception = null; + try { + userGroup = yield client.getUserGroup(userGroupId); + } + catch (e) { + exception = e; + } + (0, chai_1.expect)(exception, "get user group should not raise an exception").to.be.equal(null); + (0, chai_1.expect)(userGroup, "get user group admin is always there").not.to.be.equal(null); + try { + yield userGroup.getSubadminUserIds(); + } + catch (e) { + exception = e; + } + (0, chai_1.expect)(exception).to.be.equal(null); + })); + it("25 delete non existing user group should fail", () => __awaiter(this, void 0, void 0, function* () { + const userGroupId = "UserGroup25"; + let userGroup = null; + let userGroup1 = null; + let exception = null; + try { + userGroup = yield client.getUserGroup(userGroupId); + } + catch (e) { + exception = e; + } + (0, chai_1.expect)(exception, "get user group should not raise an exception").to.be.equal(null); + if (userGroup) { + try { + yield userGroup.delete(); + } + catch (e) { + exception = e; + } + } + (0, chai_1.expect)(exception, "delete user should not raise an exception").to.be.equal(null); + // now the user group is deleted + try { + yield client.createUserGroup(userGroupId); + } + catch (e) { + exception = e; + } + (0, chai_1.expect)(exception).to.be.equal(null); + try { + userGroup = yield client.getUserGroup(userGroupId); + } + catch (e) { + exception = e; + } + (0, chai_1.expect)(exception, "get user group should not raise an exception").to.be.equal(null); + (0, chai_1.expect)(userGroup).not.to.be.equal(null); + try { + userGroup1 = yield client.getUserGroup(userGroupId); + } + catch (e) { + exception = e; + } + (0, chai_1.expect)(exception, "get user group should not raise an exception").to.be.equal(null); + (0, chai_1.expect)(userGroup1).not.to.be.equal(null); + try { + yield userGroup.delete(); + } + catch (e) { + exception = e; + } + (0, chai_1.expect)(exception).to.be.equal(null); + try { + yield userGroup1.delete(); + } + catch (e) { + exception = e; + } + // even if the user group has been deleted previously, the delete should not fail + (0, chai_1.expect)(exception).to.be.equal(null); + })); + it("30 add user to user group and get user Groups", () => __awaiter(this, void 0, void 0, function* () { + const userGroupId1 = "UserGroup30a"; + const userGroupId2 = "UserGroup30b"; + const userId = "TestUser30"; + let userGroup1; + let userGroup2; + let user; + let exception = null; + // cleanup and setup + try { + yield client.deleteUserGroup(userGroupId1); + yield client.deleteUserGroup(userGroupId2); + } + catch (e) { + // ignore + } + try { + userGroup1 = yield client.createUserGroup(userGroupId1); + userGroup2 = yield client.createUserGroup(userGroupId2); + } + catch (e) { + exception = e; + } + (0, chai_1.expect)(exception, "create user group should not raise an exception").to.be.equal(null); + (0, chai_1.expect)(userGroup1).not.to.be.equal(undefined); + (0, chai_1.expect)(userGroup2).not.to.be.equal(undefined); + try { + yield client.deleteUser(userId); + } + catch (e) { + // ignore + } + try { + user = yield client.createUser({ id: userId, password: "this is a secure password" }); + } + catch (e) { + exception = e; + } + // user should be created successfully + (0, chai_1.expect)(exception).to.be.equal(null); + (0, chai_1.expect)(user).not.to.be.equal(undefined); + // the test: + try { + yield user.addToMemberUserGroup(userGroup1); + yield user.addToMemberUserGroup(userGroup2); + } + catch (e) { + exception = e; + } + (0, chai_1.expect)(exception, "adding a user to a user group should not raise an exception").to.be.equal(null); + let userGroups = []; + try { + userGroups = yield user.getMemberUserGroups(); + } + catch (e) { + exception = e; + } + (0, chai_1.expect)(exception).to.be.equal(null); + (0, chai_1.expect)(userGroups.length).to.be.equal(2); + // cleanup + try { + yield user.delete(); + } + catch (e) { + exception = e; + } + (0, chai_1.expect)(exception, "delete user should not raise an exception").to.be.equal(null); + try { + yield client.deleteUserGroup(userGroupId1); + yield client.deleteUserGroup(userGroupId2); + } + catch (e) { + exception = e; + } + (0, chai_1.expect)(exception, "delete user group should not raise an exception").to.be.equal(null); + })); + it("31 add non existing user to non existing user group", () => __awaiter(this, void 0, void 0, function* () { + const userGroupId = "UserGroup31"; + const userId = "TestUser31"; + let userGroup; + let user; + let exception = null; + // cleanup and setup + try { + yield client.deleteUserGroup(userGroupId); + } + catch (e) { + // ignore + } + try { + userGroup = yield client.createUserGroup(userGroupId); + } + catch (e) { + exception = e; + } + (0, chai_1.expect)(exception, "create user group should not raise an exception").to.be.equal(null); + (0, chai_1.expect)(userGroup).not.to.be.equal(undefined); + try { + yield client.deleteUser(userId); + } + catch (e) { + // ignore + } + try { + user = yield client.createUser({ id: userId, password: "this is a secure password" }); + } + catch (e) { + exception = e; + } + // user should be created successfully + (0, chai_1.expect)(exception).to.be.equal(null); + (0, chai_1.expect)(user).not.to.be.equal(undefined); + // the test: + try { + yield client.addUserToMemberUserGroup(userId, "ThisGroupDoesNotExist"); + } + catch (e) { + exception = e; + } + (0, chai_1.expect)(exception).to.be.instanceOf(client_1.UserGroupDoesNotExistError); + exception = null; + try { + yield client.addUserToMemberUserGroup("ThisUserNotExist", userGroupId); + } + catch (e) { + exception = e; + } + (0, chai_1.expect)(exception).to.be.instanceOf(client_1.UserNotFoundError); + exception = null; + // cleanup + try { + yield user.delete(); + } + catch (e) { + exception = e; + } + (0, chai_1.expect)(exception, "delete user should not raise an exception").to.be.equal(null); + try { + yield client.deleteUserGroup(userGroupId); + } + catch (e) { + exception = e; + } + (0, chai_1.expect)(exception, "delete user group should not raise an exception").to.be.equal(null); + })); + it("32 add user to user group with insufficient privileges", () => __awaiter(this, void 0, void 0, function* () { + let exception = null; + const entries = []; + entries.push({ + request: { + url: "/ocs/v1.php/cloud/users/someUserId/groups", + method: "POST", + description: "Add User someUserId to user group someGroupId", + body: "{\n \"groupid\": \"someGroupId\"\n}" + }, + response: { + body: "{\"ocs\":{\"meta\":{\"status\":\"failure\",\"statuscode\":104,\"message\":\"\",\"totalitems\":\"\",\"itemsperpage\":\"\"},\"data\":[]}}", + contentType: "application/json; charset=utf-8", + status: 200, + }, + }); + const lclient = new client_1.Client(new fakeServer_1.default(entries)); + try { + yield lclient.addUserToMemberUserGroup("someUserId", "someGroupId"); + } + catch (e) { + exception = e; + } + (0, chai_1.expect)(exception).to.be.instanceOf(client_1.InsufficientPrivilegesError); + })); + it("33 add user to user group with unkonwn error", () => __awaiter(this, void 0, void 0, function* () { + let exception = null; + const entries = []; + entries.push({ + request: { + url: "/ocs/v1.php/cloud/users/someUserId/groups", + method: "POST", + description: "Add User someUserId to user group someGroupId", + body: "{\n \"groupid\": \"someGroupId\"\n}" + }, + response: { + body: "{\"ocs\":{\"meta\":{\"status\":\"failure\",\"statuscode\":999,\"message\":\"Some unknown error\",\"totalitems\":\"\",\"itemsperpage\":\"\"},\"data\":[]}}", + contentType: "application/json; charset=utf-8", + status: 200, + }, + }); + const lclient = new client_1.Client(new fakeServer_1.default(entries)); + try { + yield lclient.addUserToMemberUserGroup("someUserId", "someGroupId"); + } + catch (e) { + exception = e; + } + (0, chai_1.expect)(exception).to.be.instanceOf(client_1.OperationFailedError); + })); + it("34 remove user from user group", () => __awaiter(this, void 0, void 0, function* () { + const userGroupId = "UserGroup34"; + const userId = "TestUser34"; + let userGroup; + let user; + let exception = null; + // cleanup and setup + try { + yield client.deleteUserGroup(userGroupId); + } + catch (e) { + // ignore + } + try { + userGroup = yield client.createUserGroup(userGroupId); + } + catch (e) { + exception = e; + } + (0, chai_1.expect)(exception, "create user group should not raise an exception").to.be.equal(null); + (0, chai_1.expect)(userGroup).not.to.be.equal(undefined); + try { + yield client.deleteUser(userId); + } + catch (e) { + // ignore + } + try { + user = yield client.createUser({ id: userId, password: "this is a secure password" }); + } + catch (e) { + exception = e; + } + // user should be created successfully + (0, chai_1.expect)(exception).to.be.equal(null); + (0, chai_1.expect)(user).not.to.be.equal(undefined); + // the test: + try { + yield user.addToMemberUserGroup(userGroup); + } + catch (e) { + exception = e; + } + (0, chai_1.expect)(exception, "adding a user to a user group should not raise an exception").to.be.equal(null); + let userGroups = []; + try { + userGroups = yield user.getMemberUserGroups(); + } + catch (e) { + exception = e; + } + (0, chai_1.expect)(exception).to.be.equal(null); + try { + yield user.removeFromMemberUserGroup(userGroup); + } + catch (e) { + exception = e; + } + (0, chai_1.expect)(exception).to.be.equal(null); + userGroups = []; + try { + userGroups = yield user.getMemberUserGroups(); + } + catch (e) { + exception = e; + } + (0, chai_1.expect)(exception).to.be.equal(null); + (0, chai_1.expect)(userGroups.length).to.be.equal(0); + // remove non existing user from user group + try { + yield client.removeUserFromMemberUserGroup("nonExistingUser", userGroup.id); + } + catch (e) { + exception = e; + } + (0, chai_1.expect)(exception).to.be.instanceOf(client_1.UserNotFoundError); + // remove non existing user group from user + exception = null; + try { + yield client.removeUserFromMemberUserGroup(user.id, "nonExistingUserGroup"); + } + catch (e) { + exception = e; + } + (0, chai_1.expect)(exception).to.be.instanceOf(client_1.UserGroupDoesNotExistError); + exception = null; + try { + yield user.removeFromMemberUserGroup(userGroup); + } + catch (e) { + exception = e; + } + (0, chai_1.expect)(exception).to.be.equal(null); + // cleanup + try { + yield user.delete(); + } + catch (e) { + exception = e; + } + (0, chai_1.expect)(exception, "delete user should not raise an exception").to.be.equal(null); + try { + yield client.deleteUserGroup(userGroupId); + } + catch (e) { + exception = e; + } + (0, chai_1.expect)(exception, "delete user group should not raise an exception").to.be.equal(null); + })); + it("35 remove user from user group with insufficient privileges", () => __awaiter(this, void 0, void 0, function* () { + let exception = null; + const entries = []; + entries.push({ + request: { + url: "/ocs/v1.php/cloud/users/someUserId/groups", + method: "DELETE", + description: "Remove User someUserId from user group someGroupId", + body: "{\n \"groupid\": \"someGroupId\"\n}" + }, + response: { + body: "{\"ocs\":{\"meta\":{\"status\":\"failure\",\"statuscode\":104,\"message\":\"\",\"totalitems\":\"\",\"itemsperpage\":\"\"},\"data\":[]}}", + contentType: "application/json; charset=utf-8", + status: 200, + }, + }); + const lclient = new client_1.Client(new fakeServer_1.default(entries)); + try { + yield lclient.removeUserFromMemberUserGroup("someUserId", "someGroupId"); + } + catch (e) { + exception = e; + } + (0, chai_1.expect)(exception).to.be.instanceOf(client_1.InsufficientPrivilegesError); + })); + it("36 remove user from user group with unkonwn error", () => __awaiter(this, void 0, void 0, function* () { + let exception = null; + const entries = []; + entries.push({ + request: { + url: "/ocs/v1.php/cloud/users/someUserId/groups", + method: "DELETE", + description: "Remove user someUserId to user group someGroupId", + body: "{\n \"groupid\": \"someGroupId\"\n}" + }, + response: { + body: "{\"ocs\":{\"meta\":{\"status\":\"failure\",\"statuscode\":999,\"message\":\"Some unknown error\",\"totalitems\":\"\",\"itemsperpage\":\"\"},\"data\":[]}}", + contentType: "application/json; charset=utf-8", + status: 200, + }, + }); + const lclient = new client_1.Client(new fakeServer_1.default(entries)); + try { + yield lclient.removeUserFromMemberUserGroup("someUserId", "someGroupId"); + } + catch (e) { + exception = e; + } + (0, chai_1.expect)(exception).to.be.instanceOf(client_1.OperationFailedError); + })); + it("37 get user group ids fails", () => __awaiter(this, void 0, void 0, function* () { + let exception = null; + const entries = []; + entries.push({ + request: { + url: "/ocs/v1.php/cloud/groups", + method: "GET", + description: "User Groups get", + }, + response: { + "body": "{\"ocs\":{\"meta\":{\"status\":\"ok\",\"statuscode\":100,\"message\":\"OK\",\"totalitems\":\"\",\"itemsperpage\":\"\"},\"data\":{\"INVALIDgroups\":[]}}}", + "contentType": "application/json; charset=utf-8", + status: 200, + }, + }); + const lclient = new client_1.Client(new fakeServer_1.default(entries)); + let userGroups = [new client_1.UserGroup(client, "g1")]; + try { + userGroups = yield lclient.getUserGroups(); + } + catch (e) { + exception = e; + } + (0, chai_1.expect)(exception).to.be.equal(null); + (0, chai_1.expect)(userGroups.length).to.be.equal(0); + })); + it("38 get user group members fails", () => __awaiter(this, void 0, void 0, function* () { + let exception = null; + const entries = []; + entries.push({ + request: { + url: "/ocs/v1.php/cloud/groups/admin", + method: "GET", + description: "User group get members" + }, + response: { + body: "{\"ocs\":{\"meta\":{\"status\":\"ok\",\"statuscode\":100,\"message\":\"OK\",\"totalitems\":\"\",\"itemsperpage\":\"\"},\"data\":{\"INVALIDusers\":[\"holger\",\"horst\"]}}}", + contentType: "application/json; charset=utf-8", + status: 200, + }, + }); + const lclient = new client_1.Client(new fakeServer_1.default(entries)); + let member = ["u1"]; + try { + member = yield lclient.getUserGroupMembers("admin"); + } + catch (e) { + exception = e; + } + (0, chai_1.expect)(exception).to.be.equal(null); + (0, chai_1.expect)(member.length).to.be.equal(0); + })); + it("40 promote user to user group admin and get subadmin user groups", () => __awaiter(this, void 0, void 0, function* () { + const userGroupId1 = "UserGroup40a"; + const userGroupId2 = "UserGroup40b"; + const userId = "TestUser40"; + let userGroup1; + let userGroup2; + let user; + let exception = null; + // cleanup and setup + try { + yield client.deleteUserGroup(userGroupId1); + yield client.deleteUserGroup(userGroupId2); + } + catch (e) { + // ignore + } + try { + userGroup1 = yield client.createUserGroup(userGroupId1); + userGroup2 = yield client.createUserGroup(userGroupId2); + } + catch (e) { + exception = e; + } + (0, chai_1.expect)(exception, "create user group should not raise an exception").to.be.equal(null); + (0, chai_1.expect)(userGroup1).not.to.be.equal(undefined); + (0, chai_1.expect)(userGroup2).not.to.be.equal(undefined); + try { + yield client.deleteUser(userId); + } + catch (e) { + // ignore + } + try { + user = yield client.createUser({ id: userId, password: "this is a secure password" }); + } + catch (e) { + exception = e; + } + // user should be created successfully + (0, chai_1.expect)(exception).to.be.equal(null); + (0, chai_1.expect)(user).not.to.be.equal(undefined); + // the test: + try { + yield user.promoteToUserGroupSubadmin(userGroup1); + yield user.promoteToUserGroupSubadmin(userGroup2); + } + catch (e) { + exception = e; + } + (0, chai_1.expect)(exception, "adding a user to a user group should not raise an exception").to.be.equal(null); + let userGroups = []; + try { + userGroups = yield user.getSubadminUserGroups(); + } + catch (e) { + exception = e; + } + (0, chai_1.expect)(exception).to.be.equal(null); + (0, chai_1.expect)(userGroups.length).to.be.equal(2); + try { + yield client.getUserGroupSubadmins(userGroupId1); + } + catch (e) { + exception = e; + } + (0, chai_1.expect)(exception).to.be.equal(null); + // cleanup + try { + yield user.delete(); + } + catch (e) { + exception = e; + } + (0, chai_1.expect)(exception, "delete user should not raise an exception").to.be.equal(null); + try { + yield client.deleteUserGroup(userGroupId1); + yield client.deleteUserGroup(userGroupId2); + } + catch (e) { + exception = e; + } + (0, chai_1.expect)(exception, "delete user group should not raise an exception").to.be.equal(null); + })); + it("41 promote non existing user to subadmin of non existing user group", () => __awaiter(this, void 0, void 0, function* () { + const userGroupId = "UserGroup41"; + const userId = "TestUser41"; + let userGroup; + let user; + let exception = null; + // cleanup and setup + try { + yield client.deleteUserGroup(userGroupId); + } + catch (e) { + // ignore + } + try { + userGroup = yield client.createUserGroup(userGroupId); + } + catch (e) { + exception = e; + } + (0, chai_1.expect)(exception, "create user group should not raise an exception").to.be.equal(null); + (0, chai_1.expect)(userGroup).not.to.be.equal(undefined); + try { + yield client.deleteUser(userId); + } + catch (e) { + // ignore + } + try { + user = yield client.createUser({ id: userId, password: "this is a secure password" }); + } + catch (e) { + exception = e; + } + // user should be created successfully + (0, chai_1.expect)(exception).to.be.equal(null); + (0, chai_1.expect)(user).not.to.be.equal(undefined); + // the test: + try { + yield client.promoteUserToUserGroupSubadmin(userId, "ThisGroupDoesNotExist"); + } + catch (e) { + exception = e; + } + (0, chai_1.expect)(exception).to.be.instanceOf(client_1.UserGroupDoesNotExistError); + exception = null; + try { + yield client.promoteUserToUserGroupSubadmin("ThisUserNotExist", userGroupId); + } + catch (e) { + exception = e; + } + (0, chai_1.expect)(exception).to.be.instanceOf(client_1.UserNotFoundError); + exception = null; + // cleanup + try { + yield user.delete(); + } + catch (e) { + exception = e; + } + (0, chai_1.expect)(exception, "delete user should not raise an exception").to.be.equal(null); + try { + yield client.deleteUserGroup(userGroupId); + } + catch (e) { + exception = e; + } + (0, chai_1.expect)(exception, "delete user group should not raise an exception").to.be.equal(null); + })); + it("42 promote user to subadmin of user group with unkown error", () => __awaiter(this, void 0, void 0, function* () { + let exception = null; + const entries = []; + entries.push({ + request: { + url: "/ocs/v1.php/cloud/users/someUserId/subadmins", + method: "POST", + description: "Add User someUserId to user group someGroupId", + body: "{\n \"groupid\": \"someGroupId\"\n}" + }, + response: { + body: "{\"ocs\":{\"meta\":{\"status\":\"failure\",\"statuscode\":103,\"message\":\"\",\"totalitems\":\"\",\"itemsperpage\":\"\"},\"data\":[]}}", + contentType: "application/json; charset=utf-8", + status: 200, + }, + }); + const lclient = new client_1.Client(new fakeServer_1.default(entries)); + try { + yield lclient.promoteUserToUserGroupSubadmin("someUserId", "someGroupId"); + } + catch (e) { + exception = e; + } + (0, chai_1.expect)(exception).to.be.instanceOf(client_1.OperationFailedError); + })); + it("43 promote user to subadmin of user group with insufficient privileges", () => __awaiter(this, void 0, void 0, function* () { + let exception = null; + const entries = []; + entries.push({ + request: { + url: "/ocs/v1.php/cloud/users/someUserId/subadmins", + method: "POST", + description: "Add User someUserId to user group someGroupId", + body: "{\n \"groupid\": \"someGroupId\"\n}" + }, + response: { + body: "{\"ocs\":{\"meta\":{\"status\":\"failure\",\"statuscode\":104,\"message\":\"\",\"totalitems\":\"\",\"itemsperpage\":\"\"},\"data\":[]}}", + contentType: "application/json; charset=utf-8", + status: 200, + }, + }); + const lclient = new client_1.Client(new fakeServer_1.default(entries)); + try { + yield lclient.promoteUserToUserGroupSubadmin("someUserId", "someGroupId"); + } + catch (e) { + exception = e; + } + (0, chai_1.expect)(exception).to.be.instanceOf(client_1.InsufficientPrivilegesError); + })); + it("44 demote user from subadmin user group", () => __awaiter(this, void 0, void 0, function* () { + const userGroupId = "UserGroup44"; + const userId = "TestUser44"; + let userGroup; + let user; + let exception = null; + // cleanup and setup + try { + yield client.deleteUserGroup(userGroupId); + } + catch (e) { + // ignore + } + try { + userGroup = yield client.createUserGroup(userGroupId); + } + catch (e) { + exception = e; + } + (0, chai_1.expect)(exception, "create user group should not raise an exception").to.be.equal(null); + (0, chai_1.expect)(userGroup).not.to.be.equal(undefined); + try { + yield client.deleteUser(userId); + } + catch (e) { + // ignore + } + try { + user = yield client.createUser({ id: userId, password: "this is a secure password" }); + } + catch (e) { + exception = e; + } + // user should be created successfully + (0, chai_1.expect)(exception).to.be.equal(null); + (0, chai_1.expect)(user).not.to.be.equal(undefined); + // the test: + try { + yield user.promoteToUserGroupSubadmin(userGroup); + } + catch (e) { + exception = e; + } + (0, chai_1.expect)(exception, "promoting a user to as a subadmin user group should not raise an exception").to.be.equal(null); + let userGroups = []; + try { + userGroups = yield user.getSubadminUserGroups(); + } + catch (e) { + exception = e; + } + (0, chai_1.expect)(exception).to.be.equal(null); + try { + yield user.demoteFromSubadminUserGroup(userGroup); + } + catch (e) { + exception = e; + } + (0, chai_1.expect)(exception).to.be.equal(null); + userGroups = []; + try { + userGroups = yield user.getSubadminUserGroups(); + } + catch (e) { + exception = e; + } + (0, chai_1.expect)(exception).to.be.equal(null); + (0, chai_1.expect)(userGroups.length).to.be.equal(0); + // demote from non existing user from user group + try { + yield client.demoteUserFromSubadminUserGroup("nonExistingUser", userGroup.id); + } + catch (e) { + exception = e; + } + (0, chai_1.expect)(exception).to.be.instanceOf(client_1.OperationFailedError); + // demote from non existing user group from user + exception = null; + try { + yield client.demoteUserFromSubadminUserGroup(user.id, "nonExistingUserGroup"); + } + catch (e) { + exception = e; + } + (0, chai_1.expect)(exception).to.be.instanceOf(client_1.OperationFailedError); + exception = null; + try { + yield user.demoteFromSubadminUserGroup(userGroup); + } + catch (e) { + exception = e; + } + (0, chai_1.expect)(exception).to.be.instanceOf(client_1.OperationFailedError); + exception = null; + // cleanup + try { + yield user.delete(); + } + catch (e) { + exception = e; + } + (0, chai_1.expect)(exception, "delete user should not raise an exception").to.be.equal(null); + try { + yield client.deleteUserGroup(userGroupId); + } + catch (e) { + exception = e; + } + (0, chai_1.expect)(exception, "delete user group should not raise an exception").to.be.equal(null); + })); + it("45 demotes user from subadmin user group with insufficient privileges", () => __awaiter(this, void 0, void 0, function* () { + let exception = null; + const entries = []; + entries.push({ + request: { + url: "/ocs/v1.php/cloud/users/someUserId/groups", + method: "DELETE", + description: "Demotes user someUserId from user group someGroupId", + body: "{\n \"groupid\": \"someGroupId\"\n}" + }, + response: { + body: "{\"ocs\":{\"meta\":{\"status\":\"failure\",\"statuscode\":104,\"message\":\"\",\"totalitems\":\"\",\"itemsperpage\":\"\"},\"data\":[]}}", + contentType: "application/json; charset=utf-8", + status: 200, + }, + }); + const lclient = new client_1.Client(new fakeServer_1.default(entries)); + try { + yield lclient.demoteUserFromSubadminUserGroup("someUserId", "someGroupId"); + } + catch (e) { + exception = e; + } + (0, chai_1.expect)(exception).to.be.instanceOf(client_1.InsufficientPrivilegesError); + })); + it("46 demote user from subadmin user group with unkonwn error", () => __awaiter(this, void 0, void 0, function* () { + let exception = null; + const entries = []; + entries.push({ + request: { + url: "/ocs/v1.php/cloud/users/someUserId/groups", + method: "DELETE", + description: "Remote user someUserId from subadmin user group someGroupId", + body: "{\n \"groupid\": \"someGroupId\"\n}" + }, + response: { + body: "{\"ocs\":{\"meta\":{\"status\":\"failure\",\"statuscode\":999,\"message\":\"Some unknown error\",\"totalitems\":\"\",\"itemsperpage\":\"\"},\"data\":[]}}", + contentType: "application/json; charset=utf-8", + status: 200, + }, + }); + const lclient = new client_1.Client(new fakeServer_1.default(entries)); + try { + yield lclient.demoteUserFromSubadminUserGroup("someUserId", "someGroupId"); + } + catch (e) { + exception = e; + } + (0, chai_1.expect)(exception).to.be.instanceOf(client_1.OperationFailedError); + })); + it("48 get user group subadmins fails", () => __awaiter(this, void 0, void 0, function* () { + let exception = null; + const entries = []; + entries.push({ + request: { + url: "/ocs/v1.php/cloud/groups/admin/subadmins", + method: "GET", + description: "User group get subadmins" + }, + response: { + "body": "{\"ocs\":{\"meta\":{\"status\":\"ok\",\"statuscode\":100,\"message\":\"OK\",\"totalitems\":\"\",\"itemsperpage\":\"\"},\"dataINVALID\":[]}}", + contentType: "application/json; charset=utf-8", + status: 200, + }, + }); + const lclient = new client_1.Client(new fakeServer_1.default(entries)); + let member = ["u1"]; + try { + member = yield lclient.getUserGroupSubadmins("admin"); + } + catch (e) { + exception = e; + } + (0, chai_1.expect)(exception).to.be.equal(null); + (0, chai_1.expect)(member.length).to.be.equal(0); + })); + it("50 invalid service response", () => __awaiter(this, void 0, void 0, function* () { + let exception = null; + const entries = []; + entries.push({ + request: { + url: "/ocs/v1.php/cloud/users/someUserId/groups", + method: "POST", + description: "Add User someUserId to user group someGroupId", + body: "{\n \"groupid\": \"someGroupId\"\n}" + }, + response: { + body: "{\"ocs\":{\"meta\":{\"status\":\"failure\",\"INVALIDstatuscode\":999,\"message\":\"Some unknown error\",\"totalitems\":\"\",\"itemsperpage\":\"\"},\"data\":[]}}", + contentType: "application/json; charset=utf-8", + status: 200, + }, + }); + const lclient = new client_1.Client(new fakeServer_1.default(entries)); + try { + yield lclient.addUserToMemberUserGroup("someUserId", "someGroupId"); + } + catch (e) { + exception = e; + } + (0, chai_1.expect)(exception).to.be.instanceOf(client_1.InvalidServiceResponseFormatError); + })); + it("60 User upsert", () => __awaiter(this, void 0, void 0, function* () { + const userId = "testUser60"; + const userGroupId1 = "testUserGroup1"; + const userGroupId2 = "testUserGroup2"; + const userGroupId3 = "testUserGroup3"; + const userGroupId4 = "testUserGroup4"; + // cleanup + try { + yield client.deleteUser(userId); + } + catch (e) { + // nop + } + try { + yield client.deleteUserGroup(userGroupId1); + yield client.deleteUserGroup(userGroupId2); + yield client.deleteUserGroup(userGroupId3); + yield client.deleteUserGroup(userGroupId4); + } + catch (e) { + // nop + } + const userUpsertOptions = [ + { + id: userId, + }, + { + id: userId, + password: "ThisIsASecurePassword", + displayName: "Horst-Thorsten Borstenson", + email: "h.t.borstenson@gmail.com", + enabled: false, + resendWelcomeEmail: false, + address: "at home", + language: "en", + locale: "de", + phone: "+49 1234 567", + twitter: "@borsti", + website: "http://borstenson.com", + quota: "3 GB", + superAdmin: true, + memberGroups: [userGroupId1, userGroupId2], + subadminGroups: [userGroupId1, userGroupId2], + }, + { + id: userId, + password: "ThisIsASecurePassword", + displayName: "Horst-Thorsten Borstenson", + email: "h.t.borstenson@gmail.com", + enabled: true, + resendWelcomeEmail: false, + address: "at home", + language: "en", + locale: "de", + phone: "+49 1234 567", + twitter: "@borsti", + website: "http://borstenson.com", + quota: "3 GB", + superAdmin: false, + memberGroups: [userGroupId1, userGroupId2, "admin"], + subadminGroups: [userGroupId1, userGroupId2], + }, + { + id: userId, + password: "ThisIsASecurePassword", + displayName: "Horst-Thorsten Borstenson", + email: "h.t.borstenson@gmail.com", + enabled: false, + resendWelcomeEmail: true, + address: "at home", + language: "en", + locale: "de", + phone: "+49 1234 5678", + twitter: "@borsti", + website: "http://borstenson.com", + quota: "3 GB", + superAdmin: true, + memberGroups: [userGroupId2, userGroupId3, "admin"], + subadminGroups: [userGroupId2, userGroupId3], + }, + { + id: userId, + }, + { + id: userId, + password: "", + displayName: "", + email: "", + enabled: false, + resendWelcomeEmail: false, + address: "", + language: "", + locale: "", + phone: "", + twitter: "", + website: "", + quota: "", + superAdmin: false, + memberGroups: [], + subadminGroups: [], + }, + { + id: userId, + password: "", + displayName: "", + email: "", + enabled: false, + resendWelcomeEmail: false, + address: "", + language: "", + locale: "", + phone: "", + twitter: "", + website: "", + quota: "", + memberGroups: [userGroupId2], + subadminGroups: [userGroupId2, userGroupId4], + } + ]; + const report = yield client.upsertUsers(userUpsertOptions); + // @todo check some values + // console.log(JSON.stringify(report, null, 4)); + // cleanup + try { + yield client.deleteUser(userId); + } + catch (e) { + // nop + } + try { + yield client.deleteUserGroup(userGroupId1); + yield client.deleteUserGroup(userGroupId2); + yield client.deleteUserGroup(userGroupId3); + yield client.deleteUserGroup(userGroupId4); + } + catch (e) { + // nop + } + })); + it("61 User upsert fails", () => __awaiter(this, void 0, void 0, function* () { + // only for code coverage + const userId = "TestUser61"; + // disable fails ------------------------------ + let entries = []; + entries.push({ + request: { + url: "/ocs/v1.php/cloud/users?search=" + userId, + method: "GET", + description: "Users get" + }, + response: { + body: "{\"ocs\":{\"meta\":{\"status\":\"ok\",\"statuscode\":100,\"message\":\"OK\",\"totalitems\":\"\",\"itemsperpage\":\"\"},\"data\":{\"users\":[\"" + userId + "\"]}}}", + contentType: "application/json; charset=utf-8", + status: 200, + }, + }); + entries.push({ + request: { + url: "/ocs/v1.php/cloud/users/" + userId, + method: "GET", + description: "User ... get" + }, + response: { + body: "{\"ocs\":{\"meta\":{\"status\":\"ok\",\"statuscode\":100,\"message\":\"OK\",\"totalitems\":\"\",\"itemsperpage\":\"\"},\"data\":{\"enabled\":true,\"storageLocation\":\"\\/var\\/nextcloud_data\\/TestUser61\",\"id\":\"TestUser61\",\"lastLogin\":0,\"backend\":\"Database\",\"subadmin\":[],\"quota\":{\"quota\":\"none\",\"used\":0},\"email\":null,\"displayname\":\"TestUser61\",\"phone\":\"\",\"address\":\"\",\"website\":\"\",\"twitter\":\"\",\"groups\":[],\"language\":\"\",\"locale\":\"\",\"backendCapabilities\":{\"setDisplayName\":true,\"setPassword\":true}}}}", + contentType: "application/json; charset=utf-8", + status: 200, + }, + }); + entries.push({ + request: { + url: "/ocs/v1.php/cloud/users/" + userId + "/disable", + method: "PUT", + description: "User ... disable" + }, + response: { + body: "{\"ocs\":{\"meta\":{\"status\":\"ok\",\"statuscode\":999,\"message\":\"OK\",\"totalitems\":\"\",\"itemsperpage\":\"\"},\"data\":[]}}", + contentType: "application/json; charset=utf-8", + status: 200, + }, + }); + entries.push({ + request: { + url: "/ocs/v1.php/cloud/users/" + userId, + method: "GET", + description: "User ... get" + }, + response: { + body: "{\"ocs\":{\"meta\":{\"status\":\"ok\",\"statuscode\":100,\"message\":\"OK\",\"totalitems\":\"\",\"itemsperpage\":\"\"},\"data\":{\"enabled\":true,\"storageLocation\":\"\\/var\\/nextcloud_data\\/TestUser61\",\"id\":\"TestUser61\",\"lastLogin\":0,\"backend\":\"Database\",\"subadmin\":[],\"quota\":{\"quota\":\"none\",\"used\":0},\"email\":null,\"displayname\":\"TestUser61\",\"phone\":\"\",\"address\":\"\",\"website\":\"\",\"twitter\":\"\",\"groups\":[],\"language\":\"\",\"locale\":\"\",\"backendCapabilities\":{\"setDisplayName\":true,\"setPassword\":true}}}}", + contentType: "application/json; charset=utf-8", + status: 200, + }, + }); + let lclient = new client_1.Client(new fakeServer_1.default(entries)); + let userUpsertOptions = [ + { + id: userId, + enabled: false, + }, + ]; + let report = yield lclient.upsertUsers(userUpsertOptions); + // enable fails ------------------------------ + entries = []; + entries.push({ + request: { + url: "/ocs/v1.php/cloud/users?search=" + userId, + method: "GET", + description: "Users get" + }, + response: { + body: "{\"ocs\":{\"meta\":{\"status\":\"ok\",\"statuscode\":100,\"message\":\"OK\",\"totalitems\":\"\",\"itemsperpage\":\"\"},\"data\":{\"users\":[\"" + userId + "\"]}}}", + contentType: "application/json; charset=utf-8", + status: 200, + }, + }); + entries.push({ + request: { + url: "/ocs/v1.php/cloud/users/" + userId, + method: "GET", + description: "User ... get" + }, + response: { + body: "{\"ocs\":{\"meta\":{\"status\":\"ok\",\"statuscode\":100,\"message\":\"OK\",\"totalitems\":\"\",\"itemsperpage\":\"\"},\"data\":{\"enabled\":false,\"storageLocation\":\"\\/var\\/nextcloud_data\\/TestUser61\",\"id\":\"TestUser61\",\"lastLogin\":0,\"backend\":\"Database\",\"subadmin\":[],\"quota\":{\"quota\":\"none\",\"used\":0},\"email\":null,\"displayname\":\"TestUser61\",\"phone\":\"\",\"address\":\"\",\"website\":\"\",\"twitter\":\"\",\"groups\":[],\"language\":\"\",\"locale\":\"\",\"backendCapabilities\":{\"setDisplayName\":true,\"setPassword\":true}}}}", + contentType: "application/json; charset=utf-8", + status: 200, + }, + }); + entries.push({ + request: { + url: "/ocs/v1.php/cloud/users/" + userId + "/enable", + method: "PUT", + description: "User ... disable" + }, + response: { + body: "{\"ocs\":{\"meta\":{\"status\":\"ok\",\"statuscode\":999,\"message\":\"OK\",\"totalitems\":\"\",\"itemsperpage\":\"\"},\"data\":[]}}", + contentType: "application/json; charset=utf-8", + status: 200, + }, + }); + entries.push({ + request: { + url: "/ocs/v1.php/cloud/users/" + userId, + method: "GET", + description: "User ... get" + }, + response: { + body: "{\"ocs\":{\"meta\":{\"status\":\"ok\",\"statuscode\":100,\"message\":\"OK\",\"totalitems\":\"\",\"itemsperpage\":\"\"},\"data\":{\"enabled\":true,\"storageLocation\":\"\\/var\\/nextcloud_data\\/TestUser61\",\"id\":\"TestUser61\",\"lastLogin\":0,\"backend\":\"Database\",\"subadmin\":[],\"quota\":{\"quota\":\"none\",\"used\":0},\"email\":null,\"displayname\":\"TestUser61\",\"phone\":\"\",\"address\":\"\",\"website\":\"\",\"twitter\":\"\",\"groups\":[],\"language\":\"\",\"locale\":\"\",\"backendCapabilities\":{\"setDisplayName\":true,\"setPassword\":true}}}}", + contentType: "application/json; charset=utf-8", + status: 200, + }, + }); + lclient = new client_1.Client(new fakeServer_1.default(entries)); + userUpsertOptions = [ + { + id: userId, + enabled: true, + }, + ]; + report = yield lclient.upsertUsers(userUpsertOptions); + // demote from superadmin ------------------------------ + entries = []; + entries.push({ + request: { + url: "/ocs/v1.php/cloud/users?search=" + userId, + method: "GET", + description: "Users get" + }, + response: { + body: "{\"ocs\":{\"meta\":{\"status\":\"ok\",\"statuscode\":100,\"message\":\"OK\",\"totalitems\":\"\",\"itemsperpage\":\"\"},\"data\":{\"users\":[\"" + userId + "\"]}}}", + contentType: "application/json; charset=utf-8", + status: 200, + }, + }); + entries.push({ + request: { + url: "/ocs/v1.php/cloud/users/" + userId, + method: "GET", + description: "User ... get" + }, + response: { + body: "{\"ocs\":{\"meta\":{\"status\":\"ok\",\"statuscode\":100,\"message\":\"OK\",\"totalitems\":\"\",\"itemsperpage\":\"\"},\"data\":{\"enabled\":false,\"storageLocation\":\"\\/var\\/nextcloud_data\\/TestUser61\",\"id\":\"TestUser61\",\"lastLogin\":0,\"backend\":\"Database\",\"subadmin\":[],\"quota\":{\"quota\":\"none\",\"used\":0},\"email\":null,\"displayname\":\"TestUser61\",\"phone\":\"\",\"address\":\"\",\"website\":\"\",\"twitter\":\"\",\"groups\":[\"admin\"],\"language\":\"\",\"locale\":\"\",\"backendCapabilities\":{\"setDisplayName\":true,\"setPassword\":true}}}}", + contentType: "application/json; charset=utf-8", + status: 200, + }, + }); + entries.push({ + request: { + url: "/ocs/v1.php/cloud/users/" + userId + "/groups", + method: "DELETE", + description: "Demote user from superadmin" + }, + response: { + body: "{\"ocs\":{\"meta\":{\"status\":\"ok\",\"statuscode\":999,\"message\":\"OK\",\"totalitems\":\"\",\"itemsperpage\":\"\"},\"data\":[]}}", + contentType: "application/json; charset=utf-8", + status: 200, + }, + }); + entries.push({ + request: { + url: "/ocs/v1.php/cloud/users/" + userId, + method: "GET", + description: "User ... get" + }, + response: { + body: "{\"ocs\":{\"meta\":{\"status\":\"ok\",\"statuscode\":100,\"message\":\"OK\",\"totalitems\":\"\",\"itemsperpage\":\"\"},\"data\":{\"enabled\":true,\"storageLocation\":\"\\/var\\/nextcloud_data\\/TestUser61\",\"id\":\"TestUser61\",\"lastLogin\":0,\"backend\":\"Database\",\"subadmin\":[],\"quota\":{\"quota\":\"none\",\"used\":0},\"email\":null,\"displayname\":\"TestUser61\",\"phone\":\"\",\"address\":\"\",\"website\":\"\",\"twitter\":\"\",\"groups\":[],\"language\":\"\",\"locale\":\"\",\"backendCapabilities\":{\"setDisplayName\":true,\"setPassword\":true}}}}", + contentType: "application/json; charset=utf-8", + status: 200, + }, + }); + lclient = new client_1.Client(new fakeServer_1.default(entries)); + userUpsertOptions = [ + { + id: userId, + superAdmin: false, + }, + ]; + report = yield lclient.upsertUsers(userUpsertOptions); + // promote to superadmin ------------------------------ + entries = []; + entries.push({ + request: { + url: "/ocs/v1.php/cloud/users?search=" + userId, + method: "GET", + description: "Users get" + }, + response: { + body: "{\"ocs\":{\"meta\":{\"status\":\"ok\",\"statuscode\":100,\"message\":\"OK\",\"totalitems\":\"\",\"itemsperpage\":\"\"},\"data\":{\"users\":[\"" + userId + "\"]}}}", + contentType: "application/json; charset=utf-8", + status: 200, + }, + }); + entries.push({ + request: { + url: "/ocs/v1.php/cloud/users/" + userId, + method: "GET", + description: "User ... get" + }, + response: { + body: "{\"ocs\":{\"meta\":{\"status\":\"ok\",\"statuscode\":100,\"message\":\"OK\",\"totalitems\":\"\",\"itemsperpage\":\"\"},\"data\":{\"enabled\":false,\"storageLocation\":\"\\/var\\/nextcloud_data\\/TestUser61\",\"id\":\"TestUser61\",\"lastLogin\":0,\"backend\":\"Database\",\"subadmin\":[],\"quota\":{\"quota\":\"none\",\"used\":0},\"email\":null,\"displayname\":\"TestUser61\",\"phone\":\"\",\"address\":\"\",\"website\":\"\",\"twitter\":\"\",\"groups\":[\"NOadmin\"],\"language\":\"\",\"locale\":\"\",\"backendCapabilities\":{\"setDisplayName\":true,\"setPassword\":true}}}}", + contentType: "application/json; charset=utf-8", + status: 200, + }, + }); + entries.push({ + request: { + url: "/ocs/v1.php/cloud/users/" + userId + "/groups", + method: "POST", + description: "Promote user to superadmin" + }, + response: { + body: "{\"ocs\":{\"meta\":{\"status\":\"ok\",\"statuscode\":999,\"message\":\"OK\",\"totalitems\":\"\",\"itemsperpage\":\"\"},\"data\":[]}}", + contentType: "application/json; charset=utf-8", + status: 200, + }, + }); + entries.push({ + request: { + url: "/ocs/v1.php/cloud/users/" + userId, + method: "GET", + description: "User ... get" + }, + response: { + body: "{\"ocs\":{\"meta\":{\"status\":\"ok\",\"statuscode\":100,\"message\":\"OK\",\"totalitems\":\"\",\"itemsperpage\":\"\"},\"data\":{\"enabled\":true,\"storageLocation\":\"\\/var\\/nextcloud_data\\/TestUser61\",\"id\":\"TestUser61\",\"lastLogin\":0,\"backend\":\"Database\",\"subadmin\":[],\"quota\":{\"quota\":\"none\",\"used\":0},\"email\":null,\"displayname\":\"TestUser61\",\"phone\":\"\",\"address\":\"\",\"website\":\"\",\"twitter\":\"\",\"groups\":[],\"language\":\"\",\"locale\":\"\",\"backendCapabilities\":{\"setDisplayName\":true,\"setPassword\":true}}}}", + contentType: "application/json; charset=utf-8", + status: 200, + }, + }); + lclient = new client_1.Client(new fakeServer_1.default(entries)); + userUpsertOptions = [ + { + id: userId, + superAdmin: true, + }, + ]; + report = yield lclient.upsertUsers(userUpsertOptions); + // remove group fails ------------------------------ + entries = []; + entries.push({ + request: { + url: "/ocs/v1.php/cloud/users?search=" + userId, + method: "GET", + description: "Users get" + }, + response: { + body: "{\"ocs\":{\"meta\":{\"status\":\"ok\",\"statuscode\":100,\"message\":\"OK\",\"totalitems\":\"\",\"itemsperpage\":\"\"},\"data\":{\"users\":[\"" + userId + "\"]}}}", + contentType: "application/json; charset=utf-8", + status: 200, + }, + }); + entries.push({ + request: { + url: "/ocs/v1.php/cloud/users/" + userId, + method: "GET", + description: "User ... get" + }, + response: { + body: "{\"ocs\":{\"meta\":{\"status\":\"ok\",\"statuscode\":100,\"message\":\"OK\",\"totalitems\":\"\",\"itemsperpage\":\"\"},\"data\":{\"enabled\":false,\"storageLocation\":\"\\/var\\/nextcloud_data\\/TestUser61\",\"id\":\"TestUser61\",\"lastLogin\":0,\"backend\":\"Database\",\"subadmin\":[],\"quota\":{\"quota\":\"none\",\"used\":0},\"email\":null,\"displayname\":\"TestUser61\",\"phone\":\"\",\"address\":\"\",\"website\":\"\",\"twitter\":\"\",\"groups\":[\"NOadmin\"],\"language\":\"\",\"locale\":\"\",\"backendCapabilities\":{\"setDisplayName\":true,\"setPassword\":true}}}}", + contentType: "application/json; charset=utf-8", + status: 200, + }, + }); + entries.push({ + request: { + url: "/ocs/v1.php/cloud/groups?search=newGroup", + method: "GET", + description: "User Groups get" + }, + response: { + body: "{\"ocs\":{\"meta\":{\"status\":\"ok\",\"statuscode\":100,\"message\":\"OK\",\"totalitems\":\"\",\"itemsperpage\":\"\"},\"data\":{\"groups\":[]}}}", + contentType: "application/json; charset=utf-8", + status: 200, + }, + }); + entries.push({ + request: { + url: "/ocs/v1.php/cloud/groups", + method: "POST", + description: "UserGroup create", + body: "{\"groupid\":\"newGroup\"}" + }, + response: { + body: "{\"ocs\":{\"meta\":{\"status\":\"ok\",\"statuscode\":999,\"message\":\"OK\",\"totalitems\":\"\",\"itemsperpage\":\"\"},\"XXdata\":[]}}", + contentType: "application/json; charset=utf-8", + status: 200, + }, + }); + lclient = new client_1.Client(new fakeServer_1.default(entries)); + userUpsertOptions = [ + { + id: userId, + memberGroups: ["newGroup"], + }, + ]; + report = yield lclient.upsertUsers(userUpsertOptions); + // create user group fails ------------------------------ + entries = []; + entries.push({ + request: { + url: "/ocs/v1.php/cloud/users?search=" + userId, + method: "GET", + description: "Users get" + }, + response: { + body: "{\"ocs\":{\"meta\":{\"status\":\"ok\",\"statuscode\":100,\"message\":\"OK\",\"totalitems\":\"\",\"itemsperpage\":\"\"},\"data\":{\"users\":[\"" + userId + "\"]}}}", + contentType: "application/json; charset=utf-8", + status: 200, + }, + }); + entries.push({ + request: { + url: "/ocs/v1.php/cloud/users/" + userId, + method: "GET", + description: "User ... get" + }, + response: { + body: "{\"ocs\":{\"meta\":{\"status\":\"ok\",\"statuscode\":100,\"message\":\"OK\",\"totalitems\":\"\",\"itemsperpage\":\"\"},\"data\":{\"enabled\":false,\"storageLocation\":\"\\/var\\/nextcloud_data\\/TestUser61\",\"id\":\"TestUser61\",\"lastLogin\":0,\"backend\":\"Database\",\"subadmin\":[],\"quota\":{\"quota\":\"none\",\"used\":0},\"email\":null,\"displayname\":\"TestUser61\",\"phone\":\"\",\"address\":\"\",\"website\":\"\",\"twitter\":\"\",\"groups\":[],\"language\":\"\",\"locale\":\"\",\"backendCapabilities\":{\"setDisplayName\":true,\"setPassword\":true}}}}", + contentType: "application/json; charset=utf-8", + status: 200, + }, + }); + entries.push({ + request: { + url: "/ocs/v1.php/cloud/groups?search=newGroup", + method: "GET", + description: "User Groups get" + }, + response: { + body: "{\"ocs\":{\"meta\":{\"status\":\"ok\",\"statuscode\":100,\"message\":\"OK\",\"totalitems\":\"\",\"itemsperpage\":\"\"},\"data\":{\"groups\":[]}}}", + contentType: "application/json; charset=utf-8", + status: 200, + }, + }); + entries.push({ + request: { + url: "/ocs/v1.php/cloud/groups", + method: "POST", + description: "UserGroup create", + body: "{\"groupid\":\"newGroup\"}" + }, + response: { + body: "{\"ocs\":{\"meta\":{\"status\":\"ok\",\"statuscode\":999,\"message\":\"some error\",\"totalitems\":\"\",\"itemsperpage\":\"\"},\"XXdata\":[]}}", + contentType: "application/json; charset=utf-8", + status: 200, + }, + }); + lclient = new client_1.Client(new fakeServer_1.default(entries)); + userUpsertOptions = [ + { + id: userId, + memberGroups: ["newGroup"], + }, + ]; + report = yield lclient.upsertUsers(userUpsertOptions); + // add group fails ------------------------------ + entries = []; + entries.push({ + request: { + url: "/ocs/v1.php/cloud/users?search=" + userId, + method: "GET", + description: "Users get" + }, + response: { + body: "{\"ocs\":{\"meta\":{\"status\":\"ok\",\"statuscode\":100,\"message\":\"OK\",\"totalitems\":\"\",\"itemsperpage\":\"\"},\"data\":{\"users\":[\"" + userId + "\"]}}}", + contentType: "application/json; charset=utf-8", + status: 200, + }, + }); + entries.push({ + request: { + url: "/ocs/v1.php/cloud/users/" + userId, + method: "GET", + description: "User ... get" + }, + response: { + body: "{\"ocs\":{\"meta\":{\"status\":\"ok\",\"statuscode\":100,\"message\":\"OK\",\"totalitems\":\"\",\"itemsperpage\":\"\"},\"data\":{\"enabled\":false,\"storageLocation\":\"\\/var\\/nextcloud_data\\/TestUser61\",\"id\":\"TestUser61\",\"lastLogin\":0,\"backend\":\"Database\",\"subadmin\":[],\"quota\":{\"quota\":\"none\",\"used\":0},\"email\":null,\"displayname\":\"TestUser61\",\"phone\":\"\",\"address\":\"\",\"website\":\"\",\"twitter\":\"\",\"groups\":[\"g1\"],\"language\":\"\",\"locale\":\"\",\"backendCapabilities\":{\"setDisplayName\":true,\"setPassword\":true}}}}", + contentType: "application/json; charset=utf-8", + status: 200, + }, + }); + entries.push({ + request: { + url: "/ocs/v1.php/cloud/groups?search=newGroup", + method: "GET", + description: "User Groups get" + }, + response: { + body: "{\"ocs\":{\"meta\":{\"status\":\"ok\",\"statuscode\":100,\"message\":\"OK\",\"totalitems\":\"\",\"itemsperpage\":\"\"},\"data\":{\"groups\":[\"newGroup\"]}}}", + contentType: "application/json; charset=utf-8", + status: 200, + }, + }); + entries.push({ + request: { + url: "/ocs/v1.php/cloud/users/" + userId + "/groups", + method: "POST", + description: "add user tp group", + body: "{\"groupid\":\"newGroup\"}" + }, + response: { + body: "{\"ocs\":{\"meta\":{\"status\":\"ok\",\"statuscode\":999,\"message\":\"OK\",\"totalitems\":\"\",\"itemsperpage\":\"\"},\"XXdata\":[]}}", + contentType: "application/json; charset=utf-8", + status: 200, + }, + }); + lclient = new client_1.Client(new fakeServer_1.default(entries)); + userUpsertOptions = [ + { + id: userId, + memberGroups: ["newGroup"], + }, + ]; + report = yield lclient.upsertUsers(userUpsertOptions); + // demote from subadmin group fails ------------------------------ + entries = []; + entries.push({ + request: { + url: "/ocs/v1.php/cloud/users?search=" + userId, + method: "GET", + description: "Users get" + }, + response: { + body: "{\"ocs\":{\"meta\":{\"status\":\"ok\",\"statuscode\":100,\"message\":\"OK\",\"totalitems\":\"\",\"itemsperpage\":\"\"},\"data\":{\"users\":[\"" + userId + "\"]}}}", + contentType: "application/json; charset=utf-8", + status: 200, + }, + }); + entries.push({ + request: { + url: "/ocs/v1.php/cloud/users/" + userId, + method: "GET", + description: "User ... get" + }, + response: { + body: "{\"ocs\":{\"meta\":{\"status\":\"ok\",\"statuscode\":100,\"message\":\"OK\",\"totalitems\":\"\",\"itemsperpage\":\"\"},\"data\":{\"enabled\":false,\"storageLocation\":\"\\/var\\/nextcloud_data\\/TestUser61\",\"id\":\"TestUser61\",\"lastLogin\":0,\"backend\":\"Database\",\"subadmin\":[\"subadminGroup\"],\"quota\":{\"quota\":\"none\",\"used\":0},\"email\":null,\"displayname\":\"TestUser61\",\"phone\":\"\",\"address\":\"\",\"website\":\"\",\"twitter\":\"\",\"groups\":[\"NOadmin\"],\"language\":\"\",\"locale\":\"\",\"backendCapabilities\":{\"setDisplayName\":true,\"setPassword\":true}}}}", + contentType: "application/json; charset=utf-8", + status: 200, + }, + }); + entries.push({ + request: { + url: "/ocs/v1.php/cloud/groups?search=newGroup", + method: "GET", + description: "User Groups get" + }, + response: { + body: "{\"ocs\":{\"meta\":{\"status\":\"ok\",\"statuscode\":999,\"message\":\"OK\",\"totalitems\":\"\",\"itemsperpage\":\"\"},\"data\":{\"groups\":[]}}}", + contentType: "application/json; charset=utf-8", + status: 200, + }, + }); + lclient = new client_1.Client(new fakeServer_1.default(entries)); + userUpsertOptions = [ + { + id: userId, + subadminGroups: [], + }, + ]; + report = yield lclient.upsertUsers(userUpsertOptions); + // create subadmin user group fails ------------------------------ + entries = []; + entries.push({ + request: { + url: "/ocs/v1.php/cloud/users?search=" + userId, + method: "GET", + description: "Users get" + }, + response: { + body: "{\"ocs\":{\"meta\":{\"status\":\"ok\",\"statuscode\":100,\"message\":\"OK\",\"totalitems\":\"\",\"itemsperpage\":\"\"},\"data\":{\"users\":[\"" + userId + "\"]}}}", + contentType: "application/json; charset=utf-8", + status: 200, + }, + }); + entries.push({ + request: { + url: "/ocs/v1.php/cloud/users/" + userId, + method: "GET", + description: "User ... get" + }, + response: { + body: "{\"ocs\":{\"meta\":{\"status\":\"ok\",\"statuscode\":100,\"message\":\"OK\",\"totalitems\":\"\",\"itemsperpage\":\"\"},\"data\":{\"enabled\":false,\"storageLocation\":\"\\/var\\/nextcloud_data\\/TestUser61\",\"id\":\"TestUser61\",\"lastLogin\":0,\"backend\":\"Database\",\"subadmin\":[],\"quota\":{\"quota\":\"none\",\"used\":0},\"email\":null,\"displayname\":\"TestUser61\",\"phone\":\"\",\"address\":\"\",\"website\":\"\",\"twitter\":\"\",\"groups\":[],\"language\":\"\",\"locale\":\"\",\"backendCapabilities\":{\"setDisplayName\":true,\"setPassword\":true}}}}", + contentType: "application/json; charset=utf-8", + status: 200, + }, + }); + entries.push({ + request: { + url: "/ocs/v1.php/cloud/groups?search=newGroup", + method: "GET", + description: "User Groups get" + }, + response: { + body: "{\"ocs\":{\"meta\":{\"status\":\"ok\",\"statuscode\":100,\"message\":\"OK\",\"totalitems\":\"\",\"itemsperpage\":\"\"},\"data\":{\"groups\":[]}}}", + contentType: "application/json; charset=utf-8", + status: 200, + }, + }); + entries.push({ + request: { + url: "/ocs/v1.php/cloud/groups", + method: "POST", + description: "UserGroup create", + body: "{\"groupid\":\"newGroup\"}" + }, + response: { + body: "{\"ocs\":{\"meta\":{\"status\":\"ok\",\"statuscode\":999,\"message\":\"some error\",\"totalitems\":\"\",\"itemsperpage\":\"\"},\"XXdata\":[]}}", + contentType: "application/json; charset=utf-8", + status: 200, + }, + }); + lclient = new client_1.Client(new fakeServer_1.default(entries)); + userUpsertOptions = [ + { + id: userId, + subadminGroups: ["newGroup"], + }, + ]; + report = yield lclient.upsertUsers(userUpsertOptions); + // add subadmin group fails ------------------------------ + entries = []; + entries.push({ + request: { + url: "/ocs/v1.php/cloud/users?search=" + userId, + method: "GET", + description: "Users get" + }, + response: { + body: "{\"ocs\":{\"meta\":{\"status\":\"ok\",\"statuscode\":100,\"message\":\"OK\",\"totalitems\":\"\",\"itemsperpage\":\"\"},\"data\":{\"users\":[\"" + userId + "\"]}}}", + contentType: "application/json; charset=utf-8", + status: 200, + }, + }); + entries.push({ + request: { + url: "/ocs/v1.php/cloud/users/" + userId, + method: "GET", + description: "User ... get" + }, + response: { + body: "{\"ocs\":{\"meta\":{\"status\":\"ok\",\"statuscode\":100,\"message\":\"OK\",\"totalitems\":\"\",\"itemsperpage\":\"\"},\"data\":{\"enabled\":false,\"storageLocation\":\"\\/var\\/nextcloud_data\\/TestUser61\",\"id\":\"TestUser61\",\"lastLogin\":0,\"backend\":\"Database\",\"subadmin\":[],\"quota\":{\"quota\":\"none\",\"used\":0},\"email\":null,\"displayname\":\"TestUser61\",\"phone\":\"\",\"address\":\"\",\"website\":\"\",\"twitter\":\"\",\"groups\":[\"g1\"],\"language\":\"\",\"locale\":\"\",\"backendCapabilities\":{\"setDisplayName\":true,\"setPassword\":true}}}}", + contentType: "application/json; charset=utf-8", + status: 200, + }, + }); + entries.push({ + request: { + url: "/ocs/v1.php/cloud/groups?search=newGroup", + method: "GET", + description: "User Groups get" + }, + response: { + body: "{\"ocs\":{\"meta\":{\"status\":\"ok\",\"statuscode\":100,\"message\":\"OK\",\"totalitems\":\"\",\"itemsperpage\":\"\"},\"data\":{\"groups\":[\"newGroup\"]}}}", + contentType: "application/json; charset=utf-8", + status: 200, + }, + }); + entries.push({ + request: { + url: "/ocs/v1.php/cloud/users/" + userId + "/groups", + method: "POST", + description: "add user tp group", + body: "{\"groupid\":\"newGroup\"}" + }, + response: { + body: "{\"ocs\":{\"meta\":{\"status\":\"ok\",\"statuscode\":999,\"message\":\"OK\",\"totalitems\":\"\",\"itemsperpage\":\"\"},\"XXdata\":[]}}", + contentType: "application/json; charset=utf-8", + status: 200, + }, + }); + lclient = new client_1.Client(new fakeServer_1.default(entries)); + userUpsertOptions = [ + { + id: userId, + subadminGroups: ["newGroup"], + }, + ]; + report = yield lclient.upsertUsers(userUpsertOptions); + // display name fails ------------------------------ + entries = []; + entries.push({ + request: { + url: "/ocs/v1.php/cloud/users?search=" + userId, + method: "GET", + description: "Users get" + }, + response: { + body: "{\"ocs\":{\"meta\":{\"status\":\"ok\",\"statuscode\":100,\"message\":\"OK\",\"totalitems\":\"\",\"itemsperpage\":\"\"},\"data\":{\"users\":[\"" + userId + "\"]}}}", + contentType: "application/json; charset=utf-8", + status: 200, + }, + }); + entries.push({ + request: { + url: "/ocs/v1.php/cloud/users/" + userId, + method: "GET", + description: "User ... get" + }, + response: { + body: "{\"ocs\":{\"meta\":{\"status\":\"ok\",\"statuscode\":100,\"message\":\"OK\",\"totalitems\":\"\",\"itemsperpage\":\"\"},\"data\":{\"enabled\":false,\"storageLocation\":\"\\/var\\/nextcloud_data\\/TestUser61\",\"id\":\"TestUser61\",\"lastLogin\":0,\"backend\":\"Database\",\"subadmin\":[],\"quota\":{\"quota\":\"none\",\"used\":0},\"email\":null,\"displayname\":\"TestUser61\",\"phone\":\"\",\"address\":\"\",\"website\":\"\",\"twitter\":\"\",\"groups\":[\"g1\"],\"language\":\"\",\"locale\":\"\",\"backendCapabilities\":{\"setDisplayName\":true,\"setPassword\":true}}}}", + contentType: "application/json; charset=utf-8", + status: 200, + }, + }); + entries.push({ + request: { + url: "/ocs/v1.php/cloud/users/" + userId, + method: "PUT", + description: "update user", + body: "{\n \"key\": \"xxkey\",\n \"value\": \"xxvalue\"\n}" + }, + response: { + body: "{\"ocs\":{\"meta\":{\"status\":\"ok\",\"statuscode\":999,\"message\":\"OK\",\"totalitems\":\"\",\"itemsperpage\":\"\"},\"data\":[]}}", + contentType: "application/json; charset=utf-8", + status: 200, + }, + }); + entries.push({ + request: { + url: "/ocs/v1.php/cloud/users/" + userId, + method: "PUT", + description: "update user", + body: "{\n \"key\": \"xxkey\",\n \"value\": \"xxvalue\"\n}" + }, + response: { + body: "{\"ocs\":{\"meta\":{\"status\":\"ok\",\"statuscode\":999,\"message\":\"OK\",\"totalitems\":\"\",\"itemsperpage\":\"\"},\"data\":[]}}", + contentType: "application/json; charset=utf-8", + status: 200, + }, + }); + entries.push({ + request: { + url: "/ocs/v1.php/cloud/users/" + userId, + method: "PUT", + description: "update user", + body: "{\n \"key\": \"xxkey\",\n \"value\": \"xxvalue\"\n}" + }, + response: { + body: "{\"ocs\":{\"meta\":{\"status\":\"ok\",\"statuscode\":999,\"message\":\"OK\",\"totalitems\":\"\",\"itemsperpage\":\"\"},\"data\":[]}}", + contentType: "application/json; charset=utf-8", + status: 200, + }, + }); + entries.push({ + request: { + url: "/ocs/v1.php/cloud/users/" + userId, + method: "PUT", + description: "update user", + body: "{\n \"key\": \"xxkey\",\n \"value\": \"xxvalue\"\n}" + }, + response: { + body: "{\"ocs\":{\"meta\":{\"status\":\"ok\",\"statuscode\":999,\"message\":\"OK\",\"totalitems\":\"\",\"itemsperpage\":\"\"},\"data\":[]}}", + contentType: "application/json; charset=utf-8", + status: 200, + }, + }); + entries.push({ + request: { + url: "/ocs/v1.php/cloud/users/" + userId, + method: "PUT", + description: "update user", + body: "{\n \"key\": \"xxkey\",\n \"value\": \"xxvalue\"\n}" + }, + response: { + body: "{\"ocs\":{\"meta\":{\"status\":\"ok\",\"statuscode\":999,\"message\":\"OK\",\"totalitems\":\"\",\"itemsperpage\":\"\"},\"data\":[]}}", + contentType: "application/json; charset=utf-8", + status: 200, + }, + }); + entries.push({ + request: { + url: "/ocs/v1.php/cloud/users/" + userId, + method: "PUT", + description: "update user", + body: "{\n \"key\": \"xxkey\",\n \"value\": \"xxvalue\"\n}" + }, + response: { + body: "{\"ocs\":{\"meta\":{\"status\":\"ok\",\"statuscode\":999,\"message\":\"OK\",\"totalitems\":\"\",\"itemsperpage\":\"\"},\"data\":[]}}", + contentType: "application/json; charset=utf-8", + status: 200, + }, + }); + entries.push({ + request: { + url: "/ocs/v1.php/cloud/users/" + userId, + method: "PUT", + description: "update user", + body: "{\n \"key\": \"xxkey\",\n \"value\": \"xxvalue\"\n}" + }, + response: { + body: "{\"ocs\":{\"meta\":{\"status\":\"ok\",\"statuscode\":999,\"message\":\"OK\",\"totalitems\":\"\",\"itemsperpage\":\"\"},\"data\":[]}}", + contentType: "application/json; charset=utf-8", + status: 200, + }, + }); + lclient = new client_1.Client(new fakeServer_1.default(entries)); + userUpsertOptions = [ + { + id: userId, + displayName: "someValue", + email: "someValue", + twitter: "someValue", + phone: "someValue", + address: "someValue", + website: "someValue", + resendWelcomeEmail: true, + }, + ]; + report = yield lclient.upsertUsers(userUpsertOptions); + })); +}); diff --git a/src/test/13.share.test.d.ts b/src/test/13.share.test.d.ts new file mode 100644 index 00000000..87ad0c95 --- /dev/null +++ b/src/test/13.share.test.d.ts @@ -0,0 +1 @@ +import "mocha"; diff --git a/src/test/13.share.test.js b/src/test/13.share.test.js new file mode 100644 index 00000000..38421106 --- /dev/null +++ b/src/test/13.share.test.js @@ -0,0 +1,267 @@ +"use strict"; +var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { + function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } + return new (P || (P = Promise))(function (resolve, reject) { + function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } + function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } + function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } + step((generator = generator.apply(thisArg, _arguments || [])).next()); + }); +}; +var __importDefault = (this && this.__importDefault) || function (mod) { + return (mod && mod.__esModule) ? mod : { "default": mod }; +}; +Object.defineProperty(exports, "__esModule", { value: true }); +const chai_1 = require("chai"); +// if you used the '@types/mocha' method to install mocha type definitions, uncomment the following line +require("mocha"); +const client_1 = require("../client"); +const fakeServer_1 = __importDefault(require("../fakeServer")); +const share_1 = __importDefault(require("../share")); +const testUtils_1 = require("./testUtils"); +let client; +// tslint:disable-next-line:only-arrow-functions +// tslint:disable-next-line:space-before-function-paren +describe("13-NEXCLOUD-NODE-CLIENT-SHARE", function () { + // tslint:disable-next-line:space-before-function-paren + beforeEach(function () { + return __awaiter(this, void 0, void 0, function* () { + if (this.currentTest && this.currentTest.parent) { + client = yield (0, testUtils_1.getNextcloudClient)(this.currentTest.parent.title + "/" + this.currentTest.title); + } + }); + }); + this.timeout(1 * 60 * 1000); + it("01 create public share", () => __awaiter(this, void 0, void 0, function* () { + const fileName = "/ncncTest/share1/file3.txt"; + let file; + file = yield client.createFile(fileName, Buffer.from("this is a test text")); + // const createShare: ICreateShare = { fileSystemElement: file, password: "password 1", publicUpload: true }; + let createShare = { fileSystemElement: file, password: "password 1", publicUpload: false }; + let share; + try { + share = yield client.createShare(createShare); + (0, chai_1.expect)(share.id).to.be.a("string"); + (0, chai_1.expect)(share.id.length).to.be.greaterThan(0); + (0, chai_1.expect)(share.url).to.be.a("string"); + (0, chai_1.expect)(share.url.length).to.be.greaterThan(0); + (0, chai_1.expect)(share.token).to.be.a("string"); + (0, chai_1.expect)(share.token.length).to.be.greaterThan(0); + try { + yield share.setPassword("some password"); + } + catch (e) { + (0, chai_1.expect)(e.message, "expect no exception setting password").to.be.equal(null); + } + (0, chai_1.expect)(share.note).to.be.equal(""); + try { + const note = "This is a Note\nNew Line"; + yield share.setNote(note); + (0, chai_1.expect)(share.note).to.be.equal(note); + } + catch (e) { + (0, chai_1.expect)(e.message, "expect no exception setting note").to.be.equal(null); + } + try { + yield share.setExpiration(new Date(2020, 11, 5)); + (0, chai_1.expect)(share.expiration).to.be.a("Date"); + } + catch (e) { + (0, chai_1.expect)(e.message, "expect no exception setting expiration").to.be.equal(null); + } + try { + yield share.delete(); + } + catch (e) { + (0, chai_1.expect)(e.message, "expect no exception deleting share").to.be.equal(null); + } + } + catch (e) { + (0, chai_1.expect)(e.message, "expect no exception").to.be.equal(null); + } + createShare = { fileSystemElement: file, publicUpload: true }; + try { + share = yield client.createShare(createShare); + } + catch (e) { + (0, chai_1.expect)(e.message, "expect no exception 'publicUpload:true'").to.be.equal(null); + } + yield file.delete(); + })); + it("02 invalid share responses", () => __awaiter(this, void 0, void 0, function* () { + const entries = []; + entries.push({ + request: { + description: "Share get", + method: "GET", + url: "/ocs/v2.php/apps/files_sharing/api/v1/shares/60", + }, + response: { + body: "{\"ocsXXX\":{\"meta\":{\"status\":\"ok\",\"statuscode\":200,\"message\":\"OK\"},\"data\":[{\"id\":\"60\",\"share_type\":3,\"uid_owner\":\"htborstenson\",\"displayname_owner\":\"Horst-Thorsten Borstenson\",\"permissions\":1,\"can_edit\":true,\"can_delete\":true,\"stime\":1580171571,\"parent\":null,\"expiration\":null,\"token\":\"HMHbFqsKfxGjjKi\",\"uid_file_owner\":\"htborstenson\",\"note\":\"\",\"label\":\"\",\"displayname_file_owner\":\"Horst-Thorsten Borstenson\",\"path\":\"\\/ncncTest\\/share1\\/file3.txt\",\"item_type\":\"file\",\"mimetype\":\"text\\/plain\",\"storage_id\":\"home::htborstenson\",\"storage\":3,\"item_source\":107213,\"file_source\":107213,\"file_parent\":107191,\"file_target\":\"\\/file3.txt\",\"share_with\":\"2|$argon2i$v=19$m=65536,t=4,p=1$SHd0ckwyeG1ieUcubThIRQ$+rO5YJNYmQAdrptAJFQAjq00QnfpTmkikZet\\/PKv3ZY\",\"share_with_displayname\":\"(Shared link)\",\"password\":\"2|$argon2i$v=19$m=65536,t=4,p=1$SHd0ckwyeG1ieUcubThIRQ$+rO5YJNYmQAdrptAJFQAjq00QnfpTmkikZet\\/PKv3ZY\",\"send_password_by_talk\":false,\"url\":\"https:\\/\\/mo.hobigo.de\\/s\\/HMHbFqsKfxGjjKi\",\"mail_send\":0,\"hide_download\":0}]}}", + contentType: "application/xml; charset=utf-8", + status: 200, + }, + }); + entries.push({ + request: { + description: "Share get", + method: "GET", + url: "/ocs/v2.php/apps/files_sharing/api/v1/shares/60", + }, + response: { + body: "{\"ocs\":{\"meta\":{\"status\":\"ok\",\"statuscode\":200,\"message\":\"OK\"},\"data\":[{\"id\":\"60\",\"share_type\":3,\"uid_owner\":\"htborstenson\",\"displayname_owner\":\"Horst-Thorsten Borstenson\",\"permissions\":1,\"can_edit\":true,\"can_delete\":true,\"stime\":1580171571,\"parent\":null,\"expiration\":null,\"token\":\"HMHbFqsKfxGjjKi\",\"uid_file_owner\":\"htborstenson\",\"note\":\"\",\"label\":\"\",\"displayname_file_owner\":\"Horst-Thorsten Borstenson\",\"path\":\"\\/ncncTest\\/share1\\/file3.txt\",\"item_type\":\"file\",\"mimetype\":\"text\\/plain\",\"storage_id\":\"home::htborstenson\",\"storage\":3,\"item_source\":107213,\"file_source\":107213,\"file_parent\":107191,\"file_target\":\"\\/file3.txt\",\"share_with\":\"2|$argon2i$v=19$m=65536,t=4,p=1$SHd0ckwyeG1ieUcubThIRQ$+rO5YJNYmQAdrptAJFQAjq00QnfpTmkikZet\\/PKv3ZY\",\"share_with_displayname\":\"(Shared link)\",\"password\":\"2|$argon2i$v=19$m=65536,t=4,p=1$SHd0ckwyeG1ieUcubThIRQ$+rO5YJNYmQAdrptAJFQAjq00QnfpTmkikZet\\/PKv3ZY\",\"send_password_by_talk\":false,\"urlXXX\":\"https:\\/\\/mo.hobigo.de\\/s\\/HMHbFqsKfxGjjKi\",\"mail_send\":0,\"hide_download\":0}]}}", + contentType: "application/xml; charset=utf-8", + status: 200, + }, + }); + entries.push({ + request: { + description: "Share get", + method: "GET", + url: "/ocs/v2.php/apps/files_sharing/api/v1/shares/60", + }, + response: { + body: "{\"ocs\":{\"meta\":{\"status\":\"ok\",\"statuscode\":200,\"message\":\"OK\"},\"data\":[{\"id\":\"60\",\"share_type\":3,\"uid_owner\":\"htborstenson\",\"displayname_owner\":\"Horst-Thorsten Borstenson\",\"permissions\":1,\"can_edit\":true,\"can_delete\":true,\"stime\":1580171571,\"parent\":null,\"expiration\":null,\"XXXtoken\":\"HMHbFqsKfxGjjKi\",\"uid_file_owner\":\"htborstenson\",\"note\":\"\",\"label\":\"\",\"displayname_file_owner\":\"Horst-Thorsten Borstenson\",\"path\":\"\\/ncncTest\\/share1\\/file3.txt\",\"item_type\":\"file\",\"mimetype\":\"text\\/plain\",\"storage_id\":\"home::htborstenson\",\"storage\":3,\"item_source\":107213,\"file_source\":107213,\"file_parent\":107191,\"file_target\":\"\\/file3.txt\",\"share_with\":\"2|$argon2i$v=19$m=65536,t=4,p=1$SHd0ckwyeG1ieUcubThIRQ$+rO5YJNYmQAdrptAJFQAjq00QnfpTmkikZet\\/PKv3ZY\",\"share_with_displayname\":\"(Shared link)\",\"password\":\"2|$argon2i$v=19$m=65536,t=4,p=1$SHd0ckwyeG1ieUcubThIRQ$+rO5YJNYmQAdrptAJFQAjq00QnfpTmkikZet\\/PKv3ZY\",\"send_password_by_talk\":false,\"url\":\"https:\\/\\/mo.hobigo.de\\/s\\/HMHbFqsKfxGjjKi\",\"mail_send\":0,\"hide_download\":0}]}}", + contentType: "application/xml; charset=utf-8", + status: 200, + }, + }); + entries.push({ + request: { + description: "Share get", + method: "GET", + url: "/ocs/v2.php/apps/files_sharing/api/v1/shares/60", + }, + response: { + body: "{\"ocs\":{\"meta\":{\"status\":\"ok\",\"statuscode\":200,\"message\":\"OK\"},\"data\":[{\"id\":\"60\",\"share_type\":3,\"uid_owner\":\"htborstenson\",\"displayname_owner\":\"Horst-Thorsten Borstenson\",\"permissions\":1,\"can_edit\":true,\"can_delete\":true,\"stime\":1580171571,\"parent\":null,\"expiration\":null,\"token\":\"HMHbFqsKfxGjjKi\",\"uid_file_owner\":\"htborstenson\",\"note\":\"\",\"label\":\"\",\"displayname_file_owner\":\"Horst-Thorsten Borstenson\",\"path\":\"\\/ncncTest\\/share1\\/file3.txt\",\"XXXitem_type\":\"file\",\"mimetype\":\"text\\/plain\",\"storage_id\":\"home::htborstenson\",\"storage\":3,\"item_source\":107213,\"file_source\":107213,\"file_parent\":107191,\"file_target\":\"\\/file3.txt\",\"share_with\":\"2|$argon2i$v=19$m=65536,t=4,p=1$SHd0ckwyeG1ieUcubThIRQ$+rO5YJNYmQAdrptAJFQAjq00QnfpTmkikZet\\/PKv3ZY\",\"share_with_displayname\":\"(Shared link)\",\"password\":\"2|$argon2i$v=19$m=65536,t=4,p=1$SHd0ckwyeG1ieUcubThIRQ$+rO5YJNYmQAdrptAJFQAjq00QnfpTmkikZet\\/PKv3ZY\",\"send_password_by_talk\":false,\"url\":\"https:\\/\\/mo.hobigo.de\\/s\\/HMHbFqsKfxGjjKi\",\"mail_send\":0,\"hide_download\":0}]}}", + contentType: "application/xml; charset=utf-8", + status: 200, + }, + }); + entries.push({ + request: { + description: "Share get", + method: "GET", + url: "/ocs/v2.php/apps/files_sharing/api/v1/shares/60", + }, + response: { + body: "{\"ocs\":{\"meta\":{\"status\":\"ok\",\"statuscode\":200,\"message\":\"OK\"},\"data\":[{\"id\":\"60\",\"share_type\":3,\"uid_owner\":\"htborstenson\",\"displayname_owner\":\"Horst-Thorsten Borstenson\",\"permissions\":1,\"can_edit\":true,\"can_delete\":true,\"stime\":1580171571,\"parent\":null,\"expiration\":null,\"token\":\"HMHbFqsKfxGjjKi\",\"uid_file_owner\":\"htborstenson\",\"note\":\"\",\"label\":\"\",\"displayname_file_owner\":\"Horst-Thorsten Borstenson\",\"path\":\"\\/ncncTest\\/share1\\/file3.txt\",\"item_type\":\"folder\",\"mimetype\":\"text\\/plain\",\"storage_id\":\"home::htborstenson\",\"storage\":3,\"item_source\":107213,\"file_source\":107213,\"file_parent\":107191,\"file_target\":\"\\/file3.txt\",\"share_with\":\"2|$argon2i$v=19$m=65536,t=4,p=1$SHd0ckwyeG1ieUcubThIRQ$+rO5YJNYmQAdrptAJFQAjq00QnfpTmkikZet\\/PKv3ZY\",\"share_with_displayname\":\"(Shared link)\",\"password\":\"2|$argon2i$v=19$m=65536,t=4,p=1$SHd0ckwyeG1ieUcubThIRQ$+rO5YJNYmQAdrptAJFQAjq00QnfpTmkikZet\\/PKv3ZY\",\"send_password_by_talk\":false,\"url\":\"https:\\/\\/mo.hobigo.de\\/s\\/HMHbFqsKfxGjjKi\",\"mail_send\":0,\"hide_download\":0}]}}", + contentType: "application/xml; charset=utf-8", + status: 200, + }, + }); + entries.push({ + request: { + description: "Share get", + method: "GET", + url: "/ocs/v2.php/apps/files_sharing/api/v1/shares/60", + }, + response: { + body: "{\"ocs\":{\"meta\":{\"status\":\"ok\",\"statuscode\":200,\"message\":\"OK\"},\"data\":[{\"id\":\"60\",\"share_type\":3,\"uid_owner\":\"htborstenson\",\"displayname_owner\":\"Horst-Thorsten Borstenson\",\"permissions\":1,\"can_edit\":true,\"can_delete\":true,\"stime\":1580171571,\"parent\":null,\"expiration\":null,\"token\":\"HMHbFqsKfxGjjKi\",\"uid_file_owner\":\"htborstenson\",\"note\":\"\",\"label\":\"\",\"displayname_file_owner\":\"Horst-Thorsten Borstenson\",\"path\":\"\\/ncncTest\\/share1\\/file3.txt\",\"item_type\":\"file\",\"mimetype\":\"text\\/plain\",\"storage_id\":\"home::htborstenson\",\"storage\":3,\"item_source\":107213,\"file_source\":107213,\"file_parent\":107191,\"file_target\":\"\\/file3.txt\",\"share_with\":\"2|$argon2i$v=19$m=65536,t=4,p=1$SHd0ckwyeG1ieUcubThIRQ$+rO5YJNYmQAdrptAJFQAjq00QnfpTmkikZet\\/PKv3ZY\",\"share_with_displayname\":\"(Shared link)\",\"password\":\"2|$argon2i$v=19$m=65536,t=4,p=1$SHd0ckwyeG1ieUcubThIRQ$+rO5YJNYmQAdrptAJFQAjq00QnfpTmkikZet\\/PKv3ZY\",\"send_password_by_talk\":false,\"url\":\"https:\\/\\/mo.hobigo.de\\/s\\/HMHbFqsKfxGjjKi\",\"mail_send\":0,\"hide_download\":0}]}}", + contentType: "application/xml; charset=utf-8", + status: 200, + }, + }); + entries.push({ + request: { + description: "Share get", + method: "GET", + url: "/ocs/v2.php/apps/files_sharing/api/v1/shares/60", + }, + response: { + body: "{\"ocs\":{\"meta\":{\"status\":\"ok\",\"statuscode\":200,\"message\":\"OK\"},\"data\":[{\"id\":\"60\",\"share_type\":3,\"uid_owner\":\"htborstenson\",\"displayname_owner\":\"Horst-Thorsten Borstenson\",\"permissions\":1,\"can_edit\":true,\"can_delete\":true,\"stime\":1580171571,\"parent\":null,\"expiration\":\"2020-12-04\",\"token\":\"HMHbFqsKfxGjjKi\",\"uid_file_owner\":\"htborstenson\",\"note\":\"\",\"label\":\"\",\"displayname_file_owner\":\"Horst-Thorsten Borstenson\",\"path\":\"\\/ncncTest\\/share1\\/file3.txt\",\"item_type\":\"file\",\"mimetype\":\"text\\/plain\",\"storage_id\":\"home::htborstenson\",\"storage\":3,\"item_source\":107213,\"file_source\":107213,\"file_parent\":107191,\"file_target\":\"\\/file3.txt\",\"share_with\":\"2|$argon2i$v=19$m=65536,t=4,p=1$SHd0ckwyeG1ieUcubThIRQ$+rO5YJNYmQAdrptAJFQAjq00QnfpTmkikZet\\/PKv3ZY\",\"share_with_displayname\":\"(Shared link)\",\"password\":\"2|$argon2i$v=19$m=65536,t=4,p=1$SHd0ckwyeG1ieUcubThIRQ$+rO5YJNYmQAdrptAJFQAjq00QnfpTmkikZet\\/PKv3ZY\",\"send_password_by_talk\":false,\"url\":\"https:\\/\\/mo.hobigo.de\\/s\\/HMHbFqsKfxGjjKi\",\"mail_send\":0,\"hide_download\":0}]}}", + contentType: "application/xml; charset=utf-8", + status: 200, + }, + }); + entries.push({ + request: { + description: "Share get", + method: "GET", + url: "/ocs/v2.php/apps/files_sharing/api/v1/shares/60", + }, + response: { + body: "{\"ocs\":{\"meta\":{\"status\":\"ok\",\"statuscode\":200,\"message\":\"OK\"},\"data\":[{\"id\":\"60\",\"share_type\":3,\"uid_owner\":\"htborstenson\",\"displayname_owner\":\"Horst-Thorsten Borstenson\",\"permissions\":1,\"can_edit\":true,\"can_delete\":true,\"stime\":1580171571,\"parent\":null,\"expiration\":\"2020-12-04\",\"token\":\"HMHbFqsKfxGjjKi\",\"uid_file_owner\":\"htborstenson\",\"note\":\"note test\",\"label\":\"\",\"displayname_file_owner\":\"Horst-Thorsten Borstenson\",\"path\":\"\\/ncncTest\\/share1\\/file3.txt\",\"item_type\":\"file\",\"mimetype\":\"text\\/plain\",\"storage_id\":\"home::htborstenson\",\"storage\":3,\"item_source\":107213,\"file_source\":107213,\"file_parent\":107191,\"file_target\":\"\\/file3.txt\",\"share_with\":\"2|$argon2i$v=19$m=65536,t=4,p=1$SHd0ckwyeG1ieUcubThIRQ$+rO5YJNYmQAdrptAJFQAjq00QnfpTmkikZet\\/PKv3ZY\",\"share_with_displayname\":\"(Shared link)\",\"password\":\"2|$argon2i$v=19$m=65536,t=4,p=1$SHd0ckwyeG1ieUcubThIRQ$+rO5YJNYmQAdrptAJFQAjq00QnfpTmkikZet\\/PKv3ZY\",\"send_password_by_talk\":false,\"url\":\"https:\\/\\/mo.hobigo.de\\/s\\/HMHbFqsKfxGjjKi\",\"mail_send\":0,\"hide_download\":0}]}}", + contentType: "application/xml; charset=utf-8", + status: 200, + }, + }); + const lclient = new client_1.Client(new fakeServer_1.default(entries)); + let errorCode = "noError"; + try { + yield share_1.default.getShare(lclient, "60"); + } + catch (e) { + errorCode = e.code; + } + (0, chai_1.expect)(errorCode, "expect an exception").to.be.equal("ERR_INVALID_SHARE_RESPONSE"); + errorCode = "noError"; + try { + yield share_1.default.getShare(lclient, "60"); + } + catch (e) { + errorCode = e.code; + } + (0, chai_1.expect)(errorCode, "expect an exception").to.be.equal("ERR_INVALID_SHARE_RESPONSE"); + errorCode = "noError"; + try { + yield share_1.default.getShare(lclient, "60"); + } + catch (e) { + errorCode = e.code; + } + (0, chai_1.expect)(errorCode, "expect an exception").to.be.equal("ERR_INVALID_SHARE_RESPONSE"); + errorCode = "noError"; + try { + yield share_1.default.getShare(lclient, "60"); + } + catch (e) { + errorCode = e.code; + } + (0, chai_1.expect)(errorCode, "expect an exception").to.be.equal("ERR_INVALID_SHARE_RESPONSE"); + errorCode = "noError"; + try { + yield share_1.default.getShare(lclient, "60"); + } + catch (e) { + (0, chai_1.expect)(e.message, "expect no exception").to.be.equal("expect no exception"); + } + errorCode = "noError"; + try { + yield share_1.default.getShare(lclient, "60"); + } + catch (e) { + (0, chai_1.expect)(e.message, "expect no exception").to.be.equal("expect no exception"); + } + errorCode = "noError"; + try { + yield share_1.default.getShare(lclient, "60"); + } + catch (e) { + (0, chai_1.expect)(e.message, "expect no exception").to.be.equal("expect no exception"); + } + errorCode = "noError"; + try { + yield share_1.default.getShare(lclient, "60"); + } + catch (e) { + (0, chai_1.expect)(e.message, "expect no exception").to.be.equal("expect no exception"); + } + })); + it("03 create public share for folder", () => __awaiter(this, void 0, void 0, function* () { + const folderName = "/ncncTest/share/03/publicUploadFolder"; + const folder = yield client.createFolder(folderName); + const createShare = { fileSystemElement: folder, publicUpload: true }; + let share; + let error = null; + try { + share = yield client.createShare(createShare); + } + catch (e) { + error = e; + } + (0, chai_1.expect)(error).to.be.equal(null); + (0, chai_1.expect)(share.publicUpload).to.be.equal(true); + yield folder.delete(); + })); +}); diff --git a/src/test/13.share.test.ts b/src/test/13.share.test.ts index 22fe08c2..17beb21a 100644 --- a/src/test/13.share.test.ts +++ b/src/test/13.share.test.ts @@ -1,16 +1,10 @@ - import { expect } from "chai"; // if you used the '@types/mocha' method to install mocha type definitions, uncomment the following line import "mocha"; -import { - Client, - File, - Folder, - ICreateShare, -} from "../client"; +import { Client, File, Folder, ICreateShare } from "../client"; import FakeServer from "../fakeServer"; import RequestResponseLogEntry from "../requestResponseLogEntry"; -import Share from "../share"; +import Share, { SharePermission, ShareType } from "../share"; import { getNextcloudClient } from "./testUtils"; let client: Client; @@ -18,267 +12,345 @@ let client: Client; // tslint:disable-next-line:only-arrow-functions // tslint:disable-next-line:space-before-function-paren describe("13-NEXCLOUD-NODE-CLIENT-SHARE", function () { - - // tslint:disable-next-line:space-before-function-paren - beforeEach(async function () { - if (this.currentTest && this.currentTest.parent) { - client = await getNextcloudClient(this.currentTest.parent.title + "/" + this.currentTest.title); - } + // tslint:disable-next-line:space-before-function-paren + beforeEach(async function () { + if (this.currentTest && this.currentTest.parent) { + client = await getNextcloudClient( + this.currentTest.parent.title + "/" + this.currentTest.title + ); + } + }); + + this.timeout(1 * 60 * 1000); + + it("01 create public share", async () => { + const fileName = "/ncncTest/share1/file3.txt"; + + let file: File; + + file = await client.createFile( + fileName, + Buffer.from("this is a test text") + ); + + // const createShare: ICreateShare = { fileSystemElement: file, password: "password 1", publicUpload: true }; + let createShare: ICreateShare = { + fileSystemElement: file, + password: "password 1", + publicUpload: false, + shareType: ShareType.publicLink, + permissions: SharePermission.all + }; + + let share: Share; + + try { + share = await client.createShare(createShare); + + expect(share.id).to.be.a("string"); + expect(share.id.length).to.be.greaterThan(0); + expect(share.url).to.be.a("string"); + expect(share.url?.length).to.be.greaterThan(0); + expect(share.token).to.be.a("string"); + expect(share.token?.length).to.be.greaterThan(0); + + try { + await share.setPassword("some password"); + } catch (e) { + expect(e.message, "expect no exception setting password").to.be.equal( + null + ); + } + + expect(share.note).to.be.equal(""); + try { + const note: string = "This is a Note\nNew Line"; + await share.setNote(note); + expect(share.note).to.be.equal(note); + } catch (e) { + expect(e.message, "expect no exception setting note").to.be.equal(null); + } + + try { + await share.setExpiration(new Date(2020, 11, 5)); + expect(share.expiration).to.be.a("Date"); + } catch (e) { + expect(e.message, "expect no exception setting expiration").to.be.equal( + null + ); + } + + try { + await share.delete(); + } catch (e) { + expect(e.message, "expect no exception deleting share").to.be.equal( + null + ); + } + } catch (e) { + expect(e.message, "expect no exception").to.be.equal(null); + } + + createShare = { + fileSystemElement: file, + publicUpload: true, + shareType: ShareType.publicLink, + permissions: SharePermission.all + }; + try { + share = await client.createShare(createShare); + } catch (e) { + expect(e.message, "expect no exception 'publicUpload:true'").to.be.equal( + null + ); + } + + await file.delete(); + }); + + it("02 invalid share responses", async () => { + const entries: RequestResponseLogEntry[] = []; + entries.push({ + request: { + description: "Share get", + method: "GET", + url: "/ocs/v2.php/apps/files_sharing/api/v1/shares/60" + }, + response: { + body: '{"ocsXXX":{"meta":{"status":"ok","statuscode":200,"message":"OK"},"data":[{"id":"60","share_type":3,"uid_owner":"htborstenson","displayname_owner":"Horst-Thorsten Borstenson","permissions":1,"can_edit":true,"can_delete":true,"stime":1580171571,"parent":null,"expiration":null,"token":"HMHbFqsKfxGjjKi","uid_file_owner":"htborstenson","note":"","label":"","displayname_file_owner":"Horst-Thorsten Borstenson","path":"\\/ncncTest\\/share1\\/file3.txt","item_type":"file","mimetype":"text\\/plain","storage_id":"home::htborstenson","storage":3,"item_source":107213,"file_source":107213,"file_parent":107191,"file_target":"\\/file3.txt","share_with":"2|$argon2i$v=19$m=65536,t=4,p=1$SHd0ckwyeG1ieUcubThIRQ$+rO5YJNYmQAdrptAJFQAjq00QnfpTmkikZet\\/PKv3ZY","share_with_displayname":"(Shared link)","password":"2|$argon2i$v=19$m=65536,t=4,p=1$SHd0ckwyeG1ieUcubThIRQ$+rO5YJNYmQAdrptAJFQAjq00QnfpTmkikZet\\/PKv3ZY","send_password_by_talk":false,"url":"https:\\/\\/mo.hobigo.de\\/s\\/HMHbFqsKfxGjjKi","mail_send":0,"hide_download":0}]}}', + contentType: "application/xml; charset=utf-8", + status: 200 + } }); - this.timeout(1 * 60 * 1000); - - it("01 create public share", async () => { - - const fileName = "/ncncTest/share1/file3.txt"; - - let file: File; - - file = await client.createFile(fileName, Buffer.from("this is a test text")); - - // const createShare: ICreateShare = { fileSystemElement: file, password: "password 1", publicUpload: true }; - let createShare: ICreateShare = { fileSystemElement: file, password: "password 1", publicUpload: false }; - - let share: Share; - - try { - share = await client.createShare(createShare); - - expect(share.id).to.be.a("string"); - expect(share.id.length).to.be.greaterThan(0); - expect(share.url).to.be.a("string"); - expect(share.url.length).to.be.greaterThan(0); - expect(share.token).to.be.a("string"); - expect(share.token.length).to.be.greaterThan(0); - - try { - await share.setPassword("some password"); - } catch (e) { - expect(e.message, "expect no exception setting password").to.be.equal(null); - } - - expect(share.note).to.be.equal(""); - try { - const note: string = "This is a Note\nNew Line"; - await share.setNote(note); - expect(share.note).to.be.equal(note); - } catch (e) { - expect(e.message, "expect no exception setting note").to.be.equal(null); - } - - try { - await share.setExpiration(new Date(2020, 11, 5)); - expect(share.expiration).to.be.a("Date"); - } catch (e) { - expect(e.message, "expect no exception setting expiration").to.be.equal(null); - } - - try { - await share.delete(); - } catch (e) { - expect(e.message, "expect no exception deleting share").to.be.equal(null); - } - - } catch (e) { - expect(e.message, "expect no exception").to.be.equal(null); - } - - createShare = { fileSystemElement: file, publicUpload: true }; - try { - share = await client.createShare(createShare); - } catch (e) { - expect(e.message, "expect no exception 'publicUpload:true'").to.be.equal(null); - } - - await file.delete(); + entries.push({ + request: { + description: "Share get", + method: "GET", + url: "/ocs/v2.php/apps/files_sharing/api/v1/shares/60" + }, + response: { + body: '{"ocs":{"meta":{"status":"ok","statuscode":200,"message":"OK"},"data":[{"id":"60","share_type":3,"uid_owner":"htborstenson","displayname_owner":"Horst-Thorsten Borstenson","permissions":1,"can_edit":true,"can_delete":true,"stime":1580171571,"parent":null,"expiration":null,"token":"HMHbFqsKfxGjjKi","uid_file_owner":"htborstenson","note":"","label":"","displayname_file_owner":"Horst-Thorsten Borstenson","path":"\\/ncncTest\\/share1\\/file3.txt","item_type":"file","mimetype":"text\\/plain","storage_id":"home::htborstenson","storage":3,"item_source":107213,"file_source":107213,"file_parent":107191,"file_target":"\\/file3.txt","share_with":"2|$argon2i$v=19$m=65536,t=4,p=1$SHd0ckwyeG1ieUcubThIRQ$+rO5YJNYmQAdrptAJFQAjq00QnfpTmkikZet\\/PKv3ZY","share_with_displayname":"(Shared link)","password":"2|$argon2i$v=19$m=65536,t=4,p=1$SHd0ckwyeG1ieUcubThIRQ$+rO5YJNYmQAdrptAJFQAjq00QnfpTmkikZet\\/PKv3ZY","send_password_by_talk":false,"urlXXX":"https:\\/\\/mo.hobigo.de\\/s\\/HMHbFqsKfxGjjKi","mail_send":0,"hide_download":0}]}}', + contentType: "application/xml; charset=utf-8", + status: 200 + } }); - it("02 invalid share responses", async () => { - - const entries: RequestResponseLogEntry[] = []; - entries.push({ - request: { - description: "Share get", - method: "GET", - url: "/ocs/v2.php/apps/files_sharing/api/v1/shares/60", - }, - response: { - body: "{\"ocsXXX\":{\"meta\":{\"status\":\"ok\",\"statuscode\":200,\"message\":\"OK\"},\"data\":[{\"id\":\"60\",\"share_type\":3,\"uid_owner\":\"htborstenson\",\"displayname_owner\":\"Horst-Thorsten Borstenson\",\"permissions\":1,\"can_edit\":true,\"can_delete\":true,\"stime\":1580171571,\"parent\":null,\"expiration\":null,\"token\":\"HMHbFqsKfxGjjKi\",\"uid_file_owner\":\"htborstenson\",\"note\":\"\",\"label\":\"\",\"displayname_file_owner\":\"Horst-Thorsten Borstenson\",\"path\":\"\\/ncncTest\\/share1\\/file3.txt\",\"item_type\":\"file\",\"mimetype\":\"text\\/plain\",\"storage_id\":\"home::htborstenson\",\"storage\":3,\"item_source\":107213,\"file_source\":107213,\"file_parent\":107191,\"file_target\":\"\\/file3.txt\",\"share_with\":\"2|$argon2i$v=19$m=65536,t=4,p=1$SHd0ckwyeG1ieUcubThIRQ$+rO5YJNYmQAdrptAJFQAjq00QnfpTmkikZet\\/PKv3ZY\",\"share_with_displayname\":\"(Shared link)\",\"password\":\"2|$argon2i$v=19$m=65536,t=4,p=1$SHd0ckwyeG1ieUcubThIRQ$+rO5YJNYmQAdrptAJFQAjq00QnfpTmkikZet\\/PKv3ZY\",\"send_password_by_talk\":false,\"url\":\"https:\\/\\/mo.hobigo.de\\/s\\/HMHbFqsKfxGjjKi\",\"mail_send\":0,\"hide_download\":0}]}}", - contentType: "application/xml; charset=utf-8", - status: 200, - }, - }); - - entries.push({ - request: { - description: "Share get", - method: "GET", - url: "/ocs/v2.php/apps/files_sharing/api/v1/shares/60", - }, - response: { - body: "{\"ocs\":{\"meta\":{\"status\":\"ok\",\"statuscode\":200,\"message\":\"OK\"},\"data\":[{\"id\":\"60\",\"share_type\":3,\"uid_owner\":\"htborstenson\",\"displayname_owner\":\"Horst-Thorsten Borstenson\",\"permissions\":1,\"can_edit\":true,\"can_delete\":true,\"stime\":1580171571,\"parent\":null,\"expiration\":null,\"token\":\"HMHbFqsKfxGjjKi\",\"uid_file_owner\":\"htborstenson\",\"note\":\"\",\"label\":\"\",\"displayname_file_owner\":\"Horst-Thorsten Borstenson\",\"path\":\"\\/ncncTest\\/share1\\/file3.txt\",\"item_type\":\"file\",\"mimetype\":\"text\\/plain\",\"storage_id\":\"home::htborstenson\",\"storage\":3,\"item_source\":107213,\"file_source\":107213,\"file_parent\":107191,\"file_target\":\"\\/file3.txt\",\"share_with\":\"2|$argon2i$v=19$m=65536,t=4,p=1$SHd0ckwyeG1ieUcubThIRQ$+rO5YJNYmQAdrptAJFQAjq00QnfpTmkikZet\\/PKv3ZY\",\"share_with_displayname\":\"(Shared link)\",\"password\":\"2|$argon2i$v=19$m=65536,t=4,p=1$SHd0ckwyeG1ieUcubThIRQ$+rO5YJNYmQAdrptAJFQAjq00QnfpTmkikZet\\/PKv3ZY\",\"send_password_by_talk\":false,\"urlXXX\":\"https:\\/\\/mo.hobigo.de\\/s\\/HMHbFqsKfxGjjKi\",\"mail_send\":0,\"hide_download\":0}]}}", - contentType: "application/xml; charset=utf-8", - status: 200, - }, - }); - - entries.push({ - request: { - description: "Share get", - method: "GET", - url: "/ocs/v2.php/apps/files_sharing/api/v1/shares/60", - }, - response: { - body: "{\"ocs\":{\"meta\":{\"status\":\"ok\",\"statuscode\":200,\"message\":\"OK\"},\"data\":[{\"id\":\"60\",\"share_type\":3,\"uid_owner\":\"htborstenson\",\"displayname_owner\":\"Horst-Thorsten Borstenson\",\"permissions\":1,\"can_edit\":true,\"can_delete\":true,\"stime\":1580171571,\"parent\":null,\"expiration\":null,\"XXXtoken\":\"HMHbFqsKfxGjjKi\",\"uid_file_owner\":\"htborstenson\",\"note\":\"\",\"label\":\"\",\"displayname_file_owner\":\"Horst-Thorsten Borstenson\",\"path\":\"\\/ncncTest\\/share1\\/file3.txt\",\"item_type\":\"file\",\"mimetype\":\"text\\/plain\",\"storage_id\":\"home::htborstenson\",\"storage\":3,\"item_source\":107213,\"file_source\":107213,\"file_parent\":107191,\"file_target\":\"\\/file3.txt\",\"share_with\":\"2|$argon2i$v=19$m=65536,t=4,p=1$SHd0ckwyeG1ieUcubThIRQ$+rO5YJNYmQAdrptAJFQAjq00QnfpTmkikZet\\/PKv3ZY\",\"share_with_displayname\":\"(Shared link)\",\"password\":\"2|$argon2i$v=19$m=65536,t=4,p=1$SHd0ckwyeG1ieUcubThIRQ$+rO5YJNYmQAdrptAJFQAjq00QnfpTmkikZet\\/PKv3ZY\",\"send_password_by_talk\":false,\"url\":\"https:\\/\\/mo.hobigo.de\\/s\\/HMHbFqsKfxGjjKi\",\"mail_send\":0,\"hide_download\":0}]}}", - contentType: "application/xml; charset=utf-8", - status: 200, - }, - }); - entries.push({ - request: { - description: "Share get", - method: "GET", - url: "/ocs/v2.php/apps/files_sharing/api/v1/shares/60", - }, - response: { - body: "{\"ocs\":{\"meta\":{\"status\":\"ok\",\"statuscode\":200,\"message\":\"OK\"},\"data\":[{\"id\":\"60\",\"share_type\":3,\"uid_owner\":\"htborstenson\",\"displayname_owner\":\"Horst-Thorsten Borstenson\",\"permissions\":1,\"can_edit\":true,\"can_delete\":true,\"stime\":1580171571,\"parent\":null,\"expiration\":null,\"token\":\"HMHbFqsKfxGjjKi\",\"uid_file_owner\":\"htborstenson\",\"note\":\"\",\"label\":\"\",\"displayname_file_owner\":\"Horst-Thorsten Borstenson\",\"path\":\"\\/ncncTest\\/share1\\/file3.txt\",\"XXXitem_type\":\"file\",\"mimetype\":\"text\\/plain\",\"storage_id\":\"home::htborstenson\",\"storage\":3,\"item_source\":107213,\"file_source\":107213,\"file_parent\":107191,\"file_target\":\"\\/file3.txt\",\"share_with\":\"2|$argon2i$v=19$m=65536,t=4,p=1$SHd0ckwyeG1ieUcubThIRQ$+rO5YJNYmQAdrptAJFQAjq00QnfpTmkikZet\\/PKv3ZY\",\"share_with_displayname\":\"(Shared link)\",\"password\":\"2|$argon2i$v=19$m=65536,t=4,p=1$SHd0ckwyeG1ieUcubThIRQ$+rO5YJNYmQAdrptAJFQAjq00QnfpTmkikZet\\/PKv3ZY\",\"send_password_by_talk\":false,\"url\":\"https:\\/\\/mo.hobigo.de\\/s\\/HMHbFqsKfxGjjKi\",\"mail_send\":0,\"hide_download\":0}]}}", - contentType: "application/xml; charset=utf-8", - status: 200, - }, - }); - entries.push({ - request: { - description: "Share get", - method: "GET", - url: "/ocs/v2.php/apps/files_sharing/api/v1/shares/60", - }, - response: { - body: "{\"ocs\":{\"meta\":{\"status\":\"ok\",\"statuscode\":200,\"message\":\"OK\"},\"data\":[{\"id\":\"60\",\"share_type\":3,\"uid_owner\":\"htborstenson\",\"displayname_owner\":\"Horst-Thorsten Borstenson\",\"permissions\":1,\"can_edit\":true,\"can_delete\":true,\"stime\":1580171571,\"parent\":null,\"expiration\":null,\"token\":\"HMHbFqsKfxGjjKi\",\"uid_file_owner\":\"htborstenson\",\"note\":\"\",\"label\":\"\",\"displayname_file_owner\":\"Horst-Thorsten Borstenson\",\"path\":\"\\/ncncTest\\/share1\\/file3.txt\",\"item_type\":\"folder\",\"mimetype\":\"text\\/plain\",\"storage_id\":\"home::htborstenson\",\"storage\":3,\"item_source\":107213,\"file_source\":107213,\"file_parent\":107191,\"file_target\":\"\\/file3.txt\",\"share_with\":\"2|$argon2i$v=19$m=65536,t=4,p=1$SHd0ckwyeG1ieUcubThIRQ$+rO5YJNYmQAdrptAJFQAjq00QnfpTmkikZet\\/PKv3ZY\",\"share_with_displayname\":\"(Shared link)\",\"password\":\"2|$argon2i$v=19$m=65536,t=4,p=1$SHd0ckwyeG1ieUcubThIRQ$+rO5YJNYmQAdrptAJFQAjq00QnfpTmkikZet\\/PKv3ZY\",\"send_password_by_talk\":false,\"url\":\"https:\\/\\/mo.hobigo.de\\/s\\/HMHbFqsKfxGjjKi\",\"mail_send\":0,\"hide_download\":0}]}}", - contentType: "application/xml; charset=utf-8", - status: 200, - }, - }); - entries.push({ - request: { - description: "Share get", - method: "GET", - url: "/ocs/v2.php/apps/files_sharing/api/v1/shares/60", - }, - response: { - body: "{\"ocs\":{\"meta\":{\"status\":\"ok\",\"statuscode\":200,\"message\":\"OK\"},\"data\":[{\"id\":\"60\",\"share_type\":3,\"uid_owner\":\"htborstenson\",\"displayname_owner\":\"Horst-Thorsten Borstenson\",\"permissions\":1,\"can_edit\":true,\"can_delete\":true,\"stime\":1580171571,\"parent\":null,\"expiration\":null,\"token\":\"HMHbFqsKfxGjjKi\",\"uid_file_owner\":\"htborstenson\",\"note\":\"\",\"label\":\"\",\"displayname_file_owner\":\"Horst-Thorsten Borstenson\",\"path\":\"\\/ncncTest\\/share1\\/file3.txt\",\"item_type\":\"file\",\"mimetype\":\"text\\/plain\",\"storage_id\":\"home::htborstenson\",\"storage\":3,\"item_source\":107213,\"file_source\":107213,\"file_parent\":107191,\"file_target\":\"\\/file3.txt\",\"share_with\":\"2|$argon2i$v=19$m=65536,t=4,p=1$SHd0ckwyeG1ieUcubThIRQ$+rO5YJNYmQAdrptAJFQAjq00QnfpTmkikZet\\/PKv3ZY\",\"share_with_displayname\":\"(Shared link)\",\"password\":\"2|$argon2i$v=19$m=65536,t=4,p=1$SHd0ckwyeG1ieUcubThIRQ$+rO5YJNYmQAdrptAJFQAjq00QnfpTmkikZet\\/PKv3ZY\",\"send_password_by_talk\":false,\"url\":\"https:\\/\\/mo.hobigo.de\\/s\\/HMHbFqsKfxGjjKi\",\"mail_send\":0,\"hide_download\":0}]}}", - contentType: "application/xml; charset=utf-8", - status: 200, - }, - }); - entries.push({ - request: { - description: "Share get", - method: "GET", - url: "/ocs/v2.php/apps/files_sharing/api/v1/shares/60", - }, - response: { - body: "{\"ocs\":{\"meta\":{\"status\":\"ok\",\"statuscode\":200,\"message\":\"OK\"},\"data\":[{\"id\":\"60\",\"share_type\":3,\"uid_owner\":\"htborstenson\",\"displayname_owner\":\"Horst-Thorsten Borstenson\",\"permissions\":1,\"can_edit\":true,\"can_delete\":true,\"stime\":1580171571,\"parent\":null,\"expiration\":\"2020-12-04\",\"token\":\"HMHbFqsKfxGjjKi\",\"uid_file_owner\":\"htborstenson\",\"note\":\"\",\"label\":\"\",\"displayname_file_owner\":\"Horst-Thorsten Borstenson\",\"path\":\"\\/ncncTest\\/share1\\/file3.txt\",\"item_type\":\"file\",\"mimetype\":\"text\\/plain\",\"storage_id\":\"home::htborstenson\",\"storage\":3,\"item_source\":107213,\"file_source\":107213,\"file_parent\":107191,\"file_target\":\"\\/file3.txt\",\"share_with\":\"2|$argon2i$v=19$m=65536,t=4,p=1$SHd0ckwyeG1ieUcubThIRQ$+rO5YJNYmQAdrptAJFQAjq00QnfpTmkikZet\\/PKv3ZY\",\"share_with_displayname\":\"(Shared link)\",\"password\":\"2|$argon2i$v=19$m=65536,t=4,p=1$SHd0ckwyeG1ieUcubThIRQ$+rO5YJNYmQAdrptAJFQAjq00QnfpTmkikZet\\/PKv3ZY\",\"send_password_by_talk\":false,\"url\":\"https:\\/\\/mo.hobigo.de\\/s\\/HMHbFqsKfxGjjKi\",\"mail_send\":0,\"hide_download\":0}]}}", - contentType: "application/xml; charset=utf-8", - status: 200, - }, - }); - - entries.push({ - request: { - description: "Share get", - method: "GET", - url: "/ocs/v2.php/apps/files_sharing/api/v1/shares/60", - }, - response: { - body: "{\"ocs\":{\"meta\":{\"status\":\"ok\",\"statuscode\":200,\"message\":\"OK\"},\"data\":[{\"id\":\"60\",\"share_type\":3,\"uid_owner\":\"htborstenson\",\"displayname_owner\":\"Horst-Thorsten Borstenson\",\"permissions\":1,\"can_edit\":true,\"can_delete\":true,\"stime\":1580171571,\"parent\":null,\"expiration\":\"2020-12-04\",\"token\":\"HMHbFqsKfxGjjKi\",\"uid_file_owner\":\"htborstenson\",\"note\":\"note test\",\"label\":\"\",\"displayname_file_owner\":\"Horst-Thorsten Borstenson\",\"path\":\"\\/ncncTest\\/share1\\/file3.txt\",\"item_type\":\"file\",\"mimetype\":\"text\\/plain\",\"storage_id\":\"home::htborstenson\",\"storage\":3,\"item_source\":107213,\"file_source\":107213,\"file_parent\":107191,\"file_target\":\"\\/file3.txt\",\"share_with\":\"2|$argon2i$v=19$m=65536,t=4,p=1$SHd0ckwyeG1ieUcubThIRQ$+rO5YJNYmQAdrptAJFQAjq00QnfpTmkikZet\\/PKv3ZY\",\"share_with_displayname\":\"(Shared link)\",\"password\":\"2|$argon2i$v=19$m=65536,t=4,p=1$SHd0ckwyeG1ieUcubThIRQ$+rO5YJNYmQAdrptAJFQAjq00QnfpTmkikZet\\/PKv3ZY\",\"send_password_by_talk\":false,\"url\":\"https:\\/\\/mo.hobigo.de\\/s\\/HMHbFqsKfxGjjKi\",\"mail_send\":0,\"hide_download\":0}]}}", - contentType: "application/xml; charset=utf-8", - status: 200, - }, - }); - - const lclient: Client = new Client(new FakeServer(entries)); - let errorCode: string = "noError"; - try { - await Share.getShare(lclient, "60"); - } catch (e) { - errorCode = e.code; - } - expect(errorCode, "expect an exception").to.be.equal("ERR_INVALID_SHARE_RESPONSE"); - - errorCode = "noError"; - try { - await Share.getShare(lclient, "60"); - } catch (e) { - errorCode = e.code; - } - expect(errorCode, "expect an exception").to.be.equal("ERR_INVALID_SHARE_RESPONSE"); - - errorCode = "noError"; - try { - await Share.getShare(lclient, "60"); - } catch (e) { - errorCode = e.code; - } - expect(errorCode, "expect an exception").to.be.equal("ERR_INVALID_SHARE_RESPONSE"); - - errorCode = "noError"; - try { - await Share.getShare(lclient, "60"); - } catch (e) { - errorCode = e.code; - } - expect(errorCode, "expect an exception").to.be.equal("ERR_INVALID_SHARE_RESPONSE"); - - errorCode = "noError"; - try { - await Share.getShare(lclient, "60"); - } catch (e) { - expect(e.message, "expect no exception").to.be.equal("expect no exception"); - } - - errorCode = "noError"; - try { - await Share.getShare(lclient, "60"); - } catch (e) { - expect(e.message, "expect no exception").to.be.equal("expect no exception"); - } - - errorCode = "noError"; - try { - await Share.getShare(lclient, "60"); - } catch (e) { - expect(e.message, "expect no exception").to.be.equal("expect no exception"); - } - - errorCode = "noError"; - try { - await Share.getShare(lclient, "60"); - } catch (e) { - expect(e.message, "expect no exception").to.be.equal("expect no exception"); - } - + entries.push({ + request: { + description: "Share get", + method: "GET", + url: "/ocs/v2.php/apps/files_sharing/api/v1/shares/60" + }, + response: { + body: '{"ocs":{"meta":{"status":"ok","statuscode":200,"message":"OK"},"data":[{"id":"60","share_type":3,"uid_owner":"htborstenson","displayname_owner":"Horst-Thorsten Borstenson","permissions":1,"can_edit":true,"can_delete":true,"stime":1580171571,"parent":null,"expiration":null,"XXXtoken":"HMHbFqsKfxGjjKi","uid_file_owner":"htborstenson","note":"","label":"","displayname_file_owner":"Horst-Thorsten Borstenson","path":"\\/ncncTest\\/share1\\/file3.txt","item_type":"file","mimetype":"text\\/plain","storage_id":"home::htborstenson","storage":3,"item_source":107213,"file_source":107213,"file_parent":107191,"file_target":"\\/file3.txt","share_with":"2|$argon2i$v=19$m=65536,t=4,p=1$SHd0ckwyeG1ieUcubThIRQ$+rO5YJNYmQAdrptAJFQAjq00QnfpTmkikZet\\/PKv3ZY","share_with_displayname":"(Shared link)","password":"2|$argon2i$v=19$m=65536,t=4,p=1$SHd0ckwyeG1ieUcubThIRQ$+rO5YJNYmQAdrptAJFQAjq00QnfpTmkikZet\\/PKv3ZY","send_password_by_talk":false,"url":"https:\\/\\/mo.hobigo.de\\/s\\/HMHbFqsKfxGjjKi","mail_send":0,"hide_download":0}]}}', + contentType: "application/xml; charset=utf-8", + status: 200 + } + }); + entries.push({ + request: { + description: "Share get", + method: "GET", + url: "/ocs/v2.php/apps/files_sharing/api/v1/shares/60" + }, + response: { + body: '{"ocs":{"meta":{"status":"ok","statuscode":200,"message":"OK"},"data":[{"id":"60","share_type":3,"uid_owner":"htborstenson","displayname_owner":"Horst-Thorsten Borstenson","permissions":1,"can_edit":true,"can_delete":true,"stime":1580171571,"parent":null,"expiration":null,"token":"HMHbFqsKfxGjjKi","uid_file_owner":"htborstenson","note":"","label":"","displayname_file_owner":"Horst-Thorsten Borstenson","path":"\\/ncncTest\\/share1\\/file3.txt","XXXitem_type":"file","mimetype":"text\\/plain","storage_id":"home::htborstenson","storage":3,"item_source":107213,"file_source":107213,"file_parent":107191,"file_target":"\\/file3.txt","share_with":"2|$argon2i$v=19$m=65536,t=4,p=1$SHd0ckwyeG1ieUcubThIRQ$+rO5YJNYmQAdrptAJFQAjq00QnfpTmkikZet\\/PKv3ZY","share_with_displayname":"(Shared link)","password":"2|$argon2i$v=19$m=65536,t=4,p=1$SHd0ckwyeG1ieUcubThIRQ$+rO5YJNYmQAdrptAJFQAjq00QnfpTmkikZet\\/PKv3ZY","send_password_by_talk":false,"url":"https:\\/\\/mo.hobigo.de\\/s\\/HMHbFqsKfxGjjKi","mail_send":0,"hide_download":0}]}}', + contentType: "application/xml; charset=utf-8", + status: 200 + } + }); + entries.push({ + request: { + description: "Share get", + method: "GET", + url: "/ocs/v2.php/apps/files_sharing/api/v1/shares/60" + }, + response: { + body: '{"ocs":{"meta":{"status":"ok","statuscode":200,"message":"OK"},"data":[{"id":"60","share_type":3,"uid_owner":"htborstenson","displayname_owner":"Horst-Thorsten Borstenson","permissions":1,"can_edit":true,"can_delete":true,"stime":1580171571,"parent":null,"expiration":null,"token":"HMHbFqsKfxGjjKi","uid_file_owner":"htborstenson","note":"","label":"","displayname_file_owner":"Horst-Thorsten Borstenson","path":"\\/ncncTest\\/share1\\/file3.txt","item_type":"folder","mimetype":"text\\/plain","storage_id":"home::htborstenson","storage":3,"item_source":107213,"file_source":107213,"file_parent":107191,"file_target":"\\/file3.txt","share_with":"2|$argon2i$v=19$m=65536,t=4,p=1$SHd0ckwyeG1ieUcubThIRQ$+rO5YJNYmQAdrptAJFQAjq00QnfpTmkikZet\\/PKv3ZY","share_with_displayname":"(Shared link)","password":"2|$argon2i$v=19$m=65536,t=4,p=1$SHd0ckwyeG1ieUcubThIRQ$+rO5YJNYmQAdrptAJFQAjq00QnfpTmkikZet\\/PKv3ZY","send_password_by_talk":false,"url":"https:\\/\\/mo.hobigo.de\\/s\\/HMHbFqsKfxGjjKi","mail_send":0,"hide_download":0}]}}', + contentType: "application/xml; charset=utf-8", + status: 200 + } + }); + entries.push({ + request: { + description: "Share get", + method: "GET", + url: "/ocs/v2.php/apps/files_sharing/api/v1/shares/60" + }, + response: { + body: '{"ocs":{"meta":{"status":"ok","statuscode":200,"message":"OK"},"data":[{"id":"60","share_type":3,"uid_owner":"htborstenson","displayname_owner":"Horst-Thorsten Borstenson","permissions":1,"can_edit":true,"can_delete":true,"stime":1580171571,"parent":null,"expiration":null,"token":"HMHbFqsKfxGjjKi","uid_file_owner":"htborstenson","note":"","label":"","displayname_file_owner":"Horst-Thorsten Borstenson","path":"\\/ncncTest\\/share1\\/file3.txt","item_type":"file","mimetype":"text\\/plain","storage_id":"home::htborstenson","storage":3,"item_source":107213,"file_source":107213,"file_parent":107191,"file_target":"\\/file3.txt","share_with":"2|$argon2i$v=19$m=65536,t=4,p=1$SHd0ckwyeG1ieUcubThIRQ$+rO5YJNYmQAdrptAJFQAjq00QnfpTmkikZet\\/PKv3ZY","share_with_displayname":"(Shared link)","password":"2|$argon2i$v=19$m=65536,t=4,p=1$SHd0ckwyeG1ieUcubThIRQ$+rO5YJNYmQAdrptAJFQAjq00QnfpTmkikZet\\/PKv3ZY","send_password_by_talk":false,"url":"https:\\/\\/mo.hobigo.de\\/s\\/HMHbFqsKfxGjjKi","mail_send":0,"hide_download":0}]}}', + contentType: "application/xml; charset=utf-8", + status: 200 + } + }); + entries.push({ + request: { + description: "Share get", + method: "GET", + url: "/ocs/v2.php/apps/files_sharing/api/v1/shares/60" + }, + response: { + body: '{"ocs":{"meta":{"status":"ok","statuscode":200,"message":"OK"},"data":[{"id":"60","share_type":3,"uid_owner":"htborstenson","displayname_owner":"Horst-Thorsten Borstenson","permissions":1,"can_edit":true,"can_delete":true,"stime":1580171571,"parent":null,"expiration":"2020-12-04","token":"HMHbFqsKfxGjjKi","uid_file_owner":"htborstenson","note":"","label":"","displayname_file_owner":"Horst-Thorsten Borstenson","path":"\\/ncncTest\\/share1\\/file3.txt","item_type":"file","mimetype":"text\\/plain","storage_id":"home::htborstenson","storage":3,"item_source":107213,"file_source":107213,"file_parent":107191,"file_target":"\\/file3.txt","share_with":"2|$argon2i$v=19$m=65536,t=4,p=1$SHd0ckwyeG1ieUcubThIRQ$+rO5YJNYmQAdrptAJFQAjq00QnfpTmkikZet\\/PKv3ZY","share_with_displayname":"(Shared link)","password":"2|$argon2i$v=19$m=65536,t=4,p=1$SHd0ckwyeG1ieUcubThIRQ$+rO5YJNYmQAdrptAJFQAjq00QnfpTmkikZet\\/PKv3ZY","send_password_by_talk":false,"url":"https:\\/\\/mo.hobigo.de\\/s\\/HMHbFqsKfxGjjKi","mail_send":0,"hide_download":0}]}}', + contentType: "application/xml; charset=utf-8", + status: 200 + } }); - it("03 create public share for folder", async () => { - - const folderName = "/ncncTest/share/03/publicUploadFolder"; - - const folder: Folder = await client.createFolder(folderName); - - const createShare: ICreateShare = { fileSystemElement: folder, publicUpload: true }; - - let share: Share; - - let error: Error | null = null; - try { - share = await client.createShare(createShare); - } catch (e) { - error = e; - } - expect(error).to.be.equal(null); - expect(share!.publicUpload).to.be.equal(true); - - await folder.delete(); + entries.push({ + request: { + description: "Share get", + method: "GET", + url: "/ocs/v2.php/apps/files_sharing/api/v1/shares/60" + }, + response: { + body: '{"ocs":{"meta":{"status":"ok","statuscode":200,"message":"OK"},"data":[{"id":"60","share_type":3,"uid_owner":"htborstenson","displayname_owner":"Horst-Thorsten Borstenson","permissions":1,"can_edit":true,"can_delete":true,"stime":1580171571,"parent":null,"expiration":"2020-12-04","token":"HMHbFqsKfxGjjKi","uid_file_owner":"htborstenson","note":"note test","label":"","displayname_file_owner":"Horst-Thorsten Borstenson","path":"\\/ncncTest\\/share1\\/file3.txt","item_type":"file","mimetype":"text\\/plain","storage_id":"home::htborstenson","storage":3,"item_source":107213,"file_source":107213,"file_parent":107191,"file_target":"\\/file3.txt","share_with":"2|$argon2i$v=19$m=65536,t=4,p=1$SHd0ckwyeG1ieUcubThIRQ$+rO5YJNYmQAdrptAJFQAjq00QnfpTmkikZet\\/PKv3ZY","share_with_displayname":"(Shared link)","password":"2|$argon2i$v=19$m=65536,t=4,p=1$SHd0ckwyeG1ieUcubThIRQ$+rO5YJNYmQAdrptAJFQAjq00QnfpTmkikZet\\/PKv3ZY","send_password_by_talk":false,"url":"https:\\/\\/mo.hobigo.de\\/s\\/HMHbFqsKfxGjjKi","mail_send":0,"hide_download":0}]}}', + contentType: "application/xml; charset=utf-8", + status: 200 + } }); + const lclient: Client = new Client(new FakeServer(entries)); + let errorCode: string = "noError"; + try { + await Share.getShare( + lclient, + ShareType.publicLink, + SharePermission.all, + "60" + ); + } catch (e) { + errorCode = e.code; + } + expect(errorCode, "expect an exception").to.be.equal( + "ERR_INVALID_SHARE_RESPONSE" + ); + + errorCode = "noError"; + try { + await Share.getShare( + lclient, + ShareType.publicLink, + SharePermission.all, + "60" + ); + } catch (e) { + errorCode = e.code; + } + expect(errorCode, "expect an exception").to.be.equal( + "ERR_INVALID_SHARE_RESPONSE" + ); + + errorCode = "noError"; + try { + await Share.getShare( + lclient, + ShareType.publicLink, + SharePermission.all, + "60" + ); + } catch (e) { + errorCode = e.code; + } + expect(errorCode, "expect an exception").to.be.equal( + "ERR_INVALID_SHARE_RESPONSE" + ); + + errorCode = "noError"; + try { + await Share.getShare( + lclient, + ShareType.publicLink, + SharePermission.all, + "60" + ); + } catch (e) { + errorCode = e.code; + } + expect(errorCode, "expect an exception").to.be.equal( + "ERR_INVALID_SHARE_RESPONSE" + ); + + errorCode = "noError"; + try { + await Share.getShare( + lclient, + ShareType.publicLink, + SharePermission.all, + "60" + ); + } catch (e) { + expect(e.message, "expect no exception").to.be.equal( + "expect no exception" + ); + } + + errorCode = "noError"; + try { + await Share.getShare( + lclient, + ShareType.publicLink, + SharePermission.all, + "60" + ); + } catch (e) { + expect(e.message, "expect no exception").to.be.equal( + "expect no exception" + ); + } + + errorCode = "noError"; + try { + await Share.getShare( + lclient, + ShareType.publicLink, + SharePermission.all, + "60" + ); + } catch (e) { + expect(e.message, "expect no exception").to.be.equal( + "expect no exception" + ); + } + + errorCode = "noError"; + try { + await Share.getShare( + lclient, + ShareType.publicLink, + SharePermission.all, + "60" + ); + } catch (e) { + expect(e.message, "expect no exception").to.be.equal( + "expect no exception" + ); + } + }); + + it("03 create public share for folder", async () => { + const folderName = "/ncncTest/share/03/publicUploadFolder"; + + const folder: Folder = await client.createFolder(folderName); + + const createShare: ICreateShare = { + fileSystemElement: folder, + publicUpload: true, + shareType: ShareType.publicLink, + permissions: SharePermission.all + }; + + let share: Share; + + let error: Error | null = null; + try { + share = await client.createShare(createShare); + } catch (e) { + error = e; + } + expect(error).to.be.equal(null); + expect(share!.publicUpload).to.be.equal(true); + + await folder.delete(); + }); }); diff --git a/src/test/14.streams.test.d.ts b/src/test/14.streams.test.d.ts new file mode 100644 index 00000000..87ad0c95 --- /dev/null +++ b/src/test/14.streams.test.d.ts @@ -0,0 +1 @@ +import "mocha"; diff --git a/src/test/14.streams.test.js b/src/test/14.streams.test.js new file mode 100644 index 00000000..bd4bcbe1 --- /dev/null +++ b/src/test/14.streams.test.js @@ -0,0 +1,66 @@ +"use strict"; +var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { + function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } + return new (P || (P = Promise))(function (resolve, reject) { + function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } + function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } + function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } + step((generator = generator.apply(thisArg, _arguments || [])).next()); + }); +}; +var __importDefault = (this && this.__importDefault) || function (mod) { + return (mod && mod.__esModule) ? mod : { "default": mod }; +}; +Object.defineProperty(exports, "__esModule", { value: true }); +const fs_1 = __importDefault(require("fs")); +// if you used the '@types/mocha' method to install mocha type definitions, uncomment the following line +require("mocha"); +const path_1 = __importDefault(require("path")); +const testUtils_1 = require("./testUtils"); +let client; +// tslint:disable-next-line:only-arrow-functions +// tslint:disable-next-line:space-before-function-paren +describe("14-NEXCLOUD-NODE-CLIENT-STREAMS", function () { + // tslint:disable-next-line:space-before-function-paren + beforeEach(function () { + return __awaiter(this, void 0, void 0, function* () { + if (this.currentTest && this.currentTest.parent) { + client = yield (0, testUtils_1.getNextcloudClient)(this.currentTest.parent.title + "/" + this.currentTest.title); + } + }); + }); + this.timeout(1 * 60 * 1000); + it.skip("01 create file from stream", () => __awaiter(this, void 0, void 0, function* () { + const rStream = fs_1.default.createReadStream(__filename); + const fileName = "/ncncTest/streams/" + path_1.default.basename(__filename); + console.log(fileName); + let file; + file = yield client.createFile(fileName, rStream); + /* + try { + await share.setPassword("some password"); + } catch (e) { + expect(e.message, "expect no exception setting password").to.be.equal(null); + } +*/ + yield file.delete(); + })); + it.skip("02 pipe file content stream", () => __awaiter(this, void 0, void 0, function* () { + const sourceFileName = "./src/test/data/text1.txt"; + const rStream = fs_1.default.createReadStream(sourceFileName); + const fileName = "/ncncTest/streams/" + path_1.default.basename(sourceFileName); + console.log(fileName); + let file; + file = yield client.createFile(fileName, rStream); + /* + try { + await share.setPassword("some password"); + } catch (e) { + expect(e.message, "expect no exception setting password").to.be.equal(null); + } + */ + const dest = fs_1.default.createWriteStream("./tmp/" + path_1.default.basename(sourceFileName)); + yield client.pipeContentStream(fileName, dest); + yield file.delete(); + })); +}); diff --git a/src/test/15.notification.test.d.ts b/src/test/15.notification.test.d.ts new file mode 100644 index 00000000..87ad0c95 --- /dev/null +++ b/src/test/15.notification.test.d.ts @@ -0,0 +1 @@ +import "mocha"; diff --git a/src/test/15.notification.test.js b/src/test/15.notification.test.js new file mode 100644 index 00000000..c8cc77fd --- /dev/null +++ b/src/test/15.notification.test.js @@ -0,0 +1,127 @@ +"use strict"; +var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { + function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } + return new (P || (P = Promise))(function (resolve, reject) { + function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } + function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } + function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } + step((generator = generator.apply(thisArg, _arguments || [])).next()); + }); +}; +var __importDefault = (this && this.__importDefault) || function (mod) { + return (mod && mod.__esModule) ? mod : { "default": mod }; +}; +Object.defineProperty(exports, "__esModule", { value: true }); +// this must be the first +const dotenv_1 = require("dotenv"); +(0, dotenv_1.config)(); +const chai_1 = require("chai"); +// if you used the '@types/mocha' method to install mocha type definitions, uncomment the following line +require("mocha"); +const client_1 = require("../client"); +const fakeServer_1 = __importDefault(require("../fakeServer")); +const testUtils_1 = require("./testUtils"); +let client; +// tslint:disable-next-line:only-arrow-functions +// tslint:disable-next-line:space-before-function-paren +describe("15-NEXCLOUD-NODE-CLIENT-NOTIFICATION", function () { + // tslint:disable-next-line:space-before-function-paren + beforeEach(function () { + return __awaiter(this, void 0, void 0, function* () { + if (this.currentTest && this.currentTest.parent) { + client = yield (0, testUtils_1.getNextcloudClient)(this.currentTest.parent.title + "/" + this.currentTest.title); + } + }); + }); + this.timeout(1 * 60 * 1000); + it("01 client get notifications", () => __awaiter(this, void 0, void 0, function* () { + const entries = []; + entries.push({ + request: { + description: "Notifications get", + method: "GET", + url: "/ocs/v2.php/apps/notifications/api/v2/notification", + }, + response: { + body: "{\"ocs\":{\"data\":[{\"n1\":1},{\"n2\":2}]}}", + contentType: "application/json; charset=utf-8", + status: 200, + }, + }); + let notifications = []; + const lclient = new client_1.Client(new fakeServer_1.default(entries)); + try { + notifications = yield lclient.getNotifications(); + // console.log(notifications); + } + catch (e) { + (0, chai_1.expect)(e.message, "expect an array and no exception").to.be.equal("no exception"); + } + (0, chai_1.expect)(notifications).to.be.a("array"); + (0, chai_1.expect)(notifications.length).to.be.equal(2); + })); + it("02 client get notifications no entries", () => __awaiter(this, void 0, void 0, function* () { + const entries = []; + entries.push({ + request: { + description: "Notifications get", + method: "GET", + url: "/ocs/v2.php/apps/notifications/api/v2/notification", + }, + response: { + body: "", + contentType: "text/html; charset=UTF-8", + status: 404, + }, + }); + let notifications = []; + const lclient = new client_1.Client(new fakeServer_1.default(entries)); + try { + notifications = yield lclient.getNotifications(); + // console.log(notifications); + } + catch (e) { + (0, chai_1.expect)(e.message, "expect an empty array and no exception").to.be.equal("no exception"); + } + (0, chai_1.expect)(notifications).to.be.a("array"); + (0, chai_1.expect)(notifications.length).to.be.equal(0); + })); + it("03 client get notifications invalid response", () => __awaiter(this, void 0, void 0, function* () { + const entries = []; + entries.push({ + request: { + description: "Notifications get", + method: "GET", + url: "/ocs/v2.php/apps/notifications/api/v2/notification", + }, + response: { + body: "{\"ocs\":{\"NOTFOUND-data\":[{\"n1\":1},{\"n2\":2}]}}", + contentType: "application/json; charset=utf-8", + status: 200, + }, + }); + let error; + const lclient = new client_1.Client(new fakeServer_1.default(entries)); + try { + yield lclient.getNotifications(); + } + catch (e) { + error = e; + } + // expect(error).to.be.a("object"); + (0, chai_1.expect)(error).to.have.property("message"); + (0, chai_1.expect)(error.message).to.be.equal("Fatal Error: nextcloud notifications data missing"); + })); + it.skip("04 send notification to user", () => __awaiter(this, void 0, void 0, function* () { + let error; + try { + yield client.sendNotificationToUser("test", "Donnerwetter", "This is a real long Message"); + } + catch (e) { + error = e; + } + // expect(error).to.be.a("object"); + (0, chai_1.expect)(error).to.have.property("message"); + (0, chai_1.expect)(error.message).to.be.equal("Fatal Error: nextcloud notifications data missing"); + })); +}); diff --git a/src/test/16.getFileSystemElements.test.d.ts b/src/test/16.getFileSystemElements.test.d.ts new file mode 100644 index 00000000..87ad0c95 --- /dev/null +++ b/src/test/16.getFileSystemElements.test.d.ts @@ -0,0 +1 @@ +import "mocha"; diff --git a/src/test/16.getFileSystemElements.test.js b/src/test/16.getFileSystemElements.test.js new file mode 100644 index 00000000..e75f8a1d --- /dev/null +++ b/src/test/16.getFileSystemElements.test.js @@ -0,0 +1,137 @@ +"use strict"; +var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { + function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } + return new (P || (P = Promise))(function (resolve, reject) { + function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } + function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } + function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } + step((generator = generator.apply(thisArg, _arguments || [])).next()); + }); +}; +Object.defineProperty(exports, "__esModule", { value: true }); +// this must be the first +const dotenv_1 = require("dotenv"); +(0, dotenv_1.config)(); +const chai_1 = require("chai"); +// if you used the '@types/mocha' method to install mocha type definitions, uncomment the following line +require("mocha"); +const client_1 = require("../client"); +const testUtils_1 = require("./testUtils"); +let client; +// tslint:disable-next-line:only-arrow-functions +// tslint:disable-next-line:space-before-function-paren +describe("16-NEXCLOUD-NODE-CLIENT-GET-FILESYSTEMELEMENTS", function () { + // tslint:disable-next-line:space-before-function-paren + beforeEach(function () { + return __awaiter(this, void 0, void 0, function* () { + if (this.currentTest && this.currentTest.parent) { + client = yield (0, testUtils_1.getNextcloudClient)(this.currentTest.parent.title + "/" + this.currentTest.title); + } + }); + }); + this.timeout(1 * 60 * 1000); + it("01 get file system elements by tags", () => __awaiter(this, void 0, void 0, function* () { + const dirName = "/test/getFileSystemElementsByTags"; + const tag1 = yield client.createTag("tag-16-1"); + const tag2 = yield client.createTag("tag-16-2"); + const tag3 = yield client.createTag("tag-16-3"); + const tag4 = yield client.createTag("tag-16-4"); + const baseFolder = yield client.createFolder(dirName); + for (let c = 1; c < 1000; c++) { + // const file: File = await baseFolder.createFile("testFile" + c + ".txt", Buffer.from("file " + c)); + // file.addTag(tag1.name); + } + const folder1 = yield client.createFolder(dirName + "/folder1"); + yield folder1.addTag(tag1.name); + const folder2 = yield client.createFolder(dirName + "/folder2"); + yield folder2.addTag(tag1.name); + yield folder2.addTag(tag2.name); + const folder3 = yield client.createFolder(dirName + "/folder3"); + yield folder3.addTag(tag1.name); + yield folder3.addTag(tag2.name); + yield folder3.addTag(tag3.name); + const file1 = yield client.createFile(dirName + "/file1.txt", Buffer.from("file 1")); + yield file1.addTag(tag1.name); + const file2 = yield client.createFile(dirName + "/file2.txt", Buffer.from("file 2")); + yield file2.addTag(tag1.name); + yield file2.addTag(tag2.name); + const file3 = yield client.createFile(dirName + "/file3.txt", Buffer.from("file 3")); + yield file3.addTag(tag1.name); + yield file3.addTag(tag2.name); + yield file3.addTag(tag3.name); + let fse = []; + let exception = null; + try { + fse = yield client.getFileSystemElementByTags([tag1, tag2, tag3]); + } + catch (e) { + exception = e; + } + (0, chai_1.expect)(exception).to.be.equal(null); + (0, chai_1.expect)(fse, "expect file to an array").to.be.a("array"); + (0, chai_1.expect)(fse.length).to.be.equal(2); + (0, chai_1.expect)(fse[0]).is.instanceOf(client_1.Folder); + (0, chai_1.expect)(fse[0].name).to.be.equal(folder3.name); + (0, chai_1.expect)(fse[1]).is.instanceOf(client_1.File); + (0, chai_1.expect)(fse[1].name).to.be.equal(file3.name); + try { + fse = yield client.getFileSystemElementByTags([tag1, tag2]); + } + catch (e) { + exception = e; + } + (0, chai_1.expect)(exception).to.be.equal(null); + (0, chai_1.expect)(fse, "expect file to an array").to.be.a("array"); + (0, chai_1.expect)(fse.length).to.be.equal(4); + (0, chai_1.expect)(fse[0]).is.instanceOf(client_1.Folder); + (0, chai_1.expect)(fse[0].name).to.be.equal(folder2.name); + (0, chai_1.expect)(fse[1]).is.instanceOf(client_1.Folder); + (0, chai_1.expect)(fse[1].name).to.be.equal(folder3.name); + (0, chai_1.expect)(fse[2]).is.instanceOf(client_1.File); + (0, chai_1.expect)(fse[2].name).to.be.equal(file2.name); + (0, chai_1.expect)(fse[3]).is.instanceOf(client_1.File); + (0, chai_1.expect)(fse[3].name).to.be.equal(file3.name); + try { + fse = yield client.getFileSystemElementByTags([tag1]); + } + catch (e) { + exception = e; + } + (0, chai_1.expect)(exception).to.be.equal(null); + (0, chai_1.expect)(fse, "expect file to an array").to.be.a("array"); + (0, chai_1.expect)(fse.length).to.be.equal(6); + (0, chai_1.expect)(fse[0]).is.instanceOf(client_1.Folder); + (0, chai_1.expect)(fse[0].name).to.be.equal(folder1.name); + (0, chai_1.expect)(fse[1]).is.instanceOf(client_1.Folder); + (0, chai_1.expect)(fse[1].name).to.be.equal(folder2.name); + (0, chai_1.expect)(fse[2]).is.instanceOf(client_1.Folder); + (0, chai_1.expect)(fse[2].name).to.be.equal(folder3.name); + (0, chai_1.expect)(fse[3]).is.instanceOf(client_1.File); + (0, chai_1.expect)(fse[3].name).to.be.equal(file1.name); + (0, chai_1.expect)(fse[4]).is.instanceOf(client_1.File); + (0, chai_1.expect)(fse[4].name).to.be.equal(file2.name); + (0, chai_1.expect)(fse[5]).is.instanceOf(client_1.File); + (0, chai_1.expect)(fse[5].name).to.be.equal(file3.name); + try { + fse = yield client.getFileSystemElementByTags([tag4]); + } + catch (e) { + exception = e; + } + (0, chai_1.expect)(exception).to.be.equal(null); + (0, chai_1.expect)(fse, "expect file to an array").to.be.a("array"); + (0, chai_1.expect)(fse.length).to.be.equal(0); + try { + fse = yield client.getFileSystemElementByTags([]); + } + catch (e) { + exception = e; + } + (0, chai_1.expect)(exception).not.to.be.equal(null); + yield tag1.delete(); + yield tag2.delete(); + yield tag3.delete(); + yield tag4.delete(); + yield baseFolder.delete(); + })); +}); diff --git a/src/test/20.httpClient.test.d.ts b/src/test/20.httpClient.test.d.ts new file mode 100644 index 00000000..87ad0c95 --- /dev/null +++ b/src/test/20.httpClient.test.d.ts @@ -0,0 +1 @@ +import "mocha"; diff --git a/src/test/20.httpClient.test.js b/src/test/20.httpClient.test.js new file mode 100644 index 00000000..d59c762b --- /dev/null +++ b/src/test/20.httpClient.test.js @@ -0,0 +1,172 @@ +"use strict"; +var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { + function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } + return new (P || (P = Promise))(function (resolve, reject) { + function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } + function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } + function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } + step((generator = generator.apply(thisArg, _arguments || [])).next()); + }); +}; +var __importDefault = (this && this.__importDefault) || function (mod) { + return (mod && mod.__esModule) ? mod : { "default": mod }; +}; +Object.defineProperty(exports, "__esModule", { value: true }); +const chai_1 = require("chai"); +// if you used the '@types/mocha' method to install mocha type definitions, uncomment the following line +require("mocha"); +const node_fetch_1 = require("node-fetch"); +const httpClient_1 = require("../httpClient"); +const requestResponseLog_1 = __importDefault(require("../requestResponseLog")); +// tslint:disable-next-line:only-arrow-functions +// tslint:disable-next-line:space-before-function-paren +describe("20-NEXCLOUD-NODE-CLIENT-HTTP-CLIENT", function () { + this.timeout(1 * 60 * 1000); + it("01 timeout unkonwn server", () => __awaiter(this, void 0, void 0, function* () { + const proxy = { + host: "host", + port: "1234", + protocol: "https", + proxyAuthorizationHeader: "some header", + secureProxy: true, + }; + const options = { + authorizationHeader: "basic 12343", + logRequestResponse: true, + origin: "origin", + proxy, + }; + const httpClient = new httpClient_1.HttpClient(options); + const requestInit = { + method: "GET", + // timeout: 1, + }; + const url = "https://this.server.does.not.exist:1234/root"; + let response; + let exceptionOccurred = false; + try { + response = yield httpClient.getHttpResponse(url, requestInit, [200], { description: "test Call" }); + } + catch (e) { + exceptionOccurred = true; + } + (0, chai_1.expect)(exceptionOccurred, "expect an exception").to.be.equal(true); + })); + it("02 post with basic auth", () => __awaiter(this, void 0, void 0, function* () { + const options = { + authorizationHeader: "Basic dGVzdDp0ZXN0", + logRequestResponse: false, + origin: "https://ptsv2.com", + }; + const httpClient = new httpClient_1.HttpClient(options); + const requestInit = { + headers: new node_fetch_1.Headers(), + method: "POST", + }; + const url = "https://ptsv2.com/t/jb6te-1577116991/post"; + let response; + try { + response = yield httpClient.getHttpResponse(url, requestInit, [200], { description: "test Call" }); + const body = yield response.text(); + (0, chai_1.expect)(body).to.be.equal("Thank you for this dump. I hope you have a lovely day!"); + } + catch (e) { + (0, chai_1.expect)(true, "expect no exception").to.be.equal(e.message); + } + })); + it("03 post without credentials", () => __awaiter(this, void 0, void 0, function* () { + const options = { + logRequestResponse: false, + origin: "https://ptsv2.com", + }; + const httpClient = new httpClient_1.HttpClient(options); + const requestInit = { + method: "POST", + }; + const url = "https://ptsv2.com/t/jb6te-1577116991/post"; + let exceptionMessage = ""; + try { + yield httpClient.getHttpResponse(url, requestInit, [200], { description: "test Call" }); + } + catch (e) { + (0, chai_1.expect)(true, "expect an exception").to.be.equal(true); + exceptionMessage = e.message; + } + (0, chai_1.expect)(exceptionMessage, "expect an exception").to.be.not.equal(""); + })); + it("04 post without credentials recording mode", () => __awaiter(this, void 0, void 0, function* () { + const rrLog = requestResponseLog_1.default.getInstance(); + yield rrLog.setContext("04 post without credentials recording mode"); + const options = { + logRequestResponse: true, + origin: "https://ptsv2.com", + }; + const httpClient = new httpClient_1.HttpClient(options); + const requestInit = { + method: "POST", + }; + const url = "https://ptsv2.com/t/rdztk-1577118815/post"; + let response; + try { + response = yield httpClient.getHttpResponse(url, requestInit, [200], { description: "test Call" }); + const body = yield response.text(); + (0, chai_1.expect)(body).to.be.equal(`{"test":true}`); + const body2 = yield response.json(); + (0, chai_1.expect)(body2).to.be.have.property("test"); + (0, chai_1.expect)(body2.test).to.be.equal(true); + const body3 = yield response.buffer(); + (0, chai_1.expect)(body3).to.be.not.equal(null); + } + catch (e) { + (0, chai_1.expect)(true, "expect no exception").to.be.equal(e.message); + } + })); + it("05 post only absolute urls are supported", () => __awaiter(this, void 0, void 0, function* () { + const rrLog = requestResponseLog_1.default.getInstance(); + yield rrLog.setContext("04 post without credentials recording mode"); + const options = { + logRequestResponse: true, + origin: "https://ptsv2.com", + }; + const httpClient = new httpClient_1.HttpClient(options); + const requestInit = { + method: "POST", + }; + const url = "/t/rdztk-1577118815/post"; + try { + yield httpClient.getHttpResponse(url, requestInit, [200], { description: "test Call" }); + } + catch (e) { + (0, chai_1.expect)(true, "expect an exception").to.be.equal(true); + } + })); + it("06 without proxy auth header, origin, description and method", () => __awaiter(this, void 0, void 0, function* () { + // no proxyAuthorizationHeader + const proxy = { + host: "host", + port: "1234", + protocol: "https", + secureProxy: true, + }; + const options = { + authorizationHeader: "basic 12343", + logRequestResponse: true, + // origin: "origin", + proxy, + }; + const httpClient = new httpClient_1.HttpClient(options); + const requestInit = { + // timeout: 1, + }; + const url = "https://this.server.does.not.exist:1234/root"; + let response; + let exceptionOccurred = false; + try { + response = yield httpClient.getHttpResponse(url, requestInit, [200], {}); + } + catch (e) { + exceptionOccurred = true; + } + (0, chai_1.expect)(exceptionOccurred).to.be.equal(true); + })); +}); diff --git a/src/test/20.httpClient.test.ts b/src/test/20.httpClient.test.ts index dc3701da..0ed61c3d 100644 --- a/src/test/20.httpClient.test.ts +++ b/src/test/20.httpClient.test.ts @@ -38,7 +38,7 @@ describe("20-NEXCLOUD-NODE-CLIENT-HTTP-CLIENT", function () { const requestInit: RequestInit = { method: "GET", - timeout: 1, + // timeout: 1, }; const url: string = "https://this.server.does.not.exist:1234/root"; @@ -210,7 +210,7 @@ describe("20-NEXCLOUD-NODE-CLIENT-HTTP-CLIENT", function () { const httpClient: HttpClient = new HttpClient(options); const requestInit: RequestInit = { - timeout: 1, + // timeout: 1, }; const url: string = "https://this.server.does.not.exist:1234/root"; diff --git a/src/test/21.fileSizeFormatter.test.d.ts b/src/test/21.fileSizeFormatter.test.d.ts new file mode 100644 index 00000000..87ad0c95 --- /dev/null +++ b/src/test/21.fileSizeFormatter.test.d.ts @@ -0,0 +1 @@ +import "mocha"; diff --git a/src/test/21.fileSizeFormatter.test.js b/src/test/21.fileSizeFormatter.test.js new file mode 100644 index 00000000..45cccb39 --- /dev/null +++ b/src/test/21.fileSizeFormatter.test.js @@ -0,0 +1,38 @@ +"use strict"; +var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { + function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } + return new (P || (P = Promise))(function (resolve, reject) { + function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } + function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } + function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } + step((generator = generator.apply(thisArg, _arguments || [])).next()); + }); +}; +var __importDefault = (this && this.__importDefault) || function (mod) { + return (mod && mod.__esModule) ? mod : { "default": mod }; +}; +Object.defineProperty(exports, "__esModule", { value: true }); +const chai_1 = require("chai"); +// if you used the '@types/mocha' method to install mocha type definitions, uncomment the following line +require("mocha"); +const fileSizeFormatter_1 = __importDefault(require("../fileSizeFormatter")); +// tslint:disable-next-line:only-arrow-functions +// tslint:disable-next-line:space-before-function-paren +describe("21-NEXCLOUD-NODE-CLIENT-FILE-SIZE-FORMATTER", () => { + it("01 byte file size", () => __awaiter(void 0, void 0, void 0, function* () { + const fsm = new fileSizeFormatter_1.default(2); + (0, chai_1.expect)(fsm.getUserFriendlyFileSize()).to.be.equal("2 B"); + })); + it("02 kilo byte file size", () => __awaiter(void 0, void 0, void 0, function* () { + const fsm = new fileSizeFormatter_1.default(1024 + 2); + (0, chai_1.expect)(fsm.getUserFriendlyFileSize()).to.be.equal("1 kB"); + })); + it("03 mega byte file size", () => __awaiter(void 0, void 0, void 0, function* () { + const fsm = new fileSizeFormatter_1.default(4 * 1024 * 1024 + 200); + (0, chai_1.expect)(fsm.getUserFriendlyFileSize()).to.be.equal("4 MB"); + })); + it("04 giga byte file size", () => __awaiter(void 0, void 0, void 0, function* () { + const fsm = new fileSizeFormatter_1.default(40 * 1024 * 1024 * 1024 + 200 * 1024 * 1024); + (0, chai_1.expect)(fsm.getUserFriendlyFileSize()).to.be.equal("40 GB"); + })); +}); diff --git a/src/test/30.command.test.d.ts b/src/test/30.command.test.d.ts new file mode 100644 index 00000000..87ad0c95 --- /dev/null +++ b/src/test/30.command.test.d.ts @@ -0,0 +1 @@ +import "mocha"; diff --git a/src/test/30.command.test.js b/src/test/30.command.test.js new file mode 100644 index 00000000..1c1ffdce --- /dev/null +++ b/src/test/30.command.test.js @@ -0,0 +1,417 @@ +"use strict"; +// nextcloud-node-client command tests +var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { + function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } + return new (P || (P = Promise))(function (resolve, reject) { + function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } + function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } + function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } + step((generator = generator.apply(thisArg, _arguments || [])).next()); + }); +}; +var __importDefault = (this && this.__importDefault) || function (mod) { + return (mod && mod.__esModule) ? mod : { "default": mod }; +}; +Object.defineProperty(exports, "__esModule", { value: true }); +const chai_1 = require("chai"); +require("mocha"); +const client_1 = require("../client"); +const testUtils_1 = require("./testUtils"); +const getFilesRecursivelyCommand_1 = __importDefault(require("../command/getFilesRecursivelyCommand")); +let client; +// tslint:disable-next-line:only-arrow-functions +// tslint:disable-next-line:space-before-function-paren +describe("30-NEXCLOUD-NODE-COMMAND", function () { + // tslint:disable-next-line:space-before-function-paren + beforeEach(function () { + return __awaiter(this, void 0, void 0, function* () { + if (this.currentTest && this.currentTest.parent) { + client = yield (0, testUtils_1.getNextcloudClient)(this.currentTest.parent.title + "/" + this.currentTest.title); + } + }); + }); + this.timeout(1 * 60 * 10000); + it("01 execute upload folder command", () => __awaiter(this, void 0, void 0, function* () { + const sourceFolderName = "./src/test/data/Borstenson"; + const targetFolderName = "/test/30/02/uploadFilesCommand"; + const fsf = new client_1.FileSystemFolder(sourceFolderName); + const folderFileNames = yield fsf.getFileNames(); + const getTargetFileNameBeforeUpload = (fileNames) => { return `${targetFolderName}${fileNames.targetFileName}`; }; + const options = { folderName: sourceFolderName, getTargetFileNameBeforeUpload }; + const uc = new client_1.UploadFolderCommand(client, options); + uc.execute(); + function sleep(seconds) { + return __awaiter(this, void 0, void 0, function* () { + return new Promise(resolve => setTimeout(resolve, seconds * 1000)); + }); + } + while (uc.isFinished() !== true) { + // tslint:disable-next-line:no-console + // console.log(uc.getPercentCompleted() + "%"); + yield sleep(0.1); + } + // tslint:disable-next-line:no-console + // console.log("result", uc.getResultMetaData()); + (0, chai_1.expect)(uc.getResultMetaData().errors.length, "result should contain no errors").to.be.equal(0); + (0, chai_1.expect)(uc.getResultMetaData().messages.length, "result should contain messages").to.be.greaterThan(0); + (0, chai_1.expect)(uc.getStatus(), "command should be successfull").to.be.equal(client_1.CommandStatus.success); + const bytesUploaded = uc.getBytesUploaded(); + (0, chai_1.expect)(bytesUploaded, "expect a certain number of bytesUploaded").to.be.greaterThan(3000000); + })); + it("02 execute upload files command", () => __awaiter(this, void 0, void 0, function* () { + const sourceFolderName = "./src/test/data/Borstenson"; + const targetFolderName = "/test/30/02/uploadFilesCommand"; + const fsf = new client_1.FileSystemFolder(sourceFolderName); + const fileNames = yield fsf.getFileNames(); + const files = []; + for (const fileNameFormat of fileNames) { + files.push({ sourceFileName: fileNameFormat.absolute, targetFileName: `${targetFolderName}${fileNameFormat.relative}` }); + } + const options = { files }; + const uc = new client_1.UploadFilesCommand(client, options); + // console.log(files); + // do not place an await here + uc.execute(); + function sleep(seconds) { + return __awaiter(this, void 0, void 0, function* () { + return new Promise(resolve => setTimeout(resolve, seconds * 1000)); + }); + } + while (uc.isFinished() !== true) { + // tslint:disable-next-line:no-console + // console.log(uc.getPercentCompleted() + "%"); + yield sleep(0.1); + } + // tslint:disable-next-line:no-console + // console.log("result", uc.getResultMetaData()); + (0, chai_1.expect)(uc.getResultMetaData().errors.length, "result should contain no errors").to.be.equal(0); + (0, chai_1.expect)(uc.getResultMetaData().messages.length, "result should contain messages").to.be.greaterThan(0); + (0, chai_1.expect)(uc.getStatus(), "command should be successfull").to.be.equal(client_1.CommandStatus.success); + })); + it("03 execute upload files command fails with invalid source file name", () => __awaiter(this, void 0, void 0, function* () { + const sourceFileName = "./does/not/exist.txt"; + const targetFileName = "/test/30/03/uploadFilesCommand"; + const files = []; + files.push({ sourceFileName, targetFileName }); + const options = { files }; + const uc = new client_1.UploadFilesCommand(client, options); + // console.log(files); + // do not place an await here + uc.execute(); + function sleep(seconds) { + return __awaiter(this, void 0, void 0, function* () { + return new Promise(resolve => setTimeout(resolve, seconds * 1000)); + }); + } + let alreadyCalled = false; + while (uc.isFinished() !== true) { + // only for code coverage + // if command is running this should not have an effect + if (!alreadyCalled) { + uc.execute(); + alreadyCalled = true; + } + // tslint:disable-next-line:no-console + // console.log(uc.getPercentCompleted() + "%"); + yield sleep(0.1); + } + // tslint:disable-next-line:no-console + // console.log("result", uc.getResultMetaData()); + (0, chai_1.expect)(uc.getResultMetaData().errors.length, "result should contain an error").to.be.equal(1); + (0, chai_1.expect)(uc.getStatus(), "command should fail").to.be.equal(client_1.CommandStatus.failed); + })); + it("04 execute upload files command fails with invalid target file name", () => __awaiter(this, void 0, void 0, function* () { + const sourceFileName = "./src/test/data/Borstenson/Company/Borstenson Company Profile.pdf"; + const targetFileName = " "; + const files = []; + files.push({ sourceFileName, targetFileName }); + const options = { files }; + const uc = new client_1.UploadFilesCommand(client, options); + // console.log(files); + // do not place an await here + uc.execute(); + function sleep(seconds) { + return __awaiter(this, void 0, void 0, function* () { + return new Promise(resolve => setTimeout(resolve, seconds * 1000)); + }); + } + while (uc.isFinished() !== true) { + // tslint:disable-next-line:no-console + // console.log(uc.getPercentCompleted() + "%"); + yield sleep(0.1); + } + // tslint:disable-next-line:no-console + // console.log("result", uc.getResultMetaData()); + (0, chai_1.expect)(uc.getResultMetaData().errors.length, "result should contain an error").to.be.equal(1); + (0, chai_1.expect)(uc.getStatus(), "command should fail").to.be.equal(client_1.CommandStatus.failed); + })); + it("05 execute upload files command with file processing callback after upload", () => __awaiter(this, void 0, void 0, function* () { + const baseName = "Borstenson Company Profile.pdf"; + const sourceFileName = "./src/test/data/Borstenson/Company/" + baseName; + const targetFileName = "/test/30/05/uploadFilesCommand/" + baseName; + const processFileAfterUpload = (file) => __awaiter(this, void 0, void 0, function* () { + (0, chai_1.expect)(file.baseName).to.be.equal(baseName); + }); + const files = []; + files.push({ sourceFileName, targetFileName }); + const options = { files, processFileAfterUpload }; + const uc = new client_1.UploadFilesCommand(client, options); + // console.log(files); + // do not place an await here + uc.execute(); + function sleep(seconds) { + return __awaiter(this, void 0, void 0, function* () { + return new Promise(resolve => setTimeout(resolve, seconds * 1000)); + }); + } + while (uc.isFinished() !== true) { + // tslint:disable-next-line:no-console + // console.log(uc.getPercentCompleted() + "%"); + yield sleep(0.1); + } + // tslint:disable-next-line:no-console + // console.log("result", uc.getResultMetaData()); + (0, chai_1.expect)(uc.getResultMetaData().errors.length, "result should contain no errors").to.be.equal(0); + (0, chai_1.expect)(uc.getResultMetaData().messages.length, "result should contain one message").to.be.equal(1); + (0, chai_1.expect)(uc.getStatus(), "command should be successfull").to.be.equal(client_1.CommandStatus.success); + })); + it("06 execute upload files command should fail in callback function", () => __awaiter(this, void 0, void 0, function* () { + const baseName = "Borstenson Company Profile.pdf"; + const sourceFileName = "./src/test/data/Borstenson/Company/" + baseName; + const targetFileName = "/test/30/06/uploadFilesCommand/" + baseName; + const errorMessage = "This is an error messsage"; + const processFileAfterUpload = (file) => __awaiter(this, void 0, void 0, function* () { + throw new Error(errorMessage); + }); + const files = []; + files.push({ sourceFileName, targetFileName }); + const options = { files, processFileAfterUpload }; + const uc = new client_1.UploadFilesCommand(client, options); + // console.log(files); + // do not place an await here + uc.execute(); + function sleep(seconds) { + return __awaiter(this, void 0, void 0, function* () { + return new Promise(resolve => setTimeout(resolve, seconds * 1000)); + }); + } + while (uc.isFinished() !== true) { + // tslint:disable-next-line:no-console + // console.log(uc.getPercentCompleted() + "%"); + yield sleep(0.1); + } + // tslint:disable-next-line:no-console + // console.log("result", uc.getResultMetaData()); + (0, chai_1.expect)(uc.getResultMetaData().errors.length, "result should contain one error").to.be.equal(1); + (0, chai_1.expect)(uc.getResultMetaData().errors[0]).to.be.equal(errorMessage); + (0, chai_1.expect)(uc.getStatus(), "command should be fail").to.be.equal(client_1.CommandStatus.failed); + })); + it("07 execute upload folder command with default target file name processing", () => __awaiter(this, void 0, void 0, function* () { + const sourceFolderName = "./src/test/data/Borstenson"; + const targetFolderName = "/test/30/07/uploadFilesCommand"; + const fsf = new client_1.FileSystemFolder(sourceFolderName); + const folderFileNames = yield fsf.getFileNames(); + const options = { folderName: sourceFolderName }; + const uc = new client_1.UploadFolderCommand(client, options); + uc.execute(); + function sleep(seconds) { + return __awaiter(this, void 0, void 0, function* () { + return new Promise(resolve => setTimeout(resolve, seconds * 1000)); + }); + } + while (uc.isFinished() !== true) { + // tslint:disable-next-line:no-console + // console.log(uc.getPercentCompleted() + "%"); + yield sleep(0.1); + } + // tslint:disable-next-line:no-console + // console.log("result", uc.getResultMetaData()); + (0, chai_1.expect)(uc.getResultMetaData().errors.length, "result should contain no errors").to.be.equal(0); + (0, chai_1.expect)(uc.getResultMetaData().messages.length, "result should contain messages").to.be.greaterThan(0); + (0, chai_1.expect)(uc.getStatus(), "command should be successfull").to.be.equal(client_1.CommandStatus.success); + })); + it("08 execute upload folder command filtering all target names", () => __awaiter(this, void 0, void 0, function* () { + const sourceFolderName = "./src/test/data/Borstenson"; + const targetFolderName = "/test/30/08/uploadFilesCommand"; + const fsf = new client_1.FileSystemFolder(sourceFolderName); + const folderFileNames = yield fsf.getFileNames(); + const getTargetFileNameBeforeUpload = (fileNames) => { return ""; }; + const options = { folderName: sourceFolderName, getTargetFileNameBeforeUpload }; + const uc = new client_1.UploadFolderCommand(client, options); + uc.execute(); + function sleep(seconds) { + return __awaiter(this, void 0, void 0, function* () { + return new Promise(resolve => setTimeout(resolve, seconds * 1000)); + }); + } + while (uc.isFinished() !== true) { + // tslint:disable-next-line:no-console + // console.log(uc.getPercentCompleted() + "%"); + yield sleep(0.1); + } + // tslint:disable-next-line:no-console + // console.log("result", uc.getResultMetaData()); + (0, chai_1.expect)(uc.getResultMetaData().errors.length, "result should contain no errors").to.be.equal(0); + (0, chai_1.expect)(uc.getResultMetaData().messages.length, "result should contain messages").to.be.equal(0); + (0, chai_1.expect)(uc.getStatus(), "command should be successfull").to.be.equal(client_1.CommandStatus.success); + })); + it("09 execute upload folder command with non exisiting folder", () => __awaiter(this, void 0, void 0, function* () { + const sourceFolderName = "./this/folder/does/not/exist"; + const targetFolderName = "/test/30/09/uploadFolderCommand"; + const options = { folderName: sourceFolderName }; + const uc = new client_1.UploadFolderCommand(client, options); + uc.execute(); + function sleep(seconds) { + return __awaiter(this, void 0, void 0, function* () { + return new Promise(resolve => setTimeout(resolve, seconds * 1000)); + }); + } + while (uc.isFinished() !== true) { + // tslint:disable-next-line:no-console + // console.log(uc.getPercentCompleted() + "%"); + yield sleep(0.1); + } + // tslint:disable-next-line:no-console + // console.log("result", uc.getResultMetaData()); + (0, chai_1.expect)(uc.getResultMetaData().errors.length, "result should contain one error").to.be.equal(1); + (0, chai_1.expect)(uc.getResultMetaData().messages.length, "result should contain messages").to.be.equal(0); + (0, chai_1.expect)(uc.getStatus(), "command should be successfull").to.be.equal(client_1.CommandStatus.failed); + })); + it("10 get files recursively", () => __awaiter(this, void 0, void 0, function* () { + const sourceFolderName = "./src/test/data/Borstenson"; + const targetFolderName = "/test/30/10/GetFilesRecursivelyCommand"; + let sourceFolder = yield client.getFolder(targetFolderName); + if (sourceFolder) { + yield sourceFolder.delete(); + } + // create the test files first + const getTargetFileNameBeforeUpload = (fileNames) => { return `${targetFolderName}${fileNames.targetFileName}`; }; + const ucfOptions = { folderName: sourceFolderName, getTargetFileNameBeforeUpload }; + const uc = new client_1.UploadFolderCommand(client, ucfOptions); + yield uc.execute(); + // tslint:disable-next-line:no-console + // console.log("result: ", JSON.stringify(uc.getResultMetaData())); + // const sourceFolder: Folder = await client.getRootFolder(); + sourceFolder = yield client.getFolder(targetFolderName); + (0, chai_1.expect)(sourceFolder).not.to.be.equal(null); + const options = { sourceFolder: sourceFolder }; + const command = new getFilesRecursivelyCommand_1.default(client, options); + command.execute(); + function sleep(seconds) { + return __awaiter(this, void 0, void 0, function* () { + return new Promise(resolve => setTimeout(resolve, seconds * 1000)); + }); + } + while (command.isFinished() !== true) { + // tslint:disable-next-line:no-console + // console.log(command.getPercentCompleted() + "%"); + yield sleep(0.1); + } + // tslint:disable-next-line:no-console + // console.log("result: ", JSON.stringify(command.getResult())); + (0, chai_1.expect)(command.getResultMetaData().errors.length, "result should contain no errors").to.be.equal(0); + (0, chai_1.expect)(command.getResultMetaData().messages.length, "result should contain messages").to.be.equal(1); + (0, chai_1.expect)(command.getStatus(), "command should be successfull").to.be.equal(client_1.CommandStatus.success); + const files = command.getFiles(); + (0, chai_1.expect)(files.length).to.be.equal(14); + // codecoverage check double execution + let error = null; + try { + yield command.execute(); + } + catch (e) { + error = e; + } + (0, chai_1.expect)(error, "it should not be possible to execute a command again").to.be.instanceOf(client_1.CommandAlreadyExecutedError); + // check filter function + const fileFilterFunction = (file) => { + if (file.mime === "application/pdf") { + return file; + } + if (file.mime === "image/jpeg") { + return file; + } + return null; + }; + const options2 = { + sourceFolder: sourceFolder, + filterFile: fileFilterFunction, + }; + const command2 = new getFilesRecursivelyCommand_1.default(client, options2); + yield command2.execute(); + const filteredFiles = command2.getFiles(); + // 2xpdf and 1xjpg + (0, chai_1.expect)(filteredFiles.length, "expect the number of filtered files is 3").to.be.equal(3); + // delete files + yield sourceFolder.delete(); + })); + it("11 get files recursively fails", () => __awaiter(this, void 0, void 0, function* () { + const notARealFolder = {}; + // this line will cause the error + const options = { sourceFolder: notARealFolder }; + const command = new getFilesRecursivelyCommand_1.default(client, options); + yield command.execute(); + // tslint:disable-next-line:no-console + // console.log("result: ", JSON.stringify(command.getResultMetaData())); + (0, chai_1.expect)(command.getResultMetaData().errors.length, "result should contain an error").to.be.equal(1); + (0, chai_1.expect)(command.getResultMetaData().messages.length, "result should contain no messages").to.be.equal(0); + (0, chai_1.expect)(command.getStatus(), "command should be successfull").to.be.equal(client_1.CommandStatus.failed); + })); + it("12 download files recursively", () => __awaiter(this, void 0, void 0, function* () { + const sourceFolderName = "./src/test/data/Borstenson"; + const targetFolderName = "/test/30/12/DownloadFilesRecursivelyCommand"; + let sourceFolder = yield client.getFolder(targetFolderName); + if (sourceFolder) { + yield sourceFolder.delete(); + } + // create the test files first + const getTargetFileNameBeforeUpload = (fileNames) => { return `${targetFolderName}${fileNames.targetFileName}`; }; + const ucfOptions = { folderName: sourceFolderName, getTargetFileNameBeforeUpload }; + const uc = new client_1.UploadFolderCommand(client, ucfOptions); + yield uc.execute(); + // tslint:disable-next-line:no-console + // console.log("result: ", JSON.stringify(uc.getResultMetaData())); + // const sourceFolder: Folder = await client.getRootFolder(); + sourceFolder = yield client.getFolder(targetFolderName); + (0, chai_1.expect)(sourceFolder).not.to.be.equal(null); + // check filter function + const fileFilterFunction = (file) => { + if (file.mime === "application/pdf" || file.mime === "image/jpeg") { + return file; + } + return null; + }; + const options = { + sourceFolder: sourceFolder, + filterFile: fileFilterFunction, + getTargetFileNameBeforeDownload: (fileNames) => { return "./tmp/" + fileNames.targetFileName; } + }; + const command = new client_1.DownloadFolderCommand(client, options); + command.execute(); + while (command.isFinished() !== true) { + // tslint:disable-next-line:no-console + // console.log(command.getPercentCompleted() + " %"); + yield (() => __awaiter(this, void 0, void 0, function* () { return new Promise(resolve => setTimeout(resolve, 100)); }))(); + } + // tslint:disable-next-line:no-console + // console.log("result: ", JSON.stringify(command.getResultMetaData())); + (0, chai_1.expect)(command.getResultMetaData().errors.length, "result should contain no errors").to.be.equal(0); + (0, chai_1.expect)(command.getResultMetaData().messages.length, "result should contain messages").to.be.equal(1); + (0, chai_1.expect)(command.getStatus(), "command should be successfull").to.be.equal(client_1.CommandStatus.success); + (0, chai_1.expect)(command.getBytesDownloaded()).to.be.greaterThan(100); + // check if error handling works + const options2 = { + sourceFolder: sourceFolder, + filterFile: fileFilterFunction, + getTargetFileNameBeforeDownload: (fileNames) => "tt:/\0/invalid filename/" + fileNames.targetFileName + }; + const command2 = new client_1.DownloadFolderCommand(client, options2); + yield command2.execute(); + (0, chai_1.expect)(command2.getResultMetaData().errors.length, "result should contain errors").to.be.equal(1); + (0, chai_1.expect)(command2.getResultMetaData().messages.length, "result should contain no messages").to.be.equal(0); + (0, chai_1.expect)(command2.getStatus(), "command should be successfull").to.be.equal(client_1.CommandStatus.failed); + // console.log(command2.getResultMetaData().errors); + // delete files + yield sourceFolder.delete(); + })); +}); diff --git a/src/test/31.fileSystemFolder.test.d.ts b/src/test/31.fileSystemFolder.test.d.ts new file mode 100644 index 00000000..87ad0c95 --- /dev/null +++ b/src/test/31.fileSystemFolder.test.d.ts @@ -0,0 +1 @@ +import "mocha"; diff --git a/src/test/31.fileSystemFolder.test.js b/src/test/31.fileSystemFolder.test.js new file mode 100644 index 00000000..6e40e635 --- /dev/null +++ b/src/test/31.fileSystemFolder.test.js @@ -0,0 +1,31 @@ +"use strict"; +var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { + function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } + return new (P || (P = Promise))(function (resolve, reject) { + function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } + function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } + function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } + step((generator = generator.apply(thisArg, _arguments || [])).next()); + }); +}; +var __importDefault = (this && this.__importDefault) || function (mod) { + return (mod && mod.__esModule) ? mod : { "default": mod }; +}; +Object.defineProperty(exports, "__esModule", { value: true }); +const chai_1 = require("chai"); +// if you used the '@types/mocha' method to install mocha type definitions, uncomment the following line +require("mocha"); +const fileSystemFolder_1 = __importDefault(require("../fileSystemFolder")); +// tslint:disable-next-line:only-arrow-functions +describe("31-NEXCLOUD-NODE-FILE-SYSTEM-FOLDER", function () { + it("01 get files of file system folder", () => __awaiter(this, void 0, void 0, function* () { + const folderName = "./src"; + const fsf = new fileSystemFolder_1.default(folderName); + fsf.getName(); + const fileNames = yield fsf.getFileNames(); + // tslint:disable-next-line:no-console + // console.log(fileNames); + (0, chai_1.expect)(fileNames).to.be.an("array"); + (0, chai_1.expect)(fileNames.length).to.be.greaterThan(1); + })); +}); diff --git a/src/test/32.logger.test.d.ts b/src/test/32.logger.test.d.ts new file mode 100644 index 00000000..87ad0c95 --- /dev/null +++ b/src/test/32.logger.test.d.ts @@ -0,0 +1 @@ +import "mocha"; diff --git a/src/test/32.logger.test.js b/src/test/32.logger.test.js new file mode 100644 index 00000000..05138642 --- /dev/null +++ b/src/test/32.logger.test.js @@ -0,0 +1,67 @@ +"use strict"; +var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { + function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } + return new (P || (P = Promise))(function (resolve, reject) { + function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } + function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } + function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } + step((generator = generator.apply(thisArg, _arguments || [])).next()); + }); +}; +var __importDefault = (this && this.__importDefault) || function (mod) { + return (mod && mod.__esModule) ? mod : { "default": mod }; +}; +Object.defineProperty(exports, "__esModule", { value: true }); +require("mocha"); +const logger_1 = __importDefault(require("../logger")); +const mocked_env_1 = __importDefault(require("mocked-env")); +describe("32-NEXCLOUD-NODE-CLIENT-LOGGER", function () { + this.timeout(1 * 60 * 1000); + it("01 Logger", () => __awaiter(this, void 0, void 0, function* () { + // only for code coverage + let restore = (0, mocked_env_1.default)({ + MIN_LOG_LEVEL: "" + }); + let log = new logger_1.default(); + log.silly("silly"); + log.trace("trace"); + log.debug("debug"); + log.info("info"); + log.warn("warn"); + log.error("error"); + log.fatal("fatal"); + restore = (0, mocked_env_1.default)({ + MIN_LOG_LEVEL: "xxx" + }); + log = new logger_1.default(); + restore = (0, mocked_env_1.default)({ + MIN_LOG_LEVEL: "silly" + }); + log = new logger_1.default(); + restore = (0, mocked_env_1.default)({ + MIN_LOG_LEVEL: "trace" + }); + log = new logger_1.default(); + restore = (0, mocked_env_1.default)({ + MIN_LOG_LEVEL: "debug" + }); + log = new logger_1.default(); + restore = (0, mocked_env_1.default)({ + MIN_LOG_LEVEL: "info" + }); + log = new logger_1.default(); + restore = (0, mocked_env_1.default)({ + MIN_LOG_LEVEL: "warn" + }); + log = new logger_1.default(); + restore = (0, mocked_env_1.default)({ + MIN_LOG_LEVEL: "error" + }); + log = new logger_1.default(); + restore = (0, mocked_env_1.default)({ + MIN_LOG_LEVEL: "fatal" + }); + log = new logger_1.default(); + restore(); + })); +}); diff --git a/src/test/testUtils.d.ts b/src/test/testUtils.d.ts new file mode 100644 index 00000000..bf607cb7 --- /dev/null +++ b/src/test/testUtils.d.ts @@ -0,0 +1,3 @@ +import Client from "../client"; +export declare const recordingModeActive: () => boolean; +export declare const getNextcloudClient: (context: string) => Promise; diff --git a/src/test/testUtils.js b/src/test/testUtils.js new file mode 100644 index 00000000..2170c4a4 --- /dev/null +++ b/src/test/testUtils.js @@ -0,0 +1,68 @@ +"use strict"; +var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { + function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } + return new (P || (P = Promise))(function (resolve, reject) { + function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } + function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } + function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } + step((generator = generator.apply(thisArg, _arguments || [])).next()); + }); +}; +var __importDefault = (this && this.__importDefault) || function (mod) { + return (mod && mod.__esModule) ? mod : { "default": mod }; +}; +Object.defineProperty(exports, "__esModule", { value: true }); +exports.getNextcloudClient = exports.recordingModeActive = void 0; +// this must be the first +const dotenv_1 = require("dotenv"); +(0, dotenv_1.config)(); +const client_1 = __importDefault(require("../client")); +const environment_1 = __importDefault(require("../environment")); +const fakeServer_1 = __importDefault(require("../fakeServer")); +const requestResponseLog_1 = __importDefault(require("../requestResponseLog")); +const server_1 = __importDefault(require("../server")); +const logger_1 = __importDefault(require("../logger")); +const log = new logger_1.default(); +const recordingModeActive = () => { + if (process.argv.find((element) => element === "--record")) { + return true; + } + return false; +}; +exports.recordingModeActive = recordingModeActive; +const getNextcloudClient = (context) => __awaiter(void 0, void 0, void 0, function* () { + const rrLog = requestResponseLog_1.default.getInstance(); + rrLog.baseDirectory = "src/test/recordings/"; + yield rrLog.setContext(context); + // use command line parameter to override recording settings + if ((0, exports.recordingModeActive)()) { + const serverOptions = { + url: environment_1.default.getNextcloudUrl(), + basicAuth: { + username: environment_1.default.getUserName(), + password: environment_1.default.getPassword(), + }, + logRequestResponse: environment_1.default.getRecordingActiveIndicator(), + }; + const ncserver = new server_1.default(serverOptions); + ncserver.logRequestResponse = true; + // tslint:disable-next-line:no-console + log.info("Test recording: " + rrLog.getFileName()); + return new client_1.default(ncserver); + } + else { + let entries; + try { + entries = yield rrLog.getEntries(); + } + catch (e) { + // throw new Error(`Error: recording does not exist for '${context}' file name; '${rrLog.getFileName()}'`); + // tslint:disable-next-line:no-console + // console.log(`recording does not exist for '${context}' file name; '${rrLog.getFileName()}'`); + entries = []; + } + const fncserver = new fakeServer_1.default(entries); + return new client_1.default(fncserver); + } +}); +exports.getNextcloudClient = getNextcloudClient; diff --git a/tsconfig.json b/tsconfig.json index 4719dd68..ea237436 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -8,7 +8,7 @@ }, /* Basic Options */ "watch": false, - "target": "ES2015", /* Specify ECMAScript target version: 'ES3' (default), 'ES5', 'ES2015', 'ES2016', 'ES2017','ES2018' or 'ESNEXT'. */ + "target": "ES2018", /* Specify ECMAScript target version: 'ES3' (default), 'ES5', 'ES2015', 'ES2016', 'ES2017','ES2018' or 'ESNEXT'. */ "module": "commonjs", /* Specify module code generation: 'none', 'commonjs', 'amd', 'system', 'umd', 'es2015', or 'ESNext'. */ // "lib": ["es2018"], /* Specify library files to be included in the compilation. */ // "allowJs": true, /* Allow javascript files to be compiled. */ @@ -26,6 +26,7 @@ // "isolatedModules": true, /* Transpile each file as a separate module (similar to 'ts.transpileModule'). */ /* Strict Type-Checking Options */ "strict": true, /* Enable all strict type-checking options. */ + "useUnknownInCatchVariables": false, // "noImplicitAny": true, /* Raise error on expressions and declarations with an implied 'any' type. */ // "strictNullChecks": true, /* Enable strict null checks. */ // "strictFunctionTypes": true, /* Enable strict checking of function types. */ diff --git a/typedoc.json b/typedoc.json index ac6c4b87..76c7cb95 100644 --- a/typedoc.json +++ b/typedoc.json @@ -3,9 +3,7 @@ "readme": true, "includes": "./src", "exclude": ["./src/test","./src/examples"], - "mode": "file", "excludeExternals": true, - "excludeNotExported": true, "excludePrivate": true, "theme": "default" } \ No newline at end of file