Skip to content

Commit 99d1cf1

Browse files
author
maxim-lixakov
committed
[DOP-21268] - update User model
1 parent e5b623d commit 99d1cf1

File tree

9 files changed

+89
-19
lines changed

9 files changed

+89
-19
lines changed

docker-compose.test.yml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@ services:
4040
- 8000:8000
4141
volumes:
4242
- ./syncmaster:/app/syncmaster
43+
- ./docs/_static:/app/docs/_static
4344
- ./cached_jars:/root/.ivy2
4445
- ./reports:/app/reports
4546
- ./tests:/app/tests

syncmaster/backend/export_openapi_schema.py

100644100755
File mode changed.

syncmaster/backend/middlewares/__init__.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,8 +10,8 @@
1010
)
1111
from syncmaster.backend.middlewares.openapi import apply_openapi_middleware
1212
from syncmaster.backend.middlewares.request_id import apply_request_id_middleware
13-
from syncmaster.backend.middlewares.static_files import apply_static_files
1413
from syncmaster.backend.middlewares.session import apply_session_middleware
14+
from syncmaster.backend.middlewares.static_files import apply_static_files
1515
from syncmaster.settings import Settings
1616

1717

syncmaster/backend/providers/auth/dummy_provider.py

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -62,7 +62,14 @@ async def get_token_password_grant(
6262
try:
6363
user = await self._uow.user.read_by_username(login)
6464
except EntityNotFoundError:
65-
user = await self._uow.user.create(username=login, is_active=True)
65+
user = await self._uow.user.create(
66+
username=login,
67+
email=f"{login}@example.com",
68+
first_name=f"{login}_first",
69+
middle_name=f"{login}_middle",
70+
last_name=f"{login}_last",
71+
is_active=True,
72+
)
6673

6774
log.info("User with id %r found", user.id)
6875
if not user.is_active:

syncmaster/backend/providers/auth/keycloak_provider.py

Lines changed: 33 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -77,13 +77,8 @@ async def get_current_user(self, access_token: str, *args, **kwargs) -> Any:
7777
refresh_token = request.session.get("refresh_token")
7878

7979
if not access_token:
80-
state = generate_state(request.url.path) # initial url request
81-
auth_url = self.keycloak_openid.auth_url(
82-
redirect_uri=self.settings.redirect_uri,
83-
scope=self.settings.scope,
84-
state=state,
85-
)
86-
raise RedirectException(redirect_url=auth_url)
80+
log.debug("No access token found in session.")
81+
self.redirect_to_auth(request.url.path)
8782

8883
try:
8984
token_info = self.keycloak_openid.decode_token(token=access_token)
@@ -93,20 +88,29 @@ async def get_current_user(self, access_token: str, *args, **kwargs) -> Any:
9388

9489
if not token_info and refresh_token:
9590
log.debug("Access token invalid. Attempting to refresh.")
96-
new_tokens = await self.refresh_access_token(refresh_token)
9791

98-
new_access_token = new_tokens.get("access_token")
99-
new_refresh_token = new_tokens.get("refresh_token")
100-
request.session["access_token"] = new_access_token
101-
request.session["refresh_token"] = new_refresh_token
92+
try:
93+
new_tokens = await self.refresh_access_token(refresh_token)
10294

103-
token_info = self.keycloak_openid.decode_token(
104-
token=new_access_token,
105-
)
106-
log.debug("Access token refreshed and decoded successfully.")
95+
new_access_token = new_tokens.get("access_token")
96+
new_refresh_token = new_tokens.get("refresh_token")
97+
request.session["access_token"] = new_access_token
98+
request.session["refresh_token"] = new_refresh_token
99+
100+
token_info = self.keycloak_openid.decode_token(
101+
token=new_access_token,
102+
)
103+
log.debug("Access token refreshed and decoded successfully.")
104+
except Exception as e:
105+
log.debug("Failed to refresh access token: %s", e)
106+
self.redirect_to_auth(request.url.path)
107107

108108
user_id = token_info.get("sub")
109109
login = token_info.get("preferred_username")
110+
email = token_info.get("email")
111+
first_name = token_info.get("given_name")
112+
middle_name = token_info.get("middle_name")
113+
last_name = token_info.get("family_name")
110114

111115
if not user_id:
112116
raise AuthorizationError("Invalid token payload")
@@ -117,6 +121,10 @@ async def get_current_user(self, access_token: str, *args, **kwargs) -> Any:
117121
except EntityNotFoundError:
118122
user = await self._uow.user.create(
119123
username=login,
124+
email=email,
125+
first_name=first_name,
126+
middle_name=middle_name,
127+
last_name=last_name,
120128
is_active=True,
121129
)
122130
return user
@@ -127,3 +135,12 @@ async def refresh_access_token(self, refresh_token: str) -> dict[str, Any]:
127135

128136
async def get_user_info(self, access_token: str) -> dict[str, Any]:
129137
return self.keycloak_openid.userinfo(access_token)
138+
139+
def redirect_to_auth(self, path: str) -> None:
140+
state = generate_state(path)
141+
auth_url = self.keycloak_openid.auth_url(
142+
redirect_uri=self.settings.redirect_uri,
143+
scope=self.settings.scope,
144+
state=state,
145+
)
146+
raise RedirectException(redirect_url=auth_url)

syncmaster/db/migrations/versions/2023-11-23_0001_create_user_table.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,10 @@ def upgrade():
2222
"user",
2323
sa.Column("id", sa.BigInteger(), nullable=False),
2424
sa.Column("username", sa.String(length=256), nullable=False),
25+
sa.Column("email", sa.String(length=256), nullable=False),
26+
sa.Column("first_name", sa.String(length=256)),
27+
sa.Column("last_name", sa.String(length=256)),
28+
sa.Column("middle_name", sa.String(length=256)),
2529
sa.Column("is_superuser", sa.Boolean(), nullable=False),
2630
sa.Column("is_active", sa.Boolean(), nullable=False),
2731
sa.Column("created_at", sa.DateTime(), server_default=sa.text("now()"), nullable=False),

syncmaster/db/models/user.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,10 @@
1212
class User(Base, TimestampMixin, DeletableMixin):
1313
id: Mapped[int] = mapped_column(BigInteger, primary_key=True)
1414
username: Mapped[str] = mapped_column(String(256), nullable=False, unique=True, index=True)
15+
email: Mapped[str] = mapped_column(String(256), nullable=False, unique=True)
16+
first_name: Mapped[str] = mapped_column(String(256))
17+
last_name: Mapped[str] = mapped_column(String(256))
18+
middle_name: Mapped[str] = mapped_column(String(256))
1519
is_superuser: Mapped[bool] = mapped_column(Boolean, default=False, nullable=False)
1620
is_active: Mapped[bool] = mapped_column(Boolean, default=False, nullable=False)
1721

syncmaster/db/repositories/user.py

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -55,11 +55,24 @@ async def update(self, user_id: int, data: dict) -> User:
5555
except IntegrityError as e:
5656
self._raise_error(e)
5757

58-
async def create(self, username: str, is_active: bool, is_superuser: bool = False) -> User:
58+
async def create(
59+
self,
60+
username: str,
61+
email: str,
62+
is_active: bool,
63+
first_name: str | None,
64+
middle_name: str | None,
65+
last_name: str | None,
66+
is_superuser: bool = False,
67+
) -> User:
5968
query = (
6069
insert(User)
6170
.values(
6271
username=username,
72+
email=email,
73+
first_name=first_name,
74+
middle_name=middle_name,
75+
last_name=last_name,
6376
is_active=is_active,
6477
is_superuser=is_superuser,
6578
)

tests/test_unit/utils.py

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,9 +33,21 @@ async def create_user_cm(
3333
is_active: bool = False,
3434
is_superuser: bool = False,
3535
is_deleted: bool = False,
36+
email: str = None,
37+
first_name: str = None,
38+
middle_name: str = None,
39+
last_name: str = None,
3640
) -> AsyncGenerator[User, None]:
41+
email = email or f"{username}@user.user"
42+
first_name = first_name or f"{username}_first"
43+
middle_name = middle_name or f"{username}_middle"
44+
last_name = last_name or f"{username}_last"
3745
u = User(
3846
username=username,
47+
email=email,
48+
first_name=first_name,
49+
middle_name=middle_name,
50+
last_name=last_name,
3951
is_active=is_active,
4052
is_superuser=is_superuser,
4153
is_deleted=is_deleted,
@@ -54,9 +66,21 @@ async def create_user(
5466
is_active: bool = False,
5567
is_superuser: bool = False,
5668
is_deleted: bool = False,
69+
email: str = None,
70+
first_name: str = None,
71+
middle_name: str = None,
72+
last_name: str = None,
5773
) -> User:
74+
email = email or f"{username}@user.user"
75+
first_name = first_name or f"{username}_first"
76+
middle_name = middle_name or f"{username}_middle"
77+
last_name = last_name or f"{username}_last"
5878
u = User(
5979
username=username,
80+
email=email,
81+
first_name=first_name,
82+
middle_name=middle_name,
83+
last_name=last_name,
6084
is_active=is_active,
6185
is_superuser=is_superuser,
6286
is_deleted=is_deleted,

0 commit comments

Comments
 (0)