We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
Il est possible de choisir un pseudo invalide
**Description du bug**

Il est possible de choisir un pseudo un peu farfelu comme par exemple `https://viki53.eu` qui est dans certains cas invalide : la fonction `reverse_lazy('tutorial:find-tutorial', args=(profile.user.username,))` qui permet de retrouver l'URL `'tutoriels/voir/(?P<username>[^/]+)/$'` retourne une erreur `NoReverseMatch`.

**Comment reproduire ?**

La liste des étapes qui permet de reproduire le bug :

1. Se renommer en `https://viki53.eu`
2. Aller sur son profil et constater l'erreur interne

**Comportement attendu**

Aucune erreur interne.

**Solution possible**

Il serait possible d'ajouter une petite vérification lors du changement de pseudo pour refuser les pseudos invalides : 

```py
try:
    reverse_lazy('tutorial:find-tutorial', args=(profile.user.username,))
except NoReverseMatch:
    # Refuser le pseudo
```

--- END ISSUE ---

Below are some code segments, each from a relevant file. One or more of these files may contain bugs.
--- BEGIN FILES ---
Path: `zds/member/validators.py`
Content:
```
1 from django.contrib.auth.models import User
2 from django.core.exceptions import ValidationError
3 from django.core.validators import EmailValidator
4 from django.utils.encoding import force_str
5 from django.utils.translation import gettext_lazy as _
6 
7 from zds.utils.misc import contains_utf8mb4
8 from zds.member.models import BannedEmailProvider, Profile
9 
10 
11 def validate_not_empty(value):
12     """
13     Fields cannot be empty or only contain spaces.
14 
15     :param value: value to validate (str or None)
16     :return:
17     """
18     if value is None or not value.strip():
19         raise ValidationError(_("Le champs ne peut être vide"))
20 
21 
22 class ZdSEmailValidator(EmailValidator):
23     """
24     Based on https://docs.djangoproject.com/en/1.8/_modules/django/core/validators/#EmailValidator
25     Changed :
26       - check if provider is not if blacklisted
27       - check if email is not used by another user
28       - remove whitelist check
29       - add custom errors and translate them into French
30     """
31 
32     message = _("Utilisez une adresse de courriel valide.")
33 
34     def __call__(self, value, check_username_available=True):
35         value = force_str(value)
36 
37         if not value or "@" not in value:
38             raise ValidationError(self.message, code=self.code)
39 
40         user_part, domain_part = value.rsplit("@", 1)
41 
42         if not self.user_regex.match(user_part) or contains_utf8mb4(user_part):
43             raise ValidationError(self.message, code=self.code)
44 
45         # check if provider is blacklisted
46         blacklist = BannedEmailProvider.objects.values_list("provider", flat=True)
47         for provider in blacklist:
48             if f"@{provider}" in value.lower():
49                 raise ValidationError(_("Ce fournisseur ne peut pas être utilisé."), code=self.code)
50 
51         # check if email is used by another user
52         user_count = User.objects.filter(email=value).count()
53         if check_username_available and user_count > 0:
54             raise ValidationError(_("Cette adresse courriel est déjà utilisée"), code=self.code)
55         # check if email exists in database
56         elif not check_username_available and user_count == 0:
57             raise ValidationError(_("Cette adresse courriel n'existe pas"), code=self.code)
58 
59         if domain_part and not self.validate_domain_part(domain_part):
60             # Try for possible IDN domain-part
61             try:
62                 domain_part = domain_part.encode("idna").decode("ascii")
63                 if self.validate_domain_part(domain_part):
64                     return
65             except UnicodeError:
66                 pass
67             raise ValidationError(self.message, code=self.code)
68 
69 
70 validate_zds_email = ZdSEmailValidator()
71 
72 
73 def validate_zds_username(value, check_username_available=True):
74     """
75     Check if username is used by another user
76 
77     :param value: value to validate (str or None)
78     :return:
79     """
80     msg = None
81     user_count = User.objects.filter(username=value).count()
82     skeleton_user_count = Profile.objects.filter(username_skeleton=Profile.find_username_skeleton(value)).count()
83     if "," in value:
84         msg = _("Le nom d'utilisateur ne peut contenir de virgules")
85     elif contains_utf8mb4(value):
86         msg = _("Le nom d'utilisateur ne peut pas contenir des caractères utf8mb4")
87     elif check_username_available and user_count > 0:
88         msg = _("Ce nom d'utilisateur est déjà utilisé")
89     elif check_username_available and skeleton_user_count > 0:
90         msg = _("Un nom d'utilisateur visuellement proche du votre existe déjà")
91     elif not check_username_available and user_count == 0:
92         msg = _("Ce nom d'utilisateur n'existe pas")
93     if msg is not None:
94         raise ValidationError(msg)
95 
96 
97 def validate_raw_zds_username(data):
98     """
99     Check if raw username hasn't space on left or right
100     """
101     msg = None
102     username = data.get("username", None)
103     if username is None:
104         msg = _("Le nom d'utilisateur n'est pas fourni")
105     elif username != username.strip():
106         msg = _("Le nom d'utilisateur ne peut commencer ou finir par des espaces")
107 
108     if msg is not None:
109         raise ValidationError(msg)
110 
111 
112 def validate_zds_password(value):
113     """
114 
115     :param value:
116     :return:
117     """
118     if contains_utf8mb4(value):
119         raise ValidationError(_("Le mot de passe ne peut pas contenir des caractères utf8mb4"))
120 
121 
122 def validate_passwords(
123     cleaned_data, password_label="password", password_confirm_label="password_confirm", username=None
124 ):
125     """
126     Chek if cleaned_data['password'] == cleaned_data['password_confirm'] and password is not username.
127     :param cleaned_data:
128     :param password_label:
129     :param password_confirm_label:
130     :return:
131     """
132 
133     password = cleaned_data.get(password_label)
134     password_confirm = cleaned_data.get(password_confirm_label)
135     msg = None
136 
137     if username is None:
138         username = cleaned_data.get("username")
139 
140     if not password_confirm == password:
141         msg = _("Les mots de passe sont différents")
142 
143         if password_label in cleaned_data:
144             del cleaned_data[password_label]
145 
146         if password_confirm_label in cleaned_data:
147             del cleaned_data[password_confirm_label]
148 
149     if username is not None:
150         # Check that password != username
151         if password == username:
152             msg = _("Le mot de passe doit être différent du pseudo")
153             if password_label in cleaned_data:
154                 del cleaned_data[password_label]
155             if password_confirm_label in cleaned_data:
156                 del cleaned_data[password_confirm_label]
157 
158     if msg is not None:
159         raise ValidationError(msg)
160 
161     return cleaned_data
162
```
--- END FILES ---

