ducky/web
ducky/web/src/models/me.js
Update our profile model to use our refresh helper. Update our profile model to send the correct authorization header when making requests, and if the request fails because the OAuth token has expired, try to use the refresh token to obtain a new access token, then retry the request.
| paddy@0 | 1 import Model from 'ampersand-model' |
| paddy@0 | 2 import Sync from 'ampersand-sync' |
| paddy@0 | 3 import qs from 'qs' |
| paddy@0 | 4 import config from '../config' |
| paddy@0 | 5 import isObject from 'lodash.isobject' |
| paddy@2 | 6 import jwtDecode from 'jwt-decode' |
| paddy@0 | 7 |
| paddy@0 | 8 export default Model.extend({ |
| paddy@0 | 9 url: config.urlBase + '/token', |
| paddy@0 | 10 ajaxConfig: { |
| paddy@0 | 11 headers: { |
| paddy@0 | 12 'Content-Type': 'application/x-www-form-urlencoded', |
| paddy@0 | 13 'Authorization': 'Basic ' + btoa(config.clientID + ':' + config.clientSecret), |
| paddy@0 | 14 } |
| paddy@0 | 15 }, |
| paddy@0 | 16 |
| paddy@0 | 17 props: { |
| paddy@0 | 18 access_token: 'string', |
| paddy@0 | 19 refresh_token: 'string', |
| paddy@0 | 20 expires_in: 'int', |
| paddy@0 | 21 token_created: 'date', |
| paddy@0 | 22 name: 'string', |
| paddy@2 | 23 profileID: 'string', |
| paddy@0 | 24 }, |
| paddy@0 | 25 |
| paddy@0 | 26 derived: { |
| paddy@0 | 27 loggedIn () { |
| paddy@0 | 28 return !!this.access_token |
| paddy@0 | 29 }, |
| paddy@0 | 30 needsRefresh () { |
| paddy@0 | 31 let d = this.token_created |
| paddy@0 | 32 return !!this.refresh_token && (new Date() >= d.setSeconds(d.getSeconds() + this.expires_in - 900)) |
| paddy@0 | 33 }, |
| paddy@2 | 34 profile: { |
| paddy@2 | 35 deps: ['profileID'], |
| paddy@2 | 36 fn () { |
| paddy@2 | 37 return app.profiles.get(this.profileID) |
| paddy@2 | 38 }, |
| paddy@2 | 39 }, |
| paddy@0 | 40 }, |
| paddy@0 | 41 |
| paddy@0 | 42 login (email, password) { |
| paddy@0 | 43 let options = { |
| paddy@0 | 44 data: qs.stringify({ |
| paddy@0 | 45 'username': email, |
| paddy@0 | 46 'password': password, |
| paddy@0 | 47 'grant_type': 'password', |
| paddy@0 | 48 }), |
| paddy@0 | 49 } |
| paddy@0 | 50 let moc = this |
| paddy@0 | 51 options.success = function(resp) { |
| paddy@0 | 52 if (!resp.access_token) { |
| paddy@0 | 53 return false |
| paddy@0 | 54 } |
| paddy@0 | 55 let serverAttrs = moc.parse(resp, options) |
| paddy@0 | 56 serverAttrs.token_created = new Date() |
| paddy@0 | 57 console.log(serverAttrs) |
| paddy@0 | 58 if (options.wait) serverAttrs = assign({}, serverAttrs) |
| paddy@0 | 59 if (isObject(serverAttrs) && !moc.set(serverAttrs, options)) { |
| paddy@0 | 60 return false |
| paddy@0 | 61 } |
| paddy@2 | 62 const token = jwtDecode(moc.access_token) |
| paddy@2 | 63 moc.profileID = token.sub |
| paddy@0 | 64 moc.trigger('sync', moc, resp, options) |
| paddy@0 | 65 } |
| paddy@0 | 66 options.error = function(resp) { |
| paddy@0 | 67 moc.trigger('error', moc, resp, options) |
| paddy@0 | 68 } |
| paddy@0 | 69 let sync = Sync('create', moc, options) |
| paddy@0 | 70 }, |
| paddy@0 | 71 |
| paddy@0 | 72 writeToCache () { |
| paddy@0 | 73 // TODO: write this to chrome.storage.local |
| paddy@0 | 74 }, |
| paddy@0 | 75 |
| paddy@0 | 76 logout () { |
| paddy@0 | 77 // TODO: clear all cached data |
| paddy@0 | 78 }, |
| paddy@0 | 79 |
| paddy@0 | 80 }) |