|
|
|
@@ -45,30 +45,33 @@ def _clean_name_fragment(value):
|
|
|
|
|
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 like 'SimFri'."""
|
|
|
|
|
"""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[:3] + last[:3]).title()
|
|
|
|
|
return (first[:2] + last[:2]).title()
|
|
|
|
|
|
|
|
|
|
combined = (first + last)
|
|
|
|
|
if not combined:
|
|
|
|
|
return 'User'
|
|
|
|
|
return combined[:6].title()
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def _generate_anonymous_username(prefix='user', length=8):
|
|
|
|
|
"""Generate a random anonymized username using lowercase letters and digits."""
|
|
|
|
|
alphabet = string.ascii_lowercase + string.digits
|
|
|
|
|
return prefix + ''.join(secrets.choice(alphabet) for _ in range(length))
|
|
|
|
|
return combined[:4].title()
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def build_username_from_name(first_name, last_name=''):
|
|
|
|
|
"""
|
|
|
|
|
Build a deterministic username abbreviation from first and last name.
|
|
|
|
|
Uses the same short alias logic (e.g. SimFri) and stores it lowercase.
|
|
|
|
|
Uses 2 letters from each name and stores it lowercase.
|
|
|
|
|
|
|
|
|
|
Args:
|
|
|
|
|
first_name (str): First name
|
|
|
|
@@ -81,50 +84,25 @@ def build_username_from_name(first_name, last_name=''):
|
|
|
|
|
return alias.lower()
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def build_anonymous_username():
|
|
|
|
|
"""
|
|
|
|
|
Build a truly anonymized username that is not derived from the user's
|
|
|
|
|
first name or last name.
|
|
|
|
|
"""
|
|
|
|
|
for _ in range(10):
|
|
|
|
|
candidate = _generate_anonymous_username()
|
|
|
|
|
if not get_user(candidate):
|
|
|
|
|
return candidate
|
|
|
|
|
|
|
|
|
|
suffix = 2
|
|
|
|
|
while get_user(f"user{suffix}"):
|
|
|
|
|
suffix += 1
|
|
|
|
|
return f"user{suffix}"
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def build_unique_username_from_name(first_name, last_name=''):
|
|
|
|
|
"""
|
|
|
|
|
Build a unique username based on the abbreviation logic.
|
|
|
|
|
If a collision occurs, increase the username by one additional letter
|
|
|
|
|
from the combined cleaned name until it is unique.
|
|
|
|
|
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)
|
|
|
|
|
combined = (first + last).lower()
|
|
|
|
|
base_username = (first[:2] + last[:2]).lower()
|
|
|
|
|
|
|
|
|
|
base_username = build_username_from_name(first_name, last_name)
|
|
|
|
|
if not combined:
|
|
|
|
|
combined = base_username or 'user'
|
|
|
|
|
if not base_username:
|
|
|
|
|
base_username = 'user'
|
|
|
|
|
|
|
|
|
|
start_len = len(base_username) if base_username else min(6, len(combined))
|
|
|
|
|
start_len = max(1, min(start_len, len(combined)))
|
|
|
|
|
if not get_user(base_username):
|
|
|
|
|
return base_username
|
|
|
|
|
|
|
|
|
|
# Main strategy: take one more letter on each collision.
|
|
|
|
|
for length in range(start_len, len(combined) + 1):
|
|
|
|
|
candidate = combined[:length]
|
|
|
|
|
if not get_user(candidate):
|
|
|
|
|
return candidate
|
|
|
|
|
|
|
|
|
|
# Fallback if full combined name is already taken repeatedly.
|
|
|
|
|
suffix = 2
|
|
|
|
|
while get_user(f"{combined}{suffix}"):
|
|
|
|
|
while get_user(f"{base_username}{suffix}"):
|
|
|
|
|
suffix += 1
|
|
|
|
|
return f"{combined}{suffix}"
|
|
|
|
|
return f"{base_username}{suffix}"
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
ACTION_PERMISSION_KEYS = (
|
|
|
|
@@ -334,7 +312,7 @@ def update_user_permissions(username, preset_key, action_permissions=None, page_
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
client = MongoClient(cfg.MONGODB_HOST, cfg.MONGODB_PORT)
|
|
|
|
|
db = client[cfg.MONGODB_DB]
|
|
|
|
|
db = _get_tenant_db(client)
|
|
|
|
|
users = db['users']
|
|
|
|
|
result = users.update_one({'Username': username}, {'$set': update_data})
|
|
|
|
|
|
|
|
|
@@ -349,7 +327,7 @@ def update_user_permissions(username, preset_key, action_permissions=None, page_
|
|
|
|
|
def get_favorites(username):
|
|
|
|
|
"""Return a list of favorite item ObjectId strings for the user."""
|
|
|
|
|
client = MongoClient(cfg.MONGODB_HOST, cfg.MONGODB_PORT)
|
|
|
|
|
db = client[cfg.MONGODB_DB]
|
|
|
|
|
db = _get_tenant_db(client)
|
|
|
|
|
users = db['users']
|
|
|
|
|
user = users.find_one({'Username': username}) or users.find_one({'username': username})
|
|
|
|
|
client.close()
|
|
|
|
@@ -363,7 +341,7 @@ def add_favorite(username, item_id):
|
|
|
|
|
"""Add an item to user's favorites (idempotent)."""
|
|
|
|
|
try:
|
|
|
|
|
client = MongoClient(cfg.MONGODB_HOST, cfg.MONGODB_PORT)
|
|
|
|
|
db = client[cfg.MONGODB_DB]
|
|
|
|
|
db = _get_tenant_db(client)
|
|
|
|
|
users = db['users']
|
|
|
|
|
users.update_one(
|
|
|
|
|
{'$or': [{'Username': username}, {'username': username}]},
|
|
|
|
@@ -378,7 +356,7 @@ def remove_favorite(username, item_id):
|
|
|
|
|
"""Remove an item from user's favorites."""
|
|
|
|
|
try:
|
|
|
|
|
client = MongoClient(cfg.MONGODB_HOST, cfg.MONGODB_PORT)
|
|
|
|
|
db = client[cfg.MONGODB_DB]
|
|
|
|
|
db = _get_tenant_db(client)
|
|
|
|
|
users = db['users']
|
|
|
|
|
users.update_one(
|
|
|
|
|
{'$or': [{'Username': username}, {'username': username}]},
|
|
|
|
@@ -461,17 +439,7 @@ def check_nm_pwd(username, password):
|
|
|
|
|
users = db['users']
|
|
|
|
|
return users.find_one({'Username': username, 'Password': hashed_password}) or users.find_one({'username': username, 'Password': hashed_password})
|
|
|
|
|
|
|
|
|
|
user = find_user_in_db(db_name)
|
|
|
|
|
if user:
|
|
|
|
|
return user
|
|
|
|
|
|
|
|
|
|
# Fallback: tenant context may not be available yet, so search all tenant databases.
|
|
|
|
|
for database_name in client.list_database_names():
|
|
|
|
|
if database_name == db_name or not database_name.startswith('inventar_'):
|
|
|
|
|
continue
|
|
|
|
|
user = find_user_in_db(database_name)
|
|
|
|
|
if user:
|
|
|
|
|
return user
|
|
|
|
|
return find_user_in_db(db_name)
|
|
|
|
|
finally:
|
|
|
|
|
client.close()
|
|
|
|
|
|
|
|
|
@@ -501,7 +469,7 @@ def add_user(
|
|
|
|
|
bool: True if user was added successfully, False if password was too weak
|
|
|
|
|
"""
|
|
|
|
|
client = MongoClient(cfg.MONGODB_HOST, cfg.MONGODB_PORT)
|
|
|
|
|
db = client[cfg.MONGODB_DB]
|
|
|
|
|
db = _get_tenant_db(client)
|
|
|
|
|
users = db['users']
|
|
|
|
|
if not check_password_strength(password):
|
|
|
|
|
return False
|
|
|
|
@@ -551,7 +519,7 @@ def student_card_exists(student_card_id):
|
|
|
|
|
if not normalized:
|
|
|
|
|
return False
|
|
|
|
|
client = MongoClient(cfg.MONGODB_HOST, cfg.MONGODB_PORT)
|
|
|
|
|
db = client[cfg.MONGODB_DB]
|
|
|
|
|
db = _get_tenant_db(client)
|
|
|
|
|
users = db['users']
|
|
|
|
|
exists = users.find_one({'StudentCardId': normalized}) is not None
|
|
|
|
|
client.close()
|
|
|
|
@@ -564,7 +532,7 @@ def get_user_by_student_card(student_card_id):
|
|
|
|
|
if not normalized:
|
|
|
|
|
return None
|
|
|
|
|
client = MongoClient(cfg.MONGODB_HOST, cfg.MONGODB_PORT)
|
|
|
|
|
db = client[cfg.MONGODB_DB]
|
|
|
|
|
db = _get_tenant_db(client)
|
|
|
|
|
users = db['users']
|
|
|
|
|
found_user = users.find_one({'StudentCardId': normalized})
|
|
|
|
|
client.close()
|
|
|
|
@@ -582,11 +550,13 @@ def make_admin(username):
|
|
|
|
|
bool: True if user was promoted successfully
|
|
|
|
|
"""
|
|
|
|
|
client = MongoClient(cfg.MONGODB_HOST, cfg.MONGODB_PORT)
|
|
|
|
|
db = client[cfg.MONGODB_DB]
|
|
|
|
|
db = _get_tenant_db(client)
|
|
|
|
|
users = db['users']
|
|
|
|
|
users.update_one({'Username': username}, {'$set': {'Admin': True}})
|
|
|
|
|
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 True
|
|
|
|
|
return result.matched_count > 0
|
|
|
|
|
|
|
|
|
|
def remove_admin(username):
|
|
|
|
|
"""
|
|
|
|
@@ -599,11 +569,13 @@ def remove_admin(username):
|
|
|
|
|
bool: True if user was demoted successfully
|
|
|
|
|
"""
|
|
|
|
|
client = MongoClient(cfg.MONGODB_HOST, cfg.MONGODB_PORT)
|
|
|
|
|
db = client[cfg.MONGODB_DB]
|
|
|
|
|
db = _get_tenant_db(client)
|
|
|
|
|
users = db['users']
|
|
|
|
|
users.update_one({'Username': username}, {'$set': {'Admin': False}})
|
|
|
|
|
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 True
|
|
|
|
|
return result.matched_count > 0
|
|
|
|
|
|
|
|
|
|
def get_user(username):
|
|
|
|
|
"""
|
|
|
|
@@ -638,14 +610,6 @@ def get_user(username):
|
|
|
|
|
if user:
|
|
|
|
|
return user
|
|
|
|
|
|
|
|
|
|
# Last fallback: search all tenant databases if the user belongs to a tenant-specific DB
|
|
|
|
|
for database_name in client.list_database_names():
|
|
|
|
|
if database_name == cfg.MONGODB_DB or not database_name.startswith('inventar_'):
|
|
|
|
|
continue
|
|
|
|
|
user = find_in_db(database_name)
|
|
|
|
|
if user:
|
|
|
|
|
return user
|
|
|
|
|
|
|
|
|
|
return None
|
|
|
|
|
finally:
|
|
|
|
|
client.close()
|
|
|
|
@@ -661,12 +625,8 @@ def check_admin(username):
|
|
|
|
|
Returns:
|
|
|
|
|
bool: True if user is an administrator, False otherwise
|
|
|
|
|
"""
|
|
|
|
|
client = MongoClient(cfg.MONGODB_HOST, cfg.MONGODB_PORT)
|
|
|
|
|
db = client[cfg.MONGODB_DB]
|
|
|
|
|
users = db['users']
|
|
|
|
|
user = users.find_one({'Username': username})
|
|
|
|
|
client.close()
|
|
|
|
|
return user and user.get('Admin', False)
|
|
|
|
|
user = get_user(username)
|
|
|
|
|
return bool(user and user.get('Admin', False))
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def update_active_ausleihung(username, id_item, ausleihung):
|
|
|
|
@@ -682,7 +642,7 @@ def update_active_ausleihung(username, id_item, ausleihung):
|
|
|
|
|
bool: True if successful
|
|
|
|
|
"""
|
|
|
|
|
client = MongoClient(cfg.MONGODB_HOST, cfg.MONGODB_PORT)
|
|
|
|
|
db = client[cfg.MONGODB_DB]
|
|
|
|
|
db = _get_tenant_db(client)
|
|
|
|
|
users = db['users']
|
|
|
|
|
users.update_one({'Username': username}, {'$set': {'active_ausleihung': {'Item': id_item, 'Ausleihung': ausleihung}}})
|
|
|
|
|
client.close()
|
|
|
|
@@ -700,7 +660,7 @@ def get_active_ausleihung(username):
|
|
|
|
|
dict: Active borrowing information or None
|
|
|
|
|
"""
|
|
|
|
|
client = MongoClient(cfg.MONGODB_HOST, cfg.MONGODB_PORT)
|
|
|
|
|
db = client[cfg.MONGODB_DB]
|
|
|
|
|
db = _get_tenant_db(client)
|
|
|
|
|
users = db['users']
|
|
|
|
|
user = users.find_one({'Username': username})
|
|
|
|
|
return user['active_ausleihung']
|
|
|
|
@@ -718,7 +678,7 @@ def has_active_borrowing(username):
|
|
|
|
|
"""
|
|
|
|
|
try:
|
|
|
|
|
client = MongoClient(cfg.MONGODB_HOST, cfg.MONGODB_PORT)
|
|
|
|
|
db = client[cfg.MONGODB_DB]
|
|
|
|
|
db = _get_tenant_db(client)
|
|
|
|
|
users = db['users']
|
|
|
|
|
|
|
|
|
|
user = users.find_one({'username': username})
|
|
|
|
@@ -749,14 +709,14 @@ def delete_user(username):
|
|
|
|
|
bool: True if user was deleted successfully, False otherwise
|
|
|
|
|
"""
|
|
|
|
|
client = MongoClient(cfg.MONGODB_HOST, cfg.MONGODB_PORT)
|
|
|
|
|
db = client[cfg.MONGODB_DB]
|
|
|
|
|
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 = client[cfg.MONGODB_DB]
|
|
|
|
|
db = _get_tenant_db(client)
|
|
|
|
|
users = db['users']
|
|
|
|
|
result = users.delete_one({'Username': username})
|
|
|
|
|
client.close()
|
|
|
|
@@ -778,7 +738,7 @@ def update_active_borrowing(username, item_id, status):
|
|
|
|
|
"""
|
|
|
|
|
try:
|
|
|
|
|
client = MongoClient(cfg.MONGODB_HOST, cfg.MONGODB_PORT)
|
|
|
|
|
db = client[cfg.MONGODB_DB]
|
|
|
|
|
db = _get_tenant_db(client)
|
|
|
|
|
users = db['users']
|
|
|
|
|
result = users.update_one(
|
|
|
|
|
{'username': username},
|
|
|
|
@@ -811,7 +771,7 @@ def get_name(username):
|
|
|
|
|
str: String of name
|
|
|
|
|
"""
|
|
|
|
|
client = MongoClient(cfg.MONGODB_HOST, cfg.MONGODB_PORT)
|
|
|
|
|
db = client[cfg.MONGODB_DB]
|
|
|
|
|
db = _get_tenant_db(client)
|
|
|
|
|
users = db['users']
|
|
|
|
|
user = users.find_one({'Username': username})
|
|
|
|
|
name = user.get("name")
|
|
|
|
@@ -826,7 +786,7 @@ def get_last_name(username):
|
|
|
|
|
str: String of last_name
|
|
|
|
|
"""
|
|
|
|
|
client = MongoClient(cfg.MONGODB_HOST, cfg.MONGODB_PORT)
|
|
|
|
|
db = client[cfg.MONGODB_DB]
|
|
|
|
|
db = _get_tenant_db(client)
|
|
|
|
|
users = db['users']
|
|
|
|
|
user = users.find_one({'Username': username})
|
|
|
|
|
name = user.get("last_name")
|
|
|
|
@@ -843,7 +803,7 @@ def get_all_users():
|
|
|
|
|
"""
|
|
|
|
|
try:
|
|
|
|
|
client = MongoClient(cfg.MONGODB_HOST, cfg.MONGODB_PORT)
|
|
|
|
|
db = client[cfg.MONGODB_DB]
|
|
|
|
|
db = _get_tenant_db(client)
|
|
|
|
|
users = db['users']
|
|
|
|
|
all_users = list(users.find())
|
|
|
|
|
client.close()
|
|
|
|
@@ -867,7 +827,7 @@ def update_password(username, new_password):
|
|
|
|
|
return False
|
|
|
|
|
|
|
|
|
|
client = MongoClient(cfg.MONGODB_HOST, cfg.MONGODB_PORT)
|
|
|
|
|
db = client[cfg.MONGODB_DB]
|
|
|
|
|
db = _get_tenant_db(client)
|
|
|
|
|
users = db['users']
|
|
|
|
|
|
|
|
|
|
# Hash the new password
|
|
|
|
@@ -900,7 +860,7 @@ def update_user_name(username, name, last_name):
|
|
|
|
|
try:
|
|
|
|
|
name_alias = build_name_synonym(name, last_name)
|
|
|
|
|
client = MongoClient(cfg.MONGODB_HOST, cfg.MONGODB_PORT)
|
|
|
|
|
db = client[cfg.MONGODB_DB]
|
|
|
|
|
db = _get_tenant_db(client)
|
|
|
|
|
users = db['users']
|
|
|
|
|
|
|
|
|
|
result = users.update_one(
|
|
|
|
|