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():