Skip to content

Commit 0f01050

Browse files
authored
27368 - Allow users to initiate and accept magic links (#3387)
1 parent 0b8097f commit 0f01050

File tree

6 files changed

+201
-38
lines changed

6 files changed

+201
-38
lines changed

auth-api/poetry.lock

Lines changed: 169 additions & 30 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

auth-api/pyproject.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ marshmallow = "<4.0.0"
3333
# VCS dependencies
3434
sql-versioning = { git = "https://github.com/bcgov/sbc-connect-common.git", subdirectory = "python/sql-versioning", branch = "main" }
3535
flask-jwt-oidc = {git = "https://github.com/seeker25/flask-jwt-oidc.git", branch = "main" }
36-
build-deps = { git = "https://github.com/bcgov/sbc-auth.git", rev = "dependency_upgrades_p2", subdirectory = "build-deps" }
36+
build-deps = { git = "https://github.com/seeker25/sbc-auth.git", rev = "27368", subdirectory = "build-deps" }
3737

3838
[tool.poetry.group.test.dependencies]
3939
pytest = "^8.3.2"

auth-api/src/auth_api/exceptions/errors.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,10 @@ class Error(Enum):
4444
"The affiliation invitation is in an invalid state for this action.",
4545
HTTPStatus.BAD_REQUEST,
4646
)
47+
INVALID_AFFILIATION_INVITATION_TYPE = (
48+
"The affiliation invitation type is invalid.",
49+
HTTPStatus.BAD_REQUEST,
50+
)
4751
INVALID_AFFILIATION_INVITATION_TOKEN = (
4852
"The affiliation invitation token is invalid.",
4953
HTTPStatus.BAD_REQUEST,

auth-api/src/auth_api/services/affiliation_invitation.py

Lines changed: 24 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,7 @@
4242
from auth_api.services.org import Org as OrgService
4343
from auth_api.services.user import User as UserService
4444
from auth_api.utils.enums import AccessType, AffiliationInvitationType, InvitationStatus, LoginSource, Status
45-
from auth_api.utils.roles import ADMIN, COORDINATOR, STAFF
45+
from auth_api.utils.roles import ADMIN, COORDINATOR, STAFF, USER
4646
from auth_api.utils.user_context import UserContext, user_context
4747

4848
from ..schemas.affiliation_invitation import AffiliationInvitationSchemaPublic
@@ -270,7 +270,9 @@ def create_affiliation_invitation(
270270
if from_org_id == to_org_id:
271271
raise BusinessException(Error.DATA_ALREADY_EXISTS, None)
272272

273-
check_auth(org_id=from_org_id, one_of_roles=(ADMIN, COORDINATOR, STAFF))
273+
AffiliationInvitation.check_auth_for_invitation(
274+
invitation_type=affiliation_invitation_type, from_org_id=from_org_id
275+
)
274276

275277
entity, from_org, business = AffiliationInvitation._validate_prerequisites(
276278
business_identifier=business_identifier,
@@ -365,10 +367,10 @@ def get_business_name_from_alternative_name(business, business_name, business_id
365367

366368
def update_affiliation_invitation(self, user, invitation_origin, affiliation_invitation_info: Dict):
367369
"""Update the specified affiliation invitation with new data."""
368-
check_auth(org_id=self._model.from_org_id, one_of_roles=(ADMIN, COORDINATOR, STAFF))
369-
370370
invitation: AffiliationInvitationModel = self._model
371371

372+
AffiliationInvitation.check_auth_for_invitation(invitation=self._model)
373+
372374
# Don't do any updates if the invitation is not in PENDING state
373375
if invitation.invitation_status_code != InvitationStatus.PENDING.value:
374376
return AffiliationInvitation(invitation)
@@ -413,7 +415,7 @@ def delete_affiliation_invitation(invitation_id):
413415
if not (invitation := AffiliationInvitationModel.find_invitation_by_id(invitation_id)):
414416
raise BusinessException(Error.DATA_NOT_FOUND, None)
415417

416-
check_auth(org_id=invitation.from_org_id, one_of_roles=(ADMIN, COORDINATOR, STAFF))
418+
AffiliationInvitation.check_auth_for_invitation(invitation=invitation)
417419

418420
if invitation.status == InvitationStatus.ACCEPTED.value:
419421
invitation.is_deleted = True
@@ -746,3 +748,20 @@ def refuse_affiliation_invitation(invitation_id: int, user: UserService):
746748
)
747749

748750
return AffiliationInvitation(invitation)
751+
752+
@staticmethod
753+
def check_auth_for_invitation(
754+
invitation: AffiliationInvitationModel = None,
755+
invitation_type: AffiliationInvitationType = None,
756+
from_org_id: int = None,
757+
):
758+
"""Check if the user has the right to view the invitation."""
759+
invitation_type = invitation_type or AffiliationInvitationType.from_value(invitation.type)
760+
from_org_id = from_org_id or invitation.from_org_id
761+
match invitation_type:
762+
case AffiliationInvitationType.REQUEST:
763+
check_auth(org_id=from_org_id, one_of_roles=(ADMIN, COORDINATOR, STAFF))
764+
case AffiliationInvitationType.EMAIL:
765+
check_auth(org_id=from_org_id, one_of_roles=(ADMIN, COORDINATOR, USER, STAFF))
766+
case _:
767+
raise BusinessException(Error.INVALID_AFFILIATION_INVITATION_TYPE, None)

auth-api/src/auth_api/utils/enums.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -221,8 +221,9 @@ class AffiliationInvitationType(Enum):
221221
@classmethod
222222
def from_value(cls, value):
223223
"""Return instance from value of the enum."""
224+
# Change this back to None after business-ui gets pushed to production.
224225
return (
225-
AffiliationInvitationType(value) if value in cls._value2member_map_ else None
226+
AffiliationInvitationType(value) if value in cls._value2member_map_ else AffiliationInvitationType.EMAIL
226227
) # pylint: disable=no-member
227228

228229

build-deps/poetry.lock

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)