|
22 | 22 |
|
23 | 23 | from pydatalab.config import CONFIG |
24 | 24 | from pydatalab.errors import UserRegistrationForbidden |
25 | | -from pydatalab.logger import LOGGER, logged_route |
| 25 | +from pydatalab.feature_flags import FEATURE_FLAGS |
| 26 | +from pydatalab.logger import LOGGER |
26 | 27 | from pydatalab.login import get_by_id |
27 | 28 | from pydatalab.models.people import AccountStatus, Identity, IdentityType, Person |
28 | 29 | from pydatalab.mongo import flask_mongo, insert_pydantic_model_fork_safe |
@@ -202,7 +203,6 @@ def set_applocal_session(): |
202 | 203 | orcid = LocalProxy(lambda: g.flask_dance_orcid) |
203 | 204 |
|
204 | 205 |
|
205 | | -@logged_route |
206 | 206 | def wrapped_login_user(*args, **kwargs): |
207 | 207 | login_user(*args, **kwargs) |
208 | 208 |
|
@@ -273,7 +273,6 @@ def _check_email_domain(email: str, allow_list: list[str] | None) -> bool: |
273 | 273 | return True |
274 | 274 |
|
275 | 275 |
|
276 | | -@logged_route |
277 | 276 | def find_user_with_identity( |
278 | 277 | identifier: str, |
279 | 278 | identity_type: str | IdentityType, |
@@ -332,7 +331,6 @@ def find_create_or_modify_user( |
332 | 331 |
|
333 | 332 | """ |
334 | 333 |
|
335 | | - @logged_route |
336 | 334 | def attach_identity_to_user( |
337 | 335 | user_id: str, |
338 | 336 | identity: Identity, |
@@ -416,7 +414,13 @@ def attach_identity_to_user( |
416 | 414 | user_model = get_by_id(str(user.immutable_id)) |
417 | 415 | if user is None: |
418 | 416 | raise RuntimeError("Failed to insert user into database") |
| 417 | + |
419 | 418 | wrapped_login_user(user_model) |
| 419 | + # Send email notification to admins |
| 420 | + _send_admin_email_notification(user) |
| 421 | + |
| 422 | + if user is not None and user.account_status == AccountStatus.DEACTIVATED: |
| 423 | + _send_admin_email_notification(user) |
420 | 424 |
|
421 | 425 | # Log the user into the session with this identity |
422 | 426 | if user is not None: |
@@ -477,6 +481,56 @@ def _check_user_registration_allowed(email: str) -> None: |
477 | 481 | ) |
478 | 482 |
|
479 | 483 |
|
| 484 | +def _send_admin_email_notification(user: Person) -> None: |
| 485 | + """Sends an email notification to the admin email address when an unverified user |
| 486 | + attempts to register an account. |
| 487 | +
|
| 488 | + """ |
| 489 | + if not FEATURE_FLAGS.email_notifications: |
| 490 | + LOGGER.info("Email notifications are disabled; not sending unverified user notification.") |
| 491 | + return |
| 492 | + |
| 493 | + admins = flask_mongo.db.users.aggregate( |
| 494 | + [ |
| 495 | + { |
| 496 | + "$lookup": { |
| 497 | + "from": "roles", |
| 498 | + "localField": "_id", |
| 499 | + "foreignField": "_id", |
| 500 | + "as": "role", |
| 501 | + } |
| 502 | + }, |
| 503 | + {"$unwind": "$role"}, |
| 504 | + {"$match": {"role.role": "admin"}}, |
| 505 | + ] |
| 506 | + ) |
| 507 | + |
| 508 | + admin_emails = [a["contact_email"] for a in admins if a.get("contact_email")] |
| 509 | + |
| 510 | + # Get contact emails of admin users via lookup in the roles and users collections |
| 511 | + if user.account_status == AccountStatus.UNVERIFIED: |
| 512 | + subject = "User Registration Notification" |
| 513 | + subject += f": {CONFIG.APP_URL}" if CONFIG.APP_URL else "" |
| 514 | + body = ( |
| 515 | + f"A new user with display name {user.display_name} attempted to register an account on {CONFIG.APP_URL}.\n\n" |
| 516 | + "Please review the registration in your admin panel and verify the user if appropriate." |
| 517 | + ) |
| 518 | + |
| 519 | + if user.account_status == AccountStatus.DEACTIVATED: |
| 520 | + subject = "Deactivated User Login Attempt Notification" |
| 521 | + subject += f": {CONFIG.APP_URL}" if CONFIG.APP_URL else "" |
| 522 | + body = ( |
| 523 | + f"A deactivated user with display name {user.display_name} attempted to log in to the datalab instance at {CONFIG.APP_URL}.\n\n" |
| 524 | + "No action is required unless you wish to reactivate this user." |
| 525 | + ) |
| 526 | + |
| 527 | + try: |
| 528 | + for email in admin_emails: |
| 529 | + send_mail(email, subject, body) |
| 530 | + except Exception as exc: |
| 531 | + LOGGER.warning("Failed to send unverified user notification email: %s", exc) |
| 532 | + |
| 533 | + |
480 | 534 | def _send_magic_link_email( |
481 | 535 | email: str, token: str, referrer: str | None, purpose: str = "authorize" |
482 | 536 | ) -> None: |
|
0 commit comments