Commit 513ac6cf authored by Ozzieisaacs's avatar Ozzieisaacs

Fix for #768 (If email server is configured, admins can send user passwords,...

Fix for #768 (If email server is configured, admins can send user passwords, also domains can be denied from registration)
Fixes from tests
Fix response opds with read/unread
changed db_reconnect
Changed output for error 500 (now including error message)
Fix in task queue after 20 messages
parent b586a328
...@@ -190,10 +190,10 @@ def update_view_configuration(): ...@@ -190,10 +190,10 @@ def update_view_configuration():
return view_configuration() return view_configuration()
@admi.route("/ajax/editdomain", methods=['POST']) @admi.route("/ajax/editdomain/<int:allow>", methods=['POST'])
@login_required @login_required
@admin_required @admin_required
def edit_domain(): def edit_domain(allow):
# POST /post # POST /post
# name: 'username', //name of field (column in db) # name: 'username', //name of field (column in db)
# pk: 1 //primary key (record id) # pk: 1 //primary key (record id)
...@@ -206,14 +206,14 @@ def edit_domain(): ...@@ -206,14 +206,14 @@ def edit_domain():
return "" return ""
@admi.route("/ajax/adddomain", methods=['POST']) @admi.route("/ajax/adddomain/<int:allow>", methods=['POST'])
@login_required @login_required
@admin_required @admin_required
def add_domain(): def add_domain(allow):
domain_name = request.form.to_dict()['domainname'].replace('*', '%').replace('?', '_').lower() domain_name = request.form.to_dict()['domainname'].replace('*', '%').replace('?', '_').lower()
check = ub.session.query(ub.Registration).filter(ub.Registration.domain == domain_name).first() check = ub.session.query(ub.Registration).filter(ub.Registration.domain == domain_name).filter(ub.Registration.allow == allow).first()
if not check: if not check:
new_domain = ub.Registration(domain=domain_name) new_domain = ub.Registration(domain=domain_name, allow=allow)
ub.session.add(new_domain) ub.session.add(new_domain)
ub.session.commit() ub.session.commit()
return "" return ""
...@@ -227,18 +227,18 @@ def delete_domain(): ...@@ -227,18 +227,18 @@ def delete_domain():
ub.session.query(ub.Registration).filter(ub.Registration.id == domain_id).delete() ub.session.query(ub.Registration).filter(ub.Registration.id == domain_id).delete()
ub.session.commit() ub.session.commit()
# If last domain was deleted, add all domains by default # If last domain was deleted, add all domains by default
if not ub.session.query(ub.Registration).count(): if not ub.session.query(ub.Registration).filter(ub.Registration.allow==1).count():
new_domain = ub.Registration(domain="%.%") new_domain = ub.Registration(domain="%.%",allow=1)
ub.session.add(new_domain) ub.session.add(new_domain)
ub.session.commit() ub.session.commit()
return "" return ""
@admi.route("/ajax/domainlist") @admi.route("/ajax/domainlist/<int:allow>")
@login_required @login_required
@admin_required @admin_required
def list_domain(): def list_domain(allow):
answer = ub.session.query(ub.Registration).all() answer = ub.session.query(ub.Registration).filter(ub.Registration.allow == allow).all()
json_dumps = json.dumps([{"domain": r.domain.replace('%', '*').replace('_', '?'), "id": r.id} for r in answer]) json_dumps = json.dumps([{"domain": r.domain.replace('%', '*').replace('_', '?'), "id": r.id} for r in answer])
js = json.dumps(json_dumps.replace('"', "'")).lstrip('"').strip('"') js = json.dumps(json_dumps.replace('"', "'")).lstrip('"').strip('"')
response = make_response(js.replace("'", '"')) response = make_response(js.replace("'", '"'))
...@@ -605,6 +605,7 @@ def edit_user(user_id): ...@@ -605,6 +605,7 @@ def edit_user(user_id):
else: else:
flash(_(u"Found an existing account for this e-mail address."), category="error") flash(_(u"Found an existing account for this e-mail address."), category="error")
return render_title_template("user_edit.html", translations=translations, languages=languages, return render_title_template("user_edit.html", translations=translations, languages=languages,
mail_configured = config.get_mail_server_configured(),
new_user=0, content=content, downloads=downloads, registered_oauth=oauth_check, new_user=0, content=content, downloads=downloads, registered_oauth=oauth_check,
title=_(u"Edit User %(nick)s", nick=content.nickname), page="edituser") title=_(u"Edit User %(nick)s", nick=content.nickname), page="edituser")
if "nickname" in to_save and to_save["nickname"] != content.nickname: if "nickname" in to_save and to_save["nickname"] != content.nickname:
...@@ -616,11 +617,11 @@ def edit_user(user_id): ...@@ -616,11 +617,11 @@ def edit_user(user_id):
return render_title_template("user_edit.html", return render_title_template("user_edit.html",
translations=translations, translations=translations,
languages=languages, languages=languages,
mail_configured=config.get_mail_server_configured(),
new_user=0, content=content, new_user=0, content=content,
downloads=downloads, downloads=downloads,
registered_oauth=oauth_check, registered_oauth=oauth_check,
title=_(u"Edit User %(nick)s", title=_(u"Edit User %(nick)s", nick=content.nickname),
nick=content.nickname),
page="edituser") page="edituser")
if "kindle_mail" in to_save and to_save["kindle_mail"] != content.kindle_mail: if "kindle_mail" in to_save and to_save["kindle_mail"] != content.kindle_mail:
...@@ -633,21 +634,27 @@ def edit_user(user_id): ...@@ -633,21 +634,27 @@ def edit_user(user_id):
flash(_(u"An unknown error occured."), category="error") flash(_(u"An unknown error occured."), category="error")
return render_title_template("user_edit.html", translations=translations, languages=languages, new_user=0, return render_title_template("user_edit.html", translations=translations, languages=languages, new_user=0,
content=content, downloads=downloads, registered_oauth=oauth_check, content=content, downloads=downloads, registered_oauth=oauth_check,
mail_configured=config.get_mail_server_configured(),
title=_(u"Edit User %(nick)s", nick=content.nickname), page="edituser") title=_(u"Edit User %(nick)s", nick=content.nickname), page="edituser")
@admi.route("/admin/resetpassword/<int:user_id>") @admi.route("/admin/resetpassword/<int:user_id>")
@login_required @login_required
@admin_required @admin_required
def reset_password(user_id): def reset_user_password(user_id):
if not config.config_public_reg: if not config.config_public_reg:
abort(404) abort(404)
if current_user is not None and current_user.is_authenticated: if current_user is not None and current_user.is_authenticated:
ret, message = reset_password(user_id) ret, message = reset_password(user_id)
if ret == 1: if ret == 1:
log.debug(u"Password for user %(user)s reset", user=message)
flash(_(u"Password for user %(user)s reset", user=message), category="success") flash(_(u"Password for user %(user)s reset", user=message), category="success")
else: elif ret == 0:
log.error(u"An unknown error occurred. Please try again later.")
flash(_(u"An unknown error occurred. Please try again later."), category="error") flash(_(u"An unknown error occurred. Please try again later."), category="error")
else:
log.error(u"Please configure the SMTP mail settings first...")
flash(_(u"Please configure the SMTP mail settings first..."), category="error")
return redirect(url_for('admin.admin')) return redirect(url_for('admin.admin'))
...@@ -681,6 +688,7 @@ def send_logfile(logtype): ...@@ -681,6 +688,7 @@ def send_logfile(logtype):
@admi.route("/get_update_status", methods=['GET']) @admi.route("/get_update_status", methods=['GET'])
@login_required_if_no_ano @login_required_if_no_ano
def get_update_status(): def get_update_status():
log.info(u"Update status requested")
return updater_thread.get_available_updates(request.method, locale=get_locale()) return updater_thread.get_available_updates(request.method, locale=get_locale())
......
...@@ -38,7 +38,7 @@ class _Settings(_Base): ...@@ -38,7 +38,7 @@ class _Settings(_Base):
__tablename__ = 'settings' __tablename__ = 'settings'
id = Column(Integer, primary_key=True) id = Column(Integer, primary_key=True)
mail_server = Column(String, default='mail.example.org') mail_server = Column(String, default=constants.DEFAULT_MAIL_SERVER)
mail_port = Column(Integer, default=25) mail_port = Column(Integer, default=25)
mail_use_ssl = Column(SmallInteger, default=0) mail_use_ssl = Column(SmallInteger, default=0)
mail_login = Column(String, default='mail@example.com') mail_login = Column(String, default='mail@example.com')
...@@ -189,6 +189,10 @@ class _ConfigSQL(object): ...@@ -189,6 +189,10 @@ class _ConfigSQL(object):
def get_mail_settings(self): def get_mail_settings(self):
return {k:v for k, v in self.__dict__.items() if k.startswith('mail_')} return {k:v for k, v in self.__dict__.items() if k.startswith('mail_')}
def get_mail_server_configured(self):
return not bool(self.mail_server == constants.DEFAULT_MAIL_SERVER)
def set_from_dictionary(self, dictionary, field, convertor=None, default=None): def set_from_dictionary(self, dictionary, field, convertor=None, default=None):
'''Possibly updates a field of this object. '''Possibly updates a field of this object.
The new value, if present, is grabbed from the given dictionary, and optionally passed through a convertor. The new value, if present, is grabbed from the given dictionary, and optionally passed through a convertor.
......
...@@ -94,6 +94,7 @@ LOGIN_LDAP = 1 ...@@ -94,6 +94,7 @@ LOGIN_LDAP = 1
LOGIN_OAUTH = 2 LOGIN_OAUTH = 2
# LOGIN_OAUTH_GOOGLE = 3 # LOGIN_OAUTH_GOOGLE = 3
DEFAULT_MAIL_SERVER = "mail.example.org"
DEFAULT_PASSWORD = "admin123" DEFAULT_PASSWORD = "admin123"
DEFAULT_PORT = 8083 DEFAULT_PORT = 8083
...@@ -105,6 +106,7 @@ except ValueError: ...@@ -105,6 +106,7 @@ except ValueError:
del env_CALIBRE_PORT del env_CALIBRE_PORT
EXTENSIONS_AUDIO = {'mp3', 'm4a', 'm4b'} EXTENSIONS_AUDIO = {'mp3', 'm4a', 'm4b'}
EXTENSIONS_CONVERT = {'pdf', 'epub', 'mobi', 'azw3', 'docx', 'rtf', 'fb2', 'lit', 'lrf', 'txt', 'htmlz', 'rtf', 'odt'} EXTENSIONS_CONVERT = {'pdf', 'epub', 'mobi', 'azw3', 'docx', 'rtf', 'fb2', 'lit', 'lrf', 'txt', 'htmlz', 'rtf', 'odt'}
EXTENSIONS_UPLOAD = {'txt', 'pdf', 'epub', 'mobi', 'azw', 'azw3', 'cbr', 'cbz', 'cbt', 'djvu', 'prc', 'doc', 'docx', EXTENSIONS_UPLOAD = {'txt', 'pdf', 'epub', 'mobi', 'azw', 'azw3', 'cbr', 'cbz', 'cbt', 'djvu', 'prc', 'doc', 'docx',
......
...@@ -33,7 +33,7 @@ from sqlalchemy.ext.declarative import declarative_base ...@@ -33,7 +33,7 @@ from sqlalchemy.ext.declarative import declarative_base
session = None session = None
cc_exceptions = ['datetime', 'comments', 'float', 'composite', 'series'] cc_exceptions = ['datetime', 'comments', 'float', 'composite', 'series']
cc_classes = {} cc_classes = {}
engine = None
Base = declarative_base() Base = declarative_base()
...@@ -288,7 +288,7 @@ class Books(Base): ...@@ -288,7 +288,7 @@ class Books(Base):
@property @property
def atom_timestamp(self): def atom_timestamp(self):
return (self.timestamp or '').replace(' ', 'T') return (self.timestamp.strftime('%Y-%m-%dT%H:%M:%S+00:00') or '')
class Custom_Columns(Base): class Custom_Columns(Base):
__tablename__ = 'custom_columns' __tablename__ = 'custom_columns'
...@@ -327,6 +327,7 @@ def update_title_sort(config, conn=None): ...@@ -327,6 +327,7 @@ def update_title_sort(config, conn=None):
def setup_db(config): def setup_db(config):
dispose() dispose()
global engine
if not config.config_calibre_dir: if not config.config_calibre_dir:
config.invalidate() config.invalidate()
...@@ -428,3 +429,8 @@ def dispose(): ...@@ -428,3 +429,8 @@ def dispose():
if name.startswith("custom_column_") or name.startswith("books_custom_column_"): if name.startswith("custom_column_") or name.startswith("books_custom_column_"):
if table is not None: if table is not None:
Base.metadata.remove(table) Base.metadata.remove(table)
def reconnect_db(config):
session.close()
engine.dispose()
setup_db(config)
...@@ -125,7 +125,7 @@ def send_registration_mail(e_mail, user_name, default_password, resend=False): ...@@ -125,7 +125,7 @@ def send_registration_mail(e_mail, user_name, default_password, resend=False):
if not resend: if not resend:
text += "Your new account at Calibre-Web has been created. Thanks for joining us!\r\n" text += "Your new account at Calibre-Web has been created. Thanks for joining us!\r\n"
text += "Please log in to your account using the following informations:\r\n" text += "Please log in to your account using the following informations:\r\n"
text += "User name: %s\n" % user_name text += "User name: %s\r\n" % user_name
text += "Password: %s\r\n" % default_password text += "Password: %s\r\n" % default_password
text += "Don't forget to change your password after first login.\r\n" text += "Don't forget to change your password after first login.\r\n"
text += "Sincerely\r\n\r\n" text += "Sincerely\r\n\r\n"
...@@ -416,6 +416,8 @@ def reset_password(user_id): ...@@ -416,6 +416,8 @@ def reset_password(user_id):
existing_user = ub.session.query(ub.User).filter(ub.User.id == user_id).first() existing_user = ub.session.query(ub.User).filter(ub.User.id == user_id).first()
password = generate_random_password() password = generate_random_password()
existing_user.password = generate_password_hash(password) existing_user.password = generate_password_hash(password)
if not config.get_mail_server_configured():
return (2, None)
try: try:
ub.session.commit() ub.session.commit()
send_registration_mail(existing_user.email, existing_user.nickname, password, True) send_registration_mail(existing_user.email, existing_user.nickname, password, True)
...@@ -699,9 +701,13 @@ def speaking_language(languages=None): ...@@ -699,9 +701,13 @@ def speaking_language(languages=None):
# from https://code.luasoftware.com/tutorials/flask/execute-raw-sql-in-flask-sqlalchemy/ # from https://code.luasoftware.com/tutorials/flask/execute-raw-sql-in-flask-sqlalchemy/
def check_valid_domain(domain_text): def check_valid_domain(domain_text):
domain_text = domain_text.split('@', 1)[-1].lower() domain_text = domain_text.split('@', 1)[-1].lower()
sql = "SELECT * FROM registration WHERE :domain LIKE domain;" sql = "SELECT * FROM registration WHERE (:domain LIKE domain and allow = 1);"
result = ub.session.query(ub.Registration).from_statement(text(sql)).params(domain=domain_text).all() result = ub.session.query(ub.Registration).from_statement(text(sql)).params(domain=domain_text).all()
return len(result) if not len(result):
return False
sql = "SELECT * FROM registration WHERE (:domain LIKE domain and allow = 0);"
result = ub.session.query(ub.Registration).from_statement(text(sql)).params(domain=domain_text).all()
return not len(result)
# Orders all Authors in the list according to authors sort # Orders all Authors in the list according to authors sort
......
...@@ -276,7 +276,7 @@ def feed_languages(book_id): ...@@ -276,7 +276,7 @@ def feed_languages(book_id):
isoLanguages.get(part3=entry.languages[index].lang_code).name)''' isoLanguages.get(part3=entry.languages[index].lang_code).name)'''
return render_xml_template('feed.xml', entries=entries, pagination=pagination) return render_xml_template('feed.xml', entries=entries, pagination=pagination)
@opds.route("/opds/shelfindex/", defaults={'public': 0}) @opds.route("/opds/shelfindex", defaults={'public': 0})
@opds.route("/opds/shelfindex/<string:public>") @opds.route("/opds/shelfindex/<string:public>")
@requires_basic_auth_if_no_ano @requires_basic_auth_if_no_ano
def feed_shelfindex(public): def feed_shelfindex(public):
...@@ -378,15 +378,16 @@ def render_xml_template(*args, **kwargs): ...@@ -378,15 +378,16 @@ def render_xml_template(*args, **kwargs):
def feed_get_cover(book_id): def feed_get_cover(book_id):
return get_book_cover(book_id) return get_book_cover(book_id)
@opds.route("/opds/readbooks/") @opds.route("/opds/readbooks")
@requires_basic_auth_if_no_ano @requires_basic_auth_if_no_ano
def feed_read_books(): def feed_read_books():
off = request.args.get("offset") or 0 off = request.args.get("offset") or 0
return render_read_books(int(off) / (int(config.config_books_per_page)) + 1, True, True) result, pagination = render_read_books(int(off) / (int(config.config_books_per_page)) + 1, True, True)
return render_xml_template('feed.xml', entries=result, pagination=pagination)
@opds.route("/opds/unreadbooks")
@opds.route("/opds/unreadbooks/")
@requires_basic_auth_if_no_ano @requires_basic_auth_if_no_ano
def feed_unread_books(): def feed_unread_books():
off = request.args.get("offset") or 0 off = request.args.get("offset") or 0
return render_read_books(int(off) / (int(config.config_books_per_page)) + 1, False, True) result, pagination = render_read_books(int(off) / (int(config.config_books_per_page)) + 1, False, True)
return render_xml_template('feed.xml', entries=result, pagination=pagination)
...@@ -19,21 +19,41 @@ ...@@ -19,21 +19,41 @@
$(function() { $(function() {
$("#domain_submit").click(function(event) { $("#domain_allow_submit").click(function(event) {
event.preventDefault(); event.preventDefault();
$("#domain_add").ajaxForm(); $("#domain_add_allow").ajaxForm();
$(this).closest("form").submit(); $(this).closest("form").submit();
$.ajax ({ $.ajax ({
method:"get", method:"get",
url: window.location.pathname + "/../../ajax/domainlist", url: window.location.pathname + "/../../ajax/domainlist/1",
async: true, async: true,
timeout: 900, timeout: 900,
success:function(data) { success:function(data) {
$("#domain-table").bootstrapTable("load", data); $("#domain-allow-table").bootstrapTable("load", data);
} }
}); });
}); });
$("#domain-table").bootstrapTable({ $("#domain-allow-table").bootstrapTable({
formatNoMatches: function () {
return "";
},
striped: false
});
$("#domain_deny_submit").click(function(event) {
event.preventDefault();
$("#domain_add_deny").ajaxForm();
$(this).closest("form").submit();
$.ajax ({
method:"get",
url: window.location.pathname + "/../../ajax/domainlist/0",
async: true,
timeout: 900,
success:function(data) {
$("#domain-deny-table").bootstrapTable("load", data);
}
});
});
$("#domain-deny-table").bootstrapTable({
formatNoMatches: function () { formatNoMatches: function () {
return ""; return "";
}, },
...@@ -50,14 +70,22 @@ $(function() { ...@@ -50,14 +70,22 @@ $(function() {
$("#DeleteDomain").modal("hide"); $("#DeleteDomain").modal("hide");
$.ajax({ $.ajax({
method:"get", method:"get",
url: window.location.pathname + "/../../ajax/domainlist", url: window.location.pathname + "/../../ajax/domainlist/1",
async: true, async: true,
timeout: 900, timeout: 900,
success:function(data) { success:function(data) {
$("#domain-table").bootstrapTable("load", data); $("#domain-allow-table").bootstrapTable("load", data);
}
});
$.ajax({
method:"get",
url: window.location.pathname + "/../../ajax/domainlist/0",
async: true,
timeout: 900,
success:function(data) {
$("#domain-deny-table").bootstrapTable("load", data);
} }
}); });
}); });
//triggered when modal is about to be shown //triggered when modal is about to be shown
$("#DeleteDomain").on("show.bs.modal", function(e) { $("#DeleteDomain").on("show.bs.modal", function(e) {
......
...@@ -41,22 +41,40 @@ ...@@ -41,22 +41,40 @@
</form> </form>
{% if g.allow_registration %} {% if g.allow_registration %}
<h2>{{_('Allowed domains for registering')}}</h2> <h2>{{_('Allowed domains for registering')}}</h2>
<table class="table table-no-bordered" id="domain-table" data-url="{{url_for('admin.list_domain')}}" data-id-field="id" data-show-header="false" data-editable-mode="inline"> <form id="domain_add_allow" action="{{ url_for('admin.add_domain',allow=1)}}" method="POST">
<div class="form-group required">
<label for="domainname_allow">{{_('Add Domain')}}</label>
<input type="text" class="form-control" name="domainname" id="domainname_allow" >
</div>
<button id="domain_allow_submit" class="btn btn-default">{{_('Add')}}</button>
</form>
<table class="table table-no-bordered" id="domain-allow-table" data-url="{{url_for('admin.list_domain', allow=1)}}" data-id-field="id" data-show-header="false" data-editable-mode="inline">
<thead>
<tr>
<th data-field="domain" id="domain-allow" data-editable-type="text" data-editable-url="{{ url_for('admin.edit_domain', allow = 1)}}" data-editable="true" data-editable-title="{{_('Enter domainname')}}"></th>
<th data-field="id" id="id-allow" data-visible="false"></th>
<th data-align="right" data-formatter="TableActions"></th>
</tr>
</thead>
</table>
<h2>{{_('Denied domains for registering')}}</h2>
<table class="table table-no-bordered" id="domain-deny-table" data-url="{{url_for('admin.list_domain', allow=0)}}" data-id-field="id" data-show-header="false" data-editable-mode="inline">
<thead> <thead>
<tr> <tr>
<th data-field="domain" id="domain" data-editable-type="text" data-editable-url="{{ url_for('admin.edit_domain')}}" data-editable="true" data-editable-title="{{_('Enter domainname')}}"></th> <th data-field="domain" id="domain-deny" data-editable-type="text" data-editable-url="{{ url_for('admin.edit_domain', allow = 0)}}" data-editable="true" data-editable-title="{{_('Enter domainname')}}"></th>
<th data-field="id" id="id" data-visible="false"></th> <th data-field="id" id="id-deny" data-visible="false"></th>
<th data-align="right" data-formatter="TableActions"></th> <th data-align="right" data-formatter="TableActions"></th>
</tr> </tr>
</thead> </thead>
</table> </table>
<form id="domain_add" action="{{ url_for('admin.add_domain')}}" method="POST"> <form id="domain_add_deny" action="{{ url_for('admin.add_domain',allow=0)}}" method="POST">
<div class="form-group required"> <div class="form-group required">
<label for="domainname">{{_('Add Domain')}}</label> <label for="domainname_deny">{{_('Add Domain')}}</label>
<input type="text" class="form-control" name="domainname" id="domainname" > <input type="text" class="form-control" name="domainname" id="domainname_deny" >
</div> </div>
<button id="domain_submit" class="btn btn-default">{{_('Add')}}</button> <button id="domain_deny_submit" class="btn btn-default">{{_('Add')}}</button>
</form> </form>
{% endif %} {% endif %}
</div> </div>
{% endblock %} {% endblock %}
......
...@@ -14,15 +14,14 @@ ...@@ -14,15 +14,14 @@
<input type="email" class="form-control" name="email" id="email" value="{{ content.email if content.email != None }}" autocomplete="off"> <input type="email" class="form-control" name="email" id="email" value="{{ content.email if content.email != None }}" autocomplete="off">
</div> </div>
{% if ( g.user and g.user.role_passwd() or g.user.role_admin() ) and not content.role_anonymous() %} {% if ( g.user and g.user.role_passwd() or g.user.role_admin() ) and not content.role_anonymous() %}
{% if g.user and g.user.role_admin() and g.allow_registration and not new_user and not profile %} {% if g.user and g.user.role_admin() and not new_user and not profile and ( mail_configured and content.email if content.email != None %}
<div class="btn btn-default" id="resend_password"><a href="{{url_for('admin.reset_password', user_id = content.id) }}">{{_('Reset user Password')}}</a></div> <div class="btn btn-default" id="resend_password"><a href="{{url_for('admin.reset_user_password', user_id = content.id) }}">{{_('Reset user Password')}}</a></div>
{% else %} {% endif %}
<div class="form-group"> <div class="form-group">
<label for="password">{{_('Password')}}</label> <label for="password">{{_('Password')}}</label>
<input type="password" class="form-control" name="password" id="password" value="" autocomplete="off"> <input type="password" class="form-control" name="password" id="password" value="" autocomplete="off">
</div> </div>
{% endif %} {% endif %}
{% endif %}
<div class="form-group"> <div class="form-group">
<label for="kindle_mail">{{_('Kindle E-Mail')}}</label> <label for="kindle_mail">{{_('Kindle E-Mail')}}</label>
<input type="email" class="form-control" name="kindle_mail" id="kindle_mail" value="{{ content.kindle_mail if content.kindle_mail != None }}"> <input type="email" class="form-control" name="kindle_mail" id="kindle_mail" value="{{ content.kindle_mail if content.kindle_mail != None }}">
......
...@@ -297,6 +297,7 @@ class Registration(Base): ...@@ -297,6 +297,7 @@ class Registration(Base):
id = Column(Integer, primary_key=True) id = Column(Integer, primary_key=True)
domain = Column(String) domain = Column(String)
allow = Column(Integer)
def __repr__(self): def __repr__(self):
return u"<Registration('{0}')>".format(self.domain) return u"<Registration('{0}')>".format(self.domain)
...@@ -332,24 +333,32 @@ def migrate_Database(session): ...@@ -332,24 +333,32 @@ def migrate_Database(session):
if not engine.dialect.has_table(engine.connect(), "registration"): if not engine.dialect.has_table(engine.connect(), "registration"):
ReadBook.__table__.create(bind=engine) ReadBook.__table__.create(bind=engine)
conn = engine.connect() conn = engine.connect()
conn.execute("insert into registration (domain) values('%.%')") conn.execute("insert into registration (domain, allow) values('%.%',1)")
session.commit()
try:
session.query(exists().where(Registration.allow)).scalar()
session.commit()
except exc.OperationalError: # Database is not compatible, some columns are missing
conn = engine.connect()
conn.execute("ALTER TABLE registration ADD column 'allow' INTEGER")
conn.execute("update registration set 'allow' = 1")
session.commit() session.commit()
# Handle table exists, but no content # Handle table exists, but no content
cnt = session.query(Registration).count() cnt = session.query(Registration).count()
if not cnt: if not cnt:
conn = engine.connect() conn = engine.connect()
conn.execute("insert into registration (domain) values('%.%')") conn.execute("insert into registration (domain, allow) values('%.%',1)")
session.commit() session.commit()
try: try:
session.query(exists().where(BookShelf.order)).scalar() session.query(exists().where(BookShelf.order)).scalar()
except exc.OperationalError: # Database is not compatible, some rows are missing except exc.OperationalError: # Database is not compatible, some columns 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 book_shelf_link ADD column 'order' INTEGER DEFAULT 1")
session.commit() session.commit()
try: try:
create = False create = False
session.query(exists().where(User.sidebar_view)).scalar() session.query(exists().where(User.sidebar_view)).scalar()
except exc.OperationalError: # Database is not compatible, some rows are missing except exc.OperationalError: # Database is not compatible, some columns are missing
conn = engine.connect() conn = engine.connect()
conn.execute("ALTER TABLE user ADD column `sidebar_view` Integer DEFAULT 1") conn.execute("ALTER TABLE user ADD column `sidebar_view` Integer DEFAULT 1")
session.commit() session.commit()
......
This diff is collapsed.
...@@ -231,7 +231,7 @@ class WorkerThread(threading.Thread): ...@@ -231,7 +231,7 @@ class WorkerThread(threading.Thread):
self.queue.pop(index) self.queue.pop(index)
self.UIqueue.pop(index) self.UIqueue.pop(index)
# if we are deleting entries before the current index, adjust the index # if we are deleting entries before the current index, adjust the index
if index <= self.current and index: if index <= self.current and self.current:
self.current -= 1 self.current -= 1
self.last = len(self.queue) self.last = len(self.queue)
......
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