bugfix
This commit is contained in:
@@ -3478,129 +3478,193 @@ class DataProcessor:
|
|||||||
logging.info(f"Modus 'find_wiki_serp' abgeschlossen. {processed_rows_count} Tasks erstellt, {found_urls_count} URLs gefunden, {skipped_timestamp_ay_count} AY gesetzt, {skipped_size_count} Größe, {skipped_m_filled_count} M gefüllt.")
|
logging.info(f"Modus 'find_wiki_serp' abgeschlossen. {processed_rows_count} Tasks erstellt, {found_urls_count} URLs gefunden, {skipped_timestamp_ay_count} AY gesetzt, {skipped_size_count} Größe, {skipped_m_filled_count} M gefüllt.")
|
||||||
|
|
||||||
# process_wiki_updates_from_chatgpt Methode
|
# process_wiki_updates_from_chatgpt Methode
|
||||||
def process_wiki_updates_from_chatgpt(self, row_limit=None): # <<< Methode in DataProcessor
|
def process_wiki_updates_from_chatgpt(self, row_limit=None): # <<< Methode in DataProcessor
|
||||||
"""
|
"""
|
||||||
Identifiziert Zeilen (S nicht OK/Updated/Copied/Invalid), prüft ob U eine *valide* und *andere* Wiki-URL ist.
|
Identifiziert Zeilen (S nicht OK/Updated/Copied/Invalid), prüft ob U eine *valide* und *andere* Wiki-URL ist.
|
||||||
- Wenn ja: Kopiert U->M, markiert S='X (URL Copied)', U='URL übernommen', löscht TS/Version, setzt ReEval-Flag A.
|
- Wenn ja: Kopiert U->M, markiert S='X (URL Copied)', U='URL übernommen',
|
||||||
- Wenn nein (U keine URL, U==M, oder U ungültig): LÖSCHT den Inhalt von U und markiert S als 'X (Invalid Suggestion)'.
|
löscht TS/Version, setzt ReEval-Flag A.
|
||||||
|
- Wenn nein (U keine URL, U==M, oder U ungültig): LÖSCHT den Inhalt von U
|
||||||
|
und markiert S als 'X (Invalid Suggestion)'.
|
||||||
Verarbeitet maximal row_limit Zeilen.
|
Verarbeitet maximal row_limit Zeilen.
|
||||||
"""
|
"""
|
||||||
logging.info(f"Starte Modus: Wiki-Updates (URL-Validierung & Löschen ungültiger Vorschläge). Limit: {limit if limit is not None else 'Unbegrenzt'}");
|
logging.info(
|
||||||
if not self.sheet_handler.load_data(): return logging.error("FEHLER beim Laden der Daten.");
|
f"Starte Modus: Wiki-Updates (URL-Validierung & Löschen ungültiger Vorschläge). "
|
||||||
|
f"Limit: {row_limit if row_limit is not None else 'Unbegrenzt'}"
|
||||||
|
)
|
||||||
|
if not self.sheet_handler.load_data():
|
||||||
|
return logging.error("FEHLER beim Laden der Daten.")
|
||||||
|
|
||||||
# KORRIGIERTE ZEILEN: Trenne Zuweisung und If-Statement
|
# Header-Zeilen überspringen
|
||||||
header_rows = 5 # Zuweisung auf eigener Zeile (z.B. 8 Leerzeichen)
|
header_rows = 5
|
||||||
# if-Statement beginnt auf neuer Zeile und ist eingerückt (z.B. 8 Leerzeichen)
|
if (not self.sheet_handler.get_all_data_with_headers()
|
||||||
if not self.sheet_handler.get_all_data_with_headers() or len(self.sheet_handler.get_all_data_with_headers()) <= header_rows:
|
or len(self.sheet_handler.get_all_data_with_headers()) <= header_rows):
|
||||||
# Die folgenden Zeilen gehören zum If-Block und müssen weiter eingerückt sein (z.B. 12 Leerzeichen)
|
logging.warning("Keine Daten gefunden oder nur Header.")
|
||||||
logging.warning("Keine Daten gefunden oder nur Header."); # Geändert von "Keine Daten gefunden."
|
return
|
||||||
return # continue oder return je nach Logik, hier return
|
|
||||||
|
|
||||||
# Diese Zeilen gehören zum normalen Fluss der Methode, nach dem if-Block
|
# Daten und Spalten-Indizes vorbereiten
|
||||||
# Sie sind auf der gleichen Ebene wie das if darüber (z.B. 8 Leerzeichen)
|
all_data = self.sheet_handler.get_all_data_with_headers()
|
||||||
all_data = self.sheet_handler.get_all_data_with_headers();
|
data_rows = all_data[header_rows:]
|
||||||
data_rows = all_data[header_rows:];
|
required_keys = [
|
||||||
required_keys = [ "Chat Wiki Konsistenzprüfung", "Chat Vorschlag Wiki Artikel", "Wiki URL", "Wikipedia Timestamp", "Wiki Verif. Timestamp", "Timestamp letzte Prüfung", "Version", "ReEval Flag", "Wiki Absatz", "Wiki Branche", "Wiki Umsatz", "Wiki Mitarbeiter", "Wiki Kategorien", "Begründung bei Abweichung" ];
|
"Chat Wiki Konsistenzprüfung", "Chat Vorschlag Wiki Artikel", "Wiki URL",
|
||||||
col_indices = {};
|
"Wikipedia Timestamp", "Wiki Verif. Timestamp", "Timestamp letzte Prüfung",
|
||||||
|
"Version", "ReEval Flag", "Wiki Absatz", "Wiki Branche", "Wiki Umsatz",
|
||||||
|
"Wiki Mitarbeiter", "Wiki Kategorien", "Begründung bei Abweichung"
|
||||||
|
]
|
||||||
|
col_indices = {}
|
||||||
|
|
||||||
# KORRIGIERTE ZEILEN: Trenne Zuweisung und For-Schleife
|
all_keys_found = True
|
||||||
all_keys_found = True # <- Zuweisung auf eigener Zeile (z.B. 8 Leerzeichen)
|
for key in required_keys:
|
||||||
# Die For-Schleife beginnt auf der nächsten Zeile und ist eingerückt
|
idx = COLUMN_MAP.get(key)
|
||||||
for key in required_keys: # <- For-Schleife beginnt hier, eingerückt unter all_keys_found
|
col_indices[key] = idx
|
||||||
# Die folgenden Zeilen gehören zum Körper der For-Schleife und sind weiter eingerückt
|
if idx is None:
|
||||||
idx = COLUMN_MAP.get(key);
|
logging.critical(f"FEHLER: Schlüssel '{key}' nicht in COLUMN_MAP gefunden! Modus abgebrochen.")
|
||||||
col_indices[key] = idx;
|
all_keys_found = False
|
||||||
if idx is None: # <- If innerhalb der For-Schleife
|
|
||||||
# <- Code unter dem If, weiter eingerückt
|
|
||||||
logging.critical(f"FEHLER: Schlüssel '{key}' nicht in COLUMN_MAP gefunden! Modus abgebrochen.");
|
|
||||||
all_keys_found = False; # <- Zuweisung unter dem If
|
|
||||||
# Hier endet die For-Schleife.
|
|
||||||
|
|
||||||
|
|
||||||
# Diese Zeilen gehören zum normalen Fluss der Methode, nach dem if not all_keys_found Block
|
|
||||||
if not all_keys_found:
|
if not all_keys_found:
|
||||||
return; # Abbruch, wenn nicht alle Schlüssel gefunden
|
return
|
||||||
|
|
||||||
# Diese Zeilen sind auf der gleichen Ebene wie das if darüber (z.B. 8 Leerzeichen)
|
all_sheet_updates = []
|
||||||
all_sheet_updates = []; processed_rows_count = 0; updated_url_count = 0; cleared_suggestion_count = 0;
|
processed_rows_count = 0
|
||||||
|
updated_url_count = 0
|
||||||
|
cleared_suggestion_count = 0
|
||||||
|
|
||||||
|
# Durch alle Datenzeilen iterieren
|
||||||
|
for idx, row in enumerate(data_rows):
|
||||||
|
row_num_in_sheet = idx + header_rows + 1
|
||||||
|
if row_limit is not None and processed_rows_count >= row_limit:
|
||||||
|
logging.info(f"Limit ({row_limit}) erreicht.")
|
||||||
|
break
|
||||||
|
|
||||||
for idx, row in enumerate(data_rows):
|
# Zeile übersprungen, wenn zu kurz
|
||||||
row_num_in_sheet = idx + header_rows + 1;
|
max_needed_idx = max(col_indices.values())
|
||||||
if limit is not None and processed_rows_count >= limit: logging.info(f"Limit ({limit}) erreicht."); break;
|
|
||||||
|
|
||||||
# KORRIGIERTE ZEILEN: Trenne Zuweisung und If-Statement
|
|
||||||
max_needed_idx = max(col_indices.values()); # Zuweisung auf eigener Zeile (z.B. 12 Leerzeichen)
|
|
||||||
# if-Statement beginnt auf neuer Zeile und ist eingerückt (z.B. 12 Leerzeichen)
|
|
||||||
if len(row) <= max_needed_idx:
|
if len(row) <= max_needed_idx:
|
||||||
# Die folgenden Zeilen gehören zum If-Block und müssen weiter eingerückt sein (z.B. 16 Leerzeichen)
|
logging.debug(f"Zeile {row_num_in_sheet}: Übersprungen (Zeile zu kurz).")
|
||||||
logging.debug(f"Zeile {row_num_in_sheet}: Übersprungen (Zeile zu kurz).");
|
continue
|
||||||
continue; # continue gehört unter das if
|
|
||||||
|
|
||||||
# Nutze private Helfermethode _get_cell_value
|
# Zellenwerte holen
|
||||||
konsistenz_s = self._get_cell_value(row, "Chat Wiki Konsistenzprüfung").strip()
|
konsistenz_s = self._get_cell_value(row, "Chat Wiki Konsistenzprüfung").strip()
|
||||||
vorschlag_u = self._get_cell_value(row, "Chat Vorschlag Wiki Artikel").strip()
|
vorschlag_u = self._get_cell_value(row, "Chat Vorschlag Wiki Artikel").strip()
|
||||||
url_m = self._get_cell_value(row, "Wiki URL").strip()
|
url_m = self._get_cell_value(row, "Wiki URL").strip()
|
||||||
|
|
||||||
konsistenz_s_upper = konsistenz_s.upper()
|
konsistenz_s_upper = konsistenz_s.upper()
|
||||||
is_candidate_for_check = bool(konsistenz_s_upper) and konsistenz_s_upper not in ["OK", "X (UPDATED)", "X (URL COPIED)", "X (INVALID SUGGESTION)", "?"]
|
is_candidate_for_check = (
|
||||||
|
bool(konsistenz_s_upper)
|
||||||
|
and konsistenz_s_upper not in ["OK", "X (UPDATED)", "X (URL COPIED)", "X (INVALID SUGGESTION)", "?"]
|
||||||
|
)
|
||||||
if is_candidate_for_check or (konsistenz_s_upper == "?" and not vorschlag_u):
|
if is_candidate_for_check or (konsistenz_s_upper == "?" and not vorschlag_u):
|
||||||
logging.debug(f"Zeile {row_num_in_sheet}: Kandidat für Wiki-Update-Prüfung (Status S = '{konsistenz_s}'). Vorschlag U = '{vorschlag_u}'")
|
logging.debug(
|
||||||
processed_rows_count += 1
|
f"Zeile {row_num_in_sheet}: Kandidat für Wiki-Update-Prüfung "
|
||||||
|
f"(Status S = '{konsistenz_s}'). Vorschlag U = '{vorschlag_u}'"
|
||||||
|
)
|
||||||
|
processed_rows_count += 1
|
||||||
|
|
||||||
is_update_candidate = False; new_url = ""
|
# Update-Kandidat prüfen
|
||||||
condition2_u_is_wiki_url = vorschlag_u.lower().startswith(("http://", "https://")) and "wikipedia.org/wiki/" in vorschlag_u.lower()
|
is_update_candidate = False
|
||||||
|
new_url = ""
|
||||||
|
condition2_u_is_wiki_url = (
|
||||||
|
vorschlag_u.lower().startswith(("http://", "https://"))
|
||||||
|
and "wikipedia.org/wiki/" in vorschlag_u.lower()
|
||||||
|
)
|
||||||
|
|
||||||
if condition2_u_is_wiki_url:
|
if condition2_u_is_wiki_url:
|
||||||
new_url = vorschlag_u
|
new_url = vorschlag_u
|
||||||
condition3_u_differs_m = simple_normalize_url(new_url) != simple_normalize_url(url_m) # Globale Funktion
|
condition3_u_differs_m = (
|
||||||
|
simple_normalize_url(new_url) != simple_normalize_url(url_m)
|
||||||
|
)
|
||||||
|
|
||||||
if condition3_u_differs_m:
|
if condition3_u_differs_m:
|
||||||
logging.debug(f" -> Prüfe Validität der neuen URL: {new_url}...")
|
logging.debug(f" -> Prüfe Validität der neuen URL: {new_url}...")
|
||||||
try: condition4_u_is_valid = is_valid_wikipedia_article_url(new_url); # Globale Funktion mit Retry
|
try:
|
||||||
except Exception as e_valid: logging.error(f" -> Fehler bei Validierung der URL '{new_url}': {e_valid}. Behandle als ungültig."); condition4_u_is_valid = False
|
condition4_u_is_valid = is_valid_wikipedia_article_url(new_url)
|
||||||
|
except Exception as e_valid:
|
||||||
|
logging.error(
|
||||||
|
f" -> Fehler bei Validierung der URL '{new_url}': {e_valid}. "
|
||||||
|
"Behandle als ungültig."
|
||||||
|
)
|
||||||
|
condition4_u_is_valid = False
|
||||||
|
|
||||||
if condition4_u_is_valid: is_update_candidate = True; logging.debug(f" -> URL '{new_url}' ist ein valider Artikel.")
|
if condition4_u_is_valid:
|
||||||
else: logging.debug(f" -> URL '{new_url}' ist KEIN valider Artikel laut API Check.")
|
is_update_candidate = True
|
||||||
else: logging.debug(f" -> Vorschlag U ist identisch mit URL M.")
|
logging.debug(f" -> URL '{new_url}' ist ein valider Artikel.")
|
||||||
else: logging.debug(f" -> Vorschlag U ist keine Wikipedia URL ('{vorschlag_u}').")
|
else:
|
||||||
|
logging.debug(f" -> URL '{new_url}' ist KEIN valider Artikel laut API Check.")
|
||||||
|
else:
|
||||||
|
logging.debug(f" -> Vorschlag U ist identisch mit URL M.")
|
||||||
|
else:
|
||||||
|
logging.debug(f" -> Vorschlag U ist keine Wikipedia URL ('{vorschlag_u}').")
|
||||||
|
|
||||||
if is_update_candidate:
|
# Je nach Ergebnis Update oder Cleanup anlegen
|
||||||
logging.info(f"Zeile {row_num_in_sheet}: Update-Kandidat VALIDIERUNG ERFOLGREICH. Setze ReEval-Flag 'x' und bereite Updates vor für URL: {new_url}");
|
if is_update_candidate:
|
||||||
updated_url_count += 1;
|
logging.info(
|
||||||
m_l=self.sheet_handler._get_col_letter(col_indices["Wiki URL"]+1); s_l=self.sheet_handler._get_col_letter(col_indices["Chat Wiki Konsistenzprüfung"]+1); u_l=self.sheet_handler._get_col_letter(col_indices["Chat Vorschlag Wiki Artikel"]+1);
|
f"Zeile {row_num_in_sheet}: Update-Kandidat VALIDIERUNG ERFOLGREICH. "
|
||||||
a_l=self.sheet_handler._get_col_letter(col_indices["ReEval Flag"]+1);
|
f"Setze ReEval-Flag 'x' und bereite Updates vor für URL: {new_url}"
|
||||||
n_idx = col_indices["Wiki Absatz"]; v_idx = col_indices["Begründung bei Abweichung"]; n_l=self.sheet_handler._get_col_letter(n_idx+1); v_l=self.sheet_handler._get_col_letter(v_idx+1);
|
)
|
||||||
an_l=self.sheet_handler._get_col_letter(col_indices["Wikipedia Timestamp"]+1); ax_l=self.sheet_handler._get_col_letter(col_indices["Wiki Verif. Timestamp"]+1); ao_l=self.sheet_handler._get_col_letter(col_indices["Timestamp letzte Prüfung"]+1); ap_l=self.sheet_handler._get_col_letter(col_indices["Version"]+1);
|
updated_url_count += 1
|
||||||
|
|
||||||
all_sheet_updates.extend([
|
# Spaltenbuchstaben bestimmen
|
||||||
{'range': f'{m_l}{row_num_in_sheet}', 'values': [[new_url]]}, {'range': f'{s_l}{row_num_in_sheet}', 'values': [["X (URL Copied)"]]}, {'range': f'{u_l}{row_num_in_sheet}', 'values': [["URL übernommen"]]},
|
m_l = self.sheet_handler._get_col_letter(col_indices["Wiki URL"] + 1)
|
||||||
{'range': f'{n_l}{row_num_in_sheet}:{v_l}{row_num_in_sheet}', 'values': [[''] * (v_idx - n_idx + 1)]},
|
s_l = self.sheet_handler._get_col_letter(col_indices["Chat Wiki Konsistenzprüfung"] + 1)
|
||||||
{'range': f'{an_l}{row_num_in_sheet}', 'values': [['']]}, {'range': f'{ax_l}{row_num_in_sheet}', 'values': [['']]},
|
u_l = self.sheet_handler._get_col_letter(col_indices["Chat Vorschlag Wiki Artikel"] + 1)
|
||||||
{'range': f'{ao_l}{row_num_in_sheet}', 'values': [['']]}, {'range': f'{ap_l}{row_num_in_sheet}', 'values': [['']]},
|
a_l = self.sheet_handler._get_col_letter(col_indices["ReEval Flag"] + 1)
|
||||||
{'range': f'{a_l}{row_num_in_sheet}', 'values': [["x"]]},
|
|
||||||
]);
|
|
||||||
else: # <= ZEILE 3583
|
|
||||||
# <<< Die folgenden Zeilen müssen EINE EBENE TIEFER als das "else:" eingerückt sein (z.B. 16 Leerzeichen)
|
|
||||||
logging.info(f"Zeile {row_num_in_sheet}: Vorschlag U ('{vorschlag_u}') ist ungültig/identisch. Lösche U und setze Status S."); # <= ZEILE 3584 (korrekt eingerückt)
|
|
||||||
cleared_suggestion_count += 1; # <= ZEILE 3585 (korrekt eingerückt)
|
|
||||||
s_l=self.sheet_handler._get_col_letter(col_indices["Chat Wiki Konsistenzprüfung"]+1); u_l=self.sheet_handler._get_col_letter(col_indices["Chat Vorschlag Wiki Artikel"]+1); # <= ZEILE 3586 (korrekt eingerückt)
|
|
||||||
all_sheet_updates.extend([ # <= ZEILE 3587 (korrekt eingerückt)
|
|
||||||
{'range': f'{s_l}{row_num_in_sheet}', 'values': [["X (Invalid Suggestion)"]]}, # Neuer Status in S
|
|
||||||
{'range': f'{u_l}{row_num_in_sheet}', 'values': [[""]]} # Vorschlag U löschen
|
|
||||||
]); # <= ZEILE 3590 (korrekt eingerückt)
|
|
||||||
|
|
||||||
# else: Status war OK, X(Updated), X(Copied), X(Invalid Suggestion) oder leer -> Kein Kandidat <= ZEILE 3591 (Gehört zum if is_candidate_for_check)
|
n_idx = col_indices["Wiki Absatz"]
|
||||||
|
v_idx = col_indices["Begründung bei Abweichung"]
|
||||||
|
n_l = self.sheet_handler._get_col_letter(n_idx + 1)
|
||||||
|
v_l = self.sheet_handler._get_col_letter(v_idx + 1)
|
||||||
|
|
||||||
|
an_l = self.sheet_handler._get_col_letter(col_indices["Wikipedia Timestamp"] + 1)
|
||||||
|
ax_l = self.sheet_handler._get_col_letter(col_indices["Wiki Verif. Timestamp"]+ 1)
|
||||||
|
ao_l = self.sheet_handler._get_col_letter(col_indices["Timestamp letzte Prüfung"]+1)
|
||||||
|
ap_l = self.sheet_handler._get_col_letter(col_indices["Version"] + 1)
|
||||||
|
|
||||||
|
all_sheet_updates.extend([
|
||||||
|
{'range': f'{m_l}{row_num_in_sheet}', 'values': [[ new_url ]]},
|
||||||
|
{'range': f'{s_l}{row_num_in_sheet}', 'values': [[ "X (URL Copied)" ]]},
|
||||||
|
{'range': f'{u_l}{row_num_in_sheet}', 'values': [[ "URL übernommen" ]]},
|
||||||
|
{
|
||||||
|
'range': f'{n_l}{row_num_in_sheet}:{v_l}{row_num_in_sheet}',
|
||||||
|
'values': [[''] * (v_idx - n_idx + 1)]
|
||||||
|
},
|
||||||
|
{'range': f'{an_l}{row_num_in_sheet}', 'values': [['']]},
|
||||||
|
{'range': f'{ax_l}{row_num_in_sheet}', 'values': [['']]},
|
||||||
|
{'range': f'{ao_l}{row_num_in_sheet}', 'values': [['']]},
|
||||||
|
{'range': f'{ap_l}{row_num_in_sheet}', 'values': [['']]},
|
||||||
|
{'range': f'{a_l}{row_num_in_sheet}', 'values': [[ "x" ]]},
|
||||||
|
])
|
||||||
|
else:
|
||||||
|
logging.info(
|
||||||
|
f"Zeile {row_num_in_sheet}: Vorschlag U ('{vorschlag_u}') ist ungültig/identisch. "
|
||||||
|
"Lösche U und setze Status S."
|
||||||
|
)
|
||||||
|
cleared_suggestion_count += 1
|
||||||
|
|
||||||
|
s_l = self.sheet_handler._get_col_letter(col_indices["Chat Wiki Konsistenzprüfung"] + 1)
|
||||||
|
u_l = self.sheet_handler._get_col_letter(col_indices["Chat Vorschlag Wiki Artikel"] + 1)
|
||||||
|
|
||||||
|
all_sheet_updates.extend([
|
||||||
|
{'range': f'{s_l}{row_num_in_sheet}', 'values': [[ "X (Invalid Suggestion)" ]]},
|
||||||
|
{'range': f'{u_l}{row_num_in_sheet}', 'values': [[ "" ]]},
|
||||||
|
])
|
||||||
|
|
||||||
|
# Nach der Schleife: Batch-Update senden, falls nötig
|
||||||
if all_sheet_updates:
|
if all_sheet_updates:
|
||||||
logging.info(f"Sende Batch-Update für {processed_rows_count} geprüfte Zeilen ({len(all_sheet_updates)} Zellen)...")
|
logging.info(
|
||||||
success = self.sheet_handler.batch_update_cells(all_sheet_updates)
|
f"Sende Batch-Update für {processed_rows_count} geprüfte Zeilen "
|
||||||
if success: logging.info(f"Sheet-Update für Wiki-Updates erfolgreich.")
|
f"({len(all_sheet_updates)} Zellen)..."
|
||||||
else: logging.error("FEHLER beim Sheet-Update für Wiki-Updates.")
|
)
|
||||||
else: logging.info("Keine Zeilen gefunden, die eine Wiki-URL-Korrektur oder Vorschlagsbereinigung benötigen.")
|
success = self.sheet_handler.batch_update_cells(all_sheet_updates)
|
||||||
|
if success:
|
||||||
|
logging.info("Sheet-Update für Wiki-Updates erfolgreich.")
|
||||||
|
else:
|
||||||
|
logging.error("FEHLER beim Sheet-Update für Wiki-Updates.")
|
||||||
|
else:
|
||||||
|
logging.info("Keine Zeilen gefunden, die eine Wiki-URL-Korrektur oder Vorschlagsbereinigung benötigen.")
|
||||||
|
|
||||||
logging.info(f"Wiki-Updates abgeschlossen. {processed_rows_count} Zeilen geprüft. {updated_url_count} URLs kopiert & für ReEval markiert, {cleared_suggestion_count} ungültige Vorschläge gelöscht/markiert.")
|
logging.info(
|
||||||
|
f"Wiki-Updates abgeschlossen. {processed_rows_count} Zeilen geprüft. "
|
||||||
|
f"{updated_url_count} URLs kopiert & für ReEval markiert, "
|
||||||
|
f"{cleared_suggestion_count} ungültige Vorschläge gelöscht/markiert."
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
# --- Private Helfer für Timestamp/Status Checks ---
|
# --- Private Helfer für Timestamp/Status Checks ---
|
||||||
|
|||||||
Reference in New Issue
Block a user