Skip to content

Commit 4c6c5df

Browse files
authored
♻️✅ invitations service: small refactoring and cleanup (#7945)
1 parent 03bc710 commit 4c6c5df

File tree

6 files changed

+62
-24
lines changed

6 files changed

+62
-24
lines changed

services/invitations/src/simcore_service_invitations/cli.py

Lines changed: 12 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import getpass
22
import logging
3+
import os
34

45
import typer
56
from cryptography.fernet import Fernet
@@ -14,7 +15,6 @@
1415
print_as_envfile,
1516
)
1617

17-
from . import web_server
1818
from ._meta import PROJECT_NAME, __version__
1919
from .core.settings import ApplicationSettings, MinimalApplicationSettings
2020
from .services.invitations import (
@@ -50,7 +50,7 @@ def generate_key(
5050
export INVITATIONS_SECRET_KEY=$(invitations-maker generate-key)
5151
"""
5252
assert ctx # nosec
53-
print(Fernet.generate_key().decode()) # noqa: T201
53+
typer.echo(Fernet.generate_key().decode())
5454

5555

5656
@main.command()
@@ -106,6 +106,10 @@ def invite(
106106
None,
107107
help=InvitationInputs.model_fields["trial_account_days"].description,
108108
),
109+
extra_credits_in_usd: int = typer.Option(
110+
None,
111+
help=InvitationInputs.model_fields["extra_credits_in_usd"].description,
112+
),
109113
product: str = typer.Option(
110114
None,
111115
help=InvitationInputs.model_fields["product"].description,
@@ -119,7 +123,7 @@ def invite(
119123
issuer=issuer,
120124
guest=TypeAdapter(EmailStr).validate_python(email),
121125
trial_account_days=trial_account_days,
122-
extra_credits_in_usd=None,
126+
extra_credits_in_usd=extra_credits_in_usd,
123127
product=product,
124128
)
125129

@@ -129,7 +133,7 @@ def invite(
129133
base_url=settings.INVITATIONS_OSPARC_URL,
130134
default_product=settings.INVITATIONS_DEFAULT_PRODUCT,
131135
)
132-
print(invitation_link) # noqa: T201
136+
typer.echo(invitation_link)
133137

134138

135139
@main.command()
@@ -149,18 +153,8 @@ def extract(ctx: typer.Context, invitation_url: str):
149153
)
150154
assert invitation.product is not None # nosec
151155

152-
print(invitation.model_dump_json(indent=1)) # noqa: T201
153-
154-
except (InvalidInvitationCodeError, ValidationError):
155-
_err_console.print("[bold red]Invalid code[/bold red]")
156-
156+
typer.echo(invitation.model_dump_json(indent=1))
157157

158-
@main.command()
159-
def serve(
160-
ctx: typer.Context,
161-
*,
162-
reload: bool = False,
163-
):
164-
"""Starts server with http API"""
165-
assert ctx # nosec
166-
web_server.start(log_level="info", reload=reload)
158+
except (InvalidInvitationCodeError, ValidationError) as err:
159+
typer.secho("Invalid code", fg=typer.colors.RED, bold=True, err=True)
160+
raise typer.Exit(os.EX_DATAERR) from err

services/invitations/tests/unit/api/test_api_invitations.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@ def test_create_invitation(
4040
assert invitation.issuer == invitation_input.issuer
4141
assert invitation.guest == invitation_input.guest
4242
assert invitation.trial_account_days == invitation_input.trial_account_days
43+
assert invitation.extra_credits_in_usd == invitation_input.extra_credits_in_usd
4344

4445
# checks issue with `//` reported in https://github.com/ITISFoundation/osparc-simcore/issues/7055
4546
assert invitation.invitation_url
@@ -61,6 +62,7 @@ def test_check_invitation(
6162
"issuer": invitation_data.issuer,
6263
"guest": invitation_data.guest,
6364
"trial_account_days": invitation_data.trial_account_days,
65+
"extra_credits_in_usd": invitation_data.extra_credits_in_usd,
6466
},
6567
auth=basic_auth,
6668
)
@@ -85,6 +87,7 @@ def test_check_invitation(
8587
assert invitation.issuer == invitation_data.issuer
8688
assert invitation.guest == invitation_data.guest
8789
assert invitation.trial_account_days == invitation_data.trial_account_days
90+
assert invitation.extra_credits_in_usd == invitation_data.extra_credits_in_usd
8891

8992

9093
def test_check_valid_invitation(

services/invitations/tests/unit/conftest.py

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
from cryptography.fernet import Fernet
1111
from faker import Faker
1212
from models_library.products import ProductName
13+
from pydantic import PositiveInt, TypeAdapter
1314
from pytest_simcore.helpers.monkeypatch_envs import setenvs_from_dict
1415
from pytest_simcore.helpers.typing_env import EnvVarsDict
1516
from simcore_service_invitations.services.invitations import InvitationInputs
@@ -85,6 +86,11 @@ def is_trial_account(request: pytest.FixtureRequest) -> bool:
8586
return request.param
8687

8788

89+
@pytest.fixture
90+
def extra_credits_in_usd(is_trial_account: bool) -> PositiveInt | None:
91+
return TypeAdapter(PositiveInt).validate_python(123) if is_trial_account else None
92+
93+
8894
@pytest.fixture
8995
def default_product() -> ProductName:
9096
return "s4llite"
@@ -98,7 +104,10 @@ def product(request: pytest.FixtureRequest) -> ProductName | None:
98104

99105
@pytest.fixture
100106
def invitation_data(
101-
is_trial_account: bool, faker: Faker, product: ProductName | None
107+
is_trial_account: bool,
108+
faker: Faker,
109+
product: ProductName | None,
110+
extra_credits_in_usd: PositiveInt | None,
102111
) -> InvitationInputs:
103112
# first version
104113
kwargs = {
@@ -110,4 +119,7 @@ def invitation_data(
110119
if product:
111120
kwargs["product"] = product
112121

122+
if extra_credits_in_usd is not None:
123+
kwargs["extra_credits_in_usd"] = extra_credits_in_usd
124+
113125
return InvitationInputs.model_validate(kwargs)

services/invitations/tests/unit/test_cli.py

Lines changed: 31 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -45,19 +45,24 @@ def test_invite_user_and_check_invitation(
4545
"INVITATIONS_DEFAULT_PRODUCT": default_product,
4646
}
4747

48-
expected = {
48+
expected_invitation = {
4949
**invitation_data.model_dump(exclude={"product"}),
5050
"product": environs["INVITATIONS_DEFAULT_PRODUCT"],
5151
}
5252

5353
# invitations-maker invite [email protected] --issuer=me --trial-account-days=3
54-
trial_account = ""
54+
other_options = ""
5555
if invitation_data.trial_account_days:
56-
trial_account = f"--trial-account-days={invitation_data.trial_account_days}"
56+
other_options = f"--trial-account-days={invitation_data.trial_account_days}"
57+
58+
if invitation_data.extra_credits_in_usd:
59+
other_options += (
60+
f" --extra-credits-in-usd={invitation_data.extra_credits_in_usd}"
61+
)
5762

5863
result = cli_runner.invoke(
5964
main,
60-
f"invite {invitation_data.guest} --issuer={invitation_data.issuer} {trial_account}",
65+
f"invite {invitation_data.guest} --issuer={invitation_data.issuer} {other_options}",
6166
env=environs,
6267
)
6368
assert result.exit_code == os.EX_OK, result.output
@@ -73,7 +78,7 @@ def test_invite_user_and_check_invitation(
7378
)
7479
assert result.exit_code == os.EX_OK, result.output
7580
assert (
76-
expected
81+
expected_invitation
7782
== TypeAdapter(InvitationInputs).validate_json(result.stdout).model_dump()
7883
)
7984

@@ -99,3 +104,24 @@ def test_list_settings(cli_runner: CliRunner, app_environment: EnvVarsDict):
99104
print(result.output)
100105
settings = ApplicationSettings.model_validate_json(result.output)
101106
assert settings == ApplicationSettings.create_from_envs()
107+
108+
109+
def test_extract_invalid_invitation_code(
110+
cli_runner: CliRunner, faker: Faker, app_environment: EnvVarsDict
111+
):
112+
"""Test that extract command handles invalid invitation codes properly"""
113+
# Create an invalid invitation URL
114+
invalid_invitation_url = f"{faker.url()}#invitation=invalid_code_123"
115+
116+
# Run extract command with invalid invitation URL
117+
result = cli_runner.invoke(
118+
main,
119+
f'extract "{invalid_invitation_url}"',
120+
env=app_environment,
121+
)
122+
123+
# Verify command exits with correct error code
124+
assert result.exit_code == os.EX_DATAERR
125+
126+
# Verify error message is displayed via stderr
127+
assert "Invalid code" in result.stdout

services/invitations/tests/unit/test_core_settings.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,3 +42,5 @@ def test_valid_application_settings(app_environment: EnvVarsDict):
4242
assert settings
4343

4444
assert settings == ApplicationSettings.create_from_envs()
45+
46+
assert settings.LOG_LEVEL == "INFO"

services/web/server/src/simcore_service_webserver/wallets/_events.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919

2020
async def _auto_add_default_wallet(
2121
app: web.Application,
22+
*,
2223
user_id: UserID,
2324
product_name: ProductName,
2425
extra_credits_in_usd: PositiveInt | None = None,

0 commit comments

Comments
 (0)