Fixed #26089 -- Removed custom user test models from public API.
Thanks to Tim Graham for the review.
This commit is contained in:
parent
19318507d9
commit
6eb3ce11e4
|
@ -448,6 +448,13 @@ output::
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
``auth.CustomUser`` and ``auth.ExtensionUser`` test models were removed.
|
||||||
|
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
|
Since the introduction of migrations for the contrib apps in Django 1.8, the
|
||||||
|
tables of these custom user test models were not created anymore making them
|
||||||
|
unusable in a testing context.
|
||||||
|
|
||||||
Miscellaneous
|
Miscellaneous
|
||||||
~~~~~~~~~~~~~
|
~~~~~~~~~~~~~
|
||||||
|
|
||||||
|
|
|
@ -1,10 +1,12 @@
|
||||||
from .custom_permissions import CustomPermissionsUser
|
from .custom_permissions import CustomPermissionsUser
|
||||||
|
from .custom_user import CustomUser, ExtensionUser
|
||||||
from .invalid_models import CustomUserNonUniqueUsername
|
from .invalid_models import CustomUserNonUniqueUsername
|
||||||
from .is_active import IsActiveTestUser1
|
from .is_active import IsActiveTestUser1
|
||||||
from .uuid_pk import UUIDUser
|
from .uuid_pk import UUIDUser
|
||||||
from .with_foreign_key import CustomUserWithFK, Email
|
from .with_foreign_key import CustomUserWithFK, Email
|
||||||
|
|
||||||
__all__ = (
|
__all__ = (
|
||||||
'CustomPermissionsUser', 'CustomUserWithFK', 'Email',
|
'CustomUser', 'CustomPermissionsUser', 'CustomUserWithFK', 'Email',
|
||||||
'IsActiveTestUser1', 'UUIDUser', 'CustomUserNonUniqueUsername',
|
'ExtensionUser', 'IsActiveTestUser1', 'UUIDUser',
|
||||||
|
'CustomUserNonUniqueUsername',
|
||||||
)
|
)
|
||||||
|
|
|
@ -4,12 +4,11 @@ Django permissions model. This allows us to check that the PermissionsMixin
|
||||||
includes everything that is needed to interact with the ModelBackend.
|
includes everything that is needed to interact with the ModelBackend.
|
||||||
"""
|
"""
|
||||||
from django.contrib.auth.models import AbstractBaseUser, PermissionsMixin
|
from django.contrib.auth.models import AbstractBaseUser, PermissionsMixin
|
||||||
from django.contrib.auth.tests.custom_user import (
|
|
||||||
CustomUserManager, RemoveGroupsAndPermissions,
|
|
||||||
)
|
|
||||||
from django.db import models
|
from django.db import models
|
||||||
from django.utils.encoding import python_2_unicode_compatible
|
from django.utils.encoding import python_2_unicode_compatible
|
||||||
|
|
||||||
|
from .custom_user import CustomUserManager, RemoveGroupsAndPermissions
|
||||||
|
|
||||||
|
|
||||||
class CustomPermissionsUserManager(CustomUserManager):
|
class CustomPermissionsUserManager(CustomUserManager):
|
||||||
def create_superuser(self, email, password, date_of_birth):
|
def create_superuser(self, email, password, date_of_birth):
|
||||||
|
|
|
@ -43,9 +43,6 @@ class CustomUser(AbstractBaseUser):
|
||||||
USERNAME_FIELD = 'email'
|
USERNAME_FIELD = 'email'
|
||||||
REQUIRED_FIELDS = ['date_of_birth']
|
REQUIRED_FIELDS = ['date_of_birth']
|
||||||
|
|
||||||
class Meta:
|
|
||||||
app_label = 'auth'
|
|
||||||
|
|
||||||
def get_full_name(self):
|
def get_full_name(self):
|
||||||
return self.email
|
return self.email
|
||||||
|
|
||||||
|
@ -108,6 +105,3 @@ with RemoveGroupsAndPermissions():
|
||||||
custom_objects = UserManager()
|
custom_objects = UserManager()
|
||||||
|
|
||||||
REQUIRED_FIELDS = AbstractUser.REQUIRED_FIELDS + ['date_of_birth']
|
REQUIRED_FIELDS = AbstractUser.REQUIRED_FIELDS + ['date_of_birth']
|
||||||
|
|
||||||
class Meta:
|
|
||||||
app_label = 'auth'
|
|
|
@ -1,9 +1,10 @@
|
||||||
import uuid
|
import uuid
|
||||||
|
|
||||||
from django.contrib.auth.models import AbstractUser
|
from django.contrib.auth.models import AbstractUser
|
||||||
from django.contrib.auth.tests.custom_user import RemoveGroupsAndPermissions
|
|
||||||
from django.db import models
|
from django.db import models
|
||||||
|
|
||||||
|
from .custom_user import RemoveGroupsAndPermissions
|
||||||
|
|
||||||
with RemoveGroupsAndPermissions():
|
with RemoveGroupsAndPermissions():
|
||||||
class UUIDUser(AbstractUser):
|
class UUIDUser(AbstractUser):
|
||||||
"""A user with a UUID as primary key"""
|
"""A user with a UUID as primary key"""
|
||||||
|
|
|
@ -8,7 +8,6 @@ from django.contrib.auth import (
|
||||||
from django.contrib.auth.backends import ModelBackend
|
from django.contrib.auth.backends import ModelBackend
|
||||||
from django.contrib.auth.hashers import MD5PasswordHasher
|
from django.contrib.auth.hashers import MD5PasswordHasher
|
||||||
from django.contrib.auth.models import AnonymousUser, Group, Permission, User
|
from django.contrib.auth.models import AnonymousUser, Group, Permission, User
|
||||||
from django.contrib.auth.tests.custom_user import CustomUser, ExtensionUser
|
|
||||||
from django.contrib.contenttypes.models import ContentType
|
from django.contrib.contenttypes.models import ContentType
|
||||||
from django.core.exceptions import ImproperlyConfigured, PermissionDenied
|
from django.core.exceptions import ImproperlyConfigured, PermissionDenied
|
||||||
from django.http import HttpRequest
|
from django.http import HttpRequest
|
||||||
|
@ -16,7 +15,7 @@ from django.test import (
|
||||||
SimpleTestCase, TestCase, modify_settings, override_settings,
|
SimpleTestCase, TestCase, modify_settings, override_settings,
|
||||||
)
|
)
|
||||||
|
|
||||||
from .models import CustomPermissionsUser, UUIDUser
|
from .models import CustomPermissionsUser, CustomUser, ExtensionUser, UUIDUser
|
||||||
|
|
||||||
|
|
||||||
class CountingMD5PasswordHasher(MD5PasswordHasher):
|
class CountingMD5PasswordHasher(MD5PasswordHasher):
|
||||||
|
@ -215,7 +214,7 @@ class ModelBackendTest(BaseModelBackendTest, TestCase):
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
@override_settings(AUTH_USER_MODEL='auth.ExtensionUser')
|
@override_settings(AUTH_USER_MODEL='auth_tests.ExtensionUser')
|
||||||
class ExtensionUserModelBackendTest(BaseModelBackendTest, TestCase):
|
class ExtensionUserModelBackendTest(BaseModelBackendTest, TestCase):
|
||||||
"""
|
"""
|
||||||
Tests for the ModelBackend using the custom ExtensionUser model.
|
Tests for the ModelBackend using the custom ExtensionUser model.
|
||||||
|
@ -275,7 +274,7 @@ class CustomPermissionsUserModelBackendTest(BaseModelBackendTest, TestCase):
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
@override_settings(AUTH_USER_MODEL='auth.CustomUser')
|
@override_settings(AUTH_USER_MODEL='auth_tests.CustomUser')
|
||||||
class CustomUserModelBackendAuthenticateTest(TestCase):
|
class CustomUserModelBackendAuthenticateTest(TestCase):
|
||||||
"""
|
"""
|
||||||
Tests that the model backend can accept a credentials kwarg labeled with
|
Tests that the model backend can accept a credentials kwarg labeled with
|
||||||
|
|
|
@ -3,13 +3,14 @@ from __future__ import unicode_literals
|
||||||
from django.apps import apps
|
from django.apps import apps
|
||||||
from django.contrib.auth import get_user_model
|
from django.contrib.auth import get_user_model
|
||||||
from django.contrib.auth.models import AnonymousUser, User
|
from django.contrib.auth.models import AnonymousUser, User
|
||||||
from django.contrib.auth.tests.custom_user import CustomUser
|
|
||||||
from django.core.exceptions import ImproperlyConfigured
|
from django.core.exceptions import ImproperlyConfigured
|
||||||
from django.dispatch import receiver
|
from django.dispatch import receiver
|
||||||
from django.test import TestCase, override_settings
|
from django.test import TestCase, override_settings
|
||||||
from django.test.signals import setting_changed
|
from django.test.signals import setting_changed
|
||||||
from django.utils import translation
|
from django.utils import translation
|
||||||
|
|
||||||
|
from .models import CustomUser
|
||||||
|
|
||||||
|
|
||||||
@receiver(setting_changed)
|
@receiver(setting_changed)
|
||||||
def user_model_swapped(**kwargs):
|
def user_model_swapped(**kwargs):
|
||||||
|
@ -87,7 +88,7 @@ class BasicTestCase(TestCase):
|
||||||
"The current user model can be retrieved"
|
"The current user model can be retrieved"
|
||||||
self.assertEqual(get_user_model(), User)
|
self.assertEqual(get_user_model(), User)
|
||||||
|
|
||||||
@override_settings(AUTH_USER_MODEL='auth.CustomUser')
|
@override_settings(AUTH_USER_MODEL='auth_tests.CustomUser')
|
||||||
def test_swappable_user(self):
|
def test_swappable_user(self):
|
||||||
"The current user model can be swapped out for another"
|
"The current user model can be swapped out for another"
|
||||||
self.assertEqual(get_user_model(), CustomUser)
|
self.assertEqual(get_user_model(), CustomUser)
|
||||||
|
|
|
@ -68,7 +68,7 @@ class PermissionsRequiredDecoratorTest(TestCase):
|
||||||
|
|
||||||
def test_many_permissions_pass(self):
|
def test_many_permissions_pass(self):
|
||||||
|
|
||||||
@permission_required(['auth.add_customuser', 'auth.change_customuser'])
|
@permission_required(['auth_tests.add_customuser', 'auth_tests.change_customuser'])
|
||||||
def a_view(request):
|
def a_view(request):
|
||||||
return HttpResponse()
|
return HttpResponse()
|
||||||
request = self.factory.get('/rand')
|
request = self.factory.get('/rand')
|
||||||
|
@ -78,7 +78,7 @@ class PermissionsRequiredDecoratorTest(TestCase):
|
||||||
|
|
||||||
def test_many_permissions_in_set_pass(self):
|
def test_many_permissions_in_set_pass(self):
|
||||||
|
|
||||||
@permission_required({'auth.add_customuser', 'auth.change_customuser'})
|
@permission_required({'auth_tests.add_customuser', 'auth_tests.change_customuser'})
|
||||||
def a_view(request):
|
def a_view(request):
|
||||||
return HttpResponse()
|
return HttpResponse()
|
||||||
request = self.factory.get('/rand')
|
request = self.factory.get('/rand')
|
||||||
|
@ -88,7 +88,7 @@ class PermissionsRequiredDecoratorTest(TestCase):
|
||||||
|
|
||||||
def test_single_permission_pass(self):
|
def test_single_permission_pass(self):
|
||||||
|
|
||||||
@permission_required('auth.add_customuser')
|
@permission_required('auth_tests.add_customuser')
|
||||||
def a_view(request):
|
def a_view(request):
|
||||||
return HttpResponse()
|
return HttpResponse()
|
||||||
request = self.factory.get('/rand')
|
request = self.factory.get('/rand')
|
||||||
|
@ -98,7 +98,7 @@ class PermissionsRequiredDecoratorTest(TestCase):
|
||||||
|
|
||||||
def test_permissioned_denied_redirect(self):
|
def test_permissioned_denied_redirect(self):
|
||||||
|
|
||||||
@permission_required(['auth.add_customuser', 'auth.change_customuser', 'non-existent-permission'])
|
@permission_required(['auth_tests.add_customuser', 'auth_tests.change_customuser', 'non-existent-permission'])
|
||||||
def a_view(request):
|
def a_view(request):
|
||||||
return HttpResponse()
|
return HttpResponse()
|
||||||
request = self.factory.get('/rand')
|
request = self.factory.get('/rand')
|
||||||
|
@ -109,7 +109,7 @@ class PermissionsRequiredDecoratorTest(TestCase):
|
||||||
def test_permissioned_denied_exception_raised(self):
|
def test_permissioned_denied_exception_raised(self):
|
||||||
|
|
||||||
@permission_required([
|
@permission_required([
|
||||||
'auth.add_customuser', 'auth.change_customuser', 'non-existent-permission'
|
'auth_tests.add_customuser', 'auth_tests.change_customuser', 'non-existent-permission'
|
||||||
], raise_exception=True)
|
], raise_exception=True)
|
||||||
def a_view(request):
|
def a_view(request):
|
||||||
return HttpResponse()
|
return HttpResponse()
|
||||||
|
|
|
@ -4,9 +4,10 @@ from django.contrib.auth.handlers.modwsgi import (
|
||||||
check_password, groups_for_user,
|
check_password, groups_for_user,
|
||||||
)
|
)
|
||||||
from django.contrib.auth.models import Group, User
|
from django.contrib.auth.models import Group, User
|
||||||
from django.contrib.auth.tests.custom_user import CustomUser
|
|
||||||
from django.test import TransactionTestCase, override_settings
|
from django.test import TransactionTestCase, override_settings
|
||||||
|
|
||||||
|
from .models import CustomUser
|
||||||
|
|
||||||
|
|
||||||
# This must be a TransactionTestCase because the WSGI auth handler performs
|
# This must be a TransactionTestCase because the WSGI auth handler performs
|
||||||
# its own transaction management.
|
# its own transaction management.
|
||||||
|
@ -18,6 +19,7 @@ class ModWsgiHandlerTestCase(TransactionTestCase):
|
||||||
available_apps = [
|
available_apps = [
|
||||||
'django.contrib.auth',
|
'django.contrib.auth',
|
||||||
'django.contrib.contenttypes',
|
'django.contrib.contenttypes',
|
||||||
|
'auth_tests',
|
||||||
]
|
]
|
||||||
|
|
||||||
def test_check_password(self):
|
def test_check_password(self):
|
||||||
|
@ -40,7 +42,7 @@ class ModWsgiHandlerTestCase(TransactionTestCase):
|
||||||
# Valid user with incorrect password
|
# Valid user with incorrect password
|
||||||
self.assertFalse(check_password({}, 'test', 'incorrect'))
|
self.assertFalse(check_password({}, 'test', 'incorrect'))
|
||||||
|
|
||||||
@override_settings(AUTH_USER_MODEL='auth.CustomUser')
|
@override_settings(AUTH_USER_MODEL='auth_tests.CustomUser')
|
||||||
def test_check_password_custom_user(self):
|
def test_check_password_custom_user(self):
|
||||||
"""
|
"""
|
||||||
Verify that check_password returns the correct values as per
|
Verify that check_password returns the correct values as per
|
||||||
|
|
|
@ -14,7 +14,6 @@ from django.contrib.auth.management.commands import (
|
||||||
from django.contrib.auth.models import (
|
from django.contrib.auth.models import (
|
||||||
AbstractBaseUser, Group, Permission, User,
|
AbstractBaseUser, Group, Permission, User,
|
||||||
)
|
)
|
||||||
from django.contrib.auth.tests.custom_user import CustomUser
|
|
||||||
from django.contrib.contenttypes.models import ContentType
|
from django.contrib.contenttypes.models import ContentType
|
||||||
from django.core import checks, exceptions
|
from django.core import checks, exceptions
|
||||||
from django.core.management import call_command
|
from django.core.management import call_command
|
||||||
|
@ -28,7 +27,9 @@ from django.utils import six
|
||||||
from django.utils.encoding import force_str
|
from django.utils.encoding import force_str
|
||||||
from django.utils.translation import ugettext_lazy as _
|
from django.utils.translation import ugettext_lazy as _
|
||||||
|
|
||||||
from .models import CustomUserNonUniqueUsername, CustomUserWithFK, Email
|
from .models import (
|
||||||
|
CustomUser, CustomUserNonUniqueUsername, CustomUserWithFK, Email,
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
def mock_inputs(inputs):
|
def mock_inputs(inputs):
|
||||||
|
@ -287,7 +288,7 @@ class CreatesuperuserManagementCommandTestCase(TestCase):
|
||||||
self.assertEqual(u.email, 'joe@somewhere.org')
|
self.assertEqual(u.email, 'joe@somewhere.org')
|
||||||
self.assertFalse(u.has_usable_password())
|
self.assertFalse(u.has_usable_password())
|
||||||
|
|
||||||
@override_settings(AUTH_USER_MODEL='auth.CustomUser')
|
@override_settings(AUTH_USER_MODEL='auth_tests.CustomUser')
|
||||||
def test_swappable_user(self):
|
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 can use the management command to create a superuser
|
||||||
|
@ -309,7 +310,7 @@ class CreatesuperuserManagementCommandTestCase(TestCase):
|
||||||
# created password should be unusable
|
# created password should be unusable
|
||||||
self.assertFalse(u.has_usable_password())
|
self.assertFalse(u.has_usable_password())
|
||||||
|
|
||||||
@override_settings(AUTH_USER_MODEL='auth.CustomUser')
|
@override_settings(AUTH_USER_MODEL='auth_tests.CustomUser')
|
||||||
def test_swappable_user_missing_required_field(self):
|
def test_swappable_user_missing_required_field(self):
|
||||||
"A Custom superuser won't be created when a required field isn't provided"
|
"A Custom superuser won't be created when a required field isn't provided"
|
||||||
# We can use the management command to create a superuser
|
# We can use the management command to create a superuser
|
||||||
|
|
|
@ -35,12 +35,12 @@ class AlwaysFalseView(AlwaysFalseMixin, EmptyResponseView):
|
||||||
|
|
||||||
|
|
||||||
class StackedMixinsView1(LoginRequiredMixin, PermissionRequiredMixin, EmptyResponseView):
|
class StackedMixinsView1(LoginRequiredMixin, PermissionRequiredMixin, EmptyResponseView):
|
||||||
permission_required = ['auth.add_customuser', 'auth.change_customuser']
|
permission_required = ['auth_tests.add_customuser', 'auth_tests.change_customuser']
|
||||||
raise_exception = True
|
raise_exception = True
|
||||||
|
|
||||||
|
|
||||||
class StackedMixinsView2(PermissionRequiredMixin, LoginRequiredMixin, EmptyResponseView):
|
class StackedMixinsView2(PermissionRequiredMixin, LoginRequiredMixin, EmptyResponseView):
|
||||||
permission_required = ['auth.add_customuser', 'auth.change_customuser']
|
permission_required = ['auth_tests.add_customuser', 'auth_tests.change_customuser']
|
||||||
raise_exception = True
|
raise_exception = True
|
||||||
|
|
||||||
|
|
||||||
|
@ -217,7 +217,7 @@ class PermissionsRequiredMixinTests(TestCase):
|
||||||
|
|
||||||
def test_many_permissions_pass(self):
|
def test_many_permissions_pass(self):
|
||||||
class AView(PermissionRequiredMixin, EmptyResponseView):
|
class AView(PermissionRequiredMixin, EmptyResponseView):
|
||||||
permission_required = ['auth.add_customuser', 'auth.change_customuser']
|
permission_required = ['auth_tests.add_customuser', 'auth_tests.change_customuser']
|
||||||
|
|
||||||
request = self.factory.get('/rand')
|
request = self.factory.get('/rand')
|
||||||
request.user = self.user
|
request.user = self.user
|
||||||
|
@ -226,7 +226,7 @@ class PermissionsRequiredMixinTests(TestCase):
|
||||||
|
|
||||||
def test_single_permission_pass(self):
|
def test_single_permission_pass(self):
|
||||||
class AView(PermissionRequiredMixin, EmptyResponseView):
|
class AView(PermissionRequiredMixin, EmptyResponseView):
|
||||||
permission_required = 'auth.add_customuser'
|
permission_required = 'auth_tests.add_customuser'
|
||||||
|
|
||||||
request = self.factory.get('/rand')
|
request = self.factory.get('/rand')
|
||||||
request.user = self.user
|
request.user = self.user
|
||||||
|
@ -235,7 +235,9 @@ class PermissionsRequiredMixinTests(TestCase):
|
||||||
|
|
||||||
def test_permissioned_denied_redirect(self):
|
def test_permissioned_denied_redirect(self):
|
||||||
class AView(PermissionRequiredMixin, EmptyResponseView):
|
class AView(PermissionRequiredMixin, EmptyResponseView):
|
||||||
permission_required = ['auth.add_customuser', 'auth.change_customuser', 'non-existent-permission']
|
permission_required = [
|
||||||
|
'auth_tests.add_customuser', 'auth_tests.change_customuser', 'non-existent-permission',
|
||||||
|
]
|
||||||
|
|
||||||
request = self.factory.get('/rand')
|
request = self.factory.get('/rand')
|
||||||
request.user = self.user
|
request.user = self.user
|
||||||
|
@ -244,7 +246,9 @@ class PermissionsRequiredMixinTests(TestCase):
|
||||||
|
|
||||||
def test_permissioned_denied_exception_raised(self):
|
def test_permissioned_denied_exception_raised(self):
|
||||||
class AView(PermissionRequiredMixin, EmptyResponseView):
|
class AView(PermissionRequiredMixin, EmptyResponseView):
|
||||||
permission_required = ['auth.add_customuser', 'auth.change_customuser', 'non-existent-permission']
|
permission_required = [
|
||||||
|
'auth_tests.add_customuser', 'auth_tests.change_customuser', 'non-existent-permission',
|
||||||
|
]
|
||||||
raise_exception = True
|
raise_exception = True
|
||||||
|
|
||||||
request = self.factory.get('/rand')
|
request = self.factory.get('/rand')
|
||||||
|
|
|
@ -15,7 +15,6 @@ from django.contrib.auth.forms import (
|
||||||
AuthenticationForm, PasswordChangeForm, SetPasswordForm,
|
AuthenticationForm, PasswordChangeForm, SetPasswordForm,
|
||||||
)
|
)
|
||||||
from django.contrib.auth.models import User
|
from django.contrib.auth.models import User
|
||||||
from django.contrib.auth.tests.custom_user import CustomUser
|
|
||||||
from django.contrib.auth.views import login as login_view, redirect_to_login
|
from django.contrib.auth.views import login as login_view, redirect_to_login
|
||||||
from django.contrib.sessions.middleware import SessionMiddleware
|
from django.contrib.sessions.middleware import SessionMiddleware
|
||||||
from django.contrib.sites.requests import RequestSite
|
from django.contrib.sites.requests import RequestSite
|
||||||
|
@ -31,7 +30,7 @@ from django.utils.http import urlquote
|
||||||
from django.utils.six.moves.urllib.parse import ParseResult, urlparse
|
from django.utils.six.moves.urllib.parse import ParseResult, urlparse
|
||||||
from django.utils.translation import LANGUAGE_SESSION_KEY
|
from django.utils.translation import LANGUAGE_SESSION_KEY
|
||||||
|
|
||||||
from .models import UUIDUser
|
from .models import CustomUser, UUIDUser
|
||||||
from .settings import AUTH_TEMPLATES
|
from .settings import AUTH_TEMPLATES
|
||||||
|
|
||||||
|
|
||||||
|
@ -367,7 +366,7 @@ class PasswordResetTest(AuthViewsTestCase):
|
||||||
self.assertContains(response, "Hello, .")
|
self.assertContains(response, "Hello, .")
|
||||||
|
|
||||||
|
|
||||||
@override_settings(AUTH_USER_MODEL='auth.CustomUser')
|
@override_settings(AUTH_USER_MODEL='auth_tests.CustomUser')
|
||||||
class CustomUserPasswordResetTest(AuthViewsTestCase):
|
class CustomUserPasswordResetTest(AuthViewsTestCase):
|
||||||
user_email = 'staffmember@example.com'
|
user_email = 'staffmember@example.com'
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue