From 63794e665acff1e86a289bccaf6446021f5dd96c Mon Sep 17 00:00:00 2001 From: Killian Courvoisier Date: Tue, 18 Apr 2023 16:02:32 +0200 Subject: [PATCH 1/7] feat: Adapt template infos for nextcloud --- manifest.konnector | 32 ++++--------- package.json | 4 +- src/index.js | 101 +++------------------------------------ src/zombie.js | 115 --------------------------------------------- 4 files changed, 19 insertions(+), 233 deletions(-) delete mode 100644 src/zombie.js diff --git a/manifest.konnector b/manifest.konnector index d396f94..84d515e 100644 --- a/manifest.konnector +++ b/manifest.konnector @@ -1,13 +1,13 @@ { "version": "1.0.0", - "name": "Connector template", + "name": "Nextcloud", "type": "konnector", "language": "node", "icon": "icon.svg", - "slug": "template", - "source": "git@github.com:konnectors/template.git", + "slug": "nextcloud", + "source": "git@github.com:konnectors/nextcloud.git", "editor": "Cozy", - "vendor_link": "Link to the target website", + "vendor_link": "https://nextcloud.cozycloud.cc", "categories": ["others"], "fields": { "login": { @@ -19,7 +19,7 @@ }, "folders": [{"defaultDir": "$administrative/$konnector/$account"}], "data_types": [ - "bill" + "contact" ], "screenshots": [], "permissions": { @@ -43,15 +43,9 @@ "langs": ["fr", "en"], "locales": { "fr": { - "short_description": "Récupère la liste de livres", - "long_description": "Récupère la liste de livre sur le site exemple", + "short_description": "Récupère la liste de contacts nextcloud", + "long_description": "Récupère la liste contact nextcloud sur le site.", "permissions": { - "bank operations": { - "description": "Utilisé pour relier les factures à des operations bancaires" - }, - "bills": { - "description": "Utilisé pour sauver les données des factures" - }, "files": { "description": "Utilisé pour sauvegarder les factures" }, @@ -61,15 +55,9 @@ } }, "en": { - "short_description": "Fetch a list of books", - "long_description": "Fetch a list of books from the example website", + "short_description": "Fetch a list of nextcloud contacts", + "long_description": "Fetch a list of nextcloud contacts on the website", "permissions": { - "bank operations": { - "description": "Required to link bank operations to bills" - }, - "bills": { - "description": "Required to save the bills data" - }, "files": { "description": "Required to save the bills" }, @@ -79,6 +67,6 @@ } } }, - "banksTransactionRegExp": "\\bbooks\\b", + "banksTransactionRegExp": "\\bnextcloud\\b", "manifest_version": "2" } diff --git a/package.json b/package.json index 490ccbf..845dc7b 100644 --- a/package.json +++ b/package.json @@ -1,10 +1,10 @@ { - "name": "cozy-konnector-template", + "name": "nextcloud", "version": "1.0.0", "description": "", "repository": { "type": "git", - "url": "git@github.com:konnectors/cozy-konnector-template.git" + "url": "git@github.com:konnectors/nextcloud.git" }, "keywords": [], "author": "Cozy Cloud", diff --git a/src/index.js b/src/index.js index 1cff2a8..e9c2b48 100644 --- a/src/index.js +++ b/src/index.js @@ -1,3 +1,4 @@ +/* eslint-disable no-unused-vars */ const { BaseKonnector, requestFactory, @@ -6,119 +7,31 @@ const { utils } = require('cozy-konnector-libs') const request = requestFactory({ - // The debug mode shows all the details about HTTP requests and responses. Very useful for - // debugging but very verbose. This is why it is commented out by default // debug: true, - // Activates [cheerio](https://cheerio.js.org/) parsing on each page cheerio: true, - // If cheerio is activated do not forget to deactivate json parsing (which is activated by - // default in cozy-konnector-libs json: false, - // This allows request-promise to keep cookies between requests jar: true }) -const VENDOR = 'template' -const baseUrl = 'http://books.toscrape.com' +const VENDOR = 'nextcloud.cozycloud.cc' +const baseUrl = 'https://nextcloud.cozycloud.cc' module.exports = new BaseKonnector(start) -// The start function is run by the BaseKonnector instance only when it got all the account -// information (fields). When you run this connector yourself in "standalone" mode or "dev" mode, -// the account information come from ./konnector-dev-config.json file -// cozyParameters are static parameters, independents from the account. Most often, it can be a -// secret api key. async function start(fields, cozyParameters) { log('info', 'Authenticating ...') if (cozyParameters) log('debug', 'Found COZY_PARAMETERS') await authenticate.bind(this)(fields.login, fields.password) log('info', 'Successfully logged in') - // The BaseKonnector instance expects a Promise as return of the function log('info', 'Fetching the list of documents') - const $ = await request(`${baseUrl}/index.html`) - // cheerio (https://cheerio.js.org/) uses the same api as jQuery (http://jquery.com/) log('info', 'Parsing list of documents') - const documents = await parseDocuments($) - - // Here we use the saveBills function even if what we fetch are not bills, - // but this is the most common case in connectors + const documents = await parseDocuments() log('info', 'Saving data to Cozy') await this.saveBills(documents, fields, { - // This is a bank identifier which will be used to link bills to bank operations. These - // identifiers should be at least a word found in the title of a bank operation related to this - // bill. It is not case sensitive. - identifiers: ['books'] - }) -} - -// This shows authentication using the [signin function](https://github.com/konnectors/libs/blob/master/packages/cozy-konnector-libs/docs/api.md#module_signin) -// even if this in another domain here, but it works as an example -function authenticate(username, password) { - return this.signin({ - url: `http://quotes.toscrape.com/login`, - formSelector: 'form', - formData: { username, password }, - // The validate function will check if the login request was a success. Every website has a - // different way to respond: HTTP status code, error message in HTML ($), HTTP redirection - // (fullResponse.request.uri.href)... - validate: (statusCode, $, fullResponse) => { - log( - 'debug', - fullResponse.request.uri.href, - 'not used here but should be useful for other connectors' - ) - // The login in toscrape.com always works except when no password is set - if ($(`a[href='/logout']`).length === 1) { - return true - } else { - // cozy-konnector-libs has its own logging function which format these logs with colors in - // standalone and dev mode and as JSON in production mode - log('error', $('.error').text()) - return false - } - } + identifiers: ['nextcloud'] }) } -// The goal of this function is to parse a HTML page wrapped by a cheerio instance -// and return an array of JS objects which will be saved to the cozy by saveBills -// (https://github.com/konnectors/libs/blob/master/packages/cozy-konnector-libs/docs/api.md#savebills) -function parseDocuments($) { - // You can find documentation about the scrape function here: - // https://github.com/konnectors/libs/blob/master/packages/cozy-konnector-libs/docs/api.md#scrape - const docs = scrape( - $, - { - title: { - sel: 'h3 a', - attr: 'title' - }, - amount: { - sel: '.price_color', - parse: normalizePrice - }, - fileurl: { - sel: 'img', - attr: 'src', - parse: src => `${baseUrl}/${src}` - } - }, - 'article' - ) - return docs.map(doc => ({ - ...doc, - // The saveBills function needs a date field - // even if it is a little artificial here (these are not real bills) - date: new Date(), - currency: 'EUR', - filename: `${utils.formatDate(new Date())}_${VENDOR}_${doc.amount.toFixed( - 2 - )}EUR${doc.vendorRef ? '_' + doc.vendorRef : ''}.jpg`, - vendor: VENDOR - })) -} +function authenticate(username, password) {} -// Convert a price string to a float -function normalizePrice(price) { - return parseFloat(price.replace('£', '').trim()) -} +function parseDocuments() {} diff --git a/src/zombie.js b/src/zombie.js deleted file mode 100644 index 19ac544..0000000 --- a/src/zombie.js +++ /dev/null @@ -1,115 +0,0 @@ -const { - BaseKonnector, - scrape, - saveBills, - log, - utils, - errors -} = require('cozy-konnector-libs') - -const Browser = require('cozy-konnector-libs/dist/libs/CozyBrowser') -const browser = new Browser() -const cheerio = require('cheerio') - -const VENDOR = 'template' -const baseUrl = 'http://books.toscrape.com' - -module.exports = new BaseKonnector(start) - -// The start function is run by the BaseKonnector instance only when it got all the account -// information (fields). When you run this connector yourself in "standalone" mode or "dev" mode, -// the account information come from ./konnector-dev-config.json file -// cozyParameters are static parameters, independents from the account. Most often, it can be a -// secret api key. -async function start(fields, cozyParameters) { - log('info', 'Authenticating ...') - if (cozyParameters) log('debug', 'Found COZY_PARAMETERS') - await authenticate(fields.login, fields.password) - log('info', 'Successfully logged in') - - log('info', 'Fetching the list of documents') - await browser.visit(`${baseUrl}/index.html`) - - const $ = cheerio.load(browser.html()) - log('info', 'Parsing list of documents') - const documents = await parseDocuments($) - - // Here we use the saveBills function even if what we fetch are not bills, - // but this is the most common case in connectors - log('info', 'Saving data to Cozy') - await saveBills(documents, fields, { - // This is a bank identifier which will be used to link bills to bank operations. These - // identifiers should be at least a word found in the title of a bank operation related to this - // bill. It is not case sensitive. - identifiers: ['books'], - sourceAccount: this.accountId, - sourceAccountIdentifier: fields.login - }) -} - -// This shows authentication using the [signin function](https://github.com/konnectors/libs/blob/master/packages/cozy-konnector-libs/docs/api.md#module_signin) -// even if this in another domain here, but it works as an example -async function authenticate(username, password) { - await browser.visit('http://quotes.toscrape.com/login') - await browser.fill('#username', username) - await browser.fill('#password', password) - await browser.pressButton(`[type=submit]`) - - if ( - !browser.redirected || - browser.location._url !== 'http://quotes.toscrape.com/' - ) { - log('error', browser.query('.error').innerHTML) - throw new Error(errors.LOGIN_FAILED) - } -} - -// The goal of this function is to parse a HTML page wrapped by a cheerio instance -// and return an array of JS objects which will be saved to the cozy by saveBills -// (https://github.com/konnectors/libs/blob/master/packages/cozy-konnector-libs/docs/api.md#savebills) -function parseDocuments($) { - // You can find documentation about the scrape function here: - // https://github.com/konnectors/libs/blob/master/packages/cozy-konnector-libs/docs/api.md#scrape - const docs = scrape( - $, - { - title: { - sel: 'h3 a', - attr: 'title' - }, - amount: { - sel: '.price_color', - parse: normalizePrice - }, - fileurl: { - sel: 'img', - attr: 'src', - parse: src => `${baseUrl}/${src}` - } - }, - 'article' - ) - return docs.map(doc => ({ - ...doc, - // The saveBills function needs a date field - // even if it is a little artificial here (these are not real bills) - date: new Date(), - currency: 'EUR', - filename: `${utils.formatDate(new Date())}_${VENDOR}_${doc.amount.toFixed( - 2 - )}EUR${doc.vendorRef ? '_' + doc.vendorRef : ''}.jpg`, - vendor: VENDOR, - metadata: { - // It can be interesting to add the date of import. This is not mandatory but may be - // useful for debugging or data migration - importDate: new Date(), - // Document version, useful for migration after change of document structure - version: 1 - } - })) -} - -// Convert a price string to a float -function normalizePrice(price) { - return parseFloat(price.replace('£', '').trim()) -} From e6acca5c5b1f391880c5b9a14d7c978c548eb8c0 Mon Sep 17 00:00:00 2001 From: Killian Courvoisier Date: Wed, 19 Apr 2023 16:20:07 +0200 Subject: [PATCH 2/7] chore: Add webdav dependency --- package.json | 3 +- yarn.lock | 135 ++++++++++++++++++++++++++++++++++++++++++++++++++- 2 files changed, 135 insertions(+), 3 deletions(-) diff --git a/package.json b/package.json index 845dc7b..92c65e9 100644 --- a/package.json +++ b/package.json @@ -36,7 +36,8 @@ "travisDeployKey": "./bin/generate_travis_deploy_key" }, "dependencies": { - "cozy-konnector-libs": "4.56.4" + "cozy-konnector-libs": "4.56.4", + "webdav": "^5.0.0-r3" }, "devDependencies": { "cozy-jobs-cli": "1.20.2", diff --git a/yarn.lock b/yarn.lock index 1f7b4c8..7e92732 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1015,6 +1015,13 @@ "@babel/helper-validator-identifier" "^7.18.6" to-fast-properties "^2.0.0" +"@buttercup/fetch@^0.1.0": + version "0.1.0" + resolved "https://registry.yarnpkg.com/@buttercup/fetch/-/fetch-0.1.0.tgz#2c2dd34ac0758927dc612832b2834d9c42fd8d71" + integrity sha512-jkV4NLlE9BGQPgY+0sGi4s41IfreHACIICGpM6YhTlJlGp8XC4W2VapMBxdPenTgzduLU30c12PTvRlxpzoqBw== + optionalDependencies: + node-fetch "^3.3.0" + "@colors/colors@1.5.0": version "1.5.0" resolved "https://registry.yarnpkg.com/@colors/colors/-/colors-1.5.0.tgz#bb504579c1cae923e6576a4f5da43d25f97bdbd9" @@ -1817,6 +1824,11 @@ balanced-match@^1.0.0: resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-1.0.2.tgz#e83e3a7e3f300b34cb9d87f615fa0cbf357690ee" integrity sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw== +base-64@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/base-64/-/base-64-1.0.0.tgz#09d0f2084e32a3fd08c2475b973788eee6ae8f4a" + integrity sha512-kwDPIFCGx0NZHog36dj+tHiwP4QMzsZ3AgMViUBKI0+V5n4U0ufTCUMhnQ04diaRI8EX/QcPfql7zlhZ7j4zgg== + basic-auth@~2.0.1: version "2.0.1" resolved "https://registry.yarnpkg.com/basic-auth/-/basic-auth-2.0.1.tgz#b998279bf47ce38344b4f3cf916d4679bbf51e3a" @@ -1887,6 +1899,13 @@ brace-expansion@^1.1.7: balanced-match "^1.0.0" concat-map "0.0.1" +brace-expansion@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-2.0.1.tgz#1edc459e0f0c548486ecf9fc99f2221364b9a0ae" + integrity sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA== + dependencies: + balanced-match "^1.0.0" + braces@^3.0.2: version "3.0.2" resolved "https://registry.yarnpkg.com/braces/-/braces-3.0.2.tgz#3454e1a462ee8d599e236df336cd9ea4f8afe107" @@ -1924,6 +1943,11 @@ buffer-from@^1.0.0: resolved "https://registry.yarnpkg.com/buffer-from/-/buffer-from-1.1.2.tgz#2b146a6fd72e80b4f55d255f35ed59a3a9a41bd5" integrity sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ== +byte-length@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/byte-length/-/byte-length-1.0.2.tgz#ba5a5909240b0121c079b7f7b15248d6f08223cc" + integrity sha512-ovBpjmsgd/teRmgcPh23d4gJvxDoXtAzEL9xTfMU8Yc2kqCDb7L9jAG0XHl1nzuGl+h3ebCIF1i62UFyA9V/2Q== + bytes@3.1.2: version "3.1.2" resolved "https://registry.yarnpkg.com/bytes/-/bytes-3.1.2.tgz#8b0beeb98605adf1b128fa4386403c009e0221a5" @@ -2539,6 +2563,11 @@ dashdash@^1.12.0: dependencies: assert-plus "^1.0.0" +data-uri-to-buffer@^4.0.0: + version "4.0.1" + resolved "https://registry.yarnpkg.com/data-uri-to-buffer/-/data-uri-to-buffer-4.0.1.tgz#d8feb2b2881e6a4f58c2e08acfd0e2834e26222e" + integrity sha512-0R9ikRb668HB7QDxT1vkpuUBtqc53YyAwMwGeUFKRojY/NWKvdZ+9UYtRfGmhqNbRkTSVpMbmyhXipFFv2cb/A== + date-fns@^1.30.1: version "1.30.1" resolved "https://registry.yarnpkg.com/date-fns/-/date-fns-1.30.1.tgz#2e71bf0b119153dbb4cc4e88d9ea5acfb50dc05c" @@ -3145,6 +3174,13 @@ fast-levenshtein@^2.0.6: resolved "https://registry.yarnpkg.com/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz#3d8a5c66883a16a30ca8643e851f19baa7797917" integrity sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw== +fast-xml-parser@^3.19.0: + version "3.21.1" + resolved "https://registry.yarnpkg.com/fast-xml-parser/-/fast-xml-parser-3.21.1.tgz#152a1d51d445380f7046b304672dd55d15c9e736" + integrity sha512-FTFVjYoBOZTJekiUsawGsSYV9QL0A+zDYCRj7y34IO6Jg+2IMYEtQa+bbictpdpV8dHxXywqU7C0gRDEOFtBFg== + dependencies: + strnum "^1.0.4" + fastest-levenshtein@^1.0.12: version "1.0.14" resolved "https://registry.yarnpkg.com/fastest-levenshtein/-/fastest-levenshtein-1.0.14.tgz#9054384e4b7a78c88d01a4432dc18871af0ac859" @@ -3157,6 +3193,14 @@ fastq@^1.6.0: dependencies: reusify "^1.0.4" +fetch-blob@^3.1.2, fetch-blob@^3.1.4: + version "3.2.0" + resolved "https://registry.yarnpkg.com/fetch-blob/-/fetch-blob-3.2.0.tgz#f09b8d4bbd45adc6f0c20b7e787e793e309dcce9" + integrity sha512-7yAQpD2UMJzLi1Dqv7qFYnPbaPx7ZfFK6PiIxQ4PfkGPyNyl2Ugx+a/umUonmKqjhM4DnfbMvdX6otXq83soQQ== + dependencies: + node-domexception "^1.0.0" + web-streams-polyfill "^3.0.3" + fetch-cookie@0.7.0: version "0.7.0" resolved "https://registry.yarnpkg.com/fetch-cookie/-/fetch-cookie-0.7.0.tgz#a6fc137ad8363aa89125864c6451b86ecb7de802" @@ -3251,6 +3295,13 @@ form-data@~2.3.2: combined-stream "^1.0.6" mime-types "^2.1.12" +formdata-polyfill@^4.0.10: + version "4.0.10" + resolved "https://registry.yarnpkg.com/formdata-polyfill/-/formdata-polyfill-4.0.10.tgz#24807c31c9d402e002ab3d8c720144ceb8848423" + integrity sha512-buewHzMvYL29jdeQTVILecSaZKnt/RJWjoZCF5OW60Z67/GmSLBkOFM7qh1PI3zFNtJbaZL5eQu1vLfazOwj4g== + dependencies: + fetch-blob "^3.1.2" + forwarded@0.2.0: version "0.2.0" resolved "https://registry.yarnpkg.com/forwarded/-/forwarded-0.2.0.tgz#2269936428aad4c15c7ebe9779a84bf0b2a81811" @@ -3483,6 +3534,11 @@ has@^1.0.3: dependencies: function-bind "^1.1.1" +he@^1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/he/-/he-1.2.0.tgz#84ae65fa7eafb165fddb61566ae14baf05664f0f" + integrity sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw== + highlight.js@^10.7.1: version "10.7.3" resolved "https://registry.yarnpkg.com/highlight.js/-/highlight.js-10.7.3.tgz#697272e3991356e40c3cac566a74eef681756531" @@ -3495,6 +3551,11 @@ hoist-non-react-statics@^3.3.0, hoist-non-react-statics@^3.3.2: dependencies: react-is "^16.7.0" +hot-patcher@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/hot-patcher/-/hot-patcher-2.0.0.tgz#10a21b5bb4f5757316c41fc98794c11192a0a41e" + integrity sha512-rwJ0ZqSFgm+5oD0KiGBVinyPWRJESRSsHlEWDzZjyOe/OfhD9tynHqUyUIGX2fWuV+BihW4nXxeoZRJVHid64w== + htmlparser2@^8.0.1: version "8.0.1" resolved "https://registry.yarnpkg.com/htmlparser2/-/htmlparser2-8.0.1.tgz#abaa985474fcefe269bc761a779b544d7196d010" @@ -3969,6 +4030,11 @@ kind-of@^6.0.2: resolved "https://registry.yarnpkg.com/kind-of/-/kind-of-6.0.3.tgz#07c05034a6c349fa06e24fa35aa76db4580ce4dd" integrity sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw== +layerr@^0.1.2: + version "0.1.2" + resolved "https://registry.yarnpkg.com/layerr/-/layerr-0.1.2.tgz#16c8e7fb042d3595ab15492bdad088f31d7afd15" + integrity sha512-ob5kTd9H3S4GOG2nVXyQhOu9O8nBgP555XxWPkJI0tR0JeRilfyTp8WtPdIJHLXBmHMSdEq5+KMxiYABeScsIQ== + levn@^0.4.1: version "0.4.1" resolved "https://registry.yarnpkg.com/levn/-/levn-0.4.1.tgz#ae4562c007473b932a6200d403268dd2fffc6ade" @@ -4059,7 +4125,7 @@ lru-cache@^6.0.0: dependencies: yallist "^4.0.0" -md5@^2.2.1: +md5@^2.2.1, md5@^2.3.0: version "2.3.0" resolved "https://registry.yarnpkg.com/md5/-/md5-2.3.0.tgz#c3da9a6aae3a30b46b7b0c349b87b110dc3bda4f" integrity sha512-T1GITYmFaKuO91vxyoQMFETst+O71VUPEU3ze5GNzDm0OWdP8v1ziTaAEPUr/3kLsY3Sftgz242A1SetQiDL7g== @@ -4150,6 +4216,13 @@ minimatch@^3.0.4, minimatch@^3.1.1, minimatch@^3.1.2: dependencies: brace-expansion "^1.1.7" +minimatch@^5.1.0: + version "5.1.6" + resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-5.1.6.tgz#1cfcb8cf5522ea69952cd2af95ae09477f122a96" + integrity sha512-lKwV/1brpG6mBUFHtb7NUmtABCb2WZZmm2wNiOA5hAb8VdCS4B3dtMWyvcoViccwAW/COERjXLt0zP1zXUN26g== + dependencies: + brace-expansion "^2.0.1" + minimist@^1.1.0, minimist@^1.2.6: version "1.2.6" resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.6.tgz#8637a5b759ea0d6e98702cfb3a9283323c93af44" @@ -4237,6 +4310,11 @@ neo-async@^2.6.2: resolved "https://registry.yarnpkg.com/neo-async/-/neo-async-2.6.2.tgz#b4aafb93e3aeb2d8174ca53cf163ab7d7308305f" integrity sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw== +nested-property@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/nested-property/-/nested-property-4.0.0.tgz#a67b5a31991e701e03cdbaa6453bc5b1011bb88d" + integrity sha512-yFehXNWRs4cM0+dz7QxCd06hTbWbSkV0ISsqBfkntU6TOY4Qm3Q88fRRLOddkGh2Qq6dZvnKVAahfhjcUvLnyA== + nice-try@^1.0.4: version "1.0.5" resolved "https://registry.yarnpkg.com/nice-try/-/nice-try-1.0.5.tgz#a3378a7696ce7d223e88fc9b764bd7ef1089e366" @@ -4257,6 +4335,11 @@ nock@^12.0.3: lodash "^4.17.13" propagate "^2.0.0" +node-domexception@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/node-domexception/-/node-domexception-1.0.0.tgz#6888db46a1f71c0b76b3f7555016b63fe64766e5" + integrity sha512-/jKZoMpw0F8GRwl4/eLROPA3cfcXtLApP0QzLmUT/HuPCZWyB7IY9ZrMeKw2O/nFIqPQB3PVM9aYm0F312AXDQ== + node-fetch@2.6.7, node-fetch@^2.0.0, node-fetch@^2.6.1: version "2.6.7" resolved "https://registry.yarnpkg.com/node-fetch/-/node-fetch-2.6.7.tgz#24de9fba827e3b4ae44dc8b20256a379160052ad" @@ -4264,6 +4347,15 @@ node-fetch@2.6.7, node-fetch@^2.0.0, node-fetch@^2.6.1: dependencies: whatwg-url "^5.0.0" +node-fetch@^3.3.0: + version "3.3.1" + resolved "https://registry.yarnpkg.com/node-fetch/-/node-fetch-3.3.1.tgz#b3eea7b54b3a48020e46f4f88b9c5a7430d20b2e" + integrity sha512-cRVc/kyto/7E5shrWca1Wsea4y6tL9iYJE5FBCius3JQfb/4P4I295PfhgbJQBLTx6lATE4z+wK0rPM4VS2uow== + dependencies: + data-uri-to-buffer "^4.0.0" + fetch-blob "^3.1.4" + formdata-polyfill "^4.0.10" + node-polyglot@2.4.2: version "2.4.2" resolved "https://registry.yarnpkg.com/node-polyglot/-/node-polyglot-2.4.2.tgz#e4876e6710b70dc00b1351a9a68de4af47a5d61d" @@ -4567,6 +4659,11 @@ path-parse@^1.0.7: resolved "https://registry.yarnpkg.com/path-parse/-/path-parse-1.0.7.tgz#fbc114b60ca42b30d9daf5858e4bd68bbedb6735" integrity sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw== +path-posix@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/path-posix/-/path-posix-1.0.0.tgz#06b26113f56beab042545a23bfa88003ccac260f" + integrity sha512-1gJ0WpNIiYcQydgg3Ed8KzvIqTsDpNwq+cjBCssvBtuTWjEqY1AW+i+OepiEMqDCzyro9B2sLAe4RBPajMYFiA== + path-to-regexp@0.1.7: version "0.1.7" resolved "https://registry.yarnpkg.com/path-to-regexp/-/path-to-regexp-0.1.7.tgz#df604178005f522f15eb4490e7247a1bfaa67f8c" @@ -5479,6 +5576,11 @@ strip-json-comments@3.1.1, strip-json-comments@^3.1.0, strip-json-comments@^3.1. resolved "https://registry.yarnpkg.com/strip-json-comments/-/strip-json-comments-3.1.1.tgz#31f1281b3832630434831c310c01cccda8cbe006" integrity sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig== +strnum@^1.0.4: + version "1.0.5" + resolved "https://registry.yarnpkg.com/strnum/-/strnum-1.0.5.tgz#5c4e829fe15ad4ff0d20c3db5ac97b73c9b072db" + integrity sha512-J8bbNyKKXl5qYcR36TIO8W3mVGVHrmmxsd5PAItGkmyzwJvybiw2IVq5nqd0i4LSNSkB/sx9VHllbfFdr9k1JA== + strtok3@^6.2.4: version "6.3.0" resolved "https://registry.yarnpkg.com/strtok3/-/strtok3-6.3.0.tgz#358b80ffe6d5d5620e19a073aa78ce947a90f9a0" @@ -5750,7 +5852,12 @@ uri-js@^4.2.2: dependencies: punycode "^2.1.0" -url-parse@^1.4.7: +url-join@^4.0.1: + version "4.0.1" + resolved "https://registry.yarnpkg.com/url-join/-/url-join-4.0.1.tgz#b642e21a2646808ffa178c4c5fda39844e12cde7" + integrity sha512-jk1+QP6ZJqyOiuEI9AEWQfju/nB2Pw466kbA0LEZljHwKeMgd9WrAEgEGxjPDD2+TNbbb37rTyhEfrCXfuKXnA== + +url-parse@^1.4.7, url-parse@^1.5.10: version "1.5.10" resolved "https://registry.yarnpkg.com/url-parse/-/url-parse-1.5.10.tgz#9d3c2f736c1d75dd3bd2be507dcc111f1e2ea9c1" integrity sha512-WypcfiRhfeUP9vvF0j6rw0J3hrWrw6iZv3+22h6iRMJ/8z1Tj6XfLP4DsUix5MhMPnXpiHDoKyoZ/bdCkwBCiQ== @@ -5864,6 +5971,30 @@ watchpack@^2.3.1: glob-to-regexp "^0.4.1" graceful-fs "^4.1.2" +web-streams-polyfill@^3.0.3: + version "3.2.1" + resolved "https://registry.yarnpkg.com/web-streams-polyfill/-/web-streams-polyfill-3.2.1.tgz#71c2718c52b45fd49dbeee88634b3a60ceab42a6" + integrity sha512-e0MO3wdXWKrLbL0DgGnUV7WHVuw9OUvL4hjgnPkIeEvESk74gAITi5G606JtZPp39cd8HA9VQzCIvA49LpPN5Q== + +webdav@^5.0.0-r3: + version "5.0.0-r3" + resolved "https://registry.yarnpkg.com/webdav/-/webdav-5.0.0-r3.tgz#647d76fb84e9998bae5e0c4fde6c3893be4d2612" + integrity sha512-UGVbBWlZ2GudtRFgWiDeF/irk+vjncnlwnflsJW9+HNz0gBXO1CBlACQeyThcCck32VxyLHsw8M5MdAg28kSFw== + dependencies: + "@buttercup/fetch" "^0.1.0" + base-64 "^1.0.0" + byte-length "^1.0.2" + fast-xml-parser "^3.19.0" + he "^1.2.0" + hot-patcher "^2.0.0" + layerr "^0.1.2" + md5 "^2.3.0" + minimatch "^5.1.0" + nested-property "^4.0.0" + path-posix "^1.0.0" + url-join "^4.0.1" + url-parse "^1.5.10" + webidl-conversions@^3.0.0: version "3.0.1" resolved "https://registry.yarnpkg.com/webidl-conversions/-/webidl-conversions-3.0.1.tgz#24534275e2a7bc6be7bc86611cc16ae0a5654871" From 32849ba124d8d8e92058a2f6f881d4ef55a3ac28 Mon Sep 17 00:00:00 2001 From: Killian Courvoisier Date: Wed, 19 Apr 2023 16:21:30 +0200 Subject: [PATCH 3/7] feat: Auth on website and additional form field for url --- manifest.konnector | 4 ++++ src/index.js | 39 +++++++++++++++++++++++---------------- 2 files changed, 27 insertions(+), 16 deletions(-) diff --git a/manifest.konnector b/manifest.konnector index 84d515e..8269df2 100644 --- a/manifest.konnector +++ b/manifest.konnector @@ -15,6 +15,10 @@ }, "password": { "type": "password" + }, + "url": { + "type": "text", + "label": "Your nextcloud full url (ex. \"https://nextcloud.cozycloud.cc\")" } }, "folders": [{"defaultDir": "$administrative/$konnector/$account"}], diff --git a/src/index.js b/src/index.js index e9c2b48..ee84734 100644 --- a/src/index.js +++ b/src/index.js @@ -8,30 +8,37 @@ const { } = require('cozy-konnector-libs') const request = requestFactory({ // debug: true, - cheerio: true, - json: false, + cheerio: false, + json: true, jar: true }) -const VENDOR = 'nextcloud.cozycloud.cc' -const baseUrl = 'https://nextcloud.cozycloud.cc' - module.exports = new BaseKonnector(start) async function start(fields, cozyParameters) { log('info', 'Authenticating ...') if (cozyParameters) log('debug', 'Found COZY_PARAMETERS') - await authenticate.bind(this)(fields.login, fields.password) + await authenticate.bind(this)(fields) log('info', 'Successfully logged in') - log('info', 'Fetching the list of documents') - log('info', 'Parsing list of documents') - const documents = await parseDocuments() - log('info', 'Saving data to Cozy') - await this.saveBills(documents, fields, { - identifiers: ['nextcloud'] - }) } -function authenticate(username, password) {} - -function parseDocuments() {} +async function authenticate(fields) { + const loginPage = await request(`${fields.url}/login`) + const requestToken = loginPage.match(/data-requesttoken="(.*)">/)[1] + const postLoginPage = await request(`${fields.url}/login`, { + method: 'POST', + form: { + user: fields.login, + password: fields.password, + timezone: 'Europe/Paris', + timezone_offset: 2, + requesttoken: requestToken + }, + followRedirect: true, + resolveWithFullResponse: true + }) + if (postLoginPage.request.uri.href !== `${fields.url}/apps/dashboard/`) { + log('warn', 'something went wrong with login') + throw new Error('LOGIN_FAILED') + } +} From fc74e40548372373dc3f1d81cf6b363f74277f8e Mon Sep 17 00:00:00 2001 From: Killian Courvoisier Date: Fri, 21 Apr 2023 19:24:58 +0200 Subject: [PATCH 4/7] chore: Add xml2js dependency --- package.json | 3 +- yarn.lock | 105 +++++++++++++++++++++++---------------------------- 2 files changed, 49 insertions(+), 59 deletions(-) diff --git a/package.json b/package.json index 92c65e9..c517279 100644 --- a/package.json +++ b/package.json @@ -37,7 +37,8 @@ }, "dependencies": { "cozy-konnector-libs": "4.56.4", - "webdav": "^5.0.0-r3" + "webdav": "^4", + "xml2js": "^0.5.0" }, "devDependencies": { "cozy-jobs-cli": "1.20.2", diff --git a/yarn.lock b/yarn.lock index 7e92732..1479f9f 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1015,13 +1015,6 @@ "@babel/helper-validator-identifier" "^7.18.6" to-fast-properties "^2.0.0" -"@buttercup/fetch@^0.1.0": - version "0.1.0" - resolved "https://registry.yarnpkg.com/@buttercup/fetch/-/fetch-0.1.0.tgz#2c2dd34ac0758927dc612832b2834d9c42fd8d71" - integrity sha512-jkV4NLlE9BGQPgY+0sGi4s41IfreHACIICGpM6YhTlJlGp8XC4W2VapMBxdPenTgzduLU30c12PTvRlxpzoqBw== - optionalDependencies: - node-fetch "^3.3.0" - "@colors/colors@1.5.0": version "1.5.0" resolved "https://registry.yarnpkg.com/@colors/colors/-/colors-1.5.0.tgz#bb504579c1cae923e6576a4f5da43d25f97bdbd9" @@ -1761,6 +1754,14 @@ aws4@^1.8.0: resolved "https://registry.yarnpkg.com/aws4/-/aws4-1.11.0.tgz#d61f46d83b2519250e2784daf5b09479a8b41c59" integrity sha512-xh1Rl34h6Fi1DC2WWKfxUTVqRsNnr6LsKz2+hfwDxQJWmrx8+c7ylaqBMcHfl1U1r2dsifOvKX3LQuLNZ+XSvA== +axios@^0.27.2: + version "0.27.2" + resolved "https://registry.yarnpkg.com/axios/-/axios-0.27.2.tgz#207658cc8621606e586c85db4b41a750e756d972" + integrity sha512-t+yRIyySRTp/wua5xEr+z1q60QmLq8ABsS5O9Me1AsE5dfKqgnCFzwiCZZ/cGNd1lq4/7akDWMxdhVlucjmnOQ== + dependencies: + follow-redirects "^1.14.9" + form-data "^4.0.0" + babel-plugin-dynamic-import-node@^2.3.3: version "2.3.3" resolved "https://registry.yarnpkg.com/babel-plugin-dynamic-import-node/-/babel-plugin-dynamic-import-node-2.3.3.tgz#84fda19c976ec5c6defef57f9427b3def66e17a3" @@ -2123,7 +2124,7 @@ colors@1.0.x: resolved "https://registry.yarnpkg.com/colors/-/colors-1.0.3.tgz#0433f44d809680fdeb60ed260f1b0c262e82a40b" integrity sha512-pFGrxThWcWQ2MsAz6RtgeWe4NK2kUE1WfsrvvlctdII745EW9I0yflqhe7++M5LEc7bV2c/9/5zc8sFcpL0Drw== -combined-stream@^1.0.6, combined-stream@~1.0.6: +combined-stream@^1.0.6, combined-stream@^1.0.8, combined-stream@~1.0.6: version "1.0.8" resolved "https://registry.yarnpkg.com/combined-stream/-/combined-stream-1.0.8.tgz#c3d45a8b34fd730631a110a8a2520682b31d5a7f" integrity sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg== @@ -2563,11 +2564,6 @@ dashdash@^1.12.0: dependencies: assert-plus "^1.0.0" -data-uri-to-buffer@^4.0.0: - version "4.0.1" - resolved "https://registry.yarnpkg.com/data-uri-to-buffer/-/data-uri-to-buffer-4.0.1.tgz#d8feb2b2881e6a4f58c2e08acfd0e2834e26222e" - integrity sha512-0R9ikRb668HB7QDxT1vkpuUBtqc53YyAwMwGeUFKRojY/NWKvdZ+9UYtRfGmhqNbRkTSVpMbmyhXipFFv2cb/A== - date-fns@^1.30.1: version "1.30.1" resolved "https://registry.yarnpkg.com/date-fns/-/date-fns-1.30.1.tgz#2e71bf0b119153dbb4cc4e88d9ea5acfb50dc05c" @@ -3193,14 +3189,6 @@ fastq@^1.6.0: dependencies: reusify "^1.0.4" -fetch-blob@^3.1.2, fetch-blob@^3.1.4: - version "3.2.0" - resolved "https://registry.yarnpkg.com/fetch-blob/-/fetch-blob-3.2.0.tgz#f09b8d4bbd45adc6f0c20b7e787e793e309dcce9" - integrity sha512-7yAQpD2UMJzLi1Dqv7qFYnPbaPx7ZfFK6PiIxQ4PfkGPyNyl2Ugx+a/umUonmKqjhM4DnfbMvdX6otXq83soQQ== - dependencies: - node-domexception "^1.0.0" - web-streams-polyfill "^3.0.3" - fetch-cookie@0.7.0: version "0.7.0" resolved "https://registry.yarnpkg.com/fetch-cookie/-/fetch-cookie-0.7.0.tgz#a6fc137ad8363aa89125864c6451b86ecb7de802" @@ -3281,11 +3269,25 @@ flatted@^3.1.0: resolved "https://registry.yarnpkg.com/flatted/-/flatted-3.2.6.tgz#022e9218c637f9f3fc9c35ab9c9193f05add60b2" integrity sha512-0sQoMh9s0BYsm+12Huy/rkKxVu4R1+r96YX5cG44rHV0pQ6iC3Q+mkoMFaGWObMFYQxCVT+ssG1ksneA2MI9KQ== +follow-redirects@^1.14.9: + version "1.15.2" + resolved "https://registry.yarnpkg.com/follow-redirects/-/follow-redirects-1.15.2.tgz#b460864144ba63f2681096f274c4e57026da2c13" + integrity sha512-VQLG33o04KaQ8uYi2tVNbdrWp1QWxNNea+nmIB4EVM28v0hmP17z7aG1+wAkNzVq4KeXTq3221ye5qTJP91JwA== + forever-agent@~0.6.1: version "0.6.1" resolved "https://registry.yarnpkg.com/forever-agent/-/forever-agent-0.6.1.tgz#fbc71f0c41adeb37f96c577ad1ed42d8fdacca91" integrity sha512-j0KLYPhm6zeac4lz3oJ3o65qvgQCcPubiyotZrXqEaG4hNagNYO8qdlUrX5vwqv9ohqeT/Z3j6+yW067yWWdUw== +form-data@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/form-data/-/form-data-4.0.0.tgz#93919daeaf361ee529584b9b31664dc12c9fa452" + integrity sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww== + dependencies: + asynckit "^0.4.0" + combined-stream "^1.0.8" + mime-types "^2.1.12" + form-data@~2.3.2: version "2.3.3" resolved "https://registry.yarnpkg.com/form-data/-/form-data-2.3.3.tgz#dcce52c05f644f298c6a7ab936bd724ceffbf3a6" @@ -3295,13 +3297,6 @@ form-data@~2.3.2: combined-stream "^1.0.6" mime-types "^2.1.12" -formdata-polyfill@^4.0.10: - version "4.0.10" - resolved "https://registry.yarnpkg.com/formdata-polyfill/-/formdata-polyfill-4.0.10.tgz#24807c31c9d402e002ab3d8c720144ceb8848423" - integrity sha512-buewHzMvYL29jdeQTVILecSaZKnt/RJWjoZCF5OW60Z67/GmSLBkOFM7qh1PI3zFNtJbaZL5eQu1vLfazOwj4g== - dependencies: - fetch-blob "^3.1.2" - forwarded@0.2.0: version "0.2.0" resolved "https://registry.yarnpkg.com/forwarded/-/forwarded-0.2.0.tgz#2269936428aad4c15c7ebe9779a84bf0b2a81811" @@ -3551,10 +3546,10 @@ hoist-non-react-statics@^3.3.0, hoist-non-react-statics@^3.3.2: dependencies: react-is "^16.7.0" -hot-patcher@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/hot-patcher/-/hot-patcher-2.0.0.tgz#10a21b5bb4f5757316c41fc98794c11192a0a41e" - integrity sha512-rwJ0ZqSFgm+5oD0KiGBVinyPWRJESRSsHlEWDzZjyOe/OfhD9tynHqUyUIGX2fWuV+BihW4nXxeoZRJVHid64w== +hot-patcher@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/hot-patcher/-/hot-patcher-1.0.0.tgz#7124d2dc4ca71bcb58b1551603cd13e4fc3fcecd" + integrity sha512-3H8VH0PreeNsKMZw16nTHbUp4YoHCnPlawpsPXGJUR4qENDynl79b6Xk9CIFvLcH1qungBsCuzKcWyzoPPalTw== htmlparser2@^8.0.1: version "8.0.1" @@ -4335,11 +4330,6 @@ nock@^12.0.3: lodash "^4.17.13" propagate "^2.0.0" -node-domexception@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/node-domexception/-/node-domexception-1.0.0.tgz#6888db46a1f71c0b76b3f7555016b63fe64766e5" - integrity sha512-/jKZoMpw0F8GRwl4/eLROPA3cfcXtLApP0QzLmUT/HuPCZWyB7IY9ZrMeKw2O/nFIqPQB3PVM9aYm0F312AXDQ== - node-fetch@2.6.7, node-fetch@^2.0.0, node-fetch@^2.6.1: version "2.6.7" resolved "https://registry.yarnpkg.com/node-fetch/-/node-fetch-2.6.7.tgz#24de9fba827e3b4ae44dc8b20256a379160052ad" @@ -4347,15 +4337,6 @@ node-fetch@2.6.7, node-fetch@^2.0.0, node-fetch@^2.6.1: dependencies: whatwg-url "^5.0.0" -node-fetch@^3.3.0: - version "3.3.1" - resolved "https://registry.yarnpkg.com/node-fetch/-/node-fetch-3.3.1.tgz#b3eea7b54b3a48020e46f4f88b9c5a7430d20b2e" - integrity sha512-cRVc/kyto/7E5shrWca1Wsea4y6tL9iYJE5FBCius3JQfb/4P4I295PfhgbJQBLTx6lATE4z+wK0rPM4VS2uow== - dependencies: - data-uri-to-buffer "^4.0.0" - fetch-blob "^3.1.4" - formdata-polyfill "^4.0.10" - node-polyglot@2.4.2: version "2.4.2" resolved "https://registry.yarnpkg.com/node-polyglot/-/node-polyglot-2.4.2.tgz#e4876e6710b70dc00b1351a9a68de4af47a5d61d" @@ -5265,7 +5246,7 @@ safe-buffer@5.2.1, safe-buffer@^5.0.1, safe-buffer@^5.1.0, safe-buffer@^5.1.2, s resolved "https://registry.yarnpkg.com/safer-buffer/-/safer-buffer-2.1.2.tgz#44fa161b0187b9549dd84bb91802f9bd8385cd6a" integrity sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg== -sax@~1.2.4: +sax@>=0.6.0, sax@~1.2.4: version "1.2.4" resolved "https://registry.yarnpkg.com/sax/-/sax-1.2.4.tgz#2816234e2378bddc4e5354fab5caa895df7100d9" integrity sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw== @@ -5971,22 +5952,17 @@ watchpack@^2.3.1: glob-to-regexp "^0.4.1" graceful-fs "^4.1.2" -web-streams-polyfill@^3.0.3: - version "3.2.1" - resolved "https://registry.yarnpkg.com/web-streams-polyfill/-/web-streams-polyfill-3.2.1.tgz#71c2718c52b45fd49dbeee88634b3a60ceab42a6" - integrity sha512-e0MO3wdXWKrLbL0DgGnUV7WHVuw9OUvL4hjgnPkIeEvESk74gAITi5G606JtZPp39cd8HA9VQzCIvA49LpPN5Q== - -webdav@^5.0.0-r3: - version "5.0.0-r3" - resolved "https://registry.yarnpkg.com/webdav/-/webdav-5.0.0-r3.tgz#647d76fb84e9998bae5e0c4fde6c3893be4d2612" - integrity sha512-UGVbBWlZ2GudtRFgWiDeF/irk+vjncnlwnflsJW9+HNz0gBXO1CBlACQeyThcCck32VxyLHsw8M5MdAg28kSFw== +webdav@^4: + version "4.11.2" + resolved "https://registry.yarnpkg.com/webdav/-/webdav-4.11.2.tgz#49cde29e33538bc9f3d3a0a4da0f3d16215f5794" + integrity sha512-Ht9TPD5EB7gYW0YmhRcE5NW0/dn/HQfyLSPQY1Rw1coQ5MQTUooAQ9Bpqt4EU7QLw0b95tX4cU59R+SIojs9KQ== dependencies: - "@buttercup/fetch" "^0.1.0" + axios "^0.27.2" base-64 "^1.0.0" byte-length "^1.0.2" fast-xml-parser "^3.19.0" he "^1.2.0" - hot-patcher "^2.0.0" + hot-patcher "^1.0.0" layerr "^0.1.2" md5 "^2.3.0" minimatch "^5.1.0" @@ -6135,6 +6111,19 @@ wrappy@1: resolved "https://registry.yarnpkg.com/wrappy/-/wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f" integrity sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ== +xml2js@^0.5.0: + version "0.5.0" + resolved "https://registry.yarnpkg.com/xml2js/-/xml2js-0.5.0.tgz#d9440631fbb2ed800203fad106f2724f62c493b7" + integrity sha512-drPFnkQJik/O+uPKpqSgr22mpuFHqKdbS835iAQrUC73L2F5WkboIRd63ai/2Yg6I1jzifPFKH2NTK+cfglkIA== + dependencies: + sax ">=0.6.0" + xmlbuilder "~11.0.0" + +xmlbuilder@~11.0.0: + version "11.0.1" + resolved "https://registry.yarnpkg.com/xmlbuilder/-/xmlbuilder-11.0.1.tgz#be9bae1c8a046e76b31127726347d0ad7002beb3" + integrity sha512-fDlsI/kFEx7gLvbecc0/ohLG50fugQp8ryHzMTuW9vSa1GJ0XYWKnhsUx7oie3G98+r56aTQIUB4kht42R3JvA== + y18n@^5.0.5: version "5.0.8" resolved "https://registry.yarnpkg.com/y18n/-/y18n-5.0.8.tgz#7f4934d0f7ca8c56f95314939ddcd2dd91ce1d55" From b73b494a45b1dd72644fd36302f8956937a42aa0 Mon Sep 17 00:00:00 2001 From: Killian Courvoisier Date: Fri, 21 Apr 2023 19:25:34 +0200 Subject: [PATCH 5/7] feat: Create client and fetch users contacts --- src/index.js | 27 ++++++++++++++- src/nextcloudClient.js | 75 ++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 101 insertions(+), 1 deletion(-) create mode 100644 src/nextcloudClient.js diff --git a/src/index.js b/src/index.js index ee84734..eb74a03 100644 --- a/src/index.js +++ b/src/index.js @@ -6,6 +6,8 @@ const { log, utils } = require('cozy-konnector-libs') +const { NextcloudClient } = require('./nextcloudClient') + const request = requestFactory({ // debug: true, cheerio: false, @@ -18,8 +20,9 @@ module.exports = new BaseKonnector(start) async function start(fields, cozyParameters) { log('info', 'Authenticating ...') if (cozyParameters) log('debug', 'Found COZY_PARAMETERS') - await authenticate.bind(this)(fields) + const userCookies = await authenticate.bind(this)(fields) log('info', 'Successfully logged in') + await getUserContacts.bind(this)(fields, userCookies) } async function authenticate(fields) { @@ -41,4 +44,26 @@ async function authenticate(fields) { log('warn', 'something went wrong with login') throw new Error('LOGIN_FAILED') } + const cookies = postLoginPage.request.headers.cookie.split('; ') + let userNumber + let ncToken + for (const cookie of cookies) { + if (cookie.startsWith('nc_username')) { + userNumber = cookie.split('=')[1] + } + if (cookie.startsWith('nc_token')) { + ncToken = cookie.split('=')[1] + } + } + log('info', ncToken) + return { ncToken, userNumber } +} + +async function getUserContacts(fields, userCookies) { + log('info', 'getUserContacts starts') + const ncClient = new NextcloudClient({ fields, userCookies }) + const client = ncClient.createClient() + log('info', client) + const XMLUserContacts = await ncClient.getUserContacts(client) + // log('info', XMLUserContacts) } diff --git a/src/nextcloudClient.js b/src/nextcloudClient.js new file mode 100644 index 0000000..c82e7d5 --- /dev/null +++ b/src/nextcloudClient.js @@ -0,0 +1,75 @@ +const { createClient } = require('webdav') +const { log } = require('cozy-konnector-libs') +const xml2js = require('xml2js') + +class NextcloudClient { + constructor({ fields, userCookies }) { + this.fields = fields + this.userCookies = userCookies + } + createClient() { + const client = createClient( + `${this.fields.url}/remote.php/dav/addressbooks/users/${this.userCookies.userNumber}/default_shared_by_admin/`, + { username: this.fields.login, password: this.fields.password } + ) + return client + } + + async getUserContacts(client) { + log('info', 'getUserContacts starts') + const resultContacts = await this.makeCustomRequest(client, '/') + // const resultContacts = await client.customRequest('/', { + // method: 'PROPFIND', + // headers: { + // 'Content-Type': 'text/xml' + // } + // }) + // log('info', resultContacts) + const contactsHref = [] + xml2js.parseString(resultContacts.data, function (err, result) { + if (err) { + log('warn', err) + return + } + const nodes = result['d:multistatus']['d:response'] + for (const node of nodes) { + contactsHref.push(node['d:href'][0]) + } + }) + // Here we shifting the first element because it's just de base URL + contactsHref.shift() + const fullContactsVCARD = [] + let loop = 1 + for (const contactHref of contactsHref) { + log('info', `contactHref is ${contactHref} at ${loop} loop`) + const contactCode = contactHref.split('admin')[1] + const fullContact = await this.makeCustomRequest(client, contactCode) + loop++ + log('info', 'fullContact') + fullContactsVCARD.push(fullContact) + } + + // ON REPRENDS ICI LUNDI + log('info', 'getUserContacts ends') + } + + async makeCustomRequest(client, path) { + log('info', 'makeCustomRequest starts') + if (path === '/') { + log('info', 'path is "/"') + const result = await client.customRequest('/', { + method: 'PROPFIND', + headers: { + 'Content-Type': 'text/xml' + } + }) + return result + } + const result = await client.getFileContents(path, { + format: 'text' + }) + return result + } +} + +module.exports = { NextcloudClient } From 230ee9eb0ed2b7be252778053fec93c744ae960d Mon Sep 17 00:00:00 2001 From: Killian Courvoisier Date: Mon, 24 Apr 2023 16:03:47 +0200 Subject: [PATCH 6/7] chore: Add cozy-vcard dependency --- package.json | 1 + yarn.lock | 20 ++++++++++++++++++++ 2 files changed, 21 insertions(+) diff --git a/package.json b/package.json index c517279..7be73c9 100644 --- a/package.json +++ b/package.json @@ -37,6 +37,7 @@ }, "dependencies": { "cozy-konnector-libs": "4.56.4", + "cozy-vcard": "^0.2.18", "webdav": "^4", "xml2js": "^0.5.0" }, diff --git a/yarn.lock b/yarn.lock index 1479f9f..b75665d 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2451,6 +2451,14 @@ cozy-stack-client@^33.4.0: mime "^2.4.0" qs "^6.7.0" +cozy-vcard@^0.2.18: + version "0.2.18" + resolved "https://registry.yarnpkg.com/cozy-vcard/-/cozy-vcard-0.2.18.tgz#9f4147da175fafca86475ddc7e212b989bdc0542" + integrity sha512-RyhCbfj/74lxvHXG2GrLutHLjNGj+qb5+BgSsu5ptMcFT+G2Ku9BrK3P7kNNPB6hFPGYmmUY/J05dGLh5+lIXg== + dependencies: + quoted-printable "0.2.1" + utf8 "2.0.0" + cross-fetch@^3.0.6: version "3.1.5" resolved "https://registry.yarnpkg.com/cross-fetch/-/cross-fetch-3.1.5.tgz#e1389f44d9e7ba767907f7af8454787952ab534f" @@ -4943,6 +4951,13 @@ queue-microtask@^1.2.2: resolved "https://registry.yarnpkg.com/queue-microtask/-/queue-microtask-1.2.3.tgz#4929228bbc724dfac43e0efb058caf7b6cfb6243" integrity sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A== +quoted-printable@0.2.1: + version "0.2.1" + resolved "https://registry.yarnpkg.com/quoted-printable/-/quoted-printable-0.2.1.tgz#448649cc22ea66a1b614d0eb93343c47602004b5" + integrity sha512-Pnirhi0yrZcNgZdpP7AGYWSoSgnA1zCgTtYycqf139+ozAG5f52lU4MnDOnqC10X7rtQOs/pAb297fjSgIioHQ== + dependencies: + utf8 "~2.0.0" + randombytes@^2.1.0: version "2.1.0" resolved "https://registry.yarnpkg.com/randombytes/-/randombytes-2.1.0.tgz#df6f84372f0270dc65cdf6291349ab7a473d4f2a" @@ -5856,6 +5871,11 @@ utf8-byte-length@^1.0.4: resolved "https://registry.yarnpkg.com/utf8-byte-length/-/utf8-byte-length-1.0.4.tgz#f45f150c4c66eee968186505ab93fcbb8ad6bf61" integrity sha512-4+wkEYLBbWxqTahEsWrhxepcoVOJ+1z5PGIjPZxRkytcdSUaNjIjBM7Xn8E+pdSuV7SzvWovBFA54FO0JSoqhA== +utf8@2.0.0, utf8@~2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/utf8/-/utf8-2.0.0.tgz#79ce59eced874809cab9a71fc7102c7d45d4118d" + integrity sha512-jWXHr+bQ8RsWazLzVY3V7XACPTbBHYSg/VoDVok+DBQk5ULm0AuBCNb9tGmjq2H+znnkBFwjhzzCbn9G3xlYcA== + util-deprecate@^1.0.1, util-deprecate@^1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/util-deprecate/-/util-deprecate-1.0.2.tgz#450d4dc9fa70de732762fbd2d4a28981419a0ccf" From b17b2eee56162aab5aa99f308ddaf2df02351b83 Mon Sep 17 00:00:00 2001 From: Killian Courvoisier Date: Mon, 24 Apr 2023 16:04:18 +0200 Subject: [PATCH 7/7] feat: Parse contacts --- src/index.js | 42 +++++++++++++++++++++++------------------- src/nextcloudClient.js | 22 ++++------------------ 2 files changed, 27 insertions(+), 37 deletions(-) diff --git a/src/index.js b/src/index.js index eb74a03..ebfa100 100644 --- a/src/index.js +++ b/src/index.js @@ -1,12 +1,7 @@ /* eslint-disable no-unused-vars */ -const { - BaseKonnector, - requestFactory, - scrape, - log, - utils -} = require('cozy-konnector-libs') +const { BaseKonnector, requestFactory, log } = require('cozy-konnector-libs') const { NextcloudClient } = require('./nextcloudClient') +const VCardParser = require('cozy-vcard') const request = requestFactory({ // debug: true, @@ -15,6 +10,13 @@ const request = requestFactory({ jar: true }) +const cozyVCardParser = { + parse: data => { + const parser = new VCardParser(data) + return parser.contacts + } +} + module.exports = new BaseKonnector(start) async function start(fields, cozyParameters) { @@ -22,7 +24,7 @@ async function start(fields, cozyParameters) { if (cozyParameters) log('debug', 'Found COZY_PARAMETERS') const userCookies = await authenticate.bind(this)(fields) log('info', 'Successfully logged in') - await getUserContacts.bind(this)(fields, userCookies) + const userContacts = await getUserContacts.bind(this)(fields, userCookies) } async function authenticate(fields) { @@ -46,24 +48,26 @@ async function authenticate(fields) { } const cookies = postLoginPage.request.headers.cookie.split('; ') let userNumber - let ncToken for (const cookie of cookies) { if (cookie.startsWith('nc_username')) { userNumber = cookie.split('=')[1] } - if (cookie.startsWith('nc_token')) { - ncToken = cookie.split('=')[1] - } } - log('info', ncToken) - return { ncToken, userNumber } + return userNumber } -async function getUserContacts(fields, userCookies) { +async function getUserContacts(fields, userNumber) { log('info', 'getUserContacts starts') - const ncClient = new NextcloudClient({ fields, userCookies }) + const ncClient = new NextcloudClient({ fields, userNumber }) const client = ncClient.createClient() - log('info', client) - const XMLUserContacts = await ncClient.getUserContacts(client) - // log('info', XMLUserContacts) + const contactsVCards = await ncClient.getUserContacts(client) + let parsedContacts = [] + for (const contactVCard of contactsVCards) { + const contact = cozyVCardParser.parse(contactVCard) + if (contact[0].n.match(';;;')) { + contact[0].n = contact[0].n.replace(/;;;/g, '').replace(';', ' ').trim() + } + parsedContacts.push(contact[0]) + } + return parsedContacts } diff --git a/src/nextcloudClient.js b/src/nextcloudClient.js index c82e7d5..5811423 100644 --- a/src/nextcloudClient.js +++ b/src/nextcloudClient.js @@ -3,13 +3,13 @@ const { log } = require('cozy-konnector-libs') const xml2js = require('xml2js') class NextcloudClient { - constructor({ fields, userCookies }) { + constructor({ fields, userNumber }) { this.fields = fields - this.userCookies = userCookies + this.userNumber = userNumber } createClient() { const client = createClient( - `${this.fields.url}/remote.php/dav/addressbooks/users/${this.userCookies.userNumber}/default_shared_by_admin/`, + `${this.fields.url}/remote.php/dav/addressbooks/users/${this.userNumber}/default_shared_by_admin/`, { username: this.fields.login, password: this.fields.password } ) return client @@ -18,13 +18,6 @@ class NextcloudClient { async getUserContacts(client) { log('info', 'getUserContacts starts') const resultContacts = await this.makeCustomRequest(client, '/') - // const resultContacts = await client.customRequest('/', { - // method: 'PROPFIND', - // headers: { - // 'Content-Type': 'text/xml' - // } - // }) - // log('info', resultContacts) const contactsHref = [] xml2js.parseString(resultContacts.data, function (err, result) { if (err) { @@ -39,24 +32,17 @@ class NextcloudClient { // Here we shifting the first element because it's just de base URL contactsHref.shift() const fullContactsVCARD = [] - let loop = 1 for (const contactHref of contactsHref) { - log('info', `contactHref is ${contactHref} at ${loop} loop`) const contactCode = contactHref.split('admin')[1] const fullContact = await this.makeCustomRequest(client, contactCode) - loop++ - log('info', 'fullContact') fullContactsVCARD.push(fullContact) } - - // ON REPRENDS ICI LUNDI - log('info', 'getUserContacts ends') + return fullContactsVCARD } async makeCustomRequest(client, path) { log('info', 'makeCustomRequest starts') if (path === '/') { - log('info', 'path is "/"') const result = await client.customRequest('/', { method: 'PROPFIND', headers: {