Skip to content

Commit

Permalink
fix: Disable invite button when email config is not set
Browse files Browse the repository at this point in the history
  • Loading branch information
tiagoapolo committed Jan 20, 2025
1 parent 3ac455d commit ef1fe5e
Show file tree
Hide file tree
Showing 5 changed files with 103 additions and 3 deletions.
19 changes: 19 additions & 0 deletions api/app/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,12 @@
from typing import TypedDict

import shortuuid
from app.settings.common import (
EMAIL_BACKEND,
EMAIL_HOST_USER,
SENDGRID_API_KEY,
AWS_SES_REGION_ENDPOINT,
)

UNKNOWN = "unknown"
VERSIONS_INFO_FILE_LOCATION = ".versions.json"
Expand All @@ -12,6 +18,7 @@
class VersionInfo(TypedDict):
ci_commit_sha: str
image_tag: str
has_email_provider: bool
is_enterprise: bool
is_saas: bool

Expand All @@ -29,6 +36,17 @@ def is_saas() -> bool:
return pathlib.Path("./SAAS_DEPLOYMENT").exists()


def has_email_provider() -> bool:
match EMAIL_BACKEND:
case "django.core.mail.backends.smtp.EmailBackend":
return EMAIL_HOST_USER is not None
case "sgbackend.SendGridBackend":
return SENDGRID_API_KEY is not None
case "django_ses.SESBackend":
return AWS_SES_REGION_ENDPOINT is not None
case _:
return False

@lru_cache
def get_version_info() -> VersionInfo:
"""Reads the version info baked into src folder of the docker container"""
Expand All @@ -45,6 +63,7 @@ def get_version_info() -> VersionInfo:
version_json = version_json | {
"ci_commit_sha": _get_file_contents("./CI_COMMIT_SHA"),
"image_tag": image_tag,
"has_email_provider": has_email_provider(),
"is_enterprise": is_enterprise(),
"is_saas": is_saas(),
}
Expand Down
70 changes: 70 additions & 0 deletions api/tests/unit/app/test_unit_app_utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@ def path_side_effect(file_path: str) -> mocker.MagicMock:
assert result == {
"ci_commit_sha": "some_sha",
"image_tag": "2.66.2",
"has_email_provider": False,
"is_enterprise": True,
"is_saas": False,
"package_versions": {".": "2.66.2"},
Expand Down Expand Up @@ -76,6 +77,75 @@ def path_side_effect(file_path: str) -> mocker.MagicMock:
assert result == {
"ci_commit_sha": "unknown",
"image_tag": "unknown",
"has_email_provider": False,
"is_enterprise": True,
"is_saas": False,
}


def test_get_version_info_with_email_config_smtp(mocker: MockerFixture) -> None:

mocker.patch(
"app.utils.EMAIL_BACKEND", "django.core.mail.backends.smtp.EmailBackend"
)
mocker.patch("app.utils.EMAIL_HOST_USER", "user")
# When
result = get_version_info()

# Then
assert result == {
"ci_commit_sha": "unknown",
"image_tag": "unknown",
"has_email_provider": True,
"is_enterprise": False,
"is_saas": False,
}


def test_get_version_info_with_email_config_sendgrid(mocker: MockerFixture) -> None:

mocker.patch("app.utils.EMAIL_BACKEND", "sgbackend.SendGridBackend")
mocker.patch("app.utils.SENDGRID_API_KEY", "key")
# When
result = get_version_info()

# Then
assert result == {
"ci_commit_sha": "unknown",
"image_tag": "unknown",
"has_email_provider": True,
"is_enterprise": False,
"is_saas": False,
}


def test_get_version_info_with_email_config_ses(mocker: MockerFixture) -> None:

mocker.patch("app.utils.EMAIL_BACKEND", "django_ses.SESBackend")
mocker.patch("app.utils.AWS_SES_REGION_ENDPOINT", "endpoint")
# When
result = get_version_info()

# Then
assert result == {
"ci_commit_sha": "unknown",
"image_tag": "unknown",
"has_email_provider": True,
"is_enterprise": False,
"is_saas": False,
}


def test_get_version_info_without_email_config(mocker: MockerFixture) -> None:

# When
result = get_version_info()

# Then
assert result == {
"ci_commit_sha": "unknown",
"image_tag": "unknown",
"has_email_provider": False,
"is_enterprise": False,
"is_saas": False,
}
1 change: 1 addition & 0 deletions api/tests/unit/app/test_unit_app_views.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ def test_get_version_info(api_client: APIClient) -> None:
assert response.json() == {
"ci_commit_sha": "unknown",
"image_tag": "unknown",
"has_email_provider": False,
"is_enterprise": False,
"is_saas": False,
}
2 changes: 2 additions & 0 deletions frontend/common/utils/utils.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -552,6 +552,8 @@ const Utils = Object.assign({}, require('./base/_utils'), {
getViewIdentitiesPermission() {
return 'VIEW_IDENTITIES'
},
hasEmailProvider: () =>
global.flagsmithVersion?.backend?.has_email_provider ?? false,
isEnterpriseImage: () => global.flagsmithVersion?.backend.is_enterprise,
isMigrating() {
const model = ProjectStore.model as null | ProjectType
Expand Down
14 changes: 11 additions & 3 deletions frontend/web/components/pages/UsersAndPermissionsPage.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@ type UsersAndPermissionsPageType = {
}

const widths = [300, 200, 80]
const noEmailProvider = `You must configure an email provider before using email invites. Please read our documentation on how to configure an email provider.`

type UsersAndPermissionsInnerType = {
organisation: Organisation
Expand All @@ -69,11 +70,11 @@ const UsersAndPermissionsInner: FC<UsersAndPermissionsInnerType> = ({
subscriptionMeta,
users,
}) => {

const paymentsEnabled = Utils.getFlagsmithHasFeature('payments_enabled')
const verifySeatsLimit = Utils.getFlagsmithHasFeature(
'verify_seats_limit_for_invite_links',
)
const hasEmailProvider = Utils.hasEmailProvider()
const manageUsersPermission = useHasPermission({
id: AccountStore.getOrganisation()?.id,
level: 'organisation',
Expand All @@ -85,6 +86,12 @@ const UsersAndPermissionsInner: FC<UsersAndPermissionsInnerType> = ({
permission: 'MANAGE_USER_GROUPS',
})

const hasInvitePermission =
hasEmailProvider && manageUsersPermission.permission
const tooltTipText = !hasEmailProvider
? noEmailProvider
: Constants.organisationPermissions('Admin')

const roleChanged = (id: number, { value: role }: { value: string }) => {
AppActions.updateUserRole(id, role)
}
Expand Down Expand Up @@ -230,10 +237,11 @@ const UsersAndPermissionsInner: FC<UsersAndPermissionsInnerType> = ({
<Row space className='mt-4'>
<h5 className='mb-0'>Team Members</h5>
{Utils.renderWithPermission(
!manageUsersPermission.permission,
Constants.organisationPermissions('Admin'),
hasInvitePermission,
tooltTipText,
<Button
disabled={
!hasEmailProvider ||
needsUpgradeForAdditionalSeats ||
!manageUsersPermission.permission
}
Expand Down

0 comments on commit ef1fe5e

Please sign in to comment.