Repository: alexander-akhmetov/python-telegram

Issue:
Support authorizationStateWaitRegistration state
After manually adding a code from an SMS I received I got the message:
```
ValueError: 'authorizationStateWaitRegistration' is not a valid AuthorizationState
```

It looks like this state is not handled at the moment.

According to this page
https://core.telegram.org/tdlib/docs/classtd_1_1td__api_1_1authorization_state_wait_registration.html
_The user is unregistered and need to accept terms of service and enter their first name and last name to finish registration._ 

Addition question: Is there a way to add name and term acceptance right now?

I replaced secrets with "11".


Error message:
```
/Users/f/PyCharm/firstTest/venv/bin/python /Users/f/PyCharm/firstTest/Main.py
[ 2][t 4][1606988251.419583082][AuthDataShared.cpp:109][#1][!Td]	DcId{2} [auth_key_id:11][state:NoAuth][created_at:11.000000]
[ 2][t 4][1606988251.419795990][SessionMultiProxy.cpp:121][#1][!SessionMultiProxy:2:main]	[session_count:1]
[ 2][t 4][1606988251.420382023][Session.cpp:147][#1][!SessionProxy:2:main]	Generate new session_id 11 for auth key 11 for main DC10002
ValueError: 'authorizationStateWaitRegistration' is not a valid AuthorizationState

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "/Users/f/PyCharm/firstTest/Main.py", line 3, in <module>
    tg = Telegram(
  File "/Users/f/PyCharm/firstTest/venv/lib/python3.8/site-packages/telegram/client.py", line 134, in __init__
    self.login()
  File "/Users/f/PyCharm/firstTest/venv/lib/python3.8/site-packages/telegram/client.py", line 574, in login
    self.authorization_state = self._wait_authorization_result(result)
  File "/Users/f/PyCharm/firstTest/venv/lib/python3.8/site-packages/telegram/client.py", line 514, in _wait_authorization_result
    return AuthorizationState(authorization_state)
  File "/Library/Frameworks/Python.framework/Versions/3.8/lib/python3.8/enum.py", line 309, in __call__
    return cls.__new__(cls, value)
  File "/Library/Frameworks/Python.framework/Versions/3.8/lib/python3.8/enum.py", line 600, in __new__
    raise exc
  File "/Library/Frameworks/Python.framework/Versions/3.8/lib/python3.8/enum.py", line 584, in __new__
    result = cls._missing_(value)
  File "/Library/Frameworks/Python.framework/Versions/3.8/lib/python3.8/enum.py", line 613, in _missing_
    raise ValueError("%r is not a valid %s" % (value, cls.__name__))
ValueError: 'authorizationStateWaitRegistration' is not a valid AuthorizationState

Process finished with exit code 1

```

Code:
```python
from telegram.client import Telegram

tg = Telegram(
    api_id=11,
    api_hash='11',
    phone='+11',
    database_encryption_key='11',

    use_test_dc=True,
    use_message_database=False,
    login=True
)


def main():
    code = '11'
    password = '11'

    state = tg.login(blocking=False)

    if state == AuthorizationState.WAIT_CODE:
        # Telegram expects a pin code
        tg.send_code(code)
        state = tg.login(blocking=False)  # continue the login process

    if state == AuthorizationState.WAIT_PASSWORD:
        tg.send_password(password)
        state = tg.login(blocking=False)  # continue the login process

# TODO I guess here the missing state should be handled

    # if this is the first run, library needs to preload all chats
    # otherwise the message will not be sent
    result = tg.get_chats()
    # `tdlib` is asynchronous, so `python-telegram` always returns you an `AsyncResult` object.
    # You can wait for a result with the blocking `wait` method.
    result.wait()

    if result.error:
        print(f'get chats error: {result.error_info}')
    else:
        print(f'chats: {result.update}')

    result = tg.send_message(
        chat_id=11,
        text="A test message",
    )

    result.wait()
    if result.error:
        print(f'send message error: {result.error_info}')
    else:
        print(f'message has been sent: {result.update}')

    tg.stop()


main()
```

Discussion:

