Skip to content

Commit

Permalink
init
Browse files Browse the repository at this point in the history
  • Loading branch information
doubleface committed Mar 31, 2017
0 parents commit 8670fac
Show file tree
Hide file tree
Showing 21 changed files with 1,544 additions and 0 deletions.
24 changes: 24 additions & 0 deletions .editorconfig
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
# editorconfig.org
# editorconfig is a unified configuration file that all editors can take
# into account
root = true

[*]
charset = utf-8
end_of_line = lf
trim_trailing_whitespace = true
insert_final_newline = true
indent_style = space
indent_size = 2

[*.coffee]
indent_size = 4

[*.jade]
trim_trailing_whitespace = false

[*.pug]
trim_trailing_whitespace = false

[*.styl]
indent_size = 4
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
node_modules/*
token.json
661 changes: 661 additions & 0 deletions LICENSE

Large diffs are not rendered by default.

79 changes: 79 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
[Cozy][cozy] <YOUR SUPER NEW KONNECTOR NAME>
=======================================

What's Cozy?
------------

![Cozy Logo](https://cdn.rawgit.com/cozy/cozy-guidelines/master/templates/cozy_logo_small.svg)

[Cozy] is a platform that brings all your web services in the same private space. With it, your webapps and your devices can share data easily, providing you with a new experience. You can install Cozy on your own hardware where no one's tracking you.


What's this new konnector?
----------------------------------

<YOUR DESCRIPTION HERE>

### Open a Pull-Request

If you want to work on Bouygues Telecom Konnector and submit code modifications, feel free to open pull-requests! See the [contributing guide][contribute] for more information about how to properly open pull-requests.

### Hack

If you have a running accessible cozy-stack you can test your the konnector without installing
and/or updating the konnector in the cozy-stack :

You first need an installed nodejs (LTS version is fine)

Then run :

```sh
export COZY_URL=http://cozy.local:8080
node gettoken.js $COZY_URL
```

Replace http://cozy.local:8080 by your real cozy url if needed.

Follow the described procedure and you will get a token.json file.

Then just run :

```sh
export COZY_CREDENTIALS=$(<token.json)
```

You can now run our konnector like this :

```sh
node index.js $login $password $folderPath
```

Where $folderPath is the path where the pdf
bills will be saved

### Maintainer

The lead maintainers for this konnector is <YOUR NAME>


### Get in touch

You can reach the Cozy Community by:

- Chatting with us on IRC [#cozycloud on Freenode][freenode]
- Posting on our [Forum]
- Posting issues on the [Github repos][github]
- Say Hi! on [Twitter]


License
-------

<YOUR KONNECTOR NAME> is developed by @doubleface and distributed under the [AGPL v3 license][agpl-3.0].

[cozy]: https://cozy.io "Cozy Cloud"
[agpl-3.0]: https://www.gnu.org/licenses/agpl-3.0.html
[freenode]: http://webchat.freenode.net/?randomnick=1&channels=%23cozycloud&uio=d4
[forum]: https://forum.cozy.io/
[github]: https://github.com/cozy/
[twitter]: https://twitter.com/mycozycloud
36 changes: 36 additions & 0 deletions README_migration.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
# How to migrate your existing konnector easily?

## Intro

This doc describes how you can migrate a v2 konnector to a V3 konnector as easily as possible. At
the moment, it applies only to login/password konnectors (not OAuth ones especially).


## Convert Coffeescript to es2015 code (if needed)

There are still a lot of konnectors which are coded in coffeescript. We do not intent to support
coffeescript in this new version of cozy, and it would be good to do it for your konnector (but you
can still compile with coffeescript if you want and it is not supported by this document).

Just run :

```sh
npm install -g decaffeinate
decaffeinate --keep-commonjs konnector.coffee
```

Now you have a nice konnector.js file !

There may be some small problems though. Each time the ''.?'' was used, a _guardxx_ function will be generated. It works but a human
intervention will make it more easy to read.

## Remove code related to kresus

Kresus is not supported (yet?) in cozy v3, then it is not possible to link you bills to you bank
operations. Just remove code calling the linkBankOperation lib.

## You can test your konnector!

Most of the libs used by konnectors have been migrated to use cozy-client-js instead of v2 code and
are directly available in the lib directory of this template. Oh yes for that you need to execute a
tiny search and replace from '../lib' to './lib' in your konnector code and you will be done.
48 changes: 48 additions & 0 deletions gettoken.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
const http = require('http')
const path = require('path')
const {Client, MemoryStorage} = require('cozy-client-js')
const manifest = require('./lib/manifest')

const cozyURL = process.argv[2] ? process.argv[2] : 'http://cozy.local:8080'

const scopes = manifest.getScopes(path.join(__dirname, 'manifest.konnectors'))

function onRegistered (client, url) {
let server
return new Promise((resolve) => {
server = http.createServer((request, response) => {
if (request.url.indexOf('/do_access') === 0) {
console.log('Received access from user with url', request.url)
resolve(request.url)
response.end()
}
})
server.listen(3333, () => {
console.log('Please visit the following url to authorize the application: ', url)
})
})
.then(
(url) => { server.close(); return url },
(err) => { server.close(); throw err }
)
}

const cozy = new Client({
cozyURL,
oauth: {
storage: new MemoryStorage(),
clientParams: {
redirectURI: 'http://localhost:3333/do_access',
softwareID: 'foobar',
clientName: 'client',
scopes: scopes
},
onRegistered: onRegistered
}
})

cozy.authorize().then((creds) => {
require('fs').writeFileSync(path.join(__dirname, '/token.json'), JSON.stringify(creds))
console.log('File saved in ' + path.join(__dirname, '/token.json'))
process.exit()
})
9 changes: 9 additions & 0 deletions index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
const konnector = require('./konnector')
const phoneNumber = process.argv[2]
const password = process.argv[3]
const folderPath = process.argv[4]

konnector.fetch({login, password, folderPath}, err => {
console.log('The konnector has been run')
if (err) console.log(err, 'There was an error')
})
1 change: 1 addition & 0 deletions konnector.js
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
// putt your konnector code here
60 changes: 60 additions & 0 deletions lib/base_konnector.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
'use strict'

const _ = require('lodash')
const printit = require('printit')
const slugify = require('cozy-slug')
const fetcher = require('./fetcher')

module.exports = {

/*
* Add common features to given konnector:
*
* * build its slug.
* * build description translation key based on slug.
* * add a dedicated logger.
* * Change the array model to object (dirty hack to ensure backward
* compatibility).
* * Add a default fetch function that runs operations set at konnector
* level.
*/
createNew: function (konnector) {
var slug = slugify(konnector.slug || konnector.name)
slug = slug.replace(/(-|\.)/g, '_')

var logger = printit({
prefix: konnector.name,
date: true
})

var modelsObj = {}
konnector.models.forEach((model) => {
modelsObj[model.displayName.toLowerCase()] = model
})

return _.assignIn(konnector, {
slug: slug,
description: `konnector description ${slug}`,
logger: logger,
models: modelsObj,

fetch: function (requiredFields, callback) {
var importer = fetcher.new()
konnector.fetchOperations.forEach(operation => {
importer.use(operation)
})
importer.args(requiredFields, {}, {})
importer.fetch((err, fields, entries) => {
if (err) {
konnector.logger.error('Import failed.')
callback(err)
} else {
konnector.logger.info('Import succeeded.')
callback(null, entries.notifContent)
}
})
}

})
}
}
29 changes: 29 additions & 0 deletions lib/cozyclient.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
const {Client, MemoryStorage} = require('cozy-client-js')

