Wording: Domain sperren → Domain ausschließen
Einheitliche Umbenennung in UI-Texten, Kommentaren und Docstrings: - Sperren → Ausschließen - Gesperrt → Ausgeschlossen - Entsperren → Ausschluss aufheben Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Dieser Commit ist enthalten in:
@@ -150,7 +150,7 @@ class DiscoverMultiResponse(BaseModel):
|
|||||||
fallback_single: bool = False
|
fallback_single: bool = False
|
||||||
|
|
||||||
|
|
||||||
# Domain-Aktionen (Sperren/Entsperren)
|
# Domain-Aktionen (Ausschließen/Ausschluss aufheben)
|
||||||
class DomainActionRequest(BaseModel):
|
class DomainActionRequest(BaseModel):
|
||||||
domain: str = Field(min_length=1, max_length=200)
|
domain: str = Field(min_length=1, max_length=200)
|
||||||
notes: Optional[str] = None
|
notes: Optional[str] = None
|
||||||
|
|||||||
@@ -291,7 +291,7 @@ async def block_domain(
|
|||||||
current_user: dict = Depends(get_current_user),
|
current_user: dict = Depends(get_current_user),
|
||||||
db: aiosqlite.Connection = Depends(db_dependency),
|
db: aiosqlite.Connection = Depends(db_dependency),
|
||||||
):
|
):
|
||||||
"""Domain sperren: Alle Feeds deaktivieren + excluded-Eintrag anlegen."""
|
"""Domain ausschließen: Alle Feeds deaktivieren + excluded-Eintrag anlegen."""
|
||||||
tenant_id = current_user.get("tenant_id")
|
tenant_id = current_user.get("tenant_id")
|
||||||
domain = data.domain.lower().strip()
|
domain = data.domain.lower().strip()
|
||||||
username = current_user["username"]
|
username = current_user["username"]
|
||||||
@@ -351,7 +351,7 @@ async def unblock_domain(
|
|||||||
current_user: dict = Depends(get_current_user),
|
current_user: dict = Depends(get_current_user),
|
||||||
db: aiosqlite.Connection = Depends(db_dependency),
|
db: aiosqlite.Connection = Depends(db_dependency),
|
||||||
):
|
):
|
||||||
"""Domain entsperren: excluded-Eintrag loeschen + Feeds reaktivieren."""
|
"""Domain-Ausschluss aufheben: excluded-Eintrag loeschen + Feeds reaktivieren."""
|
||||||
tenant_id = current_user.get("tenant_id")
|
tenant_id = current_user.get("tenant_id")
|
||||||
domain = data.domain.lower().strip()
|
domain = data.domain.lower().strip()
|
||||||
|
|
||||||
@@ -374,7 +374,7 @@ async def unblock_domain(
|
|||||||
feeds_reactivated = cursor.rowcount
|
feeds_reactivated = cursor.rowcount
|
||||||
else:
|
else:
|
||||||
await db.execute(
|
await db.execute(
|
||||||
"""UPDATE sources SET source_type = 'web_source', status = 'active', notes = 'Entsperrt'
|
"""UPDATE sources SET source_type = 'web_source', status = 'active', notes = 'Ausschluss aufgehoben'
|
||||||
WHERE LOWER(domain) = ? AND source_type = 'excluded' AND (tenant_id IS NULL OR tenant_id = ?)""",
|
WHERE LOWER(domain) = ? AND source_type = 'excluded' AND (tenant_id IS NULL OR tenant_id = ?)""",
|
||||||
(domain, tenant_id),
|
(domain, tenant_id),
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -3437,7 +3437,7 @@ a:hover {
|
|||||||
gap: var(--sp-xs);
|
gap: var(--sp-xs);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Gesperrte Domain */
|
/* Ausgeschlossene Domain */
|
||||||
.source-group-header.excluded {
|
.source-group-header.excluded {
|
||||||
grid-template-columns: 1fr auto auto;
|
grid-template-columns: 1fr auto auto;
|
||||||
border-left: 3px solid var(--error);
|
border-left: 3px solid var(--error);
|
||||||
|
|||||||
@@ -427,7 +427,7 @@
|
|||||||
<option value="">Alle Typen</option>
|
<option value="">Alle Typen</option>
|
||||||
<option value="rss_feed">RSS-Feed</option>
|
<option value="rss_feed">RSS-Feed</option>
|
||||||
<option value="web_source">Web-Quelle</option>
|
<option value="web_source">Web-Quelle</option>
|
||||||
<option value="excluded">Gesperrt</option>
|
<option value="excluded">Ausgeschlossen</option>
|
||||||
</select>
|
</select>
|
||||||
<label for="sources-filter-category" class="sr-only">Kategorie filtern</label>
|
<label for="sources-filter-category" class="sr-only">Kategorie filtern</label>
|
||||||
<select id="sources-filter-category" class="timeline-filter-select" onchange="App.filterSources()">
|
<select id="sources-filter-category" class="timeline-filter-select" onchange="App.filterSources()">
|
||||||
@@ -447,12 +447,12 @@
|
|||||||
<input type="text" id="sources-search" class="timeline-filter-input sources-search-input" placeholder="Suche..." oninput="App.filterSources()">
|
<input type="text" id="sources-search" class="timeline-filter-input sources-search-input" placeholder="Suche..." oninput="App.filterSources()">
|
||||||
</div>
|
</div>
|
||||||
<div class="sources-toolbar-actions">
|
<div class="sources-toolbar-actions">
|
||||||
<button class="btn btn-secondary btn-small source-block-btn" onclick="App.showBlockDomainDialog()">Domain sperren</button>
|
<button class="btn btn-secondary btn-small source-block-btn" onclick="App.showBlockDomainDialog()">Domain ausschließen</button>
|
||||||
<button class="btn btn-primary btn-small" onclick="App.toggleSourceForm()">+ Quelle</button>
|
<button class="btn btn-primary btn-small" onclick="App.toggleSourceForm()">+ Quelle</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- Inline-Formular: Domain sperren (ein-/ausklappbar) -->
|
<!-- Inline-Formular: Domain ausschließen (ein-/ausklappbar) -->
|
||||||
<div class="sources-add-form" id="sources-block-form" style="display:none;">
|
<div class="sources-add-form" id="sources-block-form" style="display:none;">
|
||||||
<div class="sources-form-row">
|
<div class="sources-form-row">
|
||||||
<div class="form-group flex-1">
|
<div class="form-group flex-1">
|
||||||
@@ -463,7 +463,7 @@
|
|||||||
<label for="block-domain-notes">Notizen</label>
|
<label for="block-domain-notes">Notizen</label>
|
||||||
<input type="text" id="block-domain-notes" class="source-notes-input" placeholder="Optional">
|
<input type="text" id="block-domain-notes" class="source-notes-input" placeholder="Optional">
|
||||||
</div>
|
</div>
|
||||||
<button class="btn btn-danger btn-small" onclick="App.blockDomain()">Sperren</button>
|
<button class="btn btn-danger btn-small" onclick="App.blockDomain()">Ausschließen</button>
|
||||||
<button class="btn btn-secondary btn-small" onclick="App.showBlockDomainDialog(false)">Abbrechen</button>
|
<button class="btn btn-secondary btn-small" onclick="App.showBlockDomainDialog(false)">Abbrechen</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -2199,7 +2199,7 @@ const App = {
|
|||||||
bar.innerHTML = `
|
bar.innerHTML = `
|
||||||
<span class="sources-stat-item"><span class="sources-stat-value">${rss.count}</span> RSS-Feeds</span>
|
<span class="sources-stat-item"><span class="sources-stat-value">${rss.count}</span> RSS-Feeds</span>
|
||||||
<span class="sources-stat-item"><span class="sources-stat-value">${web.count}</span> Web-Quellen</span>
|
<span class="sources-stat-item"><span class="sources-stat-value">${web.count}</span> Web-Quellen</span>
|
||||||
<span class="sources-stat-item"><span class="sources-stat-value">${excluded}</span> Gesperrt</span>
|
<span class="sources-stat-item"><span class="sources-stat-value">${excluded}</span> Ausgeschlossen</span>
|
||||||
<span class="sources-stat-item"><span class="sources-stat-value">${stats.total_articles}</span> Artikel gesamt</span>
|
<span class="sources-stat-item"><span class="sources-stat-value">${stats.total_articles}</span> Artikel gesamt</span>
|
||||||
`;
|
`;
|
||||||
},
|
},
|
||||||
@@ -2237,7 +2237,7 @@ const App = {
|
|||||||
groups.get(domain).push(s);
|
groups.get(domain).push(s);
|
||||||
});
|
});
|
||||||
|
|
||||||
// Gesperrte Domains die keine Feeds haben auch als Gruppe
|
// Ausgeschlossene Domains die keine Feeds haben auch als Gruppe
|
||||||
this._blacklistOnly.forEach(s => {
|
this._blacklistOnly.forEach(s => {
|
||||||
const domain = (s.domain || s.name || '').toLowerCase();
|
const domain = (s.domain || s.name || '').toLowerCase();
|
||||||
if (domain && !groups.has(domain)) {
|
if (domain && !groups.has(domain)) {
|
||||||
@@ -2279,7 +2279,7 @@ const App = {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Sortierung: Aktive zuerst (alphabetisch), dann gesperrte
|
// Sortierung: Aktive zuerst (alphabetisch), dann ausgeschlossene
|
||||||
filteredGroups.sort((a, b) => {
|
filteredGroups.sort((a, b) => {
|
||||||
if (a.isExcluded !== b.isExcluded) return a.isExcluded ? 1 : -1;
|
if (a.isExcluded !== b.isExcluded) return a.isExcluded ? 1 : -1;
|
||||||
return a.domain.localeCompare(b.domain);
|
return a.domain.localeCompare(b.domain);
|
||||||
@@ -2364,7 +2364,7 @@ const App = {
|
|||||||
},
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Domain sperren (aus dem Inline-Formular).
|
* Domain ausschließen (aus dem Inline-Formular).
|
||||||
*/
|
*/
|
||||||
async blockDomain() {
|
async blockDomain() {
|
||||||
const input = document.getElementById('block-domain-input');
|
const input = document.getElementById('block-domain-input');
|
||||||
@@ -2378,7 +2378,7 @@ const App = {
|
|||||||
|
|
||||||
try {
|
try {
|
||||||
await API.blockDomain(domain, notes);
|
await API.blockDomain(domain, notes);
|
||||||
UI.showToast(`${domain} gesperrt.`, 'success');
|
UI.showToast(`${domain} ausgeschlossen.`, 'success');
|
||||||
this.showBlockDomainDialog(false);
|
this.showBlockDomainDialog(false);
|
||||||
await this.loadSources();
|
await this.loadSources();
|
||||||
this.updateSidebarStats();
|
this.updateSidebarStats();
|
||||||
@@ -2437,10 +2437,10 @@ const App = {
|
|||||||
},
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Domain direkt sperren (aus der Gruppenliste).
|
* Domain direkt ausschließen (aus der Gruppenliste).
|
||||||
*/
|
*/
|
||||||
async blockDomainDirect(domain) {
|
async blockDomainDirect(domain) {
|
||||||
if (!await confirmDialog(`"${domain}" wirklich sperren? Alle Feeds dieser Domain werden deaktiviert.`)) return;
|
if (!await confirmDialog(`"${domain}" wirklich ausschließen? Alle Feeds dieser Domain werden deaktiviert.`)) return;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
await API.blockDomain(domain);
|
await API.blockDomain(domain);
|
||||||
@@ -2453,12 +2453,12 @@ const App = {
|
|||||||
},
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Domain entsperren.
|
* Domain-Ausschluss aufheben.
|
||||||
*/
|
*/
|
||||||
async unblockDomain(domain) {
|
async unblockDomain(domain) {
|
||||||
try {
|
try {
|
||||||
await API.unblockDomain(domain);
|
await API.unblockDomain(domain);
|
||||||
UI.showToast(`${domain} entsperrt.`, 'success');
|
UI.showToast(`${domain} Ausschluss aufgehoben.`, 'success');
|
||||||
await this.loadSources();
|
await this.loadSources();
|
||||||
this.updateSidebarStats();
|
this.updateSidebarStats();
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
@@ -2499,7 +2499,7 @@ const App = {
|
|||||||
},
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* "Domain sperren" Dialog ein-/ausblenden.
|
* "Domain ausschließen" Dialog ein-/ausblenden.
|
||||||
*/
|
*/
|
||||||
showBlockDomainDialog(show) {
|
showBlockDomainDialog(show) {
|
||||||
const form = document.getElementById('sources-block-form');
|
const form = document.getElementById('sources-block-form');
|
||||||
@@ -2558,12 +2558,12 @@ const App = {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Prüfen ob Domain gesperrt ist
|
// Prüfen ob Domain ausgeschlossen ist
|
||||||
const inputDomain = url.replace(/^https?:\/\//, '').replace(/^www\./, '').split('/')[0].toLowerCase();
|
const inputDomain = url.replace(/^https?:\/\//, '').replace(/^www\./, '').split('/')[0].toLowerCase();
|
||||||
const isBlocked = inputDomain && this._blacklistOnly.some(s => (s.domain || '').toLowerCase() === inputDomain);
|
const isBlocked = inputDomain && this._blacklistOnly.some(s => (s.domain || '').toLowerCase() === inputDomain);
|
||||||
|
|
||||||
if (isBlocked) {
|
if (isBlocked) {
|
||||||
if (!await confirmDialog(`"${inputDomain}" ist gesperrt. Trotzdem hinzufügen? Die Domain wird dabei entsperrt.`)) return;
|
if (!await confirmDialog(`"${inputDomain}" ist ausgeschlossen. Trotzdem hinzufügen? Der Ausschluss wird dabei aufgehoben.`)) return;
|
||||||
await API.unblockDomain(inputDomain);
|
await API.unblockDomain(inputDomain);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -537,16 +537,16 @@ const UI = {
|
|||||||
const escapedDomain = this.escape(domain);
|
const escapedDomain = this.escape(domain);
|
||||||
|
|
||||||
if (isExcluded) {
|
if (isExcluded) {
|
||||||
// Gesperrte Domain
|
// Ausgeschlossene Domain
|
||||||
const notesHtml = excludedNotes ? ` <span class="source-group-notes">${this.escape(excludedNotes)}</span>` : '';
|
const notesHtml = excludedNotes ? ` <span class="source-group-notes">${this.escape(excludedNotes)}</span>` : '';
|
||||||
return `<div class="source-group">
|
return `<div class="source-group">
|
||||||
<div class="source-group-header excluded">
|
<div class="source-group-header excluded">
|
||||||
<div class="source-group-info">
|
<div class="source-group-info">
|
||||||
<span class="source-group-name">${this.escape(displayName)}</span>${notesHtml}
|
<span class="source-group-name">${this.escape(displayName)}</span>${notesHtml}
|
||||||
</div>
|
</div>
|
||||||
<span class="source-excluded-badge">Gesperrt</span>
|
<span class="source-excluded-badge">Ausgeschlossen</span>
|
||||||
<div class="source-group-actions">
|
<div class="source-group-actions">
|
||||||
<button class="btn btn-small btn-secondary" onclick="App.unblockDomain('${escapedDomain}')">Entsperren</button>
|
<button class="btn btn-small btn-secondary" onclick="App.unblockDomain('${escapedDomain}')">Ausschluss aufheben</button>
|
||||||
<button class="source-delete-btn" onclick="App.deleteDomain('${escapedDomain}')" title="Löschen" aria-label="Löschen">×</button>
|
<button class="source-delete-btn" onclick="App.deleteDomain('${escapedDomain}')" title="Löschen" aria-label="Löschen">×</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -592,7 +592,7 @@ const UI = {
|
|||||||
${feedCountBadge}
|
${feedCountBadge}
|
||||||
<div class="source-group-actions" onclick="event.stopPropagation()">
|
<div class="source-group-actions" onclick="event.stopPropagation()">
|
||||||
${!hasMultiple && feeds[0]?.id ? `<button class="source-edit-btn" onclick="App.editSource(${feeds[0].id})" title="Bearbeiten" aria-label="Bearbeiten">✎</button>` : ''}
|
${!hasMultiple && feeds[0]?.id ? `<button class="source-edit-btn" onclick="App.editSource(${feeds[0].id})" title="Bearbeiten" aria-label="Bearbeiten">✎</button>` : ''}
|
||||||
<button class="btn btn-small btn-secondary" onclick="App.blockDomainDirect('${escapedDomain}')">Sperren</button>
|
<button class="btn btn-small btn-secondary" onclick="App.blockDomainDirect('${escapedDomain}')">Ausschließen</button>
|
||||||
<button class="source-delete-btn" onclick="App.deleteDomain('${escapedDomain}')" title="Löschen" aria-label="Löschen">×</button>
|
<button class="source-delete-btn" onclick="App.deleteDomain('${escapedDomain}')" title="Löschen" aria-label="Löschen">×</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
In neuem Issue referenzieren
Einen Benutzer sperren