Please first localize the bug based on the issue statement, and then generate a patch according to the `git diff` format fenced by three backticks.

Here is an example:

```diff
diff --git a/examples/server_async.py b/examples/server_async.py
--- a/examples/server_async.py
+++ b/examples/server_async.py
@@ -313,4 +313,4 @@
 
 
 if __name__ == "__main__":
-    asyncio.run(run_async_server("."), debug=True)
+    asyncio.run(run_async_server(), debug=True)
diff --git a/examples/server_sync.py b/examples/server_sync.py
--- a/examples/server_sync.py
+++ b/examples/server_sync.py
@@ -313,5 +313,5 @@
 
 
 if __name__ == "__main__":
-    server = run_sync_server(".")
+    server = run_sync_server()
     server.shutdown()

```

diff --git a/zds/member/validators.py b/zds/member/validators.py
--- a/zds/member/validators.py
+++ b/zds/member/validators.py
@@ -82,6 +82,8 @@
     skeleton_user_count = Profile.objects.filter(username_skeleton=Profile.find_username_skeleton(value)).count()
     if "," in value:
         msg = _("Le nom d'utilisateur ne peut contenir de virgules")
+    if "/" in value:
+        msg = _("Le nom d'utilisateur ne peut contenir de barres obliques")
     elif contains_utf8mb4(value):
         msg = _("Le nom d'utilisateur ne peut pas contenir des caractères utf8mb4")
     elif check_username_available and user_count > 0:

