mirror of
https://github.com/ascribe/onion.git
synced 2024-12-22 17:33:14 +01:00
Add first cut on persistent stores
This commit is contained in:
parent
c7ef23ee40
commit
bed067f9bc
@ -3,6 +3,8 @@
|
|||||||
import { altUser } from '../alt';
|
import { altUser } from '../alt';
|
||||||
import UserFetcher from '../fetchers/user_fetcher';
|
import UserFetcher from '../fetchers/user_fetcher';
|
||||||
|
|
||||||
|
import UserStore from '../stores/user_store';
|
||||||
|
|
||||||
|
|
||||||
class UserActions {
|
class UserActions {
|
||||||
constructor() {
|
constructor() {
|
||||||
@ -23,6 +25,19 @@ class UserActions {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*fetchCurrentUser() {
|
||||||
|
if(UserStore.getState().currentUser && !UserStore.getState().currentUser.email) {
|
||||||
|
UserFetcher.fetchOne()
|
||||||
|
.then((res) => {
|
||||||
|
this.actions.updateCurrentUser(res.users[0]);
|
||||||
|
})
|
||||||
|
.catch((err) => {
|
||||||
|
console.logGlobal(err);
|
||||||
|
this.actions.updateCurrentUser({});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}*/
|
||||||
|
|
||||||
logoutCurrentUser() {
|
logoutCurrentUser() {
|
||||||
UserFetcher.logout()
|
UserFetcher.logout()
|
||||||
.then(() => {
|
.then(() => {
|
||||||
|
98
js/models/ascribe_storage.js
Normal file
98
js/models/ascribe_storage.js
Normal file
@ -0,0 +1,98 @@
|
|||||||
|
'use strict';
|
||||||
|
|
||||||
|
import { sanitize } from '../utils/general_utils';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A tiny wrapper around HTML5's `webStorage`,
|
||||||
|
* to enable saving JSON objects directly into `webStorage`
|
||||||
|
*/
|
||||||
|
export default class AscribeStorage {
|
||||||
|
/**
|
||||||
|
* @param {String} `name` A unique storage name
|
||||||
|
*/
|
||||||
|
constructor(type, name) {
|
||||||
|
if(type === 'localStorage' || type === 'sessionStorage') {
|
||||||
|
this.storage = window[type];
|
||||||
|
} else {
|
||||||
|
throw new Error('"type" can only be either "localStorage" or "sessionStorage"');
|
||||||
|
}
|
||||||
|
|
||||||
|
this.name = name;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Private method, do not use from the outside.
|
||||||
|
* Constructs a unique identifier for a item in the global `webStorage`,
|
||||||
|
* by appending the `ÀscribeStorage`'s name
|
||||||
|
* @param {string} key A unique identifier
|
||||||
|
* @return {string} A globally unique identifier for a value in `webStorage`
|
||||||
|
*/
|
||||||
|
_constructStorageKey(key) {
|
||||||
|
return `${this.name}-${key}`;
|
||||||
|
}
|
||||||
|
|
||||||
|
_deconstructStorageKey(key) {
|
||||||
|
return key.replace(`${this.name}-`, '');
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Saves a JSON-serializeble object or a string into `webStorage`
|
||||||
|
* @param {string} key Used as a unique identifier
|
||||||
|
* @param {oneOfType([String, object])} value Either JSON-serializeble or a string
|
||||||
|
*/
|
||||||
|
setItem(key, value) {
|
||||||
|
// We're "try-catching" errors in this method ourselves, to be able to
|
||||||
|
// yield more readable error messages
|
||||||
|
|
||||||
|
if(!key || !value) {
|
||||||
|
throw new Error('"key" or "value" cannot be "falsy" values');
|
||||||
|
} else if(typeof value === 'string') {
|
||||||
|
// since `value` is a string, we can directly write
|
||||||
|
// it into `this.storage`
|
||||||
|
this.storage.setItem(this._constructStorageKey(key), value);
|
||||||
|
} else {
|
||||||
|
// if `value` is not a string, we need to JSON-serialize it and then
|
||||||
|
// put it into `this.storage`
|
||||||
|
|
||||||
|
let serializedValue;
|
||||||
|
try {
|
||||||
|
serializedValue = JSON.stringify(value);
|
||||||
|
} catch(err) {
|
||||||
|
throw new Error('You didn\'t pass valid JSON as "value" into setItem.');
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
this.storage.setItem(this._constructStorageKey(key), serializedValue);
|
||||||
|
} catch(err) {
|
||||||
|
throw new Error('Failure saving a "serializedValue" in setItem');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
getItem(key) {
|
||||||
|
let deserializedValue;
|
||||||
|
const serializedValue = this.storage.getItem(this._constructStorageKey(key));
|
||||||
|
|
||||||
|
try {
|
||||||
|
deserializedValue = JSON.parse(serializedValue);
|
||||||
|
} catch(err) {
|
||||||
|
deserializedValue = serializedValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
return deserializedValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
toObject() {
|
||||||
|
let obj = {};
|
||||||
|
const storageCopy = JSON.parse(JSON.stringify(this.storage));
|
||||||
|
const sanitizedStore = sanitize(storageCopy, s => !s.match(`${this.name}-`), true);
|
||||||
|
|
||||||
|
Object
|
||||||
|
.keys(sanitizedStore)
|
||||||
|
.forEach((key) => {
|
||||||
|
obj[this._deconstructStorageKey(key)] = JSON.parse(sanitizedStore[key]);
|
||||||
|
});
|
||||||
|
|
||||||
|
return obj;
|
||||||
|
}
|
||||||
|
}
|
21
js/stores/session_persistent_store.js
Normal file
21
js/stores/session_persistent_store.js
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
'use strict';
|
||||||
|
|
||||||
|
import AscribeStorage from '../models/ascribe_storage';
|
||||||
|
|
||||||
|
|
||||||
|
export default class SessionPersistentStore extends AscribeStorage {
|
||||||
|
constructor(name) {
|
||||||
|
super('sessionStorage', name);
|
||||||
|
}
|
||||||
|
|
||||||
|
setItem(key, value) {
|
||||||
|
this[key] = value;
|
||||||
|
super.setItem(key, value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
SessionPersistentStore.config = {
|
||||||
|
getState() {
|
||||||
|
return new AscribeStorage('sessionStorage', this.displayName).toObject();
|
||||||
|
}
|
||||||
|
};
|
@ -3,15 +3,21 @@
|
|||||||
import { altUser } from '../alt';
|
import { altUser } from '../alt';
|
||||||
import UserActions from '../actions/user_actions';
|
import UserActions from '../actions/user_actions';
|
||||||
|
|
||||||
|
import SessionPersistentStore from './session_persistent_store';
|
||||||
|
|
||||||
class UserStore {
|
// import AscribeStorage from '../models/ascribe_storage';
|
||||||
|
// import { sessionStorageAvailable } from '../utils/feature_detection_utils';
|
||||||
|
|
||||||
|
|
||||||
|
class UserStore extends SessionPersistentStore {
|
||||||
constructor() {
|
constructor() {
|
||||||
|
super('UserStore');
|
||||||
this.currentUser = {};
|
this.currentUser = {};
|
||||||
this.bindActions(UserActions);
|
this.bindActions(UserActions);
|
||||||
}
|
}
|
||||||
|
|
||||||
onUpdateCurrentUser(user) {
|
onUpdateCurrentUser(user) {
|
||||||
this.currentUser = user;
|
this.setItem('currentUser', user);
|
||||||
}
|
}
|
||||||
onDeleteCurrentUser() {
|
onDeleteCurrentUser() {
|
||||||
this.currentUser = {};
|
this.currentUser = {};
|
||||||
|
@ -51,11 +51,8 @@ function storageAvailable(type) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Function detects whether sessionStorage is both supported
|
* Const that detects whether sessionStorage is both supported
|
||||||
* and available.
|
* and available.
|
||||||
* @return {bool} Is sessionStorage available on this browser
|
|
||||||
*/
|
*/
|
||||||
export function sessionStorageAvailable() {
|
export const sessionStorageAvailable = storageAvailable('sessionStorage');
|
||||||
return storageAvailable('sessionStorage');
|
|
||||||
}
|
|
||||||
|
|
||||||
|
@ -6,9 +6,12 @@
|
|||||||
* tagged as false by the passed in filter function
|
* tagged as false by the passed in filter function
|
||||||
*
|
*
|
||||||
* @param {object} obj regular javascript object
|
* @param {object} obj regular javascript object
|
||||||
|
* @param {function} filterFn a filter function for filtering either by key or value
|
||||||
|
* @param {bool} filterByKey a boolean for choosing whether the object should be filtered by
|
||||||
|
* key or value
|
||||||
* @return {object} regular javascript object without null values or empty strings
|
* @return {object} regular javascript object without null values or empty strings
|
||||||
*/
|
*/
|
||||||
export function sanitize(obj, filterFn) {
|
export function sanitize(obj, filterFn, filterByKey) {
|
||||||
if(!filterFn) {
|
if(!filterFn) {
|
||||||
// By matching null with a double equal, we can match undefined and null
|
// By matching null with a double equal, we can match undefined and null
|
||||||
// http://stackoverflow.com/a/15992131
|
// http://stackoverflow.com/a/15992131
|
||||||
@ -18,7 +21,9 @@ export function sanitize(obj, filterFn) {
|
|||||||
Object
|
Object
|
||||||
.keys(obj)
|
.keys(obj)
|
||||||
.map((key) => {
|
.map((key) => {
|
||||||
if(filterFn(obj[key])) {
|
const filterCondition = filterByKey ? filterFn(key) : filterFn(obj[key]);
|
||||||
|
|
||||||
|
if(filterCondition) {
|
||||||
delete obj[key];
|
delete obj[key];
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
Loading…
Reference in New Issue
Block a user