fixed, scheduler, added search to log, added advanced search
This commit is contained in:
parent
076733fb53
commit
66b32ded36
19
app/main.py
19
app/main.py
|
|
@ -52,6 +52,25 @@ app.include_router(yaml_sync.router)
|
|||
app.include_router(logs.router)
|
||||
|
||||
|
||||
# --- API: Scheduler-Status ---
|
||||
|
||||
|
||||
@app.get("/api/scheduler/status")
|
||||
def scheduler_status():
|
||||
from app.services.scheduler import scheduler
|
||||
jobs = []
|
||||
for job in scheduler.get_jobs():
|
||||
jobs.append({
|
||||
"id": job.id,
|
||||
"next_run": job.next_run_time.isoformat() if job.next_run_time else None,
|
||||
"interval": str(job.trigger),
|
||||
})
|
||||
return {
|
||||
"running": scheduler.running,
|
||||
"jobs": jobs,
|
||||
}
|
||||
|
||||
|
||||
# --- Web-UI Routen ---
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -46,6 +46,8 @@ def create_account(data: AccountCreate, db: Session = Depends(get_db)):
|
|||
db.add(account)
|
||||
db.commit()
|
||||
db.refresh(account)
|
||||
from app.services.scheduler import add_account_job
|
||||
add_account_job(account)
|
||||
return account
|
||||
|
||||
|
||||
|
|
@ -62,6 +64,8 @@ def update_account(account_id: int, data: AccountUpdate, db: Session = Depends(g
|
|||
setattr(account, key, value)
|
||||
db.commit()
|
||||
db.refresh(account)
|
||||
from app.services.scheduler import add_account_job
|
||||
add_account_job(account)
|
||||
return account
|
||||
|
||||
|
||||
|
|
@ -70,6 +74,8 @@ def delete_account(account_id: int, db: Session = Depends(get_db)):
|
|||
account = db.get(Account, account_id)
|
||||
if not account:
|
||||
raise HTTPException(404, "Konto nicht gefunden")
|
||||
from app.services.scheduler import remove_account_job
|
||||
remove_account_job(account_id)
|
||||
db.delete(account)
|
||||
db.commit()
|
||||
|
||||
|
|
|
|||
|
|
@ -11,6 +11,13 @@ router = APIRouter(prefix="/api/logs", tags=["logs"])
|
|||
def get_logs(
|
||||
account_id: int | None = None,
|
||||
level: str | None = None,
|
||||
search: str | None = None,
|
||||
search_subject: str | None = None,
|
||||
search_from: str | None = None,
|
||||
search_rule: str | None = None,
|
||||
search_message: str | None = None,
|
||||
search_details: str | None = None,
|
||||
search_folder: str | None = None,
|
||||
limit: int = Query(default=100, le=500),
|
||||
offset: int = 0,
|
||||
db: Session = Depends(get_db),
|
||||
|
|
@ -20,6 +27,30 @@ def get_logs(
|
|||
query = query.filter(FilterLog.account_id == account_id)
|
||||
if level:
|
||||
query = query.filter(FilterLog.level == level)
|
||||
# Einfache Suche (ODER über alle Felder)
|
||||
if search:
|
||||
term = f"%{search}%"
|
||||
query = query.filter(
|
||||
FilterLog.message.ilike(term)
|
||||
| FilterLog.mail_subject.ilike(term)
|
||||
| FilterLog.mail_from.ilike(term)
|
||||
| FilterLog.rule_name.ilike(term)
|
||||
| FilterLog.details.ilike(term)
|
||||
| FilterLog.folder.ilike(term)
|
||||
)
|
||||
# Erweiterte Suche (UND pro Feld)
|
||||
if search_subject:
|
||||
query = query.filter(FilterLog.mail_subject.ilike(f"%{search_subject}%"))
|
||||
if search_from:
|
||||
query = query.filter(FilterLog.mail_from.ilike(f"%{search_from}%"))
|
||||
if search_rule:
|
||||
query = query.filter(FilterLog.rule_name.ilike(f"%{search_rule}%"))
|
||||
if search_message:
|
||||
query = query.filter(FilterLog.message.ilike(f"%{search_message}%"))
|
||||
if search_details:
|
||||
query = query.filter(FilterLog.details.ilike(f"%{search_details}%"))
|
||||
if search_folder:
|
||||
query = query.filter(FilterLog.folder.ilike(f"%{search_folder}%"))
|
||||
total = query.count()
|
||||
logs = query.offset(offset).limit(limit).all()
|
||||
return {
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@
|
|||
{% block content %}
|
||||
<h1>Verarbeitungslog</h1>
|
||||
|
||||
<div style="display:flex; gap:1rem; align-items:end; flex-wrap:wrap; margin-bottom:1rem;">
|
||||
<div style="display:flex; gap:1rem; align-items:end; flex-wrap:wrap; margin-bottom:0.5rem;">
|
||||
<label style="margin-bottom:0;">
|
||||
Konto
|
||||
<select id="log-account" onchange="loadLogs()" style="margin-bottom:0;">
|
||||
|
|
@ -23,16 +23,56 @@
|
|||
<option value="error">Fehler</option>
|
||||
</select>
|
||||
</label>
|
||||
<label style="margin-bottom:0; flex:1; min-width:200px;">
|
||||
Schnellsuche
|
||||
<input type="search" id="log-search" placeholder="überall suchen..." style="margin-bottom:0;" onkeydown="if(event.key==='Enter') loadLogs()">
|
||||
</label>
|
||||
<div role="group" style="margin-bottom:0;">
|
||||
<button class="outline small" onclick="loadLogs()">Aktualisieren</button>
|
||||
<button class="outline small" onclick="loadLogs()">Suchen</button>
|
||||
<button class="outline small contrast" onclick="clearLogs()">Log leeren</button>
|
||||
</div>
|
||||
<label style="margin-bottom:0; margin-left:auto;">
|
||||
<label style="margin-bottom:0;">
|
||||
<input type="checkbox" id="auto-refresh" onchange="toggleAutoRefresh()" style="margin-bottom:0;">
|
||||
Auto-Refresh (5s)
|
||||
</label>
|
||||
</div>
|
||||
|
||||
<details style="margin-bottom:1rem;">
|
||||
<summary>Erweiterte Suche (UND-verknüpft)</summary>
|
||||
<div class="grid" style="margin-top:0.5rem;">
|
||||
<label style="margin-bottom:0;">
|
||||
Betreff
|
||||
<input type="search" id="search-subject" placeholder="z.B. Rechnung" style="margin-bottom:0;" onkeydown="if(event.key==='Enter') loadLogs()">
|
||||
</label>
|
||||
<label style="margin-bottom:0;">
|
||||
Absender
|
||||
<input type="search" id="search-from" placeholder="z.B. shop@example.com" style="margin-bottom:0;" onkeydown="if(event.key==='Enter') loadLogs()">
|
||||
</label>
|
||||
<label style="margin-bottom:0;">
|
||||
Regel
|
||||
<input type="search" id="search-rule" placeholder="z.B. Newsletter" style="margin-bottom:0;" onkeydown="if(event.key==='Enter') loadLogs()">
|
||||
</label>
|
||||
</div>
|
||||
<div class="grid" style="margin-top:0.5rem;">
|
||||
<label style="margin-bottom:0;">
|
||||
Nachricht
|
||||
<input type="search" id="search-message" placeholder="z.B. Aktion ausgeführt" style="margin-bottom:0;" onkeydown="if(event.key==='Enter') loadLogs()">
|
||||
</label>
|
||||
<label style="margin-bottom:0;">
|
||||
Details
|
||||
<input type="search" id="search-details" placeholder="z.B. TREFFER" style="margin-bottom:0;" onkeydown="if(event.key==='Enter') loadLogs()">
|
||||
</label>
|
||||
<label style="margin-bottom:0;">
|
||||
Ordner
|
||||
<input type="search" id="search-folder" placeholder="z.B. INBOX" style="margin-bottom:0;" onkeydown="if(event.key==='Enter') loadLogs()">
|
||||
</label>
|
||||
</div>
|
||||
<div style="margin-top:0.5rem;">
|
||||
<button class="outline small" onclick="loadLogs()">Erweitert suchen</button>
|
||||
<button class="outline small contrast" onclick="clearAdvancedSearch()">Felder leeren</button>
|
||||
</div>
|
||||
</details>
|
||||
|
||||
<div id="log-stats" style="margin-bottom:1rem;"></div>
|
||||
|
||||
<div id="log-container">
|
||||
|
|
@ -85,9 +125,24 @@ async function loadLogs(offset = 0) {
|
|||
const level = document.getElementById('log-level').value;
|
||||
const container = document.getElementById('log-container');
|
||||
|
||||
const search = document.getElementById('log-search').value.trim();
|
||||
const searchSubject = document.getElementById('search-subject').value.trim();
|
||||
const searchFrom = document.getElementById('search-from').value.trim();
|
||||
const searchRule = document.getElementById('search-rule').value.trim();
|
||||
const searchMessage = document.getElementById('search-message').value.trim();
|
||||
const searchDetails = document.getElementById('search-details').value.trim();
|
||||
const searchFolder = document.getElementById('search-folder').value.trim();
|
||||
|
||||
let url = `/api/logs/?limit=${PAGE_SIZE}&offset=${offset}`;
|
||||
if (accountId) url += `&account_id=${accountId}`;
|
||||
if (level) url += `&level=${level}`;
|
||||
if (search) url += `&search=${encodeURIComponent(search)}`;
|
||||
if (searchSubject) url += `&search_subject=${encodeURIComponent(searchSubject)}`;
|
||||
if (searchFrom) url += `&search_from=${encodeURIComponent(searchFrom)}`;
|
||||
if (searchRule) url += `&search_rule=${encodeURIComponent(searchRule)}`;
|
||||
if (searchMessage) url += `&search_message=${encodeURIComponent(searchMessage)}`;
|
||||
if (searchDetails) url += `&search_details=${encodeURIComponent(searchDetails)}`;
|
||||
if (searchFolder) url += `&search_folder=${encodeURIComponent(searchFolder)}`;
|
||||
|
||||
try {
|
||||
const resp = await fetch(url);
|
||||
|
|
@ -196,6 +251,16 @@ function escapeHtml(text) {
|
|||
return div.innerHTML;
|
||||
}
|
||||
|
||||
function clearAdvancedSearch() {
|
||||
document.getElementById('search-subject').value = '';
|
||||
document.getElementById('search-from').value = '';
|
||||
document.getElementById('search-rule').value = '';
|
||||
document.getElementById('search-message').value = '';
|
||||
document.getElementById('search-details').value = '';
|
||||
document.getElementById('search-folder').value = '';
|
||||
loadLogs();
|
||||
}
|
||||
|
||||
// Initial load
|
||||
loadLogs();
|
||||
</script>
|
||||
|
|
|
|||
Loading…
Reference in New Issue