Patch:
diff --git a/telegram/client.py b/telegram/client.py
index 5a1ea27..01a567c 100644
--- a/telegram/client.py
+++ b/telegram/client.py
@@ -41,6 +41,7 @@ class AuthorizationState(enum.Enum):
     WAIT_TDLIB_PARAMETERS = 'authorizationStateWaitTdlibParameters'
     WAIT_ENCRYPTION_KEY = 'authorizationStateWaitEncryptionKey'
     WAIT_PHONE_NUMBER = 'authorizationStateWaitPhoneNumber'
+    WAIT_REGISTRATION = 'authorizationStateWaitRegistration'
     READY = 'authorizationStateReady'
     CLOSING = 'authorizationStateClosing'
     CLOSED = 'authorizationStateClosed'
@@ -542,7 +543,10 @@ class Telegram:
          - AuthorizationState.WAIT_PASSWORD if a telegram password is required.
            The caller should ask the telegram password
            to the end user and then call send_password(password)
-         - AuthorizationState.READY if the login process scceeded.
+         - AuthorizationState.WAIT_REGISTRATION if a the user must finish registration
+           The caller should ask the first and last names
+           to the end user and then call register_user(first, last)
+         - AuthorizationState.READY if the login process succeeded.
         """
         if self.proxy_server:
             self._send_add_proxy()
@@ -554,11 +558,13 @@ class Telegram:
             AuthorizationState.WAIT_PHONE_NUMBER: self._send_phone_number_or_bot_token,
             AuthorizationState.WAIT_CODE: self._send_telegram_code,
             AuthorizationState.WAIT_PASSWORD: self._send_password,
+            AuthorizationState.WAIT_REGISTRATION: self._register_user,
         }
 
         blocking_actions = (
             AuthorizationState.WAIT_CODE,
             AuthorizationState.WAIT_PASSWORD,
+            AuthorizationState.WAIT_REGISTRATION,
         )
 
         if self.phone:
@@ -710,3 +716,38 @@ class Telegram:
         self.authorization_state = self._wait_authorization_result(result)
 
         return self.authorization_state
+
+    def _register_user(self, first: Optional[str] = None, last: Optional[str] = None) -> AsyncResult:
+        logger.info('Registering user')
+        if first is None:
+            first = input('Enter first name: ')
+        if last is None:
+            last = input('Enter last name: ')
+
+        data = {
+            '@type': 'registerUser',
+            'first_name': first,
+            'last_name': last,
+        }
+        return self._send_data(data, result_id='updateAuthorizationState')
+
+    def register_user(self, first: str, last: str) -> AuthorizationState:
+        """
+        Finishes the new user registration process
+
+        Args:
+          first the user's first name
+          last the user's last name
+          If either argument is None, it will be asked to the user using the input() function
+
+        Returns
+         - AuthorizationState. The called have to call `login` to continue the login process.
+
+        Raises:
+          - RuntimeError if the login failed
+
+        """
+        result = self._register_user(first, last)
+        self.authorization_state = self._wait_authorization_result(result)
+
+        return self.authorization_state


Test patch:
diff --git a/tests/test_telegram_methods.py b/tests/test_telegram_methods.py
index e5d7229..0164f04 100644
--- a/tests/test_telegram_methods.py
+++ b/tests/test_telegram_methods.py
@@ -438,6 +438,9 @@ class TestTelegram__login_non_blocking:
             data={'authorization_state': {'@type': 'authorizationStateWaitCode'}}
         )
         telegram._send_telegram_code = lambda _: _get_async_result(
+            data={'authorization_state': {'@type': 'authorizationStateWaitRegistration'}}
+        )
+        telegram._register_user = lambda _, __: _get_async_result(
             data={'authorization_state': {'@type': 'authorizationStateWaitPassword'}}
         )
         telegram._send_password = lambda _: _get_async_result(
@@ -448,6 +451,10 @@ class TestTelegram__login_non_blocking:
         assert state == AuthorizationState.WAIT_CODE
         telegram.send_code('123')
 
+        state = telegram.login(blocking=False)
+        assert state == AuthorizationState.WAIT_REGISTRATION
+        telegram.register_user('new', 'user')
+
         state = telegram.login(blocking=False)
         assert state == AuthorizationState.WAIT_PASSWORD
         telegram.send_password('456')