mirror of
https://github.com/janeczku/calibre-web
synced 2024-12-25 17:40:31 +00:00
Catch some errors related to non writable settings db
This commit is contained in:
parent
a0b8cc21cc
commit
88d2c60ee8
140
cps/admin.py
140
cps/admin.py
@ -34,7 +34,7 @@ from flask import Blueprint, flash, redirect, url_for, abort, request, make_resp
|
|||||||
from flask_login import login_required, current_user, logout_user
|
from flask_login import login_required, current_user, logout_user
|
||||||
from flask_babel import gettext as _
|
from flask_babel import gettext as _
|
||||||
from sqlalchemy import and_
|
from sqlalchemy import and_
|
||||||
from sqlalchemy.exc import IntegrityError
|
from sqlalchemy.exc import IntegrityError, OperationalError, InvalidRequestError
|
||||||
from sqlalchemy.sql.expression import func
|
from sqlalchemy.sql.expression import func
|
||||||
|
|
||||||
from . import constants, logger, helper, services
|
from . import constants, logger, helper, services
|
||||||
@ -615,78 +615,83 @@ def _configuration_update_helper():
|
|||||||
to_save = request.form.to_dict()
|
to_save = request.form.to_dict()
|
||||||
|
|
||||||
to_save['config_calibre_dir'] = re.sub('[\\/]metadata\.db$', '', to_save['config_calibre_dir'], flags=re.IGNORECASE)
|
to_save['config_calibre_dir'] = re.sub('[\\/]metadata\.db$', '', to_save['config_calibre_dir'], flags=re.IGNORECASE)
|
||||||
db_change |= _config_string(to_save, "config_calibre_dir")
|
try:
|
||||||
|
db_change |= _config_string(to_save, "config_calibre_dir")
|
||||||
|
|
||||||
# Google drive setup
|
# Google drive setup
|
||||||
gdriveError = _configuration_gdrive_helper(to_save)
|
gdriveError = _configuration_gdrive_helper(to_save)
|
||||||
|
|
||||||
reboot_required |= _config_int(to_save, "config_port")
|
reboot_required |= _config_int(to_save, "config_port")
|
||||||
|
|
||||||
reboot_required |= _config_string(to_save, "config_keyfile")
|
reboot_required |= _config_string(to_save, "config_keyfile")
|
||||||
if config.config_keyfile and not os.path.isfile(config.config_keyfile):
|
if config.config_keyfile and not os.path.isfile(config.config_keyfile):
|
||||||
return _configuration_result(_('Keyfile Location is not Valid, Please Enter Correct Path'), gdriveError)
|
return _configuration_result(_('Keyfile Location is not Valid, Please Enter Correct Path'), gdriveError)
|
||||||
|
|
||||||
reboot_required |= _config_string(to_save, "config_certfile")
|
reboot_required |= _config_string(to_save, "config_certfile")
|
||||||
if config.config_certfile and not os.path.isfile(config.config_certfile):
|
if config.config_certfile and not os.path.isfile(config.config_certfile):
|
||||||
return _configuration_result(_('Certfile Location is not Valid, Please Enter Correct Path'), gdriveError)
|
return _configuration_result(_('Certfile Location is not Valid, Please Enter Correct Path'), gdriveError)
|
||||||
|
|
||||||
_config_checkbox_int(to_save, "config_uploading")
|
_config_checkbox_int(to_save, "config_uploading")
|
||||||
_config_checkbox_int(to_save, "config_anonbrowse")
|
_config_checkbox_int(to_save, "config_anonbrowse")
|
||||||
_config_checkbox_int(to_save, "config_public_reg")
|
_config_checkbox_int(to_save, "config_public_reg")
|
||||||
_config_checkbox_int(to_save, "config_register_email")
|
_config_checkbox_int(to_save, "config_register_email")
|
||||||
reboot_required |= _config_checkbox_int(to_save, "config_kobo_sync")
|
reboot_required |= _config_checkbox_int(to_save, "config_kobo_sync")
|
||||||
_config_checkbox_int(to_save, "config_kobo_proxy")
|
_config_checkbox_int(to_save, "config_kobo_proxy")
|
||||||
|
|
||||||
_config_string(to_save, "config_upload_formats")
|
_config_string(to_save, "config_upload_formats")
|
||||||
constants.EXTENSIONS_UPLOAD = [x.lstrip().rstrip() for x in config.config_upload_formats.split(',')]
|
constants.EXTENSIONS_UPLOAD = [x.lstrip().rstrip() for x in config.config_upload_formats.split(',')]
|
||||||
|
|
||||||
_config_string(to_save, "config_calibre")
|
_config_string(to_save, "config_calibre")
|
||||||
_config_string(to_save, "config_converterpath")
|
_config_string(to_save, "config_converterpath")
|
||||||
_config_string(to_save, "config_kepubifypath")
|
_config_string(to_save, "config_kepubifypath")
|
||||||
|
|
||||||
reboot_required |= _config_int(to_save, "config_login_type")
|
reboot_required |= _config_int(to_save, "config_login_type")
|
||||||
|
|
||||||
#LDAP configurator,
|
#LDAP configurator,
|
||||||
if config.config_login_type == constants.LOGIN_LDAP:
|
if config.config_login_type == constants.LOGIN_LDAP:
|
||||||
reboot, message = _configuration_ldap_helper(to_save, gdriveError)
|
reboot, message = _configuration_ldap_helper(to_save, gdriveError)
|
||||||
|
if message:
|
||||||
|
return message
|
||||||
|
reboot_required |= reboot
|
||||||
|
|
||||||
|
# Remote login configuration
|
||||||
|
|
||||||
|
_config_checkbox(to_save, "config_remote_login")
|
||||||
|
if not config.config_remote_login:
|
||||||
|
ub.session.query(ub.RemoteAuthToken).filter(ub.RemoteAuthToken.token_type==0).delete()
|
||||||
|
|
||||||
|
# Goodreads configuration
|
||||||
|
_config_checkbox(to_save, "config_use_goodreads")
|
||||||
|
_config_string(to_save, "config_goodreads_api_key")
|
||||||
|
_config_string(to_save, "config_goodreads_api_secret")
|
||||||
|
if services.goodreads_support:
|
||||||
|
services.goodreads_support.connect(config.config_goodreads_api_key,
|
||||||
|
config.config_goodreads_api_secret,
|
||||||
|
config.config_use_goodreads)
|
||||||
|
|
||||||
|
_config_int(to_save, "config_updatechannel")
|
||||||
|
|
||||||
|
# Reverse proxy login configuration
|
||||||
|
_config_checkbox(to_save, "config_allow_reverse_proxy_header_login")
|
||||||
|
_config_string(to_save, "config_reverse_proxy_login_header_name")
|
||||||
|
|
||||||
|
# OAuth configuration
|
||||||
|
if config.config_login_type == constants.LOGIN_OAUTH:
|
||||||
|
reboot_required |= _configuration_oauth_helper(to_save)
|
||||||
|
|
||||||
|
reboot, message = _configuration_logfile_helper(to_save, gdriveError)
|
||||||
if message:
|
if message:
|
||||||
return message
|
return message
|
||||||
reboot_required |= reboot
|
reboot_required |= reboot
|
||||||
|
# Rarfile Content configuration
|
||||||
# Remote login configuration
|
_config_string(to_save, "config_rarfile_location")
|
||||||
_config_checkbox(to_save, "config_remote_login")
|
if "config_rarfile_location" in to_save:
|
||||||
if not config.config_remote_login:
|
unrar_status = helper.check_unrar(config.config_rarfile_location)
|
||||||
ub.session.query(ub.RemoteAuthToken).filter(ub.RemoteAuthToken.token_type==0).delete()
|
if unrar_status:
|
||||||
|
return _configuration_result(unrar_status, gdriveError)
|
||||||
# Goodreads configuration
|
except (OperationalError, InvalidRequestError):
|
||||||
_config_checkbox(to_save, "config_use_goodreads")
|
ub.session.rollback()
|
||||||
_config_string(to_save, "config_goodreads_api_key")
|
_configuration_result(_(u"Settings DB is not Writeable"), gdriveError)
|
||||||
_config_string(to_save, "config_goodreads_api_secret")
|
|
||||||
if services.goodreads_support:
|
|
||||||
services.goodreads_support.connect(config.config_goodreads_api_key,
|
|
||||||
config.config_goodreads_api_secret,
|
|
||||||
config.config_use_goodreads)
|
|
||||||
|
|
||||||
_config_int(to_save, "config_updatechannel")
|
|
||||||
|
|
||||||
# Reverse proxy login configuration
|
|
||||||
_config_checkbox(to_save, "config_allow_reverse_proxy_header_login")
|
|
||||||
_config_string(to_save, "config_reverse_proxy_login_header_name")
|
|
||||||
|
|
||||||
# OAuth configuration
|
|
||||||
if config.config_login_type == constants.LOGIN_OAUTH:
|
|
||||||
reboot_required |= _configuration_oauth_helper(to_save)
|
|
||||||
|
|
||||||
reboot, message = _configuration_logfile_helper(to_save, gdriveError)
|
|
||||||
if message:
|
|
||||||
return message
|
|
||||||
reboot_required |= reboot
|
|
||||||
# Rarfile Content configuration
|
|
||||||
_config_string(to_save, "config_rarfile_location")
|
|
||||||
if "config_rarfile_location" in to_save:
|
|
||||||
unrar_status = helper.check_unrar(config.config_rarfile_location)
|
|
||||||
if unrar_status:
|
|
||||||
return _configuration_result(unrar_status, gdriveError)
|
|
||||||
|
|
||||||
try:
|
try:
|
||||||
metadata_db = os.path.join(config.config_calibre_dir, "metadata.db")
|
metadata_db = os.path.join(config.config_calibre_dir, "metadata.db")
|
||||||
@ -783,6 +788,9 @@ def _handle_new_user(to_save, content,languages, translations, kobo_support):
|
|||||||
except IntegrityError:
|
except IntegrityError:
|
||||||
ub.session.rollback()
|
ub.session.rollback()
|
||||||
flash(_(u"Found an existing account for this e-mail address or nickname."), category="error")
|
flash(_(u"Found an existing account for this e-mail address or nickname."), category="error")
|
||||||
|
except OperationalError:
|
||||||
|
ub.session.rollback()
|
||||||
|
flash(_(u"Settings DB is not Writeable"), category="error")
|
||||||
|
|
||||||
|
|
||||||
def _handle_edit_user(to_save, content,languages, translations, kobo_support, downloads):
|
def _handle_edit_user(to_save, content,languages, translations, kobo_support, downloads):
|
||||||
@ -872,6 +880,9 @@ def _handle_edit_user(to_save, content,languages, translations, kobo_support, do
|
|||||||
except IntegrityError:
|
except IntegrityError:
|
||||||
ub.session.rollback()
|
ub.session.rollback()
|
||||||
flash(_(u"An unknown error occured."), category="error")
|
flash(_(u"An unknown error occured."), category="error")
|
||||||
|
except OperationalError:
|
||||||
|
ub.session.rollback()
|
||||||
|
flash(_(u"Settings DB is not Writeable"), category="error")
|
||||||
|
|
||||||
|
|
||||||
@admi.route("/admin/user/new", methods=["GET", "POST"])
|
@admi.route("/admin/user/new", methods=["GET", "POST"])
|
||||||
@ -916,7 +927,12 @@ def update_mailsettings():
|
|||||||
_config_string(to_save, "mail_password")
|
_config_string(to_save, "mail_password")
|
||||||
_config_string(to_save, "mail_from")
|
_config_string(to_save, "mail_from")
|
||||||
_config_int(to_save, "mail_size", lambda y: int(y)*1024*1024)
|
_config_int(to_save, "mail_size", lambda y: int(y)*1024*1024)
|
||||||
config.save()
|
try:
|
||||||
|
config.save()
|
||||||
|
except (OperationalError, InvalidRequestError):
|
||||||
|
ub.session.rollback()
|
||||||
|
flash(_(u"Settings DB is not Writeable"), category="error")
|
||||||
|
return edit_mailsettings()
|
||||||
|
|
||||||
if to_save.get("test"):
|
if to_save.get("test"):
|
||||||
if current_user.email:
|
if current_user.email:
|
||||||
|
@ -64,7 +64,6 @@ def init_app(app, config):
|
|||||||
app.config['LDAP_OPENLDAP'] = bool(config.config_ldap_openldap)
|
app.config['LDAP_OPENLDAP'] = bool(config.config_ldap_openldap)
|
||||||
app.config['LDAP_GROUP_OBJECT_FILTER'] = config.config_ldap_group_object_filter
|
app.config['LDAP_GROUP_OBJECT_FILTER'] = config.config_ldap_group_object_filter
|
||||||
app.config['LDAP_GROUP_MEMBERS_FIELD'] = config.config_ldap_group_members_field
|
app.config['LDAP_GROUP_MEMBERS_FIELD'] = config.config_ldap_group_members_field
|
||||||
# app.config['LDAP_CUSTOM_OPTIONS'] = {'OPT_NETWORK_TIMEOUT': 10}
|
|
||||||
|
|
||||||
_ldap.init_app(app)
|
_ldap.init_app(app)
|
||||||
|
|
||||||
|
69
cps/shelf.py
69
cps/shelf.py
@ -27,8 +27,9 @@ from flask import Blueprint, request, flash, redirect, url_for
|
|||||||
from flask_babel import gettext as _
|
from flask_babel import gettext as _
|
||||||
from flask_login import login_required, current_user
|
from flask_login import login_required, current_user
|
||||||
from sqlalchemy.sql.expression import func
|
from sqlalchemy.sql.expression import func
|
||||||
|
from sqlalchemy.exc import OperationalError, InvalidRequestError
|
||||||
|
|
||||||
from . import logger, ub, searched_ids, db, calibre_db
|
from . import logger, ub, searched_ids, calibre_db
|
||||||
from .web import render_title_template
|
from .web import render_title_template
|
||||||
|
|
||||||
|
|
||||||
@ -91,8 +92,16 @@ def add_to_shelf(shelf_id, book_id):
|
|||||||
|
|
||||||
shelf.books.append(ub.BookShelf(shelf=shelf.id, book_id=book_id, order=maxOrder + 1))
|
shelf.books.append(ub.BookShelf(shelf=shelf.id, book_id=book_id, order=maxOrder + 1))
|
||||||
shelf.last_modified = datetime.utcnow()
|
shelf.last_modified = datetime.utcnow()
|
||||||
ub.session.merge(shelf)
|
try:
|
||||||
ub.session.commit()
|
ub.session.merge(shelf)
|
||||||
|
ub.session.commit()
|
||||||
|
except (OperationalError, InvalidRequestError):
|
||||||
|
ub.session.rollback()
|
||||||
|
flash(_(u"Settings DB is not Writeable"), category="error")
|
||||||
|
if "HTTP_REFERER" in request.environ:
|
||||||
|
return redirect(request.environ["HTTP_REFERER"])
|
||||||
|
else:
|
||||||
|
return redirect(url_for('web.index'))
|
||||||
if not xhr:
|
if not xhr:
|
||||||
flash(_(u"Book has been added to shelf: %(sname)s", sname=shelf.name), category="success")
|
flash(_(u"Book has been added to shelf: %(sname)s", sname=shelf.name), category="success")
|
||||||
if "HTTP_REFERER" in request.environ:
|
if "HTTP_REFERER" in request.environ:
|
||||||
@ -143,9 +152,13 @@ def search_to_shelf(shelf_id):
|
|||||||
maxOrder = maxOrder + 1
|
maxOrder = maxOrder + 1
|
||||||
shelf.books.append(ub.BookShelf(shelf=shelf.id, book_id=book, order=maxOrder))
|
shelf.books.append(ub.BookShelf(shelf=shelf.id, book_id=book, order=maxOrder))
|
||||||
shelf.last_modified = datetime.utcnow()
|
shelf.last_modified = datetime.utcnow()
|
||||||
ub.session.merge(shelf)
|
try:
|
||||||
ub.session.commit()
|
ub.session.merge(shelf)
|
||||||
flash(_(u"Books have been added to shelf: %(sname)s", sname=shelf.name), category="success")
|
ub.session.commit()
|
||||||
|
flash(_(u"Books have been added to shelf: %(sname)s", sname=shelf.name), category="success")
|
||||||
|
except (OperationalError, InvalidRequestError):
|
||||||
|
ub.session.rollback()
|
||||||
|
flash(_(u"Settings DB is not Writeable"), category="error")
|
||||||
else:
|
else:
|
||||||
flash(_(u"Could not add books to shelf: %(sname)s", sname=shelf.name), category="error")
|
flash(_(u"Could not add books to shelf: %(sname)s", sname=shelf.name), category="error")
|
||||||
return redirect(url_for('web.index'))
|
return redirect(url_for('web.index'))
|
||||||
@ -180,10 +193,17 @@ def remove_from_shelf(shelf_id, book_id):
|
|||||||
return redirect(url_for('web.index'))
|
return redirect(url_for('web.index'))
|
||||||
return "Book already removed from shelf", 410
|
return "Book already removed from shelf", 410
|
||||||
|
|
||||||
ub.session.delete(book_shelf)
|
try:
|
||||||
shelf.last_modified = datetime.utcnow()
|
ub.session.delete(book_shelf)
|
||||||
ub.session.commit()
|
shelf.last_modified = datetime.utcnow()
|
||||||
|
ub.session.commit()
|
||||||
|
except (OperationalError, InvalidRequestError):
|
||||||
|
ub.session.rollback()
|
||||||
|
flash(_(u"Settings DB is not Writeable"), category="error")
|
||||||
|
if "HTTP_REFERER" in request.environ:
|
||||||
|
return redirect(request.environ["HTTP_REFERER"])
|
||||||
|
else:
|
||||||
|
return redirect(url_for('web.index'))
|
||||||
if not xhr:
|
if not xhr:
|
||||||
flash(_(u"Book has been removed from shelf: %(sname)s", sname=shelf.name), category="success")
|
flash(_(u"Book has been removed from shelf: %(sname)s", sname=shelf.name), category="success")
|
||||||
if "HTTP_REFERER" in request.environ:
|
if "HTTP_REFERER" in request.environ:
|
||||||
@ -235,7 +255,11 @@ def create_shelf():
|
|||||||
ub.session.commit()
|
ub.session.commit()
|
||||||
flash(_(u"Shelf %(title)s created", title=to_save["title"]), category="success")
|
flash(_(u"Shelf %(title)s created", title=to_save["title"]), category="success")
|
||||||
return redirect(url_for('shelf.show_shelf', shelf_id=shelf.id))
|
return redirect(url_for('shelf.show_shelf', shelf_id=shelf.id))
|
||||||
|
except (OperationalError, InvalidRequestError):
|
||||||
|
ub.session.rollback()
|
||||||
|
flash(_(u"Settings DB is not Writeable"), category="error")
|
||||||
except Exception:
|
except Exception:
|
||||||
|
ub.session.rollback()
|
||||||
flash(_(u"There was an error"), category="error")
|
flash(_(u"There was an error"), category="error")
|
||||||
return render_title_template('shelf_edit.html', shelf=shelf, title=_(u"Create a Shelf"), page="shelfcreate")
|
return render_title_template('shelf_edit.html', shelf=shelf, title=_(u"Create a Shelf"), page="shelfcreate")
|
||||||
else:
|
else:
|
||||||
@ -280,7 +304,11 @@ def edit_shelf(shelf_id):
|
|||||||
try:
|
try:
|
||||||
ub.session.commit()
|
ub.session.commit()
|
||||||
flash(_(u"Shelf %(title)s changed", title=to_save["title"]), category="success")
|
flash(_(u"Shelf %(title)s changed", title=to_save["title"]), category="success")
|
||||||
|
except (OperationalError, InvalidRequestError):
|
||||||
|
ub.session.rollback()
|
||||||
|
flash(_(u"Settings DB is not Writeable"), category="error")
|
||||||
except Exception:
|
except Exception:
|
||||||
|
ub.session.rollback()
|
||||||
flash(_(u"There was an error"), category="error")
|
flash(_(u"There was an error"), category="error")
|
||||||
return render_title_template('shelf_edit.html', shelf=shelf, title=_(u"Edit a shelf"), page="shelfedit")
|
return render_title_template('shelf_edit.html', shelf=shelf, title=_(u"Edit a shelf"), page="shelfedit")
|
||||||
else:
|
else:
|
||||||
@ -298,11 +326,16 @@ def delete_shelf_helper(cur_shelf):
|
|||||||
log.info("successfully deleted %s", cur_shelf)
|
log.info("successfully deleted %s", cur_shelf)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@shelf.route("/shelf/delete/<int:shelf_id>")
|
@shelf.route("/shelf/delete/<int:shelf_id>")
|
||||||
@login_required
|
@login_required
|
||||||
def delete_shelf(shelf_id):
|
def delete_shelf(shelf_id):
|
||||||
cur_shelf = ub.session.query(ub.Shelf).filter(ub.Shelf.id == shelf_id).first()
|
cur_shelf = ub.session.query(ub.Shelf).filter(ub.Shelf.id == shelf_id).first()
|
||||||
delete_shelf_helper(cur_shelf)
|
try:
|
||||||
|
delete_shelf_helper(cur_shelf)
|
||||||
|
except (OperationalError, InvalidRequestError):
|
||||||
|
ub.session.rollback()
|
||||||
|
flash(_(u"Settings DB is not Writeable"), category="error")
|
||||||
return redirect(url_for('web.index'))
|
return redirect(url_for('web.index'))
|
||||||
|
|
||||||
|
|
||||||
@ -327,8 +360,12 @@ def show_shelf(shelf_type, shelf_id):
|
|||||||
cur_book = calibre_db.get_book(book.book_id)
|
cur_book = calibre_db.get_book(book.book_id)
|
||||||
if not cur_book:
|
if not cur_book:
|
||||||
log.info('Not existing book %s in %s deleted', book.book_id, shelf)
|
log.info('Not existing book %s in %s deleted', book.book_id, shelf)
|
||||||
ub.session.query(ub.BookShelf).filter(ub.BookShelf.book_id == book.book_id).delete()
|
try:
|
||||||
ub.session.commit()
|
ub.session.query(ub.BookShelf).filter(ub.BookShelf.book_id == book.book_id).delete()
|
||||||
|
ub.session.commit()
|
||||||
|
except (OperationalError, InvalidRequestError):
|
||||||
|
ub.session.rollback()
|
||||||
|
flash(_(u"Settings DB is not Writeable"), category="error")
|
||||||
return render_title_template(page, entries=result, title=_(u"Shelf: '%(name)s'", name=shelf.name),
|
return render_title_template(page, entries=result, title=_(u"Shelf: '%(name)s'", name=shelf.name),
|
||||||
shelf=shelf, page="shelf")
|
shelf=shelf, page="shelf")
|
||||||
else:
|
else:
|
||||||
@ -348,7 +385,11 @@ def order_shelf(shelf_id):
|
|||||||
setattr(book, 'order', to_save[str(book.book_id)])
|
setattr(book, 'order', to_save[str(book.book_id)])
|
||||||
counter += 1
|
counter += 1
|
||||||
# if order diffrent from before -> shelf.last_modified = datetime.utcnow()
|
# if order diffrent from before -> shelf.last_modified = datetime.utcnow()
|
||||||
ub.session.commit()
|
try:
|
||||||
|
ub.session.commit()
|
||||||
|
except (OperationalError, InvalidRequestError):
|
||||||
|
ub.session.rollback()
|
||||||
|
flash(_(u"Settings DB is not Writeable"), category="error")
|
||||||
|
|
||||||
shelf = ub.session.query(ub.Shelf).filter(ub.Shelf.id == shelf_id).first()
|
shelf = ub.session.query(ub.Shelf).filter(ub.Shelf.id == shelf_id).first()
|
||||||
result = list()
|
result = list()
|
||||||
|
11
cps/ub.py
11
cps/ub.py
@ -19,6 +19,7 @@
|
|||||||
|
|
||||||
from __future__ import division, print_function, unicode_literals
|
from __future__ import division, print_function, unicode_literals
|
||||||
import os
|
import os
|
||||||
|
import sys
|
||||||
import datetime
|
import datetime
|
||||||
import itertools
|
import itertools
|
||||||
import uuid
|
import uuid
|
||||||
@ -603,9 +604,13 @@ def migrate_Database(session):
|
|||||||
session.commit()
|
session.commit()
|
||||||
|
|
||||||
# Remove login capability of user Guest
|
# Remove login capability of user Guest
|
||||||
conn = engine.connect()
|
try:
|
||||||
conn.execute("UPDATE user SET password='' where nickname = 'Guest' and password !=''")
|
conn = engine.connect()
|
||||||
session.commit()
|
conn.execute("UPDATE user SET password='' where nickname = 'Guest' and password !=''")
|
||||||
|
session.commit()
|
||||||
|
except exc.OperationalError:
|
||||||
|
print('Settings database is not writeable. Exiting...')
|
||||||
|
sys.exit(1)
|
||||||
|
|
||||||
|
|
||||||
def clean_database(session):
|
def clean_database(session):
|
||||||
|
Loading…
Reference in New Issue
Block a user