Skip to content

Commit

Permalink
Fix internal user (#583)
Browse files Browse the repository at this point in the history
### 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
  • Loading branch information
Rotheem authored Sep 27, 2024
1 parent 0ec1546 commit 7426d7e
Show file tree
Hide file tree
Showing 3 changed files with 74 additions and 42 deletions.
1 change: 1 addition & 0 deletions app/core/models_core.py
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,7 @@ class CoreUser(Base):
"CoreGroup",
secondary="core_membership",
back_populates="members",
lazy="selectin",
)


Expand Down
82 changes: 42 additions & 40 deletions app/core/users/endpoints_users.py
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,8 @@

templates = Jinja2Templates(directory="assets/templates")

ECL_EMAIL_REGEX = r"^[\w\-.]*@etu(-enise)?\.ec-lyon\.fr$"


@router.get(
"/users/",
Expand Down Expand Up @@ -612,7 +614,7 @@ async def migrate_mail(
This endpoint will send a confirmation code to the user's new email address. He will need to use this code to confirm the change with `/users/confirm-mail-migration` endpoint.
"""

if not re.match(r"^[\w\-.]*@etu(-enise)?\.ec-lyon\.fr$", mail_migration.new_email):
if not re.match(ECL_EMAIL_REGEX, mail_migration.new_email):
raise HTTPException(
status_code=400,
detail="The new email address must match the new ECL format for student users",
Expand Down Expand Up @@ -843,6 +845,45 @@ async def update_current_user(
await cruds_users.update_user(db=db, user_id=user.id, user_update=user_update)


@router.patch(
"/users/external",
status_code=204,
)
async def switch_external_user_internal(
db: AsyncSession = Depends(get_db),
u: models_core.CoreUser = Depends(is_user_a_member_of(GroupType.admin)),
):
"""
Switch all external users to internal users if they have an ECL email address.
**This endpoint is only usable by administrators**
"""

users = await cruds_users.get_users(db=db)
for user in users:
if re.match(ECL_EMAIL_REGEX, user.email):
await cruds_users.update_user(
db=db,
user_id=user.id,
user_update=schemas_core.CoreUserUpdateAdmin(external=False),
)
group_ids = [group.id for group in user.groups]
if GroupType.external in group_ids:
await cruds_groups.delete_membership_by_group_and_user_id(
db=db,
group_id=GroupType.external,
user_id=user.id,
)
if GroupType.student not in group_ids:
await cruds_groups.create_membership(
db=db,
membership=models_core.CoreMembership(
group_id=GroupType.student,
user_id=user.id,
),
)


@router.post(
"/users/merge",
status_code=204,
Expand Down Expand Up @@ -988,42 +1029,3 @@ async def read_user_profile_picture(
filename=str(user_id),
default_asset="assets/images/default_profile_picture.png",
)


@router.patch(
"/users/external",
status_code=204,
)
async def switch_external_user_internal(
db: AsyncSession = Depends(get_db),
_: models_core.CoreUser = Depends(is_user_a_member_of(GroupType.admin)),
):
"""
Switch all external users to internal users if they have an ECL email address.
**This endpoint is only usable by administrators**
"""

users = await cruds_users.get_users(db=db)
for user in users:
if re.match(r"^[\w\-.]*@etu(-enise)?\.ec-lyon\.fr$", user.email):
await cruds_users.update_user(
db=db,
user_id=user.id,
user_update=schemas_core.CoreUserUpdateAdmin(external=False),
)
group_ids = [group.id for group in user.groups]
if GroupType.external in group_ids:
await cruds_groups.delete_membership_by_group_and_user_id(
db=db,
group_id=GroupType.external,
user_id=user.id,
)
if GroupType.student not in group_ids:
await cruds_groups.create_membership(
db=db,
membership=models_core.CoreMembership(
group_id=GroupType.student,
user_id=user.id,
),
)
33 changes: 31 additions & 2 deletions tests/test_users.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@

admin_user: models_core.CoreUser
student_user: models_core.CoreUser

external_user: models_core.CoreUser
student_user_with_old_email: models_core.CoreUser

token_admin_user: str
Expand All @@ -31,7 +31,7 @@

@pytest_asyncio.fixture(scope="module", autouse=True)
async def init_objects() -> None:
global admin_user, student_user, student_user_with_old_email
global admin_user, student_user, student_user_with_old_email, external_user

admin_user = await create_user_with_groups(
[GroupType.admin],
Expand All @@ -42,6 +42,10 @@ async def init_objects() -> None:
email=student_user_email,
password=student_user_password,
)
external_user = await create_user_with_groups(
[GroupType.external],
external=True,
)

student_user_with_old_email = await create_user_with_groups(
[GroupType.student],
Expand Down Expand Up @@ -357,3 +361,28 @@ def test_read_user_profile_picture(client: TestClient) -> None:
)

assert response.status_code == 200


def test_batch_internal_user(client: TestClient) -> None:
token = create_api_access_token(admin_user)

response = client.patch(
"/users/external",
headers={"Authorization": f"Bearer {token}"},
)

assert response.status_code == 204

response = client.get(
f"/groups/{GroupType.external.value}",
headers={"Authorization": f"Bearer {token}"},
)
assert response.json()["members"] == []

response = client.get(
f"/groups/{GroupType.student.value}",
headers={"Authorization": f"Bearer {token}"},
)
members = response.json()["members"]
members_ids = [member["id"] for member in members]
assert external_user.id in members_ids

0 comments on commit 7426d7e

Please sign in to comment.