Skip to content

Create User workflow

Exercise 1: create User workflow

The create User workflow is very similar to the create UserGroup workflow, the major difference is the increased number of user inputs needed to initialize the subscription. This workflow uses the following steps:

init
>> create_subscription
>> store_process_subscription(Target.CREATE)
>> initialize_subscription
>> provision_user
>> set_status(SubscriptionLifecycle.ACTIVE)
>> resync
>> done

There is one important difference though, one of the user inputs on the input form is special: the selection of the user group the user belongs to. It is not just an integer or a string, but the user must be able to select a user group out of a list of already provisioned user groups. For this the database will be queried to obtain a list of active user group subscriptions, and a special input field type is used to display a dropdown input field on the input form.

In the orchestrator, all access to the database is implemented using SQLAlchemy, and queries can be formulated using the classes from orchestrator.db.models that map to the tables in the database. The following query is all that is needed to get a list of active UserGroup subscriptions:

from orchestrator.db import db
from orchestrator.db.models import ProductTable, SubscriptionTable
from sqlalchemy import select

...

stmt = (
    select(SubscriptionTable)
    .join(ProductTable)
    .filter(ProductTable.product_type == "UserGroup", SubscriptionTable.status == "active")
    .with_only_columns(SubscriptionTable.subscription_id, SubscriptionTable.description)
)

subscriptions = db.session.scalars(stmt)

...

The orchestrator.forms.validators package provides a standard input component called choice_list that will create the indicated enumeration and expects an iterator that returns tuples containing a label and a value. The iterator is created making use of the standard Python zip function. This input component will show a dropdown with all labels and returns a list of associated chosen keys. The amount of entries that may be chosen is controlled by the min_items and max_items arguments.

Putting everything together, the user group selector looks like this:

from orchestrator.db import db
from orchestrator.db.models import ProductTable, SubscriptionTable
from sqlalchemy import select

def user_group_selector() -> list:
    user_group_subscriptions = {}
    stmt = (
        select(SubscriptionTable).join(ProductTable)
        .filter(ProductTable.product_type == "Port", SubscriptionTable.status == "active")
        .with_only_columns(SubscriptionTable.subscription_id, SubscriptionTable.description)
    )

    for user_group_id, user_group_description in db.session.execute(stmt).all():
        user_group_subscriptions[str(user_group_id)] = user_group_description

    return choice_list(
        Choice("UserGroupEnum", zip(user_group_subscriptions.keys(), user_group_subscriptions.items())),
        min_items=1,
        max_items=1,
    )

And can now be used in the input form as follows:

user_group_ids: user_group_selector()

In the subscription initialization step the group resource type of the UserBlock product block is assigned with the the UserGroupBlock from the UserGroup subscription:

subscription.user.group = UserGroup.from_subscription(user_group_ids[0]).user_group

Use the skeleton below to create the file workflows/user/create_user.py:

from typing import List, Optional
from uuid import uuid4

from orchestrator.db.models import ProductTable, SubscriptionTable
from orchestrator.forms import FormPage
from orchestrator.forms.validators import Choice, choice_list
from orchestrator.targets import Target
from orchestrator.types import FormGenerator, State, SubscriptionLifecycle, UUIDstr
from orchestrator.workflow import done, init, step, workflow
from orchestrator.workflows.steps import resync, set_status, store_process_subscription
from orchestrator.workflows.utils import wrap_create_initial_input_form

from products.product_types.user import UserInactive, UserProvisioning
from products.product_types.user_group import UserGroup

# user group selector
...

# initial input form generator
...

# create subscription step
...

# initialize subscription step
...

# provision user step
...

# create user workflow
...

Spoiler: for inspiration look at an example implementation of the user create workflow