0c27d7ac86
- Implemented `excel_export.py` for generating library item exports in Excel format. - Created `pdf_export.py` for generating audit reports compliant with DIN 5008 standards, including detailed event tables and signature blocks. - Developed `generate_user.py` for interactive user creation with validation for usernames and passwords. - Introduced `module_registry.py` for managing module states and path matching. - Added a basic `__init__.py` in the `terminplaner` module for initialization.
925 lines
27 KiB
Python
Executable File
925 lines
27 KiB
Python
Executable File
"""
|
|
Module for managing user accounts and authentication.
|
|
Provides methods for creating, validating, and retrieving user information.
|
|
"""
|
|
'''
|
|
Copyright 2025-2026 AIIrondev
|
|
|
|
Licensed under the Inventarsystem EULA (Endbenutzer-Lizenzvertrag).
|
|
See Legal/LICENSE for the full license text.
|
|
Unauthorized commercial use, SaaS hosting, or removal of branding is prohibited.
|
|
For commercial licensing inquiries: https://github.com/AIIrondev
|
|
'''
|
|
import hashlib
|
|
import copy
|
|
import logging
|
|
import re
|
|
import secrets
|
|
import string
|
|
from bson.objectid import ObjectId
|
|
import Web.modules.database.settings as cfg
|
|
from Web.modules.database.settings import MongoClient
|
|
|
|
logger = logging.getLogger('app')
|
|
logger.setLevel(logging.DEBUG)
|
|
logger.propagate = True
|
|
|
|
|
|
def normalize_student_card_id(card_id):
|
|
"""Normalize student card IDs for reliable lookup."""
|
|
if card_id is None:
|
|
return ''
|
|
return str(card_id).strip().upper()
|
|
|
|
|
|
def _clean_name_fragment(value):
|
|
cleaned = re.sub(r'[^A-Za-zÄÖÜäöüß]', '', str(value or '').strip())
|
|
if not cleaned:
|
|
return ''
|
|
replacements = {
|
|
'ä': 'ae',
|
|
'ö': 'oe',
|
|
'ü': 'ue',
|
|
'ß': 'ss',
|
|
'Ä': 'Ae',
|
|
'Ö': 'Oe',
|
|
'Ü': 'Ue',
|
|
}
|
|
for old_char, new_char in replacements.items():
|
|
cleaned = cleaned.replace(old_char, new_char)
|
|
return cleaned
|
|
|
|
|
|
def _get_tenant_db(client):
|
|
"""Return the current tenant database for the request, or fall back to default."""
|
|
try:
|
|
from tenant import get_tenant_db
|
|
return get_tenant_db(client)
|
|
except Exception:
|
|
return client[cfg.MONGODB_DB]
|
|
|
|
|
|
def build_name_synonym(first_name, last_name=''):
|
|
"""Build a deterministic, non-personalized short alias from 2 letters each."""
|
|
first = _clean_name_fragment(first_name)
|
|
last = _clean_name_fragment(last_name)
|
|
|
|
if first and last:
|
|
return (first[:2] + last[:2]).title()
|
|
|
|
combined = (first + last)
|
|
if not combined:
|
|
return 'User'
|
|
return combined[:4].title()
|
|
|
|
|
|
def build_username_from_name(first_name, last_name=''):
|
|
"""
|
|
Build a deterministic username abbreviation from first and last name.
|
|
Uses 2 letters from each name and stores it lowercase.
|
|
|
|
Args:
|
|
first_name (str): First name
|
|
last_name (str): Last name (optional)
|
|
|
|
Returns:
|
|
str: Generated username
|
|
"""
|
|
alias = build_name_synonym(first_name, last_name)
|
|
return alias.lower()
|
|
|
|
|
|
def build_unique_username_from_name(first_name, last_name=''):
|
|
"""
|
|
Build a unique username from the first 2 letters of the first name and
|
|
the first 2 letters of the last name.
|
|
"""
|
|
first = _clean_name_fragment(first_name)
|
|
last = _clean_name_fragment(last_name)
|
|
base_username = (first[:2] + last[:2]).lower()
|
|
|
|
if not base_username:
|
|
base_username = 'user'
|
|
|
|
if not get_user(base_username):
|
|
return base_username
|
|
|
|
suffix = 2
|
|
while get_user(f"{base_username}{suffix}"):
|
|
suffix += 1
|
|
return f"{base_username}{suffix}"
|
|
|
|
|
|
ACTION_PERMISSION_KEYS = (
|
|
'can_borrow',
|
|
'can_insert',
|
|
'can_edit',
|
|
'can_delete',
|
|
'can_manage_users',
|
|
'can_manage_settings',
|
|
'can_view_logs',
|
|
)
|
|
|
|
DEFAULT_ACTION_PERMISSIONS = {
|
|
'can_borrow': True,
|
|
'can_insert': False,
|
|
'can_edit': False,
|
|
'can_delete': False,
|
|
'can_manage_users': False,
|
|
'can_manage_settings': False,
|
|
'can_view_logs': False,
|
|
}
|
|
|
|
DEFAULT_PAGE_PERMISSIONS = {
|
|
'home': True,
|
|
'tutorial_page': True,
|
|
'my_borrowed_items': True,
|
|
'notifications_view': True,
|
|
'impressum': True,
|
|
'license': True,
|
|
'library_view': True,
|
|
'terminplan': True,
|
|
'home_admin': False,
|
|
'upload_admin': False,
|
|
'library_admin': False,
|
|
'admin_borrowings': False,
|
|
'library_loans_admin': False,
|
|
'admin_damaged_items': False,
|
|
'admin_audit_dashboard': False,
|
|
'logs': False,
|
|
'user_del': False,
|
|
'register': False,
|
|
'manage_filters': False,
|
|
'manage_locations': False,
|
|
}
|
|
|
|
PERMISSION_PRESETS = {
|
|
'standard_user': {
|
|
'label': 'Standard (Ausleihe)',
|
|
'actions': {
|
|
'can_borrow': True,
|
|
},
|
|
'pages': {
|
|
'home': True,
|
|
'tutorial_page': True,
|
|
'my_borrowed_items': True,
|
|
'notifications_view': True,
|
|
'impressum': True,
|
|
'license': True,
|
|
'library_view': True,
|
|
'terminplan': True,
|
|
},
|
|
},
|
|
'editor': {
|
|
'label': 'Editor (Einfügen/Bearbeiten)',
|
|
'actions': {
|
|
'can_borrow': True,
|
|
'can_insert': True,
|
|
'can_edit': True,
|
|
},
|
|
'pages': {
|
|
'home': True,
|
|
'tutorial_page': True,
|
|
'my_borrowed_items': True,
|
|
'notifications_view': True,
|
|
'impressum': True,
|
|
'license': True,
|
|
'library_view': True,
|
|
'terminplan': True,
|
|
'upload_admin': True,
|
|
'library_admin': True,
|
|
},
|
|
},
|
|
'manager': {
|
|
'label': 'Manager (inkl. Löschen)',
|
|
'actions': {
|
|
'can_borrow': True,
|
|
'can_insert': True,
|
|
'can_edit': True,
|
|
'can_delete': True,
|
|
'can_manage_settings': True,
|
|
'can_view_logs': True,
|
|
},
|
|
'pages': {
|
|
'home': True,
|
|
'tutorial_page': True,
|
|
'my_borrowed_items': True,
|
|
'notifications_view': True,
|
|
'impressum': True,
|
|
'license': True,
|
|
'library_view': True,
|
|
'terminplan': True,
|
|
'home_admin': True,
|
|
'upload_admin': True,
|
|
'library_admin': True,
|
|
'admin_borrowings': True,
|
|
'library_loans_admin': True,
|
|
'admin_damaged_items': True,
|
|
'admin_audit_dashboard': True,
|
|
'logs': True,
|
|
'manage_filters': True,
|
|
'manage_locations': True,
|
|
},
|
|
},
|
|
'full_access': {
|
|
'label': 'Vollzugriff',
|
|
'actions': {
|
|
'can_borrow': True,
|
|
'can_insert': True,
|
|
'can_edit': True,
|
|
'can_delete': True,
|
|
'can_manage_users': True,
|
|
'can_manage_settings': True,
|
|
'can_view_logs': True,
|
|
},
|
|
'pages': {
|
|
'home': True,
|
|
'tutorial_page': True,
|
|
'my_borrowed_items': True,
|
|
'notifications_view': True,
|
|
'impressum': True,
|
|
'license': True,
|
|
'library_view': True,
|
|
'terminplan': True,
|
|
'home_admin': True,
|
|
'upload_admin': True,
|
|
'library_admin': True,
|
|
'admin_borrowings': True,
|
|
'library_loans_admin': True,
|
|
'admin_damaged_items': True,
|
|
'admin_audit_dashboard': True,
|
|
'logs': True,
|
|
'user_del': True,
|
|
'register': True,
|
|
'manage_filters': True,
|
|
'manage_locations': True,
|
|
},
|
|
},
|
|
}
|
|
|
|
|
|
def _normalize_bool_map(source, defaults):
|
|
result = dict(defaults)
|
|
if isinstance(source, dict):
|
|
for key, value in source.items():
|
|
result[str(key)] = bool(value)
|
|
return result
|
|
|
|
|
|
def get_permission_preset_definitions():
|
|
return copy.deepcopy(PERMISSION_PRESETS)
|
|
|
|
|
|
def build_default_permission_payload(preset_key='standard_user'):
|
|
selected_key = preset_key if preset_key in PERMISSION_PRESETS else 'standard_user'
|
|
preset = PERMISSION_PRESETS.get(selected_key, {})
|
|
action_defaults = _normalize_bool_map(preset.get('actions', {}), DEFAULT_ACTION_PERMISSIONS)
|
|
page_defaults = _normalize_bool_map(preset.get('pages', {}), DEFAULT_PAGE_PERMISSIONS)
|
|
return {
|
|
'preset': selected_key,
|
|
'actions': action_defaults,
|
|
'pages': page_defaults,
|
|
}
|
|
|
|
|
|
def get_effective_permissions(username):
|
|
user = get_user(username)
|
|
if not user:
|
|
return build_default_permission_payload('standard_user')
|
|
|
|
# Admin users always have full access, independent of custom presets.
|
|
if bool(user.get('Admin', False)):
|
|
return build_default_permission_payload('full_access')
|
|
|
|
preset_key = user.get('PermissionPreset') or 'standard_user'
|
|
payload = build_default_permission_payload(preset_key)
|
|
payload['actions'] = _normalize_bool_map(user.get('ActionPermissions', {}), payload['actions'])
|
|
payload['pages'] = _normalize_bool_map(user.get('PagePermissions', {}), payload['pages'])
|
|
return payload
|
|
|
|
|
|
def update_user_permissions(username, preset_key, action_permissions=None, page_permissions=None):
|
|
selected_key = preset_key if preset_key in PERMISSION_PRESETS else 'standard_user'
|
|
payload = build_default_permission_payload(selected_key)
|
|
|
|
if isinstance(action_permissions, dict):
|
|
for key, value in action_permissions.items():
|
|
payload['actions'][str(key)] = bool(value)
|
|
|
|
if isinstance(page_permissions, dict):
|
|
for key, value in page_permissions.items():
|
|
payload['pages'][str(key)] = bool(value)
|
|
|
|
update_data = {
|
|
'PermissionPreset': payload['preset'],
|
|
'ActionPermissions': payload['actions'],
|
|
'PagePermissions': payload['pages'],
|
|
}
|
|
|
|
client = MongoClient(cfg.MONGODB_HOST, cfg.MONGODB_PORT)
|
|
db = _get_tenant_db(client)
|
|
users = db['users']
|
|
result = users.update_one({'Username': username}, {'$set': update_data})
|
|
|
|
if result.matched_count == 0:
|
|
result = users.update_one({'username': username}, {'$set': update_data})
|
|
|
|
client.close()
|
|
return result.matched_count > 0
|
|
|
|
|
|
# === FAVORITES MANAGEMENT ===
|
|
def get_favorites(username):
|
|
"""Return a list of favorite item ObjectId strings for the user."""
|
|
client = MongoClient(cfg.MONGODB_HOST, cfg.MONGODB_PORT)
|
|
db = _get_tenant_db(client)
|
|
users = db['users']
|
|
user = users.find_one({'Username': username}) or users.find_one({'username': username})
|
|
client.close()
|
|
if not user:
|
|
return []
|
|
favs = user.get('favorites', [])
|
|
# Normalize to strings
|
|
return [str(f) for f in favs if f]
|
|
|
|
def add_favorite(username, item_id):
|
|
"""Add an item to user's favorites (idempotent)."""
|
|
try:
|
|
client = MongoClient(cfg.MONGODB_HOST, cfg.MONGODB_PORT)
|
|
db = _get_tenant_db(client)
|
|
users = db['users']
|
|
users.update_one(
|
|
{'$or': [{'Username': username}, {'username': username}]},
|
|
{'$addToSet': {'favorites': ObjectId(item_id)}}
|
|
)
|
|
client.close()
|
|
return True
|
|
except Exception:
|
|
return False
|
|
|
|
def remove_favorite(username, item_id):
|
|
"""Remove an item from user's favorites."""
|
|
try:
|
|
client = MongoClient(cfg.MONGODB_HOST, cfg.MONGODB_PORT)
|
|
db = _get_tenant_db(client)
|
|
users = db['users']
|
|
users.update_one(
|
|
{'$or': [{'Username': username}, {'username': username}]},
|
|
{'$pull': {'favorites': ObjectId(item_id)}}
|
|
)
|
|
client.close()
|
|
return True
|
|
except Exception:
|
|
return False
|
|
|
|
|
|
|
|
def check_password_strength(password):
|
|
"""
|
|
Check if a password meets minimum security requirements.
|
|
|
|
Args:
|
|
password (str): Password to check
|
|
|
|
Returns:
|
|
bool: True if password is strong enough, False otherwise
|
|
"""
|
|
if password is None:
|
|
return False
|
|
|
|
if len(password) < 12:
|
|
return False
|
|
|
|
has_lower = any(char.islower() for char in password)
|
|
has_upper = any(char.isupper() for char in password)
|
|
has_digit = any(char.isdigit() for char in password)
|
|
has_symbol = any(not char.isalnum() for char in password)
|
|
|
|
if not (has_lower and has_upper and has_digit and has_symbol):
|
|
return False
|
|
return True
|
|
|
|
|
|
def hashing(password):
|
|
"""
|
|
Hash a password using SHA-512.
|
|
|
|
Args:
|
|
password (str): Password to hash
|
|
|
|
Returns:
|
|
str: Hexadecimal digest of the hashed password
|
|
"""
|
|
return hashlib.sha512(password.encode()).hexdigest()
|
|
|
|
|
|
def check_nm_pwd(username, password):
|
|
"""
|
|
Verify username and password combination.
|
|
|
|
Args:
|
|
username (str): Username to check
|
|
password (str): Password to verify
|
|
|
|
Returns:
|
|
dict: User document if credentials are valid, None otherwise
|
|
"""
|
|
db_name = cfg.MONGODB_DB
|
|
tenant_db = None
|
|
ctx = None
|
|
try:
|
|
from tenant import get_tenant_context
|
|
ctx = get_tenant_context()
|
|
if ctx and ctx.tenant_id:
|
|
tenant_db = ctx.db_name or ctx.resolve_tenant()
|
|
db_name = tenant_db
|
|
except Exception as exc:
|
|
logger.exception(f"Failed to resolve tenant context in check_nm_pwd: {exc}")
|
|
|
|
logger.info(
|
|
"check_nm_pwd start: username=%r tenant=%r db=%r host=%r port=%r uri=%r",
|
|
username,
|
|
ctx.tenant_id if ctx else None,
|
|
db_name,
|
|
cfg.MONGODB_HOST,
|
|
cfg.MONGODB_PORT,
|
|
getattr(cfg, 'MONGODB_URI', None),
|
|
)
|
|
|
|
client = MongoClient(cfg.MONGODB_HOST, cfg.MONGODB_PORT)
|
|
try:
|
|
hashed_password = hashing(password)
|
|
logger.info("check_nm_pwd password hash for username=%r: %s", username, hashed_password)
|
|
available_dbs = []
|
|
try:
|
|
available_dbs = client.list_database_names()
|
|
logger.debug("MongoDB connected. Available databases=%s", available_dbs)
|
|
except Exception as exc:
|
|
logger.exception("Unable to list MongoDB databases: %s", exc)
|
|
|
|
db = client[db_name]
|
|
try:
|
|
existing_collections = db.list_collection_names()
|
|
except Exception as exc:
|
|
logger.exception("Unable to list collections for db=%r: %s", db_name, exc)
|
|
existing_collections = []
|
|
logger.debug("Tenant db=%r collections=%s", db_name, existing_collections)
|
|
|
|
users = db['users']
|
|
query = {'$or': [{'Username': username}, {'username': username}]}
|
|
logger.debug("Running user lookup on %r: %s", db_name, query)
|
|
user_record = users.find_one(query)
|
|
|
|
if user_record is None:
|
|
logger.warning("No user document found in db=%r for username=%r", db_name, username)
|
|
if db_name not in available_dbs:
|
|
logger.warning("Tenant database %r is missing from available MongoDB databases", db_name)
|
|
if 'users' not in existing_collections:
|
|
logger.warning("Tenant database %r has no users collection", db_name)
|
|
return None
|
|
|
|
logger.info("Found user document for username=%r in db=%r: %s", username, db_name, user_record)
|
|
stored_password = user_record.get('Password') or user_record.get('password')
|
|
if stored_password is None:
|
|
logger.warning("User document for username=%r in db=%r has no password field", username, db_name)
|
|
return None
|
|
|
|
if stored_password != hashed_password:
|
|
logger.warning(
|
|
"Password mismatch for username=%r in db=%r: provided_hash=%s stored_hash=%s",
|
|
username,
|
|
db_name,
|
|
hashed_password,
|
|
stored_password,
|
|
)
|
|
return None
|
|
|
|
return user_record
|
|
finally:
|
|
client.close()
|
|
|
|
|
|
def add_user(
|
|
username,
|
|
password,
|
|
name='',
|
|
last_name='',
|
|
is_student=False,
|
|
student_card_id=None,
|
|
max_borrow_days=None,
|
|
permission_preset='standard_user',
|
|
action_permissions=None,
|
|
page_permissions=None,
|
|
):
|
|
"""
|
|
Add a new user to the database.
|
|
|
|
Args:
|
|
username (str): Username for the new user
|
|
password (str): Password for the new user
|
|
|
|
Returns:
|
|
bool: True if user was added successfully, False if password was too weak
|
|
"""
|
|
client = MongoClient(cfg.MONGODB_HOST, cfg.MONGODB_PORT)
|
|
db = _get_tenant_db(client)
|
|
users = db['users']
|
|
if not check_password_strength(password):
|
|
return False
|
|
permission_defaults = build_default_permission_payload(permission_preset)
|
|
if isinstance(action_permissions, dict):
|
|
for key, value in action_permissions.items():
|
|
permission_defaults['actions'][str(key)] = bool(value)
|
|
if isinstance(page_permissions, dict):
|
|
for key, value in page_permissions.items():
|
|
permission_defaults['pages'][str(key)] = bool(value)
|
|
|
|
user_doc = {
|
|
'Username': username,
|
|
'Password': hashing(password),
|
|
'Admin': False,
|
|
'active_ausleihung': None,
|
|
'name': name.strip() if name else '',
|
|
'last_name': last_name.strip() if last_name else '',
|
|
'IsStudent': bool(is_student),
|
|
'PermissionPreset': permission_defaults['preset'],
|
|
'ActionPermissions': permission_defaults['actions'],
|
|
'PagePermissions': permission_defaults['pages'],
|
|
}
|
|
|
|
normalized_card = normalize_student_card_id(student_card_id)
|
|
if bool(is_student):
|
|
if normalized_card:
|
|
user_doc['StudentCardId'] = normalized_card
|
|
if max_borrow_days is not None:
|
|
try:
|
|
user_doc['MaxBorrowDays'] = int(max_borrow_days)
|
|
except (TypeError, ValueError):
|
|
pass
|
|
|
|
users.insert_one(user_doc)
|
|
client.close()
|
|
return True
|
|
|
|
|
|
def student_card_exists(student_card_id):
|
|
"""Return True if a student card id is already assigned to a user."""
|
|
normalized = normalize_student_card_id(student_card_id)
|
|
if not normalized:
|
|
return False
|
|
client = MongoClient(cfg.MONGODB_HOST, cfg.MONGODB_PORT)
|
|
db = _get_tenant_db(client)
|
|
users = db['users']
|
|
exists = users.find_one({'StudentCardId': normalized}) is not None
|
|
client.close()
|
|
return exists
|
|
|
|
|
|
def get_user_by_student_card(student_card_id):
|
|
"""Return user by student card id or None."""
|
|
normalized = normalize_student_card_id(student_card_id)
|
|
if not normalized:
|
|
return None
|
|
client = MongoClient(cfg.MONGODB_HOST, cfg.MONGODB_PORT)
|
|
db = _get_tenant_db(client)
|
|
users = db['users']
|
|
found_user = users.find_one({'StudentCardId': normalized})
|
|
client.close()
|
|
return found_user
|
|
|
|
|
|
def make_admin(username):
|
|
"""
|
|
Grant administrator privileges to a user.
|
|
|
|
Args:
|
|
username (str): Username of the user to promote
|
|
|
|
Returns:
|
|
bool: True if user was promoted successfully
|
|
"""
|
|
client = MongoClient(cfg.MONGODB_HOST, cfg.MONGODB_PORT)
|
|
db = _get_tenant_db(client)
|
|
users = db['users']
|
|
result = users.update_one({'Username': username}, {'$set': {'Admin': True}})
|
|
if result.matched_count == 0:
|
|
result = users.update_one({'username': username}, {'$set': {'Admin': True}})
|
|
client.close()
|
|
return result.matched_count > 0
|
|
|
|
def remove_admin(username):
|
|
"""
|
|
Remove administrator privileges from a user.
|
|
|
|
Args:
|
|
username (str): Username of the user to demote
|
|
|
|
Returns:
|
|
bool: True if user was demoted successfully
|
|
"""
|
|
client = MongoClient(cfg.MONGODB_HOST, cfg.MONGODB_PORT)
|
|
db = _get_tenant_db(client)
|
|
users = db['users']
|
|
result = users.update_one({'Username': username}, {'$set': {'Admin': False}})
|
|
if result.matched_count == 0:
|
|
result = users.update_one({'username': username}, {'$set': {'Admin': False}})
|
|
client.close()
|
|
return result.matched_count > 0
|
|
|
|
def get_user(username):
|
|
"""
|
|
Retrieve a specific user by username.
|
|
|
|
Args:
|
|
username (str): Username to search for
|
|
|
|
Returns:
|
|
dict: User document or None if not found
|
|
"""
|
|
client = MongoClient(cfg.MONGODB_HOST, cfg.MONGODB_PORT)
|
|
try:
|
|
def find_in_db(database_name):
|
|
db = client[database_name]
|
|
users = db['users']
|
|
return users.find_one({'Username': username}) or users.find_one({'username': username})
|
|
|
|
# Try current tenant first when available
|
|
try:
|
|
from tenant import get_tenant_context
|
|
ctx = get_tenant_context()
|
|
if ctx and ctx.db_name:
|
|
user = find_in_db(ctx.db_name)
|
|
if user:
|
|
return user
|
|
except Exception:
|
|
pass
|
|
|
|
# Fallback to default configured database
|
|
user = find_in_db(cfg.MONGODB_DB)
|
|
if user:
|
|
return user
|
|
|
|
return None
|
|
finally:
|
|
client.close()
|
|
|
|
|
|
def check_admin(username):
|
|
"""
|
|
Check if a user has administrator privileges.
|
|
|
|
Args:
|
|
username (str): Username to check
|
|
|
|
Returns:
|
|
bool: True if user is an administrator, False otherwise
|
|
"""
|
|
user = get_user(username)
|
|
return bool(user and user.get('Admin', False))
|
|
|
|
|
|
def update_active_ausleihung(username, id_item, ausleihung):
|
|
"""
|
|
Update a user's active borrowing record.
|
|
|
|
Args:
|
|
username (str): Username of the user
|
|
id_item (str): ID of the borrowed item
|
|
ausleihung (str): ID of the borrowing record
|
|
|
|
Returns:
|
|
bool: True if successful
|
|
"""
|
|
client = MongoClient(cfg.MONGODB_HOST, cfg.MONGODB_PORT)
|
|
db = _get_tenant_db(client)
|
|
users = db['users']
|
|
users.update_one({'Username': username}, {'$set': {'active_ausleihung': {'Item': id_item, 'Ausleihung': ausleihung}}})
|
|
client.close()
|
|
return True
|
|
|
|
|
|
def get_active_ausleihung(username):
|
|
"""
|
|
Get a user's active borrowing record.
|
|
|
|
Args:
|
|
username (str): Username of the user
|
|
|
|
Returns:
|
|
dict: Active borrowing information or None
|
|
"""
|
|
client = MongoClient(cfg.MONGODB_HOST, cfg.MONGODB_PORT)
|
|
db = _get_tenant_db(client)
|
|
users = db['users']
|
|
user = users.find_one({'Username': username})
|
|
return user['active_ausleihung']
|
|
|
|
|
|
def has_active_borrowing(username):
|
|
"""
|
|
Check if a user currently has an active borrowing.
|
|
|
|
Args:
|
|
username (str): Username to check
|
|
|
|
Returns:
|
|
bool: True if user has an active borrowing, False otherwise
|
|
"""
|
|
try:
|
|
client = MongoClient(cfg.MONGODB_HOST, cfg.MONGODB_PORT)
|
|
db = _get_tenant_db(client)
|
|
users = db['users']
|
|
|
|
user = users.find_one({'username': username})
|
|
if not user:
|
|
user = users.find_one({'Username': username})
|
|
|
|
if not user:
|
|
client.close()
|
|
return False
|
|
|
|
has_active = user.get('active_borrowing', False)
|
|
|
|
client.close()
|
|
return has_active
|
|
except Exception as e:
|
|
return False
|
|
|
|
|
|
def delete_user(username):
|
|
"""
|
|
Delete a user from the database.
|
|
Administrative function for removing user accounts.
|
|
|
|
Args:
|
|
username (str): Username of the account to delete
|
|
|
|
Returns:
|
|
bool: True if user was deleted successfully, False otherwise
|
|
"""
|
|
client = MongoClient(cfg.MONGODB_HOST, cfg.MONGODB_PORT)
|
|
db = _get_tenant_db(client)
|
|
users = db['users']
|
|
result = users.delete_one({'username': username})
|
|
client.close()
|
|
if result.deleted_count == 0:
|
|
# Try with different field name
|
|
client = MongoClient(cfg.MONGODB_HOST, cfg.MONGODB_PORT)
|
|
db = _get_tenant_db(client)
|
|
users = db['users']
|
|
result = users.delete_one({'Username': username})
|
|
client.close()
|
|
|
|
return result.deleted_count > 0
|
|
|
|
|
|
def update_active_borrowing(username, item_id, status):
|
|
"""
|
|
Update a user's active borrowing status.
|
|
|
|
Args:
|
|
username (str): Username of the user
|
|
item_id (str): ID of the borrowed item or None if returning
|
|
status (bool): True if borrowing, False if returning
|
|
|
|
Returns:
|
|
bool: True if successful, False on error
|
|
"""
|
|
try:
|
|
client = MongoClient(cfg.MONGODB_HOST, cfg.MONGODB_PORT)
|
|
db = _get_tenant_db(client)
|
|
users = db['users']
|
|
result = users.update_one(
|
|
{'username': username},
|
|
{'$set': {
|
|
'active_borrowing': status,
|
|
'borrowed_item': item_id if status else None
|
|
}}
|
|
)
|
|
|
|
if result.matched_count == 0:
|
|
result = users.update_one(
|
|
{'Username': username},
|
|
{'$set': {
|
|
'active_borrowing': status,
|
|
'borrowed_item': item_id if status else None
|
|
}}
|
|
)
|
|
|
|
client.close()
|
|
return result.modified_count > 0
|
|
except Exception as e:
|
|
return False
|
|
|
|
|
|
def get_name(username):
|
|
"""
|
|
Retrieve the name that is assosiated with the username.
|
|
|
|
Returns:
|
|
str: String of name
|
|
"""
|
|
client = MongoClient(cfg.MONGODB_HOST, cfg.MONGODB_PORT)
|
|
db = _get_tenant_db(client)
|
|
users = db['users']
|
|
user = users.find_one({'Username': username})
|
|
name = user.get("name")
|
|
return name
|
|
|
|
|
|
def get_last_name(username):
|
|
"""
|
|
Retrieve the last_name that is assosiated with the username.
|
|
|
|
Returns:
|
|
str: String of last_name
|
|
"""
|
|
client = MongoClient(cfg.MONGODB_HOST, cfg.MONGODB_PORT)
|
|
db = _get_tenant_db(client)
|
|
users = db['users']
|
|
user = users.find_one({'Username': username})
|
|
name = user.get("last_name")
|
|
return name
|
|
|
|
|
|
def get_all_users():
|
|
"""
|
|
Retrieve all users from the database.
|
|
Administrative function for user management.
|
|
|
|
Returns:
|
|
list: List of all user documents
|
|
"""
|
|
try:
|
|
client = MongoClient(cfg.MONGODB_HOST, cfg.MONGODB_PORT)
|
|
db = _get_tenant_db(client)
|
|
users = db['users']
|
|
all_users = list(users.find())
|
|
client.close()
|
|
return all_users
|
|
except Exception as e:
|
|
return []
|
|
|
|
def update_password(username, new_password):
|
|
"""
|
|
Update a user's password with a new one.
|
|
|
|
Args:
|
|
username (str): Username of the user
|
|
new_password (str): New password to set
|
|
|
|
Returns:
|
|
bool: True if password was updated successfully, False otherwise
|
|
"""
|
|
try:
|
|
if not check_password_strength(new_password):
|
|
return False
|
|
|
|
client = MongoClient(cfg.MONGODB_HOST, cfg.MONGODB_PORT)
|
|
db = _get_tenant_db(client)
|
|
users = db['users']
|
|
|
|
# Hash the new password
|
|
hashed_password = hashing(new_password)
|
|
|
|
# Update the user's password
|
|
result = users.update_one(
|
|
{'Username': username},
|
|
{'$set': {'Password': hashed_password}}
|
|
)
|
|
|
|
client.close()
|
|
return result.modified_count > 0
|
|
except Exception as e:
|
|
print(f"Error updating password: {e}")
|
|
return False
|
|
|
|
def update_user_name(username, name, last_name):
|
|
"""
|
|
Update a user's name and last name.
|
|
|
|
Args:
|
|
username (str): Username of the user
|
|
name (str): New first name
|
|
last_name (str): New last name
|
|
|
|
Returns:
|
|
bool: True if updated successfully, False otherwise
|
|
"""
|
|
try:
|
|
name_alias = build_name_synonym(name, last_name)
|
|
client = MongoClient(cfg.MONGODB_HOST, cfg.MONGODB_PORT)
|
|
db = _get_tenant_db(client)
|
|
users = db['users']
|
|
|
|
result = users.update_one(
|
|
{'Username': username},
|
|
{'$set': {'name': name_alias, 'last_name': ''}}
|
|
)
|
|
|
|
client.close()
|
|
return True
|
|
except Exception as e:
|
|
print(f"Error updating user name: {e}")
|
|
return False
|