const decode = require('jsonwebtoken/decode') const app = require('./app') app.service('api', function($http, $location, $mdToast) { window.api = this this.opts = { headers: {}, withCredentials: true } this.claims = {} this.postProcess = (res) => res.data this.get = (path, opts = {}) => $http.get(path, Object.assign({}, opts, this.opts)).then(this.postProcess) this.post = (path, data, opts = {}) => $http.post(path, data, Object.assign({}, opts, this.opts)).then(this.postProcess) this.put = (path, data, opts = {}) => $http.put(path, data, Object.assign({}, opts, this.opts)).then(this.postProcess) this.patch = (path, data, opts = {}) => $http.patch(path, data, Object.assign({}, opts, this.opts)).then(this.postProcess) this.delete = (path, opts = {}) => $http.delete(path, Object.assign({}, opts, this.opts)).then(this.postProcess) const setUser = (user, token) => { const decoded = decode(token) this.token = token this.user = user this.claims = decoded this.opts.headers.authentication = `Bearer ${token}` localStorage.setItem('token', token) localStorage.setItem('user', JSON.stringify(user)) } const clearUser = () => { this.token = null this.user = null this.claims = {} delete this.opts.headers.authentication localStorage.removeItem('token') localStorage.removeItem('user') } this.login = async data => { const res = await this.post('/api/auth/login', data) setUser(res.user, res.token) } this.logout = async () => { clearUser() } this.renew = async () => { console.info('Renewing session...') const res = await this.post('/api/auth/renew', {}) setUser(res.user, res.token) } this.checkRenew = async () => { if (!this.user) { throw new Error('Not logged in') } try { await this.renew() } catch (e) { clearUser() throw e } } this.restore = () => { const token = localStorage.getItem('token') const userJson = localStorage.getItem('user') if (token && userJson) { try { const user = JSON.parse(userJson) setUser(user, token) } catch (err) { console.warn(`Unable to restore login:`, err) } } } this.restore() const renewTimer = () => { if (this.user) { this.renew().catch(err => { console.warn('Login session could not be renewed:', err) $mdToast.show( $mdToast.simple() .textContent(`You are not logged in: ${err.statusText || err.message}.`) .action('Return to login page') .hideDelay(60000) .position('top middle') .highlightAction(true) .highlightClass('md-warn') ) .then(res => { if (res === 'ok') { clearUser() $location.url('/login') } }) }) } } setInterval(renewTimer, 15000) renewTimer() this.crud = (apiPrefix) => ({ list: () => this.get(apiPrefix), create: data => this.post(apiPrefix, data), read: id => this.get(`${apiPrefix}/${id}`), update: (id, data) => this.patch(`${apiPrefix}/${id}`, data), delete: (id) => this.delete(`${apiPrefix}/${id}`), trash: () => this.get(`${apiPrefix}/trash`), undelete: (id) => this.delete(`${apiPrefix}/trash/${id}`), autocomplete: (searchText) => this.get(apiPrefix, { params: { q: searchText } }), lookup: (ids) => this.get(apiPrefix, { params: { ids: ids.join(',')}}) }) })