Skip to content

Commit

Permalink
fix: use api
Browse files Browse the repository at this point in the history
* login test

* regular user

* crud databases

* list test, add pouch

* crud docs

* fix: getDatabase

* fix: switch to remote couch api

* fix: use api more

* fix: remove goofy withParams HOC

* no fetcher: setup couch container

* fix: admin container

* no fetcher: config container

* deletedatabasemodal not container

* no fetcher: doc container

* no fetcher: docs container

* no fetcher edit doc container

* new database modal not container

* footer test container

* security doc save

* no fetcher search

* remove fetcher

* fix: comment

* fix: standard

* fix: remove axios
  • Loading branch information
kdoran authored Apr 13, 2020
1 parent f9e8320 commit 30fbfac
Show file tree
Hide file tree
Showing 34 changed files with 1,009 additions and 510 deletions.
45 changes: 45 additions & 0 deletions api/get-fetch.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
/* global btoa */
const isomorphicFetch = require('isomorphic-fetch')

function getFetch ({url, username, password, fetch = isomorphicFetch}) {
if (!url) {
throw new Error(`getFetch URL required`)
}

async function fetcher (endpoint, params) {
const config = {
credentials: 'include',
headers: {
'Accept': 'application/json',
'Content-Type': 'application/json'
},
...params
}
if (username && password) {
config.headers['Authorization'] = `Basic ${btoa(`${username}:${password}`)}`
delete config.credentials
}

const urlWithSlash = url.endsWith('/')
? url
: `${url}/`

const response = await fetch(`${urlWithSlash}${endpoint}`, config)
let body
try {
body = await response.json()
} catch (e) {
console.warn('error caught in fetch parsing body')
}
if (!response.ok) {
const error = new Error()
Object.assign(error, {status: response.status, statusText: response.statusText}, body)
throw error
}
return body
}

return fetcher
}

module.exports = {getFetch}
3 changes: 3 additions & 0 deletions api/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
const {RemoteCouchApi} = require('./remote-couch-api')

module.exports = {RemoteCouchApi}
25 changes: 25 additions & 0 deletions api/pouchdb.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
// see note in webpack config about this goofy movie.
const PouchDB = pickModule(require('pouchdb-core'))
const idbAdapter = pickModule(require('pouchdb-adapter-idb'))
const memoryAdapter = pickModule(require('pouchdb-adapter-memory'))
const httpAdapter = pickModule(require('pouchdb-adapter-http'))
const replication = pickModule(require('pouchdb-replication'))
const find = pickModule(require('pouchdb-find'))
const mapReduce = pickModule(require('pouchdb-mapreduce'))

PouchDB
.plugin(idbAdapter)
.plugin(httpAdapter)
.plugin(replication)
.plugin(mapReduce)
.plugin(memoryAdapter)
.plugin(find)

// pouch exports modules in a way that you cannot simply "require" these in
// node as well as in webpack, which is why we need this workaround:
// https://github.com/pouchdb-community/pouchdb-authentication/issues/164#issuecomment-357697828
function pickModule (mod) {
return 'default' in mod ? mod.default : mod
}

module.exports = {PouchDB}
115 changes: 115 additions & 0 deletions api/remote-couch-api.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,115 @@
const {getFetch} = require('./get-fetch')
const {PouchDB} = require('./pouchdb')

class RemoteCouchApi {
constructor (url) {
url = url.endsWith('/') ? url : `${url}/`

this.url = url
this.fetcher = getFetch({url})
// this will probably change to support node
// will have to deal with setDatabase & username/passwords
this.PouchDBConstructor = PouchDB.defaults({prefix: url})
this.GenericPouchDB = PouchDB
this.databases = {}
}

async logout () {
await this.fetcher('_session', {method: 'DELETE'})
this.user = null
}

async getCurrentUser () {
const session = await this.getCurrentSession()
if (!session) return null

return this.getUserFromSession(session)
}

async getCurrentSession () {
const {userCtx} = await this.fetcher('_session')
// this is couch telling us there's no session
if (!userCtx.name) return null
return userCtx
}

async getUserFromSession (session) {
// couchdb's way of saying admin user, usually does not have a user doc
if (session.roles && session.roles.includes('_admin')) {
delete session.ok
this.user = session
return session
}

const user = await this.fetcher(`_users/org.couchdb.user:${session.name}`)
this.user = user
return user
}

async login (username = '', password = '') {
const session = await this.fetcher(
'_session', {method: 'POST', body: JSON.stringify({username, password})}
)
return this.getUserFromSession(session)
}

getConfigUrl () {
const isLocal = this.url.includes('://localhost:') || this.url.includes('://127.0.0.1:')
return isLocal
? `_node/couchdb@localhost/_config`
: `_node/nonode@nohost/_config`
}

async getConfig () {
return this.fetcher(`${this.getConfigUrl()}`)
}

async getAdminConfig () {
return this.fetcher(`${this.getConfigUrl()}/admins`)
}

async updateAdmin (username, password) {
const url = `${this.getConfigUrl()}/admins/${username}`
return this.fetcher(url, {method: 'PUT', body: `"${password}"`})
}

getPouchInstance (databaseName) {
if (!this.databases[databaseName]) {
this.databases[databaseName] = new this.PouchDBConstructor(databaseName)
}

return this.databases[databaseName]
}

async listDatabases () {
return this.fetcher('_all_dbs')
}

async listInfos (keys) {
try {
const response = await this.fetcher('_dbs_info', {method: 'POST', body: JSON.stringify({keys})})
return response
} catch (error) {
if (error.status !== 404) throw error

const promises = keys.map(dbName => this.getDatabase(dbName))
const response = await Promise.all(promises)
// make same shape as _dbs_info
return response.map((info, index) => ({key: keys[index], info}))
}
}

async createDatabase (databaseName) {
return this.fetcher(databaseName, {method: 'PUT'})
}

async getDatabase (databaseName) {
return this.fetcher(databaseName)
}

async destroyDatabase (databaseName) {
return this.fetcher(databaseName, {method: 'DELETE'})
}
}

module.exports = {RemoteCouchApi}
Loading

0 comments on commit 30fbfac

Please sign in to comment.