Compare commits
13 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 6dced8b1a5 | |||
| 493ee2ea7f | |||
| 52a2ec0cad | |||
| b5f2c3c5c5 | |||
| 403c281c93 | |||
| 6d121f6110 | |||
| 9d940c6151 | |||
| 980b825e07 | |||
| 94326728eb | |||
| efe17883a6 | |||
| 76f93b3d2e | |||
| 8f793045c2 | |||
| a199439d76 |
+19
-10
@@ -388,7 +388,7 @@ ALLOWED_COVER_DOMAINS = {
|
||||
"www.googleapis.com"
|
||||
}
|
||||
|
||||
SENSITIVE_AUDIT_FIELDS = ["email", "username", "full_name", "phone"]
|
||||
SENSITIVE_AUDIT_FIELDS = ["email", "username", "full_name", "phone", "borrower", "ip"]
|
||||
|
||||
# Apply the configuration for general use throughout the app
|
||||
APP_VERSION = __version__
|
||||
@@ -3604,8 +3604,11 @@ def api_item_detail(item_id):
|
||||
# Basic detail HTML
|
||||
detail_html = f"""
|
||||
<h2>{html.escape(item.get('Name', 'Untitled'))}</h2>
|
||||
<p><strong>Autor/Künstler:</strong> {html.escape(item.get('Autor', item.get('Author', '-')))}</p>
|
||||
<p><strong>ISBN:</strong> {html.escape(item.get('ISBN', item.get('Code4', '-')))}</p>
|
||||
<p><strong>Anzahl:</strong> {html.escape(item.get('SeriesCount', '-'))}</p>
|
||||
<p><strong>Ort:</strong> {html.escape(item.get('Ort', '-'))}</p>
|
||||
<p><strong>Typ:</strong> {html.escape(item.get('ItemType', '-'))}</p>
|
||||
<p><strong>Kategorie:</strong> {html.escape(item.get('library_category', '-'))}</p>
|
||||
<p><strong>Beschreibung:</strong> {html.escape(item.get('Beschreibung', '-'))}</p>
|
||||
<p><strong>Status:</strong> {html.escape(status_label)}</p>
|
||||
{f'<p><strong>Ausgeliehen von:</strong> {html.escape(str(borrower_value))}</p>' if borrower_value and status_label == 'Ausgeliehen' else ''}
|
||||
@@ -5144,7 +5147,9 @@ def upload_item():
|
||||
individual_codes_raw = sanitize_form_value(request.form.get('individual_codes', ''))
|
||||
item_count_raw = sanitize_form_value(request.form.get('item_count', '1'))
|
||||
item_type_input = sanitize_form_value(request.form.get('item_type_input', ''))
|
||||
|
||||
library_category = sanitize_form_value(request.form.get('library_category', ''))
|
||||
|
||||
app.logger.info(f"Upload attempt by {encrypt_text(username)}: name={name!r}, ort={ort!r}, beschreibung length={len(beschreibung)}, images count={len(images)}, filters={filter_upload}, filters2={filter_upload2}, filters3={filter_upload3}, anschaffungs_jahr={anschaffungs_jahr}, anschaffungs_kosten={anschaffungs_kosten}, code_4={code_4}, isbn={isbn_raw!r}, upload_mode={upload_mode!r}, item_count={item_count_raw!r}, item_type_input={item_type_input!r}, individual_codes={individual_codes_raw!r}")
|
||||
try:
|
||||
item_count = int(item_count_raw) if item_count_raw else 1
|
||||
except (TypeError, ValueError):
|
||||
@@ -5156,6 +5161,8 @@ def upload_item():
|
||||
if individual_codes_raw:
|
||||
individual_codes = [c.strip() for c in str(individual_codes_raw).replace(',', '\n').splitlines() if c.strip()]
|
||||
|
||||
app.logger.info(f"DEBUG: Parsed individual codes: {individual_codes}, count: {len(individual_codes)}")
|
||||
|
||||
# Check if this is a duplication
|
||||
is_duplicating = request.form.get('is_duplicating') == 'true'
|
||||
|
||||
@@ -5271,6 +5278,8 @@ def upload_item():
|
||||
for c in extra_codes:
|
||||
if c not in all_item_codes:
|
||||
all_item_codes.append(c)
|
||||
|
||||
app.logger.info(f"DEBUG: Unified item codes: {all_item_codes}, total count: {len(all_item_codes)}")
|
||||
|
||||
# -------------------------------------------------------------------
|
||||
# 2. OVERRIDE ITEM COUNT
|
||||
@@ -5302,7 +5311,7 @@ def upload_item():
|
||||
# Validate every code in our master list against the database
|
||||
for code in all_item_codes:
|
||||
if not it.is_code_unique(code):
|
||||
|
||||
app.logger.info(f"DEBUG: Code '{code}' is not unique.")
|
||||
# Special case: If they only uploaded ONE item, redirect them to that existing item
|
||||
if item_count == 1:
|
||||
existing_item = it._get_items_collection().find_one({"code_4": code})
|
||||
@@ -5335,13 +5344,13 @@ def upload_item():
|
||||
if not base_code:
|
||||
return None
|
||||
|
||||
candidate = base_code if position == 1 else f"{base_code}-{position}"
|
||||
candidate = base_code if position == 1 else f"{base_code}"
|
||||
if it.is_code_unique(candidate):
|
||||
return candidate
|
||||
|
||||
suffix = 1
|
||||
while suffix <= 1000:
|
||||
alternative = f"{candidate}-{suffix}"
|
||||
alternative = f"{candidate}"
|
||||
if it.is_code_unique(alternative):
|
||||
return alternative
|
||||
suffix += 1
|
||||
@@ -6035,7 +6044,8 @@ def upload_item():
|
||||
is_grouped_sub_item=(position > 1),
|
||||
parent_item_id=parent_item_id,
|
||||
isbn=item_isbn,
|
||||
item_type=item_type
|
||||
item_type=item_type,
|
||||
library_category=library_category
|
||||
)
|
||||
if not item_id:
|
||||
break
|
||||
@@ -8101,7 +8111,7 @@ def admin_audit_export_pdf_official():
|
||||
])
|
||||
)
|
||||
|
||||
audit_rows = list(db['audit_log'].find(...).sort('chain_index', -1).limit(limit))
|
||||
audit_rows = list(db['audit_log'].find({}).sort('chain_index', -1).limit(limit))
|
||||
|
||||
# DEC_START: Decrypt sensitive fields for the PDF report
|
||||
for row in audit_rows:
|
||||
@@ -10953,8 +10963,7 @@ def reset_item(id):
|
||||
if result['success']:
|
||||
return jsonify({
|
||||
'success': True,
|
||||
'message': 'Item reset successfully',
|
||||
'details': result.get('details', {})
|
||||
'message': 'Item reset successfully'
|
||||
})
|
||||
else:
|
||||
return jsonify({
|
||||
|
||||
@@ -1235,5 +1235,5 @@ def reset_item_completely(item_id):
|
||||
except Exception as e:
|
||||
return {
|
||||
'success': False,
|
||||
'message': f'Fehler beim Zurücksetzen: {str(e)}'
|
||||
'message': f'Fehler beim Zurücksetzen.'
|
||||
}
|
||||
@@ -24,7 +24,7 @@ import Web.modules.database.settings as cfg
|
||||
from Web.modules.database.settings import MongoClient
|
||||
|
||||
|
||||
LIBRARY_ITEM_TYPES = ('book', 'cd', 'dvd', 'media')
|
||||
LIBRARY_ITEM_TYPES = ('book', 'cd', 'dvd', 'media', 'schulbuch')
|
||||
|
||||
|
||||
def _non_library_query(extra_query=None):
|
||||
@@ -49,7 +49,7 @@ def add_item(name, ort, beschreibung, images=None, filter=None, filter2=None, fi
|
||||
ansch_jahr=None, ansch_kost=None, code_4=None, reservierbar=True,
|
||||
series_group_id=None, series_count=1, series_position=1,
|
||||
is_grouped_sub_item=False, parent_item_id=None,
|
||||
isbn=None, item_type='general'):
|
||||
isbn=None, item_type='general', library_category=None):
|
||||
"""
|
||||
Add a new item to the inventory.
|
||||
|
||||
@@ -70,6 +70,9 @@ def add_item(name, ort, beschreibung, images=None, filter=None, filter2=None, fi
|
||||
series_position (int, optional): Position inside the batch (1-based)
|
||||
is_grouped_sub_item (bool, optional): Whether this item is hidden as sub-item
|
||||
parent_item_id (str, optional): Parent item id if this is a sub-item
|
||||
isbn (str, optional): ISBN for books or media items
|
||||
item_type (str, optional): Type of the item (e.g., 'general', 'book', 'cd')
|
||||
library_category (str, optional): Library category for the item
|
||||
|
||||
Returns:
|
||||
ObjectId: ID of the new item or None if failed
|
||||
@@ -97,6 +100,7 @@ def add_item(name, ort, beschreibung, images=None, filter=None, filter2=None, fi
|
||||
'Anschaffungskosten': ansch_kost,
|
||||
'Code_4': code_4,
|
||||
'ISBN': isbn,
|
||||
'library_category': library_category,
|
||||
'ItemType': item_type,
|
||||
'SeriesGroupId': series_group_id,
|
||||
'SeriesCount': series_count,
|
||||
@@ -196,7 +200,7 @@ def get_group_item_ids(id):
|
||||
|
||||
def update_item(id, name, ort, beschreibung, images=None, verfuegbar=True,
|
||||
filter=None, filter2=None, filter3=None, ansch_jahr=None, ansch_kost=None, code_4=None, reservierbar=True,
|
||||
isbn=None, item_type='general'):
|
||||
isbn=None, item_type='general', library_category=None):
|
||||
"""
|
||||
Update an existing inventory item.
|
||||
|
||||
@@ -214,7 +218,7 @@ def update_item(id, name, ort, beschreibung, images=None, verfuegbar=True,
|
||||
ansch_kost (float, optional): Cost of acquisition
|
||||
code_4 (str, optional): 4-digit identification code
|
||||
reservierbar (bool, optional): Whether the item can be reserved in advance
|
||||
|
||||
library_category (str, optional): Library category for the item
|
||||
Returns:
|
||||
bool: True if successful, False otherwise
|
||||
"""
|
||||
@@ -241,6 +245,7 @@ def update_item(id, name, ort, beschreibung, images=None, verfuegbar=True,
|
||||
'Anschaffungskosten': ansch_kost,
|
||||
'Code_4': code_4,
|
||||
'ISBN': isbn,
|
||||
'library_category': library_category,
|
||||
'ItemType': item_type,
|
||||
'LastUpdated': datetime.datetime.now()
|
||||
}
|
||||
|
||||
@@ -1057,7 +1057,7 @@
|
||||
document.getElementById('detailModal').style.display = 'none';
|
||||
}
|
||||
|
||||
// =========================================================================
|
||||
// =========================================================================
|
||||
// 5. EVENT LISTENERS INITIALIZATION & ON-LOAD INITIALIZER
|
||||
// =========================================================================
|
||||
function wireScannerUi() {
|
||||
|
||||
Reference in New Issue
Block a user