Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

✨ Optional extra_credits in invitations #4850

Merged
merged 15 commits into from
Oct 11, 2023
Original file line number Diff line number Diff line change
Expand Up @@ -29,13 +29,15 @@ class Config(OutputSchema.Config):
class GenerateInvitation(InputSchema):
guest: LowerCaseEmailStr
trial_account_days: PositiveInt | None = None
extra_credits: PositiveInt | None = None


class InvitationGenerated(OutputSchema):
product_name: ProductName
issuer: LowerCaseEmailStr
guest: LowerCaseEmailStr
trial_account_days: PositiveInt | None = None
extra_credits: PositiveInt | None = None
created: datetime
invitation_link: HttpUrl

Expand All @@ -47,6 +49,15 @@ class Config(OutputSchema.Config):
"issuer": "[email protected]",
"guest": "[email protected]",
"trialAccountDays": 7,
"extraCredits": 30,
"created": "2023-09-27T15:30:00",
"invitationLink": "https://example.com/invitation#1234",
},
# w/o optional
{
"productName": "osparc",
"issuer": "[email protected]",
"guest": "[email protected]",
"created": "2023-09-27T15:30:00",
"invitationLink": "https://example.com/invitation#1234",
},
Expand Down
4 changes: 4 additions & 0 deletions packages/models-library/src/models_library/invitations.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,10 @@ class InvitationInputs(BaseModel):
description="If set, this invitation will activate a trial account."
"Sets the number of days from creation until the account expires",
)
extra_credits: PositiveInt | None = Field(
None,
description="If set, the account's primary wallet will add these extra credits",
)


class InvitationContent(InvitationInputs):
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -126,13 +126,15 @@ def __init__(
guest_email: str | None = None,
host: dict | None = None,
trial_days: int | None = None,
extra_credits: int | None = None,
):
assert client.app
super().__init__(params=host, app=client.app)
self.client = client
self.tag = f"Created by {guest_email or FAKE.email()}"
self.confirmation = None
self.trial_days = trial_days
self.extra_credits = extra_credits

async def __aenter__(self) -> "NewInvitation":
# creates host user
Expand All @@ -146,6 +148,7 @@ async def __aenter__(self) -> "NewInvitation":
user_email=self.user["email"],
tag=self.tag,
trial_days=self.trial_days,
extra_credits=self.extra_credits,
)
return self

Expand Down
2 changes: 1 addition & 1 deletion services/invitations/VERSION
Original file line number Diff line number Diff line change
@@ -1 +1 @@
1.0.2
1.1.0
23 changes: 22 additions & 1 deletion services/invitations/openapi.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
"info": {
"title": "simcore-service-invitations web API",
"description": " Service that manages creation and validation of registration invitations",
"version": "1.0.2"
"version": "1.1.0"
},
"paths": {
"/": {
Expand Down Expand Up @@ -188,6 +188,13 @@
"description": "If set, this invitation will activate a trial account.Sets the number of days from creation until the account expires",
"minimum": 0
},
"extra_credits": {
"title": "Extra Credits",
"exclusiveMinimum": true,
"type": "integer",
"description": "If set, the account's primary wallet will add these extra credits",
"minimum": 0
},
"created": {
"title": "Created",
"type": "string",
Expand Down Expand Up @@ -233,6 +240,13 @@
"description": "If set, this invitation will activate a trial account.Sets the number of days from creation until the account expires",
"minimum": 0
},
"extra_credits": {
"title": "Extra Credits",
"exclusiveMinimum": true,
"type": "integer",
"description": "If set, the account's primary wallet will add these extra credits",
"minimum": 0
},
"created": {
"title": "Created",
"type": "string",
Expand Down Expand Up @@ -284,6 +298,13 @@
"type": "integer",
"description": "If set, this invitation will activate a trial account.Sets the number of days from creation until the account expires",
"minimum": 0
},
"extra_credits": {
"title": "Extra Credits",
"exclusiveMinimum": true,
"type": "integer",
"description": "If set, the account's primary wallet will add these extra credits",
"minimum": 0
}
},
"description": "Input data necessary to create an invitation",
Expand Down
2 changes: 1 addition & 1 deletion services/invitations/setup.cfg
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
[bumpversion]
current_version = 1.0.2
current_version = 1.1.0
commit = True
message = services/invitations version: {current_version} → {new_version}
tag = False
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,9 @@ class Config:
"trial_account_days": {
"alias": "t",
},
"extra_credits": {
"alias": "e",
},
"created": {
"alias": "c",
},
Expand Down
2 changes: 1 addition & 1 deletion services/web/server/VERSION
Original file line number Diff line number Diff line change
@@ -1 +1 @@
0.32.0
0.33.0
2 changes: 1 addition & 1 deletion services/web/server/setup.cfg
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
[bumpversion]
current_version = 0.32.0
current_version = 0.33.0
commit = True
message = services/webserver api version: {current_version} → {new_version}
tag = False
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ info:
title: simcore-service-webserver
description: ' Main service with an interface (http-API & websockets) to the web
front-end'
version: 0.32.0
version: 0.33.0
servers:
- url: ''
description: webserver
Expand Down Expand Up @@ -6272,6 +6272,11 @@ components:
exclusiveMinimum: true
type: integer
minimum: 0
extraCredits:
title: Extracredits
exclusiveMinimum: true
type: integer
minimum: 0
GetWalletAutoRecharge:
title: GetWalletAutoRecharge
required:
Expand Down Expand Up @@ -6468,6 +6473,11 @@ components:
exclusiveMinimum: true
type: integer
minimum: 0
extraCredits:
title: Extracredits
exclusiveMinimum: true
type: integer
minimum: 0
created:
title: Created
type: string
Expand Down Expand Up @@ -7472,7 +7482,7 @@ components:
required:
- pricingUnitId
- unitName
- unitAttributes
- unitExtraInfo
- currentCostPerUnit
- default
type: object
Expand All @@ -7485,8 +7495,8 @@ components:
unitName:
title: Unitname
type: string
unitAttributes:
title: Unitattributes
unitExtraInfo:
title: Unitextrainfo
type: object
currentCostPerUnit:
title: Currentcostperunit
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,10 @@ def create_application() -> web.Application:
setup_products(app)
setup_statics(app)

