mirror of
https://github.com/django/django.git
synced 2025-02-20 22:34:31 +00:00
Normalized casing of "custom user model".
This commit is contained in:
parent
d02a03d574
commit
93a081946d
@ -15,7 +15,7 @@ version >= 2.2 and mod_wsgi >= 2.0. For example, you could:
|
||||
* Allow certain users to connect to a WebDAV share created with mod_dav_.
|
||||
|
||||
.. note::
|
||||
If you have installed a :ref:`custom User model <auth-custom-user>` and
|
||||
If you have installed a :ref:`custom user model <auth-custom-user>` and
|
||||
want to use this default auth handler, it must support an ``is_active``
|
||||
attribute. If you want to use group based authorization, your custom user
|
||||
must have a relation named 'groups', referring to a related object that has
|
||||
|
@ -183,9 +183,9 @@ Methods
|
||||
|
||||
.. method:: get_username()
|
||||
|
||||
Returns the username for the user. Since the User model can be swapped
|
||||
out, you should use this method instead of referencing the username
|
||||
attribute directly.
|
||||
Returns the username for the user. Since the ``User`` model can be
|
||||
swapped out, you should use this method instead of referencing the
|
||||
username attribute directly.
|
||||
|
||||
.. method:: get_full_name()
|
||||
|
||||
@ -305,7 +305,7 @@ Manager methods
|
||||
|
||||
The ``extra_fields`` keyword arguments are passed through to the
|
||||
:class:`~django.contrib.auth.models.User`’s ``__init__`` method to
|
||||
allow setting arbitrary fields on a :ref:`custom User model
|
||||
allow setting arbitrary fields on a :ref:`custom user model
|
||||
<auth-custom-user>`.
|
||||
|
||||
See :ref:`Creating users <topics-auth-creating-users>` for example usage.
|
||||
@ -615,16 +615,14 @@ The following backends are available in :mod:`django.contrib.auth.backends`:
|
||||
|
||||
.. attribute:: RemoteUserBackend.create_unknown_user
|
||||
|
||||
``True`` or ``False``. Determines whether or not a
|
||||
:class:`~django.contrib.auth.models.User` object is created if not already
|
||||
in the database. Defaults to ``True``.
|
||||
``True`` or ``False``. Determines whether or not a user object is created
|
||||
if not already in the database Defaults to ``True``.
|
||||
|
||||
.. method:: RemoteUserBackend.authenticate(request, remote_user)
|
||||
|
||||
The username passed as ``remote_user`` is considered trusted. This method
|
||||
simply returns the ``User`` object with the given username, creating a new
|
||||
``User`` object if :attr:`~RemoteUserBackend.create_unknown_user` is
|
||||
``True``.
|
||||
simply returns the user object with the given username, creating a new
|
||||
user object if :attr:`~RemoteUserBackend.create_unknown_user` is ``True``.
|
||||
|
||||
Returns ``None`` if :attr:`~RemoteUserBackend.create_unknown_user` is
|
||||
``False`` and a ``User`` object with the given username is not found in the
|
||||
@ -637,9 +635,8 @@ The following backends are available in :mod:`django.contrib.auth.backends`:
|
||||
.. method:: RemoteUserBackend.clean_username(username)
|
||||
|
||||
Performs any cleaning on the ``username`` (e.g. stripping LDAP DN
|
||||
information) prior to using it to get or create a
|
||||
:class:`~django.contrib.auth.models.User` object. Returns the cleaned
|
||||
username.
|
||||
information) prior to using it to get or create a user object. Returns the
|
||||
cleaned username.
|
||||
|
||||
.. method:: RemoteUserBackend.configure_user(user)
|
||||
|
||||
|
@ -133,7 +133,7 @@ you may need to make some changes to the way you reference User instances. You
|
||||
should also document any specific features of the User model that your
|
||||
application relies upon.
|
||||
|
||||
See the :ref:`documentation on custom User models <auth-custom-user>` for
|
||||
See the :ref:`documentation on custom user models <auth-custom-user>` for
|
||||
more details.
|
||||
|
||||
Support for saving a subset of model's fields
|
||||
@ -560,7 +560,7 @@ Prior to Django 1.5, if you attempted to log into the admin interface and
|
||||
mistakenly used your email address instead of your username, the admin
|
||||
interface would provide a warning advising that your email address was
|
||||
not your username. In Django 1.5, the introduction of
|
||||
:ref:`custom User models <auth-custom-user>` has required the removal of this
|
||||
:ref:`custom user models <auth-custom-user>` has required the removal of this
|
||||
warning. This doesn't change the login behavior of the admin site; it only
|
||||
affects the warning message that is displayed under one particular mode of
|
||||
login failure.
|
||||
@ -741,7 +741,7 @@ framework.
|
||||
``AUTH_PROFILE_MODULE``
|
||||
-----------------------
|
||||
|
||||
With the introduction of :ref:`custom User models <auth-custom-user>`, there is
|
||||
With the introduction of :ref:`custom user models <auth-custom-user>`, there is
|
||||
no longer any need for a built-in mechanism to store user profile data.
|
||||
|
||||
You can still define user profiles models that have a one-to-one relation with
|
||||
|
@ -448,7 +448,7 @@ removed and the standalone GeoDjango tests execution setup it implemented isn't
|
||||
supported anymore. To run the GeoDjango tests simply use the new
|
||||
``DiscoverRunner`` and specify the ``django.contrib.gis`` app.
|
||||
|
||||
Custom User models in tests
|
||||
Custom user models in tests
|
||||
---------------------------
|
||||
|
||||
The introduction of the new test runner has also slightly changed the way that
|
||||
|
@ -9,14 +9,14 @@ provided system are extensible or replaceable. This document provides details
|
||||
about how the auth system can be customized.
|
||||
|
||||
:ref:`Authentication backends <authentication-backends>` provide an extensible
|
||||
system for when a username and password stored with the User model need
|
||||
to be authenticated against a different service than Django's default.
|
||||
system for when a username and password stored with the user model need to be
|
||||
authenticated against a different service than Django's default.
|
||||
|
||||
You can give your models :ref:`custom permissions <custom-permissions>` that can be
|
||||
checked through Django's authorization system.
|
||||
You can give your models :ref:`custom permissions <custom-permissions>` that
|
||||
can be checked through Django's authorization system.
|
||||
|
||||
You can :ref:`extend <extending-user>` the default User model, or :ref:`substitute
|
||||
<auth-custom-user>` a completely customized model.
|
||||
You can :ref:`extend <extending-user>` the default ``User`` model, or
|
||||
:ref:`substitute <auth-custom-user>` a completely customized model.
|
||||
|
||||
.. _authentication-backends:
|
||||
|
||||
@ -94,27 +94,27 @@ a set of optional permission related :ref:`authorization methods
|
||||
<authorization_methods>`.
|
||||
|
||||
The ``get_user`` method takes a ``user_id`` -- which could be a username,
|
||||
database ID or whatever, but has to be the primary key of your ``User`` object
|
||||
-- and returns a ``User`` object.
|
||||
database ID or whatever, but has to be the primary key of your user object --
|
||||
and returns a user object.
|
||||
|
||||
The ``authenticate`` method takes a ``request`` argument and credentials as
|
||||
keyword arguments. Most of the time, it'll just look like this::
|
||||
|
||||
class MyBackend(object):
|
||||
def authenticate(self, request, username=None, password=None):
|
||||
# Check the username/password and return a User.
|
||||
# Check the username/password and return a user.
|
||||
...
|
||||
|
||||
But it could also authenticate a token, like so::
|
||||
|
||||
class MyBackend(object):
|
||||
def authenticate(self, request, token=None):
|
||||
# Check the token and return a User.
|
||||
# Check the token and return a user.
|
||||
...
|
||||
|
||||
Either way, ``authenticate`` should check the credentials it gets, and it
|
||||
should return a ``User`` object that matches those credentials, if the
|
||||
credentials are valid. If they're not valid, it should return ``None``.
|
||||
Either way, ``authenticate()`` should check the credentials it gets and return
|
||||
a user object that matches those credentials if the credentials are valid. If
|
||||
they're not valid, it should return ``None``.
|
||||
|
||||
``request`` is an :class:`~django.http.HttpRequest` and may be ``None`` if it
|
||||
wasn't provided to :func:`~django.contrib.auth.authenticate` (which passes it
|
||||
@ -364,17 +364,17 @@ add it to a ``UserAdmin`` class which is registered with the
|
||||
admin.site.unregister(User)
|
||||
admin.site.register(User, UserAdmin)
|
||||
|
||||
These profile models are not special in any way - they are just Django models that
|
||||
happen to have a one-to-one link with a User model. As such, they do not get
|
||||
These profile models are not special in any way - they are just Django models
|
||||
that happen to have a one-to-one link with a user model. As such, they aren't
|
||||
auto created when a user is created, but
|
||||
a :attr:`django.db.models.signals.post_save` could be used to create or update
|
||||
related models as appropriate.
|
||||
|
||||
Note that using related models results in additional queries or joins to
|
||||
retrieve the related data, and depending on your needs substituting the User
|
||||
model and adding the related fields may be your better option. However
|
||||
existing links to the default User model within your project's apps may justify
|
||||
the extra database load.
|
||||
Using related models results in additional queries or joins to retrieve the
|
||||
related data. Depending on your needs, a custom user model that includes the
|
||||
related fields may be your better option, however, existing relations to the
|
||||
default user model within your project's apps may justify the extra database
|
||||
load.
|
||||
|
||||
.. _auth-custom-user:
|
||||
|
||||
@ -386,14 +386,14 @@ built-in :class:`~django.contrib.auth.models.User` model is not always
|
||||
appropriate. For instance, on some sites it makes more sense to use an email
|
||||
address as your identification token instead of a username.
|
||||
|
||||
Django allows you to override the default User model by providing a value for
|
||||
Django allows you to override the default user model by providing a value for
|
||||
the :setting:`AUTH_USER_MODEL` setting that references a custom model::
|
||||
|
||||
AUTH_USER_MODEL = 'myapp.MyUser'
|
||||
|
||||
This dotted pair describes the name of the Django app (which must be in your
|
||||
:setting:`INSTALLED_APPS`), and the name of the Django model that you wish to
|
||||
use as your User model.
|
||||
use as your user model.
|
||||
|
||||
Using a custom user model when starting a project
|
||||
-------------------------------------------------
|
||||
@ -453,17 +453,17 @@ Referencing the ``User`` model
|
||||
If you reference :class:`~django.contrib.auth.models.User` directly (for
|
||||
example, by referring to it in a foreign key), your code will not work in
|
||||
projects where the :setting:`AUTH_USER_MODEL` setting has been changed to a
|
||||
different User model.
|
||||
different user model.
|
||||
|
||||
.. function:: get_user_model()
|
||||
|
||||
Instead of referring to :class:`~django.contrib.auth.models.User` directly,
|
||||
you should reference the user model using
|
||||
``django.contrib.auth.get_user_model()``. This method will return the
|
||||
currently active User model -- the custom User model if one is specified, or
|
||||
currently active user model -- the custom user model if one is specified, or
|
||||
:class:`~django.contrib.auth.models.User` otherwise.
|
||||
|
||||
When you define a foreign key or many-to-many relations to the User model,
|
||||
When you define a foreign key or many-to-many relations to the user model,
|
||||
you should specify the custom model using the :setting:`AUTH_USER_MODEL`
|
||||
setting. For example::
|
||||
|
||||
@ -476,7 +476,7 @@ different User model.
|
||||
on_delete=models.CASCADE,
|
||||
)
|
||||
|
||||
When connecting to signals sent by the ``User`` model, you should specify
|
||||
When connecting to signals sent by the user model, you should specify
|
||||
the custom model using the :setting:`AUTH_USER_MODEL` setting. For example::
|
||||
|
||||
from django.conf import settings
|
||||
@ -487,27 +487,27 @@ different User model.
|
||||
|
||||
post_save.connect(post_save_receiver, sender=settings.AUTH_USER_MODEL)
|
||||
|
||||
Generally speaking, you should reference the User model with the
|
||||
Generally speaking, you should reference the user model with the
|
||||
:setting:`AUTH_USER_MODEL` setting in code that is executed at import
|
||||
time. ``get_user_model()`` only works once Django has imported all models.
|
||||
|
||||
.. _specifying-custom-user-model:
|
||||
|
||||
Specifying a custom ``User`` model
|
||||
----------------------------------
|
||||
Specifying a custom user model
|
||||
------------------------------
|
||||
|
||||
.. admonition:: Model design considerations
|
||||
|
||||
Think carefully before handling information not directly related to
|
||||
authentication in your custom User Model.
|
||||
authentication in your custom user model.
|
||||
|
||||
It may be better to store app-specific user information in a model
|
||||
that has a relation with the User model. That allows each app to specify
|
||||
that has a relation with the user model. That allows each app to specify
|
||||
its own user data requirements without risking conflicts with other
|
||||
apps. On the other hand, queries to retrieve this related information
|
||||
will involve a database join, which may have an effect on performance.
|
||||
|
||||
Django expects your custom User model to meet some minimum requirements.
|
||||
Django expects your custom user model to meet some minimum requirements.
|
||||
|
||||
#. If you use the default authentication backend, then your model must have a
|
||||
single unique field that can be used for identification purposes. This can
|
||||
@ -522,10 +522,10 @@ Django expects your custom User model to meet some minimum requirements.
|
||||
what these two methods return - if you want, they can return exactly
|
||||
the same value.
|
||||
|
||||
The easiest way to construct a compliant custom User model is to inherit from
|
||||
The easiest way to construct a compliant custom user model is to inherit from
|
||||
:class:`~django.contrib.auth.models.AbstractBaseUser`.
|
||||
:class:`~django.contrib.auth.models.AbstractBaseUser` provides the core
|
||||
implementation of a ``User`` model, including hashed passwords and tokenized
|
||||
implementation of a user model, including hashed passwords and tokenized
|
||||
password resets. You must then provide some key implementation details:
|
||||
|
||||
.. currentmodule:: django.contrib.auth
|
||||
@ -534,7 +534,7 @@ password resets. You must then provide some key implementation details:
|
||||
|
||||
.. attribute:: USERNAME_FIELD
|
||||
|
||||
A string describing the name of the field on the User model that is
|
||||
A string describing the name of the field on the user model that is
|
||||
used as the unique identifier. This will usually be a username of some
|
||||
kind, but it can also be an email address, or any other unique
|
||||
identifier. The field *must* be unique (i.e., have ``unique=True`` set
|
||||
@ -575,7 +575,7 @@ password resets. You must then provide some key implementation details:
|
||||
``REQUIRED_FIELDS`` has no effect in other parts of Django, like
|
||||
creating a user in the admin.
|
||||
|
||||
For example, here is the partial definition for a ``User`` model that
|
||||
For example, here is the partial definition for a user model that
|
||||
defines two required fields - a date of birth and height::
|
||||
|
||||
class MyUser(AbstractBaseUser):
|
||||
@ -587,8 +587,8 @@ password resets. You must then provide some key implementation details:
|
||||
|
||||
.. note::
|
||||
|
||||
``REQUIRED_FIELDS`` must contain all required fields on your
|
||||
``User`` model, but should *not* contain the ``USERNAME_FIELD`` or
|
||||
``REQUIRED_FIELDS`` must contain all required fields on your user
|
||||
model, but should *not* contain the ``USERNAME_FIELD`` or
|
||||
``password`` as these fields will always be prompted for.
|
||||
|
||||
:attr:`REQUIRED_FIELDS` now supports
|
||||
@ -739,14 +739,13 @@ The following attributes and methods are available on any subclass of
|
||||
:meth:`.BaseUserManager.normalize_email`. If you override this method,
|
||||
be sure to call ``super()`` to retain the normalization.
|
||||
|
||||
You should also define a custom manager for your ``User`` model. If your
|
||||
``User`` model defines ``username``, ``email``, ``is_staff``, ``is_active``,
|
||||
``is_superuser``, ``last_login``, and ``date_joined`` fields the same as
|
||||
Django's default ``User``, you can just install Django's
|
||||
:class:`~django.contrib.auth.models.UserManager`; however, if your ``User``
|
||||
model defines different fields, you will need to define a custom manager that
|
||||
extends :class:`~django.contrib.auth.models.BaseUserManager` providing two
|
||||
additional methods:
|
||||
You should also define a custom manager for your user model. If your user model
|
||||
defines ``username``, ``email``, ``is_staff``, ``is_active``, ``is_superuser``,
|
||||
``last_login``, and ``date_joined`` fields the same as Django's default user,
|
||||
you can just install Django's :class:`~django.contrib.auth.models.UserManager`;
|
||||
however, if your user model defines different fields, you'll need to define a
|
||||
custom manager that extends :class:`~django.contrib.auth.models.BaseUserManager`
|
||||
providing two additional methods:
|
||||
|
||||
.. class:: models.CustomUserManager
|
||||
|
||||
@ -862,9 +861,9 @@ can extend these forms in this manner::
|
||||
Custom users and :mod:`django.contrib.admin`
|
||||
--------------------------------------------
|
||||
|
||||
If you want your custom User model to also work with Admin, your User model must
|
||||
define some additional attributes and methods. These methods allow the admin to
|
||||
control access of the User to admin content:
|
||||
If you want your custom user model to also work with the admin, your user model
|
||||
must define some additional attributes and methods. These methods allow the
|
||||
admin to control access of the user to admin content:
|
||||
|
||||
.. class:: models.CustomUser
|
||||
|
||||
@ -887,23 +886,23 @@ control access of the User to admin content:
|
||||
Returns ``True`` if the user has permission to access models in
|
||||
the given app.
|
||||
|
||||
You will also need to register your custom User model with the admin. If
|
||||
your custom User model extends ``django.contrib.auth.models.AbstractUser``,
|
||||
You will also need to register your custom user model with the admin. If
|
||||
your custom user model extends ``django.contrib.auth.models.AbstractUser``,
|
||||
you can use Django's existing ``django.contrib.auth.admin.UserAdmin``
|
||||
class. However, if your User model extends
|
||||
class. However, if your user model extends
|
||||
:class:`~django.contrib.auth.models.AbstractBaseUser`, you'll need to define
|
||||
a custom ``ModelAdmin`` class. It may be possible to subclass the default
|
||||
``django.contrib.auth.admin.UserAdmin``; however, you'll need to
|
||||
override any of the definitions that refer to fields on
|
||||
``django.contrib.auth.models.AbstractUser`` that aren't on your
|
||||
custom User class.
|
||||
custom user class.
|
||||
|
||||
Custom users and permissions
|
||||
----------------------------
|
||||
|
||||
To make it easy to include Django's permission framework into your own User
|
||||
To make it easy to include Django's permission framework into your own user
|
||||
class, Django provides :class:`~django.contrib.auth.models.PermissionsMixin`.
|
||||
This is an abstract model you can include in the class hierarchy for your User
|
||||
This is an abstract model you can include in the class hierarchy for your user
|
||||
model, giving you all the methods and database fields necessary to support
|
||||
Django's permission model.
|
||||
|
||||
@ -964,21 +963,21 @@ methods and attributes:
|
||||
If you don't include the
|
||||
:class:`~django.contrib.auth.models.PermissionsMixin`, you must ensure you
|
||||
don't invoke the permissions methods on ``ModelBackend``. ``ModelBackend``
|
||||
assumes that certain fields are available on your user model. If your
|
||||
``User`` model doesn't provide those fields, you will receive database
|
||||
errors when you check permissions.
|
||||
assumes that certain fields are available on your user model. If your user
|
||||
model doesn't provide those fields, you'll receive database errors when
|
||||
you check permissions.
|
||||
|
||||
Custom users and proxy models
|
||||
-----------------------------
|
||||
|
||||
One limitation of custom User models is that installing a custom User model
|
||||
One limitation of custom user models is that installing a custom user model
|
||||
will break any proxy model extending :class:`~django.contrib.auth.models.User`.
|
||||
Proxy models must be based on a concrete base class; by defining a custom User
|
||||
Proxy models must be based on a concrete base class; by defining a custom user
|
||||
model, you remove the ability of Django to reliably identify the base class.
|
||||
|
||||
If your project uses proxy models, you must either modify the proxy to extend
|
||||
the User model that is currently in use in your project, or merge your proxy's
|
||||
behavior into your User subclass.
|
||||
the user model that's in use in your project, or merge your proxy's behavior
|
||||
into your :class:`~django.contrib.auth.models.User` subclass.
|
||||
|
||||
A full example
|
||||
--------------
|
||||
@ -987,7 +986,7 @@ Here is an example of an admin-compliant custom user app. This user model uses
|
||||
an email address as the username, and has a required date of birth; it
|
||||
provides no permission checking, beyond a simple ``admin`` flag on the user
|
||||
account. This model would be compatible with all the built-in auth forms and
|
||||
views, except for the User creation forms. This example illustrates how most of
|
||||
views, except for the user creation forms. This example illustrates how most of
|
||||
the components work together, but is not intended to be copied directly into
|
||||
projects for production use.
|
||||
|
||||
@ -1075,7 +1074,7 @@ authentication app::
|
||||
# Simplest possible answer: All admins are staff
|
||||
return self.is_admin
|
||||
|
||||
Then, to register this custom User model with Django's admin, the following
|
||||
Then, to register this custom user model with Django's admin, the following
|
||||
code would be required in the app's ``admin.py`` file::
|
||||
|
||||
from django import forms
|
||||
|
@ -86,7 +86,7 @@ function is used when creating a user.
|
||||
To change a user's password, you have several options:
|
||||
|
||||
:djadmin:`manage.py changepassword *username* <changepassword>` offers a method
|
||||
of changing a User's password from the command line. It prompts you to
|
||||
of changing a user's password from the command line. It prompts you to
|
||||
change the password of a given user which you must enter twice. If
|
||||
they both match, the new password will be changed immediately. If you
|
||||
do not supply a user, the command will attempt to change the password
|
||||
@ -267,12 +267,12 @@ Permission caching
|
||||
------------------
|
||||
|
||||
The :class:`~django.contrib.auth.backends.ModelBackend` caches permissions on
|
||||
the ``User`` object after the first time they need to be fetched for a
|
||||
permissions check. This is typically fine for the request-response cycle since
|
||||
permissions are not typically checked immediately after they are added (in the
|
||||
admin, for example). If you are adding permissions and checking them immediately
|
||||
the user object after the first time they need to be fetched for a permissions
|
||||
check. This is typically fine for the request-response cycle since permissions
|
||||
aren't typically checked immediately after they are added (in the admin, for
|
||||
example). If you are adding permissions and checking them immediately
|
||||
afterward, in a test or view for example, the easiest solution is to re-fetch
|
||||
the ``User`` from the database. For example::
|
||||
the user from the database. For example::
|
||||
|
||||
from django.contrib.auth.models import Permission, User
|
||||
from django.shortcuts import get_object_or_404
|
||||
@ -380,7 +380,7 @@ is selected as follows:
|
||||
pairing :func:`~django.contrib.auth.authenticate()` and
|
||||
:func:`~django.contrib.auth.login()`:
|
||||
:func:`~django.contrib.auth.authenticate()`
|
||||
sets the ``user.backend`` attribute on the ``User`` object it returns.
|
||||
sets the ``user.backend`` attribute on the user object it returns.
|
||||
#. Use the ``backend`` in :setting:`AUTHENTICATION_BACKENDS`, if there is only
|
||||
one.
|
||||
#. Otherwise, raise an exception.
|
||||
@ -1602,7 +1602,7 @@ provides several built-in forms located in :mod:`django.contrib.auth.forms`:
|
||||
|
||||
.. note::
|
||||
The built-in authentication forms make certain assumptions about the user
|
||||
model that they are working with. If you're using a :ref:`custom User model
|
||||
model that they are working with. If you're using a :ref:`custom user model
|
||||
<auth-custom-user>`, it may be necessary to define your own forms for the
|
||||
authentication system. For more information, refer to the documentation
|
||||
about :ref:`using the built-in authentication forms with custom user models
|
||||
|
@ -6,7 +6,7 @@ from django.db import models
|
||||
from django.utils.encoding import python_2_unicode_compatible
|
||||
|
||||
|
||||
# The custom User uses email as the unique identifier, and requires
|
||||
# The custom user uses email as the unique identifier, and requires
|
||||
# that every user provide a date of birth. This lets us test
|
||||
# changes in username datatype, and non-text required fields.
|
||||
class CustomUserManager(BaseUserManager):
|
||||
|
@ -263,7 +263,7 @@ class CreatesuperuserManagementCommandTestCase(TestCase):
|
||||
|
||||
@override_settings(AUTH_USER_MODEL='auth_tests.CustomUser')
|
||||
def test_swappable_user(self):
|
||||
"A superuser can be created when a custom User model is in use"
|
||||
"A superuser can be created when a custom user model is in use"
|
||||
# We can use the management command to create a superuser
|
||||
# We skip validation because the temporary substitution of the
|
||||
# swappable User model messes with validation.
|
||||
|
Loading…
x
Reference in New Issue
Block a user