Resolve merge conflicts

This commit is contained in:
mmonkey
2021-09-16 22:58:54 -05:00
753 changed files with 106429 additions and 94299 deletions

159
cps/ub.py
View File

@@ -28,16 +28,18 @@ from flask import session as flask_session
from binascii import hexlify
from flask_login import AnonymousUserMixin, current_user
from flask_login import user_logged_in
from contextlib import contextmanager
try:
from flask_dance.consumer.backend.sqla import OAuthConsumerMixin
oauth_support = True
except ImportError:
except ImportError as e:
# fails on flask-dance >1.3, due to renaming
try:
from flask_dance.consumer.storage.sqla import OAuthConsumerMixin
oauth_support = True
except ImportError:
except ImportError as e:
oauth_support = False
from sqlalchemy import create_engine, exc, exists, event, text
from sqlalchemy import Column, ForeignKey
@@ -61,6 +63,65 @@ app_DB_path = None
Base = declarative_base()
searched_ids = {}
logged_in = dict()
def store_user_session():
if flask_session.get('_user_id', ""):
if logged_in.get(flask_session.get('_user_id', "")):
logged_in[flask_session.get('_user_id', "")].append(flask_session.get('_id', ""))
else:
logged_in[flask_session.get('_user_id', "")] = [flask_session.get('_id', "")]
log.info(flask_session.get('_id', ""))
def delete_user_session(user_id, session_key):
try:
logged_in.get(str(user_id), []).remove(session_key)
except ValueError:
pass
def check_user_session(user_id, session_key):
return session_key in logged_in.get(str(user_id), [])
def signal_store_user_session(object, user):
store_user_session()
def store_user_session():
if flask_session.get('_user_id', ""):
try:
if not check_user_session(flask_session.get('_user_id', ""), flask_session.get('_id', "")):
user_session = User_Sessions(flask_session.get('_user_id', ""), flask_session.get('_id', ""))
session.add(user_session)
session.commit()
log.debug("Login and store session : " + flask_session.get('_id', ""))
else:
log.debug("Found stored session: " + flask_session.get('_id', ""))
except (exc.OperationalError, exc.InvalidRequestError) as e:
session.rollback()
log.exception(e)
else:
log.error("No user id in session")
def delete_user_session(user_id, session_key):
try:
log.debug("Deleted session_key: " + session_key)
session.query(User_Sessions).filter(User_Sessions.user_id==user_id,
User_Sessions.session_key==session_key).delete()
session.commit()
except (exc.OperationalError, exc.InvalidRequestError):
session.rollback()
log.exception(e)
def check_user_session(user_id, session_key):
try:
return bool(session.query(User_Sessions).filter(User_Sessions.user_id==user_id,
User_Sessions.session_key==session_key).one_or_none())
except (exc.OperationalError, exc.InvalidRequestError):
session.rollback()
log.exception(e)
user_logged_in.connect(signal_store_user_session)
def store_ids(result):
ids = list()
@@ -73,7 +134,7 @@ class UserBase:
@property
def is_authenticated(self):
return True
return self.is_active
def _has_role(self, role_flag):
return constants.has_flag(self.role, role_flag)
@@ -163,7 +224,7 @@ class UserBase:
# ToDo: Error message
def __repr__(self):
return '<User %r>' % self.nickname
return '<User %r>' % self.name
# Baseclass for Users in Calibre-Web, settings which are depending on certain users are stored here. It is derived from
@@ -173,7 +234,7 @@ class User(UserBase, Base):
__table_args__ = {'sqlite_autoincrement': True}
id = Column(Integer, primary_key=True)
nickname = Column(String(64), unique=True)
name = Column(String(64), unique=True)
email = Column(String(120), unique=True, default="")
role = Column(SmallInteger, default=constants.ROLE_USER)
password = Column(String)
@@ -183,14 +244,13 @@ class User(UserBase, Base):
locale = Column(String(2), default="en")
sidebar_view = Column(Integer, default=1)
default_language = Column(String(3), default="all")
mature_content = Column(Boolean, default=True)
denied_tags = Column(String, default="")
allowed_tags = Column(String, default="")
denied_column_value = Column(String, default="")
allowed_column_value = Column(String, default="")
remote_auth_token = relationship('RemoteAuthToken', backref='user', lazy='dynamic')
view_settings = Column(JSON, default={})
kobo_only_shelves_sync = Column(Integer, default=0)
if oauth_support:
@@ -219,19 +279,19 @@ class Anonymous(AnonymousUserMixin, UserBase):
def loadSettings(self):
data = session.query(User).filter(User.role.op('&')(constants.ROLE_ANONYMOUS) == constants.ROLE_ANONYMOUS)\
.first() # type: User
self.nickname = data.nickname
self.name = data.name
self.role = data.role
self.id=data.id
self.sidebar_view = data.sidebar_view
self.default_language = data.default_language
self.locale = data.locale
# self.mature_content = data.mature_content
self.kindle_mail = data.kindle_mail
self.denied_tags = data.denied_tags
self.allowed_tags = data.allowed_tags
self.denied_column_value = data.denied_column_value
self.allowed_column_value = data.allowed_column_value
self.view_settings = data.view_settings
self.kobo_only_shelves_sync = data.kobo_only_shelves_sync
def role_admin(self):
@@ -263,6 +323,17 @@ class Anonymous(AnonymousUserMixin, UserBase):
flask_session['view'][page][prop] = value
return None
class User_Sessions(Base):
__tablename__ = 'user_session'
id = Column(Integer, primary_key=True)
user_id = Column(Integer, ForeignKey('user.id'))
session_key = Column(String, default="")
def __init__(self, user_id, session_key):
self.user_id = user_id
self.session_key = session_key
# Baseclass representing Shelfs in calibre-web in app.db
class Shelf(Base):
@@ -273,6 +344,7 @@ class Shelf(Base):
name = Column(String)
is_public = Column(Integer, default=0)
user_id = Column(Integer, ForeignKey('user.id'))
kobo_sync = Column(Boolean, default=False)
books = relationship("BookShelf", backref="ub_shelf", cascade="all, delete-orphan", lazy="dynamic")
created = Column(DateTime, default=datetime.datetime.utcnow)
last_modified = Column(DateTime, default=datetime.datetime.utcnow, onupdate=datetime.datetime.utcnow)
@@ -509,11 +581,12 @@ def migrate_registration_table(engine, session):
# Remove login capability of user Guest
def migrate_guest_password(engine, session):
def migrate_guest_password(engine):
try:
with engine.connect() as conn:
conn.execute(text("UPDATE user SET password='' where nickname = 'Guest' and password !=''"))
session.commit()
trans = conn.begin()
conn.execute(text("UPDATE user SET password='' where name = 'Guest' and password !=''"))
trans.commit()
except exc.OperationalError:
print('Settings database is not writeable. Exiting...')
sys.exit(2)
@@ -528,6 +601,7 @@ def migrate_shelfs(engine, session):
conn.execute("ALTER TABLE shelf ADD column 'created' DATETIME")
conn.execute("ALTER TABLE shelf ADD column 'last_modified' DATETIME")
conn.execute("ALTER TABLE book_shelf_link ADD column 'date_added' DATETIME")
conn.execute("ALTER TABLE shelf ADD column 'kobo_sync' BOOLEAN DEFAULT false")
for shelf in session.query(Shelf).all():
shelf.uuid = str(uuid.uuid4())
shelf.created = datetime.datetime.now()
@@ -535,6 +609,15 @@ def migrate_shelfs(engine, session):
for book_shelf in session.query(BookShelf).all():
book_shelf.date_added = datetime.datetime.now()
session.commit()
try:
session.query(exists().where(Shelf.kobo_sync)).scalar()
except exc.OperationalError:
with engine.connect() as conn:
conn.execute("ALTER TABLE shelf ADD column 'kobo_sync' BOOLEAN DEFAULT false")
session.commit()
try:
session.query(exists().where(BookShelf.order)).scalar()
except exc.OperationalError: # Database is not compatible, some columns are missing
@@ -618,38 +701,51 @@ def migrate_Database(session):
with engine.connect() as conn:
conn.execute("ALTER TABLE user ADD column `view_settings` VARCHAR(10) DEFAULT '{}'")
session.commit()
if session.query(User).filter(User.role.op('&')(constants.ROLE_ANONYMOUS) == constants.ROLE_ANONYMOUS).first() \
is None:
create_anonymous_user(session)
try:
# check if one table with autoincrement is existing (should be user table)
session.query(exists().where(User.kobo_only_shelves_sync)).scalar()
except exc.OperationalError:
with engine.connect() as conn:
conn.execute(text("SELECT COUNT(*) FROM sqlite_sequence WHERE name='user'"))
conn.execute("ALTER TABLE user ADD column `kobo_only_shelves_sync` SMALLINT DEFAULT 0")
session.commit()
try:
# check if name is in User table instead of nickname
session.query(exists().where(User.name)).scalar()
except exc.OperationalError:
# Create new table user_id and copy contents of table user into it
with engine.connect() as conn:
conn.execute(text("CREATE TABLE user_id (id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT,"
"nickname VARCHAR(64),"
"name VARCHAR(64),"
"email VARCHAR(120),"
"role SMALLINT,"
"password VARCHAR,"
"kindle_mail VARCHAR(120),"
"locale VARCHAR(2),"
"sidebar_view INTEGER,"
"default_language VARCHAR(3),"
"view_settings VARCHAR,"
"UNIQUE (nickname),"
"default_language VARCHAR(3),"
"denied_tags VARCHAR,"
"allowed_tags VARCHAR,"
"denied_column_value VARCHAR,"
"allowed_column_value VARCHAR,"
"view_settings JSON,"
"kobo_only_shelves_sync SMALLINT,"
"UNIQUE (name),"
"UNIQUE (email))"))
conn.execute(text("INSERT INTO user_id(id, nickname, email, role, password, kindle_mail,locale,"
"sidebar_view, default_language, view_settings) "
conn.execute(text("INSERT INTO user_id(id, name, email, role, password, kindle_mail,locale,"
"sidebar_view, default_language, denied_tags, allowed_tags, denied_column_value, "
"allowed_column_value, view_settings, kobo_only_shelves_sync)"
"SELECT id, nickname, email, role, password, kindle_mail, locale,"
"sidebar_view, default_language FROM user"))
"sidebar_view, default_language, denied_tags, allowed_tags, denied_column_value, "
"allowed_column_value, view_settings, kobo_only_shelves_sync FROM user"))
# delete old user table and rename new user_id table to user:
conn.execute(text("DROP TABLE user"))
conn.execute(text("ALTER TABLE user_id RENAME TO user"))
session.commit()
migrate_guest_password(engine, session)
if session.query(User).filter(User.role.op('&')(constants.ROLE_ANONYMOUS) == constants.ROLE_ANONYMOUS).first() \
is None:
create_anonymous_user(session)
migrate_guest_password(engine)
def clean_database(session):
@@ -684,7 +780,7 @@ def delete_download(book_id):
# Generate user Guest (translated text), as anonymous user, no rights
def create_anonymous_user(session):
user = User()
user.nickname = "Guest"
user.name = "Guest"
user.email = 'no@email'
user.role = constants.ROLE_ANONYMOUS
user.password = ''
@@ -699,7 +795,7 @@ def create_anonymous_user(session):
# Generate User admin with admin123 password, and access to everything
def create_admin_user(session):
user = User()
user.nickname = "admin"
user.name = "admin"
user.role = constants.ADMIN_USER_ROLES
user.sidebar_view = constants.ADMIN_USER_SIDEBAR
@@ -734,9 +830,12 @@ def init_db(app_db_path):
create_anonymous_user(session)
if cli.user_credentials:
username, password = cli.user_credentials.split(':')
user = session.query(User).filter(func.lower(User.nickname) == username.lower()).first()
username, password = cli.user_credentials.split(':', 1)
user = session.query(User).filter(func.lower(User.name) == username.lower()).first()
if user:
if not password:
print("Empty password is not allowed")
sys.exit(4)
user.password = generate_password_hash(password)
if session_commit() == "":
print("Password for user '{}' changed".format(username))