Compare commits

...

4 Commits

2 changed files with 166 additions and 40 deletions
+119 -4
View File
@@ -54,10 +54,34 @@ def _clean_name_fragment(value):
return cleaned
def _get_tenant_db(client):
def _get_tenant_db(client, tenant_id=None):
"""Return the current tenant database for the request, or fall back to default."""
try:
from tenant import get_tenant_db
if tenant_id is None:
return get_tenant_db(client)
tenant_id = str(tenant_id).strip()
if tenant_id:
try:
from tenant import get_tenant_config
config = get_tenant_config(tenant_id)
if isinstance(config, dict):
explicit_db = config.get('db') or config.get('db_name')
if explicit_db:
db_name = str(explicit_db).strip()
if db_name and not db_name.startswith('inventar_'):
db_name = f'inventar_{db_name}'
if db_name:
return client[db_name]
except Exception:
pass
sanitized = ''.join(c for c in tenant_id.lower() if c.isalnum() or c == '_')
if sanitized:
return client[f'inventar_{sanitized}']
return get_tenant_db(client)
except Exception:
return client[cfg.MONGODB_DB]
@@ -479,8 +503,45 @@ def check_nm_pwd(username, password):
query = {'$or': [{'Username': username}, {'username': username}]}
user_record_fallback = users.find_one(query)
if user_record_fallback is None:
logger.warning("Kein Benutzer für %r in DB %r gefunden.", dp.encrypt_text(username), db_name)
return None
if db_name != cfg.MONGODB_DB:
default_users = client[cfg.MONGODB_DB]['users']
user_record_fallback = default_users.find_one(
{'$or': [
{'Username': dp.encrypt_text(username)},
{'username': dp.encrypt_text(username)},
{'Username': username},
{'username': username},
]}
)
if user_record_fallback is not None:
migrated_record = dict(user_record_fallback)
migrated_record.pop('_id', None)
users.replace_one(
{'$or': [
{'Username': migrated_record.get('Username')},
{'username': migrated_record.get('username')},
]},
migrated_record,
upsert=True,
)
logger.warning(
"Tenant user %r migrated from default DB %r to tenant DB %r.",
dp.encrypt_text(username),
cfg.MONGODB_DB,
db_name,
)
user_record = users.find_one(
{'$or': [
{'Username': migrated_record.get('Username')},
{'username': migrated_record.get('username')},
]}
) or migrated_record
else:
logger.warning("Kein Benutzer für %r in DB %r gefunden.", dp.encrypt_text(username), db_name)
return None
else:
logger.warning("Kein Benutzer für %r in DB %r gefunden.", dp.encrypt_text(username), db_name)
return None
else:
user_record = user_record_fallback
@@ -497,6 +558,59 @@ def check_nm_pwd(username, password):
finally:
client.close()
def add_admin(
username,
password,
name='',
last_name='',
is_student=False,
permission_preset='full_access',
action_permissions=None,
page_permissions=None,
tenant_id=None,
):
"""
Add a new user to the database.
"""
if not check_password_strength(password):
return False
client = MongoClient(cfg.MONGODB_HOST, cfg.MONGODB_PORT)
try:
db = _get_tenant_db(client, tenant_id)
users = db['users']
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)
safe_name = name.strip() if name else ''
safe_last_name = last_name.strip() if last_name else ''
user_doc = {
'Username': username,
'Password': hashing(password),
'Admin': True,
'active_ausleihung': None,
'name': dp.encrypt_text(safe_name) if safe_name else '',
'last_name': dp.encrypt_text(safe_last_name) if safe_last_name else '',
'IsStudent': bool(is_student),
'PermissionPreset': permission_defaults['preset'],
'ActionPermissions': permission_defaults['actions'],
'PagePermissions': permission_defaults['pages'],
}
users.insert_one(user_doc)
return True
finally:
client.close()
def add_user(
username,
@@ -509,6 +623,7 @@ def add_user(
permission_preset='standard_user',
action_permissions=None,
page_permissions=None,
tenant_id=None,
):
"""
Add a new user to the database.
@@ -518,7 +633,7 @@ def add_user(
client = MongoClient(cfg.MONGODB_HOST, cfg.MONGODB_PORT)
try:
db = _get_tenant_db(client)
db = _get_tenant_db(client, tenant_id)
users = db['users']
permission_defaults = build_default_permission_payload(permission_preset)
+47 -36
View File
@@ -206,12 +206,30 @@ import Web.modules.database.user as us
tenant_id = sys.argv[1].lower()
mode = sys.argv[2]
sanitized = "".join(c for c in tenant_id if c.isalnum() or c == "_")
db_name = f"inventar_{sanitized}" if sanitized else settings.MONGODB_DB
us.add_user("admin", "admin123", "admin", "admin", permission_preset='full_access')
us.make_admin("admin")
client = MongoClient(settings.MONGODB_HOST, settings.MONGODB_PORT)
db = client[db_name]
users = db["users"]
permission_defaults = us.build_default_permission_payload("full_access")
admin_doc = {
"Username": "admin",
"Password": us.hashing("admin123"),
"Admin": True,
"active_ausleihung": None,
"name": dp.encrypt_text("admin"),
"last_name": dp.encrypt_text("admin"),
"IsStudent": False,
"PermissionPreset": permission_defaults["preset"],
"ActionPermissions": permission_defaults["actions"],
"PagePermissions": permission_defaults["pages"],
}
users.replace_one({"Username": "admin"}, admin_doc, upsert=True)
print("Fallback successfully applied")
if mode == "trial":
client = MongoClient(settings.MONGODB_HOST, settings.MONGODB_PORT)
db = client[db_name]
db.settings.update_one(
{"setting_type": "tenant_trial"},
{"$set": {
@@ -224,6 +242,8 @@ if mode == "trial":
upsert=True,
)
client.close()
print(f"Tenant {sys.argv[1]} database initialized. Default admin: admin / admin123")
PY
}
@@ -595,11 +615,11 @@ case "$COMMAND" in
initialize_tenant_database "$TENANT_ID" "trial"
echo "Trial tenant '$TENANT_ID' successfully configured. It will expire after $DAYS_ARG day(s) and self-delete."
;;
remove)
FORCE_REMOVE=false
TENANT_ARG="${2:-}"
if [ "$TENANT_ARG" = "--yes" ] || [ "$TENANT_ARG" = "-y" ]; then
FORCE_REMOVE=true
TENANT_ID="${3:-}"
@@ -624,40 +644,31 @@ case "$COMMAND" in
echo "Removing tenant '$TENANT_ID'..."
APP_CONTAINER=$(docker ps -qf "name=app" | head -n 1)
port_to_remove=""
if [ -n "$APP_CONTAINER" ]; then
# Zuerst die Datenbank via PyMongo hart droppen (Erzwungenes Löschen)
port_to_remove="$(docker exec "$APP_CONTAINER" python3 - "$TENANT_ID" <<'PY'
import sys, re
sys.path.insert(0, '/app')
sys.path.insert(0, '/app/Web')
from tenant import delete_tenant, get_tenant_config
from Web.modules.database import settings
from pymongo import MongoClient
# MongoDB-Datenbank via PyMongo direkt im Container droppen
docker exec -i "$APP_CONTAINER" python3 -c '
import sys, os
try:
import pymongo
tenant_id = sys.argv[1]
mongo_uri = os.environ.get("MONGO_URI", "mongodb://localhost:27017/")
client = pymongo.MongoClient(mongo_uri, serverSelectionTimeoutMS=2000)
db_name = f"inventar_{tenant_id}"
if db_name in client.list_database_names():
client.drop_database(db_name)
print(f"Dropped database: {db_name}")
except Exception as e:
print(f"Error dropping database: {e}", file=sys.stderr)
' "$TENANT_ID" > /dev/null 2>&1
tenant_id = sys.argv[1]
tenant_cfg = get_tenant_config(tenant_id)
port = tenant_cfg.get('port')
# Konfiguration und Port via Host-Funktion bereinigen und Port ermitteln
if port_to_remove="$(remove_tenant_port "$TENANT_ID" 2>/dev/null)"; then
:
else
port_to_remove=""
fi
# Datenbanknamen exakt rekonstruieren
sanitized = "".join(c for c in tenant_id if c.isalnum() or c == "_")
db_name = f"inventar_{sanitized}"
try:
client = MongoClient(settings.MONGODB_HOST, int(settings.MONGODB_PORT))
client.drop_database(db_name)
print(f"MongoDB database '{db_name}' dropped successfully.", file=sys.stderr)
except Exception as e:
print(f"Warning: Could not drop database '{db_name}': {e}", file=sys.stderr)
if not delete_tenant(tenant_id):
print(f'Error: failed to delete tenant {tenant_id}', file=sys.stderr)
sys.exit(1)
if port is not None:
print(port)
PY
)"
echo "Tenant '$TENANT_ID' database and config removed."
else
echo "Warning: Application container not running. Tenant database may still exist in MongoDB."
@@ -680,7 +691,7 @@ PY
else
echo "Removed tenant '$TENANT_ID'. No port mapping was present."
fi
;;
;;
restart-tenant)
TENANT_ID="${2:-}"