from aws_lambda_powertools.event_handler.exceptions import ( BadRequestError, ) from botocore.exceptions import ClientError from layercake.dateutils import now from layercake.dynamodb import ( ComposeKey, DynamoDBPersistenceLayer, KeyPair, TransactItems, ) def add_email( id: str, email: str, /, *, persistence_layer: DynamoDBPersistenceLayer, ): now_ = now() transact = TransactItems(persistence_layer.table_name) transact.update( key=KeyPair(id, '0'), update_expr='ADD emails :email', expr_attr_values={ ':email': {email}, }, ) transact.put( item={ 'id': id, 'sk': f'emails#{email}', 'email_primary': False, 'email_verified': False, 'create_date': now_, }, cond_expr='attribute_not_exists(sk)', ) transact.put( item={ 'id': 'email', 'sk': email, 'user_id': id, 'create_date': now_, }, cond_expr='attribute_not_exists(sk)', ) try: return persistence_layer.transact_write_items(transact) except ClientError: raise BadRequestError('Email already exists.') def del_email( id: str, email: str, /, *, persistence_layer: DynamoDBPersistenceLayer, ) -> bool: """Delete any email except the primary email.""" transact = TransactItems(persistence_layer.table_name) transact.delete( key=KeyPair('email', email), ) transact.delete( key=KeyPair(id, ComposeKey(email, prefix='emails')), cond_expr='email_primary <> :primary', expr_attr_values={':primary': True}, ) transact.update( key=KeyPair(id, '0'), update_expr='DELETE emails :email', expr_attr_values={ ':email': {email}, }, ) try: return persistence_layer.transact_write_items(transact) except ClientError: raise BadRequestError('Cannot remove the primary email.') def set_email_as_primary( id: str, new_email: str, old_email: str, /, *, email_verified: bool = False, persistence_layer: DynamoDBPersistenceLayer, ): now_ = now() expr = 'SET email_primary = :email_primary, update_date = :update_date' transact = TransactItems(persistence_layer.table_name) # Set the old email as non-primary transact.update( key=KeyPair(id, ComposeKey(old_email, 'emails')), update_expr=expr, expr_attr_values={ ':email_primary': False, ':update_date': now_, }, ) # Set the new email as primary transact.update( key=KeyPair(id, ComposeKey(new_email, 'emails')), update_expr=expr, expr_attr_values={ ':email_primary': True, ':update_date': now_, }, ) transact.update( key=KeyPair(id, '0'), update_expr=( 'SET email = :email, email_verified = :email_verified, ' 'update_date = :update_date' ), expr_attr_values={ ':email': new_email, ':email_verified': email_verified, ':update_date': now_, }, ) return persistence_layer.transact_write_items(transact) def del_org_member( id: str, *, org_id: str, persistence_layer: DynamoDBPersistenceLayer, ) -> bool: transact = TransactItems(persistence_layer.table_name) # Remove the user's relationship with the organization and their privileges transact.delete(key=KeyPair(id, f'acls#{org_id}')) transact.delete(key=KeyPair(id, f'orgs#{org_id}')) transact.update( key=KeyPair(id, '0'), update_expr='DELETE #tenant :org_id', expr_attr_names={'#tenant': 'tenant__org_id'}, expr_attr_values={':org_id': {org_id}}, ) # Remove the user from the organization's admins and members list transact.delete(key=KeyPair(org_id, f'admins#{id}')) transact.delete(key=KeyPair(f'orgmembers#{org_id}', id)) return persistence_layer.transact_write_items(transact)