Initial commit
Dieser Commit ist enthalten in:
465
utils/username_generator.py
Normale Datei
465
utils/username_generator.py
Normale Datei
@ -0,0 +1,465 @@
|
||||
# utils/username_generator.py
|
||||
|
||||
"""
|
||||
Benutzernamen-Generator für den Social Media Account Generator.
|
||||
"""
|
||||
|
||||
import random
|
||||
import string
|
||||
import re
|
||||
import logging
|
||||
from typing import Dict, List, Any, Optional, Tuple, Union
|
||||
|
||||
logger = logging.getLogger("username_generator")
|
||||
|
||||
class UsernameGenerator:
|
||||
"""Klasse zur Generierung von Benutzernamen für verschiedene Plattformen."""
|
||||
|
||||
def __init__(self):
|
||||
"""Initialisiert den UsernameGenerator."""
|
||||
# Plattformspezifische Richtlinien
|
||||
self.platform_policies = {
|
||||
"instagram": {
|
||||
"min_length": 1,
|
||||
"max_length": 30,
|
||||
"allowed_chars": string.ascii_letters + string.digits + "._",
|
||||
"allowed_start_chars": string.ascii_letters + string.digits,
|
||||
"allowed_end_chars": string.ascii_letters + string.digits + ".",
|
||||
"allowed_consecutive_special": False,
|
||||
"disallowed_words": ["instagram", "admin", "official"],
|
||||
"auto_suggestions": True
|
||||
},
|
||||
"facebook": {
|
||||
"min_length": 5,
|
||||
"max_length": 50,
|
||||
"allowed_chars": string.ascii_letters + string.digits + ".-",
|
||||
"allowed_start_chars": string.ascii_letters,
|
||||
"allowed_end_chars": string.ascii_letters + string.digits,
|
||||
"allowed_consecutive_special": True,
|
||||
"disallowed_words": ["facebook", "meta", "admin"],
|
||||
"auto_suggestions": False
|
||||
},
|
||||
"twitter": {
|
||||
"min_length": 4,
|
||||
"max_length": 15,
|
||||
"allowed_chars": string.ascii_letters + string.digits + "_",
|
||||
"allowed_start_chars": string.ascii_letters + string.digits,
|
||||
"allowed_end_chars": string.ascii_letters + string.digits + "_",
|
||||
"allowed_consecutive_special": True,
|
||||
"disallowed_words": ["twitter", "admin", "official"],
|
||||
"auto_suggestions": True
|
||||
},
|
||||
"tiktok": {
|
||||
"min_length": 2,
|
||||
"max_length": 24,
|
||||
"allowed_chars": string.ascii_letters + string.digits + "._",
|
||||
"allowed_start_chars": string.ascii_letters + string.digits,
|
||||
"allowed_end_chars": string.ascii_letters + string.digits,
|
||||
"allowed_consecutive_special": False,
|
||||
"disallowed_words": ["tiktok", "admin", "official"],
|
||||
"auto_suggestions": True
|
||||
},
|
||||
"default": {
|
||||
"min_length": 3,
|
||||
"max_length": 20,
|
||||
"allowed_chars": string.ascii_letters + string.digits + "._-",
|
||||
"allowed_start_chars": string.ascii_letters,
|
||||
"allowed_end_chars": string.ascii_letters + string.digits,
|
||||
"allowed_consecutive_special": False,
|
||||
"disallowed_words": ["admin", "root", "system"],
|
||||
"auto_suggestions": True
|
||||
}
|
||||
}
|
||||
|
||||
# Liste von Adjektiven und Substantiven für zufällige Benutzernamen
|
||||
self.adjectives = [
|
||||
"happy", "sunny", "clever", "brave", "mighty", "gentle", "wild", "calm", "bright",
|
||||
"quiet", "swift", "bold", "wise", "fancy", "little", "big", "smart", "cool", "hot",
|
||||
"super", "mega", "epic", "magic", "golden", "silver", "bronze", "shiny", "dark",
|
||||
"light", "fast", "slow", "strong", "soft", "hard", "sweet", "sour", "tasty", "fresh",
|
||||
"green", "blue", "red", "purple", "yellow", "orange", "pink", "white", "black"
|
||||
]
|
||||
|
||||
self.nouns = [
|
||||
"tiger", "eagle", "lion", "wolf", "bear", "fox", "owl", "hawk", "falcon", "dolphin",
|
||||
"shark", "whale", "turtle", "panda", "koala", "monkey", "cat", "dog", "horse", "pony",
|
||||
"unicorn", "dragon", "phoenix", "wizard", "knight", "warrior", "ninja", "samurai",
|
||||
"queen", "king", "prince", "princess", "hero", "legend", "star", "moon", "sun", "sky",
|
||||
"ocean", "river", "mountain", "forest", "tree", "flower", "rose", "tulip", "daisy"
|
||||
]
|
||||
|
||||
# Internationaler Wortschatz (nur mit ASCII-Zeichen) für verschiedene Sprachen
|
||||
# Jeweils 100 kurze, neutrale Begriffe pro Sprache
|
||||
self.international_words = {
|
||||
# Deutsch - 100 kurze, neutrale Begriffe ohne Umlaute oder Sonderzeichen
|
||||
"de": [
|
||||
"wald", "berg", "fluss", "tal", "see", "meer", "boot", "schiff", "haus", "dach",
|
||||
"tuer", "fenster", "glas", "holz", "stein", "sand", "erde", "weg", "pfad", "strasse",
|
||||
"auto", "rad", "ball", "spiel", "tisch", "stuhl", "bett", "kissen", "lampe", "licht",
|
||||
"tag", "nacht", "sonne", "mond", "stern", "himmel", "wolke", "regen", "schnee", "wind",
|
||||
"baum", "blume", "gras", "blatt", "frucht", "apfel", "brot", "wasser", "milch", "kaffee",
|
||||
"buch", "brief", "stift", "musik", "lied", "tanz", "film", "bild", "farbe", "kunst",
|
||||
"hand", "fuss", "kopf", "auge", "ohr", "nase", "mund", "zahn", "haar", "herz",
|
||||
"zeit", "jahr", "monat", "woche", "tag", "stunde", "minute", "uhr", "zahl", "wort",
|
||||
"name", "freund", "kind", "tier", "vogel", "fisch", "stadt", "land", "dorf", "garten",
|
||||
"feld", "werk", "kraft", "geld", "gold", "bank", "markt", "preis", "karte", "punkt"
|
||||
],
|
||||
|
||||
# Englisch - 100 kurze, neutrale Begriffe
|
||||
"en": [
|
||||
"wood", "hill", "river", "valley", "lake", "sea", "boat", "ship", "house", "roof",
|
||||
"door", "window", "glass", "wood", "stone", "sand", "earth", "way", "path", "road",
|
||||
"car", "wheel", "ball", "game", "table", "chair", "bed", "pillow", "lamp", "light",
|
||||
"day", "night", "sun", "moon", "star", "sky", "cloud", "rain", "snow", "wind",
|
||||
"tree", "flower", "grass", "leaf", "fruit", "apple", "bread", "water", "milk", "coffee",
|
||||
"book", "letter", "pen", "music", "song", "dance", "film", "image", "color", "art",
|
||||
"hand", "foot", "head", "eye", "ear", "nose", "mouth", "tooth", "hair", "heart",
|
||||
"time", "year", "month", "week", "day", "hour", "minute", "clock", "number", "word",
|
||||
"name", "friend", "child", "animal", "bird", "fish", "city", "country", "village", "garden",
|
||||
"field", "work", "power", "money", "gold", "bank", "market", "price", "card", "point"
|
||||
],
|
||||
|
||||
# Französisch - 100 kurze, neutrale Begriffe (ohne Akzente oder Sonderzeichen)
|
||||
"fr": [
|
||||
"bois", "mont", "fleuve", "vallee", "lac", "mer", "bateau", "navire", "maison", "toit",
|
||||
"porte", "fenetre", "verre", "bois", "pierre", "sable", "terre", "voie", "sentier", "route",
|
||||
"auto", "roue", "balle", "jeu", "table", "chaise", "lit", "coussin", "lampe", "lumiere",
|
||||
"jour", "nuit", "soleil", "lune", "etoile", "ciel", "nuage", "pluie", "neige", "vent",
|
||||
"arbre", "fleur", "herbe", "feuille", "fruit", "pomme", "pain", "eau", "lait", "cafe",
|
||||
"livre", "lettre", "stylo", "musique", "chanson", "danse", "film", "image", "couleur", "art",
|
||||
"main", "pied", "tete", "oeil", "oreille", "nez", "bouche", "dent", "cheveu", "coeur",
|
||||
"temps", "annee", "mois", "semaine", "jour", "heure", "minute", "horloge", "nombre", "mot",
|
||||
"nom", "ami", "enfant", "animal", "oiseau", "poisson", "ville", "pays", "village", "jardin",
|
||||
"champ", "travail", "force", "argent", "or", "banque", "marche", "prix", "carte", "point"
|
||||
],
|
||||
|
||||
# Spanisch - 100 kurze, neutrale Begriffe (ohne Akzente oder Sonderzeichen)
|
||||
"es": [
|
||||
"bosque", "monte", "rio", "valle", "lago", "mar", "barco", "nave", "casa", "techo",
|
||||
"puerta", "ventana", "vidrio", "madera", "piedra", "arena", "tierra", "via", "ruta", "calle",
|
||||
"coche", "rueda", "bola", "juego", "mesa", "silla", "cama", "cojin", "lampara", "luz",
|
||||
"dia", "noche", "sol", "luna", "estrella", "cielo", "nube", "lluvia", "nieve", "viento",
|
||||
"arbol", "flor", "hierba", "hoja", "fruta", "manzana", "pan", "agua", "leche", "cafe",
|
||||
"libro", "carta", "pluma", "musica", "cancion", "baile", "pelicula", "imagen", "color", "arte",
|
||||
"mano", "pie", "cabeza", "ojo", "oreja", "nariz", "boca", "diente", "pelo", "corazon",
|
||||
"tiempo", "ano", "mes", "semana", "dia", "hora", "minuto", "reloj", "numero", "palabra",
|
||||
"nombre", "amigo", "nino", "animal", "ave", "pez", "ciudad", "pais", "pueblo", "jardin",
|
||||
"campo", "trabajo", "fuerza", "dinero", "oro", "banco", "mercado", "precio", "carta", "punto"
|
||||
],
|
||||
|
||||
# Japanisch - 100 kurze, neutrale Begriffe (in romanisierter Form)
|
||||
"ja": [
|
||||
"ki", "yama", "kawa", "tani", "mizu", "umi", "fune", "ie", "yane", "kado",
|
||||
"mado", "garasu", "ki", "ishi", "suna", "tsuchi", "michi", "kuruma", "wa", "tama",
|
||||
"asobi", "tsukue", "isu", "neru", "makura", "akari", "hikari", "hi", "yoru", "taiyou",
|
||||
"tsuki", "hoshi", "sora", "kumo", "ame", "yuki", "kaze", "ki", "hana", "kusa",
|
||||
"ha", "kudamono", "ringo", "pan", "mizu", "gyunyu", "kohi", "hon", "tegami", "pen",
|
||||
"ongaku", "uta", "odori", "eiga", "e", "iro", "geijutsu", "te", "ashi", "atama",
|
||||
"me", "mimi", "hana", "kuchi", "ha", "kami", "kokoro", "jikan", "toshi", "tsuki",
|
||||
"shukan", "hi", "jikan", "fun", "tokei", "kazu", "kotoba", "namae", "tomodachi", "kodomo",
|
||||
"doubutsu", "tori", "sakana", "machi", "kuni", "mura", "niwa", "hatake", "shigoto", "chikara",
|
||||
"okane", "kin", "ginko", "ichiba", "nedan", "kado", "ten", "ai", "heiwa", "yume"
|
||||
]
|
||||
}
|
||||
|
||||
def get_platform_policy(self, platform: str) -> Dict[str, Any]:
|
||||
"""
|
||||
Gibt die Benutzernamen-Richtlinie für eine bestimmte Plattform zurück.
|
||||
|
||||
Args:
|
||||
platform: Name der Plattform
|
||||
|
||||
Returns:
|
||||
Dictionary mit der Benutzernamen-Richtlinie
|
||||
"""
|
||||
platform = platform.lower()
|
||||
return self.platform_policies.get(platform, self.platform_policies["default"])
|
||||
|
||||
def set_platform_policy(self, platform: str, policy: Dict[str, Any]) -> None:
|
||||
"""
|
||||
Setzt oder aktualisiert die Benutzernamen-Richtlinie für eine Plattform.
|
||||
|
||||
Args:
|
||||
platform: Name der Plattform
|
||||
policy: Dictionary mit der Benutzernamen-Richtlinie
|
||||
"""
|
||||
platform = platform.lower()
|
||||
self.platform_policies[platform] = policy
|
||||
logger.info(f"Benutzernamen-Richtlinie für '{platform}' aktualisiert")
|
||||
|
||||
def generate_username(self, platform: str = "default", name: Optional[str] = None,
|
||||
custom_policy: Optional[Dict[str, Any]] = None) -> str:
|
||||
"""
|
||||
Generiert einen Benutzernamen gemäß den Richtlinien.
|
||||
|
||||
Args:
|
||||
platform: Name der Plattform
|
||||
name: Optionaler vollständiger Name für die Generierung
|
||||
custom_policy: Optionale benutzerdefinierte Richtlinie
|
||||
|
||||
Returns:
|
||||
Generierter Benutzername
|
||||
"""
|
||||
# Richtlinie bestimmen
|
||||
if custom_policy:
|
||||
policy = custom_policy
|
||||
else:
|
||||
policy = self.get_platform_policy(platform)
|
||||
|
||||
# Wenn ein Name angegeben ist, versuche einen darauf basierenden Benutzernamen zu erstellen
|
||||
if name:
|
||||
return self.generate_from_name(name, policy)
|
||||
else:
|
||||
# Zufälligen Benutzernamen erstellen
|
||||
return self.generate_random_username(policy)
|
||||
|
||||
def generate_from_name(self, name: str, policy: Dict[str, Any]) -> str:
|
||||
"""
|
||||
Generiert einen Benutzernamen aus einem vollständigen Namen im Format
|
||||
Vorname_RandomBegriffAusDerAusgewähltenSprache_GeburtsjahrXX.
|
||||
|
||||
Args:
|
||||
name: Vollständiger Name
|
||||
policy: Benutzernamen-Richtlinie
|
||||
|
||||
Returns:
|
||||
Generierter Benutzername
|
||||
"""
|
||||
# Name in Teile zerlegen
|
||||
parts = name.lower().split()
|
||||
|
||||
# Sonderzeichen und Leerzeichen entfernen
|
||||
parts = [re.sub(r'[^a-z0-9]', '', part) for part in parts]
|
||||
parts = [part for part in parts if part]
|
||||
|
||||
if not parts:
|
||||
# Falls keine gültigen Teile, zufälligen Benutzernamen generieren
|
||||
return self.generate_random_username(policy)
|
||||
|
||||
# Vorname nehmen
|
||||
firstname = parts[0]
|
||||
|
||||
# Zufällige Sprache auswählen
|
||||
available_languages = list(self.international_words.keys())
|
||||
chosen_language = random.choice(available_languages)
|
||||
|
||||
# Zufälliges Wort aus der gewählten Sprache wählen
|
||||
random_word = random.choice(self.international_words[chosen_language])
|
||||
|
||||
# Geburtsjahr simulieren (zwischen 18 und 40 Jahre alt)
|
||||
current_year = 2025 # Aktuelle Jahresangabe im Code
|
||||
birth_year = current_year - random.randint(18, 40)
|
||||
|
||||
# Letzte zwei Ziffern vom Geburtsjahr plus eine Zufallszahl
|
||||
year_suffix = str(birth_year)[-2:] + str(random.randint(0, 9))
|
||||
|
||||
# Benutzernamen im neuen Format zusammensetzen
|
||||
username = f"{firstname}_{random_word}_{year_suffix}"
|
||||
|
||||
# Länge prüfen und anpassen
|
||||
if len(username) > policy["max_length"]:
|
||||
# Bei Überlänge, kürze den Mittelteil
|
||||
max_word_length = policy["max_length"] - len(firstname) - len(year_suffix) - 2 # 2 für die Unterstriche
|
||||
if max_word_length < 3: # Zu kurz für ein sinnvolles Wort
|
||||
# Fallback: Nur Vorname + Jahreszahl
|
||||
username = f"{firstname}_{year_suffix}"
|
||||
else:
|
||||
random_word = random_word[:max_word_length]
|
||||
username = f"{firstname}_{random_word}_{year_suffix}"
|
||||
|
||||
# Überprüfen, ob die Richtlinien erfüllt sind
|
||||
valid, error_msg = self.validate_username(username, policy=policy)
|
||||
if not valid:
|
||||
# Wenn nicht gültig, generiere einen alternativen Namen
|
||||
logger.debug(f"Generierter Name '{username}' nicht gültig: {error_msg}")
|
||||
|
||||
# Einfachere Variante versuchen
|
||||
username = f"{firstname}{year_suffix}"
|
||||
|
||||
valid, _ = self.validate_username(username, policy=policy)
|
||||
if not valid:
|
||||
# Wenn immer noch nicht gültig, Fallback auf Standard-Generator
|
||||
return self.generate_random_username(policy)
|
||||
|
||||
logger.info(f"Aus Name generierter Benutzername: {username}")
|
||||
return username
|
||||
|
||||
def generate_random_username(self, policy: Dict[str, Any]) -> str:
|
||||
"""
|
||||
Generiert einen zufälligen Benutzernamen.
|
||||
|
||||
Args:
|
||||
policy: Benutzernamen-Richtlinie
|
||||
|
||||
Returns:
|
||||
Generierter Benutzername
|
||||
"""
|
||||
# Verschiedene Muster für zufällige Benutzernamen
|
||||
patterns = [
|
||||
# Adjektiv + Substantiv
|
||||
lambda: random.choice(self.adjectives) + random.choice(self.nouns),
|
||||
|
||||
# Substantiv + Zahlen
|
||||
lambda: random.choice(self.nouns) + "".join(random.choices(string.digits, k=random.randint(1, 4))),
|
||||
|
||||
# Adjektiv + Substantiv + Zahlen
|
||||
lambda: random.choice(self.adjectives) + random.choice(self.nouns) + "".join(random.choices(string.digits, k=random.randint(1, 3))),
|
||||
|
||||
# Substantiv + Unterstrich + Substantiv
|
||||
lambda: random.choice(self.nouns) + ("_" if "_" in policy["allowed_chars"] else "") + random.choice(self.nouns),
|
||||
|
||||
# Benutzer + Zahlen
|
||||
lambda: "user" + "".join(random.choices(string.digits, k=random.randint(3, 6)))
|
||||
]
|
||||
|
||||
# Zufälliges Muster auswählen und Benutzernamen generieren
|
||||
max_attempts = 10
|
||||
for _ in range(max_attempts):
|
||||
pattern_func = random.choice(patterns)
|
||||
username = pattern_func()
|
||||
|
||||
# Zu lange Benutzernamen kürzen
|
||||
if len(username) > policy["max_length"]:
|
||||
username = username[:policy["max_length"]]
|
||||
|
||||
# Zu kurze Benutzernamen verlängern
|
||||
if len(username) < policy["min_length"]:
|
||||
username += "".join(random.choices(string.digits, k=policy["min_length"] - len(username)))
|
||||
|
||||
# Überprüfen, ob der Benutzername den Richtlinien entspricht
|
||||
valid, _ = self.validate_username(username, policy=policy)
|
||||
if valid:
|
||||
logger.info(f"Zufälliger Benutzername generiert: {username}")
|
||||
return username
|
||||
|
||||
# Fallback: Einfachen Benutzernamen mit Zufallsbuchstaben und Zahlen generieren
|
||||
length = random.randint(policy["min_length"], min(policy["max_length"], policy["min_length"] + 5))
|
||||
username = random.choice(string.ascii_lowercase) # Erster Buchstabe
|
||||
|
||||
allowed_chars = [c for c in policy["allowed_chars"] if c in (string.ascii_lowercase + string.digits)]
|
||||
username += "".join(random.choice(allowed_chars) for _ in range(length - 1))
|
||||
|
||||
logger.info(f"Fallback-Benutzername generiert: {username}")
|
||||
return username
|
||||
|
||||
def suggest_alternatives(self, username: str, platform: str = "default") -> List[str]:
|
||||
"""
|
||||
Schlägt alternative Benutzernamen vor, wenn der gewünschte bereits vergeben ist.
|
||||
|
||||
Args:
|
||||
username: Gewünschter Benutzername
|
||||
platform: Name der Plattform
|
||||
|
||||
Returns:
|
||||
Liste mit alternativen Benutzernamen
|
||||
"""
|
||||
policy = self.get_platform_policy(platform)
|
||||
|
||||
# Wenn Auto-Suggestions deaktiviert sind, leere Liste zurückgeben
|
||||
if not policy.get("auto_suggestions", True):
|
||||
return []
|
||||
|
||||
alternatives = []
|
||||
base_username = username
|
||||
|
||||
# Verschiedene Modifikationen ausprobieren
|
||||
|
||||
# Anhängen von Zahlen
|
||||
for i in range(5):
|
||||
suffix = str(random.randint(1, 999))
|
||||
alt = base_username + suffix
|
||||
if len(alt) <= policy["max_length"]:
|
||||
alternatives.append(alt)
|
||||
|
||||
# Sonderzeichen einfügen
|
||||
for special in ["_", ".", "-"]:
|
||||
if special in policy["allowed_chars"]:
|
||||
alt = base_username + special + str(random.randint(1, 99))
|
||||
if len(alt) <= policy["max_length"]:
|
||||
alternatives.append(alt)
|
||||
|
||||
# Adjektiv voranstellen
|
||||
for _ in range(2):
|
||||
prefix = random.choice(self.adjectives)
|
||||
alt = prefix + base_username
|
||||
if len(alt) <= policy["max_length"]:
|
||||
alternatives.append(alt)
|
||||
|
||||
# Buchstaben ersetzen (z.B. 'o' durch '0')
|
||||
if "0" in policy["allowed_chars"] and "o" in base_username.lower():
|
||||
alt = base_username.lower().replace("o", "0")
|
||||
if len(alt) <= policy["max_length"]:
|
||||
alternatives.append(alt)
|
||||
|
||||
# Zufällige Buchstaben voranstellen
|
||||
for _ in range(2):
|
||||
prefix = "".join(random.choices(string.ascii_lowercase, k=random.randint(1, 3)))
|
||||
alt = prefix + base_username
|
||||
if len(alt) <= policy["max_length"]:
|
||||
alternatives.append(alt)
|
||||
|
||||
# Validiere die alternativen Benutzernamen
|
||||
valid_alternatives = []
|
||||
for alt in alternatives:
|
||||
valid, _ = self.validate_username(alt, policy=policy)
|
||||
if valid:
|
||||
valid_alternatives.append(alt)
|
||||
|
||||
# Zufällige Auswahl aus den gültigen Alternativen (maximal 5)
|
||||
if len(valid_alternatives) > 5:
|
||||
valid_alternatives = random.sample(valid_alternatives, 5)
|
||||
|
||||
logger.info(f"{len(valid_alternatives)} alternative Benutzernamen generiert für '{username}'")
|
||||
|
||||
return valid_alternatives
|
||||
|
||||
def validate_username(self, username: str, platform: str = "default",
|
||||
policy: Optional[Dict[str, Any]] = None) -> Tuple[bool, str]:
|
||||
"""
|
||||
Überprüft, ob ein Benutzername den Richtlinien entspricht.
|
||||
|
||||
Args:
|
||||
username: Zu überprüfender Benutzername
|
||||
platform: Name der Plattform
|
||||
policy: Optionale Richtlinie (sonst wird die der Plattform verwendet)
|
||||
|
||||
Returns:
|
||||
(Gültigkeit, Fehlermeldung)
|
||||
"""
|
||||
# Richtlinie bestimmen
|
||||
if not policy:
|
||||
policy = self.get_platform_policy(platform)
|
||||
|
||||
# Länge prüfen
|
||||
if len(username) < policy["min_length"]:
|
||||
return False, f"Benutzername ist zu kurz (mindestens {policy['min_length']} Zeichen erforderlich)"
|
||||
|
||||
if len(username) > policy["max_length"]:
|
||||
return False, f"Benutzername ist zu lang (maximal {policy['max_length']} Zeichen erlaubt)"
|
||||
|
||||
# Erlaubte Zeichen prüfen
|
||||
for char in username:
|
||||
if char not in policy["allowed_chars"]:
|
||||
return False, f"Unerlaubtes Zeichen: '{char}'"
|
||||
|
||||
# Anfangszeichen prüfen
|
||||
if username[0] not in policy["allowed_start_chars"]:
|
||||
return False, f"Benutzername darf nicht mit '{username[0]}' beginnen"
|
||||
|
||||
# Endzeichen prüfen
|
||||
if username[-1] not in policy["allowed_end_chars"]:
|
||||
return False, f"Benutzername darf nicht mit '{username[-1]}' enden"
|
||||
|
||||
# Aufeinanderfolgende Sonderzeichen prüfen
|
||||
if not policy["allowed_consecutive_special"]:
|
||||
special_chars = set(policy["allowed_chars"]) - set(string.ascii_letters + string.digits)
|
||||
for i in range(len(username) - 1):
|
||||
if username[i] in special_chars and username[i+1] in special_chars:
|
||||
return False, "Keine aufeinanderfolgenden Sonderzeichen erlaubt"
|
||||
|
||||
# Disallowed words
|
||||
for word in policy["disallowed_words"]:
|
||||
if word.lower() in username.lower():
|
||||
return False, f"Der Benutzername darf '{word}' nicht enthalten"
|
||||
|
||||
return True, "Benutzername ist gültig"
|
||||
In neuem Issue referenzieren
Einen Benutzer sperren