Optim: fix N+1 queries itop_service (pre-load batch) + macros Jinja2 badges
This commit is contained in:
parent
a0f90cd719
commit
9a72fa7eb7
@ -144,63 +144,63 @@ def sync_from_itop(db, itop_url, itop_user, itop_pass):
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
# ─── 1. Typologies: Environnements ───
|
||||
# ─── 1. Typologies: Environnements (batch) ───
|
||||
existing_envs = {r.name.lower() for r in db.execute(text("SELECT name FROM environments")).fetchall()}
|
||||
for item in client.get_all("Environnement", "name"):
|
||||
name = item.get("name", "")
|
||||
if not name:
|
||||
if not name or name.lower() in existing_envs:
|
||||
continue
|
||||
existing = db.execute(text("SELECT id FROM environments WHERE LOWER(name)=LOWER(:n)"), {"n": name}).fetchone()
|
||||
if not existing:
|
||||
try:
|
||||
db.execute(text("INSERT INTO environments (name, code) VALUES (:n, :c)"),
|
||||
{"n": name, "c": name[:10].upper().replace(" ", "").replace("-", "")})
|
||||
db.commit()
|
||||
stats["environments"] += 1
|
||||
except Exception:
|
||||
db.rollback()
|
||||
try:
|
||||
db.execute(text("INSERT INTO environments (name, code) VALUES (:n, :c)"),
|
||||
{"n": name, "c": name[:10].upper().replace(" ", "").replace("-", "")})
|
||||
existing_envs.add(name.lower())
|
||||
stats["environments"] += 1
|
||||
except Exception:
|
||||
db.rollback()
|
||||
db.commit()
|
||||
|
||||
# ─── 2. Typologies: Domaines applicatifs ───
|
||||
# ─── 2. Typologies: Domaines applicatifs (batch) ───
|
||||
existing_doms = {r.name.lower() for r in db.execute(text("SELECT name FROM domains")).fetchall()}
|
||||
for item in client.get_all("DomaineApplicatif", "name"):
|
||||
name = item.get("name", "")
|
||||
if not name:
|
||||
if not name or name.lower() in existing_doms:
|
||||
continue
|
||||
existing = db.execute(text("SELECT id FROM domains WHERE LOWER(name)=LOWER(:n)"), {"n": name}).fetchone()
|
||||
if not existing:
|
||||
try:
|
||||
db.execute(text("INSERT INTO domains (name, code) VALUES (:n, :c)"),
|
||||
{"n": name, "c": name[:10].upper().replace(" ", "")})
|
||||
db.commit()
|
||||
stats["domains"] += 1
|
||||
except Exception:
|
||||
db.rollback()
|
||||
try:
|
||||
db.execute(text("INSERT INTO domains (name, code) VALUES (:n, :c)"),
|
||||
{"n": name, "c": name[:10].upper().replace(" ", "")})
|
||||
existing_doms.add(name.lower())
|
||||
stats["domains"] += 1
|
||||
except Exception:
|
||||
db.rollback()
|
||||
db.commit()
|
||||
|
||||
# ─── 3. Typologies: Zones ───
|
||||
# ─── 3. Typologies: Zones (batch) ───
|
||||
existing_zones = {r.name.lower() for r in db.execute(text("SELECT name FROM zones")).fetchall()}
|
||||
for item in client.get_all("Zone", "name"):
|
||||
name = item.get("name", "")
|
||||
if not name:
|
||||
if not name or name.lower() in existing_zones:
|
||||
continue
|
||||
existing = db.execute(text("SELECT id FROM zones WHERE LOWER(name)=LOWER(:n)"), {"n": name}).fetchone()
|
||||
if not existing:
|
||||
try:
|
||||
db.execute(text("INSERT INTO zones (name, is_dmz) VALUES (:n, :d)"),
|
||||
{"n": name, "d": "dmz" in name.lower()})
|
||||
db.commit()
|
||||
stats["zones"] += 1
|
||||
except Exception:
|
||||
db.rollback()
|
||||
try:
|
||||
db.execute(text("INSERT INTO zones (name, is_dmz) VALUES (:n, :d)"),
|
||||
{"n": name, "d": "dmz" in name.lower()})
|
||||
existing_zones.add(name.lower())
|
||||
stats["zones"] += 1
|
||||
except Exception:
|
||||
db.rollback()
|
||||
db.commit()
|
||||
|
||||
# ─── 4. Typologies: DomainLdap → domain_ltd_list ───
|
||||
# ─── 4. Typologies: DomainLdap → domain_ltd_list (batch) ───
|
||||
existing_ltd = {r.name.lower() for r in db.execute(text("SELECT name FROM domain_ltd_list")).fetchall()}
|
||||
for item in client.get_all("DomainLdap", "name"):
|
||||
name = item.get("name", "")
|
||||
if not name:
|
||||
if not name or name.lower() in existing_ltd:
|
||||
continue
|
||||
existing = db.execute(text("SELECT id FROM domain_ltd_list WHERE LOWER(name)=LOWER(:n)"), {"n": name}).fetchone()
|
||||
if not existing:
|
||||
try:
|
||||
db.execute(text("INSERT INTO domain_ltd_list (name) VALUES (:n)"), {"n": name})
|
||||
db.commit()
|
||||
except Exception:
|
||||
db.rollback()
|
||||
try:
|
||||
db.execute(text("INSERT INTO domain_ltd_list (name) VALUES (:n)"), {"n": name})
|
||||
existing_ltd.add(name.lower())
|
||||
except Exception:
|
||||
db.rollback()
|
||||
db.commit()
|
||||
|
||||
# ─── 5. Contacts + Teams (filtre périmètre IT uniquement) ───
|
||||
persons = client.get_all("Person", "name,first_name,email,phone,org_name,function,status")
|
||||
@ -233,6 +233,9 @@ def sync_from_itop(db, itop_url, itop_user, itop_pass):
|
||||
seen_emails = set()
|
||||
stats["contacts_deactivated"] = 0
|
||||
|
||||
contacts_by_email = {}
|
||||
for r in db.execute(text("SELECT id, email FROM contacts")).fetchall():
|
||||
contacts_by_email[r.email.lower()] = r
|
||||
for p in persons:
|
||||
fullname = f"{p.get('first_name','')} {p.get('name','')}".strip()
|
||||
email = p.get("email", "")
|
||||
@ -254,7 +257,7 @@ def sync_from_itop(db, itop_url, itop_user, itop_pass):
|
||||
seen_itop_ids.add(int(itop_id))
|
||||
seen_emails.add(email.lower())
|
||||
|
||||
existing = db.execute(text("SELECT id FROM contacts WHERE LOWER(email)=LOWER(:e)"), {"e": email}).fetchone()
|
||||
existing = contacts_by_email.get(email.lower())
|
||||
if existing:
|
||||
db.execute(text("""UPDATE contacts SET name=:n, role=:r, itop_id=:iid,
|
||||
telephone=:tel, team=:t, function=:f, is_active=:a, updated_at=NOW() WHERE id=:id"""),
|
||||
@ -292,6 +295,9 @@ def sync_from_itop(db, itop_url, itop_user, itop_pass):
|
||||
|
||||
# Person name → email lookup
|
||||
person_email = {}
|
||||
contacts_by_email = {}
|
||||
for r in db.execute(text("SELECT id, email FROM contacts")).fetchall():
|
||||
contacts_by_email[r.email.lower()] = r
|
||||
for p in persons:
|
||||
fullname = f"{p.get('first_name','')} {p.get('name','')}".strip()
|
||||
person_email[fullname.lower()] = p.get("email", "")
|
||||
|
||||
33
app/templates/macros.html
Normal file
33
app/templates/macros.html
Normal file
@ -0,0 +1,33 @@
|
||||
{% macro badge_etat(etat) -%}
|
||||
<span class="badge {% if etat == 'Production' %}badge-green{% elif etat == 'Recette' %}badge-yellow{% elif etat == 'Decommissioned' %}badge-red{% else %}badge-gray{% endif %}" title="{{ etat or '' }}">{{ (etat or '-')[:6] }}</span>
|
||||
{%- endmacro %}
|
||||
|
||||
{% macro badge_env(env) -%}
|
||||
<span class="badge {% if env == 'Production' %}badge-green{% elif env == 'Recette' %}badge-yellow{% else %}badge-gray{% endif %}" title="{{ env or '' }}">{{ (env or '-')[:6] }}</span>
|
||||
{%- endmacro %}
|
||||
|
||||
{% macro badge_os(os) -%}
|
||||
<span class="text-gray-400">{{ (os or '-')[:6] }}</span>
|
||||
{%- endmacro %}
|
||||
|
||||
{% macro badge_zone(zone) -%}
|
||||
<span class="badge {% if zone == 'DMZ' %}badge-red{% else %}badge-gray{% endif %}">{{ zone or '-' }}</span>
|
||||
{%- endmacro %}
|
||||
|
||||
{% macro badge_status(status) -%}
|
||||
<span class="badge {% if status in ('ok','patched','validated_ok','active','open') %}badge-green{% elif status in ('ko','failed','validated_ko','closed','freeze') %}badge-red{% elif status in ('en_attente','pending','wip','in_progress') %}badge-yellow{% else %}badge-gray{% endif %}">{{ status or '-' }}</span>
|
||||
{%- endmacro %}
|
||||
|
||||
{% macro badge_source(source_type, campaign_id=None, campaign_label=None, run_id=None, run_label=None) -%}
|
||||
{% if source_type == 'import' %}<span class="badge" style="background:#1e3a5f;color:#60a5fa;">xlsx</span>
|
||||
{% elif source_type == 'standard' %}<a href="/campaigns/{{ campaign_id }}" class="badge" style="background:#164e63;color:#22d3ee;text-decoration:none">{{ campaign_label or 'Campagne' }}</a>
|
||||
{% elif source_type == 'quickwin' %}<a href="/quickwin/{{ run_id }}" class="badge" style="background:#3b1f5e;color:#c084fc;text-decoration:none">{{ run_label or 'QuickWin' }}</a>
|
||||
{% else %}<span class="badge badge-gray">{{ source_type or '?' }}</span>{% endif %}
|
||||
{%- endmacro %}
|
||||
|
||||
{% macro filter_select(name, label, options, selected) -%}
|
||||
<select name="{{ name }}" class="text-xs py-1 px-2">
|
||||
<option value="">{{ label }}</option>
|
||||
{% for o in options %}<option value="{{ o }}" {% if selected == o %}selected{% endif %}>{{ o }}</option>{% endfor %}
|
||||
</select>
|
||||
{%- endmacro %}
|
||||
Loading…
Reference in New Issue
Block a user