// COZY_CREDENTIALS
let credentials = null
try {
credentials = JSON.parse(process.env.COZY_CREDENTIALS)
} catch (err) {
console.log(`Please provide proper COZY_CREDENTIALS environment variable. ${process.env.COZY_CREDENTIALS} is not OK`)
process.exit(1)
}

// COZY_URL
if (process.env.COZY_URL === undefined) {
console.log(`Please provide COZY_URL environment variable.`)
process.exit(1)
}

credentials.token.toAuthHeader = function () {
return 'Bearer ' + credentials.client.registrationAccessToken
}

const cozy = new Client({
cozyURL: process.env.COZY_URL,
oauth: {storage: new MemoryStorage()}
})

cozy.saveCredentials(credentials.client, credentials.token)

module.exports = cozy
47 changes: 47 additions & 0 deletions lib/fetcher.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
const ware = require('ware')

// Class to handle the layer of the fetching operation. Basically it runs a set
// of function and make sure they all share the same parameters.
//
// Example that runs to functions logIn and parsePage.
//
// fetcher.new()
// .use(logIn)
// .use(parsePage)
// .args(requiredFields, {}, {})
// .fetch (err, fields, entries) ->
// log.info "Import finished"
class Fetcher {
constructor () {
this.ware = ware()
}

// Set arguments to give to all layers.
args () {
this.args = arguments
return this
}

// Add a layer to use. A layer is a function to execute while fetching.
use (operation) {
this.ware.use(operation)
return this
}

// Run fetching by running layers one by one.
fetch (callback) {
let args = [].slice.call(this.args)
args.push(callback)

return this.ware.run.apply(this.ware, args)
}

// Return all set layers.
getLayers () {
return this.ware.fns
}
}

module.exports = {
new: () => new Fetcher()
}
53 changes: 53 additions & 0 deletions lib/filter_existing.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
// Returns a fetcher layer that adds a new array field to the second function
// parameter.
// This array contains all entries that are not already stored in the
// database. To know if an entry has no match in the database, it checks if
// date fields are the same.
//
// It expects a field called "fetched" as field of the second parameter. This
// field contains the entries to filter.
//
module.exports = (log, model, suffix, vendor) => {
return function (requiredFields, entries, body, next) {
entries.filtered = []

// Set vendor automatically if not given
if ((vendor == null) && (entries.fetched.length > 0)) {
({ vendor } = entries.fetched[0])
}

// Get current entries
return model.all(function (err, entryObjects) {
let hash
if (err) { return next(err) }
const entryHash = {}

// Build an hash where key is the date and valie is the entry
for (let entry of Array.from(entryObjects)) {
// If a vendor parameter is given, entry should be of given
// vendor to be added to the hash (useful for bills).
if (vendor != null) {
if (entry.vendor === vendor) {
hash = `${entry.date.format('YYYY-MM-DD')}T00:00:00.000Z`
entryHash[hash] = entry
}

// Simply add the entry
} else {
hash = `${entry.date.format('YYYY-MM-DD')}T00:00:00.000Z`
entryHash[hash] = entry
}
}

// Keep only non already existing entries.
entries.filtered = entries.fetched.filter(function (entry) {
hash = `${entry.date.format('YYYY-MM-DD')}T00:00:00.000Z`
return (entryHash[hash] == null)
})

// Keep only entries matching current vendor.
entries.filtered = entries.filtered.filter(entry => entry.vendor === vendor)
return next()
})
}
}
Loading

0 comments on commit 8670fac

Please sign in to comment.