Skip to content

Commit 7238091

Browse files
authored
Core refacto: move core's schemas and models to groups and users specific files (#673)
### Description Please explain the changes you made here. ### Checklist - [ ] Created tests which fail without the change (if possible) - [ ] All tests passing - [ ] Extended the documentation, if necessary
1 parent cf3016c commit 7238091

File tree

98 files changed

+1173
-1121
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

98 files changed

+1173
-1121
lines changed

app/app.py

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -22,12 +22,14 @@
2222
from sqlalchemy.orm import Session
2323

2424
from app import api
25-
from app.core.config import Settings
2625
from app.core.core_endpoints import coredata_core, models_core
2726
from app.core.google_api.google_api import GoogleAPI
27+
from app.core.groups import models_groups
2828
from app.core.groups.groups_type import GroupType
29-
from app.core.log import LogConfig
29+
from app.core.schools import models_schools
3030
from app.core.schools.schools_type import SchoolType
31+
from app.core.utils.config import Settings
32+
from app.core.utils.log import LogConfig
3133
from app.dependencies import (
3234
get_db,
3335
get_redis_client,
@@ -176,7 +178,7 @@ def initialize_groups(
176178
exists = initialization.get_group_by_id_sync(group_id=group_type, db=db)
177179
# We don't want to recreate the groups if they already exist
178180
if not exists:
179-
group = models_core.CoreGroup(
181+
group = models_groups.CoreGroup(
180182
id=group_type,
181183
name=group_type.name,
182184
description="Group type",
@@ -202,7 +204,7 @@ def initialize_schools(
202204
exists = initialization.get_school_by_id_sync(school_id=school.value, db=db)
203205
# We don't want to recreate the groups if they already exist
204206
if not exists:
205-
db_school = models_core.CoreSchool(
207+
db_school = models_schools.CoreSchool(
206208
id=school.value,
207209
name=school.name,
208210
email_regex="null",

app/core/auth/endpoints_auth.py

Lines changed: 6 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -20,18 +20,17 @@
2020
from fastapi.templating import Jinja2Templates
2121
from sqlalchemy.ext.asyncio import AsyncSession
2222

23-
from app.core import security
2423
from app.core.auth import cruds_auth, models_auth, schemas_auth
25-
from app.core.config import Settings
26-
from app.core.core_endpoints import models_core
27-
from app.core.security import (
24+
from app.core.users import cruds_users, models_users
25+
from app.core.utils.config import Settings
26+
from app.core.utils.security import (
2827
authenticate_user,
2928
create_access_token,
3029
create_access_token_RS256,
3130
generate_token,
3231
jws_algorithm,
32+
jwt_algorithm,
3333
)
34-
from app.core.users import cruds_users
3534
from app.dependencies import (
3635
get_db,
3736
get_request_id,
@@ -1024,7 +1023,7 @@ def introspect_access_token(
10241023
payload = jwt.decode(
10251024
access_token,
10261025
settings.ACCESS_TOKEN_SECRET_KEY,
1027-
algorithms=[security.jwt_algorithm],
1026+
algorithms=[jwt_algorithm],
10281027
)
10291028
# We want to validate the structure of the payload
10301029
_ = schemas_auth.TokenData(**payload)
@@ -1060,7 +1059,7 @@ async def introspect_refresh_token(
10601059
status_code=200,
10611060
)
10621061
async def auth_get_userinfo(
1063-
user: models_core.CoreUser = Depends(
1062+
user: models_users.CoreUser = Depends(
10641063
get_user_from_token_with_scopes([[ScopeType.openid], [ScopeType.profile]]),
10651064
),
10661065
token_data: schemas_auth.TokenData = Depends(get_token_data),

app/core/core_endpoints/cruds_core.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,10 +6,11 @@
66

77
from app.core.core_endpoints import models_core
88
from app.core.groups.groups_type import AccountType
9+
from app.core.users import models_users
910

1011

1112
async def get_modules_by_user(
12-
user: models_core.CoreUser,
13+
user: models_users.CoreUser,
1314
db: AsyncSession,
1415
) -> list[str]:
1516
"""Return the modules a user has access to"""

app/core/core_endpoints/endpoints_core.py

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -6,9 +6,10 @@
66
from fastapi.responses import FileResponse
77
from sqlalchemy.ext.asyncio import AsyncSession
88

9-
from app.core.config import Settings
109
from app.core.core_endpoints import cruds_core, models_core, schemas_core
1110
from app.core.groups.groups_type import AccountType, GroupType
11+
from app.core.users import models_users
12+
from app.core.utils.config import Settings
1213
from app.dependencies import (
1314
get_db,
1415
get_settings,
@@ -169,7 +170,7 @@ async def get_favicon():
169170
)
170171
async def get_module_visibility(
171172
db: AsyncSession = Depends(get_db),
172-
user: models_core.CoreUser = Depends(is_user_in(GroupType.admin)),
173+
user: models_users.CoreUser = Depends(is_user_in(GroupType.admin)),
173174
):
174175
"""
175176
Get all existing module_visibility.
@@ -205,7 +206,7 @@ async def get_module_visibility(
205206
)
206207
async def get_user_modules_visibility(
207208
db: AsyncSession = Depends(get_db),
208-
user: models_core.CoreUser = Depends(is_user()),
209+
user: models_users.CoreUser = Depends(is_user()),
209210
):
210211
"""
211212
Get group user accessible root
@@ -223,7 +224,7 @@ async def get_user_modules_visibility(
223224
async def add_module_visibility(
224225
module_visibility: schemas_core.ModuleVisibilityCreate,
225226
db: AsyncSession = Depends(get_db),
226-
user: models_core.CoreUser = Depends(is_user_in(GroupType.admin)),
227+
user: models_users.CoreUser = Depends(is_user_in(GroupType.admin)),
227228
):
228229
"""
229230
Add a new group or account type to a module
@@ -277,7 +278,7 @@ async def delete_module_group_visibility(
277278
root: str,
278279
group_id: str,
279280
db: AsyncSession = Depends(get_db),
280-
user: models_core.CoreUser = Depends(is_user_in(GroupType.admin)),
281+
user: models_users.CoreUser = Depends(is_user_in(GroupType.admin)),
281282
):
282283
await cruds_core.delete_module_group_visibility(
283284
root=root,
@@ -294,7 +295,7 @@ async def delete_module_account_type_visibility(
294295
root: str,
295296
account_type: AccountType,
296297
db: AsyncSession = Depends(get_db),
297-
user: models_core.CoreUser = Depends(is_user_in(GroupType.admin)),
298+
user: models_users.CoreUser = Depends(is_user_in(GroupType.admin)),
298299
):
299300
await cruds_core.delete_module_account_type_visibility(
300301
root=root,

app/core/core_endpoints/models_core.py

Lines changed: 3 additions & 126 deletions
Original file line numberDiff line numberDiff line change
@@ -1,138 +1,15 @@
11
"""Common model files for all core in order to avoid circular import due to bidirectional relationship"""
22

3-
from datetime import date, datetime
4-
from uuid import UUID
3+
from datetime import date
54

6-
from sqlalchemy import ForeignKey, String
7-
from sqlalchemy.orm import Mapped, mapped_column, relationship
5+
from sqlalchemy import ForeignKey
6+
from sqlalchemy.orm import Mapped, mapped_column
87

98
from app.core.groups.groups_type import AccountType
10-
from app.types.floors_type import FloorsType
119
from app.types.membership import AvailableAssociationMembership
1210
from app.types.sqlalchemy import Base, PrimaryKey
1311

1412

15-
class CoreMembership(Base):
16-
__tablename__ = "core_membership"
17-
18-
user_id: Mapped[str] = mapped_column(ForeignKey("core_user.id"), primary_key=True)
19-
group_id: Mapped[str] = mapped_column(ForeignKey("core_group.id"), primary_key=True)
20-
# A description can be added to the membership
21-
# This can be used to note why a user is in a given group
22-
description: Mapped[str | None]
23-
24-
25-
class CoreUser(Base):
26-
__tablename__ = "core_user"
27-
28-
id: Mapped[str] = mapped_column(
29-
primary_key=True,
30-
index=True,
31-
) # Use UUID later
32-
email: Mapped[str] = mapped_column(unique=True, index=True)
33-
school_id: Mapped[UUID] = mapped_column(ForeignKey("core_school.id"))
34-
password_hash: Mapped[str]
35-
# Depending on the account type, the user may have different rights and access to different features
36-
# External users may exist for:
37-
# - accounts meant to be used by external services based on Hyperion SSO or Hyperion backend
38-
# - new users that need to do additional steps before being able to all features,
39-
# like using a specific email address, going through an inscription process or being manually validated
40-
account_type: Mapped[AccountType]
41-
name: Mapped[str]
42-
firstname: Mapped[str]
43-
nickname: Mapped[str | None]
44-
birthday: Mapped[date | None]
45-
promo: Mapped[int | None]
46-
phone: Mapped[str | None]
47-
floor: Mapped[FloorsType | None]
48-
created_on: Mapped[datetime | None]
49-
50-
# We use list["CoreGroup"] with quotes as CoreGroup is only defined after this class
51-
# Defining CoreUser after CoreGroup would cause a similar issue
52-
groups: Mapped[list["CoreGroup"]] = relationship(
53-
"CoreGroup",
54-
secondary="core_membership",
55-
back_populates="members",
56-
lazy="selectin",
57-
default_factory=list,
58-
)
59-
school: Mapped["CoreSchool"] = relationship(
60-
"CoreSchool",
61-
lazy="selectin",
62-
init=False,
63-
)
64-
65-
66-
class CoreUserUnconfirmed(Base):
67-
__tablename__ = "core_user_unconfirmed"
68-
69-
id: Mapped[str] = mapped_column(primary_key=True)
70-
# The email column should not be unique.
71-
# Someone can indeed create more than one user creation request,
72-
# for example after losing the previously received confirmation email.
73-
# For each user creation request, a row will be added in this table with a new token
74-
email: Mapped[str]
75-
activation_token: Mapped[str]
76-
created_on: Mapped[datetime]
77-
expire_on: Mapped[datetime]
78-
79-
80-
class CoreUserRecoverRequest(Base):
81-
__tablename__ = "core_user_recover_request"
82-
83-
# The email column should not be unique.
84-
# Someone can indeed create more than one password reset request,
85-
email: Mapped[str]
86-
user_id: Mapped[str]
87-
reset_token: Mapped[str] = mapped_column(primary_key=True)
88-
created_on: Mapped[datetime]
89-
expire_on: Mapped[datetime]
90-
91-
92-
class CoreUserEmailMigrationCode(Base):
93-
"""
94-
The ECL changed the email format for student users, requiring them to migrate their email.
95-
"""
96-
97-
__tablename__ = "core_user_email_migration_code"
98-
99-
user_id: Mapped[str] = mapped_column(ForeignKey("core_user.id"), primary_key=True)
100-
new_email: Mapped[str]
101-
old_email: Mapped[str]
102-
103-
confirmation_token: Mapped[str] = mapped_column(
104-
String,
105-
nullable=False,
106-
primary_key=True,
107-
)
108-
109-
# If the user should become an external or a member user after the email change
110-
make_user_external: Mapped[bool] = mapped_column(default=False)
111-
112-
113-
class CoreGroup(Base):
114-
__tablename__ = "core_group"
115-
116-
id: Mapped[str] = mapped_column(primary_key=True, index=True)
117-
name: Mapped[str] = mapped_column(index=True, unique=True)
118-
description: Mapped[str | None]
119-
120-
members: Mapped[list["CoreUser"]] = relationship(
121-
"CoreUser",
122-
secondary="core_membership",
123-
back_populates="groups",
124-
default_factory=list,
125-
)
126-
127-
128-
class CoreSchool(Base):
129-
__tablename__ = "core_school"
130-
131-
id: Mapped[PrimaryKey]
132-
name: Mapped[str] = mapped_column(unique=True)
133-
email_regex: Mapped[str]
134-
135-
13613
class CoreAssociationMembership(Base):
13714
__tablename__ = "core_association_membership"
13815

0 commit comments

Comments
 (0)