Пример #1
0
def delete(user_email: str, session_id: bytes) -> None:
    """Delete the session from the database.

    Args:
        user_email: User's email in Cognito.
        session_id: The session id.

    Raises:
        `db.DatabaseError` if there was an error connecting to the database.

    """
    sess_hash = _hex_hash(session_id)
    pk = db.PartitionKey(ent.Session, sess_hash)
    sk_session = db.SortKey(ent.Session, sess_hash)
    sk_user = db.SortKey(ent.User, user_email)

    # We create a session entity in the database while creating a
    # SESSION-USER relation to make sure that there can be no duplicate
    # session ids in the database. Can not use conditions for this purpose,
    # as those require knowing the primary (composite) key which we don't
    # without querying the database.
    get_table().transact_write_items([
        db.DeleteArg(pk, sk_session),
        db.DeleteArg(pk, sk_user)
    ])
Пример #2
0
def create(user_email: str, session_id: bytes) -> None:
    """Store the session id in the database.

    Args:
        user_email: User's email in Cognito.
        session_id: New session id.

    Raises:
        `db.ConditionalCheckFailedError` if the session id already exists.
        `db.DatabasError` if there was an error connecting to the database.

    """
    attributes: SessionAttributes = {
        'ExpiresAt': _get_session_ttl()
    }

    sess_hash = _hex_hash(session_id)
    pk = db.PartitionKey(ent.Session, sess_hash)
    sk_session = db.SortKey(ent.Session, sess_hash)
    sk_user = db.SortKey(ent.User, user_email)

    # We create a session entity in the database while creating a
    # SESSION-USER relation to make sure that there can be no duplicate
    # session ids in the database. Can not use conditions for this purpose,
    # as those require knowing the primary (composite) key which we don't
    # without querying the database.
    get_table().transact_write_items([
        db.InsertArg(pk, sk_session, attributes=attributes),
        db.InsertArg(pk, sk_user, attributes=attributes)
    ])
Пример #3
0
def fetch(user_email: str, project_domain: str, consistent: bool = False) \
        -> Optional[SubAttributes]:
    """Fetch subscription attributes for a user.

    Args:
        user_email: User's email address that uniquely identifies them.
        project_domain: The project's domain name that uniquely identifies it.
        consistent: Whether the read should be strongly consistent.

    Returns:
        The subscription attributes if the subscription exists.

    Raises:
        `db.DatabaseError` if there was an error connecting to the Database.

    """
    pk = db.PartitionKey(ent.User, user_email)
    sk = db.SortKey(ent.Sub, project_domain)
    res = get_table().get(pk, sk,
                          consistent=consistent,
                          attributes=['IsActive'])
    if res is not None:
        return cast(SubAttributes, res)
    else:
        return None
Пример #4
0
def is_valid(user_email: str, project_domain: str) -> bool:
    """Verify whether a user has an active subscription to a project.

    Args:
        user_email: The user's email address.
        project_domain: The project's domain name.

    Returns:
        True if the user has an activate subscription to the project.

    """
    pk = db.PartitionKey(ent.User, user_email)
    sk_user = db.SortKey(ent.Sub, project_domain)
    sk_group = db.SortKey(ent.GroupSub, project_domain)

    pk_cond = cond.Key('PK').eq(str(pk))
    sk_cond = cond.Key('SK').eq(str(sk_user)) | cond.Key('SK').eq(str(sk_group))  # noqa 501
    key_cond = pk_cond & sk_cond

    query_arg = db.QueryArg(key_cond, attributes=['IsActive'])
    subs = get_table().query(query_arg)
    for s in subs:
        if s['IsActive']:
            return True
    else:
        return False
Пример #5
0
def fetch_all(user_email: str, consistent: bool = False) -> List[Subscription]:
    """Fetch all subscriptions for a user.

    Args:
        user_email: User's email address that uniquely identifies them.
        consistent: Whether the read should be strongly consistent.

    Returns:
        The user's subscriptions.

    Raises:
        `db.DatabaseError` if there was an error connecting to the Database.

    """
    # TODO (abiro) add group subs as well
    pk = db.PartitionKey(ent.User, user_email)
    sk = db.PrefixSortKey(ent.Sub)
    subs = get_table().query_prefix(pk, sk,
                                    consistent=consistent,
                                    attributes=['SK', 'IsActive'])
    res = []
    for s in subs:
        r: Subscription = {
            'ProjectDomain': s['SK'],
            'IsActive': s['IsActive']
        }
        res.append(r)
    return res
Пример #6
0
def fetch(group_name: str, project_domain: str, consistent: bool = False) \
        -> Optional[GroupSubAttributes]:
    """Fetch subscription attributes for a group.

    Args:
        group_name: The user's email address.
        project_domain: The project's domain name.
        consistent: Whether the read should be strongly consistent.


    Returns:
        The subscription attributes if the subscription exists.

    Raises:
        `db.DatabaseError` if there was an error connecting to the Database.

    """
    pk = db.PartitionKey(ent.Group, group_name)
    sk = db.SortKey(ent.GroupSub, project_domain)
    res = get_table().get(pk,
                          sk,
                          consistent=consistent,
                          attributes=['IsActive'])
    if res is not None:
        return cast(GroupSubAttributes, res)
    else:
        return None