# users
setup_users(app)
setup_groups(app)

# resource tracking / billing
setup_resource_tracker(app)
setup_payments(app)
Expand All @@ -119,10 +123,6 @@ def create_application() -> web.Application:
setup_resource_manager(app)
setup_garbage_collector(app)

# users
setup_users(app)
setup_groups(app)

# projects
setup_projects(app)
# project add-ons
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@
from .storage import AsyncpgStorage, BaseConfirmationTokenDict, ConfirmationTokenDict
from .utils import CONFIRMATION_PENDING

log = logging.getLogger(__name__)
_logger = logging.getLogger(__name__)


class ConfirmationTokenInfoDict(ConfirmationTokenDict):
Expand All @@ -50,6 +50,7 @@ class InvitationData(BaseModel):
description="If set, this invitation will activate a trial account."
"Sets the number of days from creation until the account expires",
)
extra_credits: PositiveInt | None = None


class _InvitationValidator(BaseModel):
Expand Down Expand Up @@ -100,7 +101,7 @@ async def check_other_registrations(
user=user, confirmation=_confirmation
)

log.warning(
_logger.warning(
"Re-registration of %s with expired %s"
"Deleting user and proceeding to a new registration",
f"{user=}",
Expand All @@ -120,6 +121,7 @@ async def create_invitation_token(
user_email: LowerCaseEmailStr | None = None,
tag: str | None = None,
trial_days: PositiveInt | None = None,
extra_credits: PositiveInt | None = None,
) -> ConfirmationTokenDict:
"""Creates an invitation token for a guest to register in the platform and returns

Expand All @@ -130,12 +132,11 @@ async def create_invitation_token(
:type host: Dict-like
:param guest: some description of the guest, e.g. email, name or a json
"""
data_model = InvitationData.parse_obj(
{
"issuer": user_email,
"guest": tag,
"trial_account_days": trial_days,
}
data_model = InvitationData(
issuer=user_email,
guest=tag,
trial_account_days=trial_days,
extra_credits=extra_credits,
)
return await db.create_confirmation(
user_id=user_id,
Expand Down Expand Up @@ -191,7 +192,7 @@ async def check_and_consume_invitation(
guest_email: str,
db: AsyncpgStorage,
cfg: LoginOptions,
app=web.Application,
pcrespov marked this conversation as resolved.
Show resolved Hide resolved
app: web.Application,
) -> InvitationData:
"""Consumes invitation: the code is validated, the invitation retrieives and then deleted
since it only has one use
Expand All @@ -210,15 +211,17 @@ async def check_and_consume_invitation(
invitation_url=f"{url}",
)

log.info("Consuming invitation from service:\n%s", content.json(indent=1))
_logger.info(
"Consuming invitation from service:\n%s", content.json(indent=1)
)
return InvitationData(
issuer=content.issuer,
guest=content.guest,
trial_account_days=content.trial_account_days,
extra_credits=content.extra_credits,
)

# database-type invitations

if confirmation_token := await validate_confirmation_code(invitation_code, db, cfg):
try:
invitation_data: InvitationData = _InvitationValidator.parse_obj(
Expand All @@ -227,7 +230,7 @@ async def check_and_consume_invitation(
return invitation_data

except ValidationError as err:
log.warning(
_logger.warning(
"%s is associated with an invalid %s.\nDetails: %s",
f"{invitation_code=}",
f"{confirmation_token=}",
Expand All @@ -236,7 +239,7 @@ async def check_and_consume_invitation(

finally:
await db.delete_confirmation(confirmation_token)
log.info("Invitation with %s was consumed", f"{confirmation_token=}")
_logger.info("Invitation with %s was consumed", f"{confirmation_token=}")

raise web.HTTPForbidden(
reason=(
Expand Down
Loading