diff --git a/packages/syft/src/syft/service/user/user.py b/packages/syft/src/syft/service/user/user.py index 71a07d2dfb0..13f971536d7 100644 --- a/packages/syft/src/syft/service/user/user.py +++ b/packages/syft/src/syft/service/user/user.py @@ -26,6 +26,7 @@ from ...types.syft_object import PartialSyftObject from ...types.syft_object import SYFT_OBJECT_VERSION_1 from ...types.syft_object import SYFT_OBJECT_VERSION_2 +from ...types.syft_object import SYFT_OBJECT_VERSION_3 from ...types.syft_object import SyftObject from ...types.transforms import TransformContext from ...types.transforms import drop @@ -57,18 +58,42 @@ class UserV1(SyftObject): @serializable() -class User(SyftObject): +class UserV2(SyftObject): # version __canonical_name__ = "User" __version__ = SYFT_OBJECT_VERSION_2 id: Optional[UID] + # fields + email: Optional[EmailStr] + name: Optional[str] + hashed_password: Optional[str] + salt: Optional[str] + signing_key: Optional[SyftSigningKey] + verify_key: Optional[SyftVerifyKey] + role: Optional[ServiceRole] + institution: Optional[str] + website: Optional[str] = None + created_at: Optional[str] = None + # TODO where do we put this flag? + mock_execution_permission: bool = False + + +@serializable() +class User(SyftObject): + # version + __canonical_name__ = "User" + __version__ = SYFT_OBJECT_VERSION_3 + + id: Optional[UID] + @pydantic.validator("email", pre=True, always=True) def make_email(cls, v: EmailStr) -> EmailStr: return EmailStr(v) # fields + email_notifications_enabled: bool = True email: Optional[EmailStr] name: Optional[str] hashed_password: Optional[str] @@ -141,10 +166,26 @@ class UserUpdateV1(PartialSyftObject): @serializable() -class UserUpdate(PartialSyftObject): +class UserUpdateV2(PartialSyftObject): __canonical_name__ = "UserUpdate" __version__ = SYFT_OBJECT_VERSION_2 + email: EmailStr + name: str + role: ServiceRole # make sure role cant be set without uid + password: str + password_verify: str + verify_key: SyftVerifyKey + institution: str + website: str + mock_execution_permission: bool + + +@serializable() +class UserUpdate(PartialSyftObject): + __canonical_name__ = "UserUpdate" + __version__ = SYFT_OBJECT_VERSION_3 + @pydantic.validator("email", pre=True) def make_email(cls, v: Any) -> Any: return EmailStr(v) if isinstance(v, str) and not isinstance(v, EmailStr) else v @@ -155,6 +196,7 @@ def str_to_role(cls, v: Any) -> Any: return getattr(ServiceRole, v.upper()) return v + email_notifications_enabled: Optional[bool] = None email: EmailStr name: str role: ServiceRole # make sure role cant be set without uid @@ -172,7 +214,7 @@ class UserCreateV1(UserUpdateV1): email: EmailStr name: str - role: Optional[ServiceRole] = None # type: ignore[assignment] + role: Optional[ServiceRole] = None # TODO: type: ignore[assignment] password: str password_verify: Optional[str] = None # type: ignore[assignment] verify_key: Optional[SyftVerifyKey] @@ -182,13 +224,33 @@ class UserCreateV1(UserUpdateV1): @serializable() -class UserCreate(UserUpdate): +class UserCreateV2(UserUpdateV2): __canonical_name__ = "UserCreate" __version__ = SYFT_OBJECT_VERSION_2 email: EmailStr name: str - role: Optional[ServiceRole] = None # type: ignore[assignment] + role: Optional[ServiceRole] = None # TODO: type: ignore[assignment] + password: str + password_verify: Optional[str] = None # type: ignore[assignment] + verify_key: Optional[SyftVerifyKey] + institution: Optional[str] # type: ignore[assignment] + website: Optional[str] # type: ignore[assignment] + created_by: Optional[SyftSigningKey] + mock_execution_permission: bool = False + + __repr_attrs__ = ["name", "email"] + + +@serializable() +class UserCreate(UserUpdate): + __canonical_name__ = "UserCreate" + __version__ = SYFT_OBJECT_VERSION_3 + + email_notifications_enabled: bool = True + email: EmailStr + name: str + role: Optional[ServiceRole] = None # TODO: type: ignore[assignment] password: str password_verify: Optional[str] = None # type: ignore[assignment] verify_key: Optional[SyftVerifyKey] @@ -223,7 +285,7 @@ class UserViewV1(SyftObject): @serializable() -class UserView(SyftObject): +class UserViewV2(SyftObject): __canonical_name__ = "UserView" __version__ = SYFT_OBJECT_VERSION_2 @@ -236,6 +298,29 @@ class UserView(SyftObject): __repr_attrs__ = ["name", "email", "institution", "website", "role"] + +@serializable() +class UserView(SyftObject): + __canonical_name__ = "UserView" + __version__ = SYFT_OBJECT_VERSION_3 + + email_notifications_enabled: bool + email: EmailStr + name: str + role: ServiceRole # make sure role cant be set without uid + institution: Optional[str] + website: Optional[str] + mock_execution_permission: bool + + __repr_attrs__ = [ + "name", + "email", + "institution", + "website", + "role", + "email_notifications_enabled", + ] + def _coll_repr_(self) -> Dict[str, Any]: return { "Name": self.name, @@ -442,3 +527,47 @@ def upgrade_user_view_v1_to_v2() -> List[Callable]: @migrate(UserView, UserViewV1) def downgrade_user_view_v2_to_v1() -> List[Callable]: return [drop(["mock_execution_permission"])] + + +# User +@migrate(UserV2, User) +def upgrade_user_v2_to_v3() -> List[Callable]: + return [make_set_default(key="email_notifications_enabled", value=True)] + + +@migrate(User, UserV2) +def downgrade_user_v3_to_v2() -> List[Callable]: + return [drop(["email_notifications_enabled"])] + + +# View +@migrate(UserViewV2, UserView) +def upgrade_user_view_v2_to_v3() -> List[Callable]: + return [make_set_default(key="email_notifications_enabled", value=True)] + + +@migrate(UserView, UserViewV2) +def downgrade_user_view_v3_to_v2() -> List[Callable]: + return [drop(["email_notifications_enabled"])] + + +# Create +@migrate(UserViewV2, UserView) +def upgrade_user_create_v2_to_v3() -> List[Callable]: + return [make_set_default(key="email_notifications_enabled", value=True)] + + +@migrate(UserView, UserViewV2) +def downgrade_create_view_v3_to_v2() -> List[Callable]: + return [drop(["email_notifications_enabled"])] + + +# Update +@migrate(UserUpdateV2, UserUpdate) +def upgrade_user_update_v2_to_v3() -> List[Callable]: + return [make_set_default(key="email_notifications_enabled", value=True)] + + +@migrate(UserUpdate, UserViewV2) +def downgrade_user_update_v3_to_v2() -> List[Callable]: + return [drop(["email_notifications_enabled"])]