on server, augment default token lifetime and add settings in .env to control it. Add the refresh endpoint
authorymh <ymh.work@gmail.com>
Mon, 19 Jun 2017 21:37:33 +0200
changeset 58 f16a080e0bc4
parent 57 2e4e9f9ebc4f
child 59 1eb52770eefa
on server, augment default token lifetime and add settings in .env to control it. Add the refresh endpoint
client/package.json
client/src/actions/notesActions.js
client/src/actions/sessionsActions.js
client/src/components/Navbar.js
client/src/components/NotesList.js
client/src/components/Session.js
client/src/components/Sessions.js
client/src/reducers/index.js
client/src/reducers/notesReducer.js
client/src/reducers/sessionsReducer.js
client/src/sagas/index.js
client/src/store/configureStore.js
client/src/store/noteRecord.js
client/yarn.lock
src/.env.tmpl
src/irinotes/settings.py
src/irinotes/urls.py
--- a/client/package.json	Mon Jun 19 18:32:27 2017 +0200
+++ b/client/package.json	Mon Jun 19 21:37:33 2017 +0200
@@ -6,6 +6,7 @@
   "dependencies": {
     "bootstrap-sass": "^3.3.7",
     "immutable": "^3.8.1",
+    "localforage": "^1.5.0",
     "lodash": "^4.17.4",
     "moment": "^2.18.1",
     "pouchdb": "^6.2.0",
@@ -19,6 +20,8 @@
     "redux": "^3.6.0",
     "redux-history-transitions": "^2.2.0",
     "redux-immutable": "^4.0.0",
+    "redux-offline": "^2.0.0",
+    "redux-persist-transform-immutable": "^4.3.0",
     "redux-saga": "^0.15.3",
     "slate": "^0.20.1",
     "uuid": "^3.0.1"
--- a/client/src/actions/notesActions.js	Mon Jun 19 18:32:27 2017 +0200
+++ b/client/src/actions/notesActions.js	Mon Jun 19 21:37:33 2017 +0200
@@ -4,7 +4,7 @@
 
 export const addNote = (session, data) => {
   return {
-    type: types.ADD_NOTE_ASYNC,
+    type: types.ADD_NOTE,
     note: {
       _id: uuidV1(),
       session: session._id,
@@ -20,7 +20,7 @@
 
 export const loadNotesBySession = (session) => {
   return {
-    type: types.LOAD_NOTES_BY_SESSION_ASYNC,
+    type: types.LOAD_NOTES_BY_SESSION,
     session: session
   }
 }
--- a/client/src/actions/sessionsActions.js	Mon Jun 19 18:32:27 2017 +0200
+++ b/client/src/actions/sessionsActions.js	Mon Jun 19 21:37:33 2017 +0200
@@ -1,22 +1,40 @@
-import uuidV1 from 'uuid/v1';
+//import uuidV1 from 'uuid/v1';
 
 import * as types from '../constants/actionTypes';
 
-export const createSession = () => {
-  return {
-    type: types.CREATE_SESSION_ASYNC,
-    session: {
-      _id: uuidV1(),
+export const createSession = (sessionId) => {
+
+  //const sessionId = uuidV1();
+  const newSession = {
+      _id: sessionId,
+      ext_id: sessionId,
       date: new Date(),
       title: '',
       description: '',
+  };
+
+  return {
+    type: types.CREATE_SESSION,
+    session: newSession,
+    meta: {
+      offline: {
+        effect: {
+          url: "http://localhost:8000/api/notes/sessions/",
+          body: JSON.stringify(newSession), method: 'POST',
+          headers: {
+            Authorization: "JWT eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ1c2VyX2lkIjoyLCJlbWFpbCI6IiIsInVzZXJuYW1lIjoieW1oIiwiZXhwIjoxNDk3NjU2MjY5fQ.qrwbC4oRqvWNOp8x_8yZRJJowVVoFEpjy1uLhiERTTI"
+          }
+        },
+        commit: { type: types.CREATE_SESSION_ASYNC },
+        rollback: { type: 'NoOp'}
+      }
     }
   };
 }
 
 export const updateSession = (session, values) => {
   return {
-    type: types.UPDATE_SESSION_ASYNC,
+    type: types.UPDATE_SESSION,
     session: session,
     values: values,
   };
@@ -24,6 +42,6 @@
 
 export const loadSessions = () => {
   return {
-    type: types.LOAD_SESSIONS_ASYNC
+    type: types.LOAD_SESSIONS
   }
 }
--- a/client/src/components/Navbar.js	Mon Jun 19 18:32:27 2017 +0200
+++ b/client/src/components/Navbar.js	Mon Jun 19 21:37:33 2017 +0200
@@ -1,4 +1,3 @@
-
 import PropTypes from 'prop-types';
 import React, { Component } from 'react';
 import { connect } from 'react-redux';
--- a/client/src/components/NotesList.js	Mon Jun 19 18:32:27 2017 +0200
+++ b/client/src/components/NotesList.js	Mon Jun 19 21:37:33 2017 +0200
@@ -14,7 +14,6 @@
       <Alert bsStyle="warning">No notes yet. Add notes with the textarea below.</Alert>
     );
   }
-
   return (
     <div>
       {notes.map((note) =>
--- a/client/src/components/Session.js	Mon Jun 19 18:32:27 2017 +0200
+++ b/client/src/components/Session.js	Mon Jun 19 21:37:33 2017 +0200
@@ -13,7 +13,7 @@
 class Session extends Component {
 
   componentDidMount = () => {
-    this.props.notesActions.loadNotesBySession({ _id: this.props.match.params.id });
+    //this.props.notesActions.loadNotesBySession({ _id: this.props.match.params.id });
   }
 
   render() {
@@ -50,14 +50,20 @@
 
   const sessionId = props.match.params.id;
 
-  const sessions = state.get('sessions');
-  const notes = state.get('notes');
+//   const sessions = state.get('sessions');
+//   const notes = state.get('notes');
+  const sessions = state['sessions'];
+  const notes = state['notes'];
+
   const currentSession = sessions.find(session => session._id === sessionId);
+  const currentNotes = notes.filter(note => {
+        return note.session === sessionId;
+    });
 
   return {
     currentSession,
     sessions,
-    notes,
+    notes: currentNotes,
   };
 }
 
--- a/client/src/components/Sessions.js	Mon Jun 19 18:32:27 2017 +0200
+++ b/client/src/components/Sessions.js	Mon Jun 19 21:37:33 2017 +0200
@@ -6,17 +6,14 @@
 import '../App.css';
 import Navbar from './Navbar';
 import * as sessionsActions from '../actions/sessionsActions';
+import uuidV1 from 'uuid/v1';
 
 class Sessions extends Component {
 
   createSession = () => {
-    this.props.sessionsActions.createSession();
-  }
-
-  componentDidUpdate = () => {
-    if (this.props.currentSession) {
-      this.props.history.push('/sessions/' + this.props.currentSession._id)
-    }
+    const sessionId = uuidV1();
+    this.props.sessionsActions.createSession(sessionId);
+    this.props.history.push('/sessions/' + sessionId);
   }
 
   render() {
@@ -46,8 +43,9 @@
 
 function mapStateToProps(state, props) {
   return {
-    currentSession: state.get('currentSession'),
-    sessions: state.get('sessions')
+    // currentSession: state.get('currentSession'),
+    // sessions: state.get('sessions')
+    sessions: state['sessions']
   };
 }
 
--- a/client/src/reducers/index.js	Mon Jun 19 18:32:27 2017 +0200
+++ b/client/src/reducers/index.js	Mon Jun 19 21:37:33 2017 +0200
@@ -1,4 +1,5 @@
-import { combineReducers } from 'redux-immutable';
+//import { combineReducers } from 'redux-immutable';
+import { combineReducers } from 'redux';
 import { routerReducer } from 'react-router-redux';
 
 import notes from './notesReducer';
@@ -6,7 +7,7 @@
 import { isAuthenticated, currentUser, login, token } from './authReducer';
 
 const rootReducer = combineReducers({
-  currentSession,
+//  currentSession,
   sessions,
   notes,
   isAuthenticated,
--- a/client/src/reducers/notesReducer.js	Mon Jun 19 18:32:27 2017 +0200
+++ b/client/src/reducers/notesReducer.js	Mon Jun 19 21:37:33 2017 +0200
@@ -7,7 +7,8 @@
     case types.ADD_NOTE:
       return state.push(new noteRecord(action.note));
     case types.LOAD_NOTES_BY_SESSION:
-      return action.notes;
+      //return action.notes;
+      return state;
     default:
       return state;
   }
--- a/client/src/reducers/sessionsReducer.js	Mon Jun 19 18:32:27 2017 +0200
+++ b/client/src/reducers/sessionsReducer.js	Mon Jun 19 21:37:33 2017 +0200
@@ -1,14 +1,14 @@
 import Immutable from 'immutable';
 import * as types from '../constants/actionTypes';
 
-export const currentSession = (state = null, action) => {
-  switch (action.type) {
-    case types.CREATE_SESSION:
-      return action.session;
-    default:
-      return state;
-  }
-};
+// export const currentSession = (state = null, action) => {
+//   switch (action.type) {
+//     case types.CREATE_SESSION:
+//       return action.session;
+//     default:
+//       return state;
+//   }
+// };
 
 export const sessions = (state = Immutable.List([]), action) => {
   switch (action.type) {
--- a/client/src/sagas/index.js	Mon Jun 19 18:32:27 2017 +0200
+++ b/client/src/sagas/index.js	Mon Jun 19 21:37:33 2017 +0200
@@ -28,10 +28,11 @@
 // ---
 
 export function* createSession(action) {
-  const response = yield sessionsDB.put(action.session);
+  //const response = yield sessionsDB.put(action.session);
   // TODO Error control
-  const session = Object.assign({}, action.session, { rev: response.rev });
-  yield put({ type: types.CREATE_SESSION, session: session })
+  //const session = Object.assign({}, action.session, { rev: response.rev });
+  //yield put({ type: types.CREATE_SESSION, session: session })
+  yield console.log("CREATE SESSION", action);
 }
 
 export function* watchCreateSession() {
--- a/client/src/store/configureStore.js	Mon Jun 19 18:32:27 2017 +0200
+++ b/client/src/store/configureStore.js	Mon Jun 19 21:37:33 2017 +0200
@@ -1,11 +1,16 @@
 import rootReducer from '../reducers';
 import rootSaga from '../sagas';
 import { loadSessions } from '../actions/sessionsActions';
-import { createStore, applyMiddleware, compose } from 'redux';
+import { compose, createStore, applyMiddleware } from 'redux';
 import { routerMiddleware } from 'react-router-redux';
 import handleTransitions from 'redux-history-transitions';
 import createSagaMiddleware from 'redux-saga'
 import Immutable from 'immutable';
+import { offline } from 'redux-offline';
+import offlineDefaultConfig from 'redux-offline/lib/defaults';
+import localForage from 'localforage';
+import immutableTransform from 'redux-persist-transform-immutable'
+import NoteRecord from './noteRecord'
 import APIClient from '../APIClient';
 import config from '../config';
 
@@ -13,7 +18,7 @@
 const currentUser = localStorage.getItem('currentUser');
 
 const defaultState = {
-  currentSession: null,
+//  currentSession: null,
   sessions: Immutable.List([]),
   notes: Immutable.List([]),
   isAuthenticated: token !== null,
@@ -26,7 +31,23 @@
   }
 };
 
-const storeInitialState = Immutable.Map(defaultState);
+const immutableTransformConfig = {
+    records: [NoteRecord],
+    whitelist: ['sessions', 'notes']
+}
+
+const offlineConfig = {
+  ...offlineDefaultConfig,
+  persistOptions: {
+    storage: localForage,
+    transforms: [immutableTransform(immutableTransformConfig)]
+  },
+  detectNetwork: callback => callback(true),
+}
+
+//const storeInitialState = Immutable.Map(defaultState);
+//const storeInitialState = new Map(defaultState);
+const storeInitialState = defaultState;
 
 export default (history, initialState = storeInitialState) => {
 
@@ -34,7 +55,7 @@
   const saga = createSagaMiddleware();
   const transitions = handleTransitions(history);
 
-  const store = createStore(rootReducer, initialState, compose(
+  const store = offline(offlineConfig)(createStore)(rootReducer, initialState, compose(
     applyMiddleware(router, saga),
     transitions
   ));
@@ -45,7 +66,7 @@
 
   saga.run(rootSaga, context);
 
-  store.dispatch(loadSessions());
+  //store.dispatch(loadSessions());
 
   return store;
 };
--- a/client/src/store/noteRecord.js	Mon Jun 19 18:32:27 2017 +0200
+++ b/client/src/store/noteRecord.js	Mon Jun 19 21:37:33 2017 +0200
@@ -12,4 +12,4 @@
   finishedAt: '',
 
   categories: []
-});
+}, 'Note');
--- a/client/yarn.lock	Mon Jun 19 18:32:27 2017 +0200
+++ b/client/yarn.lock	Mon Jun 19 21:37:33 2017 +0200
@@ -54,6 +54,10 @@
   dependencies:
     acorn "^3.0.4"
 
+acorn@^1.0.3:
+  version "1.2.2"
+  resolved "https://registry.yarnpkg.com/acorn/-/acorn-1.2.2.tgz#c8ce27de0acc76d896d2b1fad3df588d9e82f014"
+
 acorn@^3.0.4:
   version "3.3.0"
   resolved "https://registry.yarnpkg.com/acorn/-/acorn-3.3.0.tgz#45e37fb39e8da3f25baee3ff5369e2bb5f22017a"
@@ -288,6 +292,10 @@
   version "0.0.7"
   resolved "https://registry.yarnpkg.com/ast-types-flow/-/ast-types-flow-0.0.7.tgz#f70b735c6bca1a5c9c22d982c3e39e7feba3bdad"
 
+ast-types@0.8.15:
+  version "0.8.15"
+  resolved "https://registry.yarnpkg.com/ast-types/-/ast-types-0.8.15.tgz#8eef0827f04dff0ec8857ba925abe3fea6194e52"
+
 async-each@^1.0.0:
   version "1.0.1"
   resolved "https://registry.yarnpkg.com/async-each/-/async-each-1.0.1.tgz#19d386a1d9edc6e7c1c85d388aedbcc56d33602d"
@@ -983,6 +991,10 @@
   version "0.4.2"
   resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-0.4.2.tgz#cb3f3e3c732dc0f01ee70b403f302e61d7709838"
 
+base62@0.1.1:
+  version "0.1.1"
+  resolved "https://registry.yarnpkg.com/base62/-/base62-0.1.1.tgz#7b4174c2f94449753b11c2651c083da841a7b084"
+
 base64-js@^1.0.2:
   version "1.2.0"
   resolved "https://registry.yarnpkg.com/base64-js/-/base64-js-1.2.0.tgz#a39992d723584811982be5e290bb6a53d86700f1"
@@ -2130,6 +2142,14 @@
     is-date-object "^1.0.1"
     is-symbol "^1.0.1"
 
+es3ify@^0.1.3:
+  version "0.1.4"
+  resolved "https://registry.yarnpkg.com/es3ify/-/es3ify-0.1.4.tgz#ad9fa5df1ae34f3f31e1211b5818b2d51078dfd1"
+  dependencies:
+    esprima-fb "~3001.0001.0000-dev-harmony-fb"
+    jstransform "~3.0.0"
+    through "~2.3.4"
+
 es5-ext@^0.10.14, es5-ext@^0.10.9, es5-ext@~0.10.14:
   version "0.10.20"
   resolved "https://registry.yarnpkg.com/es5-ext/-/es5-ext-0.10.20.tgz#72a9b4fd5832797ba1bb65dceb2e25c04241c492"
@@ -2325,6 +2345,10 @@
     text-table "~0.2.0"
     user-home "^2.0.0"
 
+esmangle-evaluator@^1.0.0:
+  version "1.0.1"
+  resolved "https://registry.yarnpkg.com/esmangle-evaluator/-/esmangle-evaluator-1.0.1.tgz#620d866ef4861b3311f75766d52a8572bb3c6336"
+
 espree@^3.4.0:
   version "3.4.3"
   resolved "https://registry.yarnpkg.com/espree/-/espree-3.4.3.tgz#2910b5ccd49ce893c2ffffaab4fd8b3a31b82374"
@@ -2332,6 +2356,14 @@
     acorn "^5.0.1"
     acorn-jsx "^3.0.0"
 
+esprima-fb@~15001.1001.0-dev-harmony-fb:
+  version "15001.1001.0-dev-harmony-fb"
+  resolved "https://registry.yarnpkg.com/esprima-fb/-/esprima-fb-15001.1001.0-dev-harmony-fb.tgz#43beb57ec26e8cf237d3dd8b33e42533577f2659"
+
+esprima-fb@~3001.0001.0000-dev-harmony-fb, esprima-fb@~3001.1.0-dev-harmony-fb:
+  version "3001.1.0-dev-harmony-fb"
+  resolved "https://registry.yarnpkg.com/esprima-fb/-/esprima-fb-3001.0001.0000-dev-harmony-fb.tgz#b77d37abcd38ea0b77426bb8bc2922ce6b426411"
+
 esprima@^2.6.0, esprima@^2.7.1:
   version "2.7.3"
   resolved "https://registry.yarnpkg.com/esprima/-/esprima-2.7.3.tgz#96e3b70d5779f6ad49cd032673d1c312767ba581"
@@ -2510,6 +2542,15 @@
   version "1.0.2"
   resolved "https://registry.yarnpkg.com/extsprintf/-/extsprintf-1.0.2.tgz#e1080e0658e300b06294990cc70e1502235fd550"
 
+falafel@^1.0.1:
+  version "1.2.0"
+  resolved "https://registry.yarnpkg.com/falafel/-/falafel-1.2.0.tgz#c18d24ef5091174a497f318cd24b026a25cddab4"
+  dependencies:
+    acorn "^1.0.3"
+    foreach "^2.0.5"
+    isarray "0.0.1"
+    object-keys "^1.0.6"
+
 fast-future@~1.0.0:
   version "1.0.2"
   resolved "https://registry.yarnpkg.com/fast-future/-/fast-future-1.0.2.tgz#8435a9aaa02d79248d17d704e76259301d99280a"
@@ -3236,6 +3277,13 @@
   version "1.3.4"
   resolved "https://registry.yarnpkg.com/ini/-/ini-1.3.4.tgz#0537cb79daf59b59a1a517dff706c86ec039162e"
 
+inline-process-browser@^1.0.0:
+  version "1.0.0"
+  resolved "https://registry.yarnpkg.com/inline-process-browser/-/inline-process-browser-1.0.0.tgz#46a61b153dd3c9b1624b1a00626edb4f7f414f22"
+  dependencies:
+    falafel "^1.0.1"
+    through2 "^0.6.5"
+
 inquirer@3.0.6:
   version "3.0.6"
   resolved "https://registry.yarnpkg.com/inquirer/-/inquirer-3.0.6.tgz#e04aaa9d05b7a3cb9b0f407d04375f0447190347"
@@ -3907,7 +3955,7 @@
   dependencies:
     jsonify "~0.0.0"
 
-json-stringify-safe@~5.0.0, json-stringify-safe@~5.0.1:
+json-stringify-safe@^5.0.1, json-stringify-safe@~5.0.0, json-stringify-safe@~5.0.1:
   version "5.0.1"
   resolved "https://registry.yarnpkg.com/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz#1296a2d58fd45f19a0f6ce01d65701e2c735b6eb"
 
@@ -3957,6 +4005,14 @@
     json-schema "0.2.3"
     verror "1.3.6"
 
+jstransform@~3.0.0:
+  version "3.0.0"
+  resolved "https://registry.yarnpkg.com/jstransform/-/jstransform-3.0.0.tgz#a2591ab6cee8d97bf3be830dbfa2313b87cd640b"
+  dependencies:
+    base62 "0.1.1"
+    esprima-fb "~3001.1.0-dev-harmony-fb"
+    source-map "0.1.31"
+
 jsx-ast-utils@^1.3.4, jsx-ast-utils@^1.4.0:
   version "1.4.1"
   resolved "https://registry.yarnpkg.com/jsx-ast-utils/-/jsx-ast-utils-1.4.1.tgz#3867213e8dd79bf1e8f2300c0cfc1efb182c0df1"
@@ -4059,6 +4115,15 @@
     prelude-ls "~1.1.2"
     type-check "~0.3.2"
 
+lie@3.0.2:
+  version "3.0.2"
+  resolved "https://registry.yarnpkg.com/lie/-/lie-3.0.2.tgz#ffda21d7bba26f377cad865d3649b2fc8ce39fea"
+  dependencies:
+    es3ify "^0.1.3"
+    immediate "~3.0.5"
+    inline-process-browser "^1.0.0"
+    unreachable-branch-transform "^0.3.0"
+
 lie@3.1.1:
   version "3.1.1"
   resolved "https://registry.yarnpkg.com/lie/-/lie-3.1.1.tgz#9a436b2cc7746ca59de7a41fa469b3efb76bd87e"
@@ -4112,6 +4177,12 @@
     emojis-list "^2.0.0"
     json5 "^0.5.0"
 
+localforage@^1.5.0:
+  version "1.5.0"
+  resolved "https://registry.yarnpkg.com/localforage/-/localforage-1.5.0.tgz#6b994e19b56611fa85df3992df397ac4ab66e815"
+  dependencies:
+    lie "3.0.2"
+
 locate-path@^2.0.0:
   version "2.0.0"
   resolved "https://registry.yarnpkg.com/locate-path/-/locate-path-2.0.0.tgz#2b568b265eec944c6d9c0de9c3dbbbca0354cd8e"
@@ -4119,7 +4190,7 @@
     p-locate "^2.0.0"
     path-exists "^3.0.0"
 
-lodash-es@^4.2.0, lodash-es@^4.2.1:
+lodash-es@^4.17.4, lodash-es@^4.2.0, lodash-es@^4.2.1:
   version "4.17.4"
   resolved "https://registry.yarnpkg.com/lodash-es/-/lodash-es-4.17.4.tgz#dcc1d7552e150a0640073ba9cb31d70f032950e7"
 
@@ -4712,7 +4783,7 @@
   version "1.0.1"
   resolved "https://registry.yarnpkg.com/object-is/-/object-is-1.0.1.tgz#0aa60ec9989a0b3ed795cf4d06f62cf1ad6539b6"
 
-object-keys@^1.0.10, object-keys@^1.0.8:
+object-keys@^1.0.10, object-keys@^1.0.6, object-keys@^1.0.8:
   version "1.0.11"
   resolved "https://registry.yarnpkg.com/object-keys/-/object-keys-1.0.11.tgz#c54601778ad560f1142ce0e01bcca8b56d13426d"
 
@@ -5465,7 +5536,7 @@
     ansi-regex "^2.1.1"
     ansi-styles "^3.0.0"
 
-private@^0.1.6:
+private@^0.1.6, private@~0.1.5:
   version "0.1.7"
   resolved "https://registry.yarnpkg.com/private/-/private-0.1.7.tgz#68ce5e8a1ef0a23bb570cc28537b5332aba63ef1"
 
@@ -5867,6 +5938,15 @@
     is-fullwidth-code-point "^1.0.0"
     mute-stream "0.0.5"
 
+recast@^0.10.1:
+  version "0.10.43"
+  resolved "https://registry.yarnpkg.com/recast/-/recast-0.10.43.tgz#b95d50f6d60761a5f6252e15d80678168491ce7f"
+  dependencies:
+    ast-types "0.8.15"
+    esprima-fb "~15001.1001.0-dev-harmony-fb"
+    private "~0.1.5"
+    source-map "~0.5.0"
+
 rechoir@^0.6.2:
   version "0.6.2"
   resolved "https://registry.yarnpkg.com/rechoir/-/rechoir-0.6.2.tgz#85204b54dba82d5742e28c96756ef43af50e3384"
@@ -5908,6 +5988,27 @@
   version "4.0.0"
   resolved "https://registry.yarnpkg.com/redux-immutable/-/redux-immutable-4.0.0.tgz#3a1a32df66366462b63691f0e1dc35e472bbc9f3"
 
+redux-offline@^2.0.0:
+  version "2.0.0"
+  resolved "https://registry.yarnpkg.com/redux-offline/-/redux-offline-2.0.0.tgz#5896e95477417c8173e083f4f2d977466ec91808"
+  dependencies:
+    redux-persist "^4.5.0"
+
+redux-persist-transform-immutable@^4.3.0:
+  version "4.3.0"
+  resolved "https://registry.yarnpkg.com/redux-persist-transform-immutable/-/redux-persist-transform-immutable-4.3.0.tgz#24720c99f0707dd99e920b95f851ae3d1baa6ed8"
+  dependencies:
+    transit-immutable-js "^0.7.0"
+    transit-js "^0.8.846"
+
+redux-persist@^4.5.0:
+  version "4.8.0"
+  resolved "https://registry.yarnpkg.com/redux-persist/-/redux-persist-4.8.0.tgz#17fd998949bdeef9275e4cf60ad5bbe1c73675fc"
+  dependencies:
+    json-stringify-safe "^5.0.1"
+    lodash "^4.17.4"
+    lodash-es "^4.17.4"
+
 redux-saga@^0.15.3:
   version "0.15.3"
   resolved "https://registry.yarnpkg.com/redux-saga/-/redux-saga-0.15.3.tgz#be2b86b4ad46bf0d84fcfcb0ca96cfc33db91acb"
@@ -6433,7 +6534,13 @@
   dependencies:
     source-map "^0.5.6"
 
-source-map@0.5.6, source-map@0.5.x, source-map@^0.5.0, source-map@^0.5.3, source-map@^0.5.6, source-map@~0.5.1, source-map@~0.5.3:
+source-map@0.1.31:
+  version "0.1.31"
+  resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.1.31.tgz#9f704d0d69d9e138a81badf6ebb4fde33d151c61"
+  dependencies:
+    amdefine ">=0.0.4"
+
+source-map@0.5.6, source-map@0.5.x, source-map@^0.5.0, source-map@^0.5.3, source-map@^0.5.6, source-map@~0.5.0, source-map@~0.5.1, source-map@~0.5.3:
   version "0.5.6"
   resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.5.6.tgz#75ce38f52bf0733c5a7f0c118d81334a2bb5f412"
 
@@ -6763,14 +6870,14 @@
     readable-stream "^2.1.5"
     xtend "~4.0.1"
 
-through2@~0.6.3:
+through2@^0.6.2, through2@^0.6.5, through2@~0.6.3:
   version "0.6.5"
   resolved "https://registry.yarnpkg.com/through2/-/through2-0.6.5.tgz#41ab9c67b29d57209071410e1d7a7a968cd3ad48"
   dependencies:
     readable-stream ">=1.0.33-1 <1.1.0-0"
     xtend ">=4.0.0 <4.1.0-0"
 
-through@2, through@^2.3.6, through@~2.3, through@~2.3.1:
+through@2, through@^2.3.6, through@~2.3, through@~2.3.1, through@~2.3.4:
   version "2.3.8"
   resolved "https://registry.yarnpkg.com/through/-/through-2.3.8.tgz#0dd4c9ffaabc357960b1b724115d7e0e86a2e1f5"
 
@@ -6823,6 +6930,14 @@
   version "0.0.3"
   resolved "https://registry.yarnpkg.com/tr46/-/tr46-0.0.3.tgz#8184fd347dac9cdc185992f3a6622e14b9d9ab6a"
 
+transit-immutable-js@^0.7.0:
+  version "0.7.0"
+  resolved "https://registry.yarnpkg.com/transit-immutable-js/-/transit-immutable-js-0.7.0.tgz#993e25089b6311ff402140f556276d6d253005d9"
+
+transit-js@^0.8.846:
+  version "0.8.846"
+  resolved "https://registry.yarnpkg.com/transit-js/-/transit-js-0.8.846.tgz#76e06e8f0e6be27675e3442112f5c9bb75343464"
+
 trim-newlines@^1.0.0:
   version "1.0.0"
   resolved "https://registry.yarnpkg.com/trim-newlines/-/trim-newlines-1.0.0.tgz#5887966bb582a4503a41eb524f7d35011815a613"
@@ -6930,6 +7045,14 @@
   version "1.0.0"
   resolved "https://registry.yarnpkg.com/unpipe/-/unpipe-1.0.0.tgz#b2bf4ee8514aae6165b4817829d21b2ef49904ec"
 
+unreachable-branch-transform@^0.3.0:
+  version "0.3.0"
+  resolved "https://registry.yarnpkg.com/unreachable-branch-transform/-/unreachable-branch-transform-0.3.0.tgz#d99cc4c6e746d264928845b611db54b0f3474caa"
+  dependencies:
+    esmangle-evaluator "^1.0.0"
+    recast "^0.10.1"
+    through2 "^0.6.2"
+
 unzip-response@^1.0.0, unzip-response@^1.0.2:
   version "1.0.2"
   resolved "https://registry.yarnpkg.com/unzip-response/-/unzip-response-1.0.2.tgz#b984f0877fc0a89c2c773cc1ef7b5b232b5b06fe"
--- a/src/.env.tmpl	Mon Jun 19 18:32:27 2017 +0200
+++ b/src/.env.tmpl	Mon Jun 19 21:37:33 2017 +0200
@@ -1,37 +1,41 @@
 # Base url for the application. default=''
-BASE_URL=
+# BASE_URL=
 
 # base url for static resources (ends with "/")
 # default : /static/
-STATIC_URL=/static/
+# STATIC_URL=/static/
 
 # The absolute path to the directory where collectstatic will collect static files for deployment. (https://docs.djangoproject.com/en/1.11/ref/settings/#std:setting-STATIC_ROOT)
 # default: <path to irinotes repository clone>/run/web/static
-STATIC_ROOT=
+# STATIC_ROOT=
 
 # Absolute filesystem path to the directory that will hold user-uploaded files (https://docs.djangoproject.com/en/1.11/ref/settings/#media-root)
 # default: <path to irinotes repository clone>/run/web/media
-MEDIA_ROOT=
+# MEDIA_ROOT=
 
 # Secret key for the application. cf. https://docs.djangoproject.com/en/1.11/ref/settings/#secret-key
-SECRET_KEY=ARANDOMSECRETKEY
+# SECRET_KEY=ARANDOMSECRETKEY
 
 # Debug the application. Default True
-DEBUG=<true|False>
+# DEBUG=<true|False>
 
 # Comma separated values of authorized host. cf. https://docs.djangoproject.com/en/1.11/ref/settings/#allowed-hosts
 # default: empty
-ALLOWED_HOSTS=127.0.0.1,localhost
+# ALLOWED_HOSTS=127.0.0.1,localhost
 
 # 12factor inspired DATABASE_URL environment variable cf.https://github.com/kennethreitz/dj-database-url
 # examples: postgres://<user>:<password>@<host>:<port>/<db_name>
 # examples: sqlite:////full/path/to/your/database/file.sqlite
 # default: sqlite:///<path to irinotes repository clone>/run/db/db.sqlite3
-DATABASE_URL=sqlite:///<path to irinotes repository clone>/run/db/db.sqlite3
+# DATABASE_URL=sqlite:///<path to irinotes repository clone>/run/db/db.sqlite3
 
 # path for the log file
 # default: <path to irinotes repository clone>/run/log/log.txt
-LOG_FILE=
+# LOG_FILE=
 
 # log level one of CRITICAL, ERROR, WARNING, INFO, DEBUG, NOTSET. Default: ERROR
-LOG_LEVEL=DEBUG
+# LOG_LEVEL=DEBUG
+
+# expiration delta for JWT tokens (in seconds)
+# default: 3600
+# JWT_EXPIRATION_DELTA = 3600
--- a/src/irinotes/settings.py	Mon Jun 19 18:32:27 2017 +0200
+++ b/src/irinotes/settings.py	Mon Jun 19 21:37:33 2017 +0200
@@ -10,6 +10,7 @@
 https://docs.djangoproject.com/en/1.11/ref/settings/
 """
 
+import datetime
 import logging
 
 from decouple import Csv, config
@@ -230,8 +231,14 @@
 REST_USE_JWT = True
 OLD_PASSWORD_FIELD_ENABLED = True
 
+#JWT settings
+JWT_AUTH = {
+    'JWT_ALLOW_REFRESH' : True,
+    'JWT_EXPIRATION_DELTA' : datetime.timedelta(
+        seconds=config('JWT_EXPIRATION_DELTA', 3600, cast=int)
+    )
+}
+
 # CORS Headers
 CORS_ORIGIN_ALLOW_ALL = True
 CORS_URLS_REGEX = r'^/api/.*$'
-
-
--- a/src/irinotes/urls.py	Mon Jun 19 18:32:27 2017 +0200
+++ b/src/irinotes/urls.py	Mon Jun 19 21:37:33 2017 +0200
@@ -16,10 +16,12 @@
 from allauth.account.views import confirm_email as allauthemailconfirmation
 from django.conf.urls import include, url
 from django.contrib import admin
+from rest_framework_jwt.views import refresh_jwt_token
 
 urlpatterns = [
     url(r'^admin/', admin.site.urls),
     url(r'^api/notes/', include('notes.api.urls', namespace='notes')),
+    url(r'^api/auth/refresh/', refresh_jwt_token, name='rest_refresh'),
     url(r'^api/auth/', include('rest_auth.urls', namespace='rest_auth')),
     url(
         '^api/auth/registration/account-confirm-email/(?P<key>[\\s\\d\\w().+-_\',:&]+)/$',