{"golden_diff": "diff --git a/zds/member/validators.py b/zds/member/validators.py\n--- a/zds/member/validators.py\n+++ b/zds/member/validators.py\n@@ -82,6 +82,8 @@\n     skeleton_user_count = Profile.objects.filter(username_skeleton=Profile.find_username_skeleton(value)).count()\n     if \",\" in value:\n         msg = _(\"Le nom d'utilisateur ne peut contenir de virgules\")\n+    if \"/\" in value:\n+        msg = _(\"Le nom d'utilisateur ne peut contenir de barres obliques\")\n     elif contains_utf8mb4(value):\n         msg = _(\"Le nom d'utilisateur ne peut pas contenir des caract\u00e8res utf8mb4\")\n     elif check_username_available and user_count > 0:\n", "issue": "Il est possible de choisir un pseudo invalide\n**Description du bug**\r\n\r\nIl est possible de choisir un pseudo un peu farfelu comme par exemple `https://viki53.eu` qui est dans certains cas invalide : la fonction `reverse_lazy('tutorial:find-tutorial', args=(profile.user.username,))` qui permet de retrouver l'URL `'tutoriels/voir/(?P<username>[^/]+)/$'` retourne une erreur `NoReverseMatch`.\r\n\r\n**Comment reproduire ?**\r\n\r\nLa liste des \u00e9tapes qui permet de reproduire le bug :\r\n\r\n1. Se renommer en `https://viki53.eu`\r\n2. Aller sur son profil et constater l'erreur interne\r\n\r\n**Comportement attendu**\r\n\r\nAucune erreur interne.\r\n\r\n**Solution possible**\r\n\r\nIl serait possible d'ajouter une petite v\u00e9rification lors du changement de pseudo pour refuser les pseudos invalides : \r\n\r\n```py\r\ntry:\r\n    reverse_lazy('tutorial:find-tutorial', args=(profile.user.username,))\r\nexcept NoReverseMatch:\r\n    # Refuser le pseudo\r\n```\n", "before_files": [{"content": "from django.contrib.auth.models import User\nfrom django.core.exceptions import ValidationError\nfrom django.core.validators import EmailValidator\nfrom django.utils.encoding import force_str\nfrom django.utils.translation import gettext_lazy as _\n\nfrom zds.utils.misc import contains_utf8mb4\nfrom zds.member.models import BannedEmailProvider, Profile\n\n\ndef validate_not_empty(value):\n    \"\"\"\n    Fields cannot be empty or only contain spaces.\n\n    :param value: value to validate (str or None)\n    :return:\n    \"\"\"\n    if value is None or not value.strip():\n        raise ValidationError(_(\"Le champs ne peut \u00eatre vide\"))\n\n\nclass ZdSEmailValidator(EmailValidator):\n    \"\"\"\n    Based on https://docs.djangoproject.com/en/1.8/_modules/django/core/validators/#EmailValidator\n    Changed :\n      - check if provider is not if blacklisted\n      - check if email is not used by another user\n      - remove whitelist check\n      - add custom errors and translate them into French\n    \"\"\"\n\n    message = _(\"Utilisez une adresse de courriel valide.\")\n\n    def __call__(self, value, check_username_available=True):\n        value = force_str(value)\n\n        if not value or \"@\" not in value:\n            raise ValidationError(self.message, code=self.code)\n\n        user_part, domain_part = value.rsplit(\"@\", 1)\n\n        if not self.user_regex.match(user_part) or contains_utf8mb4(user_part):\n            raise ValidationError(self.message, code=self.code)\n\n        # check if provider is blacklisted\n        blacklist = BannedEmailProvider.objects.values_list(\"provider\", flat=True)\n        for provider in blacklist:\n            if f\"@{provider}\" in value.lower():\n                raise ValidationError(_(\"Ce fournisseur ne peut pas \u00eatre utilis\u00e9.\"), code=self.code)\n\n        # check if email is used by another user\n        user_count = User.objects.filter(email=value).count()\n        if check_username_available and user_count > 0:\n            raise ValidationError(_(\"Cette adresse courriel est d\u00e9j\u00e0 utilis\u00e9e\"), code=self.code)\n        # check if email exists in database\n        elif not check_username_available and user_count == 0:\n            raise ValidationError(_(\"Cette adresse courriel n'existe pas\"), code=self.code)\n\n        if domain_part and not self.validate_domain_part(domain_part):\n            # Try for possible IDN domain-part\n            try:\n                domain_part = domain_part.encode(\"idna\").decode(\"ascii\")\n                if self.validate_domain_part(domain_part):\n                    return\n            except UnicodeError:\n                pass\n            raise ValidationError(self.message, code=self.code)\n\n\nvalidate_zds_email = ZdSEmailValidator()\n\n\ndef validate_zds_username(value, check_username_available=True):\n    \"\"\"\n    Check if username is used by another user\n\n    :param value: value to validate (str or None)\n    :return:\n    \"\"\"\n    msg = None\n    user_count = User.objects.filter(username=value).count()\n    skeleton_user_count = Profile.objects.filter(username_skeleton=Profile.find_username_skeleton(value)).count()\n    if \",\" in value:\n        msg = _(\"Le nom d'utilisateur ne peut contenir de virgules\")\n    elif contains_utf8mb4(value):\n        msg = _(\"Le nom d'utilisateur ne peut pas contenir des caract\u00e8res utf8mb4\")\n    elif check_username_available and user_count > 0:\n        msg = _(\"Ce nom d'utilisateur est d\u00e9j\u00e0 utilis\u00e9\")\n    elif check_username_available and skeleton_user_count > 0:\n        msg = _(\"Un nom d'utilisateur visuellement proche du votre existe d\u00e9j\u00e0\")\n    elif not check_username_available and user_count == 0:\n        msg = _(\"Ce nom d'utilisateur n'existe pas\")\n    if msg is not None:\n        raise ValidationError(msg)\n\n\ndef validate_raw_zds_username(data):\n    \"\"\"\n    Check if raw username hasn't space on left or right\n    \"\"\"\n    msg = None\n    username = data.get(\"username\", None)\n    if username is None:\n        msg = _(\"Le nom d'utilisateur n'est pas fourni\")\n    elif username != username.strip():\n        msg = _(\"Le nom d'utilisateur ne peut commencer ou finir par des espaces\")\n\n    if msg is not None:\n        raise ValidationError(msg)\n\n\ndef validate_zds_password(value):\n    \"\"\"\n\n    :param value:\n    :return:\n    \"\"\"\n    if contains_utf8mb4(value):\n        raise ValidationError(_(\"Le mot de passe ne peut pas contenir des caract\u00e8res utf8mb4\"))\n\n\ndef validate_passwords(\n    cleaned_data, password_label=\"password\", password_confirm_label=\"password_confirm\", username=None\n):\n    \"\"\"\n    Chek if cleaned_data['password'] == cleaned_data['password_confirm'] and password is not username.\n    :param cleaned_data:\n    :param password_label:\n    :param password_confirm_label:\n    :return:\n    \"\"\"\n\n    password = cleaned_data.get(password_label)\n    password_confirm = cleaned_data.get(password_confirm_label)\n    msg = None\n\n    if username is None:\n        username = cleaned_data.get(\"username\")\n\n    if not password_confirm == password:\n        msg = _(\"Les mots de passe sont diff\u00e9rents\")\n\n        if password_label in cleaned_data:\n            del cleaned_data[password_label]\n\n        if password_confirm_label in cleaned_data:\n            del cleaned_data[password_confirm_label]\n\n    if username is not None:\n        # Check that password != username\n        if password == username:\n            msg = _(\"Le mot de passe doit \u00eatre diff\u00e9rent du pseudo\")\n            if password_label in cleaned_data:\n                del cleaned_data[password_label]\n            if password_confirm_label in cleaned_data:\n                del cleaned_data[password_confirm_label]\n\n    if msg is not None:\n        raise ValidationError(msg)\n\n    return cleaned_data\n", "path": "zds/member/validators.py"}], "after_files": [{"content": "from django.contrib.auth.models import User\nfrom django.core.exceptions import ValidationError\nfrom django.core.validators import EmailValidator\nfrom django.utils.encoding import force_str\nfrom django.utils.translation import gettext_lazy as _\n\nfrom zds.utils.misc import contains_utf8mb4\nfrom zds.member.models import BannedEmailProvider, Profile\n\n\ndef validate_not_empty(value):\n    \"\"\"\n    Fields cannot be empty or only contain spaces.\n\n    :param value: value to validate (str or None)\n    :return:\n    \"\"\"\n    if value is None or not value.strip():\n        raise ValidationError(_(\"Le champs ne peut \u00eatre vide\"))\n\n\nclass ZdSEmailValidator(EmailValidator):\n    \"\"\"\n    Based on https://docs.djangoproject.com/en/1.8/_modules/django/core/validators/#EmailValidator\n    Changed :\n      - check if provider is not if blacklisted\n      - check if email is not used by another user\n      - remove whitelist check\n      - add custom errors and translate them into French\n    \"\"\"\n\n    message = _(\"Utilisez une adresse de courriel valide.\")\n\n    def __call__(self, value, check_username_available=True):\n        value = force_str(value)\n\n        if not value or \"@\" not in value:\n            raise ValidationError(self.message, code=self.code)\n\n        user_part, domain_part = value.rsplit(\"@\", 1)\n\n        if not self.user_regex.match(user_part) or contains_utf8mb4(user_part):\n            raise ValidationError(self.message, code=self.code)\n\n        # check if provider is blacklisted\n        blacklist = BannedEmailProvider.objects.values_list(\"provider\", flat=True)\n        for provider in blacklist:\n            if f\"@{provider}\" in value.lower():\n                raise ValidationError(_(\"Ce fournisseur ne peut pas \u00eatre utilis\u00e9.\"), code=self.code)\n\n        # check if email is used by another user\n        user_count = User.objects.filter(email=value).count()\n        if check_username_available and user_count > 0:\n            raise ValidationError(_(\"Cette adresse courriel est d\u00e9j\u00e0 utilis\u00e9e\"), code=self.code)\n        # check if email exists in database\n        elif not check_username_available and user_count == 0:\n            raise ValidationError(_(\"Cette adresse courriel n'existe pas\"), code=self.code)\n\n        if domain_part and not self.validate_domain_part(domain_part):\n            # Try for possible IDN domain-part\n            try:\n                domain_part = domain_part.encode(\"idna\").decode(\"ascii\")\n                if self.validate_domain_part(domain_part):\n                    return\n            except UnicodeError:\n                pass\n            raise ValidationError(self.message, code=self.code)\n\n\nvalidate_zds_email = ZdSEmailValidator()\n\n\ndef validate_zds_username(value, check_username_available=True):\n    \"\"\"\n    Check if username is used by another user\n\n    :param value: value to validate (str or None)\n    :return:\n    \"\"\"\n    msg = None\n    user_count = User.objects.filter(username=value).count()\n    skeleton_user_count = Profile.objects.filter(username_skeleton=Profile.find_username_skeleton(value)).count()\n    if \",\" in value:\n        msg = _(\"Le nom d'utilisateur ne peut contenir de virgules\")\n    if \"/\" in value:\n        msg = _(\"Le nom d'utilisateur ne peut contenir de barres obliques\")\n    elif contains_utf8mb4(value):\n        msg = _(\"Le nom d'utilisateur ne peut pas contenir des caract\u00e8res utf8mb4\")\n    elif check_username_available and user_count > 0:\n        msg = _(\"Ce nom d'utilisateur est d\u00e9j\u00e0 utilis\u00e9\")\n    elif check_username_available and skeleton_user_count > 0:\n        msg = _(\"Un nom d'utilisateur visuellement proche du votre existe d\u00e9j\u00e0\")\n    elif not check_username_available and user_count == 0:\n        msg = _(\"Ce nom d'utilisateur n'existe pas\")\n    if msg is not None:\n        raise ValidationError(msg)\n\n\ndef validate_raw_zds_username(data):\n    \"\"\"\n    Check if raw username hasn't space on left or right\n    \"\"\"\n    msg = None\n    username = data.get(\"username\", None)\n    if username is None:\n        msg = _(\"Le nom d'utilisateur n'est pas fourni\")\n    elif username != username.strip():\n        msg = _(\"Le nom d'utilisateur ne peut commencer ou finir par des espaces\")\n\n    if msg is not None:\n        raise ValidationError(msg)\n\n\ndef validate_zds_password(value):\n    \"\"\"\n\n    :param value:\n    :return:\n    \"\"\"\n    if contains_utf8mb4(value):\n        raise ValidationError(_(\"Le mot de passe ne peut pas contenir des caract\u00e8res utf8mb4\"))\n\n\ndef validate_passwords(\n    cleaned_data, password_label=\"password\", password_confirm_label=\"password_confirm\", username=None\n):\n    \"\"\"\n    Chek if cleaned_data['password'] == cleaned_data['password_confirm'] and password is not username.\n    :param cleaned_data:\n    :param password_label:\n    :param password_confirm_label:\n    :return:\n    \"\"\"\n\n    password = cleaned_data.get(password_label)\n    password_confirm = cleaned_data.get(password_confirm_label)\n    msg = None\n\n    if username is None:\n        username = cleaned_data.get(\"username\")\n\n    if not password_confirm == password:\n        msg = _(\"Les mots de passe sont diff\u00e9rents\")\n\n        if password_label in cleaned_data:\n            del cleaned_data[password_label]\n\n        if password_confirm_label in cleaned_data:\n            del cleaned_data[password_confirm_label]\n\n    if username is not None:\n        # Check that password != username\n        if password == username:\n            msg = _(\"Le mot de passe doit \u00eatre diff\u00e9rent du pseudo\")\n            if password_label in cleaned_data:\n                del cleaned_data[password_label]\n            if password_confirm_label in cleaned_data:\n                del cleaned_data[password_confirm_label]\n\n    if msg is not None:\n        raise ValidationError(msg)\n\n    return cleaned_data\n", "path": "zds/member/validators.py"}]}