Files
profilarr/backend/app/settings/__init__.py
Samuel Chau 5281752269 feat: dynamic language score (#207)
- add database setting for language score on imports
- add settings container on general tab to let user update the value
- improved styling of general settings page to be more like media management page
2025-06-16 11:46:12 +09:30

159 lines
5.6 KiB
Python

# backend/app/settings/__init__.py
from flask import Blueprint, jsonify, request, session
from werkzeug.security import generate_password_hash, check_password_hash
import secrets
from ..db import get_db
from ..db.queries.settings import get_language_import_score, update_language_import_score
import logging
logger = logging.getLogger(__name__)
bp = Blueprint('settings', __name__)
@bp.route('/general', methods=['GET'])
def get_general_settings():
db = get_db()
try:
user = db.execute('SELECT username, api_key FROM auth').fetchone()
if not user:
logger.error('No user found in auth table')
return jsonify({'error': 'No user configuration found'}), 500
return jsonify({
'username': user['username'],
'api_key': user['api_key']
})
except Exception as e:
logger.error(f'Error fetching general settings: {str(e)}')
return jsonify({'error': 'Failed to fetch settings'}), 500
@bp.route('/username', methods=['PUT'])
def update_username():
db = get_db()
data = request.get_json()
new_username = data.get('username')
current_password = data.get('current_password')
if not new_username or not current_password:
return jsonify({'error':
'Username and current password are required'}), 400
try:
# Verify current password
user = db.execute('SELECT password_hash FROM auth').fetchone()
if not check_password_hash(user['password_hash'], current_password):
logger.warning('Failed username change - invalid password')
return jsonify({'error': 'Invalid password'}), 401
db.execute('UPDATE auth SET username = ?', (new_username, ))
db.commit()
logger.info(f'Username updated to: {new_username}')
return jsonify({'message': 'Username updated successfully'})
except Exception as e:
logger.error(f'Failed to update username: {str(e)}')
return jsonify({'error': 'Failed to update username'}), 500
@bp.route('/password', methods=['PUT'])
def update_password():
db = get_db()
data = request.get_json()
current_password = data.get('current_password')
new_password = data.get('new_password')
if not current_password or not new_password:
return jsonify({'error':
'Current and new passwords are required'}), 400
try:
# Verify current password
user = db.execute(
'SELECT password_hash, session_id FROM auth').fetchone()
if not check_password_hash(user['password_hash'], current_password):
logger.warning('Failed password change - invalid current password')
return jsonify({'error': 'Invalid current password'}), 401
# Update password and generate a new session ID
password_hash = generate_password_hash(new_password)
new_session_id = secrets.token_urlsafe(32)
db.execute('UPDATE auth SET password_hash = ?, session_id = ?',
(password_hash, new_session_id))
db.commit()
# Clear the current session to force re-login
session.clear()
logger.info('Password updated successfully')
return jsonify({
'message': 'Password updated successfully. Please log in again.',
'requireRelogin': True
})
except Exception as e:
logger.error(f'Failed to update password: {str(e)}')
return jsonify({'error': 'Failed to update password'}), 500
@bp.route('/api-key', methods=['POST'])
def reset_api_key():
db = get_db()
data = request.get_json()
current_password = data.get('current_password')
if not current_password:
return jsonify({'error': 'Current password is required'}), 400
try:
# Verify current password
user = db.execute('SELECT password_hash FROM auth').fetchone()
if not check_password_hash(user['password_hash'], current_password):
logger.warning('Failed API key reset - invalid password')
return jsonify({'error': 'Invalid password'}), 401
# Generate and save new API key
new_api_key = secrets.token_urlsafe(32)
db.execute('UPDATE auth SET api_key = ?', (new_api_key, ))
db.commit()
logger.info('API key reset successfully')
return jsonify({
'message': 'API key reset successfully',
'api_key': new_api_key
})
except Exception as e:
logger.error(f'Failed to reset API key: {str(e)}')
return jsonify({'error': 'Failed to reset API key'}), 500
@bp.route('/language-import-score', methods=['GET'])
def get_language_import_score_route():
try:
score = get_language_import_score()
return jsonify({'score': score})
except Exception as e:
logger.error(f'Failed to get language import score: {str(e)}')
return jsonify({'error': 'Failed to get language import score'}), 500
@bp.route('/language-import-score', methods=['PUT'])
def update_language_import_score_route():
data = request.get_json()
score = data.get('score')
if score is None:
return jsonify({'error': 'Score is required'}), 400
try:
score = int(score)
except (ValueError, TypeError):
return jsonify({'error': 'Score must be an integer'}), 400
try:
update_language_import_score(score)
return jsonify({'message': 'Language import score updated successfully'})
except Exception as e:
logger.error(f'Failed to update language import score: {str(e)}')
return jsonify({'error': 'Failed to update language import score'}), 500