124 lines
No EOL
4.5 KiB
Python
124 lines
No EOL
4.5 KiB
Python
import uuid
|
||
import time
|
||
|
||
from typing import Iterable
|
||
|
||
class InterventionDraftManager:
|
||
SESSION_KEY = 'intervention_drafts'
|
||
EXPIRATION_SECONDS = 3600 # 1h
|
||
|
||
def __init__(self, session):
|
||
self.session = session
|
||
if self.SESSION_KEY not in self.session:
|
||
self.session[self.SESSION_KEY] = {}
|
||
|
||
def _touch(self, draft):
|
||
draft['timestamp'] = time.time()
|
||
self.session.modified = True
|
||
|
||
def get_or_create(self, draft_id=None):
|
||
self.cleanup()
|
||
drafts = self.session[self.SESSION_KEY]
|
||
if not draft_id or draft_id not in drafts:
|
||
draft_id = str(uuid.uuid4())
|
||
drafts[draft_id] = {
|
||
'form_data': {},
|
||
'assets': [], # liste d'objets {"model","object_id"}
|
||
'locations': [], # si besoin, même principe {"id": ...} ou {"model","object_id"}
|
||
'timestamp': time.time()
|
||
}
|
||
self.session.modified = True
|
||
return draft_id
|
||
|
||
def get(self, draft_id):
|
||
self.cleanup()
|
||
return self.session[self.SESSION_KEY].get(draft_id, {})
|
||
|
||
def update_form_data(self, draft_id, form_data: dict):
|
||
draft = self.get(draft_id)
|
||
if draft:
|
||
draft['form_data'] = form_data or {}
|
||
self._touch(draft)
|
||
|
||
# --- Helpers de normalisation ---
|
||
@staticmethod
|
||
def _norm_assets(items: Iterable):
|
||
"""Normalise en [{'model': str, 'object_id': int}, ...] + dédup."""
|
||
norm = []
|
||
seen = set()
|
||
for i, a in enumerate(items or []):
|
||
if isinstance(a, dict) and 'model' in a and 'object_id' in a:
|
||
model = str(a['model']).lower().strip()
|
||
oid = int(a['object_id'])
|
||
key = (model, oid)
|
||
if key not in seen:
|
||
seen.add(key)
|
||
norm.append({'model': model, 'object_id': oid, 'asset_type': model})
|
||
else:
|
||
# Compat : si ancien format [id, id, ...], on ignore (impossible d’inférer le model)
|
||
# => à migrer côté appelant
|
||
continue
|
||
return norm
|
||
|
||
def update_assets(self, draft_id, assets_list):
|
||
draft = self.get(draft_id)
|
||
if draft is not None:
|
||
draft['assets'] = self._norm_assets(assets_list)
|
||
self._touch(draft)
|
||
|
||
def update_locations(self, draft_id, locations_ids):
|
||
draft = self.get(draft_id)
|
||
if draft is not None:
|
||
ids = []
|
||
for x in (locations_ids or []):
|
||
try:
|
||
v = int(str(x).strip()) # gère '', ' 12 ', etc.
|
||
except (ValueError, TypeError):
|
||
continue # ignore les invalides
|
||
if v > 0: # optionnel: n'autoriser que des ids positifs
|
||
ids.append(v)
|
||
draft['locations'] = ids
|
||
self._touch(draft)
|
||
|
||
def remove_location(self, draft_id, location_id):
|
||
"""Supprime une localisation spécifique du draft"""
|
||
draft = self.get(draft_id)
|
||
if draft is not None:
|
||
try:
|
||
location_id = int(location_id)
|
||
draft['locations'] = [loc_id for loc_id in draft.get('locations', []) if loc_id != location_id]
|
||
self._touch(draft)
|
||
return True
|
||
except (ValueError, TypeError):
|
||
return False
|
||
return False
|
||
|
||
def remove_asset(self, draft_id, asset_model, asset_id):
|
||
"""Supprime un asset spécifique du draft"""
|
||
draft = self.get(draft_id)
|
||
if draft is not None:
|
||
try:
|
||
asset_id = int(asset_id)
|
||
asset_model = str(asset_model).lower().strip()
|
||
draft['assets'] = [
|
||
a for a in draft.get('assets', [])
|
||
if not (a.get('model') == asset_model and a.get('object_id') == asset_id)
|
||
]
|
||
self._touch(draft)
|
||
return True
|
||
except (ValueError, TypeError):
|
||
return False
|
||
return False
|
||
|
||
def delete(self, draft_id):
|
||
self.session[self.SESSION_KEY].pop(draft_id, None)
|
||
self.session.modified = True
|
||
|
||
def cleanup(self):
|
||
now = time.time()
|
||
expired = [k for k, v in self.session[self.SESSION_KEY].items()
|
||
if v.get('timestamp', 0) < now - self.EXPIRATION_SECONDS]
|
||
for k in expired:
|
||
self.session[self.SESSION_KEY].pop(k, None)
|
||
if expired:
|
||
self.session.modified = True |