mirror of
https://github.com/kovidgoyal/calibre.git
synced 2025-07-09 03:04:10 -04:00
Add basic user management to the server
This code is mostly just a stub, will need to be fleshed out later.
This commit is contained in:
parent
08fa7a72c1
commit
424a430d15
@ -6,7 +6,7 @@
|
|||||||
<meta name="robots" content="noindex">
|
<meta name="robots" content="noindex">
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||||
<link rel="icon" type="image/png" href="favicon.png">
|
<link rel="icon" type="image/png" href="favicon.png">
|
||||||
<script>window.calibre_entry_point = 'ENTRY_POINT'; window.calibre_username = USERNAME;</script>
|
<script>window.calibre_entry_point = 'ENTRY_POINT';</script>
|
||||||
<script type="text/javascript" src="static/main.js"></script>
|
<script type="text/javascript" src="static/main.js"></script>
|
||||||
<link rel="stylesheet" href="static/reset.css"></link>
|
<link rel="stylesheet" href="static/reset.css"></link>
|
||||||
<link rel="stylesheet" href="static/font-awesome/fa.css"></link>
|
<link rel="stylesheet" href="static/font-awesome/fa.css"></link>
|
||||||
|
@ -593,7 +593,19 @@ def interface_data(ctx, rd):
|
|||||||
'''
|
'''
|
||||||
ans = {'username':rd.username}
|
ans = {'username':rd.username}
|
||||||
ans['library_map'], ans['default_library'] = ctx.library_map
|
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['library_id'], db, sorts, orders = get_basic_query_data(ctx, rd.query)
|
||||||
|
ans['user_session_data'] = ud
|
||||||
try:
|
try:
|
||||||
num = int(rd.query.get('num', 50))
|
num = int(rd.query.get('num', 50))
|
||||||
except Exception:
|
except Exception:
|
||||||
|
@ -4,7 +4,7 @@
|
|||||||
|
|
||||||
from __future__ import (unicode_literals, division, absolute_import,
|
from __future__ import (unicode_literals, division, absolute_import,
|
||||||
print_function)
|
print_function)
|
||||||
import re, json
|
import re
|
||||||
from functools import partial
|
from functools import partial
|
||||||
from threading import Lock
|
from threading import Lock
|
||||||
|
|
||||||
@ -44,5 +44,4 @@ def get_html(name, auto_reload_port, **replacements):
|
|||||||
def index(ctx, rd):
|
def index(ctx, rd):
|
||||||
return rd.generate_static_output('/', partial(
|
return rd.generate_static_output('/', partial(
|
||||||
get_html, 'content-server/index.html', getattr(rd.opts, 'auto_reload_port', 0),
|
get_html, 'content-server/index.html', getattr(rd.opts, 'auto_reload_port', 0),
|
||||||
USERNAME=json.dumps(rd.username), ENTRY_POINT='book list',
|
ENTRY_POINT='book list', LOADING_MSG=prepare_string_for_xml(_('Loading library, please wait'))))
|
||||||
LOADING_MSG=prepare_string_for_xml(_('Loading library, please wait'))))
|
|
||||||
|
@ -15,6 +15,7 @@ from threading import Lock
|
|||||||
from calibre.db.cache import Cache
|
from calibre.db.cache import Cache
|
||||||
from calibre.db.legacy import create_backend, LibraryDatabase
|
from calibre.db.legacy import create_backend, LibraryDatabase
|
||||||
from calibre.srv.routes import Router
|
from calibre.srv.routes import Router
|
||||||
|
from calibre.srv.users import UserManager
|
||||||
from calibre.utils.date import utcnow
|
from calibre.utils.date import utcnow
|
||||||
|
|
||||||
def init_library(library_path):
|
def init_library(library_path):
|
||||||
@ -85,6 +86,7 @@ class Context(object):
|
|||||||
self.library_broker = LibraryBroker(libraries)
|
self.library_broker = LibraryBroker(libraries)
|
||||||
self.testing = testing
|
self.testing = testing
|
||||||
self.lock = Lock()
|
self.lock = Lock()
|
||||||
|
self.user_manager = UserManager()
|
||||||
|
|
||||||
def init_session(self, endpoint, data):
|
def init_session(self, endpoint, data):
|
||||||
pass
|
pass
|
||||||
|
66
src/calibre/srv/users.py
Normal file
66
src/calibre/srv/users.py
Normal file
@ -0,0 +1,66 @@
|
|||||||
|
#!/usr/bin/env python2
|
||||||
|
# vim:fileencoding=utf-8
|
||||||
|
# License: GPLv3 Copyright: 2015, Kovid Goyal <kovid at kovidgoyal.net>
|
||||||
|
|
||||||
|
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))
|
@ -4,7 +4,7 @@
|
|||||||
from ajax import ajax
|
from ajax import ajax
|
||||||
from elementmaker import E
|
from elementmaker import E
|
||||||
from gettext import gettext as _
|
from gettext import gettext as _
|
||||||
from session import UserSessionData
|
from session import UserSessionData, SessionData
|
||||||
from book_list.boss import Boss
|
from book_list.boss import Boss
|
||||||
from book_list.globals import set_boss, set_session_data
|
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)
|
p.parentNode.removeChild(p)
|
||||||
if end_type == 'load':
|
if end_type == 'load':
|
||||||
interface_data = JSON.parse(xhr.responseText)
|
interface_data = JSON.parse(xhr.responseText)
|
||||||
|
set_session_data(UserSessionData(interface_data['username']))
|
||||||
# TODO: Copy any user specific session data from the server to
|
# TODO: Copy any user specific session data from the server to
|
||||||
# the local session data object, overriding local data
|
# the local session data object, overriding local data
|
||||||
boss = Boss(interface_data)
|
boss = Boss(interface_data)
|
||||||
@ -28,11 +29,8 @@ def on_library_load_progress(loaded, total):
|
|||||||
p.value = loaded
|
p.value = loaded
|
||||||
|
|
||||||
def load_book_list():
|
def load_book_list():
|
||||||
sd = set_session_data(UserSessionData(window.calibre_username))
|
temp = SessionData() # So that settings for anonymous users are preserved
|
||||||
query = {}
|
query = {'library_id':temp.get('library_id'), 'sort':temp.get('sort')}
|
||||||
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')}
|
|
||||||
ajax('ajax/interface-data', on_library_loaded, on_library_load_progress, query=query).send()
|
ajax('ajax/interface-data', on_library_loaded, on_library_load_progress, query=query).send()
|
||||||
|
|
||||||
def on_load():
|
def on_load():
|
||||||
|
Loading…
x
Reference in New Issue
Block a user