forked from FrederikBaerentsen/BrickTracker
Split the uncomfortably big admin view into smaller admin views
This commit is contained in:
parent
e2bcd61ace
commit
798226932f
@ -12,7 +12,13 @@ from bricktracker.navbar import Navbar
|
||||
from bricktracker.sql import close
|
||||
from bricktracker.version import __version__
|
||||
from bricktracker.views.add import add_page
|
||||
from bricktracker.views.admin import admin_page
|
||||
from bricktracker.views.admin.admin import admin_page
|
||||
from bricktracker.views.admin.checkbox import admin_checkbox_page
|
||||
from bricktracker.views.admin.database import admin_database_page
|
||||
from bricktracker.views.admin.image import admin_image_page
|
||||
from bricktracker.views.admin.instructions import admin_instructions_page
|
||||
from bricktracker.views.admin.retired import admin_retired_page
|
||||
from bricktracker.views.admin.theme import admin_theme_page
|
||||
from bricktracker.views.error import error_404
|
||||
from bricktracker.views.index import index_page
|
||||
from bricktracker.views.instructions import instructions_page
|
||||
@ -60,9 +66,8 @@ def setup_app(app: Flask) -> None:
|
||||
# Register errors
|
||||
app.register_error_handler(404, error_404)
|
||||
|
||||
# Register routes
|
||||
# Register app routes
|
||||
app.register_blueprint(add_page)
|
||||
app.register_blueprint(admin_page)
|
||||
app.register_blueprint(index_page)
|
||||
app.register_blueprint(instructions_page)
|
||||
app.register_blueprint(login_page)
|
||||
@ -71,6 +76,15 @@ def setup_app(app: Flask) -> None:
|
||||
app.register_blueprint(set_page)
|
||||
app.register_blueprint(wish_page)
|
||||
|
||||
# Register admin routes
|
||||
app.register_blueprint(admin_page)
|
||||
app.register_blueprint(admin_checkbox_page)
|
||||
app.register_blueprint(admin_database_page)
|
||||
app.register_blueprint(admin_image_page)
|
||||
app.register_blueprint(admin_instructions_page)
|
||||
app.register_blueprint(admin_retired_page)
|
||||
app.register_blueprint(admin_theme_page)
|
||||
|
||||
# An helper to make global variables available to the
|
||||
# request
|
||||
@app.before_request
|
||||
|
19
bricktracker/reload.py
Normal file
19
bricktracker/reload.py
Normal file
@ -0,0 +1,19 @@
|
||||
from .instructions_list import BrickInstructionsList
|
||||
from .retired_list import BrickRetiredList
|
||||
from .theme_list import BrickThemeList
|
||||
|
||||
|
||||
# Reload everything related to a database after an operation
|
||||
def reload() -> None:
|
||||
# Failsafe
|
||||
try:
|
||||
# Reload the instructions
|
||||
BrickInstructionsList(force=True)
|
||||
|
||||
# Reload retired sets
|
||||
BrickRetiredList(force=True)
|
||||
|
||||
# Reload themes
|
||||
BrickThemeList(force=True)
|
||||
except Exception:
|
||||
pass
|
@ -1,334 +0,0 @@
|
||||
from datetime import datetime
|
||||
import logging
|
||||
import os
|
||||
|
||||
from flask import (
|
||||
Blueprint,
|
||||
current_app,
|
||||
g,
|
||||
redirect,
|
||||
request,
|
||||
render_template,
|
||||
send_file,
|
||||
url_for,
|
||||
)
|
||||
from flask_login import login_required
|
||||
from werkzeug.wrappers.response import Response
|
||||
|
||||
from ..configuration_list import BrickConfigurationList
|
||||
from .exceptions import exception_handler
|
||||
from ..instructions_list import BrickInstructionsList
|
||||
from ..minifigure import BrickMinifigure
|
||||
from ..part import BrickPart
|
||||
from ..rebrickable_image import RebrickableImage
|
||||
from ..retired_list import BrickRetiredList
|
||||
from ..set import BrickSet
|
||||
from ..sql_counter import BrickCounter
|
||||
from ..sql_migration_list import BrickSQLMigrationList
|
||||
from ..sql import BrickSQL
|
||||
from ..theme_list import BrickThemeList
|
||||
from .upload import upload_helper
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
admin_page = Blueprint('admin', __name__, url_prefix='/admin')
|
||||
|
||||
|
||||
# Admin
|
||||
@admin_page.route('/', methods=['GET'])
|
||||
@login_required
|
||||
@exception_handler(__file__)
|
||||
def admin() -> str:
|
||||
database_counters: list[BrickCounter] = []
|
||||
database_exception: Exception | None = None
|
||||
database_upgrade_needed: bool = False
|
||||
database_version: int = -1
|
||||
nil_minifigure_name: str = ''
|
||||
nil_minifigure_url: str = ''
|
||||
nil_part_name: str = ''
|
||||
nil_part_url: str = ''
|
||||
|
||||
# This view needs to be protected against SQL errors
|
||||
try:
|
||||
database = BrickSQL(failsafe=True)
|
||||
database_upgrade_needed = database.upgrade_needed()
|
||||
database_version = database.version
|
||||
|
||||
if not database_upgrade_needed:
|
||||
database_counters = BrickSQL().count_records()
|
||||
except Exception as e:
|
||||
database_exception = e
|
||||
|
||||
# Warning
|
||||
logger.warning('A database exception occured while loading the admin page: {exception}'.format( # noqa: E501
|
||||
exception=str(e),
|
||||
))
|
||||
|
||||
nil_minifigure_name = RebrickableImage.nil_minifigure_name()
|
||||
nil_minifigure_url = RebrickableImage.static_url(
|
||||
nil_minifigure_name,
|
||||
'MINIFIGURES_FOLDER'
|
||||
)
|
||||
|
||||
nil_part_name = RebrickableImage.nil_name()
|
||||
nil_part_url = RebrickableImage.static_url(
|
||||
nil_part_name,
|
||||
'PARTS_FOLDER'
|
||||
)
|
||||
|
||||
open_image = request.args.get('open_image', None)
|
||||
open_instructions = request.args.get('open_instructions', None)
|
||||
open_logout = request.args.get('open_logout', None)
|
||||
open_retired = request.args.get('open_retired', None)
|
||||
open_theme = request.args.get('open_theme', None)
|
||||
|
||||
open_database = (
|
||||
open_image is None and
|
||||
open_instructions is None and
|
||||
open_logout is None and
|
||||
open_retired is None and
|
||||
open_theme is None
|
||||
)
|
||||
|
||||
return render_template(
|
||||
'admin.html',
|
||||
configuration=BrickConfigurationList.list(),
|
||||
database_counters=database_counters,
|
||||
database_error=request.args.get('error'),
|
||||
database_exception=database_exception,
|
||||
database_upgrade_needed=database_upgrade_needed,
|
||||
database_version=database_version,
|
||||
instructions=BrickInstructionsList(),
|
||||
nil_minifigure_name=nil_minifigure_name,
|
||||
nil_minifigure_url=nil_minifigure_url,
|
||||
nil_part_name=nil_part_name,
|
||||
nil_part_url=nil_part_url,
|
||||
open_database=open_database,
|
||||
open_image=open_image,
|
||||
open_instructions=open_instructions,
|
||||
open_logout=open_logout,
|
||||
open_retired=open_retired,
|
||||
open_theme=open_theme,
|
||||
retired=BrickRetiredList(),
|
||||
theme=BrickThemeList(),
|
||||
)
|
||||
|
||||
|
||||
# Delete the database
|
||||
@admin_page.route('/delete-database', methods=['GET'])
|
||||
@login_required
|
||||
@exception_handler(__file__)
|
||||
def delete_database() -> str:
|
||||
return render_template(
|
||||
'admin.html',
|
||||
delete_database=True,
|
||||
error=request.args.get('error')
|
||||
)
|
||||
|
||||
|
||||
# Actually delete the database
|
||||
@admin_page.route('/delete-database', methods=['POST'])
|
||||
@login_required
|
||||
@exception_handler(__file__, post_redirect='admin.delete_database')
|
||||
def do_delete_database() -> Response:
|
||||
BrickSQL.delete()
|
||||
|
||||
# Reload the instructions
|
||||
BrickInstructionsList(force=True)
|
||||
|
||||
return redirect(url_for('admin.admin'))
|
||||
|
||||
|
||||
# Download the database
|
||||
@admin_page.route('/download-database', methods=['GET'])
|
||||
@login_required
|
||||
@exception_handler(__file__)
|
||||
def download_database() -> Response:
|
||||
# Create a file name with a timestamp embedded
|
||||
name, extension = os.path.splitext(
|
||||
os.path.basename(current_app.config['DATABASE_PATH'])
|
||||
)
|
||||
|
||||
# Info
|
||||
logger.info('The database has been downloaded')
|
||||
|
||||
return send_file(
|
||||
current_app.config['DATABASE_PATH'],
|
||||
as_attachment=True,
|
||||
download_name='{name}-v{version}-{timestamp}{extension}'.format(
|
||||
name=name,
|
||||
version=BrickSQL(failsafe=True).version,
|
||||
timestamp=datetime.now().astimezone(g.timezone).strftime(
|
||||
current_app.config['DATABASE_TIMESTAMP_FORMAT']
|
||||
),
|
||||
extension=extension
|
||||
)
|
||||
)
|
||||
|
||||
|
||||
# Drop the database
|
||||
@admin_page.route('/drop-database', methods=['GET'])
|
||||
@login_required
|
||||
@exception_handler(__file__)
|
||||
def drop_database() -> str:
|
||||
return render_template(
|
||||
'admin.html',
|
||||
drop_database=True,
|
||||
error=request.args.get('error')
|
||||
)
|
||||
|
||||
|
||||
# Actually drop the database
|
||||
@admin_page.route('/drop-database', methods=['POST'])
|
||||
@login_required
|
||||
@exception_handler(__file__, post_redirect='admin.drop_database')
|
||||
def do_drop_database() -> Response:
|
||||
BrickSQL.drop()
|
||||
|
||||
# Reload the instructions
|
||||
BrickInstructionsList(force=True)
|
||||
|
||||
return redirect(url_for('admin.admin'))
|
||||
|
||||
|
||||
# Actually upgrade the database
|
||||
@admin_page.route('/upgrade-database', methods=['POST'])
|
||||
@login_required
|
||||
@exception_handler(__file__, post_redirect='admin.upgrade_database')
|
||||
def do_upgrade_database() -> Response:
|
||||
BrickSQL(failsafe=True).upgrade()
|
||||
|
||||
return redirect(url_for('admin.admin'))
|
||||
|
||||
|
||||
# Import a database
|
||||
@admin_page.route('/import-database', methods=['GET'])
|
||||
@login_required
|
||||
@exception_handler(__file__)
|
||||
def import_database() -> str:
|
||||
return render_template(
|
||||
'admin.html',
|
||||
import_database=True,
|
||||
error=request.args.get('error')
|
||||
)
|
||||
|
||||
|
||||
# Actually import a database
|
||||
@admin_page.route('/import-database', methods=['POST'])
|
||||
@login_required
|
||||
@exception_handler(__file__, post_redirect='admin.import_database')
|
||||
def do_import_database() -> Response:
|
||||
file = upload_helper(
|
||||
'database',
|
||||
'admin.import_database',
|
||||
extensions=['.db'],
|
||||
)
|
||||
|
||||
if isinstance(file, Response):
|
||||
return file
|
||||
|
||||
BrickSQL.upload(file)
|
||||
|
||||
# Reload the instructions
|
||||
BrickInstructionsList(force=True)
|
||||
|
||||
return redirect(url_for('admin.admin'))
|
||||
|
||||
|
||||
# Refresh the instructions cache
|
||||
@admin_page.route('/refresh-instructions', methods=['GET'])
|
||||
@login_required
|
||||
@exception_handler(__file__)
|
||||
def refresh_instructions() -> Response:
|
||||
BrickInstructionsList(force=True)
|
||||
|
||||
return redirect(url_for('admin.admin', open_instructions=True))
|
||||
|
||||
|
||||
# Refresh the retired sets cache
|
||||
@admin_page.route('/refresh-retired', methods=['GET'])
|
||||
@login_required
|
||||
@exception_handler(__file__)
|
||||
def refresh_retired() -> Response:
|
||||
BrickRetiredList(force=True)
|
||||
|
||||
return redirect(url_for('admin.admin', open_retired=True))
|
||||
|
||||
|
||||
# Refresh the themes cache
|
||||
@admin_page.route('/refresh-themes', methods=['GET'])
|
||||
@login_required
|
||||
@exception_handler(__file__)
|
||||
def refresh_themes() -> Response:
|
||||
BrickThemeList(force=True)
|
||||
|
||||
return redirect(url_for('admin.admin', open_theme=True))
|
||||
|
||||
|
||||
# Update the default images
|
||||
@admin_page.route('/update-image', methods=['GET'])
|
||||
@login_required
|
||||
@exception_handler(__file__)
|
||||
def update_image() -> Response:
|
||||
# Abusing the object to create a 'nil' minifigure
|
||||
RebrickableImage(
|
||||
BrickSet(),
|
||||
minifigure=BrickMinifigure(record={
|
||||
'set_img_url': None,
|
||||
})
|
||||
).download()
|
||||
|
||||
# Abusing the object to create a 'nil' part
|
||||
RebrickableImage(
|
||||
BrickSet(),
|
||||
part=BrickPart(record={
|
||||
'part_img_url': None,
|
||||
'part_img_url_id': None
|
||||
})
|
||||
).download()
|
||||
|
||||
return redirect(url_for('admin.admin', open_image=True))
|
||||
|
||||
|
||||
# Update the themes file
|
||||
@admin_page.route('/update-retired', methods=['GET'])
|
||||
@login_required
|
||||
@exception_handler(__file__)
|
||||
def update_retired() -> Response:
|
||||
BrickRetiredList().update()
|
||||
|
||||
BrickRetiredList(force=True)
|
||||
|
||||
return redirect(url_for('admin.admin', open_retired=True))
|
||||
|
||||
|
||||
# Update the themes file
|
||||
@admin_page.route('/update-themes', methods=['GET'])
|
||||
@login_required
|
||||
@exception_handler(__file__)
|
||||
def update_themes() -> Response:
|
||||
BrickThemeList().update()
|
||||
|
||||
BrickThemeList(force=True)
|
||||
|
||||
return redirect(url_for('admin.admin', open_theme=True))
|
||||
|
||||
|
||||
# Upgrade the database
|
||||
@admin_page.route('/upgrade-database', methods=['GET'])
|
||||
@login_required
|
||||
@exception_handler(__file__, post_redirect='admin.admin')
|
||||
def upgrade_database() -> str | Response:
|
||||
database = BrickSQL(failsafe=True)
|
||||
|
||||
if not database.upgrade_needed():
|
||||
return redirect(url_for('admin.admin'))
|
||||
|
||||
return render_template(
|
||||
'admin.html',
|
||||
upgrade_database=True,
|
||||
migrations=BrickSQLMigrationList().pending(
|
||||
database.version
|
||||
),
|
||||
error=request.args.get('error')
|
||||
)
|
0
bricktracker/views/admin/__init__.py
Normal file
0
bricktracker/views/admin/__init__.py
Normal file
104
bricktracker/views/admin/admin.py
Normal file
104
bricktracker/views/admin/admin.py
Normal file
@ -0,0 +1,104 @@
|
||||
import logging
|
||||
|
||||
from flask import Blueprint, request, render_template
|
||||
from flask_login import login_required
|
||||
|
||||
from ...configuration_list import BrickConfigurationList
|
||||
from ..exceptions import exception_handler
|
||||
from ...instructions_list import BrickInstructionsList
|
||||
from ...rebrickable_image import RebrickableImage
|
||||
from ...retired_list import BrickRetiredList
|
||||
from ...set_checkbox import BrickSetCheckbox
|
||||
from ...set_checkbox_list import BrickSetCheckboxList
|
||||
from ...sql_counter import BrickCounter
|
||||
from ...sql import BrickSQL
|
||||
from ...theme_list import BrickThemeList
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
admin_page = Blueprint('admin', __name__, url_prefix='/admin')
|
||||
|
||||
|
||||
# Admin
|
||||
@admin_page.route('/', methods=['GET'])
|
||||
@login_required
|
||||
@exception_handler(__file__)
|
||||
def admin() -> str:
|
||||
brickset_checkboxes: list[BrickSetCheckbox] = []
|
||||
database_counters: list[BrickCounter] = []
|
||||
database_exception: Exception | None = None
|
||||
database_upgrade_needed: bool = False
|
||||
database_version: int = -1
|
||||
nil_minifigure_name: str = ''
|
||||
nil_minifigure_url: str = ''
|
||||
nil_part_name: str = ''
|
||||
nil_part_url: str = ''
|
||||
|
||||
# This view needs to be protected against SQL errors
|
||||
try:
|
||||
database = BrickSQL(failsafe=True)
|
||||
database_upgrade_needed = database.upgrade_needed()
|
||||
database_version = database.version
|
||||
database_counters = BrickSQL().count_records()
|
||||
|
||||
brickset_checkboxes = BrickSetCheckboxList().list(all=True)
|
||||
except Exception as e:
|
||||
database_exception = e
|
||||
|
||||
# Warning
|
||||
logger.warning('A database exception occured while loading the admin page: {exception}'.format( # noqa: E501
|
||||
exception=str(e),
|
||||
))
|
||||
|
||||
nil_minifigure_name = RebrickableImage.nil_minifigure_name()
|
||||
nil_minifigure_url = RebrickableImage.static_url(
|
||||
nil_minifigure_name,
|
||||
'MINIFIGURES_FOLDER'
|
||||
)
|
||||
|
||||
nil_part_name = RebrickableImage.nil_name()
|
||||
nil_part_url = RebrickableImage.static_url(
|
||||
nil_part_name,
|
||||
'PARTS_FOLDER'
|
||||
)
|
||||
|
||||
open_checkbox = request.args.get('open_checkbox', None)
|
||||
open_image = request.args.get('open_image', None)
|
||||
open_instructions = request.args.get('open_instructions', None)
|
||||
open_logout = request.args.get('open_logout', None)
|
||||
open_retired = request.args.get('open_retired', None)
|
||||
open_theme = request.args.get('open_theme', None)
|
||||
|
||||
open_database = (
|
||||
open_checkbox is None and
|
||||
open_image is None and
|
||||
open_instructions is None and
|
||||
open_logout is None and
|
||||
open_retired is None and
|
||||
open_theme is None
|
||||
)
|
||||
|
||||
return render_template(
|
||||
'admin.html',
|
||||
configuration=BrickConfigurationList.list(),
|
||||
brickset_checkboxes=brickset_checkboxes,
|
||||
database_counters=database_counters,
|
||||
database_error=request.args.get('error'),
|
||||
database_exception=database_exception,
|
||||
database_upgrade_needed=database_upgrade_needed,
|
||||
database_version=database_version,
|
||||
instructions=BrickInstructionsList(),
|
||||
nil_minifigure_name=nil_minifigure_name,
|
||||
nil_minifigure_url=nil_minifigure_url,
|
||||
nil_part_name=nil_part_name,
|
||||
nil_part_url=nil_part_url,
|
||||
open_checkbox=open_checkbox,
|
||||
open_database=open_database,
|
||||
open_image=open_image,
|
||||
open_instructions=open_instructions,
|
||||
open_logout=open_logout,
|
||||
open_retired=open_retired,
|
||||
open_theme=open_theme,
|
||||
retired=BrickRetiredList(),
|
||||
theme=BrickThemeList(),
|
||||
)
|
170
bricktracker/views/admin/database.py
Normal file
170
bricktracker/views/admin/database.py
Normal file
@ -0,0 +1,170 @@
|
||||
from datetime import datetime
|
||||
import logging
|
||||
import os
|
||||
|
||||
from flask import (
|
||||
Blueprint,
|
||||
current_app,
|
||||
g,
|
||||
redirect,
|
||||
request,
|
||||
render_template,
|
||||
send_file,
|
||||
url_for,
|
||||
)
|
||||
from flask_login import login_required
|
||||
from werkzeug.wrappers.response import Response
|
||||
|
||||
from ..exceptions import exception_handler
|
||||
from ...reload import reload
|
||||
from ...sql_migration_list import BrickSQLMigrationList
|
||||
from ...sql import BrickSQL
|
||||
from ..upload import upload_helper
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
admin_database_page = Blueprint(
|
||||
'admin_database',
|
||||
__name__,
|
||||
url_prefix='/admin/database'
|
||||
)
|
||||
|
||||
|
||||
# Delete the database
|
||||
@admin_database_page.route('/delete', methods=['GET'])
|
||||
@login_required
|
||||
@exception_handler(__file__)
|
||||
def delete() -> str:
|
||||
return render_template(
|
||||
'admin.html',
|
||||
delete_database=True,
|
||||
error=request.args.get('error')
|
||||
)
|
||||
|
||||
|
||||
# Actually delete the database
|
||||
@admin_database_page.route('/delete', methods=['POST'])
|
||||
@login_required
|
||||
@exception_handler(__file__, post_redirect='admin_database.delete')
|
||||
def do_delete() -> Response:
|
||||
BrickSQL.delete()
|
||||
|
||||
reload()
|
||||
|
||||
return redirect(url_for('admin.admin'))
|
||||
|
||||
|
||||
# Download the database
|
||||
@admin_database_page.route('/download', methods=['GET'])
|
||||
@login_required
|
||||
@exception_handler(__file__)
|
||||
def download() -> Response:
|
||||
# Create a file name with a timestamp embedded
|
||||
name, extension = os.path.splitext(
|
||||
os.path.basename(current_app.config['DATABASE_PATH'])
|
||||
)
|
||||
|
||||
# Info
|
||||
logger.info('The database has been downloaded')
|
||||
|
||||
return send_file(
|
||||
current_app.config['DATABASE_PATH'],
|
||||
as_attachment=True,
|
||||
download_name='{name}-v{version}-{timestamp}{extension}'.format(
|
||||
name=name,
|
||||
version=BrickSQL(failsafe=True).version,
|
||||
timestamp=datetime.now().astimezone(g.timezone).strftime(
|
||||
current_app.config['DATABASE_TIMESTAMP_FORMAT']
|
||||
),
|
||||
extension=extension
|
||||
)
|
||||
)
|
||||
|
||||
|
||||
# Drop the database
|
||||
@admin_database_page.route('/drop', methods=['GET'])
|
||||
@login_required
|
||||
@exception_handler(__file__)
|
||||
def drop() -> str:
|
||||
return render_template(
|
||||
'admin.html',
|
||||
drop_database=True,
|
||||
error=request.args.get('error')
|
||||
)
|
||||
|
||||
|
||||
# Actually drop the database
|
||||
@admin_database_page.route('/drop', methods=['POST'])
|
||||
@login_required
|
||||
@exception_handler(__file__, post_redirect='admin_database.drop')
|
||||
def do_drop() -> Response:
|
||||
BrickSQL.drop()
|
||||
|
||||
reload()
|
||||
|
||||
return redirect(url_for('admin.admin'))
|
||||
|
||||
|
||||
# Actually upgrade the database
|
||||
@admin_database_page.route('/upgrade', methods=['POST'])
|
||||
@login_required
|
||||
@exception_handler(__file__, post_redirect='admin_database.upgrade')
|
||||
def do_upgrade() -> Response:
|
||||
BrickSQL(failsafe=True).upgrade()
|
||||
|
||||
reload()
|
||||
|
||||
return redirect(url_for('admin.admin'))
|
||||
|
||||
|
||||
# Import a database
|
||||
@admin_database_page.route('/import', methods=['GET'])
|
||||
@login_required
|
||||
@exception_handler(__file__)
|
||||
def upload() -> str:
|
||||
return render_template(
|
||||
'admin.html',
|
||||
import_database=True,
|
||||
error=request.args.get('error')
|
||||
)
|
||||
|
||||
|
||||
# Actually import a database
|
||||
@admin_database_page.route('/import', methods=['POST'])
|
||||
@login_required
|
||||
@exception_handler(__file__, post_redirect='admin_database.upload')
|
||||
def do_upload() -> Response:
|
||||
file = upload_helper(
|
||||
'database',
|
||||
'admin_database.upload',
|
||||
extensions=['.db'],
|
||||
)
|
||||
|
||||
if isinstance(file, Response):
|
||||
return file
|
||||
|
||||
BrickSQL.upload(file)
|
||||
|
||||
reload()
|
||||
|
||||
return redirect(url_for('admin.admin'))
|
||||
|
||||
|
||||
# Upgrade the database
|
||||
@admin_database_page.route('/upgrade', methods=['GET'])
|
||||
@login_required
|
||||
@exception_handler(__file__, post_redirect='admin.admin')
|
||||
def upgrade() -> str | Response:
|
||||
database = BrickSQL(failsafe=True)
|
||||
|
||||
if not database.upgrade_needed():
|
||||
return redirect(url_for('admin.admin'))
|
||||
|
||||
return render_template(
|
||||
'admin.html',
|
||||
upgrade_database=True,
|
||||
migrations=BrickSQLMigrationList().pending(
|
||||
database.version
|
||||
),
|
||||
error=request.args.get('error')
|
||||
)
|
44
bricktracker/views/admin/image.py
Normal file
44
bricktracker/views/admin/image.py
Normal file
@ -0,0 +1,44 @@
|
||||
import logging
|
||||
|
||||
from flask import Blueprint, redirect, url_for
|
||||
from flask_login import login_required
|
||||
from werkzeug.wrappers.response import Response
|
||||
|
||||
from ..exceptions import exception_handler
|
||||
from ...minifigure import BrickMinifigure
|
||||
from ...part import BrickPart
|
||||
from ...rebrickable_image import RebrickableImage
|
||||
from ...set import BrickSet
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
admin_image_page = Blueprint(
|
||||
'admin_image',
|
||||
__name__,
|
||||
url_prefix='/admin/image'
|
||||
)
|
||||
|
||||
|
||||
# Update the default images
|
||||
@admin_image_page.route('/update', methods=['GET'])
|
||||
@login_required
|
||||
@exception_handler(__file__)
|
||||
def update() -> Response:
|
||||
# Abusing the object to create a 'nil' minifigure
|
||||
RebrickableImage(
|
||||
BrickSet(),
|
||||
minifigure=BrickMinifigure(record={
|
||||
'set_img_url': None,
|
||||
})
|
||||
).download()
|
||||
|
||||
# Abusing the object to create a 'nil' part
|
||||
RebrickableImage(
|
||||
BrickSet(),
|
||||
part=BrickPart(record={
|
||||
'part_img_url': None,
|
||||
'part_img_url_id': None
|
||||
})
|
||||
).download()
|
||||
|
||||
return redirect(url_for('admin.admin', open_image=True))
|
26
bricktracker/views/admin/instructions.py
Normal file
26
bricktracker/views/admin/instructions.py
Normal file
@ -0,0 +1,26 @@
|
||||
import logging
|
||||
|
||||
from flask import Blueprint, redirect, url_for
|
||||
from flask_login import login_required
|
||||
from werkzeug.wrappers.response import Response
|
||||
|
||||
from ..exceptions import exception_handler
|
||||
from ...instructions_list import BrickInstructionsList
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
admin_instructions_page = Blueprint(
|
||||
'admin_instructions',
|
||||
__name__,
|
||||
url_prefix='/admin/instructions'
|
||||
)
|
||||
|
||||
|
||||
# Refresh the instructions cache
|
||||
@admin_instructions_page.route('/refresh', methods=['GET'])
|
||||
@login_required
|
||||
@exception_handler(__file__)
|
||||
def refresh() -> Response:
|
||||
BrickInstructionsList(force=True)
|
||||
|
||||
return redirect(url_for('admin.admin', open_instructions=True))
|
38
bricktracker/views/admin/retired.py
Normal file
38
bricktracker/views/admin/retired.py
Normal file
@ -0,0 +1,38 @@
|
||||
import logging
|
||||
|
||||
from flask import Blueprint, redirect, url_for
|
||||
from flask_login import login_required
|
||||
from werkzeug.wrappers.response import Response
|
||||
|
||||
from ..exceptions import exception_handler
|
||||
from ...retired_list import BrickRetiredList
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
admin_retired_page = Blueprint(
|
||||
'admin_retired',
|
||||
__name__,
|
||||
url_prefix='/admin/retired'
|
||||
)
|
||||
|
||||
|
||||
# Refresh the retired sets cache
|
||||
@admin_retired_page.route('/refresh', methods=['GET'])
|
||||
@login_required
|
||||
@exception_handler(__file__)
|
||||
def refresh() -> Response:
|
||||
BrickRetiredList(force=True)
|
||||
|
||||
return redirect(url_for('admin.admin', open_retired=True))
|
||||
|
||||
|
||||
# Update the retired sets
|
||||
@admin_retired_page.route('/update', methods=['GET'])
|
||||
@login_required
|
||||
@exception_handler(__file__)
|
||||
def update() -> Response:
|
||||
BrickRetiredList().update()
|
||||
|
||||
BrickRetiredList(force=True)
|
||||
|
||||
return redirect(url_for('admin.admin', open_retired=True))
|
38
bricktracker/views/admin/theme.py
Normal file
38
bricktracker/views/admin/theme.py
Normal file
@ -0,0 +1,38 @@
|
||||
import logging
|
||||
|
||||
from flask import Blueprint, redirect, url_for
|
||||
from flask_login import login_required
|
||||
from werkzeug.wrappers.response import Response
|
||||
|
||||
from ..exceptions import exception_handler
|
||||
from ...theme_list import BrickThemeList
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
admin_theme_page = Blueprint(
|
||||
'admin_theme',
|
||||
__name__,
|
||||
url_prefix='/admin/theme'
|
||||
)
|
||||
|
||||
|
||||
# Refresh the themes cache
|
||||
@admin_theme_page.route('/refresh', methods=['GET'])
|
||||
@login_required
|
||||
@exception_handler(__file__)
|
||||
def refresh() -> Response:
|
||||
BrickThemeList(force=True)
|
||||
|
||||
return redirect(url_for('admin.admin', open_theme=True))
|
||||
|
||||
|
||||
# Update the themes file
|
||||
@admin_theme_page.route('/update', methods=['GET'])
|
||||
@login_required
|
||||
@exception_handler(__file__)
|
||||
def update() -> Response:
|
||||
BrickThemeList().update()
|
||||
|
||||
BrickThemeList(force=True)
|
||||
|
||||
return redirect(url_for('admin.admin', open_theme=True))
|
@ -9,13 +9,13 @@
|
||||
<p>Your database needs to be upgraded.</p>
|
||||
<hr>
|
||||
<div class="text-end">
|
||||
<a href="{{ url_for('admin.upgrade_database') }}" class="btn btn-warning" role="button"><i class="ri-arrow-up-double-line"></i> Upgrade the database</a>
|
||||
<a href="{{ url_for('admin_database.upgrade') }}" class="btn btn-warning" role="button"><i class="ri-arrow-up-double-line"></i> Upgrade the database</a>
|
||||
</div>
|
||||
</div>
|
||||
{% endif %}
|
||||
<p>The database file is: <code>{{ config['DATABASE_PATH'] }}</code> at version <span class="badge rounded-pill text-bg-light border fw-normal"><i class="ri-hashtag"></i>{{ database_version }}</span></p>
|
||||
<p>
|
||||
<a href="{{ url_for('admin.download_database') }}" class="btn btn-primary" role="button"><i class="ri-download-line"></i> Download the database file</a>
|
||||
<a href="{{ url_for('admin_database.download') }}" class="btn btn-primary" role="button"><i class="ri-download-line"></i> Download the database file</a>
|
||||
</p>
|
||||
{% if database_counters %}
|
||||
<h5 class="border-bottom">Records</h5>
|
||||
@ -37,7 +37,7 @@
|
||||
|
||||
{{ accordion.header('Database danger zone', 'database-danger', 'admin', danger=true, class='text-end') }}
|
||||
{% if error %}<div class="alert alert-danger text-start" role="alert"><strong>Error:</strong> {{ error }}.</div>{% endif %}
|
||||
<a href="{{ url_for('admin.import_database') }}" class="btn btn-warning" role="button"><i class="ri-upload-line"></i> Import a database file</a>
|
||||
<a href="{{ url_for('admin.drop_database') }}" class="btn btn-danger" role="button"><i class="ri-close-line"></i> Drop the database</a>
|
||||
<a href="{{ url_for('admin.delete_database') }}" class="btn btn-danger" role="button"><i class="ri-delete-bin-2-line"></i> Delete the database file</a>
|
||||
<a href="{{ url_for('admin_database.upload') }}" class="btn btn-warning" role="button"><i class="ri-upload-line"></i> Import a database file</a>
|
||||
<a href="{{ url_for('admin_database.drop') }}" class="btn btn-danger" role="button"><i class="ri-close-line"></i> Drop the database</a>
|
||||
<a href="{{ url_for('admin_database.delete') }}" class="btn btn-danger" role="button"><i class="ri-delete-bin-2-line"></i> Delete the database file</a>
|
||||
{{ accordion.footer() }}
|
||||
|
@ -1,7 +1,7 @@
|
||||
{% import 'macro/accordion.html' as accordion %}
|
||||
|
||||
{{ accordion.header('Database danger zone', 'database-danger', 'admin', expanded=true, danger=true, class='text-end') }}
|
||||
<form action="{{ url_for('admin.do_delete_database') }}" method="post">
|
||||
<form action="{{ url_for('admin_database.do_delete') }}" method="post">
|
||||
{% if error %}<div class="alert alert-danger text-start" role="alert"><strong>Error:</strong> {{ error }}.</div>{% endif %}
|
||||
<div class="alert alert-danger text-center" role="alert">You are about to <strong>delete the database file</strong>. This action is irreversible.</div>
|
||||
<a class="btn btn-danger" href="{{ url_for('admin.admin') }}" role="button"><i class="ri-arrow-left-long-line"></i> Back to the admin</a>
|
||||
|
@ -1,7 +1,7 @@
|
||||
{% import 'macro/accordion.html' as accordion %}
|
||||
|
||||
{{ accordion.header('Database danger zone', 'database-danger', 'admin', expanded=true, danger=true, class='text-end') }}
|
||||
<form action="{{ url_for('admin.do_drop_database') }}" method="post">
|
||||
<form action="{{ url_for('admin_database.do_drop') }}" method="post">
|
||||
{% if error %}<div class="alert alert-danger text-start" role="alert"><strong>Error:</strong> {{ error }}.</div>{% endif %}
|
||||
<div class="alert alert-danger text-center" role="alert">You are about to <strong>drop all the tables from the database</strong>. This action is irreversible.</div>
|
||||
<a class="btn btn-danger" href="{{ url_for('admin.admin') }}" role="button"><i class="ri-arrow-left-long-line"></i> Back to the admin</a>
|
||||
|
@ -1,7 +1,7 @@
|
||||
{% import 'macro/accordion.html' as accordion %}
|
||||
|
||||
{{ accordion.header('Database danger zone', 'database-danger', 'admin', expanded=true, danger=true) }}
|
||||
<form action="{{ url_for('admin.do_import_database') }}" method="post" enctype="multipart/form-data">
|
||||
<form action="{{ url_for('admin_database.do_upload') }}" method="post" enctype="multipart/form-data">
|
||||
{% if error %}<div class="alert alert-danger text-start" role="alert"><strong>Error:</strong> {{ error }}.</div>{% endif %}
|
||||
<div class="alert alert-warning text-center" role="alert">You are about to <strong>import a database file</strong>. This will replace the <strong>whole content</strong> of the database. This action is irreversible.</div>
|
||||
<div class="mb-3">
|
||||
|
@ -1,7 +1,7 @@
|
||||
{% import 'macro/accordion.html' as accordion %}
|
||||
|
||||
{{ accordion.header('Database', 'database', 'admin', expanded=true, icon='database-2-line') }}
|
||||
<form action="{{ url_for('admin.do_upgrade_database') }}" method="post">
|
||||
<form action="{{ url_for('admin_database.do_upgrade') }}" method="post">
|
||||
{% if error %}<div class="alert alert-danger text-start" role="alert"><strong>Error:</strong> {{ error }}.</div>{% endif %}
|
||||
<div class="alert alert-warning text-center" role="alert">
|
||||
You are about to <strong>upgrade your database file</strong>. This action is irreversible.<br>
|
||||
@ -22,7 +22,7 @@
|
||||
</ul>
|
||||
<div class="text-end">
|
||||
<a class="btn btn-danger" href="{{ url_for('admin.admin') }}" role="button"><i class="ri-arrow-left-long-line"></i> Back to the admin</a>
|
||||
<a href="{{ url_for('admin.download_database') }}" class="btn btn-primary" role="button"><i class="ri-download-line"></i> Download the database file</a>
|
||||
<a href="{{ url_for('admin_database.download') }}" class="btn btn-primary" role="button"><i class="ri-download-line"></i> Download the database file</a>
|
||||
<button type="submit" class="btn btn-warning"><i class="ri-arrow-up-double-line"></i> Upgrade the database</button>
|
||||
</div>
|
||||
</form>
|
||||
|
@ -9,6 +9,6 @@
|
||||
<img class="table-img border mx-1" src="{{ nil_part_url }}" alt="{{ nil_part_name }}">
|
||||
</div>
|
||||
<p>
|
||||
<a href="{{ url_for('admin.update_image') }}" class="btn btn-primary" role="button"><i class="ri-download-line"></i> Update the images</a>
|
||||
<a href="{{ url_for('admin_image.update') }}" class="btn btn-primary" role="button"><i class="ri-download-line"></i> Update the images</a>
|
||||
</p>
|
||||
{{ accordion.footer() }}
|
||||
|
@ -27,6 +27,6 @@
|
||||
</p>
|
||||
<h5 class="border-bottom">Refresh</h5>
|
||||
<p>
|
||||
<a href="{{ url_for('admin.refresh_instructions') }}" class="btn btn-primary" role="button"><i class="ri-refresh-line"></i> Refresh the instructions cache</a>
|
||||
<a href="{{ url_for('admin_instructions.refresh') }}" class="btn btn-primary" role="button"><i class="ri-refresh-line"></i> Refresh the instructions cache</a>
|
||||
</p>
|
||||
{{ accordion.footer() }}
|
||||
|
@ -20,7 +20,7 @@
|
||||
</p>
|
||||
<h5 class="border-bottom">Refresh</h5>
|
||||
<p>
|
||||
<a href="{{ url_for('admin.refresh_retired') }}" class="btn btn-primary" role="button"><i class="ri-refresh-line"></i> Refresh the retired sets cache</a>
|
||||
<a href="{{ url_for('admin.update_retired') }}" class="btn btn-primary" role="button"><i class="ri-download-line"></i> Update the retired sets file</a>
|
||||
<a href="{{ url_for('admin_retired.refresh') }}" class="btn btn-primary" role="button"><i class="ri-refresh-line"></i> Refresh the retired sets cache</a>
|
||||
<a href="{{ url_for('admin_retired.update') }}" class="btn btn-primary" role="button"><i class="ri-download-line"></i> Update the retired sets file</a>
|
||||
</p>
|
||||
{{ accordion.footer() }}
|
||||
|
@ -20,7 +20,7 @@
|
||||
</p>
|
||||
<h5 class="border-bottom">Refresh</h5>
|
||||
<p>
|
||||
<a href="{{ url_for('admin.refresh_themes') }}" class="btn btn-primary" role="button"><i class="ri-refresh-line"></i> Refresh the themes cache</a>
|
||||
<a href="{{ url_for('admin.update_themes') }}" class="btn btn-primary" role="button"><i class="ri-download-line"></i> Update the themes file</a>
|
||||
<a href="{{ url_for('admin_theme.refresh') }}" class="btn btn-primary" role="button"><i class="ri-refresh-line"></i> Refresh the themes cache</a>
|
||||
<a href="{{ url_for('admin_theme.update') }}" class="btn btn-primary" role="button"><i class="ri-download-line"></i> Update the themes file</a>
|
||||
</p>
|
||||
{{ accordion.footer() }}
|
||||
|
Loading…
Reference in New Issue
Block a user