Commit 4eee58c2 authored by OzzieIsaacs's avatar OzzieIsaacs

Started migration of config to app database

parent a2a48515
#!/usr/bin/env python
import os import os
import sys import sys
from threading import Thread
from multiprocessing import Queue
import time import time
base_path = os.path.dirname(os.path.abspath(__file__)) base_path = os.path.dirname(os.path.abspath(__file__))
...@@ -12,50 +8,22 @@ base_path = os.path.dirname(os.path.abspath(__file__)) ...@@ -12,50 +8,22 @@ base_path = os.path.dirname(os.path.abspath(__file__))
sys.path.insert(0, os.path.join(base_path, 'vendor')) sys.path.insert(0, os.path.join(base_path, 'vendor'))
from cps import web from cps import web
from cps import config # from cps import config
from tornado.wsgi import WSGIContainer from tornado.wsgi import WSGIContainer
from tornado.httpserver import HTTPServer from tornado.httpserver import HTTPServer
from tornado.ioloop import IOLoop from tornado.ioloop import IOLoop
global title_sort
def start_calibreweb(messagequeue):
web.global_queue = messagequeue
if config.DEVELOPMENT:
web.app.run(host="0.0.0.0", port=config.PORT, debug=True)
else:
http_server = HTTPServer(WSGIContainer(web.app))
http_server.listen(config.PORT)
IOLoop.instance().start()
print "Tornado finished"
http_server.stop()
def stop_calibreweb():
# Close Database connections for user and data
web.db.session.close()
web.db.engine.dispose()
web.ub.session.close()
web.ub.engine.dispose()
test=IOLoop.instance()
test.add_callback(test.stop)
print("Asked Tornado to exit")
if __name__ == '__main__': if __name__ == '__main__':
if config.DEVELOPMENT: '''if config.DEVELOPMENT:
web.app.run(host="0.0.0.0",port=config.PORT, debug=True) web.app.run(host="0.0.0.0", port=web.config.config_port, debug=True)
else:'''
http_server = HTTPServer(WSGIContainer(web.app))
http_server.listen(web.config.config_port)
IOLoop.instance().start()
if web.global_task == 0:
print("Performing restart of Calibre-web")
os.execl(sys.executable,sys.executable, *sys.argv)
else: else:
while True: print("Performing shutdown of Calibre-web")
q = Queue() os._exit(0)
t = Thread(target=start_calibreweb, args=(q,))
t.start()
while True: #watching queue, if there is no call than sleep, otherwise break
if q.empty():
time.sleep(1)
else:
break
stop_calibreweb()
t.join()
#!/usr/bin/env python
# -*- coding: utf-8 -*-
import os
import sys
from configobj import ConfigObj
CONFIG_FILE = os.path.join(os.path.normpath(os.path.dirname(os.path.realpath(__file__))+os.sep+".."+os.sep), "config.ini")
CFG = ConfigObj(CONFIG_FILE)
CFG.encoding = 'UTF-8'
def CheckSection(sec):
""" Check if INI section exists, if not create it """
try:
CFG[sec]
return True
except:
CFG[sec] = {}
return False
def check_setting_str(config, cfg_name, item_name, def_val, log=True):
try:
my_val = config[cfg_name][item_name].decode('UTF-8')
if my_val == u"":
my_val = def_val
config[cfg_name][item_name] = my_val
except:
my_val = def_val
try:
config[cfg_name][item_name] = my_val
except:
config[cfg_name] = {}
config[cfg_name][item_name] = my_val
return my_val
def check_setting_int(config, cfg_name, item_name, def_val):
try:
my_val = int(config[cfg_name][item_name])
except:
my_val = def_val
try:
config[cfg_name][item_name] = my_val
except:
config[cfg_name] = {}
config[cfg_name][item_name] = my_val
return my_val
CheckSection('General')
DB_ROOT = check_setting_str(CFG, 'General', 'DB_ROOT', "")
APP_DB_ROOT = check_setting_str(CFG, 'General', 'APP_DB_ROOT', os.getcwd())
MAIN_DIR = check_setting_str(CFG, 'General', 'MAIN_DIR', os.getcwd())
LOG_DIR = check_setting_str(CFG, 'General', 'LOG_DIR', os.getcwd())
PORT = check_setting_int(CFG, 'General', 'PORT', 8083)
NEWEST_BOOKS = check_setting_str(CFG, 'General', 'NEWEST_BOOKS', 60)
RANDOM_BOOKS = check_setting_int(CFG, 'General', 'RANDOM_BOOKS', 4)
CheckSection('Advanced')
TITLE_REGEX = check_setting_str(CFG, 'Advanced', 'TITLE_REGEX', '^(A|The|An|Der|Die|Das|Den|Ein|Eine|Einen|Dem|Des|Einem|Eines)\s+')
DEVELOPMENT = bool(check_setting_int(CFG, 'Advanced', 'DEVELOPMENT', 0))
PUBLIC_REG = bool(check_setting_int(CFG, 'Advanced', 'PUBLIC_REG', 0))
UPLOADING = bool(check_setting_int(CFG, 'Advanced', 'UPLOADING', 0))
ANON_BROWSE = bool(check_setting_int(CFG, 'Advanced', 'ANON_BROWSE', 0))
SYS_ENCODING = "UTF-8"
if DB_ROOT == "":
print "Calibre database directory (DB_ROOT) is not configured"
sys.exit(1)
configval = {"DB_ROOT": DB_ROOT, "APP_DB_ROOT": APP_DB_ROOT, "MAIN_DIR": MAIN_DIR, "LOG_DIR": LOG_DIR, "PORT": PORT,
"NEWEST_BOOKS": NEWEST_BOOKS, "DEVELOPMENT": DEVELOPMENT, "TITLE_REGEX": TITLE_REGEX,
"PUBLIC_REG": PUBLIC_REG, "UPLOADING": UPLOADING, "ANON_BROWSE": ANON_BROWSE}
def save_config(configval):
new_config = ConfigObj(encoding='UTF-8')
new_config.filename = CONFIG_FILE
new_config['General'] = {}
new_config['General']['DB_ROOT'] = configval["DB_ROOT"]
new_config['General']['APP_DB_ROOT'] = configval["APP_DB_ROOT"]
new_config['General']['MAIN_DIR'] = configval["MAIN_DIR"]
new_config['General']['LOG_DIR'] = configval["LOG_DIR"]
new_config['General']['PORT'] = configval["PORT"]
new_config['General']['NEWEST_BOOKS'] = configval["NEWEST_BOOKS"]
new_config['Advanced'] = {}
new_config['Advanced']['TITLE_REGEX'] = configval["TITLE_REGEX"]
new_config['Advanced']['DEVELOPMENT'] = int(configval["DEVELOPMENT"])
new_config['Advanced']['PUBLIC_REG'] = int(configval["PUBLIC_REG"])
new_config['Advanced']['UPLOADING'] = int(configval["UPLOADING"])
new_config['Advanced']['ANON_BROWSE'] = int(configval["ANON_BROWSE"])
new_config.write()
return "Saved"
save_config(configval)
...@@ -5,13 +5,11 @@ from sqlalchemy import * ...@@ -5,13 +5,11 @@ from sqlalchemy import *
from sqlalchemy.ext.declarative import declarative_base from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy.orm import * from sqlalchemy.orm import *
import os import os
import config # import config
import re import re
import ast import ast
# calibre sort stuff global session
title_pat = re.compile(config.TITLE_REGEX, re.IGNORECASE)
def title_sort(title): def title_sort(title):
match = title_pat.search(title) match = title_pat.search(title)
...@@ -21,59 +19,32 @@ def title_sort(title): ...@@ -21,59 +19,32 @@ def title_sort(title):
return title.strip() return title.strip()
dbpath = os.path.join(config.DB_ROOT, "metadata.db")
engine = create_engine('sqlite:///{0}'.format(dbpath.encode('utf-8')), echo=False)
conn = engine.connect()
conn.connection.create_function('title_sort', 1, title_sort)
Base = declarative_base() Base = declarative_base()
books_authors_link = Table('books_authors_link', Base.metadata, books_authors_link = Table('books_authors_link', Base.metadata,
Column('book', Integer, ForeignKey('books.id'), primary_key=True), Column('book', Integer, ForeignKey('books.id'), primary_key=True),
Column('author', Integer, ForeignKey('authors.id'), primary_key=True) Column('author', Integer, ForeignKey('authors.id'), primary_key=True)
) )
books_tags_link = Table('books_tags_link', Base.metadata, books_tags_link = Table('books_tags_link', Base.metadata,
Column('book', Integer, ForeignKey('books.id'), primary_key=True), Column('book', Integer, ForeignKey('books.id'), primary_key=True),
Column('tag', Integer, ForeignKey('tags.id'), primary_key=True) Column('tag', Integer, ForeignKey('tags.id'), primary_key=True)
) )
books_series_link = Table('books_series_link', Base.metadata, books_series_link = Table('books_series_link', Base.metadata,
Column('book', Integer, ForeignKey('books.id'), primary_key=True), Column('book', Integer, ForeignKey('books.id'), primary_key=True),
Column('series', Integer, ForeignKey('series.id'), primary_key=True) Column('series', Integer, ForeignKey('series.id'), primary_key=True)
) )
books_ratings_link = Table('books_ratings_link', Base.metadata, books_ratings_link = Table('books_ratings_link', Base.metadata,
Column('book', Integer, ForeignKey('books.id'), primary_key=True), Column('book', Integer, ForeignKey('books.id'), primary_key=True),
Column('rating', Integer, ForeignKey('ratings.id'), primary_key=True) Column('rating', Integer, ForeignKey('ratings.id'), primary_key=True)
) )
books_languages_link = Table('books_languages_link', Base.metadata, books_languages_link = Table('books_languages_link', Base.metadata,
Column('book', Integer, ForeignKey('books.id'), primary_key=True), Column('book', Integer, ForeignKey('books.id'), primary_key=True),
Column('lang_code', Integer, ForeignKey('languages.id'), primary_key=True) Column('lang_code', Integer, ForeignKey('languages.id'), primary_key=True)
) )
cc = conn.execute("SELECT id, datatype FROM custom_columns")
cc_ids = []
cc_exceptions = ['datetime', 'int', 'comments', 'float', 'composite', 'series']
books_custom_column_links = {}
cc_classes = {}
for row in cc:
if row.datatype not in cc_exceptions:
books_custom_column_links[row.id] = Table('books_custom_column_' + str(row.id) + '_link', Base.metadata,
Column('book', Integer, ForeignKey('books.id'), primary_key=True),
Column('value', Integer, ForeignKey('custom_column_' + str(row.id) + '.id'), primary_key=True)
)
cc_ids.append([row.id, row.datatype])
if row.datatype == 'bool':
ccdict = {'__tablename__': 'custom_column_' + str(row.id),
'id': Column(Integer, primary_key=True),
'book': Column(Integer, ForeignKey('books.id')),
'value': Column(Boolean)}
else:
ccdict = {'__tablename__': 'custom_column_' + str(row.id),
'id': Column(Integer, primary_key=True),
'value': Column(String)}
cc_classes[row.id] = type('Custom_Column_' + str(row.id), (Base,), ccdict)
class Identifiers(Base): class Identifiers(Base):
...@@ -260,15 +231,6 @@ class Books(Base): ...@@ -260,15 +231,6 @@ class Books(Base):
return u"<Books('{0},{1}{2}{3}{4}{5}{6}{7}{8}')>".format(self.title, self.sort, self.author_sort, return u"<Books('{0},{1}{2}{3}{4}{5}{6}{7}{8}')>".format(self.title, self.sort, self.author_sort,
self.timestamp, self.pubdate, self.series_index, self.timestamp, self.pubdate, self.series_index,
self.last_modified, self.path, self.has_cover) self.last_modified, self.path, self.has_cover)
for id in cc_ids:
if id[1] == 'bool':
setattr(Books, 'custom_column_' + str(id[0]), relationship(cc_classes[id[0]],
primaryjoin=(Books.id == cc_classes[id[0]].book),
backref='books'))
else:
setattr(Books, 'custom_column_' + str(id[0]), relationship(cc_classes[id[0]],
secondary = books_custom_column_links[id[0]],
backref='books'))
class Custom_Columns(Base): class Custom_Columns(Base):
...@@ -288,7 +250,57 @@ class Custom_Columns(Base): ...@@ -288,7 +250,57 @@ class Custom_Columns(Base):
display_dict = ast.literal_eval(self.display) display_dict = ast.literal_eval(self.display)
return display_dict return display_dict
# Base.metadata.create_all(engine) def setup_db(config):
Session = sessionmaker() global session
Session.configure(bind=engine) # calibre sort stuff
session = Session() title_pat = re.compile(config.config_title_regex, re.IGNORECASE)
if config.config_calibre_dir is None:
return
dbpath = os.path.join(config.config_calibre_dir, "metadata.db")
engine = create_engine('sqlite:///{0}'.format(dbpath.encode('utf-8')), echo=False)
conn = engine.connect()
conn.connection.create_function('title_sort', 1, title_sort)
cc = conn.execute("SELECT id, datatype FROM custom_columns")
cc_ids = []
cc_exceptions = ['datetime', 'int', 'comments', 'float', 'composite', 'series']
books_custom_column_links = {}
cc_classes = {}
for row in cc:
if row.datatype not in cc_exceptions:
books_custom_column_links[row.id] = Table('books_custom_column_' + str(row.id) + '_link', Base.metadata,
Column('book', Integer, ForeignKey('books.id'),
primary_key=True),
Column('value', Integer,
ForeignKey('custom_column_' + str(row.id) + '.id'),
primary_key=True)
)
cc_ids.append([row.id, row.datatype])
if row.datatype == 'bool':
ccdict = {'__tablename__': 'custom_column_' + str(row.id),
'id': Column(Integer, primary_key=True),
'book': Column(Integer, ForeignKey('books.id')),
'value': Column(Boolean)}
else:
ccdict = {'__tablename__': 'custom_column_' + str(row.id),
'id': Column(Integer, primary_key=True),
'value': Column(String)}
cc_classes[row.id] = type('Custom_Column_' + str(row.id), (Base,), ccdict)
for id in cc_ids:
if id[1] == 'bool':
setattr(Books, 'custom_column_' + str(id[0]), relationship(cc_classes[id[0]],
primaryjoin=(
Books.id == cc_classes[id[0]].book),
backref='books'))
else:
setattr(Books, 'custom_column_' + str(id[0]), relationship(cc_classes[id[0]],
secondary=books_custom_column_links[id[0]],
backref='books'))
# Base.metadata.create_all(engine)
Session = sessionmaker()
Session.configure(bind=engine)
session = Session()
...@@ -2,7 +2,7 @@ ...@@ -2,7 +2,7 @@
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
import db, ub import db, ub
import config # import config
from flask import current_app as app from flask import current_app as app
import logging import logging
import smtplib import smtplib
...@@ -33,11 +33,12 @@ def update_download(book_id, user_id): ...@@ -33,11 +33,12 @@ def update_download(book_id, user_id):
ub.session.commit() ub.session.commit()
def make_mobi(book_id): def make_mobi(book_id,calibrepath):
vendorpath = os.path.join(os.path.normpath(os.path.dirname(os.path.realpath(__file__)) + os.sep + "../vendor" + os.sep))
if sys.platform == "win32": if sys.platform == "win32":
kindlegen = os.path.join(config.MAIN_DIR, "vendor", u"kindlegen.exe") kindlegen = os.path.join(vendorpath, u"kindlegen.exe")
else: else:
kindlegen = os.path.join(config.MAIN_DIR, "vendor", u"kindlegen") kindlegen = os.path.join(vendorpath, u"kindlegen")
if not os.path.exists(kindlegen): if not os.path.exists(kindlegen):
app.logger.error("make_mobi: kindlegen binary not found in: %s" % kindlegen) app.logger.error("make_mobi: kindlegen binary not found in: %s" % kindlegen)
return None return None
...@@ -47,7 +48,7 @@ def make_mobi(book_id): ...@@ -47,7 +48,7 @@ def make_mobi(book_id):
app.logger.error("make_mobi: epub format not found for book id: %d" % book_id) app.logger.error("make_mobi: epub format not found for book id: %d" % book_id)
return None return None
file_path = os.path.join(config.DB_ROOT, book.path, data.name) file_path = os.path.join(calibrepath, book.path, data.name)
if os.path.exists(file_path + u".epub"): if os.path.exists(file_path + u".epub"):
p = subprocess.Popen((kindlegen + " \"" + file_path + u".epub\" ").encode(sys.getfilesystemencoding()), p = subprocess.Popen((kindlegen + " \"" + file_path + u".epub\" ").encode(sys.getfilesystemencoding()),
shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE, stdin=subprocess.PIPE) shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE, stdin=subprocess.PIPE)
...@@ -90,15 +91,13 @@ class StderrLogger(object): ...@@ -90,15 +91,13 @@ class StderrLogger(object):
else: else:
self.buffer=self.buffer+message self.buffer=self.buffer+message
def send_test_mail(kindle_mail): def send_raw_email(kindle_mail,msg):
settings = ub.get_mail_settings() settings = ub.get_mail_settings()
msg = MIMEMultipart()
msg['From'] = settings["mail_from"] msg['From'] = settings["mail_from"]
msg['To'] = kindle_mail msg['To'] = kindle_mail
msg['Subject'] = _('Calibre-web test email')
text = _('This email has been sent via calibre web.')
use_ssl = settings.get('mail_use_ssl', 0) use_ssl = int(settings.get('mail_use_ssl', 0))
# convert MIME message to string # convert MIME message to string
fp = StringIO() fp = StringIO()
...@@ -113,16 +112,14 @@ def send_test_mail(kindle_mail): ...@@ -113,16 +112,14 @@ def send_test_mail(kindle_mail):
org_stderr = smtplib.stderr org_stderr = smtplib.stderr
smtplib.stderr = StderrLogger() smtplib.stderr = StderrLogger()
if int(use_ssl) == 2: if use_ssl == 2:
mailserver = smtplib.SMTP_SSL(settings["mail_server"], settings["mail_port"], timeout) mailserver = smtplib.SMTP_SSL(settings["mail_server"], settings["mail_port"], timeout)
else: else:
mailserver = smtplib.SMTP(settings["mail_server"], settings["mail_port"], timeout) mailserver = smtplib.SMTP(settings["mail_server"], settings["mail_port"], timeout)
mailserver.set_debuglevel(1) mailserver.set_debuglevel(1)
if int(use_ssl) == 1: if use_ssl == 1:
#mailserver.ehlo()
mailserver.starttls() mailserver.starttls()
#mailserver.ehlo()
if settings["mail_password"]: if settings["mail_password"]:
mailserver.login(settings["mail_login"], settings["mail_password"]) mailserver.login(settings["mail_login"], settings["mail_password"])
...@@ -138,7 +135,15 @@ def send_test_mail(kindle_mail): ...@@ -138,7 +135,15 @@ def send_test_mail(kindle_mail):
return None return None
def send_mail(book_id, kindle_mail): def send_test_mail(kindle_mail):
msg = MIMEMultipart()
msg['Subject'] = _(u'Calibre-web test email')
text = _(u'This email has been sent via calibre web.')
msg.attach(MIMEText(text.encode('UTF-8'), 'plain', 'UTF-8'))
return send_raw_email(kindle_mail,msg)
def send_mail(book_id, kindle_mail,calibrepath):
"""Send email with attachments""" """Send email with attachments"""
is_mobi = False is_mobi = False
is_azw = False is_azw = False
...@@ -149,17 +154,10 @@ def send_mail(book_id, kindle_mail): ...@@ -149,17 +154,10 @@ def send_mail(book_id, kindle_mail):
settings = ub.get_mail_settings() settings = ub.get_mail_settings()
# create MIME message # create MIME message
msg = MIMEMultipart() msg = MIMEMultipart()
msg['From'] = settings["mail_from"]
msg['To'] = kindle_mail
msg['Subject'] = _(u'Send to Kindle') msg['Subject'] = _(u'Send to Kindle')
text = _(u'This email has been sent via calibre web.') text = _(u'This email has been sent via calibre web.')
msg.attach(MIMEText(text.encode('UTF-8'), 'plain', 'UTF-8')) msg.attach(MIMEText(text.encode('UTF-8'), 'plain', 'UTF-8'))
use_ssl = settings.get('mail_use_ssl', 0)
# attach files
# msg.attach(self.get_attachment(file_path))
book = db.session.query(db.Books).filter(db.Books.id == book_id).first() book = db.session.query(db.Books).filter(db.Books.id == book_id).first()
data = db.session.query(db.Data).filter(db.Data.book == book.id) data = db.session.query(db.Data).filter(db.Data.book == book.id)
...@@ -167,11 +165,11 @@ def send_mail(book_id, kindle_mail): ...@@ -167,11 +165,11 @@ def send_mail(book_id, kindle_mail):
for entry in data: for entry in data:
if entry.format == "MOBI": if entry.format == "MOBI":
formats["mobi"] = os.path.join(config.DB_ROOT, book.path, entry.name + ".mobi") formats["mobi"] = os.path.join(calibrepath, book.path, entry.name + ".mobi")
if entry.format == "EPUB": if entry.format == "EPUB":
formats["epub"] = os.path.join(config.DB_ROOT, book.path, entry.name + ".epub") formats["epub"] = os.path.join(calibrepath, book.path, entry.name + ".epub")
if entry.format == "PDF": if entry.format == "PDF":
formats["pdf"] = os.path.join(config.DB_ROOT, book.path, entry.name + ".pdf") formats["pdf"] = os.path.join(calibrepath, book.path, entry.name + ".pdf")
if len(formats) == 0: if len(formats) == 0:
return _("Could not find any formats suitable for sending by email") return _("Could not find any formats suitable for sending by email")
...@@ -179,7 +177,7 @@ def send_mail(book_id, kindle_mail): ...@@ -179,7 +177,7 @@ def send_mail(book_id, kindle_mail):
if 'mobi' in formats: if 'mobi' in formats:
msg.attach(get_attachment(formats['mobi'])) msg.attach(get_attachment(formats['mobi']))
elif 'epub' in formats: elif 'epub' in formats:
filepath = make_mobi(book.id) filepath = make_mobi(book.id,calibrepath)
if filepath is not None: if filepath is not None:
msg.attach(get_attachment(filepath)) msg.attach(get_attachment(filepath))
elif filepath is None: elif filepath is None:
...@@ -191,40 +189,7 @@ def send_mail(book_id, kindle_mail): ...@@ -191,40 +189,7 @@ def send_mail(book_id, kindle_mail):
else: else:
return _("Could not find any formats suitable for sending by email") return _("Could not find any formats suitable for sending by email")
# convert MIME message to string return send_raw_email(kindle_mail, msg)
fp = StringIO()
gen = Generator(fp, mangle_from_=False)
gen.flatten(msg)
msg = fp.getvalue()
# send email
try:
timeout=600 # set timeout to 5mins
org_stderr = smtplib.stderr
smtplib.stderr = StderrLogger()
if int(use_ssl) == 2:
mailserver = smtplib.SMTP_SSL(settings["mail_server"], settings["mail_port"], timeout)
else:
mailserver = smtplib.SMTP(settings["mail_server"], settings["mail_port"], timeout)
mailserver.set_debuglevel(1)
if int(use_ssl) == 1:
mailserver.starttls()
if settings["mail_password"]:
mailserver.login(settings["mail_login"], settings["mail_password"])
mailserver.sendmail(settings["mail_login"], kindle_mail, msg)
mailserver.quit()
smtplib.stderr = org_stderr
except (socket.error, smtplib.SMTPRecipientsRefused, smtplib.SMTPException), e:
app.logger.error(traceback.print_exc())
return _("Failed to send mail: %s" % str(e))
return None
def get_attachment(file_path): def get_attachment(file_path):
...@@ -273,10 +238,10 @@ def get_normalized_author(value): ...@@ -273,10 +238,10 @@ def get_normalized_author(value):
return value return value
def update_dir_stucture(book_id): def update_dir_stucture(book_id,calibrepath):
db.session.connection().connection.connection.create_function("title_sort", 1, db.title_sort) db.session.connection().connection.connection.create_function("title_sort", 1, db.title_sort)
book = db.session.query(db.Books).filter(db.Books.id == book_id).first() book = db.session.query(db.Books).filter(db.Books.id == book_id).first()
path = os.path.join(config.DB_ROOT, book.path) path = os.path.join(calibrepath, book.path)
authordir = book.path.split(os.sep)[0] authordir = book.path.split(os.sep)[0]
new_authordir = get_valid_filename(book.authors[0].name, False) new_authordir = get_valid_filename(book.authors[0].name, False)
......
This source diff could not be displayed because it is too large. You can view the blob instead.
...@@ -73,9 +73,66 @@ ...@@ -73,9 +73,66 @@
<td>{% if config.PUBLIC_REG %}<span class="glyphicon glyphicon-ok"></span>{% else %}<span class="glyphicon glyphicon-remove"></span>{% endif %}</td> <td>{% if config.PUBLIC_REG %}<span class="glyphicon glyphicon-ok"></span>{% else %}<span class="glyphicon glyphicon-remove"></span>{% endif %}</td>
<td>{% if config.ANON_BROWSE %}<span class="glyphicon glyphicon-ok"></span>{% else %}<span class="glyphicon glyphicon-remove"></span>{% endif %}</td> <td>{% if config.ANON_BROWSE %}<span class="glyphicon glyphicon-ok"></span>{% else %}<span class="glyphicon glyphicon-remove"></span>{% endif %}</td>
</table> </table>
<div class="btn btn-default"><a href="{{url_for('configuration')}}">{{_('Configuration')}}</a></div>
<h2>{{_('Administration')}}</h2> <h2>{{_('Administration')}}</h2>
{% if not config.DEVELOPMENT %} {% if not config.DEVELOPMENT %}
<div class="btn btn-default"><a href="{{url_for('shutdown')}}">{{_('Restart Calibre-web')}}</a></div> <div class="btn btn-default" data-toggle="modal" data-target="#RestartDialog">{{_('Restart Calibre-web')}}</a></div>
<div class="btn btn-default" data-toggle="modal" data-target="#ShutdownDialog">{{_('Stop Calibre-web')}}</a></div>
{% endif %} {% endif %}
</div> </div>
<!-- Modal -->
<div id="RestartDialog" class="modal fade" role="dialog">
<div class="modal-dialog modal-sm">
<!-- Modal content-->
<div class="modal-content">
<div class="modal-header bg-info">
</div>
<div class="modal-body text-center">
<p>{{_('Do you really want to restart Calibre-web?')}}</p>
<button type="button" class="btn btn-default" id="restart" data-dismiss="modal">{{_('Ok')}}</button>
<button type="button" class="btn btn-default" data-dismiss="modal">{{_('Back')}}</button>
</div>
</div>
</div>
</div>
<div id="ShutdownDialog" class="modal fade" role="dialog">
<div class="modal-dialog modal-sm">
<!-- Modal content-->
<div class="modal-content">
<div class="modal-header bg-info">
</div>
<div class="modal-body text-center">
<p>{{_('Do you really want to stop Calibre-web?')}}</p>
<button type="button" class="btn btn-default" id="shutdown" data-dismiss="modal">{{_('Ok')}}</button>
<button type="button" class="btn btn-default" data-dismiss="modal">{{_('Back')}}</button>
</div>
</div>
</div>
</div>
{% endblock %}
{% block js %}
<script type="text/javascript">
$("#restart").click(function() {
$.ajax({
dataType: 'json',
url: "{{url_for('shutdown')}}",
data: {"parameter":0},
//data: data,
success: function(data) {
return alert(data.text);}
});
});
$("#shutdown").click(function() {
$.ajax({
dataType: 'json',
url: "{{url_for('shutdown')}}",
data: {"parameter":1},
success: function(data) {
return alert(data.text);}
});
});
</script>
{% endblock %} {% endblock %}
{% extends "layout.html" %}
{% block body %}
<div class="discover">
<h1>{{title}}</h1>
<form role="form" method="POST" autocomplete="off">
<div class="form-group required">
<label for="config_calibre_dir">{{_('Location of Calibre database')}}</label>
<input type="text" class="form-control" name="config_calibre_dir" id="config_calibre_dir" value="{% if content.config_calibre_dir != None %}{{ content.config_calibre_dir }}{% endif %}" autocomplete="off">
</div>
<div class="form-group">
<label for="config_port">{{_('Server Port')}}</label>
<input type="text" class="form-control" name="config_port" id="port" value="{% if content.config_port != None %}{{ content.config_port }}{% endif %}" autocomplete="off" required>
</div>
<div class="form-group">
<label for="config_calibre_web_title">{{_('Title')}}</label>
<input type="text" class="form-control" name="config_calibre_web_title" id="config_calibre_web_title" value="{% if content.config_calibre_web_title != None %}{{ content.config_calibre_web_title }}{% endif %}" autocomplete="off" required>
</div>
<div class="form-group">
<label for="config_books_per_page">{{_('Books per page')}}</label>
<input type="text" class="form-control" name="config_books_per_page" id="config_books_per_page" value="{% if content.config_books_per_page != None %}{{ content.config_books_per_page }}{% endif %}" autocomplete="off">
</div>
<div class="form-group">
<label for="config_random_books">{{_('No. of random books to show')}}</label>
<input type="text" class="form-control" name="config_random_books" id="config_random_books" value="{% if content.config_random_books != None %}{{ content.config_random_books }}{% endif %}" autocomplete="off">
</div>
<div class="form-group">
<label for="config_title_regex">{{_('Regular expression for title sorting')}}</label>
<input type="text" class="form-control" name="config_title_regex" id="config_title_regex" value="{% if content.config_title_regex != None %}{{ content.config_title_regex }}{% endif %}" autocomplete="off">
</div>
<div class="form-group">
<label for="config_log_level">{{_('Log Level')}}</label>
<select name="config_log_level" id="config_log_level" class="form-control">
<option value="DEBUG" {% if content.config_log_level == 'DEBUG' %}selected{% endif %}>DEBUG</option>
<option value="INFO" {% if content.config_log_level == 'INFO' or content.config_log_level == None %}selected{% endif %}>INFO</option>
<option value="WARNING" {% if content.config_log_level == 'WARNING' %}selected{% endif %}>WARNING</option>
<option value="ERROR" {% if content.config_log_level == 'ERROR' %}selected{% endif %}>ERROR</option>
</select>
</div>
<div class="form-group">
<input type="checkbox" id="config_uploading" name="config_uploading" {% if content.config_uploading %}checked{% endif %}>
<label for="config_uploading">{{_('Enable uploading')}}</label>
</div>
<div class="form-group">
<input type="checkbox" id="config_anonbrowse" name="config_anonbrowse" {% if content.config_anonbrowse %}checked{% endif %}>
<label for="config_anonbrowse">{{_('Enable anonymous browsing')}}</label>
</div>
<div class="form-group">
<input type="checkbox" id="config_public_reg" name="config_public_reg" {% if content.config_public_reg %}checked{% endif %}>
<label for="config_public_reg">{{_('Enable public registration')}}</label>
</div>
<button type="submit" class="btn btn-default">{{_('Submit')}}</button>
</form>
</div>
{% endblock %}
...@@ -191,7 +191,6 @@ ...@@ -191,7 +191,6 @@
<div class="btn-toolbar" role="toolbar"> <div class="btn-toolbar" role="toolbar">
<div class="btn-group" role="group" aria-label="Edit/Delete book"> <div class="btn-group" role="group" aria-label="Edit/Delete book">
<a href="{{ url_for('edit_book', book_id=entry.id) }}" class="btn btn-sm btn-warning" role="button"><span class="glyphicon glyphicon-edit"></span> {{_('Edit metadata')}}</a> <a href="{{ url_for('edit_book', book_id=entry.id) }}" class="btn btn-sm btn-warning" role="button"><span class="glyphicon glyphicon-edit"></span> {{_('Edit metadata')}}</a>
<!-- <a href="{{ url_for('edit_book', book_id=entry.id) }}" class="btn btn-sm btn-danger" role="button"><span class="glyphicon glyphicon-trash"></span> Delete</a> -->
</div> </div>
{% endif %} {% endif %}
......
...@@ -44,7 +44,6 @@ ...@@ -44,7 +44,6 @@
{% endif %} {% endif %}
</div> </div>
</div> </div>
<!-- <p><a href="{{ url_for('edit_book', book_id=entry.id) }}">{{entry.authors[0].name}}: {{entry.title}}</a></p> -->
{% endfor %} {% endfor %}
</div> </div>
</div> </div>
......
...@@ -36,7 +36,6 @@ ...@@ -36,7 +36,6 @@
{% endif %} {% endif %}
</div> </div>
</div> </div>
<!-- <p><a href="{{ url_for('edit_book', book_id=entry.id) }}">{{entry.authors[0].name}}: {{entry.title}}</a></p> -->
{% endfor %} {% endfor %}
</div> </div>
</div> </div>
......
...@@ -41,23 +41,23 @@ ...@@ -41,23 +41,23 @@
</select> </select>
</div> </div>
<div class="form-group"> <div class="form-group">
<input type="checkbox" name="show_random" {% if content.random_books %}checked{% endif %}> <input type="checkbox" name="show_random" id="show_random" {% if content.random_books %}checked{% endif %}>
<label for="show_random">{{_('Show random books')}}</label> <label for="show_random">{{_('Show random books')}}</label>
</div> </div>
<div class="form-group"> <div class="form-group">
<input type="checkbox" name="show_hot" {% if content.hot_books %}checked{% endif %}> <input type="checkbox" name="show_hot" id="show_hot" {% if content.hot_books %}checked{% endif %}>
<label for="show_hot">{{_('Show hot books')}}</label> <label for="show_hot">{{_('Show hot books')}}</label>
</div> </div>
<div class="form-group"> <div class="form-group">
<input type="checkbox" name="show_language" {% if content.language_books %}checked{% endif %}> <input type="checkbox" name="show_language" id="show_language" {% if content.language_books %}checked{% endif %}>
<label for="show_language">{{_('Show language selection')}}</label> <label for="show_language">{{_('Show language selection')}}</label>
</div> </div>
<div class="form-group"> <div class="form-group">
<input type="checkbox" name="show_series" {% if content.series_books %}checked{% endif %}> <input type="checkbox" name="show_series" id="show_series" {% if content.series_books %}checked{% endif %}>
<label for="show_series">{{_('Show series selection')}}</label> <label for="show_series">{{_('Show series selection')}}</label>
</div> </div>
<div class="form-group"> <div class="form-group">
<input type="checkbox" name="show_category" {% if content.category_books %}checked{% endif %}> <input type="checkbox" name="show_category" id="show_category" {% if content.category_books %}checked{% endif %}>
<label for="show_category">{{_('Show category selection')}}</label> <label for="show_category">{{_('Show category selection')}}</label>
</div> </div>
......
...@@ -7,12 +7,12 @@ from sqlalchemy.ext.declarative import declarative_base ...@@ -7,12 +7,12 @@ from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy.orm import * from sqlalchemy.orm import *
from flask_login import AnonymousUserMixin from flask_login import AnonymousUserMixin
import os import os
import config # import config
import traceback import traceback
from werkzeug.security import generate_password_hash from werkzeug.security import generate_password_hash
from flask_babel import gettext as _ from flask_babel import gettext as _
dbpath = os.path.join(config.APP_DB_ROOT, "app.db") dbpath = os.path.join(os.path.normpath(os.path.dirname(os.path.realpath(__file__))+os.sep+".."+os.sep), "app.db")
engine = create_engine('sqlite:///{0}'.format(dbpath), echo=False) engine = create_engine('sqlite:///{0}'.format(dbpath), echo=False)
Base = declarative_base() Base = declarative_base()
...@@ -96,6 +96,23 @@ class UserBase(): ...@@ -96,6 +96,23 @@ class UserBase():
def __repr__(self): def __repr__(self):
return '<User %r>' % self.nickname return '<User %r>' % self.nickname
class Config():
def __init__(self):
self.loadSettings()
def loadSettings(self):
data=session.query(Settings).first()
self.config_calibre_dir = data.config_calibre_dir
self.config_port = data.config_port
self.config_calibre_web_title = data.config_calibre_web_title
self.config_books_per_page = data.config_books_per_page
self.config_random_books = data.config_random_books
self.config_title_regex = data.config_title_regex
self.config_log_level = data.config_log_level
self.config_uploading = data.config_uploading
self.config_anonbrowse = data.config_anonbrowse
self.config_public_reg = data.config_public_reg
class User(UserBase,Base): class User(UserBase,Base):
__tablename__ = 'user' __tablename__ = 'user'
...@@ -118,11 +135,14 @@ class User(UserBase,Base): ...@@ -118,11 +135,14 @@ class User(UserBase,Base):
class Anonymous(AnonymousUserMixin,UserBase): class Anonymous(AnonymousUserMixin,UserBase):
anon_browse = None
def __init__(self): def __init__(self):
self.loadSettings() self.loadSettings()
def loadSettings(self): def loadSettings(self):
data=session.query(User).filter(User.role.op('&')(ROLE_ANONYMOUS) == ROLE_ANONYMOUS).first() data=session.query(User).filter(User.role.op('&')(ROLE_ANONYMOUS) == ROLE_ANONYMOUS).first()
settings=session.query(Settings).first()
self.nickname = data.nickname self.nickname = data.nickname
self.role = data.role self.role = data.role
self.random_books = data.random_books self.random_books = data.random_books
...@@ -133,6 +153,7 @@ class Anonymous(AnonymousUserMixin,UserBase): ...@@ -133,6 +153,7 @@ class Anonymous(AnonymousUserMixin,UserBase):
self.hot_books = data.hot_books self.hot_books = data.hot_books
self.default_language = data.default_language self.default_language = data.default_language
self.locale = data.locale self.locale = data.locale
self.anon_browse = settings.config_anonbrowse
def role_admin(self): def role_admin(self):
return False return False
...@@ -141,7 +162,7 @@ class Anonymous(AnonymousUserMixin,UserBase): ...@@ -141,7 +162,7 @@ class Anonymous(AnonymousUserMixin,UserBase):
return False return False
def is_anonymous(self): def is_anonymous(self):
return config.ANON_BROWSE return self.anon_browse
class Shelf(Base): class Shelf(Base):
...@@ -187,6 +208,16 @@ class Settings(Base): ...@@ -187,6 +208,16 @@ class Settings(Base):
mail_login = Column(String) mail_login = Column(String)
mail_password = Column(String) mail_password = Column(String)
mail_from = Column(String) mail_from = Column(String)
config_calibre_dir = Column(String)
config_port = Column(Integer, default = 8083)
config_calibre_web_title = Column(String,default = u'Calibre-web')
config_books_per_page = Column(Integer, default = 60)
config_random_books = Column(Integer, default = 4)
config_title_regex = Column(String,default=u'^(A|The|An|Der|Die|Das|Den|Ein|Eine|Einen|Dem|Des|Einem|Eines)\s+')
config_log_level = Column(String, default=u'INFO')
config_uploading = Column(SmallInteger, default = 0)
config_anonbrowse = Column(SmallInteger, default = 0)
config_public_reg = Column(SmallInteger, default = 0)
def __repr__(self): def __repr__(self):
#return '<Smtp %r>' % (self.mail_server) #return '<Smtp %r>' % (self.mail_server)
...@@ -216,14 +247,22 @@ def migrate_Database(): ...@@ -216,14 +247,22 @@ def migrate_Database():
conn.execute("ALTER TABLE user ADD column hot_books INTEGER DEFAULT 1") conn.execute("ALTER TABLE user ADD column hot_books INTEGER DEFAULT 1")
session.commit() session.commit()
try: try:
session.query(exists().where(BookShelf.order)).scalar() session.query(exists().where(Settings.config_calibre_dir)).scalar()
session.commit() session.commit()
except exc.OperationalError: # Database is not compatible, some rows are missing except exc.OperationalError: # Database is not compatible, some rows are missing
conn = engine.connect() conn = engine.connect()
conn.execute("ALTER TABLE book_shelf_link ADD column `order` INTEGER DEFAULT 1") conn.execute("ALTER TABLE Settings ADD column `config_calibre_dir` String")
conn.execute("ALTER TABLE Settings ADD column `config_port` INTEGER DEFAULT 8083")
conn.execute("ALTER TABLE Settings ADD column `config_calibre_web_title` String DEFAULT 'Calibre-web'")
conn.execute("ALTER TABLE Settings ADD column `config_books_per_page` INTEGER DEFAULT 60")
conn.execute("ALTER TABLE Settings ADD column `config_random_books` INTEGER DEFAULT 4")
conn.execute("ALTER TABLE Settings ADD column `config_title_regex` String DEFAULT '^(A|The|An|Der|Die|Das|Den|Ein|Eine|Einen|Dem|Des|Einem|Eines)\s+'")
conn.execute("ALTER TABLE Settings ADD column `config_log_level` String DEFAULT 'INFO'")
conn.execute("ALTER TABLE Settings ADD column `config_uploading` SmallInteger DEFAULT 0")
conn.execute("ALTER TABLE Settings ADD column `config_anonbrowse` SmallInteger DEFAULT 0")
conn.execute("ALTER TABLE Settings ADD column `config_public_reg` SmallInteger DEFAULT 0")
session.commit() session.commit()
def create_default_config(): def create_default_config():
settings = Settings() settings = Settings()
settings.mail_server = "mail.example.com" settings.mail_server = "mail.example.com"
......
This diff is collapsed.
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment