# Buggy code
def update_dir_structure_file(book_id, calibrepath):
    localbook = db.session.query(db.Books).filter(db.Books.id == book_id).first()
    path = os.path.join(calibrepath, localbook.path)

    authordir = localbook.path.split("/")[0]
    new_authordir = get_valid_filename(localbook.authors[0].name)

    titledir = localbook.path.split("/")[1]
    new_titledir = get_valid_filename(localbook.title) + " (" + str(book_id) + ")"

    if titledir != new_titledir:
        try:
            new_title_path = os.path.join(os.path.dirname(path), new_titledir)
            if not os.path.exists(new_title_path):
                os.renames(path, new_title_path)
            else:
                web.app.logger.info(
                    "Copying title: " + path + " into existing: " + new_title_path
                )
                for dir_name, subdir_list, file_list in os.walk(path):
                    for file in file_list:
                        os.renames(
                            os.path.join(dir_name, file),
                            os.path.join(new_title_path + dir_name[len(path) :], file),
                        )
            path = new_title_path
            localbook.path = localbook.path.split("/")[0] + "/" + new_titledir
        except OSError as ex:
            web.app.logger.error(
                "Rename title from: " + path + " to " + new_title_path + ": " + str(ex)
            )
            web.app.logger.debug(ex, exc_info=True)
            return _(
                "Rename title from: '%(src)s' to '%(dest)s' failed with error: %(error)s",
                src=path,
                dest=new_title_path,
                error=str(ex),
            )
    if authordir != new_authordir:
        try:
            new_author_path = os.path.join(
                os.path.join(calibrepath, new_authordir), os.path.basename(path)
            )
            os.renames(path, new_author_path)
            localbook.path = new_authordir + "/" + localbook.path.split("/")[1]
        except OSError as ex:
            web.app.logger.error(
                "Rename author from: "
                + path
                + " to "
                + new_author_path
                + ": "
                + str(ex)
            )
            web.app.logger.debug(ex, exc_info=True)
            return _(
                "Rename author from: '%(src)s' to '%(dest)s' failed with error: %(error)s",
                src=path,
                dest=new_author_path,
                error=str(ex),
            )
    return False


# Traceback (OperationalError)
ERROR:cps.web:Exception on /book/125 [GET]
Traceback (most recent call last):
File "/Users/jgillman/Code/calibre-web/vendor/flask/app.py", line 1817, in wsgi_app
response = self.full_dispatch_request()
File "/Users/jgillman/Code/calibre-web/vendor/flask/app.py", line 1477, in full_dispatch_request
rv = self.handle_user_exception(e)
File "/Users/jgillman/Code/calibre-web/vendor/flask/app.py", line 1381, in handle_user_exception
reraise(exc_type, exc_value, tb)
File "/Users/jgillman/Code/calibre-web/vendor/flask/app.py", line 1475, in full_dispatch_request
rv = self.dispatch_request()
File "/Users/jgillman/Code/calibre-web/vendor/flask/app.py", line 1461, in dispatch_request
return self.view_functions[rule.endpoint](**req.view_args)
File "/Users/jgillman/Code/calibre-web/vendor/flask_login.py", line 717, in decorated_view
return func(*args, **kwargs)
File "/Users/jgillman/Code/calibre-web/cps/web.py", line 381, in show_book
return render_template('detail.html', entry=entries,  cc=cc, title=entries.title, books_shelfs=book_in_shelfs)
File "/Users/jgillman/Code/calibre-web/vendor/flask/templating.py", line 128, in render_template
context, ctx.app)
File "/Users/jgillman/Code/calibre-web/vendor/flask/templating.py", line 110, in _render
rv = template.render(context)
File "/Users/jgillman/Code/calibre-web/vendor/jinja2/environment.py", line 969, in render
return self.environment.handle_exception(exc_info, True)
File "/Users/jgillman/Code/calibre-web/vendor/jinja2/environment.py", line 742, in handle_exception
reraise(exc_type, exc_value, tb)
File "/Users/jgillman/Code/calibre-web/cps/templates/detail.html", line 1, in top-level template code
{% extends "layout.html" %}
File "/Users/jgillman/Code/calibre-web/cps/templates/layout.html", line 136, in top-level template code
{% block body %}{% endblock %}
File "/Users/jgillman/Code/calibre-web/cps/templates/detail.html", line 66, in block "body"
{% if entry['custom_column_' ~ c.id]|length > 0 %}
File "/Users/jgillman/Code/calibre-web/vendor/jinja2/environment.py", line 387, in getitem
return getattr(obj, attr)
File "/Users/jgillman/Code/calibre-web/vendor/sqlalchemy/orm/attributes.py", line 316, in __get__
return self.impl.get(instance_state(instance), dict_)
File "/Users/jgillman/Code/calibre-web/vendor/sqlalchemy/orm/attributes.py", line 613, in get
value = self.callable_(state, passive)
File "/Users/jgillman/Code/calibre-web/vendor/sqlalchemy/orm/strategies.py", line 524, in _load_for_state
return self._emit_lazyload(session, state, ident_key, passive)
File "/Users/jgillman/Code/calibre-web/vendor/sqlalchemy/orm/strategies.py", line 585, in _emit_lazyload
result = q.all()
File "/Users/jgillman/Code/calibre-web/vendor/sqlalchemy/orm/query.py", line 2241, in all
return list(self)
File "/Users/jgillman/Code/calibre-web/vendor/sqlalchemy/orm/query.py", line 2353, in __iter__
return self._execute_and_instances(context)
File "/Users/jgillman/Code/calibre-web/vendor/sqlalchemy/orm/query.py", line 2368, in _execute_and_instances
result = conn.execute(querycontext.statement, self._params)
File "/Users/jgillman/Code/calibre-web/vendor/sqlalchemy/engine/base.py", line 662, in execute
params)
File "/Users/jgillman/Code/calibre-web/vendor/sqlalchemy/engine/base.py", line 761, in _execute_clauseelement
compiled_sql, distilled_params
File "/Users/jgillman/Code/calibre-web/vendor/sqlalchemy/engine/base.py", line 874, in _execute_context
context)
File "/Users/jgillman/Code/calibre-web/vendor/sqlalchemy/engine/base.py", line 1024, in _handle_dbapi_exception
exc_info
File "/Users/jgillman/Code/calibre-web/vendor/sqlalchemy/util/compat.py", line 196, in raise_from_cause
reraise(type(exception), exception, tb=exc_tb)
File "/Users/jgillman/Code/calibre-web/vendor/sqlalchemy/engine/base.py", line 867, in _execute_context
context)
File "/Users/jgillman/Code/calibre-web/vendor/sqlalchemy/engine/default.py", line 324, in do_execute
cursor.execute(statement, parameters)
OperationalError: (OperationalError) no such table: books_custom_column_1_link u'SELECT custom_column_1.id AS custom_column_1_id, custom_column_1.value AS custom_column_1_value \
nFROM custom_column_1, books_custom_column_1_link \nWHERE ? = books_custom_column_1_link.book AND custom_column_1.id = books_custom_column_1_link.value' (125,)
ERROR:tornado.access:500 GET /book/125 (::1) 89.60ms

# Fixed code
def update_dir_structure_file(book_id, calibrepath, first_author):
    localbook = db.session.query(db.Books).filter(db.Books.id == book_id).first()
    path = os.path.join(calibrepath, localbook.path)

    authordir = localbook.path.split("/")[0]
    if first_author:
        new_authordir = get_valid_filename(first_author)
    else:
        new_authordir = get_valid_filename(localbook.authors[0].name)

    titledir = localbook.path.split("/")[1]
    new_titledir = get_valid_filename(localbook.title) + " (" + str(book_id) + ")"

    if titledir != new_titledir:
        try:
            new_title_path = os.path.join(os.path.dirname(path), new_titledir)
            if not os.path.exists(new_title_path):
                os.renames(path, new_title_path)
            else:
                web.app.logger.info(
                    "Copying title: " + path + " into existing: " + new_title_path
                )
                for dir_name, subdir_list, file_list in os.walk(path):
                    for file in file_list:
                        os.renames(
                            os.path.join(dir_name, file),
                            os.path.join(new_title_path + dir_name[len(path) :], file),
                        )
            path = new_title_path
            localbook.path = localbook.path.split("/")[0] + "/" + new_titledir
        except OSError as ex:
            web.app.logger.error(
                "Rename title from: " + path + " to " + new_title_path + ": " + str(ex)
            )
            web.app.logger.debug(ex, exc_info=True)
            return _(
                "Rename title from: '%(src)s' to '%(dest)s' failed with error: %(error)s",
                src=path,
                dest=new_title_path,
                error=str(ex),
            )
    if authordir != new_authordir:
        try:
            new_author_path = os.path.join(
                calibrepath, new_authordir, os.path.basename(path)
            )
            os.renames(path, new_author_path)
            localbook.path = new_authordir + "/" + localbook.path.split("/")[1]
        except OSError as ex:
            web.app.logger.error(
                "Rename author from: "
                + path
                + " to "
                + new_author_path
                + ": "
                + str(ex)
            )
            web.app.logger.debug(ex, exc_info=True)
            return _(
                "Rename author from: '%(src)s' to '%(dest)s' failed with error: %(error)s",
                src=path,
                dest=new_author_path,
                error=str(ex),
            )
    # Rename all files from old names to new names
    if authordir != new_authordir or titledir != new_titledir:
        try:
            new_name = (
                get_valid_filename(localbook.title)
                + " - "
                + get_valid_filename(new_authordir)
            )
            path_name = os.path.join(calibrepath, new_authordir, os.path.basename(path))
            for file_format in localbook.data:
                os.renames(
                    os.path.join(
                        path_name, file_format.name + "." + file_format.format.lower()
                    ),
                    os.path.join(
                        path_name, new_name + "." + file_format.format.lower()
                    ),
                )
                file_format.name = new_name
        except OSError as ex:
            web.app.logger.error(
                "Rename file in path " + path + " to " + new_name + ": " + str(ex)
            )
            web.app.logger.debug(ex, exc_info=True)
            return _(
                "Rename file in path '%(src)s' to '%(dest)s' failed with error: %(error)s",
                src=path,
                dest=new_name,
                error=str(ex),
            )
    return False