bazis-users 2.2.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- bazis/contrib/users/__init__.py +31 -0
- bazis/contrib/users/_version.py +34 -0
- bazis/contrib/users/admin_abstract.py +40 -0
- bazis/contrib/users/apps.py +28 -0
- bazis/contrib/users/conf.py +41 -0
- bazis/contrib/users/locale/en/LC_MESSAGES/django.mo +0 -0
- bazis/contrib/users/locale/en/LC_MESSAGES/django.po +63 -0
- bazis/contrib/users/locale/ru/LC_MESSAGES/django.mo +0 -0
- bazis/contrib/users/locale/ru/LC_MESSAGES/django.po +81 -0
- bazis/contrib/users/middleware.py +37 -0
- bazis/contrib/users/migrations/0001_initial.py +63 -0
- bazis/contrib/users/migrations/0002_user_dt_first_login.py +34 -0
- bazis/contrib/users/migrations/__init__.py +14 -0
- bazis/contrib/users/models.py +34 -0
- bazis/contrib/users/models_abstract.py +156 -0
- bazis/contrib/users/router.py +23 -0
- bazis/contrib/users/routes.py +97 -0
- bazis/contrib/users/routes_abstract.py +110 -0
- bazis/contrib/users/schemas.py +25 -0
- bazis/contrib/users/service.py +92 -0
- bazis_users-2.2.0.dist-info/METADATA +594 -0
- bazis_users-2.2.0.dist-info/RECORD +24 -0
- bazis_users-2.2.0.dist-info/WHEEL +5 -0
- bazis_users-2.2.0.dist-info/top_level.txt +1 -0
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
# Copyright 2026 EcoFuture Technology Services LLC and contributors
|
|
2
|
+
#
|
|
3
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
4
|
+
# you may not use this file except in compliance with the License.
|
|
5
|
+
# You may obtain a copy of the License at
|
|
6
|
+
#
|
|
7
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
|
8
|
+
#
|
|
9
|
+
# Unless required by applicable law or agreed to in writing, software
|
|
10
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
11
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
12
|
+
# See the License for the specific language governing permissions and
|
|
13
|
+
# limitations under the License.
|
|
14
|
+
|
|
15
|
+
try:
|
|
16
|
+
from importlib.metadata import PackageNotFoundError, version
|
|
17
|
+
__version__ = version('bazis-users')
|
|
18
|
+
except PackageNotFoundError:
|
|
19
|
+
__version__ = 'dev'
|
|
20
|
+
|
|
21
|
+
from django.conf import settings
|
|
22
|
+
from django.contrib.auth import get_user_model
|
|
23
|
+
|
|
24
|
+
from bazis.core.utils.imp import import_class
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
def get_anonymous_user_model():
|
|
28
|
+
"""
|
|
29
|
+
Retrieve the anonymous user model class specified in the Django settings.
|
|
30
|
+
"""
|
|
31
|
+
return import_class(settings.AUTH_ANONYMOUS_USER_MODEL)
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
# file generated by setuptools-scm
|
|
2
|
+
# don't change, don't track in version control
|
|
3
|
+
|
|
4
|
+
__all__ = [
|
|
5
|
+
"__version__",
|
|
6
|
+
"__version_tuple__",
|
|
7
|
+
"version",
|
|
8
|
+
"version_tuple",
|
|
9
|
+
"__commit_id__",
|
|
10
|
+
"commit_id",
|
|
11
|
+
]
|
|
12
|
+
|
|
13
|
+
TYPE_CHECKING = False
|
|
14
|
+
if TYPE_CHECKING:
|
|
15
|
+
from typing import Tuple
|
|
16
|
+
from typing import Union
|
|
17
|
+
|
|
18
|
+
VERSION_TUPLE = Tuple[Union[int, str], ...]
|
|
19
|
+
COMMIT_ID = Union[str, None]
|
|
20
|
+
else:
|
|
21
|
+
VERSION_TUPLE = object
|
|
22
|
+
COMMIT_ID = object
|
|
23
|
+
|
|
24
|
+
version: str
|
|
25
|
+
__version__: str
|
|
26
|
+
__version_tuple__: VERSION_TUPLE
|
|
27
|
+
version_tuple: VERSION_TUPLE
|
|
28
|
+
commit_id: COMMIT_ID
|
|
29
|
+
__commit_id__: COMMIT_ID
|
|
30
|
+
|
|
31
|
+
__version__ = version = '2.2.0'
|
|
32
|
+
__version_tuple__ = version_tuple = (2, 2, 0)
|
|
33
|
+
|
|
34
|
+
__commit_id__ = commit_id = None
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
# Copyright 2026 EcoFuture Technology Services LLC and contributors
|
|
2
|
+
#
|
|
3
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
4
|
+
# you may not use this file except in compliance with the License.
|
|
5
|
+
# You may obtain a copy of the License at
|
|
6
|
+
#
|
|
7
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
|
8
|
+
#
|
|
9
|
+
# Unless required by applicable law or agreed to in writing, software
|
|
10
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
11
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
12
|
+
# See the License for the specific language governing permissions and
|
|
13
|
+
# limitations under the License.
|
|
14
|
+
|
|
15
|
+
from django.utils.translation import gettext_lazy as _
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
class UserAdminAbstract:
|
|
19
|
+
|
|
20
|
+
def get_fields_common(self, request, obj=None):
|
|
21
|
+
return ('username', 'password')
|
|
22
|
+
|
|
23
|
+
def get_fields_personal(self, request, obj=None):
|
|
24
|
+
return ('first_name', 'last_name', 'email')
|
|
25
|
+
|
|
26
|
+
def get_fields_permissions(self, request, obj=None):
|
|
27
|
+
return ('is_active', 'is_staff', 'is_superuser')
|
|
28
|
+
|
|
29
|
+
def get_fields_dates(self, request, obj=None):
|
|
30
|
+
return ('last_login', 'date_joined', 'dt_first_login')
|
|
31
|
+
|
|
32
|
+
def get_fieldsets(self, request, obj=None):
|
|
33
|
+
if not obj:
|
|
34
|
+
return self.add_fieldsets
|
|
35
|
+
return (
|
|
36
|
+
(None, {'fields': self.get_fields_common(request, obj)}),
|
|
37
|
+
(_('Personal info'), {'fields': self.get_fields_personal(request, obj)}),
|
|
38
|
+
(_('Permissions'), {'fields': self.get_fields_permissions(request, obj)}),
|
|
39
|
+
(_('Important dates'), {'fields': self.get_fields_dates(request, obj)}),
|
|
40
|
+
)
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
# Copyright 2026 EcoFuture Technology Services LLC and contributors
|
|
2
|
+
#
|
|
3
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
4
|
+
# you may not use this file except in compliance with the License.
|
|
5
|
+
# You may obtain a copy of the License at
|
|
6
|
+
#
|
|
7
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
|
8
|
+
#
|
|
9
|
+
# Unless required by applicable law or agreed to in writing, software
|
|
10
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
11
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
12
|
+
# See the License for the specific language governing permissions and
|
|
13
|
+
# limitations under the License.
|
|
14
|
+
|
|
15
|
+
from django.utils.translation import gettext_lazy as _
|
|
16
|
+
|
|
17
|
+
from bazis.core.utils.apps import BaseConfig
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
class UsersConfig(BaseConfig):
|
|
21
|
+
"""
|
|
22
|
+
Configuration class for the 'users' application within the Bazis project. It
|
|
23
|
+
sets the application name and provides a human-readable name for the application
|
|
24
|
+
using Django's translation utilities.
|
|
25
|
+
"""
|
|
26
|
+
|
|
27
|
+
name = 'bazis.contrib.users'
|
|
28
|
+
verbose_name = _('Users')
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
# Copyright 2026 EcoFuture Technology Services LLC and contributors
|
|
2
|
+
#
|
|
3
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
4
|
+
# you may not use this file except in compliance with the License.
|
|
5
|
+
# You may obtain a copy of the License at
|
|
6
|
+
#
|
|
7
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
|
8
|
+
#
|
|
9
|
+
# Unless required by applicable law or agreed to in writing, software
|
|
10
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
11
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
12
|
+
# See the License for the specific language governing permissions and
|
|
13
|
+
# limitations under the License.
|
|
14
|
+
|
|
15
|
+
from django.utils.translation import gettext_lazy as _
|
|
16
|
+
|
|
17
|
+
from pydantic import Field
|
|
18
|
+
|
|
19
|
+
from jose.constants import Algorithms
|
|
20
|
+
|
|
21
|
+
from bazis.core.utils.schemas import BazisSettings
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
class Settings(BazisSettings):
|
|
25
|
+
"""
|
|
26
|
+
Settings class inherits from BazisSettings and defines various configuration
|
|
27
|
+
parameters for the application, including user models, OpenAPI token endpoint,
|
|
28
|
+
JWT algorithm, and JWT session lifetime.
|
|
29
|
+
"""
|
|
30
|
+
|
|
31
|
+
AUTH_USER_MODEL: str = Field('users.User', title=_('Default user model'))
|
|
32
|
+
AUTH_ANONYMOUS_USER_MODEL: str = Field(
|
|
33
|
+
'bazis.contrib.users.models.AnonymousUser', title=_('Default anonymous user model')
|
|
34
|
+
)
|
|
35
|
+
BAZIS_OPENAPI_TOKEN_URL: str = Field('/api/openapi-token/', title=_('OpenAPI token`s endpoint'))
|
|
36
|
+
BAZIS_AUTH_COOKIE_NAME: str = Field('bazis_auth', title=_('Name of the user cookie'))
|
|
37
|
+
BAZIS_JWT_SESSION_ALG: str = Field(Algorithms.HS256, title=_('JWT algorithm'))
|
|
38
|
+
BAZIS_JWT_SESSION_LIFETIME: int = Field(86400, title=_('JWT lifetime'), dynamic=True)
|
|
39
|
+
|
|
40
|
+
|
|
41
|
+
settings = Settings()
|
|
Binary file
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
# SOME DESCRIPTIVE TITLE.
|
|
2
|
+
# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
|
|
3
|
+
# This file is distributed under the same license as the PACKAGE package.
|
|
4
|
+
# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
|
|
5
|
+
#
|
|
6
|
+
#, fuzzy
|
|
7
|
+
msgid ""
|
|
8
|
+
msgstr ""
|
|
9
|
+
"Project-Id-Version: PACKAGE VERSION\n"
|
|
10
|
+
"Report-Msgid-Bugs-To: \n"
|
|
11
|
+
"POT-Creation-Date: 2024-07-04 13:45+0000\n"
|
|
12
|
+
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
|
|
13
|
+
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
|
|
14
|
+
"Language-Team: LANGUAGE <LL@li.org>\n"
|
|
15
|
+
"Language: \n"
|
|
16
|
+
"MIME-Version: 1.0\n"
|
|
17
|
+
"Content-Type: text/plain; charset=UTF-8\n"
|
|
18
|
+
"Content-Transfer-Encoding: 8bit\n"
|
|
19
|
+
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
|
|
20
|
+
|
|
21
|
+
#: apps.py:13 router.py:7
|
|
22
|
+
msgid "Users"
|
|
23
|
+
msgstr ""
|
|
24
|
+
|
|
25
|
+
#: conf.py:14
|
|
26
|
+
msgid "Default user model"
|
|
27
|
+
msgstr ""
|
|
28
|
+
|
|
29
|
+
#: conf.py:16
|
|
30
|
+
msgid "Default anonymous user model"
|
|
31
|
+
msgstr ""
|
|
32
|
+
|
|
33
|
+
#: conf.py:18
|
|
34
|
+
msgid "OpenAPI token`s endpoint"
|
|
35
|
+
msgstr ""
|
|
36
|
+
|
|
37
|
+
#: conf.py:19
|
|
38
|
+
msgid "JWT algorithm"
|
|
39
|
+
msgstr ""
|
|
40
|
+
|
|
41
|
+
#: conf.py:20
|
|
42
|
+
msgid "JWT lifetime"
|
|
43
|
+
msgstr ""
|
|
44
|
+
|
|
45
|
+
#: models_abstract.py:30
|
|
46
|
+
msgid "user"
|
|
47
|
+
msgstr ""
|
|
48
|
+
|
|
49
|
+
#: models_abstract.py:31
|
|
50
|
+
msgid "users"
|
|
51
|
+
msgstr ""
|
|
52
|
+
|
|
53
|
+
#: routes.py:30
|
|
54
|
+
msgid "Credentials are invalid"
|
|
55
|
+
msgstr ""
|
|
56
|
+
|
|
57
|
+
#: service.py:31
|
|
58
|
+
msgid "Token expired"
|
|
59
|
+
msgstr ""
|
|
60
|
+
|
|
61
|
+
#: service.py:54
|
|
62
|
+
msgid "Token is invalid"
|
|
63
|
+
msgstr ""
|
|
Binary file
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
# SOME DESCRIPTIVE TITLE.
|
|
2
|
+
# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
|
|
3
|
+
# This file is distributed under the same license as the PACKAGE package.
|
|
4
|
+
# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
|
|
5
|
+
#
|
|
6
|
+
#, fuzzy
|
|
7
|
+
msgid ""
|
|
8
|
+
msgstr ""
|
|
9
|
+
"Project-Id-Version: PACKAGE VERSION\n"
|
|
10
|
+
"Report-Msgid-Bugs-To: \n"
|
|
11
|
+
"POT-Creation-Date: 2025-03-29 00:27+0300\n"
|
|
12
|
+
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
|
|
13
|
+
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
|
|
14
|
+
"Language-Team: LANGUAGE <LL@li.org>\n"
|
|
15
|
+
"Language: \n"
|
|
16
|
+
"MIME-Version: 1.0\n"
|
|
17
|
+
"Content-Type: text/plain; charset=UTF-8\n"
|
|
18
|
+
"Content-Transfer-Encoding: 8bit\n"
|
|
19
|
+
"Plural-Forms: nplurals=4; plural=(n%10==1 && n%100!=11 ? 0 : n%10>=2 && "
|
|
20
|
+
"n%10<=4 && (n%100<12 || n%100>14) ? 1 : n%10==0 || (n%10>=5 && n%10<=9) || "
|
|
21
|
+
"(n%100>=11 && n%100<=14)? 2 : 3);\n"
|
|
22
|
+
|
|
23
|
+
#: admin_abstract.py:23
|
|
24
|
+
msgid "Personal info"
|
|
25
|
+
msgstr ""
|
|
26
|
+
|
|
27
|
+
#: admin_abstract.py:24
|
|
28
|
+
msgid "Permissions"
|
|
29
|
+
msgstr ""
|
|
30
|
+
|
|
31
|
+
#: admin_abstract.py:25
|
|
32
|
+
msgid "Important dates"
|
|
33
|
+
msgstr ""
|
|
34
|
+
|
|
35
|
+
#: apps.py:14 router.py:7
|
|
36
|
+
msgid "Users"
|
|
37
|
+
msgstr "Пользователи"
|
|
38
|
+
|
|
39
|
+
#: conf.py:15
|
|
40
|
+
msgid "Default user model"
|
|
41
|
+
msgstr "Модель пользователя по умолчанию"
|
|
42
|
+
|
|
43
|
+
#: conf.py:17
|
|
44
|
+
msgid "Default anonymous user model"
|
|
45
|
+
msgstr "Модель анонимного пользователя по умолчанию"
|
|
46
|
+
|
|
47
|
+
#: conf.py:19
|
|
48
|
+
msgid "OpenAPI token`s endpoint"
|
|
49
|
+
msgstr "Эндпоинт для токена OpenAPI"
|
|
50
|
+
|
|
51
|
+
#: conf.py:20
|
|
52
|
+
msgid "Name of the user cookie"
|
|
53
|
+
msgstr ""
|
|
54
|
+
|
|
55
|
+
#: conf.py:21
|
|
56
|
+
msgid "JWT algorithm"
|
|
57
|
+
msgstr "Алгоритм JWT"
|
|
58
|
+
|
|
59
|
+
#: conf.py:22
|
|
60
|
+
msgid "JWT lifetime"
|
|
61
|
+
msgstr "Срок жизни JWT"
|
|
62
|
+
|
|
63
|
+
#: models_abstract.py:34
|
|
64
|
+
msgid "user"
|
|
65
|
+
msgstr "пользователь"
|
|
66
|
+
|
|
67
|
+
#: models_abstract.py:35
|
|
68
|
+
msgid "users"
|
|
69
|
+
msgstr "Пользователи"
|
|
70
|
+
|
|
71
|
+
#: routes.py:29
|
|
72
|
+
msgid "Credentials are invalid"
|
|
73
|
+
msgstr "Учетные данные недействительны"
|
|
74
|
+
|
|
75
|
+
#: service.py:36
|
|
76
|
+
msgid "Token expired"
|
|
77
|
+
msgstr "Срок действия токена истек"
|
|
78
|
+
|
|
79
|
+
#: service.py:61
|
|
80
|
+
msgid "Token is invalid"
|
|
81
|
+
msgstr "Токен недействителен"
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
# Copyright 2026 EcoFuture Technology Services LLC and contributors
|
|
2
|
+
#
|
|
3
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
4
|
+
# you may not use this file except in compliance with the License.
|
|
5
|
+
# You may obtain a copy of the License at
|
|
6
|
+
#
|
|
7
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
|
8
|
+
#
|
|
9
|
+
# Unless required by applicable law or agreed to in writing, software
|
|
10
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
11
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
12
|
+
# See the License for the specific language governing permissions and
|
|
13
|
+
# limitations under the License.
|
|
14
|
+
|
|
15
|
+
from .models_abstract import UserMixin
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
class UserRequestMiddleware:
|
|
19
|
+
"""
|
|
20
|
+
Middleware that attaches the current authenticated user to the context for the
|
|
21
|
+
duration of the request.
|
|
22
|
+
"""
|
|
23
|
+
|
|
24
|
+
def __init__(self, get_response):
|
|
25
|
+
"""
|
|
26
|
+
Initializes the middleware with the given response handler.
|
|
27
|
+
"""
|
|
28
|
+
self.get_response = get_response
|
|
29
|
+
|
|
30
|
+
def __call__(self, request):
|
|
31
|
+
"""
|
|
32
|
+
Processes the incoming request, setting the user in the context if the user is
|
|
33
|
+
authenticated, and then passes the request to the next middleware or view.
|
|
34
|
+
"""
|
|
35
|
+
if request.user and getattr(request.user, 'is_anonymous', None) is False:
|
|
36
|
+
UserMixin.CTX_USER_REQUEST.set(request.user)
|
|
37
|
+
return self.get_response(request)
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
# Copyright 2026 EcoFuture Technology Services LLC and contributors
|
|
2
|
+
#
|
|
3
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
4
|
+
# you may not use this file except in compliance with the License.
|
|
5
|
+
# You may obtain a copy of the License at
|
|
6
|
+
#
|
|
7
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
|
8
|
+
#
|
|
9
|
+
# Unless required by applicable law or agreed to in writing, software
|
|
10
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
11
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
12
|
+
# See the License for the specific language governing permissions and
|
|
13
|
+
# limitations under the License.
|
|
14
|
+
|
|
15
|
+
# Generated by Django 5.0.1 on 2024-02-14 15:51
|
|
16
|
+
|
|
17
|
+
import uuid
|
|
18
|
+
|
|
19
|
+
import django.contrib.auth.models
|
|
20
|
+
import django.contrib.auth.validators
|
|
21
|
+
import django.utils.timezone
|
|
22
|
+
from django.db import migrations, models
|
|
23
|
+
|
|
24
|
+
import model_clone.mixin
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
class Migration(migrations.Migration):
|
|
28
|
+
|
|
29
|
+
initial = True
|
|
30
|
+
|
|
31
|
+
dependencies = [
|
|
32
|
+
('auth', '0012_alter_user_first_name_max_length'),
|
|
33
|
+
]
|
|
34
|
+
|
|
35
|
+
operations = [
|
|
36
|
+
migrations.CreateModel(
|
|
37
|
+
name='User',
|
|
38
|
+
fields=[
|
|
39
|
+
('id', models.UUIDField(default=uuid.uuid4, editable=False, primary_key=True, serialize=False)),
|
|
40
|
+
('password', models.CharField(max_length=128, verbose_name='password')),
|
|
41
|
+
('last_login', models.DateTimeField(blank=True, null=True, verbose_name='last login')),
|
|
42
|
+
('is_superuser', models.BooleanField(default=False, help_text='Designates that this user has all permissions without explicitly assigning them.', verbose_name='superuser status')),
|
|
43
|
+
('username', models.CharField(error_messages={'unique': 'A user with that username already exists.'}, help_text='Required. 150 characters or fewer. Letters, digits and @/./+/-/_ only.', max_length=150, unique=True, validators=[django.contrib.auth.validators.UnicodeUsernameValidator()], verbose_name='username')),
|
|
44
|
+
('first_name', models.CharField(blank=True, max_length=150, verbose_name='first name')),
|
|
45
|
+
('last_name', models.CharField(blank=True, max_length=150, verbose_name='last name')),
|
|
46
|
+
('email', models.EmailField(blank=True, max_length=254, verbose_name='email address')),
|
|
47
|
+
('is_staff', models.BooleanField(default=False, help_text='Designates whether the user can log into this admin site.', verbose_name='staff status')),
|
|
48
|
+
('is_active', models.BooleanField(default=True, help_text='Designates whether this user should be treated as active. Unselect this instead of deleting accounts.', verbose_name='active')),
|
|
49
|
+
('date_joined', models.DateTimeField(default=django.utils.timezone.now, verbose_name='date joined')),
|
|
50
|
+
('groups', models.ManyToManyField(blank=True, help_text='The groups this user belongs to. A user will get all permissions granted to each of their groups.', related_name='user_set', related_query_name='user', to='auth.group', verbose_name='groups')),
|
|
51
|
+
('user_permissions', models.ManyToManyField(blank=True, help_text='Specific permissions for this user.', related_name='user_set', related_query_name='user', to='auth.permission', verbose_name='user permissions')),
|
|
52
|
+
],
|
|
53
|
+
options={
|
|
54
|
+
'verbose_name': 'user',
|
|
55
|
+
'verbose_name_plural': 'users',
|
|
56
|
+
'abstract': False,
|
|
57
|
+
},
|
|
58
|
+
bases=(model_clone.mixin.CloneMixin, models.Model),
|
|
59
|
+
managers=[
|
|
60
|
+
('objects', django.contrib.auth.models.UserManager()),
|
|
61
|
+
],
|
|
62
|
+
),
|
|
63
|
+
]
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
# Copyright 2026 EcoFuture Technology Services LLC and contributors
|
|
2
|
+
#
|
|
3
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
4
|
+
# you may not use this file except in compliance with the License.
|
|
5
|
+
# You may obtain a copy of the License at
|
|
6
|
+
#
|
|
7
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
|
8
|
+
#
|
|
9
|
+
# Unless required by applicable law or agreed to in writing, software
|
|
10
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
11
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
12
|
+
# See the License for the specific language governing permissions and
|
|
13
|
+
# limitations under the License.
|
|
14
|
+
|
|
15
|
+
# Generated by Django 6.0.1 on 2026-01-16 17:38
|
|
16
|
+
|
|
17
|
+
from django.db import migrations, models
|
|
18
|
+
from django.utils.translation import gettext_lazy as _
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
class Migration(migrations.Migration):
|
|
23
|
+
|
|
24
|
+
dependencies = [
|
|
25
|
+
('users', '0001_initial'),
|
|
26
|
+
]
|
|
27
|
+
|
|
28
|
+
operations = [
|
|
29
|
+
migrations.AddField(
|
|
30
|
+
model_name='user',
|
|
31
|
+
name='dt_first_login',
|
|
32
|
+
field=models.DateTimeField(blank=True, null=True, verbose_name='Date/time of first login'),
|
|
33
|
+
),
|
|
34
|
+
]
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
# Copyright 2026 EcoFuture Technology Services LLC and contributors
|
|
2
|
+
#
|
|
3
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
4
|
+
# you may not use this file except in compliance with the License.
|
|
5
|
+
# You may obtain a copy of the License at
|
|
6
|
+
#
|
|
7
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
|
8
|
+
#
|
|
9
|
+
# Unless required by applicable law or agreed to in writing, software
|
|
10
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
11
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
12
|
+
# See the License for the specific language governing permissions and
|
|
13
|
+
# limitations under the License.
|
|
14
|
+
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
# Copyright 2026 EcoFuture Technology Services LLC and contributors
|
|
2
|
+
#
|
|
3
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
4
|
+
# you may not use this file except in compliance with the License.
|
|
5
|
+
# You may obtain a copy of the License at
|
|
6
|
+
#
|
|
7
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
|
8
|
+
#
|
|
9
|
+
# Unless required by applicable law or agreed to in writing, software
|
|
10
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
11
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
12
|
+
# See the License for the specific language governing permissions and
|
|
13
|
+
# limitations under the License.
|
|
14
|
+
|
|
15
|
+
from bazis.contrib.users.models_abstract import AnonymousUserAbstract, UserAbstract
|
|
16
|
+
from bazis.core.models_abstract import JsonApiMixin, UuidMixin
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
class User(JsonApiMixin, UuidMixin, UserAbstract):
|
|
20
|
+
"""
|
|
21
|
+
Represents a user in the system, combining JSON API support, UUID functionality,
|
|
22
|
+
and user-specific attributes and methods.
|
|
23
|
+
"""
|
|
24
|
+
|
|
25
|
+
pass
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
class AnonymousUser(AnonymousUserAbstract):
|
|
29
|
+
"""
|
|
30
|
+
Represents an anonymous user with attributes and methods specific to users who
|
|
31
|
+
are not logged in.
|
|
32
|
+
"""
|
|
33
|
+
|
|
34
|
+
pass
|
|
@@ -0,0 +1,156 @@
|
|
|
1
|
+
# Copyright 2026 EcoFuture Technology Services LLC and contributors
|
|
2
|
+
#
|
|
3
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
4
|
+
# you may not use this file except in compliance with the License.
|
|
5
|
+
# You may obtain a copy of the License at
|
|
6
|
+
#
|
|
7
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
|
8
|
+
#
|
|
9
|
+
# Unless required by applicable law or agreed to in writing, software
|
|
10
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
11
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
12
|
+
# See the License for the specific language governing permissions and
|
|
13
|
+
# limitations under the License.
|
|
14
|
+
|
|
15
|
+
"""
|
|
16
|
+
The module provides mixins for working with User
|
|
17
|
+
"""
|
|
18
|
+
|
|
19
|
+
from contextvars import ContextVar
|
|
20
|
+
from datetime import timedelta
|
|
21
|
+
|
|
22
|
+
from django.conf import settings
|
|
23
|
+
from django.contrib.auth.models import AbstractUser
|
|
24
|
+
from django.contrib.auth.models import AnonymousUser as BaseAnonymousUser
|
|
25
|
+
from django.contrib.auth.signals import user_logged_in
|
|
26
|
+
from django.contrib.gis.db import models
|
|
27
|
+
from django.db import IntegrityError, transaction
|
|
28
|
+
from django.dispatch import receiver
|
|
29
|
+
from django.utils.timezone import now
|
|
30
|
+
from django.utils.translation import gettext_lazy as _
|
|
31
|
+
|
|
32
|
+
from jose import jwt
|
|
33
|
+
|
|
34
|
+
from bazis.core.models_abstract import InitialBase, JsonApiMixin
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
class UserAbstract(AbstractUser, InitialBase):
|
|
38
|
+
"""
|
|
39
|
+
Abstract base class for user models, extending Django's AbstractUser and
|
|
40
|
+
InitialBase.
|
|
41
|
+
"""
|
|
42
|
+
dt_first_login = models.DateTimeField('Date/time of first login', blank=True, null=True)
|
|
43
|
+
|
|
44
|
+
class Meta:
|
|
45
|
+
"""
|
|
46
|
+
Meta class for UserAbstract, defining verbose names and setting the model as
|
|
47
|
+
abstract.
|
|
48
|
+
"""
|
|
49
|
+
|
|
50
|
+
verbose_name = _('user')
|
|
51
|
+
verbose_name_plural = _('users')
|
|
52
|
+
abstract = True
|
|
53
|
+
|
|
54
|
+
def get_full_name(self):
|
|
55
|
+
"""
|
|
56
|
+
Returns the full name of the user, combining first and last name if available,
|
|
57
|
+
otherwise returns the username.
|
|
58
|
+
"""
|
|
59
|
+
full_name = ''
|
|
60
|
+
if self.first_name:
|
|
61
|
+
full_name = self.first_name
|
|
62
|
+
if self.last_name:
|
|
63
|
+
full_name += ' ' + self.last_name
|
|
64
|
+
return full_name.strip() or self.username
|
|
65
|
+
|
|
66
|
+
def jwt_build(self, auth_type=None) -> str:
|
|
67
|
+
"""
|
|
68
|
+
Generates a JSON Web Token (JWT) for the user, optionally including an
|
|
69
|
+
authentication type.
|
|
70
|
+
"""
|
|
71
|
+
data = {
|
|
72
|
+
'sub': self.username,
|
|
73
|
+
'exp': now() + timedelta(seconds=settings.BAZIS_JWT_SESSION_LIFETIME),
|
|
74
|
+
}
|
|
75
|
+
if auth_type:
|
|
76
|
+
data['auth_type'] = auth_type
|
|
77
|
+
|
|
78
|
+
return jwt.encode(data, settings.SECRET_KEY, algorithm=settings.BAZIS_JWT_SESSION_ALG)
|
|
79
|
+
|
|
80
|
+
@classmethod
|
|
81
|
+
def find_or_create(cls, filters, params):
|
|
82
|
+
"""
|
|
83
|
+
Class method to find a user by filters or create a new one with the provided
|
|
84
|
+
parameters, ensuring atomic transactions.
|
|
85
|
+
"""
|
|
86
|
+
with transaction.atomic():
|
|
87
|
+
if user := cls.objects.filter(filters).first():
|
|
88
|
+
return user
|
|
89
|
+
|
|
90
|
+
try:
|
|
91
|
+
with transaction.atomic(savepoint=False):
|
|
92
|
+
return cls.objects.create(**params)
|
|
93
|
+
except IntegrityError:
|
|
94
|
+
if user := cls.objects.filter(filters).first():
|
|
95
|
+
return user
|
|
96
|
+
raise
|
|
97
|
+
|
|
98
|
+
@property
|
|
99
|
+
def raw_password(self) -> str | None:
|
|
100
|
+
"""
|
|
101
|
+
Property to get the user's password in a masked format or set a new password.
|
|
102
|
+
"""
|
|
103
|
+
if self.password:
|
|
104
|
+
return '**********'
|
|
105
|
+
|
|
106
|
+
@raw_password.setter
|
|
107
|
+
def raw_password(self, value):
|
|
108
|
+
"""
|
|
109
|
+
Property to get the user's password in a masked format or set a new password.
|
|
110
|
+
"""
|
|
111
|
+
self.set_password(value)
|
|
112
|
+
|
|
113
|
+
|
|
114
|
+
@receiver(user_logged_in)
|
|
115
|
+
def set_dt_first_login(sender, user=None, **kwargs):
|
|
116
|
+
if user and not user.dt_first_login and user.pk:
|
|
117
|
+
type(user).objects.filter(pk=user.pk).update(dt_first_login=now())
|
|
118
|
+
|
|
119
|
+
|
|
120
|
+
class AnonymousUserAbstract(BaseAnonymousUser):
|
|
121
|
+
"""
|
|
122
|
+
Mixin for the AnonymousUser class, adding basic fields like first_name,
|
|
123
|
+
last_name, and email.
|
|
124
|
+
"""
|
|
125
|
+
|
|
126
|
+
first_name = ''
|
|
127
|
+
last_name = ''
|
|
128
|
+
email = ''
|
|
129
|
+
|
|
130
|
+
def get_full_name(self):
|
|
131
|
+
"""
|
|
132
|
+
Returns the full name of the anonymous user, combining first and last name if
|
|
133
|
+
available, otherwise returns the username.
|
|
134
|
+
"""
|
|
135
|
+
full_name = ''
|
|
136
|
+
if self.first_name:
|
|
137
|
+
full_name = self.first_name
|
|
138
|
+
if self.last_name:
|
|
139
|
+
full_name += ' ' + self.last_name
|
|
140
|
+
return full_name.strip() or self.username
|
|
141
|
+
|
|
142
|
+
|
|
143
|
+
class UserMixin(JsonApiMixin):
|
|
144
|
+
"""
|
|
145
|
+
Mixin that allows saving the current user in the context using a ContextVar.
|
|
146
|
+
"""
|
|
147
|
+
|
|
148
|
+
#: Context variable in which the current active user can be stored
|
|
149
|
+
CTX_USER_REQUEST: ContextVar['UserMixin'] = ContextVar('CTX_USER_REQUEST', default=None)
|
|
150
|
+
|
|
151
|
+
class Meta:
|
|
152
|
+
"""
|
|
153
|
+
Meta class for UserMixin, setting the model as abstract.
|
|
154
|
+
"""
|
|
155
|
+
|
|
156
|
+
abstract = True
|