diff --git a/resources/content-server/index.html b/resources/content-server/index.html
index f93c9522db..5460c8cc33 100644
--- a/resources/content-server/index.html
+++ b/resources/content-server/index.html
@@ -6,7 +6,7 @@
-
+
diff --git a/src/calibre/srv/ajax.py b/src/calibre/srv/ajax.py
index 701899206c..ae33941a2f 100644
--- a/src/calibre/srv/ajax.py
+++ b/src/calibre/srv/ajax.py
@@ -593,7 +593,19 @@ def interface_data(ctx, rd):
'''
ans = {'username':rd.username}
ans['library_map'], ans['default_library'] = ctx.library_map
+ ud = {}
+ if rd.username:
+ # Override session data with stored values for the authenticated user,
+ # if any
+ ud = ctx.user_manager.get_session_data(rd.username)
+ lid = ud.get('library_id')
+ if lid and lid in ans['library_map']:
+ rd.query.set('library_id', lid)
+ usort = ud.get('sort')
+ if usort:
+ rd.query.set('sort', usort)
ans['library_id'], db, sorts, orders = get_basic_query_data(ctx, rd.query)
+ ans['user_session_data'] = ud
try:
num = int(rd.query.get('num', 50))
except Exception:
diff --git a/src/calibre/srv/code.py b/src/calibre/srv/code.py
index 3cf0389fa4..391354fe39 100644
--- a/src/calibre/srv/code.py
+++ b/src/calibre/srv/code.py
@@ -4,7 +4,7 @@
from __future__ import (unicode_literals, division, absolute_import,
print_function)
-import re, json
+import re
from functools import partial
from threading import Lock
@@ -44,5 +44,4 @@ def get_html(name, auto_reload_port, **replacements):
def index(ctx, rd):
return rd.generate_static_output('/', partial(
get_html, 'content-server/index.html', getattr(rd.opts, 'auto_reload_port', 0),
- USERNAME=json.dumps(rd.username), ENTRY_POINT='book list',
- LOADING_MSG=prepare_string_for_xml(_('Loading library, please wait'))))
+ ENTRY_POINT='book list', LOADING_MSG=prepare_string_for_xml(_('Loading library, please wait'))))
diff --git a/src/calibre/srv/handler.py b/src/calibre/srv/handler.py
index 38a3187693..6d0f68a01b 100644
--- a/src/calibre/srv/handler.py
+++ b/src/calibre/srv/handler.py
@@ -15,6 +15,7 @@ from threading import Lock
from calibre.db.cache import Cache
from calibre.db.legacy import create_backend, LibraryDatabase
from calibre.srv.routes import Router
+from calibre.srv.users import UserManager
from calibre.utils.date import utcnow
def init_library(library_path):
@@ -85,6 +86,7 @@ class Context(object):
self.library_broker = LibraryBroker(libraries)
self.testing = testing
self.lock = Lock()
+ self.user_manager = UserManager()
def init_session(self, endpoint, data):
pass
diff --git a/src/calibre/srv/users.py b/src/calibre/srv/users.py
new file mode 100644
index 0000000000..7a5020abc7
--- /dev/null
+++ b/src/calibre/srv/users.py
@@ -0,0 +1,66 @@
+#!/usr/bin/env python2
+# vim:fileencoding=utf-8
+# License: GPLv3 Copyright: 2015, Kovid Goyal
+
+from __future__ import (unicode_literals, division, absolute_import,
+ print_function)
+import os, json
+
+import apsw
+
+from calibre.constants import config_dir
+from calibre.utils.config import to_json, from_json
+
+class UserManager(object):
+
+ @property
+ def conn(self):
+ if self._conn is None:
+ self._conn = apsw.Connection(self.path)
+ c = self._conn.cursor()
+ uv = next(c.execute('PRAGMA foreign_keys = ON; PRAGMA user_version'))[0]
+ if uv == 0:
+ c.execute('''
+CREATE TABLE users (
+ id INTEGER PRIMARY KEY,
+ name TEXT NOT NULL,
+ salt TEXT NOT NULL,
+ hashed_pw TEXT NOT NULL,
+ hash_type TEXT NOT NULL,
+ creation_date INTEGER NOT NULL,
+ UNIQUE(name)
+);
+
+CREATE TABLE session_data (
+ id INTEGER PRIMARY KEY,
+ user INTEGER NOT NULL,
+ data TEXT NOT NULL,
+ UNIQUE(user),
+ FOREIGN KEY user REFERENCES users.id
+);
+
+PRAGMA user_version=1;
+''')
+ c.close()
+
+ def __init__(self):
+ self.path = os.path.join(config_dir, 'server-users.sqlite')
+ self._conn = None
+
+ def get_session_data(self, username):
+ for data, in self.conn.cursor().execute(
+ 'SELECT data FROM session_data INNER JOIN users ON (session_data.user = users.id) WHERE users.name=?', (username,)):
+ try:
+ return json.loads(data, object_hook=from_json)
+ except Exception:
+ pass
+ return {}
+
+ def set_session_data(self, username, data):
+ conn = self.conn
+ c = conn.cursor()
+ for user_id, in c.execute('SELECT id FROM users WHERE name=?', (username,)):
+ data = json.dumps(data, ensure_ascii=False, default=to_json)
+ c.execute('UPDATE session_data SET data=? WHERE user=?', (data, user_id))
+ if not conn.changes():
+ c.execute('INSERT INTO session_data (data,user) VALUES (?,?)', (data, user_id))
diff --git a/src/pyj/srv.pyj b/src/pyj/srv.pyj
index 61687d8520..a37d290ede 100644
--- a/src/pyj/srv.pyj
+++ b/src/pyj/srv.pyj
@@ -4,7 +4,7 @@
from ajax import ajax
from elementmaker import E
from gettext import gettext as _
-from session import UserSessionData
+from session import UserSessionData, SessionData
from book_list.boss import Boss
from book_list.globals import set_boss, set_session_data
@@ -13,6 +13,7 @@ def on_library_loaded(end_type, xhr, ev):
p.parentNode.removeChild(p)
if end_type == 'load':
interface_data = JSON.parse(xhr.responseText)
+ set_session_data(UserSessionData(interface_data['username']))
# TODO: Copy any user specific session data from the server to
# the local session data object, overriding local data
boss = Boss(interface_data)
@@ -28,11 +29,8 @@ def on_library_load_progress(loaded, total):
p.value = loaded
def load_book_list():
- sd = set_session_data(UserSessionData(window.calibre_username))
- query = {}
- if not sd.has_user:
- # For authenticated users use the session data cached on the server
- query = {'library_id':sd.get('library_id'), 'sort':sd.get('sort')}
+ temp = SessionData() # So that settings for anonymous users are preserved
+ query = {'library_id':temp.get('library_id'), 'sort':temp.get('sort')}
ajax('ajax/interface-data', on_library_loaded, on_library_load_progress, query=query).send()
def on_load():