Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 19 additions & 1 deletion controller/auth/kratos.py
Original file line number Diff line number Diff line change
Expand Up @@ -254,7 +254,7 @@ def email_with_link(to_email: str, recovery_link: str) -> None:
f"{LANGUAGE_MESSAGES['de']}{recovery_link}\n\n{LANGUAGE_EXPIRATION_INFO['de']}\n\n\n------\n\n{LANGUAGE_MESSAGES['en']}{recovery_link}\n\n{LANGUAGE_EXPIRATION_INFO['en']}",
)
msg["Subject"] = INVITATION_SUBJECT
msg["From"] = "no-reply@kern.ai"
msg["From"] = "signup@kern.ai"
msg["To"] = to_email

with smtplib.SMTP(SMTP_HOST, SMTP_PORT) as server:
Expand All @@ -265,6 +265,24 @@ def email_with_link(to_email: str, recovery_link: str) -> None:
server.send_message(msg)


def send_bulk_emails(emails: List[str], recovery_links: List[str]) -> None:

with smtplib.SMTP(SMTP_HOST, SMTP_PORT) as server:
if SMTP_USER and SMTP_PASSWORD:
server.ehlo()
server.starttls()
server.login(SMTP_USER, SMTP_PASSWORD)

for to_email, recovery_link in zip(emails, recovery_links):
msg = MIMEText(
f"{LANGUAGE_MESSAGES['de']}{recovery_link}\n\n{LANGUAGE_EXPIRATION_INFO['de']}\n\n\n------\n\n{LANGUAGE_MESSAGES['en']}{recovery_link}\n\n{LANGUAGE_EXPIRATION_INFO['en']}",
)
msg["Subject"] = INVITATION_SUBJECT
msg["From"] = "signup@kern.ai"
msg["To"] = to_email
server.send_message(msg)


def check_user_exists(email: str) -> bool:
request = requests.get(
f"{KRATOS_ADMIN_URL}/identities?preview_credentials_identifier_similar={quote(email)}"
Expand Down
34 changes: 23 additions & 11 deletions controller/auth/manager.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
from controller.user import manager as user_manager
from controller.organization import manager as organization_manager
from submodules.model import enums, exceptions
from submodules.model.business_objects import organization
from submodules.model.business_objects import general, organization
from submodules.model.business_objects.user import check_email_in_full_admin
from submodules.model.models import Organization, Project, User
import sqlalchemy
Expand Down Expand Up @@ -183,32 +183,44 @@ def invite_users(
team_ids: Optional[List[str]] = None,
):
user_ids = []
recovery_links = []
organization = organization_manager.get_organization_by_name(organization_name)
if organization is None:
raise exceptions.EntityNotFoundException("Organization not found")
for email in emails:
# Create accounts for the email
user = kratos.create_user_kratos(email, provider)
if not user:
raise AuthManagerError("User creation failed")
user_ids.append(user["id"])
# Assign the account to the organization
user_manager.update_organization_of_user(organization_name, email)
user_database = user_manager.get_or_create_user(user["id"], with_commit=False)
if not user_database:
raise AuthManagerError("User creation in database failed")

# Assign the user role
user_manager.update_user_role(user["id"], user_role)
user_database.language_display = language

# Add the preferred language
user_manager.update_user_field(user["id"], "language_display", language)
try:
role = enums.UserRoles[user_role.upper()].value
except KeyError:
raise ValueError(f"Invalid role: {role}")
user_database.role = role
user_database.organization_id = organization.id

# Add the user to the teams
if team_ids:
user_manager.add_user_to_teams(creation_user_id, user["id"], team_ids)
user_manager.add_user_to_teams(
creation_user_id, user["id"], team_ids, with_commit=False
)

# Get the recovery link for the email
recovery_link = kratos.get_recovery_link(user["id"])
if not recovery_link:
raise AuthManagerError("Failed to get recovery link")

# Send the recovery link to the email
kratos.email_with_link(email, recovery_link["recovery_link"])
recovery_links.append(recovery_link["recovery_link"])
general.commit()
kratos.send_bulk_emails(emails, recovery_links)
kratos.__refresh_identity_cache()
organization_manager.sync_organization_sharepoint_integrations(organization.id)
return user_ids


Expand Down
17 changes: 11 additions & 6 deletions controller/user/manager.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,12 +17,14 @@ def get_user(user_id: str) -> User:
return user_item


def get_or_create_user(user_id: str) -> User:
def get_or_create_user(user_id: str, with_commit: bool = True) -> User:
user_item = user.get(user_id)
if not user_item:
user_item = user.create(user_id, with_commit=True)
kratos.__refresh_identity_cache()
update_last_interaction(user_item.id)
user_item = user.create(user_id, with_commit=with_commit)
if with_commit:
kratos.__refresh_identity_cache()
else:
update_last_interaction(user_item.id)
return user_item


Expand Down Expand Up @@ -89,10 +91,13 @@ def update_user_field(user_id: str, field: str, value: Any) -> User:
return user_item


def add_user_to_teams(creation_user_id: str, user_id: str, team_ids: list) -> User:
def add_user_to_teams(
creation_user_id: str, user_id: str, team_ids: list, with_commit: bool = True
) -> User:
for team_id in team_ids:
team_member_db_co.create(team_id, user_id, creation_user_id, with_commit=False)
general.commit()
if with_commit:
general.commit()


def remove_organization_from_user(user_mail: str) -> None:
Expand Down
2 changes: 0 additions & 2 deletions fast_api/routes/organization.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
import json
from controller.auth import kratos
from fastapi import APIRouter, Request, Body
from fast_api.models import (
AddUserToOrganizationBody,
Expand Down Expand Up @@ -95,7 +94,6 @@ def get_user_info(request: Request):
# in use cognition-ui & admin dashboard (07.01.25)
@router.get("/get-user-info-extended")
def get_user_info_extended(request: Request):
kratos.__refresh_identity_cache()
user = auth_manager.get_user_by_info(request.state.info)
name = resolve_user_name_by_id(user.id)
user_dict = {
Expand Down