Module supertokens_python.recipe.accountlinking.interfaces
Expand source code
# Copyright (c) 2024, VRAI Labs and/or its affiliates. All rights reserved.
#
# This software is licensed under the Apache License, Version 2.0 (the
# "License") as published by the Apache Software Foundation.
#
# You may not use this file except in compliance with the License. You may
# obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
from __future__ import annotations
from abc import ABC, abstractmethod
from typing import TYPE_CHECKING, Any, Dict, List, Union, Optional
from typing_extensions import Literal
if TYPE_CHECKING:
from supertokens_python.types import (
User,
RecipeUserId,
AccountInfo,
)
class RecipeInterface(ABC):
@abstractmethod
async def get_users(
self,
tenant_id: str,
time_joined_order: Literal["ASC", "DESC"],
limit: Optional[int],
pagination_token: Optional[str],
include_recipe_ids: Optional[List[str]],
query: Optional[Dict[str, str]],
user_context: Dict[str, Any],
) -> GetUsersResult:
pass
@abstractmethod
async def can_create_primary_user(
self, recipe_user_id: RecipeUserId, user_context: Dict[str, Any]
) -> Union[
CanCreatePrimaryUserOkResult,
CanCreatePrimaryUserRecipeUserIdAlreadyLinkedError,
CanCreatePrimaryUserAccountInfoAlreadyAssociatedError,
]:
pass
@abstractmethod
async def create_primary_user(
self, recipe_user_id: RecipeUserId, user_context: Dict[str, Any]
) -> Union[
CreatePrimaryUserOkResult,
CreatePrimaryUserRecipeUserIdAlreadyLinkedError,
CreatePrimaryUserAccountInfoAlreadyAssociatedError,
]:
pass
@abstractmethod
async def can_link_accounts(
self,
recipe_user_id: RecipeUserId,
primary_user_id: str,
user_context: Dict[str, Any],
) -> Union[
CanLinkAccountsOkResult,
CanLinkAccountsRecipeUserIdAlreadyLinkedError,
CanLinkAccountsAccountInfoAlreadyAssociatedError,
CanLinkAccountsInputUserNotPrimaryError,
]:
pass
@abstractmethod
async def link_accounts(
self,
recipe_user_id: RecipeUserId,
primary_user_id: str,
user_context: Dict[str, Any],
) -> Union[
LinkAccountsOkResult,
LinkAccountsRecipeUserIdAlreadyLinkedError,
LinkAccountsAccountInfoAlreadyAssociatedError,
LinkAccountsInputUserNotPrimaryError,
]:
pass
@abstractmethod
async def unlink_account(
self, recipe_user_id: RecipeUserId, user_context: Dict[str, Any]
) -> UnlinkAccountOkResult:
pass
@abstractmethod
async def get_user(
self, user_id: str, user_context: Dict[str, Any]
) -> Optional[User]:
pass
@abstractmethod
async def list_users_by_account_info(
self,
tenant_id: str,
account_info: AccountInfo,
do_union_of_account_info: bool,
user_context: Dict[str, Any],
) -> List[User]:
pass
@abstractmethod
async def delete_user(
self,
user_id: str,
remove_all_linked_accounts: bool,
user_context: Dict[str, Any],
) -> None:
pass
class GetUsersResult:
def __init__(self, users: List[User], next_pagination_token: Optional[str]):
self.users = users
self.next_pagination_token = next_pagination_token
class CanCreatePrimaryUserOkResult:
def __init__(self, was_already_a_primary_user: bool):
self.status: Literal["OK"] = "OK"
self.was_already_a_primary_user = was_already_a_primary_user
class CanCreatePrimaryUserRecipeUserIdAlreadyLinkedError:
def __init__(self, primary_user_id: str, description: str):
self.status: Literal[
"RECIPE_USER_ID_ALREADY_LINKED_WITH_PRIMARY_USER_ID_ERROR"
] = "RECIPE_USER_ID_ALREADY_LINKED_WITH_PRIMARY_USER_ID_ERROR"
self.primary_user_id = primary_user_id
self.description = description
class CanCreatePrimaryUserAccountInfoAlreadyAssociatedError:
def __init__(self, primary_user_id: str, description: str):
self.status: Literal[
"ACCOUNT_INFO_ALREADY_ASSOCIATED_WITH_ANOTHER_PRIMARY_USER_ID_ERROR"
] = "ACCOUNT_INFO_ALREADY_ASSOCIATED_WITH_ANOTHER_PRIMARY_USER_ID_ERROR"
self.primary_user_id = primary_user_id
self.description = description
class CreatePrimaryUserOkResult:
def __init__(self, user: User, was_already_a_primary_user: bool):
self.status: Literal["OK"] = "OK"
self.user = user
self.was_already_a_primary_user = was_already_a_primary_user
def to_json(self) -> Dict[str, Any]:
return {
"status": self.status,
"user": self.user.to_json(),
"wasAlreadyAPrimaryUser": self.was_already_a_primary_user,
}
class CreatePrimaryUserRecipeUserIdAlreadyLinkedError:
def __init__(self, primary_user_id: str, description: Optional[str] = None):
self.status: Literal[
"RECIPE_USER_ID_ALREADY_LINKED_WITH_PRIMARY_USER_ID_ERROR"
] = "RECIPE_USER_ID_ALREADY_LINKED_WITH_PRIMARY_USER_ID_ERROR"
self.primary_user_id = primary_user_id
self.description = description
class CreatePrimaryUserAccountInfoAlreadyAssociatedError:
def __init__(self, primary_user_id: str, description: Optional[str] = None):
self.status: Literal[
"ACCOUNT_INFO_ALREADY_ASSOCIATED_WITH_ANOTHER_PRIMARY_USER_ID_ERROR"
] = "ACCOUNT_INFO_ALREADY_ASSOCIATED_WITH_ANOTHER_PRIMARY_USER_ID_ERROR"
self.primary_user_id = primary_user_id
self.description = description
class CanLinkAccountsOkResult:
def __init__(self, accounts_already_linked: bool):
self.status: Literal["OK"] = "OK"
self.accounts_already_linked = accounts_already_linked
class CanLinkAccountsRecipeUserIdAlreadyLinkedError:
def __init__(
self, primary_user_id: Optional[str] = None, description: Optional[str] = None
):
self.status: Literal[
"RECIPE_USER_ID_ALREADY_LINKED_WITH_ANOTHER_PRIMARY_USER_ID_ERROR"
] = "RECIPE_USER_ID_ALREADY_LINKED_WITH_ANOTHER_PRIMARY_USER_ID_ERROR"
self.primary_user_id = primary_user_id
self.description = description
class CanLinkAccountsAccountInfoAlreadyAssociatedError:
def __init__(
self, primary_user_id: Optional[str] = None, description: Optional[str] = None
):
self.status: Literal[
"ACCOUNT_INFO_ALREADY_ASSOCIATED_WITH_ANOTHER_PRIMARY_USER_ID_ERROR"
] = "ACCOUNT_INFO_ALREADY_ASSOCIATED_WITH_ANOTHER_PRIMARY_USER_ID_ERROR"
self.primary_user_id = primary_user_id
self.description = description
class CanLinkAccountsInputUserNotPrimaryError:
def __init__(self, description: Optional[str] = None):
self.status: Literal[
"INPUT_USER_IS_NOT_A_PRIMARY_USER"
] = "INPUT_USER_IS_NOT_A_PRIMARY_USER"
self.description = description
class LinkAccountsOkResult:
def __init__(self, accounts_already_linked: bool, user: User):
self.status: Literal["OK"] = "OK"
self.accounts_already_linked = accounts_already_linked
self.user = user
def to_json(self) -> Dict[str, Any]:
return {
"status": self.status,
"accountsAlreadyLinked": self.accounts_already_linked,
"user": self.user.to_json(),
}
class LinkAccountsRecipeUserIdAlreadyLinkedError:
def __init__(
self,
primary_user_id: str,
user: User,
description: str,
):
self.status: Literal[
"RECIPE_USER_ID_ALREADY_LINKED_WITH_ANOTHER_PRIMARY_USER_ID_ERROR"
] = "RECIPE_USER_ID_ALREADY_LINKED_WITH_ANOTHER_PRIMARY_USER_ID_ERROR"
self.primary_user_id = primary_user_id
self.user = user
self.description = description
class LinkAccountsAccountInfoAlreadyAssociatedError:
def __init__(
self,
primary_user_id: Optional[str] = None,
description: Optional[str] = None,
):
self.status: Literal[
"ACCOUNT_INFO_ALREADY_ASSOCIATED_WITH_ANOTHER_PRIMARY_USER_ID_ERROR"
] = "ACCOUNT_INFO_ALREADY_ASSOCIATED_WITH_ANOTHER_PRIMARY_USER_ID_ERROR"
self.primary_user_id = primary_user_id
self.description = description
class LinkAccountsInputUserNotPrimaryError:
def __init__(self):
self.status: Literal[
"INPUT_USER_IS_NOT_A_PRIMARY_USER"
] = "INPUT_USER_IS_NOT_A_PRIMARY_USER"
class UnlinkAccountOkResult:
def __init__(self, was_recipe_user_deleted: bool, was_linked: bool):
self.status: Literal["OK"] = "OK"
self.was_recipe_user_deleted = was_recipe_user_deleted
self.was_linked = was_linked
Classes
class CanCreatePrimaryUserAccountInfoAlreadyAssociatedError (primary_user_id: str, description: str)
-
Expand source code
class CanCreatePrimaryUserAccountInfoAlreadyAssociatedError: def __init__(self, primary_user_id: str, description: str): self.status: Literal[ "ACCOUNT_INFO_ALREADY_ASSOCIATED_WITH_ANOTHER_PRIMARY_USER_ID_ERROR" ] = "ACCOUNT_INFO_ALREADY_ASSOCIATED_WITH_ANOTHER_PRIMARY_USER_ID_ERROR" self.primary_user_id = primary_user_id self.description = description
class CanCreatePrimaryUserOkResult (was_already_a_primary_user: bool)
-
Expand source code
class CanCreatePrimaryUserOkResult: def __init__(self, was_already_a_primary_user: bool): self.status: Literal["OK"] = "OK" self.was_already_a_primary_user = was_already_a_primary_user
class CanCreatePrimaryUserRecipeUserIdAlreadyLinkedError (primary_user_id: str, description: str)
-
Expand source code
class CanCreatePrimaryUserRecipeUserIdAlreadyLinkedError: def __init__(self, primary_user_id: str, description: str): self.status: Literal[ "RECIPE_USER_ID_ALREADY_LINKED_WITH_PRIMARY_USER_ID_ERROR" ] = "RECIPE_USER_ID_ALREADY_LINKED_WITH_PRIMARY_USER_ID_ERROR" self.primary_user_id = primary_user_id self.description = description
class CanLinkAccountsAccountInfoAlreadyAssociatedError (primary_user_id: Optional[str] = None, description: Optional[str] = None)
-
Expand source code
class CanLinkAccountsAccountInfoAlreadyAssociatedError: def __init__( self, primary_user_id: Optional[str] = None, description: Optional[str] = None ): self.status: Literal[ "ACCOUNT_INFO_ALREADY_ASSOCIATED_WITH_ANOTHER_PRIMARY_USER_ID_ERROR" ] = "ACCOUNT_INFO_ALREADY_ASSOCIATED_WITH_ANOTHER_PRIMARY_USER_ID_ERROR" self.primary_user_id = primary_user_id self.description = description
class CanLinkAccountsInputUserNotPrimaryError (description: Optional[str] = None)
-
Expand source code
class CanLinkAccountsInputUserNotPrimaryError: def __init__(self, description: Optional[str] = None): self.status: Literal[ "INPUT_USER_IS_NOT_A_PRIMARY_USER" ] = "INPUT_USER_IS_NOT_A_PRIMARY_USER" self.description = description
class CanLinkAccountsOkResult (accounts_already_linked: bool)
-
Expand source code
class CanLinkAccountsOkResult: def __init__(self, accounts_already_linked: bool): self.status: Literal["OK"] = "OK" self.accounts_already_linked = accounts_already_linked
class CanLinkAccountsRecipeUserIdAlreadyLinkedError (primary_user_id: Optional[str] = None, description: Optional[str] = None)
-
Expand source code
class CanLinkAccountsRecipeUserIdAlreadyLinkedError: def __init__( self, primary_user_id: Optional[str] = None, description: Optional[str] = None ): self.status: Literal[ "RECIPE_USER_ID_ALREADY_LINKED_WITH_ANOTHER_PRIMARY_USER_ID_ERROR" ] = "RECIPE_USER_ID_ALREADY_LINKED_WITH_ANOTHER_PRIMARY_USER_ID_ERROR" self.primary_user_id = primary_user_id self.description = description
class CreatePrimaryUserAccountInfoAlreadyAssociatedError (primary_user_id: str, description: Optional[str] = None)
-
Expand source code
class CreatePrimaryUserAccountInfoAlreadyAssociatedError: def __init__(self, primary_user_id: str, description: Optional[str] = None): self.status: Literal[ "ACCOUNT_INFO_ALREADY_ASSOCIATED_WITH_ANOTHER_PRIMARY_USER_ID_ERROR" ] = "ACCOUNT_INFO_ALREADY_ASSOCIATED_WITH_ANOTHER_PRIMARY_USER_ID_ERROR" self.primary_user_id = primary_user_id self.description = description
class CreatePrimaryUserOkResult (user: User, was_already_a_primary_user: bool)
-
Expand source code
class CreatePrimaryUserOkResult: def __init__(self, user: User, was_already_a_primary_user: bool): self.status: Literal["OK"] = "OK" self.user = user self.was_already_a_primary_user = was_already_a_primary_user def to_json(self) -> Dict[str, Any]: return { "status": self.status, "user": self.user.to_json(), "wasAlreadyAPrimaryUser": self.was_already_a_primary_user, }
Methods
def to_json(self) ‑> Dict[str, Any]
-
Expand source code
def to_json(self) -> Dict[str, Any]: return { "status": self.status, "user": self.user.to_json(), "wasAlreadyAPrimaryUser": self.was_already_a_primary_user, }
class CreatePrimaryUserRecipeUserIdAlreadyLinkedError (primary_user_id: str, description: Optional[str] = None)
-
Expand source code
class CreatePrimaryUserRecipeUserIdAlreadyLinkedError: def __init__(self, primary_user_id: str, description: Optional[str] = None): self.status: Literal[ "RECIPE_USER_ID_ALREADY_LINKED_WITH_PRIMARY_USER_ID_ERROR" ] = "RECIPE_USER_ID_ALREADY_LINKED_WITH_PRIMARY_USER_ID_ERROR" self.primary_user_id = primary_user_id self.description = description
class GetUsersResult (users: List[User], next_pagination_token: Optional[str])
-
Expand source code
class GetUsersResult: def __init__(self, users: List[User], next_pagination_token: Optional[str]): self.users = users self.next_pagination_token = next_pagination_token
class LinkAccountsAccountInfoAlreadyAssociatedError (primary_user_id: Optional[str] = None, description: Optional[str] = None)
-
Expand source code
class LinkAccountsAccountInfoAlreadyAssociatedError: def __init__( self, primary_user_id: Optional[str] = None, description: Optional[str] = None, ): self.status: Literal[ "ACCOUNT_INFO_ALREADY_ASSOCIATED_WITH_ANOTHER_PRIMARY_USER_ID_ERROR" ] = "ACCOUNT_INFO_ALREADY_ASSOCIATED_WITH_ANOTHER_PRIMARY_USER_ID_ERROR" self.primary_user_id = primary_user_id self.description = description
class LinkAccountsInputUserNotPrimaryError
-
Expand source code
class LinkAccountsInputUserNotPrimaryError: def __init__(self): self.status: Literal[ "INPUT_USER_IS_NOT_A_PRIMARY_USER" ] = "INPUT_USER_IS_NOT_A_PRIMARY_USER"
class LinkAccountsOkResult (accounts_already_linked: bool, user: User)
-
Expand source code
class LinkAccountsOkResult: def __init__(self, accounts_already_linked: bool, user: User): self.status: Literal["OK"] = "OK" self.accounts_already_linked = accounts_already_linked self.user = user def to_json(self) -> Dict[str, Any]: return { "status": self.status, "accountsAlreadyLinked": self.accounts_already_linked, "user": self.user.to_json(), }
Methods
def to_json(self) ‑> Dict[str, Any]
-
Expand source code
def to_json(self) -> Dict[str, Any]: return { "status": self.status, "accountsAlreadyLinked": self.accounts_already_linked, "user": self.user.to_json(), }
class LinkAccountsRecipeUserIdAlreadyLinkedError (primary_user_id: str, user: User, description: str)
-
Expand source code
class LinkAccountsRecipeUserIdAlreadyLinkedError: def __init__( self, primary_user_id: str, user: User, description: str, ): self.status: Literal[ "RECIPE_USER_ID_ALREADY_LINKED_WITH_ANOTHER_PRIMARY_USER_ID_ERROR" ] = "RECIPE_USER_ID_ALREADY_LINKED_WITH_ANOTHER_PRIMARY_USER_ID_ERROR" self.primary_user_id = primary_user_id self.user = user self.description = description
class RecipeInterface
-
Helper class that provides a standard way to create an ABC using inheritance.
Expand source code
class RecipeInterface(ABC): @abstractmethod async def get_users( self, tenant_id: str, time_joined_order: Literal["ASC", "DESC"], limit: Optional[int], pagination_token: Optional[str], include_recipe_ids: Optional[List[str]], query: Optional[Dict[str, str]], user_context: Dict[str, Any], ) -> GetUsersResult: pass @abstractmethod async def can_create_primary_user( self, recipe_user_id: RecipeUserId, user_context: Dict[str, Any] ) -> Union[ CanCreatePrimaryUserOkResult, CanCreatePrimaryUserRecipeUserIdAlreadyLinkedError, CanCreatePrimaryUserAccountInfoAlreadyAssociatedError, ]: pass @abstractmethod async def create_primary_user( self, recipe_user_id: RecipeUserId, user_context: Dict[str, Any] ) -> Union[ CreatePrimaryUserOkResult, CreatePrimaryUserRecipeUserIdAlreadyLinkedError, CreatePrimaryUserAccountInfoAlreadyAssociatedError, ]: pass @abstractmethod async def can_link_accounts( self, recipe_user_id: RecipeUserId, primary_user_id: str, user_context: Dict[str, Any], ) -> Union[ CanLinkAccountsOkResult, CanLinkAccountsRecipeUserIdAlreadyLinkedError, CanLinkAccountsAccountInfoAlreadyAssociatedError, CanLinkAccountsInputUserNotPrimaryError, ]: pass @abstractmethod async def link_accounts( self, recipe_user_id: RecipeUserId, primary_user_id: str, user_context: Dict[str, Any], ) -> Union[ LinkAccountsOkResult, LinkAccountsRecipeUserIdAlreadyLinkedError, LinkAccountsAccountInfoAlreadyAssociatedError, LinkAccountsInputUserNotPrimaryError, ]: pass @abstractmethod async def unlink_account( self, recipe_user_id: RecipeUserId, user_context: Dict[str, Any] ) -> UnlinkAccountOkResult: pass @abstractmethod async def get_user( self, user_id: str, user_context: Dict[str, Any] ) -> Optional[User]: pass @abstractmethod async def list_users_by_account_info( self, tenant_id: str, account_info: AccountInfo, do_union_of_account_info: bool, user_context: Dict[str, Any], ) -> List[User]: pass @abstractmethod async def delete_user( self, user_id: str, remove_all_linked_accounts: bool, user_context: Dict[str, Any], ) -> None: pass
Ancestors
- abc.ABC
Subclasses
Methods
async def can_create_primary_user(self, recipe_user_id: RecipeUserId, user_context: Dict[str, Any]) ‑> Union[CanCreatePrimaryUserOkResult, CanCreatePrimaryUserRecipeUserIdAlreadyLinkedError, CanCreatePrimaryUserAccountInfoAlreadyAssociatedError]
-
Expand source code
@abstractmethod async def can_create_primary_user( self, recipe_user_id: RecipeUserId, user_context: Dict[str, Any] ) -> Union[ CanCreatePrimaryUserOkResult, CanCreatePrimaryUserRecipeUserIdAlreadyLinkedError, CanCreatePrimaryUserAccountInfoAlreadyAssociatedError, ]: pass
async def can_link_accounts(self, recipe_user_id: RecipeUserId, primary_user_id: str, user_context: Dict[str, Any]) ‑> Union[CanLinkAccountsOkResult, CanLinkAccountsRecipeUserIdAlreadyLinkedError, CanLinkAccountsAccountInfoAlreadyAssociatedError, CanLinkAccountsInputUserNotPrimaryError]
-
Expand source code
@abstractmethod async def can_link_accounts( self, recipe_user_id: RecipeUserId, primary_user_id: str, user_context: Dict[str, Any], ) -> Union[ CanLinkAccountsOkResult, CanLinkAccountsRecipeUserIdAlreadyLinkedError, CanLinkAccountsAccountInfoAlreadyAssociatedError, CanLinkAccountsInputUserNotPrimaryError, ]: pass
async def create_primary_user(self, recipe_user_id: RecipeUserId, user_context: Dict[str, Any]) ‑> Union[CreatePrimaryUserOkResult, CreatePrimaryUserRecipeUserIdAlreadyLinkedError, CreatePrimaryUserAccountInfoAlreadyAssociatedError]
-
Expand source code
@abstractmethod async def create_primary_user( self, recipe_user_id: RecipeUserId, user_context: Dict[str, Any] ) -> Union[ CreatePrimaryUserOkResult, CreatePrimaryUserRecipeUserIdAlreadyLinkedError, CreatePrimaryUserAccountInfoAlreadyAssociatedError, ]: pass
async def delete_user(self, user_id: str, remove_all_linked_accounts: bool, user_context: Dict[str, Any]) ‑> None
-
Expand source code
@abstractmethod async def delete_user( self, user_id: str, remove_all_linked_accounts: bool, user_context: Dict[str, Any], ) -> None: pass
async def get_user(self, user_id: str, user_context: Dict[str, Any]) ‑> Optional[User]
-
Expand source code
@abstractmethod async def get_user( self, user_id: str, user_context: Dict[str, Any] ) -> Optional[User]: pass
async def get_users(self, tenant_id: str, time_joined_order: "Literal[('ASC', 'DESC')]", limit: Optional[int], pagination_token: Optional[str], include_recipe_ids: Optional[List[str]], query: Optional[Dict[str, str]], user_context: Dict[str, Any]) ‑> GetUsersResult
-
Expand source code
@abstractmethod async def get_users( self, tenant_id: str, time_joined_order: Literal["ASC", "DESC"], limit: Optional[int], pagination_token: Optional[str], include_recipe_ids: Optional[List[str]], query: Optional[Dict[str, str]], user_context: Dict[str, Any], ) -> GetUsersResult: pass
async def link_accounts(self, recipe_user_id: RecipeUserId, primary_user_id: str, user_context: Dict[str, Any]) ‑> Union[LinkAccountsOkResult, LinkAccountsRecipeUserIdAlreadyLinkedError, LinkAccountsAccountInfoAlreadyAssociatedError, LinkAccountsInputUserNotPrimaryError]
-
Expand source code
@abstractmethod async def link_accounts( self, recipe_user_id: RecipeUserId, primary_user_id: str, user_context: Dict[str, Any], ) -> Union[ LinkAccountsOkResult, LinkAccountsRecipeUserIdAlreadyLinkedError, LinkAccountsAccountInfoAlreadyAssociatedError, LinkAccountsInputUserNotPrimaryError, ]: pass
async def list_users_by_account_info(self, tenant_id: str, account_info: AccountInfo, do_union_of_account_info: bool, user_context: Dict[str, Any]) ‑> List[User]
-
Expand source code
@abstractmethod async def list_users_by_account_info( self, tenant_id: str, account_info: AccountInfo, do_union_of_account_info: bool, user_context: Dict[str, Any], ) -> List[User]: pass
async def unlink_account(self, recipe_user_id: RecipeUserId, user_context: Dict[str, Any]) ‑> UnlinkAccountOkResult
-
Expand source code
@abstractmethod async def unlink_account( self, recipe_user_id: RecipeUserId, user_context: Dict[str, Any] ) -> UnlinkAccountOkResult: pass
class UnlinkAccountOkResult (was_recipe_user_deleted: bool, was_linked: bool)
-
Expand source code
class UnlinkAccountOkResult: def __init__(self, was_recipe_user_deleted: bool, was_linked: bool): self.status: Literal["OK"] = "OK" self.was_recipe_user_deleted = was_recipe_user_deleted self.was_linked = was_linked