Auto-commit local changes before build (2026-03-20 10:22:35)
This commit is contained in:
parent
461c46b0ff
commit
af84039daf
@ -287,6 +287,10 @@ def upsert_cloud_connect_report(mail_message_id: int, html_body: str) -> dict:
|
|||||||
external_id=external_id,
|
external_id=external_id,
|
||||||
)
|
)
|
||||||
db.session.add(run)
|
db.session.add(run)
|
||||||
|
db.session.flush() # need run.id for object links
|
||||||
|
|
||||||
|
_persist_cc_objects(row, job.customer_id, job.id, run.id, report_dt)
|
||||||
|
|
||||||
counters["created"] += 1
|
counters["created"] += 1
|
||||||
counters["linked"] += 1
|
counters["linked"] += 1
|
||||||
|
|
||||||
@ -294,6 +298,86 @@ def upsert_cloud_connect_report(mail_message_id: int, html_body: str) -> dict:
|
|||||||
return counters
|
return counters
|
||||||
|
|
||||||
|
|
||||||
|
def _persist_cc_objects(
|
||||||
|
row: dict,
|
||||||
|
customer_id: int,
|
||||||
|
job_id: int,
|
||||||
|
run_id: int,
|
||||||
|
observed_at: datetime,
|
||||||
|
) -> None:
|
||||||
|
"""Upsert repository as a customer_object and create a run_object_link.
|
||||||
|
|
||||||
|
This mirrors the Cove datasource object persistence so Cloud Connect runs
|
||||||
|
have per-run object records suitable for reporting.
|
||||||
|
"""
|
||||||
|
from sqlalchemy import text as _text
|
||||||
|
|
||||||
|
repo_name = (row.get("repo_name") or "").strip() or "Unknown Repository"
|
||||||
|
repo_type = (row.get("repo_type") or "").strip()
|
||||||
|
object_name = f"{repo_name} ({repo_type})" if repo_type else repo_name
|
||||||
|
|
||||||
|
used = row.get("used_space") or ""
|
||||||
|
quota = row.get("total_quota") or ""
|
||||||
|
free = row.get("free_space") or ""
|
||||||
|
last = row.get("last_active_raw") or "unknown"
|
||||||
|
|
||||||
|
detail = f"Used: {used} / {quota} — Free: {free} — Last active: {last}"
|
||||||
|
|
||||||
|
try:
|
||||||
|
customer_object_id = db.session.execute(
|
||||||
|
_text("""
|
||||||
|
INSERT INTO customer_objects
|
||||||
|
(customer_id, object_name, object_type, first_seen_at, last_seen_at)
|
||||||
|
VALUES
|
||||||
|
(:customer_id, :object_name, :object_type, NOW(), NOW())
|
||||||
|
ON CONFLICT (customer_id, object_name)
|
||||||
|
DO UPDATE SET
|
||||||
|
object_type = COALESCE(EXCLUDED.object_type, customer_objects.object_type),
|
||||||
|
last_seen_at = NOW()
|
||||||
|
RETURNING id
|
||||||
|
"""),
|
||||||
|
{
|
||||||
|
"customer_id": customer_id,
|
||||||
|
"object_name": object_name,
|
||||||
|
"object_type": "cloud_connect_repo",
|
||||||
|
},
|
||||||
|
).scalar()
|
||||||
|
|
||||||
|
db.session.execute(
|
||||||
|
_text("""
|
||||||
|
INSERT INTO job_object_links
|
||||||
|
(job_id, customer_object_id, first_seen_at, last_seen_at)
|
||||||
|
VALUES (:job_id, :customer_object_id, NOW(), NOW())
|
||||||
|
ON CONFLICT (job_id, customer_object_id)
|
||||||
|
DO UPDATE SET last_seen_at = NOW()
|
||||||
|
"""),
|
||||||
|
{"job_id": job_id, "customer_object_id": customer_object_id},
|
||||||
|
)
|
||||||
|
|
||||||
|
db.session.execute(
|
||||||
|
_text("""
|
||||||
|
INSERT INTO run_object_links
|
||||||
|
(run_id, customer_object_id, status, error_message, observed_at)
|
||||||
|
VALUES
|
||||||
|
(:run_id, :customer_object_id, :status, :error_message, :observed_at)
|
||||||
|
ON CONFLICT (run_id, customer_object_id)
|
||||||
|
DO UPDATE SET
|
||||||
|
status = EXCLUDED.status,
|
||||||
|
error_message = EXCLUDED.error_message,
|
||||||
|
observed_at = EXCLUDED.observed_at
|
||||||
|
"""),
|
||||||
|
{
|
||||||
|
"run_id": run_id,
|
||||||
|
"customer_object_id": customer_object_id,
|
||||||
|
"status": row["status"],
|
||||||
|
"error_message": detail,
|
||||||
|
"observed_at": observed_at,
|
||||||
|
},
|
||||||
|
)
|
||||||
|
except Exception as exc:
|
||||||
|
logger.warning("CC object persist failed for run %s: %s", run_id, exc)
|
||||||
|
|
||||||
|
|
||||||
def _build_error_message(row: dict) -> str:
|
def _build_error_message(row: dict) -> str:
|
||||||
"""Build a human-readable remark for a Cloud Connect run."""
|
"""Build a human-readable remark for a Cloud Connect run."""
|
||||||
parts = [
|
parts = [
|
||||||
|
|||||||
@ -1494,7 +1494,7 @@ def run_checks_details():
|
|||||||
"last_active": _cc_acc.last_active_raw or "",
|
"last_active": _cc_acc.last_active_raw or "",
|
||||||
"status": _cc_acc.last_status or "",
|
"status": _cc_acc.last_status or "",
|
||||||
}
|
}
|
||||||
# Keep mail meta and EML link for audit trail; skip body HTML.
|
# Keep mail meta, EML link, and body for the collapsible source panel.
|
||||||
if msg:
|
if msg:
|
||||||
mail_meta = {
|
mail_meta = {
|
||||||
"from_address": msg.from_address or "",
|
"from_address": msg.from_address or "",
|
||||||
@ -1508,7 +1508,7 @@ def run_checks_details():
|
|||||||
"subject": msg.subject or "",
|
"subject": msg.subject or "",
|
||||||
"received_at": _format_datetime(msg.received_at),
|
"received_at": _format_datetime(msg.received_at),
|
||||||
}
|
}
|
||||||
if msg and cloud_connect_summary is None:
|
if msg:
|
||||||
def _is_blank_text(s):
|
def _is_blank_text(s):
|
||||||
return s is None or (isinstance(s, str) and s.strip() == "")
|
return s is None or (isinstance(s, str) and s.strip() == "")
|
||||||
|
|
||||||
@ -1584,7 +1584,8 @@ def run_checks_details():
|
|||||||
)
|
)
|
||||||
|
|
||||||
# If no run-linked objects exist yet, fall back to objects parsed/stored on the mail message.
|
# If no run-linked objects exist yet, fall back to objects parsed/stored on the mail message.
|
||||||
if (not objects_payload) and msg:
|
# Skip this fallback for cloud_connect runs: the mail contains all tenants, not just this one.
|
||||||
|
if (not objects_payload) and msg and getattr(run, "source_type", None) != "cloud_connect":
|
||||||
try:
|
try:
|
||||||
for mo in (
|
for mo in (
|
||||||
MailObject.query.filter_by(mail_message_id=msg.id)
|
MailObject.query.filter_by(mail_message_id=msg.id)
|
||||||
|
|||||||
@ -318,9 +318,9 @@
|
|||||||
</dd>
|
</dd>
|
||||||
</dl>
|
</dl>
|
||||||
|
|
||||||
<div class="mb-3 rcm-mail-panel" id="rcm_cc_summary_panel" style="display:none;">
|
<div class="mb-3" id="rcm_cc_summary_panel" style="display:none;">
|
||||||
<h6>Cloud Connect</h6>
|
<h6>Cloud Connect</h6>
|
||||||
<dl class="row mb-0 dl-compact" id="rcm_cc_summary_dl">
|
<dl class="row mb-0 dl-compact">
|
||||||
<dt class="col-4">User</dt> <dd class="col-8" id="rcc_user"></dd>
|
<dt class="col-4">User</dt> <dd class="col-8" id="rcc_user"></dd>
|
||||||
<dt class="col-4">Section</dt> <dd class="col-8" id="rcc_section"></dd>
|
<dt class="col-4">Section</dt> <dd class="col-8" id="rcc_section"></dd>
|
||||||
<dt class="col-4">Repository</dt> <dd class="col-8" id="rcc_repo"></dd>
|
<dt class="col-4">Repository</dt> <dd class="col-8" id="rcc_repo"></dd>
|
||||||
@ -332,7 +332,18 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="mb-3 rcm-mail-panel" id="rcm_mail_iframe_panel">
|
<div class="mb-3 rcm-mail-panel" id="rcm_mail_iframe_panel">
|
||||||
<h6>Mail</h6>
|
<div class="d-flex align-items-center gap-2 mb-1">
|
||||||
|
<h6 class="mb-0" id="rcm_mail_heading">Mail</h6>
|
||||||
|
<a href="#" class="small text-muted" id="rcm_mail_toggle" style="display:none;"
|
||||||
|
onclick="(function(){
|
||||||
|
var b=document.getElementById('rcm_mail_iframe_body');
|
||||||
|
var lnk=document.getElementById('rcm_mail_toggle');
|
||||||
|
var collapsed=b.style.display==='none';
|
||||||
|
b.style.display=collapsed?'':'none';
|
||||||
|
lnk.textContent=collapsed?'hide':'show';
|
||||||
|
})();return false;">show</a>
|
||||||
|
</div>
|
||||||
|
<div id="rcm_mail_iframe_body">
|
||||||
<iframe
|
<iframe
|
||||||
id="rcm_body_iframe"
|
id="rcm_body_iframe"
|
||||||
class="border rounded"
|
class="border rounded"
|
||||||
@ -341,6 +352,7 @@
|
|||||||
referrerpolicy="no-referrer"
|
referrerpolicy="no-referrer"
|
||||||
></iframe>
|
></iframe>
|
||||||
</div>
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
<div>
|
<div>
|
||||||
<div class="table-responsive rcm-objects-scroll">
|
<div class="table-responsive rcm-objects-scroll">
|
||||||
@ -1435,7 +1447,9 @@ table.addEventListener('change', function (e) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
var ccPanel = document.getElementById('rcm_cc_summary_panel');
|
var ccPanel = document.getElementById('rcm_cc_summary_panel');
|
||||||
var iframePanel = document.getElementById('rcm_mail_iframe_panel');
|
var mailHeading = document.getElementById('rcm_mail_heading');
|
||||||
|
var mailToggle = document.getElementById('rcm_mail_toggle');
|
||||||
|
var mailBody = document.getElementById('rcm_mail_iframe_body');
|
||||||
var bodyFrame = document.getElementById('rcm_body_iframe');
|
var bodyFrame = document.getElementById('rcm_body_iframe');
|
||||||
|
|
||||||
if (run.cloud_connect_summary) {
|
if (run.cloud_connect_summary) {
|
||||||
@ -1448,10 +1462,16 @@ table.addEventListener('change', function (e) {
|
|||||||
document.getElementById('rcc_last_active').textContent = s.last_active || '—';
|
document.getElementById('rcc_last_active').textContent = s.last_active || '—';
|
||||||
document.getElementById('rcc_status').textContent = s.status || '—';
|
document.getElementById('rcc_status').textContent = s.status || '—';
|
||||||
if (ccPanel) ccPanel.style.display = '';
|
if (ccPanel) ccPanel.style.display = '';
|
||||||
if (iframePanel) iframePanel.style.display = 'none';
|
if (mailHeading) mailHeading.textContent = 'Source report email';
|
||||||
|
if (mailToggle) mailToggle.style.display = '';
|
||||||
|
if (mailToggle) mailToggle.textContent = 'show';
|
||||||
|
if (mailBody) mailBody.style.display = 'none';
|
||||||
|
if (bodyFrame) bodyFrame.srcdoc = wrapMailHtml(run.body_html || '');
|
||||||
} else {
|
} else {
|
||||||
if (ccPanel) ccPanel.style.display = 'none';
|
if (ccPanel) ccPanel.style.display = 'none';
|
||||||
if (iframePanel) iframePanel.style.display = '';
|
if (mailHeading) mailHeading.textContent = 'Mail';
|
||||||
|
if (mailToggle) mailToggle.style.display = 'none';
|
||||||
|
if (mailBody) mailBody.style.display = '';
|
||||||
if (bodyFrame) {
|
if (bodyFrame) {
|
||||||
bodyFrame.srcdoc = wrapMailHtml(run.body_html || (run.missed ? '<div class="text-muted">No email for missed run.</div>' : ''));
|
bodyFrame.srcdoc = wrapMailHtml(run.body_html || (run.missed ? '<div class="text-muted">No email for missed run.</div>' : ''));
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user