Пример #7
0
def create(user_email: str, project_domain: str, trial_days: int) -> None:
    """Create a subscription to a project for a user.

    Args:
        user_email: User's email address that uniquely identifies them.
        project_domain: The project's domain name that uniquely identifies it.
        trial_days: The number of trial days for the project.

    Raises:
        `db.ConditionalCheckFailedError` if the subscription already exists.
        `db.DatabaseError` if there was an error connecting to the Database.

    """
    # TODO (abiro) Stripe logic
    user_op = _get_user_create_op(user_email, project_domain)
    trial_end_op = _get_trial_end_op(user_email, project_domain, trial_days)
    get_table().transact_write_items([
        user_op,
        trial_end_op
    ])
Пример #8
0
def delete(user_email: str, project_domain: str) -> None:
    """Delete a subscription for a user.

    The subscription item is not removed from the database, but it's `IsActive`
    attribute is set to false.

    Args:
        user_email: User's email address that uniquely identifies them.
        project_domain: The project's domain name that uniquely identifies it.

    Raises:
        `db.DatabaseError` if there was an error connecting to the Database.

    """
    # TODO (abiro) Stripe logic
    pk = db.PartitionKey(ent.User, user_email)
    sk = db.SortKey(ent.Sub, project_domain)
    attr: SubAttributes = {
        'IsActive': False
    }
    get_table().update_attributes(pk, sk, attr)
Пример #9
0
def recreate(user_email: str, project_domain: str) -> None:
    """Recreate a subscription to a project for a user that has lapsed.

    There is no trial in this case.

    Args:
        user_email: User's email address that uniquely identifies them.
        project_domain: The project's domain name that uniquely identifies it.

    Raises:
        `db.DatabaseError` if there was an error connecting to the Database.

    """
    # TODO (abiro) Stripe logic
    # TODO (abiro) Update instead of Put
    pk = db.PartitionKey(ent.User, user_email)
    sk = db.SortKey(ent.Sub, project_domain)
    attr: SubAttributes = {
        'IsActive': True
    }
    get_table().update_attributes(pk, sk, attr)
Пример #10
0
def create(group_name: str, project_domain: str, trial_days: int) -> None:
    """Create a group subscription.

    Args:
        group_name: The group's name that uniquely identifies it.
        project_domain: The project's domain name that uniquely identifies it.
        trial_days: The number of trial days for the project.

    Raises:
        `db.ConditionalCheckFailedError` if the subscription already exists.
        `db.DatabaseError` if there was an error connecting to the Database.

    """
    # TODO (abiro) Stripe logic
    # TODO (abiro) Publish group sub created event to propagate to members
    group_op = _get_group_create_op(group_name=group_name,
                                    project_domain=project_domain)
    trial_end_op = _get_trial_end_op(group_name=group_name,
                                     project_domain=project_domain,
                                     trial_days=trial_days)
    get_table().transact_write_items([group_op, trial_end_op])
Пример #11
0
def exists(project_domain: str) -> bool:
    """Check whether a project exists in the database.

    Args:
        project_domain: The project's domain name.

    Returns:
        True if the project exists.

    """
    pk = db.PartitionKey(ent.Project, project_domain)
    sk = db.SortKey(ent.Project, project_domain)
    res = get_table().get(pk, sk)
    return bool(res)
Пример #12
0
def is_owner(group_name: str, user_email: str) -> bool:
    """Check whether a user is an owner of a group.

    Args:
        group_name: The group's name that uniquely identifies it.
        user_email: The user's email address.

    Returns:
        True if the user is the owner of the group.

    """
    pk = db.PartitionKey(ent.Group, group_name)
    sk = db.SortKey(ent.Group, group_name)
    res = get_table().get(pk, sk, attributes=['OwnerEmail'])
    return res is not None and res['OwnerEmail'] == user_email
Пример #13
0
def fetch(project_domain: str) -> Optional[ProjectAttributes]:
    """Fetch project attributes based on domain name.

    Args:
        project_domain: The project's domain name.

    Returns:
        The project attributes if the project exists.

    """
    pk = db.PartitionKey(ent.Project, project_domain)
    sk = db.SortKey(ent.Project, project_domain)
    res = get_table().get(pk, sk, attributes=['TrialDays'])
    if res is not None:
        return cast(ProjectAttributes, res)
    else:
        return None
Пример #14
0
def fetch_user_email(session_id: bytes) -> Optional[str]:
    """Fetch the user email based on the session from the database.

    Args:
        session_id: The session id.

    Returns:
        The user's email.

    Raises:
        `db.DatabaseError` if there was an error connecting to the database.

    """
    sess_hash = _hex_hash(session_id)
    pk = db.PartitionKey(ent.Session, sess_hash)
    sk = db.PrefixSortKey(ent.User)
    res = get_table().query_prefix(pk, sk, attributes=['SK'])
    if res:
        return cast(str, res[0]['SK'])
    else:
        return None